[llvm] [LICM] Rewrite noConflictingReadWrites to walk MemorySSA graph (PR #191468)

via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 13 02:44:27 PDT 2026


================
@@ -2319,54 +2319,77 @@ static bool noConflictingReadWrites(Instruction *I, MemorySSA *MSSA,
   if (!MSSA->isLiveOnEntryDef(Source) && CurLoop->contains(Source->getBlock()))
     return false;
 
-  // If there are interfering Uses (i.e. their defining access is in the
-  // loop), or ordered loads (stored as Defs!), don't move this store.
-  // Could do better here, but this is conservatively correct.
-  // TODO: Cache set of Uses on the first walk in runOnLoop, update when
-  // moving accesses. Can also extend to dominating uses.
-  for (auto *BB : CurLoop->getBlocks()) {
-    auto *Accesses = MSSA->getBlockAccesses(BB);
-    if (!Accesses)
-      continue;
-    for (const auto &MA : *Accesses)
-      if (const auto *MU = dyn_cast<MemoryUse>(&MA)) {
-        auto *MD = getClobberingMemoryAccess(*MSSA, BAA, Flags,
-                                             const_cast<MemoryUse *>(MU));
-        if (!MSSA->isLiveOnEntryDef(MD) && CurLoop->contains(MD->getBlock()))
-          return false;
-        // Disable hoisting past potentially interfering loads. Optimized
-        // Uses may point to an access outside the loop, as getClobbering
-        // checks the previous iteration when walking the backedge.
-        // FIXME: More precise: no Uses that alias I.
-        if (!Flags.getIsSink() && !MSSA->dominates(IMD, MU))
-          return false;
-      } else if (const auto *MD = dyn_cast<MemoryDef>(&MA)) {
+  // Walk the MemorySSA graph from the loop header's MemoryPhi.  Every
+  // MemoryDef and (in optimized MSSA) every aliasing MemoryUse in the loop
+  // is reachable through the users of the MemoryPhi and loop-internal defs.
+  auto *HeaderPhi = MSSA->getMemoryAccess(CurLoop->getHeader());
+  if (!HeaderPhi)
+    return true;
+
+  SmallVector<const MemoryAccess *, 8> Worklist;
+  SmallPtrSet<const MemoryAccess *, 8> Visited;
+  Worklist.push_back(HeaderPhi);
+  Visited.insert(HeaderPhi);
+
+  while (!Worklist.empty()) {
+    const MemoryAccess *MA = Worklist.pop_back_val();
+    for (const User *U : MA->users()) {
+      const auto *UserMA = cast<MemoryAccess>(U);
+      if (!Visited.insert(UserMA).second)
+        continue;
+      // Skip accesses outside the loop (e.g., LCSSA phi users).
+      if (!CurLoop->contains(UserMA->getBlock()))
+        continue;
+
+      if (const auto *MU = dyn_cast<MemoryUse>(UserMA)) {
+        // If this use's defining access is IMD, it reads the location I
----------------
CarolineConcatto wrote:

Just in case, could we do something like this:

```
    if (const auto *MU = dyn_cast<MemoryUse>(UserMA)) {
         auto *MD = getClobberingMemoryAccess(*MSSA, BAA, Flags,                                           const_cast<MemoryUse *>(MU));
         if (!MSSA->isLiveOnEntryDef(MD)) {
             auto *MDI = dyn_cast_or_null<MemoryDef>(MD);
             if (!MDI || MDI->getMemoryInst() != I)
                return false;
          }
    }
```
For the memory uses, according to what I understand the  getClobberingMemoryAccess check has similar intention as the checks  added bellow for call and store

https://github.com/llvm/llvm-project/pull/191468


More information about the llvm-commits mailing list