Bug 1112154 - Add MSimdBox and inline calls to SIMD constructors. r=bbouvier,jandem
authorNicolas B. Pierron <nicolas.b.pierron@mozilla.com>
Mon, 12 Jan 2015 16:45:55 +0100
changeset 249198 ac3b15d066657f307b8bcad8bd1b9993f0f82ece
parent 249197 ab1e869cfc5649ba7008d38deb73acac36e6096a
child 249199 a1654fa1847df3b85fc1d83879c9290332ea0325
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier, jandem
bugs1112154
milestone37.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 1112154 - Add MSimdBox and inline calls to SIMD constructors. r=bbouvier,jandem
js/src/asmjs/AsmJSValidate.cpp
js/src/jit/BaselineIC.cpp
js/src/jit/CodeGenerator.cpp
js/src/jit/CodeGenerator.h
js/src/jit/IonBuilder.h
js/src/jit/LIR-Common.h
js/src/jit/LOpcodes.h
js/src/jit/Lowering.cpp
js/src/jit/Lowering.h
js/src/jit/MCallOptimize.cpp
js/src/jit/MIR.h
js/src/jit/MOpcodes.h
js/src/jit/TypePolicy.cpp
js/src/jit/TypePolicy.h
--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -2908,17 +2908,17 @@ class FunctionCompiler
     template<typename T>
     MDefinition *constructSimd(MDefinition *x, MDefinition *y, MDefinition *z, MDefinition *w,
                                MIRType type)
     {
         if (inDeadCode())
             return nullptr;
 
         MOZ_ASSERT(IsSimdType(type));
-        T *ins = T::New(alloc(), type, x, y, z, w);
+        T *ins = T::NewAsmJS(alloc(), type, x, y, z, w);
         curBlock_->add(ins);
         return ins;
     }
 
     /***************************************************************** Calls */
 
     // The IonMonkey backend maintains a single stack offset (from the stack
     // pointer to the base of the frame) by adding the total amount of spill
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -9110,17 +9110,17 @@ GetTemplateObjectForClassHook(JSContext 
         Rooted<TypeDescr *> descr(cx, &args.callee().as<TypeDescr>());
         JSObject *obj = TypedObject::createZeroed(cx, descr, 1, gc::TenuredHeap);
         if (!obj)
             return false;
         templateObject.set(obj);
         return true;
     }
 
-    if (hook == SimdTypeDescr::call) {
+    if (hook == SimdTypeDescr::call && JitSupportsSimd()) {
         Rooted<SimdTypeDescr *> descr(cx, &args.callee().as<SimdTypeDescr>());
         JSObject *obj = TypedObject::createZeroed(cx, descr, 0, gc::TenuredHeap);
         if (!obj)
             return false;
         templateObject.set(obj);
         return true;
     }
 
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -4188,16 +4188,46 @@ CodeGenerator::visitNewTypedObject(LNewT
                                    (ArgList(), ImmGCPtr(templateObject), Imm32(initialHeap)),
                                    StoreRegisterTo(object));
 
     masm.createGCObject(object, temp, templateObject, initialHeap, ool->entry());
 
     masm.bind(ool->rejoin());
 }
 
