/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * 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/. */ #ifndef jit_shared_Lowering_shared_inl_h #define jit_shared_Lowering_shared_inl_h #include "jit/shared/Lowering-shared.h" #include "jit/MIR.h" #include "jit/MIRGenerator.h" namespace js { namespace jit { void LIRGeneratorShared::emitAtUses(MInstruction* mir) { MOZ_ASSERT(mir->canEmitAtUses()); mir->setEmittedAtUses(); mir->setVirtualRegister(0); } LUse LIRGeneratorShared::use(MDefinition* mir, LUse policy) { // It is illegal to call use() on an instruction with two defs. #if BOX_PIECES > 1 MOZ_ASSERT(mir->type() != MIRType::Value); #endif #if INT64_PIECES > 1 MOZ_ASSERT(mir->type() != MIRType::Int64); #endif ensureDefined(mir); policy.setVirtualRegister(mir->virtualRegister()); return policy; } template void LIRGeneratorShared::define(details::LInstructionFixedDefsTempsHelper<1, X>* lir, MDefinition* mir, LDefinition::Policy policy) { LDefinition::Type type = LDefinition::TypeFrom(mir->type()); define(lir, mir, LDefinition(type, policy)); } template void LIRGeneratorShared::define(details::LInstructionFixedDefsTempsHelper<1, X>* lir, MDefinition* mir, const LDefinition& def) { // Call instructions should use defineReturn. MOZ_ASSERT(!lir->isCall()); uint32_t vreg = getVirtualRegister(); // Assign the definition and a virtual register. Then, propagate this // virtual register to the MIR, so we can map MIR to LIR during lowering. lir->setDef(0, def); lir->getDef(0)->setVirtualRegister(vreg); lir->setMir(mir); mir->setVirtualRegister(vreg); add(lir); } template void LIRGeneratorShared::defineFixed(LInstructionHelper<1, X, Y>* lir, MDefinition* mir, const LAllocation& output) { LDefinition::Type type = LDefinition::TypeFrom(mir->type()); LDefinition def(type, LDefinition::FIXED); def.setOutput(output); define(lir, mir, def); } template void LIRGeneratorShared::defineInt64Fixed(LInstructionHelper* lir, MDefinition* mir, const LInt64Allocation& output) { uint32_t vreg = getVirtualRegister(); #if JS_BITS_PER_WORD == 64 LDefinition def(LDefinition::GENERAL, LDefinition::FIXED); def.setOutput(output.value()); lir->setDef(0, def); lir->getDef(0)->setVirtualRegister(vreg); #else LDefinition def0(LDefinition::GENERAL, LDefinition::FIXED); def0.setOutput(output.low()); lir->setDef(0, def0); lir->getDef(0)->setVirtualRegister(vreg); getVirtualRegister(); LDefinition def1(LDefinition::GENERAL, LDefinition::FIXED); def1.setOutput(output.high()); lir->setDef(1, def1); lir->getDef(1)->setVirtualRegister(vreg + 1); #endif lir->setMir(mir); mir->setVirtualRegister(vreg); add(lir); } template void LIRGeneratorShared::defineReuseInput(LInstructionHelper<1, Ops, Temps>* lir, MDefinition* mir, uint32_t operand) { // Note: Any other operand that is not the same as this operand should be // marked as not being "atStart". The regalloc cannot handle those and can // overwrite the inputs! // The input should be used at the start of the instruction, to avoid moves. MOZ_ASSERT(lir->getOperand(operand)->toUse()->usedAtStart()); LDefinition::Type type = LDefinition::TypeFrom(mir->type()); LDefinition def(type, LDefinition::MUST_REUSE_INPUT); def.setReusedInput(operand); define(lir, mir, def); } template void LIRGeneratorShared::defineInt64ReuseInput(LInstructionHelper* lir, MDefinition* mir, uint32_t operand) { // Note: Any other operand that is not the same as this operand should be // marked as not being "atStart". The regalloc cannot handle those and can // overwrite the inputs! // The input should be used at the start of the instruction, to avoid moves. MOZ_ASSERT(lir->getOperand(operand)->toUse()->usedAtStart()); #if JS_BITS_PER_WORD == 32 MOZ_ASSERT(lir->getOperand(operand + 1)->toUse()->usedAtStart()); #endif MOZ_ASSERT(!lir->isCall()); uint32_t vreg = getVirtualRegister(); LDefinition def1(LDefinition::GENERAL, LDefinition::MUST_REUSE_INPUT); def1.setReusedInput(operand); lir->setDef(0, def1); lir->getDef(0)->setVirtualRegister(vreg); #if JS_BITS_PER_WORD == 32 getVirtualRegister(); LDefinition def2(LDefinition::GENERAL, LDefinition::MUST_REUSE_INPUT); def2.setReusedInput(operand + 1); lir->setDef(1, def2); lir->getDef(1)->setVirtualRegister(vreg + 1); #endif lir->setMir(mir); mir->setVirtualRegister(vreg); add(lir); } template void LIRGeneratorShared::defineBox(LInstructionHelper* lir, MDefinition* mir, LDefinition::Policy policy) { // Call instructions should use defineReturn. MOZ_ASSERT(!lir->isCall()); MOZ_ASSERT(mir->type() == MIRType::Value); uint32_t vreg = getVirtualRegister(); #if defined(JS_NUNBOX32) lir->setDef(0, LDefinition(vreg + VREG_TYPE_OFFSET, LDefinition::TYPE, policy)); lir->setDef(1, LDefinition(vreg + VREG_DATA_OFFSET, LDefinition::PAYLOAD, policy)); getVirtualRegister(); #elif defined(JS_PUNBOX64) lir->setDef(0, LDefinition(vreg, LDefinition::BOX, policy)); #endif lir->setMir(mir); mir->setVirtualRegister(vreg); add(lir); } template void LIRGeneratorShared::defineInt64(LInstructionHelper* lir, MDefinition* mir, LDefinition::Policy policy) { // Call instructions should use defineReturn. MOZ_ASSERT(!lir->isCall()); MOZ_ASSERT(mir->type() == MIRType::Int64); uint32_t vreg = getVirtualRegister(); #if JS_BITS_PER_WORD == 32 lir->setDef(0, LDefinition(vreg + INT64LOW_INDEX, LDefinition::GENERAL, policy)); lir->setDef(1, LDefinition(vreg + INT64HIGH_INDEX, LDefinition::GENERAL, policy)); getVirtualRegister(); #else lir->setDef(0, LDefinition(vreg, LDefinition::GENERAL, policy)); #endif lir->setMir(mir); mir->setVirtualRegister(vreg); add(lir); } void LIRGeneratorShared::defineSharedStubReturn(LInstruction* lir, MDefinition* mir) { lir->setMir(mir); MOZ_ASSERT(lir->isBinarySharedStub() || lir->isUnarySharedStub() || lir->isNullarySharedStub()); MOZ_ASSERT(mir->type() == MIRType::Value); uint32_t vreg = getVirtualRegister(); #if defined(JS_NUNBOX32) lir->setDef(TYPE_INDEX, LDefinition(vreg + VREG_TYPE_OFFSET, LDefinition::TYPE, LGeneralReg(JSReturnReg_Type))); lir->setDef(PAYLOAD_INDEX, LDefinition(vreg + VREG_DATA_OFFSET, LDefinition::PAYLOAD, LGeneralReg(JSReturnReg_Data))); getVirtualRegister(); #elif defined(JS_PUNBOX64) lir->setDef(0, LDefinition(vreg, LDefinition::BOX, LGeneralReg(JSReturnReg))); #endif mir->setVirtualRegister(vreg); add(lir); } void LIRGeneratorShared::defineReturn(LInstruction* lir, MDefinition* mir) { lir->setMir(mir); MOZ_ASSERT(lir->isCall()); uint32_t vreg = getVirtualRegister(); switch (mir->type()) { case MIRType::Value: #if defined(JS_NUNBOX32) lir->setDef(TYPE_INDEX, LDefinition(vreg + VREG_TYPE_OFFSET, LDefinition::TYPE, LGeneralReg(JSReturnReg_Type))); lir->setDef(PAYLOAD_INDEX, LDefinition(vreg + VREG_DATA_OFFSET, LDefinition::PAYLOAD, LGeneralReg(JSReturnReg_Data))); getVirtualRegister(); #elif defined(JS_PUNBOX64) lir->setDef(0, LDefinition(vreg, LDefinition::BOX, LGeneralReg(JSReturnReg))); #endif break; case MIRType::Int64: #if defined(JS_NUNBOX32) lir->setDef(INT64LOW_INDEX, LDefinition(vreg + INT64LOW_INDEX, LDefinition::GENERAL, LGeneralReg(ReturnReg64.low))); lir->setDef(INT64HIGH_INDEX, LDefinition(vreg + INT64HIGH_INDEX, LDefinition::GENERAL, LGeneralReg(ReturnReg64.high))); getVirtualRegister(); #elif defined(JS_PUNBOX64) lir->setDef(0, LDefinition(vreg, LDefinition::GENERAL, LGeneralReg(ReturnReg))); #endif break; case MIRType::Float32: lir->setDef(0, LDefinition(vreg, LDefinition::FLOAT32, LFloatReg(ReturnFloat32Reg))); break; case MIRType::Double: lir->setDef(0, LDefinition(vreg, LDefinition::DOUBLE, LFloatReg(ReturnDoubleReg))); break; case MIRType::Int8x16: case MIRType::Int16x8: case MIRType::Int32x4: case MIRType::Bool8x16: case MIRType::Bool16x8: case MIRType::Bool32x4: lir->setDef(0, LDefinition(vreg, LDefinition::SIMD128INT, LFloatReg(ReturnSimd128Reg))); break; case MIRType::Float32x4: lir->setDef(0, LDefinition(vreg, LDefinition::SIMD128FLOAT, LFloatReg(ReturnSimd128Reg))); break; default: LDefinition::Type type = LDefinition::TypeFrom(mir->type()); MOZ_ASSERT(type != LDefinition::DOUBLE && type != LDefinition::FLOAT32); lir->setDef(0, LDefinition(vreg, type, LGeneralReg(ReturnReg))); break; } mir->setVirtualRegister(vreg); add(lir); } template void LIRGeneratorShared::defineSinCos(LInstructionHelper<2, Ops, Temps> *lir, MDefinition *mir, LDefinition::Policy policy) { MOZ_ASSERT(lir->isCall()); uint32_t vreg = getVirtualRegister(); lir->setDef(0, LDefinition(vreg, LDefinition::DOUBLE, LFloatReg(ReturnDoubleReg))); #if defined(JS_CODEGEN_ARM) lir->setDef(1, LDefinition(vreg + VREG_INCREMENT, LDefinition::DOUBLE, LFloatReg(FloatRegister(FloatRegisters::d1, FloatRegister::Double)))); #elif defined(JS_CODEGEN_ARM64) lir->setDef(1, LDefinition(vreg + VREG_INCREMENT, LDefinition::DOUBLE, LFloatReg(FloatRegister(FloatRegisters::d1, FloatRegisters::Double)))); #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) lir->setDef(1, LDefinition(vreg + VREG_INCREMENT, LDefinition::DOUBLE, LFloatReg(f2))); #elif defined(JS_CODEGEN_NONE) MOZ_CRASH(); #elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) lir->setDef(1, LDefinition(vreg + VREG_INCREMENT, LDefinition::DOUBLE, LFloatReg(xmm1))); #else #error "Unsupported architecture for SinCos" #endif getVirtualRegister(); lir->setMir(mir); mir->setVirtualRegister(vreg); add(lir); return; } // In LIR, we treat booleans and integers as the same low-level type (INTEGER). // When snapshotting, we recover the actual JS type from MIR. This function // checks that when making redefinitions, we don't accidentally coerce two // incompatible types. static inline bool IsCompatibleLIRCoercion(MIRType to, MIRType from) { if (to == from) return true; if ((to == MIRType::Int32 || to == MIRType::Boolean) && (from == MIRType::Int32 || from == MIRType::Boolean)) { return true; } // SIMD types can be coerced with from*Bits operators. if (IsSimdType(to) && IsSimdType(from)) return true; return false; } // We can redefine the sin(x) and cos(x) function to return the sincos result. void LIRGeneratorShared::redefine(MDefinition* def, MDefinition* as, MMathFunction::Function func) { MOZ_ASSERT(def->isMathFunction()); MOZ_ASSERT(def->type() == MIRType::Double && as->type() == MIRType::SinCosDouble); MOZ_ASSERT(MMathFunction::Sin == func || MMathFunction::Cos == func); ensureDefined(as); MMathFunction *math = def->toMathFunction(); MOZ_ASSERT(math->function() == MMathFunction::Cos || math->function() == MMathFunction::Sin); // The sincos returns two values: // - VREG: it returns the sin's value of the sincos; // - VREG + VREG_INCREMENT: it returns the cos' value of the sincos. if (math->function() == MMathFunction::Sin) def->setVirtualRegister(as->virtualRegister()); else def->setVirtualRegister(as->virtualRegister() + VREG_INCREMENT); } void LIRGeneratorShared::redefine(MDefinition* def, MDefinition* as) { MOZ_ASSERT(IsCompatibleLIRCoercion(def->type(), as->type())); // Try to emit MIR marked as emitted-at-uses at, well, uses. For // snapshotting reasons we delay the MIRTypes match, or when we are // coercing between bool and int32 constants. if (as->isEmittedAtUses() && (def->type() == as->type() || (as->isConstant() && (def->type() == MIRType::Int32 || def->type() == MIRType::Boolean) && (as->type() == MIRType::Int32 || as->type() == MIRType::Boolean)))) { MInstruction* replacement; if (def->type() != as->type()) { if (as->type() == MIRType::Int32) replacement = MConstant::New(alloc(), BooleanValue(as->toConstant()->toInt32())); else replacement = MConstant::New(alloc(), Int32Value(as->toConstant()->toBoolean())); def->block()->insertBefore(def->toInstruction(), replacement); emitAtUses(replacement->toInstruction()); } else { replacement = as->toInstruction(); } def->replaceAllUsesWith(replacement); } else { ensureDefined(as); def->setVirtualRegister(as->virtualRegister()); #ifdef DEBUG if (JitOptions.runExtraChecks && def->resultTypeSet() && as->resultTypeSet() && !def->resultTypeSet()->equals(as->resultTypeSet())) { switch (def->type()) { case MIRType::Object: case MIRType::ObjectOrNull: case MIRType::String: case MIRType::Symbol: { LAssertResultT* check = new(alloc()) LAssertResultT(useRegister(def)); add(check, def->toInstruction()); break; } case MIRType::Value: { LAssertResultV* check = new(alloc()) LAssertResultV(useBox(def)); add(check, def->toInstruction()); break; } default: break; } } #endif } } void LIRGeneratorShared::ensureDefined(MDefinition* mir) { if (mir->isEmittedAtUses()) { mir->toInstruction()->accept(this); MOZ_ASSERT(mir->isLowered()); } } LUse LIRGeneratorShared::useRegister(MDefinition* mir) { return use(mir, LUse(LUse::REGISTER)); } LUse LIRGeneratorShared::useRegisterAtStart(MDefinition* mir) { return use(mir, LUse(LUse::REGISTER, true)); } LUse LIRGeneratorShared::use(MDefinition* mir) { return use(mir, LUse(LUse::ANY)); } LUse LIRGeneratorShared::useAtStart(MDefinition* mir) { return use(mir, LUse(LUse::ANY, true)); } LAllocation LIRGeneratorShared::useOrConstant(MDefinition* mir) { if (mir->isConstant()) return LAllocation(mir->toConstant()); return use(mir); } LAllocation LIRGeneratorShared::useOrConstantAtStart(MDefinition* mir) { if (mir->isConstant()) return LAllocation(mir->toConstant()); return useAtStart(mir); } LAllocation LIRGeneratorShared::useRegisterOrConstant(MDefinition* mir) { if (mir->isConstant()) return LAllocation(mir->toConstant()); return useRegister(mir); } LAllocation LIRGeneratorShared::useRegisterOrConstantAtStart(MDefinition* mir) { if (mir->isConstant()) return LAllocation(mir->toConstant()); return useRegisterAtStart(mir); } LAllocation LIRGeneratorShared::useRegisterOrZeroAtStart(MDefinition* mir) { if (mir->isConstant() && mir->toConstant()->isInt32(0)) return LAllocation(); return useRegisterAtStart(mir); } LAllocation LIRGeneratorShared::useRegisterOrNonDoubleConstant(MDefinition* mir) { if (mir->isConstant() && mir->type() != MIRType::Double && mir->type() != MIRType::Float32) return LAllocation(mir->toConstant()); return useRegister(mir); } #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) LAllocation LIRGeneratorShared::useAnyOrConstant(MDefinition* mir) { return useRegisterOrConstant(mir); } LAllocation LIRGeneratorShared::useStorable(MDefinition* mir) { return useRegister(mir); } LAllocation LIRGeneratorShared::useStorableAtStart(MDefinition* mir) { return useRegisterAtStart(mir); } LAllocation LIRGeneratorShared::useAny(MDefinition* mir) { return useRegister(mir); } #else LAllocation LIRGeneratorShared::useAnyOrConstant(MDefinition* mir) { return useOrConstant(mir); } LAllocation LIRGeneratorShared::useAny(MDefinition* mir) { return use(mir); } LAllocation LIRGeneratorShared::useStorable(MDefinition* mir) { return useRegisterOrConstant(mir); } LAllocation LIRGeneratorShared::useStorableAtStart(MDefinition* mir) { return useRegisterOrConstantAtStart(mir); } #endif LAllocation LIRGeneratorShared::useKeepalive(MDefinition* mir) { return use(mir, LUse(LUse::KEEPALIVE)); } LAllocation LIRGeneratorShared::useKeepaliveOrConstant(MDefinition* mir) { if (mir->isConstant()) return LAllocation(mir->toConstant()); return useKeepalive(mir); } LUse LIRGeneratorShared::useFixed(MDefinition* mir, Register reg) { return use(mir, LUse(reg)); } LUse LIRGeneratorShared::useFixedAtStart(MDefinition* mir, Register reg) { return use(mir, LUse(reg, true)); } LUse LIRGeneratorShared::useFixed(MDefinition* mir, FloatRegister reg) { return use(mir, LUse(reg)); } LUse LIRGeneratorShared::useFixed(MDefinition* mir, AnyRegister reg) { return reg.isFloat() ? use(mir, LUse(reg.fpu())) : use(mir, LUse(reg.gpr())); } LUse LIRGeneratorShared::useFixedAtStart(MDefinition* mir, AnyRegister reg) { return reg.isFloat() ? use(mir, LUse(reg.fpu(), true)) : use(mir, LUse(reg.gpr(), true)); } LDefinition LIRGeneratorShared::temp(LDefinition::Type type, LDefinition::Policy policy) { return LDefinition(getVirtualRegister(), type, policy); } LInt64Definition LIRGeneratorShared::tempInt64(LDefinition::Policy policy) { #if JS_BITS_PER_WORD == 32 LDefinition high = temp(LDefinition::GENERAL, policy); LDefinition low = temp(LDefinition::GENERAL, policy); return LInt64Definition(high, low); #else return LInt64Definition(temp(LDefinition::GENERAL, policy)); #endif } LDefinition LIRGeneratorShared::tempFixed(Register reg) { LDefinition t = temp(LDefinition::GENERAL); t.setOutput(LGeneralReg(reg)); return t; } LDefinition LIRGeneratorShared::tempFloat32() { return temp(LDefinition::FLOAT32); } LDefinition LIRGeneratorShared::tempDouble() { return temp(LDefinition::DOUBLE); } LDefinition LIRGeneratorShared::tempCopy(MDefinition* input, uint32_t reusedInput) { MOZ_ASSERT(input->virtualRegister()); LDefinition t = temp(LDefinition::TypeFrom(input->type()), LDefinition::MUST_REUSE_INPUT); t.setReusedInput(reusedInput); return t; } template void LIRGeneratorShared::annotate(T* ins) { ins->setId(lirGraph_.getInstructionId()); } template void LIRGeneratorShared::add(T* ins, MInstruction* mir) { MOZ_ASSERT(!ins->isPhi()); current->add(ins); if (mir) { MOZ_ASSERT(current == mir->block()->lir()); ins->setMir(mir); } annotate(ins); } #ifdef JS_NUNBOX32 // Returns the virtual register of a js::Value-defining instruction. This is // abstracted because MBox is a special value-returning instruction that // redefines its input payload if its input is not constant. Therefore, it is // illegal to request a box's payload by adding VREG_DATA_OFFSET to its raw id. static inline uint32_t VirtualRegisterOfPayload(MDefinition* mir) { if (mir->isBox()) { MDefinition* inner = mir->toBox()->getOperand(0); if (!inner->isConstant() && inner->type() != MIRType::Double && inner->type() != MIRType::Float32) return inner->virtualRegister(); } if (mir->isTypeBarrier()) return VirtualRegisterOfPayload(mir->getOperand(0)); return mir->virtualRegister() + VREG_DATA_OFFSET; } // Note: always call ensureDefined before calling useType/usePayload, // so that emitted-at-use operands are handled correctly. LUse LIRGeneratorShared::useType(MDefinition* mir, LUse::Policy policy) { MOZ_ASSERT(mir->type() == MIRType::Value); return LUse(mir->virtualRegister() + VREG_TYPE_OFFSET, policy); } LUse LIRGeneratorShared::usePayload(MDefinition* mir, LUse::Policy policy) { MOZ_ASSERT(mir->type() == MIRType::Value); return LUse(VirtualRegisterOfPayload(mir), policy); } LUse LIRGeneratorShared::usePayloadAtStart(MDefinition* mir, LUse::Policy policy) { MOZ_ASSERT(mir->type() == MIRType::Value); return LUse(VirtualRegisterOfPayload(mir), policy, true); } LUse LIRGeneratorShared::usePayloadInRegisterAtStart(MDefinition* mir) { return usePayloadAtStart(mir, LUse::REGISTER); } void LIRGeneratorShared::fillBoxUses(LInstruction* lir, size_t n, MDefinition* mir) { ensureDefined(mir); lir->getOperand(n)->toUse()->setVirtualRegister(mir->virtualRegister() + VREG_TYPE_OFFSET); lir->getOperand(n + 1)->toUse()->setVirtualRegister(VirtualRegisterOfPayload(mir)); } #endif LUse LIRGeneratorShared::useRegisterForTypedLoad(MDefinition* mir, MIRType type) { MOZ_ASSERT(type != MIRType::Value && type != MIRType::None); MOZ_ASSERT(mir->type() == MIRType::Object || mir->type() == MIRType::Slots); #ifdef JS_PUNBOX64 // On x64, masm.loadUnboxedValue emits slightly less efficient code when // the input and output use the same register and we're not loading an // int32/bool/double, so we just call useRegister in this case. if (type != MIRType::Int32 && type != MIRType::Boolean && type != MIRType::Double) return useRegister(mir); #endif return useRegisterAtStart(mir); } LBoxAllocation LIRGeneratorShared::useBox(MDefinition* mir, LUse::Policy policy, bool useAtStart) { MOZ_ASSERT(mir->type() == MIRType::Value); ensureDefined(mir); #if defined(JS_NUNBOX32) return LBoxAllocation(LUse(mir->virtualRegister(), policy, useAtStart), LUse(VirtualRegisterOfPayload(mir), policy, useAtStart)); #else return LBoxAllocation(LUse(mir->virtualRegister(), policy, useAtStart)); #endif } LBoxAllocation LIRGeneratorShared::useBoxOrTypedOrConstant(MDefinition* mir, bool useConstant) { if (mir->type() == MIRType::Value) return useBox(mir); if (useConstant && mir->isConstant()) { #if defined(JS_NUNBOX32) return LBoxAllocation(LAllocation(mir->toConstant()), LAllocation()); #else return LBoxAllocation(LAllocation(mir->toConstant())); #endif } #if defined(JS_NUNBOX32) return LBoxAllocation(useRegister(mir), LAllocation()); #else return LBoxAllocation(useRegister(mir)); #endif } LInt64Allocation LIRGeneratorShared::useInt64(MDefinition* mir, LUse::Policy policy, bool useAtStart) { MOZ_ASSERT(mir->type() == MIRType::Int64); ensureDefined(mir); uint32_t vreg = mir->virtualRegister(); #if JS_BITS_PER_WORD == 32 return LInt64Allocation(LUse(vreg + INT64HIGH_INDEX, policy, useAtStart), LUse(vreg + INT64LOW_INDEX, policy, useAtStart)); #else return LInt64Allocation(LUse(vreg, policy, useAtStart)); #endif } LInt64Allocation LIRGeneratorShared::useInt64Fixed(MDefinition* mir, Register64 regs, bool useAtStart) { MOZ_ASSERT(mir->type() == MIRType::Int64); ensureDefined(mir); uint32_t vreg = mir->virtualRegister(); #if JS_BITS_PER_WORD == 32 return LInt64Allocation(LUse(regs.high, vreg + INT64HIGH_INDEX, useAtStart), LUse(regs.low, vreg + INT64LOW_INDEX, useAtStart)); #else return LInt64Allocation(LUse(regs.reg, vreg, useAtStart)); #endif } LInt64Allocation LIRGeneratorShared::useInt64(MDefinition* mir, bool useAtStart) { // On 32-bit platforms, always load the value in registers. #if JS_BITS_PER_WORD == 32 return useInt64(mir, LUse::REGISTER, useAtStart); #else return useInt64(mir, LUse::ANY, useAtStart); #endif } LInt64Allocation LIRGeneratorShared::useInt64AtStart(MDefinition* mir) { return useInt64(mir, /* useAtStart = */ true); } LInt64Allocation LIRGeneratorShared::useInt64Register(MDefinition* mir, bool useAtStart) { return useInt64(mir, LUse::REGISTER, useAtStart); } LInt64Allocation LIRGeneratorShared::useInt64OrConstant(MDefinition* mir, bool useAtStart) { if (mir->isConstant()) { #if defined(JS_NUNBOX32) return LInt64Allocation(LAllocation(mir->toConstant()), LAllocation()); #else return LInt64Allocation(LAllocation(mir->toConstant())); #endif } return useInt64(mir, useAtStart); } LInt64Allocation LIRGeneratorShared::useInt64RegisterOrConstant(MDefinition* mir, bool useAtStart) { if (mir->isConstant()) { #if defined(JS_NUNBOX32) return LInt64Allocation(LAllocation(mir->toConstant()), LAllocation()); #else return LInt64Allocation(LAllocation(mir->toConstant())); #endif } return useInt64Register(mir, useAtStart); } } // namespace jit } // namespace js #endif /* jit_shared_Lowering_shared_inl_h */