LLVM 24.0.0git
SLPCompatibilityAnalysis.cpp
Go to the documentation of this file.
1//===- SLPCompatibilityAnalysis.cpp - SLP same-opcode 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
10#include "SLPUtils.h"
11
12#include "llvm/ADT/APInt.h"
13#include "llvm/ADT/STLExtras.h"
15#include "llvm/IR/Constants.h"
16#include "llvm/IR/InstrTypes.h"
17#include "llvm/IR/Instruction.h"
18#include "llvm/IR/Value.h"
21
22#include <utility>
23
24using namespace llvm;
25
26namespace llvm::slpvectorizer {
27
28bool isValidForAlternation(unsigned Opcode) {
29 return !Instruction::isIntDivRem(Opcode);
30}
31
32std::pair<Constant *, unsigned>
33BinOpSameOpcodeHelper::isBinOpWithConstant(const Instruction *I) {
34 [[maybe_unused]] unsigned Opcode = I->getOpcode();
35 assert(binary_search(SupportedOp, Opcode) && "Unsupported opcode.");
36 (void)SupportedOp;
37 auto *BinOp = cast<BinaryOperator>(I);
38 auto GetConstant = [](Value *V) -> Constant * {
39 if (auto *CI = dyn_cast<ConstantInt>(V))
40 return CI;
41 return dyn_cast<ConstantFP>(V);
42 };
43 if (Constant *C = GetConstant(BinOp->getOperand(1)))
44 return {C, 1};
45 if (!isCommutative(I))
46 return {nullptr, 0};
47 if (Constant *C = GetConstant(BinOp->getOperand(0)))
48 return {C, 0};
49 return {nullptr, 0};
50}
51
52bool BinOpSameOpcodeHelper::InterchangeableInfo::trySet(
53 MaskType OpcodeInMaskForm, MaskType InterchangeableMask) {
54 if (Mask & InterchangeableMask) {
55 SeenBefore |= OpcodeInMaskForm;
56 Mask &= InterchangeableMask;
57 return true;
58 }
59 return false;
60}
61
62unsigned BinOpSameOpcodeHelper::InterchangeableInfo::getOpcode() const {
63 MaskType Candidate = Mask & SeenBefore;
64 if (Candidate & MainOpBIT)
65 return I->getOpcode();
66 if (Candidate & ShlBIT)
67 return Instruction::Shl;
68 if (Candidate & AShrBIT)
69 return Instruction::AShr;
70 if (Candidate & MulBIT)
71 return Instruction::Mul;
72 if (Candidate & AddBIT)
73 return Instruction::Add;
74 if (Candidate & SubBIT)
75 return Instruction::Sub;
76 if (Candidate & FAddBIT)
77 return Instruction::FAdd;
78 if (Candidate & FSubBIT)
79 return Instruction::FSub;
80 if (Candidate & AndBIT)
81 return Instruction::And;
82 if (Candidate & OrBIT)
83 return Instruction::Or;
84 if (Candidate & XorBIT)
85 return Instruction::Xor;
86 llvm_unreachable("Cannot find interchangeable instruction.");
87}
88
89bool BinOpSameOpcodeHelper::InterchangeableInfo::hasCandidateOpcode(
90 unsigned Opcode) const {
91 MaskType Candidate = Mask & SeenBefore;
92 switch (Opcode) {
93 case Instruction::Shl:
94 return Candidate & ShlBIT;
95 case Instruction::AShr:
96 return Candidate & AShrBIT;
97 case Instruction::Mul:
98 return Candidate & MulBIT;
99 case Instruction::Add:
100 return Candidate & AddBIT;
101 case Instruction::Sub:
102 return Candidate & SubBIT;
103 case Instruction::And:
104 return Candidate & AndBIT;
105 case Instruction::Or:
106 return Candidate & OrBIT;
107 case Instruction::Xor:
108 return Candidate & XorBIT;
109 case Instruction::FAdd:
110 return Candidate & FAddBIT;
111 case Instruction::FSub:
112 return Candidate & FSubBIT;
113 case Instruction::LShr:
114 case Instruction::FMul:
115 case Instruction::SDiv:
116 case Instruction::UDiv:
117 case Instruction::FDiv:
118 case Instruction::SRem:
119 case Instruction::URem:
120 case Instruction::FRem:
121 return false;
122 default:
123 break;
124 }
125 llvm_unreachable("Cannot find interchangeable instruction.");
126}
127
128SmallVector<Value *> BinOpSameOpcodeHelper::InterchangeableInfo::getOperand(
129 const Instruction *To) const {
130 unsigned ToOpcode = To->getOpcode();
131 unsigned FromOpcode = I->getOpcode();
132 if (FromOpcode == ToOpcode)
133 return SmallVector<Value *>(I->operands());
134 assert(binary_search(SupportedOp, ToOpcode) && "Unsupported opcode.");
135 auto [C, Pos] = isBinOpWithConstant(I);
136 Type *RHSType = I->getOperand(Pos)->getType();
137 Constant *RHS;
138 if (auto *CFP = dyn_cast<ConstantFP>(C)) {
139 // fsub(x, c) == fadd(x, -c) for every FP constant c, since IEEE 754
140 // defines subtraction as addition of the negated operand.
141 assert(is_contained({Instruction::FAdd, Instruction::FSub}, ToOpcode) &&
142 "Cannot convert the instruction.");
143 RHS = ConstantFP::get(RHSType, -CFP->getValueAPF());
144 } else {
145 auto *CI = cast<ConstantInt>(C);
146 const APInt &FromCIValue = CI->getValue();
147 unsigned FromCIValueBitWidth = FromCIValue.getBitWidth();
148 switch (FromOpcode) {
149 case Instruction::Shl:
150 if (ToOpcode == Instruction::Add && FromCIValue.isOne())
151 return {I->getOperand(0), I->getOperand(0)};
152 if (ToOpcode == Instruction::Mul) {
153 RHS = ConstantInt::get(RHSType,
154 APInt::getOneBitSet(FromCIValueBitWidth,
155 FromCIValue.getZExtValue()));
156 } else {
157 assert(FromCIValue.isZero() && "Cannot convert the instruction.");
158 RHS = ConstantExpr::getBinOpIdentity(ToOpcode, RHSType,
159 /*AllowRHSConstant=*/true);
160 }
161 break;
162 case Instruction::Mul:
163 assert(FromCIValue.isPowerOf2() && "Cannot convert the instruction.");
164 if (ToOpcode == Instruction::Shl) {
165 RHS = ConstantInt::get(
166 RHSType, APInt(FromCIValueBitWidth, FromCIValue.logBase2()));
167 } else {
168 assert(FromCIValue.isOne() && "Cannot convert the instruction.");
169 RHS = ConstantExpr::getBinOpIdentity(ToOpcode, RHSType,
170 /*AllowRHSConstant=*/true);
171 }
172 break;
173 case Instruction::Add:
174 case Instruction::Sub:
175 if (FromCIValue.isZero()) {
176 RHS = ConstantExpr::getBinOpIdentity(ToOpcode, RHSType,
177 /*AllowRHSConstant=*/true);
178 } else {
179 assert(is_contained({Instruction::Add, Instruction::Sub}, ToOpcode) &&
180 "Cannot convert the instruction.");
181 APInt NegatedVal = APInt(FromCIValue);
182 NegatedVal.negate();
183 RHS = ConstantInt::get(RHSType, NegatedVal);
184 }
185 break;
186 case Instruction::And:
187 assert(FromCIValue.isAllOnes() && "Cannot convert the instruction.");
188 RHS = ConstantExpr::getBinOpIdentity(ToOpcode, RHSType,
189 /*AllowRHSConstant=*/true);
190 break;
191 default:
192 assert(FromCIValue.isZero() && "Cannot convert the instruction.");
193 RHS = ConstantExpr::getBinOpIdentity(ToOpcode, RHSType,
194 /*AllowRHSConstant=*/true);
195 break;
196 }
197 }
198 Value *LHS = I->getOperand(1 - Pos);
199 // If the target opcode is non-commutative (e.g., shl, sub),
200 // force the variable to the left and the constant to the right.
201 if (Pos == 1 || !Instruction::isCommutative(ToOpcode))
202 return SmallVector<Value *>({LHS, RHS});
203
204 return SmallVector<Value *>({RHS, LHS});
205}
206
207bool BinOpSameOpcodeHelper::isValidForAlternation(const Instruction *I) const {
208 return slpvectorizer::isValidForAlternation(MainOp.I->getOpcode()) &&
210}
211
212bool BinOpSameOpcodeHelper::initializeAltOp(const Instruction *I) {
213 if (AltOp.I)
214 return true;
215 if (!isValidForAlternation(I))
216 return false;
217 AltOp.I = I;
218 return true;
219}
220
223 "BinOpSameOpcodeHelper only accepts BinaryOperator.");
224 unsigned Opcode = I->getOpcode();
225 MaskType OpcodeInMaskForm;
226 // Prefer Shl, AShr, Mul, Add, Sub, And, Or, Xor, FAdd and FSub over
227 // MainOp.
228 switch (Opcode) {
229 case Instruction::Shl:
230 OpcodeInMaskForm = ShlBIT;
231 break;
232 case Instruction::AShr:
233 OpcodeInMaskForm = AShrBIT;
234 break;
235 case Instruction::Mul:
236 OpcodeInMaskForm = MulBIT;
237 break;
238 case Instruction::Add:
239 OpcodeInMaskForm = AddBIT;
240 break;
241 case Instruction::Sub:
242 OpcodeInMaskForm = SubBIT;
243 break;
244 case Instruction::And:
245 OpcodeInMaskForm = AndBIT;
246 break;
247 case Instruction::Or:
248 OpcodeInMaskForm = OrBIT;
249 break;
250 case Instruction::Xor:
251 OpcodeInMaskForm = XorBIT;
252 break;
253 case Instruction::FAdd:
254 OpcodeInMaskForm = FAddBIT;
255 break;
256 case Instruction::FSub:
257 OpcodeInMaskForm = FSubBIT;
258 break;
259 default:
260 return MainOp.equal(Opcode) || (initializeAltOp(I) && AltOp.equal(Opcode));
261 }
262 MaskType InterchangeableMask = OpcodeInMaskForm;
263 auto [C, Pos] = isBinOpWithConstant(I);
264 if (auto *CI = dyn_cast_or_null<ConstantInt>(C)) {
265 constexpr MaskType CanBeAll =
266 XorBIT | OrBIT | AndBIT | SubBIT | AddBIT | MulBIT | AShrBIT | ShlBIT;
267 const APInt &CIValue = CI->getValue();
268 switch (Opcode) {
269 case Instruction::Shl:
270 if (CIValue.ult(CIValue.getBitWidth()))
271 InterchangeableMask = CIValue.isZero() ? CanBeAll : MulBIT | ShlBIT;
272 if (CIValue.isOne())
273 InterchangeableMask |= AddBIT;
274 break;
275 case Instruction::Mul:
276 if (CIValue.isOne()) {
277 InterchangeableMask = CanBeAll;
278 break;
279 }
280 if (CIValue.isPowerOf2())
281 InterchangeableMask = MulBIT | ShlBIT;
282 break;
283 case Instruction::Add:
284 case Instruction::Sub:
285 InterchangeableMask = CIValue.isZero() ? CanBeAll : SubBIT | AddBIT;
286 break;
287 case Instruction::And:
288 if (CIValue.isAllOnes())
289 InterchangeableMask = CanBeAll;
290 break;
291 case Instruction::Xor:
292 if (CIValue.isZero())
293 InterchangeableMask = XorBIT | OrBIT | SubBIT | AddBIT;
294 break;
295 default:
296 if (CIValue.isZero())
297 InterchangeableMask = CanBeAll;
298 break;
299 }
300 } else if (C && Pos == 1) {
301 // FAdd/FSub with a constant RHS: negating the constant always
302 // converts one into the other, so no value check is needed. A
303 // constant LHS (Pos == 0, e.g. "0.0 - x") is excluded: unlike a
304 // constant RHS, it cannot be moved to the other opcode without also
305 // swapping the variable operand, which would misalign it against
306 // lanes that keep their native opcode (their variable operand stays
307 // on the other side).
308 InterchangeableMask = FSubBIT | FAddBIT;
309 }
310 return MainOp.trySet(OpcodeInMaskForm, InterchangeableMask) ||
311 (initializeAltOp(I) &&
312 AltOp.trySet(OpcodeInMaskForm, InterchangeableMask));
313}
314
315} // namespace llvm::slpvectorizer
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file implements a class to represent arbitrary precision integral constant values and operations...
This file contains the declarations for the subclasses of Constant, which represent the different fla...
#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.
Value * RHS
Value * LHS
Class for arbitrary precision integers.
Definition APInt.h:78
uint64_t getZExtValue() const
Get zero extended value.
Definition APInt.h:1565
bool isAllOnes() const
Determine if all bits are set. This is true for zero-width values.
Definition APInt.h:372
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
Definition APInt.h:381
unsigned getBitWidth() const
Return the number of bits in the APInt.
Definition APInt.h:1513
bool ult(const APInt &RHS) const
Unsigned less than comparison.
Definition APInt.h:1120
unsigned logBase2() const
Definition APInt.h:1786
bool isPowerOf2() const
Check if this APInt's value is a power of two greater than zero.
Definition APInt.h:441
bool isOne() const
Determine if this is a value of 1.
Definition APInt.h:390
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
Definition APInt.h:240
static LLVM_ABI Constant * getBinOpIdentity(unsigned Opcode, Type *Ty, bool AllowRHSConstant=false, bool NSZ=false)
Return the identity constant for a binary opcode.
This is an important base class in LLVM.
Definition Constant.h:43
LLVM_ABI bool isCommutative() const LLVM_READONLY
Return true if the instruction is commutative:
unsigned getOpcode() const
Returns a member of one of the enums like Instruction::Add.
bool isIntDivRem() const
LLVM Value Representation.
Definition Value.h:75
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
A private "module" namespace for types and utilities used by this pass.
bool isValidForAlternation(unsigned Opcode)
bool isCommutative(const Instruction *I, const Value *ValWithUses, bool IsCopyable)
Definition SLPUtils.cpp:137
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
auto binary_search(R &&Range, T &&Value)
Provide wrappers to std::binary_search which take ranges instead of having to pass begin/end explicit...
Definition STLExtras.h:2039
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:753
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
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
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1947