filename | src/xlat/x86/amd64abi.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. |
file | annotate | diff | log | raw |
nkeynes@539 | 1 | /** |
nkeynes@586 | 2 | * $Id$ |
nkeynes@539 | 3 | * |
nkeynes@736 | 4 | * Provides the implementation for the AMD64 ABI (eg prologue, epilogue, and |
nkeynes@539 | 5 | * calling conventions) |
nkeynes@539 | 6 | * |
nkeynes@539 | 7 | * Copyright (c) 2007 Nathan Keynes. |
nkeynes@539 | 8 | * |
nkeynes@539 | 9 | * This program is free software; you can redistribute it and/or modify |
nkeynes@539 | 10 | * it under the terms of the GNU General Public License as published by |
nkeynes@539 | 11 | * the Free Software Foundation; either version 2 of the License, or |
nkeynes@539 | 12 | * (at your option) any later version. |
nkeynes@539 | 13 | * |
nkeynes@539 | 14 | * This program is distributed in the hope that it will be useful, |
nkeynes@539 | 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
nkeynes@539 | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
nkeynes@539 | 17 | * GNU General Public License for more details. |
nkeynes@539 | 18 | */ |
nkeynes@539 | 19 | |
nkeynes@995 | 20 | #define REG_ARG1 REG_RDI |
nkeynes@995 | 21 | #define REG_ARG2 REG_RSI |
nkeynes@995 | 22 | #define REG_ARG3 REG_RDX |
nkeynes@995 | 23 | #define REG_RESULT1 REG_RAX |
nkeynes@995 | 24 | #define MAX_REG_ARG 3 /* There's more, but we don't use more than 3 here anyway */ |
nkeynes@736 | 25 | |
nkeynes@1004 | 26 | static inline void decode_address( uintptr_t base, int addr_reg ) |
nkeynes@953 | 27 | { |
nkeynes@995 | 28 | MOVL_r32_r32( addr_reg, REG_ECX ); |
nkeynes@995 | 29 | SHRL_imm_r32( 12, REG_ECX ); |
nkeynes@991 | 30 | MOVP_immptr_rptr( base, REG_RDI ); |
nkeynes@995 | 31 | MOVP_sib_rptr( 3, REG_RCX, REG_RDI, 0, REG_RCX ); |
nkeynes@953 | 32 | } |
nkeynes@953 | 33 | |
nkeynes@539 | 34 | /** |
nkeynes@995 | 35 | * Note: clobbers ECX to make the indirect call - this isn't usually |
nkeynes@995 | 36 | * a problem since the callee will generally clobber it anyway. |
nkeynes@539 | 37 | * Size: 12 bytes |
nkeynes@539 | 38 | */ |
nkeynes@995 | 39 | static inline void CALL_ptr( void *ptr ) |
nkeynes@539 | 40 | { |
nkeynes@995 | 41 | MOVP_immptr_rptr( (uintptr_t)ptr, REG_ECX ); |
nkeynes@995 | 42 | CALL_r32(REG_ECX); |
nkeynes@539 | 43 | } |
nkeynes@539 | 44 | |
nkeynes@995 | 45 | static inline void CALL1_ptr_r32( void *ptr, int arg1 ) |
nkeynes@539 | 46 | { |
nkeynes@995 | 47 | if( arg1 != REG_ARG1 ) { |
nkeynes@995 | 48 | MOVQ_r64_r64( arg1, REG_ARG1 ); |
nkeynes@995 | 49 | } |
nkeynes@995 | 50 | CALL_ptr(ptr); |
nkeynes@539 | 51 | } |
nkeynes@539 | 52 | |
nkeynes@995 | 53 | static inline void CALL1_r32disp_r32( int preg, uint32_t disp, int arg1 ) |
nkeynes@927 | 54 | { |
nkeynes@995 | 55 | if( arg1 != REG_ARG1 ) { |
nkeynes@995 | 56 | MOVQ_r64_r64( arg1, REG_ARG1 ); |
nkeynes@995 | 57 | } |
nkeynes@995 | 58 | CALL_r32disp(preg, disp); |
nkeynes@927 | 59 | } |
nkeynes@927 | 60 | |
nkeynes@995 | 61 | static inline void CALL2_ptr_r32_r32( void *ptr, int arg1, int arg2 ) |
nkeynes@953 | 62 | { |
nkeynes@995 | 63 | if( arg2 != REG_ARG2 ) { |
nkeynes@995 | 64 | MOVQ_r64_r64( arg2, REG_ARG2 ); |
nkeynes@995 | 65 | } |
nkeynes@995 | 66 | if( arg1 != REG_ARG1 ) { |
nkeynes@995 | 67 | MOVQ_r64_r64( arg1, REG_ARG1 ); |
nkeynes@995 | 68 | } |
nkeynes@995 | 69 | CALL_ptr(ptr); |
nkeynes@953 | 70 | } |
nkeynes@953 | 71 | |
nkeynes@995 | 72 | static inline void CALL2_r32disp_r32_r32( int preg, uint32_t disp, int arg1, int arg2 ) |
nkeynes@953 | 73 | { |
nkeynes@995 | 74 | if( arg2 != REG_ARG2 ) { |
nkeynes@995 | 75 | MOVQ_r64_r64( arg2, REG_ARG2 ); |
nkeynes@995 | 76 | } |
nkeynes@995 | 77 | if( arg1 != REG_ARG1 ) { |
nkeynes@995 | 78 | MOVQ_r64_r64( arg1, REG_ARG1 ); |
nkeynes@995 | 79 | } |
nkeynes@995 | 80 | CALL_r32disp(preg, disp); |
nkeynes@953 | 81 | } |
nkeynes@953 | 82 | |
nkeynes@995 | 83 | static inline void CALL3_r32disp_r32_r32_r32( int preg, uint32_t disp, int arg1, int arg2, int arg3 ) |
nkeynes@539 | 84 | { |
nkeynes@995 | 85 | if( arg3 != REG_ARG3 ) { |
nkeynes@995 | 86 | MOVQ_r64_r64( arg3, REG_ARG3 ); |
nkeynes@995 | 87 | } |
nkeynes@995 | 88 | if( arg2 != REG_ARG2 ) { |
nkeynes@995 | 89 | MOVQ_r64_r64( arg2, REG_ARG2 ); |
nkeynes@995 | 90 | } |
nkeynes@995 | 91 | if( arg1 != REG_ARG1 ) { |
nkeynes@995 | 92 | MOVQ_r64_r64( arg1, REG_ARG1 ); |
nkeynes@995 | 93 | } |
nkeynes@995 | 94 | CALL_r32disp(preg, disp); |
nkeynes@539 | 95 | } |
nkeynes@539 | 96 | |
nkeynes@1112 | 97 | #define PROLOGUE_SIZE 15 |
nkeynes@1112 | 98 | |
nkeynes@539 | 99 | /** |
nkeynes@539 | 100 | * Emit the 'start of block' assembly. Sets up the stack frame and save |
nkeynes@539 | 101 | * SI/DI as required |
nkeynes@539 | 102 | */ |
nkeynes@995 | 103 | static inline void enter_block( ) |
nkeynes@539 | 104 | { |
nkeynes@991 | 105 | PUSH_r32(REG_RBP); |
nkeynes@995 | 106 | SUBQ_imms_r64( 16, REG_RSP ); |
nkeynes@1112 | 107 | MOVP_immptr_rptr( ((uint8_t *)&sh4r) + 128, REG_EBP ); |
nkeynes@926 | 108 | } |
nkeynes@926 | 109 | |
nkeynes@926 | 110 | static inline void exit_block( ) |
nkeynes@926 | 111 | { |
nkeynes@991 | 112 | ADDQ_imms_r64( 16, REG_RSP ); |
nkeynes@991 | 113 | POP_r32(REG_RBP); |
nkeynes@926 | 114 | RET(); |
nkeynes@539 | 115 | } |
.