]> git.unchartedbackwaters.co.uk Git - francis/libjit.git/commitdiff
Add the "outgoing_frame_posn" instruction, to support tail calls.
authorRhys Weatherley <rweather@southern-storm.com.au>
Sun, 13 Jun 2004 01:48:58 +0000 (01:48 +0000)
committerRhys Weatherley <rweather@southern-storm.com.au>
Sun, 13 Jun 2004 01:48:58 +0000 (01:48 +0000)
ChangeLog
include/jit/jit-insn.h
include/jit/jit-opcode.h
include/jit/jit-plus.h
jit/jit-function.c
jit/jit-insn.c
jit/jit-interp.c
jit/jit-opcode.c
jit/jit-rules-interp.c
jitplus/jit-plus-function.cpp

index 5052cb17fb10fe3b7250a4b1b315ae223c47e11f..68a3827ece8ab391c274f4ddbc8ec238aa97fcca 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -4,6 +4,12 @@
        * jit/jit-insn.c, jit/jit-rules-x86.c, jit/jit-rules-x86.sel:
        implement or stub missing x86 instruction selection rules.
 
+       * include/jit/jit-insn.h, include/jit/jit-opcode.h,
+       include/jit/jit-plus.h, jit/jit-function.c, jit/jit-insn.c,
+       jit/jit-interp.c, jit/jit-opcode.c, jit/jit-rules-interp.c,
+       jitplus/jit-plus-function.cpp: add the "outgoing_frame_posn"
+       instruction, to support tail calls.
+
 2004-06-11  Rhys Weatherley  <rweather@southern-storm.com.au>
 
        * doc/libjit.texi, jit/jit-insn.c, jit/jit-internal.h,
index 1ce9cc1c0e2b0a64d7aa1b4c412d7a6bfb520010..340115f43674b7a84c2a9d96900704cf955bc214 100644 (file)
@@ -241,6 +241,8 @@ int jit_insn_incoming_frame_posn
        (jit_function_t func, jit_value_t value, jit_nint frame_offset) JIT_NOTHROW;
 int jit_insn_outgoing_reg
        (jit_function_t func, jit_value_t value, int reg) JIT_NOTHROW;
+int jit_insn_outgoing_frame_posn
+       (jit_function_t func, jit_value_t value, jit_nint frame_offset) JIT_NOTHROW;
 int jit_insn_return_reg
        (jit_function_t func, jit_value_t value, int reg) JIT_NOTHROW;
 int jit_insn_setup_for_nested
