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