summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2023-01-09 11:34:07 -0800
committerGitHub <noreply@github.com>2023-01-09 11:34:07 -0800
commit2608864d6fc812a90d2e2594c70767f5fb4811a7 (patch)
tree8fe6bb60979b39156a63756599610c39b11ab939
parentc049a24c12cc9420f2a6e13bc4b1549922ec5d1f (diff)
downloadbinaryen-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.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)
+ )
+ )
+ )
)