index 5223b51729911c255e746cfa7f22aa88bd8a81c3..a5bb59b3068f1a77ebdc2e13120ab799c4276233 100644 (file)
@@ -438,81 +438,82 @@ extern    "C" {
 #define        JIT_OP_INCOMING_REG                                     0x0165
 #define        JIT_OP_INCOMING_FRAME_POSN                      0x0166
 #define        JIT_OP_OUTGOING_REG                                     0x0167
-#define        JIT_OP_RETURN_REG                                       0x0168
-#define        JIT_OP_PUSH_INT                                         0x0169
-#define        JIT_OP_PUSH_LONG                                        0x016A
-#define        JIT_OP_PUSH_FLOAT32                                     0x016B
-#define        JIT_OP_PUSH_FLOAT64                                     0x016C
-#define        JIT_OP_PUSH_NFLOAT                                      0x016D
-#define        JIT_OP_PUSH_STRUCT                                      0x016E
-#define        JIT_OP_POP_STACK                                        0x016F
-#define        JIT_OP_FLUSH_SMALL_STRUCT                       0x0170
-#define        JIT_OP_SET_PARAM_INT                            0x0171
-#define        JIT_OP_SET_PARAM_LONG                           0x0172
-#define        JIT_OP_SET_PARAM_FLOAT32                        0x0173
-#define        JIT_OP_SET_PARAM_FLOAT64                        0x0174
-#define        JIT_OP_SET_PARAM_NFLOAT                         0x0175
-#define        JIT_OP_SET_PARAM_STRUCT                         0x0176
+#define        JIT_OP_OUTGOING_FRAME_POSN                      0x0168
+#define        JIT_OP_RETURN_REG                                       0x0169
+#define        JIT_OP_PUSH_INT                                         0x016A
+#define        JIT_OP_PUSH_LONG                                        0x016B
+#define        JIT_OP_PUSH_FLOAT32                                     0x016C
+#define        JIT_OP_PUSH_FLOAT64                                     0x016D
+#define        JIT_OP_PUSH_NFLOAT                                      0x016E
+#define        JIT_OP_PUSH_STRUCT                                      0x016F
+#define        JIT_OP_POP_STACK                                        0x0170
+#define        JIT_OP_FLUSH_SMALL_STRUCT                       0x0171
+#define        JIT_OP_SET_PARAM_INT                            0x0172
+#define        JIT_OP_SET_PARAM_LONG                           0x0173
+#define        JIT_OP_SET_PARAM_FLOAT32                        0x0174
+#define        JIT_OP_SET_PARAM_FLOAT64                        0x0175
+#define        JIT_OP_SET_PARAM_NFLOAT                         0x0176
+#define        JIT_OP_SET_PARAM_STRUCT                         0x0177
 
 /*
  * Pointer-relative loads and stores.
  */
-#define        JIT_OP_LOAD_RELATIVE_SBYTE                      0x0177
-#define        JIT_OP_LOAD_RELATIVE_UBYTE                      0x0178
-#define        JIT_OP_LOAD_RELATIVE_SHORT                      0x0179
-#define        JIT_OP_LOAD_RELATIVE_USHORT                     0x017A
-#define        JIT_OP_LOAD_RELATIVE_INT                        0x017B
-#define        JIT_OP_LOAD_RELATIVE_LONG                       0x017C
-#define        JIT_OP_LOAD_RELATIVE_FLOAT32            0x017D
-#define        JIT_OP_LOAD_RELATIVE_FLOAT64            0x017E
-#define        JIT_OP_LOAD_RELATIVE_NFLOAT                     0x017F
-#define        JIT_OP_LOAD_RELATIVE_STRUCT                     0x0180
-#define        JIT_OP_STORE_RELATIVE_BYTE                      0x0181
-#define        JIT_OP_STORE_RELATIVE_SHORT                     0x0182
-#define        JIT_OP_STORE_RELATIVE_INT                       0x0183
-#define        JIT_OP_STORE_RELATIVE_LONG                      0x0184
-#define        JIT_OP_STORE_RELATIVE_FLOAT32           0x0185
-#define        JIT_OP_STORE_RELATIVE_FLOAT64           0x0186
-#define        JIT_OP_STORE_RELATIVE_NFLOAT            0x0187
-#define        JIT_OP_STORE_RELATIVE_STRUCT            0x0188
-#define        JIT_OP_ADD_RELATIVE                                     0x0189
+#define        JIT_OP_LOAD_RELATIVE_SBYTE                      0x0178
+#define        JIT_OP_LOAD_RELATIVE_UBYTE                      0x0179
+#define        JIT_OP_LOAD_RELATIVE_SHORT                      0x017A
+#define        JIT_OP_LOAD_RELATIVE_USHORT                     0x017B
+#define        JIT_OP_LOAD_RELATIVE_INT                        0x017C
+#define        JIT_OP_LOAD_RELATIVE_LONG                       0x017D
+#define        JIT_OP_LOAD_RELATIVE_FLOAT32            0x017E
+#define        JIT_OP_LOAD_RELATIVE_FLOAT64            0x017F
+#define        JIT_OP_LOAD_RELATIVE_NFLOAT                     0x0180
+#define        JIT_OP_LOAD_RELATIVE_STRUCT                     0x0181
+#define        JIT_OP_STORE_RELATIVE_BYTE                      0x0182
+#define        JIT_OP_STORE_RELATIVE_SHORT                     0x0183
+#define        JIT_OP_STORE_RELATIVE_INT                       0x0184
+#define        JIT_OP_STORE_RELATIVE_LONG                      0x0185
+#define        JIT_OP_STORE_RELATIVE_FLOAT32           0x0186
+#define        JIT_OP_STORE_RELATIVE_FLOAT64           0x0187
+#define        JIT_OP_STORE_RELATIVE_NFLOAT            0x0188
+#define        JIT_OP_STORE_RELATIVE_STRUCT            0x0189
+#define        JIT_OP_ADD_RELATIVE                                     0x018A
 
 /*
  * Array element loads and stores.
  */
-#define        JIT_OP_LOAD_ELEMENT_SBYTE                       0x018A
-#define        JIT_OP_LOAD_ELEMENT_UBYTE                       0x018B
-#define        JIT_OP_LOAD_ELEMENT_SHORT                       0x018C
-#define        JIT_OP_LOAD_ELEMENT_USHORT                      0x018D
-#define        JIT_OP_LOAD_ELEMENT_INT                         0x018E
-#define        JIT_OP_LOAD_ELEMENT_LONG                        0x018F
-#define        JIT_OP_LOAD_ELEMENT_FLOAT32                     0x0190
-#define        JIT_OP_LOAD_ELEMENT_FLOAT64                     0x0191
-#define        JIT_OP_LOAD_ELEMENT_NFLOAT                      0x0192
-#define        JIT_OP_STORE_ELEMENT_BYTE                       0x0193
-#define        JIT_OP_STORE_ELEMENT_SHORT                      0x0194
-#define        JIT_OP_STORE_ELEMENT_INT                        0x0195
-#define        JIT_OP_STORE_ELEMENT_LONG                       0x0196
-#define        JIT_OP_STORE_ELEMENT_FLOAT32            0x0197
-#define        JIT_OP_STORE_ELEMENT_FLOAT64            0x0198
-#define        JIT_OP_STORE_ELEMENT_NFLOAT                     0x0199
+#define        JIT_OP_LOAD_ELEMENT_SBYTE                       0x018B
+#define        JIT_OP_LOAD_ELEMENT_UBYTE                       0x018C
+#define        JIT_OP_LOAD_ELEMENT_SHORT                       0x018D
+#define        JIT_OP_LOAD_ELEMENT_USHORT                      0x018E
+#define        JIT_OP_LOAD_ELEMENT_INT                         0x018F
+#define        JIT_OP_LOAD_ELEMENT_LONG                        0x0190
+#define        JIT_OP_LOAD_ELEMENT_FLOAT32                     0x0191
+#define        JIT_OP_LOAD_ELEMENT_FLOAT64                     0x0192
+#define        JIT_OP_LOAD_ELEMENT_NFLOAT                      0x0193
+#define        JIT_OP_STORE_ELEMENT_BYTE                       0x0194
+#define        JIT_OP_STORE_ELEMENT_SHORT                      0x0195
+#define        JIT_OP_STORE_ELEMENT_INT                        0x0196
+#define        JIT_OP_STORE_ELEMENT_LONG                       0x0197
+#define        JIT_OP_STORE_ELEMENT_FLOAT32            0x0198
+#define        JIT_OP_STORE_ELEMENT_FLOAT64            0x0199
+#define        JIT_OP_STORE_ELEMENT_NFLOAT                     0x019A
 
 /*
  * Block operations.
  */
-#define        JIT_OP_MEMCPY                                           0x019A
-#define        JIT_OP_MEMMOVE                                          0x019B
-#define        JIT_OP_MEMSET                                           0x019C
+#define        JIT_OP_MEMCPY                                           0x019B
+#define        JIT_OP_MEMMOVE                                          0x019C
+#define        JIT_OP_MEMSET                                           0x019D
 
 /*
  * Allocate memory from the stack.
  */
-#define        JIT_OP_ALLOCA                                           0x019D
+#define        JIT_OP_ALLOCA                                           0x019E
 
 /*
  * The number of opcodes in the above list.
  */
-#define        JIT_OP_NUM_OPCODES                                      0x019E
+#define        JIT_OP_NUM_OPCODES                                      0x019F
 
 /*
  * Opcode information.
index d8cb174857b86ad1e54125008e406f7af044b906..d958a6904b10a31146e68ee74093155e0b6d992d 100644 (file)
@@ -308,6 +308,7 @@ public:
        void insn_incoming_reg(const jit_value& value, int reg);
        void insn_incoming_frame_posn(const jit_value& value, jit_nint posn);
        void insn_outgoing_reg(const jit_value& value, int reg);
+       void insn_outgoing_frame_posn(const jit_value& value, jit_nint posn);
        void insn_return_reg(const jit_value& value, int reg);
        void insn_setup_for_nested(int nested_level, int reg);
        void insn_flush_struct(const jit_value& value);
index a8212c8315605beb95dd08af659110c4f44941c9..578622b985cfccd0c1c4c46d890c0b6c1afca1ef 100644 (file)
@@ -495,6 +495,19 @@ static void compile_block(jit_gencode_t gen, jit_function_t func,
                        }
                        break;
 
+                       case JIT_OP_OUTGOING_FRAME_POSN:
+                       {
+                               /* Set the frame position for an outgoing value */
+                               insn->value1->frame_offset =
+                                       jit_value_get_nint_constant(insn->value2);
+                               insn->value1->in_register = 0;
+                               insn->value1->in_global_register = 0;
+                               insn->value1->in_frame = 0;
+                               insn->value1->has_frame_offset = 1;
+                               insn->value1->has_global_register = 0;
+                       }
+                       break;
+
                        case JIT_OP_RETURN_REG:
                        {
                                /* Assign a register to a return value */
index dcf7c430c5d7bd3692e85a53ffcb0cc3fe8dc69d..c72961e911664837e23a3cd546afee54876d8d27 100644 (file)
@@ -5968,6 +5968,24 @@ int jit_insn_outgoing_reg(jit_function_t func, jit_value_t value, int reg)
                                                        (func, jit_type_int, (jit_nint)reg));
 }
 
