diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/lit/passes/gufa-tnh.wast | 59 | ||||
-rw-r--r-- | test/lit/passes/optimize-casts-noeh.wast | 69 | ||||
-rw-r--r-- | test/lit/passes/optimize-casts.wast | 70 | ||||
-rw-r--r-- | test/lit/passes/simplify-locals-gc.wast | 9 |
4 files changed, 205 insertions, 2 deletions
diff --git a/test/lit/passes/gufa-tnh.wast b/test/lit/passes/gufa-tnh.wast index 79d524cf0..e1dee4773 100644 --- a/test/lit/passes/gufa-tnh.wast +++ b/test/lit/passes/gufa-tnh.wast @@ -1953,3 +1953,62 @@ ) ) ) + +;; Control flow around calls. +(module + ;; CHECK: (type $none_=>_none (func)) + + ;; CHECK: (type $A (struct )) + (type $A (struct)) + + ;; CHECK: (type $B (sub $A (struct ))) + (type $B (sub $A (struct))) + + ;; CHECK: (type $ref?|$A|_=>_none (func (param (ref null $A)))) + + ;; CHECK: (import "a" "b" (func $import-throw (type $none_=>_none))) + (import "a" "b" (func $import-throw)) + + ;; CHECK: (export "a" (func $caller)) + + ;; CHECK: (func $called (type $ref?|$A|_=>_none) (param $0 (ref null $A)) + ;; CHECK-NEXT: (call $import-throw) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.cast $B + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $called (param $0 (ref null $A)) + ;; This function calls an import, and later casts. We cannot use those casts + ;; to infer anything in the callers, since the import might throw (in which + ;; case we'd never reach the cast). + (call $import-throw) + (drop + (ref.cast $B + (local.get $0) + ) + ) + ) + + ;; CHECK: (func $caller (type $none_=>_none) + ;; CHECK-NEXT: (call $called + ;; CHECK-NEXT: (struct.new_default $B) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $called + ;; CHECK-NEXT: (struct.new_default $A) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $caller (export "a") + ;; This call sends a $B which will be cast to $B (assuming the import does + ;; not trap), so nothing should happen here. + (call $called + (struct.new $B) + ) + ;; This call sends an $A, which would fail the cast if it were reached. But + ;; it might not, so we do nothing here. + (call $called + (struct.new $A) + ) + ) +) diff --git a/test/lit/passes/optimize-casts-noeh.wast b/test/lit/passes/optimize-casts-noeh.wast new file mode 100644 index 000000000..46d92953d --- /dev/null +++ b/test/lit/passes/optimize-casts-noeh.wast @@ -0,0 +1,69 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. +;; RUN: wasm-opt %s --optimize-casts --enable-reference-types --enable-gc --enable-tail-call -S -o - | filecheck %s + +(module + ;; CHECK: (type $A (struct )) + (type $A (struct)) + + ;; CHECK: (func $yes-past-call (type $ref|struct|_=>_none) (param $x (ref struct)) + ;; CHECK-NEXT: (local $1 (ref $A)) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.tee $1 + ;; CHECK-NEXT: (ref.cast $A + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $none) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $yes-past-call (param $x (ref struct)) + (drop + (ref.cast $A + (local.get $x) + ) + ) + ;; The call in the middle does not stop us from helping the last get, since + ;; EH is not enabled. The last get will flip from $x to a new tee of the + ;; cast. + (call $none) + (drop + (local.get $x) + ) + ) + + ;; CHECK: (func $not-past-return_call (type $ref|struct|_=>_none) (param $x (ref struct)) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.cast $A + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (return_call $none) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $not-past-return_call (param $x (ref struct)) + (drop + (ref.cast $A + (local.get $x) + ) + ) + ;; The call_return in the middle stops us from helping the last get. We + ;; could still optimize in this case, however, with more precision (since + ;; after we branch out it doesn't matter what we have below). + (return_call $none) + (drop + (local.get $x) + ) + ) + + ;; CHECK: (func $none (type $none_=>_none) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + (func $none + ;; Helper for the above. + ) +) diff --git a/test/lit/passes/optimize-casts.wast b/test/lit/passes/optimize-casts.wast index 4dd839d97..83cde8a4b 100644 --- a/test/lit/passes/optimize-casts.wast +++ b/test/lit/passes/optimize-casts.wast @@ -8,9 +8,13 @@ ;; CHECK: (type $B (sub $A (struct ))) (type $B (struct_subtype $A)) + ;; CHECK: (type $void (func)) + ;; CHECK: (type $D (array (mut i32))) (type $D (array (mut i32))) + (type $void (func)) + ;; CHECK: (global $a (mut i32) (i32.const 0)) (global $a (mut i32) (i32.const 0)) @@ -173,6 +177,65 @@ ) ) + ;; CHECK: (func $not-past-call (type $ref|struct|_=>_none) (param $x (ref struct)) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.cast $A + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (call $get) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $not-past-call (param $x (ref struct)) + (drop + (ref.cast $A + (local.get $x) + ) + ) + ;; The call in the middle stops us from helping the last get, since a call + ;; might branch out. TODO we could still optimize in this case, with more + ;; precision (since if we branch out it doesn't matter what we have below). + (drop + (call $get) + ) + (drop + (local.get $x) + ) + ) + + ;; CHECK: (func $not-past-call_ref (type $ref|struct|_=>_none) (param $x (ref struct)) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.cast $A + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call_ref $void + ;; CHECK-NEXT: (ref.func $void) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $not-past-call_ref (param $x (ref struct)) + (drop + (ref.cast $A + (local.get $x) + ) + ) + ;; As in the last function, the call in the middle stops us from helping the + ;; last get (this time with a call_ref). + (call_ref $void + (ref.func $void) + ) + (drop + (local.get $x) + ) + ) + ;; CHECK: (func $best (type $ref|struct|_=>_none) (param $x (ref struct)) ;; CHECK-NEXT: (local $1 (ref $A)) ;; CHECK-NEXT: (local $2 (ref $B)) @@ -1229,4 +1292,11 @@ ;; Helper for the above. (unreachable) ) + + ;; CHECK: (func $void (type $void) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + (func $void + ;; Helper for the above. + ) ) diff --git a/test/lit/passes/simplify-locals-gc.wast b/test/lit/passes/simplify-locals-gc.wast index 6b2b10462..500d12b5a 100644 --- a/test/lit/passes/simplify-locals-gc.wast +++ b/test/lit/passes/simplify-locals-gc.wast @@ -366,7 +366,9 @@ ;; CHECK-NEXT: (local.get $nn-any) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (nop) - ;; CHECK-NEXT: (local.get $nn-any) + ;; CHECK-NEXT: (local.tee $any + ;; CHECK-NEXT: (local.get $nn-any) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $pick-casted (param $any anyref) (result anyref) (local $nn-any (ref any)) @@ -382,7 +384,10 @@ (call $use-nn-any (local.get $nn-any) ) - ;; This copy is not needed, as they hold the same value. + ;; This copy is not needed, as they hold the same value. However, the call + ;; before us inhibits us from optimizing here. TODO: with a more precise + ;; analysis we could optimize this, as if the call branches out it doesn't + ;; matter what happens after it. (local.set $any (local.get $nn-any) ) |