diff options
-rw-r--r-- | src/ir/effects.h | 1 | ||||
-rw-r--r-- | test/lit/passes/global-effects-O.wast | 376 |
2 files changed, 296 insertions, 81 deletions
diff --git a/src/ir/effects.h b/src/ir/effects.h index 28de83850..46138d03c 100644 --- a/src/ir/effects.h +++ b/src/ir/effects.h @@ -364,6 +364,7 @@ public: isAtomic = isAtomic || other.isAtomic; throws_ = throws_ || other.throws_; danglingPop = danglingPop || other.danglingPop; + mayNotReturn = mayNotReturn || other.mayNotReturn; for (auto i : other.localsRead) { localsRead.insert(i); } diff --git a/test/lit/passes/global-effects-O.wast b/test/lit/passes/global-effects-O.wast index c7ba06781..ef2cf62e0 100644 --- a/test/lit/passes/global-effects-O.wast +++ b/test/lit/passes/global-effects-O.wast @@ -11,31 +11,38 @@ (module ;; CHECK_0: (type $0 (func)) - ;; CHECK_0: (type $1 (func (result i32))) + ;; CHECK_0: (type $1 (func (param i32) (result i32))) ;; CHECK_0: (export "main" (func $main)) ;; CHECK_1: (type $0 (func)) - ;; CHECK_1: (type $1 (func (result i32))) + ;; CHECK_1: (type $1 (func (param i32) (result i32))) ;; CHECK_1: (export "main" (func $main)) ;; CHECK_3: (type $0 (func)) - ;; CHECK_3: (type $1 (func (result i32))) + ;; CHECK_3: (type $1 (func (param i32) (result i32))) ;; CHECK_3: (export "main" (func $main)) ;; CHECK_s: (type $0 (func)) - ;; CHECK_s: (type $1 (func (result i32))) + ;; CHECK_s: (type $1 (func (param i32) (result i32))) ;; CHECK_s: (export "main" (func $main)) ;; CHECK_O: (type $0 (func)) - ;; CHECK_O: (type $1 (func (result i32))) + ;; CHECK_O: (type $1 (func (param i32) (result i32))) ;; CHECK_O: (export "main" (func $main)) (export "main" (func $main)) + ;; CHECK_0: (export "main-infinite" (func $main-infinite)) + ;; CHECK_1: (export "main-infinite" (func $main-infinite)) + ;; CHECK_3: (export "main-infinite" (func $main-infinite)) + ;; CHECK_s: (export "main-infinite" (func $main-infinite)) + ;; CHECK_O: (export "main-infinite" (func $main-infinite)) + (export "main-infinite" (func $main-infinite)) + ;; CHECK_0: (export "pointless-work" (func $pointless-work)) ;; CHECK_1: (export "pointless-work" (func $pointless-work)) ;; CHECK_3: (export "pointless-work" (func $pointless-work)) @@ -45,10 +52,14 @@ ;; CHECK_0: (func $main (type $0) ;; CHECK_0-NEXT: (if - ;; CHECK_0-NEXT: (call $pointless-work) + ;; CHECK_0-NEXT: (call $pointless-work + ;; CHECK_0-NEXT: (i32.const 0) + ;; CHECK_0-NEXT: ) ;; CHECK_0-NEXT: (then ;; CHECK_0-NEXT: (drop - ;; CHECK_0-NEXT: (call $pointless-work) + ;; CHECK_0-NEXT: (call $pointless-work + ;; CHECK_0-NEXT: (i32.const 1) + ;; CHECK_0-NEXT: ) ;; CHECK_0-NEXT: ) ;; CHECK_0-NEXT: ) ;; CHECK_0-NEXT: ) @@ -70,17 +81,248 @@ ;; effects we can see that it is pointless and remove this entire if (except ;; for -O0). (if - (call $pointless-work) + (call $pointless-work + (i32.const 0) + ) (then (drop - (call $pointless-work) + (call $pointless-work + (i32.const 1) + ) ) ) ) ) - ;; CHECK_0: (func $pointless-work (type $1) (result i32) - ;; CHECK_0-NEXT: (local $x i32) + ;; CHECK_0: (func $main-infinite (type $0) + ;; CHECK_0-NEXT: (if + ;; CHECK_0-NEXT: (call $infinite-work + ;; CHECK_0-NEXT: (i32.const 0) + ;; CHECK_0-NEXT: ) + ;; CHECK_0-NEXT: (then + ;; CHECK_0-NEXT: (drop + ;; CHECK_0-NEXT: (call $infinite-work + ;; CHECK_0-NEXT: (i32.const 1) + ;; CHECK_0-NEXT: ) + ;; CHECK_0-NEXT: ) + ;; CHECK_0-NEXT: ) + ;; CHECK_0-NEXT: ) + ;; CHECK_0-NEXT: ) + ;; CHECK_1: (func $main-infinite (type $0) + ;; CHECK_1-NEXT: (if + ;; CHECK_1-NEXT: (call $infinite-work + ;; CHECK_1-NEXT: (i32.const 0) + ;; CHECK_1-NEXT: ) + ;; CHECK_1-NEXT: (then + ;; CHECK_1-NEXT: (drop + ;; CHECK_1-NEXT: (call $infinite-work + ;; CHECK_1-NEXT: (i32.const 1) + ;; CHECK_1-NEXT: ) + ;; CHECK_1-NEXT: ) + ;; CHECK_1-NEXT: ) + ;; CHECK_1-NEXT: ) + ;; CHECK_1-NEXT: ) + ;; CHECK_3: (func $main-infinite (type $0) + ;; CHECK_3-NEXT: (if + ;; CHECK_3-NEXT: (call $infinite-work + ;; CHECK_3-NEXT: (i32.const 0) + ;; CHECK_3-NEXT: ) + ;; CHECK_3-NEXT: (then + ;; CHECK_3-NEXT: (drop + ;; CHECK_3-NEXT: (call $infinite-work + ;; CHECK_3-NEXT: (i32.const 1) + ;; CHECK_3-NEXT: ) + ;; CHECK_3-NEXT: ) + ;; CHECK_3-NEXT: ) + ;; CHECK_3-NEXT: ) + ;; CHECK_3-NEXT: ) + ;; CHECK_s: (func $main-infinite (type $0) + ;; CHECK_s-NEXT: (if + ;; CHECK_s-NEXT: (call $infinite-work + ;; CHECK_s-NEXT: (i32.const 0) + ;; CHECK_s-NEXT: ) + ;; CHECK_s-NEXT: (then + ;; CHECK_s-NEXT: (drop + ;; CHECK_s-NEXT: (call $infinite-work + ;; CHECK_s-NEXT: (i32.const 1) + ;; CHECK_s-NEXT: ) + ;; CHECK_s-NEXT: ) + ;; CHECK_s-NEXT: ) + ;; CHECK_s-NEXT: ) + ;; CHECK_s-NEXT: ) + ;; CHECK_O: (func $main-infinite (type $0) + ;; CHECK_O-NEXT: (if + ;; CHECK_O-NEXT: (call $infinite-work + ;; CHECK_O-NEXT: (i32.const 0) + ;; CHECK_O-NEXT: ) + ;; CHECK_O-NEXT: (then + ;; CHECK_O-NEXT: (drop + ;; CHECK_O-NEXT: (call $infinite-work + ;; CHECK_O-NEXT: (i32.const 1) + ;; CHECK_O-NEXT: ) + ;; CHECK_O-NEXT: ) + ;; CHECK_O-NEXT: ) + ;; CHECK_O-NEXT: ) + ;; CHECK_O-NEXT: ) + (func $main-infinite + ;; We cannot remove in this case as the pointless work may have an infinite + ;; loop, which we do not eliminate. + (if + (call $infinite-work + (i32.const 0) + ) + (then + (drop + (call $infinite-work + (i32.const 1) + ) + ) + ) + ) + ) + + ;; CHECK_0: (func $pointless-work (type $1) (param $x i32) (result i32) + ;; CHECK_0-NEXT: (local.set $x + ;; CHECK_0-NEXT: (i32.add + ;; CHECK_0-NEXT: (local.get $x) + ;; CHECK_0-NEXT: (i32.const 1) + ;; CHECK_0-NEXT: ) + ;; CHECK_0-NEXT: ) + ;; CHECK_0-NEXT: (if + ;; CHECK_0-NEXT: (i32.ge_u + ;; CHECK_0-NEXT: (local.get $x) + ;; CHECK_0-NEXT: (i32.const 12345678) + ;; CHECK_0-NEXT: ) + ;; CHECK_0-NEXT: (then + ;; CHECK_0-NEXT: (local.set $x + ;; CHECK_0-NEXT: (i32.add + ;; CHECK_0-NEXT: (local.get $x) + ;; CHECK_0-NEXT: (i32.const 1) + ;; CHECK_0-NEXT: ) + ;; CHECK_0-NEXT: ) + ;; CHECK_0-NEXT: ) + ;; CHECK_0-NEXT: ) + ;; CHECK_0-NEXT: (return + ;; CHECK_0-NEXT: (local.get $x) + ;; CHECK_0-NEXT: ) + ;; CHECK_0-NEXT: ) + ;; CHECK_1: (func $pointless-work (type $1) (param $0 i32) (result i32) + ;; CHECK_1-NEXT: (if (result i32) + ;; CHECK_1-NEXT: (i32.ge_u + ;; CHECK_1-NEXT: (local.tee $0 + ;; CHECK_1-NEXT: (i32.add + ;; CHECK_1-NEXT: (local.get $0) + ;; CHECK_1-NEXT: (i32.const 1) + ;; CHECK_1-NEXT: ) + ;; CHECK_1-NEXT: ) + ;; CHECK_1-NEXT: (i32.const 12345678) + ;; CHECK_1-NEXT: ) + ;; CHECK_1-NEXT: (then + ;; CHECK_1-NEXT: (i32.add + ;; CHECK_1-NEXT: (local.get $0) + ;; CHECK_1-NEXT: (i32.const 1) + ;; CHECK_1-NEXT: ) + ;; CHECK_1-NEXT: ) + ;; CHECK_1-NEXT: (else + ;; CHECK_1-NEXT: (local.get $0) + ;; CHECK_1-NEXT: ) + ;; CHECK_1-NEXT: ) + ;; CHECK_1-NEXT: ) + ;; CHECK_3: (func $pointless-work (type $1) (param $0 i32) (result i32) + ;; CHECK_3-NEXT: (if (result i32) + ;; CHECK_3-NEXT: (i32.ge_u + ;; CHECK_3-NEXT: (local.tee $0 + ;; CHECK_3-NEXT: (i32.add + ;; CHECK_3-NEXT: (local.get $0) + ;; CHECK_3-NEXT: (i32.const 1) + ;; CHECK_3-NEXT: ) + ;; CHECK_3-NEXT: ) + ;; CHECK_3-NEXT: (i32.const 12345678) + ;; CHECK_3-NEXT: ) + ;; CHECK_3-NEXT: (then + ;; CHECK_3-NEXT: (i32.add + ;; CHECK_3-NEXT: (local.get $0) + ;; CHECK_3-NEXT: (i32.const 1) + ;; CHECK_3-NEXT: ) + ;; CHECK_3-NEXT: ) + ;; CHECK_3-NEXT: (else + ;; CHECK_3-NEXT: (local.get $0) + ;; CHECK_3-NEXT: ) + ;; CHECK_3-NEXT: ) + ;; CHECK_3-NEXT: ) + ;; CHECK_s: (func $pointless-work (type $1) (param $0 i32) (result i32) + ;; CHECK_s-NEXT: (if (result i32) + ;; CHECK_s-NEXT: (i32.ge_u + ;; CHECK_s-NEXT: (local.tee $0 + ;; CHECK_s-NEXT: (i32.add + ;; CHECK_s-NEXT: (local.get $0) + ;; CHECK_s-NEXT: (i32.const 1) + ;; CHECK_s-NEXT: ) + ;; CHECK_s-NEXT: ) + ;; CHECK_s-NEXT: (i32.const 12345678) + ;; CHECK_s-NEXT: ) + ;; CHECK_s-NEXT: (then + ;; CHECK_s-NEXT: (i32.add + ;; CHECK_s-NEXT: (local.get $0) + ;; CHECK_s-NEXT: (i32.const 1) + ;; CHECK_s-NEXT: ) + ;; CHECK_s-NEXT: ) + ;; CHECK_s-NEXT: (else + ;; CHECK_s-NEXT: (local.get $0) + ;; CHECK_s-NEXT: ) + ;; CHECK_s-NEXT: ) + ;; CHECK_s-NEXT: ) + ;; CHECK_O: (func $pointless-work (type $1) (param $0 i32) (result i32) + ;; CHECK_O-NEXT: (if (result i32) + ;; CHECK_O-NEXT: (i32.ge_u + ;; CHECK_O-NEXT: (local.tee $0 + ;; CHECK_O-NEXT: (i32.add + ;; CHECK_O-NEXT: (local.get $0) + ;; CHECK_O-NEXT: (i32.const 1) + ;; CHECK_O-NEXT: ) + ;; CHECK_O-NEXT: ) + ;; CHECK_O-NEXT: (i32.const 12345678) + ;; CHECK_O-NEXT: ) + ;; CHECK_O-NEXT: (then + ;; CHECK_O-NEXT: (i32.add + ;; CHECK_O-NEXT: (local.get $0) + ;; CHECK_O-NEXT: (i32.const 1) + ;; CHECK_O-NEXT: ) + ;; CHECK_O-NEXT: ) + ;; CHECK_O-NEXT: (else + ;; CHECK_O-NEXT: (local.get $0) + ;; CHECK_O-NEXT: ) + ;; CHECK_O-NEXT: ) + ;; CHECK_O-NEXT: ) + (func $pointless-work (param $x i32) (result i32) + ;; Some pointless work, with no side effects, that cannot be inlined. (The + ;; changes here are not important for this test.) + (local.set $x + (i32.add + (local.get $x) + (i32.const 1) + ) + ) + (if + (i32.ge_u + (local.get $x) + (i32.const 12345678) + ) + (then + (local.set $x + (i32.add + (local.get $x) + (i32.const 1) + ) + ) + ) + ) + (return + (local.get $x) + ) + ) + + ;; CHECK_0: (func $infinite-work (type $1) (param $x i32) (result i32) ;; CHECK_0-NEXT: (loop $loop ;; CHECK_0-NEXT: (local.set $x ;; CHECK_0-NEXT: (i32.add @@ -88,92 +330,70 @@ ;; CHECK_0-NEXT: (i32.const 1) ;; CHECK_0-NEXT: ) ;; CHECK_0-NEXT: ) - ;; CHECK_0-NEXT: (if - ;; CHECK_0-NEXT: (i32.ge_u - ;; CHECK_0-NEXT: (local.get $x) - ;; CHECK_0-NEXT: (i32.const 12345678) - ;; CHECK_0-NEXT: ) - ;; CHECK_0-NEXT: (then - ;; CHECK_0-NEXT: (return - ;; CHECK_0-NEXT: (local.get $x) - ;; CHECK_0-NEXT: ) - ;; CHECK_0-NEXT: ) + ;; CHECK_0-NEXT: (br_if $loop + ;; CHECK_0-NEXT: (local.get $x) ;; CHECK_0-NEXT: ) - ;; CHECK_0-NEXT: (br $loop) + ;; CHECK_0-NEXT: ) + ;; CHECK_0-NEXT: (return + ;; CHECK_0-NEXT: (local.get $x) ;; CHECK_0-NEXT: ) ;; CHECK_0-NEXT: ) - ;; CHECK_1: (func $pointless-work (type $1) (result i32) - ;; CHECK_1-NEXT: (local $0 i32) - ;; CHECK_1-NEXT: (loop $loop (result i32) + ;; CHECK_1: (func $infinite-work (type $1) (param $0 i32) (result i32) + ;; CHECK_1-NEXT: (loop $loop ;; CHECK_1-NEXT: (br_if $loop - ;; CHECK_1-NEXT: (i32.lt_u - ;; CHECK_1-NEXT: (local.tee $0 - ;; CHECK_1-NEXT: (i32.add - ;; CHECK_1-NEXT: (local.get $0) - ;; CHECK_1-NEXT: (i32.const 1) - ;; CHECK_1-NEXT: ) + ;; CHECK_1-NEXT: (local.tee $0 + ;; CHECK_1-NEXT: (i32.add + ;; CHECK_1-NEXT: (local.get $0) + ;; CHECK_1-NEXT: (i32.const 1) ;; CHECK_1-NEXT: ) - ;; CHECK_1-NEXT: (i32.const 12345678) ;; CHECK_1-NEXT: ) ;; CHECK_1-NEXT: ) - ;; CHECK_1-NEXT: (local.get $0) ;; CHECK_1-NEXT: ) + ;; CHECK_1-NEXT: (local.get $0) ;; CHECK_1-NEXT: ) - ;; CHECK_3: (func $pointless-work (type $1) (result i32) - ;; CHECK_3-NEXT: (local $0 i32) - ;; CHECK_3-NEXT: (loop $loop (result i32) + ;; CHECK_3: (func $infinite-work (type $1) (param $0 i32) (result i32) + ;; CHECK_3-NEXT: (loop $loop ;; CHECK_3-NEXT: (br_if $loop - ;; CHECK_3-NEXT: (i32.lt_u - ;; CHECK_3-NEXT: (local.tee $0 - ;; CHECK_3-NEXT: (i32.add - ;; CHECK_3-NEXT: (local.get $0) - ;; CHECK_3-NEXT: (i32.const 1) - ;; CHECK_3-NEXT: ) + ;; CHECK_3-NEXT: (local.tee $0 + ;; CHECK_3-NEXT: (i32.add + ;; CHECK_3-NEXT: (local.get $0) + ;; CHECK_3-NEXT: (i32.const 1) ;; CHECK_3-NEXT: ) - ;; CHECK_3-NEXT: (i32.const 12345678) ;; CHECK_3-NEXT: ) ;; CHECK_3-NEXT: ) - ;; CHECK_3-NEXT: (local.get $0) ;; CHECK_3-NEXT: ) + ;; CHECK_3-NEXT: (local.get $0) ;; CHECK_3-NEXT: ) - ;; CHECK_s: (func $pointless-work (type $1) (result i32) - ;; CHECK_s-NEXT: (local $0 i32) - ;; CHECK_s-NEXT: (loop $loop (result i32) + ;; CHECK_s: (func $infinite-work (type $1) (param $0 i32) (result i32) + ;; CHECK_s-NEXT: (loop $loop ;; CHECK_s-NEXT: (br_if $loop - ;; CHECK_s-NEXT: (i32.lt_u - ;; CHECK_s-NEXT: (local.tee $0 - ;; CHECK_s-NEXT: (i32.add - ;; CHECK_s-NEXT: (local.get $0) - ;; CHECK_s-NEXT: (i32.const 1) - ;; CHECK_s-NEXT: ) + ;; CHECK_s-NEXT: (local.tee $0 + ;; CHECK_s-NEXT: (i32.add + ;; CHECK_s-NEXT: (local.get $0) + ;; CHECK_s-NEXT: (i32.const 1) ;; CHECK_s-NEXT: ) - ;; CHECK_s-NEXT: (i32.const 12345678) ;; CHECK_s-NEXT: ) ;; CHECK_s-NEXT: ) - ;; CHECK_s-NEXT: (local.get $0) ;; CHECK_s-NEXT: ) + ;; CHECK_s-NEXT: (local.get $0) ;; CHECK_s-NEXT: ) - ;; CHECK_O: (func $pointless-work (type $1) (result i32) - ;; CHECK_O-NEXT: (local $0 i32) - ;; CHECK_O-NEXT: (loop $loop (result i32) + ;; CHECK_O: (func $infinite-work (type $1) (param $0 i32) (result i32) + ;; CHECK_O-NEXT: (loop $loop ;; CHECK_O-NEXT: (br_if $loop - ;; CHECK_O-NEXT: (i32.lt_u - ;; CHECK_O-NEXT: (local.tee $0 - ;; CHECK_O-NEXT: (i32.add - ;; CHECK_O-NEXT: (local.get $0) - ;; CHECK_O-NEXT: (i32.const 1) - ;; CHECK_O-NEXT: ) + ;; CHECK_O-NEXT: (local.tee $0 + ;; CHECK_O-NEXT: (i32.add + ;; CHECK_O-NEXT: (local.get $0) + ;; CHECK_O-NEXT: (i32.const 1) ;; CHECK_O-NEXT: ) - ;; CHECK_O-NEXT: (i32.const 12345678) ;; CHECK_O-NEXT: ) ;; CHECK_O-NEXT: ) - ;; CHECK_O-NEXT: (local.get $0) ;; CHECK_O-NEXT: ) + ;; CHECK_O-NEXT: (local.get $0) ;; CHECK_O-NEXT: ) - (func $pointless-work (result i32) - (local $x i32) - ;; Some pointless work, with no side effects, that cannot be inlined. (The - ;; changes here are not important for this test.) + (func $infinite-work (param $x i32) (result i32) + ;; Some work with no side effects aside from that it appears to potentially + ;; do infinite work, due to a loop. (The changes here are not important for + ;; this test.) (loop $loop (local.set $x (i32.add @@ -181,18 +401,12 @@ (i32.const 1) ) ) - (if - (i32.ge_u - (local.get $x) - (i32.const 12345678) - ) - (then - (return - (local.get $x) - ) - ) + (br_if $loop + (local.get $x) ) - (br $loop) + ) + (return + (local.get $x) ) ) ) |