aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/testsuite/g++.dg/tree-ssa/pr112711.C31
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr112721.c26
-rw-r--r--gcc/tree-sra.cc40
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);