clang 24.0.0git
NVPTX.cpp
Go to the documentation of this file.
1//===- NVPTX.cpp ----------------------------------------------------------===//
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
9#include "ABIInfoImpl.h"
10#include "TargetInfo.h"
12#include "llvm/ADT/STLExtras.h"
13#include "llvm/ADT/StringExtras.h"
14#include "llvm/IR/CallingConv.h"
15#include "llvm/IR/IntrinsicsNVPTX.h"
16#include "llvm/IR/LLVMContext.h"
17#include "llvm/Support/NVVMAttributes.h"
18
19using namespace clang;
20using namespace clang::CodeGen;
21
22//===----------------------------------------------------------------------===//
23// NVPTX ABI Implementation
24//===----------------------------------------------------------------------===//
25
26namespace {
27
28class NVPTXTargetCodeGenInfo;
29
30class NVPTXABIInfo : public ABIInfo {
31 NVPTXTargetCodeGenInfo &CGInfo;
32
33public:
34 NVPTXABIInfo(CodeGenTypes &CGT, NVPTXTargetCodeGenInfo &Info)
35 : ABIInfo(CGT), CGInfo(Info) {}
36
37 ABIArgInfo classifyReturnType(QualType RetTy) const;
38 ABIArgInfo classifyArgumentType(QualType Ty) const;
39
40 void computeInfo(CGFunctionInfo &FI) const override;
41 RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
42 AggValueSlot Slot) const override;
43 bool isUnsupportedType(QualType T) const;
44 ABIArgInfo coerceToIntArrayWithLimit(QualType Ty, unsigned MaxSize) const;
45};
46
47class NVPTXTargetCodeGenInfo : public TargetCodeGenInfo {
48public:
49 NVPTXTargetCodeGenInfo(CodeGenTypes &CGT)
50 : TargetCodeGenInfo(std::make_unique<NVPTXABIInfo>(CGT, *this)) {}
51
52 void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
53 CodeGen::CodeGenModule &M) const override;
54 void setTargetAtomicMetadata(CodeGenFunction &CGF,
55 llvm::Instruction &AtomicInst,
56 const AtomicExpr *AE) const override;
57 bool shouldEmitStaticExternCAliases() const override;
58
59 StringRef getLLVMSyncScopeStr(const LangOptions &LangOpts, SyncScope Scope,
60 llvm::AtomicOrdering Ordering) const override;
61
62 llvm::Constant *getNullPointer(const CodeGen::CodeGenModule &CGM,
63 llvm::PointerType *T,
64 QualType QT) const override;
65
66 llvm::Type *getCUDADeviceBuiltinSurfaceDeviceType() const override {
67 // On the device side, surface reference is represented as an object handle
68 // in 64-bit integer.
69 return llvm::Type::getInt64Ty(getABIInfo().getVMContext());
70 }
71
72 llvm::Type *getCUDADeviceBuiltinTextureDeviceType() const override {
73 // On the device side, texture reference is represented as an object handle
74 // in 64-bit integer.
75 return llvm::Type::getInt64Ty(getABIInfo().getVMContext());
76 }
77
78 bool emitCUDADeviceBuiltinSurfaceDeviceCopy(CodeGenFunction &CGF, LValue Dst,
79 LValue Src) const override {
80 emitBuiltinSurfTexDeviceCopy(CGF, Dst, Src);
81 return true;
82 }
83
84 bool emitCUDADeviceBuiltinTextureDeviceCopy(CodeGenFunction &CGF, LValue Dst,
85 LValue Src) const override {
86 emitBuiltinSurfTexDeviceCopy(CGF, Dst, Src);
87 return true;
88 }
89
90 unsigned getDeviceKernelCallingConv() const override {
91 return llvm::CallingConv::PTX_Kernel;
92 }
93
94 void setCUDAKernelCallingConvention(const FunctionType *&FT) const override {
95 FT = getABIInfo().getContext().adjustFunctionType(
97 }
98
99 // Adds a NamedMDNode with GV, Name, and Operand as operands, and adds the
100 // resulting MDNode to the nvvm.annotations MDNode.
101 static void addNVVMMetadata(llvm::GlobalValue *GV, StringRef Name,
102 int Operand);
103
104private:
105 static void emitBuiltinSurfTexDeviceCopy(CodeGenFunction &CGF, LValue Dst,
106 LValue Src) {
107 llvm::Value *Handle = nullptr;
108 llvm::Constant *C =
109 llvm::dyn_cast<llvm::Constant>(Src.getAddress().emitRawPointer(CGF));
110 // Lookup `addrspacecast` through the constant pointer if any.
111 if (auto *ASC = llvm::dyn_cast_or_null<llvm::AddrSpaceCastOperator>(C))
112 C = llvm::cast<llvm::Constant>(ASC->getPointerOperand());
113 if (auto *GV = llvm::dyn_cast_or_null<llvm::GlobalVariable>(C)) {
114 // Load the handle from the specific global variable using
115 // `nvvm.texsurf.handle.internal` intrinsic.
116 Handle = CGF.EmitRuntimeCall(
117 CGF.CGM.getIntrinsic(llvm::Intrinsic::nvvm_texsurf_handle_internal,
118 {GV->getType()}),
119 {GV}, "texsurf_handle");
120 } else
121 Handle = CGF.EmitLoadOfScalar(Src, SourceLocation());
122 CGF.EmitStoreOfScalar(Handle, Dst);
123 }
124};
125
126/// Checks if the type is unsupported directly by the current target.
127bool NVPTXABIInfo::isUnsupportedType(QualType T) const {
128 ASTContext &Context = getContext();
129 if (!Context.getTargetInfo().hasFloat16Type() && T->isFloat16Type())
130 return true;
131 if (!Context.getTargetInfo().hasFloat128Type() &&
132 (T->isFloat128Type() ||
133 (T->isRealFloatingType() && Context.getTypeSize(T) == 128)))
134 return true;
135 if (const auto *EIT = T->getAs<BitIntType>())
136 return EIT->getNumBits() >
137 (Context.getTargetInfo().hasInt128Type() ? 128U : 64U);
138 if (!Context.getTargetInfo().hasInt128Type() && T->isIntegerType() &&
139 Context.getTypeSize(T) > 64U)
140 return true;
141 if (const auto *AT = T->getAsArrayTypeUnsafe())
142 return isUnsupportedType(AT->getElementType());
143 const auto *RD = T->getAsRecordDecl();
144 if (!RD)
145 return false;
146
147 // If this is a C++ record, check the bases first.
148 if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
149 for (const CXXBaseSpecifier &I : CXXRD->bases())
150 if (isUnsupportedType(I.getType()))
151 return true;
152
153 for (const FieldDecl *I : RD->fields())
154 if (isUnsupportedType(I->getType()))
155 return true;
156 return false;
157}
158
159/// Coerce the given type into an array with maximum allowed size of elements.
160ABIArgInfo NVPTXABIInfo::coerceToIntArrayWithLimit(QualType Ty,
161 unsigned MaxSize) const {
162 // Alignment and Size are measured in bits.
163 const uint64_t Size = getContext().getTypeSize(Ty);
164 const uint64_t Alignment = getContext().getTypeAlign(Ty);
165 const unsigned Div = std::min<unsigned>(MaxSize, Alignment);
166 llvm::Type *IntType = llvm::Type::getIntNTy(getVMContext(), Div);
167 const uint64_t NumElements = (Size + Div - 1) / Div;
168 return ABIArgInfo::getDirect(llvm::ArrayType::get(IntType, NumElements));
169}
170
171ABIArgInfo NVPTXABIInfo::classifyReturnType(QualType RetTy) const {
172 if (RetTy->isVoidType())
173 return ABIArgInfo::getIgnore();
174
175 if (getContext().getLangOpts().OpenMP &&
176 getContext().getLangOpts().OpenMPIsTargetDevice &&
177 isUnsupportedType(RetTy))
178 return coerceToIntArrayWithLimit(RetTy, 64);
179
180 // note: this is different from default ABI
181 if (!RetTy->isScalarType())
182 return ABIArgInfo::getDirect();
183
184 // Treat an enum type as its underlying type.
185 if (const auto *ED = RetTy->getAsEnumDecl())
186 RetTy = ED->getIntegerType();
187
188 return (isPromotableIntegerTypeForABI(RetTy) ? ABIArgInfo::getExtend(RetTy)
190}
191
192ABIArgInfo NVPTXABIInfo::classifyArgumentType(QualType Ty) const {
193 // Treat an enum type as its underlying type.
194 if (const auto *ED = Ty->getAsEnumDecl())
195 Ty = ED->getIntegerType();
196
197 // Return aggregates type as indirect by value
198 if (isAggregateTypeForABI(Ty)) {
199 // Under CUDA device compilation, tex/surf builtin types are replaced with
200 // object types and passed directly.
201 if (getContext().getLangOpts().CUDAIsDevice) {
204 CGInfo.getCUDADeviceBuiltinSurfaceDeviceType());
207 CGInfo.getCUDADeviceBuiltinTextureDeviceType());
208 }
209 return getNaturalAlignIndirect(
210 Ty, /* AddrSpace */ getDataLayout().getAllocaAddrSpace(),
211 /* byval */ true);
212 }
213
214 if (const auto *EIT = Ty->getAs<BitIntType>()) {
215 if ((EIT->getNumBits() > 128) ||
216 (!getContext().getTargetInfo().hasInt128Type() &&
217 EIT->getNumBits() > 64))
218 return getNaturalAlignIndirect(
219 Ty, /* AddrSpace */ getDataLayout().getAllocaAddrSpace(),
220 /* byval */ true);
221 }
222
223 return (isPromotableIntegerTypeForABI(Ty) ? ABIArgInfo::getExtend(Ty)
225}
226
227void NVPTXABIInfo::computeInfo(CGFunctionInfo &FI) const {
228 if (!getCXXABI().classifyReturnType(FI))
230
231 for (auto &&[ArgumentsCount, I] : llvm::enumerate(FI.arguments()))
232 I.info = ArgumentsCount < FI.getNumRequiredArgs()
233 ? classifyArgumentType(I.type)
234 : ABIArgInfo::getDirect();
235
236 // Always honor user-specified calling convention.
237 if (FI.getCallingConvention() != llvm::CallingConv::C)
238 return;
239
240 FI.setEffectiveCallingConvention(getRuntimeCC());
241}
242
243RValue NVPTXABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
244 QualType Ty, AggValueSlot Slot) const {
245 return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*IsIndirect=*/false,
246 getContext().getTypeInfoInChars(Ty),
248 /*AllowHigherAlign=*/true, Slot);
249}
250
251void NVPTXTargetCodeGenInfo::setTargetAttributes(
252 const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const {
253 if (GV->isDeclaration())
254 return;
255 const VarDecl *VD = dyn_cast_or_null<VarDecl>(D);
256 if (VD) {
257 if (M.getLangOpts().CUDA) {
259 addNVVMMetadata(GV, "surface", 1);
260 else if (VD->getType()->isCUDADeviceBuiltinTextureType())
261 addNVVMMetadata(GV, "texture", 1);
262 return;
263 }
264 }
265
266 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
267 if (!FD)
268 return;
269
270 llvm::Function *F = cast<llvm::Function>(GV);
271
272 // Perform special handling in OpenCL/CUDA mode
273 if (M.getLangOpts().OpenCL || M.getLangOpts().CUDA) {
274 // Use function attributes to check for kernel functions
275 // By default, all functions are device functions
276 if (FD->hasAttr<DeviceKernelAttr>() || FD->hasAttr<CUDAGlobalAttr>()) {
277 // OpenCL/CUDA kernel functions get kernel metadata
278 // And kernel functions are not subject to inlining
279 F->addFnAttr(llvm::Attribute::NoInline);
280 if (FD->hasAttr<CUDAGlobalAttr>()) {
281 for (auto IV : llvm::enumerate(FD->parameters()))
282 if (IV.value()->hasAttr<CUDAGridConstantAttr>())
283 F->addParamAttr(IV.index(),
284 llvm::Attribute::get(F->getContext(),
285 llvm::NVVMAttr::GridConstant));
286 }
287 if (CUDALaunchBoundsAttr *Attr = FD->getAttr<CUDALaunchBoundsAttr>())
289 }
290 }
291}
292
293void NVPTXTargetCodeGenInfo::addNVVMMetadata(llvm::GlobalValue *GV,
294 StringRef Name, int Operand) {
295 llvm::Module *M = GV->getParent();
296 llvm::LLVMContext &Ctx = M->getContext();
297
298 // Get "nvvm.annotations" metadata node
299 llvm::NamedMDNode *MD = M->getOrInsertNamedMetadata("nvvm.annotations");
300
301 SmallVector<llvm::Metadata *, 5> MDVals = {
302 llvm::ConstantAsMetadata::get(GV), llvm::MDString::get(Ctx, Name),
303 llvm::ConstantAsMetadata::get(
304 llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx), Operand))};
305
306 // Append metadata to nvvm.annotations
307 MD->addOperand(llvm::MDNode::get(Ctx, MDVals));
308}
309
310bool NVPTXTargetCodeGenInfo::shouldEmitStaticExternCAliases() const {
311 return false;
312}
313
314void NVPTXTargetCodeGenInfo::setTargetAtomicMetadata(
315 CodeGenFunction &CGF, llvm::Instruction &AtomicInst,
316 const AtomicExpr *AE) const {
317 AtomicOptions AO = CGF.CGM.getAtomicOpts();
319 addAtomicIgnoreDenormalModeMetadata(CGF, AtomicInst, /*AllowHalf=*/true);
320}
321
322StringRef NVPTXTargetCodeGenInfo::getLLVMSyncScopeStr(
323 const LangOptions &LangOpts, SyncScope Scope,
324 llvm::AtomicOrdering Ordering) const {
325 return *llvm::getAtomicScopeIRString(getABIInfo().getTarget().getTriple(),
326 getAtomicScope(Scope));
327}
328
329llvm::Constant *
330NVPTXTargetCodeGenInfo::getNullPointer(const CodeGen::CodeGenModule &CGM,
331 llvm::PointerType *PT,
332 QualType QT) const {
333 auto &Ctx = CGM.getContext();
334 if (PT->getAddressSpace() != Ctx.getTargetAddressSpace(LangAS::opencl_local))
335 return llvm::ConstantPointerNull::get(PT);
336
337 auto NPT = llvm::PointerType::get(
338 PT->getContext(), Ctx.getTargetAddressSpace(LangAS::opencl_generic));
339 return llvm::ConstantExpr::getAddrSpaceCast(
340 llvm::ConstantPointerNull::get(NPT), PT);
341}
342} // namespace
343
345 const CUDALaunchBoundsAttr *Attr,
346 int32_t *MaxThreadsVal,
347 int32_t *MinBlocksVal,
348 int32_t *MaxClusterRankVal) {
349 llvm::APSInt MaxThreads(32);
350 MaxThreads = Attr->getMaxThreads()->EvaluateKnownConstInt(getContext());
351 if (MaxThreads > 0) {
352 if (MaxThreadsVal)
353 *MaxThreadsVal = MaxThreads.getExtValue();
354 if (F)
355 F->addFnAttr(llvm::NVVMAttr::MaxNTID,
356 llvm::utostr(MaxThreads.getExtValue()));
357 }
358
359 // min and max blocks is an optional argument for CUDALaunchBoundsAttr. If it
360 // was not specified in __launch_bounds__ or if the user specified a 0 value,
361 // we don't have to add a PTX directive.
362 if (Attr->getMinBlocks()) {
363 llvm::APSInt MinBlocks(32);
364 MinBlocks = Attr->getMinBlocks()->EvaluateKnownConstInt(getContext());
365 if (MinBlocks > 0) {
366 if (MinBlocksVal)
367 *MinBlocksVal = MinBlocks.getExtValue();
368 if (F)
369 F->addFnAttr(llvm::NVVMAttr::MinCTASm,
370 llvm::utostr(MinBlocks.getExtValue()));
371 }
372 }
373 if (Attr->getMaxBlocks()) {
374 llvm::APSInt MaxBlocks(32);
375 MaxBlocks = Attr->getMaxBlocks()->EvaluateKnownConstInt(getContext());
376 if (MaxBlocks > 0) {
377 if (MaxClusterRankVal)
378 *MaxClusterRankVal = MaxBlocks.getExtValue();
379 if (F)
380 F->addFnAttr(llvm::NVVMAttr::MaxClusterRank,
381 llvm::utostr(MaxBlocks.getExtValue()));
382 }
383 }
384}
385
386std::unique_ptr<TargetCodeGenInfo>
388 return std::make_unique<NVPTXTargetCodeGenInfo>(CGM.getTypes());
389}
static void setCUDAKernelCallingConvention(CanQualType &funcTy, CIRGenModule &cgm, const FunctionDecl *fd)
Set calling convention for CUDA/HIP kernel.
static StringRef getTriple(const Command &Job)
Provides definitions for the atomic synchronization scopes.
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
const TargetInfo & getTargetInfo() const
Definition ASTContext.h:975
Attr - This represents one attribute.
Definition Attr.h:46
static CharUnits fromQuantity(QuantityType Quantity)
Construct a CharUnits quantity from a raw integer type.
Definition CharUnits.h:58
static ABIArgInfo getIgnore()
static ABIArgInfo getDirect(llvm::Type *T=nullptr, unsigned Offset=0, llvm::Type *Padding=nullptr, bool CanBeFlattened=true, unsigned Align=0)
static ABIArgInfo getExtend(QualType Ty, llvm::Type *T=nullptr, llvm::Type *Padding=nullptr)
ABIInfo - Target specific hooks for defining how a type should be passed or returned from functions.
Definition ABIInfo.h:49
unsigned getCallingConvention() const
getCallingConvention - Return the user specified calling convention, which has been translated into a...
CanQualType getReturnType() const
MutableArrayRef< ArgInfo > arguments()
void setEffectiveCallingConvention(unsigned Value)
llvm::Value * EmitLoadOfScalar(Address Addr, bool Volatile, QualType Ty, SourceLocation Loc, AlignmentSource Source=AlignmentSource::Type, bool isNontemporal=false)
EmitLoadOfScalar - Load a scalar value from an address, taking care to appropriately convert from the...
llvm::CallInst * EmitRuntimeCall(llvm::FunctionCallee callee, const Twine &name="")
void EmitStoreOfScalar(llvm::Value *Value, Address Addr, bool Volatile, QualType Ty, AlignmentSource Source=AlignmentSource::Type, bool isInit=false, bool isNontemporal=false)
EmitStoreOfScalar - Store a scalar value to an address, taking care to appropriately convert from the...
This class organizes the cross-function state that is used while generating LLVM code.
void handleCUDALaunchBoundsAttr(llvm::Function *F, const CUDALaunchBoundsAttr *A, int32_t *MaxThreadsVal=nullptr, int32_t *MinBlocksVal=nullptr, int32_t *MaxClusterRankVal=nullptr)
Emit the IR encoding to attach the CUDA launch bounds attribute to F.
Definition NVPTX.cpp:344
const LangOptions & getLangOpts() const
AtomicOptions getAtomicOpts()
Get the current Atomic options.
ASTContext & getContext() const
llvm::Function * getIntrinsic(unsigned IID, ArrayRef< llvm::Type * > Tys={})
TargetCodeGenInfo - This class organizes various target-specific codegeneration issues,...
Definition TargetInfo.h:80
T * getAttr() const
Definition DeclBase.h:581
bool hasAttr() const
Definition DeclBase.h:585
ArrayRef< ParmVarDecl * > parameters() const
Definition Decl.h:2905
ExtInfo withCallingConv(CallingConv cc) const
Definition TypeBase.h:4835
ExtInfo getExtInfo() const
Definition TypeBase.h:4968
A (possibly-)qualified type.
Definition TypeBase.h:938
virtual bool hasInt128Type() const
Determine whether the __int128 type is supported on this target.
Definition TargetInfo.h:686
virtual bool hasFloat16Type() const
Determine whether the _Float16 type is supported on this target.
Definition TargetInfo.h:716
virtual bool hasFloat128Type() const
Determine whether the __float128 type is supported on this target.
Definition TargetInfo.h:713
bool isVoidType() const
Definition TypeBase.h:9068
bool isFloat16Type() const
Definition TypeBase.h:9081
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition Type.h:41
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
Definition TypeBase.h:9116
bool isScalarType() const
Definition TypeBase.h:9178
bool isFloat128Type() const
Definition TypeBase.h:9101
bool isCUDADeviceBuiltinSurfaceType() const
Check if the type is the CUDA device builtin surface type.
Definition Type.cpp:5654
bool isCUDADeviceBuiltinTextureType() const
Check if the type is the CUDA device builtin texture type.
Definition Type.cpp:5663
const ArrayType * getAsArrayTypeUnsafe() const
A variant of getAs<> for array types which silently discards qualifiers from the outermost type.
Definition TypeBase.h:9352
EnumDecl * getAsEnumDecl() const
Retrieves the EnumDecl this type refers to.
Definition Type.h:53
bool isRealFloatingType() const
Floating point categories.
Definition Type.cpp:2533
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9299
QualType getType() const
Definition Decl.h:724
ABIArgInfo classifyArgumentType(CodeGenModule &CGM, CanQualType type)
Classify the rules for how to pass a particular type.
@ Decl
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
Definition CGValue.h:146
bool classifyReturnType(const CGCXXABI &CXXABI, CGFunctionInfo &FI, const ABIInfo &Info)
std::unique_ptr< TargetCodeGenInfo > createNVPTXTargetCodeGenInfo(CodeGenModule &CGM)
Definition NVPTX.cpp:387
RValue emitVoidPtrVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType ValueTy, bool IsIndirect, TypeInfoChars ValueInfo, CharUnits SlotSizeAndAlign, bool AllowHigherAlign, AggValueSlot Slot, bool ForceRightAdjust=false)
Emit va_arg for a platform using the common void* representation, where arguments are simply emitted ...
void addAtomicIgnoreDenormalModeMetadata(CodeGenFunction &CGF, llvm::Instruction &AtomicInst, bool AllowHalf=false)
Attach !atomic.ignore.denormal.mode to AtomicInst, if it is an atomicrmw the metadata is meaningful f...
bool isAggregateTypeForABI(QualType T)
bool Div(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition Interp.h:773
Top level wrappers for InstallAPI frontend operations.
const FunctionProtoType * T
llvm::AtomicScope getAtomicScope(SyncScope S)
Collapses a clang sync scope onto the target-neutral llvm::AtomicScope.
Definition TargetInfo.h:40
SyncScope
Defines sync scope values used internally by clang.
Definition SyncScope.h:43
@ CC_DeviceKernel
Definition Specifiers.h:295
U cast(CodeGen::Address addr)
Definition Address.h:327
unsigned long uint64_t
bool getOption(AtomicOptionKind Kind) const