Bug 1244254 - Add IonBuilder::unboxSimd(). r=nbp
authorJakob Stoklund Olesen <jolesen@mozilla.com>
Tue, 09 Feb 2016 08:46:00 -0800
changeset 329863 dbf37b8608533bc4a652e0055618dd2b2080aeb2
parent 329862 3104d4155b1e9f2ec92286fcfa380dc5ba540f5f
child 329864 65c42ca17bc765a219d793c7e27be46bc8400a3e
push id10618
push userdmitchell@mozilla.com
push dateTue, 09 Feb 2016 17:40:09 +0000
reviewersnbp
bugs1244254
milestone47.0a1
Bug 1244254 - Add IonBuilder::unboxSimd(). r=nbp This helper function inserts an MUnboxSimd node which checks the arguments to an inlined SIMD operation. Use it for inlineSimdCheck() which now takes a SimdType argument. Also make inlineSimdCheck produce a value that is a box/unbox pair instead of simply returning its argument. This means that any SIMD type checking and unboxing will happen at the time the check() function is executed, rather than when its result is used. This is usually what you want.
js/src/jit/IonBuilder.h
js/src/jit/MCallOptimize.cpp
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -854,17 +854,18 @@ class IonBuilder
     InliningStatus inlineConstructTypedObject(CallInfo& callInfo, TypeDescr* target);
 
     // SIMD intrinsics and natives.
     InliningStatus inlineConstructSimdObject(CallInfo& callInfo, SimdTypeDescr* target);
 
     // SIMD helpers.
     bool canInlineSimd(CallInfo& callInfo, JSNative native, unsigned numArgs,
                        InlineTypedObject** templateObj);
