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@1146 | 47 | #define CALL1_PTR_MIN_SIZE 7
|
nkeynes@1146 | 48 |
|
nkeynes@995 | 49 | static inline void CALL1_ptr_r32( void *ptr, int arg1 )
|
nkeynes@905 | 50 | {
|
nkeynes@995 | 51 | if( arg1 != REG_ARG1 ) {
|
nkeynes@995 | 52 | MOVL_r32_r32( arg1, REG_ARG1 );
|
nkeynes@905 | 53 | }
|
nkeynes@995 | 54 | CALL_ptr(ptr);
|
nkeynes@953 | 55 | }
|
nkeynes@953 | 56 |
|
nkeynes@995 | 57 | static inline void CALL1_r32disp_r32( int preg, uint32_t disp, int arg1 )
|
nkeynes@953 | 58 | {
|
nkeynes@995 | 59 | if( arg1 != REG_ARG1 ) {
|
nkeynes@995 | 60 | MOVL_r32_r32( arg1, REG_ARG1 );
|
nkeynes@953 | 61 | }
|
nkeynes@995 | 62 | CALL_r32disp(preg, disp);
|
nkeynes@953 | 63 | }
|
nkeynes@953 | 64 |
|
nkeynes@995 | 65 | static inline void CALL2_ptr_r32_r32( void *ptr, int arg1, int arg2 )
|
nkeynes@953 | 66 | {
|
nkeynes@995 | 67 | if( arg2 != REG_ARG2 ) {
|
nkeynes@995 | 68 | MOVL_r32_r32( arg2, REG_ARG2 );
|
nkeynes@953 | 69 | }
|
nkeynes@995 | 70 | if( arg1 != REG_ARG1 ) {
|
nkeynes@995 | 71 | MOVL_r32_r32( arg1, REG_ARG1 );
|
nkeynes@995 | 72 | }
|
nkeynes@995 | 73 | CALL_ptr(ptr);
|
nkeynes@953 | 74 | }
|
nkeynes@953 | 75 |
|
nkeynes@995 | 76 | static inline void CALL2_r32disp_r32_r32( int preg, uint32_t disp, int arg1, int arg2 )
|
nkeynes@953 | 77 | {
|
nkeynes@995 | 78 | if( arg2 != REG_ARG2 ) {
|
nkeynes@995 | 79 | MOVL_r32_r32( arg2, REG_ARG2 );
|
nkeynes@953 | 80 | }
|
nkeynes@995 | 81 | if( arg1 != REG_ARG1 ) {
|
nkeynes@995 | 82 | MOVL_r32_r32( arg1, REG_ARG1 );
|
nkeynes@995 | 83 | }
|
nkeynes@995 | 84 | CALL_r32disp(preg, disp);
|
nkeynes@905 | 85 | }
|
nkeynes@905 | 86 |
|
nkeynes@995 | 87 | #define CALL3_r32disp_r32_r32_r32(preg,disp,arg1,arg2,arg3) CALL2_r32disp_r32_r32(preg,disp,arg1,arg2)
|
nkeynes@927 | 88 |
|
nkeynes@905 | 89 | #else
|
nkeynes@1146 | 90 |
|
nkeynes@1146 | 91 | #define CALL1_PTR_MIN_SIZE (3+1+7+3)
|
nkeynes@1146 | 92 |
|
nkeynes@1146 | 93 | static inline void CALL1_ptr_r32( void *ptr, int arg1 )
|
nkeynes@539 | 94 | {
|
nkeynes@991 | 95 | SUBL_imms_r32( 12, REG_ESP );
|
nkeynes@539 | 96 | PUSH_r32(arg1);
|
nkeynes@995 | 97 | CALL_ptr(ptr);
|
nkeynes@991 | 98 | ADDL_imms_r32( 16, REG_ESP );
|
nkeynes@539 | 99 | }
|
nkeynes@539 | 100 |
|
nkeynes@995 | 101 | static inline void CALL1_r32disp_r32( int preg, uint32_t disp, int arg1 )
|
nkeynes@995 | 102 | {
|
nkeynes@995 | 103 | SUBL_imms_r32( 12, REG_ESP );
|
nkeynes@995 | 104 | PUSH_r32(arg1);
|
nkeynes@995 | 105 | CALL_r32disp(preg, disp);
|
nkeynes@995 | 106 | ADDL_imms_r32( 16, REG_ESP );
|
nkeynes@995 | 107 | }
|
nkeynes@995 | 108 |
|
nkeynes@995 | 109 | static inline void CALL2_ptr_r32_r32( void *ptr, int arg1, int arg2 )
|
nkeynes@539 | 110 | {
|
nkeynes@991 | 111 | SUBL_imms_r32( 8, REG_ESP );
|
nkeynes@539 | 112 | PUSH_r32(arg2);
|
nkeynes@539 | 113 | PUSH_r32(arg1);
|
nkeynes@995 | 114 | CALL_ptr(ptr);
|
nkeynes@995 | 115 | ADDL_imms_r32( 16, REG_ESP );
|
nkeynes@995 | 116 | }
|
nkeynes@995 | 117 |
|
nkeynes@995 | 118 | static inline void CALL2_r32disp_r32_r32( int preg, uint32_t disp, int arg1, int arg2 )
|
nkeynes@995 | 119 | {
|
nkeynes@995 | 120 | SUBL_imms_r32( 8, REG_ESP );
|
nkeynes@995 | 121 | PUSH_r32(arg2);
|
nkeynes@995 | 122 | PUSH_r32(arg1);
|
nkeynes@995 | 123 | CALL_r32disp(preg, disp);
|
nkeynes@995 | 124 | ADDL_imms_r32( 16, REG_ESP );
|
nkeynes@995 | 125 | }
|
nkeynes@995 | 126 |
|
nkeynes@995 | 127 | static inline void CALL3_r32disp_r32_r32_r32( int preg, uint32_t disp, int arg1, int arg2, int arg3 )
|
nkeynes@995 | 128 | {
|
nkeynes@995 | 129 | SUBL_imms_r32( 8, REG_ESP );
|
nkeynes@995 | 130 | PUSH_r32(arg2);
|
nkeynes@995 | 131 | PUSH_r32(arg1);
|
nkeynes@995 | 132 | MOVL_rspdisp_r32( 16, REG_EAX );
|
nkeynes@1146 | 133 | MOVL_r32_rspdisp( REG_EAX, 8 );
|
nkeynes@995 | 134 | CALL_r32disp(preg,disp);
|
nkeynes@991 | 135 | ADDL_imms_r32( 16, REG_ESP );
|
nkeynes@539 | 136 | }
|
nkeynes@926 | 137 |
|
nkeynes@905 | 138 | #endif
|
nkeynes@539 | 139 |
|
nkeynes@1112 | 140 | #define PROLOGUE_SIZE 9
|
nkeynes@1112 | 141 |
|
nkeynes@539 | 142 | /**
|
nkeynes@539 | 143 | * Emit the 'start of block' assembly. Sets up the stack frame and save
|
nkeynes@539 | 144 | * SI/DI as required
|
nkeynes@926 | 145 | * Allocates 8 bytes for local variables, which also has the convenient
|
nkeynes@926 | 146 | * side-effect of aligning the stack.
|
nkeynes@539 | 147 | */
|
nkeynes@1125 | 148 | static inline void emit_prologue( )
|
nkeynes@539 | 149 | {
|
nkeynes@991 | 150 | PUSH_r32(REG_EBP);
|
nkeynes@991 | 151 | SUBL_imms_r32( 8, REG_ESP );
|
nkeynes@1112 | 152 | MOVP_immptr_rptr( ((uint8_t *)&sh4r) + 128, REG_EBP );
|
nkeynes@926 | 153 | }
|
nkeynes@736 | 154 |
|
nkeynes@1125 | 155 | static inline void emit_epilogue( )
|
nkeynes@926 | 156 | {
|
nkeynes@991 | 157 | ADDL_imms_r32( 8, REG_ESP );
|
nkeynes@991 | 158 | POP_r32(REG_EBP);
|
nkeynes@539 | 159 | }
|
nkeynes@1125 | 160 |
|