diff options
-rw-r--r-- | gcc/testsuite/g++.dg/tree-ssa/pr112711.C | 31 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/pr112721.c | 26 | ||||
-rw-r--r-- | gcc/tree-sra.cc | 40 |
3 files changed, 88 insertions, 9 deletions
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr112711.C b/gcc/testsuite/g++.dg/tree-ssa/pr112711.C new file mode 100644 index 0000000..13bc48d --- /dev/null +++ b/gcc/testsuite/g++.dg/tree-ssa/pr112711.C @@ -0,0 +1,31 @@ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O1" } */ + +typedef int i32; +typedef unsigned int u32; + +static inline void write_i32(void *memory, i32 value) { + // swap i32 bytes as if it was u32: + u32 u_value = value; + value = __builtin_bswap32(u_value); + + // llvm infers '1' alignment from destination type + __builtin_memcpy(__builtin_assume_aligned(memory, 1), &value, sizeof(value)); +} + +__attribute__((noipa)) +static void bug (void) { + #define assert_eq(lhs, rhs) if (lhs != rhs) __builtin_trap() + + unsigned char data[5]; + write_i32(data, -1362446643); + assert_eq(data[0], 0xAE); + assert_eq(data[1], 0xCA); + write_i32(data + 1, -1362446643); + assert_eq(data[1], 0xAE); +} + +int main() { + bug(); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr112721.c b/gcc/testsuite/gcc.dg/tree-ssa/pr112721.c new file mode 100644 index 0000000..adf6261 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr112721.c @@ -0,0 +1,26 @@ +/* { dg-do run } */ +/* { dg-options "-O1" } */ + +unsigned * volatile gv; + +struct a { + int b; +}; +int c, e; +long d; +unsigned * __attribute__((noinline)) +f(unsigned *g) { + for (; c;) + e = d; + return gv ? gv : g; +} +int main() { + int *h; + struct a i = {8}; + int *j = &i.b; + h = (unsigned *) f(j); + *h = 0; + if (i.b != 0) + __builtin_abort (); + return 0; +} diff --git a/gcc/tree-sra.cc b/gcc/tree-sra.cc index 0349410..3bd0c7a 100644 --- a/gcc/tree-sra.cc +++ b/gcc/tree-sra.cc @@ -1268,18 +1268,27 @@ abnormal_edge_after_stmt_p (gimple *stmt, enum out_edge_check *oe_check) } /* Scan expression EXPR which is an argument of a call and create access - structures for all accesses to candidates for scalarization. Return true if - any access has been inserted. STMT must be the statement from which the - expression is taken. */ + structures for all accesses to candidates for scalarization. Return true + if any access has been inserted. STMT must be the statement from which the + expression is taken. CAN_BE_RETURNED must be true if call argument flags + do not rule out that the argument is directly returned. OE_CHECK is used + to remember result of a test for abnormal outgoing edges after this + statement. */ static bool -build_access_from_call_arg (tree expr, gimple *stmt, +build_access_from_call_arg (tree expr, gimple *stmt, bool can_be_returned, enum out_edge_check *oe_check) { if (TREE_CODE (expr) == ADDR_EXPR) { tree base = get_base_address (TREE_OPERAND (expr, 0)); + if (can_be_returned) + { + disqualify_base_of_expr (base, "Address possibly returned, " + "leading to an alis SRA may not know."); + return false; + } if (abnormal_edge_after_stmt_p (stmt, oe_check)) { disqualify_base_of_expr (base, "May lead to need to add statements " @@ -1508,12 +1517,25 @@ scan_function (void) case GIMPLE_CALL: { enum out_edge_check oe_check = SRA_OUTGOING_EDGES_UNCHECKED; - for (i = 0; i < gimple_call_num_args (stmt); i++) - ret |= build_access_from_call_arg (gimple_call_arg (stmt, i), - stmt, &oe_check); + gcall *call = as_a <gcall *> (stmt); + for (i = 0; i < gimple_call_num_args (call); i++) + { + bool can_be_returned; + if (gimple_call_lhs (call)) + { + int af = gimple_call_arg_flags (call, i); + can_be_returned = !(af & EAF_NOT_RETURNED_DIRECTLY); + } + else + can_be_returned = false; + ret |= build_access_from_call_arg (gimple_call_arg (call, + i), + stmt, can_be_returned, + &oe_check); + } if (gimple_call_chain(stmt)) - ret |= build_access_from_call_arg (gimple_call_chain(stmt), - stmt, &oe_check); + ret |= build_access_from_call_arg (gimple_call_chain(call), + stmt, false, &oe_check); } t = gimple_call_lhs (stmt); |