diff options
author | Daniel Wirtz <dcode@dcode.io> | 2020-04-20 23:01:26 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-20 14:01:26 -0700 |
commit | 483d759230f4693abfca3a74a97b1c1db6d2a0d6 (patch) | |
tree | c37b39802b9e5791abb3e329b88ba7185557de49 /src/passes/Precompute.cpp | |
parent | 1dc820c913712a2c50d05caee77e90a7ec49d2e1 (diff) | |
download | binaryen-483d759230f4693abfca3a74a97b1c1db6d2a0d6.tar.gz binaryen-483d759230f4693abfca3a74a97b1c1db6d2a0d6.tar.bz2 binaryen-483d759230f4693abfca3a74a97b1c1db6d2a0d6.zip |
Refactor expression runner so it can be used via the C and JS APIs (#2702)
Refactors most of the precompute pass's expression runner into its
base class so it can also be used via the C and JS APIs. Also adds
the option to populate the runner with known constant local and global
values upfront, and remembers assigned intermediate values as well
as traversing into functions if requested.
Diffstat (limited to 'src/passes/Precompute.cpp')
-rw-r--r-- | src/passes/Precompute.cpp | 103 |
1 files changed, 25 insertions, 78 deletions
diff --git a/src/passes/Precompute.cpp b/src/passes/Precompute.cpp index d809b8b43..dd390150e 100644 --- a/src/passes/Precompute.cpp +++ b/src/passes/Precompute.cpp @@ -39,53 +39,41 @@ namespace wasm { -static const Name NOTPRECOMPUTABLE_FLOW("Binaryen|notprecomputable"); - -// Limit evaluation depth for 2 reasons: first, it is highly unlikely -// that we can do anything useful to precompute a hugely nested expression -// (we should succed at smaller parts of it first). Second, a low limit is -// helpful to avoid platform differences in native stack sizes. -static const Index MAX_DEPTH = 50; - typedef std::unordered_map<LocalGet*, Literals> GetValues; // 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 + // Concrete values of gets computed during the pass, which the runner does not + // know about since it only records values of sets it visits. 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. - bool replaceExpression; + // Limit evaluation depth for 2 reasons: first, it is highly unlikely + // that we can do anything useful to precompute a hugely nested expression + // (we should succed at smaller parts of it first). Second, a low limit is + // helpful to avoid platform differences in native stack sizes. + static const Index MAX_DEPTH = 50; + + // Limit loop iterations since loops might be infinite. Since we are going to + // replace the expression and must preserve side effects, we limit this to the + // very first iteration because a side effect would be necessary to achieve + // more than one iteration before becoming concrete. + static const Index MAX_LOOP_ITERATIONS = 1; public: PrecomputingExpressionRunner(Module* module, GetValues& getValues, bool replaceExpression) - : ExpressionRunner<PrecomputingExpressionRunner>(MAX_DEPTH), module(module), - getValues(getValues), replaceExpression(replaceExpression) {} - - struct NonstandaloneException { - }; // TODO: use a flow with a special name, as this is likely very slow + : ExpressionRunner<PrecomputingExpressionRunner>( + module, + replaceExpression ? FlagValues::PRESERVE_SIDEEFFECTS + : FlagValues::DEFAULT, + MAX_DEPTH, + MAX_LOOP_ITERATIONS), + getValues(getValues) {} - 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 - return Flow(NOTPRECOMPUTABLE_FLOW); - } - - Flow visitCall(Call* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); } - Flow visitCallIndirect(CallIndirect* curr) { - return Flow(NOTPRECOMPUTABLE_FLOW); - } Flow visitLocalGet(LocalGet* curr) { auto iter = getValues.find(curr); if (iter != getValues.end()) { @@ -94,51 +82,10 @@ public: return Flow(std::move(values)); } } - return Flow(NOTPRECOMPUTABLE_FLOW); - } - Flow visitLocalSet(LocalSet* curr) { - // If we don't need to replace the whole expression, see if there - // is a value flowing through a tee. - if (!replaceExpression) { - if (curr->type.isConcrete()) { - assert(curr->isTee()); - return visit(curr->value); - } - } - return Flow(NOTPRECOMPUTABLE_FLOW); - } - Flow visitGlobalGet(GlobalGet* curr) { - auto* global = module->getGlobal(curr->name); - if (!global->imported() && !global->mutable_) { - return visit(global->init); - } - return Flow(NOTPRECOMPUTABLE_FLOW); - } - Flow visitGlobalSet(GlobalSet* 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); + return ExpressionRunner<PrecomputingExpressionRunner>::visitLocalGet(curr); } - Flow visitSIMDLoad(SIMDLoad* 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); } - Flow visitTry(Try* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); } - Flow visitThrow(Throw* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); } - Flow visitRethrow(Rethrow* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); } - Flow visitBrOnExn(BrOnExn* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); } - Flow visitPush(Push* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); } - Flow visitPop(Pop* curr) { return Flow(NOTPRECOMPUTABLE_FLOW); } - void trap(const char* why) override { throw NonstandaloneException(); } + void trap(const char* why) override { throw NonconstantException(); } }; struct Precompute @@ -223,7 +170,7 @@ struct Precompute return; } if (flow.breaking()) { - if (flow.breakTo == NOTPRECOMPUTABLE_FLOW) { + if (flow.breakTo == NONCONSTANT_FLOW) { return; } if (flow.breakTo == RETURN_FLOW) { @@ -276,8 +223,8 @@ private: return PrecomputingExpressionRunner( getModule(), getValues, replaceExpression) .visit(curr); - } catch (PrecomputingExpressionRunner::NonstandaloneException&) { - return Flow(NOTPRECOMPUTABLE_FLOW); + } catch (PrecomputingExpressionRunner::NonconstantException&) { + return Flow(NONCONSTANT_FLOW); } } |