summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/OptimizeInstructions.cpp27
-rw-r--r--test/lit/passes/optimize-instructions-gc.wast91
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)
+ )
+ )
+ )
+ )
)