LLVM 22.0.0git
Legality.cpp
Go to the documentation of this file.
1//===- Legality.cpp -------------------------------------------------------===//
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
14#include "llvm/Support/Debug.h"
17
18namespace llvm::sandboxir {
19
20#ifndef NDEBUG
21void ShuffleMask::dump() const {
22 print(dbgs());
23 dbgs() << "\n";
24}
25
27 print(dbgs());
28 dbgs() << "\n";
29}
30#endif // NDEBUG
31
32std::optional<ResultReason>
33LegalityAnalysis::notVectorizableBasedOnOpcodesAndTypes(
34 ArrayRef<Value *> Bndl) {
35 auto *I0 = cast<Instruction>(Bndl[0]);
36 auto Opcode = I0->getOpcode();
37 // If they have different opcodes, then we cannot form a vector (for now).
38 if (any_of(drop_begin(Bndl), [Opcode](Value *V) {
39 return cast<Instruction>(V)->getOpcode() != Opcode;
40 }))
42
43 // If not the same scalar type, Pack. This will accept scalars and vectors as
44 // long as the element type is the same.
46 if (any_of(drop_begin(Bndl), [ElmTy0](Value *V) {
48 }))
50
51 // TODO: Allow vectorization of instrs with different flags as long as we
52 // change them to the least common one.
53 // For now pack if differnt FastMathFlags.
54 if (isa<FPMathOperator>(I0)) {
55 FastMathFlags FMF0 = cast<Instruction>(Bndl[0])->getFastMathFlags();
56 if (any_of(drop_begin(Bndl), [FMF0](auto *V) {
57 return cast<Instruction>(V)->getFastMathFlags() != FMF0;
58 }))
60 }
61
62 // TODO: Allow vectorization by using common flags.
63 // For now Pack if they don't have the same wrap flags.
64 bool CanHaveWrapFlags =
65 isa<OverflowingBinaryOperator>(I0) || isa<TruncInst>(I0);
66 if (CanHaveWrapFlags) {
67 bool NUW0 = I0->hasNoUnsignedWrap();
68 bool NSW0 = I0->hasNoSignedWrap();
69 if (any_of(drop_begin(Bndl), [NUW0, NSW0](auto *V) {
70 return cast<Instruction>(V)->hasNoUnsignedWrap() != NUW0 ||
71 cast<Instruction>(V)->hasNoSignedWrap() != NSW0;
72 })) {
74 }
75 }
76
77 // Now we need to do further checks for specific opcodes.
78 switch (Opcode) {
79 case Instruction::Opcode::ZExt:
80 case Instruction::Opcode::SExt:
81 case Instruction::Opcode::FPToUI:
82 case Instruction::Opcode::FPToSI:
83 case Instruction::Opcode::FPExt:
84 case Instruction::Opcode::PtrToAddr:
85 case Instruction::Opcode::PtrToInt:
86 case Instruction::Opcode::IntToPtr:
87 case Instruction::Opcode::SIToFP:
88 case Instruction::Opcode::UIToFP:
89 case Instruction::Opcode::Trunc:
90 case Instruction::Opcode::FPTrunc:
91 case Instruction::Opcode::BitCast: {
92 // We have already checked that they are of the same opcode.
93 assert(all_of(Bndl,
94 [Opcode](Value *V) {
95 return cast<Instruction>(V)->getOpcode() == Opcode;
96 }) &&
97 "Different opcodes, should have early returned!");
98 // But for these opcodes we should also check the operand type.
99 Type *FromTy0 = Utils::getExpectedType(I0->getOperand(0));
100 if (any_of(drop_begin(Bndl), [FromTy0](Value *V) {
101 return Utils::getExpectedType(cast<User>(V)->getOperand(0)) !=
102 FromTy0;
103 }))
105 return std::nullopt;
106 }
107 case Instruction::Opcode::FCmp:
108 case Instruction::Opcode::ICmp: {
109 // We need the same predicate..
110 auto Pred0 = cast<CmpInst>(I0)->getPredicate();
111 bool Same = all_of(Bndl, [Pred0](Value *V) {
112 return cast<CmpInst>(V)->getPredicate() == Pred0;
113 });
114 if (Same)
115 return std::nullopt;
117 }
118 case Instruction::Opcode::Select: {
119 auto *Sel0 = cast<SelectInst>(Bndl[0]);
120 auto *Cond0 = Sel0->getCondition();
122 // TODO: For now we don't vectorize if the lanes in the condition don't
123 // match those of the select instruction.
125 return std::nullopt;
126 }
127 case Instruction::Opcode::FNeg:
128 case Instruction::Opcode::Add:
129 case Instruction::Opcode::FAdd:
130 case Instruction::Opcode::Sub:
131 case Instruction::Opcode::FSub:
132 case Instruction::Opcode::Mul:
133 case Instruction::Opcode::FMul:
134 case Instruction::Opcode::FRem:
135 case Instruction::Opcode::UDiv:
136 case Instruction::Opcode::SDiv:
137 case Instruction::Opcode::FDiv:
138 case Instruction::Opcode::URem:
139 case Instruction::Opcode::SRem:
140 case Instruction::Opcode::Shl:
141 case Instruction::Opcode::LShr:
142 case Instruction::Opcode::AShr:
143 case Instruction::Opcode::And:
144 case Instruction::Opcode::Or:
145 case Instruction::Opcode::Xor:
146 return std::nullopt;
147 case Instruction::Opcode::Load:
148 if (VecUtils::areConsecutive<LoadInst>(Bndl, SE, DL))
149 return std::nullopt;
151 case Instruction::Opcode::Store:
152 if (VecUtils::areConsecutive<StoreInst>(Bndl, SE, DL))
153 return std::nullopt;
155 case Instruction::Opcode::PHI:
157 case Instruction::Opcode::Opaque:
159 case Instruction::Opcode::Br:
160 case Instruction::Opcode::Ret:
161 case Instruction::Opcode::AddrSpaceCast:
162 case Instruction::Opcode::InsertElement:
163 case Instruction::Opcode::InsertValue:
164 case Instruction::Opcode::ExtractElement:
165 case Instruction::Opcode::ExtractValue:
166 case Instruction::Opcode::ShuffleVector:
167 case Instruction::Opcode::Call:
168 case Instruction::Opcode::GetElementPtr:
169 case Instruction::Opcode::Switch:
171 case Instruction::Opcode::VAArg:
172 case Instruction::Opcode::Freeze:
173 case Instruction::Opcode::Fence:
174 case Instruction::Opcode::Invoke:
175 case Instruction::Opcode::CallBr:
176 case Instruction::Opcode::LandingPad:
177 case Instruction::Opcode::CatchPad:
178 case Instruction::Opcode::CleanupPad:
179 case Instruction::Opcode::CatchRet:
180 case Instruction::Opcode::CleanupRet:
181 case Instruction::Opcode::Resume:
182 case Instruction::Opcode::CatchSwitch:
183 case Instruction::Opcode::AtomicRMW:
184 case Instruction::Opcode::AtomicCmpXchg:
185 case Instruction::Opcode::Alloca:
186 case Instruction::Opcode::Unreachable:
188 }
189
190 return std::nullopt;
191}
192
193CollectDescr
194LegalityAnalysis::getHowToCollectValues(ArrayRef<Value *> Bndl) const {
195 SmallVector<CollectDescr::ExtractElementDescr, 4> Vec;
196 Vec.reserve(Bndl.size());
197 for (auto [Elm, V] : enumerate(Bndl)) {
198 if (auto *VecOp = IMaps.getVectorForOrig(V)) {
199 // If there is a vector containing `V`, then get the lane it came from.
200 std::optional<int> ExtractIdxOpt = IMaps.getOrigLane(VecOp, V);
201 // This could be a vector, like <2 x float> in which case the mask needs
202 // to enumerate all lanes.
203 for (unsigned Ln = 0, Lanes = VecUtils::getNumLanes(V); Ln != Lanes; ++Ln)
204 Vec.emplace_back(VecOp, ExtractIdxOpt ? *ExtractIdxOpt + Ln : -1);
205 } else {
206 Vec.emplace_back(V);
207 }
208 }
209 return CollectDescr(std::move(Vec));
210}
211
213 bool SkipScheduling) {
214 // If Bndl contains values other than instructions, we need to Pack.
215 if (any_of(Bndl, [](auto *V) { return !isa<Instruction>(V); }))
216 return createLegalityResult<Pack>(ResultReason::NotInstructions);
217 // Pack if not in the same BB.
218 auto *BB = cast<Instruction>(Bndl[0])->getParent();
219 if (any_of(drop_begin(Bndl),
220 [BB](auto *V) { return cast<Instruction>(V)->getParent() != BB; }))
221 return createLegalityResult<Pack>(ResultReason::DiffBBs);
222 // Pack if instructions repeat, i.e., require some sort of broadcast.
224 if (Unique.size() != Bndl.size())
225 return createLegalityResult<Pack>(ResultReason::RepeatedInstrs);
226
227 auto CollectDescrs = getHowToCollectValues(Bndl);
228 if (CollectDescrs.hasVectorInputs()) {
229 if (auto ValueShuffleOpt = CollectDescrs.getSingleInput()) {
230 auto [Vec, Mask] = *ValueShuffleOpt;
231 if (Mask.isIdentity())
232 return createLegalityResult<DiamondReuse>(Vec);
233 return createLegalityResult<DiamondReuseWithShuffle>(Vec, Mask);
234 }
235 return createLegalityResult<DiamondReuseMultiInput>(
236 std::move(CollectDescrs));
237 }
238
239 if (auto ReasonOpt = notVectorizableBasedOnOpcodesAndTypes(Bndl))
240 return createLegalityResult<Pack>(*ReasonOpt);
241
242 if (!SkipScheduling) {
243 // TODO: Try to remove the IBndl vector.
245 IBndl.reserve(Bndl.size());
246 for (auto *V : Bndl)
247 IBndl.push_back(cast<Instruction>(V));
248 if (!Sched.trySchedule(IBndl))
249 return createLegalityResult<Pack>(ResultReason::CantSchedule);
250 }
251
252 return createLegalityResult<Widen>();
253}
254
256 Sched.clear();
257 IMaps.clear();
258}
259} // namespace llvm::sandboxir
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:147
size_type size() const
Definition: SmallPtrSet.h:99
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
Definition: SmallPtrSet.h:541
void reserve(size_type N)
Definition: SmallVector.h:664
void push_back(const T &Elt)
Definition: SmallVector.h:414
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
LLVM Value Representation.
Definition: Value.h:75
std::optional< unsigned > getOrigLane(Action *Vec, Value *Orig) const
\Returns the lane of Orig before it got vectorized into Vec, or nullopt if not found.
Definition: InstrMaps.h:73
Action * getVectorForOrig(Value *Orig) const
\Returns the vector value that we got from vectorizing Orig, or nullptr if not found.
Definition: InstrMaps.h:67
LLVM_ABI const LegalityResult & canVectorize(ArrayRef< Value * > Bndl, bool SkipScheduling=false)
Checks if it's legal to vectorize the instructions in Bndl.
Definition: Legality.cpp:212
The legality outcome is represented by a class rather than an enum class because in some cases the le...
Definition: Legality.h:158
LLVM_DUMP_METHOD void dump() const
Definition: Legality.cpp:26
virtual void print(raw_ostream &OS) const
Definition: Legality.h:173
LLVM_ABI bool trySchedule(ArrayRef< Instruction * > Instrs)
Tries to build a schedule that includes all of Instrs scheduled at the same scheduling cycle.
Definition: Scheduler.cpp:290
void clear()
Clear the scheduler's state, including the DAG.
Definition: Scheduler.h:236
void print(raw_ostream &OS) const
Definition: Legality.h:73
LLVM_DUMP_METHOD void dump() const
Definition: Legality.cpp:21
static Type * getExpectedType(const Value *V)
\Returns the expected type of Value V.
Definition: Utils.h:32
A SandboxIR Value has users. This is the base class.
Definition: Value.h:66
static unsigned getNumLanes(Type *Ty)
\Returns the number of vector lanes of Ty or 1 if not a vector.
Definition: VecUtils.h:91
static Type * getElementType(Type *Ty)
Returns Ty if scalar or its element type if vector.
Definition: VecUtils.h:51
Type
MessagePack types as defined in the standard, with the exception of Integer being divided into a sign...
Definition: MsgPackReader.h:54
static SmallVector< Value *, 4 > getOperand(ArrayRef< Value * > Bndl, unsigned OpIdx)
Definition: BottomUpVec.cpp:43
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition: STLExtras.h:338
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:1744
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:2491
constexpr from_range_t from_range
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:1751
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:207