[llvm] [LLVM] Refine MemoryEffect handling for target-specific intrinsics (PR #155590)

via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 24 06:16:26 PST 2026


https://github.com/CarolineConcatto updated https://github.com/llvm/llvm-project/pull/155590

>From 4f8bcc20b5e09554eda5e72141e2efc5f3fe9c06 Mon Sep 17 00:00:00 2001
From: CarolineConcatto <caroline.concatto at arm.com>
Date: Fri, 31 Oct 2025 16:26:46 +0000
Subject: [PATCH 1/3] [Draft][LLVM]Extend memory effects for memory alias
 analysis

This patch improves memory alias analysis between calls if they
change the target memory.

If both calls dont clobber the same location it can return without
setting ModeRefInfo among them. Otherwise it relies in the default
behaviour to set ModRefInfo to Read and Write.
---
 llvm/include/llvm/IR/InstrTypes.h             |  1 +
 llvm/include/llvm/Support/ModRef.h            |  7 ++
 llvm/lib/Analysis/MemorySSA.cpp               | 29 +++++++
 llvm/lib/IR/Instructions.cpp                  |  5 ++
 .../test/Transforms/EarlyCSE/target-memory.ll | 80 +++++++++++++++++++
 5 files changed, 122 insertions(+)
 create mode 100644 llvm/test/Transforms/EarlyCSE/target-memory.ll

diff --git a/llvm/include/llvm/IR/InstrTypes.h b/llvm/include/llvm/IR/InstrTypes.h
index 7aea805e0b86b..2198dec3d71ff 100644
--- a/llvm/include/llvm/IR/InstrTypes.h
+++ b/llvm/include/llvm/IR/InstrTypes.h
@@ -1936,6 +1936,7 @@ class CallBase : public Instruction {
   /// inaccessible from the IR.
   LLVM_ABI bool onlyAccessesInaccessibleMemory() const;
   LLVM_ABI void setOnlyAccessesInaccessibleMemory();
+  LLVM_ABI bool onlyAccessesTargetMemory() const;
 
   /// Determine if the function may only access memory that is
   /// either inaccessible from the IR or pointed to by its arguments.
diff --git a/llvm/include/llvm/Support/ModRef.h b/llvm/include/llvm/Support/ModRef.h
index 34f116e478966..86e0394593846 100644
--- a/llvm/include/llvm/Support/ModRef.h
+++ b/llvm/include/llvm/Support/ModRef.h
@@ -240,6 +240,13 @@ template <typename LocationEnum> class MemoryEffectsBase {
     return getWithoutLoc(Location::InaccessibleMem).doesNotAccessMemory();
   }
 
+  /// Whether this function only (at most) accesses target  memory.
+  bool onlyAccessesTargetMem() const {
+    return getWithoutLoc(Location::TargetMem0)
+        .getWithoutLoc(Location::TargetMem1)
+        .doesNotAccessMemory();
+  }
+
   /// Whether this function only (at most) accesses errno memory.
   bool onlyAccessesErrnoMem() const {
     return getWithoutLoc(Location::ErrnoMem).doesNotAccessMemory();
diff --git a/llvm/lib/Analysis/MemorySSA.cpp b/llvm/lib/Analysis/MemorySSA.cpp
index 4f03080d9af67..088c1e4530963 100644
--- a/llvm/lib/Analysis/MemorySSA.cpp
+++ b/llvm/lib/Analysis/MemorySSA.cpp
@@ -277,6 +277,30 @@ static bool areLoadsReorderable(const LoadInst *Use,
   return !(SeqCstUse || MayClobberIsAcquire);
 }
 
+bool writeToSameTargetMemLoc(const CallBase *CallFirst,
+                             const CallBase *CallSecond) {
+  MemoryEffects ME1 = CallFirst->getMemoryEffects();
+  MemoryEffects ME2 = CallSecond->getMemoryEffects();
+
+  auto writes = [](ModRefInfo m) {
+    return m != ModRefInfo::NoModRef && m != ModRefInfo::Ref;
+  };
+
+  for (unsigned ILoc = static_cast<unsigned>(IRMemLocation::FirstTarget);
+       ILoc <= static_cast<unsigned>(IRMemLocation::Last); ++ILoc) {
+    const auto Loc = static_cast<IRMemLocation>(ILoc);
+
+    if (!writes(ME1.getModRef(Loc)))
+      continue;
+    if (!writes(ME2.getModRef(Loc)))
+      continue;
+
+    // Both have write capability to the same location.
+    return true;
+  }
+  return false;
+}
+
 template <typename AliasAnalysisType>
 static bool
 instructionClobbersQuery(const MemoryDef *MD, const MemoryLocation &UseLoc,
@@ -311,6 +335,11 @@ instructionClobbersQuery(const MemoryDef *MD, const MemoryLocation &UseLoc,
   }
 
   if (auto *CB = dyn_cast_or_null<CallBase>(UseInst)) {
+    if (auto *CU = dyn_cast_or_null<CallBase>(DefInst))
+      if (CU->onlyAccessesTargetMemory() || CB->onlyAccessesTargetMemory()) {
+        if (!writeToSameTargetMemLoc(CB, CU))
+          return false;
+      }
     ModRefInfo I = AA.getModRefInfo(DefInst, CB);
     return isModSet(I);
   }
diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
index 52b6c35e18d95..7a6a717764702 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -690,6 +690,11 @@ void CallBase::setOnlyAccessesArgMemory() {
 bool CallBase::onlyAccessesInaccessibleMemory() const {
   return getMemoryEffects().onlyAccessesInaccessibleMem();
 }
+
+bool CallBase::onlyAccessesTargetMemory() const {
+  return getMemoryEffects().onlyAccessesTargetMem();
+}
+
 void CallBase::setOnlyAccessesInaccessibleMemory() {
   setMemoryEffects(getMemoryEffects() & MemoryEffects::inaccessibleMemOnly());
 }
diff --git a/llvm/test/Transforms/EarlyCSE/target-memory.ll b/llvm/test/Transforms/EarlyCSE/target-memory.ll
new file mode 100644
index 0000000000000..1d6235f97aa01
--- /dev/null
+++ b/llvm/test/Transforms/EarlyCSE/target-memory.ll
@@ -0,0 +1,80 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -S -passes='early-cse<memssa>' < %s | FileCheck %s
+
+define void @foo(){
+; CHECK-LABEL: define void @foo() {
+; CHECK-NEXT:    call void @fn_write_target1()
+; CHECK-NEXT:    call void @fn_readwrite_target0_read_target1()
+; CHECK-NEXT:    call void @fn_readwrite_target0_read_target1()
+; CHECK-NEXT:    ret void
+;
+  call void @fn_write_target1()
+  call void @fn_readwrite_target0_read_target1()
+  call void @fn_write_target1()
+  call void @fn_readwrite_target0_read_target1()
+  ret void
+}
+
+define void @goo(){
+; CHECK-LABEL: define void @goo() {
+; CHECK-NEXT:    call void @fn_read_target0_read_target1()
+; CHECK-NEXT:    call void @fn_read_target0()
+; CHECK-NEXT:    call void @fn_read_target0_read_target1()
+; CHECK-NEXT:    call void @fn_read_target0_read_target1()
+; CHECK-NEXT:    ret void
+;
+  call void @fn_read_target0_read_target1()
+  call void @fn_read_target0()
+  call void @fn_read_target0_read_target1()
+  call void @fn_read_target0()
+  call void @fn_read_target0_read_target1()
+  ret void
+}
+
+;; In this case the clobber function is not even called
+define void @neg_foo(){
+; CHECK-LABEL: define void @neg_foo() {
+; CHECK-NEXT:    call void @fn_readwrite_target0_read_target1()
+; CHECK-NEXT:    call void @fn_read_target0_readwrite_target1()
+; CHECK-NEXT:    call void @fn_readwrite_target0_read_target1()
+; CHECK-NEXT:    call void @fn_read_target0_readwrite_target1()
+; CHECK-NEXT:    ret void
+;
+  call void @fn_readwrite_target0_read_target1()
+  call void @fn_read_target0_readwrite_target1()
+  call void @fn_readwrite_target0_read_target1()
+  call void @fn_read_target0_readwrite_target1()
+  ret void
+}
+
+define void @foo_neg_foo(){
+; CHECK-LABEL: define void @foo_neg_foo() {
+; CHECK-NEXT:    call void @fn_write_target1()
+; CHECK-NEXT:    call void @fn_readwrite_target0_read_target1()
+; CHECK-NEXT:    call void @neg_foo()
+; CHECK-NEXT:    call void @fn_write_target1()
+; CHECK-NEXT:    call void @fn_readwrite_target0_read_target1()
+; CHECK-NEXT:    ret void
+;
+  call void @fn_write_target1()
+  call void @fn_readwrite_target0_read_target1()
+  call void @neg_foo()
+  call void @fn_write_target1()
+  call void @fn_readwrite_target0_read_target1()
+  ret void
+}
+
+declare void @fn_write_target1()
+  memory(target_mem1:  write)
+
+declare void @fn_read_target0_read_target1()
+  memory(target_mem0: readwrite, target_mem1: read)
+
+declare void @fn_read_target0()
+  memory( target_mem0: read)
+
+declare void @fn_read_target0_readwrite_target1()
+  memory(target_mem0: read, target_mem1: readwrite)
+
+declare void @fn_readwrite_target0_read_target1()
+  memory(target_mem0: readwrite, target_mem1: read)

>From 5ad3dcffd6217fe2536253cf35372a3a479b87a5 Mon Sep 17 00:00:00 2001
From: CarolineConcatto <caroline.concatto at arm.com>
Date: Thu, 20 Nov 2025 16:42:28 +0000
Subject: [PATCH 2/3] Improve code for writeToSameTargetMemLoc

---
 llvm/lib/Analysis/MemorySSA.cpp | 29 +++++++----------------------
 1 file changed, 7 insertions(+), 22 deletions(-)

diff --git a/llvm/lib/Analysis/MemorySSA.cpp b/llvm/lib/Analysis/MemorySSA.cpp
index 088c1e4530963..1a444ec543a70 100644
--- a/llvm/lib/Analysis/MemorySSA.cpp
+++ b/llvm/lib/Analysis/MemorySSA.cpp
@@ -279,26 +279,13 @@ static bool areLoadsReorderable(const LoadInst *Use,
 
 bool writeToSameTargetMemLoc(const CallBase *CallFirst,
                              const CallBase *CallSecond) {
+
   MemoryEffects ME1 = CallFirst->getMemoryEffects();
   MemoryEffects ME2 = CallSecond->getMemoryEffects();
-
-  auto writes = [](ModRefInfo m) {
-    return m != ModRefInfo::NoModRef && m != ModRefInfo::Ref;
-  };
-
-  for (unsigned ILoc = static_cast<unsigned>(IRMemLocation::FirstTarget);
-       ILoc <= static_cast<unsigned>(IRMemLocation::Last); ++ILoc) {
-    const auto Loc = static_cast<IRMemLocation>(ILoc);
-
-    if (!writes(ME1.getModRef(Loc)))
-      continue;
-    if (!writes(ME2.getModRef(Loc)))
-      continue;
-
-    // Both have write capability to the same location.
-    return true;
-  }
-  return false;
+  if (CallFirst->onlyAccessesTargetMemory() ||
+      CallSecond->onlyAccessesTargetMemory())
+    return !(ME1 & ME2 & MemoryEffects::writeOnly()).onlyReadsMemory();
+  return true;
 }
 
 template <typename AliasAnalysisType>
@@ -336,10 +323,8 @@ instructionClobbersQuery(const MemoryDef *MD, const MemoryLocation &UseLoc,
 
   if (auto *CB = dyn_cast_or_null<CallBase>(UseInst)) {
     if (auto *CU = dyn_cast_or_null<CallBase>(DefInst))
-      if (CU->onlyAccessesTargetMemory() || CB->onlyAccessesTargetMemory()) {
-        if (!writeToSameTargetMemLoc(CB, CU))
-          return false;
-      }
+      if (!writeToSameTargetMemLoc(CB, CU))
+        return false;
     ModRefInfo I = AA.getModRefInfo(DefInst, CB);
     return isModSet(I);
   }

>From b909b5011bf93808e4639178b325dbe7ffb1d96f Mon Sep 17 00:00:00 2001
From: CarolineConcatto <caroline.concatto at arm.com>
Date: Tue, 3 Feb 2026 13:13:58 +0000
Subject: [PATCH 3/3] Move changes to Alias Analysis as suggested

---
 llvm/include/llvm/IR/InstrTypes.h             |  1 -
 llvm/include/llvm/Support/ModRef.h            | 18 ++--
 llvm/lib/Analysis/AliasAnalysis.cpp           | 29 +++++++
 llvm/lib/Analysis/MemorySSA.cpp               | 14 ---
 llvm/lib/IR/Instructions.cpp                  |  5 --
 .../test/Transforms/EarlyCSE/target-memory.ll | 85 ++++++++++++++-----
 6 files changed, 103 insertions(+), 49 deletions(-)

diff --git a/llvm/include/llvm/IR/InstrTypes.h b/llvm/include/llvm/IR/InstrTypes.h
index 2198dec3d71ff..7aea805e0b86b 100644
--- a/llvm/include/llvm/IR/InstrTypes.h
+++ b/llvm/include/llvm/IR/InstrTypes.h
@@ -1936,7 +1936,6 @@ class CallBase : public Instruction {
   /// inaccessible from the IR.
   LLVM_ABI bool onlyAccessesInaccessibleMemory() const;
   LLVM_ABI void setOnlyAccessesInaccessibleMemory();
-  LLVM_ABI bool onlyAccessesTargetMemory() const;
 
   /// Determine if the function may only access memory that is
   /// either inaccessible from the IR or pointed to by its arguments.
diff --git a/llvm/include/llvm/Support/ModRef.h b/llvm/include/llvm/Support/ModRef.h
index 86e0394593846..f71c287778f83 100644
--- a/llvm/include/llvm/Support/ModRef.h
+++ b/llvm/include/llvm/Support/ModRef.h
@@ -73,7 +73,6 @@ enum class IRMemLocation {
   /// Helpers to iterate all locations in the MemoryEffectsBase class.
   First = ArgMem,
   FirstTarget = TargetMem0,
-  // TargetMem IDs must be at the end of the list.
   Last = TargetMem1,
 };
 
@@ -105,6 +104,11 @@ template <typename LocationEnum> class MemoryEffectsBase {
                               force_iteration_on_noniterable_enum);
   }
 
+  static auto targetMemLocations() {
+    return enum_seq_inclusive(Location::TargetMem0, Location::TargetMem1,
+                              force_iteration_on_noniterable_enum);
+  }
+
   /// Create MemoryEffectsBase that can access only the given location with the
   /// given ModRefInfo.
   MemoryEffectsBase(Location Loc, ModRefInfo MR) { setModRef(Loc, MR); }
@@ -240,11 +244,13 @@ template <typename LocationEnum> class MemoryEffectsBase {
     return getWithoutLoc(Location::InaccessibleMem).doesNotAccessMemory();
   }
 
-  /// Whether this function only (at most) accesses target  memory.
-  bool onlyAccessesTargetMem() const {
-    return getWithoutLoc(Location::TargetMem0)
-        .getWithoutLoc(Location::TargetMem1)
-        .doesNotAccessMemory();
+  /// Whether this function only (at most) accesses inaccessible or target
+  /// memory.
+  bool onlyAccessesInaccessibleOrTargetMem() const {
+    MemoryEffectsBase ME = *this;
+    for (auto Loc : MemoryEffectsBase::targetMemLocations())
+      ME &= ME.getWithoutLoc(Loc);
+    return ME.getWithoutLoc(Location::InaccessibleMem).doesNotAccessMemory();
   }
 
   /// Whether this function only (at most) accesses errno memory.
diff --git a/llvm/lib/Analysis/AliasAnalysis.cpp b/llvm/lib/Analysis/AliasAnalysis.cpp
index 26a560252d9aa..102f0c070d517 100644
--- a/llvm/lib/Analysis/AliasAnalysis.cpp
+++ b/llvm/lib/Analysis/AliasAnalysis.cpp
@@ -244,6 +244,29 @@ ModRefInfo AAResults::getModRefInfo(const CallBase *Call,
   return Result;
 }
 
+ModRefInfo
+getModRefInfoInaccessibleAndTargetMemLoc(const MemoryEffects CallUse,
+                                         const MemoryEffects CallDef) {
+
+  ModRefInfo Result = ModRefInfo::NoModRef;
+  auto addModRefInfoForLoc = [&](IRMemLocation L) {
+    ModRefInfo UseMR = CallUse.getModRef(L);
+    if (UseMR == ModRefInfo::NoModRef)
+      return;
+    ModRefInfo DefMR = CallDef.getModRef(L);
+    if (DefMR == ModRefInfo::NoModRef)
+      return;
+    if (DefMR == ModRefInfo::Ref && DefMR == UseMR)
+      return;
+    Result |= UseMR;
+  };
+
+  addModRefInfoForLoc(IRMemLocation::InaccessibleMem);
+  for (auto Loc : MemoryEffects::targetMemLocations())
+    addModRefInfoForLoc(Loc);
+  return Result;
+}
+
 ModRefInfo AAResults::getModRefInfo(const CallBase *Call1,
                                     const CallBase *Call2, AAQueryInfo &AAQI) {
   ModRefInfo Result = ModRefInfo::ModRef;
@@ -348,6 +371,12 @@ ModRefInfo AAResults::getModRefInfo(const CallBase *Call1,
     return R;
   }
 
+  // If only Inaccessible and Target Memory Location have set ModRefInfo
+  // then check the relation between the same locations.
+  if (Call1B.onlyAccessesInaccessibleOrTargetMem() &&
+      Call2B.onlyAccessesInaccessibleOrTargetMem())
+    return getModRefInfoInaccessibleAndTargetMemLoc(Call1B, Call2B);
+
   return Result;
 }
 
diff --git a/llvm/lib/Analysis/MemorySSA.cpp b/llvm/lib/Analysis/MemorySSA.cpp
index 1a444ec543a70..4f03080d9af67 100644
--- a/llvm/lib/Analysis/MemorySSA.cpp
+++ b/llvm/lib/Analysis/MemorySSA.cpp
@@ -277,17 +277,6 @@ static bool areLoadsReorderable(const LoadInst *Use,
   return !(SeqCstUse || MayClobberIsAcquire);
 }
 
-bool writeToSameTargetMemLoc(const CallBase *CallFirst,
-                             const CallBase *CallSecond) {
-
-  MemoryEffects ME1 = CallFirst->getMemoryEffects();
-  MemoryEffects ME2 = CallSecond->getMemoryEffects();
-  if (CallFirst->onlyAccessesTargetMemory() ||
-      CallSecond->onlyAccessesTargetMemory())
-    return !(ME1 & ME2 & MemoryEffects::writeOnly()).onlyReadsMemory();
-  return true;
-}
-
 template <typename AliasAnalysisType>
 static bool
 instructionClobbersQuery(const MemoryDef *MD, const MemoryLocation &UseLoc,
@@ -322,9 +311,6 @@ instructionClobbersQuery(const MemoryDef *MD, const MemoryLocation &UseLoc,
   }
 
   if (auto *CB = dyn_cast_or_null<CallBase>(UseInst)) {
-    if (auto *CU = dyn_cast_or_null<CallBase>(DefInst))
-      if (!writeToSameTargetMemLoc(CB, CU))
-        return false;
     ModRefInfo I = AA.getModRefInfo(DefInst, CB);
     return isModSet(I);
   }
diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
index 7a6a717764702..52b6c35e18d95 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -690,11 +690,6 @@ void CallBase::setOnlyAccessesArgMemory() {
 bool CallBase::onlyAccessesInaccessibleMemory() const {
   return getMemoryEffects().onlyAccessesInaccessibleMem();
 }
-
-bool CallBase::onlyAccessesTargetMemory() const {
-  return getMemoryEffects().onlyAccessesTargetMem();
-}
-
 void CallBase::setOnlyAccessesInaccessibleMemory() {
   setMemoryEffects(getMemoryEffects() & MemoryEffects::inaccessibleMemOnly());
 }
diff --git a/llvm/test/Transforms/EarlyCSE/target-memory.ll b/llvm/test/Transforms/EarlyCSE/target-memory.ll
index 1d6235f97aa01..74fda76e1c22b 100644
--- a/llvm/test/Transforms/EarlyCSE/target-memory.ll
+++ b/llvm/test/Transforms/EarlyCSE/target-memory.ll
@@ -15,21 +15,6 @@ define void @foo(){
   ret void
 }
 
-define void @goo(){
-; CHECK-LABEL: define void @goo() {
-; CHECK-NEXT:    call void @fn_read_target0_read_target1()
-; CHECK-NEXT:    call void @fn_read_target0()
-; CHECK-NEXT:    call void @fn_read_target0_read_target1()
-; CHECK-NEXT:    call void @fn_read_target0_read_target1()
-; CHECK-NEXT:    ret void
-;
-  call void @fn_read_target0_read_target1()
-  call void @fn_read_target0()
-  call void @fn_read_target0_read_target1()
-  call void @fn_read_target0()
-  call void @fn_read_target0_read_target1()
-  ret void
-}
 
 ;; In this case the clobber function is not even called
 define void @neg_foo(){
@@ -47,8 +32,8 @@ define void @neg_foo(){
   ret void
 }
 
-define void @foo_neg_foo(){
-; CHECK-LABEL: define void @foo_neg_foo() {
+define void @neg_foo_call(){
+; CHECK-LABEL: define void @neg_foo_call() {
 ; CHECK-NEXT:    call void @fn_write_target1()
 ; CHECK-NEXT:    call void @fn_readwrite_target0_read_target1()
 ; CHECK-NEXT:    call void @neg_foo()
@@ -64,17 +49,71 @@ define void @foo_neg_foo(){
   ret void
 }
 
-declare void @fn_write_target1()
-  memory(target_mem1:  write)
 
-declare void @fn_read_target0_read_target1()
-  memory(target_mem0: readwrite, target_mem1: read)
+define void @neg_foo_x(i64 %x, i64 %y){
+; CHECK-LABEL: define void @neg_foo_x(
+; CHECK-SAME: i64 [[X:%.*]], i64 [[Y:%.*]]) {
+; CHECK-NEXT:    call void @fn_write_target1_x(i64 [[X]])
+; CHECK-NEXT:    call void @fn_readwrite_target0_read_target1_x(i64 [[X]])
+; CHECK-NEXT:    call void @fn_write_target1_x(i64 [[Y]])
+; CHECK-NEXT:    call void @fn_readwrite_target0_read_target1_x(i64 [[X]])
+; CHECK-NEXT:    ret void
+;
+  call void @fn_write_target1_x(i64 %x)
+  call void @fn_readwrite_target0_read_target1_x(i64 %x)
+  call void @fn_write_target1_x(i64 %y)
+  call void @fn_readwrite_target0_read_target1_x(i64 %x)
+  ret void
+}
 
-declare void @fn_read_target0()
-  memory( target_mem0: read)
+define void @f1(i64 %x, i64 %y){
+; CHECK-LABEL: define void @f1(
+; CHECK-SAME: i64 [[X:%.*]], i64 [[Y:%.*]]) {
+; CHECK-NEXT:    call void @fn_read_target1()
+; CHECK-NEXT:    call void @fn_readwrite_target0_read_target1()
+; CHECK-NEXT:    call void @fn_readwrite_target0_read_target1()
+; CHECK-NEXT:    ret void
+;
+  call void @fn_read_target1()
+  call void @fn_readwrite_target0_read_target1()
+  call void @fn_read_target1()
+  call void @fn_readwrite_target0_read_target1()
+  ret void
+}
+
+define void @bar(){
+; CHECK-LABEL: define void @bar() {
+; CHECK-NEXT:    call void @fn_write_target1()
+; CHECK-NEXT:    call void @fn_write_inaccessiblemem()
+; CHECK-NEXT:    call void @fn_read_inaccessiblemem()
+; CHECK-NEXT:    ret void
+;
+  call void @fn_write_target1()
+  call void @fn_write_inaccessiblemem()
+  call void @fn_write_target1()
+  call void @fn_read_inaccessiblemem()
+  ret void
+}
+
+declare void @fn_write_target1()
+  memory(target_mem1: write)
+declare void @fn_read_target1()
+  memory(target_mem1: read)
 
 declare void @fn_read_target0_readwrite_target1()
   memory(target_mem0: read, target_mem1: readwrite)
 
+declare void @fn_read_inaccessiblemem()
+  memory(inaccessiblemem: read)
+declare void @fn_write_inaccessiblemem()
+  memory(inaccessiblemem: write)
+
+
 declare void @fn_readwrite_target0_read_target1()
   memory(target_mem0: readwrite, target_mem1: read)
+
+declare void @fn_write_target1_x(i64)
+  memory(target_mem1:  write)
+
+declare void @fn_readwrite_target0_read_target1_x(i64)
+  memory(target_mem0: readwrite, target_mem1: read)



More information about the llvm-commits mailing list