summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ir/possible-contents.cpp26
-rw-r--r--src/ir/possible-contents.h18
2 files changed, 32 insertions, 12 deletions
diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp
index b2a0b417a..83762a458 100644
--- a/src/ir/possible-contents.cpp
+++ b/src/ir/possible-contents.cpp
@@ -197,18 +197,17 @@ void PossibleContents::intersectWithFullCone(const PossibleContents& other) {
return;
}
- if (isLiteral() || isGlobal()) {
+ if (isLiteral()) {
// The information about the value being identical to a particular literal
- // or immutable global is not removed by intersection, if the type is in the
- // cone we are intersecting with.
+ // is not removed by intersection, if the type is in the cone we are
+ // intersecting with.
if (isSubType) {
return;
}
- // The type must change, so continue down to the generic code path.
- // TODO: for globals we could perhaps refine the type here, but then the
- // type on GlobalInfo would not match the module, so that needs some
- // refactoring.
+ // The type must change in a nontrivial manner, so continue down to the
+ // generic code path. This will stop being a Literal. TODO: can we do better
+ // here?
}
// Intersect the cones, as there is no more specific information we can use.
@@ -226,6 +225,14 @@ void PossibleContents::intersectWithFullCone(const PossibleContents& other) {
newHeapType = heapType;
}
+ // Note the global's information, if we started as a global. In that case, the
+ // code below will refine our type but we can remain a global, which we will
+ // accomplish by restoring our global status at the end.
+ std::optional<Name> globalName;
+ if (isGlobal()) {
+ globalName = getGlobal();
+ }
+
auto newType = Type(newHeapType, nullability);
// By assumption |other| has full depth. Consider the other cone in |this|.
@@ -261,6 +268,11 @@ void PossibleContents::intersectWithFullCone(const PossibleContents& other) {
value = ConeType{newType, newDepth};
}
+
+ if (globalName) {
+ // Restore the global but keep the new and refined type.
+ value = GlobalInfo{*globalName, getType()};
+ }
}
bool PossibleContents::haveIntersection(const PossibleContents& a,
diff --git a/src/ir/possible-contents.h b/src/ir/possible-contents.h
index b7c9bfafd..b4326688e 100644
--- a/src/ir/possible-contents.h
+++ b/src/ir/possible-contents.h
@@ -66,10 +66,15 @@ class PossibleContents {
struct GlobalInfo {
Name name;
- // The type of the global in the module. We stash this here so that we do
- // not need to pass around a module all the time.
- // TODO: could we save size in this variant if we did pass around the
- // module?
+ // The type of contents. Note that this may not match the type of the
+ // global, if we were filtered. For example:
+ //
+ // (ref.as_non_null
+ // (global.get $nullable-global)
+ // )
+ //
+ // The contents flowing out will be a Global, but of a non-nullable type,
+ // unlike the original global.
Type type;
bool operator==(const GlobalInfo& other) const {
return name == other.name && type == other.type;
@@ -287,6 +292,9 @@ public:
return builder.makeConstantExpression(getLiteral());
} else {
auto name = getGlobal();
+ // Note that we load the type from the module, rather than use the type
+ // in the GlobalInfo, as that type may not match the global (see comment
+ // in the GlobalInfo declaration above).
return builder.makeGlobalGet(name, wasm.getGlobal(name)->type);
}
}
@@ -321,7 +329,7 @@ public:
o << " HT: " << h;
}
} else if (isGlobal()) {
- o << "GlobalInfo $" << getGlobal();
+ o << "GlobalInfo $" << getGlobal() << " T: " << getType();
} else if (auto* coneType = std::get_if<ConeType>(&value)) {
auto t = coneType->type;
o << "ConeType " << t;