Bug 1160971 - Part 3: SIMD boolean vector support for JIT. r=bbouvier
authorSajjad Taheri <staheri@mozilla.com>
Tue, 22 Dec 2015 14:17:13 -0800
changeset 312552 aff94d347ecdc8965d2b9c30f3604a8b3d0ab24b
parent 312551 61ae54811bed58ac44e8493bea75634051a18a66
child 312553 739b78a0d10987c77e2b5a53b83910e53dcd48c7
push id5703
push userraliiev@mozilla.com
push dateMon, 07 Mar 2016 14:18:41 +0000
treeherdermozilla-beta@31e373ad5b5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier
bugs1160971
milestone46.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 1160971 - Part 3: SIMD boolean vector support for JIT. r=bbouvier Based on a patch by Sajjad Taheri!
js/src/builtin/SIMD.cpp
js/src/builtin/SIMD.h
js/src/jit-test/tests/SIMD/bool32x4-const.js
js/src/jit/BaselineBailouts.cpp
js/src/jit/BaselineIC.cpp
js/src/jit/CodeGenerator.cpp
js/src/jit/EagerSimdUnbox.cpp
js/src/jit/InlinableNatives.h
js/src/jit/IonAnalysis.cpp
js/src/jit/IonBuilder.cpp
js/src/jit/IonBuilder.h
js/src/jit/IonTypes.h
js/src/jit/LIR.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/Recover.cpp
js/src/jit/TypePolicy.cpp
js/src/jit/shared/CodeGenerator-shared.cpp
js/src/jit/shared/LIR-shared.h
js/src/jit/shared/LOpcodes-shared.h
js/src/jit/shared/Lowering-shared-inl.h
js/src/jit/x64/Assembler-x64.cpp
js/src/jit/x64/CodeGenerator-x64.cpp
js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
js/src/jit/x86-shared/CodeGenerator-x86-shared.h
js/src/jit/x86-shared/Lowering-x86-shared.cpp
js/src/jit/x86/Assembler-x86.cpp
js/src/jit/x86/CodeGenerator-x86.cpp
--- a/js/src/builtin/SIMD.cpp
+++ b/js/src/builtin/SIMD.cpp
@@ -116,16 +116,17 @@ js::ToSimdConstant(JSContext* cx, Handle
 
     Elem* mem = reinterpret_cast<Elem*>(v.toObject().as<TypedObject>().typedMem());
     *out = jit::SimdConstant::CreateX4(mem);
     return true;
 }
 
 template bool js::ToSimdConstant<Int32x4>(JSContext* cx, HandleValue v, jit::SimdConstant* out);
 template bool js::ToSimdConstant<Float32x4>(JSContext* cx, HandleValue v, jit::SimdConstant* out);
+template bool js::ToSimdConstant<Bool32x4>(JSContext* cx, HandleValue v, jit::SimdConstant* out);
 
 template<typename Elem>
 static Elem
 TypedObjectMemory(HandleValue v)
 {
     TypedObject& obj = v.toObject().as<TypedObject>();
     return reinterpret_cast<Elem>(obj.typedMem());
 }
--- a/js/src/builtin/SIMD.h
+++ b/js/src/builtin/SIMD.h
@@ -386,23 +386,16 @@
 #define ARITH_COMMONX4_SIMD_OP(_)    \
     _(add)                           \
     _(sub)                           \
     _(mul)
 #define BITWISE_COMMONX4_SIMD_OP(_)  \
     _(and)                           \
     _(or)                            \
     _(xor)
-#define COMP_COMMONX4_TO_INT32X4_SIMD_OP(_) \
-    _(lessThan)                      \
-    _(lessThanOrEqual)               \
-    _(equal)                         \
-    _(notEqual)                      \
-    _(greaterThan)                   \
-    _(greaterThanOrEqual)
 #define COMP_COMMONX4_TO_BOOL32X4_SIMD_OP(_) \
     _(lessThan)                      \
     _(lessThanOrEqual)               \
     _(equal)                         \
     _(notEqual)                      \
     _(greaterThan)                   \
     _(greaterThanOrEqual)
 // TODO: remove when all SIMD calls are inlined (bug 1112155)
@@ -423,17 +416,17 @@
     _(load3)                         \
     _(store)                         \
     _(store1)                        \
     _(store2)                        \
     _(store3)                        \
     _(check)
 #define FOREACH_COMMONX4_SIMD_OP(_)  \
     ION_COMMONX4_SIMD_OP(_)          \
