[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