diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/lit/passes/directize_all-features.wast | 25 | ||||
-rw-r--r-- | test/lit/passes/optimize-instructions-call_ref.wast | 203 | ||||
-rw-r--r-- | test/passes/Oz_fuzz-exec_all-features.txt | 4 |
3 files changed, 206 insertions, 26 deletions
diff --git a/test/lit/passes/directize_all-features.wast b/test/lit/passes/directize_all-features.wast index d9010a76d..54cf07556 100644 --- a/test/lit/passes/directize_all-features.wast +++ b/test/lit/passes/directize_all-features.wast @@ -494,28 +494,3 @@ ) ) ) -;; call_ref -(module - ;; CHECK: (type $i32_i32_=>_none (func (param i32 i32))) - - ;; CHECK: (func $foo (param $0 i32) (param $1 i32) - ;; CHECK-NEXT: (unreachable) - ;; CHECK-NEXT: ) - (func $foo (param i32) (param i32) - (unreachable) - ) - ;; CHECK: (func $bar (param $x i32) (param $y i32) - ;; CHECK-NEXT: (call $foo - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: (local.get $y) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - (func $bar (param $x i32) (param $y i32) - (call_ref - (local.get $x) - (local.get $y) - (ref.func $foo) - ) - ) -) - diff --git a/test/lit/passes/optimize-instructions-call_ref.wast b/test/lit/passes/optimize-instructions-call_ref.wast new file mode 100644 index 000000000..0a45b9e4d --- /dev/null +++ b/test/lit/passes/optimize-instructions-call_ref.wast @@ -0,0 +1,203 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. +;; NOTE: This test was ported using port_test.py and could be cleaned up. + +;; RUN: wasm-opt %s --remove-unused-names --optimize-instructions --all-features -S -o - | filecheck %s +;; remove-unused-names is to allow fallthrough computations to work on blocks + +(module + ;; CHECK: (type $i32_i32_=>_none (func (param i32 i32))) + (type $i32_i32_=>_none (func (param i32 i32))) + + ;; CHECK: (type $none_=>_i32 (func (result i32))) + (type $none_=>_i32 (func (result i32))) + + ;; CHECK: (type $none_=>_none (func)) + (type $none_=>_none (func)) + + ;; CHECK: (type $data_=>_none (func (param dataref))) + (type $data_=>_none (func (param (ref data)))) + + ;; CHECK: (type $i32_=>_none (func (param i32))) + + ;; CHECK: (elem declare func $fallthrough-no-params $fallthrough-non-nullable $foo $return-nothing) + + ;; CHECK: (func $foo (param $0 i32) (param $1 i32) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + (func $foo (param i32) (param i32) + (unreachable) + ) + ;; CHECK: (func $call_ref-to-direct (param $x i32) (param $y i32) + ;; CHECK-NEXT: (call $foo + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $call_ref-to-direct (param $x i32) (param $y i32) + ;; This call_ref should become a direct call. + (call_ref + (local.get $x) + (local.get $y) + (ref.func $foo) + ) + ) + + ;; CHECK: (func $fallthrough (param $x i32) + ;; CHECK-NEXT: (local $1 i32) + ;; CHECK-NEXT: (call $foo + ;; CHECK-NEXT: (local.tee $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (local.set $1 + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block (result (ref $i32_i32_=>_none)) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.func $foo) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $fallthrough (param $x i32) + ;; This call_ref should become a direct call, even though it doesn't have a + ;; simple ref.func as the target - we need to look into the fallthrough, and + ;; handle things with locals. + (call_ref + ;; Write to $x before the block, and write to it in the block; we should not + ;; reorder these things as the side effects could alter what value appears + ;; in the get of $x. (There is a risk of reordering here if we naively moved + ;; the call target (the block) to before the first parameter (the tee). + ;; Instead, we append it after the second param (the get) which keeps the + ;; ordering as it was.) + (local.tee $x + (i32.const 1) + ) + (local.get $x) + (block (result (ref $i32_i32_=>_none)) + (local.set $x + (i32.const 2) + ) + (ref.func $foo) + ) + ) + ) + + ;; CHECK: (func $fallthrough-no-params (result i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block (result (ref $none_=>_i32)) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (ref.func $fallthrough-no-params) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $fallthrough-no-params) + ;; CHECK-NEXT: ) + (func $fallthrough-no-params (result i32) + ;; A fallthrough appears here, but there are no operands so this is easier to + ;; optimize: we can just drop the call_ref's target before the call. + (call_ref + (block (result (ref $none_=>_i32)) + (nop) + (ref.func $fallthrough-no-params) + ) + ) + ) + + ;; CHECK: (func $fallthrough-non-nullable (param $x dataref) + ;; CHECK-NEXT: (local $1 (ref null data)) + ;; CHECK-NEXT: (call $fallthrough-non-nullable + ;; CHECK-NEXT: (block (result dataref) + ;; CHECK-NEXT: (local.set $1 + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block (result (ref $data_=>_none)) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (ref.func $fallthrough-non-nullable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $fallthrough-non-nullable (param $x (ref data)) + ;; A fallthrough appears here, and in addition the last operand is non- + ;; nullable, which means we must be careful when we create a temp local for + ;; it: the local should be nullable, and gets of it should use a + ;; ref.as_non_null so that we validate. + (call_ref + (local.get $x) + (block (result (ref $data_=>_none)) + (nop) + (ref.func $fallthrough-non-nullable) + ) + ) + ) + + ;; CHECK: (func $fallthrough-bad-type (result i32) + ;; CHECK-NEXT: (call_ref + ;; CHECK-NEXT: (ref.cast + ;; CHECK-NEXT: (ref.func $return-nothing) + ;; CHECK-NEXT: (rtt.canon $none_=>_i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $fallthrough-bad-type (result i32) + ;; A fallthrough appears here, and we cast the function type to something else + ;; in a way that is bad: the actual target function has a different return + ;; type than the cast type. The cast will fail at runtime, and we should not + ;; emit non-validating code here, which would happen if we replace the + ;; call_ref that returns nothing with a call that returns an i32. + (call_ref + (ref.cast + (ref.func $return-nothing) + (rtt.canon $none_=>_i32) + ) + ) + ) + + ;; Helper function for the above test. + ;; CHECK: (func $return-nothing + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + (func $return-nothing) + + ;; CHECK: (func $fallthrough-unreachable + ;; CHECK-NEXT: (call_ref + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (block (result (ref $i32_i32_=>_none)) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (ref.func $foo) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $fallthrough-unreachable + ;; If the call is not reached, do not optimize it. + (call_ref + (unreachable) + (unreachable) + (block (result (ref $i32_i32_=>_none)) + (nop) + (ref.func $foo) + ) + ) + ) + + ;; CHECK: (func $ignore-unreachable + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + (func $ignore-unreachable + ;; Ignore an unreachable call_ref target entirely. + (call_ref + (unreachable) + ) + ) +) diff --git a/test/passes/Oz_fuzz-exec_all-features.txt b/test/passes/Oz_fuzz-exec_all-features.txt index b0f4c6448..ddeacdc65 100644 --- a/test/passes/Oz_fuzz-exec_all-features.txt +++ b/test/passes/Oz_fuzz-exec_all-features.txt @@ -351,7 +351,9 @@ (call $log (i32.const 2) ) - (call $a-void-func) + (call $log + (i32.const 1337) + ) (call $log (i32.const 3) ) |