Bug 943769 Part 2 -- Set up SIMD inlining infrastructure r=nmatsakis
authorHaitao Feng <haitao.feng@intel.com>
Tue, 04 Mar 2014 20:06:26 -0500
changeset 171821 7efaabf97f0cc5b22f4b789af7807056f5d9a537
parent 171820 3194cb1d73f6a269f114b84f5e5fcf4a8b835806
child 171822 780785bdec58e105c1774da0edaed9c98f04ad3c
push id40586
push usernmatsakis@mozilla.com
push dateWed, 05 Mar 2014 01:09:37 +0000
treeherdermozilla-inbound@7efaabf97f0c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnmatsakis
bugs943769
milestone30.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 943769 Part 2 -- Set up SIMD inlining infrastructure r=nmatsakis
js/src/jit/IonBuilder.h
js/src/jit/IonTypes.h
js/src/jit/MCallOptimize.cpp
js/src/jit/MIR.cpp
js/src/jit/MIR.h
js/src/jit/MOpcodes.h
js/src/jit/ParallelSafetyAnalysis.cpp
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -151,17 +151,17 @@ class IonBuilder : public MIRGenerator
                 jsbytecode *exitpc;
 
                 // Deferred break and continue targets.
                 DeferredEdge *breaks;
 
                 // MIR instruction
                 MTableSwitch *ins;
 
-                // The number of current successor that get mapped into a block. 
+                // The number of current successor that get mapped into a block.
                 uint32_t currentBlock;
 
             } tableswitch;
             struct {
                 // Vector of body blocks to process after the cases.
                 FixedList<MBasicBlock *> *bodies;
 
                 // When processing case statements, this counter points at the
@@ -644,16 +644,20 @@ class IonBuilder : public MIRGenerator
     InliningStatus inlineMathHypot(CallInfo &callInfo);
     InliningStatus inlineMathMinMax(CallInfo &callInfo, bool max);
     InliningStatus inlineMathPow(CallInfo &callInfo);
     InliningStatus inlineMathRandom(CallInfo &callInfo);
     InliningStatus inlineMathImul(CallInfo &callInfo);
     InliningStatus inlineMathFRound(CallInfo &callInfo);
     InliningStatus inlineMathFunction(CallInfo &callInfo, MMathFunction::Function function);
 
+    // SIMD natives.
+    InliningStatus checkSIMDArgs(CallInfo &callInfo, const MIRType *argumentTypes);
+    InliningStatus inlineSIMDFunction(CallInfo &callInfo, uint32_t id, uint32_t argumentCount);
+
     // String natives.
     InliningStatus inlineStringObject(CallInfo &callInfo);
     InliningStatus inlineStringSplit(CallInfo &callInfo);
     InliningStatus inlineStrCharCodeAt(CallInfo &callInfo);
     InliningStatus inlineStrFromCharCode(CallInfo &callInfo);
     InliningStatus inlineStrCharAt(CallInfo &callInfo);
     InliningStatus inlineStrReplace(CallInfo &callInfo);
 
--- a/js/src/jit/IonTypes.h
+++ b/js/src/jit/IonTypes.h
@@ -159,16 +159,19 @@ ValueTypeFromMIRType(MIRType type)
       return JSVAL_TYPE_INT32;
     case MIRType_Float32: // Fall through, there's no JSVAL for Float32
     case MIRType_Double:
       return JSVAL_TYPE_DOUBLE;
     case MIRType_String:
       return JSVAL_TYPE_STRING;
     case MIRType_Magic:
       return JSVAL_TYPE_MAGIC;
+    case MIRType_Float32x4:
+    case MIRType_Int32x4:
+      return JSVAL_TYPE_OBJECT;
     default:
       JS_ASSERT(type == MIRType_Object);
       return JSVAL_TYPE_OBJECT;
   }
 }
 
 static inline JSValueTag
 MIRTypeToTag(MIRType type)
@@ -189,16 +192,20 @@ StringFromMIRType(MIRType type)
     case MIRType_Int32:
       return "Int32";
     case MIRType_Double:
       return "Double";
     case MIRType_Float32:
       return "Float32";
     case MIRType_String:
       return "String";
+    case MIRType_Float32x4:
+      return "Float32x4";
+    case MIRType_Int32x4:
+      return "Int32x4";
     case MIRType_Object:
       return "Object";
     case MIRType_Magic:
       return "Magic";
     case MIRType_Value:
       return "Value";
     case MIRType_None:
       return "None";
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 #include "jsmath.h"
 
+#include "builtin/SIMD.h"
 #include "builtin/TestingFunctions.h"
 #include "jit/BaselineInspector.h"
 #include "jit/IonBuilder.h"
 #include "jit/Lowering.h"
 #include "jit/MIR.h"
 #include "jit/MIRGraph.h"
 
 #include "jsscriptinlines.h"
