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