diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 901e4131f77..1dfcd6cf5e0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +Sun Jul 25 22:45:55 1999 Richard Henderson + + * alpha.h (EXPAND_BUILTIN_SAVEREGS): Delete. + (BUILD_VA_LIST_TYPE): New. + (EXPAND_BUILTIN_VA_START): New. + (EXPAND_BUILTIN_VA_ARG): New. + * alpha.c (alpha_builtin_saveregs): Delete. + (alpha_build_va_list): New. + (alpha_va_start): New. + (alpha_va_arg): New. + Sun Jul 25 21:40:33 1999 Jeffrey A Law (law@cygnus.com) * gcc.texi: More changes related to list conversion. diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c index a1e8770eb0d..9f07b21df06 100644 --- a/gcc/config/alpha/alpha.c +++ b/gcc/config/alpha/alpha.c @@ -3083,101 +3083,132 @@ alpha_initialize_trampoline (tramp, fnaddr, cxt, fnofs, cxtofs, jmpofs) emit_insn (gen_imb ()); } -/* Do what is necessary for `va_start'. The argument is ignored; - We look at the current function to determine if stdarg or varargs - is used and fill in an initial va_list. A pointer to this constructor - is returned. */ - -struct rtx_def * -alpha_builtin_saveregs (arglist) - tree arglist ATTRIBUTE_UNUSED; +tree +alpha_build_va_list () { - rtx block, addr, dest, argsize; - tree fntype = TREE_TYPE (current_function_decl); - int stdarg = (TYPE_ARG_TYPES (fntype) != 0 - && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) - != void_type_node)); - - /* Compute the current position into the args, taking into account - both registers and memory. Both of these are already included in - NUM_ARGS. */ - - argsize = GEN_INT (NUM_ARGS * UNITS_PER_WORD); - - /* For Unix, SETUP_INCOMING_VARARGS moves the starting address base up by 48, - storing fp arg registers in the first 48 bytes, and the integer arg - registers in the next 48 bytes. This is only done, however, if any - integer registers need to be stored. - - If no integer registers need be stored, then we must subtract 48 in - order to account for the integer arg registers which are counted in - argsize above, but which are not actually stored on the stack. */ + tree base, ofs, record; if (TARGET_OPEN_VMS) - addr = plus_constant (virtual_incoming_args_rtx, - NUM_ARGS <= 5 + stdarg - ? UNITS_PER_WORD : - 6 * UNITS_PER_WORD); + return ptr_type_node; + + record = make_node (RECORD_TYPE); + /* C++? SET_IS_AGGR_TYPE (record, 1); */ + + ofs = build_decl (FIELD_DECL, get_identifier ("__offset"), + integer_type_node); + DECL_FIELD_CONTEXT (ofs) = record; + + base = build_decl (FIELD_DECL, get_identifier ("__base"), + ptr_type_node); + DECL_FIELD_CONTEXT (base) = record; + TREE_CHAIN (base) = ofs; + + TYPE_FIELDS (record) = base; + layout_type (record); + + return record; +} + +void +alpha_va_start (stdarg_p, valist, nextarg) + int stdarg_p; + tree valist; + rtx nextarg ATTRIBUTE_UNUSED; +{ + HOST_WIDE_INT offset; + tree t, offset_field, base_field; + + if (TARGET_OPEN_VMS) + std_expand_builtin_va_start (stdarg_p, valist, nextarg); + + /* For Unix, SETUP_INCOMING_VARARGS moves the starting address base + up by 48, storing fp arg registers in the first 48 bytes, and the + integer arg registers in the next 48 bytes. This is only done, + however, if any integer registers need to be stored. + + If no integer registers need be stored, then we must subtract 48 + in order to account for the integer arg registers which are counted + in argsize above, but which are not actually stored on the stack. */ + + if (NUM_ARGS <= 5 + stdarg_p) + offset = 6 * UNITS_PER_WORD; else - addr = (NUM_ARGS <= 5 + stdarg - ? plus_constant (virtual_incoming_args_rtx, - 6 * UNITS_PER_WORD) - : plus_constant (virtual_incoming_args_rtx, - - (6 * UNITS_PER_WORD))); + offset = -6 * UNITS_PER_WORD; - /* For VMS, we include the argsize, while on Unix, it's handled as - a separate field. */ - if (TARGET_OPEN_VMS) - addr = plus_constant (addr, INTVAL (argsize)); + base_field = TYPE_FIELDS (TREE_TYPE (valist)); + offset_field = TREE_CHAIN (base_field); - addr = force_operand (addr, NULL_RTX); + base_field = build (COMPONENT_REF, TREE_TYPE (base_field), + valist, base_field); + offset_field = build (COMPONENT_REF, TREE_TYPE (offset_field), + valist, offset_field); -#ifdef POINTERS_EXTEND_UNSIGNED - addr = convert_memory_address (ptr_mode, addr); -#endif + t = make_tree (ptr_type_node, virtual_incoming_args_rtx); + t = build (PLUS_EXPR, ptr_type_node, t, build_int_2 (offset, 0)); + t = build (MODIFY_EXPR, TREE_TYPE (base_field), base_field, t); + TREE_SIDE_EFFECTS (t) = 1; + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); + + t = build_int_2 (NUM_ARGS*UNITS_PER_WORD, 0); + t = build (MODIFY_EXPR, TREE_TYPE (offset_field), offset_field, t); + TREE_SIDE_EFFECTS (t) = 1; + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); +} + +rtx +alpha_va_arg (valist, type) + tree valist, type; +{ + HOST_WIDE_INT tsize; + rtx addr; + tree t; + tree offset_field, base_field, addr_tree, addend; + tree wide_type, wide_ofs; if (TARGET_OPEN_VMS) - return addr; - else + return std_expand_builtin_va_arg (valist, type); + + tsize = ((TREE_INT_CST_LOW (TYPE_SIZE (type)) / BITS_PER_UNIT + 7) / 8) * 8; + + base_field = TYPE_FIELDS (TREE_TYPE (valist)); + offset_field = TREE_CHAIN (base_field); + + base_field = build (COMPONENT_REF, TREE_TYPE (base_field), + valist, base_field); + offset_field = build (COMPONENT_REF, TREE_TYPE (offset_field), + valist, offset_field); + + wide_type = make_signed_type (64); + wide_ofs = save_expr (build1 (CONVERT_EXPR, wide_type, offset_field)); + + addend = wide_ofs; + if (FLOAT_TYPE_P (type)) { - /* Allocate the va_list constructor */ - block = assign_stack_local (BLKmode, 2 * UNITS_PER_WORD, BITS_PER_WORD); - RTX_UNCHANGING_P (block) = 1; - RTX_UNCHANGING_P (XEXP (block, 0)) = 1; + tree fpaddend, cond; - /* Store the address of the first integer register in the __base - member. */ + fpaddend = fold (build (PLUS_EXPR, TREE_TYPE (addend), + addend, build_int_2 (-6*8, 0))); - dest = change_address (block, ptr_mode, XEXP (block, 0)); - emit_move_insn (dest, addr); + cond = fold (build (LT_EXPR, integer_type_node, + wide_ofs, build_int_2 (6*8, 0))); - if (current_function_check_memory_usage) - emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3, - dest, ptr_mode, - GEN_INT (GET_MODE_SIZE (ptr_mode)), - TYPE_MODE (sizetype), - GEN_INT (MEMORY_USE_RW), - TYPE_MODE (integer_type_node)); - - /* Store the argsize as the __va_offset member. */ - dest = change_address (block, TYPE_MODE (integer_type_node), - plus_constant (XEXP (block, 0), - POINTER_SIZE/BITS_PER_UNIT)); - emit_move_insn (dest, argsize); - - if (current_function_check_memory_usage) - emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3, - dest, ptr_mode, - GEN_INT (GET_MODE_SIZE - (TYPE_MODE (integer_type_node))), - TYPE_MODE (sizetype), - GEN_INT (MEMORY_USE_RW), - TYPE_MODE (integer_type_node)); - - /* Return the address of the va_list constructor, but don't put it in a - register. Doing so would fail when not optimizing and produce worse - code when optimizing. */ - return XEXP (block, 0); + addend = fold (build (COND_EXPR, TREE_TYPE (addend), cond, + fpaddend, addend)); } + + addr_tree = build (PLUS_EXPR, TREE_TYPE (base_field), + base_field, addend); + + addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL); + addr = copy_to_reg (addr); + + t = build (MODIFY_EXPR, TREE_TYPE (offset_field), offset_field, + build (PLUS_EXPR, TREE_TYPE (offset_field), + offset_field, build_int_2 (tsize, 0))); + TREE_SIDE_EFFECTS (t) = 1; + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); + + return addr; } /* This page contains routines that are used to determine what the function diff --git a/gcc/config/alpha/alpha.h b/gcc/config/alpha/alpha.h index e9c3f6d2f68..5499edb66db 100644 --- a/gcc/config/alpha/alpha.h +++ b/gcc/config/alpha/alpha.h @@ -1161,19 +1161,22 @@ extern int alpha_memory_latency; { \ if (! (NO_RTL)) \ { \ + rtx tmp; int set = get_varargs_alias_set (); \ + tmp = gen_rtx_MEM (BLKmode, \ + plus_constant (virtual_incoming_args_rtx, \ + ((CUM) + 6)* UNITS_PER_WORD)); \ + MEM_ALIAS_SET (tmp) = set; \ move_block_from_reg \ - (16 + CUM, \ - gen_rtx (MEM, BLKmode, \ - plus_constant (virtual_incoming_args_rtx, \ - ((CUM) + 6)* UNITS_PER_WORD)), \ + (16 + CUM, tmp, \ 6 - (CUM), (6 - (CUM)) * UNITS_PER_WORD); \ + \ + tmp = gen_rtx_MEM (BLKmode, \ + plus_constant (virtual_incoming_args_rtx, \ + (CUM) * UNITS_PER_WORD)); \ + MEM_ALIAS_SET (tmp) = set; \ move_block_from_reg \ - (16 + (TARGET_FPREGS ? 32 : 0) + CUM, \ - gen_rtx (MEM, BLKmode, \ - plus_constant (virtual_incoming_args_rtx, \ - (CUM) * UNITS_PER_WORD)), \ + (16 + (TARGET_FPREGS ? 32 : 0) + CUM, tmp, \ 6 - (CUM), (6 - (CUM)) * UNITS_PER_WORD); \ - emit_insn (gen_blockage ()); \ } \ PRETEND_SIZE = 12 * UNITS_PER_WORD; \ } \ @@ -1189,11 +1192,6 @@ extern struct rtx_def *alpha_emit_set_long_const (); extern struct rtx_def *alpha_emit_conditional_branch (); extern struct rtx_def *alpha_emit_conditional_move (); -/* Generate necessary RTL for __builtin_saveregs(). - ARGLIST is the argument list; see expr.c. */ -extern struct rtx_def *alpha_builtin_saveregs (); -#define EXPAND_BUILTIN_SAVEREGS(ARGLIST) alpha_builtin_saveregs (ARGLIST) - /* Define the information needed to generate branch and scc insns. This is stored from the compare operation. Note that we can't use "rtx" here since it hasn't been defined! */ @@ -2348,6 +2346,18 @@ do { \ {"reg_not_elim_operand", {SUBREG, REG}}, \ {"reg_no_subreg_operand", {REG}}, +/* Define the `__builtin_va_list' type for the ABI. */ +#define BUILD_VA_LIST_TYPE(VALIST) \ + (VALIST) = alpha_build_va_list () + +/* Implement `va_start' for varargs and stdarg. */ +#define EXPAND_BUILTIN_VA_START(stdarg, valist, nextarg) \ + alpha_va_start (stdarg, valist, nextarg) + +/* Implement `va_arg'. */ +#define EXPAND_BUILTIN_VA_ARG(valist, type) \ + alpha_va_arg (valist, type) + /* Tell collect that the object format is ECOFF. */ #define OBJECT_FORMAT_COFF #define EXTENDED_COFF @@ -2548,3 +2558,6 @@ extern int alpha_expand_block_move (); extern int alpha_expand_block_clear (); extern void alpha_expand_prologue (); extern void alpha_expand_epilogue (); +extern union tree_node *alpha_build_va_list (); +extern void alpha_va_start (); +extern struct rtx_def *alpha_va_arg ();