fully short-circuit &&, ||, //
authorDavid Mitchell <davem@iabyn.com>
Thu, 14 Jul 2011 15:35:26 +0000 (16:35 +0100)
committerDavid Mitchell <davem@iabyn.com>
Thu, 14 Jul 2011 16:23:17 +0000 (17:23 +0100)
Currently in an expression like (A || B || C || D), if A is true, then
B, C and D aren't evaluated, but the 2nd, 3rd and 4th OR ops are *still*
executed. Use the peephole optimiser to bypass them.

i.e. change the op tree from

    - A - OR - OR - OR - X---
            \ /  \ /  \ /
             B    C    D
to
    - A - OR --------------------X---
            \                   /
             B - OR -----------/
           \          /
    C - OR --/
          \ /
   D

With this, the following code's execution time reduces from 1.6s to 0.9s
approx on my system:

    my $a = 1; my $b = 0; my $x = 0;
    for (1..10_000_000) {
if ($a || $b || $b || $b || $b || $b) {
    $x++;
}
    }

op.c

diff --git a/op.c b/op.c
index 1ad2074..7b129ac 100644 (file)
--- a/op.c
+++ b/op.c
@@ -9623,6 +9623,9 @@ Perl_rpeep(pTHX_ register OP *o)
             sop = fop->op_sibling;
            while (cLOGOP->op_other->op_type == OP_NULL)
                cLOGOP->op_other = cLOGOP->op_other->op_next;
+           while (o->op_next && (   o->op_type == o->op_next->op_type
+                                 || o->op_next->op_type == OP_NULL))
+               o->op_next = o->op_next->op_next;
            DEFER(cLOGOP->op_other);
           
           stitch_keys: