diff --git a/js/src/assembler/assembler/X86Assembler.h b/js/src/assembler/assembler/X86Assembler.h index f7603de8347c..3e65c196184f 100644 --- a/js/src/assembler/assembler/X86Assembler.h +++ b/js/src/assembler/assembler/X86Assembler.h @@ -2899,6 +2899,13 @@ public: m_formatter.twoByteOp(OP2_ANDPD_VpdWpd, (RegisterID)dst, (RegisterID)src); } + void andps_rr(XMMRegisterID src, XMMRegisterID dst) + { + spew("andps %s, %s", + nameFPReg(src), nameFPReg(dst)); + m_formatter.twoByteOp(OP2_ANDPD_VpdWpd, (RegisterID)dst, (RegisterID)src); + } + void sqrtsd_rr(XMMRegisterID src, XMMRegisterID dst) { spew("sqrtsd %s, %s", diff --git a/js/src/jit/LIR-Common.h b/js/src/jit/LIR-Common.h index 9031ccdc34ca..02c33a0e3dbe 100644 --- a/js/src/jit/LIR-Common.h +++ b/js/src/jit/LIR-Common.h @@ -2293,6 +2293,16 @@ class LAbsD : public LInstructionHelper<1, 1, 0> } }; +// Absolute value of a float32. +class LAbsF : public LInstructionHelper<1, 1, 0> +{ + public: + LIR_HEADER(AbsF) + LAbsF(const LAllocation &num) { + setOperand(0, num); + } +}; + // Square root of a double. class LSqrtD : public LInstructionHelper<1, 1, 0> { diff --git a/js/src/jit/LOpcodes.h b/js/src/jit/LOpcodes.h index 122b3b616417..c4b4bc423e47 100644 --- a/js/src/jit/LOpcodes.h +++ b/js/src/jit/LOpcodes.h @@ -101,6 +101,7 @@ _(NegF) \ _(AbsI) \ _(AbsD) \ + _(AbsF) \ _(SqrtD) \ _(SqrtF) \ _(Atan2D) \ diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index ecb1e5360fe2..4183d8d13ab1 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -1167,6 +1167,7 @@ bool LIRGenerator::visitAbs(MAbs *ins) { MDefinition *num = ins->num(); + JS_ASSERT(IsNumberType(num->type())); if (num->type() == MIRType_Int32) { LAbsI *lir = new LAbsI(useRegisterAtStart(num)); @@ -1175,8 +1176,11 @@ LIRGenerator::visitAbs(MAbs *ins) return false; return defineReuseInput(lir, ins, 0); } + if (num->type() == MIRType_Float32) { + LAbsF *lir = new LAbsF(useRegisterAtStart(num)); + return defineReuseInput(lir, ins, 0); + } - JS_ASSERT(num->type() == MIRType_Double); LAbsD *lir = new LAbsD(useRegisterAtStart(num)); return defineReuseInput(lir, ins, 0); } diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index fb4ea0d679ef..e716cc02d95d 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -520,18 +520,27 @@ IonBuilder::inlineMathAbs(CallInfo &callInfo) MIRType returnType = getInlineReturnType(); MIRType argType = callInfo.getArg(0)->type(); - if (argType != MIRType_Int32 && argType != MIRType_Double) + if (!IsNumberType(argType)) return InliningStatus_NotInlined; - if (argType != returnType && returnType != MIRType_Int32) + // Either argType == returnType, or + // argType == Double or Float32, returnType == Int, or + // argType == Float32, returnType == Double + if (argType != returnType && !(IsFloatingPointType(argType) && returnType == MIRType_Int32) + && !(argType == MIRType_Float32 && returnType == MIRType_Double)) + { return InliningStatus_NotInlined; + } callInfo.unwrapArgs(); - MInstruction *ins = MAbs::New(callInfo.getArg(0), argType); + // If the arg is a Float32, we specialize the op as double, it will be specialized + // as float32 if necessary later. + MIRType absType = (argType == MIRType_Float32) ? MIRType_Double : argType; + MInstruction *ins = MAbs::New(callInfo.getArg(0), absType); current->add(ins); - if (argType != returnType) { + if (IsFloatingPointType(argType) && returnType == MIRType_Int32) { MToInt32 *toInt = MToInt32::New(ins); toInt->setCanBeNegativeZero(false); current->add(toInt); diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 070c724aa96e..2456d25b7a31 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -1279,6 +1279,19 @@ MAbs::fallible() const return !implicitTruncate_ && (!range() || !range()->hasInt32Bounds()); } +void +MAbs::trySpecializeFloat32() +{ + if (!input()->canProduceFloat32() || !CheckUsesAreFloat32Consumers(this)) { + if (input()->type() == MIRType_Float32) + ConvertDefinitionToDouble<0>(input(), this); + return; + } + + setResultType(MIRType_Float32); + specialization_ = MIRType_Float32; +} + MDefinition * MDiv::foldsTo(bool useValueNumbers) { diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index c9f20a473957..cb26bd884696 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -3418,7 +3418,7 @@ class MAbs : MUnaryInstruction(num), implicitTruncate_(false) { - JS_ASSERT(type == MIRType_Double || type == MIRType_Int32); + JS_ASSERT(IsNumberType(type)); setResultType(type); setMovable(); specialization_ = type; @@ -3450,6 +3450,8 @@ class MAbs return AliasSet::None(); } void computeRange(); + bool isFloat32Commutative() const { return true; } + void trySpecializeFloat32(); }; // Inline implementation of Math.sqrt(). diff --git a/js/src/jit/arm/CodeGenerator-arm.cpp b/js/src/jit/arm/CodeGenerator-arm.cpp index 52fde26668c6..115cc5c9a90b 100644 --- a/js/src/jit/arm/CodeGenerator-arm.cpp +++ b/js/src/jit/arm/CodeGenerator-arm.cpp @@ -339,6 +339,15 @@ CodeGeneratorARM::visitAbsD(LAbsD *ins) return true; } +bool +CodeGeneratorARM::visitAbsF(LAbsF *ins) +{ + FloatRegister input = ToFloatRegister(ins->input()); + JS_ASSERT(input == ToFloatRegister(ins->output())); + masm.ma_vabs_f32(input, input); + return true; +} + bool CodeGeneratorARM::visitSqrtD(LSqrtD *ins) { diff --git a/js/src/jit/arm/CodeGenerator-arm.h b/js/src/jit/arm/CodeGenerator-arm.h index f0e3da4014a5..45a41acaa3ec 100644 --- a/js/src/jit/arm/CodeGenerator-arm.h +++ b/js/src/jit/arm/CodeGenerator-arm.h @@ -66,6 +66,7 @@ class CodeGeneratorARM : public CodeGeneratorShared // Instruction visitors. virtual bool visitMinMaxD(LMinMaxD *ins); virtual bool visitAbsD(LAbsD *ins); + virtual bool visitAbsF(LAbsF *ins); virtual bool visitSqrtD(LSqrtD *ins); virtual bool visitSqrtF(LSqrtF *ins); virtual bool visitAddI(LAddI *ins); diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index 52a2041a715d..effde0f826f8 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -1425,6 +1425,12 @@ MacroAssemblerARM::ma_vabs(FloatRegister src, FloatRegister dest, Condition cc) as_vabs(dest, src, cc); } +void +MacroAssemblerARM::ma_vabs_f32(FloatRegister src, FloatRegister dest, Condition cc) +{ + as_vabs(VFPRegister(dest).singleOverlay(), VFPRegister(src).singleOverlay(), cc); +} + void MacroAssemblerARM::ma_vsqrt(FloatRegister src, FloatRegister dest, Condition cc) { diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index f6d3b2a4df9f..4639d8682b8f 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -317,6 +317,7 @@ class MacroAssemblerARM : public Assembler void ma_vneg(FloatRegister src, FloatRegister dest, Condition cc = Always); void ma_vmov(FloatRegister src, FloatRegister dest, Condition cc = Always); void ma_vabs(FloatRegister src, FloatRegister dest, Condition cc = Always); + void ma_vabs_f32(FloatRegister src, FloatRegister dest, Condition cc = Always); void ma_vsqrt(FloatRegister src, FloatRegister dest, Condition cc = Always); void ma_vsqrt_f32(FloatRegister src, FloatRegister dest, Condition cc = Always); diff --git a/js/src/jit/shared/Assembler-x86-shared.h b/js/src/jit/shared/Assembler-x86-shared.h index dcaaafcbe2d8..a88325c38d77 100644 --- a/js/src/jit/shared/Assembler-x86-shared.h +++ b/js/src/jit/shared/Assembler-x86-shared.h @@ -1448,6 +1448,10 @@ class AssemblerX86Shared JS_ASSERT(HasSSE2()); masm.andpd_rr(src.code(), dest.code()); } + void andps(const FloatRegister &src, const FloatRegister &dest) { + JS_ASSERT(HasSSE2()); + masm.andps_rr(src.code(), dest.code()); + } void sqrtsd(const FloatRegister &src, const FloatRegister &dest) { JS_ASSERT(HasSSE2()); masm.sqrtsd_rr(src.code(), dest.code()); diff --git a/js/src/jit/shared/CodeGenerator-x86-shared.cpp b/js/src/jit/shared/CodeGenerator-x86-shared.cpp index bbaf04cd8259..5262b789be7a 100644 --- a/js/src/jit/shared/CodeGenerator-x86-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-x86-shared.cpp @@ -19,9 +19,11 @@ using namespace js; using namespace js::jit; using mozilla::DoubleSignificandBits; +using mozilla::FloatSignificandBits; using mozilla::FloorLog2; using mozilla::NegativeInfinity; using mozilla::SpecificNaN; +using mozilla::SpecificFloatNaN; namespace js { namespace jit { @@ -473,6 +475,17 @@ CodeGeneratorX86Shared::visitAbsD(LAbsD *ins) return true; } +bool +CodeGeneratorX86Shared::visitAbsF(LAbsF *ins) +{ + FloatRegister input = ToFloatRegister(ins->input()); + JS_ASSERT(input == ToFloatRegister(ins->output())); + // Same trick as visitAbsD above. + masm.loadConstantFloat32(SpecificFloatNaN(0, FloatSignificandBits), ScratchFloatReg); + masm.andps(ScratchFloatReg, input); + return true; +} + bool CodeGeneratorX86Shared::visitSqrtD(LSqrtD *ins) { diff --git a/js/src/jit/shared/CodeGenerator-x86-shared.h b/js/src/jit/shared/CodeGenerator-x86-shared.h index ad50cc2edb91..9ab47503c1cb 100644 --- a/js/src/jit/shared/CodeGenerator-x86-shared.h +++ b/js/src/jit/shared/CodeGenerator-x86-shared.h @@ -82,6 +82,7 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared virtual bool visitFloat32(LFloat32 *ins); virtual bool visitMinMaxD(LMinMaxD *ins); virtual bool visitAbsD(LAbsD *ins); + virtual bool visitAbsF(LAbsF *ins); virtual bool visitSqrtD(LSqrtD *ins); virtual bool visitSqrtF(LSqrtF *ins); virtual bool visitPowHalfD(LPowHalfD *ins); diff --git a/mfbt/FloatingPoint.h b/mfbt/FloatingPoint.h index b80ce266f1a8..ad0250efdc6a 100644 --- a/mfbt/FloatingPoint.h +++ b/mfbt/FloatingPoint.h @@ -241,6 +241,34 @@ DoublesAreIdentical(double d1, double d2) return BitwiseCast(d1) == BitwiseCast(d2); } +/** Determines whether a float is NaN. */ +static MOZ_ALWAYS_INLINE bool +IsFloatNaN(float f) +{ + /* + * A float is NaN if all exponent bits are 1 and the significand contains at + * least one non-zero bit. + */ + uint32_t bits = BitwiseCast(f); + return (bits & FloatExponentBits) == FloatExponentBits && + (bits & FloatSignificandBits) != 0; +} + +/** Constructs a NaN value with the specified sign bit and significand bits. */ +static MOZ_ALWAYS_INLINE float +SpecificFloatNaN(int signbit, uint32_t significand) +{ + MOZ_ASSERT(signbit == 0 || signbit == 1); + MOZ_ASSERT((significand & ~FloatSignificandBits) == 0); + MOZ_ASSERT(significand & FloatSignificandBits); + + float f = BitwiseCast((signbit ? FloatSignBit : 0) | + FloatExponentBits | + significand); + MOZ_ASSERT(IsFloatNaN(f)); + return f; +} + } /* namespace mozilla */ #endif /* mozilla_FloatingPoint_h */