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/BuiltinOps.h" 18 #include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h" 19 #include "mlir/Target/LLVMIR/Export.h" 20 #include "mlir/Target/LLVMIR/ModuleTranslation.h" 21 22 #include "llvm/Bitcode/BitcodeWriter.h" 23 #include "llvm/IR/LegacyPassManager.h" 24 #include "llvm/IRReader/IRReader.h" 25 #include "llvm/Linker/Linker.h" 26 #include "llvm/MC/TargetRegistry.h" 27 #include "llvm/Support/FileSystem.h" 28 #include "llvm/Support/Path.h" 29 #include "llvm/Support/SourceMgr.h" 30 #include "llvm/Support/raw_ostream.h" 31 #include "llvm/Target/TargetMachine.h" 32 #include "llvm/Transforms/IPO/Internalize.h" 33 34 using namespace mlir; 35 using namespace mlir::LLVM; 36 37 ModuleToObject::ModuleToObject(Operation &module, StringRef triple, 38 StringRef chip, StringRef features, int optLevel) 39 : module(module), triple(triple), chip(chip), features(features), 40 optLevel(optLevel) {} 41 42 Operation &ModuleToObject::getOperation() { return module; } 43 44 std::unique_ptr<llvm::TargetMachine> ModuleToObject::createTargetMachine() { 45 std::string error; 46 // Load the target. 47 const llvm::Target *target = 48 llvm::TargetRegistry::lookupTarget(triple, error); 49 if (!target) { 50 getOperation().emitError() << "Failed to lookup target: " << error; 51 return {}; 52 } 53 54 // Create the target machine using the target. 55 llvm::TargetMachine *machine = 56 target->createTargetMachine(triple, chip, features, {}, {}); 57 if (!machine) { 58 getOperation().emitError() << "Failed to create the target machine."; 59 return {}; 60 } 61 return std::unique_ptr<llvm::TargetMachine>{machine}; 62 } 63 64 std::unique_ptr<llvm::Module> 65 ModuleToObject::loadBitcodeFile(llvm::LLVMContext &context, 66 llvm::TargetMachine &targetMachine, 67 StringRef path) { 68 llvm::SMDiagnostic error; 69 std::unique_ptr<llvm::Module> library = 70 llvm::getLazyIRFileModule(path, error, context); 71 if (!library) { 72 getOperation().emitError() << "Failed loading file from " << path 73 << ", error: " << error.getMessage(); 74 return nullptr; 75 } 76 if (failed(handleBitcodeFile(*library, targetMachine))) { 77 return nullptr; 78 } 79 return library; 80 } 81 82 LogicalResult ModuleToObject::loadBitcodeFilesFromList( 83 llvm::LLVMContext &context, llvm::TargetMachine &targetMachine, 84 ArrayRef<std::string> fileList, 85 SmallVector<std::unique_ptr<llvm::Module>> &llvmModules, 86 bool failureOnError) { 87 for (const std::string &str : fileList) { 88 // Test if the path exists, if it doesn't abort. 89 StringRef pathRef = StringRef(str.data(), str.size()); 90 if (!llvm::sys::fs::is_regular_file(pathRef)) { 91 getOperation().emitError() 92 << "File path: " << pathRef << " does not exist or is not a file.\n"; 93 return failure(); 94 } 95 // Load the file or abort on error. 96 if (auto bcFile = loadBitcodeFile(context, targetMachine, pathRef)) 97 llvmModules.push_back(std::move(bcFile)); 98 else if (failureOnError) 99 return failure(); 100 } 101 return success(); 102 } 103 104 std::unique_ptr<llvm::Module> 105 ModuleToObject::translateToLLVMIR(llvm::LLVMContext &llvmContext) { 106 return translateModuleToLLVMIR(&getOperation(), llvmContext); 107 } 108 109 LogicalResult 110 ModuleToObject::linkFiles(llvm::Module &module, 111 SmallVector<std::unique_ptr<llvm::Module>> &&libs) { 112 if (libs.empty()) 113 return success(); 114 llvm::Linker linker(module); 115 for (std::unique_ptr<llvm::Module> &libModule : libs) { 116 // This bitcode linking imports the library functions into the module, 117 // allowing LLVM optimization passes (which must run after linking) to 118 // optimize across the libraries and the module's code. We also only import 119 // symbols if they are referenced by the module or a previous library since 120 // there will be no other source of references to those symbols in this 121 // compilation and since we don't want to bloat the resulting code object. 122 bool err = linker.linkInModule( 123 std::move(libModule), llvm::Linker::Flags::LinkOnlyNeeded, 124 [](llvm::Module &m, const StringSet<> &gvs) { 125 llvm::internalizeModule(m, [&gvs](const llvm::GlobalValue &gv) { 126 return !gv.hasName() || (gvs.count(gv.getName()) == 0); 127 }); 128 }); 129 // True is linker failure 130 if (err) { 131 getOperation().emitError("Unrecoverable failure during bitcode linking."); 132 // We have no guaranties about the state of `ret`, so bail 133 return failure(); 134 } 135 } 136 return success(); 137 } 138 139 LogicalResult ModuleToObject::optimizeModule(llvm::Module &module, 140 llvm::TargetMachine &targetMachine, 141 int optLevel) { 142 if (optLevel < 0 || optLevel > 3) 143 return getOperation().emitError() 144 << "Invalid optimization level: " << optLevel << "."; 145 146 targetMachine.setOptLevel(static_cast<llvm::CodeGenOptLevel>(optLevel)); 147 148 auto transformer = 149 makeOptimizingTransformer(optLevel, /*sizeLevel=*/0, &targetMachine); 150 auto error = transformer(&module); 151 if (error) { 152 InFlightDiagnostic mlirError = getOperation().emitError(); 153 llvm::handleAllErrors( 154 std::move(error), [&mlirError](const llvm::ErrorInfoBase &ei) { 155 mlirError << "Could not optimize LLVM IR: " << ei.message() << "\n"; 156 }); 157 return mlirError; 158 } 159 return success(); 160 } 161 162 std::optional<std::string> 163 ModuleToObject::translateToISA(llvm::Module &llvmModule, 164 llvm::TargetMachine &targetMachine) { 165 std::string targetISA; 166 llvm::raw_string_ostream stream(targetISA); 167 168 { // Drop pstream after this to prevent the ISA from being stuck buffering 169 llvm::buffer_ostream pstream(stream); 170 llvm::legacy::PassManager codegenPasses; 171 172 if (targetMachine.addPassesToEmitFile(codegenPasses, pstream, nullptr, 173 llvm::CodeGenFileType::AssemblyFile)) 174 return std::nullopt; 175 176 codegenPasses.run(llvmModule); 177 } 178 return stream.str(); 179 } 180 181 std::optional<SmallVector<char, 0>> 182 ModuleToObject::moduleToObject(llvm::Module &llvmModule, 183 llvm::TargetMachine &targetMachine) { 184 SmallVector<char, 0> binaryData; 185 // Write the LLVM module bitcode to a buffer. 186 llvm::raw_svector_ostream outputStream(binaryData); 187 llvm::WriteBitcodeToFile(llvmModule, outputStream); 188 return binaryData; 189 } 190 191 std::optional<SmallVector<char, 0>> ModuleToObject::run() { 192 // Translate the module to LLVM IR. 193 llvm::LLVMContext llvmContext; 194 std::unique_ptr<llvm::Module> llvmModule = translateToLLVMIR(llvmContext); 195 if (!llvmModule) { 196 getOperation().emitError() << "Failed creating the llvm::Module."; 197 return std::nullopt; 198 } 199 200 // Create the target machine. 201 std::unique_ptr<llvm::TargetMachine> targetMachine = createTargetMachine(); 202 if (!targetMachine) 203 return std::nullopt; 204 205 // Set the data layout and target triple of the module. 206 llvmModule->setDataLayout(targetMachine->createDataLayout()); 207 llvmModule->setTargetTriple(targetMachine->getTargetTriple().getTriple()); 208 209 // Link bitcode files. 210 handleModulePreLink(*llvmModule, *targetMachine); 211 { 212 auto libs = loadBitcodeFiles(*llvmModule, *targetMachine); 213 if (!libs) 214 return std::nullopt; 215 if (!libs->empty()) 216 if (failed(linkFiles(*llvmModule, std::move(*libs)))) 217 return std::nullopt; 218 handleModulePostLink(*llvmModule, *targetMachine); 219 } 220 221 // Optimize the module. 222 if (failed(optimizeModule(*llvmModule, *targetMachine, optLevel))) 223 return std::nullopt; 224 225 // Return the serialized object. 226 return moduleToObject(*llvmModule, *targetMachine); 227 } 228