|
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 bool |
|
19 LIRGeneratorShared::emitAtUses(MInstruction *mir) |
|
20 { |
|
21 JS_ASSERT(mir->canEmitAtUses()); |
|
22 mir->setEmittedAtUses(); |
|
23 mir->setVirtualRegister(0); |
|
24 return true; |
|
25 } |
|
26 |
|
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 } |
|
39 |
|
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()); |
|
45 |
|
46 uint32_t vreg = getVirtualRegister(); |
|
47 if (vreg >= MAX_VIRTUAL_REGISTERS) |
|
48 return false; |
|
49 |
|
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 } |
|
58 |
|
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 } |
|
65 |
|
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()); |
|
70 |
|
71 LDefinition def(type, LDefinition::PRESET); |
|
72 def.setOutput(output); |
|
73 |
|
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; |
|
78 |
|
79 if (gen->optimizationInfo().registerAllocator() == RegisterAllocator_LSRA) { |
|
80 if (!add(new(alloc()) LNop)) |
|
81 return false; |
|
82 } |
|
83 |
|
84 return true; |
|
85 } |
|
86 |
|
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()); |
|
92 |
|
93 LDefinition::Type type = LDefinition::TypeFrom(mir->type()); |
|
94 |
|
95 LDefinition def(type, LDefinition::MUST_REUSE_INPUT); |
|
96 def.setReusedInput(operand); |
|
97 |
|
98 return define(lir, mir, def); |
|
99 } |
|
100 |
|
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()); |
|
107 |
|
108 uint32_t vreg = getVirtualRegister(); |
|
109 if (vreg >= MAX_VIRTUAL_REGISTERS) |
|
110 return false; |
|
111 |
|
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); |
|
121 |
|
122 mir->setVirtualRegister(vreg); |
|
123 return add(lir); |
|
124 } |
|
125 |
|
126 bool |
|
127 LIRGeneratorShared::defineReturn(LInstruction *lir, MDefinition *mir) |
|
128 { |
|
129 lir->setMir(mir); |
|
130 |
|
131 JS_ASSERT(lir->isCall()); |
|
132 |
|
133 uint32_t vreg = getVirtualRegister(); |
|
134 if (vreg >= MAX_VIRTUAL_REGISTERS) |
|
135 return false; |
|
136 |
|
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))); |
|
144 |
|
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 } |
|
163 |
|
164 mir->setVirtualRegister(vreg); |
|
165 if (!add(lir)) |
|
166 return false; |
|
167 |
|
168 if (gen->optimizationInfo().registerAllocator() == RegisterAllocator_LSRA) { |
|
169 if (!add(new(alloc()) LNop)) |
|
170 return false; |
|
171 } |
|
172 |
|
173 return true; |
|
174 } |
|
175 |
|
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 } |
|
191 |
|
192 bool |
|
193 LIRGeneratorShared::redefine(MDefinition *def, MDefinition *as) |
|
194 { |
|
195 JS_ASSERT(IsCompatibleLIRCoercion(def->type(), as->type())); |
|
196 |
|
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 } |
|
221 |
|
222 if (!ensureDefined(as)) |
|
223 return false; |
|
224 def->setVirtualRegister(as->virtualRegister()); |
|
225 return true; |
|
226 } |
|
227 |
|
228 bool |
|
229 LIRGeneratorShared::defineAs(LInstruction *outLir, MDefinition *outMir, MDefinition *inMir) |
|
230 { |
|
231 uint32_t vreg = inMir->virtualRegister(); |
|
232 LDefinition::Policy policy = LDefinition::PASSTHROUGH; |
|
233 |
|
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 } |
|
251 |
|
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 } |
|
262 |
|
263 LUse |
|
264 LIRGeneratorShared::useRegister(MDefinition *mir) |
|
265 { |
|
266 return use(mir, LUse(LUse::REGISTER)); |
|
267 } |
|
268 |
|
269 LUse |
|
270 LIRGeneratorShared::useRegisterAtStart(MDefinition *mir) |
|
271 { |
|
272 return use(mir, LUse(LUse::REGISTER, true)); |
|
273 } |
|
274 |
|
275 LUse |
|
276 LIRGeneratorShared::use(MDefinition *mir) |
|
277 { |
|
278 return use(mir, LUse(LUse::ANY)); |
|
279 } |
|
280 |
|
281 LUse |
|
282 LIRGeneratorShared::useAtStart(MDefinition *mir) |
|
283 { |
|
284 return use(mir, LUse(LUse::ANY, true)); |
|
285 } |
|
286 |
|
287 LAllocation |
|
288 LIRGeneratorShared::useOrConstant(MDefinition *mir) |
|
289 { |
|
290 if (mir->isConstant()) |
|
291 return LAllocation(mir->toConstant()->vp()); |
|
292 return use(mir); |
|
293 } |
|
294 |
|
295 LAllocation |
|
296 LIRGeneratorShared::useRegisterOrConstant(MDefinition *mir) |
|
297 { |
|
298 if (mir->isConstant()) |
|
299 return LAllocation(mir->toConstant()->vp()); |
|
300 return useRegister(mir); |
|
301 } |
|
302 |
|
303 LAllocation |
|
304 LIRGeneratorShared::useRegisterOrConstantAtStart(MDefinition *mir) |
|
305 { |
|
306 if (mir->isConstant()) |
|
307 return LAllocation(mir->toConstant()->vp()); |
|
308 return useRegisterAtStart(mir); |
|
309 } |
|
310 |
|
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 } |
|
318 |
|
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 } |
|
326 |
|
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 } |
|
343 |
|
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 } |
|
355 |
|
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 } |
|
371 |
|
372 #endif |
|
373 |
|
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 } |
|
381 |
|
382 LUse |
|
383 LIRGeneratorShared::useFixed(MDefinition *mir, Register reg) |
|
384 { |
|
385 return use(mir, LUse(reg)); |
|
386 } |
|
387 |
|
388 LUse |
|
389 LIRGeneratorShared::useFixedAtStart(MDefinition *mir, Register reg) |
|
390 { |
|
391 return use(mir, LUse(reg, true)); |
|
392 } |
|
393 |
|
394 LUse |
|
395 LIRGeneratorShared::useFixed(MDefinition *mir, FloatRegister reg) |
|
396 { |
|
397 return use(mir, LUse(reg)); |
|
398 } |
|
399 |
|
400 LUse |
|
401 LIRGeneratorShared::useFixed(MDefinition *mir, AnyRegister reg) |
|
402 { |
|
403 return reg.isFloat() ? use(mir, reg.fpu()) : use(mir, reg.gpr()); |
|
404 } |
|
405 |
|
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 } |
|
416 |
|
417 LDefinition |
|
418 LIRGeneratorShared::tempFixed(Register reg) |
|
419 { |
|
420 LDefinition t = temp(LDefinition::GENERAL); |
|
421 t.setOutput(LGeneralReg(reg)); |
|
422 return t; |
|
423 } |
|
424 |
|
425 LDefinition |
|
426 LIRGeneratorShared::tempFloat32() |
|
427 { |
|
428 return temp(LDefinition::FLOAT32); |
|
429 } |
|
430 |
|
431 LDefinition |
|
432 LIRGeneratorShared::tempDouble() |
|
433 { |
|
434 return temp(LDefinition::DOUBLE); |
|
435 } |
|
436 |
|
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 } |
|
445 |
|
446 template <typename T> void |
|
447 LIRGeneratorShared::annotate(T *ins) |
|
448 { |
|
449 ins->setId(lirGraph_.getInstructionId()); |
|
450 } |
|
451 |
|
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 } |
|
464 |
|
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 } |
|
482 |
|
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); |
|
489 |
|
490 return LUse(mir->virtualRegister() + VREG_TYPE_OFFSET, policy); |
|
491 } |
|
492 |
|
493 LUse |
|
494 LIRGeneratorShared::usePayload(MDefinition *mir, LUse::Policy policy) |
|
495 { |
|
496 JS_ASSERT(mir->type() == MIRType_Value); |
|
497 |
|
498 return LUse(VirtualRegisterOfPayload(mir), policy); |
|
499 } |
|
500 |
|
501 LUse |
|
502 LIRGeneratorShared::usePayloadAtStart(MDefinition *mir, LUse::Policy policy) |
|
503 { |
|
504 JS_ASSERT(mir->type() == MIRType_Value); |
|
505 |
|
506 return LUse(VirtualRegisterOfPayload(mir), policy, true); |
|
507 } |
|
508 |
|
509 LUse |
|
510 LIRGeneratorShared::usePayloadInRegisterAtStart(MDefinition *mir) |
|
511 { |
|
512 return usePayloadAtStart(mir, LUse::REGISTER); |
|
513 } |
|
514 |
|
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 |
|
525 |
|
526 } // namespace jit |
|
527 } // namespace js |
|
528 |
|
529 #endif /* jit_shared_Lowering_shared_inl_h */ |