Bug 915495 - Support float32 optimization in typed array SetElem ICs. (r=bbouvier)
authorShu-yu Guo <shu@rfrn.org>
Sat, 14 Sep 2013 01:45:42 -0700
changeset 160126 a43be719866ef0c25042a1893377f84c054dc7d3
parent 160125 311794c74d453a15fcc761b3ad80c865f5b4317e
child 160127 e576ec4af14b3c5254fbcea3e404dda8afc47f42
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier
bugs915495
milestone26.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 915495 - Support float32 optimization in typed array SetElem ICs. (r=bbouvier)
js/src/jit-test/tests/ion/setelem-float32-typedarray-ic.js
js/src/jit/CodeGenerator.cpp
js/src/jit/CodeGenerator.h
js/src/jit/IonCaches.cpp
js/src/jit/IonMacroAssembler.cpp
js/src/jit/IonMacroAssembler.h
js/src/jit/MIR.h
js/src/jit/arm/CodeGenerator-arm.cpp
js/src/jit/arm/CodeGenerator-arm.h
js/src/jit/arm/LIR-arm.h
js/src/jit/arm/LOpcodes-arm.h
js/src/jit/arm/Lowering-arm.cpp
js/src/jit/arm/MacroAssembler-arm.h
js/src/jit/shared/Assembler-x86-shared.h
js/src/jit/shared/MacroAssembler-x86-shared.h
js/src/jit/x64/CodeGenerator-x64.cpp
js/src/jit/x64/LIR-x64.h
js/src/jit/x64/LOpcodes-x64.h
js/src/jit/x64/Lowering-x64.cpp
js/src/jit/x86/CodeGenerator-x86.cpp
js/src/jit/x86/CodeGenerator-x86.h
js/src/jit/x86/LIR-x86.h
js/src/jit/x86/LOpcodes-x86.h
js/src/jit/x86/Lowering-x86.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/setelem-float32-typedarray-ic.js
@@ -0,0 +1,23 @@
+function testFloat32SetElemIC(a) {
+  for (var i = 0; i < a.length; i++) {
+    var r = Math.fround(Math.random());
+    a[i] = r;
+    assertEq(a[i], r);
+  }
+}
+
+function testCompoundClamping(a, b) {
+  for (var i = 0; i < a.length; i++) {
+    var r = Math.random();
+    a[i] = b[i] = r;
+    assertEq(a[i], b[i]);
+  }
+}
+
+testFloat32SetElemIC(new Array(2048));
+testFloat32SetElemIC(new Float64Array(2048));
+testFloat32SetElemIC(new Float32Array(2048));
+
+testCompoundClamping(new Array(2048), new Array(2048));
+testCompoundClamping(new Uint8Array(2048), new Uint8Array(2048));
+testCompoundClamping(new Uint8ClampedArray(2048), new Uint8ClampedArray(2048));
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -15,16 +15,17 @@
 #include "jsmath.h"
 #include "jsnum.h"
 
 #include "builtin/Eval.h"
 #include "gc/Nursery.h"
 #include "jit/ExecutionModeInlines.h"
 #include "jit/IonLinker.h"
 #include "jit/IonSpewer.h"
+#include "jit/Lowering.h"
 #include "jit/MIRGenerator.h"
 #include "jit/MoveEmitter.h"
 #include "jit/ParallelFunctions.h"
 #include "jit/ParallelSafetyAnalysis.h"
 #include "jit/PerfSpewer.h"
 #include "vm/ForkJoin.h"
 
 #include "jsboolinlines.h"
@@ -5749,65 +5750,68 @@ CodeGenerator::link()
         break;
       default:
         MOZ_ASSUME_UNREACHABLE("No such execution mode");
     }
 
     return true;
 }
 
