Bug 1244254 - Add SimdType to MSimdBox and MSimdUnbox. r=nbp
authorJakob Stoklund Olesen <jolesen@mozilla.com>
Tue, 09 Feb 2016 08:46:00 -0800
changeset 319982 6e9789224055886c7a1a7126ca4e3428ce00d42e
parent 319981 d79a8c190b860f0cda2f3f2e71d7619936d45a79
child 319983 b7ecabf42762c4a152dd32cd53280d27e84faef2
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnbp
bugs1244254
milestone47.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 1244254 - Add SimdType to MSimdBox and MSimdUnbox. r=nbp The MIRType is not specific enough for MSimdUnbox to distinguish signed from unsigned SIMD types, and when generating code for a MSimdBox, we can't look at the templateObject to get the SimdType because it belongs to a different thread. Pass a SimdType to CodeGenerator::registerSimdTemplate() instead of inspecting the template object. Delete MIRTypeToSimdType() which can't be accurate because MIRType doesn't carry signedness information. Add an optimization to unboxSimd(): With a SimdType on MSimdBox, we can recognize the very common pattern where unboxSimd() gets called with an MSimdBox value. In the types check out, just reuse the MSimdBox input and don't even inert the check code.
js/src/jit/CodeGenerator.cpp
js/src/jit/CodeGenerator.h
js/src/jit/EagerSimdUnbox.cpp
js/src/jit/MCallOptimize.cpp
js/src/jit/MIR.cpp
js/src/jit/MIR.h
js/src/jit/Recover.cpp
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -5142,20 +5142,20 @@ void
 CodeGenerator::visitSimdBox(LSimdBox* lir)
 {
     FloatRegister in = ToFloatRegister(lir->input());
     Register object = ToRegister(lir->output());
     Register temp = ToRegister(lir->temp());
     InlineTypedObject* templateObject = lir->mir()->templateObject();
     gc::InitialHeap initialHeap = lir->mir()->initialHeap();
     MIRType type = lir->mir()->input()->type();
-    registerSimdTemplate(templateObject);
-
-    MOZ_ASSERT(lir->safepoint()->liveRegs().has(in),
-               "Save the input register across the oolCallVM");
+
+    registerSimdTemplate(lir->mir()->simdType());
+
+    MOZ_ASSERT(lir->safepoint()->liveRegs().has(in), "Save the input register across oolCallVM");
     OutOfLineCode* ool = oolCallVM(NewTypedObjectInfo, lir,
                                    ArgList(ImmGCPtr(templateObject), Imm32(initialHeap)),
                                    StoreRegisterTo(object));
 
     masm.createGCObject(object, temp, templateObject, initialHeap, ool->entry());
     masm.bind(ool->rejoin());
 
     Address objectData(object, InlineTypedObject::offsetOfDataStart());
@@ -5168,20 +5168,19 @@ CodeGenerator::visitSimdBox(LSimdBox* li
         masm.storeUnalignedFloat32x4(in, objectData);
         break;
       default:
         MOZ_CRASH("Unknown SIMD kind when generating code for SimdBox.");
     }
 }
 
 void
