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/mips32/Lowering-mips32.h"
8 
9 #include "jit/mips32/Assembler-mips32.h"
10 
11 #include "jit/MIR.h"
12 
13 #include "jit/shared/Lowering-shared-inl.h"
14 
15 using namespace js;
16 using namespace js::jit;
17 
18 LBoxAllocation
19 LIRGeneratorMIPS::useBoxFixed(MDefinition* mir, Register reg1, Register reg2, bool useAtStart)
20 {
21     MOZ_ASSERT(mir->type() == MIRType::Value);
22     MOZ_ASSERT(reg1 != reg2);
23 
24     ensureDefined(mir);
25     return LBoxAllocation(LUse(reg1, mir->virtualRegister(), useAtStart),
26                           LUse(reg2, VirtualRegisterOfPayload(mir), useAtStart));
27 }
28 
29 void
30 LIRGeneratorMIPS::visitBox(MBox* box)
31 {
32     MDefinition* inner = box->getOperand(0);
33 
34     // If the box wrapped a double, it needs a new register.
35     if (IsFloatingPointType(inner->type())) {
36         defineBox(new(alloc()) LBoxFloatingPoint(useRegisterAtStart(inner),
37                                                  tempCopy(inner, 0), inner->type()), box);
38         return;
39     }
40 
41     if (box->canEmitAtUses()) {
42         emitAtUses(box);
43         return;
44     }
45 
46     if (inner->isConstant()) {
47         defineBox(new(alloc()) LValue(inner->toConstant()->toJSValue()), box);
48         return;
49     }
50 
51     LBox* lir = new(alloc()) LBox(use(inner), inner->type());
52 
53     // Otherwise, we should not define a new register for the payload portion
54     // of the output, so bypass defineBox().
55     uint32_t vreg = getVirtualRegister();
56 
57     // Note that because we're using BogusTemp(), we do not change the type of
58     // the definition. We also do not define the first output as "TYPE",
59     // because it has no corresponding payload at (vreg + 1). Also note that
60     // although we copy the input's original type for the payload half of the
61     // definition, this is only for clarity. BogusTemp() definitions are
62     // ignored.
63     lir->setDef(0, LDefinition(vreg, LDefinition::GENERAL));
64     lir->setDef(1, LDefinition::BogusTemp());
65     box->setVirtualRegister(vreg);
66     add(lir);
67 }
68 
69 void
70 LIRGeneratorMIPS::visitUnbox(MUnbox* unbox)
71 {
72     MDefinition* inner = unbox->getOperand(0);
73 
74     if (inner->type() == MIRType::ObjectOrNull) {
75         LUnboxObjectOrNull* lir = new(alloc()) LUnboxObjectOrNull(useRegisterAtStart(inner));
76         if (unbox->fallible())
77             assignSnapshot(lir, unbox->bailoutKind());
78         defineReuseInput(lir, unbox, 0);
79         return;
80     }
81 
82     // An unbox on mips reads in a type tag (either in memory or a register) and
83     // a payload. Unlike most instructions consuming a box, we ask for the type
84     // second, so that the result can re-use the first input.
85     MOZ_ASSERT(inner->type() == MIRType::Value);
86 
87     ensureDefined(inner);
88 
89     if (IsFloatingPointType(unbox->type())) {
90         LUnboxFloatingPoint* lir = new(alloc()) LUnboxFloatingPoint(useBox(inner), unbox->type());
91         if (unbox->fallible())
92             assignSnapshot(lir, unbox->bailoutKind());
93         define(lir, unbox);
94         return;
95     }
96 
97     // Swap the order we use the box pieces so we can re-use the payload
98     // register.
99     LUnbox* lir = new(alloc()) LUnbox;
100     lir->setOperand(0, usePayloadInRegisterAtStart(inner));
101     lir->setOperand(1, useType(inner, LUse::REGISTER));
102 
103     if (unbox->fallible())
104         assignSnapshot(lir, unbox->bailoutKind());
105 
106     // Types and payloads form two separate intervals. If the type becomes dead
107     // before the payload, it could be used as a Value without the type being
108     // recoverable. Unbox's purpose is to eagerly kill the definition of a type
109     // tag, so keeping both alive (for the purpose of gcmaps) is unappealing.
110     // Instead, we create a new virtual register.
111     defineReuseInput(lir, unbox, 0);
112 }
113 
114 void
115 LIRGeneratorMIPS::visitReturn(MReturn* ret)
116 {
117     MDefinition* opd = ret->getOperand(0);
118     MOZ_ASSERT(opd->type() == MIRType::Value);
119 
120     LReturn* ins = new(alloc()) LReturn;
121     ins->setOperand(0, LUse(JSReturnReg_Type));
122     ins->setOperand(1, LUse(JSReturnReg_Data));
123     fillBoxUses(ins, 0, opd);
124     add(ins);
125 }
126 
127 void
128 LIRGeneratorMIPS::defineUntypedPhi(MPhi* phi, size_t lirIndex)
129 {
130     LPhi* type = current->getPhi(lirIndex + VREG_TYPE_OFFSET);
131     LPhi* payload = current->getPhi(lirIndex + VREG_DATA_OFFSET);
132 
133     uint32_t typeVreg = getVirtualRegister();
134     phi->setVirtualRegister(typeVreg);
135 
136     uint32_t payloadVreg = getVirtualRegister();
137     MOZ_ASSERT(typeVreg + 1 == payloadVreg);
138 
139     type->setDef(0, LDefinition(typeVreg, LDefinition::TYPE));
140     payload->setDef(0, LDefinition(payloadVreg, LDefinition::PAYLOAD));
141     annotate(type);
142     annotate(payload);
143 }
144 
145 void
146 LIRGeneratorMIPS::lowerUntypedPhiInput(MPhi* phi, uint32_t inputPosition,
147                                        LBlock* block, size_t lirIndex)
148 {
149     MDefinition* operand = phi->getOperand(inputPosition);
150     LPhi* type = block->getPhi(lirIndex + VREG_TYPE_OFFSET);
151     LPhi* payload = block->getPhi(lirIndex + VREG_DATA_OFFSET);
152     type->setOperand(inputPosition, LUse(operand->virtualRegister() + VREG_TYPE_OFFSET,
153                                          LUse::ANY));
154     payload->setOperand(inputPosition, LUse(VirtualRegisterOfPayload(operand), LUse::ANY));
155 }
156 
157 void
158 LIRGeneratorMIPS::defineInt64Phi(MPhi* phi, size_t lirIndex)
159 {
160     LPhi* low = current->getPhi(lirIndex + INT64LOW_INDEX);
161     LPhi* high = current->getPhi(lirIndex + INT64HIGH_INDEX);
162 
163     uint32_t lowVreg = getVirtualRegister();
164 
165     phi->setVirtualRegister(lowVreg);
166 
167     uint32_t highVreg = getVirtualRegister();
168     MOZ_ASSERT(lowVreg + INT64HIGH_INDEX == highVreg + INT64LOW_INDEX);
169 
170     low->setDef(0, LDefinition(lowVreg, LDefinition::INT32));
171     high->setDef(0, LDefinition(highVreg, LDefinition::INT32));
172     annotate(high);
173     annotate(low);
174 }
175 
176 void
177 LIRGeneratorMIPS::lowerInt64PhiInput(MPhi* phi, uint32_t inputPosition,
178                                      LBlock* block, size_t lirIndex)
179 {
180     MDefinition* operand = phi->getOperand(inputPosition);
181     LPhi* low = block->getPhi(lirIndex + INT64LOW_INDEX);
182     LPhi* high = block->getPhi(lirIndex + INT64HIGH_INDEX);
183     low->setOperand(inputPosition, LUse(operand->virtualRegister() + INT64LOW_INDEX, LUse::ANY));
184     high->setOperand(inputPosition, LUse(operand->virtualRegister() + INT64HIGH_INDEX, LUse::ANY));
185 }
186 
187 void
188 LIRGeneratorMIPS::lowerTruncateDToInt32(MTruncateToInt32* ins)
189 {
190     MDefinition* opd = ins->input();
191     MOZ_ASSERT(opd->type() == MIRType::Double);
192 
193     define(new(alloc()) LTruncateDToInt32(useRegister(opd), LDefinition::BogusTemp()), ins);
194 }
195 
196 void
197 LIRGeneratorMIPS::lowerTruncateFToInt32(MTruncateToInt32* ins)
198 {
199     MDefinition* opd = ins->input();
200     MOZ_ASSERT(opd->type() == MIRType::Float32);
201 
202     define(new(alloc()) LTruncateFToInt32(useRegister(opd), LDefinition::BogusTemp()), ins);
203 }
204 
205 void
206 LIRGeneratorMIPS::lowerDivI64(MDiv* div)
207 {
208     if (div->isUnsigned()) {
209         lowerUDivI64(div);
210         return;
211     }
212 
213     LDivOrModI64* lir = new(alloc()) LDivOrModI64(useInt64RegisterAtStart(div->lhs()),
214                                                   useInt64RegisterAtStart(div->rhs()));
215 
216     defineReturn(lir, div);
217 }
218 
219 void
220 LIRGeneratorMIPS::lowerModI64(MMod* mod)
221 {
222     if (mod->isUnsigned()) {
223         lowerUModI64(mod);
224         return;
225     }
226 
227     LDivOrModI64* lir = new(alloc()) LDivOrModI64(useInt64RegisterAtStart(mod->lhs()),
228                                                   useInt64RegisterAtStart(mod->rhs()));
229 
230     defineReturn(lir, mod);
231 }
232 
233 void
234 LIRGeneratorMIPS::lowerUDivI64(MDiv* div)
235 {
236     LUDivOrModI64* lir = new(alloc()) LUDivOrModI64(useInt64RegisterAtStart(div->lhs()),
237                                                     useInt64RegisterAtStart(div->rhs()));
238     defineReturn(lir, div);
239 }
240 
241 void
242 LIRGeneratorMIPS::lowerUModI64(MMod* mod)
243 {
244     LUDivOrModI64* lir = new(alloc()) LUDivOrModI64(useInt64RegisterAtStart(mod->lhs()),
245                                                     useInt64RegisterAtStart(mod->rhs()));
246     defineReturn(lir, mod);
247 }
248 
249 void
250 LIRGeneratorMIPS::visitRandom(MRandom* ins)
251 {
252     LRandom *lir = new(alloc()) LRandom(temp(),
253                                         temp(),
254                                         temp(),
255                                         temp(),
256                                         temp());
257     defineFixed(lir, ins, LFloatReg(ReturnDoubleReg));
258 }
259