1 // [AsmJit]
2 // Complete JIT Assembler for C++ Language.
3 //
4 // [License]
5 // Zlib - See COPYING file in this package.
6
7 #define ASMJIT_EXPORTS
8
9 // [Dependencies - AsmJit]
10 #include "../core/intutil.h"
11 #include "../core/stringutil.h"
12
13 #include "../x86/x86assembler.h"
14 #include "../x86/x86compiler.h"
15 #include "../x86/x86compilercontext.h"
16 #include "../x86/x86compilerfunc.h"
17 #include "../x86/x86compileritem.h"
18 #include "../x86/x86util.h"
19
20 // [Api-Begin]
21 #include "../core/apibegin.h"
22
23 namespace AsmJit {
24
25 // ============================================================================
26 // [AsmJit::CompilerContext - Construction / Destruction]
27 // ============================================================================
28
X86CompilerContext(X86Compiler * x86Compiler)29 X86CompilerContext::X86CompilerContext(X86Compiler* x86Compiler) :
30 CompilerContext(x86Compiler)
31 {
32 _state = &_x86State;
33
34 _clear();
35 _emitComments = x86Compiler->getLogger() != NULL;
36 }
37
~X86CompilerContext()38 X86CompilerContext::~X86CompilerContext()
39 {
40 }
41
42 // ============================================================================
43 // [AsmJit::CompilerContext - Clear]
44 // ============================================================================
45
_clear()46 void X86CompilerContext::_clear()
47 {
48 _zoneMemory.clear();
49 _func = NULL;
50
51 _start = NULL;
52 _stop = NULL;
53
54 _x86State.clear();
55 _active = NULL;
56
57 _forwardJumps = NULL;
58
59 _currentOffset = 0;
60 _isUnreachable = 0;
61
62 _modifiedGpRegisters = 0;
63 _modifiedMmRegisters = 0;
64 _modifiedXmmRegisters = 0;
65
66 _allocableEBP = false;
67
68 _adjustESP = 0;
69
70 _argumentsBaseReg = kRegIndexInvalid; // Used by patcher.
71 _argumentsBaseOffset = 0; // Used by patcher.
72 _argumentsActualDisp = 0; // Used by translate().
73
74 _variablesBaseReg = kRegIndexInvalid; // Used by patcher.
75 _variablesBaseOffset = 0; // Used by patcher.
76 _variablesActualDisp = 0; // Used by translate()
77
78 _memUsed = NULL;
79 _memFree = NULL;
80
81 _mem4BlocksCount = 0;
82 _mem8BlocksCount = 0;
83 _mem16BlocksCount = 0;
84
85 _memBytesTotal = 0;
86
87 _backCode.clear();
88 _backPos = 0;
89 }
90
91 // ============================================================================
92 // [AsmJit::CompilerContext - Construction / Destruction]
93 // ============================================================================
94
allocVar(X86CompilerVar * var,uint32_t regMask,uint32_t vflags)95 void X86CompilerContext::allocVar(X86CompilerVar* var, uint32_t regMask, uint32_t vflags)
96 {
97 switch (var->getType())
98 {
99 case kX86VarTypeGpd:
100 #if defined(ASMJIT_X64)
101 case kX86VarTypeGpq:
102 #endif // ASMJIT_X64
103 allocGpVar(var, regMask, vflags);
104 break;
105
106 case kX86VarTypeX87:
107 case kX86VarTypeX87SS:
108 case kX86VarTypeX87SD:
109 // TODO: X87 Support.
110 break;
111
112 case kX86VarTypeMm:
113 allocMmVar(var, regMask, vflags);
114 break;
115
116 case kX86VarTypeXmm:
117 case kX86VarTypeXmmSS:
118 case kX86VarTypeXmmPS:
119 case kX86VarTypeXmmSD:
120 case kX86VarTypeXmmPD:
121 allocXmmVar(var, regMask, vflags);
122 break;
123 }
124
125 _postAlloc(var, vflags);
126 }
127
saveVar(X86CompilerVar * var)128 void X86CompilerContext::saveVar(X86CompilerVar* var)
129 {
130 switch (var->getType())
131 {
132 case kX86VarTypeGpd:
133 #if defined(ASMJIT_X64)
134 case kX86VarTypeGpq:
135 #endif // ASMJIT_X64
136 saveGpVar(var);
137 break;
138
139 case kX86VarTypeX87:
140 case kX86VarTypeX87SS:
141 case kX86VarTypeX87SD:
142 // TODO: X87 Support.
143 break;
144
145 case kX86VarTypeMm:
146 saveMmVar(var);
147 break;
148
149 case kX86VarTypeXmm:
150 case kX86VarTypeXmmSS:
151 case kX86VarTypeXmmPS:
152 case kX86VarTypeXmmSD:
153 case kX86VarTypeXmmPD:
154 saveXmmVar(var);
155 break;
156 }
157 }
158
spillVar(X86CompilerVar * var)159 void X86CompilerContext::spillVar(X86CompilerVar* var)
160 {
161 switch (var->getType())
162 {
163 case kX86VarTypeGpd:
164 #if defined(ASMJIT_X64)
165 case kX86VarTypeGpq:
166 #endif // ASMJIT_X64
167 spillGpVar(var);
168 break;
169
170 case kX86VarTypeX87:
171 case kX86VarTypeX87SS:
172 case kX86VarTypeX87SD:
173 // TODO: X87 Support.
174 break;
175
176 case kX86VarTypeMm:
177 spillMmVar(var);
178 break;
179
180 case kX86VarTypeXmm:
181 case kX86VarTypeXmmSS:
182 case kX86VarTypeXmmPS:
183 case kX86VarTypeXmmSD:
184 case kX86VarTypeXmmPD:
185 spillXmmVar(var);
186 break;
187 }
188 }
189
unuseVar(X86CompilerVar * var,uint32_t toState)190 void X86CompilerContext::unuseVar(X86CompilerVar* var, uint32_t toState)
191 {
192 ASMJIT_ASSERT(toState != kVarStateReg);
193
194 if (var->state == kVarStateReg)
195 {
196 uint32_t regIndex = var->regIndex;
197 switch (var->getType())
198 {
199 case kX86VarTypeGpd:
200 #if defined(ASMJIT_X64)
201 case kX86VarTypeGpq:
202 #endif // ASMJIT_X64
203 _x86State.gp[regIndex] = NULL;
204 _freedGpRegister(regIndex);
205 break;
206
207 case kX86VarTypeX87:
208 case kX86VarTypeX87SS:
209 case kX86VarTypeX87SD:
210 // TODO: X87 Support.
211 break;
212
213 case kX86VarTypeMm:
214 _x86State.mm[regIndex] = NULL;
215 _freedMmRegister(regIndex);
216 break;
217
218 case kX86VarTypeXmm:
219 case kX86VarTypeXmmSS:
220 case kX86VarTypeXmmPS:
221 case kX86VarTypeXmmSD:
222 case kX86VarTypeXmmPD:
223 _x86State.xmm[regIndex] = NULL;
224 _freedXmmRegister(regIndex);
225 break;
226 }
227 }
228
229 var->state = toState;
230 var->changed = false;
231 var->regIndex = kRegIndexInvalid;
232 }
233
allocGpVar(X86CompilerVar * var,uint32_t regMask,uint32_t vflags)234 void X86CompilerContext::allocGpVar(X86CompilerVar* var, uint32_t regMask, uint32_t vflags)
235 {
236 uint32_t fullMask = IntUtil::maskUpToIndex(kX86RegNumGp) & ~IntUtil::maskFromIndex(kX86RegIndexEsp);
237 if (!_allocableEBP)
238 fullMask &= ~IntUtil::maskFromIndex(kX86RegIndexEbp);
239
240 // Fix the regMask (0 or full bit-array means that any register may be used).
241 if (regMask == 0)
242 regMask = 0xFFFFFFFF;
243 regMask &= fullMask;
244
245 // Working variables.
246 uint32_t i;
247 uint32_t mask;
248
249 // Last register code (aka home).
250 uint32_t home = var->homeRegisterIndex;
251 // New register code.
252 uint32_t idx = kRegIndexInvalid;
253
254 // Preserved GP variables.
255 uint32_t preservedGP = var->funcScope->getDecl()->getGpPreservedMask();
256
257 // Spill candidate.
258 X86CompilerVar* spillCandidate = NULL;
259
260 // Whether to alloc the non-preserved variables first.
261 bool nonPreservedFirst = true;
262
263 if (getFunc()->isCaller())
264 nonPreservedFirst = (var->funcCall == NULL) || (var->funcCall->getOffset() >= var->lastItem->getOffset());
265
266 // --------------------------------------------------------------------------
267 // [Already Allocated]
268 // --------------------------------------------------------------------------
269
270 // Go away if variable is already allocated.
271 if (var->state == kVarStateReg)
272 {
273 uint32_t oldIndex = var->regIndex;
274
275 // Already allocated in the right register.
276 if (IntUtil::maskFromIndex(oldIndex) & regMask)
277 return;
278
279 // Try to find unallocated register first.
280 mask = regMask & ~_x86State.usedGP;
281 if (mask != 0)
282 {
283 idx = IntUtil::findFirstBit((nonPreservedFirst && (mask & ~preservedGP) != 0) ? mask & ~preservedGP : mask);
284 }
285 // Then find the allocated and exchange later.
286 else
287 {
288 idx = IntUtil::findFirstBit(regMask & _x86State.usedGP);
289 }
290 ASMJIT_ASSERT(idx != kRegIndexInvalid);
291
292 X86CompilerVar* other = _x86State.gp[idx];
293 emitExchangeVar(var, idx, vflags, other);
294
295 _x86State.gp[oldIndex] = other;
296 _x86State.gp[idx ] = var;
297
298 if (other)
299 other->regIndex = oldIndex;
300 else
301 _freedGpRegister(oldIndex);
302
303 // Update X86CompilerVar.
304 var->state = kVarStateReg;
305 var->regIndex = idx;
306 var->homeRegisterIndex = idx;
307
308 _allocatedGpRegister(idx);
309 return;
310 }
311
312 // --------------------------------------------------------------------------
313 // [Find Unused GP]
314 // --------------------------------------------------------------------------
315
316 // Home register code.
317 if ((idx == kRegIndexInvalid) &&
318 (home != kRegIndexInvalid) &&
319 (regMask & IntUtil::maskFromIndex(home)) != 0 &&
320 (_x86State.usedGP & IntUtil::maskFromIndex(home)) == 0)
321 {
322 idx = home;
323 goto _Alloc;
324 }
325
326 // We start from 1, because EAX/RAX register is sometimes explicitly
327 // needed. So we trying to prevent reallocation in near future.
328 if (idx == kRegIndexInvalid)
329 {
330 for (i = 1, mask = (1 << i); i < kX86RegNumGp; i++, mask <<= 1)
331 {
332 if ((regMask & mask) != 0 && (_x86State.usedGP & mask) == 0)
333 {
334 // Convenience to alloc non-preserved first or non-preserved last.
335 if (nonPreservedFirst)
336 {
337 if (idx != kRegIndexInvalid && (preservedGP & mask) != 0)
338 continue;
339
340 idx = i;
341 // If current register is preserved, we should try to find different
342 // one that is not. This can save one push / pop in prolog / epilog.
343 if ((preservedGP & mask) == 0)
344 break;
345 }
346 else
347 {
348 if (idx != kRegIndexInvalid && (preservedGP & mask) == 0)
349 continue;
350
351 idx = i;
352 // The opposite.
353 if ((preservedGP & mask) != 0)
354 break;
355 }
356 }
357 }
358 }
359
360 // If not found, try EAX/RAX.
361 if ((idx == kRegIndexInvalid) &&
362 (regMask & IntUtil::maskFromIndex(kX86RegIndexEax)) != 0 &&
363 (_x86State.usedGP & IntUtil::maskFromIndex(kX86RegIndexEax)) == 0)
364 {
365 idx = kX86RegIndexEax;
366 goto _Alloc;
367 }
368
369 // If regMask contains restricted registers which may be used then everything
370 // is handled inside this block.
371 if ((idx == kRegIndexInvalid) && (regMask != fullMask))
372 {
373 // Try to find unallocated register first.
374 mask = regMask & ~_x86State.usedGP;
375 if (mask != 0)
376 {
377 idx = IntUtil::findFirstBit((nonPreservedFirst && (mask & ~preservedGP) != 0) ? (mask & ~preservedGP) : mask);
378 ASMJIT_ASSERT(idx != kRegIndexInvalid);
379 }
380 // Then find the allocated and spill later.
381 else
382 {
383 idx = IntUtil::findFirstBit(regMask & _x86State.usedGP);
384 ASMJIT_ASSERT(idx != kRegIndexInvalid);
385
386 // Spill register we need.
387 spillCandidate = _x86State.gp[idx];
388
389 // Jump to spill part of allocation.
390 goto L_Spill;
391 }
392 }
393
394 // --------------------------------------------------------------------------
395 // [Spill]
396 // --------------------------------------------------------------------------
397
398 // If register is still not found, spill other variable.
399 if (idx == kRegIndexInvalid)
400 {
401 if (spillCandidate == NULL)
402 {
403 spillCandidate = _getSpillCandidateGP();
404 }
405
406 // Spill candidate not found?
407 if (spillCandidate == NULL)
408 {
409 _compiler->setError(kErrorNoRegisters);
410 return;
411 }
412
413 L_Spill:
414 // Prevented variables can't be spilled. _getSpillCandidate() never returns
415 // prevented variables, but when jumping to L_Spill it could happen.
416 if (spillCandidate->workOffset == _currentOffset)
417 {
418 _compiler->setError(kErrorOverlappedRegisters);
419 return;
420 }
421
422 idx = spillCandidate->regIndex;
423 spillGpVar(spillCandidate);
424 }
425
426 // --------------------------------------------------------------------------
427 // [Alloc]
428 // --------------------------------------------------------------------------
429
430 _Alloc:
431 if (var->state == kVarStateMem && (vflags & kVarAllocRead) != 0)
432 {
433 emitLoadVar(var, idx);
434 }
435
436 // Update X86CompilerVar.
437 var->state = kVarStateReg;
438 var->regIndex = idx;
439 var->homeRegisterIndex = idx;
440
441 // Update CompilerState.
442 _allocatedVariable(var);
443 }
444
saveGpVar(X86CompilerVar * var)445 void X86CompilerContext::saveGpVar(X86CompilerVar* var)
446 {
447 // Can't save variable that isn't allocated.
448 ASMJIT_ASSERT(var->state == kVarStateReg);
449 ASMJIT_ASSERT(var->regIndex != kRegIndexInvalid);
450
451 uint32_t idx = var->regIndex;
452 emitSaveVar(var, idx);
453
454 // Update X86CompilerVar.
455 var->changed = false;
456 }
457
spillGpVar(X86CompilerVar * var)458 void X86CompilerContext::spillGpVar(X86CompilerVar* var)
459 {
460 // Can't spill variable that isn't allocated.
461 ASMJIT_ASSERT(var->state == kVarStateReg);
462 ASMJIT_ASSERT(var->regIndex != kRegIndexInvalid);
463
464 uint32_t idx = var->regIndex;
465
466 if (var->changed) emitSaveVar(var, idx);
467
468 // Update X86CompilerVar.
469 var->regIndex = kRegIndexInvalid;
470 var->state = kVarStateMem;
471 var->changed = false;
472
473 // Update CompilerState.
474 _x86State.gp[idx] = NULL;
475 _freedGpRegister(idx);
476 }
477
allocMmVar(X86CompilerVar * var,uint32_t regMask,uint32_t vflags)478 void X86CompilerContext::allocMmVar(X86CompilerVar* var, uint32_t regMask, uint32_t vflags)
479 {
480 // Fix the regMask (0 or full bit-array means that any register may be used).
481 if (regMask == 0) regMask = IntUtil::maskUpToIndex(kX86RegNumMm);
482 regMask &= IntUtil::maskUpToIndex(kX86RegNumMm);
483
484 // Working variables.
485 uint32_t i;
486 uint32_t mask;
487
488 // Last register code (aka home).
489 uint32_t home = var->homeRegisterIndex;
490 // New register code.
491 uint32_t idx = kRegIndexInvalid;
492
493 // Preserved MM variables.
494 //
495 // NOTE: Currently MM variables are not preserved and there is no calling
496 // convention known to me that does that. But on the other side it's possible
497 // to write such calling convention.
498 uint32_t preservedMM = var->funcScope->getDecl()->getMmPreservedMask();
499
500 // Spill candidate.
501 X86CompilerVar* spillCandidate = NULL;
502
503 // Whether to alloc non-preserved first or last.
504 bool nonPreservedFirst = true;
505 if (this->getFunc()->isCaller())
506 {
507 nonPreservedFirst = var->funcCall == NULL || var->funcCall->getOffset() >= var->lastItem->getOffset();
508 }
509
510 // --------------------------------------------------------------------------
511 // [Already Allocated]
512 // --------------------------------------------------------------------------
513
514 // Go away if variable is already allocated.
515 if (var->state == kVarStateReg)
516 {
517 uint32_t oldIndex = var->regIndex;
518
519 // Already allocated in the right register.
520 if (IntUtil::maskFromIndex(oldIndex) & regMask) return;
521
522 // Try to find unallocated register first.
523 mask = regMask & ~_x86State.usedMM;
524 if (mask != 0)
525 {
526 idx = IntUtil::findFirstBit(
527 (nonPreservedFirst && (mask & ~preservedMM) != 0) ? mask & ~preservedMM : mask);
528 }
529 // Then find the allocated and exchange later.
530 else
531 {
532 idx = IntUtil::findFirstBit(regMask & _x86State.usedMM);
533 }
534 ASMJIT_ASSERT(idx != kRegIndexInvalid);
535
536 X86CompilerVar* other = _x86State.mm[idx];
537 if (other) spillMmVar(other);
538
539 emitMoveVar(var, idx, vflags);
540 _freedMmRegister(oldIndex);
541 _x86State.mm[idx] = var;
542
543 // Update X86CompilerVar.
544 var->state = kVarStateReg;
545 var->regIndex = idx;
546 var->homeRegisterIndex = idx;
547
548 _allocatedMmRegister(idx);
549 return;
550 }
551
552 // --------------------------------------------------------------------------
553 // [Find Unused MM]
554 // --------------------------------------------------------------------------
555
556 // If regMask contains restricted registers which may be used then everything
557 // is handled in this block.
558 if (regMask != IntUtil::maskUpToIndex(kX86RegNumMm))
559 {
560 // Try to find unallocated register first.
561 mask = regMask & ~_x86State.usedMM;
562 if (mask != 0)
563 {
564 idx = IntUtil::findFirstBit(
565 (nonPreservedFirst && (mask & ~preservedMM) != 0) ? mask & ~preservedMM : mask);
566 ASMJIT_ASSERT(idx != kRegIndexInvalid);
567 }
568 // Then find the allocated and spill later.
569 else
570 {
571 idx = IntUtil::findFirstBit(regMask & _x86State.usedMM);
572 ASMJIT_ASSERT(idx != kRegIndexInvalid);
573
574 // Spill register we need.
575 spillCandidate = _x86State.mm[idx];
576
577 // Jump to spill part of allocation.
578 goto L_Spill;
579 }
580 }
581
582 // Home register code.
583 if (idx == kRegIndexInvalid && home != kRegIndexInvalid)
584 {
585 if ((_x86State.usedMM & (1U << home)) == 0) idx = home;
586 }
587
588 if (idx == kRegIndexInvalid)
589 {
590 for (i = 0, mask = (1 << i); i < kX86RegNumMm; i++, mask <<= 1)
591 {
592 if ((_x86State.usedMM & mask) == 0)
593 {
594 // Convenience to alloc non-preserved first or non-preserved last.
595 if (nonPreservedFirst)
596 {
597 if (idx != kRegIndexInvalid && (preservedMM & mask) != 0) continue;
598 idx = i;
599 // If current register is preserved, we should try to find different
600 // one that is not. This can save one push / pop in prolog / epilog.
601 if ((preservedMM & mask) == 0) break;
602 }
603 else
604 {
605 if (idx != kRegIndexInvalid && (preservedMM & mask) == 0) continue;
606 idx = i;
607 // The opposite.
608 if ((preservedMM & mask) != 0) break;
609 }
610 }
611 }
612 }
613
614 // --------------------------------------------------------------------------
615 // [Spill]
616 // --------------------------------------------------------------------------
617
618 // If register is still not found, spill other variable.
619 if (idx == kRegIndexInvalid)
620 {
621 if (spillCandidate == NULL) spillCandidate = _getSpillCandidateMM();
622
623 // Spill candidate not found?
624 if (spillCandidate == NULL)
625 {
626 _compiler->setError(kErrorNoRegisters);
627 return;
628 }
629
630 L_Spill:
631
632 // Prevented variables can't be spilled. _getSpillCandidate() never returns
633 // prevented variables, but when jumping to L_spill it can happen.
634 if (spillCandidate->workOffset == _currentOffset)
635 {
636 _compiler->setError(kErrorOverlappedRegisters);
637 return;
638 }
639
640 idx = spillCandidate->regIndex;
641 spillMmVar(spillCandidate);
642 }
643
644 // --------------------------------------------------------------------------
645 // [Alloc]
646 // --------------------------------------------------------------------------
647
648 if (var->state == kVarStateMem && (vflags & kVarAllocRead) != 0)
649 {
650 emitLoadVar(var, idx);
651 }
652
653 // Update X86CompilerVar.
654 var->state = kVarStateReg;
655 var->regIndex = idx;
656 var->homeRegisterIndex = idx;
657
658 // Update CompilerState.
659 _allocatedVariable(var);
660 }
661
saveMmVar(X86CompilerVar * var)662 void X86CompilerContext::saveMmVar(X86CompilerVar* var)
663 {
664 // Can't save variable that isn't allocated.
665 ASMJIT_ASSERT(var->state == kVarStateReg);
666 ASMJIT_ASSERT(var->regIndex != kRegIndexInvalid);
667
668 uint32_t idx = var->regIndex;
669 emitSaveVar(var, idx);
670
671 // Update X86CompilerVar.
672 var->changed = false;
673 }
674
spillMmVar(X86CompilerVar * var)675 void X86CompilerContext::spillMmVar(X86CompilerVar* var)
676 {
677 // Can't spill variable that isn't allocated.
678 ASMJIT_ASSERT(var->state == kVarStateReg);
679 ASMJIT_ASSERT(var->regIndex != kRegIndexInvalid);
680
681 uint32_t idx = var->regIndex;
682
683 if (var->changed) emitSaveVar(var, idx);
684
685 // Update X86CompilerVar.
686 var->regIndex = kRegIndexInvalid;
687 var->state = kVarStateMem;
688 var->changed = false;
689
690 // Update CompilerState.
691 _x86State.mm[idx] = NULL;
692 _freedMmRegister(idx);
693 }
694
allocXmmVar(X86CompilerVar * var,uint32_t regMask,uint32_t vflags)695 void X86CompilerContext::allocXmmVar(X86CompilerVar* var, uint32_t regMask, uint32_t vflags)
696 {
697 // Fix the regMask (0 or full bit-array means that any register may be used).
698 if (regMask == 0) regMask = IntUtil::maskUpToIndex(kX86RegNumXmm);
699 regMask &= IntUtil::maskUpToIndex(kX86RegNumXmm);
700
701 // Working variables.
702 uint32_t i;
703 uint32_t mask;
704
705 // Last register code (aka home).
706 uint32_t home = var->homeRegisterIndex;
707 // New register code.
708 uint32_t idx = kRegIndexInvalid;
709
710 // Preserved XMM variables.
711 uint32_t preservedXMM = var->funcScope->getDecl()->getXmmPreservedMask();
712
713 // Spill candidate.
714 X86CompilerVar* spillCandidate = NULL;
715
716 // Whether to alloc non-preserved first or last.
717 bool nonPreservedFirst = true;
718
719 if (this->getFunc()->isCaller())
720 nonPreservedFirst = (var->funcCall == NULL) || (var->funcCall->getOffset() >= var->lastItem->getOffset());
721
722 // --------------------------------------------------------------------------
723 // [Already Allocated]
724 // --------------------------------------------------------------------------
725
726 // Go away if variable is already allocated.
727 if (var->state == kVarStateReg)
728 {
729 uint32_t oldIndex = var->regIndex;
730
731 // Already allocated in the right register.
732 if (IntUtil::maskFromIndex(oldIndex) & regMask) return;
733
734 // Try to find unallocated register first.
735 mask = regMask & ~_x86State.usedXMM;
736 if (mask != 0)
737 {
738 idx = IntUtil::findFirstBit(
739 (nonPreservedFirst && (mask & ~preservedXMM) != 0) ? mask & ~preservedXMM : mask);
740 }
741 // Then find the allocated and exchange later.
742 else
743 {
744 idx = IntUtil::findFirstBit(regMask & _x86State.usedXMM);
745 }
746 ASMJIT_ASSERT(idx != kRegIndexInvalid);
747
748 X86CompilerVar* other = _x86State.xmm[idx];
749 if (other) spillXmmVar(other);
750
751 emitMoveVar(var, idx, vflags);
752 _freedXmmRegister(oldIndex);
753 _x86State.xmm[idx] = var;
754
755 // Update X86CompilerVar.
756 var->state = kVarStateReg;
757 var->regIndex = idx;
758 var->homeRegisterIndex = idx;
759
760 _allocatedXmmRegister(idx);
761 return;
762 }
763
764 // --------------------------------------------------------------------------
765 // [Find Unused XMM]
766 // --------------------------------------------------------------------------
767
768 // If regMask contains restricted registers which may be used then everything
769 // is handled in this block.
770 if (regMask != IntUtil::maskUpToIndex(kX86RegNumXmm))
771 {
772 // Try to find unallocated register first.
773 mask = regMask & ~_x86State.usedXMM;
774 if (mask != 0)
775 {
776 idx = IntUtil::findFirstBit(
777 (nonPreservedFirst && (mask & ~preservedXMM) != 0) ? mask & ~preservedXMM : mask);
778 ASMJIT_ASSERT(idx != kRegIndexInvalid);
779 }
780 // Then find the allocated and spill later.
781 else
782 {
783 idx = IntUtil::findFirstBit(regMask & _x86State.usedXMM);
784 ASMJIT_ASSERT(idx != kRegIndexInvalid);
785
786 // Spill register we need.
787 spillCandidate = _x86State.xmm[idx];
788
789 // Jump to spill part of allocation.
790 goto L_Spill;
791 }
792 }
793
794 // Home register code.
795 if (idx == kRegIndexInvalid && home != kRegIndexInvalid)
796 {
797 if ((_x86State.usedXMM & (1U << home)) == 0) idx = home;
798 }
799
800 if (idx == kRegIndexInvalid)
801 {
802 for (i = 0, mask = (1 << i); i < kX86RegNumXmm; i++, mask <<= 1)
803 {
804 if ((_x86State.usedXMM & mask) == 0)
805 {
806 // Convenience to alloc non-preserved first or non-preserved last.
807 if (nonPreservedFirst)
808 {
809 if (idx != kRegIndexInvalid && (preservedXMM & mask) != 0) continue;
810 idx = i;
811 // If current register is preserved, we should try to find different
812 // one that is not. This can save one push / pop in prolog / epilog.
813 if ((preservedXMM & mask) == 0) break;
814 }
815 else
816 {
817 if (idx != kRegIndexInvalid && (preservedXMM & mask) == 0) continue;
818 idx = i;
819 // The opposite.
820 if ((preservedXMM & mask) != 0) break;
821 }
822 }
823 }
824 }
825
826 // --------------------------------------------------------------------------
827 // [Spill]
828 // --------------------------------------------------------------------------
829
830 // If register is still not found, spill other variable.
831 if (idx == kRegIndexInvalid)
832 {
833 if (spillCandidate == NULL)
834 spillCandidate = _getSpillCandidateXMM();
835
836 // Spill candidate not found?
837 if (spillCandidate == NULL)
838 {
839 _compiler->setError(kErrorNoRegisters);
840 return;
841 }
842
843 L_Spill:
844
845 // Prevented variables can't be spilled. _getSpillCandidate() never returns
846 // prevented variables, but when jumping to L_spill it can happen.
847 if (spillCandidate->workOffset == _currentOffset)
848 {
849 _compiler->setError(kErrorOverlappedRegisters);
850 return;
851 }
852
853 idx = spillCandidate->regIndex;
854 spillXmmVar(spillCandidate);
855 }
856
857 // --------------------------------------------------------------------------
858 // [Alloc]
859 // --------------------------------------------------------------------------
860
861 if (var->state == kVarStateMem && (vflags & kVarAllocRead) != 0)
862 {
863 emitLoadVar(var, idx);
864 }
865
866 // Update X86CompilerVar.
867 var->state = kVarStateReg;
868 var->regIndex = idx;
869 var->homeRegisterIndex = idx;
870
871 // Update CompilerState.
872 _allocatedVariable(var);
873 }
874
saveXmmVar(X86CompilerVar * var)875 void X86CompilerContext::saveXmmVar(X86CompilerVar* var)
876 {
877 // Can't save variable that isn't allocated.
878 ASMJIT_ASSERT(var->state == kVarStateReg);
879 ASMJIT_ASSERT(var->regIndex != kRegIndexInvalid);
880
881 uint32_t idx = var->regIndex;
882 emitSaveVar(var, idx);
883
884 // Update X86CompilerVar.
885 var->changed = false;
886 }
887
spillXmmVar(X86CompilerVar * var)888 void X86CompilerContext::spillXmmVar(X86CompilerVar* var)
889 {
890 // Can't spill variable that isn't allocated.
891 ASMJIT_ASSERT(var->state == kVarStateReg);
892 ASMJIT_ASSERT(var->regIndex != kRegIndexInvalid);
893
894 uint32_t idx = var->regIndex;
895
896 if (var->changed) emitSaveVar(var, idx);
897
898 // Update CompilerVar.
899 var->regIndex = kRegIndexInvalid;
900 var->state = kVarStateMem;
901 var->changed = false;
902
903 // Update CompilerState.
904 _x86State.xmm[idx] = NULL;
905 _freedXmmRegister(idx);
906 }
907
emitLoadVar(X86CompilerVar * var,uint32_t regIndex)908 void X86CompilerContext::emitLoadVar(X86CompilerVar* var, uint32_t regIndex)
909 {
910 X86Compiler* x86Compiler = getCompiler();
911 Mem m = _getVarMem(var);
912
913 switch (var->getType())
914 {
915 case kX86VarTypeGpd:
916 x86Compiler->emit(kX86InstMov, gpd(regIndex), m);
917 if (_emitComments) goto _AddComment;
918 break;
919 #if defined(ASMJIT_X64)
920 case kX86VarTypeGpq:
921 x86Compiler->emit(kX86InstMov, gpq(regIndex), m);
922 if (_emitComments) goto _AddComment;
923 break;
924 #endif // ASMJIT_X64
925
926 case kX86VarTypeX87:
927 case kX86VarTypeX87SS:
928 case kX86VarTypeX87SD:
929 // TODO: X87 Support.
930 break;
931
932 case kX86VarTypeMm:
933 x86Compiler->emit(kX86InstMovQ, mm(regIndex), m);
934 if (_emitComments) goto _AddComment;
935 break;
936
937 case kX86VarTypeXmm:
938 x86Compiler->emit(kX86InstMovDQA, xmm(regIndex), m);
939 if (_emitComments) goto _AddComment;
940 break;
941 case kX86VarTypeXmmSS:
942 x86Compiler->emit(kX86InstMovSS, xmm(regIndex), m);
943 if (_emitComments) goto _AddComment;
944 break;
945 case kX86VarTypeXmmSD:
946 x86Compiler->emit(kX86InstMovSD, xmm(regIndex), m);
947 if (_emitComments) goto _AddComment;
948 break;
949 case kX86VarTypeXmmPS:
950 x86Compiler->emit(kX86InstMovAPS, xmm(regIndex), m);
951 if (_emitComments) goto _AddComment;
952 break;
953 case kX86VarTypeXmmPD:
954 x86Compiler->emit(kX86InstMovAPD, xmm(regIndex), m);
955 if (_emitComments) goto _AddComment;
956 break;
957 }
958 return;
959
960 _AddComment:
961 x86Compiler->getCurrentItem()->formatComment("Alloc %s", var->getName());
962 }
963
emitSaveVar(X86CompilerVar * var,uint32_t regIndex)964 void X86CompilerContext::emitSaveVar(X86CompilerVar* var, uint32_t regIndex)
965 {
966 // Caller must ensure that variable is allocated.
967 ASMJIT_ASSERT(regIndex != kRegIndexInvalid);
968
969 X86Compiler* x86Compiler = getCompiler();
970 Mem m = _getVarMem(var);
971
972 switch (var->getType())
973 {
974 case kX86VarTypeGpd:
975 x86Compiler->emit(kX86InstMov, m, gpd(regIndex));
976 if (_emitComments) goto _AddComment;
977 break;
978 #if defined(ASMJIT_X64)
979 case kX86VarTypeGpq:
980 x86Compiler->emit(kX86InstMov, m, gpq(regIndex));
981 if (_emitComments) goto _AddComment;
982 break;
983 #endif // ASMJIT_X64
984
985 case kX86VarTypeX87:
986 case kX86VarTypeX87SS:
987 case kX86VarTypeX87SD:
988 // TODO: X87 Support.
989 break;
990
991 case kX86VarTypeMm:
992 x86Compiler->emit(kX86InstMovQ, m, mm(regIndex));
993 if (_emitComments) goto _AddComment;
994 break;
995
996 case kX86VarTypeXmm:
997 x86Compiler->emit(kX86InstMovDQA, m, xmm(regIndex));
998 if (_emitComments) goto _AddComment;
999 break;
1000 case kX86VarTypeXmmSS:
1001 x86Compiler->emit(kX86InstMovSS, m, xmm(regIndex));
1002 if (_emitComments) goto _AddComment;
1003 break;
1004 case kX86VarTypeXmmSD:
1005 x86Compiler->emit(kX86InstMovSD, m, xmm(regIndex));
1006 if (_emitComments) goto _AddComment;
1007 break;
1008 case kX86VarTypeXmmPS:
1009 x86Compiler->emit(kX86InstMovAPS, m, xmm(regIndex));
1010 if (_emitComments) goto _AddComment;
1011 break;
1012 case kX86VarTypeXmmPD:
1013 x86Compiler->emit(kX86InstMovAPD, m, xmm(regIndex));
1014 if (_emitComments) goto _AddComment;
1015 break;
1016 }
1017 return;
1018
1019 _AddComment:
1020 x86Compiler->getCurrentItem()->formatComment("Spill %s", var->getName());
1021 }
1022
emitMoveVar(X86CompilerVar * var,uint32_t regIndex,uint32_t vflags)1023 void X86CompilerContext::emitMoveVar(X86CompilerVar* var, uint32_t regIndex, uint32_t vflags)
1024 {
1025 // Caller must ensure that the given variable is allocated.
1026 ASMJIT_ASSERT(var->regIndex != kRegIndexInvalid);
1027
1028 X86Compiler* x86Compiler = getCompiler();
1029 if ((vflags & kVarAllocRead) == 0) return;
1030
1031 switch (var->getType())
1032 {
1033 case kX86VarTypeGpd:
1034 x86Compiler->emit(kX86InstMov, gpd(regIndex), gpd(var->regIndex));
1035 break;
1036 #if defined(ASMJIT_X64)
1037 case kX86VarTypeGpq:
1038 x86Compiler->emit(kX86InstMov, gpq(regIndex), gpq(var->regIndex));
1039 break;
1040 #endif // ASMJIT_X64
1041
1042 case kX86VarTypeX87:
1043 case kX86VarTypeX87SS:
1044 case kX86VarTypeX87SD:
1045 // TODO: X87 Support.
1046 break;
1047
1048 case kX86VarTypeMm:
1049 x86Compiler->emit(kX86InstMovQ, mm(regIndex), mm(var->regIndex));
1050 break;
1051
1052 case kX86VarTypeXmm:
1053 x86Compiler->emit(kX86InstMovDQA, xmm(regIndex), xmm(var->regIndex));
1054 break;
1055 case kX86VarTypeXmmSS:
1056 x86Compiler->emit(kX86InstMovSS, xmm(regIndex), xmm(var->regIndex));
1057 break;
1058 case kX86VarTypeXmmSD:
1059 x86Compiler->emit(kX86InstMovSD, xmm(regIndex), xmm(var->regIndex));
1060 break;
1061 case kX86VarTypeXmmPS:
1062 x86Compiler->emit(kX86InstMovAPS, xmm(regIndex), xmm(var->regIndex));
1063 break;
1064 case kX86VarTypeXmmPD:
1065 x86Compiler->emit(kX86InstMovAPD, xmm(regIndex), xmm(var->regIndex));
1066 break;
1067 }
1068 }
1069
emitExchangeVar(X86CompilerVar * var,uint32_t regIndex,uint32_t vflags,X86CompilerVar * other)1070 void X86CompilerContext::emitExchangeVar(X86CompilerVar* var, uint32_t regIndex, uint32_t vflags, X86CompilerVar* other)
1071 {
1072 // Caller must ensure that the given variable is allocated.
1073 ASMJIT_ASSERT(var->regIndex != kRegIndexInvalid);
1074
1075 X86Compiler* x86Compiler = getCompiler();
1076
1077 // If other is not valid then we can just emit MOV (or other similar instruction).
1078 if (other == NULL)
1079 {
1080 emitMoveVar(var, regIndex, vflags);
1081 return;
1082 }
1083
1084 // If we need to alloc for write-only operation then we can move other
1085 // variable away instead of exchanging them.
1086 if ((vflags & kVarAllocRead) == 0)
1087 {
1088 emitMoveVar(other, var->regIndex, kVarAllocRead);
1089 return;
1090 }
1091
1092 switch (var->getType())
1093 {
1094 case kX86VarTypeGpd:
1095 x86Compiler->emit(kX86InstXchg, gpd(regIndex), gpd(var->regIndex));
1096 break;
1097 #if defined(ASMJIT_X64)
1098 case kX86VarTypeGpq:
1099 x86Compiler->emit(kX86InstXchg, gpq(regIndex), gpq(var->regIndex));
1100 break;
1101 #endif // ASMJIT_X64
1102
1103 case kX86VarTypeX87:
1104 case kX86VarTypeX87SS:
1105 case kX86VarTypeX87SD:
1106 // TODO: X87 Support.
1107 break;
1108
1109 // NOTE: MM and XMM registers shoudln't be exchanged using this way, it's
1110 // correct, but instead of using one instruction we need three.
1111
1112 case kX86VarTypeMm:
1113 {
1114 MmReg a = mm(regIndex);
1115 MmReg b = mm(var->regIndex);
1116
1117 x86Compiler->emit(kX86InstPXor, a, b);
1118 x86Compiler->emit(kX86InstPXor, b, a);
1119 x86Compiler->emit(kX86InstPXor, a, b);
1120 break;
1121 }
1122
1123 case kX86VarTypeXmmSS:
1124 case kX86VarTypeXmmPS:
1125 {
1126 XmmReg a = xmm(regIndex);
1127 XmmReg b = xmm(var->regIndex);
1128
1129 x86Compiler->emit(kX86InstXorPS, a, b);
1130 x86Compiler->emit(kX86InstXorPS, b, a);
1131 x86Compiler->emit(kX86InstXorPS, a, b);
1132 break;
1133 }
1134
1135 case kX86VarTypeXmmSD:
1136 case kX86VarTypeXmmPD:
1137 {
1138 XmmReg a = xmm(regIndex);
1139 XmmReg b = xmm(var->regIndex);
1140
1141 x86Compiler->emit(kX86InstXorPD, a, b);
1142 x86Compiler->emit(kX86InstXorPD, b, a);
1143 x86Compiler->emit(kX86InstXorPD, a, b);
1144 break;
1145 }
1146
1147 case kX86VarTypeXmm:
1148 {
1149 XmmReg a = xmm(regIndex);
1150 XmmReg b = xmm(var->regIndex);
1151
1152 x86Compiler->emit(kX86InstPXor, a, b);
1153 x86Compiler->emit(kX86InstPXor, b, a);
1154 x86Compiler->emit(kX86InstPXor, a, b);
1155 break;
1156 }
1157 }
1158 }
1159
_postAlloc(X86CompilerVar * var,uint32_t vflags)1160 void X86CompilerContext::_postAlloc(X86CompilerVar* var, uint32_t vflags)
1161 {
1162 if (vflags & kVarAllocWrite)
1163 var->changed = true;
1164 }
1165
_markMemoryUsed(X86CompilerVar * var)1166 void X86CompilerContext::_markMemoryUsed(X86CompilerVar* var)
1167 {
1168 if (var->homeMemoryData != NULL) return;
1169
1170 VarMemBlock* mem = _allocMemBlock(var->getSize());
1171 if (!mem) return;
1172
1173 var->homeMemoryData = mem;
1174 }
1175
_getVarMem(X86CompilerVar * var)1176 Mem X86CompilerContext::_getVarMem(X86CompilerVar* var)
1177 {
1178 Mem m;
1179 m._mem.id = var->getId();
1180
1181 if (!var->isMemArgument())
1182 m._mem.displacement = _adjustESP;
1183
1184 _markMemoryUsed(var);
1185 return m;
1186 }
1187
getSpillScore(X86CompilerVar * var,uint32_t currentOffset)1188 static int32_t getSpillScore(X86CompilerVar* var, uint32_t currentOffset)
1189 {
1190 int32_t score = 0;
1191
1192 ASMJIT_ASSERT(var->lastItem != NULL);
1193 uint32_t lastOffset = var->lastItem->getOffset();
1194
1195 if (lastOffset >= currentOffset)
1196 score += (int32_t)(lastOffset - currentOffset);
1197
1198 // Each write access decreases probability of spill.
1199 score -= static_cast<int32_t>(var->regWriteCount) + static_cast<int32_t>(var->regRwCount);
1200 // Each read-only access increases probability of spill.
1201 score += static_cast<int32_t>(var->regReadCount);
1202
1203 // Each memory access increases probability of spill.
1204 score += static_cast<int32_t>(var->memWriteCount) + static_cast<int32_t>(var->memRwCount);
1205 score += static_cast<int32_t>(var->memReadCount);
1206
1207 return score;
1208 }
1209
_getSpillCandidateGP()1210 X86CompilerVar* X86CompilerContext::_getSpillCandidateGP()
1211 {
1212 return _getSpillCandidateGeneric(_x86State.gp, kX86RegNumGp);
1213 }
1214
_getSpillCandidateMM()1215 X86CompilerVar* X86CompilerContext::_getSpillCandidateMM()
1216 {
1217 return _getSpillCandidateGeneric(_x86State.mm, kX86RegNumMm);
1218 }
1219
_getSpillCandidateXMM()1220 X86CompilerVar* X86CompilerContext::_getSpillCandidateXMM()
1221 {
1222 return _getSpillCandidateGeneric(_x86State.xmm, kX86RegNumXmm);
1223 }
1224
_getSpillCandidateGeneric(X86CompilerVar ** varArray,uint32_t count)1225 X86CompilerVar* X86CompilerContext::_getSpillCandidateGeneric(X86CompilerVar** varArray, uint32_t count)
1226 {
1227 uint32_t i;
1228
1229 X86CompilerVar* candidate = NULL;
1230 uint32_t candidatePriority = 0;
1231 int32_t candidateScore = 0;
1232
1233 uint32_t currentOffset = _compiler->getCurrentItem()->getOffset();
1234
1235 for (i = 0; i < count; i++)
1236 {
1237 // Get variable.
1238 X86CompilerVar* cv = varArray[i];
1239
1240 // Never spill variables needed for next instruction.
1241 if (cv == NULL || cv->workOffset == _currentOffset) continue;
1242
1243 uint32_t variablePriority = cv->getPriority();
1244 int32_t variableScore = getSpillScore(cv, currentOffset);
1245
1246 if ((candidate == NULL) ||
1247 (variablePriority > candidatePriority) ||
1248 (variablePriority == candidatePriority && variableScore > candidateScore))
1249 {
1250 candidate = cv;
1251 candidatePriority = variablePriority;
1252 candidateScore = variableScore;
1253 }
1254 }
1255
1256 return candidate;
1257 }
1258
_addActive(X86CompilerVar * var)1259 void X86CompilerContext::_addActive(X86CompilerVar* var)
1260 {
1261 // Never call with variable that is already in active list.
1262 ASMJIT_ASSERT(var->nextActive == NULL);
1263 ASMJIT_ASSERT(var->prevActive == NULL);
1264
1265 if (_active == NULL)
1266 {
1267 var->nextActive = var;
1268 var->prevActive = var;
1269
1270 _active = var;
1271 }
1272 else
1273 {
1274 X86CompilerVar* vlast = static_cast<X86CompilerVar*>(_active)->prevActive;
1275
1276 vlast->nextActive = var;
1277 static_cast<X86CompilerVar*>(_active)->prevActive = var;
1278
1279 var->nextActive = static_cast<X86CompilerVar*>(_active);
1280 var->prevActive = vlast;
1281 }
1282 }
1283
_freeActive(X86CompilerVar * var)1284 void X86CompilerContext::_freeActive(X86CompilerVar* var)
1285 {
1286 X86CompilerVar* next = var->nextActive;
1287 X86CompilerVar* prev = var->prevActive;
1288
1289 if (prev == next)
1290 {
1291 _active = NULL;
1292 }
1293 else
1294 {
1295 if (_active == var)
1296 _active = next;
1297
1298 prev->nextActive = next;
1299 next->prevActive = prev;
1300 }
1301
1302 var->nextActive = NULL;
1303 var->prevActive = NULL;
1304 }
1305
_freeAllActive()1306 void X86CompilerContext::_freeAllActive()
1307 {
1308 if (_active == NULL)
1309 return;
1310
1311 X86CompilerVar* cur = static_cast<X86CompilerVar*>(_active);
1312 for (;;)
1313 {
1314 X86CompilerVar* next = cur->nextActive;
1315
1316 cur->nextActive = NULL;
1317 cur->prevActive = NULL;
1318
1319 if (next == _active)
1320 break;
1321 }
1322
1323 _active = NULL;
1324 }
1325
_allocatedVariable(X86CompilerVar * var)1326 void X86CompilerContext::_allocatedVariable(X86CompilerVar* var)
1327 {
1328 uint32_t idx = var->regIndex;
1329
1330 switch (var->getType())
1331 {
1332 case kX86VarTypeGpd:
1333 case kX86VarTypeGpq:
1334 _x86State.gp[idx] = var;
1335 _allocatedGpRegister(idx);
1336 break;
1337
1338 case kX86VarTypeMm:
1339 _x86State.mm[idx] = var;
1340 _allocatedMmRegister(idx);
1341 break;
1342
1343 case kX86VarTypeXmm:
1344 case kX86VarTypeXmmSS:
1345 case kX86VarTypeXmmPS:
1346 case kX86VarTypeXmmSD:
1347 case kX86VarTypeXmmPD:
1348 _x86State.xmm[idx] = var;
1349 _allocatedXmmRegister(idx);
1350 break;
1351
1352 default:
1353 ASMJIT_ASSERT(0);
1354 break;
1355 }
1356 }
1357
translateOperands(Operand * operands,uint32_t count)1358 void X86CompilerContext::translateOperands(Operand* operands, uint32_t count)
1359 {
1360 X86Compiler* x86Compiler = getCompiler();
1361 uint32_t i;
1362
1363 // Translate variables to registers.
1364 for (i = 0; i < count; i++)
1365 {
1366 Operand& o = operands[i];
1367
1368 if (o.isVar())
1369 {
1370 X86CompilerVar* cv = x86Compiler->_getVar(o.getId());
1371 ASMJIT_ASSERT(cv != NULL);
1372
1373 o._reg.op = kOperandReg;
1374 o._reg.code |= cv->regIndex;
1375 }
1376 else if (o.isMem())
1377 {
1378 if ((o.getId() & kOperandIdTypeMask) == kOperandIdTypeVar)
1379 {
1380 // Memory access. We just increment here actual displacement.
1381 X86CompilerVar* cv = x86Compiler->_getVar(o.getId());
1382 ASMJIT_ASSERT(cv != NULL);
1383
1384 o._mem.displacement += cv->isMemArgument()
1385 ? _argumentsActualDisp
1386 : _variablesActualDisp;
1387 // NOTE: This is not enough, variable position will be patched later
1388 // by X86CompilerContext::_patchMemoryOperands().
1389 }
1390 else if ((o._mem.base & kOperandIdTypeMask) == kOperandIdTypeVar)
1391 {
1392 X86CompilerVar* cv = x86Compiler->_getVar(o._mem.base);
1393 ASMJIT_ASSERT(cv != NULL);
1394
1395 o._mem.base = cv->regIndex;
1396 }
1397
1398 if ((o._mem.index & kOperandIdTypeMask) == kOperandIdTypeVar)
1399 {
1400 X86CompilerVar* cv = x86Compiler->_getVar(o._mem.index);
1401 ASMJIT_ASSERT(cv != NULL);
1402
1403 o._mem.index = cv->regIndex;
1404 }
1405 }
1406 }
1407 }
1408
addBackwardCode(X86CompilerJmpInst * from)1409 void X86CompilerContext::addBackwardCode(X86CompilerJmpInst* from)
1410 {
1411 _backCode.append(from);
1412 }
1413
addForwardJump(X86CompilerJmpInst * inst)1414 void X86CompilerContext::addForwardJump(X86CompilerJmpInst* inst)
1415 {
1416 ForwardJumpData* j =
1417 reinterpret_cast<ForwardJumpData*>(_zoneMemory.alloc(sizeof(ForwardJumpData)));
1418 if (j == NULL) { _compiler->setError(kErrorNoHeapMemory); return; }
1419
1420 j->inst = inst;
1421 j->state = _saveState();
1422 j->next = _forwardJumps;
1423 _forwardJumps = j;
1424 }
1425
_saveState()1426 X86CompilerState* X86CompilerContext::_saveState()
1427 {
1428 X86Compiler* x86Compiler = getCompiler();
1429
1430 // Get count of variables stored in memory.
1431 uint32_t memVarsCount = 0;
1432 X86CompilerVar* cur = static_cast<X86CompilerVar*>(_active);
1433
1434 if (cur)
1435 {
1436 do {
1437 if (cur->state == kVarStateMem) memVarsCount++;
1438 cur = cur->nextActive;
1439 } while (cur != _active);
1440 }
1441
1442 // Alloc X86CompilerState structure (using zone allocator) and copy current
1443 // state into it.
1444 X86CompilerState* state = x86Compiler->_newState(memVarsCount);
1445 memcpy(state, &_x86State, sizeof(X86CompilerState));
1446
1447 // Clear changed flags.
1448 state->changedGP = 0;
1449 state->changedMM = 0;
1450 state->changedXMM = 0;
1451
1452 uint i;
1453 uint mask;
1454
1455 // Save variables stored in REGISTERs and CHANGE flag.
1456 for (i = 0, mask = 1; i < kX86RegNumGp; i++, mask <<= 1)
1457 {
1458 if (state->gp[i] && state->gp[i]->changed)
1459 state->changedGP |= mask;
1460 }
1461
1462 for (i = 0, mask = 1; i < kX86RegNumMm; i++, mask <<= 1)
1463 {
1464 if (state->mm[i] && state->mm[i]->changed)
1465 state->changedMM |= mask;
1466 }
1467
1468 for (i = 0, mask = 1; i < kX86RegNumXmm; i++, mask <<= 1)
1469 {
1470 if (state->xmm[i] && state->xmm[i]->changed)
1471 state->changedXMM |= mask;
1472 }
1473
1474 // Save variables stored in MEMORY.
1475 state->memVarsCount = memVarsCount;
1476 memVarsCount = 0;
1477
1478 cur = static_cast<X86CompilerVar*>(_active);
1479 if (cur)
1480 {
1481 do {
1482 if (cur->state == kVarStateMem) state->memVarsData[memVarsCount++] = cur;
1483 cur = cur->nextActive;
1484 } while (cur != _active);
1485 }
1486
1487 // Finished.
1488 return state;
1489 }
1490
_assignState(X86CompilerState * state)1491 void X86CompilerContext::_assignState(X86CompilerState* state)
1492 {
1493 Compiler* compiler = getCompiler();
1494
1495 memcpy(&_x86State, state, sizeof(X86CompilerState));
1496 _x86State.memVarsCount = 0;
1497
1498 uint i, mask;
1499 X86CompilerVar* cv;
1500
1501 // Unuse all variables first.
1502 cv = static_cast<X86CompilerVar*>(_active);
1503 if (cv)
1504 {
1505 do {
1506 cv->state = kVarStateUnused;
1507 cv = cv->nextActive;
1508 } while (cv != _active);
1509 }
1510
1511 // Assign variables stored in memory which are not unused.
1512 for (i = 0; i < state->memVarsCount; i++)
1513 {
1514 state->memVarsData[i]->state = kVarStateMem;
1515 }
1516
1517 // Assign allocated variables.
1518 for (i = 0, mask = 1; i < kX86RegNumGp; i++, mask <<= 1)
1519 {
1520 if ((cv = _x86State.gp[i]) != NULL)
1521 {
1522 cv->state = kVarStateReg;
1523 cv->regIndex = i;
1524 cv->changed = (_x86State.changedGP & mask) != 0;
1525 }
1526 }
1527
1528 for (i = 0, mask = 1; i < kX86RegNumMm; i++, mask <<= 1)
1529 {
1530 if ((cv = _x86State.mm[i]) != NULL)
1531 {
1532 cv->state = kVarStateReg;
1533 cv->regIndex = i;
1534 cv->changed = (_x86State.changedMM & mask) != 0;
1535 }
1536 }
1537
1538 for (i = 0, mask = 1; i < kX86RegNumXmm; i++, mask <<= 1)
1539 {
1540 if ((cv = _x86State.xmm[i]) != NULL)
1541 {
1542 cv->state = kVarStateReg;
1543 cv->regIndex = i;
1544 cv->changed = (_x86State.changedXMM & mask) != 0;
1545 }
1546 }
1547 }
1548
_restoreState(X86CompilerState * state,uint32_t targetOffset)1549 void X86CompilerContext::_restoreState(X86CompilerState* state, uint32_t targetOffset)
1550 {
1551 X86CompilerState* fromState = &_x86State;
1552 X86CompilerState* toState = state;
1553
1554 // No change, rare...
1555 if (fromState == toState)
1556 return;
1557
1558 uint base;
1559 uint i;
1560
1561 // --------------------------------------------------------------------------
1562 // Set target state to all variables. cv->tInt is target state in this func.
1563 // --------------------------------------------------------------------------
1564
1565 {
1566 // UNUSED.
1567 X86CompilerVar* cv = static_cast<X86CompilerVar*>(_active);
1568 if (cv)
1569 {
1570 do {
1571 cv->tInt = kVarStateUnused;
1572 cv = cv->nextActive;
1573 } while (cv != _active);
1574 }
1575
1576 // MEMORY.
1577 for (i = 0; i < toState->memVarsCount; i++)
1578 {
1579 toState->memVarsData[i]->tInt = kVarStateMem;
1580 }
1581
1582 // REGISTER.
1583 for (i = 0; i < X86CompilerState::kStateRegCount; i++)
1584 {
1585 if ((cv = toState->regs[i]) != NULL) cv->tInt = kVarStateReg;
1586 }
1587 }
1588
1589 // --------------------------------------------------------------------------
1590 // [GP-Registers Switch]
1591 // --------------------------------------------------------------------------
1592
1593 // TODO.
1594 #if 0
1595 for (i = 0; i < kX86RegNumGp; i++)
1596 {
1597 X86CompilerVar* fromVar = fromState->gp[i];
1598 X86CompilerVar* toVar = toState->gp[i];
1599
1600 if (fromVar != toVar)
1601 {
1602 if (fromVar != NULL)
1603 {
1604 if (toVar != NULL)
1605 {
1606 if (fromState->gp[to
1607 }
1608 else
1609 {
1610 // It is possible that variable that was saved in state currently not
1611 // exists (tInt is target scope!).
1612 if (fromVar->tInt == kVarStateUnused)
1613 {
1614 unuseVar(fromVar, kVarStateUnused);
1615 }
1616 else
1617 {
1618 spillVar(fromVar);
1619 }
1620 }
1621 }
1622 }
1623 else if (fromVar != NULL)
1624 {
1625 uint32_t mask = IntUtil::maskFromIndex(i);
1626 // Variables are the same, we just need to compare changed flags.
1627 if ((fromState->changedGP & mask) && !(toState->changedGP & mask)) saveVar(fromVar);
1628 }
1629 }
1630 #endif
1631
1632 // Spill.
1633 for (base = 0, i = 0; i < X86CompilerState::kStateRegCount; i++)
1634 {
1635 // Change the base offset (from base offset so the register index can be calculated).
1636 if (i == X86CompilerState::kStateRegMmBase || i == X86CompilerState::kStateRegXmmBase)
1637 base = i;
1638
1639 uint32_t regIndex = i - base;
1640 X86CompilerVar* fromVar = fromState->regs[i];
1641 X86CompilerVar* toVar = toState->regs[i];
1642
1643 if (fromVar != toVar)
1644 {
1645 // Spill the register.
1646 if (fromVar != NULL)
1647 {
1648 // It is possible that variable that was saved in state currently not
1649 // exists (tInt is target scope!).
1650 if (fromVar->tInt == kVarStateUnused)
1651 unuseVar(fromVar, kVarStateUnused);
1652 else
1653 spillVar(fromVar);
1654 }
1655 }
1656 else if (fromVar != NULL)
1657 {
1658 // Variables are the same, we just need to compare changed flags.
1659 uint32_t mask = IntUtil::maskFromIndex(regIndex);
1660
1661 if ((fromState->changedGP & mask) && !(toState->changedGP & mask))
1662 saveVar(fromVar);
1663 }
1664 }
1665
1666 // Alloc.
1667 for (base = 0, i = 0; i < X86CompilerState::kStateRegCount; i++)
1668 {
1669 // Change the base offset (from base offset so the register index can be calculated).
1670 if (i == X86CompilerState::kStateRegMmBase || i == X86CompilerState::kStateRegXmmBase)
1671 base = i;
1672
1673 X86CompilerVar* fromVar = fromState->regs[i];
1674 X86CompilerVar* toVar = toState->regs[i];
1675
1676 if (fromVar != toVar)
1677 {
1678 // Alloc register.
1679 uint32_t regIndex = i - base;
1680
1681 if (toVar != NULL)
1682 allocVar(toVar, IntUtil::maskFromIndex(regIndex), kVarAllocRead);
1683 }
1684
1685 // TODO:
1686 //if (toVar)
1687 //{
1688 // toVar->changed = to->changed;
1689 //}
1690 }
1691
1692 // --------------------------------------------------------------------------
1693 // Update used masks.
1694 // --------------------------------------------------------------------------
1695
1696 _x86State.usedGP = state->usedGP;
1697 _x86State.usedMM = state->usedMM;
1698 _x86State.usedXMM = state->usedXMM;
1699
1700 // --------------------------------------------------------------------------
1701 // Update changed masks and cleanup.
1702 // --------------------------------------------------------------------------
1703
1704 {
1705 X86CompilerVar* cv = static_cast<X86CompilerVar*>(_active);
1706 if (cv)
1707 {
1708 do {
1709 if (cv->tInt != kVarStateReg)
1710 {
1711 cv->state = (int)cv->tInt;
1712 cv->changed = false;
1713 }
1714
1715 cv->tInt = 0;
1716 cv = cv->nextActive;
1717 } while (cv != _active);
1718 }
1719 }
1720 }
1721
_allocMemBlock(uint32_t size)1722 VarMemBlock* X86CompilerContext::_allocMemBlock(uint32_t size)
1723 {
1724 ASMJIT_ASSERT(size != 0);
1725
1726 // First try to find mem blocks.
1727 VarMemBlock* mem = _memFree;
1728 VarMemBlock* prev = NULL;
1729
1730 while (mem)
1731 {
1732 VarMemBlock* next = mem->nextFree;
1733
1734 if (mem->size == size)
1735 {
1736 if (prev)
1737 prev->nextFree = next;
1738 else
1739 _memFree = next;
1740
1741 mem->nextFree = NULL;
1742 return mem;
1743 }
1744
1745 prev = mem;
1746 mem = next;
1747 }
1748
1749 // Never mind, create new.
1750 mem = reinterpret_cast<VarMemBlock*>(_zoneMemory.alloc(sizeof(VarMemBlock)));
1751 if (mem == NULL)
1752 {
1753 _compiler->setError(kErrorNoHeapMemory);
1754 return NULL;
1755 }
1756
1757 mem->offset = 0;
1758 mem->size = size;
1759
1760 mem->nextUsed = _memUsed;
1761 mem->nextFree = NULL;
1762
1763 _memUsed = mem;
1764
1765 switch (size)
1766 {
1767 case 16: _mem16BlocksCount++; break;
1768 case 8: _mem8BlocksCount++; break;
1769 case 4: _mem4BlocksCount++; break;
1770 }
1771
1772 return mem;
1773 }
1774
_freeMemBlock(VarMemBlock * mem)1775 void X86CompilerContext::_freeMemBlock(VarMemBlock* mem)
1776 {
1777 // Add mem to free blocks.
1778 mem->nextFree = _memFree;
1779 _memFree = mem;
1780 }
1781
_allocMemoryOperands()1782 void X86CompilerContext::_allocMemoryOperands()
1783 {
1784 VarMemBlock* mem;
1785
1786 // Variables are allocated in this order:
1787 // 1. 16-byte variables.
1788 // 2. 8-byte variables.
1789 // 3. 4-byte variables.
1790 // 4. All others.
1791
1792 uint32_t start16 = 0;
1793 uint32_t start8 = start16 + _mem16BlocksCount * 16;
1794 uint32_t start4 = start8 + _mem8BlocksCount * 8;
1795 uint32_t startX = IntUtil::align<uint32_t>(start4 + _mem4BlocksCount * 4, 16);
1796
1797 for (mem = _memUsed; mem; mem = mem->nextUsed)
1798 {
1799 uint32_t size = mem->size;
1800 uint32_t offset;
1801
1802 switch (size)
1803 {
1804 case 16:
1805 offset = start16;
1806 start16 += 16;
1807 break;
1808
1809 case 8:
1810 offset = start8;
1811 start8 += 8;
1812 break;
1813
1814 case 4:
1815 offset = start4;
1816 start4 += 4;
1817 break;
1818
1819 default:
1820 // Align to 16 bytes if size is 16 or more.
1821 if (size >= 16)
1822 {
1823 size = IntUtil::align<uint32_t>(size, 16);
1824 startX = IntUtil::align<uint32_t>(startX, 16);
1825 }
1826
1827 offset = startX;
1828 startX += size;
1829 break;
1830 }
1831
1832 mem->offset = (int32_t)offset;
1833 _memBytesTotal += size;
1834 }
1835 }
1836
_patchMemoryOperands(CompilerItem * start,CompilerItem * stop)1837 void X86CompilerContext::_patchMemoryOperands(CompilerItem* start, CompilerItem* stop)
1838 {
1839 CompilerItem* cur;
1840
1841 for (cur = start;; cur = cur->getNext())
1842 {
1843 if (cur->getType() == kCompilerItemInst)
1844 {
1845 Mem* mem = reinterpret_cast<X86CompilerInst*>(cur)->_memOp;
1846
1847 if (mem && (mem->_mem.id & kOperandIdTypeMask) == kOperandIdTypeVar)
1848 {
1849 X86CompilerVar* cv = getCompiler()->_getVar(mem->_mem.id);
1850 ASMJIT_ASSERT(cv != NULL);
1851
1852 if (cv->isMemArgument())
1853 {
1854 mem->_mem.base = _argumentsBaseReg;
1855 mem->_mem.displacement += cv->homeMemoryOffset;
1856 mem->_mem.displacement += _argumentsBaseOffset;
1857 }
1858 else
1859 {
1860 VarMemBlock* mb = reinterpret_cast<VarMemBlock*>(cv->homeMemoryData);
1861 ASMJIT_ASSERT(mb != NULL);
1862
1863 mem->_mem.base = _variablesBaseReg;
1864 mem->_mem.displacement += mb->offset;
1865 mem->_mem.displacement += _variablesBaseOffset;
1866 }
1867 }
1868 }
1869 if (cur == stop) break;
1870 }
1871 }
1872
1873 } // AsmJit namespace
1874
1875 // [Api-End]
1876 #include "../core/apiend.h"
1877