summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/Vacuum.cpp13
-rw-r--r--test/lit/passes/vacuum-gc.wast18
2 files changed, 31 insertions, 0 deletions
diff --git a/src/passes/Vacuum.cpp b/src/passes/Vacuum.cpp
index 44abed27b..84ae5199c 100644
--- a/src/passes/Vacuum.cpp
+++ b/src/passes/Vacuum.cpp
@@ -37,8 +37,18 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> {
TypeUpdater typeUpdater;
+ // The TypeUpdater class handles efficient updating of unreachability as we
+ // go, but we may also refine types, which requires refinalization.
+ bool refinalize = false;
+
Expression* replaceCurrent(Expression* expression) {
auto* old = getCurrent();
+ if (expression->type != old->type &&
+ expression->type != Type::unreachable) {
+ // We are changing this to a new type that is not unreachable, so it is a
+ // refinement that we need to use refinalize to propagate up.
+ refinalize = true;
+ }
super::replaceCurrent(expression);
// also update the type updater
typeUpdater.noteReplacement(old, expression);
@@ -48,6 +58,9 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> {
void doWalkFunction(Function* func) {
typeUpdater.walk(func->body);
walk(func->body);
+ if (refinalize) {
+ ReFinalize().walkFunctionInModule(func, getModule());
+ }
}
// Returns nullptr if curr is dead, curr if it must stay as is, or one of its
diff --git a/test/lit/passes/vacuum-gc.wast b/test/lit/passes/vacuum-gc.wast
index f84988f46..c7ff5a37f 100644
--- a/test/lit/passes/vacuum-gc.wast
+++ b/test/lit/passes/vacuum-gc.wast
@@ -2,6 +2,7 @@
;; RUN: wasm-opt %s --vacuum -all -S -o - | filecheck %s
(module
+ ;; CHECK: (type ${} (struct ))
(type ${} (struct))
;; CHECK: (func $drop-ref-as (type $anyref_=>_none) (param $x anyref)
@@ -92,4 +93,21 @@
)
)
)
+
+ ;; CHECK: (func $ref.cast.null.block (type $ref|${}|_=>_dataref) (param $ref (ref ${})) (result dataref)
+ ;; CHECK-NEXT: (ref.cast ${}
+ ;; CHECK-NEXT: (local.get $ref)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $ref.cast.null.block (param $ref (ref ${})) (result (ref null data))
+ ;; We can vacuum away the block, which will make this ref.cast null operate
+ ;; on a non-nullable input. That is, we are refining the input to the cast.
+ ;; The cast must be updated properly following that, to be a non-nullable
+ ;; cast.
+ (ref.cast null ${}
+ (block (result (ref null ${}))
+ (local.get $ref)
+ )
+ )
+ )
)