/* -*- 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/. */ #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::defineBoxReuseInput( LInstructionHelper* lir, MDefinition* mir, uint32_t operand) { // The input should be used at the start of the instruction, to avoid moves. MOZ_ASSERT(lir->getOperand(operand)->toUse()->usedAtStart()); #ifdef JS_NUNBOX32 MOZ_ASSERT(lir->getOperand(operand + 1)->toUse()->usedAtStart()); #endif MOZ_ASSERT(!lir->isCall()); MOZ_ASSERT(mir->type() == MIRType::Value); uint32_t vreg = getVirtualRegister(); #ifdef JS_NUNBOX32 static_assert(VREG_TYPE_OFFSET == 0, "Code below assumes VREG_TYPE_OFFSET == 0"); static_assert(VREG_DATA_OFFSET == 1, "Code below assumes VREG_DATA_OFFSET == 1"); LDefinition def1(LDefinition::TYPE, LDefinition::MUST_REUSE_INPUT); def1.setReusedInput(operand); def1.setVirtualRegister(vreg); lir->setDef(0, def1); getVirtualRegister(); LDefinition def2(LDefinition::PAYLOAD, LDefinition::MUST_REUSE_INPUT); def2.setReusedInput(operand + 1); def2.setVirtualRegister(vreg + 1); lir->setDef(1, def2); #else LDefinition def(LDefinition::BOX, LDefinition::MUST_REUSE_INPUT); def.setReusedInput(operand); def.setVirtualRegister(vreg); lir->setDef(0, def); #endif lir->setMir(mir); mir->setVirtualRegister(vreg); add(lir); } template void LIRGeneratorShared::defineBox( details::LInstructionFixedDefsTempsHelper* 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()); #ifdef JS_64BIT MOZ_ASSERT(mir->type() == MIRType::Int64 || mir->type() == MIRType::IntPtr); #else MOZ_ASSERT(mir->type() == MIRType::Int64); #endif 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::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::Simd128: #ifdef ENABLE_WASM_SIMD lir->setDef(0, LDefinition(vreg, LDefinition::SIMD128, LFloatReg(ReturnSimd128Reg))); break; #else MOZ_CRASH("No SIMD support"); #endif default: LDefinition::Type type = LDefinition::TypeFrom(mir->type()); switch (type) { case LDefinition::GENERAL: case LDefinition::INT32: case LDefinition::OBJECT: case LDefinition::SLOTS: case LDefinition::STACKRESULTS: lir->setDef(0, LDefinition(vreg, type, LGeneralReg(ReturnReg))); break; case LDefinition::DOUBLE: case LDefinition::FLOAT32: case LDefinition::SIMD128: MOZ_CRASH("Float cases must have been handled earlier"); default: MOZ_CRASH("Unexpected type"); } break; } mir->setVirtualRegister(vreg); add(lir); } #ifdef DEBUG // 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; } // In LIR, we treat boolean and int32 as the same low-level type (INTEGER). // When snapshotting, we recover the actual JS type from MIR. if ((to == MIRType::Int32 || to == MIRType::Boolean) && (from == MIRType::Int32 || from == MIRType::Boolean)) { return true; } // On 32-bit platforms Int32 can be redefined as IntPtr and vice versa. // On 64-bit platforms we can redefine non-negative Int32 values as IntPtr. if (from == MIRType::Int32 && to == MIRType::IntPtr) { return true; } # ifndef JS_64BIT if (from == MIRType::IntPtr && to == MIRType::Int32) { return true; } # endif return false; } #endif 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()); } } void LIRGeneratorShared::ensureDefined(MDefinition* mir) { if (mir->isEmittedAtUses()) { visitEmittedAtUses(mir->toInstruction()); MOZ_ASSERT(mir->isLowered()); } } bool LIRGeneratorShared::willHaveDifferentLIRNodes(MDefinition* mir1, MDefinition* mir2) { if (mir1 != mir2) { return true; } if (mir1->isEmittedAtUses()) { return true; } return false; } template LClass* LIRGeneratorShared::allocateVariadic(uint32_t numOperands, Args&&... args) { size_t numBytes = sizeof(LClass) + numOperands * sizeof(LAllocation); void* buf = alloc().allocate(numBytes); if (!buf) { return nullptr; } LClass* ins = static_cast(buf); new (ins) LClass(numOperands, std::forward(args)...); ins->initOperandsOffset(sizeof(LClass)); for (uint32_t i = 0; i < numOperands; i++) { ins->setOperand(i, LAllocation()); } return ins; } 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); } inline bool CanUseInt32Constant(MDefinition* mir) { if (!mir->isConstant()) { return false; } MConstant* cst = mir->toConstant(); if (cst->type() == MIRType::IntPtr) { return INT32_MIN <= cst->toIntPtr() && cst->toIntPtr() <= INT32_MAX; } MOZ_ASSERT(cst->type() == MIRType::Int32); return true; } LAllocation LIRGeneratorShared::useRegisterOrInt32Constant(MDefinition* mir) { if (CanUseInt32Constant(mir)) { return LAllocation(mir->toConstant()); } return useRegister(mir); } LAllocation LIRGeneratorShared::useAnyOrInt32Constant(MDefinition* mir) { if (CanUseInt32Constant(mir)) { return LAllocation(mir->toConstant()); } return useAny(mir); } LAllocation LIRGeneratorShared::useRegisterOrZero(MDefinition* mir) { if (mir->isConstant() && (mir->toConstant()->isInt32(0) || mir->toConstant()->isInt64(0))) { return LAllocation(); } return useRegister(mir); } LAllocation LIRGeneratorShared::useRegisterOrZeroAtStart(MDefinition* mir) { if (mir->isConstant() && (mir->toConstant()->isInt32(0) || mir->toConstant()->isInt64(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) || \ defined(JS_CODEGEN_LOONG64) || defined(JS_CODEGEN_MIPS64) || \ defined(JS_CODEGEN_RISCV64) 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); } LAllocation LIRGeneratorShared::useAnyAtStart(MDefinition* mir) { return useRegisterAtStart(mir); } #else LAllocation LIRGeneratorShared::useAnyOrConstant(MDefinition* mir) { return useOrConstant(mir); } LAllocation LIRGeneratorShared::useAny(MDefinition* mir) { return use(mir); } LAllocation LIRGeneratorShared::useAnyAtStart(MDefinition* mir) { return useAtStart(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; } LInt64Definition LIRGeneratorShared::tempInt64Fixed(Register64 reg) { #if JS_BITS_PER_WORD == 32 LDefinition high = temp(LDefinition::GENERAL); LDefinition low = temp(LDefinition::GENERAL); high.setOutput(LGeneralReg(reg.high)); low.setOutput(LGeneralReg(reg.low)); return LInt64Definition(high, low); #else LDefinition t = temp(LDefinition::GENERAL); t.setOutput(LGeneralReg(reg.reg)); return LInt64Definition(t); #endif } LDefinition LIRGeneratorShared::tempFixed(FloatRegister reg) { LDefinition t = temp(LDefinition::DOUBLE); t.setOutput(LFloatReg(reg)); return t; } LDefinition LIRGeneratorShared::tempFloat32() { return temp(LDefinition::FLOAT32); } LDefinition LIRGeneratorShared::tempDouble() { return temp(LDefinition::DOUBLE); } #ifdef ENABLE_WASM_SIMD LDefinition LIRGeneratorShared::tempSimd128() { return temp(LDefinition::SIMD128); } #endif 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); if (ins->isCall()) { gen->setNeedsOverrecursedCheck(); gen->setNeedsStaticStackAlignment(); } } #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(); } } 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::useBoxOrTyped(MDefinition* mir, bool useAtStart) { if (mir->type() == MIRType::Value) { return useBox(mir, LUse::REGISTER, useAtStart); } #if defined(JS_NUNBOX32) return LBoxAllocation(useAtStart ? useRegisterAtStart(mir) : useRegister(mir), LAllocation()); #else return LBoxAllocation(useAtStart ? useRegisterAtStart(mir) : useRegister(mir)); #endif } LBoxAllocation LIRGeneratorShared::useBoxOrTypedOrConstant(MDefinition* mir, bool useConstant, bool useAtStart) { if (useConstant && mir->isConstant()) { #if defined(JS_NUNBOX32) return LBoxAllocation(LAllocation(mir->toConstant()), LAllocation()); #else return LBoxAllocation(LAllocation(mir->toConstant())); #endif } return useBoxOrTyped(mir, useAtStart); } 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::useInt64FixedAtStart(MDefinition* mir, Register64 regs) { return useInt64Fixed(mir, regs, true); } 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); } LInt64Allocation LIRGeneratorShared::useInt64RegisterAtStart(MDefinition* mir) { return useInt64Register(mir, /* useAtStart = */ true); } LInt64Allocation LIRGeneratorShared::useInt64RegisterOrConstantAtStart( MDefinition* mir) { return useInt64RegisterOrConstant(mir, /* useAtStart = */ true); } LInt64Allocation LIRGeneratorShared::useInt64OrConstantAtStart( MDefinition* mir) { return useInt64OrConstant(mir, /* useAtStart = */ true); } void LIRGeneratorShared::lowerConstantDouble(double d, MInstruction* mir) { define(new (alloc()) LDouble(d), mir); } void LIRGeneratorShared::lowerConstantFloat32(float f, MInstruction* mir) { define(new (alloc()) LFloat32(f), mir); } } // namespace jit } // namespace js #endif /* jit_shared_Lowering_shared_inl_h */