michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "jit/x64/CodeGenerator-x64.h" michael@0: michael@0: #include "jit/IonCaches.h" michael@0: #include "jit/MIR.h" michael@0: michael@0: #include "jsscriptinlines.h" michael@0: michael@0: #include "jit/shared/CodeGenerator-shared-inl.h" michael@0: michael@0: using namespace js; michael@0: using namespace js::jit; michael@0: michael@0: CodeGeneratorX64::CodeGeneratorX64(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm) michael@0: : CodeGeneratorX86Shared(gen, graph, masm) michael@0: { michael@0: } michael@0: michael@0: ValueOperand michael@0: CodeGeneratorX64::ToValue(LInstruction *ins, size_t pos) michael@0: { michael@0: return ValueOperand(ToRegister(ins->getOperand(pos))); michael@0: } michael@0: michael@0: ValueOperand michael@0: CodeGeneratorX64::ToOutValue(LInstruction *ins) michael@0: { michael@0: return ValueOperand(ToRegister(ins->getDef(0))); michael@0: } michael@0: michael@0: ValueOperand michael@0: CodeGeneratorX64::ToTempValue(LInstruction *ins, size_t pos) michael@0: { michael@0: return ValueOperand(ToRegister(ins->getTemp(pos))); michael@0: } michael@0: michael@0: FrameSizeClass michael@0: FrameSizeClass::FromDepth(uint32_t frameDepth) michael@0: { michael@0: return FrameSizeClass::None(); michael@0: } michael@0: michael@0: FrameSizeClass michael@0: FrameSizeClass::ClassLimit() michael@0: { michael@0: return FrameSizeClass(0); michael@0: } michael@0: michael@0: uint32_t michael@0: FrameSizeClass::frameSize() const michael@0: { michael@0: MOZ_ASSUME_UNREACHABLE("x64 does not use frame size classes"); michael@0: } michael@0: michael@0: bool michael@0: CodeGeneratorX64::visitValue(LValue *value) michael@0: { michael@0: LDefinition *reg = value->getDef(0); michael@0: masm.moveValue(value->value(), ToRegister(reg)); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: CodeGeneratorX64::visitBox(LBox *box) michael@0: { michael@0: const LAllocation *in = box->getOperand(0); michael@0: const LDefinition *result = box->getDef(0); michael@0: michael@0: if (IsFloatingPointType(box->type())) { michael@0: FloatRegister reg = ToFloatRegister(in); michael@0: if (box->type() == MIRType_Float32) { michael@0: masm.convertFloat32ToDouble(reg, ScratchFloatReg); michael@0: reg = ScratchFloatReg; michael@0: } michael@0: masm.movq(reg, ToRegister(result)); michael@0: } else { michael@0: masm.boxValue(ValueTypeFromMIRType(box->type()), ToRegister(in), ToRegister(result)); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: CodeGeneratorX64::visitUnbox(LUnbox *unbox) michael@0: { michael@0: const ValueOperand value = ToValue(unbox, LUnbox::Input); michael@0: const LDefinition *result = unbox->output(); michael@0: MUnbox *mir = unbox->mir(); michael@0: michael@0: if (mir->fallible()) { michael@0: Assembler::Condition cond; michael@0: switch (mir->type()) { michael@0: case MIRType_Int32: michael@0: cond = masm.testInt32(Assembler::NotEqual, value); michael@0: break; michael@0: case MIRType_Boolean: michael@0: cond = masm.testBoolean(Assembler::NotEqual, value); michael@0: break; michael@0: case MIRType_Object: michael@0: cond = masm.testObject(Assembler::NotEqual, value); michael@0: break; michael@0: case MIRType_String: michael@0: cond = masm.testString(Assembler::NotEqual, value); michael@0: break; michael@0: default: michael@0: MOZ_ASSUME_UNREACHABLE("Given MIRType cannot be unboxed."); michael@0: } michael@0: if (!bailoutIf(cond, unbox->snapshot())) michael@0: return false; michael@0: } michael@0: michael@0: switch (mir->type()) { michael@0: case MIRType_Int32: michael@0: masm.unboxInt32(value, ToRegister(result)); michael@0: break; michael@0: case MIRType_Boolean: michael@0: masm.unboxBoolean(value, ToRegister(result)); michael@0: break; michael@0: case MIRType_Object: michael@0: masm.unboxObject(value, ToRegister(result)); michael@0: break; michael@0: case MIRType_String: michael@0: masm.unboxString(value, ToRegister(result)); michael@0: break; michael@0: default: michael@0: MOZ_ASSUME_UNREACHABLE("Given MIRType cannot be unboxed."); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: CodeGeneratorX64::visitLoadSlotV(LLoadSlotV *load) michael@0: { michael@0: ValueOperand dest = ToOutValue(load); michael@0: Register base = ToRegister(load->input()); michael@0: int32_t offset = load->mir()->slot() * sizeof(js::Value); michael@0: michael@0: masm.loadValue(Address(base, offset), dest); michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: CodeGeneratorX64::loadUnboxedValue(Operand source, MIRType type, const LDefinition *dest) michael@0: { michael@0: switch (type) { michael@0: case MIRType_Double: michael@0: masm.loadInt32OrDouble(source, ToFloatRegister(dest)); michael@0: break; michael@0: michael@0: case MIRType_Object: michael@0: case MIRType_String: michael@0: masm.unboxObject(source, ToRegister(dest)); michael@0: break; michael@0: michael@0: case MIRType_Int32: michael@0: case MIRType_Boolean: michael@0: masm.movl(source, ToRegister(dest)); michael@0: break; michael@0: michael@0: default: michael@0: MOZ_ASSUME_UNREACHABLE("unexpected type"); michael@0: } michael@0: } michael@0: michael@0: bool michael@0: CodeGeneratorX64::visitLoadSlotT(LLoadSlotT *load) michael@0: { michael@0: Register base = ToRegister(load->input()); michael@0: int32_t offset = load->mir()->slot() * sizeof(js::Value); michael@0: michael@0: loadUnboxedValue(Operand(base, offset), load->mir()->type(), load->output()); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: CodeGeneratorX64::storeUnboxedValue(const LAllocation *value, MIRType valueType, michael@0: Operand dest, MIRType slotType) michael@0: { michael@0: if (valueType == MIRType_Double) { michael@0: masm.storeDouble(ToFloatRegister(value), dest); michael@0: return; michael@0: } michael@0: michael@0: // For known integers and booleans, we can just store the unboxed value if michael@0: // the slot has the same type. michael@0: if ((valueType == MIRType_Int32 || valueType == MIRType_Boolean) && slotType == valueType) { michael@0: if (value->isConstant()) { michael@0: Value val = *value->toConstant(); michael@0: if (valueType == MIRType_Int32) michael@0: masm.movl(Imm32(val.toInt32()), dest); michael@0: else michael@0: masm.movl(Imm32(val.toBoolean() ? 1 : 0), dest); michael@0: } else { michael@0: masm.movl(ToRegister(value), dest); michael@0: } michael@0: return; michael@0: } michael@0: michael@0: if (value->isConstant()) { michael@0: masm.moveValue(*value->toConstant(), ScratchReg); michael@0: masm.movq(ScratchReg, dest); michael@0: } else { michael@0: masm.storeValue(ValueTypeFromMIRType(valueType), ToRegister(value), dest); michael@0: } michael@0: } michael@0: michael@0: bool michael@0: CodeGeneratorX64::visitStoreSlotT(LStoreSlotT *store) michael@0: { michael@0: Register base = ToRegister(store->slots()); michael@0: int32_t offset = store->mir()->slot() * sizeof(js::Value); michael@0: michael@0: const LAllocation *value = store->value(); michael@0: MIRType valueType = store->mir()->value()->type(); michael@0: MIRType slotType = store->mir()->slotType(); michael@0: michael@0: if (store->mir()->needsBarrier()) michael@0: emitPreBarrier(Address(base, offset), slotType); michael@0: michael@0: storeUnboxedValue(value, valueType, Operand(base, offset), slotType); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: CodeGeneratorX64::visitLoadElementT(LLoadElementT *load) michael@0: { michael@0: Operand source = createArrayElementOperand(ToRegister(load->elements()), load->index()); michael@0: michael@0: if (load->mir()->loadDoubles()) { michael@0: FloatRegister fpreg = ToFloatRegister(load->output()); michael@0: if (source.kind() == Operand::MEM_REG_DISP) michael@0: masm.loadDouble(source.toAddress(), fpreg); michael@0: else michael@0: masm.loadDouble(source.toBaseIndex(), fpreg); michael@0: } else { michael@0: loadUnboxedValue(source, load->mir()->type(), load->output()); michael@0: } michael@0: michael@0: JS_ASSERT(!load->mir()->needsHoleCheck()); michael@0: return true; michael@0: } michael@0: michael@0: michael@0: void michael@0: CodeGeneratorX64::storeElementTyped(const LAllocation *value, MIRType valueType, MIRType elementType, michael@0: const Register &elements, const LAllocation *index) michael@0: { michael@0: Operand dest = createArrayElementOperand(elements, index); michael@0: storeUnboxedValue(value, valueType, dest, elementType); michael@0: } michael@0: michael@0: bool michael@0: CodeGeneratorX64::visitImplicitThis(LImplicitThis *lir) michael@0: { michael@0: Register callee = ToRegister(lir->callee()); michael@0: michael@0: // The implicit |this| is always |undefined| if the function's environment michael@0: // is the current global. michael@0: GlobalObject *global = &gen->info().script()->global(); michael@0: masm.cmpPtr(Operand(callee, JSFunction::offsetOfEnvironment()), ImmGCPtr(global)); michael@0: michael@0: // TODO: OOL stub path. michael@0: if (!bailoutIf(Assembler::NotEqual, lir->snapshot())) michael@0: return false; michael@0: michael@0: masm.moveValue(UndefinedValue(), ToOutValue(lir)); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: CodeGeneratorX64::visitInterruptCheck(LInterruptCheck *lir) michael@0: { michael@0: OutOfLineCode *ool = oolCallVM(InterruptCheckInfo, lir, (ArgList()), StoreNothing()); michael@0: if (!ool) michael@0: return false; michael@0: michael@0: masm.branch32(Assembler::NotEqual, michael@0: AbsoluteAddress(GetIonContext()->runtime->addressOfInterrupt()), Imm32(0), michael@0: ool->entry()); michael@0: masm.bind(ool->rejoin()); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: CodeGeneratorX64::visitCompareB(LCompareB *lir) michael@0: { michael@0: MCompare *mir = lir->mir(); michael@0: michael@0: const ValueOperand lhs = ToValue(lir, LCompareB::Lhs); michael@0: const LAllocation *rhs = lir->rhs(); michael@0: const Register output = ToRegister(lir->output()); michael@0: michael@0: JS_ASSERT(mir->jsop() == JSOP_STRICTEQ || mir->jsop() == JSOP_STRICTNE); michael@0: michael@0: // Load boxed boolean in ScratchReg. michael@0: if (rhs->isConstant()) michael@0: masm.moveValue(*rhs->toConstant(), ScratchReg); michael@0: else michael@0: masm.boxValue(JSVAL_TYPE_BOOLEAN, ToRegister(rhs), ScratchReg); michael@0: michael@0: // Perform the comparison. michael@0: masm.cmpq(lhs.valueReg(), ScratchReg); michael@0: masm.emitSet(JSOpToCondition(mir->compareType(), mir->jsop()), output); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: CodeGeneratorX64::visitCompareBAndBranch(LCompareBAndBranch *lir) michael@0: { michael@0: MCompare *mir = lir->cmpMir(); michael@0: michael@0: const ValueOperand lhs = ToValue(lir, LCompareBAndBranch::Lhs); michael@0: const LAllocation *rhs = lir->rhs(); michael@0: michael@0: JS_ASSERT(mir->jsop() == JSOP_STRICTEQ || mir->jsop() == JSOP_STRICTNE); michael@0: michael@0: // Load boxed boolean in ScratchReg. michael@0: if (rhs->isConstant()) michael@0: masm.moveValue(*rhs->toConstant(), ScratchReg); michael@0: else michael@0: masm.boxValue(JSVAL_TYPE_BOOLEAN, ToRegister(rhs), ScratchReg); michael@0: michael@0: // Perform the comparison. michael@0: masm.cmpq(lhs.valueReg(), ScratchReg); michael@0: emitBranch(JSOpToCondition(mir->compareType(), mir->jsop()), lir->ifTrue(), lir->ifFalse()); michael@0: return true; michael@0: } michael@0: bool michael@0: CodeGeneratorX64::visitCompareV(LCompareV *lir) michael@0: { michael@0: MCompare *mir = lir->mir(); michael@0: const ValueOperand lhs = ToValue(lir, LCompareV::LhsInput); michael@0: const ValueOperand rhs = ToValue(lir, LCompareV::RhsInput); michael@0: const Register output = ToRegister(lir->output()); michael@0: michael@0: JS_ASSERT(IsEqualityOp(mir->jsop())); michael@0: michael@0: masm.cmpq(lhs.valueReg(), rhs.valueReg()); michael@0: masm.emitSet(JSOpToCondition(mir->compareType(), mir->jsop()), output); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: CodeGeneratorX64::visitCompareVAndBranch(LCompareVAndBranch *lir) michael@0: { michael@0: MCompare *mir = lir->cmpMir(); michael@0: michael@0: const ValueOperand lhs = ToValue(lir, LCompareVAndBranch::LhsInput); michael@0: const ValueOperand rhs = ToValue(lir, LCompareVAndBranch::RhsInput); michael@0: michael@0: JS_ASSERT(mir->jsop() == JSOP_EQ || mir->jsop() == JSOP_STRICTEQ || michael@0: mir->jsop() == JSOP_NE || mir->jsop() == JSOP_STRICTNE); michael@0: michael@0: masm.cmpq(lhs.valueReg(), rhs.valueReg()); michael@0: emitBranch(JSOpToCondition(mir->compareType(), mir->jsop()), lir->ifTrue(), lir->ifFalse()); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: CodeGeneratorX64::visitAsmJSUInt32ToDouble(LAsmJSUInt32ToDouble *lir) michael@0: { michael@0: masm.convertUInt32ToDouble(ToRegister(lir->input()), ToFloatRegister(lir->output())); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: CodeGeneratorX64::visitAsmJSUInt32ToFloat32(LAsmJSUInt32ToFloat32 *lir) michael@0: { michael@0: masm.convertUInt32ToFloat32(ToRegister(lir->input()), ToFloatRegister(lir->output())); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: CodeGeneratorX64::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic *ins) michael@0: { michael@0: MOZ_ASSUME_UNREACHABLE("NYI"); michael@0: } michael@0: michael@0: bool michael@0: CodeGeneratorX64::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic *ins) michael@0: { michael@0: MOZ_ASSUME_UNREACHABLE("NYI"); michael@0: } michael@0: michael@0: bool michael@0: CodeGeneratorX64::visitAsmJSLoadHeap(LAsmJSLoadHeap *ins) michael@0: { michael@0: MAsmJSLoadHeap *mir = ins->mir(); michael@0: ArrayBufferView::ViewType vt = mir->viewType(); michael@0: const LAllocation *ptr = ins->ptr(); michael@0: michael@0: // No need to note the access if it will never fault. michael@0: bool skipNote = mir->skipBoundsCheck(); michael@0: Operand srcAddr(HeapReg); michael@0: michael@0: if (ptr->isConstant()) { michael@0: int32_t ptrImm = ptr->toConstant()->toInt32(); michael@0: // Note only a positive index is accepted here because a negative offset would michael@0: // not wrap back into the protected area reserved for the heap. michael@0: JS_ASSERT(ptrImm >= 0); michael@0: srcAddr = Operand(HeapReg, ptrImm); michael@0: } else { michael@0: srcAddr = Operand(HeapReg, ToRegister(ptr), TimesOne); michael@0: } michael@0: michael@0: uint32_t before = masm.size(); michael@0: switch (vt) { michael@0: case ArrayBufferView::TYPE_INT8: masm.movsbl(srcAddr, ToRegister(ins->output())); break; michael@0: case ArrayBufferView::TYPE_UINT8: masm.movzbl(srcAddr, ToRegister(ins->output())); break; michael@0: case ArrayBufferView::TYPE_INT16: masm.movswl(srcAddr, ToRegister(ins->output())); break; michael@0: case ArrayBufferView::TYPE_UINT16: masm.movzwl(srcAddr, ToRegister(ins->output())); break; michael@0: case ArrayBufferView::TYPE_INT32: michael@0: case ArrayBufferView::TYPE_UINT32: masm.movl(srcAddr, ToRegister(ins->output())); break; michael@0: case ArrayBufferView::TYPE_FLOAT32: masm.loadFloat32(srcAddr, ToFloatRegister(ins->output())); break; michael@0: case ArrayBufferView::TYPE_FLOAT64: masm.loadDouble(srcAddr, ToFloatRegister(ins->output())); break; michael@0: default: MOZ_ASSUME_UNREACHABLE("unexpected array type"); michael@0: } michael@0: uint32_t after = masm.size(); michael@0: return skipNote || masm.append(AsmJSHeapAccess(before, after, vt, ToAnyRegister(ins->output()))); michael@0: } michael@0: michael@0: bool michael@0: CodeGeneratorX64::visitAsmJSStoreHeap(LAsmJSStoreHeap *ins) michael@0: { michael@0: MAsmJSStoreHeap *mir = ins->mir(); michael@0: ArrayBufferView::ViewType vt = mir->viewType(); michael@0: const LAllocation *ptr = ins->ptr(); michael@0: // No need to note the access if it will never fault. michael@0: bool skipNote = mir->skipBoundsCheck(); michael@0: Operand dstAddr(HeapReg); michael@0: michael@0: if (ptr->isConstant()) { michael@0: int32_t ptrImm = ptr->toConstant()->toInt32(); michael@0: // Note only a positive index is accepted here because a negative offset would michael@0: // not wrap back into the protected area reserved for the heap. michael@0: JS_ASSERT(ptrImm >= 0); michael@0: dstAddr = Operand(HeapReg, ptrImm); michael@0: } else { michael@0: dstAddr = Operand(HeapReg, ToRegister(ins->ptr()), TimesOne); michael@0: } michael@0: michael@0: uint32_t before = masm.size(); michael@0: if (ins->value()->isConstant()) { michael@0: switch (vt) { michael@0: case ArrayBufferView::TYPE_INT8: michael@0: case ArrayBufferView::TYPE_UINT8: masm.movb(Imm32(ToInt32(ins->value())), dstAddr); break; michael@0: case ArrayBufferView::TYPE_INT16: michael@0: case ArrayBufferView::TYPE_UINT16: masm.movw(Imm32(ToInt32(ins->value())), dstAddr); break; michael@0: case ArrayBufferView::TYPE_INT32: michael@0: case ArrayBufferView::TYPE_UINT32: masm.movl(Imm32(ToInt32(ins->value())), dstAddr); break; michael@0: default: MOZ_ASSUME_UNREACHABLE("unexpected array type"); michael@0: } michael@0: } else { michael@0: switch (vt) { michael@0: case ArrayBufferView::TYPE_INT8: michael@0: case ArrayBufferView::TYPE_UINT8: masm.movb(ToRegister(ins->value()), dstAddr); break; michael@0: case ArrayBufferView::TYPE_INT16: michael@0: case ArrayBufferView::TYPE_UINT16: masm.movw(ToRegister(ins->value()), dstAddr); break; michael@0: case ArrayBufferView::TYPE_INT32: michael@0: case ArrayBufferView::TYPE_UINT32: masm.movl(ToRegister(ins->value()), dstAddr); break; michael@0: case ArrayBufferView::TYPE_FLOAT32: masm.storeFloat32(ToFloatRegister(ins->value()), dstAddr); break; michael@0: case ArrayBufferView::TYPE_FLOAT64: masm.storeDouble(ToFloatRegister(ins->value()), dstAddr); break; michael@0: default: MOZ_ASSUME_UNREACHABLE("unexpected array type"); michael@0: } michael@0: } michael@0: uint32_t after = masm.size(); michael@0: return skipNote || masm.append(AsmJSHeapAccess(before, after)); michael@0: } michael@0: michael@0: bool michael@0: CodeGeneratorX64::visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar *ins) michael@0: { michael@0: MAsmJSLoadGlobalVar *mir = ins->mir(); michael@0: michael@0: CodeOffsetLabel label; michael@0: if (mir->type() == MIRType_Int32) michael@0: label = masm.loadRipRelativeInt32(ToRegister(ins->output())); michael@0: else michael@0: label = masm.loadRipRelativeDouble(ToFloatRegister(ins->output())); michael@0: michael@0: return masm.append(AsmJSGlobalAccess(label.offset(), mir->globalDataOffset())); michael@0: } michael@0: michael@0: bool michael@0: CodeGeneratorX64::visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar *ins) michael@0: { michael@0: MAsmJSStoreGlobalVar *mir = ins->mir(); michael@0: michael@0: MIRType type = mir->value()->type(); michael@0: JS_ASSERT(IsNumberType(type)); michael@0: michael@0: CodeOffsetLabel label; michael@0: if (type == MIRType_Int32) michael@0: label = masm.storeRipRelativeInt32(ToRegister(ins->value())); michael@0: else michael@0: label = masm.storeRipRelativeDouble(ToFloatRegister(ins->value())); michael@0: michael@0: return masm.append(AsmJSGlobalAccess(label.offset(), mir->globalDataOffset())); michael@0: } michael@0: michael@0: bool michael@0: CodeGeneratorX64::visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr *ins) michael@0: { michael@0: MAsmJSLoadFuncPtr *mir = ins->mir(); michael@0: michael@0: Register index = ToRegister(ins->index()); michael@0: Register tmp = ToRegister(ins->temp()); michael@0: Register out = ToRegister(ins->output()); michael@0: michael@0: CodeOffsetLabel label = masm.leaRipRelative(tmp); michael@0: masm.loadPtr(Operand(tmp, index, TimesEight, 0), out); michael@0: michael@0: return masm.append(AsmJSGlobalAccess(label.offset(), mir->globalDataOffset())); michael@0: } michael@0: michael@0: bool michael@0: CodeGeneratorX64::visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc *ins) michael@0: { michael@0: MAsmJSLoadFFIFunc *mir = ins->mir(); michael@0: michael@0: CodeOffsetLabel label = masm.loadRipRelativeInt64(ToRegister(ins->output())); michael@0: michael@0: return masm.append(AsmJSGlobalAccess(label.offset(), mir->globalDataOffset())); michael@0: } michael@0: michael@0: void michael@0: DispatchIonCache::initializeAddCacheState(LInstruction *ins, AddCacheState *addState) michael@0: { michael@0: // Can always use the scratch register on x64. michael@0: addState->dispatchScratch = ScratchReg; michael@0: } michael@0: michael@0: bool michael@0: CodeGeneratorX64::visitTruncateDToInt32(LTruncateDToInt32 *ins) michael@0: { michael@0: FloatRegister input = ToFloatRegister(ins->input()); michael@0: Register output = ToRegister(ins->output()); michael@0: michael@0: // On x64, branchTruncateDouble uses cvttsd2sq. Unlike the x86 michael@0: // implementation, this should handle most doubles and we can just michael@0: // call a stub if it fails. michael@0: return emitTruncateDouble(input, output); michael@0: } michael@0: michael@0: bool michael@0: CodeGeneratorX64::visitTruncateFToInt32(LTruncateFToInt32 *ins) michael@0: { michael@0: FloatRegister input = ToFloatRegister(ins->input()); michael@0: Register output = ToRegister(ins->output()); michael@0: michael@0: // On x64, branchTruncateFloat32 uses cvttss2sq. Unlike the x86 michael@0: // implementation, this should handle most floats and we can just michael@0: // call a stub if it fails. michael@0: return emitTruncateFloat32(input, output); michael@0: }