[PATCH] D97828: [LoopInterchange] Disallow interchange when memory accesses are guarded by control flow (PR48057)
Congzhe Cao via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Sat May 15 13:24:21 PDT 2021
congzhe added inline comments.
================
Comment at: llvm/lib/Transforms/Scalar/LoopInterchange.cpp:989
+
+ while (!Worklist.empty()) {
+ BasicBlock *BB = Worklist.pop_back_val();
----------------
Whitney wrote:
> ```
> br cond, BB1, BB2
> BB1:
> br BB3
> BB2
> br BB3
> ```
>
> BB3 should not guarded by a loop variant block, but this function would return BB1, BB2, and BB3.
I agree with this concern. I'm wondering if we can do this: instead of the entire worklist algorithm in this function, can we just loop over all BBs in the inner loop that are successors of loop-variant cmps, and check if they dominate the loop latch?
Currently in loop interchange the inner loop latch is also the (only) inner loop exiting block, therefore a BB that does not dominate the inner latch can be considered as involved in control-flow divergence. This way the treatment of the above case would be seemingly easier.
================
Comment at: llvm/lib/Transforms/Scalar/LoopInterchange.cpp:1035
+ if (PHINode *PHI = dyn_cast<PHINode>(&I)) {
+ for (BasicBlock *OpBlock : PHI->blocks())
+ Guarded |= !DT->dominates(OpBlock, LoopLatch);
----------------
is `OpBlock` is not from `LoopVariantGuardedBlocks`, would interchange be legal?
================
Comment at: llvm/lib/Transforms/Scalar/LoopInterchange.cpp:1048
+ // instructions in the worklist.
+ while (!Worklist.empty()) {
+ Instruction *Inst = Worklist.pop_back_val();
----------------
would it simplify the logic if we use only `GuardedInst` instead of both `GuardedInst` and `Worklist`, and directly check for every instruction `I` in `GuardedInst`, if any of `I` or users of `I` accesses memory then we bail out (detailed checks in the suggestion below)?
This way we can also avoid looping over all instructions in the loop as in line 1061.
================
Comment at: llvm/lib/Transforms/Scalar/LoopInterchange.cpp:1066
+ if (GuardedInst.find(&I) != GuardedInst.end())
+ return true;
+ }
----------------
IMHO maybe we make the check more fine-grained.
1. If the value being stored is a loop-invariant, then it would not break legality.
2. Otherwise if we store (loop-variants) to the same location, then bail out.
3. Otherwise if we store (loop-variants) not to the same location and the memory locations do not alias, then it would not break legality. I'm thinking of cases like `cond && B[i][j] = A[i][j]` inside the inner loop.
Suggestion No.3 might be less straightforward to implement, but No.1/No.2 is hopefully more straightforward to implement.
================
Comment at: llvm/test/Transforms/LoopInterchange/control-flow.ll:153
+ %0 = load i8, i8* %cond, align 1
+ %tobool = trunc i8 %0 to i1
+ br i1 %tobool, label %if.then, label %if.else
----------------
is `%tobool` a loop-invariant? I guess interchange in this case is actually legal should `%0` is a loop-invariant?
If in this IR we hoist `%0` outside of the loop nest (can we add the corresponding test case), I guess loop interchange should not bail out but with this patch it would bail out. Maybe it makes more sense to use `SCEV::isLoopInvariant()` rather than `Loop::isLoopInvariant()` in function `getLoopVariantGuardedBlocks()`.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D97828/new/
https://reviews.llvm.org/D97828
More information about the llvm-commits
mailing list