[llvm] [Transforms][Utils] Add LoopSplit for iteration-space loop splitting (PR #217232)
Ramkumar Ramachandra via llvm-commits
llvm-commits at lists.llvm.org
Sun Aug 23 01:30:00 PDT 2026
================
@@ -0,0 +1,143 @@
+//===- LoopSplitPass.cpp - Test driver for LoopSplit ----------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass drives LoopSplit from `opt` for testing. For every eligible loop it
+// builds partitions from the -loop-split-points offsets and splits the loop.
+// Which loops are eligible is chosen by -loop-split-depth; the default is the
+// innermost ones.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Utils/LoopSplitPass.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/ScalarEvolution.h"
+#include "llvm/Analysis/ScalarEvolutionExpressions.h"
+#include "llvm/Analysis/ScalarEvolutionPatternMatch.h"
+#include "llvm/IR/Dominators.h"
+#include "llvm/IR/Function.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Transforms/Utils/LoopSplit.h"
+
+using namespace llvm;
+using namespace llvm::SCEVPatternMatch;
+
+#define DEBUG_TYPE "loop-split"
+
+static cl::list<unsigned>
+ SplitPoints("loop-split-points",
+ cl::desc("Iteration offsets (relative to the induction start) "
+ "at which to split each loop"),
+ cl::CommaSeparated);
+
+static cl::opt<unsigned> SplitDepth(
+ "loop-split-depth",
+ cl::desc(
+ "Split the loops at this nesting depth (1 is outermost) instead of "
+ "the innermost ones"),
+ cl::init(0));
+
+// Build the partition list for \p L from the command-line split offsets and run
+// the transform. Returns true if the loop was split.
+static bool splitLoop(Loop *L, ScalarEvolution &SE, DominatorTree &DT,
+ LoopInfo &LI) {
+ LoopSplit LS(L, &LI, &SE, &DT);
+ if (!LS.isLegal()) {
+ LLVM_DEBUG(dbgs() << DEBUG_TYPE ": loop is not legal for splitting\n");
+ return false;
+ }
+
+ // isLegal() has already established this shape.
+ const SCEV *IndVarSCEV = SE.getSCEV(LS.getInductionVariable());
+ const SCEV *Start;
+ const APInt *StepC;
+ [[maybe_unused]] bool Matched = match(
+ IndVarSCEV, m_scev_AffineAddRec(m_SCEV(Start), m_scev_APInt(StepC)));
+ assert(Matched && "isLegal() guarantees a unit-step affine induction");
+
+ const SCEV *BTC = SE.getBackedgeTakenCount(L);
+ const SCEV *End = LS.getInductionEnd();
+ Type *Ty = Start->getType();
+ unsigned BitWidth = Ty->getIntegerBitWidth();
+ // The backedge-taken count is a separate expression and need not share the
+ // induction's width, so coerce it before doing arithmetic in that type.
+ const SCEV *Count = SE.getTruncateOrZeroExtend(BTC, Ty);
+
+ // Build boundaries in iteration order, stepping away from Start by each
+ // offset (down for a descending loop). Each offset opens a new partition at
+ // iteration `Start +/- offset`; the previous partition ends one step before.
+ bool Descending = StepC->isAllOnes();
+
+ // Boundaries must be increasing and distinct to tile the space, so sort and
+ // unique the offsets. Drop any that do not fit the induction type; truncating
+ // would reorder them and the partitions would overlap.
+ SmallVector<unsigned, 4> Offsets;
+ for (unsigned Offset : SplitPoints)
+ if (BitWidth >= 32 || Offset < (1u << BitWidth))
----------------
artagnon wrote:
1u << BitWidth would overflow when BitWidth > 64 bits? Please add a test for this.
https://github.com/llvm/llvm-project/pull/217232
More information about the llvm-commits
mailing list