+/*@
+ * @deftypefun int jit_insn_outgoing_frame_posn (jit_function_t func, jit_value_t value, jit_nint frame_offset)
+ * Output an instruction that notes that the contents of @code{value}
+ * should be stored in the stack frame at @code{frame_offset} at this point
+ * in the code.
+ *
+ * You normally wouldn't call this yourself - it is used internally
+ * by the CPU back ends to set up an outgoing frame for tail calls.
+ * @end deftypefun
+@*/
+int jit_insn_outgoing_frame_posn
+               (jit_function_t func, jit_value_t value, jit_nint frame_offset)
+{
+       return create_note(func, JIT_OP_OUTGOING_FRAME_POSN, value,
+                                          jit_value_create_nint_constant
+                                                       (func, jit_type_int, frame_offset));
+}
+
 /*@
  * @deftypefun int jit_insn_return_reg (jit_function_t func, jit_value_t value, int reg)
  * Output an instruction that notes that the contents of @code{value}
index 39a0fc549e564567620d5af86ecc7006a230f52d..b92fb762f7f21e75cd1e7ac3c4e70b5bd0bcfa26 100644 (file)
@@ -4478,6 +4478,7 @@ void _jit_run_function(jit_function_interp_t func, jit_item *args,
                VMCASE(JIT_OP_INCOMING_REG):
                VMCASE(JIT_OP_INCOMING_FRAME_POSN):
                VMCASE(JIT_OP_OUTGOING_REG):
+               VMCASE(JIT_OP_OUTGOING_FRAME_POSN):
                VMCASE(JIT_OP_RETURN_REG):
                VMCASE(JIT_OP_PUSH_INT):
                VMCASE(JIT_OP_PUSH_LONG):
index f71ed9b0e592e71526f6ee10d865e052a6236ede..ac0aa1ee30e9f318a4dc4e08d05b97c971246f6c 100644 (file)
@@ -454,6 +454,7 @@ jit_opcode_info_t const jit_opcodes[JIT_OP_NUM_OPCODES] = {
        {"incoming_reg",                                JIT_OPCODE_IS_REG},
        {"incoming_frame_posn",                 F_(EMPTY, ANY, INT)},
        {"outgoing_reg",                                JIT_OPCODE_IS_REG},
+       {"outgoing_frame_posn",                 F_(EMPTY, ANY, INT)},
        {"return_reg",                                  JIT_OPCODE_IS_REG},
        {"push_int",                                    F_(EMPTY, INT, EMPTY)},
        {"push_long",                                   F_(EMPTY, LONG, EMPTY)},
index 4d3d5e19ab6c6e29724c2f79d1538f4158380b53..183a2225ea6971290737b2fdb818518e56b4d579 100644 (file)
@@ -381,63 +381,128 @@ int _jit_create_call_setup_insns
        jit_type_t type;
        jit_type_t vtype;
        jit_value_t value;
+       unsigned int arg_num;
+       jit_nint offset;
+       jit_nuint size;
 
-       /* Push all of the arguments in reverse order */
-       while(num_args > 0)
+       /* Regular or tail call? */
+       if((flags & JIT_CALL_TAIL) == 0)
        {
-               --num_args;
-               type = jit_type_normalize(jit_type_get_param(signature, num_args));
-               if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION)
+               /* Push all of the arguments in reverse order */
+               while(num_args > 0)
                {
-                       /* If the value is a pointer, then we are pushing a structure
-                          argument by pointer rather than by local variable */
-                       vtype = jit_type_normalize(jit_value_get_type(args[num_args]));
-                       if(vtype->kind <= JIT_TYPE_MAX_PRIMITIVE)
+                       --num_args;
+                       type = jit_type_normalize(jit_type_get_param(signature, num_args));
+                       if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION)
                        {
-                               if(!jit_insn_push_ptr(func, args[num_args], type))
+                               /* If the value is a pointer, then we are pushing a structure
+                                  argument by pointer rather than by local variable */
+                               vtype = jit_type_normalize(jit_value_get_type(args[num_args]));
+                               if(vtype->kind <= JIT_TYPE_MAX_PRIMITIVE)
                                {
-                                       return 0;
+                                       if(!jit_insn_push_ptr(func, args[num_args], type))
+                                       {
+                                               return 0;
+                                       }
+                                       continue;
                                }
                        }
