diff --git a/mlir/examples/toy/Ch6/toyc.cpp b/mlir/examples/toy/Ch6/toyc.cpp --- a/mlir/examples/toy/Ch6/toyc.cpp +++ b/mlir/examples/toy/Ch6/toyc.cpp @@ -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" diff --git a/mlir/examples/toy/Ch7/toyc.cpp b/mlir/examples/toy/Ch7/toyc.cpp --- a/mlir/examples/toy/Ch7/toyc.cpp +++ b/mlir/examples/toy/Ch7/toyc.cpp @@ -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" diff --git a/mlir/include/mlir/Target/LLVMIR.h b/mlir/include/mlir/Target/LLVMIR.h --- a/mlir/include/mlir/Target/LLVMIR.h +++ b/mlir/include/mlir/Target/LLVMIR.h @@ -19,7 +19,6 @@ // Forward-declare LLVM classes. namespace llvm { -class LLVMContext; class Module; } // namespace llvm @@ -28,15 +27,6 @@ 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 -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 diff --git a/mlir/include/mlir/Target/LLVMIR/Export.h b/mlir/include/mlir/Target/LLVMIR/Export.h new file mode 100644 --- /dev/null +++ b/mlir/include/mlir/Target/LLVMIR/Export.h @@ -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 + +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 +translateModuleToLLVMIR(Operation *module, llvm::LLVMContext &llvmContext, + llvm::StringRef name = "LLVMDialectModule"); +} // namespace mlir + +#endif // MLIR_TARGET_LLVMIR_EXPORT_H diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h --- a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h +++ b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h @@ -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 @@ /// mappings in one class since the conversion of control flow operations /// needs to look up block and function mappings. class ModuleTranslation { -public: - template - static std::unique_ptr - translateModule(Operation *m, llvm::LLVMContext &llvmContext, - StringRef name = "LLVMDialectModule") { - if (!satisfiesLLVMModule(m)) - return nullptr; - if (failed(checkSupportedModuleOps(m))) - return nullptr; - std::unique_ptr 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(); } + friend std::unique_ptr + mlir::translateModuleToLLVMIR(Operation *, llvm::LLVMContext &, StringRef); +public: /// 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 @@ /// 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 llvmModule); - virtual ~ModuleTranslation(); - - virtual LogicalResult convertOperation(Operation &op, - llvm::IRBuilder<> &builder); - - static std::unique_ptr - 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 @@ /// Builder for LLVM IR generation of OpenMP constructs. std::unique_ptr 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 globalsMapping; diff --git a/mlir/lib/ExecutionEngine/ExecutionEngine.cpp b/mlir/lib/ExecutionEngine/ExecutionEngine.cpp --- a/mlir/lib/ExecutionEngine/ExecutionEngine.cpp +++ b/mlir/lib/ExecutionEngine/ExecutionEngine.cpp @@ -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" diff --git a/mlir/lib/Target/LLVMIR/ConvertToLLVMIR.cpp b/mlir/lib/Target/LLVMIR/ConvertToLLVMIR.cpp --- a/mlir/lib/Target/LLVMIR/ConvertToLLVMIR.cpp +++ b/mlir/lib/Target/LLVMIR/ConvertToLLVMIR.cpp @@ -35,18 +35,6 @@ using namespace mlir; -std::unique_ptr -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 ®istry) { registry.insert(); registry.addDialectInterface( - module, llvmContext, "LLVMDialectModule"); + auto llvmModule = translateModuleToLLVMIR(module, llvmContext); if (!llvmModule) return failure(); diff --git a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp --- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp @@ -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; diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp --- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp @@ -58,14 +58,9 @@ 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 &>(builder)))) { + llvm::IRBuilderBase::InsertPointGuard guard(builder); + if (failed( + moduleTranslation.convertBlock(*bb, bb->isEntryBlock(), builder))) { bodyGenStatus = failure(); return; } diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp --- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp @@ -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 @@ : mlirModule(module), llvmModule(std::move(llvmModule)), debugTranslation( std::make_unique(module, *this->llvmModule)), - ompDialect(module->getContext()->getLoadedDialect("omp")), typeTranslator(this->llvmModule->getContext()), iface(module->getContext()) { assert(satisfiesLLVMModule(mlirModule) && @@ -301,8 +302,9 @@ /// 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 @@ /// 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 @@ 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 @@ 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(&o) && !o.hasTrait()) @@ -648,8 +657,9 @@ return llvmModule->getOrInsertNamedMetadata(name); } -std::unique_ptr ModuleTranslation::prepareLLVMModule( - Operation *m, llvm::LLVMContext &llvmContext, StringRef name) { +static std::unique_ptr +prepareLLVMModule(Operation *m, llvm::LLVMContext &llvmContext, + StringRef name) { m->getContext()->getOrLoadDialect(); auto llvmModule = std::make_unique(name, llvmContext); if (auto dataLayoutAttr = @@ -669,3 +679,28 @@ return llvmModule; } + +std::unique_ptr +mlir::translateModuleToLLVMIR(Operation *module, llvm::LLVMContext &llvmContext, + StringRef name) { + if (!satisfiesLLVMModule(module)) + return nullptr; + if (failed(checkSupportedModuleOps(module))) + return nullptr; + std::unique_ptr 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); +} diff --git a/mlir/test/lib/Transforms/TestConvertGPUKernelToCubin.cpp b/mlir/test/lib/Transforms/TestConvertGPUKernelToCubin.cpp --- a/mlir/test/lib/Transforms/TestConvertGPUKernelToCubin.cpp +++ b/mlir/test/lib/Transforms/TestConvertGPUKernelToCubin.cpp @@ -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; diff --git a/mlir/test/lib/Transforms/TestConvertGPUKernelToHsaco.cpp b/mlir/test/lib/Transforms/TestConvertGPUKernelToHsaco.cpp --- a/mlir/test/lib/Transforms/TestConvertGPUKernelToHsaco.cpp +++ b/mlir/test/lib/Transforms/TestConvertGPUKernelToHsaco.cpp @@ -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; diff --git a/mlir/tools/mlir-cuda-runner/mlir-cuda-runner.cpp b/mlir/tools/mlir-cuda-runner/mlir-cuda-runner.cpp --- a/mlir/tools/mlir-cuda-runner/mlir-cuda-runner.cpp +++ b/mlir/tools/mlir-cuda-runner/mlir-cuda-runner.cpp @@ -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" diff --git a/mlir/tools/mlir-rocm-runner/mlir-rocm-runner.cpp b/mlir/tools/mlir-rocm-runner/mlir-rocm-runner.cpp --- a/mlir/tools/mlir-rocm-runner/mlir-rocm-runner.cpp +++ b/mlir/tools/mlir-rocm-runner/mlir-rocm-runner.cpp @@ -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" diff --git a/mlir/tools/mlir-spirv-cpu-runner/mlir-spirv-cpu-runner.cpp b/mlir/tools/mlir-spirv-cpu-runner/mlir-spirv-cpu-runner.cpp --- a/mlir/tools/mlir-spirv-cpu-runner/mlir-spirv-cpu-runner.cpp +++ b/mlir/tools/mlir-spirv-cpu-runner/mlir-spirv-cpu-runner.cpp @@ -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"