summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/OptimizeCasts.cpp10
-rw-r--r--test/lit/passes/optimize-casts-noeh.wast18
-rw-r--r--test/lit/passes/optimize-casts.wast83
3 files changed, 90 insertions, 21 deletions
diff --git a/src/passes/OptimizeCasts.cpp b/src/passes/OptimizeCasts.cpp
index e4d7b1647..599e403ff 100644
--- a/src/passes/OptimizeCasts.cpp
+++ b/src/passes/OptimizeCasts.cpp
@@ -423,6 +423,16 @@ struct BestCastFinder : public LinearExecutionWalker<BestCastFinder> {
self->mostCastedGets.clear();
}
+ // It is ok to look at adjacent blocks together, as if a later part of a block
+ // is not reached that is fine - changes we make there would not be reached in
+ // that case.
+ //
+ // Note that we *cannot* do the same in EarlyCastFinder, as it modifies the
+ // earlier code in a dangerous way: it may move a trap to an earlier position.
+ // We cannot move a trap before a branch, as perhaps the branch is all that
+ // prevented us from trapping.
+ bool connectAdjacentBlocks = true;
+
void visitLocalSet(LocalSet* curr) {
// Clear any information about this local; it has a new value here.
mostCastedGets.erase(curr->index);
diff --git a/test/lit/passes/optimize-casts-noeh.wast b/test/lit/passes/optimize-casts-noeh.wast
index 46d92953d..6cd6fa704 100644
--- a/test/lit/passes/optimize-casts-noeh.wast
+++ b/test/lit/passes/optimize-casts-noeh.wast
@@ -34,26 +34,28 @@
)
)
- ;; CHECK: (func $not-past-return_call (type $ref|struct|_=>_none) (param $x (ref struct))
+ ;; CHECK: (func $yes-past-return_call (type $ref|struct|_=>_none) (param $x (ref struct))
+ ;; CHECK-NEXT: (local $1 (ref $A))
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (ref.cast $A
- ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (local.tee $1
+ ;; CHECK-NEXT: (ref.cast $A
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (return_call $none)
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- (func $not-past-return_call (param $x (ref struct))
+ (func $yes-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).
+ ;; The call_return in the middle does not stop us from optimizing, since
+ ;; after we branch out it doesn't matter what we have below.
(return_call $none)
(drop
(local.get $x)
diff --git a/test/lit/passes/optimize-casts.wast b/test/lit/passes/optimize-casts.wast
index 83cde8a4b..254daedc4 100644
--- a/test/lit/passes/optimize-casts.wast
+++ b/test/lit/passes/optimize-casts.wast
@@ -177,28 +177,30 @@
)
)
- ;; CHECK: (func $not-past-call (type $ref|struct|_=>_none) (param $x (ref 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: (ref.cast $A
- ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (local.tee $1
+ ;; CHECK-NEXT: (ref.cast $A
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $get)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- (func $not-past-call (param $x (ref struct))
+ (func $yes-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).
+ ;; The call in the middle does not stops us from helping the last get, since
+ ;; if we branch out it doesn't matter what we have below.
(drop
(call $get)
)
@@ -208,16 +210,19 @@
)
;; CHECK: (func $not-past-call_ref (type $ref|struct|_=>_none) (param $x (ref struct))
+ ;; CHECK-NEXT: (local $1 (ref $A))
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (ref.cast $A
- ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (local.tee $1
+ ;; CHECK-NEXT: (ref.cast $A
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
;; 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: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $not-past-call_ref (param $x (ref struct))
@@ -226,8 +231,7 @@
(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).
+ ;; As in the last function, but a call_ref.
(call_ref $void
(ref.func $void)
)
@@ -236,6 +240,59 @@
)
)
+ ;; CHECK: (func $not-backwards-past-call (type $ref|struct|_=>_none) (param $x (ref struct))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (call $void)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.cast $A
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $not-backwards-past-call (param $x (ref struct))
+ ;; As above, but here we would like to move a cast *earlier*. We must not do
+ ;; that past a possible branch.
+ (drop
+ (local.get $x)
+ )
+ (call $void)
+ (drop
+ (ref.cast $A
+ (local.get $x)
+ )
+ )
+ )
+
+ ;; CHECK: (func $not-backwards-past-call_ref (type $ref|struct|_=>_none) (param $x (ref struct))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (call_ref $void
+ ;; CHECK-NEXT: (ref.func $void)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.cast $A
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $not-backwards-past-call_ref (param $x (ref struct))
+ ;; As above, but with a call_ref.
+ (drop
+ (local.get $x)
+ )
+ (call_ref $void
+ (ref.func $void)
+ )
+ (drop
+ (ref.cast $A
+ (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))