diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/passes/ConstantFieldPropagation.cpp | 66 |
1 files changed, 49 insertions, 17 deletions
diff --git a/src/passes/ConstantFieldPropagation.cpp b/src/passes/ConstantFieldPropagation.cpp index 7b13b1766..f4476ef04 100644 --- a/src/passes/ConstantFieldPropagation.cpp +++ b/src/passes/ConstantFieldPropagation.cpp @@ -53,20 +53,23 @@ struct Many : public std::monostate {}; // Represents data about what constant values are possible in a particular // place. There may be no values, or one, or many, or if a non-constant value is // possible, then all we can say is that the value is "unknown" - it can be -// anything. +// anything. The values can either be literal values (Literal) or the names of +// immutable globals (Name). // // Currently this just looks for a single constant value, and even two constant // values are treated as unknown. It may be worth optimizing more than that TODO struct PossibleConstantValues { private: - std::variant<None, Literal, Many> value; + using Variant = std::variant<None, Literal, Name, Many>; + Variant value; public: PossibleConstantValues() : value(None()) {} // Note a written value as we see it, and update our internal knowledge based - // on it and all previous values noted. - void note(Literal curr) { + // on it and all previous values noted. This can be called using either a + // Literal or a Name, so it uses a template. + template<typename T> void note(T curr) { if (std::get_if<None>(&value)) { // This is the first value. value = curr; @@ -79,9 +82,9 @@ public: } // This is a subsequent value. Check if it is different from all previous - // ones, and if so, we now represent many possible values. - if (curr != std::get<Literal>(value)) { - value = Many(); + // ones. + if (Variant(curr) != value) { + noteUnknown(); } } @@ -117,14 +120,25 @@ public: } // Check if all the values are identical and constant. - bool isConstant() const { return std::get_if<Literal>(&value); } + bool isConstant() const { + return !std::get_if<None>(&value) && !std::get_if<Many>(&value); + } + + bool isConstantLiteral() const { return std::get_if<Literal>(&value); } + + bool isConstantGlobal() const { return std::get_if<Name>(&value); } // Returns the single constant value. - Literal getConstantValue() const { + Literal getConstantLiteral() const { assert(isConstant()); return std::get<Literal>(value); } + Name getConstantGlobal() const { + assert(isConstant()); + return std::get<Name>(value); + } + // Returns whether we have ever noted a value. bool hasNoted() const { return !std::get_if<None>(&value); } @@ -134,8 +148,10 @@ public: o << "unwritten"; } else if (!isConstant()) { o << "unknown"; - } else { - o << getConstantValue(); + } else if (isConstantLiteral()) { + o << getConstantLiteral(); + } else if (isConstantGlobal()) { + o << '$' << getConstantGlobal(); } o << ']'; } @@ -200,9 +216,14 @@ struct FunctionOptimizer : public WalkerPass<PostWalker<FunctionOptimizer>> { // ref.as_non_null (we need to trap as the get would have done so), plus the // constant value. (Leave it to further optimizations to get rid of the // ref.) + Expression* value; + if (info.isConstantLiteral()) { + value = builder.makeConstantExpression(info.getConstantLiteral()); + } else { + value = builder.makeGlobalGet(info.getConstantGlobal(), curr->type); + } replaceCurrent(builder.makeSequence( - builder.makeDrop(builder.makeRefAs(RefAsNonNull, curr->ref)), - builder.makeConstantExpression(info.getConstantValue()))); + builder.makeDrop(builder.makeRefAs(RefAsNonNull, curr->ref)), value)); changed = true; } @@ -236,12 +257,23 @@ struct PCVScanner : public Scanner<PossibleConstantValues, PCVScanner> { HeapType type, Index index, PossibleConstantValues& info) { - - if (!Properties::isConstantExpression(expr)) { - info.noteUnknown(); - } else { + // If this is a constant literal value, note that. + if (Properties::isConstantExpression(expr)) { info.note(Properties::getLiteral(expr)); + return; + } + + // If this is an immutable global that we get, note that. + if (auto* get = expr->dynCast<GlobalGet>()) { + auto* global = getModule()->getGlobal(get->name); + if (global->mutable_ == Immutable) { + info.note(get->name); + return; + } } + + // Otherwise, this is not something we can reason about. + info.noteUnknown(); } void noteDefault(Type fieldType, |