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@1146 | 45 | #define CALL1_PTR_MIN_SIZE 12
|
nkeynes@995 | 46 | static inline void CALL1_ptr_r32( void *ptr, int arg1 )
|
nkeynes@539 | 47 | {
|
nkeynes@995 | 48 | if( arg1 != REG_ARG1 ) {
|
nkeynes@995 | 49 | MOVQ_r64_r64( arg1, REG_ARG1 );
|
nkeynes@995 | 50 | }
|
nkeynes@995 | 51 | CALL_ptr(ptr);
|
nkeynes@539 | 52 | }
|
nkeynes@539 | 53 |
|
nkeynes@995 | 54 | static inline void CALL1_r32disp_r32( int preg, uint32_t disp, int arg1 )
|
nkeynes@927 | 55 | {
|
nkeynes@995 | 56 | if( arg1 != REG_ARG1 ) {
|
nkeynes@995 | 57 | MOVQ_r64_r64( arg1, REG_ARG1 );
|
nkeynes@995 | 58 | }
|
nkeynes@995 | 59 | CALL_r32disp(preg, disp);
|
nkeynes@927 | 60 | }
|
nkeynes@927 | 61 |
|
nkeynes@995 | 62 | static inline void CALL2_ptr_r32_r32( void *ptr, int arg1, int arg2 )
|
nkeynes@953 | 63 | {
|
nkeynes@995 | 64 | if( arg2 != REG_ARG2 ) {
|
nkeynes@995 | 65 | MOVQ_r64_r64( arg2, REG_ARG2 );
|
nkeynes@995 | 66 | }
|
nkeynes@995 | 67 | if( arg1 != REG_ARG1 ) {
|
nkeynes@995 | 68 | MOVQ_r64_r64( arg1, REG_ARG1 );
|
nkeynes@995 | 69 | }
|
nkeynes@995 | 70 | CALL_ptr(ptr);
|
nkeynes@953 | 71 | }
|
nkeynes@953 | 72 |
|
nkeynes@995 | 73 | static inline void CALL2_r32disp_r32_r32( int preg, uint32_t disp, int arg1, int arg2 )
|
nkeynes@953 | 74 | {
|
nkeynes@995 | 75 | if( arg2 != REG_ARG2 ) {
|
nkeynes@995 | 76 | MOVQ_r64_r64( arg2, REG_ARG2 );
|
nkeynes@995 | 77 | }
|
nkeynes@995 | 78 | if( arg1 != REG_ARG1 ) {
|
nkeynes@995 | 79 | MOVQ_r64_r64( arg1, REG_ARG1 );
|
nkeynes@995 | 80 | }
|
nkeynes@995 | 81 | CALL_r32disp(preg, disp);
|
nkeynes@953 | 82 | }
|
nkeynes@953 | 83 |
|
nkeynes@995 | 84 | static inline void CALL3_r32disp_r32_r32_r32( int preg, uint32_t disp, int arg1, int arg2, int arg3 )
|
nkeynes@539 | 85 | {
|
nkeynes@995 | 86 | if( arg3 != REG_ARG3 ) {
|
nkeynes@995 | 87 | MOVQ_r64_r64( arg3, REG_ARG3 );
|
nkeynes@995 | 88 | }
|
nkeynes@995 | 89 | if( arg2 != REG_ARG2 ) {
|
nkeynes@995 | 90 | MOVQ_r64_r64( arg2, REG_ARG2 );
|
nkeynes@995 | 91 | }
|
nkeynes@995 | 92 | if( arg1 != REG_ARG1 ) {
|
nkeynes@995 | 93 | MOVQ_r64_r64( arg1, REG_ARG1 );
|
nkeynes@995 | 94 | }
|
nkeynes@995 | 95 | CALL_r32disp(preg, disp);
|
nkeynes@539 | 96 | }
|
nkeynes@539 | 97 |
|
nkeynes@1112 | 98 | #define PROLOGUE_SIZE 15
|
nkeynes@1112 | 99 |
|
nkeynes@539 | 100 | /**
|
nkeynes@539 | 101 | * Emit the 'start of block' assembly. Sets up the stack frame and save
|
nkeynes@539 | 102 | * SI/DI as required
|
nkeynes@539 | 103 | */
|
nkeynes@1125 | 104 | static inline void emit_prologue( )
|
nkeynes@539 | 105 | {
|
nkeynes@991 | 106 | PUSH_r32(REG_RBP);
|
nkeynes@995 | 107 | SUBQ_imms_r64( 16, REG_RSP );
|
nkeynes@1112 | 108 | MOVP_immptr_rptr( ((uint8_t *)&sh4r) + 128, REG_EBP );
|
nkeynes@926 | 109 | }
|
nkeynes@926 | 110 |
|
nkeynes@1125 | 111 | static inline void emit_epilogue( )
|
nkeynes@926 | 112 | {
|
nkeynes@991 | 113 | ADDQ_imms_r64( 16, REG_RSP );
|
nkeynes@991 | 114 | POP_r32(REG_RBP);
|
nkeynes@539 | 115 | }
|