-CodeGenerator::registerSimdTemplate(InlineTypedObject* templateObject)
-{
-    simdRefreshTemplatesDuringLink_ |=
-        1 << uint32_t(templateObject->typeDescr().as<SimdTypeDescr>().type());
+CodeGenerator::registerSimdTemplate(SimdType simdType)
+{
+    simdRefreshTemplatesDuringLink_ |= 1 << uint32_t(simdType);
 }
 
 void
 CodeGenerator::captureSimdTemplate(JSContext* cx)
 {
     JitCompartment* jitCompartment = cx->compartment()->jitCompartment();
     while (simdRefreshTemplatesDuringLink_) {
         uint32_t typeIndex = mozilla::CountTrailingZeroes32(simdRefreshTemplatesDuringLink_);
@@ -5221,17 +5220,17 @@ CodeGenerator::visitSimdUnbox(LSimdUnbox
     // Check for the /Kind/ reserved slot of the TypeDescr.  This is an Int32
     // Value which is equivalent to the object class check.
     static_assert(JS_DESCR_SLOT_KIND < NativeObject::MAX_FIXED_SLOTS, "Load from fixed slots");
     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);
 
-    SimdType type = MIRTypeToSimdType(lir->mir()->type());
+    SimdType type = lir->mir()->simdType();
 
     // Check if the SimdTypeDescr /Type/ match the specialization of this
     // MSimdUnbox instruction.
     static_assert(JS_DESCR_SLOT_TYPE < NativeObject::MAX_FIXED_SLOTS, "Load from fixed slots");
     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(int32_t(type)), &bail);
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -533,16 +533,16 @@ class CodeGenerator : public CodeGenerat
     // Read Barriers, but such barrier cannot be used during the compilation. To
     // work around this issue, the barriers are captured during
     // CodeGenerator::link.
     //
     // Instead of saving the pointers, we just save the index of the Read
     // Barriered objects in a bit mask.
     uint32_t simdRefreshTemplatesDuringLink_;
 
-    void registerSimdTemplate(InlineTypedObject* templateObject);
+    void registerSimdTemplate(SimdType simdType);
     void captureSimdTemplate(JSContext* cx);
 };
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_CodeGenerator_h */
--- a/js/src/jit/EagerSimdUnbox.cpp
+++ b/js/src/jit/EagerSimdUnbox.cpp
@@ -11,89 +11,90 @@
 #include "jit/MIRGraph.h"
 
 namespace js {
 namespace jit {
 
 // Do not optimize any Phi instruction which has conflicting Unbox operations,
 // as this might imply some intended polymorphism.
 static bool
-CanUnboxSimdPhi(const JitCompartment* jitCompartment, MPhi* phi, MIRType unboxType)
+CanUnboxSimdPhi(const JitCompartment* jitCompartment, MPhi* phi, SimdType unboxType)
 {
     MOZ_ASSERT(phi->type() == MIRType_Object);
 
     // If we are unboxing, we are more than likely to have boxed this SIMD type
     // once in baseline, otherwise, we cannot create a MSimdBox as we have no
     // template object to use.
-    if (!jitCompartment->maybeGetSimdTemplateObjectFor(MIRTypeToSimdType(unboxType)))
+    if (!jitCompartment->maybeGetSimdTemplateObjectFor(unboxType))
         return false;
 
     MResumePoint* entry = phi->block()->entryResumePoint();
+    MIRType mirType = SimdTypeToMIRType(unboxType);
     for (MUseIterator i(phi->usesBegin()), e(phi->usesEnd()); i != e; i++) {
         // If we cannot recover the Simd object at the entry of the basic block,
         // then we would have to box the content anyways.
         if ((*i)->consumer() == entry && !entry->isRecoverableOperand(*i))
             return false;
 
         if (!(*i)->consumer()->isDefinition())
             continue;
 
         MDefinition* def = (*i)->consumer()->toDefinition();
-        if (def->isSimdUnbox() && def->toSimdUnbox()->type() != unboxType)
+        if (def->isSimdUnbox() && def->toSimdUnbox()->type() != mirType)
             return false;
     }
 
     return true;
 }
 
 static void
-UnboxSimdPhi(const JitCompartment* jitCompartment, MIRGraph& graph, MPhi* phi, MIRType unboxType)
+UnboxSimdPhi(const JitCompartment* jitCompartment, MIRGraph& graph, MPhi* phi, SimdType unboxType)
 {
     TempAllocator& alloc = graph.alloc();
 
     // Unbox and replace all operands.
     for (size_t i = 0, e = phi->numOperands(); i < e; i++) {
         MDefinition* op = phi->getOperand(i);
         MSimdUnbox* unbox = MSimdUnbox::New(alloc, op, unboxType);
         op->block()->insertAtEnd(unbox);
         phi->replaceOperand(i, unbox);
     }
 
     // Change the MIRType of the Phi.
-    phi->setResultType(unboxType);
+    MIRType mirType = SimdTypeToMIRType(unboxType);
+    phi->setResultType(mirType);
 
     MBasicBlock* phiBlock = phi->block();
     MInstruction* atRecover = phiBlock->safeInsertTop(nullptr, MBasicBlock::IgnoreRecover);
     MInstruction* at = phiBlock->safeInsertTop(atRecover);
 
     // Note, we capture the uses-list now, as new instructions are not visited.
     MUseIterator i(phi->usesBegin()), e(phi->usesEnd());
 
     // Add a MSimdBox, and replace all the Phi uses with it.
-    JSObject* templateObject =
-        jitCompartment->maybeGetSimdTemplateObjectFor(MIRTypeToSimdType(unboxType));
+    JSObject* templateObject = jitCompartment->maybeGetSimdTemplateObjectFor(unboxType);
     InlineTypedObject* inlineTypedObject = &templateObject->as<InlineTypedObject>();
-    MSimdBox* recoverBox = MSimdBox::New(alloc, nullptr, phi, inlineTypedObject, gc::DefaultHeap);
+    MSimdBox* recoverBox = MSimdBox::New(alloc, nullptr, phi, inlineTypedObject, unboxType, gc::DefaultHeap);
     recoverBox->setRecoveredOnBailout();
     phiBlock->insertBefore(atRecover, recoverBox);
 
     MSimdBox* box = nullptr;
     while (i != e) {
         MUse* use = *i++;
         MNode* ins = use->consumer();
 
         if ((ins->isDefinition() && ins->toDefinition()->isRecoveredOnBailout()) ||
             (ins->isResumePoint() && ins->toResumePoint()->isRecoverableOperand(use)))
         {
             use->replaceProducer(recoverBox);
             continue;
         }
 
         if (!box) {
-            box = MSimdBox::New(alloc, nullptr, phi, inlineTypedObject, gc::DefaultHeap);
+            box = MSimdBox::New(alloc, nullptr, phi, inlineTypedObject, unboxType, gc::DefaultHeap);
             phiBlock->insertBefore(at, box);
         }
 
         use->replaceProducer(box);
     }
 }
 
 bool
@@ -108,20 +109,20 @@ EagerSimdUnbox(MIRGenerator* mir, MIRGra
             if (!ins->isSimdUnbox())
                 continue;
 
             MSimdUnbox* unbox = ins->toSimdUnbox();
             if (!unbox->input()->isPhi())
                 continue;
 
             MPhi* phi = unbox->input()->toPhi();
-            if (!CanUnboxSimdPhi(jitCompartment, phi, unbox->type()))
+            if (!CanUnboxSimdPhi(jitCompartment, phi, unbox->simdType()))
                 continue;
 
-            UnboxSimdPhi(jitCompartment, graph, phi, unbox->type());
+            UnboxSimdPhi(jitCompartment, graph, phi, unbox->simdType());
         }
     }
 
     return true;
 }
 
 } /* namespace jit */
 } /* namespace js */
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -3307,17 +3307,17 @@ IonBuilder::inlineConstructSimdObject(Ca
         for (unsigned i = 0; i < 4; i++)
             lane[i] = convertToBooleanSimdLane(lane[i]);
     }
 
     MSimdValueX4* values =
       MSimdValueX4::New(alloc(), simdType, lane[0], lane[1], lane[2], lane[3]);
     current->add(values);
 
