LLVM 24.0.0git
LoopSplitUtilsPass.cpp
Go to the documentation of this file.
1//===- LoopSplitUtilsPass.cpp - Test driver for LoopSplitUtils ------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This pass drives LoopSplitUtils from `opt` for testing. For every eligible
10// loop it builds partitions from the -loop-split-points offsets and splits the
11// loop.
12//
13//===----------------------------------------------------------------------===//
14
21#include "llvm/IR/Dominators.h"
22#include "llvm/IR/Function.h"
23#include "llvm/IR/ValueHandle.h"
25#include "llvm/Support/Debug.h"
28
29using namespace llvm;
30using namespace llvm::SCEVPatternMatch;
31
32#define DEBUG_TYPE "loop-split-utils"
33
35 SplitPoints("loop-split-points",
36 cl::desc("Iteration offsets (relative to the induction start) "
37 "at which to split each loop"),
39
41 "loop-split-unguarded",
42 cl::desc("Partition indices whose entry guard is omitted (the caller "
43 "guarantees they run at least one iteration)"),
45
46/// Build the partition list for \p L from the command-line split offsets and
47/// run the transform. Returns true if the loop was split.
49 LoopInfo &LI) {
50 LoopSplitUtils LSU(L, &LI, &SE, &DT);
51 if (!LSU.isLegal()) {
52 LLVM_DEBUG(dbgs() << DEBUG_TYPE ": loop is not legal for splitting\n");
53 return false;
54 }
55
56 const SCEV *IndVarSCEV = SE.getSCEV(LSU.getInductionVariable());
57 const SCEV *Start;
58 const APInt *StepC;
59 if (!match(IndVarSCEV,
61 return false;
62 auto *IndAR = cast<SCEVAddRecExpr>(IndVarSCEV);
63
64 const SCEV *BTC = SE.getBackedgeTakenCount(L);
65 const SCEV *End = IndAR->evaluateAtIteration(BTC, SE);
66 Type *Ty = Start->getType();
67 if (End->getType() != Ty)
68 End = SE.getTruncateExpr(End, Ty);
69
70 // Build boundaries in iteration order, stepping away from Start by each
71 // offset (down for a descending loop). Each offset opens a new partition at
72 // iteration `Start +/- offset`; the previous partition ends one step before.
73 bool Descending = StepC->isAllOnes();
74
75 const SCEV *PrevStart = Start;
76 const SCEV *One = SE.getOne(Ty);
77 for (unsigned Offset : SplitPoints) {
78 const SCEV *Off = SE.getConstant(Ty, Offset);
79 const SCEV *Point =
80 Descending ? SE.getMinusSCEV(Start, Off) : SE.getAddExpr(Start, Off);
81 const SCEV *PrevEnd =
82 Descending ? SE.getAddExpr(Point, One) : SE.getMinusSCEV(Point, One);
83 LSU.addPartition(PrevStart, PrevEnd);
84 PrevStart = Point;
85 }
86 // The final partition runs to the iteration-space end.
87 LSU.addPartition(PrevStart, End);
88
89 // Suppress guards for the partitions the caller listed (out-of-range indices
90 // are ignored).
91 for (unsigned Idx : UnguardedPartitions)
92 if (Idx < LSU.getNumPartitions())
93 LSU.avoidPartitionGuard(Idx);
94
95 if (LSU.getNumPartitions() < 2)
96 return false;
97
98 // Snapshot the original loop's named instructions before the transform so we
99 // can query their per-partition counterparts afterwards (handles track any
100 // that the transform deletes). Only used to print the debug map below.
101 [[maybe_unused]] SmallVector<WeakTrackingVH, 16> OrigValues;
102 LLVM_DEBUG({
103 for (BasicBlock *BB : L->blocks())
104 for (Instruction &I : *BB)
105 if (I.hasName())
106 OrigValues.push_back(&I);
107 });
108
109 if (!LSU.split())
110 return false;
111
112 LLVM_DEBUG({
113 const unsigned N = LSU.getNumPartitions();
114 for (unsigned P = 0; P < N; ++P) {
115 dbgs() << "LS-MAP partition " << P << ":\n";
116 for (WeakTrackingVH &VH : OrigValues) {
117 if (!VH)
118 continue;
119 Value *M = LSU.getPartitionValue(VH, P);
120 dbgs() << "LS-MAP " << VH->getName() << " -> "
121 << (M ? M->getName() : "<none>") << "\n";
122 }
123 }
124 });
125 return true;
126}
127
130 if (SplitPoints.empty())
131 return PreservedAnalyses::all();
132
133 auto &LI = AM.getResult<LoopAnalysis>(F);
134 auto &SE = AM.getResult<ScalarEvolutionAnalysis>(F);
135 auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
136
137 // Collect the original top-level loops up front; the transform creates new
138 // sub-loops that we must not revisit.
139 SmallVector<Loop *, 4> Worklist(LI.begin(), LI.end());
140
141 bool Changed = false;
142 for (Loop *L : Worklist) {
143 SE.forgetLoop(L);
144 Changed |= splitLoop(L, SE, DT, LI);
145 }
146
148}
#define DEBUG_TYPE
static cl::list< unsigned > UnguardedPartitions("loop-split-unguarded", cl::desc("Partition indices whose entry guard is omitted (the caller " "guarantees they run at least one iteration)"), cl::CommaSeparated)
static bool splitLoop(Loop *L, ScalarEvolution &SE, DominatorTree &DT, LoopInfo &LI)
Build the partition list for L from the command-line split offsets and run the transform.
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)
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
#define P(N)
This file defines the SmallVector class.
#define LLVM_DEBUG(...)
Definition Debug.h:119
Class for arbitrary precision integers.
Definition APInt.h:78
bool isAllOnes() const
Determine if all bits are set. This is true for zero-width values.
Definition APInt.h:372
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
LLVM Basic Block Representation.
Definition BasicBlock.h:62
Analysis pass which computes a DominatorTree.
Definition Dominators.h:241
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
Definition Dominators.h:122
Analysis pass that exposes the LoopInfo for a function.
Definition LoopInfo.h:587
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
Splits a counted loop into a chain of per-partition sub-loops.
LLVM_ABI bool split()
Perform the split.
LLVM_ABI unsigned getNumPartitions() const
LLVM_ABI PHINode * getInductionVariable() const
Return the loop's induction variable. Valid only after isLegal() succeeds.
LLVM_ABI bool isLegal()
Analyze L and return true if it is a counted loop this utility can split: a bottom-tested single-exit...
LLVM_ABI void addPartition(const SCEV *Start, const SCEV *End)
Append an inclusive partition range [Start, End] in iteration order.
LLVM_ABI Value * getPartitionValue(Value *V, unsigned PartitionIndex) const
Return the counterpart of original-loop value V in partition PartitionIndex (0-based).
LLVM_ABI void avoidPartitionGuard(unsigned PartitionIndex)
Suppress the entry guard for partition PartitionIndex (already added).
Represents a single loop in the control flow graph.
Definition LoopInfo.h:40
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
This class represents an analyzed expression in the program.
Type * getType() const
Return the LLVM type of this SCEV expression.
Analysis pass that exposes the ScalarEvolution for a function.
The main scalar evolution driver.
LLVM_ABI const SCEV * getBackedgeTakenCount(const Loop *L, ExitCountKind Kind=Exact)
If the specified loop has a predictable backedge-taken count, return it, otherwise return a SCEVCould...
LLVM_ABI const SCEV * getConstant(ConstantInt *V)
LLVM_ABI const SCEV * getSCEV(Value *V)
Return a SCEV expression for the full generality of the specified expression.
LLVM_ABI const SCEV * getMinusSCEV(SCEVUse LHS, SCEVUse RHS, SCEV::NoWrapFlags Flags=SCEV::FlagAnyWrap, unsigned Depth=0)
Return LHS-RHS.
const SCEV * getOne(Type *Ty)
Return a SCEV for the constant 1 of a specific type.
LLVM_ABI const SCEV * getTruncateExpr(const SCEV *Op, Type *Ty, unsigned Depth=0)
LLVM_ABI const SCEV * getAddExpr(SmallVectorImpl< SCEVUse > &Ops, SCEV::NoWrapFlags Flags=SCEV::FlagAnyWrap, unsigned Depth=0)
Get a canonical add expression, or something simpler if possible.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
LLVM Value Representation.
Definition Value.h:75
Value handle that is nullable, but tries to track the Value.
Changed
bind_cst_ty m_scev_APInt(const APInt *&C)
Match an SCEV constant and bind it to an APInt.
bool match(const SCEV *S, const Pattern &P)
SCEVAffineAddRec_match< Op0_t, Op1_t, match_isa< const Loop > > m_scev_AffineAddRec(const Op0_t &Op0, const Op1_t &Op1)
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:578
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
#define N