1 //===- ModuleToObject.cpp - Module to object base class ---------*- 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 // This file implements the base class for transforming Operations into binary 10 // objects. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "mlir/Target/LLVM/ModuleToObject.h" 15 16 #include "mlir/ExecutionEngine/OptUtils.h" 17 #include "mlir/IR/BuiltinAttributeInterfaces.h" 18 #include "mlir/IR/BuiltinAttributes.h" 19 #include "mlir/IR/BuiltinOps.h" 20 #include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h" 21 #include "mlir/Target/LLVMIR/Export.h" 22 #include "mlir/Target/LLVMIR/ModuleTranslation.h" 23 24 #include "llvm/Bitcode/BitcodeWriter.h" 25 #include "llvm/IR/LegacyPassManager.h" 26 #include "llvm/IRReader/IRReader.h" 27 #include "llvm/Linker/Linker.h" 28 #include "llvm/MC/TargetRegistry.h" 29 #include "llvm/Support/FileSystem.h" 30 #include "llvm/Support/MemoryBuffer.h" 31 #include "llvm/Support/Path.h" 32 #include "llvm/Support/SourceMgr.h" 33 #include "llvm/Support/raw_ostream.h" 34 #include "llvm/Target/TargetMachine.h" 35 #include "llvm/Transforms/IPO/Internalize.h" 36 37 using namespace mlir; 38 using namespace mlir::LLVM; 39 40 ModuleToObject::ModuleToObject( 41 Operation &module, StringRef triple, StringRef chip, StringRef features, 42 int optLevel, function_ref<void(llvm::Module &)> initialLlvmIRCallback, 43 function_ref<void(llvm::Module &)> linkedLlvmIRCallback, 44 function_ref<void(llvm::Module &)> optimizedLlvmIRCallback, 45 function_ref<void(StringRef)> isaCallback) 46 : module(module), triple(triple), chip(chip), features(features), 47 optLevel(optLevel), initialLlvmIRCallback(initialLlvmIRCallback), 48 linkedLlvmIRCallback(linkedLlvmIRCallback), 49 optimizedLlvmIRCallback(optimizedLlvmIRCallback), 50 isaCallback(isaCallback) {} 51 52 ModuleToObject::~ModuleToObject() = default; 53 54 Operation &ModuleToObject::getOperation() { return module; } 55 56 std::optional<llvm::TargetMachine *> 57 ModuleToObject::getOrCreateTargetMachine() { 58 if (targetMachine) 59 return targetMachine.get(); 60 // Load the target. 61 std::string error; 62 const llvm::Target *target = 63 llvm::TargetRegistry::lookupTarget(triple, error); 64 if (!target) { 65 getOperation().emitError() 66 << "Failed to lookup target for triple '" << triple << "' " << error; 67 return std::nullopt; 68 } 69 70 // Create the target machine using the target. 71 targetMachine.reset( 72 target->createTargetMachine(triple, chip, features, {}, {})); 73 if (!targetMachine) 74 return std::nullopt; 75 return targetMachine.get(); 76 } 77 78 std::unique_ptr<llvm::Module> 79 ModuleToObject::loadBitcodeFile(llvm::LLVMContext &context, StringRef path) { 80 llvm::SMDiagnostic error; 81 std::unique_ptr<llvm::Module> library = 82 llvm::getLazyIRFileModule(path, error, context); 83 if (!library) { 84 getOperation().emitError() << "Failed loading file from " << path 85 << ", error: " << error.getMessage(); 86 return nullptr; 87 } 88 if (failed(handleBitcodeFile(*library))) { 89 return nullptr; 90 } 91 return library; 92 } 93 94 LogicalResult ModuleToObject::loadBitcodeFilesFromList( 95 llvm::LLVMContext &context, ArrayRef<Attribute> librariesToLink, 96 SmallVector<std::unique_ptr<llvm::Module>> &llvmModules, 97 bool failureOnError) { 98 for (Attribute linkLib : librariesToLink) { 99 // Attributes in this list can be either list of file paths using 100 // StringAttr, or a resource attribute pointing to the LLVM bitcode in 101 // memory. 102 if (auto filePath = dyn_cast<StringAttr>(linkLib)) { 103 // Test if the path exists, if it doesn't abort. 104 if (!llvm::sys::fs::is_regular_file(filePath.strref())) { 105 getOperation().emitError() 106 << "File path: " << filePath << " does not exist or is not a file."; 107 return failure(); 108 } 109 // Load the file or abort on error. 110 if (auto bcFile = loadBitcodeFile(context, filePath)) 111 llvmModules.push_back(std::move(bcFile)); 112 else if (failureOnError) 113 return failure(); 114 continue; 115 } 116 if (auto blobAttr = dyn_cast<BlobAttr>(linkLib)) { 117 // Load the file or abort on error. 118 llvm::SMDiagnostic error; 119 ArrayRef<char> data = blobAttr.getData(); 120 std::unique_ptr<llvm::MemoryBuffer> buffer = 121 llvm::MemoryBuffer::getMemBuffer(StringRef(data.data(), data.size()), 122 "blobLinkedLib", 123 /*RequiresNullTerminator=*/false); 124 std::unique_ptr<llvm::Module> mod = 125 getLazyIRModule(std::move(buffer), error, context); 126 if (mod) { 127 if (failed(handleBitcodeFile(*mod))) 128 return failure(); 129 llvmModules.push_back(std::move(mod)); 130 } else if (failureOnError) { 131 getOperation().emitError() 132 << "Couldn't load LLVM library for linking: " << error.getMessage(); 133 return failure(); 134 } 135 continue; 136 } 137 if (failureOnError) { 138 getOperation().emitError() 139 << "Unknown attribute describing LLVM library to load: " << linkLib; 140 return failure(); 141 } 142 } 143 return success(); 144 } 145 146 std::unique_ptr<llvm::Module> 147 ModuleToObject::translateToLLVMIR(llvm::LLVMContext &llvmContext) { 148 return translateModuleToLLVMIR(&getOperation(), llvmContext); 149 } 150 151 LogicalResult 152 ModuleToObject::linkFiles(llvm::Module &module, 153 SmallVector<std::unique_ptr<llvm::Module>> &&libs) { 154 if (libs.empty()) 155 return success(); 156 llvm::Linker linker(module); 157 for (std::unique_ptr<llvm::Module> &libModule : libs) { 158 // This bitcode linking imports the library functions into the module, 159 // allowing LLVM optimization passes (which must run after linking) to 160 // optimize across the libraries and the module's code. We also only import 161 // symbols if they are referenced by the module or a previous library since 162 // there will be no other source of references to those symbols in this 163 // compilation and since we don't want to bloat the resulting code object. 164 bool err = linker.linkInModule( 165 std::move(libModule), llvm::Linker::Flags::LinkOnlyNeeded, 166 [](llvm::Module &m, const StringSet<> &gvs) { 167 llvm::internalizeModule(m, [&gvs](const llvm::GlobalValue &gv) { 168 return !gv.hasName() || (gvs.count(gv.getName()) == 0); 169 }); 170 }); 171 // True is linker failure 172 if (err) { 173 getOperation().emitError("Unrecoverable failure during bitcode linking."); 174 // We have no guaranties about the state of `ret`, so bail 175 return failure(); 176 } 177 } 178 return success(); 179 } 180 181 LogicalResult ModuleToObject::optimizeModule(llvm::Module &module, 182 183 int optLevel) { 184 if (optLevel < 0 || optLevel > 3) 185 return getOperation().emitError() 186 << "Invalid optimization level: " << optLevel << "."; 187 188 std::optional<llvm::TargetMachine *> targetMachine = 189 getOrCreateTargetMachine(); 190 if (!targetMachine) 191 return getOperation().emitError() 192 << "Target Machine unavailable for triple " << triple 193 << ", can't optimize with LLVM\n"; 194 (*targetMachine)->setOptLevel(static_cast<llvm::CodeGenOptLevel>(optLevel)); 195 196 auto transformer = 197 makeOptimizingTransformer(optLevel, /*sizeLevel=*/0, *targetMachine); 198 auto error = transformer(&module); 199 if (error) { 200 InFlightDiagnostic mlirError = getOperation().emitError(); 201 llvm::handleAllErrors( 202 std::move(error), [&mlirError](const llvm::ErrorInfoBase &ei) { 203 mlirError << "Could not optimize LLVM IR: " << ei.message() << "\n"; 204 }); 205 return mlirError; 206 } 207 return success(); 208 } 209 210 std::optional<std::string> 211 ModuleToObject::translateToISA(llvm::Module &llvmModule, 212 llvm::TargetMachine &targetMachine) { 213 std::string targetISA; 214 llvm::raw_string_ostream stream(targetISA); 215 216 { // Drop pstream after this to prevent the ISA from being stuck buffering 217 llvm::buffer_ostream pstream(stream); 218 llvm::legacy::PassManager codegenPasses; 219 220 if (targetMachine.addPassesToEmitFile(codegenPasses, pstream, nullptr, 221 llvm::CodeGenFileType::AssemblyFile)) 222 return std::nullopt; 223 224 codegenPasses.run(llvmModule); 225 } 226 return targetISA; 227 } 228 229 void ModuleToObject::setDataLayoutAndTriple(llvm::Module &module) { 230 // Create the target machine. 231 std::optional<llvm::TargetMachine *> targetMachine = 232 getOrCreateTargetMachine(); 233 if (targetMachine) { 234 // Set the data layout and target triple of the module. 235 module.setDataLayout((*targetMachine)->createDataLayout()); 236 module.setTargetTriple((*targetMachine)->getTargetTriple().getTriple()); 237 } 238 } 239 240 std::optional<SmallVector<char, 0>> 241 ModuleToObject::moduleToObject(llvm::Module &llvmModule) { 242 SmallVector<char, 0> binaryData; 243 // Write the LLVM module bitcode to a buffer. 244 llvm::raw_svector_ostream outputStream(binaryData); 245 llvm::WriteBitcodeToFile(llvmModule, outputStream); 246 return binaryData; 247 } 248 249 std::optional<SmallVector<char, 0>> ModuleToObject::run() { 250 // Translate the module to LLVM IR. 251 llvm::LLVMContext llvmContext; 252 std::unique_ptr<llvm::Module> llvmModule = translateToLLVMIR(llvmContext); 253 if (!llvmModule) { 254 getOperation().emitError() << "Failed creating the llvm::Module."; 255 return std::nullopt; 256 } 257 setDataLayoutAndTriple(*llvmModule); 258 259 if (initialLlvmIRCallback) 260 initialLlvmIRCallback(*llvmModule); 261 262 // Link bitcode files. 263 handleModulePreLink(*llvmModule); 264 { 265 auto libs = loadBitcodeFiles(*llvmModule); 266 if (!libs) 267 return std::nullopt; 268 if (!libs->empty()) 269 if (failed(linkFiles(*llvmModule, std::move(*libs)))) 270 return std::nullopt; 271 handleModulePostLink(*llvmModule); 272 } 273 274 if (linkedLlvmIRCallback) 275 linkedLlvmIRCallback(*llvmModule); 276 277 // Optimize the module. 278 if (failed(optimizeModule(*llvmModule, optLevel))) 279 return std::nullopt; 280 281 if (optimizedLlvmIRCallback) 282 optimizedLlvmIRCallback(*llvmModule); 283 284 // Return the serialized object. 285 return moduleToObject(*llvmModule); 286 } 287