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/x86compiler.h"
14 #include "../x86/x86compilercontext.h"
15 #include "../x86/x86compilerfunc.h"
16 #include "../x86/x86compileritem.h"
17 #include "../x86/x86cpuinfo.h"
18 #include "../x86/x86util.h"
19
20 // [Api-Begin]
21 #include "../core/apibegin.h"
22
23 namespace AsmJit {
24
25 // ============================================================================
26 // [AsmJit::X86Assembler - Logging]
27 // ============================================================================
28
29 // Defined in AsmJit/X86/X86Assembler.cpp.
30 char* X86Assembler_dumpRegister(char* buf, uint32_t type, uint32_t index);
31 char* X86Assembler_dumpOperand(char* buf, const Operand* op, uint32_t memRegType, uint32_t loggerFlags);
32
33 // ============================================================================
34 // [AsmJit::X86CompilerFuncDecl - Construction / Destructioin]
35 // ============================================================================
36
X86CompilerFuncDecl(X86Compiler * x86Compiler)37 X86CompilerFuncDecl::X86CompilerFuncDecl(X86Compiler* x86Compiler) :
38 CompilerFuncDecl(x86Compiler),
39 _gpModifiedAndPreserved(0),
40 _mmModifiedAndPreserved(0),
41 _xmmModifiedAndPreserved(0),
42 _movDqInstCode(kInstNone),
43 _pePushPopStackSize(0),
44 _peMovStackSize(0),
45 _peAdjustStackSize(0),
46 _memStackSize(0),
47 _memStackSize16(0)
48 {
49 _decl = &_x86Decl;
50
51 // Just clear to safe defaults.
52 _funcHints |= IntUtil::maskFromIndex(kX86FuncHintPushPop);
53
54 // Stack is always aligned to 16-bytes when using 64-bit OS.
55 if (CompilerUtil::isStack16ByteAligned())
56 _funcHints |= IntUtil::maskFromIndex(kX86FuncHintAssume16ByteAlignment);
57
58 _entryLabel = x86Compiler->newLabel();
59 _exitLabel = x86Compiler->newLabel();
60
61 _entryTarget = x86Compiler->_getTarget(_entryLabel.getId());
62 _exitTarget = x86Compiler->_getTarget(_exitLabel.getId());
63
64 _end = Compiler_newItem<X86CompilerFuncEnd>(x86Compiler, this);
65 }
66
~X86CompilerFuncDecl()67 X86CompilerFuncDecl::~X86CompilerFuncDecl()
68 {
69 }
70
71 // ============================================================================
72 // [AsmJit::X86CompilerFuncDecl - Interface]
73 // ============================================================================
74
prepare(CompilerContext & cc)75 void X86CompilerFuncDecl::prepare(CompilerContext& cc)
76 {
77 X86CompilerContext& x86Context = static_cast<X86CompilerContext&>(cc);
78 _offset = x86Context._currentOffset++;
79
80 _prepareVariables(this);
81 }
82
translate(CompilerContext & cc)83 CompilerItem* X86CompilerFuncDecl::translate(CompilerContext& cc)
84 {
85 X86CompilerContext& x86Context = static_cast<X86CompilerContext&>(cc);
86
87 _allocVariables(x86Context);
88 return translated();
89 }
90
91 // ============================================================================
92 // [AsmJit::X86CompilerFuncDecl - Misc]
93 // ============================================================================
94
getMaxSize() const95 int X86CompilerFuncDecl::getMaxSize() const
96 {
97 // NOP.
98 return 0;
99 }
100
101 // ============================================================================
102 // [AsmJit::X86CompilerFuncDecl - Prototype]
103 // ============================================================================
104
setPrototype(uint32_t convention,uint32_t returnType,const uint32_t * arguments,uint32_t argumentsCount)105 void X86CompilerFuncDecl::setPrototype(uint32_t convention, uint32_t returnType, const uint32_t* arguments, uint32_t argumentsCount)
106 {
107 _x86Decl.setPrototype(convention, returnType, arguments, argumentsCount);
108 }
109
110 // ============================================================================
111 // [AsmJit::X86CompilerFuncDecl - Helpers]
112 // ============================================================================
113
_createVariables()114 void X86CompilerFuncDecl::_createVariables()
115 {
116 X86Compiler* x86Compiler = getCompiler();
117
118 uint32_t i, count = _x86Decl.getArgumentsCount();
119 if (count == 0) return;
120
121 _vars = reinterpret_cast<CompilerVar**>(x86Compiler->getZoneMemory().alloc(count * sizeof(void*)));
122 if (_vars == NULL)
123 {
124 x86Compiler->setError(kErrorNoHeapMemory);
125 return;
126 }
127
128 char argNameStorage[64];
129 char* argName = NULL;
130
131 bool debug = x86Compiler->getLogger() != NULL;
132 if (debug) argName = argNameStorage;
133
134 for (i = 0; i < count; i++)
135 {
136 FuncArg& arg = _x86Decl.getArgument(i);
137
138 if (debug)
139 snprintf(argName, ASMJIT_ARRAY_SIZE(argNameStorage), "arg_%u", i);
140
141 uint32_t size = X86Util::getVarSizeFromVarType(arg.getVarType());
142 X86CompilerVar* cv = x86Compiler->_newVar(argName, arg.getVarType(), size);
143
144 if (arg.getRegIndex() != kRegIndexInvalid)
145 {
146 cv->_isRegArgument = true;
147 cv->regIndex = arg.getRegIndex();
148 }
149
150 if (arg.getStackOffset() != kFuncStackInvalid)
151 {
152 cv->_isMemArgument = true;
153 cv->homeMemoryOffset = arg.getStackOffset();
154 }
155
156 _vars[i] = cv;
157 }
158 }
159
_prepareVariables(CompilerItem * first)160 void X86CompilerFuncDecl::_prepareVariables(CompilerItem* first)
161 {
162 uint32_t count = _x86Decl.getArgumentsCount();
163 if (count == 0) return;
164
165 for (uint32_t i = 0; i < count; i++)
166 {
167 X86CompilerVar* cv = getVar(i);
168
169 // This is where variable scope starts.
170 cv->firstItem = first;
171 // If this will not be changed then it will be deallocated immediately.
172 cv->lastItem = first;
173 }
174 }
175
_allocVariables(CompilerContext & cc)176 void X86CompilerFuncDecl::_allocVariables(CompilerContext& cc)
177 {
178 X86CompilerContext& x86Context = static_cast<X86CompilerContext&>(cc);
179 uint32_t count = getDecl()->getArgumentsCount();
180
181 if (count == 0)
182 return;
183
184 for (uint32_t i = 0; i < count; i++)
185 {
186 X86CompilerVar* cv = getVar(i);
187
188 if (cv->firstItem != NULL || cv->isArgument())
189 {
190 // Variable is used.
191 if (cv->regIndex != kRegIndexInvalid)
192 {
193 cv->state = kVarStateReg;
194 // If variable is in register -> mark it as changed so it will not be
195 // lost by first spill.
196 cv->changed = true;
197 x86Context._allocatedVariable(cv);
198 }
199 else if (cv->isMemArgument())
200 {
201 cv->state = kVarStateMem;
202 }
203 }
204 else
205 {
206 // Variable is not used.
207 cv->regIndex = kRegIndexInvalid;
208 }
209 }
210 }
211
_preparePrologEpilog(CompilerContext & cc)212 void X86CompilerFuncDecl::_preparePrologEpilog(CompilerContext& cc)
213 {
214 X86CompilerContext& x86Context = static_cast<X86CompilerContext&>(cc);
215 const X86CpuInfo* cpuInfo = X86CpuInfo::getGlobal();
216
217 clearFuncFlag(
218 kX86FuncFlagPushPop |
219 kX86FuncFlagEmitEmms |
220 kX86FuncFlagEmitSFence |
221 kX86FuncFlagEmitLFence |
222 kX86FuncFlagAssume16ByteAlignment |
223 kX86FuncFlagPerform16ByteAlignment);
224
225 uint32_t accessibleMemoryBelowStack = 0;
226 if (getDecl()->getConvention() == kX86FuncConvX64U)
227 accessibleMemoryBelowStack = 128;
228
229 if (getHint(kX86FuncHintAssume16ByteAlignment ))
230 setFuncFlag(kX86FuncFlagAssume16ByteAlignment);
231
232 if (getHint(kX86FuncHintPerform16ByteAlignment))
233 setFuncFlag(kX86FuncFlagPerform16ByteAlignment);
234
235 if (getHint(kFuncHintNaked) != 0)
236 setFuncFlag(kFuncFlagIsNaked);
237
238 if (isCaller() && (x86Context._memBytesTotal > 0 || isAssumed16ByteAlignment()))
239 setFuncFlag(kX86FuncFlagIsEspAdjusted);
240
241 if (x86Context._memBytesTotal > accessibleMemoryBelowStack)
242 setFuncFlag(kX86FuncFlagIsEspAdjusted);
243
244 if (getHint(kX86FuncHintPushPop) != 0)
245 setFuncFlag(kX86FuncFlagPushPop);
246
247 if (getHint(kX86FuncHintEmms) != 0)
248 setFuncFlag(kX86FuncFlagEmitEmms);
249
250 if (getHint(kX86FuncHintSFence) != 0)
251 setFuncFlag(kX86FuncFlagEmitSFence);
252
253 if (getHint(kX86FuncHintLFence) != 0)
254 setFuncFlag(kX86FuncFlagEmitLFence);
255
256 // Updated to respect comment from issue #47, align also when using MMX code.
257 if (!isAssumed16ByteAlignment() && !isNaked() && (x86Context._mem16BlocksCount + (x86Context._mem8BlocksCount > 0)))
258 {
259 // Have to align stack to 16-bytes.
260 setFuncFlag(kX86FuncFlagIsEspAdjusted | kX86FuncFlagPerform16ByteAlignment);
261 }
262
263 _gpModifiedAndPreserved = x86Context._modifiedGpRegisters & _x86Decl.getGpPreservedMask() & (~IntUtil::maskFromIndex(kX86RegIndexEsp));
264 _mmModifiedAndPreserved = x86Context._modifiedMmRegisters & _x86Decl.getMmPreservedMask();
265 _xmmModifiedAndPreserved = x86Context._modifiedXmmRegisters & _x86Decl.getXmmPreservedMask();
266 _movDqInstCode = (isAssumed16ByteAlignment() | isPerformed16ByteAlignment()) ? kX86InstMovDQA : kX86InstMovDQU;
267
268 // Prolog & Epilog stack size.
269 {
270 int32_t memGpSize = IntUtil::bitCount(_gpModifiedAndPreserved) * sizeof(intptr_t);
271 int32_t memMmSize = IntUtil::bitCount(_mmModifiedAndPreserved) * 8;
272 int32_t memXmmSize = IntUtil::bitCount(_xmmModifiedAndPreserved) * 16;
273
274 if (hasFuncFlag(kX86FuncFlagPushPop))
275 {
276 _pePushPopStackSize = memGpSize;
277 _peMovStackSize = memXmmSize + IntUtil::align<int32_t>(memMmSize, 16);
278 }
279 else
280 {
281 _pePushPopStackSize = 0;
282 _peMovStackSize = memXmmSize + IntUtil::align<int32_t>(memMmSize + memGpSize, 16);
283 }
284 }
285
286 if (isPerformed16ByteAlignment())
287 {
288 _peAdjustStackSize += IntUtil::delta<int32_t>(_pePushPopStackSize, 16);
289 }
290 else
291 {
292 int32_t v = 16 - sizeof(uintptr_t);
293
294 if (!isNaked())
295 v -= sizeof(uintptr_t);
296
297 v -= _pePushPopStackSize & 15;
298
299 if (v < 0)
300 v += 16;
301
302 _peAdjustStackSize = v;
303
304 //_peAdjustStackSize += IntUtil::delta<int32_t>(_pePushPopStackSize + v, 16);
305 }
306
307 // Memory stack size.
308 _memStackSize = x86Context._memBytesTotal;
309 _memStackSize16 = IntUtil::align(_memStackSize, 16);
310
311 if (isNaked())
312 {
313 x86Context._argumentsBaseReg = kX86RegIndexEsp;
314 x86Context._argumentsBaseOffset = hasFuncFlag(kX86FuncFlagIsEspAdjusted)
315 ? (_funcCallStackSize + _memStackSize16 + _peMovStackSize + _pePushPopStackSize + _peAdjustStackSize)
316 : (_pePushPopStackSize);
317 }
318 else
319 {
320 x86Context._argumentsBaseReg = kX86RegIndexEbp;
321 x86Context._argumentsBaseOffset = sizeof(sysint_t);
322 }
323
324 x86Context._variablesBaseReg = kX86RegIndexEsp;
325 x86Context._variablesBaseOffset = _funcCallStackSize;
326
327 if (!hasFuncFlag(kX86FuncFlagIsEspAdjusted))
328 x86Context._variablesBaseOffset = -_memStackSize16 - _peMovStackSize - _peAdjustStackSize;
329 }
330
_dumpFunction(CompilerContext & cc)331 void X86CompilerFuncDecl::_dumpFunction(CompilerContext& cc)
332 {
333 X86CompilerContext& x86Context = static_cast<X86CompilerContext&>(cc);
334 X86Compiler* x86Compiler = getCompiler();
335
336 Logger* logger = x86Compiler->getLogger();
337 ASMJIT_ASSERT(logger != NULL);
338
339 uint32_t i;
340 char _buf[1024];
341 char* p;
342
343 // Log function prototype.
344 {
345 uint32_t argumentsCount = _x86Decl.getArgumentsCount();
346 bool first = true;
347
348 logger->logString("; Function Prototype:\n");
349 logger->logString(";\n");
350
351 for (i = 0; i < argumentsCount; i++)
352 {
353 const FuncArg& a = _x86Decl.getArgument(i);
354 X86CompilerVar* cv = getVar(i);
355
356 if (first)
357 {
358 logger->logString("; IDX| Type | Sz | Home |\n");
359 logger->logString("; ---+----------+----+----------------+\n");
360 }
361
362 char* memHome = memHome = _buf;
363
364 if (a.hasRegIndex())
365 {
366 Reg regOp(a.getRegIndex() | kX86RegTypeGpz, 0);
367 X86Assembler_dumpOperand(memHome, ®Op, kX86RegTypeGpz, 0)[0] = '\0';
368 }
369 else
370 {
371 Mem memOp;
372 memOp._mem.base = kX86RegIndexEsp;
373 memOp._mem.displacement = a.getStackOffset();
374 X86Assembler_dumpOperand(memHome, &memOp, kX86RegTypeGpz, 0)[0] = '\0';
375 }
376
377 logger->logFormat("; %-3u| %-9s| %-3u| %-15s|\n",
378 // Argument index.
379 i,
380 // Argument type.
381 cv->getType() < kX86VarTypeCount ? x86VarInfo[cv->getType()].getName() : "invalid",
382 // Argument size.
383 cv->getSize(),
384 // Argument memory home.
385 memHome
386 );
387
388 first = false;
389 }
390 logger->logString(";\n");
391 }
392
393 // Log variables.
394 {
395 uint32_t variablesCount = (uint32_t)x86Compiler->_vars.getLength();
396 bool first = true;
397
398 logger->logString("; Variables:\n");
399 logger->logString(";\n");
400
401 for (i = 0; i < variablesCount; i++)
402 {
403 X86CompilerVar* cv = static_cast<X86CompilerVar*>(x86Compiler->_vars[i]);
404
405 // If this variable is not related to this function then skip it.
406 if (cv->funcScope != this)
407 continue;
408
409 // Get some information about variable type.
410 const X86VarInfo& vinfo = x86VarInfo[cv->getType()];
411
412 if (first)
413 {
414 logger->logString("; ID | Type | Sz | Home | Register Access | Memory Access |\n");
415 logger->logString("; ---+----------+----+----------------+-------------------+-------------------+\n");
416 }
417
418 char* memHome = (char*)"[None]";
419 if (cv->homeMemoryData != NULL)
420 {
421 VarMemBlock* memBlock = reinterpret_cast<VarMemBlock*>(cv->homeMemoryData);
422 memHome = _buf;
423
424 Mem memOp;
425 if (cv->isMemArgument())
426 {
427 const FuncArg& a = _x86Decl.getArgument(i);
428
429 memOp._mem.base = x86Context._argumentsBaseReg;
430 memOp._mem.displacement += x86Context._argumentsBaseOffset;
431 memOp._mem.displacement += a.getStackOffset();
432 }
433 else
434 {
435 memOp._mem.base = x86Context._variablesBaseReg;
436 memOp._mem.displacement += x86Context._variablesBaseOffset;
437 memOp._mem.displacement += memBlock->offset;
438 }
439 X86Assembler_dumpOperand(memHome, &memOp, kX86RegTypeGpz, 0)[0] = '\0';
440 }
441
442 logger->logFormat("; %-3u| %-9s| %-3u| %-15s| r=%-4uw=%-4ux=%-4u| r=%-4uw=%-4ux=%-4u|\n",
443 // Variable id.
444 (uint)(i & kOperandIdValueMask),
445 // Variable type.
446 cv->getType() < kX86VarTypeCount ? vinfo.getName() : "invalid",
447 // Variable size.
448 cv->getSize(),
449 // Variable memory home.
450 memHome,
451 // Register access count.
452 (unsigned int)cv->regReadCount,
453 (unsigned int)cv->regWriteCount,
454 (unsigned int)cv->regRwCount,
455 // Memory access count.
456 (unsigned int)cv->memReadCount,
457 (unsigned int)cv->memWriteCount,
458 (unsigned int)cv->memRwCount
459 );
460 first = false;
461 }
462 logger->logString(";\n");
463 }
464
465 // Log modified registers.
466 {
467 p = _buf;
468
469 uint32_t r;
470 uint32_t modifiedRegisters = 0;
471
472 for (r = 0; r < 3; r++)
473 {
474 bool first = true;
475 uint32_t regs;
476 uint32_t type;
477
478 switch (r)
479 {
480 case 0:
481 regs = x86Context._modifiedGpRegisters;
482 type = kX86RegTypeGpz;
483 p = StringUtil::copy(p, "; GP : ");
484 break;
485 case 1:
486 regs = x86Context._modifiedMmRegisters;
487 type = kX86RegTypeMm;
488 p = StringUtil::copy(p, "; MM : ");
489 break;
490 case 2:
491 regs = x86Context._modifiedXmmRegisters;
492 type = kX86RegTypeXmm;
493 p = StringUtil::copy(p, "; XMM: ");
494 break;
495 default:
496 ASMJIT_ASSERT(0);
497 }
498
499 for (i = 0; i < kX86RegNumBase; i++)
500 {
501 if ((regs & IntUtil::maskFromIndex(i)) != 0)
502 {
503 if (!first) { *p++ = ','; *p++ = ' '; }
504 p = X86Assembler_dumpRegister(p, type, i);
505 first = false;
506 modifiedRegisters++;
507 }
508 }
509 *p++ = '\n';
510 }
511 *p = '\0';
512
513 logger->logFormat("; Modified registers (%u):\n", (unsigned int)modifiedRegisters);
514 logger->logString(_buf);
515 }
516
517 logger->logString("\n");
518 }
519
_emitProlog(CompilerContext & cc)520 void X86CompilerFuncDecl::_emitProlog(CompilerContext& cc)
521 {
522 X86CompilerContext& x86Context = static_cast<X86CompilerContext&>(cc);
523 X86Compiler* x86Compiler = getCompiler();
524
525 // --------------------------------------------------------------------------
526 // [Init]
527 // --------------------------------------------------------------------------
528
529 uint32_t i, mask;
530 uint32_t preservedGP = _gpModifiedAndPreserved;
531 uint32_t preservedMM = _mmModifiedAndPreserved;
532 uint32_t preservedXMM = _xmmModifiedAndPreserved;
533
534 int32_t stackOffset = _getRequiredStackOffset();
535 int32_t stackPos;
536
537 // --------------------------------------------------------------------------
538 // [Prolog]
539 // --------------------------------------------------------------------------
540
541 if (x86Compiler->getLogger())
542 x86Compiler->comment("Prolog");
543
544 // Emit standard prolog entry code (but don't do it if function is set to be
545 // naked).
546 //
547 // Also see the _prologEpilogStackAdjust variable. If function is naked (so
548 // prolog and epilog will not contain "push ebp" and "mov ebp, esp", we need
549 // to adjust stack by 8 bytes in 64-bit mode (this will give us that stack
550 // will remain aligned to 16 bytes).
551 if (!isNaked())
552 {
553 x86Compiler->emit(kX86InstPush, zbp);
554 x86Compiler->emit(kX86InstMov, zbp, zsp);
555 }
556
557 // Align manually stack-pointer to 16-bytes.
558 if (isPerformed16ByteAlignment())
559 {
560 ASMJIT_ASSERT(!isNaked());
561 x86Compiler->emit(kX86InstAnd, zsp, imm(-16));
562 }
563
564 // --------------------------------------------------------------------------
565 // [Save Gp - Push/Pop]
566 // --------------------------------------------------------------------------
567
568 if (preservedGP != 0 && hasFuncFlag(kX86FuncFlagPushPop))
569 {
570 for (i = 0, mask = 1; i < kX86RegNumGp; i++, mask <<= 1)
571 {
572 if (preservedGP & mask)
573 x86Compiler->emit(kX86InstPush, gpz(i));
574 }
575 }
576
577 // --------------------------------------------------------------------------
578 // [Adjust Scack]
579 // --------------------------------------------------------------------------
580
581 if (isEspAdjusted())
582 {
583 stackPos = _memStackSize16 + _funcCallStackSize;
584 if (stackOffset != 0)
585 x86Compiler->emit(kX86InstSub, zsp, imm(stackOffset));
586 }
587 else
588 {
589 stackPos = -(_peMovStackSize + _peAdjustStackSize);
590 //if (_pePushPop) stackPos += IntUtil::bitCount(preservedGP) * sizeof(sysint_t);
591 }
592
593 // --------------------------------------------------------------------------
594 // [Save Xmm - MovDqa/MovDqu]
595 // --------------------------------------------------------------------------
596
597 if (preservedXMM != 0)
598 {
599 for (i = 0, mask = 1; i < kX86RegNumXmm; i++, mask <<= 1)
600 {
601 if (preservedXMM & mask)
602 {
603 x86Compiler->emit(_movDqInstCode, dqword_ptr(zsp, stackPos), xmm(i));
604 stackPos += 16;
605 }
606 }
607 }
608
609 // --------------------------------------------------------------------------
610 // [Save Mm - MovQ]
611 // --------------------------------------------------------------------------
612
613 if (preservedMM != 0)
614 {
615 for (i = 0, mask = 1; i < 8; i++, mask <<= 1)
616 {
617 if (preservedMM & mask)
618 {
619 x86Compiler->emit(kX86InstMovQ, qword_ptr(zsp, stackPos), mm(i));
620 stackPos += 8;
621 }
622 }
623 }
624
625 // --------------------------------------------------------------------------
626 // [Save Gp - Mov]
627 // --------------------------------------------------------------------------
628
629 if (preservedGP != 0 && !hasFuncFlag(kX86FuncFlagPushPop))
630 {
631 for (i = 0, mask = 1; i < kX86RegNumGp; i++, mask <<= 1)
632 {
633 if (preservedGP & mask)
634 {
635 x86Compiler->emit(kX86InstMov, sysint_ptr(zsp, stackPos), gpz(i));
636 stackPos += sizeof(sysint_t);
637 }
638 }
639 }
640
641 // --------------------------------------------------------------------------
642 // [...]
643 // --------------------------------------------------------------------------
644
645 if (x86Compiler->getLogger())
646 x86Compiler->comment("Body");
647 }
648
_emitEpilog(CompilerContext & cc)649 void X86CompilerFuncDecl::_emitEpilog(CompilerContext& cc)
650 {
651 X86CompilerContext& x86Context = static_cast<X86CompilerContext&>(cc);
652 X86Compiler* x86Compiler = getCompiler();
653
654 const X86CpuInfo* cpuInfo = X86CpuInfo::getGlobal();
655
656 // --------------------------------------------------------------------------
657 // [Init]
658 // --------------------------------------------------------------------------
659
660 uint32_t i, mask;
661 uint32_t preservedGP = _gpModifiedAndPreserved;
662 uint32_t preservedMM = _mmModifiedAndPreserved;
663 uint32_t preservedXMM = _xmmModifiedAndPreserved;
664
665 int32_t stackOffset = _getRequiredStackOffset();
666 int32_t stackPos;
667
668 if (isEspAdjusted())
669 stackPos = _memStackSize16 + _funcCallStackSize;
670 else
671 stackPos = -(_peMovStackSize + _peAdjustStackSize);
672
673 // --------------------------------------------------------------------------
674 // [Epilog]
675 // --------------------------------------------------------------------------
676
677 if (x86Compiler->getLogger())
678 x86Compiler->comment("Epilog");
679
680 // --------------------------------------------------------------------------
681 // [Restore Xmm - MovDqa/ModDqu]
682 // --------------------------------------------------------------------------
683
684 if (preservedXMM != 0)
685 {
686 for (i = 0, mask = 1; i < kX86RegNumXmm; i++, mask <<= 1)
687 {
688 if (preservedXMM & mask)
689 {
690 x86Compiler->emit(_movDqInstCode, xmm(i), dqword_ptr(zsp, stackPos));
691 stackPos += 16;
692 }
693 }
694 }
695
696 // --------------------------------------------------------------------------
697 // [Restore Mm - MovQ]
698 // --------------------------------------------------------------------------
699
700 if (preservedMM != 0)
701 {
702 for (i = 0, mask = 1; i < 8; i++, mask <<= 1)
703 {
704 if (preservedMM & mask)
705 {
706 x86Compiler->emit(kX86InstMovQ, mm(i), qword_ptr(zsp, stackPos));
707 stackPos += 8;
708 }
709 }
710 }
711
712 // --------------------------------------------------------------------------
713 // [Restore Gp - Mov]
714 // --------------------------------------------------------------------------
715
716 if (preservedGP != 0 && !hasFuncFlag(kX86FuncFlagPushPop))
717 {
718 for (i = 0, mask = 1; i < kX86RegNumGp; i++, mask <<= 1)
719 {
720 if (preservedGP & mask)
721 {
722 x86Compiler->emit(kX86InstMov, gpz(i), sysint_ptr(zsp, stackPos));
723 stackPos += sizeof(sysint_t);
724 }
725 }
726 }
727
728 // --------------------------------------------------------------------------
729 // [Adjust Stack]
730 // --------------------------------------------------------------------------
731
732 if (isEspAdjusted() && stackOffset != 0)
733 x86Compiler->emit(kX86InstAdd, zsp, imm(stackOffset));
734
735 // --------------------------------------------------------------------------
736 // [Restore Gp - Push/Pop]
737 // --------------------------------------------------------------------------
738
739 if (preservedGP != 0 && hasFuncFlag(kX86FuncFlagPushPop))
740 {
741 for (i = kX86RegNumGp - 1, mask = 1 << i; (int32_t)i >= 0; i--, mask >>= 1)
742 {
743 if (preservedGP & mask)
744 x86Compiler->emit(kX86InstPop, gpz(i));
745 }
746 }
747
748 // --------------------------------------------------------------------------
749 // [Emms]
750 // --------------------------------------------------------------------------
751
752 if (hasFuncFlag(kX86FuncFlagEmitEmms))
753 x86Compiler->emit(kX86InstEmms);
754
755 // --------------------------------------------------------------------------
756 // [MFence/SFence/LFence]
757 // --------------------------------------------------------------------------
758
759 if (hasFuncFlag(kX86FuncFlagEmitSFence) & hasFuncFlag(kX86FuncFlagEmitLFence))
760 x86Compiler->emit(kX86InstMFence);
761 else if (hasFuncFlag(kX86FuncFlagEmitSFence))
762 x86Compiler->emit(kX86InstSFence);
763 else if (hasFuncFlag(kX86FuncFlagEmitLFence))
764 x86Compiler->emit(kX86InstLFence);
765
766 // --------------------------------------------------------------------------
767 // [Epilog]
768 // --------------------------------------------------------------------------
769
770 // Emit standard epilog leave code (if needed).
771 if (!isNaked())
772 {
773 // AMD seems to prefer LEAVE instead of MOV/POP sequence.
774 if (cpuInfo->getVendorId() == kCpuAmd)
775 {
776 x86Compiler->emit(kX86InstLeave);
777 }
778 else
779 {
780 x86Compiler->emit(kX86InstMov, zsp, zbp);
781 x86Compiler->emit(kX86InstPop, zbp);
782 }
783 }
784
785 // Emit return.
786 if (_x86Decl.getCalleePopsStack())
787 x86Compiler->emit(kX86InstRet, imm((int16_t)_x86Decl.getArgumentsStackSize()));
788 else
789 x86Compiler->emit(kX86InstRet);
790 }
791
792 // ============================================================================
793 // [AsmJit::X86CompilerFuncDecl - Function-Call]
794 // ============================================================================
795
reserveStackForFunctionCall(int32_t size)796 void X86CompilerFuncDecl::reserveStackForFunctionCall(int32_t size)
797 {
798 size = IntUtil::align<int32_t>(size, 16);
799 if (size > _funcCallStackSize)
800 _funcCallStackSize = size;
801 setFuncFlag(kFuncFlagIsCaller);
802 }
803
804 // ============================================================================
805 // [AsmJit::X86CompilerFuncEnd - Construction / Destruction]
806 // ============================================================================
807
X86CompilerFuncEnd(X86Compiler * x86Compiler,X86CompilerFuncDecl * func)808 X86CompilerFuncEnd::X86CompilerFuncEnd(X86Compiler* x86Compiler, X86CompilerFuncDecl* func) :
809 CompilerFuncEnd(x86Compiler, func)
810 {
811 }
812
~X86CompilerFuncEnd()813 X86CompilerFuncEnd::~X86CompilerFuncEnd()
814 {
815 }
816
817 // ============================================================================
818 // [AsmJit::X86CompilerFuncEnd - Interface]
819 // ============================================================================
820
prepare(CompilerContext & cc)821 void X86CompilerFuncEnd::prepare(CompilerContext& cc)
822 {
823 X86CompilerContext& x86Context = static_cast<X86CompilerContext&>(cc);
824 _offset = x86Context._currentOffset++;
825 }
826
translate(CompilerContext & cc)827 CompilerItem* X86CompilerFuncEnd::translate(CompilerContext& cc)
828 {
829 _isTranslated = true;
830 return NULL;
831 }
832
833 // ============================================================================
834 // [AsmJit::X86CompilerFuncRet - Construction / Destruction]
835 // ============================================================================
836
X86CompilerFuncRet(X86Compiler * x86Compiler,X86CompilerFuncDecl * func,const Operand * first,const Operand * second)837 X86CompilerFuncRet::X86CompilerFuncRet(X86Compiler* x86Compiler, X86CompilerFuncDecl* func, const Operand* first, const Operand* second) :
838 CompilerFuncRet(x86Compiler, func, first, second)
839 {
840 /*
841 // TODO:?
842
843 // Check whether the return value is compatible.
844 uint32_t retValType = function->_x86Decl.getReturnType();
845 bool valid = false;
846
847 switch (retValType)
848 {
849 case kX86VarTypeGpd:
850 case kX86VarTypeGpq:
851 if ((_ret[0].isVar() && (reinterpret_cast<const Var&>(_ret[0]).isGpVar())) ||
852 (_ret[0].isImm()))
853 {
854 valid = true;
855 }
856 break;
857
858 case kX86VarTypeX87:
859 case kX86VarTypeX87SS:
860 case kX86VarTypeX87SD:
861 if ((_ret[0].isVar() && (reinterpret_cast<const Var&>(_ret[0]).isX87Var() ||
862 reinterpret_cast<const Var&>(_ret[0]).isXmmVar() )) )
863 {
864 valid = true;
865 }
866 break;
867
868 case kX86VarTypeMm:
869 break;
870
871 case kVarTypeInvalid:
872 if (_ret[0].isNone() &&
873 _ret[1].isNone())
874 {
875 valid = true;
876 }
877 break;
878
879 default:
880 break;
881 }
882
883 // Incompatible return value.
884 if (!valid)
885 {
886 c->setError(kErrorIncompatibleReturnType);
887 }
888 */
889 }
890
~X86CompilerFuncRet()891 X86CompilerFuncRet::~X86CompilerFuncRet()
892 {
893 }
894
895 // ============================================================================
896 // [AsmJit::X86CompilerFuncRet - Interface]
897 // ============================================================================
898
prepare(CompilerContext & cc)899 void X86CompilerFuncRet::prepare(CompilerContext& cc)
900 {
901 X86CompilerContext& x86Context = static_cast<X86CompilerContext&>(cc);
902 X86Compiler* x86Compiler = x86Context.getCompiler();
903
904 uint32_t retValType = getFunc()->_x86Decl.getReturnType();
905 _offset = x86Context._currentOffset;
906
907 if (retValType != kVarTypeInvalid)
908 {
909 uint32_t i;
910 for (i = 0; i < 2; i++)
911 {
912 Operand& o = _ret[i];
913
914 if (o.isVar())
915 {
916 ASMJIT_ASSERT(o.getId() != kInvalidValue);
917 X86CompilerVar* cv = x86Compiler->_getVar(o.getId());
918 ASMJIT_ASSERT(cv != NULL);
919
920 // First item (begin of variable scope).
921 if (cv->firstItem == NULL) cv->firstItem = this;
922
923 // Last item (end of variable scope).
924 cv->lastItem = this;
925
926 if (cv->workOffset == _offset) continue;
927 if (!x86Context._isActive(cv)) x86Context._addActive(cv);
928
929 cv->workOffset = _offset;
930 cv->regReadCount++;
931
932 if (X86Util::isVarTypeInt(cv->getType()) && X86Util::isVarTypeInt(retValType))
933 {
934 x86Context._newRegisterHomeIndex(cv, (i == 0) ? kX86RegIndexEax : kX86RegIndexEdx);
935 }
936 }
937 }
938 }
939
940 x86Context._currentOffset++;
941 }
942
translate(CompilerContext & cc)943 CompilerItem* X86CompilerFuncRet::translate(CompilerContext& cc)
944 {
945 X86CompilerContext& x86Context = static_cast<X86CompilerContext&>(cc);
946 X86Compiler* x86Compiler = x86Context.getCompiler();
947
948 // Check whether the return value is compatible.
949 uint32_t retValType = getFunc()->getDecl()->getReturnType();
950 uint32_t i;
951
952 switch (retValType)
953 {
954 case kX86VarTypeGpd:
955 case kX86VarTypeGpq:
956 for (i = 0; i < 2; i++)
957 {
958 uint32_t dstIndex = (i == 0) ? kX86RegIndexEax : kX86RegIndexEdx;
959 uint32_t srcIndex;
960
961 if (_ret[i].isVar())
962 {
963 if (reinterpret_cast<const Var&>(_ret[i]).isGpVar())
964 {
965 X86CompilerVar* cv = x86Compiler->_getVar(_ret[i].getId());
966 ASMJIT_ASSERT(cv != NULL);
967
968 srcIndex = cv->regIndex;
969 if (srcIndex == kRegIndexInvalid)
970 x86Compiler->emit(kX86InstMov, gpz(dstIndex), x86Context._getVarMem(cv));
971 else if (dstIndex != srcIndex)
972 x86Compiler->emit(kX86InstMov, gpz(dstIndex), gpz(srcIndex));
973 }
974 }
975 else if (_ret[i].isImm())
976 {
977 x86Compiler->emit(kX86InstMov, gpz(dstIndex), _ret[i]);
978 }
979 }
980 break;
981
982 case kX86VarTypeX87:
983 case kX86VarTypeX87SS:
984 case kX86VarTypeX87SD:
985 // There is case that we need to return two values (Unix-ABI specific):
986 // - FLD #2
987 //- FLD #1
988 i = 2;
989 do {
990 i--;
991 uint32_t dsti = i;
992 uint32_t srci;
993
994 if (_ret[i].isVar())
995 {
996 if (reinterpret_cast<const Var&>(_ret[i]).isX87Var())
997 {
998 // TODO: X87 Support.
999 }
1000 else if (reinterpret_cast<const Var&>(_ret[i]).isXmmVar())
1001 {
1002 X86CompilerVar* cv = x86Compiler->_getVar(_ret[i].getId());
1003 ASMJIT_ASSERT(cv != NULL);
1004
1005 srci = cv->regIndex;
1006 if (srci != kRegIndexInvalid)
1007 x86Context.saveXmmVar(cv);
1008
1009 switch (cv->getType())
1010 {
1011 case kX86VarTypeXmmSS:
1012 case kX86VarTypeXmmPS:
1013 x86Compiler->emit(kX86InstFLd, _BaseVarMem(reinterpret_cast<Var&>(_ret[i]), 4));
1014 break;
1015 case kX86VarTypeXmmSD:
1016 case kX86VarTypeXmmPD:
1017 x86Compiler->emit(kX86InstFLd, _BaseVarMem(reinterpret_cast<Var&>(_ret[i]), 8));
1018 break;
1019 }
1020 }
1021 }
1022 } while (i != 0);
1023 break;
1024
1025 case kX86VarTypeMm:
1026 for (i = 0; i < 2; i++)
1027 {
1028 uint32_t dsti = i;
1029 uint32_t srci;
1030
1031 if (_ret[i].isVar())
1032 {
1033 if (reinterpret_cast<const Var&>(_ret[i]).isGpVar())
1034 {
1035 X86CompilerVar* cv = x86Compiler->_getVar(_ret[i].getId());
1036 ASMJIT_ASSERT(cv != NULL);
1037
1038 srci = cv->regIndex;
1039 uint32_t inst = _ret[i].isRegType(kX86RegTypeGpq) ? kX86InstMovQ : kX86InstMovD;
1040
1041 if (srci == kRegIndexInvalid)
1042 x86Compiler->emit(inst, mm(dsti), x86Context._getVarMem(cv));
1043 else
1044 #if defined(ASMJIT_X86)
1045 x86Compiler->emit(inst, mm(dsti), gpd(srci));
1046 #else
1047 x86Compiler->emit(inst, mm(dsti), _ret[i].isRegType(kX86RegTypeGpq) ? gpq(srci) : gpd(srci));
1048 #endif
1049 }
1050 else if (reinterpret_cast<const Var&>(_ret[i]).isMmVar())
1051 {
1052 X86CompilerVar* cv = x86Compiler->_getVar(_ret[i].getId());
1053 ASMJIT_ASSERT(cv != NULL);
1054
1055 srci = cv->regIndex;
1056 uint32_t inst = kX86InstMovQ;
1057
1058 if (srci == kRegIndexInvalid)
1059 x86Compiler->emit(inst, mm(dsti), x86Context._getVarMem(cv));
1060 else if (dsti != srci)
1061 x86Compiler->emit(inst, mm(dsti), mm(srci));
1062 }
1063 else if (reinterpret_cast<const Var&>(_ret[i]).isXmmVar())
1064 {
1065 X86CompilerVar* cv = x86Compiler->_getVar(_ret[i].getId());
1066 ASMJIT_ASSERT(cv != NULL);
1067
1068 srci = cv->regIndex;
1069 uint32_t inst = kX86InstMovQ;
1070 if (reinterpret_cast<const Var&>(_ret[i]).getVarType() == kX86VarTypeXmmSS) inst = kX86InstMovD;
1071
1072 if (srci == kRegIndexInvalid)
1073 x86Compiler->emit(inst, mm(dsti), x86Context._getVarMem(cv));
1074 else
1075 x86Compiler->emit(inst, mm(dsti), xmm(srci));
1076 }
1077 }
1078 }
1079 break;
1080
1081 case kX86VarTypeXmm:
1082 case kX86VarTypeXmmPS:
1083 case kX86VarTypeXmmPD:
1084 for (i = 0; i < 2; i++)
1085 {
1086 uint32_t dsti = i;
1087 uint32_t srci;
1088
1089 if (_ret[i].isVar())
1090 {
1091 if (reinterpret_cast<const Var&>(_ret[i]).isGpVar())
1092 {
1093 X86CompilerVar* cv = x86Compiler->_getVar(_ret[i].getId());
1094 ASMJIT_ASSERT(cv != NULL);
1095
1096 srci = cv->regIndex;
1097 uint32_t inst = _ret[i].isRegType(kX86RegTypeGpq) ? kX86InstMovQ : kX86InstMovD;
1098
1099 if (srci == kRegIndexInvalid)
1100 x86Compiler->emit(inst, xmm(dsti), x86Context._getVarMem(cv));
1101 else
1102 #if defined(ASMJIT_X86)
1103 x86Compiler->emit(inst, xmm(dsti), gpd(srci));
1104 #else
1105 x86Compiler->emit(inst, xmm(dsti), _ret[i].isRegType(kX86RegTypeGpq) ? gpq(srci) : gpd(srci));
1106 #endif
1107 }
1108 else if (reinterpret_cast<const Var&>(_ret[i]).isX87Var())
1109 {
1110 // TODO: X87 Support.
1111 }
1112 else if (reinterpret_cast<const Var&>(_ret[i]).isMmVar())
1113 {
1114 X86CompilerVar* cv = x86Compiler->_getVar(_ret[i].getId());
1115 ASMJIT_ASSERT(cv != NULL);
1116
1117 srci = cv->regIndex;
1118 if (srci == kRegIndexInvalid)
1119 x86Compiler->emit(kX86InstMovQ, xmm(dsti), x86Context._getVarMem(cv));
1120 else
1121 x86Compiler->emit(kX86InstMovQ, xmm(dsti), mm(srci));
1122 }
1123 else if (reinterpret_cast<const Var&>(_ret[i]).isXmmVar())
1124 {
1125 X86CompilerVar* cv = x86Compiler->_getVar(_ret[i].getId());
1126 ASMJIT_ASSERT(cv != NULL);
1127
1128 srci = cv->regIndex;
1129 if (srci == kRegIndexInvalid)
1130 x86Compiler->emit(kX86InstMovDQA, xmm(dsti), x86Context._getVarMem(cv));
1131 else if (dsti != srci)
1132 x86Compiler->emit(kX86InstMovDQA, xmm(dsti), xmm(srci));
1133 }
1134 }
1135 }
1136 break;
1137
1138 case kX86VarTypeXmmSS:
1139 for (i = 0; i < 2; i++)
1140 {
1141 uint32_t dsti = i;
1142 uint32_t srci;
1143
1144 if (_ret[i].isVar())
1145 {
1146 if (reinterpret_cast<const Var&>(_ret[i]).isX87Var())
1147 {
1148 // TODO: X87 Support.
1149 }
1150 else if (reinterpret_cast<const Var&>(_ret[i]).isXmmVar())
1151 {
1152 X86CompilerVar* cv = x86Compiler->_getVar(_ret[i].getId());
1153 ASMJIT_ASSERT(cv != NULL);
1154
1155 srci = cv->regIndex;
1156 switch (cv->getType())
1157 {
1158 case kX86VarTypeXmm:
1159 if (srci == kRegIndexInvalid)
1160 x86Compiler->emit(kX86InstMovDQA, xmm(dsti), x86Context._getVarMem(cv));
1161 else if (dsti != srci)
1162 x86Compiler->emit(kX86InstMovDQA, xmm(dsti), xmm(srci));
1163 break;
1164 case kX86VarTypeXmmSS:
1165 case kX86VarTypeXmmPS:
1166 if (srci == kRegIndexInvalid)
1167 x86Compiler->emit(kX86InstMovSS, xmm(dsti), x86Context._getVarMem(cv));
1168 else
1169 x86Compiler->emit(kX86InstMovSS, xmm(dsti), xmm(srci));
1170 break;
1171 case kX86VarTypeXmmSD:
1172 case kX86VarTypeXmmPD:
1173 if (srci == kRegIndexInvalid)
1174 x86Compiler->emit(kX86InstCvtSD2SS, xmm(dsti), x86Context._getVarMem(cv));
1175 else if (dsti != srci)
1176 x86Compiler->emit(kX86InstCvtSD2SS, xmm(dsti), xmm(srci));
1177 break;
1178 }
1179 }
1180 }
1181 }
1182 break;
1183
1184 case kX86VarTypeXmmSD:
1185 for (i = 0; i < 2; i++)
1186 {
1187 uint32_t dsti = i;
1188 uint32_t srci;
1189
1190 if (_ret[i].isVar())
1191 {
1192 if (reinterpret_cast<const Var&>(_ret[i]).isX87Var())
1193 {
1194 // TODO: X87 Support.
1195 }
1196 else if (reinterpret_cast<const Var&>(_ret[i]).isXmmVar())
1197 {
1198 X86CompilerVar* cv = x86Compiler->_getVar(_ret[i].getId());
1199 ASMJIT_ASSERT(cv != NULL);
1200
1201 srci = cv->regIndex;
1202 switch (cv->getType())
1203 {
1204 case kX86VarTypeXmm:
1205 if (srci == kRegIndexInvalid)
1206 x86Compiler->emit(kX86InstMovDQA, xmm(dsti), x86Context._getVarMem(cv));
1207 else if (dsti != srci)
1208 x86Compiler->emit(kX86InstMovDQA, xmm(dsti), xmm(srci));
1209 break;
1210 case kX86VarTypeXmmSS:
1211 case kX86VarTypeXmmPS:
1212 if (srci == kRegIndexInvalid)
1213 x86Compiler->emit(kX86InstCvtSS2SD, xmm(dsti), x86Context._getVarMem(cv));
1214 else
1215 x86Compiler->emit(kX86InstCvtSS2SD, xmm(dsti), xmm(srci));
1216 break;
1217 case kX86VarTypeXmmSD:
1218 case kX86VarTypeXmmPD:
1219 if (srci == kRegIndexInvalid)
1220 x86Compiler->emit(kX86InstMovSD, xmm(dsti), x86Context._getVarMem(cv));
1221 else
1222 x86Compiler->emit(kX86InstMovSD, xmm(dsti), xmm(srci));
1223 break;
1224 }
1225 }
1226 }
1227 }
1228 break;
1229
1230 case kInvalidValue:
1231 default:
1232 break;
1233 }
1234
1235 if (mustEmitJump())
1236 {
1237 x86Context._isUnreachable = 1;
1238 }
1239
1240 for (i = 0; i < 2; i++)
1241 {
1242 if (_ret[i].isVar())
1243 {
1244 X86CompilerVar* cv = x86Compiler->_getVar(_ret[i].getId());
1245 x86Context._unuseVarOnEndOfScope(this, cv);
1246 }
1247 }
1248
1249 return translated();
1250 }
1251
emit(Assembler & a)1252 void X86CompilerFuncRet::emit(Assembler& a)
1253 {
1254 X86Assembler& x86Asm = static_cast<X86Assembler&>(a);
1255
1256 if (mustEmitJump())
1257 x86Asm.jmp(getFunc()->getExitLabel());
1258 }
1259
1260 // ============================================================================
1261 // [AsmJit::X86CompilerFuncRet - Misc]
1262 // ============================================================================
1263
getMaxSize() const1264 int X86CompilerFuncRet::getMaxSize() const
1265 {
1266 return mustEmitJump() ? 15 : 0;
1267 }
1268
1269 // ============================================================================
1270 // [AsmJit::X86CompilerFuncCall - Construction / Destruction]
1271 // ============================================================================
1272
X86CompilerFuncCall(X86Compiler * x86Compiler,X86CompilerFuncDecl * caller,const Operand * target)1273 X86CompilerFuncCall::X86CompilerFuncCall(X86Compiler* x86Compiler, X86CompilerFuncDecl* caller, const Operand* target) :
1274 CompilerFuncCall(x86Compiler, caller, target),
1275 _gpParams(0),
1276 _mmParams(0),
1277 _xmmParams(0),
1278 _variablesCount(0),
1279 _variables(NULL)
1280 {
1281 }
1282
~X86CompilerFuncCall()1283 X86CompilerFuncCall::~X86CompilerFuncCall()
1284 {
1285 memset(_argumentToVarRecord, 0, sizeof(VarCallRecord*) * kFuncArgsMax);
1286 }
1287
1288 // ============================================================================
1289 // [AsmJit::X86CompilerFuncCall - Interface]
1290 // ============================================================================
1291
prepare(CompilerContext & cc)1292 void X86CompilerFuncCall::prepare(CompilerContext& cc)
1293 {
1294 X86CompilerContext& x86Context = static_cast<X86CompilerContext&>(cc);
1295 X86Compiler* x86Compiler = getCompiler();
1296
1297 // Prepare is similar to X86CompilerInst::prepare(). We collect unique variables
1298 // and update statistics, but we don't use standard alloc/free register calls.
1299 //
1300 // The calling function is also unique in variable allocator point of view,
1301 // because we need to alloc some variables that may be destroyed be the
1302 // callee (okay, may not, but this is not guaranteed).
1303 _offset = x86Context._currentOffset;
1304
1305 // Tell EFunction that another function will be called inside. It needs this
1306 // information to reserve stack for the call and to mark esp adjustable.
1307 getCaller()->reserveStackForFunctionCall(static_cast<int32_t>(_x86Decl.getArgumentsStackSize()));
1308
1309 uint32_t i;
1310 uint32_t argumentsCount = _x86Decl.getArgumentsCount();
1311 uint32_t operandsCount = argumentsCount;
1312 uint32_t variablesCount = 0;
1313
1314 // Create registers used as arguments mask.
1315 for (i = 0; i < argumentsCount; i++)
1316 {
1317 const FuncArg& fArg = _x86Decl.getArguments()[i];
1318
1319 if (fArg.hasRegIndex())
1320 {
1321 switch (fArg.getVarType())
1322 {
1323 case kX86VarTypeGpd:
1324 case kX86VarTypeGpq:
1325 _gpParams |= IntUtil::maskFromIndex(fArg.getRegIndex());
1326 break;
1327 case kX86VarTypeMm:
1328 _mmParams |= IntUtil::maskFromIndex(fArg.getRegIndex());
1329 break;
1330 case kX86VarTypeXmm:
1331 case kX86VarTypeXmmSS:
1332 case kX86VarTypeXmmPS:
1333 case kX86VarTypeXmmSD:
1334 case kX86VarTypeXmmPD:
1335 _xmmParams |= IntUtil::maskFromIndex(fArg.getRegIndex());
1336 break;
1337 default:
1338 ASMJIT_ASSERT(0);
1339 }
1340 }
1341 else
1342 {
1343 x86Context.getFunc()->setFuncFlag(kX86FuncFlagIsEspAdjusted);
1344 }
1345 }
1346
1347 // Call address.
1348 operandsCount++;
1349
1350 // The first and the second return value.
1351 if (!_ret[0].isNone())
1352 operandsCount++;
1353 if (!_ret[1].isNone())
1354 operandsCount++;
1355
1356 #define __GET_VARIABLE(__vardata__) \
1357 { \
1358 X86CompilerVar* _candidate = __vardata__; \
1359 \
1360 for (var = cur; ;) \
1361 { \
1362 if (var == _variables) \
1363 { \
1364 var = cur++; \
1365 var->vdata = _candidate; \
1366 break; \
1367 } \
1368 \
1369 var--; \
1370 \
1371 if (var->vdata == _candidate) \
1372 { \
1373 break; \
1374 } \
1375 } \
1376 \
1377 ASMJIT_ASSERT(var != NULL); \
1378 }
1379
1380 for (i = 0; i < operandsCount; i++)
1381 {
1382 Operand& o = (i < argumentsCount)
1383 ? (_args[i])
1384 : (i == argumentsCount ? _target : _ret[i - argumentsCount - 1]);
1385
1386 if (o.isVar())
1387 {
1388 ASMJIT_ASSERT(o.getId() != kInvalidValue);
1389 X86CompilerVar* cv = x86Compiler->_getVar(o.getId());
1390 ASMJIT_ASSERT(cv != NULL);
1391
1392 if (cv->workOffset == _offset) continue;
1393 if (!x86Context._isActive(cv)) x86Context._addActive(cv);
1394
1395 cv->workOffset = _offset;
1396 variablesCount++;
1397 }
1398 else if (o.isMem())
1399 {
1400 if ((o.getId() & kOperandIdTypeMask) == kOperandIdTypeVar)
1401 {
1402 X86CompilerVar* cv = x86Compiler->_getVar(o.getId());
1403 ASMJIT_ASSERT(cv != NULL);
1404
1405 x86Context._markMemoryUsed(cv);
1406 if (!x86Context._isActive(cv)) x86Context._addActive(cv);
1407
1408 continue;
1409 }
1410 else if ((o._mem.base & kOperandIdTypeMask) == kOperandIdTypeVar)
1411 {
1412 X86CompilerVar* cv = x86Compiler->_getVar(o._mem.base);
1413 ASMJIT_ASSERT(cv != NULL);
1414
1415 if (cv->workOffset == _offset) continue;
1416 if (!x86Context._isActive(cv)) x86Context._addActive(cv);
1417
1418 cv->workOffset = _offset;
1419 variablesCount++;
1420 }
1421
1422 if ((o._mem.index & kOperandIdTypeMask) == kOperandIdTypeVar)
1423 {
1424 X86CompilerVar* cv = x86Compiler->_getVar(o._mem.index);
1425 ASMJIT_ASSERT(cv != NULL);
1426
1427 if (cv->workOffset == _offset) continue;
1428 if (!x86Context._isActive(cv)) x86Context._addActive(cv);
1429
1430 cv->workOffset = _offset;
1431 variablesCount++;
1432 }
1433 }
1434 }
1435
1436 // Traverse all active variables and set their funcCall pointer to this
1437 // call. This information can be used to choose between the preserved-first
1438 // and preserved-last register allocation.
1439 if (x86Context._active)
1440 {
1441 X86CompilerVar* first = static_cast<X86CompilerVar*>(x86Context._active);
1442 X86CompilerVar* active = first;
1443 do {
1444 if (active->funcCall == NULL)
1445 active->funcCall = this;
1446 active = active->nextActive;
1447 } while (active != first);
1448 }
1449
1450 if (!variablesCount)
1451 {
1452 x86Context._currentOffset++;
1453 return;
1454 }
1455
1456 _variables = reinterpret_cast<VarCallRecord*>(x86Compiler->getZoneMemory().alloc(sizeof(VarCallRecord) * variablesCount));
1457 if (!_variables)
1458 {
1459 x86Compiler->setError(kErrorNoHeapMemory);
1460 x86Context._currentOffset++;
1461 return;
1462 }
1463
1464 _variablesCount = variablesCount;
1465 memset(_variables, 0, sizeof(VarCallRecord) * variablesCount);
1466
1467 VarCallRecord* cur = _variables;
1468 VarCallRecord* var = NULL;
1469
1470 for (i = 0; i < operandsCount; i++)
1471 {
1472 Operand& o = (i < argumentsCount)
1473 ? (_args[i])
1474 : (i == argumentsCount ? _target : _ret[i - argumentsCount - 1]);
1475
1476 if (o.isVar())
1477 {
1478 X86CompilerVar* cv = x86Compiler->_getVar(o.getId());
1479 ASMJIT_ASSERT(cv != NULL);
1480
1481 __GET_VARIABLE(cv)
1482 _argumentToVarRecord[i] = var;
1483
1484 if (i < argumentsCount)
1485 {
1486 const FuncArg& fArg = _x86Decl.getArgument(i);
1487
1488 if (fArg.hasRegIndex())
1489 {
1490 x86Context._newRegisterHomeIndex(cv, fArg.getRegIndex());
1491
1492 switch (fArg.getVarType())
1493 {
1494 case kX86VarTypeGpd:
1495 case kX86VarTypeGpq:
1496 var->flags |= VarCallRecord::kFlagInGp;
1497 var->inCount++;
1498 break;
1499
1500 case kX86VarTypeMm:
1501 var->flags |= VarCallRecord::kFlagInMm;
1502 var->inCount++;
1503 break;
1504
1505 case kX86VarTypeXmm:
1506 case kX86VarTypeXmmSS:
1507 case kX86VarTypeXmmPS:
1508 case kX86VarTypeXmmSD:
1509 case kX86VarTypeXmmPD:
1510 var->flags |= VarCallRecord::kFlagInXmm;
1511 var->inCount++;
1512 break;
1513
1514 default:
1515 ASMJIT_ASSERT(0);
1516 }
1517 }
1518 else
1519 {
1520 var->inCount++;
1521 }
1522
1523 cv->regReadCount++;
1524 }
1525 else if (i == argumentsCount)
1526 {
1527 uint32_t mask = (~_x86Decl.getGpPreservedMask()) &
1528 (~_x86Decl.getGpArgumentsMask()) &
1529 (IntUtil::maskUpToIndex(kX86RegNumGp));
1530
1531 x86Context._newRegisterHomeIndex(cv, IntUtil::findFirstBit(mask));
1532 x86Context._newRegisterHomeMask(cv, mask);
1533
1534 var->flags |= VarCallRecord::kFlagCallReg;
1535 cv->regReadCount++;
1536 }
1537 else
1538 {
1539 switch (cv->getType())
1540 {
1541 case kX86VarTypeGpd:
1542 case kX86VarTypeGpq:
1543 if (i == argumentsCount+1)
1544 var->flags |= VarCallRecord::kFlagOutEax;
1545 else
1546 var->flags |= VarCallRecord::kFlagOutEdx;
1547 break;
1548
1549 case kX86VarTypeX87:
1550 case kX86VarTypeX87SS:
1551 case kX86VarTypeX87SD:
1552 #if defined(ASMJIT_X86)
1553 if (i == argumentsCount+1)
1554 var->flags |= VarCallRecord::kFlagOutSt0;
1555 else
1556 var->flags |= VarCallRecord::kFlagOutSt1;
1557 #else
1558 if (i == argumentsCount+1)
1559 var->flags |= VarCallRecord::kFlagOutXmm0;
1560 else
1561 var->flags |= VarCallRecord::kFlagOutXmm1;
1562 #endif
1563 break;
1564
1565 case kX86VarTypeMm:
1566 var->flags |= VarCallRecord::kFlagOutMm0;
1567 break;
1568
1569 case kX86VarTypeXmm:
1570 case kX86VarTypeXmmPS:
1571 case kX86VarTypeXmmPD:
1572 if (i == argumentsCount+1)
1573 var->flags |= VarCallRecord::kFlagOutXmm0;
1574 else
1575 var->flags |= VarCallRecord::kFlagOutXmm1;
1576 break;
1577
1578 case kX86VarTypeXmmSS:
1579 case kX86VarTypeXmmSD:
1580 #if defined(ASMJIT_X86)
1581 if (i == argumentsCount+1)
1582 var->flags |= VarCallRecord::kFlagOutSt0;
1583 else
1584 var->flags |= VarCallRecord::kFlagOutSt1;
1585 #else
1586 if (i == argumentsCount+1)
1587 var->flags |= VarCallRecord::kFlagOutXmm0;
1588 else
1589 var->flags |= VarCallRecord::kFlagOutXmm1;
1590 #endif
1591 break;
1592
1593 default:
1594 ASMJIT_ASSERT(0);
1595 }
1596
1597 cv->regWriteCount++;
1598 }
1599 }
1600 else if (o.isMem())
1601 {
1602 ASMJIT_ASSERT(i == argumentsCount);
1603
1604 if ((o.getId() & kOperandIdTypeMask) == kOperandIdTypeVar)
1605 {
1606 X86CompilerVar* cv = x86Compiler->_getVar(o.getId());
1607 ASMJIT_ASSERT(cv != NULL);
1608
1609 cv->memReadCount++;
1610 }
1611 else if ((o._mem.base & kOperandIdTypeMask) == kOperandIdTypeVar)
1612 {
1613 X86CompilerVar* cv = x86Compiler->_getVar(reinterpret_cast<Mem&>(o).getBase());
1614 ASMJIT_ASSERT(cv != NULL);
1615
1616 cv->regReadCount++;
1617
1618 __GET_VARIABLE(cv)
1619 var->flags |= VarCallRecord::kFlagCallReg | VarCallRecord::kFlagCallMem;
1620 }
1621
1622 if ((o._mem.index & kOperandIdTypeMask) == kOperandIdTypeVar)
1623 {
1624 X86CompilerVar* cv = x86Compiler->_getVar(reinterpret_cast<Mem&>(o).getIndex());
1625 ASMJIT_ASSERT(cv != NULL);
1626
1627 cv->regReadCount++;
1628
1629 __GET_VARIABLE(cv)
1630 var->flags |= VarCallRecord::kFlagCallReg | VarCallRecord::kFlagCallMem;
1631 }
1632 }
1633 }
1634
1635 // Traverse all variables and update firstItem / lastItem. This
1636 // function is called from iterator that scans items using forward
1637 // direction so we can use this knowledge to optimize the process.
1638 //
1639 // Same code is in X86CompilerInst::prepare().
1640 for (i = 0; i < _variablesCount; i++)
1641 {
1642 X86CompilerVar* v = _variables[i].vdata;
1643
1644 // First item (begin of variable scope).
1645 if (v->firstItem == NULL) v->firstItem = this;
1646
1647 // Last item (end of variable scope).
1648 v->lastItem = this;
1649 }
1650
1651 x86Context._currentOffset++;
1652
1653 #undef __GET_VARIABLE
1654 }
1655
translate(CompilerContext & cc)1656 CompilerItem* X86CompilerFuncCall::translate(CompilerContext& cc)
1657 {
1658 X86CompilerContext& x86Context = static_cast<X86CompilerContext&>(cc);
1659 X86Compiler* x86Compiler = x86Context.getCompiler();
1660
1661 uint32_t i;
1662 uint32_t preserved, mask;
1663
1664 uint32_t temporaryGpReg;
1665 uint32_t temporaryXmmReg;
1666
1667 uint32_t offset = x86Context._currentOffset;
1668
1669 // Constants.
1670 const FuncArg* targs = _x86Decl.getArguments();
1671
1672 uint32_t argumentsCount = _x86Decl.getArgumentsCount();
1673 uint32_t variablesCount = _variablesCount;
1674
1675 // Processed arguments kFuncArgsMax.
1676 uint8_t processed[kFuncArgsMax] = { 0 };
1677
1678 x86Compiler->comment("Call");
1679
1680 // These variables are used by the instruction so we set current offset
1681 // to their work offsets -> The getSpillCandidate() method never returns
1682 // the variable used by this instruction.
1683 for (i = 0; i < variablesCount; i++)
1684 {
1685 _variables[i].vdata->workOffset = offset;
1686
1687 // Init back-reference to VarCallRecord.
1688 _variables[i].vdata->tPtr = &_variables[i];
1689 }
1690
1691 // --------------------------------------------------------------------------
1692 // STEP 1:
1693 //
1694 // Spill variables which are not used by the function call and have to
1695 // be destroyed. These registers may be used by callee.
1696 // --------------------------------------------------------------------------
1697
1698 preserved = _x86Decl.getGpPreservedMask();
1699 for (i = 0, mask = 1; i < kX86RegNumGp; i++, mask <<= 1)
1700 {
1701 X86CompilerVar* cv = x86Context._x86State.gp[i];
1702 if (cv && cv->workOffset != offset && (preserved & mask) == 0)
1703 x86Context.spillGpVar(cv);
1704 }
1705
1706 preserved = _x86Decl.getMmPreservedMask();
1707 for (i = 0, mask = 1; i < kX86RegNumMm; i++, mask <<= 1)
1708 {
1709 X86CompilerVar* cv = x86Context._x86State.mm[i];
1710 if (cv && cv->workOffset != offset && (preserved & mask) == 0)
1711 x86Context.spillMmVar(cv);
1712 }
1713
1714 preserved = _x86Decl.getXmmPreservedMask();
1715 for (i = 0, mask = 1; i < kX86RegNumXmm; i++, mask <<= 1)
1716 {
1717 X86CompilerVar* cv = x86Context._x86State.xmm[i];
1718 if (cv && cv->workOffset != offset && (preserved & mask) == 0)
1719 x86Context.spillXmmVar(cv);
1720 }
1721
1722 // --------------------------------------------------------------------------
1723 // STEP 2:
1724 //
1725 // Move all arguments to the stack which all already in registers.
1726 // --------------------------------------------------------------------------
1727
1728 for (i = 0; i < argumentsCount; i++)
1729 {
1730 if (processed[i])
1731 continue;
1732
1733 const FuncArg& argType = targs[i];
1734 if (argType.hasRegIndex())
1735 continue;
1736
1737 Operand& operand = _args[i];
1738
1739 if (operand.isVar())
1740 {
1741 VarCallRecord* rec = _argumentToVarRecord[i];
1742 X86CompilerVar* cv = x86Compiler->_getVar(operand.getId());
1743
1744 if (cv->regIndex != kRegIndexInvalid)
1745 {
1746 _moveAllocatedVariableToStack(cc,
1747 cv, argType);
1748
1749 rec->inDone++;
1750 processed[i] = true;
1751 }
1752 }
1753 }
1754
1755 // --------------------------------------------------------------------------
1756 // STEP 3:
1757 //
1758 // Spill all non-preserved variables we moved to stack in STEP #2.
1759 // --------------------------------------------------------------------------
1760
1761 for (i = 0; i < argumentsCount; i++)
1762 {
1763 VarCallRecord* rec = _argumentToVarRecord[i];
1764 if (!rec || processed[i])
1765 continue;
1766
1767 if (rec->inDone >= rec->inCount)
1768 {
1769 X86CompilerVar* cv = rec->vdata;
1770 if (cv->regIndex == kRegIndexInvalid)
1771 continue;
1772
1773 if (rec->outCount)
1774 {
1775 // Variable will be rewritten by function return value, it's not needed
1776 // to spill it. It will be allocated again by X86CompilerFuncCall.
1777 x86Context.unuseVar(rec->vdata, kVarStateUnused);
1778 }
1779 else
1780 {
1781 switch (cv->getType())
1782 {
1783 case kX86VarTypeGpd:
1784 case kX86VarTypeGpq:
1785 if ((_x86Decl.getGpPreservedMask() & IntUtil::maskFromIndex(cv->regIndex)) == 0)
1786 x86Context.spillGpVar(cv);
1787 break;
1788 case kX86VarTypeMm:
1789 if ((_x86Decl.getMmPreservedMask() & IntUtil::maskFromIndex(cv->regIndex)) == 0)
1790 x86Context.spillMmVar(cv);
1791 break;
1792 case kX86VarTypeXmm:
1793 case kX86VarTypeXmmSS:
1794 case kX86VarTypeXmmSD:
1795 case kX86VarTypeXmmPS:
1796 case kX86VarTypeXmmPD:
1797 if ((_x86Decl.getXmmPreservedMask() & IntUtil::maskFromIndex(cv->regIndex)) == 0)
1798 x86Context.spillXmmVar(cv);
1799 break;
1800 }
1801 }
1802 }
1803 }
1804
1805 // --------------------------------------------------------------------------
1806 // STEP 4:
1807 //
1808 // Get temporary register that we can use to pass input function arguments.
1809 // Now it's safe to do, because the non-needed variables should be spilled.
1810 // --------------------------------------------------------------------------
1811
1812 temporaryGpReg = _findTemporaryGpRegister(cc);
1813 temporaryXmmReg = _findTemporaryXmmRegister(cc);
1814
1815 // If failed to get temporary register then we need just to pick one.
1816 if (temporaryGpReg == kRegIndexInvalid)
1817 {
1818 // TODO.
1819 }
1820 if (temporaryXmmReg == kRegIndexInvalid)
1821 {
1822 // TODO.
1823 }
1824
1825 // --------------------------------------------------------------------------
1826 // STEP 5:
1827 //
1828 // Move all remaining arguments to the stack (we can use temporary register).
1829 // or allocate it to the primary register. Also move immediates.
1830 // --------------------------------------------------------------------------
1831
1832 for (i = 0; i < argumentsCount; i++)
1833 {
1834 if (processed[i])
1835 continue;
1836
1837 const FuncArg& argType = targs[i];
1838
1839 if (argType.hasRegIndex())
1840 continue;
1841
1842 Operand& operand = _args[i];
1843
1844 if (operand.isVar())
1845 {
1846 VarCallRecord* rec = _argumentToVarRecord[i];
1847 X86CompilerVar* cv = x86Compiler->_getVar(operand.getId());
1848
1849 _moveSpilledVariableToStack(cc,
1850 cv, argType,
1851 temporaryGpReg, temporaryXmmReg);
1852
1853 rec->inDone++;
1854 processed[i] = true;
1855 }
1856 else if (operand.isImm())
1857 {
1858 // TODO.
1859 }
1860 }
1861
1862 // --------------------------------------------------------------------------
1863 // STEP 6:
1864 //
1865 // Allocate arguments to registers.
1866 // --------------------------------------------------------------------------
1867
1868 bool didWork;
1869
1870 do {
1871 didWork = false;
1872
1873 for (i = 0; i < argumentsCount; i++)
1874 {
1875 if (processed[i])
1876 continue;
1877
1878 VarCallRecord* rsrc = _argumentToVarRecord[i];
1879
1880 Operand& osrc = _args[i];
1881 ASMJIT_ASSERT(osrc.isVar());
1882 X86CompilerVar* vsrc = x86Compiler->_getVar(osrc.getId());
1883
1884 const FuncArg& srcArgType = targs[i];
1885 X86CompilerVar* vdst = _getOverlappingVariable(cc, srcArgType);
1886
1887 if (vsrc == vdst)
1888 {
1889 rsrc->inDone++;
1890 processed[i] = true;
1891
1892 didWork = true;
1893 continue;
1894 }
1895 else if (vdst != NULL)
1896 {
1897 VarCallRecord* rdst = reinterpret_cast<VarCallRecord*>(vdst->tPtr);
1898
1899 if (rdst == NULL)
1900 {
1901 x86Context.spillVar(vdst);
1902 vdst = NULL;
1903 }
1904 else if (rdst->inDone >= rdst->inCount && (rdst->flags & VarCallRecord::kFlagCallReg) == 0)
1905 {
1906 // Safe to spill.
1907 if (rdst->outCount || vdst->lastItem == this)
1908 x86Context.unuseVar(vdst, kVarStateUnused);
1909 else
1910 x86Context.spillVar(vdst);
1911 vdst = NULL;
1912 }
1913 else
1914 {
1915 uint32_t x = _x86Decl.findArgumentByRegCode(X86Util::getRegCodeFromVarType(vsrc->getType(), vsrc->regIndex));
1916 bool doSpill = true;
1917
1918 if ((vdst->getClass() & kX86VarClassGp) != 0)
1919 {
1920 // Try to emit mov to register which is possible for call() operand.
1921 if (x == kInvalidValue && (rdst->flags & VarCallRecord::kFlagCallReg) != 0)
1922 {
1923 uint32_t rIndex;
1924 uint32_t rBit;
1925
1926 // The mask which contains registers which are not-preserved
1927 // (these that might be clobbered by the callee) and which are
1928 // not used to pass function arguments. Each register contained
1929 // in this mask is ideal to be used by call() instruction.
1930 uint32_t possibleMask = (~_x86Decl.getGpPreservedMask()) &
1931 (~_x86Decl.getGpArgumentsMask()) &
1932 (IntUtil::maskUpToIndex(kX86RegNumGp));
1933
1934 if (possibleMask != 0)
1935 {
1936 for (rIndex = 0, rBit = 1; rIndex < kX86RegNumGp; rIndex++, rBit <<= 1)
1937 {
1938 if ((possibleMask & rBit) != 0)
1939 {
1940 if (x86Context._x86State.gp[rIndex] == NULL)
1941 {
1942 // This is the best possible solution, the register is
1943 // free. We do not need to continue with this loop, the
1944 // rIndex will be used by the call().
1945 break;
1946 }
1947 else
1948 {
1949 // Wait until the register is freed or try to find another.
1950 doSpill = false;
1951 didWork = true;
1952 }
1953 }
1954 }
1955 }
1956 else
1957 {
1958 // Try to find a register which is free and which is not used
1959 // to pass a function argument.
1960 possibleMask = _x86Decl.getGpPreservedMask();
1961
1962 for (rIndex = 0, rBit = 1; rIndex < kX86RegNumGp; rIndex++, rBit <<= 1)
1963 {
1964 if ((possibleMask & rBit) != 0)
1965 {
1966 // Found one.
1967 if (x86Context._x86State.gp[rIndex] == NULL) break;
1968 }
1969 }
1970 }
1971
1972 if (rIndex < kX86RegNumGp)
1973 {
1974 if (temporaryGpReg == vsrc->regIndex) temporaryGpReg = rIndex;
1975 x86Compiler->emit(kX86InstMov, gpz(rIndex), gpz(vsrc->regIndex));
1976
1977 x86Context._x86State.gp[vsrc->regIndex] = NULL;
1978 x86Context._x86State.gp[rIndex] = vsrc;
1979
1980 vsrc->regIndex = rIndex;
1981 x86Context._allocatedGpRegister(rIndex);
1982
1983 doSpill = false;
1984 didWork = true;
1985 }
1986 }
1987 // Emit xchg instead of spill/alloc if possible.
1988 else if (x != kInvalidValue)
1989 {
1990 const FuncArg& dstArgType = targs[x];
1991 if (X86Util::getVarClassFromVarType(dstArgType.getVarType()) == X86Util::getVarClassFromVarType(srcArgType.getVarType()))
1992 {
1993 uint32_t dstIndex = vdst->regIndex;
1994 uint32_t srcIndex = vsrc->regIndex;
1995
1996 if (srcIndex == dstArgType.getRegIndex())
1997 {
1998 #if defined(ASMJIT_X64)
1999 if (vdst->getType() != kX86VarTypeGpd || vsrc->getType() != kX86VarTypeGpd)
2000 x86Compiler->emit(kX86InstXchg, gpq(dstIndex), gpq(srcIndex));
2001 else
2002 #endif
2003 x86Compiler->emit(kX86InstXchg, gpd(dstIndex), gpd(srcIndex));
2004
2005 x86Context._x86State.gp[srcIndex] = vdst;
2006 x86Context._x86State.gp[dstIndex] = vsrc;
2007
2008 vdst->regIndex = srcIndex;
2009 vsrc->regIndex = dstIndex;
2010
2011 rdst->inDone++;
2012 rsrc->inDone++;
2013
2014 processed[i] = true;
2015 processed[x] = true;
2016
2017 doSpill = false;
2018 }
2019 }
2020 }
2021 }
2022
2023 if (doSpill)
2024 {
2025 x86Context.spillVar(vdst);
2026 vdst = NULL;
2027 }
2028 }
2029 }
2030
2031 if (vdst == NULL)
2032 {
2033 VarCallRecord* rec = reinterpret_cast<VarCallRecord*>(vsrc->tPtr);
2034
2035 _moveSrcVariableToRegister(cc, vsrc, srcArgType);
2036
2037 switch (srcArgType.getVarType())
2038 {
2039 case kX86VarTypeGpd:
2040 case kX86VarTypeGpq:
2041 x86Context._markGpRegisterModified(srcArgType.getRegIndex());
2042 break;
2043 case kX86VarTypeMm:
2044 x86Context._markMmRegisterModified(srcArgType.getRegIndex());
2045 break;
2046 case kX86VarTypeXmm:
2047 case kX86VarTypeXmmSS:
2048 case kX86VarTypeXmmSD:
2049 case kX86VarTypeXmmPS:
2050 case kX86VarTypeXmmPD:
2051 x86Context._markMmRegisterModified(srcArgType.getRegIndex());
2052 break;
2053 }
2054
2055 rec->inDone++;
2056 processed[i] = true;
2057 }
2058 }
2059 } while (didWork);
2060
2061 // --------------------------------------------------------------------------
2062 // STEP 7:
2063 //
2064 // Allocate operand used by CALL instruction.
2065 // --------------------------------------------------------------------------
2066
2067 for (i = 0; i < variablesCount; i++)
2068 {
2069 VarCallRecord& r = _variables[i];
2070 if ((r.flags & VarCallRecord::kFlagCallReg) &&
2071 (r.vdata->regIndex == kRegIndexInvalid))
2072 {
2073 // If the register is not allocated and the call form is 'call reg' then
2074 // it's possible to keep it in memory.
2075 if ((r.flags & VarCallRecord::kFlagCallMem) == 0)
2076 {
2077 _target = r.vdata->asGpVar().m();
2078 break;
2079 }
2080
2081 if (temporaryGpReg == kRegIndexInvalid)
2082 temporaryGpReg = _findTemporaryGpRegister(cc);
2083
2084 x86Context.allocGpVar(r.vdata,
2085 IntUtil::maskFromIndex(temporaryGpReg),
2086 kVarAllocRegister | kVarAllocRead);
2087 }
2088 }
2089
2090 x86Context.translateOperands(&_target, 1);
2091
2092 // --------------------------------------------------------------------------
2093 // STEP 8:
2094 //
2095 // Spill all preserved variables.
2096 // --------------------------------------------------------------------------
2097
2098 preserved = _x86Decl.getGpPreservedMask();
2099 for (i = 0, mask = 1; i < kX86RegNumGp; i++, mask <<= 1)
2100 {
2101 X86CompilerVar* vdata = x86Context._x86State.gp[i];
2102 if (vdata && (preserved & mask) == 0)
2103 {
2104 VarCallRecord* rec = reinterpret_cast<VarCallRecord*>(vdata->tPtr);
2105 if (rec && (rec->outCount || rec->flags & VarCallRecord::kFlagUnuseAfterUse || vdata->lastItem == this))
2106 x86Context.unuseVar(vdata, kVarStateUnused);
2107 else
2108 x86Context.spillGpVar(vdata);
2109 }
2110 }
2111
2112 preserved = _x86Decl.getMmPreservedMask();
2113 for (i = 0, mask = 1; i < kX86RegNumMm; i++, mask <<= 1)
2114 {
2115 X86CompilerVar* vdata = x86Context._x86State.mm[i];
2116 if (vdata && (preserved & mask) == 0)
2117 {
2118 VarCallRecord* rec = reinterpret_cast<VarCallRecord*>(vdata->tPtr);
2119 if (rec && (rec->outCount || vdata->lastItem == this))
2120 x86Context.unuseVar(vdata, kVarStateUnused);
2121 else
2122 x86Context.spillMmVar(vdata);
2123 }
2124 }
2125
2126 preserved = _x86Decl.getXmmPreservedMask();
2127 for (i = 0, mask = 1; i < kX86RegNumXmm; i++, mask <<= 1)
2128 {
2129 X86CompilerVar* vdata = x86Context._x86State.xmm[i];
2130 if (vdata && (preserved & mask) == 0)
2131 {
2132 VarCallRecord* rec = reinterpret_cast<VarCallRecord*>(vdata->tPtr);
2133 if (rec && (rec->outCount || vdata->lastItem == this))
2134 x86Context.unuseVar(vdata, kVarStateUnused);
2135 else
2136 x86Context.spillXmmVar(vdata);
2137 }
2138 }
2139
2140 // --------------------------------------------------------------------------
2141 // STEP 9:
2142 //
2143 // Emit CALL instruction.
2144 // --------------------------------------------------------------------------
2145
2146 x86Compiler->emit(kX86InstCall, _target);
2147
2148 // Restore the stack offset.
2149 if (_x86Decl.getCalleePopsStack())
2150 {
2151 int32_t s = static_cast<int32_t>(_x86Decl.getArgumentsStackSize());
2152
2153 if (s != 0)
2154 x86Compiler->emit(kX86InstSub, zsp, imm(s));
2155 }
2156
2157 // --------------------------------------------------------------------------
2158 // STEP 10:
2159 //
2160 // Prepare others for return value(s) and cleanup.
2161 // --------------------------------------------------------------------------
2162
2163 // Clear temp data, see AsmJit::X86CompilerVar::temp why it's needed.
2164 for (i = 0; i < variablesCount; i++)
2165 {
2166 VarCallRecord* rec = &_variables[i];
2167 X86CompilerVar* vdata = rec->vdata;
2168
2169 if (rec->flags & (VarCallRecord::kFlagOutEax | VarCallRecord::kFlagOutEdx))
2170 {
2171 if (vdata->getClass() & kX86VarClassGp)
2172 {
2173 x86Context.allocGpVar(vdata,
2174 IntUtil::maskFromIndex((rec->flags & VarCallRecord::kFlagOutEax) != 0
2175 ? kX86RegIndexEax
2176 : kX86RegIndexEdx),
2177 kVarAllocRegister | kVarAllocWrite);
2178 vdata->changed = true;
2179 }
2180 }
2181
2182 if (rec->flags & (VarCallRecord::kFlagOutMm0))
2183 {
2184 if (vdata->getClass() & kX86VarClassMm)
2185 {
2186 x86Context.allocMmVar(vdata, IntUtil::maskFromIndex(kX86RegIndexMm0),
2187 kVarAllocRegister | kVarAllocWrite);
2188 vdata->changed = true;
2189 }
2190 }
2191
2192 if (rec->flags & (VarCallRecord::kFlagOutXmm0 | VarCallRecord::kFlagOutXmm1))
2193 {
2194 if (vdata->getClass() & kX86VarClassXmm)
2195 {
2196 x86Context.allocXmmVar(vdata,
2197 IntUtil::maskFromIndex((rec->flags & VarCallRecord::kFlagOutXmm0) != 0
2198 ? kX86RegIndexXmm0
2199 : kX86RegIndexXmm1),
2200 kVarAllocRegister | kVarAllocWrite);
2201 vdata->changed = true;
2202 }
2203 }
2204
2205 if (rec->flags & (VarCallRecord::kFlagOutSt0 | VarCallRecord::kFlagOutSt1))
2206 {
2207 if (vdata->getClass() & kX86VarClassXmm)
2208 {
2209 Mem mem(x86Context._getVarMem(vdata));
2210 x86Context.unuseVar(vdata, kVarStateMem);
2211
2212 switch (vdata->getType())
2213 {
2214 case kX86VarTypeXmmSS:
2215 case kX86VarTypeXmmPS:
2216 {
2217 mem.setSize(4);
2218 x86Compiler->emit(kX86InstFStP, mem);
2219 break;
2220 }
2221 case kX86VarTypeXmmSD:
2222 case kX86VarTypeXmmPD:
2223 {
2224 mem.setSize(8);
2225 x86Compiler->emit(kX86InstFStP, mem);
2226 break;
2227 }
2228 default:
2229 {
2230 x86Compiler->comment("*** WARNING: Can't convert float return value to untyped XMM\n");
2231 break;
2232 }
2233 }
2234 }
2235 }
2236
2237 // Cleanup.
2238 vdata->tPtr = NULL;
2239 }
2240
2241 for (i = 0; i < variablesCount; i++)
2242 {
2243 x86Context._unuseVarOnEndOfScope(this, &_variables[i]);
2244 }
2245
2246 return translated();
2247 }
2248
2249 // ============================================================================
2250 // [AsmJit::X86CompilerFuncCall - Misc]
2251 // ============================================================================
2252
getMaxSize() const2253 int X86CompilerFuncCall::getMaxSize() const
2254 {
2255 // TODO: Instruction max size.
2256 return 15;
2257 }
2258
_tryUnuseVar(CompilerVar * _v)2259 bool X86CompilerFuncCall::_tryUnuseVar(CompilerVar* _v)
2260 {
2261 X86CompilerVar* cv = static_cast<X86CompilerVar*>(_v);
2262
2263 for (uint32_t i = 0; i < _variablesCount; i++)
2264 {
2265 if (_variables[i].vdata == cv)
2266 {
2267 _variables[i].flags |= VarCallRecord::kFlagUnuseAfterUse;
2268 return true;
2269 }
2270 }
2271
2272 return false;
2273 }
2274
2275 // ============================================================================
2276 // [AsmJit::X86CompilerFuncCall - Helpers]
2277 // ============================================================================
2278
_findTemporaryGpRegister(CompilerContext & cc)2279 uint32_t X86CompilerFuncCall::_findTemporaryGpRegister(CompilerContext& cc)
2280 {
2281 X86CompilerContext& x86Context = static_cast<X86CompilerContext&>(cc);
2282
2283 uint32_t i;
2284 uint32_t mask;
2285
2286 uint32_t passedGP = _x86Decl.getGpArgumentsMask();
2287 uint32_t candidate = kRegIndexInvalid;
2288
2289 // Find all registers used to pass function arguments. We shouldn't use these
2290 // if possible.
2291 for (i = 0, mask = 1; i < kX86RegNumGp; i++, mask <<= 1)
2292 {
2293 if (x86Context._x86State.gp[i] == NULL)
2294 {
2295 // If this register is used to pass arguments to function, we will mark
2296 // it and use it only if there is no other one.
2297 if ((passedGP & mask) != 0)
2298 candidate = i;
2299 else
2300 return i;
2301 }
2302 }
2303
2304 return candidate;
2305 }
2306
_findTemporaryXmmRegister(CompilerContext & cc)2307 uint32_t X86CompilerFuncCall::_findTemporaryXmmRegister(CompilerContext& cc)
2308 {
2309 X86CompilerContext& x86Context = static_cast<X86CompilerContext&>(cc);
2310
2311 uint32_t i;
2312 uint32_t mask;
2313
2314 uint32_t passedXMM = _x86Decl.getXmmArgumentsMask();
2315 uint32_t candidate = kRegIndexInvalid;
2316
2317 // Find all registers used to pass function arguments. We shouldn't use these
2318 // if possible.
2319 for (i = 0, mask = 1; i < kX86RegNumXmm; i++, mask <<= 1)
2320 {
2321 if (x86Context._x86State.xmm[i] == NULL)
2322 {
2323 // If this register is used to pass arguments to function, we will mark
2324 // it and use it only if there is no other one.
2325 if ((passedXMM & mask) != 0)
2326 candidate = i;
2327 else
2328 return i;
2329 }
2330 }
2331
2332 return candidate;
2333 }
2334
_getOverlappingVariable(CompilerContext & cc,const FuncArg & argType) const2335 X86CompilerVar* X86CompilerFuncCall::_getOverlappingVariable(CompilerContext& cc, const FuncArg& argType) const
2336 {
2337 X86CompilerContext& x86Context = static_cast<X86CompilerContext&>(cc);
2338 ASMJIT_ASSERT(argType.getVarType() != kVarTypeInvalid);
2339
2340 switch (argType.getVarType())
2341 {
2342 case kX86VarTypeGpd:
2343 case kX86VarTypeGpq:
2344 return x86Context._x86State.gp[argType.getRegIndex()];
2345 case kX86VarTypeMm:
2346 return x86Context._x86State.mm[argType.getRegIndex()];
2347 case kX86VarTypeXmm:
2348 case kX86VarTypeXmmSS:
2349 case kX86VarTypeXmmSD:
2350 case kX86VarTypeXmmPS:
2351 case kX86VarTypeXmmPD:
2352 return x86Context._x86State.xmm[argType.getRegIndex()];
2353 }
2354
2355 return NULL;
2356 }
2357
_moveAllocatedVariableToStack(CompilerContext & cc,X86CompilerVar * vdata,const FuncArg & argType)2358 void X86CompilerFuncCall::_moveAllocatedVariableToStack(CompilerContext& cc, X86CompilerVar* vdata, const FuncArg& argType)
2359 {
2360 X86CompilerContext& x86Context = static_cast<X86CompilerContext&>(cc);
2361 X86Compiler* x86Compiler = x86Context.getCompiler();
2362
2363 ASMJIT_ASSERT(!argType.hasRegIndex());
2364 ASMJIT_ASSERT(vdata->regIndex != kRegIndexInvalid);
2365
2366 uint32_t src = vdata->regIndex;
2367 Mem dst = ptr(zsp, -(int)sizeof(uintptr_t) + argType.getStackOffset());
2368
2369 switch (vdata->getType())
2370 {
2371 case kX86VarTypeGpd:
2372 switch (argType.getVarType())
2373 {
2374 case kX86VarTypeGpd:
2375 x86Compiler->emit(kX86InstMov, dst, gpd(src));
2376 return;
2377 #if defined(ASMJIT_X64)
2378 case kX86VarTypeGpq:
2379 case kX86VarTypeMm:
2380 x86Compiler->emit(kX86InstMov, dst, gpq(src));
2381 return;
2382 #endif // ASMJIT_X64
2383 }
2384 break;
2385
2386 #if defined(ASMJIT_X64)
2387 case kX86VarTypeGpq:
2388 switch (argType.getVarType())
2389 {
2390 case kX86VarTypeGpd:
2391 x86Compiler->emit(kX86InstMov, dst, gpd(src));
2392 return;
2393 case kX86VarTypeGpq:
2394 x86Compiler->emit(kX86InstMov, dst, gpq(src));
2395 return;
2396 case kX86VarTypeMm:
2397 x86Compiler->emit(kX86InstMovQ, dst, gpq(src));
2398 return;
2399 }
2400 break;
2401 #endif // ASMJIT_X64
2402
2403 case kX86VarTypeMm:
2404 switch (argType.getVarType())
2405 {
2406 case kX86VarTypeGpd:
2407 case kX86VarTypeX87SS:
2408 case kX86VarTypeXmmSS:
2409 x86Compiler->emit(kX86InstMovD, dst, mm(src));
2410 return;
2411 case kX86VarTypeGpq:
2412 case kX86VarTypeMm:
2413 case kX86VarTypeX87SD:
2414 case kX86VarTypeXmmSD:
2415 x86Compiler->emit(kX86InstMovQ, dst, mm(src));
2416 return;
2417 }
2418 break;
2419
2420 // We allow incompatible types here, because the called can convert them
2421 // to correct format before function is called.
2422
2423 case kX86VarTypeXmm:
2424 case kX86VarTypeXmmPS:
2425 case kX86VarTypeXmmPD:
2426 switch (argType.getVarType())
2427 {
2428 case kX86VarTypeXmm:
2429 x86Compiler->emit(kX86InstMovDQU, dst, xmm(src));
2430 return;
2431 case kX86VarTypeXmmSS:
2432 case kX86VarTypeXmmPS:
2433 x86Compiler->emit(kX86InstMovUPS, dst, xmm(src));
2434 return;
2435 case kX86VarTypeXmmSD:
2436 case kX86VarTypeXmmPD:
2437 x86Compiler->emit(kX86InstMovUPD, dst, xmm(src));
2438 return;
2439 }
2440 break;
2441
2442 case kX86VarTypeXmmSS:
2443 switch (argType.getVarType())
2444 {
2445 case kX86VarTypeX87SS:
2446 case kX86VarTypeXmm:
2447 case kX86VarTypeXmmSS:
2448 case kX86VarTypeXmmPS:
2449 case kX86VarTypeXmmSD:
2450 case kX86VarTypeXmmPD:
2451 x86Compiler->emit(kX86InstMovSS, dst, xmm(src));
2452 return;
2453 }
2454 break;
2455
2456 case kX86VarTypeXmmSD:
2457 switch (argType.getVarType())
2458 {
2459 case kX86VarTypeX87SD:
2460 case kX86VarTypeXmm:
2461 case kX86VarTypeXmmSS:
2462 case kX86VarTypeXmmPS:
2463 case kX86VarTypeXmmSD:
2464 case kX86VarTypeXmmPD:
2465 x86Compiler->emit(kX86InstMovSD, dst, xmm(src));
2466 return;
2467 }
2468 break;
2469 }
2470
2471 x86Compiler->setError(kErrorIncompatibleArgumentType);
2472 }
2473
_moveSpilledVariableToStack(CompilerContext & cc,X86CompilerVar * cv,const FuncArg & argType,uint32_t temporaryGpReg,uint32_t temporaryXmmReg)2474 void X86CompilerFuncCall::_moveSpilledVariableToStack(CompilerContext& cc,
2475 X86CompilerVar* cv, const FuncArg& argType,
2476 uint32_t temporaryGpReg,
2477 uint32_t temporaryXmmReg)
2478 {
2479 X86CompilerContext& x86Context = static_cast<X86CompilerContext&>(cc);
2480 X86Compiler* x86Compiler = x86Context.getCompiler();
2481
2482 ASMJIT_ASSERT(!argType.hasRegIndex());
2483 ASMJIT_ASSERT(cv->regIndex == kRegIndexInvalid);
2484
2485 Mem src = x86Context._getVarMem(cv);
2486 Mem dst = ptr(zsp, -(int)sizeof(sysint_t) + argType.getStackOffset());
2487
2488 switch (cv->getType())
2489 {
2490 case kX86VarTypeGpd:
2491 switch (argType.getVarType())
2492 {
2493 case kX86VarTypeGpd:
2494 x86Compiler->emit(kX86InstMov, gpd(temporaryGpReg), src);
2495 x86Compiler->emit(kX86InstMov, dst, gpd(temporaryGpReg));
2496 return;
2497 #if defined(ASMJIT_X64)
2498 case kX86VarTypeGpq:
2499 case kX86VarTypeMm:
2500 x86Compiler->emit(kX86InstMov, gpd(temporaryGpReg), src);
2501 x86Compiler->emit(kX86InstMov, dst, gpq(temporaryGpReg));
2502 return;
2503 #endif // ASMJIT_X64
2504 }
2505 break;
2506
2507 #if defined(ASMJIT_X64)
2508 case kX86VarTypeGpq:
2509 switch (argType.getVarType())
2510 {
2511 case kX86VarTypeGpd:
2512 x86Compiler->emit(kX86InstMov, gpd(temporaryGpReg), src);
2513 x86Compiler->emit(kX86InstMov, dst, gpd(temporaryGpReg));
2514 return;
2515 case kX86VarTypeGpq:
2516 case kX86VarTypeMm:
2517 x86Compiler->emit(kX86InstMov, gpq(temporaryGpReg), src);
2518 x86Compiler->emit(kX86InstMov, dst, gpq(temporaryGpReg));
2519 return;
2520 }
2521 break;
2522 #endif // ASMJIT_X64
2523
2524 case kX86VarTypeMm:
2525 switch (argType.getVarType())
2526 {
2527 case kX86VarTypeGpd:
2528 case kX86VarTypeX87SS:
2529 case kX86VarTypeXmmSS:
2530 x86Compiler->emit(kX86InstMov, gpd(temporaryGpReg), src);
2531 x86Compiler->emit(kX86InstMov, dst, gpd(temporaryGpReg));
2532 return;
2533 case kX86VarTypeGpq:
2534 case kX86VarTypeMm:
2535 case kX86VarTypeX87SD:
2536 case kX86VarTypeXmmSD:
2537 // TODO
2538 return;
2539 }
2540 break;
2541
2542 // We allow incompatible types here, because the caller can convert them
2543 // to correct format before function is called.
2544
2545 case kX86VarTypeXmm:
2546 case kX86VarTypeXmmPS:
2547 case kX86VarTypeXmmPD:
2548 switch (argType.getVarType())
2549 {
2550 case kX86VarTypeXmm:
2551 x86Compiler->emit(kX86InstMovDQU, xmm(temporaryXmmReg), src);
2552 x86Compiler->emit(kX86InstMovDQU, dst, xmm(temporaryXmmReg));
2553 return;
2554 case kX86VarTypeXmmSS:
2555 case kX86VarTypeXmmPS:
2556 x86Compiler->emit(kX86InstMovUPS, xmm(temporaryXmmReg), src);
2557 x86Compiler->emit(kX86InstMovUPS, dst, xmm(temporaryXmmReg));
2558 return;
2559 case kX86VarTypeXmmSD:
2560 case kX86VarTypeXmmPD:
2561 x86Compiler->emit(kX86InstMovUPD, xmm(temporaryXmmReg), src);
2562 x86Compiler->emit(kX86InstMovUPD, dst, xmm(temporaryXmmReg));
2563 return;
2564 }
2565 break;
2566
2567 case kX86VarTypeXmmSS:
2568 switch (argType.getVarType())
2569 {
2570 case kX86VarTypeX87SS:
2571 case kX86VarTypeXmm:
2572 case kX86VarTypeXmmSS:
2573 case kX86VarTypeXmmPS:
2574 case kX86VarTypeXmmSD:
2575 case kX86VarTypeXmmPD:
2576 x86Compiler->emit(kX86InstMovSS, xmm(temporaryXmmReg), src);
2577 x86Compiler->emit(kX86InstMovSS, dst, xmm(temporaryXmmReg));
2578 return;
2579 }
2580 break;
2581
2582 case kX86VarTypeXmmSD:
2583 switch (argType.getVarType())
2584 {
2585 case kX86VarTypeX87SD:
2586 case kX86VarTypeXmm:
2587 case kX86VarTypeXmmSS:
2588 case kX86VarTypeXmmPS:
2589 case kX86VarTypeXmmSD:
2590 case kX86VarTypeXmmPD:
2591 x86Compiler->emit(kX86InstMovSD, xmm(temporaryXmmReg), src);
2592 x86Compiler->emit(kX86InstMovSD, dst, xmm(temporaryXmmReg));
2593 return;
2594 }
2595 break;
2596 }
2597
2598 x86Compiler->setError(kErrorIncompatibleArgumentType);
2599 }
2600
_moveSrcVariableToRegister(CompilerContext & cc,X86CompilerVar * cv,const FuncArg & argType)2601 void X86CompilerFuncCall::_moveSrcVariableToRegister(CompilerContext& cc,
2602 X86CompilerVar* cv, const FuncArg& argType)
2603 {
2604 X86CompilerContext& x86Context = static_cast<X86CompilerContext&>(cc);
2605 X86Compiler* x86Compiler = x86Context.getCompiler();
2606
2607 uint32_t dst = argType.getRegIndex();
2608 uint32_t src = cv->regIndex;
2609
2610 if (src != kRegIndexInvalid)
2611 {
2612 switch (argType.getVarType())
2613 {
2614 case kX86VarTypeGpd:
2615 switch (cv->getType())
2616 {
2617 case kX86VarTypeGpd:
2618 #if defined(ASMJIT_X64)
2619 case kX86VarTypeGpq:
2620 #endif // ASMJIT_X64
2621 x86Compiler->emit(kX86InstMov, gpd(dst), gpd(src));
2622 return;
2623 case kX86VarTypeMm:
2624 x86Compiler->emit(kX86InstMovD, gpd(dst), mm(src));
2625 return;
2626 }
2627 break;
2628
2629 #if defined(ASMJIT_X64)
2630 case kX86VarTypeGpq:
2631 switch (cv->getType())
2632 {
2633 case kX86VarTypeGpd:
2634 x86Compiler->emit(kX86InstMov, gpd(dst), gpd(src));
2635 return;
2636 case kX86VarTypeGpq:
2637 x86Compiler->emit(kX86InstMov, gpq(dst), gpq(src));
2638 return;
2639 case kX86VarTypeMm:
2640 x86Compiler->emit(kX86InstMovQ, gpq(dst), mm(src));
2641 return;
2642 }
2643 break;
2644 #endif // ASMJIT_X64
2645
2646 case kX86VarTypeMm:
2647 switch (cv->getType())
2648 {
2649 case kX86VarTypeGpd:
2650 x86Compiler->emit(kX86InstMovD, gpd(dst), gpd(src));
2651 return;
2652 #if defined(ASMJIT_X64)
2653 case kX86VarTypeGpq:
2654 x86Compiler->emit(kX86InstMovQ, gpq(dst), gpq(src));
2655 return;
2656 #endif // ASMJIT_X64
2657 case kX86VarTypeMm:
2658 x86Compiler->emit(kX86InstMovQ, mm(dst), mm(src));
2659 return;
2660 }
2661 break;
2662
2663 case kX86VarTypeXmm:
2664 case kX86VarTypeXmmPS:
2665 case kX86VarTypeXmmPD:
2666 switch (cv->getType())
2667 {
2668 case kX86VarTypeGpd:
2669 x86Compiler->emit(kX86InstMovD, xmm(dst), gpd(src));
2670 return;
2671 #if defined(ASMJIT_X64)
2672 case kX86VarTypeGpq:
2673 x86Compiler->emit(kX86InstMovQ, xmm(dst), gpq(src));
2674 return;
2675 #endif // ASMJIT_X64
2676 case kX86VarTypeMm:
2677 x86Compiler->emit(kX86InstMovQ, xmm(dst), mm(src));
2678 return;
2679 case kX86VarTypeXmm:
2680 case kX86VarTypeXmmSS:
2681 case kX86VarTypeXmmPS:
2682 case kX86VarTypeXmmSD:
2683 case kX86VarTypeXmmPD:
2684 x86Compiler->emit(kX86InstMovDQA, xmm(dst), xmm(src));
2685 return;
2686 }
2687 break;
2688
2689 case kX86VarTypeXmmSS:
2690 switch (cv->getType())
2691 {
2692 case kX86VarTypeMm:
2693 x86Compiler->emit(kX86InstMovQ, xmm(dst), mm(src));
2694 return;
2695
2696 case kX86VarTypeXmm:
2697 x86Compiler->emit(kX86InstMovDQA, xmm(dst), xmm(src));
2698 return;
2699 case kX86VarTypeXmmSS:
2700 case kX86VarTypeXmmPS:
2701 x86Compiler->emit(kX86InstMovSS, xmm(dst), xmm(src));
2702 return;
2703 case kX86VarTypeXmmSD:
2704 case kX86VarTypeXmmPD:
2705 x86Compiler->emit(kX86InstCvtSD2SS, xmm(dst), xmm(src));
2706 return;
2707 }
2708 break;
2709
2710 case kX86VarTypeXmmSD:
2711 switch (cv->getType())
2712 {
2713 case kX86VarTypeMm:
2714 x86Compiler->emit(kX86InstMovQ, xmm(dst), mm(src));
2715 return;
2716
2717 case kX86VarTypeXmm:
2718 x86Compiler->emit(kX86InstMovDQA, xmm(dst), xmm(src));
2719 return;
2720 case kX86VarTypeXmmSS:
2721 case kX86VarTypeXmmPS:
2722 x86Compiler->emit(kX86InstCvtSS2SD, xmm(dst), xmm(src));
2723 return;
2724 case kX86VarTypeXmmSD:
2725 case kX86VarTypeXmmPD:
2726 x86Compiler->emit(kX86InstMovSD, xmm(dst), xmm(src));
2727 return;
2728 }
2729 break;
2730 }
2731 }
2732 else
2733 {
2734 Mem mem = x86Context._getVarMem(cv);
2735
2736 switch (argType.getVarType())
2737 {
2738 case kX86VarTypeGpd:
2739 switch (cv->getType())
2740 {
2741 case kX86VarTypeGpd:
2742 #if defined(ASMJIT_X64)
2743 case kX86VarTypeGpq:
2744 #endif // ASMJIT_X64
2745 x86Compiler->emit(kX86InstMov, gpd(dst), mem);
2746 return;
2747 case kX86VarTypeMm:
2748 x86Compiler->emit(kX86InstMovD, gpd(dst), mem);
2749 return;
2750 }
2751 break;
2752
2753 #if defined(ASMJIT_X64)
2754 case kX86VarTypeGpq:
2755 switch (cv->getType())
2756 {
2757 case kX86VarTypeGpd:
2758 x86Compiler->emit(kX86InstMov, gpd(dst), mem);
2759 return;
2760 case kX86VarTypeGpq:
2761 x86Compiler->emit(kX86InstMov, gpq(dst), mem);
2762 return;
2763 case kX86VarTypeMm:
2764 x86Compiler->emit(kX86InstMovQ, gpq(dst), mem);
2765 return;
2766 }
2767 break;
2768 #endif // ASMJIT_X64
2769
2770 case kX86VarTypeMm:
2771 switch (cv->getType())
2772 {
2773 case kX86VarTypeGpd:
2774 x86Compiler->emit(kX86InstMovD, gpd(dst), mem);
2775 return;
2776 #if defined(ASMJIT_X64)
2777 case kX86VarTypeGpq:
2778 x86Compiler->emit(kX86InstMovQ, gpq(dst), mem);
2779 return;
2780 #endif // ASMJIT_X64
2781 case kX86VarTypeMm:
2782 x86Compiler->emit(kX86InstMovQ, mm(dst), mem);
2783 return;
2784 }
2785 break;
2786
2787 case kX86VarTypeXmm:
2788 case kX86VarTypeXmmPS:
2789 case kX86VarTypeXmmPD:
2790 switch (cv->getType())
2791 {
2792 case kX86VarTypeGpd:
2793 x86Compiler->emit(kX86InstMovD, xmm(dst), mem);
2794 return;
2795 #if defined(ASMJIT_X64)
2796 case kX86VarTypeGpq:
2797 x86Compiler->emit(kX86InstMovQ, xmm(dst), mem);
2798 return;
2799 #endif // ASMJIT_X64
2800 case kX86VarTypeMm:
2801 x86Compiler->emit(kX86InstMovQ, xmm(dst), mem);
2802 return;
2803 case kX86VarTypeXmm:
2804 case kX86VarTypeXmmSS:
2805 case kX86VarTypeXmmPS:
2806 case kX86VarTypeXmmSD:
2807 case kX86VarTypeXmmPD:
2808 x86Compiler->emit(kX86InstMovDQA, xmm(dst), mem);
2809 return;
2810 }
2811 break;
2812
2813 case kX86VarTypeXmmSS:
2814 switch (cv->getType())
2815 {
2816 case kX86VarTypeMm:
2817 x86Compiler->emit(kX86InstMovQ, xmm(dst), mem);
2818 return;
2819
2820 case kX86VarTypeXmm:
2821 x86Compiler->emit(kX86InstMovDQA, xmm(dst), mem);
2822 return;
2823 case kX86VarTypeXmmSS:
2824 case kX86VarTypeXmmPS:
2825 x86Compiler->emit(kX86InstMovSS, xmm(dst), mem);
2826 return;
2827 case kX86VarTypeXmmSD:
2828 case kX86VarTypeXmmPD:
2829 x86Compiler->emit(kX86InstCvtSD2SS, xmm(dst), mem);
2830 return;
2831 }
2832 break;
2833
2834 case kX86VarTypeXmmSD:
2835 switch (cv->getType())
2836 {
2837 case kX86VarTypeMm:
2838 x86Compiler->emit(kX86InstMovQ, xmm(dst), mem);
2839 return;
2840
2841 case kX86VarTypeXmm:
2842 x86Compiler->emit(kX86InstMovDQA, xmm(dst), mem);
2843 return;
2844 case kX86VarTypeXmmSS:
2845 case kX86VarTypeXmmPS:
2846 x86Compiler->emit(kX86InstCvtSS2SD, xmm(dst), mem);
2847 return;
2848 case kX86VarTypeXmmSD:
2849 case kX86VarTypeXmmPD:
2850 x86Compiler->emit(kX86InstMovSD, xmm(dst), mem);
2851 return;
2852 }
2853 break;
2854 }
2855 }
2856
2857 x86Compiler->setError(kErrorIncompatibleArgumentType);
2858 }
2859
2860 // Prototype & Arguments Management.
setPrototype(uint32_t callingConvention,uint32_t returnType,const uint32_t * arguments,uint32_t argumentsCount)2861 void X86CompilerFuncCall::setPrototype(uint32_t callingConvention, uint32_t returnType, const uint32_t* arguments, uint32_t argumentsCount)
2862 {
2863 _x86Decl.setPrototype(callingConvention, returnType, arguments, argumentsCount);
2864 _args = reinterpret_cast<Operand*>(
2865 getCompiler()->getZoneMemory().alloc(sizeof(Operand) * argumentsCount));
2866 memset(_args, 0, sizeof(Operand) * argumentsCount);
2867 }
2868
setArgument(uint32_t i,const Var & var)2869 bool X86CompilerFuncCall::setArgument(uint32_t i, const Var& var)
2870 {
2871 ASMJIT_ASSERT(i < _x86Decl.getArgumentsCount());
2872
2873 if (i >= _x86Decl.getArgumentsCount())
2874 return false;
2875
2876 _args[i] = var;
2877 return true;
2878 }
2879
setArgument(uint32_t i,const Imm & imm)2880 bool X86CompilerFuncCall::setArgument(uint32_t i, const Imm& imm)
2881 {
2882 ASMJIT_ASSERT(i < _x86Decl.getArgumentsCount());
2883
2884 if (i >= _x86Decl.getArgumentsCount())
2885 return false;
2886
2887 _args[i] = imm;
2888 return true;
2889 }
2890
setReturn(const Operand & first,const Operand & second)2891 bool X86CompilerFuncCall::setReturn(const Operand& first, const Operand& second)
2892 {
2893 _ret[0] = first;
2894 _ret[1] = second;
2895
2896 return true;
2897 }
2898
2899 } // AsmJit namespace
2900
2901 // [Api-End]
2902 #include "../core/apiend.h"
2903