summaryrefslogtreecommitdiff
path: root/src/passes/LocalSubtyping.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/passes/LocalSubtyping.cpp')
-rw-r--r--src/passes/LocalSubtyping.cpp32
1 files changed, 20 insertions, 12 deletions
diff --git a/src/passes/LocalSubtyping.cpp b/src/passes/LocalSubtyping.cpp
index b6e94b771..31e689075 100644
--- a/src/passes/LocalSubtyping.cpp
+++ b/src/passes/LocalSubtyping.cpp
@@ -25,6 +25,7 @@
#include <ir/find_all.h>
#include <ir/linear-execution.h>
#include <ir/local-graph.h>
+#include <ir/local-structural-dominance.h>
#include <ir/lubs.h>
#include <ir/utils.h>
#include <pass.h>
@@ -36,6 +37,10 @@ namespace wasm {
struct LocalSubtyping : public WalkerPass<PostWalker<LocalSubtyping>> {
bool isFunctionParallel() override { return true; }
+ // This pass carefully avoids breaking validation by only refining a local's
+ // type to be non-nullable if it would validate.
+ bool requiresNonNullableLocalFixups() override { return false; }
+
Pass* create() override { return new LocalSubtyping(); }
void doWalkFunction(Function* func) {
@@ -68,24 +73,30 @@ struct LocalSubtyping : public WalkerPass<PostWalker<LocalSubtyping>> {
}
}
- // Find which vars use the default value, if we allow non-nullable locals.
- //
- // If that feature is not enabled, then we can safely assume that the
- // default is never used - the default would be a null value, and the type
- // of the null does not really matter as all nulls compare equally, so we do
- // not need to worry.
- std::unordered_set<Index> usesDefault;
+ // Find which vars can be non-nullable.
+ std::unordered_set<Index> cannotBeNonNullable;
if (getModule()->features.hasGCNNLocals()) {
+ // If the feature is enabled then the only constraint is being able to
+ // read the default value - if it is readable, the local cannot become
+ // non-nullable.
for (auto& [get, sets] : localGraph.getSetses) {
auto index = get->index;
if (func->isVar(index) &&
std::any_of(sets.begin(), sets.end(), [&](LocalSet* set) {
return set == nullptr;
})) {
- usesDefault.insert(index);
+ cannotBeNonNullable.insert(index);
}
}
+ } else {
+ // Without GCNNLocals, validation rules follow the spec rules: all gets
+ // must be dominated structurally by sets, for the local to be non-
+ // nullable.
+ LocalStructuralDominance info(func, *getModule());
+ for (auto index : info.nonDominatingIndices) {
+ cannotBeNonNullable.insert(index);
+ }
}
auto varBase = func->getVarIndexBase();
@@ -136,10 +147,7 @@ struct LocalSubtyping : public WalkerPass<PostWalker<LocalSubtyping>> {
// Remove non-nullability if we disallow that in locals.
if (newType.isNonNullable()) {
- // As mentioned earlier, even if we allow non-nullability, there may
- // be a problem if the default value - a null - is used. In that case,
- // remove non-nullability as well.
- if (!getModule()->features.hasGCNNLocals() || usesDefault.count(i)) {
+ if (cannotBeNonNullable.count(i)) {
newType = Type(newType.getHeapType(), Nullable);
}
} else if (!newType.isDefaultable()) {