Bug type: miscompilation
Component: AggressiveInstCombine
Bug location: llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp: foldLoadsRecursive
Issue title: [AggressiveInstCombine] Miscompilation at O3
Labels: miscompilation
llvm:instcombine
generated by fuzzer
Reported by: dtcxzyw

Reproducer: https://alive2.llvm.org/ce/z/msNmWC
```
; bin/opt -passes=aggressive-instcombine test.ll -S
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

@g_374 = global ptr @g_375
@g_375 = global { i32, i8, [3 x i8] } { i32 8, i8 -9, [3 x i8] zeroinitializer }

define i32 @main() {
entry:
  %0 = load ptr, ptr @g_374, align 8
  %l_1162.sroa.3.8.copyload.i.i = load i32, ptr %0, align 4
  %l_1162.sroa.6.8..sroa_idx.i.i = getelementptr i8, ptr %0, i64 4
  %l_1162.sroa.8.8..sroa_idx.i.i = getelementptr i8, ptr %0, i64 5
  store i8 0, ptr getelementptr inbounds nuw (i8, ptr @g_375, i64 4), align 4
  %l_1162.sroa.6.8.copyload.i.i = load i8, ptr %l_1162.sroa.6.8..sroa_idx.i.i, align 4
  %l_1162.sroa.8.8.copyload.i.i = load i24, ptr %l_1162.sroa.8.8..sroa_idx.i.i, align 1
  %1 = zext i24 %l_1162.sroa.8.8.copyload.i.i to i64
  %2 = shl i64 %1, 40
  %3 = zext i8 %l_1162.sroa.6.8.copyload.i.i to i64
  %4 = shl i64 %3, 32
  %5 = or i64 %2, %4
  %6 = zext i32 %l_1162.sroa.3.8.copyload.i.i to i64
  %7 = or i64 %5, %6
  store i64 %7, ptr %0, align 4
  %8 = load i32, ptr getelementptr inbounds nuw (i8, ptr @g_375, i64 4), align 4
  ret i32 %8
}
```
```
; ModuleID = 'reduced.ll'
source_filename = "reduced.ll"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

@g_374 = global ptr @g_375
@g_375 = global { i32, i8, [3 x i8] } { i32 8, i8 -9, [3 x i8] zeroinitializer }

define i32 @main() {
entry:
  %0 = load ptr, ptr @g_374, align 8
  %l_1162.sroa.3.8.copyload.i.i = load i64, ptr %0, align 4
  store i8 0, ptr getelementptr inbounds nuw (i8, ptr @g_375, i64 4), align 4
  store i64 %l_1162.sroa.3.8.copyload.i.i, ptr %0, align 4
  %1 = load i32, ptr getelementptr inbounds nuw (i8, ptr @g_375, i64 4), align 4
  ret i32 %1
}
```
llubi output:
src:
```
Entering function main
  %0 = load ptr, ptr @g_374, align 8 -> Ptr 2056[@g_375] captures(address, provenance) RW
  %l_1162.sroa.3.8.copyload.i.i = load i32, ptr %0, align 4 -> i32 8
  %l_1162.sroa.6.8..sroa_idx.i.i = getelementptr i8, ptr %0, i64 4 -> Ptr 2060[@g_375 + 4] captures(address, provenance) RW
  %l_1162.sroa.8.8..sroa_idx.i.i = getelementptr i8, ptr %0, i64 5 -> Ptr 2061[@g_375 + 5] captures(address, provenance) RW
  %1 = getelementptr inbounds nuw i8, ptr @g_375, i64 4 -> Ptr 2060[@g_375 + 4] captures(address, provenance) RW
  store i8 0, ptr %1, align 4
  %l_1162.sroa.6.8.copyload.i.i = load i8, ptr %l_1162.sroa.6.8..sroa_idx.i.i, align 4 -> i8 0
  %l_1162.sroa.8.8.copyload.i.i = load i24, ptr %l_1162.sroa.8.8..sroa_idx.i.i, align 1 -> i24 0
  %2 = zext i24 %l_1162.sroa.8.8.copyload.i.i to i64 -> i64 0
  %3 = shl i64 %2, 40 -> i64 0
  %4 = zext i8 %l_1162.sroa.6.8.copyload.i.i to i64 -> i64 0
  %5 = shl i64 %4, 32 -> i64 0
  %6 = or i64 %3, %5 -> i64 0
  %7 = zext i32 %l_1162.sroa.3.8.copyload.i.i to i64 -> i64 8
  %8 = or i64 %6, %7 -> i64 8
  store i64 %8, ptr %0, align 4
  %9 = getelementptr inbounds nuw i8, ptr @g_375, i64 4 -> Ptr 2060[@g_375 + 4] captures(address, provenance) RW
  %10 = load i32, ptr %9, align 4 -> i32 0
  ret i32 %10
Exiting function main
```
tgt:
```
Entering function main
  %0 = load ptr, ptr @g_374, align 8 -> Ptr 2056[@g_375] captures(address, provenance) RW
  %l_1162.sroa.3.8.copyload.i.i = load i64, ptr %0, align 4 -> i64 1060856922120
  %1 = getelementptr inbounds nuw i8, ptr @g_375, i64 4 -> Ptr 2060[@g_375 + 4] captures(address, provenance) RW
  store i8 0, ptr %1, align 4
  store i64 %l_1162.sroa.3.8.copyload.i.i, ptr %0, align 4
  %2 = getelementptr inbounds nuw i8, ptr @g_375, i64 4 -> Ptr 2060[@g_375 + 4] captures(address, provenance) RW
  %3 = load i32, ptr %2, align 4 -> i32 247
  ret i32 %3
Exiting function main
```

