Try fix for simplifylocals when a throw is present
diff --git a/src/ir/linear-execution.h b/src/ir/linear-execution.h index 9e69405..430271f 100644 --- a/src/ir/linear-execution.h +++ b/src/ir/linear-execution.h
@@ -76,6 +76,7 @@ // cases (calls, if without an else) and it has very low overhead (we still // only do a simple postorder walk on the IR, no CFG is constructed, etc.). bool connectAdjacentBlocks = false; + bool connectAdjacentCalls = false; static void scan(SubType* self, Expression** currp) { Expression* curr = *currp; @@ -89,7 +90,7 @@ // Control is nonlinear if we return or throw. Traps don't need to be // taken into account since they don't break control flow in a way // that's observable. - if (mayThrow || isReturn) { + if (isReturn || (!self->connectAdjacentCalls && mayThrow)) { self->pushTask(SubType::doNoteNonLinear, currp); } }
diff --git a/src/passes/SimplifyLocals.cpp b/src/passes/SimplifyLocals.cpp index 0879138..605799e 100644 --- a/src/passes/SimplifyLocals.cpp +++ b/src/passes/SimplifyLocals.cpp
@@ -76,13 +76,17 @@ SimplifyLocals<allowTee, allowStructure, allowNesting>>(); } + bool connectAdjacentCalls = true; + // information for a local.set we can sink struct SinkableInfo { Expression** item; EffectAnalyzer effects; SinkableInfo(Expression** item, PassOptions& passOptions, Module& module) - : item(item), effects(passOptions, module, *item) {} + : item(item), + effects( + passOptions, module, (*item)->template cast<LocalSet>()->value) {} }; // a list of sinkables in a linear execution trace
diff --git a/test/lit/ctor-eval/multivalue-local.wast b/test/lit/ctor-eval/multivalue-local.wast index 306e26a..aa9e80e 100644 --- a/test/lit/ctor-eval/multivalue-local.wast +++ b/test/lit/ctor-eval/multivalue-local.wast
@@ -44,13 +44,6 @@ ;; CHECK: (export "multivalue-local" (func $multivalue-local_2)) ;; CHECK: (func $multivalue-local_2 (type $1) (result i32) -;; CHECK-NEXT: (local $0 i32) -;; CHECK-NEXT: (local.set $0 -;; CHECK-NEXT: (i32.const 42) -;; CHECK-NEXT: ) ;; CHECK-NEXT: (call $import) -;; CHECK-NEXT: (i32.add -;; CHECK-NEXT: (local.get $0) -;; CHECK-NEXT: (local.get $0) -;; CHECK-NEXT: ) +;; CHECK-NEXT: (i32.const 84) ;; CHECK-NEXT: )
diff --git a/test/lit/passes/flatten_simplify-locals-nonesting_souperify-single-use_enable-threads.wast b/test/lit/passes/flatten_simplify-locals-nonesting_souperify-single-use_enable-threads.wast index f719700..0ab4ed4 100644 --- a/test/lit/passes/flatten_simplify-locals-nonesting_souperify-single-use_enable-threads.wast +++ b/test/lit/passes/flatten_simplify-locals-nonesting_souperify-single-use_enable-threads.wast
@@ -3133,9 +3133,7 @@ ;; CHECK-NEXT: (local.set $y ;; CHECK-NEXT: (i32.const 2) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $z - ;; CHECK-NEXT: (i32.const 3) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (loop $loopy ;; CHECK-NEXT: (local.set $x ;; CHECK-NEXT: (i32.const 4) @@ -3151,18 +3149,18 @@ ;; CHECK-NEXT: (br_if $loopy ;; CHECK-NEXT: (local.get $t) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $z - ;; CHECK-NEXT: (i32.const 6) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (nop) - ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (local.set $8 + ;; CHECK-NEXT: (i32.const 6) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $9 ;; CHECK-NEXT: (select ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: (local.get $y) - ;; CHECK-NEXT: (local.get $z) + ;; CHECK-NEXT: (local.get $8) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (return @@ -3534,13 +3532,13 @@ ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (nop) - ;; CHECK-NEXT: (local.set $10 - ;; CHECK-NEXT: (f64.const 0) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (local.set $11 + ;; CHECK-NEXT: (f64.const 0) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.get $10) + ;; CHECK-NEXT: (local.get $11) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: )
diff --git a/test/lit/passes/flatten_simplify-locals-nonesting_souperify_enable-threads.wast b/test/lit/passes/flatten_simplify-locals-nonesting_souperify_enable-threads.wast index d57df65..08a4bf6 100644 --- a/test/lit/passes/flatten_simplify-locals-nonesting_souperify_enable-threads.wast +++ b/test/lit/passes/flatten_simplify-locals-nonesting_souperify_enable-threads.wast
@@ -3200,9 +3200,7 @@ ;; CHECK-NEXT: (local.set $y ;; CHECK-NEXT: (i32.const 2) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $z - ;; CHECK-NEXT: (i32.const 3) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (loop $loopy ;; CHECK-NEXT: (local.set $x ;; CHECK-NEXT: (i32.const 4) @@ -3218,18 +3216,18 @@ ;; CHECK-NEXT: (br_if $loopy ;; CHECK-NEXT: (local.get $t) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $z - ;; CHECK-NEXT: (i32.const 6) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (nop) - ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (local.set $8 + ;; CHECK-NEXT: (i32.const 6) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $9 ;; CHECK-NEXT: (select ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: (local.get $y) - ;; CHECK-NEXT: (local.get $z) + ;; CHECK-NEXT: (local.get $8) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (return @@ -3601,13 +3599,13 @@ ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (nop) - ;; CHECK-NEXT: (local.set $10 - ;; CHECK-NEXT: (f64.const 0) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (local.set $11 + ;; CHECK-NEXT: (f64.const 0) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.get $10) + ;; CHECK-NEXT: (local.get $11) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: )
diff --git a/test/lit/passes/simplify-locals-eh.wast b/test/lit/passes/simplify-locals-eh.wast index b65b5ba..adc34e8 100644 --- a/test/lit/passes/simplify-locals-eh.wast +++ b/test/lit/passes/simplify-locals-eh.wast
@@ -138,9 +138,7 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.get $0) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $equivalent-set-removal-call (param $0 i32) (local $1 i32)
diff --git a/test/lit/passes/simplify-locals-global-effects-eh.wast b/test/lit/passes/simplify-locals-global-effects-eh.wast index 2fed91f..0e7badf 100644 --- a/test/lit/passes/simplify-locals-global-effects-eh.wast +++ b/test/lit/passes/simplify-locals-global-effects-eh.wast
@@ -38,17 +38,16 @@ ;; CHECK: (func $read-g-with-throw-in-between (type $1) (result i32) ;; CHECK-NEXT: (local $x i32) - ;; CHECK-NEXT: (local.set $x - ;; CHECK-NEXT: (global.get $g) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (call $throws) - ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (global.get $g) ;; CHECK-NEXT: ) (func $read-g-with-throw-in-between (result i32) (local $x i32) (local.set $x (global.get $g)) - ;; A potential throw halts our optimizations. + ;; Sinking across a throw is valid here because reading the global has no + ;; side effects. (call $throws) (local.get $x) @@ -132,22 +131,19 @@ ;; CHECK: (func $read-g-with-effectful-call-ref (type $3) (param $ref (ref $throw-type)) (result i32) ;; CHECK-NEXT: (local $x i32) - ;; CHECK-NEXT: (local.set $x - ;; CHECK-NEXT: (global.get $g) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call_ref $throw-type ;; CHECK-NEXT: (local.get $ref) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (global.get $g) ;; CHECK-NEXT: ) (func $read-g-with-effectful-call-ref (param $ref (ref $throw-type)) (result i32) (local $x i32) (local.set $x (global.get $g)) - ;; Similar to above, except here we can tell that the indirect call may - ;; throw so optimization is halted. + ;; Sinking across a potentially throwing call is valid here. (drop (call_ref $throw-type (local.get $ref))) (local.get $x) @@ -155,22 +151,19 @@ ;; CHECK: (func $read-g-with-effectful-call-indirect (type $3) (param $ref (ref $throw-type)) (result i32) ;; CHECK-NEXT: (local $x i32) - ;; CHECK-NEXT: (local.set $x - ;; CHECK-NEXT: (global.get $g) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call_indirect $t (type $throw-type) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (global.get $g) ;; CHECK-NEXT: ) (func $read-g-with-effectful-call-indirect (param $ref (ref $throw-type)) (result i32) (local $x i32) (local.set $x (global.get $g)) - ;; Similar to above, except here we can tell that the indirect call may - ;; throw so optimization is halted. + ;; Sinking across a potentially throwing call is valid here. (drop (call_indirect (type $throw-type) (i32.const 0))) (local.get $x)