+                       if(!jit_insn_push(func, args[num_args]))
+                       {
+                               return 0;
+                       }
                }
-               if(!jit_insn_push(func, args[num_args]))
-               {
-                       return 0;
-               }
-       }
 
-       /* Do we need to add a structure return pointer argument? */
-       type = jit_type_get_return(signature);
-       if(jit_type_return_via_pointer(type))
-       {
-               value = jit_value_create(func, type);
-               if(!value)
+               /* Do we need to add a structure return pointer argument? */
+               type = jit_type_get_return(signature);
+               if(jit_type_return_via_pointer(type))
                {
-                       return 0;
+                       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(!jit_insn_push(func, value))
+                       {
+                               return 0;
+                       }
                }
-               *struct_return = value;
-               value = jit_insn_address_of(func, value);
-               if(!value)
+               else
                {
-                       return 0;
+                       *struct_return = 0;
                }
-               if(!jit_insn_push(func, value))
+
+               /* Do we need to add nested function scope information? */
+               if(is_nested)
                {
-                       return 0;
+                       if(!jit_insn_setup_for_nested(func, nested_level, -1))
+                       {
+                               return 0;
+                       }
                }
        }
        else
        {
-               *struct_return = 0;
-       }
-
-       /* Do we need to add nested function scope information? */
-       if(is_nested)
-       {
-               if(!jit_insn_setup_for_nested(func, nested_level, -1))
+               /* Copy the arguments into our own parameter slots */
+               offset = -1;
+               if(func->nested_parent)
                {
-                       return 0;
+                       offset -= 2;
+               }
+               type = jit_type_get_return(signature);
+               if(jit_type_return_via_pointer(type))
+               {
+                       --offset;
+               }
+               for(arg_num = 0; arg_num < num_args; ++arg_num)
+               {
+                       type = jit_type_get_param(signature, arg_num);
+                       value = jit_value_create(func, type);
+                       if(!value)
+                       {
+                               return 0;
+                       }
+                       if(!jit_insn_outgoing_frame_posn(func, value, offset))
+                       {
+                               return 0;
+                       }
+                       type = jit_type_normalize(type);
+                       size = jit_type_get_size(type);
+                       offset -= (jit_nint)(JIT_NUM_ITEMS_IN_STRUCT(size));
+                       if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION)
+                       {
+                               /* If the value is a pointer, then we are pushing a structure
+                                  argument by pointer rather than by local variable */
+                               vtype = jit_type_normalize(jit_value_get_type(args[arg_num]));
+                               if(vtype->kind <= JIT_TYPE_MAX_PRIMITIVE)
+                               {
+                                       value = jit_insn_address_of(func, value);
+                                       if(!value)
+                                       {
+                                               return 0;
+                                       }
+                                       if(!jit_insn_memcpy
+                                                       (func, value, args[arg_num],
+                                                        jit_value_create_nint_constant
+                                                               (func, jit_type_nint, (jit_nint)size)))
+                                       {
+                                               return 0;
+                                       }
+                                       continue;
+                               }
+                       }
+                       if(!jit_insn_store(func, value, args[arg_num]))
+                       {
+                               return 0;
+                       }
                }
