106c3fb27SDimitry Andric //===- NVPTX.cpp ----------------------------------------------------------===// 206c3fb27SDimitry Andric // 306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 606c3fb27SDimitry Andric // 706c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 806c3fb27SDimitry Andric 906c3fb27SDimitry Andric #include "ABIInfoImpl.h" 1006c3fb27SDimitry Andric #include "TargetInfo.h" 1106c3fb27SDimitry Andric #include "llvm/IR/IntrinsicsNVPTX.h" 1206c3fb27SDimitry Andric 1306c3fb27SDimitry Andric using namespace clang; 1406c3fb27SDimitry Andric using namespace clang::CodeGen; 1506c3fb27SDimitry Andric 1606c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 1706c3fb27SDimitry Andric // NVPTX ABI Implementation 1806c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 1906c3fb27SDimitry Andric 2006c3fb27SDimitry Andric namespace { 2106c3fb27SDimitry Andric 2206c3fb27SDimitry Andric class NVPTXTargetCodeGenInfo; 2306c3fb27SDimitry Andric 2406c3fb27SDimitry Andric class NVPTXABIInfo : public ABIInfo { 2506c3fb27SDimitry Andric NVPTXTargetCodeGenInfo &CGInfo; 2606c3fb27SDimitry Andric 2706c3fb27SDimitry Andric public: 2806c3fb27SDimitry Andric NVPTXABIInfo(CodeGenTypes &CGT, NVPTXTargetCodeGenInfo &Info) 2906c3fb27SDimitry Andric : ABIInfo(CGT), CGInfo(Info) {} 3006c3fb27SDimitry Andric 3106c3fb27SDimitry Andric ABIArgInfo classifyReturnType(QualType RetTy) const; 3206c3fb27SDimitry Andric ABIArgInfo classifyArgumentType(QualType Ty) const; 3306c3fb27SDimitry Andric 3406c3fb27SDimitry Andric void computeInfo(CGFunctionInfo &FI) const override; 3506c3fb27SDimitry Andric Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, 3606c3fb27SDimitry Andric QualType Ty) const override; 3706c3fb27SDimitry Andric bool isUnsupportedType(QualType T) const; 3806c3fb27SDimitry Andric ABIArgInfo coerceToIntArrayWithLimit(QualType Ty, unsigned MaxSize) const; 3906c3fb27SDimitry Andric }; 4006c3fb27SDimitry Andric 4106c3fb27SDimitry Andric class NVPTXTargetCodeGenInfo : public TargetCodeGenInfo { 4206c3fb27SDimitry Andric public: 4306c3fb27SDimitry Andric NVPTXTargetCodeGenInfo(CodeGenTypes &CGT) 4406c3fb27SDimitry Andric : TargetCodeGenInfo(std::make_unique<NVPTXABIInfo>(CGT, *this)) {} 4506c3fb27SDimitry Andric 4606c3fb27SDimitry Andric void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, 4706c3fb27SDimitry Andric CodeGen::CodeGenModule &M) const override; 4806c3fb27SDimitry Andric bool shouldEmitStaticExternCAliases() const override; 4906c3fb27SDimitry Andric 5006c3fb27SDimitry Andric llvm::Type *getCUDADeviceBuiltinSurfaceDeviceType() const override { 5106c3fb27SDimitry Andric // On the device side, surface reference is represented as an object handle 5206c3fb27SDimitry Andric // in 64-bit integer. 5306c3fb27SDimitry Andric return llvm::Type::getInt64Ty(getABIInfo().getVMContext()); 5406c3fb27SDimitry Andric } 5506c3fb27SDimitry Andric 5606c3fb27SDimitry Andric llvm::Type *getCUDADeviceBuiltinTextureDeviceType() const override { 5706c3fb27SDimitry Andric // On the device side, texture reference is represented as an object handle 5806c3fb27SDimitry Andric // in 64-bit integer. 5906c3fb27SDimitry Andric return llvm::Type::getInt64Ty(getABIInfo().getVMContext()); 6006c3fb27SDimitry Andric } 6106c3fb27SDimitry Andric 6206c3fb27SDimitry Andric bool emitCUDADeviceBuiltinSurfaceDeviceCopy(CodeGenFunction &CGF, LValue Dst, 6306c3fb27SDimitry Andric LValue Src) const override { 6406c3fb27SDimitry Andric emitBuiltinSurfTexDeviceCopy(CGF, Dst, Src); 6506c3fb27SDimitry Andric return true; 6606c3fb27SDimitry Andric } 6706c3fb27SDimitry Andric 6806c3fb27SDimitry Andric bool emitCUDADeviceBuiltinTextureDeviceCopy(CodeGenFunction &CGF, LValue Dst, 6906c3fb27SDimitry Andric LValue Src) const override { 7006c3fb27SDimitry Andric emitBuiltinSurfTexDeviceCopy(CGF, Dst, Src); 7106c3fb27SDimitry Andric return true; 7206c3fb27SDimitry Andric } 7306c3fb27SDimitry Andric 7406c3fb27SDimitry Andric // Adds a NamedMDNode with GV, Name, and Operand as operands, and adds the 7506c3fb27SDimitry Andric // resulting MDNode to the nvvm.annotations MDNode. 7606c3fb27SDimitry Andric static void addNVVMMetadata(llvm::GlobalValue *GV, StringRef Name, 7706c3fb27SDimitry Andric int Operand); 7806c3fb27SDimitry Andric 79*5f757f3fSDimitry Andric private: 8006c3fb27SDimitry Andric static void emitBuiltinSurfTexDeviceCopy(CodeGenFunction &CGF, LValue Dst, 8106c3fb27SDimitry Andric LValue Src) { 8206c3fb27SDimitry Andric llvm::Value *Handle = nullptr; 8306c3fb27SDimitry Andric llvm::Constant *C = 8406c3fb27SDimitry Andric llvm::dyn_cast<llvm::Constant>(Src.getAddress(CGF).getPointer()); 8506c3fb27SDimitry Andric // Lookup `addrspacecast` through the constant pointer if any. 8606c3fb27SDimitry Andric if (auto *ASC = llvm::dyn_cast_or_null<llvm::AddrSpaceCastOperator>(C)) 8706c3fb27SDimitry Andric C = llvm::cast<llvm::Constant>(ASC->getPointerOperand()); 8806c3fb27SDimitry Andric if (auto *GV = llvm::dyn_cast_or_null<llvm::GlobalVariable>(C)) { 8906c3fb27SDimitry Andric // Load the handle from the specific global variable using 9006c3fb27SDimitry Andric // `nvvm.texsurf.handle.internal` intrinsic. 9106c3fb27SDimitry Andric Handle = CGF.EmitRuntimeCall( 9206c3fb27SDimitry Andric CGF.CGM.getIntrinsic(llvm::Intrinsic::nvvm_texsurf_handle_internal, 9306c3fb27SDimitry Andric {GV->getType()}), 9406c3fb27SDimitry Andric {GV}, "texsurf_handle"); 9506c3fb27SDimitry Andric } else 9606c3fb27SDimitry Andric Handle = CGF.EmitLoadOfScalar(Src, SourceLocation()); 9706c3fb27SDimitry Andric CGF.EmitStoreOfScalar(Handle, Dst); 9806c3fb27SDimitry Andric } 9906c3fb27SDimitry Andric }; 10006c3fb27SDimitry Andric 10106c3fb27SDimitry Andric /// Checks if the type is unsupported directly by the current target. 10206c3fb27SDimitry Andric bool NVPTXABIInfo::isUnsupportedType(QualType T) const { 10306c3fb27SDimitry Andric ASTContext &Context = getContext(); 10406c3fb27SDimitry Andric if (!Context.getTargetInfo().hasFloat16Type() && T->isFloat16Type()) 10506c3fb27SDimitry Andric return true; 10606c3fb27SDimitry Andric if (!Context.getTargetInfo().hasFloat128Type() && 10706c3fb27SDimitry Andric (T->isFloat128Type() || 10806c3fb27SDimitry Andric (T->isRealFloatingType() && Context.getTypeSize(T) == 128))) 10906c3fb27SDimitry Andric return true; 11006c3fb27SDimitry Andric if (const auto *EIT = T->getAs<BitIntType>()) 11106c3fb27SDimitry Andric return EIT->getNumBits() > 11206c3fb27SDimitry Andric (Context.getTargetInfo().hasInt128Type() ? 128U : 64U); 11306c3fb27SDimitry Andric if (!Context.getTargetInfo().hasInt128Type() && T->isIntegerType() && 11406c3fb27SDimitry Andric Context.getTypeSize(T) > 64U) 11506c3fb27SDimitry Andric return true; 11606c3fb27SDimitry Andric if (const auto *AT = T->getAsArrayTypeUnsafe()) 11706c3fb27SDimitry Andric return isUnsupportedType(AT->getElementType()); 11806c3fb27SDimitry Andric const auto *RT = T->getAs<RecordType>(); 11906c3fb27SDimitry Andric if (!RT) 12006c3fb27SDimitry Andric return false; 12106c3fb27SDimitry Andric const RecordDecl *RD = RT->getDecl(); 12206c3fb27SDimitry Andric 12306c3fb27SDimitry Andric // If this is a C++ record, check the bases first. 12406c3fb27SDimitry Andric if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) 12506c3fb27SDimitry Andric for (const CXXBaseSpecifier &I : CXXRD->bases()) 12606c3fb27SDimitry Andric if (isUnsupportedType(I.getType())) 12706c3fb27SDimitry Andric return true; 12806c3fb27SDimitry Andric 12906c3fb27SDimitry Andric for (const FieldDecl *I : RD->fields()) 13006c3fb27SDimitry Andric if (isUnsupportedType(I->getType())) 13106c3fb27SDimitry Andric return true; 13206c3fb27SDimitry Andric return false; 13306c3fb27SDimitry Andric } 13406c3fb27SDimitry Andric 13506c3fb27SDimitry Andric /// Coerce the given type into an array with maximum allowed size of elements. 13606c3fb27SDimitry Andric ABIArgInfo NVPTXABIInfo::coerceToIntArrayWithLimit(QualType Ty, 13706c3fb27SDimitry Andric unsigned MaxSize) const { 13806c3fb27SDimitry Andric // Alignment and Size are measured in bits. 13906c3fb27SDimitry Andric const uint64_t Size = getContext().getTypeSize(Ty); 14006c3fb27SDimitry Andric const uint64_t Alignment = getContext().getTypeAlign(Ty); 14106c3fb27SDimitry Andric const unsigned Div = std::min<unsigned>(MaxSize, Alignment); 14206c3fb27SDimitry Andric llvm::Type *IntType = llvm::Type::getIntNTy(getVMContext(), Div); 14306c3fb27SDimitry Andric const uint64_t NumElements = (Size + Div - 1) / Div; 14406c3fb27SDimitry Andric return ABIArgInfo::getDirect(llvm::ArrayType::get(IntType, NumElements)); 14506c3fb27SDimitry Andric } 14606c3fb27SDimitry Andric 14706c3fb27SDimitry Andric ABIArgInfo NVPTXABIInfo::classifyReturnType(QualType RetTy) const { 14806c3fb27SDimitry Andric if (RetTy->isVoidType()) 14906c3fb27SDimitry Andric return ABIArgInfo::getIgnore(); 15006c3fb27SDimitry Andric 15106c3fb27SDimitry Andric if (getContext().getLangOpts().OpenMP && 15206c3fb27SDimitry Andric getContext().getLangOpts().OpenMPIsTargetDevice && 15306c3fb27SDimitry Andric isUnsupportedType(RetTy)) 15406c3fb27SDimitry Andric return coerceToIntArrayWithLimit(RetTy, 64); 15506c3fb27SDimitry Andric 15606c3fb27SDimitry Andric // note: this is different from default ABI 15706c3fb27SDimitry Andric if (!RetTy->isScalarType()) 15806c3fb27SDimitry Andric return ABIArgInfo::getDirect(); 15906c3fb27SDimitry Andric 16006c3fb27SDimitry Andric // Treat an enum type as its underlying type. 16106c3fb27SDimitry Andric if (const EnumType *EnumTy = RetTy->getAs<EnumType>()) 16206c3fb27SDimitry Andric RetTy = EnumTy->getDecl()->getIntegerType(); 16306c3fb27SDimitry Andric 16406c3fb27SDimitry Andric return (isPromotableIntegerTypeForABI(RetTy) ? ABIArgInfo::getExtend(RetTy) 16506c3fb27SDimitry Andric : ABIArgInfo::getDirect()); 16606c3fb27SDimitry Andric } 16706c3fb27SDimitry Andric 16806c3fb27SDimitry Andric ABIArgInfo NVPTXABIInfo::classifyArgumentType(QualType Ty) const { 16906c3fb27SDimitry Andric // Treat an enum type as its underlying type. 17006c3fb27SDimitry Andric if (const EnumType *EnumTy = Ty->getAs<EnumType>()) 17106c3fb27SDimitry Andric Ty = EnumTy->getDecl()->getIntegerType(); 17206c3fb27SDimitry Andric 17306c3fb27SDimitry Andric // Return aggregates type as indirect by value 17406c3fb27SDimitry Andric if (isAggregateTypeForABI(Ty)) { 17506c3fb27SDimitry Andric // Under CUDA device compilation, tex/surf builtin types are replaced with 17606c3fb27SDimitry Andric // object types and passed directly. 17706c3fb27SDimitry Andric if (getContext().getLangOpts().CUDAIsDevice) { 17806c3fb27SDimitry Andric if (Ty->isCUDADeviceBuiltinSurfaceType()) 17906c3fb27SDimitry Andric return ABIArgInfo::getDirect( 18006c3fb27SDimitry Andric CGInfo.getCUDADeviceBuiltinSurfaceDeviceType()); 18106c3fb27SDimitry Andric if (Ty->isCUDADeviceBuiltinTextureType()) 18206c3fb27SDimitry Andric return ABIArgInfo::getDirect( 18306c3fb27SDimitry Andric CGInfo.getCUDADeviceBuiltinTextureDeviceType()); 18406c3fb27SDimitry Andric } 18506c3fb27SDimitry Andric return getNaturalAlignIndirect(Ty, /* byval */ true); 18606c3fb27SDimitry Andric } 18706c3fb27SDimitry Andric 18806c3fb27SDimitry Andric if (const auto *EIT = Ty->getAs<BitIntType>()) { 18906c3fb27SDimitry Andric if ((EIT->getNumBits() > 128) || 19006c3fb27SDimitry Andric (!getContext().getTargetInfo().hasInt128Type() && 19106c3fb27SDimitry Andric EIT->getNumBits() > 64)) 19206c3fb27SDimitry Andric return getNaturalAlignIndirect(Ty, /* byval */ true); 19306c3fb27SDimitry Andric } 19406c3fb27SDimitry Andric 19506c3fb27SDimitry Andric return (isPromotableIntegerTypeForABI(Ty) ? ABIArgInfo::getExtend(Ty) 19606c3fb27SDimitry Andric : ABIArgInfo::getDirect()); 19706c3fb27SDimitry Andric } 19806c3fb27SDimitry Andric 19906c3fb27SDimitry Andric void NVPTXABIInfo::computeInfo(CGFunctionInfo &FI) const { 20006c3fb27SDimitry Andric if (!getCXXABI().classifyReturnType(FI)) 20106c3fb27SDimitry Andric FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); 20206c3fb27SDimitry Andric for (auto &I : FI.arguments()) 20306c3fb27SDimitry Andric I.info = classifyArgumentType(I.type); 20406c3fb27SDimitry Andric 20506c3fb27SDimitry Andric // Always honor user-specified calling convention. 20606c3fb27SDimitry Andric if (FI.getCallingConvention() != llvm::CallingConv::C) 20706c3fb27SDimitry Andric return; 20806c3fb27SDimitry Andric 20906c3fb27SDimitry Andric FI.setEffectiveCallingConvention(getRuntimeCC()); 21006c3fb27SDimitry Andric } 21106c3fb27SDimitry Andric 21206c3fb27SDimitry Andric Address NVPTXABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, 21306c3fb27SDimitry Andric QualType Ty) const { 21406c3fb27SDimitry Andric llvm_unreachable("NVPTX does not support varargs"); 21506c3fb27SDimitry Andric } 21606c3fb27SDimitry Andric 21706c3fb27SDimitry Andric void NVPTXTargetCodeGenInfo::setTargetAttributes( 21806c3fb27SDimitry Andric const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const { 21906c3fb27SDimitry Andric if (GV->isDeclaration()) 22006c3fb27SDimitry Andric return; 22106c3fb27SDimitry Andric const VarDecl *VD = dyn_cast_or_null<VarDecl>(D); 22206c3fb27SDimitry Andric if (VD) { 22306c3fb27SDimitry Andric if (M.getLangOpts().CUDA) { 22406c3fb27SDimitry Andric if (VD->getType()->isCUDADeviceBuiltinSurfaceType()) 22506c3fb27SDimitry Andric addNVVMMetadata(GV, "surface", 1); 22606c3fb27SDimitry Andric else if (VD->getType()->isCUDADeviceBuiltinTextureType()) 22706c3fb27SDimitry Andric addNVVMMetadata(GV, "texture", 1); 22806c3fb27SDimitry Andric return; 22906c3fb27SDimitry Andric } 23006c3fb27SDimitry Andric } 23106c3fb27SDimitry Andric 23206c3fb27SDimitry Andric const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D); 23306c3fb27SDimitry Andric if (!FD) return; 23406c3fb27SDimitry Andric 23506c3fb27SDimitry Andric llvm::Function *F = cast<llvm::Function>(GV); 23606c3fb27SDimitry Andric 23706c3fb27SDimitry Andric // Perform special handling in OpenCL mode 23806c3fb27SDimitry Andric if (M.getLangOpts().OpenCL) { 23906c3fb27SDimitry Andric // Use OpenCL function attributes to check for kernel functions 24006c3fb27SDimitry Andric // By default, all functions are device functions 24106c3fb27SDimitry Andric if (FD->hasAttr<OpenCLKernelAttr>()) { 24206c3fb27SDimitry Andric // OpenCL __kernel functions get kernel metadata 24306c3fb27SDimitry Andric // Create !{<func-ref>, metadata !"kernel", i32 1} node 24406c3fb27SDimitry Andric addNVVMMetadata(F, "kernel", 1); 24506c3fb27SDimitry Andric // And kernel functions are not subject to inlining 24606c3fb27SDimitry Andric F->addFnAttr(llvm::Attribute::NoInline); 24706c3fb27SDimitry Andric } 24806c3fb27SDimitry Andric } 24906c3fb27SDimitry Andric 25006c3fb27SDimitry Andric // Perform special handling in CUDA mode. 25106c3fb27SDimitry Andric if (M.getLangOpts().CUDA) { 25206c3fb27SDimitry Andric // CUDA __global__ functions get a kernel metadata entry. Since 25306c3fb27SDimitry Andric // __global__ functions cannot be called from the device, we do not 25406c3fb27SDimitry Andric // need to set the noinline attribute. 25506c3fb27SDimitry Andric if (FD->hasAttr<CUDAGlobalAttr>()) { 25606c3fb27SDimitry Andric // Create !{<func-ref>, metadata !"kernel", i32 1} node 25706c3fb27SDimitry Andric addNVVMMetadata(F, "kernel", 1); 25806c3fb27SDimitry Andric } 259*5f757f3fSDimitry Andric if (CUDALaunchBoundsAttr *Attr = FD->getAttr<CUDALaunchBoundsAttr>()) 260*5f757f3fSDimitry Andric M.handleCUDALaunchBoundsAttr(F, Attr); 26106c3fb27SDimitry Andric } 26206c3fb27SDimitry Andric 26306c3fb27SDimitry Andric // Attach kernel metadata directly if compiling for NVPTX. 26406c3fb27SDimitry Andric if (FD->hasAttr<NVPTXKernelAttr>()) { 26506c3fb27SDimitry Andric addNVVMMetadata(F, "kernel", 1); 26606c3fb27SDimitry Andric } 26706c3fb27SDimitry Andric } 26806c3fb27SDimitry Andric 26906c3fb27SDimitry Andric void NVPTXTargetCodeGenInfo::addNVVMMetadata(llvm::GlobalValue *GV, 27006c3fb27SDimitry Andric StringRef Name, int Operand) { 27106c3fb27SDimitry Andric llvm::Module *M = GV->getParent(); 27206c3fb27SDimitry Andric llvm::LLVMContext &Ctx = M->getContext(); 27306c3fb27SDimitry Andric 27406c3fb27SDimitry Andric // Get "nvvm.annotations" metadata node 27506c3fb27SDimitry Andric llvm::NamedMDNode *MD = M->getOrInsertNamedMetadata("nvvm.annotations"); 27606c3fb27SDimitry Andric 27706c3fb27SDimitry Andric llvm::Metadata *MDVals[] = { 27806c3fb27SDimitry Andric llvm::ConstantAsMetadata::get(GV), llvm::MDString::get(Ctx, Name), 27906c3fb27SDimitry Andric llvm::ConstantAsMetadata::get( 28006c3fb27SDimitry Andric llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx), Operand))}; 28106c3fb27SDimitry Andric // Append metadata to nvvm.annotations 28206c3fb27SDimitry Andric MD->addOperand(llvm::MDNode::get(Ctx, MDVals)); 28306c3fb27SDimitry Andric } 28406c3fb27SDimitry Andric 28506c3fb27SDimitry Andric bool NVPTXTargetCodeGenInfo::shouldEmitStaticExternCAliases() const { 28606c3fb27SDimitry Andric return false; 28706c3fb27SDimitry Andric } 28806c3fb27SDimitry Andric } 28906c3fb27SDimitry Andric 290*5f757f3fSDimitry Andric void CodeGenModule::handleCUDALaunchBoundsAttr(llvm::Function *F, 291*5f757f3fSDimitry Andric const CUDALaunchBoundsAttr *Attr, 292*5f757f3fSDimitry Andric int32_t *MaxThreadsVal, 293*5f757f3fSDimitry Andric int32_t *MinBlocksVal, 294*5f757f3fSDimitry Andric int32_t *MaxClusterRankVal) { 295*5f757f3fSDimitry Andric // Create !{<func-ref>, metadata !"maxntidx", i32 <val>} node 296*5f757f3fSDimitry Andric llvm::APSInt MaxThreads(32); 297*5f757f3fSDimitry Andric MaxThreads = Attr->getMaxThreads()->EvaluateKnownConstInt(getContext()); 298*5f757f3fSDimitry Andric if (MaxThreads > 0) { 299*5f757f3fSDimitry Andric if (MaxThreadsVal) 300*5f757f3fSDimitry Andric *MaxThreadsVal = MaxThreads.getExtValue(); 301*5f757f3fSDimitry Andric if (F) { 302*5f757f3fSDimitry Andric // Create !{<func-ref>, metadata !"maxntidx", i32 <val>} node 303*5f757f3fSDimitry Andric NVPTXTargetCodeGenInfo::addNVVMMetadata(F, "maxntidx", 304*5f757f3fSDimitry Andric MaxThreads.getExtValue()); 305*5f757f3fSDimitry Andric } 306*5f757f3fSDimitry Andric } 307*5f757f3fSDimitry Andric 308*5f757f3fSDimitry Andric // min and max blocks is an optional argument for CUDALaunchBoundsAttr. If it 309*5f757f3fSDimitry Andric // was not specified in __launch_bounds__ or if the user specified a 0 value, 310*5f757f3fSDimitry Andric // we don't have to add a PTX directive. 311*5f757f3fSDimitry Andric if (Attr->getMinBlocks()) { 312*5f757f3fSDimitry Andric llvm::APSInt MinBlocks(32); 313*5f757f3fSDimitry Andric MinBlocks = Attr->getMinBlocks()->EvaluateKnownConstInt(getContext()); 314*5f757f3fSDimitry Andric if (MinBlocks > 0) { 315*5f757f3fSDimitry Andric if (MinBlocksVal) 316*5f757f3fSDimitry Andric *MinBlocksVal = MinBlocks.getExtValue(); 317*5f757f3fSDimitry Andric if (F) { 318*5f757f3fSDimitry Andric // Create !{<func-ref>, metadata !"minctasm", i32 <val>} node 319*5f757f3fSDimitry Andric NVPTXTargetCodeGenInfo::addNVVMMetadata(F, "minctasm", 320*5f757f3fSDimitry Andric MinBlocks.getExtValue()); 321*5f757f3fSDimitry Andric } 322*5f757f3fSDimitry Andric } 323*5f757f3fSDimitry Andric } 324*5f757f3fSDimitry Andric if (Attr->getMaxBlocks()) { 325*5f757f3fSDimitry Andric llvm::APSInt MaxBlocks(32); 326*5f757f3fSDimitry Andric MaxBlocks = Attr->getMaxBlocks()->EvaluateKnownConstInt(getContext()); 327*5f757f3fSDimitry Andric if (MaxBlocks > 0) { 328*5f757f3fSDimitry Andric if (MaxClusterRankVal) 329*5f757f3fSDimitry Andric *MaxClusterRankVal = MaxBlocks.getExtValue(); 330*5f757f3fSDimitry Andric if (F) { 331*5f757f3fSDimitry Andric // Create !{<func-ref>, metadata !"maxclusterrank", i32 <val>} node 332*5f757f3fSDimitry Andric NVPTXTargetCodeGenInfo::addNVVMMetadata(F, "maxclusterrank", 333*5f757f3fSDimitry Andric MaxBlocks.getExtValue()); 334*5f757f3fSDimitry Andric } 335*5f757f3fSDimitry Andric } 336*5f757f3fSDimitry Andric } 337*5f757f3fSDimitry Andric } 338*5f757f3fSDimitry Andric 33906c3fb27SDimitry Andric std::unique_ptr<TargetCodeGenInfo> 34006c3fb27SDimitry Andric CodeGen::createNVPTXTargetCodeGenInfo(CodeGenModule &CGM) { 34106c3fb27SDimitry Andric return std::make_unique<NVPTXTargetCodeGenInfo>(CGM.getTypes()); 34206c3fb27SDimitry Andric } 343