-// An out-of-line path to convert a boxed int32 to a double.
-class OutOfLineUnboxDouble : public OutOfLineCodeBase<CodeGenerator>
-{
-    LUnboxDouble *unboxDouble_;
+// An out-of-line path to convert a boxed int32 to either a float or double.
+class OutOfLineUnboxFloatingPoint : public OutOfLineCodeBase<CodeGenerator>
+{
+    LUnboxFloatingPoint *unboxFloatingPoint_;
 
   public:
-    OutOfLineUnboxDouble(LUnboxDouble *unboxDouble)
-      : unboxDouble_(unboxDouble)
+    OutOfLineUnboxFloatingPoint(LUnboxFloatingPoint *unboxFloatingPoint)
+      : unboxFloatingPoint_(unboxFloatingPoint)
     { }
 
     bool accept(CodeGenerator *codegen) {
-        return codegen->visitOutOfLineUnboxDouble(this);
-    }
-
-    LUnboxDouble *unboxDouble() const {
-        return unboxDouble_;
+        return codegen->visitOutOfLineUnboxFloatingPoint(this);
+    }
+
+    LUnboxFloatingPoint *unboxFloatingPoint() const {
+        return unboxFloatingPoint_;
     }
 };
 
 bool
-CodeGenerator::visitUnboxDouble(LUnboxDouble *lir)
-{
-    const ValueOperand box = ToValue(lir, LUnboxDouble::Input);
+CodeGenerator::visitUnboxFloatingPoint(LUnboxFloatingPoint *lir)
+{
+    const ValueOperand box = ToValue(lir, LUnboxFloatingPoint::Input);
     const LDefinition *result = lir->output();
 
     // Out-of-line path to convert int32 to double or bailout
     // if this instruction is fallible.
-    OutOfLineUnboxDouble *ool = new OutOfLineUnboxDouble(lir);
+    OutOfLineUnboxFloatingPoint *ool = new OutOfLineUnboxFloatingPoint(lir);
     if (!addOutOfLineCode(ool))
         return false;
 
+    FloatRegister resultReg = ToFloatRegister(result);
     masm.branchTestDouble(Assembler::NotEqual, box, ool->entry());
-    masm.unboxDouble(box, ToFloatRegister(result));
+    masm.unboxDouble(box, resultReg);
+    if (lir->type() == MIRType_Float32)
+        masm.convertDoubleToFloat(resultReg, resultReg);
     masm.bind(ool->rejoin());
     return true;
 }
 
 bool
-CodeGenerator::visitOutOfLineUnboxDouble(OutOfLineUnboxDouble *ool)
-{
-    LUnboxDouble *ins = ool->unboxDouble();
-    const ValueOperand value = ToValue(ins, LUnboxDouble::Input);
+CodeGenerator::visitOutOfLineUnboxFloatingPoint(OutOfLineUnboxFloatingPoint *ool)
+{
+    LUnboxFloatingPoint *ins = ool->unboxFloatingPoint();
+    const ValueOperand value = ToValue(ins, LUnboxFloatingPoint::Input);
 
     if (ins->mir()->fallible()) {
         Assembler::Condition cond = masm.testInt32(Assembler::NotEqual, value);
         if (!bailoutIf(cond, ins->snapshot()))
             return false;
     }
-    masm.int32ValueToDouble(value, ToFloatRegister(ins->output()));
+    masm.int32ValueToFloatingPoint(value, ToFloatRegister(ins->output()), ins->type());
     masm.jump(ool->rejoin());
     return true;
 }
 
 typedef bool (*GetPropertyFn)(JSContext *, HandleValue, HandlePropertyName, MutableHandleValue);
 static const VMFunction GetPropertyInfo = FunctionInfo<GetPropertyFn>(GetProperty);
 
 bool
@@ -6695,17 +6699,19 @@ CodeGenerator::visitLoadTypedArrayElemen
     masm.bind(&done);
     return true;
 }
 
 template <typename T>
 static inline void
 StoreToTypedArray(MacroAssembler &masm, int arrayType, const LAllocation *value, const T &dest)
 {
-    if (arrayType == ScalarTypeRepresentation::TYPE_FLOAT32 || arrayType == ScalarTypeRepresentation::TYPE_FLOAT64) {
+    if (arrayType == ScalarTypeRepresentation::TYPE_FLOAT32 ||
+        arrayType == ScalarTypeRepresentation::TYPE_FLOAT64)
+    {
         masm.storeToTypedFloatArray(arrayType, ToFloatRegister(value), dest);
     } else {
         if (value->isConstant())
             masm.storeToTypedIntArray(arrayType, Imm32(ToInt32(value)), dest);
         else
             masm.storeToTypedIntArray(arrayType, ToRegister(value), dest);
     }
 }
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -25,17 +25,17 @@ namespace jit {
 class OutOfLineNewParallelArray;
 class OutOfLineTestObject;
 class OutOfLineNewArray;
 class OutOfLineNewObject;
 class CheckOverRecursedFailure;
 class CheckOverRecursedFailurePar;
 class OutOfLineCheckInterruptPar;
 class OutOfLineInterruptCheckImplicit;
-class OutOfLineUnboxDouble;
+class OutOfLineUnboxFloatingPoint;
 class OutOfLineStoreElementHole;
 class OutOfLineTypeOfV;
 class OutOfLineLoadTypedArray;
 class OutOfLineNewGCThingPar;
 class OutOfLineUpdateCache;
 class OutOfLineCallPostWriteBarrier;
 
 class CodeGenerator : public CodeGeneratorSpecific
@@ -267,18 +267,18 @@ class CodeGenerator : public CodeGenerat
     bool visitCheckOverRecursedFailurePar(CheckOverRecursedFailurePar *ool);
 
     bool visitCheckInterruptPar(LCheckInterruptPar *lir);
     bool visitOutOfLineCheckInterruptPar(OutOfLineCheckInterruptPar *ool);
 
     bool visitInterruptCheckImplicit(LInterruptCheckImplicit *ins);
     bool visitOutOfLineInterruptCheckImplicit(OutOfLineInterruptCheckImplicit *ins);
 
-    bool visitUnboxDouble(LUnboxDouble *lir);
-    bool visitOutOfLineUnboxDouble(OutOfLineUnboxDouble *ool);
+    bool visitUnboxFloatingPoint(LUnboxFloatingPoint *lir);
+    bool visitOutOfLineUnboxFloatingPoint(OutOfLineUnboxFloatingPoint *ool);
     bool visitOutOfLineStoreElementHole(OutOfLineStoreElementHole *ool);
 
     bool visitOutOfLineNewGCThingPar(OutOfLineNewGCThingPar *ool);
     bool visitOutOfLineAbortPar(OutOfLineAbortPar *ool);
     bool visitOutOfLinePropagateAbortPar(OutOfLinePropagateAbortPar *ool);
     void loadJSScriptForBlock(MBasicBlock *block, Register reg);
     void loadOutermostJSScript(Register reg);
 
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -3397,19 +3397,21 @@ GenerateSetTypedArrayElement(JSContext *
     Register elements = temp;
     masm.loadPtr(Address(object, TypedArrayObject::dataOffset()), elements);
 
     // Set the value.
     int arrayType = tarr->type();
     int width = TypedArrayObject::slotWidth(arrayType);
     BaseIndex target(elements, index, ScaleFromElemWidth(width));
 
-    if (arrayType == ScalarTypeRepresentation::TYPE_FLOAT32 ||
-        arrayType == ScalarTypeRepresentation::TYPE_FLOAT64)
-    {
+    if (arrayType == ScalarTypeRepresentation::TYPE_FLOAT32) {
+        if (!masm.convertConstantOrRegisterToFloat(cx, value, tempFloat, &failures))
+            return false;
+        masm.storeToTypedFloatArray(arrayType, tempFloat, target);
+    } else if (arrayType == ScalarTypeRepresentation::TYPE_FLOAT64) {
         if (!masm.convertConstantOrRegisterToDouble(cx, value, tempFloat, &failures))
             return false;
         masm.storeToTypedFloatArray(arrayType, tempFloat, target);
     } else {
         // On x86 we only have 6 registers available to use, so reuse the object
         // register to compute the intermediate value to store and restore it
         // afterwards.
         masm.push(object);
--- a/js/src/jit/IonMacroAssembler.cpp
+++ b/js/src/jit/IonMacroAssembler.cpp
@@ -300,17 +300,18 @@ MacroAssembler::moveNurseryPtr(const Imm
     if (ptr.value && gc::IsInsideNursery(GetIonContext()->cx->runtime(), (void *)ptr.value))
         embedsNurseryPointers_ = true;
 #endif
     movePtr(ptr, reg);
 }
 
 template<typename S, typename T>
 static void
-StoreToTypedFloatArray(MacroAssembler &masm, int arrayType, const S &value, const T &dest) {
+StoreToTypedFloatArray(MacroAssembler &masm, int arrayType, const S &value, const T &dest)
+{
     switch (arrayType) {
       case ScalarTypeRepresentation::TYPE_FLOAT32:
         if (LIRGenerator::allowFloat32Optimizations()) {
             masm.storeFloat(value, dest);
         } else {
 #ifdef JS_MORE_DETERMINISTIC
             // See the comment in ToDoubleForTypedArray.
             masm.canonicalizeDouble(value);
@@ -326,20 +327,26 @@ StoreToTypedFloatArray(MacroAssembler &m
 #endif
         masm.storeDouble(value, dest);
         break;
       default:
         MOZ_ASSUME_UNREACHABLE("Invalid typed array type");
     }
 }
 
-void MacroAssembler::storeToTypedFloatArray(int arrayType, const FloatRegister &value, const BaseIndex &dest) {
+void
+MacroAssembler::storeToTypedFloatArray(int arrayType, const FloatRegister &value,
+                                       const BaseIndex &dest)
+{
     StoreToTypedFloatArray(*this, arrayType, value, dest);
 }
-void MacroAssembler::storeToTypedFloatArray(int arrayType, const FloatRegister &value, const Address &dest) {
+void
+MacroAssembler::storeToTypedFloatArray(int arrayType, const FloatRegister &value,
+                                       const Address &dest)
+{
     StoreToTypedFloatArray(*this, arrayType, value, dest);
 }
 
 template<typename T>
 void
 MacroAssembler::loadFromTypedArray(int arrayType, const T &src, AnyRegister dest, Register temp,
                                    Label *fail)
 {
@@ -1369,84 +1376,91 @@ MacroAssembler::convertInt32ValueToDoubl
     branchTestInt32(Assembler::NotEqual, address, done);
     unboxInt32(address, scratch);
     convertInt32ToDouble(scratch, ScratchFloatReg);
     storeDouble(ScratchFloatReg, address);
 }
 
 static const double DoubleZero = 0.0;
 static const double DoubleOne  = 1.0;
+static const float FloatZero = 0.0;
+static const float FloatOne  = 1.0;
+static const float FloatNaN = js_NaN;
 
 void
-MacroAssembler::convertValueToDouble(ValueOperand value, FloatRegister output, Label *fail)
+MacroAssembler::convertValueToFloatingPoint(ValueOperand value, FloatRegister output,
+                                            Label *fail, MIRType outputType)
 {
     Register tag = splitTagForTest(value);
 
     Label isDouble, isInt32, isBool, isNull, done;
 
     branchTestDouble(Assembler::Equal, tag, &isDouble);
     branchTestInt32(Assembler::Equal, tag, &isInt32);
     branchTestBoolean(Assembler::Equal, tag, &isBool);
     branchTestNull(Assembler::Equal, tag, &isNull);
     branchTestUndefined(Assembler::NotEqual, tag, fail);
 
     // fall-through: undefined
-    loadStaticDouble(&js_NaN, output);
+    loadStaticFloatingPoint(&js_NaN, &FloatNaN, output, outputType);
     jump(&done);
 
     bind(&isNull);
-    loadStaticDouble(&DoubleZero, output);
+    loadStaticFloatingPoint(&DoubleZero, &FloatZero, output, outputType);
     jump(&done);
 
     bind(&isBool);
-    boolValueToDouble(value, output);
+    boolValueToFloatingPoint(value, output, outputType);
     jump(&done);
 
     bind(&isInt32);
-    int32ValueToDouble(value, output);
+    int32ValueToFloatingPoint(value, output, outputType);
     jump(&done);
 
     bind(&isDouble);
     unboxDouble(value, output);
+    if (outputType == MIRType_Float32)
+        convertDoubleToFloat(output, output);
     bind(&done);
 }
 
 bool
-MacroAssembler::convertValueToDouble(JSContext *cx, const Value &v, FloatRegister output, Label *fail)
+MacroAssembler::convertValueToFloatingPoint(JSContext *cx, const Value &v, FloatRegister output,
+                                            Label *fail, MIRType outputType)
 {
     if (v.isNumber() || v.isString()) {
         double d;
         if (v.isNumber())
             d = v.toNumber();
         else if (!StringToNumber(cx, v.toString(), &d))
             return false;
 
         if (d == js_NaN)
-            loadStaticDouble(&js_NaN, output);
+            loadStaticFloatingPoint(&js_NaN, &FloatNaN, output, outputType);
         else
-            loadConstantDouble(d, output);
+            loadConstantFloatingPoint(d, static_cast<float>(d), output, outputType);
 
         return true;
     }
 
     if (v.isBoolean()) {
         if (v.toBoolean())
-            loadStaticDouble(&DoubleOne, output);
+            loadStaticFloatingPoint(&DoubleOne, &FloatOne, output, outputType);
         else
-            loadStaticDouble(&DoubleZero, output);
+            loadStaticFloatingPoint(&DoubleZero, &FloatZero, output, outputType);
         return true;
     }
 
     if (v.isNull()) {
-        loadStaticDouble(&DoubleZero, output);
+        loadStaticFloatingPoint(&DoubleZero, &FloatZero, output, outputType);
         return true;
     }
 
     if (v.isUndefined()) {
-        loadStaticDouble(&js_NaN, output);
+        loadStaticFloatingPoint(&js_NaN, &FloatNaN, output, outputType);
         return true;
     }
 
     JS_ASSERT(v.isObject());
     jump(fail);
     return true;
 }
 
@@ -1485,73 +1499,92 @@ MacroAssembler::popRooted(VMFunction::Ro
         break;
       case VMFunction::RootValue:
         Pop(valueReg);
         break;
     }
 }
 
 bool
-MacroAssembler::convertConstantOrRegisterToDouble(JSContext *cx, ConstantOrRegister src,
-                                                  FloatRegister output, Label *fail)
+MacroAssembler::convertConstantOrRegisterToFloatingPoint(JSContext *cx, ConstantOrRegister src,
+                                                         FloatRegister output, Label *fail,
+                                                         MIRType outputType)
 {
     if (src.constant())
-        return convertValueToDouble(cx, src.value(), output, fail);
+        return convertValueToFloatingPoint(cx, src.value(), output, fail, outputType);
 
-    convertTypedOrValueToDouble(src.reg(), output, fail);
+    convertTypedOrValueToFloatingPoint(src.reg(), output, fail, outputType);
     return true;
 }
 
 void
-MacroAssembler::convertTypedOrValueToDouble(TypedOrValueRegister src, FloatRegister output,
-                                            Label *fail)
+MacroAssembler::convertTypedOrValueToFloatingPoint(TypedOrValueRegister src, FloatRegister output,
+                                                   Label *fail, MIRType outputType)
 {
+    JS_ASSERT(IsFloatingPointType(outputType));
+
     if (src.hasValue()) {
-        convertValueToDouble(src.valueReg(), output, fail);
+        convertValueToFloatingPoint(src.valueReg(), output, fail, outputType);
         return;
     }
 
+    bool outputIsDouble = outputType == MIRType_Double;
     switch (src.type()) {
       case MIRType_Null:
-        loadStaticDouble(&DoubleZero, output);
+        loadStaticFloatingPoint(&DoubleZero, &FloatZero, output, outputType);
         break;
       case MIRType_Boolean:
       case MIRType_Int32:
-        convertInt32ToDouble(src.typedReg().gpr(), output);
+        convertInt32ToFloatingPoint(src.typedReg().gpr(), output, outputType);
+        break;
+      case MIRType_Float32:
+        if (outputIsDouble) {
+            convertFloatToDouble(src.typedReg().fpu(), output);
+        } else {
+            if (src.typedReg().fpu() != output)
+                moveFloat(src.typedReg().fpu(), output);
+        }
         break;
       case MIRType_Double:
-        if (src.typedReg().fpu() != output)
-            moveDouble(src.typedReg().fpu(), output);
+        if (outputIsDouble) {
+            if (src.typedReg().fpu() != output)
+                moveDouble(src.typedReg().fpu(), output);
+        } else {
+            convertDoubleToFloat(src.typedReg().fpu(), output);
+        }
         break;
       case MIRType_Object:
       case MIRType_String:
         jump(fail);
         break;
       case MIRType_Undefined:
-        loadStaticDouble(&js_NaN, output);
+        loadStaticFloatingPoint(&js_NaN, &FloatNaN, output, outputType);
         break;
       default:
         MOZ_ASSUME_UNREACHABLE("Bad MIRType");
     }
 }
 
 void
-MacroAssembler::convertDoubleToInt(FloatRegister src, Register output, Label *truncateFail,
-                                   Label *fail, IntConversionBehavior behavior)
+MacroAssembler::convertDoubleToInt(FloatRegister src, Register output, FloatRegister temp,
+                                   Label *truncateFail, Label *fail,
+                                   IntConversionBehavior behavior)
 {
     switch (behavior) {
       case IntConversion_Normal:
       case IntConversion_NegativeZeroCheck:
         convertDoubleToInt32(src, output, fail, behavior == IntConversion_NegativeZeroCheck);
         break;
       case IntConversion_Truncate:
         branchTruncateDouble(src, output, truncateFail ? truncateFail : fail);
         break;
       case IntConversion_ClampToUint8:
-        clampDoubleToUint8(src, output);
+        // Clamping clobbers the input register, so use a temp.
+        moveDouble(src, temp);
+        clampDoubleToUint8(temp, output);
         break;
     }
 }
 
 void
 MacroAssembler::convertValueToInt(ValueOperand value, MDefinition *maybeInput,
                                   Label *handleStringEntry, Label *handleStringRejoin,
                                   Label *truncateDoubleSlow,
@@ -1608,17 +1641,17 @@ MacroAssembler::convertValueToInt(ValueO
         if (isDouble.used()) {
             bind(&isDouble);
             unboxDouble(value, temp);
         }
 
         if (handleStrings)
             bind(handleStringRejoin);
 
-        convertDoubleToInt(temp, output, truncateDoubleSlow, fail, behavior);
+        convertDoubleToInt(temp, output, temp, truncateDoubleSlow, fail, behavior);
         jump(&done);
     }
 
     // Just unbox a bool, the result is 0 or 1.
     if (isBool.used()) {
         bind(&isBool);
         unboxBoolean(value, output);
         jump(&done);
@@ -1717,19 +1750,21 @@ MacroAssembler::convertTypedOrValueToInt
       case MIRType_Undefined:
       case MIRType_Null:
         move32(Imm32(0), output);
         break;
       case MIRType_Boolean:
       case MIRType_Int32:
         if (src.typedReg().gpr() != output)
             move32(src.typedReg().gpr(), output);
+        if (src.type() == MIRType_Int32 && behavior == IntConversion_ClampToUint8)
+            clampIntToUint8(output);
         break;
       case MIRType_Double:
-        convertDoubleToInt(src.typedReg().fpu(), output, NULL, fail, behavior);
+        convertDoubleToInt(src.typedReg().fpu(), output, temp, NULL, fail, behavior);
         break;
       case MIRType_String:
       case MIRType_Object:
         jump(fail);
         break;
       default:
         MOZ_ASSUME_UNREACHABLE("Bad MIRType");
     }
--- a/js/src/jit/IonMacroAssembler.h
+++ b/js/src/jit/IonMacroAssembler.h
@@ -280,22 +280,26 @@ class MacroAssembler : public MacroAssem
             if (holeCheck)
                 branchTestMagic(Assembler::Equal, src, hole);
             loadUnboxedValue(src, dest.type(), dest.typedReg());
         }
     }
 
     template <typename T>
     void storeTypedOrValue(TypedOrValueRegister src, const T &dest) {
-        if (src.hasValue())
+        if (src.hasValue()) {
             storeValue(src.valueReg(), dest);
-        else if (src.type() == MIRType_Double)
-            storeDouble(src.typedReg().fpu(), dest);
-        else
+        } else if (IsFloatingPointType(src.type())) {
+            FloatRegister reg = src.typedReg().fpu();
+            if (src.type() == MIRType_Float32)
+                convertFloatToDouble(reg, reg);
+            storeDouble(reg, dest);
+        } else {
             storeValue(ValueTypeFromMIRType(src.type()), src.typedReg().gpr(), dest);
+        }
     }
 
     template <typename T>
     void storeConstantOrRegister(ConstantOrRegister src, const T &dest) {
         if (src.constant())
             storeValue(src.value(), dest);
         else
             storeTypedOrValue(src.reg(), dest);
@@ -422,22 +426,26 @@ class MacroAssembler : public MacroAssem
                 Push(ImmGCPtr(str));
             }
         } else {
             Push(ImmWord(JSID_BITS(id)));
         }
     }
 
     void Push(TypedOrValueRegister v) {
-        if (v.hasValue())
+        if (v.hasValue()) {
             Push(v.valueReg());
-        else if (IsFloatingPointType(v.type()))
-            Push(v.typedReg().fpu());
-        else
+        } else if (IsFloatingPointType(v.type())) {
+            FloatRegister reg = v.typedReg().fpu();
+            if (v.type() == MIRType_Float32)
+                convertFloatToDouble(reg, reg);
+            Push(reg);
+        } else {
             Push(ValueTypeFromMIRType(v.type()), v.typedReg().gpr());
+        }
     }
 
     void Push(ConstantOrRegister v) {
         if (v.constant())
             Push(v.value());
         else
             Push(v.reg());
     }
@@ -990,35 +998,96 @@ class MacroAssembler : public MacroAssem
     void printf(const char *output, Register value);
 
 #if JS_TRACE_LOGGING
     void tracelogStart(JSScript *script);
     void tracelogStop();
     void tracelogLog(TraceLogging::Type type);
 #endif
 
+#define DISPATCH_FLOATING_POINT_OP(method, type, arg1d, arg1f, arg2)    \
+    JS_ASSERT(IsFloatingPointType(type));                               \
+    if (type == MIRType_Double)                                         \
+        method##Double(arg1d, arg2);                                    \
+    else                                                                \
+        method##Float32(arg1f, arg2);                                   \
+
+    void loadStaticFloatingPoint(const double *dp, const float *fp, FloatRegister dest,
+                                 MIRType destType)
+    {
+        DISPATCH_FLOATING_POINT_OP(loadStatic, destType, dp, fp, dest);
+    }
+    void loadConstantFloatingPoint(double d, float f, FloatRegister dest, MIRType destType) {
+        DISPATCH_FLOATING_POINT_OP(loadConstant, destType, d, f, dest);
+    }
+    void boolValueToFloatingPoint(ValueOperand value, FloatRegister dest, MIRType destType) {
+        DISPATCH_FLOATING_POINT_OP(boolValueTo, destType, value, value, dest);
+    }
+    void int32ValueToFloatingPoint(ValueOperand value, FloatRegister dest, MIRType destType) {
+        DISPATCH_FLOATING_POINT_OP(int32ValueTo, destType, value, value, dest);
+    }
+    void convertInt32ToFloatingPoint(Register src, FloatRegister dest, MIRType destType) {
+        DISPATCH_FLOATING_POINT_OP(convertInt32To, destType, src, src, dest);
+    }
+
+#undef DISPATCH_FLOATING_POINT_OP
+
+    void convertValueToFloatingPoint(ValueOperand value, FloatRegister output, Label *fail,
+                                     MIRType outputType);
+    bool convertValueToFloatingPoint(JSContext *cx, const Value &v, FloatRegister output,
+                                     Label *fail, MIRType outputType);
+    bool convertConstantOrRegisterToFloatingPoint(JSContext *cx, ConstantOrRegister src,
+                                                  FloatRegister output, Label *fail,
+                                                  MIRType outputType);
+    void convertTypedOrValueToFloatingPoint(TypedOrValueRegister src, FloatRegister output,
+                                            Label *fail, MIRType outputType);
+
     void convertInt32ValueToDouble(const Address &address, Register scratch, Label *done);
-    void convertValueToDouble(ValueOperand value, FloatRegister output, Label *fail);
-    bool convertValueToDouble(JSContext *cx, const Value &v, FloatRegister output, Label *fail);
+    void convertValueToDouble(ValueOperand value, FloatRegister output, Label *fail) {
+        convertValueToFloatingPoint(value, output, fail, MIRType_Double);
+    }
+    bool convertValueToDouble(JSContext *cx, const Value &v, FloatRegister output, Label *fail) {
+        return convertValueToFloatingPoint(cx, v, output, fail, MIRType_Double);
+    }
     bool convertConstantOrRegisterToDouble(JSContext *cx, ConstantOrRegister src,
-                                           FloatRegister output, Label *fail);
-    void convertTypedOrValueToDouble(TypedOrValueRegister src, FloatRegister output, Label *fail);
+                                           FloatRegister output, Label *fail)
+    {
+        return convertConstantOrRegisterToFloatingPoint(cx, src, output, fail, MIRType_Double);
+    }
+    void convertTypedOrValueToDouble(TypedOrValueRegister src, FloatRegister output, Label *fail) {
+        convertTypedOrValueToFloatingPoint(src, output, fail, MIRType_Double);
+    }
+
+    void convertValueToFloat(ValueOperand value, FloatRegister output, Label *fail) {
+        convertValueToFloatingPoint(value, output, fail, MIRType_Float32);
+    }
+    bool convertValueToFloat(JSContext *cx, const Value &v, FloatRegister output, Label *fail) {
+        return convertValueToFloatingPoint(cx, v, output, fail, MIRType_Float32);
+    }
+    bool convertConstantOrRegisterToFloat(JSContext *cx, ConstantOrRegister src,
+                                          FloatRegister output, Label *fail)
+    {
+        return convertConstantOrRegisterToFloatingPoint(cx, src, output, fail, MIRType_Float32);
+    }
+    void convertTypedOrValueToFloat(TypedOrValueRegister src, FloatRegister output, Label *fail) {
+        convertTypedOrValueToFloatingPoint(src, output, fail, MIRType_Float32);
+    }
 
     enum IntConversionBehavior {
         IntConversion_Normal,
         IntConversion_NegativeZeroCheck,
         IntConversion_Truncate,
         IntConversion_ClampToUint8,
     };
 
     //
     // Functions for converting values to int.
     //
-    void convertDoubleToInt(FloatRegister src, Register output, Label *truncateFail, Label *fail,
-                            IntConversionBehavior behavior);
+    void convertDoubleToInt(FloatRegister src, Register output, FloatRegister temp,
+                            Label *truncateFail, Label *fail, IntConversionBehavior behavior);
 
     // Strings may be handled by providing labels to jump to when the behavior
     // is truncation or clamping. The subroutine, usually an OOL call, is
     // passed the unboxed string in |stringReg| and should convert it to a
     // double store into |temp|.
     void convertValueToInt(ValueOperand value, MDefinition *input,
                            Label *handleStringEntry, Label *handleStringRejoin,
                            Label *truncateDoubleSlow,
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -6959,16 +6959,18 @@ class MSetElementCache
 
     bool strict() const {
         return strict_;
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
+
+    bool canConsumeFloat32() const { return true; }
 };
 
 class MCallGetProperty
   : public MUnaryInstruction,
     public BoxInputsPolicy
 {
     CompilerRootPropertyName name_;
     bool idempotent_;
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -1259,25 +1259,31 @@ CodeGeneratorARM::visitBox(LBox *box)
     // On x86, the input operand and the output payload have the same
     // virtual register. All that needs to be written is the type tag for
     // the type definition.
     masm.ma_mov(Imm32(MIRTypeToTag(box->type())), ToRegister(type));
     return true;
 }
 
 bool
-CodeGeneratorARM::visitBoxDouble(LBoxDouble *box)
+CodeGeneratorARM::visitBoxFloatingPoint(LBoxFloatingPoint *box)
 {
     const LDefinition *payload = box->getDef(PAYLOAD_INDEX);
     const LDefinition *type = box->getDef(TYPE_INDEX);
     const LAllocation *in = box->getOperand(0);
 
+    FloatRegister reg = ToFloatRegister(in);
+    if (box->type() == MIRType_Float32) {
+        masm.convertFloatToDouble(reg, ScratchFloatReg);
+        reg = ScratchFloatReg;
+    }
+
     //masm.as_vxfer(ToRegister(payload), ToRegister(type),
     //              VFPRegister(ToFloatRegister(in)), Assembler::FloatToCore);
-    masm.ma_vxfer(VFPRegister(ToFloatRegister(in)), ToRegister(payload), ToRegister(type));
+    masm.ma_vxfer(VFPRegister(reg), ToRegister(payload), ToRegister(type));
     return true;
 }
 
 bool
 CodeGeneratorARM::visitUnbox(LUnbox *unbox)
 {
     // Note that for unbox, the type and payload indexes are switched on the
     // inputs.
--- a/js/src/jit/arm/CodeGenerator-arm.h
+++ b/js/src/jit/arm/CodeGenerator-arm.h
@@ -125,17 +125,17 @@ class CodeGeneratorARM : public CodeGene
     bool modICommon(MMod *mir, Register lhs, Register rhs, Register output, LSnapshot *snapshot,
                     Label &done);
 
   public:
     CodeGeneratorARM(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm);
 
   public:
     bool visitBox(LBox *box);
-    bool visitBoxDouble(LBoxDouble *box);
+    bool visitBoxFloatingPoint(LBoxFloatingPoint *box);
     bool visitUnbox(LUnbox *unbox);
     bool visitValue(LValue *value);
     bool visitOsrValue(LOsrValue *value);
     bool visitDouble(LDouble *ins);
 
     bool visitLoadSlotV(LLoadSlotV *load);
     bool visitLoadSlotT(LLoadSlotT *load);
     bool visitStoreSlotT(LStoreSlotT *load);
--- a/js/src/jit/arm/LIR-arm.h
+++ b/js/src/jit/arm/LIR-arm.h
@@ -23,25 +23,33 @@ class LBox : public LInstructionHelper<2
         setOperand(0, in_payload);
     }
 
     MIRType type() const {
         return type_;
     }
 };
 
-class LBoxDouble : public LInstructionHelper<2, 1, 1>
+class LBoxFloatingPoint : public LInstructionHelper<2, 1, 1>
 {
+    MIRType type_;
+
   public:
-    LIR_HEADER(BoxDouble);
+    LIR_HEADER(BoxFloatingPoint);
 
-    LBoxDouble(const LAllocation &in, const LDefinition &temp) {
+    LBoxFloatingPoint(const LAllocation &in, const LDefinition &temp, MIRType type)
+      : type_(type)
+    {
         setOperand(0, in);
         setTemp(0, temp);
     }
+
+    MIRType type() const {
+        return type_;
+    }
 };
 
 class LUnbox : public LInstructionHelper<1, 2, 0>
 {
   public:
     LIR_HEADER(Unbox);
 
     MUnbox *mir() const {
@@ -50,26 +58,36 @@ class LUnbox : public LInstructionHelper
     const LAllocation *payload() {
         return getOperand(0);
     }
     const LAllocation *type() {
         return getOperand(1);
     }
 };
 
-class LUnboxDouble : public LInstructionHelper<1, 2, 0>
+class LUnboxFloatingPoint : public LInstructionHelper<1, 2, 0>
 {
+    MIRType type_;
+
   public:
-    LIR_HEADER(UnboxDouble);
+    LIR_HEADER(UnboxFloatingPoint);
 
     static const size_t Input = 0;
 
+    LUnboxFloatingPoint(MIRType type)
+      : type_(type)
+    { }
+
     MUnbox *mir() const {
         return mir_->toUnbox();
     }
+
+    MIRType type() const {
+        return type_;
+    }
 };
 
 // Convert a 32-bit unsigned integer to a double.
 class LUInt32ToDouble : public LInstructionHelper<1, 1, 0>
 {
   public:
     LIR_HEADER(UInt32ToDouble)
 
--- a/js/src/jit/arm/LOpcodes-arm.h
+++ b/js/src/jit/arm/LOpcodes-arm.h
@@ -4,19 +4,19 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jit_arm_LOpcodes_arm_h
 #define jit_arm_LOpcodes_arm_h
 
 #define LIR_CPU_OPCODE_LIST(_)  \
     _(Unbox)                    \
-    _(UnboxDouble)              \
+    _(UnboxFloatingPoint)       \
     _(Box)                      \
-    _(BoxDouble)                \
+    _(BoxFloatingPoint)         \
     _(DivI)                     \
     _(SoftDivI)                 \
     _(DivPowTwoI)               \
     _(ModI)                     \
     _(SoftModI)                 \
     _(ModPowTwoI)               \
     _(ModMaskI)                 \
     _(PowHalfD)                 \
--- a/js/src/jit/arm/Lowering-arm.cpp
+++ b/js/src/jit/arm/Lowering-arm.cpp
@@ -77,18 +77,19 @@ LIRGeneratorARM::visitConstant(MConstant
 }
 
 bool
 LIRGeneratorARM::visitBox(MBox *box)
 {
     MDefinition *inner = box->getOperand(0);
 
     // If the box wrapped a double, it needs a new register.
-    if (inner->type() == MIRType_Double)
-        return defineBox(new LBoxDouble(useRegisterAtStart(inner), tempCopy(inner, 0)), box);
+    if (IsFloatingPointType(inner->type()))
+        return defineBox(new LBoxFloatingPoint(useRegisterAtStart(inner), tempCopy(inner, 0),
+                                               inner->type()), box);
 
     if (box->canEmitAtUses())
         return emitAtUses(box);
 
     if (inner->isConstant())
         return defineBox(new LValue(inner->toConstant()->value()), box);
 
     LBox *lir = new LBox(use(inner), inner->type());
@@ -118,21 +119,21 @@ LIRGeneratorARM::visitUnbox(MUnbox *unbo
     // An unbox on arm reads in a type tag (either in memory or a register) and
     // a payload. Unlike most instructions conusming a box, we ask for the type
     // second, so that the result can re-use the first input.
     MDefinition *inner = unbox->getOperand(0);
 
     if (!ensureDefined(inner))
         return false;
 
-    if (unbox->type() == MIRType_Double) {
-        LUnboxDouble *lir = new LUnboxDouble();
+    if (IsFloatingPointType(unbox->type())) {
+        LUnboxFloatingPoint *lir = new LUnboxFloatingPoint(unbox->type());
         if (unbox->fallible() && !assignSnapshot(lir, unbox->bailoutKind()))
             return false;
-        if (!useBox(lir, LUnboxDouble::Input, inner))
+        if (!useBox(lir, LUnboxFloatingPoint::Input, inner))
             return false;
         return define(lir, unbox);
     }
 
     // Swap the order we use the box pieces so we can re-use the payload register.
     LUnbox *lir = new LUnbox;
     lir->setOperand(0, usePayloadInRegisterAtStart(inner));
     lir->setOperand(1, useType(inner, LUse::REGISTER));
--- a/js/src/jit/arm/MacroAssembler-arm.h
+++ b/js/src/jit/arm/MacroAssembler-arm.h
@@ -779,16 +779,19 @@ class MacroAssemblerARMCompat : public M
         MOZ_ASSUME_UNREACHABLE("NYI");
     }
     void int32ValueToFloat32(const ValueOperand &operand, const FloatRegister &dest) {
         MOZ_ASSUME_UNREACHABLE("NYI");
     }
     void loadStaticFloat32(const float *dp, const FloatRegister &dest) {
         MOZ_ASSUME_UNREACHABLE("NYI");
     }
+    void loadConstantFloat32(const float dp, const FloatRegister &dest) {
+        MOZ_ASSUME_UNREACHABLE("NYI");
+    }
 
     template<typename T>
     void branchTestInt32(Condition cond, const T & t, Label *label) {
         Condition c = testInt32(cond, t);
         ma_b(label, c);
     }
     template<typename T>
     void branchTestBoolean(Condition cond, const T & t, Label *label) {
@@ -1452,16 +1455,19 @@ class MacroAssemblerARMCompat : public M
         return as_cmp(bounded, Imm8(0));
     }
 
     void storeFloat(VFPRegister src, Register base, Register index, Condition cond) {
         as_vcvt(VFPRegister(ScratchFloatReg).singleOverlay(), src, false, cond);
         ma_vstr(VFPRegister(ScratchFloatReg).singleOverlay(), base, index, 0, cond);
 
     }
+    void moveFloat(FloatRegister src, FloatRegister dest) {
+        as_vmov(VFPRegister(src).singleOverlay(), VFPRegister(dest).singleOverlay());
+    }
 };
 
 typedef MacroAssemblerARMCompat MacroAssemblerSpecific;
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_arm_MacroAssembler_arm_h */
--- a/js/src/jit/shared/Assembler-x86-shared.h
+++ b/js/src/jit/shared/Assembler-x86-shared.h
@@ -324,16 +324,20 @@ class AssemblerX86Shared
             break;
           case Operand::MEM_SCALE:
             masm.movsd_rm(src.code(), dest.disp(), dest.base(), dest.index(), dest.scale());
             break;
           default:
             MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
         }
     }
+    void movss(const FloatRegister &src, const FloatRegister &dest) {
+        JS_ASSERT(HasSSE2());
+        masm.movss_rr(src.code(), dest.code());
+    }
     void movss(const Operand &src, const FloatRegister &dest) {
         JS_ASSERT(HasSSE2());
         switch (src.kind()) {
           case Operand::FPREG:
             masm.movss_rr(src.fpu(), dest.code());
             break;
           case Operand::MEM_REG_DISP:
             masm.movss_mr(src.disp(), src.base(), dest.code());
--- a/js/src/jit/shared/MacroAssembler-x86-shared.h
+++ b/js/src/jit/shared/MacroAssembler-x86-shared.h
@@ -387,16 +387,19 @@ class MacroAssemblerX86Shared : public A
         movss(src, dest);
     }
     void storeFloat(FloatRegister src, const Address &dest) {
         movss(src, Operand(dest));
     }
     void storeFloat(FloatRegister src, const BaseIndex &dest) {
         movss(src, Operand(dest));
     }
+    void moveFloat(FloatRegister src, FloatRegister dest) {
+        movss(src, dest);
+    }
 
     // Checks whether a double 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 convertDoubleToInt32(FloatRegister src, Register dest, Label *fail,
                               bool negativeZeroCheck = true)
     {
         cvttsd2si(src, dest);
--- a/js/src/jit/x64/CodeGenerator-x64.cpp
+++ b/js/src/jit/x64/CodeGenerator-x64.cpp
@@ -79,20 +79,26 @@ CodeGeneratorX64::visitOsrValue(LOsrValu
 }
 
 bool
 CodeGeneratorX64::visitBox(LBox *box)
 {
     const LAllocation *in = box->getOperand(0);
     const LDefinition *result = box->getDef(0);
 
-    if (box->type() != MIRType_Double)
+    if (IsFloatingPointType(box->type())) {
+        FloatRegister reg = ToFloatRegister(in);
+        if (box->type() == MIRType_Float32) {
+            masm.convertFloatToDouble(reg, ScratchFloatReg);
+            reg = ScratchFloatReg;
+        }
+        masm.movq(reg, ToRegister(result));
+    } else {
         masm.boxValue(ValueTypeFromMIRType(box->type()), ToRegister(in), ToRegister(result));
-    else
-        masm.movq(ToFloatRegister(in), ToRegister(result));
+    }
     return true;
 }
 
 bool
 CodeGeneratorX64::visitUnbox(LUnbox *unbox)
 {
     const ValueOperand value = ToValue(unbox, LUnbox::Input);
     const LDefinition *result = unbox->output();
--- a/js/src/jit/x64/LIR-x64.h
+++ b/js/src/jit/x64/LIR-x64.h
@@ -49,23 +49,30 @@ class LUnbox : public LUnboxBase {
   public:
     LIR_HEADER(Unbox)
 
     LUnbox(const LAllocation &input)
       : LUnboxBase(input)
     { }
 };
 
-class LUnboxDouble : public LUnboxBase {
+class LUnboxFloatingPoint : public LUnboxBase {
+    MIRType type_;
+
   public:
-    LIR_HEADER(UnboxDouble)
+    LIR_HEADER(UnboxFloatingPoint)
 
-    LUnboxDouble(const LAllocation &input)
-      : LUnboxBase(input)
+    LUnboxFloatingPoint(const LAllocation &input, MIRType type)
+      : LUnboxBase(input),
+        type_(type)
     { }
+
+    MIRType type() const {
+        return type_;
+    }
 };
 
 // Convert a 32-bit unsigned integer to a double.
 class LUInt32ToDouble : public LInstructionHelper<1, 1, 0>
 {
   public:
     LIR_HEADER(UInt32ToDouble)
 
--- a/js/src/jit/x64/LOpcodes-x64.h
+++ b/js/src/jit/x64/LOpcodes-x64.h
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jit_x64_LOpcodes_x64_h
 #define jit_x64_LOpcodes_x64_h
 
 #define LIR_CPU_OPCODE_LIST(_)      \
     _(Box)                          \
     _(Unbox)                        \
-    _(UnboxDouble)                  \
+    _(UnboxFloatingPoint)           \
     _(DivI)                         \
     _(DivPowTwoI)                   \
     _(DivSelfI)                     \
     _(ModI)                         \
     _(ModPowTwoI)                   \
     _(PowHalfD)                     \
     _(UInt32ToDouble)               \
     _(AsmJSLoadFuncPtr)             \
--- a/js/src/jit/x64/Lowering-x64.cpp
+++ b/js/src/jit/x64/Lowering-x64.cpp
@@ -71,18 +71,18 @@ LIRGeneratorX64::visitBox(MBox *box)
     return define(ins, box, LDefinition(LDefinition::BOX));
 }
 
 bool
 LIRGeneratorX64::visitUnbox(MUnbox *unbox)
 {
     MDefinition *box = unbox->getOperand(0);
     LUnboxBase *lir;
-    if (unbox->type() == MIRType_Double)
-        lir = new LUnboxDouble(useRegister(box));
+    if (IsFloatingPointType(unbox->type()))
+        lir = new LUnboxFloatingPoint(useRegister(box), unbox->type());
     else
         lir = new LUnbox(useRegister(box));
 
     if (unbox->fallible() && !assignSnapshot(lir, unbox->bailoutKind()))
         return false;
 
     return define(lir, unbox);
 }
--- a/js/src/jit/x86/CodeGenerator-x86.cpp
+++ b/js/src/jit/x86/CodeGenerator-x86.cpp
@@ -113,22 +113,27 @@ CodeGeneratorX86::visitBox(LBox *box)
     // On x86, the input operand and the output payload have the same
     // virtual register. All that needs to be written is the type tag for
     // the type definition.
     masm.movl(Imm32(MIRTypeToTag(box->type())), ToRegister(type));
     return true;
 }
 
 bool
-CodeGeneratorX86::visitBoxDouble(LBoxDouble *box)
+CodeGeneratorX86::visitBoxFloatingPoint(LBoxFloatingPoint *box)
 {
     const LAllocation *in = box->getOperand(0);
     const ValueOperand out = ToOutValue(box);
 
-    masm.boxDouble(ToFloatRegister(in), out);
+    FloatRegister reg = ToFloatRegister(in);
+    if (box->type() == MIRType_Float32) {
+        masm.convertFloatToDouble(reg, ScratchFloatReg);
+        reg = ScratchFloatReg;
+    }
+    masm.boxDouble(reg, out);
     return true;
 }
 
 bool
 CodeGeneratorX86::visitUnbox(LUnbox *unbox)
 {
     // Note that for unbox, the type and payload indexes are switched on the
     // inputs.
--- a/js/src/jit/x86/CodeGenerator-x86.h
+++ b/js/src/jit/x86/CodeGenerator-x86.h
@@ -43,17 +43,17 @@ class CodeGeneratorX86 : public CodeGene
     void storeElementTyped(const LAllocation *value, MIRType valueType, MIRType elementType,
                            const Register &elements, const LAllocation *index);
 
   public:
     CodeGeneratorX86(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm);
 
   public:
     bool visitBox(LBox *box);
-    bool visitBoxDouble(LBoxDouble *box);
+    bool visitBoxFloatingPoint(LBoxFloatingPoint *box);
     bool visitUnbox(LUnbox *unbox);
     bool visitValue(LValue *value);
     bool visitOsrValue(LOsrValue *value);
     bool visitLoadSlotV(LLoadSlotV *load);
     bool visitLoadSlotT(LLoadSlotT *load);
     bool visitStoreSlotT(LStoreSlotT *store);
     bool visitLoadElementT(LLoadElementT *load);
     bool visitImplicitThis(LImplicitThis *lir);
--- a/js/src/jit/x86/LIR-x86.h
+++ b/js/src/jit/x86/LIR-x86.h
@@ -23,25 +23,34 @@ class LBox : public LInstructionHelper<2
         setOperand(0, in_payload);
     }
 
     MIRType type() const {
         return type_;
     }
 };
 
-class LBoxDouble : public LInstructionHelper<2, 1, 1>
+class LBoxFloatingPoint : public LInstructionHelper<2, 1, 1>
 {
+    MIRType type_;
+
   public:
-    LIR_HEADER(BoxDouble);
+    LIR_HEADER(BoxFloatingPoint);
 
-    LBoxDouble(const LAllocation &in, const LDefinition &temp) {
+    LBoxFloatingPoint(const LAllocation &in, const LDefinition &temp, MIRType type)
+      : type_(type)
+    {
+        JS_ASSERT(IsFloatingPointType(type));
         setOperand(0, in);
         setTemp(0, temp);
     }
+
+    MIRType type() const {
+        return type_;
+    }
 };
 
 class LUnbox : public LInstructionHelper<1, 2, 0>
 {
   public:
     LIR_HEADER(Unbox);
 
     MUnbox *mir() const {
@@ -50,26 +59,36 @@ class LUnbox : public LInstructionHelper
     const LAllocation *payload() {
         return getOperand(0);
     }
     const LAllocation *type() {
         return getOperand(1);
     }
 };
 
-class LUnboxDouble : public LInstructionHelper<1, 2, 0>
+class LUnboxFloatingPoint : public LInstructionHelper<1, 2, 0>
 {
+    MIRType type_;
+
   public:
-    LIR_HEADER(UnboxDouble);
+    LIR_HEADER(UnboxFloatingPoint);
 
     static const size_t Input = 0;
 
+    LUnboxFloatingPoint(MIRType type)
+      : type_(type)
+    { }
+
     MUnbox *mir() const {
         return mir_->toUnbox();
     }
+
+    MIRType type() const {
+        return type_;
+    }
 };
 
 // Convert a 32-bit unsigned integer to a double.
 class LUInt32ToDouble : public LInstructionHelper<1, 1, 1>
 {
   public:
     LIR_HEADER(UInt32ToDouble)
 
--- a/js/src/jit/x86/LOpcodes-x86.h
+++ b/js/src/jit/x86/LOpcodes-x86.h
@@ -4,19 +4,19 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jit_x86_LOpcodes_x86_h
 #define jit_x86_LOpcodes_x86_h
 
 #define LIR_CPU_OPCODE_LIST(_)  \
     _(Unbox)                    \
-    _(UnboxDouble)              \
+    _(UnboxFloatingPoint)       \
     _(Box)                      \
-    _(BoxDouble)                \
+    _(BoxFloatingPoint)         \
     _(DivI)                     \
     _(DivPowTwoI)               \
     _(DivSelfI)                 \
     _(ModI)                     \
     _(ModPowTwoI)               \
     _(PowHalfD)                 \
     _(UInt32ToDouble)           \
     _(AsmJSLoadFuncPtr)         \
--- a/js/src/jit/x86/Lowering-x86.cpp
+++ b/js/src/jit/x86/Lowering-x86.cpp
@@ -54,18 +54,19 @@ LIRGeneratorX86::useByteOpRegisterOrNonD
 }
 
 bool
 LIRGeneratorX86::visitBox(MBox *box)
 {
     MDefinition *inner = box->getOperand(0);
 
     // If the box wrapped a double, it needs a new register.
-    if (inner->type() == MIRType_Double)
-        return defineBox(new LBoxDouble(useRegisterAtStart(inner), tempCopy(inner, 0)), box);
+    if (IsFloatingPointType(inner->type()))
+        return defineBox(new LBoxFloatingPoint(useRegisterAtStart(inner), tempCopy(inner, 0),
+                                               inner->type()), box);
 
     if (box->canEmitAtUses())
         return emitAtUses(box);
 
     if (inner->isConstant())
         return defineBox(new LValue(inner->toConstant()->value()), box);
 
     LBox *lir = new LBox(use(inner), inner->type());
@@ -95,21 +96,21 @@ LIRGeneratorX86::visitUnbox(MUnbox *unbo
     // An unbox on x86 reads in a type tag (either in memory or a register) and
     // a payload. Unlike most instructions conusming a box, we ask for the type
     // second, so that the result can re-use the first input.
     MDefinition *inner = unbox->getOperand(0);
 
     if (!ensureDefined(inner))
         return false;
 
-    if (unbox->type() == MIRType_Double) {
-        LUnboxDouble *lir = new LUnboxDouble;
+    if (IsFloatingPointType(unbox->type())) {
+        LUnboxFloatingPoint *lir = new LUnboxFloatingPoint(unbox->type());
         if (unbox->fallible() && !assignSnapshot(lir, unbox->bailoutKind()))
             return false;
-        if (!useBox(lir, LUnboxDouble::Input, inner))
+        if (!useBox(lir, LUnboxFloatingPoint::Input, inner))
             return false;
         return define(lir, unbox);
     }
 
     // Swap the order we use the box pieces so we can re-use the payload register.
     LUnbox *lir = new LUnbox;
     lir->setOperand(0, usePayloadInRegisterAtStart(inner));
     lir->setOperand(1, useType(inner, LUse::ANY));