Bug 919838: Specialize ToInt32 for Float32; r=sstangl

This commit is contained in:
Benjamin Bouvier 2013-09-26 18:11:31 -07:00
parent 009454da8e
commit c5f86b8e06
11 changed files with 120 additions and 6 deletions

View File

@ -2459,6 +2459,13 @@ public:
m_formatter.twoByteOp(OP2_MOVMSKPD_EdVd, dst, (RegisterID)src);
}
void movmskps_rr(XMMRegisterID src, RegisterID dst)
{
spew("movmskps %s, %s",
nameFPReg(src), nameIReg(dst));
m_formatter.twoByteOp(OP2_MOVMSKPD_EdVd, dst, (RegisterID)src);
}
void ptest_rr(XMMRegisterID lhs, XMMRegisterID rhs) {
spew("ptest %s, %s",
nameFPReg(lhs), nameFPReg(rhs));

View File

@ -361,6 +361,18 @@ CodeGenerator::visitDoubleToInt32(LDoubleToInt32 *lir)
return true;
}
bool
CodeGenerator::visitFloat32ToInt32(LFloat32ToInt32 *lir)
{
Label fail;
FloatRegister input = ToFloatRegister(lir->input());
Register output = ToRegister(lir->output());
masm.convertFloat32ToInt32(input, output, &fail, lir->mir()->canBeNegativeZero());
if (!bailoutFrom(&fail, lir->snapshot()))
return false;
return true;
}
void
CodeGenerator::emitOOLTestObject(Register objreg, Label *ifTruthy, Label *ifFalsy, Register scratch)
{

View File

@ -120,6 +120,7 @@ class CodeGenerator : public CodeGeneratorSpecific
bool visitFilterArguments(LFilterArguments *lir);
bool visitCallDirectEval(LCallDirectEval *lir);
bool visitDoubleToInt32(LDoubleToInt32 *lir);
bool visitFloat32ToInt32(LFloat32ToInt32 *lir);
bool visitNewSlots(LNewSlots *lir);
bool visitNewParallelArrayVMCall(LNewParallelArray *lir);
bool visitNewParallelArray(LNewParallelArray *lir);

View File

@ -2672,6 +2672,23 @@ class LDoubleToInt32 : public LInstructionHelper<1, 1, 0>
}
};
// Convert a float32 to an int32.
// Input: floating-point register
// Output: 32-bit integer
// Bailout: if the float32 cannot be converted to an integer.
class LFloat32ToInt32 : public LInstructionHelper<1, 1, 0>
{
public:
LIR_HEADER(Float32ToInt32)
LFloat32ToInt32(const LAllocation &in) {
setOperand(0, in);
}
MToInt32 *mir() const {
return mir_->toToInt32();
}
};
// Convert a double to a truncated int32.
// Input: floating-point register

View File

@ -127,6 +127,7 @@
_(ValueToInt32) \
_(ValueToFloat32) \
_(DoubleToInt32) \
_(Float32ToInt32) \
_(TruncateDToInt32) \
_(IntToString) \
_(DoubleToString) \

View File

@ -1670,6 +1670,12 @@ LIRGenerator::visitToInt32(MToInt32 *convert)
case MIRType_Boolean:
return redefine(convert, opd);
case MIRType_Float32:
{
LFloat32ToInt32 *lir = new LFloat32ToInt32(useRegister(opd));
return assignSnapshot(lir) && define(lir, convert);
}
case MIRType_Double:
{
LDoubleToInt32 *lir = new LDoubleToInt32(useRegister(opd));

View File

@ -2849,9 +2849,7 @@ class MAsmJSUnsignedToDouble
// Converts a primitive (either typed or untyped) to an int32. If the input is
// not primitive at runtime, a bailout occurs. If the input cannot be converted
// to an int32 without loss (i.e. "5.5" or undefined) then a bailout occurs.
class MToInt32
: public MUnaryInstruction,
public NoFloatPolicy<0>
class MToInt32 : public MUnaryInstruction
{
bool canBeNegativeZero_;
@ -2891,9 +2889,9 @@ class MToInt32
}
void computeRange();
TypePolicy *typePolicy() {
return this;
}
#ifdef DEBUG
bool isConsistentFloat32Use() const { return true; }
#endif
};
// Converts a value or typed input to a truncated int32, for use with bitwise

View File

