diff options
-rw-r--r-- | src/passes/OptimizeInstructions.cpp | 27 | ||||
-rw-r--r-- | test/lit/passes/optimize-instructions-gc.wast | 91 |
2 files changed, 109 insertions, 9 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index e71506e28..1f55c0a4b 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -992,20 +992,45 @@ struct OptimizeInstructions } } + // If an instruction traps on a null input, there is no need for a + // ref.as_non_null on that input: we will trap either way (and the binaryen + // optimizer does not differentiate traps). + void skipNonNullCast(Expression*& input) { + while (1) { + if (auto* as = input->dynCast<RefAs>()) { + if (as->op == RefAsNonNull) { + input = as->value; + continue; + } + } + break; + } + } + + void visitStructGet(StructGet* curr) { skipNonNullCast(curr->ref); } + void visitStructSet(StructSet* curr) { + skipNonNullCast(curr->ref); + if (curr->ref->type != Type::unreachable && curr->value->type.isInteger()) { const auto& fields = curr->ref->type.getHeapType().getStruct().fields; optimizeStoredValue(curr->value, fields[curr->index].getByteSize()); } } + void visitArrayGet(ArrayGet* curr) { skipNonNullCast(curr->ref); } + void visitArraySet(ArraySet* curr) { + skipNonNullCast(curr->ref); + if (curr->ref->type != Type::unreachable && curr->value->type.isInteger()) { auto element = curr->ref->type.getHeapType().getArray().element; optimizeStoredValue(curr->value, element.getByteSize()); } } + void visitArrayLen(ArrayLen* curr) { skipNonNullCast(curr->ref); } + void visitRefCast(RefCast* curr) { if (curr->type == Type::unreachable) { return; @@ -1110,6 +1135,8 @@ struct OptimizeInstructions return; } + skipNonNullCast(curr->value); + // Check if the type is the kind we are checking for. auto result = GCTypeUtils::evaluateKindCheck(curr); diff --git a/test/lit/passes/optimize-instructions-gc.wast b/test/lit/passes/optimize-instructions-gc.wast index 5c469b617..b00d08193 100644 --- a/test/lit/passes/optimize-instructions-gc.wast +++ b/test/lit/passes/optimize-instructions-gc.wast @@ -386,9 +386,7 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (local.get $data) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $data) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) @@ -396,9 +394,7 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (local.get $i31) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $i31) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) @@ -406,9 +402,7 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (local.get $func) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $func) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) @@ -460,4 +454,83 @@ (ref.as_func (unreachable)) ) ) + + ;; CHECK: (func $redundant-non-null-casts (param $x (ref null $struct)) (param $y (ref null $array)) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.set $struct $i8 + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.get_u $struct $i8 + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (array.set $array + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: (i32.const 3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (array.get_u $array + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: (i32.const 4) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (array.len $array + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $redundant-non-null-casts (param $x (ref null $struct)) (param $y (ref null $array)) + (drop + (ref.as_non_null + (ref.as_non_null + (ref.as_non_null + (local.get $x) + ) + ) + ) + ) + (struct.set $struct 0 + (ref.as_non_null + (local.get $x) + ) + (i32.const 1) + ) + (drop + (struct.get_u $struct 0 + (ref.as_non_null + (local.get $x) + ) + ) + ) + (array.set $array + (ref.as_non_null + (local.get $y) + ) + (i32.const 2) + (i32.const 3) + ) + (drop + (array.get $array + (ref.as_non_null + (local.get $y) + ) + (i32.const 4) + ) + ) + (drop + (array.len $array + (ref.as_non_null + (local.get $y) + ) + ) + ) + ) ) |