diff options
-rw-r--r-- | src/passes/Vacuum.cpp | 13 | ||||
-rw-r--r-- | test/lit/passes/vacuum-gc.wast | 18 |
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) + ) + ) + ) ) |