LLVM 24.0.0git
SLPReductionUtils.cpp
Go to the documentation of this file.
1//===- SLPReductionUtils.cpp - SLP reduction match helpers ----------------===//
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#include "SLPReductionUtils.h"
10
11#include "SLPCostAnalysis.h"
12#include "SLPUtils.h"
13
14#include "llvm/ADT/STLExtras.h"
15#include "llvm/ADT/Sequence.h"
21#include "llvm/IR/Constants.h"
22#include "llvm/IR/DataLayout.h"
24#include "llvm/IR/Dominators.h"
25#include "llvm/IR/IRBuilder.h"
27#include "llvm/IR/Intrinsics.h"
29#include "llvm/IR/Type.h"
30
31using namespace llvm;
32using namespace llvm::PatternMatch;
33
34namespace llvm::slpvectorizer {
35
36static bool matchRdxBop(Instruction *I, Value *&V0, Value *&V1) {
37 if (match(I, m_BinOp(m_Value(V0), m_Value(V1))))
38 return true;
39 if (match(I, m_FMaxNum(m_Value(V0), m_Value(V1))))
40 return true;
41 if (match(I, m_FMinNum(m_Value(V0), m_Value(V1))))
42 return true;
43 if (match(I, m_FMaximum(m_Value(V0), m_Value(V1))))
44 return true;
45 if (match(I, m_FMinimum(m_Value(V0), m_Value(V1))))
46 return true;
48 return true;
50 return true;
52 return true;
54 return true;
55 return false;
56}
57
59 Value *Op0 = nullptr;
60 Value *Op1 = nullptr;
61 if (!matchRdxBop(I, Op0, Op1))
62 return nullptr;
63 return dyn_cast<Instruction>(Op0 == Phi ? Op1 : Op0);
64}
65
67 bool IsSelect = match(I, m_Select(m_Value(), m_Value(), m_Value()));
68 Value *B0 = nullptr, *B1 = nullptr;
69 bool IsBinop = matchRdxBop(I, B0, B1);
70 return IsBinop || IsSelect;
71}
72
73Type *getBoolReduxWideTy(RecurKind RdxKind, Type *RootTy, Type *LeafTy) {
74 if ((RdxKind == RecurKind::And || RdxKind == RecurKind::Or) &&
75 RootTy->isIntegerTy(1) && LeafTy->isIntegerTy() &&
76 !LeafTy->isIntegerTy(1))
77 return LeafTy;
78 return nullptr;
79}
80
82 RecurKind RdxKind,
83 const SmallDenseMap<Value *, NarrowedLeafInfo> &NarrowedLeafShifts,
84 const DataLayout &DL) {
85 if (RdxKind != RecurKind::Or || DL.isBigEndian() ||
86 NarrowedLeafShifts.empty())
87 return BoolBitmask::None;
88 unsigned NumLeaves = NarrowedLeafShifts.size();
89 SmallBitVector Seen(NumLeaves);
90 bool NeedMask = false;
91 for (const auto &[V, L] : NarrowedLeafShifts) {
92 if (L.Shift >= NumLeaves || Seen.test(L.Shift))
93 return BoolBitmask::None;
94 Seen.set(L.Shift);
96 // The masked leaf must be known to be 0 or 1.
97 if ((L.Mask & ~Known.Zero).ugt(1))
98 return BoolBitmask::None;
99 // The mask is redundant if it keeps all not-known-zero bits.
100 NeedMask |= !(Known.Zero | L.Mask).isAllOnes();
101 }
103}
104
105bool matchPackedFields(Value *V, unsigned MaxDepth,
108 auto *PackTy = dyn_cast<IntegerType>(V->getType());
109 if (!PackTy)
110 return false;
112 collectNarrowedLeaves(V, Instruction::Or, PackTy->getBitWidth(), MaxDepth,
113 Leaves, Chain);
114 if (Leaves.size() < 2)
115 return false;
116 Type *FieldTy = Leaves.front().V->getType();
117 if (!FieldTy->isIntegerTy() ||
118 PackTy->getBitWidth() != Leaves.size() * FieldTy->getIntegerBitWidth())
119 return false;
120 llvm::sort(Leaves, [](const NarrowedLeafInfo &A, const NarrowedLeafInfo &B) {
121 return A.Shift < B.Shift;
122 });
123 for (const auto &[Pos, L] : enumerate(Leaves))
124 if (L.V->getType() != FieldTy || !L.Mask.isAllOnes() ||
125 L.Shift != Pos * FieldTy->getIntegerBitWidth())
126 return false;
128 Fields, map_range(Leaves, [](const NarrowedLeafInfo &L) { return L.V; }));
129 return true;
130}
131
134 RecurKind RdxKind, Value *Vec,
135 const Value *Root, FastMathFlags FMF,
136 const TTI::TargetCostKind CostKind) {
137 auto *VecTy = cast<FixedVectorType>(Vec->getType());
138 unsigned VF = VecTy->getNumElements();
139 auto *I1VecTy = FixedVectorType::get(Builder.getInt1Ty(), VF);
140 DebugLoc DL = Builder.getCurrentDebugLocation();
141 Builder.SetCurrentDebugLocation(cast<Instruction>(Root)->getDebugLoc());
142 Value *T = Builder.CreateTrunc(Vec, I1VecTy);
143 Value *BC = Builder.CreateBitCast(T, Builder.getIntNTy(VF));
144 CmpInst::Predicate Pred =
146 Constant *RHS = RdxKind == RecurKind::And
149 Value *Res = Builder.CreateICmp(Pred, BC, RHS);
150 // The costs are evaluated from the emitted instructions; they are dropped
151 // if the wide reduction form is cheaper.
152 auto CastCost = [&](Value *V, unsigned Opcode, Type *SrcTy) {
153 auto *I = dyn_cast<Instruction>(V);
154 if (!I)
155 return InstructionCost(0);
156 return TTI.getCastInstrCost(Opcode, I->getType(), SrcTy,
157 TTI.getCastContextHint(I), CostKind, I);
158 };
159 InstructionCost BitcastCmpCost = CastCost(T, Instruction::Trunc, VecTy) +
160 CastCost(BC, Instruction::BitCast, I1VecTy);
161 if (auto *Cmp = dyn_cast<Instruction>(Res))
162 BitcastCmpCost += TTI.getCmpSelInstrCost(
163 Instruction::ICmp, BC->getType(), /*CondTy=*/nullptr, Pred, CostKind,
164 TTI.getOperandInfo(BC), TTI.getOperandInfo(RHS), Cmp);
165 if (BitcastCmpCost >=
166 getBoolReduxWideRdxCost(TTI, RdxKind, VecTy, Root, FMF, CostKind)) {
167 for (Value *V : {Res, BC, T})
168 if (auto *I = dyn_cast<Instruction>(V))
169 I->eraseFromParent();
170 Builder.SetCurrentDebugLocation(DL);
171 return nullptr;
172 }
173 Builder.SetCurrentDebugLocation(DL);
174 return Res;
175}
176
178 BasicBlock *ParentBB, LoopInfo *LI) {
179 // There are situations where the reduction value is not dominated by the
180 // reduction phi. Vectorizing such cases has been reported to cause
181 // miscompiles. See PR25787.
182 auto DominatedReduxValue = [&](Value *R) {
183 return isa<Instruction>(R) &&
184 DT->dominates(P->getParent(), cast<Instruction>(R)->getParent());
185 };
186
187 Instruction *Rdx = nullptr;
188
189 // Return the incoming value if it comes from the same BB as the phi node.
190 if (P->getIncomingBlock(0) == ParentBB) {
191 Rdx = dyn_cast<Instruction>(P->getIncomingValue(0));
192 } else if (P->getIncomingBlock(1) == ParentBB) {
193 Rdx = dyn_cast<Instruction>(P->getIncomingValue(1));
194 }
195
196 if (Rdx && DominatedReduxValue(Rdx))
197 return Rdx;
198
199 // Otherwise, check whether we have a loop latch to look at.
200 Loop *BBL = LI->getLoopFor(ParentBB);
201 if (!BBL)
202 return nullptr;
203 BasicBlock *BBLatch = BBL->getLoopLatch();
204 if (!BBLatch)
205 return nullptr;
206
207 // There is a loop latch, return the incoming value if it comes from
208 // that. This reduction pattern occasionally turns up.
209 if (P->getIncomingBlock(0) == BBLatch) {
210 Rdx = dyn_cast<Instruction>(P->getIncomingValue(0));
211 } else if (P->getIncomingBlock(1) == BBLatch) {
212 Rdx = dyn_cast<Instruction>(P->getIncomingValue(1));
213 }
214
215 if (Rdx && DominatedReduxValue(Rdx))
216 return Rdx;
217
218 return nullptr;
219}
220
222 const DataLayout &DL,
223 ScalarEvolution &SE,
224 unsigned MaxDepth,
228 SmallVector<Instruction *> Worklist(1, Root);
229 while (!Worklist.empty()) {
230 for (Value *Op : Worklist.pop_back_val()->operands()) {
231 auto *I = dyn_cast<Instruction>(Op);
232 if (!I)
233 return false;
234 if (I->getOpcode() == Root->getOpcode() &&
235 I->getParent() == Root->getParent() && I->hasOneUse() &&
237 Worklist.push_back(I);
238 else
239 RdxVals.push_back(I);
240 }
241 }
242 constexpr unsigned MinReducedVals = 4;
243 BasicBlock *BB = RdxVals.front()->getParent();
244 const Loop *L = LI.getLoopFor(BB);
245 if (RdxVals.size() < MinReducedVals || !L || L->contains(Root) ||
246 any_of(RdxVals, [&](Instruction *I) { return I->getParent() != BB; }))
247 return false;
248 // The accumulators, used by the other ones, cannot be vectorized along the
249 // reduced values without the shuffles in the loop.
250 auto GetAccumulator = [&](Instruction *RdxVal) -> PHINode * {
251 PHINode *Acc = nullptr;
252 for (User *U : RdxVal->users()) {
253 if (!L->contains(cast<Instruction>(U)))
254 continue;
255 auto *P = dyn_cast<PHINode>(U);
256 if (Acc || !P || P->getParent() != L->getHeader() || !P->hasOneUse())
257 return nullptr;
258 Acc = P;
259 }
260 return Acc;
261 };
263 for (Instruction *RdxVal : RdxVals) {
264 PHINode *Acc = GetAccumulator(RdxVal);
265 if (!Acc)
266 return false;
267 Accs.insert(Acc);
268 SmallVectorImpl<LoadInst *> &RdxLoads = Loads.emplace_back();
269 SmallVector<unsigned> RdxShape;
272 while (!Stack.empty()) {
273 auto [I, Depth] = Stack.pop_back_val();
274 if (!Visited.insert(I).second)
275 continue;
276 if (I != Acc && isa<PHINode>(I) && I->getParent() == L->getHeader())
277 return false;
278 if (auto *LdI = dyn_cast<LoadInst>(I)) {
279 RdxLoads.push_back(LdI);
280 RdxShape.push_back(I->getOpcode());
281 continue;
282 }
283 if (Depth == MaxDepth || isa<PHINode>(I) || I->getParent() != BB)
284 continue;
285 RdxShape.push_back(I->getOpcode());
286 if (auto *Cmp = dyn_cast<CmpInst>(I))
287 RdxShape.push_back(Cmp->getPredicate());
288 for (Value *Op : reverse(I->operands()))
289 if (auto *OpI = dyn_cast<Instruction>(Op))
290 Stack.emplace_back(OpI, Depth + 1);
291 }
292 if (RdxLoads.empty() || !Visited.contains(Acc))
293 return false;
294 if (Shape.empty())
295 Shape.assign(RdxShape.begin(), RdxShape.end());
296 else if (RdxShape != Shape)
297 return false;
298 }
299 return all_of(seq<unsigned>(Loads.front().size()), [&](unsigned Pos) {
300 LoadInst *Ld0 = Loads.front()[Pos];
301 SmallVector<int64_t> Offsets;
302 for (ArrayRef<LoadInst *> RdxLoads : Loads) {
303 std::optional<int64_t> Diff = getPointersDiff(
304 Ld0->getType(), Ld0->getPointerOperand(), RdxLoads[Pos]->getType(),
305 RdxLoads[Pos]->getPointerOperand(), DL, SE);
306 if (!Diff)
307 return false;
308 Offsets.push_back(*Diff);
309 }
310 sort(Offsets);
311 return all_of(enumerate(Offsets), [&](const auto &P) {
312 return P.value() == Offsets.front() + static_cast<int64_t>(P.index());
313 });
314 });
315}
316
317} // namespace llvm::slpvectorizer
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
#define I(x, y, z)
Definition MD5.cpp:57
#define T
#define P(N)
static bool IsSelect(unsigned Opcode, bool CheckOnlyCC=false)
Check if the opcode is a SELECT or SELECT_CC variant.
Func MI getDebugLoc()))
This file contains some templates that are useful if you are working with the STL at all.
Provides some synthesis utilities to produce sequences of values.
This file implements the SmallBitVector class.
LLVM Basic Block Representation.
Definition BasicBlock.h:62
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Definition InstrTypes.h:740
@ ICMP_NE
not equal
Definition InstrTypes.h:762
This is an important base class in LLVM.
Definition Constant.h:44
static LLVM_ABI Constant * getAllOnesValue(Type *Ty)
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
A debug info location.
Definition DebugLoc.h:126
bool empty() const
Definition DenseMap.h:716
unsigned size() const
Definition DenseMap.h:717
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
Definition Dominators.h:122
LLVM_ABI bool dominates(const BasicBlock *BB, const Use &U) const
Return true if the (end of the) basic block BB dominates the use U.
Convenience struct for specifying and reasoning about fast-math flags.
Definition FMF.h:23
static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)
Definition Type.cpp:843
Common base class shared among various IRBuilders.
Definition IRBuilder.h:111
unsigned getOpcode() const
Returns a member of one of the enums like Instruction::Add.
BlockT * getLoopLatch() const
If there is a single latch block for this loop, return it.
LoopT * getLoopFor(const BlockT *BB) const
Return the inner most loop that BB lives in.
Represents a single loop in the control flow graph.
Definition LoopInfo.h:40
The main scalar evolution driver.
This is a 'bitvector' (really, a variable-sized bit array), optimized for the case when the array is ...
SmallBitVector & set()
bool test(unsigned Idx) const
Returns true if bit Idx is set.
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void assign(size_type NumElts, ValueParamT Elt)
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
This pass provides access to the codegen interfaces that are needed for IR-level transformations.
TargetCostKind
The kind of cost model.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
LLVM_ABI unsigned getIntegerBitWidth() const
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition Type.h:252
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:257
iterator_range< user_iterator > users()
Definition Value.h:428
const ParentTy * getParent() const
Definition ilist_node.h:34
bool match(Val *V, const Pattern &P)
ThreeOps_match< Cond, LHS, RHS, Instruction::Select > m_Select(const Cond &C, const LHS &L, const RHS &R)
Matches SelectInst.
auto m_BinOp()
Match an arbitrary binary operation and ignore it.
auto m_FMinimum(const Opnd0 &Op0, const Opnd1 &Op1)
auto m_Value()
Match an arbitrary value and ignore it.
auto m_FMaximum(const Opnd0 &Op0, const Opnd1 &Op1)
auto m_Intrinsic(const Ts &...Ops)
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
auto m_FMinNum(const Opnd0 &Op0, const Opnd1 &Op1)
auto m_FMaxNum(const Opnd0 &Op0, const Opnd1 &Op1)
A private "module" namespace for types and utilities used by this pass.
bool matchPackedFields(Value *V, unsigned MaxDepth, SmallVectorImpl< Value * > &Fields, SmallVectorImpl< Instruction * > &Chain)
Matches V as the zero-extended fields, placed one after another from the lowest bit and filling V com...
Instruction * getReductionInstr(const DominatorTree *DT, PHINode *P, BasicBlock *ParentBB, LoopInfo *LI)
Try to get a reduction instruction from phi node P in block ParentBB, considering incoming values fro...
Type * getBoolReduxWideTy(RecurKind RdxKind, Type *RootTy, Type *LeafTy)
Value * tryEmitBoolReduxBitcastCmp(IRBuilderBase &Builder, const TargetTransformInfo &TTI, RecurKind RdxKind, Value *Vec, const Value *Root, FastMathFlags FMF, const TTI::TargetCostKind CostKind)
Emits the booleanized logical and/or reduction of Vec with the i1 root Root as trunc+bitcast+cmp (all...
bool isReductionOfConsecutiveAccumulators(Instruction *Root, const LoopInfo &LI, const DataLayout &DL, ScalarEvolution &SE, unsigned MaxDepth, SmallVectorImpl< unsigned > &Shape, SmallPtrSetImpl< PHINode * > &Accs)
Checks if the reduction, rooted at Root, reduces the loop accumulators, whose updates are the same ex...
BoolBitmask isBoolBitmaskRdx(RecurKind RdxKind, const SmallDenseMap< Value *, NarrowedLeafInfo > &NarrowedLeafShifts, const DataLayout &DL)
InstructionCost getBoolReduxWideRdxCost(const TargetTransformInfo &TTI, RecurKind RdxKind, FixedVectorType *VecTy, const Value *Root, FastMathFlags FMF, const TTI::TargetCostKind CostKind)
Returns the cost of the booleanized logical and/or reduction of a vector of type VecTy with the i1 ro...
static bool matchRdxBop(Instruction *I, Value *&V0, Value *&V1)
Instruction * getNonPhiOperand(Instruction *I, PHINode *Phi)
bool isReductionCandidate(Instruction *I)
void collectNarrowedLeaves(Value *V, unsigned RdxOpcode, unsigned WideBW, unsigned MaxDepth, SmallVectorImpl< NarrowedLeafInfo > &Leaves, SmallVectorImpl< Instruction * > &ChainInsts)
Recursively collects the narrow leaves of the widened reduction value V.
BoolBitmask
The result of matching a boolean bitmask reduction over narrowed leaves.
This is an optimization pass for GlobalISel generic memory operations.
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
@ Known
Known to have no common set bits.
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition STLExtras.h:2570
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition STLExtras.h:2224
LLVM_ABI void computeKnownBits(const Value *V, KnownBits &Known, const DataLayout &DL, AssumptionCache *AC=nullptr, const Instruction *CtxI=nullptr, const DominatorTree *DT=nullptr, bool UseInstrInfo=true, unsigned Depth=0)
Determine which bits of V are known to be either zero or one and return them in the KnownZero/KnownOn...
auto map_range(ContainerTy &&C, FuncTy F)
Return a range that applies F to the elements of C.
Definition STLExtras.h:366
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1762
auto reverse(ContainerTy &&C)
Definition STLExtras.h:408
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1652
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
TargetTransformInfo TTI
RecurKind
These are the kinds of recurrences that we support.
@ Or
Bitwise or logical OR of integers.
@ And
Bitwise or logical AND of integers.
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
constexpr auto seq(T Begin, T End)
Iterate over an integral type from Begin up to - but not including - End.
Definition Sequence.h:341
Narrow reduction leaf: the value, the shift applied after widening and the mask applied in the narrow...
Definition SLPUtils.h:455