On 09/24/2011 01:42 PM, Richard Guenther wrote: > On Sat, Sep 24, 2011 at 11:40 AM, Jakub Jelinek <ja...@redhat.com> wrote: >> On Sat, Sep 24, 2011 at 11:31:25AM +0200, Richard Guenther wrote: >>> In the end I'd probably say the patch is ok without the option (thus >>> turned on by default), but if LC_GLOBAL_LOCALE is part of the >>> glibc ABI then we clearly can't do this. >> >> Yes, LC_GLOBAL_LOCALE is part of glibc ABI. I guess we could only assume >> the alignment if the pointer is actually dereferenced on the statement >> that checks the ABI or in some stmt that dominates the spot where you want >> to check the alignment. It is IMHO quite common to pass arbitrary values >> in pointer types, then cast them back or just compare. > > Yeah (even if technically invoking undefined behavior in C). Checking if > there is a dereference post-dominating function entry with sth like > > FOR_EACH_IMM_USE_STMT (... ptr ...) > if (stmt_post_dominates_entry && contains derefrence of ptr) > alignment = TYPE_ALIGN (...); > > and otherwise not assuming anything about parameter alignment might work. > Be careful to check the alignment of the dereference though, > > typedef int int_unaligned __attribute__((aligned(1))); > int foo (int *p) > { > int_unaligned *q = p; > return *q; > } > > will be MEM[p] but with (well, hopefully ;)) TYPE_ALIGN of TREE_TYPE (MEM[p]) > being 1. And yes, you'd have to look into handled-components as well. I > guess > you'll face similar problems as we do with tree-sra.c > tree_non_mode_aligned_mem_p > (you need to assume eventually misaligned accesses the same way expansion > does for the dereference, otherwise you'll run into issues on > strict-align targets). > > As that de-refrence thing doesn't really fit the CCP propagation you > won't be able > to handle > > int foo (int *p) > { > int *q = (char *)p + 3; > return *q; > } > > and assume q is aligned (and p is misaligned by 1). > > That is, if the definition of a pointer is post-dominated by a derefrence > we could assume proper alignment for that pointer (as opposed to just > special-casing its default definition). Would be certainly interesting to > see what kind of fallout we would get from that ;) >
I gave this a try in deduce_alignment_from_dereferences. The fall-out I got from this were unaligned dereferenced pointers in gcc.c-torture/unsorted/*{cmp,set}.c. Bootstrapped and reg-tested on x86_64. Build and reg-tested on MIPS and ARM. Ok for trunk? Thanks, - Tom > Richard. > >> Jakub >> 2011-10-25 Tom de Vries <t...@codesourcery.com> PR target/43814 * tree-ssa-ccp.c (get_align_value): New function, factored out of get_value_from_alignment. (get_value_from_alignment): Use get_align_value. (get_value_for_expr): Use get_align_value to handle alignment of pointers with ptr_info->align set. (deduce_alignment_from_dereferences): New function. (do_ssa_ccp): Calculate post-dominance info and call deduce_alignment_from_dereferences. * gcc/testsuite/gcc.target/arm/pr43814-2.c: New test. * gcc.c-torture/unsorted/HIcmp.c: Fix unaligned pointer. * gcc.c-torture/unsorted/HIset.c: Same. * gcc.c-torture/unsorted/SIcmp.c: Same. * gcc.c-torture/unsorted/SIset.c: Same. * gcc.c-torture/unsorted/SFset.c: Same. * gcc.c-torture/unsorted/UHIcmp.c: Same. * gcc.c-torture/unsorted/USIcmp.c: Same. * gcc.c-torture/unsorted/DFcmp.c: Same.
Index: gcc/tree-ssa-ccp.c =================================================================== --- gcc/tree-ssa-ccp.c (revision 180237) +++ gcc/tree-ssa-ccp.c (working copy) @@ -500,20 +500,14 @@ value_to_double_int (prop_value_t val) return double_int_zero; } -/* Return the value for the address expression EXPR based on alignment - information. */ +/* Return the value for an expr of type TYPE with alignment ALIGN and offset + BITPOS relative to the alignment. */ static prop_value_t -get_value_from_alignment (tree expr) +get_align_value (unsigned int align, tree type, unsigned HOST_WIDE_INT bitpos) { - tree type = TREE_TYPE (expr); prop_value_t val; - unsigned HOST_WIDE_INT bitpos; - unsigned int align; - - gcc_assert (TREE_CODE (expr) == ADDR_EXPR); - align = get_object_alignment_1 (TREE_OPERAND (expr, 0), &bitpos); val.mask = double_int_and_not (POINTER_TYPE_P (type) || TYPE_UNSIGNED (type) ? double_int_mask (TYPE_PRECISION (type)) @@ -529,6 +523,21 @@ get_value_from_alignment (tree expr) return val; } +/* Return the value for the address expression EXPR based on alignment + information. */ + +static prop_value_t +get_value_from_alignment (tree expr) +{ + unsigned int align; + unsigned HOST_WIDE_INT bitpos; + + gcc_assert (TREE_CODE (expr) == ADDR_EXPR); + + align = get_object_alignment_1 (TREE_OPERAND (expr, 0), &bitpos); + return get_align_value (align, TREE_TYPE (expr), bitpos); +} + /* Return the value for the tree operand EXPR. If FOR_BITS_P is true return constant bits extracted from alignment information for invariant addresses. */ @@ -541,10 +550,18 @@ get_value_for_expr (tree expr, bool for_ if (TREE_CODE (expr) == SSA_NAME) { val = *get_value (expr); - if (for_bits_p - && val.lattice_val == CONSTANT + if (!for_bits_p) + return val; + + if (val.lattice_val == CONSTANT && TREE_CODE (val.value) == ADDR_EXPR) val = get_value_from_alignment (val.value); + else if (val.lattice_val == VARYING + && SSA_NAME_PTR_INFO (expr) != NULL + && SSA_NAME_PTR_INFO (expr)->align > 1 + && SSA_NAME_PTR_INFO (expr)->misalign == 0) + val = get_align_value (SSA_NAME_PTR_INFO (expr)->align * BITS_PER_UNIT, + TREE_TYPE (expr), 0); } else if (is_gimple_min_invariant (expr) && (!for_bits_p || TREE_CODE (expr) != ADDR_EXPR)) @@ -2018,12 +2035,105 @@ ccp_visit_stmt (gimple stmt, edge *taken return SSA_PROP_VARYING; } +/* Find pointer dereferences that post-dominate function entry and set + ptr_info->align for those pointers, and propagate backward through pointer + arithmetic. */ + +static void +deduce_alignment_from_dereferences (void) +{ + basic_block bb, entry; + gimple stmt, def; + unsigned int align; + tree memref, ptr, offset; + struct ptr_info_def *pi; + + /* Needs to be the successor of entry, for CDI_POST_DOMINATORS. */ + entry = single_succ (ENTRY_BLOCK_PTR); + + FOR_EACH_BB (bb) + { + gimple_stmt_iterator i; + + if (!dominated_by_p (CDI_POST_DOMINATORS, entry, bb)) + continue; + + for (i = gsi_start_nondebug_bb (bb); !gsi_end_p (i); + gsi_next_nondebug (&i)) + { + stmt = gsi_stmt (i); + if (!is_gimple_assign (stmt)) + continue; + + if (gimple_assign_rhs_code (stmt) == MEM_REF) + { + memref = gimple_assign_rhs1 (stmt); + + align = TYPE_ALIGN (TREE_TYPE (memref)) / BITS_PER_UNIT; + if (align == 1) + continue; + + offset = TREE_OPERAND (memref, 1); + if (!host_integerp (offset, 0) + || tree_low_cst (offset, 0) % align != 0) + continue; + + ptr = TREE_OPERAND (memref, 0); + } + else + /* Todo: handle more cases. */ + continue; + + if (TREE_CODE (ptr) == INTEGER_CST + && host_integerp (ptr, 0) + && tree_low_cst (ptr, 0) % align != 0) + error ("misaligned pointer dereferenced"); + + while (TREE_CODE (ptr) == SSA_NAME) + { + pi = get_ptr_info (ptr); + if (pi->misalign != 0) + { + error ("misaligned pointer dereferenced"); + break; + } + + if (pi->align >= align) + break; + pi->align = align; + + if (SSA_NAME_IS_DEFAULT_DEF (ptr)) + break; + + /* Propagate backwards over pointer arithmetic. */ + def = SSA_NAME_DEF_STMT (ptr); + if (!is_gimple_assign (def)) + break; + + if (gimple_assign_rhs_code (def) == POINTER_PLUS_EXPR) + { + offset = gimple_assign_rhs2 (def); + if (!host_integerp (offset, 0) + || tree_low_cst (offset, 0) % align != 0) + break; + + ptr = gimple_assign_rhs1 (def); + } + else + /* Todo: handle more cases. */ + break; + } + } + } +} /* Main entry point for SSA Conditional Constant Propagation. */ static unsigned int do_ssa_ccp (void) { + calculate_dominance_info (CDI_POST_DOMINATORS); + deduce_alignment_from_dereferences (); ccp_initialize (); ssa_propagate (ccp_visit_stmt, ccp_visit_phi_node); if (ccp_finalize ()) Index: gcc/testsuite/gcc.target/arm/pr43814-2.c =================================================================== --- /dev/null (new file) +++ gcc/testsuite/gcc.target/arm/pr43814-2.c (revision 0) @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-Os -finline-functions -mno-unaligned-access -fdump-rtl-expand" } */ + +typedef unsigned int size_t; +extern void* memcpy (void *, const void *, size_t); + +typedef union JValue { + void* l; +} JValue; +typedef struct Object { + int x; +} Object; + +extern __inline__ long long +dvmGetArgLong (const unsigned int* args, int elem) +{ + long long val; + memcpy (&val, &args[elem], 8); + return val; +} + +void +Dalvik_sun_misc_Unsafe_getObject (const unsigned int* args, JValue* pResult) +{ + Object* obj = (Object*) args[1]; + long long offset = dvmGetArgLong (args, 2); + Object** address = (Object**) (((unsigned char*) obj) + offset); + pResult->l = ((void*) *address); +} + +/* { dg-final { scan-rtl-dump-times "memcpy" 0 "expand"} } */ +/* { dg-final { cleanup-tree-dump "expand" } } */ + Index: gcc/testsuite/gcc.c-torture/unsorted/HIcmp.c =================================================================== --- gcc/testsuite/gcc.c-torture/unsorted/HIcmp.c (revision 180237) +++ gcc/testsuite/gcc.c-torture/unsorted/HIcmp.c (working copy) @@ -12,7 +12,7 @@ type glob0, glob1; #define adrx0 (E0[x0]) #define regx0 (p0[x0]) -#define E1 ((type *)11111111) +#define E1 ((type *)(11111111 & ~(sizeof (type) - 1))) #define reg1 r1 #define indreg1 (*p1) #define imm1 33 Index: gcc/testsuite/gcc.c-torture/unsorted/HIset.c =================================================================== --- gcc/testsuite/gcc.c-torture/unsorted/HIset.c (revision 180237) +++ gcc/testsuite/gcc.c-torture/unsorted/HIset.c (working copy) @@ -8,7 +8,7 @@ #define adrx0 (E0[x0]) #define regx0 (p0[x0]) -#define E1 ((type *)11111111) +#define E1 ((type *)(11111111 & ~(sizeof (type) - 1))) #define reg1 r1 #define indreg1 (*p1) #define imm1 33 Index: gcc/testsuite/gcc.c-torture/unsorted/SIcmp.c =================================================================== --- gcc/testsuite/gcc.c-torture/unsorted/SIcmp.c (revision 180237) +++ gcc/testsuite/gcc.c-torture/unsorted/SIcmp.c (working copy) @@ -12,7 +12,7 @@ type glob0, glob1; #define adrx0 (E0[x0]) #define regx0 (p0[x0]) -#define E1 ((type *)11111111) +#define E1 ((type *)(11111111 & ~(sizeof (type) - 1))) #define reg1 r1 #define indreg1 (*p1) #define imm1 33 Index: gcc/testsuite/gcc.c-torture/unsorted/SIset.c =================================================================== --- gcc/testsuite/gcc.c-torture/unsorted/SIset.c (revision 180237) +++ gcc/testsuite/gcc.c-torture/unsorted/SIset.c (working copy) @@ -8,7 +8,7 @@ #define adrx0 (E0[x0]) #define regx0 (p0[x0]) -#define E1 ((type *)11111111) +#define E1 ((type *)(11111111 & ~(sizeof (type) - 1))) #define reg1 r1 #define indreg1 (*p1) #define imm1 33 Index: gcc/testsuite/gcc.c-torture/unsorted/SFset.c =================================================================== --- gcc/testsuite/gcc.c-torture/unsorted/SFset.c (revision 180237) +++ gcc/testsuite/gcc.c-torture/unsorted/SFset.c (working copy) @@ -8,7 +8,7 @@ #define adrx0 (E0[x0]) #define regx0 (p0[x0]) -#define E1 ((type *)11111111) +#define E1 ((type *)(11111111 & ~(sizeof (type) - 1))) #define reg1 r1 #define indreg1 (*p1) #define imm1 33 Index: gcc/testsuite/gcc.c-torture/unsorted/UHIcmp.c =================================================================== --- gcc/testsuite/gcc.c-torture/unsorted/UHIcmp.c (revision 180237) +++ gcc/testsuite/gcc.c-torture/unsorted/UHIcmp.c (working copy) @@ -12,7 +12,7 @@ type glob0, glob1; #define adrx0 (E0[x0]) #define regx0 (p0[x0]) -#define E1 ((type *)11111111) +#define E1 ((type *)(11111111 & ~(sizeof (type) - 1))) #define reg1 r1 #define indreg1 (*p1) #define imm1 33 Index: gcc/testsuite/gcc.c-torture/unsorted/USIcmp.c =================================================================== --- gcc/testsuite/gcc.c-torture/unsorted/USIcmp.c (revision 180237) +++ gcc/testsuite/gcc.c-torture/unsorted/USIcmp.c (working copy) @@ -12,7 +12,7 @@ type glob0, glob1; #define adrx0 (E0[x0]) #define regx0 (p0[x0]) -#define E1 ((type *)11111111) +#define E1 ((type *)(11111111 & ~(sizeof (type) - 1))) #define reg1 r1 #define indreg1 (*p1) #define imm1 33 Index: gcc/testsuite/gcc.c-torture/unsorted/DFcmp.c =================================================================== --- gcc/testsuite/gcc.c-torture/unsorted/DFcmp.c (revision 180237) +++ gcc/testsuite/gcc.c-torture/unsorted/DFcmp.c (working copy) @@ -12,7 +12,7 @@ type glob0, glob1; #define adrx0 (E0[x0]) #define regx0 (p0[x0]) -#define E1 ((type *)11111111) +#define E1 ((type *)(11111111 & ~(sizeof (type) - 1))) #define reg1 r1 #define indreg1 (*p1) #define imm1 33