[llvm] [GlobalISel] Fix volatile flag handling in memmove legalizer (PR #206025)

Ömer Sinan Ağacan via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 15 05:39:51 PDT 2026


https://github.com/osa1 updated https://github.com/llvm/llvm-project/pull/206025

>From 026fcbb01ea3fd9736ee4b66cb8702c4ad8eb61e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= <omeragacan at gmail.com>
Date: Wed, 8 Jul 2026 12:03:09 +0100
Subject: [PATCH] Rebase

---
 .../CodeGen/GlobalISel/LegalizerHelper.cpp    |  65 ++++++---
 llvm/lib/CodeGen/GlobalISel/Utils.cpp         |   5 +-
 .../AArch64/GlobalISel/inline-memcpy.mir      | 120 +++++++++++++++++
 .../AArch64/GlobalISel/inline-memmove.mir     | 125 ++++++++++++++++++
 4 files changed, 293 insertions(+), 22 deletions(-)

diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index 021f7233ce3b7..c693dc13b536a 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -10837,9 +10837,10 @@ LegalizerHelper::lowerMemset(MachineInstr &MI, Register Dst, Register Val,
   for (unsigned I = 0; I < MemOps.size(); I++) {
     LLT Ty = MemOps[I];
     unsigned TySize = Ty.getSizeInBytes();
+
     if (TySize > Size) {
-      // Issuing an unaligned load / store pair that overlaps with the previous
-      // pair. Adjust the offset accordingly.
+      // Issuing a load / store pair that overlaps with the previous pair.
+      // Adjust the offset accordingly.
       assert(I == MemOps.size() - 1 && I != 0);
       DstOff -= TySize - Size;
     }
@@ -10930,16 +10931,20 @@ LegalizerHelper::lowerMemcpy(MachineInstr &MI, Register Dst, Register Src,
   unsigned CurrOffset = 0;
   unsigned Size = KnownLen;
   for (auto CopyTy : MemOps) {
-    // Issuing an unaligned load / store pair  that overlaps with the previous
-    // pair. Adjust the offset accordingly.
-    if (CopyTy.getSizeInBytes() > Size)
-      CurrOffset -= CopyTy.getSizeInBytes() - Size;
+    unsigned TySize = CopyTy.getSizeInBytes();
+
+    // Issuing a load / store pair that overlaps with the previous pair. Adjust
+    // the offset accordingly.
+    if (TySize > Size) {
+      unsigned Overlap = TySize - Size;
+      assert(Overlap < CurrOffset &&
+             "overlapping memcpy load/store spans the whole region or more");
+      CurrOffset -= Overlap;
+    }
 
     // Construct MMOs for the accesses.
-    auto *LoadMMO =
-        MF.getMachineMemOperand(&SrcMMO, CurrOffset, CopyTy.getSizeInBytes());
-    auto *StoreMMO =
-        MF.getMachineMemOperand(&DstMMO, CurrOffset, CopyTy.getSizeInBytes());
+    auto *LoadMMO = MF.getMachineMemOperand(&SrcMMO, CurrOffset, TySize);
+    auto *StoreMMO = MF.getMachineMemOperand(&DstMMO, CurrOffset, TySize);
 
     // Create the load.
     Register LoadPtr = Src;
@@ -10960,8 +10965,8 @@ LegalizerHelper::lowerMemcpy(MachineInstr &MI, Register Dst, Register Src,
       StorePtr = MIB.buildObjectPtrOffset(DstTy, Dst, Offset).getReg(0);
     }
     MIB.buildStore(LdVal, StorePtr, *StoreMMO);
-    CurrOffset += CopyTy.getSizeInBytes();
-    Size -= CopyTy.getSizeInBytes();
+    CurrOffset += TySize;
+    Size -= TySize;
   }
 
   MI.eraseFromParent();
@@ -11012,11 +11017,22 @@ LegalizerHelper::lowerMemmove(MachineInstr &MI, Register Dst, Register Src,
   // Apart from that, this loop is pretty much doing the same thing as the
   // memcpy codegen function.
   unsigned CurrOffset = 0;
+  unsigned Size = KnownLen;
   SmallVector<Register, 16> LoadVals;
   for (auto CopyTy : MemOps) {
+    unsigned TySize = CopyTy.getSizeInBytes();
+
+    // Issuing a load that overlaps with the previous load. Adjust the offset
+    // accordingly.
+    if (TySize > Size) {
+      unsigned Overlap = TySize - Size;
+      assert(Overlap < CurrOffset &&
+             "overlapping memmove load spans the whole region or more");
+      CurrOffset -= Overlap;
+    }
+
     // Construct MMO for the load.
-    auto *LoadMMO =
-        MF.getMachineMemOperand(&SrcMMO, CurrOffset, CopyTy.getSizeInBytes());
+    auto *LoadMMO = MF.getMachineMemOperand(&SrcMMO, CurrOffset, TySize);
 
     // Create the load.
     Register LoadPtr = Src;
@@ -11027,15 +11043,27 @@ LegalizerHelper::lowerMemmove(MachineInstr &MI, Register Dst, Register Src,
       LoadPtr = MIB.buildObjectPtrOffset(SrcTy, Src, Offset).getReg(0);
     }
     LoadVals.push_back(MIB.buildLoad(CopyTy, LoadPtr, *LoadMMO).getReg(0));
-    CurrOffset += CopyTy.getSizeInBytes();
+    CurrOffset += TySize;
+    Size -= TySize;
   }
 
   CurrOffset = 0;
+  Size = KnownLen;
   for (unsigned I = 0; I < MemOps.size(); ++I) {
     LLT CopyTy = MemOps[I];
+    unsigned TySize = CopyTy.getSizeInBytes();
+
+    // Issuing a store that overlaps with the previous store. Adjust the offset
+    // accordingly.
+    if (TySize > Size) {
+      unsigned Overlap = TySize - Size;
+      assert(Overlap < CurrOffset &&
+             "overlapping memmove store spans the whole region or more");
+      CurrOffset -= Overlap;
+    }
+
     // Now store the values loaded.
-    auto *StoreMMO =
-        MF.getMachineMemOperand(&DstMMO, CurrOffset, CopyTy.getSizeInBytes());
+    auto *StoreMMO = MF.getMachineMemOperand(&DstMMO, CurrOffset, TySize);
 
     Register StorePtr = Dst;
     if (CurrOffset != 0) {
@@ -11045,7 +11073,8 @@ LegalizerHelper::lowerMemmove(MachineInstr &MI, Register Dst, Register Src,
       StorePtr = MIB.buildObjectPtrOffset(DstTy, Dst, Offset).getReg(0);
     }
     MIB.buildStore(LoadVals[I], StorePtr, *StoreMMO);
-    CurrOffset += CopyTy.getSizeInBytes();
+    CurrOffset += TySize;
+    Size -= TySize;
   }
   MI.eraseFromParent();
   return Legalized;
diff --git a/llvm/lib/CodeGen/GlobalISel/Utils.cpp b/llvm/lib/CodeGen/GlobalISel/Utils.cpp
index fbb54d8971502..d1e80d547abe8 100644
--- a/llvm/lib/CodeGen/GlobalISel/Utils.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/Utils.cpp
@@ -2235,13 +2235,10 @@ bool llvm::canLowerMemCpyFamily(const MachineInstr &MI,
     const auto &SrcMMO = **std::next(MI.memoperands_begin());
     MachinePointerInfo SrcPtrInfo = SrcMMO.getPointerInfo();
     unsigned Limit = TLI.getMaxStoresPerMemmove(OptSize);
-    // FIXME: SelectionDAG always passes false for 'AllowOverlap', apparently
-    // due to a bug in it's findOptimalMemOpLowering implementation. For now do
-    // the same thing here.
     return findGISelOptimalMemOpLowering(
         MemOps, Limit,
         MemOp::Copy(KnownLen, DstAlignCanChange, std::min(DstAlign, SrcAlign),
-                    SrcAlign, /*IsVolatile=*/true),
+                    SrcAlign, IsVolatile),
         DstPtrInfo.getAddrSpace(), SrcPtrInfo.getAddrSpace(),
         MF.getFunction().getAttributes(), TLI);
   }
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/inline-memcpy.mir b/llvm/test/CodeGen/AArch64/GlobalISel/inline-memcpy.mir
index 75380895d8064..dea5f4cb8c8ad 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/inline-memcpy.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/inline-memcpy.mir
@@ -10,6 +10,10 @@
   define void @test_memcpy2_const_minsize() #3 { entry: unreachable }
   define void @test_memcpy3_const_arrays_unaligned() #4 { entry: unreachable }
   define void @test_memcpy_addrspace() #5 { entry: unreachable }
+  define void @test_memcpy_load_store_offsets_1() #6 { entry: unreachable }
+  define void @test_memcpy_load_store_offsets_2() #7 { entry: unreachable }
+  define void @test_memcpy_load_store_offsets_volatile_1() #8 { entry: unreachable }
+  define void @test_memcpy_load_store_offsets_volatile_2() #9 { entry: unreachable }
 
   attributes #2 = { optsize }
   attributes #3 = { minsize }
@@ -282,3 +286,119 @@ body:             |
     RET_ReallyLR
 
 ...
+---
+name:            test_memcpy_load_store_offsets_1
+alignment:       4
+tracksRegLiveness: true
+body:             |
+  bb.0.entry:
+    liveins: $x0, $x1
+
+    ; CHECK-LABEL: name: test_memcpy_load_store_offsets_1
+    ; CHECK: liveins: $x0, $x1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $x0
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(p0) = COPY $x1
+    ; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(i16) = G_LOAD [[COPY1]](p0) :: (load (s16), align 8)
+    ; CHECK-NEXT: G_STORE [[LOAD]](i16), [[COPY]](p0) :: (store (s16), align 8)
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 2
+    ; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[COPY1]], [[C]](i64)
+    ; CHECK-NEXT: [[LOAD1:%[0-9]+]]:_(i8) = G_LOAD [[PTR_ADD]](p0) :: (load (s8) from unknown-address + 2, align 2)
+    ; CHECK-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[COPY]], [[C]](i64)
+    ; CHECK-NEXT: G_STORE [[LOAD1]](i8), [[PTR_ADD1]](p0) :: (store (s8) into unknown-address + 2, align 2)
+    ; CHECK-NEXT: RET_ReallyLR
+    %0:_(p0) = COPY $x0
+    %1:_(p0) = COPY $x1
+    %2:_(i64) = G_CONSTANT i64 3
+    G_MEMCPY %0(p0), %1(p0), %2(i64), 0 :: (store (s8), align 8), (load (s8), align 8)
+    RET_ReallyLR
+
+...
+---
+name:            test_memcpy_load_store_offsets_2
+alignment:       4
+tracksRegLiveness: true
+body:             |
+  bb.0.entry:
+    liveins: $x0, $x1
+
+    ; CHECK-LABEL: name: test_memcpy_load_store_offsets_2
+    ; CHECK: liveins: $x0, $x1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $x0
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(p0) = COPY $x1
+    ; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(i32) = G_LOAD [[COPY1]](p0) :: (load (s32), align 8)
+    ; CHECK-NEXT: G_STORE [[LOAD]](i32), [[COPY]](p0) :: (store (s32), align 8)
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 3
+    ; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[COPY1]], [[C]](i64)
+    ; CHECK-NEXT: [[LOAD1:%[0-9]+]]:_(i32) = G_LOAD [[PTR_ADD]](p0) :: (load (s32) from unknown-address + 3, align 1)
+    ; CHECK-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[COPY]], [[C]](i64)
+    ; CHECK-NEXT: G_STORE [[LOAD1]](i32), [[PTR_ADD1]](p0) :: (store (s32) into unknown-address + 3, align 1)
+    ; CHECK-NEXT: RET_ReallyLR
+    %0:_(p0) = COPY $x0
+    %1:_(p0) = COPY $x1
+    %2:_(i64) = G_CONSTANT i64 7
+    G_MEMCPY %0(p0), %1(p0), %2(i64), 0 :: (store (s8), align 8), (load (s8), align 8)
+    RET_ReallyLR
+
+...
+---
+name:            test_memcpy_load_store_offsets_volatile_1
+alignment:       4
+tracksRegLiveness: true
+body:             |
+  bb.0.entry:
+    liveins: $x0, $x1
+
+    ; CHECK-LABEL: name: test_memcpy_load_store_offsets_volatile_1
+    ; CHECK: liveins: $x0, $x1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $x0
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(p0) = COPY $x1
+    ; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(i16) = G_LOAD [[COPY1]](p0) :: (volatile load (s16), align 8)
+    ; CHECK-NEXT: G_STORE [[LOAD]](i16), [[COPY]](p0) :: (volatile store (s16), align 8)
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 2
+    ; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[COPY1]], [[C]](i64)
+    ; CHECK-NEXT: [[LOAD1:%[0-9]+]]:_(i8) = G_LOAD [[PTR_ADD]](p0) :: (volatile load (s8) from unknown-address + 2, align 2)
+    ; CHECK-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[COPY]], [[C]](i64)
+    ; CHECK-NEXT: G_STORE [[LOAD1]](i8), [[PTR_ADD1]](p0) :: (volatile store (s8) into unknown-address + 2, align 2)
+    ; CHECK-NEXT: RET_ReallyLR
+    %0:_(p0) = COPY $x0
+    %1:_(p0) = COPY $x1
+    %2:_(i64) = G_CONSTANT i64 3
+    G_MEMCPY %0(p0), %1(p0), %2(i64), 0 :: (volatile store (s8), align 8), (volatile load (s8), align 8)
+    RET_ReallyLR
+
+...
+---
+name:            test_memcpy_load_store_offsets_volatile_2
+alignment:       4
+tracksRegLiveness: true
+body:             |
+  bb.0.entry:
+    liveins: $x0, $x1
+
+    ; CHECK-LABEL: name: test_memcpy_load_store_offsets_volatile_2
+    ; CHECK: liveins: $x0, $x1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $x0
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(p0) = COPY $x1
+    ; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(i32) = G_LOAD [[COPY1]](p0) :: (volatile load (s32), align 8)
+    ; CHECK-NEXT: G_STORE [[LOAD]](i32), [[COPY]](p0) :: (volatile store (s32), align 8)
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 4
+    ; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[COPY1]], [[C]](i64)
+    ; CHECK-NEXT: [[LOAD1:%[0-9]+]]:_(i16) = G_LOAD [[PTR_ADD]](p0) :: (volatile load (s16) from unknown-address + 4, align 4)
+    ; CHECK-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[COPY]], [[C]](i64)
+    ; CHECK-NEXT: G_STORE [[LOAD1]](i16), [[PTR_ADD1]](p0) :: (volatile store (s16) into unknown-address + 4, align 4)
+    ; CHECK-NEXT: [[C1:%[0-9]+]]:_(i64) = G_CONSTANT i64 6
+    ; CHECK-NEXT: [[PTR_ADD2:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[COPY1]], [[C1]](i64)
+    ; CHECK-NEXT: [[LOAD2:%[0-9]+]]:_(i8) = G_LOAD [[PTR_ADD2]](p0) :: (volatile load (s8) from unknown-address + 6, align 2)
+    ; CHECK-NEXT: [[PTR_ADD3:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[COPY]], [[C1]](i64)
+    ; CHECK-NEXT: G_STORE [[LOAD2]](i8), [[PTR_ADD3]](p0) :: (volatile store (s8) into unknown-address + 6, align 2)
+    ; CHECK-NEXT: RET_ReallyLR
+    %0:_(p0) = COPY $x0
+    %1:_(p0) = COPY $x1
+    %2:_(i64) = G_CONSTANT i64 7
+    G_MEMCPY %0(p0), %1(p0), %2(i64), 0 :: (volatile store (s8), align 8), (volatile load (s8), align 8)
+    RET_ReallyLR
+...
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/inline-memmove.mir b/llvm/test/CodeGen/AArch64/GlobalISel/inline-memmove.mir
index bbdaa97aeac5b..6441d0ea96989 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/inline-memmove.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/inline-memmove.mir
@@ -9,6 +9,10 @@
   define void @test_memmove3_const_toolarge() { entry: unreachable }
   define void @test_memmove4_const_unaligned() { entry: unreachable }
   define void @test_memmove_addrspace() { entry: unreachable }
+  define void @test_memmove_load_store_offsets_1() { entry: unreachable }
+  define void @test_memmove_load_store_offsets_2() { entry: unreachable }
+  define void @test_memmove_load_store_offsets_volatile_1() { entry: unreachable }
+  define void @test_memmove_load_store_offsets_volatile_2() { entry: unreachable }
 ...
 ---
 name:            test_memmove1
@@ -197,3 +201,124 @@ body:             |
     RET_ReallyLR
 
 ...
+---
+name:            test_memmove_load_store_offsets_1
+alignment:       4
+tracksRegLiveness: true
+body:             |
+  bb.0.entry:
+    liveins: $x0, $x1
+
+    ; CHECK-LABEL: name: test_memmove_load_store_offsets_1
+    ; CHECK: liveins: $x0, $x1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $x0
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(p0) = COPY $x1
+    ; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(i16) = G_LOAD [[COPY1]](p0) :: (load (s16), align 8)
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 2
+    ; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[COPY1]], [[C]](s64)
+    ; CHECK-NEXT: [[LOAD1:%[0-9]+]]:_(i8) = G_LOAD [[PTR_ADD]](p0) :: (load (s8) from unknown-address + 2, align 2)
+    ; CHECK-NEXT: G_STORE [[LOAD]](i16), [[COPY]](p0) :: (store (s16), align 8)
+    ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 2
+    ; CHECK-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[COPY]], [[C1]](s64)
+    ; CHECK-NEXT: G_STORE [[LOAD1]](i8), [[PTR_ADD1]](p0) :: (store (s8) into unknown-address + 2, align 2)
+    ; CHECK-NEXT: RET_ReallyLR
+    %0:_(p0) = COPY $x0
+    %1:_(p0) = COPY $x1
+    %2:_(i64) = G_CONSTANT i64 3
+    G_MEMMOVE %0(p0), %1(p0), %2(i64), 0 :: (store (s8), align 8), (load (s8), align 8)
+    RET_ReallyLR
+
+...
+---
+name:            test_memmove_load_store_offsets_2
+alignment:       4
+tracksRegLiveness: true
+body:             |
+  bb.0.entry:
+    liveins: $x0, $x1
+
+    ; CHECK-LABEL: name: test_memmove_load_store_offsets_2
+    ; CHECK: liveins: $x0, $x1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $x0
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(p0) = COPY $x1
+    ; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(i32) = G_LOAD [[COPY1]](p0) :: (load (s32), align 8)
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 3
+    ; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[COPY1]], [[C]](s64)
+    ; CHECK-NEXT: [[LOAD1:%[0-9]+]]:_(i32) = G_LOAD [[PTR_ADD]](p0) :: (load (s32) from unknown-address + 3, align 1)
+    ; CHECK-NEXT: G_STORE [[LOAD]](i32), [[COPY]](p0) :: (store (s32), align 8)
+    ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 3
+    ; CHECK-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[COPY]], [[C1]](s64)
+    ; CHECK-NEXT: G_STORE [[LOAD1]](i32), [[PTR_ADD1]](p0) :: (store (s32) into unknown-address + 3, align 1)
+    ; CHECK-NEXT: RET_ReallyLR
+    %0:_(p0) = COPY $x0
+    %1:_(p0) = COPY $x1
+    %2:_(i64) = G_CONSTANT i64 7
+    G_MEMMOVE %0(p0), %1(p0), %2(i64), 0 :: (store (s8), align 8), (load (s8), align 8)
+    RET_ReallyLR
+
+...
+---
+name:            test_memmove_load_store_offsets_volatile_1
+alignment:       4
+tracksRegLiveness: true
+body:             |
+  bb.0.entry:
+    liveins: $x0, $x1
+
+    ; CHECK-LABEL: name: test_memmove_load_store_offsets_volatile_1
+    ; CHECK: liveins: $x0, $x1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $x0
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(p0) = COPY $x1
+    ; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(i16) = G_LOAD [[COPY1]](p0) :: (volatile load (s16), align 8)
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 2
+    ; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[COPY1]], [[C]](s64)
+    ; CHECK-NEXT: [[LOAD1:%[0-9]+]]:_(i8) = G_LOAD [[PTR_ADD]](p0) :: (volatile load (s8) from unknown-address + 2, align 2)
+    ; CHECK-NEXT: G_STORE [[LOAD]](i16), [[COPY]](p0) :: (volatile store (s16), align 8)
+    ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 2
+    ; CHECK-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[COPY]], [[C1]](s64)
+    ; CHECK-NEXT: G_STORE [[LOAD1]](i8), [[PTR_ADD1]](p0) :: (volatile store (s8) into unknown-address + 2, align 2)
+    ; CHECK-NEXT: RET_ReallyLR
+    %0:_(p0) = COPY $x0
+    %1:_(p0) = COPY $x1
+    %2:_(i64) = G_CONSTANT i64 3
+    G_MEMMOVE %0(p0), %1(p0), %2(i64), 0 :: (volatile store (s8), align 8), (volatile load (s8), align 8)
+    RET_ReallyLR
+
+...
+---
+name:            test_memmove_load_store_offsets_volatile_2
+alignment:       4
+tracksRegLiveness: true
+body:             |
+  bb.0.entry:
+    liveins: $x0, $x1
+
+    ; CHECK-LABEL: name: test_memmove_load_store_offsets_volatile_2
+    ; CHECK: liveins: $x0, $x1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $x0
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(p0) = COPY $x1
+    ; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(i32) = G_LOAD [[COPY1]](p0) :: (volatile load (s32), align 8)
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
+    ; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[COPY1]], [[C]](s64)
+    ; CHECK-NEXT: [[LOAD1:%[0-9]+]]:_(i16) = G_LOAD [[PTR_ADD]](p0) :: (volatile load (s16) from unknown-address + 4, align 4)
+    ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 6
+    ; CHECK-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[COPY1]], [[C1]](s64)
+    ; CHECK-NEXT: [[LOAD2:%[0-9]+]]:_(i8) = G_LOAD [[PTR_ADD1]](p0) :: (volatile load (s8) from unknown-address + 6, align 2)
+    ; CHECK-NEXT: G_STORE [[LOAD]](i32), [[COPY]](p0) :: (volatile store (s32), align 8)
+    ; CHECK-NEXT: [[C2:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
+    ; CHECK-NEXT: [[PTR_ADD2:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[COPY]], [[C2]](s64)
+    ; CHECK-NEXT: G_STORE [[LOAD1]](i16), [[PTR_ADD2]](p0) :: (volatile store (s16) into unknown-address + 4, align 4)
+    ; CHECK-NEXT: [[C3:%[0-9]+]]:_(s64) = G_CONSTANT i64 6
+    ; CHECK-NEXT: [[PTR_ADD3:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[COPY]], [[C3]](s64)
+    ; CHECK-NEXT: G_STORE [[LOAD2]](i8), [[PTR_ADD3]](p0) :: (volatile store (s8) into unknown-address + 6, align 2)
+    ; CHECK-NEXT: RET_ReallyLR
+    %0:_(p0) = COPY $x0
+    %1:_(p0) = COPY $x1
+    %2:_(i64) = G_CONSTANT i64 7
+    G_MEMMOVE %0(p0), %1(p0), %2(i64), 0 :: (volatile store (s8), align 8), (volatile load (s8), align 8)
+    RET_ReallyLR
+...



More information about the llvm-commits mailing list