I have to stare at this. <br><br><div class="gmail_quote"><div dir="ltr">On Fri, Jul 29, 2016, 7:10 PM Sebastian Pop <<a href="mailto:sebpop@gmail.com">sebpop@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">sebpop updated this revision to Diff 66212.<br>
sebpop added a comment.<br>
<br>
Updated the patch as I first wrote it: I think this is the natural way to update an SSA variable.<br>
<br>
This fails because when invoking:<br>
+ MSSA->removeMemoryAccess(OldMemAcc);<br>
<br>
we go from:<br>
; MemoryUse(2)<br>
<br>
%2 = load i32, i32* %v.addr, align 4<br>
<br>
to no annotation at all:<br>
<br>
%2 = load i32, i32* %v.addr, align 4<br>
<br>
This is because removeMemoryAccess calls removeFromLookups which does:<br>
<br>
Value *MemoryInst;<br>
if (MemoryUseOrDef *MUD = dyn_cast<MemoryUseOrDef>(MA)) {<br>
MemoryInst = MUD->getMemoryInst();<br>
} else {<br>
MemoryInst = MA->getBlock();<br>
}<br>
ValueToMemoryAccess.erase(MemoryInst);<br>
<br>
and erase() removes both the new and old MemoryAccess'es leaving the instruction without MSSA annotation.<br></blockquote></div><div><br></div><div>Yes, only one memory access can exist for an instruction for real. You can't create two at once and get the right result.</div><div><br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
For loads this can be fixed by first removing the OldMemoryAccess and then creating the NewMemoryAccess.<br>
This works for loads because there are no users of a MemoryUse.<br>
However for a store, we need to keep both the old and new MemoryAccess'es at the same time, to be able to rename the uses of old with new.<br></blockquote></div><div><br></div><div>Yes, most of the hoisters are cloning, so do not have this issue.</div><div><br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
I think the solution would be for "MSSA->removeMemoryAccess(OldMemAcc);" to only invalidate and remove "OldMemAcc" without touching "NewMemAcc" that should remain attached to the instruction.<br></blockquote></div><div><br></div><div>We can't make it work with two memoryacceses for the same instruction at once.</div><div><br></div><div>We can probably implement either a createReplacement (that takes over the uses of the old one) or a moveBefore/moveAfter.</div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
<br>
<a href="https://reviews.llvm.org/D22966" rel="noreferrer" target="_blank">https://reviews.llvm.org/D22966</a><br>
<br>
Files:<br>
lib/Transforms/Scalar/GVNHoist.cpp<br>
<br>
Index: lib/Transforms/Scalar/GVNHoist.cpp<br>
===================================================================<br>
--- lib/Transforms/Scalar/GVNHoist.cpp<br>
+++ lib/Transforms/Scalar/GVNHoist.cpp<br>
@@ -193,30 +193,27 @@<br>
VN.setAliasAnalysis(AA);<br>
VN.setMemDep(MD);<br>
bool Res = false;<br>
+ MemorySSA M(F, AA, DT);<br>
+ MSSA = &M;<br>
<br>
// FIXME: use lazy evaluation of VN to avoid the fix-point computation.<br>
while (1) {<br>
- // FIXME: only compute MemorySSA once. We need to update the analysis in<br>
- // the same time as transforming the code.<br>
- MemorySSA M(F, AA, DT);<br>
- MSSA = &M;<br>
-<br>
// Perform DFS Numbering of instructions.<br>
unsigned I = 0;<br>
for (const BasicBlock *BB : depth_first(&F.getEntryBlock()))<br>
for (auto &Inst: *BB)<br>
DFSNumber.insert({&Inst, ++I});<br>
<br>
auto HoistStat = hoistExpressions(F);<br>
- if (HoistStat.first + HoistStat.second == 0) {<br>
+ if (HoistStat.first + HoistStat.second == 0)<br>
return Res;<br>
- }<br>
- if (HoistStat.second > 0) {<br>
+<br>
+ if (HoistStat.second > 0)<br>
// To address a limitation of the current GVN, we need to rerun the<br>
- // hoisting after we hoisted loads in order to be able to hoist all<br>
- // scalars dependent on the hoisted loads. Same for stores.<br>
+ // hoisting after we hoisted loads or stores in order to be able to<br>
+ // hoist all scalars dependent on the hoisted ld/st.<br>
VN.clear();<br>
- }<br>
+<br>
Res = true;<br>
<br>
// DFS numbers change when instructions are hoisted: clear and recompute.<br>
@@ -725,6 +722,8 @@<br>
if (!Repl || firstInBB(I, Repl))<br>
Repl = I;<br>
<br>
+ MemoryAccess *NewMemAcc = nullptr;<br>
+<br>
if (Repl) {<br>
// Repl is already in HoistPt: it remains in place.<br>
assert(allOperandsAvailable(Repl, HoistPt) &&<br>
@@ -742,7 +741,23 @@<br>
!makeGepOperandsAvailable(Repl, HoistPt, InstructionsToHoist))<br>
continue;<br>
<br>
+ // Before moving the instruction, get its MSSA access.<br>
+ MemoryUseOrDef *OldMemAcc = nullptr;<br>
+ if (MemoryAccess *MA = MSSA->getMemoryAccess(Repl))<br>
+ OldMemAcc = dyn_cast<MemoryUseOrDef>(MA);<br>
+<br>
+ // Move the instruction at the end of HoistPt.<br>
Repl->moveBefore(HoistPt->getTerminator());<br>
+<br>
+ if (OldMemAcc) {<br>
+ // The definition of this ld/st will not change: ld/st hoisting is<br>
+ // legal when the ld/st is not moved past its current definition.<br>
+ MemoryAccess *Def = OldMemAcc->getDefiningAccess();<br>
+ NewMemAcc = MSSA->createMemoryAccessInBB(Repl, Def, HoistPt,<br>
+ MemorySSA::End);<br>
+ OldMemAcc->replaceAllUsesWith(NewMemAcc);<br>
+ MSSA->removeMemoryAccess(OldMemAcc);<br>
+ }<br>
}<br>
<br>
if (isa<LoadInst>(Repl))<br>
@@ -775,6 +790,14 @@<br>
} else if (isa<CallInst>(Repl)) {<br>
++NumCallsRemoved;<br>
}<br>
+<br>
+ if (NewMemAcc) {<br>
+ // Update the uses of the old MSSA access with NewMemAcc.<br>
+ MemoryAccess *OldMA = MSSA->getMemoryAccess(I);<br>
+ OldMA->replaceAllUsesWith(NewMemAcc);<br>
+ MSSA->removeMemoryAccess(OldMA);<br>
+ }<br>
+<br>
Repl->intersectOptionalDataWith(I);<br>
combineKnownMetadata(Repl, I);<br>
I->replaceAllUsesWith(Repl);<br>
<br>
<br>
</blockquote></div>