MLIR  19.0.0git
ModuleToObject.cpp
Go to the documentation of this file.
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 
15 
17 #include "mlir/IR/BuiltinOps.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 
43 
45 
46 std::optional<llvm::TargetMachine *>
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) {
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 
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)) {
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 
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 
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 =
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 stream.str();
186 }
187 
188 void ModuleToObject::setDataLayoutAndTriple(llvm::Module &module) {
189  // Create the target machine.
190  std::optional<llvm::TargetMachine *> targetMachine =
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 }
This class represents a diagnostic that is inflight and set to be reported.
Definition: Diagnostics.h:308
StringRef features
Target features.
std::unique_ptr< llvm::Module > translateToLLVMIR(llvm::LLVMContext &llvmContext)
Translates the operation to LLVM IR.
virtual std::optional< SmallVector< char, 0 > > run()
Runs the serialization pipeline, returning std::nullopt on error.
static std::optional< std::string > translateToISA(llvm::Module &llvmModule, llvm::TargetMachine &targetMachine)
Utility function for translating to ISA, returns std::nullopt on failure.
virtual std::optional< SmallVector< char, 0 > > moduleToObject(llvm::Module &llvmModule)
Serializes the LLVM IR bitcode to an object file, by default it serializes to LLVM bitcode.
virtual void setDataLayoutAndTriple(llvm::Module &module)
Hook for computing the Datalayout.
virtual void handleModulePreLink(llvm::Module &module)
Hook for performing additional actions on the llvmModule pre linking.
StringRef triple
Target triple.
int optLevel
Optimization level.
ModuleToObject(Operation &module, StringRef triple, StringRef chip, StringRef features={}, int optLevel=3)
virtual LogicalResult handleBitcodeFile(llvm::Module &module)
Hook for performing additional actions on a loaded bitcode file.
std::optional< llvm::TargetMachine * > getOrCreateTargetMachine()
Create the target machine based on the target triple and chip.
Operation & getOperation()
Returns the operation being serialized.
LogicalResult loadBitcodeFilesFromList(llvm::LLVMContext &context, ArrayRef< std::string > fileList, SmallVector< std::unique_ptr< llvm::Module >> &llvmModules, bool failureOnError=true)
Loads multiple bitcode files.
virtual LogicalResult optimizeModule(llvm::Module &module, int optL)
Optimize the module.
LogicalResult linkFiles(llvm::Module &module, SmallVector< std::unique_ptr< llvm::Module >> &&libs)
Link the llvmModule to other bitcode file.
StringRef chip
Target chip.
std::unique_ptr< llvm::Module > loadBitcodeFile(llvm::LLVMContext &context, StringRef path)
Loads a bitcode file from path.
virtual std::optional< SmallVector< std::unique_ptr< llvm::Module > > > loadBitcodeFiles(llvm::Module &module)
Hook for loading bitcode files, returns std::nullopt on failure.
virtual void handleModulePostLink(llvm::Module &module)
Hook for performing additional actions on the llvmModule post linking.
Operation & module
Module to transform to a binary object.
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
Definition: Operation.cpp:268
Include the generated interface declarations.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
std::function< llvm::Error(llvm::Module *)> makeOptimizingTransformer(unsigned optLevel, unsigned sizeLevel, llvm::TargetMachine *targetMachine)
Create a module transformer function for MLIR ExecutionEngine that runs LLVM IR passes corresponding ...
std::unique_ptr< llvm::Module > translateModuleToLLVMIR(Operation *module, llvm::LLVMContext &llvmContext, llvm::StringRef name="LLVMDialectModule")
Translate operation that satisfies LLVM dialect module requirements into an LLVM IR module living in ...
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
Definition: LogicalResult.h:72
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26