xref: /freebsd-src/contrib/llvm-project/llvm/lib/Object/OffloadBinary.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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