From: Jason Eckhardt Date: Sat, 23 Aug 2003 04:20:02 +0000 (+0000) Subject: i860.c (i860_build_va_list): Create the va_decl declaration. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=5dab8d924c9fa9ff82d3e9ac5c8d8633ff7f76f7;p=gcc.git i860.c (i860_build_va_list): Create the va_decl declaration. 2003-08-22 Jason Eckhardt * config/i860/i860.c (i860_build_va_list): Create the va_decl declaration. Document the va_list structure. (i860_va_start): Initialize the va_list structure. (i860_va_arg): Rewrite completely. * config/i860/i860.h (LIBGCC_NEEDS_DOUBLE): Don't define. * config/i860/varargs.asm: Do not allocate or initialize a va_list. Return the address of the register save area. From-SVN: r70729 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d0b957e3215..a86131c96c1 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2003-08-22 Jason Eckhardt + + * config/i860/i860.c (i860_build_va_list): Create the va_decl + declaration. Document the va_list structure. + (i860_va_start): Initialize the va_list structure. + (i860_va_arg): Rewrite completely. + * config/i860/i860.h (LIBGCC_NEEDS_DOUBLE): Don't define. + * config/i860/varargs.asm: Do not allocate or initialize + a va_list. Return the address of the register save area. + 2003-08-22 Kazu Hirata * config/iq2000/iq2000.c: Fix comment typos. diff --git a/gcc/config/i860/i860.c b/gcc/config/i860/i860.c index 0e171a9a8de..5bc32edb3c5 100644 --- a/gcc/config/i860/i860.c +++ b/gcc/config/i860/i860.c @@ -47,6 +47,7 @@ Boston, MA 02111-1307, USA. */ #include "tm_p.h" #include "target.h" #include "target-def.h" +#include "langhooks.h" static rtx find_addr_reg (rtx); @@ -1772,6 +1773,7 @@ i860_output_function_epilogue (FILE *asm_file, HOST_WIDE_INT local_bytes) /* Expand a library call to __builtin_saveregs. */ + rtx i860_saveregs (void) { @@ -1791,94 +1793,118 @@ i860_saveregs (void) return ret; } +/* Create the va_list data type. + The SVR4 ABI requires the following structure: + typedef struct { + unsigned long ireg_used; + unsigned long freg_used; + long *reg_base; + long *mem_ptr; + } va_list; + + Otherwise, this structure is used: + typedef struct { + long *reg_base; + long *mem_ptr; + unsigned long ireg_used; + unsigned long freg_used; + } va_list; + + The tree representing the va_list declaration is returned. */ + tree i860_build_va_list (void) { - tree field_ireg_used, field_freg_used, field_reg_base, field_mem_ptr; - tree record; + tree f_gpr, f_fpr, f_mem, f_sav, record, type_decl; + + record = (*lang_hooks.types.make_type) (RECORD_TYPE); + type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record); - record = make_node (RECORD_TYPE); + f_gpr = build_decl (FIELD_DECL, get_identifier ("__ireg_used"), + unsigned_type_node); + f_fpr = build_decl (FIELD_DECL, get_identifier ("__freg_used"), + unsigned_type_node); + f_sav = build_decl (FIELD_DECL, get_identifier ("__reg_base"), + ptr_type_node); + f_mem = build_decl (FIELD_DECL, get_identifier ("__mem_ptr"), + ptr_type_node); - field_ireg_used = build_decl (FIELD_DECL, get_identifier ("__ireg_used"), - unsigned_type_node); - field_freg_used = build_decl (FIELD_DECL, get_identifier ("__freg_used"), - unsigned_type_node); - field_reg_base = build_decl (FIELD_DECL, get_identifier ("__reg_base"), - ptr_type_node); - field_mem_ptr = build_decl (FIELD_DECL, get_identifier ("__mem_ptr"), - ptr_type_node); + DECL_FIELD_CONTEXT (f_gpr) = record; + DECL_FIELD_CONTEXT (f_fpr) = record; + DECL_FIELD_CONTEXT (f_sav) = record; + DECL_FIELD_CONTEXT (f_mem) = record; - DECL_FIELD_CONTEXT (field_ireg_used) = record; - DECL_FIELD_CONTEXT (field_freg_used) = record; - DECL_FIELD_CONTEXT (field_reg_base) = record; - DECL_FIELD_CONTEXT (field_mem_ptr) = record; + TREE_CHAIN (record) = type_decl; + TYPE_NAME (record) = type_decl; #ifdef I860_SVR4_VA_LIST - TYPE_FIELDS (record) = field_ireg_used; - TREE_CHAIN (field_ireg_used) = field_freg_used; - TREE_CHAIN (field_freg_used) = field_reg_base; - TREE_CHAIN (field_reg_base) = field_mem_ptr; + TYPE_FIELDS (record) = f_gpr; + TREE_CHAIN (f_gpr) = f_fpr; + TREE_CHAIN (f_fpr) = f_sav; + TREE_CHAIN (f_sav) = f_mem; #else - TYPE_FIELDS (record) = field_reg_base; - TREE_CHAIN (field_reg_base) = field_mem_ptr; - TREE_CHAIN (field_mem_ptr) = field_ireg_used; - TREE_CHAIN (field_ireg_used) = field_freg_used; + TYPE_FIELDS (record) = f_sav; + TREE_CHAIN (f_sav) = f_mem; + TREE_CHAIN (f_mem) = f_gpr; + TREE_CHAIN (f_gpr) = f_fpr; #endif layout_type (record); return record; } +/* Initialize the va_list structure. */ + void -i860_va_start (tree valist, rtx nextarg) +i860_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED) { tree saveregs, t; - tree field_ireg_used, field_freg_used, field_reg_base, field_mem_ptr; - tree ireg_used, freg_used, reg_base, mem_ptr; - - saveregs = make_tree (build_pointer_type (va_list_type_node), - expand_builtin_saveregs ()); - saveregs = build1 (INDIRECT_REF, va_list_type_node, saveregs); + tree f_gpr, f_fpr, f_mem, f_sav; + tree gpr, fpr, mem, sav; + int off = 0; + saveregs = make_tree (ptr_type_node, expand_builtin_saveregs ()); #ifdef I860_SVR4_VA_LIST - field_ireg_used = TYPE_FIELDS (va_list_type_node); - field_freg_used = TREE_CHAIN (field_ireg_used); - field_reg_base = TREE_CHAIN (field_freg_used); - field_mem_ptr = TREE_CHAIN (field_reg_base); + f_gpr = TYPE_FIELDS (va_list_type_node); + f_fpr = TREE_CHAIN (f_gpr); + f_sav = TREE_CHAIN (f_fpr); + f_mem = TREE_CHAIN (f_sav); #else - field_reg_base = TYPE_FIELDS (va_list_type_node); - field_mem_ptr = TREE_CHAIN (field_reg_base); - field_ireg_used = TREE_CHAIN (field_mem_ptr); - field_freg_used = TREE_CHAIN (field_ireg_used); + f_sav = TYPE_FIELDS (va_list_type_node); + f_mem = TREE_CHAIN (f_sav); + f_gpr = TREE_CHAIN (f_mem); + f_fpr = TREE_CHAIN (f_gpr); #endif - ireg_used = build (COMPONENT_REF, TREE_TYPE (field_ireg_used), - valist, field_ireg_used); - freg_used = build (COMPONENT_REF, TREE_TYPE (field_freg_used), - valist, field_freg_used); - reg_base = build (COMPONENT_REF, TREE_TYPE (field_reg_base), - valist, field_reg_base); - mem_ptr = build (COMPONENT_REF, TREE_TYPE (field_mem_ptr), - valist, field_mem_ptr); + gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr); + fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr); + sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav); + mem = build (COMPONENT_REF, TREE_TYPE (f_mem), valist, f_mem); + + /* Initialize the `mem_ptr' field to the address of the first anonymous + stack argument. */ + t = make_tree (TREE_TYPE (mem), virtual_incoming_args_rtx); + off = INTVAL (current_function_arg_offset_rtx); + off = off < 0 ? 0 : off; + t = build (PLUS_EXPR, TREE_TYPE (mem), t, build_int_2 (off, 0)); + t = build (MODIFY_EXPR, TREE_TYPE (mem), mem, t); + TREE_SIDE_EFFECTS (t) = 1; + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); + /* Initialize the `ireg_used' field. */ t = build_int_2 (current_function_args_info.ints / UNITS_PER_WORD, 0); - t = build (MODIFY_EXPR, TREE_TYPE (ireg_used), ireg_used, t); + t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr, t); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); - - t = build_int_2 (ROUNDUP ((current_function_args_info.floats / UNITS_PER_WORD), 8), 0); - t = build (MODIFY_EXPR, TREE_TYPE (freg_used), freg_used, t); + + /* Initialize the `freg_used' field. */ + t = build_int_2 (current_function_args_info.floats / UNITS_PER_WORD, 0); + t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr, t); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); - t = build (COMPONENT_REF, TREE_TYPE (field_reg_base), - saveregs, field_reg_base); - t = build (MODIFY_EXPR, TREE_TYPE (reg_base), reg_base, t); - TREE_SIDE_EFFECTS (t) = 1; - expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); - - t = make_tree (ptr_type_node, nextarg); - t = build (MODIFY_EXPR, TREE_TYPE (mem_ptr), mem_ptr, t); + /* Initialize the `reg_base' field. */ + t = build (MODIFY_EXPR, TREE_TYPE (sav), sav, saveregs); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); } @@ -1893,116 +1919,136 @@ i860_va_start (tree valist, rtx nextarg) #define IREG_OFFSET 0 #endif +/* Update the VALIST structure as necessary for an + argument of the given TYPE, and return the argument. */ + rtx i860_va_arg (tree valist, tree type) { - tree field_ireg_used, field_freg_used, field_reg_base, field_mem_ptr; - tree type_ptr_node, t; - rtx lab_over = NULL_RTX; - rtx ret, val; - HOST_WIDE_INT align; + tree f_gpr, f_fpr, f_mem, f_sav; + tree gpr, fpr, mem, sav, reg, t, u; + int size, n_reg, sav_ofs, sav_scale, max_reg; + rtx lab_false, lab_over, addr_rtx, r; #ifdef I860_SVR4_VA_LIST - field_ireg_used = TYPE_FIELDS (va_list_type_node); - field_freg_used = TREE_CHAIN (field_ireg_used); - field_reg_base = TREE_CHAIN (field_freg_used); - field_mem_ptr = TREE_CHAIN (field_reg_base); + f_gpr = TYPE_FIELDS (va_list_type_node); + f_fpr = TREE_CHAIN (f_gpr); + f_sav = TREE_CHAIN (f_fpr); + f_mem = TREE_CHAIN (f_sav); #else - field_reg_base = TYPE_FIELDS (va_list_type_node); - field_mem_ptr = TREE_CHAIN (field_reg_base); - field_ireg_used = TREE_CHAIN (field_mem_ptr); - field_freg_used = TREE_CHAIN (field_ireg_used); + f_sav = TYPE_FIELDS (va_list_type_node); + f_mem = TREE_CHAIN (f_sav); + f_gpr = TREE_CHAIN (f_mem); + f_fpr = TREE_CHAIN (f_gpr); #endif - field_ireg_used = build (COMPONENT_REF, TREE_TYPE (field_ireg_used), - valist, field_ireg_used); - field_freg_used = build (COMPONENT_REF, TREE_TYPE (field_freg_used), - valist, field_freg_used); - field_reg_base = build (COMPONENT_REF, TREE_TYPE (field_reg_base), - valist, field_reg_base); - field_mem_ptr = build (COMPONENT_REF, TREE_TYPE (field_mem_ptr), - valist, field_mem_ptr); + gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr); + fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr); + mem = build (COMPONENT_REF, TREE_TYPE (f_mem), valist, f_mem); + sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav); - ret = gen_reg_rtx (Pmode); - type_ptr_node = build_pointer_type (type); + size = int_size_in_bytes (type); - if (! AGGREGATE_TYPE_P (type)) + if (AGGREGATE_TYPE_P (type)) { - int nparm, incr, ofs; - tree field; - rtx lab_false; + /* Aggregates are passed on the stack. */ + HOST_WIDE_INT align; + + align = TYPE_ALIGN (type); + if (align < BITS_PER_WORD) + align = BITS_PER_WORD; + align /= BITS_PER_UNIT; + + addr_rtx = gen_reg_rtx (Pmode); + t = build (PLUS_EXPR, ptr_type_node, mem, build_int_2 (align - 1, 0)); + t = build (BIT_AND_EXPR, ptr_type_node, t, build_int_2 (-align, -1)); + r = expand_expr (t, addr_rtx, VOIDmode /* Pmode */, EXPAND_NORMAL); + if (r != addr_rtx) + emit_move_insn (addr_rtx, r); + + t = fold (build (PLUS_EXPR, ptr_type_node, + make_tree (ptr_type_node, addr_rtx), + build_int_2 (size, 0))); + t = build (MODIFY_EXPR, ptr_type_node, mem, t); + TREE_SIDE_EFFECTS (t) = 1; + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); - if (FLOAT_TYPE_P (type)) - { - field = field_freg_used; - nparm = NUM_PARM_FREGS; - incr = 2; - ofs = FREG_OFFSET; - } - else - { - field = field_ireg_used; - nparm = NUM_PARM_IREGS; - incr = int_size_in_bytes (type) / UNITS_PER_WORD; - ofs = IREG_OFFSET; - } + return addr_rtx; + } + else if (FLOAT_TYPE_P (type) || (INTEGRAL_TYPE_P (type) && size == 8)) + { + /* Floats and long longs are passed in the floating-point registers. */ + reg = fpr; + n_reg = size / UNITS_PER_WORD; + sav_ofs = FREG_OFFSET; + sav_scale = UNITS_PER_WORD; + max_reg = NUM_PARM_FREGS; + } + else + { + /* Everything else is passed in general registers. */ + reg = gpr; + n_reg = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + sav_ofs = IREG_OFFSET; + sav_scale = UNITS_PER_WORD; + max_reg = NUM_PARM_IREGS; + if (n_reg > 1) + abort (); + } - lab_false = gen_label_rtx (); - lab_over = gen_label_rtx (); + /* The value was passed in a register, so read it from the register + save area initialized by __builtin_saveregs. */ - emit_cmp_and_jump_insns (expand_expr (field, NULL_RTX, 0, 0), - GEN_INT (nparm - incr), GT, const0_rtx, - TYPE_MODE (TREE_TYPE (field)), - TREE_UNSIGNED (field), lab_false); + lab_false = gen_label_rtx (); + lab_over = gen_label_rtx (); + addr_rtx = gen_reg_rtx (Pmode); - t = fold (build (POSTINCREMENT_EXPR, TREE_TYPE (field), field, - build_int_2 (incr, 0))); - TREE_SIDE_EFFECTS (t) = 1; + emit_cmp_and_jump_insns (expand_expr (reg, NULL_RTX, Pmode, EXPAND_NORMAL), + GEN_INT (max_reg - n_reg), + GT, const1_rtx, Pmode, 0, lab_false); - t = fold (build (MULT_EXPR, TREE_TYPE (field), t /* field */, - build_int_2 (UNITS_PER_WORD, 0))); - TREE_SIDE_EFFECTS (t) = 1; - - t = fold (build (PLUS_EXPR, ptr_type_node, field_reg_base, - fold (build (PLUS_EXPR, TREE_TYPE (field), t, - build_int_2 (ofs, 0))))); - TREE_SIDE_EFFECTS (t) = 1; - - val = expand_expr (t, ret, VOIDmode, EXPAND_NORMAL); - if (val != ret) - emit_move_insn (ret, val); + if (sav_ofs) + t = build (PLUS_EXPR, ptr_type_node, sav, build_int_2 (sav_ofs, 0)); + else + t = sav; - emit_jump_insn (gen_jump (lab_over)); - emit_barrier (); - emit_label (lab_false); - } + u = build (MULT_EXPR, long_integer_type_node, + reg, build_int_2 (sav_scale, 0)); + TREE_SIDE_EFFECTS (u) = 1; + + t = build (PLUS_EXPR, ptr_type_node, t, u); + TREE_SIDE_EFFECTS (t) = 1; + + r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL); + if (r != addr_rtx) + emit_move_insn (addr_rtx, r); - align = TYPE_ALIGN (type); - if (align < BITS_PER_WORD) - align = BITS_PER_WORD; - align /= BITS_PER_UNIT; + emit_jump_insn (gen_jump (lab_over)); + emit_barrier (); + emit_label (lab_false); - t = build (PLUS_EXPR, ptr_type_node, field_mem_ptr, - build_int_2 (align - 1, 0)); - t = build (BIT_AND_EXPR, ptr_type_node, t, build_int_2 (-align, -1)); + /* The value was passed in memory, so read it from the overflow area. */ - val = expand_expr (t, ret, VOIDmode, EXPAND_NORMAL); - if (val != ret) - emit_move_insn (ret, val); + t = save_expr (mem); + r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL); + if (r != addr_rtx) + emit_move_insn (addr_rtx, r); - t = fold (build (PLUS_EXPR, ptr_type_node, - make_tree (ptr_type_node, ret), - build_int_2 (int_size_in_bytes (type), 0))); - t = build (MODIFY_EXPR, ptr_type_node, field_mem_ptr, t); + t = build (PLUS_EXPR, TREE_TYPE (t), t, build_int_2 (size, 0)); + t = build (MODIFY_EXPR, TREE_TYPE (mem), mem, t); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); - if (lab_over) - emit_label (lab_over); + emit_label (lab_over); - return ret; -} + /* Increment either the ireg_used or freg_used field. */ + u = build (PREINCREMENT_EXPR, TREE_TYPE (reg), reg, build_int_2 (n_reg, 0)); + TREE_SIDE_EFFECTS (u) = 1; + expand_expr (u, const0_rtx, VOIDmode, EXPAND_NORMAL); + + return addr_rtx; +} /* Compute a (partial) cost for rtx X. Return true if the complete cost has been computed, and false if subexpressions should be diff --git a/gcc/config/i860/i860.h b/gcc/config/i860/i860.h index 231cbed45d7..38ddc1c75c1 100644 --- a/gcc/config/i860/i860.h +++ b/gcc/config/i860/i860.h @@ -836,7 +836,7 @@ struct cumulative_args { int ints, floats; }; /* #define CASE_VECTOR_PC_RELATIVE 1 */ /* Must pass floats to libgcc functions as doubles. */ -#define LIBGCC_NEEDS_DOUBLE 1 +/* #define LIBGCC_NEEDS_DOUBLE 1 */ #define DIVSI3_LIBCALL "*.div" #define UDIVSI3_LIBCALL "*.udiv" diff --git a/gcc/config/i860/varargs.asm b/gcc/config/i860/varargs.asm index f740426172b..ff58d7325b0 100644 --- a/gcc/config/i860/varargs.asm +++ b/gcc/config/i860/varargs.asm @@ -38,9 +38,13 @@ __builtin_saveregs: ___builtin_saveregs: andnot 0x0f,%sp,%sp /* round down to 16-byte boundary */ +#if 0 adds -96,%sp,%sp /* allocate stack space for reg save area and also for a new va_list structure */ +#else + adds -80,%sp,%sp /* allocate stack space for reg save area */ +#endif /* Save all argument registers in the arg reg save area. The arg reg save area must have the following layout (according to the svr4 ABI): @@ -70,10 +74,12 @@ ___builtin_saveregs: st.l %r26,72(%sp) st.l %r27,76(%sp) +#if 0 adds 80,%sp,%r16 /* compute the address of the new va_list structure. Put in into r16 so that it will be returned to the caller. */ +#endif /* Initialize all fields of the new va_list structure. This structure looks like: @@ -86,11 +92,16 @@ ___builtin_saveregs: } va_list; */ +#if 0 st.l %r0, 0(%r16) /* nfixed */ st.l %r0, 4(%r16) /* nfloating */ st.l %sp, 8(%r16) /* __va_ctl points to __va_struct. */ bri %r1 /* delayed return */ st.l %r28,12(%r16) /* pointer to overflow args */ +#else + bri %r1 /* delayed return */ + or %sp,%r0,%r16 /* Return the address of the reg save area. */ +#endif #else /* not __svr4__ */ #if defined(__PARAGON__)