Bug 1135039: Generalize swizzle MIR node to SimdGeneralShuffle; r=sunfish
authorBenjamin Bouvier <benj@benj.me>
Wed, 18 Mar 2015 20:07:45 +0100
changeset 263608 bcad11e292db400d298c4732793c6580e7ece25d
parent 263607 12c2f0b35afed34eed6c632dfc3cb0678b7218fb
child 263609 71a8d6e735ef718ea9aed9d29e4153907c8a3e10
push id4718
push userraliiev@mozilla.com
push dateMon, 11 May 2015 18:39:53 +0000
treeherdermozilla-beta@c20c4ef55f08 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssunfish
bugs1135039
milestone39.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 1135039: Generalize swizzle MIR node to SimdGeneralShuffle; r=sunfish
js/src/asmjs/AsmJSValidate.cpp
js/src/builtin/SIMD.h
js/src/jit-test/tests/SIMD/shuffle.js
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.cpp
js/src/jit/MIR.h
js/src/jit/MOpcodes.h
js/src/jit/TypePolicy.cpp
js/src/jit/TypePolicy.h
js/src/jit/arm/CodeGenerator-arm.h
js/src/jit/mips/CodeGenerator-mips.h
js/src/jit/shared/CodeGenerator-x86-shared.cpp
js/src/jit/shared/CodeGenerator-x86-shared.h
--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -2727,28 +2727,28 @@ class FunctionCompiler
     }
 
     MDefinition *swizzleSimd(MDefinition *vector, int32_t X, int32_t Y, int32_t Z, int32_t W,
                              MIRType type)
     {
         if (inDeadCode())
             return nullptr;
 
-        MSimdSwizzle *ins = MSimdSwizzle::NewAsmJS(alloc(), vector, type, X, Y, Z, W);
+        MSimdSwizzle *ins = MSimdSwizzle::New(alloc(), vector, type, X, Y, Z, W);
         curBlock_->add(ins);
         return ins;
     }
 
     MDefinition *shuffleSimd(MDefinition *lhs, MDefinition *rhs, int32_t X, int32_t Y,
                              int32_t Z, int32_t W, MIRType type)
     {
         if (inDeadCode())
             return nullptr;
 
-        MInstruction *ins = MSimdShuffle::NewAsmJS(alloc(), lhs, rhs, type, X, Y, Z, W);
+        MInstruction *ins = MSimdShuffle::New(alloc(), lhs, rhs, type, X, Y, Z, W);
         curBlock_->add(ins);
         return ins;
     }
 
     MDefinition *insertElementSimd(MDefinition *vec, MDefinition *val, SimdLane lane, MIRType type)
     {
         if (inDeadCode())
             return nullptr;
--- a/js/src/builtin/SIMD.h
+++ b/js/src/builtin/SIMD.h
@@ -237,23 +237,23 @@
     BITWISE_COMMONX4_SIMD_OP(_)      \
     WITH_COMMONX4_SIMD_OP(_)         \
     _(bitselect)                     \
     _(select)                        \
     _(splat)                         \
     _(not)                           \
     _(neg)                           \
     _(swizzle)                       \
+    _(shuffle)                       \
     _(load)                          \
     _(store)                         \
     _(check)
 #define FOREACH_COMMONX4_SIMD_OP(_)  \
     ION_COMMONX4_SIMD_OP(_)          \
     COMP_COMMONX4_TO_INT32X4_SIMD_OP(_) \
-    _(shuffle)                       \
     _(loadX)                         \
     _(loadXY)                        \
     _(loadXYZ)                       \
     _(storeX)                        \
     _(storeXY)                       \
     _(storeXYZ)
 #define FORALL_SIMD_OP(_)            \
     FOREACH_INT32X4_SIMD_OP(_)       \
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/SIMD/shuffle.js
@@ -0,0 +1,81 @@
+if (!this.hasOwnProperty("SIMD"))
+  quit();
+
+load(libdir + 'simd.js');
+
+setJitCompilerOption("ion.warmup.trigger", 50);
+
+function f() {
+    var i1 = SIMD.int32x4(1, 2, 3, 4);
+    var i2 = SIMD.int32x4(5, 6, 7, 8);
+
+    var leet = Math.fround(13.37);
+    var f1 = SIMD.float32x4(-.5, -0, Infinity, leet);
+    var f2 = SIMD.float32x4(42, .5, 23, -10);
+
+    // computes all rotations of a given array
+    function *gen(arr) {
+        var previous = arr.slice().splice(0, 4);
+        var i = 4;
+        for (var j = 0; j < 8; j++) {
+            yield previous.slice();
+            previous = previous.splice(1, previous.length - 1);
+            previous.push(arr[i]);
+            i = (i + 1) % arr.length;
+        }
+    }
+
+    var compI = [];
+    for (var k of gen([i1.x, i1.y, i1.z, i1.w, i2.x, i2.y, i2.z, i2.w]))
+        compI.push(k);
+
+    var compF = [];
+    for (var k of gen([f1.x, f1.y, f1.z, f1.w, f2.x, f2.y, f2.z, f2.w]))
+        compF.push(k);
+
+    for (var i = 0; i < 150; i++) {
+        // Variable lanes
+        var r = SIMD.float32x4.shuffle(f1, f2, i % 8, (i + 1) % 8, (i + 2) % 8, (i + 3) % 8);
+        assertEqX4(r, compF[i % 8]);
+
+        // Constant lanes
+        assertEqX4(SIMD.float32x4.shuffle(f1, f2, 3, 2, 4, 5), [leet, Infinity, 42, .5]);
+
+        // Variable lanes
+        var r = SIMD.int32x4.shuffle(i1, i2, i % 8, (i + 1) % 8, (i + 2) % 8, (i + 3) % 8);
+        assertEqX4(r, compI[i % 8]);
+
+        // Constant lanes
+        assertEqX4(SIMD.int32x4.shuffle(i1, i2, 3, 2, 4, 5), [4, 3, 5, 6]);
+    }
+}
+
+function testBailouts(uglyDuckling) {
+    var i1 = SIMD.int32x4(1, 2, 3, 4);
+    var i2 = SIMD.int32x4(5, 6, 7, 8);
+
+    for (var i = 0; i < 150; i++) {
+        // Test bailouts
+        var value = i == 149 ? uglyDuckling : 3;
+        var caught = false;
+        try {
+            assertEqX4(SIMD.int32x4.shuffle(i1, i2, value, 2, 4, 5), [4, 3, 5, 6]);
+        } catch(e) {
+            print(e);
+            caught = true;
+            assertEq(i, 149);
+            assertEq(e instanceof TypeError, true);
+        }
+        assertEq(i < 149 || caught, true);
+    }
+}
+
+f();
+testBailouts(-1);
+testBailouts(8);
+testBailouts(2.5);
+testBailouts(undefined);
+testBailouts(null);
+testBailouts({});
+testBailouts('one');
+testBailouts(true);
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -827,17 +827,18 @@ class IonBuilder
                                     typename T::Operation op, SimdTypeDescr::Type type);
     InliningStatus inlineCompSimd(CallInfo &callInfo, JSNative native,
                                   MSimdBinaryComp::Operation op, SimdTypeDescr::Type compType);
     InliningStatus inlineUnarySimd(CallInfo &callInfo, JSNative native,
                                    MSimdUnaryArith::Operation op, SimdTypeDescr::Type type);
     InliningStatus inlineSimdWith(CallInfo &callInfo, JSNative native, SimdLane lane,
                                   SimdTypeDescr::Type type);
     InliningStatus inlineSimdSplat(CallInfo &callInfo, JSNative native, SimdTypeDescr::Type type);
