xref: /freebsd/contrib/llvm-project/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h (revision e64bea71c21eb42e97aa615188ba91f6cce0d36d)
1 //===-- NVPTXTargetTransformInfo.h - NVPTX 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 a TargetTransformInfoImplBase conforming object specific to the
10 /// NVPTX 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_NVPTX_NVPTXTARGETTRANSFORMINFO_H
17 #define LLVM_LIB_TARGET_NVPTX_NVPTXTARGETTRANSFORMINFO_H
18 
19 #include "MCTargetDesc/NVPTXBaseInfo.h"
20 #include "NVPTXTargetMachine.h"
21 #include "NVPTXUtilities.h"
22 #include "llvm/Analysis/TargetTransformInfo.h"
23 #include "llvm/CodeGen/BasicTTIImpl.h"
24 #include "llvm/CodeGen/TargetLowering.h"
25 #include <optional>
26 
27 namespace llvm {
28 
29 class NVPTXTTIImpl final : public BasicTTIImplBase<NVPTXTTIImpl> {
30   typedef BasicTTIImplBase<NVPTXTTIImpl> BaseT;
31   typedef TargetTransformInfo TTI;
32   friend BaseT;
33 
34   const NVPTXSubtarget *ST;
35   const NVPTXTargetLowering *TLI;
36 
getST()37   const NVPTXSubtarget *getST() const { return ST; };
getTLI()38   const NVPTXTargetLowering *getTLI() const { return TLI; };
39 
40 public:
NVPTXTTIImpl(const NVPTXTargetMachine * TM,const Function & F)41   explicit NVPTXTTIImpl(const NVPTXTargetMachine *TM, const Function &F)
42       : BaseT(TM, F.getDataLayout()), ST(TM->getSubtargetImpl()),
43         TLI(ST->getTargetLowering()) {}
44 
45   bool hasBranchDivergence(const Function *F = nullptr) const override {
46     return true;
47   }
48 
49   bool isSourceOfDivergence(const Value *V) const override;
50 
getFlatAddressSpace()51   unsigned getFlatAddressSpace() const override {
52     return AddressSpace::ADDRESS_SPACE_GENERIC;
53   }
54 
55   bool
canHaveNonUndefGlobalInitializerInAddressSpace(unsigned AS)56   canHaveNonUndefGlobalInitializerInAddressSpace(unsigned AS) const override {
57     return AS != AddressSpace::ADDRESS_SPACE_SHARED &&
58            AS != AddressSpace::ADDRESS_SPACE_LOCAL && AS != ADDRESS_SPACE_PARAM;
59   }
60 
61   std::optional<Instruction *>
62   instCombineIntrinsic(InstCombiner &IC, IntrinsicInst &II) const override;
63 
64   // Loads and stores can be vectorized if the alignment is at least as big as
65   // the load/store we want to vectorize.
isLegalToVectorizeLoadChain(unsigned ChainSizeInBytes,Align Alignment,unsigned AddrSpace)66   bool isLegalToVectorizeLoadChain(unsigned ChainSizeInBytes, Align Alignment,
67                                    unsigned AddrSpace) const override {
68     return Alignment >= ChainSizeInBytes;
69   }
isLegalToVectorizeStoreChain(unsigned ChainSizeInBytes,Align Alignment,unsigned AddrSpace)70   bool isLegalToVectorizeStoreChain(unsigned ChainSizeInBytes, Align Alignment,
71                                     unsigned AddrSpace) const override {
72     return isLegalToVectorizeLoadChain(ChainSizeInBytes, Alignment, AddrSpace);
73   }
74 
75   // NVPTX has infinite registers of all kinds, but the actual machine doesn't.
76   // We conservatively return 1 here which is just enough to enable the
77   // vectorizers but disables heuristics based on the number of registers.
78   // FIXME: Return a more reasonable number, while keeping an eye on
79   // LoopVectorizer's unrolling heuristics.
getNumberOfRegisters(unsigned ClassID)80   unsigned getNumberOfRegisters(unsigned ClassID) const override { return 1; }
81 
82   // Only <2 x half> should be vectorized, so always return 32 for the vector
83   // register size.
84   TypeSize
getRegisterBitWidth(TargetTransformInfo::RegisterKind K)85   getRegisterBitWidth(TargetTransformInfo::RegisterKind K) const override {
86     return TypeSize::getFixed(32);
87   }
getMinVectorRegisterBitWidth()88   unsigned getMinVectorRegisterBitWidth() const override { return 32; }
89 
90   // We don't want to prevent inlining because of target-cpu and -features
91   // attributes that were added to newer versions of LLVM/Clang: There are
92   // no incompatible functions in PTX, ptxas will throw errors in such cases.
areInlineCompatible(const Function * Caller,const Function * Callee)93   bool areInlineCompatible(const Function *Caller,
94                            const Function *Callee) const override {
95     return true;
96   }
97 
98   // Increase the inlining cost threshold by a factor of 11, reflecting that
99   // calls are particularly expensive in NVPTX.
getInliningThresholdMultiplier()100   unsigned getInliningThresholdMultiplier() const override { return 11; }
101 
102   InstructionCost
103   getInstructionCost(const User *U, ArrayRef<const Value *> Operands,
104                      TTI::TargetCostKind CostKind) const override;
105 
106   InstructionCost getArithmeticInstrCost(
107       unsigned Opcode, Type *Ty, TTI::TargetCostKind CostKind,
108       TTI::OperandValueInfo Op1Info = {TTI::OK_AnyValue, TTI::OP_None},
109       TTI::OperandValueInfo Op2Info = {TTI::OK_AnyValue, TTI::OP_None},
110       ArrayRef<const Value *> Args = {},
111       const Instruction *CxtI = nullptr) const override;
112 
113   InstructionCost getScalarizationOverhead(
114       VectorType *InTy, const APInt &DemandedElts, bool Insert, bool Extract,
115       TTI::TargetCostKind CostKind, bool ForPoisonSrc = true,
116       ArrayRef<Value *> VL = {}) const override {
117     if (!InTy->getElementCount().isFixed())
118       return InstructionCost::getInvalid();
119 
120     auto VT = getTLI()->getValueType(DL, InTy);
121     auto NumElements = InTy->getElementCount().getFixedValue();
122     InstructionCost Cost = 0;
123     if (Insert && !VL.empty()) {
124       bool AllConstant = all_of(seq(NumElements), [&](int Idx) {
125         return !DemandedElts[Idx] || isa<Constant>(VL[Idx]);
126       });
127       if (AllConstant) {
128         Cost += TTI::TCC_Free;
129         Insert = false;
130       }
131     }
132     if (Insert && NVPTX::isPackedVectorTy(VT) && VT.is32BitVector()) {
133       // Can be built in a single 32-bit mov (64-bit regs are emulated in SASS
134       // with 2x 32-bit regs)
135       Cost += 1;
136       Insert = false;
137     }
138     if (Insert && VT == MVT::v4i8) {
139       InstructionCost Cost = 3; // 3 x PRMT
140       for (auto Idx : seq(NumElements))
141         if (DemandedElts[Idx])
142           Cost += 1; // zext operand to i32
143       Insert = false;
144     }
145     return Cost + BaseT::getScalarizationOverhead(InTy, DemandedElts, Insert,
146                                                   Extract, CostKind,
147                                                   ForPoisonSrc, VL);
148   }
149 
150   void getUnrollingPreferences(Loop *L, ScalarEvolution &SE,
151                                TTI::UnrollingPreferences &UP,
152                                OptimizationRemarkEmitter *ORE) const override;
153 
154   void getPeelingPreferences(Loop *L, ScalarEvolution &SE,
155                              TTI::PeelingPreferences &PP) const override;
156 
hasVolatileVariant(Instruction * I,unsigned AddrSpace)157   bool hasVolatileVariant(Instruction *I, unsigned AddrSpace) const override {
158     // Volatile loads/stores are only supported for shared and global address
159     // spaces, or for generic AS that maps to them.
160     if (!(AddrSpace == llvm::ADDRESS_SPACE_GENERIC ||
161           AddrSpace == llvm::ADDRESS_SPACE_GLOBAL ||
162           AddrSpace == llvm::ADDRESS_SPACE_SHARED))
163       return false;
164 
165     switch(I->getOpcode()){
166     default:
167       return false;
168     case Instruction::Load:
169     case Instruction::Store:
170       return true;
171     }
172   }
173 
174   bool collectFlatAddressOperands(SmallVectorImpl<int> &OpIndexes,
175                                   Intrinsic::ID IID) const override;
176 
177   unsigned getLoadStoreVecRegBitWidth(unsigned AddrSpace) const override;
178 
179   Value *rewriteIntrinsicWithAddressSpace(IntrinsicInst *II, Value *OldV,
180                                           Value *NewV) const override;
181   unsigned getAssumedAddrSpace(const Value *V) const override;
182 
183   void collectKernelLaunchBounds(
184       const Function &F,
185       SmallVectorImpl<std::pair<StringRef, int64_t>> &LB) const override;
186 
shouldBuildRelLookupTables()187   bool shouldBuildRelLookupTables() const override {
188     // Self-referential globals are not supported.
189     return false;
190   }
191 };
192 
193 } // end namespace llvm
194 
195 #endif
196