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