]> git.unchartedbackwaters.co.uk Git - francis/libjit.git/commitdiff
Rewrite the x86 and ARM parameter handling routines to centralise the
authorRhys Weatherley <rweather@southern-storm.com.au>
Fri, 18 Jun 2004 06:51:33 +0000 (06:51 +0000)
committerRhys Weatherley <rweather@southern-storm.com.au>
Fri, 18 Jun 2004 06:51:33 +0000 (06:51 +0000)
code and fix several bugs; add new tests for fastcall and stdcall conventions.

ChangeLog
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

index 0eed2f99e950a6260748ed06bba05311834cedb0..9fb4eca6d567073f30a199abf11bb82aac36d62e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,13 @@
 
+2004-06-18  Rhys Weatherley  <rweather@southern-storm.com.au>
+
+       * 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  <rweather@southern-storm.com.au>
 
        * jit/jit-reg-alloc.c (_jit_regs_set_outgoing): pass 64-bit "fastcall"
index adcd4cf10db1ac94a4f68d11573484a5843181a4..78bc1fa2568bac756aafb0ff1b3677864dad04ed 100644 (file)
@@ -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;
 
index 7a1842c4fcacd15dc8432e54d13e6293070b418b..4348f5c5d613b1e8fef45eed0bc6c0ea6fa2bf4f 100644 (file)
@@ -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);
                }
        }
 }
index 24e36c5647d34019bf0990636035cfb5045069b4..0c361e176f006fed5774370d795c01f995a3a77e 100644 (file)
@@ -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);
index 935fdb7093408c9fcde637cfc7ace42baddd9986..0e9e6421fbb9040af4a49e51050a4b478f71d011 100644 (file)
@@ -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
index d2b5b40325b32975356cf711b39fde4d1fb4e661..76c60e8a34084161750496032a0c04b0dc4a9db5 100644 (file)
 #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;
                }
index 8db9c7c201e67cb98486bbcd276d60233e4d9553..74a2100c498a16044ed007a3a6f7e0cb16b621a2 100644 (file)
@@ -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
index 5481814bb2693161b1e06ebe29cb8f9bb9660ade..225d0d6e7b86daaf0687c32dfb792ab15062e7ae 100644 (file)
@@ -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 *));
index 35ed9269b54ec7472659024de6394c2ab6c91296..a16226dbe644ce0cd83e72e67cb33a5bfcfaa797 100644 (file)
  */
 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
index fad16009bd536e9e3d9b59abacf1797f20b50a0f..224830b3cd6a659c3b961b34c58451d80dfb3017 100644 (file)
@@ -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 */
index 5258ff8d737eed9f8f133b6fd625908dd57d1341..503e0265871e95f8890e10ab696a0cc32cde6d92 100644 (file)
@@ -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