2019-08-05 Bernd Edlinger PR middle-end/89544 * builtins.c (expand_builtin_init_descriptor): Set memory alignment. * expr.c (expand_expr_real_1): Handle FUNCTION_DECL as unaligned. * function.c (assign_parm_find_stack_rtl): Use larger alignment when possible. (assign_parm_setup_reg): Handle misaligned stack arguments. (assign_parm_setup_stack): Allocate properly aligned stack slots. * varasm.c (align_variable): Align constants of misaligned types. * config/arm/arm.md (movdi, movsi, movhi, movhf, movsf, movdf): Check strict alignment restrictions on memory addresses. * config/arm/neon.md (movti, mov, mov): Likewise. * config/arm/vec-common.md (mov): Likewise. testsuite: 2019-08-05 Bernd Edlinger PR middle-end/89544 * gcc.target/arm/unaligned-argument-1.c: New test. * gcc.target/arm/unaligned-argument-2.c: New test. Index: gcc/builtins.c =================================================================== --- gcc/builtins.c (revision 274168) +++ gcc/builtins.c (working copy) @@ -5756,6 +5756,7 @@ expand_builtin_init_descriptor (tree exp) r_descr = expand_normal (t_descr); m_descr = gen_rtx_MEM (BLKmode, r_descr); MEM_NOTRAP_P (m_descr) = 1; + set_mem_align (m_descr, GET_MODE_ALIGNMENT (ptr_mode)); r_func = expand_normal (t_func); r_chain = expand_normal (t_chain); Index: gcc/config/arm/arm.md =================================================================== --- gcc/config/arm/arm.md (revision 274168) +++ gcc/config/arm/arm.md (working copy) @@ -5824,6 +5824,12 @@ (match_operand:DI 1 "general_operand"))] "TARGET_EITHER" " + gcc_checking_assert (!MEM_P (operands[0]) + || MEM_ALIGN (operands[0]) + >= GET_MODE_ALIGNMENT (DImode)); + gcc_checking_assert (!MEM_P (operands[1]) + || MEM_ALIGN (operands[1]) + >= GET_MODE_ALIGNMENT (DImode)); if (can_create_pseudo_p ()) { if (!REG_P (operands[0])) @@ -6000,6 +6006,12 @@ { rtx base, offset, tmp; + gcc_checking_assert (!MEM_P (operands[0]) + || MEM_ALIGN (operands[0]) + >= GET_MODE_ALIGNMENT (SImode)); + gcc_checking_assert (!MEM_P (operands[1]) + || MEM_ALIGN (operands[1]) + >= GET_MODE_ALIGNMENT (SImode)); if (TARGET_32BIT || TARGET_HAVE_MOVT) { /* Everything except mem = const or mem = mem can be done easily. */ @@ -6489,6 +6501,12 @@ (match_operand:HI 1 "general_operand"))] "TARGET_EITHER" " + gcc_checking_assert (!MEM_P (operands[0]) + || MEM_ALIGN (operands[0]) + >= GET_MODE_ALIGNMENT (HImode)); + gcc_checking_assert (!MEM_P (operands[1]) + || MEM_ALIGN (operands[1]) + >= GET_MODE_ALIGNMENT (HImode)); if (TARGET_ARM) { if (can_create_pseudo_p ()) @@ -6898,6 +6916,12 @@ (match_operand:HF 1 "general_operand"))] "TARGET_EITHER" " + gcc_checking_assert (!MEM_P (operands[0]) + || MEM_ALIGN (operands[0]) + >= GET_MODE_ALIGNMENT (HFmode)); + gcc_checking_assert (!MEM_P (operands[1]) + || MEM_ALIGN (operands[1]) + >= GET_MODE_ALIGNMENT (HFmode)); if (TARGET_32BIT) { if (MEM_P (operands[0])) @@ -6962,6 +6986,12 @@ (match_operand:SF 1 "general_operand"))] "TARGET_EITHER" " + gcc_checking_assert (!MEM_P (operands[0]) + || MEM_ALIGN (operands[0]) + >= GET_MODE_ALIGNMENT (SFmode)); + gcc_checking_assert (!MEM_P (operands[1]) + || MEM_ALIGN (operands[1]) + >= GET_MODE_ALIGNMENT (SFmode)); if (TARGET_32BIT) { if (MEM_P (operands[0])) @@ -7057,6 +7087,12 @@ (match_operand:DF 1 "general_operand"))] "TARGET_EITHER" " + gcc_checking_assert (!MEM_P (operands[0]) + || MEM_ALIGN (operands[0]) + >= GET_MODE_ALIGNMENT (DFmode)); + gcc_checking_assert (!MEM_P (operands[1]) + || MEM_ALIGN (operands[1]) + >= GET_MODE_ALIGNMENT (DFmode)); if (TARGET_32BIT) { if (MEM_P (operands[0])) Index: gcc/config/arm/neon.md =================================================================== --- gcc/config/arm/neon.md (revision 274168) +++ gcc/config/arm/neon.md (working copy) @@ -127,6 +127,12 @@ (match_operand:TI 1 "general_operand"))] "TARGET_NEON" { + gcc_checking_assert (!MEM_P (operands[0]) + || MEM_ALIGN (operands[0]) + >= GET_MODE_ALIGNMENT (TImode)); + gcc_checking_assert (!MEM_P (operands[1]) + || MEM_ALIGN (operands[1]) + >= GET_MODE_ALIGNMENT (TImode)); if (can_create_pseudo_p ()) { if (!REG_P (operands[0])) @@ -139,6 +145,12 @@ (match_operand:VSTRUCT 1 "general_operand"))] "TARGET_NEON" { + gcc_checking_assert (!MEM_P (operands[0]) + || MEM_ALIGN (operands[0]) + >= GET_MODE_ALIGNMENT (mode)); + gcc_checking_assert (!MEM_P (operands[1]) + || MEM_ALIGN (operands[1]) + >= GET_MODE_ALIGNMENT (mode)); if (can_create_pseudo_p ()) { if (!REG_P (operands[0])) @@ -151,6 +163,12 @@ (match_operand:VH 1 "s_register_operand"))] "TARGET_NEON" { + gcc_checking_assert (!MEM_P (operands[0]) + || MEM_ALIGN (operands[0]) + >= GET_MODE_ALIGNMENT (mode)); + gcc_checking_assert (!MEM_P (operands[1]) + || MEM_ALIGN (operands[1]) + >= GET_MODE_ALIGNMENT (mode)); if (can_create_pseudo_p ()) { if (!REG_P (operands[0])) Index: gcc/config/arm/vec-common.md =================================================================== --- gcc/config/arm/vec-common.md (revision 274168) +++ gcc/config/arm/vec-common.md (working copy) @@ -26,6 +26,12 @@ "TARGET_NEON || (TARGET_REALLY_IWMMXT && VALID_IWMMXT_REG_MODE (mode))" { + gcc_checking_assert (!MEM_P (operands[0]) + || MEM_ALIGN (operands[0]) + >= GET_MODE_ALIGNMENT (mode)); + gcc_checking_assert (!MEM_P (operands[1]) + || MEM_ALIGN (operands[1]) + >= GET_MODE_ALIGNMENT (mode)); if (can_create_pseudo_p ()) { if (!REG_P (operands[0])) Index: gcc/expr.c =================================================================== --- gcc/expr.c (revision 274168) +++ gcc/expr.c (working copy) @@ -10796,6 +10796,14 @@ expand_expr_real_1 (tree exp, rtx target, machine_ MEM_VOLATILE_P (op0) = 1; } + if (MEM_P (op0) && TREE_CODE (tem) == FUNCTION_DECL) + { + if (op0 == orig_op0) + op0 = copy_rtx (op0); + + set_mem_align (op0, BITS_PER_UNIT); + } + /* In cases where an aligned union has an unaligned object as a field, we might be extracting a BLKmode value from an integer-mode (e.g., SImode) object. Handle this case Index: gcc/function.c =================================================================== --- gcc/function.c (revision 274168) +++ gcc/function.c (working copy) @@ -2697,8 +2697,23 @@ assign_parm_find_stack_rtl (tree parm, struct assi intentionally forcing upward padding. Otherwise we have to come up with a guess at the alignment based on OFFSET_RTX. */ poly_int64 offset; - if (data->locate.where_pad != PAD_DOWNWARD || data->entry_parm) + if (data->locate.where_pad == PAD_NONE || data->entry_parm) align = boundary; + else if (data->locate.where_pad == PAD_UPWARD) + { + align = boundary; + /* If the argument offset is actually more aligned than the nominal + stack slot boundary, take advantage of that excess alignment. + Don't make any assumptions if STACK_POINTER_OFFSET is in use. */ + if (poly_int_rtx_p (offset_rtx, &offset) + && STACK_POINTER_OFFSET == 0) + { + unsigned int offset_align = known_alignment (offset) * BITS_PER_UNIT; + if (offset_align == 0 || offset_align > STACK_BOUNDARY) + offset_align = STACK_BOUNDARY; + align = MAX (align, offset_align); + } + } else if (poly_int_rtx_p (offset_rtx, &offset)) { align = least_bit_hwi (boundary); @@ -3127,6 +3142,7 @@ assign_parm_setup_reg (struct assign_parm_data_all int unsignedp = TYPE_UNSIGNED (TREE_TYPE (parm)); bool did_conversion = false; bool need_conversion, moved; + enum insn_code icode; rtx rtl; /* Store the parm in a pseudoregister during the function, but we may @@ -3188,7 +3204,6 @@ assign_parm_setup_reg (struct assign_parm_data_all conversion. We verify that this insn does not clobber any hard registers. */ - enum insn_code icode; rtx op0, op1; icode = can_extend_p (promoted_nominal_mode, data->passed_mode, @@ -3291,6 +3306,23 @@ assign_parm_setup_reg (struct assign_parm_data_all did_conversion = true; } + else if (MEM_P (data->entry_parm) + && GET_MODE_ALIGNMENT (promoted_nominal_mode) + > MEM_ALIGN (data->entry_parm) + && (((icode = optab_handler (movmisalign_optab, + promoted_nominal_mode)) + != CODE_FOR_nothing) + || targetm.slow_unaligned_access (promoted_nominal_mode, + MEM_ALIGN (data->entry_parm)))) + { + if (icode != CODE_FOR_nothing) + emit_insn (GEN_FCN (icode) (parmreg, validated_mem)); + else + rtl = parmreg = extract_bit_field (validated_mem, + GET_MODE_BITSIZE (promoted_nominal_mode), 0, + unsignedp, parmreg, + promoted_nominal_mode, VOIDmode, false, NULL); + } else emit_move_insn (parmreg, validated_mem); @@ -3449,11 +3481,17 @@ assign_parm_setup_stack (struct assign_parm_data_a int align = STACK_SLOT_ALIGNMENT (data->passed_type, GET_MODE (data->entry_parm), TYPE_ALIGN (data->passed_type)); + if (align < (int)GET_MODE_ALIGNMENT (GET_MODE (data->entry_parm)) + && targetm.slow_unaligned_access (GET_MODE (data->entry_parm), + align)) + align = GET_MODE_ALIGNMENT (GET_MODE (data->entry_parm)); data->stack_parm = assign_stack_local (GET_MODE (data->entry_parm), GET_MODE_SIZE (GET_MODE (data->entry_parm)), align); + align = MEM_ALIGN (data->stack_parm); set_mem_attributes (data->stack_parm, parm, 1); + set_mem_align (data->stack_parm, align); } dest = validize_mem (copy_rtx (data->stack_parm)); Index: gcc/testsuite/gcc.target/arm/unaligned-argument-1.c =================================================================== --- gcc/testsuite/gcc.target/arm/unaligned-argument-1.c (revision 0) +++ gcc/testsuite/gcc.target/arm/unaligned-argument-1.c (working copy) @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target arm_arm_ok } */ +/* { dg-require-effective-target arm_ldrd_strd_ok } */ +/* { dg-options "-marm -mno-unaligned-access -O3" } */ + +struct s { + int a, b; +} __attribute__((aligned(8))); + +struct s f0; + +void f(int a, int b, int c, int d, struct s f) +{ + f0 = f; +} + +/* { dg-final { scan-assembler-times "ldrd" 1 } } */ +/* { dg-final { scan-assembler-times "strd" 1 } } */ +/* { dg-final { scan-assembler-times "stm" 0 } } */ Index: gcc/testsuite/gcc.target/arm/unaligned-argument-2.c =================================================================== --- gcc/testsuite/gcc.target/arm/unaligned-argument-2.c (revision 0) +++ gcc/testsuite/gcc.target/arm/unaligned-argument-2.c (working copy) @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target arm_arm_ok } */ +/* { dg-require-effective-target arm_ldrd_strd_ok } */ +/* { dg-options "-marm -mno-unaligned-access -O3" } */ + +struct s { + int a, b; +} __attribute__((aligned(8))); + +struct s f0; + +void f(int a, int b, int c, int d, int e, struct s f) +{ + f0 = f; +} + +/* { dg-final { scan-assembler-times "ldrd" 0 } } */ +/* { dg-final { scan-assembler-times "strd" 0 } } */ +/* { dg-final { scan-assembler-times "stm" 1 } } */ Index: gcc/varasm.c =================================================================== --- gcc/varasm.c (revision 274168) +++ gcc/varasm.c (working copy) @@ -1085,6 +1085,10 @@ align_variable (tree decl, bool dont_output_data) } } + if (align < GET_MODE_ALIGNMENT (DECL_MODE (decl)) + && targetm.slow_unaligned_access (DECL_MODE (decl), align)) + align = GET_MODE_ALIGNMENT (DECL_MODE (decl)); + /* Reset the alignment in case we have made it tighter, so we can benefit from it in get_pointer_alignment. */ SET_DECL_ALIGN (decl, align);