LLVM 24.0.0git
SLPCompatibilityAnalysis.h
Go to the documentation of this file.
1//===- SLPCompatibilityAnalysis.h - SLP same-opcode helpers ----*- 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// Internal header used by SLPVectorizer.cpp. It declares the same-opcode
10// compatibility primitives that decide whether a group of values can be
11// treated as sharing the same (or an interchangeable/alternate) opcode. These
12// do not depend on BoUpSLP or any other SLP-private type.
13//
14//===----------------------------------------------------------------------===//
15
16#ifndef LLVM_LIB_TRANSFORMS_VECTORIZE_SLPVECTORIZER_SLPCOMPATIBILITYANALYSIS_H
17#define LLVM_LIB_TRANSFORMS_VECTORIZE_SLPVECTORIZER_SLPCOMPATIBILITYANALYSIS_H
18
20#include "llvm/ADT/STLExtras.h"
23#include "llvm/IR/Instruction.h"
24
25#include <cstdint>
26#include <utility>
27
28namespace llvm {
29class Constant;
30class Value;
31} // namespace llvm
32
33namespace llvm::slpvectorizer {
34
35/// \returns true if \p Opcode is allowed as part of the main/alternate
36/// instruction for SLP vectorization.
37///
38/// Example of unsupported opcode is SDIV that can potentially cause UB if the
39/// "shuffled out" lane would result in division by zero.
40bool isValidForAlternation(unsigned Opcode);
41
42/// Helper class that determines VL can use the same opcode.
43/// Alternate instruction is supported. In addition, it supports interchangeable
44/// instruction. An interchangeable instruction is an instruction that can be
45/// converted to another instruction with same semantics. For example, x << 1 is
46/// equal to x * 2. x * 1 is equal to x | 0.
48 using MaskType = std::uint_fast32_t;
49 /// Sort SupportedOp because it is used by binary_search.
50 constexpr static unsigned SupportedOp[] = {
51 Instruction::Add, Instruction::FAdd, Instruction::Sub, Instruction::FSub,
52 Instruction::Mul, Instruction::Shl, Instruction::AShr, Instruction::And,
53 Instruction::Or, Instruction::Xor};
54 static_assert(llvm::is_sorted_constexpr(SupportedOp) &&
55 "SupportedOp is not sorted.");
56 enum : MaskType {
57 ShlBIT = 1,
58 AShrBIT = 1 << 1,
59 MulBIT = 1 << 2,
60 AddBIT = 1 << 3,
61 SubBIT = 1 << 4,
62 AndBIT = 1 << 5,
63 OrBIT = 1 << 6,
64 XorBIT = 1 << 7,
65 FAddBIT = 1 << 8,
66 FSubBIT = 1 << 9,
67 MainOpBIT = 1 << 10,
69 };
70 /// Return a non-nullptr if either operand of I is a ConstantInt (for the
71 /// integer opcodes) or a ConstantFP (for FAdd/FSub).
72 /// The second return value represents the operand position. We check the
73 /// right-hand side first (1). If the right hand side is not a constant and
74 /// the instruction is neither Sub, FSub, Shl, nor AShr, we then check the
75 /// left hand side (0).
76 static std::pair<Constant *, unsigned>
77 isBinOpWithConstant(const Instruction *I);
78 struct InterchangeableInfo {
79 const Instruction *I = nullptr;
80 /// The bit it sets represents whether MainOp can be converted to.
81 MaskType Mask = MainOpBIT | XorBIT | OrBIT | AndBIT | SubBIT | AddBIT |
82 MulBIT | AShrBIT | ShlBIT | FSubBIT | FAddBIT;
83 /// We cannot create an interchangeable instruction that does not exist in
84 /// VL. For example, VL [x + 0, y * 1] can be converted to [x << 0, y << 0],
85 /// but << does not exist in VL. In the end, we convert VL to [x * 1, y *
86 /// 1]. SeenBefore is used to know what operations have been seen before.
87 MaskType SeenBefore = 0;
88 InterchangeableInfo(const Instruction *I) : I(I) {}
89 /// Return false allows BinOpSameOpcodeHelper to find an alternate
90 /// instruction. Directly setting the mask will destroy the mask state,
91 /// preventing us from determining which instruction it should convert to.
92 bool trySet(MaskType OpcodeInMaskForm, MaskType InterchangeableMask);
93 bool equal(unsigned Opcode) {
94 return Opcode == I->getOpcode() && trySet(MainOpBIT, MainOpBIT);
95 }
96 unsigned getOpcode() const;
97 bool hasDefinedOpcode() const { return (Mask & SeenBefore) > 0; }
98 /// Return true if the instruction can be converted to \p Opcode.
99 bool hasCandidateOpcode(unsigned Opcode) const;
101 };
102 InterchangeableInfo MainOp;
103 InterchangeableInfo AltOp;
104 bool isValidForAlternation(const Instruction *I) const;
105 bool initializeAltOp(const Instruction *I);
106
107public:
109 const Instruction *AltOp = nullptr)
110 : MainOp(MainOp), AltOp(AltOp) {}
111 bool add(const Instruction *I);
112 unsigned getMainOpcode() const { return MainOp.getOpcode(); }
113 bool hasDefinedMainOpcode() const { return MainOp.hasDefinedOpcode(); }
114 /// Checks if the list of potential opcodes includes \p Opcode.
115 bool hasCandidateOpcode(unsigned Opcode) const {
116 return MainOp.hasCandidateOpcode(Opcode);
117 }
118 bool hasAltOp() const { return AltOp.I; }
119 unsigned getAltOpcode() const {
120 return hasAltOp() ? AltOp.getOpcode() : getMainOpcode();
121 }
122 bool hasDefinedAltOpcode() const {
123 return !hasAltOp() || AltOp.hasDefinedOpcode();
124 }
126 return MainOp.getOperand(I);
127 }
128};
129
130/// Main data required for vectorization of instructions.
132 /// MainOp and AltOp are primarily determined by getSameOpcode. Currently,
133 /// only BinaryOperator, CastInst, and CmpInst support alternate instructions
134 /// (i.e., AltOp is not equal to MainOp; this can be checked using
135 /// isAltShuffle).
136 /// A rare exception is TrySplitNode, where the InstructionsState is derived
137 /// from getMainAltOpsNoStateVL.
138 /// For those InstructionsState that use alternate instructions, the resulting
139 /// vectorized output ultimately comes from a shufflevector. For example,
140 /// given a vector list (VL):
141 /// VL[0] = add i32 a, e
142 /// VL[1] = sub i32 b, f
143 /// VL[2] = add i32 c, g
144 /// VL[3] = sub i32 d, h
145 /// The vectorized result would be:
146 /// intermediated_0 = add <4 x i32> <a, b, c, d>, <e, f, g, h>
147 /// intermediated_1 = sub <4 x i32> <a, b, c, d>, <e, f, g, h>
148 /// result = shufflevector <4 x i32> intermediated_0,
149 /// <4 x i32> intermediated_1,
150 /// <4 x i32> <i32 0, i32 5, i32 2, i32 7>
151 /// Since shufflevector is used in the final result, when calculating the cost
152 /// (getEntryCost), we must account for the usage of shufflevector in
153 /// GetVectorCost.
154 Instruction *MainOp = nullptr;
155 Instruction *AltOp = nullptr;
156 /// Whether the instruction state represents copyable instructions.
157 bool HasCopyables = false;
158 /// Index of the operand modeling the copyable values: the addend for
159 /// fmuladd (retried with a multiplicand), the first operand otherwise.
160 unsigned CopyableOpIdx = 0;
161 /// Whether copyable single-use fmuls are modeled as fmuladd(a, b, -0.0),
162 /// absorbing the multiply instead of computing and gathering its result.
163 bool AbsorbCopyableFMul = false;
164
165public:
167 assert(valid() && "InstructionsState is invalid.");
168 return MainOp;
169 }
170
172 assert(valid() && "InstructionsState is invalid.");
173 return AltOp;
174 }
175
176 /// The main/alternate opcodes for the list of instructions.
177 unsigned getOpcode() const { return getMainOp()->getOpcode(); }
178
179 unsigned getAltOpcode() const { return getAltOp()->getOpcode(); }
180
181 /// Some of the instructions in the list have alternate opcodes.
182 bool isAltShuffle() const { return getMainOp() != getAltOp(); }
183
184 /// Checks if \p I is the same operation as \p Op, distinguishing calls by
185 /// intrinsic ID (all calls share the Call opcode, so e.g. umax != smax).
186 static bool isSameOperation(const Instruction *I, const Instruction *Op);
187
188 /// Checks if the instruction matches either the main or alternate opcode.
189 /// \returns
190 /// - MainOp if \param I matches MainOp's opcode directly or can be converted
191 /// to it
192 /// - AltOp if \param I matches AltOp's opcode directly or can be converted to
193 /// it
194 /// - nullptr if \param I cannot be matched or converted to either opcode
196
197 /// Checks if main/alt instructions are shift operations.
198 bool isShiftOp() const {
199 return getMainOp()->isShift() && getAltOp()->isShift();
200 }
201
202 /// Checks if main/alt instructions are bitwise logic operations.
203 bool isBitwiseLogicOp() const {
205 }
206
207 /// Checks if main/alt instructions are mul/div/rem/fmul/fdiv/frem operations.
208 bool isMulDivLikeOp() const;
209
210 /// Checks if main/alt instructions are add/sub/fadd/fsub operations.
211 bool isAddSubLikeOp() const;
212
213 /// Checks if main/alt instructions are cmp operations.
214 bool isCmpOp() const {
215 return (getOpcode() == Instruction::ICmp ||
216 getOpcode() == Instruction::FCmp) &&
217 getAltOpcode() == getOpcode();
218 }
219
220 /// Checks if the current state is valid, i.e. has non-null MainOp
221 bool valid() const { return MainOp && AltOp; }
222
223 explicit operator bool() const { return valid(); }
224
227 bool HasCopyables = false)
228 : MainOp(MainOp), AltOp(AltOp), HasCopyables(HasCopyables),
229 CopyableOpIdx(MainOp && RecurrenceDescriptor::isFMulAddIntrinsic(MainOp)
230 ? 2
231 : 0) {}
232 static InstructionsState invalid() { return {nullptr, nullptr}; }
233
234 /// Checks if the value is a copyable element.
235 bool isCopyableElement(Value *V) const;
236
237 /// Checks if the value \p V is a transformed instruction, compatible either
238 /// with main or alternate ops.
239 bool isExpandedBinOp(Value *V) const;
240
241 /// Checks if the operand at index \p Idx of instruction \p I is an expanded
242 /// operand.
243 bool isExpandedOperand(Instruction *I, unsigned Idx) const;
244
245 /// Checks if the value is non-schedulable.
246 bool isNonSchedulable(Value *V) const;
247
248 /// Checks if the state represents copyable instructions.
250 assert(valid() && "InstructionsState is invalid.");
251 return HasCopyables;
252 }
253
254 /// Returns the index of the operand the copyable value is modeled in.
255 unsigned getCopyableOpIdx() const {
256 assert(valid() && "InstructionsState is invalid.");
257 return CopyableOpIdx;
258 }
259
260 /// Sets the index of the operand the copyable value is modeled in.
261 void setCopyableOpIdx(unsigned Idx) {
262 assert((Idx == 0 || Idx == 2) && "Unexpected copyable operand index.");
263 CopyableOpIdx = Idx;
264 }
265
266 /// Checks if copyable fmuls are absorbed as fmuladd(a, b, -0.0).
268 assert(valid() && "InstructionsState is invalid.");
269 return AbsorbCopyableFMul;
270 }
271
272 /// Sets the absorbed-fmul modeling for copyable fmuls.
273 void setAbsorbCopyableFMul(bool Absorb) { AbsorbCopyableFMul = Absorb; }
274};
275
276/// Checks if \p V is a single-use fmul with operands outside \p VL.
278
279/// Checks if \p V is a copyable single-use fmul, absorbable as
280/// fmuladd(a, b, -0.0).
281bool isAbsorbableCopyableFMul(const InstructionsState &S, Value *V);
282
283} // namespace llvm::slpvectorizer
284
285#endif // LLVM_LIB_TRANSFORMS_VECTORIZE_SLPVECTORIZER_SLPCOMPATIBILITYANALYSIS_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define I(x, y, z)
Definition MD5.cpp:57
This file contains some templates that are useful if you are working with the STL at all.
This file defines the SmallVector class.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
This is an important base class in LLVM.
Definition Constant.h:43
static bool isBitwiseLogicOp(unsigned Opcode)
Determine if the Opcode is and/or/xor.
unsigned getOpcode() const
Returns a member of one of the enums like Instruction::Add.
bool isShift() const
The RecurrenceDescriptor is used to identify recurrences variables in a loop.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
LLVM Value Representation.
Definition Value.h:75
SmallVector< Value * > getOperand(const Instruction *I) const
bool hasCandidateOpcode(unsigned Opcode) const
Checks if the list of potential opcodes includes Opcode.
BinOpSameOpcodeHelper(const Instruction *MainOp, const Instruction *AltOp=nullptr)
bool hasAbsorbedCopyableFMul() const
Checks if copyable fmuls are absorbed as fmuladd(a, b, -0.0).
Instruction * getMatchingMainOpOrAltOp(Instruction *I) const
Checks if the instruction matches either the main or alternate opcode.
bool areInstructionsWithCopyableElements() const
Checks if the state represents copyable instructions.
bool isCmpOp() const
Checks if main/alt instructions are cmp operations.
static bool isSameOperation(const Instruction *I, const Instruction *Op)
Checks if I is the same operation as Op, distinguishing calls by intrinsic ID (all calls share the Ca...
bool valid() const
Checks if the current state is valid, i.e. has non-null MainOp.
bool isExpandedBinOp(Value *V) const
Checks if the value V is a transformed instruction, compatible either with main or alternate ops.
bool isAddSubLikeOp() const
Checks if main/alt instructions are add/sub/fadd/fsub operations.
bool isShiftOp() const
Checks if main/alt instructions are shift operations.
bool isExpandedOperand(Instruction *I, unsigned Idx) const
Checks if the operand at index Idx of instruction I is an expanded operand.
bool isCopyableElement(Value *V) const
Checks if the value is a copyable element.
bool isAltShuffle() const
Some of the instructions in the list have alternate opcodes.
void setCopyableOpIdx(unsigned Idx)
Sets the index of the operand the copyable value is modeled in.
InstructionsState(Instruction *MainOp, Instruction *AltOp, bool HasCopyables=false)
bool isNonSchedulable(Value *V) const
Checks if the value is non-schedulable.
unsigned getCopyableOpIdx() const
Returns the index of the operand the copyable value is modeled in.
bool isBitwiseLogicOp() const
Checks if main/alt instructions are bitwise logic operations.
void setAbsorbCopyableFMul(bool Absorb)
Sets the absorbed-fmul modeling for copyable fmuls.
bool isMulDivLikeOp() const
Checks if main/alt instructions are mul/div/rem/fmul/fdiv/frem operations.
unsigned getOpcode() const
The main/alternate opcodes for the list of instructions.
A private "module" namespace for types and utilities used by this pass.
bool isValidForAlternation(unsigned Opcode)
bool isAbsorbableFMul(ArrayRef< Value * > VL, Value *V)
Checks if V is a single-use fmul with operands outside VL.
bool isAbsorbableCopyableFMul(const InstructionsState &S, Value *V)
Checks if V is a copyable single-use fmul, absorbable as fmuladd(a, b, -0.0).
This is an optimization pass for GlobalISel generic memory operations.
constexpr bool is_sorted_constexpr(R &&Range, Cmp C=Cmp{})
Check if elements in a range R are sorted with respect to a comparator C.
Definition STLExtras.h:1984
DWARFExpression::Operation Op
bool equal(L &&LRange, R &&RRange)
Wrapper function around std::equal to detect if pair-wise elements between two ranges are the same.
Definition STLExtras.h:2146