filename | src/xlat/x86/ia32abi.h |
changeset | 1292:799fdd4f704a |
prev | 1146:76c5d1064262 |
author | nkeynes |
date | Fri Aug 24 08:53:50 2012 +1000 (8 years ago) |
permissions | -rw-r--r-- |
last change | Move the generated prologue/epilogue code out into a common entry stub (reduces space requirements) and pre-save all saved registers. Change FASTCALL to use 3 regs instead of 2 since we can now keep everything in regs. |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
3 *
4 * Provides the implementation for the ia32 ABI variant
5 * (eg prologue, epilogue, and calling conventions). Stack frame is
6 * aligned on 16-byte boundaries for the benefit of OS X (which
7 * requires it).
8 *
9 * Note: These should only be included from x86op.h
10 *
11 * Copyright (c) 2007 Nathan Keynes.
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 */
24 #define REG_ARG1 REG_EAX
25 #define REG_ARG2 REG_EDX
26 #define REG_ARG3 REG_ECX
27 #define REG_RESULT1 REG_EAX
28 #define MAX_REG_ARG 3
29 #define REG_SAVE1 REG_ESI
30 #define REG_SAVE2 REG_EDI
31 #define REG_CALLPTR REG_EBX
33 static inline void decode_address( uintptr_t base, int addr_reg, int target_reg )
34 {
35 MOVL_r32_r32( addr_reg, target_reg );
36 SHRL_imm_r32( 12, target_reg );
37 MOVP_sib_rptr( 2, target_reg, -1, base, target_reg );
38 }
40 /**
41 * Note: clobbers ECX to make the indirect call - this isn't usually
42 * a problem since the callee will generally clobber it anyway.
43 */
44 static inline void CALL_ptr( void *ptr )
45 {
46 MOVP_immptr_rptr( (uintptr_t)ptr, REG_ECX );
47 CALL_r32(REG_ECX);
48 }
50 #ifdef HAVE_FASTCALL
51 #define CALL1_PTR_MIN_SIZE 7
53 static inline void CALL1_ptr_r32( void *ptr, int arg1 )
54 {
55 if( arg1 != REG_ARG1 ) {
56 MOVL_r32_r32( arg1, REG_ARG1 );
57 }
58 CALL_ptr(ptr);
59 }
61 static inline void CALL1_r32disp_r32( int preg, uint32_t disp, int arg1 )
62 {
63 if( arg1 != REG_ARG1 ) {
64 MOVL_r32_r32( arg1, REG_ARG1 );
65 }
66 CALL_r32disp(preg, disp);
67 }
69 static inline void CALL2_ptr_r32_r32( void *ptr, int arg1, int arg2 )
70 {
71 if( arg2 != REG_ARG2 ) {
72 MOVL_r32_r32( arg2, REG_ARG2 );
73 }
74 if( arg1 != REG_ARG1 ) {
75 MOVL_r32_r32( arg1, REG_ARG1 );
76 }
77 CALL_ptr(ptr);
78 }
80 static inline void CALL2_r32disp_r32_r32( int preg, uint32_t disp, int arg1, int arg2 )
81 {
82 if( arg2 != REG_ARG2 ) {
83 MOVL_r32_r32( arg2, REG_ARG2 );
84 }
85 if( arg1 != REG_ARG1 ) {
86 MOVL_r32_r32( arg1, REG_ARG1 );
87 }
88 CALL_r32disp(preg, disp);
89 }
91 static inline void CALL3_r32disp_r32_r32_r32( int preg, uint32_t disp, int arg1, int arg2, int arg3)
92 {
93 if( arg3 != REG_ARG3 ) {
94 MOVL_r32_r32( arg3, REG_ARG3 );
95 }
96 if( arg2 != REG_ARG2 ) {
97 MOVL_r32_r32( arg2, REG_ARG2 );
98 }
99 if( arg1 != REG_ARG1 ) {
100 MOVL_r32_r32( arg1, REG_ARG1 );
101 }
102 CALL_r32disp(preg, disp);
103 }
105 #else
107 #define CALL1_PTR_MIN_SIZE (3+1+7+3)
109 static inline void CALL1_ptr_r32( void *ptr, int arg1 )
110 {
111 SUBL_imms_r32( 12, REG_ESP );
112 PUSH_r32(arg1);
113 CALL_ptr(ptr);
114 ADDL_imms_r32( 16, REG_ESP );
115 }
117 static inline void CALL1_r32disp_r32( int preg, uint32_t disp, int arg1 )
118 {
119 SUBL_imms_r32( 12, REG_ESP );
120 PUSH_r32(arg1);
121 CALL_r32disp(preg, disp);
122 ADDL_imms_r32( 16, REG_ESP );
123 }
125 static inline void CALL2_ptr_r32_r32( void *ptr, int arg1, int arg2 )
126 {
127 SUBL_imms_r32( 8, REG_ESP );
128 PUSH_r32(arg2);
129 PUSH_r32(arg1);
130 CALL_ptr(ptr);
131 ADDL_imms_r32( 16, REG_ESP );
132 }
134 static inline void CALL2_r32disp_r32_r32( int preg, uint32_t disp, int arg1, int arg2 )
135 {
136 SUBL_imms_r32( 8, REG_ESP );
137 PUSH_r32(arg2);
138 PUSH_r32(arg1);
139 CALL_r32disp(preg, disp);
140 ADDL_imms_r32( 16, REG_ESP );
141 }
143 static inline void CALL3_r32disp_r32_r32_r32( int preg, uint32_t disp, int arg1, int arg2, int arg3 )
144 {
145 SUBL_imms_r32( 8, REG_ESP );
146 PUSH_r32(arg2);
147 PUSH_r32(arg1);
148 MOVL_rspdisp_r32( 16, REG_EAX );
149 MOVL_r32_rspdisp( REG_EAX, 8 );
150 CALL_r32disp(preg,disp);
151 ADDL_imms_r32( 16, REG_ESP );
152 }
154 #endif
156 #define PROLOGUE_SIZE 9
158 /**
159 * Emit the 'start of block' assembly. Sets up the stack frame and save
160 * SI/DI as required
161 * Allocates 8 bytes for local variables, which also has the convenient
162 * side-effect of aligning the stack.
163 */
164 static inline void emit_prologue( )
165 {
166 PUSH_r32(REG_EBP);
167 SUBL_imms_r32( 8, REG_ESP );
168 MOVP_immptr_rptr( ((uint8_t *)&sh4r) + 128, REG_EBP );
169 }
171 static inline void emit_epilogue( )
172 {
173 ADDL_imms_r32( 8, REG_ESP );
174 POP_r32(REG_EBP);
175 }
.