1 //===- ModuleToObject.cpp - Module to object base class ---------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This file implements the base class for transforming Operations into binary
12 //===----------------------------------------------------------------------===//
14 #include "mlir/Target/LLVM/ModuleToObject.h"
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"
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"
35 using namespace mlir::LLVM
;
37 ModuleToObject::ModuleToObject(
38 Operation
&module
, StringRef triple
, StringRef chip
, StringRef features
,
39 int optLevel
, function_ref
<void(llvm::Module
&)> initialLlvmIRCallback
,
40 function_ref
<void(llvm::Module
&)> linkedLlvmIRCallback
,
41 function_ref
<void(llvm::Module
&)> optimizedLlvmIRCallback
,
42 function_ref
<void(StringRef
)> isaCallback
)
43 : module(module
), triple(triple
), chip(chip
), features(features
),
44 optLevel(optLevel
), initialLlvmIRCallback(initialLlvmIRCallback
),
45 linkedLlvmIRCallback(linkedLlvmIRCallback
),
46 optimizedLlvmIRCallback(optimizedLlvmIRCallback
),
47 isaCallback(isaCallback
) {}
49 ModuleToObject::~ModuleToObject() = default;
51 Operation
&ModuleToObject::getOperation() { return module
; }
53 std::optional
<llvm::TargetMachine
*>
54 ModuleToObject::getOrCreateTargetMachine() {
56 return targetMachine
.get();
59 const llvm::Target
*target
=
60 llvm::TargetRegistry::lookupTarget(triple
, error
);
62 getOperation().emitError()
63 << "Failed to lookup target for triple '" << triple
<< "' " << error
;
67 // Create the target machine using the target.
69 target
->createTargetMachine(triple
, chip
, features
, {}, {}));
72 return targetMachine
.get();
75 std::unique_ptr
<llvm::Module
>
76 ModuleToObject::loadBitcodeFile(llvm::LLVMContext
&context
, StringRef path
) {
77 llvm::SMDiagnostic error
;
78 std::unique_ptr
<llvm::Module
> library
=
79 llvm::getLazyIRFileModule(path
, error
, context
);
81 getOperation().emitError() << "Failed loading file from " << path
82 << ", error: " << error
.getMessage();
85 if (failed(handleBitcodeFile(*library
))) {
91 LogicalResult
ModuleToObject::loadBitcodeFilesFromList(
92 llvm::LLVMContext
&context
, ArrayRef
<std::string
> fileList
,
93 SmallVector
<std::unique_ptr
<llvm::Module
>> &llvmModules
,
94 bool failureOnError
) {
95 for (const std::string
&str
: fileList
) {
96 // Test if the path exists, if it doesn't abort.
97 StringRef pathRef
= StringRef(str
.data(), str
.size());
98 if (!llvm::sys::fs::is_regular_file(pathRef
)) {
99 getOperation().emitError()
100 << "File path: " << pathRef
<< " does not exist or is not a file.\n";
103 // Load the file or abort on error.
104 if (auto bcFile
= loadBitcodeFile(context
, pathRef
))
105 llvmModules
.push_back(std::move(bcFile
));
106 else if (failureOnError
)
112 std::unique_ptr
<llvm::Module
>
113 ModuleToObject::translateToLLVMIR(llvm::LLVMContext
&llvmContext
) {
114 return translateModuleToLLVMIR(&getOperation(), llvmContext
);
118 ModuleToObject::linkFiles(llvm::Module
&module
,
119 SmallVector
<std::unique_ptr
<llvm::Module
>> &&libs
) {
122 llvm::Linker
linker(module
);
123 for (std::unique_ptr
<llvm::Module
> &libModule
: libs
) {
124 // This bitcode linking imports the library functions into the module,
125 // allowing LLVM optimization passes (which must run after linking) to
126 // optimize across the libraries and the module's code. We also only import
127 // symbols if they are referenced by the module or a previous library since
128 // there will be no other source of references to those symbols in this
129 // compilation and since we don't want to bloat the resulting code object.
130 bool err
= linker
.linkInModule(
131 std::move(libModule
), llvm::Linker::Flags::LinkOnlyNeeded
,
132 [](llvm::Module
&m
, const StringSet
<> &gvs
) {
133 llvm::internalizeModule(m
, [&gvs
](const llvm::GlobalValue
&gv
) {
134 return !gv
.hasName() || (gvs
.count(gv
.getName()) == 0);
137 // True is linker failure
139 getOperation().emitError("Unrecoverable failure during bitcode linking.");
140 // We have no guaranties about the state of `ret`, so bail
147 LogicalResult
ModuleToObject::optimizeModule(llvm::Module
&module
,
150 if (optLevel
< 0 || optLevel
> 3)
151 return getOperation().emitError()
152 << "Invalid optimization level: " << optLevel
<< ".";
154 std::optional
<llvm::TargetMachine
*> targetMachine
=
155 getOrCreateTargetMachine();
157 return getOperation().emitError()
158 << "Target Machine unavailable for triple " << triple
159 << ", can't optimize with LLVM\n";
160 (*targetMachine
)->setOptLevel(static_cast<llvm::CodeGenOptLevel
>(optLevel
));
163 makeOptimizingTransformer(optLevel
, /*sizeLevel=*/0, *targetMachine
);
164 auto error
= transformer(&module
);
166 InFlightDiagnostic mlirError
= getOperation().emitError();
167 llvm::handleAllErrors(
168 std::move(error
), [&mlirError
](const llvm::ErrorInfoBase
&ei
) {
169 mlirError
<< "Could not optimize LLVM IR: " << ei
.message() << "\n";
176 std::optional
<std::string
>
177 ModuleToObject::translateToISA(llvm::Module
&llvmModule
,
178 llvm::TargetMachine
&targetMachine
) {
179 std::string targetISA
;
180 llvm::raw_string_ostream
stream(targetISA
);
182 { // Drop pstream after this to prevent the ISA from being stuck buffering
183 llvm::buffer_ostream
pstream(stream
);
184 llvm::legacy::PassManager codegenPasses
;
186 if (targetMachine
.addPassesToEmitFile(codegenPasses
, pstream
, nullptr,
187 llvm::CodeGenFileType::AssemblyFile
))
190 codegenPasses
.run(llvmModule
);
195 void ModuleToObject::setDataLayoutAndTriple(llvm::Module
&module
) {
196 // Create the target machine.
197 std::optional
<llvm::TargetMachine
*> targetMachine
=
198 getOrCreateTargetMachine();
200 // Set the data layout and target triple of the module.
201 module
.setDataLayout((*targetMachine
)->createDataLayout());
202 module
.setTargetTriple((*targetMachine
)->getTargetTriple().getTriple());
206 std::optional
<SmallVector
<char, 0>>
207 ModuleToObject::moduleToObject(llvm::Module
&llvmModule
) {
208 SmallVector
<char, 0> binaryData
;
209 // Write the LLVM module bitcode to a buffer.
210 llvm::raw_svector_ostream
outputStream(binaryData
);
211 llvm::WriteBitcodeToFile(llvmModule
, outputStream
);
215 std::optional
<SmallVector
<char, 0>> ModuleToObject::run() {
216 // Translate the module to LLVM IR.
217 llvm::LLVMContext llvmContext
;
218 std::unique_ptr
<llvm::Module
> llvmModule
= translateToLLVMIR(llvmContext
);
220 getOperation().emitError() << "Failed creating the llvm::Module.";
223 setDataLayoutAndTriple(*llvmModule
);
225 if (initialLlvmIRCallback
)
226 initialLlvmIRCallback(*llvmModule
);
228 // Link bitcode files.
229 handleModulePreLink(*llvmModule
);
231 auto libs
= loadBitcodeFiles(*llvmModule
);
235 if (failed(linkFiles(*llvmModule
, std::move(*libs
))))
237 handleModulePostLink(*llvmModule
);
240 if (linkedLlvmIRCallback
)
241 linkedLlvmIRCallback(*llvmModule
);
243 // Optimize the module.
244 if (failed(optimizeModule(*llvmModule
, optLevel
)))
247 if (optimizedLlvmIRCallback
)
248 optimizedLlvmIRCallback(*llvmModule
);
250 // Return the serialized object.
251 return moduleToObject(*llvmModule
);