LLVM  7.0.0svn
AMDGPUHSAMetadataStreamer.cpp
Go to the documentation of this file.
1 //===--- AMDGPUHSAMetadataStreamer.cpp --------------------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 /// \file
11 /// AMDGPU HSA Metadata Streamer.
12 ///
13 //
14 //===----------------------------------------------------------------------===//
15 
17 #include "AMDGPU.h"
18 #include "AMDGPUSubtarget.h"
19 #include "SIMachineFunctionInfo.h"
20 #include "SIProgramInfo.h"
21 #include "Utils/AMDGPUBaseInfo.h"
22 #include "llvm/ADT/StringSwitch.h"
23 #include "llvm/IR/Constants.h"
24 #include "llvm/IR/Module.h"
26 
27 namespace llvm {
28 
29 static cl::opt<bool> DumpHSAMetadata(
30  "amdgpu-dump-hsa-metadata",
31  cl::desc("Dump AMDGPU HSA Metadata"));
32 static cl::opt<bool> VerifyHSAMetadata(
33  "amdgpu-verify-hsa-metadata",
34  cl::desc("Verify AMDGPU HSA Metadata"));
35 
36 namespace AMDGPU {
37 namespace HSAMD {
38 
39 void MetadataStreamer::dump(StringRef HSAMetadataString) const {
40  errs() << "AMDGPU HSA Metadata:\n" << HSAMetadataString << '\n';
41 }
42 
43 void MetadataStreamer::verify(StringRef HSAMetadataString) const {
44  errs() << "AMDGPU HSA Metadata Parser Test: ";
45 
46  HSAMD::Metadata FromHSAMetadataString;
47  if (fromString(HSAMetadataString, FromHSAMetadataString)) {
48  errs() << "FAIL\n";
49  return;
50  }
51 
52  std::string ToHSAMetadataString;
53  if (toString(FromHSAMetadataString, ToHSAMetadataString)) {
54  errs() << "FAIL\n";
55  return;
56  }
57 
58  errs() << (HSAMetadataString == ToHSAMetadataString ? "PASS" : "FAIL")
59  << '\n';
60  if (HSAMetadataString != ToHSAMetadataString) {
61  errs() << "Original input: " << HSAMetadataString << '\n'
62  << "Produced output: " << ToHSAMetadataString << '\n';
63  }
64 }
65 
66 AccessQualifier MetadataStreamer::getAccessQualifier(StringRef AccQual) const {
67  if (AccQual.empty())
69 
70  return StringSwitch<AccessQualifier>(AccQual)
71  .Case("read_only", AccessQualifier::ReadOnly)
72  .Case("write_only", AccessQualifier::WriteOnly)
73  .Case("read_write", AccessQualifier::ReadWrite)
74  .Default(AccessQualifier::Default);
75 }
76 
77 AddressSpaceQualifier MetadataStreamer::getAddressSpaceQualifer(
78  unsigned AddressSpace) const {
79  if (AddressSpace == AMDGPUASI.PRIVATE_ADDRESS)
81  if (AddressSpace == AMDGPUASI.GLOBAL_ADDRESS)
83  if (AddressSpace == AMDGPUASI.CONSTANT_ADDRESS)
85  if (AddressSpace == AMDGPUASI.LOCAL_ADDRESS)
87  if (AddressSpace == AMDGPUASI.FLAT_ADDRESS)
89  if (AddressSpace == AMDGPUASI.REGION_ADDRESS)
91 
92  llvm_unreachable("Unknown address space qualifier");
93 }
94 
95 ValueKind MetadataStreamer::getValueKind(Type *Ty, StringRef TypeQual,
96  StringRef BaseTypeName) const {
97  if (TypeQual.find("pipe") != StringRef::npos)
98  return ValueKind::Pipe;
99 
100  return StringSwitch<ValueKind>(BaseTypeName)
101  .Case("image1d_t", ValueKind::Image)
102  .Case("image1d_array_t", ValueKind::Image)
103  .Case("image1d_buffer_t", ValueKind::Image)
104  .Case("image2d_t", ValueKind::Image)
105  .Case("image2d_array_t", ValueKind::Image)
106  .Case("image2d_array_depth_t", ValueKind::Image)
107  .Case("image2d_array_msaa_t", ValueKind::Image)
108  .Case("image2d_array_msaa_depth_t", ValueKind::Image)
109  .Case("image2d_depth_t", ValueKind::Image)
110  .Case("image2d_msaa_t", ValueKind::Image)
111  .Case("image2d_msaa_depth_t", ValueKind::Image)
112  .Case("image3d_t", ValueKind::Image)
113  .Case("sampler_t", ValueKind::Sampler)
114  .Case("queue_t", ValueKind::Queue)
115  .Default(isa<PointerType>(Ty) ?
116  (Ty->getPointerAddressSpace() ==
117  AMDGPUASI.LOCAL_ADDRESS ?
121 }
122 
123 ValueType MetadataStreamer::getValueType(Type *Ty, StringRef TypeName) const {
124  switch (Ty->getTypeID()) {
125  case Type::IntegerTyID: {
126  auto Signed = !TypeName.startswith("u");
127  switch (Ty->getIntegerBitWidth()) {
128  case 8:
130  case 16:
132  case 32:
134  case 64:
136  default:
137  return ValueType::Struct;
138  }
139  }
140  case Type::HalfTyID:
141  return ValueType::F16;
142  case Type::FloatTyID:
143  return ValueType::F32;
144  case Type::DoubleTyID:
145  return ValueType::F64;
146  case Type::PointerTyID:
147  return getValueType(Ty->getPointerElementType(), TypeName);
148  case Type::VectorTyID:
149  return getValueType(Ty->getVectorElementType(), TypeName);
150  default:
151  return ValueType::Struct;
152  }
153 }
154 
155 std::string MetadataStreamer::getTypeName(Type *Ty, 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";
181  case Type::VectorTyID: {
182  auto VecTy = cast<VectorType>(Ty);
183  auto ElTy = VecTy->getElementType();
184  auto NumElements = VecTy->getVectorNumElements();
185  return (Twine(getTypeName(ElTy, Signed)) + Twine(NumElements)).str();
186  }
187  default:
188  return "unknown";
189  }
190 }
191 
192 std::vector<uint32_t> MetadataStreamer::getWorkGroupDimensions(
193  MDNode *Node) const {
194  std::vector<uint32_t> Dims;
195  if (Node->getNumOperands() != 3)
196  return Dims;
197 
198  for (auto &Op : Node->operands())
199  Dims.push_back(mdconst::extract<ConstantInt>(Op)->getZExtValue());
200  return Dims;
201 }
202 
203 Kernel::CodeProps::Metadata MetadataStreamer::getHSACodeProps(
204  const MachineFunction &MF,
205  const SIProgramInfo &ProgramInfo) const {
206  const GCNSubtarget &STM = MF.getSubtarget<GCNSubtarget>();
207  const SIMachineFunctionInfo &MFI = *MF.getInfo<SIMachineFunctionInfo>();
209  const Function &F = MF.getFunction();
210 
211  // Avoid asserting on erroneous cases.
212  if (F.getCallingConv() != CallingConv::AMDGPU_KERNEL)
213  return HSACodeProps;
214 
215  HSACodeProps.mKernargSegmentSize =
216  STM.getKernArgSegmentSize(F, MFI.getExplicitKernArgSize());
217  HSACodeProps.mGroupSegmentFixedSize = ProgramInfo.LDSSize;
218  HSACodeProps.mPrivateSegmentFixedSize = ProgramInfo.ScratchSize;
219  HSACodeProps.mKernargSegmentAlign =
220  std::max(uint32_t(4), MFI.getMaxKernArgAlign());
221  HSACodeProps.mWavefrontSize = STM.getWavefrontSize();
222  HSACodeProps.mNumSGPRs = ProgramInfo.NumSGPR;
223  HSACodeProps.mNumVGPRs = ProgramInfo.NumVGPR;
224  HSACodeProps.mMaxFlatWorkGroupSize = MFI.getMaxFlatWorkGroupSize();
225  HSACodeProps.mIsDynamicCallStack = ProgramInfo.DynamicCallStack;
226  HSACodeProps.mIsXNACKEnabled = STM.isXNACKEnabled();
227  HSACodeProps.mNumSpilledSGPRs = MFI.getNumSpilledSGPRs();
228  HSACodeProps.mNumSpilledVGPRs = MFI.getNumSpilledVGPRs();
229 
230  return HSACodeProps;
231 }
232 
233 Kernel::DebugProps::Metadata MetadataStreamer::getHSADebugProps(
234  const MachineFunction &MF,
235  const SIProgramInfo &ProgramInfo) const {
236  const GCNSubtarget &STM = MF.getSubtarget<GCNSubtarget>();
238 
239  if (!STM.debuggerSupported())
240  return HSADebugProps;
241 
242  HSADebugProps.mDebuggerABIVersion.push_back(1);
243  HSADebugProps.mDebuggerABIVersion.push_back(0);
244 
245  if (STM.debuggerEmitPrologue()) {
246  HSADebugProps.mPrivateSegmentBufferSGPR =
247  ProgramInfo.DebuggerPrivateSegmentBufferSGPR;
248  HSADebugProps.mWavefrontPrivateSegmentOffsetSGPR =
249  ProgramInfo.DebuggerWavefrontPrivateSegmentOffsetSGPR;
250  }
251 
252  return HSADebugProps;
253 }
254 
255 void MetadataStreamer::emitVersion() {
256  auto &Version = HSAMetadata.mVersion;
257 
258  Version.push_back(VersionMajor);
259  Version.push_back(VersionMinor);
260 }
261 
262 void MetadataStreamer::emitPrintf(const Module &Mod) {
263  auto &Printf = HSAMetadata.mPrintf;
264 
265  auto Node = Mod.getNamedMetadata("llvm.printf.fmts");
266  if (!Node)
267  return;
268 
269  for (auto Op : Node->operands())
270  if (Op->getNumOperands())
271  Printf.push_back(cast<MDString>(Op->getOperand(0))->getString());
272 }
273 
274 void MetadataStreamer::emitKernelLanguage(const Function &Func) {
275  auto &Kernel = HSAMetadata.mKernels.back();
276 
277  // TODO: What about other languages?
278  auto Node = Func.getParent()->getNamedMetadata("opencl.ocl.version");
279  if (!Node || !Node->getNumOperands())
280  return;
281  auto Op0 = Node->getOperand(0);
282  if (Op0->getNumOperands() <= 1)
283  return;
284 
285  Kernel.mLanguage = "OpenCL C";
286  Kernel.mLanguageVersion.push_back(
287  mdconst::extract<ConstantInt>(Op0->getOperand(0))->getZExtValue());
288  Kernel.mLanguageVersion.push_back(
289  mdconst::extract<ConstantInt>(Op0->getOperand(1))->getZExtValue());
290 }
291 
292 void MetadataStreamer::emitKernelAttrs(const Function &Func) {
293  auto &Attrs = HSAMetadata.mKernels.back().mAttrs;
294 
295  if (auto Node = Func.getMetadata("reqd_work_group_size"))
296  Attrs.mReqdWorkGroupSize = getWorkGroupDimensions(Node);
297  if (auto Node = Func.getMetadata("work_group_size_hint"))
298  Attrs.mWorkGroupSizeHint = getWorkGroupDimensions(Node);
299  if (auto Node = Func.getMetadata("vec_type_hint")) {
300  Attrs.mVecTypeHint = getTypeName(
301  cast<ValueAsMetadata>(Node->getOperand(0))->getType(),
302  mdconst::extract<ConstantInt>(Node->getOperand(1))->getZExtValue());
303  }
304  if (Func.hasFnAttribute("runtime-handle")) {
305  Attrs.mRuntimeHandle =
306  Func.getFnAttribute("runtime-handle").getValueAsString().str();
307  }
308 }
309 
310 void MetadataStreamer::emitKernelArgs(const Function &Func) {
311  for (auto &Arg : Func.args())
312  emitKernelArg(Arg);
313 
314  emitHiddenKernelArgs(Func);
315 }
316 
317 void MetadataStreamer::emitKernelArg(const Argument &Arg) {
318  auto Func = Arg.getParent();
319  auto ArgNo = Arg.getArgNo();
320  const MDNode *Node;
321 
322  StringRef Name;
323  Node = Func->getMetadata("kernel_arg_name");
324  if (Node && ArgNo < Node->getNumOperands())
325  Name = cast<MDString>(Node->getOperand(ArgNo))->getString();
326  else if (Arg.hasName())
327  Name = Arg.getName();
328 
329  StringRef TypeName;
330  Node = Func->getMetadata("kernel_arg_type");
331  if (Node && ArgNo < Node->getNumOperands())
332  TypeName = cast<MDString>(Node->getOperand(ArgNo))->getString();
333 
334  StringRef BaseTypeName;
335  Node = Func->getMetadata("kernel_arg_base_type");
336  if (Node && ArgNo < Node->getNumOperands())
337  BaseTypeName = cast<MDString>(Node->getOperand(ArgNo))->getString();
338 
339  StringRef AccQual;
340  if (Arg.getType()->isPointerTy() && Arg.onlyReadsMemory() &&
341  Arg.hasNoAliasAttr()) {
342  AccQual = "read_only";
343  } else {
344  Node = Func->getMetadata("kernel_arg_access_qual");
345  if (Node && ArgNo < Node->getNumOperands())
346  AccQual = cast<MDString>(Node->getOperand(ArgNo))->getString();
347  }
348 
349  StringRef TypeQual;
350  Node = Func->getMetadata("kernel_arg_type_qual");
351  if (Node && ArgNo < Node->getNumOperands())
352  TypeQual = cast<MDString>(Node->getOperand(ArgNo))->getString();
353 
354  Type *Ty = Arg.getType();
355  const DataLayout &DL = Func->getParent()->getDataLayout();
356 
357  unsigned PointeeAlign = 0;
358  if (auto PtrTy = dyn_cast<PointerType>(Ty)) {
359  if (PtrTy->getAddressSpace() == AMDGPUASI.LOCAL_ADDRESS) {
360  PointeeAlign = Arg.getParamAlignment();
361  if (PointeeAlign == 0)
362  PointeeAlign = DL.getABITypeAlignment(PtrTy->getElementType());
363  }
364  }
365 
366  emitKernelArg(DL, Ty, getValueKind(Arg.getType(), TypeQual, BaseTypeName),
367  PointeeAlign, Name, TypeName, BaseTypeName, AccQual, TypeQual);
368 }
369 
370 void MetadataStreamer::emitKernelArg(const DataLayout &DL, Type *Ty,
372  unsigned PointeeAlign,
373  StringRef Name,
374  StringRef TypeName, StringRef BaseTypeName,
375  StringRef AccQual, StringRef TypeQual) {
376  HSAMetadata.mKernels.back().mArgs.push_back(Kernel::Arg::Metadata());
377  auto &Arg = HSAMetadata.mKernels.back().mArgs.back();
378 
379  Arg.mName = Name;
380  Arg.mTypeName = TypeName;
381  Arg.mSize = DL.getTypeAllocSize(Ty);
382  Arg.mAlign = DL.getABITypeAlignment(Ty);
383  Arg.mValueKind = ValueKind;
384  Arg.mValueType = getValueType(Ty, BaseTypeName);
385  Arg.mPointeeAlign = PointeeAlign;
386 
387  if (auto PtrTy = dyn_cast<PointerType>(Ty))
388  Arg.mAddrSpaceQual = getAddressSpaceQualifer(PtrTy->getAddressSpace());
389 
390  Arg.mAccQual = getAccessQualifier(AccQual);
391 
392  // TODO: Emit Arg.mActualAccQual.
393 
394  SmallVector<StringRef, 1> SplitTypeQuals;
395  TypeQual.split(SplitTypeQuals, " ", -1, false);
396  for (StringRef Key : SplitTypeQuals) {
397  auto P = StringSwitch<bool*>(Key)
398  .Case("const", &Arg.mIsConst)
399  .Case("restrict", &Arg.mIsRestrict)
400  .Case("volatile", &Arg.mIsVolatile)
401  .Case("pipe", &Arg.mIsPipe)
402  .Default(nullptr);
403  if (P)
404  *P = true;
405  }
406 }
407 
408 void MetadataStreamer::emitHiddenKernelArgs(const Function &Func) {
409  int HiddenArgNumBytes =
410  getIntegerAttribute(Func, "amdgpu-implicitarg-num-bytes", 0);
411 
412  if (!HiddenArgNumBytes)
413  return;
414 
415  auto &DL = Func.getParent()->getDataLayout();
416  auto Int64Ty = Type::getInt64Ty(Func.getContext());
417 
418  if (HiddenArgNumBytes >= 8)
419  emitKernelArg(DL, Int64Ty, ValueKind::HiddenGlobalOffsetX);
420  if (HiddenArgNumBytes >= 16)
421  emitKernelArg(DL, Int64Ty, ValueKind::HiddenGlobalOffsetY);
422  if (HiddenArgNumBytes >= 24)
423  emitKernelArg(DL, Int64Ty, ValueKind::HiddenGlobalOffsetZ);
424 
425  auto Int8PtrTy = Type::getInt8PtrTy(Func.getContext(),
426  AMDGPUASI.GLOBAL_ADDRESS);
427 
428  // Emit "printf buffer" argument if printf is used, otherwise emit dummy
429  // "none" argument.
430  if (HiddenArgNumBytes >= 32) {
431  if (Func.getParent()->getNamedMetadata("llvm.printf.fmts"))
432  emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenPrintfBuffer);
433  else
434  emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenNone);
435  }
436 
437  // Emit "default queue" and "completion action" arguments if enqueue kernel is
438  // used, otherwise emit dummy "none" arguments.
439  if (HiddenArgNumBytes >= 48) {
440  if (Func.hasFnAttribute("calls-enqueue-kernel")) {
441  emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenDefaultQueue);
442  emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenCompletionAction);
443  } else {
444  emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenNone);
445  emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenNone);
446  }
447  }
448 }
449 
450 void MetadataStreamer::begin(const Module &Mod) {
451  AMDGPUASI = getAMDGPUAS(Mod);
452  emitVersion();
453  emitPrintf(Mod);
454 }
455 
457  std::string HSAMetadataString;
458  if (toString(HSAMetadata, HSAMetadataString))
459  return;
460 
461  if (DumpHSAMetadata)
462  dump(HSAMetadataString);
463  if (VerifyHSAMetadata)
464  verify(HSAMetadataString);
465 }
466 
467 void MetadataStreamer::emitKernel(const MachineFunction &MF, const SIProgramInfo &ProgramInfo) {
468  auto &Func = MF.getFunction();
469  auto CodeProps = getHSACodeProps(MF, ProgramInfo);
470  auto DebugProps = getHSADebugProps(MF, ProgramInfo);
471 
472  if (Func.getCallingConv() != CallingConv::AMDGPU_KERNEL)
473  return;
474 
475  HSAMetadata.mKernels.push_back(Kernel::Metadata());
476  auto &Kernel = HSAMetadata.mKernels.back();
477 
478  Kernel.mName = Func.getName();
479  Kernel.mSymbolName = (Twine(Func.getName()) + Twine("@kd")).str();
480  emitKernelLanguage(Func);
481  emitKernelAttrs(Func);
482  emitKernelArgs(Func);
483  HSAMetadata.mKernels.back().mCodeProps = CodeProps;
484  HSAMetadata.mKernels.back().mDebugProps = DebugProps;
485 }
486 
487 } // end namespace HSAMD
488 } // end namespace AMDGPU
489 } // end namespace llvm
raw_ostream & errs()
This returns a reference to a raw_ostream for standard error.
GCNRegPressure max(const GCNRegPressure &P1, const GCNRegPressure &P2)
AMDGPU specific subclass of TargetSubtarget.
Compute iterated dominance frontiers using a linear time algorithm.
Definition: AllocatorList.h:24
A Module instance is used to store all the information related to an LLVM module. ...
Definition: Module.h:63
2: 32-bit floating point type
Definition: Type.h:59
void emitKernel(const MachineFunction &MF, const SIProgramInfo &ProgramInfo)
constexpr char PointeeAlign[]
Key for Kernel::Arg::Metadata::mPointeeAlign.
Address space for global memory (RAT0, VTX0).
Definition: AMDGPU.h:234
AMDGPUAS getAMDGPUAS(const Module &M)
Calling convention for AMDGPU code object kernels.
Definition: CallingConv.h:201
F(f)
1: 16-bit floating point type
Definition: Type.h:58
static IntegerType * getInt64Ty(LLVMContext &C)
Definition: Type.cpp:177
15: Pointers
Definition: Type.h:75
Track resource usage for kernels / entry functions.
Definition: SIProgramInfo.h:22
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
constexpr char Printf[]
Key for HSA::Metadata::mPrintf.
Defines struct to track resource usage for kernels and entry functions.
std::error_code fromString(std::string String, Metadata &HSAMetadata)
Converts String to HSAMetadata.
Key
PAL metadata keys.
static cl::opt< bool > VerifyHSAMetadata("amdgpu-verify-hsa-metadata", cl::desc("Verify AMDGPU HSA Metadata"))
constexpr char Attrs[]
Key for Kernel::Metadata::mAttrs.
AMDGPU HSA Metadata Streamer.
11: Arbitrary bit width integers
Definition: Type.h:71
#define P(N)
static cl::opt< bool > DumpHSAMetadata("amdgpu-dump-hsa-metadata", cl::desc("Dump AMDGPU HSA Metadata"))
In-memory representation of kernel metadata.
ValueKind
Value kinds.
This file contains the declarations for the subclasses of Constant, which represent the different fla...
std::vector< uint32_t > mVersion
HSA metadata version. Required.
constexpr char TypeName[]
Key for Kernel::Arg::Metadata::mTypeName.
unsigned REGION_ADDRESS
Address space for region memory.
Definition: AMDGPU.h:228
static wasm::ValType getType(const TargetRegisterClass *RC)
static PointerType * getInt8PtrTy(LLVMContext &C, unsigned AS=0)
Definition: Type.cpp:220
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
AccessQualifier
Access qualifiers.
std::vector< std::string > mPrintf
Printf metadata. Optional.
16: SIMD &#39;packed&#39; format, or other vector type
Definition: Type.h:76
Module.h This file contains the declarations for the Module class.
AddressSpace
Definition: NVPTXBaseInfo.h:22
constexpr char CodeProps[]
Key for Kernel::Metadata::mCodeProps.
ValueType
Value types.
const Function & getFunction() const
Return the LLVM function that this machine code represents.
constexpr uint32_t VersionMinor
HSA metadata minor version.
amdgpu Simplify well known AMD library false Value Value * Arg
std::error_code toString(Metadata HSAMetadata, std::string &String)
Converts HSAMetadata to String.
static const size_t npos
Definition: StringRef.h:51
constexpr char DebugProps[]
Key for Kernel::Metadata::mDebugProps.
AddressSpaceQualifier
Address space qualifiers.
unsigned FLAT_ADDRESS
Address space for flat memory.
Definition: AMDGPU.h:227
int getIntegerAttribute(const Function &F, StringRef Name, int Default)
constexpr char AccQual[]
Key for Kernel::Arg::Metadata::mAccQual.
3: 64-bit floating point type
Definition: Type.h:60
Address space for local memory.
Definition: AMDGPU.h:236
std::vector< Kernel::Metadata > mKernels
Kernels metadata. Required.
Address space for constant memory (VTX2)
Definition: AMDGPU.h:235
const uint64_t Version
Definition: InstrProf.h:895
constexpr uint32_t VersionMajor
HSA metadata major version.
unsigned PRIVATE_ADDRESS
Address space for private memory.
Definition: AMDGPU.h:226
std::vector< uint32_t > Metadata
PAL metadata represented as a vector.