| /* -*- 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); |
| } |