1//===- RISCVTargetTransformInfo.h - RISC-V specific TTI ---------*- 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/// \file
9/// This file defines a TargetTransformInfoImplBase conforming object specific
10/// to the RISC-V target machine. It uses the target's detailed information to
11/// provide more precise answers to certain TTI queries, while letting the
12/// target independent and default TTI implementations handle the rest.
13///
14//===----------------------------------------------------------------------===//
15
16#ifndef LLVM_LIB_TARGET_RISCV_RISCVTARGETTRANSFORMINFO_H
17#define LLVM_LIB_TARGET_RISCV_RISCVTARGETTRANSFORMINFO_H
18
19#include "RISCVSubtarget.h"
20#include "RISCVTargetMachine.h"
21#include "llvm/Analysis/TargetTransformInfo.h"
22#include "llvm/CodeGen/BasicTTIImpl.h"
23#include "llvm/IR/Function.h"
24#include <optional>
25
26namespace llvm {
27
28class RISCVTTIImpl final : public BasicTTIImplBase<RISCVTTIImpl> {
29 using BaseT = BasicTTIImplBase<RISCVTTIImpl>;
30 using TTI = TargetTransformInfo;
31
32 friend BaseT;
33
34 const RISCVSubtarget *ST;
35 const RISCVTargetLowering *TLI;
36
37 const RISCVSubtarget *getST() const { return ST; }
38 const RISCVTargetLowering *getTLI() const { return TLI; }
39
40 /// This function returns an estimate for VL to be used in VL based terms
41 /// of the cost model. For fixed length vectors, this is simply the
42 /// vector length. For scalable vectors, we return results consistent
43 /// with getVScaleForTuning under the assumption that clients are also
44 /// using that when comparing costs between scalar and vector representation.
45 /// This does unfortunately mean that we can both undershoot and overshot
46 /// the true cost significantly if getVScaleForTuning is wildly off for the
47 /// actual target hardware.
48 unsigned getEstimatedVLFor(VectorType *Ty) const;
49
50 /// This function calculates the costs for one or more RVV opcodes based
51 /// on the vtype and the cost kind.
52 /// \param Opcodes A list of opcodes of the RVV instruction to evaluate.
53 /// \param VT The MVT of vtype associated with the RVV instructions.
54 /// For widening/narrowing instructions where the result and source types
55 /// differ, it is important to check the spec to determine whether the vtype
56 /// refers to the result or source type.
57 /// \param CostKind The type of cost to compute.
58 InstructionCost getRISCVInstructionCost(ArrayRef<unsigned> OpCodes, MVT VT,
59 TTI::TargetCostKind CostKind) const;
60
61 /// Return the cost of accessing a constant pool entry of the specified
62 /// type.
63 InstructionCost getConstantPoolLoadCost(Type *Ty,
64 TTI::TargetCostKind CostKind) const;
65
66 /// If this shuffle can be lowered as a masked slide pair (at worst),
67 /// return a cost for it.
68 InstructionCost getSlideCost(FixedVectorType *Tp, ArrayRef<int> Mask,
69 TTI::TargetCostKind CostKind) const;
70
71public:
72 explicit RISCVTTIImpl(const RISCVTargetMachine *TM, const Function &F)
73 : BaseT(TM, F.getDataLayout()), ST(TM->getSubtargetImpl(F)),
74 TLI(ST->getTargetLowering()) {}
75
76 /// Return the cost of materializing an immediate for a value operand of
77 /// a store instruction.
78 InstructionCost getStoreImmCost(Type *VecTy, TTI::OperandValueInfo OpInfo,
79 TTI::TargetCostKind CostKind) const;
80
81 InstructionCost getIntImmCost(const APInt &Imm, Type *Ty,
82 TTI::TargetCostKind CostKind) const override;
83 InstructionCost getIntImmCostInst(unsigned Opcode, unsigned Idx,
84 const APInt &Imm, Type *Ty,
85 TTI::TargetCostKind CostKind,
86 Instruction *Inst = nullptr) const override;
87 InstructionCost
88 getIntImmCostIntrin(Intrinsic::ID IID, unsigned Idx, const APInt &Imm,
89 Type *Ty, TTI::TargetCostKind CostKind) const override;
90
91 /// \name EVL Support for predicated vectorization.
92 /// Whether the target supports the %evl parameter of VP intrinsic efficiently
93 /// in hardware. (see LLVM Language Reference - "Vector Predication
94 /// Intrinsics",
95 /// https://llvm.org/docs/LangRef.html#vector-predication-intrinsics and
96 /// "IR-level VP intrinsics",
97 /// https://llvm.org/docs/Proposals/VectorPredication.html#ir-level-vp-intrinsics).
98 bool hasActiveVectorLength() const override;
99
100 TargetTransformInfo::PopcntSupportKind
101 getPopcntSupport(unsigned TyWidth) const override;
102
103 InstructionCost getPartialReductionCost(
104 unsigned Opcode, Type *InputTypeA, Type *InputTypeB, Type *AccumType,
105 ElementCount VF, TTI::PartialReductionExtendKind OpAExtend,
106 TTI::PartialReductionExtendKind OpBExtend, std::optional<unsigned> BinOp,
107 TTI::TargetCostKind CostKind) const override;
108
109 bool shouldExpandReduction(const IntrinsicInst *II) const override;
110 bool supportsScalableVectors() const override {
111 return ST->hasVInstructions();
112 }
113 bool enableOrderedReductions() const override { return true; }
114 bool enableScalableVectorization() const override {
115 return ST->hasVInstructions();
116 }
117 TailFoldingStyle
118 getPreferredTailFoldingStyle(bool IVUpdateMayOverflow) const override {
119 return ST->hasVInstructions() ? TailFoldingStyle::Data
120 : TailFoldingStyle::DataWithoutLaneMask;
121 }
122 std::optional<unsigned> getMaxVScale() const override;
123 std::optional<unsigned> getVScaleForTuning() const override;
124
125 TypeSize
126 getRegisterBitWidth(TargetTransformInfo::RegisterKind K) const override;
127
128 unsigned getRegUsageForType(Type *Ty) const override;
129
130 unsigned getMaximumVF(unsigned ElemWidth, unsigned Opcode) const override;
131
132 bool preferAlternateOpcodeVectorization() const override { return false; }
133
134 bool preferEpilogueVectorization() const override {
135 // Epilogue vectorization is usually unprofitable - tail folding or
136 // a smaller VF would have been better. This a blunt hammer - we
137 // should re-examine this once vectorization is better tuned.
138 return false;
139 }
140
141 InstructionCost
142 getMaskedMemoryOpCost(unsigned Opcode, Type *Src, Align Alignment,
143 unsigned AddressSpace,
144 TTI::TargetCostKind CostKind) const override;
145
146 InstructionCost
147 getPointersChainCost(ArrayRef<const Value *> Ptrs, const Value *Base,
148 const TTI::PointersChainInfo &Info, Type *AccessTy,
149 TTI::TargetCostKind CostKind) const override;
150
151 void getUnrollingPreferences(Loop *L, ScalarEvolution &SE,
152 TTI::UnrollingPreferences &UP,
153 OptimizationRemarkEmitter *ORE) const override;
154
155 void getPeelingPreferences(Loop *L, ScalarEvolution &SE,
156 TTI::PeelingPreferences &PP) const override;
157
158 unsigned getMinVectorRegisterBitWidth() const override {
159 return ST->useRVVForFixedLengthVectors() ? 16 : 0;
160 }
161
162 InstructionCost
163 getShuffleCost(TTI::ShuffleKind Kind, VectorType *DstTy, VectorType *SrcTy,
164 ArrayRef<int> Mask, TTI::TargetCostKind CostKind, int Index,
165 VectorType *SubTp, ArrayRef<const Value *> Args = {},
166 const Instruction *CxtI = nullptr) const override;
167
168 InstructionCost getScalarizationOverhead(
169 VectorType *Ty, const APInt &DemandedElts, bool Insert, bool Extract,
170 TTI::TargetCostKind CostKind, bool ForPoisonSrc = true,
171 ArrayRef<Value *> VL = {}) const override;
172
173 InstructionCost
174 getIntrinsicInstrCost(const IntrinsicCostAttributes &ICA,
175 TTI::TargetCostKind CostKind) const override;
176
177 InstructionCost getInterleavedMemoryOpCost(
178 unsigned Opcode, Type *VecTy, unsigned Factor, ArrayRef<unsigned> Indices,
179 Align Alignment, unsigned AddressSpace, TTI::TargetCostKind CostKind,
180 bool UseMaskForCond = false, bool UseMaskForGaps = false) const override;
181
182 InstructionCost getGatherScatterOpCost(unsigned Opcode, Type *DataTy,
183 const Value *Ptr, bool VariableMask,
184 Align Alignment,
185 TTI::TargetCostKind CostKind,
186 const Instruction *I) const override;
187
188 InstructionCost
189 getExpandCompressMemoryOpCost(unsigned Opcode, Type *Src, bool VariableMask,
190 Align Alignment, TTI::TargetCostKind CostKind,
191 const Instruction *I = nullptr) const override;
192
193 InstructionCost getStridedMemoryOpCost(unsigned Opcode, Type *DataTy,
194 const Value *Ptr, bool VariableMask,
195 Align Alignment,
196 TTI::TargetCostKind CostKind,
197 const Instruction *I) const override;
198
199 InstructionCost
200 getCostOfKeepingLiveOverCall(ArrayRef<Type *> Tys) const override;
201
202 InstructionCost
203 getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src,
204 TTI::CastContextHint CCH, TTI::TargetCostKind CostKind,
205 const Instruction *I = nullptr) const override;
206
207 InstructionCost
208 getMinMaxReductionCost(Intrinsic::ID IID, VectorType *Ty, FastMathFlags FMF,
209 TTI::TargetCostKind CostKind) const override;
210
211 InstructionCost
212 getArithmeticReductionCost(unsigned Opcode, VectorType *Ty,
213 std::optional<FastMathFlags> FMF,
214 TTI::TargetCostKind CostKind) const override;
215
216 InstructionCost
217 getExtendedReductionCost(unsigned Opcode, bool IsUnsigned, Type *ResTy,
218 VectorType *ValTy, std::optional<FastMathFlags> FMF,
219 TTI::TargetCostKind CostKind) const override;
220
221 InstructionCost getMemoryOpCost(
222 unsigned Opcode, Type *Src, Align Alignment, unsigned AddressSpace,
223 TTI::TargetCostKind CostKind,
224 TTI::OperandValueInfo OpdInfo = {.Kind: TTI::OK_AnyValue, .Properties: TTI::OP_None},
225 const Instruction *I = nullptr) const override;
226
227 InstructionCost getCmpSelInstrCost(
228 unsigned Opcode, Type *ValTy, Type *CondTy, CmpInst::Predicate VecPred,
229 TTI::TargetCostKind CostKind,
230 TTI::OperandValueInfo Op1Info = {.Kind: TTI::OK_AnyValue, .Properties: TTI::OP_None},
231 TTI::OperandValueInfo Op2Info = {.Kind: TTI::OK_AnyValue, .Properties: TTI::OP_None},
232 const Instruction *I = nullptr) const override;
233
234 InstructionCost getCFInstrCost(unsigned Opcode, TTI::TargetCostKind CostKind,
235 const Instruction *I = nullptr) const override;
236
237 using BaseT::getVectorInstrCost;
238 InstructionCost getVectorInstrCost(unsigned Opcode, Type *Val,
239 TTI::TargetCostKind CostKind,
240 unsigned Index, const Value *Op0,
241 const Value *Op1) const override;
242
243 InstructionCost getArithmeticInstrCost(
244 unsigned Opcode, Type *Ty, TTI::TargetCostKind CostKind,
245 TTI::OperandValueInfo Op1Info = {.Kind: TTI::OK_AnyValue, .Properties: TTI::OP_None},
246 TTI::OperandValueInfo Op2Info = {.Kind: TTI::OK_AnyValue, .Properties: TTI::OP_None},
247 ArrayRef<const Value *> Args = {},
248 const Instruction *CxtI = nullptr) const override;
249
250 bool isElementTypeLegalForScalableVector(Type *Ty) const override {
251 return TLI->isLegalElementTypeForRVV(ScalarTy: TLI->getValueType(DL, Ty));
252 }
253
254 bool isLegalMaskedLoadStore(Type *DataType, Align Alignment) const {
255 if (!ST->hasVInstructions())
256 return false;
257
258 EVT DataTypeVT = TLI->getValueType(DL, Ty: DataType);
259
260 // Only support fixed vectors if we know the minimum vector size.
261 if (DataTypeVT.isFixedLengthVector() && !ST->useRVVForFixedLengthVectors())
262 return false;
263
264 EVT ElemType = DataTypeVT.getScalarType();
265 if (!ST->enableUnalignedVectorMem() && Alignment < ElemType.getStoreSize())
266 return false;
267
268 return TLI->isLegalElementTypeForRVV(ScalarTy: ElemType);
269 }
270
271 bool isLegalMaskedLoad(Type *DataType, Align Alignment,
272 unsigned /*AddressSpace*/) const override {
273 return isLegalMaskedLoadStore(DataType, Alignment);
274 }
275 bool isLegalMaskedStore(Type *DataType, Align Alignment,
276 unsigned /*AddressSpace*/) const override {
277 return isLegalMaskedLoadStore(DataType, Alignment);
278 }
279
280 bool isLegalMaskedGatherScatter(Type *DataType, Align Alignment) const {
281 if (!ST->hasVInstructions())
282 return false;
283
284 EVT DataTypeVT = TLI->getValueType(DL, Ty: DataType);
285
286 // Only support fixed vectors if we know the minimum vector size.
287 if (DataTypeVT.isFixedLengthVector() && !ST->useRVVForFixedLengthVectors())
288 return false;
289
290 // We also need to check if the vector of address is valid.
291 EVT PointerTypeVT = EVT(TLI->getPointerTy(DL));
292 if (DataTypeVT.isScalableVector() &&
293 !TLI->isLegalElementTypeForRVV(ScalarTy: PointerTypeVT))
294 return false;
295
296 EVT ElemType = DataTypeVT.getScalarType();
297 if (!ST->enableUnalignedVectorMem() && Alignment < ElemType.getStoreSize())
298 return false;
299
300 return TLI->isLegalElementTypeForRVV(ScalarTy: ElemType);
301 }
302
303 bool isLegalMaskedGather(Type *DataType, Align Alignment) const override {
304 return isLegalMaskedGatherScatter(DataType, Alignment);
305 }
306 bool isLegalMaskedScatter(Type *DataType, Align Alignment) const override {
307 return isLegalMaskedGatherScatter(DataType, Alignment);
308 }
309
310 bool forceScalarizeMaskedGather(VectorType *VTy,
311 Align Alignment) const override {
312 // Scalarize masked gather for RV64 if EEW=64 indices aren't supported.
313 return ST->is64Bit() && !ST->hasVInstructionsI64();
314 }
315
316 bool forceScalarizeMaskedScatter(VectorType *VTy,
317 Align Alignment) const override {
318 // Scalarize masked scatter for RV64 if EEW=64 indices aren't supported.
319 return ST->is64Bit() && !ST->hasVInstructionsI64();
320 }
321
322 bool isLegalStridedLoadStore(Type *DataType, Align Alignment) const override {
323 EVT DataTypeVT = TLI->getValueType(DL, Ty: DataType);
324 return TLI->isLegalStridedLoadStore(DataType: DataTypeVT, Alignment);
325 }
326
327 bool isLegalInterleavedAccessType(VectorType *VTy, unsigned Factor,
328 Align Alignment,
329 unsigned AddrSpace) const override {
330 return TLI->isLegalInterleavedAccessType(VTy, Factor, Alignment, AddrSpace,
331 DL);
332 }
333
334 bool isLegalMaskedExpandLoad(Type *DataType, Align Alignment) const override;
335
336 bool isLegalMaskedCompressStore(Type *DataTy, Align Alignment) const override;
337
338 bool isVScaleKnownToBeAPowerOfTwo() const override {
339 return TLI->isVScaleKnownToBeAPowerOfTwo();
340 }
341
342 /// \returns How the target needs this vector-predicated operation to be
343 /// transformed.
344 TargetTransformInfo::VPLegalization
345 getVPLegalizationStrategy(const VPIntrinsic &PI) const override {
346 using VPLegalization = TargetTransformInfo::VPLegalization;
347 if (!ST->hasVInstructions() ||
348 (PI.getIntrinsicID() == Intrinsic::vp_reduce_mul &&
349 cast<VectorType>(Val: PI.getArgOperand(i: 1)->getType())
350 ->getElementType()
351 ->getIntegerBitWidth() != 1))
352 return VPLegalization(VPLegalization::Discard, VPLegalization::Convert);
353 return VPLegalization(VPLegalization::Legal, VPLegalization::Legal);
354 }
355
356 bool isLegalToVectorizeReduction(const RecurrenceDescriptor &RdxDesc,
357 ElementCount VF) const override {
358 if (!VF.isScalable())
359 return true;
360
361 Type *Ty = RdxDesc.getRecurrenceType();
362 if (!TLI->isLegalElementTypeForRVV(ScalarTy: TLI->getValueType(DL, Ty)))
363 return false;
364
365 switch (RdxDesc.getRecurrenceKind()) {
366 case RecurKind::Add:
367 case RecurKind::And:
368 case RecurKind::Or:
369 case RecurKind::Xor:
370 case RecurKind::SMin:
371 case RecurKind::SMax:
372 case RecurKind::UMin:
373 case RecurKind::UMax:
374 case RecurKind::FMin:
375 case RecurKind::FMax:
376 return true;
377 case RecurKind::AnyOf:
378 case RecurKind::FAdd:
379 case RecurKind::FMulAdd:
380 // We can't promote f16/bf16 fadd reductions and scalable vectors can't be
381 // expanded.
382 if (Ty->isBFloatTy() || (Ty->isHalfTy() && !ST->hasVInstructionsF16()))
383 return false;
384 return true;
385 default:
386 return false;
387 }
388 }
389
390 unsigned getMaxInterleaveFactor(ElementCount VF) const override {
391 // Don't interleave if the loop has been vectorized with scalable vectors.
392 if (VF.isScalable())
393 return 1;
394 // If the loop will not be vectorized, don't interleave the loop.
395 // Let regular unroll to unroll the loop.
396 return VF.isScalar() ? 1 : ST->getMaxInterleaveFactor();
397 }
398
399 bool enableInterleavedAccessVectorization() const override { return true; }
400
401 unsigned getMinTripCountTailFoldingThreshold() const override;
402
403 enum RISCVRegisterClass { GPRRC, FPRRC, VRRC };
404 unsigned getNumberOfRegisters(unsigned ClassID) const override {
405 switch (ClassID) {
406 case RISCVRegisterClass::GPRRC:
407 // 31 = 32 GPR - x0 (zero register)
408 // FIXME: Should we exclude fixed registers like SP, TP or GP?
409 return 31;
410 case RISCVRegisterClass::FPRRC:
411 if (ST->hasStdExtF())
412 return 32;
413 return 0;
414 case RISCVRegisterClass::VRRC:
415 // Although there are 32 vector registers, v0 is special in that it is the
416 // only register that can be used to hold a mask.
417 // FIXME: Should we conservatively return 31 as the number of usable
418 // vector registers?
419 return ST->hasVInstructions() ? 32 : 0;
420 }
421 llvm_unreachable("unknown register class");
422 }
423
424 TTI::AddressingModeKind
425 getPreferredAddressingMode(const Loop *L, ScalarEvolution *SE) const override;
426
427 unsigned getRegisterClassForType(bool Vector,
428 Type *Ty = nullptr) const override {
429 if (Vector)
430 return RISCVRegisterClass::VRRC;
431 if (!Ty)
432 return RISCVRegisterClass::GPRRC;
433
434 Type *ScalarTy = Ty->getScalarType();
435 if ((ScalarTy->isHalfTy() && ST->hasStdExtZfhmin()) ||
436 (ScalarTy->isFloatTy() && ST->hasStdExtF()) ||
437 (ScalarTy->isDoubleTy() && ST->hasStdExtD())) {
438 return RISCVRegisterClass::FPRRC;
439 }
440
441 return RISCVRegisterClass::GPRRC;
442 }
443
444 const char *getRegisterClassName(unsigned ClassID) const override {
445 switch (ClassID) {
446 case RISCVRegisterClass::GPRRC:
447 return "RISCV::GPRRC";
448 case RISCVRegisterClass::FPRRC:
449 return "RISCV::FPRRC";
450 case RISCVRegisterClass::VRRC:
451 return "RISCV::VRRC";
452 }
453 llvm_unreachable("unknown register class");
454 }
455
456 bool isLSRCostLess(const TargetTransformInfo::LSRCost &C1,
457 const TargetTransformInfo::LSRCost &C2) const override;
458
459 bool shouldConsiderAddressTypePromotion(
460 const Instruction &I,
461 bool &AllowPromotionWithoutCommonHeader) const override;
462 std::optional<unsigned> getMinPageSize() const override { return 4096; }
463 /// Return true if the (vector) instruction I will be lowered to an
464 /// instruction with a scalar splat operand for the given Operand number.
465 bool canSplatOperand(Instruction *I, int Operand) const;
466 /// Return true if a vector instruction will lower to a target instruction
467 /// able to splat the given operand.
468 bool canSplatOperand(unsigned Opcode, int Operand) const;
469
470 bool isProfitableToSinkOperands(Instruction *I,
471 SmallVectorImpl<Use *> &Ops) const override;
472
473 TTI::MemCmpExpansionOptions
474 enableMemCmpExpansion(bool OptSize, bool IsZeroCmp) const override;
475};
476
477} // end namespace llvm
478
479#endif // LLVM_LIB_TARGET_RISCV_RISCVTARGETTRANSFORMINFO_H
480