author | Dan Gohman <sunfish@mozilla.com> |
Wed, 17 Sep 2014 10:27:25 -0700 | |
changeset 205743 | ff831540e312febfe640805f1cdc207ad8530185 |
parent 205742 | 6e9a69bead52911e66eb586184c558259a344caa |
child 205744 | 8f27a48a25d5a7acabf69867597f3dfe0f951cdd |
push id | 49264 |
push user | dgohman@mozilla.com |
push date | Wed, 17 Sep 2014 17:27:46 +0000 |
treeherder | mozilla-inbound@ce0a75f9481b [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | nbp |
bugs | 1029830 |
milestone | 35.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -310,18 +310,23 @@ MTest::cacheOperandMightEmulateUndefined markOperandCantEmulateUndefined(); } MDefinition * MTest::foldsTo(TempAllocator &alloc) { MDefinition *op = getOperand(0); - if (op->isNot()) + if (op->isNot()) { + // If the operand of the Not is itself a Not, they cancel out. + MDefinition *opop = op->getOperand(0); + if (opop->isNot()) + return MTest::New(alloc, opop->toNot()->input(), ifTrue(), ifFalse()); return MTest::New(alloc, op->toNot()->input(), ifFalse(), ifTrue()); + } return this; } void MTest::filtersUndefinedOrNull(bool trueBranch, MDefinition **subject, bool *filtersUndefined, bool *filtersNull) { @@ -2983,16 +2988,26 @@ MNot::foldsTo(TempAllocator &alloc) bool result = input()->toConstant()->valueToBoolean(); if (type() == MIRType_Int32) return MConstant::New(alloc, Int32Value(!result)); // ToBoolean can't cause side effects, so this is safe. return MConstant::New(alloc, BooleanValue(!result)); } + // If the operand of the Not is itself a Not, they cancel out. But we can't + // always convert Not(Not(x)) to x because that may loose the conversion to + // boolean. We can simplify Not(Not(Not(x))) to Not(x) though. + MDefinition *op = getOperand(0); + if (op->isNot()) { + MDefinition *opop = op->getOperand(0); + if (opop->isNot()) + return opop; + } + // NOT of an undefined or null value is always true if (input()->type() == MIRType_Undefined || input()->type() == MIRType_Null) return MConstant::New(alloc, BooleanValue(true)); // NOT of an object that can't emulate undefined is always false. if (input()->type() == MIRType_Object && !operandMightEmulateUndefined()) return MConstant::New(alloc, BooleanValue(false));
--- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -7222,26 +7222,26 @@ class MSetTypedObjectOffset // Perform !-operation class MNot : public MUnaryInstruction, public TestPolicy { bool operandMightEmulateUndefined_; bool operandIsNeverNaN_; - public: explicit MNot(MDefinition *input) : MUnaryInstruction(input), operandMightEmulateUndefined_(true), operandIsNeverNaN_(false) { setResultType(MIRType_Boolean); setMovable(); } + public: static MNot *New(TempAllocator &alloc, MDefinition *elements) { return new(alloc) MNot(elements); } static MNot *NewAsmJS(TempAllocator &alloc, MDefinition *elements) { MNot *ins = new(alloc) MNot(elements); ins->setResultType(MIRType_Int32); return ins; }
--- a/js/src/jsapi-tests/testJitFoldsTo.cpp +++ b/js/src/jsapi-tests/testJitFoldsTo.cpp @@ -65,8 +65,145 @@ BEGIN_TEST(testJitFoldsTo_NoDivReciproca // Test that the div didn't get folded. MDefinition *op = ret->getOperand(0); CHECK(op->isDiv()); CHECK(op->getOperand(0) == p); CHECK(op->getOperand(1) == c); return true; } END_TEST(testJitFoldsTo_NoDivReciprocal) + +BEGIN_TEST(testJitNotNot) +{ + MinimalFunc func; + MBasicBlock *block = func.createEntryBlock(); + + // return Not(Not(p)) + MParameter *p = func.createParameter(); + block->add(p); + MNot *not0 = MNot::New(func.alloc, p); + block->add(not0); + MNot *not1 = MNot::New(func.alloc, not0); + block->add(not1); + MReturn *ret = MReturn::New(func.alloc, not1); + block->end(ret); + + if (!func.runGVN()) + return false; + + // Test that the nots did not get folded. + MDefinition *op = ret->getOperand(0); + CHECK(op->isNot()); + CHECK(op->getOperand(0)->isNot()); + CHECK(op->getOperand(0)->getOperand(0) == p); + return true; +} +END_TEST(testJitNotNot) + +BEGIN_TEST(testJitNotNotNot) +{ + MinimalFunc func; + MBasicBlock *block = func.createEntryBlock(); + + // return Not(Not(Not(p))) + MParameter *p = func.createParameter(); + block->add(p); + MNot *not0 = MNot::New(func.alloc, p); + block->add(not0); + MNot *not1 = MNot::New(func.alloc, not0); + block->add(not1); + MNot *not2 = MNot::New(func.alloc, not1); + block->add(not2); + MReturn *ret = MReturn::New(func.alloc, not2); + block->end(ret); + + if (!func.runGVN()) + return false; + + // Test that the nots got folded. + MDefinition *op = ret->getOperand(0); + CHECK(op->isNot()); + CHECK(op->getOperand(0) == p); + return true; +} +END_TEST(testJitNotNotNot) + +BEGIN_TEST(testJitNotTest) +{ + MinimalFunc func; + MBasicBlock *block = func.createEntryBlock(); + MBasicBlock *then = func.createBlock(block); + MBasicBlock *else_ = func.createBlock(block); + MBasicBlock *exit = func.createBlock(block); + + // MTest(Not(p)) + MParameter *p = func.createParameter(); + block->add(p); + MNot *not0 = MNot::New(func.alloc, p); + block->add(not0); + MTest *test = MTest::New(func.alloc, not0, then, else_); + block->end(test); + + MNop *anchor = MNop::New(func.alloc); + anchor->setGuard(); + then->add(anchor); + then->end(MGoto::New(func.alloc, exit)); + + else_->end(MGoto::New(func.alloc, exit)); + + MReturn *ret = MReturn::New(func.alloc, p); + exit->end(ret); + + exit->addPredecessorWithoutPhis(then); + + if (!func.runGVN()) + return false; + + // Test that the not got folded. + test = block->lastIns()->toTest(); + CHECK(test->getOperand(0) == p); + CHECK(test->getSuccessor(0) == else_); + CHECK(test->getSuccessor(1) == then); + return true; +} +END_TEST(testJitNotTest) + +BEGIN_TEST(testJitNotNotTest) +{ + MinimalFunc func; + MBasicBlock *block = func.createEntryBlock(); + MBasicBlock *then = func.createBlock(block); + MBasicBlock *else_ = func.createBlock(block); + MBasicBlock *exit = func.createBlock(block); + + // MTest(Not(Not(p))) + MParameter *p = func.createParameter(); + block->add(p); + MNot *not0 = MNot::New(func.alloc, p); + block->add(not0); + MNot *not1 = MNot::New(func.alloc, not0); + block->add(not1); + MTest *test = MTest::New(func.alloc, not1, then, else_); + block->end(test); + + MNop *anchor = MNop::New(func.alloc); + anchor->setGuard(); + then->add(anchor); + then->end(MGoto::New(func.alloc, exit)); + + else_->end(MGoto::New(func.alloc, exit)); + + MReturn *ret = MReturn::New(func.alloc, p); + exit->end(ret); + + exit->addPredecessorWithoutPhis(then); + + if (!func.runGVN()) + return false; + + // Test that the nots got folded. + test = block->lastIns()->toTest(); + CHECK(test->getOperand(0) == p); + CHECK(test->getSuccessor(0) == then); + CHECK(test->getSuccessor(1) == else_); + return true; +} +END_TEST(testJitNotNotTest)