19fa9d9a7SFabian Mora //===- Utility.cpp ------ Collection of generic offloading utilities ------===// 2078ae8cdSJoseph Huber // 3078ae8cdSJoseph Huber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4078ae8cdSJoseph Huber // See https://llvm.org/LICENSE.txt for license information. 5078ae8cdSJoseph Huber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6078ae8cdSJoseph Huber // 7078ae8cdSJoseph Huber //===----------------------------------------------------------------------===// 8078ae8cdSJoseph Huber 9078ae8cdSJoseph Huber #include "llvm/Frontend/Offloading/Utility.h" 10cfc76b64SFabian Mora #include "llvm/BinaryFormat/AMDGPUMetadataVerifier.h" 11cfc76b64SFabian Mora #include "llvm/BinaryFormat/ELF.h" 12cfc76b64SFabian Mora #include "llvm/BinaryFormat/MsgPackDocument.h" 13078ae8cdSJoseph Huber #include "llvm/IR/Constants.h" 14078ae8cdSJoseph Huber #include "llvm/IR/GlobalValue.h" 15078ae8cdSJoseph Huber #include "llvm/IR/GlobalVariable.h" 16078ae8cdSJoseph Huber #include "llvm/IR/Value.h" 17cfc76b64SFabian Mora #include "llvm/Object/ELFObjectFile.h" 18cfc76b64SFabian Mora #include "llvm/Support/MemoryBufferRef.h" 19a551703cSJoseph Huber #include "llvm/Transforms/Utils/ModuleUtils.h" 20078ae8cdSJoseph Huber 21078ae8cdSJoseph Huber using namespace llvm; 22078ae8cdSJoseph Huber using namespace llvm::offloading; 23078ae8cdSJoseph Huber 249c0e6499SJoseph Huber StructType *offloading::getEntryTy(Module &M) { 25078ae8cdSJoseph Huber LLVMContext &C = M.getContext(); 26078ae8cdSJoseph Huber StructType *EntryTy = 27078ae8cdSJoseph Huber StructType::getTypeByName(C, "struct.__tgt_offload_entry"); 28078ae8cdSJoseph Huber if (!EntryTy) 297b9d73c2SPaulo Matos EntryTy = StructType::create( 30*13dcc95dSJoseph Huber "struct.__tgt_offload_entry", Type::getInt64Ty(C), Type::getInt16Ty(C), 31*13dcc95dSJoseph Huber Type::getInt16Ty(C), Type::getInt32Ty(C), PointerType::getUnqual(C), 32*13dcc95dSJoseph Huber PointerType::getUnqual(C), Type::getInt64Ty(C), Type::getInt64Ty(C), 33*13dcc95dSJoseph Huber PointerType::getUnqual(C)); 34078ae8cdSJoseph Huber return EntryTy; 35078ae8cdSJoseph Huber } 36078ae8cdSJoseph Huber 379fa9d9a7SFabian Mora std::pair<Constant *, GlobalVariable *> 38*13dcc95dSJoseph Huber offloading::getOffloadingEntryInitializer(Module &M, object::OffloadKind Kind, 39*13dcc95dSJoseph Huber Constant *Addr, StringRef Name, 40*13dcc95dSJoseph Huber uint64_t Size, uint32_t Flags, 41*13dcc95dSJoseph Huber uint64_t Data, Constant *AuxAddr) { 423bf88163SJoseph Huber llvm::Triple Triple(M.getTargetTriple()); 43*13dcc95dSJoseph Huber Type *PtrTy = PointerType::getUnqual(M.getContext()); 44*13dcc95dSJoseph Huber Type *Int64Ty = Type::getInt64Ty(M.getContext()); 45078ae8cdSJoseph Huber Type *Int32Ty = Type::getInt32Ty(M.getContext()); 46*13dcc95dSJoseph Huber Type *Int16Ty = Type::getInt16Ty(M.getContext()); 47078ae8cdSJoseph Huber 48078ae8cdSJoseph Huber Constant *AddrName = ConstantDataArray::getString(M.getContext(), Name); 49078ae8cdSJoseph Huber 50470aefb2SJoseph Huber StringRef Prefix = 51470aefb2SJoseph Huber Triple.isNVPTX() ? "$offloading$entry_name" : ".offloading.entry_name"; 523bf88163SJoseph Huber 53078ae8cdSJoseph Huber // Create the constant string used to look up the symbol in the device. 543bf88163SJoseph Huber auto *Str = 553bf88163SJoseph Huber new GlobalVariable(M, AddrName->getType(), /*isConstant=*/true, 563bf88163SJoseph Huber GlobalValue::InternalLinkage, AddrName, Prefix); 5742eb54b7SJoseph Huber StringRef SectionName = ".llvm.rodata.offloading"; 5852204a29SJoseph Huber Str->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); 5942eb54b7SJoseph Huber Str->setSection(SectionName); 6042eb54b7SJoseph Huber Str->setAlignment(Align(1)); 6142eb54b7SJoseph Huber 6242eb54b7SJoseph Huber // Make a metadata node for these constants so it can be queried from IR. 6342eb54b7SJoseph Huber NamedMDNode *MD = M.getOrInsertNamedMetadata("llvm.offloading.symbols"); 6442eb54b7SJoseph Huber Metadata *MDVals[] = {ConstantAsMetadata::get(Str)}; 6542eb54b7SJoseph Huber MD->addOperand(llvm::MDNode::get(M.getContext(), MDVals)); 66078ae8cdSJoseph Huber 67078ae8cdSJoseph Huber // Construct the offloading entry. 68078ae8cdSJoseph Huber Constant *EntryData[] = { 69*13dcc95dSJoseph Huber ConstantExpr::getNullValue(Int64Ty), 70*13dcc95dSJoseph Huber ConstantInt::get(Int16Ty, 1), 71*13dcc95dSJoseph Huber ConstantInt::get(Int16Ty, Kind), 72078ae8cdSJoseph Huber ConstantInt::get(Int32Ty, Flags), 73*13dcc95dSJoseph Huber ConstantExpr::getPointerBitCastOrAddrSpaceCast(Addr, PtrTy), 74*13dcc95dSJoseph Huber ConstantExpr::getPointerBitCastOrAddrSpaceCast(Str, PtrTy), 75*13dcc95dSJoseph Huber ConstantInt::get(Int64Ty, Size), 76*13dcc95dSJoseph Huber ConstantInt::get(Int64Ty, Data), 77*13dcc95dSJoseph Huber AuxAddr ? ConstantExpr::getPointerBitCastOrAddrSpaceCast(AuxAddr, PtrTy) 78*13dcc95dSJoseph Huber : ConstantExpr::getNullValue(PtrTy)}; 79078ae8cdSJoseph Huber Constant *EntryInitializer = ConstantStruct::get(getEntryTy(M), EntryData); 809fa9d9a7SFabian Mora return {EntryInitializer, Str}; 819fa9d9a7SFabian Mora } 829fa9d9a7SFabian Mora 83*13dcc95dSJoseph Huber void offloading::emitOffloadingEntry(Module &M, object::OffloadKind Kind, 84*13dcc95dSJoseph Huber Constant *Addr, StringRef Name, 85*13dcc95dSJoseph Huber uint64_t Size, uint32_t Flags, 86*13dcc95dSJoseph Huber uint64_t Data, StringRef SectionName, 87*13dcc95dSJoseph Huber Constant *AuxAddr) { 889fa9d9a7SFabian Mora llvm::Triple Triple(M.getTargetTriple()); 899fa9d9a7SFabian Mora 90*13dcc95dSJoseph Huber auto [EntryInitializer, NameGV] = getOffloadingEntryInitializer( 91*13dcc95dSJoseph Huber M, Kind, Addr, Name, Size, Flags, Data, AuxAddr); 92078ae8cdSJoseph Huber 933bf88163SJoseph Huber StringRef Prefix = 94470aefb2SJoseph Huber Triple.isNVPTX() ? "$offloading$entry$" : ".offloading.entry."; 95078ae8cdSJoseph Huber auto *Entry = new GlobalVariable( 96078ae8cdSJoseph Huber M, getEntryTy(M), 97078ae8cdSJoseph Huber /*isConstant=*/true, GlobalValue::WeakAnyLinkage, EntryInitializer, 983bf88163SJoseph Huber Prefix + Name, nullptr, GlobalValue::NotThreadLocal, 99078ae8cdSJoseph Huber M.getDataLayout().getDefaultGlobalsAddressSpace()); 100078ae8cdSJoseph Huber 101078ae8cdSJoseph Huber // The entry has to be created in the section the linker expects it to be. 10252204a29SJoseph Huber if (Triple.isOSBinFormatCOFF()) 10352204a29SJoseph Huber Entry->setSection((SectionName + "$OE").str()); 10452204a29SJoseph Huber else 105078ae8cdSJoseph Huber Entry->setSection(SectionName); 106078ae8cdSJoseph Huber Entry->setAlignment(Align(1)); 107078ae8cdSJoseph Huber } 1089c0e6499SJoseph Huber 1099c0e6499SJoseph Huber std::pair<GlobalVariable *, GlobalVariable *> 1109c0e6499SJoseph Huber offloading::getOffloadEntryArray(Module &M, StringRef SectionName) { 11152204a29SJoseph Huber llvm::Triple Triple(M.getTargetTriple()); 11252204a29SJoseph Huber 11352204a29SJoseph Huber auto *ZeroInitilaizer = 11452204a29SJoseph Huber ConstantAggregateZero::get(ArrayType::get(getEntryTy(M), 0u)); 11552204a29SJoseph Huber auto *EntryInit = Triple.isOSBinFormatCOFF() ? ZeroInitilaizer : nullptr; 11652204a29SJoseph Huber auto *EntryType = ArrayType::get(getEntryTy(M), 0); 117a551703cSJoseph Huber auto Linkage = Triple.isOSBinFormatCOFF() ? GlobalValue::WeakODRLinkage 118a551703cSJoseph Huber : GlobalValue::ExternalLinkage; 11952204a29SJoseph Huber 120a551703cSJoseph Huber auto *EntriesB = 121a551703cSJoseph Huber new GlobalVariable(M, EntryType, /*isConstant=*/true, Linkage, EntryInit, 12252204a29SJoseph Huber "__start_" + SectionName); 1239c0e6499SJoseph Huber EntriesB->setVisibility(GlobalValue::HiddenVisibility); 124a551703cSJoseph Huber auto *EntriesE = 125a551703cSJoseph Huber new GlobalVariable(M, EntryType, /*isConstant=*/true, Linkage, EntryInit, 12652204a29SJoseph Huber "__stop_" + SectionName); 1279c0e6499SJoseph Huber EntriesE->setVisibility(GlobalValue::HiddenVisibility); 1289c0e6499SJoseph Huber 12952204a29SJoseph Huber if (Triple.isOSBinFormatELF()) { 1309c0e6499SJoseph Huber // We assume that external begin/end symbols that we have created above will 13152204a29SJoseph Huber // be defined by the linker. This is done whenever a section name with a 13252204a29SJoseph Huber // valid C-identifier is present. We define a dummy variable here to force 13352204a29SJoseph Huber // the linker to always provide these symbols. 13452204a29SJoseph Huber auto *DummyEntry = new GlobalVariable( 135a551703cSJoseph Huber M, ZeroInitilaizer->getType(), true, GlobalVariable::InternalLinkage, 13652204a29SJoseph Huber ZeroInitilaizer, "__dummy." + SectionName); 1379c0e6499SJoseph Huber DummyEntry->setSection(SectionName); 138a551703cSJoseph Huber appendToCompilerUsed(M, DummyEntry); 13952204a29SJoseph Huber } else { 14052204a29SJoseph Huber // The COFF linker will merge sections containing a '$' together into a 14152204a29SJoseph Huber // single section. The order of entries in this section will be sorted 14252204a29SJoseph Huber // alphabetically by the characters following the '$' in the name. Set the 14352204a29SJoseph Huber // sections here to ensure that the beginning and end symbols are sorted. 14452204a29SJoseph Huber EntriesB->setSection((SectionName + "$OA").str()); 14552204a29SJoseph Huber EntriesE->setSection((SectionName + "$OZ").str()); 14652204a29SJoseph Huber } 1479c0e6499SJoseph Huber 1489c0e6499SJoseph Huber return std::make_pair(EntriesB, EntriesE); 1499c0e6499SJoseph Huber } 150cfc76b64SFabian Mora 151cfc76b64SFabian Mora bool llvm::offloading::amdgpu::isImageCompatibleWithEnv(StringRef ImageArch, 152cfc76b64SFabian Mora uint32_t ImageFlags, 153cfc76b64SFabian Mora StringRef EnvTargetID) { 154cfc76b64SFabian Mora using namespace llvm::ELF; 155cfc76b64SFabian Mora StringRef EnvArch = EnvTargetID.split(":").first; 156cfc76b64SFabian Mora 157cfc76b64SFabian Mora // Trivial check if the base processors match. 158cfc76b64SFabian Mora if (EnvArch != ImageArch) 159cfc76b64SFabian Mora return false; 160cfc76b64SFabian Mora 161cfc76b64SFabian Mora // Check if the image is requesting xnack on or off. 162cfc76b64SFabian Mora switch (ImageFlags & EF_AMDGPU_FEATURE_XNACK_V4) { 163cfc76b64SFabian Mora case EF_AMDGPU_FEATURE_XNACK_OFF_V4: 164cfc76b64SFabian Mora // The image is 'xnack-' so the environment must be 'xnack-'. 165cfc76b64SFabian Mora if (!EnvTargetID.contains("xnack-")) 166cfc76b64SFabian Mora return false; 167cfc76b64SFabian Mora break; 168cfc76b64SFabian Mora case EF_AMDGPU_FEATURE_XNACK_ON_V4: 169cfc76b64SFabian Mora // The image is 'xnack+' so the environment must be 'xnack+'. 170cfc76b64SFabian Mora if (!EnvTargetID.contains("xnack+")) 171cfc76b64SFabian Mora return false; 172cfc76b64SFabian Mora break; 173cfc76b64SFabian Mora case EF_AMDGPU_FEATURE_XNACK_UNSUPPORTED_V4: 174cfc76b64SFabian Mora case EF_AMDGPU_FEATURE_XNACK_ANY_V4: 175cfc76b64SFabian Mora default: 176cfc76b64SFabian Mora break; 177cfc76b64SFabian Mora } 178cfc76b64SFabian Mora 179cfc76b64SFabian Mora // Check if the image is requesting sramecc on or off. 180cfc76b64SFabian Mora switch (ImageFlags & EF_AMDGPU_FEATURE_SRAMECC_V4) { 181cfc76b64SFabian Mora case EF_AMDGPU_FEATURE_SRAMECC_OFF_V4: 182cfc76b64SFabian Mora // The image is 'sramecc-' so the environment must be 'sramecc-'. 183cfc76b64SFabian Mora if (!EnvTargetID.contains("sramecc-")) 184cfc76b64SFabian Mora return false; 185cfc76b64SFabian Mora break; 186cfc76b64SFabian Mora case EF_AMDGPU_FEATURE_SRAMECC_ON_V4: 187cfc76b64SFabian Mora // The image is 'sramecc+' so the environment must be 'sramecc+'. 188cfc76b64SFabian Mora if (!EnvTargetID.contains("sramecc+")) 189cfc76b64SFabian Mora return false; 190cfc76b64SFabian Mora break; 191cfc76b64SFabian Mora case EF_AMDGPU_FEATURE_SRAMECC_UNSUPPORTED_V4: 192cfc76b64SFabian Mora case EF_AMDGPU_FEATURE_SRAMECC_ANY_V4: 193cfc76b64SFabian Mora break; 194cfc76b64SFabian Mora } 195cfc76b64SFabian Mora 196cfc76b64SFabian Mora return true; 197cfc76b64SFabian Mora } 198cfc76b64SFabian Mora 199cfc76b64SFabian Mora namespace { 200cfc76b64SFabian Mora /// Reads the AMDGPU specific per-kernel-metadata from an image. 201cfc76b64SFabian Mora class KernelInfoReader { 202cfc76b64SFabian Mora public: 203cfc76b64SFabian Mora KernelInfoReader(StringMap<offloading::amdgpu::AMDGPUKernelMetaData> &KIM) 204cfc76b64SFabian Mora : KernelInfoMap(KIM) {} 205cfc76b64SFabian Mora 206cfc76b64SFabian Mora /// Process ELF note to read AMDGPU metadata from respective information 207cfc76b64SFabian Mora /// fields. 208cfc76b64SFabian Mora Error processNote(const llvm::object::ELF64LE::Note &Note, size_t Align) { 209cfc76b64SFabian Mora if (Note.getName() != "AMDGPU") 210cfc76b64SFabian Mora return Error::success(); // We are not interested in other things 211cfc76b64SFabian Mora 212cfc76b64SFabian Mora assert(Note.getType() == ELF::NT_AMDGPU_METADATA && 213cfc76b64SFabian Mora "Parse AMDGPU MetaData"); 214cfc76b64SFabian Mora auto Desc = Note.getDesc(Align); 215cfc76b64SFabian Mora StringRef MsgPackString = 216cfc76b64SFabian Mora StringRef(reinterpret_cast<const char *>(Desc.data()), Desc.size()); 217cfc76b64SFabian Mora msgpack::Document MsgPackDoc; 218cfc76b64SFabian Mora if (!MsgPackDoc.readFromBlob(MsgPackString, /*Multi=*/false)) 219cfc76b64SFabian Mora return Error::success(); 220cfc76b64SFabian Mora 221cfc76b64SFabian Mora AMDGPU::HSAMD::V3::MetadataVerifier Verifier(true); 222cfc76b64SFabian Mora if (!Verifier.verify(MsgPackDoc.getRoot())) 223cfc76b64SFabian Mora return Error::success(); 224cfc76b64SFabian Mora 225cfc76b64SFabian Mora auto RootMap = MsgPackDoc.getRoot().getMap(true); 226cfc76b64SFabian Mora 227cfc76b64SFabian Mora if (auto Err = iterateAMDKernels(RootMap)) 228cfc76b64SFabian Mora return Err; 229cfc76b64SFabian Mora 230cfc76b64SFabian Mora return Error::success(); 231cfc76b64SFabian Mora } 232cfc76b64SFabian Mora 233cfc76b64SFabian Mora private: 234cfc76b64SFabian Mora /// Extracts the relevant information via simple string look-up in the msgpack 235cfc76b64SFabian Mora /// document elements. 236cfc76b64SFabian Mora Error 237cfc76b64SFabian Mora extractKernelData(msgpack::MapDocNode::MapTy::value_type V, 238cfc76b64SFabian Mora std::string &KernelName, 239cfc76b64SFabian Mora offloading::amdgpu::AMDGPUKernelMetaData &KernelData) { 240cfc76b64SFabian Mora if (!V.first.isString()) 241cfc76b64SFabian Mora return Error::success(); 242cfc76b64SFabian Mora 243cfc76b64SFabian Mora const auto IsKey = [](const msgpack::DocNode &DK, StringRef SK) { 244cfc76b64SFabian Mora return DK.getString() == SK; 245cfc76b64SFabian Mora }; 246cfc76b64SFabian Mora 247cfc76b64SFabian Mora const auto GetSequenceOfThreeInts = [](msgpack::DocNode &DN, 248cfc76b64SFabian Mora uint32_t *Vals) { 249cfc76b64SFabian Mora assert(DN.isArray() && "MsgPack DocNode is an array node"); 250cfc76b64SFabian Mora auto DNA = DN.getArray(); 251cfc76b64SFabian Mora assert(DNA.size() == 3 && "ArrayNode has at most three elements"); 252cfc76b64SFabian Mora 253cfc76b64SFabian Mora int I = 0; 254cfc76b64SFabian Mora for (auto DNABegin = DNA.begin(), DNAEnd = DNA.end(); DNABegin != DNAEnd; 255cfc76b64SFabian Mora ++DNABegin) { 256cfc76b64SFabian Mora Vals[I++] = DNABegin->getUInt(); 257cfc76b64SFabian Mora } 258cfc76b64SFabian Mora }; 259cfc76b64SFabian Mora 260cfc76b64SFabian Mora if (IsKey(V.first, ".name")) { 261cfc76b64SFabian Mora KernelName = V.second.toString(); 262cfc76b64SFabian Mora } else if (IsKey(V.first, ".sgpr_count")) { 263cfc76b64SFabian Mora KernelData.SGPRCount = V.second.getUInt(); 264cfc76b64SFabian Mora } else if (IsKey(V.first, ".sgpr_spill_count")) { 265cfc76b64SFabian Mora KernelData.SGPRSpillCount = V.second.getUInt(); 266cfc76b64SFabian Mora } else if (IsKey(V.first, ".vgpr_count")) { 267cfc76b64SFabian Mora KernelData.VGPRCount = V.second.getUInt(); 268cfc76b64SFabian Mora } else if (IsKey(V.first, ".vgpr_spill_count")) { 269cfc76b64SFabian Mora KernelData.VGPRSpillCount = V.second.getUInt(); 270cfc76b64SFabian Mora } else if (IsKey(V.first, ".agpr_count")) { 271cfc76b64SFabian Mora KernelData.AGPRCount = V.second.getUInt(); 272cfc76b64SFabian Mora } else if (IsKey(V.first, ".private_segment_fixed_size")) { 273cfc76b64SFabian Mora KernelData.PrivateSegmentSize = V.second.getUInt(); 274cfc76b64SFabian Mora } else if (IsKey(V.first, ".group_segment_fixed_size")) { 275cfc76b64SFabian Mora KernelData.GroupSegmentList = V.second.getUInt(); 276cfc76b64SFabian Mora } else if (IsKey(V.first, ".reqd_workgroup_size")) { 277cfc76b64SFabian Mora GetSequenceOfThreeInts(V.second, KernelData.RequestedWorkgroupSize); 278cfc76b64SFabian Mora } else if (IsKey(V.first, ".workgroup_size_hint")) { 279cfc76b64SFabian Mora GetSequenceOfThreeInts(V.second, KernelData.WorkgroupSizeHint); 280cfc76b64SFabian Mora } else if (IsKey(V.first, ".wavefront_size")) { 281cfc76b64SFabian Mora KernelData.WavefrontSize = V.second.getUInt(); 282cfc76b64SFabian Mora } else if (IsKey(V.first, ".max_flat_workgroup_size")) { 283cfc76b64SFabian Mora KernelData.MaxFlatWorkgroupSize = V.second.getUInt(); 284cfc76b64SFabian Mora } 285cfc76b64SFabian Mora 286cfc76b64SFabian Mora return Error::success(); 287cfc76b64SFabian Mora } 288cfc76b64SFabian Mora 289cfc76b64SFabian Mora /// Get the "amdhsa.kernels" element from the msgpack Document 290cfc76b64SFabian Mora Expected<msgpack::ArrayDocNode> getAMDKernelsArray(msgpack::MapDocNode &MDN) { 291cfc76b64SFabian Mora auto Res = MDN.find("amdhsa.kernels"); 292cfc76b64SFabian Mora if (Res == MDN.end()) 293cfc76b64SFabian Mora return createStringError(inconvertibleErrorCode(), 294cfc76b64SFabian Mora "Could not find amdhsa.kernels key"); 295cfc76b64SFabian Mora 296cfc76b64SFabian Mora auto Pair = *Res; 297cfc76b64SFabian Mora assert(Pair.second.isArray() && 298cfc76b64SFabian Mora "AMDGPU kernel entries are arrays of entries"); 299cfc76b64SFabian Mora 300cfc76b64SFabian Mora return Pair.second.getArray(); 301cfc76b64SFabian Mora } 302cfc76b64SFabian Mora 303cfc76b64SFabian Mora /// Iterate all entries for one "amdhsa.kernels" entry. Each entry is a 304cfc76b64SFabian Mora /// MapDocNode that either maps a string to a single value (most of them) or 305cfc76b64SFabian Mora /// to another array of things. Currently, we only handle the case that maps 306cfc76b64SFabian Mora /// to scalar value. 307cfc76b64SFabian Mora Error generateKernelInfo(msgpack::ArrayDocNode::ArrayTy::iterator It) { 308cfc76b64SFabian Mora offloading::amdgpu::AMDGPUKernelMetaData KernelData; 309cfc76b64SFabian Mora std::string KernelName; 310cfc76b64SFabian Mora auto Entry = (*It).getMap(); 311cfc76b64SFabian Mora for (auto MI = Entry.begin(), E = Entry.end(); MI != E; ++MI) 312cfc76b64SFabian Mora if (auto Err = extractKernelData(*MI, KernelName, KernelData)) 313cfc76b64SFabian Mora return Err; 314cfc76b64SFabian Mora 315cfc76b64SFabian Mora KernelInfoMap.insert({KernelName, KernelData}); 316cfc76b64SFabian Mora return Error::success(); 317cfc76b64SFabian Mora } 318cfc76b64SFabian Mora 319cfc76b64SFabian Mora /// Go over the list of AMD kernels in the "amdhsa.kernels" entry 320cfc76b64SFabian Mora Error iterateAMDKernels(msgpack::MapDocNode &MDN) { 321cfc76b64SFabian Mora auto KernelsOrErr = getAMDKernelsArray(MDN); 322cfc76b64SFabian Mora if (auto Err = KernelsOrErr.takeError()) 323cfc76b64SFabian Mora return Err; 324cfc76b64SFabian Mora 325cfc76b64SFabian Mora auto KernelsArr = *KernelsOrErr; 326cfc76b64SFabian Mora for (auto It = KernelsArr.begin(), E = KernelsArr.end(); It != E; ++It) { 327cfc76b64SFabian Mora if (!It->isMap()) 328cfc76b64SFabian Mora continue; // we expect <key,value> pairs 329cfc76b64SFabian Mora 330cfc76b64SFabian Mora // Obtain the value for the different entries. Each array entry is a 331cfc76b64SFabian Mora // MapDocNode 332cfc76b64SFabian Mora if (auto Err = generateKernelInfo(It)) 333cfc76b64SFabian Mora return Err; 334cfc76b64SFabian Mora } 335cfc76b64SFabian Mora return Error::success(); 336cfc76b64SFabian Mora } 337cfc76b64SFabian Mora 338cfc76b64SFabian Mora // Kernel names are the keys 339cfc76b64SFabian Mora StringMap<offloading::amdgpu::AMDGPUKernelMetaData> &KernelInfoMap; 340cfc76b64SFabian Mora }; 341cfc76b64SFabian Mora } // namespace 342cfc76b64SFabian Mora 343cfc76b64SFabian Mora Error llvm::offloading::amdgpu::getAMDGPUMetaDataFromImage( 344cfc76b64SFabian Mora MemoryBufferRef MemBuffer, 345cfc76b64SFabian Mora StringMap<offloading::amdgpu::AMDGPUKernelMetaData> &KernelInfoMap, 346cfc76b64SFabian Mora uint16_t &ELFABIVersion) { 347cfc76b64SFabian Mora Error Err = Error::success(); // Used later as out-parameter 348cfc76b64SFabian Mora 349cfc76b64SFabian Mora auto ELFOrError = object::ELF64LEFile::create(MemBuffer.getBuffer()); 350cfc76b64SFabian Mora if (auto Err = ELFOrError.takeError()) 351cfc76b64SFabian Mora return Err; 352cfc76b64SFabian Mora 353cfc76b64SFabian Mora const object::ELF64LEFile ELFObj = ELFOrError.get(); 354cfc76b64SFabian Mora Expected<ArrayRef<object::ELF64LE::Shdr>> Sections = ELFObj.sections(); 355cfc76b64SFabian Mora if (!Sections) 356cfc76b64SFabian Mora return Sections.takeError(); 357cfc76b64SFabian Mora KernelInfoReader Reader(KernelInfoMap); 358cfc76b64SFabian Mora 359cfc76b64SFabian Mora // Read the code object version from ELF image header 360cfc76b64SFabian Mora auto Header = ELFObj.getHeader(); 361cfc76b64SFabian Mora ELFABIVersion = (uint8_t)(Header.e_ident[ELF::EI_ABIVERSION]); 362cfc76b64SFabian Mora for (const auto &S : *Sections) { 363cfc76b64SFabian Mora if (S.sh_type != ELF::SHT_NOTE) 364cfc76b64SFabian Mora continue; 365cfc76b64SFabian Mora 366cfc76b64SFabian Mora for (const auto N : ELFObj.notes(S, Err)) { 367cfc76b64SFabian Mora if (Err) 368cfc76b64SFabian Mora return Err; 369cfc76b64SFabian Mora // Fills the KernelInfoTabel entries in the reader 370cfc76b64SFabian Mora if ((Err = Reader.processNote(N, S.sh_addralign))) 371cfc76b64SFabian Mora return Err; 372cfc76b64SFabian Mora } 373cfc76b64SFabian Mora } 374cfc76b64SFabian Mora return Error::success(); 375cfc76b64SFabian Mora } 376