xref: /freebsd/contrib/llvm-project/llvm/lib/Target/AMDGPU/AMDGPUHSAMetadataStreamer.cpp (revision 8bcb0991864975618c09697b1aca10683346d9f0)
10b57cec5SDimitry Andric //===--- AMDGPUHSAMetadataStreamer.cpp --------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// AMDGPU HSA Metadata Streamer.
110b57cec5SDimitry Andric ///
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #include "AMDGPUHSAMetadataStreamer.h"
160b57cec5SDimitry Andric #include "AMDGPU.h"
170b57cec5SDimitry Andric #include "AMDGPUSubtarget.h"
180b57cec5SDimitry Andric #include "MCTargetDesc/AMDGPUTargetStreamer.h"
190b57cec5SDimitry Andric #include "SIMachineFunctionInfo.h"
200b57cec5SDimitry Andric #include "SIProgramInfo.h"
210b57cec5SDimitry Andric #include "Utils/AMDGPUBaseInfo.h"
220b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h"
230b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
240b57cec5SDimitry Andric #include "llvm/IR/Module.h"
250b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric namespace llvm {
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric static cl::opt<bool> DumpHSAMetadata(
300b57cec5SDimitry Andric     "amdgpu-dump-hsa-metadata",
310b57cec5SDimitry Andric     cl::desc("Dump AMDGPU HSA Metadata"));
320b57cec5SDimitry Andric static cl::opt<bool> VerifyHSAMetadata(
330b57cec5SDimitry Andric     "amdgpu-verify-hsa-metadata",
340b57cec5SDimitry Andric     cl::desc("Verify AMDGPU HSA Metadata"));
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric namespace AMDGPU {
370b57cec5SDimitry Andric namespace HSAMD {
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
400b57cec5SDimitry Andric // HSAMetadataStreamerV2
410b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
420b57cec5SDimitry Andric void MetadataStreamerV2::dump(StringRef HSAMetadataString) const {
430b57cec5SDimitry Andric   errs() << "AMDGPU HSA Metadata:\n" << HSAMetadataString << '\n';
440b57cec5SDimitry Andric }
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric void MetadataStreamerV2::verify(StringRef HSAMetadataString) const {
470b57cec5SDimitry Andric   errs() << "AMDGPU HSA Metadata Parser Test: ";
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric   HSAMD::Metadata FromHSAMetadataString;
500b57cec5SDimitry Andric   if (fromString(HSAMetadataString, FromHSAMetadataString)) {
510b57cec5SDimitry Andric     errs() << "FAIL\n";
520b57cec5SDimitry Andric     return;
530b57cec5SDimitry Andric   }
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric   std::string ToHSAMetadataString;
560b57cec5SDimitry Andric   if (toString(FromHSAMetadataString, ToHSAMetadataString)) {
570b57cec5SDimitry Andric     errs() << "FAIL\n";
580b57cec5SDimitry Andric     return;
590b57cec5SDimitry Andric   }
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric   errs() << (HSAMetadataString == ToHSAMetadataString ? "PASS" : "FAIL")
620b57cec5SDimitry Andric          << '\n';
630b57cec5SDimitry Andric   if (HSAMetadataString != ToHSAMetadataString) {
640b57cec5SDimitry Andric     errs() << "Original input: " << HSAMetadataString << '\n'
650b57cec5SDimitry Andric            << "Produced output: " << ToHSAMetadataString << '\n';
660b57cec5SDimitry Andric   }
670b57cec5SDimitry Andric }
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric AccessQualifier
700b57cec5SDimitry Andric MetadataStreamerV2::getAccessQualifier(StringRef AccQual) const {
710b57cec5SDimitry Andric   if (AccQual.empty())
720b57cec5SDimitry Andric     return AccessQualifier::Unknown;
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric   return StringSwitch<AccessQualifier>(AccQual)
750b57cec5SDimitry Andric              .Case("read_only",  AccessQualifier::ReadOnly)
760b57cec5SDimitry Andric              .Case("write_only", AccessQualifier::WriteOnly)
770b57cec5SDimitry Andric              .Case("read_write", AccessQualifier::ReadWrite)
780b57cec5SDimitry Andric              .Default(AccessQualifier::Default);
790b57cec5SDimitry Andric }
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric AddressSpaceQualifier
820b57cec5SDimitry Andric MetadataStreamerV2::getAddressSpaceQualifier(
830b57cec5SDimitry Andric     unsigned AddressSpace) const {
840b57cec5SDimitry Andric   switch (AddressSpace) {
850b57cec5SDimitry Andric   case AMDGPUAS::PRIVATE_ADDRESS:
860b57cec5SDimitry Andric     return AddressSpaceQualifier::Private;
870b57cec5SDimitry Andric   case AMDGPUAS::GLOBAL_ADDRESS:
880b57cec5SDimitry Andric     return AddressSpaceQualifier::Global;
890b57cec5SDimitry Andric   case AMDGPUAS::CONSTANT_ADDRESS:
900b57cec5SDimitry Andric     return AddressSpaceQualifier::Constant;
910b57cec5SDimitry Andric   case AMDGPUAS::LOCAL_ADDRESS:
920b57cec5SDimitry Andric     return AddressSpaceQualifier::Local;
930b57cec5SDimitry Andric   case AMDGPUAS::FLAT_ADDRESS:
940b57cec5SDimitry Andric     return AddressSpaceQualifier::Generic;
950b57cec5SDimitry Andric   case AMDGPUAS::REGION_ADDRESS:
960b57cec5SDimitry Andric     return AddressSpaceQualifier::Region;
970b57cec5SDimitry Andric   default:
980b57cec5SDimitry Andric     return AddressSpaceQualifier::Unknown;
990b57cec5SDimitry Andric   }
1000b57cec5SDimitry Andric }
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric ValueKind MetadataStreamerV2::getValueKind(Type *Ty, StringRef TypeQual,
1030b57cec5SDimitry Andric                                            StringRef BaseTypeName) const {
1040b57cec5SDimitry Andric   if (TypeQual.find("pipe") != StringRef::npos)
1050b57cec5SDimitry Andric     return ValueKind::Pipe;
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric   return StringSwitch<ValueKind>(BaseTypeName)
1080b57cec5SDimitry Andric              .Case("image1d_t", ValueKind::Image)
1090b57cec5SDimitry Andric              .Case("image1d_array_t", ValueKind::Image)
1100b57cec5SDimitry Andric              .Case("image1d_buffer_t", ValueKind::Image)
1110b57cec5SDimitry Andric              .Case("image2d_t", ValueKind::Image)
1120b57cec5SDimitry Andric              .Case("image2d_array_t", ValueKind::Image)
1130b57cec5SDimitry Andric              .Case("image2d_array_depth_t", ValueKind::Image)
1140b57cec5SDimitry Andric              .Case("image2d_array_msaa_t", ValueKind::Image)
1150b57cec5SDimitry Andric              .Case("image2d_array_msaa_depth_t", ValueKind::Image)
1160b57cec5SDimitry Andric              .Case("image2d_depth_t", ValueKind::Image)
1170b57cec5SDimitry Andric              .Case("image2d_msaa_t", ValueKind::Image)
1180b57cec5SDimitry Andric              .Case("image2d_msaa_depth_t", ValueKind::Image)
1190b57cec5SDimitry Andric              .Case("image3d_t", ValueKind::Image)
1200b57cec5SDimitry Andric              .Case("sampler_t", ValueKind::Sampler)
1210b57cec5SDimitry Andric              .Case("queue_t", ValueKind::Queue)
1220b57cec5SDimitry Andric              .Default(isa<PointerType>(Ty) ?
1230b57cec5SDimitry Andric                           (Ty->getPointerAddressSpace() ==
1240b57cec5SDimitry Andric                            AMDGPUAS::LOCAL_ADDRESS ?
1250b57cec5SDimitry Andric                            ValueKind::DynamicSharedPointer :
1260b57cec5SDimitry Andric                            ValueKind::GlobalBuffer) :
1270b57cec5SDimitry Andric                       ValueKind::ByValue);
1280b57cec5SDimitry Andric }
1290b57cec5SDimitry Andric 
1300b57cec5SDimitry Andric ValueType MetadataStreamerV2::getValueType(Type *Ty, StringRef TypeName) const {
1310b57cec5SDimitry Andric   switch (Ty->getTypeID()) {
1320b57cec5SDimitry Andric   case Type::IntegerTyID: {
1330b57cec5SDimitry Andric     auto Signed = !TypeName.startswith("u");
1340b57cec5SDimitry Andric     switch (Ty->getIntegerBitWidth()) {
1350b57cec5SDimitry Andric     case 8:
1360b57cec5SDimitry Andric       return Signed ? ValueType::I8 : ValueType::U8;
1370b57cec5SDimitry Andric     case 16:
1380b57cec5SDimitry Andric       return Signed ? ValueType::I16 : ValueType::U16;
1390b57cec5SDimitry Andric     case 32:
1400b57cec5SDimitry Andric       return Signed ? ValueType::I32 : ValueType::U32;
1410b57cec5SDimitry Andric     case 64:
1420b57cec5SDimitry Andric       return Signed ? ValueType::I64 : ValueType::U64;
1430b57cec5SDimitry Andric     default:
1440b57cec5SDimitry Andric       return ValueType::Struct;
1450b57cec5SDimitry Andric     }
1460b57cec5SDimitry Andric   }
1470b57cec5SDimitry Andric   case Type::HalfTyID:
1480b57cec5SDimitry Andric     return ValueType::F16;
1490b57cec5SDimitry Andric   case Type::FloatTyID:
1500b57cec5SDimitry Andric     return ValueType::F32;
1510b57cec5SDimitry Andric   case Type::DoubleTyID:
1520b57cec5SDimitry Andric     return ValueType::F64;
1530b57cec5SDimitry Andric   case Type::PointerTyID:
1540b57cec5SDimitry Andric     return getValueType(Ty->getPointerElementType(), TypeName);
1550b57cec5SDimitry Andric   case Type::VectorTyID:
1560b57cec5SDimitry Andric     return getValueType(Ty->getVectorElementType(), TypeName);
1570b57cec5SDimitry Andric   default:
1580b57cec5SDimitry Andric     return ValueType::Struct;
1590b57cec5SDimitry Andric   }
1600b57cec5SDimitry Andric }
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric std::string MetadataStreamerV2::getTypeName(Type *Ty, bool Signed) const {
1630b57cec5SDimitry Andric   switch (Ty->getTypeID()) {
1640b57cec5SDimitry Andric   case Type::IntegerTyID: {
1650b57cec5SDimitry Andric     if (!Signed)
1660b57cec5SDimitry Andric       return (Twine('u') + getTypeName(Ty, true)).str();
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric     auto BitWidth = Ty->getIntegerBitWidth();
1690b57cec5SDimitry Andric     switch (BitWidth) {
1700b57cec5SDimitry Andric     case 8:
1710b57cec5SDimitry Andric       return "char";
1720b57cec5SDimitry Andric     case 16:
1730b57cec5SDimitry Andric       return "short";
1740b57cec5SDimitry Andric     case 32:
1750b57cec5SDimitry Andric       return "int";
1760b57cec5SDimitry Andric     case 64:
1770b57cec5SDimitry Andric       return "long";
1780b57cec5SDimitry Andric     default:
1790b57cec5SDimitry Andric       return (Twine('i') + Twine(BitWidth)).str();
1800b57cec5SDimitry Andric     }
1810b57cec5SDimitry Andric   }
1820b57cec5SDimitry Andric   case Type::HalfTyID:
1830b57cec5SDimitry Andric     return "half";
1840b57cec5SDimitry Andric   case Type::FloatTyID:
1850b57cec5SDimitry Andric     return "float";
1860b57cec5SDimitry Andric   case Type::DoubleTyID:
1870b57cec5SDimitry Andric     return "double";
1880b57cec5SDimitry Andric   case Type::VectorTyID: {
1890b57cec5SDimitry Andric     auto VecTy = cast<VectorType>(Ty);
1900b57cec5SDimitry Andric     auto ElTy = VecTy->getElementType();
1910b57cec5SDimitry Andric     auto NumElements = VecTy->getVectorNumElements();
1920b57cec5SDimitry Andric     return (Twine(getTypeName(ElTy, Signed)) + Twine(NumElements)).str();
1930b57cec5SDimitry Andric   }
1940b57cec5SDimitry Andric   default:
1950b57cec5SDimitry Andric     return "unknown";
1960b57cec5SDimitry Andric   }
1970b57cec5SDimitry Andric }
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric std::vector<uint32_t>
2000b57cec5SDimitry Andric MetadataStreamerV2::getWorkGroupDimensions(MDNode *Node) const {
2010b57cec5SDimitry Andric   std::vector<uint32_t> Dims;
2020b57cec5SDimitry Andric   if (Node->getNumOperands() != 3)
2030b57cec5SDimitry Andric     return Dims;
2040b57cec5SDimitry Andric 
2050b57cec5SDimitry Andric   for (auto &Op : Node->operands())
2060b57cec5SDimitry Andric     Dims.push_back(mdconst::extract<ConstantInt>(Op)->getZExtValue());
2070b57cec5SDimitry Andric   return Dims;
2080b57cec5SDimitry Andric }
2090b57cec5SDimitry Andric 
2100b57cec5SDimitry Andric Kernel::CodeProps::Metadata
2110b57cec5SDimitry Andric MetadataStreamerV2::getHSACodeProps(const MachineFunction &MF,
2120b57cec5SDimitry Andric                                     const SIProgramInfo &ProgramInfo) const {
2130b57cec5SDimitry Andric   const GCNSubtarget &STM = MF.getSubtarget<GCNSubtarget>();
2140b57cec5SDimitry Andric   const SIMachineFunctionInfo &MFI = *MF.getInfo<SIMachineFunctionInfo>();
2150b57cec5SDimitry Andric   HSAMD::Kernel::CodeProps::Metadata HSACodeProps;
2160b57cec5SDimitry Andric   const Function &F = MF.getFunction();
2170b57cec5SDimitry Andric 
2180b57cec5SDimitry Andric   assert(F.getCallingConv() == CallingConv::AMDGPU_KERNEL ||
2190b57cec5SDimitry Andric          F.getCallingConv() == CallingConv::SPIR_KERNEL);
2200b57cec5SDimitry Andric 
221*8bcb0991SDimitry Andric   Align MaxKernArgAlign;
2220b57cec5SDimitry Andric   HSACodeProps.mKernargSegmentSize = STM.getKernArgSegmentSize(F,
2230b57cec5SDimitry Andric                                                                MaxKernArgAlign);
2240b57cec5SDimitry Andric   HSACodeProps.mGroupSegmentFixedSize = ProgramInfo.LDSSize;
2250b57cec5SDimitry Andric   HSACodeProps.mPrivateSegmentFixedSize = ProgramInfo.ScratchSize;
226*8bcb0991SDimitry Andric   HSACodeProps.mKernargSegmentAlign =
227*8bcb0991SDimitry Andric       std::max(MaxKernArgAlign, Align(4)).value();
2280b57cec5SDimitry Andric   HSACodeProps.mWavefrontSize = STM.getWavefrontSize();
2290b57cec5SDimitry Andric   HSACodeProps.mNumSGPRs = ProgramInfo.NumSGPR;
2300b57cec5SDimitry Andric   HSACodeProps.mNumVGPRs = ProgramInfo.NumVGPR;
2310b57cec5SDimitry Andric   HSACodeProps.mMaxFlatWorkGroupSize = MFI.getMaxFlatWorkGroupSize();
2320b57cec5SDimitry Andric   HSACodeProps.mIsDynamicCallStack = ProgramInfo.DynamicCallStack;
2330b57cec5SDimitry Andric   HSACodeProps.mIsXNACKEnabled = STM.isXNACKEnabled();
2340b57cec5SDimitry Andric   HSACodeProps.mNumSpilledSGPRs = MFI.getNumSpilledSGPRs();
2350b57cec5SDimitry Andric   HSACodeProps.mNumSpilledVGPRs = MFI.getNumSpilledVGPRs();
2360b57cec5SDimitry Andric 
2370b57cec5SDimitry Andric   return HSACodeProps;
2380b57cec5SDimitry Andric }
2390b57cec5SDimitry Andric 
2400b57cec5SDimitry Andric Kernel::DebugProps::Metadata
2410b57cec5SDimitry Andric MetadataStreamerV2::getHSADebugProps(const MachineFunction &MF,
2420b57cec5SDimitry Andric                                      const SIProgramInfo &ProgramInfo) const {
2430b57cec5SDimitry Andric   return HSAMD::Kernel::DebugProps::Metadata();
2440b57cec5SDimitry Andric }
2450b57cec5SDimitry Andric 
2460b57cec5SDimitry Andric void MetadataStreamerV2::emitVersion() {
2470b57cec5SDimitry Andric   auto &Version = HSAMetadata.mVersion;
2480b57cec5SDimitry Andric 
2490b57cec5SDimitry Andric   Version.push_back(VersionMajor);
2500b57cec5SDimitry Andric   Version.push_back(VersionMinor);
2510b57cec5SDimitry Andric }
2520b57cec5SDimitry Andric 
2530b57cec5SDimitry Andric void MetadataStreamerV2::emitPrintf(const Module &Mod) {
2540b57cec5SDimitry Andric   auto &Printf = HSAMetadata.mPrintf;
2550b57cec5SDimitry Andric 
2560b57cec5SDimitry Andric   auto Node = Mod.getNamedMetadata("llvm.printf.fmts");
2570b57cec5SDimitry Andric   if (!Node)
2580b57cec5SDimitry Andric     return;
2590b57cec5SDimitry Andric 
2600b57cec5SDimitry Andric   for (auto Op : Node->operands())
2610b57cec5SDimitry Andric     if (Op->getNumOperands())
2620b57cec5SDimitry Andric       Printf.push_back(cast<MDString>(Op->getOperand(0))->getString());
2630b57cec5SDimitry Andric }
2640b57cec5SDimitry Andric 
2650b57cec5SDimitry Andric void MetadataStreamerV2::emitKernelLanguage(const Function &Func) {
2660b57cec5SDimitry Andric   auto &Kernel = HSAMetadata.mKernels.back();
2670b57cec5SDimitry Andric 
2680b57cec5SDimitry Andric   // TODO: What about other languages?
2690b57cec5SDimitry Andric   auto Node = Func.getParent()->getNamedMetadata("opencl.ocl.version");
2700b57cec5SDimitry Andric   if (!Node || !Node->getNumOperands())
2710b57cec5SDimitry Andric     return;
2720b57cec5SDimitry Andric   auto Op0 = Node->getOperand(0);
2730b57cec5SDimitry Andric   if (Op0->getNumOperands() <= 1)
2740b57cec5SDimitry Andric     return;
2750b57cec5SDimitry Andric 
2760b57cec5SDimitry Andric   Kernel.mLanguage = "OpenCL C";
2770b57cec5SDimitry Andric   Kernel.mLanguageVersion.push_back(
2780b57cec5SDimitry Andric       mdconst::extract<ConstantInt>(Op0->getOperand(0))->getZExtValue());
2790b57cec5SDimitry Andric   Kernel.mLanguageVersion.push_back(
2800b57cec5SDimitry Andric       mdconst::extract<ConstantInt>(Op0->getOperand(1))->getZExtValue());
2810b57cec5SDimitry Andric }
2820b57cec5SDimitry Andric 
2830b57cec5SDimitry Andric void MetadataStreamerV2::emitKernelAttrs(const Function &Func) {
2840b57cec5SDimitry Andric   auto &Attrs = HSAMetadata.mKernels.back().mAttrs;
2850b57cec5SDimitry Andric 
2860b57cec5SDimitry Andric   if (auto Node = Func.getMetadata("reqd_work_group_size"))
2870b57cec5SDimitry Andric     Attrs.mReqdWorkGroupSize = getWorkGroupDimensions(Node);
2880b57cec5SDimitry Andric   if (auto Node = Func.getMetadata("work_group_size_hint"))
2890b57cec5SDimitry Andric     Attrs.mWorkGroupSizeHint = getWorkGroupDimensions(Node);
2900b57cec5SDimitry Andric   if (auto Node = Func.getMetadata("vec_type_hint")) {
2910b57cec5SDimitry Andric     Attrs.mVecTypeHint = getTypeName(
2920b57cec5SDimitry Andric         cast<ValueAsMetadata>(Node->getOperand(0))->getType(),
2930b57cec5SDimitry Andric         mdconst::extract<ConstantInt>(Node->getOperand(1))->getZExtValue());
2940b57cec5SDimitry Andric   }
2950b57cec5SDimitry Andric   if (Func.hasFnAttribute("runtime-handle")) {
2960b57cec5SDimitry Andric     Attrs.mRuntimeHandle =
2970b57cec5SDimitry Andric         Func.getFnAttribute("runtime-handle").getValueAsString().str();
2980b57cec5SDimitry Andric   }
2990b57cec5SDimitry Andric }
3000b57cec5SDimitry Andric 
3010b57cec5SDimitry Andric void MetadataStreamerV2::emitKernelArgs(const Function &Func) {
3020b57cec5SDimitry Andric   for (auto &Arg : Func.args())
3030b57cec5SDimitry Andric     emitKernelArg(Arg);
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric   emitHiddenKernelArgs(Func);
3060b57cec5SDimitry Andric }
3070b57cec5SDimitry Andric 
3080b57cec5SDimitry Andric void MetadataStreamerV2::emitKernelArg(const Argument &Arg) {
3090b57cec5SDimitry Andric   auto Func = Arg.getParent();
3100b57cec5SDimitry Andric   auto ArgNo = Arg.getArgNo();
3110b57cec5SDimitry Andric   const MDNode *Node;
3120b57cec5SDimitry Andric 
3130b57cec5SDimitry Andric   StringRef Name;
3140b57cec5SDimitry Andric   Node = Func->getMetadata("kernel_arg_name");
3150b57cec5SDimitry Andric   if (Node && ArgNo < Node->getNumOperands())
3160b57cec5SDimitry Andric     Name = cast<MDString>(Node->getOperand(ArgNo))->getString();
3170b57cec5SDimitry Andric   else if (Arg.hasName())
3180b57cec5SDimitry Andric     Name = Arg.getName();
3190b57cec5SDimitry Andric 
3200b57cec5SDimitry Andric   StringRef TypeName;
3210b57cec5SDimitry Andric   Node = Func->getMetadata("kernel_arg_type");
3220b57cec5SDimitry Andric   if (Node && ArgNo < Node->getNumOperands())
3230b57cec5SDimitry Andric     TypeName = cast<MDString>(Node->getOperand(ArgNo))->getString();
3240b57cec5SDimitry Andric 
3250b57cec5SDimitry Andric   StringRef BaseTypeName;
3260b57cec5SDimitry Andric   Node = Func->getMetadata("kernel_arg_base_type");
3270b57cec5SDimitry Andric   if (Node && ArgNo < Node->getNumOperands())
3280b57cec5SDimitry Andric     BaseTypeName = cast<MDString>(Node->getOperand(ArgNo))->getString();
3290b57cec5SDimitry Andric 
3300b57cec5SDimitry Andric   StringRef AccQual;
3310b57cec5SDimitry Andric   if (Arg.getType()->isPointerTy() && Arg.onlyReadsMemory() &&
3320b57cec5SDimitry Andric       Arg.hasNoAliasAttr()) {
3330b57cec5SDimitry Andric     AccQual = "read_only";
3340b57cec5SDimitry Andric   } else {
3350b57cec5SDimitry Andric     Node = Func->getMetadata("kernel_arg_access_qual");
3360b57cec5SDimitry Andric     if (Node && ArgNo < Node->getNumOperands())
3370b57cec5SDimitry Andric       AccQual = cast<MDString>(Node->getOperand(ArgNo))->getString();
3380b57cec5SDimitry Andric   }
3390b57cec5SDimitry Andric 
3400b57cec5SDimitry Andric   StringRef TypeQual;
3410b57cec5SDimitry Andric   Node = Func->getMetadata("kernel_arg_type_qual");
3420b57cec5SDimitry Andric   if (Node && ArgNo < Node->getNumOperands())
3430b57cec5SDimitry Andric     TypeQual = cast<MDString>(Node->getOperand(ArgNo))->getString();
3440b57cec5SDimitry Andric 
3450b57cec5SDimitry Andric   Type *Ty = Arg.getType();
3460b57cec5SDimitry Andric   const DataLayout &DL = Func->getParent()->getDataLayout();
3470b57cec5SDimitry Andric 
3480b57cec5SDimitry Andric   unsigned PointeeAlign = 0;
3490b57cec5SDimitry Andric   if (auto PtrTy = dyn_cast<PointerType>(Ty)) {
3500b57cec5SDimitry Andric     if (PtrTy->getAddressSpace() == AMDGPUAS::LOCAL_ADDRESS) {
3510b57cec5SDimitry Andric       PointeeAlign = Arg.getParamAlignment();
3520b57cec5SDimitry Andric       if (PointeeAlign == 0)
3530b57cec5SDimitry Andric         PointeeAlign = DL.getABITypeAlignment(PtrTy->getElementType());
3540b57cec5SDimitry Andric     }
3550b57cec5SDimitry Andric   }
3560b57cec5SDimitry Andric 
3570b57cec5SDimitry Andric   emitKernelArg(DL, Ty, getValueKind(Arg.getType(), TypeQual, BaseTypeName),
3580b57cec5SDimitry Andric                 PointeeAlign, Name, TypeName, BaseTypeName, AccQual, TypeQual);
3590b57cec5SDimitry Andric }
3600b57cec5SDimitry Andric 
3610b57cec5SDimitry Andric void MetadataStreamerV2::emitKernelArg(const DataLayout &DL, Type *Ty,
3620b57cec5SDimitry Andric                                        ValueKind ValueKind,
3630b57cec5SDimitry Andric                                        unsigned PointeeAlign, StringRef Name,
3640b57cec5SDimitry Andric                                        StringRef TypeName,
3650b57cec5SDimitry Andric                                        StringRef BaseTypeName,
3660b57cec5SDimitry Andric                                        StringRef AccQual, StringRef TypeQual) {
3670b57cec5SDimitry Andric   HSAMetadata.mKernels.back().mArgs.push_back(Kernel::Arg::Metadata());
3680b57cec5SDimitry Andric   auto &Arg = HSAMetadata.mKernels.back().mArgs.back();
3690b57cec5SDimitry Andric 
3700b57cec5SDimitry Andric   Arg.mName = Name;
3710b57cec5SDimitry Andric   Arg.mTypeName = TypeName;
3720b57cec5SDimitry Andric   Arg.mSize = DL.getTypeAllocSize(Ty);
3730b57cec5SDimitry Andric   Arg.mAlign = DL.getABITypeAlignment(Ty);
3740b57cec5SDimitry Andric   Arg.mValueKind = ValueKind;
3750b57cec5SDimitry Andric   Arg.mValueType = getValueType(Ty, BaseTypeName);
3760b57cec5SDimitry Andric   Arg.mPointeeAlign = PointeeAlign;
3770b57cec5SDimitry Andric 
3780b57cec5SDimitry Andric   if (auto PtrTy = dyn_cast<PointerType>(Ty))
3790b57cec5SDimitry Andric     Arg.mAddrSpaceQual = getAddressSpaceQualifier(PtrTy->getAddressSpace());
3800b57cec5SDimitry Andric 
3810b57cec5SDimitry Andric   Arg.mAccQual = getAccessQualifier(AccQual);
3820b57cec5SDimitry Andric 
3830b57cec5SDimitry Andric   // TODO: Emit Arg.mActualAccQual.
3840b57cec5SDimitry Andric 
3850b57cec5SDimitry Andric   SmallVector<StringRef, 1> SplitTypeQuals;
3860b57cec5SDimitry Andric   TypeQual.split(SplitTypeQuals, " ", -1, false);
3870b57cec5SDimitry Andric   for (StringRef Key : SplitTypeQuals) {
3880b57cec5SDimitry Andric     auto P = StringSwitch<bool*>(Key)
3890b57cec5SDimitry Andric                  .Case("const",    &Arg.mIsConst)
3900b57cec5SDimitry Andric                  .Case("restrict", &Arg.mIsRestrict)
3910b57cec5SDimitry Andric                  .Case("volatile", &Arg.mIsVolatile)
3920b57cec5SDimitry Andric                  .Case("pipe",     &Arg.mIsPipe)
3930b57cec5SDimitry Andric                  .Default(nullptr);
3940b57cec5SDimitry Andric     if (P)
3950b57cec5SDimitry Andric       *P = true;
3960b57cec5SDimitry Andric   }
3970b57cec5SDimitry Andric }
3980b57cec5SDimitry Andric 
3990b57cec5SDimitry Andric void MetadataStreamerV2::emitHiddenKernelArgs(const Function &Func) {
4000b57cec5SDimitry Andric   int HiddenArgNumBytes =
4010b57cec5SDimitry Andric       getIntegerAttribute(Func, "amdgpu-implicitarg-num-bytes", 0);
4020b57cec5SDimitry Andric 
4030b57cec5SDimitry Andric   if (!HiddenArgNumBytes)
4040b57cec5SDimitry Andric     return;
4050b57cec5SDimitry Andric 
4060b57cec5SDimitry Andric   auto &DL = Func.getParent()->getDataLayout();
4070b57cec5SDimitry Andric   auto Int64Ty = Type::getInt64Ty(Func.getContext());
4080b57cec5SDimitry Andric 
4090b57cec5SDimitry Andric   if (HiddenArgNumBytes >= 8)
4100b57cec5SDimitry Andric     emitKernelArg(DL, Int64Ty, ValueKind::HiddenGlobalOffsetX);
4110b57cec5SDimitry Andric   if (HiddenArgNumBytes >= 16)
4120b57cec5SDimitry Andric     emitKernelArg(DL, Int64Ty, ValueKind::HiddenGlobalOffsetY);
4130b57cec5SDimitry Andric   if (HiddenArgNumBytes >= 24)
4140b57cec5SDimitry Andric     emitKernelArg(DL, Int64Ty, ValueKind::HiddenGlobalOffsetZ);
4150b57cec5SDimitry Andric 
4160b57cec5SDimitry Andric   auto Int8PtrTy = Type::getInt8PtrTy(Func.getContext(),
4170b57cec5SDimitry Andric                                       AMDGPUAS::GLOBAL_ADDRESS);
4180b57cec5SDimitry Andric 
4190b57cec5SDimitry Andric   // Emit "printf buffer" argument if printf is used, otherwise emit dummy
4200b57cec5SDimitry Andric   // "none" argument.
4210b57cec5SDimitry Andric   if (HiddenArgNumBytes >= 32) {
4220b57cec5SDimitry Andric     if (Func.getParent()->getNamedMetadata("llvm.printf.fmts"))
4230b57cec5SDimitry Andric       emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenPrintfBuffer);
4240b57cec5SDimitry Andric     else
4250b57cec5SDimitry Andric       emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenNone);
4260b57cec5SDimitry Andric   }
4270b57cec5SDimitry Andric 
4280b57cec5SDimitry Andric   // Emit "default queue" and "completion action" arguments if enqueue kernel is
4290b57cec5SDimitry Andric   // used, otherwise emit dummy "none" arguments.
4300b57cec5SDimitry Andric   if (HiddenArgNumBytes >= 48) {
4310b57cec5SDimitry Andric     if (Func.hasFnAttribute("calls-enqueue-kernel")) {
4320b57cec5SDimitry Andric       emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenDefaultQueue);
4330b57cec5SDimitry Andric       emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenCompletionAction);
4340b57cec5SDimitry Andric     } else {
4350b57cec5SDimitry Andric       emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenNone);
4360b57cec5SDimitry Andric       emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenNone);
4370b57cec5SDimitry Andric     }
4380b57cec5SDimitry Andric   }
4390b57cec5SDimitry Andric 
4400b57cec5SDimitry Andric   // Emit the pointer argument for multi-grid object.
4410b57cec5SDimitry Andric   if (HiddenArgNumBytes >= 56)
4420b57cec5SDimitry Andric     emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenMultiGridSyncArg);
4430b57cec5SDimitry Andric }
4440b57cec5SDimitry Andric 
4450b57cec5SDimitry Andric bool MetadataStreamerV2::emitTo(AMDGPUTargetStreamer &TargetStreamer) {
4460b57cec5SDimitry Andric   return TargetStreamer.EmitHSAMetadata(getHSAMetadata());
4470b57cec5SDimitry Andric }
4480b57cec5SDimitry Andric 
4490b57cec5SDimitry Andric void MetadataStreamerV2::begin(const Module &Mod) {
4500b57cec5SDimitry Andric   emitVersion();
4510b57cec5SDimitry Andric   emitPrintf(Mod);
4520b57cec5SDimitry Andric }
4530b57cec5SDimitry Andric 
4540b57cec5SDimitry Andric void MetadataStreamerV2::end() {
4550b57cec5SDimitry Andric   std::string HSAMetadataString;
4560b57cec5SDimitry Andric   if (toString(HSAMetadata, HSAMetadataString))
4570b57cec5SDimitry Andric     return;
4580b57cec5SDimitry Andric 
4590b57cec5SDimitry Andric   if (DumpHSAMetadata)
4600b57cec5SDimitry Andric     dump(HSAMetadataString);
4610b57cec5SDimitry Andric   if (VerifyHSAMetadata)
4620b57cec5SDimitry Andric     verify(HSAMetadataString);
4630b57cec5SDimitry Andric }
4640b57cec5SDimitry Andric 
4650b57cec5SDimitry Andric void MetadataStreamerV2::emitKernel(const MachineFunction &MF,
4660b57cec5SDimitry Andric                                     const SIProgramInfo &ProgramInfo) {
4670b57cec5SDimitry Andric   auto &Func = MF.getFunction();
4680b57cec5SDimitry Andric   if (Func.getCallingConv() != CallingConv::AMDGPU_KERNEL)
4690b57cec5SDimitry Andric     return;
4700b57cec5SDimitry Andric 
4710b57cec5SDimitry Andric   auto CodeProps = getHSACodeProps(MF, ProgramInfo);
4720b57cec5SDimitry Andric   auto DebugProps = getHSADebugProps(MF, ProgramInfo);
4730b57cec5SDimitry Andric 
4740b57cec5SDimitry Andric   HSAMetadata.mKernels.push_back(Kernel::Metadata());
4750b57cec5SDimitry Andric   auto &Kernel = HSAMetadata.mKernels.back();
4760b57cec5SDimitry Andric 
4770b57cec5SDimitry Andric   Kernel.mName = Func.getName();
4780b57cec5SDimitry Andric   Kernel.mSymbolName = (Twine(Func.getName()) + Twine("@kd")).str();
4790b57cec5SDimitry Andric   emitKernelLanguage(Func);
4800b57cec5SDimitry Andric   emitKernelAttrs(Func);
4810b57cec5SDimitry Andric   emitKernelArgs(Func);
4820b57cec5SDimitry Andric   HSAMetadata.mKernels.back().mCodeProps = CodeProps;
4830b57cec5SDimitry Andric   HSAMetadata.mKernels.back().mDebugProps = DebugProps;
4840b57cec5SDimitry Andric }
4850b57cec5SDimitry Andric 
4860b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
4870b57cec5SDimitry Andric // HSAMetadataStreamerV3
4880b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
4890b57cec5SDimitry Andric 
4900b57cec5SDimitry Andric void MetadataStreamerV3::dump(StringRef HSAMetadataString) const {
4910b57cec5SDimitry Andric   errs() << "AMDGPU HSA Metadata:\n" << HSAMetadataString << '\n';
4920b57cec5SDimitry Andric }
4930b57cec5SDimitry Andric 
4940b57cec5SDimitry Andric void MetadataStreamerV3::verify(StringRef HSAMetadataString) const {
4950b57cec5SDimitry Andric   errs() << "AMDGPU HSA Metadata Parser Test: ";
4960b57cec5SDimitry Andric 
4970b57cec5SDimitry Andric   msgpack::Document FromHSAMetadataString;
4980b57cec5SDimitry Andric 
4990b57cec5SDimitry Andric   if (!FromHSAMetadataString.fromYAML(HSAMetadataString)) {
5000b57cec5SDimitry Andric     errs() << "FAIL\n";
5010b57cec5SDimitry Andric     return;
5020b57cec5SDimitry Andric   }
5030b57cec5SDimitry Andric 
5040b57cec5SDimitry Andric   std::string ToHSAMetadataString;
5050b57cec5SDimitry Andric   raw_string_ostream StrOS(ToHSAMetadataString);
5060b57cec5SDimitry Andric   FromHSAMetadataString.toYAML(StrOS);
5070b57cec5SDimitry Andric 
5080b57cec5SDimitry Andric   errs() << (HSAMetadataString == StrOS.str() ? "PASS" : "FAIL") << '\n';
5090b57cec5SDimitry Andric   if (HSAMetadataString != ToHSAMetadataString) {
5100b57cec5SDimitry Andric     errs() << "Original input: " << HSAMetadataString << '\n'
5110b57cec5SDimitry Andric            << "Produced output: " << StrOS.str() << '\n';
5120b57cec5SDimitry Andric   }
5130b57cec5SDimitry Andric }
5140b57cec5SDimitry Andric 
5150b57cec5SDimitry Andric Optional<StringRef>
5160b57cec5SDimitry Andric MetadataStreamerV3::getAccessQualifier(StringRef AccQual) const {
5170b57cec5SDimitry Andric   return StringSwitch<Optional<StringRef>>(AccQual)
5180b57cec5SDimitry Andric       .Case("read_only", StringRef("read_only"))
5190b57cec5SDimitry Andric       .Case("write_only", StringRef("write_only"))
5200b57cec5SDimitry Andric       .Case("read_write", StringRef("read_write"))
5210b57cec5SDimitry Andric       .Default(None);
5220b57cec5SDimitry Andric }
5230b57cec5SDimitry Andric 
5240b57cec5SDimitry Andric Optional<StringRef>
5250b57cec5SDimitry Andric MetadataStreamerV3::getAddressSpaceQualifier(unsigned AddressSpace) const {
5260b57cec5SDimitry Andric   switch (AddressSpace) {
5270b57cec5SDimitry Andric   case AMDGPUAS::PRIVATE_ADDRESS:
5280b57cec5SDimitry Andric     return StringRef("private");
5290b57cec5SDimitry Andric   case AMDGPUAS::GLOBAL_ADDRESS:
5300b57cec5SDimitry Andric     return StringRef("global");
5310b57cec5SDimitry Andric   case AMDGPUAS::CONSTANT_ADDRESS:
5320b57cec5SDimitry Andric     return StringRef("constant");
5330b57cec5SDimitry Andric   case AMDGPUAS::LOCAL_ADDRESS:
5340b57cec5SDimitry Andric     return StringRef("local");
5350b57cec5SDimitry Andric   case AMDGPUAS::FLAT_ADDRESS:
5360b57cec5SDimitry Andric     return StringRef("generic");
5370b57cec5SDimitry Andric   case AMDGPUAS::REGION_ADDRESS:
5380b57cec5SDimitry Andric     return StringRef("region");
5390b57cec5SDimitry Andric   default:
5400b57cec5SDimitry Andric     return None;
5410b57cec5SDimitry Andric   }
5420b57cec5SDimitry Andric }
5430b57cec5SDimitry Andric 
5440b57cec5SDimitry Andric StringRef MetadataStreamerV3::getValueKind(Type *Ty, StringRef TypeQual,
5450b57cec5SDimitry Andric                                            StringRef BaseTypeName) const {
5460b57cec5SDimitry Andric   if (TypeQual.find("pipe") != StringRef::npos)
5470b57cec5SDimitry Andric     return "pipe";
5480b57cec5SDimitry Andric 
5490b57cec5SDimitry Andric   return StringSwitch<StringRef>(BaseTypeName)
5500b57cec5SDimitry Andric       .Case("image1d_t", "image")
5510b57cec5SDimitry Andric       .Case("image1d_array_t", "image")
5520b57cec5SDimitry Andric       .Case("image1d_buffer_t", "image")
5530b57cec5SDimitry Andric       .Case("image2d_t", "image")
5540b57cec5SDimitry Andric       .Case("image2d_array_t", "image")
5550b57cec5SDimitry Andric       .Case("image2d_array_depth_t", "image")
5560b57cec5SDimitry Andric       .Case("image2d_array_msaa_t", "image")
5570b57cec5SDimitry Andric       .Case("image2d_array_msaa_depth_t", "image")
5580b57cec5SDimitry Andric       .Case("image2d_depth_t", "image")
5590b57cec5SDimitry Andric       .Case("image2d_msaa_t", "image")
5600b57cec5SDimitry Andric       .Case("image2d_msaa_depth_t", "image")
5610b57cec5SDimitry Andric       .Case("image3d_t", "image")
5620b57cec5SDimitry Andric       .Case("sampler_t", "sampler")
5630b57cec5SDimitry Andric       .Case("queue_t", "queue")
5640b57cec5SDimitry Andric       .Default(isa<PointerType>(Ty)
5650b57cec5SDimitry Andric                    ? (Ty->getPointerAddressSpace() == AMDGPUAS::LOCAL_ADDRESS
5660b57cec5SDimitry Andric                           ? "dynamic_shared_pointer"
5670b57cec5SDimitry Andric                           : "global_buffer")
5680b57cec5SDimitry Andric                    : "by_value");
5690b57cec5SDimitry Andric }
5700b57cec5SDimitry Andric 
5710b57cec5SDimitry Andric StringRef MetadataStreamerV3::getValueType(Type *Ty, StringRef TypeName) const {
5720b57cec5SDimitry Andric   switch (Ty->getTypeID()) {
5730b57cec5SDimitry Andric   case Type::IntegerTyID: {
5740b57cec5SDimitry Andric     auto Signed = !TypeName.startswith("u");
5750b57cec5SDimitry Andric     switch (Ty->getIntegerBitWidth()) {
5760b57cec5SDimitry Andric     case 8:
5770b57cec5SDimitry Andric       return Signed ? "i8" : "u8";
5780b57cec5SDimitry Andric     case 16:
5790b57cec5SDimitry Andric       return Signed ? "i16" : "u16";
5800b57cec5SDimitry Andric     case 32:
5810b57cec5SDimitry Andric       return Signed ? "i32" : "u32";
5820b57cec5SDimitry Andric     case 64:
5830b57cec5SDimitry Andric       return Signed ? "i64" : "u64";
5840b57cec5SDimitry Andric     default:
5850b57cec5SDimitry Andric       return "struct";
5860b57cec5SDimitry Andric     }
5870b57cec5SDimitry Andric   }
5880b57cec5SDimitry Andric   case Type::HalfTyID:
5890b57cec5SDimitry Andric     return "f16";
5900b57cec5SDimitry Andric   case Type::FloatTyID:
5910b57cec5SDimitry Andric     return "f32";
5920b57cec5SDimitry Andric   case Type::DoubleTyID:
5930b57cec5SDimitry Andric     return "f64";
5940b57cec5SDimitry Andric   case Type::PointerTyID:
5950b57cec5SDimitry Andric     return getValueType(Ty->getPointerElementType(), TypeName);
5960b57cec5SDimitry Andric   case Type::VectorTyID:
5970b57cec5SDimitry Andric     return getValueType(Ty->getVectorElementType(), TypeName);
5980b57cec5SDimitry Andric   default:
5990b57cec5SDimitry Andric     return "struct";
6000b57cec5SDimitry Andric   }
6010b57cec5SDimitry Andric }
6020b57cec5SDimitry Andric 
6030b57cec5SDimitry Andric std::string MetadataStreamerV3::getTypeName(Type *Ty, bool Signed) const {
6040b57cec5SDimitry Andric   switch (Ty->getTypeID()) {
6050b57cec5SDimitry Andric   case Type::IntegerTyID: {
6060b57cec5SDimitry Andric     if (!Signed)
6070b57cec5SDimitry Andric       return (Twine('u') + getTypeName(Ty, true)).str();
6080b57cec5SDimitry Andric 
6090b57cec5SDimitry Andric     auto BitWidth = Ty->getIntegerBitWidth();
6100b57cec5SDimitry Andric     switch (BitWidth) {
6110b57cec5SDimitry Andric     case 8:
6120b57cec5SDimitry Andric       return "char";
6130b57cec5SDimitry Andric     case 16:
6140b57cec5SDimitry Andric       return "short";
6150b57cec5SDimitry Andric     case 32:
6160b57cec5SDimitry Andric       return "int";
6170b57cec5SDimitry Andric     case 64:
6180b57cec5SDimitry Andric       return "long";
6190b57cec5SDimitry Andric     default:
6200b57cec5SDimitry Andric       return (Twine('i') + Twine(BitWidth)).str();
6210b57cec5SDimitry Andric     }
6220b57cec5SDimitry Andric   }
6230b57cec5SDimitry Andric   case Type::HalfTyID:
6240b57cec5SDimitry Andric     return "half";
6250b57cec5SDimitry Andric   case Type::FloatTyID:
6260b57cec5SDimitry Andric     return "float";
6270b57cec5SDimitry Andric   case Type::DoubleTyID:
6280b57cec5SDimitry Andric     return "double";
6290b57cec5SDimitry Andric   case Type::VectorTyID: {
6300b57cec5SDimitry Andric     auto VecTy = cast<VectorType>(Ty);
6310b57cec5SDimitry Andric     auto ElTy = VecTy->getElementType();
6320b57cec5SDimitry Andric     auto NumElements = VecTy->getVectorNumElements();
6330b57cec5SDimitry Andric     return (Twine(getTypeName(ElTy, Signed)) + Twine(NumElements)).str();
6340b57cec5SDimitry Andric   }
6350b57cec5SDimitry Andric   default:
6360b57cec5SDimitry Andric     return "unknown";
6370b57cec5SDimitry Andric   }
6380b57cec5SDimitry Andric }
6390b57cec5SDimitry Andric 
6400b57cec5SDimitry Andric msgpack::ArrayDocNode
6410b57cec5SDimitry Andric MetadataStreamerV3::getWorkGroupDimensions(MDNode *Node) const {
6420b57cec5SDimitry Andric   auto Dims = HSAMetadataDoc->getArrayNode();
6430b57cec5SDimitry Andric   if (Node->getNumOperands() != 3)
6440b57cec5SDimitry Andric     return Dims;
6450b57cec5SDimitry Andric 
6460b57cec5SDimitry Andric   for (auto &Op : Node->operands())
6470b57cec5SDimitry Andric     Dims.push_back(Dims.getDocument()->getNode(
6480b57cec5SDimitry Andric         uint64_t(mdconst::extract<ConstantInt>(Op)->getZExtValue())));
6490b57cec5SDimitry Andric   return Dims;
6500b57cec5SDimitry Andric }
6510b57cec5SDimitry Andric 
6520b57cec5SDimitry Andric void MetadataStreamerV3::emitVersion() {
6530b57cec5SDimitry Andric   auto Version = HSAMetadataDoc->getArrayNode();
6540b57cec5SDimitry Andric   Version.push_back(Version.getDocument()->getNode(VersionMajor));
6550b57cec5SDimitry Andric   Version.push_back(Version.getDocument()->getNode(VersionMinor));
6560b57cec5SDimitry Andric   getRootMetadata("amdhsa.version") = Version;
6570b57cec5SDimitry Andric }
6580b57cec5SDimitry Andric 
6590b57cec5SDimitry Andric void MetadataStreamerV3::emitPrintf(const Module &Mod) {
6600b57cec5SDimitry Andric   auto Node = Mod.getNamedMetadata("llvm.printf.fmts");
6610b57cec5SDimitry Andric   if (!Node)
6620b57cec5SDimitry Andric     return;
6630b57cec5SDimitry Andric 
6640b57cec5SDimitry Andric   auto Printf = HSAMetadataDoc->getArrayNode();
6650b57cec5SDimitry Andric   for (auto Op : Node->operands())
6660b57cec5SDimitry Andric     if (Op->getNumOperands())
6670b57cec5SDimitry Andric       Printf.push_back(Printf.getDocument()->getNode(
6680b57cec5SDimitry Andric           cast<MDString>(Op->getOperand(0))->getString(), /*Copy=*/true));
6690b57cec5SDimitry Andric   getRootMetadata("amdhsa.printf") = Printf;
6700b57cec5SDimitry Andric }
6710b57cec5SDimitry Andric 
6720b57cec5SDimitry Andric void MetadataStreamerV3::emitKernelLanguage(const Function &Func,
6730b57cec5SDimitry Andric                                             msgpack::MapDocNode Kern) {
6740b57cec5SDimitry Andric   // TODO: What about other languages?
6750b57cec5SDimitry Andric   auto Node = Func.getParent()->getNamedMetadata("opencl.ocl.version");
6760b57cec5SDimitry Andric   if (!Node || !Node->getNumOperands())
6770b57cec5SDimitry Andric     return;
6780b57cec5SDimitry Andric   auto Op0 = Node->getOperand(0);
6790b57cec5SDimitry Andric   if (Op0->getNumOperands() <= 1)
6800b57cec5SDimitry Andric     return;
6810b57cec5SDimitry Andric 
6820b57cec5SDimitry Andric   Kern[".language"] = Kern.getDocument()->getNode("OpenCL C");
6830b57cec5SDimitry Andric   auto LanguageVersion = Kern.getDocument()->getArrayNode();
6840b57cec5SDimitry Andric   LanguageVersion.push_back(Kern.getDocument()->getNode(
6850b57cec5SDimitry Andric       mdconst::extract<ConstantInt>(Op0->getOperand(0))->getZExtValue()));
6860b57cec5SDimitry Andric   LanguageVersion.push_back(Kern.getDocument()->getNode(
6870b57cec5SDimitry Andric       mdconst::extract<ConstantInt>(Op0->getOperand(1))->getZExtValue()));
6880b57cec5SDimitry Andric   Kern[".language_version"] = LanguageVersion;
6890b57cec5SDimitry Andric }
6900b57cec5SDimitry Andric 
6910b57cec5SDimitry Andric void MetadataStreamerV3::emitKernelAttrs(const Function &Func,
6920b57cec5SDimitry Andric                                          msgpack::MapDocNode Kern) {
6930b57cec5SDimitry Andric 
6940b57cec5SDimitry Andric   if (auto Node = Func.getMetadata("reqd_work_group_size"))
6950b57cec5SDimitry Andric     Kern[".reqd_workgroup_size"] = getWorkGroupDimensions(Node);
6960b57cec5SDimitry Andric   if (auto Node = Func.getMetadata("work_group_size_hint"))
6970b57cec5SDimitry Andric     Kern[".workgroup_size_hint"] = getWorkGroupDimensions(Node);
6980b57cec5SDimitry Andric   if (auto Node = Func.getMetadata("vec_type_hint")) {
6990b57cec5SDimitry Andric     Kern[".vec_type_hint"] = Kern.getDocument()->getNode(
7000b57cec5SDimitry Andric         getTypeName(
7010b57cec5SDimitry Andric             cast<ValueAsMetadata>(Node->getOperand(0))->getType(),
7020b57cec5SDimitry Andric             mdconst::extract<ConstantInt>(Node->getOperand(1))->getZExtValue()),
7030b57cec5SDimitry Andric         /*Copy=*/true);
7040b57cec5SDimitry Andric   }
7050b57cec5SDimitry Andric   if (Func.hasFnAttribute("runtime-handle")) {
7060b57cec5SDimitry Andric     Kern[".device_enqueue_symbol"] = Kern.getDocument()->getNode(
7070b57cec5SDimitry Andric         Func.getFnAttribute("runtime-handle").getValueAsString().str(),
7080b57cec5SDimitry Andric         /*Copy=*/true);
7090b57cec5SDimitry Andric   }
7100b57cec5SDimitry Andric }
7110b57cec5SDimitry Andric 
7120b57cec5SDimitry Andric void MetadataStreamerV3::emitKernelArgs(const Function &Func,
7130b57cec5SDimitry Andric                                         msgpack::MapDocNode Kern) {
7140b57cec5SDimitry Andric   unsigned Offset = 0;
7150b57cec5SDimitry Andric   auto Args = HSAMetadataDoc->getArrayNode();
7160b57cec5SDimitry Andric   for (auto &Arg : Func.args())
7170b57cec5SDimitry Andric     emitKernelArg(Arg, Offset, Args);
7180b57cec5SDimitry Andric 
7190b57cec5SDimitry Andric   emitHiddenKernelArgs(Func, Offset, Args);
7200b57cec5SDimitry Andric 
7210b57cec5SDimitry Andric   Kern[".args"] = Args;
7220b57cec5SDimitry Andric }
7230b57cec5SDimitry Andric 
7240b57cec5SDimitry Andric void MetadataStreamerV3::emitKernelArg(const Argument &Arg, unsigned &Offset,
7250b57cec5SDimitry Andric                                        msgpack::ArrayDocNode Args) {
7260b57cec5SDimitry Andric   auto Func = Arg.getParent();
7270b57cec5SDimitry Andric   auto ArgNo = Arg.getArgNo();
7280b57cec5SDimitry Andric   const MDNode *Node;
7290b57cec5SDimitry Andric 
7300b57cec5SDimitry Andric   StringRef Name;
7310b57cec5SDimitry Andric   Node = Func->getMetadata("kernel_arg_name");
7320b57cec5SDimitry Andric   if (Node && ArgNo < Node->getNumOperands())
7330b57cec5SDimitry Andric     Name = cast<MDString>(Node->getOperand(ArgNo))->getString();
7340b57cec5SDimitry Andric   else if (Arg.hasName())
7350b57cec5SDimitry Andric     Name = Arg.getName();
7360b57cec5SDimitry Andric 
7370b57cec5SDimitry Andric   StringRef TypeName;
7380b57cec5SDimitry Andric   Node = Func->getMetadata("kernel_arg_type");
7390b57cec5SDimitry Andric   if (Node && ArgNo < Node->getNumOperands())
7400b57cec5SDimitry Andric     TypeName = cast<MDString>(Node->getOperand(ArgNo))->getString();
7410b57cec5SDimitry Andric 
7420b57cec5SDimitry Andric   StringRef BaseTypeName;
7430b57cec5SDimitry Andric   Node = Func->getMetadata("kernel_arg_base_type");
7440b57cec5SDimitry Andric   if (Node && ArgNo < Node->getNumOperands())
7450b57cec5SDimitry Andric     BaseTypeName = cast<MDString>(Node->getOperand(ArgNo))->getString();
7460b57cec5SDimitry Andric 
7470b57cec5SDimitry Andric   StringRef AccQual;
7480b57cec5SDimitry Andric   if (Arg.getType()->isPointerTy() && Arg.onlyReadsMemory() &&
7490b57cec5SDimitry Andric       Arg.hasNoAliasAttr()) {
7500b57cec5SDimitry Andric     AccQual = "read_only";
7510b57cec5SDimitry Andric   } else {
7520b57cec5SDimitry Andric     Node = Func->getMetadata("kernel_arg_access_qual");
7530b57cec5SDimitry Andric     if (Node && ArgNo < Node->getNumOperands())
7540b57cec5SDimitry Andric       AccQual = cast<MDString>(Node->getOperand(ArgNo))->getString();
7550b57cec5SDimitry Andric   }
7560b57cec5SDimitry Andric 
7570b57cec5SDimitry Andric   StringRef TypeQual;
7580b57cec5SDimitry Andric   Node = Func->getMetadata("kernel_arg_type_qual");
7590b57cec5SDimitry Andric   if (Node && ArgNo < Node->getNumOperands())
7600b57cec5SDimitry Andric     TypeQual = cast<MDString>(Node->getOperand(ArgNo))->getString();
7610b57cec5SDimitry Andric 
7620b57cec5SDimitry Andric   Type *Ty = Arg.getType();
7630b57cec5SDimitry Andric   const DataLayout &DL = Func->getParent()->getDataLayout();
7640b57cec5SDimitry Andric 
7650b57cec5SDimitry Andric   unsigned PointeeAlign = 0;
7660b57cec5SDimitry Andric   if (auto PtrTy = dyn_cast<PointerType>(Ty)) {
7670b57cec5SDimitry Andric     if (PtrTy->getAddressSpace() == AMDGPUAS::LOCAL_ADDRESS) {
7680b57cec5SDimitry Andric       PointeeAlign = Arg.getParamAlignment();
7690b57cec5SDimitry Andric       if (PointeeAlign == 0)
7700b57cec5SDimitry Andric         PointeeAlign = DL.getABITypeAlignment(PtrTy->getElementType());
7710b57cec5SDimitry Andric     }
7720b57cec5SDimitry Andric   }
7730b57cec5SDimitry Andric 
7740b57cec5SDimitry Andric   emitKernelArg(Func->getParent()->getDataLayout(), Arg.getType(),
7750b57cec5SDimitry Andric                 getValueKind(Arg.getType(), TypeQual, BaseTypeName), Offset,
7760b57cec5SDimitry Andric                 Args, PointeeAlign, Name, TypeName, BaseTypeName, AccQual,
7770b57cec5SDimitry Andric                 TypeQual);
7780b57cec5SDimitry Andric }
7790b57cec5SDimitry Andric 
7800b57cec5SDimitry Andric void MetadataStreamerV3::emitKernelArg(const DataLayout &DL, Type *Ty,
7810b57cec5SDimitry Andric                                        StringRef ValueKind, unsigned &Offset,
7820b57cec5SDimitry Andric                                        msgpack::ArrayDocNode Args,
7830b57cec5SDimitry Andric                                        unsigned PointeeAlign, StringRef Name,
7840b57cec5SDimitry Andric                                        StringRef TypeName,
7850b57cec5SDimitry Andric                                        StringRef BaseTypeName,
7860b57cec5SDimitry Andric                                        StringRef AccQual, StringRef TypeQual) {
7870b57cec5SDimitry Andric   auto Arg = Args.getDocument()->getMapNode();
7880b57cec5SDimitry Andric 
7890b57cec5SDimitry Andric   if (!Name.empty())
7900b57cec5SDimitry Andric     Arg[".name"] = Arg.getDocument()->getNode(Name, /*Copy=*/true);
7910b57cec5SDimitry Andric   if (!TypeName.empty())
7920b57cec5SDimitry Andric     Arg[".type_name"] = Arg.getDocument()->getNode(TypeName, /*Copy=*/true);
7930b57cec5SDimitry Andric   auto Size = DL.getTypeAllocSize(Ty);
7940b57cec5SDimitry Andric   auto Align = DL.getABITypeAlignment(Ty);
7950b57cec5SDimitry Andric   Arg[".size"] = Arg.getDocument()->getNode(Size);
7960b57cec5SDimitry Andric   Offset = alignTo(Offset, Align);
7970b57cec5SDimitry Andric   Arg[".offset"] = Arg.getDocument()->getNode(Offset);
7980b57cec5SDimitry Andric   Offset += Size;
7990b57cec5SDimitry Andric   Arg[".value_kind"] = Arg.getDocument()->getNode(ValueKind, /*Copy=*/true);
8000b57cec5SDimitry Andric   Arg[".value_type"] =
8010b57cec5SDimitry Andric       Arg.getDocument()->getNode(getValueType(Ty, BaseTypeName), /*Copy=*/true);
8020b57cec5SDimitry Andric   if (PointeeAlign)
8030b57cec5SDimitry Andric     Arg[".pointee_align"] = Arg.getDocument()->getNode(PointeeAlign);
8040b57cec5SDimitry Andric 
8050b57cec5SDimitry Andric   if (auto PtrTy = dyn_cast<PointerType>(Ty))
8060b57cec5SDimitry Andric     if (auto Qualifier = getAddressSpaceQualifier(PtrTy->getAddressSpace()))
8070b57cec5SDimitry Andric       Arg[".address_space"] = Arg.getDocument()->getNode(*Qualifier, /*Copy=*/true);
8080b57cec5SDimitry Andric 
8090b57cec5SDimitry Andric   if (auto AQ = getAccessQualifier(AccQual))
8100b57cec5SDimitry Andric     Arg[".access"] = Arg.getDocument()->getNode(*AQ, /*Copy=*/true);
8110b57cec5SDimitry Andric 
8120b57cec5SDimitry Andric   // TODO: Emit Arg[".actual_access"].
8130b57cec5SDimitry Andric 
8140b57cec5SDimitry Andric   SmallVector<StringRef, 1> SplitTypeQuals;
8150b57cec5SDimitry Andric   TypeQual.split(SplitTypeQuals, " ", -1, false);
8160b57cec5SDimitry Andric   for (StringRef Key : SplitTypeQuals) {
8170b57cec5SDimitry Andric     if (Key == "const")
8180b57cec5SDimitry Andric       Arg[".is_const"] = Arg.getDocument()->getNode(true);
8190b57cec5SDimitry Andric     else if (Key == "restrict")
8200b57cec5SDimitry Andric       Arg[".is_restrict"] = Arg.getDocument()->getNode(true);
8210b57cec5SDimitry Andric     else if (Key == "volatile")
8220b57cec5SDimitry Andric       Arg[".is_volatile"] = Arg.getDocument()->getNode(true);
8230b57cec5SDimitry Andric     else if (Key == "pipe")
8240b57cec5SDimitry Andric       Arg[".is_pipe"] = Arg.getDocument()->getNode(true);
8250b57cec5SDimitry Andric   }
8260b57cec5SDimitry Andric 
8270b57cec5SDimitry Andric   Args.push_back(Arg);
8280b57cec5SDimitry Andric }
8290b57cec5SDimitry Andric 
8300b57cec5SDimitry Andric void MetadataStreamerV3::emitHiddenKernelArgs(const Function &Func,
8310b57cec5SDimitry Andric                                               unsigned &Offset,
8320b57cec5SDimitry Andric                                               msgpack::ArrayDocNode Args) {
8330b57cec5SDimitry Andric   int HiddenArgNumBytes =
8340b57cec5SDimitry Andric       getIntegerAttribute(Func, "amdgpu-implicitarg-num-bytes", 0);
8350b57cec5SDimitry Andric 
8360b57cec5SDimitry Andric   if (!HiddenArgNumBytes)
8370b57cec5SDimitry Andric     return;
8380b57cec5SDimitry Andric 
8390b57cec5SDimitry Andric   auto &DL = Func.getParent()->getDataLayout();
8400b57cec5SDimitry Andric   auto Int64Ty = Type::getInt64Ty(Func.getContext());
8410b57cec5SDimitry Andric 
8420b57cec5SDimitry Andric   if (HiddenArgNumBytes >= 8)
8430b57cec5SDimitry Andric     emitKernelArg(DL, Int64Ty, "hidden_global_offset_x", Offset, Args);
8440b57cec5SDimitry Andric   if (HiddenArgNumBytes >= 16)
8450b57cec5SDimitry Andric     emitKernelArg(DL, Int64Ty, "hidden_global_offset_y", Offset, Args);
8460b57cec5SDimitry Andric   if (HiddenArgNumBytes >= 24)
8470b57cec5SDimitry Andric     emitKernelArg(DL, Int64Ty, "hidden_global_offset_z", Offset, Args);
8480b57cec5SDimitry Andric 
8490b57cec5SDimitry Andric   auto Int8PtrTy =
8500b57cec5SDimitry Andric       Type::getInt8PtrTy(Func.getContext(), AMDGPUAS::GLOBAL_ADDRESS);
8510b57cec5SDimitry Andric 
8520b57cec5SDimitry Andric   // Emit "printf buffer" argument if printf is used, otherwise emit dummy
8530b57cec5SDimitry Andric   // "none" argument.
8540b57cec5SDimitry Andric   if (HiddenArgNumBytes >= 32) {
8550b57cec5SDimitry Andric     if (Func.getParent()->getNamedMetadata("llvm.printf.fmts"))
8560b57cec5SDimitry Andric       emitKernelArg(DL, Int8PtrTy, "hidden_printf_buffer", Offset, Args);
8570b57cec5SDimitry Andric     else
8580b57cec5SDimitry Andric       emitKernelArg(DL, Int8PtrTy, "hidden_none", Offset, Args);
8590b57cec5SDimitry Andric   }
8600b57cec5SDimitry Andric 
8610b57cec5SDimitry Andric   // Emit "default queue" and "completion action" arguments if enqueue kernel is
8620b57cec5SDimitry Andric   // used, otherwise emit dummy "none" arguments.
8630b57cec5SDimitry Andric   if (HiddenArgNumBytes >= 48) {
8640b57cec5SDimitry Andric     if (Func.hasFnAttribute("calls-enqueue-kernel")) {
8650b57cec5SDimitry Andric       emitKernelArg(DL, Int8PtrTy, "hidden_default_queue", Offset, Args);
8660b57cec5SDimitry Andric       emitKernelArg(DL, Int8PtrTy, "hidden_completion_action", Offset, Args);
8670b57cec5SDimitry Andric     } else {
8680b57cec5SDimitry Andric       emitKernelArg(DL, Int8PtrTy, "hidden_none", Offset, Args);
8690b57cec5SDimitry Andric       emitKernelArg(DL, Int8PtrTy, "hidden_none", Offset, Args);
8700b57cec5SDimitry Andric     }
8710b57cec5SDimitry Andric   }
8720b57cec5SDimitry Andric 
8730b57cec5SDimitry Andric   // Emit the pointer argument for multi-grid object.
8740b57cec5SDimitry Andric   if (HiddenArgNumBytes >= 56)
8750b57cec5SDimitry Andric     emitKernelArg(DL, Int8PtrTy, "hidden_multigrid_sync_arg", Offset, Args);
8760b57cec5SDimitry Andric }
8770b57cec5SDimitry Andric 
8780b57cec5SDimitry Andric msgpack::MapDocNode
8790b57cec5SDimitry Andric MetadataStreamerV3::getHSAKernelProps(const MachineFunction &MF,
8800b57cec5SDimitry Andric                                       const SIProgramInfo &ProgramInfo) const {
8810b57cec5SDimitry Andric   const GCNSubtarget &STM = MF.getSubtarget<GCNSubtarget>();
8820b57cec5SDimitry Andric   const SIMachineFunctionInfo &MFI = *MF.getInfo<SIMachineFunctionInfo>();
8830b57cec5SDimitry Andric   const Function &F = MF.getFunction();
8840b57cec5SDimitry Andric 
8850b57cec5SDimitry Andric   auto Kern = HSAMetadataDoc->getMapNode();
8860b57cec5SDimitry Andric 
887*8bcb0991SDimitry Andric   Align MaxKernArgAlign;
8880b57cec5SDimitry Andric   Kern[".kernarg_segment_size"] = Kern.getDocument()->getNode(
8890b57cec5SDimitry Andric       STM.getKernArgSegmentSize(F, MaxKernArgAlign));
8900b57cec5SDimitry Andric   Kern[".group_segment_fixed_size"] =
8910b57cec5SDimitry Andric       Kern.getDocument()->getNode(ProgramInfo.LDSSize);
8920b57cec5SDimitry Andric   Kern[".private_segment_fixed_size"] =
8930b57cec5SDimitry Andric       Kern.getDocument()->getNode(ProgramInfo.ScratchSize);
8940b57cec5SDimitry Andric   Kern[".kernarg_segment_align"] =
895*8bcb0991SDimitry Andric       Kern.getDocument()->getNode(std::max(Align(4), MaxKernArgAlign).value());
8960b57cec5SDimitry Andric   Kern[".wavefront_size"] =
8970b57cec5SDimitry Andric       Kern.getDocument()->getNode(STM.getWavefrontSize());
8980b57cec5SDimitry Andric   Kern[".sgpr_count"] = Kern.getDocument()->getNode(ProgramInfo.NumSGPR);
8990b57cec5SDimitry Andric   Kern[".vgpr_count"] = Kern.getDocument()->getNode(ProgramInfo.NumVGPR);
9000b57cec5SDimitry Andric   Kern[".max_flat_workgroup_size"] =
9010b57cec5SDimitry Andric       Kern.getDocument()->getNode(MFI.getMaxFlatWorkGroupSize());
9020b57cec5SDimitry Andric   Kern[".sgpr_spill_count"] =
9030b57cec5SDimitry Andric       Kern.getDocument()->getNode(MFI.getNumSpilledSGPRs());
9040b57cec5SDimitry Andric   Kern[".vgpr_spill_count"] =
9050b57cec5SDimitry Andric       Kern.getDocument()->getNode(MFI.getNumSpilledVGPRs());
9060b57cec5SDimitry Andric 
9070b57cec5SDimitry Andric   return Kern;
9080b57cec5SDimitry Andric }
9090b57cec5SDimitry Andric 
9100b57cec5SDimitry Andric bool MetadataStreamerV3::emitTo(AMDGPUTargetStreamer &TargetStreamer) {
9110b57cec5SDimitry Andric   return TargetStreamer.EmitHSAMetadata(*HSAMetadataDoc, true);
9120b57cec5SDimitry Andric }
9130b57cec5SDimitry Andric 
9140b57cec5SDimitry Andric void MetadataStreamerV3::begin(const Module &Mod) {
9150b57cec5SDimitry Andric   emitVersion();
9160b57cec5SDimitry Andric   emitPrintf(Mod);
9170b57cec5SDimitry Andric   getRootMetadata("amdhsa.kernels") = HSAMetadataDoc->getArrayNode();
9180b57cec5SDimitry Andric }
9190b57cec5SDimitry Andric 
9200b57cec5SDimitry Andric void MetadataStreamerV3::end() {
9210b57cec5SDimitry Andric   std::string HSAMetadataString;
9220b57cec5SDimitry Andric   raw_string_ostream StrOS(HSAMetadataString);
9230b57cec5SDimitry Andric   HSAMetadataDoc->toYAML(StrOS);
9240b57cec5SDimitry Andric 
9250b57cec5SDimitry Andric   if (DumpHSAMetadata)
9260b57cec5SDimitry Andric     dump(StrOS.str());
9270b57cec5SDimitry Andric   if (VerifyHSAMetadata)
9280b57cec5SDimitry Andric     verify(StrOS.str());
9290b57cec5SDimitry Andric }
9300b57cec5SDimitry Andric 
9310b57cec5SDimitry Andric void MetadataStreamerV3::emitKernel(const MachineFunction &MF,
9320b57cec5SDimitry Andric                                     const SIProgramInfo &ProgramInfo) {
9330b57cec5SDimitry Andric   auto &Func = MF.getFunction();
9340b57cec5SDimitry Andric   auto Kern = getHSAKernelProps(MF, ProgramInfo);
9350b57cec5SDimitry Andric 
9360b57cec5SDimitry Andric   assert(Func.getCallingConv() == CallingConv::AMDGPU_KERNEL ||
9370b57cec5SDimitry Andric          Func.getCallingConv() == CallingConv::SPIR_KERNEL);
9380b57cec5SDimitry Andric 
9390b57cec5SDimitry Andric   auto Kernels =
9400b57cec5SDimitry Andric       getRootMetadata("amdhsa.kernels").getArray(/*Convert=*/true);
9410b57cec5SDimitry Andric 
9420b57cec5SDimitry Andric   {
9430b57cec5SDimitry Andric     Kern[".name"] = Kern.getDocument()->getNode(Func.getName());
9440b57cec5SDimitry Andric     Kern[".symbol"] = Kern.getDocument()->getNode(
9450b57cec5SDimitry Andric         (Twine(Func.getName()) + Twine(".kd")).str(), /*Copy=*/true);
9460b57cec5SDimitry Andric     emitKernelLanguage(Func, Kern);
9470b57cec5SDimitry Andric     emitKernelAttrs(Func, Kern);
9480b57cec5SDimitry Andric     emitKernelArgs(Func, Kern);
9490b57cec5SDimitry Andric   }
9500b57cec5SDimitry Andric 
9510b57cec5SDimitry Andric   Kernels.push_back(Kern);
9520b57cec5SDimitry Andric }
9530b57cec5SDimitry Andric 
9540b57cec5SDimitry Andric } // end namespace HSAMD
9550b57cec5SDimitry Andric } // end namespace AMDGPU
9560b57cec5SDimitry Andric } // end namespace llvm
957