+void
+CodeGenerator::visitSimdBox(LSimdBox *lir)
+{
+    FloatRegister in = ToFloatRegister(lir->input());
+    Register object = ToRegister(lir->output());
+    Register temp = ToRegister(lir->temp());
+    InlineTypedObject *templateObject = lir->mir()->templateObject();
+    gc::InitialHeap initialHeap = lir->mir()->initialHeap();
+    MIRType type = lir->mir()->input()->type();
+
+    // :TODO: We cannot spill SIMD registers (Bug 1112164) from safepoints, thus
+    // we cannot use the same oolCallVM as visitNewTypedObject for allocating
+    // SIMD Typed Objects if we are at the end of the nursery. (Bug 1119303)
+    Label bail;
+    masm.createGCObject(object, temp, templateObject, initialHeap, &bail);
+    bailoutFrom(&bail, lir->snapshot());
+
+    Address objectData(object, InlineTypedObject::offsetOfDataStart());
+    switch (type) {
+      case MIRType_Int32x4:
+        masm.storeUnalignedInt32x4(in, objectData);
+        break;
+      case MIRType_Float32x4:
+        masm.storeUnalignedFloat32x4(in, objectData);
+        break;
+      default:
+        MOZ_CRASH("Unknown SIMD kind when generating code for SimdBox.");
+    }
+}
+
 typedef js::DeclEnvObject *(*NewDeclEnvObjectFn)(JSContext *, HandleFunction, gc::InitialHeap);
 static const VMFunction NewDeclEnvObjectInfo =
     FunctionInfo<NewDeclEnvObjectFn>(DeclEnvObject::createTemplateObject);
 
 void
 CodeGenerator::visitNewDeclEnvObject(LNewDeclEnvObject *lir)
 {
     Register objReg = ToRegister(lir->output());
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -150,16 +150,17 @@ class CodeGenerator : public CodeGenerat
     void visitNewArray(LNewArray *lir);
     void visitOutOfLineNewArray(OutOfLineNewArray *ool);
     void visitNewArrayCopyOnWrite(LNewArrayCopyOnWrite *lir);
     void visitNewArrayDynamicLength(LNewArrayDynamicLength *lir);
     void visitNewObjectVMCall(LNewObject *lir);
     void visitNewObject(LNewObject *lir);
     void visitOutOfLineNewObject(OutOfLineNewObject *ool);
     void visitNewTypedObject(LNewTypedObject *lir);
+    void visitSimdBox(LSimdBox *lir);
     void visitNewDeclEnvObject(LNewDeclEnvObject *lir);
     void visitNewCallObject(LNewCallObject *lir);
     void visitNewSingletonCallObject(LNewSingletonCallObject *lir);
     void visitNewStringObject(LNewStringObject *lir);
     void visitNewDerivedTypedObject(LNewDerivedTypedObject *lir);
     void visitInitElem(LInitElem *lir);
     void visitInitElemGetterSetter(LInitElemGetterSetter *lir);
     void visitMutateProto(LMutateProto *lir);
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -780,16 +780,17 @@ class IonBuilder
     InliningStatus inlineTypedArrayLength(CallInfo &callInfo);
 
     // TypedObject intrinsics and natives.
     InliningStatus inlineObjectIsTypeDescr(CallInfo &callInfo);
     InliningStatus inlineSetTypedObjectOffset(CallInfo &callInfo);
     bool elementAccessIsTypedObjectArrayOfScalarType(MDefinition* obj, MDefinition* id,
                                                      ScalarTypeDescr::Type *arrayType);
     InliningStatus inlineConstructTypedObject(CallInfo &callInfo, TypeDescr *target);
+    InliningStatus inlineConstructSimdObject(CallInfo &callInfo, SimdTypeDescr *target);
 
     // Utility intrinsics.
     InliningStatus inlineIsCallable(CallInfo &callInfo);
     InliningStatus inlineIsObject(CallInfo &callInfo);
     InliningStatus inlineToObject(CallInfo &callInfo);
     InliningStatus inlineToInteger(CallInfo &callInfo);
     InliningStatus inlineToString(CallInfo &callInfo);
     InliningStatus inlineDump(CallInfo &callInfo);
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -130,16 +130,38 @@ class LMoveGroup : public LInstructionHe
     size_t numMoves() const {
         return moves_.length();
     }
     const LMove &getMove(size_t i) const {
         return moves_[i];
     }
 };
 
