xref: /freebsd/contrib/llvm-project/llvm/lib/Target/AMDGPU/AMDGPUHSAMetadataStreamer.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===--- AMDGPUHSAMetadataStreamer.cpp --------------------------*- C++ -*-===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric /// \file
10*0b57cec5SDimitry Andric /// AMDGPU HSA Metadata Streamer.
11*0b57cec5SDimitry Andric ///
12*0b57cec5SDimitry Andric //
13*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
14*0b57cec5SDimitry Andric 
15*0b57cec5SDimitry Andric #include "AMDGPUHSAMetadataStreamer.h"
16*0b57cec5SDimitry Andric #include "AMDGPU.h"
17*0b57cec5SDimitry Andric #include "AMDGPUSubtarget.h"
18*0b57cec5SDimitry Andric #include "MCTargetDesc/AMDGPUTargetStreamer.h"
19*0b57cec5SDimitry Andric #include "SIMachineFunctionInfo.h"
20*0b57cec5SDimitry Andric #include "SIProgramInfo.h"
21*0b57cec5SDimitry Andric #include "Utils/AMDGPUBaseInfo.h"
22*0b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h"
23*0b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
24*0b57cec5SDimitry Andric #include "llvm/IR/Module.h"
25*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
26*0b57cec5SDimitry Andric 
27*0b57cec5SDimitry Andric namespace llvm {
28*0b57cec5SDimitry Andric 
29*0b57cec5SDimitry Andric static cl::opt<bool> DumpHSAMetadata(
30*0b57cec5SDimitry Andric     "amdgpu-dump-hsa-metadata",
31*0b57cec5SDimitry Andric     cl::desc("Dump AMDGPU HSA Metadata"));
32*0b57cec5SDimitry Andric static cl::opt<bool> VerifyHSAMetadata(
33*0b57cec5SDimitry Andric     "amdgpu-verify-hsa-metadata",
34*0b57cec5SDimitry Andric     cl::desc("Verify AMDGPU HSA Metadata"));
35*0b57cec5SDimitry Andric 
36*0b57cec5SDimitry Andric namespace AMDGPU {
37*0b57cec5SDimitry Andric namespace HSAMD {
38*0b57cec5SDimitry Andric 
39*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
40*0b57cec5SDimitry Andric // HSAMetadataStreamerV2
41*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
42*0b57cec5SDimitry Andric void MetadataStreamerV2::dump(StringRef HSAMetadataString) const {
43*0b57cec5SDimitry Andric   errs() << "AMDGPU HSA Metadata:\n" << HSAMetadataString << '\n';
44*0b57cec5SDimitry Andric }
45*0b57cec5SDimitry Andric 
46*0b57cec5SDimitry Andric void MetadataStreamerV2::verify(StringRef HSAMetadataString) const {
47*0b57cec5SDimitry Andric   errs() << "AMDGPU HSA Metadata Parser Test: ";
48*0b57cec5SDimitry Andric 
49*0b57cec5SDimitry Andric   HSAMD::Metadata FromHSAMetadataString;
50*0b57cec5SDimitry Andric   if (fromString(HSAMetadataString, FromHSAMetadataString)) {
51*0b57cec5SDimitry Andric     errs() << "FAIL\n";
52*0b57cec5SDimitry Andric     return;
53*0b57cec5SDimitry Andric   }
54*0b57cec5SDimitry Andric 
55*0b57cec5SDimitry Andric   std::string ToHSAMetadataString;
56*0b57cec5SDimitry Andric   if (toString(FromHSAMetadataString, ToHSAMetadataString)) {
57*0b57cec5SDimitry Andric     errs() << "FAIL\n";
58*0b57cec5SDimitry Andric     return;
59*0b57cec5SDimitry Andric   }
60*0b57cec5SDimitry Andric 
61*0b57cec5SDimitry Andric   errs() << (HSAMetadataString == ToHSAMetadataString ? "PASS" : "FAIL")
62*0b57cec5SDimitry Andric          << '\n';
63*0b57cec5SDimitry Andric   if (HSAMetadataString != ToHSAMetadataString) {
64*0b57cec5SDimitry Andric     errs() << "Original input: " << HSAMetadataString << '\n'
65*0b57cec5SDimitry Andric            << "Produced output: " << ToHSAMetadataString << '\n';
66*0b57cec5SDimitry Andric   }
67*0b57cec5SDimitry Andric }
68*0b57cec5SDimitry Andric 
69*0b57cec5SDimitry Andric AccessQualifier
70*0b57cec5SDimitry Andric MetadataStreamerV2::getAccessQualifier(StringRef AccQual) const {
71*0b57cec5SDimitry Andric   if (AccQual.empty())
72*0b57cec5SDimitry Andric     return AccessQualifier::Unknown;
73*0b57cec5SDimitry Andric 
74*0b57cec5SDimitry Andric   return StringSwitch<AccessQualifier>(AccQual)
75*0b57cec5SDimitry Andric              .Case("read_only",  AccessQualifier::ReadOnly)
76*0b57cec5SDimitry Andric              .Case("write_only", AccessQualifier::WriteOnly)
77*0b57cec5SDimitry Andric              .Case("read_write", AccessQualifier::ReadWrite)
78*0b57cec5SDimitry Andric              .Default(AccessQualifier::Default);
79*0b57cec5SDimitry Andric }
80*0b57cec5SDimitry Andric 
81*0b57cec5SDimitry Andric AddressSpaceQualifier
82*0b57cec5SDimitry Andric MetadataStreamerV2::getAddressSpaceQualifier(
83*0b57cec5SDimitry Andric     unsigned AddressSpace) const {
84*0b57cec5SDimitry Andric   switch (AddressSpace) {
85*0b57cec5SDimitry Andric   case AMDGPUAS::PRIVATE_ADDRESS:
86*0b57cec5SDimitry Andric     return AddressSpaceQualifier::Private;
87*0b57cec5SDimitry Andric   case AMDGPUAS::GLOBAL_ADDRESS:
88*0b57cec5SDimitry Andric     return AddressSpaceQualifier::Global;
89*0b57cec5SDimitry Andric   case AMDGPUAS::CONSTANT_ADDRESS:
90*0b57cec5SDimitry Andric     return AddressSpaceQualifier::Constant;
91*0b57cec5SDimitry Andric   case AMDGPUAS::LOCAL_ADDRESS:
92*0b57cec5SDimitry Andric     return AddressSpaceQualifier::Local;
93*0b57cec5SDimitry Andric   case AMDGPUAS::FLAT_ADDRESS:
94*0b57cec5SDimitry Andric     return AddressSpaceQualifier::Generic;
95*0b57cec5SDimitry Andric   case AMDGPUAS::REGION_ADDRESS:
96*0b57cec5SDimitry Andric     return AddressSpaceQualifier::Region;
97*0b57cec5SDimitry Andric   default:
98*0b57cec5SDimitry Andric     return AddressSpaceQualifier::Unknown;
99*0b57cec5SDimitry Andric   }
100*0b57cec5SDimitry Andric }
101*0b57cec5SDimitry Andric 
102*0b57cec5SDimitry Andric ValueKind MetadataStreamerV2::getValueKind(Type *Ty, StringRef TypeQual,
103*0b57cec5SDimitry Andric                                            StringRef BaseTypeName) const {
104*0b57cec5SDimitry Andric   if (TypeQual.find("pipe") != StringRef::npos)
105*0b57cec5SDimitry Andric     return ValueKind::Pipe;
106*0b57cec5SDimitry Andric 
107*0b57cec5SDimitry Andric   return StringSwitch<ValueKind>(BaseTypeName)
108*0b57cec5SDimitry Andric              .Case("image1d_t", ValueKind::Image)
109*0b57cec5SDimitry Andric              .Case("image1d_array_t", ValueKind::Image)
110*0b57cec5SDimitry Andric              .Case("image1d_buffer_t", ValueKind::Image)
111*0b57cec5SDimitry Andric              .Case("image2d_t", ValueKind::Image)
112*0b57cec5SDimitry Andric              .Case("image2d_array_t", ValueKind::Image)
113*0b57cec5SDimitry Andric              .Case("image2d_array_depth_t", ValueKind::Image)
114*0b57cec5SDimitry Andric              .Case("image2d_array_msaa_t", ValueKind::Image)
115*0b57cec5SDimitry Andric              .Case("image2d_array_msaa_depth_t", ValueKind::Image)
116*0b57cec5SDimitry Andric              .Case("image2d_depth_t", ValueKind::Image)
117*0b57cec5SDimitry Andric              .Case("image2d_msaa_t", ValueKind::Image)
118*0b57cec5SDimitry Andric              .Case("image2d_msaa_depth_t", ValueKind::Image)
119*0b57cec5SDimitry Andric              .Case("image3d_t", ValueKind::Image)
120*0b57cec5SDimitry Andric              .Case("sampler_t", ValueKind::Sampler)
121*0b57cec5SDimitry Andric              .Case("queue_t", ValueKind::Queue)
122*0b57cec5SDimitry Andric              .Default(isa<PointerType>(Ty) ?
123*0b57cec5SDimitry Andric                           (Ty->getPointerAddressSpace() ==
124*0b57cec5SDimitry Andric                            AMDGPUAS::LOCAL_ADDRESS ?
125*0b57cec5SDimitry Andric                            ValueKind::DynamicSharedPointer :
126*0b57cec5SDimitry Andric                            ValueKind::GlobalBuffer) :
127*0b57cec5SDimitry Andric                       ValueKind::ByValue);
128*0b57cec5SDimitry Andric }
129*0b57cec5SDimitry Andric 
130*0b57cec5SDimitry Andric ValueType MetadataStreamerV2::getValueType(Type *Ty, StringRef TypeName) const {
131*0b57cec5SDimitry Andric   switch (Ty->getTypeID()) {
132*0b57cec5SDimitry Andric   case Type::IntegerTyID: {
133*0b57cec5SDimitry Andric     auto Signed = !TypeName.startswith("u");
134*0b57cec5SDimitry Andric     switch (Ty->getIntegerBitWidth()) {
135*0b57cec5SDimitry Andric     case 8:
136*0b57cec5SDimitry Andric       return Signed ? ValueType::I8 : ValueType::U8;
137*0b57cec5SDimitry Andric     case 16:
138*0b57cec5SDimitry Andric       return Signed ? ValueType::I16 : ValueType::U16;
139*0b57cec5SDimitry Andric     case 32:
140*0b57cec5SDimitry Andric       return Signed ? ValueType::I32 : ValueType::U32;
141*0b57cec5SDimitry Andric     case 64:
142*0b57cec5SDimitry Andric       return Signed ? ValueType::I64 : ValueType::U64;
143*0b57cec5SDimitry Andric     default:
144*0b57cec5SDimitry Andric       return ValueType::Struct;
145*0b57cec5SDimitry Andric     }
146*0b57cec5SDimitry Andric   }
147*0b57cec5SDimitry Andric   case Type::HalfTyID:
148*0b57cec5SDimitry Andric     return ValueType::F16;
149*0b57cec5SDimitry Andric   case Type::FloatTyID:
150*0b57cec5SDimitry Andric     return ValueType::F32;
151*0b57cec5SDimitry Andric   case Type::DoubleTyID:
152*0b57cec5SDimitry Andric     return ValueType::F64;
153*0b57cec5SDimitry Andric   case Type::PointerTyID:
154*0b57cec5SDimitry Andric     return getValueType(Ty->getPointerElementType(), TypeName);
155*0b57cec5SDimitry Andric   case Type::VectorTyID:
156*0b57cec5SDimitry Andric     return getValueType(Ty->getVectorElementType(), TypeName);
157*0b57cec5SDimitry Andric   default:
158*0b57cec5SDimitry Andric     return ValueType::Struct;
159*0b57cec5SDimitry Andric   }
160*0b57cec5SDimitry Andric }
161*0b57cec5SDimitry Andric 
162*0b57cec5SDimitry Andric std::string MetadataStreamerV2::getTypeName(Type *Ty, bool Signed) const {
163*0b57cec5SDimitry Andric   switch (Ty->getTypeID()) {
164*0b57cec5SDimitry Andric   case Type::IntegerTyID: {
165*0b57cec5SDimitry Andric     if (!Signed)
166*0b57cec5SDimitry Andric       return (Twine('u') + getTypeName(Ty, true)).str();
167*0b57cec5SDimitry Andric 
168*0b57cec5SDimitry Andric     auto BitWidth = Ty->getIntegerBitWidth();
169*0b57cec5SDimitry Andric     switch (BitWidth) {
170*0b57cec5SDimitry Andric     case 8:
171*0b57cec5SDimitry Andric       return "char";
172*0b57cec5SDimitry Andric     case 16:
173*0b57cec5SDimitry Andric       return "short";
174*0b57cec5SDimitry Andric     case 32:
175*0b57cec5SDimitry Andric       return "int";
176*0b57cec5SDimitry Andric     case 64:
177*0b57cec5SDimitry Andric       return "long";
178*0b57cec5SDimitry Andric     default:
179*0b57cec5SDimitry Andric       return (Twine('i') + Twine(BitWidth)).str();
180*0b57cec5SDimitry Andric     }
181*0b57cec5SDimitry Andric   }
182*0b57cec5SDimitry Andric   case Type::HalfTyID:
183*0b57cec5SDimitry Andric     return "half";
184*0b57cec5SDimitry Andric   case Type::FloatTyID:
185*0b57cec5SDimitry Andric     return "float";
186*0b57cec5SDimitry Andric   case Type::DoubleTyID:
187*0b57cec5SDimitry Andric     return "double";
188*0b57cec5SDimitry Andric   case Type::VectorTyID: {
189*0b57cec5SDimitry Andric     auto VecTy = cast<VectorType>(Ty);
190*0b57cec5SDimitry Andric     auto ElTy = VecTy->getElementType();
191*0b57cec5SDimitry Andric     auto NumElements = VecTy->getVectorNumElements();
192*0b57cec5SDimitry Andric     return (Twine(getTypeName(ElTy, Signed)) + Twine(NumElements)).str();
193*0b57cec5SDimitry Andric   }
194*0b57cec5SDimitry Andric   default:
195*0b57cec5SDimitry Andric     return "unknown";
196*0b57cec5SDimitry Andric   }
197*0b57cec5SDimitry Andric }
198*0b57cec5SDimitry Andric 
199*0b57cec5SDimitry Andric std::vector<uint32_t>
200*0b57cec5SDimitry Andric MetadataStreamerV2::getWorkGroupDimensions(MDNode *Node) const {
201*0b57cec5SDimitry Andric   std::vector<uint32_t> Dims;
202*0b57cec5SDimitry Andric   if (Node->getNumOperands() != 3)
203*0b57cec5SDimitry Andric     return Dims;
204*0b57cec5SDimitry Andric 
205*0b57cec5SDimitry Andric   for (auto &Op : Node->operands())
206*0b57cec5SDimitry Andric     Dims.push_back(mdconst::extract<ConstantInt>(Op)->getZExtValue());
207*0b57cec5SDimitry Andric   return Dims;
208*0b57cec5SDimitry Andric }
209*0b57cec5SDimitry Andric 
210*0b57cec5SDimitry Andric Kernel::CodeProps::Metadata
211*0b57cec5SDimitry Andric MetadataStreamerV2::getHSACodeProps(const MachineFunction &MF,
212*0b57cec5SDimitry Andric                                     const SIProgramInfo &ProgramInfo) const {
213*0b57cec5SDimitry Andric   const GCNSubtarget &STM = MF.getSubtarget<GCNSubtarget>();
214*0b57cec5SDimitry Andric   const SIMachineFunctionInfo &MFI = *MF.getInfo<SIMachineFunctionInfo>();
215*0b57cec5SDimitry Andric   HSAMD::Kernel::CodeProps::Metadata HSACodeProps;
216*0b57cec5SDimitry Andric   const Function &F = MF.getFunction();
217*0b57cec5SDimitry Andric 
218*0b57cec5SDimitry Andric   assert(F.getCallingConv() == CallingConv::AMDGPU_KERNEL ||
219*0b57cec5SDimitry Andric          F.getCallingConv() == CallingConv::SPIR_KERNEL);
220*0b57cec5SDimitry Andric 
221*0b57cec5SDimitry Andric   unsigned MaxKernArgAlign;
222*0b57cec5SDimitry Andric   HSACodeProps.mKernargSegmentSize = STM.getKernArgSegmentSize(F,
223*0b57cec5SDimitry Andric                                                                MaxKernArgAlign);
224*0b57cec5SDimitry Andric   HSACodeProps.mGroupSegmentFixedSize = ProgramInfo.LDSSize;
225*0b57cec5SDimitry Andric   HSACodeProps.mPrivateSegmentFixedSize = ProgramInfo.ScratchSize;
226*0b57cec5SDimitry Andric   HSACodeProps.mKernargSegmentAlign = std::max(MaxKernArgAlign, 4u);
227*0b57cec5SDimitry Andric   HSACodeProps.mWavefrontSize = STM.getWavefrontSize();
228*0b57cec5SDimitry Andric   HSACodeProps.mNumSGPRs = ProgramInfo.NumSGPR;
229*0b57cec5SDimitry Andric   HSACodeProps.mNumVGPRs = ProgramInfo.NumVGPR;
230*0b57cec5SDimitry Andric   HSACodeProps.mMaxFlatWorkGroupSize = MFI.getMaxFlatWorkGroupSize();
231*0b57cec5SDimitry Andric   HSACodeProps.mIsDynamicCallStack = ProgramInfo.DynamicCallStack;
232*0b57cec5SDimitry Andric   HSACodeProps.mIsXNACKEnabled = STM.isXNACKEnabled();
233*0b57cec5SDimitry Andric   HSACodeProps.mNumSpilledSGPRs = MFI.getNumSpilledSGPRs();
234*0b57cec5SDimitry Andric   HSACodeProps.mNumSpilledVGPRs = MFI.getNumSpilledVGPRs();
235*0b57cec5SDimitry Andric 
236*0b57cec5SDimitry Andric   return HSACodeProps;
237*0b57cec5SDimitry Andric }
238*0b57cec5SDimitry Andric 
239*0b57cec5SDimitry Andric Kernel::DebugProps::Metadata
240*0b57cec5SDimitry Andric MetadataStreamerV2::getHSADebugProps(const MachineFunction &MF,
241*0b57cec5SDimitry Andric                                      const SIProgramInfo &ProgramInfo) const {
242*0b57cec5SDimitry Andric   return HSAMD::Kernel::DebugProps::Metadata();
243*0b57cec5SDimitry Andric }
244*0b57cec5SDimitry Andric 
245*0b57cec5SDimitry Andric void MetadataStreamerV2::emitVersion() {
246*0b57cec5SDimitry Andric   auto &Version = HSAMetadata.mVersion;
247*0b57cec5SDimitry Andric 
248*0b57cec5SDimitry Andric   Version.push_back(VersionMajor);
249*0b57cec5SDimitry Andric   Version.push_back(VersionMinor);
250*0b57cec5SDimitry Andric }
251*0b57cec5SDimitry Andric 
252*0b57cec5SDimitry Andric void MetadataStreamerV2::emitPrintf(const Module &Mod) {
253*0b57cec5SDimitry Andric   auto &Printf = HSAMetadata.mPrintf;
254*0b57cec5SDimitry Andric 
255*0b57cec5SDimitry Andric   auto Node = Mod.getNamedMetadata("llvm.printf.fmts");
256*0b57cec5SDimitry Andric   if (!Node)
257*0b57cec5SDimitry Andric     return;
258*0b57cec5SDimitry Andric 
259*0b57cec5SDimitry Andric   for (auto Op : Node->operands())
260*0b57cec5SDimitry Andric     if (Op->getNumOperands())
261*0b57cec5SDimitry Andric       Printf.push_back(cast<MDString>(Op->getOperand(0))->getString());
262*0b57cec5SDimitry Andric }
263*0b57cec5SDimitry Andric 
264*0b57cec5SDimitry Andric void MetadataStreamerV2::emitKernelLanguage(const Function &Func) {
265*0b57cec5SDimitry Andric   auto &Kernel = HSAMetadata.mKernels.back();
266*0b57cec5SDimitry Andric 
267*0b57cec5SDimitry Andric   // TODO: What about other languages?
268*0b57cec5SDimitry Andric   auto Node = Func.getParent()->getNamedMetadata("opencl.ocl.version");
269*0b57cec5SDimitry Andric   if (!Node || !Node->getNumOperands())
270*0b57cec5SDimitry Andric     return;
271*0b57cec5SDimitry Andric   auto Op0 = Node->getOperand(0);
272*0b57cec5SDimitry Andric   if (Op0->getNumOperands() <= 1)
273*0b57cec5SDimitry Andric     return;
274*0b57cec5SDimitry Andric 
275*0b57cec5SDimitry Andric   Kernel.mLanguage = "OpenCL C";
276*0b57cec5SDimitry Andric   Kernel.mLanguageVersion.push_back(
277*0b57cec5SDimitry Andric       mdconst::extract<ConstantInt>(Op0->getOperand(0))->getZExtValue());
278*0b57cec5SDimitry Andric   Kernel.mLanguageVersion.push_back(
279*0b57cec5SDimitry Andric       mdconst::extract<ConstantInt>(Op0->getOperand(1))->getZExtValue());
280*0b57cec5SDimitry Andric }
281*0b57cec5SDimitry Andric 
282*0b57cec5SDimitry Andric void MetadataStreamerV2::emitKernelAttrs(const Function &Func) {
283*0b57cec5SDimitry Andric   auto &Attrs = HSAMetadata.mKernels.back().mAttrs;
284*0b57cec5SDimitry Andric 
285*0b57cec5SDimitry Andric   if (auto Node = Func.getMetadata("reqd_work_group_size"))
286*0b57cec5SDimitry Andric     Attrs.mReqdWorkGroupSize = getWorkGroupDimensions(Node);
287*0b57cec5SDimitry Andric   if (auto Node = Func.getMetadata("work_group_size_hint"))
288*0b57cec5SDimitry Andric     Attrs.mWorkGroupSizeHint = getWorkGroupDimensions(Node);
289*0b57cec5SDimitry Andric   if (auto Node = Func.getMetadata("vec_type_hint")) {
290*0b57cec5SDimitry Andric     Attrs.mVecTypeHint = getTypeName(
291*0b57cec5SDimitry Andric         cast<ValueAsMetadata>(Node->getOperand(0))->getType(),
292*0b57cec5SDimitry Andric         mdconst::extract<ConstantInt>(Node->getOperand(1))->getZExtValue());
293*0b57cec5SDimitry Andric   }
294*0b57cec5SDimitry Andric   if (Func.hasFnAttribute("runtime-handle")) {
295*0b57cec5SDimitry Andric     Attrs.mRuntimeHandle =
296*0b57cec5SDimitry Andric         Func.getFnAttribute("runtime-handle").getValueAsString().str();
297*0b57cec5SDimitry Andric   }
298*0b57cec5SDimitry Andric }
299*0b57cec5SDimitry Andric 
300*0b57cec5SDimitry Andric void MetadataStreamerV2::emitKernelArgs(const Function &Func) {
301*0b57cec5SDimitry Andric   for (auto &Arg : Func.args())
302*0b57cec5SDimitry Andric     emitKernelArg(Arg);
303*0b57cec5SDimitry Andric 
304*0b57cec5SDimitry Andric   emitHiddenKernelArgs(Func);
305*0b57cec5SDimitry Andric }
306*0b57cec5SDimitry Andric 
307*0b57cec5SDimitry Andric void MetadataStreamerV2::emitKernelArg(const Argument &Arg) {
308*0b57cec5SDimitry Andric   auto Func = Arg.getParent();
309*0b57cec5SDimitry Andric   auto ArgNo = Arg.getArgNo();
310*0b57cec5SDimitry Andric   const MDNode *Node;
311*0b57cec5SDimitry Andric 
312*0b57cec5SDimitry Andric   StringRef Name;
313*0b57cec5SDimitry Andric   Node = Func->getMetadata("kernel_arg_name");
314*0b57cec5SDimitry Andric   if (Node && ArgNo < Node->getNumOperands())
315*0b57cec5SDimitry Andric     Name = cast<MDString>(Node->getOperand(ArgNo))->getString();
316*0b57cec5SDimitry Andric   else if (Arg.hasName())
317*0b57cec5SDimitry Andric     Name = Arg.getName();
318*0b57cec5SDimitry Andric 
319*0b57cec5SDimitry Andric   StringRef TypeName;
320*0b57cec5SDimitry Andric   Node = Func->getMetadata("kernel_arg_type");
321*0b57cec5SDimitry Andric   if (Node && ArgNo < Node->getNumOperands())
322*0b57cec5SDimitry Andric     TypeName = cast<MDString>(Node->getOperand(ArgNo))->getString();
323*0b57cec5SDimitry Andric 
324*0b57cec5SDimitry Andric   StringRef BaseTypeName;
325*0b57cec5SDimitry Andric   Node = Func->getMetadata("kernel_arg_base_type");
326*0b57cec5SDimitry Andric   if (Node && ArgNo < Node->getNumOperands())
327*0b57cec5SDimitry Andric     BaseTypeName = cast<MDString>(Node->getOperand(ArgNo))->getString();
328*0b57cec5SDimitry Andric 
329*0b57cec5SDimitry Andric   StringRef AccQual;
330*0b57cec5SDimitry Andric   if (Arg.getType()->isPointerTy() && Arg.onlyReadsMemory() &&
331*0b57cec5SDimitry Andric       Arg.hasNoAliasAttr()) {
332*0b57cec5SDimitry Andric     AccQual = "read_only";
333*0b57cec5SDimitry Andric   } else {
334*0b57cec5SDimitry Andric     Node = Func->getMetadata("kernel_arg_access_qual");
335*0b57cec5SDimitry Andric     if (Node && ArgNo < Node->getNumOperands())
336*0b57cec5SDimitry Andric       AccQual = cast<MDString>(Node->getOperand(ArgNo))->getString();
337*0b57cec5SDimitry Andric   }
338*0b57cec5SDimitry Andric 
339*0b57cec5SDimitry Andric   StringRef TypeQual;
340*0b57cec5SDimitry Andric   Node = Func->getMetadata("kernel_arg_type_qual");
341*0b57cec5SDimitry Andric   if (Node && ArgNo < Node->getNumOperands())
342*0b57cec5SDimitry Andric     TypeQual = cast<MDString>(Node->getOperand(ArgNo))->getString();
343*0b57cec5SDimitry Andric 
344*0b57cec5SDimitry Andric   Type *Ty = Arg.getType();
345*0b57cec5SDimitry Andric   const DataLayout &DL = Func->getParent()->getDataLayout();
346*0b57cec5SDimitry Andric 
347*0b57cec5SDimitry Andric   unsigned PointeeAlign = 0;
348*0b57cec5SDimitry Andric   if (auto PtrTy = dyn_cast<PointerType>(Ty)) {
349*0b57cec5SDimitry Andric     if (PtrTy->getAddressSpace() == AMDGPUAS::LOCAL_ADDRESS) {
350*0b57cec5SDimitry Andric       PointeeAlign = Arg.getParamAlignment();
351*0b57cec5SDimitry Andric       if (PointeeAlign == 0)
352*0b57cec5SDimitry Andric         PointeeAlign = DL.getABITypeAlignment(PtrTy->getElementType());
353*0b57cec5SDimitry Andric     }
354*0b57cec5SDimitry Andric   }
355*0b57cec5SDimitry Andric 
356*0b57cec5SDimitry Andric   emitKernelArg(DL, Ty, getValueKind(Arg.getType(), TypeQual, BaseTypeName),
357*0b57cec5SDimitry Andric                 PointeeAlign, Name, TypeName, BaseTypeName, AccQual, TypeQual);
358*0b57cec5SDimitry Andric }
359*0b57cec5SDimitry Andric 
360*0b57cec5SDimitry Andric void MetadataStreamerV2::emitKernelArg(const DataLayout &DL, Type *Ty,
361*0b57cec5SDimitry Andric                                        ValueKind ValueKind,
362*0b57cec5SDimitry Andric                                        unsigned PointeeAlign, StringRef Name,
363*0b57cec5SDimitry Andric                                        StringRef TypeName,
364*0b57cec5SDimitry Andric                                        StringRef BaseTypeName,
365*0b57cec5SDimitry Andric                                        StringRef AccQual, StringRef TypeQual) {
366*0b57cec5SDimitry Andric   HSAMetadata.mKernels.back().mArgs.push_back(Kernel::Arg::Metadata());
367*0b57cec5SDimitry Andric   auto &Arg = HSAMetadata.mKernels.back().mArgs.back();
368*0b57cec5SDimitry Andric 
369*0b57cec5SDimitry Andric   Arg.mName = Name;
370*0b57cec5SDimitry Andric   Arg.mTypeName = TypeName;
371*0b57cec5SDimitry Andric   Arg.mSize = DL.getTypeAllocSize(Ty);
372*0b57cec5SDimitry Andric   Arg.mAlign = DL.getABITypeAlignment(Ty);
373*0b57cec5SDimitry Andric   Arg.mValueKind = ValueKind;
374*0b57cec5SDimitry Andric   Arg.mValueType = getValueType(Ty, BaseTypeName);
375*0b57cec5SDimitry Andric   Arg.mPointeeAlign = PointeeAlign;
376*0b57cec5SDimitry Andric 
377*0b57cec5SDimitry Andric   if (auto PtrTy = dyn_cast<PointerType>(Ty))
378*0b57cec5SDimitry Andric     Arg.mAddrSpaceQual = getAddressSpaceQualifier(PtrTy->getAddressSpace());
379*0b57cec5SDimitry Andric 
380*0b57cec5SDimitry Andric   Arg.mAccQual = getAccessQualifier(AccQual);
381*0b57cec5SDimitry Andric 
382*0b57cec5SDimitry Andric   // TODO: Emit Arg.mActualAccQual.
383*0b57cec5SDimitry Andric 
384*0b57cec5SDimitry Andric   SmallVector<StringRef, 1> SplitTypeQuals;
385*0b57cec5SDimitry Andric   TypeQual.split(SplitTypeQuals, " ", -1, false);
386*0b57cec5SDimitry Andric   for (StringRef Key : SplitTypeQuals) {
387*0b57cec5SDimitry Andric     auto P = StringSwitch<bool*>(Key)
388*0b57cec5SDimitry Andric                  .Case("const",    &Arg.mIsConst)
389*0b57cec5SDimitry Andric                  .Case("restrict", &Arg.mIsRestrict)
390*0b57cec5SDimitry Andric                  .Case("volatile", &Arg.mIsVolatile)
391*0b57cec5SDimitry Andric                  .Case("pipe",     &Arg.mIsPipe)
392*0b57cec5SDimitry Andric                  .Default(nullptr);
393*0b57cec5SDimitry Andric     if (P)
394*0b57cec5SDimitry Andric       *P = true;
395*0b57cec5SDimitry Andric   }
396*0b57cec5SDimitry Andric }
397*0b57cec5SDimitry Andric 
398*0b57cec5SDimitry Andric void MetadataStreamerV2::emitHiddenKernelArgs(const Function &Func) {
399*0b57cec5SDimitry Andric   int HiddenArgNumBytes =
400*0b57cec5SDimitry Andric       getIntegerAttribute(Func, "amdgpu-implicitarg-num-bytes", 0);
401*0b57cec5SDimitry Andric 
402*0b57cec5SDimitry Andric   if (!HiddenArgNumBytes)
403*0b57cec5SDimitry Andric     return;
404*0b57cec5SDimitry Andric 
405*0b57cec5SDimitry Andric   auto &DL = Func.getParent()->getDataLayout();
406*0b57cec5SDimitry Andric   auto Int64Ty = Type::getInt64Ty(Func.getContext());
407*0b57cec5SDimitry Andric 
408*0b57cec5SDimitry Andric   if (HiddenArgNumBytes >= 8)
409*0b57cec5SDimitry Andric     emitKernelArg(DL, Int64Ty, ValueKind::HiddenGlobalOffsetX);
410*0b57cec5SDimitry Andric   if (HiddenArgNumBytes >= 16)
411*0b57cec5SDimitry Andric     emitKernelArg(DL, Int64Ty, ValueKind::HiddenGlobalOffsetY);
412*0b57cec5SDimitry Andric   if (HiddenArgNumBytes >= 24)
413*0b57cec5SDimitry Andric     emitKernelArg(DL, Int64Ty, ValueKind::HiddenGlobalOffsetZ);
414*0b57cec5SDimitry Andric 
415*0b57cec5SDimitry Andric   auto Int8PtrTy = Type::getInt8PtrTy(Func.getContext(),
416*0b57cec5SDimitry Andric                                       AMDGPUAS::GLOBAL_ADDRESS);
417*0b57cec5SDimitry Andric 
418*0b57cec5SDimitry Andric   // Emit "printf buffer" argument if printf is used, otherwise emit dummy
419*0b57cec5SDimitry Andric   // "none" argument.
420*0b57cec5SDimitry Andric   if (HiddenArgNumBytes >= 32) {
421*0b57cec5SDimitry Andric     if (Func.getParent()->getNamedMetadata("llvm.printf.fmts"))
422*0b57cec5SDimitry Andric       emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenPrintfBuffer);
423*0b57cec5SDimitry Andric     else
424*0b57cec5SDimitry Andric       emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenNone);
425*0b57cec5SDimitry Andric   }
426*0b57cec5SDimitry Andric 
427*0b57cec5SDimitry Andric   // Emit "default queue" and "completion action" arguments if enqueue kernel is
428*0b57cec5SDimitry Andric   // used, otherwise emit dummy "none" arguments.
429*0b57cec5SDimitry Andric   if (HiddenArgNumBytes >= 48) {
430*0b57cec5SDimitry Andric     if (Func.hasFnAttribute("calls-enqueue-kernel")) {
431*0b57cec5SDimitry Andric       emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenDefaultQueue);
432*0b57cec5SDimitry Andric       emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenCompletionAction);
433*0b57cec5SDimitry Andric     } else {
434*0b57cec5SDimitry Andric       emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenNone);
435*0b57cec5SDimitry Andric       emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenNone);
436*0b57cec5SDimitry Andric     }
437*0b57cec5SDimitry Andric   }
438*0b57cec5SDimitry Andric 
439*0b57cec5SDimitry Andric   // Emit the pointer argument for multi-grid object.
440*0b57cec5SDimitry Andric   if (HiddenArgNumBytes >= 56)
441*0b57cec5SDimitry Andric     emitKernelArg(DL, Int8PtrTy, ValueKind::HiddenMultiGridSyncArg);
442*0b57cec5SDimitry Andric }
443*0b57cec5SDimitry Andric 
444*0b57cec5SDimitry Andric bool MetadataStreamerV2::emitTo(AMDGPUTargetStreamer &TargetStreamer) {
445*0b57cec5SDimitry Andric   return TargetStreamer.EmitHSAMetadata(getHSAMetadata());
446*0b57cec5SDimitry Andric }
447*0b57cec5SDimitry Andric 
448*0b57cec5SDimitry Andric void MetadataStreamerV2::begin(const Module &Mod) {
449*0b57cec5SDimitry Andric   emitVersion();
450*0b57cec5SDimitry Andric   emitPrintf(Mod);
451*0b57cec5SDimitry Andric }
452*0b57cec5SDimitry Andric 
453*0b57cec5SDimitry Andric void MetadataStreamerV2::end() {
454*0b57cec5SDimitry Andric   std::string HSAMetadataString;
455*0b57cec5SDimitry Andric   if (toString(HSAMetadata, HSAMetadataString))
456*0b57cec5SDimitry Andric     return;
457*0b57cec5SDimitry Andric 
458*0b57cec5SDimitry Andric   if (DumpHSAMetadata)
459*0b57cec5SDimitry Andric     dump(HSAMetadataString);
460*0b57cec5SDimitry Andric   if (VerifyHSAMetadata)
461*0b57cec5SDimitry Andric     verify(HSAMetadataString);
462*0b57cec5SDimitry Andric }
463*0b57cec5SDimitry Andric 
464*0b57cec5SDimitry Andric void MetadataStreamerV2::emitKernel(const MachineFunction &MF,
465*0b57cec5SDimitry Andric                                     const SIProgramInfo &ProgramInfo) {
466*0b57cec5SDimitry Andric   auto &Func = MF.getFunction();
467*0b57cec5SDimitry Andric   if (Func.getCallingConv() != CallingConv::AMDGPU_KERNEL)
468*0b57cec5SDimitry Andric     return;
469*0b57cec5SDimitry Andric 
470*0b57cec5SDimitry Andric   auto CodeProps = getHSACodeProps(MF, ProgramInfo);
471*0b57cec5SDimitry Andric   auto DebugProps = getHSADebugProps(MF, ProgramInfo);
472*0b57cec5SDimitry Andric 
473*0b57cec5SDimitry Andric   HSAMetadata.mKernels.push_back(Kernel::Metadata());
474*0b57cec5SDimitry Andric   auto &Kernel = HSAMetadata.mKernels.back();
475*0b57cec5SDimitry Andric 
476*0b57cec5SDimitry Andric   Kernel.mName = Func.getName();
477*0b57cec5SDimitry Andric   Kernel.mSymbolName = (Twine(Func.getName()) + Twine("@kd")).str();
478*0b57cec5SDimitry Andric   emitKernelLanguage(Func);
479*0b57cec5SDimitry Andric   emitKernelAttrs(Func);
480*0b57cec5SDimitry Andric   emitKernelArgs(Func);
481*0b57cec5SDimitry Andric   HSAMetadata.mKernels.back().mCodeProps = CodeProps;
482*0b57cec5SDimitry Andric   HSAMetadata.mKernels.back().mDebugProps = DebugProps;
483*0b57cec5SDimitry Andric }
484*0b57cec5SDimitry Andric 
485*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
486*0b57cec5SDimitry Andric // HSAMetadataStreamerV3
487*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
488*0b57cec5SDimitry Andric 
489*0b57cec5SDimitry Andric void MetadataStreamerV3::dump(StringRef HSAMetadataString) const {
490*0b57cec5SDimitry Andric   errs() << "AMDGPU HSA Metadata:\n" << HSAMetadataString << '\n';
491*0b57cec5SDimitry Andric }
492*0b57cec5SDimitry Andric 
493*0b57cec5SDimitry Andric void MetadataStreamerV3::verify(StringRef HSAMetadataString) const {
494*0b57cec5SDimitry Andric   errs() << "AMDGPU HSA Metadata Parser Test: ";
495*0b57cec5SDimitry Andric 
496*0b57cec5SDimitry Andric   msgpack::Document FromHSAMetadataString;
497*0b57cec5SDimitry Andric 
498*0b57cec5SDimitry Andric   if (!FromHSAMetadataString.fromYAML(HSAMetadataString)) {
499*0b57cec5SDimitry Andric     errs() << "FAIL\n";
500*0b57cec5SDimitry Andric     return;
501*0b57cec5SDimitry Andric   }
502*0b57cec5SDimitry Andric 
503*0b57cec5SDimitry Andric   std::string ToHSAMetadataString;
504*0b57cec5SDimitry Andric   raw_string_ostream StrOS(ToHSAMetadataString);
505*0b57cec5SDimitry Andric   FromHSAMetadataString.toYAML(StrOS);
506*0b57cec5SDimitry Andric 
507*0b57cec5SDimitry Andric   errs() << (HSAMetadataString == StrOS.str() ? "PASS" : "FAIL") << '\n';
508*0b57cec5SDimitry Andric   if (HSAMetadataString != ToHSAMetadataString) {
509*0b57cec5SDimitry Andric     errs() << "Original input: " << HSAMetadataString << '\n'
510*0b57cec5SDimitry Andric            << "Produced output: " << StrOS.str() << '\n';
511*0b57cec5SDimitry Andric   }
512*0b57cec5SDimitry Andric }
513*0b57cec5SDimitry Andric 
514*0b57cec5SDimitry Andric Optional<StringRef>
515*0b57cec5SDimitry Andric MetadataStreamerV3::getAccessQualifier(StringRef AccQual) const {
516*0b57cec5SDimitry Andric   return StringSwitch<Optional<StringRef>>(AccQual)
517*0b57cec5SDimitry Andric       .Case("read_only", StringRef("read_only"))
518*0b57cec5SDimitry Andric       .Case("write_only", StringRef("write_only"))
519*0b57cec5SDimitry Andric       .Case("read_write", StringRef("read_write"))
520*0b57cec5SDimitry Andric       .Default(None);
521*0b57cec5SDimitry Andric }
522*0b57cec5SDimitry Andric 
523*0b57cec5SDimitry Andric Optional<StringRef>
524*0b57cec5SDimitry Andric MetadataStreamerV3::getAddressSpaceQualifier(unsigned AddressSpace) const {
525*0b57cec5SDimitry Andric   switch (AddressSpace) {
526*0b57cec5SDimitry Andric   case AMDGPUAS::PRIVATE_ADDRESS:
527*0b57cec5SDimitry Andric     return StringRef("private");
528*0b57cec5SDimitry Andric   case AMDGPUAS::GLOBAL_ADDRESS:
529*0b57cec5SDimitry Andric     return StringRef("global");
530*0b57cec5SDimitry Andric   case AMDGPUAS::CONSTANT_ADDRESS:
531*0b57cec5SDimitry Andric     return StringRef("constant");
532*0b57cec5SDimitry Andric   case AMDGPUAS::LOCAL_ADDRESS:
533*0b57cec5SDimitry Andric     return StringRef("local");
534*0b57cec5SDimitry Andric   case AMDGPUAS::FLAT_ADDRESS:
535*0b57cec5SDimitry Andric     return StringRef("generic");
536*0b57cec5SDimitry Andric   case AMDGPUAS::REGION_ADDRESS:
537*0b57cec5SDimitry Andric     return StringRef("region");
538*0b57cec5SDimitry Andric   default:
539*0b57cec5SDimitry Andric     return None;
540*0b57cec5SDimitry Andric   }
541*0b57cec5SDimitry Andric }
542*0b57cec5SDimitry Andric 
543*0b57cec5SDimitry Andric StringRef MetadataStreamerV3::getValueKind(Type *Ty, StringRef TypeQual,
544*0b57cec5SDimitry Andric                                            StringRef BaseTypeName) const {
545*0b57cec5SDimitry Andric   if (TypeQual.find("pipe") != StringRef::npos)
546*0b57cec5SDimitry Andric     return "pipe";
547*0b57cec5SDimitry Andric 
548*0b57cec5SDimitry Andric   return StringSwitch<StringRef>(BaseTypeName)
549*0b57cec5SDimitry Andric       .Case("image1d_t", "image")
550*0b57cec5SDimitry Andric       .Case("image1d_array_t", "image")
551*0b57cec5SDimitry Andric       .Case("image1d_buffer_t", "image")
552*0b57cec5SDimitry Andric       .Case("image2d_t", "image")
553*0b57cec5SDimitry Andric       .Case("image2d_array_t", "image")
554*0b57cec5SDimitry Andric       .Case("image2d_array_depth_t", "image")
555*0b57cec5SDimitry Andric       .Case("image2d_array_msaa_t", "image")
556*0b57cec5SDimitry Andric       .Case("image2d_array_msaa_depth_t", "image")
557*0b57cec5SDimitry Andric       .Case("image2d_depth_t", "image")
558*0b57cec5SDimitry Andric       .Case("image2d_msaa_t", "image")
559*0b57cec5SDimitry Andric       .Case("image2d_msaa_depth_t", "image")
560*0b57cec5SDimitry Andric       .Case("image3d_t", "image")
561*0b57cec5SDimitry Andric       .Case("sampler_t", "sampler")
562*0b57cec5SDimitry Andric       .Case("queue_t", "queue")
563*0b57cec5SDimitry Andric       .Default(isa<PointerType>(Ty)
564*0b57cec5SDimitry Andric                    ? (Ty->getPointerAddressSpace() == AMDGPUAS::LOCAL_ADDRESS
565*0b57cec5SDimitry Andric                           ? "dynamic_shared_pointer"
566*0b57cec5SDimitry Andric                           : "global_buffer")
567*0b57cec5SDimitry Andric                    : "by_value");
568*0b57cec5SDimitry Andric }
569*0b57cec5SDimitry Andric 
570*0b57cec5SDimitry Andric StringRef MetadataStreamerV3::getValueType(Type *Ty, StringRef TypeName) const {
571*0b57cec5SDimitry Andric   switch (Ty->getTypeID()) {
572*0b57cec5SDimitry Andric   case Type::IntegerTyID: {
573*0b57cec5SDimitry Andric     auto Signed = !TypeName.startswith("u");
574*0b57cec5SDimitry Andric     switch (Ty->getIntegerBitWidth()) {
575*0b57cec5SDimitry Andric     case 8:
576*0b57cec5SDimitry Andric       return Signed ? "i8" : "u8";
577*0b57cec5SDimitry Andric     case 16:
578*0b57cec5SDimitry Andric       return Signed ? "i16" : "u16";
579*0b57cec5SDimitry Andric     case 32:
580*0b57cec5SDimitry Andric       return Signed ? "i32" : "u32";
581*0b57cec5SDimitry Andric     case 64:
582*0b57cec5SDimitry Andric       return Signed ? "i64" : "u64";
583*0b57cec5SDimitry Andric     default:
584*0b57cec5SDimitry Andric       return "struct";
585*0b57cec5SDimitry Andric     }
586*0b57cec5SDimitry Andric   }
587*0b57cec5SDimitry Andric   case Type::HalfTyID:
588*0b57cec5SDimitry Andric     return "f16";
589*0b57cec5SDimitry Andric   case Type::FloatTyID:
590*0b57cec5SDimitry Andric     return "f32";
591*0b57cec5SDimitry Andric   case Type::DoubleTyID:
592*0b57cec5SDimitry Andric     return "f64";
593*0b57cec5SDimitry Andric   case Type::PointerTyID:
594*0b57cec5SDimitry Andric     return getValueType(Ty->getPointerElementType(), TypeName);
595*0b57cec5SDimitry Andric   case Type::VectorTyID:
596*0b57cec5SDimitry Andric     return getValueType(Ty->getVectorElementType(), TypeName);
597*0b57cec5SDimitry Andric   default:
598*0b57cec5SDimitry Andric     return "struct";
599*0b57cec5SDimitry Andric   }
600*0b57cec5SDimitry Andric }
601*0b57cec5SDimitry Andric 
602*0b57cec5SDimitry Andric std::string MetadataStreamerV3::getTypeName(Type *Ty, bool Signed) const {
603*0b57cec5SDimitry Andric   switch (Ty->getTypeID()) {
604*0b57cec5SDimitry Andric   case Type::IntegerTyID: {
605*0b57cec5SDimitry Andric     if (!Signed)
606*0b57cec5SDimitry Andric       return (Twine('u') + getTypeName(Ty, true)).str();
607*0b57cec5SDimitry Andric 
608*0b57cec5SDimitry Andric     auto BitWidth = Ty->getIntegerBitWidth();
609*0b57cec5SDimitry Andric     switch (BitWidth) {
610*0b57cec5SDimitry Andric     case 8:
611*0b57cec5SDimitry Andric       return "char";
612*0b57cec5SDimitry Andric     case 16:
613*0b57cec5SDimitry Andric       return "short";
614*0b57cec5SDimitry Andric     case 32:
615*0b57cec5SDimitry Andric       return "int";
616*0b57cec5SDimitry Andric     case 64:
617*0b57cec5SDimitry Andric       return "long";
618*0b57cec5SDimitry Andric     default:
619*0b57cec5SDimitry Andric       return (Twine('i') + Twine(BitWidth)).str();
620*0b57cec5SDimitry Andric     }
621*0b57cec5SDimitry Andric   }
622*0b57cec5SDimitry Andric   case Type::HalfTyID:
623*0b57cec5SDimitry Andric     return "half";
624*0b57cec5SDimitry Andric   case Type::FloatTyID:
625*0b57cec5SDimitry Andric     return "float";
626*0b57cec5SDimitry Andric   case Type::DoubleTyID:
627*0b57cec5SDimitry Andric     return "double";
628*0b57cec5SDimitry Andric   case Type::VectorTyID: {
629*0b57cec5SDimitry Andric     auto VecTy = cast<VectorType>(Ty);
630*0b57cec5SDimitry Andric     auto ElTy = VecTy->getElementType();
631*0b57cec5SDimitry Andric     auto NumElements = VecTy->getVectorNumElements();
632*0b57cec5SDimitry Andric     return (Twine(getTypeName(ElTy, Signed)) + Twine(NumElements)).str();
633*0b57cec5SDimitry Andric   }
634*0b57cec5SDimitry Andric   default:
635*0b57cec5SDimitry Andric     return "unknown";
636*0b57cec5SDimitry Andric   }
637*0b57cec5SDimitry Andric }
638*0b57cec5SDimitry Andric 
639*0b57cec5SDimitry Andric msgpack::ArrayDocNode
640*0b57cec5SDimitry Andric MetadataStreamerV3::getWorkGroupDimensions(MDNode *Node) const {
641*0b57cec5SDimitry Andric   auto Dims = HSAMetadataDoc->getArrayNode();
642*0b57cec5SDimitry Andric   if (Node->getNumOperands() != 3)
643*0b57cec5SDimitry Andric     return Dims;
644*0b57cec5SDimitry Andric 
645*0b57cec5SDimitry Andric   for (auto &Op : Node->operands())
646*0b57cec5SDimitry Andric     Dims.push_back(Dims.getDocument()->getNode(
647*0b57cec5SDimitry Andric         uint64_t(mdconst::extract<ConstantInt>(Op)->getZExtValue())));
648*0b57cec5SDimitry Andric   return Dims;
649*0b57cec5SDimitry Andric }
650*0b57cec5SDimitry Andric 
651*0b57cec5SDimitry Andric void MetadataStreamerV3::emitVersion() {
652*0b57cec5SDimitry Andric   auto Version = HSAMetadataDoc->getArrayNode();
653*0b57cec5SDimitry Andric   Version.push_back(Version.getDocument()->getNode(VersionMajor));
654*0b57cec5SDimitry Andric   Version.push_back(Version.getDocument()->getNode(VersionMinor));
655*0b57cec5SDimitry Andric   getRootMetadata("amdhsa.version") = Version;
656*0b57cec5SDimitry Andric }
657*0b57cec5SDimitry Andric 
658*0b57cec5SDimitry Andric void MetadataStreamerV3::emitPrintf(const Module &Mod) {
659*0b57cec5SDimitry Andric   auto Node = Mod.getNamedMetadata("llvm.printf.fmts");
660*0b57cec5SDimitry Andric   if (!Node)
661*0b57cec5SDimitry Andric     return;
662*0b57cec5SDimitry Andric 
663*0b57cec5SDimitry Andric   auto Printf = HSAMetadataDoc->getArrayNode();
664*0b57cec5SDimitry Andric   for (auto Op : Node->operands())
665*0b57cec5SDimitry Andric     if (Op->getNumOperands())
666*0b57cec5SDimitry Andric       Printf.push_back(Printf.getDocument()->getNode(
667*0b57cec5SDimitry Andric           cast<MDString>(Op->getOperand(0))->getString(), /*Copy=*/true));
668*0b57cec5SDimitry Andric   getRootMetadata("amdhsa.printf") = Printf;
669*0b57cec5SDimitry Andric }
670*0b57cec5SDimitry Andric 
671*0b57cec5SDimitry Andric void MetadataStreamerV3::emitKernelLanguage(const Function &Func,
672*0b57cec5SDimitry Andric                                             msgpack::MapDocNode Kern) {
673*0b57cec5SDimitry Andric   // TODO: What about other languages?
674*0b57cec5SDimitry Andric   auto Node = Func.getParent()->getNamedMetadata("opencl.ocl.version");
675*0b57cec5SDimitry Andric   if (!Node || !Node->getNumOperands())
676*0b57cec5SDimitry Andric     return;
677*0b57cec5SDimitry Andric   auto Op0 = Node->getOperand(0);
678*0b57cec5SDimitry Andric   if (Op0->getNumOperands() <= 1)
679*0b57cec5SDimitry Andric     return;
680*0b57cec5SDimitry Andric 
681*0b57cec5SDimitry Andric   Kern[".language"] = Kern.getDocument()->getNode("OpenCL C");
682*0b57cec5SDimitry Andric   auto LanguageVersion = Kern.getDocument()->getArrayNode();
683*0b57cec5SDimitry Andric   LanguageVersion.push_back(Kern.getDocument()->getNode(
684*0b57cec5SDimitry Andric       mdconst::extract<ConstantInt>(Op0->getOperand(0))->getZExtValue()));
685*0b57cec5SDimitry Andric   LanguageVersion.push_back(Kern.getDocument()->getNode(
686*0b57cec5SDimitry Andric       mdconst::extract<ConstantInt>(Op0->getOperand(1))->getZExtValue()));
687*0b57cec5SDimitry Andric   Kern[".language_version"] = LanguageVersion;
688*0b57cec5SDimitry Andric }
689*0b57cec5SDimitry Andric 
690*0b57cec5SDimitry Andric void MetadataStreamerV3::emitKernelAttrs(const Function &Func,
691*0b57cec5SDimitry Andric                                          msgpack::MapDocNode Kern) {
692*0b57cec5SDimitry Andric 
693*0b57cec5SDimitry Andric   if (auto Node = Func.getMetadata("reqd_work_group_size"))
694*0b57cec5SDimitry Andric     Kern[".reqd_workgroup_size"] = getWorkGroupDimensions(Node);
695*0b57cec5SDimitry Andric   if (auto Node = Func.getMetadata("work_group_size_hint"))
696*0b57cec5SDimitry Andric     Kern[".workgroup_size_hint"] = getWorkGroupDimensions(Node);
697*0b57cec5SDimitry Andric   if (auto Node = Func.getMetadata("vec_type_hint")) {
698*0b57cec5SDimitry Andric     Kern[".vec_type_hint"] = Kern.getDocument()->getNode(
699*0b57cec5SDimitry Andric         getTypeName(
700*0b57cec5SDimitry Andric             cast<ValueAsMetadata>(Node->getOperand(0))->getType(),
701*0b57cec5SDimitry Andric             mdconst::extract<ConstantInt>(Node->getOperand(1))->getZExtValue()),
702*0b57cec5SDimitry Andric         /*Copy=*/true);
703*0b57cec5SDimitry Andric   }
704*0b57cec5SDimitry Andric   if (Func.hasFnAttribute("runtime-handle")) {
705*0b57cec5SDimitry Andric     Kern[".device_enqueue_symbol"] = Kern.getDocument()->getNode(
706*0b57cec5SDimitry Andric         Func.getFnAttribute("runtime-handle").getValueAsString().str(),
707*0b57cec5SDimitry Andric         /*Copy=*/true);
708*0b57cec5SDimitry Andric   }
709*0b57cec5SDimitry Andric }
710*0b57cec5SDimitry Andric 
711*0b57cec5SDimitry Andric void MetadataStreamerV3::emitKernelArgs(const Function &Func,
712*0b57cec5SDimitry Andric                                         msgpack::MapDocNode Kern) {
713*0b57cec5SDimitry Andric   unsigned Offset = 0;
714*0b57cec5SDimitry Andric   auto Args = HSAMetadataDoc->getArrayNode();
715*0b57cec5SDimitry Andric   for (auto &Arg : Func.args())
716*0b57cec5SDimitry Andric     emitKernelArg(Arg, Offset, Args);
717*0b57cec5SDimitry Andric 
718*0b57cec5SDimitry Andric   emitHiddenKernelArgs(Func, Offset, Args);
719*0b57cec5SDimitry Andric 
720*0b57cec5SDimitry Andric   Kern[".args"] = Args;
721*0b57cec5SDimitry Andric }
722*0b57cec5SDimitry Andric 
723*0b57cec5SDimitry Andric void MetadataStreamerV3::emitKernelArg(const Argument &Arg, unsigned &Offset,
724*0b57cec5SDimitry Andric                                        msgpack::ArrayDocNode Args) {
725*0b57cec5SDimitry Andric   auto Func = Arg.getParent();
726*0b57cec5SDimitry Andric   auto ArgNo = Arg.getArgNo();
727*0b57cec5SDimitry Andric   const MDNode *Node;
728*0b57cec5SDimitry Andric 
729*0b57cec5SDimitry Andric   StringRef Name;
730*0b57cec5SDimitry Andric   Node = Func->getMetadata("kernel_arg_name");
731*0b57cec5SDimitry Andric   if (Node && ArgNo < Node->getNumOperands())
732*0b57cec5SDimitry Andric     Name = cast<MDString>(Node->getOperand(ArgNo))->getString();
733*0b57cec5SDimitry Andric   else if (Arg.hasName())
734*0b57cec5SDimitry Andric     Name = Arg.getName();
735*0b57cec5SDimitry Andric 
736*0b57cec5SDimitry Andric   StringRef TypeName;
737*0b57cec5SDimitry Andric   Node = Func->getMetadata("kernel_arg_type");
738*0b57cec5SDimitry Andric   if (Node && ArgNo < Node->getNumOperands())
739*0b57cec5SDimitry Andric     TypeName = cast<MDString>(Node->getOperand(ArgNo))->getString();
740*0b57cec5SDimitry Andric 
741*0b57cec5SDimitry Andric   StringRef BaseTypeName;
742*0b57cec5SDimitry Andric   Node = Func->getMetadata("kernel_arg_base_type");
743*0b57cec5SDimitry Andric   if (Node && ArgNo < Node->getNumOperands())
744*0b57cec5SDimitry Andric     BaseTypeName = cast<MDString>(Node->getOperand(ArgNo))->getString();
745*0b57cec5SDimitry Andric 
746*0b57cec5SDimitry Andric   StringRef AccQual;
747*0b57cec5SDimitry Andric   if (Arg.getType()->isPointerTy() && Arg.onlyReadsMemory() &&
748*0b57cec5SDimitry Andric       Arg.hasNoAliasAttr()) {
749*0b57cec5SDimitry Andric     AccQual = "read_only";
750*0b57cec5SDimitry Andric   } else {
751*0b57cec5SDimitry Andric     Node = Func->getMetadata("kernel_arg_access_qual");
752*0b57cec5SDimitry Andric     if (Node && ArgNo < Node->getNumOperands())
753*0b57cec5SDimitry Andric       AccQual = cast<MDString>(Node->getOperand(ArgNo))->getString();
754*0b57cec5SDimitry Andric   }
755*0b57cec5SDimitry Andric 
756*0b57cec5SDimitry Andric   StringRef TypeQual;
757*0b57cec5SDimitry Andric   Node = Func->getMetadata("kernel_arg_type_qual");
758*0b57cec5SDimitry Andric   if (Node && ArgNo < Node->getNumOperands())
759*0b57cec5SDimitry Andric     TypeQual = cast<MDString>(Node->getOperand(ArgNo))->getString();
760*0b57cec5SDimitry Andric 
761*0b57cec5SDimitry Andric   Type *Ty = Arg.getType();
762*0b57cec5SDimitry Andric   const DataLayout &DL = Func->getParent()->getDataLayout();
763*0b57cec5SDimitry Andric 
764*0b57cec5SDimitry Andric   unsigned PointeeAlign = 0;
765*0b57cec5SDimitry Andric   if (auto PtrTy = dyn_cast<PointerType>(Ty)) {
766*0b57cec5SDimitry Andric     if (PtrTy->getAddressSpace() == AMDGPUAS::LOCAL_ADDRESS) {
767*0b57cec5SDimitry Andric       PointeeAlign = Arg.getParamAlignment();
768*0b57cec5SDimitry Andric       if (PointeeAlign == 0)
769*0b57cec5SDimitry Andric         PointeeAlign = DL.getABITypeAlignment(PtrTy->getElementType());
770*0b57cec5SDimitry Andric     }
771*0b57cec5SDimitry Andric   }
772*0b57cec5SDimitry Andric 
773*0b57cec5SDimitry Andric   emitKernelArg(Func->getParent()->getDataLayout(), Arg.getType(),
774*0b57cec5SDimitry Andric                 getValueKind(Arg.getType(), TypeQual, BaseTypeName), Offset,
775*0b57cec5SDimitry Andric                 Args, PointeeAlign, Name, TypeName, BaseTypeName, AccQual,
776*0b57cec5SDimitry Andric                 TypeQual);
777*0b57cec5SDimitry Andric }
778*0b57cec5SDimitry Andric 
779*0b57cec5SDimitry Andric void MetadataStreamerV3::emitKernelArg(const DataLayout &DL, Type *Ty,
780*0b57cec5SDimitry Andric                                        StringRef ValueKind, unsigned &Offset,
781*0b57cec5SDimitry Andric                                        msgpack::ArrayDocNode Args,
782*0b57cec5SDimitry Andric                                        unsigned PointeeAlign, StringRef Name,
783*0b57cec5SDimitry Andric                                        StringRef TypeName,
784*0b57cec5SDimitry Andric                                        StringRef BaseTypeName,
785*0b57cec5SDimitry Andric                                        StringRef AccQual, StringRef TypeQual) {
786*0b57cec5SDimitry Andric   auto Arg = Args.getDocument()->getMapNode();
787*0b57cec5SDimitry Andric 
788*0b57cec5SDimitry Andric   if (!Name.empty())
789*0b57cec5SDimitry Andric     Arg[".name"] = Arg.getDocument()->getNode(Name, /*Copy=*/true);
790*0b57cec5SDimitry Andric   if (!TypeName.empty())
791*0b57cec5SDimitry Andric     Arg[".type_name"] = Arg.getDocument()->getNode(TypeName, /*Copy=*/true);
792*0b57cec5SDimitry Andric   auto Size = DL.getTypeAllocSize(Ty);
793*0b57cec5SDimitry Andric   auto Align = DL.getABITypeAlignment(Ty);
794*0b57cec5SDimitry Andric   Arg[".size"] = Arg.getDocument()->getNode(Size);
795*0b57cec5SDimitry Andric   Offset = alignTo(Offset, Align);
796*0b57cec5SDimitry Andric   Arg[".offset"] = Arg.getDocument()->getNode(Offset);
797*0b57cec5SDimitry Andric   Offset += Size;
798*0b57cec5SDimitry Andric   Arg[".value_kind"] = Arg.getDocument()->getNode(ValueKind, /*Copy=*/true);
799*0b57cec5SDimitry Andric   Arg[".value_type"] =
800*0b57cec5SDimitry Andric       Arg.getDocument()->getNode(getValueType(Ty, BaseTypeName), /*Copy=*/true);
801*0b57cec5SDimitry Andric   if (PointeeAlign)
802*0b57cec5SDimitry Andric     Arg[".pointee_align"] = Arg.getDocument()->getNode(PointeeAlign);
803*0b57cec5SDimitry Andric 
804*0b57cec5SDimitry Andric   if (auto PtrTy = dyn_cast<PointerType>(Ty))
805*0b57cec5SDimitry Andric     if (auto Qualifier = getAddressSpaceQualifier(PtrTy->getAddressSpace()))
806*0b57cec5SDimitry Andric       Arg[".address_space"] = Arg.getDocument()->getNode(*Qualifier, /*Copy=*/true);
807*0b57cec5SDimitry Andric 
808*0b57cec5SDimitry Andric   if (auto AQ = getAccessQualifier(AccQual))
809*0b57cec5SDimitry Andric     Arg[".access"] = Arg.getDocument()->getNode(*AQ, /*Copy=*/true);
810*0b57cec5SDimitry Andric 
811*0b57cec5SDimitry Andric   // TODO: Emit Arg[".actual_access"].
812*0b57cec5SDimitry Andric 
813*0b57cec5SDimitry Andric   SmallVector<StringRef, 1> SplitTypeQuals;
814*0b57cec5SDimitry Andric   TypeQual.split(SplitTypeQuals, " ", -1, false);
815*0b57cec5SDimitry Andric   for (StringRef Key : SplitTypeQuals) {
816*0b57cec5SDimitry Andric     if (Key == "const")
817*0b57cec5SDimitry Andric       Arg[".is_const"] = Arg.getDocument()->getNode(true);
818*0b57cec5SDimitry Andric     else if (Key == "restrict")
819*0b57cec5SDimitry Andric       Arg[".is_restrict"] = Arg.getDocument()->getNode(true);
820*0b57cec5SDimitry Andric     else if (Key == "volatile")
821*0b57cec5SDimitry Andric       Arg[".is_volatile"] = Arg.getDocument()->getNode(true);
822*0b57cec5SDimitry Andric     else if (Key == "pipe")
823*0b57cec5SDimitry Andric       Arg[".is_pipe"] = Arg.getDocument()->getNode(true);
824*0b57cec5SDimitry Andric   }
825*0b57cec5SDimitry Andric 
826*0b57cec5SDimitry Andric   Args.push_back(Arg);
827*0b57cec5SDimitry Andric }
828*0b57cec5SDimitry Andric 
829*0b57cec5SDimitry Andric void MetadataStreamerV3::emitHiddenKernelArgs(const Function &Func,
830*0b57cec5SDimitry Andric                                               unsigned &Offset,
831*0b57cec5SDimitry Andric                                               msgpack::ArrayDocNode Args) {
832*0b57cec5SDimitry Andric   int HiddenArgNumBytes =
833*0b57cec5SDimitry Andric       getIntegerAttribute(Func, "amdgpu-implicitarg-num-bytes", 0);
834*0b57cec5SDimitry Andric 
835*0b57cec5SDimitry Andric   if (!HiddenArgNumBytes)
836*0b57cec5SDimitry Andric     return;
837*0b57cec5SDimitry Andric 
838*0b57cec5SDimitry Andric   auto &DL = Func.getParent()->getDataLayout();
839*0b57cec5SDimitry Andric   auto Int64Ty = Type::getInt64Ty(Func.getContext());
840*0b57cec5SDimitry Andric 
841*0b57cec5SDimitry Andric   if (HiddenArgNumBytes >= 8)
842*0b57cec5SDimitry Andric     emitKernelArg(DL, Int64Ty, "hidden_global_offset_x", Offset, Args);
843*0b57cec5SDimitry Andric   if (HiddenArgNumBytes >= 16)
844*0b57cec5SDimitry Andric     emitKernelArg(DL, Int64Ty, "hidden_global_offset_y", Offset, Args);
845*0b57cec5SDimitry Andric   if (HiddenArgNumBytes >= 24)
846*0b57cec5SDimitry Andric     emitKernelArg(DL, Int64Ty, "hidden_global_offset_z", Offset, Args);
847*0b57cec5SDimitry Andric 
848*0b57cec5SDimitry Andric   auto Int8PtrTy =
849*0b57cec5SDimitry Andric       Type::getInt8PtrTy(Func.getContext(), AMDGPUAS::GLOBAL_ADDRESS);
850*0b57cec5SDimitry Andric 
851*0b57cec5SDimitry Andric   // Emit "printf buffer" argument if printf is used, otherwise emit dummy
852*0b57cec5SDimitry Andric   // "none" argument.
853*0b57cec5SDimitry Andric   if (HiddenArgNumBytes >= 32) {
854*0b57cec5SDimitry Andric     if (Func.getParent()->getNamedMetadata("llvm.printf.fmts"))
855*0b57cec5SDimitry Andric       emitKernelArg(DL, Int8PtrTy, "hidden_printf_buffer", Offset, Args);
856*0b57cec5SDimitry Andric     else
857*0b57cec5SDimitry Andric       emitKernelArg(DL, Int8PtrTy, "hidden_none", Offset, Args);
858*0b57cec5SDimitry Andric   }
859*0b57cec5SDimitry Andric 
860*0b57cec5SDimitry Andric   // Emit "default queue" and "completion action" arguments if enqueue kernel is
861*0b57cec5SDimitry Andric   // used, otherwise emit dummy "none" arguments.
862*0b57cec5SDimitry Andric   if (HiddenArgNumBytes >= 48) {
863*0b57cec5SDimitry Andric     if (Func.hasFnAttribute("calls-enqueue-kernel")) {
864*0b57cec5SDimitry Andric       emitKernelArg(DL, Int8PtrTy, "hidden_default_queue", Offset, Args);
865*0b57cec5SDimitry Andric       emitKernelArg(DL, Int8PtrTy, "hidden_completion_action", Offset, Args);
866*0b57cec5SDimitry Andric     } else {
867*0b57cec5SDimitry Andric       emitKernelArg(DL, Int8PtrTy, "hidden_none", Offset, Args);
868*0b57cec5SDimitry Andric       emitKernelArg(DL, Int8PtrTy, "hidden_none", Offset, Args);
869*0b57cec5SDimitry Andric     }
870*0b57cec5SDimitry Andric   }
871*0b57cec5SDimitry Andric 
872*0b57cec5SDimitry Andric   // Emit the pointer argument for multi-grid object.
873*0b57cec5SDimitry Andric   if (HiddenArgNumBytes >= 56)
874*0b57cec5SDimitry Andric     emitKernelArg(DL, Int8PtrTy, "hidden_multigrid_sync_arg", Offset, Args);
875*0b57cec5SDimitry Andric }
876*0b57cec5SDimitry Andric 
877*0b57cec5SDimitry Andric msgpack::MapDocNode
878*0b57cec5SDimitry Andric MetadataStreamerV3::getHSAKernelProps(const MachineFunction &MF,
879*0b57cec5SDimitry Andric                                       const SIProgramInfo &ProgramInfo) const {
880*0b57cec5SDimitry Andric   const GCNSubtarget &STM = MF.getSubtarget<GCNSubtarget>();
881*0b57cec5SDimitry Andric   const SIMachineFunctionInfo &MFI = *MF.getInfo<SIMachineFunctionInfo>();
882*0b57cec5SDimitry Andric   const Function &F = MF.getFunction();
883*0b57cec5SDimitry Andric 
884*0b57cec5SDimitry Andric   auto Kern = HSAMetadataDoc->getMapNode();
885*0b57cec5SDimitry Andric 
886*0b57cec5SDimitry Andric   unsigned MaxKernArgAlign;
887*0b57cec5SDimitry Andric   Kern[".kernarg_segment_size"] = Kern.getDocument()->getNode(
888*0b57cec5SDimitry Andric       STM.getKernArgSegmentSize(F, MaxKernArgAlign));
889*0b57cec5SDimitry Andric   Kern[".group_segment_fixed_size"] =
890*0b57cec5SDimitry Andric       Kern.getDocument()->getNode(ProgramInfo.LDSSize);
891*0b57cec5SDimitry Andric   Kern[".private_segment_fixed_size"] =
892*0b57cec5SDimitry Andric       Kern.getDocument()->getNode(ProgramInfo.ScratchSize);
893*0b57cec5SDimitry Andric   Kern[".kernarg_segment_align"] =
894*0b57cec5SDimitry Andric       Kern.getDocument()->getNode(std::max(uint32_t(4), MaxKernArgAlign));
895*0b57cec5SDimitry Andric   Kern[".wavefront_size"] =
896*0b57cec5SDimitry Andric       Kern.getDocument()->getNode(STM.getWavefrontSize());
897*0b57cec5SDimitry Andric   Kern[".sgpr_count"] = Kern.getDocument()->getNode(ProgramInfo.NumSGPR);
898*0b57cec5SDimitry Andric   Kern[".vgpr_count"] = Kern.getDocument()->getNode(ProgramInfo.NumVGPR);
899*0b57cec5SDimitry Andric   Kern[".max_flat_workgroup_size"] =
900*0b57cec5SDimitry Andric       Kern.getDocument()->getNode(MFI.getMaxFlatWorkGroupSize());
901*0b57cec5SDimitry Andric   Kern[".sgpr_spill_count"] =
902*0b57cec5SDimitry Andric       Kern.getDocument()->getNode(MFI.getNumSpilledSGPRs());
903*0b57cec5SDimitry Andric   Kern[".vgpr_spill_count"] =
904*0b57cec5SDimitry Andric       Kern.getDocument()->getNode(MFI.getNumSpilledVGPRs());
905*0b57cec5SDimitry Andric 
906*0b57cec5SDimitry Andric   return Kern;
907*0b57cec5SDimitry Andric }
908*0b57cec5SDimitry Andric 
909*0b57cec5SDimitry Andric bool MetadataStreamerV3::emitTo(AMDGPUTargetStreamer &TargetStreamer) {
910*0b57cec5SDimitry Andric   return TargetStreamer.EmitHSAMetadata(*HSAMetadataDoc, true);
911*0b57cec5SDimitry Andric }
912*0b57cec5SDimitry Andric 
913*0b57cec5SDimitry Andric void MetadataStreamerV3::begin(const Module &Mod) {
914*0b57cec5SDimitry Andric   emitVersion();
915*0b57cec5SDimitry Andric   emitPrintf(Mod);
916*0b57cec5SDimitry Andric   getRootMetadata("amdhsa.kernels") = HSAMetadataDoc->getArrayNode();
917*0b57cec5SDimitry Andric }
918*0b57cec5SDimitry Andric 
919*0b57cec5SDimitry Andric void MetadataStreamerV3::end() {
920*0b57cec5SDimitry Andric   std::string HSAMetadataString;
921*0b57cec5SDimitry Andric   raw_string_ostream StrOS(HSAMetadataString);
922*0b57cec5SDimitry Andric   HSAMetadataDoc->toYAML(StrOS);
923*0b57cec5SDimitry Andric 
924*0b57cec5SDimitry Andric   if (DumpHSAMetadata)
925*0b57cec5SDimitry Andric     dump(StrOS.str());
926*0b57cec5SDimitry Andric   if (VerifyHSAMetadata)
927*0b57cec5SDimitry Andric     verify(StrOS.str());
928*0b57cec5SDimitry Andric }
929*0b57cec5SDimitry Andric 
930*0b57cec5SDimitry Andric void MetadataStreamerV3::emitKernel(const MachineFunction &MF,
931*0b57cec5SDimitry Andric                                     const SIProgramInfo &ProgramInfo) {
932*0b57cec5SDimitry Andric   auto &Func = MF.getFunction();
933*0b57cec5SDimitry Andric   auto Kern = getHSAKernelProps(MF, ProgramInfo);
934*0b57cec5SDimitry Andric 
935*0b57cec5SDimitry Andric   assert(Func.getCallingConv() == CallingConv::AMDGPU_KERNEL ||
936*0b57cec5SDimitry Andric          Func.getCallingConv() == CallingConv::SPIR_KERNEL);
937*0b57cec5SDimitry Andric 
938*0b57cec5SDimitry Andric   auto Kernels =
939*0b57cec5SDimitry Andric       getRootMetadata("amdhsa.kernels").getArray(/*Convert=*/true);
940*0b57cec5SDimitry Andric 
941*0b57cec5SDimitry Andric   {
942*0b57cec5SDimitry Andric     Kern[".name"] = Kern.getDocument()->getNode(Func.getName());
943*0b57cec5SDimitry Andric     Kern[".symbol"] = Kern.getDocument()->getNode(
944*0b57cec5SDimitry Andric         (Twine(Func.getName()) + Twine(".kd")).str(), /*Copy=*/true);
945*0b57cec5SDimitry Andric     emitKernelLanguage(Func, Kern);
946*0b57cec5SDimitry Andric     emitKernelAttrs(Func, Kern);
947*0b57cec5SDimitry Andric     emitKernelArgs(Func, Kern);
948*0b57cec5SDimitry Andric   }
949*0b57cec5SDimitry Andric 
950*0b57cec5SDimitry Andric   Kernels.push_back(Kern);
951*0b57cec5SDimitry Andric }
952*0b57cec5SDimitry Andric 
953*0b57cec5SDimitry Andric } // end namespace HSAMD
954*0b57cec5SDimitry Andric } // end namespace AMDGPU
955*0b57cec5SDimitry Andric } // end namespace llvm
956