diff options
author | Alon Zakai <azakai@google.com> | 2023-01-09 11:34:07 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-01-09 11:34:07 -0800 |
commit | 2608864d6fc812a90d2e2594c70767f5fb4811a7 (patch) | |
tree | 8fe6bb60979b39156a63756599610c39b11ab939 | |
parent | c049a24c12cc9420f2a6e13bc4b1549922ec5d1f (diff) | |
download | binaryen-2608864d6fc812a90d2e2594c70767f5fb4811a7.tar.gz binaryen-2608864d6fc812a90d2e2594c70767f5fb4811a7.tar.bz2 binaryen-2608864d6fc812a90d2e2594c70767f5fb4811a7.zip |
[Wasm GC] Refinalize in Vacuum (#5412)
We use TypeUpdater there, which handles updating unreachability. But with wasm GC
we also need to refinalize if we refine types. Somehow, this was not noticed until now,
but the new ref.cast null assertion on not losing type info was enough to uncover
this long-existing issue.
-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) + ) + ) + ) ) |