https://gcc.gnu.org/g:ee4a808fdab1b7a83636a64dff633b0bff849629
commit r16-6340-gee4a808fdab1b7a83636a64dff633b0bff849629 Author: Kugan Vivekanandarajah <[email protected]> Date: Tue Dec 23 08:28:54 2025 +1100 [Bug 123067][V3] Fix LICM wrong code Check for partial aliasing in self write test. gcc/ChangeLog: 2025-12-22 Kugan Vivekanandarajah <[email protected]> PR middle-end/123067 * tree-ssa-loop-im.cc(is_self_write): Check load and store refer to same location. gcc/testsuite/ChangeLog: 2025-12-22 Kugan Vivekanandarajah <[email protected]> PR middle-end/123067 * gcc.dg/licm-self-write-partial-alias.c: New test. Signed-off-by: Kugan Vivekanandarajah <[email protected]> Diff: --- .../gcc.dg/licm-self-write-partial-alias.c | 31 ++++++++++++++++++++++ gcc/tree-ssa-loop-im.cc | 22 ++++++++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/gcc/testsuite/gcc.dg/licm-self-write-partial-alias.c b/gcc/testsuite/gcc.dg/licm-self-write-partial-alias.c new file mode 100644 index 000000000000..7b8792feb754 --- /dev/null +++ b/gcc/testsuite/gcc.dg/licm-self-write-partial-alias.c @@ -0,0 +1,31 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +int +main (void) +{ + /* Array element shifting - partial aliasing. */ + { + int a[6] = {0, 0, 1, 2, 0, 0}; + unsigned char i, j; + for (i = 1; i != 0; ++i) + { + for (j = 1; j <= 4; j++) + a[j] = a[j + 1]; + } + if (a[1] != 0) + __builtin_abort (); + } + + /* Memmove with overlapping regions - partial aliasing. */ + { + unsigned char a[6] = {0, 0, 1, 2, 0, 0}; + for (int i = 0; i < 256; i++) + __builtin_memmove (&a[1], &a[2], 4); + if (a[1] != 0) + __builtin_abort (); + } + + return 0; +} + diff --git a/gcc/tree-ssa-loop-im.cc b/gcc/tree-ssa-loop-im.cc index 61f08beb9ff6..35628befc502 100644 --- a/gcc/tree-ssa-loop-im.cc +++ b/gcc/tree-ssa-loop-im.cc @@ -3174,7 +3174,27 @@ is_self_write (im_mem_ref *load_ref, im_mem_ref *store_ref) return false; /* Self write: stored value is the loaded value. */ - return stored_val == loaded_val; + if (stored_val != loaded_val) + return false; + + + /* TODO: Try to factor this out with mem_ref_hasher::equal + into im_compare_access_position_and_size + or a similar helper to centralize this delicate handling + complete for MEM_REF offsets and base pointer equality. + + TODO: Also ensure max_size_known_p agrees or resort to + alignment considerations to rule out partial overlaps. + + See: + https://gcc.gnu.org/pipermail/gcc-patches/2025-December/704155.html + For more context on TODOs above. */ + + /* They may alias. Verify exact same location. */ + return (operand_equal_p (load_ref->mem.base, store_ref->mem.base, 0) + && known_eq (load_ref->mem.size, store_ref->mem.size) + && known_eq (load_ref->mem.offset, store_ref->mem.offset)); + } /* Returns true if REF1 and REF2 are independent. */
