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 #ifndef jit_shared_Lowering_shared_inl_h
8 #define jit_shared_Lowering_shared_inl_h
10 #include "jit/shared/Lowering-shared.h"
12 #include "jit/MIR.h"
13 #include "jit/MIRGenerator.h"
15 namespace js {
16 namespace jit {
18 bool
19 LIRGeneratorShared::emitAtUses(MInstruction *mir)
20 {
21 JS_ASSERT(mir->canEmitAtUses());
22 mir->setEmittedAtUses();
23 mir->setVirtualRegister(0);
24 return true;
25 }
27 LUse
28 LIRGeneratorShared::use(MDefinition *mir, LUse policy)
29 {
30 // It is illegal to call use() on an instruction with two defs.
31 #if BOX_PIECES > 1
32 JS_ASSERT(mir->type() != MIRType_Value);
33 #endif
34 if (!ensureDefined(mir))
35 return policy;
36 policy.setVirtualRegister(mir->virtualRegister());
37 return policy;
38 }
40 template <size_t X, size_t Y> bool
41 LIRGeneratorShared::define(LInstructionHelper<1, X, Y> *lir, MDefinition *mir, const LDefinition &def)
42 {
43 // Call instructions should use defineReturn.
44 JS_ASSERT(!lir->isCall());
46 uint32_t vreg = getVirtualRegister();
47 if (vreg >= MAX_VIRTUAL_REGISTERS)
48 return false;
50 // Assign the definition and a virtual register. Then, propagate this
51 // virtual register to the MIR, so we can map MIR to LIR during lowering.
52 lir->setDef(0, def);
53 lir->getDef(0)->setVirtualRegister(vreg);
54 lir->setMir(mir);
55 mir->setVirtualRegister(vreg);
56 return add(lir);
57 }
59 template <size_t X, size_t Y> bool
60 LIRGeneratorShared::define(LInstructionHelper<1, X, Y> *lir, MDefinition *mir, LDefinition::Policy policy)
61 {
62 LDefinition::Type type = LDefinition::TypeFrom(mir->type());
63 return define(lir, mir, LDefinition(type, policy));
64 }
66 template <size_t X, size_t Y> bool
67 LIRGeneratorShared::defineFixed(LInstructionHelper<1, X, Y> *lir, MDefinition *mir, const LAllocation &output)
68 {
69 LDefinition::Type type = LDefinition::TypeFrom(mir->type());
71 LDefinition def(type, LDefinition::PRESET);
72 def.setOutput(output);
74 // Add an LNop to avoid regalloc problems if the next op uses this value
75 // with a fixed or at-start policy.
76 if (!define(lir, mir, def))
77 return false;
79 if (gen->optimizationInfo().registerAllocator() == RegisterAllocator_LSRA) {
80 if (!add(new(alloc()) LNop))
81 return false;
82 }
84 return true;
85 }
87 template <size_t Ops, size_t Temps> bool
88 LIRGeneratorShared::defineReuseInput(LInstructionHelper<1, Ops, Temps> *lir, MDefinition *mir, uint32_t operand)
89 {
90 // The input should be used at the start of the instruction, to avoid moves.
91 JS_ASSERT(lir->getOperand(operand)->toUse()->usedAtStart());
93 LDefinition::Type type = LDefinition::TypeFrom(mir->type());
95 LDefinition def(type, LDefinition::MUST_REUSE_INPUT);
96 def.setReusedInput(operand);
98 return define(lir, mir, def);
99 }
101 template <size_t Ops, size_t Temps> bool
102 LIRGeneratorShared::defineBox(LInstructionHelper<BOX_PIECES, Ops, Temps> *lir, MDefinition *mir,
103 LDefinition::Policy policy)
104 {
105 // Call instructions should use defineReturn.
106 JS_ASSERT(!lir->isCall());
108 uint32_t vreg = getVirtualRegister();
109 if (vreg >= MAX_VIRTUAL_REGISTERS)
110 return false;
112 #if defined(JS_NUNBOX32)
113 lir->setDef(0, LDefinition(vreg + VREG_TYPE_OFFSET, LDefinition::TYPE, policy));
114 lir->setDef(1, LDefinition(vreg + VREG_DATA_OFFSET, LDefinition::PAYLOAD, policy));
115 if (getVirtualRegister() >= MAX_VIRTUAL_REGISTERS)
116 return false;
117 #elif defined(JS_PUNBOX64)
118 lir->setDef(0, LDefinition(vreg, LDefinition::BOX, policy));
119 #endif
120 lir->setMir(mir);
122 mir->setVirtualRegister(vreg);
123 return add(lir);
124 }
126 bool
127 LIRGeneratorShared::defineReturn(LInstruction *lir, MDefinition *mir)
128 {
129 lir->setMir(mir);
131 JS_ASSERT(lir->isCall());
133 uint32_t vreg = getVirtualRegister();
134 if (vreg >= MAX_VIRTUAL_REGISTERS)
135 return false;
137 switch (mir->type()) {
138 case MIRType_Value:
139 #if defined(JS_NUNBOX32)
140 lir->setDef(TYPE_INDEX, LDefinition(vreg + VREG_TYPE_OFFSET, LDefinition::TYPE,
141 LGeneralReg(JSReturnReg_Type)));
142 lir->setDef(PAYLOAD_INDEX, LDefinition(vreg + VREG_DATA_OFFSET, LDefinition::PAYLOAD,
143 LGeneralReg(JSReturnReg_Data)));
145 if (getVirtualRegister() >= MAX_VIRTUAL_REGISTERS)
146 return false;
147 #elif defined(JS_PUNBOX64)
148 lir->setDef(0, LDefinition(vreg, LDefinition::BOX, LGeneralReg(JSReturnReg)));
149 #endif
150 break;
151 case MIRType_Float32:
152 lir->setDef(0, LDefinition(vreg, LDefinition::FLOAT32, LFloatReg(ReturnFloatReg)));
153 break;
154 case MIRType_Double:
155 lir->setDef(0, LDefinition(vreg, LDefinition::DOUBLE, LFloatReg(ReturnFloatReg)));
156 break;
157 default:
158 LDefinition::Type type = LDefinition::TypeFrom(mir->type());
159 JS_ASSERT(type != LDefinition::DOUBLE && type != LDefinition::FLOAT32);
160 lir->setDef(0, LDefinition(vreg, type, LGeneralReg(ReturnReg)));
161 break;
162 }
164 mir->setVirtualRegister(vreg);
165 if (!add(lir))
166 return false;
168 if (gen->optimizationInfo().registerAllocator() == RegisterAllocator_LSRA) {
169 if (!add(new(alloc()) LNop))
170 return false;
171 }
173 return true;
174 }
176 // In LIR, we treat booleans and integers as the same low-level type (INTEGER).
177 // When snapshotting, we recover the actual JS type from MIR. This function
178 // checks that when making redefinitions, we don't accidentally coerce two
179 // incompatible types.
180 static inline bool
181 IsCompatibleLIRCoercion(MIRType to, MIRType from)
182 {
183 if (to == from)
184 return true;
185 if ((to == MIRType_Int32 || to == MIRType_Boolean) &&
186 (from == MIRType_Int32 || from == MIRType_Boolean)) {
187 return true;
188 }
189 return false;
190 }
192 bool
193 LIRGeneratorShared::redefine(MDefinition *def, MDefinition *as)
194 {
195 JS_ASSERT(IsCompatibleLIRCoercion(def->type(), as->type()));
197 // Try to emit MIR marked as emitted-at-uses at, well, uses. For
198 // snapshotting reasons we delay the MIRTypes match, or when we are
199 // coercing between bool and int32 constants.
200 if (as->isEmittedAtUses() &&
201 (def->type() == as->type() ||
202 (as->isConstant() &&
203 (def->type() == MIRType_Int32 || def->type() == MIRType_Boolean) &&
204 (as->type() == MIRType_Int32 || as->type() == MIRType_Boolean))))
205 {
206 MDefinition *replacement;
207 if (def->type() != as->type()) {
208 Value v = as->toConstant()->value();
209 if (as->type() == MIRType_Int32)
210 replacement = MConstant::New(alloc(), BooleanValue(v.toInt32()));
211 else
212 replacement = MConstant::New(alloc(), Int32Value(v.toBoolean()));
213 if (!emitAtUses(replacement->toInstruction()))
214 return false;
215 } else {
216 replacement = as;
217 }
218 def->replaceAllUsesWith(replacement);
219 return true;
220 }
222 if (!ensureDefined(as))
223 return false;
224 def->setVirtualRegister(as->virtualRegister());
225 return true;
226 }
228 bool
229 LIRGeneratorShared::defineAs(LInstruction *outLir, MDefinition *outMir, MDefinition *inMir)
230 {
231 uint32_t vreg = inMir->virtualRegister();
232 LDefinition::Policy policy = LDefinition::PASSTHROUGH;
234 if (outMir->type() == MIRType_Value) {
235 #ifdef JS_NUNBOX32
236 outLir->setDef(TYPE_INDEX,
237 LDefinition(vreg + VREG_TYPE_OFFSET, LDefinition::TYPE, policy));
238 outLir->setDef(PAYLOAD_INDEX,
239 LDefinition(vreg + VREG_DATA_OFFSET, LDefinition::PAYLOAD, policy));
240 #elif JS_PUNBOX64
241 outLir->setDef(0, LDefinition(vreg, LDefinition::BOX, policy));
242 #else
243 # error "Unexpected boxing type"
244 #endif
245 } else {
246 outLir->setDef(0, LDefinition(vreg, LDefinition::TypeFrom(inMir->type()), policy));
247 }
248 outLir->setMir(outMir);
249 return redefine(outMir, inMir);
250 }
252 bool
253 LIRGeneratorShared::ensureDefined(MDefinition *mir)
254 {
255 if (mir->isEmittedAtUses()) {
256 if (!mir->toInstruction()->accept(this))
257 return false;
258 JS_ASSERT(mir->isLowered());
259 }
260 return true;
261 }
263 LUse
264 LIRGeneratorShared::useRegister(MDefinition *mir)
265 {
266 return use(mir, LUse(LUse::REGISTER));
267 }
269 LUse
270 LIRGeneratorShared::useRegisterAtStart(MDefinition *mir)
271 {
272 return use(mir, LUse(LUse::REGISTER, true));
273 }
275 LUse
276 LIRGeneratorShared::use(MDefinition *mir)
277 {
278 return use(mir, LUse(LUse::ANY));
279 }
281 LUse
282 LIRGeneratorShared::useAtStart(MDefinition *mir)
283 {
284 return use(mir, LUse(LUse::ANY, true));
285 }
287 LAllocation
288 LIRGeneratorShared::useOrConstant(MDefinition *mir)
289 {
290 if (mir->isConstant())
291 return LAllocation(mir->toConstant()->vp());
292 return use(mir);
293 }
295 LAllocation
296 LIRGeneratorShared::useRegisterOrConstant(MDefinition *mir)
297 {
298 if (mir->isConstant())
299 return LAllocation(mir->toConstant()->vp());
300 return useRegister(mir);
301 }
303 LAllocation
304 LIRGeneratorShared::useRegisterOrConstantAtStart(MDefinition *mir)
305 {
306 if (mir->isConstant())
307 return LAllocation(mir->toConstant()->vp());
308 return useRegisterAtStart(mir);
309 }
311 LAllocation
312 LIRGeneratorShared::useRegisterOrNonNegativeConstantAtStart(MDefinition *mir)
313 {
314 if (mir->isConstant() && mir->toConstant()->value().toInt32() >= 0)
315 return LAllocation(mir->toConstant()->vp());
316 return useRegisterAtStart(mir);
317 }
319 LAllocation
320 LIRGeneratorShared::useRegisterOrNonDoubleConstant(MDefinition *mir)
321 {
322 if (mir->isConstant() && mir->type() != MIRType_Double && mir->type() != MIRType_Float32)
323 return LAllocation(mir->toConstant()->vp());
324 return useRegister(mir);
325 }
327 #if defined(JS_CODEGEN_ARM)
328 LAllocation
329 LIRGeneratorShared::useAnyOrConstant(MDefinition *mir)
330 {
331 return useRegisterOrConstant(mir);
332 }
333 LAllocation
334 LIRGeneratorShared::useStorable(MDefinition *mir)
335 {
336 return useRegister(mir);
337 }
338 LAllocation
339 LIRGeneratorShared::useStorableAtStart(MDefinition *mir)
340 {
341 return useRegisterAtStart(mir);
342 }
344 LAllocation
345 LIRGeneratorShared::useAny(MDefinition *mir)
346 {
347 return useRegister(mir);
348 }
349 #else
350 LAllocation
351 LIRGeneratorShared::useAnyOrConstant(MDefinition *mir)
352 {
353 return useOrConstant(mir);
354 }
356 LAllocation
357 LIRGeneratorShared::useAny(MDefinition *mir)
358 {
359 return use(mir);
360 }
361 LAllocation
362 LIRGeneratorShared::useStorable(MDefinition *mir)
363 {
364 return useRegisterOrConstant(mir);
365 }
366 LAllocation
367 LIRGeneratorShared::useStorableAtStart(MDefinition *mir)
368 {
369 return useRegisterOrConstantAtStart(mir);
370 }
372 #endif
374 LAllocation
375 LIRGeneratorShared::useKeepaliveOrConstant(MDefinition *mir)
376 {
377 if (mir->isConstant())
378 return LAllocation(mir->toConstant()->vp());
379 return use(mir, LUse(LUse::KEEPALIVE));
380 }
382 LUse
383 LIRGeneratorShared::useFixed(MDefinition *mir, Register reg)
384 {
385 return use(mir, LUse(reg));
386 }
388 LUse
389 LIRGeneratorShared::useFixedAtStart(MDefinition *mir, Register reg)
390 {
391 return use(mir, LUse(reg, true));
392 }
394 LUse
395 LIRGeneratorShared::useFixed(MDefinition *mir, FloatRegister reg)
396 {
397 return use(mir, LUse(reg));
398 }
400 LUse
401 LIRGeneratorShared::useFixed(MDefinition *mir, AnyRegister reg)
402 {
403 return reg.isFloat() ? use(mir, reg.fpu()) : use(mir, reg.gpr());
404 }
406 LDefinition
407 LIRGeneratorShared::temp(LDefinition::Type type, LDefinition::Policy policy)
408 {
409 uint32_t vreg = getVirtualRegister();
410 if (vreg >= MAX_VIRTUAL_REGISTERS) {
411 gen->abort("max virtual registers");
412 return LDefinition();
413 }
414 return LDefinition(vreg, type, policy);
415 }
417 LDefinition
418 LIRGeneratorShared::tempFixed(Register reg)
419 {
420 LDefinition t = temp(LDefinition::GENERAL);
421 t.setOutput(LGeneralReg(reg));
422 return t;
423 }
425 LDefinition
426 LIRGeneratorShared::tempFloat32()
427 {
428 return temp(LDefinition::FLOAT32);
429 }
431 LDefinition
432 LIRGeneratorShared::tempDouble()
433 {
434 return temp(LDefinition::DOUBLE);
435 }
437 LDefinition
438 LIRGeneratorShared::tempCopy(MDefinition *input, uint32_t reusedInput)
439 {
440 JS_ASSERT(input->virtualRegister());
441 LDefinition t = temp(LDefinition::TypeFrom(input->type()), LDefinition::MUST_REUSE_INPUT);
442 t.setReusedInput(reusedInput);
443 return t;
444 }
446 template <typename T> void
447 LIRGeneratorShared::annotate(T *ins)
448 {
449 ins->setId(lirGraph_.getInstructionId());
450 }
452 template <typename T> bool
453 LIRGeneratorShared::add(T *ins, MInstruction *mir)
454 {
455 JS_ASSERT(!ins->isPhi());
456 current->add(ins);
457 if (mir) {
458 JS_ASSERT(current == mir->block()->lir());
459 ins->setMir(mir);
460 }
461 annotate(ins);
462 return true;
463 }
465 #ifdef JS_NUNBOX32
466 // Returns the virtual register of a js::Value-defining instruction. This is
467 // abstracted because MBox is a special value-returning instruction that
468 // redefines its input payload if its input is not constant. Therefore, it is
469 // illegal to request a box's payload by adding VREG_DATA_OFFSET to its raw id.
470 static inline uint32_t
471 VirtualRegisterOfPayload(MDefinition *mir)
472 {
473 if (mir->isBox()) {
474 MDefinition *inner = mir->toBox()->getOperand(0);
475 if (!inner->isConstant() && inner->type() != MIRType_Double && inner->type() != MIRType_Float32)
476 return inner->virtualRegister();
477 }
478 if (mir->isTypeBarrier())
479 return VirtualRegisterOfPayload(mir->getOperand(0));
480 return mir->virtualRegister() + VREG_DATA_OFFSET;
481 }
483 // Note: always call ensureDefined before calling useType/usePayload,
484 // so that emitted-at-use operands are handled correctly.
485 LUse
486 LIRGeneratorShared::useType(MDefinition *mir, LUse::Policy policy)
487 {
488 JS_ASSERT(mir->type() == MIRType_Value);
490 return LUse(mir->virtualRegister() + VREG_TYPE_OFFSET, policy);
491 }
493 LUse
494 LIRGeneratorShared::usePayload(MDefinition *mir, LUse::Policy policy)
495 {
496 JS_ASSERT(mir->type() == MIRType_Value);
498 return LUse(VirtualRegisterOfPayload(mir), policy);
499 }
501 LUse
502 LIRGeneratorShared::usePayloadAtStart(MDefinition *mir, LUse::Policy policy)
503 {
504 JS_ASSERT(mir->type() == MIRType_Value);
506 return LUse(VirtualRegisterOfPayload(mir), policy, true);
507 }
509 LUse
510 LIRGeneratorShared::usePayloadInRegisterAtStart(MDefinition *mir)
511 {
512 return usePayloadAtStart(mir, LUse::REGISTER);
513 }
515 bool
516 LIRGeneratorShared::fillBoxUses(LInstruction *lir, size_t n, MDefinition *mir)
517 {
518 if (!ensureDefined(mir))
519 return false;
520 lir->getOperand(n)->toUse()->setVirtualRegister(mir->virtualRegister() + VREG_TYPE_OFFSET);
521 lir->getOperand(n + 1)->toUse()->setVirtualRegister(VirtualRegisterOfPayload(mir));
522 return true;
523 }
524 #endif
526 } // namespace jit
527 } // namespace js
529 #endif /* jit_shared_Lowering_shared_inl_h */