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