diff options
author | Alon Zakai <azakai@google.com> | 2023-10-24 14:37:52 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-10-24 14:37:52 -0700 |
commit | ec8220f4aa556ce39145db13eddd84855b11f76c (patch) | |
tree | d994013922dcd35e59f043df83899e6325f36102 /test | |
parent | ba04e395508fc3414b952287d7e918d20361087e (diff) | |
download | binaryen-ec8220f4aa556ce39145db13eddd84855b11f76c.tar.gz binaryen-ec8220f4aa556ce39145db13eddd84855b11f76c.tar.bz2 binaryen-ec8220f4aa556ce39145db13eddd84855b11f76c.zip |
Fix unreachable code in LocalGraph by making it imprecise there (#6048)
Followup to #6046 - the fuzzer found we missed handling the case of the entry itself
being unreachable, or of an unreachable loop later. Properly identifying unreachable
code requires a flow analysis, unfortunately, so this PR gives up on that and instead
allows LocalGraph to be imprecise in unreachable code. That avoids adding any
overhead, but does mean the IR may be slightly confusing when debugging. It does
not have any optimization downsides, however, as it only affects unreachable code.
Also add a dump() impl in that file which helps debugging.
Diffstat (limited to 'test')
-rw-r--r-- | test/lit/passes/precompute-gc.wast | 91 |
1 files changed, 83 insertions, 8 deletions
diff --git a/test/lit/passes/precompute-gc.wast b/test/lit/passes/precompute-gc.wast index b2e9593d5..3a16eddbc 100644 --- a/test/lit/passes/precompute-gc.wast +++ b/test/lit/passes/precompute-gc.wast @@ -229,7 +229,7 @@ (struct.get $struct 0 (local.get $x)) ) ) - ;; CHECK: (func $ref-comparisons (type $9) (param $x (ref null $struct)) (param $y (ref null $struct)) + ;; CHECK: (func $ref-comparisons (type $10) (param $x (ref null $struct)) (param $y (ref null $struct)) ;; CHECK-NEXT: (local $z (ref null $struct)) ;; CHECK-NEXT: (local $w (ref null $struct)) ;; CHECK-NEXT: (call $log @@ -407,7 +407,7 @@ (local.get $tempresult) ) - ;; CHECK: (func $propagate-different-params (type $10) (param $input1 (ref $empty)) (param $input2 (ref $empty)) (result i32) + ;; CHECK: (func $propagate-different-params (type $11) (param $input1 (ref $empty)) (param $input2 (ref $empty)) (result i32) ;; CHECK-NEXT: (local $tempresult i32) ;; CHECK-NEXT: (local.set $tempresult ;; CHECK-NEXT: (ref.eq @@ -723,7 +723,7 @@ ) ) - ;; CHECK: (func $helper (type $11) (param $0 i32) (result i32) + ;; CHECK: (func $helper (type $12) (param $0 i32) (result i32) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) (func $helper (param i32) (result i32) @@ -801,14 +801,14 @@ ) ) - ;; CHECK: (func $receive-f64 (type $12) (param $0 f64) + ;; CHECK: (func $receive-f64 (type $13) (param $0 f64) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) (func $receive-f64 (param f64) (unreachable) ) - ;; CHECK: (func $odd-cast-and-get-non-null (type $13) (param $temp (ref $func-return-i32)) + ;; CHECK: (func $odd-cast-and-get-non-null (type $14) (param $temp (ref $func-return-i32)) ;; CHECK-NEXT: (local.set $temp ;; CHECK-NEXT: (ref.cast (ref nofunc) ;; CHECK-NEXT: (ref.func $receive-f64) @@ -857,7 +857,7 @@ ) ) - ;; CHECK: (func $br_on_cast-on-creation (type $14) (result (ref $empty)) + ;; CHECK: (func $br_on_cast-on-creation (type $15) (result (ref $empty)) ;; CHECK-NEXT: (block $label (result (ref $empty)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (br_on_cast $label (ref $empty) (ref $empty) @@ -952,7 +952,7 @@ ) ) - ;; CHECK: (func $remove-set (type $15) (result (ref func)) + ;; CHECK: (func $remove-set (type $16) (result (ref func)) ;; CHECK-NEXT: (local $nn funcref) ;; CHECK-NEXT: (local $i i32) ;; CHECK-NEXT: (loop $loop @@ -995,7 +995,7 @@ ) ) - ;; CHECK: (func $strings (type $16) (param $param (ref string)) + ;; CHECK: (func $strings (type $17) (param $param (ref string)) ;; CHECK-NEXT: (local $s (ref string)) ;; CHECK-NEXT: (local.set $s ;; CHECK-NEXT: (string.const "hello, world") @@ -1066,4 +1066,79 @@ ) (local.get $x) ) + + ;; CHECK: (func $get-nonnullable-in-unreachable-entry (type $9) (param $x i32) (param $y (ref any)) + ;; CHECK-NEXT: (local $0 (ref any)) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (local.set $0 + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (loop $loop + ;; CHECK-NEXT: (br_if $loop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $get-nonnullable-in-unreachable-entry (param $x i32) (param $y (ref any)) + (local $0 (ref any)) + ;; As above, but now the first basic block is unreachable, and we need to + ;; detect that specifically, as the block after it *does* have entries even + ;; though it is unreachable (it is a loop, and has itself as an entry). + (unreachable) + (local.set $0 + (local.get $y) + ) + (loop $loop + (br_if $loop + (local.get $x) + ) + (drop + (local.get $0) + ) + ) + ) + + ;; CHECK: (func $get-nonnullable-in-unreachable-later-loop (type $9) (param $x i32) (param $y (ref any)) + ;; CHECK-NEXT: (local $0 (ref any)) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (local.set $0 + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (loop $loop + ;; CHECK-NEXT: (br_if $loop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $get-nonnullable-in-unreachable-later-loop (param $x i32) (param $y (ref any)) + (local $0 (ref any)) + ;; This |if| is added, which means the loop is later in the function. + ;; Otherwise this is the same as before. + (if + (local.get $x) + (nop) + ) + (unreachable) + (local.set $0 + (local.get $y) + ) + (loop $loop + (br_if $loop + (local.get $x) + ) + (drop + (local.get $0) + ) + ) + ) ) |