diff options
author | Alon Zakai <azakai@google.com> | 2021-07-23 11:17:54 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-23 11:17:54 -0700 |
commit | 501259b4695ad6aaf42ce3f8875c3b8177ef756d (patch) | |
tree | d9abf92bfa3a53089c513cc302c08a5a58402215 /test | |
parent | 464ddbe5faf151b5ef50d56d00ad442ac76620a6 (diff) | |
download | binaryen-501259b4695ad6aaf42ce3f8875c3b8177ef756d.tar.gz binaryen-501259b4695ad6aaf42ce3f8875c3b8177ef756d.tar.bz2 binaryen-501259b4695ad6aaf42ce3f8875c3b8177ef756d.zip |
[Wasm GC] Refine function parameter types (#4014)
If a function is always called with a more specific type than it is declared, we can
make the type more specific.
DeadArgumentElimination's name is becoming increasingly misleading, and should
maybe be renamed. But it is the right place for this as it already does an LTO
scan of the call graph and builds up parameter data structures etc.
Diffstat (limited to 'test')
-rw-r--r-- | test/lit/passes/dae-gc.wast | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/test/lit/passes/dae-gc.wast b/test/lit/passes/dae-gc.wast index 65d65d4c9..b3f8eddd2 100644 --- a/test/lit/passes/dae-gc.wast +++ b/test/lit/passes/dae-gc.wast @@ -2,8 +2,18 @@ ;; RUN: wasm-opt %s -all --dae -S -o - | filecheck %s (module + ;; CHECK: (type ${i32} (struct (field i32))) + ;; CHECK: (type ${} (struct )) (type ${} (struct)) + (type ${i32} (struct (field i32))) + ;; CHECK: (type ${i32_i64} (struct (field i32) (field i64))) + + ;; CHECK: (type ${f64} (struct (field f64))) + (type ${f64} (struct (field f64))) + (type ${i32_i64} (struct (field i32) (field i64))) + ;; CHECK: (type ${i32_f32} (struct (field i32) (field f32))) + (type ${i32_f32} (struct (field i32) (field f32))) ;; CHECK: (func $foo ;; CHECK-NEXT: (call $bar) @@ -67,4 +77,220 @@ (rtt.canon ${}) ) ) + + ;; CHECK: (func $call-various-params-no + ;; CHECK-NEXT: (call $various-params-no + ;; CHECK-NEXT: (ref.null ${}) + ;; CHECK-NEXT: (ref.null ${i32}) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $various-params-no + ;; CHECK-NEXT: (ref.null ${i32}) + ;; CHECK-NEXT: (ref.null ${f64}) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $call-various-params-no + ;; The first argument gets {} and {i32}; the second {i32} and {f64}; none of + ;; those pairs can be optimized. + (call $various-params-no + (ref.null ${}) + (ref.null ${i32}) + ) + (call $various-params-no + (ref.null ${i32}) + (ref.null ${f64}) + ) + ) + ;; This function is called in ways that do not allow us to alter the types of + ;; its parameters (see last function). + ;; CHECK: (func $various-params-no (param $x (ref null ${})) (param $y (ref null ${})) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $various-params-no (param $x (ref null ${})) (param $y (ref null ${})) + ;; "Use" the locals to avoid other optimizations kicking in. + (drop (local.get $x)) + (drop (local.get $y)) + ) + + ;; CHECK: (func $call-various-params-yes + ;; CHECK-NEXT: (call $various-params-yes + ;; CHECK-NEXT: (ref.null ${i32}) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (ref.null ${i32}) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $various-params-yes + ;; CHECK-NEXT: (ref.null ${i32}) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: (ref.null ${i32_i64}) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $call-various-params-yes + ;; The first argument gets {i32} and {i32}; the second {i32} and {i32_i64}; + ;; both of those pairs can be optimized to {i32}. + ;; There is also an i32 in the middle, which should not confuse us. + (call $various-params-yes + (ref.null ${i32}) + (i32.const 0) + (ref.null ${i32}) + ) + (call $various-params-yes + (ref.null ${i32}) + (i32.const 1) + (ref.null ${i32_i64}) + ) + ) + ;; This function is called in ways that *do* allow us to alter the types of + ;; its parameters (see last function). + ;; CHECK: (func $various-params-yes (param $x (ref null ${i32})) (param $i i32) (param $y (ref null ${i32})) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $i) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $various-params-yes (param $x (ref null ${})) (param $i i32) (param $y (ref null ${})) + ;; "Use" the locals to avoid other optimizations kicking in. + (drop (local.get $x)) + (drop (local.get $i)) + (drop (local.get $y)) + ) + + ;; CHECK: (func $call-various-params-set + ;; CHECK-NEXT: (call $various-params-set + ;; CHECK-NEXT: (ref.null ${i32}) + ;; CHECK-NEXT: (ref.null ${i32}) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $various-params-set + ;; CHECK-NEXT: (ref.null ${i32}) + ;; CHECK-NEXT: (ref.null ${i32_i64}) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $call-various-params-set + ;; The first argument gets {i32} and {i32}; the second {i32} and {i32_i64; + ;; both of those pairs can be optimized to {i32} + (call $various-params-set + (ref.null ${i32}) + (ref.null ${i32}) + ) + (call $various-params-set + (ref.null ${i32}) + (ref.null ${i32_i64}) + ) + ) + ;; This function is called in ways that *do* allow us to alter the types of + ;; its parameters (see last function), however, we reuse the parameters by + ;; writing to them, which causes problems in one case. + ;; CHECK: (func $various-params-set (param $x (ref null ${})) (param $y (ref null ${i32})) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (ref.null ${}) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $y + ;; CHECK-NEXT: (ref.null ${i32_i64}) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $various-params-set (param $x (ref null ${})) (param $y (ref null ${})) + ;; "Use" the locals to avoid other optimizations kicking in. + (drop (local.get $x)) + (drop (local.get $y)) + ;; Write to $x in a way that prevents us making the type more specific. + (local.set $x (ref.null ${})) + ;; Write to $y in a way that still allows us to make the type more specific. + (local.set $y (ref.null ${i32_i64})) + ) + + ;; CHECK: (func $call-various-params-null + ;; CHECK-NEXT: (call $various-params-null + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (ref.null ${i32}) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null ${i32}) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $various-params-null + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (ref.null ${i32}) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (ref.null ${i32}) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $call-various-params-null + ;; The first argument gets non-null values, allowing us to refine it. The + ;; second gets only one. + (call $various-params-null + (ref.as_non_null (ref.null ${i32})) + (ref.null ${i32}) + ) + (call $various-params-null + (ref.as_non_null (ref.null ${i32})) + (ref.as_non_null (ref.null ${i32})) + ) + ) + ;; This function is called in ways that allow us to make the first parameter + ;; non-nullable. + ;; CHECK: (func $various-params-null (param $x (ref ${i32})) (param $y (ref null ${i32})) + ;; CHECK-NEXT: (local $temp i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $temp + ;; CHECK-NEXT: (local.get $temp) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $various-params-null (param $x (ref null ${})) (param $y (ref null ${})) + (local $temp i32) + ;; "Use" the locals to avoid other optimizations kicking in. + (drop (local.get $x)) + (drop (local.get $y)) + ;; Use a local in this function as well, which should be ignored by this pass + ;; (when we scan and update all local.gets and sets, we should only do so on + ;; parameters, and not vars - and we can crash if we scan/update things we + ;; should not). + (local.set $temp (local.get $temp)) + ) + + ;; CHECK: (func $call-various-params-middle + ;; CHECK-NEXT: (call $various-params-middle + ;; CHECK-NEXT: (ref.null ${i32_i64}) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $various-params-middle + ;; CHECK-NEXT: (ref.null ${i32_f32}) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $call-various-params-middle + ;; The argument gets {i32_i64} and {i32_f32}. This allows us to refine from + ;; {} to {i32}, a type "in the middle". + (call $various-params-middle + (ref.null ${i32_i64}) + ) + (call $various-params-middle + (ref.null ${i32_f32}) + ) + ) + ;; CHECK: (func $various-params-middle (param $x (ref null ${i32})) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $various-params-middle (param $x (ref null ${})) + ;; "Use" the local to avoid other optimizations kicking in. + (drop (local.get $x)) + ) ) |