nkeynes@539: /** nkeynes@586: * $Id$ nkeynes@539: * nkeynes@926: * Provides the implementation for the ia32 ABI variant nkeynes@926: * (eg prologue, epilogue, and calling conventions). Stack frame is nkeynes@926: * aligned on 16-byte boundaries for the benefit of OS X (which nkeynes@926: * requires it). nkeynes@995: * nkeynes@995: * Note: These should only be included from x86op.h nkeynes@539: * nkeynes@539: * Copyright (c) 2007 Nathan Keynes. nkeynes@539: * nkeynes@539: * This program is free software; you can redistribute it and/or modify nkeynes@539: * it under the terms of the GNU General Public License as published by nkeynes@539: * the Free Software Foundation; either version 2 of the License, or nkeynes@539: * (at your option) any later version. nkeynes@539: * nkeynes@539: * This program is distributed in the hope that it will be useful, nkeynes@539: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@539: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@539: * GNU General Public License for more details. nkeynes@539: */ nkeynes@539: nkeynes@995: #define REG_ARG1 REG_EAX nkeynes@995: #define REG_ARG2 REG_EDX nkeynes@995: #define REG_RESULT1 REG_EAX nkeynes@995: #define MAX_REG_ARG 2 nkeynes@539: nkeynes@1004: static inline void decode_address( uintptr_t base, int addr_reg ) nkeynes@953: { nkeynes@995: MOVL_r32_r32( addr_reg, REG_ECX ); nkeynes@991: SHRL_imm_r32( 12, REG_ECX ); nkeynes@991: MOVP_sib_rptr( 2, REG_ECX, -1, base, REG_ECX ); nkeynes@953: } nkeynes@953: nkeynes@539: /** nkeynes@995: * Note: clobbers ECX to make the indirect call - this isn't usually nkeynes@995: * a problem since the callee will generally clobber it anyway. nkeynes@539: */ nkeynes@995: static inline void CALL_ptr( void *ptr ) nkeynes@539: { nkeynes@995: MOVP_immptr_rptr( (uintptr_t)ptr, REG_ECX ); nkeynes@991: CALL_r32(REG_ECX); nkeynes@539: } nkeynes@539: nkeynes@905: #ifdef HAVE_FASTCALL nkeynes@1146: #define CALL1_PTR_MIN_SIZE 7 nkeynes@1146: nkeynes@995: static inline void CALL1_ptr_r32( void *ptr, int arg1 ) nkeynes@905: { nkeynes@995: if( arg1 != REG_ARG1 ) { nkeynes@995: MOVL_r32_r32( arg1, REG_ARG1 ); nkeynes@905: } nkeynes@995: CALL_ptr(ptr); nkeynes@953: } nkeynes@953: nkeynes@995: static inline void CALL1_r32disp_r32( int preg, uint32_t disp, int arg1 ) nkeynes@953: { nkeynes@995: if( arg1 != REG_ARG1 ) { nkeynes@995: MOVL_r32_r32( arg1, REG_ARG1 ); nkeynes@953: } nkeynes@995: CALL_r32disp(preg, disp); nkeynes@953: } nkeynes@953: nkeynes@995: static inline void CALL2_ptr_r32_r32( void *ptr, int arg1, int arg2 ) nkeynes@953: { nkeynes@995: if( arg2 != REG_ARG2 ) { nkeynes@995: MOVL_r32_r32( arg2, REG_ARG2 ); nkeynes@953: } nkeynes@995: if( arg1 != REG_ARG1 ) { nkeynes@995: MOVL_r32_r32( arg1, REG_ARG1 ); nkeynes@995: } nkeynes@995: CALL_ptr(ptr); nkeynes@953: } nkeynes@953: nkeynes@995: static inline void CALL2_r32disp_r32_r32( int preg, uint32_t disp, int arg1, int arg2 ) nkeynes@953: { nkeynes@995: if( arg2 != REG_ARG2 ) { nkeynes@995: MOVL_r32_r32( arg2, REG_ARG2 ); nkeynes@953: } nkeynes@995: if( arg1 != REG_ARG1 ) { nkeynes@995: MOVL_r32_r32( arg1, REG_ARG1 ); nkeynes@995: } nkeynes@995: CALL_r32disp(preg, disp); nkeynes@905: } nkeynes@905: nkeynes@995: #define CALL3_r32disp_r32_r32_r32(preg,disp,arg1,arg2,arg3) CALL2_r32disp_r32_r32(preg,disp,arg1,arg2) nkeynes@927: nkeynes@905: #else nkeynes@1146: nkeynes@1146: #define CALL1_PTR_MIN_SIZE (3+1+7+3) nkeynes@1146: nkeynes@1146: static inline void CALL1_ptr_r32( void *ptr, int arg1 ) nkeynes@539: { nkeynes@991: SUBL_imms_r32( 12, REG_ESP ); nkeynes@539: PUSH_r32(arg1); nkeynes@995: CALL_ptr(ptr); nkeynes@991: ADDL_imms_r32( 16, REG_ESP ); nkeynes@539: } nkeynes@539: nkeynes@995: static inline void CALL1_r32disp_r32( int preg, uint32_t disp, int arg1 ) nkeynes@995: { nkeynes@995: SUBL_imms_r32( 12, REG_ESP ); nkeynes@995: PUSH_r32(arg1); nkeynes@995: CALL_r32disp(preg, disp); nkeynes@995: ADDL_imms_r32( 16, REG_ESP ); nkeynes@995: } nkeynes@995: nkeynes@995: static inline void CALL2_ptr_r32_r32( void *ptr, int arg1, int arg2 ) nkeynes@539: { nkeynes@991: SUBL_imms_r32( 8, REG_ESP ); nkeynes@539: PUSH_r32(arg2); nkeynes@539: PUSH_r32(arg1); nkeynes@995: CALL_ptr(ptr); nkeynes@995: ADDL_imms_r32( 16, REG_ESP ); nkeynes@995: } nkeynes@995: nkeynes@995: static inline void CALL2_r32disp_r32_r32( int preg, uint32_t disp, int arg1, int arg2 ) nkeynes@995: { nkeynes@995: SUBL_imms_r32( 8, REG_ESP ); nkeynes@995: PUSH_r32(arg2); nkeynes@995: PUSH_r32(arg1); nkeynes@995: CALL_r32disp(preg, disp); nkeynes@995: ADDL_imms_r32( 16, REG_ESP ); nkeynes@995: } nkeynes@995: nkeynes@995: static inline void CALL3_r32disp_r32_r32_r32( int preg, uint32_t disp, int arg1, int arg2, int arg3 ) nkeynes@995: { nkeynes@995: SUBL_imms_r32( 8, REG_ESP ); nkeynes@995: PUSH_r32(arg2); nkeynes@995: PUSH_r32(arg1); nkeynes@995: MOVL_rspdisp_r32( 16, REG_EAX ); nkeynes@1146: MOVL_r32_rspdisp( REG_EAX, 8 ); nkeynes@995: CALL_r32disp(preg,disp); nkeynes@991: ADDL_imms_r32( 16, REG_ESP ); nkeynes@539: } nkeynes@926: nkeynes@905: #endif nkeynes@539: nkeynes@1112: #define PROLOGUE_SIZE 9 nkeynes@1112: nkeynes@539: /** nkeynes@539: * Emit the 'start of block' assembly. Sets up the stack frame and save nkeynes@539: * SI/DI as required nkeynes@926: * Allocates 8 bytes for local variables, which also has the convenient nkeynes@926: * side-effect of aligning the stack. nkeynes@539: */ nkeynes@1125: static inline void emit_prologue( ) nkeynes@539: { nkeynes@991: PUSH_r32(REG_EBP); nkeynes@991: SUBL_imms_r32( 8, REG_ESP ); nkeynes@1112: MOVP_immptr_rptr( ((uint8_t *)&sh4r) + 128, REG_EBP ); nkeynes@926: } nkeynes@736: nkeynes@1125: static inline void emit_epilogue( ) nkeynes@926: { nkeynes@991: ADDL_imms_r32( 8, REG_ESP ); nkeynes@991: POP_r32(REG_EBP); nkeynes@539: } nkeynes@1125: