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