101ce144dSScott Linder //===--- AMDGPUHSAMetadataStreamer.cpp --------------------------*- C++ -*-===//
201ce144dSScott Linder //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
601ce144dSScott Linder //
701ce144dSScott Linder //===----------------------------------------------------------------------===//
801ce144dSScott Linder //
901ce144dSScott Linder /// \file
1001ce144dSScott Linder /// AMDGPU HSA Metadata Streamer.
1101ce144dSScott Linder ///
1201ce144dSScott Linder //
1301ce144dSScott Linder //===----------------------------------------------------------------------===//
1401ce144dSScott Linder 
1501ce144dSScott Linder #include "AMDGPUHSAMetadataStreamer.h"
1601ce144dSScott Linder #include "AMDGPU.h"
1701ce144dSScott Linder #include "AMDGPUSubtarget.h"
18f5b36e56SScott Linder #include "MCTargetDesc/AMDGPUTargetStreamer.h"
1901ce144dSScott Linder #include "SIMachineFunctionInfo.h"
2001ce144dSScott Linder #include "SIProgramInfo.h"
2101ce144dSScott Linder #include "Utils/AMDGPUBaseInfo.h"
2201ce144dSScott Linder #include "llvm/ADT/StringSwitch.h"
2301ce144dSScott Linder #include "llvm/IR/Constants.h"
2401ce144dSScott Linder #include "llvm/IR/Module.h"
2501ce144dSScott Linder #include "llvm/Support/raw_ostream.h"
2601ce144dSScott Linder 
2701ce144dSScott Linder namespace llvm {
2801ce144dSScott Linder 
2901ce144dSScott Linder static cl::opt<bool> DumpHSAMetadata(
3001ce144dSScott Linder     "amdgpu-dump-hsa-metadata",
3101ce144dSScott Linder     cl::desc("Dump AMDGPU HSA Metadata"));
3201ce144dSScott Linder static cl::opt<bool> VerifyHSAMetadata(
3301ce144dSScott Linder     "amdgpu-verify-hsa-metadata",
3401ce144dSScott Linder     cl::desc("Verify AMDGPU HSA Metadata"));
3501ce144dSScott Linder 
3601ce144dSScott Linder namespace AMDGPU {
3701ce144dSScott Linder namespace HSAMD {
3801ce144dSScott Linder 
39f5b36e56SScott Linder //===----------------------------------------------------------------------===//
40f5b36e56SScott Linder // HSAMetadataStreamerV2
41f5b36e56SScott Linder //===----------------------------------------------------------------------===//
42f5b36e56SScott Linder void MetadataStreamerV2::dump(StringRef HSAMetadataString) const {
4301ce144dSScott Linder   errs() << "AMDGPU HSA Metadata:\n" << HSAMetadataString << '\n';
4401ce144dSScott Linder }
4501ce144dSScott Linder 
46f5b36e56SScott Linder void MetadataStreamerV2::verify(StringRef HSAMetadataString) const {
4701ce144dSScott Linder   errs() << "AMDGPU HSA Metadata Parser Test: ";
4801ce144dSScott Linder 
4901ce144dSScott Linder   HSAMD::Metadata FromHSAMetadataString;
5001ce144dSScott Linder   if (fromString(HSAMetadataString, FromHSAMetadataString)) {
5101ce144dSScott Linder     errs() << "FAIL\n";
5201ce144dSScott Linder     return;
5301ce144dSScott Linder   }
5401ce144dSScott Linder 
5501ce144dSScott Linder   std::string ToHSAMetadataString;
5601ce144dSScott Linder   if (toString(FromHSAMetadataString, ToHSAMetadataString)) {
5701ce144dSScott Linder     errs() << "FAIL\n";
5801ce144dSScott Linder     return;
5901ce144dSScott Linder   }
6001ce144dSScott Linder 
6101ce144dSScott Linder   errs() << (HSAMetadataString == ToHSAMetadataString ? "PASS" : "FAIL")
6201ce144dSScott Linder          << '\n';
6301ce144dSScott Linder   if (HSAMetadataString != ToHSAMetadataString) {
6401ce144dSScott Linder     errs() << "Original input: " << HSAMetadataString << '\n'
6501ce144dSScott Linder            << "Produced output: " << ToHSAMetadataString << '\n';
6601ce144dSScott Linder   }
6701ce144dSScott Linder }
6801ce144dSScott Linder 
69f5b36e56SScott Linder AccessQualifier
70f5b36e56SScott Linder MetadataStreamerV2::getAccessQualifier(StringRef AccQual) const {
7101ce144dSScott Linder   if (AccQual.empty())
7201ce144dSScott Linder     return AccessQualifier::Unknown;
7301ce144dSScott Linder 
7401ce144dSScott Linder   return StringSwitch<AccessQualifier>(AccQual)
7501ce144dSScott Linder              .Case("read_only",  AccessQualifier::ReadOnly)
7601ce144dSScott Linder              .Case("write_only", AccessQualifier::WriteOnly)
7701ce144dSScott Linder              .Case("read_write", AccessQualifier::ReadWrite)
7801ce144dSScott Linder              .Default(AccessQualifier::Default);
7901ce144dSScott Linder }
8001ce144dSScott Linder 
81f5b36e56SScott Linder AddressSpaceQualifier
82f5b36e56SScott Linder MetadataStreamerV2::getAddressSpaceQualifier(
8301ce144dSScott Linder     unsigned AddressSpace) const {
84b9986746SMatt Arsenault   switch (AddressSpace) {
85b9986746SMatt Arsenault   case AMDGPUAS::PRIVATE_ADDRESS:
8601ce144dSScott Linder     return AddressSpaceQualifier::Private;
87b9986746SMatt Arsenault   case AMDGPUAS::GLOBAL_ADDRESS:
8801ce144dSScott Linder     return AddressSpaceQualifier::Global;
89b9986746SMatt Arsenault   case AMDGPUAS::CONSTANT_ADDRESS:
9001ce144dSScott Linder     return AddressSpaceQualifier::Constant;
91b9986746SMatt Arsenault   case AMDGPUAS::LOCAL_ADDRESS:
9201ce144dSScott Linder     return AddressSpaceQualifier::Local;
93b9986746SMatt Arsenault   case AMDGPUAS::FLAT_ADDRESS:
9401ce144dSScott Linder     return AddressSpaceQualifier::Generic;
95b9986746SMatt Arsenault   case AMDGPUAS::REGION_ADDRESS:
9601ce144dSScott Linder     return AddressSpaceQualifier::Region;
97b9986746SMatt Arsenault   default:
98b9986746SMatt Arsenault     return AddressSpaceQualifier::Unknown;
99b9986746SMatt Arsenault   }
10001ce144dSScott Linder }
10101ce144dSScott Linder 
102f5b36e56SScott Linder ValueKind MetadataStreamerV2::getValueKind(Type *Ty, StringRef TypeQual,
10301ce144dSScott Linder                                            StringRef BaseTypeName) const {
10401ce144dSScott Linder   if (TypeQual.find("pipe") != StringRef::npos)
10501ce144dSScott Linder     return ValueKind::Pipe;
10601ce144dSScott Linder 
10701ce144dSScott Linder   return StringSwitch<ValueKind>(BaseTypeName)
10801ce144dSScott Linder              .Case("image1d_t", ValueKind::Image)
10901ce144dSScott Linder              .Case("image1d_array_t", ValueKind::Image)
11001ce144dSScott Linder              .Case("image1d_buffer_t", ValueKind::Image)
11101ce144dSScott Linder              .Case("image2d_t", ValueKind::Image)
11201ce144dSScott Linder              .Case("image2d_array_t", ValueKind::Image)
11301ce144dSScott Linder              .Case("image2d_array_depth_t", ValueKind::Image)
11401ce144dSScott Linder              .Case("image2d_array_msaa_t", ValueKind::Image)
11501ce144dSScott Linder              .Case("image2d_array_msaa_depth_t", ValueKind::Image)
11601ce144dSScott Linder              .Case("image2d_depth_t", ValueKind::Image)
11701ce144dSScott Linder              .Case("image2d_msaa_t", ValueKind::Image)
11801ce144dSScott Linder              .Case("image2d_msaa_depth_t", ValueKind::Image)
11901ce144dSScott Linder              .Case("image3d_t", ValueKind::Image)
12001ce144dSScott Linder              .Case("sampler_t", ValueKind::Sampler)
12101ce144dSScott Linder              .Case("queue_t", ValueKind::Queue)
12201ce144dSScott Linder              .Default(isa<PointerType>(Ty) ?
12301ce144dSScott Linder                           (Ty->getPointerAddressSpace() ==
1240da6350dSMatt Arsenault                            AMDGPUAS::LOCAL_ADDRESS ?
12501ce144dSScott Linder                            ValueKind::DynamicSharedPointer :
12601ce144dSScott Linder                            ValueKind::GlobalBuffer) :
12701ce144dSScott Linder                       ValueKind::ByValue);
12801ce144dSScott Linder }
12901ce144dSScott Linder 
130f5b36e56SScott Linder ValueType MetadataStreamerV2::getValueType(Type *Ty, StringRef TypeName) const {
13101ce144dSScott Linder   switch (Ty->getTypeID()) {
13201ce144dSScott Linder   case Type::IntegerTyID: {
13301ce144dSScott Linder     auto Signed = !TypeName.startswith("u");
13401ce144dSScott Linder     switch (Ty->getIntegerBitWidth()) {
13501ce144dSScott Linder     case 8:
13601ce144dSScott Linder       return Signed ? ValueType::I8 : ValueType::U8;
13701ce144dSScott Linder     case 16:
13801ce144dSScott Linder       return Signed ? ValueType::I16 : ValueType::U16;
13901ce144dSScott Linder     case 32:
14001ce144dSScott Linder       return Signed ? ValueType::I32 : ValueType::U32;
14101ce144dSScott Linder     case 64:
14201ce144dSScott Linder       return Signed ? ValueType::I64 : ValueType::U64;
14301ce144dSScott Linder     default:
14401ce144dSScott Linder       return ValueType::Struct;
14501ce144dSScott Linder     }
14601ce144dSScott Linder   }
14701ce144dSScott Linder   case Type::HalfTyID:
14801ce144dSScott Linder     return ValueType::F16;
14901ce144dSScott Linder   case Type::FloatTyID:
15001ce144dSScott Linder     return ValueType::F32;
15101ce144dSScott Linder   case Type::DoubleTyID:
15201ce144dSScott Linder     return ValueType::F64;
15301ce144dSScott Linder   case Type::PointerTyID:
15401ce144dSScott Linder     return getValueType(Ty->getPointerElementType(), TypeName);
15501ce144dSScott Linder   case Type::VectorTyID:
15601ce144dSScott Linder     return getValueType(Ty->getVectorElementType(), TypeName);
15701ce144dSScott Linder   default:
15801ce144dSScott Linder     return ValueType::Struct;
15901ce144dSScott Linder   }
16001ce144dSScott Linder }
16101ce144dSScott Linder 
162f5b36e56SScott Linder std::string MetadataStreamerV2::getTypeName(Type *Ty, bool Signed) const {
16301ce144dSScott Linder   switch (Ty->getTypeID()) {
16401ce144dSScott Linder   case Type::IntegerTyID: {
16501ce144dSScott Linder     if (!Signed)
16601ce144dSScott Linder       return (Twine('u') + getTypeName(Ty, true)).str();
16701ce144dSScott Linder 
16801ce144dSScott Linder     auto BitWidth = Ty->getIntegerBitWidth();
16901ce144dSScott Linder     switch (BitWidth) {
17001ce144dSScott Linder     case 8:
17101ce144dSScott Linder       return "char";
17201ce144dSScott Linder     case 16:
17301ce144dSScott Linder       return "short";
17401ce144dSScott Linder     case 32:
17501ce144dSScott Linder       return "int";
17601ce144dSScott Linder     case 64:
17701ce144dSScott Linder       return "long";
17801ce144dSScott Linder     default:
17901ce144dSScott Linder       return (Twine('i') + Twine(BitWidth)).str();
18001ce144dSScott Linder     }
18101ce144dSScott Linder   }
18201ce144dSScott Linder   case Type::HalfTyID:
18301ce144dSScott Linder     return "half";
18401ce144dSScott Linder   case Type::FloatTyID:
18501ce144dSScott Linder     return "float";
18601ce144dSScott Linder   case Type::DoubleTyID:
18701ce144dSScott Linder     return "double";
18801ce144dSScott Linder   case Type::VectorTyID: {
18901ce144dSScott Linder     auto VecTy = cast<VectorType>(Ty);
19001ce144dSScott Linder     auto ElTy = VecTy->getElementType();
19101ce144dSScott Linder     auto NumElements = VecTy->getVectorNumElements();
19201ce144dSScott Linder     return (Twine(getTypeName(ElTy, Signed)) + Twine(NumElements)).str();
19301ce144dSScott Linder   }
19401ce144dSScott Linder   default:
19501ce144dSScott Linder     return "unknown";
19601ce144dSScott Linder   }
19701ce144dSScott Linder }
19801ce144dSScott Linder 
199f5b36e56SScott Linder std::vector<uint32_t>
200f5b36e56SScott Linder MetadataStreamerV2::getWorkGroupDimensions(MDNode *Node) const {
20101ce144dSScott Linder   std::vector<uint32_t> Dims;
20201ce144dSScott Linder   if (Node->getNumOperands() != 3)
20301ce144dSScott Linder     return Dims;
20401ce144dSScott Linder 
20501ce144dSScott Linder   for (auto &Op : Node->operands())
20601ce144dSScott Linder     Dims.push_back(mdconst::extract<ConstantInt>(Op)->getZExtValue());
20701ce144dSScott Linder   return Dims;
20801ce144dSScott Linder }
20901ce144dSScott Linder 
210f5b36e56SScott Linder Kernel::CodeProps::Metadata
211f5b36e56SScott Linder MetadataStreamerV2::getHSACodeProps(const MachineFunction &MF,
21201ce144dSScott Linder                                     const SIProgramInfo &ProgramInfo) const {
2135bfbae5cSTom Stellard   const GCNSubtarget &STM = MF.getSubtarget<GCNSubtarget>();
21401ce144dSScott Linder   const SIMachineFunctionInfo &MFI = *MF.getInfo<SIMachineFunctionInfo>();
21501ce144dSScott Linder   HSAMD::Kernel::CodeProps::Metadata HSACodeProps;
21601ce144dSScott Linder   const Function &F = MF.getFunction();
21701ce144dSScott Linder 
2184bec7d42SMatt Arsenault   assert(F.getCallingConv() == CallingConv::AMDGPU_KERNEL ||
2194bec7d42SMatt Arsenault          F.getCallingConv() == CallingConv::SPIR_KERNEL);
22001ce144dSScott Linder 
221b65fa483SGuillaume Chatelet   Align MaxKernArgAlign;
2224bec7d42SMatt Arsenault   HSACodeProps.mKernargSegmentSize = STM.getKernArgSegmentSize(F,
2234bec7d42SMatt Arsenault                                                                MaxKernArgAlign);
22401ce144dSScott Linder   HSACodeProps.mGroupSegmentFixedSize = ProgramInfo.LDSSize;
22501ce144dSScott Linder   HSACodeProps.mPrivateSegmentFixedSize = ProgramInfo.ScratchSize;
226b65fa483SGuillaume Chatelet   HSACodeProps.mKernargSegmentAlign =
227b65fa483SGuillaume Chatelet       std::max(MaxKernArgAlign, Align(4)).value();
22801ce144dSScott Linder   HSACodeProps.mWavefrontSize = STM.getWavefrontSize();
22901ce144dSScott Linder   HSACodeProps.mNumSGPRs = ProgramInfo.NumSGPR;
23001ce144dSScott Linder   HSACodeProps.mNumVGPRs = ProgramInfo.NumVGPR;
23101ce144dSScott Linder   HSACodeProps.mMaxFlatWorkGroupSize = MFI.getMaxFlatWorkGroupSize();
23201ce144dSScott Linder   HSACodeProps.mIsDynamicCallStack = ProgramInfo.DynamicCallStack;
23301ce144dSScott Linder   HSACodeProps.mIsXNACKEnabled = STM.isXNACKEnabled();
23401ce144dSScott Linder   HSACodeProps.mNumSpilledSGPRs = MFI.getNumSpilledSGPRs();
23501ce144dSScott Linder   HSACodeProps.mNumSpilledVGPRs = MFI.getNumSpilledVGPRs();
23601ce144dSScott Linder 
23701ce144dSScott Linder   return HSACodeProps;
23801ce144dSScott Linder }
23901ce144dSScott Linder 
240f5b36e56SScott Linder Kernel::DebugProps::Metadata
241f5b36e56SScott Linder MetadataStreamerV2::getHSADebugProps(const MachineFunction &MF,
24201ce144dSScott Linder                                      const SIProgramInfo &ProgramInfo) const {
243aa6fb4c4SMatt Arsenault   return HSAMD::Kernel::DebugProps::Metadata();
24401ce144dSScott Linder }
24501ce144dSScott Linder 
246f5b36e56SScott Linder void MetadataStreamerV2::emitVersion() {
24701ce144dSScott Linder   auto &Version = HSAMetadata.mVersion;
24801ce144dSScott Linder 
24901ce144dSScott Linder   Version.push_back(VersionMajor);
25001ce144dSScott Linder   Version.push_back(VersionMinor);
25101ce144dSScott Linder }
25201ce144dSScott Linder 
253f5b36e56SScott Linder void MetadataStreamerV2::emitPrintf(const Module &Mod) {
25401ce144dSScott Linder   auto &Printf = HSAMetadata.mPrintf;
25501ce144dSScott Linder 
25601ce144dSScott Linder   auto Node = Mod.getNamedMetadata("llvm.printf.fmts");
25701ce144dSScott Linder   if (!Node)
25801ce144dSScott Linder     return;
25901ce144dSScott Linder 
26001ce144dSScott Linder   for (auto Op : Node->operands())
26101ce144dSScott Linder     if (Op->getNumOperands())
26201ce144dSScott Linder       Printf.push_back(cast<MDString>(Op->getOperand(0))->getString());
26301ce144dSScott Linder }
26401ce144dSScott Linder 
265f5b36e56SScott Linder void MetadataStreamerV2::emitKernelLanguage(const Function &Func) {
26601ce144dSScott Linder   auto &Kernel = HSAMetadata.mKernels.back();
26701ce144dSScott Linder 
26801ce144dSScott Linder   // TODO: What about other languages?
26901ce144dSScott Linder   auto Node = Func.getParent()->getNamedMetadata("opencl.ocl.version");
27001ce144dSScott Linder   if (!Node || !Node->getNumOperands())
27101ce144dSScott Linder     return;
27201ce144dSScott Linder   auto Op0 = Node->getOperand(0);
27301ce144dSScott Linder   if (Op0->getNumOperands() <= 1)
27401ce144dSScott Linder     return;
27501ce144dSScott Linder 
27601ce144dSScott Linder   Kernel.mLanguage = "OpenCL C";
27701ce144dSScott Linder   Kernel.mLanguageVersion.push_back(
27801ce144dSScott Linder       mdconst::extract<ConstantInt>(Op0->getOperand(0))->getZExtValue());
27901ce144dSScott Linder   Kernel.mLanguageVersion.push_back(
28001ce144dSScott Linder       mdconst::extract<ConstantInt>(Op0->getOperand(1))->getZExtValue());
28101ce144dSScott Linder }
28201ce144dSScott Linder 
283f5b36e56SScott Linder void MetadataStreamerV2::emitKernelAttrs(const Function &Func) {
28401ce144dSScott Linder   auto &Attrs = HSAMetadata.mKernels.back().mAttrs;
28501ce144dSScott Linder 
28601ce144dSScott Linder   if (auto Node = Func.getMetadata("reqd_work_group_size"))
28701ce144dSScott Linder     Attrs.mReqdWorkGroupSize = getWorkGroupDimensions(Node);
28801ce144dSScott Linder   if (auto Node = Func.getMetadata("work_group_size_hint"))
28901ce144dSScott Linder     Attrs.mWorkGroupSizeHint = getWorkGroupDimensions(Node);
29001ce144dSScott Linder   if (auto Node = Func.getMetadata("vec_type_hint")) {
29101ce144dSScott Linder     Attrs.mVecTypeHint = getTypeName(
29201ce144dSScott Linder         cast<ValueAsMetadata>(Node->getOperand(0))->getType(),
29301ce144dSScott Linder         mdconst::extract<ConstantInt>(Node->getOperand(1))->getZExtValue());
29401ce144dSScott Linder   }
29501ce144dSScott Linder   if (Func.hasFnAttribute("runtime-handle")) {
29601ce144dSScott Linder     Attrs.mRuntimeHandle =
29701ce144dSScott Linder         Func.getFnAttribute("runtime-handle").getValueAsString().str();
29801ce144dSScott Linder   }
29901ce144dSScott Linder }
30001ce144dSScott Linder 
301f5b36e56SScott Linder void MetadataStreamerV2::emitKernelArgs(const Function &Func) {
30201ce144dSScott Linder   for (auto &Arg : Func.args())
30301ce144dSScott Linder     emitKernelArg(Arg);
30401ce144dSScott Linder 
30501ce144dSScott Linder   emitHiddenKernelArgs(Func);
30601ce144dSScott Linder }
30701ce144dSScott Linder 
308f5b36e56SScott Linder void MetadataStreamerV2::emitKernelArg(const Argument &Arg) {
30901ce144dSScott Linder   auto Func = Arg.getParent();
31001ce144dSScott Linder   auto ArgNo = Arg.getArgNo();
31101ce144dSScott Linder   const MDNode *Node;
31201ce144dSScott Linder 
31301ce144dSScott Linder   StringRef Name;
31401ce144dSScott Linder   Node = Func->getMetadata("kernel_arg_name");
31501ce144dSScott Linder   if (Node && ArgNo < Node->getNumOperands())
31601ce144dSScott Linder     Name = cast<MDString>(Node->getOperand(ArgNo))->getString();
31701ce144dSScott Linder   else if (Arg.hasName())
31801ce144dSScott Linder     Name = Arg.getName();
31901ce144dSScott Linder 
32001ce144dSScott Linder   StringRef TypeName;
32101ce144dSScott Linder   Node = Func->getMetadata("kernel_arg_type");
32201ce144dSScott Linder   if (Node && ArgNo < Node->getNumOperands())
32301ce144dSScott Linder     TypeName = cast<MDString>(Node->getOperand(ArgNo))->getString();
32401ce144dSScott Linder 
32501ce144dSScott Linder   StringRef BaseTypeName;
32601ce144dSScott Linder   Node = Func->getMetadata("kernel_arg_base_type");
32701ce144dSScott Linder   if (Node && ArgNo < Node->getNumOperands())
32801ce144dSScott Linder     BaseTypeName = cast<MDString>(Node->getOperand(ArgNo))->getString();
32901ce144dSScott Linder 
33001ce144dSScott Linder   StringRef AccQual;
33101ce144dSScott Linder   if (Arg.getType()->isPointerTy() && Arg.onlyReadsMemory() &&
33201ce144dSScott Linder       Arg.hasNoAliasAttr()) {
33301ce144dSScott Linder     AccQual = "read_only";
33401ce144dSScott Linder   } else {
33501ce144dSScott Linder     Node = Func->getMetadata("kernel_arg_access_qual");
33601ce144dSScott Linder     if (Node && ArgNo < Node->getNumOperands())
33701ce144dSScott Linder       AccQual = cast<MDString>(Node->getOperand(ArgNo))->getString();
33801ce144dSScott Linder   }
33901ce144dSScott Linder 
34001ce144dSScott Linder   StringRef TypeQual;
34101ce144dSScott Linder   Node = Func->getMetadata("kernel_arg_type_qual");
34201ce144dSScott Linder   if (Node && ArgNo < Node->getNumOperands())
34301ce144dSScott Linder     TypeQual = cast<MDString>(Node->getOperand(ArgNo))->getString();
34401ce144dSScott Linder 
34501ce144dSScott Linder   Type *Ty = Arg.getType();
34601ce144dSScott Linder   const DataLayout &DL = Func->getParent()->getDataLayout();
34701ce144dSScott Linder 
34801ce144dSScott Linder   unsigned PointeeAlign = 0;
34901ce144dSScott Linder   if (auto PtrTy = dyn_cast<PointerType>(Ty)) {
3500da6350dSMatt Arsenault     if (PtrTy->getAddressSpace() == AMDGPUAS::LOCAL_ADDRESS) {
35101ce144dSScott Linder       PointeeAlign = Arg.getParamAlignment();
35201ce144dSScott Linder       if (PointeeAlign == 0)
35301ce144dSScott Linder         PointeeAlign = DL.getABITypeAlignment(PtrTy->getElementType());
35401ce144dSScott Linder     }
35501ce144dSScott Linder   }
35601ce144dSScott Linder 
35701ce144dSScott Linder   emitKernelArg(DL, Ty, getValueKind(Arg.getType(), TypeQual, BaseTypeName),
35801ce144dSScott Linder                 PointeeAlign, Name, TypeName, BaseTypeName, AccQual, TypeQual);
35901ce144dSScott Linder }
36001ce144dSScott Linder 
361f5b36e56SScott Linder void MetadataStreamerV2::emitKernelArg(const DataLayout &DL, Type *Ty,
36201ce144dSScott Linder                                        ValueKind ValueKind,
363f5b36e56SScott Linder                                        unsigned PointeeAlign, StringRef Name,
364f5b36e56SScott Linder                                        StringRef TypeName,
365f5b36e56SScott Linder                                        StringRef BaseTypeName,
36601ce144dSScott Linder                                        StringRef AccQual, StringRef TypeQual) {
36701ce144dSScott Linder   HSAMetadata.mKernels.back().mArgs.push_back(Kernel::Arg::Metadata());
36801ce144dSScott Linder   auto &Arg = HSAMetadata.mKernels.back().mArgs.back();
36901ce144dSScott Linder 
37001ce144dSScott Linder   Arg.mName = Name;
37101ce144dSScott Linder   Arg.mTypeName = TypeName;
37201ce144dSScott Linder   Arg.mSize = DL.getTypeAllocSize(Ty);
37301ce144dSScott Linder   Arg.mAlign = DL.getABITypeAlignment(Ty);
37401ce144dSScott Linder   Arg.mValueKind = ValueKind;
37501ce144dSScott Linder   Arg.mValueType = getValueType(Ty, BaseTypeName);
37601ce144dSScott Linder   Arg.mPointeeAlign = PointeeAlign;
37701ce144dSScott Linder 
37801ce144dSScott Linder   if (auto PtrTy = dyn_cast<PointerType>(Ty))
379f5b36e56SScott Linder     Arg.mAddrSpaceQual = getAddressSpaceQualifier(PtrTy->getAddressSpace());
38001ce144dSScott Linder 
38101ce144dSScott Linder   Arg.mAccQual = getAccessQualifier(AccQual);
38201ce144dSScott Linder 
38301ce144dSScott Linder   // TODO: Emit Arg.mActualAccQual.
38401ce144dSScott Linder 
38501ce144dSScott Linder   SmallVector<StringRef, 1> SplitTypeQuals;
38601ce144dSScott Linder   TypeQual.split(SplitTypeQuals, " ", -1, false);
38701ce144dSScott Linder   for (StringRef Key : SplitTypeQuals) {
38801ce144dSScott Linder     auto P = StringSwitch<bool*>(Key)
38901ce144dSScott Linder                  .Case("const",    &Arg.mIsConst)
39001ce144dSScott Linder                  .Case("restrict", &Arg.mIsRestrict)
39101ce144dSScott Linder                  .Case("volatile", &Arg.mIsVolatile)
39201ce144dSScott Linder                  .Case("pipe",     &Arg.mIsPipe)
39301ce144dSScott Linder                  .Default(nullptr);
39401ce144dSScott Linder     if (P)
39501ce144dSScott Linder       *P = true;
39601ce144dSScott Linder   }
39701ce144dSScott Linder }
39801ce144dSScott Linder 
399f5b36e56SScott Linder void MetadataStreamerV2::emitHiddenKernelArgs(const Function &Func) {
40001ce144dSScott Linder   int HiddenArgNumBytes =
40101ce144dSScott Linder       getIntegerAttribute(Func, "amdgpu-implicitarg-num-bytes", 0);
40201ce144dSScott Linder 
40301ce144dSScott Linder   if (!HiddenArgNumBytes)
40401ce144dSScott Linder     return;
40501ce144dSScott Linder 
40601ce144dSScott Linder   auto &DL = Func.getParent()->getDataLayout();
40701ce144dSScott Linder   auto Int64Ty = Type::getInt64Ty(Func.getContext());
40801ce144dSScott Linder 
40901ce144dSScott Linder   if (HiddenArgNumBytes >= 8)
41001ce144dSScott Linder     emitKernelArg(DL, Int64Ty, ValueKind::HiddenGlobalOffsetX);
41101ce144dSScott Linder   if (HiddenArgNumBytes >= 16)
41201ce144dSScott Linder     emitKernelArg(DL, Int64Ty, ValueKind::HiddenGlobalOffsetY);
41301ce144dSScott Linder   if (HiddenArgNumBytes >= 24)
41401ce144dSScott Linder     emitKernelArg(DL, Int64Ty, ValueKind::HiddenGlobalOffsetZ);
41501ce144dSScott Linder 
41601ce144dSScott Linder   auto Int8PtrTy = Type::getInt8PtrTy(Func.getContext(),
4170da6350dSMatt Arsenault                                       AMDGPUAS::GLOBAL_ADDRESS);
41801ce144dSScott Linder 
41901ce144dSScott Linder   // Emit "printf buffer" argument if printf is used, otherwise emit dummy
42001ce144dSScott Linder   // "none" argument.
42101ce144dSScott Linder   if (HiddenArgNumBytes >= 32) {
42201ce144dSScott Linder     if (Func.getParent()->getNamedMetadata("llvm.printf.fmts"))
42301ce144dSScott Linder       emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenPrintfBuffer);
424*52c5014dSSameer Sahasrabuddhe     else if (Func.getParent()->getFunction("__ockl_hostcall_internal")) {
425*52c5014dSSameer Sahasrabuddhe       // The printf runtime binding pass should have ensured that hostcall and
426*52c5014dSSameer Sahasrabuddhe       // printf are not used in the same module.
427*52c5014dSSameer Sahasrabuddhe       assert(!Func.getParent()->getNamedMetadata("llvm.printf.fmts"));
428*52c5014dSSameer Sahasrabuddhe       emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenHostcallBuffer);
429*52c5014dSSameer Sahasrabuddhe     } else
43001ce144dSScott Linder       emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenNone);
43101ce144dSScott Linder   }
43201ce144dSScott Linder 
43301ce144dSScott Linder   // Emit "default queue" and "completion action" arguments if enqueue kernel is
43401ce144dSScott Linder   // used, otherwise emit dummy "none" arguments.
43501ce144dSScott Linder   if (HiddenArgNumBytes >= 48) {
43601ce144dSScott Linder     if (Func.hasFnAttribute("calls-enqueue-kernel")) {
43701ce144dSScott Linder       emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenDefaultQueue);
43801ce144dSScott Linder       emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenCompletionAction);
43901ce144dSScott Linder     } else {
44001ce144dSScott Linder       emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenNone);
44101ce144dSScott Linder       emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenNone);
44201ce144dSScott Linder     }
44301ce144dSScott Linder   }
444a6241352SYaxun Liu 
445a6241352SYaxun Liu   // Emit the pointer argument for multi-grid object.
446a6241352SYaxun Liu   if (HiddenArgNumBytes >= 56)
447a6241352SYaxun Liu     emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenMultiGridSyncArg);
44801ce144dSScott Linder }
44901ce144dSScott Linder 
450f5b36e56SScott Linder bool MetadataStreamerV2::emitTo(AMDGPUTargetStreamer &TargetStreamer) {
451f5b36e56SScott Linder   return TargetStreamer.EmitHSAMetadata(getHSAMetadata());
452f5b36e56SScott Linder }
453f5b36e56SScott Linder 
454f5b36e56SScott Linder void MetadataStreamerV2::begin(const Module &Mod) {
45501ce144dSScott Linder   emitVersion();
45601ce144dSScott Linder   emitPrintf(Mod);
45701ce144dSScott Linder }
45801ce144dSScott Linder 
459f5b36e56SScott Linder void MetadataStreamerV2::end() {
46001ce144dSScott Linder   std::string HSAMetadataString;
46101ce144dSScott Linder   if (toString(HSAMetadata, HSAMetadataString))
46201ce144dSScott Linder     return;
46301ce144dSScott Linder 
46401ce144dSScott Linder   if (DumpHSAMetadata)
46501ce144dSScott Linder     dump(HSAMetadataString);
46601ce144dSScott Linder   if (VerifyHSAMetadata)
46701ce144dSScott Linder     verify(HSAMetadataString);
46801ce144dSScott Linder }
46901ce144dSScott Linder 
470f5b36e56SScott Linder void MetadataStreamerV2::emitKernel(const MachineFunction &MF,
471f5b36e56SScott Linder                                     const SIProgramInfo &ProgramInfo) {
47201ce144dSScott Linder   auto &Func = MF.getFunction();
47301ce144dSScott Linder   if (Func.getCallingConv() != CallingConv::AMDGPU_KERNEL)
47401ce144dSScott Linder     return;
47501ce144dSScott Linder 
4764bec7d42SMatt Arsenault   auto CodeProps = getHSACodeProps(MF, ProgramInfo);
4774bec7d42SMatt Arsenault   auto DebugProps = getHSADebugProps(MF, ProgramInfo);
4784bec7d42SMatt Arsenault 
47901ce144dSScott Linder   HSAMetadata.mKernels.push_back(Kernel::Metadata());
48001ce144dSScott Linder   auto &Kernel = HSAMetadata.mKernels.back();
48101ce144dSScott Linder 
48201ce144dSScott Linder   Kernel.mName = Func.getName();
48301ce144dSScott Linder   Kernel.mSymbolName = (Twine(Func.getName()) + Twine("@kd")).str();
48401ce144dSScott Linder   emitKernelLanguage(Func);
48501ce144dSScott Linder   emitKernelAttrs(Func);
48601ce144dSScott Linder   emitKernelArgs(Func);
48701ce144dSScott Linder   HSAMetadata.mKernels.back().mCodeProps = CodeProps;
48801ce144dSScott Linder   HSAMetadata.mKernels.back().mDebugProps = DebugProps;
48901ce144dSScott Linder }
49001ce144dSScott Linder 
491f5b36e56SScott Linder //===----------------------------------------------------------------------===//
492f5b36e56SScott Linder // HSAMetadataStreamerV3
493f5b36e56SScott Linder //===----------------------------------------------------------------------===//
494f5b36e56SScott Linder 
495f5b36e56SScott Linder void MetadataStreamerV3::dump(StringRef HSAMetadataString) const {
496f5b36e56SScott Linder   errs() << "AMDGPU HSA Metadata:\n" << HSAMetadataString << '\n';
497f5b36e56SScott Linder }
498f5b36e56SScott Linder 
499f5b36e56SScott Linder void MetadataStreamerV3::verify(StringRef HSAMetadataString) const {
500f5b36e56SScott Linder   errs() << "AMDGPU HSA Metadata Parser Test: ";
501f5b36e56SScott Linder 
502ed0b9af9STim Renouf   msgpack::Document FromHSAMetadataString;
503f5b36e56SScott Linder 
504ed0b9af9STim Renouf   if (!FromHSAMetadataString.fromYAML(HSAMetadataString)) {
505f5b36e56SScott Linder     errs() << "FAIL\n";
506f5b36e56SScott Linder     return;
507f5b36e56SScott Linder   }
508f5b36e56SScott Linder 
509f5b36e56SScott Linder   std::string ToHSAMetadataString;
510f5b36e56SScott Linder   raw_string_ostream StrOS(ToHSAMetadataString);
511ed0b9af9STim Renouf   FromHSAMetadataString.toYAML(StrOS);
512f5b36e56SScott Linder 
513f5b36e56SScott Linder   errs() << (HSAMetadataString == StrOS.str() ? "PASS" : "FAIL") << '\n';
514f5b36e56SScott Linder   if (HSAMetadataString != ToHSAMetadataString) {
515f5b36e56SScott Linder     errs() << "Original input: " << HSAMetadataString << '\n'
516f5b36e56SScott Linder            << "Produced output: " << StrOS.str() << '\n';
517f5b36e56SScott Linder   }
518f5b36e56SScott Linder }
519f5b36e56SScott Linder 
520f5b36e56SScott Linder Optional<StringRef>
521f5b36e56SScott Linder MetadataStreamerV3::getAccessQualifier(StringRef AccQual) const {
522f5b36e56SScott Linder   return StringSwitch<Optional<StringRef>>(AccQual)
523f5b36e56SScott Linder       .Case("read_only", StringRef("read_only"))
524f5b36e56SScott Linder       .Case("write_only", StringRef("write_only"))
525f5b36e56SScott Linder       .Case("read_write", StringRef("read_write"))
526f5b36e56SScott Linder       .Default(None);
527f5b36e56SScott Linder }
528f5b36e56SScott Linder 
529f5b36e56SScott Linder Optional<StringRef>
530f5b36e56SScott Linder MetadataStreamerV3::getAddressSpaceQualifier(unsigned AddressSpace) const {
531f5b36e56SScott Linder   switch (AddressSpace) {
532f5b36e56SScott Linder   case AMDGPUAS::PRIVATE_ADDRESS:
533f5b36e56SScott Linder     return StringRef("private");
534f5b36e56SScott Linder   case AMDGPUAS::GLOBAL_ADDRESS:
535f5b36e56SScott Linder     return StringRef("global");
536f5b36e56SScott Linder   case AMDGPUAS::CONSTANT_ADDRESS:
537f5b36e56SScott Linder     return StringRef("constant");
538f5b36e56SScott Linder   case AMDGPUAS::LOCAL_ADDRESS:
539f5b36e56SScott Linder     return StringRef("local");
540f5b36e56SScott Linder   case AMDGPUAS::FLAT_ADDRESS:
541f5b36e56SScott Linder     return StringRef("generic");
542f5b36e56SScott Linder   case AMDGPUAS::REGION_ADDRESS:
543f5b36e56SScott Linder     return StringRef("region");
544f5b36e56SScott Linder   default:
545f5b36e56SScott Linder     return None;
546f5b36e56SScott Linder   }
547f5b36e56SScott Linder }
548f5b36e56SScott Linder 
549f5b36e56SScott Linder StringRef MetadataStreamerV3::getValueKind(Type *Ty, StringRef TypeQual,
550f5b36e56SScott Linder                                            StringRef BaseTypeName) const {
551f5b36e56SScott Linder   if (TypeQual.find("pipe") != StringRef::npos)
552f5b36e56SScott Linder     return "pipe";
553f5b36e56SScott Linder 
554f5b36e56SScott Linder   return StringSwitch<StringRef>(BaseTypeName)
555f5b36e56SScott Linder       .Case("image1d_t", "image")
556f5b36e56SScott Linder       .Case("image1d_array_t", "image")
557f5b36e56SScott Linder       .Case("image1d_buffer_t", "image")
558f5b36e56SScott Linder       .Case("image2d_t", "image")
559f5b36e56SScott Linder       .Case("image2d_array_t", "image")
560f5b36e56SScott Linder       .Case("image2d_array_depth_t", "image")
561f5b36e56SScott Linder       .Case("image2d_array_msaa_t", "image")
562f5b36e56SScott Linder       .Case("image2d_array_msaa_depth_t", "image")
563f5b36e56SScott Linder       .Case("image2d_depth_t", "image")
564f5b36e56SScott Linder       .Case("image2d_msaa_t", "image")
565f5b36e56SScott Linder       .Case("image2d_msaa_depth_t", "image")
566f5b36e56SScott Linder       .Case("image3d_t", "image")
567f5b36e56SScott Linder       .Case("sampler_t", "sampler")
568f5b36e56SScott Linder       .Case("queue_t", "queue")
569f5b36e56SScott Linder       .Default(isa<PointerType>(Ty)
570f5b36e56SScott Linder                    ? (Ty->getPointerAddressSpace() == AMDGPUAS::LOCAL_ADDRESS
571f5b36e56SScott Linder                           ? "dynamic_shared_pointer"
572f5b36e56SScott Linder                           : "global_buffer")
573f5b36e56SScott Linder                    : "by_value");
574f5b36e56SScott Linder }
575f5b36e56SScott Linder 
576f5b36e56SScott Linder StringRef MetadataStreamerV3::getValueType(Type *Ty, StringRef TypeName) const {
577f5b36e56SScott Linder   switch (Ty->getTypeID()) {
578f5b36e56SScott Linder   case Type::IntegerTyID: {
579f5b36e56SScott Linder     auto Signed = !TypeName.startswith("u");
580f5b36e56SScott Linder     switch (Ty->getIntegerBitWidth()) {
581f5b36e56SScott Linder     case 8:
582f5b36e56SScott Linder       return Signed ? "i8" : "u8";
583f5b36e56SScott Linder     case 16:
584f5b36e56SScott Linder       return Signed ? "i16" : "u16";
585f5b36e56SScott Linder     case 32:
586f5b36e56SScott Linder       return Signed ? "i32" : "u32";
587f5b36e56SScott Linder     case 64:
588f5b36e56SScott Linder       return Signed ? "i64" : "u64";
589f5b36e56SScott Linder     default:
590f5b36e56SScott Linder       return "struct";
591f5b36e56SScott Linder     }
592f5b36e56SScott Linder   }
593f5b36e56SScott Linder   case Type::HalfTyID:
594f5b36e56SScott Linder     return "f16";
595f5b36e56SScott Linder   case Type::FloatTyID:
596f5b36e56SScott Linder     return "f32";
597f5b36e56SScott Linder   case Type::DoubleTyID:
598f5b36e56SScott Linder     return "f64";
599f5b36e56SScott Linder   case Type::PointerTyID:
600f5b36e56SScott Linder     return getValueType(Ty->getPointerElementType(), TypeName);
601f5b36e56SScott Linder   case Type::VectorTyID:
602f5b36e56SScott Linder     return getValueType(Ty->getVectorElementType(), TypeName);
603f5b36e56SScott Linder   default:
604f5b36e56SScott Linder     return "struct";
605f5b36e56SScott Linder   }
606f5b36e56SScott Linder }
607f5b36e56SScott Linder 
608f5b36e56SScott Linder std::string MetadataStreamerV3::getTypeName(Type *Ty, bool Signed) const {
609f5b36e56SScott Linder   switch (Ty->getTypeID()) {
610f5b36e56SScott Linder   case Type::IntegerTyID: {
611f5b36e56SScott Linder     if (!Signed)
612f5b36e56SScott Linder       return (Twine('u') + getTypeName(Ty, true)).str();
613f5b36e56SScott Linder 
614f5b36e56SScott Linder     auto BitWidth = Ty->getIntegerBitWidth();
615f5b36e56SScott Linder     switch (BitWidth) {
616f5b36e56SScott Linder     case 8:
617f5b36e56SScott Linder       return "char";
618f5b36e56SScott Linder     case 16:
619f5b36e56SScott Linder       return "short";
620f5b36e56SScott Linder     case 32:
621f5b36e56SScott Linder       return "int";
622f5b36e56SScott Linder     case 64:
623f5b36e56SScott Linder       return "long";
624f5b36e56SScott Linder     default:
625f5b36e56SScott Linder       return (Twine('i') + Twine(BitWidth)).str();
626f5b36e56SScott Linder     }
627f5b36e56SScott Linder   }
628f5b36e56SScott Linder   case Type::HalfTyID:
629f5b36e56SScott Linder     return "half";
630f5b36e56SScott Linder   case Type::FloatTyID:
631f5b36e56SScott Linder     return "float";
632f5b36e56SScott Linder   case Type::DoubleTyID:
633f5b36e56SScott Linder     return "double";
634f5b36e56SScott Linder   case Type::VectorTyID: {
635f5b36e56SScott Linder     auto VecTy = cast<VectorType>(Ty);
636f5b36e56SScott Linder     auto ElTy = VecTy->getElementType();
637f5b36e56SScott Linder     auto NumElements = VecTy->getVectorNumElements();
638f5b36e56SScott Linder     return (Twine(getTypeName(ElTy, Signed)) + Twine(NumElements)).str();
639f5b36e56SScott Linder   }
640f5b36e56SScott Linder   default:
641f5b36e56SScott Linder     return "unknown";
642f5b36e56SScott Linder   }
643f5b36e56SScott Linder }
644f5b36e56SScott Linder 
645ed0b9af9STim Renouf msgpack::ArrayDocNode
646f5b36e56SScott Linder MetadataStreamerV3::getWorkGroupDimensions(MDNode *Node) const {
647ed0b9af9STim Renouf   auto Dims = HSAMetadataDoc->getArrayNode();
648f5b36e56SScott Linder   if (Node->getNumOperands() != 3)
649f5b36e56SScott Linder     return Dims;
650f5b36e56SScott Linder 
651f5b36e56SScott Linder   for (auto &Op : Node->operands())
652ed0b9af9STim Renouf     Dims.push_back(Dims.getDocument()->getNode(
653ed0b9af9STim Renouf         uint64_t(mdconst::extract<ConstantInt>(Op)->getZExtValue())));
654f5b36e56SScott Linder   return Dims;
655f5b36e56SScott Linder }
656f5b36e56SScott Linder 
657f5b36e56SScott Linder void MetadataStreamerV3::emitVersion() {
658ed0b9af9STim Renouf   auto Version = HSAMetadataDoc->getArrayNode();
659ed0b9af9STim Renouf   Version.push_back(Version.getDocument()->getNode(VersionMajor));
660ed0b9af9STim Renouf   Version.push_back(Version.getDocument()->getNode(VersionMinor));
661ed0b9af9STim Renouf   getRootMetadata("amdhsa.version") = Version;
662f5b36e56SScott Linder }
663f5b36e56SScott Linder 
664f5b36e56SScott Linder void MetadataStreamerV3::emitPrintf(const Module &Mod) {
665f5b36e56SScott Linder   auto Node = Mod.getNamedMetadata("llvm.printf.fmts");
666f5b36e56SScott Linder   if (!Node)
667f5b36e56SScott Linder     return;
668f5b36e56SScott Linder 
669ed0b9af9STim Renouf   auto Printf = HSAMetadataDoc->getArrayNode();
670f5b36e56SScott Linder   for (auto Op : Node->operands())
671f5b36e56SScott Linder     if (Op->getNumOperands())
672ed0b9af9STim Renouf       Printf.push_back(Printf.getDocument()->getNode(
673ed0b9af9STim Renouf           cast<MDString>(Op->getOperand(0))->getString(), /*Copy=*/true));
674ed0b9af9STim Renouf   getRootMetadata("amdhsa.printf") = Printf;
675f5b36e56SScott Linder }
676f5b36e56SScott Linder 
677f5b36e56SScott Linder void MetadataStreamerV3::emitKernelLanguage(const Function &Func,
678ed0b9af9STim Renouf                                             msgpack::MapDocNode Kern) {
679f5b36e56SScott Linder   // TODO: What about other languages?
680f5b36e56SScott Linder   auto Node = Func.getParent()->getNamedMetadata("opencl.ocl.version");
681f5b36e56SScott Linder   if (!Node || !Node->getNumOperands())
682f5b36e56SScott Linder     return;
683f5b36e56SScott Linder   auto Op0 = Node->getOperand(0);
684f5b36e56SScott Linder   if (Op0->getNumOperands() <= 1)
685f5b36e56SScott Linder     return;
686f5b36e56SScott Linder 
687ed0b9af9STim Renouf   Kern[".language"] = Kern.getDocument()->getNode("OpenCL C");
688ed0b9af9STim Renouf   auto LanguageVersion = Kern.getDocument()->getArrayNode();
689ed0b9af9STim Renouf   LanguageVersion.push_back(Kern.getDocument()->getNode(
690f5b36e56SScott Linder       mdconst::extract<ConstantInt>(Op0->getOperand(0))->getZExtValue()));
691ed0b9af9STim Renouf   LanguageVersion.push_back(Kern.getDocument()->getNode(
692f5b36e56SScott Linder       mdconst::extract<ConstantInt>(Op0->getOperand(1))->getZExtValue()));
693ed0b9af9STim Renouf   Kern[".language_version"] = LanguageVersion;
694f5b36e56SScott Linder }
695f5b36e56SScott Linder 
696f5b36e56SScott Linder void MetadataStreamerV3::emitKernelAttrs(const Function &Func,
697ed0b9af9STim Renouf                                          msgpack::MapDocNode Kern) {
698f5b36e56SScott Linder 
699f5b36e56SScott Linder   if (auto Node = Func.getMetadata("reqd_work_group_size"))
700f5b36e56SScott Linder     Kern[".reqd_workgroup_size"] = getWorkGroupDimensions(Node);
701f5b36e56SScott Linder   if (auto Node = Func.getMetadata("work_group_size_hint"))
702f5b36e56SScott Linder     Kern[".workgroup_size_hint"] = getWorkGroupDimensions(Node);
703f5b36e56SScott Linder   if (auto Node = Func.getMetadata("vec_type_hint")) {
704ed0b9af9STim Renouf     Kern[".vec_type_hint"] = Kern.getDocument()->getNode(
705ed0b9af9STim Renouf         getTypeName(
706f5b36e56SScott Linder             cast<ValueAsMetadata>(Node->getOperand(0))->getType(),
707ed0b9af9STim Renouf             mdconst::extract<ConstantInt>(Node->getOperand(1))->getZExtValue()),
708ed0b9af9STim Renouf         /*Copy=*/true);
709f5b36e56SScott Linder   }
710f5b36e56SScott Linder   if (Func.hasFnAttribute("runtime-handle")) {
711ed0b9af9STim Renouf     Kern[".device_enqueue_symbol"] = Kern.getDocument()->getNode(
712ed0b9af9STim Renouf         Func.getFnAttribute("runtime-handle").getValueAsString().str(),
713ed0b9af9STim Renouf         /*Copy=*/true);
714f5b36e56SScott Linder   }
715f5b36e56SScott Linder }
716f5b36e56SScott Linder 
717f5b36e56SScott Linder void MetadataStreamerV3::emitKernelArgs(const Function &Func,
718ed0b9af9STim Renouf                                         msgpack::MapDocNode Kern) {
719f5b36e56SScott Linder   unsigned Offset = 0;
720ed0b9af9STim Renouf   auto Args = HSAMetadataDoc->getArrayNode();
721f5b36e56SScott Linder   for (auto &Arg : Func.args())
722ed0b9af9STim Renouf     emitKernelArg(Arg, Offset, Args);
723f5b36e56SScott Linder 
724ed0b9af9STim Renouf   emitHiddenKernelArgs(Func, Offset, Args);
725f5b36e56SScott Linder 
726ed0b9af9STim Renouf   Kern[".args"] = Args;
727f5b36e56SScott Linder }
728f5b36e56SScott Linder 
729f5b36e56SScott Linder void MetadataStreamerV3::emitKernelArg(const Argument &Arg, unsigned &Offset,
730ed0b9af9STim Renouf                                        msgpack::ArrayDocNode Args) {
731f5b36e56SScott Linder   auto Func = Arg.getParent();
732f5b36e56SScott Linder   auto ArgNo = Arg.getArgNo();
733f5b36e56SScott Linder   const MDNode *Node;
734f5b36e56SScott Linder 
735f5b36e56SScott Linder   StringRef Name;
736f5b36e56SScott Linder   Node = Func->getMetadata("kernel_arg_name");
737f5b36e56SScott Linder   if (Node && ArgNo < Node->getNumOperands())
738f5b36e56SScott Linder     Name = cast<MDString>(Node->getOperand(ArgNo))->getString();
739f5b36e56SScott Linder   else if (Arg.hasName())
740f5b36e56SScott Linder     Name = Arg.getName();
741f5b36e56SScott Linder 
742f5b36e56SScott Linder   StringRef TypeName;
743f5b36e56SScott Linder   Node = Func->getMetadata("kernel_arg_type");
744f5b36e56SScott Linder   if (Node && ArgNo < Node->getNumOperands())
745f5b36e56SScott Linder     TypeName = cast<MDString>(Node->getOperand(ArgNo))->getString();
746f5b36e56SScott Linder 
747f5b36e56SScott Linder   StringRef BaseTypeName;
748f5b36e56SScott Linder   Node = Func->getMetadata("kernel_arg_base_type");
749f5b36e56SScott Linder   if (Node && ArgNo < Node->getNumOperands())
750f5b36e56SScott Linder     BaseTypeName = cast<MDString>(Node->getOperand(ArgNo))->getString();
751f5b36e56SScott Linder 
752f5b36e56SScott Linder   StringRef AccQual;
753f5b36e56SScott Linder   if (Arg.getType()->isPointerTy() && Arg.onlyReadsMemory() &&
754f5b36e56SScott Linder       Arg.hasNoAliasAttr()) {
755f5b36e56SScott Linder     AccQual = "read_only";
756f5b36e56SScott Linder   } else {
757f5b36e56SScott Linder     Node = Func->getMetadata("kernel_arg_access_qual");
758f5b36e56SScott Linder     if (Node && ArgNo < Node->getNumOperands())
759f5b36e56SScott Linder       AccQual = cast<MDString>(Node->getOperand(ArgNo))->getString();
760f5b36e56SScott Linder   }
761f5b36e56SScott Linder 
762f5b36e56SScott Linder   StringRef TypeQual;
763f5b36e56SScott Linder   Node = Func->getMetadata("kernel_arg_type_qual");
764f5b36e56SScott Linder   if (Node && ArgNo < Node->getNumOperands())
765f5b36e56SScott Linder     TypeQual = cast<MDString>(Node->getOperand(ArgNo))->getString();
766f5b36e56SScott Linder 
767f5b36e56SScott Linder   Type *Ty = Arg.getType();
768f5b36e56SScott Linder   const DataLayout &DL = Func->getParent()->getDataLayout();
769f5b36e56SScott Linder 
770f5b36e56SScott Linder   unsigned PointeeAlign = 0;
771f5b36e56SScott Linder   if (auto PtrTy = dyn_cast<PointerType>(Ty)) {
772f5b36e56SScott Linder     if (PtrTy->getAddressSpace() == AMDGPUAS::LOCAL_ADDRESS) {
773f5b36e56SScott Linder       PointeeAlign = Arg.getParamAlignment();
774f5b36e56SScott Linder       if (PointeeAlign == 0)
775f5b36e56SScott Linder         PointeeAlign = DL.getABITypeAlignment(PtrTy->getElementType());
776f5b36e56SScott Linder     }
777f5b36e56SScott Linder   }
778f5b36e56SScott Linder 
779f5b36e56SScott Linder   emitKernelArg(Func->getParent()->getDataLayout(), Arg.getType(),
780f5b36e56SScott Linder                 getValueKind(Arg.getType(), TypeQual, BaseTypeName), Offset,
781f5b36e56SScott Linder                 Args, PointeeAlign, Name, TypeName, BaseTypeName, AccQual,
782f5b36e56SScott Linder                 TypeQual);
783f5b36e56SScott Linder }
784f5b36e56SScott Linder 
785f5b36e56SScott Linder void MetadataStreamerV3::emitKernelArg(const DataLayout &DL, Type *Ty,
786f5b36e56SScott Linder                                        StringRef ValueKind, unsigned &Offset,
787ed0b9af9STim Renouf                                        msgpack::ArrayDocNode Args,
788f5b36e56SScott Linder                                        unsigned PointeeAlign, StringRef Name,
789f5b36e56SScott Linder                                        StringRef TypeName,
790f5b36e56SScott Linder                                        StringRef BaseTypeName,
791f5b36e56SScott Linder                                        StringRef AccQual, StringRef TypeQual) {
792ed0b9af9STim Renouf   auto Arg = Args.getDocument()->getMapNode();
793f5b36e56SScott Linder 
794f5b36e56SScott Linder   if (!Name.empty())
795ed0b9af9STim Renouf     Arg[".name"] = Arg.getDocument()->getNode(Name, /*Copy=*/true);
796f5b36e56SScott Linder   if (!TypeName.empty())
797ed0b9af9STim Renouf     Arg[".type_name"] = Arg.getDocument()->getNode(TypeName, /*Copy=*/true);
798f5b36e56SScott Linder   auto Size = DL.getTypeAllocSize(Ty);
799f5b36e56SScott Linder   auto Align = DL.getABITypeAlignment(Ty);
800ed0b9af9STim Renouf   Arg[".size"] = Arg.getDocument()->getNode(Size);
801f5b36e56SScott Linder   Offset = alignTo(Offset, Align);
802ed0b9af9STim Renouf   Arg[".offset"] = Arg.getDocument()->getNode(Offset);
803f5b36e56SScott Linder   Offset += Size;
804ed0b9af9STim Renouf   Arg[".value_kind"] = Arg.getDocument()->getNode(ValueKind, /*Copy=*/true);
805f5b36e56SScott Linder   Arg[".value_type"] =
806ed0b9af9STim Renouf       Arg.getDocument()->getNode(getValueType(Ty, BaseTypeName), /*Copy=*/true);
807f5b36e56SScott Linder   if (PointeeAlign)
808ed0b9af9STim Renouf     Arg[".pointee_align"] = Arg.getDocument()->getNode(PointeeAlign);
809f5b36e56SScott Linder 
810f5b36e56SScott Linder   if (auto PtrTy = dyn_cast<PointerType>(Ty))
811f5b36e56SScott Linder     if (auto Qualifier = getAddressSpaceQualifier(PtrTy->getAddressSpace()))
812ed0b9af9STim Renouf       Arg[".address_space"] = Arg.getDocument()->getNode(*Qualifier, /*Copy=*/true);
813f5b36e56SScott Linder 
814f5b36e56SScott Linder   if (auto AQ = getAccessQualifier(AccQual))
815ed0b9af9STim Renouf     Arg[".access"] = Arg.getDocument()->getNode(*AQ, /*Copy=*/true);
816f5b36e56SScott Linder 
817f5b36e56SScott Linder   // TODO: Emit Arg[".actual_access"].
818f5b36e56SScott Linder 
819f5b36e56SScott Linder   SmallVector<StringRef, 1> SplitTypeQuals;
820f5b36e56SScott Linder   TypeQual.split(SplitTypeQuals, " ", -1, false);
821f5b36e56SScott Linder   for (StringRef Key : SplitTypeQuals) {
822f5b36e56SScott Linder     if (Key == "const")
823ed0b9af9STim Renouf       Arg[".is_const"] = Arg.getDocument()->getNode(true);
824f5b36e56SScott Linder     else if (Key == "restrict")
825ed0b9af9STim Renouf       Arg[".is_restrict"] = Arg.getDocument()->getNode(true);
826f5b36e56SScott Linder     else if (Key == "volatile")
827ed0b9af9STim Renouf       Arg[".is_volatile"] = Arg.getDocument()->getNode(true);
828f5b36e56SScott Linder     else if (Key == "pipe")
829ed0b9af9STim Renouf       Arg[".is_pipe"] = Arg.getDocument()->getNode(true);
830f5b36e56SScott Linder   }
831f5b36e56SScott Linder 
832ed0b9af9STim Renouf   Args.push_back(Arg);
833f5b36e56SScott Linder }
834f5b36e56SScott Linder 
835f5b36e56SScott Linder void MetadataStreamerV3::emitHiddenKernelArgs(const Function &Func,
836f5b36e56SScott Linder                                               unsigned &Offset,
837ed0b9af9STim Renouf                                               msgpack::ArrayDocNode Args) {
838f5b36e56SScott Linder   int HiddenArgNumBytes =
839f5b36e56SScott Linder       getIntegerAttribute(Func, "amdgpu-implicitarg-num-bytes", 0);
840f5b36e56SScott Linder 
841f5b36e56SScott Linder   if (!HiddenArgNumBytes)
842f5b36e56SScott Linder     return;
843f5b36e56SScott Linder 
844f5b36e56SScott Linder   auto &DL = Func.getParent()->getDataLayout();
845f5b36e56SScott Linder   auto Int64Ty = Type::getInt64Ty(Func.getContext());
846f5b36e56SScott Linder 
847f5b36e56SScott Linder   if (HiddenArgNumBytes >= 8)
848f5b36e56SScott Linder     emitKernelArg(DL, Int64Ty, "hidden_global_offset_x", Offset, Args);
849f5b36e56SScott Linder   if (HiddenArgNumBytes >= 16)
850f5b36e56SScott Linder     emitKernelArg(DL, Int64Ty, "hidden_global_offset_y", Offset, Args);
851f5b36e56SScott Linder   if (HiddenArgNumBytes >= 24)
852f5b36e56SScott Linder     emitKernelArg(DL, Int64Ty, "hidden_global_offset_z", Offset, Args);
853f5b36e56SScott Linder 
854f5b36e56SScott Linder   auto Int8PtrTy =
855f5b36e56SScott Linder       Type::getInt8PtrTy(Func.getContext(), AMDGPUAS::GLOBAL_ADDRESS);
856f5b36e56SScott Linder 
857f5b36e56SScott Linder   // Emit "printf buffer" argument if printf is used, otherwise emit dummy
858f5b36e56SScott Linder   // "none" argument.
859f5b36e56SScott Linder   if (HiddenArgNumBytes >= 32) {
860f5b36e56SScott Linder     if (Func.getParent()->getNamedMetadata("llvm.printf.fmts"))
861f5b36e56SScott Linder       emitKernelArg(DL, Int8PtrTy, "hidden_printf_buffer", Offset, Args);
862*52c5014dSSameer Sahasrabuddhe     else if (Func.getParent()->getFunction("__ockl_hostcall_internal")) {
863*52c5014dSSameer Sahasrabuddhe       // The printf runtime binding pass should have ensured that hostcall and
864*52c5014dSSameer Sahasrabuddhe       // printf are not used in the same module.
865*52c5014dSSameer Sahasrabuddhe       assert(!Func.getParent()->getNamedMetadata("llvm.printf.fmts"));
866*52c5014dSSameer Sahasrabuddhe       emitKernelArg(DL, Int8PtrTy, "hidden_hostcall_buffer", Offset, Args);
867*52c5014dSSameer Sahasrabuddhe     } else
868f5b36e56SScott Linder       emitKernelArg(DL, Int8PtrTy, "hidden_none", Offset, Args);
869f5b36e56SScott Linder   }
870f5b36e56SScott Linder 
871f5b36e56SScott Linder   // Emit "default queue" and "completion action" arguments if enqueue kernel is
872f5b36e56SScott Linder   // used, otherwise emit dummy "none" arguments.
873f5b36e56SScott Linder   if (HiddenArgNumBytes >= 48) {
874f5b36e56SScott Linder     if (Func.hasFnAttribute("calls-enqueue-kernel")) {
875f5b36e56SScott Linder       emitKernelArg(DL, Int8PtrTy, "hidden_default_queue", Offset, Args);
876f5b36e56SScott Linder       emitKernelArg(DL, Int8PtrTy, "hidden_completion_action", Offset, Args);
877f5b36e56SScott Linder     } else {
878f5b36e56SScott Linder       emitKernelArg(DL, Int8PtrTy, "hidden_none", Offset, Args);
879f5b36e56SScott Linder       emitKernelArg(DL, Int8PtrTy, "hidden_none", Offset, Args);
880f5b36e56SScott Linder     }
881f5b36e56SScott Linder   }
882a6241352SYaxun Liu 
883a6241352SYaxun Liu   // Emit the pointer argument for multi-grid object.
884a6241352SYaxun Liu   if (HiddenArgNumBytes >= 56)
885a6241352SYaxun Liu     emitKernelArg(DL, Int8PtrTy, "hidden_multigrid_sync_arg", Offset, Args);
886f5b36e56SScott Linder }
887f5b36e56SScott Linder 
888ed0b9af9STim Renouf msgpack::MapDocNode
889f5b36e56SScott Linder MetadataStreamerV3::getHSAKernelProps(const MachineFunction &MF,
890f5b36e56SScott Linder                                       const SIProgramInfo &ProgramInfo) const {
891f5b36e56SScott Linder   const GCNSubtarget &STM = MF.getSubtarget<GCNSubtarget>();
892f5b36e56SScott Linder   const SIMachineFunctionInfo &MFI = *MF.getInfo<SIMachineFunctionInfo>();
893f5b36e56SScott Linder   const Function &F = MF.getFunction();
894f5b36e56SScott Linder 
895ed0b9af9STim Renouf   auto Kern = HSAMetadataDoc->getMapNode();
896f5b36e56SScott Linder 
897b65fa483SGuillaume Chatelet   Align MaxKernArgAlign;
898ed0b9af9STim Renouf   Kern[".kernarg_segment_size"] = Kern.getDocument()->getNode(
899f5b36e56SScott Linder       STM.getKernArgSegmentSize(F, MaxKernArgAlign));
900f5b36e56SScott Linder   Kern[".group_segment_fixed_size"] =
901ed0b9af9STim Renouf       Kern.getDocument()->getNode(ProgramInfo.LDSSize);
902f5b36e56SScott Linder   Kern[".private_segment_fixed_size"] =
903ed0b9af9STim Renouf       Kern.getDocument()->getNode(ProgramInfo.ScratchSize);
904f5b36e56SScott Linder   Kern[".kernarg_segment_align"] =
905b65fa483SGuillaume Chatelet       Kern.getDocument()->getNode(std::max(Align(4), MaxKernArgAlign).value());
906f5b36e56SScott Linder   Kern[".wavefront_size"] =
907ed0b9af9STim Renouf       Kern.getDocument()->getNode(STM.getWavefrontSize());
908ed0b9af9STim Renouf   Kern[".sgpr_count"] = Kern.getDocument()->getNode(ProgramInfo.NumSGPR);
909ed0b9af9STim Renouf   Kern[".vgpr_count"] = Kern.getDocument()->getNode(ProgramInfo.NumVGPR);
910f5b36e56SScott Linder   Kern[".max_flat_workgroup_size"] =
911ed0b9af9STim Renouf       Kern.getDocument()->getNode(MFI.getMaxFlatWorkGroupSize());
912f5b36e56SScott Linder   Kern[".sgpr_spill_count"] =
913ed0b9af9STim Renouf       Kern.getDocument()->getNode(MFI.getNumSpilledSGPRs());
914f5b36e56SScott Linder   Kern[".vgpr_spill_count"] =
915ed0b9af9STim Renouf       Kern.getDocument()->getNode(MFI.getNumSpilledVGPRs());
916f5b36e56SScott Linder 
917ed0b9af9STim Renouf   return Kern;
918f5b36e56SScott Linder }
919f5b36e56SScott Linder 
920f5b36e56SScott Linder bool MetadataStreamerV3::emitTo(AMDGPUTargetStreamer &TargetStreamer) {
921ed0b9af9STim Renouf   return TargetStreamer.EmitHSAMetadata(*HSAMetadataDoc, true);
922f5b36e56SScott Linder }
923f5b36e56SScott Linder 
924f5b36e56SScott Linder void MetadataStreamerV3::begin(const Module &Mod) {
925f5b36e56SScott Linder   emitVersion();
926f5b36e56SScott Linder   emitPrintf(Mod);
927ed0b9af9STim Renouf   getRootMetadata("amdhsa.kernels") = HSAMetadataDoc->getArrayNode();
928f5b36e56SScott Linder }
929f5b36e56SScott Linder 
930f5b36e56SScott Linder void MetadataStreamerV3::end() {
931f5b36e56SScott Linder   std::string HSAMetadataString;
932f5b36e56SScott Linder   raw_string_ostream StrOS(HSAMetadataString);
933ed0b9af9STim Renouf   HSAMetadataDoc->toYAML(StrOS);
934f5b36e56SScott Linder 
935f5b36e56SScott Linder   if (DumpHSAMetadata)
936f5b36e56SScott Linder     dump(StrOS.str());
937f5b36e56SScott Linder   if (VerifyHSAMetadata)
938f5b36e56SScott Linder     verify(StrOS.str());
939f5b36e56SScott Linder }
940f5b36e56SScott Linder 
941f5b36e56SScott Linder void MetadataStreamerV3::emitKernel(const MachineFunction &MF,
942f5b36e56SScott Linder                                     const SIProgramInfo &ProgramInfo) {
943f5b36e56SScott Linder   auto &Func = MF.getFunction();
944ed0b9af9STim Renouf   auto Kern = getHSAKernelProps(MF, ProgramInfo);
945f5b36e56SScott Linder 
946f5b36e56SScott Linder   assert(Func.getCallingConv() == CallingConv::AMDGPU_KERNEL ||
947f5b36e56SScott Linder          Func.getCallingConv() == CallingConv::SPIR_KERNEL);
948f5b36e56SScott Linder 
949ed0b9af9STim Renouf   auto Kernels =
950ed0b9af9STim Renouf       getRootMetadata("amdhsa.kernels").getArray(/*Convert=*/true);
951f5b36e56SScott Linder 
952f5b36e56SScott Linder   {
953ed0b9af9STim Renouf     Kern[".name"] = Kern.getDocument()->getNode(Func.getName());
954ed0b9af9STim Renouf     Kern[".symbol"] = Kern.getDocument()->getNode(
955ed0b9af9STim Renouf         (Twine(Func.getName()) + Twine(".kd")).str(), /*Copy=*/true);
956f5b36e56SScott Linder     emitKernelLanguage(Func, Kern);
957f5b36e56SScott Linder     emitKernelAttrs(Func, Kern);
958f5b36e56SScott Linder     emitKernelArgs(Func, Kern);
959f5b36e56SScott Linder   }
960f5b36e56SScott Linder 
961ed0b9af9STim Renouf   Kernels.push_back(Kern);
962f5b36e56SScott Linder }
963f5b36e56SScott Linder 
96401ce144dSScott Linder } // end namespace HSAMD
96501ce144dSScott Linder } // end namespace AMDGPU
96601ce144dSScott Linder } // end namespace llvm
967