diff options
Diffstat (limited to 'test/lit/passes/signature-pruning.wast')
-rw-r--r-- | test/lit/passes/signature-pruning.wast | 301 |
1 files changed, 270 insertions, 31 deletions
diff --git a/test/lit/passes/signature-pruning.wast b/test/lit/passes/signature-pruning.wast index 4d22ef619..cad9af82b 100644 --- a/test/lit/passes/signature-pruning.wast +++ b/test/lit/passes/signature-pruning.wast @@ -136,7 +136,7 @@ ;; CHECK: (rec ;; CHECK-NEXT: (type $0 (func)) - ;; CHECK: (type $sig (sub (func (param i32 i64 f32)))) + ;; CHECK: (type $sig (sub (func (param i64 f32)))) (type $sig (sub (func (param i32) (param i64) (param f32) (param f64)))) (memory 1 1) @@ -145,19 +145,20 @@ ;; CHECK: (elem declare func $foo) - ;; CHECK: (func $foo (type $sig) (param $0 i32) (param $1 i64) (param $2 f32) - ;; CHECK-NEXT: (local $3 f64) + ;; CHECK: (func $foo (type $sig) (param $0 i64) (param $1 f32) + ;; CHECK-NEXT: (local $2 f64) + ;; CHECK-NEXT: (local $3 i32) ;; CHECK-NEXT: (i64.store ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (f32.store ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: (local.get $2) + ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $foo (type $sig) (param $i32 i32) (param $i64 i64) (param $f32 f32) (param $f64 f64) - ;; Use the middle two parameters. + ;; Use the middle two parameters. The other two vanish. (i64.store (i32.const 0) (local.get $i64) @@ -169,25 +170,29 @@ ) ;; CHECK: (func $caller (type $0) - ;; CHECK-NEXT: (call $foo - ;; CHECK-NEXT: (block (result i32) - ;; CHECK-NEXT: (call $caller) - ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (local $0 i32) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $0 + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (call $caller) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $foo + ;; CHECK-NEXT: (i64.const 1) + ;; CHECK-NEXT: (f32.const 2) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i64.const 1) - ;; CHECK-NEXT: (f32.const 2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (call_ref $sig - ;; CHECK-NEXT: (i32.const 4) ;; CHECK-NEXT: (i64.const 5) ;; CHECK-NEXT: (f32.const 6) ;; CHECK-NEXT: (ref.func $foo) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $caller - ;; As above, but now one of the unused parameters has a side effect which - ;; prevents us from removing it (flattening the IR first would avoid this - ;; limitation). We only end up removing a single unused param, the last. + ;; As above, but now one of the unused parameters has a side effect. We + ;; move it to a local, which allows us to remove it (and also the last, + ;; which is trivial). (call $foo (block (result i32) (call $caller) @@ -207,13 +212,13 @@ ) ) -;; As above, but with the effects on a call_ref. Once more, we can only optimize -;; away the very last param. +;; As above, but with the effects on a call_ref. Once more, we can optimize +;; even with effects on a param, using locals. (module ;; CHECK: (rec ;; CHECK-NEXT: (type $0 (func)) - ;; CHECK: (type $sig (sub (func (param i32 i64 f32)))) + ;; CHECK: (type $sig (sub (func (param i64 f32)))) (type $sig (sub (func (param i32) (param i64) (param f32) (param f64)))) (memory 1 1) @@ -222,15 +227,16 @@ ;; CHECK: (elem declare func $foo) - ;; CHECK: (func $foo (type $sig) (param $0 i32) (param $1 i64) (param $2 f32) - ;; CHECK-NEXT: (local $3 f64) + ;; CHECK: (func $foo (type $sig) (param $0 i64) (param $1 f32) + ;; CHECK-NEXT: (local $2 f64) + ;; CHECK-NEXT: (local $3 i32) ;; CHECK-NEXT: (i64.store ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (f32.store ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: (local.get $2) + ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $foo (type $sig) (param $i32 i32) (param $i64 i64) (param $f32 f32) (param $f64 f64) @@ -245,19 +251,23 @@ ) ;; CHECK: (func $caller (type $0) + ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (call $foo - ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: (i64.const 1) ;; CHECK-NEXT: (f32.const 2) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (call_ref $sig - ;; CHECK-NEXT: (block (result i32) - ;; CHECK-NEXT: (call $caller) - ;; CHECK-NEXT: (i32.const 4) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $0 + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (call $caller) + ;; CHECK-NEXT: (i32.const 4) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call_ref $sig + ;; CHECK-NEXT: (i64.const 5) + ;; CHECK-NEXT: (f32.const 6) + ;; CHECK-NEXT: (ref.func $foo) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i64.const 5) - ;; CHECK-NEXT: (f32.const 6) - ;; CHECK-NEXT: (ref.func $foo) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $caller @@ -912,3 +922,232 @@ (unreachable) ) ) + +;; Test corner cases with var updating. To remove the parameter of $func we +;; must move the parameter to a local first. We must then adjust local types +;; properly while adjusting the signature (when the signature loses a parameter, +;; local indexes change, which is a delicate dance handled by +;; GlobalTypeRewriter::updateSignatures and ParamUtils::removeParameters; +;; moving the parameter to a local first should not get in the way there). +(module + ;; CHECK: (rec + ;; CHECK-NEXT: (type $struct (sub (struct (field v128)))) + (type $struct (sub (struct (field v128)))) + ;; CHECK: (type $1 (func)) + + ;; CHECK: (type $func (func)) + (type $func (func (param v128))) + + ;; CHECK: (elem declare func $func) + + ;; CHECK: (func $func (type $func) + ;; CHECK-NEXT: (local $0 v128) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + (func $func (type $func) (param $0 v128) + ;; The parameter will be removed. + (nop) + ) + + ;; CHECK: (func $caller (type $1) + ;; CHECK-NEXT: (local $0 (ref $struct)) + ;; CHECK-NEXT: (local $1 externref) + ;; CHECK-NEXT: (local $2 v128) + ;; CHECK-NEXT: (local.set $2 + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.tee $0 + ;; CHECK-NEXT: (struct.new_default $struct) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call_ref $func + ;; CHECK-NEXT: (ref.func $func) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $caller (param $param externref) + (local $var (ref $struct)) + ;; The parameter of this call_ref will be removed. + (call_ref $func + ;; Use a struct.get, which would error if the type the nested tee were + ;; incorrect (it asserts on it being a struct type). + (struct.get $struct 0 + ;; Use a tee to test the updating of tee'd vars, as mentioned above. + (local.tee $var + (struct.new_default $struct) + ) + ) + (ref.func $func) + ) + ) +) + +(module + ;; CHECK: (type $0 (func (param i32))) + + ;; CHECK: (rec + ;; CHECK-NEXT: (type $1 (func (param i32))) + + ;; CHECK: (type $2 (func (result i32))) + + ;; CHECK: (type $3 (func (param i32))) + + ;; CHECK: (tag $tag (param i32)) + (tag $tag (param i32)) + + ;; CHECK: (func $catch-pop (type $2) (result i32) + ;; CHECK-NEXT: (local $0 i32) + ;; CHECK-NEXT: (local $1 i32) + ;; CHECK-NEXT: (local $2 i32) + ;; CHECK-NEXT: (block $block (result i32) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch $tag + ;; CHECK-NEXT: (local.set $2 + ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $0 + ;; CHECK-NEXT: (local.get $2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $1 + ;; CHECK-NEXT: (br_if $block + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $target + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $catch-pop (result i32) + (block $block (result i32) + (try $try + (do + (nop) + ) + (catch $tag + (call $target + (pop i32) + ;; We can remove this parameter by moving it to a local first, which + ;; also moves the pop, which then needs to be fixed up. + (br_if $block + (i32.const 1) + (i32.const 2) + ) + ) + ;; This nop causes the call to be in a block. When we add another + ;; block to hold the code that we move, we'd get an error if we don't + ;; apply fixups. + (nop) + ) + ) + (i32.const 3) + ) + ) + + ;; CHECK: (func $target (type $1) (param $0 i32) + ;; CHECK-NEXT: (local $1 i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $target (param $x i32) (param $y i32) + ;; Use only the first param. The second will be removed. + (drop + (local.get $x) + ) + ) +) + +;; As above, but remove the other parameter (the pop). +(module + ;; CHECK: (type $0 (func (param i32))) + + ;; CHECK: (rec + ;; CHECK-NEXT: (type $1 (func (param i32))) + + ;; CHECK: (type $2 (func (result i32))) + + ;; CHECK: (type $3 (func (param i32))) + + ;; CHECK: (tag $tag (param i32)) + (tag $tag (param i32)) + + ;; CHECK: (func $catch-pop (type $2) (result i32) + ;; CHECK-NEXT: (local $0 i32) + ;; CHECK-NEXT: (local $1 i32) + ;; CHECK-NEXT: (local $2 i32) + ;; CHECK-NEXT: (block $block (result i32) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch $tag + ;; CHECK-NEXT: (local.set $2 + ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $0 + ;; CHECK-NEXT: (local.get $2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $1 + ;; CHECK-NEXT: (br_if $block + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $target + ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $catch-pop (result i32) + (block $block (result i32) + (try $try + (do + (nop) + ) + (catch $tag + (call $target + (pop i32) + (br_if $block + (i32.const 1) + (i32.const 2) + ) + ) + (nop) + ) + ) + (i32.const 3) + ) + ) + + ;; CHECK: (func $target (type $1) (param $0 i32) + ;; CHECK-NEXT: (local $1 i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $target (param $x i32) (param $y i32) + (drop + (local.get $y) ;; this changed from $x to $y + ) + ) +) |