This changes alignment computation of a MEM during expansion from MAX (TYPE_ALIGN (TREE_TYPE (exp)), get_object_alignment (exp)) to something weaker (with possibly less alignment) when we were able to compute an explicit misaligned value (thus, get_object_alignment_1 (exp, &misalign) would return an alignment of 8, but misaligned by 4, for example - in which case get_object_alignment () would return 4). This is to less often fall into the trap that the frontends and the middle-end are not careful about providing a type with properly alignment for misaligned memory references (classical example is struct __attribute__((packed)) { int i; } a; &a, where &a has int * type, not int __attribute__((aligned(1))) * type).
The patch unbreaks the testcase in the PR (which is strictly invalid) by using precise misalign information we are able to compute at -O1 and up: typedef int vec __attribute__((vector_size(16))); int main () { int * arr = __builtin_malloc (1024); vec *p = (vec *) &arr[1]; *p = (vec){1, 2, 3, 4}; return *(char *)p; } on x86_64 without the patch we emit movaps while with the patch we use a movups instruction (which is being nice to our users). I didn't bother to try thinking of a heuristic when to use the misaligned info and when not - always using it makes the most sense consistency-wise. I had considered only using TYPE_ALIGN () when get_object_alignment_1 returns BITS_PER_UNIT for the alignment (which sort-of means don't know). Bootstrap and regtest scheduled on x86_64-unknown-linux-gnu. Any comments? Thanks, Richard. 2011-10-17 Richard Guenther <rguent...@suse.de> PR middle-end/50716 * expr.c (get_object_or_type_alignment): New function. (expand_assignment): Use it. (expand_expr_real_1): Likewise. Index: gcc/expr.c =================================================================== *** gcc/expr.c (revision 180077) --- gcc/expr.c (working copy) *************** get_bit_range (unsigned HOST_WIDE_INT *b *** 4544,4549 **** --- 4544,4568 ---- } } + /* Return the alignment of the object EXP, also considering its type + when we do not know of explicit misalignment. + ??? Note that generally the type of an expression is not kept + consistent with misalignment information by the frontend, for + example when taking the address of a member of a packed structure. + So taking into account type information for alignment is generally + wrong, but is done here as a compromise. */ + + static unsigned int + get_object_or_type_alignment (tree exp) + { + unsigned HOST_WIDE_INT misalign; + unsigned int align = get_object_alignment_1 (exp, &misalign); + align = MAX (TYPE_ALIGN (TREE_TYPE (exp)), align); + if (misalign != 0) + align = (misalign & -misalign); + return align; + } + /* Expand an assignment that stores the value of FROM into TO. If NONTEMPORAL is true, try generating a nontemporal store. */ *************** expand_assignment (tree to, tree from, b *** 4553,4559 **** rtx to_rtx = 0; rtx result; enum machine_mode mode; ! int align; enum insn_code icode; /* Don't crash if the lhs of the assignment was erroneous. */ --- 4572,4578 ---- rtx to_rtx = 0; rtx result; enum machine_mode mode; ! unsigned int align; enum insn_code icode; /* Don't crash if the lhs of the assignment was erroneous. */ *************** expand_assignment (tree to, tree from, b *** 4571,4578 **** if ((TREE_CODE (to) == MEM_REF || TREE_CODE (to) == TARGET_MEM_REF) && mode != BLKmode ! && ((align = MAX (TYPE_ALIGN (TREE_TYPE (to)), get_object_alignment (to))) ! < (signed) GET_MODE_ALIGNMENT (mode)) && ((icode = optab_handler (movmisalign_optab, mode)) != CODE_FOR_nothing)) { --- 4590,4597 ---- if ((TREE_CODE (to) == MEM_REF || TREE_CODE (to) == TARGET_MEM_REF) && mode != BLKmode ! && ((align = get_object_or_type_alignment (to)) ! < GET_MODE_ALIGNMENT (mode)) && ((icode = optab_handler (movmisalign_optab, mode)) != CODE_FOR_nothing)) { *************** expand_expr_real_1 (tree exp, rtx target *** 9241,9247 **** addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (exp)); struct mem_address addr; enum insn_code icode; ! int align; get_address_description (exp, &addr); op0 = addr_for_mem_ref (&addr, as, true); --- 9260,9266 ---- addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (exp)); struct mem_address addr; enum insn_code icode; ! unsigned int align; get_address_description (exp, &addr); op0 = addr_for_mem_ref (&addr, as, true); *************** expand_expr_real_1 (tree exp, rtx target *** 9249,9257 **** temp = gen_rtx_MEM (mode, op0); set_mem_attributes (temp, exp, 0); set_mem_addr_space (temp, as); ! align = MAX (TYPE_ALIGN (TREE_TYPE (exp)), get_object_alignment (exp)); if (mode != BLKmode ! && (unsigned) align < GET_MODE_ALIGNMENT (mode) /* If the target does not have special handling for unaligned loads of mode then it can use regular moves for them. */ && ((icode = optab_handler (movmisalign_optab, mode)) --- 9268,9276 ---- temp = gen_rtx_MEM (mode, op0); set_mem_attributes (temp, exp, 0); set_mem_addr_space (temp, as); ! align = get_object_or_type_alignment (exp); if (mode != BLKmode ! && align < GET_MODE_ALIGNMENT (mode) /* If the target does not have special handling for unaligned loads of mode then it can use regular moves for them. */ && ((icode = optab_handler (movmisalign_optab, mode)) *************** expand_expr_real_1 (tree exp, rtx target *** 9278,9284 **** tree base = TREE_OPERAND (exp, 0); gimple def_stmt; enum insn_code icode; ! int align; /* Handle expansion of non-aliased memory with non-BLKmode. That might end up in a register. */ if (TREE_CODE (base) == ADDR_EXPR) --- 9297,9303 ---- tree base = TREE_OPERAND (exp, 0); gimple def_stmt; enum insn_code icode; ! unsigned align; /* Handle expansion of non-aliased memory with non-BLKmode. That might end up in a register. */ if (TREE_CODE (base) == ADDR_EXPR) *************** expand_expr_real_1 (tree exp, rtx target *** 9329,9335 **** gimple_assign_rhs1 (def_stmt), mask); TREE_OPERAND (exp, 0) = base; } ! align = MAX (TYPE_ALIGN (TREE_TYPE (exp)), get_object_alignment (exp)); op0 = expand_expr (base, NULL_RTX, VOIDmode, EXPAND_SUM); op0 = memory_address_addr_space (address_mode, op0, as); if (!integer_zerop (TREE_OPERAND (exp, 1))) --- 9348,9354 ---- gimple_assign_rhs1 (def_stmt), mask); TREE_OPERAND (exp, 0) = base; } ! align = get_object_or_type_alignment (exp); op0 = expand_expr (base, NULL_RTX, VOIDmode, EXPAND_SUM); op0 = memory_address_addr_space (address_mode, op0, as); if (!integer_zerop (TREE_OPERAND (exp, 1))) *************** expand_expr_real_1 (tree exp, rtx target *** 9345,9351 **** if (TREE_THIS_VOLATILE (exp)) MEM_VOLATILE_P (temp) = 1; if (mode != BLKmode ! && (unsigned) align < GET_MODE_ALIGNMENT (mode) /* If the target does not have special handling for unaligned loads of mode then it can use regular moves for them. */ && ((icode = optab_handler (movmisalign_optab, mode)) --- 9364,9370 ---- if (TREE_THIS_VOLATILE (exp)) MEM_VOLATILE_P (temp) = 1; if (mode != BLKmode ! && align < GET_MODE_ALIGNMENT (mode) /* If the target does not have special handling for unaligned loads of mode then it can use regular moves for them. */ && ((icode = optab_handler (movmisalign_optab, mode))