LLVM 24.0.0git
LoopUnrollAnalyzer.cpp
Go to the documentation of this file.
1//===- LoopUnrollAnalyzer.cpp - Unrolling Effect Estimation -----*- C++ -*-===//
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 file implements UnrolledInstAnalyzer class. It's used for predicting
10// potential effects that loop unrolling might have, such as enabling constant
11// propagation and other optimizations.
12//
13//===----------------------------------------------------------------------===//
14
21#include "llvm/IR/Operator.h"
22
23using namespace llvm;
24
25/// Try to simplify instruction \param I using its SCEV expression.
26///
27/// The idea is that some AddRec expressions become constants, which then
28/// could trigger folding of other instructions. However, that only happens
29/// for expressions whose start value is also constant, which isn't always the
30/// case. In another common and important case the start value is just some
31/// address (i.e. SCEVUnknown) - in this case we compute the offset and save
32/// it along with the base address instead.
33bool UnrolledInstAnalyzer::simplifyInstWithSCEV(Instruction *I) {
34 if (!SE.isSCEVable(I->getType()))
35 return false;
36
37 const SCEV *S = SE.getSCEV(I);
38 if (auto *SC = dyn_cast<SCEVConstant>(S)) {
39 SimplifiedValues[I] = SC->getValue();
40 return true;
41 }
42
43 // If we have a loop invariant computation, we only need to compute it once.
44 // Given that, all but the first occurance are free.
45 if (!IterationNumber->isZero() && SE.isLoopInvariant(S, L))
46 return true;
47
48 auto *AR = dyn_cast<SCEVAddRecExpr>(S);
49 if (!AR || AR->getLoop() != L)
50 return false;
51
52 const SCEV *ValueAtIteration = AR->evaluateAtIteration(IterationNumber, SE);
53 // Check if the AddRec expression becomes a constant.
54 if (auto *SC = dyn_cast<SCEVConstant>(ValueAtIteration)) {
55 SimplifiedValues[I] = SC->getValue();
56 return true;
57 }
58
59 // Check if the offset from the base address becomes a constant.
60 auto *Base = dyn_cast<SCEVUnknown>(SE.getPointerBase(S));
61 if (!Base)
62 return false;
63 std::optional<APInt> Offset =
64 SE.computeConstantDifference(ValueAtIteration, Base);
65 if (!Offset)
66 return false;
67 SimplifiedAddress Address;
68 Address.Base = Base->getValue();
69 Address.Offset = *Offset;
70 SimplifiedAddresses[I] = std::move(Address);
71 return false;
72}
73
74/// Try to simplify binary operator I.
75///
76/// TODO: Probably it's worth to hoist the code for estimating the
77/// simplifications effects to a separate class, since we have a very similar
78/// code in InlineCost already.
79bool UnrolledInstAnalyzer::visitBinaryOperator(BinaryOperator &I) {
80 Value *LHS = I.getOperand(0), *RHS = I.getOperand(1);
81 if (!isa<Constant>(LHS))
82 if (Value *SimpleLHS = SimplifiedValues.lookup(LHS))
83 LHS = SimpleLHS;
84 if (!isa<Constant>(RHS))
85 if (Value *SimpleRHS = SimplifiedValues.lookup(RHS))
86 RHS = SimpleRHS;
87
88 Value *SimpleV = nullptr;
89 const DataLayout &DL = I.getDataLayout();
90 if (auto FI = dyn_cast<FPMathOperator>(&I))
91 SimpleV =
92 simplifyBinOp(I.getOpcode(), LHS, RHS, FI->getFastMathFlags(), DL);
93 else
94 SimpleV = simplifyBinOp(I.getOpcode(), LHS, RHS, DL);
95
96 if (SimpleV) {
97 SimplifiedValues[&I] = SimpleV;
98 return true;
99 }
101}
102
103/// Try to fold load I.
104bool UnrolledInstAnalyzer::visitLoad(LoadInst &I) {
105 Value *AddrOp = I.getPointerOperand();
106
107 auto AddressIt = SimplifiedAddresses.find(AddrOp);
108 if (AddressIt == SimplifiedAddresses.end())
109 return false;
110
111 auto *GV = dyn_cast<GlobalVariable>(AddressIt->second.Base);
112 // We're only interested in loads that can be completely folded to a
113 // constant.
114 if (!GV || !GV->hasDefinitiveInitializer() || !GV->isConstant())
115 return false;
116
117 Constant *Res =
118 ConstantFoldLoadFromConst(GV->getInitializer(), I.getType(),
119 AddressIt->second.Offset, I.getDataLayout());
120 if (!Res)
121 return false;
122
123 SimplifiedValues[&I] = Res;
124 return true;
125}
126
127/// Try to simplify cast instruction.
128bool UnrolledInstAnalyzer::visitCastInst(CastInst &I) {
129 Value *Op = I.getOperand(0);
130 if (Value *Simplified = SimplifiedValues.lookup(Op))
131 Op = Simplified;
132
133 // The cast can be invalid, because SimplifiedValues contains results of SCEV
134 // analysis, which operates on integers (and, e.g., might convert i8* null to
135 // i32 0).
136 if (CastInst::castIsValid(I.getOpcode(), Op, I.getType())) {
137 const DataLayout &DL = I.getDataLayout();
138 if (Value *V = simplifyCastInst(I.getOpcode(), Op, I.getType(), DL)) {
139 SimplifiedValues[&I] = V;
140 return true;
141 }
142 }
143
144 return Base::visitCastInst(I);
145}
146
147/// Try to simplify cmp instruction.
148bool UnrolledInstAnalyzer::visitCmpInst(CmpInst &I) {
149 Value *LHS = I.getOperand(0), *RHS = I.getOperand(1);
150
151 // First try to handle simplified comparisons.
152 if (!isa<Constant>(LHS))
153 if (Value *SimpleLHS = SimplifiedValues.lookup(LHS))
154 LHS = SimpleLHS;
155 if (!isa<Constant>(RHS))
156 if (Value *SimpleRHS = SimplifiedValues.lookup(RHS))
157 RHS = SimpleRHS;
158
159 if (!isa<Constant>(LHS) && !isa<Constant>(RHS) && !I.isSigned()) {
160 auto SimplifiedLHS = SimplifiedAddresses.find(LHS);
161 if (SimplifiedLHS != SimplifiedAddresses.end()) {
162 auto SimplifiedRHS = SimplifiedAddresses.find(RHS);
163 if (SimplifiedRHS != SimplifiedAddresses.end()) {
164 SimplifiedAddress &LHSAddr = SimplifiedLHS->second;
165 SimplifiedAddress &RHSAddr = SimplifiedRHS->second;
166 if (LHSAddr.Base == RHSAddr.Base) {
167 // FIXME: This is only correct for equality predicates. For
168 // unsigned predicates, this only holds if we have nowrap flags,
169 // which we don't track (for nuw it's valid as-is, for nusw it
170 // requires converting the predicated to signed). As this is used only
171 // for cost modelling, this is not a correctness issue.
172 bool Res = ICmpInst::compare(LHSAddr.Offset, RHSAddr.Offset,
173 I.getPredicate());
174 SimplifiedValues[&I] = ConstantInt::getBool(I.getType(), Res);
175 return true;
176 }
177 }
178 }
179 }
180
181 const DataLayout &DL = I.getDataLayout();
182 if (Value *V = simplifyCmpInst(I.getPredicate(), LHS, RHS, DL)) {
183 SimplifiedValues[&I] = V;
184 return true;
185 }
186
187 return Base::visitCmpInst(I);
188}
189
190bool UnrolledInstAnalyzer::visitPHINode(PHINode &PN) {
191 // Run base visitor first. This way we can gather some useful for later
192 // analysis information.
193 if (Base::visitPHINode(PN))
194 return true;
195
196 // The loop induction PHI nodes are definitionally free.
197 return PN.getParent() == L->getHeader();
198}
199
200/// Returns true if \p I computes the same value on every iteration of the
201/// loop: it does not access memory, has no side effects, and all of its
202/// operands are defined outside the loop or are themselves such computations.
203/// Unlike SCEV-based invariance this works for any type, e.g. floating point.
204bool UnrolledInstAnalyzer::isInvariantComputation(Instruction *I) {
205 if (!L->contains(I))
206 return true;
207 if (auto It = InvariantInsts.find(I); It != InvariantInsts.end())
208 return It->second;
210 if (isa<PHINode, AllocaInst>(I) || I->isTerminator() ||
211 (II && II->isAssumeLikeIntrinsic()) || I->mayReadOrWriteMemory() ||
212 I->mayHaveSideEffects()) {
213 InvariantInsts[I] = false;
214 return false;
215 }
216 bool Invariant = all_of(I->operands(), [&](Value *Op) {
217 auto *OpI = dyn_cast<Instruction>(Op);
218 return !OpI || isInvariantComputation(OpI);
219 });
220 InvariantInsts[I] = Invariant;
221 return Invariant;
222}
223
224bool UnrolledInstAnalyzer::visitInstruction(Instruction &I) {
225 if (simplifyInstWithSCEV(&I))
226 return true;
227
228 // Invariance of SCEVable values is decided by SCEV above. For other values,
229 // e.g. floating point, an invariant computation likewise only has to be
230 // performed once after unrolling; all but the first occurrence are free.
231 return !SE.isSCEVable(I.getType()) && !IterationNumber->isZero() &&
232 isInvariantComputation(&I);
233}
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
#define I(x, y, z)
Definition MD5.cpp:57
uint64_t IntrinsicInst * II
Value * RHS
Value * LHS
This is the base class for all instructions that perform data casts.
Definition InstrTypes.h:512
static LLVM_ABI bool castIsValid(Instruction::CastOps op, Type *SrcTy, Type *DstTy)
This method can be used to determine if a cast from SrcTy to DstTy using Opcode op is valid or not.
This class is the base class for the comparison instructions.
Definition InstrTypes.h:728
static LLVM_ABI ConstantInt * getBool(LLVMContext &Context, bool V)
static LLVM_ABI bool compare(const APInt &LHS, const APInt &RHS, ICmpInst::Predicate Pred)
Return result of LHS Pred RHS comparison.
An instruction for reading from memory.
const ParentTy * getParent() const
Definition ilist_node.h:34
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:577
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1755
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
LLVM_ABI Value * simplifyCastInst(unsigned CastOpc, Value *Op, Type *Ty, const SimplifyQuery &Q)
Given operands for a CastInst, fold the result or return null.
LLVM_ABI Constant * ConstantFoldLoadFromConst(Constant *C, Type *Ty, const APInt &Offset, const DataLayout &DL)
Extract value of C at the given Offset reinterpreted as Ty.
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
LLVM_ABI Value * simplifyBinOp(unsigned Opcode, Value *LHS, Value *RHS, const SimplifyQuery &Q)
Given operands for a BinaryOperator, fold the result or return null.
DWARFExpression::Operation Op
LLVM_ABI Value * simplifyCmpInst(CmpPredicate Predicate, Value *LHS, Value *RHS, const SimplifyQuery &Q)
Given operands for a CmpInst, fold the result or return null.