diff options
-rw-r--r-- | src/passes/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/passes/RelooperJumpThreading.cpp | 281 | ||||
-rw-r--r-- | src/passes/pass.cpp | 3 | ||||
-rw-r--r-- | src/passes/passes.h | 1 |
4 files changed, 0 insertions, 286 deletions
diff --git a/src/passes/CMakeLists.txt b/src/passes/CMakeLists.txt index c22e8589a..12914e590 100644 --- a/src/passes/CMakeLists.txt +++ b/src/passes/CMakeLists.txt @@ -61,7 +61,6 @@ set(passes_SOURCES Strip.cpp StripTargetFeatures.cpp RedundantSetElimination.cpp - RelooperJumpThreading.cpp RemoveImports.cpp RemoveMemory.cpp RemoveNonJSOps.cpp diff --git a/src/passes/RelooperJumpThreading.cpp b/src/passes/RelooperJumpThreading.cpp deleted file mode 100644 index 8dfc1e0e4..000000000 --- a/src/passes/RelooperJumpThreading.cpp +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Copyright 2016 WebAssembly Community Group participants - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// Optimize relooper-generated label variable usage: add blocks and turn -// a label-set/break/label-check into a break into the new block. -// This assumes the very specific output the fastcomp relooper emits, -// including the name of the 'label' variable. - -#include "ir/manipulation.h" -#include "ir/utils.h" -#include "pass.h" -#include "wasm.h" - -namespace wasm { - -static Name LABEL("label"); - -static Name getInnerName(int i) { - return Name(std::string("__rjti$") + std::to_string(i)); -} - -static Name getOuterName(int i) { - return Name(std::string("__rjto$") + std::to_string(i)); -} - -static If* isLabelCheckingIf(Expression* curr, Index labelIndex) { - if (!curr) { - return nullptr; - } - auto* iff = curr->dynCast<If>(); - if (!iff) { - return nullptr; - } - auto* condition = iff->condition->dynCast<Binary>(); - if (!(condition && condition->op == EqInt32)) { - return nullptr; - } - auto* left = condition->left->dynCast<LocalGet>(); - if (!(left && left->index == labelIndex)) { - return nullptr; - } - return iff; -} - -static Index getCheckedLabelValue(If* iff) { - return iff->condition->cast<Binary>()->right->cast<Const>()->value.geti32(); -} - -static LocalSet* isLabelSettingLocalSet(Expression* curr, Index labelIndex) { - if (!curr) { - return nullptr; - } - auto* set = curr->dynCast<LocalSet>(); - if (!set) { - return nullptr; - } - if (set->index != labelIndex) { - return nullptr; - } - return set; -} - -static Index getSetLabelValue(LocalSet* set) { - return set->value->cast<Const>()->value.geti32(); -} - -struct LabelUseFinder : public PostWalker<LabelUseFinder> { - Index labelIndex; - std::map<Index, Index>& checks; // label value => number of checks on it - std::map<Index, Index>& sets; // label value => number of sets to it - - LabelUseFinder(Index labelIndex, - std::map<Index, Index>& checks, - std::map<Index, Index>& sets) - : labelIndex(labelIndex), checks(checks), sets(sets) {} - - void visitIf(If* curr) { - if (isLabelCheckingIf(curr, labelIndex)) { - checks[getCheckedLabelValue(curr)]++; - } - } - - void visitLocalSet(LocalSet* curr) { - if (isLabelSettingLocalSet(curr, labelIndex)) { - sets[getSetLabelValue(curr)]++; - } - } -}; - -struct RelooperJumpThreading - : public WalkerPass<ExpressionStackWalker<RelooperJumpThreading>> { - bool isFunctionParallel() override { return true; } - - Pass* create() override { return new RelooperJumpThreading; } - - std::map<Index, Index> labelChecks; - std::map<Index, Index> labelSets; - - Index labelIndex; - Index newNameCounter = 0; - - void visitBlock(Block* curr) { - // look for the if label == X pattern - auto& list = curr->list; - if (list.size() == 0) { - return; - } - for (Index i = 0; i < list.size() - 1; i++) { - // once we see something that might be irreducible, we must skip that if - // and the rest of the dependents - bool irreducible = false; - Index origin = i; - for (Index j = i + 1; j < list.size(); j++) { - if (auto* iff = isLabelCheckingIf(list[j], labelIndex)) { - irreducible |= hasIrreducibleControlFlow(iff, list[origin]); - if (!irreducible) { - optimizeJumpsToLabelCheck(list[origin], iff); - ExpressionManipulator::nop(iff); - } - i++; - continue; - } - // if the next element is a block, it may be the holding block of - // label-checking ifs - if (auto* holder = list[j]->dynCast<Block>()) { - if (holder->list.size() > 0) { - if (If* iff = isLabelCheckingIf(holder->list[0], labelIndex)) { - irreducible |= hasIrreducibleControlFlow(iff, list[origin]); - if (!irreducible) { - // this is indeed a holder. we can process the ifs, and must - // also move the block to enclose the origin, so it is properly - // reachable - - // must be size 1, a relooper multiple will have its own label, - // and is an if-else sequence and nothing more - assert(holder->list.size() == 1); - optimizeJumpsToLabelCheck(list[origin], iff); - holder->list[0] = list[origin]; - list[origin] = holder; - // reuse the if as a nop - list[j] = iff; - ExpressionManipulator::nop(iff); - } - i++; - continue; - } - } - } - break; // we didn't see something we like, so stop here - } - } - } - - void doWalkFunction(Function* func) { - // if there isn't a label variable, nothing for us to do - if (func->localIndices.count(LABEL)) { - labelIndex = func->getLocalIndex(LABEL); - LabelUseFinder finder(labelIndex, labelChecks, labelSets); - finder.walk(func->body); - super::doWalkFunction(func); - } - } - - void visitFunction(Function* curr) { - // we may alter types - ReFinalize().walkFunctionInModule(curr, getModule()); - } - -private: - bool hasIrreducibleControlFlow(If* iff, Expression* origin) { - // Gather the checks in this if chain. If all the label values checked are - // only set in origin, then since origin is right before us, this is not - // irreducible - we can replace all sets in origin with jumps forward to us, - // and since there is nothing else, this is safe and complete. We must also - // have the property that there is just one check for the label value, as - // otherwise node splitting has complicated things. - std::map<Index, Index> labelChecksInOrigin; - std::map<Index, Index> labelSetsInOrigin; - LabelUseFinder finder(labelIndex, labelChecksInOrigin, labelSetsInOrigin); - finder.walk(origin); - while (iff) { - auto num = getCheckedLabelValue(iff); - assert(labelChecks[num] > 0); - if (labelChecks[num] > 1) { - return true; // checked more than once, somewhere in function - } - assert(labelChecksInOrigin[num] == 0); - if (labelSetsInOrigin[num] != labelSets[num]) { - assert(labelSetsInOrigin[num] < labelSets[num]); - // the label is set outside of the origin - // if the only other location is inside the if body, then it is ok - it - // must be in a loop and returning to the top of the loop body, so we - // don't need to do anything for that label setting anyhow - std::map<Index, Index> labelChecksInIfTrue; - std::map<Index, Index> labelSetsInIfTrue; - LabelUseFinder finder( - labelIndex, labelChecksInIfTrue, labelSetsInIfTrue); - finder.walk(iff->ifTrue); - if (labelSetsInOrigin[num] + labelSetsInIfTrue[num] < labelSets[num]) { - // label set somewhere we can't see now, could be irreducible control - // flow - // TODO: one case where this happens is instead of an if-chain, we - // have ifs and a switch on label|0, in separate elements. - // perhaps not emitting switches on label|0 in the relooper - // would avoid that. - return true; - } - } - iff = isLabelCheckingIf(iff->ifFalse, labelIndex); - } - return false; - } - - // optimizes jumps to a label check - // * origin is where the jumps originate, and also where we should write our - // output - // * iff is the if - void optimizeJumpsToLabelCheck(Expression*& origin, If* iff) { - Index nameCounter = newNameCounter++; - Index num = getCheckedLabelValue(iff); - // create a new block for this jump target - Builder builder(*getModule()); - // origin is where all jumps to this target must come from - the element - // right before this if we break out of inner to reach the target. instead - // of flowing out of normally, we break out of the outer, so we skip the - // target. - auto innerName = getInnerName(nameCounter); - auto outerName = getOuterName(nameCounter); - auto* ifFalse = iff->ifFalse; - // all assignments of label to the target can be replaced with breaks to the - // target, via innerName - struct JumpUpdater : public PostWalker<JumpUpdater> { - Index labelIndex; - Index targetNum; - Name targetName; - - void visitLocalSet(LocalSet* curr) { - if (curr->index == labelIndex) { - if (Index(curr->value->cast<Const>()->value.geti32()) == targetNum) { - replaceCurrent(Builder(*getModule()).makeBreak(targetName)); - } - } - } - }; - JumpUpdater updater; - updater.labelIndex = labelIndex; - updater.targetNum = num; - updater.targetName = innerName; - updater.setModule(getModule()); - updater.walk(origin); - // restructure code - auto* inner = - builder.blockifyWithName(origin, innerName, builder.makeBreak(outerName)); - auto* outer = builder.makeSequence(inner, iff->ifTrue); - outer->name = outerName; - origin = outer; - // if another label value is checked here, handle that too - if (ifFalse) { - optimizeJumpsToLabelCheck(origin, ifFalse->cast<If>()); - } - } -}; - -// declare pass - -Pass* createRelooperJumpThreadingPass() { return new RelooperJumpThreading(); } - -} // namespace wasm diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp index 48d121098..b653269bf 100644 --- a/src/passes/pass.cpp +++ b/src/passes/pass.cpp @@ -270,9 +270,6 @@ void PassRegistry::registerPasses() { registerPass("print-stack-ir", "print out Stack IR (useful for internal debugging)", createPrintStackIRPass); - registerPass("relooper-jump-threading", - "thread relooper jumps (fastcomp output only)", - createRelooperJumpThreadingPass); registerPass("remove-non-js-ops", "removes operations incompatible with js", createRemoveNonJSOpsPass); diff --git a/src/passes/passes.h b/src/passes/passes.h index bee30eebc..53a7d3aa2 100644 --- a/src/passes/passes.h +++ b/src/passes/passes.h @@ -90,7 +90,6 @@ Pass* createPrintCallGraphPass(); Pass* createPrintFeaturesPass(); Pass* createPrintFunctionMapPass(); Pass* createPrintStackIRPass(); -Pass* createRelooperJumpThreadingPass(); Pass* createRemoveNonJSOpsPass(); Pass* createRemoveImportsPass(); Pass* createRemoveMemoryPass(); |