diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 21 | ||||
-rw-r--r-- | gcc/config/sh/sh.c | 65 | ||||
-rw-r--r-- | gcc/config/sh/sh.h | 96 |
3 files changed, 139 insertions, 43 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 53609e4..6b63396 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,24 @@ +2003-06-24 J"orn Rennecke <joern.rennecke@superh.com> + + Back out these patches: + 2003-06-02 J"orn Rennecke <joern.rennecke@superh.com> + * sh.h (OLD_ARG_MODE): New macro. + (FUNCTION_ARG_ADVANCE, FUNCTION_ARG_PASS_BY_REFERENCE): Use it. + (FUNCTION_ARG_1): Break out of: + (FUNCTION_ARG). Use OLD_ARG_MODE. + 2003-06-06 J"orn Rennecke <joern.rennecke@superh.com> + * sh.h (FUNCTION_ARG_1): Consistently use NEW_MODE for the mode + of the generated register. + + * sh.h (FUNCTION_ARG_SCmode_WART): Define. + (FUNCTION_ARG): Unless FUNCTION_ARG_SCmode_WART is defined and + an even number of floating point regs are in use, use the same + sequence of argument passing registers for SCmode as would be + used for two SFmode values. + * sh.c (sh_va_arg): If FUNCTION_ARG_SCmode_WART is defined, + swap real / imaginary parts in incoming SCmode values passed + in registers. + 2003-06-24 Falk Hueffner <falk.hueffner@student.uni-tuebingen.de> PR target/11260 diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index 070e409..aab3c39 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -5940,8 +5940,9 @@ sh_va_arg (valist, type) HOST_WIDE_INT size, rsize; tree tmp, pptr_type_node; rtx addr_rtx, r; - rtx result; + rtx result_ptr, result = NULL_RTX; int pass_by_ref = MUST_PASS_IN_STACK (TYPE_MODE (type), type); + rtx lab_over; size = int_size_in_bytes (type); rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD; @@ -5955,7 +5956,7 @@ sh_va_arg (valist, type) tree f_next_o, f_next_o_limit, f_next_fp, f_next_fp_limit, f_next_stack; tree next_o, next_o_limit, next_fp, next_fp_limit, next_stack; int pass_as_float; - rtx lab_false, lab_over; + rtx lab_false; f_next_o = TYPE_FIELDS (va_list_type_node); f_next_o_limit = TREE_CHAIN (f_next_o); @@ -5973,6 +5974,16 @@ sh_va_arg (valist, type) next_stack = build (COMPONENT_REF, TREE_TYPE (f_next_stack), valist, f_next_stack); + /* Structures with a single member with a distinct mode are passed + like their member. This is relevant if the latter has a REAL_TYPE + or COMPLEX_TYPE type. */ + if (TREE_CODE (type) == RECORD_TYPE + && TYPE_FIELDS (type) + && TREE_CODE (TYPE_FIELDS (type)) == FIELD_DECL + && (TREE_CODE (TREE_TYPE (TYPE_FIELDS (type))) == REAL_TYPE + || TREE_CODE (TREE_TYPE (TYPE_FIELDS (type))) == COMPLEX_TYPE) + && TREE_CHAIN (TYPE_FIELDS (type)) == NULL_TREE) + type = TREE_TYPE (TYPE_FIELDS (type)); if (TARGET_SH4) { pass_as_float = ((TREE_CODE (type) == REAL_TYPE && size <= 8) @@ -5989,6 +6000,9 @@ sh_va_arg (valist, type) lab_false = gen_label_rtx (); lab_over = gen_label_rtx (); + tmp = make_tree (pptr_type_node, addr_rtx); + valist = build1 (INDIRECT_REF, ptr_type_node, tmp); + if (pass_as_float) { int first_floatreg @@ -6018,6 +6032,37 @@ sh_va_arg (valist, type) if (r != addr_rtx) emit_move_insn (addr_rtx, r); +#ifdef FUNCTION_ARG_SCmode_WART + if (TYPE_MODE (type) == SCmode && TARGET_SH4 && TARGET_LITTLE_ENDIAN) + { + rtx addr, real, imag, result_value, slot; + tree subtype = TREE_TYPE (type); + + addr = std_expand_builtin_va_arg (valist, subtype); +#ifdef POINTERS_EXTEND_UNSIGNED + if (GET_MODE (addr) != Pmode) + addr = convert_memory_address (Pmode, addr); +#endif + imag = gen_rtx_MEM (TYPE_MODE (type), addr); + set_mem_alias_set (imag, get_varargs_alias_set ()); + + addr = std_expand_builtin_va_arg (valist, subtype); +#ifdef POINTERS_EXTEND_UNSIGNED + if (GET_MODE (addr) != Pmode) + addr = convert_memory_address (Pmode, addr); +#endif + real = gen_rtx_MEM (TYPE_MODE (type), addr); + set_mem_alias_set (real, get_varargs_alias_set ()); + + result_value = gen_rtx_CONCAT (SCmode, real, imag); + /* ??? this interface is stupid - why require a pointer? */ + result = gen_reg_rtx (Pmode); + slot = assign_stack_temp (SCmode, 8, 0); + emit_move_insn (slot, result_value); + emit_move_insn (result, XEXP (slot, 0)); + } +#endif /* FUNCTION_ARG_SCmode_WART */ + emit_jump_insn (gen_jump (lab_over)); emit_barrier (); emit_label (lab_false); @@ -6060,16 +6105,22 @@ sh_va_arg (valist, type) emit_move_insn (addr_rtx, r); } - emit_label (lab_over); - - tmp = make_tree (pptr_type_node, addr_rtx); - valist = build1 (INDIRECT_REF, ptr_type_node, tmp); + if (! result) + emit_label (lab_over); } /* ??? In va-sh.h, there had been code to make values larger than size 8 indirect. This does not match the FUNCTION_ARG macros. */ - result = std_expand_builtin_va_arg (valist, type); + result_ptr = std_expand_builtin_va_arg (valist, type); + if (result) + { + emit_move_insn (result, result_ptr); + emit_label (lab_over); + } + else + result = result_ptr; + if (pass_by_ref) { #ifdef POINTERS_EXTEND_UNSIGNED diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h index 2c62d47..ee49f6b 100644 --- a/gcc/config/sh/sh.h +++ b/gcc/config/sh/sh.h @@ -1867,20 +1867,12 @@ struct sh_args { (CUM).outgoing = 0; \ } while (0) -#define OLD_ARG_MODE(MODE, TYPE) \ - (((TYPE) \ - && (TREE_CODE (TYPE) == RECORD_TYPE || TREE_CODE (TYPE) == UNION_TYPE) \ - && (MODE) != BLKmode && GET_MODE_CLASS (MODE) != MODE_INT) \ - ? int_mode_for_mode (MODE) : (MODE)) - /* Update the data in CUM to advance over an argument of mode MODE and data type TYPE. (TYPE is null for libcalls where that information may not be available.) */ #define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ -do { \ - enum machine_mode MODE_ = OLD_ARG_MODE ((MODE), (TYPE));\ if ((CUM).force_mem) \ (CUM).force_mem = 0; \ else if (TARGET_SH5) \ @@ -1888,17 +1880,17 @@ do { \ tree TYPE_ = ((CUM).byref && (TYPE) \ ? TREE_TYPE (TYPE) \ : (TYPE)); \ - int dwords, numregs; \ + enum machine_mode MODE_ = ((CUM).byref && (TYPE) \ + ? TYPE_MODE (TYPE_) \ + : (MODE)); \ + int dwords = (((CUM).byref \ + ? (CUM).byref \ + : (MODE_) == BLKmode \ + ? int_size_in_bytes (TYPE_) \ + : GET_MODE_SIZE (MODE_)) + 7) / 8; \ + int numregs = MIN (dwords, NPARM_REGS (SImode) \ + - (CUM).arg_count[(int) SH_ARG_INT]); \ \ - MODE_ = ((CUM).byref && (TYPE) \ - ? TYPE_MODE (TYPE_) : (MODE_)); \ - dwords = (((CUM).byref \ - ? (CUM).byref \ - : (MODE_) == BLKmode \ - ? int_size_in_bytes (TYPE_) \ - : GET_MODE_SIZE (MODE_)) + 7) / 8; \ - numregs = MIN (dwords, NPARM_REGS (SImode) \ - - (CUM).arg_count[(int) SH_ARG_INT]); \ if (numregs) \ { \ (CUM).arg_count[(int) SH_ARG_INT] += numregs; \ @@ -1990,13 +1982,12 @@ do { \ } \ } \ } \ - else if (! TARGET_SH4 || PASS_IN_REG_P ((CUM), (MODE_), (TYPE))) \ - ((CUM).arg_count[(int) GET_SH_ARG_CLASS (MODE_)] \ - = (ROUND_REG ((CUM), (MODE_)) \ - + ((MODE_) == BLKmode \ + else if (! TARGET_SH4 || PASS_IN_REG_P ((CUM), (MODE), (TYPE))) \ + ((CUM).arg_count[(int) GET_SH_ARG_CLASS (MODE)] \ + = (ROUND_REG ((CUM), (MODE)) \ + + ((MODE) == BLKmode \ ? ROUND_ADVANCE (int_size_in_bytes (TYPE)) \ - : ROUND_ADVANCE (GET_MODE_SIZE (MODE_))))); \ -} while (0) + : ROUND_ADVANCE (GET_MODE_SIZE (MODE))))) /* Return boolean indicating arg of mode MODE will be passed in a reg. This macro is only used in this file. */ @@ -2016,6 +2007,24 @@ do { \ <= NPARM_REGS (MODE))) \ : ROUND_REG ((CUM), (MODE)) < NPARM_REGS (MODE))) +/* By accident we got stuck with passing SCmode on SH4 little endian + in two registers that are nominally successive - which is different from + two single SFmode values, where we take endianness translation into + account. That does not work at all if an odd number of registers is + already in use, so that got fixed, but library functions are still more + likely to use complex numbers without mixing them with SFmode arguments + (which in C would have to be structures), so for the sake of ABI + compatibility the way SCmode values are passed when an even number of + FP registers is in use remains different from a pair of SFmode values for + now. + I.e.: + foo (double); a: fr5,fr4 + foo (float a, float b); a: fr5 b: fr4 + foo (__complex float a); a.real fr4 a.imag: fr5 - for consistency, + this should be the other way round... + foo (float a, __complex float b); a: fr5 b.real: fr4 b.imag: fr7 */ +#define FUNCTION_ARG_SCmode_WART 1 + /* Define where to put the arguments to a function. Value is zero to push the argument on the stack, or a hard register in which to store the argument. @@ -2035,29 +2044,44 @@ do { \ its data type forbids. */ #define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ - FUNCTION_ARG_1 ((CUM), OLD_ARG_MODE ((MODE), (TYPE)), (MODE), (TYPE), (NAMED)) - -#define FUNCTION_ARG_1(CUM, MODE, NEW_MODE, TYPE, NAMED) \ ((! TARGET_SH5 \ && PASS_IN_REG_P ((CUM), (MODE), (TYPE)) \ && ((NAMED) || !TARGET_HITACHI)) \ - ? gen_rtx_REG ((NEW_MODE), \ - ((BASE_ARG_REG (MODE) + ROUND_REG ((CUM), (MODE))) \ - ^ ((MODE) == SFmode && TARGET_SH4 \ - && TARGET_LITTLE_ENDIAN != 0))) \ + ? (((MODE) == SCmode && TARGET_SH4 && TARGET_LITTLE_ENDIAN \ + && (! FUNCTION_ARG_SCmode_WART || (ROUND_REG ((CUM), (MODE)) & 1)))\ + ? (gen_rtx_PARALLEL \ + (SCmode, \ + (gen_rtvec \ + (2, \ + (gen_rtx_EXPR_LIST \ + (VOIDmode, \ + gen_rtx_REG (SFmode, \ + BASE_ARG_REG (MODE) \ + + ROUND_REG ((CUM), (MODE)) ^ 1), \ + const0_rtx)), \ + (gen_rtx_EXPR_LIST \ + (VOIDmode, \ + gen_rtx_REG (SFmode, \ + BASE_ARG_REG (MODE) \ + + (ROUND_REG ((CUM), (MODE)) + 1) ^ 1), \ + GEN_INT (4))))))) \ + : gen_rtx_REG ((MODE), \ + ((BASE_ARG_REG (MODE) + ROUND_REG ((CUM), (MODE))) \ + ^ ((MODE) == SFmode && TARGET_SH4 \ + && TARGET_LITTLE_ENDIAN != 0)))) \ : TARGET_SH5 \ ? ((MODE) == VOIDmode && TARGET_SHCOMPACT \ ? GEN_INT ((CUM).call_cookie) \ /* The following test assumes unnamed arguments are promoted to \ DFmode. */ \ : (MODE) == SFmode && (CUM).free_single_fp_reg \ - ? SH5_PROTOTYPED_FLOAT_ARG ((CUM), (NEW_MODE), (CUM).free_single_fp_reg) \ + ? SH5_PROTOTYPED_FLOAT_ARG ((CUM), (MODE), (CUM).free_single_fp_reg) \ : (GET_SH_ARG_CLASS (MODE) == SH_ARG_FLOAT \ && ((NAMED) || ! (CUM).prototype_p) \ && (CUM).arg_count[(int) SH_ARG_FLOAT] < NPARM_REGS (SFmode)) \ ? ((! (CUM).prototype_p && TARGET_SHMEDIA) \ - ? SH5_PROTOTYPELESS_FLOAT_ARG ((CUM), (NEW_MODE)) \ - : SH5_PROTOTYPED_FLOAT_ARG ((CUM), (NEW_MODE), \ + ? SH5_PROTOTYPELESS_FLOAT_ARG ((CUM), (MODE)) \ + : SH5_PROTOTYPED_FLOAT_ARG ((CUM), (MODE), \ FIRST_FP_PARM_REG \ + (CUM).arg_count[(int) SH_ARG_FLOAT])) \ : ((CUM).arg_count[(int) SH_ARG_INT] < NPARM_REGS (SImode) \ @@ -2065,7 +2089,7 @@ do { \ || (! SHCOMPACT_FORCE_ON_STACK ((MODE), (TYPE)) \ && ! SH5_WOULD_BE_PARTIAL_NREGS ((CUM), (MODE), \ (TYPE), (NAMED))))) \ - ? gen_rtx_REG ((NEW_MODE), (FIRST_PARM_REG \ + ? gen_rtx_REG ((MODE), (FIRST_PARM_REG \ + (CUM).arg_count[(int) SH_ARG_INT])) \ : 0) \ : 0) @@ -2076,7 +2100,7 @@ do { \ loads them into the full 64-bits registers. */ #define FUNCTION_ARG_PASS_BY_REFERENCE(CUM,MODE,TYPE,NAMED) \ (MUST_PASS_IN_STACK ((MODE), (TYPE)) \ - || SHCOMPACT_BYREF ((CUM), OLD_ARG_MODE ((MODE), (TYPE)), (TYPE), (NAMED))) + || SHCOMPACT_BYREF ((CUM), (MODE), (TYPE), (NAMED))) #define SHCOMPACT_BYREF(CUM, MODE, TYPE, NAMED) \ ((CUM).byref \ |