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
34using namespace mlir;
35using namespace mlir::LLVM;
36
37ModuleToObject::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
42ModuleToObject::~ModuleToObject() = default;
43
44Operation &ModuleToObject::getOperation() { return module; }
45
46std::optional<llvm::TargetMachine *>
47ModuleToObject::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: triple, Error&: 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 p: target->createTargetMachine(TT: triple, CPU: chip, Features: features, Options: {}, RM: {}));
63 if (!targetMachine)
64 return std::nullopt;
65 return targetMachine.get();
66}
67
68std::unique_ptr<llvm::Module>
69ModuleToObject::loadBitcodeFile(llvm::LLVMContext &context, StringRef path) {
70 llvm::SMDiagnostic error;
71 std::unique_ptr<llvm::Module> library =
72 llvm::getLazyIRFileModule(Filename: path, Err&: error, Context&: context);
73 if (!library) {
74 getOperation().emitError() << "Failed loading file from " << path
75 << ", error: " << error.getMessage();
76 return nullptr;
77 }
78 if (failed(result: handleBitcodeFile(module&: *library))) {
79 return nullptr;
80 }
81 return library;
82}
83
84LogicalResult 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(Path: 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, path: pathRef))
98 llvmModules.push_back(Elt: std::move(bcFile));
99 else if (failureOnError)
100 return failure();
101 }
102 return success();
103}
104
105std::unique_ptr<llvm::Module>
106ModuleToObject::translateToLLVMIR(llvm::LLVMContext &llvmContext) {
107 return translateModuleToLLVMIR(module: &getOperation(), llvmContext);
108}
109
110LogicalResult
111ModuleToObject::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 Src: std::move(libModule), Flags: llvm::Linker::Flags::LinkOnlyNeeded,
125 InternalizeCallback: [](llvm::Module &m, const StringSet<> &gvs) {
126 llvm::internalizeModule(TheModule&: m, MustPreserveGV: [&gvs](const llvm::GlobalValue &gv) {
127 return !gv.hasName() || (gvs.count(Key: gv.getName()) == 0);
128 });
129 });
130 // True is linker failure
131 if (err) {
132 getOperation().emitError(message: "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
140LogicalResult 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: *targetMachine);
157 auto error = transformer(&module);
158 if (error) {
159 InFlightDiagnostic mlirError = getOperation().emitError();
160 llvm::handleAllErrors(
161 E: std::move(error), Handlers: [&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
169std::optional<std::string>
170ModuleToObject::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(M&: llvmModule);
184 }
185 return stream.str();
186}
187
188void 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
199std::optional<SmallVector<char, 0>>
200ModuleToObject::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(M: llvmModule, Out&: outputStream);
205 return binaryData;
206}
207
208std::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(module&: *llvmModule);
220 {
221 auto libs = loadBitcodeFiles(module&: *llvmModule);
222 if (!libs)
223 return std::nullopt;
224 if (!libs->empty())
225 if (failed(result: linkFiles(module&: *llvmModule, libs: std::move(*libs))))
226 return std::nullopt;
227 handleModulePostLink(module&: *llvmModule);
228 }
229
230 // Optimize the module.
231 if (failed(result: optimizeModule(module&: *llvmModule, optLevel)))
232 return std::nullopt;
233
234 // Return the serialized object.
235 return moduleToObject(llvmModule&: *llvmModule);
236}
237

source code of mlir/lib/Target/LLVM/ModuleToObject.cpp