clang 24.0.0git
SPIR.cpp
Go to the documentation of this file.
1//===- SPIR.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"
11#include "TargetInfo.h"
12#include "clang/AST/DeclCXX.h"
15#include "llvm/IR/DerivedTypes.h"
16#include "llvm/IR/LLVMContext.h"
17
18#include <stdint.h>
19#include <utility>
20
21using namespace clang;
22using namespace clang::CodeGen;
23
24//===----------------------------------------------------------------------===//
25// Base ABI and target codegen info implementation common between SPIR and
26// SPIR-V.
27//===----------------------------------------------------------------------===//
28
29namespace {
30class CommonSPIRABIInfo : public DefaultABIInfo {
31public:
32 CommonSPIRABIInfo(CodeGenTypes &CGT) : DefaultABIInfo(CGT) { setCCs(); }
33
34private:
35 void setCCs();
36};
37
38class SPIRVABIInfo : public CommonSPIRABIInfo {
39public:
40 SPIRVABIInfo(CodeGenTypes &CGT) : CommonSPIRABIInfo(CGT) {}
41 void computeInfo(CGFunctionInfo &FI) const override;
42 RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
43 AggValueSlot Slot) const override;
44
45 llvm::FixedVectorType *
46 getOptimalVectorMemoryType(llvm::FixedVectorType *Ty,
47 const LangOptions &LangOpt) const override;
48
49private:
50 ABIArgInfo classifyKernelArgumentType(QualType Ty) const;
51};
52
53class AMDGCNSPIRVABIInfo : public SPIRVABIInfo {
54 // TODO: this should be unified / shared with AMDGPU, ideally we'd like to
55 // re-use AMDGPUABIInfo eventually, rather than duplicate.
56 static constexpr unsigned MaxNumRegsForArgsRet = 16; // 16 32-bit registers
57 mutable unsigned NumRegsLeft = 0;
58
59 uint64_t numRegsForType(QualType Ty) const;
60
61 bool isHomogeneousAggregateBaseType(QualType Ty) const override {
62 return true;
63 }
64 bool isHomogeneousAggregateSmallEnough(const Type *Base,
65 uint64_t Members) const override {
66 uint32_t NumRegs = (getContext().getTypeSize(Base) + 31) / 32;
67
68 // Homogeneous Aggregates may occupy at most 16 registers.
69 return Members * NumRegs <= MaxNumRegsForArgsRet;
70 }
71
72 // Coerce HIP scalar pointer arguments from generic pointers to global ones.
73 llvm::Type *coerceKernelArgumentType(llvm::Type *Ty, unsigned FromAS,
74 unsigned ToAS) const;
75
76 ABIArgInfo classifyReturnType(QualType RetTy) const;
77 ABIArgInfo classifyKernelArgumentType(QualType Ty) const;
78 ABIArgInfo classifyArgumentType(QualType Ty, bool Variadic) const;
79
80public:
81 AMDGCNSPIRVABIInfo(CodeGenTypes &CGT) : SPIRVABIInfo(CGT) {}
82 void computeInfo(CGFunctionInfo &FI) const override;
83
84 llvm::FixedVectorType *
85 getOptimalVectorMemoryType(llvm::FixedVectorType *Ty,
86 const LangOptions &LangOpt) const override;
87};
88} // end anonymous namespace
89namespace {
90class CommonSPIRTargetCodeGenInfo : public TargetCodeGenInfo {
91public:
92 CommonSPIRTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
93 : TargetCodeGenInfo(std::make_unique<CommonSPIRABIInfo>(CGT)) {}
94 CommonSPIRTargetCodeGenInfo(std::unique_ptr<ABIInfo> ABIInfo)
95 : TargetCodeGenInfo(std::move(ABIInfo)) {}
96
97 unsigned getDeviceKernelCallingConv() const override;
98 llvm::Type *getOpenCLType(CodeGenModule &CGM, const Type *T) const override;
99 llvm::Type *getHLSLType(CodeGenModule &CGM, const Type *Ty,
100 const CGHLSLOffsetInfo &OffsetInfo) const override;
101
102 llvm::Type *getHLSLPadding(CodeGenModule &CGM,
103 CharUnits NumBytes) const override {
104 unsigned Size = NumBytes.getQuantity();
105 return llvm::TargetExtType::get(CGM.getLLVMContext(), "spirv.Padding", {},
106 {Size});
107 }
108
109 bool isHLSLPadding(llvm::Type *Ty) const override {
110 if (auto *TET = dyn_cast<llvm::TargetExtType>(Ty))
111 return TET->getName() == "spirv.Padding";
112 return false;
113 }
114
115 llvm::Type *getSPIRVImageTypeFromHLSLResource(
116 const HLSLAttributedResourceType::Attributes &attributes,
117 QualType SampledType, CodeGenModule &CGM) const;
118 void
119 setOCLKernelStubCallingConvention(const FunctionType *&FT) const override;
120 llvm::Constant *getNullPointer(const CodeGen::CodeGenModule &CGM,
121 llvm::PointerType *T,
122 QualType QT) const override;
123};
124class SPIRVTargetCodeGenInfo : public CommonSPIRTargetCodeGenInfo {
125public:
126 SPIRVTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
127 : CommonSPIRTargetCodeGenInfo(
128 (CGT.getTarget().getTriple().getVendor() == llvm::Triple::AMD)
129 ? std::make_unique<AMDGCNSPIRVABIInfo>(CGT)
130 : std::make_unique<SPIRVABIInfo>(CGT)) {}
131 void setCUDAKernelCallingConvention(const FunctionType *&FT) const override;
132 LangAS getGlobalVarAddressSpace(CodeGenModule &CGM,
133 const VarDecl *D) const override;
134 void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
135 CodeGen::CodeGenModule &M) const override;
136 StringRef getLLVMSyncScopeStr(const LangOptions &LangOpts, SyncScope Scope,
137 llvm::AtomicOrdering Ordering) const override;
138 void setTargetAtomicMetadata(CodeGenFunction &CGF,
139 llvm::Instruction &AtomicInst,
140 const AtomicExpr *Expr = nullptr) const override;
141 bool supportsLibCall() const override {
142 return getABIInfo().getTarget().getTriple().getVendor() !=
143 llvm::Triple::AMD;
144 }
145
146 LangAS getSRetAddrSpace(const CXXRecordDecl *RD) const override;
147};
148} // End anonymous namespace.
149
150void CommonSPIRABIInfo::setCCs() {
151 assert(getRuntimeCC() == llvm::CallingConv::C);
152 RuntimeCC = llvm::CallingConv::SPIR_FUNC;
153}
154
155ABIArgInfo SPIRVABIInfo::classifyKernelArgumentType(QualType Ty) const {
156 // Coerce pointer arguments with default address space to CrossWorkGroup
157 // pointers as default address space kernel
158 // arguments are not allowed. We use the opencl_global language address
159 // space which always maps to CrossWorkGroup.
160 llvm::Type *LTy = CGT.ConvertType(Ty);
161 auto DefaultAS = getContext().getTargetAddressSpace(LangAS::Default);
162 auto GlobalAS = getContext().getTargetAddressSpace(LangAS::opencl_global);
163 auto *PtrTy = llvm::dyn_cast<llvm::PointerType>(LTy);
164 if (PtrTy && PtrTy->getAddressSpace() == DefaultAS) {
165 LTy = llvm::PointerType::get(PtrTy->getContext(), GlobalAS);
166 return ABIArgInfo::getDirect(LTy, 0, nullptr, false);
167 }
168
169 if (getContext().getLangOpts().isTargetDevice() &&
171 // Force copying aggregate type in kernel arguments by value when
172 // compiling CUDA targeting SPIR-V. This is required for the object
173 // copied to be valid on the device.
174 // This behavior follows the CUDA spec
175 // https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#global-function-argument-processing,
176 // and matches the NVPTX implementation. TODO: hardcoding to 0 should be
177 // revisited if HIPSPV / byval starts making use of the AS of an indirect
178 // arg.
179 return getNaturalAlignIndirect(Ty, /*AddrSpace=*/0, /*byval=*/true);
180 }
181 return classifyArgumentType(Ty);
182}
183
184void SPIRVABIInfo::computeInfo(CGFunctionInfo &FI) const {
185 // The logic is same as in DefaultABIInfo with an exception on the kernel
186 // arguments handling.
187 llvm::CallingConv::ID CC = FI.getCallingConvention();
188
189 if (!getCXXABI().classifyReturnType(FI))
191
192 for (auto &I : FI.arguments()) {
193 if (CC == llvm::CallingConv::SPIR_KERNEL) {
194 I.info = classifyKernelArgumentType(I.type);
195 } else {
196 I.info = classifyArgumentType(I.type);
197 }
198 }
199}
200
201RValue SPIRVABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
202 QualType Ty, AggValueSlot Slot) const {
203 return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*IsIndirect=*/false,
204 getContext().getTypeInfoInChars(Ty),
206 /*AllowHigherAlign=*/true, Slot);
207}
208
209uint64_t AMDGCNSPIRVABIInfo::numRegsForType(QualType Ty) const {
210 // This duplicates the AMDGPUABI computation.
211 uint64_t NumRegs = 0;
212
213 if (const VectorType *VT = Ty->getAs<VectorType>()) {
214 // Compute from the number of elements. The reported size is based on the
215 // in-memory size, which includes the padding 4th element for 3-vectors.
216 QualType EltTy = VT->getElementType();
217 uint64_t EltSize = getContext().getTypeSize(EltTy);
218
219 // 16-bit element vectors should be passed as packed.
220 if (EltSize == 16)
221 return (VT->getNumElements() + 1) / 2;
222
223 uint64_t EltNumRegs = (EltSize + 31) / 32;
224 return EltNumRegs * VT->getNumElements();
225 }
226
227 if (const auto *RD = Ty->getAsRecordDecl()) {
228 assert(!RD->hasFlexibleArrayMember());
229
230 for (const FieldDecl *Field : RD->fields()) {
231 QualType FieldTy = Field->getType();
232 NumRegs += numRegsForType(FieldTy);
233 }
234
235 return NumRegs;
236 }
237
238 return (getContext().getTypeSize(Ty) + 31) / 32;
239}
240
241llvm::Type *AMDGCNSPIRVABIInfo::coerceKernelArgumentType(llvm::Type *Ty,
242 unsigned FromAS,
243 unsigned ToAS) const {
244 // Single value types.
245 auto *PtrTy = llvm::dyn_cast<llvm::PointerType>(Ty);
246 if (PtrTy && PtrTy->getAddressSpace() == FromAS)
247 return llvm::PointerType::get(Ty->getContext(), ToAS);
248 return Ty;
249}
250
251ABIArgInfo AMDGCNSPIRVABIInfo::classifyReturnType(QualType RetTy) const {
252 if (!isAggregateTypeForABI(RetTy) || getRecordArgABI(RetTy, getCXXABI()))
254
255 // Ignore empty structs/unions.
256 if (isEmptyRecord(getContext(), RetTy, true))
257 return ABIArgInfo::getIgnore();
258
259 // Lower single-element structs to just return a regular value.
260 if (const Type *SeltTy = isSingleElementRecord(RetTy, getContext()))
261 return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
262
263 if (const auto *RD = RetTy->getAsRecordDecl();
264 RD && RD->hasFlexibleArrayMember())
266
267 // Pack aggregates <= 4 bytes into single VGPR or pair.
268 uint64_t Size = getContext().getTypeSize(RetTy);
269 if (Size <= 16)
270 return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext()));
271
272 if (Size <= 32)
273 return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext()));
274
275 // TODO: This carried over from AMDGPU oddity, we retain it to
276 // ensure consistency, but it might be reasonable to return Int64.
277 if (Size <= 64) {
278 llvm::Type *I32Ty = llvm::Type::getInt32Ty(getVMContext());
279 return ABIArgInfo::getDirect(llvm::ArrayType::get(I32Ty, 2));
280 }
281
282 if (numRegsForType(RetTy) <= MaxNumRegsForArgsRet)
283 return ABIArgInfo::getDirect();
285}
286
287/// For kernels all parameters are really passed in a special buffer. It doesn't
288/// make sense to pass anything byval, so everything must be direct.
289ABIArgInfo AMDGCNSPIRVABIInfo::classifyKernelArgumentType(QualType Ty) const {
291
292 // TODO: Can we omit empty structs?
293
294 if (const Type *SeltTy = isSingleElementRecord(Ty, getContext()))
295 Ty = QualType(SeltTy, 0);
296
297 llvm::Type *OrigLTy = CGT.ConvertType(Ty);
298 llvm::Type *LTy = OrigLTy;
299 if (getContext().getLangOpts().isTargetDevice()) {
300 LTy = coerceKernelArgumentType(
301 OrigLTy, /*FromAS=*/getContext().getTargetAddressSpace(LangAS::Default),
302 /*ToAS=*/getContext().getTargetAddressSpace(LangAS::opencl_global));
303 }
304
305 // FIXME: This doesn't apply the optimization of coercing pointers in structs
306 // to global address space when using byref. This would require implementing a
307 // new kind of coercion of the in-memory type when for indirect arguments.
308 if (LTy == OrigLTy && isAggregateTypeForABI(Ty)) {
310 getContext().getTypeAlignInChars(Ty),
311 getContext().getTargetAddressSpace(LangAS::opencl_constant),
312 false /*Realign*/, nullptr /*Padding*/);
313 }
314
315 // TODO: inhibiting flattening is an AMDGPU workaround for Clover, which might
316 // be vestigial and should be revisited.
317 return ABIArgInfo::getDirect(LTy, 0, nullptr, false);
318}
319
320ABIArgInfo AMDGCNSPIRVABIInfo::classifyArgumentType(QualType Ty,
321 bool Variadic) const {
322 assert(NumRegsLeft <= MaxNumRegsForArgsRet && "register estimate underflow");
323
325
326 if (Variadic) {
327 return ABIArgInfo::getDirect(/*T=*/nullptr,
328 /*Offset=*/0,
329 /*Padding=*/nullptr,
330 /*CanBeFlattened=*/false,
331 /*Align=*/0);
332 }
333
334 if (!isAggregateTypeForABI(Ty)) {
335 ABIArgInfo ArgInfo = DefaultABIInfo::classifyArgumentType(Ty);
336 if (!ArgInfo.isIndirect()) {
337 uint64_t NumRegs = numRegsForType(Ty);
338 NumRegsLeft -= std::min(NumRegs, uint64_t{NumRegsLeft});
339 }
340
341 return ArgInfo;
342 }
343
344 // Records with non-trivial destructors/copy-constructors should not be
345 // passed by value.
346 if (auto RAA = getRecordArgABI(Ty, getCXXABI()))
347 return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace(),
349
350 // Ignore empty structs/unions.
351 if (isEmptyRecord(getContext(), Ty, true))
352 return ABIArgInfo::getIgnore();
353
354 // Lower single-element structs to just pass a regular value. TODO: We
355 // could do reasonable-size multiple-element structs too, using getExpand(),
356 // though watch out for things like bitfields.
357 if (const Type *SeltTy = isSingleElementRecord(Ty, getContext()))
358 return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
359
360 if (const auto *RD = Ty->getAsRecordDecl();
361 RD && RD->hasFlexibleArrayMember())
363
364 uint64_t Size = getContext().getTypeSize(Ty);
365 if (Size <= 64) {
366 // Pack aggregates <= 8 bytes into single VGPR or pair.
367 unsigned NumRegs = (Size + 31) / 32;
368 NumRegsLeft -= std::min(NumRegsLeft, NumRegs);
369
370 if (Size <= 16)
371 return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext()));
372
373 if (Size <= 32)
374 return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext()));
375
376 // TODO: This is an AMDGPU oddity, and might be vestigial, we retain it to
377 // ensure consistency, but it should be revisited.
378 llvm::Type *I32Ty = llvm::Type::getInt32Ty(getVMContext());
379 return ABIArgInfo::getDirect(llvm::ArrayType::get(I32Ty, 2));
380 }
381
382 if (NumRegsLeft > 0) {
383 uint64_t NumRegs = numRegsForType(Ty);
384 if (NumRegsLeft >= NumRegs) {
385 NumRegsLeft -= NumRegs;
386 return ABIArgInfo::getDirect();
387 }
388 }
389
390 // Use pass-by-reference in stead of pass-by-value for struct arguments in
391 // function ABI.
393 getContext().getTypeAlignInChars(Ty),
394 getContext().getTargetAddressSpace(LangAS::opencl_private));
395}
396
397void AMDGCNSPIRVABIInfo::computeInfo(CGFunctionInfo &FI) const {
398 llvm::CallingConv::ID CC = FI.getCallingConvention();
399
400 if (!getCXXABI().classifyReturnType(FI))
402
403 unsigned ArgumentIndex = 0;
404 const unsigned NumRequiredArgs = FI.getNumRequiredArgs();
405
406 NumRegsLeft = MaxNumRegsForArgsRet;
407 for (auto &I : FI.arguments()) {
408 if (CC == llvm::CallingConv::SPIR_KERNEL) {
409 I.info = classifyKernelArgumentType(I.type);
410 } else {
411 bool FixedArgument = ArgumentIndex++ < NumRequiredArgs;
412 I.info = classifyArgumentType(I.type, !FixedArgument);
413 }
414 }
415}
416
417llvm::FixedVectorType *
418SPIRVABIInfo::getOptimalVectorMemoryType(llvm::FixedVectorType *Ty,
419 const LangOptions &LangOpt) const {
420 // For Logical SPIR-V, we don't know the underlying hardware or layout.
421 // This means we don't know which vector size is better, and also cannot
422 // assume a smaller vector size is stored in a larger vector size.
423 if (getTarget().getTriple().isSPIRVLogical())
424 return Ty;
425 return DefaultABIInfo::getOptimalVectorMemoryType(Ty, LangOpt);
426}
427
428llvm::FixedVectorType *AMDGCNSPIRVABIInfo::getOptimalVectorMemoryType(
429 llvm::FixedVectorType *Ty, const LangOptions &LangOpt) const {
430 // AMDGPU has legal instructions for 96-bit so 3x32 can be supported.
431 if (Ty->getNumElements() == 3 && getDataLayout().getTypeSizeInBits(Ty) == 96)
432 return Ty;
433 return DefaultABIInfo::getOptimalVectorMemoryType(Ty, LangOpt);
434}
435
436namespace clang {
437namespace CodeGen {
439 if (CGM.getTarget().getTriple().isSPIRV()) {
440 if (CGM.getTarget().getTriple().getVendor() == llvm::Triple::AMD)
441 AMDGCNSPIRVABIInfo(CGM.getTypes()).computeInfo(FI);
442 else
443 SPIRVABIInfo(CGM.getTypes()).computeInfo(FI);
444 } else {
445 CommonSPIRABIInfo(CGM.getTypes()).computeInfo(FI);
446 }
447}
448}
449}
450
451unsigned CommonSPIRTargetCodeGenInfo::getDeviceKernelCallingConv() const {
452 return llvm::CallingConv::SPIR_KERNEL;
453}
454
455LangAS SPIRVTargetCodeGenInfo::getSRetAddrSpace(const CXXRecordDecl *RD) const {
456 // Types with no viable copy/move must be constructed in-place, use the
457 // default AS so the sret pointer matches the "this" convention.
458 if (RD && !RD->canPassInRegisters())
459 return LangAS::Default;
461 getABIInfo().getDataLayout().getAllocaAddrSpace());
462}
463
464void SPIRVTargetCodeGenInfo::setCUDAKernelCallingConvention(
465 const FunctionType *&FT) const {
466 // Convert HIP kernels to SPIR-V kernels.
467 if (getABIInfo().getContext().getLangOpts().HIP) {
468 FT = getABIInfo().getContext().adjustFunctionType(
470 return;
471 }
472}
473
474void CommonSPIRTargetCodeGenInfo::setOCLKernelStubCallingConvention(
475 const FunctionType *&FT) const {
476 FT = getABIInfo().getContext().adjustFunctionType(
477 FT, FT->getExtInfo().withCallingConv(CC_C));
478}
479
480// LLVM currently assumes a null pointer has the bit pattern 0, but some GPU
481// targets use a non-zero encoding for null in certain address spaces.
482// Because SPIR(-V) is a generic target and the bit pattern of null in
483// non-generic AS is unspecified, materialize null in non-generic AS via an
484// addrspacecast from null in generic AS. This allows later lowering to
485// substitute the target's real sentinel value.
486llvm::Constant *
487CommonSPIRTargetCodeGenInfo::getNullPointer(const CodeGen::CodeGenModule &CGM,
488 llvm::PointerType *PT,
489 QualType QT) const {
491 return llvm::ConstantPointerNull::get(PT);
492
493 auto &Ctx = CGM.getContext();
494 auto NPT = llvm::PointerType::get(
495 PT->getContext(), Ctx.getTargetAddressSpace(LangAS::opencl_generic));
496 return llvm::ConstantExpr::getAddrSpaceCast(
497 llvm::ConstantPointerNull::get(NPT), PT);
498}
499
500LangAS
501SPIRVTargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM,
502 const VarDecl *D) const {
503 assert(!CGM.getLangOpts().OpenCL &&
504 !(CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) &&
505 "Address space agnostic languages only");
506 // If we're here it means that we're using the SPIRDefIsGen ASMap, hence for
507 // the global AS we can rely on either cuda_device or sycl_global to be
508 // correct; however, since this is not a CUDA Device context, we use
509 // sycl_global to prevent confusion with the assertion.
510 LangAS DefaultGlobalAS = getLangASFromTargetAS(
511 CGM.getContext().getTargetAddressSpace(LangAS::sycl_global));
512 if (!D)
513 return DefaultGlobalAS;
514
515 LangAS AddrSpace = D->getType().getAddressSpace();
516 if (AddrSpace != LangAS::Default)
517 return AddrSpace;
518
519 return DefaultGlobalAS;
520}
521
522void SPIRVTargetCodeGenInfo::setTargetAttributes(
523 const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const {
524 if (GV->isDeclaration())
525 return;
526
527 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
528 if (!FD)
529 return;
530
531 llvm::Function *F = dyn_cast<llvm::Function>(GV);
532 assert(F && "Expected GlobalValue to be a Function");
533
534 if (!M.getLangOpts().HIP ||
535 M.getTarget().getTriple().getVendor() != llvm::Triple::AMD)
536 return;
537
538 if (!FD->hasAttr<CUDAGlobalAttr>())
539 return;
540
541 unsigned N = M.getLangOpts().GPUMaxThreadsPerBlock;
542 if (auto FlatWGS = FD->getAttr<AMDGPUFlatWorkGroupSizeAttr>()) {
543 N = FlatWGS->getMax()->EvaluateKnownConstInt(M.getContext()).getExtValue();
544 } else if (auto LB = FD->getAttr<CUDALaunchBoundsAttr>()) {
545 if (uint64_t MaxThreads = LB->getMaxThreads()
546 ->EvaluateKnownConstInt(M.getContext())
547 .getExtValue())
548 N = MaxThreads;
549 }
550
551 // We encode the maximum flat WG size in the first component of the 3D
552 // max_work_group_size attribute, which will get reverse translated into the
553 // original AMDGPU attribute when targeting AMDGPU.
554 auto Int32Ty = llvm::IntegerType::getInt32Ty(M.getLLVMContext());
555 llvm::Metadata *AttrMDArgs[] = {
556 llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(Int32Ty, N)),
557 llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(Int32Ty, 1)),
558 llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(Int32Ty, 1))};
559
560 F->setMetadata("max_work_group_size",
561 llvm::MDNode::get(M.getLLVMContext(), AttrMDArgs));
562}
563
564StringRef SPIRVTargetCodeGenInfo::getLLVMSyncScopeStr(
565 const LangOptions &, SyncScope Scope, llvm::AtomicOrdering) const {
566 return *llvm::getAtomicScopeIRString(getABIInfo().getTarget().getTriple(),
567 getAtomicScope(Scope));
568}
569
570void SPIRVTargetCodeGenInfo::setTargetAtomicMetadata(
571 CodeGenFunction &CGF, llvm::Instruction &AtomicInst,
572 const AtomicExpr *AE) const {
573 if (CGF.CGM.getTriple().getVendor() != llvm::Triple::VendorType::AMD)
574 return;
575
576 auto *RMW = dyn_cast<llvm::AtomicRMWInst>(&AtomicInst);
577 if (!RMW)
578 return;
579
580 AtomicOptions AO = CGF.CGM.getAtomicOpts();
581 llvm::MDNode *Empty = llvm::MDNode::get(CGF.getLLVMContext(), {});
583 RMW->setMetadata("amdgpu.no.fine.grained.memory", Empty);
585 RMW->setMetadata("amdgpu.no.remote.memory", Empty);
588}
589
590/// Construct a SPIR-V target extension type for the given OpenCL image type.
591static llvm::Type *getSPIRVImageType(llvm::LLVMContext &Ctx, StringRef BaseType,
592 StringRef OpenCLName,
593 unsigned AccessQualifier) {
594 // These parameters compare to the operands of OpTypeImage (see
595 // https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpTypeImage
596 // for more details). The first 6 integer parameters all default to 0, and
597 // will be changed to 1 only for the image type(s) that set the parameter to
598 // one. The 7th integer parameter is the access qualifier, which is tacked on
599 // at the end.
600 SmallVector<unsigned, 7> IntParams = {0, 0, 0, 0, 0, 0};
601
602 // Choose the dimension of the image--this corresponds to the Dim enum in
603 // SPIR-V (first integer parameter of OpTypeImage).
604 if (OpenCLName.starts_with("image2d"))
605 IntParams[0] = 1;
606 else if (OpenCLName.starts_with("image3d"))
607 IntParams[0] = 2;
608 else if (OpenCLName == "image1d_buffer")
609 IntParams[0] = 5; // Buffer
610 else
611 assert(OpenCLName.starts_with("image1d") && "Unknown image type");
612
613 // Set the other integer parameters of OpTypeImage if necessary. Note that the
614 // OpenCL image types don't provide any information for the Sampled or
615 // Image Format parameters.
616 if (OpenCLName.contains("_depth"))
617 IntParams[1] = 1;
618 if (OpenCLName.contains("_array"))
619 IntParams[2] = 1;
620 if (OpenCLName.contains("_msaa"))
621 IntParams[3] = 1;
622
623 // Access qualifier
624 IntParams.push_back(AccessQualifier);
625
626 return llvm::TargetExtType::get(Ctx, BaseType, {llvm::Type::getVoidTy(Ctx)},
627 IntParams);
628}
629
630llvm::Type *CommonSPIRTargetCodeGenInfo::getOpenCLType(CodeGenModule &CGM,
631 const Type *Ty) const {
632 llvm::LLVMContext &Ctx = CGM.getLLVMContext();
633 if (auto *PipeTy = dyn_cast<PipeType>(Ty))
634 return llvm::TargetExtType::get(Ctx, "spirv.Pipe", {},
635 {!PipeTy->isReadOnly()});
636 if (auto *BuiltinTy = dyn_cast<BuiltinType>(Ty)) {
637 enum AccessQualifier : unsigned { AQ_ro = 0, AQ_wo = 1, AQ_rw = 2 };
638 switch (BuiltinTy->getKind()) {
639#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
640 case BuiltinType::Id: \
641 return getSPIRVImageType(Ctx, "spirv.Image", #ImgType, AQ_##Suffix);
642#include "clang/Basic/OpenCLImageTypes.def"
643 case BuiltinType::OCLSampler:
644 return llvm::TargetExtType::get(Ctx, "spirv.Sampler");
645 case BuiltinType::OCLEvent:
646 return llvm::TargetExtType::get(Ctx, "spirv.Event");
647 case BuiltinType::OCLClkEvent:
648 return llvm::TargetExtType::get(Ctx, "spirv.DeviceEvent");
649 case BuiltinType::OCLQueue:
650 return llvm::TargetExtType::get(Ctx, "spirv.Queue");
651 case BuiltinType::OCLReserveID:
652 return llvm::TargetExtType::get(Ctx, "spirv.ReserveId");
653#define INTEL_SUBGROUP_AVC_TYPE(Name, Id) \
654 case BuiltinType::OCLIntelSubgroupAVC##Id: \
655 return llvm::TargetExtType::get(Ctx, "spirv.Avc" #Id "INTEL");
656#include "clang/Basic/OpenCLExtensionTypes.def"
657 default:
658 return nullptr;
659 }
660 }
661
662 return nullptr;
663}
664
665// Gets a spirv.IntegralConstant or spirv.Literal. If IntegralType is present,
666// returns an IntegralConstant, otherwise returns a Literal.
667static llvm::Type *getInlineSpirvConstant(CodeGenModule &CGM,
668 llvm::Type *IntegralType,
669 llvm::APInt Value) {
670 llvm::LLVMContext &Ctx = CGM.getLLVMContext();
671
672 // Convert the APInt value to an array of uint32_t words
674
675 while (Value.ugt(0)) {
676 uint32_t Word = Value.trunc(32).getZExtValue();
677 Value.lshrInPlace(32);
678
679 Words.push_back(Word);
680 }
681 if (Words.size() == 0)
682 Words.push_back(0);
683
684 if (IntegralType)
685 return llvm::TargetExtType::get(Ctx, "spirv.IntegralConstant",
686 {IntegralType}, Words);
687 return llvm::TargetExtType::get(Ctx, "spirv.Literal", {}, Words);
688}
689
690static llvm::Type *getInlineSpirvType(CodeGenModule &CGM,
691 const HLSLInlineSpirvType *SpirvType) {
692 llvm::LLVMContext &Ctx = CGM.getLLVMContext();
693
695
696 for (auto &Operand : SpirvType->getOperands()) {
697 using SpirvOperandKind = SpirvOperand::SpirvOperandKind;
698
699 llvm::Type *Result = nullptr;
700 switch (Operand.getKind()) {
701 case SpirvOperandKind::ConstantId: {
702 llvm::Type *IntegralType =
703 CGM.getTypes().ConvertType(Operand.getResultType());
704
705 Result = getInlineSpirvConstant(CGM, IntegralType, Operand.getValue());
706 break;
707 }
708 case SpirvOperandKind::Literal: {
709 Result = getInlineSpirvConstant(CGM, nullptr, Operand.getValue());
710 break;
711 }
712 case SpirvOperandKind::TypeId: {
713 QualType TypeOperand = Operand.getResultType();
714 if (const auto *RD = TypeOperand->getAsRecordDecl()) {
715 assert(RD->isCompleteDefinition() &&
716 "Type completion should have been required in Sema");
717
718 const FieldDecl *HandleField = RD->findFirstNamedDataMember();
719 if (HandleField) {
720 QualType ResourceType = HandleField->getType();
721 if (ResourceType->getAs<HLSLAttributedResourceType>()) {
722 TypeOperand = ResourceType;
723 }
724 }
725 }
726 Result = CGM.getTypes().ConvertType(TypeOperand);
727 break;
728 }
729 default:
730 llvm_unreachable("HLSLInlineSpirvType had invalid operand!");
731 break;
732 }
733
734 assert(Result);
735 Operands.push_back(Result);
736 }
737
738 return llvm::TargetExtType::get(Ctx, "spirv.Type", Operands,
739 {SpirvType->getOpcode(), SpirvType->getSize(),
740 SpirvType->getAlignment()});
741}
742
743llvm::Type *CommonSPIRTargetCodeGenInfo::getHLSLType(
744 CodeGenModule &CGM, const Type *Ty,
745 const CGHLSLOffsetInfo &OffsetInfo) const {
746 llvm::LLVMContext &Ctx = CGM.getLLVMContext();
747
748 if (auto *SpirvType = dyn_cast<HLSLInlineSpirvType>(Ty))
749 return getInlineSpirvType(CGM, SpirvType);
750
751 auto *ResType = dyn_cast<HLSLAttributedResourceType>(Ty);
752 if (!ResType)
753 return nullptr;
754
755 const HLSLAttributedResourceType::Attributes &ResAttrs = ResType->getAttrs();
756 switch (ResAttrs.ResourceClass) {
757 case llvm::dxil::ResourceClass::UAV:
758 case llvm::dxil::ResourceClass::SRV: {
759 // TypedBuffer and RawBuffer both need element type
760 QualType ContainedTy = ResType->getContainedType();
761 if (ContainedTy.isNull())
762 return nullptr;
763
764 assert(!ResAttrs.IsROV &&
765 "Rasterizer order views not implemented for SPIR-V yet");
766
767 if (!ResAttrs.RawBuffer) {
768 // convert element type
769 return getSPIRVImageTypeFromHLSLResource(ResAttrs, ContainedTy, CGM);
770 }
771
772 if (ResAttrs.IsCounter) {
773 llvm::Type *ElemType = llvm::Type::getInt32Ty(Ctx);
774 uint32_t StorageClass = /* StorageBuffer storage class */ 12;
775 return llvm::TargetExtType::get(Ctx, "spirv.VulkanBuffer", {ElemType},
776 {StorageClass, true});
777 }
778 llvm::Type *ElemType = CGM.getTypes().ConvertTypeForMem(ContainedTy);
779 llvm::ArrayType *RuntimeArrayType = llvm::ArrayType::get(ElemType, 0);
780 uint32_t StorageClass = /* StorageBuffer storage class */ 12;
781 bool IsWritable = ResAttrs.ResourceClass == llvm::dxil::ResourceClass::UAV;
782 return llvm::TargetExtType::get(Ctx, "spirv.VulkanBuffer",
783 {RuntimeArrayType},
784 {StorageClass, IsWritable});
785 }
786 case llvm::dxil::ResourceClass::CBuffer: {
787 QualType ContainedTy = ResType->getContainedType();
788 if (ContainedTy.isNull() || !ContainedTy->isStructureType())
789 return nullptr;
790
791 llvm::StructType *BufferLayoutTy =
792 HLSLBufferLayoutBuilder(CGM).layOutStruct(
793 ContainedTy->getAsCanonical<RecordType>(), OffsetInfo);
794 uint32_t StorageClass = /* Uniform storage class */ 2;
795 return llvm::TargetExtType::get(Ctx, "spirv.VulkanBuffer", {BufferLayoutTy},
796 {StorageClass, false});
797 break;
798 }
799 case llvm::dxil::ResourceClass::Sampler:
800 return llvm::TargetExtType::get(Ctx, "spirv.Sampler");
801 }
802 return nullptr;
803}
804
805static unsigned
807 const HLSLAttributedResourceType::Attributes &attributes,
808 llvm::Type *SampledType, QualType Ty, unsigned NumChannels) {
809 // For images with `Sampled` operand equal to 2, there are restrictions on
810 // using the Unknown image format. To avoid these restrictions in common
811 // cases, we guess an image format for them based on the sampled type and the
812 // number of channels. This is intended to match the behaviour of DXC.
813 if (LangOpts.HLSLSpvUseUnknownImageFormat ||
814 attributes.ResourceClass != llvm::dxil::ResourceClass::UAV) {
815 return 0; // Unknown
816 }
817
818 if (SampledType->isIntegerTy(32)) {
819 if (Ty->isSignedIntegerType()) {
820 if (NumChannels == 1)
821 return 24; // R32i
822 if (NumChannels == 2)
823 return 25; // Rg32i
824 if (NumChannels == 4)
825 return 21; // Rgba32i
826 } else {
827 if (NumChannels == 1)
828 return 33; // R32ui
829 if (NumChannels == 2)
830 return 35; // Rg32ui
831 if (NumChannels == 4)
832 return 30; // Rgba32ui
833 }
834 } else if (SampledType->isIntegerTy(64)) {
835 if (NumChannels == 1) {
836 if (Ty->isSignedIntegerType()) {
837 return 41; // R64i
838 }
839 return 40; // R64ui
840 }
841 } else if (SampledType->isFloatTy()) {
842 if (NumChannels == 1)
843 return 3; // R32f
844 if (NumChannels == 2)
845 return 6; // Rg32f
846 if (NumChannels == 4)
847 return 1; // Rgba32f
848 }
849
850 return 0; // Unknown
851}
852
853llvm::Type *CommonSPIRTargetCodeGenInfo::getSPIRVImageTypeFromHLSLResource(
854 const HLSLAttributedResourceType::Attributes &attributes, QualType Ty,
855 CodeGenModule &CGM) const {
856 llvm::LLVMContext &Ctx = CGM.getLLVMContext();
857
858 unsigned NumChannels = 1;
860 if (const VectorType *V = dyn_cast<VectorType>(Ty)) {
861 NumChannels = V->getNumElements();
862 Ty = V->getElementType();
863 }
864 assert(!Ty->isVectorType() && "We still have a vector type.");
865
866 llvm::Type *SampledType = CGM.getTypes().ConvertTypeForMem(Ty);
867
868 assert((SampledType->isIntegerTy() || SampledType->isFloatingPointTy()) &&
869 "The element type for a SPIR-V resource must be a scalar integer or "
870 "floating point type.");
871
872 assert((!SampledType->isIntegerTy(64) || NumChannels <= 2) &&
873 "A 64-bit SPIR-V resource element can have at most 2 components.");
874
875 // SPIR-V has no 64-bit multi-component image format, so pack a 2-component
876 // 64-bit typed buffer into a 4-component 32-bit image. The backend
877 // reinterprets it with OpBitcast on load and store.
878 if (SampledType->isIntegerTy(64) && NumChannels == 2) {
879 SampledType = llvm::Type::getInt32Ty(Ctx);
880 NumChannels = 4;
881 }
882
883 // These parameters correspond to the operands to the OpTypeImage SPIR-V
884 // instruction. See
885 // https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpTypeImage.
886 SmallVector<unsigned, 6> IntParams(6, 0);
887
888 const char *Name =
889 Ty->isSignedIntegerType() ? "spirv.SignedImage" : "spirv.Image";
890
891 // Dim
892 switch (attributes.ResourceDimension) {
893 case llvm::dxil::ResourceDimension::Dim1D:
894 IntParams[0] = 0;
895 break;
896 case llvm::dxil::ResourceDimension::Dim2D:
897 IntParams[0] = 1;
898 break;
899 case llvm::dxil::ResourceDimension::Dim3D:
900 IntParams[0] = 2;
901 break;
902 case llvm::dxil::ResourceDimension::Cube:
903 IntParams[0] = 3;
904 break;
905 case llvm::dxil::ResourceDimension::Unknown:
906 IntParams[0] = 5;
907 break;
908 }
909
910 // Depth
911 // HLSL does not indicate if it is a depth texture or not, so we use unknown.
912 IntParams[1] = 2;
913
914 // Arrayed
915 IntParams[2] = static_cast<unsigned>(attributes.IsArray);
916
917 // MS
918 IntParams[3] = static_cast<unsigned>(attributes.isMultiSampled());
919
920 // Sampled
921 IntParams[4] =
922 attributes.ResourceClass == llvm::dxil::ResourceClass::UAV ? 2 : 1;
923
924 // Image format.
925 IntParams[5] = getImageFormat(CGM.getLangOpts(), attributes, SampledType, Ty,
926 NumChannels);
927
928 llvm::TargetExtType *ImageType =
929 llvm::TargetExtType::get(Ctx, Name, {SampledType}, IntParams);
930 return ImageType;
931}
932
933std::unique_ptr<TargetCodeGenInfo>
935 return std::make_unique<CommonSPIRTargetCodeGenInfo>(CGM.getTypes());
936}
937
938std::unique_ptr<TargetCodeGenInfo>
940 return std::make_unique<SPIRVTargetCodeGenInfo>(CGM.getTypes());
941}
#define V(N, I)
static void setCUDAKernelCallingConvention(CanQualType &funcTy, CIRGenModule &cgm, const FunctionDecl *fd)
Set calling convention for CUDA/HIP kernel.
static llvm::Type * getInlineSpirvType(CodeGenModule &CGM, const HLSLInlineSpirvType *SpirvType)
Definition SPIR.cpp:690
static llvm::Type * getSPIRVImageType(llvm::LLVMContext &Ctx, StringRef BaseType, StringRef OpenCLName, unsigned AccessQualifier)
Construct a SPIR-V target extension type for the given OpenCL image type.
Definition SPIR.cpp:591
static unsigned getImageFormat(const LangOptions &LangOpts, const HLSLAttributedResourceType::Attributes &attributes, llvm::Type *SampledType, QualType Ty, unsigned NumChannels)
Definition SPIR.cpp:806
static llvm::Type * getInlineSpirvConstant(CodeGenModule &CGM, llvm::Type *IntegralType, llvm::APInt Value)
Definition SPIR.cpp:667
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Result
Implement __builtin_bit_cast and related operations.
Defines the clang::LangOptions interface.
static StringRef getTriple(const Command &Job)
unsigned getTargetAddressSpace(LangAS AS) const
QuantityType getQuantity() const
Get the raw integer representation of this quantity.
Definition CharUnits.h:155
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 getIndirectAliased(CharUnits Alignment, unsigned AddrSpace, bool Realign=false, llvm::Type *Padding=nullptr)
Pass this in memory using the IR byref attribute.
@ RAA_DirectInMemory
Pass it on the stack using its defined layout.
Definition CGCXXABI.h:158
CGFunctionInfo - Class to encapsulate the information about a function definition.
unsigned getCallingConvention() const
getCallingConvention - Return the user specified calling convention, which has been translated into a...
CanQualType getReturnType() const
MutableArrayRef< ArgInfo > arguments()
llvm::LLVMContext & getLLVMContext()
This class organizes the cross-function state that is used while generating LLVM code.
const LangOptions & getLangOpts() const
const TargetInfo & getTarget() const
const llvm::Triple & getTriple() const
AtomicOptions getAtomicOpts()
Get the current Atomic options.
ASTContext & getContext() const
llvm::LLVMContext & getLLVMContext()
llvm::Type * ConvertType(QualType T)
ConvertType - Convert type T into a llvm::Type.
llvm::Type * ConvertTypeForMem(QualType T)
ConvertTypeForMem - Convert type T into a llvm::Type.
DefaultABIInfo - The default implementation for ABI specific details.
Definition ABIInfoImpl.h:21
ABIArgInfo classifyArgumentType(QualType RetTy) const
ABIArgInfo classifyReturnType(QualType RetTy) const
TargetCodeGenInfo - This class organizes various target-specific codegeneration issues,...
Definition TargetInfo.h:80
T * getAttr() const
Definition DeclBase.h:582
bool hasAttr() const
Definition DeclBase.h:586
Represents a member of a struct/union/class.
Definition Decl.h:3311
ExtInfo withCallingConv(CallingConv cc) const
Definition TypeBase.h:4835
ExtInfo getExtInfo() const
Definition TypeBase.h:4968
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
A (possibly-)qualified type.
Definition TypeBase.h:938
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1005
LangAS getAddressSpace() const
Return the address space of this type.
Definition TypeBase.h:8572
bool canPassInRegisters() const
Determine whether this class can be passed in registers.
Definition Decl.h:4613
bool hasFlexibleArrayMember() const
Definition Decl.h:4509
const FieldDecl * findFirstNamedDataMember() const
Finds the first data member which has a name.
Definition Decl.cpp:5501
bool isCompleteDefinition() const
Return true if this decl has its body fully specified.
Definition Decl.h:3969
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
bool isStructureType() const
Definition Type.cpp:811
bool isSignedIntegerType() const
Return true if this is an integer type that is signed, according to C99 6.2.5p4 [char,...
Definition Type.cpp:2392
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition Type.h:41
CanQualType getCanonicalTypeUnqualified() const
bool isVectorType() const
Definition TypeBase.h:8822
const T * getAsCanonical() const
If this type is canonically the specified type, return its canonical type cast to that specified type...
Definition TypeBase.h:3002
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9299
QualType getType() const
Definition Decl.h:725
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...
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
CGCXXABI::RecordArgABI getRecordArgABI(const RecordType *RT, CGCXXABI &CXXABI)
bool classifyReturnType(const CGCXXABI &CXXABI, CGFunctionInfo &FI, const ABIInfo &Info)
void computeSPIRKernelABIInfo(CodeGenModule &CGM, CGFunctionInfo &FI)
Definition SPIR.cpp:438
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 ...
const Type * isSingleElementRecord(QualType T, ASTContext &Context)
isSingleElementRecord - Determine if a record is a "singleelement record", i.e.
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)
std::unique_ptr< TargetCodeGenInfo > createSPIRVTargetCodeGenInfo(CodeGenModule &CGM)
Definition SPIR.cpp:939
QualType useFirstFieldIfTransparentUnion(QualType Ty)
Pass transparent unions as if they were the type of the first element.
std::unique_ptr< TargetCodeGenInfo > createCommonSPIRTargetCodeGenInfo(CodeGenModule &CGM)
Definition SPIR.cpp:934
bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays, bool AsIfNoUniqueAddr=false)
isEmptyRecord - Return true iff a structure contains only empty fields.
Top level wrappers for InstallAPI frontend operations.
StorageClass
Storage classes.
Definition Specifiers.h:252
const FunctionProtoType * T
LangAS
Defines the address space values used by the address space qualifier of QualType.
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
LangAS getLangASFromTargetAS(unsigned TargetAS)
unsigned long uint64_t
bool getOption(AtomicOptionKind Kind) const