1b8851fccSafresh1#!./perl 2b8851fccSafresh1 3b8851fccSafresh1# Use B to test that optimisations are not inadvertently removed, 4b8851fccSafresh1# by examining particular nodes in the optree. 5b8851fccSafresh1 6*5759b3d2Safresh1use warnings; 7*5759b3d2Safresh1use strict; 8*5759b3d2Safresh1 9b8851fccSafresh1BEGIN { 10b8851fccSafresh1 chdir 't'; 11b8851fccSafresh1 require './test.pl'; 12b8851fccSafresh1 skip_all_if_miniperl("No B under miniperl"); 13b8851fccSafresh1 @INC = '../lib'; 14b8851fccSafresh1} 15b8851fccSafresh1 16*5759b3d2Safresh1plan 2285; 17b8851fccSafresh1 18b8851fccSafresh1use v5.10; # state 19b8851fccSafresh1use B qw(svref_2object 20b8851fccSafresh1 OPpASSIGN_COMMON_SCALAR 21b8851fccSafresh1 OPpASSIGN_COMMON_RC1 22b8851fccSafresh1 OPpASSIGN_COMMON_AGG 23*5759b3d2Safresh1 OPpTRUEBOOL 24*5759b3d2Safresh1 OPpMAYBE_TRUEBOOL 25*5759b3d2Safresh1 OPpASSIGN_TRUEBOOL 26b8851fccSafresh1 ); 27b8851fccSafresh1 28*5759b3d2Safresh1# for debugging etc. Basic dump of an optree 29*5759b3d2Safresh1 30*5759b3d2Safresh1sub dump_optree { 31*5759b3d2Safresh1 my ($o, $depth) = @_; 32*5759b3d2Safresh1 33*5759b3d2Safresh1 return '' unless $$o; 34*5759b3d2Safresh1 # use Devel::Peek; Dump $o; 35*5759b3d2Safresh1 my $s = (" " x $depth) . $o->name . "\n"; 36*5759b3d2Safresh1 my $n = eval { $o->first }; 37*5759b3d2Safresh1 while ($n && $$n) { 38*5759b3d2Safresh1 $s .= dump_optree($n, $depth+1); 39*5759b3d2Safresh1 $n = $n->sibling; 40*5759b3d2Safresh1 } 41*5759b3d2Safresh1 $s; 42*5759b3d2Safresh1} 43*5759b3d2Safresh1 44*5759b3d2Safresh1 45b8851fccSafresh1 46b8851fccSafresh1# Test that OP_AASSIGN gets the appropriate 47b8851fccSafresh1# OPpASSIGN_COMMON* flags set. 48b8851fccSafresh1# 49b8851fccSafresh1# Too few flags set is likely to cause code to misbehave; 50b8851fccSafresh1# too many flags set unnecessarily slows things down. 51b8851fccSafresh1# See also the tests in t/op/aassign.t 52b8851fccSafresh1 53b8851fccSafresh1for my $test ( 54b8851fccSafresh1 # Each anon array contains: 55b8851fccSafresh1 # [ 56b8851fccSafresh1 # expected flags: 57b8851fccSafresh1 # a 3 char string, each char showing whether we expect a 58b8851fccSafresh1 # particular flag to be set: 59b8851fccSafresh1 # '-' indicates any char not set, while 60b8851fccSafresh1 # 'S': char 0: OPpASSIGN_COMMON_SCALAR, 61b8851fccSafresh1 # 'R': char 1: OPpASSIGN_COMMON_RC1, 62b8851fccSafresh1 # 'A' char 2: OPpASSIGN_COMMON_AGG, 63b8851fccSafresh1 # code to eval, 64b8851fccSafresh1 # description, 65b8851fccSafresh1 # ] 66b8851fccSafresh1 67b8851fccSafresh1 [ "---", '() = (1, $x, my $y, @z, f($p))', 'no LHS' ], 68b8851fccSafresh1 [ "---", '(undef, $x, my $y, @z, ($a ? $b : $c)) = ()', 'no RHS' ], 69b8851fccSafresh1 [ "---", '(undef, $x, my $y, @z, ($a ? $b : $c)) = (1,2)', 'safe RHS' ], 70b8851fccSafresh1 [ "---", 'my @a = (1,2)', 'safe RHS: my array' ], 71b8851fccSafresh1 [ "---", 'my %h = (1,2)', 'safe RHS: my hash' ], 72b8851fccSafresh1 [ "---", 'my ($a,$b,$c,$d) = 1..6; ($a,$b) = ($c,$d);', 'non-common lex' ], 73b8851fccSafresh1 [ "---", '($x,$y) = (1,2)', 'pkg var LHS only' ], 74b8851fccSafresh1 [ "---", 'my $p; my ($x,$y) = ($p, $p)', 'my; dup lex var on RHS' ], 75b8851fccSafresh1 [ "---", 'my $p; my ($x,$y); ($x,$y) = ($p, $p)', 'dup lex var on RHS' ], 76b8851fccSafresh1 [ "---", 'my ($self) = @_', 'LHS lex scalar only' ], 77b8851fccSafresh1 [ "--A", 'my ($self, @rest) = @_', 'LHS lex mixed' ], 78b8851fccSafresh1 [ "-R-", 'my ($x,$y) = ($p, $q)', 'pkg var RHS only' ], 79b8851fccSafresh1 [ "S--", '($x,$y) = ($p, $q)', 'pkg scalar both sides' ], 80b8851fccSafresh1 [ "--A", 'my (@a, @b); @a = @b', 'lex ary both sides' ], 81b8851fccSafresh1 [ "-R-", 'my ($x,$y,$z,@a); ($x,$y,$z) = @a ', 'lex vars to lex ary' ], 82b8851fccSafresh1 [ "--A", '@a = @b', 'pkg ary both sides' ], 83b8851fccSafresh1 [ "--A", 'my (%a,%b); %a = %b', 'lex hash both sides' ], 84b8851fccSafresh1 [ "--A", '%a = %b', 'pkg hash both sides' ], 85b8851fccSafresh1 [ "--A", 'my $x; @a = ($a[0], $a[$x])', 'common ary' ], 86b8851fccSafresh1 [ "--A", 'my ($x,@a); @a = ($a[0], $a[$x])', 'common lex ary' ], 87b8851fccSafresh1 [ "S-A", 'my $x; ($a[$x], $a[0]) = ($a[0], $a[$x])', 'common ary elems' ], 88b8851fccSafresh1 [ "S-A", 'my ($x,@a); ($a[$x], $a[0]) = ($a[0], $a[$x])', 89b8851fccSafresh1 'common lex ary elems' ], 90b8851fccSafresh1 [ "--A", 'my $x; my @a = @$x', 'lex ary may have stuff' ], 91b8851fccSafresh1 [ "-RA", 'my $x; my ($b, @a) = @$x', 'lex ary may have stuff' ], 92b8851fccSafresh1 [ "--A", 'my $x; my %a = @$x', 'lex hash may have stuff' ], 93b8851fccSafresh1 [ "-RA", 'my $x; my ($b, %a) = @$x', 'lex hash may have stuff' ], 94b8851fccSafresh1 [ "--A", 'my (@a,@b); @a = ($b[0])', 'lex ary and elem' ], 95b8851fccSafresh1 [ "S-A", 'my @a; ($a[1],$a[0]) = @a', 'lex ary and elem' ], 96b8851fccSafresh1 [ "--A", 'my @x; @y = $x[0]', 'pkg ary from lex elem' ], 97b8851fccSafresh1 [ "---", '(undef,$x) = f()', 'single scalar on LHS' ], 98b8851fccSafresh1 [ "---", '($x,$y) = ($x)', 'single scalar on RHS, no AGG' ], 99b8851fccSafresh1 [ "--A", '($x,@b) = ($x)', 'single scalar on RHS' ], 100*5759b3d2Safresh1 [ "--A", 'my @a; @a = (@a = split())', 'split a/a' ], 101*5759b3d2Safresh1 [ "--A", 'my (@a,@b); @a = (@b = split())', 'split a/b' ], 102*5759b3d2Safresh1 [ "---", 'my @a; @a = (split(), 1)', '(split(),1)' ], 103*5759b3d2Safresh1 [ "---", '@a = (split(//, @a), 1)', 'split(@a)' ], 104*5759b3d2Safresh1 [ "--A", 'my @a; my $ar = @a; @a = (@$ar = split())', 'a/ar split' ], 105b8851fccSafresh1) { 106*5759b3d2Safresh1 107b8851fccSafresh1 my ($exp, $code, $desc) = @$test; 108*5759b3d2Safresh1 my $sub; 109*5759b3d2Safresh1 { 110*5759b3d2Safresh1 # package vars used in code snippets 111*5759b3d2Safresh1 our (@a, %a, @b, %b, $c, $p, $q, $x, $y, @y, @z); 112*5759b3d2Safresh1 113*5759b3d2Safresh1 $sub = eval "sub { $code }" 114b8851fccSafresh1 or die 115*5759b3d2Safresh1 "aassign eval('$code') failed: this test needs" 116*5759b3d2Safresh1 . "to be rewritten:\n$@" 117*5759b3d2Safresh1 } 118b8851fccSafresh1 119b8851fccSafresh1 my $last_expr = svref_2object($sub)->ROOT->first->last; 120b8851fccSafresh1 if ($last_expr->name ne 'aassign') { 121b8851fccSafresh1 die "Expected aassign but found ", $last_expr->name, 122b8851fccSafresh1 "; this test needs to be rewritten" 123b8851fccSafresh1 } 124b8851fccSafresh1 my $got = 125b8851fccSafresh1 (($last_expr->private & OPpASSIGN_COMMON_SCALAR) ? 'S' : '-') 126b8851fccSafresh1 . (($last_expr->private & OPpASSIGN_COMMON_RC1) ? 'R' : '-') 127b8851fccSafresh1 . (($last_expr->private & OPpASSIGN_COMMON_AGG) ? 'A' : '-'); 128b8851fccSafresh1 is $got, $exp, "OPpASSIGN_COMMON: $desc: '$code'"; 129b8851fccSafresh1} 130b8851fccSafresh1 131b8851fccSafresh1 132b8851fccSafresh1# join -> stringify/const 133b8851fccSafresh1 134b8851fccSafresh1for (['CONSTANT', sub { join "foo", $_ }], 135b8851fccSafresh1 ['$var' , sub { join $_ , $_ }], 136b8851fccSafresh1 ['$myvar' , sub { my $var; join $var, $_ }], 137b8851fccSafresh1) { 138b8851fccSafresh1 my($sep,$sub) = @$_; 139b8851fccSafresh1 my $last_expr = svref_2object($sub)->ROOT->first->last; 140b8851fccSafresh1 is $last_expr->name, 'stringify', 141b8851fccSafresh1 "join($sep, \$scalar) optimised to stringify"; 142b8851fccSafresh1} 143b8851fccSafresh1 144b8851fccSafresh1for (['CONSTANT', sub { join "foo", "bar" }, 0, "bar" ], 145b8851fccSafresh1 ['CONSTANT', sub { join "foo", "bar", 3 }, 1, "barfoo3"], 146b8851fccSafresh1 ['$var' , sub { join $_ , "bar" }, 0, "bar" ], 147b8851fccSafresh1 ['$myvar' , sub { my $var; join $var, "bar" }, 0, "bar" ], 148b8851fccSafresh1) { 149b8851fccSafresh1 my($sep,$sub,$is_list,$expect) = @$_; 150b8851fccSafresh1 my $last_expr = svref_2object($sub)->ROOT->first->last; 151b8851fccSafresh1 my $tn = "join($sep, " . ($is_list?'list of constants':'const') . ")"; 152b8851fccSafresh1 is $last_expr->name, 'const', "$tn optimised to constant"; 153b8851fccSafresh1 is $sub->(), $expect, "$tn folded correctly"; 154b8851fccSafresh1} 155b8851fccSafresh1 156b8851fccSafresh1 157b8851fccSafresh1# list+pushmark in list context elided out of the execution chain 158b8851fccSafresh1is svref_2object(sub { () = ($_, ($_, $_)) }) 159b8851fccSafresh1 ->START # nextstate 160b8851fccSafresh1 ->next # pushmark 161b8851fccSafresh1 ->next # gvsv 162b8851fccSafresh1 ->next # should be gvsv, not pushmark 163b8851fccSafresh1 ->name, 'gvsv', 164b8851fccSafresh1 "list+pushmark in list context where list's elder sibling is a null"; 165b8851fccSafresh1 166b8851fccSafresh1 167b8851fccSafresh1# nextstate multiple times becoming one nextstate 168b8851fccSafresh1 169b8851fccSafresh1is svref_2object(sub { 0;0;0;0;0;0;time })->START->next->name, 'time', 170b8851fccSafresh1 'multiple nextstates become one'; 171b8851fccSafresh1 172b8851fccSafresh1 173b8851fccSafresh1# pad[ahs]v state declarations in void context 174b8851fccSafresh1 175b8851fccSafresh1is svref_2object(sub{state($foo,@fit,%far);state $bar;state($a,$b); time}) 176b8851fccSafresh1 ->START->next->name, 'time', 177b8851fccSafresh1 'pad[ahs]v state declarations in void context'; 178b8851fccSafresh1 179b8851fccSafresh1 180b8851fccSafresh1# pushmark-padsv-padav-padhv in list context --> padrange 181b8851fccSafresh1 182b8851fccSafresh1{ 183b8851fccSafresh1 my @ops; 184b8851fccSafresh1 my $sub = sub { \my( $f, @f, %f ) }; 185b8851fccSafresh1 my $op = svref_2object($sub)->START; 186b8851fccSafresh1 push(@ops, $op->name), $op = $op->next while $$op; 187b8851fccSafresh1 is "@ops", "nextstate padrange refgen leavesub", 'multi-type padrange' 188b8851fccSafresh1} 189b8851fccSafresh1 190b8851fccSafresh1 191b8851fccSafresh1# rv2[ahs]v in void context 192b8851fccSafresh1 193b8851fccSafresh1is svref_2object(sub { our($foo,@fit,%far); our $bar; our($a,$b); time }) 194b8851fccSafresh1 ->START->next->name, 'time', 195b8851fccSafresh1 'rv2[ahs]v in void context'; 196b8851fccSafresh1 197b8851fccSafresh1 198b8851fccSafresh1# split to array 199b8851fccSafresh1 200b8851fccSafresh1for(['@pkgary' , '@_' ], 201b8851fccSafresh1 ['@lexary' , 'my @a; @a'], 202b8851fccSafresh1 ['my(@array)' , 'my(@a)' ], 203b8851fccSafresh1 ['local(@array)', 'local(@_)'], 204b8851fccSafresh1 ['@{...}' , '@{\@_}' ], 205b8851fccSafresh1){ 206b8851fccSafresh1 my($tn,$code) = @$_; 207b8851fccSafresh1 my $sub = eval "sub { $code = split }"; 208b8851fccSafresh1 my $split = svref_2object($sub)->ROOT->first->last; 209b8851fccSafresh1 is $split->name, 'split', "$tn = split swallows up the assignment"; 210b8851fccSafresh1} 211b8851fccSafresh1 212b8851fccSafresh1 213b8851fccSafresh1# stringify with join kid --> join 214b8851fccSafresh1is svref_2object(sub { "@_" })->ROOT->first->last->name, 'join', 215b8851fccSafresh1 'qq"@_" optimised from stringify(join(...)) to join(...)'; 216*5759b3d2Safresh1 217*5759b3d2Safresh1 218*5759b3d2Safresh1# Check that certain ops, when in boolean context, have the 219*5759b3d2Safresh1# right private "is boolean" or "maybe boolean" flags set. 220*5759b3d2Safresh1# 221*5759b3d2Safresh1# A maybe flag is set when the context at the end of a chain of and/or/dor 222*5759b3d2Safresh1# ops isn't known till runtime, e.g. 223*5759b3d2Safresh1# sub f { ....; ((%h || $x) || $y)) } 224*5759b3d2Safresh1# If f() is called in void context, then %h can return a boolean value; 225*5759b3d2Safresh1# if in scalar context, %h must return a key count. 226*5759b3d2Safresh1 227*5759b3d2Safresh1for my $ops ( 228*5759b3d2Safresh1 # op code op_path flag maybe_flag 229*5759b3d2Safresh1 # --------- ---------- ------- ----------------- ---------------- 230*5759b3d2Safresh1 [ 'aassign', '(@pkg = @lex)',[], OPpASSIGN_TRUEBOOL,0, ], 231*5759b3d2Safresh1 [ 'grepwhile','grep($_,1)', [], OPpTRUEBOOL, 0, ], 232*5759b3d2Safresh1 [ 'length', 'length($x)', [], OPpTRUEBOOL, 0, ], 233*5759b3d2Safresh1 [ 'padav', '@lex', [], OPpTRUEBOOL, 0, ], 234*5759b3d2Safresh1 [ 'padav', 'scalar @lex', [0], OPpTRUEBOOL, 0, ], 235*5759b3d2Safresh1 [ 'padhv', '%lex', [], OPpTRUEBOOL, OPpMAYBE_TRUEBOOL ], 236*5759b3d2Safresh1 [ 'padhv', 'scalar(%lex)', [0], OPpTRUEBOOL, OPpMAYBE_TRUEBOOL ], 237*5759b3d2Safresh1 [ 'pos', 'pos($x)', [], OPpTRUEBOOL, 0, ], 238*5759b3d2Safresh1 [ 'ref', 'ref($x)', [], OPpTRUEBOOL, OPpMAYBE_TRUEBOOL ], 239*5759b3d2Safresh1 [ 'rv2av', '@pkg', [], OPpTRUEBOOL, 0, ], 240*5759b3d2Safresh1 [ 'rv2av', 'scalar(@pkg)', [0], OPpTRUEBOOL, 0, ], 241*5759b3d2Safresh1 [ 'rv2hv', '%pkg', [], OPpTRUEBOOL, OPpMAYBE_TRUEBOOL ], 242*5759b3d2Safresh1 [ 'rv2hv', 'scalar(%pkg)', [0], OPpTRUEBOOL, OPpMAYBE_TRUEBOOL ], 243*5759b3d2Safresh1 [ 'subst', 's/a/b/', [], OPpTRUEBOOL, 0, ], 244*5759b3d2Safresh1) { 245*5759b3d2Safresh1 my ($op_name, $op_code, $post_op_path, $bool_flag, $maybe_flag) = @$ops; 246*5759b3d2Safresh1 247*5759b3d2Safresh1 for my $test ( 248*5759b3d2Safresh1 # 1st column: what to expect for each $context (void, scalar, unknown), 249*5759b3d2Safresh1 # 0: expect no flag 250*5759b3d2Safresh1 # 1: expect bool flag 251*5759b3d2Safresh1 # 2: expect maybe bool flag 252*5759b3d2Safresh1 # 9: skip test 253*5759b3d2Safresh1 # 2nd column: path though the op subtree to the flagged op: 254*5759b3d2Safresh1 # 0 is first child, 1 is second child etc. 255*5759b3d2Safresh1 # Will have @$post_op_path from above appended. 256*5759b3d2Safresh1 # 3rd column: code to execute: %s holds the code for the op 257*5759b3d2Safresh1 # 258*5759b3d2Safresh1 # [V S U] PATH CODE 259*5759b3d2Safresh1 260*5759b3d2Safresh1 # INNER PLAIN 261*5759b3d2Safresh1 262*5759b3d2Safresh1 [ [0,0,0], [], '%s' ], 263*5759b3d2Safresh1 [ [1,9,1], [0,0], 'if (%s) {$x}' ], 264*5759b3d2Safresh1 [ [1,9,1], [0,0], 'if (%s) {$x} else {$y}' ], 265*5759b3d2Safresh1 [ [1,9,2], [0,0], 'unless (%s) {$x}' ], 266*5759b3d2Safresh1 267*5759b3d2Safresh1 # INNER NOT 268*5759b3d2Safresh1 269*5759b3d2Safresh1 [ [1,1,1], [0], '!%s' ], 270*5759b3d2Safresh1 [ [1,9,1], [0,0,0], 'if (!%s) {$x}' ], 271*5759b3d2Safresh1 [ [1,9,1], [0,0,0], 'if (!%s) {$x} else {$y}' ], 272*5759b3d2Safresh1 [ [1,9,1], [0,0,0], 'unless (!%s) {$x}' ], 273*5759b3d2Safresh1 274*5759b3d2Safresh1 # INNER COND 275*5759b3d2Safresh1 276*5759b3d2Safresh1 [ [1,1,1], [0,0,], '%s ? $p : $q' ], 277*5759b3d2Safresh1 [ [1,9,1], [0,0,0,0], 'if (%s ? $p : $q) {$x}' ], 278*5759b3d2Safresh1 [ [1,9,1], [0,0,0,0], 'if (%s ? $p : $q) {$x} else {$y}' ], 279*5759b3d2Safresh1 [ [1,9,1], [0,0,0,0], 'unless (%s ? $p : $q) {$x}' ], 280*5759b3d2Safresh1 281*5759b3d2Safresh1 282*5759b3d2Safresh1 # INNER OR LHS 283*5759b3d2Safresh1 284*5759b3d2Safresh1 [ [1,0,2], [0,0], '%s || $x' ], 285*5759b3d2Safresh1 [ [1,1,1], [0,0,0], '!(%s || $x)' ], 286*5759b3d2Safresh1 [ [1,0,2], [0,1,0,0], '$y && (%s || $x)' ], 287*5759b3d2Safresh1 [ [1,9,1], [0,0,0,0], 'if (%s || $x) {$x}' ], 288*5759b3d2Safresh1 [ [1,9,1], [0,0,0,0], 'if (%s || $x) {$x} else {$y}' ], 289*5759b3d2Safresh1 [ [1,9,2], [0,0,0,0], 'unless (%s || $x) {$x}' ], 290*5759b3d2Safresh1 291*5759b3d2Safresh1 # INNER OR RHS 292*5759b3d2Safresh1 293*5759b3d2Safresh1 [ [0,0,0], [0,1], '$x || %s' ], 294*5759b3d2Safresh1 [ [1,1,1], [0,0,1], '!($x || %s)' ], 295*5759b3d2Safresh1 [ [0,0,0], [0,1,0,1], '$y && ($x || %s)' ], 296*5759b3d2Safresh1 [ [1,9,1], [0,0,0,1], 'if ($x || %s) {$x}' ], 297*5759b3d2Safresh1 [ [1,9,1], [0,0,0,1], 'if ($x || %s) {$x} else {$y}' ], 298*5759b3d2Safresh1 [ [1,9,2], [0,0,0,1], 'unless ($x || %s) {$x}' ], 299*5759b3d2Safresh1 300*5759b3d2Safresh1 # INNER DOR LHS 301*5759b3d2Safresh1 302*5759b3d2Safresh1 [ [1,0,2], [0,0], '%s // $x' ], 303*5759b3d2Safresh1 [ [1,1,1], [0,0,0], '!(%s // $x)' ], 304*5759b3d2Safresh1 [ [1,0,2], [0,1,0,0], '$y && (%s // $x)' ], 305*5759b3d2Safresh1 [ [1,9,1], [0,0,0,0], 'if (%s // $x) {$x}' ], 306*5759b3d2Safresh1 [ [1,9,1], [0,0,0,0], 'if (%s // $x) {$x} else {$y}' ], 307*5759b3d2Safresh1 [ [1,9,2], [0,0,0,0], 'unless (%s // $x) {$x}' ], 308*5759b3d2Safresh1 309*5759b3d2Safresh1 # INNER DOR RHS 310*5759b3d2Safresh1 311*5759b3d2Safresh1 [ [0,0,0], [0,1], '$x // %s' ], 312*5759b3d2Safresh1 [ [1,1,1], [0,0,1], '!($x // %s)' ], 313*5759b3d2Safresh1 [ [0,0,0], [0,1,0,1], '$y && ($x // %s)' ], 314*5759b3d2Safresh1 [ [1,9,1], [0,0,0,1], 'if ($x // %s) {$x}' ], 315*5759b3d2Safresh1 [ [1,9,1], [0,0,0,1], 'if ($x // %s) {$x} else {$y}' ], 316*5759b3d2Safresh1 [ [1,9,2], [0,0,0,1], 'unless ($x // %s) {$x}' ], 317*5759b3d2Safresh1 318*5759b3d2Safresh1 # INNER AND LHS 319*5759b3d2Safresh1 320*5759b3d2Safresh1 [ [1,1,1], [0,0], '%s && $x' ], 321*5759b3d2Safresh1 [ [1,1,1], [0,0,0], '!(%s && $x)' ], 322*5759b3d2Safresh1 [ [1,1,1], [0,1,0,0], '$y || (%s && $x)' ], 323*5759b3d2Safresh1 [ [1,9,1], [0,0,0,0], 'if (%s && $x) {$x}' ], 324*5759b3d2Safresh1 [ [1,9,1], [0,0,0,0], 'if (%s && $x) {$x} else {$y}' ], 325*5759b3d2Safresh1 [ [1,9,1], [0,0,0,0], 'unless (%s && $x) {$x}' ], 326*5759b3d2Safresh1 327*5759b3d2Safresh1 # INNER AND RHS 328*5759b3d2Safresh1 329*5759b3d2Safresh1 [ [0,0,0], [0,1], '$x && %s' ], 330*5759b3d2Safresh1 [ [1,1,1], [0,0,1], '!($x && %s)' ], 331*5759b3d2Safresh1 [ [0,0,0], [0,1,0,1], '$y || ($x && %s)' ], 332*5759b3d2Safresh1 [ [1,9,1], [0,0,0,1], 'if ($x && %s) {$x}' ], 333*5759b3d2Safresh1 [ [1,9,1], [0,0,0,1], 'if ($x && %s) {$x} else {$y}' ], 334*5759b3d2Safresh1 [ [1,9,2], [0,0,0,1], 'unless ($x && %s) {$x}' ], 335*5759b3d2Safresh1 336*5759b3d2Safresh1 # INNER XOR LHS 337*5759b3d2Safresh1 338*5759b3d2Safresh1 # LHS of XOR is currently too hard to detect as 339*5759b3d2Safresh1 # being in boolean context 340*5759b3d2Safresh1 341*5759b3d2Safresh1 # INNER XOR RHS 342*5759b3d2Safresh1 343*5759b3d2Safresh1 [ [1,1,1], [1], '($x xor %s)' ], 344*5759b3d2Safresh1 [ [1,1,1], [0,1], '!($x xor %s)' ], 345*5759b3d2Safresh1 [ [1,1,1], [0,1,1], '$y || ($x xor %s)' ], 346*5759b3d2Safresh1 [ [1,9,1], [0,0,1], 'if ($x xor %s) {$x}' ], 347*5759b3d2Safresh1 [ [1,9,1], [0,0,1], 'if ($x xor %s) {$x} else {$y}' ], 348*5759b3d2Safresh1 [ [1,9,1], [0,0,1], 'unless ($x xor %s) {$x}' ], 349*5759b3d2Safresh1 350*5759b3d2Safresh1 # GREP 351*5759b3d2Safresh1 352*5759b3d2Safresh1 [ [1,1,1], [0,1,0], 'grep(%s,1,2)' ], 353*5759b3d2Safresh1 [ [1,1,1], [0,1,0,0], 'grep(!%s,1,2)' ], 354*5759b3d2Safresh1 [ [1,1,1], [0,1,0,0,1],'grep($y || %s,1,2)' ], 355*5759b3d2Safresh1 356*5759b3d2Safresh1 # FLIP 357*5759b3d2Safresh1 358*5759b3d2Safresh1 [ [1,1,1], [0,0,0,0], '%s..$x' ], 359*5759b3d2Safresh1 [ [1,1,1], [0,0,0,0,0], '!%s..$x' ], 360*5759b3d2Safresh1 [ [1,1,1], [0,0,0,0,0,1], '($y || %s)..$x' ], 361*5759b3d2Safresh1 362*5759b3d2Safresh1 # FLOP 363*5759b3d2Safresh1 364*5759b3d2Safresh1 [ [1,1,1], [0,0,0,1], '$x..%s' ], 365*5759b3d2Safresh1 [ [1,1,1], [0,0,0,1,0], '$x..!%s' ], 366*5759b3d2Safresh1 [ [1,1,1], [0,0,0,1,0,1], '$x..($y || %s)' ], 367*5759b3d2Safresh1 368*5759b3d2Safresh1 ) { 369*5759b3d2Safresh1 my ($expects, $op_path, $code_fmt) = @$test; 370*5759b3d2Safresh1 371*5759b3d2Safresh1 for my $context (0,1,2) { 372*5759b3d2Safresh1 # 0: void 373*5759b3d2Safresh1 # 1: scalar 374*5759b3d2Safresh1 # 2: unknown 375*5759b3d2Safresh1 # 9: skip test (principally if() can't be in scalar context) 376*5759b3d2Safresh1 377*5759b3d2Safresh1 next if $expects->[$context] == 9; 378*5759b3d2Safresh1 379*5759b3d2Safresh1 my $base_code = sprintf $code_fmt, $op_code; 380*5759b3d2Safresh1 my $code = $base_code; 381*5759b3d2Safresh1 my @op_path = @$op_path; 382*5759b3d2Safresh1 push @op_path, @$post_op_path; 383*5759b3d2Safresh1 384*5759b3d2Safresh1 # where to find the expression in the top-level lineseq 385*5759b3d2Safresh1 my $seq_offset = -1; 386*5759b3d2Safresh1 387*5759b3d2Safresh1 if ($context == 0) { 388*5759b3d2Safresh1 $seq_offset -= 2; 389*5759b3d2Safresh1 $code .= "; 1"; 390*5759b3d2Safresh1 } 391*5759b3d2Safresh1 elsif ($context == 1) { 392*5759b3d2Safresh1 $code = "\$pkg_result = ($code)"; 393*5759b3d2Safresh1 unshift @op_path, 0; 394*5759b3d2Safresh1 } 395*5759b3d2Safresh1 396*5759b3d2Safresh1 397*5759b3d2Safresh1 my $sub; 398*5759b3d2Safresh1 { 399*5759b3d2Safresh1 # don't use 'my' for $pkg_result to avoid the assignment in 400*5759b3d2Safresh1 # '$result = foo()' being optimised away with OPpTARGET_MY 401*5759b3d2Safresh1 our (@pkg, %pkg, $pkg_result); 402*5759b3d2Safresh1 my (@lex, %lex, $p, $q, $x, $y); 403*5759b3d2Safresh1 404*5759b3d2Safresh1 no warnings 'void'; 405*5759b3d2Safresh1 $sub = eval "sub { $code }" 406*5759b3d2Safresh1 or die 407*5759b3d2Safresh1 "eval'$code' failed: this test needs to be rewritten;\n" 408*5759b3d2Safresh1 . "Errors were:\n$@"; 409*5759b3d2Safresh1 } 410*5759b3d2Safresh1 411*5759b3d2Safresh1 # find the expression subtree in the main lineseq of the sub 412*5759b3d2Safresh1 my $expr = svref_2object($sub)->ROOT->first; 413*5759b3d2Safresh1 my $orig_expr = $expr; 414*5759b3d2Safresh1 my @ops; 415*5759b3d2Safresh1 my $next = $expr->first; 416*5759b3d2Safresh1 while ($$next) { 417*5759b3d2Safresh1 push @ops, $next; 418*5759b3d2Safresh1 $next = $next->sibling; 419*5759b3d2Safresh1 } 420*5759b3d2Safresh1 $expr = $ops[$seq_offset]; 421*5759b3d2Safresh1 422*5759b3d2Safresh1 # search through the expr subtree looking for the named op - 423*5759b3d2Safresh1 # this assumes that for all the code examples above, the 424*5759b3d2Safresh1 # op is always in the LH branch 425*5759b3d2Safresh1 my @orig_op_path = @op_path; 426*5759b3d2Safresh1 while (defined (my $p = shift @op_path)) { 427*5759b3d2Safresh1 eval { 428*5759b3d2Safresh1 $expr = $expr->first; 429*5759b3d2Safresh1 $expr = $expr->sibling while $p--; 430*5759b3d2Safresh1 } 431*5759b3d2Safresh1 } 432*5759b3d2Safresh1 433*5759b3d2Safresh1 if (!$expr || !$$expr || $expr->name ne $op_name) { 434*5759b3d2Safresh1 my $optree = dump_optree($orig_expr,2); 435*5759b3d2Safresh1 print STDERR "Can't find $op_name op in optree for '$code'.\n"; 436*5759b3d2Safresh1 print STDERR "This test needs to be rewritten\n"; 437*5759b3d2Safresh1 print STDERR "seq_offset=$seq_offset op_path=(@orig_op_path)\n"; 438*5759b3d2Safresh1 print STDERR "optree=\n$optree"; 439*5759b3d2Safresh1 exit 1; 440*5759b3d2Safresh1 } 441*5759b3d2Safresh1 442*5759b3d2Safresh1 my $exp = $expects->[$context]; 443*5759b3d2Safresh1 $exp = $exp == 0 ? 0 444*5759b3d2Safresh1 : $exp == 1 ? $bool_flag 445*5759b3d2Safresh1 : $maybe_flag; 446*5759b3d2Safresh1 447*5759b3d2Safresh1 my $got = ($expr->private & ($bool_flag | $maybe_flag)); 448*5759b3d2Safresh1 my $cxt_name = ('void ', 'scalar ', 'unknown')[$context]; 449*5759b3d2Safresh1 is $got, $exp, "boolean: $op_name $cxt_name '$base_code'"; 450*5759b3d2Safresh1 } 451*5759b3d2Safresh1 } 452*5759b3d2Safresh1} 453*5759b3d2Safresh1 454