diff options
Diffstat (limited to 'src/passes/Precompute.cpp')
-rw-r--r-- | src/passes/Precompute.cpp | 149 |
1 files changed, 73 insertions, 76 deletions
diff --git a/src/passes/Precompute.cpp b/src/passes/Precompute.cpp index 565809ddb..074dd832c 100644 --- a/src/passes/Precompute.cpp +++ b/src/passes/Precompute.cpp @@ -27,14 +27,14 @@ // looked at. // -#include <wasm.h> -#include <pass.h> -#include <wasm-builder.h> -#include <wasm-interpreter.h> -#include <ir/utils.h> #include <ir/literal-utils.h> #include <ir/local-graph.h> #include <ir/manipulation.h> +#include <ir/utils.h> +#include <pass.h> +#include <wasm-builder.h> +#include <wasm-interpreter.h> +#include <wasm.h> namespace wasm { @@ -42,38 +42,44 @@ static const Name NOTPRECOMPUTABLE_FLOW("Binaryen|notprecomputable"); typedef std::unordered_map<GetLocal*, Literal> GetValues; -// Precomputes an expression. Errors if we hit anything that can't be precomputed. -class PrecomputingExpressionRunner : public ExpressionRunner<PrecomputingExpressionRunner> { +// Precomputes an expression. Errors if we hit anything that can't be +// precomputed. +class PrecomputingExpressionRunner + : public ExpressionRunner<PrecomputingExpressionRunner> { Module* module; // map gets to constant values, if they are known to be constant GetValues& getValues; - // Whether we are trying to precompute down to an expression (which we can do on - // say 5 + 6) or to a value (which we can't do on a local.tee that flows a 7 - // through it). When we want to replace the expression, we can only do so - // when it has no side effects. When we don't care about replacing the expression, - // we just want to know if it will contain a known constant. + // Whether we are trying to precompute down to an expression (which we can do + // on say 5 + 6) or to a value (which we can't do on a local.tee that flows a + // 7 through it). When we want to replace the expression, we can only do so + // when it has no side effects. When we don't care about replacing the + // expression, we just want to know if it will contain a known constant. bool replaceExpression; public: - PrecomputingExpressionRunner(Module* module, GetValues& getValues, bool replaceExpression) : module(module), getValues(getValues), replaceExpression(replaceExpression) {} + PrecomputingExpressionRunner(Module* module, + GetValues& getValues, + bool replaceExpression) + : module(module), getValues(getValues), + replaceExpression(replaceExpression) {} - struct NonstandaloneException {}; // TODO: use a flow with a special name, as this is likely very slow + struct NonstandaloneException { + }; // TODO: use a flow with a special name, as this is likely very slow Flow visitLoop(Loop* curr) { // loops might be infinite, so must be careful - // but we can't tell if non-infinite, since we don't have state, so loops are just impossible to optimize for now + // but we can't tell if non-infinite, since we don't have state, so loops + // are just impossible to optimize for now return Flow(NOTPRECOMPUTABLE_FLOW); } - Flow visitCall(Call* curr) { - return Flow(NOTPRECOMPUTABLE_FLOW); - } + Flow visitCall(Call* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); } Flow visitCallIndirect(CallIndirect* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); } - Flow visitGetLocal(GetLocal *curr) { + Flow visitGetLocal(GetLocal* curr) { auto iter = getValues.find(curr); if (iter != getValues.end()) { auto value = iter->second; @@ -83,7 +89,7 @@ public: } return Flow(NOTPRECOMPUTABLE_FLOW); } - Flow visitSetLocal(SetLocal *curr) { + Flow visitSetLocal(SetLocal* curr) { // If we don't need to replace the whole expression, see if there // is a value flowing through a tee. if (!replaceExpression) { @@ -94,56 +100,36 @@ public: } return Flow(NOTPRECOMPUTABLE_FLOW); } - Flow visitGetGlobal(GetGlobal *curr) { + Flow visitGetGlobal(GetGlobal* curr) { auto* global = module->getGlobal(curr->name); if (!global->imported() && !global->mutable_) { return visit(global->init); } return Flow(NOTPRECOMPUTABLE_FLOW); } - Flow visitSetGlobal(SetGlobal *curr) { + Flow visitSetGlobal(SetGlobal* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); } + Flow visitLoad(Load* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); } + Flow visitStore(Store* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); } + Flow visitAtomicRMW(AtomicRMW* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); } + Flow visitAtomicCmpxchg(AtomicCmpxchg* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); } - Flow visitLoad(Load *curr) { - return Flow(NOTPRECOMPUTABLE_FLOW); - } - Flow visitStore(Store *curr) { - return Flow(NOTPRECOMPUTABLE_FLOW); - } - Flow visitAtomicRMW(AtomicRMW *curr) { - return Flow(NOTPRECOMPUTABLE_FLOW); - } - Flow visitAtomicCmpxchg(AtomicCmpxchg *curr) { - return Flow(NOTPRECOMPUTABLE_FLOW); - } - Flow visitAtomicWait(AtomicWait *curr) { - return Flow(NOTPRECOMPUTABLE_FLOW); - } - Flow visitAtomicNotify(AtomicNotify *curr) { - return Flow(NOTPRECOMPUTABLE_FLOW); - } - Flow visitMemoryInit(MemoryInit *curr) { - return Flow(NOTPRECOMPUTABLE_FLOW); - } - Flow visitDataDrop(DataDrop *curr) { - return Flow(NOTPRECOMPUTABLE_FLOW); - } - Flow visitMemoryCopy(MemoryCopy *curr) { - return Flow(NOTPRECOMPUTABLE_FLOW); - } - Flow visitMemoryFill(MemoryFill *curr) { - return Flow(NOTPRECOMPUTABLE_FLOW); - } - Flow visitHost(Host *curr) { + Flow visitAtomicWait(AtomicWait* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); } + Flow visitAtomicNotify(AtomicNotify* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); } + Flow visitMemoryInit(MemoryInit* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); } + Flow visitDataDrop(DataDrop* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); } + Flow visitMemoryCopy(MemoryCopy* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); } + Flow visitMemoryFill(MemoryFill* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); } + Flow visitHost(Host* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); } - void trap(const char* why) override { - throw NonstandaloneException(); - } + void trap(const char* why) override { throw NonstandaloneException(); } }; -struct Precompute : public WalkerPass<PostWalker<Precompute, UnifiedExpressionVisitor<Precompute>>> { +struct Precompute + : public WalkerPass< + PostWalker<Precompute, UnifiedExpressionVisitor<Precompute>>> { bool isFunctionParallel() override { return true; } Pass* create() override { return new Precompute(propagate); } @@ -175,19 +161,25 @@ struct Precompute : public WalkerPass<PostWalker<Precompute, UnifiedExpressionVi } void visitExpression(Expression* curr) { - // TODO: if local.get, only replace with a constant if we don't care about size...? - if (curr->is<Const>() || curr->is<Nop>()) return; + // TODO: if local.get, only replace with a constant if we don't care about + // size...? + if (curr->is<Const>() || curr->is<Nop>()) + return; // Until engines implement v128.const and we have SIMD-aware optimizations // that can break large v128.const instructions into smaller consts and // splats, do not try to precompute v128 expressions. - if (isVectorType(curr->type)) return; + if (isVectorType(curr->type)) + return; // try to evaluate this into a const Flow flow = precomputeExpression(curr); - if (isVectorType(flow.value.type)) return; + if (isVectorType(flow.value.type)) + return; if (flow.breaking()) { - if (flow.breakTo == NOTPRECOMPUTABLE_FLOW) return; + if (flow.breakTo == NOTPRECOMPUTABLE_FLOW) + return; if (flow.breakTo == RETURN_FLOW) { - // this expression causes a return. if it's already a return, reuse the node + // this expression causes a return. if it's already a return, reuse the + // node if (auto* ret = curr->dynCast<Return>()) { if (flow.value.type != none) { // reuse a const value if there is one @@ -204,11 +196,13 @@ struct Precompute : public WalkerPass<PostWalker<Precompute, UnifiedExpressionVi } } else { Builder builder(*getModule()); - replaceCurrent(builder.makeReturn(flow.value.type != none ? builder.makeConst(flow.value) : nullptr)); + replaceCurrent(builder.makeReturn( + flow.value.type != none ? builder.makeConst(flow.value) : nullptr)); } return; } - // this expression causes a break, emit it directly. if it's already a br, reuse the node. + // this expression causes a break, emit it directly. if it's already a br, + // reuse the node. if (auto* br = curr->dynCast<Break>()) { br->name = flow.breakTo; br->condition = nullptr; @@ -229,7 +223,9 @@ struct Precompute : public WalkerPass<PostWalker<Precompute, UnifiedExpressionVi br->finalize(); } else { Builder builder(*getModule()); - replaceCurrent(builder.makeBreak(flow.breakTo, flow.value.type != none ? builder.makeConst(flow.value) : nullptr)); + replaceCurrent(builder.makeBreak( + flow.breakTo, + flow.value.type != none ? builder.makeConst(flow.value) : nullptr)); } return; } @@ -252,7 +248,9 @@ private: // (that we can replace the expression with if replaceExpression is set). Flow precomputeExpression(Expression* curr, bool replaceExpression = true) { try { - return PrecomputingExpressionRunner(getModule(), getValues, replaceExpression).visit(curr); + return PrecomputingExpressionRunner( + getModule(), getValues, replaceExpression) + .visit(curr); } catch (PrecomputingExpressionRunner::NonstandaloneException&) { return Flow(NOTPRECOMPUTABLE_FLOW); } @@ -292,7 +290,8 @@ private: auto* curr = pair.first; work.insert(curr); } - std::unordered_map<SetLocal*, Literal> setValues; // the constant value, or none if not a constant + // the constant value, or none if not a constant + std::unordered_map<SetLocal*, Literal> setValues; // propagate constant values while (!work.empty()) { auto iter = work.begin(); @@ -302,7 +301,8 @@ private: // mark it as such and add everything it influences to the work list, // as they may be constant too. if (auto* set = curr->dynCast<SetLocal>()) { - if (setValues[set].isConcrete()) continue; // already known constant + if (setValues[set].isConcrete()) + continue; // already known constant auto value = setValues[set] = precomputeValue(set->value); if (value.isConcrete()) { for (auto* get : localGraph.setInfluences[set]) { @@ -311,7 +311,8 @@ private: } } else { auto* get = curr->cast<GetLocal>(); - if (getValues[get].isConcrete()) continue; // already known constant + if (getValues[get].isConcrete()) + continue; // already known constant // for this get to have constant value, all sets must agree Literal value; bool first = true; @@ -358,12 +359,8 @@ private: } }; -Pass *createPrecomputePass() { - return new Precompute(false); -} +Pass* createPrecomputePass() { return new Precompute(false); } -Pass *createPrecomputePropagatePass() { - return new Precompute(true); -} +Pass* createPrecomputePropagatePass() { return new Precompute(true); } } // namespace wasm |