void CodeGeneratorX86::visitOutOfLineTruncateFloat32(OutOfLineTruncateFloat32* ool) { LTruncateFToInt32* ins = ool->ins(); FloatRegister input = ToFloatRegister(ins->input()); Register output = ToRegister(ins->output()); Label fail; if (Assembler::HasSSE3()) { // Push float32, but subtracts 64 bits so that the value popped by fisttp fits masm.subl(Imm32(sizeof(uint64_t)), esp); masm.storeFloat32(input, Operand(esp, 0)); static const uint32_t EXPONENT_MASK = FloatingPoint<float>::kExponentBits; static const uint32_t EXPONENT_SHIFT = FloatingPoint<float>::kExponentShift; // Integers are still 64 bits long, so we can still test for an exponent > 63. static const uint32_t TOO_BIG_EXPONENT = (FloatingPoint<float>::kExponentBias + 63) << EXPONENT_SHIFT; // Check exponent to avoid fp exceptions. Label failPopFloat; masm.movl(Operand(esp, 0), output); masm.and32(Imm32(EXPONENT_MASK), output); masm.branch32(Assembler::GreaterThanOrEqual, output, Imm32(TOO_BIG_EXPONENT), &failPopFloat); // Load float, perform 32-bit truncation. masm.fld32(Operand(esp, 0)); masm.fisttp(Operand(esp, 0)); // Load low word, pop 64bits and jump back. masm.load32(Address(esp, 0), output); masm.addl(Imm32(sizeof(uint64_t)), esp); masm.jump(ool->rejoin()); masm.bind(&failPopFloat); masm.addl(Imm32(sizeof(uint64_t)), esp); masm.jump(&fail); } else { FloatRegister temp = ToFloatRegister(ins->tempFloat()); // Try to convert float32 representing integers within 2^32 of a signed // integer, by adding/subtracting 2^32 and then trying to convert to int32. // This has to be an exact conversion, as otherwise the truncation works // incorrectly on the modified value. masm.zeroFloat32(ScratchFloat32Reg); masm.vucomiss(ScratchFloat32Reg, input); masm.j(Assembler::Parity, &fail); { Label positive; masm.j(Assembler::Above, &positive); masm.loadConstantFloat32(4294967296.f, temp); Label skip; masm.jmp(&skip); masm.bind(&positive); masm.loadConstantFloat32(-4294967296.f, temp); masm.bind(&skip); } masm.addFloat32(input, temp); masm.vcvttss2si(temp, output); masm.vcvtsi2ss(output, ScratchFloat32Reg, ScratchFloat32Reg); masm.vucomiss(ScratchFloat32Reg, temp); masm.j(Assembler::Parity, &fail); masm.j(Assembler::Equal, ool->rejoin()); } masm.bind(&fail); { saveVolatile(output); masm.push(input); masm.setupUnalignedABICall(output); masm.vcvtss2sd(input, input, input); masm.passABIArg(input.asDouble(), MoveOp::DOUBLE); if (gen->compilingAsmJS()) masm.callWithABI(AsmJSImm_ToInt32); else masm.callWithABI(BitwiseCast<void*, int32_t(*)(double)>(JS::ToInt32)); masm.storeCallResult(output); masm.pop(input); restoreVolatile(output); } masm.jump(ool->rejoin()); }
void CodeGeneratorX86::visitOutOfLineTruncateFloat32(OutOfLineTruncateFloat32* ool) { LTruncateFToInt32* ins = ool->ins(); FloatRegister input = ToFloatRegister(ins->input()); Register output = ToRegister(ins->output()); Label fail; if (Assembler::HasSSE3()) { Label failPopFloat; // Push float32, but subtracts 64 bits so that the value popped by fisttp fits masm.subl(Imm32(sizeof(uint64_t)), esp); masm.storeFloat32(input, Operand(esp, 0)); // Check exponent to avoid fp exceptions. masm.branchDoubleNotInInt64Range(Address(esp, 0), output, &failPopFloat); // Load float, perform 32-bit truncation. masm.truncateFloat32ToInt64(Address(esp, 0), Address(esp, 0), output); // Load low word, pop 64bits and jump back. masm.load32(Address(esp, 0), output); masm.addl(Imm32(sizeof(uint64_t)), esp); masm.jump(ool->rejoin()); masm.bind(&failPopFloat); masm.addl(Imm32(sizeof(uint64_t)), esp); masm.jump(&fail); } else { FloatRegister temp = ToFloatRegister(ins->tempFloat()); // Try to convert float32 representing integers within 2^32 of a signed // integer, by adding/subtracting 2^32 and then trying to convert to int32. // This has to be an exact conversion, as otherwise the truncation works // incorrectly on the modified value. masm.zeroFloat32(ScratchFloat32Reg); masm.vucomiss(ScratchFloat32Reg, input); masm.j(Assembler::Parity, &fail); { Label positive; masm.j(Assembler::Above, &positive); masm.loadConstantFloat32(4294967296.f, temp); Label skip; masm.jmp(&skip); masm.bind(&positive); masm.loadConstantFloat32(-4294967296.f, temp); masm.bind(&skip); } masm.addFloat32(input, temp); masm.vcvttss2si(temp, output); masm.vcvtsi2ss(output, ScratchFloat32Reg, ScratchFloat32Reg); masm.vucomiss(ScratchFloat32Reg, temp); masm.j(Assembler::Parity, &fail); masm.j(Assembler::Equal, ool->rejoin()); } masm.bind(&fail); { saveVolatile(output); masm.Push(input); if (gen->compilingWasm()) masm.setupWasmABICall(); else masm.setupUnalignedABICall(output); masm.vcvtss2sd(input, input, input); masm.passABIArg(input.asDouble(), MoveOp::DOUBLE); if (gen->compilingWasm()) masm.callWithABI(ins->mir()->bytecodeOffset(), wasm::SymbolicAddress::ToInt32); else masm.callWithABI(BitwiseCast<void*, int32_t(*)(double)>(JS::ToInt32)); masm.storeCallWordResult(output); masm.Pop(input); restoreVolatile(output); } masm.jump(ool->rejoin()); }