brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.0 KiB · 4098ccc Raw
285 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the base class for transforming Operations into binary10// 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/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/MemoryBuffer.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(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) {}48 49ModuleToObject::~ModuleToObject() = default;50 51Operation &ModuleToObject::getOperation() { return module; }52 53std::optional<llvm::TargetMachine *>54ModuleToObject::getOrCreateTargetMachine() {55  if (targetMachine)56    return targetMachine.get();57  // Load the target.58  std::string error;59  llvm::Triple parsedTriple(triple);60  const llvm::Target *target =61      llvm::TargetRegistry::lookupTarget(parsedTriple, error);62  if (!target) {63    getOperation().emitError()64        << "Failed to lookup target for triple '" << triple << "' " << error;65    return std::nullopt;66  }67 68  // Create the target machine using the target.69  targetMachine.reset(70      target->createTargetMachine(parsedTriple, chip, features, {}, {}));71  if (!targetMachine)72    return std::nullopt;73  return targetMachine.get();74}75 76std::unique_ptr<llvm::Module>77ModuleToObject::loadBitcodeFile(llvm::LLVMContext &context, StringRef path) {78  llvm::SMDiagnostic error;79  std::unique_ptr<llvm::Module> library =80      llvm::getLazyIRFileModule(path, error, context);81  if (!library) {82    getOperation().emitError() << "Failed loading file from " << path83                               << ", error: " << error.getMessage();84    return nullptr;85  }86  if (failed(handleBitcodeFile(*library))) {87    return nullptr;88  }89  return library;90}91 92LogicalResult ModuleToObject::loadBitcodeFilesFromList(93    llvm::LLVMContext &context, ArrayRef<Attribute> librariesToLink,94    SmallVector<std::unique_ptr<llvm::Module>> &llvmModules,95    bool failureOnError) {96  for (Attribute linkLib : librariesToLink) {97    // Attributes in this list can be either list of file paths using98    // StringAttr, or a resource attribute pointing to the LLVM bitcode in99    // memory.100    if (auto filePath = dyn_cast<StringAttr>(linkLib)) {101      // Test if the path exists, if it doesn't abort.102      if (!llvm::sys::fs::is_regular_file(filePath.strref())) {103        getOperation().emitError()104            << "File path: " << filePath << " does not exist or is not a file.";105        return failure();106      }107      // Load the file or abort on error.108      if (auto bcFile = loadBitcodeFile(context, filePath))109        llvmModules.push_back(std::move(bcFile));110      else if (failureOnError)111        return failure();112      continue;113    }114    if (auto blobAttr = dyn_cast<BlobAttr>(linkLib)) {115      // Load the file or abort on error.116      llvm::SMDiagnostic error;117      ArrayRef<char> data = blobAttr.getData();118      std::unique_ptr<llvm::MemoryBuffer> buffer =119          llvm::MemoryBuffer::getMemBuffer(StringRef(data.data(), data.size()),120                                           "blobLinkedLib",121                                           /*RequiresNullTerminator=*/false);122      std::unique_ptr<llvm::Module> mod =123          getLazyIRModule(std::move(buffer), error, context);124      if (mod) {125        if (failed(handleBitcodeFile(*mod)))126          return failure();127        llvmModules.push_back(std::move(mod));128      } else if (failureOnError) {129        getOperation().emitError()130            << "Couldn't load LLVM library for linking: " << error.getMessage();131        return failure();132      }133      continue;134    }135    if (failureOnError) {136      getOperation().emitError()137          << "Unknown attribute describing LLVM library to load: " << linkLib;138      return failure();139    }140  }141  return success();142}143 144std::unique_ptr<llvm::Module>145ModuleToObject::translateToLLVMIR(llvm::LLVMContext &llvmContext) {146  return translateModuleToLLVMIR(&getOperation(), llvmContext);147}148 149LogicalResult150ModuleToObject::linkFiles(llvm::Module &module,151                          SmallVector<std::unique_ptr<llvm::Module>> &&libs) {152  if (libs.empty())153    return success();154  llvm::Linker linker(module);155  for (std::unique_ptr<llvm::Module> &libModule : libs) {156    // This bitcode linking imports the library functions into the module,157    // allowing LLVM optimization passes (which must run after linking) to158    // optimize across the libraries and the module's code. We also only import159    // symbols if they are referenced by the module or a previous library since160    // there will be no other source of references to those symbols in this161    // compilation and since we don't want to bloat the resulting code object.162    bool err = linker.linkInModule(163        std::move(libModule), llvm::Linker::Flags::LinkOnlyNeeded,164        [](llvm::Module &m, const StringSet<> &gvs) {165          llvm::internalizeModule(m, [&gvs](const llvm::GlobalValue &gv) {166            return !gv.hasName() || (gvs.count(gv.getName()) == 0);167          });168        });169    // True is linker failure170    if (err) {171      getOperation().emitError("Unrecoverable failure during bitcode linking.");172      // We have no guaranties about the state of `ret`, so bail173      return failure();174    }175  }176  return success();177}178 179LogicalResult ModuleToObject::optimizeModule(llvm::Module &module,180 181                                             int optLevel) {182  if (optLevel < 0 || optLevel > 3)183    return getOperation().emitError()184           << "Invalid optimization level: " << optLevel << ".";185 186  std::optional<llvm::TargetMachine *> targetMachine =187      getOrCreateTargetMachine();188  if (!targetMachine)189    return getOperation().emitError()190           << "Target Machine unavailable for triple " << triple191           << ", can't optimize with LLVM\n";192  (*targetMachine)->setOptLevel(static_cast<llvm::CodeGenOptLevel>(optLevel));193 194  auto transformer =195      makeOptimizingTransformer(optLevel, /*sizeLevel=*/0, *targetMachine);196  auto error = transformer(&module);197  if (error) {198    InFlightDiagnostic mlirError = getOperation().emitError();199    llvm::handleAllErrors(200        std::move(error), [&mlirError](const llvm::ErrorInfoBase &ei) {201          mlirError << "Could not optimize LLVM IR: " << ei.message() << "\n";202        });203    return mlirError;204  }205  return success();206}207 208std::optional<std::string>209ModuleToObject::translateToISA(llvm::Module &llvmModule,210                               llvm::TargetMachine &targetMachine) {211  std::string targetISA;212  llvm::raw_string_ostream stream(targetISA);213 214  { // Drop pstream after this to prevent the ISA from being stuck buffering215    llvm::buffer_ostream pstream(stream);216    llvm::legacy::PassManager codegenPasses;217 218    if (targetMachine.addPassesToEmitFile(codegenPasses, pstream, nullptr,219                                          llvm::CodeGenFileType::AssemblyFile))220      return std::nullopt;221 222    codegenPasses.run(llvmModule);223  }224  return targetISA;225}226 227void ModuleToObject::setDataLayoutAndTriple(llvm::Module &module) {228  // Create the target machine.229  std::optional<llvm::TargetMachine *> targetMachine =230      getOrCreateTargetMachine();231  if (targetMachine) {232    // Set the data layout and target triple of the module.233    module.setDataLayout((*targetMachine)->createDataLayout());234    module.setTargetTriple((*targetMachine)->getTargetTriple());235  }236}237 238std::optional<SmallVector<char, 0>>239ModuleToObject::moduleToObject(llvm::Module &llvmModule) {240  SmallVector<char, 0> binaryData;241  // Write the LLVM module bitcode to a buffer.242  llvm::raw_svector_ostream outputStream(binaryData);243  llvm::WriteBitcodeToFile(llvmModule, outputStream);244  return binaryData;245}246 247std::optional<SmallVector<char, 0>> ModuleToObject::run() {248  // Translate the module to LLVM IR.249  llvm::LLVMContext llvmContext;250  std::unique_ptr<llvm::Module> llvmModule = translateToLLVMIR(llvmContext);251  if (!llvmModule) {252    getOperation().emitError() << "Failed creating the llvm::Module.";253    return std::nullopt;254  }255  setDataLayoutAndTriple(*llvmModule);256 257  if (initialLlvmIRCallback)258    initialLlvmIRCallback(*llvmModule);259 260  // Link bitcode files.261  handleModulePreLink(*llvmModule);262  {263    auto libs = loadBitcodeFiles(*llvmModule);264    if (!libs)265      return std::nullopt;266    if (!libs->empty())267      if (failed(linkFiles(*llvmModule, std::move(*libs))))268        return std::nullopt;269    handleModulePostLink(*llvmModule);270  }271 272  if (linkedLlvmIRCallback)273    linkedLlvmIRCallback(*llvmModule);274 275  // Optimize the module.276  if (failed(optimizeModule(*llvmModule, optLevel)))277    return std::nullopt;278 279  if (optimizedLlvmIRCallback)280    optimizedLlvmIRCallback(*llvmModule);281 282  // Return the serialized object.283  return moduleToObject(*llvmModule);284}285