summaryrefslogtreecommitdiffstats
path: root/js/src/jit/MIR.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit/MIR.cpp')
-rw-r--r--js/src/jit/MIR.cpp65
1 files changed, 65 insertions, 0 deletions
diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp
index c6daecb166..a74406567b 100644
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -689,7 +689,62 @@ MDefinition* MTest::foldsNeedlessControlFlow(TempAllocator& alloc) {
return MGoto::New(alloc, ifTrue());
}
+// If a test is dominated by either the true or false path of a previous test of
+// the same condition, then the test is redundant and can be converted into a
+// goto true or goto false, respectively.
+MDefinition* MTest::foldsRedundantTest(TempAllocator& alloc) {
+ MBasicBlock* myBlock = this->block();
+ MDefinition* originalInput = getOperand(0);
+
+ // Handle single and double negatives. This ensures that we do not miss a
+ // folding opportunity due to a condition being inverted.
+ MDefinition* newInput = input();
+ bool inverted = false;
+ if (originalInput->isNot()) {
+ newInput = originalInput->toNot()->input();
+ inverted = true;
+ if (originalInput->toNot()->input()->isNot()) {
+ newInput = originalInput->toNot()->input()->toNot()->input();
+ inverted = false;
+ }
+ }
+
+ // The specific order of traversal does not matter. If there are multiple
+ // dominating redundant tests, they will either agree on direction (in which
+ // case we will prune the same way regardless of order), or they will
+ // disagree, in which case we will eventually be marked entirely dead by the
+ // folding of the redundant parent.
+ for (MUseIterator i(newInput->usesBegin()), e(newInput->usesEnd()); i != e;
+ ++i) {
+ if (!i->consumer()->isDefinition()) {
+ continue;
+ }
+ if (!i->consumer()->toDefinition()->isTest()) {
+ continue;
+ }
+ MTest* otherTest = i->consumer()->toDefinition()->toTest();
+ if (otherTest == this) {
+ continue;
+ }
+
+ if (otherTest->ifFalse()->dominates(myBlock)) {
+ // This test cannot be true, so fold to a goto false.
+ return MGoto::New(alloc, inverted ? ifTrue() : ifFalse());
+ }
+ if (otherTest->ifTrue()->dominates(myBlock)) {
+ // This test cannot be false, so fold to a goto true.
+ return MGoto::New(alloc, inverted ? ifFalse() : ifTrue());
+ }
+ }
+
+ return nullptr;
+}
+
MDefinition* MTest::foldsTo(TempAllocator& alloc) {
+ if (MDefinition* def = foldsRedundantTest(alloc)) {
+ return def;
+ }
+
if (MDefinition* def = foldsDoubleNegation(alloc)) {
return def;
}
@@ -7187,6 +7242,16 @@ AliasSet MLoadWrapperTarget::getAliasSet() const {
return AliasSet::Load(AliasSet::Any);
}
+bool MLoadWrapperTarget::congruentTo(const MDefinition* ins) const {
+ if (!ins->isLoadWrapperTarget()) {
+ return false;
+ }
+ if (ins->toLoadWrapperTarget()->fallible() != fallible()) {
+ return false;
+ }
+ return congruentIfOperandsEqual(ins);
+}
+
AliasSet MGuardHasGetterSetter::getAliasSet() const {
return AliasSet::Load(AliasSet::ObjectFields);
}