[PATCH] D72700: [DSE] Add first version of MemorySSA-backed DSE (Bottom up walk).

Alina Sbirlea via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 15 12:32:50 PST 2020


asbirlea added a comment.

Regarding handling the branching example, the solution fhahn proposes sounds reasonable to me.
I was thinking something similar, along the lines of: do the checks bottom-up from both second and third stores during the main algorithm, both find the dead store but do not postdominate it; don't abandon them, but keep this info (include the checks for no intervening reads) for after the main search. The data structure could be a Hashmap<PotentialDeadStore, ListOfDefsOrBlocksWhoFoundThisPotentialDeadStore>. If all paths are covered in the List for a PotentialDeadStore, then it's truly dead.



================
Comment at: llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp:1539
+  // Check if DomDef may be read.
+  for (unsigned I = 0; I < WorkList.size(); I++) {
+    MemoryAccess *UseAccess = WorkList[I];
----------------
fhahn wrote:
> asbirlea wrote:
> > Walking uses may miss cases due to aliasing not being transitive. This needs to be throughly analyzed. Here's a very rough example.
> > ```
> > 1 = Def(LoE) ; <----- DomDef  stores [0,3]
> > 2 = Def(1) ; (2, 1)=NoAlias,   stores [4,7]
> > Use(2)      ; MayAlias 2 *and* 1, the Use points to the *first* Def it may alias, loads [0, 7].
> > 3 = Def(1)  ; <---- Current  (3, 2)=NoAlias, (3,1)=MayAlias,  stores [0,3]
> > ```
> > The situation may be simplified due to handling stores, but all Uses may need looking at. Note this will not work to recurse on uses of the uses either.
> > Rough example why:
> > ```
> > 1 = Def(LoE)
> > 2 = Def(1)     ; <----- DomDef 
> > 3 = Def(1) ; (3, 2)=NoAlias
> > Use(3)      ; MayAlias 3 *and* 2, the Use points to the *first* Def it may alias.
> > 4 = Def(2)  ; <---- Current  (4, 3)=NoAlias, (4,2)=MayAlias
> > ```
> > 
> Thanks for the example. I think I might be missing something for the optimized version though. From the example in MemorySSA.h:
> 
> ```
> /// Given this form, all the stores that could ever effect the load at %8 can be
> /// gotten by using the MemoryUse associated with it, and walking from use to
> /// def until you hit the top of the function.
> ```
> 
> From the comment above, shouldn't we visit both  2 and 3 when walking up from Use(3), as both may change the read location? In the example we would only see 3 and 1.
> 
> But even assuming we would visit both 2 and 3, I think I can see how we could end up with scenarios we could miss overlapping reads. I think we would have to take a look at all users of DomDef and we specifically *cannot* skip any non-aliasing MemoryDefs for the read-checks. 
> 
> That would make things more expensive, but would be something we have to do regardless of going bottom-up/top-down. Does that make sense to you? However I think that would mean that in the worst-case, we would have to do a top-down walk similar to the general top-down approach for the read checks.
I think I know what I missed. MemoryDefs keep two fields, the defining and the optimized access. So `3 = Def(1) ` actually looks like this: `3 = Def(2) - Optimized 1 `, and is a user of both 1 and 2.

Yes, I think you're right that the read checks for all accesses are needed regardless of which approach is taken. And yes, it will be expensive. 
I came across something similar in LICM, and I limited or outright avoided analyzing all uses against a store to avoid the cost of analyzing all of them (see ~LICM.cpp:1300)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D72700/new/

https://reviews.llvm.org/D72700





More information about the llvm-commits mailing list