-    InliningStatus inlineSimdSwizzle(CallInfo &callInfo, JSNative native, SimdTypeDescr::Type type);
+    InliningStatus inlineSimdShuffle(CallInfo &callInfo, JSNative native, SimdTypeDescr::Type type,
+                                     unsigned numVectors, unsigned numLanes);
     InliningStatus inlineSimdCheck(CallInfo &callInfo, JSNative native, SimdTypeDescr::Type type);
     InliningStatus inlineSimdConvert(CallInfo &callInfo, JSNative native, bool isCast,
                                      SimdTypeDescr::Type from, SimdTypeDescr::Type to);
     InliningStatus inlineSimdSelect(CallInfo &callInfo, JSNative native, bool isElementWise,
                                     SimdTypeDescr::Type type);
 
     bool prepareForSimdLoadStore(CallInfo &callInfo, Scalar::Type simdType, MInstruction **elements,
                                  MDefinition **index, Scalar::Type *arrayType);
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -369,56 +369,53 @@ class LSimdSwizzleI : public LSimdSwizzl
 class LSimdSwizzleF : public LSimdSwizzleBase
 {
   public:
     LIR_HEADER(SimdSwizzleF);
     explicit LSimdSwizzleF(const LAllocation &base) : LSimdSwizzleBase(base)
     {}
 };
 
