When using the C++ frontend to build gcc.dg/fold-bitand-4.c it currently fails to optimize because we don't handle &a[i] properly in get_pointer_modulus_and_residue. We do have nice conservative code in get_object_alignment that just needs splitting out. Which is what the following patch does.
Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk. Richard. 2011-04-14 Richard Guenther <rguent...@suse.de> * tree.h (get_object_alignment_1): Declare. * builtins.c (get_object_alignment_1): Split out worker from ... (get_object_alignment): ... here. * fold-const.c (get_pointer_modulus_and_residue): Use get_object_alignment_1. * gcc.dg/fold-bitand-4.c: Move ... * c-c++-common/fold-bitand-4.c: ... here. Adjust slightly. Index: gcc/tree.h =================================================================== *** gcc/tree.h (revision 172416) --- gcc/tree.h (working copy) *************** extern bool can_trust_pointer_alignment *** 5224,5229 **** --- 5224,5230 ---- extern unsigned int get_pointer_alignment (tree, unsigned int); extern bool is_builtin_name (const char *); extern bool is_builtin_fn (tree); + extern unsigned int get_object_alignment_1 (tree, unsigned HOST_WIDE_INT *); extern unsigned int get_object_alignment (tree, unsigned int); extern tree fold_call_stmt (gimple, bool); extern tree gimple_fold_builtin_snprintf_chk (gimple, tree, enum built_in_function); Index: gcc/builtins.c =================================================================== *** gcc/builtins.c (revision 172416) --- gcc/builtins.c (working copy) *************** called_as_built_in (tree node) *** 268,274 **** Don't return more than MAX_ALIGN no matter what. */ unsigned int ! get_object_alignment (tree exp, unsigned int max_align) { HOST_WIDE_INT bitsize, bitpos; tree offset; --- 268,274 ---- Don't return more than MAX_ALIGN no matter what. */ unsigned int ! get_object_alignment_1 (tree exp, unsigned HOST_WIDE_INT *bitposp) { HOST_WIDE_INT bitsize, bitpos; tree offset; *************** get_object_alignment (tree exp, unsigned *** 320,327 **** align = MAX (pi->align * BITS_PER_UNIT, align); } else if (TREE_CODE (addr) == ADDR_EXPR) ! align = MAX (align, get_object_alignment (TREE_OPERAND (addr, 0), ! max_align)); bitpos += mem_ref_offset (exp).low * BITS_PER_UNIT; } else if (TREE_CODE (exp) == TARGET_MEM_REF) --- 320,326 ---- align = MAX (pi->align * BITS_PER_UNIT, align); } else if (TREE_CODE (addr) == ADDR_EXPR) ! align = MAX (align, get_object_alignment (TREE_OPERAND (addr, 0), ~0U)); bitpos += mem_ref_offset (exp).low * BITS_PER_UNIT; } else if (TREE_CODE (exp) == TARGET_MEM_REF) *************** get_object_alignment (tree exp, unsigned *** 345,352 **** align = MAX (pi->align * BITS_PER_UNIT, align); } else if (TREE_CODE (addr) == ADDR_EXPR) ! align = MAX (align, get_object_alignment (TREE_OPERAND (addr, 0), ! max_align)); if (TMR_OFFSET (exp)) bitpos += TREE_INT_CST_LOW (TMR_OFFSET (exp)) * BITS_PER_UNIT; if (TMR_INDEX (exp) && TMR_STEP (exp)) --- 344,350 ---- align = MAX (pi->align * BITS_PER_UNIT, align); } else if (TREE_CODE (addr) == ADDR_EXPR) ! align = MAX (align, get_object_alignment (TREE_OPERAND (addr, 0), ~0U)); if (TMR_OFFSET (exp)) bitpos += TREE_INT_CST_LOW (TMR_OFFSET (exp)) * BITS_PER_UNIT; if (TMR_INDEX (exp) && TMR_STEP (exp)) *************** get_object_alignment (tree exp, unsigned *** 364,370 **** /* If there is a non-constant offset part extract the maximum alignment that can prevail. */ ! inner = max_align; while (offset) { tree next_offset; --- 362,368 ---- /* If there is a non-constant offset part extract the maximum alignment that can prevail. */ ! inner = ~0U; while (offset) { tree next_offset; *************** get_object_alignment (tree exp, unsigned *** 411,416 **** --- 409,429 ---- align = MIN (align, inner); bitpos = bitpos & (align - 1); + *bitposp = bitpos; + return align; + } + + /* Return the alignment in bits of EXP, an object. + Don't return more than MAX_ALIGN no matter what. */ + + unsigned int + get_object_alignment (tree exp, unsigned int max_align) + { + unsigned HOST_WIDE_INT bitpos = 0; + unsigned int align; + + align = get_object_alignment_1 (exp, &bitpos); + /* align and bitpos now specify known low bits of the pointer. ptr & (align - 1) == bitpos. */ Index: gcc/fold-const.c =================================================================== *** gcc/fold-const.c (revision 172416) --- gcc/fold-const.c (working copy) *************** get_pointer_modulus_and_residue (tree ex *** 9230,9259 **** code = TREE_CODE (expr); if (code == ADDR_EXPR) { ! expr = TREE_OPERAND (expr, 0); ! if (handled_component_p (expr)) ! { ! HOST_WIDE_INT bitsize, bitpos; ! tree offset; ! enum machine_mode mode; ! int unsignedp, volatilep; ! ! expr = get_inner_reference (expr, &bitsize, &bitpos, &offset, ! &mode, &unsignedp, &volatilep, false); ! *residue = bitpos / BITS_PER_UNIT; ! if (offset) ! { ! if (TREE_CODE (offset) == INTEGER_CST) ! *residue += TREE_INT_CST_LOW (offset); ! else ! /* We don't handle more complicated offset expressions. */ ! return 1; ! } ! } ! ! if (DECL_P (expr) ! && (allow_func_align || TREE_CODE (expr) != FUNCTION_DECL)) ! return DECL_ALIGN_UNIT (expr); } else if (code == POINTER_PLUS_EXPR) { --- 9230,9239 ---- code = TREE_CODE (expr); if (code == ADDR_EXPR) { ! unsigned int bitalign; ! bitalign = get_object_alignment_1 (TREE_OPERAND (expr, 0), residue); ! *residue /= BITS_PER_UNIT; ! return bitalign / BITS_PER_UNIT; } else if (code == POINTER_PLUS_EXPR) { *************** get_pointer_modulus_and_residue (tree ex *** 9298,9306 **** } } ! /* If we get here, we were unable to determine anything useful about the ! expression. */ ! return 1; } --- 9278,9286 ---- } } ! /* If we get here, we were unable to determine anything useful about the ! expression. */ ! return 1; } Index: gcc/testsuite/c-c++-common/fold-bitand-4.c =================================================================== *** gcc/testsuite/c-c++-common/fold-bitand-4.c (revision 0) --- gcc/testsuite/c-c++-common/fold-bitand-4.c (revision 0) *************** *** 0 **** --- 1,45 ---- + /* { dg-do compile } */ + /* { dg-options "-fdump-tree-original" } */ + /* { dg-options "-fdump-tree-original -fno-common" { target hppa*-*-hpux* } } */ + + typedef char char4[4] __attribute__ ((aligned (4))); + char4 c4[4] __attribute__ ((aligned (16))); + + typedef char char16[16] __attribute__ ((aligned (16))); + char16 c16[4] __attribute__ ((aligned (4))); + + int f1 (void) + { + /* 12 */ + return 15 & (__SIZE_TYPE__)&c4[3]; + } + + int f2 (int i) + { + /* Indeterminate */ + return 15 & (__SIZE_TYPE__)&c4[i]; + } + + int f3 (int i) + { + /* 0 */ + return 3 & (__SIZE_TYPE__)&c4[i]; + } + + int f4 (int i) + { + /* Indeterminate */ + return 7 & (__SIZE_TYPE__)&c16[i]; + } + + int f5 (int i) + { + /* 0 */ + return 3 & (__SIZE_TYPE__)&c16[i]; + } + + /* { dg-final { scan-tree-dump-times "return \[^\n0-9\]*12;" 1 "original" } } */ + /* { dg-final { scan-tree-dump-times "\& 15" 1 "original" } } */ + /* { dg-final { scan-tree-dump-times "return \[^\n0-9\]*0;" 2 "original" } } */ + /* { dg-final { scan-tree-dump-times "\& 7" 1 "original" } } */ + /* { dg-final { cleanup-tree-dump "original" } } */