xref: /freebsd/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.h (revision b64c5a0ace59af62eff52bfe110a521dc73c937b)
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 TargetTransformInfo::Concept 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/IVDescriptors.h"
22 #include "llvm/Analysis/TargetTransformInfo.h"
23 #include "llvm/CodeGen/BasicTTIImpl.h"
24 #include "llvm/IR/Function.h"
25 #include <optional>
26 
27 namespace llvm {
28 
29 class RISCVTTIImpl : public BasicTTIImplBase<RISCVTTIImpl> {
30   using BaseT = BasicTTIImplBase<RISCVTTIImpl>;
31   using TTI = TargetTransformInfo;
32 
33   friend BaseT;
34 
35   const RISCVSubtarget *ST;
36   const RISCVTargetLowering *TLI;
37 
38   const RISCVSubtarget *getST() const { return ST; }
39   const RISCVTargetLowering *getTLI() const { return TLI; }
40 
41   /// This function returns an estimate for VL to be used in VL based terms
42   /// of the cost model.  For fixed length vectors, this is simply the
43   /// vector length.  For scalable vectors, we return results consistent
44   /// with getVScaleForTuning under the assumption that clients are also
45   /// using that when comparing costs between scalar and vector representation.
46   /// This does unfortunately mean that we can both undershoot and overshot
47   /// the true cost significantly if getVScaleForTuning is wildly off for the
48   /// actual target hardware.
49   unsigned getEstimatedVLFor(VectorType *Ty);
50 
51   InstructionCost getRISCVInstructionCost(ArrayRef<unsigned> OpCodes, MVT VT,
52                                           TTI::TargetCostKind CostKind);
53 
54   /// Return the cost of accessing a constant pool entry of the specified
55   /// type.
56   InstructionCost getConstantPoolLoadCost(Type *Ty,
57                                           TTI::TargetCostKind CostKind);
58 public:
59   explicit RISCVTTIImpl(const RISCVTargetMachine *TM, const Function &F)
60       : BaseT(TM, F.getDataLayout()), ST(TM->getSubtargetImpl(F)),
61         TLI(ST->getTargetLowering()) {}
62 
63   bool areInlineCompatible(const Function *Caller,
64                            const Function *Callee) const;
65 
66   /// Return the cost of materializing an immediate for a value operand of
67   /// a store instruction.
68   InstructionCost getStoreImmCost(Type *VecTy, TTI::OperandValueInfo OpInfo,
69                                   TTI::TargetCostKind CostKind);
70 
71   InstructionCost getIntImmCost(const APInt &Imm, Type *Ty,
72                                 TTI::TargetCostKind CostKind);
73   InstructionCost getIntImmCostInst(unsigned Opcode, unsigned Idx,
74                                     const APInt &Imm, Type *Ty,
75                                     TTI::TargetCostKind CostKind,
76                                     Instruction *Inst = nullptr);
77   InstructionCost getIntImmCostIntrin(Intrinsic::ID IID, unsigned Idx,
78                                       const APInt &Imm, Type *Ty,
79                                       TTI::TargetCostKind CostKind);
80 
81   /// \name EVL Support for predicated vectorization.
82   /// Whether the target supports the %evl parameter of VP intrinsic efficiently
83   /// in hardware, for the given opcode and type/alignment. (see LLVM Language
84   /// Reference - "Vector Predication Intrinsics",
85   /// https://llvm.org/docs/LangRef.html#vector-predication-intrinsics and
86   /// "IR-level VP intrinsics",
87   /// https://llvm.org/docs/Proposals/VectorPredication.html#ir-level-vp-intrinsics).
88   /// \param Opcode the opcode of the instruction checked for predicated version
89   /// support.
90   /// \param DataType the type of the instruction with the \p Opcode checked for
91   /// prediction support.
92   /// \param Alignment the alignment for memory access operation checked for
93   /// predicated version support.
94   bool hasActiveVectorLength(unsigned Opcode, Type *DataType,
95                              Align Alignment) const;
96 
97   TargetTransformInfo::PopcntSupportKind getPopcntSupport(unsigned TyWidth);
98 
99   bool shouldExpandReduction(const IntrinsicInst *II) const;
100   bool supportsScalableVectors() const { return ST->hasVInstructions(); }
101   bool enableOrderedReductions() const { return true; }
102   bool enableScalableVectorization() const { return ST->hasVInstructions(); }
103   TailFoldingStyle
104   getPreferredTailFoldingStyle(bool IVUpdateMayOverflow) const {
105     return ST->hasVInstructions() ? TailFoldingStyle::Data
106                                   : TailFoldingStyle::DataWithoutLaneMask;
107   }
108   std::optional<unsigned> getMaxVScale() const;
109   std::optional<unsigned> getVScaleForTuning() const;
110 
111   TypeSize getRegisterBitWidth(TargetTransformInfo::RegisterKind K) const;
112 
113   unsigned getRegUsageForType(Type *Ty);
114 
115   unsigned getMaximumVF(unsigned ElemWidth, unsigned Opcode) const;
116 
117   bool preferEpilogueVectorization() const {
118     // Epilogue vectorization is usually unprofitable - tail folding or
119     // a smaller VF would have been better.  This a blunt hammer - we
120     // should re-examine this once vectorization is better tuned.
121     return false;
122   }
123 
124   InstructionCost getMaskedMemoryOpCost(unsigned Opcode, Type *Src,
125                                         Align Alignment, unsigned AddressSpace,
126                                         TTI::TargetCostKind CostKind);
127 
128   InstructionCost getPointersChainCost(ArrayRef<const Value *> Ptrs,
129                                        const Value *Base,
130                                        const TTI::PointersChainInfo &Info,
131                                        Type *AccessTy,
132                                        TTI::TargetCostKind CostKind);
133 
134   void getUnrollingPreferences(Loop *L, ScalarEvolution &SE,
135                                TTI::UnrollingPreferences &UP,
136                                OptimizationRemarkEmitter *ORE);
137 
138   void getPeelingPreferences(Loop *L, ScalarEvolution &SE,
139                              TTI::PeelingPreferences &PP);
140 
141   unsigned getMinVectorRegisterBitWidth() const {
142     return ST->useRVVForFixedLengthVectors() ? 16 : 0;
143   }
144 
145   InstructionCost getShuffleCost(TTI::ShuffleKind Kind, VectorType *Tp,
146                                  ArrayRef<int> Mask,
147                                  TTI::TargetCostKind CostKind, int Index,
148                                  VectorType *SubTp,
149                                  ArrayRef<const Value *> Args = std::nullopt,
150                                  const Instruction *CxtI = nullptr);
151 
152   InstructionCost getIntrinsicInstrCost(const IntrinsicCostAttributes &ICA,
153                                         TTI::TargetCostKind CostKind);
154 
155   InstructionCost getInterleavedMemoryOpCost(
156       unsigned Opcode, Type *VecTy, unsigned Factor, ArrayRef<unsigned> Indices,
157       Align Alignment, unsigned AddressSpace, TTI::TargetCostKind CostKind,
158       bool UseMaskForCond = false, bool UseMaskForGaps = false);
159 
160   InstructionCost getGatherScatterOpCost(unsigned Opcode, Type *DataTy,
161                                          const Value *Ptr, bool VariableMask,
162                                          Align Alignment,
163                                          TTI::TargetCostKind CostKind,
164                                          const Instruction *I);
165 
166   InstructionCost getStridedMemoryOpCost(unsigned Opcode, Type *DataTy,
167                                          const Value *Ptr, bool VariableMask,
168                                          Align Alignment,
169                                          TTI::TargetCostKind CostKind,
170                                          const Instruction *I);
171 
172   InstructionCost getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src,
173                                    TTI::CastContextHint CCH,
174                                    TTI::TargetCostKind CostKind,
175                                    const Instruction *I = nullptr);
176 
177   InstructionCost getMinMaxReductionCost(Intrinsic::ID IID, VectorType *Ty,
178                                          FastMathFlags FMF,
179                                          TTI::TargetCostKind CostKind);
180 
181   InstructionCost getArithmeticReductionCost(unsigned Opcode, VectorType *Ty,
182                                              std::optional<FastMathFlags> FMF,
183                                              TTI::TargetCostKind CostKind);
184 
185   InstructionCost getExtendedReductionCost(unsigned Opcode, bool IsUnsigned,
186                                            Type *ResTy, VectorType *ValTy,
187                                            FastMathFlags FMF,
188                                            TTI::TargetCostKind CostKind);
189 
190   InstructionCost
191   getMemoryOpCost(unsigned Opcode, Type *Src, MaybeAlign Alignment,
192                   unsigned AddressSpace, TTI::TargetCostKind CostKind,
193                   TTI::OperandValueInfo OpdInfo = {TTI::OK_AnyValue, TTI::OP_None},
194                   const Instruction *I = nullptr);
195 
196   InstructionCost getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy,
197                                      CmpInst::Predicate VecPred,
198                                      TTI::TargetCostKind CostKind,
199                                      const Instruction *I = nullptr);
200 
201   InstructionCost getCFInstrCost(unsigned Opcode, TTI::TargetCostKind CostKind,
202                                  const Instruction *I = nullptr);
203 
204   using BaseT::getVectorInstrCost;
205   InstructionCost getVectorInstrCost(unsigned Opcode, Type *Val,
206                                      TTI::TargetCostKind CostKind,
207                                      unsigned Index, Value *Op0, Value *Op1);
208 
209   InstructionCost getArithmeticInstrCost(
210       unsigned Opcode, Type *Ty, TTI::TargetCostKind CostKind,
211       TTI::OperandValueInfo Op1Info = {TTI::OK_AnyValue, TTI::OP_None},
212       TTI::OperandValueInfo Op2Info = {TTI::OK_AnyValue, TTI::OP_None},
213       ArrayRef<const Value *> Args = std::nullopt,
214       const Instruction *CxtI = nullptr);
215 
216   bool isElementTypeLegalForScalableVector(Type *Ty) const {
217     return TLI->isLegalElementTypeForRVV(TLI->getValueType(DL, Ty));
218   }
219 
220   bool isLegalMaskedLoadStore(Type *DataType, Align Alignment) {
221     if (!ST->hasVInstructions())
222       return false;
223 
224     EVT DataTypeVT = TLI->getValueType(DL, DataType);
225 
226     // Only support fixed vectors if we know the minimum vector size.
227     if (DataTypeVT.isFixedLengthVector() && !ST->useRVVForFixedLengthVectors())
228       return false;
229 
230     EVT ElemType = DataTypeVT.getScalarType();
231     if (!ST->enableUnalignedVectorMem() && Alignment < ElemType.getStoreSize())
232       return false;
233 
234     return TLI->isLegalElementTypeForRVV(ElemType);
235 
236   }
237 
238   bool isLegalMaskedLoad(Type *DataType, Align Alignment) {
239     return isLegalMaskedLoadStore(DataType, Alignment);
240   }
241   bool isLegalMaskedStore(Type *DataType, Align Alignment) {
242     return isLegalMaskedLoadStore(DataType, Alignment);
243   }
244 
245   bool isLegalMaskedGatherScatter(Type *DataType, Align Alignment) {
246     if (!ST->hasVInstructions())
247       return false;
248 
249     EVT DataTypeVT = TLI->getValueType(DL, DataType);
250 
251     // Only support fixed vectors if we know the minimum vector size.
252     if (DataTypeVT.isFixedLengthVector() && !ST->useRVVForFixedLengthVectors())
253       return false;
254 
255     EVT ElemType = DataTypeVT.getScalarType();
256     if (!ST->enableUnalignedVectorMem() && Alignment < ElemType.getStoreSize())
257       return false;
258 
259     return TLI->isLegalElementTypeForRVV(ElemType);
260   }
261 
262   bool isLegalMaskedGather(Type *DataType, Align Alignment) {
263     return isLegalMaskedGatherScatter(DataType, Alignment);
264   }
265   bool isLegalMaskedScatter(Type *DataType, Align Alignment) {
266     return isLegalMaskedGatherScatter(DataType, Alignment);
267   }
268 
269   bool forceScalarizeMaskedGather(VectorType *VTy, Align Alignment) {
270     // Scalarize masked gather for RV64 if EEW=64 indices aren't supported.
271     return ST->is64Bit() && !ST->hasVInstructionsI64();
272   }
273 
274   bool forceScalarizeMaskedScatter(VectorType *VTy, Align Alignment) {
275     // Scalarize masked scatter for RV64 if EEW=64 indices aren't supported.
276     return ST->is64Bit() && !ST->hasVInstructionsI64();
277   }
278 
279   bool isLegalStridedLoadStore(Type *DataType, Align Alignment) {
280     EVT DataTypeVT = TLI->getValueType(DL, DataType);
281     return TLI->isLegalStridedLoadStore(DataTypeVT, Alignment);
282   }
283 
284   bool isLegalMaskedCompressStore(Type *DataTy, Align Alignment);
285 
286   bool isVScaleKnownToBeAPowerOfTwo() const {
287     return TLI->isVScaleKnownToBeAPowerOfTwo();
288   }
289 
290   /// \returns How the target needs this vector-predicated operation to be
291   /// transformed.
292   TargetTransformInfo::VPLegalization
293   getVPLegalizationStrategy(const VPIntrinsic &PI) const {
294     using VPLegalization = TargetTransformInfo::VPLegalization;
295     if (!ST->hasVInstructions() ||
296         (PI.getIntrinsicID() == Intrinsic::vp_reduce_mul &&
297          cast<VectorType>(PI.getArgOperand(1)->getType())
298                  ->getElementType()
299                  ->getIntegerBitWidth() != 1))
300       return VPLegalization(VPLegalization::Discard, VPLegalization::Convert);
301     return VPLegalization(VPLegalization::Legal, VPLegalization::Legal);
302   }
303 
304   bool isLegalToVectorizeReduction(const RecurrenceDescriptor &RdxDesc,
305                                    ElementCount VF) const {
306     if (!VF.isScalable())
307       return true;
308 
309     Type *Ty = RdxDesc.getRecurrenceType();
310     if (!TLI->isLegalElementTypeForRVV(TLI->getValueType(DL, Ty)))
311       return false;
312 
313     switch (RdxDesc.getRecurrenceKind()) {
314     case RecurKind::Add:
315     case RecurKind::FAdd:
316     case RecurKind::And:
317     case RecurKind::Or:
318     case RecurKind::Xor:
319     case RecurKind::SMin:
320     case RecurKind::SMax:
321     case RecurKind::UMin:
322     case RecurKind::UMax:
323     case RecurKind::FMin:
324     case RecurKind::FMax:
325     case RecurKind::FMulAdd:
326     case RecurKind::IAnyOf:
327     case RecurKind::FAnyOf:
328       return true;
329     default:
330       return false;
331     }
332   }
333 
334   unsigned getMaxInterleaveFactor(ElementCount VF) {
335     // Don't interleave if the loop has been vectorized with scalable vectors.
336     if (VF.isScalable())
337       return 1;
338     // If the loop will not be vectorized, don't interleave the loop.
339     // Let regular unroll to unroll the loop.
340     return VF.isScalar() ? 1 : ST->getMaxInterleaveFactor();
341   }
342 
343   bool enableInterleavedAccessVectorization() { return true; }
344 
345   enum RISCVRegisterClass { GPRRC, FPRRC, VRRC };
346   unsigned getNumberOfRegisters(unsigned ClassID) const {
347     switch (ClassID) {
348     case RISCVRegisterClass::GPRRC:
349       // 31 = 32 GPR - x0 (zero register)
350       // FIXME: Should we exclude fixed registers like SP, TP or GP?
351       return 31;
352     case RISCVRegisterClass::FPRRC:
353       if (ST->hasStdExtF())
354         return 32;
355       return 0;
356     case RISCVRegisterClass::VRRC:
357       // Although there are 32 vector registers, v0 is special in that it is the
358       // only register that can be used to hold a mask.
359       // FIXME: Should we conservatively return 31 as the number of usable
360       // vector registers?
361       return ST->hasVInstructions() ? 32 : 0;
362     }
363     llvm_unreachable("unknown register class");
364   }
365 
366   unsigned getRegisterClassForType(bool Vector, Type *Ty = nullptr) const {
367     if (Vector)
368       return RISCVRegisterClass::VRRC;
369     if (!Ty)
370       return RISCVRegisterClass::GPRRC;
371 
372     Type *ScalarTy = Ty->getScalarType();
373     if ((ScalarTy->isHalfTy() && ST->hasStdExtZfhmin()) ||
374         (ScalarTy->isFloatTy() && ST->hasStdExtF()) ||
375         (ScalarTy->isDoubleTy() && ST->hasStdExtD())) {
376       return RISCVRegisterClass::FPRRC;
377     }
378 
379     return RISCVRegisterClass::GPRRC;
380   }
381 
382   const char *getRegisterClassName(unsigned ClassID) const {
383     switch (ClassID) {
384     case RISCVRegisterClass::GPRRC:
385       return "RISCV::GPRRC";
386     case RISCVRegisterClass::FPRRC:
387       return "RISCV::FPRRC";
388     case RISCVRegisterClass::VRRC:
389       return "RISCV::VRRC";
390     }
391     llvm_unreachable("unknown register class");
392   }
393 
394   bool isLSRCostLess(const TargetTransformInfo::LSRCost &C1,
395                      const TargetTransformInfo::LSRCost &C2);
396 
397   bool shouldFoldTerminatingConditionAfterLSR() const {
398     return true;
399   }
400 
401   std::optional<unsigned> getMinPageSize() const { return 4096; }
402 };
403 
404 } // end namespace llvm
405 
406 #endif // LLVM_LIB_TARGET_RISCV_RISCVTARGETTRANSFORMINFO_H
407