Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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/. */
7 #include "mozilla/MathAlgorithms.h"
10 #include "jit/Lowering.h"
11 #include "jit/mips/Assembler-mips.h"
12 #include "jit/MIR.h"
14 #include "jit/shared/Lowering-shared-inl.h"
16 using namespace js;
17 using namespace js::jit;
19 using mozilla::FloorLog2;
21 bool
22 LIRGeneratorMIPS::useBox(LInstruction *lir, size_t n, MDefinition *mir,
23 LUse::Policy policy, bool useAtStart)
24 {
25 MOZ_ASSERT(mir->type() == MIRType_Value);
27 if (!ensureDefined(mir))
28 return false;
29 lir->setOperand(n, LUse(mir->virtualRegister(), policy, useAtStart));
30 lir->setOperand(n + 1, LUse(VirtualRegisterOfPayload(mir), policy, useAtStart));
31 return true;
32 }
34 bool
35 LIRGeneratorMIPS::useBoxFixed(LInstruction *lir, size_t n, MDefinition *mir, Register reg1,
36 Register reg2)
37 {
38 MOZ_ASSERT(mir->type() == MIRType_Value);
39 MOZ_ASSERT(reg1 != reg2);
41 if (!ensureDefined(mir))
42 return false;
43 lir->setOperand(n, LUse(reg1, mir->virtualRegister()));
44 lir->setOperand(n + 1, LUse(reg2, VirtualRegisterOfPayload(mir)));
45 return true;
46 }
48 LAllocation
49 LIRGeneratorMIPS::useByteOpRegister(MDefinition *mir)
50 {
51 return useRegister(mir);
52 }
54 LAllocation
55 LIRGeneratorMIPS::useByteOpRegisterOrNonDoubleConstant(MDefinition *mir)
56 {
57 return useRegisterOrNonDoubleConstant(mir);
58 }
60 bool
61 LIRGeneratorMIPS::lowerConstantDouble(double d, MInstruction *mir)
62 {
63 return define(new(alloc()) LDouble(d), mir);
64 }
66 bool
67 LIRGeneratorMIPS::lowerConstantFloat32(float d, MInstruction *mir)
68 {
69 return define(new(alloc()) LFloat32(d), mir);
70 }
72 bool
73 LIRGeneratorMIPS::visitConstant(MConstant *ins)
74 {
75 if (ins->type() == MIRType_Double)
76 return lowerConstantDouble(ins->value().toDouble(), ins);
78 if (ins->type() == MIRType_Float32)
79 return lowerConstantFloat32(ins->value().toDouble(), ins);
81 // Emit non-double constants at their uses.
82 if (ins->canEmitAtUses())
83 return emitAtUses(ins);
85 return LIRGeneratorShared::visitConstant(ins);
86 }
88 bool
89 LIRGeneratorMIPS::visitBox(MBox *box)
90 {
91 MDefinition *inner = box->getOperand(0);
93 // If the box wrapped a double, it needs a new register.
94 if (IsFloatingPointType(inner->type()))
95 return defineBox(new(alloc()) LBoxFloatingPoint(useRegisterAtStart(inner),
96 tempCopy(inner, 0), inner->type()), box);
98 if (box->canEmitAtUses())
99 return emitAtUses(box);
101 if (inner->isConstant())
102 return defineBox(new(alloc()) LValue(inner->toConstant()->value()), box);
104 LBox *lir = new(alloc()) LBox(use(inner), inner->type());
106 // Otherwise, we should not define a new register for the payload portion
107 // of the output, so bypass defineBox().
108 uint32_t vreg = getVirtualRegister();
109 if (vreg >= MAX_VIRTUAL_REGISTERS)
110 return false;
112 // Note that because we're using PASSTHROUGH, we do not change the type of
113 // the definition. We also do not define the first output as "TYPE",
114 // because it has no corresponding payload at (vreg + 1). Also note that
115 // although we copy the input's original type for the payload half of the
116 // definition, this is only for clarity. PASSTHROUGH definitions are
117 // ignored.
118 lir->setDef(0, LDefinition(vreg, LDefinition::GENERAL));
119 lir->setDef(1, LDefinition(inner->virtualRegister(), LDefinition::TypeFrom(inner->type()),
120 LDefinition::PASSTHROUGH));
121 box->setVirtualRegister(vreg);
122 return add(lir);
123 }
125 bool
126 LIRGeneratorMIPS::visitUnbox(MUnbox *unbox)
127 {
128 // An unbox on mips reads in a type tag (either in memory or a register) and
129 // a payload. Unlike most instructions consuming a box, we ask for the type
130 // second, so that the result can re-use the first input.
131 MDefinition *inner = unbox->getOperand(0);
133 if (!ensureDefined(inner))
134 return false;
136 if (IsFloatingPointType(unbox->type())) {
137 LUnboxFloatingPoint *lir = new(alloc()) LUnboxFloatingPoint(unbox->type());
138 if (unbox->fallible() && !assignSnapshot(lir, unbox->bailoutKind()))
139 return false;
140 if (!useBox(lir, LUnboxFloatingPoint::Input, inner))
141 return false;
142 return define(lir, unbox);
143 }
145 // Swap the order we use the box pieces so we can re-use the payload
146 // register.
147 LUnbox *lir = new(alloc()) LUnbox;
148 lir->setOperand(0, usePayloadInRegisterAtStart(inner));
149 lir->setOperand(1, useType(inner, LUse::REGISTER));
151 if (unbox->fallible() && !assignSnapshot(lir, unbox->bailoutKind()))
152 return false;
154 // Note that PASSTHROUGH here is illegal, since types and payloads form two
155 // separate intervals. If the type becomes dead before the payload, it
156 // could be used as a Value without the type being recoverable. Unbox's
157 // purpose is to eagerly kill the definition of a type tag, so keeping both
158 // alive (for the purpose of gcmaps) is unappealing. Instead, we create a
159 // new virtual register.
160 return defineReuseInput(lir, unbox, 0);
161 }
163 bool
164 LIRGeneratorMIPS::visitReturn(MReturn *ret)
165 {
166 MDefinition *opd = ret->getOperand(0);
167 MOZ_ASSERT(opd->type() == MIRType_Value);
169 LReturn *ins = new(alloc()) LReturn;
170 ins->setOperand(0, LUse(JSReturnReg_Type));
171 ins->setOperand(1, LUse(JSReturnReg_Data));
172 return fillBoxUses(ins, 0, opd) && add(ins);
173 }
175 // x = !y
176 bool
177 LIRGeneratorMIPS::lowerForALU(LInstructionHelper<1, 1, 0> *ins,
178 MDefinition *mir, MDefinition *input)
179 {
180 ins->setOperand(0, useRegister(input));
181 return define(ins, mir,
182 LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::DEFAULT));
183 }
185 // z = x+y
186 bool
187 LIRGeneratorMIPS::lowerForALU(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir,
188 MDefinition *lhs, MDefinition *rhs)
189 {
190 ins->setOperand(0, useRegister(lhs));
191 ins->setOperand(1, useRegisterOrConstant(rhs));
192 return define(ins, mir,
193 LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::DEFAULT));
194 }
196 bool
197 LIRGeneratorMIPS::lowerForFPU(LInstructionHelper<1, 1, 0> *ins, MDefinition *mir,
198 MDefinition *input)
199 {
200 ins->setOperand(0, useRegister(input));
201 return define(ins, mir,
202 LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::DEFAULT));
203 }
205 bool
206 LIRGeneratorMIPS::lowerForFPU(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir,
207 MDefinition *lhs, MDefinition *rhs)
208 {
209 ins->setOperand(0, useRegister(lhs));
210 ins->setOperand(1, useRegister(rhs));
211 return define(ins, mir,
212 LDefinition(LDefinition::TypeFrom(mir->type()), LDefinition::DEFAULT));
213 }
215 bool
216 LIRGeneratorMIPS::lowerForBitAndAndBranch(LBitAndAndBranch *baab, MInstruction *mir,
217 MDefinition *lhs, MDefinition *rhs)
218 {
219 baab->setOperand(0, useRegisterAtStart(lhs));
220 baab->setOperand(1, useRegisterOrConstantAtStart(rhs));
221 return add(baab, mir);
222 }
224 bool
225 LIRGeneratorMIPS::defineUntypedPhi(MPhi *phi, size_t lirIndex)
226 {
227 LPhi *type = current->getPhi(lirIndex + VREG_TYPE_OFFSET);
228 LPhi *payload = current->getPhi(lirIndex + VREG_DATA_OFFSET);
230 uint32_t typeVreg = getVirtualRegister();
231 if (typeVreg >= MAX_VIRTUAL_REGISTERS)
232 return false;
234 phi->setVirtualRegister(typeVreg);
236 uint32_t payloadVreg = getVirtualRegister();
237 if (payloadVreg >= MAX_VIRTUAL_REGISTERS)
238 return false;
239 MOZ_ASSERT(typeVreg + 1 == payloadVreg);
241 type->setDef(0, LDefinition(typeVreg, LDefinition::TYPE));
242 payload->setDef(0, LDefinition(payloadVreg, LDefinition::PAYLOAD));
243 annotate(type);
244 annotate(payload);
245 return true;
246 }
248 void
249 LIRGeneratorMIPS::lowerUntypedPhiInput(MPhi *phi, uint32_t inputPosition,
250 LBlock *block, size_t lirIndex)
251 {
252 MDefinition *operand = phi->getOperand(inputPosition);
253 LPhi *type = block->getPhi(lirIndex + VREG_TYPE_OFFSET);
254 LPhi *payload = block->getPhi(lirIndex + VREG_DATA_OFFSET);
255 type->setOperand(inputPosition, LUse(operand->virtualRegister() + VREG_TYPE_OFFSET,
256 LUse::ANY));
257 payload->setOperand(inputPosition, LUse(VirtualRegisterOfPayload(operand), LUse::ANY));
258 }
260 bool
261 LIRGeneratorMIPS::lowerForShift(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir,
262 MDefinition *lhs, MDefinition *rhs)
263 {
264 ins->setOperand(0, useRegister(lhs));
265 ins->setOperand(1, useRegisterOrConstant(rhs));
266 return define(ins, mir);
267 }
269 bool
270 LIRGeneratorMIPS::lowerDivI(MDiv *div)
271 {
272 if (div->isUnsigned())
273 return lowerUDiv(div);
275 // Division instructions are slow. Division by constant denominators can be
276 // rewritten to use other instructions.
277 if (div->rhs()->isConstant()) {
278 int32_t rhs = div->rhs()->toConstant()->value().toInt32();
279 // Check for division by a positive power of two, which is an easy and
280 // important case to optimize. Note that other optimizations are also
281 // possible; division by negative powers of two can be optimized in a
282 // similar manner as positive powers of two, and division by other
283 // constants can be optimized by a reciprocal multiplication technique.
284 int32_t shift = FloorLog2(rhs);
285 if (rhs > 0 && 1 << shift == rhs) {
286 LDivPowTwoI *lir = new(alloc()) LDivPowTwoI(useRegister(div->lhs()), shift, temp());
287 if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
288 return false;
289 return define(lir, div);
290 }
291 }
293 LDivI *lir = new(alloc()) LDivI(useRegister(div->lhs()), useRegister(div->rhs()), temp());
294 if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
295 return false;
296 return define(lir, div);
297 }
299 bool
300 LIRGeneratorMIPS::lowerMulI(MMul *mul, MDefinition *lhs, MDefinition *rhs)
301 {
302 LMulI *lir = new(alloc()) LMulI;
303 if (mul->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
304 return false;
306 return lowerForALU(lir, mul, lhs, rhs);
307 }
309 bool
310 LIRGeneratorMIPS::lowerModI(MMod *mod)
311 {
312 if (mod->isUnsigned())
313 return lowerUMod(mod);
315 if (mod->rhs()->isConstant()) {
316 int32_t rhs = mod->rhs()->toConstant()->value().toInt32();
317 int32_t shift = FloorLog2(rhs);
318 if (rhs > 0 && 1 << shift == rhs) {
319 LModPowTwoI *lir = new(alloc()) LModPowTwoI(useRegister(mod->lhs()), shift);
320 if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
321 return false;
322 return define(lir, mod);
323 } else if (shift < 31 && (1 << (shift + 1)) - 1 == rhs) {
324 LModMaskI *lir = new(alloc()) LModMaskI(useRegister(mod->lhs()),
325 temp(LDefinition::GENERAL), shift + 1);
326 if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
327 return false;
328 return define(lir, mod);
329 }
330 }
331 LModI *lir = new(alloc()) LModI(useRegister(mod->lhs()), useRegister(mod->rhs()),
332 temp(LDefinition::GENERAL));
334 if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
335 return false;
336 return define(lir, mod);
337 }
339 bool
340 LIRGeneratorMIPS::visitPowHalf(MPowHalf *ins)
341 {
342 MDefinition *input = ins->input();
343 MOZ_ASSERT(input->type() == MIRType_Double);
344 LPowHalfD *lir = new(alloc()) LPowHalfD(useRegisterAtStart(input));
345 return defineReuseInput(lir, ins, 0);
346 }
348 LTableSwitch *
349 LIRGeneratorMIPS::newLTableSwitch(const LAllocation &in, const LDefinition &inputCopy,
350 MTableSwitch *tableswitch)
351 {
352 return new(alloc()) LTableSwitch(in, inputCopy, temp(), tableswitch);
353 }
355 LTableSwitchV *
356 LIRGeneratorMIPS::newLTableSwitchV(MTableSwitch *tableswitch)
357 {
358 return new(alloc()) LTableSwitchV(temp(), tempFloat32(), temp(), tableswitch);
359 }
361 bool
362 LIRGeneratorMIPS::visitGuardShape(MGuardShape *ins)
363 {
364 MOZ_ASSERT(ins->obj()->type() == MIRType_Object);
366 LDefinition tempObj = temp(LDefinition::OBJECT);
367 LGuardShape *guard = new(alloc()) LGuardShape(useRegister(ins->obj()), tempObj);
368 if (!assignSnapshot(guard, ins->bailoutKind()))
369 return false;
370 if (!add(guard, ins))
371 return false;
372 return redefine(ins, ins->obj());
373 }
375 bool
376 LIRGeneratorMIPS::visitGuardObjectType(MGuardObjectType *ins)
377 {
378 MOZ_ASSERT(ins->obj()->type() == MIRType_Object);
380 LDefinition tempObj = temp(LDefinition::OBJECT);
381 LGuardObjectType *guard = new(alloc()) LGuardObjectType(useRegister(ins->obj()), tempObj);
382 if (!assignSnapshot(guard))
383 return false;
384 if (!add(guard, ins))
385 return false;
386 return redefine(ins, ins->obj());
387 }
389 bool
390 LIRGeneratorMIPS::lowerUrshD(MUrsh *mir)
391 {
392 MDefinition *lhs = mir->lhs();
393 MDefinition *rhs = mir->rhs();
395 MOZ_ASSERT(lhs->type() == MIRType_Int32);
396 MOZ_ASSERT(rhs->type() == MIRType_Int32);
398 LUrshD *lir = new(alloc()) LUrshD(useRegister(lhs), useRegisterOrConstant(rhs), temp());
399 return define(lir, mir);
400 }
402 bool
403 LIRGeneratorMIPS::visitAsmJSNeg(MAsmJSNeg *ins)
404 {
405 if (ins->type() == MIRType_Int32)
406 return define(new(alloc()) LNegI(useRegisterAtStart(ins->input())), ins);
408 if (ins->type() == MIRType_Float32)
409 return define(new(alloc()) LNegF(useRegisterAtStart(ins->input())), ins);
411 MOZ_ASSERT(ins->type() == MIRType_Double);
412 return define(new(alloc()) LNegD(useRegisterAtStart(ins->input())), ins);
413 }
415 bool
416 LIRGeneratorMIPS::lowerUDiv(MDiv *div)
417 {
418 MDefinition *lhs = div->getOperand(0);
419 MDefinition *rhs = div->getOperand(1);
421 LUDiv *lir = new(alloc()) LUDiv;
422 lir->setOperand(0, useRegister(lhs));
423 lir->setOperand(1, useRegister(rhs));
424 if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
425 return false;
427 return define(lir, div);
428 }
430 bool
431 LIRGeneratorMIPS::lowerUMod(MMod *mod)
432 {
433 MDefinition *lhs = mod->getOperand(0);
434 MDefinition *rhs = mod->getOperand(1);
436 LUMod *lir = new(alloc()) LUMod;
437 lir->setOperand(0, useRegister(lhs));
438 lir->setOperand(1, useRegister(rhs));
439 if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
440 return false;
442 return define(lir, mod);
443 }
445 bool
446 LIRGeneratorMIPS::visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins)
447 {
448 MOZ_ASSERT(ins->input()->type() == MIRType_Int32);
449 LAsmJSUInt32ToDouble *lir = new(alloc()) LAsmJSUInt32ToDouble(useRegisterAtStart(ins->input()));
450 return define(lir, ins);
451 }
453 bool
454 LIRGeneratorMIPS::visitAsmJSUnsignedToFloat32(MAsmJSUnsignedToFloat32 *ins)
455 {
456 MOZ_ASSERT(ins->input()->type() == MIRType_Int32);
457 LAsmJSUInt32ToFloat32 *lir = new(alloc()) LAsmJSUInt32ToFloat32(useRegisterAtStart(ins->input()));
458 return define(lir, ins);
459 }
461 bool
462 LIRGeneratorMIPS::visitAsmJSLoadHeap(MAsmJSLoadHeap *ins)
463 {
464 MDefinition *ptr = ins->ptr();
465 MOZ_ASSERT(ptr->type() == MIRType_Int32);
466 LAllocation ptrAlloc;
468 // For MIPS it is best to keep the 'ptr' in a register if a bounds check
469 // is needed.
470 if (ptr->isConstant() && ins->skipBoundsCheck()) {
471 int32_t ptrValue = ptr->toConstant()->value().toInt32();
472 // A bounds check is only skipped for a positive index.
473 MOZ_ASSERT(ptrValue >= 0);
474 ptrAlloc = LAllocation(ptr->toConstant()->vp());
475 } else
476 ptrAlloc = useRegisterAtStart(ptr);
478 return define(new(alloc()) LAsmJSLoadHeap(ptrAlloc), ins);
479 }
481 bool
482 LIRGeneratorMIPS::visitAsmJSStoreHeap(MAsmJSStoreHeap *ins)
483 {
484 MDefinition *ptr = ins->ptr();
485 MOZ_ASSERT(ptr->type() == MIRType_Int32);
486 LAllocation ptrAlloc;
488 if (ptr->isConstant() && ins->skipBoundsCheck()) {
489 MOZ_ASSERT(ptr->toConstant()->value().toInt32() >= 0);
490 ptrAlloc = LAllocation(ptr->toConstant()->vp());
491 } else
492 ptrAlloc = useRegisterAtStart(ptr);
494 return add(new(alloc()) LAsmJSStoreHeap(ptrAlloc, useRegisterAtStart(ins->value())), ins);
495 }
497 bool
498 LIRGeneratorMIPS::visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr *ins)
499 {
500 return define(new(alloc()) LAsmJSLoadFuncPtr(useRegister(ins->index()), temp()), ins);
501 }
503 bool
504 LIRGeneratorMIPS::lowerTruncateDToInt32(MTruncateToInt32 *ins)
505 {
506 MDefinition *opd = ins->input();
507 MOZ_ASSERT(opd->type() == MIRType_Double);
509 return define(new(alloc()) LTruncateDToInt32(useRegister(opd), LDefinition::BogusTemp()), ins);
510 }
512 bool
513 LIRGeneratorMIPS::lowerTruncateFToInt32(MTruncateToInt32 *ins)
514 {
515 MDefinition *opd = ins->input();
516 MOZ_ASSERT(opd->type() == MIRType_Float32);
518 return define(new(alloc()) LTruncateFToInt32(useRegister(opd), LDefinition::BogusTemp()), ins);
519 }
521 bool
522 LIRGeneratorMIPS::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins)
523 {
524 MOZ_ASSUME_UNREACHABLE("NYI");
525 }
527 bool
528 LIRGeneratorMIPS::visitForkJoinGetSlice(MForkJoinGetSlice *ins)
529 {
530 MOZ_ASSUME_UNREACHABLE("NYI");
531 }