2004-10-06 Paolo Bonzini PR target/17836 * config/rs6000/rs6000.c (USE_ALTIVEC_FOR_ARG_P, init_cumulative_args, function_arg_boundary, function_arg_advance, function_arg, rs6000_gimplify_va_arg): Look into the type instead of using ALTIVEC_VECTOR_MODE. (rs6000_pass_by_reference): Same as above, plus warn for wide (>16 bytes) vector types and pass them by reference. (rs6000_return_in_memory): Return true for vectors above 16 bytes. Index: rs6000.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.c,v retrieving revision 1.720 diff -u -r1.720 rs6000.c --- rs6000.c 5 Oct 2004 12:43:53 -0000 1.720 +++ rs6000.c 7 Oct 2004 09:33:42 -0000 @@ -4531,7 +4531,9 @@ /* Nonzero if we can use an AltiVec register to pass this arg. */ #define USE_ALTIVEC_FOR_ARG_P(CUM,MODE,TYPE,NAMED) \ - (ALTIVEC_VECTOR_MODE (MODE) \ + ((TYPE) \ + && TREE_CODE (TYPE) == VECTOR_TYPE \ + && int_size_in_bytes (TYPE) == 16 \ && (CUM)->vregno <= ALTIVEC_ARG_MAX_REG \ && TARGET_ALTIVEC_ABI \ && (NAMED)) @@ -4564,6 +4566,12 @@ && (TARGET_AIX_STRUCT_RET || (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 8)) return true; + /* If TARGET_ALTIVEC is not set, we return 16-byte vectors in memory, + otherwise function.c tries to use a TImode register and we get + an unrecognizable insn. */ + if (TREE_CODE (type) == VECTOR_TYPE + && int_size_in_bytes (type) > (TARGET_ALTIVEC ? 16 : 8)) + return true; if (DEFAULT_ABI == ABI_V4 && TYPE_MODE (type) == TFmode) return true; return false; @@ -4626,7 +4634,8 @@ if (fntype && !TARGET_ALTIVEC && TARGET_ALTIVEC_ABI - && ALTIVEC_VECTOR_MODE (TYPE_MODE (TREE_TYPE (fntype)))) + && TREE_CODE (TREE_TYPE (fntype)) == VECTOR_TYPE + && int_size_in_bytes (TREE_TYPE (fntype)) == 16) { error ("Cannot return value in vector register because" " altivec instructions are disabled, use -maltivec" @@ -4710,14 +4719,15 @@ V.4 wants long longs to be double word aligned. */ int -function_arg_boundary (enum machine_mode mode, tree type ATTRIBUTE_UNUSED) +function_arg_boundary (enum machine_mode mode, tree type) { if (DEFAULT_ABI == ABI_V4 && GET_MODE_SIZE (mode) == 8) return 64; - else if (SPE_VECTOR_MODE (mode)) - return 64; - else if (ALTIVEC_VECTOR_MODE (mode)) - return 128; + else if (type + && TREE_CODE (type) == VECTOR_TYPE + && (int_size_in_bytes (type) == 8 + || int_size_in_bytes (type) == 16)) + return 8 * int_size_in_bytes (type); else return PARM_BOUNDARY; } @@ -4754,7 +4764,10 @@ { cum->nargs_prototype--; - if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode)) + if (TARGET_ALTIVEC_ABI + && type + && TREE_CODE (type) == VECTOR_TYPE + && int_size_in_bytes (type) == 16) { bool stack = false; @@ -5057,7 +5070,10 @@ } else return gen_rtx_REG (mode, cum->vregno); - else if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode)) + else if (TARGET_ALTIVEC_ABI + && type + && TREE_CODE (type) == VECTOR_TYPE + && int_size_in_bytes (type) == 16) { if (named || abi == ABI_V4) return NULL_RTX; @@ -5296,25 +5312,64 @@ As an extension to all 32-bit ABIs, AltiVec vectors are passed by reference unless the AltiVec vector extension ABI is in force. - As an extension to all ABIs, variable sized types are passed by - reference. */ + As an extension to all ABIs, variable sized types and vectors + wider than 16 bytes are passed by reference. */ static bool -rs6000_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED, - enum machine_mode mode ATTRIBUTE_UNUSED, - tree type, bool named ATTRIBUTE_UNUSED) -{ - if ((DEFAULT_ABI == ABI_V4 - && ((type && AGGREGATE_TYPE_P (type)) - || mode == TFmode)) - || (TARGET_32BIT && !TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode)) - || (type && int_size_in_bytes (type) < 0)) +rs6000_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED, + enum machine_mode mode, tree type, + bool named ATTRIBUTE_UNUSED) +{ + if (DEFAULT_ABI == ABI_V4 && mode == TFmode) + { + if (TARGET_DEBUG_ARG) + fprintf (stderr, "function_arg_pass_by_reference: V4 long double\n"); + return 1; + } + + if (!type) + return 0; + + if (DEFAULT_ABI == ABI_V4 && AGGREGATE_TYPE_P (type)) + { + if (TARGET_DEBUG_ARG) + fprintf (stderr, "function_arg_pass_by_reference: V4 aggregates\n"); + return 1; + } + + if (TARGET_32BIT + && !TARGET_ALTIVEC_ABI + && TREE_CODE (type) == VECTOR_TYPE + && int_size_in_bytes (type) == 16) { if (TARGET_DEBUG_ARG) - fprintf (stderr, "function_arg_pass_by_reference\n"); + fprintf (stderr, "function_arg_pass_by_reference: AltiVec\n"); + return 1; + } + + if (TREE_CODE (type) == VECTOR_TYPE + && int_size_in_bytes (type) > 16) + { + static int warned_for_big_vectors = false; + if (TARGET_DEBUG_ARG) + fprintf (stderr, "function_arg_pass_by_reference: vectors >16 bytes\n"); + if (!warned_for_big_vectors) + { + warning ("vectors bigger than 16 bytes are passed by reference: " + "this may change in a future version of the ABI"); + warned_for_big_vectors = 1; + } return 1; } + + if (int_size_in_bytes (type) == -1) + { + if (TARGET_DEBUG_ARG) + fprintf (stderr, "function_arg_pass_by_reference: variable size\n"); + return 1; + } + return 0; } @@ -5646,7 +5701,9 @@ DECL_POINTER_ALIAS_SET (addr) = get_varargs_alias_set (); /* AltiVec vectors never go in registers when -mabi=altivec. */ - if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (TYPE_MODE (type))) + if (TARGET_ALTIVEC_ABI + && TREE_CODE (type) == VECTOR_TYPE + && int_size_in_bytes (type) == 16) align = 16; else {