1 //===- Offloading.cpp - Utilities for handling offloading code -*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/Object/OffloadBinary.h" 10 11 #include "llvm/ADT/StringSwitch.h" 12 #include "llvm/BinaryFormat/Magic.h" 13 #include "llvm/MC/StringTableBuilder.h" 14 #include "llvm/Object/Error.h" 15 #include "llvm/Support/FileOutputBuffer.h" 16 17 namespace llvm { 18 19 namespace object { 20 21 Expected<std::unique_ptr<OffloadBinary>> 22 OffloadBinary::create(MemoryBufferRef Buf) { 23 if (Buf.getBufferSize() < sizeof(Header) + sizeof(Entry)) 24 return errorCodeToError(object_error::parse_failed); 25 26 // Check for 0x10FF1OAD magic bytes. 27 if (identify_magic(Buf.getBuffer()) != file_magic::offload_binary) 28 return errorCodeToError(object_error::parse_failed); 29 30 const char *Start = Buf.getBufferStart(); 31 const Header *TheHeader = reinterpret_cast<const Header *>(Start); 32 const Entry *TheEntry = 33 reinterpret_cast<const Entry *>(&Start[TheHeader->EntryOffset]); 34 35 return std::unique_ptr<OffloadBinary>( 36 new OffloadBinary(Buf, TheHeader, TheEntry)); 37 } 38 39 std::unique_ptr<MemoryBuffer> 40 OffloadBinary::write(const OffloadingImage &OffloadingData) { 41 // Create a null-terminated string table with all the used strings. 42 StringTableBuilder StrTab(StringTableBuilder::ELF); 43 for (auto &KeyAndValue : OffloadingData.StringData) { 44 StrTab.add(KeyAndValue.getKey()); 45 StrTab.add(KeyAndValue.getValue()); 46 } 47 StrTab.finalize(); 48 49 uint64_t StringEntrySize = 50 sizeof(StringEntry) * OffloadingData.StringData.size(); 51 52 // Create the header and fill in the offsets. The entry will be directly 53 // placed after the header in memory. Align the size to the alignment of the 54 // header so this can be placed contiguously in a single section. 55 Header TheHeader; 56 TheHeader.Size = 57 alignTo(sizeof(Header) + sizeof(Entry) + StringEntrySize + 58 OffloadingData.Image.getBufferSize() + StrTab.getSize(), 59 getAlignment()); 60 TheHeader.EntryOffset = sizeof(Header); 61 TheHeader.EntrySize = sizeof(Entry); 62 63 // Create the entry using the string table offsets. The string table will be 64 // placed directly after the entry in memory, and the image after that. 65 Entry TheEntry; 66 TheEntry.TheImageKind = OffloadingData.TheImageKind; 67 TheEntry.TheOffloadKind = OffloadingData.TheOffloadKind; 68 TheEntry.Flags = OffloadingData.Flags; 69 TheEntry.StringOffset = sizeof(Header) + sizeof(Entry); 70 TheEntry.NumStrings = OffloadingData.StringData.size(); 71 72 TheEntry.ImageOffset = 73 sizeof(Header) + sizeof(Entry) + StringEntrySize + StrTab.getSize(); 74 TheEntry.ImageSize = OffloadingData.Image.getBufferSize(); 75 76 SmallVector<char, 1024> Data; 77 raw_svector_ostream OS(Data); 78 OS << StringRef(reinterpret_cast<char *>(&TheHeader), sizeof(Header)); 79 OS << StringRef(reinterpret_cast<char *>(&TheEntry), sizeof(Entry)); 80 for (auto &KeyAndValue : OffloadingData.StringData) { 81 uint64_t Offset = sizeof(Header) + sizeof(Entry) + StringEntrySize; 82 StringEntry Map{Offset + StrTab.getOffset(KeyAndValue.getKey()), 83 Offset + StrTab.getOffset(KeyAndValue.getValue())}; 84 OS << StringRef(reinterpret_cast<char *>(&Map), sizeof(StringEntry)); 85 } 86 StrTab.write(OS); 87 OS << OffloadingData.Image.getBuffer(); 88 89 // Add final padding to required alignment. 90 assert(TheHeader.Size >= OS.tell() && "Too much data written?"); 91 OS.write_zeros(TheHeader.Size - OS.tell()); 92 assert(TheHeader.Size == OS.tell() && "Size mismatch"); 93 94 return MemoryBuffer::getMemBufferCopy(OS.str()); 95 } 96 97 OffloadKind getOffloadKind(StringRef Name) { 98 return llvm::StringSwitch<OffloadKind>(Name) 99 .Case("openmp", OFK_OpenMP) 100 .Case("cuda", OFK_Cuda) 101 .Case("hip", OFK_HIP) 102 .Default(OFK_None); 103 } 104 105 StringRef getOffloadKindName(OffloadKind Kind) { 106 switch (Kind) { 107 case OFK_OpenMP: 108 return "openmp"; 109 case OFK_Cuda: 110 return "cuda"; 111 case OFK_HIP: 112 return "hip"; 113 default: 114 return "none"; 115 } 116 } 117 118 ImageKind getImageKind(StringRef Name) { 119 return llvm::StringSwitch<ImageKind>(Name) 120 .Case("o", IMG_Object) 121 .Case("bc", IMG_Bitcode) 122 .Case("cubin", IMG_Cubin) 123 .Case("fatbin", IMG_Fatbinary) 124 .Case("s", IMG_PTX) 125 .Default(IMG_None); 126 } 127 128 StringRef getImageKindName(ImageKind Kind) { 129 switch (Kind) { 130 case IMG_Object: 131 return "o"; 132 case IMG_Bitcode: 133 return "bc"; 134 case IMG_Cubin: 135 return "cubin"; 136 case IMG_Fatbinary: 137 return "fatbin"; 138 case IMG_PTX: 139 return "s"; 140 default: 141 return ""; 142 } 143 } 144 145 } // namespace object 146 147 } // namespace llvm 148