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