+
+// Constructs a SIMD object (value type) based on the MIRType of its input.
+class LSimdBox : public LInstructionHelper<1, 1, 1>
+{
+  public:
+    LIR_HEADER(SimdBox)
+
+    explicit LSimdBox(const LAllocation &simd, const LDefinition &temp)
+    {
+        setOperand(0, simd);
+        setTemp(0, temp);
+    }
+
+    const LDefinition *temp() {
+        return getTemp(0);
+    }
+
+    MSimdBox *mir() const {
+        return mir_->toSimdBox();
+    }
+};
+
 // Constructs a SIMD value with 4 equal components (e.g. int32x4, float32x4).
 class LSimdSplatX4 : public LInstructionHelper<1, 1, 0>
 {
   public:
     LIR_HEADER(SimdSplatX4)
     explicit LSimdSplatX4(const LAllocation &v)
     {
         setOperand(0, v);
--- a/js/src/jit/LOpcodes.h
+++ b/js/src/jit/LOpcodes.h
@@ -12,16 +12,17 @@
     _(Nop)                          \
     _(Mop)                          \
     _(OsiPoint)                     \
     _(MoveGroup)                    \
     _(Integer)                      \
     _(Pointer)                      \
     _(Double)                       \
     _(Float32)                      \
+    _(SimdBox)                      \
     _(SimdSplatX4)                  \
     _(Int32x4)                      \
     _(Float32x4)                    \
     _(SimdExtractElementI)          \
     _(SimdExtractElementF)          \
     _(SimdInsertElementI)           \
     _(SimdInsertElementF)           \
     _(SimdSignMaskX4)               \
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -3724,16 +3724,27 @@ LIRGenerator::visitRecompileCheck(MRecom
 void
 LIRGenerator::visitMemoryBarrier(MMemoryBarrier *ins)
 {
     LMemoryBarrier *lir = new(alloc()) LMemoryBarrier(ins->type());
     add(lir, ins);
 }
 
 void
+LIRGenerator::visitSimdBox(MSimdBox *ins)
+{
+    MOZ_ASSERT(IsSimdType(ins->input()->type()));
+    LUse in = useRegister(ins->input());
+    LSimdBox *lir = new(alloc()) LSimdBox(in, temp());
+    // :TODO: Cannot spill SIMD registers (Bug 1112164)
+    assignSnapshot(lir, Bailout_Inevitable);
+    define(lir, ins);
+}
+
+void
 LIRGenerator::visitSimdConstant(MSimdConstant *ins)
 {
     MOZ_ASSERT(IsSimdType(ins->type()));
 
     if (ins->type() == MIRType_Int32x4)
         define(new(alloc()) LInt32x4(), ins);
     else if (ins->type() == MIRType_Float32x4)
         define(new(alloc()) LFloat32x4(), ins);
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -260,16 +260,17 @@ class LIRGenerator : public LIRGenerator
     void visitAsmJSVoidReturn(MAsmJSVoidReturn *ins);
     void visitAsmJSPassStackArg(MAsmJSPassStackArg *ins);
     void visitAsmJSCall(MAsmJSCall *ins);
     void visitSetDOMProperty(MSetDOMProperty *ins);
     void visitGetDOMProperty(MGetDOMProperty *ins);
     void visitGetDOMMember(MGetDOMMember *ins);
     void visitRecompileCheck(MRecompileCheck *ins);
     void visitMemoryBarrier(MMemoryBarrier *ins);
+    void visitSimdBox(MSimdBox *ins);
     void visitSimdExtractElement(MSimdExtractElement *ins);
     void visitSimdInsertElement(MSimdInsertElement *ins);
     void visitSimdSignMask(MSimdSignMask *ins);
     void visitSimdSwizzle(MSimdSwizzle *ins);
     void visitSimdShuffle(MSimdShuffle *ins);
     void visitSimdUnaryArith(MSimdUnaryArith *ins);
     void visitSimdBinaryComp(MSimdBinaryComp *ins);
     void visitSimdBinaryBitwise(MSimdBinaryBitwise *ins);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -290,16 +290,19 @@ IonBuilder::InliningStatus
 IonBuilder::inlineNonFunctionCall(CallInfo &callInfo, JSObject *target)
 {
     // Inline a call to a non-function object, invoking the object's call or
     // construct hook.
 
     if (callInfo.constructing() && target->constructHook() == TypedObject::construct)
         return inlineConstructTypedObject(callInfo, &target->as<TypeDescr>());
 
+    if (!callInfo.constructing() && target->callHook() == SimdTypeDescr::call)
+        return inlineConstructSimdObject(callInfo, &target->as<SimdTypeDescr>());
+
     return InliningStatus_NotInlined;
 }
 
 types::TemporaryTypeSet *
 IonBuilder::getInlineReturnTypeSet()
 {
     return bytecodeTypes(pc);
 }
@@ -2507,10 +2510,61 @@ IonBuilder::inlineConstructTypedObject(C
     MNewTypedObject *ins = MNewTypedObject::New(alloc(), constraints(), templateObject,
                                                 templateObject->type()->initialHeap(constraints()));
     current->add(ins);
     current->push(ins);
 
     return InliningStatus_Inlined;
 }
 
+IonBuilder::InliningStatus
+IonBuilder::inlineConstructSimdObject(CallInfo &callInfo, SimdTypeDescr *descr)
+{
+    if (callInfo.argc() == 1)
+        return InliningStatus_NotInlined;
+
+    // Generic constructor of SIMD valuesX4.
+    MIRType simdType;
+    switch (descr->type()) {
+      case SimdTypeDescr::TYPE_INT32:
+        simdType = MIRType_Int32x4;
+        break;
+      case SimdTypeDescr::TYPE_FLOAT32:
+        simdType = MIRType_Float32x4;
+        break;
+      default:
+        MOZ_CRASH("Unknown SIMD kind when generating MSimdBox instruction.");
+        return InliningStatus_NotInlined;
+    }
+
+    // We do not inline SIMD constructors if the number of arguments does not
+    // match the number of lanes.
+    if (SimdTypeToLength(simdType) != callInfo.argc())
+        return InliningStatus_NotInlined;
+
+    // Take the templateObject out of Baseline ICs, such that we can box
+    // SIMD value type in the same kind of objects.
+    MOZ_ASSERT(size_t(descr->size(descr->type())) < InlineTypedObject::MaximumSize);
+    JSObject *templateObject = inspector->getTemplateObjectForClassHook(pc, descr->getClass());
+    if (!templateObject)
+        return InliningStatus_NotInlined;
+
+    // The previous assertion ensures this will never fail if we were able to
+    // allocate a templateObject in Baseline.
+    InlineTypedObject *inlineTypedObject = &templateObject->as<InlineTypedObject>();
+    MOZ_ASSERT(&inlineTypedObject->typeDescr() == descr);
+
+    MSimdValueX4 *values = MSimdValueX4::New(alloc(), simdType,
+                                             callInfo.getArg(0), callInfo.getArg(1),
+                                             callInfo.getArg(2), callInfo.getArg(3));
+    current->add(values);
+
+    MSimdBox *obj = MSimdBox::New(alloc(), constraints(), values, inlineTypedObject,
+                                  inlineTypedObject->type()->initialHeap(constraints()));
+    current->add(obj);
+    current->push(obj);
+
+    callInfo.setImplicitlyUsedUnchecked();
+    return InliningStatus_Inlined;
+}
+
 } // namespace jit
 } // namespace js
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -1314,43 +1314,50 @@ class MConstant : public MNullaryInstruc
     bool canProduceFloat32() const;
 
     ALLOW_CLONE(MConstant)
 };
 
 // Generic constructor of SIMD valuesX4.
 class MSimdValueX4
   : public MQuaternaryInstruction,
-    public NoTypePolicy::Data
+    public Mix4Policy<SimdScalarPolicy<0>, SimdScalarPolicy<1>,
+                      SimdScalarPolicy<2>, SimdScalarPolicy<3> >::Data
 {
   protected:
     MSimdValueX4(MIRType type, MDefinition *x, MDefinition *y, MDefinition *z, MDefinition *w)
       : MQuaternaryInstruction(x, y, z, w)
     {
         MOZ_ASSERT(IsSimdType(type));
         MOZ_ASSERT(SimdTypeToLength(type) == 4);
-        mozilla::DebugOnly<MIRType> scalarType = SimdTypeToScalarType(type);
-        MOZ_ASSERT(scalarType == x->type());
-        MOZ_ASSERT(scalarType == y->type());
-        MOZ_ASSERT(scalarType == z->type());
-        MOZ_ASSERT(scalarType == w->type());
 
         setMovable();
         setResultType(type);
     }
 
   public:
     INSTRUCTION_HEADER(SimdValueX4)
 
     static MSimdValueX4 *New(TempAllocator &alloc, MIRType type, MDefinition *x,
                              MDefinition *y, MDefinition *z, MDefinition *w)
     {
         return new(alloc) MSimdValueX4(type, x, y, z, w);
     }
 
+    static MSimdValueX4 *NewAsmJS(TempAllocator &alloc, MIRType type, MDefinition *x,
+                                  MDefinition *y, MDefinition *z, MDefinition *w)
+    {
+        mozilla::DebugOnly<MIRType> scalarType = SimdTypeToScalarType(type);
+        MOZ_ASSERT(scalarType == x->type());
+        MOZ_ASSERT(scalarType == y->type());
+        MOZ_ASSERT(scalarType == z->type());
+        MOZ_ASSERT(scalarType == w->type());
+        return MSimdValueX4::New(alloc, type, x, y, z, w);
+    }
+
     bool canConsumeFloat32(MUse *use) const {
         return SimdTypeToScalarType(type()) == MIRType_Float32;
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
@@ -2900,16 +2907,66 @@ class MTypedObjectDescr
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 };
 
+// Generic way for constructing a SIMD object in IonMonkey, this instruction
+// takes as argument a SIMD instruction and returns a new SIMD object which
+// corresponds to the MIRType of its operand.
+class MSimdBox
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+  protected:
+    AlwaysTenured<InlineTypedObject *> templateObject_;
+    gc::InitialHeap initialHeap_;
+
+    MSimdBox(types::CompilerConstraintList *constraints,
+             MDefinition *op,
+             InlineTypedObject *templateObject,
+             gc::InitialHeap initialHeap)
+      : MUnaryInstruction(op),
+        templateObject_(templateObject),
+        initialHeap_(initialHeap)
+    {
+        MOZ_ASSERT(IsSimdType(op->type()));
+        setMovable();
+        setResultType(MIRType_Object);
+        setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
+    }
+
+  public:
+    INSTRUCTION_HEADER(SimdBox)
+
+    static MSimdBox *New(TempAllocator &alloc,
+                         types::CompilerConstraintList *constraints,
+                         MDefinition *op,
+                         InlineTypedObject *templateObject,
+                         gc::InitialHeap initialHeap)
+    {
+        return new(alloc) MSimdBox(constraints, op, templateObject, initialHeap);
+    }
+
+    InlineTypedObject *templateObject() const {
+        return templateObject_;
+    }
+
+    gc::InitialHeap initialHeap() const {
+        return initialHeap_;
+    }
+
+    AliasSet getAliasSet() const {
+        return AliasSet::None();
+    }
+};
+
 // Creates a new derived type object. At runtime, this is just a call
 // to `BinaryBlock::createDerived()`. That is, the MIR itself does not
 // compile to particularly optimized code. However, using a distinct
 // MIR for creating derived type objects allows the compiler to
 // optimize ephemeral typed objects as would be created for a
 // reference like `a.b.c` -- here, the `a.b` will create an ephemeral
 // derived type object that aliases the memory of `a` itself. The
 // specific nature of `a.b` is revealed by using
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -7,16 +7,17 @@
 #ifndef jit_MOpcodes_h
 #define jit_MOpcodes_h
 
 namespace js {
 namespace jit {
 
 #define MIR_OPCODE_LIST(_)                                                  \
     _(Constant)                                                             \
+    _(SimdBox)                                                              \
     _(SimdValueX4)                                                          \
     _(SimdSplatX4)                                                          \
     _(SimdConstant)                                                         \
     _(SimdConvert)                                                          \
     _(SimdReinterpretCast)                                                  \
     _(SimdExtractElement)                                                   \
     _(SimdInsertElement)                                                    \
     _(SimdSignMask)                                                         \
--- a/js/src/jit/TypePolicy.cpp
+++ b/js/src/jit/TypePolicy.cpp
@@ -517,16 +517,46 @@ NoFloatPolicyAfter<FirstOp>::adjustInput
     return true;
 }
 
 template bool NoFloatPolicyAfter<1>::adjustInputs(TempAllocator &alloc, MInstruction *def);
 template bool NoFloatPolicyAfter<2>::adjustInputs(TempAllocator &alloc, MInstruction *def);
 
 template <unsigned Op>
 bool
+SimdScalarPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
+{
+    MOZ_ASSERT(IsSimdType(ins->type()));
+    MIRType scalarType = SimdTypeToScalarType(ins->type());
+
+    MDefinition *in = ins->getOperand(Op);
+    if (in->type() == scalarType)
+        return true;
+
+    MInstruction *replace;
+    if (scalarType == MIRType_Int32) {
+        replace = MTruncateToInt32::New(alloc, in);
+    } else {
+        MOZ_ASSERT(scalarType == MIRType_Float32);
+        replace = MToFloat32::New(alloc, in);
+    }
+
+    ins->block()->insertBefore(ins, replace);
+    ins->replaceOperand(Op, replace);
+
+    return replace->typePolicy()->adjustInputs(alloc, replace);
+}
+
+template bool SimdScalarPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
+template bool SimdScalarPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
+template bool SimdScalarPolicy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
+template bool SimdScalarPolicy<3>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
+
+template <unsigned Op>
+bool
 BoxPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
 {
     MDefinition *in = ins->getOperand(Op);
     if (in->type() == MIRType_Value)
         return true;
 
     ins->replaceOperand(Op, BoxAt(alloc, ins, in));
     return true;
@@ -992,16 +1022,17 @@ FilterTypeSetPolicy::adjustInputs(TempAl
     _(Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, ObjectPolicy<2> >)      \
     _(Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, BoxPolicy<2> >)         \
     _(Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2> >)         \
     _(Mix3Policy<ObjectPolicy<0>, ObjectPolicy<1>, IntPolicy<2> >)      \
     _(Mix3Policy<StringPolicy<0>, IntPolicy<1>, IntPolicy<2>>)          \
     _(Mix3Policy<StringPolicy<0>, ObjectPolicy<1>, StringPolicy<2> >)   \
     _(Mix3Policy<StringPolicy<0>, StringPolicy<1>, StringPolicy<2> >)   \
     _(Mix4Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2>, IntPolicy<3>>) \
+    _(Mix4Policy<SimdScalarPolicy<0>, SimdScalarPolicy<1>, SimdScalarPolicy<2>, SimdScalarPolicy<3> >) \
     _(MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >)                        \
     _(MixPolicy<ConvertToStringPolicy<0>, ConvertToStringPolicy<1> >)   \
     _(MixPolicy<ConvertToStringPolicy<0>, ObjectPolicy<1> >)            \
     _(MixPolicy<DoublePolicy<0>, DoublePolicy<1> >)                     \
     _(MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >)                        \
     _(MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<1> >)            \
     _(MixPolicy<ObjectPolicy<0>, IntPolicy<1> >)                        \
     _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<1> >)                    \
--- a/js/src/jit/TypePolicy.h
+++ b/js/src/jit/TypePolicy.h
@@ -299,16 +299,29 @@ class ObjectPolicy MOZ_FINAL : public Ty
         return staticAdjustInputs(alloc, ins);
     }
 };
 
 // Single-object input. If the input is a Value, it is unboxed. If it is
 // a primitive, we use ValueToNonNullObject.
 typedef ObjectPolicy<0> SingleObjectPolicy;
 
+// Convert an operand to have a type identical to the scalar type of the
+// returned type of the instruction.
+template <unsigned Op>
+class SimdScalarPolicy MOZ_FINAL : public TypePolicy
+{
+  public:
+    EMPTY_DATA_;
+    static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def) MOZ_OVERRIDE {
+        return staticAdjustInputs(alloc, def);
+    }
+};
+
 template <unsigned Op>
 class BoxPolicy MOZ_FINAL : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
     virtual bool adjustInputs(TempAllocator &alloc, MInstruction *ins) MOZ_OVERRIDE {
         return staticAdjustInputs(alloc, ins);