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