Line data Source code
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 : #ifndef jit_shared_Lowering_shared_inl_h
8 : #define jit_shared_Lowering_shared_inl_h
9 :
10 : #include "jit/shared/Lowering-shared.h"
11 :
12 : #include "jit/MIR.h"
13 : #include "jit/MIRGenerator.h"
14 :
15 : namespace js {
16 : namespace jit {
17 :
18 : void
19 237 : LIRGeneratorShared::emitAtUses(MInstruction* mir)
20 : {
21 237 : MOZ_ASSERT(mir->canEmitAtUses());
22 237 : mir->setEmittedAtUses();
23 237 : mir->setVirtualRegister(0);
24 237 : }
25 :
26 : LUse
27 5866 : LIRGeneratorShared::use(MDefinition* mir, LUse policy)
28 : {
29 : // It is illegal to call use() on an instruction with two defs.
30 : #if BOX_PIECES > 1
31 : MOZ_ASSERT(mir->type() != MIRType::Value);
32 : #endif
33 : #if INT64_PIECES > 1
34 : MOZ_ASSERT(mir->type() != MIRType::Int64);
35 : #endif
36 5866 : ensureDefined(mir);
37 5866 : policy.setVirtualRegister(mir->virtualRegister());
38 5866 : return policy;
39 : }
40 :
41 : template <size_t X> void
42 289 : LIRGeneratorShared::define(details::LInstructionFixedDefsTempsHelper<1, X>* lir, MDefinition* mir,
43 : LDefinition::Policy policy)
44 : {
45 289 : LDefinition::Type type = LDefinition::TypeFrom(mir->type());
46 289 : define(lir, mir, LDefinition(type, policy));
47 289 : }
48 :
49 : template <size_t X> void
50 404 : LIRGeneratorShared::define(details::LInstructionFixedDefsTempsHelper<1, X>* lir, MDefinition* mir,
51 : const LDefinition& def)
52 : {
53 : // Call instructions should use defineReturn.
54 404 : MOZ_ASSERT(!lir->isCall());
55 :
56 404 : uint32_t vreg = getVirtualRegister();
57 :
58 : // Assign the definition and a virtual register. Then, propagate this
59 : // virtual register to the MIR, so we can map MIR to LIR during lowering.
60 404 : lir->setDef(0, def);
61 404 : lir->getDef(0)->setVirtualRegister(vreg);
62 404 : lir->setMir(mir);
63 404 : mir->setVirtualRegister(vreg);
64 404 : add(lir);
65 404 : }
66 :
67 : template <size_t X, size_t Y> void
68 15 : LIRGeneratorShared::defineFixed(LInstructionHelper<1, X, Y>* lir, MDefinition* mir,
69 : const LAllocation& output)
70 : {
71 15 : LDefinition::Type type = LDefinition::TypeFrom(mir->type());
72 :
73 15 : LDefinition def(type, LDefinition::FIXED);
74 15 : def.setOutput(output);
75 :
76 15 : define(lir, mir, def);
77 15 : }
78 :
79 : template <size_t Ops, size_t Temps> void
80 0 : LIRGeneratorShared::defineInt64Fixed(LInstructionHelper<INT64_PIECES, Ops, Temps>* lir, MDefinition* mir,
81 : const LInt64Allocation& output)
82 : {
83 0 : uint32_t vreg = getVirtualRegister();
84 :
85 : #if JS_BITS_PER_WORD == 64
86 0 : LDefinition def(LDefinition::GENERAL, LDefinition::FIXED);
87 0 : def.setOutput(output.value());
88 0 : lir->setDef(0, def);
89 0 : lir->getDef(0)->setVirtualRegister(vreg);
90 : #else
91 : LDefinition def0(LDefinition::GENERAL, LDefinition::FIXED);
92 : def0.setOutput(output.low());
93 : lir->setDef(0, def0);
94 : lir->getDef(0)->setVirtualRegister(vreg);
95 :
96 : getVirtualRegister();
97 : LDefinition def1(LDefinition::GENERAL, LDefinition::FIXED);
98 : def1.setOutput(output.high());
99 : lir->setDef(1, def1);
100 : lir->getDef(1)->setVirtualRegister(vreg + 1);
101 : #endif
102 :
103 0 : lir->setMir(mir);
104 0 : mir->setVirtualRegister(vreg);
105 0 : add(lir);
106 0 : }
107 :
108 : template <size_t Ops, size_t Temps> void
109 13 : LIRGeneratorShared::defineReuseInput(LInstructionHelper<1, Ops, Temps>* lir, MDefinition* mir, uint32_t operand)
110 : {
111 : // Note: Any other operand that is not the same as this operand should be
112 : // marked as not being "atStart". The regalloc cannot handle those and can
113 : // overwrite the inputs!
114 :
115 : // The input should be used at the start of the instruction, to avoid moves.
116 13 : MOZ_ASSERT(lir->getOperand(operand)->toUse()->usedAtStart());
117 :
118 13 : LDefinition::Type type = LDefinition::TypeFrom(mir->type());
119 :
120 13 : LDefinition def(type, LDefinition::MUST_REUSE_INPUT);
121 13 : def.setReusedInput(operand);
122 :
123 13 : define(lir, mir, def);
124 13 : }
125 :
126 : template <size_t Ops, size_t Temps> void
127 0 : LIRGeneratorShared::defineInt64ReuseInput(LInstructionHelper<INT64_PIECES, Ops, Temps>* lir,
128 : MDefinition* mir, uint32_t operand)
129 : {
130 : // Note: Any other operand that is not the same as this operand should be
131 : // marked as not being "atStart". The regalloc cannot handle those and can
132 : // overwrite the inputs!
133 :
134 : // The input should be used at the start of the instruction, to avoid moves.
135 0 : MOZ_ASSERT(lir->getOperand(operand)->toUse()->usedAtStart());
136 : #if JS_BITS_PER_WORD == 32
137 : MOZ_ASSERT(lir->getOperand(operand + 1)->toUse()->usedAtStart());
138 : #endif
139 0 : MOZ_ASSERT(!lir->isCall());
140 :
141 0 : uint32_t vreg = getVirtualRegister();
142 :
143 0 : LDefinition def1(LDefinition::GENERAL, LDefinition::MUST_REUSE_INPUT);
144 0 : def1.setReusedInput(operand);
145 0 : lir->setDef(0, def1);
146 0 : lir->getDef(0)->setVirtualRegister(vreg);
147 :
148 : #if JS_BITS_PER_WORD == 32
149 : getVirtualRegister();
150 : LDefinition def2(LDefinition::GENERAL, LDefinition::MUST_REUSE_INPUT);
151 : def2.setReusedInput(operand + 1);
152 : lir->setDef(1, def2);
153 : lir->getDef(1)->setVirtualRegister(vreg + 1);
154 : #endif
155 :
156 0 : lir->setMir(mir);
157 0 : mir->setVirtualRegister(vreg);
158 0 : add(lir);
159 :
160 0 : }
161 :
162 : template <size_t Ops, size_t Temps> void
163 132 : LIRGeneratorShared::defineBox(LInstructionHelper<BOX_PIECES, Ops, Temps>* lir, MDefinition* mir,
164 : LDefinition::Policy policy)
165 : {
166 : // Call instructions should use defineReturn.
167 132 : MOZ_ASSERT(!lir->isCall());
168 132 : MOZ_ASSERT(mir->type() == MIRType::Value);
169 :
170 132 : uint32_t vreg = getVirtualRegister();
171 :
172 : #if defined(JS_NUNBOX32)
173 : lir->setDef(0, LDefinition(vreg + VREG_TYPE_OFFSET, LDefinition::TYPE, policy));
174 : lir->setDef(1, LDefinition(vreg + VREG_DATA_OFFSET, LDefinition::PAYLOAD, policy));
175 : getVirtualRegister();
176 : #elif defined(JS_PUNBOX64)
177 132 : lir->setDef(0, LDefinition(vreg, LDefinition::BOX, policy));
178 : #endif
179 132 : lir->setMir(mir);
180 :
181 132 : mir->setVirtualRegister(vreg);
182 132 : add(lir);
183 132 : }
184 :
185 : template <size_t Ops, size_t Temps> void
186 0 : LIRGeneratorShared::defineInt64(LInstructionHelper<INT64_PIECES, Ops, Temps>* lir, MDefinition* mir,
187 : LDefinition::Policy policy)
188 : {
189 : // Call instructions should use defineReturn.
190 0 : MOZ_ASSERT(!lir->isCall());
191 0 : MOZ_ASSERT(mir->type() == MIRType::Int64);
192 :
193 0 : uint32_t vreg = getVirtualRegister();
194 :
195 : #if JS_BITS_PER_WORD == 32
196 : lir->setDef(0, LDefinition(vreg + INT64LOW_INDEX, LDefinition::GENERAL, policy));
197 : lir->setDef(1, LDefinition(vreg + INT64HIGH_INDEX, LDefinition::GENERAL, policy));
198 : getVirtualRegister();
199 : #else
200 0 : lir->setDef(0, LDefinition(vreg, LDefinition::GENERAL, policy));
201 : #endif
202 0 : lir->setMir(mir);
203 :
204 0 : mir->setVirtualRegister(vreg);
205 0 : add(lir);
206 0 : }
207 :
208 : void
209 0 : LIRGeneratorShared::defineSharedStubReturn(LInstruction* lir, MDefinition* mir)
210 : {
211 0 : lir->setMir(mir);
212 :
213 0 : MOZ_ASSERT(lir->isBinarySharedStub() || lir->isUnarySharedStub() || lir->isNullarySharedStub());
214 0 : MOZ_ASSERT(mir->type() == MIRType::Value);
215 :
216 0 : uint32_t vreg = getVirtualRegister();
217 :
218 : #if defined(JS_NUNBOX32)
219 : lir->setDef(TYPE_INDEX, LDefinition(vreg + VREG_TYPE_OFFSET, LDefinition::TYPE,
220 : LGeneralReg(JSReturnReg_Type)));
221 : lir->setDef(PAYLOAD_INDEX, LDefinition(vreg + VREG_DATA_OFFSET, LDefinition::PAYLOAD,
222 : LGeneralReg(JSReturnReg_Data)));
223 : getVirtualRegister();
224 : #elif defined(JS_PUNBOX64)
225 0 : lir->setDef(0, LDefinition(vreg, LDefinition::BOX, LGeneralReg(JSReturnReg)));
226 : #endif
227 :
228 0 : mir->setVirtualRegister(vreg);
229 0 : add(lir);
230 0 : }
231 :
232 : void
233 37 : LIRGeneratorShared::defineReturn(LInstruction* lir, MDefinition* mir)
234 : {
235 37 : lir->setMir(mir);
236 :
237 37 : MOZ_ASSERT(lir->isCall());
238 37 : gen->setNeedsStaticStackAlignment();
239 :
240 37 : uint32_t vreg = getVirtualRegister();
241 :
242 37 : switch (mir->type()) {
243 : case MIRType::Value:
244 : #if defined(JS_NUNBOX32)
245 : lir->setDef(TYPE_INDEX, LDefinition(vreg + VREG_TYPE_OFFSET, LDefinition::TYPE,
246 : LGeneralReg(JSReturnReg_Type)));
247 : lir->setDef(PAYLOAD_INDEX, LDefinition(vreg + VREG_DATA_OFFSET, LDefinition::PAYLOAD,
248 : LGeneralReg(JSReturnReg_Data)));
249 : getVirtualRegister();
250 : #elif defined(JS_PUNBOX64)
251 35 : lir->setDef(0, LDefinition(vreg, LDefinition::BOX, LGeneralReg(JSReturnReg)));
252 : #endif
253 35 : break;
254 : case MIRType::Int64:
255 : #if defined(JS_NUNBOX32)
256 : lir->setDef(INT64LOW_INDEX, LDefinition(vreg + INT64LOW_INDEX, LDefinition::GENERAL,
257 : LGeneralReg(ReturnReg64.low)));
258 : lir->setDef(INT64HIGH_INDEX, LDefinition(vreg + INT64HIGH_INDEX, LDefinition::GENERAL,
259 : LGeneralReg(ReturnReg64.high)));
260 : getVirtualRegister();
261 : #elif defined(JS_PUNBOX64)
262 0 : lir->setDef(0, LDefinition(vreg, LDefinition::GENERAL, LGeneralReg(ReturnReg)));
263 : #endif
264 0 : break;
265 : case MIRType::Float32:
266 0 : lir->setDef(0, LDefinition(vreg, LDefinition::FLOAT32, LFloatReg(ReturnFloat32Reg)));
267 0 : break;
268 : case MIRType::Double:
269 0 : lir->setDef(0, LDefinition(vreg, LDefinition::DOUBLE, LFloatReg(ReturnDoubleReg)));
270 0 : break;
271 : case MIRType::Int8x16:
272 : case MIRType::Int16x8:
273 : case MIRType::Int32x4:
274 : case MIRType::Bool8x16:
275 : case MIRType::Bool16x8:
276 : case MIRType::Bool32x4:
277 0 : lir->setDef(0, LDefinition(vreg, LDefinition::SIMD128INT, LFloatReg(ReturnSimd128Reg)));
278 0 : break;
279 : case MIRType::Float32x4:
280 0 : lir->setDef(0, LDefinition(vreg, LDefinition::SIMD128FLOAT, LFloatReg(ReturnSimd128Reg)));
281 0 : break;
282 : default:
283 2 : LDefinition::Type type = LDefinition::TypeFrom(mir->type());
284 2 : MOZ_ASSERT(type != LDefinition::DOUBLE && type != LDefinition::FLOAT32);
285 2 : lir->setDef(0, LDefinition(vreg, type, LGeneralReg(ReturnReg)));
286 2 : break;
287 : }
288 :
289 37 : mir->setVirtualRegister(vreg);
290 37 : add(lir);
291 37 : }
292 :
293 : template <size_t Ops, size_t Temps> void
294 0 : LIRGeneratorShared::defineSinCos(LInstructionHelper<2, Ops, Temps> *lir, MDefinition *mir,
295 : LDefinition::Policy policy)
296 : {
297 0 : MOZ_ASSERT(lir->isCall());
298 :
299 0 : uint32_t vreg = getVirtualRegister();
300 0 : lir->setDef(0, LDefinition(vreg, LDefinition::DOUBLE, LFloatReg(ReturnDoubleReg)));
301 : #if defined(JS_CODEGEN_ARM)
302 : lir->setDef(1, LDefinition(vreg + VREG_INCREMENT, LDefinition::DOUBLE,
303 : LFloatReg(FloatRegister(FloatRegisters::d1, FloatRegister::Double))));
304 : #elif defined(JS_CODEGEN_ARM64)
305 : lir->setDef(1, LDefinition(vreg + VREG_INCREMENT, LDefinition::DOUBLE,
306 : LFloatReg(FloatRegister(FloatRegisters::d1, FloatRegisters::Double))));
307 : #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
308 : lir->setDef(1, LDefinition(vreg + VREG_INCREMENT, LDefinition::DOUBLE, LFloatReg(f2)));
309 : #elif defined(JS_CODEGEN_NONE)
310 : MOZ_CRASH();
311 : #elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
312 0 : lir->setDef(1, LDefinition(vreg + VREG_INCREMENT, LDefinition::DOUBLE, LFloatReg(xmm1)));
313 : #else
314 : #error "Unsupported architecture for SinCos"
315 : #endif
316 :
317 0 : getVirtualRegister();
318 :
319 0 : lir->setMir(mir);
320 0 : mir->setVirtualRegister(vreg);
321 0 : add(lir);
322 :
323 0 : return;
324 : }
325 :
326 : // In LIR, we treat booleans and integers as the same low-level type (INTEGER).
327 : // When snapshotting, we recover the actual JS type from MIR. This function
328 : // checks that when making redefinitions, we don't accidentally coerce two
329 : // incompatible types.
330 : static inline bool
331 153 : IsCompatibleLIRCoercion(MIRType to, MIRType from)
332 : {
333 153 : if (to == from)
334 153 : return true;
335 0 : if ((to == MIRType::Int32 || to == MIRType::Boolean) &&
336 0 : (from == MIRType::Int32 || from == MIRType::Boolean)) {
337 0 : return true;
338 : }
339 : // SIMD types can be coerced with from*Bits operators.
340 0 : if (IsSimdType(to) && IsSimdType(from))
341 0 : return true;
342 0 : return false;
343 : }
344 :
345 :
346 : // We can redefine the sin(x) and cos(x) function to return the sincos result.
347 : void
348 0 : LIRGeneratorShared::redefine(MDefinition* def, MDefinition* as, MMathFunction::Function func)
349 : {
350 0 : MOZ_ASSERT(def->isMathFunction());
351 0 : MOZ_ASSERT(def->type() == MIRType::Double && as->type() == MIRType::SinCosDouble);
352 0 : MOZ_ASSERT(MMathFunction::Sin == func || MMathFunction::Cos == func);
353 :
354 0 : ensureDefined(as);
355 0 : MMathFunction *math = def->toMathFunction();
356 :
357 0 : MOZ_ASSERT(math->function() == MMathFunction::Cos ||
358 : math->function() == MMathFunction::Sin);
359 :
360 : // The sincos returns two values:
361 : // - VREG: it returns the sin's value of the sincos;
362 : // - VREG + VREG_INCREMENT: it returns the cos' value of the sincos.
363 0 : if (math->function() == MMathFunction::Sin)
364 0 : def->setVirtualRegister(as->virtualRegister());
365 : else
366 0 : def->setVirtualRegister(as->virtualRegister() + VREG_INCREMENT);
367 0 : }
368 :
369 : void
370 153 : LIRGeneratorShared::redefine(MDefinition* def, MDefinition* as)
371 : {
372 153 : MOZ_ASSERT(IsCompatibleLIRCoercion(def->type(), as->type()));
373 :
374 : // Try to emit MIR marked as emitted-at-uses at, well, uses. For
375 : // snapshotting reasons we delay the MIRTypes match, or when we are
376 : // coercing between bool and int32 constants.
377 153 : if (as->isEmittedAtUses() &&
378 0 : (def->type() == as->type() ||
379 0 : (as->isConstant() &&
380 0 : (def->type() == MIRType::Int32 || def->type() == MIRType::Boolean) &&
381 0 : (as->type() == MIRType::Int32 || as->type() == MIRType::Boolean))))
382 : {
383 : MInstruction* replacement;
384 0 : if (def->type() != as->type()) {
385 0 : if (as->type() == MIRType::Int32)
386 0 : replacement = MConstant::New(alloc(), BooleanValue(as->toConstant()->toInt32()));
387 : else
388 0 : replacement = MConstant::New(alloc(), Int32Value(as->toConstant()->toBoolean()));
389 0 : def->block()->insertBefore(def->toInstruction(), replacement);
390 0 : emitAtUses(replacement->toInstruction());
391 : } else {
392 0 : replacement = as->toInstruction();
393 : }
394 0 : def->replaceAllUsesWith(replacement);
395 : } else {
396 153 : ensureDefined(as);
397 153 : def->setVirtualRegister(as->virtualRegister());
398 :
399 : #ifdef DEBUG
400 306 : if (JitOptions.runExtraChecks &&
401 153 : def->resultTypeSet() && as->resultTypeSet() &&
402 0 : !def->resultTypeSet()->equals(as->resultTypeSet()))
403 : {
404 0 : switch (def->type()) {
405 : case MIRType::Object:
406 : case MIRType::ObjectOrNull:
407 : case MIRType::String:
408 : case MIRType::Symbol: {
409 0 : LAssertResultT* check = new(alloc()) LAssertResultT(useRegister(def));
410 0 : add(check, def->toInstruction());
411 0 : break;
412 : }
413 : case MIRType::Value: {
414 0 : LAssertResultV* check = new(alloc()) LAssertResultV(useBox(def));
415 0 : add(check, def->toInstruction());
416 0 : break;
417 : }
418 : default:
419 0 : break;
420 : }
421 : }
422 : #endif
423 : }
424 153 : }
425 :
426 : void
427 6554 : LIRGeneratorShared::ensureDefined(MDefinition* mir)
428 : {
429 6554 : if (mir->isEmittedAtUses()) {
430 118 : mir->toInstruction()->accept(this);
431 118 : MOZ_ASSERT(mir->isLowered());
432 : }
433 6554 : }
434 :
435 : LUse
436 387 : LIRGeneratorShared::useRegister(MDefinition* mir)
437 : {
438 387 : return use(mir, LUse(LUse::REGISTER));
439 : }
440 :
441 : LUse
442 177 : LIRGeneratorShared::useRegisterAtStart(MDefinition* mir)
443 : {
444 177 : return use(mir, LUse(LUse::REGISTER, true));
445 : }
446 :
447 : LUse
448 9 : LIRGeneratorShared::use(MDefinition* mir)
449 : {
450 9 : return use(mir, LUse(LUse::ANY));
451 : }
452 :
453 : LUse
454 29 : LIRGeneratorShared::useAtStart(MDefinition* mir)
455 : {
456 29 : return use(mir, LUse(LUse::ANY, true));
457 : }
458 :
459 : LAllocation
460 54 : LIRGeneratorShared::useOrConstant(MDefinition* mir)
461 : {
462 54 : if (mir->isConstant())
463 45 : return LAllocation(mir->toConstant());
464 9 : return use(mir);
465 : }
466 :
467 : LAllocation
468 0 : LIRGeneratorShared::useOrConstantAtStart(MDefinition* mir)
469 : {
470 0 : if (mir->isConstant())
471 0 : return LAllocation(mir->toConstant());
472 0 : return useAtStart(mir);
473 : }
474 :
475 : LAllocation
476 110 : LIRGeneratorShared::useRegisterOrConstant(MDefinition* mir)
477 : {
478 110 : if (mir->isConstant())
479 54 : return LAllocation(mir->toConstant());
480 56 : return useRegister(mir);
481 : }
482 :
483 : LAllocation
484 8 : LIRGeneratorShared::useRegisterOrConstantAtStart(MDefinition* mir)
485 : {
486 8 : if (mir->isConstant())
487 0 : return LAllocation(mir->toConstant());
488 8 : return useRegisterAtStart(mir);
489 : }
490 :
491 : LAllocation
492 : LIRGeneratorShared::useRegisterOrZero(MDefinition* mir)
493 : {
494 : if (mir->isConstant() && mir->toConstant()->isInt32(0))
495 : return LAllocation();
496 : return useRegister(mir);
497 : }
498 :
499 : LAllocation
500 0 : LIRGeneratorShared::useRegisterOrZeroAtStart(MDefinition* mir)
501 : {
502 0 : if (mir->isConstant() && mir->toConstant()->isInt32(0))
503 0 : return LAllocation();
504 0 : return useRegisterAtStart(mir);
505 : }
506 :
507 : LAllocation
508 6 : LIRGeneratorShared::useRegisterOrNonDoubleConstant(MDefinition* mir)
509 : {
510 6 : if (mir->isConstant() && mir->type() != MIRType::Double && mir->type() != MIRType::Float32)
511 0 : return LAllocation(mir->toConstant());
512 6 : return useRegister(mir);
513 : }
514 :
515 : #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
516 : LAllocation
517 : LIRGeneratorShared::useAnyOrConstant(MDefinition* mir)
518 : {
519 : return useRegisterOrConstant(mir);
520 : }
521 : LAllocation
522 : LIRGeneratorShared::useStorable(MDefinition* mir)
523 : {
524 : return useRegister(mir);
525 : }
526 : LAllocation
527 : LIRGeneratorShared::useStorableAtStart(MDefinition* mir)
528 : {
529 : return useRegisterAtStart(mir);
530 : }
531 :
532 : LAllocation
533 : LIRGeneratorShared::useAny(MDefinition* mir)
534 : {
535 : return useRegister(mir);
536 : }
537 : #else
538 : LAllocation
539 46 : LIRGeneratorShared::useAnyOrConstant(MDefinition* mir)
540 : {
541 46 : return useOrConstant(mir);
542 : }
543 :
544 : LAllocation
545 0 : LIRGeneratorShared::useAny(MDefinition* mir)
546 : {
547 0 : return use(mir);
548 : }
549 : LAllocation
550 : LIRGeneratorShared::useStorable(MDefinition* mir)
551 : {
552 : return useRegisterOrConstant(mir);
553 : }
554 : LAllocation
555 : LIRGeneratorShared::useStorableAtStart(MDefinition* mir)
556 : {
557 : return useRegisterOrConstantAtStart(mir);
558 : }
559 :
560 : #endif
561 :
562 : LAllocation
563 5204 : LIRGeneratorShared::useKeepalive(MDefinition* mir)
564 : {
565 5204 : return use(mir, LUse(LUse::KEEPALIVE));
566 : }
567 :
568 : LAllocation
569 7013 : LIRGeneratorShared::useKeepaliveOrConstant(MDefinition* mir)
570 : {
571 7013 : if (mir->isConstant())
572 1811 : return LAllocation(mir->toConstant());
573 5202 : return useKeepalive(mir);
574 : }
575 :
576 : LUse
577 17 : LIRGeneratorShared::useFixed(MDefinition* mir, Register reg)
578 : {
579 17 : return use(mir, LUse(reg));
580 : }
581 :
582 : LUse
583 43 : LIRGeneratorShared::useFixedAtStart(MDefinition* mir, Register reg)
584 : {
585 43 : return use(mir, LUse(reg, true));
586 : }
587 :
588 : LUse
589 0 : LIRGeneratorShared::useFixed(MDefinition* mir, FloatRegister reg)
590 : {
591 0 : return use(mir, LUse(reg));
592 : }
593 :
594 : LUse
595 : LIRGeneratorShared::useFixed(MDefinition* mir, AnyRegister reg)
596 : {
597 : return reg.isFloat() ? use(mir, LUse(reg.fpu())) : use(mir, LUse(reg.gpr()));
598 : }
599 :
600 : LUse
601 0 : LIRGeneratorShared::useFixedAtStart(MDefinition* mir, AnyRegister reg)
602 : {
603 0 : return reg.isFloat() ? use(mir, LUse(reg.fpu(), true)) : use(mir, LUse(reg.gpr(), true));
604 : }
605 :
606 : LDefinition
607 314 : LIRGeneratorShared::temp(LDefinition::Type type, LDefinition::Policy policy)
608 : {
609 314 : return LDefinition(getVirtualRegister(), type, policy);
610 : }
611 :
612 : LInt64Definition
613 : LIRGeneratorShared::tempInt64(LDefinition::Policy policy)
614 : {
615 : #if JS_BITS_PER_WORD == 32
616 : LDefinition high = temp(LDefinition::GENERAL, policy);
617 : LDefinition low = temp(LDefinition::GENERAL, policy);
618 : return LInt64Definition(high, low);
619 : #else
620 : return LInt64Definition(temp(LDefinition::GENERAL, policy));
621 : #endif
622 : }
623 :
624 : LDefinition
625 126 : LIRGeneratorShared::tempFixed(Register reg)
626 : {
627 126 : LDefinition t = temp(LDefinition::GENERAL);
628 126 : t.setOutput(LGeneralReg(reg));
629 126 : return t;
630 : }
631 :
632 : LDefinition
633 0 : LIRGeneratorShared::tempFloat32()
634 : {
635 0 : return temp(LDefinition::FLOAT32);
636 : }
637 :
638 : LDefinition
639 40 : LIRGeneratorShared::tempDouble()
640 : {
641 40 : return temp(LDefinition::DOUBLE);
642 : }
643 :
644 : LDefinition
645 0 : LIRGeneratorShared::tempCopy(MDefinition* input, uint32_t reusedInput)
646 : {
647 0 : MOZ_ASSERT(input->virtualRegister());
648 0 : LDefinition t = temp(LDefinition::TypeFrom(input->type()), LDefinition::MUST_REUSE_INPUT);
649 0 : t.setReusedInput(reusedInput);
650 0 : return t;
651 : }
652 :
653 : template <typename T> void
654 1534 : LIRGeneratorShared::annotate(T* ins)
655 : {
656 1534 : ins->setId(lirGraph_.getInstructionId());
657 1534 : }
658 :
659 : template <typename T> void
660 1359 : LIRGeneratorShared::add(T* ins, MInstruction* mir)
661 : {
662 1359 : MOZ_ASSERT(!ins->isPhi());
663 1359 : current->add(ins);
664 1359 : if (mir) {
665 242 : MOZ_ASSERT(current == mir->block()->lir());
666 242 : ins->setMir(mir);
667 : }
668 1359 : annotate(ins);
669 1359 : }
670 :
671 : #ifdef JS_NUNBOX32
672 : // Returns the virtual register of a js::Value-defining instruction. This is
673 : // abstracted because MBox is a special value-returning instruction that
674 : // redefines its input payload if its input is not constant. Therefore, it is
675 : // illegal to request a box's payload by adding VREG_DATA_OFFSET to its raw id.
676 : static inline uint32_t
677 : VirtualRegisterOfPayload(MDefinition* mir)
678 : {
679 : if (mir->isBox()) {
680 : MDefinition* inner = mir->toBox()->getOperand(0);
681 : if (!inner->isConstant() && inner->type() != MIRType::Double && inner->type() != MIRType::Float32)
682 : return inner->virtualRegister();
683 : }
684 : if (mir->isTypeBarrier())
685 : return VirtualRegisterOfPayload(mir->getOperand(0));
686 : return mir->virtualRegister() + VREG_DATA_OFFSET;
687 : }
688 :
689 : // Note: always call ensureDefined before calling useType/usePayload,
690 : // so that emitted-at-use operands are handled correctly.
691 : LUse
692 : LIRGeneratorShared::useType(MDefinition* mir, LUse::Policy policy)
693 : {
694 : MOZ_ASSERT(mir->type() == MIRType::Value);
695 :
696 : return LUse(mir->virtualRegister() + VREG_TYPE_OFFSET, policy);
697 : }
698 :
699 : LUse
700 : LIRGeneratorShared::usePayload(MDefinition* mir, LUse::Policy policy)
701 : {
702 : MOZ_ASSERT(mir->type() == MIRType::Value);
703 :
704 : return LUse(VirtualRegisterOfPayload(mir), policy);
705 : }
706 :
707 : LUse
708 : LIRGeneratorShared::usePayloadAtStart(MDefinition* mir, LUse::Policy policy)
709 : {
710 : MOZ_ASSERT(mir->type() == MIRType::Value);
711 :
712 : return LUse(VirtualRegisterOfPayload(mir), policy, true);
713 : }
714 :
715 : LUse
716 : LIRGeneratorShared::usePayloadInRegisterAtStart(MDefinition* mir)
717 : {
718 : return usePayloadAtStart(mir, LUse::REGISTER);
719 : }
720 :
721 : void
722 : LIRGeneratorShared::fillBoxUses(LInstruction* lir, size_t n, MDefinition* mir)
723 : {
724 : ensureDefined(mir);
725 : lir->getOperand(n)->toUse()->setVirtualRegister(mir->virtualRegister() + VREG_TYPE_OFFSET);
726 : lir->getOperand(n + 1)->toUse()->setVirtualRegister(VirtualRegisterOfPayload(mir));
727 : }
728 : #endif
729 :
730 : LUse
731 12 : LIRGeneratorShared::useRegisterForTypedLoad(MDefinition* mir, MIRType type)
732 : {
733 12 : MOZ_ASSERT(type != MIRType::Value && type != MIRType::None);
734 12 : MOZ_ASSERT(mir->type() == MIRType::Object || mir->type() == MIRType::Slots);
735 :
736 : #ifdef JS_PUNBOX64
737 : // On x64, masm.loadUnboxedValue emits slightly less efficient code when
738 : // the input and output use the same register and we're not loading an
739 : // int32/bool/double, so we just call useRegister in this case.
740 12 : if (type != MIRType::Int32 && type != MIRType::Boolean && type != MIRType::Double)
741 7 : return useRegister(mir);
742 : #endif
743 :
744 5 : return useRegisterAtStart(mir);
745 : }
746 :
747 : LBoxAllocation
748 105 : LIRGeneratorShared::useBox(MDefinition* mir, LUse::Policy policy, bool useAtStart)
749 : {
750 105 : MOZ_ASSERT(mir->type() == MIRType::Value);
751 :
752 105 : ensureDefined(mir);
753 :
754 : #if defined(JS_NUNBOX32)
755 : return LBoxAllocation(LUse(mir->virtualRegister(), policy, useAtStart),
756 : LUse(VirtualRegisterOfPayload(mir), policy, useAtStart));
757 : #else
758 105 : return LBoxAllocation(LUse(mir->virtualRegister(), policy, useAtStart));
759 : #endif
760 : }
761 :
762 : LBoxAllocation
763 41 : LIRGeneratorShared::useBoxOrTyped(MDefinition* mir)
764 : {
765 41 : if (mir->type() == MIRType::Value)
766 5 : return useBox(mir);
767 :
768 :
769 : #if defined(JS_NUNBOX32)
770 : return LBoxAllocation(useRegister(mir), LAllocation());
771 : #else
772 36 : return LBoxAllocation(useRegister(mir));
773 : #endif
774 : }
775 :
776 : LBoxAllocation
777 35 : LIRGeneratorShared::useBoxOrTypedOrConstant(MDefinition* mir, bool useConstant)
778 : {
779 35 : if (useConstant && mir->isConstant()) {
780 : #if defined(JS_NUNBOX32)
781 : return LBoxAllocation(LAllocation(mir->toConstant()), LAllocation());
782 : #else
783 19 : return LBoxAllocation(LAllocation(mir->toConstant()));
784 : #endif
785 : }
786 :
787 16 : return useBoxOrTyped(mir);
788 : }
789 :
790 : LInt64Allocation
791 0 : LIRGeneratorShared::useInt64(MDefinition* mir, LUse::Policy policy, bool useAtStart)
792 : {
793 0 : MOZ_ASSERT(mir->type() == MIRType::Int64);
794 :
795 0 : ensureDefined(mir);
796 :
797 0 : uint32_t vreg = mir->virtualRegister();
798 : #if JS_BITS_PER_WORD == 32
799 : return LInt64Allocation(LUse(vreg + INT64HIGH_INDEX, policy, useAtStart),
800 : LUse(vreg + INT64LOW_INDEX, policy, useAtStart));
801 : #else
802 0 : return LInt64Allocation(LUse(vreg, policy, useAtStart));
803 : #endif
804 : }
805 :
806 : LInt64Allocation
807 0 : LIRGeneratorShared::useInt64Fixed(MDefinition* mir, Register64 regs, bool useAtStart)
808 : {
809 0 : MOZ_ASSERT(mir->type() == MIRType::Int64);
810 :
811 0 : ensureDefined(mir);
812 :
813 0 : uint32_t vreg = mir->virtualRegister();
814 : #if JS_BITS_PER_WORD == 32
815 : return LInt64Allocation(LUse(regs.high, vreg + INT64HIGH_INDEX, useAtStart),
816 : LUse(regs.low, vreg + INT64LOW_INDEX, useAtStart));
817 : #else
818 0 : return LInt64Allocation(LUse(regs.reg, vreg, useAtStart));
819 : #endif
820 : }
821 :
822 : LInt64Allocation
823 : LIRGeneratorShared::useInt64FixedAtStart(MDefinition* mir, Register64 regs)
824 : {
825 : return useInt64Fixed(mir, regs, true);
826 : }
827 :
828 : LInt64Allocation
829 0 : LIRGeneratorShared::useInt64(MDefinition* mir, bool useAtStart)
830 : {
831 : // On 32-bit platforms, always load the value in registers.
832 : #if JS_BITS_PER_WORD == 32
833 : return useInt64(mir, LUse::REGISTER, useAtStart);
834 : #else
835 0 : return useInt64(mir, LUse::ANY, useAtStart);
836 : #endif
837 : }
838 :
839 : LInt64Allocation
840 0 : LIRGeneratorShared::useInt64AtStart(MDefinition* mir)
841 : {
842 0 : return useInt64(mir, /* useAtStart = */ true);
843 : }
844 :
845 : LInt64Allocation
846 0 : LIRGeneratorShared::useInt64Register(MDefinition* mir, bool useAtStart)
847 : {
848 0 : return useInt64(mir, LUse::REGISTER, useAtStart);
849 : }
850 :
851 : LInt64Allocation
852 0 : LIRGeneratorShared::useInt64OrConstant(MDefinition* mir, bool useAtStart)
853 : {
854 0 : if (mir->isConstant()) {
855 : #if defined(JS_NUNBOX32)
856 : return LInt64Allocation(LAllocation(mir->toConstant()), LAllocation());
857 : #else
858 0 : return LInt64Allocation(LAllocation(mir->toConstant()));
859 : #endif
860 : }
861 0 : return useInt64(mir, useAtStart);
862 : }
863 :
864 : LInt64Allocation
865 0 : LIRGeneratorShared::useInt64RegisterOrConstant(MDefinition* mir, bool useAtStart)
866 : {
867 0 : if (mir->isConstant()) {
868 : #if defined(JS_NUNBOX32)
869 : return LInt64Allocation(LAllocation(mir->toConstant()), LAllocation());
870 : #else
871 0 : return LInt64Allocation(LAllocation(mir->toConstant()));
872 : #endif
873 : }
874 0 : return useInt64Register(mir, useAtStart);
875 : }
876 :
877 : } // namespace jit
878 : } // namespace js
879 :
880 : #endif /* jit_shared_Lowering_shared_inl_h */
|