181ad6265SDimitry Andric //===- Offloading.cpp - Utilities for handling offloading code -*- C++ -*-===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric 981ad6265SDimitry Andric #include "llvm/Object/OffloadBinary.h" 1081ad6265SDimitry Andric 1181ad6265SDimitry Andric #include "llvm/ADT/StringSwitch.h" 1281ad6265SDimitry Andric #include "llvm/BinaryFormat/Magic.h" 13bdd1243dSDimitry Andric #include "llvm/IR/Constants.h" 14bdd1243dSDimitry Andric #include "llvm/IR/Module.h" 15bdd1243dSDimitry Andric #include "llvm/IRReader/IRReader.h" 1681ad6265SDimitry Andric #include "llvm/MC/StringTableBuilder.h" 17bdd1243dSDimitry Andric #include "llvm/Object/Archive.h" 18bdd1243dSDimitry Andric #include "llvm/Object/ArchiveWriter.h" 19bdd1243dSDimitry Andric #include "llvm/Object/Binary.h" 20bdd1243dSDimitry Andric #include "llvm/Object/COFF.h" 21bdd1243dSDimitry Andric #include "llvm/Object/ELFObjectFile.h" 2281ad6265SDimitry Andric #include "llvm/Object/Error.h" 23bdd1243dSDimitry Andric #include "llvm/Object/IRObjectFile.h" 24bdd1243dSDimitry Andric #include "llvm/Object/ObjectFile.h" 2581ad6265SDimitry Andric #include "llvm/Support/Alignment.h" 2681ad6265SDimitry Andric #include "llvm/Support/FileOutputBuffer.h" 27bdd1243dSDimitry Andric #include "llvm/Support/SourceMgr.h" 2881ad6265SDimitry Andric 2981ad6265SDimitry Andric using namespace llvm; 3081ad6265SDimitry Andric using namespace llvm::object; 3181ad6265SDimitry Andric 32bdd1243dSDimitry Andric namespace { 33bdd1243dSDimitry Andric 34bdd1243dSDimitry Andric /// Attempts to extract all the embedded device images contained inside the 35bdd1243dSDimitry Andric /// buffer \p Contents. The buffer is expected to contain a valid offloading 36bdd1243dSDimitry Andric /// binary format. 37bdd1243dSDimitry Andric Error extractOffloadFiles(MemoryBufferRef Contents, 38bdd1243dSDimitry Andric SmallVectorImpl<OffloadFile> &Binaries) { 39bdd1243dSDimitry Andric uint64_t Offset = 0; 40bdd1243dSDimitry Andric // There could be multiple offloading binaries stored at this section. 41bdd1243dSDimitry Andric while (Offset < Contents.getBuffer().size()) { 42bdd1243dSDimitry Andric std::unique_ptr<MemoryBuffer> Buffer = 43bdd1243dSDimitry Andric MemoryBuffer::getMemBuffer(Contents.getBuffer().drop_front(Offset), "", 44bdd1243dSDimitry Andric /*RequiresNullTerminator*/ false); 45bdd1243dSDimitry Andric if (!isAddrAligned(Align(OffloadBinary::getAlignment()), 46bdd1243dSDimitry Andric Buffer->getBufferStart())) 47bdd1243dSDimitry Andric Buffer = MemoryBuffer::getMemBufferCopy(Buffer->getBuffer(), 48bdd1243dSDimitry Andric Buffer->getBufferIdentifier()); 49bdd1243dSDimitry Andric auto BinaryOrErr = OffloadBinary::create(*Buffer); 50bdd1243dSDimitry Andric if (!BinaryOrErr) 51bdd1243dSDimitry Andric return BinaryOrErr.takeError(); 52bdd1243dSDimitry Andric OffloadBinary &Binary = **BinaryOrErr; 53bdd1243dSDimitry Andric 54bdd1243dSDimitry Andric // Create a new owned binary with a copy of the original memory. 55bdd1243dSDimitry Andric std::unique_ptr<MemoryBuffer> BufferCopy = MemoryBuffer::getMemBufferCopy( 56bdd1243dSDimitry Andric Binary.getData().take_front(Binary.getSize()), 57bdd1243dSDimitry Andric Contents.getBufferIdentifier()); 58bdd1243dSDimitry Andric auto NewBinaryOrErr = OffloadBinary::create(*BufferCopy); 59bdd1243dSDimitry Andric if (!NewBinaryOrErr) 60bdd1243dSDimitry Andric return NewBinaryOrErr.takeError(); 61bdd1243dSDimitry Andric Binaries.emplace_back(std::move(*NewBinaryOrErr), std::move(BufferCopy)); 62bdd1243dSDimitry Andric 63bdd1243dSDimitry Andric Offset += Binary.getSize(); 64bdd1243dSDimitry Andric } 65bdd1243dSDimitry Andric 66bdd1243dSDimitry Andric return Error::success(); 67bdd1243dSDimitry Andric } 68bdd1243dSDimitry Andric 69bdd1243dSDimitry Andric // Extract offloading binaries from an Object file \p Obj. 70bdd1243dSDimitry Andric Error extractFromObject(const ObjectFile &Obj, 71bdd1243dSDimitry Andric SmallVectorImpl<OffloadFile> &Binaries) { 72bdd1243dSDimitry Andric assert((Obj.isELF() || Obj.isCOFF()) && "Invalid file type"); 73bdd1243dSDimitry Andric 74bdd1243dSDimitry Andric for (SectionRef Sec : Obj.sections()) { 75bdd1243dSDimitry Andric // ELF files contain a section with the LLVM_OFFLOADING type. 76bdd1243dSDimitry Andric if (Obj.isELF() && 77bdd1243dSDimitry Andric static_cast<ELFSectionRef>(Sec).getType() != ELF::SHT_LLVM_OFFLOADING) 78bdd1243dSDimitry Andric continue; 79bdd1243dSDimitry Andric 80bdd1243dSDimitry Andric // COFF has no section types so we rely on the name of the section. 81bdd1243dSDimitry Andric if (Obj.isCOFF()) { 82bdd1243dSDimitry Andric Expected<StringRef> NameOrErr = Sec.getName(); 83bdd1243dSDimitry Andric if (!NameOrErr) 84bdd1243dSDimitry Andric return NameOrErr.takeError(); 85bdd1243dSDimitry Andric 86*0fca6ea1SDimitry Andric if (!NameOrErr->starts_with(".llvm.offloading")) 87bdd1243dSDimitry Andric continue; 88bdd1243dSDimitry Andric } 89bdd1243dSDimitry Andric 90bdd1243dSDimitry Andric Expected<StringRef> Buffer = Sec.getContents(); 91bdd1243dSDimitry Andric if (!Buffer) 92bdd1243dSDimitry Andric return Buffer.takeError(); 93bdd1243dSDimitry Andric 94bdd1243dSDimitry Andric MemoryBufferRef Contents(*Buffer, Obj.getFileName()); 95bdd1243dSDimitry Andric if (Error Err = extractOffloadFiles(Contents, Binaries)) 96bdd1243dSDimitry Andric return Err; 97bdd1243dSDimitry Andric } 98bdd1243dSDimitry Andric 99bdd1243dSDimitry Andric return Error::success(); 100bdd1243dSDimitry Andric } 101bdd1243dSDimitry Andric 102bdd1243dSDimitry Andric Error extractFromBitcode(MemoryBufferRef Buffer, 103bdd1243dSDimitry Andric SmallVectorImpl<OffloadFile> &Binaries) { 104bdd1243dSDimitry Andric LLVMContext Context; 105bdd1243dSDimitry Andric SMDiagnostic Err; 106bdd1243dSDimitry Andric std::unique_ptr<Module> M = getLazyIRModule( 107bdd1243dSDimitry Andric MemoryBuffer::getMemBuffer(Buffer, /*RequiresNullTerminator=*/false), Err, 108bdd1243dSDimitry Andric Context); 109bdd1243dSDimitry Andric if (!M) 110bdd1243dSDimitry Andric return createStringError(inconvertibleErrorCode(), 111bdd1243dSDimitry Andric "Failed to create module"); 112bdd1243dSDimitry Andric 113bdd1243dSDimitry Andric // Extract offloading data from globals referenced by the 114bdd1243dSDimitry Andric // `llvm.embedded.object` metadata with the `.llvm.offloading` section. 115bdd1243dSDimitry Andric auto *MD = M->getNamedMetadata("llvm.embedded.objects"); 116bdd1243dSDimitry Andric if (!MD) 117bdd1243dSDimitry Andric return Error::success(); 118bdd1243dSDimitry Andric 119bdd1243dSDimitry Andric for (const MDNode *Op : MD->operands()) { 120bdd1243dSDimitry Andric if (Op->getNumOperands() < 2) 121bdd1243dSDimitry Andric continue; 122bdd1243dSDimitry Andric 123bdd1243dSDimitry Andric MDString *SectionID = dyn_cast<MDString>(Op->getOperand(1)); 124bdd1243dSDimitry Andric if (!SectionID || SectionID->getString() != ".llvm.offloading") 125bdd1243dSDimitry Andric continue; 126bdd1243dSDimitry Andric 127bdd1243dSDimitry Andric GlobalVariable *GV = 128bdd1243dSDimitry Andric mdconst::dyn_extract_or_null<GlobalVariable>(Op->getOperand(0)); 129bdd1243dSDimitry Andric if (!GV) 130bdd1243dSDimitry Andric continue; 131bdd1243dSDimitry Andric 132bdd1243dSDimitry Andric auto *CDS = dyn_cast<ConstantDataSequential>(GV->getInitializer()); 133bdd1243dSDimitry Andric if (!CDS) 134bdd1243dSDimitry Andric continue; 135bdd1243dSDimitry Andric 136bdd1243dSDimitry Andric MemoryBufferRef Contents(CDS->getAsString(), M->getName()); 137bdd1243dSDimitry Andric if (Error Err = extractOffloadFiles(Contents, Binaries)) 138bdd1243dSDimitry Andric return Err; 139bdd1243dSDimitry Andric } 140bdd1243dSDimitry Andric 141bdd1243dSDimitry Andric return Error::success(); 142bdd1243dSDimitry Andric } 143bdd1243dSDimitry Andric 144bdd1243dSDimitry Andric Error extractFromArchive(const Archive &Library, 145bdd1243dSDimitry Andric SmallVectorImpl<OffloadFile> &Binaries) { 146bdd1243dSDimitry Andric // Try to extract device code from each file stored in the static archive. 147bdd1243dSDimitry Andric Error Err = Error::success(); 148bdd1243dSDimitry Andric for (auto Child : Library.children(Err)) { 149bdd1243dSDimitry Andric auto ChildBufferOrErr = Child.getMemoryBufferRef(); 150bdd1243dSDimitry Andric if (!ChildBufferOrErr) 151bdd1243dSDimitry Andric return ChildBufferOrErr.takeError(); 152bdd1243dSDimitry Andric std::unique_ptr<MemoryBuffer> ChildBuffer = 153bdd1243dSDimitry Andric MemoryBuffer::getMemBuffer(*ChildBufferOrErr, false); 154bdd1243dSDimitry Andric 155bdd1243dSDimitry Andric // Check if the buffer has the required alignment. 156bdd1243dSDimitry Andric if (!isAddrAligned(Align(OffloadBinary::getAlignment()), 157bdd1243dSDimitry Andric ChildBuffer->getBufferStart())) 158bdd1243dSDimitry Andric ChildBuffer = MemoryBuffer::getMemBufferCopy( 159bdd1243dSDimitry Andric ChildBufferOrErr->getBuffer(), 160bdd1243dSDimitry Andric ChildBufferOrErr->getBufferIdentifier()); 161bdd1243dSDimitry Andric 162bdd1243dSDimitry Andric if (Error Err = extractOffloadBinaries(*ChildBuffer, Binaries)) 163bdd1243dSDimitry Andric return Err; 164bdd1243dSDimitry Andric } 165bdd1243dSDimitry Andric 166bdd1243dSDimitry Andric if (Err) 167bdd1243dSDimitry Andric return Err; 168bdd1243dSDimitry Andric return Error::success(); 169bdd1243dSDimitry Andric } 170bdd1243dSDimitry Andric 171bdd1243dSDimitry Andric } // namespace 172bdd1243dSDimitry Andric 17381ad6265SDimitry Andric Expected<std::unique_ptr<OffloadBinary>> 17481ad6265SDimitry Andric OffloadBinary::create(MemoryBufferRef Buf) { 17581ad6265SDimitry Andric if (Buf.getBufferSize() < sizeof(Header) + sizeof(Entry)) 17681ad6265SDimitry Andric return errorCodeToError(object_error::parse_failed); 17781ad6265SDimitry Andric 17881ad6265SDimitry Andric // Check for 0x10FF1OAD magic bytes. 17981ad6265SDimitry Andric if (identify_magic(Buf.getBuffer()) != file_magic::offload_binary) 18081ad6265SDimitry Andric return errorCodeToError(object_error::parse_failed); 18181ad6265SDimitry Andric 18281ad6265SDimitry Andric // Make sure that the data has sufficient alignment. 18381ad6265SDimitry Andric if (!isAddrAligned(Align(getAlignment()), Buf.getBufferStart())) 18481ad6265SDimitry Andric return errorCodeToError(object_error::parse_failed); 18581ad6265SDimitry Andric 18681ad6265SDimitry Andric const char *Start = Buf.getBufferStart(); 18781ad6265SDimitry Andric const Header *TheHeader = reinterpret_cast<const Header *>(Start); 18881ad6265SDimitry Andric if (TheHeader->Version != OffloadBinary::Version) 18981ad6265SDimitry Andric return errorCodeToError(object_error::parse_failed); 19081ad6265SDimitry Andric 19181ad6265SDimitry Andric if (TheHeader->Size > Buf.getBufferSize() || 192*0fca6ea1SDimitry Andric TheHeader->Size < sizeof(Entry) || TheHeader->Size < sizeof(Header)) 193*0fca6ea1SDimitry Andric return errorCodeToError(object_error::unexpected_eof); 194*0fca6ea1SDimitry Andric 195*0fca6ea1SDimitry Andric if (TheHeader->EntryOffset > TheHeader->Size - sizeof(Entry) || 19681ad6265SDimitry Andric TheHeader->EntrySize > TheHeader->Size - sizeof(Header)) 19781ad6265SDimitry Andric return errorCodeToError(object_error::unexpected_eof); 19881ad6265SDimitry Andric 19981ad6265SDimitry Andric const Entry *TheEntry = 20081ad6265SDimitry Andric reinterpret_cast<const Entry *>(&Start[TheHeader->EntryOffset]); 20181ad6265SDimitry Andric 20281ad6265SDimitry Andric if (TheEntry->ImageOffset > Buf.getBufferSize() || 20381ad6265SDimitry Andric TheEntry->StringOffset > Buf.getBufferSize()) 20481ad6265SDimitry Andric return errorCodeToError(object_error::unexpected_eof); 20581ad6265SDimitry Andric 20681ad6265SDimitry Andric return std::unique_ptr<OffloadBinary>( 20781ad6265SDimitry Andric new OffloadBinary(Buf, TheHeader, TheEntry)); 20881ad6265SDimitry Andric } 20981ad6265SDimitry Andric 2105f757f3fSDimitry Andric SmallString<0> OffloadBinary::write(const OffloadingImage &OffloadingData) { 21181ad6265SDimitry Andric // Create a null-terminated string table with all the used strings. 21281ad6265SDimitry Andric StringTableBuilder StrTab(StringTableBuilder::ELF); 21381ad6265SDimitry Andric for (auto &KeyAndValue : OffloadingData.StringData) { 21406c3fb27SDimitry Andric StrTab.add(KeyAndValue.first); 21506c3fb27SDimitry Andric StrTab.add(KeyAndValue.second); 21681ad6265SDimitry Andric } 21781ad6265SDimitry Andric StrTab.finalize(); 21881ad6265SDimitry Andric 21981ad6265SDimitry Andric uint64_t StringEntrySize = 22081ad6265SDimitry Andric sizeof(StringEntry) * OffloadingData.StringData.size(); 22181ad6265SDimitry Andric 22281ad6265SDimitry Andric // Make sure the image we're wrapping around is aligned as well. 22381ad6265SDimitry Andric uint64_t BinaryDataSize = alignTo(sizeof(Header) + sizeof(Entry) + 22481ad6265SDimitry Andric StringEntrySize + StrTab.getSize(), 22581ad6265SDimitry Andric getAlignment()); 22681ad6265SDimitry Andric 22781ad6265SDimitry Andric // Create the header and fill in the offsets. The entry will be directly 22881ad6265SDimitry Andric // placed after the header in memory. Align the size to the alignment of the 22981ad6265SDimitry Andric // header so this can be placed contiguously in a single section. 23081ad6265SDimitry Andric Header TheHeader; 23181ad6265SDimitry Andric TheHeader.Size = alignTo( 23281ad6265SDimitry Andric BinaryDataSize + OffloadingData.Image->getBufferSize(), getAlignment()); 23381ad6265SDimitry Andric TheHeader.EntryOffset = sizeof(Header); 23481ad6265SDimitry Andric TheHeader.EntrySize = sizeof(Entry); 23581ad6265SDimitry Andric 23681ad6265SDimitry Andric // Create the entry using the string table offsets. The string table will be 23781ad6265SDimitry Andric // placed directly after the entry in memory, and the image after that. 23881ad6265SDimitry Andric Entry TheEntry; 23981ad6265SDimitry Andric TheEntry.TheImageKind = OffloadingData.TheImageKind; 24081ad6265SDimitry Andric TheEntry.TheOffloadKind = OffloadingData.TheOffloadKind; 24181ad6265SDimitry Andric TheEntry.Flags = OffloadingData.Flags; 24281ad6265SDimitry Andric TheEntry.StringOffset = sizeof(Header) + sizeof(Entry); 24381ad6265SDimitry Andric TheEntry.NumStrings = OffloadingData.StringData.size(); 24481ad6265SDimitry Andric 24581ad6265SDimitry Andric TheEntry.ImageOffset = BinaryDataSize; 24681ad6265SDimitry Andric TheEntry.ImageSize = OffloadingData.Image->getBufferSize(); 24781ad6265SDimitry Andric 2485f757f3fSDimitry Andric SmallString<0> Data; 24981ad6265SDimitry Andric Data.reserve(TheHeader.Size); 25081ad6265SDimitry Andric raw_svector_ostream OS(Data); 25181ad6265SDimitry Andric OS << StringRef(reinterpret_cast<char *>(&TheHeader), sizeof(Header)); 25281ad6265SDimitry Andric OS << StringRef(reinterpret_cast<char *>(&TheEntry), sizeof(Entry)); 25381ad6265SDimitry Andric for (auto &KeyAndValue : OffloadingData.StringData) { 25481ad6265SDimitry Andric uint64_t Offset = sizeof(Header) + sizeof(Entry) + StringEntrySize; 25506c3fb27SDimitry Andric StringEntry Map{Offset + StrTab.getOffset(KeyAndValue.first), 25606c3fb27SDimitry Andric Offset + StrTab.getOffset(KeyAndValue.second)}; 25781ad6265SDimitry Andric OS << StringRef(reinterpret_cast<char *>(&Map), sizeof(StringEntry)); 25881ad6265SDimitry Andric } 25981ad6265SDimitry Andric StrTab.write(OS); 26081ad6265SDimitry Andric // Add padding to required image alignment. 26181ad6265SDimitry Andric OS.write_zeros(TheEntry.ImageOffset - OS.tell()); 26281ad6265SDimitry Andric OS << OffloadingData.Image->getBuffer(); 26381ad6265SDimitry Andric 26481ad6265SDimitry Andric // Add final padding to required alignment. 26581ad6265SDimitry Andric assert(TheHeader.Size >= OS.tell() && "Too much data written?"); 26681ad6265SDimitry Andric OS.write_zeros(TheHeader.Size - OS.tell()); 26781ad6265SDimitry Andric assert(TheHeader.Size == OS.tell() && "Size mismatch"); 26881ad6265SDimitry Andric 2695f757f3fSDimitry Andric return Data; 27081ad6265SDimitry Andric } 27181ad6265SDimitry Andric 272bdd1243dSDimitry Andric Error object::extractOffloadBinaries(MemoryBufferRef Buffer, 273bdd1243dSDimitry Andric SmallVectorImpl<OffloadFile> &Binaries) { 274bdd1243dSDimitry Andric file_magic Type = identify_magic(Buffer.getBuffer()); 275bdd1243dSDimitry Andric switch (Type) { 276bdd1243dSDimitry Andric case file_magic::bitcode: 277bdd1243dSDimitry Andric return extractFromBitcode(Buffer, Binaries); 278bdd1243dSDimitry Andric case file_magic::elf_relocatable: 279bdd1243dSDimitry Andric case file_magic::elf_executable: 280bdd1243dSDimitry Andric case file_magic::elf_shared_object: 281bdd1243dSDimitry Andric case file_magic::coff_object: { 282bdd1243dSDimitry Andric Expected<std::unique_ptr<ObjectFile>> ObjFile = 283bdd1243dSDimitry Andric ObjectFile::createObjectFile(Buffer, Type); 284bdd1243dSDimitry Andric if (!ObjFile) 285bdd1243dSDimitry Andric return ObjFile.takeError(); 286bdd1243dSDimitry Andric return extractFromObject(*ObjFile->get(), Binaries); 287bdd1243dSDimitry Andric } 288bdd1243dSDimitry Andric case file_magic::archive: { 289bdd1243dSDimitry Andric Expected<std::unique_ptr<llvm::object::Archive>> LibFile = 290bdd1243dSDimitry Andric object::Archive::create(Buffer); 291bdd1243dSDimitry Andric if (!LibFile) 292bdd1243dSDimitry Andric return LibFile.takeError(); 293bdd1243dSDimitry Andric return extractFromArchive(*LibFile->get(), Binaries); 294bdd1243dSDimitry Andric } 295bdd1243dSDimitry Andric case file_magic::offload_binary: 296bdd1243dSDimitry Andric return extractOffloadFiles(Buffer, Binaries); 297bdd1243dSDimitry Andric default: 298bdd1243dSDimitry Andric return Error::success(); 299bdd1243dSDimitry Andric } 300bdd1243dSDimitry Andric } 301bdd1243dSDimitry Andric 30281ad6265SDimitry Andric OffloadKind object::getOffloadKind(StringRef Name) { 30381ad6265SDimitry Andric return llvm::StringSwitch<OffloadKind>(Name) 30481ad6265SDimitry Andric .Case("openmp", OFK_OpenMP) 30581ad6265SDimitry Andric .Case("cuda", OFK_Cuda) 30681ad6265SDimitry Andric .Case("hip", OFK_HIP) 30781ad6265SDimitry Andric .Default(OFK_None); 30881ad6265SDimitry Andric } 30981ad6265SDimitry Andric 31081ad6265SDimitry Andric StringRef object::getOffloadKindName(OffloadKind Kind) { 31181ad6265SDimitry Andric switch (Kind) { 31281ad6265SDimitry Andric case OFK_OpenMP: 31381ad6265SDimitry Andric return "openmp"; 31481ad6265SDimitry Andric case OFK_Cuda: 31581ad6265SDimitry Andric return "cuda"; 31681ad6265SDimitry Andric case OFK_HIP: 31781ad6265SDimitry Andric return "hip"; 31881ad6265SDimitry Andric default: 31981ad6265SDimitry Andric return "none"; 32081ad6265SDimitry Andric } 32181ad6265SDimitry Andric } 32281ad6265SDimitry Andric 32381ad6265SDimitry Andric ImageKind object::getImageKind(StringRef Name) { 32481ad6265SDimitry Andric return llvm::StringSwitch<ImageKind>(Name) 32581ad6265SDimitry Andric .Case("o", IMG_Object) 32681ad6265SDimitry Andric .Case("bc", IMG_Bitcode) 32781ad6265SDimitry Andric .Case("cubin", IMG_Cubin) 32881ad6265SDimitry Andric .Case("fatbin", IMG_Fatbinary) 32981ad6265SDimitry Andric .Case("s", IMG_PTX) 33081ad6265SDimitry Andric .Default(IMG_None); 33181ad6265SDimitry Andric } 33281ad6265SDimitry Andric 33381ad6265SDimitry Andric StringRef object::getImageKindName(ImageKind Kind) { 33481ad6265SDimitry Andric switch (Kind) { 33581ad6265SDimitry Andric case IMG_Object: 33681ad6265SDimitry Andric return "o"; 33781ad6265SDimitry Andric case IMG_Bitcode: 33881ad6265SDimitry Andric return "bc"; 33981ad6265SDimitry Andric case IMG_Cubin: 34081ad6265SDimitry Andric return "cubin"; 34181ad6265SDimitry Andric case IMG_Fatbinary: 34281ad6265SDimitry Andric return "fatbin"; 34381ad6265SDimitry Andric case IMG_PTX: 34481ad6265SDimitry Andric return "s"; 34581ad6265SDimitry Andric default: 34681ad6265SDimitry Andric return ""; 34781ad6265SDimitry Andric } 34881ad6265SDimitry Andric } 3497a6dacacSDimitry Andric 3507a6dacacSDimitry Andric bool object::areTargetsCompatible(const OffloadFile::TargetID &LHS, 3517a6dacacSDimitry Andric const OffloadFile::TargetID &RHS) { 3527a6dacacSDimitry Andric // Exact matches are not considered compatible because they are the same 3537a6dacacSDimitry Andric // target. We are interested in different targets that are compatible. 3547a6dacacSDimitry Andric if (LHS == RHS) 3557a6dacacSDimitry Andric return false; 3567a6dacacSDimitry Andric 3577a6dacacSDimitry Andric // The triples must match at all times. 3587a6dacacSDimitry Andric if (LHS.first != RHS.first) 3597a6dacacSDimitry Andric return false; 3607a6dacacSDimitry Andric 361*0fca6ea1SDimitry Andric // If the architecture is "all" we assume it is always compatible. 362*0fca6ea1SDimitry Andric if (LHS.second == "generic" || RHS.second == "generic") 363*0fca6ea1SDimitry Andric return true; 364*0fca6ea1SDimitry Andric 3657a6dacacSDimitry Andric // Only The AMDGPU target requires additional checks. 3667a6dacacSDimitry Andric llvm::Triple T(LHS.first); 3677a6dacacSDimitry Andric if (!T.isAMDGPU()) 3687a6dacacSDimitry Andric return false; 3697a6dacacSDimitry Andric 3707a6dacacSDimitry Andric // The base processor must always match. 3717a6dacacSDimitry Andric if (LHS.second.split(":").first != RHS.second.split(":").first) 3727a6dacacSDimitry Andric return false; 3737a6dacacSDimitry Andric 3747a6dacacSDimitry Andric // Check combintions of on / off features that must match. 3757a6dacacSDimitry Andric if (LHS.second.contains("xnack+") && RHS.second.contains("xnack-")) 3767a6dacacSDimitry Andric return false; 3777a6dacacSDimitry Andric if (LHS.second.contains("xnack-") && RHS.second.contains("xnack+")) 3787a6dacacSDimitry Andric return false; 3797a6dacacSDimitry Andric if (LHS.second.contains("sramecc-") && RHS.second.contains("sramecc+")) 3807a6dacacSDimitry Andric return false; 3817a6dacacSDimitry Andric if (LHS.second.contains("sramecc+") && RHS.second.contains("sramecc-")) 3827a6dacacSDimitry Andric return false; 3837a6dacacSDimitry Andric return true; 3847a6dacacSDimitry Andric } 385