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