-    MSimdBox* obj = MSimdBox::New(alloc(), constraints(), values, inlineTypedObject,
+    MSimdBox* obj = MSimdBox::New(alloc(), constraints(), values, inlineTypedObject, descr->type(),
                                   inlineTypedObject->group()->initialHeap(constraints()));
     current->add(obj);
     current->push(obj);
 
     callInfo.setImplicitlyUsedUnchecked();
     return InliningStatus_Inlined;
 }
 
@@ -3364,27 +3364,39 @@ IonBuilder::inlineSimdCheck(CallInfo& ca
 // 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);
+    // Trivial optimization: If ins is a MSimdBox of the same SIMD type, there
+    // is no way the unboxing could fail, and we can skip it altogether.
+    // This is the same thing MSimdUnbox::foldsTo() does, but we can save the
+    // memory allocation here.
+    if (ins->isSimdBox()) {
+        MSimdBox* box = ins->toSimdBox();
+        if (box->simdType() == type) {
+            MDefinition* value = box->input();
+            MOZ_ASSERT(value->type() == SimdTypeToMIRType(type));
+            return value;
+        }
+    }
+
+    MSimdUnbox* unbox = MSimdUnbox::New(alloc(), ins, type);
     current->add(unbox);
     return unbox;
 }
 
 IonBuilder::InliningStatus
 IonBuilder::boxSimd(CallInfo& callInfo, MDefinition* ins, InlineTypedObject* templateObj)
 {
-    MSimdBox* obj = MSimdBox::New(alloc(), constraints(), ins, templateObj,
+    SimdType simdType = templateObj->typeDescr().as<SimdTypeDescr>().type();
+    MSimdBox* obj = MSimdBox::New(alloc(), constraints(), ins, templateObj, simdType,
                                   templateObj->group()->initialHeap(constraints()));
 
     // In some cases, ins has already been added to current.
     if (!ins->block() && ins->isInstruction())
         current->add(ins->toInstruction());
     current->add(obj);
     current->push(obj);
 
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -989,22 +989,24 @@ MSimdSplatX4::foldsTo(TempAllocator& all
 }
 
 MDefinition*
 MSimdUnbox::foldsTo(TempAllocator& alloc)
 {
     MDefinition* in = input();
 
     if (in->isSimdBox()) {
+        MSimdBox* box = in->toSimdBox();
         // If the operand is a MSimdBox, then we just reuse the operand of the
         // MSimdBox as long as the type corresponds to what we are supposed to
         // unbox.
-        in = in->toSimdBox()->input();
-        if (in->type() != type())
+        in = box->input();
+        if (box->simdType() != simdType())
             return this;
+        MOZ_ASSERT(in->type() == type());
         return in;
     }
 
     return this;
 }
 
 MDefinition*
 MSimdSwizzle::foldsTo(TempAllocator& alloc)
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -3353,60 +3353,69 @@ class MTypedObjectDescr
 // takes as argument a SIMD instruction and returns a new SIMD object which
 // corresponds to the MIRType of its operand.
 class MSimdBox
   : public MUnaryInstruction,
     public NoTypePolicy::Data
 {
   protected:
     CompilerGCPointer<InlineTypedObject*> templateObject_;
+    SimdType simdType_;
     gc::InitialHeap initialHeap_;
 
     MSimdBox(CompilerConstraintList* constraints,
              MDefinition* op,
              InlineTypedObject* templateObject,
+             SimdType simdType,
              gc::InitialHeap initialHeap)
       : MUnaryInstruction(op),
         templateObject_(templateObject),
+        simdType_(simdType),
         initialHeap_(initialHeap)
     {
         MOZ_ASSERT(IsSimdType(op->type()));
         setMovable();
         setResultType(MIRType_Object);
         if (constraints)
             setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
     }
 
   public:
     INSTRUCTION_HEADER(SimdBox)
 
     static MSimdBox* New(TempAllocator& alloc,
                          CompilerConstraintList* constraints,
                          MDefinition* op,
                          InlineTypedObject* templateObject,
+                         SimdType simdType,
                          gc::InitialHeap initialHeap)
     {
-        return new(alloc) MSimdBox(constraints, op, templateObject, initialHeap);
+        return new(alloc) MSimdBox(constraints, op, templateObject, simdType, initialHeap);
     }
 
     InlineTypedObject* templateObject() const {
         return templateObject_;
     }
 
+    SimdType simdType() const {
+        return simdType_;
+    }
+
     gc::InitialHeap initialHeap() const {
         return initialHeap_;
     }
 
     bool congruentTo(const MDefinition* ins) const override {
-        if (congruentIfOperandsEqual(ins)) {
-            MOZ_ASSERT(ins->toSimdBox()->initialHeap() == initialHeap());
-            return true;
-        }
-
-        return false;
+        if (!congruentIfOperandsEqual(ins))
+            return false;
+        const MSimdBox* box = ins->toSimdBox();
+        if (box->simdType() != simdType())
+            return false;
+        MOZ_ASSERT(box->initialHeap() == initialHeap());
+        return true;
     }
 
     AliasSet getAliasSet() const override {
         return AliasSet::None();
     }
 
     bool writeRecoverData(CompactBufferWriter& writer) const override;
     bool canRecoverOnBailout() const override {
@@ -3414,37 +3423,45 @@ class MSimdBox
     }
 };
 
 class MSimdUnbox
   : public MUnaryInstruction,
     public SingleObjectPolicy::Data
 {
   protected:
-    MSimdUnbox(MDefinition* op, MIRType type)
-      : MUnaryInstruction(op)
-    {
+    SimdType simdType_;
+
+    MSimdUnbox(MDefinition* op, SimdType simdType)
+      : MUnaryInstruction(op),
+        simdType_(simdType)
+    {
+        MIRType type = SimdTypeToMIRType(simdType);
         MOZ_ASSERT(IsSimdType(type));
         setGuard();
         setMovable();
         setResultType(type);
     }
 
   public:
     INSTRUCTION_HEADER(SimdUnbox)
     ALLOW_CLONE(MSimdUnbox)
 
-    static MSimdUnbox* New(TempAllocator& alloc, MDefinition* op, MIRType type)
-    {
-        return new(alloc) MSimdUnbox(op, type);
-    }
+    static MSimdUnbox* New(TempAllocator& alloc, MDefinition* op, SimdType simdType)
+    {
+        return new(alloc) MSimdUnbox(op, simdType);
+    }
+
+    SimdType simdType() const { return simdType_; }
 
     MDefinition* foldsTo(TempAllocator& alloc) override;
     bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
+        if (!congruentIfOperandsEqual(ins))
+            return false;
+        return ins->toSimdUnbox()->simdType() == simdType();
     }
 
     AliasSet getAliasSet() const override {
         return AliasSet::None();
     }
 };
 
 // Creates a new derived type object. At runtime, this is just a call
--- a/js/src/jit/Recover.cpp
+++ b/js/src/jit/Recover.cpp
@@ -1331,18 +1331,17 @@ RLambda::recover(JSContext* cx, Snapshot
 }
 
 bool
 MSimdBox::writeRecoverData(CompactBufferWriter& writer) const
 {
     MOZ_ASSERT(canRecoverOnBailout());
     writer.writeUnsigned(uint32_t(RInstruction::Recover_SimdBox));
     static_assert(sizeof(SimdType) == sizeof(uint8_t), "assuming uint8 storage class for SimdType");
-    SimdType type = templateObject()->typeDescr().as<SimdTypeDescr>().type();
-    writer.writeByte(uint8_t(type));
+    writer.writeByte(uint8_t(simdType()));
     return true;
 }
 
 RSimdBox::RSimdBox(CompactBufferReader& reader)
 {
     type_ = reader.readByte();
 }