summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/CMakeLists.txt1
-rw-r--r--src/passes/RelooperJumpThreading.cpp281
-rw-r--r--src/passes/pass.cpp3
-rw-r--r--src/passes/passes.h1
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();