Comments: author: dtcxzyw
body: Reduced:
```
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

@g = global i64 1060856922120, align 8
@g_ref = global ptr @g, align 8

define i64 @test() {
entry:
  %p = load ptr, ptr @g_ref, align 8
  %load1 = load i32, ptr %p, align 4
  %gep1 = getelementptr i8, ptr %p, i64 4
  %gep2 = getelementptr i8, ptr %p, i64 5
  store i8 0, ptr getelementptr inbounds nuw (i8, ptr @g, i64 4), align 4
  %load2 = load i8, ptr %gep1, align 4
  %load3 = load i24, ptr %gep2, align 1
  %zext1 = zext i24 %load3 to i64
  %shl1 = shl i64 %zext1, 40
  %zext2 = zext i8 %load2 to i64
  %shl2 = shl i64 %zext2, 32
  %or1 = or i64 %shl1, %shl2
  %zext3 = zext i32 %load1 to i64
  %or2 = or i64 %or1, %zext3
  %res = lshr i64 %or2, 32
  ret i64 %res
}

```

Fix patch:
commit c7c6c0a45c1d840d05b414d73f7bab5136dcb8c2
Author: Yingwei Zheng <dtcxzyw2333@gmail.com>
Date:   Mon Dec 1 22:46:16 2025 +0800

    [AggressiveInstCombine] Fix memory location for alias analysis (#169953)
    
    When LOps.RootInsert comes after LI2, since we use LI2 as the new insert
    point, we should make sure the memory region accessed by LOps isn't
    modified. However, the original implementation passes the bit width
    `LOps.LoadSize` as the number of bytes to be accessed, causing BasicAA
    to return NoAlias:
    
    https://github.com/llvm/llvm-project/blob/a941e150749650e6a75e948f10d46b0bedcc128b/llvm/lib/Analysis/BasicAliasAnalysis.cpp#L1658-L1667
    With `-aa-trace`, we get:
    ```
    End ptr getelementptr inbounds nuw (i8, ptr @g, i64 4) @ LocationSize::precise(1),   %gep1 = getelementptr i8, ptr %p, i64 4 @ LocationSize::precise(32) = NoAlias
    ```
    This patch uses `getTypeStoreSize` to compute the correct access size
    for LOps. Instead of modifying the MemoryLocation for End (i.e.,
    `LOps.RootInsert`), it also uses the computed base and AATag for
    correctness.
    
    Closes https://github.com/llvm/llvm-project/issues/169921.

diff --git a/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp b/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp
index 7ed8fb68f107..2397133fa61e 100644
--- a/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp
+++ b/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp
@@ -710,9 +710,17 @@ static bool foldLoadsRecursive(Value *V, LoadOps &LOps, const DataLayout &DL,
   MemoryLocation Loc;
   if (!Start->comesBefore(End)) {
     std::swap(Start, End);
-    Loc = MemoryLocation::get(End);
+    // If LOps.RootInsert comes after LI2, since we use LI2 as the new insert
+    // point, we should make sure whether the memory region accessed by LOps
+    // isn't modified.
     if (LOps.FoundRoot)
-      Loc = Loc.getWithNewSize(LOps.LoadSize);
+      Loc = MemoryLocation(
+          LOps.Root->getPointerOperand(),
+          LocationSize::precise(DL.getTypeStoreSize(
+              IntegerType::get(LI1->getContext(), LOps.LoadSize))),
+          LOps.AATags);
+    else
+      Loc = MemoryLocation::get(End);
   } else
     Loc = MemoryLocation::get(End);
   unsigned NumScanned = 0;


Regression tests:
file: llvm/test/Transforms/AggressiveInstCombine/X86/or-load.ll
commands: opt < %s -passes=aggressive-instcombine -mtriple x86_64-none-eabi -mattr=avx2 -data-layout="e-n64" -S
opt < %s -passes=aggressive-instcombine -mtriple x86_64-none-eabi -mattr=avx2 -data-layout="E-n64" -S
tests: test_name: loadcombine_consecutive_mayalias
test_body: @g = global i64 1060856922120

define i64 @loadcombine_consecutive_mayalias(ptr %p) {
entry:
  %load1 = load i32, ptr %p, align 4
  %gep1 = getelementptr i8, ptr %p, i64 4
  %gep2 = getelementptr i8, ptr %p, i64 5
  store i8 0, ptr getelementptr inbounds nuw (i8, ptr @g, i64 4), align 4
  %load2 = load i8, ptr %gep1, align 4
  %load3 = load i24, ptr %gep2, align 1
  %zext1 = zext i24 %load3 to i64
  %shl1 = shl i64 %zext1, 40
  %zext2 = zext i8 %load2 to i64
  %shl2 = shl i64 %zext2, 32
  %or1 = or i64 %shl1, %shl2
  %zext3 = zext i32 %load1 to i64
  %or2 = or i64 %or1, %zext3
  %res = lshr i64 %or2, 32
  ret i64 %res
}