LLVM 24.0.0git
AMDGPUHSAMetadataStreamer.cpp
Go to the documentation of this file.
1//===--- AMDGPUHSAMetadataStreamer.cpp --------------------------*- C++ -*-===//
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/// \file
10/// AMDGPU HSA Metadata Streamer.
11///
12//
13//===----------------------------------------------------------------------===//
14
16#include "AMDGPU.h"
17#include "GCNSubtarget.h"
20#include "SIProgramInfo.h"
21#include "llvm/IR/Module.h"
22#include "llvm/MC/MCContext.h"
23#include "llvm/MC/MCExpr.h"
25
26using namespace llvm;
27
28static std::pair<Type *, Align> getArgumentTypeAlign(const Argument &Arg,
29 const DataLayout &DL) {
30 Type *Ty = Arg.getType();
31 MaybeAlign ArgAlign;
32 if (Arg.hasByRefAttr()) {
33 Ty = Arg.getParamByRefType();
34 ArgAlign = Arg.getParamAlign();
35 }
36
37 if (!ArgAlign)
38 ArgAlign = DL.getABITypeAlign(Ty);
39
40 return std::pair(Ty, *ArgAlign);
41}
42
43/// Find the mangled symbol name for the runtime handle for \p EnqueuedBlock
45 const Function &EnqueuedBlock) {
46 const MDNode *Associated =
47 EnqueuedBlock.getMetadata(LLVMContext::MD_associated);
48 if (!Associated)
49 return "";
50
51 auto *VM = cast<ValueAsMetadata>(Associated->getOperand(0));
52 auto *RuntimeHandle =
53 dyn_cast<GlobalVariable>(VM->getValue()->stripPointerCasts());
54 if (!RuntimeHandle ||
55 RuntimeHandle->getSection() != ".amdgpu.kernel.runtime.handle")
56 return "";
57
59 TM.getNameWithPrefix(Name, RuntimeHandle,
61 return Name.str().str();
62}
63
64namespace llvm {
65
66namespace AMDGPU::HSAMD {
67
68//===----------------------------------------------------------------------===//
69// HSAMetadataStreamerV4
70//===----------------------------------------------------------------------===//
71
72void MetadataStreamerMsgPackV4::dump(StringRef HSAMetadataString) const {
73 errs() << "AMDGPU HSA Metadata:\n" << HSAMetadataString << '\n';
74}
75
76void MetadataStreamerMsgPackV4::verify(StringRef HSAMetadataString) const {
77 errs() << "AMDGPU HSA Metadata Parser Test: ";
78
79 msgpack::Document FromHSAMetadataString;
80
81 if (!FromHSAMetadataString.fromYAML(HSAMetadataString)) {
82 errs() << "FAIL\n";
83 return;
84 }
85
86 std::string ToHSAMetadataString;
87 raw_string_ostream StrOS(ToHSAMetadataString);
88 FromHSAMetadataString.toYAML(StrOS);
89
90 errs() << (HSAMetadataString == StrOS.str() ? "PASS" : "FAIL") << '\n';
91 if (HSAMetadataString != ToHSAMetadataString) {
92 errs() << "Original input: " << HSAMetadataString << '\n'
93 << "Produced output: " << StrOS.str() << '\n';
94 }
95}
96
97std::optional<StringRef>
100 .Case("read_only", StringRef("read_only"))
101 .Case("write_only", StringRef("write_only"))
102 .Case("read_write", StringRef("read_write"))
103 .Default(std::nullopt);
104}
105
107 unsigned AddressSpace) const {
108 switch (AddressSpace) {
110 return StringRef("private");
112 return StringRef("global");
114 return StringRef("constant");
116 return StringRef("local");
118 return StringRef("generic");
120 return StringRef("region");
121 default:
122 return std::nullopt;
123 }
124}
125
128 StringRef BaseTypeName) const {
129 if (TypeQual.contains("pipe"))
130 return "pipe";
131
132 return StringSwitch<StringRef>(BaseTypeName)
133 .Case("image1d_t", "image")
134 .Case("image1d_array_t", "image")
135 .Case("image1d_buffer_t", "image")
136 .Case("image2d_t", "image")
137 .Case("image2d_array_t", "image")
138 .Case("image2d_array_depth_t", "image")
139 .Case("image2d_array_msaa_t", "image")
140 .Case("image2d_array_msaa_depth_t", "image")
141 .Case("image2d_depth_t", "image")
142 .Case("image2d_msaa_t", "image")
143 .Case("image2d_msaa_depth_t", "image")
144 .Case("image3d_t", "image")
145 .Case("sampler_t", "sampler")
146 .Case("queue_t", "queue")
148 ? (Ty->getPointerAddressSpace() == AMDGPUAS::LOCAL_ADDRESS
149 ? "dynamic_shared_pointer"
150 : "global_buffer")
151 : "by_value");
152}
153
155 bool Signed) const {
156 switch (Ty->getTypeID()) {
157 case Type::IntegerTyID: {
158 if (!Signed)
159 return (Twine('u') + getTypeName(Ty, true)).str();
160
161 auto BitWidth = Ty->getIntegerBitWidth();
162 switch (BitWidth) {
163 case 8:
164 return "char";
165 case 16:
166 return "short";
167 case 32:
168 return "int";
169 case 64:
170 return "long";
171 default:
172 return (Twine('i') + Twine(BitWidth)).str();
173 }
174 }
175 case Type::HalfTyID:
176 return "half";
177 case Type::FloatTyID:
178 return "float";
179 case Type::DoubleTyID:
180 return "double";
182 auto *VecTy = cast<FixedVectorType>(Ty);
183 auto *ElTy = VecTy->getElementType();
184 auto NumElements = VecTy->getNumElements();
185 return (Twine(getTypeName(ElTy, Signed)) + Twine(NumElements)).str();
186 }
187 default:
188 return "unknown";
189 }
190}
191
194 auto Dims = HSAMetadataDoc->getArrayNode();
195 if (Node->getNumOperands() != 3)
196 return Dims;
197
198 for (auto &Op : Node->operands())
199 Dims.push_back(Dims.getDocument()->getNode(
200 mdconst::extract<ConstantInt>(Op)->getZExtValue()));
201 return Dims;
202}
203
205 auto Version = HSAMetadataDoc->getArrayNode();
206 Version.push_back(Version.getDocument()->getNode(VersionMajorV4));
207 Version.push_back(Version.getDocument()->getNode(VersionMinorV4));
208 getRootMetadata("amdhsa.version") = Version;
209}
210
212 getRootMetadata("amdhsa.target") =
213 HSAMetadataDoc->getNode(TargetID.toString(), /*Copy=*/true);
214}
215
217 auto *Node = Mod.getNamedMetadata("llvm.printf.fmts");
218 if (!Node)
219 return;
220
221 auto Printf = HSAMetadataDoc->getArrayNode();
222 for (auto *Op : Node->operands())
223 if (Op->getNumOperands())
224 Printf.push_back(Printf.getDocument()->getNode(
225 cast<MDString>(Op->getOperand(0))->getString(), /*Copy=*/true));
226 getRootMetadata("amdhsa.printf") = Printf;
227}
228
230 msgpack::MapDocNode Kern) {
231 // TODO: What about other languages?
232 auto *Node = Func.getParent()->getNamedMetadata("opencl.ocl.version");
233 if (!Node || !Node->getNumOperands())
234 return;
235 auto *Op0 = Node->getOperand(0);
236 if (Op0->getNumOperands() <= 1)
237 return;
238
239 Kern[".language"] = Kern.getDocument()->getNode("OpenCL C");
240 auto LanguageVersion = Kern.getDocument()->getArrayNode();
241 LanguageVersion.push_back(Kern.getDocument()->getNode(
242 mdconst::extract<ConstantInt>(Op0->getOperand(0))->getZExtValue()));
243 LanguageVersion.push_back(Kern.getDocument()->getNode(
244 mdconst::extract<ConstantInt>(Op0->getOperand(1))->getZExtValue()));
245 Kern[".language_version"] = LanguageVersion;
246}
247
249 const MachineFunction &MF,
250 msgpack::MapDocNode Kern) {
251 const Function &Func = MF.getFunction();
252 if (auto *Node = Func.getMetadata("reqd_work_group_size"))
253 Kern[".reqd_workgroup_size"] = getWorkGroupDimensions(Node);
254 if (auto *Node = Func.getMetadata("work_group_size_hint"))
255 Kern[".workgroup_size_hint"] = getWorkGroupDimensions(Node);
256 if (auto *Node = Func.getMetadata("vec_type_hint")) {
257 Kern[".vec_type_hint"] = Kern.getDocument()->getNode(
259 cast<ValueAsMetadata>(Node->getOperand(0))->getType(),
260 mdconst::extract<ConstantInt>(Node->getOperand(1))->getZExtValue()),
261 /*Copy=*/true);
262 }
263
264 std::string HandleName = getEnqueuedBlockSymbolName(TM, Func);
265 if (!HandleName.empty()) {
266 Kern[".device_enqueue_symbol"] =
267 Kern.getDocument()->getNode(std::move(HandleName), /*Copy=*/true);
268 }
269
270 if (Func.hasFnAttribute("device-init"))
271 Kern[".kind"] = Kern.getDocument()->getNode("init");
272 else if (Func.hasFnAttribute("device-fini"))
273 Kern[".kind"] = Kern.getDocument()->getNode("fini");
274}
275
277 msgpack::MapDocNode Kern) {
278 auto &Func = MF.getFunction();
279 unsigned Offset = 0;
280 auto Args = HSAMetadataDoc->getArrayNode();
281 for (auto &Arg : Func.args()) {
282 if (Arg.hasAttribute("amdgpu-hidden-argument"))
283 continue;
284
285 emitKernelArg(Arg, Offset, Args);
286 }
287
288 emitHiddenKernelArgs(MF, Offset, Args);
289
290 Kern[".args"] = Args;
291}
292
294 unsigned &Offset,
296 const auto *Func = Arg.getParent();
297 auto ArgNo = Arg.getArgNo();
298 const MDNode *Node;
299
300 StringRef Name;
301 Node = Func->getMetadata("kernel_arg_name");
302 if (Node && ArgNo < Node->getNumOperands())
303 Name = cast<MDString>(Node->getOperand(ArgNo))->getString();
304 else if (Arg.hasName())
305 Name = Arg.getName();
306
307 StringRef TypeName;
308 Node = Func->getMetadata("kernel_arg_type");
309 if (Node && ArgNo < Node->getNumOperands())
310 TypeName = cast<MDString>(Node->getOperand(ArgNo))->getString();
311
312 StringRef BaseTypeName;
313 Node = Func->getMetadata("kernel_arg_base_type");
314 if (Node && ArgNo < Node->getNumOperands())
315 BaseTypeName = cast<MDString>(Node->getOperand(ArgNo))->getString();
316
317 StringRef ActAccQual;
318 // Do we really need NoAlias check here?
319 if (Arg.getType()->isPointerTy() && Arg.hasNoAliasAttr()) {
320 if (Arg.onlyReadsMemory())
321 ActAccQual = "read_only";
322 else if (Arg.hasAttribute(Attribute::WriteOnly))
323 ActAccQual = "write_only";
324 }
325
326 StringRef AccQual;
327 Node = Func->getMetadata("kernel_arg_access_qual");
328 if (Node && ArgNo < Node->getNumOperands())
329 AccQual = cast<MDString>(Node->getOperand(ArgNo))->getString();
330
331 StringRef TypeQual;
332 Node = Func->getMetadata("kernel_arg_type_qual");
333 if (Node && ArgNo < Node->getNumOperands())
334 TypeQual = cast<MDString>(Node->getOperand(ArgNo))->getString();
335
336 const DataLayout &DL = Func->getDataLayout();
337
338 MaybeAlign PointeeAlign;
339 Type *Ty = Arg.hasByRefAttr() ? Arg.getParamByRefType() : Arg.getType();
340
341 // FIXME: Need to distinguish in memory alignment from pointer alignment.
342 if (auto *PtrTy = dyn_cast<PointerType>(Ty)) {
343 if (PtrTy->getAddressSpace() == AMDGPUAS::LOCAL_ADDRESS)
344 PointeeAlign = Arg.getParamAlign().valueOrOne();
345 }
346
347 // There's no distinction between byval aggregates and raw aggregates.
348 Type *ArgTy;
349 Align ArgAlign;
350 std::tie(ArgTy, ArgAlign) = getArgumentTypeAlign(Arg, DL);
351
352 emitKernelArg(DL, ArgTy, ArgAlign,
353 getValueKind(ArgTy, TypeQual, BaseTypeName), Offset, Args,
354 PointeeAlign, Name, TypeName, BaseTypeName, ActAccQual,
355 AccQual, TypeQual);
356}
357
359 const DataLayout &DL, Type *Ty, Align Alignment, StringRef ValueKind,
360 unsigned &Offset, msgpack::ArrayDocNode Args, MaybeAlign PointeeAlign,
361 StringRef Name, StringRef TypeName, StringRef BaseTypeName,
362 StringRef ActAccQual, StringRef AccQual, StringRef TypeQual) {
363 auto Arg = Args.getDocument()->getMapNode();
364
365 if (!Name.empty())
366 Arg[".name"] = Arg.getDocument()->getNode(Name, /*Copy=*/true);
367 if (!TypeName.empty())
368 Arg[".type_name"] = Arg.getDocument()->getNode(TypeName, /*Copy=*/true);
369 auto Size = DL.getTypeAllocSize(Ty);
370 Arg[".size"] = Arg.getDocument()->getNode(Size);
371 Offset = alignTo(Offset, Alignment);
372 Arg[".offset"] = Arg.getDocument()->getNode(Offset);
373 Offset += Size;
374 Arg[".value_kind"] = Arg.getDocument()->getNode(ValueKind, /*Copy=*/true);
375 if (PointeeAlign)
376 Arg[".pointee_align"] = Arg.getDocument()->getNode(PointeeAlign->value());
377
378 if (auto *PtrTy = dyn_cast<PointerType>(Ty))
379 if (auto Qualifier = getAddressSpaceQualifier(PtrTy->getAddressSpace()))
380 // Limiting address space to emit only for a certain ValueKind.
381 if (ValueKind == "global_buffer" || ValueKind == "dynamic_shared_pointer")
382 Arg[".address_space"] = Arg.getDocument()->getNode(*Qualifier,
383 /*Copy=*/true);
384
385 if (auto AQ = getAccessQualifier(AccQual))
386 Arg[".access"] = Arg.getDocument()->getNode(*AQ, /*Copy=*/true);
387
388 if (auto AAQ = getAccessQualifier(ActAccQual))
389 Arg[".actual_access"] = Arg.getDocument()->getNode(*AAQ, /*Copy=*/true);
390
391 SmallVector<StringRef, 1> SplitTypeQuals;
392 TypeQual.split(SplitTypeQuals, " ", -1, false);
393 for (StringRef Key : SplitTypeQuals) {
394 if (Key == "const")
395 Arg[".is_const"] = Arg.getDocument()->getNode(true);
396 else if (Key == "restrict")
397 Arg[".is_restrict"] = Arg.getDocument()->getNode(true);
398 else if (Key == "volatile")
399 Arg[".is_volatile"] = Arg.getDocument()->getNode(true);
400 else if (Key == "pipe")
401 Arg[".is_pipe"] = Arg.getDocument()->getNode(true);
402 }
403
404 Args.push_back(Arg);
405}
406
408 const MachineFunction &MF, unsigned &Offset, msgpack::ArrayDocNode Args) {
409 auto &Func = MF.getFunction();
410 const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
411
412 unsigned HiddenArgNumBytes = ST.getImplicitArgNumBytes(Func);
413 if (!HiddenArgNumBytes)
414 return;
415
416 const Module *M = Func.getParent();
417 auto &DL = M->getDataLayout();
418 auto *Int64Ty = Type::getInt64Ty(Func.getContext());
419
420 Offset = alignTo(Offset, ST.getAlignmentForImplicitArgPtr());
421
422 if (HiddenArgNumBytes >= 8)
423 emitKernelArg(DL, Int64Ty, Align(8), "hidden_global_offset_x", Offset,
424 Args);
425 if (HiddenArgNumBytes >= 16)
426 emitKernelArg(DL, Int64Ty, Align(8), "hidden_global_offset_y", Offset,
427 Args);
428 if (HiddenArgNumBytes >= 24)
429 emitKernelArg(DL, Int64Ty, Align(8), "hidden_global_offset_z", Offset,
430 Args);
431
432 auto *Int8PtrTy =
433 PointerType::get(Func.getContext(), AMDGPUAS::GLOBAL_ADDRESS);
434
435 if (HiddenArgNumBytes >= 32) {
436 // We forbid the use of features requiring hostcall when compiling OpenCL
437 // before code object V5, which makes the mutual exclusion between the
438 // "printf buffer" and "hostcall buffer" here sound.
439 if (M->getNamedMetadata("llvm.printf.fmts"))
440 emitKernelArg(DL, Int8PtrTy, Align(8), "hidden_printf_buffer", Offset,
441 Args);
442 else if (!Func.hasFnAttribute("amdgpu-no-hostcall-ptr"))
443 emitKernelArg(DL, Int8PtrTy, Align(8), "hidden_hostcall_buffer", Offset,
444 Args);
445 else
446 emitKernelArg(DL, Int8PtrTy, Align(8), "hidden_none", Offset, Args);
447 }
448
449 // Emit "default queue" and "completion action" arguments if enqueue kernel is
450 // used, otherwise emit dummy "none" arguments.
451 if (HiddenArgNumBytes >= 40) {
452 if (!Func.hasFnAttribute("amdgpu-no-default-queue")) {
453 emitKernelArg(DL, Int8PtrTy, Align(8), "hidden_default_queue", Offset,
454 Args);
455 } else {
456 emitKernelArg(DL, Int8PtrTy, Align(8), "hidden_none", Offset, Args);
457 }
458 }
459
460 if (HiddenArgNumBytes >= 48) {
461 if (!Func.hasFnAttribute("amdgpu-no-completion-action")) {
462 emitKernelArg(DL, Int8PtrTy, Align(8), "hidden_completion_action", Offset,
463 Args);
464 } else {
465 emitKernelArg(DL, Int8PtrTy, Align(8), "hidden_none", Offset, Args);
466 }
467 }
468
469 // Emit the pointer argument for multi-grid object.
470 if (HiddenArgNumBytes >= 56) {
471 if (!Func.hasFnAttribute("amdgpu-no-multigrid-sync-arg")) {
472 emitKernelArg(DL, Int8PtrTy, Align(8), "hidden_multigrid_sync_arg", Offset,
473 Args);
474 } else {
475 emitKernelArg(DL, Int8PtrTy, Align(8), "hidden_none", Offset, Args);
476 }
477 }
478}
479
482 const SIProgramInfo &ProgramInfo,
483 unsigned CodeObjectVersion) const {
484 const GCNSubtarget &STM = MF.getSubtarget<GCNSubtarget>();
486 const Function &F = MF.getFunction();
487
488 auto Kern = HSAMetadataDoc->getMapNode();
489
490 Align MaxKernArgAlign;
491 Kern[".kernarg_segment_size"] = Kern.getDocument()->getNode(
492 STM.getKernArgSegmentSize(F, MaxKernArgAlign));
493 Kern[".group_segment_fixed_size"] =
494 Kern.getDocument()->getNode(ProgramInfo.LDSSize);
495 DelayedExprs->assignDocNode(Kern[".private_segment_fixed_size"],
496 msgpack::Type::UInt, ProgramInfo.ScratchSize);
497 if (CodeObjectVersion >= AMDGPU::AMDHSA_COV5) {
498 DelayedExprs->assignDocNode(Kern[".uses_dynamic_stack"],
500 ProgramInfo.DynamicCallStack);
501 }
502
503 if (CodeObjectVersion >= AMDGPU::AMDHSA_COV5 && STM.hasSupportsWGP())
504 Kern[".workgroup_processor_mode"] =
505 Kern.getDocument()->getNode(ProgramInfo.WgpMode);
506
507 // FIXME: The metadata treats the minimum as 16?
508 Kern[".kernarg_segment_align"] =
509 Kern.getDocument()->getNode(std::max(Align(4), MaxKernArgAlign).value());
510 Kern[".wavefront_size"] =
511 Kern.getDocument()->getNode(STM.getWavefrontSize());
512 DelayedExprs->assignDocNode(Kern[".sgpr_count"], msgpack::Type::UInt,
513 ProgramInfo.NumSGPR);
514 DelayedExprs->assignDocNode(Kern[".vgpr_count"], msgpack::Type::UInt,
515 ProgramInfo.NumVGPR);
516
517 // Only add AGPR count to metadata for supported devices
518 if (STM.hasMAIInsts()) {
519 DelayedExprs->assignDocNode(Kern[".agpr_count"], msgpack::Type::UInt,
520 ProgramInfo.NumAccVGPR);
521 }
522
523 Kern[".max_flat_workgroup_size"] =
524 Kern.getDocument()->getNode(MFI.getMaxFlatWorkGroupSize());
525
526 uint32_t NumWGY = MFI.getMaxNumWorkGroupsY();
527 uint32_t NumWGZ = MFI.getMaxNumWorkGroupsZ();
528 uint32_t NumWGX = MFI.getMaxNumWorkGroupsX();
529
530 // TODO: Should consider 0 invalid and reject in IR verifier.
531 if (NumWGX != std::numeric_limits<uint32_t>::max() && NumWGX != 0)
532 Kern[".max_num_workgroups_x"] = Kern.getDocument()->getNode(NumWGX);
533
534 if (NumWGY != std::numeric_limits<uint32_t>::max() && NumWGY != 0)
535 Kern[".max_num_workgroups_y"] = Kern.getDocument()->getNode(NumWGY);
536
537 if (NumWGZ != std::numeric_limits<uint32_t>::max() && NumWGZ != 0)
538 Kern[".max_num_workgroups_z"] = Kern.getDocument()->getNode(NumWGZ);
539
540 Kern[".sgpr_spill_count"] =
541 Kern.getDocument()->getNode(MFI.getNumSpilledSGPRs());
542 Kern[".vgpr_spill_count"] =
543 Kern.getDocument()->getNode(MFI.getNumSpilledVGPRs());
544
545 return Kern;
546}
547
549 DelayedExprs->resolveDelayedExpressions();
550 return TargetStreamer.EmitHSAMetadata(*HSAMetadataDoc, true);
551}
552
554 const TargetID &TargetID) {
555 emitVersion();
558 getRootMetadata("amdhsa.kernels") = HSAMetadataDoc->getArrayNode();
559 DelayedExprs->clear();
560}
561
563 DelayedExprs->resolveDelayedExpressions();
564 std::string HSAMetadataString;
565 raw_string_ostream StrOS(HSAMetadataString);
566 HSAMetadataDoc->toYAML(StrOS);
567
568 if (CLOpts.dump_hsa_metadata)
569 dump(StrOS.str());
570 if (CLOpts.verify_hsa_metadata)
571 verify(StrOS.str());
572}
573
575 const SIProgramInfo &ProgramInfo) {
576 auto &Func = MF.getFunction();
577 if (Func.getCallingConv() != CallingConv::AMDGPU_KERNEL &&
578 Func.getCallingConv() != CallingConv::SPIR_KERNEL)
579 return;
580
581 auto CodeObjectVersion =
582 AMDGPU::getAMDHSACodeObjectVersion(*Func.getParent());
583 auto Kern = getHSAKernelProps(MF, ProgramInfo, CodeObjectVersion);
584
585 auto Kernels =
586 getRootMetadata("amdhsa.kernels").getArray(/*Convert=*/true);
587
588 auto &TM = static_cast<const AMDGPUTargetMachine &>(MF.getTarget());
589 {
590 Kern[".name"] = Kern.getDocument()->getNode(Func.getName());
591 Kern[".symbol"] = Kern.getDocument()->getNode(
592 (Twine(Func.getName()) + Twine(".kd")).str(), /*Copy=*/true);
593 emitKernelLanguage(Func, Kern);
594 emitKernelAttrs(TM, MF, Kern);
595 emitKernelArgs(MF, Kern);
596 }
597
598 Kernels.push_back(Kern);
599}
600
601//===----------------------------------------------------------------------===//
602// HSAMetadataStreamerV5
603//===----------------------------------------------------------------------===//
604
606 auto Version = HSAMetadataDoc->getArrayNode();
607 Version.push_back(Version.getDocument()->getNode(VersionMajorV5));
608 Version.push_back(Version.getDocument()->getNode(VersionMinorV5));
609 getRootMetadata("amdhsa.version") = Version;
610}
611
613 const MachineFunction &MF, unsigned &Offset, msgpack::ArrayDocNode Args) {
614 auto &Func = MF.getFunction();
615 const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
616
617 // No implicit kernel argument is used.
618 if (ST.getImplicitArgNumBytes(Func) == 0)
619 return;
620
621 const Module *M = Func.getParent();
622 auto &DL = M->getDataLayout();
624
625 auto *Int64Ty = Type::getInt64Ty(Func.getContext());
626 auto *Int32Ty = Type::getInt32Ty(Func.getContext());
627 auto *Int16Ty = Type::getInt16Ty(Func.getContext());
628
629 Offset = alignTo(Offset, ST.getAlignmentForImplicitArgPtr());
630 emitKernelArg(DL, Int32Ty, Align(4), "hidden_block_count_x", Offset, Args);
631 emitKernelArg(DL, Int32Ty, Align(4), "hidden_block_count_y", Offset, Args);
632 emitKernelArg(DL, Int32Ty, Align(4), "hidden_block_count_z", Offset, Args);
633
634 emitKernelArg(DL, Int16Ty, Align(2), "hidden_group_size_x", Offset, Args);
635 emitKernelArg(DL, Int16Ty, Align(2), "hidden_group_size_y", Offset, Args);
636 emitKernelArg(DL, Int16Ty, Align(2), "hidden_group_size_z", Offset, Args);
637
638 emitKernelArg(DL, Int16Ty, Align(2), "hidden_remainder_x", Offset, Args);
639 emitKernelArg(DL, Int16Ty, Align(2), "hidden_remainder_y", Offset, Args);
640 emitKernelArg(DL, Int16Ty, Align(2), "hidden_remainder_z", Offset, Args);
641
642 // Reserved for hidden_tool_correlation_id.
643 Offset += 8;
644
645 Offset += 8; // Reserved.
646
647 emitKernelArg(DL, Int64Ty, Align(8), "hidden_global_offset_x", Offset, Args);
648 emitKernelArg(DL, Int64Ty, Align(8), "hidden_global_offset_y", Offset, Args);
649 emitKernelArg(DL, Int64Ty, Align(8), "hidden_global_offset_z", Offset, Args);
650
651 emitKernelArg(DL, Int16Ty, Align(2), "hidden_grid_dims", Offset, Args);
652
653 Offset += 6; // Reserved.
654 auto *Int8PtrTy =
655 PointerType::get(Func.getContext(), AMDGPUAS::GLOBAL_ADDRESS);
656
657 if (M->getNamedMetadata("llvm.printf.fmts")) {
658 emitKernelArg(DL, Int8PtrTy, Align(8), "hidden_printf_buffer", Offset,
659 Args);
660 } else {
661 Offset += 8; // Skipped.
662 }
663
664 if (!Func.hasFnAttribute("amdgpu-no-hostcall-ptr")) {
665 emitKernelArg(DL, Int8PtrTy, Align(8), "hidden_hostcall_buffer", Offset,
666 Args);
667 } else {
668 Offset += 8; // Skipped.
669 }
670
671 if (!Func.hasFnAttribute("amdgpu-no-multigrid-sync-arg")) {
672 emitKernelArg(DL, Int8PtrTy, Align(8), "hidden_multigrid_sync_arg", Offset,
673 Args);
674 } else {
675 Offset += 8; // Skipped.
676 }
677
678 if (!Func.hasFnAttribute("amdgpu-no-heap-ptr"))
679 emitKernelArg(DL, Int8PtrTy, Align(8), "hidden_heap_v1", Offset, Args);
680 else
681 Offset += 8; // Skipped.
682
683 if (!Func.hasFnAttribute("amdgpu-no-default-queue")) {
684 emitKernelArg(DL, Int8PtrTy, Align(8), "hidden_default_queue", Offset,
685 Args);
686 } else {
687 Offset += 8; // Skipped.
688 }
689
690 if (!Func.hasFnAttribute("amdgpu-no-completion-action")) {
691 emitKernelArg(DL, Int8PtrTy, Align(8), "hidden_completion_action", Offset,
692 Args);
693 } else {
694 Offset += 8; // Skipped.
695 }
696
697 // Emit argument for hidden dynamic lds size
698 if (MFI.isDynamicLDSUsed()) {
699 emitKernelArg(DL, Int32Ty, Align(4), "hidden_dynamic_lds_size", Offset,
700 Args);
701 } else {
702 Offset += 4; // skipped
703 }
704
705 Offset += 68; // Reserved.
706
707 // hidden_private_base and hidden_shared_base are only when the subtarget has
708 // ApertureRegs.
709 if (!ST.hasApertureRegs()) {
710 emitKernelArg(DL, Int32Ty, Align(4), "hidden_private_base", Offset, Args);
711 emitKernelArg(DL, Int32Ty, Align(4), "hidden_shared_base", Offset, Args);
712 } else {
713 Offset += 8; // Skipped.
714 }
715
716 if (MFI.getUserSGPRInfo().hasQueuePtr())
717 emitKernelArg(DL, Int8PtrTy, Align(8), "hidden_queue_ptr", Offset, Args);
718}
719
721 const MachineFunction &MF,
722 msgpack::MapDocNode Kern) {
724
725 const Function &Func = MF.getFunction();
726 if (Func.hasFnAttribute("uniform-work-group-size"))
727 Kern[".uniform_work_group_size"] = Kern.getDocument()->getNode(1);
728}
729
730//===----------------------------------------------------------------------===//
731// HSAMetadataStreamerV6
732//===----------------------------------------------------------------------===//
733
735 auto Version = HSAMetadataDoc->getArrayNode();
736 Version.push_back(Version.getDocument()->getNode(VersionMajorV6));
737 Version.push_back(Version.getDocument()->getNode(VersionMinorV6));
738 getRootMetadata("amdhsa.version") = Version;
739}
740
742 const MachineFunction &MF,
743 msgpack::MapDocNode Kern) {
745
747 ClusterDimsAttr Attr = MFI.getClusterDims();
748 if (Attr.isFixedDims()) {
749 msgpack::ArrayDocNode ClusterDimsNode = HSAMetadataDoc->getArrayNode();
750 ClusterDimsNode.push_back(HSAMetadataDoc->getNode(Attr.getDims()[0]));
751 ClusterDimsNode.push_back(HSAMetadataDoc->getNode(Attr.getDims()[1]));
752 ClusterDimsNode.push_back(HSAMetadataDoc->getNode(Attr.getDims()[2]));
753 Kern[".cluster_dims"] = ClusterDimsNode;
754 }
755}
756
757} // end namespace AMDGPU::HSAMD
758} // end namespace llvm
static std::string getEnqueuedBlockSymbolName(const AMDGPUTargetMachine &TM, const Function &EnqueuedBlock)
Find the mangled symbol name for the runtime handle for EnqueuedBlock.
static std::pair< Type *, Align > getArgumentTypeAlign(const Argument &Arg, const DataLayout &DL)
AMDGPU HSA Metadata Streamer.
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
AMD GCN specific subclass of TargetSubtarget.
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition MD5.cpp:54
ppc ctr loops verify
Defines struct to track resource usage and hardware flags for kernels and entry functions.
unsigned getKernArgSegmentSize(const Function &F, Align &MaxAlign) const
unsigned getWavefrontSize() const
TargetLoweringObjectFile * getObjFileLowering() const override
virtual bool EmitHSAMetadata(msgpack::Document &HSAMetadata, bool Strict)
Emit HSA Metadata.
std::optional< StringRef > getAddressSpaceQualifier(unsigned AddressSpace) const
msgpack::ArrayDocNode getWorkGroupDimensions(MDNode *Node) const
std::optional< StringRef > getAccessQualifier(StringRef AccQual) const
void emitKernelLanguage(const Function &Func, msgpack::MapDocNode Kern)
msgpack::MapDocNode getHSAKernelProps(const MachineFunction &MF, const SIProgramInfo &ProgramInfo, unsigned CodeObjectVersion) const
std::unique_ptr< msgpack::Document > HSAMetadataDoc
bool emitTo(AMDGPUTargetStreamer &TargetStreamer) override
void emitKernelArgs(const MachineFunction &MF, msgpack::MapDocNode Kern)
std::string getTypeName(Type *Ty, bool Signed) const
void emitKernelArg(const Argument &Arg, unsigned &Offset, msgpack::ArrayDocNode Args)
void emitKernelAttrs(const AMDGPUTargetMachine &TM, const MachineFunction &MF, msgpack::MapDocNode Kern) override
void begin(const Module &Mod, const TargetID &TargetID) override
StringRef getValueKind(Type *Ty, StringRef TypeQual, StringRef BaseTypeName) const
void emitHiddenKernelArgs(const MachineFunction &MF, unsigned &Offset, msgpack::ArrayDocNode Args) override
void emitKernel(const MachineFunction &MF, const SIProgramInfo &ProgramInfo) override
void emitHiddenKernelArgs(const MachineFunction &MF, unsigned &Offset, msgpack::ArrayDocNode Args) override
void emitKernelAttrs(const AMDGPUTargetMachine &TM, const MachineFunction &MF, msgpack::MapDocNode Kern) override
void emitKernelAttrs(const AMDGPUTargetMachine &TM, const MachineFunction &MF, msgpack::MapDocNode Kern) override
std::string toString() const
This class represents an incoming formal argument to a Function.
Definition Argument.h:32
LLVM_ABI Type * getParamByRefType() const
If this is a byref argument, return its type.
Definition Function.cpp:228
LLVM_ABI bool hasNoAliasAttr() const
Return true if this argument has the noalias attribute.
Definition Function.cpp:266
LLVM_ABI bool hasByRefAttr() const
Return true if this argument has the byref attribute.
Definition Function.cpp:136
LLVM_ABI bool onlyReadsMemory() const
Return true if this argument has the readonly or readnone attribute.
Definition Function.cpp:302
LLVM_ABI bool hasAttribute(Attribute::AttrKind Kind) const
Check if an argument has a given attribute.
Definition Function.cpp:332
const Function * getParent() const
Definition Argument.h:44
unsigned getArgNo() const
Return the index of this formal argument in its containing function.
Definition Argument.h:50
LLVM_ABI MaybeAlign getParamAlign() const
If this is a byval or inalloca argument, return its alignment.
Definition Function.cpp:209
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
MDNode * getMetadata(unsigned KindID) const
Get the metadata of given kind attached to this GlobalObject.
Metadata node.
Definition Metadata.h:1081
const MDOperand & getOperand(unsigned I) const
Definition Metadata.h:1437
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Function & getFunction()
Return the LLVM function that this machine code represents.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
static LLVM_ABI PointerType * get(LLVMContext &C, unsigned AddressSpace)
This constructs an opaque pointer to an object in a numbered address space.
Definition Type.cpp:887
This class keeps track of the SPI_SP_INPUT_ADDR config register, which tells the hardware which inter...
GCNUserSGPRUsageInfo & getUserSGPRInfo()
AMDGPU::ClusterDimsAttr getClusterDims() const
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition SmallString.h:28
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
Definition StringRef.h:736
bool contains(StringRef Other) const
Return true if the given string is a substring of *this, and false otherwise.
Definition StringRef.h:446
A switch()-like statement whose cases are string literals.
StringSwitch & Case(StringLiteral S, T Value)
void getNameWithPrefix(SmallVectorImpl< char > &Name, const GlobalValue *GV, Mangler &Mang, bool MayAlwaysUsePrivate=false) const
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
static LLVM_ABI IntegerType * getInt64Ty(LLVMContext &C)
Definition Type.cpp:300
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
Definition Type.cpp:299
bool isPointerTy() const
True if this is an instance of PointerType.
Definition Type.h:277
@ HalfTyID
16-bit floating point type
Definition Type.h:57
@ FloatTyID
32-bit floating point type
Definition Type.h:59
@ IntegerTyID
Arbitrary bit width integers.
Definition Type.h:71
@ FixedVectorTyID
Fixed width SIMD vector type.
Definition Type.h:77
@ DoubleTyID
64-bit floating point type
Definition Type.h:60
static LLVM_ABI IntegerType * getInt16Ty(LLVMContext &C)
Definition Type.cpp:298
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:257
bool hasName() const
Definition Value.h:263
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:314
A DocNode that is an array.
ArrayDocNode & getArray(bool Convert=false)
Get an ArrayDocNode for an array node.
Document * getDocument() const
Simple in-memory representation of a document of msgpack objects with ability to find and create arra...
DocNode getNode()
Create a nil node associated with this Document.
ArrayDocNode getArrayNode()
Create an empty Array node associated with this Document.
LLVM_ABI void toYAML(raw_ostream &OS)
Convert MsgPack Document to YAML text.
LLVM_ABI bool fromYAML(StringRef S)
Read YAML text into the MsgPack document. Returns false on failure.
A DocNode that is a map.
A raw_ostream that writes to an std::string.
std::string & str()
Returns the string's reference.
@ REGION_ADDRESS
Address space for region memory. (GDS)
@ LOCAL_ADDRESS
Address space for local memory.
@ CONSTANT_ADDRESS
Address space for constant memory (VTX2).
@ FLAT_ADDRESS
Address space for flat memory.
@ GLOBAL_ADDRESS
Address space for global memory (RAT0, VTX0).
@ PRIVATE_ADDRESS
Address space for private memory.
constexpr uint32_t VersionMajorV5
HSA metadata major version for code object V5.
constexpr uint32_t VersionMinorV4
HSA metadata minor version for code object V4.
constexpr uint32_t VersionMinorV5
HSA metadata minor version for code object V5.
constexpr uint32_t VersionMinorV6
HSA metadata minor version for code object V6.
constexpr uint32_t VersionMajorV6
HSA metadata major version for code object V6.
constexpr uint32_t VersionMajorV4
HSA metadata major version for code object V4.
unsigned getAMDHSACodeObjectVersion(const Module &M)
@ AMDGPU_KERNEL
Used for AMDGPU code object kernels.
@ SPIR_KERNEL
Used for SPIR kernel functions.
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > extract(Y &&MD)
Extract a Value from Metadata.
Definition Metadata.h:679
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:577
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
LLVM_GET_TYPE_NAME_CONSTEXPR StringRef getTypeName()
We provide a function which tries to compute the (demangled) name of a type statically.
Definition TypeName.h:42
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition Alignment.h:149
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
@ Mod
The access may modify the value stored in memory.
Definition ModRef.h:34
DWARFExpression::Operation Op
constexpr unsigned BitWidth
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
This struct is a compact representation of a valid (power of two) or undefined (0) alignment.
Definition Alignment.h:111
Align valueOrOne() const
For convenience, returns a valid alignment or 1 if undefined.
Definition Alignment.h:135
Track resource usage for kernels / entry functions.
const MCExpr * NumSGPR
const MCExpr * NumAccVGPR
const MCExpr * DynamicCallStack
const MCExpr * NumVGPR
const MCExpr * ScratchSize