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