-    IonBuilder::InliningStatus boxSimd(CallInfo& callInfo, MInstruction* ins,
+    MDefinition* unboxSimd(MDefinition* ins, SimdType type);
+    IonBuilder::InliningStatus boxSimd(CallInfo& callInfo, MDefinition* ins,
                                        InlineTypedObject* templateObj);
     MDefinition* convertToBooleanSimdLane(MDefinition* scalar);
 
     InliningStatus inlineSimd(CallInfo& callInfo, JSFunction* target, SimdType type);
 
     template <typename T>
     InliningStatus inlineSimdBinary(CallInfo& callInfo, JSNative native,
                                     typename T::Operation op, MIRType mirType);
@@ -874,17 +875,17 @@ class IonBuilder
     InliningStatus inlineSimdUnary(CallInfo& callInfo, JSNative native,
                                    MSimdUnaryArith::Operation op, MIRType mirType);
     InliningStatus inlineSimdExtractLane(CallInfo& callInfo, JSNative native,
                                          MIRType vecType, SimdSign sign);
     InliningStatus inlineSimdReplaceLane(CallInfo& callInfo, JSNative native, MIRType mirType);
     InliningStatus inlineSimdSplat(CallInfo& callInfo, JSNative native, MIRType mirType);
     InliningStatus inlineSimdShuffle(CallInfo& callInfo, JSNative native, MIRType type,
                                      unsigned numVectors, unsigned numLanes);
-    InliningStatus inlineSimdCheck(CallInfo& callInfo, JSNative native, MIRType type);
+    InliningStatus inlineSimdCheck(CallInfo& callInfo, JSNative native, SimdType type);
     InliningStatus inlineSimdConvert(CallInfo& callInfo, JSNative native, bool isCast,
                                      MIRType from, MIRType to,
                                      SimdSign sign = SimdSign::NotApplicable);
     InliningStatus inlineSimdSelect(CallInfo& callInfo, JSNative native, MIRType type);
 
     bool prepareForSimdLoadStore(CallInfo& callInfo, Scalar::Type simdType, MInstruction** elements,
                                  MDefinition** index, Scalar::Type* arrayType);
     InliningStatus inlineSimdLoad(CallInfo& callInfo, JSNative native, MIRType type,
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -3079,17 +3079,17 @@ IonBuilder::inlineSimd(CallInfo& callInf
 
     switch(simdOp) {
       case SimdOperation::Constructor:
         // SIMD constructor calls are handled via inlineNonFunctionCall(), so
         // they won't show up here where target is required to be a JSFunction.
         // See also inlineConstructSimdObject().
         MOZ_CRASH("SIMD constructor call not expected.");
       case SimdOperation::Fn_check:
-        return inlineSimdCheck(callInfo, native, simdType);
+        return inlineSimdCheck(callInfo, native, type);
       case SimdOperation::Fn_splat:
         return inlineSimdSplat(callInfo, native, simdType);
       case SimdOperation::Fn_extractLane:
         return inlineSimdExtractLane(callInfo, native, simdType, sign);
       case SimdOperation::Fn_replaceLane:
         return inlineSimdReplaceLane(callInfo, native, simdType);
       case SimdOperation::Fn_select:
         return inlineSimdSelect(callInfo, native, simdType);
@@ -3343,39 +3343,64 @@ IonBuilder::canInlineSimd(CallInfo& call
     if (!templateObject)
         return false;
 
     *templateObj = &templateObject->as<InlineTypedObject>();
     return true;
 }
 
 IonBuilder::InliningStatus
-IonBuilder::inlineSimdCheck(CallInfo& callInfo, JSNative native, MIRType mirType)
+IonBuilder::inlineSimdCheck(CallInfo& callInfo, JSNative native, SimdType type)
 {
     InlineTypedObject* templateObj = nullptr;
     if (!canInlineSimd(callInfo, native, 1, &templateObj))
         return InliningStatus_NotInlined;
 
-    MSimdUnbox* unbox = MSimdUnbox::New(alloc(), callInfo.getArg(0), mirType);
+    // Unboxing checks the SIMD object type and throws a TypeError if it doesn't
+    // match type.
+    MDefinition *arg = unboxSimd(callInfo.getArg(0), type);
+
+    // Create an unbox/box pair, expecting the box to be optimized away if
+    // anyone use the return value from this check() call. This is what you want
+    // for code like this:
+    //
+    // function f(x) {
+    //   x = Int32x4.check(x)
+    //   for(...) {
+    //     y = Int32x4.add(x, ...)
+    //   }
+    //
+    // The unboxing of x happens as early as possible, and only once.
+    return boxSimd(callInfo, arg, templateObj);
+}
+
+// Given a value or object, insert a dynamic check that this is a SIMD object of
+// the required SimdType, and unbox it into the corresponding SIMD MIRType.
+//
+// This represents the standard type checking that all the SIMD operations
+// perform on their arguments.
+MDefinition*
+IonBuilder::unboxSimd(MDefinition* ins, SimdType type)
+{
+    MIRType mirType = SimdTypeToMIRType(type);
+
+    MSimdUnbox* unbox = MSimdUnbox::New(alloc(), ins, mirType);
     current->add(unbox);
-    current->push(callInfo.getArg(0));
-
-    callInfo.setImplicitlyUsedUnchecked();
-    return InliningStatus_Inlined;
+    return unbox;
 }
 
 IonBuilder::InliningStatus
-IonBuilder::boxSimd(CallInfo& callInfo, MInstruction* ins, InlineTypedObject* templateObj)
+IonBuilder::boxSimd(CallInfo& callInfo, MDefinition* ins, InlineTypedObject* templateObj)
 {
     MSimdBox* obj = MSimdBox::New(alloc(), constraints(), ins, templateObj,
                                   templateObj->group()->initialHeap(constraints()));
 
     // In some cases, ins has already been added to current.
-    if (!ins->block())
-        current->add(ins);
+    if (!ins->block() && ins->isInstruction())
+        current->add(ins->toInstruction());
     current->add(obj);
     current->push(obj);
 
     callInfo.setImplicitlyUsedUnchecked();
     return InliningStatus_Inlined;
 }
 
 template<typename T>