summaryrefslogtreecommitdiff
path: root/src/passes
diff options
context:
space:
mode:
Diffstat (limited to 'src/passes')
-rw-r--r--src/passes/DeadArgumentElimination.cpp47
-rw-r--r--src/passes/LocalSubtyping.cpp6
-rw-r--r--src/passes/TypeRefining.cpp65
3 files changed, 53 insertions, 65 deletions
diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp
index e997c591f..b7ce5ef5f 100644
--- a/src/passes/DeadArgumentElimination.cpp
+++ b/src/passes/DeadArgumentElimination.cpp
@@ -553,6 +553,7 @@ private:
auto numParams = func->getNumParams();
std::vector<Type> newParamTypes;
newParamTypes.reserve(numParams);
+ std::vector<LUBFinder> lubs(numParams);
for (Index i = 0; i < numParams; i++) {
auto originalType = func->getLocalType(i);
// If the parameter type is not a reference, there is nothing to refine.
@@ -565,10 +566,11 @@ private:
newParamTypes.push_back(originalType);
continue;
}
- LUBFinder lub;
+ auto& lub = lubs[i];
for (auto* call : calls) {
auto* operand = call->operands[i];
- if (lub.note(operand) == originalType) {
+ lub.noteUpdatableExpression(operand);
+ if (lub.getBestPossible() == originalType) {
// We failed to refine this parameter to anything more specific.
break;
}
@@ -578,7 +580,7 @@ private:
if (!lub.noted()) {
return;
}
- newParamTypes.push_back(lub.get());
+ newParamTypes.push_back(lub.getBestPossible());
}
// Check if we are able to optimize here before we do the work to scan the
@@ -591,6 +593,11 @@ private:
// We can do this!
TypeUpdating::updateParamTypes(func, newParamTypes, *module);
+ // Update anything the lubs need to update.
+ for (auto& lub : lubs) {
+ lub.updateNulls();
+ }
+
// Also update the function's type.
func->setParams(newParams);
}
@@ -633,21 +640,28 @@ private:
ReFinalize().walkFunctionInModule(func, module);
LUBFinder lub;
- if (lub.note(func->body) == originalType) {
+ lub.noteUpdatableExpression(func->body);
+ if (lub.getBestPossible() == originalType) {
return false;
}
- // Scan the body and look at the returns.
- auto processReturnType = [&](Type type) {
- // Return whether we still look ok to do the optimization. If this is
- // false then we can stop here.
- return lub.note(type) != originalType;
- };
+ // Scan the body and look at the returns. First, return expressions.
for (auto* ret : FindAll<Return>(func->body).list) {
- if (!processReturnType(ret->value->type)) {
+ lub.noteUpdatableExpression(ret->value);
+ if (lub.getBestPossible() == originalType) {
return false;
}
}
+
+ // Process return_calls and call_refs. Unlike return expressions which we
+ // just handled, these only get a type to update, not a value.
+ auto processReturnType = [&](Type type) {
+ // Return whether we still look ok to do the optimization. If this is
+ // false then we can stop here.
+ lub.note(type);
+ return lub.getBestPossible() != originalType;
+ };
+
for (auto* call : FindAll<Call>(func->body).list) {
if (call->isReturn &&
!processReturnType(module->getFunction(call->target)->getResults())) {
@@ -671,7 +685,6 @@ private:
}
}
}
- assert(lub.get() != originalType);
// If the refined type is unreachable then nothing actually returns from
// this function.
@@ -680,13 +693,19 @@ private:
return false;
}
+ auto newType = lub.getBestPossible();
+ if (newType == originalType) {
+ return false;
+ }
+
// Success. Update the type, and the calls.
- func->setResults(lub.get());
+ func->setResults(newType);
for (auto* call : calls) {
if (call->type != Type::unreachable) {
- call->type = lub.get();
+ call->type = newType;
}
}
+ lub.updateNulls();
return true;
}
};
diff --git a/src/passes/LocalSubtyping.cpp b/src/passes/LocalSubtyping.cpp
index 57119a253..a8174aa2d 100644
--- a/src/passes/LocalSubtyping.cpp
+++ b/src/passes/LocalSubtyping.cpp
@@ -124,7 +124,8 @@ struct LocalSubtyping : public WalkerPass<PostWalker<LocalSubtyping>> {
// Find all the types assigned to the var, and compute the optimal LUB.
LUBFinder lub;
for (auto* set : setsForLocal[i]) {
- if (lub.note(set->value) == oldType) {
+ lub.noteUpdatableExpression(set->value);
+ if (lub.getBestPossible() == oldType) {
break;
}
}
@@ -133,7 +134,7 @@ struct LocalSubtyping : public WalkerPass<PostWalker<LocalSubtyping>> {
continue;
}
- auto newType = lub.get();
+ auto newType = lub.getBestPossible();
assert(newType != Type::none); // in valid wasm there must be a LUB
// Remove non-nullability if we disallow that in locals.
@@ -157,6 +158,7 @@ struct LocalSubtyping : public WalkerPass<PostWalker<LocalSubtyping>> {
func->vars[i - varBase] = newType;
more = true;
optimized = true;
+ lub.updateNulls();
// Update gets and tees.
for (auto* get : getsForLocal[i]) {
diff --git a/src/passes/TypeRefining.cpp b/src/passes/TypeRefining.cpp
index 33e382bc5..9480322bb 100644
--- a/src/passes/TypeRefining.cpp
+++ b/src/passes/TypeRefining.cpp
@@ -36,38 +36,7 @@ namespace {
// possible LUB so far. The only extra functionality we need here is whether
// there is a default null value (which would force us to keep the type
// nullable).
-struct FieldInfo : public LUBFinder {
- bool nullDefault = false;
-
- void noteNullDefault() { nullDefault = true; }
-
- bool hasNullDefault() { return nullDefault; }
-
- bool noted() { return LUBFinder::noted() || nullDefault; }
-
- Type get() {
- auto ret = LUBFinder::get();
- if (nullDefault && !ret.isNullable()) {
- ret = Type(ret.getHeapType(), Nullable);
- }
- return ret;
- }
-
- bool combine(const FieldInfo& other) {
- auto old = nullDefault;
- if (other.nullDefault) {
- noteNullDefault();
- }
- return LUBFinder::combine(other) || nullDefault != old;
- }
-
- // Force the lub to a particular type.
- void set(Type type) { lub = type; }
-
- void dump(std::ostream& o) {
- std::cout << "FieldInfo(" << lub << ", " << nullDefault << ")";
- }
-};
+using FieldInfo = LUBFinder;
struct FieldInfoScanner
: public StructUtils::StructScanner<FieldInfo, FieldInfoScanner> {
@@ -85,7 +54,7 @@ struct FieldInfoScanner
HeapType type,
Index index,
FieldInfo& info) {
- info.note(expr);
+ info.noteUpdatableExpression(expr);
}
void
@@ -171,9 +140,8 @@ struct TypeRefining : public Pass {
for (Index i = 0; i < fields.size(); i++) {
auto oldType = fields[i].type;
auto& info = finalInfos[type][i];
- auto newType = info.get();
- if (newType == Type::unreachable) {
- info.set(oldType);
+ if (!info.noted()) {
+ info = LUBFinder(oldType);
}
}
@@ -181,9 +149,9 @@ struct TypeRefining : public Pass {
if (auto super = type.getSuperType()) {
auto& superFields = super->getStruct().fields;
for (Index i = 0; i < superFields.size(); i++) {
- auto newSuperType = finalInfos[*super][i].get();
+ auto newSuperType = finalInfos[*super][i].getBestPossible();
auto& info = finalInfos[type][i];
- auto newType = info.get();
+ auto newType = info.getBestPossible();
if (!Type::isSubType(newType, newSuperType)) {
// To ensure we are a subtype of the super's field, simply copy that
// value, which is more specific than us.
@@ -201,7 +169,7 @@ struct TypeRefining : public Pass {
// to something more specific than $C's old type, we end up with the
// problem that this code path fixes: we just need to get $C's type
// to be identical to its super so that validation works.
- info.set(newSuperType);
+ info = LUBFinder(newSuperType);
} else if (fields[i].mutable_ == Mutable) {
// Mutable fields must have identical types, so we cannot
// specialize.
@@ -209,20 +177,19 @@ struct TypeRefining : public Pass {
// here? This entire analysis might be done on fields, and not
// types, which would also handle more things added to fields
// in the future.
- info.set(newSuperType);
+ info = LUBFinder(newSuperType);
}
}
}
// After all those decisions, see if we found anything to optimize.
- if (!canOptimize) {
- for (Index i = 0; i < fields.size(); i++) {
- auto oldType = fields[i].type;
- auto newType = finalInfos[type][i].get();
- if (newType != oldType) {
- canOptimize = true;
- break;
- }
+ for (Index i = 0; i < fields.size(); i++) {
+ auto oldType = fields[i].type;
+ auto& lub = finalInfos[type][i];
+ auto newType = lub.getBestPossible();
+ if (newType != oldType) {
+ canOptimize = true;
+ lub.updateNulls();
}
}
@@ -253,7 +220,7 @@ struct TypeRefining : public Pass {
if (!oldType.isRef()) {
continue;
}
- auto newType = parent.finalInfos[oldStructType][i].get();
+ auto newType = parent.finalInfos[oldStructType][i].getBestPossible();
newFields[i].type = getTempType(newType);
}
}