1e471ba3dSJoseph Huber //===- Offloading.cpp - Utilities for handling offloading code -*- C++ -*-===// 2e471ba3dSJoseph Huber // 3e471ba3dSJoseph Huber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e471ba3dSJoseph Huber // See https://llvm.org/LICENSE.txt for license information. 5e471ba3dSJoseph Huber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e471ba3dSJoseph Huber // 7e471ba3dSJoseph Huber //===----------------------------------------------------------------------===// 8e471ba3dSJoseph Huber 9e471ba3dSJoseph Huber #include "llvm/Object/OffloadBinary.h" 10e471ba3dSJoseph Huber 11e471ba3dSJoseph Huber #include "llvm/ADT/StringSwitch.h" 12afd2f7e9SJoseph Huber #include "llvm/BinaryFormat/Magic.h" 135dbc7cf7SJoseph Huber #include "llvm/IR/Constants.h" 145dbc7cf7SJoseph Huber #include "llvm/IR/Module.h" 155dbc7cf7SJoseph Huber #include "llvm/IRReader/IRReader.h" 16e471ba3dSJoseph Huber #include "llvm/MC/StringTableBuilder.h" 175dbc7cf7SJoseph Huber #include "llvm/Object/Archive.h" 185dbc7cf7SJoseph Huber #include "llvm/Object/Binary.h" 195dbc7cf7SJoseph Huber #include "llvm/Object/ELFObjectFile.h" 20e471ba3dSJoseph Huber #include "llvm/Object/Error.h" 215dbc7cf7SJoseph Huber #include "llvm/Object/IRObjectFile.h" 225dbc7cf7SJoseph Huber #include "llvm/Object/ObjectFile.h" 23ccf7dd5eSJoseph Huber #include "llvm/Support/Alignment.h" 245dbc7cf7SJoseph Huber #include "llvm/Support/SourceMgr.h" 25e471ba3dSJoseph Huber 262108f7a2SFangrui Song using namespace llvm; 272108f7a2SFangrui Song using namespace llvm::object; 28afd2f7e9SJoseph Huber 295dbc7cf7SJoseph Huber namespace { 305dbc7cf7SJoseph Huber 315dbc7cf7SJoseph Huber /// Attempts to extract all the embedded device images contained inside the 325dbc7cf7SJoseph Huber /// buffer \p Contents. The buffer is expected to contain a valid offloading 335dbc7cf7SJoseph Huber /// binary format. 345dbc7cf7SJoseph Huber Error extractOffloadFiles(MemoryBufferRef Contents, 355dbc7cf7SJoseph Huber SmallVectorImpl<OffloadFile> &Binaries) { 365dbc7cf7SJoseph Huber uint64_t Offset = 0; 375dbc7cf7SJoseph Huber // There could be multiple offloading binaries stored at this section. 385dbc7cf7SJoseph Huber while (Offset < Contents.getBuffer().size()) { 395dbc7cf7SJoseph Huber std::unique_ptr<MemoryBuffer> Buffer = 405dbc7cf7SJoseph Huber MemoryBuffer::getMemBuffer(Contents.getBuffer().drop_front(Offset), "", 415dbc7cf7SJoseph Huber /*RequiresNullTerminator*/ false); 423384f05aSJoseph Huber if (!isAddrAligned(Align(OffloadBinary::getAlignment()), 433384f05aSJoseph Huber Buffer->getBufferStart())) 443384f05aSJoseph Huber Buffer = MemoryBuffer::getMemBufferCopy(Buffer->getBuffer(), 453384f05aSJoseph Huber Buffer->getBufferIdentifier()); 465dbc7cf7SJoseph Huber auto BinaryOrErr = OffloadBinary::create(*Buffer); 475dbc7cf7SJoseph Huber if (!BinaryOrErr) 485dbc7cf7SJoseph Huber return BinaryOrErr.takeError(); 495dbc7cf7SJoseph Huber OffloadBinary &Binary = **BinaryOrErr; 505dbc7cf7SJoseph Huber 515dbc7cf7SJoseph Huber // Create a new owned binary with a copy of the original memory. 525dbc7cf7SJoseph Huber std::unique_ptr<MemoryBuffer> BufferCopy = MemoryBuffer::getMemBufferCopy( 535dbc7cf7SJoseph Huber Binary.getData().take_front(Binary.getSize()), 545dbc7cf7SJoseph Huber Contents.getBufferIdentifier()); 555dbc7cf7SJoseph Huber auto NewBinaryOrErr = OffloadBinary::create(*BufferCopy); 565dbc7cf7SJoseph Huber if (!NewBinaryOrErr) 575dbc7cf7SJoseph Huber return NewBinaryOrErr.takeError(); 585dbc7cf7SJoseph Huber Binaries.emplace_back(std::move(*NewBinaryOrErr), std::move(BufferCopy)); 595dbc7cf7SJoseph Huber 605dbc7cf7SJoseph Huber Offset += Binary.getSize(); 615dbc7cf7SJoseph Huber } 625dbc7cf7SJoseph Huber 635dbc7cf7SJoseph Huber return Error::success(); 645dbc7cf7SJoseph Huber } 655dbc7cf7SJoseph Huber 665dbc7cf7SJoseph Huber // Extract offloading binaries from an Object file \p Obj. 678298f0b7SJoseph Huber Error extractFromObject(const ObjectFile &Obj, 685dbc7cf7SJoseph Huber SmallVectorImpl<OffloadFile> &Binaries) { 698298f0b7SJoseph Huber assert((Obj.isELF() || Obj.isCOFF()) && "Invalid file type"); 708298f0b7SJoseph Huber 718298f0b7SJoseph Huber for (SectionRef Sec : Obj.sections()) { 728298f0b7SJoseph Huber // ELF files contain a section with the LLVM_OFFLOADING type. 738298f0b7SJoseph Huber if (Obj.isELF() && 748298f0b7SJoseph Huber static_cast<ELFSectionRef>(Sec).getType() != ELF::SHT_LLVM_OFFLOADING) 755dbc7cf7SJoseph Huber continue; 765dbc7cf7SJoseph Huber 778298f0b7SJoseph Huber // COFF has no section types so we rely on the name of the section. 788298f0b7SJoseph Huber if (Obj.isCOFF()) { 798298f0b7SJoseph Huber Expected<StringRef> NameOrErr = Sec.getName(); 808298f0b7SJoseph Huber if (!NameOrErr) 818298f0b7SJoseph Huber return NameOrErr.takeError(); 828298f0b7SJoseph Huber 835c840542SJoseph Huber if (!NameOrErr->starts_with(".llvm.offloading")) 848298f0b7SJoseph Huber continue; 858298f0b7SJoseph Huber } 868298f0b7SJoseph Huber 875dbc7cf7SJoseph Huber Expected<StringRef> Buffer = Sec.getContents(); 885dbc7cf7SJoseph Huber if (!Buffer) 895dbc7cf7SJoseph Huber return Buffer.takeError(); 905dbc7cf7SJoseph Huber 915dbc7cf7SJoseph Huber MemoryBufferRef Contents(*Buffer, Obj.getFileName()); 925dbc7cf7SJoseph Huber if (Error Err = extractOffloadFiles(Contents, Binaries)) 935dbc7cf7SJoseph Huber return Err; 945dbc7cf7SJoseph Huber } 955dbc7cf7SJoseph Huber 965dbc7cf7SJoseph Huber return Error::success(); 975dbc7cf7SJoseph Huber } 985dbc7cf7SJoseph Huber 995dbc7cf7SJoseph Huber Error extractFromBitcode(MemoryBufferRef Buffer, 1005dbc7cf7SJoseph Huber SmallVectorImpl<OffloadFile> &Binaries) { 1015dbc7cf7SJoseph Huber LLVMContext Context; 1025dbc7cf7SJoseph Huber SMDiagnostic Err; 1035dbc7cf7SJoseph Huber std::unique_ptr<Module> M = getLazyIRModule( 1045dbc7cf7SJoseph Huber MemoryBuffer::getMemBuffer(Buffer, /*RequiresNullTerminator=*/false), Err, 1055dbc7cf7SJoseph Huber Context); 1065dbc7cf7SJoseph Huber if (!M) 1075dbc7cf7SJoseph Huber return createStringError(inconvertibleErrorCode(), 1085dbc7cf7SJoseph Huber "Failed to create module"); 1095dbc7cf7SJoseph Huber 1105dbc7cf7SJoseph Huber // Extract offloading data from globals referenced by the 1115dbc7cf7SJoseph Huber // `llvm.embedded.object` metadata with the `.llvm.offloading` section. 1125dbc7cf7SJoseph Huber auto *MD = M->getNamedMetadata("llvm.embedded.objects"); 1135dbc7cf7SJoseph Huber if (!MD) 1145dbc7cf7SJoseph Huber return Error::success(); 1155dbc7cf7SJoseph Huber 1165dbc7cf7SJoseph Huber for (const MDNode *Op : MD->operands()) { 1175dbc7cf7SJoseph Huber if (Op->getNumOperands() < 2) 1185dbc7cf7SJoseph Huber continue; 1195dbc7cf7SJoseph Huber 1205dbc7cf7SJoseph Huber MDString *SectionID = dyn_cast<MDString>(Op->getOperand(1)); 1215dbc7cf7SJoseph Huber if (!SectionID || SectionID->getString() != ".llvm.offloading") 1225dbc7cf7SJoseph Huber continue; 1235dbc7cf7SJoseph Huber 1245dbc7cf7SJoseph Huber GlobalVariable *GV = 1255dbc7cf7SJoseph Huber mdconst::dyn_extract_or_null<GlobalVariable>(Op->getOperand(0)); 1265dbc7cf7SJoseph Huber if (!GV) 1275dbc7cf7SJoseph Huber continue; 1285dbc7cf7SJoseph Huber 1295dbc7cf7SJoseph Huber auto *CDS = dyn_cast<ConstantDataSequential>(GV->getInitializer()); 1305dbc7cf7SJoseph Huber if (!CDS) 1315dbc7cf7SJoseph Huber continue; 1325dbc7cf7SJoseph Huber 1335dbc7cf7SJoseph Huber MemoryBufferRef Contents(CDS->getAsString(), M->getName()); 1345dbc7cf7SJoseph Huber if (Error Err = extractOffloadFiles(Contents, Binaries)) 1355dbc7cf7SJoseph Huber return Err; 1365dbc7cf7SJoseph Huber } 1375dbc7cf7SJoseph Huber 1385dbc7cf7SJoseph Huber return Error::success(); 1395dbc7cf7SJoseph Huber } 1405dbc7cf7SJoseph Huber 1415dbc7cf7SJoseph Huber Error extractFromArchive(const Archive &Library, 1425dbc7cf7SJoseph Huber SmallVectorImpl<OffloadFile> &Binaries) { 1435dbc7cf7SJoseph Huber // Try to extract device code from each file stored in the static archive. 1445dbc7cf7SJoseph Huber Error Err = Error::success(); 1455dbc7cf7SJoseph Huber for (auto Child : Library.children(Err)) { 1465dbc7cf7SJoseph Huber auto ChildBufferOrErr = Child.getMemoryBufferRef(); 1475dbc7cf7SJoseph Huber if (!ChildBufferOrErr) 1485dbc7cf7SJoseph Huber return ChildBufferOrErr.takeError(); 1495dbc7cf7SJoseph Huber std::unique_ptr<MemoryBuffer> ChildBuffer = 1505dbc7cf7SJoseph Huber MemoryBuffer::getMemBuffer(*ChildBufferOrErr, false); 1515dbc7cf7SJoseph Huber 1525dbc7cf7SJoseph Huber // Check if the buffer has the required alignment. 1535dbc7cf7SJoseph Huber if (!isAddrAligned(Align(OffloadBinary::getAlignment()), 1545dbc7cf7SJoseph Huber ChildBuffer->getBufferStart())) 1555dbc7cf7SJoseph Huber ChildBuffer = MemoryBuffer::getMemBufferCopy( 1565dbc7cf7SJoseph Huber ChildBufferOrErr->getBuffer(), 1575dbc7cf7SJoseph Huber ChildBufferOrErr->getBufferIdentifier()); 1585dbc7cf7SJoseph Huber 1595dbc7cf7SJoseph Huber if (Error Err = extractOffloadBinaries(*ChildBuffer, Binaries)) 1605dbc7cf7SJoseph Huber return Err; 1615dbc7cf7SJoseph Huber } 1625dbc7cf7SJoseph Huber 1635dbc7cf7SJoseph Huber if (Err) 1645dbc7cf7SJoseph Huber return Err; 1655dbc7cf7SJoseph Huber return Error::success(); 1665dbc7cf7SJoseph Huber } 1675dbc7cf7SJoseph Huber 1685dbc7cf7SJoseph Huber } // namespace 1695dbc7cf7SJoseph Huber 170e471ba3dSJoseph Huber Expected<std::unique_ptr<OffloadBinary>> 171e471ba3dSJoseph Huber OffloadBinary::create(MemoryBufferRef Buf) { 172e471ba3dSJoseph Huber if (Buf.getBufferSize() < sizeof(Header) + sizeof(Entry)) 173afd2f7e9SJoseph Huber return errorCodeToError(object_error::parse_failed); 174e471ba3dSJoseph Huber 175e471ba3dSJoseph Huber // Check for 0x10FF1OAD magic bytes. 176afd2f7e9SJoseph Huber if (identify_magic(Buf.getBuffer()) != file_magic::offload_binary) 177afd2f7e9SJoseph Huber return errorCodeToError(object_error::parse_failed); 178e471ba3dSJoseph Huber 179ccf7dd5eSJoseph Huber // Make sure that the data has sufficient alignment. 180ccf7dd5eSJoseph Huber if (!isAddrAligned(Align(getAlignment()), Buf.getBufferStart())) 181ccf7dd5eSJoseph Huber return errorCodeToError(object_error::parse_failed); 182ccf7dd5eSJoseph Huber 183e471ba3dSJoseph Huber const char *Start = Buf.getBufferStart(); 184e471ba3dSJoseph Huber const Header *TheHeader = reinterpret_cast<const Header *>(Start); 1851dcbe03cSJoseph Huber if (TheHeader->Version != OffloadBinary::Version) 1861dcbe03cSJoseph Huber return errorCodeToError(object_error::parse_failed); 1871dcbe03cSJoseph Huber 1881dcbe03cSJoseph Huber if (TheHeader->Size > Buf.getBufferSize() || 1896f44bb77SAntonio Frighetto TheHeader->Size < sizeof(Entry) || TheHeader->Size < sizeof(Header)) 1906f44bb77SAntonio Frighetto return errorCodeToError(object_error::unexpected_eof); 1916f44bb77SAntonio Frighetto 1926f44bb77SAntonio Frighetto if (TheHeader->EntryOffset > TheHeader->Size - sizeof(Entry) || 1931dcbe03cSJoseph Huber TheHeader->EntrySize > TheHeader->Size - sizeof(Header)) 1941dcbe03cSJoseph Huber return errorCodeToError(object_error::unexpected_eof); 1951dcbe03cSJoseph Huber 196e471ba3dSJoseph Huber const Entry *TheEntry = 197e471ba3dSJoseph Huber reinterpret_cast<const Entry *>(&Start[TheHeader->EntryOffset]); 198e471ba3dSJoseph Huber 1991dcbe03cSJoseph Huber if (TheEntry->ImageOffset > Buf.getBufferSize() || 2004e2a0092SJoseph Huber TheEntry->StringOffset > Buf.getBufferSize()) 2014e2a0092SJoseph Huber return errorCodeToError(object_error::unexpected_eof); 2024e2a0092SJoseph Huber 203e471ba3dSJoseph Huber return std::unique_ptr<OffloadBinary>( 204afd2f7e9SJoseph Huber new OffloadBinary(Buf, TheHeader, TheEntry)); 205e471ba3dSJoseph Huber } 206e471ba3dSJoseph Huber 207f93c271dSFangrui Song SmallString<0> OffloadBinary::write(const OffloadingImage &OffloadingData) { 208e471ba3dSJoseph Huber // Create a null-terminated string table with all the used strings. 209e471ba3dSJoseph Huber StringTableBuilder StrTab(StringTableBuilder::ELF); 210e471ba3dSJoseph Huber for (auto &KeyAndValue : OffloadingData.StringData) { 211ecb1d844SFangrui Song StrTab.add(KeyAndValue.first); 212ecb1d844SFangrui Song StrTab.add(KeyAndValue.second); 213e471ba3dSJoseph Huber } 214e471ba3dSJoseph Huber StrTab.finalize(); 215e471ba3dSJoseph Huber 216e471ba3dSJoseph Huber uint64_t StringEntrySize = 217e471ba3dSJoseph Huber sizeof(StringEntry) * OffloadingData.StringData.size(); 218e471ba3dSJoseph Huber 2199db2f323SJoseph Huber // Make sure the image we're wrapping around is aligned as well. 2209db2f323SJoseph Huber uint64_t BinaryDataSize = alignTo(sizeof(Header) + sizeof(Entry) + 2219db2f323SJoseph Huber StringEntrySize + StrTab.getSize(), 2229db2f323SJoseph Huber getAlignment()); 2239db2f323SJoseph Huber 224e471ba3dSJoseph Huber // Create the header and fill in the offsets. The entry will be directly 225e471ba3dSJoseph Huber // placed after the header in memory. Align the size to the alignment of the 226e471ba3dSJoseph Huber // header so this can be placed contiguously in a single section. 227e471ba3dSJoseph Huber Header TheHeader; 2289db2f323SJoseph Huber TheHeader.Size = alignTo( 229f06731e3SJoseph Huber BinaryDataSize + OffloadingData.Image->getBufferSize(), getAlignment()); 230e471ba3dSJoseph Huber TheHeader.EntryOffset = sizeof(Header); 231e471ba3dSJoseph Huber TheHeader.EntrySize = sizeof(Entry); 232e471ba3dSJoseph Huber 233e471ba3dSJoseph Huber // Create the entry using the string table offsets. The string table will be 234e471ba3dSJoseph Huber // placed directly after the entry in memory, and the image after that. 235e471ba3dSJoseph Huber Entry TheEntry; 236e471ba3dSJoseph Huber TheEntry.TheImageKind = OffloadingData.TheImageKind; 237e471ba3dSJoseph Huber TheEntry.TheOffloadKind = OffloadingData.TheOffloadKind; 238e471ba3dSJoseph Huber TheEntry.Flags = OffloadingData.Flags; 239e471ba3dSJoseph Huber TheEntry.StringOffset = sizeof(Header) + sizeof(Entry); 240e471ba3dSJoseph Huber TheEntry.NumStrings = OffloadingData.StringData.size(); 241e471ba3dSJoseph Huber 2429db2f323SJoseph Huber TheEntry.ImageOffset = BinaryDataSize; 243f06731e3SJoseph Huber TheEntry.ImageSize = OffloadingData.Image->getBufferSize(); 244e471ba3dSJoseph Huber 245f93c271dSFangrui Song SmallString<0> Data; 2464e2a0092SJoseph Huber Data.reserve(TheHeader.Size); 247e471ba3dSJoseph Huber raw_svector_ostream OS(Data); 248e471ba3dSJoseph Huber OS << StringRef(reinterpret_cast<char *>(&TheHeader), sizeof(Header)); 249e471ba3dSJoseph Huber OS << StringRef(reinterpret_cast<char *>(&TheEntry), sizeof(Entry)); 250e471ba3dSJoseph Huber for (auto &KeyAndValue : OffloadingData.StringData) { 251e471ba3dSJoseph Huber uint64_t Offset = sizeof(Header) + sizeof(Entry) + StringEntrySize; 252ecb1d844SFangrui Song StringEntry Map{Offset + StrTab.getOffset(KeyAndValue.first), 253ecb1d844SFangrui Song Offset + StrTab.getOffset(KeyAndValue.second)}; 254e471ba3dSJoseph Huber OS << StringRef(reinterpret_cast<char *>(&Map), sizeof(StringEntry)); 255e471ba3dSJoseph Huber } 256e471ba3dSJoseph Huber StrTab.write(OS); 2579db2f323SJoseph Huber // Add padding to required image alignment. 2589db2f323SJoseph Huber OS.write_zeros(TheEntry.ImageOffset - OS.tell()); 259f06731e3SJoseph Huber OS << OffloadingData.Image->getBuffer(); 260e471ba3dSJoseph Huber 261e471ba3dSJoseph Huber // Add final padding to required alignment. 262e471ba3dSJoseph Huber assert(TheHeader.Size >= OS.tell() && "Too much data written?"); 263e471ba3dSJoseph Huber OS.write_zeros(TheHeader.Size - OS.tell()); 264e471ba3dSJoseph Huber assert(TheHeader.Size == OS.tell() && "Size mismatch"); 265e471ba3dSJoseph Huber 266f93c271dSFangrui Song return Data; 267e471ba3dSJoseph Huber } 268e471ba3dSJoseph Huber 2695dbc7cf7SJoseph Huber Error object::extractOffloadBinaries(MemoryBufferRef Buffer, 2705dbc7cf7SJoseph Huber SmallVectorImpl<OffloadFile> &Binaries) { 2715dbc7cf7SJoseph Huber file_magic Type = identify_magic(Buffer.getBuffer()); 2725dbc7cf7SJoseph Huber switch (Type) { 2735dbc7cf7SJoseph Huber case file_magic::bitcode: 2745dbc7cf7SJoseph Huber return extractFromBitcode(Buffer, Binaries); 2753384f05aSJoseph Huber case file_magic::elf_relocatable: 2763384f05aSJoseph Huber case file_magic::elf_executable: 2778298f0b7SJoseph Huber case file_magic::elf_shared_object: 2788298f0b7SJoseph Huber case file_magic::coff_object: { 2795dbc7cf7SJoseph Huber Expected<std::unique_ptr<ObjectFile>> ObjFile = 2805dbc7cf7SJoseph Huber ObjectFile::createObjectFile(Buffer, Type); 2815dbc7cf7SJoseph Huber if (!ObjFile) 2825dbc7cf7SJoseph Huber return ObjFile.takeError(); 2838298f0b7SJoseph Huber return extractFromObject(*ObjFile->get(), Binaries); 2845dbc7cf7SJoseph Huber } 2855dbc7cf7SJoseph Huber case file_magic::archive: { 2865dbc7cf7SJoseph Huber Expected<std::unique_ptr<llvm::object::Archive>> LibFile = 2875dbc7cf7SJoseph Huber object::Archive::create(Buffer); 2885dbc7cf7SJoseph Huber if (!LibFile) 2895dbc7cf7SJoseph Huber return LibFile.takeError(); 2905dbc7cf7SJoseph Huber return extractFromArchive(*LibFile->get(), Binaries); 2915dbc7cf7SJoseph Huber } 2925dbc7cf7SJoseph Huber case file_magic::offload_binary: 2935dbc7cf7SJoseph Huber return extractOffloadFiles(Buffer, Binaries); 2945dbc7cf7SJoseph Huber default: 2955dbc7cf7SJoseph Huber return Error::success(); 2965dbc7cf7SJoseph Huber } 2975dbc7cf7SJoseph Huber } 2985dbc7cf7SJoseph Huber 2992108f7a2SFangrui Song OffloadKind object::getOffloadKind(StringRef Name) { 300e471ba3dSJoseph Huber return llvm::StringSwitch<OffloadKind>(Name) 301e471ba3dSJoseph Huber .Case("openmp", OFK_OpenMP) 302e471ba3dSJoseph Huber .Case("cuda", OFK_Cuda) 303e471ba3dSJoseph Huber .Case("hip", OFK_HIP) 304e471ba3dSJoseph Huber .Default(OFK_None); 305e471ba3dSJoseph Huber } 306e471ba3dSJoseph Huber 3072108f7a2SFangrui Song StringRef object::getOffloadKindName(OffloadKind Kind) { 308e471ba3dSJoseph Huber switch (Kind) { 309e471ba3dSJoseph Huber case OFK_OpenMP: 310e471ba3dSJoseph Huber return "openmp"; 311e471ba3dSJoseph Huber case OFK_Cuda: 312e471ba3dSJoseph Huber return "cuda"; 313e471ba3dSJoseph Huber case OFK_HIP: 314e471ba3dSJoseph Huber return "hip"; 315e471ba3dSJoseph Huber default: 316e471ba3dSJoseph Huber return "none"; 317e471ba3dSJoseph Huber } 318e471ba3dSJoseph Huber } 319e471ba3dSJoseph Huber 3202108f7a2SFangrui Song ImageKind object::getImageKind(StringRef Name) { 321e471ba3dSJoseph Huber return llvm::StringSwitch<ImageKind>(Name) 322e471ba3dSJoseph Huber .Case("o", IMG_Object) 323e471ba3dSJoseph Huber .Case("bc", IMG_Bitcode) 324e471ba3dSJoseph Huber .Case("cubin", IMG_Cubin) 325e471ba3dSJoseph Huber .Case("fatbin", IMG_Fatbinary) 326e471ba3dSJoseph Huber .Case("s", IMG_PTX) 327e471ba3dSJoseph Huber .Default(IMG_None); 328e471ba3dSJoseph Huber } 329e471ba3dSJoseph Huber 3302108f7a2SFangrui Song StringRef object::getImageKindName(ImageKind Kind) { 331e471ba3dSJoseph Huber switch (Kind) { 332e471ba3dSJoseph Huber case IMG_Object: 333e471ba3dSJoseph Huber return "o"; 334e471ba3dSJoseph Huber case IMG_Bitcode: 335e471ba3dSJoseph Huber return "bc"; 336e471ba3dSJoseph Huber case IMG_Cubin: 337e471ba3dSJoseph Huber return "cubin"; 338e471ba3dSJoseph Huber case IMG_Fatbinary: 339e471ba3dSJoseph Huber return "fatbin"; 340e471ba3dSJoseph Huber case IMG_PTX: 341e471ba3dSJoseph Huber return "s"; 342e471ba3dSJoseph Huber default: 343e471ba3dSJoseph Huber return ""; 344e471ba3dSJoseph Huber } 345e471ba3dSJoseph Huber } 34612c90bd6SJoseph Huber 34712c90bd6SJoseph Huber bool object::areTargetsCompatible(const OffloadFile::TargetID &LHS, 34812c90bd6SJoseph Huber const OffloadFile::TargetID &RHS) { 34912c90bd6SJoseph Huber // Exact matches are not considered compatible because they are the same 35012c90bd6SJoseph Huber // target. We are interested in different targets that are compatible. 35112c90bd6SJoseph Huber if (LHS == RHS) 35212c90bd6SJoseph Huber return false; 35312c90bd6SJoseph Huber 35412c90bd6SJoseph Huber // The triples must match at all times. 35512c90bd6SJoseph Huber if (LHS.first != RHS.first) 35612c90bd6SJoseph Huber return false; 35712c90bd6SJoseph Huber 35842230e21SJoseph Huber // If the architecture is "all" we assume it is always compatible. 359*bb6df080SKazu Hirata if (LHS.second == "generic" || RHS.second == "generic") 36042230e21SJoseph Huber return true; 36142230e21SJoseph Huber 36212c90bd6SJoseph Huber // Only The AMDGPU target requires additional checks. 36312c90bd6SJoseph Huber llvm::Triple T(LHS.first); 36412c90bd6SJoseph Huber if (!T.isAMDGPU()) 36512c90bd6SJoseph Huber return false; 36612c90bd6SJoseph Huber 36712c90bd6SJoseph Huber // The base processor must always match. 36812c90bd6SJoseph Huber if (LHS.second.split(":").first != RHS.second.split(":").first) 36912c90bd6SJoseph Huber return false; 37012c90bd6SJoseph Huber 37112c90bd6SJoseph Huber // Check combintions of on / off features that must match. 37212c90bd6SJoseph Huber if (LHS.second.contains("xnack+") && RHS.second.contains("xnack-")) 37312c90bd6SJoseph Huber return false; 37412c90bd6SJoseph Huber if (LHS.second.contains("xnack-") && RHS.second.contains("xnack+")) 37512c90bd6SJoseph Huber return false; 37612c90bd6SJoseph Huber if (LHS.second.contains("sramecc-") && RHS.second.contains("sramecc+")) 37712c90bd6SJoseph Huber return false; 37812c90bd6SJoseph Huber if (LHS.second.contains("sramecc+") && RHS.second.contains("sramecc-")) 37912c90bd6SJoseph Huber return false; 38012c90bd6SJoseph Huber return true; 38112c90bd6SJoseph Huber } 382