On 09/24/2011 01:42 PM, Richard Guenther wrote:
> On Sat, Sep 24, 2011 at 11:40 AM, Jakub Jelinek <[email protected]> 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 <[email protected]>
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