1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim: set ts=8 sts=4 et sw=4 tw=99:
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "jit/EagerSimdUnbox.h"
8 
9 #include "jit/MIR.h"
10 #include "jit/MIRGenerator.h"
11 #include "jit/MIRGraph.h"
12 
13 namespace js {
14 namespace jit {
15 
16 // Do not optimize any Phi instruction which has conflicting Unbox operations,
17 // as this might imply some intended polymorphism.
18 static bool
CanUnboxSimdPhi(const JitCompartment * jitCompartment,MPhi * phi,SimdType unboxType)19 CanUnboxSimdPhi(const JitCompartment* jitCompartment, MPhi* phi, SimdType unboxType)
20 {
21     MOZ_ASSERT(phi->type() == MIRType::Object);
22 
23     // If we are unboxing, we are more than likely to have boxed this SIMD type
24     // once in baseline, otherwise, we cannot create a MSimdBox as we have no
25     // template object to use.
26     if (!jitCompartment->maybeGetSimdTemplateObjectFor(unboxType))
27         return false;
28 
29     MResumePoint* entry = phi->block()->entryResumePoint();
30     MIRType mirType = SimdTypeToMIRType(unboxType);
31     for (MUseIterator i(phi->usesBegin()), e(phi->usesEnd()); i != e; i++) {
32         // If we cannot recover the Simd object at the entry of the basic block,
33         // then we would have to box the content anyways.
34         if ((*i)->consumer() == entry && !entry->isRecoverableOperand(*i))
35             return false;
36 
37         if (!(*i)->consumer()->isDefinition())
38             continue;
39 
40         MDefinition* def = (*i)->consumer()->toDefinition();
41         if (def->isSimdUnbox() && def->toSimdUnbox()->type() != mirType)
42             return false;
43     }
44 
45     return true;
46 }
47 
48 static void
UnboxSimdPhi(const JitCompartment * jitCompartment,MIRGraph & graph,MPhi * phi,SimdType unboxType)49 UnboxSimdPhi(const JitCompartment* jitCompartment, MIRGraph& graph, MPhi* phi, SimdType unboxType)
50 {
51     TempAllocator& alloc = graph.alloc();
52 
53     // Unbox and replace all operands.
54     for (size_t i = 0, e = phi->numOperands(); i < e; i++) {
55         MDefinition* op = phi->getOperand(i);
56         MSimdUnbox* unbox = MSimdUnbox::New(alloc, op, unboxType);
57         op->block()->insertAtEnd(unbox);
58         phi->replaceOperand(i, unbox);
59     }
60 
61     // Change the MIRType of the Phi.
62     MIRType mirType = SimdTypeToMIRType(unboxType);
63     phi->setResultType(mirType);
64 
65     MBasicBlock* phiBlock = phi->block();
66     MInstruction* atRecover = phiBlock->safeInsertTop(nullptr, MBasicBlock::IgnoreRecover);
67     MInstruction* at = phiBlock->safeInsertTop(atRecover);
68 
69     // Note, we capture the uses-list now, as new instructions are not visited.
70     MUseIterator i(phi->usesBegin()), e(phi->usesEnd());
71 
72     // Add a MSimdBox, and replace all the Phi uses with it.
73     JSObject* templateObject = jitCompartment->maybeGetSimdTemplateObjectFor(unboxType);
74     InlineTypedObject* inlineTypedObject = &templateObject->as<InlineTypedObject>();
75     MSimdBox* recoverBox = MSimdBox::New(alloc, nullptr, phi, inlineTypedObject, unboxType, gc::DefaultHeap);
76     recoverBox->setRecoveredOnBailout();
77     phiBlock->insertBefore(atRecover, recoverBox);
78 
79     MSimdBox* box = nullptr;
80     while (i != e) {
81         MUse* use = *i++;
82         MNode* ins = use->consumer();
83 
84         if ((ins->isDefinition() && ins->toDefinition()->isRecoveredOnBailout()) ||
85             (ins->isResumePoint() && ins->toResumePoint()->isRecoverableOperand(use)))
86         {
87             use->replaceProducer(recoverBox);
88             continue;
89         }
90 
91         if (!box) {
92             box = MSimdBox::New(alloc, nullptr, phi, inlineTypedObject, unboxType, gc::DefaultHeap);
93             phiBlock->insertBefore(at, box);
94         }
95 
96         use->replaceProducer(box);
97     }
98 }
99 
100 bool
EagerSimdUnbox(MIRGenerator * mir,MIRGraph & graph)101 EagerSimdUnbox(MIRGenerator* mir, MIRGraph& graph)
102 {
103     const JitCompartment* jitCompartment = GetJitContext()->compartment->jitCompartment();
104     for (PostorderIterator block = graph.poBegin(); block != graph.poEnd(); block++) {
105         if (mir->shouldCancel("Eager Simd Unbox"))
106             return false;
107 
108         for (MInstructionReverseIterator ins = block->rbegin(); ins != block->rend(); ins++) {
109             if (!ins->isSimdUnbox())
110                 continue;
111 
112             MSimdUnbox* unbox = ins->toSimdUnbox();
113             if (!unbox->input()->isPhi())
114                 continue;
115 
116             MPhi* phi = unbox->input()->toPhi();
117             if (!CanUnboxSimdPhi(jitCompartment, phi, unbox->simdType()))
118                 continue;
119 
120             UnboxSimdPhi(jitCompartment, graph, phi, unbox->simdType());
121         }
122     }
123 
124     return true;
125 }
126 
127 } /* namespace jit */
128 } /* namespace js */
129