summaryrefslogtreecommitdiff
path: root/src/common/x64/abi.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/x64/abi.cpp')
-rw-r--r--src/common/x64/abi.cpp411
1 files changed, 47 insertions, 364 deletions
diff --git a/src/common/x64/abi.cpp b/src/common/x64/abi.cpp
index 4c07a6ebe..955eb86ce 100644
--- a/src/common/x64/abi.cpp
+++ b/src/common/x64/abi.cpp
@@ -22,247 +22,69 @@ using namespace Gen;
22 22
23// Shared code between Win64 and Unix64 23// Shared code between Win64 and Unix64
24 24
25// Sets up a __cdecl function. 25void XEmitter::ABI_CalculateFrameSize(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size, size_t* shadowp, size_t* subtractionp, size_t* xmm_offsetp) {
26void XEmitter::ABI_EmitPrologue(int maxCallParams) 26 size_t shadow = 0;
27{ 27#if defined(_WIN32)
28#ifdef _M_IX86 28 shadow = 0x20;
29 // Don't really need to do anything
30#elif defined(ARCHITECTURE_x86_64)
31#if _WIN32
32 int stacksize = ((maxCallParams + 1) & ~1) * 8 + 8;
33 // Set up a stack frame so that we can call functions
34 // TODO: use maxCallParams
35 SUB(64, R(RSP), Imm8(stacksize));
36#endif
37#else
38#error Arch not supported
39#endif 29#endif
40}
41
42void XEmitter::ABI_EmitEpilogue(int maxCallParams)
43{
44#ifdef _M_IX86
45 RET();
46#elif defined(ARCHITECTURE_x86_64)
47#ifdef _WIN32
48 int stacksize = ((maxCallParams+1)&~1)*8 + 8;
49 ADD(64, R(RSP), Imm8(stacksize));
50#endif
51 RET();
52#else
53#error Arch not supported
54
55
56#endif
57}
58
59#ifdef _M_IX86 // All32
60
61// Shared code between Win32 and Unix32
62void XEmitter::ABI_CallFunction(const void *func) {
63 ABI_AlignStack(0);
64 CALL(func);
65 ABI_RestoreStack(0);
66}
67
68void XEmitter::ABI_CallFunctionC16(const void *func, u16 param1) {
69 ABI_AlignStack(1 * 2);
70 PUSH(16, Imm16(param1));
71 CALL(func);
72 ABI_RestoreStack(1 * 2);
73}
74
75void XEmitter::ABI_CallFunctionCC16(const void *func, u32 param1, u16 param2) {
76 ABI_AlignStack(1 * 2 + 1 * 4);
77 PUSH(16, Imm16(param2));
78 PUSH(32, Imm32(param1));
79 CALL(func);
80 ABI_RestoreStack(1 * 2 + 1 * 4);
81}
82
83void XEmitter::ABI_CallFunctionC(const void *func, u32 param1) {
84 ABI_AlignStack(1 * 4);
85 PUSH(32, Imm32(param1));
86 CALL(func);
87 ABI_RestoreStack(1 * 4);
88}
89
90void XEmitter::ABI_CallFunctionCC(const void *func, u32 param1, u32 param2) {
91 ABI_AlignStack(2 * 4);
92 PUSH(32, Imm32(param2));
93 PUSH(32, Imm32(param1));
94 CALL(func);
95 ABI_RestoreStack(2 * 4);
96}
97
98void XEmitter::ABI_CallFunctionCCC(const void *func, u32 param1, u32 param2, u32 param3) {
99 ABI_AlignStack(3 * 4);
100 PUSH(32, Imm32(param3));
101 PUSH(32, Imm32(param2));
102 PUSH(32, Imm32(param1));
103 CALL(func);
104 ABI_RestoreStack(3 * 4);
105}
106
107void XEmitter::ABI_CallFunctionCCP(const void *func, u32 param1, u32 param2, void *param3) {
108 ABI_AlignStack(3 * 4);
109 PUSH(32, ImmPtr(param3));
110 PUSH(32, Imm32(param2));
111 PUSH(32, Imm32(param1));
112 CALL(func);
113 ABI_RestoreStack(3 * 4);
114}
115
116void XEmitter::ABI_CallFunctionCCCP(const void *func, u32 param1, u32 param2,u32 param3, void *param4) {
117 ABI_AlignStack(4 * 4);
118 PUSH(32, ImmPtr(param4));
119 PUSH(32, Imm32(param3));
120 PUSH(32, Imm32(param2));
121 PUSH(32, Imm32(param1));
122 CALL(func);
123 ABI_RestoreStack(4 * 4);
124}
125
126void XEmitter::ABI_CallFunctionP(const void *func, void *param1) {
127 ABI_AlignStack(1 * 4);
128 PUSH(32, ImmPtr(param1));
129 CALL(func);
130 ABI_RestoreStack(1 * 4);
131}
132
133void XEmitter::ABI_CallFunctionPA(const void *func, void *param1, const Gen::OpArg &arg2) {
134 ABI_AlignStack(2 * 4);
135 PUSH(32, arg2);
136 PUSH(32, ImmPtr(param1));
137 CALL(func);
138 ABI_RestoreStack(2 * 4);
139}
140
141void XEmitter::ABI_CallFunctionPAA(const void *func, void *param1, const Gen::OpArg &arg2, const Gen::OpArg &arg3) {
142 ABI_AlignStack(3 * 4);
143 PUSH(32, arg3);
144 PUSH(32, arg2);
145 PUSH(32, ImmPtr(param1));
146 CALL(func);
147 ABI_RestoreStack(3 * 4);
148}
149
150void XEmitter::ABI_CallFunctionPPC(const void *func, void *param1, void *param2, u32 param3) {
151 ABI_AlignStack(3 * 4);
152 PUSH(32, Imm32(param3));
153 PUSH(32, ImmPtr(param2));
154 PUSH(32, ImmPtr(param1));
155 CALL(func);
156 ABI_RestoreStack(3 * 4);
157}
158
159// Pass a register as a parameter.
160void XEmitter::ABI_CallFunctionR(const void *func, X64Reg reg1) {
161 ABI_AlignStack(1 * 4);
162 PUSH(32, R(reg1));
163 CALL(func);
164 ABI_RestoreStack(1 * 4);
165}
166
167// Pass two registers as parameters.
168void XEmitter::ABI_CallFunctionRR(const void *func, Gen::X64Reg reg1, Gen::X64Reg reg2)
169{
170 ABI_AlignStack(2 * 4);
171 PUSH(32, R(reg2));
172 PUSH(32, R(reg1));
173 CALL(func);
174 ABI_RestoreStack(2 * 4);
175}
176 30
177void XEmitter::ABI_CallFunctionAC(const void *func, const Gen::OpArg &arg1, u32 param2) 31 int count = (mask & ABI_ALL_GPRS).Count();
178{ 32 rsp_alignment -= count * 8;
179 ABI_AlignStack(2 * 4); 33 size_t subtraction = 0;
180 PUSH(32, Imm32(param2)); 34 int fpr_count = (mask & ABI_ALL_FPRS).Count();
181 PUSH(32, arg1); 35 if (fpr_count) {
182 CALL(func); 36 // If we have any XMMs to save, we must align the stack here.
183 ABI_RestoreStack(2 * 4); 37 subtraction = rsp_alignment & 0xf;
184} 38 }
39 subtraction += 16 * fpr_count;
40 size_t xmm_base_subtraction = subtraction;
41 subtraction += needed_frame_size;
42 subtraction += shadow;
43 // Final alignment.
44 rsp_alignment -= subtraction;
45 subtraction += rsp_alignment & 0xf;
185 46
186void XEmitter::ABI_CallFunctionACC(const void *func, const Gen::OpArg &arg1, u32 param2, u32 param3) 47 *shadowp = shadow;
187{ 48 *subtractionp = subtraction;
188 ABI_AlignStack(3 * 4); 49 *xmm_offsetp = subtraction - xmm_base_subtraction;
189 PUSH(32, Imm32(param3));
190 PUSH(32, Imm32(param2));
191 PUSH(32, arg1);
192 CALL(func);
193 ABI_RestoreStack(3 * 4);
194} 50}
195 51
196void XEmitter::ABI_CallFunctionA(const void *func, const Gen::OpArg &arg1) 52size_t XEmitter::ABI_PushRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size) {
197{ 53 size_t shadow, subtraction, xmm_offset;
198 ABI_AlignStack(1 * 4); 54 ABI_CalculateFrameSize(mask, rsp_alignment, needed_frame_size, &shadow, &subtraction, &xmm_offset);
199 PUSH(32, arg1);
200 CALL(func);
201 ABI_RestoreStack(1 * 4);
202}
203 55
204void XEmitter::ABI_CallFunctionAA(const void *func, const Gen::OpArg &arg1, const Gen::OpArg &arg2) 56 for (int r : mask & ABI_ALL_GPRS)
205{ 57 PUSH((X64Reg)r);
206 ABI_AlignStack(2 * 4);
207 PUSH(32, arg2);
208 PUSH(32, arg1);
209 CALL(func);
210 ABI_RestoreStack(2 * 4);
211}
212 58
213void XEmitter::ABI_PushAllCalleeSavedRegsAndAdjustStack() { 59 if (subtraction)
214 // Note: 4 * 4 = 16 bytes, so alignment is preserved. 60 SUB(64, R(RSP), subtraction >= 0x80 ? Imm32((u32)subtraction) : Imm8((u8)subtraction));
215 PUSH(EBP);
216 PUSH(EBX);
217 PUSH(ESI);
218 PUSH(EDI);
219}
220 61
221void XEmitter::ABI_PopAllCalleeSavedRegsAndAdjustStack() { 62 for (int x : mask & ABI_ALL_FPRS) {
222 POP(EDI); 63 MOVAPD(MDisp(RSP, (int)xmm_offset), (X64Reg)(x - 16));
223 POP(ESI); 64 xmm_offset += 16;
224 POP(EBX); 65 }
225 POP(EBP);
226}
227 66
228unsigned int XEmitter::ABI_GetAlignedFrameSize(unsigned int frameSize) { 67 return shadow;
229 frameSize += 4; // reserve space for return address
230 unsigned int alignedSize =
231#ifdef __GNUC__
232 (frameSize + 15) & -16;
233#else
234 (frameSize + 3) & -4;
235#endif
236 return alignedSize;
237} 68}
238 69
70void XEmitter::ABI_PopRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size) {
71 size_t shadow, subtraction, xmm_offset;
72 ABI_CalculateFrameSize(mask, rsp_alignment, needed_frame_size, &shadow, &subtraction, &xmm_offset);
239 73
240void XEmitter::ABI_AlignStack(unsigned int frameSize) { 74 for (int x : mask & ABI_ALL_FPRS) {
241// Mac OS X requires the stack to be 16-byte aligned before every call. 75 MOVAPD((X64Reg) (x - 16), MDisp(RSP, (int)xmm_offset));
242// Linux requires the stack to be 16-byte aligned before calls that put SSE 76 xmm_offset += 16;
243// vectors on the stack, but since we do not keep track of which calls do that,
244// it is effectively every call as well.
245// Windows binaries compiled with MSVC do not have such a restriction*, but I
246// expect that GCC on Windows acts the same as GCC on Linux in this respect.
247// It would be nice if someone could verify this.
248// *However, the MSVC optimizing compiler assumes a 4-byte-aligned stack at times.
249 unsigned int fillSize =
250 ABI_GetAlignedFrameSize(frameSize) - (frameSize + 4);
251 if (fillSize != 0) {
252 SUB(32, R(ESP), Imm8(fillSize));
253 } 77 }
254}
255 78
256void XEmitter::ABI_RestoreStack(unsigned int frameSize) { 79 if (subtraction)
257 unsigned int alignedSize = ABI_GetAlignedFrameSize(frameSize); 80 ADD(64, R(RSP), subtraction >= 0x80 ? Imm32((u32)subtraction) : Imm8((u8)subtraction));
258 alignedSize -= 4; // return address is POPped at end of call 81
259 if (alignedSize != 0) { 82 for (int r = 15; r >= 0; r--) {
260 ADD(32, R(ESP), Imm8(alignedSize)); 83 if (mask[r])
84 POP((X64Reg)r);
261 } 85 }
262} 86}
263 87
264#else //64bit
265
266// Common functions 88// Common functions
267void XEmitter::ABI_CallFunction(const void *func) { 89void XEmitter::ABI_CallFunction(const void *func) {
268 u64 distance = u64(func) - (u64(code) + 5); 90 u64 distance = u64(func) - (u64(code) + 5);
@@ -538,143 +360,4 @@ void XEmitter::ABI_CallFunctionAA(const void *func, const Gen::OpArg &arg1, cons
538 } else { 360 } else {
539 CALL(func); 361 CALL(func);
540 } 362 }
541} 363} \ No newline at end of file
542
543unsigned int XEmitter::ABI_GetAlignedFrameSize(unsigned int frameSize) {
544 return frameSize;
545}
546
547#ifdef _WIN32
548
549// The Windows x64 ABI requires XMM6 - XMM15 to be callee saved. 10 regs.
550// But, not saving XMM4 and XMM5 breaks things in VS 2010, even though they are volatile regs.
551// Let's just save all 16.
552const int XMM_STACK_SPACE = 16 * 16;
553
554// Win64 Specific Code
555void XEmitter::ABI_PushAllCalleeSavedRegsAndAdjustStack() {
556 //we only want to do this once
557 PUSH(RBX);
558 PUSH(RSI);
559 PUSH(RDI);
560 PUSH(RBP);
561 PUSH(R12);
562 PUSH(R13);
563 PUSH(R14);
564 PUSH(R15);
565 ABI_AlignStack(0);
566
567 // Do this after aligning, because before it's offset by 8.
568 SUB(64, R(RSP), Imm32(XMM_STACK_SPACE));
569 for (int i = 0; i < 16; ++i)
570 MOVAPS(MDisp(RSP, i * 16), (X64Reg)(XMM0 + i));
571}
572
573void XEmitter::ABI_PopAllCalleeSavedRegsAndAdjustStack() {
574 for (int i = 0; i < 16; ++i)
575 MOVAPS((X64Reg)(XMM0 + i), MDisp(RSP, i * 16));
576 ADD(64, R(RSP), Imm32(XMM_STACK_SPACE));
577
578 ABI_RestoreStack(0);
579 POP(R15);
580 POP(R14);
581 POP(R13);
582 POP(R12);
583 POP(RBP);
584 POP(RDI);
585 POP(RSI);
586 POP(RBX);
587}
588
589// Win64 Specific Code
590void XEmitter::ABI_PushAllCallerSavedRegsAndAdjustStack() {
591 PUSH(RCX);
592 PUSH(RDX);
593 PUSH(RSI);
594 PUSH(RDI);
595 PUSH(R8);
596 PUSH(R9);
597 PUSH(R10);
598 PUSH(R11);
599 // TODO: Callers preserve XMM4-5 (XMM0-3 are args.)
600 ABI_AlignStack(0);
601}
602
603void XEmitter::ABI_PopAllCallerSavedRegsAndAdjustStack() {
604 ABI_RestoreStack(0);
605 POP(R11);
606 POP(R10);
607 POP(R9);
608 POP(R8);
609 POP(RDI);
610 POP(RSI);
611 POP(RDX);
612 POP(RCX);
613}
614
615void XEmitter::ABI_AlignStack(unsigned int /*frameSize*/) {
616 SUB(64, R(RSP), Imm8(0x28));
617}
618
619void XEmitter::ABI_RestoreStack(unsigned int /*frameSize*/) {
620 ADD(64, R(RSP), Imm8(0x28));
621}
622
623#else
624// Unix64 Specific Code
625void XEmitter::ABI_PushAllCalleeSavedRegsAndAdjustStack() {
626 PUSH(RBX);
627 PUSH(RBP);
628 PUSH(R12);
629 PUSH(R13);
630 PUSH(R14);
631 PUSH(R15);
632 PUSH(R15); //just to align stack. duped push/pop doesn't hurt.
633 // TODO: XMM?
634}
635
636void XEmitter::ABI_PopAllCalleeSavedRegsAndAdjustStack() {
637 POP(R15);
638 POP(R15);
639 POP(R14);
640 POP(R13);
641 POP(R12);
642 POP(RBP);
643 POP(RBX);
644}
645
646void XEmitter::ABI_PushAllCallerSavedRegsAndAdjustStack() {
647 PUSH(RCX);
648 PUSH(RDX);
649 PUSH(RSI);
650 PUSH(RDI);
651 PUSH(R8);
652 PUSH(R9);
653 PUSH(R10);
654 PUSH(R11);
655 PUSH(R11);
656}
657
658void XEmitter::ABI_PopAllCallerSavedRegsAndAdjustStack() {
659 POP(R11);
660 POP(R11);
661 POP(R10);
662 POP(R9);
663 POP(R8);
664 POP(RDI);
665 POP(RSI);
666 POP(RDX);
667 POP(RCX);
668}
669
670void XEmitter::ABI_AlignStack(unsigned int /*frameSize*/) {
671 SUB(64, R(RSP), Imm8(0x08));
672}
673
674void XEmitter::ABI_RestoreStack(unsigned int /*frameSize*/) {
675 ADD(64, R(RSP), Imm8(0x08));
676}
677
678#endif // WIN32
679
680#endif // 32bit