void CodeGeneratorX86::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins) { const MLoadTypedArrayElementStatic* mir = ins->mir(); Scalar::Type accessType = mir->accessType(); MOZ_ASSERT_IF(accessType == Scalar::Float32, mir->type() == MIRType::Float32); Register ptr = ToRegister(ins->ptr()); AnyRegister out = ToAnyRegister(ins->output()); OutOfLineLoadTypedArrayOutOfBounds* ool = nullptr; uint32_t offset = mir->offset(); if (mir->needsBoundsCheck()) { MOZ_ASSERT(offset == 0); if (!mir->fallible()) { ool = new(alloc()) OutOfLineLoadTypedArrayOutOfBounds(out, accessType); addOutOfLineCode(ool, ins->mir()); } masm.cmpPtr(ptr, ImmWord(mir->length())); if (ool) masm.j(Assembler::AboveOrEqual, ool->entry()); else bailoutIf(Assembler::AboveOrEqual, ins->snapshot()); } Operand srcAddr(ptr, int32_t(mir->base().asValue()) + int32_t(offset)); switch (accessType) { case Scalar::Int8: masm.movsblWithPatch(srcAddr, out.gpr()); break; case Scalar::Uint8Clamped: case Scalar::Uint8: masm.movzblWithPatch(srcAddr, out.gpr()); break; case Scalar::Int16: masm.movswlWithPatch(srcAddr, out.gpr()); break; case Scalar::Uint16: masm.movzwlWithPatch(srcAddr, out.gpr()); break; case Scalar::Int32: case Scalar::Uint32: masm.movlWithPatch(srcAddr, out.gpr()); break; case Scalar::Float32: masm.vmovssWithPatch(srcAddr, out.fpu()); break; case Scalar::Float64: masm.vmovsdWithPatch(srcAddr, out.fpu()); break; default: MOZ_CRASH("Unexpected type"); } if (accessType == Scalar::Float64) masm.canonicalizeDouble(out.fpu()); if (accessType == Scalar::Float32) masm.canonicalizeFloat(out.fpu()); if (ool) masm.bind(ool->rejoin()); }
void MacroAssemblerX86Shared::atomicExchangeToTypedIntArray(Scalar::Type arrayType, const T& mem, Register value, Register temp, AnyRegister output) { switch (arrayType) { case Scalar::Int8: atomicExchange8SignExtend(mem, value, output.gpr()); break; case Scalar::Uint8: atomicExchange8ZeroExtend(mem, value, output.gpr()); break; case Scalar::Int16: atomicExchange16SignExtend(mem, value, output.gpr()); break; case Scalar::Uint16: atomicExchange16ZeroExtend(mem, value, output.gpr()); break; case Scalar::Int32: atomicExchange32(mem, value, output.gpr()); break; case Scalar::Uint32: // At the moment, the code in MCallOptimize.cpp requires the output // type to be double for uint32 arrays. See bug 1077305. MOZ_ASSERT(output.isFloat()); atomicExchange32(mem, value, temp); asMasm().convertUInt32ToDouble(temp, output.fpu()); break; default: MOZ_CRASH("Invalid typed array type"); } }
void MacroAssembler::loadFromTypedArray(int arrayType, const T &src, AnyRegister dest, Register temp, Label *fail) { switch (arrayType) { case TypedArray::TYPE_INT8: load8SignExtend(src, dest.gpr()); break; case TypedArray::TYPE_UINT8: case TypedArray::TYPE_UINT8_CLAMPED: load8ZeroExtend(src, dest.gpr()); break; case TypedArray::TYPE_INT16: load16SignExtend(src, dest.gpr()); break; case TypedArray::TYPE_UINT16: load16ZeroExtend(src, dest.gpr()); break; case TypedArray::TYPE_INT32: load32(src, dest.gpr()); break; case TypedArray::TYPE_UINT32: if (dest.isFloat()) { load32(src, temp); convertUInt32ToDouble(temp, dest.fpu()); } else { load32(src, dest.gpr()); test32(dest.gpr(), dest.gpr()); j(Assembler::Signed, fail); } break; case TypedArray::TYPE_FLOAT32: case TypedArray::TYPE_FLOAT64: if (arrayType == js::TypedArray::TYPE_FLOAT32) loadFloatAsDouble(src, dest.fpu()); else loadDouble(src, dest.fpu()); canonicalizeDouble(dest.fpu()); break; default: JS_NOT_REACHED("Invalid typed array type"); break; } }
static void SetRegisterToCoercedUndefined(CONTEXT *context, bool isFloat32, AnyRegister reg) { if (reg.isFloat()) { switch (reg.fpu().code()) { case JSC::X86Registers::xmm0: SetXMMRegToNaN(isFloat32, &XMM_sig(context, 0)); break; case JSC::X86Registers::xmm1: SetXMMRegToNaN(isFloat32, &XMM_sig(context, 1)); break; case JSC::X86Registers::xmm2: SetXMMRegToNaN(isFloat32, &XMM_sig(context, 2)); break; case JSC::X86Registers::xmm3: SetXMMRegToNaN(isFloat32, &XMM_sig(context, 3)); break; case JSC::X86Registers::xmm4: SetXMMRegToNaN(isFloat32, &XMM_sig(context, 4)); break; case JSC::X86Registers::xmm5: SetXMMRegToNaN(isFloat32, &XMM_sig(context, 5)); break; case JSC::X86Registers::xmm6: SetXMMRegToNaN(isFloat32, &XMM_sig(context, 6)); break; case JSC::X86Registers::xmm7: SetXMMRegToNaN(isFloat32, &XMM_sig(context, 7)); break; case JSC::X86Registers::xmm8: SetXMMRegToNaN(isFloat32, &XMM_sig(context, 8)); break; case JSC::X86Registers::xmm9: SetXMMRegToNaN(isFloat32, &XMM_sig(context, 9)); break; case JSC::X86Registers::xmm10: SetXMMRegToNaN(isFloat32, &XMM_sig(context, 10)); break; case JSC::X86Registers::xmm11: SetXMMRegToNaN(isFloat32, &XMM_sig(context, 11)); break; case JSC::X86Registers::xmm12: SetXMMRegToNaN(isFloat32, &XMM_sig(context, 12)); break; case JSC::X86Registers::xmm13: SetXMMRegToNaN(isFloat32, &XMM_sig(context, 13)); break; case JSC::X86Registers::xmm14: SetXMMRegToNaN(isFloat32, &XMM_sig(context, 14)); break; case JSC::X86Registers::xmm15: SetXMMRegToNaN(isFloat32, &XMM_sig(context, 15)); break; default: MOZ_CRASH(); } } else { switch (reg.gpr().code()) { case JSC::X86Registers::eax: RAX_sig(context) = 0; break; case JSC::X86Registers::ecx: RCX_sig(context) = 0; break; case JSC::X86Registers::edx: RDX_sig(context) = 0; break; case JSC::X86Registers::ebx: RBX_sig(context) = 0; break; case JSC::X86Registers::esp: RSP_sig(context) = 0; break; case JSC::X86Registers::ebp: RBP_sig(context) = 0; break; case JSC::X86Registers::esi: RSI_sig(context) = 0; break; case JSC::X86Registers::edi: RDI_sig(context) = 0; break; case JSC::X86Registers::r8: R8_sig(context) = 0; break; case JSC::X86Registers::r9: R9_sig(context) = 0; break; case JSC::X86Registers::r10: R10_sig(context) = 0; break; case JSC::X86Registers::r11: R11_sig(context) = 0; break; case JSC::X86Registers::r12: R12_sig(context) = 0; break; case JSC::X86Registers::r13: R13_sig(context) = 0; break; case JSC::X86Registers::r14: R14_sig(context) = 0; break; case JSC::X86Registers::r15: R15_sig(context) = 0; break; default: MOZ_CRASH(); } } }
bool GreedyAllocator::allocateDefinition(LInstruction *ins, LDefinition *def) { VirtualRegister *vr = getVirtualRegister(def); LAllocation output; switch (def->policy()) { case LDefinition::PASSTHROUGH: // This is purely passthru, so ignore it. return true; case LDefinition::DEFAULT: case LDefinition::MUST_REUSE_INPUT: { AnyRegister reg; // Either take the register requested, or allocate a new one. if (def->policy() == LDefinition::MUST_REUSE_INPUT && ins->getOperand(def->getReusedInput())->toUse()->isFixedRegister()) { LAllocation *a = ins->getOperand(def->getReusedInput()); VirtualRegister *vuse = getVirtualRegister(a->toUse()); reg = GetFixedRegister(vuse->def, a->toUse()); } else if (vr->hasRegister()) { reg = vr->reg(); } else { if (!allocate(vr->type(), DISALLOW, ®)) return false; } if (def->policy() == LDefinition::MUST_REUSE_INPUT) { LUse *use = ins->getOperand(def->getReusedInput())->toUse(); VirtualRegister *vuse = getVirtualRegister(use); // If the use already has the given register, we need to evict. if (vuse->hasRegister() && vuse->reg() == reg) { if (!evict(reg)) return false; } // Make sure our input is using a fixed register. if (reg.isFloat()) *use = LUse(reg.fpu(), use->virtualRegister()); else *use = LUse(reg.gpr(), use->virtualRegister()); } output = LAllocation(reg); break; } case LDefinition::PRESET: { // Eviction and disallowing occurred during the definition // pre-scan pass. output = *def->output(); break; } } if (output.isRegister()) { JS_ASSERT_IF(output.isFloatReg(), disallowed.has(output.toFloatReg()->reg())); JS_ASSERT_IF(output.isGeneralReg(), disallowed.has(output.toGeneralReg()->reg())); } // Finally, set the output. def->setOutput(output); return true; }
void MacroAssembler::wasmStore(const wasm::MemoryAccessDesc& access, AnyRegister value, Operand dstAddr) { memoryBarrier(access.barrierBefore()); size_t storeOffset = size(); switch (access.type()) { case Scalar::Int8: case Scalar::Uint8: movb(value.gpr(), dstAddr); break; case Scalar::Int16: case Scalar::Uint16: movw(value.gpr(), dstAddr); break; case Scalar::Int32: case Scalar::Uint32: movl(value.gpr(), dstAddr); break; case Scalar::Int64: movq(value.gpr(), dstAddr); break; case Scalar::Float32: storeUncanonicalizedFloat32(value.fpu(), dstAddr); break; case Scalar::Float64: storeUncanonicalizedDouble(value.fpu(), dstAddr); break; case Scalar::Float32x4: switch (access.numSimdElems()) { // In memory-to-register mode, movss zeroes out the high lanes. case 1: storeUncanonicalizedFloat32(value.fpu(), dstAddr); break; // See comment above, which also applies to movsd. case 2: storeUncanonicalizedDouble(value.fpu(), dstAddr); break; case 4: storeUnalignedSimd128Float(value.fpu(), dstAddr); break; default: MOZ_CRASH("unexpected size for partial load"); } break; case Scalar::Int32x4: switch (access.numSimdElems()) { // In memory-to-register mode, movd zeroes out the high lanes. case 1: vmovd(value.fpu(), dstAddr); break; // See comment above, which also applies to movq. case 2: vmovq(value.fpu(), dstAddr); break; case 4: storeUnalignedSimd128Int(value.fpu(), dstAddr); break; default: MOZ_CRASH("unexpected size for partial load"); } break; case Scalar::Int8x16: MOZ_ASSERT(access.numSimdElems() == 16, "unexpected partial store"); storeUnalignedSimd128Int(value.fpu(), dstAddr); break; case Scalar::Int16x8: MOZ_ASSERT(access.numSimdElems() == 8, "unexpected partial store"); storeUnalignedSimd128Int(value.fpu(), dstAddr); break; case Scalar::Uint8Clamped: case Scalar::MaxTypedArrayViewType: MOZ_CRASH("unexpected array type"); } append(access, storeOffset, framePushed()); memoryBarrier(access.barrierAfter()); }
void MacroAssembler::wasmLoad(const wasm::MemoryAccessDesc& access, Operand srcAddr, AnyRegister out) { memoryBarrier(access.barrierBefore()); size_t loadOffset = size(); switch (access.type()) { case Scalar::Int8: movsbl(srcAddr, out.gpr()); break; case Scalar::Uint8: movzbl(srcAddr, out.gpr()); break; case Scalar::Int16: movswl(srcAddr, out.gpr()); break; case Scalar::Uint16: movzwl(srcAddr, out.gpr()); break; case Scalar::Int32: case Scalar::Uint32: movl(srcAddr, out.gpr()); break; case Scalar::Float32: loadFloat32(srcAddr, out.fpu()); break; case Scalar::Float64: loadDouble(srcAddr, out.fpu()); break; case Scalar::Float32x4: switch (access.numSimdElems()) { // In memory-to-register mode, movss zeroes out the high lanes. case 1: loadFloat32(srcAddr, out.fpu()); break; // See comment above, which also applies to movsd. case 2: loadDouble(srcAddr, out.fpu()); break; case 4: loadUnalignedSimd128Float(srcAddr, out.fpu()); break; default: MOZ_CRASH("unexpected size for partial load"); } break; case Scalar::Int32x4: switch (access.numSimdElems()) { // In memory-to-register mode, movd zeroes out the high lanes. case 1: vmovd(srcAddr, out.fpu()); break; // See comment above, which also applies to movq. case 2: vmovq(srcAddr, out.fpu()); break; case 4: loadUnalignedSimd128Int(srcAddr, out.fpu()); break; default: MOZ_CRASH("unexpected size for partial load"); } break; case Scalar::Int8x16: MOZ_ASSERT(access.numSimdElems() == 16, "unexpected partial load"); loadUnalignedSimd128Int(srcAddr, out.fpu()); break; case Scalar::Int16x8: MOZ_ASSERT(access.numSimdElems() == 8, "unexpected partial load"); loadUnalignedSimd128Int(srcAddr, out.fpu()); break; case Scalar::Int64: MOZ_CRASH("int64 loads must use load64"); case Scalar::Uint8Clamped: case Scalar::MaxTypedArrayViewType: MOZ_CRASH("unexpected array type"); } append(access, loadOffset, framePushed()); memoryBarrier(access.barrierAfter()); }