/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- * vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "jit/IonAnalysis.h" #include "jit/MIRGenerator.h" #include "jit/MIRGraph.h" #include "jit/ValueNumbering.h" #include "jsapi-tests/testJitMinimalFunc.h" #include "jsapi-tests/tests.h" using namespace js; using namespace js::jit; BEGIN_TEST(testJitDCEinGVN_ins) { MinimalFunc func; MBasicBlock* block = func.createEntryBlock(); // mul0 = p * p // mul1 = mul0 * mul0 // return p MParameter* p = func.createParameter(); block->add(p); MMul* mul0 = MMul::New(func.alloc, p, p, MIRType::Double); block->add(mul0); if (!mul0->typePolicy()->adjustInputs(func.alloc, mul0)) { return false; } MMul* mul1 = MMul::New(func.alloc, mul0, mul0, MIRType::Double); block->add(mul1); if (!mul1->typePolicy()->adjustInputs(func.alloc, mul1)) { return false; } MReturn* ret = MReturn::New(func.alloc, p); block->end(ret); if (!func.runGVN()) { return false; } // mul0 and mul1 should be deleted. for (MInstructionIterator ins = block->begin(); ins != block->end(); ins++) { CHECK(!ins->isMul() || (ins->getOperand(0) != p && ins->getOperand(1) != p)); CHECK(!ins->isMul() || (ins->getOperand(0) != mul0 && ins->getOperand(1) != mul0)); } return true; } END_TEST(testJitDCEinGVN_ins) BEGIN_TEST(testJitDCEinGVN_phi) { MinimalFunc func; MBasicBlock* block = func.createEntryBlock(); MBasicBlock* thenBlock1 = func.createBlock(block); MBasicBlock* thenBlock2 = func.createBlock(block); MBasicBlock* elifBlock = func.createBlock(block); MBasicBlock* elseBlock = func.createBlock(block); MBasicBlock* joinBlock = func.createBlock(block); // if (p) { // x = 1.0; // y = 3.0; // } else if (q) { // x = 2.0; // y = 4.0; // } else { // x = 1.0; // y = 5.0; // } // x = phi(1.0, 2.0, 1.0); // y = phi(3.0, 4.0, 5.0); // z = x * y; // return y; MConstant* c1 = MConstant::New(func.alloc, DoubleValue(1.0)); block->add(c1); MPhi* x = MPhi::New(func.alloc); MPhi* y = MPhi::New(func.alloc); // if (p) { MParameter* p = func.createParameter(); block->add(p); block->end(MTest::New(func.alloc, p, thenBlock1, elifBlock)); // x = 1.0 // y = 3.0; MOZ_RELEASE_ASSERT(x->addInputSlow(c1)); MConstant* c3 = MConstant::New(func.alloc, DoubleValue(3.0)); thenBlock1->add(c3); MOZ_RELEASE_ASSERT(y->addInputSlow(c3)); thenBlock1->end(MGoto::New(func.alloc, joinBlock)); MOZ_ALWAYS_TRUE(joinBlock->addPredecessor(func.alloc, thenBlock1)); // } else if (q) { MParameter* q = func.createParameter(); elifBlock->add(q); elifBlock->end(MTest::New(func.alloc, q, thenBlock2, elseBlock)); // x = 2.0 // y = 4.0; MConstant* c2 = MConstant::New(func.alloc, DoubleValue(2.0)); thenBlock2->add(c2); MOZ_RELEASE_ASSERT(x->addInputSlow(c2)); MConstant* c4 = MConstant::New(func.alloc, DoubleValue(4.0)); thenBlock2->add(c4); MOZ_RELEASE_ASSERT(y->addInputSlow(c4)); thenBlock2->end(MGoto::New(func.alloc, joinBlock)); MOZ_ALWAYS_TRUE(joinBlock->addPredecessor(func.alloc, thenBlock2)); // } else { // x = 1.0 // y = 5.0; // } MOZ_RELEASE_ASSERT(x->addInputSlow(c1)); MConstant* c5 = MConstant::New(func.alloc, DoubleValue(5.0)); elseBlock->add(c5); MOZ_RELEASE_ASSERT(y->addInputSlow(c5)); elseBlock->end(MGoto::New(func.alloc, joinBlock)); MOZ_ALWAYS_TRUE(joinBlock->addPredecessor(func.alloc, elseBlock)); // x = phi(1.0, 2.0, 1.0) // y = phi(3.0, 4.0, 5.0) // z = x * y // return y joinBlock->addPhi(x); joinBlock->addPhi(y); MMul* z = MMul::New(func.alloc, x, y, MIRType::Double); joinBlock->add(z); MReturn* ret = MReturn::New(func.alloc, y); joinBlock->end(ret); if (!func.runGVN()) { return false; } // c1 should be deleted. for (MInstructionIterator ins = block->begin(); ins != block->end(); ins++) { CHECK(!ins->isConstant() || (ins->toConstant()->numberToDouble() != 1.0)); } return true; } END_TEST(testJitDCEinGVN_phi)