-class LSimdGeneralSwizzleBase : public LInstructionHelper<1, 5, 1>
-{
-  public:
-    LSimdGeneralSwizzleBase(const LAllocation &base, const LAllocation lanes[4],
-                            const LDefinition &temp)
-    {
-        setOperand(0, base);
-        for (size_t i = 0; i < 4; i++)
-            setOperand(1 + i, lanes[i]);
+class LSimdGeneralShuffleBase : public LVariadicInstruction<1, 1>
+{
+  public:
+    explicit LSimdGeneralShuffleBase(const LDefinition &temp) {
         setTemp(0, temp);
     }
-
-    const LAllocation *base() {
-        return getOperand(0);
-    }
-    const LAllocation *lane(size_t i) {
-        return getOperand(1 + i);
+    const LAllocation *vector(unsigned i) {
+        MOZ_ASSERT(i < mir()->numVectors());
+        return getOperand(i);
+    }
+    const LAllocation *lane(unsigned i) {
+        MOZ_ASSERT(i < mir()->numLanes());
+        return getOperand(mir()->numVectors() + i);
     }
     const LDefinition *temp() {
         return getTemp(0);
     }
-};
-
-class LSimdGeneralSwizzleI : public LSimdGeneralSwizzleBase
-{
-  public:
-    LIR_HEADER(SimdGeneralSwizzleI);
-    LSimdGeneralSwizzleI(const LAllocation &base, const LAllocation lanes[4],
-                         const LDefinition &temp)
-      : LSimdGeneralSwizzleBase(base, lanes, temp)
+    MSimdGeneralShuffle *mir() const {
+        return mir_->toSimdGeneralShuffle();
+    }
+};
+
+class LSimdGeneralShuffleI : public LSimdGeneralShuffleBase
+{
+  public:
+    LIR_HEADER(SimdGeneralShuffleI);
+    explicit LSimdGeneralShuffleI(const LDefinition &temp)
+      : LSimdGeneralShuffleBase(temp)
     {}
 };
 
-class LSimdGeneralSwizzleF : public LSimdGeneralSwizzleBase
-{
-  public:
-    LIR_HEADER(SimdGeneralSwizzleF);
-    LSimdGeneralSwizzleF(const LAllocation &base, const LAllocation lanes[4],
-                         const LDefinition &temp)
-      : LSimdGeneralSwizzleBase(base, lanes, temp)
+class LSimdGeneralShuffleF : public LSimdGeneralShuffleBase
+{
+  public:
+    LIR_HEADER(SimdGeneralShuffleF);
+    explicit LSimdGeneralShuffleF(const LDefinition &temp)
+      : LSimdGeneralShuffleBase(temp)
     {}
 };
 
 // Base class for both int32x4 and float32x4 shuffle instructions.
 class LSimdShuffle : public LInstructionHelper<1, 2, 1>
 {
   public:
     LIR_HEADER(SimdShuffle);
--- a/js/src/jit/LOpcodes.h
+++ b/js/src/jit/LOpcodes.h
@@ -23,18 +23,18 @@
     _(Int32x4)                      \
     _(Float32x4)                    \
     _(SimdReinterpretCast)          \
     _(SimdExtractElementI)          \
     _(SimdExtractElementF)          \
     _(SimdInsertElementI)           \
     _(SimdInsertElementF)           \
     _(SimdSignMaskX4)               \
-    _(SimdGeneralSwizzleI)          \
-    _(SimdGeneralSwizzleF)          \
+    _(SimdGeneralShuffleI)          \
+    _(SimdGeneralShuffleF)          \
     _(SimdSwizzleI)                 \
     _(SimdSwizzleF)                 \
     _(SimdShuffle)                  \
     _(SimdUnaryArithIx4)            \
     _(SimdUnaryArithFx4)            \
     _(SimdBinaryCompIx4)            \
     _(SimdBinaryCompFx4)            \
     _(SimdBinaryArithIx4)           \
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -3952,38 +3952,43 @@ LIRGenerator::visitSimdSwizzle(MSimdSwiz
         LSimdSwizzleF *lir = new (alloc()) LSimdSwizzleF(use);
         define(lir, ins);
     } else {
         MOZ_CRASH("Unknown SIMD kind when getting lane");
     }
 }
 
 void
-LIRGenerator::visitSimdGeneralSwizzle(MSimdGeneralSwizzle *ins)
-{
-    MOZ_ASSERT(IsSimdType(ins->input()->type()));
+LIRGenerator::visitSimdGeneralShuffle(MSimdGeneralShuffle*ins)
+{
     MOZ_ASSERT(IsSimdType(ins->type()));
 
-    LAllocation lanesUses[4];
-    for (size_t i = 0; i < 4; i++)
-        lanesUses[i] = use(ins->lane(i));
-
-    if (ins->input()->type() == MIRType_Int32x4) {
-        LSimdGeneralSwizzleI *lir = new (alloc()) LSimdGeneralSwizzleI(useRegister(ins->input()),
-                                                                       lanesUses, temp());
-        assignSnapshot(lir, Bailout_BoundsCheck);
-        define(lir, ins);
-    } else if (ins->input()->type() == MIRType_Float32x4) {
-        LSimdGeneralSwizzleF *lir = new (alloc()) LSimdGeneralSwizzleF(useRegister(ins->input()),
-                                                                       lanesUses, temp());
-        assignSnapshot(lir, Bailout_BoundsCheck);
-        define(lir, ins);
-    } else {
-        MOZ_CRASH("Unknown SIMD kind when getting lane");
+    LSimdGeneralShuffleBase *lir;
+    if (ins->type() == MIRType_Int32x4)
+        lir = new (alloc()) LSimdGeneralShuffleI(temp());
+    else if (ins->type() == MIRType_Float32x4)
+        lir = new (alloc()) LSimdGeneralShuffleF(temp());
+    else
+        MOZ_CRASH("Unknown SIMD kind when doing a shuffle");
+
+    if (!lir->init(alloc(), ins->numVectors() + ins->numLanes()))
+        return;
+
+    for (unsigned i = 0; i < ins->numVectors(); i++) {
+        MOZ_ASSERT(IsSimdType(ins->vector(i)->type()));
+        lir->setOperand(i, useRegister(ins->vector(i)));
     }
+
+    for (unsigned i = 0; i < ins->numLanes(); i++) {
+        MOZ_ASSERT(ins->lane(i)->type() == MIRType_Int32);
+        lir->setOperand(i + ins->numVectors(), useRegister(ins->lane(i)));
+    }
+
+    assignSnapshot(lir, Bailout_BoundsCheck);
+    define(lir, ins);
 }
 
 void
 LIRGenerator::visitSimdShuffle(MSimdShuffle *ins)
 {
     MOZ_ASSERT(IsSimdType(ins->lhs()->type()));
     MOZ_ASSERT(IsSimdType(ins->rhs()->type()));
     MOZ_ASSERT(IsSimdType(ins->type()));
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -264,17 +264,17 @@ class LIRGenerator : public LIRGenerator
     void visitRecompileCheck(MRecompileCheck *ins);
     void visitMemoryBarrier(MMemoryBarrier *ins);
     void visitSimdBox(MSimdBox *ins);
     void visitSimdUnbox(MSimdUnbox *ins);
     void visitSimdExtractElement(MSimdExtractElement *ins);
     void visitSimdInsertElement(MSimdInsertElement *ins);
     void visitSimdSignMask(MSimdSignMask *ins);
     void visitSimdSwizzle(MSimdSwizzle *ins);
-    void visitSimdGeneralSwizzle(MSimdGeneralSwizzle *ins);
+    void visitSimdGeneralShuffle(MSimdGeneralShuffle *ins);
     void visitSimdShuffle(MSimdShuffle *ins);
     void visitSimdUnaryArith(MSimdUnaryArith *ins);
     void visitSimdBinaryComp(MSimdBinaryComp *ins);
     void visitSimdBinaryBitwise(MSimdBinaryBitwise *ins);
     void visitSimdShift(MSimdShift *ins);
     void visitSimdConstant(MSimdConstant *ins);
     void visitSimdConvert(MSimdConvert *ins);
     void visitSimdReinterpretCast(MSimdReinterpretCast *ins);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -346,19 +346,23 @@ IonBuilder::inlineNativeCall(CallInfo &c
     if (native == js::simd_int32x4_bitselect)
         return inlineSimdSelect(callInfo, native, IsElementWise(false), SimdTypeDescr::TYPE_INT32);
     if (native == js::simd_float32x4_select)
         return inlineSimdSelect(callInfo, native, IsElementWise(true), SimdTypeDescr::TYPE_FLOAT32);
     if (native == js::simd_float32x4_bitselect)
         return inlineSimdSelect(callInfo, native, IsElementWise(false), SimdTypeDescr::TYPE_FLOAT32);
 
     if (native == js::simd_int32x4_swizzle)
-        return inlineSimdSwizzle(callInfo, native, SimdTypeDescr::TYPE_INT32);
+        return inlineSimdShuffle(callInfo, native, SimdTypeDescr::TYPE_INT32, 1, 4);
     if (native == js::simd_float32x4_swizzle)
-        return inlineSimdSwizzle(callInfo, native, SimdTypeDescr::TYPE_FLOAT32);
+        return inlineSimdShuffle(callInfo, native, SimdTypeDescr::TYPE_FLOAT32, 1, 4);
+    if (native == js::simd_int32x4_shuffle)
+        return inlineSimdShuffle(callInfo, native, SimdTypeDescr::TYPE_INT32, 2, 4);
+    if (native == js::simd_float32x4_shuffle)
+        return inlineSimdShuffle(callInfo, native, SimdTypeDescr::TYPE_FLOAT32, 2, 4);
 
     if (native == js::simd_int32x4_load)
         return inlineSimdLoad(callInfo, native, SimdTypeDescr::TYPE_INT32);
     if (native == js::simd_float32x4_load)
         return inlineSimdLoad(callInfo, native, SimdTypeDescr::TYPE_FLOAT32);
 
     if (native == js::simd_int32x4_store)
         return inlineSimdStore(callInfo, native, SimdTypeDescr::TYPE_INT32);
@@ -3108,28 +3112,34 @@ IonBuilder::inlineSimdCheck(CallInfo &ca
     current->add(unbox);
     current->push(callInfo.getArg(0));
 
     callInfo.setImplicitlyUsedUnchecked();
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
-IonBuilder::inlineSimdSwizzle(CallInfo &callInfo, JSNative native, SimdTypeDescr::Type type)
+IonBuilder::inlineSimdShuffle(CallInfo &callInfo, JSNative native, SimdTypeDescr::Type type,
+                              unsigned numVectors, unsigned numLanes)
 {
     InlineTypedObject *templateObj = nullptr;
-    if (!checkInlineSimd(callInfo, native, type, 5, &templateObj))
+    if (!checkInlineSimd(callInfo, native, type, numVectors + numLanes, &templateObj))
         return InliningStatus_NotInlined;
 
-    MDefinition *lanes[4];
-    for (size_t i = 0; i < 4; i++)
-        lanes[i] = callInfo.getArg(1 + i);
-
     MIRType mirType = SimdTypeDescrToMIRType(type);
-    MSimdGeneralSwizzle *ins = MSimdGeneralSwizzle::New(alloc(), callInfo.getArg(0), lanes, mirType);
+    MSimdGeneralShuffle *ins = MSimdGeneralShuffle::New(alloc(), numVectors, numLanes, mirType);
+
+    if (!ins->init(alloc()))
+        return InliningStatus_Error;
+
+    for (unsigned i = 0; i < numVectors; i++)
+        ins->setVector(i, callInfo.getArg(i));
+    for (size_t i = 0; i < numLanes; i++)
+        ins->setLane(i, callInfo.getArg(numVectors + i));
+
     return boxSimd(callInfo, ins, templateObj);
 }
 
 static Scalar::Type
 SimdTypeToScalarType(SimdTypeDescr::Type type)
 {
     switch (type) {
       case SimdTypeDescr::TYPE_FLOAT32: return Scalar::Float32x4;
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -960,27 +960,36 @@ MDefinition *
 MSimdSwizzle::foldsTo(TempAllocator &alloc)
 {
     if (lanesMatch(0, 1, 2, 3))
         return input();
     return this;
 }
 
 MDefinition *
-MSimdGeneralSwizzle::foldsTo(TempAllocator &alloc)
-{
-    int32_t lanes[4];
-    for (size_t i = 0; i < 4; i++) {
+MSimdGeneralShuffle::foldsTo(TempAllocator &alloc)
+{
+    FixedList<uint32_t> lanes;
+    if (!lanes.init(alloc, numLanes()))
+        return this;
+
+    for (size_t i = 0; i < numLanes(); i++) {
         if (!lane(i)->isConstant() || lane(i)->type() != MIRType_Int32)
             return this;
-        lanes[i] = lane(i)->toConstant()->value().toInt32();
-        if (lanes[i] < 0 || lanes[i] >= 4)
+        int32_t temp = lane(i)->toConstant()->value().toInt32();
+        if (temp < 0 || uint32_t(temp) >= numLanes() * numVectors())
             return this;
+        lanes[i] = uint32_t(temp);
     }
-    return MSimdSwizzle::New(alloc, input(), type(), lanes[0], lanes[1], lanes[2], lanes[3]);
+
+    if (numVectors() == 1)
+        return MSimdSwizzle::New(alloc, vector(0), type(), lanes[0], lanes[1], lanes[2], lanes[3]);
+
+    MOZ_ASSERT(numVectors() == 2);
+    return MSimdShuffle::New(alloc, vector(0), vector(1), type(), lanes[0], lanes[1], lanes[2], lanes[3]);
 }
 
 template <typename T>
 static void
 PrintOpcodeOperation(T *mir, FILE *fp)
 {
     mir->MDefinition::printOpcode(fp);
     fprintf(fp, " (%s)", T::OperationName(mir->operation()));
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -1809,22 +1809,16 @@ class MSimdSwizzle
         MOZ_ASSERT(obj->type() == type);
         setResultType(type);
         setMovable();
     }
 
   public:
     INSTRUCTION_HEADER(SimdSwizzle)
 
-    static MSimdSwizzle *NewAsmJS(TempAllocator &alloc, MDefinition *obj, MIRType type,
-                                  uint32_t laneX, uint32_t laneY, uint32_t laneZ, uint32_t laneW)
-    {
-        return new(alloc) MSimdSwizzle(obj, type, laneX, laneY, laneZ, laneW);
-    }
-
     static MSimdSwizzle *New(TempAllocator &alloc, MDefinition *obj, MIRType type,
                              uint32_t laneX, uint32_t laneY, uint32_t laneZ, uint32_t laneW)
     {
         return new(alloc) MSimdSwizzle(obj, type, laneX, laneY, laneZ, laneW);
     }
 
     bool congruentTo(const MDefinition *ins) const MOZ_OVERRIDE {
         if (!ins->isSimdSwizzle())
@@ -1837,58 +1831,83 @@ class MSimdSwizzle
         return AliasSet::None();
     }
 
     MDefinition *foldsTo(TempAllocator &alloc) MOZ_OVERRIDE;
 
     ALLOW_CLONE(MSimdSwizzle)
 };
 
-// A "general swizzle" is a swizzle with non-constant lane indices.  This is the
-// one that Ion inlines and it can be folded into a MSimdSwizzle if lane indices
-// are constant. Performance of general swizzle does not really matter, as we
-// expect to always get constant indices.
-class MSimdGeneralSwizzle :
-    public MAryInstruction<5>,
-    public SimdSwizzlePolicy::Data
-{
+// A "general swizzle" is a swizzle or a shuffle with non-constant lane
+// indices.  This is the one that Ion inlines and it can be folded into a
+// MSimdSwizzle/MSimdShuffle if lane indices are constant.  Performance of
+// general swizzle/shuffle does not really matter, as we expect to get
+// constant indices most of the time.
+class MSimdGeneralShuffle :
+    public MVariadicInstruction,
+    public SimdShufflePolicy::Data
+{
+    unsigned numVectors_;
+    unsigned numLanes_;
+
   protected:
-    MSimdGeneralSwizzle(MDefinition *vec, MDefinition *lanes[4], MIRType type)
+    MSimdGeneralShuffle(unsigned numVectors, unsigned numLanes, MIRType type)
+      : numVectors_(numVectors), numLanes_(numLanes)
     {
         MOZ_ASSERT(IsSimdType(type));
-        MOZ_ASSERT(SimdTypeToLength(type) == 4);
-
-        initOperand(0, vec);
-        for (unsigned i = 0; i < 4; i++)
-            initOperand(1 + i, lanes[i]);
+        MOZ_ASSERT(SimdTypeToLength(type) == numLanes_);
 
         setResultType(type);
         specialization_ = type;
         setMovable();
     }
 
   public:
-    INSTRUCTION_HEADER(SimdGeneralSwizzle);
-    ALLOW_CLONE(MSimdGeneralSwizzle);
-
-    static MSimdGeneralSwizzle *New(TempAllocator &alloc, MDefinition *vec, MDefinition *lanes[4],
+    INSTRUCTION_HEADER(SimdGeneralShuffle);
+
+    static MSimdGeneralShuffle *New(TempAllocator &alloc, unsigned numVectors, unsigned numLanes,
                                     MIRType type)
     {
-        return new(alloc) MSimdGeneralSwizzle(vec, lanes, type);
-    }
-
-    MDefinition *input() const {
-        return getOperand(0);
-    }
-    MDefinition *lane(size_t i) const {
-        return getOperand(1 + i);
-    }
-
-    bool congruentTo(const MDefinition *ins) const MOZ_OVERRIDE {
-        return congruentIfOperandsEqual(ins);
+        return new(alloc) MSimdGeneralShuffle(numVectors, numLanes, type);
+    }
+
+    bool init(TempAllocator &alloc) {
+        return MVariadicInstruction::init(alloc, numVectors_ + numLanes_);
+    }
+    void setVector(unsigned i, MDefinition* vec) {
+        MOZ_ASSERT(i < numVectors_);
+        initOperand(i, vec);
+    }
+    void setLane(unsigned i, MDefinition* laneIndex) {
+        MOZ_ASSERT(i < numLanes_);
+        initOperand(numVectors_ + i, laneIndex);
+    }
+
+    unsigned numVectors() const {
+        return numVectors_;
+    }
+    unsigned numLanes() const {
+        return numLanes_;
+    }
+    MDefinition *vector(unsigned i) const {
+        MOZ_ASSERT(i < numVectors_);
+        return getOperand(i);
+    }
+    MDefinition *lane(unsigned i) const {
+        MOZ_ASSERT(i < numLanes_);
+        return getOperand(numVectors_ + i);
+    }
+
+    bool congruentTo(const MDefinition *ins) const MOZ_OVERRIDE {
+        if (!ins->isSimdGeneralShuffle())
+            return false;
+        const MSimdGeneralShuffle *other = ins->toSimdGeneralShuffle();
+        return numVectors_ == other->numVectors() &&
+               numLanes_ == other->numLanes() &&
+               congruentIfOperandsEqual(other);
     }
 
     MDefinition *foldsTo(TempAllocator &alloc) MOZ_OVERRIDE;
 
     AliasSet getAliasSet() const MOZ_OVERRIDE {
         return AliasSet::None();
     }
 };
@@ -1913,35 +1932,35 @@ class MSimdShuffle
         MOZ_ASSERT(lhs->type() == type);
         setResultType(type);
         setMovable();
     }
 
   public:
     INSTRUCTION_HEADER(SimdShuffle)
 
-    static MInstruction *NewAsmJS(TempAllocator &alloc, MDefinition *lhs, MDefinition *rhs,
-                                  MIRType type, uint32_t laneX, uint32_t laneY, uint32_t laneZ,
-                                  uint32_t laneW)
+    static MInstruction *New(TempAllocator &alloc, MDefinition *lhs, MDefinition *rhs,
+                             MIRType type, uint32_t laneX, uint32_t laneY, uint32_t laneZ,
+                             uint32_t laneW)
     {
         // Swap operands so that new lanes come from LHS in majority.
         // In the balanced case, swap operands if needs be, in order to be able
         // to do only one vshufps on x86.
         unsigned lanesFromLHS = (laneX < 4) + (laneY < 4) + (laneZ < 4) + (laneW < 4);
         if (lanesFromLHS < 2 || (lanesFromLHS == 2 && laneX >= 4 && laneY >=4)) {
             laneX = (laneX + 4) % 8;
             laneY = (laneY + 4) % 8;
             laneZ = (laneZ + 4) % 8;
             laneW = (laneW + 4) % 8;
             mozilla::Swap(lhs, rhs);
         }
 
         // If all lanes come from the same vector, just use swizzle instead.
         if (laneX < 4 && laneY < 4 && laneZ < 4 && laneW < 4)
-            return MSimdSwizzle::NewAsmJS(alloc, lhs, type, laneX, laneY, laneZ, laneW);
+            return MSimdSwizzle::New(alloc, lhs, type, laneX, laneY, laneZ, laneW);
 
         return new(alloc) MSimdShuffle(lhs, rhs, type, laneX, laneY, laneZ, laneW);
     }
 
     bool congruentTo(const MDefinition *ins) const MOZ_OVERRIDE {
         if (!ins->isSimdShuffle())
             return false;
         const MSimdShuffle *other = ins->toSimdShuffle();
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -19,17 +19,17 @@ namespace jit {
     _(SimdSplatX4)                                                          \
     _(SimdConstant)                                                         \
     _(SimdConvert)                                                          \
     _(SimdReinterpretCast)                                                  \
     _(SimdExtractElement)                                                   \
     _(SimdInsertElement)                                                    \
     _(SimdSignMask)                                                         \
     _(SimdSwizzle)                                                          \
-    _(SimdGeneralSwizzle)                                                   \
+    _(SimdGeneralShuffle)                                                   \
     _(SimdShuffle)                                                          \
     _(SimdUnaryArith)                                                       \
     _(SimdBinaryComp)                                                       \
     _(SimdBinaryArith)                                                      \
     _(SimdBinaryBitwise)                                                    \
     _(SimdShift)                                                            \
     _(SimdSelect)                                                           \
     _(CloneLiteral)                                                         \
--- a/js/src/jit/TypePolicy.cpp
+++ b/js/src/jit/TypePolicy.cpp
@@ -781,33 +781,36 @@ SimdPolicy<Op>::adjustInputs(TempAllocat
 {
     return MaybeSimdUnbox(alloc, ins, ins->typePolicySpecialization(), Op);
 }
 
 template bool
 SimdPolicy<0>::adjustInputs(TempAllocator &alloc, MInstruction *ins);
 
 bool
-SimdSwizzlePolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
+SimdShufflePolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
 {
     MIRType specialization = ins->typePolicySpecialization();
 
-    // First input is the vector input.
-    if (!MaybeSimdUnbox(alloc, ins, specialization, 0))
-        return false;
+    MSimdGeneralShuffle *s = ins->toSimdGeneralShuffle();
+
+    for (unsigned i = 0; i < s->numVectors(); i++) {
+        if (!MaybeSimdUnbox(alloc, ins, specialization, i))
+            return false;
+    }
 
     // Next inputs are the lanes, which need to be int32
-    for (unsigned i = 0; i < 4; i++) {
-        MDefinition *in = ins->getOperand(i + 1);
+    for (unsigned i = 0; i < s->numLanes(); i++) {
+        MDefinition *in = ins->getOperand(s->numVectors() + i);
         if (in->type() == MIRType_Int32)
             continue;
 
         MInstruction *replace = MToInt32::New(alloc, in, MacroAssembler::IntConversion_NumbersOnly);
         ins->block()->insertBefore(ins, replace);
-        ins->replaceOperand(i + 1, replace);
+        ins->replaceOperand(s->numVectors() + i, replace);
         if (!replace->typePolicy()->adjustInputs(alloc, replace))
             return false;
     }
 
     return true;
 }
 
 bool
@@ -1110,17 +1113,17 @@ FilterTypeSetPolicy::adjustInputs(TempAl
     _(CallSetElementPolicy)                     \
     _(ClampPolicy)                              \
     _(ComparePolicy)                            \
     _(FilterTypeSetPolicy)                      \
     _(InstanceOfPolicy)                         \
     _(PowPolicy)                                \
     _(SimdAllPolicy)                            \
     _(SimdSelectPolicy)                         \
-    _(SimdSwizzlePolicy)                        \
+    _(SimdShufflePolicy)                        \
     _(StoreTypedArrayElementStaticPolicy)       \
     _(StoreTypedArrayHolePolicy)                \
     _(StoreUnboxedScalarPolicy)                 \
     _(StoreUnboxedObjectOrNullPolicy)           \
     _(TestPolicy)                               \
     _(AllDoublePolicy)                          \
     _(ToDoublePolicy)                           \
     _(ToInt32Policy)                            \
--- a/js/src/jit/TypePolicy.h
+++ b/js/src/jit/TypePolicy.h
@@ -325,17 +325,17 @@ class SimdPolicy MOZ_FINAL : public Type
 
 class SimdSelectPolicy MOZ_FINAL : public TypePolicy
 {
   public:
     SPECIALIZATION_DATA_;
     virtual bool adjustInputs(TempAllocator &alloc, MInstruction *ins) MOZ_OVERRIDE;
 };
 
-class SimdSwizzlePolicy MOZ_FINAL : public TypePolicy
+class SimdShufflePolicy MOZ_FINAL : public TypePolicy
 {
   public:
     SPECIALIZATION_DATA_;
     virtual bool adjustInputs(TempAllocator &alloc, MInstruction *ins) MOZ_OVERRIDE;
 };
 
 // SIMD value-type policy, use the returned type of the instruction to determine
 // how to unbox its operand.
--- a/js/src/jit/arm/CodeGenerator-arm.h
+++ b/js/src/jit/arm/CodeGenerator-arm.h
@@ -240,18 +240,18 @@ class CodeGeneratorARM : public CodeGene
     // Unimplemented SIMD instructions
     void visitSimdSplatX4(LSimdSplatX4 *lir) { MOZ_CRASH("NYI"); }
     void visitInt32x4(LInt32x4 *ins) { MOZ_CRASH("NYI"); }
     void visitFloat32x4(LFloat32x4 *ins) { MOZ_CRASH("NYI"); }
     void visitSimdReinterpretCast(LSimdReinterpretCast *ins) { MOZ_CRASH("NYI"); }
     void visitSimdExtractElementI(LSimdExtractElementI *ins) { MOZ_CRASH("NYI"); }
     void visitSimdExtractElementF(LSimdExtractElementF *ins) { MOZ_CRASH("NYI"); }
     void visitSimdSignMaskX4(LSimdSignMaskX4 *ins) { MOZ_CRASH("NYI"); }
-    void visitSimdGeneralSwizzleI(LSimdGeneralSwizzleI *lir) { MOZ_CRASH("NYI"); }
-    void visitSimdGeneralSwizzleF(LSimdGeneralSwizzleF *lir) { MOZ_CRASH("NYI"); }
+    void visitSimdGeneralShuffleI(LSimdGeneralShuffleI *lir) { MOZ_CRASH("NYI"); }
+    void visitSimdGeneralShuffleF(LSimdGeneralShuffleF *lir) { MOZ_CRASH("NYI"); }
     void visitSimdSwizzleI(LSimdSwizzleI *lir) { MOZ_CRASH("NYI"); }
     void visitSimdSwizzleF(LSimdSwizzleF *lir) { MOZ_CRASH("NYI"); }
     void visitSimdBinaryCompIx4(LSimdBinaryCompIx4 *lir) { MOZ_CRASH("NYI"); }
     void visitSimdBinaryCompFx4(LSimdBinaryCompFx4 *lir) { MOZ_CRASH("NYI"); }
     void visitSimdBinaryArithIx4(LSimdBinaryArithIx4 *lir) { MOZ_CRASH("NYI"); }
     void visitSimdBinaryArithFx4(LSimdBinaryArithFx4 *lir) { MOZ_CRASH("NYI"); }
     void visitSimdBinaryBitwiseX4(LSimdBinaryBitwiseX4 *lir) { MOZ_CRASH("NYI"); }
 };
--- a/js/src/jit/mips/CodeGenerator-mips.h
+++ b/js/src/jit/mips/CodeGenerator-mips.h
@@ -285,18 +285,18 @@ class CodeGeneratorMIPS : public CodeGen
     void visitSimdExtractElementI(LSimdExtractElementI *ins) { MOZ_CRASH("NYI"); }
     void visitSimdExtractElementF(LSimdExtractElementF *ins) { MOZ_CRASH("NYI"); }
     void visitSimdSignMaskX4(LSimdSignMaskX4 *ins) { MOZ_CRASH("NYI"); }
     void visitSimdBinaryCompIx4(LSimdBinaryCompIx4 *lir) { MOZ_CRASH("NYI"); }
     void visitSimdBinaryCompFx4(LSimdBinaryCompFx4 *lir) { MOZ_CRASH("NYI"); }
     void visitSimdBinaryArithIx4(LSimdBinaryArithIx4 *lir) { MOZ_CRASH("NYI"); }
     void visitSimdBinaryArithFx4(LSimdBinaryArithFx4 *lir) { MOZ_CRASH("NYI"); }
     void visitSimdBinaryBitwiseX4(LSimdBinaryBitwiseX4 *lir) { MOZ_CRASH("NYI"); }
-    void visitSimdGeneralSwizzleI(LSimdGeneralSwizzleI *lir) { MOZ_CRASH("NYI"); }
-    void visitSimdGeneralSwizzleF(LSimdGeneralSwizzleF *lir) { MOZ_CRASH("NYI"); }
+    void visitSimdGeneralShuffleI(LSimdGeneralShuffleI *lir) { MOZ_CRASH("NYI"); }
+    void visitSimdGeneralShuffleF(LSimdGeneralShuffleF *lir) { MOZ_CRASH("NYI"); }
 };
 
 typedef CodeGeneratorMIPS CodeGeneratorSpecific;
 
 // An out-of-line bailout thunk.
 class OutOfLineBailout : public OutOfLineCodeBase<CodeGeneratorMIPS>
 {
     LSnapshot *snapshot_;
--- a/js/src/jit/shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-x86-shared.cpp
@@ -2381,34 +2381,38 @@ CodeGeneratorX86Shared::visitSimdSignMas
     FloatRegister input = ToFloatRegister(ins->input());
     Register output = ToRegister(ins->output());
 
     // For Float32x4 and Int32x4.
     masm.vmovmskps(input, output);
 }
 
 void
-CodeGeneratorX86Shared::visitSimdGeneralSwizzleI(LSimdGeneralSwizzleI *ins)
+CodeGeneratorX86Shared::visitSimdGeneralShuffleI(LSimdGeneralShuffleI *ins)
 {
-    FloatRegister input = ToFloatRegister(ins->base());
+    MSimdGeneralShuffle *mir = ins->mir();
+    unsigned numVectors = mir->numVectors();
+
     Register temp = ToRegister(ins->temp());
 
     // This won't generate fast code, but it's fine because we expect users
-    // to have used constant indices (and thus MSimdGeneralSwizzle to be fold
-    // into MSimdSwizzle, which are fast).
-    masm.reserveStack(Simd128DataSize * 2);
-
-    masm.storeAlignedInt32x4(input, Address(StackPointer, Simd128DataSize));
+    // to have used constant indices (and thus MSimdGeneralShuffle to be fold
+    // into MSimdSwizzle/MSimdShuffle, which are fast).
+    masm.reserveStack(Simd128DataSize * numVectors);
+
+    for (unsigned i = 0; i < numVectors; i++)
+        masm.storeAlignedInt32x4(ToFloatRegister(ins->vector(i)),
+                                 Address(StackPointer, Simd128DataSize * (1 + i)));
 
     Label bail;
 
-    for (size_t i = 0; i < 4; i++) {
+    for (size_t i = 0; i < mir->numLanes(); i++) {
         Operand lane = ToOperand(ins->lane(i));
 
-        masm.cmp32(lane, Imm32(3));
+        masm.cmp32(lane, Imm32(mir->numVectors() * mir->numLanes() - 1));
         masm.j(Assembler::Above, &bail);
 
         if (lane.kind() == Operand::REG) {
             masm.load32(Operand(StackPointer, ToRegister(ins->lane(i)), TimesFour, Simd128DataSize),
                         temp);
         } else {
             masm.load32(lane, temp);
             masm.load32(Operand(StackPointer, temp, TimesFour, Simd128DataSize), temp);
@@ -2420,70 +2424,76 @@ CodeGeneratorX86Shared::visitSimdGeneral
     FloatRegister output = ToFloatRegister(ins->output());
     masm.loadAlignedInt32x4(Address(StackPointer, 0), output);
 
     Label join;
     masm.jump(&join);
 
     {
         masm.bind(&bail);
-        masm.freeStack(Simd128DataSize * 2);
+        masm.freeStack(Simd128DataSize * numVectors);
         bailout(ins->snapshot());
     }
 
     masm.bind(&join);
-    masm.setFramePushed(masm.framePushed() + Simd128DataSize * 2);
-    masm.freeStack(Simd128DataSize * 2);
+    masm.setFramePushed(masm.framePushed() + Simd128DataSize * numVectors);
+    masm.freeStack(Simd128DataSize * numVectors);
 }
 
 void
-CodeGeneratorX86Shared::visitSimdGeneralSwizzleF(LSimdGeneralSwizzleF *ins)
+CodeGeneratorX86Shared::visitSimdGeneralShuffleF(LSimdGeneralShuffleF *ins)
 {
-    FloatRegister input = ToFloatRegister(ins->base());
+    MSimdGeneralShuffle *mir = ins->mir();
+    unsigned numVectors = mir->numVectors();
+
     Register temp = ToRegister(ins->temp());
 
-    // See comment in the visitSimdGeneralSwizzleI.
-    masm.reserveStack(Simd128DataSize * 2);
-
-    masm.storeAlignedFloat32x4(input, Address(StackPointer, Simd128DataSize));
+    // This won't generate fast code, but it's fine because we expect users
+    // to have used constant indices (and thus MSimdGeneralShuffle to be fold
+    // into MSimdSwizzle/MSimdShuffle, which are fast).
+    masm.reserveStack(Simd128DataSize * numVectors);
+
+    for (unsigned i = 0; i < numVectors; i++)
+        masm.storeAlignedFloat32x4(ToFloatRegister(ins->vector(i)),
+                                   Address(StackPointer, Simd128DataSize * (1 + i)));
 
     Label bail;
 
-    for (size_t i = 0; i < 4; i++) {
+    for (size_t i = 0; i < mir->numLanes(); i++) {
         Operand lane = ToOperand(ins->lane(i));
 
-        masm.cmp32(lane, Imm32(3));
+        masm.cmp32(lane, Imm32(mir->numVectors() * mir->numLanes() - 1));
         masm.j(Assembler::Above, &bail);
 
         if (lane.kind() == Operand::REG) {
             masm.loadFloat32(Operand(StackPointer, ToRegister(ins->lane(i)), TimesFour, Simd128DataSize),
-                             ScratchFloat32Reg);
+                            ScratchFloat32Reg);
         } else {
             masm.load32(lane, temp);
             masm.loadFloat32(Operand(StackPointer, temp, TimesFour, Simd128DataSize), ScratchFloat32Reg);
         }
 
         masm.storeFloat32(ScratchFloat32Reg, Address(StackPointer, i * sizeof(int32_t)));
     }
 
     FloatRegister output = ToFloatRegister(ins->output());
     masm.loadAlignedFloat32x4(Address(StackPointer, 0), output);
 
     Label join;
     masm.jump(&join);
 
     {
         masm.bind(&bail);
-        masm.freeStack(Simd128DataSize * 2);
+        masm.freeStack(Simd128DataSize * numVectors);
         bailout(ins->snapshot());
     }
 
     masm.bind(&join);
-    masm.setFramePushed(masm.framePushed() + Simd128DataSize * 2);
-    masm.freeStack(Simd128DataSize * 2);
+    masm.setFramePushed(masm.framePushed() + Simd128DataSize * numVectors);
+    masm.freeStack(Simd128DataSize * numVectors);
 }
 
 void
 CodeGeneratorX86Shared::visitSimdSwizzleI(LSimdSwizzleI *ins)
 {
     FloatRegister input = ToFloatRegister(ins->input());
     FloatRegister output = ToFloatRegister(ins->output());
 
--- a/js/src/jit/shared/CodeGenerator-x86-shared.h
+++ b/js/src/jit/shared/CodeGenerator-x86-shared.h
@@ -253,18 +253,18 @@ class CodeGeneratorX86Shared : public Co
     void visitInt32x4ToFloat32x4(LInt32x4ToFloat32x4 *ins);
     void visitFloat32x4ToInt32x4(LFloat32x4ToInt32x4 *ins);
     void visitSimdReinterpretCast(LSimdReinterpretCast *lir);
     void visitSimdExtractElementI(LSimdExtractElementI *lir);
     void visitSimdExtractElementF(LSimdExtractElementF *lir);
     void visitSimdInsertElementI(LSimdInsertElementI *lir);
     void visitSimdInsertElementF(LSimdInsertElementF *lir);
     void visitSimdSignMaskX4(LSimdSignMaskX4 *ins);
-    void visitSimdGeneralSwizzleI(LSimdGeneralSwizzleI *lir);
-    void visitSimdGeneralSwizzleF(LSimdGeneralSwizzleF *lir);
+    void visitSimdGeneralShuffleI(LSimdGeneralShuffleI *lir);
+    void visitSimdGeneralShuffleF(LSimdGeneralShuffleF *lir);
     void visitSimdSwizzleI(LSimdSwizzleI *lir);
     void visitSimdSwizzleF(LSimdSwizzleF *lir);
     void visitSimdShuffle(LSimdShuffle *lir);
     void visitSimdUnaryArithIx4(LSimdUnaryArithIx4 *lir);
     void visitSimdUnaryArithFx4(LSimdUnaryArithFx4 *lir);
     void visitSimdBinaryCompIx4(LSimdBinaryCompIx4 *lir);
     void visitSimdBinaryCompFx4(LSimdBinaryCompFx4 *lir);
     void visitSimdBinaryArithIx4(LSimdBinaryArithIx4 *lir);