clang 24.0.0git
AMDGPU.cpp
Go to the documentation of this file.
1//===- AMDGPU.cpp ---------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "ABIInfoImpl.h"
10#include "TargetInfo.h"
11#include "clang/AST/DeclCXX.h"
12#include "llvm/ADT/StringExtras.h"
13#include "llvm/IR/MemoryModelRelaxationAnnotations.h"
14#include "llvm/Support/AMDGPUAddrSpace.h"
15
16using namespace clang;
17using namespace clang::CodeGen;
18
19//===----------------------------------------------------------------------===//
20// AMDGPU ABI Implementation
21//===----------------------------------------------------------------------===//
22
23namespace {
24
25class AMDGPUABIInfo final : public DefaultABIInfo {
26private:
27 static const unsigned MaxNumRegsForArgsRet = 16;
28
29 uint64_t numRegsForType(QualType Ty) const;
30
31 bool isHomogeneousAggregateBaseType(QualType Ty) const override;
32 bool isHomogeneousAggregateSmallEnough(const Type *Base,
33 uint64_t Members) const override;
34
35 // Coerce HIP scalar pointer arguments from generic pointers to global ones.
36 llvm::Type *coerceKernelArgumentType(llvm::Type *Ty, unsigned FromAS,
37 unsigned ToAS) const {
38 // Single value types.
39 auto *PtrTy = llvm::dyn_cast<llvm::PointerType>(Ty);
40 if (PtrTy && PtrTy->getAddressSpace() == FromAS)
41 return llvm::PointerType::get(Ty->getContext(), ToAS);
42 return Ty;
43 }
44
45public:
46 explicit AMDGPUABIInfo(CodeGen::CodeGenTypes &CGT) :
47 DefaultABIInfo(CGT) {}
48
49 ABIArgInfo classifyReturnType(QualType RetTy) const;
50 ABIArgInfo classifyKernelArgumentType(QualType Ty) const;
51 ABIArgInfo classifyArgumentType(QualType Ty, bool Variadic,
52 unsigned &NumRegsLeft) const;
53
54 void computeInfo(CGFunctionInfo &FI) const override;
55 RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
56 AggValueSlot Slot) const override;
57
58 llvm::FixedVectorType *
59 getOptimalVectorMemoryType(llvm::FixedVectorType *T,
60 const LangOptions &Opt) const override {
61 // We have legal instructions for 96-bit so 3x32 can be supported.
62 // FIXME: This check should be a subtarget feature as technically SI doesn't
63 // support it.
64 if (T->getNumElements() == 3 && getDataLayout().getTypeSizeInBits(T) == 96)
65 return T;
66 return DefaultABIInfo::getOptimalVectorMemoryType(T, Opt);
67 }
68};
69
70bool AMDGPUABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const {
71 return true;
72}
73
74bool AMDGPUABIInfo::isHomogeneousAggregateSmallEnough(
75 const Type *Base, uint64_t Members) const {
76 uint32_t NumRegs = (getContext().getTypeSize(Base) + 31) / 32;
77
78 // Homogeneous Aggregates may occupy at most 16 registers.
79 return Members * NumRegs <= MaxNumRegsForArgsRet;
80}
81
82/// Estimate number of registers the type will use when passed in registers.
83uint64_t AMDGPUABIInfo::numRegsForType(QualType Ty) const {
84 uint64_t NumRegs = 0;
85
86 if (const VectorType *VT = Ty->getAs<VectorType>()) {
87 // Compute from the number of elements. The reported size is based on the
88 // in-memory size, which includes the padding 4th element for 3-vectors.
89 QualType EltTy = VT->getElementType();
90 uint64_t EltSize = getContext().getTypeSize(EltTy);
91
92 // 16-bit element vectors should be passed as packed.
93 if (EltSize == 16)
94 return (VT->getNumElements() + 1) / 2;
95
96 uint64_t EltNumRegs = (EltSize + 31) / 32;
97 return EltNumRegs * VT->getNumElements();
98 }
99
100 if (const auto *RD = Ty->getAsRecordDecl()) {
101 assert(!RD->hasFlexibleArrayMember());
102
103 for (const FieldDecl *Field : RD->fields()) {
104 QualType FieldTy = Field->getType();
105 NumRegs += numRegsForType(FieldTy);
106 }
107
108 return NumRegs;
109 }
110
111 return (getContext().getTypeSize(Ty) + 31) / 32;
112}
113
114void AMDGPUABIInfo::computeInfo(CGFunctionInfo &FI) const {
115 llvm::CallingConv::ID CC = FI.getCallingConvention();
116
117 if (!getCXXABI().classifyReturnType(FI))
119
120 unsigned ArgumentIndex = 0;
121 const unsigned numFixedArguments = FI.getNumRequiredArgs();
122
123 unsigned NumRegsLeft = MaxNumRegsForArgsRet;
124 for (auto &Arg : FI.arguments()) {
125 if (CC == llvm::CallingConv::AMDGPU_KERNEL) {
126 Arg.info = classifyKernelArgumentType(Arg.type);
127 } else {
128 bool FixedArgument = ArgumentIndex++ < numFixedArguments;
129 Arg.info = classifyArgumentType(Arg.type, !FixedArgument, NumRegsLeft);
130 }
131 }
132}
133
134RValue AMDGPUABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
135 QualType Ty, AggValueSlot Slot) const {
136 const bool IsIndirect = false;
137 const bool AllowHigherAlign = false;
138 return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect,
139 getContext().getTypeInfoInChars(Ty),
140 CharUnits::fromQuantity(4), AllowHigherAlign, Slot);
141}
142
143ABIArgInfo AMDGPUABIInfo::classifyReturnType(QualType RetTy) const {
144 if (isAggregateTypeForABI(RetTy)) {
145 // Records with non-trivial destructors/copy-constructors should not be
146 // returned by value.
147 if (!getRecordArgABI(RetTy, getCXXABI())) {
148 // Ignore empty structs/unions.
149 if (isEmptyRecord(getContext(), RetTy, true))
150 return ABIArgInfo::getIgnore();
151
152 // Lower single-element structs to just return a regular value.
153 if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext()))
154 return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
155
156 if (const auto *RD = RetTy->getAsRecordDecl();
157 RD && RD->hasFlexibleArrayMember())
159
160 // Pack aggregates <= 4 bytes into single VGPR or pair.
161 uint64_t Size = getContext().getTypeSize(RetTy);
162 if (Size <= 16)
163 return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext()));
164
165 if (Size <= 32)
166 return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext()));
167
168 if (Size <= 64) {
169 llvm::Type *I32Ty = llvm::Type::getInt32Ty(getVMContext());
170 return ABIArgInfo::getDirect(llvm::ArrayType::get(I32Ty, 2));
171 }
172
173 if (numRegsForType(RetTy) <= MaxNumRegsForArgsRet)
174 return ABIArgInfo::getDirect();
175 }
176 }
177
178 // Otherwise just do the default thing.
180}
181
182/// For kernels all parameters are really passed in a special buffer. It doesn't
183/// make sense to pass anything byval, so everything must be direct.
184ABIArgInfo AMDGPUABIInfo::classifyKernelArgumentType(QualType Ty) const {
186
187 // TODO: Can we omit empty structs?
188
189 if (const Type *SeltTy = isSingleElementStruct(Ty, getContext()))
190 Ty = QualType(SeltTy, 0);
191
192 llvm::Type *OrigLTy = CGT.ConvertType(Ty);
193 llvm::Type *LTy = OrigLTy;
194 if (getContext().getLangOpts().HIP) {
195 LTy = coerceKernelArgumentType(
196 OrigLTy, /*FromAS=*/getContext().getTargetAddressSpace(LangAS::Default),
197 /*ToAS=*/getContext().getTargetAddressSpace(LangAS::cuda_device));
198 }
199
200 // FIXME: This doesn't apply the optimization of coercing pointers in structs
201 // to global address space when using byref. This would require implementing a
202 // new kind of coercion of the in-memory type when for indirect arguments.
203 if (LTy == OrigLTy && isAggregateTypeForABI(Ty)) {
205 getContext().getTypeAlignInChars(Ty),
206 getContext().getTargetAddressSpace(LangAS::opencl_constant),
207 false /*Realign*/, nullptr /*Padding*/);
208 }
209
210 // If we set CanBeFlattened to true, CodeGen will expand the struct to its
211 // individual elements, which confuses the Clover OpenCL backend; therefore we
212 // have to set it to false here. Other args of getDirect() are just defaults.
213 return ABIArgInfo::getDirect(LTy, 0, nullptr, false);
214}
215
216ABIArgInfo AMDGPUABIInfo::classifyArgumentType(QualType Ty, bool Variadic,
217 unsigned &NumRegsLeft) const {
218 assert(NumRegsLeft <= MaxNumRegsForArgsRet && "register estimate underflow");
219
221
222 if (Variadic) {
223 return ABIArgInfo::getDirect(/*T=*/nullptr,
224 /*Offset=*/0,
225 /*Padding=*/nullptr,
226 /*CanBeFlattened=*/false,
227 /*Align=*/0);
228 }
229
230 if (isAggregateTypeForABI(Ty)) {
231 // Records with non-trivial destructors/copy-constructors should not be
232 // passed by value.
233 if (auto RAA = getRecordArgABI(Ty, getCXXABI()))
234 return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace(),
236
237 // Ignore empty structs/unions.
238 if (isEmptyRecord(getContext(), Ty, true))
239 return ABIArgInfo::getIgnore();
240
241 // Lower single-element structs to just pass a regular value. TODO: We
242 // could do reasonable-size multiple-element structs too, using getExpand(),
243 // though watch out for things like bitfields.
244 if (const Type *SeltTy = isSingleElementStruct(Ty, getContext()))
245 return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
246
247 if (const auto *RD = Ty->getAsRecordDecl();
248 RD && RD->hasFlexibleArrayMember())
250
251 // Pack aggregates <= 8 bytes into single VGPR or pair.
252 uint64_t Size = getContext().getTypeSize(Ty);
253 if (Size <= 64) {
254 unsigned NumRegs = (Size + 31) / 32;
255 NumRegsLeft -= std::min(NumRegsLeft, NumRegs);
256
257 if (Size <= 16)
258 return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext()));
259
260 if (Size <= 32)
261 return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext()));
262
263 // XXX: Should this be i64 instead, and should the limit increase?
264 llvm::Type *I32Ty = llvm::Type::getInt32Ty(getVMContext());
265 return ABIArgInfo::getDirect(llvm::ArrayType::get(I32Ty, 2));
266 }
267
268 if (NumRegsLeft > 0) {
269 uint64_t NumRegs = numRegsForType(Ty);
270 if (NumRegsLeft >= NumRegs) {
271 NumRegsLeft -= NumRegs;
272 return ABIArgInfo::getDirect();
273 }
274 }
275
276 // Use pass-by-reference in stead of pass-by-value for struct arguments in
277 // function ABI.
279 getContext().getTypeAlignInChars(Ty),
280 getContext().getTargetAddressSpace(LangAS::opencl_private));
281 }
282
283 // Otherwise just do the default thing.
284 ABIArgInfo ArgInfo = DefaultABIInfo::classifyArgumentType(Ty);
285 if (!ArgInfo.isIndirect()) {
286 uint64_t NumRegs = numRegsForType(Ty);
287 NumRegsLeft -= std::min(NumRegs, uint64_t{NumRegsLeft});
288 }
289
290 return ArgInfo;
291}
292
293class AMDGPUTargetCodeGenInfo : public TargetCodeGenInfo {
294public:
295 AMDGPUTargetCodeGenInfo(CodeGenTypes &CGT)
296 : TargetCodeGenInfo(std::make_unique<AMDGPUABIInfo>(CGT)) {}
297
298 bool supportsLibCall() const override { return false; }
299 void setFunctionDeclAttributes(const FunctionDecl *FD, llvm::Function *F,
300 CodeGenModule &CGM) const;
301
302 void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
303 CodeGen::CodeGenModule &M) const override;
304 unsigned getDeviceKernelCallingConv() const override;
305
306 llvm::Constant *getNullPointer(const CodeGen::CodeGenModule &CGM,
307 llvm::PointerType *T, QualType QT) const override;
308
309 LangAS getSRetAddrSpace(const CXXRecordDecl *RD) const override;
310
311 LangAS getGlobalVarAddressSpace(CodeGenModule &CGM,
312 const VarDecl *D) const override;
313 StringRef getLLVMSyncScopeStr(const LangOptions &LangOpts, SyncScope Scope,
314 llvm::AtomicOrdering Ordering) const override;
315 void setTargetAtomicMetadata(CodeGenFunction &CGF,
316 llvm::Instruction &AtomicInst,
317 const AtomicExpr *Expr = nullptr) const override;
318 llvm::Value *createEnqueuedBlockKernel(CodeGenFunction &CGF,
319 llvm::Function *BlockInvokeFunc,
320 llvm::Type *BlockTy) const override;
321 bool shouldEmitStaticExternCAliases() const override;
322 bool shouldEmitDWARFBitFieldSeparators() const override;
323 void setCUDAKernelCallingConvention(const FunctionType *&FT) const override;
324};
325}
326
328 llvm::GlobalValue *GV) {
329 if (GV->getVisibility() != llvm::GlobalValue::HiddenVisibility)
330 return false;
331
332 return !D->hasAttr<OMPDeclareTargetDeclAttr>() &&
333 (D->hasAttr<DeviceKernelAttr>() ||
334 (isa<FunctionDecl>(D) && D->hasAttr<CUDAGlobalAttr>()) ||
335 (isa<VarDecl>(D) &&
336 (D->hasAttr<CUDADeviceAttr>() || D->hasAttr<CUDAConstantAttr>() ||
337 cast<VarDecl>(D)->getType()->isCUDADeviceBuiltinSurfaceType() ||
338 cast<VarDecl>(D)->getType()->isCUDADeviceBuiltinTextureType())));
339}
340
341void AMDGPUTargetCodeGenInfo::setFunctionDeclAttributes(
342 const FunctionDecl *FD, llvm::Function *F, CodeGenModule &M) const {
343 const auto *ReqdWGS =
344 M.getLangOpts().OpenCL ? FD->getAttr<ReqdWorkGroupSizeAttr>() : nullptr;
345 const bool IsOpenCLKernel =
346 M.getLangOpts().OpenCL && FD->hasAttr<DeviceKernelAttr>();
347 const bool IsHIPKernel = M.getLangOpts().HIP && FD->hasAttr<CUDAGlobalAttr>();
348
349 const auto *FlatWGS = FD->getAttr<AMDGPUFlatWorkGroupSizeAttr>();
350 if (ReqdWGS || FlatWGS) {
351 M.handleAMDGPUFlatWorkGroupSizeAttr(F, FlatWGS, ReqdWGS);
352 } else if (IsOpenCLKernel || IsHIPKernel) {
353 // By default, restrict the maximum size to a value specified by
354 // --gpu-max-threads-per-block=n or its default value for HIP.
355 const unsigned OpenCLDefaultMaxWorkGroupSize = 256;
356 const unsigned DefaultMaxWorkGroupSize =
357 IsOpenCLKernel ? OpenCLDefaultMaxWorkGroupSize
358 : M.getLangOpts().GPUMaxThreadsPerBlock;
359 std::string AttrVal =
360 std::string("1,") + llvm::utostr(DefaultMaxWorkGroupSize);
361 F->addFnAttr("amdgpu-flat-work-group-size", AttrVal);
362 }
363
364 if (const auto *Attr = FD->getAttr<AMDGPUWavesPerEUAttr>())
366
367 if (const auto *Attr = FD->getAttr<AMDGPUNumSGPRAttr>()) {
368 unsigned NumSGPR = Attr->getNumSGPR();
369
370 if (NumSGPR != 0)
371 F->addFnAttr("amdgpu-num-sgpr", llvm::utostr(NumSGPR));
372 }
373
374 if (const auto *Attr = FD->getAttr<AMDGPUNumVGPRAttr>()) {
375 uint32_t NumVGPR = Attr->getNumVGPR();
376
377 if (NumVGPR != 0)
378 F->addFnAttr("amdgpu-num-vgpr", llvm::utostr(NumVGPR));
379 }
380
381 if (const auto *Attr = FD->getAttr<AMDGPUMaxNumWorkGroupsAttr>()) {
382 uint32_t X = Attr->getMaxNumWorkGroupsX()
383 ->EvaluateKnownConstInt(M.getContext())
384 .getExtValue();
385 // Y and Z dimensions default to 1 if not specified
386 uint32_t Y = Attr->getMaxNumWorkGroupsY()
387 ? Attr->getMaxNumWorkGroupsY()
388 ->EvaluateKnownConstInt(M.getContext())
389 .getExtValue()
390 : 1;
391 uint32_t Z = Attr->getMaxNumWorkGroupsZ()
392 ? Attr->getMaxNumWorkGroupsZ()
393 ->EvaluateKnownConstInt(M.getContext())
394 .getExtValue()
395 : 1;
396
397 llvm::SmallString<32> AttrVal;
398 llvm::raw_svector_ostream OS(AttrVal);
399 OS << X << ',' << Y << ',' << Z;
400
401 F->addFnAttr("amdgpu-max-num-workgroups", AttrVal.str());
402 }
403
404 if (auto *Attr = FD->getAttr<CUDAClusterDimsAttr>()) {
405 auto GetExprVal = [&](const auto &E) {
406 return E ? E->EvaluateKnownConstInt(M.getContext()).getExtValue() : 1;
407 };
408 unsigned X = GetExprVal(Attr->getX());
409 unsigned Y = GetExprVal(Attr->getY());
410 unsigned Z = GetExprVal(Attr->getZ());
411 llvm::SmallString<32> AttrVal;
412 llvm::raw_svector_ostream OS(AttrVal);
413 OS << X << ',' << Y << ',' << Z;
414 F->addFnAttr("amdgpu-cluster-dims", AttrVal.str());
415 }
416
417 // OpenCL doesn't support cluster feature.
418 const TargetInfo &TTI = M.getContext().getTargetInfo();
419 if ((IsOpenCLKernel &&
420 TTI.hasFeatureEnabled(TTI.getTargetOpts().FeatureMap, "clusters")) ||
421 FD->hasAttr<CUDANoClusterAttr>())
422 F->addFnAttr("amdgpu-cluster-dims", "0,0,0");
423}
424
425void AMDGPUTargetCodeGenInfo::setTargetAttributes(
426 const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const {
428 GV->setVisibility(llvm::GlobalValue::ProtectedVisibility);
429 GV->setDSOLocal(true);
430 }
431
432 if (GV->isDeclaration())
433 return;
434
435 llvm::Function *F = dyn_cast<llvm::Function>(GV);
436 if (!F)
437 return;
438
439 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
440 if (FD)
441 setFunctionDeclAttributes(FD, F, M);
442 if (!getABIInfo().getCodeGenOpts().EmitIEEENaNCompliantInsts)
443 F->addFnAttr("amdgpu-ieee", "false");
444 if (getABIInfo().getCodeGenOpts().AMDGPUExpandWaitcntProfiling)
445 F->addFnAttr("amdgpu-expand-waitcnt-profiling");
446}
447
448unsigned AMDGPUTargetCodeGenInfo::getDeviceKernelCallingConv() const {
449 return llvm::CallingConv::AMDGPU_KERNEL;
450}
451
452// Currently LLVM assumes null pointers always have value 0,
453// which results in incorrectly transformed IR. Therefore, instead of
454// emitting null pointers in private and local address spaces, a null
455// pointer in generic address space is emitted which is casted to a
456// pointer in local or private address space.
457llvm::Constant *AMDGPUTargetCodeGenInfo::getNullPointer(
458 const CodeGen::CodeGenModule &CGM, llvm::PointerType *PT,
459 QualType QT) const {
460 if (CGM.getContext().getTargetNullPointerValue(QT) == 0)
461 return llvm::ConstantPointerNull::get(PT);
462
463 auto &Ctx = CGM.getContext();
464 auto NPT = llvm::PointerType::get(
465 PT->getContext(), Ctx.getTargetAddressSpace(LangAS::opencl_generic));
466 return llvm::ConstantExpr::getAddrSpaceCast(
467 llvm::ConstantPointerNull::get(NPT), PT);
468}
469
470LangAS
471AMDGPUTargetCodeGenInfo::getSRetAddrSpace(const CXXRecordDecl *RD) const {
472 // Types with no viable copy/move must be constructed in-place , use the
473 // default AS so the sret pointer matches the "this" convention.
474 if (RD && !RD->canPassInRegisters())
475 return LangAS::Default;
477 getABIInfo().getDataLayout().getAllocaAddrSpace());
478}
479
480LangAS
481AMDGPUTargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM,
482 const VarDecl *D) const {
483 assert(!CGM.getLangOpts().OpenCL &&
484 !(CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) &&
485 "Address space agnostic languages only");
486 LangAS DefaultGlobalAS = getLangASFromTargetAS(
487 CGM.getContext().getTargetAddressSpace(LangAS::opencl_global));
488 if (!D)
489 return DefaultGlobalAS;
490
491 LangAS AddrSpace = D->getType().getAddressSpace();
492 if (AddrSpace != LangAS::Default)
493 return AddrSpace;
494
495 // Only promote to address space 4 if VarDecl has constant initialization.
496 if (D->getType().isConstantStorage(CGM.getContext(), false, false) &&
498 if (auto ConstAS = CGM.getTarget().getConstantAddressSpace())
499 return *ConstAS;
500 }
501 return DefaultGlobalAS;
502}
503
504StringRef AMDGPUTargetCodeGenInfo::getLLVMSyncScopeStr(
505 const LangOptions &LangOpts, SyncScope Scope,
506 llvm::AtomicOrdering Ordering) const {
507
508 // OpenCL assumes by default that atomic scopes are per-address space for
509 // non-sequentially consistent operations.
510 bool IsOneAs = (Scope >= SyncScope::OpenCLWorkGroup &&
511 Scope <= SyncScope::OpenCLSubGroup &&
512 Ordering != llvm::AtomicOrdering::SequentiallyConsistent);
513
514 llvm::AtomicScope AS = getAtomicScope(Scope);
515 assert((AS != llvm::AtomicScope::Cluster || !IsOneAs) &&
516 "OpenCL does not have cluster scope");
517 return *llvm::getAtomicScopeIRString(getABIInfo().getTarget().getTriple(), AS,
518 IsOneAs);
519}
520
521void AMDGPUTargetCodeGenInfo::setTargetAtomicMetadata(
522 CodeGenFunction &CGF, llvm::Instruction &AtomicInst,
523 const AtomicExpr *AE) const {
524 auto *RMW = dyn_cast<llvm::AtomicRMWInst>(&AtomicInst);
525 auto *CmpX = dyn_cast<llvm::AtomicCmpXchgInst>(&AtomicInst);
526
527 // OpenCL and old style HIP atomics consider atomics targeting thread private
528 // memory to be undefined.
529 //
530 // TODO: This is probably undefined for atomic load/store, but there's not
531 // much direct codegen benefit to knowing this.
532 if (((RMW && RMW->getPointerAddressSpace() == llvm::AMDGPUAS::FLAT_ADDRESS) ||
533 (CmpX &&
534 CmpX->getPointerAddressSpace() == llvm::AMDGPUAS::FLAT_ADDRESS)) &&
536 llvm::MDBuilder MDHelper(CGF.getLLVMContext());
537 llvm::MDNode *ASRange = MDHelper.createRange(
538 llvm::APInt(32, llvm::AMDGPUAS::PRIVATE_ADDRESS),
539 llvm::APInt(32, llvm::AMDGPUAS::PRIVATE_ADDRESS + 1));
540 AtomicInst.setMetadata(llvm::LLVMContext::MD_noalias_addrspace, ASRange);
541 }
542
543 CGF.AddAMDGPUAvailableVisibleMMRA(&AtomicInst);
544
545 if (!RMW)
546 return;
547
548 AtomicOptions AO = CGF.CGM.getAtomicOpts();
549 llvm::MDNode *Empty = llvm::MDNode::get(CGF.getLLVMContext(), {});
551 RMW->setMetadata("amdgpu.no.fine.grained.memory", Empty);
553 RMW->setMetadata("amdgpu.no.remote.memory", Empty);
555 RMW->getOperation() == llvm::AtomicRMWInst::FAdd &&
556 RMW->getType()->isFloatTy())
557 RMW->setMetadata("amdgpu.ignore.denormal.mode", Empty);
558}
559
560bool AMDGPUTargetCodeGenInfo::shouldEmitStaticExternCAliases() const {
561 return false;
562}
563
564bool AMDGPUTargetCodeGenInfo::shouldEmitDWARFBitFieldSeparators() const {
565 return true;
566}
567
568void AMDGPUTargetCodeGenInfo::setCUDAKernelCallingConvention(
569 const FunctionType *&FT) const {
570 FT = getABIInfo().getContext().adjustFunctionType(
572}
573
574/// Return IR struct type for rtinfo struct in rocm-device-libs used for device
575/// enqueue.
576///
577/// ptr addrspace(1) kernel_object, i32 private_segment_size,
578/// i32 group_segment_size
579
580static llvm::StructType *
581getAMDGPURuntimeHandleType(llvm::LLVMContext &C,
582 llvm::Type *KernelDescriptorPtrTy) {
583 llvm::Type *Int32 = llvm::Type::getInt32Ty(C);
584 return llvm::StructType::create(C, {KernelDescriptorPtrTy, Int32, Int32},
585 "block.runtime.handle.t");
586}
587
588/// Create an OpenCL kernel for an enqueued block.
589///
590/// The type of the first argument (the block literal) is the struct type
591/// of the block literal instead of a pointer type. The first argument
592/// (block literal) is passed directly by value to the kernel. The kernel
593/// allocates the same type of struct on stack and stores the block literal
594/// to it and passes its pointer to the block invoke function. The kernel
595/// has "enqueued-block" function attribute and kernel argument metadata.
596llvm::Value *AMDGPUTargetCodeGenInfo::createEnqueuedBlockKernel(
597 CodeGenFunction &CGF, llvm::Function *Invoke, llvm::Type *BlockTy) const {
598 auto &Builder = CGF.Builder;
599 auto &C = CGF.getLLVMContext();
600
601 auto *InvokeFT = Invoke->getFunctionType();
602 llvm::SmallVector<llvm::Type *, 2> ArgTys;
603 llvm::SmallVector<llvm::Metadata *, 8> AddressQuals;
604 llvm::SmallVector<llvm::Metadata *, 8> AccessQuals;
605 llvm::SmallVector<llvm::Metadata *, 8> ArgTypeNames;
606 llvm::SmallVector<llvm::Metadata *, 8> ArgBaseTypeNames;
607 llvm::SmallVector<llvm::Metadata *, 8> ArgTypeQuals;
608 llvm::SmallVector<llvm::Metadata *, 8> ArgNames;
609
610 ArgTys.push_back(BlockTy);
611 ArgTypeNames.push_back(llvm::MDString::get(C, "__block_literal"));
612 AddressQuals.push_back(llvm::ConstantAsMetadata::get(Builder.getInt32(0)));
613 ArgBaseTypeNames.push_back(llvm::MDString::get(C, "__block_literal"));
614 ArgTypeQuals.push_back(llvm::MDString::get(C, ""));
615 AccessQuals.push_back(llvm::MDString::get(C, "none"));
616 ArgNames.push_back(llvm::MDString::get(C, "block_literal"));
617 for (unsigned I = 1, E = InvokeFT->getNumParams(); I < E; ++I) {
618 ArgTys.push_back(InvokeFT->getParamType(I));
619 ArgTypeNames.push_back(llvm::MDString::get(C, "void*"));
620 AddressQuals.push_back(llvm::ConstantAsMetadata::get(Builder.getInt32(3)));
621 AccessQuals.push_back(llvm::MDString::get(C, "none"));
622 ArgBaseTypeNames.push_back(llvm::MDString::get(C, "void*"));
623 ArgTypeQuals.push_back(llvm::MDString::get(C, ""));
624 ArgNames.push_back(
625 llvm::MDString::get(C, (Twine("local_arg") + Twine(I)).str()));
626 }
627
628 llvm::Module &Mod = CGF.CGM.getModule();
629 const llvm::DataLayout &DL = Mod.getDataLayout();
630
631 llvm::Twine Name = Invoke->getName() + "_kernel";
632 auto *FT = llvm::FunctionType::get(llvm::Type::getVoidTy(C), ArgTys, false);
633
634 // The kernel itself can be internal, the runtime does not directly access the
635 // kernel address (only the kernel descriptor).
636 auto *F = llvm::Function::Create(FT, llvm::GlobalValue::InternalLinkage, Name,
637 &Mod);
638 F->setCallingConv(getDeviceKernelCallingConv());
639
640 llvm::AttrBuilder KernelAttrs(C);
641 // FIXME: The invoke isn't applying the right attributes either
642 // FIXME: This is missing setTargetAttributes
644 F->addFnAttrs(KernelAttrs);
645
646 auto IP = CGF.Builder.saveIP();
647 auto *BB = llvm::BasicBlock::Create(C, "entry", F);
648 Builder.SetInsertPoint(BB);
649 const auto BlockAlign = DL.getPrefTypeAlign(BlockTy);
650 auto *BlockPtr = Builder.CreateAlloca(BlockTy, nullptr);
651 BlockPtr->setAlignment(BlockAlign);
652 Builder.CreateAlignedStore(F->arg_begin(), BlockPtr, BlockAlign);
653 auto *Cast = Builder.CreatePointerCast(BlockPtr, InvokeFT->getParamType(0));
654 llvm::SmallVector<llvm::Value *, 2> Args;
655 Args.push_back(Cast);
656 for (llvm::Argument &A : llvm::drop_begin(F->args()))
657 Args.push_back(&A);
658 llvm::CallInst *call = Builder.CreateCall(Invoke, Args);
659 call->setCallingConv(Invoke->getCallingConv());
660 Builder.CreateRetVoid();
661 Builder.restoreIP(IP);
662
663 F->setMetadata("kernel_arg_addr_space", llvm::MDNode::get(C, AddressQuals));
664 F->setMetadata("kernel_arg_access_qual", llvm::MDNode::get(C, AccessQuals));
665 F->setMetadata("kernel_arg_type", llvm::MDNode::get(C, ArgTypeNames));
666 F->setMetadata("kernel_arg_base_type",
667 llvm::MDNode::get(C, ArgBaseTypeNames));
668 F->setMetadata("kernel_arg_type_qual", llvm::MDNode::get(C, ArgTypeQuals));
669 if (CGF.CGM.getCodeGenOpts().EmitOpenCLArgMetadata)
670 F->setMetadata("kernel_arg_name", llvm::MDNode::get(C, ArgNames));
671
672 llvm::StructType *HandleTy = getAMDGPURuntimeHandleType(
673 C, llvm::PointerType::get(C, DL.getDefaultGlobalsAddressSpace()));
674 llvm::Constant *RuntimeHandleInitializer =
675 llvm::ConstantAggregateZero::get(HandleTy);
676
677 llvm::Twine RuntimeHandleName = F->getName() + ".runtime.handle";
678
679 // The runtime needs access to the runtime handle as an external symbol. The
680 // runtime handle will need to be made external later, in
681 // AMDGPUExportOpenCLEnqueuedBlocks. The kernel itself has a hidden reference
682 // inside the runtime handle, and is not directly referenced.
683
684 // TODO: We would initialize the first field by declaring F->getName() + ".kd"
685 // to reference the kernel descriptor. The runtime wouldn't need to bother
686 // setting it. We would need to have a final symbol name though.
687 // TODO: Can we directly use an external symbol with getGlobalIdentifier?
688 auto *RuntimeHandle = new llvm::GlobalVariable(
689 Mod, HandleTy,
690 /*isConstant=*/true, llvm::GlobalValue::InternalLinkage,
691 /*Initializer=*/RuntimeHandleInitializer, RuntimeHandleName,
692 /*InsertBefore=*/nullptr, llvm::GlobalValue::NotThreadLocal,
693 DL.getDefaultGlobalsAddressSpace(),
694 /*isExternallyInitialized=*/true);
695
696 llvm::MDNode *HandleAsMD =
697 llvm::MDNode::get(C, llvm::ValueAsMetadata::get(RuntimeHandle));
698 F->setMetadata(llvm::LLVMContext::MD_associated, HandleAsMD);
699
700 RuntimeHandle->setSection(".amdgpu.kernel.runtime.handle");
701
702 CGF.CGM.addUsedGlobal(F);
703 CGF.CGM.addUsedGlobal(RuntimeHandle);
704 return RuntimeHandle;
705}
706
708 llvm::Function *F, const AMDGPUFlatWorkGroupSizeAttr *FlatWGS,
709 const ReqdWorkGroupSizeAttr *ReqdWGS, int32_t *MinThreadsVal,
710 int32_t *MaxThreadsVal) {
711 unsigned Min = 0;
712 unsigned Max = 0;
713 auto Eval = [&](Expr *E) {
714 return E->EvaluateKnownConstInt(getContext()).getExtValue();
715 };
716 if (ReqdWGS) {
717 Min = Max = Eval(ReqdWGS->getXDim()) * Eval(ReqdWGS->getYDim()) *
718 Eval(ReqdWGS->getZDim());
719 } else if (FlatWGS) {
720 Min = Eval(FlatWGS->getMin());
721 Max = Eval(FlatWGS->getMax());
722 }
723
724 if (Min != 0 || ReqdWGS) {
725 assert(Min <= Max && "Min must be less than or equal Max");
726
727 if (MinThreadsVal)
728 *MinThreadsVal = Min;
729 if (MaxThreadsVal)
730 *MaxThreadsVal = Max;
731 std::string AttrVal = llvm::utostr(Min) + "," + llvm::utostr(Max);
732 if (F)
733 F->addFnAttr("amdgpu-flat-work-group-size", AttrVal);
734 } else
735 assert(Max == 0 && "Max must be zero");
736}
737
739 llvm::Function *F, const AMDGPUWavesPerEUAttr *Attr) {
740 unsigned Min =
741 Attr->getMin()->EvaluateKnownConstInt(getContext()).getExtValue();
742 unsigned Max =
743 Attr->getMax()
744 ? Attr->getMax()->EvaluateKnownConstInt(getContext()).getExtValue()
745 : 0;
746
747 if (Min != 0) {
748 assert((Max == 0 || Min <= Max) && "Min must be less than or equal Max");
749
750 std::string AttrVal = llvm::utostr(Min);
751 if (Max != 0)
752 AttrVal = AttrVal + "," + llvm::utostr(Max);
753 F->addFnAttr("amdgpu-waves-per-eu", AttrVal);
754 } else
755 assert(Max == 0 && "Max must be zero");
756}
757
758std::unique_ptr<TargetCodeGenInfo>
760 return std::make_unique<AMDGPUTargetCodeGenInfo>(CGM.getTypes());
761}
static void setCUDAKernelCallingConvention(CanQualType &FTy, CodeGenModule &CGM, const FunctionDecl *FD)
Set calling convention for CUDA/HIP kernel.
Definition CGCall.cpp:374
static bool requiresAMDGPUProtectedVisibility(const Decl *D, llvm::GlobalValue *GV)
Definition AMDGPU.cpp:327
static llvm::StructType * getAMDGPURuntimeHandleType(llvm::LLVMContext &C, llvm::Type *KernelDescriptorPtrTy)
Return IR struct type for rtinfo struct in rocm-device-libs used for device enqueue.
Definition AMDGPU.cpp:581
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
#define X(type, name)
Definition Value.h:97
static StringRef getTriple(const Command &Job)
uint64_t getTargetNullPointerValue(QualType QT) const
Get target-dependent integer value for null pointer which is used for constant folding.
const TargetInfo & getTargetInfo() const
Definition ASTContext.h:927
unsigned getTargetAddressSpace(LangAS AS) const
bool threadPrivateMemoryAtomicsAreUndefined() const
Return true if atomics operations targeting allocations in private memory are undefined.
Definition Expr.h:7064
Attr - This represents one attribute.
Definition Attr.h:46
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
Definition CharUnits.h:63
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
unsigned getCallingConvention() const
getCallingConvention - Return the user specified calling convention, which has been translated into a...
CanQualType getReturnType() const
MutableArrayRef< ArgInfo > arguments()
void AddAMDGPUAvailableVisibleMMRA(llvm::Instruction *Inst)
Attach the AMDGPU availability/visibility MMRA to Inst when the amdgpu_av attribute is active on the ...
Definition AMDGPU.cpp:491
llvm::LLVMContext & getLLVMContext()
This class organizes the cross-function state that is used while generating LLVM code.
llvm::Module & getModule() const
void handleAMDGPUWavesPerEUAttr(llvm::Function *F, const AMDGPUWavesPerEUAttr *A)
Emit the IR encoding to attach the AMD GPU waves-per-eu attribute to F.
Definition AMDGPU.cpp:738
const LangOptions & getLangOpts() const
const TargetInfo & getTarget() const
void addUsedGlobal(llvm::GlobalValue *GV)
Add a global to a list to be added to the llvm.used metadata.
void handleAMDGPUFlatWorkGroupSizeAttr(llvm::Function *F, const AMDGPUFlatWorkGroupSizeAttr *A, const ReqdWorkGroupSizeAttr *ReqdWGS=nullptr, int32_t *MinThreadsVal=nullptr, int32_t *MaxThreadsVal=nullptr)
Emit the IR encoding to attach the AMD GPU flat-work-group-size attribute to F.
Definition AMDGPU.cpp:707
AtomicOptions getAtomicOpts()
Get the current Atomic options.
ASTContext & getContext() const
const CodeGenOptions & getCodeGenOpts() const
void addDefaultFunctionDefinitionAttributes(llvm::AttrBuilder &attrs)
Like the overload taking a Function &, but intended specifically for frontends that want to build on ...
Definition CGCall.cpp:2552
DefaultABIInfo - The default implementation for ABI specific details.
Definition ABIInfoImpl.h:21
ABIArgInfo classifyArgumentType(QualType RetTy) const
ABIArgInfo classifyReturnType(QualType RetTy) const
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
T * getAttr() const
Definition DeclBase.h:581
bool hasAttr() const
Definition DeclBase.h:585
This represents one expression.
Definition Expr.h:112
ExtInfo withCallingConv(CallingConv cc) const
Definition TypeBase.h:4837
ExtInfo getExtInfo() const
Definition TypeBase.h:4970
A (possibly-)qualified type.
Definition TypeBase.h:938
LangAS getAddressSpace() const
Return the address space of this type.
Definition TypeBase.h:8627
bool isConstantStorage(const ASTContext &Ctx, bool ExcludeCtor, bool ExcludeDtor)
Definition TypeBase.h:1037
bool canPassInRegisters() const
Determine whether this class can be passed in registers.
Definition Decl.h:4506
bool hasFlexibleArrayMember() const
Definition Decl.h:4402
TargetOptions & getTargetOpts() const
Retrieve the target options.
Definition TargetInfo.h:333
virtual std::optional< LangAS > getConstantAddressSpace() const
Return an AST address space which can be used opportunistically for constant global memory.
virtual bool hasFeatureEnabled(const llvm::StringMap< bool > &Features, StringRef Name) const
Check if target has a given feature enabled.
llvm::StringMap< bool > FeatureMap
The map of which features have been enabled disabled based on the command line.
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition Type.h:41
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9337
QualType getType() const
Definition Decl.h:723
bool hasConstantInitialization() const
Determine whether this variable has constant initialization.
Definition Decl.cpp:2632
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)
std::unique_ptr< TargetCodeGenInfo > createAMDGPUTargetCodeGenInfo(CodeGenModule &CGM)
Definition AMDGPU.cpp:759
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 ...
bool isAggregateTypeForABI(QualType T)
const Type * isSingleElementStruct(QualType T, ASTContext &Context)
isSingleElementStruct - Determine if a structure is a "singleelement struct", i.e.
QualType useFirstFieldIfTransparentUnion(QualType Ty)
Pass transparent unions as if they were the type of the first element.
bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays, bool AsIfNoUniqueAddr=false)
isEmptyRecord - Return true iff a structure contains only empty fields.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
bool Cast(InterpState &S, CodePtr OpPC)
Definition Interp.h:2832
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
const FunctionProtoType * T
@ Type
The name was classified as a type.
Definition Sema.h:570
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:293
U cast(CodeGen::Address addr)
Definition Address.h:327
LangAS getLangASFromTargetAS(unsigned TargetAS)
unsigned long uint64_t
__packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 __packed_splat2 __packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 uint32_t
bool getOption(AtomicOptionKind Kind) const