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
37using namespace mlir;
38using namespace mlir::LLVM;
39
40ModuleToObject::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
52ModuleToObject::~ModuleToObject() = default;
53
54Operation &ModuleToObject::getOperation() { return module; }
55
56std::optional<llvm::TargetMachine *>
57ModuleToObject::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(TripleStr: triple, Error&: 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(p: target->createTargetMachine(TT: llvm::Triple(triple), CPU: chip,
72 Features: features, Options: {}, RM: {}));
73 if (!targetMachine)
74 return std::nullopt;
75 return targetMachine.get();
76}
77
78std::unique_ptr<llvm::Module>
79ModuleToObject::loadBitcodeFile(llvm::LLVMContext &context, StringRef path) {
80 llvm::SMDiagnostic error;
81 std::unique_ptr<llvm::Module> library =
82 llvm::getLazyIRFileModule(Filename: path, Err&: error, Context&: context);
83 if (!library) {
84 getOperation().emitError() << "Failed loading file from " << path
85 << ", error: " << error.getMessage();
86 return nullptr;
87 }
88 if (failed(Result: handleBitcodeFile(module&: *library))) {
89 return nullptr;
90 }
91 return library;
92}
93
94LogicalResult 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(InputData: StringRef(data.data(), data.size()),
122 BufferName: "blobLinkedLib",
123 /*RequiresNullTerminator=*/false);
124 std::unique_ptr<llvm::Module> mod =
125 getLazyIRModule(Buffer: std::move(buffer), Err&: error, Context&: context);
126 if (mod) {
127 if (failed(Result: handleBitcodeFile(module&: *mod)))
128 return failure();
129 llvmModules.push_back(Elt: 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
146std::unique_ptr<llvm::Module>
147ModuleToObject::translateToLLVMIR(llvm::LLVMContext &llvmContext) {
148 return translateModuleToLLVMIR(module: &getOperation(), llvmContext);
149}
150
151LogicalResult
152ModuleToObject::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 Src: std::move(libModule), Flags: llvm::Linker::Flags::LinkOnlyNeeded,
166 InternalizeCallback: [](llvm::Module &m, const StringSet<> &gvs) {
167 llvm::internalizeModule(TheModule&: m, MustPreserveGV: [&gvs](const llvm::GlobalValue &gv) {
168 return !gv.hasName() || (gvs.count(Key: gv.getName()) == 0);
169 });
170 });
171 // True is linker failure
172 if (err) {
173 getOperation().emitError(message: "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
181LogicalResult 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: *targetMachine);
198 auto error = transformer(&module);
199 if (error) {
200 InFlightDiagnostic mlirError = getOperation().emitError();
201 llvm::handleAllErrors(
202 E: std::move(error), Handlers: [&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
210std::optional<std::string>
211ModuleToObject::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(M&: llvmModule);
225 }
226 return targetISA;
227}
228
229void 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());
237 }
238}
239
240std::optional<SmallVector<char, 0>>
241ModuleToObject::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(M: llvmModule, Out&: outputStream);
246 return binaryData;
247}
248
249std::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(module&: *llvmModule);
264 {
265 auto libs = loadBitcodeFiles(module&: *llvmModule);
266 if (!libs)
267 return std::nullopt;
268 if (!libs->empty())
269 if (failed(Result: linkFiles(module&: *llvmModule, libs: std::move(*libs))))
270 return std::nullopt;
271 handleModulePostLink(module&: *llvmModule);
272 }
273
274 if (linkedLlvmIRCallback)
275 linkedLlvmIRCallback(*llvmModule);
276
277 // Optimize the module.
278 if (failed(Result: optimizeModule(module&: *llvmModule, optLevel)))
279 return std::nullopt;
280
281 if (optimizedLlvmIRCallback)
282 optimizedLlvmIRCallback(*llvmModule);
283
284 // Return the serialized object.
285 return moduleToObject(llvmModule&: *llvmModule);
286}
287

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

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