From 9c1af08af2b6634a426302ef3ba1ca00a41da65a Mon Sep 17 00:00:00 2001 From: Rhys Weatherley Date: Fri, 18 Jun 2004 06:51:33 +0000 Subject: [PATCH] Rewrite the x86 and ARM parameter handling routines to centralise the code and fix several bugs; add new tests for fastcall and stdcall conventions. --- ChangeLog | 9 + jit/jit-dump.c | 12 +- jit/jit-reg-alloc.c | 23 +- jit/jit-rules-arm.c | 323 ------------------- jit/jit-rules-arm.h | 10 + jit/jit-rules-x86.c | 598 +++++------------------------------ jit/jit-rules-x86.h | 9 + jit/jit-rules-x86.sel | 25 +- jit/jit-rules.c | 709 ++++++++++++++++++++++++++++++++++++++++++ jit/jit-rules.h | 1 + tests/param.pas | 332 ++++++++++++++++++++ 11 files changed, 1202 insertions(+), 849 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0eed2f9..9fb4eca 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,13 @@ +2004-06-18 Rhys Weatherley + + * jit/jit-dump.c, jit/jit-reg-alloc.c, jit/jit-rules-arm.c, + jit/jit-rules-arm.h, jit/jit-rules-x86.c, jit/jit-rules-x86.h, + jit/jit-rules-x86.sel, jit/jit-rules.c, jit/jit-rules.h, + tests/param.pas: rewrite the x86 and ARM parameter handling + routines to centralise the code and fix several bugs; add new + tests for fastcall and stdcall conventions. + 2004-06-17 Rhys Weatherley * jit/jit-reg-alloc.c (_jit_regs_set_outgoing): pass 64-bit "fastcall" diff --git a/jit/jit-dump.c b/jit/jit-dump.c index adcd4cf..78bc1fa 100644 --- a/jit/jit-dump.c +++ b/jit/jit-dump.c @@ -188,7 +188,7 @@ void jit_dump_value(FILE *stream, jit_function_t func, jit_value_t value, const case JIT_TYPE_FLOAT32: { - jit_snprintf(buf, sizeof(buf), "%g", + jit_snprintf(buf, sizeof(buf), "%f", (double)(const_value.un.float32_value)); name = buf; } @@ -196,7 +196,7 @@ void jit_dump_value(FILE *stream, jit_function_t func, jit_value_t value, const case JIT_TYPE_FLOAT64: { - jit_snprintf(buf, sizeof(buf), "%g", + jit_snprintf(buf, sizeof(buf), "%f", (double)(const_value.un.float64_value)); name = buf; } @@ -204,7 +204,7 @@ void jit_dump_value(FILE *stream, jit_function_t func, jit_value_t value, const case JIT_TYPE_NFLOAT: { - jit_snprintf(buf, sizeof(buf), "%g", + jit_snprintf(buf, sizeof(buf), "%f", (double)(const_value.un.nfloat_value)); name = buf; } @@ -572,7 +572,7 @@ static void dump_interp_code(FILE *stream, void **pc, void **end) jit_memcpy(&value, pc, sizeof(jit_float32)); pc += (sizeof(jit_float32) + sizeof(void *) - 1) / sizeof(void *); - fprintf(stream, " %g", (double)value); + fprintf(stream, " %f", (double)value); } break; @@ -582,7 +582,7 @@ static void dump_interp_code(FILE *stream, void **pc, void **end) jit_memcpy(&value, pc, sizeof(jit_float64)); pc += (sizeof(jit_float64) + sizeof(void *) - 1) / sizeof(void *); - fprintf(stream, " %g", (double)value); + fprintf(stream, " %f", (double)value); } break; @@ -592,7 +592,7 @@ static void dump_interp_code(FILE *stream, void **pc, void **end) jit_memcpy(&value, pc, sizeof(jit_nfloat)); pc += (sizeof(jit_nfloat) + sizeof(void *) - 1) / sizeof(void *); - fprintf(stream, " %g", (double)value); + fprintf(stream, " %f", (double)value); } break; diff --git a/jit/jit-reg-alloc.c b/jit/jit-reg-alloc.c index 7a1842c..4348f5c 100644 --- a/jit/jit-reg-alloc.c +++ b/jit/jit-reg-alloc.c @@ -55,6 +55,7 @@ void _jit_regs_init_for_block(jit_gencode_t gen) } gen->stack_map[reg] = -1; } + gen->inhibit = jit_regused_init; } /*@ @@ -749,10 +750,22 @@ void _jit_regs_set_outgoing(jit_gencode_t gen, int reg, jit_value_t value) int other_reg; int need_pair; - need_pair = _jit_regs_needs_long_pair(value->type); #ifdef JIT_BACKEND_X86 + jit_type_t type; + type = jit_type_normalize(value->type); + need_pair = 0; + if(type) + { + /* We might need to put float values in register pairs under x86 */ + if(type->kind == JIT_TYPE_LONG || type->kind == JIT_TYPE_ULONG || + type->kind == JIT_TYPE_FLOAT64 || type->kind == JIT_TYPE_NFLOAT) + { + need_pair = 1; + } + } if(value->in_register && value->reg == reg && !need_pair) #else + need_pair = _jit_regs_needs_long_pair(value->type); if(value->in_register && value->reg == reg) #endif { @@ -789,11 +802,14 @@ void _jit_regs_set_outgoing(jit_gencode_t gen, int reg, jit_value_t value) other_reg = _jit_reg_info[reg].other_reg; #endif _jit_gen_load_value(gen, reg, other_reg, value); + jit_reg_set_used(gen->inhibit, reg); + jit_reg_set_used(gen->inhibit, other_reg); } else { _jit_regs_want_reg(gen, reg, 0); _jit_gen_load_value(gen, reg, -1, value); + jit_reg_set_used(gen->inhibit, reg); } } } @@ -956,7 +972,8 @@ static int free_register_for_value for(reg = 0; reg < JIT_NUM_REGS; ++reg) { if((_jit_reg_info[reg].flags & type) != 0 && - !jit_reg_is_used(gen->permanent, reg)) + !jit_reg_is_used(gen->permanent, reg) && + !jit_reg_is_used(gen->inhibit, reg)) { if((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) != 0) { @@ -1437,7 +1454,7 @@ void _jit_regs_force_out(jit_gencode_t gen, jit_value_t value, int is_dest) else { /* Always do a spill for a stack register */ - _jit_regs_want_reg(gen, value->reg, 0); + spill_register(gen, value->reg); } } } diff --git a/jit/jit-rules-arm.c b/jit/jit-rules-arm.c index 24e36c5..0c361e1 100644 --- a/jit/jit-rules-arm.c +++ b/jit/jit-rules-arm.c @@ -347,329 +347,6 @@ static void mov_freg_imm_64 jit_gen_load_inst_ptr(gen, *inst); } -/* - * Force values out of parameter registers that cannot be easily - * accessed in register form (i.e. long, float, and struct values). - */ -static int force_out_of_regs(jit_function_t func, jit_value_t param, - int next_reg, unsigned int size) -{ - jit_value_t address; - jit_value_t temp; - jit_nint offset = 0; - jit_nint frame_offset = sizeof(void *); - - /* Get the address of the parameter, to force it into the frame, - and to set up for the later "jit_insn_store_relative" calls */ - address = jit_insn_address_of(func, param); - if(!address) - { - return 0; - } - - /* Force the values out of the registers */ - while(next_reg < ARM_NUM_PARAM_REGS && size > 0) - { - temp = jit_value_create(func, jit_type_void_ptr); - if(!temp) - { - return 0; - } - if(!jit_insn_incoming_reg(func, temp, next_reg)) - { - return 0; - } - if(!jit_insn_store_relative(func, address, offset, temp)) - { - return 0; - } - offset += sizeof(void *); - size -= sizeof(void *); - ++next_reg; - } - - - /* Force the rest of the value out of the incoming stack frame */ - while(size > 0) - { - temp = jit_value_create(func, jit_type_void_ptr); - if(!temp) - { - return 0; - } - if(!jit_insn_incoming_frame_posn(func, temp, frame_offset)) - { - return 0; - } - if(!jit_insn_store_relative(func, address, offset, temp)) - { - return 0; - } - offset += sizeof(void *); - frame_offset += sizeof(void *); - size -= sizeof(void *); - } - return 1; -} - -int _jit_create_entry_insns(jit_function_t func) -{ - jit_type_t signature = func->signature; - jit_type_t type; - int next_reg; - jit_nint offset; - jit_value_t value; - unsigned int num_params; - unsigned int param; - unsigned int size; - - /* Reset the frame size for this function. We start by assuming - that lr, sp, fp, r8, r7, r6, r5, and r4 need to be saved in - the local frame, as that is the worst-case scenario */ - func->builder->frame_size = 8 * sizeof(void *); - - /* The next register to be allocated to parameters is r0 */ - next_reg = 0; - - /* The starting parameter offset (saved pc on stack) */ - offset = sizeof(void *); - - /* If the function is nested, then we need an extra parameter - to pass the pointer to the parent's local variable frame */ - if(func->nested_parent) - { - ++next_reg; - } - - /* Allocate the structure return pointer */ - value = jit_value_get_struct_pointer(func); - if(value) - { - if(!jit_insn_incoming_reg(func, value, next_reg)) - { - return 0; - } - ++next_reg; - } - - /* Allocate the parameter registers and offsets */ - num_params = jit_type_num_params(signature); - for(param = 0; param < num_params; ++param) - { - value = jit_value_get_param(func, param); - if(!value) - { - continue; - } - type = jit_type_normalize(jit_value_get_type(value)); - switch(type->kind) - { - case JIT_TYPE_SBYTE: - case JIT_TYPE_UBYTE: - case JIT_TYPE_SHORT: - case JIT_TYPE_USHORT: - case JIT_TYPE_INT: - case JIT_TYPE_UINT: - case JIT_TYPE_NINT: - case JIT_TYPE_NUINT: - case JIT_TYPE_SIGNATURE: - case JIT_TYPE_PTR: - { - if(next_reg < ARM_NUM_PARAM_REGS) - { - if(!jit_insn_incoming_reg(func, value, next_reg)) - { - return 0; - } - ++next_reg; - } - else - { - if(!jit_insn_incoming_frame_posn(func, value, offset)) - { - return 0; - } - offset += sizeof(void *); - } - } - break; - - case JIT_TYPE_LONG: - case JIT_TYPE_ULONG: - case JIT_TYPE_FLOAT32: - case JIT_TYPE_FLOAT64: - case JIT_TYPE_NFLOAT: - case JIT_TYPE_STRUCT: - case JIT_TYPE_UNION: - { - /* Force these kinds of values out of the word registers. - While technically we could keep long and float values - in word registers on ARM, it simplifies the register - allocator if we force them out first */ - size = ROUND_STACK(jit_type_get_size(type)); - if(next_reg < ARM_NUM_PARAM_REGS) - { - if((ARM_NUM_PARAM_REGS - next_reg) >= size) - { - if(!force_out_of_regs(func, value, next_reg, size)) - { - return 0; - } - while(size > 0 && next_reg < ARM_NUM_PARAM_REGS) - { - ++next_reg; - size -= sizeof(void *); - } - } - else - { - /* Cannot overlap registers and the stack */ - next_reg = ARM_NUM_PARAM_REGS; - if(!jit_insn_incoming_frame_posn(func, value, offset)) - { - return 0; - } - } - offset += size; - } - else - { - /* The value is completely on the stack */ - if(!jit_insn_incoming_frame_posn(func, value, offset)) - { - return 0; - } - offset += size; - } - } - break; - } - } - return 1; -} - -int _jit_create_call_setup_insns - (jit_function_t func, jit_type_t signature, - jit_value_t *args, unsigned int num_args, - int is_nested, int nesting_level, jit_value_t *struct_return, int flags) -{ - jit_type_t type = jit_type_get_return(signature); - jit_value_t value; - unsigned int size; - unsigned int index; - unsigned int num_stack_args; - unsigned int word_regs; - unsigned int param_offset; - - /* Determine which values are going to end up in registers */ - word_regs = 0; - if(func->nested_parent) - { - ++word_regs; - } - if(jit_type_return_via_pointer(type)) - { - ++word_regs; - } - index = 0; - while(index < num_args && word_regs < ARM_NUM_PARAM_REGS) - { - size = jit_type_get_size(jit_value_get_type(args[index])); - size = ROUND_STACK(size) / sizeof(void *); - if(size <= (ARM_NUM_PARAM_REGS - word_regs)) - { - /* This argument will fit entirely in registers */ - word_regs += size; - ++index; - } - else - { - /* The rest of the arguments go onto the stack */ - break; - } - } - num_stack_args = num_args - index; - - /* Determine the highest parameter offset */ - param_offset = 0; - for(index = 0; index < num_stack_args; ++index) - { - size = jit_type_get_size - (jit_value_get_type(args[num_args - 1 - index])); - param_offset += ROUND_STACK(size); - } - if(param_offset > (unsigned int)(func->builder->param_area_size)) - { - func->builder->param_area_size = (jit_nint)param_offset; - } - - /* Set all of the stacked arguments in reverse order. We set them - into the outgoing parameter area, which allows us to avoid constantly - updating the stack pointer when pushing stacked arguments */ - while(num_stack_args > 0) - { - --num_stack_args; - --num_args; - size = jit_type_get_size(jit_value_get_type(args[num_args])); - param_offset -= ROUND_STACK(size); - if(!jit_insn_set_param(func, args[num_args], (jit_nint)param_offset)) - { - return 0; - } - } - - /* Push arguments that will end up entirely in registers */ - while(num_args > 0) - { - --num_args; - size = jit_type_get_size(jit_value_get_type(args[num_args])); - size = ROUND_STACK(size) / sizeof(void *); - word_regs -= size; - if(!jit_insn_outgoing_reg(func, args[num_args], (int)word_regs)) - { - return 0; - } - } - - /* Do we need to add a structure return pointer argument? */ - if(jit_type_return_via_pointer(type)) - { - value = jit_value_create(func, type); - if(!value) - { - return 0; - } - *struct_return = value; - value = jit_insn_address_of(func, value); - if(!value) - { - return 0; - } - --word_regs; - if(!jit_insn_outgoing_reg(func, value, (int)word_regs)) - { - return 0; - } - } - else - { - *struct_return = 0; - } - - /* Do we need to add nested function scope information? */ - if(is_nested) - { - --word_regs; - if(!jit_insn_setup_for_nested(func, nesting_level, (int)word_regs)) - { - return 0; - } - } - - /* The call is ready to proceed */ - return 1; -} - int _jit_setup_indirect_pointer(jit_function_t func, jit_value_t value) { return jit_insn_outgoing_reg(func, value, ARM_WORK); diff --git a/jit/jit-rules-arm.h b/jit/jit-rules-arm.h index 935fdb7..0e9e642 100644 --- a/jit/jit-rules-arm.h +++ b/jit/jit-rules-arm.h @@ -114,6 +114,16 @@ extern "C" { } while (0) #define jit_extra_gen_cleanup(gen) do { ; } while (0) +/* + * Parameter passing rules. We start by assuming that lr, sp, fp, + r8, r7, r6, r5, and r4 need to be saved in the local frame. + */ +#define JIT_CDECL_WORD_REG_PARAMS {0, 1, 2, 3, -1} +#define JIT_MAX_WORD_REG_PARAMS 4 +#define JIT_INITIAL_STACK_OFFSET (sizeof(void *)) +#define JIT_INITIAL_FRAME_SIZE (8 * sizeof(void *)) +#define JIT_USE_PARAM_AREA 1 + #ifdef __cplusplus }; #endif diff --git a/jit/jit-rules-x86.c b/jit/jit-rules-x86.c index d2b5b40..76c60e8 100644 --- a/jit/jit-rules-x86.c +++ b/jit/jit-rules-x86.c @@ -51,6 +51,12 @@ #define X86_REG_ST6 14 #define X86_REG_ST7 15 +/* + * Determine if a pseudo register number is word-based or float-based. + */ +#define IS_WORD_REG(reg) ((reg) < X86_REG_ST0) +#define IS_FLOAT_REG(reg) ((reg) >= X86_REG_ST0) + /* * Round a size up to a multiple of the stack word size. */ @@ -77,504 +83,6 @@ void _jit_gen_get_elf_info(jit_elf_info_t *info) info->abi_version = 0; } -/* - * Force values out of fastcall registers that cannot be easily - * accessed in register form (i.e. long, float, and struct values). - */ -static int force_out_of_regs(jit_function_t func, jit_value_t param, - int num_regs, unsigned int num_stack_words) -{ - jit_value_t address; - jit_value_t temp; - jit_nint offset = 0; - jit_nint frame_offset = 2 * sizeof(void *); - - /* Get the address of the parameter, to force it into the frame, - and to set up for the later "jit_insn_store_relative" calls */ - address = jit_insn_address_of(func, param); - if(!address) - { - return 0; - } - - /* Force the values out of the registers */ - while(num_regs > 0) - { - temp = jit_value_create(func, jit_type_void_ptr); - if(!temp) - { - return 0; - } - if(num_regs == 2) - { - if(!jit_insn_incoming_reg(func, temp, X86_REG_ECX)) - { - return 0; - } - } - else - { - if(!jit_insn_incoming_reg(func, temp, X86_REG_EDX)) - { - return 0; - } - } - if(!jit_insn_store_relative(func, address, offset, temp)) - { - return 0; - } - offset += sizeof(void *); - --num_regs; - } - - - /* Force the rest of the value out of the incoming stack frame */ - while(num_stack_words > 0) - { - temp = jit_value_create(func, jit_type_void_ptr); - if(!temp) - { - return 0; - } - if(!jit_insn_incoming_frame_posn(func, temp, frame_offset)) - { - return 0; - } - if(!jit_insn_store_relative(func, address, offset, temp)) - { - return 0; - } - offset += sizeof(void *); - frame_offset += sizeof(void *); - --num_stack_words; - } - return 1; -} - -int _jit_create_entry_insns(jit_function_t func) -{ - jit_type_t signature = func->signature; - jit_type_t type; - int num_regs; - jit_nint offset; - jit_value_t value; - unsigned int num_params; - unsigned int param; - unsigned int size; - unsigned int num_stack_words; - - /* Reset the local variable frame size for this function */ - func->builder->frame_size = 0; - - /* Determine the number of registers to allocate to parameters */ -#if JIT_APPLY_X86_FASTCALL == 1 - if(jit_type_get_abi(signature) == jit_abi_fastcall) - { - num_regs = 2; - } - else -#endif - { - num_regs = 0; - } - - /* The starting parameter offset (saved ebp and return address on stack) */ - offset = 2 * sizeof(void *); - - /* If the function is nested, then we need an extra parameter - to pass the pointer to the parent's local variable frame */ - if(func->nested_parent) - { - if(num_regs > 0) - { - --num_regs; - } - else - { - offset += sizeof(void *); - } - } - - /* Allocate the structure return pointer */ - value = jit_value_get_struct_pointer(func); - if(value) - { - if(num_regs == 2) - { - if(!jit_insn_incoming_reg(func, value, X86_REG_ECX)) - { - return 0; - } - --num_regs; - } - else if(num_regs == 1) - { - if(!jit_insn_incoming_reg(func, value, X86_REG_EDX)) - { - return 0; - } - --num_regs; - } - else - { - if(!jit_insn_incoming_frame_posn(func, value, offset)) - { - return 0; - } - offset += sizeof(void *); - } - } - - /* Allocate the parameter offsets */ - num_params = jit_type_num_params(signature); - for(param = 0; param < num_params; ++param) - { - value = jit_value_get_param(func, param); - if(!value) - { - continue; - } - type = jit_type_normalize(jit_value_get_type(value)); - switch(type->kind) - { - case JIT_TYPE_SBYTE: - case JIT_TYPE_UBYTE: - case JIT_TYPE_SHORT: - case JIT_TYPE_USHORT: - case JIT_TYPE_INT: - case JIT_TYPE_UINT: - case JIT_TYPE_NINT: - case JIT_TYPE_NUINT: - case JIT_TYPE_SIGNATURE: - case JIT_TYPE_PTR: - { - if(num_regs == 2) - { - if(!jit_insn_incoming_reg(func, value, X86_REG_ECX)) - { - return 0; - } - --num_regs; - } - else if(num_regs == 1) - { - if(!jit_insn_incoming_reg(func, value, X86_REG_EDX)) - { - return 0; - } - --num_regs; - } - else - { - if(!jit_insn_incoming_frame_posn(func, value, offset)) - { - return 0; - } - offset += sizeof(void *); - } - } - break; - - case JIT_TYPE_LONG: - case JIT_TYPE_ULONG: - case JIT_TYPE_FLOAT32: - case JIT_TYPE_FLOAT64: - case JIT_TYPE_NFLOAT: - case JIT_TYPE_STRUCT: - case JIT_TYPE_UNION: - { - /* Deal with the possibility that the value may be split - between registers and the stack */ - size = ROUND_STACK(jit_type_get_size(type)); - if(num_regs == 2) - { - if(size <= sizeof(void *)) - { - if(!force_out_of_regs(func, value, 1, 0)) - { - return 0; - } - --num_regs; - } - else - { - num_stack_words = (size / sizeof(void *)) - 2; - if(!force_out_of_regs(func, value, 2, num_stack_words)) - { - return 0; - } - num_regs = 0; - offset += num_stack_words * sizeof(void *); - } - } - else if(num_regs == 1) - { - num_stack_words = (size / sizeof(void *)) - 1; - if(!force_out_of_regs(func, value, 1, num_stack_words)) - { - return 0; - } - num_regs = 0; - offset += num_stack_words * sizeof(void *); - } - else - { - if(!jit_insn_incoming_frame_posn(func, value, offset)) - { - return 0; - } - offset += size; - } - } - break; - } - } - return 1; -} - -int _jit_create_call_setup_insns - (jit_function_t func, jit_type_t signature, - jit_value_t *args, unsigned int num_args, - int is_nested, int nesting_level, jit_value_t *struct_return, int flags) -{ - jit_type_t type = jit_type_get_return(signature); - jit_value_t value; - unsigned int size; - unsigned int index; - unsigned int num_stack_args; - unsigned int word_regs; - jit_value_t partial; - - /* Determine which values are going to end up in fastcall registers */ -#if JIT_APPLY_X86_FASTCALL == 1 - if(jit_type_get_abi(signature) == jit_abi_fastcall) - { - word_regs = 0; - if(func->nested_parent) - { - ++word_regs; - } - if(jit_type_return_via_pointer(type)) - { - ++word_regs; - } - index = 0; - partial = 0; - while(index < num_args && word_regs < 2) - { - size = jit_type_get_size(jit_value_get_type(args[index])); - size = ROUND_STACK(size) / sizeof(void *); - if(size <= (2 - word_regs)) - { - /* This argument will fit entirely in registers */ - word_regs += size; - ++index; - } - else - { - /* Partly in registers and partly on the stack. - We first copy it into a buffer that we can address */ - partial = jit_value_create - (func, jit_value_get_type(args[index])); - if(!partial) - { - return 0; - } - jit_value_set_addressable(partial); - if(!jit_insn_store(func, partial, args[index])) - { - return 0; - } - ++index; - break; - } - } - num_stack_args = num_args - index; - } - else -#endif - { - word_regs = 0; - partial = 0; - num_stack_args = num_args; - } - - /* Flush deferred stack pops from previous calls if too many - parameters have collected up on the stack since last time */ - if(!jit_insn_flush_defer_pop - (func, 32 - (jit_nint)(num_stack_args * sizeof(void *)))) - { - return 0; - } - - /* Push all of the stacked arguments in reverse order */ - while(num_stack_args > 0) - { - --num_stack_args; - --num_args; - if(!jit_insn_push(func, args[num_args])) - { - return 0; - } - } - - /* Handle a value that is partly on the stack and partly in registers */ - if(partial) - { - --num_args; - index = (2 - word_regs) * sizeof(void *); - size = ROUND_STACK(jit_type_get_size(jit_value_get_type(partial))); - while(size > index) - { - size -= sizeof(void *); - value = jit_insn_address_of(func, partial); - if(!value) - { - return 0; - } - value = jit_insn_load_relative - (func, value, (jit_nint)size, jit_type_void_ptr); - if(!value) - { - return 0; - } - if(!jit_insn_push(func, value)) - { - return 0; - } - } - word_regs = 2; - while(size > 0) - { - size -= sizeof(void *); - value = jit_insn_address_of(func, partial); - if(!value) - { - return 0; - } - value = jit_insn_load_relative - (func, value, (jit_nint)size, jit_type_void_ptr); - if(!value) - { - return 0; - } - if(word_regs == 2) - { - if(!jit_insn_outgoing_reg(func, value, X86_REG_EDX)) - { - return 0; - } - --word_regs; - } - else - { - if(!jit_insn_outgoing_reg(func, value, X86_REG_ECX)) - { - return 0; - } - --word_regs; - } - } - } - - /* Push arguments that will end up entirely in registers */ - while(num_args > 0) - { - --num_args; - size = jit_type_get_size(jit_value_get_type(args[num_args])); - size = ROUND_STACK(size) / sizeof(void *); - if(size == 2) - { - if(!jit_insn_outgoing_reg(func, args[num_args], X86_REG_ECX)) - { - return 0; - } - word_regs = 0; - } - else if(word_regs == 2) - { - if(!jit_insn_outgoing_reg(func, args[num_args], X86_REG_EDX)) - { - return 0; - } - --word_regs; - } - else - { - if(!jit_insn_outgoing_reg(func, args[num_args], X86_REG_ECX)) - { - return 0; - } - --word_regs; - } - } - - /* Do we need to add a structure return pointer argument? */ - if(jit_type_return_via_pointer(type)) - { - value = jit_value_create(func, type); - if(!value) - { - return 0; - } - *struct_return = value; - value = jit_insn_address_of(func, value); - if(!value) - { - return 0; - } - if(word_regs == 2) - { - if(!jit_insn_outgoing_reg(func, value, X86_REG_EDX)) - { - return 0; - } - --word_regs; - } - else if(word_regs == 1) - { - if(!jit_insn_outgoing_reg(func, value, X86_REG_ECX)) - { - return 0; - } - --word_regs; - } - else - { - if(!jit_insn_push(func, value)) - { - return 0; - } - } - } - else - { - *struct_return = 0; - } - - /* Do we need to add nested function scope information? */ - if(is_nested) - { - if(word_regs > 0) - { - if(!jit_insn_setup_for_nested(func, nesting_level, X86_REG_ECX)) - { - return 0; - } - } - else - { - if(!jit_insn_setup_for_nested(func, nesting_level, -1)) - { - return 0; - } - } - } - - /* The call is ready to proceed */ - return 1; -} - int _jit_setup_indirect_pointer(jit_function_t func, jit_value_t value) { return jit_insn_outgoing_reg(func, value, X86_REG_EAX); @@ -915,7 +423,7 @@ void _jit_gen_spill_reg(jit_gencode_t gen, int reg, /* Output an appropriate instruction to spill the value */ offset = (int)(value->frame_offset); - if(reg < X86_REG_ST0) + if(IS_WORD_REG(reg)) { /* Spill a word register. If the value is smaller than a word, then we write the entire word. The local stack frame is @@ -964,7 +472,7 @@ void _jit_gen_free_reg(jit_gencode_t gen, int reg, { /* We only need to take explicit action if we are freeing a floating-point register whose value hasn't been used yet */ - if(!value_used && reg >= X86_REG_ST0 && reg <= X86_REG_ST7) + if(!value_used && IS_FLOAT_REG(reg)) { if(jit_cache_check_for_n(&(gen->posn), 2)) { @@ -1029,9 +537,17 @@ void _jit_gen_load_value jit_cache_mark_full(&(gen->posn)); return; } - ptr = _jit_cache_alloc(&(gen->posn), sizeof(jit_float32)); - jit_memcpy(ptr, &float32_value, sizeof(float32_value)); - x86_fld(inst, ptr, 0); + if(IS_WORD_REG(reg)) + { + x86_mov_reg_imm(inst, _jit_reg_info[reg].cpu_reg, + ((jit_int *)&float32_value)[0]); + } + else + { + ptr = _jit_cache_alloc(&(gen->posn), sizeof(jit_float32)); + jit_memcpy(ptr, &float32_value, sizeof(float32_value)); + x86_fld(inst, ptr, 0); + } } break; @@ -1044,9 +560,19 @@ void _jit_gen_load_value jit_cache_mark_full(&(gen->posn)); return; } - ptr = _jit_cache_alloc(&(gen->posn), sizeof(jit_float64)); - jit_memcpy(ptr, &float64_value, sizeof(float64_value)); - x86_fld(inst, ptr, 1); + if(IS_WORD_REG(reg)) + { + x86_mov_reg_imm(inst, _jit_reg_info[reg].cpu_reg, + ((jit_int *)&float64_value)[0]); + x86_mov_reg_imm(inst, _jit_reg_info[other_reg].cpu_reg, + ((jit_int *)&float64_value)[1]); + } + else + { + ptr = _jit_cache_alloc(&(gen->posn), sizeof(jit_float64)); + jit_memcpy(ptr, &float64_value, sizeof(float64_value)); + x86_fld(inst, ptr, 1); + } } break; @@ -1059,15 +585,26 @@ void _jit_gen_load_value jit_cache_mark_full(&(gen->posn)); return; } - ptr = _jit_cache_alloc(&(gen->posn), sizeof(jit_nfloat)); - jit_memcpy(ptr, &nfloat_value, sizeof(nfloat_value)); - if(sizeof(jit_nfloat) != sizeof(jit_float64)) + if(IS_WORD_REG(reg) && + sizeof(jit_nfloat) == sizeof(jit_float64)) { - x86_fld80_mem(inst, ptr); + x86_mov_reg_imm(inst, _jit_reg_info[reg].cpu_reg, + ((jit_int *)&nfloat_value)[0]); + x86_mov_reg_imm(inst, _jit_reg_info[other_reg].cpu_reg, + ((jit_int *)&nfloat_value)[1]); } else { - x86_fld(inst, ptr, 1); + ptr = _jit_cache_alloc(&(gen->posn), sizeof(jit_nfloat)); + jit_memcpy(ptr, &nfloat_value, sizeof(nfloat_value)); + if(sizeof(jit_nfloat) != sizeof(jit_float64)) + { + x86_fld80_mem(inst, ptr); + } + else + { + x86_fld(inst, ptr, 1); + } } } break; @@ -1142,19 +679,52 @@ void _jit_gen_load_value case JIT_TYPE_FLOAT32: { - x86_fld_membase(inst, X86_EBP, offset, 0); + if(IS_WORD_REG(reg)) + { + x86_mov_reg_membase(inst, _jit_reg_info[reg].cpu_reg, + X86_EBP, offset, 4); + } + else + { + x86_fld_membase(inst, X86_EBP, offset, 0); + } } break; case JIT_TYPE_FLOAT64: { - x86_fld_membase(inst, X86_EBP, offset, 1); + if(IS_WORD_REG(reg)) + { + x86_mov_reg_membase(inst, _jit_reg_info[reg].cpu_reg, + X86_EBP, offset, 4); + x86_mov_reg_membase(inst, _jit_reg_info[other_reg].cpu_reg, + X86_EBP, offset + 4, 4); + } + else + { + x86_fld_membase(inst, X86_EBP, offset, 1); + } } break; case JIT_TYPE_NFLOAT: { - x86_fld80_membase(inst, X86_EBP, offset); + if(IS_WORD_REG(reg) && + sizeof(jit_nfloat) == sizeof(jit_float64)) + { + x86_mov_reg_membase(inst, _jit_reg_info[reg].cpu_reg, + X86_EBP, offset, 4); + x86_mov_reg_membase(inst, _jit_reg_info[other_reg].cpu_reg, + X86_EBP, offset + 4, 4); + } + else if(sizeof(jit_nfloat) == sizeof(jit_float64)) + { + x86_fld_membase(inst, X86_EBP, offset, 1); + } + else + { + x86_fld80_membase(inst, X86_EBP, offset); + } } break; } diff --git a/jit/jit-rules-x86.h b/jit/jit-rules-x86.h index 8db9c7c..74a2100 100644 --- a/jit/jit-rules-x86.h +++ b/jit/jit-rules-x86.h @@ -75,6 +75,15 @@ extern "C" { */ #define JIT_ALIGN_OVERRIDES 1 +/* + * Parameter passing rules. + */ +#define JIT_CDECL_WORD_REG_PARAMS {-1} +#define JIT_FASTCALL_WORD_REG_PARAMS {1, 2, -1} /* ecx, edx */ +#define JIT_MAX_WORD_REG_PARAMS 2 +#define JIT_INITIAL_STACK_OFFSET (2 * sizeof(void *)) +#define JIT_INITIAL_FRAME_SIZE 0 + #ifdef __cplusplus }; #endif diff --git a/jit/jit-rules-x86.sel b/jit/jit-rules-x86.sel index 5481814..225d0d6 100644 --- a/jit/jit-rules-x86.sel +++ b/jit/jit-rules-x86.sel @@ -1826,6 +1826,7 @@ JIT_OP_SETUP_FOR_NESTED: spill_before JIT_OP_SETUP_FOR_SIBLING: spill_before [] -> { + jit_value_t parent; jit_nint level = jit_value_get_nint_constant(insn->value1); jit_nint nest_reg = jit_value_get_nint_constant(insn->value2); int cpu_reg; @@ -1837,7 +1838,25 @@ JIT_OP_SETUP_FOR_SIBLING: spill_before { cpu_reg = _jit_reg_info[nest_reg].cpu_reg; } - x86_mov_reg_membase(inst, cpu_reg, X86_EBP, 0, sizeof(void *)); + parent = func->builder->parent_frame; + if(parent->in_register) + { + x86_mov_reg_reg(inst, cpu_reg, + _jit_reg_info[parent->reg].cpu_reg, + sizeof(void *)); + } + else if(parent->in_global_register) + { + x86_mov_reg_reg(inst, cpu_reg, + _jit_reg_info[parent->global_reg].cpu_reg, + sizeof(void *)); + } + else + { + _jit_gen_fix_value(parent); + x86_mov_reg_membase(inst, cpu_reg, X86_EBP, + parent->frame_offset, sizeof(void *)); + } while(level > 0) { gen->posn.ptr = inst; @@ -1861,7 +1880,8 @@ JIT_OP_IMPORT: manual int reg; jit_nint level = jit_value_get_nint_constant(insn->value2); _jit_gen_fix_value(insn->value1); - reg = _jit_regs_dest_value(gen, insn->dest); + reg = _jit_regs_load_value + (gen, func->builder->parent_frame, 1, 0); inst = gen->posn.ptr; if(!jit_cache_check_for_n(&(gen->posn), 32 + level * 8)) { @@ -1869,7 +1889,6 @@ JIT_OP_IMPORT: manual return; } reg = _jit_reg_info[reg].cpu_reg; - x86_mov_reg_membase(inst, reg, X86_EBP, 0, sizeof(void *)); while(level > 0) { x86_mov_reg_membase(inst, reg, reg, 0, sizeof(void *)); diff --git a/jit/jit-rules.c b/jit/jit-rules.c index 35ed926..a16226d 100644 --- a/jit/jit-rules.c +++ b/jit/jit-rules.c @@ -26,6 +26,715 @@ */ jit_reginfo_t const _jit_reg_info[JIT_NUM_REGS] = {JIT_REG_INFO}; +#ifdef JIT_CDECL_WORD_REG_PARAMS + +/* + * List of registers to use for simple parameter passing. + */ +static int const cdecl_word_regs[] = JIT_CDECL_WORD_REG_PARAMS; +#ifdef JIT_FASTCALL_WORD_REG_PARAMS +static int const fastcall_word_regs[] = JIT_FASTCALL_WORD_REG_PARAMS; +#endif + +/* + * Structure that is used to help with parameter passing. + */ +typedef struct +{ + jit_nint offset; + unsigned int index; + unsigned int max_regs; + const int *word_regs; + jit_value_t word_values[JIT_MAX_WORD_REG_PARAMS]; + +} jit_param_passing_t; + +/* + * Round a size up to a multiple of the stack word size. + */ +#define ROUND_STACK(size) \ + (((size) + (sizeof(void *) - 1)) & ~(sizeof(void *) - 1)) +#define STACK_WORDS(size) \ + (((size) + (sizeof(void *) - 1)) / sizeof(void *)) + +/* + * Allocate a word register or incoming frame position to a value. + */ +static int alloc_incoming_word + (jit_function_t func, jit_param_passing_t *passing, + jit_value_t value, int extra_offset) +{ + int reg; + reg = passing->word_regs[passing->index]; + if(reg != -1 && passing->word_values[passing->index] != 0) + { + /* The value was already forced out previously, so just copy it */ + if(!jit_insn_store(func, value, passing->word_values[passing->index])) + { + return 0; + } + ++(passing->index); + } + else if(reg != -1) + { + if(!jit_insn_incoming_reg(func, value, reg)) + { + return 0; + } + ++(passing->index); + } + else + { + if(!jit_insn_incoming_frame_posn + (func, value, passing->offset + extra_offset)) + { + return 0; + } + passing->offset += sizeof(void *); + } + return 1; +} + +/* + * Force the remaining word registers out into temporary values, + * to protect them from being accidentally overwritten by the code + * that deals with multi-word parameters. + */ +static int force_remaining_out + (jit_function_t func, jit_param_passing_t *passing) +{ + unsigned int index = passing->index; + jit_value_t value; + while(index < passing->max_regs && passing->word_regs[index] != -1) + { + if(passing->word_values[index] != 0) + { + /* We've already done this before */ + return 1; + } + value = jit_value_create(func, jit_type_void_ptr); + if(!value) + { + return 0; + } + if(!jit_insn_incoming_reg(func, value, passing->word_regs[index])) + { + return 0; + } + passing->word_values[index] = value; + ++index; + } + return 1; +} + +int _jit_create_entry_insns(jit_function_t func) +{ + jit_type_t signature = func->signature; + jit_type_t type; + jit_value_t value; + jit_value_t temp; + jit_value_t addr_of; + unsigned int num_params; + unsigned int param; + unsigned int size; + jit_param_passing_t passing; + jit_nint partial_offset; + + /* Reset the local variable frame size for this function */ + func->builder->frame_size = JIT_INITIAL_FRAME_SIZE; + + /* Initialize the parameter passing information block */ + passing.offset = JIT_INITIAL_STACK_OFFSET; + passing.index = 0; +#ifdef JIT_FASTCALL_WORD_REG_PARAMS + if(jit_type_get_abi(signature) == jit_abi_fastcall) + { + passing.word_regs = fastcall_word_regs; + } + else +#endif + { + passing.word_regs = cdecl_word_regs; + } + for(size = 0; size < JIT_MAX_WORD_REG_PARAMS; ++size) + { + passing.word_values[size] = 0; + } + + /* If the function is nested, then we need an extra parameter + to pass the pointer to the parent's local variable frame */ + if(func->nested_parent) + { + value = jit_value_create(func, jit_type_void_ptr); + if(!value) + { + return 0; + } + func->builder->parent_frame = value; + if(!alloc_incoming_word(func, &passing, value, 0)) + { + return 0; + } + } + + /* Allocate the structure return pointer */ + value = jit_value_get_struct_pointer(func); + if(value) + { + if(!alloc_incoming_word(func, &passing, value, 0)) + { + return 0; + } + } + + /* Determine the maximum number of registers that may be needed + to pass the function's parameters */ + num_params = jit_type_num_params(signature); + passing.max_regs = passing.index; + for(param = 0; param < num_params; ++param) + { + value = jit_value_get_param(func, param); + if(value) + { + size = STACK_WORDS(jit_type_get_size(jit_value_get_type(value))); + passing.max_regs += size; + } + } + + /* Allocate the parameter offsets */ + for(param = 0; param < num_params; ++param) + { + value = jit_value_get_param(func, param); + if(!value) + { + continue; + } + type = jit_type_remove_tags(jit_value_get_type(value)); + switch(type->kind) + { + case JIT_TYPE_SBYTE: + case JIT_TYPE_UBYTE: + { + if(!alloc_incoming_word + (func, &passing, value, _jit_nint_lowest_byte())) + { + return 0; + } + } + break; + + case JIT_TYPE_SHORT: + case JIT_TYPE_USHORT: + { + if(!alloc_incoming_word + (func, &passing, value, _jit_nint_lowest_short())) + { + return 0; + } + } + break; + + case JIT_TYPE_INT: + case JIT_TYPE_UINT: + { + if(!alloc_incoming_word + (func, &passing, value, _jit_nint_lowest_int())) + { + return 0; + } + } + break; + + case JIT_TYPE_NINT: + case JIT_TYPE_NUINT: + case JIT_TYPE_SIGNATURE: + case JIT_TYPE_PTR: + { + if(!alloc_incoming_word(func, &passing, value, 0)) + { + return 0; + } + } + break; + + case JIT_TYPE_LONG: + case JIT_TYPE_ULONG: + #ifdef JIT_NATIVE_INT64 + { + if(!alloc_incoming_word(func, &passing, value, 0)) + { + return 0; + } + } + break; + #endif + /* Fall through on 32-bit platforms */ + + case JIT_TYPE_FLOAT32: + case JIT_TYPE_FLOAT64: + case JIT_TYPE_NFLOAT: + case JIT_TYPE_STRUCT: + case JIT_TYPE_UNION: + { + /* Force the remaining registers out into temporary copies */ + if(!force_remaining_out(func, &passing)) + { + return 0; + } + + /* Determine how many words that we need to copy */ + size = STACK_WORDS(jit_type_get_size(type)); + + /* If there are no registers left, then alloc on the stack */ + if(passing.word_regs[passing.index] == -1) + { + if(!jit_insn_incoming_frame_posn + (func, value, passing.offset)) + { + return 0; + } + passing.offset += size * sizeof(void *); + break; + } + + /* Copy the register components across */ + partial_offset = 0; + addr_of = jit_insn_address_of(func, value); + if(!addr_of) + { + return 0; + } + while(size > 0 && passing.word_regs[passing.index] != -1) + { + temp = passing.word_values[passing.index]; + ++(passing.index); + if(!jit_insn_store_relative + (func, addr_of, partial_offset, temp)) + { + return 0; + } + partial_offset += sizeof(void *); + --size; + } + + /* Copy the stack components across */ + while(size > 0) + { + temp = jit_value_create(func, jit_type_void_ptr); + if(!temp) + { + return 0; + } + if(!jit_insn_incoming_frame_posn + (func, temp, passing.offset)) + { + return 0; + } + if(!jit_insn_store_relative + (func, addr_of, partial_offset, temp)) + { + return 0; + } + passing.offset += sizeof(void *); + partial_offset += sizeof(void *); + --size; + } + } + break; + } + } + return 1; +} + +/* + * Record that we need an outgoing register or stack slot for a word value. + */ +static void need_outgoing_word(jit_param_passing_t *passing) +{ + if(passing->word_regs[passing->index] != -1) + { + ++(passing->index); + } + else + { + passing->offset += sizeof(void *); + } +} + +/* + * Record that we need an outgoing register, containing a particular value. + */ +static void need_outgoing_value + (jit_param_passing_t *passing, jit_value_t value) +{ + passing->word_values[passing->index] = value; + ++(passing->index); +} + +/* + * Count the number of registers that are left for parameter passing. + */ +static jit_nint count_regs_left(jit_param_passing_t *passing) +{ + int left = 0; + unsigned int index = passing->index; + while(passing->word_regs[index] != -1) + { + ++left; + ++index; + } + return left; +} + +/* + * Determine if a type corresponds to a structure or union. + */ +static int is_struct_or_union(jit_type_t type) +{ + type = jit_type_normalize(type); + if(type) + { + if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION) + { + return 1; + } + } + return 0; +} + +/* + * Push a parameter onto the stack. + */ +static int push_param + (jit_function_t func, jit_param_passing_t *passing, + jit_value_t value, jit_type_t type) +{ + jit_nint size = (jit_nint)(jit_type_get_size(value->type)); + passing->offset -= ROUND_STACK(size); + if(is_struct_or_union(type) && !is_struct_or_union(value->type)) + { + #ifdef JIT_USE_PARAM_AREA + /* Copy the value into the outgoing parameter area, by pointer */ + if(!jit_insn_set_param_ptr(func, value, type, passing->offset)) + { + return 0; + } + #else + /* Push the parameter value onto the stack, by pointer */ + if(!jit_insn_push_ptr(func, value, type)) + { + return 0; + } + #endif + } + else + { + #ifdef JIT_USE_PARAM_AREA + /* Copy the value into the outgoing parameter area */ + if(!jit_insn_set_param(func, value, passing->offset)) + { + return 0; + } + #else + /* Push the parameter value onto the stack */ + if(!jit_insn_push(func, value)) + { + return 0; + } + #endif + } + return 1; +} + +/* + * Allocate an outgoing word register to a value. + */ +static int alloc_outgoing_word + (jit_function_t func, jit_param_passing_t *passing, jit_value_t value) +{ + int reg; + --(passing->index); + reg = passing->word_regs[passing->index]; + if(passing->word_values[passing->index] != 0) + { + /* We copied the value previously, so use the copy instead */ + value = passing->word_values[passing->index]; + } + if(!jit_insn_outgoing_reg(func, value, reg)) + { + return 0; + } + return 1; +} + +int _jit_create_call_setup_insns + (jit_function_t func, jit_type_t signature, + jit_value_t *args, unsigned int num_args, + int is_nested, int nesting_level, jit_value_t *struct_return, int flags) +{ + jit_type_t type; + jit_value_t value; + jit_nint size; + jit_nint regs_left; + jit_nint rounded_size; + jit_nint partial_offset; + jit_param_passing_t passing; + jit_value_t return_ptr; + jit_value_t partial; + unsigned int param; + + /* Initialize the parameter passing information block */ + passing.offset = 0; + passing.index = 0; +#ifdef JIT_FASTCALL_WORD_REG_PARAMS + if(jit_type_get_abi(signature) == jit_abi_fastcall) + { + passing.word_regs = fastcall_word_regs; + } + else +#endif + { + passing.word_regs = cdecl_word_regs; + } + for(size = 0; size < JIT_MAX_WORD_REG_PARAMS; ++size) + { + passing.word_values[size] = 0; + } + + /* Determine how many parameters are going to end up in word registers, + and compute the largest stack size needed to pass stack parameters */ + if(is_nested) + { + need_outgoing_word(&passing); + } + type = jit_type_get_return(signature); + if(jit_type_return_via_pointer(type)) + { + value = jit_value_create(func, type); + if(!value) + { + return 0; + } + *struct_return = value; + return_ptr = jit_insn_address_of(func, value); + if(!return_ptr) + { + return 0; + } + need_outgoing_word(&passing); + } + else + { + *struct_return = 0; + return_ptr = 0; + } + partial = 0; + for(param = 0; param < num_args; ++param) + { + type = jit_type_get_param(signature, param); + size = STACK_WORDS(jit_type_get_size(type)); + if(size <= 1) + { + /* Allocate a word register or stack position */ + need_outgoing_word(&passing); + } + else + { + regs_left = count_regs_left(&passing); + if(regs_left > 0) + { + /* May be partly in registers and partly on the stack */ + if(is_struct_or_union(type) && + !is_struct_or_union(jit_value_get_type(args[param]))) + { + /* Passing a structure by pointer */ + partial = args[param]; + } + else if(jit_value_is_constant(args[param])) + { + if(size <= regs_left) + { + /* We can split the constant, without a temporary */ + partial_offset = 0; + while(size > 0) + { + value = jit_value_create_nint_constant + (func, jit_type_void_ptr, + *((jit_nint *)(args[param]->address + + partial_offset))); + need_outgoing_value(&passing, value); + partial_offset += sizeof(void *); + --size; + } + continue; + } + else + { + /* Copy the constant into a temporary local variable */ + partial = jit_value_create(func, type); + if(!partial) + { + return 0; + } + if(!jit_insn_store(func, partial, args[param])) + { + return 0; + } + partial = jit_insn_address_of(func, partial); + } + } + else + { + /* Get the address of this parameter */ + partial = jit_insn_address_of(func, args[param]); + } + if(!partial) + { + return 0; + } + partial_offset = 0; + while(size > 0 && regs_left > 0) + { + value = jit_insn_load_relative + (func, partial, partial_offset, jit_type_void_ptr); + if(!value) + { + return 0; + } + need_outgoing_value(&passing, value); + --size; + --regs_left; + partial_offset += sizeof(void *); + } + passing.offset += size * sizeof(void *); + } + else + { + /* Pass this parameter completely on the stack */ + passing.offset += size * sizeof(void *); + } + } + } +#ifdef JIT_USE_PARAM_AREA + if(passing.offset > func->builder->param_area_size) + { + func->builder->param_area_size = passing.offset; + } +#else + /* Flush deferred stack pops from previous calls if too many + parameters have collected up on the stack since last time */ + if(!jit_insn_flush_defer_pop(func, 32 - passing.offset)) + { + return 0; + } +#endif + + /* Move all of the parameters into their final locations */ + param = num_args; + while(param > 0) + { + --param; + type = jit_type_get_param(signature, param); + size = (jit_nint)(jit_type_get_size(type)); + rounded_size = ROUND_STACK(size); + size = STACK_WORDS(size); + if(rounded_size <= passing.offset) + { + /* This parameter is completely on the stack */ + if(!push_param(func, &passing, args[param], type)) + { + return 0; + } + } + else if(passing.offset > 0) + { + /* This parameter is split between the stack and registers */ + while(passing.offset > 0) + { + rounded_size -= sizeof(void *); + value = jit_insn_load_relative + (func, partial, rounded_size, jit_type_void_ptr); + if(!value) + { + return 0; + } + if(!push_param(func, &passing, value, jit_type_void_ptr)) + { + return 0; + } + --size; + } + while(size > 0) + { + if(!alloc_outgoing_word(func, &passing, 0)) + { + return 0; + } + --size; + } + } + else + { + /* This parameter is completely in registers. If the parameter + occupies multiple registers, then it has already been split */ + while(size > 0) + { + if(!alloc_outgoing_word(func, &passing, args[param])) + { + return 0; + } + --size; + } + } + } + + /* Add the structure return pointer if required */ + if(return_ptr) + { + if(passing.index > 0) + { + if(!alloc_outgoing_word(func, &passing, return_ptr)) + { + return 0; + } + } + else + { + if(!push_param + (func, &passing, return_ptr, jit_type_void_ptr)) + { + return 0; + } + } + } + + /* Add nested scope information if required */ + if(is_nested) + { + if(passing.index > 0) + { + --(passing.index); + if(!jit_insn_setup_for_nested + (func, nesting_level, passing.word_regs[passing.index])) + { + return 0; + } + } + else + { + if(!jit_insn_setup_for_nested(func, nesting_level, -1)) + { + return 0; + } + } + } + + /* The call is ready to proceed */ + return 1; +} + +#endif /* JIT_CDECL_WORD_REG_PARAMS */ + int _jit_int_lowest_byte(void) { union diff --git a/jit/jit-rules.h b/jit/jit-rules.h index fad1600..224830b 100644 --- a/jit/jit-rules.h +++ b/jit/jit-rules.h @@ -139,6 +139,7 @@ struct jit_gencode { jit_regused_t permanent; /* Permanently allocated global regs */ jit_regused_t touched; /* All registers that were touched */ + jit_regused_t inhibit; /* Temporarily inhibited registers */ jit_cache_posn posn; /* Current cache output position */ jit_regcontents_t contents[JIT_NUM_REGS]; /* Contents of each register */ int current_age;/* Current age value for registers */ diff --git a/tests/param.pas b/tests/param.pas index 5258ff8..503e026 100644 --- a/tests/param.pas +++ b/tests/param.pas @@ -208,6 +208,38 @@ begin (p25 = 25) and (p26 = 26) and (p27 = 27) and (p28 = 28) and (p29 = 29) and (p30 = 30) and (p31 = 31) and (p32 = 32)); end; +procedure param_float32_fastcall + (p1, p2, p3, p4, p5, p6, p7, p8, + p9, p10, p11, p12, p13, p14, p15, p16, + p17, p18, p19, p20, p21, p22, p23, p24, + p25, p26, p27, p28, p29, p30, p31, p32: shortreal) fastcall; +begin + run("param_float32_fastcall", + (p1 = 1) and (p2 = 2) and (p3 = 3) and (p4 = 4) and + (p5 = 5) and (p6 = 6) and (p7 = 7) and (p8 = 8) and + (p9 = 9) and (p10 = 10) and (p11 = 11) and (p12 = 12) and + (p13 = 13) and (p14 = 14) and (p15 = 15) and (p16 = 16) and + (p17 = 17) and (p18 = 18) and (p19 = 19) and (p20 = 20) and + (p21 = 21) and (p22 = 22) and (p23 = 23) and (p24 = 24) and + (p25 = 25) and (p26 = 26) and (p27 = 27) and (p28 = 28) and + (p29 = 29) and (p30 = 30) and (p31 = 31) and (p32 = 32)); +end; +procedure param_float32_stdcall + (p1, p2, p3, p4, p5, p6, p7, p8, + p9, p10, p11, p12, p13, p14, p15, p16, + p17, p18, p19, p20, p21, p22, p23, p24, + p25, p26, p27, p28, p29, p30, p31, p32: shortreal) stdcall; +begin + run("param_float32_stdcall", + (p1 = 1) and (p2 = 2) and (p3 = 3) and (p4 = 4) and + (p5 = 5) and (p6 = 6) and (p7 = 7) and (p8 = 8) and + (p9 = 9) and (p10 = 10) and (p11 = 11) and (p12 = 12) and + (p13 = 13) and (p14 = 14) and (p15 = 15) and (p16 = 16) and + (p17 = 17) and (p18 = 18) and (p19 = 19) and (p20 = 20) and + (p21 = 21) and (p22 = 22) and (p23 = 23) and (p24 = 24) and + (p25 = 25) and (p26 = 26) and (p27 = 27) and (p28 = 28) and + (p29 = 29) and (p30 = 30) and (p31 = 31) and (p32 = 32)); +end; { Test passing 64-bit float values in registers and on the stack } procedure param_float64 @@ -226,6 +258,38 @@ begin (p25 = 25) and (p26 = 26) and (p27 = 27) and (p28 = 28) and (p29 = 29) and (p30 = 30) and (p31 = 31) and (p32 = 32)); end; +procedure param_float64_fastcall + (p1, p2, p3, p4, p5, p6, p7, p8, + p9, p10, p11, p12, p13, p14, p15, p16, + p17, p18, p19, p20, p21, p22, p23, p24, + p25, p26, p27, p28, p29, p30, p31, p32: real) fastcall; +begin + run("param_float64_fastcall", + (p1 = 1) and (p2 = 2) and (p3 = 3) and (p4 = 4) and + (p5 = 5) and (p6 = 6) and (p7 = 7) and (p8 = 8) and + (p9 = 9) and (p10 = 10) and (p11 = 11) and (p12 = 12) and + (p13 = 13) and (p14 = 14) and (p15 = 15) and (p16 = 16) and + (p17 = 17) and (p18 = 18) and (p19 = 19) and (p20 = 20) and + (p21 = 21) and (p22 = 22) and (p23 = 23) and (p24 = 24) and + (p25 = 25) and (p26 = 26) and (p27 = 27) and (p28 = 28) and + (p29 = 29) and (p30 = 30) and (p31 = 31) and (p32 = 32)); +end; +procedure param_float64_stdcall + (p1, p2, p3, p4, p5, p6, p7, p8, + p9, p10, p11, p12, p13, p14, p15, p16, + p17, p18, p19, p20, p21, p22, p23, p24, + p25, p26, p27, p28, p29, p30, p31, p32: real) stdcall; +begin + run("param_float64_stdcall", + (p1 = 1) and (p2 = 2) and (p3 = 3) and (p4 = 4) and + (p5 = 5) and (p6 = 6) and (p7 = 7) and (p8 = 8) and + (p9 = 9) and (p10 = 10) and (p11 = 11) and (p12 = 12) and + (p13 = 13) and (p14 = 14) and (p15 = 15) and (p16 = 16) and + (p17 = 17) and (p18 = 18) and (p19 = 19) and (p20 = 20) and + (p21 = 21) and (p22 = 22) and (p23 = 23) and (p24 = 24) and + (p25 = 25) and (p26 = 26) and (p27 = 27) and (p28 = 28) and + (p29 = 29) and (p30 = 30) and (p31 = 31) and (p32 = 32)); +end; { Test passing native float values in registers and on the stack } procedure param_nfloat @@ -244,6 +308,38 @@ begin (p25 = 25) and (p26 = 26) and (p27 = 27) and (p28 = 28) and (p29 = 29) and (p30 = 30) and (p31 = 31) and (p32 = 32)); end; +procedure param_nfloat_fastcall + (p1, p2, p3, p4, p5, p6, p7, p8, + p9, p10, p11, p12, p13, p14, p15, p16, + p17, p18, p19, p20, p21, p22, p23, p24, + p25, p26, p27, p28, p29, p30, p31, p32: longreal) fastcall; +begin + run("param_nfloat_fastcall", + (p1 = 1) and (p2 = 2) and (p3 = 3) and (p4 = 4) and + (p5 = 5) and (p6 = 6) and (p7 = 7) and (p8 = 8) and + (p9 = 9) and (p10 = 10) and (p11 = 11) and (p12 = 12) and + (p13 = 13) and (p14 = 14) and (p15 = 15) and (p16 = 16) and + (p17 = 17) and (p18 = 18) and (p19 = 19) and (p20 = 20) and + (p21 = 21) and (p22 = 22) and (p23 = 23) and (p24 = 24) and + (p25 = 25) and (p26 = 26) and (p27 = 27) and (p28 = 28) and + (p29 = 29) and (p30 = 30) and (p31 = 31) and (p32 = 32)); +end; +procedure param_nfloat_stdcall + (p1, p2, p3, p4, p5, p6, p7, p8, + p9, p10, p11, p12, p13, p14, p15, p16, + p17, p18, p19, p20, p21, p22, p23, p24, + p25, p26, p27, p28, p29, p30, p31, p32: longreal) stdcall; +begin + run("param_nfloat_stdcall", + (p1 = 1) and (p2 = 2) and (p3 = 3) and (p4 = 4) and + (p5 = 5) and (p6 = 6) and (p7 = 7) and (p8 = 8) and + (p9 = 9) and (p10 = 10) and (p11 = 11) and (p12 = 12) and + (p13 = 13) and (p14 = 14) and (p15 = 15) and (p16 = 16) and + (p17 = 17) and (p18 = 18) and (p19 = 19) and (p20 = 20) and + (p21 = 21) and (p22 = 22) and (p23 = 23) and (p24 = 24) and + (p25 = 25) and (p26 = 26) and (p27 = 27) and (p28 = 28) and + (p29 = 29) and (p30 = 30) and (p31 = 31) and (p32 = 32)); +end; { Test passing both int and float64 parameters } procedure param_int_float64 @@ -274,6 +370,62 @@ begin (q25 = 25) and (q26 = 26) and (q27 = 27) and (q28 = 28) and (q29 = 29) and (q30 = 30) and (q31 = 31) and (q32 = 32)); end; +procedure param_int_float64_fastcall + (p1, p2, p3, p4, p5, p6, p7, p8, + p9, p10, p11, p12, p13, p14, p15, p16, + p17, p18, p19, p20, p21, p22, p23, p24, + p25, p26, p27, p28, p29, p30, p31, p32: integer; + q1, q2, q3, q4, q5, q6, q7, q8, + q9, q10, q11, q12, q13, q14, q15, q16, + q17, q18, q19, q20, q21, q22, q23, q24, + q25, q26, q27, q28, q29, q30, q31, q32: real) fastcall; +begin + run("param_int_float64_fastcall", + (p1 = 1) and (p2 = 2) and (p3 = 3) and (p4 = 4) and + (p5 = 5) and (p6 = 6) and (p7 = 7) and (p8 = 8) and + (p9 = 9) and (p10 = 10) and (p11 = 11) and (p12 = 12) and + (p13 = 13) and (p14 = 14) and (p15 = 15) and (p16 = 16) and + (p17 = 17) and (p18 = 18) and (p19 = 19) and (p20 = 20) and + (p21 = 21) and (p22 = 22) and (p23 = 23) and (p24 = 24) and + (p25 = 25) and (p26 = 26) and (p27 = 27) and (p28 = 28) and + (p29 = 29) and (p30 = 30) and (p31 = 31) and (p32 = 32) and + (q1 = 1) and (q2 = 2) and (q3 = 3) and (q4 = 4) and + (q5 = 5) and (q6 = 6) and (q7 = 7) and (q8 = 8) and + (q9 = 9) and (q10 = 10) and (q11 = 11) and (q12 = 12) and + (q13 = 13) and (q14 = 14) and (q15 = 15) and (q16 = 16) and + (q17 = 17) and (q18 = 18) and (q19 = 19) and (q20 = 20) and + (q21 = 21) and (q22 = 22) and (q23 = 23) and (q24 = 24) and + (q25 = 25) and (q26 = 26) and (q27 = 27) and (q28 = 28) and + (q29 = 29) and (q30 = 30) and (q31 = 31) and (q32 = 32)); +end; +procedure param_int_float64_stdcall + (p1, p2, p3, p4, p5, p6, p7, p8, + p9, p10, p11, p12, p13, p14, p15, p16, + p17, p18, p19, p20, p21, p22, p23, p24, + p25, p26, p27, p28, p29, p30, p31, p32: integer; + q1, q2, q3, q4, q5, q6, q7, q8, + q9, q10, q11, q12, q13, q14, q15, q16, + q17, q18, q19, q20, q21, q22, q23, q24, + q25, q26, q27, q28, q29, q30, q31, q32: real) stdcall; +begin + run("param_int_float64_stdcall", + (p1 = 1) and (p2 = 2) and (p3 = 3) and (p4 = 4) and + (p5 = 5) and (p6 = 6) and (p7 = 7) and (p8 = 8) and + (p9 = 9) and (p10 = 10) and (p11 = 11) and (p12 = 12) and + (p13 = 13) and (p14 = 14) and (p15 = 15) and (p16 = 16) and + (p17 = 17) and (p18 = 18) and (p19 = 19) and (p20 = 20) and + (p21 = 21) and (p22 = 22) and (p23 = 23) and (p24 = 24) and + (p25 = 25) and (p26 = 26) and (p27 = 27) and (p28 = 28) and + (p29 = 29) and (p30 = 30) and (p31 = 31) and (p32 = 32) and + (q1 = 1) and (q2 = 2) and (q3 = 3) and (q4 = 4) and + (q5 = 5) and (q6 = 6) and (q7 = 7) and (q8 = 8) and + (q9 = 9) and (q10 = 10) and (q11 = 11) and (q12 = 12) and + (q13 = 13) and (q14 = 14) and (q15 = 15) and (q16 = 16) and + (q17 = 17) and (q18 = 18) and (q19 = 19) and (q20 = 20) and + (q21 = 21) and (q22 = 22) and (q23 = 23) and (q24 = 24) and + (q25 = 25) and (q26 = 26) and (q27 = 27) and (q28 = 28) and + (q29 = 29) and (q30 = 30) and (q31 = 31) and (q32 = 32)); +end; { Test passing both int and float64 parameters, reversed from above } procedure param_float64_int @@ -304,6 +456,62 @@ begin (q25 = 25) and (q26 = 26) and (q27 = 27) and (q28 = 28) and (q29 = 29) and (q30 = 30) and (q31 = 31) and (q32 = 32)); end; +procedure param_float64_int_fastcall + (p1, p2, p3, p4, p5, p6, p7, p8, + p9, p10, p11, p12, p13, p14, p15, p16, + p17, p18, p19, p20, p21, p22, p23, p24, + p25, p26, p27, p28, p29, p30, p31, p32: real; + q1, q2, q3, q4, q5, q6, q7, q8, + q9, q10, q11, q12, q13, q14, q15, q16, + q17, q18, q19, q20, q21, q22, q23, q24, + q25, q26, q27, q28, q29, q30, q31, q32: integer) fastcall; +begin + run("param_float64_int_fastcall", + (p1 = 1) and (p2 = 2) and (p3 = 3) and (p4 = 4) and + (p5 = 5) and (p6 = 6) and (p7 = 7) and (p8 = 8) and + (p9 = 9) and (p10 = 10) and (p11 = 11) and (p12 = 12) and + (p13 = 13) and (p14 = 14) and (p15 = 15) and (p16 = 16) and + (p17 = 17) and (p18 = 18) and (p19 = 19) and (p20 = 20) and + (p21 = 21) and (p22 = 22) and (p23 = 23) and (p24 = 24) and + (p25 = 25) and (p26 = 26) and (p27 = 27) and (p28 = 28) and + (p29 = 29) and (p30 = 30) and (p31 = 31) and (p32 = 32) and + (q1 = 1) and (q2 = 2) and (q3 = 3) and (q4 = 4) and + (q5 = 5) and (q6 = 6) and (q7 = 7) and (q8 = 8) and + (q9 = 9) and (q10 = 10) and (q11 = 11) and (q12 = 12) and + (q13 = 13) and (q14 = 14) and (q15 = 15) and (q16 = 16) and + (q17 = 17) and (q18 = 18) and (q19 = 19) and (q20 = 20) and + (q21 = 21) and (q22 = 22) and (q23 = 23) and (q24 = 24) and + (q25 = 25) and (q26 = 26) and (q27 = 27) and (q28 = 28) and + (q29 = 29) and (q30 = 30) and (q31 = 31) and (q32 = 32)); +end; +procedure param_float64_int_stdcall + (p1, p2, p3, p4, p5, p6, p7, p8, + p9, p10, p11, p12, p13, p14, p15, p16, + p17, p18, p19, p20, p21, p22, p23, p24, + p25, p26, p27, p28, p29, p30, p31, p32: real; + q1, q2, q3, q4, q5, q6, q7, q8, + q9, q10, q11, q12, q13, q14, q15, q16, + q17, q18, q19, q20, q21, q22, q23, q24, + q25, q26, q27, q28, q29, q30, q31, q32: integer) stdcall; +begin + run("param_float64_int_stdcall", + (p1 = 1) and (p2 = 2) and (p3 = 3) and (p4 = 4) and + (p5 = 5) and (p6 = 6) and (p7 = 7) and (p8 = 8) and + (p9 = 9) and (p10 = 10) and (p11 = 11) and (p12 = 12) and + (p13 = 13) and (p14 = 14) and (p15 = 15) and (p16 = 16) and + (p17 = 17) and (p18 = 18) and (p19 = 19) and (p20 = 20) and + (p21 = 21) and (p22 = 22) and (p23 = 23) and (p24 = 24) and + (p25 = 25) and (p26 = 26) and (p27 = 27) and (p28 = 28) and + (p29 = 29) and (p30 = 30) and (p31 = 31) and (p32 = 32) and + (q1 = 1) and (q2 = 2) and (q3 = 3) and (q4 = 4) and + (q5 = 5) and (q6 = 6) and (q7 = 7) and (q8 = 8) and + (q9 = 9) and (q10 = 10) and (q11 = 11) and (q12 = 12) and + (q13 = 13) and (q14 = 14) and (q15 = 15) and (q16 = 16) and + (q17 = 17) and (q18 = 18) and (q19 = 19) and (q20 = 20) and + (q21 = 21) and (q22 = 22) and (q23 = 23) and (q24 = 24) and + (q25 = 25) and (q26 = 26) and (q27 = 27) and (q28 = 28) and + (q29 = 29) and (q30 = 30) and (q31 = 31) and (q32 = 32)); +end; { Test passing both int and float 64 parameters, alternatively mixed } procedure param_int_float64_mixed @@ -342,6 +550,78 @@ begin (p29 = 25) and (q29 = 26) and (p30 = 27) and (q30 = 28) and (p31 = 29) and (q31 = 30) and (p32 = 31) and (q32 = 32)); end; +procedure param_int_float64_mixed_fastcall + ( p1: integer; q1: real; p2: integer; q2: real; + p3: integer; q3: real; p4: integer; q4: real; + p5: integer; q5: real; p6: integer; q6: real; + p7: integer; q7: real; p8: integer; q8: real; + p9: integer; q9: real; p10: integer; q10: real; + p11: integer; q11: real; p12: integer; q12: real; + p13: integer; q13: real; p14: integer; q14: real; + p15: integer; q15: real; p16: integer; q16: real; + p17: integer; q17: real; p18: integer; q18: real; + p19: integer; q19: real; p20: integer; q20: real; + p21: integer; q21: real; p22: integer; q22: real; + p23: integer; q23: real; p24: integer; q24: real; + p25: integer; q25: real; p26: integer; q26: real; + p27: integer; q27: real; p28: integer; q28: real; + p29: integer; q29: real; p30: integer; q30: real; + p31: integer; q31: real; p32: integer; q32: real) fastcall; +begin + run("param_int_float64_mixed_fastcall", + (p1 = 1) and (q1 = 2) and (p2 = 3) and (q2 = 4) and + (p3 = 5) and (q3 = 6) and (p4 = 7) and (q4 = 8) and + (p5 = 9) and (q5 = 10) and (p6 = 11) and (q6 = 12) and + (p7 = 13) and (q7 = 14) and (p8 = 15) and (q8 = 16) and + (p9 = 17) and (q9 = 18) and (p10 = 19) and (q10 = 20) and + (p11 = 21) and (q11 = 22) and (p12 = 23) and (q12 = 24) and + (p13 = 25) and (q13 = 26) and (p14 = 27) and (q14 = 28) and + (p15 = 29) and (q15 = 30) and (p16 = 31) and (q16 = 32) and + (p17 = 1) and (q17 = 2) and (p18 = 3) and (q18 = 4) and + (p19 = 5) and (q19 = 6) and (p20 = 7) and (q20 = 8) and + (p21 = 9) and (q21 = 10) and (p22 = 11) and (q22 = 12) and + (p23 = 13) and (q23 = 14) and (p24 = 15) and (q24 = 16) and + (p25 = 17) and (q25 = 18) and (p26 = 19) and (q26 = 20) and + (p27 = 21) and (q27 = 22) and (p28 = 23) and (q28 = 24) and + (p29 = 25) and (q29 = 26) and (p30 = 27) and (q30 = 28) and + (p31 = 29) and (q31 = 30) and (p32 = 31) and (q32 = 32)); +end; +procedure param_int_float64_mixed_stdcall + ( p1: integer; q1: real; p2: integer; q2: real; + p3: integer; q3: real; p4: integer; q4: real; + p5: integer; q5: real; p6: integer; q6: real; + p7: integer; q7: real; p8: integer; q8: real; + p9: integer; q9: real; p10: integer; q10: real; + p11: integer; q11: real; p12: integer; q12: real; + p13: integer; q13: real; p14: integer; q14: real; + p15: integer; q15: real; p16: integer; q16: real; + p17: integer; q17: real; p18: integer; q18: real; + p19: integer; q19: real; p20: integer; q20: real; + p21: integer; q21: real; p22: integer; q22: real; + p23: integer; q23: real; p24: integer; q24: real; + p25: integer; q25: real; p26: integer; q26: real; + p27: integer; q27: real; p28: integer; q28: real; + p29: integer; q29: real; p30: integer; q30: real; + p31: integer; q31: real; p32: integer; q32: real) stdcall; +begin + run("param_int_float64_mixed_stdcall", + (p1 = 1) and (q1 = 2) and (p2 = 3) and (q2 = 4) and + (p3 = 5) and (q3 = 6) and (p4 = 7) and (q4 = 8) and + (p5 = 9) and (q5 = 10) and (p6 = 11) and (q6 = 12) and + (p7 = 13) and (q7 = 14) and (p8 = 15) and (q8 = 16) and + (p9 = 17) and (q9 = 18) and (p10 = 19) and (q10 = 20) and + (p11 = 21) and (q11 = 22) and (p12 = 23) and (q12 = 24) and + (p13 = 25) and (q13 = 26) and (p14 = 27) and (q14 = 28) and + (p15 = 29) and (q15 = 30) and (p16 = 31) and (q16 = 32) and + (p17 = 1) and (q17 = 2) and (p18 = 3) and (q18 = 4) and + (p19 = 5) and (q19 = 6) and (p20 = 7) and (q20 = 8) and + (p21 = 9) and (q21 = 10) and (p22 = 11) and (q22 = 12) and + (p23 = 13) and (q23 = 14) and (p24 = 15) and (q24 = 16) and + (p25 = 17) and (q25 = 18) and (p26 = 19) and (q26 = 20) and + (p27 = 21) and (q27 = 22) and (p28 = 23) and (q28 = 24) and + (p29 = 25) and (q29 = 26) and (p30 = 27) and (q30 = 28) and + (p31 = 29) and (q31 = 30) and (p32 = 31) and (q32 = 32)); +end; procedure run_tests; begin @@ -378,28 +658,80 @@ begin param_float32 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + param_float32_fastcall + (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + param_float32_stdcall + (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + param_float64 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + param_float64_fastcall + (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + param_float64_stdcall + (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + param_nfloat (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + param_nfloat_fastcall + (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + param_nfloat_stdcall + (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); param_int_float64 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + param_int_float64_fastcall + (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + param_int_float64_stdcall + (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + param_float64_int (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + param_float64_int_fastcall + (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + param_float64_int_stdcall + (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + param_int_float64_mixed (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + param_int_float64_mixed_fastcall + (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + param_int_float64_mixed_stdcall + (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); end; begin -- 2.47.3