blob: 69d11a010b91975bf860382051db4f9f20756037 [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/MIR.h"
#include "jit/Lowering.h"
#include "jit/shared/Lowering-x86-shared.h"
#include "jit/shared/Lowering-shared-inl.h"
using namespace js;
using namespace js::jit;
LTableSwitch *
LIRGeneratorX86Shared::newLTableSwitch(const LAllocation &in, const LDefinition &inputCopy,
MTableSwitch *tableswitch)
{
return new LTableSwitch(in, inputCopy, temp(), tableswitch);
}
LTableSwitchV *
LIRGeneratorX86Shared::newLTableSwitchV(MTableSwitch *tableswitch)
{
return new LTableSwitchV(temp(), tempFloat(), temp(), tableswitch);
}
bool
LIRGeneratorX86Shared::visitInterruptCheck(MInterruptCheck *ins)
{
LInterruptCheck *lir = new LInterruptCheck();
if (!add(lir, ins))
return false;
if (!assignSafepoint(lir, ins))
return false;
return true;
}
bool
LIRGeneratorX86Shared::visitGuardShape(MGuardShape *ins)
{
JS_ASSERT(ins->obj()->type() == MIRType_Object);
LGuardShape *guard = new LGuardShape(useRegister(ins->obj()));
if (!assignSnapshot(guard, ins->bailoutKind()))
return false;
if (!add(guard, ins))
return false;
return redefine(ins, ins->obj());
}
bool
LIRGeneratorX86Shared::visitGuardObjectType(MGuardObjectType *ins)
{
JS_ASSERT(ins->obj()->type() == MIRType_Object);
LGuardObjectType *guard = new LGuardObjectType(useRegister(ins->obj()));
if (!assignSnapshot(guard))
return false;
if (!add(guard, ins))
return false;
return redefine(ins, ins->obj());
}
bool
LIRGeneratorX86Shared::visitPowHalf(MPowHalf *ins)
{
MDefinition *input = ins->input();
JS_ASSERT(input->type() == MIRType_Double);
LPowHalfD *lir = new LPowHalfD(useRegisterAtStart(input), temp());
return defineReuseInput(lir, ins, 0);
}
bool
LIRGeneratorX86Shared::lowerForShift(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir,
MDefinition *lhs, MDefinition *rhs)
{
ins->setOperand(0, useRegisterAtStart(lhs));
// shift operator should be constant or in register ecx
// x86 can't shift a non-ecx register
if (rhs->isConstant())
ins->setOperand(1, useOrConstant(rhs));
else
ins->setOperand(1, useFixed(rhs, ecx));
return defineReuseInput(ins, mir, 0);
}
bool
LIRGeneratorX86Shared::lowerForALU(LInstructionHelper<1, 1, 0> *ins, MDefinition *mir,
MDefinition *input)
{
ins->setOperand(0, useRegisterAtStart(input));
return defineReuseInput(ins, mir, 0);
}
bool
LIRGeneratorX86Shared::lowerForALU(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir,
MDefinition *lhs, MDefinition *rhs)
{
ins->setOperand(0, useRegisterAtStart(lhs));
ins->setOperand(1, useOrConstant(rhs));
return defineReuseInput(ins, mir, 0);
}
bool
LIRGeneratorX86Shared::lowerForFPU(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir, MDefinition *lhs, MDefinition *rhs)
{
ins->setOperand(0, useRegisterAtStart(lhs));
ins->setOperand(1, use(rhs));
return defineReuseInput(ins, mir, 0);
}
bool
LIRGeneratorX86Shared::lowerMulI(MMul *mul, MDefinition *lhs, MDefinition *rhs)
{
// Note: lhs is used twice, so that we can restore the original value for the
// negative zero check.
LMulI *lir = new LMulI(useRegisterAtStart(lhs), useOrConstant(rhs), use(lhs));
if (mul->fallible() && !assignSnapshot(lir))
return false;
return defineReuseInput(lir, mul, 0);
}
bool
LIRGeneratorX86Shared::lowerDivI(MDiv *div)
{
// Division instructions are slow. Division by constant denominators can be
// rewritten to use other instructions.
if (div->rhs()->isConstant()) {
int32_t rhs = div->rhs()->toConstant()->value().toInt32();
// Check for division by a positive power of two, which is an easy and
// important case to optimize. Note that other optimizations are also
// possible; division by negative powers of two can be optimized in a
// similar manner as positive powers of two, and division by other
// constants can be optimized by a reciprocal multiplication technique.
int32_t shift;
JS_FLOOR_LOG2(shift, rhs);
if (rhs > 0 && 1 << shift == rhs) {
LDivPowTwoI *lir = new LDivPowTwoI(useRegisterAtStart(div->lhs()), useRegister(div->lhs()), shift);
if (div->fallible() && !assignSnapshot(lir))
return false;
return defineReuseInput(lir, div, 0);
}
}
LDivI *lir = new LDivI(useFixed(div->lhs(), eax), useRegister(div->rhs()), tempFixed(edx));
if (div->fallible() && !assignSnapshot(lir))
return false;
return defineFixed(lir, div, LAllocation(AnyRegister(eax)));
}
bool
LIRGeneratorX86Shared::lowerModI(MMod *mod)
{
if (mod->rhs()->isConstant()) {
int32_t rhs = mod->rhs()->toConstant()->value().toInt32();
int32_t shift;
JS_FLOOR_LOG2(shift, rhs);
if (rhs > 0 && 1 << shift == rhs) {
LModPowTwoI *lir = new LModPowTwoI(useRegisterAtStart(mod->lhs()), shift);
if (mod->fallible() && !assignSnapshot(lir))
return false;
return defineReuseInput(lir, mod, 0);
}
}
LModI *lir = new LModI(useRegister(mod->lhs()), useRegister(mod->rhs()), tempFixed(eax));
if (mod->fallible() && !assignSnapshot(lir))
return false;
return defineFixed(lir, mod, LAllocation(AnyRegister(edx)));
}
bool
LIRGeneratorX86Shared::visitAsmJSNeg(MAsmJSNeg *ins)
{
if (ins->type() == MIRType_Int32)
return defineReuseInput(new LNegI(useRegisterAtStart(ins->input())), ins, 0);
JS_ASSERT(ins->type() == MIRType_Double);
return defineReuseInput(new LNegD(useRegisterAtStart(ins->input())), ins, 0);
}
bool
LIRGeneratorX86Shared::visitAsmJSUDiv(MAsmJSUDiv *div)
{
LAsmJSDivOrMod *lir = new LAsmJSDivOrMod(useFixed(div->lhs(), eax),
useRegister(div->rhs()),
tempFixed(edx));
return defineFixed(lir, div, LAllocation(AnyRegister(eax)));
}
bool
LIRGeneratorX86Shared::visitAsmJSUMod(MAsmJSUMod *mod)
{
LAsmJSDivOrMod *lir = new LAsmJSDivOrMod(useFixed(mod->lhs(), eax),
useRegister(mod->rhs()),
LDefinition::BogusTemp());
return defineFixed(lir, mod, LAllocation(AnyRegister(edx)));
}
bool
LIRGeneratorX86Shared::lowerUrshD(MUrsh *mir)
{
MDefinition *lhs = mir->lhs();
MDefinition *rhs = mir->rhs();
JS_ASSERT(lhs->type() == MIRType_Int32);
JS_ASSERT(rhs->type() == MIRType_Int32);
JS_ASSERT(mir->type() == MIRType_Double);
#ifdef JS_CPU_X64
JS_ASSERT(ecx == rcx);
#endif
LUse lhsUse = useRegisterAtStart(lhs);
LAllocation rhsAlloc = rhs->isConstant() ? useOrConstant(rhs) : useFixed(rhs, ecx);
LUrshD *lir = new LUrshD(lhsUse, rhsAlloc, tempCopy(lhs, 0));
return define(lir, mir);
}
bool
LIRGeneratorX86Shared::lowerConstantDouble(double d, MInstruction *mir)
{
return define(new LDouble(d), mir);
}
bool
LIRGeneratorX86Shared::visitConstant(MConstant *ins)
{
if (ins->type() == MIRType_Double)
return lowerConstantDouble(ins->value().toDouble(), ins);
// Emit non-double constants at their uses.
if (ins->canEmitAtUses())
return emitAtUses(ins);
return LIRGeneratorShared::visitConstant(ins);
}
bool
LIRGeneratorX86Shared::lowerTruncateDToInt32(MTruncateToInt32 *ins)
{
MDefinition *opd = ins->input();
JS_ASSERT(opd->type() == MIRType_Double);
LDefinition maybeTemp = Assembler::HasSSE3() ? LDefinition::BogusTemp() : tempFloat();
return define(new LTruncateDToInt32(useRegister(opd), maybeTemp), ins);
}