@@ -103,16 +104,67 @@ IonBuilder::inlineNativeCall(CallInfo &c
         return inlineMathFunction(callInfo, MMathFunction::ATanH);
     if (native == js::math_sign)
         return inlineMathFunction(callInfo, MMathFunction::Sign);
     if (native == js::math_trunc)
         return inlineMathFunction(callInfo, MMathFunction::Trunc);
     if (native == js::math_cbrt)
         return inlineMathFunction(callInfo, MMathFunction::Cbrt);
 
+    // SIMD natives.
+#define INLINE_FLOAT32X4_NULLARY_FUNCTION(Name, Func, Operands, Flags, MIRId)            \
+    if (native == js::simd_float32x4_##Name)                                             \
+        return inlineSIMDFunction(callInfo, MSIMDNullaryFunction::Float32x4##MIRId, 0);
+FLOAT32X4_NULLARY_FUNCTION_LIST(INLINE_FLOAT32X4_NULLARY_FUNCTION)
+#undef INLINE_FLOAT32X4_NULLARY_FUNCTION
+#define INLINE_INT32X4_NULLARY_FUNCTION(Name, Func, Operands, Flags, MIRId)              \
+    if (native == js::simd_int32x4_##Name)                                               \
+        return inlineSIMDFunction(callInfo, MSIMDNullaryFunction::Int32x4##MIRId, 0);
+INT32X4_NULLARY_FUNCTION_LIST(INLINE_INT32X4_NULLARY_FUNCTION)
+#undef INLINE_INT32X4_NULLARY_FUNCTION
+
+#define INLINE_FLOAT32X4_UNARY_FUNCTION(Name, Func, Operands, Flags, MIRId)              \
+    if (native == js::simd_float32x4_##Name)                                             \
+        return inlineSIMDFunction(callInfo, MSIMDUnaryFunction::Float32x4##MIRId, 1);
+FLOAT32X4_UNARY_FUNCTION_LIST(INLINE_FLOAT32X4_UNARY_FUNCTION)
+#undef INLINE_FLOAT32X4_UNARY_FUNCTION
+#define INLINE_INT32X4_UNARY_FUNCTION(Name, Func, Operands, Flags, MIRId)                \
+    if (native == js::simd_int32x4_##Name)                                               \
+        return inlineSIMDFunction(callInfo, MSIMDUnaryFunction::Int32x4##MIRId, 1);
+INT32X4_UNARY_FUNCTION_LIST(INLINE_INT32X4_UNARY_FUNCTION)
+#undef INLINE_INT32X4_UNARY_FUNCTION
+
+#define INLINE_FLOAT32X4_BINARY_FUNCTION(Name, Func, Operands, Flags, MIRId)             \
+    if (native == js::simd_float32x4_##Name)                                             \
+        return inlineSIMDFunction(callInfo, MSIMDBinaryFunction::Float32x4##MIRId, 2);
+FLOAT32X4_BINARY_FUNCTION_LIST(INLINE_FLOAT32X4_BINARY_FUNCTION)
+#undef INLINE_FLOAT32X4_BINARY_FUNCTION
+#define INLINE_INT32X4_BINARY_FUNCTION(Name, Func, Operands, Flags, MIRId)               \
+    if (native == js::simd_int32x4_##Name)                                               \
+        return inlineSIMDFunction(callInfo, MSIMDBinaryFunction::Int32x4##MIRId, 2);
+INT32X4_BINARY_FUNCTION_LIST(INLINE_INT32X4_BINARY_FUNCTION)
+#undef INLINE_INT32X4_BINARY_FUNCTION
+
+#define INLINE_FLOAT32X4_TERNARY_FUNCTION(Name, Func, Operands, Flags, MIRId)            \
+    if (native == js::simd_float32x4_##Name)                                             \
+        return inlineSIMDFunction(callInfo, MSIMDTernaryFunction::Float32x4##MIRId, 3);
+FLOAT32X4_TERNARY_FUNCTION_LIST(INLINE_FLOAT32X4_TERNARY_FUNCTION)
+#undef INLINE_FLOAT32X4_TERNARY_FUNCTION
+#define INLINE_INT32X4_TERNARY_FUNCTION(Name, Func, Operands, Flags, MIRId)              \
+    if (native == js::simd_int32x4_##Name)                                               \
+        return inlineSIMDFunction(callInfo, MSIMDTernaryFunction::Int32x4##MIRId, 3);
+INT32X4_TERNARY_FUNCTION_LIST(INLINE_INT32X4_TERNARY_FUNCTION)
+#undef INLINE_INT32X4_TERNARY_FUNCTION
+
+#define INLINE_INT32X4_QUARTERNARY_FUNCTION(Name, Func, Operands, Flags, MIRId)          \
+    if (native == js::simd_int32x4_##Name)                                               \
+        return inlineSIMDFunction(callInfo, MSIMDQuarternaryFunction::Int32x4##MIRId, 4);
+INT32X4_QUARTERNARY_FUNCTION_LIST(INLINE_INT32X4_QUARTERNARY_FUNCTION)
+#undef INLINE_INT32X4_QUARTERNARY_FUNCTION
+
     // String natives.
     if (native == js_String)
         return inlineStringObject(callInfo);
     if (native == js::str_split)
         return inlineStringSplit(callInfo);
     if (native == js_str_charCodeAt)
         return inlineStrCharCodeAt(callInfo);
     if (native == js::str_fromCharCode)
@@ -212,16 +264,110 @@ IonBuilder::inlineMathFunction(CallInfo 
 
     MMathFunction *ins = MMathFunction::New(alloc(), callInfo.getArg(0), function, cache);
     current->add(ins);
     current->push(ins);
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
+IonBuilder::checkSIMDArgs(CallInfo &callInfo, const MIRType *argumentTypes)
+{
+    for (uint32_t i = 0; i < callInfo.argc(); i++) {
+        MDefinition *arg = callInfo.getArg(i);
+        MIRType type = argumentTypes[i];
+        switch (type) {
+          case MIRType_Float32x4:
+          case MIRType_Int32x4:
+            // SIMDTypePolicy will do the type check and un-box the typed object.
+            break;
+
+          case MIRType_Int32:
+          case MIRType_Float32:
+            if (!IsNumberType(arg->type()))
+                return InliningStatus_NotInlined;
+            break;
+
+          default:
+            MOZ_ASSUME_UNREACHABLE("Unknown SIMD MIR Type");
+        }
+    }
+    return InliningStatus_Inlined;
+}
+
+IonBuilder::InliningStatus
+IonBuilder::inlineSIMDFunction(CallInfo &callInfo, uint32_t id, uint32_t argumentCount)
+{
+    if (callInfo.constructing())
+        return InliningStatus_NotInlined;
+
+    if (callInfo.argc() != argumentCount)
+        return InliningStatus_NotInlined;
+
+    if (getInlineReturnType() != MIRType_Object)
+        return InliningStatus_NotInlined;
+
+    MIRType *argumentTypes = nullptr;
+    switch (argumentCount) {
+      case 0:
+        break;
+      case 1:
+        argumentTypes = &MSIMDUnaryFunction::ArgumentTypes[id];
+        break;
+      case 2:
+        argumentTypes = MSIMDBinaryFunction::ArgumentTypes[id];
+        break;
+      case 3:
+        argumentTypes = MSIMDTernaryFunction::ArgumentTypes[id];
+        break;
+      case 4:
+        argumentTypes = MSIMDQuarternaryFunction::ArgumentTypes[id];
+        break;
+      default:
+        MOZ_ASSUME_UNREACHABLE("Unknown SIMD function argument count");
+    }
+    InliningStatus s = checkSIMDArgs(callInfo, argumentTypes);
+    if (s != InliningStatus_Inlined)
+        return s;
+
+    callInfo.setImplicitlyUsedUnchecked();
+
+    MInstruction *ins = nullptr;
+    switch (argumentCount) {
+      case 0:
+        ins = MSIMDNullaryFunction::New(alloc(), static_cast<MSIMDNullaryFunction::Id>(id));
+        break;
+      case 1:
+        ins = MSIMDUnaryFunction::New(alloc(), callInfo.getArg(0),
+                                      static_cast<MSIMDUnaryFunction::Id>(id));
+        break;
+      case 2:
+        ins = MSIMDBinaryFunction::New(alloc(), callInfo.getArg(0), callInfo.getArg(1),
+                                       static_cast<MSIMDBinaryFunction::Id>(id));
+        break;
+      case 3:
+        ins = MSIMDTernaryFunction::New(alloc(), callInfo.getArg(0),
+                                        callInfo.getArg(1), callInfo.getArg(2),
+                                        static_cast<MSIMDTernaryFunction::Id>(id));
+        break;
+      case 4:
+        ins = MSIMDQuarternaryFunction::New(alloc(), callInfo.getArg(0), callInfo.getArg(1),
+                                            callInfo.getArg(2), callInfo.getArg(3),
+                                            static_cast<MSIMDQuarternaryFunction::Id>(id));
+        break;
+      default:
+        MOZ_ASSUME_UNREACHABLE("Unknown SIMD function argument count");
+    }
+
+    current->add(ins);
+    current->push(ins);
+    return InliningStatus_Inlined;
+}
+
+IonBuilder::InliningStatus
 IonBuilder::inlineArray(CallInfo &callInfo)
 {
     uint32_t initLength = 0;
     MNewArray::AllocatingBehaviour allocating = MNewArray::NewArray_Unallocating;
 
     JSObject *templateObject = inspector->getTemplateObjectForNative(pc, js_Array);
     if (!templateObject)
         return InliningStatus_NotInlined;
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -8,16 +8,17 @@
 
 #include "mozilla/FloatingPoint.h"
 
 #include <ctype.h>
 
 #include "jslibmath.h"
 #include "jsstr.h"
 
+#include "builtin/SIMD.h"
 #include "jit/BaselineInspector.h"
 #include "jit/IonBuilder.h"
 #include "jit/IonSpewer.h"
 #include "jit/MIRGraph.h"
 #include "jit/RangeAnalysis.h"
 
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
@@ -619,16 +620,126 @@ MMathFunction::FunctionName(Function fun
 
 void
 MMathFunction::printOpcode(FILE *fp) const
 {
     MDefinition::printOpcode(fp);
     fprintf(fp, " %s", FunctionName(function()));
 }
 
+const char *MSIMDNullaryFunction::Names[] = {
+#define MSIMD_NULLARY_FUNCTION_NAME_TYPE(Id, Name, ReturnType) "SIMD." Name,
+        MSIMD_NULLARY_FUNCTION_LIST(MSIMD_NULLARY_FUNCTION_NAME_TYPE)
+#undef MSIMD_NULLARY_FUNCTION_NAME_TYPE
+        ""
+};
+
+MIRType MSIMDNullaryFunction::ReturnTypes[] = {
+#define MSIMD_NULLARY_FUNCTION_RETURN_TYPE(Id, Name, ReturnType) ReturnType,
+        MSIMD_NULLARY_FUNCTION_LIST(MSIMD_NULLARY_FUNCTION_RETURN_TYPE)
+#undef MSIMD_NULLARY_FUNCTION_RETURN_TYPE
+        MIRType_None
+};
+
+const char *MSIMDUnaryFunction::Names[] = {
+#define MSIMD_UNARY_FUNCTION_NAME_TYPE(Id, Name, ReturnType, ArgumentType)    \
+        "SIMD." Name,
+        MSIMD_UNARY_FUNCTION_LIST(MSIMD_UNARY_FUNCTION_NAME_TYPE)
+#undef MSIMD_UNARY_FUNCTION_NAME_TYPE
+        ""
+};
+
+MIRType MSIMDUnaryFunction::ReturnTypes[] = {
+#define MSIMD_UNARY_FUNCTION_RETURN_TYPE(Id, Name, ReturnType, ArgumentType)    \
+        ReturnType,
+        MSIMD_UNARY_FUNCTION_LIST(MSIMD_UNARY_FUNCTION_RETURN_TYPE)
+#undef MSIMD_UNARY_FUNCTION_RETURN_TYPE
+        MIRType_None
+};
+
+MIRType MSIMDUnaryFunction::ArgumentTypes[] = {
+#define MSIMD_UNARY_FUNCTION_ARGUMENT_TYPE(Id, Name, ReturnType, ArgumentType)  \
+        ArgumentType,
+        MSIMD_UNARY_FUNCTION_LIST(MSIMD_UNARY_FUNCTION_ARGUMENT_TYPE)
+#undef MSIMD_UNARY_FUNCTION_ARGUMENT_TYPE
+        MIRType_None
+};
+
+const char *MSIMDBinaryFunction::Names[] = {
+#define MSIMD_BINARY_FUNCTION_NAME_TYPE(Id, Name, ReturnType, Argument1Type, Argument2Type)       \
+        "SIMD." Name,
+        MSIMD_BINARY_FUNCTION_LIST(MSIMD_BINARY_FUNCTION_NAME_TYPE)
+#undef MSIMD_BINARY_FUNCTION_NAME_TYPE
+        ""
+};
+
+MIRType MSIMDBinaryFunction::ReturnTypes[] = {
+#define MSIMD_BINARY_FUNCTION_RETURN_TYPE(Id, Name, ReturnType, Argument1Type, Argument2Type)       \
+        ReturnType,
+        MSIMD_BINARY_FUNCTION_LIST(MSIMD_BINARY_FUNCTION_RETURN_TYPE)
+#undef MSIMD_BINARY_FUNCTION_RETURN_TYPE
+        MIRType_None
+};
+
+MIRType MSIMDBinaryFunction::ArgumentTypes[][2] = {
+#define MSIMD_BINARY_FUNCTION_ARGUMENTS_TYPE(Id, Name, ReturnType, Argument1Type, Argument2Type)    \
+        {Argument1Type, Argument2Type},
+        MSIMD_BINARY_FUNCTION_LIST(MSIMD_BINARY_FUNCTION_ARGUMENTS_TYPE)
+#undef MSIMD_BINARY_FUNCTION_ARGUMENTS_TYPE
+        {MIRType_None, MIRType_None}
+};
+
+const char *MSIMDTernaryFunction::Names[] = {
+#define MSIMD_TERNARY_FUNCTION_NAME_TYPE(Id, Name, ReturnType, Argument1Type, Argument2Type, Argument3Type)       \
+        "SIMD." Name,
+        MSIMD_TERNARY_FUNCTION_LIST(MSIMD_TERNARY_FUNCTION_NAME_TYPE)
+#undef MSIMD_TERNARY_FUNCTION_NAME_TYPE
+        ""
+};
+
+MIRType MSIMDTernaryFunction::ReturnTypes[] = {
+#define MSIMD_TERNARY_FUNCTION_RETURN_TYPE(Id, Name, ReturnType, Argument1Type, Argument2Type, Argument3Type)       \
+        ReturnType,
+        MSIMD_TERNARY_FUNCTION_LIST(MSIMD_TERNARY_FUNCTION_RETURN_TYPE)
+#undef MSIMD_TERNARY_FUNCTION_RETURN_TYPE
+        MIRType_None
+};
+
+MIRType MSIMDTernaryFunction::ArgumentTypes[][3] = {
+#define MSIMD_TERNARY_FUNCTION_ARGUMENTS_TYPE(Id, Name, ReturnType, Argument1Type, Argument2Type, Argument3Type)    \
+        {Argument1Type, Argument2Type, Argument3Type},
+        MSIMD_TERNARY_FUNCTION_LIST(MSIMD_TERNARY_FUNCTION_ARGUMENTS_TYPE)
+#undef MSIMD_TERNARY_FUNCTION_ARGUMENTS_TYPE
+        {MIRType_None, MIRType_None, MIRType_None}
+};
+
+const char *MSIMDQuarternaryFunction::Names[] = {
+#define MSIMD_QUARTERNARY_FUNCTION_NAME_TYPE(Id, Name, ReturnType, Argument1Type, Argument2Type, Argument3Type, Argument4Type)       \
+        "SIMD." Name,
+        MSIMD_QUARTERNARY_FUNCTION_LIST(MSIMD_QUARTERNARY_FUNCTION_NAME_TYPE)
+#undef MSIMD_QUARTERNARY_FUNCTION_NAME_TYPE
+        ""
+};
+
+MIRType MSIMDQuarternaryFunction::ReturnTypes[] = {
+#define MSIMD_QUARTERNARY_FUNCTION_RETURN_TYPE(Id, Name, ReturnType, Argument1Type, Argument2Type, Argument3Type, Argument4Type)       \
+        ReturnType,
+        MSIMD_QUARTERNARY_FUNCTION_LIST(MSIMD_QUARTERNARY_FUNCTION_RETURN_TYPE)
+#undef MSIMD_QUARTERNARY_FUNCTION_RETURN_TYPE
+        MIRType_None
+};
+
+MIRType MSIMDQuarternaryFunction::ArgumentTypes[][4] = {
+#define MSIMD_QUARTERNARY_FUNCTION_ARGUMENTS_TYPE(Id, Name, ReturnType, Argument1Type, Argument2Type, Argument3Type, Argument4Type)    \
+        {Argument1Type, Argument2Type, Argument3Type, Argument4Type},
+        MSIMD_QUARTERNARY_FUNCTION_LIST(MSIMD_QUARTERNARY_FUNCTION_ARGUMENTS_TYPE)
+#undef MSIMD_QUARTERNARY_FUNCTION_ARGUMENTS_TYPE
+        {MIRType_None, MIRType_None, MIRType_None, MIRType_None}
+};
+
 MParameter *
 MParameter::New(TempAllocator &alloc, int32_t index, types::TemporaryTypeSet *types)
 {
     return new(alloc) MParameter(index, types);
 }
 
 void
 MParameter::printOpcode(FILE *fp) const
@@ -891,17 +1002,17 @@ MUnbox::printOpcode(FILE *fp) const
 
 void
 MTypeBarrier::printOpcode(FILE *fp) const
 {
     PrintOpcodeName(fp, op());
     fprintf(fp, " ");
     getOperand(0)->printName(fp);
 }
- 
+
 void
 MPhi::removeOperand(size_t index)
 {
     MUse *use = getUseFor(index);
 
     JS_ASSERT(index < inputs_.length());
     JS_ASSERT(inputs_.length() > 1);
 
@@ -2439,17 +2550,17 @@ MCompare::evaluateConstantOperands(bool 
     Value lhs = left->toConstant()->value();
     Value rhs = right->toConstant()->value();
 
     // Fold away some String equality comparisons.
     if (lhs.isString() && rhs.isString()) {
         int32_t comp = 0; // Default to equal.
         if (left != right)
             comp = CompareAtoms(&lhs.toString()->asAtom(), &rhs.toString()->asAtom());
-        
+
         switch (jsop_) {
           case JSOP_LT:
             *result = (comp < 0);
             break;
           case JSOP_LE:
             *result = (comp <= 0);
             break;
           case JSOP_GT:
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -3931,16 +3931,293 @@ class MMathFunction
 
     bool isFloat32Commutative() const {
         return function_ == Floor || function_ == Ceil || function_ == Round;
     }
     void trySpecializeFloat32(TempAllocator &alloc);
     void computeRange(TempAllocator &alloc);
 };
 
+#define DECLARE_COMMON_SIMD_FUNCTION(opcode)                        \
+    static MIRType ReturnTypes[];                                   \
+    static const char *Names[];                                     \
+    Id id() const {                                                 \
+        return id_;                                                 \
+    }                                                               \
+    bool congruentTo(MDefinition *ins) const {                      \
+        if (!ins->is##opcode())                                     \
+            return false;                                           \
+        if (ins->to##opcode()->id() != id())                        \
+            return false;                                           \
+        return congruentIfOperandsEqual(ins);                       \
+    }                                                               \
+    AliasSet getAliasSet() const {                                  \
+        return AliasSet::None();                                    \
+    }                                                               \
+    bool possiblyCalls() const {                                    \
+        return true;                                                \
+    }                                                               \
+    void printOpcode(FILE *fp) const {                              \
+        MDefinition::printOpcode(fp);                               \
+        fprintf(fp, " %s", Names[id()]);                            \
+    }
+
+#define MSIMD_NULLARY_FUNCTION_LIST(V)                              \
+  V(Float32x4Zero, "float32x4.zero", MIRType_Float32x4)             \
+  V(Int32x4Zero, "int32x4.zero", MIRType_Int32x4)
+
+class MSIMDNullaryFunction
+  : public MNullaryInstruction
+{
+  public:
+    enum Id {
+#define MSIMD_NULLARY_FUNCTION_ID(Id, Name, Type) Id,
+        MSIMD_NULLARY_FUNCTION_LIST(MSIMD_NULLARY_FUNCTION_ID)
+        NUMBER_OF_IDS
+#undef MSIMD_NULLARY_FUNCTION_ID
+    };
+
+  private:
+    Id id_;
+
+    MSIMDNullaryFunction(Id id)
+      : MNullaryInstruction(), id_(id)
+    {
+        setMovable();
+        setResultType(ReturnTypes[id]);
+    }
+
+  public:
+    INSTRUCTION_HEADER(SIMDNullaryFunction)
+    DECLARE_COMMON_SIMD_FUNCTION(SIMDNullaryFunction)
+    static MSIMDNullaryFunction *New(TempAllocator &alloc, Id id)
+    {
+        return new(alloc) MSIMDNullaryFunction(id);
+    }
+};
+
+#define MSIMD_UNARY_FUNCTION_LIST(V)                                                            \
+  V(Float32x4Abs, "float32x4.abs", MIRType_Float32x4, MIRType_Float32x4)                        \
+  V(Float32x4BitsToInt32x4, "float32x4.bitstoInt32x4", MIRType_Int32x4, MIRType_Float32x4)      \
+  V(Float32x4Neg, "float32x4.neg", MIRType_Float32x4, MIRType_Float32x4)                        \
+  V(Float32x4Reciprocal, "float32x4.reciprocal", MIRType_Float32x4, MIRType_Float32x4)          \
+  V(Float32x4ReciprocalSqrt, "float32x4.reciprocalSqrt", MIRType_Float32x4, MIRType_Float32x4)  \
+  V(Float32x4Splat, "float32x4.splat", MIRType_Float32x4, MIRType_Float32)                      \
+  V(Float32x4Sqrt, "float32x4.sqrt", MIRType_Float32x4, MIRType_Float32x4)                      \
+  V(Float32x4ToInt32x4, "float32x4.toInt32x4", MIRType_Int32x4, MIRType_Float32x4)              \
+  V(Float32x4GetX, "float32x4.getX", MIRType_Float32, MIRType_Float32x4)                        \
+  V(Float32x4GetY, "float32x4.getY", MIRType_Float32, MIRType_Float32x4)                        \
+  V(Float32x4GetZ, "float32x4.getZ", MIRType_Float32, MIRType_Float32x4)                        \
+  V(Float32x4GetW, "float32x4.getW", MIRType_Float32, MIRType_Float32x4)                        \
+  V(Float32x4GetSignMask, "float32x4.getSignMask", MIRType_Int32, MIRType_Float32x4)            \
+  V(Int32x4BitsToFloat32x4, "int32x4.bitsToFloat32x4", MIRType_Float32x4, MIRType_Int32x4)      \
+  V(Int32x4Neg, "int32x4.neg", MIRType_Int32x4, MIRType_Int32x4)                                \
+  V(Int32x4Not, "int32x4.not", MIRType_Int32x4, MIRType_Int32x4)                                \
+  V(Int32x4Splat, "int32x4.splat", MIRType_Int32x4, MIRType_Int32)                              \
+  V(Int32x4ToFloat32x4, "int32x4.toFloat32x4", MIRType_Float32x4, MIRType_Int32x4)              \
+  V(Int32x4GetX, "int32x4.getX", MIRType_Int32, MIRType_Int32x4)                                \
+  V(Int32x4GetY, "int32x4.getY", MIRType_Int32, MIRType_Int32x4)                                \
+  V(Int32x4GetZ, "int32x4.getZ", MIRType_Int32, MIRType_Int32x4)                                \
+  V(Int32x4GetW, "int32x4.getW", MIRType_Int32, MIRType_Int32x4)                                \
+  V(Int32x4GetSignMask, "int32x4.getSignMask", MIRType_Int32, MIRType_Int32x4)                  \
+  V(Int32x4GetFlagX, "int32x4.getFlagX", MIRType_Boolean, MIRType_Int32x4)                      \
+  V(Int32x4GetFlagY, "int32x4.getFlagY", MIRType_Boolean, MIRType_Int32x4)                      \
+  V(Int32x4GetFlagZ, "int32x4.getFlagZ", MIRType_Boolean, MIRType_Int32x4)                      \
+  V(Int32x4GetFlagW, "int32x4.getFlagW", MIRType_Boolean, MIRType_Int32x4)
+
+class MSIMDUnaryFunction
+  : public MUnaryInstruction
+{
+  public:
+    enum Id {
+#define MSIMD_UNARY_FUNCTION_ID(Id, Name, ReturnType, ArgumentType) Id,
+        MSIMD_UNARY_FUNCTION_LIST(MSIMD_UNARY_FUNCTION_ID)
+        NUMBER_OF_IDS
+#undef MSIMD_UNARY_FUNCTION_ID
+    };
+
+    static MIRType ArgumentTypes[];
+
+  private:
+    Id id_;
+
+    MSIMDUnaryFunction(MDefinition *argument, Id id)
+      : MUnaryInstruction(argument), id_(id)
+    {
+        setMovable();
+        setResultType(ReturnTypes[id]);
+    }
+
+  public:
+    INSTRUCTION_HEADER(SIMDUnaryFunction)
+    DECLARE_COMMON_SIMD_FUNCTION(SIMDUnaryFunction)
+    static MSIMDUnaryFunction *New(TempAllocator &alloc, MDefinition *argument, Id id)
+    {
+        return new(alloc) MSIMDUnaryFunction(argument, id);
+    }
+    bool canProduceFloat32() const {
+        return type() == MIRType_Float32;
+    }
+    bool canConsumeFloat32(MUse *use) const {
+        return id() == Float32x4Splat;
+    }
+#ifdef DEBUG
+    bool isConsistentFloat32Use(MUse *use) const { return canProduceFloat32() || canConsumeFloat32(use); }
+#endif
+};
+
+#define MSIMD_BINARY_FUNCTION_LIST(V)                                                                                   \
+  V(Float32x4Add, "float32x4.add", MIRType_Float32x4, MIRType_Float32x4, MIRType_Float32x4)                             \
+  V(Float32x4Div, "float32x4.div", MIRType_Float32x4, MIRType_Float32x4, MIRType_Float32x4)                             \
+  V(Float32x4Equal, "float32x4.equal", MIRType_Int32x4, MIRType_Float32x4, MIRType_Float32x4)                           \
+  V(Float32x4GreaterThan, "float32x4.greaterThan", MIRType_Int32x4, MIRType_Float32x4, MIRType_Float32x4)               \
+  V(Float32x4GreaterThanOrEqual, "float32x4.greaterThanOrEqual", MIRType_Int32x4, MIRType_Float32x4, MIRType_Float32x4) \
+  V(Float32x4LessThan, "float32x4.lessThan", MIRType_Int32x4, MIRType_Float32x4, MIRType_Float32x4)                     \
+  V(Float32x4LessThanOrEqual, "float32x4.lessThanOrEqual", MIRType_Int32x4, MIRType_Float32x4, MIRType_Float32x4)       \
+  V(Float32x4Max, "float32x4.max", MIRType_Float32x4, MIRType_Float32x4, MIRType_Float32x4)                             \
+  V(Float32x4Min, "float32x4.min", MIRType_Float32x4, MIRType_Float32x4, MIRType_Float32x4)                             \
+  V(Float32x4Mul, "float32x4.mul", MIRType_Float32x4, MIRType_Float32x4, MIRType_Float32x4)                             \
+  V(Float32x4NotEqual, "float32x4.notEqual", MIRType_Int32x4, MIRType_Float32x4, MIRType_Float32x4)                     \
+  V(Float32x4Shuffle, "float32x4.shuffle", MIRType_Float32x4, MIRType_Float32x4, MIRType_Int32)                         \
+  V(Float32x4Scale, "float32x4.scale", MIRType_Float32x4, MIRType_Float32x4, MIRType_Float32)                           \
+  V(Float32x4Sub, "float32x4.sub", MIRType_Float32x4, MIRType_Float32x4, MIRType_Float32x4)                             \
+  V(Float32x4WithX, "float32x4.withX", MIRType_Float32x4, MIRType_Float32x4, MIRType_Float32)                           \
+  V(Float32x4WithY, "float32x4.withY", MIRType_Float32x4, MIRType_Float32x4, MIRType_Float32)                           \
+  V(Float32x4WithZ, "float32x4.withZ", MIRType_Float32x4, MIRType_Float32x4, MIRType_Float32)                           \
+  V(Float32x4WithW, "float32x4.withW", MIRType_Float32x4, MIRType_Float32x4, MIRType_Float32)                           \
+  V(Int32x4Add, "int32x4.add", MIRType_Int32x4, MIRType_Int32x4, MIRType_Int32x4)                                       \
+  V(Int32x4And, "int32x4.and", MIRType_Int32x4, MIRType_Int32x4, MIRType_Int32x4)                                       \
+  V(Int32x4Mul, "int32x4.mul", MIRType_Int32x4, MIRType_Int32x4, MIRType_Int32x4)                                       \
+  V(Int32x4Or, "int32x4.or", MIRType_Int32x4, MIRType_Int32x4, MIRType_Int32x4)                                         \
+  V(Int32x4Sub, "int32x4.sub", MIRType_Int32x4, MIRType_Int32x4, MIRType_Int32x4)                                       \
+  V(Int32x4Shuffle, "int32x4.shuffle", MIRType_Int32x4, MIRType_Int32x4, MIRType_Int32)                                 \
+  V(Int32x4WithFlagX, "int32x4.withFlagX", MIRType_Int32x4, MIRType_Int32x4, MIRType_Boolean)                           \
+  V(Int32x4WithFlagY, "int32x4.withFlagY", MIRType_Int32x4, MIRType_Int32x4, MIRType_Boolean)                           \
+  V(Int32x4WithFlagZ, "int32x4.withFlagZ", MIRType_Int32x4, MIRType_Int32x4, MIRType_Boolean)                           \
+  V(Int32x4WithFlagW, "int32x4.withFlagW", MIRType_Int32x4, MIRType_Int32x4, MIRType_Boolean)                           \
+  V(Int32x4WithX, "int32x4.withX", MIRType_Int32x4, MIRType_Int32x4, MIRType_Int32)                                     \
+  V(Int32x4WithY, "int32x4.withY", MIRType_Int32x4, MIRType_Int32x4, MIRType_Int32)                                     \
+  V(Int32x4WithZ, "int32x4.withZ", MIRType_Int32x4, MIRType_Int32x4, MIRType_Int32)                                     \
+  V(Int32x4WithW, "int32x4.withW", MIRType_Int32x4, MIRType_Int32x4, MIRType_Int32)                                     \
+  V(Int32x4Xor, "int32x4.xor", MIRType_Int32x4, MIRType_Int32x4, MIRType_Int32x4)
+
+class MSIMDBinaryFunction
+  : public MBinaryInstruction
+{
+  public:
+    enum Id {
+#define MSIMD_BINARY_FUNCTION_ID(Id, Name, Type, Argument1Type, Argument2Type) Id,
+        MSIMD_BINARY_FUNCTION_LIST(MSIMD_BINARY_FUNCTION_ID)
+        NUMBER_OF_IDS
+#undef MSIMD_BINARY_FUNCTION_ID
+    };
+
+    static MIRType ArgumentTypes[][2];
+
+  private:
+    Id id_;
+
+    MSIMDBinaryFunction(MDefinition *left, MDefinition *right, Id id)
+      : MBinaryInstruction(left, right), id_(id)
+    {
+        setMovable();
+        setResultType(ReturnTypes[id]);
+    }
+
+  public:
+    INSTRUCTION_HEADER(SIMDBinaryFunction)
+    DECLARE_COMMON_SIMD_FUNCTION(SIMDBinaryFunction)
+    static MSIMDBinaryFunction *New(TempAllocator &alloc, MDefinition *left, MDefinition *right, Id id)
+    {
+        return new(alloc) MSIMDBinaryFunction(left, right, id);
+    }
+    bool canConsumeFloat32(MUse *use) const {
+        return id() == Float32x4Scale || id() == Float32x4WithX || id() == Float32x4WithY ||
+               id() == Float32x4WithZ || id() == Float32x4WithW;
+    }
+#ifdef DEBUG
+    bool isConsistentFloat32Use(MUse *use) const {
+        return canConsumeFloat32(use);
+    }
+#endif
+};
+
+#define MSIMD_TERNARY_FUNCTION_LIST(V)                                                                                      \
+  V(Float32x4Clamp, "float32x4.clamp", MIRType_Float32x4, MIRType_Float32x4, MIRType_Float32x4, MIRType_Float32x4)          \
+  V(Float32x4ShuffleMix, "float32x4.shuffleMix", MIRType_Float32x4, MIRType_Float32x4, MIRType_Float32x4, MIRType_Int32)    \
+  V(Int32x4Select, "int32x4.select", MIRType_Float32x4, MIRType_Int32x4, MIRType_Float32x4, MIRType_Float32x4)              \
+  V(Int32x4ShuffleMix, "int32x4.shuffleMix", MIRType_Int32x4, MIRType_Int32x4, MIRType_Int32x4, MIRType_Int32)
+
+class MSIMDTernaryFunction
+  : public MTernaryInstruction
+{
+  public:
+    enum Id {
+#define MSIMD_TERNARY_FUNCTION_ID(Id, Name, Type, Argument1Type, Argument2Type, Argument3Type) Id,
+        MSIMD_TERNARY_FUNCTION_LIST(MSIMD_TERNARY_FUNCTION_ID)
+        NUMBER_OF_IDS
+#undef MSIMD_TERNARY_FUNCTION_ID
+    };
+
+    static MIRType ArgumentTypes[][3];
+
+  private:
+    Id id_;
+
+    MSIMDTernaryFunction(MDefinition *first, MDefinition *second, MDefinition *third, Id id)
+      : MTernaryInstruction(first, second, third), id_(id)
+    {
+        setMovable();
+        setResultType(ReturnTypes[id]);
+    }
+
+  public:
+    INSTRUCTION_HEADER(SIMDTernaryFunction)
+    DECLARE_COMMON_SIMD_FUNCTION(SIMDTernaryFunction)
+    static MSIMDTernaryFunction *New(TempAllocator &alloc, MDefinition *first, MDefinition *second, MDefinition *third, Id id)
+    {
+        return new(alloc) MSIMDTernaryFunction(first, second, third, id);
+    }
+};
+
+#define MSIMD_QUARTERNARY_FUNCTION_LIST(V)                                                                              \
+  V(Int32x4Bool, "int32x4.bool", MIRType_Int32x4, MIRType_Boolean, MIRType_Boolean, MIRType_Boolean, MIRType_Boolean)
+
+class MSIMDQuarternaryFunction
+  : public MQuaternaryInstruction
+{
+  public:
+    enum Id {
+#define MSIMD_QUARTERNARY_FUNCTION_ID(Id, Name, Type, Argument1Type, Argument2Type, Argument3Type, Argument4Type) Id,
+        MSIMD_QUARTERNARY_FUNCTION_LIST(MSIMD_QUARTERNARY_FUNCTION_ID)
+        NUMBER_OF_IDS
+#undef MSIMD_QUARTERNARY_FUNCTION_ID
+    };
+
+    static MIRType ArgumentTypes[][4];
+
+  private:
+    Id id_;
+
+    MSIMDQuarternaryFunction(MDefinition *first, MDefinition *second, MDefinition *third, MDefinition *fourth, Id id)
+      : MQuaternaryInstruction(first, second, third, fourth), id_(id)
+    {
+        setMovable();
+        setResultType(ReturnTypes[id]);
+    }
+
+  public:
+    INSTRUCTION_HEADER(SIMDQuarternaryFunction)
+    DECLARE_COMMON_SIMD_FUNCTION(SIMDQuarternaryFunction)
+    static MSIMDQuarternaryFunction *New(TempAllocator &alloc, MDefinition *first, MDefinition *second, MDefinition *third, MDefinition *fourth, Id id)
+    {
+        return new(alloc) MSIMDQuarternaryFunction(first, second, third, fourth, id);
+    }
+};
+
 class MAdd : public MBinaryArithInstruction
 {
     // Is this instruction really an int at heart?
     MAdd(MDefinition *left, MDefinition *right)
       : MBinaryArithInstruction(left, right)
     {
         setResultType(MIRType_Value);
     }
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -58,16 +58,21 @@ namespace jit {
     _(Abs)                                                                  \
     _(Sqrt)                                                                 \
     _(Atan2)                                                                \
     _(Hypot)                                                                \
     _(Pow)                                                                  \
     _(PowHalf)                                                              \
     _(Random)                                                               \
     _(MathFunction)                                                         \
+    _(SIMDNullaryFunction)                                                  \
+    _(SIMDUnaryFunction)                                                    \
+    _(SIMDBinaryFunction)                                                   \
+    _(SIMDTernaryFunction)                                                  \
+    _(SIMDQuarternaryFunction)                                              \
     _(Add)                                                                  \
     _(Sub)                                                                  \
     _(Mul)                                                                  \
     _(Div)                                                                  \
     _(Mod)                                                                  \
     _(Concat)                                                               \
     _(ConcatPar)                                                            \
     _(CharCodeAt)                                                           \
--- a/js/src/jit/ParallelSafetyAnalysis.cpp
+++ b/js/src/jit/ParallelSafetyAnalysis.cpp
@@ -153,16 +153,21 @@ class ParallelSafetyVisitor : public MIn
     SAFE_OP(Rsh)
     SAFE_OP(Ursh)
     SPECIALIZED_OP(MinMax, PERMIT_NUMERIC)
     SAFE_OP(Abs)
     SAFE_OP(Sqrt)
     UNSAFE_OP(Atan2)
     UNSAFE_OP(Hypot)
     CUSTOM_OP(MathFunction)
+    SAFE_OP(SIMDNullaryFunction)
+    SAFE_OP(SIMDUnaryFunction)
+    SAFE_OP(SIMDBinaryFunction)
+    SAFE_OP(SIMDTernaryFunction)
+    SAFE_OP(SIMDQuarternaryFunction)
     SPECIALIZED_OP(Add, PERMIT_NUMERIC)
     SPECIALIZED_OP(Sub, PERMIT_NUMERIC)
     SPECIALIZED_OP(Mul, PERMIT_NUMERIC)
     SPECIALIZED_OP(Div, PERMIT_NUMERIC)
     SPECIALIZED_OP(Mod, PERMIT_NUMERIC)
     CUSTOM_OP(Concat)
     SAFE_OP(ConcatPar)
     UNSAFE_OP(CharCodeAt)