+               *struct_return = 0;
        }
 
        /* The call is ready to proceed */
index 38b9a8687943850225f1f69ca1e0811caa27db27..1541b0046921ce3f46ac6c7789059727b3f5291a 100644 (file)
@@ -639,6 +639,7 @@ jit_value jit_function::get_struct_pointer()
  * @deftypemethodx jit_function void insn_incoming_reg ({const jit_value&} value, int reg)
  * @deftypemethodx jit_function void insn_incoming_frame_posn ({const jit_value&}  value, jit_nint posn)
  * @deftypemethodx jit_function void insn_outgoing_reg ({const jit_value&} value, int reg)
+ * @deftypemethodx jit_function void insn_outgoing_frame_posn ({const jit_value&}  value, jit_nint posn)
  * @deftypemethodx jit_function void insn_return_reg ({const jit_value&} value, int reg)
  * @deftypemethodx jit_function void insn_setup_for_nested (int nested_level, int reg)
  * @deftypemethodx jit_function void insn_flush_struct ({const jit_value&} value)
@@ -1174,6 +1175,15 @@ void jit_function::insn_outgoing_reg(const jit_value& value, int reg)
        }
 }
 
+void jit_function::insn_outgoing_frame_posn
+       (const jit_value& value, jit_nint posn)
+{
+       if(!jit_insn_outgoing_frame_posn(func, value.raw(), posn))
+       {
+               out_of_memory();
+       }
+}
+
 void jit_function::insn_return_reg(const jit_value& value, int reg)
 {
        if(!jit_insn_return_reg(func, value.raw(), reg))