diff options
-rw-r--r-- | src/passes/OptimizeCasts.cpp | 10 | ||||
-rw-r--r-- | test/lit/passes/optimize-casts-noeh.wast | 18 | ||||
-rw-r--r-- | test/lit/passes/optimize-casts.wast | 83 |
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)) |