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 (11 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. |
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@995 | 26 | #define REG_RESULT1 REG_EAX |
nkeynes@995 | 27 | #define MAX_REG_ARG 2 |
nkeynes@539 | 28 | |
nkeynes@1004 | 29 | static inline void decode_address( uintptr_t base, int addr_reg ) |
nkeynes@953 | 30 | { |
nkeynes@995 | 31 | MOVL_r32_r32( addr_reg, REG_ECX ); |
nkeynes@991 | 32 | SHRL_imm_r32( 12, REG_ECX ); |
nkeynes@991 | 33 | MOVP_sib_rptr( 2, REG_ECX, -1, base, REG_ECX ); |
nkeynes@953 | 34 | } |
nkeynes@953 | 35 | |
nkeynes@539 | 36 | /** |
nkeynes@995 | 37 | * Note: clobbers ECX to make the indirect call - this isn't usually |
nkeynes@995 | 38 | * a problem since the callee will generally clobber it anyway. |
nkeynes@539 | 39 | */ |
nkeynes@995 | 40 | static inline void CALL_ptr( void *ptr ) |
nkeynes@539 | 41 | { |
nkeynes@995 | 42 | MOVP_immptr_rptr( (uintptr_t)ptr, REG_ECX ); |
nkeynes@991 | 43 | CALL_r32(REG_ECX); |
nkeynes@539 | 44 | } |
nkeynes@539 | 45 | |
nkeynes@905 | 46 | #ifdef HAVE_FASTCALL |
nkeynes@995 | 47 | static inline void CALL1_ptr_r32( void *ptr, int arg1 ) |
nkeynes@905 | 48 | { |
nkeynes@995 | 49 | if( arg1 != REG_ARG1 ) { |
nkeynes@995 | 50 | MOVL_r32_r32( arg1, REG_ARG1 ); |
nkeynes@905 | 51 | } |
nkeynes@995 | 52 | CALL_ptr(ptr); |
nkeynes@953 | 53 | } |
nkeynes@953 | 54 | |
nkeynes@995 | 55 | static inline void CALL1_r32disp_r32( int preg, uint32_t disp, int arg1 ) |
nkeynes@953 | 56 | { |
nkeynes@995 | 57 | if( arg1 != REG_ARG1 ) { |
nkeynes@995 | 58 | MOVL_r32_r32( arg1, REG_ARG1 ); |
nkeynes@953 | 59 | } |
nkeynes@995 | 60 | CALL_r32disp(preg, disp); |
nkeynes@953 | 61 | } |
nkeynes@953 | 62 | |
nkeynes@995 | 63 | static inline void CALL2_ptr_r32_r32( void *ptr, int arg1, int arg2 ) |
nkeynes@953 | 64 | { |
nkeynes@995 | 65 | if( arg2 != REG_ARG2 ) { |
nkeynes@995 | 66 | MOVL_r32_r32( arg2, REG_ARG2 ); |
nkeynes@953 | 67 | } |
nkeynes@995 | 68 | if( arg1 != REG_ARG1 ) { |
nkeynes@995 | 69 | MOVL_r32_r32( arg1, REG_ARG1 ); |
nkeynes@995 | 70 | } |
nkeynes@995 | 71 | CALL_ptr(ptr); |
nkeynes@953 | 72 | } |
nkeynes@953 | 73 | |
nkeynes@995 | 74 | static inline void CALL2_r32disp_r32_r32( int preg, uint32_t disp, int arg1, int arg2 ) |
nkeynes@953 | 75 | { |
nkeynes@995 | 76 | if( arg2 != REG_ARG2 ) { |
nkeynes@995 | 77 | MOVL_r32_r32( arg2, REG_ARG2 ); |
nkeynes@953 | 78 | } |
nkeynes@995 | 79 | if( arg1 != REG_ARG1 ) { |
nkeynes@995 | 80 | MOVL_r32_r32( arg1, REG_ARG1 ); |
nkeynes@995 | 81 | } |
nkeynes@995 | 82 | CALL_r32disp(preg, disp); |
nkeynes@905 | 83 | } |
nkeynes@905 | 84 | |
nkeynes@995 | 85 | #define CALL3_r32disp_r32_r32_r32(preg,disp,arg1,arg2,arg3) CALL2_r32disp_r32_r32(preg,disp,arg1,arg2) |
nkeynes@927 | 86 | |
nkeynes@905 | 87 | #else |
nkeynes@995 | 88 | static inline void CALL1_ptr( void *ptr, int arg1 ) |
nkeynes@539 | 89 | { |
nkeynes@991 | 90 | SUBL_imms_r32( 12, REG_ESP ); |
nkeynes@539 | 91 | PUSH_r32(arg1); |
nkeynes@995 | 92 | CALL_ptr(ptr); |
nkeynes@991 | 93 | ADDL_imms_r32( 16, REG_ESP ); |
nkeynes@539 | 94 | } |
nkeynes@539 | 95 | |
nkeynes@995 | 96 | static inline void CALL1_r32disp_r32( int preg, uint32_t disp, int arg1 ) |
nkeynes@995 | 97 | { |
nkeynes@995 | 98 | SUBL_imms_r32( 12, REG_ESP ); |
nkeynes@995 | 99 | PUSH_r32(arg1); |
nkeynes@995 | 100 | CALL_r32disp(preg, disp); |
nkeynes@995 | 101 | ADDL_imms_r32( 16, REG_ESP ); |
nkeynes@995 | 102 | } |
nkeynes@995 | 103 | |
nkeynes@995 | 104 | static inline void CALL2_ptr_r32_r32( void *ptr, int arg1, int arg2 ) |
nkeynes@539 | 105 | { |
nkeynes@991 | 106 | SUBL_imms_r32( 8, REG_ESP ); |
nkeynes@539 | 107 | PUSH_r32(arg2); |
nkeynes@539 | 108 | PUSH_r32(arg1); |
nkeynes@995 | 109 | CALL_ptr(ptr); |
nkeynes@995 | 110 | ADDL_imms_r32( 16, REG_ESP ); |
nkeynes@995 | 111 | } |
nkeynes@995 | 112 | |
nkeynes@995 | 113 | static inline void CALL2_r32disp_r32_r32( int preg, uint32_t disp, int arg1, int arg2 ) |
nkeynes@995 | 114 | { |
nkeynes@995 | 115 | SUBL_imms_r32( 8, REG_ESP ); |
nkeynes@995 | 116 | PUSH_r32(arg2); |
nkeynes@995 | 117 | PUSH_r32(arg1); |
nkeynes@995 | 118 | CALL_r32disp(preg, disp); |
nkeynes@995 | 119 | ADDL_imms_r32( 16, REG_ESP ); |
nkeynes@995 | 120 | } |
nkeynes@995 | 121 | |
nkeynes@995 | 122 | static inline void CALL3_r32disp_r32_r32_r32( int preg, uint32_t disp, int arg1, int arg2, int arg3 ) |
nkeynes@995 | 123 | { |
nkeynes@995 | 124 | SUBL_imms_r32( 8, REG_ESP ); |
nkeynes@995 | 125 | PUSH_r32(arg2); |
nkeynes@995 | 126 | PUSH_r32(arg1); |
nkeynes@995 | 127 | MOVL_rspdisp_r32( 16, REG_EAX ); |
nkeynes@995 | 128 | MOVL_r32_rspdisp( R_EAX, 8 ); |
nkeynes@995 | 129 | CALL_r32disp(preg,disp); |
nkeynes@991 | 130 | ADDL_imms_r32( 16, REG_ESP ); |
nkeynes@539 | 131 | } |
nkeynes@926 | 132 | |
nkeynes@905 | 133 | #endif |
nkeynes@539 | 134 | |
nkeynes@1112 | 135 | #define PROLOGUE_SIZE 9 |
nkeynes@1112 | 136 | |
nkeynes@539 | 137 | /** |
nkeynes@539 | 138 | * Emit the 'start of block' assembly. Sets up the stack frame and save |
nkeynes@539 | 139 | * SI/DI as required |
nkeynes@926 | 140 | * Allocates 8 bytes for local variables, which also has the convenient |
nkeynes@926 | 141 | * side-effect of aligning the stack. |
nkeynes@539 | 142 | */ |
nkeynes@995 | 143 | static inline void enter_block( ) |
nkeynes@539 | 144 | { |
nkeynes@991 | 145 | PUSH_r32(REG_EBP); |
nkeynes@991 | 146 | SUBL_imms_r32( 8, REG_ESP ); |
nkeynes@1112 | 147 | MOVP_immptr_rptr( ((uint8_t *)&sh4r) + 128, REG_EBP ); |
nkeynes@926 | 148 | } |
nkeynes@736 | 149 | |
nkeynes@926 | 150 | static inline void exit_block( ) |
nkeynes@926 | 151 | { |
nkeynes@991 | 152 | ADDL_imms_r32( 8, REG_ESP ); |
nkeynes@991 | 153 | POP_r32(REG_EBP); |
nkeynes@926 | 154 | RET(); |
nkeynes@539 | 155 | } |
.