summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2023-08-24 11:16:17 -0700
committerGitHub <noreply@github.com>2023-08-24 18:16:17 +0000
commit91114e6a9b69969e673ffb40e7dc54029d15a0f8 (patch)
treedeef2d2c9cf9e2edfd18662e36ac84bd951d43f7
parent73bbbab144c4543edb70d35160cd620d3fe94539 (diff)
downloadbinaryen-91114e6a9b69969e673ffb40e7dc54029d15a0f8.tar.gz
binaryen-91114e6a9b69969e673ffb40e7dc54029d15a0f8.tar.bz2
binaryen-91114e6a9b69969e673ffb40e7dc54029d15a0f8.zip
GlobalStructInference: Add missing ReFinalize (#5898)
-rw-r--r--src/passes/GlobalStructInference.cpp18
-rw-r--r--test/lit/passes/gsi.wast47
2 files changed, 64 insertions, 1 deletions
diff --git a/src/passes/GlobalStructInference.cpp b/src/passes/GlobalStructInference.cpp
index 6a917596f..ceee8b02d 100644
--- a/src/passes/GlobalStructInference.cpp
+++ b/src/passes/GlobalStructInference.cpp
@@ -52,6 +52,7 @@
#include "ir/module-utils.h"
#include "ir/properties.h"
#include "ir/subtypes.h"
+#include "ir/utils.h"
#include "pass.h"
#include "wasm-builder.h"
#include "wasm.h"
@@ -221,6 +222,8 @@ struct GlobalStructInference : public Pass {
FunctionOptimizer(GlobalStructInference& parent) : parent(parent) {}
+ bool refinalize = false;
+
void visitStructGet(StructGet* curr) {
auto type = curr->ref->type;
if (type == Type::unreachable) {
@@ -262,9 +265,16 @@ struct GlobalStructInference : public Pass {
// will unlock those other optimizations. Note we must trap if the ref
// is null, so add RefAsNonNull here.
auto global = globals[0];
+ auto globalType = wasm.getGlobal(global)->type;
+ if (globalType != curr->ref->type) {
+ // The struct.get will now read from something of the type of the
+ // global, which is different, so the field being read might be
+ // refined, which could change the struct.get's type.
+ refinalize = true;
+ }
curr->ref = builder.makeSequence(
builder.makeDrop(builder.makeRefAs(RefAsNonNull, curr->ref)),
- builder.makeGlobalGet(global, wasm.getGlobal(globals[0])->type));
+ builder.makeGlobalGet(global, globalType));
return;
}
@@ -367,6 +377,12 @@ struct GlobalStructInference : public Pass {
builder.makeConstantExpression(values[1])));
}
+ void visitFunction(Function* func) {
+ if (refinalize) {
+ ReFinalize().walkFunctionInModule(func, getModule());
+ }
+ }
+
private:
GlobalStructInference& parent;
};
diff --git a/test/lit/passes/gsi.wast b/test/lit/passes/gsi.wast
index df1abc04f..559050f1f 100644
--- a/test/lit/passes/gsi.wast
+++ b/test/lit/passes/gsi.wast
@@ -1390,3 +1390,50 @@
)
)
)
+
+(module
+ (rec
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $A (struct (field funcref)))
+ (type $A (struct (field funcref)))
+ ;; CHECK: (type $B (sub $A (struct (field (ref func)))))
+ (type $B (sub $A (struct (field (ref func)))))
+ )
+
+ ;; CHECK: (type $2 (func (param (ref null $A) (ref null $B)) (result funcref)))
+
+ ;; CHECK: (global $global (ref $B) (struct.new $B
+ ;; CHECK-NEXT: (ref.func $func)
+ ;; CHECK-NEXT: ))
+ (global $global (ref $B) (struct.new $B
+ (ref.func $func)
+ ))
+
+ ;; CHECK: (func $func (type $2) (param $a (ref null $A)) (param $b (ref null $B)) (result funcref)
+ ;; CHECK-NEXT: (struct.get $B 0
+ ;; CHECK-NEXT: (block (result (ref $B))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.as_non_null
+ ;; CHECK-NEXT: (local.tee $a
+ ;; CHECK-NEXT: (local.get $b)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (global.get $global)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $func (param $a (ref null $A)) (param $b (ref null $B)) (result funcref)
+ (struct.get $A 0
+ ;; We can infer that we read from $global here, since it is the only place
+ ;; a $B is created (the tee in the middle to $A does not confuse us).
+ ;; After that, the struct.get will be reading a global.get of $global,
+ ;; which is of type $B, and compared to $A from before we will read a more
+ ;; refined type from the field, ref func vs funcref, which must be updated
+ ;; in the IR.
+ (local.tee $a
+ (local.get $b)
+ )
+ )
+ )
+)