Mercurial > repos > blastem
diff gen_x86.c @ 656:24ccfd70133a
Added 2 new functions to gen_x86.c for handling passing args according to the C abi of the host system and adapted the code in m68k_core_x86.c to use that instead of doing everything by hand
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Thu, 01 Jan 2015 19:15:05 -0800 |
parents | 8c7b63f9fab8 |
children | d0943769353b |
line wrap: on
line diff
--- a/gen_x86.c Thu Jan 01 17:36:23 2015 -0800 +++ b/gen_x86.c Thu Jan 01 19:15:05 2015 -0800 @@ -8,6 +8,8 @@ #include <stddef.h> #include <stdio.h> #include <stdlib.h> +#include <stdarg.h> +#include <string.h> #define REX_RM_FIELD 0x1 #define REX_SIB_FIELD 0x2 @@ -1953,3 +1955,87 @@ code->cur = out; } +uint32_t prep_args(code_info *code, uint32_t num_args, va_list args) +{ + uint8_t *arg_arr = malloc(num_args); + for (int i = 0; i < num_args; i ++) + { + arg_arr[i] = va_arg(args, int); + } +#ifdef X86_64 + uint32_t stack_args = 0; + uint8_t abi_regs[] = {RDI, RSI, RDX, RCX, R8, R9}; + int8_t reg_swap[R15+1]; + uint32_t usage = 0; + memset(reg_swap, -1, sizeof(reg_swap)); + for (int i = 0; i < num_args; i ++) + { + usage |= 1 << arg_arr[i]; + } + for (int i = 0; i < num_args; i ++) + { + uint8_t reg_arg = arg_arr[i]; + if (i < sizeof(abi_regs)) { + if (reg_swap[reg_arg] >= 0) { + reg_arg = reg_swap[reg_arg]; + } + if (reg_arg != abi_regs[i]) { + if (usage & (1 << abi_regs[i])) { + xchg_rr(code, reg_arg, abi_regs[i], SZ_PTR); + reg_swap[abi_regs[i]] = reg_arg; + } else { + mov_rr(code, reg_arg, abi_regs[i], SZ_PTR); + } + } + } else { + arg_arr[stack_args++] = reg_arg; + } + } +#else +#define stack_args num_args +#endif + for (int i = stack_args -1; i >= 0; i--) + { + push_r(code, arg_arr[i]); + } + + return stack_args * sizeof(void *); +} + +void call_args(code_info *code, code_ptr fun, uint32_t num_args, ...) +{ + va_list args; + va_start(args, num_args); + uint32_t adjust = prep_args(code, num_args, args); + va_end(args); + call(code, fun); + if (adjust) { + add_ir(code, adjust, RSP, SZ_PTR); + } +} + +void call_args_abi(code_info *code, code_ptr fun, uint32_t num_args, ...) +{ + va_list args; + va_start(args, num_args); + uint32_t adjust = prep_args(code, num_args, args); + va_end(args); +#ifdef X86_64 + test_ir(code, 8, RSP, SZ_PTR); //check stack alignment + code_ptr do_adjust_rsp = code->cur + 1; + jcc(code, CC_NZ, code->cur + 2); +#endif + call(code, fun); + if (adjust) { + add_ir(code, adjust, RSP, SZ_PTR); + } +#ifdef X86_64 + code_ptr no_adjust_rsp = code->cur + 1; + jmp(code, code->cur + 2); + *do_adjust_rsp = code->cur - (do_adjust_rsp+1); + sub_ir(code, 8, RSP, SZ_PTR); + call(code, fun); + add_ir(code, adjust + 8 , RSP, SZ_PTR); + *no_adjust_rsp = code->cur - (no_adjust_rsp+1); +#endif +}