-    COMP_COMMONX4_TO_INT32X4_SIMD_OP(_)
+    COMP_COMMONX4_TO_BOOL32X4_SIMD_OP(_)
 #define FORALL_SIMD_OP(_)            \
     FOREACH_INT32X4_SIMD_OP(_)       \
     FOREACH_FLOAT32X4_SIMD_OP(_)     \
     FOREACH_BOOL_SIMD_OP(_)          \
     FOREACH_COMMONX4_SIMD_OP(_)
 
 namespace js {
 
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/SIMD/bool32x4-const.js
@@ -0,0 +1,65 @@
+load(libdir + "simd.js");
+
+setJitCompilerOption("ion.warmup.trigger", 50);
+
+// Test constant folding into the Bool32x4 constructor.
+// Verify that we get the truthiness right, c.f. the ECMA ToBoolean() function.
+function f1() {
+    var B = SIMD.Bool32x4;
+    var S = SIMD.Bool32x4.splat;
+    return [
+        B(false, false, false, true),
+        B(true),
+        B(undefined, null, "", "x"),
+        B({}, 0, 1, -0.0),
+        B(NaN, -NaN, Symbol(), objectEmulatingUndefined()),
+
+        S(false),
+        S(true),
+        S(undefined),
+        S(null),
+
+        S(""),
+        S("x"),
+        S(0),
+        S(1),
+
+        S({}),
+        S(-0.0),
+        S(NaN),
+        S(Symbol()),
+
+        S(objectEmulatingUndefined())
+    ];
+}
+
+function f() {
+    for (var i = 0; i < 100; i++) {
+        var a = f1()
+        assertEqX4(a[0], [false, false, false, true]);
+        assertEqX4(a[1], [true,  false, false, false]);
+        assertEqX4(a[2], [false, false, false, true]);
+        assertEqX4(a[3], [true,  false, true,  false]);
+        assertEqX4(a[4], [false, false, true,  false]);
+
+        // Splats.
+        assertEqX4(a[5], [false, false, false, false]);
+        assertEqX4(a[6], [true, true, true, true]);
+        assertEqX4(a[7], [false, false, false, false]);
+        assertEqX4(a[8], [false, false, false, false]);
+
+        assertEqX4(a[9], [false, false, false, false]);
+        assertEqX4(a[10], [true, true, true, true]);
+        assertEqX4(a[11], [false, false, false, false]);
+        assertEqX4(a[12], [true, true, true, true]);
+
+        assertEqX4(a[13], [true, true, true, true]);
+        assertEqX4(a[14], [false, false, false, false]);
+        assertEqX4(a[15], [false, false, false, false]);
+        assertEqX4(a[16], [true, true, true, true]);
+
+        assertEqX4(a[17], [false, false, false, false]);
+    }
+}
+
+f();
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -1888,16 +1888,17 @@ jit::FinishBailoutToBaseline(BaselineBai
       case Bailout_Hole:
       case Bailout_NegativeIndex:
       case Bailout_NonInt32Input:
       case Bailout_NonNumericInput:
       case Bailout_NonBooleanInput:
       case Bailout_NonObjectInput:
       case Bailout_NonStringInput:
       case Bailout_NonSymbolInput:
+      case Bailout_NonSimdBool32x4Input:
       case Bailout_NonSimdInt32x4Input:
       case Bailout_NonSimdFloat32x4Input:
       case Bailout_NonSharedTypedArrayInput:
       case Bailout_InitialState:
       case Bailout_Debugger:
       case Bailout_UninitializedThis:
       case Bailout_BadDerivedConstructorReturn:
         // Do nothing.
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -5695,35 +5695,47 @@ GetTemplateObjectForNative(JSContext* cx
     if (native == obj_create && args.length() == 1 && args[0].isObjectOrNull()) {
         RootedObject proto(cx, args[0].toObjectOrNull());
         res.set(ObjectCreateImpl(cx, proto, TenuredObject));
         return !!res;
     }
 
     if (JitSupportsSimd()) {
 #define ADD_INT32X4_SIMD_OP_NAME_(OP) || native == js::simd_int32x4_##OP
+#define ADD_BOOL32X4_SIMD_OP_NAME_(OP) || native == js::simd_bool32x4_##OP
 #define ADD_FLOAT32X4_SIMD_OP_NAME_(OP) || native == js::simd_float32x4_##OP
-       if (false
-           ION_COMMONX4_SIMD_OP(ADD_INT32X4_SIMD_OP_NAME_)
-           COMP_COMMONX4_TO_INT32X4_SIMD_OP(ADD_INT32X4_SIMD_OP_NAME_)
-           COMP_COMMONX4_TO_INT32X4_SIMD_OP(ADD_FLOAT32X4_SIMD_OP_NAME_)
-           FOREACH_INT32X4_SIMD_OP(ADD_INT32X4_SIMD_OP_NAME_))
-       {
+        // Operations producing an int32x4.
+        if (false
+            ION_COMMONX4_SIMD_OP(ADD_INT32X4_SIMD_OP_NAME_)
+            FOREACH_INT32X4_SIMD_OP(ADD_INT32X4_SIMD_OP_NAME_))
+        {
             Rooted<SimdTypeDescr*> descr(cx, cx->global()->getOrCreateSimdTypeDescr<Int32x4>(cx));
             res.set(cx->compartment()->jitCompartment()->getSimdTemplateObjectFor(cx, descr));
             return !!res;
-       }
-       if (false
-           FOREACH_FLOAT32X4_SIMD_OP(ADD_FLOAT32X4_SIMD_OP_NAME_)
-           ION_COMMONX4_SIMD_OP(ADD_FLOAT32X4_SIMD_OP_NAME_))
-       {
+        }
+        // Operations producing a bool32x4.
+        if (false
+            BITWISE_COMMONX4_SIMD_OP(ADD_BOOL32X4_SIMD_OP_NAME_)
+            COMP_COMMONX4_TO_BOOL32X4_SIMD_OP(ADD_INT32X4_SIMD_OP_NAME_)
+            COMP_COMMONX4_TO_BOOL32X4_SIMD_OP(ADD_FLOAT32X4_SIMD_OP_NAME_))
+        {
+            Rooted<SimdTypeDescr*> descr(cx, cx->global()->getOrCreateSimdTypeDescr<Bool32x4>(cx));
+            res.set(cx->compartment()->jitCompartment()->getSimdTemplateObjectFor(cx, descr));
+            return !!res;
+        }
+        // Operations producing a float32x4.
+        if (false
+            FOREACH_FLOAT32X4_SIMD_OP(ADD_FLOAT32X4_SIMD_OP_NAME_)
+            ION_COMMONX4_SIMD_OP(ADD_FLOAT32X4_SIMD_OP_NAME_))
+        {
             Rooted<SimdTypeDescr*> descr(cx, cx->global()->getOrCreateSimdTypeDescr<Float32x4>(cx));
             res.set(cx->compartment()->jitCompartment()->getSimdTemplateObjectFor(cx, descr));
             return !!res;
-       }
+        }
+#undef ADD_BOOL32X4_SIMD_OP_NAME_
 #undef ADD_INT32X4_SIMD_OP_NAME_
 #undef ADD_FLOAT32X4_SIMD_OP_NAME_
     }
 
     return true;
 }
 
 static bool
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -4736,16 +4736,17 @@ CodeGenerator::visitSimdBox(LSimdBox* li
                                    ArgList(ImmGCPtr(templateObject), Imm32(initialHeap)),
                                    StoreRegisterTo(object));
 
     masm.createGCObject(object, temp, templateObject, initialHeap, ool->entry());
     masm.bind(ool->rejoin());
 
     Address objectData(object, InlineTypedObject::offsetOfDataStart());
     switch (type) {
+      case MIRType_Bool32x4:
       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.");
@@ -4804,16 +4805,19 @@ CodeGenerator::visitSimdUnbox(LSimdUnbox
     Address typeDescrKind(temp, NativeObject::getFixedSlotOffset(JS_DESCR_SLOT_KIND));
     masm.assertTestInt32(Assembler::Equal, typeDescrKind,
       "MOZ_ASSERT(obj->type()->typeDescr()->getReservedSlot(JS_DESCR_SLOT_KIND).isInt32())");
     masm.branch32(Assembler::NotEqual, masm.ToPayload(typeDescrKind), Imm32(js::type::Simd), &bail);
 
     // Convert the SIMD MIRType to a SimdTypeDescr::Type.
     js::SimdTypeDescr::Type type;
     switch (lir->mir()->type()) {
+      case MIRType_Bool32x4:
+        type = js::SimdTypeDescr::Bool32x4;
+        break;
       case MIRType_Int32x4:
         type = js::SimdTypeDescr::Int32x4;
         break;
       case MIRType_Float32x4:
         type = js::SimdTypeDescr::Float32x4;
         break;
       default:
         MOZ_CRASH("Unexpected SIMD Type.");
@@ -4825,16 +4829,17 @@ CodeGenerator::visitSimdUnbox(LSimdUnbox
     Address typeDescrType(temp, NativeObject::getFixedSlotOffset(JS_DESCR_SLOT_TYPE));
     masm.assertTestInt32(Assembler::Equal, typeDescrType,
       "MOZ_ASSERT(obj->type()->typeDescr()->getReservedSlot(JS_DESCR_SLOT_TYPE).isInt32())");
     masm.branch32(Assembler::NotEqual, masm.ToPayload(typeDescrType), Imm32(type), &bail);
 
     // Load the value from the data of the InlineTypedObject.
     Address objectData(object, InlineTypedObject::offsetOfDataStart());
     switch (lir->mir()->type()) {
+      case MIRType_Bool32x4:
       case MIRType_Int32x4:
         masm.loadUnalignedInt32x4(objectData, simd);
         break;
       case MIRType_Float32x4:
         masm.loadUnalignedFloat32x4(objectData, simd);
         break;
       default:
         MOZ_CRASH("The impossible happened!");
--- a/js/src/jit/EagerSimdUnbox.cpp
+++ b/js/src/jit/EagerSimdUnbox.cpp
@@ -15,16 +15,17 @@ namespace jit {
 
 static SimdTypeDescr::Type
 MIRTypeToSimdTypeDescr(MIRType type)
 {
     MOZ_ASSERT(IsSimdType(type));
     switch (type) {
       case MIRType_Float32x4:   return SimdTypeDescr::Float32x4;
       case MIRType_Int32x4:     return SimdTypeDescr::Int32x4;
+      case MIRType_Bool32x4:    return SimdTypeDescr::Bool32x4;
       default:                  break;
     }
     MOZ_CRASH("unexpected MIRType");
 }
 
 // Do not optimize any Phi instruction which has conflicting Unbox operations,
 // as this might imply some intended polymorphism.
 static bool
--- a/js/src/jit/InlinableNatives.h
+++ b/js/src/jit/InlinableNatives.h
@@ -76,16 +76,17 @@
     _(StringReplace)                \
                                     \
     _(ObjectCreate)                 \
                                     \
     _(CallBoundFunction)            \
                                     \
     _(SimdInt32x4)                  \
     _(SimdFloat32x4)                \
+    _(SimdBool32x4)                 \
                                     \
     _(TestBailout)                  \
     _(TestAssertFloat32)            \
     _(TestAssertRecoveredOnBailout) \
                                     \
     _(IntrinsicUnsafeSetReservedSlot) \
     _(IntrinsicUnsafeGetReservedSlot) \
     _(IntrinsicUnsafeGetObjectFromReservedSlot) \
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -2466,16 +2466,17 @@ IsResumableMIRType(MIRType type)
       case MIRType_Symbol:
       case MIRType_Object:
       case MIRType_MagicOptimizedArguments:
       case MIRType_MagicOptimizedOut:
       case MIRType_MagicUninitializedLexical:
       case MIRType_Value:
       case MIRType_Float32x4:
       case MIRType_Int32x4:
+      case MIRType_Bool32x4:
         return true;
 
       case MIRType_MagicHole:
       case MIRType_MagicIsConstructing:
       case MIRType_ObjectOrNull:
       case MIRType_None:
       case MIRType_Slots:
       case MIRType_Elements:
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -11244,22 +11244,22 @@ IonBuilder::getPropTryConstant(bool* emi
 }
 
 MIRType
 IonBuilder::SimdTypeDescrToMIRType(SimdTypeDescr::Type type)
 {
     switch (type) {
       case SimdTypeDescr::Int32x4:   return MIRType_Int32x4;
       case SimdTypeDescr::Float32x4: return MIRType_Float32x4;
+      case SimdTypeDescr::Bool32x4:  return MIRType_Bool32x4;
       case SimdTypeDescr::Int8x16:
       case SimdTypeDescr::Int16x8:
       case SimdTypeDescr::Float64x2:
       case SimdTypeDescr::Bool8x16:
       case SimdTypeDescr::Bool16x8:
-      case SimdTypeDescr::Bool32x4:
       case SimdTypeDescr::Bool64x2: return MIRType_Undefined;
     }
     MOZ_CRASH("unimplemented MIR type for a SimdTypeDescr::Type");
 }
 
 bool
 IonBuilder::getPropTrySimdGetter(bool* emitted, MDefinition* obj, PropertyName* name)
 {
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -854,19 +854,21 @@ class IonBuilder
     InliningStatus inlineConstructSimdObject(CallInfo& callInfo, SimdTypeDescr* target);
 
     //  helpers
     static MIRType SimdTypeDescrToMIRType(SimdTypeDescr::Type type);
     bool checkInlineSimd(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type,
                          unsigned numArgs, InlineTypedObject** templateObj);
     IonBuilder::InliningStatus boxSimd(CallInfo& callInfo, MInstruction* ins,
                                        InlineTypedObject* templateObj);
+    MDefinition* convertToBooleanSimdLane(MDefinition* scalar);
 
     InliningStatus inlineSimdInt32x4(CallInfo& callInfo, JSNative native);
     InliningStatus inlineSimdFloat32x4(CallInfo& callInfo, JSNative native);
+    InliningStatus inlineSimdBool32x4(CallInfo& callInfo, JSNative native);
 
     template <typename T>
     InliningStatus inlineBinarySimd(CallInfo& callInfo, JSNative native,
                                     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);
@@ -885,16 +887,18 @@ class IonBuilder
 
     bool prepareForSimdLoadStore(CallInfo& callInfo, Scalar::Type simdType, MInstruction** elements,
                                  MDefinition** index, Scalar::Type* arrayType);
     InliningStatus inlineSimdLoad(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type,
                                   unsigned numElems);
     InliningStatus inlineSimdStore(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type,
                                    unsigned numElems);
 
+    InliningStatus inlineSimdAnyAllTrue(CallInfo& callInfo, bool IsAllTrue, JSNative native);
+
     // 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);
     InliningStatus inlineHasClass(CallInfo& callInfo, const Class* clasp,
--- a/js/src/jit/IonTypes.h
+++ b/js/src/jit/IonTypes.h
@@ -97,16 +97,17 @@ enum BailoutKind
     Bailout_NonInt32Input,
     Bailout_NonNumericInput, // unboxing a double works with int32 too
     Bailout_NonBooleanInput,
     Bailout_NonObjectInput,
     Bailout_NonStringInput,
     Bailout_NonSymbolInput,
 
     // SIMD Unbox expects a given type, bails out if it doesn't match.
+    Bailout_NonSimdBool32x4Input,
     Bailout_NonSimdInt32x4Input,
     Bailout_NonSimdFloat32x4Input,
 
     // Atomic operations require shared memory, bail out if the typed array
     // maps unshared memory.
     Bailout_NonSharedTypedArrayInput,
 
     // For the initial snapshot when entering a function.
@@ -208,16 +209,18 @@ BailoutKindString(BailoutKind kind)
       case Bailout_NonBooleanInput:
         return "Bailout_NonBooleanInput";
       case Bailout_NonObjectInput:
         return "Bailout_NonObjectInput";
       case Bailout_NonStringInput:
         return "Bailout_NonStringInput";
       case Bailout_NonSymbolInput:
         return "Bailout_NonSymbolInput";
+      case Bailout_NonSimdBool32x4Input:
+        return "Bailout_NonSimdBool32x4Input";
       case Bailout_NonSimdInt32x4Input:
         return "Bailout_NonSimdInt32x4Input";
       case Bailout_NonSimdFloat32x4Input:
         return "Bailout_NonSimdFloat32x4Input";
       case Bailout_NonSharedTypedArrayInput:
         return "Bailout_NonSharedTypedArrayInput";
       case Bailout_InitialState:
         return "Bailout_InitialState";
@@ -409,16 +412,17 @@ enum MIRType
     MIRType_Slots,                     // A slots vector
     MIRType_Elements,                  // An elements vector
     MIRType_Pointer,                   // An opaque pointer that receives no special treatment
     MIRType_Shape,                     // A Shape pointer.
     MIRType_ObjectGroup,               // An ObjectGroup pointer.
     MIRType_Last = MIRType_ObjectGroup,
     MIRType_Float32x4 = MIRType_Float32 | (2 << VECTOR_SCALE_SHIFT),
     MIRType_Int32x4   = MIRType_Int32   | (2 << VECTOR_SCALE_SHIFT),
+    MIRType_Bool32x4  = MIRType_Boolean | (2 << VECTOR_SCALE_SHIFT),
     MIRType_Doublex2  = MIRType_Double  | (1 << VECTOR_SCALE_SHIFT)
 };
 
 static inline MIRType
 MIRTypeFromValueType(JSValueType type)
 {
     // This function does not deal with magic types. Magic constants should be
     // filtered out in MIRTypeFromValue.
@@ -566,32 +570,38 @@ static inline bool
 IsNullOrUndefined(MIRType type)
 {
     return type == MIRType_Null || type == MIRType_Undefined;
 }
 
 static inline bool
 IsSimdType(MIRType type)
 {
-    return type == MIRType_Int32x4 || type == MIRType_Float32x4;
+    return type == MIRType_Int32x4 || type == MIRType_Float32x4 || type == MIRType_Bool32x4;
 }
 
 static inline bool
 IsFloatingPointSimdType(MIRType type)
 {
     return type == MIRType_Float32x4;
 }
 
 static inline bool
 IsIntegerSimdType(MIRType type)
 {
     return type == MIRType_Int32x4;
 }
 
 static inline bool
+IsBooleanSimdType(MIRType type)
+{
+    return type == MIRType_Bool32x4;
+}
+
+static inline bool
 IsMagicType(MIRType type)
 {
     return type == MIRType_MagicHole ||
            type == MIRType_MagicOptimizedOut ||
            type == MIRType_MagicIsConstructing ||
            type == MIRType_MagicOptimizedArguments ||
            type == MIRType_MagicUninitializedLexical;
 }
@@ -650,26 +660,39 @@ ScalarTypeToLength(Scalar::Type type)
         return 4;
       case Scalar::MaxTypedArrayViewType:
         break;
     }
     MOZ_CRASH("unexpected SIMD kind");
 }
 
 // Get the type of the individual lanes in a SIMD type.
-// For example, Int32x4 -> Int32, FLoat32x4 -> Float32 etc.
+// For example, Int32x4 -> Int32, Float32x4 -> Float32 etc.
 static inline MIRType
 SimdTypeToLaneType(MIRType type)
 {
     MOZ_ASSERT(IsSimdType(type));
     static_assert(MIRType_Last <= ELEMENT_TYPE_MASK,
                   "ELEMENT_TYPE_MASK should be larger than the last MIRType");
     return MIRType((type >> ELEMENT_TYPE_SHIFT) & ELEMENT_TYPE_MASK);
 }
 
+// Get the type expected when inserting a lane into a SIMD type.
+// This is the argument type expected by the MSimdValue constructors as well as
+// MSimdSplat and MSimdInsertElement.
+static inline MIRType
+SimdTypeToLaneArgumentType(MIRType type)
+{
+    MIRType laneType = SimdTypeToLaneType(type);
+
+    // Boolean lanes should be pre-converted to an Int32 with the values 0 or -1.
+    // All other lane types are inserted directly.
+    return laneType == MIRType_Boolean ? MIRType_Int32 : laneType;
+}
+
 // Indicates a lane in a SIMD register: X for the first lane, Y for the second,
 // Z for the third (if any), W for the fourth (if any).
 enum SimdLane {
     LaneX = 0x0,
     LaneY = 0x1,
     LaneZ = 0x2,
     LaneW = 0x3
 };
--- a/js/src/jit/LIR.h
+++ b/js/src/jit/LIR.h
@@ -563,16 +563,17 @@ class LDefinition
 #endif
           case MIRType_SinCosDouble:
             return LDefinition::SINCOS;
           case MIRType_Slots:
           case MIRType_Elements:
             return LDefinition::SLOTS;
           case MIRType_Pointer:
             return LDefinition::GENERAL;
+          case MIRType_Bool32x4:
           case MIRType_Int32x4:
             return LDefinition::INT32X4;
           case MIRType_Float32x4:
             return LDefinition::FLOAT32X4;
           default:
             MOZ_CRASH("unexpected type");
         }
     }
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -4012,16 +4012,19 @@ void
 LIRGenerator::visitSimdUnbox(MSimdUnbox* ins)
 {
     MOZ_ASSERT(ins->input()->type() == MIRType_Object);
     MOZ_ASSERT(IsSimdType(ins->type()));
     LUse in = useRegister(ins->input());
 
     BailoutKind kind;
     switch (ins->type()) {
+      case MIRType_Bool32x4:
+        kind = Bailout_NonSimdBool32x4Input;
+        break;
       case MIRType_Int32x4:
         kind = Bailout_NonSimdInt32x4Input;
         break;
       case MIRType_Float32x4:
         kind = Bailout_NonSimdFloat32x4Input;
         break;
       default:
         MOZ_CRASH("Unexpected SIMD Type.");
@@ -4032,22 +4035,27 @@ LIRGenerator::visitSimdUnbox(MSimdUnbox*
     define(lir, ins);
 }
 
 void
 LIRGenerator::visitSimdConstant(MSimdConstant* ins)
 {
     MOZ_ASSERT(IsSimdType(ins->type()));
 
-    if (ins->type() == MIRType_Int32x4)
+    switch (ins->type()) {
+      case MIRType_Bool32x4:
+      case MIRType_Int32x4:
         define(new(alloc()) LInt32x4(), ins);
-    else if (ins->type() == MIRType_Float32x4)
+        break;
+      case MIRType_Float32x4:
         define(new(alloc()) LFloat32x4(), ins);
-    else
+        break;
+      default:
         MOZ_CRASH("Unknown SIMD kind when generating constant");
+    }
 }
 
 void
 LIRGenerator::visitSimdConvert(MSimdConvert* ins)
 {
     MOZ_ASSERT(IsSimdType(ins->type()));
     MDefinition* input = ins->input();
     LUse use = useRegister(input);
@@ -4078,42 +4086,57 @@ LIRGenerator::visitSimdReinterpretCast(M
 }
 
 void
 LIRGenerator::visitSimdExtractElement(MSimdExtractElement* ins)
 {
     MOZ_ASSERT(IsSimdType(ins->input()->type()));
     MOZ_ASSERT(!IsSimdType(ins->type()));
 
-    if (ins->input()->type() == MIRType_Int32x4) {
+    switch (ins->input()->type()) {
+      case MIRType_Int32x4: {
         // Note: there could be int16x8 in the future, which doesn't use the
         // same instruction. We either need to pass the arity or create new LIns.
         LUse use = useRegisterAtStart(ins->input());
         define(new(alloc()) LSimdExtractElementI(use), ins);
-    } else if (ins->input()->type() == MIRType_Float32x4) {
+        break;
+      }
+      case MIRType_Float32x4: {
         LUse use = useRegisterAtStart(ins->input());
         define(new(alloc()) LSimdExtractElementF(use), ins);
-    } else {
+        break;
+      }
+      case MIRType_Bool32x4: {
+        LUse use = useRegisterAtStart(ins->input());
+        define(new(alloc()) LSimdExtractElementB(use), ins);
+        break;
+      }
+      default:
         MOZ_CRASH("Unknown SIMD kind when extracting element");
     }
 }
 
 void
 LIRGenerator::visitSimdInsertElement(MSimdInsertElement* ins)
 {
     MOZ_ASSERT(IsSimdType(ins->type()));
 
     LUse vec = useRegisterAtStart(ins->vector());
     LUse val = useRegister(ins->value());
-    if (ins->type() == MIRType_Int32x4)
+    switch (ins->type()) {
+      case MIRType_Int32x4:
+      case MIRType_Bool32x4:
         defineReuseInput(new(alloc()) LSimdInsertElementI(vec, val), ins, 0);
-    else if (ins->type() == MIRType_Float32x4)
+        break;
+      case MIRType_Float32x4:
         defineReuseInput(new(alloc()) LSimdInsertElementF(vec, val), ins, 0);
-    else
+        break;
+      default:
         MOZ_CRASH("Unknown SIMD kind when generating constant");
+    }
 }
 
 void
 LIRGenerator::visitSimdSignMask(MSimdSignMask* ins)
 {
     MDefinition* input = ins->input();
     MOZ_ASSERT(IsSimdType(input->type()));
     MOZ_ASSERT(ins->type() == MIRType_Int32);
@@ -4126,16 +4149,36 @@ LIRGenerator::visitSimdSignMask(MSimdSig
         define(new(alloc()) LSimdSignMaskX4(use), ins);
         break;
       default:
         MOZ_CRASH("Unexpected SIMD type extracting sign bits.");
     }
 }
 
 void
+LIRGenerator::visitSimdAllTrue(MSimdAllTrue* ins)
+{
+    MDefinition* input = ins->input();
+    MOZ_ASSERT(IsBooleanSimdType(input->type()));
+
+    LUse use = useRegisterAtStart(input);
+    define(new(alloc()) LSimdAllTrue(use), ins);
+}
+
+void
+LIRGenerator::visitSimdAnyTrue(MSimdAnyTrue* ins)
+{
+    MDefinition* input = ins->input();
+    MOZ_ASSERT(IsBooleanSimdType(input->type()));
+
+    LUse use = useRegisterAtStart(input);
+    define(new(alloc()) LSimdAnyTrue(use), ins);
+}
+
+void
 LIRGenerator::visitSimdSwizzle(MSimdSwizzle* ins)
 {
     MOZ_ASSERT(IsSimdType(ins->input()->type()));
     MOZ_ASSERT(IsSimdType(ins->type()));
 
     if (ins->input()->type() == MIRType_Int32x4) {
         LUse use = useRegisterAtStart(ins->input());
         LSimdSwizzleI* lir = new (alloc()) LSimdSwizzleI(use);
@@ -4203,33 +4246,33 @@ void
 LIRGenerator::visitSimdUnaryArith(MSimdUnaryArith* ins)
 {
     MOZ_ASSERT(IsSimdType(ins->input()->type()));
     MOZ_ASSERT(IsSimdType(ins->type()));
 
     // Cannot be at start, as the ouput is used as a temporary to store values.
     LUse in = use(ins->input());
 
-    if (ins->type() == MIRType_Int32x4) {
+    if (ins->type() == MIRType_Int32x4 || ins->type() == MIRType_Bool32x4) {
         LSimdUnaryArithIx4* lir = new(alloc()) LSimdUnaryArithIx4(in);
         define(lir, ins);
     } else if (ins->type() == MIRType_Float32x4) {
         LSimdUnaryArithFx4* lir = new(alloc()) LSimdUnaryArithFx4(in);
         define(lir, ins);
     } else {
         MOZ_CRASH("Unknown SIMD kind for unary operation");
     }
 }
 
 void
 LIRGenerator::visitSimdBinaryComp(MSimdBinaryComp* ins)
 {
     MOZ_ASSERT(IsSimdType(ins->lhs()->type()));
     MOZ_ASSERT(IsSimdType(ins->rhs()->type()));
-    MOZ_ASSERT(ins->type() == MIRType_Int32x4);
+    MOZ_ASSERT(IsBooleanSimdType(ins->type()));
 
     if (ShouldReorderCommutative(ins->lhs(), ins->rhs(), ins))
         ins->reverse();
 
     if (ins->specialization() == MIRType_Int32x4) {
         LSimdBinaryCompIx4* add = new(alloc()) LSimdBinaryCompIx4();
         lowerForCompIx4(add, ins, ins->lhs(), ins->rhs());
     } else if (ins->specialization() == MIRType_Float32x4) {
@@ -4246,20 +4289,25 @@ LIRGenerator::visitSimdBinaryBitwise(MSi
     MOZ_ASSERT(IsSimdType(ins->lhs()->type()));
     MOZ_ASSERT(IsSimdType(ins->rhs()->type()));
     MOZ_ASSERT(IsSimdType(ins->type()));
 
     MDefinition* lhs = ins->lhs();
     MDefinition* rhs = ins->rhs();
     ReorderCommutative(&lhs, &rhs, ins);
 
-    if (ins->type() == MIRType_Int32x4 || ins->type() == MIRType_Float32x4) {
+    switch (ins->type()) {
+      case MIRType_Bool32x4:
+      case MIRType_Int32x4:
+      case MIRType_Float32x4: {
         LSimdBinaryBitwiseX4* lir = new(alloc()) LSimdBinaryBitwiseX4;
         lowerForFPU(lir, ins, lhs, rhs);
-    } else {
+        break;
+      }
+      default:
         MOZ_CRASH("Unknown SIMD kind when doing bitwise operations");
     }
 }
 
 void
 LIRGenerator::visitSimdShift(MSimdShift* ins)
 {
     MOZ_ASSERT(ins->type() == MIRType_Int32x4);
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -291,16 +291,18 @@ class LIRGenerator : public LIRGenerator
     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);
+    void visitSimdAllTrue(MSimdAllTrue* ins);
+    void visitSimdAnyTrue(MSimdAnyTrue* ins);
     void visitPhi(MPhi* ins);
     void visitBeta(MBeta* ins);
     void visitObjectState(MObjectState* ins);
     void visitArrayState(MArrayState* ins);
     void visitUnknownValue(MUnknownValue* ins);
     void visitLexicalCheck(MLexicalCheck* ins);
     void visitThrowRuntimeLexicalError(MThrowRuntimeLexicalError* ins);
     void visitGlobalNameConflictsCheck(MGlobalNameConflictsCheck* ins);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -201,16 +201,18 @@ IonBuilder::inlineNativeCall(CallInfo& c
       case InlinableNative::CallBoundFunction:
         return inlineBoundFunction(callInfo, target);
 
       // SIMD natives.
       case InlinableNative::SimdInt32x4:
         return inlineSimdInt32x4(callInfo, target->native());
       case InlinableNative::SimdFloat32x4:
         return inlineSimdFloat32x4(callInfo, target->native());
+      case InlinableNative::SimdBool32x4:
+        return inlineSimdBool32x4(callInfo, target->native());
 
       // Testing functions.
       case InlinableNative::TestBailout:
         return inlineBailout(callInfo);
       case InlinableNative::TestAssertFloat32:
         return inlineAssertFloat32(callInfo);
       case InlinableNative::TestAssertRecoveredOnBailout:
         return inlineAssertRecoveredOnBailout(callInfo);
@@ -3044,16 +3046,48 @@ IonBuilder::inlineConstructTypedObject(C
                                                 templateObject->group()->initialHeap(constraints()));
     current->add(ins);
     current->push(ins);
 
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
+IonBuilder::inlineSimdBool32x4(CallInfo& callInfo, JSNative native)
+{
+#define INLINE_SIMD_BITWISE_(OP)                                                                   \
+    if (native == js::simd_bool32x4_##OP)                                                          \
+        return inlineBinarySimd<MSimdBinaryBitwise>(callInfo, native, MSimdBinaryBitwise::OP##_,   \
+                                                    SimdTypeDescr::Bool32x4);
+
+    BITWISE_COMMONX4_SIMD_OP(INLINE_SIMD_BITWISE_)
+#undef INLINE_SIMD_BITWISE_
+
+    if (native == js::simd_bool32x4_extractLane)
+        return inlineSimdExtractLane(callInfo, native, SimdTypeDescr::Bool32x4);
+    if (native == js::simd_bool32x4_replaceLane)
+        return inlineSimdReplaceLane(callInfo, native, SimdTypeDescr::Bool32x4);
+
+    if (native == js::simd_bool32x4_not)
+        return inlineUnarySimd(callInfo, native, MSimdUnaryArith::not_, SimdTypeDescr::Bool32x4);
+
+    if (native == js::simd_bool32x4_splat)
+        return inlineSimdSplat(callInfo, native, SimdTypeDescr::Bool32x4);
+    if (native == js::simd_bool32x4_check)
+        return inlineSimdCheck(callInfo, native, SimdTypeDescr::Bool32x4);
+
+    if (native == js::simd_bool32x4_allTrue)
+        return inlineSimdAnyAllTrue(callInfo, true, native);
+    if (native == js::simd_bool32x4_anyTrue)
+        return inlineSimdAnyAllTrue(callInfo, false, native);
+
+    return InliningStatus_NotInlined;
+}
+
+IonBuilder::InliningStatus
 IonBuilder::inlineSimdInt32x4(CallInfo& callInfo, JSNative native)
 {
 #define INLINE_INT32X4_SIMD_ARITH_(OP)                                                           \
     if (native == js::simd_int32x4_##OP)                                                         \
         return inlineBinarySimd<MSimdBinaryArith>(callInfo, native, MSimdBinaryArith::Op_##OP,   \
                                                   SimdTypeDescr::Int32x4);
 
     ARITH_COMMONX4_SIMD_OP(INLINE_INT32X4_SIMD_ARITH_)
@@ -3073,17 +3107,17 @@ IonBuilder::inlineSimdInt32x4(CallInfo& 
         return inlineBinarySimd<MSimdShift>(callInfo, native, MSimdShift::rsh, SimdTypeDescr::Int32x4);
     if (native == js::simd_int32x4_shiftRightLogicalByScalar)
         return inlineBinarySimd<MSimdShift>(callInfo, native, MSimdShift::ursh, SimdTypeDescr::Int32x4);
 
 #define INLINE_SIMD_COMPARISON_(OP)                                                                \
     if (native == js::simd_int32x4_##OP)                                                           \
         return inlineCompSimd(callInfo, native, MSimdBinaryComp::OP, SimdTypeDescr::Int32x4);
 
-    COMP_COMMONX4_TO_INT32X4_SIMD_OP(INLINE_SIMD_COMPARISON_)
+    COMP_COMMONX4_TO_BOOL32X4_SIMD_OP(INLINE_SIMD_COMPARISON_)
 #undef INLINE_SIMD_COMPARISON_
 
     if (native == js::simd_int32x4_extractLane)
         return inlineSimdExtractLane(callInfo, native, SimdTypeDescr::Int32x4);
     if (native == js::simd_int32x4_replaceLane)
         return inlineSimdReplaceLane(callInfo, native, SimdTypeDescr::Int32x4);
 
     if (native == js::simd_int32x4_not)
@@ -3155,17 +3189,17 @@ IonBuilder::inlineSimdFloat32x4(CallInfo
 
     BITWISE_COMMONX4_SIMD_OP(INLINE_SIMD_BITWISE_)
 #undef INLINE_SIMD_BITWISE_
 
 #define INLINE_SIMD_COMPARISON_(OP)                                                                \
     if (native == js::simd_float32x4_##OP)                                                         \
         return inlineCompSimd(callInfo, native, MSimdBinaryComp::OP, SimdTypeDescr::Float32x4);
 
-    COMP_COMMONX4_TO_INT32X4_SIMD_OP(INLINE_SIMD_COMPARISON_)
+    COMP_COMMONX4_TO_BOOL32X4_SIMD_OP(INLINE_SIMD_COMPARISON_)
 #undef INLINE_SIMD_COMPARISON_
 
     if (native == js::simd_float32x4_extractLane)
         return inlineSimdExtractLane(callInfo, native, SimdTypeDescr::Float32x4);
     if (native == js::simd_float32x4_replaceLane)
         return inlineSimdReplaceLane(callInfo, native, SimdTypeDescr::Float32x4);
 
 #define INLINE_SIMD_FLOAT32X4_UNARY_(OP)                                                           \
@@ -3216,16 +3250,47 @@ IonBuilder::inlineSimdFloat32x4(CallInfo
     if (native == js::simd_float32x4_store2)
         return inlineSimdStore(callInfo, native, SimdTypeDescr::Float32x4, 2);
     if (native == js::simd_float32x4_store3)
         return inlineSimdStore(callInfo, native, SimdTypeDescr::Float32x4, 3);
 
     return InliningStatus_NotInlined;
 }
 
+// The representation of boolean SIMD vectors is the same as the corresponding
+// integer SIMD vectors with -1 lanes meaning true and 0 lanes meaning false.
+//
+// Functions that set the value of a boolean vector lane work by applying
+// ToBoolean on the input argument, so they accept any argument type, just like
+// the MNot and MTest instructions.
+//
+// Convert any scalar value into an appropriate SIMD lane value: An Int32 value
+// that is either 0 for false or -1 for true.
+MDefinition*
+IonBuilder::convertToBooleanSimdLane(MDefinition* scalar)
+{
+    MSub* result;
+
+    if (scalar->type() == MIRType_Boolean) {
+        // The input scalar is already a boolean with the int32 values 0 / 1.
+        // Compute result = 0 - scalar.
+        result = MSub::New(alloc(), constant(Int32Value(0)), scalar);
+    } else {
+        // For any other type, let MNot handle the conversion to boolean.
+        // Compute result = !scalar - 1.
+        MNot* inv = MNot::New(alloc(), scalar);
+        current->add(inv);
+        result = MSub::New(alloc(), inv, constant(Int32Value(1)));
+    }
+
+    result->setInt32Specialization();
+    current->add(result);
+    return result;
+}
+
 IonBuilder::InliningStatus
 IonBuilder::inlineConstructSimdObject(CallInfo& callInfo, SimdTypeDescr* descr)
 {
     // Generic constructor of SIMD valuesX4.
     MIRType simdType = SimdTypeDescrToMIRType(descr->type());
 
     // TODO Happens for Float64x2 (Bug 1124205) and Int8x16/Int16x8 (Bug 1136226)
     if (simdType == MIRType_Undefined)
@@ -3241,31 +3306,41 @@ IonBuilder::inlineConstructSimdObject(Ca
     // 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);
 
     // When there are missing arguments, provide a default value
     // containing the coercion of 'undefined' to the right type.
     MConstant* defVal = nullptr;
+    MIRType laneType = SimdTypeToLaneType(simdType);
     if (callInfo.argc() < SimdTypeToLength(simdType)) {
-        MIRType laneType = SimdTypeToLaneType(simdType);
         if (laneType == MIRType_Int32) {
             defVal = constant(Int32Value(0));
+        } else if (laneType == MIRType_Boolean) {
+            defVal = constant(BooleanValue(false));
         } else {
             MOZ_ASSERT(IsFloatingPointType(laneType));
             defVal = constant(DoubleNaNValue());
             defVal->setResultType(laneType);
         }
     }
 
+    MDefinition* lane[4];
+    for (unsigned i = 0; i < 4; i++)
+        lane[i] = callInfo.getArgWithDefault(i, defVal);
+
+    // Convert boolean lanes into Int32 0 / -1.
+    if (laneType == MIRType_Boolean) {
+        for (unsigned i = 0; i < 4; i++)
+            lane[i] = convertToBooleanSimdLane(lane[i]);
+    }
+
     MSimdValueX4* values =
-        MSimdValueX4::New(alloc(), simdType,
-                          callInfo.getArgWithDefault(0, defVal), callInfo.getArgWithDefault(1, defVal),
-                          callInfo.getArgWithDefault(2, defVal), callInfo.getArgWithDefault(3, defVal));
+      MSimdValueX4::New(alloc(), simdType, lane[0], lane[1], lane[2], lane[3]);
     current->add(values);
 
     MSimdBox* obj = MSimdBox::New(alloc(), constraints(), values, inlineTypedObject,
                                   inlineTypedObject->group()->initialHeap(constraints()));
     current->add(obj);
     current->push(obj);
 
     callInfo.setImplicitlyUsedUnchecked();
@@ -3321,17 +3396,17 @@ IonBuilder::inlineBinarySimd(CallInfo& c
     return boxSimd(callInfo, ins, templateObj);
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineCompSimd(CallInfo& callInfo, JSNative native, MSimdBinaryComp::Operation op,
                            SimdTypeDescr::Type compType)
 {
     InlineTypedObject* templateObj = nullptr;
-    if (!checkInlineSimd(callInfo, native, SimdTypeDescr::Int32x4, 2, &templateObj))
+    if (!checkInlineSimd(callInfo, native, SimdTypeDescr::Bool32x4, 2, &templateObj))
         return InliningStatus_NotInlined;
 
     // If the type of any of the arguments is neither a SIMD type, an Object
     // type, or a Value, then the applyTypes phase will add a fallible box &
     // unbox sequence.  This does not matter much as all binary SIMD
     // instructions are supposed to produce a TypeError when they're called
     // with non SIMD-arguments.
     MIRType mirType = SimdTypeDescrToMIRType(compType);
@@ -3357,17 +3432,23 @@ IonBuilder::InliningStatus
 IonBuilder::inlineSimdSplat(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type)
 {
     InlineTypedObject* templateObj = nullptr;
     if (!checkInlineSimd(callInfo, native, type, 1, &templateObj))
         return InliningStatus_NotInlined;
 
     // See comment in inlineBinarySimd
     MIRType mirType = SimdTypeDescrToMIRType(type);
-    MSimdSplatX4* ins = MSimdSplatX4::New(alloc(), callInfo.getArg(0), mirType);
+    MDefinition* arg = callInfo.getArg(0);
+
+    // Convert to 0 / -1 before splatting a boolean lane.
+    if (SimdTypeToLaneType(mirType) == MIRType_Boolean)
+        arg = convertToBooleanSimdLane(arg);
+
+    MSimdSplatX4* ins = MSimdSplatX4::New(alloc(), arg, mirType);
     return boxSimd(callInfo, ins, templateObj);
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineSimdExtractLane(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type)
 {
     InlineTypedObject* templateObj = nullptr;
     if (!checkInlineSimd(callInfo, native, type, 2, &templateObj))
@@ -3403,18 +3484,24 @@ IonBuilder::inlineSimdReplaceLane(CallIn
         return InliningStatus_NotInlined;
 
     int32_t lane = arg->constantValue().toInt32();
     if (lane < 0 || lane >= 4)
         return InliningStatus_NotInlined;
 
     // See comment in inlineBinarySimd
     MIRType mirType = SimdTypeDescrToMIRType(type);
-    MSimdInsertElement* ins = MSimdInsertElement::New(alloc(), callInfo.getArg(0),
-                                                      callInfo.getArg(2), mirType, SimdLane(lane));
+
+    // Convert to 0 / -1 before inserting a boolean lane.
+    MDefinition* value = callInfo.getArg(2);
+    if (SimdTypeToLaneType(mirType) == MIRType_Boolean)
+        value = convertToBooleanSimdLane(value);
+
+    MSimdInsertElement* ins =
+      MSimdInsertElement::New(alloc(), callInfo.getArg(0), value, mirType, SimdLane(lane));
     return boxSimd(callInfo, ins, templateObj);
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineSimdConvert(CallInfo& callInfo, JSNative native, bool isCast,
                               SimdTypeDescr::Type from, SimdTypeDescr::Type to)
 {
     InlineTypedObject* templateObj = nullptr;
@@ -3481,16 +3568,35 @@ IonBuilder::inlineSimdShuffle(CallInfo& 
     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);
 }
 
+IonBuilder::InliningStatus
+IonBuilder::inlineSimdAnyAllTrue(CallInfo& callInfo, bool IsAllTrue, JSNative native)
+{
+    InlineTypedObject* templateObj = nullptr;
+    if (!checkInlineSimd(callInfo, native, SimdTypeDescr::Bool32x4, 1, &templateObj))
+        return InliningStatus_NotInlined;
+
+    MUnaryInstruction* ins;
+    if (IsAllTrue)
+        ins = MSimdAllTrue::New(alloc(), callInfo.getArg(0), MIRType_Bool32x4);
+    else
+        ins = MSimdAnyTrue::New(alloc(), callInfo.getArg(0), MIRType_Bool32x4);
+
+    current->add(ins);
+    current->push(ins);
+    callInfo.setImplicitlyUsedUnchecked();
+    return InliningStatus_Inlined;
+}
+
 // Get the typed array element type corresponding to the lanes in a SIMD vector type.
 // This only applies to SIMD types that can be loaded and stored to a typed array.
 static Scalar::Type
 SimdTypeToArrayElementType(SimdTypeDescr::Type type)
 {
     switch (type) {
       case SimdTypeDescr::Float32x4: return Scalar::Float32x4;
       case SimdTypeDescr::Int32x4:   return Scalar::Int32x4;
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -901,17 +901,17 @@ MConstant::canProduceFloat32() const
     if (type() == MIRType_Double)
         return IsFloat32Representable(value_.toDouble());
     return true;
 }
 
 MDefinition*
 MSimdValueX4::foldsTo(TempAllocator& alloc)
 {
-    DebugOnly<MIRType> laneType = SimdTypeToLaneType(type());
+    DebugOnly<MIRType> laneType = SimdTypeToLaneArgumentType(type());
     bool allConstants = true;
     bool allSame = true;
 
     for (size_t i = 0; i < 4; ++i) {
         MDefinition* op = getOperand(i);
         MOZ_ASSERT(op->type() == laneType);
         if (!op->isConstantValue())
             allConstants = false;
@@ -920,16 +920,23 @@ MSimdValueX4::foldsTo(TempAllocator& all
     }
 
     if (!allConstants && !allSame)
         return this;
 
     if (allConstants) {
         SimdConstant cst;
         switch (type()) {
+          case MIRType_Bool32x4: {
+            int32_t a[4];
+            for (size_t i = 0; i < 4; ++i)
+                a[i] = getOperand(i)->constantToBoolean() ? -1 : 0;
+            cst = SimdConstant::CreateX4(a);
+            break;
+          }
           case MIRType_Int32x4: {
             int32_t a[4];
             for (size_t i = 0; i < 4; ++i)
                 a[i] = getOperand(i)->constantValue().toInt32();
             cst = SimdConstant::CreateX4(a);
             break;
           }
           case MIRType_Float32x4: {
@@ -947,38 +954,37 @@ MSimdValueX4::foldsTo(TempAllocator& all
 
     MOZ_ASSERT(allSame);
     return MSimdSplatX4::New(alloc, getOperand(0), type());
 }
 
 MDefinition*
 MSimdSplatX4::foldsTo(TempAllocator& alloc)
 {
-    DebugOnly<MIRType> laneType = SimdTypeToLaneType(type());
+    DebugOnly<MIRType> laneType = SimdTypeToLaneArgumentType(type());
     MDefinition* op = getOperand(0);
     if (!op->isConstantValue())
         return this;
     MOZ_ASSERT(op->type() == laneType);
 
     SimdConstant cst;
     switch (type()) {
+      case MIRType_Bool32x4: {
+        int32_t v = op->constantToBoolean() ? -1 : 0;
+        cst = SimdConstant::SplatX4(v);
+        break;
+      }
       case MIRType_Int32x4: {
-        int32_t a[4];
-        int32_t v = getOperand(0)->constantValue().toInt32();
-        for (size_t i = 0; i < 4; ++i)
-            a[i] = v;
-        cst = SimdConstant::CreateX4(a);
+        int32_t v = op->constantValue().toInt32();
+        cst = SimdConstant::SplatX4(v);
         break;
       }
       case MIRType_Float32x4: {
-        float a[4];
-        float v = getOperand(0)->constantValue().toNumber();
-        for (size_t i = 0; i < 4; ++i)
-            a[i] = v;
-        cst = SimdConstant::CreateX4(a);
+        float v = op->constantValue().toNumber();
+        cst = SimdConstant::SplatX4(v);
         break;
       }
       default: MOZ_CRASH("unexpected type in MSimdSplatX4::foldsTo");
     }
 
     return MSimdConstant::New(alloc, cst, type());
 }
 
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -1396,17 +1396,17 @@ class MSimdValueX4
                              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> laneType = SimdTypeToLaneType(type);
+        mozilla::DebugOnly<MIRType> laneType = SimdTypeToLaneArgumentType(type);
         MOZ_ASSERT(laneType == x->type());
         MOZ_ASSERT(laneType == y->type());
         MOZ_ASSERT(laneType == z->type());
         MOZ_ASSERT(laneType == w->type());
         return MSimdValueX4::New(alloc, type, x, y, z, w);
     }
 
     bool canConsumeFloat32(MUse* use) const override {
@@ -1440,17 +1440,17 @@ class MSimdSplatX4
         setResultType(type);
     }
 
   public:
     INSTRUCTION_HEADER(SimdSplatX4)
 
     static MSimdSplatX4* NewAsmJS(TempAllocator& alloc, MDefinition* v, MIRType type)
     {
-        MOZ_ASSERT(SimdTypeToLaneType(type) == v->type());
+        MOZ_ASSERT(SimdTypeToLaneArgumentType(type) == v->type());
         return new(alloc) MSimdSplatX4(type, v);
     }
 
     static MSimdSplatX4* New(TempAllocator& alloc, MDefinition* v, MIRType type)
     {
         return new(alloc) MSimdSplatX4(type, v);
     }
 
@@ -1488,16 +1488,19 @@ class MSimdConstant
     INSTRUCTION_HEADER(SimdConstant)
     static MSimdConstant* New(TempAllocator& alloc, const SimdConstant& v, MIRType type) {
         return new(alloc) MSimdConstant(v, type);
     }
 
     bool congruentTo(const MDefinition* ins) const override {
         if (!ins->isSimdConstant())
             return false;
+        // Bool32x4 and Int32x4 share the same underlying SimdConstant representation.
+        if (type() != ins->type())
+            return false;
         return value() == ins->toSimdConstant()->value();
     }
 
     const SimdConstant& value() const {
         return value_;
     }
 
     AliasSet getAliasSet() const override {
@@ -1597,17 +1600,20 @@ class MSimdExtractElement
     SimdLane lane_;
 
     MSimdExtractElement(MDefinition* obj, MIRType vecType, MIRType laneType, SimdLane lane)
       : MUnaryInstruction(obj), lane_(lane)
     {
         MOZ_ASSERT(IsSimdType(vecType));
         MOZ_ASSERT(uint32_t(lane) < SimdTypeToLength(vecType));
         MOZ_ASSERT(!IsSimdType(laneType));
-        MOZ_ASSERT(SimdTypeToLaneType(vecType) == laneType);
+        // The resulting type should match the lane type.
+        // Allow extracting boolean lanes directly into an Int32 (for asm.js).
+        MOZ_ASSERT(SimdTypeToLaneType(vecType) == laneType ||
+                   (IsBooleanSimdType(vecType) && laneType == MIRType_Int32));
 
         setMovable();
         specialization_ = vecType;
         setResultType(laneType);
     }
 
   public:
     INSTRUCTION_HEADER(SimdExtractElement)
@@ -1660,17 +1666,17 @@ class MSimdInsertElement
 
   public:
     INSTRUCTION_HEADER(SimdInsertElement)
 
     static MSimdInsertElement* NewAsmJS(TempAllocator& alloc, MDefinition* vec, MDefinition* val,
                                          MIRType type, SimdLane lane)
     {
         MOZ_ASSERT(vec->type() == type);
-        MOZ_ASSERT(SimdTypeToLaneType(type) == val->type());
+        MOZ_ASSERT(SimdTypeToLaneArgumentType(type) == val->type());
         return new(alloc) MSimdInsertElement(vec, val, type, lane);
     }
 
     static MSimdInsertElement* New(TempAllocator& alloc, MDefinition* vec, MDefinition* val,
                                    MIRType type, SimdLane lane)
     {
         return new(alloc) MSimdInsertElement(vec, val, type, lane);
     }
@@ -1747,16 +1753,93 @@ class MSimdSignMask
         if (!ins->isSimdSignMask())
             return false;
         return congruentIfOperandsEqual(ins);
     }
 
     ALLOW_CLONE(MSimdSignMask)
 };
 
+// Returns true if all lanes are true.
+class MSimdAllTrue
+  : public MUnaryInstruction,
+    public SimdPolicy<0>::Data
+{
+  protected:
+    explicit MSimdAllTrue(MDefinition* obj, MIRType simdType, MIRType result)
+      : MUnaryInstruction(obj)
+    {
+        MOZ_ASSERT(result == MIRType_Boolean || result == MIRType_Int32);
+        setResultType(result);
+        specialization_ = simdType;
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(SimdAllTrue)
+
+    static MSimdAllTrue* NewAsmJS(TempAllocator& alloc, MDefinition* obj)
+    {
+        MOZ_ASSERT(IsSimdType(obj->type()));
+        return new(alloc) MSimdAllTrue(obj, obj->type(), MIRType_Int32);
+    }
+
+    static MSimdAllTrue* New(TempAllocator& alloc, MDefinition* obj, MIRType type)
+    {
+        return new(alloc) MSimdAllTrue(obj, type, MIRType_Boolean);
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    ALLOW_CLONE(MSimdAllTrue)
+};
+
+// Returns true if any lane is true.
+class MSimdAnyTrue
+  : public MUnaryInstruction,
+    public SimdPolicy<0>::Data
+{
+  protected:
+    explicit MSimdAnyTrue(MDefinition* obj, MIRType simdType, MIRType result)
+      : MUnaryInstruction(obj)
+    {
+        MOZ_ASSERT(result == MIRType_Boolean || result == MIRType_Int32);
+        setResultType(result);
+        specialization_ = simdType;
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(SimdAnyTrue)
+
+    static MSimdAnyTrue* NewAsmJS(TempAllocator& alloc, MDefinition* obj)
+    {
+        MOZ_ASSERT(IsSimdType(obj->type()));
+        return new(alloc) MSimdAnyTrue(obj, obj->type(), MIRType_Int32);
+    }
+
+    static MSimdAnyTrue* New(TempAllocator& alloc, MDefinition* obj, MIRType type)
+    {
+        return new(alloc) MSimdAnyTrue(obj, type, MIRType_Boolean);
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+
+    ALLOW_CLONE(MSimdAnyTrue)
+};
+
 // Base for the MSimdSwizzle and MSimdShuffle classes.
 class MSimdShuffleBase
 {
   protected:
     // As of now, there are at most 4 lanes. For each lane, we need to know
     // which input we choose and which of the 4 lanes we choose; that can be
     // packed in 3 bits for each lane, so 12 bits in total.
     uint32_t laneMask_;
@@ -2044,36 +2127,36 @@ class MSimdUnaryArith
 // the comparison: all bits are set to 1 if the comparison is true, 0 otherwise.
 class MSimdBinaryComp
   : public MBinaryInstruction,
     public SimdAllPolicy::Data
 {
   public:
     enum Operation {
 #define NAME_(x) x,
-        COMP_COMMONX4_TO_INT32X4_SIMD_OP(NAME_)
+        COMP_COMMONX4_TO_BOOL32X4_SIMD_OP(NAME_)
 #undef NAME_
     };
 
     static const char* OperationName(Operation op) {
         switch (op) {
 #define NAME_(x) case x: return #x;
-        COMP_COMMONX4_TO_INT32X4_SIMD_OP(NAME_)
+        COMP_COMMONX4_TO_BOOL32X4_SIMD_OP(NAME_)
 #undef NAME_
         }
         MOZ_CRASH("unexpected operation");
     }
 
   private:
     Operation operation_;
 
     MSimdBinaryComp(MDefinition* left, MDefinition* right, Operation op, MIRType opType)
       : MBinaryInstruction(left, right), operation_(op)
     {
-        setResultType(MIRType_Int32x4);
+        setResultType(MIRType_Bool32x4);
         specialization_ = opType;
         setMovable();
         if (op == equal || op == notEqual)
             setCommutative();
     }
 
   public:
     INSTRUCTION_HEADER(SimdBinaryComp)
@@ -2339,17 +2422,17 @@ class MSimdSelect
         setMovable();
     }
 
   public:
     INSTRUCTION_HEADER(SimdSelect)
     static MSimdSelect* NewAsmJS(TempAllocator& alloc, MDefinition* mask, MDefinition* lhs,
                                  MDefinition* rhs, MIRType t, bool isElementWise)
     {
-        MOZ_ASSERT(mask->type() == MIRType_Int32x4);
+        MOZ_ASSERT(mask->type() == (isElementWise ? MIRType_Bool32x4 : t));
         MOZ_ASSERT(lhs->type() == rhs->type());
         MOZ_ASSERT(lhs->type() == t);
         return new(alloc) MSimdSelect(mask, lhs, rhs, t, isElementWise);
     }
 
     static MSimdSelect* New(TempAllocator& alloc, MDefinition* mask, MDefinition* lhs,
                             MDefinition* rhs, MIRType t, bool isElementWise)
     {
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -26,16 +26,18 @@ namespace jit {
     _(SimdGeneralShuffle)                                                   \
     _(SimdShuffle)                                                          \
     _(SimdUnaryArith)                                                       \
     _(SimdBinaryComp)                                                       \
     _(SimdBinaryArith)                                                      \
     _(SimdBinaryBitwise)                                                    \
     _(SimdShift)                                                            \
     _(SimdSelect)                                                           \
+    _(SimdAllTrue)                                                          \
+    _(SimdAnyTrue)                                                          \
     _(CloneLiteral)                                                         \
     _(Parameter)                                                            \
     _(Callee)                                                               \
     _(IsConstructing)                                                       \
     _(TableSwitch)                                                          \
     _(Goto)                                                                 \
     _(Test)                                                                 \
     _(GotoWithFake)                                                         \
--- a/js/src/jit/Recover.cpp
+++ b/js/src/jit/Recover.cpp
@@ -1334,16 +1334,21 @@ RSimdBox::RSimdBox(CompactBufferReader& 
 bool
 RSimdBox::recover(JSContext* cx, SnapshotIterator& iter) const
 {
     JSObject* resultObject = nullptr;
     RValueAllocation a = iter.readAllocation();
     MOZ_ASSERT(iter.allocationReadable(a));
     const FloatRegisters::RegisterContent* raw = iter.floatAllocationPointer(a);
     switch (SimdTypeDescr::Type(type_)) {
+      case SimdTypeDescr::Bool32x4:
+        MOZ_ASSERT_IF(a.mode() == RValueAllocation::ANY_FLOAT_REG,
+                      a.fpuReg().isSimd128());
+        resultObject = js::CreateSimd<Bool32x4>(cx, (const Bool32x4::Elem*) raw);
+        break;
       case SimdTypeDescr::Int32x4:
         MOZ_ASSERT_IF(a.mode() == RValueAllocation::ANY_FLOAT_REG,
                       a.fpuReg().isSimd128());
         resultObject = js::CreateSimd<Int32x4>(cx, (const Int32x4::Elem*) raw);
         break;
       case SimdTypeDescr::Float32x4:
         MOZ_ASSERT_IF(a.mode() == RValueAllocation::ANY_FLOAT_REG,
                       a.fpuReg().isSimd128());
@@ -1359,19 +1364,16 @@ RSimdBox::recover(JSContext* cx, Snapsho
         MOZ_CRASH("NYI, RSimdBox of Int16x8");
         break;
       case SimdTypeDescr::Bool8x16:
         MOZ_CRASH("NYI, RSimdBox of Bool8x16");
         break;
       case SimdTypeDescr::Bool16x8:
         MOZ_CRASH("NYI, RSimdBox of Bool16x8");
         break;
-      case SimdTypeDescr::Bool32x4:
-        MOZ_CRASH("NYI, RSimdBox of Bool32x4");
-        break;
       case SimdTypeDescr::Bool64x2:
         MOZ_CRASH("NYI, RSimdBox of Bool64x2");
         break;
     }
 
     if (!resultObject)
         return false;
 
--- a/js/src/jit/TypePolicy.cpp
+++ b/js/src/jit/TypePolicy.cpp
@@ -565,16 +565,25 @@ template bool NoFloatPolicyAfter<2>::adj
 template <unsigned Op>
 bool
 SimdScalarPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins)
 {
     MOZ_ASSERT(IsSimdType(ins->type()));
     MIRType laneType = SimdTypeToLaneType(ins->type());
 
     MDefinition* in = ins->getOperand(Op);
+
+    // A vector with boolean lanes requires Int32 inputs that have already been
+    // converted to 0/-1.
+    // We can't insert a MIRType_Boolean lane directly - it requires conversion.
+    if (laneType == MIRType_Boolean) {
+        MOZ_ASSERT(in->type() == MIRType_Int32, "Boolean SIMD vector requires Int32 lanes.");
+        return true;
+    }
+
     if (in->type() == laneType)
         return true;
 
     MInstruction* replace;
     if (laneType == MIRType_Int32) {
         replace = MTruncateToInt32::New(alloc, in);
     } else {
         MOZ_ASSERT(laneType == MIRType_Float32);
@@ -852,18 +861,18 @@ SimdShufflePolicy::adjustInputs(TempAllo
     return true;
 }
 
 bool
 SimdSelectPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
 {
     MIRType specialization = ins->typePolicySpecialization();
 
-    // First input is the mask, which has to be an int32x4 (for now).
-    if (!MaybeSimdUnbox(alloc, ins, MIRType_Int32x4, 0))
+    // First input is the mask, which has to be a bool32x4.
+    if (!MaybeSimdUnbox(alloc, ins, MIRType_Bool32x4, 0))
         return false;
 
     // Next inputs are the two vectors of a particular type.
     for (unsigned i = 1; i < 3; i++) {
         if (!MaybeSimdUnbox(alloc, ins, specialization, i))
             return false;
     }
 
--- a/js/src/jit/shared/CodeGenerator-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -453,16 +453,17 @@ CodeGeneratorShared::encodeAllocation(LS
             alloc = RValueAllocation::Typed(valueType, ToStackIndex(payload));
         else if (payload->isGeneralReg())
             alloc = RValueAllocation::Typed(valueType, ToRegister(payload));
         else if (payload->isFloatReg())
             alloc = RValueAllocation::Double(ToFloatRegister(payload));
         break;
       }
       case MIRType_Float32:
+      case MIRType_Bool32x4:
       case MIRType_Int32x4:
       case MIRType_Float32x4:
       {
         LAllocation* payload = snapshot->payloadOfSlot(*allocIndex);
         if (payload->isConstant()) {
             MConstant* constant = mir->toConstant();
             uint32_t index;
             masm.propagateOOM(graph.addConstantToPool(constant->value(), &index));
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -245,25 +245,36 @@ class LSimdExtractElementBase : public L
           case LaneY: return "lane y";
           case LaneZ: return "lane z";
           case LaneW: return "lane w";
         }
         return "unknown lane";
     }
 };
 
+// Extracts an element from a given SIMD bool32x4 lane.
+class LSimdExtractElementB : public LSimdExtractElementBase
+{
+  public:
+    LIR_HEADER(SimdExtractElementB);
+    explicit LSimdExtractElementB(const LAllocation& base)
+      : LSimdExtractElementBase(base)
+    {}
+};
+
 // Extracts an element from a given SIMD int32x4 lane.
 class LSimdExtractElementI : public LSimdExtractElementBase
 {
   public:
     LIR_HEADER(SimdExtractElementI);
     explicit LSimdExtractElementI(const LAllocation& base)
       : LSimdExtractElementBase(base)
     {}
 };
+
 // Extracts an element from a given SIMD float32x4 lane.
 class LSimdExtractElementF : public LSimdExtractElementBase
 {
   public:
     LIR_HEADER(SimdExtractElementF);
     explicit LSimdExtractElementF(const LAllocation& base)
       : LSimdExtractElementBase(base)
     {}
@@ -288,17 +299,18 @@ class LSimdInsertElementBase : public LI
     SimdLane lane() const {
         return mir_->toSimdInsertElement()->lane();
     }
     const char* extraName() const {
         return MSimdInsertElement::LaneName(lane());
     }
 };
 
-// Replace an element from a given SIMD int32x4 lane with a given value.
+// Replace an element from a given SIMD integer or boolean lane with a given value.
+// The value inserted into a boolean lane should be 0 or -1.
 class LSimdInsertElementI : public LSimdInsertElementBase
 {
   public:
     LIR_HEADER(SimdInsertElementI);
     LSimdInsertElementI(const LAllocation& vec, const LAllocation& val)
       : LSimdInsertElementBase(vec, val)
     {}
 };
@@ -601,16 +613,47 @@ class LSimdSelect : public LInstructionH
     const LDefinition* temp() {
         return getTemp(0);
     }
     MSimdSelect* mir() const {
         return mir_->toSimdSelect();
     }
 };
 
+class LSimdAnyTrue : public LInstructionHelper<1, 1, 0>
+{
+  public:
+    LIR_HEADER(SimdAnyTrue)
+    explicit LSimdAnyTrue(const LAllocation& input) {
+        setOperand(0, input);
+    }
+    const LAllocation* vector() {
+        return getOperand(0);
+    }
+    MSimdAnyTrue* mir() const {
+        return mir_->toSimdAnyTrue();
+    }
+};
+
+class LSimdAllTrue : public LInstructionHelper<1, 1, 0>
+{
+  public:
+    LIR_HEADER(SimdAllTrue)
+    explicit LSimdAllTrue(const LAllocation& input) {
+        setOperand(0, input);
+    }
+    const LAllocation* vector() {
+        return getOperand(0);
+    }
+    MSimdAllTrue* mir() const {
+        return mir_->toSimdAllTrue();
+    }
+};
+
+
 // Constant 32-bit integer.
 class LInteger : public LInstructionHelper<1, 0, 0>
 {
     int32_t i32_;
 
   public:
     LIR_HEADER(Integer)
 
@@ -688,27 +731,27 @@ class LFloat32 : public LInstructionHelp
       : f_(f)
     { }
 
     float getFloat() const {
         return f_;
     }
 };
 
-// Constant SIMD int32x4
+// Constant SIMD int32x4. Also used for bool32x4.
 class LInt32x4 : public LInstructionHelper<1, 0, 0>
 {
   public:
     LIR_HEADER(Int32x4);
 
     explicit LInt32x4() {}
     const SimdConstant& getValue() const { return mir_->toSimdConstant()->value(); }
 };
 
-// Constant SIMD float32x4
+// Constant SIMD float32x4.
 class LFloat32x4 : public LInstructionHelper<1, 0, 0>
 {
   public:
     LIR_HEADER(Float32x4);
 
     explicit LFloat32x4() {}
     const SimdConstant& getValue() const { return mir_->toSimdConstant()->value(); }
 };
--- a/js/src/jit/shared/LOpcodes-shared.h
+++ b/js/src/jit/shared/LOpcodes-shared.h
@@ -17,18 +17,21 @@
     _(Pointer)                      \
     _(Double)                       \
     _(Float32)                      \
     _(SimdBox)                      \
     _(SimdUnbox)                    \
     _(SimdSplatX4)                  \
     _(Int32x4)                      \
     _(Float32x4)                    \
+    _(SimdAllTrue)                  \
+    _(SimdAnyTrue)                  \
     _(SimdReinterpretCast)          \
     _(SimdExtractElementI)          \
+    _(SimdExtractElementB)          \
     _(SimdExtractElementF)          \
     _(SimdInsertElementI)           \
     _(SimdInsertElementF)           \
     _(SimdSignMaskX4)               \
     _(SimdGeneralShuffleI)          \
     _(SimdGeneralShuffleF)          \
     _(SimdSwizzleI)                 \
     _(SimdSwizzleF)                 \
--- a/js/src/jit/shared/Lowering-shared-inl.h
+++ b/js/src/jit/shared/Lowering-shared-inl.h
@@ -154,16 +154,17 @@ LIRGeneratorShared::defineReturn(LInstru
 #endif
         break;
       case MIRType_Float32:
         lir->setDef(0, LDefinition(vreg, LDefinition::FLOAT32, LFloatReg(ReturnFloat32Reg)));
         break;
       case MIRType_Double:
         lir->setDef(0, LDefinition(vreg, LDefinition::DOUBLE, LFloatReg(ReturnDoubleReg)));
         break;
+      case MIRType_Bool32x4:
       case MIRType_Int32x4:
         lir->setDef(0, LDefinition(vreg, LDefinition::INT32X4, LFloatReg(ReturnSimd128Reg)));
         break;
       case MIRType_Float32x4:
         lir->setDef(0, LDefinition(vreg, LDefinition::FLOAT32X4, LFloatReg(ReturnSimd128Reg)));
         break;
       default:
         LDefinition::Type type = LDefinition::TypeFrom(mir->type());
--- a/js/src/jit/x64/Assembler-x64.cpp
+++ b/js/src/jit/x64/Assembler-x64.cpp
@@ -49,16 +49,17 @@ ABIArgGenerator::next(MIRType type)
         current_ = ABIArg(IntArgRegs[regIndex_++]);
         break;
       case MIRType_Float32:
         current_ = ABIArg(FloatArgRegs[regIndex_++].asSingle());
         break;
       case MIRType_Double:
         current_ = ABIArg(FloatArgRegs[regIndex_++]);
         break;
+      case MIRType_Bool32x4:
       case MIRType_Int32x4:
       case MIRType_Float32x4:
         // On Win64, >64 bit args need to be passed by reference, but asm.js
         // doesn't allow passing SIMD values to FFIs. The only way to reach
         // here is asm to asm calls, so we can break the ABI here.
         current_ = ABIArg(FloatArgRegs[regIndex_++].asSimd128());
         break;
       default:
@@ -83,16 +84,17 @@ ABIArgGenerator::next(MIRType type)
             stackOffset_ += sizeof(uint64_t);
             break;
         }
         if (type == MIRType_Float32)
             current_ = ABIArg(FloatArgRegs[floatRegIndex_++].asSingle());
         else
             current_ = ABIArg(FloatArgRegs[floatRegIndex_++]);
         break;
+      case MIRType_Bool32x4:
       case MIRType_Int32x4:
       case MIRType_Float32x4:
         if (floatRegIndex_ == NumFloatArgRegs) {
             stackOffset_ = AlignBytes(stackOffset_, SimdMemoryAlignment);
             current_ = ABIArg(stackOffset_);
             stackOffset_ += Simd128DataSize;
             break;
         }
--- a/js/src/jit/x64/CodeGenerator-x64.cpp
+++ b/js/src/jit/x64/CodeGenerator-x64.cpp
@@ -746,16 +746,17 @@ CodeGeneratorX64::visitAsmJSLoadGlobalVa
         label = masm.loadRipRelativeFloat32(ToFloatRegister(ins->output()));
         break;
       case MIRType_Double:
         label = masm.loadRipRelativeDouble(ToFloatRegister(ins->output()));
         break;
       // Aligned access: code is aligned on PageSize + there is padding
       // before the global data section.
       case MIRType_Int32x4:
+      case MIRType_Bool32x4:
         label = masm.loadRipRelativeInt32x4(ToFloatRegister(ins->output()));
         break;
       case MIRType_Float32x4:
         label = masm.loadRipRelativeFloat32x4(ToFloatRegister(ins->output()));
         break;
       default:
         MOZ_CRASH("unexpected type in visitAsmJSLoadGlobalVar");
     }
@@ -780,16 +781,17 @@ CodeGeneratorX64::visitAsmJSStoreGlobalV
         label = masm.storeRipRelativeFloat32(ToFloatRegister(ins->value()));
         break;
       case MIRType_Double:
         label = masm.storeRipRelativeDouble(ToFloatRegister(ins->value()));
         break;
       // Aligned access: code is aligned on PageSize + there is padding
       // before the global data section.
       case MIRType_Int32x4:
+      case MIRType_Bool32x4:
         label = masm.storeRipRelativeInt32x4(ToFloatRegister(ins->value()));
         break;
       case MIRType_Float32x4:
         label = masm.storeRipRelativeFloat32x4(ToFloatRegister(ins->value()));
         break;
       default:
         MOZ_CRASH("unexpected type in visitAsmJSStoreGlobalVar");
     }
--- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
@@ -282,16 +282,17 @@ CodeGeneratorX86Shared::visitAsmJSPassSt
             switch (mir->input()->type()) {
               case MIRType_Double:
               case MIRType_Float32:
                 masm.storeDouble(ToFloatRegister(ins->arg()), dst);
                 return;
               // StackPointer is SIMD-aligned and ABIArgGenerator guarantees
               // stack offsets are SIMD-aligned.
               case MIRType_Int32x4:
+              case MIRType_Bool32x4:
                 masm.storeAlignedInt32x4(ToFloatRegister(ins->arg()), dst);
                 return;
               case MIRType_Float32x4:
                 masm.storeAlignedFloat32x4(ToFloatRegister(ins->arg()), dst);
                 return;
               default: break;
             }
             MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected mir type in AsmJSPassStackArg");
@@ -2303,17 +2304,17 @@ CodeGeneratorX86Shared::visitOutOfLineSi
         masm.bind(&bail);
         bailout(ool->ins()->snapshot());
     }
 }
 
 void
 CodeGeneratorX86Shared::visitSimdValueInt32x4(LSimdValueInt32x4* ins)
 {
-    MOZ_ASSERT(ins->mir()->type() == MIRType_Int32x4);
+    MOZ_ASSERT(ins->mir()->type() == MIRType_Int32x4 || ins->mir()->type() == MIRType_Bool32x4);
 
     FloatRegister output = ToFloatRegister(ins->output());
     if (AssemblerX86Shared::HasSSE41()) {
         masm.vmovd(ToRegister(ins->getOperand(0)), output);
         for (size_t i = 1; i < 4; ++i) {
             Register r = ToRegister(ins->getOperand(i));
             masm.vpinsrd(i, r, output, output);
         }
@@ -2354,17 +2355,18 @@ CodeGeneratorX86Shared::visitSimdSplatX4
 {
     FloatRegister output = ToFloatRegister(ins->output());
 
     MSimdSplatX4* mir = ins->mir();
     MOZ_ASSERT(IsSimdType(mir->type()));
     JS_STATIC_ASSERT(sizeof(float) == sizeof(int32_t));
 
     switch (mir->type()) {
-      case MIRType_Int32x4: {
+      case MIRType_Int32x4:
+      case MIRType_Bool32x4: {
         Register r = ToRegister(ins->getOperand(0));
         masm.vmovd(r, output);
         masm.vpshufd(0, output, output);
         break;
       }
       case MIRType_Float32x4: {
         FloatRegister r = ToFloatRegister(ins->getOperand(0));
         FloatRegister rCopy = masm.reusedInputFloat32x4(r, output);
@@ -2393,16 +2395,38 @@ CodeGeneratorX86Shared::visitSimdReinter
         masm.vmovaps(input, output);
         break;
       default:
         MOZ_CRASH("Unknown SIMD kind");
     }
 }
 
 void
+CodeGeneratorX86Shared::visitSimdExtractElementB(LSimdExtractElementB* ins)
+{
+    FloatRegister input = ToFloatRegister(ins->input());
+    Register output = ToRegister(ins->output());
+
+    SimdLane lane = ins->lane();
+    if (lane == LaneX) {
+        // The value we want to extract is in the low double-word
+        masm.moveLowInt32(input, output);
+    } else if (AssemblerX86Shared::HasSSE41()) {
+        masm.vpextrd(lane, input, output);
+    } else {
+        uint32_t mask = MacroAssembler::ComputeShuffleMask(lane);
+        masm.shuffleInt32(mask, input, ScratchSimd128Reg);
+        masm.moveLowInt32(ScratchSimd128Reg, output);
+    }
+
+    // We need to generate a 0/1 value. We have 0/-1.
+    masm.and32(Imm32(1), output);
+}
+
+void
 CodeGeneratorX86Shared::visitSimdExtractElementI(LSimdExtractElementI* ins)
 {
     FloatRegister input = ToFloatRegister(ins->input());
     Register output = ToRegister(ins->output());
 
     SimdLane lane = ins->lane();
     if (lane == LaneX) {
         // The value we want to extract is in the low double-word
@@ -2503,16 +2527,38 @@ CodeGeneratorX86Shared::visitSimdSignMas
 {
     FloatRegister input = ToFloatRegister(ins->input());
     Register output = ToRegister(ins->output());
 
     // For Float32x4 and Int32x4.
     masm.vmovmskps(input, output);
 }
 
+void
+CodeGeneratorX86Shared::visitSimdAllTrue(LSimdAllTrue* ins)
+{
+    FloatRegister input = ToFloatRegister(ins->input());
+    Register output = ToRegister(ins->output());
+
+    masm.vmovmskps(input, output);
+    masm.cmp32(output, Imm32(0xf));
+    masm.emitSet(Assembler::Zero, output);
+}
+
+void
+CodeGeneratorX86Shared::visitSimdAnyTrue(LSimdAnyTrue* ins)
+{
+    FloatRegister input = ToFloatRegister(ins->input());
+    Register output = ToRegister(ins->output());
+
+    masm.vmovmskps(input, output);
+    masm.cmp32(output, Imm32(0x0));
+    masm.emitSet(Assembler::NonZero, output);
+}
+
 template <class T, class Reg> void
 CodeGeneratorX86Shared::visitSimdGeneralShuffle(LSimdGeneralShuffleBase* ins, Reg tempRegister)
 {
     MSimdGeneralShuffle* mir = ins->mir();
     unsigned numVectors = mir->numVectors();
 
     Register laneTemp = ToRegister(ins->temp());
 
--- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.h
+++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.h
@@ -257,16 +257,17 @@ class CodeGeneratorX86Shared : public Co
     void visitSimdValueInt32x4(LSimdValueInt32x4* lir);
     void visitSimdValueFloat32x4(LSimdValueFloat32x4* lir);
     void visitSimdSplatX4(LSimdSplatX4* lir);
     void visitInt32x4(LInt32x4* ins);
     void visitFloat32x4(LFloat32x4* ins);
     void visitInt32x4ToFloat32x4(LInt32x4ToFloat32x4* ins);
     void visitFloat32x4ToInt32x4(LFloat32x4ToInt32x4* ins);
     void visitSimdReinterpretCast(LSimdReinterpretCast* lir);
+    void visitSimdExtractElementB(LSimdExtractElementB* lir);
     void visitSimdExtractElementI(LSimdExtractElementI* lir);
     void visitSimdExtractElementF(LSimdExtractElementF* lir);
     void visitSimdInsertElementI(LSimdInsertElementI* lir);
     void visitSimdInsertElementF(LSimdInsertElementF* lir);
     void visitSimdSignMaskX4(LSimdSignMaskX4* ins);
     void visitSimdSwizzleI(LSimdSwizzleI* lir);
     void visitSimdSwizzleF(LSimdSwizzleF* lir);
     void visitSimdShuffle(LSimdShuffle* lir);
@@ -274,16 +275,18 @@ class CodeGeneratorX86Shared : public Co
     void visitSimdUnaryArithFx4(LSimdUnaryArithFx4* lir);
     void visitSimdBinaryCompIx4(LSimdBinaryCompIx4* lir);
     void visitSimdBinaryCompFx4(LSimdBinaryCompFx4* lir);
     void visitSimdBinaryArithIx4(LSimdBinaryArithIx4* lir);
     void visitSimdBinaryArithFx4(LSimdBinaryArithFx4* lir);
     void visitSimdBinaryBitwiseX4(LSimdBinaryBitwiseX4* lir);
     void visitSimdShift(LSimdShift* lir);
     void visitSimdSelect(LSimdSelect* ins);
+    void visitSimdAllTrue(LSimdAllTrue* ins);
+    void visitSimdAnyTrue(LSimdAnyTrue* ins);
 
     template <class T, class Reg> void visitSimdGeneralShuffle(LSimdGeneralShuffleBase* lir, Reg temp);
     void visitSimdGeneralShuffleI(LSimdGeneralShuffleI* lir);
     void visitSimdGeneralShuffleF(LSimdGeneralShuffleF* lir);
 
     // Out of line visitors.
     void visitOutOfLineBailout(OutOfLineBailout* ool);
     void visitOutOfLineUndoALUOperation(OutOfLineUndoALUOperation* ool);
--- a/js/src/jit/x86-shared/Lowering-x86-shared.cpp
+++ b/js/src/jit/x86-shared/Lowering-x86-shared.cpp
@@ -634,16 +634,17 @@ LIRGeneratorX86Shared::visitSimdSelect(M
 void
 LIRGeneratorX86Shared::visitSimdSplatX4(MSimdSplatX4* ins)
 {
     LAllocation x = useRegisterAtStart(ins->getOperand(0));
     LSimdSplatX4* lir = new(alloc()) LSimdSplatX4(x);
 
     switch (ins->type()) {
       case MIRType_Int32x4:
+      case MIRType_Bool32x4:
         define(lir, ins);
         break;
       case MIRType_Float32x4:
         // (Non-AVX) codegen actually wants the input and the output to be in
         // the same register, but we can't currently use defineReuseInput
         // because they have different types (scalar vs vector), so a spill slot
         // for one may not be suitable for the other.
         define(lir, ins);
@@ -651,29 +652,35 @@ LIRGeneratorX86Shared::visitSimdSplatX4(
       default:
         MOZ_CRASH("Unknown SIMD kind");
     }
 }
 
 void
 LIRGeneratorX86Shared::visitSimdValueX4(MSimdValueX4* ins)
 {
-    if (ins->type() == MIRType_Float32x4) {
+    switch (ins->type()) {
+      case MIRType_Float32x4: {
         // Ideally, x would be used at start and reused for the output, however
         // register allocation currently doesn't permit us to tie together two
         // virtual registers with different types.
         LAllocation x = useRegister(ins->getOperand(0));
         LAllocation y = useRegister(ins->getOperand(1));
         LAllocation z = useRegister(ins->getOperand(2));
         LAllocation w = useRegister(ins->getOperand(3));
         LDefinition t = temp(LDefinition::FLOAT32X4);
         define(new (alloc()) LSimdValueFloat32x4(x, y, z, w, t), ins);
-    } else {
-        MOZ_ASSERT(ins->type() == MIRType_Int32x4);
-
+        break;
+      }
+      case MIRType_Bool32x4:
+      case MIRType_Int32x4: {
         // No defineReuseInput => useAtStart for everyone.
         LAllocation x = useRegisterAtStart(ins->getOperand(0));
         LAllocation y = useRegisterAtStart(ins->getOperand(1));
         LAllocation z = useRegisterAtStart(ins->getOperand(2));
         LAllocation w = useRegisterAtStart(ins->getOperand(3));
         define(new(alloc()) LSimdValueInt32x4(x, y, z, w), ins);
+        break;
+      }
+      default:
+        MOZ_CRASH("Unknown SIMD kind");
     }
 }
--- a/js/src/jit/x86/Assembler-x86.cpp
+++ b/js/src/jit/x86/Assembler-x86.cpp
@@ -27,16 +27,17 @@ ABIArgGenerator::next(MIRType type)
         break;
       case MIRType_Float32: // Float32 moves are actually double moves
       case MIRType_Double:
         current_ = ABIArg(stackOffset_);
         stackOffset_ += sizeof(uint64_t);
         break;
       case MIRType_Int32x4:
       case MIRType_Float32x4:
+      case MIRType_Bool32x4:
         // SIMD values aren't passed in or out of C++, so we can make up
         // whatever internal ABI we like. visitAsmJSPassArg assumes
         // SimdMemoryAlignment.
         stackOffset_ = AlignBytes(stackOffset_, SimdMemoryAlignment);
         current_ = ABIArg(stackOffset_);
         stackOffset_ += Simd128DataSize;
         break;
       default:
--- a/js/src/jit/x86/CodeGenerator-x86.cpp
+++ b/js/src/jit/x86/CodeGenerator-x86.cpp
@@ -787,16 +787,17 @@ CodeGeneratorX86::visitAsmJSLoadGlobalVa
         label = masm.vmovssWithPatch(PatchedAbsoluteAddress(), ToFloatRegister(ins->output()));
         break;
       case MIRType_Double:
         label = masm.vmovsdWithPatch(PatchedAbsoluteAddress(), ToFloatRegister(ins->output()));
         break;
       // Aligned access: code is aligned on PageSize + there is padding
       // before the global data section.
       case MIRType_Int32x4:
+      case MIRType_Bool32x4:
         label = masm.vmovdqaWithPatch(PatchedAbsoluteAddress(), ToFloatRegister(ins->output()));
         break;
       case MIRType_Float32x4:
         label = masm.vmovapsWithPatch(PatchedAbsoluteAddress(), ToFloatRegister(ins->output()));
         break;
       default:
         MOZ_CRASH("unexpected type in visitAsmJSLoadGlobalVar");
     }
@@ -820,16 +821,17 @@ CodeGeneratorX86::visitAsmJSStoreGlobalV
         label = masm.vmovssWithPatch(ToFloatRegister(ins->value()), PatchedAbsoluteAddress());
         break;
       case MIRType_Double:
         label = masm.vmovsdWithPatch(ToFloatRegister(ins->value()), PatchedAbsoluteAddress());
         break;
       // Aligned access: code is aligned on PageSize + there is padding
       // before the global data section.
       case MIRType_Int32x4:
+      case MIRType_Bool32x4:
         label = masm.vmovdqaWithPatch(ToFloatRegister(ins->value()), PatchedAbsoluteAddress());
         break;
       case MIRType_Float32x4:
         label = masm.vmovapsWithPatch(ToFloatRegister(ins->value()), PatchedAbsoluteAddress());
         break;
       default:
         MOZ_CRASH("unexpected type in visitAsmJSStoreGlobalVar");
     }