clang 24.0.0git
SPIRV.cpp
Go to the documentation of this file.
1//===---- SPIRV.cpp - SPIR-V-specific CIR CodeGen -------------------------===//
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// This provides SPIR/SPIRV-specific CIR CodeGen logic for function attributes.
10//
11//===----------------------------------------------------------------------===//
12
13#include "../CIRGenModule.h"
14#include "../TargetInfo.h"
15
16#include "clang/AST/Attr.h"
17#include "clang/AST/Decl.h"
20
21using namespace clang;
22using namespace clang::CIRGen;
23
24namespace {
25
26class CommonSPIRABIInfo : public ABIInfo {
27public:
28 CommonSPIRABIInfo(CIRGenTypes &cgt) : ABIInfo(cgt) {}
29};
30
31class CommonSPIRTargetCIRGenInfo : public TargetCIRGenInfo {
32public:
33 CommonSPIRTargetCIRGenInfo(CIRGenTypes &cgt)
34 : TargetCIRGenInfo(std::make_unique<CommonSPIRABIInfo>(cgt)) {}
35
36 mlir::ptr::MemorySpaceAttrInterface
37 getCIRAllocaAddressSpace() const override {
38 return cir::LangAddressSpaceAttr::get(
39 &getABIInfo().cgt.getMLIRContext(),
40 cir::LangAddressSpace::OffloadPrivate);
41 }
42
43 mlir::ptr::MemorySpaceAttrInterface
44 getGlobalCIRAddressSpace(LangAS as) const override {
45 // The cir::LangAddressSpace fold loses the SPIRDefIsGenMap split between
46 // cuda_constant and opencl_constant, so use the target map like classic.
47 if (as == LangAS::cuda_device || as == LangAS::cuda_constant ||
48 as == LangAS::cuda_shared)
49 return cir::TargetAddressSpaceAttr::get(
50 &getABIInfo().cgt.getMLIRContext(),
51 getABIInfo().cgt.getASTContext().getTargetAddressSpace(as));
53 }
54
55 void setTargetAttributes(const clang::Decl *decl, mlir::Operation *global,
56 CIRGenModule &cgm) const override {
57 auto func = mlir::dyn_cast<cir::FuncOp>(global);
58 if (!func || func.isDeclaration())
59 return;
60
61 const auto *fd = dyn_cast_or_null<FunctionDecl>(decl);
62 if (!fd)
63 return;
64
65 if (!cgm.getLangOpts().HIP || !cgm.getTriple().isSPIRV() ||
66 cgm.getTriple().getVendor() != llvm::Triple::AMD)
67 return;
68
69 if (!fd->hasAttr<CUDAGlobalAttr>())
70 return;
71
72 unsigned n = cgm.getLangOpts().GPUMaxThreadsPerBlock;
73 if (const auto *flatWGS = fd->getAttr<AMDGPUFlatWorkGroupSizeAttr>()) {
74 n = flatWGS->getMax()
75 ->EvaluateKnownConstInt(cgm.getASTContext())
76 .getExtValue();
77 } else if (const auto *lb = fd->getAttr<CUDALaunchBoundsAttr>()) {
78 if (uint64_t maxThreads = lb->getMaxThreads()
79 ->EvaluateKnownConstInt(cgm.getASTContext())
80 .getExtValue())
81 n = maxThreads;
82 }
83
84 // Only x carries the flat WG size, reverse translated for AMDGPU targets.
85 func->setAttr(
86 cir::CIRDialect::getMaxWorkGroupSizeAttrName(),
87 cir::MaxWorkGroupSizeAttr::get(func.getContext(), n, /*y=*/1, /*z=*/1));
88 }
89
90 cir::CallingConv getDeviceKernelCallingConv() const override {
91 return cir::CallingConv::SpirKernel;
92 }
93
94 bool supportsLibCall() const override {
95 const llvm::Triple &triple = getABIInfo().cgt.getCGModule().getTriple();
96 return !(triple.isSPIRV() && triple.getVendor() == llvm::Triple::AMD);
97 }
98
99 void setCUDAKernelCallingConvention(const FunctionType *&ft) const override {
100 // Convert HIP kernels to SPIR-V kernels.
101 if (getABIInfo().cgt.getASTContext().getLangOpts().HIP)
102 ft = getABIInfo().cgt.getASTContext().adjustFunctionType(
104 }
105
106 mlir::Value getNullPointer(CIRGenModule &cgm, cir::PointerType ptrTy,
107 QualType qt, mlir::Location loc) const override;
108};
109
110} // namespace
111
112// The bit pattern of null in non-generic AS is unspecified for SPIR(-V), so
113// materialize it via an address space cast from null in generic AS.
114mlir::Value
115CommonSPIRTargetCIRGenInfo::getNullPointer(CIRGenModule &cgm,
116 cir::PointerType ptrTy, QualType qt,
117 mlir::Location loc) const {
118 CIRGenBuilderTy &builder = cgm.getBuilder();
120 return builder.getNullPtr(ptrTy, loc);
121
122 cir::PointerType genericPtrTy =
123 builder.getPointerTo(ptrTy.getPointee(), LangAS::opencl_generic);
124 return builder.createAddrSpaceCast(loc, builder.getNullPtr(genericPtrTy, loc),
125 ptrTy);
126}
127
128std::unique_ptr<TargetCIRGenInfo>
130 return std::make_unique<CommonSPIRTargetCIRGenInfo>(cgt);
131}
static void setCUDAKernelCallingConvention(CanQualType &funcTy, CIRGenModule &cgm, const FunctionDecl *fd)
Set calling convention for CUDA/HIP kernel.
cir::PointerType getPointerTo(mlir::Type ty)
cir::ConstantOp getNullPtr(mlir::Type ty, mlir::Location loc)
mlir::Value createAddrSpaceCast(mlir::Location loc, mlir::Value src, mlir::Type newTy)
This class organizes the cross-function state that is used while generating CIR code.
clang::ASTContext & getASTContext() const
CIRGenBuilderTy & getBuilder()
const llvm::Triple & getTriple() const
const clang::LangOptions & getLangOpts() const
This class organizes the cross-module state that is used while lowering AST types to CIR types.
Definition CIRGenTypes.h:51
virtual mlir::ptr::MemorySpaceAttrInterface getGlobalCIRAddressSpace(clang::LangAS as) const
Get the CIR address space attribute for a global in AST address space as.
Definition TargetInfo.h:76
ExtInfo withCallingConv(CallingConv cc) const
Definition TypeBase.h:4835
ExtInfo getExtInfo() const
Definition TypeBase.h:4968
A (possibly-)qualified type.
Definition TypeBase.h:938
std::unique_ptr< TargetCIRGenInfo > createCommonSPIRTargetCIRGenInfo(CIRGenTypes &cgt)
Definition SPIRV.cpp:129
bool spirNullPointerNeedsGenericCast(QualType QT, const llvm::Triple &Triple)
Return true if a SPIR(-V) null pointer of type QT must be materialized as an addrspacecast from a gen...
const internal::VariadicAllOfMatcher< Decl > decl
Matches declarations.
Top level wrappers for InstallAPI frontend operations.
LangAS
Defines the address space values used by the address space qualifier of QualType.
@ CC_DeviceKernel
Definition Specifiers.h:295