[PATCH] D93764: [LoopUnswitch] Implement first version of partial unswitching.
Florian Hahn via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 12 11:53:32 PST 2021
fhahn added inline comments.
================
Comment at: llvm/lib/Transforms/Scalar/LoopUnswitch.cpp:742
+ for (Use &U : Current->uses())
+ AccessesToCheck.push_back(cast<MemoryAccess>(U.getUser()));
+ }
----------------
jdoerfert wrote:
> fhahn wrote:
> > jdoerfert wrote:
> > > Why do we need to check these uses?
> > Unfortunately a `MemoryDef` does not necessarily have all may/must-alias defs that follow it as users. For example, I think we could have something like
> >
> > ```
> > %0 = MemoryDef (LiveOnEntry)
> > %1 = MemoryPhi(%0,...)
> > %2 = MemoryDef(%1,...) ; may-alias %0
> > ```
> >
> > depending on what MemorySSA optimizations are applied, I think there could be similar examples with just MemoryDefs.
> I'm trying to wrap my head around this and it is probably me. I haven't worked with MSSA much.
>
> So, `AccessesToCheck` starts with the defining access for each read location, so far so good. (correct me if I'm wrong at some point)
> If that access is outside the loop, done.
> If that access is inside and aliasing a location, done.
> If that access is inside and not aliasing a location, why do we look at the uses?
> I would understand if we look at the "operands":
>
> ```
> Header:
> %1 = MemDef(%0,...) // clobbers %3
> %2 = MemDef(%1,...) // defining access of %3
> %3 = MemUse(%2,...) // in AccessedLocations
> ```
>
> Though, I assume I simply do not understand MSSA in various ways.
> So, AccessesToCheck starts with the defining access for each read location, so far so good. (correct me if I'm wrong at some point)
> If that access is outside the loop, done.
> If that access is inside and aliasing a location, done.
Sounds good so far.
> If that access is inside and not aliasing a location, why do we look at the uses?
Because the uses of access `A` are the memory accesses that may read/write the memory location written by `A`, after `A`. For accesses that may access the same memory locations in a loop/cycle, there will be uses in `MemoryPhis`.
A concrete example is below. To visit all potential clobbers of `; MemoryUse(1) ( %lv = load i32, i32* %ptr, align 4)` , we have to visit all uses of `%1 = MemoryDef(4) (call void @clobber())`, their uses and so on.
The case where a clobber comes before the defining access in the header (as in your example) will be handled by this forward-scanning approach because there will be a `MemoryPhi` that's the defining access of `%1` in your example.
Does this make sense?
While looking at this again, I realized that queuing the defining access at line 692 could be overly pessimistic, if there are scenarios where it may alias a location in `AccessedLocations`, but its defining access is outside the loop. It would probably better to directly queue the uses of the defining access. But I am not sure if such a scenario can happen in practice.
```
define i32 @test(i32* %ptr, i32 %N) {
entry:
br label %loop.header
loop.header: ; preds = %loop.latch, %entry
; 4 = MemoryPhi({entry,liveOnEntry},{loop.latch,3})
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
; 1 = MemoryDef(4)
call void @clobber()
; MemoryUse(1)
%lv = load i32, i32* %ptr, align 4
%sc = icmp eq i32 %lv, 100
br i1 %sc, label %noclobber, label %clobber
noclobber: ; preds = %loop.header
br label %loop.latch
clobber: ; preds = %loop.header
; 2 = MemoryDef(1)
call void @clobber()
br label %loop.latch
loop.latch: ; preds = %clobber, %noclobber
; 3 = MemoryPhi({noclobber,1},{clobber,2})
%c = icmp ult i32 %iv, %N
%iv.next = add i32 %iv, 1
br i1 %c, label %loop.header, label %exit
exit: ; preds = %loop.latch
ret i32 10
}
```
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D93764/new/
https://reviews.llvm.org/D93764
More information about the llvm-commits
mailing list