https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89546
--- Comment #5 from Jakub Jelinek <jakub at gcc dot gnu.org> --- You mean -fno-strict-aliasing? I guess many options change the behavior that it doesn't trigger anymore. In the #c3 dump, I really don't see how aliasing could matter though, all are MEM_REFs with addresses of particular automatic vars, there are no pointers involved. I've instrumented the compiler a little bit: --- gcc/gimple-pretty-print.c.jj 2019-01-01 12:37:15.700998856 +0100 +++ gcc/gimple-pretty-print.c 2019-03-01 17:44:46.673862737 +0100 @@ -41,6 +41,7 @@ along with GCC; see the file COPYING3. #include "stringpool.h" #include "attribs.h" #include "asan.h" +#include "tree-dfa.h" #define INDENT(SPACE) \ do { int i; for (i = 0; i < SPACE; i++) pp_space (buffer); } while (0) @@ -575,6 +576,7 @@ dump_ternary_rhs (pretty_printer *buffer } } +volatile bool assign_extra; /* Dump the gimple assignment GS. BUFFER, SPC and FLAGS are as in pp_gimple_stmt_1. */ @@ -634,6 +636,35 @@ dump_gimple_assign (pretty_printer *buff gcc_unreachable (); if (!(flags & TDF_RHS_ONLY)) pp_semicolon (buffer); + + if (assign_extra && gimple_num_ops (gs) == 2) + { + bool any = false; + for (int i = 0; i < 2; i++) + { + tree op = gimple_op (gs, i); + if (handled_component_p (op) + || TREE_CODE (op) == MEM_REF + || TREE_CODE (op) == TARGET_MEM_REF + || DECL_P (op)) + { + poly_int64 off, size, max_size; + bool dummy; + get_ref_base_and_extent (op, &off, &size, &max_size, &dummy); + if (!any) + { + pp_string (buffer, "//"); + any = true; + } + pp_string (buffer, i ? " rhs1 " : " lhs "); + pp_wide_integer (buffer, off); + pp_space (buffer); + pp_wide_integer (buffer, size); + pp_space (buffer); + pp_wide_integer (buffer, max_size); + } + } + } } } and at the start of late_intra_sra after set assign_extra = 1 debug_bb_n (2) looks like below. Extra comments added where the value 2 propagates through: <bb 2> [local count: 1073741824]: MEM[(struct &)&merged1] ={v} {CLOBBER};// lhs 0 32 32 MEM[(struct &)&merged1 + 4] ={v} {CLOBBER};// lhs 32 32 32 MEM[(struct &)&merged1 + 8] ={v} {CLOBBER};// lhs 64 96 96 MEM[(struct &)&merged1 + 8] ={v} {CLOBBER};// lhs 64 32 32 MEM[(struct &)&merged1 + 12] ={v} {CLOBBER};// lhs 96 32 32 MEM[(struct &)&merged1 + 16] ={v} {CLOBBER};// lhs 128 16 16 MEM[(struct &)&D.9937] ={v} {CLOBBER};// lhs 0 128 128 D.9933 ={v} {CLOBBER};// lhs 0 96 96 MEM[(struct &)&D.9936] ={v} {CLOBBER};// lhs 0 128 128 D.9940 ={v} {CLOBBER};// lhs 0 96 96 D.9941 ={v} {CLOBBER};// lhs 0 96 96 D.9942 ={v} {CLOBBER};// lhs 0 64 64 D.9936 ={v} {CLOBBER};// lhs 0 128 128 MEM[(struct &)&n1] ={v} {CLOBBER};// lhs 0 128 128 D.9937 ={v} {CLOBBER};// lhs 0 128 128 n1 ={v} {CLOBBER};// lhs 0 128 128 MEM[(struct &)&merged2] ={v} {CLOBBER};// lhs 0 32 32 MEM[(struct &)&merged2 + 4] ={v} {CLOBBER};// lhs 32 32 32 MEM[(struct &)&merged2 + 8] ={v} {CLOBBER};// lhs 64 96 96 MEM[(struct &)&merged2 + 8] ={v} {CLOBBER};// lhs 64 32 32 MEM[(struct &)&merged2 + 12] ={v} {CLOBBER};// lhs 96 32 32 MEM[(struct &)&merged2 + 16] ={v} {CLOBBER};// lhs 128 16 16 MEM[(struct tuple &)&merged2 + 4].head.payload = 2;// lhs 32 32 32 // MEM[&merged2+4] == 2 MEM[(struct tuple &)&merged2 + 8].head.payload = 3;// lhs 64 32 32 D.9957.head = MEM[(const struct type_n &)&merged2 + 4];// lhs 0 32 32 rhs1 32 32 32 // MEM[&D.9957+0] == 2 MEM[(struct &)&D.9959] ={v} {CLOBBER};// lhs 0 96 96 MEM[(struct tuple *)&D.9959].head = MEM[(const struct type_n &)&D.9957];// lhs 0 32 32 rhs1 0 32 32 // MEM[&D.9959+0] == 2 D.9957 ={v} {CLOBBER};// lhs 0 64 64 MEM[(struct tuple *)&D.9959 + 4B] = 4;// lhs 32 32 32 D.9960 = D.9959;// lhs 0 96 96 rhs1 0 96 96 // MEM[&D.9960+0] == 2 MEM[(struct &)&D.9953] ={v} {CLOBBER};// lhs 0 128 128 D.9953.head = MEM[(const struct type_n &)&merged2 + 8];// lhs 0 32 32 rhs1 64 32 32 D.9953.tail = MEM[(const struct tuple &)&D.9960];// lhs 32 96 96 rhs1 0 96 96 // MEM[&D.9953+4] == 2 D.9960 ={v} {CLOBBER};// lhs 0 96 96 D.9959 ={v} {CLOBBER};// lhs 0 96 96 D.9952 = D.9953;// lhs 0 128 128 rhs1 0 128 128 // MEM[&D.9952+4] == 2 MEM[(struct &)&D.9944] ={v} {CLOBBER};// lhs 0 160 160 MEM[(struct tuple *)&D.9944].tail = MEM[(const struct tuple &)&D.9952];// lhs 32 128 128 rhs1 0 128 128 // MEM[&D.9944+8] == 2 D.9952 ={v} {CLOBBER};// lhs 0 128 128 D.9953 ={v} {CLOBBER};// lhs 0 128 128 D.9954 ={v} {CLOBBER};// lhs 0 64 64 D.9947 = MEM[(const struct tuple &)&D.9944 + 8];// lhs 0 96 96 rhs1 64 96 96 // MEM[&D.9947+0] == 2 MEM[(struct tuple *)&D.9948].tail = MEM[(const struct tuple &)&D.9947];// lhs 32 96 96 rhs1 0 96 96 // MEM[&D.9948+4] == 2 SR.150_36 = MEM[(const struct tuple &)&D.9947 + 4];// rhs1 32 32 32 D.9947 ={v} {CLOBBER};// lhs 0 96 96 MEM[(struct &)&D.9949] ={v} {CLOBBER};// lhs 0 96 96 D.9949.head = MEM[(const struct type_n &)&D.9948 + 4];// lhs 0 32 32 rhs1 32 32 32 // MEM[&D.9949+0] == 2 MEM[(struct &)&n1] ={v} {CLOBBER};// lhs 0 128 128 MEM[(const struct tuple &)&D.9949 + 4] = SR.150_36;// lhs 32 32 32 n1.tail = MEM[(const struct tuple &)&D.9949];// lhs 32 96 96 rhs1 0 96 96 // MEM[&n1+4] == 2 D.9949 ={v} {CLOBBER};// lhs 0 96 96 D.9948 ={v} {CLOBBER};// lhs 0 128 128 D.9944 ={v} {CLOBBER};// lhs 0 160 160 _2 = n1.tail.head.payload;// rhs1 32 32 32 // _2 == 2 if (_2 != 2) goto <bb 3>; [0.00%] else goto <bb 4>; [100.00%] Thus, I believe the IL is correct at least of the 12 step propagation of value 2 down to _2 before late sra in main. And that is all the testcase cares about.