@ -116,6 +116,34 @@ MacroAssemblerARM::convertDoubleToInt32(const FloatRegister &src, const Register
}
}
// Checks whether a float32 is representable as a 32-bit integer. If so, the
// integer is written to the output register. Otherwise, a bailout is taken to
// the given snapshot. This function overwrites the scratch float register.
void
MacroAssemblerARM::convertFloat32ToInt32(const FloatRegister &src, const Register &dest, Label *fail, bool negativeZeroCheck)
{
// convert the floating point value to an integer, if it did not fit,
// then when we convert it *back* to a float, it will have a
// different value, which we can test.
ma_vcvt_F32_I32(src, ScratchFloatReg);
// move the value into the dest register.
ma_vxfer(ScratchFloatReg, dest);
ma_vcvt_I32_F32(ScratchFloatReg, ScratchFloatReg);
ma_vcmp_f32(src, ScratchFloatReg);
as_vmrs(pc);
ma_b(fail, Assembler::VFP_NotEqualOrUnordered);
if (negativeZeroCheck) {
ma_cmp(dest, Imm32(0));
// Test and bail for -0.0, when integer result is 0
// Move the top word of the double into the output reg, if it is non-zero,
// then the original value was -0.0
as_vxfer(dest, InvalidReg, src, FloatToCore, Assembler::Equal, 0);
ma_cmp(dest, Imm32(0x80000000), Assembler::Equal);
ma_b(fail, Assembler::Equal);
}
}
void
MacroAssemblerARM::convertFloatToDouble(const FloatRegister &src, const FloatRegister &dest) {
as_vcvt(VFPRegister(dest), VFPRegister(src).singleOverlay());
@ -1486,6 +1514,11 @@ MacroAssemblerARM::ma_vcmp(FloatRegister src1, FloatRegister src2, Condition cc)
as_vcmp(VFPRegister(src1), VFPRegister(src2), cc);
}
void
MacroAssemblerARM::ma_vcmp_f32(FloatRegister src1, FloatRegister src2, Condition cc)
{
as_vcmp(VFPRegister(src1).singleOverlay(), VFPRegister(src2).singleOverlay(), cc);
}
void
MacroAssemblerARM::ma_vcmpz(FloatRegister src1, Condition cc)
{
as_vcmpz(VFPRegister(src1), cc);

View File

@ -53,6 +53,8 @@ class MacroAssemblerARM : public Assembler
void branchTruncateDouble(const FloatRegister &src, const Register &dest, Label *fail);
void convertDoubleToInt32(const FloatRegister &src, const Register &dest, Label *fail,
bool negativeZeroCheck = true);
void convertFloat32ToInt32(const FloatRegister &src, const Register &dest, Label *fail,
bool negativeZeroCheck = true);
void convertFloatToDouble(const FloatRegister &src, const FloatRegister &dest);
void branchTruncateFloat32(const FloatRegister &src, const Register &dest, Label *fail);
@ -322,6 +324,7 @@ class MacroAssemblerARM : public Assembler
void ma_vimm_f32(float value, FloatRegister dest, Condition cc = Always);
void ma_vcmp(FloatRegister src1, FloatRegister src2, Condition cc = Always);
void ma_vcmp_f32(FloatRegister src1, FloatRegister src2, Condition cc = Always);
void ma_vcmpz(FloatRegister src1, Condition cc = Always);
void ma_vadd_f32(FloatRegister src1, FloatRegister src2, FloatRegister dst);

View File

@ -1303,6 +1303,10 @@ class AssemblerX86Shared
JS_ASSERT(HasSSE2());
masm.movmskpd_rr(src.code(), dest.code());
}
void movmskps(const FloatRegister &src, const Register &dest) {
JS_ASSERT(HasSSE2());
masm.movmskps_rr(src.code(), dest.code());
}
void ptest(const FloatRegister &lhs, const FloatRegister &rhs) {
JS_ASSERT(HasSSE41());
masm.ptest_rr(rhs.code(), lhs.code());

View File

@ -457,6 +457,38 @@ class MacroAssemblerX86Shared : public Assembler
}
}
// Checks whether a float32 is representable as a 32-bit integer. If so, the
// integer is written to the output register. Otherwise, a bailout is taken to
// the given snapshot. This function overwrites the scratch float register.
void convertFloat32ToInt32(FloatRegister src, Register dest, Label *fail,
bool negativeZeroCheck = true)
{
cvttss2si(src, dest);
convertInt32ToFloat32(dest, ScratchFloatReg);
ucomiss(src, ScratchFloatReg);
j(Assembler::Parity, fail);
j(Assembler::NotEqual, fail);
// Check for -0
if (negativeZeroCheck) {
Label notZero;
branchTest32(Assembler::NonZero, dest, dest, &notZero);
if (Assembler::HasSSE41()) {
ptest(src, src);
j(Assembler::NonZero, fail);
} else {
// bit 0 = sign of low float
// bits 1 to 3 = signs of higher floats
movmskps(src, dest);
andl(Imm32(1), dest);
j(Assembler::NonZero, fail);
}
bind(&notZero);
}
}
void clampIntToUint8(Register reg) {
Label inRange;
branchTest32(Assembler::Zero, reg, Imm32(0xffffff00), &inRange);