This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
fix index(...) == -1 type optimisations
[perl5.git] / op.c
diff --git a/op.c b/op.c
index 53a6cfe..99c4db8 100644 (file)
--- a/op.c
+++ b/op.c
@@ -9688,8 +9688,11 @@ Perl_ck_cmp(pTHX_ OP *o)
 {
     bool is_eq;
     bool neg;
+    bool reverse;
+    bool iv0;
     OP *indexop, *constop, *start;
     SV *sv;
+    IV iv;
 
     PERL_ARGS_ASSERT_CK_CMP;
 
@@ -9718,6 +9721,8 @@ Perl_ck_cmp(pTHX_ OP *o)
      *   (r)index/BOOL(,NEG)
      */
 
+    reverse = FALSE;
+
     indexop = cUNOPo->op_first;
     constop = OpSIBLING(indexop);
     start = NULL;
@@ -9725,6 +9730,7 @@ Perl_ck_cmp(pTHX_ OP *o)
         constop = indexop;
         indexop = OpSIBLING(constop);
         start = constop;
+        reverse = TRUE;
     }
 
     if (indexop->op_type != OP_INDEX && indexop->op_type != OP_RINDEX)
@@ -9741,28 +9747,42 @@ Perl_ck_cmp(pTHX_ OP *o)
     if (!(sv && SvIOK_notUV(sv)))
         return o;
 
-    neg = FALSE;
+    iv = SvIVX(sv);
+    if (iv != -1 && iv != 0)
+        return o;
+    iv0 = (iv == 0);
 
-    if (SvIVX(sv) == -1) {
-        if (  o->op_type == OP_EQ || o->op_type == OP_I_EQ
-           || o->op_type == OP_LE || o->op_type == OP_I_LE
-        )
-            neg = TRUE;
-        else 
-        if (!(   o->op_type == OP_NE || o->op_type == OP_I_NE
-              || o->op_type == OP_GT || o->op_type == OP_I_GT)
-        )
+    if (o->op_type == OP_LT || o->op_type == OP_I_LT) {
+        if (!(iv0 ^ reverse))
             return o;
+        neg = iv0;
     }
-    else if (SvIVX(sv) == 0) {
-        if (o->op_type == OP_LT || o->op_type == OP_I_LT)
-            neg = TRUE;
-        else 
-        if (!(o->op_type == OP_GE || o->op_type == OP_I_GE))
+    else if (o->op_type == OP_LE || o->op_type == OP_I_LE) {
+        if (iv0 ^ reverse)
             return o;
+        neg = !iv0;
+    }
+    else if (o->op_type == OP_GE || o->op_type == OP_I_GE) {
+        if (!(iv0 ^ reverse))
+            return o;
+        neg = !iv0;
+    }
+    else if (o->op_type == OP_GT || o->op_type == OP_I_GT) {
+        if (iv0 ^ reverse)
+            return o;
+        neg = iv0;
+    }
+    else if (o->op_type == OP_EQ || o->op_type == OP_I_EQ) {
+        if (iv0)
+            return o;
+        neg = TRUE;
+    }
+    else {
+        assert(o->op_type == OP_NE || o->op_type == OP_I_NE);
+        if (iv0)
+            return o;
+        neg = FALSE;
     }
-    else
-        return o;
 
     indexop->op_flags &= ~OPf_PARENS;
     indexop->op_flags |= (o->op_flags & OPf_PARENS);