[llvm] [LLVM IR] [LoopPeel] Performing loop split to reduce divergence. (PR #102283)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 7 01:05:47 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Vikash Gupta (vg0204)
<details>
<summary>Changes</summary>
The Loop can be peeled/split based on the conditional statement within its body into two parts if condition is uniform, monotonic and simple loop variant. Thus, removing non-loop invariant condition. Example :
```
for (uint i = 0; i < n; ++i) {
int x = 1;
if (i < k) x = a[lid + i];
s += x;
}
```
can be splitted based on "i < k" non-loop invariant predicate into 2 parts as follows :
```
for (uint i = 0; i < n && i < k; ++i) {
int x = a[lid + i];
s += x;
}
for (uint i = k; i < n; ++i) {
int x = 1;
s += x;
}
```
Note: In above example, n & k are only uniform & loop-invariants. The above logic can be reapplied into split parts to eliminate similar more such conditional branches.
---
Full diff: https://github.com/llvm/llvm-project/pull/102283.diff
5 Files Affected:
- (added) llvm/include/llvm/Transforms/Scalar/LoopPeelPass.h (+33)
- (modified) llvm/lib/Passes/PassBuilder.cpp (+1)
- (modified) llvm/lib/Passes/PassRegistry.def (+1)
- (modified) llvm/lib/Transforms/Scalar/CMakeLists.txt (+1)
- (added) llvm/lib/Transforms/Scalar/LoopPeelPass.cpp (+93)
``````````diff
diff --git a/llvm/include/llvm/Transforms/Scalar/LoopPeelPass.h b/llvm/include/llvm/Transforms/Scalar/LoopPeelPass.h
new file mode 100644
index 0000000000000..a52cb0c04525e
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Scalar/LoopPeelPass.h
@@ -0,0 +1,33 @@
+//===------- LoopPeelPass.h - Loop Peeling Pass -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements the Loop Peeling pass.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_SCALAR_LOOPPEELPASS_H
+#define LLVM_TRANSFORMS_SCALAR_LOOPPEELPASS_H
+
+#include "llvm/Analysis/LoopAnalysisManager.h"
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+
+class Loop;
+class LPMUpdater;
+
+class LoopPeelPass : public PassInfoMixin<LoopPeelPass> {
+public:
+ PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM,
+ LoopStandardAnalysisResults &AR, LPMUpdater &LU);
+};
+
+} // end namespace llvm
+
+#endif // LLVM_TRANSFORMS_SCALAR_LOOPFUSE_H
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index 17cc156846d36..5da030f52652a 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -231,6 +231,7 @@
#include "llvm/Transforms/Scalar/LoopInterchange.h"
#include "llvm/Transforms/Scalar/LoopLoadElimination.h"
#include "llvm/Transforms/Scalar/LoopPassManager.h"
+#include "llvm/Transforms/Scalar/LoopPeelPass.h"
#include "llvm/Transforms/Scalar/LoopPredication.h"
#include "llvm/Transforms/Scalar/LoopRotation.h"
#include "llvm/Transforms/Scalar/LoopSimplifyCFG.h"
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 3b92823cd283b..b2743ca761ce5 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -626,6 +626,7 @@ LOOP_PASS("loop-deletion", LoopDeletionPass())
LOOP_PASS("loop-idiom", LoopIdiomRecognizePass())
LOOP_PASS("loop-idiom-vectorize", LoopIdiomVectorizePass())
LOOP_PASS("loop-instsimplify", LoopInstSimplifyPass())
+LOOP_PASS("loop-peel-pass", LoopPeelPass())
LOOP_PASS("loop-predication", LoopPredicationPass())
LOOP_PASS("loop-reduce", LoopStrengthReducePass())
LOOP_PASS("loop-simplifycfg", LoopSimplifyCFGPass())
diff --git a/llvm/lib/Transforms/Scalar/CMakeLists.txt b/llvm/lib/Transforms/Scalar/CMakeLists.txt
index ba09ebf8b04c4..b087964c70912 100644
--- a/llvm/lib/Transforms/Scalar/CMakeLists.txt
+++ b/llvm/lib/Transforms/Scalar/CMakeLists.txt
@@ -40,6 +40,7 @@ add_llvm_component_library(LLVMScalarOpts
LoopFlatten.cpp
LoopLoadElimination.cpp
LoopPassManager.cpp
+ LoopPeelPass.cpp
LoopPredication.cpp
LoopRotation.cpp
LoopSimplifyCFG.cpp
diff --git a/llvm/lib/Transforms/Scalar/LoopPeelPass.cpp b/llvm/lib/Transforms/Scalar/LoopPeelPass.cpp
new file mode 100644
index 0000000000000..8e7e14f3f24d7
--- /dev/null
+++ b/llvm/lib/Transforms/Scalar/LoopPeelPass.cpp
@@ -0,0 +1,93 @@
+//===------- LoopPeelPass.h - Loop Peeling Pass -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Scalar/LoopPeelPass.h"
+#include "llvm/ADT/Sequence.h"
+#include "llvm/Analysis/DomTreeUpdater.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/ScalarEvolution.h"
+#include "llvm/Analysis/ScalarEvolutionExpressions.h"
+#include "llvm/IR/PatternMatch.h"
+#include "llvm/Transforms/Scalar/LoopPassManager.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/Cloning.h"
+#include "llvm/Transforms/Utils/LoopSimplify.h"
+#include "llvm/Transforms/Utils/ScalarEvolutionExpander.h"
+
+#define DEBUG_TYPE "loop-peel-pass"
+
+using namespace llvm;
+using namespace llvm::PatternMatch;
+
+namespace {
+
+static bool canPeelLoop(const Loop &L, const DominatorTree &DT,
+ ScalarEvolution &SE) {
+ // Skip function with optsize.
+ if (L.getHeader()->getParent()->hasOptSize())
+ return false;
+
+ // Split only innermost loop.
+ if (!L.isInnermost())
+ return false;
+
+ // Check loop is in simplified form.
+ if (!L.isLoopSimplifyForm())
+ return false;
+
+ // Check loop is in LCSSA form.
+ if (!L.isLCSSAForm(DT))
+ return false;
+
+ // Skip loop that cannot be cloned.
+ if (!L.isSafeToClone())
+ return false;
+
+ BasicBlock *ExitingBB = L.getExitingBlock();
+ // Assumed only one exiting block.
+ if (!ExitingBB)
+ return false;
+
+ // Exiting block terminator should be conditional
+ BranchInst *ExitingBI = dyn_cast<BranchInst>(ExitingBB->getTerminator());
+ if (!ExitingBI || ExitingBI->isUnconditional())
+ return false;
+
+ BranchInst *ExitingBI = dyn_cast<BranchInst>(ExitingBB->getTerminator());
+ if (!ExitingBI)
+ return false;
+
+ // TODO: Analyze Predicate of ExitingBI of loop to among them -> ugt, sgt,
+ // ult, slt If sge, uge, sle, sge, see if can be coverted into above ones by
+ // modifiying SCEVExpr. If this holds than loop peel is suppoerted.
+
+ LLVM_DEBUG(dbgs() << "Can Peel Loop : " << L << '\n');
+ return true;
+}
+} // namespace
+
+PreservedAnalyses LoopPeelPass::run(Loop &L, LoopAnalysisManager &AM,
+ LoopStandardAnalysisResults &AR,
+ LPMUpdater &LU) {
+ dbgs() << "\nStart here\n";
+ Function &F = *L.getHeader()->getParent();
+ dbgs() << "Peel loop in function : " << F.getName() << " ->\n " << L << "\n";
+
+ auto &LI = AR.LI;
+ auto &DT = AR.DT;
+ auto &SE = AR.SE;
+
+ // const TargetTransformInfo &TTI = AR.TTI;
+
+ // if (canPeelLoop(L, DT, SE))
+ // Process Loop now!!!
+
+ PreservedAnalyses PA;
+ PA.areAllPreserved();
+ return PA;
+}
\ No newline at end of file
``````````
</details>
https://github.com/llvm/llvm-project/pull/102283
More information about the llvm-commits
mailing list