[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