Do note code fold ifs with concrete arms Code folding does not support folding tails that produce concrete values, but it previously did not check for this condition when deciding whether to attempt to code fold ifs. As a result, code folding would proceed on ifs with concretely typed arms. The incorrect block types produced by the folding logic as a result of the violated assumption that the folded tails would never produce concrete values were papered over by later refinalization, so this never caused problems. However, an upcoming change (#7094) that relaxes the typing of ifs to allow them to be unreachable whenever their conditions are unreachable makes it possible for the violated assumptions in code folding to cause problems that are not fixed by refinalization. Fix code folding to disallow folding of concretely typed if arms and add a test that would fail once #7094 lands without this fix.
diff --git a/src/passes/CodeFolding.cpp b/src/passes/CodeFolding.cpp index 21527da..47e7916 100644 --- a/src/passes/CodeFolding.cpp +++ b/src/passes/CodeFolding.cpp
@@ -243,6 +243,10 @@ if (!curr->ifFalse) { return; } + if (curr->ifTrue->type.isConcrete()) { + // We don't support folding tails that produce values. + return; + } // if both sides are identical, this is easy to fold if (ExpressionAnalyzer::equal(curr->ifTrue, curr->ifFalse)) { Builder builder(*getModule());
diff --git a/test/lit/passes/code-folding_enable-threads.wast b/test/lit/passes/code-folding_enable-threads.wast index b070002..3df2d8c 100644 --- a/test/lit/passes/code-folding_enable-threads.wast +++ b/test/lit/passes/code-folding_enable-threads.wast
@@ -83,11 +83,18 @@ ) ) ;; CHECK: (func $negative-zero-b (result f32) - ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (if (result f32) ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block $label$0 (result f32) - ;; CHECK-NEXT: (f32.const -0) + ;; CHECK-NEXT: (then + ;; CHECK-NEXT: (block $label$0 (result f32) + ;; CHECK-NEXT: (f32.const -0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (else + ;; CHECK-NEXT: (block $label$1 (result f32) + ;; CHECK-NEXT: (f32.const -0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $negative-zero-b (result f32) @@ -106,11 +113,18 @@ ) ) ;; CHECK: (func $negative-zero-c (result f32) - ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (if (result f32) ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block $label$0 (result f32) - ;; CHECK-NEXT: (f32.const 0) + ;; CHECK-NEXT: (then + ;; CHECK-NEXT: (block $label$0 (result f32) + ;; CHECK-NEXT: (f32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (else + ;; CHECK-NEXT: (block $label$1 (result f32) + ;; CHECK-NEXT: (f32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $negative-zero-c (result f32) @@ -482,3 +496,36 @@ ) ) ) + +(module + ;; CHECK: (type $0 (func)) + + ;; CHECK: (func $unreachable-if-concrete-arms + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (if (result i32) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (then + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (else + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + (func $unreachable-if-concrete-arms + (if (result i32) + (unreachable) + (then + (i32.const 1) + ) + (else + (nop) + (i32.const 1) + ) + ) + (unreachable) + ) +)
diff --git a/test/lit/passes/inlining-optimizing_optimize-level=3.wast b/test/lit/passes/inlining-optimizing_optimize-level=3.wast index f6df730..9e514cc 100644 --- a/test/lit/passes/inlining-optimizing_optimize-level=3.wast +++ b/test/lit/passes/inlining-optimizing_optimize-level=3.wast
@@ -5742,42 +5742,43 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (if - ;; CHECK-NEXT: (i32.and - ;; CHECK-NEXT: (local.get $9) - ;; CHECK-NEXT: (i32.const 8) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (then - ;; CHECK-NEXT: (local.set $7 + ;; CHECK-NEXT: (local.set $5 + ;; CHECK-NEXT: (if (result i32) + ;; CHECK-NEXT: (i32.and ;; CHECK-NEXT: (local.get $9) + ;; CHECK-NEXT: (i32.const 8) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $6 - ;; CHECK-NEXT: (select - ;; CHECK-NEXT: (local.tee $5 - ;; CHECK-NEXT: (i32.add - ;; CHECK-NEXT: (i32.sub - ;; CHECK-NEXT: (local.get $23) - ;; CHECK-NEXT: (local.get $8) + ;; CHECK-NEXT: (then + ;; CHECK-NEXT: (local.set $7 + ;; CHECK-NEXT: (local.get $9) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $6 + ;; CHECK-NEXT: (select + ;; CHECK-NEXT: (local.tee $5 + ;; CHECK-NEXT: (i32.add + ;; CHECK-NEXT: (i32.sub + ;; CHECK-NEXT: (local.get $23) + ;; CHECK-NEXT: (local.get $8) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $6) + ;; CHECK-NEXT: (i32.gt_s + ;; CHECK-NEXT: (local.get $5) + ;; CHECK-NEXT: (local.get $6) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $6) - ;; CHECK-NEXT: (i32.gt_s - ;; CHECK-NEXT: (local.get $5) - ;; CHECK-NEXT: (local.get $6) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $8) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (else + ;; CHECK-NEXT: (local.set $7 + ;; CHECK-NEXT: (local.get $9) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $8) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (else - ;; CHECK-NEXT: (local.set $7 - ;; CHECK-NEXT: (local.get $9) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $5 - ;; CHECK-NEXT: (local.get $8) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $8 ;; CHECK-NEXT: (i32.const 0)
diff --git a/test/passes/remove-unused-names_code-folding.txt b/test/passes/remove-unused-names_code-folding.txt index d0486b3..4b228bd 100644 --- a/test/passes/remove-unused-names_code-folding.txt +++ b/test/passes/remove-unused-names_code-folding.txt
@@ -26,13 +26,19 @@ ) ) (drop - (block (result i32) - (drop - (i32.const 0) + (if (result i32) + (i32.const 0) + (then + (i32.add + (i32.const 1) + (i32.const 2) + ) ) - (i32.add - (i32.const 1) - (i32.const 2) + (else + (i32.add + (i32.const 1) + (i32.const 2) + ) ) ) ) @@ -218,54 +224,61 @@ (unreachable) ) (drop - (block (result i32) - (if - (i32.const 2) - (then - (drop - (i32.const -1234) - ) - (drop - (i32.const -1000) - ) - ) - (else - (drop - (i32.const 999) - ) - ) - ) - (drop - (i32.const 1) - ) - (nop) - (unreachable) + (if (result i32) (i32.const 2) + (then + (drop + (i32.const -1234) + ) + (drop + (i32.const -1000) + ) + (drop + (i32.const 1) + ) + (nop) + (unreachable) + (i32.const 2) + ) + (else + (drop + (i32.const 999) + ) + (drop + (i32.const 1) + ) + (nop) + (unreachable) + (i32.const 2) + ) ) ) (drop - (block (result i32) - (if - (i32.const 3) - (then - (drop - (i32.const -1234) - ) - (drop - (i32.const -1000) - ) + (if (result i32) + (i32.const 3) + (then + (drop + (i32.const -1234) ) - (else - (drop - (i32.const 999) - ) + (drop + (i32.const -1000) ) + (drop + (i32.const 1) + ) + (nop) + (i32.const 2) ) - (drop - (i32.const 1) + (else + (drop + (i32.const 999) + ) + (drop + (i32.const 1) + ) + (nop) + (i32.const 2) ) - (nop) - (i32.const 2) ) ) ) @@ -388,28 +401,28 @@ ) (drop (block (result i32) - (block (result i32) - (if - (i32.const 9999) - (then - (drop - (i32.const -51234) - ) - (drop - (i32.const -51000) - ) + (if (result i32) + (i32.const 9999) + (then + (drop + (i32.const -51234) ) - (else - (drop - (i32.const 5999) - ) - (drop - (i32.const 51) - ) + (drop + (i32.const -51000) ) + (unreachable) + (i32.const 10) ) - (unreachable) - (i32.const 10) + (else + (drop + (i32.const 5999) + ) + (drop + (i32.const 51) + ) + (unreachable) + (i32.const 10) + ) ) ) ) @@ -1523,11 +1536,15 @@ ) (nop) (drop - (block (result i32) - (drop - (unreachable) + (if (result i32) + (unreachable) + (then + (i32.add + (i32.const 1) + (i32.const 2) + ) ) - (block (result i32) + (else (i32.add (i32.const 1) (i32.const 2) @@ -1874,20 +1891,19 @@ (i32.const 1) ) ) - (block (result i32) - (if - (local.get $x) - (then - ) - (else - (drop - (call $if-suffix - (i32.const -2) - ) + (if (result i32) + (local.get $x) + (then + (i32.const 2) + ) + (else + (drop + (call $if-suffix + (i32.const -2) ) ) + (i32.const 2) ) - (i32.const 2) ) ) )