summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ir/drop.cpp10
-rw-r--r--test/lit/passes/optimize-instructions-gc.wast43
2 files changed, 46 insertions, 7 deletions
diff --git a/src/ir/drop.cpp b/src/ir/drop.cpp
index 49bff55f7..5a860fa29 100644
--- a/src/ir/drop.cpp
+++ b/src/ir/drop.cpp
@@ -59,7 +59,12 @@ Expression* getDroppedChildrenAndAppend(Expression* curr,
if (effects.hasUnremovableSideEffects() || curr->is<If>() ||
curr->is<Try>() || curr->is<Pop>() ||
BranchUtils::getDefinedName(curr).is()) {
- return builder.makeSequence(builder.makeDrop(curr), last);
+ // If curr is concrete we must drop it. Or, if it is unreachable or none,
+ // then we can leave it as it is.
+ if (curr->type.isConcrete()) {
+ curr = builder.makeDrop(curr);
+ }
+ return builder.makeSequence(curr, last);
}
std::vector<Expression*> contents;
@@ -67,11 +72,10 @@ Expression* getDroppedChildrenAndAppend(Expression* curr,
if (!EffectAnalyzer(options, wasm, child).hasUnremovableSideEffects()) {
continue;
}
+ // See above.
if (child->type.isConcrete()) {
contents.push_back(builder.makeDrop(child));
} else {
- // The child is unreachable, or none (none is possible as a child of a
- // block or loop, etc.); in both cases we do not need a drop.
contents.push_back(child);
}
}
diff --git a/test/lit/passes/optimize-instructions-gc.wast b/test/lit/passes/optimize-instructions-gc.wast
index ff880b475..c7238b353 100644
--- a/test/lit/passes/optimize-instructions-gc.wast
+++ b/test/lit/passes/optimize-instructions-gc.wast
@@ -28,17 +28,17 @@
(type $B (struct_subtype (field i32) (field i32) (field f32) $A))
+ ;; CHECK: (type $void (func))
+
;; CHECK: (type $B-child (struct_subtype (field i32) (field i32) (field f32) (field i64) $B))
+ ;; NOMNL: (type $void (func))
+
;; NOMNL: (type $B-child (struct_subtype (field i32) (field i32) (field f32) (field i64) $B))
(type $B-child (struct_subtype (field i32) (field i32) (field f32) (field i64) $B))
(type $empty (struct))
- ;; CHECK: (type $void (func))
-
;; CHECK: (type $C (struct_subtype (field i32) (field i32) (field f64) $A))
- ;; NOMNL: (type $void (func))
-
;; NOMNL: (type $C (struct_subtype (field i32) (field i32) (field f64) $A))
(type $C (struct_subtype (field i32) (field i32) (field f64) $A))
@@ -3157,4 +3157,39 @@
)
)
)
+
+ ;; CHECK: (func $struct.set.null.fallthrough (type $void)
+ ;; CHECK-NEXT: (local $temp (ref null $struct))
+ ;; CHECK-NEXT: (struct.set $struct $i8
+ ;; CHECK-NEXT: (local.tee $temp
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 100)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; NOMNL: (func $struct.set.null.fallthrough (type $void)
+ ;; NOMNL-NEXT: (local $temp (ref null $struct))
+ ;; NOMNL-NEXT: (struct.set $struct $i8
+ ;; NOMNL-NEXT: (local.tee $temp
+ ;; NOMNL-NEXT: (ref.null none)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (i32.const 100)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (unreachable)
+ ;; NOMNL-NEXT: )
+ (func $struct.set.null.fallthrough
+ (local $temp (ref null $struct))
+ ;; The value falling through the tee shows the local.set will trap. We can
+ ;; append an unreachable after it. While doing so we must not emit a drop of
+ ;; the struct.set (which would be valid for a struct.get etc.).
+ (struct.set $struct 0
+ (local.tee $temp
+ (ref.as_non_null
+ (ref.null none)
+ )
+ )
+ (i32.const 100)
+ )
+ )
)