diff options
author | Alan Modra <amodra@gcc.gnu.org> | 2004-03-13 17:44:12 +1030 |
---|---|---|
committer | Alan Modra <amodra@gcc.gnu.org> | 2004-03-13 17:44:12 +1030 |
commit | c53bdcf59be1f9b9c8bc10ec3388564f47d62acf (patch) | |
tree | 6203b2eff0f970afb254fb285321946988596d59 /gcc | |
parent | 8b0d605196ebf4556ef13b3a5a62d69f20ed2e36 (diff) | |
download | gcc-c53bdcf59be1f9b9c8bc10ec3388564f47d62acf.zip gcc-c53bdcf59be1f9b9c8bc10ec3388564f47d62acf.tar.gz gcc-c53bdcf59be1f9b9c8bc10ec3388564f47d62acf.tar.bz2 |
re PR target/14567 ([3.4 only] long double and va_arg complex args)
PR target/14567
* config/rs6000/rs6000.h (UNITS_PER_ARG, RS6000_ARG_SIZE): Delete.
(HARD_REGNO_MODE_OK): Disallow TFmode for fp31.
* config/rs6000/rs6000.c (rs6000_arg_size): New function.
Update all users of RS6000_ARG_SIZE.
(function_arg_advance): Count fregno using mode size.
(function_arg): Handle long double split over regs and memory.
(function_arg_partial_nregs): Likewise.
(rs6000_va_arg): Repackage complex args.
From-SVN: r79436
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 34 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.c | 188 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.h | 13 |
3 files changed, 162 insertions, 73 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 002ad1d..33d6149 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2004-03-13 Alan Modra <amodra@bigpond.net.au> + + PR target/14567 + * config/rs6000/rs6000.h (UNITS_PER_ARG, RS6000_ARG_SIZE): Delete. + (HARD_REGNO_MODE_OK): Disallow TFmode for fp31. + * config/rs6000/rs6000.c (rs6000_arg_size): New function. + Update all users of RS6000_ARG_SIZE. + (function_arg_advance): Count fregno using mode size. + (function_arg): Handle long double split over regs and memory. + (function_arg_partial_nregs): Likewise. + (rs6000_va_arg): Repackage complex args. + 2004-03-13 Dean Ferreyra <dferreyra@igc.org> PR target/14047 @@ -54,7 +66,7 @@ that corresponds to this FDE. (FRAME_BEGIN_LABEL): Allow target to override default label. (output_call_frame_info): If FDEs are linknonce, then use extra - indirection for FDE encoding, output a label for each FDE, and + indirection for FDE encoding, output a label for each FDE, and output an empty label for each function without an FDE. (dwarf2out_begin_prologue): Set up decl field when creating an FDE. * varasm.c (globalize_decl): Call ASM_MAKE_LABEL_LINKONCE for @@ -114,10 +126,10 @@ * target.h (struct gcc_target): Move calls substructure before booleans. Add split_complex_arg. * function.c (assign_parms, split_complex_args): Use it. - * calls.c (expand_call): Likewise. - (split_complex_values): Likewise. Check for splittable types - before allocating memory. - (split_complex_types): Likewise. + * calls.c (expand_call): Likewise. + (split_complex_values): Likewise. Check for splittable types + before allocating memory. + (split_complex_types): Likewise. * system.h (SPLIT_COMPLEX_ARGS): Poison. * expr.h (SPLIT_COMPLEX_ARGS): Remove. * target-def.h (TARGET_SPLIT_COMPLEX_ARG): New. @@ -247,7 +259,7 @@ (set_frame_base_location): Unshare variable if needed. (set_variable_part): Init the refcount of new variable. Unshare the variables if needed. - (delete_variable_part): Unshare the variables if needed. + (delete_variable_part): Unshare the variables if needed. (emit_notes_for_differences_1): Init the refcount of new variable. (vt_add_function_parameters): Do not add function parameters to IN set of ENTRY_BLOCK_PTR because it is unused anyway. @@ -310,7 +322,7 @@ and gt_pch_use_address. * config/host-linux.c, config/host-solaris.c: New files. * config/x-linux, config/x-solaris: New files. - * config/rs6000/host-darwin.c darwin_rs6000_gt_pch_get_address): + * config/rs6000/host-darwin.c (darwin_rs6000_gt_pch_get_address): Update for changed definition. (darwin_rs6000_gt_pch_use_address): Likewise. * doc/hostconfig.texi: Update docs. @@ -407,7 +419,7 @@ PR bootstrap/12371 * config/m68k/m68k.h (FIXED_REGISTERS): Add arg pointer. (CALL_USED_REGISTERS): Likewise. - (REG_CLASS_CONTENTS): Likewise. + (REG_CLASS_CONTENTS): Likewise. (REG_ALLOC_ORDER): New. (REGNO_REG_CLASS): Use regno_reg_class. * config/m68k/m68k.c: Add regno_reg_class array. @@ -2099,7 +2111,7 @@ * toplev.c (dump_file_tbl): Rename from dump_file. * bb-reorder.c, bt-load.c, cfgcleanup.c, cfglayout.c, cfgloopanal.c, - cfgloopmanip.c, cfgrtl.c, config/arm/arm.c, config/frv/frv.c, + cfgloopmanip.c, cfgrtl.c, config/arm/arm.c, config/frv/frv.c, config/i386/i386.c, config/ia64/ia64.c, config/mips/mips.c, config/sh/sh.c, cse.c, flow.c, ifcvt.c, loop-iv.c, loop-unroll.c, loop-unswitch.c, output.h, predict.c, profile.c, ra-build.c, @@ -5827,7 +5839,7 @@ 2004-01-31 Paolo Bonzini <bonzini@gnu.org> - * combine.c (cse_main): Set gen_lowpart to gen_lowpart_for_combine + * combine.c (cse_main): Set gen_lowpart to gen_lowpart_for_combine and restore it to gen_lowpart_general on exit. (gen_lowpart_for_combine): Adjust all callers to go through gen_lowpart. @@ -8109,7 +8121,7 @@ * fixinc/inclhack.def (alpha___extern_prefix, alpha___extern_prefix_standards): New hacks to obey - __PRAGMA_EXTERN_PREFIX. + __PRAGMA_EXTERN_PREFIX. * fixinc/tests/base/testing.h [ALPHA___EXTERN_PREFIX_CHECK]: New test. * fixinc/tests/base/standards.h: Likewise. diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 5577464..56e4e76 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -3979,6 +3979,24 @@ function_arg_boundary (enum machine_mode mode, tree type ATTRIBUTE_UNUSED) else return PARM_BOUNDARY; } + +/* Compute the size (in words) of a function argument. */ + +static unsigned long +rs6000_arg_size (enum machine_mode mode, tree type) +{ + unsigned long size; + + if (mode != BLKmode) + size = GET_MODE_SIZE (mode); + else + size = int_size_in_bytes (type); + + if (TARGET_32BIT) + return (size + 3) >> 2; + else + return (size + 7) >> 3; +} /* Update the data in CUM to advance over an argument of mode MODE and data type TYPE. @@ -4019,7 +4037,7 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, align = ((6 - (cum->words & 3)) & 3); else align = cum->words & 1; - cum->words += align + RS6000_ARG_SIZE (mode, type); + cum->words += align + rs6000_arg_size (mode, type); if (TARGET_DEBUG_ARG) { @@ -4046,7 +4064,7 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, { if (mode == DFmode) cum->words += cum->words & 1; - cum->words += RS6000_ARG_SIZE (mode, type); + cum->words += rs6000_arg_size (mode, type); } } else @@ -4059,7 +4077,7 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, || mode == TFmode) n_words = 1; else - n_words = RS6000_ARG_SIZE (mode, type); + n_words = rs6000_arg_size (mode, type); /* Long long and SPE vectors are put in odd registers. */ if (n_words == 2 && (gregno & 1) == 0) @@ -4096,11 +4114,11 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, int align = (TARGET_32BIT && (cum->words & 1) != 0 && function_arg_boundary (mode, type) == 64) ? 1 : 0; - cum->words += align + RS6000_ARG_SIZE (mode, type); + cum->words += align + rs6000_arg_size (mode, type); if (GET_MODE_CLASS (mode) == MODE_FLOAT && TARGET_HARD_FLOAT && TARGET_FPRS) - cum->fregno += (mode == TFmode ? 2 : 1); + cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3; if (TARGET_DEBUG_ARG) { @@ -4122,7 +4140,7 @@ rs6000_spe_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, if (cum->stdarg) { int gregno = cum->sysv_gregno; - int n_words = RS6000_ARG_SIZE (mode, type); + int n_words = rs6000_arg_size (mode, type); /* SPE vectors are put in odd registers. */ if (n_words == 2 && (gregno & 1) == 0) @@ -4170,7 +4188,7 @@ rs6000_mixed_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, gen_rtx_REG (mode, cum->fregno), const0_rtx))); - else if (align_words + RS6000_ARG_SIZE (mode, type) + else if (align_words + rs6000_arg_size (mode, type) > GP_ARG_NUM_REG) /* If this is partially on the stack, then we only include the portion actually in registers here. */ @@ -4394,13 +4412,13 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, || mode == TFmode) n_words = 1; else - n_words = RS6000_ARG_SIZE (mode, type); + n_words = rs6000_arg_size (mode, type); /* Long long and SPE vectors are put in odd registers. */ if (n_words == 2 && (gregno & 1) == 0) gregno += 1; - /* Long long do not split between registers and stack. */ + /* Long long does not split between registers and stack. */ if (gregno + n_words - 1 <= GP_ARG_MAX_REG) return gen_rtx_REG (mode, gregno); else @@ -4422,39 +4440,69 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, if (USE_FP_FOR_ARG_P (cum, mode, type)) { - if (! type - || ((cum->nargs_prototype > 0) - /* IBM AIX extended its linkage convention definition always - to require FP args after register save area hole on the - stack. */ - && (DEFAULT_ABI != ABI_AIX - || ! TARGET_XL_CALL - || (align_words < GP_ARG_NUM_REG)))) - return gen_rtx_REG (mode, cum->fregno); + rtx fpr[2]; + rtx *r; + bool needs_psave; + enum machine_mode fmode = mode; + int n; + unsigned long n_fpreg = (GET_MODE_SIZE (mode) + 7) >> 3; + + if (cum->fregno + n_fpreg > FP_ARG_MAX_REG + 1) + { + /* Long double split over regs and memory. */ + if (fmode == TFmode) + fmode = DFmode; + + /* Currently, we only ever need one reg here because complex + doubles are split. */ + if (cum->fregno != FP_ARG_MAX_REG - 1) + abort (); + } + fpr[1] = gen_rtx_REG (fmode, cum->fregno); + + /* Do we also need to pass this arg in the parameter save + area? */ + needs_psave = (type + && (cum->nargs_prototype <= 0 + || (DEFAULT_ABI == ABI_AIX + && TARGET_XL_CALL + && align_words >= GP_ARG_NUM_REG))); + + if (!needs_psave && mode == fmode) + return fpr[1]; if (TARGET_32BIT && TARGET_POWERPC64 && mode == DFmode && cum->stdarg) return rs6000_mixed_function_arg (cum, mode, type, align_words); - return gen_rtx_PARALLEL (mode, - gen_rtvec (2, - gen_rtx_EXPR_LIST (VOIDmode, - ((align_words >= GP_ARG_NUM_REG) - ? NULL_RTX - : (align_words - + RS6000_ARG_SIZE (mode, type) - > GP_ARG_NUM_REG - /* If this is partially on the stack, then - we only include the portion actually - in registers here. */ - ? gen_rtx_REG (Pmode, - GP_ARG_MIN_REG + align_words) - : gen_rtx_REG (mode, - GP_ARG_MIN_REG + align_words))), - const0_rtx), - gen_rtx_EXPR_LIST (VOIDmode, - gen_rtx_REG (mode, cum->fregno), - const0_rtx))); + /* Describe where this piece goes. */ + r = fpr + 1; + *r = gen_rtx_EXPR_LIST (VOIDmode, *r, const0_rtx); + n = 1; + + if (needs_psave) + { + /* Now describe the part that goes in gprs or the stack. + This piece must come first, before the fprs. */ + rtx reg = NULL_RTX; + if (align_words < GP_ARG_NUM_REG) + { + unsigned long n_words = rs6000_arg_size (mode, type); + enum machine_mode rmode = mode; + + if (align_words + n_words > GP_ARG_NUM_REG) + /* If this is partially on the stack, then we only + include the portion actually in registers here. + We know this can only be one register because + complex doubles are splt. */ + rmode = Pmode; + reg = gen_rtx_REG (rmode, GP_ARG_MIN_REG + align_words); + } + *--r = gen_rtx_EXPR_LIST (VOIDmode, reg, const0_rtx); + ++n; + } + + return gen_rtx_PARALLEL (mode, gen_rtvec_v (n, r)); } else if (align_words < GP_ARG_NUM_REG) return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words); @@ -4471,27 +4519,31 @@ int function_arg_partial_nregs (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type, int named) { + int ret = 0; + if (DEFAULT_ABI == ABI_V4) return 0; - if (USE_FP_FOR_ARG_P (cum, mode, type) - || USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named)) + if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named) + && cum->nargs_prototype >= 0) + return 0; + + if (USE_FP_FOR_ARG_P (cum, mode, type)) { - if (cum->nargs_prototype >= 0) + if (cum->fregno + ((GET_MODE_SIZE (mode) + 7) >> 3) > FP_ARG_MAX_REG + 1) + ret = FP_ARG_MAX_REG - cum->fregno; + else if (cum->nargs_prototype >= 0) return 0; } if (cum->words < GP_ARG_NUM_REG - && GP_ARG_NUM_REG < (cum->words + RS6000_ARG_SIZE (mode, type))) - { - int ret = GP_ARG_NUM_REG - cum->words; - if (ret && TARGET_DEBUG_ARG) - fprintf (stderr, "function_arg_partial_nregs: %d\n", ret); + && GP_ARG_NUM_REG < cum->words + rs6000_arg_size (mode, type)) + ret = GP_ARG_NUM_REG - cum->words; - return ret; - } + if (ret != 0 && TARGET_DEBUG_ARG) + fprintf (stderr, "function_arg_partial_nregs: %d\n", ret); - return 0; + return ret; } /* A C expression that indicates when an argument must be passed by @@ -4597,7 +4649,7 @@ setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode, cfun->machine->sysv_varargs_p = 0; if (MUST_PASS_IN_STACK (mode, type)) - first_reg_offset += RS6000_ARG_SIZE (TYPE_MODE (type), type); + first_reg_offset += rs6000_arg_size (TYPE_MODE (type), type); } set = get_varargs_alias_set (); @@ -4787,8 +4839,42 @@ rs6000_va_arg (tree valist, tree type) return expand_expr (t, NULL_RTX, VOIDmode, EXPAND_NORMAL); } - else - return std_expand_builtin_va_arg (valist, type); + if (SPLIT_COMPLEX_ARGS + && TREE_CODE (type) == COMPLEX_TYPE) + { + tree elem_type = TREE_TYPE (type); + enum machine_mode elem_mode = TYPE_MODE (elem_type); + int elem_size = GET_MODE_SIZE (elem_mode); + + if (elem_size < UNITS_PER_WORD) + { + rtx real_part, imag_part, dest_real, rr; + + real_part = rs6000_va_arg (valist, elem_type); + imag_part = rs6000_va_arg (valist, elem_type); + + /* We're not returning the value here, but the address. + real_part and imag_part are not contiguous, and we know + there is space available to pack real_part next to + imag_part. float _Complex is not promoted to + double _Complex by the default promotion rules that + promote float to double. */ + if (2 * elem_size > UNITS_PER_WORD) + abort (); + + real_part = gen_rtx_MEM (elem_mode, real_part); + imag_part = gen_rtx_MEM (elem_mode, imag_part); + + dest_real = adjust_address (imag_part, elem_mode, -elem_size); + rr = gen_reg_rtx (elem_mode); + emit_move_insn (rr, real_part); + emit_move_insn (dest_real, rr); + + return XEXP (dest_real, 0); + } + } + + return std_expand_builtin_va_arg (valist, type); } f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node)); diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index aceb56d..bd9d36b 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -1065,7 +1065,8 @@ extern const char *rs6000_warn_altivec_long_switch; (INT_REGNO_P (REGNO) ? \ INT_REGNO_P (REGNO + HARD_REGNO_NREGS (REGNO, MODE) - 1) \ : FP_REGNO_P (REGNO) ? \ - (GET_MODE_CLASS (MODE) == MODE_FLOAT \ + ((GET_MODE_CLASS (MODE) == MODE_FLOAT \ + && FP_REGNO_P (REGNO + HARD_REGNO_NREGS (REGNO, MODE) - 1)) \ || (GET_MODE_CLASS (MODE) == MODE_INT \ && GET_MODE_SIZE (MODE) == UNITS_PER_FP_WORD)) \ : ALTIVEC_REGNO_P (REGNO) ? ALTIVEC_VECTOR_MODE (MODE) \ @@ -1762,16 +1763,6 @@ typedef struct rs6000_args int sysv_gregno; /* next available GP register */ } CUMULATIVE_ARGS; -/* Define intermediate macro to compute the size (in registers) of an argument - for the RS/6000. */ - -#define UNITS_PER_ARG (TARGET_32BIT ? 4 : 8) - -#define RS6000_ARG_SIZE(MODE, TYPE) \ -((MODE) != BLKmode \ - ? (GET_MODE_SIZE (MODE) + (UNITS_PER_ARG - 1)) / UNITS_PER_ARG \ - : (int_size_in_bytes (TYPE) + (UNITS_PER_ARG - 1)) / UNITS_PER_ARG) - /* Initialize a variable CUM of type CUMULATIVE_ARGS for a call to a function whose data type is FNTYPE. For a library call, FNTYPE is 0. */ |