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 for (auto &&[ArgumentsCount, I] : llvm::enumerate(FI.arguments()))
190 I.info = ArgumentsCount < FI.getNumRequiredArgs()
191 ? classifyArgumentType(I.type)
192 : ABIArgInfo::getDirect();
193
194 if (!getCXXABI().classifyReturnType(FI))
196
197 for (auto &I : FI.arguments()) {
198 if (CC == llvm::CallingConv::SPIR_KERNEL) {
199 I.info = classifyKernelArgumentType(I.type);
200 } else {
201 I.info = classifyArgumentType(I.type);
202 }
203 }
204}
205
206RValue SPIRVABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
207 QualType Ty, AggValueSlot Slot) const {
208 return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*IsIndirect=*/false,
209 getContext().getTypeInfoInChars(Ty),
211 /*AllowHigherAlign=*/true, Slot);
212}
213
214uint64_t AMDGCNSPIRVABIInfo::numRegsForType(QualType Ty) const {
215 // This duplicates the AMDGPUABI computation.
216 uint64_t NumRegs = 0;
217
218 if (const VectorType *VT = Ty->getAs<VectorType>()) {
219 // Compute from the number of elements. The reported size is based on the
220 // in-memory size, which includes the padding 4th element for 3-vectors.
221 QualType EltTy = VT->getElementType();
222 uint64_t EltSize = getContext().getTypeSize(EltTy);
223
224 // 16-bit element vectors should be passed as packed.
225 if (EltSize == 16)
226 return (VT->getNumElements() + 1) / 2;
227
228 uint64_t EltNumRegs = (EltSize + 31) / 32;
229 return EltNumRegs * VT->getNumElements();
230 }
231
232 if (const auto *RD = Ty->getAsRecordDecl()) {
233 assert(!RD->hasFlexibleArrayMember());
234
235 for (const FieldDecl *Field : RD->fields()) {
236 QualType FieldTy = Field->getType();
237 NumRegs += numRegsForType(FieldTy);
238 }
239
240 return NumRegs;
241 }
242
243 return (getContext().getTypeSize(Ty) + 31) / 32;
244}
245
246llvm::Type *AMDGCNSPIRVABIInfo::coerceKernelArgumentType(llvm::Type *Ty,
247 unsigned FromAS,
248 unsigned ToAS) const {
249 // Single value types.
250 auto *PtrTy = llvm::dyn_cast<llvm::PointerType>(Ty);
251 if (PtrTy && PtrTy->getAddressSpace() == FromAS)
252 return llvm::PointerType::get(Ty->getContext(), ToAS);
253 return Ty;
254}
255
256ABIArgInfo AMDGCNSPIRVABIInfo::classifyReturnType(QualType RetTy) const {
257 if (!isAggregateTypeForABI(RetTy) || getRecordArgABI(RetTy, getCXXABI()))
259
260 // Ignore empty structs/unions.
261 if (isEmptyRecord(getContext(), RetTy, true))
262 return ABIArgInfo::getIgnore();
263
264 // Lower single-element structs to just return a regular value.
265 if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext()))
266 return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
267
268 if (const auto *RD = RetTy->getAsRecordDecl();
269 RD && RD->hasFlexibleArrayMember())
271
272 // Pack aggregates <= 4 bytes into single VGPR or pair.
273 uint64_t Size = getContext().getTypeSize(RetTy);
274 if (Size <= 16)
275 return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext()));
276
277 if (Size <= 32)
278 return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext()));
279
280 // TODO: This carried over from AMDGPU oddity, we retain it to
281 // ensure consistency, but it might be reasonable to return Int64.
282 if (Size <= 64) {
283 llvm::Type *I32Ty = llvm::Type::getInt32Ty(getVMContext());
284 return ABIArgInfo::getDirect(llvm::ArrayType::get(I32Ty, 2));
285 }
286
287 if (numRegsForType(RetTy) <= MaxNumRegsForArgsRet)
288 return ABIArgInfo::getDirect();
290}
291
292/// For kernels all parameters are really passed in a special buffer. It doesn't
293/// make sense to pass anything byval, so everything must be direct.
294ABIArgInfo AMDGCNSPIRVABIInfo::classifyKernelArgumentType(QualType Ty) const {
296
297 // TODO: Can we omit empty structs?
298
299 if (const Type *SeltTy = isSingleElementStruct(Ty, getContext()))
300 Ty = QualType(SeltTy, 0);
301
302 llvm::Type *OrigLTy = CGT.ConvertType(Ty);
303 llvm::Type *LTy = OrigLTy;
304 if (getContext().getLangOpts().isTargetDevice()) {
305 LTy = coerceKernelArgumentType(
306 OrigLTy, /*FromAS=*/getContext().getTargetAddressSpace(LangAS::Default),
307 /*ToAS=*/getContext().getTargetAddressSpace(LangAS::opencl_global));
308 }
309
310 // FIXME: This doesn't apply the optimization of coercing pointers in structs
311 // to global address space when using byref. This would require implementing a
312 // new kind of coercion of the in-memory type when for indirect arguments.
313 if (LTy == OrigLTy && isAggregateTypeForABI(Ty)) {
315 getContext().getTypeAlignInChars(Ty),
316 getContext().getTargetAddressSpace(LangAS::opencl_constant),
317 false /*Realign*/, nullptr /*Padding*/);
318 }
319
320 // TODO: inhibiting flattening is an AMDGPU workaround for Clover, which might
321 // be vestigial and should be revisited.
322 return ABIArgInfo::getDirect(LTy, 0, nullptr, false);
323}
324
325ABIArgInfo AMDGCNSPIRVABIInfo::classifyArgumentType(QualType Ty,
326 bool Variadic) const {
327 assert(NumRegsLeft <= MaxNumRegsForArgsRet && "register estimate underflow");
328
330
331 if (Variadic) {
332 return ABIArgInfo::getDirect(/*T=*/nullptr,
333 /*Offset=*/0,
334 /*Padding=*/nullptr,
335 /*CanBeFlattened=*/false,
336 /*Align=*/0);
337 }
338
339 if (!isAggregateTypeForABI(Ty)) {
340 ABIArgInfo ArgInfo = DefaultABIInfo::classifyArgumentType(Ty);
341 if (!ArgInfo.isIndirect()) {
342 uint64_t NumRegs = numRegsForType(Ty);
343 NumRegsLeft -= std::min(NumRegs, uint64_t{NumRegsLeft});
344 }
345
346 return ArgInfo;
347 }
348
349 // Records with non-trivial destructors/copy-constructors should not be
350 // passed by value.
351 if (auto RAA = getRecordArgABI(Ty, getCXXABI()))
352 return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace(),
354
355 // Ignore empty structs/unions.
356 if (isEmptyRecord(getContext(), Ty, true))
357 return ABIArgInfo::getIgnore();
358
359 // Lower single-element structs to just pass a regular value. TODO: We
360 // could do reasonable-size multiple-element structs too, using getExpand(),
361 // though watch out for things like bitfields.
362 if (const Type *SeltTy = isSingleElementStruct(Ty, getContext()))
363 return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
364
365 if (const auto *RD = Ty->getAsRecordDecl();
366 RD && RD->hasFlexibleArrayMember())
368
369 uint64_t Size = getContext().getTypeSize(Ty);
370 if (Size <= 64) {
371 // Pack aggregates <= 8 bytes into single VGPR or pair.
372 unsigned NumRegs = (Size + 31) / 32;
373 NumRegsLeft -= std::min(NumRegsLeft, NumRegs);
374
375 if (Size <= 16)
376 return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext()));
377
378 if (Size <= 32)
379 return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext()));
380
381 // TODO: This is an AMDGPU oddity, and might be vestigial, we retain it to
382 // ensure consistency, but it should be revisited.
383 llvm::Type *I32Ty = llvm::Type::getInt32Ty(getVMContext());
384 return ABIArgInfo::getDirect(llvm::ArrayType::get(I32Ty, 2));
385 }
386
387 if (NumRegsLeft > 0) {
388 uint64_t NumRegs = numRegsForType(Ty);
389 if (NumRegsLeft >= NumRegs) {
390 NumRegsLeft -= NumRegs;
391 return ABIArgInfo::getDirect();
392 }
393 }
394
395 // Use pass-by-reference in stead of pass-by-value for struct arguments in
396 // function ABI.
398 getContext().getTypeAlignInChars(Ty),
399 getContext().getTargetAddressSpace(LangAS::opencl_private));
400}
401
402void AMDGCNSPIRVABIInfo::computeInfo(CGFunctionInfo &FI) const {
403 llvm::CallingConv::ID CC = FI.getCallingConvention();
404
405 if (!getCXXABI().classifyReturnType(FI))
407
408 unsigned ArgumentIndex = 0;
409 const unsigned NumRequiredArgs = FI.getNumRequiredArgs();
410
411 NumRegsLeft = MaxNumRegsForArgsRet;
412 for (auto &I : FI.arguments()) {
413 if (CC == llvm::CallingConv::SPIR_KERNEL) {
414 I.info = classifyKernelArgumentType(I.type);
415 } else {
416 bool FixedArgument = ArgumentIndex++ < NumRequiredArgs;
417 I.info = classifyArgumentType(I.type, !FixedArgument);
418 }
419 }
420}
421
422llvm::FixedVectorType *
423SPIRVABIInfo::getOptimalVectorMemoryType(llvm::FixedVectorType *Ty,
424 const LangOptions &LangOpt) const {
425 // For Logical SPIR-V, we don't know the underlying hardware or layout.
426 // This means we don't know which vector size is better, and also cannot
427 // assume a smaller vector size is stored in a larger vector size.
428 if (getTarget().getTriple().isSPIRVLogical())
429 return Ty;
430 return DefaultABIInfo::getOptimalVectorMemoryType(Ty, LangOpt);
431}
432
433llvm::FixedVectorType *AMDGCNSPIRVABIInfo::getOptimalVectorMemoryType(
434 llvm::FixedVectorType *Ty, const LangOptions &LangOpt) const {
435 // AMDGPU has legal instructions for 96-bit so 3x32 can be supported.
436 if (Ty->getNumElements() == 3 && getDataLayout().getTypeSizeInBits(Ty) == 96)
437 return Ty;
438 return DefaultABIInfo::getOptimalVectorMemoryType(Ty, LangOpt);
439}
440
441namespace clang {
442namespace CodeGen {
444 if (CGM.getTarget().getTriple().isSPIRV()) {
445 if (CGM.getTarget().getTriple().getVendor() == llvm::Triple::AMD)
446 AMDGCNSPIRVABIInfo(CGM.getTypes()).computeInfo(FI);
447 else
448 SPIRVABIInfo(CGM.getTypes()).computeInfo(FI);
449 } else {
450 CommonSPIRABIInfo(CGM.getTypes()).computeInfo(FI);
451 }
452}
453}
454}
455
456unsigned CommonSPIRTargetCodeGenInfo::getDeviceKernelCallingConv() const {
457 return llvm::CallingConv::SPIR_KERNEL;
458}
459
460LangAS SPIRVTargetCodeGenInfo::getSRetAddrSpace(const CXXRecordDecl *RD) const {
461 // Types with no viable copy/move must be constructed in-place, use the
462 // default AS so the sret pointer matches the "this" convention.
463 if (RD && !RD->canPassInRegisters())
464 return LangAS::Default;
466 getABIInfo().getDataLayout().getAllocaAddrSpace());
467}
468
469void SPIRVTargetCodeGenInfo::setCUDAKernelCallingConvention(
470 const FunctionType *&FT) const {
471 // Convert HIP kernels to SPIR-V kernels.
472 if (getABIInfo().getContext().getLangOpts().HIP) {
473 FT = getABIInfo().getContext().adjustFunctionType(
475 return;
476 }
477}
478
479void CommonSPIRTargetCodeGenInfo::setOCLKernelStubCallingConvention(
480 const FunctionType *&FT) const {
481 FT = getABIInfo().getContext().adjustFunctionType(
482 FT, FT->getExtInfo().withCallingConv(CC_C));
483}
484
485// LLVM currently assumes a null pointer has the bit pattern 0, but some GPU
486// targets use a non-zero encoding for null in certain address spaces.
487// Because SPIR(-V) is a generic target and the bit pattern of null in
488// non-generic AS is unspecified, materialize null in non-generic AS via an
489// addrspacecast from null in generic AS. This allows later lowering to
490// substitute the target's real sentinel value.
491llvm::Constant *
492CommonSPIRTargetCodeGenInfo::getNullPointer(const CodeGen::CodeGenModule &CGM,
493 llvm::PointerType *PT,
494 QualType QT) const {
496 return llvm::ConstantPointerNull::get(PT);
497
498 auto &Ctx = CGM.getContext();
499 auto NPT = llvm::PointerType::get(
500 PT->getContext(), Ctx.getTargetAddressSpace(LangAS::opencl_generic));
501 return llvm::ConstantExpr::getAddrSpaceCast(
502 llvm::ConstantPointerNull::get(NPT), PT);
503}
504
505LangAS
506SPIRVTargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM,
507 const VarDecl *D) const {
508 assert(!CGM.getLangOpts().OpenCL &&
509 !(CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) &&
510 "Address space agnostic languages only");
511 // If we're here it means that we're using the SPIRDefIsGen ASMap, hence for
512 // the global AS we can rely on either cuda_device or sycl_global to be
513 // correct; however, since this is not a CUDA Device context, we use
514 // sycl_global to prevent confusion with the assertion.
515 LangAS DefaultGlobalAS = getLangASFromTargetAS(
516 CGM.getContext().getTargetAddressSpace(LangAS::sycl_global));
517 if (!D)
518 return DefaultGlobalAS;
519
520 LangAS AddrSpace = D->getType().getAddressSpace();
521 if (AddrSpace != LangAS::Default)
522 return AddrSpace;
523
524 return DefaultGlobalAS;
525}
526
527void SPIRVTargetCodeGenInfo::setTargetAttributes(
528 const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const {
529 if (GV->isDeclaration())
530 return;
531
532 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
533 if (!FD)
534 return;
535
536 llvm::Function *F = dyn_cast<llvm::Function>(GV);
537 assert(F && "Expected GlobalValue to be a Function");
538
539 if (!M.getLangOpts().HIP ||
540 M.getTarget().getTriple().getVendor() != llvm::Triple::AMD)
541 return;
542
543 if (!FD->hasAttr<CUDAGlobalAttr>())
544 return;
545
546 unsigned N = M.getLangOpts().GPUMaxThreadsPerBlock;
547 if (auto FlatWGS = FD->getAttr<AMDGPUFlatWorkGroupSizeAttr>()) {
548 N = FlatWGS->getMax()->EvaluateKnownConstInt(M.getContext()).getExtValue();
549 } else if (auto LB = FD->getAttr<CUDALaunchBoundsAttr>()) {
550 if (uint64_t MaxThreads = LB->getMaxThreads()
551 ->EvaluateKnownConstInt(M.getContext())
552 .getExtValue())
553 N = MaxThreads;
554 }
555
556 // We encode the maximum flat WG size in the first component of the 3D
557 // max_work_group_size attribute, which will get reverse translated into the
558 // original AMDGPU attribute when targeting AMDGPU.
559 auto Int32Ty = llvm::IntegerType::getInt32Ty(M.getLLVMContext());
560 llvm::Metadata *AttrMDArgs[] = {
561 llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(Int32Ty, N)),
562 llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(Int32Ty, 1)),
563 llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(Int32Ty, 1))};
564
565 F->setMetadata("max_work_group_size",
566 llvm::MDNode::get(M.getLLVMContext(), AttrMDArgs));
567}
568
569StringRef SPIRVTargetCodeGenInfo::getLLVMSyncScopeStr(
570 const LangOptions &, SyncScope Scope, llvm::AtomicOrdering) const {
571 return *llvm::getAtomicScopeIRString(getABIInfo().getTarget().getTriple(),
572 getAtomicScope(Scope));
573}
574
575void SPIRVTargetCodeGenInfo::setTargetAtomicMetadata(
576 CodeGenFunction &CGF, llvm::Instruction &AtomicInst,
577 const AtomicExpr *AE) const {
578 if (CGF.CGM.getTriple().getVendor() != llvm::Triple::VendorType::AMD)
579 return;
580
581 auto *RMW = dyn_cast<llvm::AtomicRMWInst>(&AtomicInst);
582 if (!RMW)
583 return;
584
585 AtomicOptions AO = CGF.CGM.getAtomicOpts();
586 llvm::MDNode *Empty = llvm::MDNode::get(CGF.getLLVMContext(), {});
588 RMW->setMetadata("amdgpu.no.fine.grained.memory", Empty);
590 RMW->setMetadata("amdgpu.no.remote.memory", Empty);
593}
594
595/// Construct a SPIR-V target extension type for the given OpenCL image type.
596static llvm::Type *getSPIRVImageType(llvm::LLVMContext &Ctx, StringRef BaseType,
597 StringRef OpenCLName,
598 unsigned AccessQualifier) {
599 // These parameters compare to the operands of OpTypeImage (see
600 // https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpTypeImage
601 // for more details). The first 6 integer parameters all default to 0, and
602 // will be changed to 1 only for the image type(s) that set the parameter to
603 // one. The 7th integer parameter is the access qualifier, which is tacked on
604 // at the end.
605 SmallVector<unsigned, 7> IntParams = {0, 0, 0, 0, 0, 0};
606
607 // Choose the dimension of the image--this corresponds to the Dim enum in
608 // SPIR-V (first integer parameter of OpTypeImage).
609 if (OpenCLName.starts_with("image2d"))
610 IntParams[0] = 1;
611 else if (OpenCLName.starts_with("image3d"))
612 IntParams[0] = 2;
613 else if (OpenCLName == "image1d_buffer")
614 IntParams[0] = 5; // Buffer
615 else
616 assert(OpenCLName.starts_with("image1d") && "Unknown image type");
617
618 // Set the other integer parameters of OpTypeImage if necessary. Note that the
619 // OpenCL image types don't provide any information for the Sampled or
620 // Image Format parameters.
621 if (OpenCLName.contains("_depth"))
622 IntParams[1] = 1;
623 if (OpenCLName.contains("_array"))
624 IntParams[2] = 1;
625 if (OpenCLName.contains("_msaa"))
626 IntParams[3] = 1;
627
628 // Access qualifier
629 IntParams.push_back(AccessQualifier);
630
631 return llvm::TargetExtType::get(Ctx, BaseType, {llvm::Type::getVoidTy(Ctx)},
632 IntParams);
633}
634
635llvm::Type *CommonSPIRTargetCodeGenInfo::getOpenCLType(CodeGenModule &CGM,
636 const Type *Ty) const {
637 llvm::LLVMContext &Ctx = CGM.getLLVMContext();
638 if (auto *PipeTy = dyn_cast<PipeType>(Ty))
639 return llvm::TargetExtType::get(Ctx, "spirv.Pipe", {},
640 {!PipeTy->isReadOnly()});
641 if (auto *BuiltinTy = dyn_cast<BuiltinType>(Ty)) {
642 enum AccessQualifier : unsigned { AQ_ro = 0, AQ_wo = 1, AQ_rw = 2 };
643 switch (BuiltinTy->getKind()) {
644#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
645 case BuiltinType::Id: \
646 return getSPIRVImageType(Ctx, "spirv.Image", #ImgType, AQ_##Suffix);
647#include "clang/Basic/OpenCLImageTypes.def"
648 case BuiltinType::OCLSampler:
649 return llvm::TargetExtType::get(Ctx, "spirv.Sampler");
650 case BuiltinType::OCLEvent:
651 return llvm::TargetExtType::get(Ctx, "spirv.Event");
652 case BuiltinType::OCLClkEvent:
653 return llvm::TargetExtType::get(Ctx, "spirv.DeviceEvent");
654 case BuiltinType::OCLQueue:
655 return llvm::TargetExtType::get(Ctx, "spirv.Queue");
656 case BuiltinType::OCLReserveID:
657 return llvm::TargetExtType::get(Ctx, "spirv.ReserveId");
658#define INTEL_SUBGROUP_AVC_TYPE(Name, Id) \
659 case BuiltinType::OCLIntelSubgroupAVC##Id: \
660 return llvm::TargetExtType::get(Ctx, "spirv.Avc" #Id "INTEL");
661#include "clang/Basic/OpenCLExtensionTypes.def"
662 default:
663 return nullptr;
664 }
665 }
666
667 return nullptr;
668}
669
670// Gets a spirv.IntegralConstant or spirv.Literal. If IntegralType is present,
671// returns an IntegralConstant, otherwise returns a Literal.
672static llvm::Type *getInlineSpirvConstant(CodeGenModule &CGM,
673 llvm::Type *IntegralType,
674 llvm::APInt Value) {
675 llvm::LLVMContext &Ctx = CGM.getLLVMContext();
676
677 // Convert the APInt value to an array of uint32_t words
679
680 while (Value.ugt(0)) {
681 uint32_t Word = Value.trunc(32).getZExtValue();
682 Value.lshrInPlace(32);
683
684 Words.push_back(Word);
685 }
686 if (Words.size() == 0)
687 Words.push_back(0);
688
689 if (IntegralType)
690 return llvm::TargetExtType::get(Ctx, "spirv.IntegralConstant",
691 {IntegralType}, Words);
692 return llvm::TargetExtType::get(Ctx, "spirv.Literal", {}, Words);
693}
694
695static llvm::Type *getInlineSpirvType(CodeGenModule &CGM,
696 const HLSLInlineSpirvType *SpirvType) {
697 llvm::LLVMContext &Ctx = CGM.getLLVMContext();
698
700
701 for (auto &Operand : SpirvType->getOperands()) {
702 using SpirvOperandKind = SpirvOperand::SpirvOperandKind;
703
704 llvm::Type *Result = nullptr;
705 switch (Operand.getKind()) {
706 case SpirvOperandKind::ConstantId: {
707 llvm::Type *IntegralType =
708 CGM.getTypes().ConvertType(Operand.getResultType());
709
710 Result = getInlineSpirvConstant(CGM, IntegralType, Operand.getValue());
711 break;
712 }
713 case SpirvOperandKind::Literal: {
714 Result = getInlineSpirvConstant(CGM, nullptr, Operand.getValue());
715 break;
716 }
717 case SpirvOperandKind::TypeId: {
718 QualType TypeOperand = Operand.getResultType();
719 if (const auto *RD = TypeOperand->getAsRecordDecl()) {
720 assert(RD->isCompleteDefinition() &&
721 "Type completion should have been required in Sema");
722
723 const FieldDecl *HandleField = RD->findFirstNamedDataMember();
724 if (HandleField) {
725 QualType ResourceType = HandleField->getType();
726 if (ResourceType->getAs<HLSLAttributedResourceType>()) {
727 TypeOperand = ResourceType;
728 }
729 }
730 }
731 Result = CGM.getTypes().ConvertType(TypeOperand);
732 break;
733 }
734 default:
735 llvm_unreachable("HLSLInlineSpirvType had invalid operand!");
736 break;
737 }
738
739 assert(Result);
740 Operands.push_back(Result);
741 }
742
743 return llvm::TargetExtType::get(Ctx, "spirv.Type", Operands,
744 {SpirvType->getOpcode(), SpirvType->getSize(),
745 SpirvType->getAlignment()});
746}
747
748llvm::Type *CommonSPIRTargetCodeGenInfo::getHLSLType(
749 CodeGenModule &CGM, const Type *Ty,
750 const CGHLSLOffsetInfo &OffsetInfo) const {
751 llvm::LLVMContext &Ctx = CGM.getLLVMContext();
752
753 if (auto *SpirvType = dyn_cast<HLSLInlineSpirvType>(Ty))
754 return getInlineSpirvType(CGM, SpirvType);
755
756 auto *ResType = dyn_cast<HLSLAttributedResourceType>(Ty);
757 if (!ResType)
758 return nullptr;
759
760 const HLSLAttributedResourceType::Attributes &ResAttrs = ResType->getAttrs();
761 switch (ResAttrs.ResourceClass) {
762 case llvm::dxil::ResourceClass::UAV:
763 case llvm::dxil::ResourceClass::SRV: {
764 // TypedBuffer and RawBuffer both need element type
765 QualType ContainedTy = ResType->getContainedType();
766 if (ContainedTy.isNull())
767 return nullptr;
768
769 assert(!ResAttrs.IsROV &&
770 "Rasterizer order views not implemented for SPIR-V yet");
771
772 if (!ResAttrs.RawBuffer) {
773 // convert element type
774 return getSPIRVImageTypeFromHLSLResource(ResAttrs, ContainedTy, CGM);
775 }
776
777 if (ResAttrs.IsCounter) {
778 llvm::Type *ElemType = llvm::Type::getInt32Ty(Ctx);
779 uint32_t StorageClass = /* StorageBuffer storage class */ 12;
780 return llvm::TargetExtType::get(Ctx, "spirv.VulkanBuffer", {ElemType},
781 {StorageClass, true});
782 }
783 llvm::Type *ElemType = CGM.getTypes().ConvertTypeForMem(ContainedTy);
784 llvm::ArrayType *RuntimeArrayType = llvm::ArrayType::get(ElemType, 0);
785 uint32_t StorageClass = /* StorageBuffer storage class */ 12;
786 bool IsWritable = ResAttrs.ResourceClass == llvm::dxil::ResourceClass::UAV;
787 return llvm::TargetExtType::get(Ctx, "spirv.VulkanBuffer",
788 {RuntimeArrayType},
789 {StorageClass, IsWritable});
790 }
791 case llvm::dxil::ResourceClass::CBuffer: {
792 QualType ContainedTy = ResType->getContainedType();
793 if (ContainedTy.isNull() || !ContainedTy->isStructureType())
794 return nullptr;
795
796 llvm::StructType *BufferLayoutTy =
797 HLSLBufferLayoutBuilder(CGM).layOutStruct(
798 ContainedTy->getAsCanonical<RecordType>(), OffsetInfo);
799 uint32_t StorageClass = /* Uniform storage class */ 2;
800 return llvm::TargetExtType::get(Ctx, "spirv.VulkanBuffer", {BufferLayoutTy},
801 {StorageClass, false});
802 break;
803 }
804 case llvm::dxil::ResourceClass::Sampler:
805 return llvm::TargetExtType::get(Ctx, "spirv.Sampler");
806 }
807 return nullptr;
808}
809
810static unsigned
812 const HLSLAttributedResourceType::Attributes &attributes,
813 llvm::Type *SampledType, QualType Ty, unsigned NumChannels) {
814 // For images with `Sampled` operand equal to 2, there are restrictions on
815 // using the Unknown image format. To avoid these restrictions in common
816 // cases, we guess an image format for them based on the sampled type and the
817 // number of channels. This is intended to match the behaviour of DXC.
818 if (LangOpts.HLSLSpvUseUnknownImageFormat ||
819 attributes.ResourceClass != llvm::dxil::ResourceClass::UAV) {
820 return 0; // Unknown
821 }
822
823 if (SampledType->isIntegerTy(32)) {
824 if (Ty->isSignedIntegerType()) {
825 if (NumChannels == 1)
826 return 24; // R32i
827 if (NumChannels == 2)
828 return 25; // Rg32i
829 if (NumChannels == 4)
830 return 21; // Rgba32i
831 } else {
832 if (NumChannels == 1)
833 return 33; // R32ui
834 if (NumChannels == 2)
835 return 35; // Rg32ui
836 if (NumChannels == 4)
837 return 30; // Rgba32ui
838 }
839 } else if (SampledType->isIntegerTy(64)) {
840 if (NumChannels == 1) {
841 if (Ty->isSignedIntegerType()) {
842 return 41; // R64i
843 }
844 return 40; // R64ui
845 }
846 } else if (SampledType->isFloatTy()) {
847 if (NumChannels == 1)
848 return 3; // R32f
849 if (NumChannels == 2)
850 return 6; // Rg32f
851 if (NumChannels == 4)
852 return 1; // Rgba32f
853 }
854
855 return 0; // Unknown
856}
857
858llvm::Type *CommonSPIRTargetCodeGenInfo::getSPIRVImageTypeFromHLSLResource(
859 const HLSLAttributedResourceType::Attributes &attributes, QualType Ty,
860 CodeGenModule &CGM) const {
861 llvm::LLVMContext &Ctx = CGM.getLLVMContext();
862
863 unsigned NumChannels = 1;
865 if (const VectorType *V = dyn_cast<VectorType>(Ty)) {
866 NumChannels = V->getNumElements();
867 Ty = V->getElementType();
868 }
869 assert(!Ty->isVectorType() && "We still have a vector type.");
870
871 llvm::Type *SampledType = CGM.getTypes().ConvertTypeForMem(Ty);
872
873 assert((SampledType->isIntegerTy() || SampledType->isFloatingPointTy()) &&
874 "The element type for a SPIR-V resource must be a scalar integer or "
875 "floating point type.");
876
877 assert((!SampledType->isIntegerTy(64) || NumChannels <= 2) &&
878 "A 64-bit SPIR-V resource element can have at most 2 components.");
879
880 // SPIR-V has no 64-bit multi-component image format, so pack a 2-component
881 // 64-bit typed buffer into a 4-component 32-bit image. The backend
882 // reinterprets it with OpBitcast on load and store.
883 if (SampledType->isIntegerTy(64) && NumChannels == 2) {
884 SampledType = llvm::Type::getInt32Ty(Ctx);
885 NumChannels = 4;
886 }
887
888 // These parameters correspond to the operands to the OpTypeImage SPIR-V
889 // instruction. See
890 // https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpTypeImage.
891 SmallVector<unsigned, 6> IntParams(6, 0);
892
893 const char *Name =
894 Ty->isSignedIntegerType() ? "spirv.SignedImage" : "spirv.Image";
895
896 // Dim
897 switch (attributes.ResourceDimension) {
898 case llvm::dxil::ResourceDimension::Dim1D:
899 IntParams[0] = 0;
900 break;
901 case llvm::dxil::ResourceDimension::Dim2D:
902 IntParams[0] = 1;
903 break;
904 case llvm::dxil::ResourceDimension::Dim3D:
905 IntParams[0] = 2;
906 break;
907 case llvm::dxil::ResourceDimension::Cube:
908 IntParams[0] = 3;
909 break;
910 case llvm::dxil::ResourceDimension::Unknown:
911 IntParams[0] = 5;
912 break;
913 }
914
915 // Depth
916 // HLSL does not indicate if it is a depth texture or not, so we use unknown.
917 IntParams[1] = 2;
918
919 // Arrayed
920 IntParams[2] = static_cast<unsigned>(attributes.IsArray);
921
922 // MS
923 IntParams[3] = static_cast<unsigned>(attributes.isMultiSampled());
924
925 // Sampled
926 IntParams[4] =
927 attributes.ResourceClass == llvm::dxil::ResourceClass::UAV ? 2 : 1;
928
929 // Image format.
930 IntParams[5] = getImageFormat(CGM.getLangOpts(), attributes, SampledType, Ty,
931 NumChannels);
932
933 llvm::TargetExtType *ImageType =
934 llvm::TargetExtType::get(Ctx, Name, {SampledType}, IntParams);
935 return ImageType;
936}
937
938std::unique_ptr<TargetCodeGenInfo>
940 return std::make_unique<CommonSPIRTargetCodeGenInfo>(CGM.getTypes());
941}
942
943std::unique_ptr<TargetCodeGenInfo>
945 return std::make_unique<SPIRVTargetCodeGenInfo>(CGM.getTypes());
946}
#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:695
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:596
static unsigned getImageFormat(const LangOptions &LangOpts, const HLSLAttributedResourceType::Attributes &attributes, llvm::Type *SampledType, QualType Ty, unsigned NumChannels)
Definition SPIR.cpp:811
static llvm::Type * getInlineSpirvConstant(CodeGenModule &CGM, llvm::Type *IntegralType, llvm::APInt Value)
Definition SPIR.cpp:672
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:581
bool hasAttr() const
Definition DeclBase.h:585
Represents a member of a struct/union/class.
Definition Decl.h:3299
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:4601
bool hasFlexibleArrayMember() const
Definition Decl.h:4497
const FieldDecl * findFirstNamedDataMember() const
Finds the first data member which has a name.
Definition Decl.cpp:5483
bool isCompleteDefinition() const
Return true if this decl has its body fully specified.
Definition Decl.h:3957
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:724
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:443
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)
const Type * isSingleElementStruct(QualType T, ASTContext &Context)
isSingleElementStruct - Determine if a structure is a "singleelement struct", i.e.
std::unique_ptr< TargetCodeGenInfo > createSPIRVTargetCodeGenInfo(CodeGenModule &CGM)
Definition SPIR.cpp:944
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:939
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
for(const auto &A :T->param_types())
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