blob: aa829515be2603ad4b667773ed1a9d0ee23d0171 [file] [log] [blame]
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
*/
/* 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(testJitFoldsTo_DivReciprocal)
{
MinimalFunc func;
MBasicBlock* block = func.createEntryBlock();
// return p / 4.0
MParameter* p = func.createParameter();
block->add(p);
MConstant* c = MConstant::New(func.alloc, DoubleValue(4.0));
block->add(c);
MDiv* div = MDiv::New(func.alloc, p, c, MIRType_Double);
block->add(div);
if (!div->typePolicy()->adjustInputs(func.alloc, div))
return false;
MDefinition* left = div->getOperand(0);
MReturn* ret = MReturn::New(func.alloc, div);
block->end(ret);
if (!func.runGVN())
return false;
// Test that the div got folded to p * 0.25.
MDefinition* op = ret->getOperand(0);
CHECK(op->isMul());
CHECK(op->getOperand(0) == left);
CHECK(op->getOperand(1)->isConstant());
CHECK(op->getOperand(1)->toConstant()->value().toNumber() == 0.25);
return true;
}
END_TEST(testJitFoldsTo_DivReciprocal)
BEGIN_TEST(testJitFoldsTo_NoDivReciprocal)
{
MinimalFunc func;
MBasicBlock* block = func.createEntryBlock();
// return p / 5.0
MParameter* p = func.createParameter();
block->add(p);
MConstant* c = MConstant::New(func.alloc, DoubleValue(5.0));
block->add(c);
MDiv* div = MDiv::New(func.alloc, p, c, MIRType_Double);
block->add(div);
if (!div->typePolicy()->adjustInputs(func.alloc, div))
return false;
MDefinition* left = div->getOperand(0);
MDefinition* right = div->getOperand(1);
MReturn* ret = MReturn::New(func.alloc, div);
block->end(ret);
if (!func.runGVN())
return false;
// Test that the div didn't get folded.
MDefinition* op = ret->getOperand(0);
CHECK(op->isDiv());
CHECK(op->getOperand(0) == left);
CHECK(op->getOperand(1) == right);
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);
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);
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)
BEGIN_TEST(testJitFoldsTo_UnsignedDiv)
{
MinimalFunc func;
MBasicBlock* block = func.createEntryBlock();
// return 1.0 / 0xffffffff
MConstant* c0 = MConstant::New(func.alloc, Int32Value(1));
block->add(c0);
MConstant* c1 = MConstant::New(func.alloc, Int32Value(0xffffffff));
block->add(c1);
MDiv* div = MDiv::NewAsmJS(func.alloc, c0, c1, MIRType_Int32, /*unsignd=*/true);
block->add(div);
MReturn* ret = MReturn::New(func.alloc, div);
block->end(ret);
if (!func.runGVN())
return false;
// Test that the div got folded to 0.
MConstant* op = ret->getOperand(0)->toConstant();
CHECK(mozilla::NumbersAreIdentical(op->value().toNumber(), 0.0));
return true;
}
END_TEST(testJitFoldsTo_UnsignedDiv)
BEGIN_TEST(testJitFoldsTo_UnsignedMod)
{
MinimalFunc func;
MBasicBlock* block = func.createEntryBlock();
// return 1.0 % 0xffffffff
MConstant* c0 = MConstant::New(func.alloc, Int32Value(1));
block->add(c0);
MConstant* c1 = MConstant::New(func.alloc, Int32Value(0xffffffff));
block->add(c1);
MMod* mod = MMod::NewAsmJS(func.alloc, c0, c1, MIRType_Int32, /*unsignd=*/true);
block->add(mod);
MReturn* ret = MReturn::New(func.alloc, mod);
block->end(ret);
if (!func.runGVN())
return false;
// Test that the mod got folded to 1.
MConstant* op = ret->getOperand(0)->toConstant();
CHECK(mozilla::NumbersAreIdentical(op->value().toNumber(), 1.0));
return true;
}
END_TEST(testJitFoldsTo_UnsignedMod)