filename | src/xlat/x86/ia32abi.h |
changeset | 1112:4cac5e474d4c |
prev | 1067:d3c00ffccfcd |
next | 1125:9dd5dee45db9 |
author | nkeynes |
date | Tue Jul 13 18:23:16 2010 +1000 (13 years ago) |
permissions | -rw-r--r-- |
last change | Rearrange the main translation loop to allow translated blocks to jump directly to their successors without needing to return to the main loop in between. Shaves about 6% off the core runtime. |
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_RESULT1 REG_EAX
27 #define MAX_REG_ARG 2
29 static inline void decode_address( uintptr_t base, int addr_reg )
30 {
31 MOVL_r32_r32( addr_reg, REG_ECX );
32 SHRL_imm_r32( 12, REG_ECX );
33 MOVP_sib_rptr( 2, REG_ECX, -1, base, REG_ECX );
34 }
36 /**
37 * Note: clobbers ECX to make the indirect call - this isn't usually
38 * a problem since the callee will generally clobber it anyway.
39 */
40 static inline void CALL_ptr( void *ptr )
41 {
42 MOVP_immptr_rptr( (uintptr_t)ptr, REG_ECX );
43 CALL_r32(REG_ECX);
44 }
46 #ifdef HAVE_FASTCALL
47 static inline void CALL1_ptr_r32( void *ptr, int arg1 )
48 {
49 if( arg1 != REG_ARG1 ) {
50 MOVL_r32_r32( arg1, REG_ARG1 );
51 }
52 CALL_ptr(ptr);
53 }
55 static inline void CALL1_r32disp_r32( int preg, uint32_t disp, int arg1 )
56 {
57 if( arg1 != REG_ARG1 ) {
58 MOVL_r32_r32( arg1, REG_ARG1 );
59 }
60 CALL_r32disp(preg, disp);
61 }
63 static inline void CALL2_ptr_r32_r32( void *ptr, int arg1, int arg2 )
64 {
65 if( arg2 != REG_ARG2 ) {
66 MOVL_r32_r32( arg2, REG_ARG2 );
67 }
68 if( arg1 != REG_ARG1 ) {
69 MOVL_r32_r32( arg1, REG_ARG1 );
70 }
71 CALL_ptr(ptr);
72 }
74 static inline void CALL2_r32disp_r32_r32( int preg, uint32_t disp, int arg1, int arg2 )
75 {
76 if( arg2 != REG_ARG2 ) {
77 MOVL_r32_r32( arg2, REG_ARG2 );
78 }
79 if( arg1 != REG_ARG1 ) {
80 MOVL_r32_r32( arg1, REG_ARG1 );
81 }
82 CALL_r32disp(preg, disp);
83 }
85 #define CALL3_r32disp_r32_r32_r32(preg,disp,arg1,arg2,arg3) CALL2_r32disp_r32_r32(preg,disp,arg1,arg2)
87 #else
88 static inline void CALL1_ptr( void *ptr, int arg1 )
89 {
90 SUBL_imms_r32( 12, REG_ESP );
91 PUSH_r32(arg1);
92 CALL_ptr(ptr);
93 ADDL_imms_r32( 16, REG_ESP );
94 }
96 static inline void CALL1_r32disp_r32( int preg, uint32_t disp, int arg1 )
97 {
98 SUBL_imms_r32( 12, REG_ESP );
99 PUSH_r32(arg1);
100 CALL_r32disp(preg, disp);
101 ADDL_imms_r32( 16, REG_ESP );
102 }
104 static inline void CALL2_ptr_r32_r32( void *ptr, int arg1, int arg2 )
105 {
106 SUBL_imms_r32( 8, REG_ESP );
107 PUSH_r32(arg2);
108 PUSH_r32(arg1);
109 CALL_ptr(ptr);
110 ADDL_imms_r32( 16, REG_ESP );
111 }
113 static inline void CALL2_r32disp_r32_r32( int preg, uint32_t disp, int arg1, int arg2 )
114 {
115 SUBL_imms_r32( 8, REG_ESP );
116 PUSH_r32(arg2);
117 PUSH_r32(arg1);
118 CALL_r32disp(preg, disp);
119 ADDL_imms_r32( 16, REG_ESP );
120 }
122 static inline void CALL3_r32disp_r32_r32_r32( int preg, uint32_t disp, int arg1, int arg2, int arg3 )
123 {
124 SUBL_imms_r32( 8, REG_ESP );
125 PUSH_r32(arg2);
126 PUSH_r32(arg1);
127 MOVL_rspdisp_r32( 16, REG_EAX );
128 MOVL_r32_rspdisp( R_EAX, 8 );
129 CALL_r32disp(preg,disp);
130 ADDL_imms_r32( 16, REG_ESP );
131 }
133 #endif
135 #define PROLOGUE_SIZE 9
137 /**
138 * Emit the 'start of block' assembly. Sets up the stack frame and save
139 * SI/DI as required
140 * Allocates 8 bytes for local variables, which also has the convenient
141 * side-effect of aligning the stack.
142 */
143 static inline void enter_block( )
144 {
145 PUSH_r32(REG_EBP);
146 SUBL_imms_r32( 8, REG_ESP );
147 MOVP_immptr_rptr( ((uint8_t *)&sh4r) + 128, REG_EBP );
148 }
150 static inline void exit_block( )
151 {
152 ADDL_imms_r32( 8, REG_ESP );
153 POP_r32(REG_EBP);
154 RET();
155 }
.