[PATCH] D22966: GVN-hoist: compute MSSA once per function (PR28670)
Sebastian Pop via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 29 20:46:37 PDT 2016
Yes, your patch works without my last changes: i.e., keeping the
natural way of search/replace an SSA name.
On Fri, Jul 29, 2016 at 10:35 PM, Daniel Berlin <dberlin at dberlin.org> wrote:
> FWIW: The patch i sent should fix the issue of being able to create them.
> The code right now is clearly wrong, it assumes but does not check that
> insertion never fails, etc.
>
>
> On Fri, Jul 29, 2016 at 8:30 PM, Sebastian Pop <sebpop at gmail.com> wrote:
>>
>> I think I have a patch that works around the limitation of only one
>> MSSA per instruction:
>> instead of moving the instruction that we hoist, we clone it, such
>> that it can have its own separate MSSA annotation.
>>
>>
>> On Fri, Jul 29, 2016 at 10:23 PM, Daniel Berlin <dberlin at dberlin.org>
>> wrote:
>> > Okay, so ...
>> >
>> > you have to create before you can remove.
>> >
>> > remove is going to destroy the memory, and not much we can do about
>> > that.
>> > (We could split remove into remove and erase, but ... ugly)
>> >
>> > If you create first, right now, it will do the wrong thing (the
>> > annotation
>> > will never end up on the instruction, unless the instruction is new)
>> > Please try the attached, which should make it stop doing the wrong thing
>> > there. If that works, i'll add unit tests and commit it.
>> >
>> > verifyMemorySSA will catch if you mess it up (verifyOrdering checks that
>> > the
>> > accesslist and the lookups have the same number of things).
>> >
>> >
>> > On Fri, Jul 29, 2016 at 7:36 PM, Daniel Berlin <dberlin at dberlin.org>
>> > wrote:
>> >>
>> >> So, I think remove from lookups should check and only remove from the
>> >> lookup if the lookups point to that access
>> >>
>> >>
>> >> On Fri, Jul 29, 2016, 7:23 PM Daniel Berlin <dberlin at dberlin.org>
>> >> wrote:
>> >>>
>> >>> I have to stare at this.
>> >>>
>> >>> On Fri, Jul 29, 2016, 7:10 PM Sebastian Pop <sebpop at gmail.com> wrote:
>> >>>>
>> >>>> sebpop updated this revision to Diff 66212.
>> >>>> sebpop added a comment.
>> >>>>
>> >>>> Updated the patch as I first wrote it: I think this is the natural
>> >>>> way
>> >>>> to update an SSA variable.
>> >>>>
>> >>>> This fails because when invoking:
>> >>>> + MSSA->removeMemoryAccess(OldMemAcc);
>> >>>>
>> >>>> we go from:
>> >>>> ; MemoryUse(2)
>> >>>>
>> >>>> %2 = load i32, i32* %v.addr, align 4
>> >>>>
>> >>>> to no annotation at all:
>> >>>>
>> >>>> %2 = load i32, i32* %v.addr, align 4
>> >>>>
>> >>>> This is because removeMemoryAccess calls removeFromLookups which
>> >>>> does:
>> >>>>
>> >>>> Value *MemoryInst;
>> >>>> if (MemoryUseOrDef *MUD = dyn_cast<MemoryUseOrDef>(MA)) {
>> >>>> MemoryInst = MUD->getMemoryInst();
>> >>>> } else {
>> >>>> MemoryInst = MA->getBlock();
>> >>>> }
>> >>>> ValueToMemoryAccess.erase(MemoryInst);
>> >>>>
>> >>>> and erase() removes both the new and old MemoryAccess'es leaving the
>> >>>> instruction without MSSA annotation.
>> >>>
>> >>>
>> >>> Yes, only one memory access can exist for an instruction for real.
>> >>> You
>> >>> can't create two at once and get the right result.
>> >>>
>> >>>>
>> >>>> For loads this can be fixed by first removing the OldMemoryAccess and
>> >>>> then creating the NewMemoryAccess.
>> >>>> This works for loads because there are no users of a MemoryUse.
>> >>>> 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.
>> >>>
>> >>>
>> >>> Yes, most of the hoisters are cloning, so do not have this issue.
>> >>>
>> >>>>
>> >>>> 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.
>> >>>
>> >>>
>> >>> We can't make it work with two memoryacceses for the same instruction
>> >>> at
>> >>> once.
>> >>>
>> >>> We can probably implement either a createReplacement (that takes over
>> >>> the
>> >>> uses of the old one) or a moveBefore/moveAfter.
>> >>>>
>> >>>>
>> >>>>
>> >>>> https://reviews.llvm.org/D22966
>> >>>>
>> >>>> Files:
>> >>>> lib/Transforms/Scalar/GVNHoist.cpp
>> >>>>
>> >>>> Index: lib/Transforms/Scalar/GVNHoist.cpp
>> >>>> ===================================================================
>> >>>> --- lib/Transforms/Scalar/GVNHoist.cpp
>> >>>> +++ lib/Transforms/Scalar/GVNHoist.cpp
>> >>>> @@ -193,30 +193,27 @@
>> >>>> VN.setAliasAnalysis(AA);
>> >>>> VN.setMemDep(MD);
>> >>>> bool Res = false;
>> >>>> + MemorySSA M(F, AA, DT);
>> >>>> + MSSA = &M;
>> >>>>
>> >>>> // FIXME: use lazy evaluation of VN to avoid the fix-point
>> >>>> computation.
>> >>>> while (1) {
>> >>>> - // FIXME: only compute MemorySSA once. We need to update the
>> >>>> analysis in
>> >>>> - // the same time as transforming the code.
>> >>>> - MemorySSA M(F, AA, DT);
>> >>>> - MSSA = &M;
>> >>>> -
>> >>>> // Perform DFS Numbering of instructions.
>> >>>> unsigned I = 0;
>> >>>> for (const BasicBlock *BB : depth_first(&F.getEntryBlock()))
>> >>>> for (auto &Inst: *BB)
>> >>>> DFSNumber.insert({&Inst, ++I});
>> >>>>
>> >>>> auto HoistStat = hoistExpressions(F);
>> >>>> - if (HoistStat.first + HoistStat.second == 0) {
>> >>>> + if (HoistStat.first + HoistStat.second == 0)
>> >>>> return Res;
>> >>>> - }
>> >>>> - if (HoistStat.second > 0) {
>> >>>> +
>> >>>> + if (HoistStat.second > 0)
>> >>>> // To address a limitation of the current GVN, we need to
>> >>>> rerun
>> >>>> the
>> >>>> - // hoisting after we hoisted loads in order to be able to
>> >>>> hoist
>> >>>> all
>> >>>> - // scalars dependent on the hoisted loads. Same for stores.
>> >>>> + // hoisting after we hoisted loads or stores in order to be
>> >>>> able to
>> >>>> + // hoist all scalars dependent on the hoisted ld/st.
>> >>>> VN.clear();
>> >>>> - }
>> >>>> +
>> >>>> Res = true;
>> >>>>
>> >>>> // DFS numbers change when instructions are hoisted: clear and
>> >>>> recompute.
>> >>>> @@ -725,6 +722,8 @@
>> >>>> if (!Repl || firstInBB(I, Repl))
>> >>>> Repl = I;
>> >>>>
>> >>>> + MemoryAccess *NewMemAcc = nullptr;
>> >>>> +
>> >>>> if (Repl) {
>> >>>> // Repl is already in HoistPt: it remains in place.
>> >>>> assert(allOperandsAvailable(Repl, HoistPt) &&
>> >>>> @@ -742,7 +741,23 @@
>> >>>> !makeGepOperandsAvailable(Repl, HoistPt,
>> >>>> InstructionsToHoist))
>> >>>> continue;
>> >>>>
>> >>>> + // Before moving the instruction, get its MSSA access.
>> >>>> + MemoryUseOrDef *OldMemAcc = nullptr;
>> >>>> + if (MemoryAccess *MA = MSSA->getMemoryAccess(Repl))
>> >>>> + OldMemAcc = dyn_cast<MemoryUseOrDef>(MA);
>> >>>> +
>> >>>> + // Move the instruction at the end of HoistPt.
>> >>>> Repl->moveBefore(HoistPt->getTerminator());
>> >>>> +
>> >>>> + if (OldMemAcc) {
>> >>>> + // The definition of this ld/st will not change: ld/st
>> >>>> hoisting is
>> >>>> + // legal when the ld/st is not moved past its current
>> >>>> definition.
>> >>>> + MemoryAccess *Def = OldMemAcc->getDefiningAccess();
>> >>>> + NewMemAcc = MSSA->createMemoryAccessInBB(Repl, Def,
>> >>>> HoistPt,
>> >>>> + MemorySSA::End);
>> >>>> + OldMemAcc->replaceAllUsesWith(NewMemAcc);
>> >>>> + MSSA->removeMemoryAccess(OldMemAcc);
>> >>>> + }
>> >>>> }
>> >>>>
>> >>>> if (isa<LoadInst>(Repl))
>> >>>> @@ -775,6 +790,14 @@
>> >>>> } else if (isa<CallInst>(Repl)) {
>> >>>> ++NumCallsRemoved;
>> >>>> }
>> >>>> +
>> >>>> + if (NewMemAcc) {
>> >>>> + // Update the uses of the old MSSA access with
>> >>>> NewMemAcc.
>> >>>> + MemoryAccess *OldMA = MSSA->getMemoryAccess(I);
>> >>>> + OldMA->replaceAllUsesWith(NewMemAcc);
>> >>>> + MSSA->removeMemoryAccess(OldMA);
>> >>>> + }
>> >>>> +
>> >>>> Repl->intersectOptionalDataWith(I);
>> >>>> combineKnownMetadata(Repl, I);
>> >>>> I->replaceAllUsesWith(Repl);
>> >>>>
>> >>>>
>> >
>
>
More information about the llvm-commits
mailing list