xref: /freebsd-src/contrib/llvm-project/llvm/lib/Object/OffloadBinary.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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"
13*bdd1243dSDimitry Andric #include "llvm/IR/Constants.h"
14*bdd1243dSDimitry Andric #include "llvm/IR/Module.h"
15*bdd1243dSDimitry Andric #include "llvm/IRReader/IRReader.h"
1681ad6265SDimitry Andric #include "llvm/MC/StringTableBuilder.h"
17*bdd1243dSDimitry Andric #include "llvm/Object/Archive.h"
18*bdd1243dSDimitry Andric #include "llvm/Object/ArchiveWriter.h"
19*bdd1243dSDimitry Andric #include "llvm/Object/Binary.h"
20*bdd1243dSDimitry Andric #include "llvm/Object/COFF.h"
21*bdd1243dSDimitry Andric #include "llvm/Object/ELFObjectFile.h"
2281ad6265SDimitry Andric #include "llvm/Object/Error.h"
23*bdd1243dSDimitry Andric #include "llvm/Object/IRObjectFile.h"
24*bdd1243dSDimitry Andric #include "llvm/Object/ObjectFile.h"
2581ad6265SDimitry Andric #include "llvm/Support/Alignment.h"
2681ad6265SDimitry Andric #include "llvm/Support/FileOutputBuffer.h"
27*bdd1243dSDimitry Andric #include "llvm/Support/SourceMgr.h"
2881ad6265SDimitry Andric 
2981ad6265SDimitry Andric using namespace llvm;
3081ad6265SDimitry Andric using namespace llvm::object;
3181ad6265SDimitry Andric 
32*bdd1243dSDimitry Andric namespace {
33*bdd1243dSDimitry Andric 
34*bdd1243dSDimitry Andric /// Attempts to extract all the embedded device images contained inside the
35*bdd1243dSDimitry Andric /// buffer \p Contents. The buffer is expected to contain a valid offloading
36*bdd1243dSDimitry Andric /// binary format.
37*bdd1243dSDimitry Andric Error extractOffloadFiles(MemoryBufferRef Contents,
38*bdd1243dSDimitry Andric                           SmallVectorImpl<OffloadFile> &Binaries) {
39*bdd1243dSDimitry Andric   uint64_t Offset = 0;
40*bdd1243dSDimitry Andric   // There could be multiple offloading binaries stored at this section.
41*bdd1243dSDimitry Andric   while (Offset < Contents.getBuffer().size()) {
42*bdd1243dSDimitry Andric     std::unique_ptr<MemoryBuffer> Buffer =
43*bdd1243dSDimitry Andric         MemoryBuffer::getMemBuffer(Contents.getBuffer().drop_front(Offset), "",
44*bdd1243dSDimitry Andric                                    /*RequiresNullTerminator*/ false);
45*bdd1243dSDimitry Andric     if (!isAddrAligned(Align(OffloadBinary::getAlignment()),
46*bdd1243dSDimitry Andric                        Buffer->getBufferStart()))
47*bdd1243dSDimitry Andric       Buffer = MemoryBuffer::getMemBufferCopy(Buffer->getBuffer(),
48*bdd1243dSDimitry Andric                                               Buffer->getBufferIdentifier());
49*bdd1243dSDimitry Andric     auto BinaryOrErr = OffloadBinary::create(*Buffer);
50*bdd1243dSDimitry Andric     if (!BinaryOrErr)
51*bdd1243dSDimitry Andric       return BinaryOrErr.takeError();
52*bdd1243dSDimitry Andric     OffloadBinary &Binary = **BinaryOrErr;
53*bdd1243dSDimitry Andric 
54*bdd1243dSDimitry Andric     // Create a new owned binary with a copy of the original memory.
55*bdd1243dSDimitry Andric     std::unique_ptr<MemoryBuffer> BufferCopy = MemoryBuffer::getMemBufferCopy(
56*bdd1243dSDimitry Andric         Binary.getData().take_front(Binary.getSize()),
57*bdd1243dSDimitry Andric         Contents.getBufferIdentifier());
58*bdd1243dSDimitry Andric     auto NewBinaryOrErr = OffloadBinary::create(*BufferCopy);
59*bdd1243dSDimitry Andric     if (!NewBinaryOrErr)
60*bdd1243dSDimitry Andric       return NewBinaryOrErr.takeError();
61*bdd1243dSDimitry Andric     Binaries.emplace_back(std::move(*NewBinaryOrErr), std::move(BufferCopy));
62*bdd1243dSDimitry Andric 
63*bdd1243dSDimitry Andric     Offset += Binary.getSize();
64*bdd1243dSDimitry Andric   }
65*bdd1243dSDimitry Andric 
66*bdd1243dSDimitry Andric   return Error::success();
67*bdd1243dSDimitry Andric }
68*bdd1243dSDimitry Andric 
69*bdd1243dSDimitry Andric // Extract offloading binaries from an Object file \p Obj.
70*bdd1243dSDimitry Andric Error extractFromObject(const ObjectFile &Obj,
71*bdd1243dSDimitry Andric                         SmallVectorImpl<OffloadFile> &Binaries) {
72*bdd1243dSDimitry Andric   assert((Obj.isELF() || Obj.isCOFF()) && "Invalid file type");
73*bdd1243dSDimitry Andric 
74*bdd1243dSDimitry Andric   for (SectionRef Sec : Obj.sections()) {
75*bdd1243dSDimitry Andric     // ELF files contain a section with the LLVM_OFFLOADING type.
76*bdd1243dSDimitry Andric     if (Obj.isELF() &&
77*bdd1243dSDimitry Andric         static_cast<ELFSectionRef>(Sec).getType() != ELF::SHT_LLVM_OFFLOADING)
78*bdd1243dSDimitry Andric       continue;
79*bdd1243dSDimitry Andric 
80*bdd1243dSDimitry Andric     // COFF has no section types so we rely on the name of the section.
81*bdd1243dSDimitry Andric     if (Obj.isCOFF()) {
82*bdd1243dSDimitry Andric       Expected<StringRef> NameOrErr = Sec.getName();
83*bdd1243dSDimitry Andric       if (!NameOrErr)
84*bdd1243dSDimitry Andric         return NameOrErr.takeError();
85*bdd1243dSDimitry Andric 
86*bdd1243dSDimitry Andric       if (!NameOrErr->equals(".llvm.offloading"))
87*bdd1243dSDimitry Andric         continue;
88*bdd1243dSDimitry Andric     }
89*bdd1243dSDimitry Andric 
90*bdd1243dSDimitry Andric     Expected<StringRef> Buffer = Sec.getContents();
91*bdd1243dSDimitry Andric     if (!Buffer)
92*bdd1243dSDimitry Andric       return Buffer.takeError();
93*bdd1243dSDimitry Andric 
94*bdd1243dSDimitry Andric     MemoryBufferRef Contents(*Buffer, Obj.getFileName());
95*bdd1243dSDimitry Andric     if (Error Err = extractOffloadFiles(Contents, Binaries))
96*bdd1243dSDimitry Andric       return Err;
97*bdd1243dSDimitry Andric   }
98*bdd1243dSDimitry Andric 
99*bdd1243dSDimitry Andric   return Error::success();
100*bdd1243dSDimitry Andric }
101*bdd1243dSDimitry Andric 
102*bdd1243dSDimitry Andric Error extractFromBitcode(MemoryBufferRef Buffer,
103*bdd1243dSDimitry Andric                          SmallVectorImpl<OffloadFile> &Binaries) {
104*bdd1243dSDimitry Andric   LLVMContext Context;
105*bdd1243dSDimitry Andric   SMDiagnostic Err;
106*bdd1243dSDimitry Andric   std::unique_ptr<Module> M = getLazyIRModule(
107*bdd1243dSDimitry Andric       MemoryBuffer::getMemBuffer(Buffer, /*RequiresNullTerminator=*/false), Err,
108*bdd1243dSDimitry Andric       Context);
109*bdd1243dSDimitry Andric   if (!M)
110*bdd1243dSDimitry Andric     return createStringError(inconvertibleErrorCode(),
111*bdd1243dSDimitry Andric                              "Failed to create module");
112*bdd1243dSDimitry Andric 
113*bdd1243dSDimitry Andric   // Extract offloading data from globals referenced by the
114*bdd1243dSDimitry Andric   // `llvm.embedded.object` metadata with the `.llvm.offloading` section.
115*bdd1243dSDimitry Andric   auto *MD = M->getNamedMetadata("llvm.embedded.objects");
116*bdd1243dSDimitry Andric   if (!MD)
117*bdd1243dSDimitry Andric     return Error::success();
118*bdd1243dSDimitry Andric 
119*bdd1243dSDimitry Andric   for (const MDNode *Op : MD->operands()) {
120*bdd1243dSDimitry Andric     if (Op->getNumOperands() < 2)
121*bdd1243dSDimitry Andric       continue;
122*bdd1243dSDimitry Andric 
123*bdd1243dSDimitry Andric     MDString *SectionID = dyn_cast<MDString>(Op->getOperand(1));
124*bdd1243dSDimitry Andric     if (!SectionID || SectionID->getString() != ".llvm.offloading")
125*bdd1243dSDimitry Andric       continue;
126*bdd1243dSDimitry Andric 
127*bdd1243dSDimitry Andric     GlobalVariable *GV =
128*bdd1243dSDimitry Andric         mdconst::dyn_extract_or_null<GlobalVariable>(Op->getOperand(0));
129*bdd1243dSDimitry Andric     if (!GV)
130*bdd1243dSDimitry Andric       continue;
131*bdd1243dSDimitry Andric 
132*bdd1243dSDimitry Andric     auto *CDS = dyn_cast<ConstantDataSequential>(GV->getInitializer());
133*bdd1243dSDimitry Andric     if (!CDS)
134*bdd1243dSDimitry Andric       continue;
135*bdd1243dSDimitry Andric 
136*bdd1243dSDimitry Andric     MemoryBufferRef Contents(CDS->getAsString(), M->getName());
137*bdd1243dSDimitry Andric     if (Error Err = extractOffloadFiles(Contents, Binaries))
138*bdd1243dSDimitry Andric       return Err;
139*bdd1243dSDimitry Andric   }
140*bdd1243dSDimitry Andric 
141*bdd1243dSDimitry Andric   return Error::success();
142*bdd1243dSDimitry Andric }
143*bdd1243dSDimitry Andric 
144*bdd1243dSDimitry Andric Error extractFromArchive(const Archive &Library,
145*bdd1243dSDimitry Andric                          SmallVectorImpl<OffloadFile> &Binaries) {
146*bdd1243dSDimitry Andric   // Try to extract device code from each file stored in the static archive.
147*bdd1243dSDimitry Andric   Error Err = Error::success();
148*bdd1243dSDimitry Andric   for (auto Child : Library.children(Err)) {
149*bdd1243dSDimitry Andric     auto ChildBufferOrErr = Child.getMemoryBufferRef();
150*bdd1243dSDimitry Andric     if (!ChildBufferOrErr)
151*bdd1243dSDimitry Andric       return ChildBufferOrErr.takeError();
152*bdd1243dSDimitry Andric     std::unique_ptr<MemoryBuffer> ChildBuffer =
153*bdd1243dSDimitry Andric         MemoryBuffer::getMemBuffer(*ChildBufferOrErr, false);
154*bdd1243dSDimitry Andric 
155*bdd1243dSDimitry Andric     // Check if the buffer has the required alignment.
156*bdd1243dSDimitry Andric     if (!isAddrAligned(Align(OffloadBinary::getAlignment()),
157*bdd1243dSDimitry Andric                        ChildBuffer->getBufferStart()))
158*bdd1243dSDimitry Andric       ChildBuffer = MemoryBuffer::getMemBufferCopy(
159*bdd1243dSDimitry Andric           ChildBufferOrErr->getBuffer(),
160*bdd1243dSDimitry Andric           ChildBufferOrErr->getBufferIdentifier());
161*bdd1243dSDimitry Andric 
162*bdd1243dSDimitry Andric     if (Error Err = extractOffloadBinaries(*ChildBuffer, Binaries))
163*bdd1243dSDimitry Andric       return Err;
164*bdd1243dSDimitry Andric   }
165*bdd1243dSDimitry Andric 
166*bdd1243dSDimitry Andric   if (Err)
167*bdd1243dSDimitry Andric     return Err;
168*bdd1243dSDimitry Andric   return Error::success();
169*bdd1243dSDimitry Andric }
170*bdd1243dSDimitry Andric 
171*bdd1243dSDimitry Andric } // namespace
172*bdd1243dSDimitry 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() ||
19281ad6265SDimitry Andric       TheHeader->EntryOffset > TheHeader->Size - sizeof(Entry) ||
19381ad6265SDimitry Andric       TheHeader->EntrySize > TheHeader->Size - sizeof(Header))
19481ad6265SDimitry Andric     return errorCodeToError(object_error::unexpected_eof);
19581ad6265SDimitry Andric 
19681ad6265SDimitry Andric   const Entry *TheEntry =
19781ad6265SDimitry Andric       reinterpret_cast<const Entry *>(&Start[TheHeader->EntryOffset]);
19881ad6265SDimitry Andric 
19981ad6265SDimitry Andric   if (TheEntry->ImageOffset > Buf.getBufferSize() ||
20081ad6265SDimitry Andric       TheEntry->StringOffset > Buf.getBufferSize())
20181ad6265SDimitry Andric     return errorCodeToError(object_error::unexpected_eof);
20281ad6265SDimitry Andric 
20381ad6265SDimitry Andric   return std::unique_ptr<OffloadBinary>(
20481ad6265SDimitry Andric       new OffloadBinary(Buf, TheHeader, TheEntry));
20581ad6265SDimitry Andric }
20681ad6265SDimitry Andric 
20781ad6265SDimitry Andric std::unique_ptr<MemoryBuffer>
20881ad6265SDimitry Andric OffloadBinary::write(const OffloadingImage &OffloadingData) {
20981ad6265SDimitry Andric   // Create a null-terminated string table with all the used strings.
21081ad6265SDimitry Andric   StringTableBuilder StrTab(StringTableBuilder::ELF);
21181ad6265SDimitry Andric   for (auto &KeyAndValue : OffloadingData.StringData) {
21281ad6265SDimitry Andric     StrTab.add(KeyAndValue.getKey());
21381ad6265SDimitry Andric     StrTab.add(KeyAndValue.getValue());
21481ad6265SDimitry Andric   }
21581ad6265SDimitry Andric   StrTab.finalize();
21681ad6265SDimitry Andric 
21781ad6265SDimitry Andric   uint64_t StringEntrySize =
21881ad6265SDimitry Andric       sizeof(StringEntry) * OffloadingData.StringData.size();
21981ad6265SDimitry Andric 
22081ad6265SDimitry Andric   // Make sure the image we're wrapping around is aligned as well.
22181ad6265SDimitry Andric   uint64_t BinaryDataSize = alignTo(sizeof(Header) + sizeof(Entry) +
22281ad6265SDimitry Andric                                         StringEntrySize + StrTab.getSize(),
22381ad6265SDimitry Andric                                     getAlignment());
22481ad6265SDimitry Andric 
22581ad6265SDimitry Andric   // Create the header and fill in the offsets. The entry will be directly
22681ad6265SDimitry Andric   // placed after the header in memory. Align the size to the alignment of the
22781ad6265SDimitry Andric   // header so this can be placed contiguously in a single section.
22881ad6265SDimitry Andric   Header TheHeader;
22981ad6265SDimitry Andric   TheHeader.Size = alignTo(
23081ad6265SDimitry Andric       BinaryDataSize + OffloadingData.Image->getBufferSize(), getAlignment());
23181ad6265SDimitry Andric   TheHeader.EntryOffset = sizeof(Header);
23281ad6265SDimitry Andric   TheHeader.EntrySize = sizeof(Entry);
23381ad6265SDimitry Andric 
23481ad6265SDimitry Andric   // Create the entry using the string table offsets. The string table will be
23581ad6265SDimitry Andric   // placed directly after the entry in memory, and the image after that.
23681ad6265SDimitry Andric   Entry TheEntry;
23781ad6265SDimitry Andric   TheEntry.TheImageKind = OffloadingData.TheImageKind;
23881ad6265SDimitry Andric   TheEntry.TheOffloadKind = OffloadingData.TheOffloadKind;
23981ad6265SDimitry Andric   TheEntry.Flags = OffloadingData.Flags;
24081ad6265SDimitry Andric   TheEntry.StringOffset = sizeof(Header) + sizeof(Entry);
24181ad6265SDimitry Andric   TheEntry.NumStrings = OffloadingData.StringData.size();
24281ad6265SDimitry Andric 
24381ad6265SDimitry Andric   TheEntry.ImageOffset = BinaryDataSize;
24481ad6265SDimitry Andric   TheEntry.ImageSize = OffloadingData.Image->getBufferSize();
24581ad6265SDimitry Andric 
24681ad6265SDimitry Andric   SmallVector<char> Data;
24781ad6265SDimitry Andric   Data.reserve(TheHeader.Size);
24881ad6265SDimitry Andric   raw_svector_ostream OS(Data);
24981ad6265SDimitry Andric   OS << StringRef(reinterpret_cast<char *>(&TheHeader), sizeof(Header));
25081ad6265SDimitry Andric   OS << StringRef(reinterpret_cast<char *>(&TheEntry), sizeof(Entry));
25181ad6265SDimitry Andric   for (auto &KeyAndValue : OffloadingData.StringData) {
25281ad6265SDimitry Andric     uint64_t Offset = sizeof(Header) + sizeof(Entry) + StringEntrySize;
25381ad6265SDimitry Andric     StringEntry Map{Offset + StrTab.getOffset(KeyAndValue.getKey()),
25481ad6265SDimitry Andric                     Offset + StrTab.getOffset(KeyAndValue.getValue())};
25581ad6265SDimitry Andric     OS << StringRef(reinterpret_cast<char *>(&Map), sizeof(StringEntry));
25681ad6265SDimitry Andric   }
25781ad6265SDimitry Andric   StrTab.write(OS);
25881ad6265SDimitry Andric   // Add padding to required image alignment.
25981ad6265SDimitry Andric   OS.write_zeros(TheEntry.ImageOffset - OS.tell());
26081ad6265SDimitry Andric   OS << OffloadingData.Image->getBuffer();
26181ad6265SDimitry Andric 
26281ad6265SDimitry Andric   // Add final padding to required alignment.
26381ad6265SDimitry Andric   assert(TheHeader.Size >= OS.tell() && "Too much data written?");
26481ad6265SDimitry Andric   OS.write_zeros(TheHeader.Size - OS.tell());
26581ad6265SDimitry Andric   assert(TheHeader.Size == OS.tell() && "Size mismatch");
26681ad6265SDimitry Andric 
26781ad6265SDimitry Andric   return MemoryBuffer::getMemBufferCopy(OS.str());
26881ad6265SDimitry Andric }
26981ad6265SDimitry Andric 
270*bdd1243dSDimitry Andric Error object::extractOffloadBinaries(MemoryBufferRef Buffer,
271*bdd1243dSDimitry Andric                                      SmallVectorImpl<OffloadFile> &Binaries) {
272*bdd1243dSDimitry Andric   file_magic Type = identify_magic(Buffer.getBuffer());
273*bdd1243dSDimitry Andric   switch (Type) {
274*bdd1243dSDimitry Andric   case file_magic::bitcode:
275*bdd1243dSDimitry Andric     return extractFromBitcode(Buffer, Binaries);
276*bdd1243dSDimitry Andric   case file_magic::elf_relocatable:
277*bdd1243dSDimitry Andric   case file_magic::elf_executable:
278*bdd1243dSDimitry Andric   case file_magic::elf_shared_object:
279*bdd1243dSDimitry Andric   case file_magic::coff_object: {
280*bdd1243dSDimitry Andric     Expected<std::unique_ptr<ObjectFile>> ObjFile =
281*bdd1243dSDimitry Andric         ObjectFile::createObjectFile(Buffer, Type);
282*bdd1243dSDimitry Andric     if (!ObjFile)
283*bdd1243dSDimitry Andric       return ObjFile.takeError();
284*bdd1243dSDimitry Andric     return extractFromObject(*ObjFile->get(), Binaries);
285*bdd1243dSDimitry Andric   }
286*bdd1243dSDimitry Andric   case file_magic::archive: {
287*bdd1243dSDimitry Andric     Expected<std::unique_ptr<llvm::object::Archive>> LibFile =
288*bdd1243dSDimitry Andric         object::Archive::create(Buffer);
289*bdd1243dSDimitry Andric     if (!LibFile)
290*bdd1243dSDimitry Andric       return LibFile.takeError();
291*bdd1243dSDimitry Andric     return extractFromArchive(*LibFile->get(), Binaries);
292*bdd1243dSDimitry Andric   }
293*bdd1243dSDimitry Andric   case file_magic::offload_binary:
294*bdd1243dSDimitry Andric     return extractOffloadFiles(Buffer, Binaries);
295*bdd1243dSDimitry Andric   default:
296*bdd1243dSDimitry Andric     return Error::success();
297*bdd1243dSDimitry Andric   }
298*bdd1243dSDimitry Andric }
299*bdd1243dSDimitry Andric 
30081ad6265SDimitry Andric OffloadKind object::getOffloadKind(StringRef Name) {
30181ad6265SDimitry Andric   return llvm::StringSwitch<OffloadKind>(Name)
30281ad6265SDimitry Andric       .Case("openmp", OFK_OpenMP)
30381ad6265SDimitry Andric       .Case("cuda", OFK_Cuda)
30481ad6265SDimitry Andric       .Case("hip", OFK_HIP)
30581ad6265SDimitry Andric       .Default(OFK_None);
30681ad6265SDimitry Andric }
30781ad6265SDimitry Andric 
30881ad6265SDimitry Andric StringRef object::getOffloadKindName(OffloadKind Kind) {
30981ad6265SDimitry Andric   switch (Kind) {
31081ad6265SDimitry Andric   case OFK_OpenMP:
31181ad6265SDimitry Andric     return "openmp";
31281ad6265SDimitry Andric   case OFK_Cuda:
31381ad6265SDimitry Andric     return "cuda";
31481ad6265SDimitry Andric   case OFK_HIP:
31581ad6265SDimitry Andric     return "hip";
31681ad6265SDimitry Andric   default:
31781ad6265SDimitry Andric     return "none";
31881ad6265SDimitry Andric   }
31981ad6265SDimitry Andric }
32081ad6265SDimitry Andric 
32181ad6265SDimitry Andric ImageKind object::getImageKind(StringRef Name) {
32281ad6265SDimitry Andric   return llvm::StringSwitch<ImageKind>(Name)
32381ad6265SDimitry Andric       .Case("o", IMG_Object)
32481ad6265SDimitry Andric       .Case("bc", IMG_Bitcode)
32581ad6265SDimitry Andric       .Case("cubin", IMG_Cubin)
32681ad6265SDimitry Andric       .Case("fatbin", IMG_Fatbinary)
32781ad6265SDimitry Andric       .Case("s", IMG_PTX)
32881ad6265SDimitry Andric       .Default(IMG_None);
32981ad6265SDimitry Andric }
33081ad6265SDimitry Andric 
33181ad6265SDimitry Andric StringRef object::getImageKindName(ImageKind Kind) {
33281ad6265SDimitry Andric   switch (Kind) {
33381ad6265SDimitry Andric   case IMG_Object:
33481ad6265SDimitry Andric     return "o";
33581ad6265SDimitry Andric   case IMG_Bitcode:
33681ad6265SDimitry Andric     return "bc";
33781ad6265SDimitry Andric   case IMG_Cubin:
33881ad6265SDimitry Andric     return "cubin";
33981ad6265SDimitry Andric   case IMG_Fatbinary:
34081ad6265SDimitry Andric     return "fatbin";
34181ad6265SDimitry Andric   case IMG_PTX:
34281ad6265SDimitry Andric     return "s";
34381ad6265SDimitry Andric   default:
34481ad6265SDimitry Andric     return "";
34581ad6265SDimitry Andric   }
34681ad6265SDimitry Andric }
347