summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2011-07-14 16:35:26 +0100
committerDavid Mitchell <davem@iabyn.com>2011-07-14 17:23:17 +0100
commitdb4d68cf2dda3f17d4e9fb440385189f55271b32 (patch)
treeff5bc18625827c63d279962b641ee74b0eae10dd
parent0e1b3a4b35c4f6798b244c5b82edcf759e9e6806 (diff)
downloadperl-db4d68cf2dda3f17d4e9fb440385189f55271b32.tar.gz
fully short-circuit &&, ||, //
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++; } }
-rw-r--r--op.c3
1 files changed, 3 insertions, 0 deletions
diff --git a/op.c b/op.c
index 1ad20745b2..7b129ac334 100644
--- 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: