[mlir] Simplify ModuleTranslation for LLVM IR

A series of preceding patches changed the mechanism for translating MLIR to
LLVM IR to use dialect interface with delayed registration. It is no longer
necessary for specific dialects to derive from ModuleTranslation. Remove all
virtual methods from ModuleTranslation and factor out the entry point to be a
free function.

Also perform some cleanups in ModuleTranslation internals.

Depends On D96774

Reviewed By: nicolasvasilache

Differential Revision: https://reviews.llvm.org/D96775
This commit is contained in:
Alex Zinenko 2021-02-16 17:36:45 +01:00
parent df45c18135
commit ce8f10d6cb
15 changed files with 105 additions and 102 deletions

View File

@ -26,6 +26,7 @@
#include "mlir/Pass/Pass.h"
#include "mlir/Pass/PassManager.h"
#include "mlir/Target/LLVMIR.h"
#include "mlir/Target/LLVMIR/Export.h"
#include "mlir/Transforms/Passes.h"
#include "llvm/ADT/StringRef.h"

View File

@ -26,6 +26,7 @@
#include "mlir/Pass/Pass.h"
#include "mlir/Pass/PassManager.h"
#include "mlir/Target/LLVMIR.h"
#include "mlir/Target/LLVMIR/Export.h"
#include "mlir/Transforms/Passes.h"
#include "llvm/ADT/StringRef.h"

View File

@ -19,7 +19,6 @@
// Forward-declare LLVM classes.
namespace llvm {
class LLVMContext;
class Module;
} // namespace llvm
@ -28,15 +27,6 @@ namespace mlir {
class DialectRegistry;
class OwningModuleRef;
class MLIRContext;
class Operation;
/// Convert the given MLIR module into LLVM IR. The LLVM context is extracted
/// from the registered LLVM IR dialect. In case of error, report it
/// to the error handler registered with the MLIR context, if any (obtained from
/// the MLIR module), and return `nullptr`.
std::unique_ptr<llvm::Module>
translateModuleToLLVMIR(Operation *op, llvm::LLVMContext &llvmContext,
StringRef name = "LLVMDialectModule");
/// Convert the given LLVM module into MLIR's LLVM dialect. The LLVM context is
/// extracted from the registered LLVM IR dialect. In case of error, report it

View File

@ -0,0 +1,32 @@
//===- Export.h - MLIR to LLVM IR translation entry point -------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef MLIR_TARGET_LLVMIR_EXPORT_H
#define MLIR_TARGET_LLVMIR_EXPORT_H
#include "llvm/ADT/StringRef.h"
#include <memory>
namespace llvm {
class LLVMContext;
class Module;
} // namespace llvm
namespace mlir {
class Operation;
/// Translate operation that satisfies LLVM dialect module requirements into an
/// LLVM IR module living in the given context. This translates operations from
/// any dilalect that has a registered implementation of
/// LLVMTranslationDialectInterface.
std::unique_ptr<llvm::Module>
translateModuleToLLVMIR(Operation *module, llvm::LLVMContext &llvmContext,
llvm::StringRef name = "LLVMDialectModule");
} // namespace mlir
#endif // MLIR_TARGET_LLVMIR_EXPORT_H

View File

@ -14,27 +14,26 @@
#ifndef MLIR_TARGET_LLVMIR_MODULETRANSLATION_H
#define MLIR_TARGET_LLVMIR_MODULETRANSLATION_H
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "mlir/Dialect/LLVMIR/Transforms/LegalizeForExport.h"
#include "mlir/IR/Block.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/Operation.h"
#include "mlir/IR/Value.h"
#include "mlir/Target/LLVMIR/Export.h"
#include "mlir/Target/LLVMIR/LLVMTranslationInterface.h"
#include "mlir/Target/LLVMIR/TypeTranslation.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/MatrixBuilder.h"
#include "llvm/IR/Value.h"
namespace llvm {
class BasicBlock;
class IRBuilderBase;
class Function;
class Value;
} // namespace llvm
namespace mlir {
class Attribute;
class Block;
class Location;
class ModuleOp;
class Operation;
namespace LLVM {
@ -50,35 +49,10 @@ class LLVMFuncOp;
/// mappings in one class since the conversion of control flow operations
/// needs to look up block and function mappings.
class ModuleTranslation {
friend std::unique_ptr<llvm::Module>
mlir::translateModuleToLLVMIR(Operation *, llvm::LLVMContext &, StringRef);
public:
template <typename T = ModuleTranslation>
static std::unique_ptr<llvm::Module>
translateModule(Operation *m, llvm::LLVMContext &llvmContext,
StringRef name = "LLVMDialectModule") {
if (!satisfiesLLVMModule(m))
return nullptr;
if (failed(checkSupportedModuleOps(m)))
return nullptr;
std::unique_ptr<llvm::Module> llvmModule =
prepareLLVMModule(m, llvmContext, name);
LLVM::ensureDistinctSuccessors(m);
T translator(m, std::move(llvmModule));
if (failed(translator.convertFunctionSignatures()))
return nullptr;
if (failed(translator.convertGlobals()))
return nullptr;
if (failed(translator.convertFunctions()))
return nullptr;
return std::move(translator.llvmModule);
}
/// A helper method to get the single Block in an operation honoring LLVM's
/// module requirements.
static Block &getModuleBody(Operation *m) { return m->getRegion(0).front(); }
/// Stores the mapping between a function name and its LLVM IR representation.
void mapFunction(StringRef name, llvm::Function *func) {
auto result = functionMapping.try_emplace(name, func);
@ -175,31 +149,19 @@ public:
/// PHI nodes are constructed for block arguments but are _not_ connected to
/// the predecessors that may not exist yet.
LogicalResult convertBlock(Block &bb, bool ignoreArguments,
llvm::IRBuilder<> &builder);
llvm::IRBuilderBase &builder);
/// Gets the named metadata in the LLVM IR module being constructed, creating
/// it if it does not exist.
llvm::NamedMDNode *getOrInsertNamedModuleMetadata(StringRef name);
protected:
/// Translate the given MLIR module expressed in MLIR LLVM IR dialect into an
/// LLVM IR module. The MLIR LLVM IR dialect holds a pointer to an
/// LLVMContext, the LLVM IR module will be created in that context.
private:
ModuleTranslation(Operation *module,
std::unique_ptr<llvm::Module> llvmModule);
virtual ~ModuleTranslation();
virtual LogicalResult convertOperation(Operation &op,
llvm::IRBuilder<> &builder);
static std::unique_ptr<llvm::Module>
prepareLLVMModule(Operation *m, llvm::LLVMContext &llvmContext,
StringRef name);
private:
/// Check whether the module contains only supported ops directly in its body.
static LogicalResult checkSupportedModuleOps(Operation *m);
~ModuleTranslation();
/// Converts individual components.
LogicalResult convertOperation(Operation &op, llvm::IRBuilderBase &builder);
LogicalResult convertFunctionSignatures();
LogicalResult convertFunctions();
LogicalResult convertGlobals();
@ -217,11 +179,6 @@ private:
/// Builder for LLVM IR generation of OpenMP constructs.
std::unique_ptr<llvm::OpenMPIRBuilder> ompBuilder;
/// Precomputed pointer to OpenMP dialect. Note this can be nullptr if the
/// OpenMP dialect hasn't been loaded (it is always loaded if there are OpenMP
/// operations in the module though).
const Dialect *ompDialect;
/// Mappings between llvm.mlir.global definitions and corresponding globals.
DenseMap<Operation *, llvm::GlobalValue *> globalsMapping;

View File

@ -14,7 +14,7 @@
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/Support/FileUtilities.h"
#include "mlir/Target/LLVMIR.h"
#include "mlir/Target/LLVMIR/Export.h"
#include "llvm/ExecutionEngine/JITEventListener.h"
#include "llvm/ExecutionEngine/ObjectCache.h"

View File

@ -35,18 +35,6 @@
using namespace mlir;
std::unique_ptr<llvm::Module>
mlir::translateModuleToLLVMIR(Operation *op, llvm::LLVMContext &llvmContext,
StringRef name) {
auto llvmModule =
LLVM::ModuleTranslation::translateModule<>(op, llvmContext, name);
if (!llvmModule)
emitError(op->getLoc(), "Fail to convert MLIR to LLVM IR");
else if (verifyModule(*llvmModule))
emitError(op->getLoc(), "LLVM IR fails to verify");
return llvmModule;
}
void mlir::registerLLVMDialectTranslation(DialectRegistry &registry) {
registry.insert<LLVM::LLVMDialect>();
registry.addDialectInterface<LLVM::LLVMDialect,
@ -71,8 +59,7 @@ void registerToLLVMIRTranslation() {
"mlir-to-llvmir",
[](ModuleOp module, raw_ostream &output) {
llvm::LLVMContext llvmContext;
auto llvmModule = LLVM::ModuleTranslation::translateModule<>(
module, llvmContext, "LLVMDialectModule");
auto llvmModule = translateModuleToLLVMIR(module, llvmContext);
if (!llvmModule)
return failure();

View File

@ -19,6 +19,7 @@
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/MatrixBuilder.h"
#include "llvm/IR/Operator.h"
using namespace mlir;

View File

@ -58,14 +58,9 @@ static void convertOmpOpRegions(Region &region, StringRef blockName,
sourceTerminator->setSuccessor(0, llvmBB);
}
llvm::IRBuilder<>::InsertPointGuard guard(builder);
if (failed(moduleTranslation.convertBlock(
*bb, bb->isEntryBlock(),
// TODO: this downcast should be removed after all of
// ModuleTranslation migrated to using IRBuilderBase &; the cast is
// safe in practice because the builder always comes from
// ModuleTranslation itself that only uses this subclass.
static_cast<llvm::IRBuilder<> &>(builder)))) {
llvm::IRBuilderBase::InsertPointGuard guard(builder);
if (failed(
moduleTranslation.convertBlock(*bb, bb->isEntryBlock(), builder))) {
bodyGenStatus = failure();
return;
}

View File

@ -15,6 +15,7 @@
#include "DebugTranslation.h"
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "mlir/Dialect/LLVMIR/Transforms/LegalizeForExport.h"
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
#include "mlir/IR/Attributes.h"
#include "mlir/IR/BuiltinOps.h"
@ -37,6 +38,7 @@
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Cloning.h"
@ -192,7 +194,6 @@ ModuleTranslation::ModuleTranslation(Operation *module,
: mlirModule(module), llvmModule(std::move(llvmModule)),
debugTranslation(
std::make_unique<DebugTranslation>(module, *this->llvmModule)),
ompDialect(module->getContext()->getLoadedDialect("omp")),
typeTranslator(this->llvmModule->getContext()),
iface(module->getContext()) {
assert(satisfiesLLVMModule(mlirModule) &&
@ -301,8 +302,9 @@ llvm::Value *mlir::LLVM::detail::createIntrinsicCall(
/// Given a single MLIR operation, create the corresponding LLVM IR operation
/// using the `builder`.
LogicalResult ModuleTranslation::convertOperation(Operation &opInst,
llvm::IRBuilder<> &builder) {
LogicalResult
ModuleTranslation::convertOperation(Operation &opInst,
llvm::IRBuilderBase &builder) {
if (failed(iface.convertOperation(&opInst, builder, *this)))
return opInst.emitError("unsupported or non-LLVM operation: ")
<< opInst.getName();
@ -318,7 +320,7 @@ LogicalResult ModuleTranslation::convertOperation(Operation &opInst,
/// instructions at the end of the block and leaves `builder` in a state
/// suitable for further insertion into the end of the block.
LogicalResult ModuleTranslation::convertBlock(Block &bb, bool ignoreArguments,
llvm::IRBuilder<> &builder) {
llvm::IRBuilderBase &builder) {
builder.SetInsertPoint(lookupBlock(&bb));
auto *subprogram = builder.GetInsertBlock()->getParent()->getSubprogram();
@ -356,6 +358,12 @@ LogicalResult ModuleTranslation::convertBlock(Block &bb, bool ignoreArguments,
return success();
}
/// A helper method to get the single Block in an operation honoring LLVM's
/// module requirements.
static Block &getModuleBody(Operation *module) {
return module->getRegion(0).front();
}
/// Create named global variables that correspond to llvm.mlir.global
/// definitions.
LogicalResult ModuleTranslation::convertGlobals() {
@ -582,7 +590,8 @@ LogicalResult ModuleTranslation::convertDialectAttributes(Operation *op) {
return success();
}
LogicalResult ModuleTranslation::checkSupportedModuleOps(Operation *m) {
/// Check whether the module contains only supported ops directly in its body.
static LogicalResult checkSupportedModuleOps(Operation *m) {
for (Operation &o : getModuleBody(m).getOperations())
if (!isa<LLVM::LLVMFuncOp, LLVM::GlobalOp>(&o) &&
!o.hasTrait<OpTrait::IsTerminator>())
@ -648,8 +657,9 @@ ModuleTranslation::getOrInsertNamedModuleMetadata(StringRef name) {
return llvmModule->getOrInsertNamedMetadata(name);
}
std::unique_ptr<llvm::Module> ModuleTranslation::prepareLLVMModule(
Operation *m, llvm::LLVMContext &llvmContext, StringRef name) {
static std::unique_ptr<llvm::Module>
prepareLLVMModule(Operation *m, llvm::LLVMContext &llvmContext,
StringRef name) {
m->getContext()->getOrLoadDialect<LLVM::LLVMDialect>();
auto llvmModule = std::make_unique<llvm::Module>(name, llvmContext);
if (auto dataLayoutAttr =
@ -669,3 +679,28 @@ std::unique_ptr<llvm::Module> ModuleTranslation::prepareLLVMModule(
return llvmModule;
}
std::unique_ptr<llvm::Module>
mlir::translateModuleToLLVMIR(Operation *module, llvm::LLVMContext &llvmContext,
StringRef name) {
if (!satisfiesLLVMModule(module))
return nullptr;
if (failed(checkSupportedModuleOps(module)))
return nullptr;
std::unique_ptr<llvm::Module> llvmModule =
prepareLLVMModule(module, llvmContext, name);
LLVM::ensureDistinctSuccessors(module);
ModuleTranslation translator(module, std::move(llvmModule));
if (failed(translator.convertFunctionSignatures()))
return nullptr;
if (failed(translator.convertGlobals()))
return nullptr;
if (failed(translator.convertFunctions()))
return nullptr;
if (llvm::verifyModule(*translator.llvmModule, &llvm::errs()))
return nullptr;
return std::move(translator.llvmModule);
}

View File

@ -12,6 +12,7 @@
#include "mlir/Pass/PassManager.h"
#include "mlir/Target/LLVMIR.h"
#include "mlir/Target/LLVMIR/Dialect/NVVM/NVVMToLLVMIRTranslation.h"
#include "mlir/Target/LLVMIR/Export.h"
#include "llvm/Support/TargetSelect.h"
using namespace mlir;

View File

@ -12,6 +12,7 @@
#include "mlir/Pass/PassManager.h"
#include "mlir/Target/LLVMIR.h"
#include "mlir/Target/LLVMIR/Dialect/ROCDL/ROCDLToLLVMIRTranslation.h"
#include "mlir/Target/LLVMIR/Export.h"
#include "llvm/Support/TargetSelect.h"
using namespace mlir;

View File

@ -33,6 +33,7 @@
#include "mlir/Pass/PassManager.h"
#include "mlir/Target/LLVMIR.h"
#include "mlir/Target/LLVMIR/Dialect/NVVM/NVVMToLLVMIRTranslation.h"
#include "mlir/Target/LLVMIR/Export.h"
#include "mlir/Transforms/DialectConversion.h"
#include "mlir/Transforms/Passes.h"

View File

@ -32,7 +32,7 @@
#include "mlir/Support/FileUtilities.h"
#include "mlir/Target/LLVMIR.h"
#include "mlir/Target/LLVMIR/Dialect/ROCDL/ROCDLToLLVMIRTranslation.h"
#include "mlir/Target/ROCDLIR.h"
#include "mlir/Target/LLVMIR/Export.h"
#include "mlir/Transforms/DialectConversion.h"
#include "mlir/Transforms/Passes.h"
#include "llvm/Support/ErrorOr.h"

View File

@ -27,6 +27,7 @@
#include "mlir/Pass/Pass.h"
#include "mlir/Pass/PassManager.h"
#include "mlir/Target/LLVMIR.h"
#include "mlir/Target/LLVMIR/Export.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"