diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 2e385c4..40c8ecf 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -2256,33 +2256,65 @@ aarch64_vfp_is_call_candidate (cumulative_args_t pcum_v, machine_mode mode, NULL); } +struct aarch64_fn_arg_alignment +{ + /* alignment for FIELD_DECLS in function arguments. */ + unsigned int alignment; + /* alignment for everything other than FIELD_DECLS in function arguments. */ + unsigned int warning_alignment; +}; + /* Given MODE and TYPE of a function argument, return the alignment in bits. The idea is to suppress any stronger alignment requested by the user and opt for the natural alignment (specified in AAPCS64 \S 4.1). This is a helper function for local use only. */ -static unsigned int +static struct aarch64_fn_arg_alignment aarch64_function_arg_alignment (machine_mode mode, const_tree type) { + struct aarch64_fn_arg_alignment a; + a.alignment = 0; + a.warning_alignment = 0; + if (!type) - return GET_MODE_ALIGNMENT (mode); + { + a.alignment = GET_MODE_ALIGNMENT (mode); + a.warning_alignment = GET_MODE_ALIGNMENT (mode); + return a; + } + if (integer_zerop (TYPE_SIZE (type))) - return 0; + return a; gcc_assert (TYPE_MODE (type) == mode); if (!AGGREGATE_TYPE_P (type)) - return TYPE_ALIGN (TYPE_MAIN_VARIANT (type)); + { + a.alignment = TYPE_ALIGN (TYPE_MAIN_VARIANT (type)); + a.warning_alignment = a.alignment; + return a; + } if (TREE_CODE (type) == ARRAY_TYPE) - return TYPE_ALIGN (TREE_TYPE (type)); - - unsigned int alignment = 0; + { + a.alignment = TYPE_ALIGN (TREE_TYPE (type)); + a.warning_alignment = a.alignment; + return a; + } for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) - alignment = std::max (alignment, DECL_ALIGN (field)); + { + if (TREE_CODE (field) == FIELD_DECL) + a.alignment = std::max (a.alignment, DECL_ALIGN (field)); + else + a.warning_alignment = std::max (a.warning_alignment, + DECL_ALIGN (field)); + } - return alignment; + if (a.warning_alignment <= a.alignment) + a.warning_alignment = a.alignment; + + return a; } /* Layout a function argument according to the AAPCS64 rules. The rule @@ -2369,10 +2401,24 @@ aarch64_layout_arg (cumulative_args_t pcum_v, machine_mode mode, entirely general registers. */ if (allocate_ncrn && (ncrn + nregs <= NUM_ARG_REGS)) { - unsigned int alignment = aarch64_function_arg_alignment (mode, type); + struct aarch64_fn_arg_alignment a = aarch64_function_arg_alignment (mode, + type); + unsigned int alignment = a.alignment; gcc_assert (nregs == 0 || nregs == 1 || nregs == 2); + if (nregs == 2 + && a.warning_alignment == 16 * BITS_PER_UNIT + && ncrn % 2) + { + if (a.warning_alignment < a.alignment + && warn_psabi) + inform (input_location, + "parameter passing changed for argument %qT " + "since GCC 7.1", + type); + } + /* C.8 if the argument has an alignment of 16 then the NGRN is rounded up to the next even number. */ if (nregs == 2 && alignment == 16 * BITS_PER_UNIT && ncrn % 2) @@ -2414,7 +2460,10 @@ aarch64_layout_arg (cumulative_args_t pcum_v, machine_mode mode, this argument and align the total size if necessary. */ on_stack: pcum->aapcs_stack_words = size / UNITS_PER_WORD; - if (aarch64_function_arg_alignment (mode, type) == 16 * BITS_PER_UNIT) + struct aarch64_fn_arg_alignment ab; + ab = aarch64_function_arg_alignment (mode, type); + + if (ab.alignment == 16 * BITS_PER_UNIT) pcum->aapcs_stack_size = ROUND_UP (pcum->aapcs_stack_size, 16 / UNITS_PER_WORD); return; @@ -2505,12 +2554,27 @@ aarch64_function_arg_regno_p (unsigned regno) static unsigned int aarch64_function_arg_boundary (machine_mode mode, const_tree type) { - unsigned int alignment = aarch64_function_arg_alignment (mode, type); - + struct aarch64_fn_arg_alignment a = aarch64_function_arg_alignment (mode, + type); + unsigned int alignment = a.alignment; if (alignment < PARM_BOUNDARY) alignment = PARM_BOUNDARY; if (alignment > STACK_BOUNDARY) alignment = STACK_BOUNDARY; + + if (a.warning_alignment < PARM_BOUNDARY) + a.warning_alignment = PARM_BOUNDARY; + + if (a.warning_alignment > STACK_BOUNDARY) + a.warning_alignment = STACK_BOUNDARY; + + if (warn_psabi + && a.warning_alignment > alignment) + inform (input_location, + "parameter passing changed for argument of type %qT " + "since GCC 7.1", + type); + return alignment; } @@ -10211,7 +10275,9 @@ aarch64_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, stack = build3 (COMPONENT_REF, TREE_TYPE (f_stack), unshare_expr (valist), f_stack, NULL_TREE); size = int_size_in_bytes (type); - align = aarch64_function_arg_alignment (mode, type) / BITS_PER_UNIT; + struct aarch64_fn_arg_alignment a = aarch64_function_arg_alignment (mode, + type); + align = a.alignment / BITS_PER_UNIT; dw_align = false; adjust = 0;