filename | src/xlat/x86/amd64abi.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@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@1292 | 25 | #define REG_SAVE1 REG_R12 |
nkeynes@1292 | 26 | #define REG_SAVE2 REG_R13 |
nkeynes@1292 | 27 | #define REG_SAVE3 REG_R14 |
nkeynes@1292 | 28 | #define REG_SAVE4 REG_R15 |
nkeynes@1292 | 29 | #define REG_CALLPTR REG_EBX |
nkeynes@736 | 30 | |
nkeynes@1292 | 31 | static inline void decode_address( uintptr_t base, int addr_reg, int target_reg ) |
nkeynes@953 | 32 | { |
nkeynes@1292 | 33 | MOVL_r32_r32( addr_reg, target_reg ); |
nkeynes@1292 | 34 | SHRL_imm_r32( 12, target_reg ); |
nkeynes@991 | 35 | MOVP_immptr_rptr( base, REG_RDI ); |
nkeynes@1292 | 36 | MOVP_sib_rptr( 3, target_reg, REG_RDI, 0, target_reg ); |
nkeynes@953 | 37 | } |
nkeynes@953 | 38 | |
nkeynes@539 | 39 | /** |
nkeynes@995 | 40 | * Note: clobbers ECX to make the indirect call - this isn't usually |
nkeynes@995 | 41 | * a problem since the callee will generally clobber it anyway. |
nkeynes@539 | 42 | * Size: 12 bytes |
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@995 | 47 | CALL_r32(REG_ECX); |
nkeynes@539 | 48 | } |
nkeynes@539 | 49 | |
nkeynes@1146 | 50 | #define CALL1_PTR_MIN_SIZE 12 |
nkeynes@995 | 51 | static inline void CALL1_ptr_r32( void *ptr, int arg1 ) |
nkeynes@539 | 52 | { |
nkeynes@995 | 53 | if( arg1 != REG_ARG1 ) { |
nkeynes@995 | 54 | MOVQ_r64_r64( arg1, REG_ARG1 ); |
nkeynes@995 | 55 | } |
nkeynes@995 | 56 | CALL_ptr(ptr); |
nkeynes@539 | 57 | } |
nkeynes@539 | 58 | |
nkeynes@995 | 59 | static inline void CALL1_r32disp_r32( int preg, uint32_t disp, int arg1 ) |
nkeynes@927 | 60 | { |
nkeynes@995 | 61 | if( arg1 != REG_ARG1 ) { |
nkeynes@995 | 62 | MOVQ_r64_r64( arg1, REG_ARG1 ); |
nkeynes@995 | 63 | } |
nkeynes@995 | 64 | CALL_r32disp(preg, disp); |
nkeynes@927 | 65 | } |
nkeynes@927 | 66 | |
nkeynes@995 | 67 | static inline void CALL2_ptr_r32_r32( void *ptr, int arg1, int arg2 ) |
nkeynes@953 | 68 | { |
nkeynes@995 | 69 | if( arg2 != REG_ARG2 ) { |
nkeynes@995 | 70 | MOVQ_r64_r64( arg2, REG_ARG2 ); |
nkeynes@995 | 71 | } |
nkeynes@995 | 72 | if( arg1 != REG_ARG1 ) { |
nkeynes@995 | 73 | MOVQ_r64_r64( arg1, REG_ARG1 ); |
nkeynes@995 | 74 | } |
nkeynes@995 | 75 | CALL_ptr(ptr); |
nkeynes@953 | 76 | } |
nkeynes@953 | 77 | |
nkeynes@995 | 78 | static inline void CALL2_r32disp_r32_r32( int preg, uint32_t disp, int arg1, int arg2 ) |
nkeynes@953 | 79 | { |
nkeynes@995 | 80 | if( arg2 != REG_ARG2 ) { |
nkeynes@995 | 81 | MOVQ_r64_r64( arg2, REG_ARG2 ); |
nkeynes@995 | 82 | } |
nkeynes@995 | 83 | if( arg1 != REG_ARG1 ) { |
nkeynes@995 | 84 | MOVQ_r64_r64( arg1, REG_ARG1 ); |
nkeynes@995 | 85 | } |
nkeynes@995 | 86 | CALL_r32disp(preg, disp); |
nkeynes@953 | 87 | } |
nkeynes@953 | 88 | |
nkeynes@995 | 89 | static inline void CALL3_r32disp_r32_r32_r32( int preg, uint32_t disp, int arg1, int arg2, int arg3 ) |
nkeynes@539 | 90 | { |
nkeynes@995 | 91 | if( arg3 != REG_ARG3 ) { |
nkeynes@995 | 92 | MOVQ_r64_r64( arg3, REG_ARG3 ); |
nkeynes@995 | 93 | } |
nkeynes@995 | 94 | if( arg2 != REG_ARG2 ) { |
nkeynes@995 | 95 | MOVQ_r64_r64( arg2, REG_ARG2 ); |
nkeynes@995 | 96 | } |
nkeynes@995 | 97 | if( arg1 != REG_ARG1 ) { |
nkeynes@995 | 98 | MOVQ_r64_r64( arg1, REG_ARG1 ); |
nkeynes@995 | 99 | } |
nkeynes@995 | 100 | CALL_r32disp(preg, disp); |
nkeynes@539 | 101 | } |
nkeynes@539 | 102 | |
nkeynes@1112 | 103 | #define PROLOGUE_SIZE 15 |
nkeynes@1112 | 104 | |
nkeynes@539 | 105 | /** |
nkeynes@539 | 106 | * Emit the 'start of block' assembly. Sets up the stack frame and save |
nkeynes@539 | 107 | * SI/DI as required |
nkeynes@539 | 108 | */ |
nkeynes@1125 | 109 | static inline void emit_prologue( ) |
nkeynes@539 | 110 | { |
nkeynes@991 | 111 | PUSH_r32(REG_RBP); |
nkeynes@995 | 112 | SUBQ_imms_r64( 16, REG_RSP ); |
nkeynes@1112 | 113 | MOVP_immptr_rptr( ((uint8_t *)&sh4r) + 128, REG_EBP ); |
nkeynes@926 | 114 | } |
nkeynes@926 | 115 | |
nkeynes@1125 | 116 | static inline void emit_epilogue( ) |
nkeynes@926 | 117 | { |
nkeynes@991 | 118 | ADDQ_imms_r64( 16, REG_RSP ); |
nkeynes@991 | 119 | POP_r32(REG_RBP); |
nkeynes@539 | 120 | } |
.