diff --git a/mlir/include/mlir/Conversion/StandardToLLVM/ConvertStandardToLLVMPass.h b/mlir/include/mlir/Conversion/StandardToLLVM/ConvertStandardToLLVMPass.h --- a/mlir/include/mlir/Conversion/StandardToLLVM/ConvertStandardToLLVMPass.h +++ b/mlir/include/mlir/Conversion/StandardToLLVM/ConvertStandardToLLVMPass.h @@ -61,15 +61,6 @@ createLowerToLLVMPass(bool useAlloca = false, bool useBarePtrCallConv = false, bool emitCWrappers = false); -namespace LLVM { -/// Make argument-taking successors of each block distinct. PHI nodes in LLVM -/// IR use the predecessor ID to identify which value to take. They do not -/// support different values coming from the same predecessor. If a block has -/// another block as a successor more than once with different values, insert -/// a new dummy block for LLVM PHI nodes to tell the sources apart. -void ensureDistinctSuccessors(ModuleOp m); -} // namespace LLVM - } // namespace mlir #endif // MLIR_CONVERSION_STANDARDTOLLVM_CONVERTSTANDARDTOLLVMPASS_H_ diff --git a/mlir/include/mlir/Dialect/LLVMIR/Transforms/Legalize.h b/mlir/include/mlir/Dialect/LLVMIR/Transforms/Legalize.h new file mode 100644 --- /dev/null +++ b/mlir/include/mlir/Dialect/LLVMIR/Transforms/Legalize.h @@ -0,0 +1,29 @@ +//===- Legalize.h - Make the LLVM dialect convertible to LLVM IR-*- 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 +// +//===----------------------------------------------------------------------===// + +#include + +namespace mlir { +class Operation; +class Pass; + +namespace LLVM { + +/// Make argument-taking successors of each block distinct. PHI nodes in LLVM +/// IR use the predecessor ID to identify which value to take. They do not +/// support different values coming from the same predecessor. If a block has +/// another block as a successor more than once with different values, insert +/// a new dummy block for LLVM PHI nodes to tell the sources apart. +void ensureDistinctSuccessors(Operation *op); + +/// Creates a pass that legalizes the LLVM dialect operations so that they can +/// be translated to LLVM IR. +std::unique_ptr createLegalizePass(); + +} // namespace LLVM +} // namespace mlir diff --git a/mlir/include/mlir/InitAllPasses.h b/mlir/include/mlir/InitAllPasses.h --- a/mlir/include/mlir/InitAllPasses.h +++ b/mlir/include/mlir/InitAllPasses.h @@ -26,6 +26,7 @@ #include "mlir/Conversion/StandardToSPIRV/ConvertStandardToSPIRVPass.h" #include "mlir/Dialect/FxpMathOps/Passes.h" #include "mlir/Dialect/GPU/Passes.h" +#include "mlir/Dialect/LLVMIR/Transforms/Legalize.h" #include "mlir/Dialect/Linalg/Passes.h" #include "mlir/Dialect/LoopOps/Passes.h" #include "mlir/Dialect/QuantOps/Passes.h" @@ -107,6 +108,9 @@ createConvertLinalgToAffineLoopsPass(); createConvertLinalgToLLVMPass(); + // LLVM + LLVM::createLegalizePass(); + // LoopOps createParallelLoopFusionPass(); createParallelLoopSpecializationPass(); 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 @@ -15,6 +15,7 @@ #define MLIR_TARGET_LLVMIR_MODULETRANSLATION_H #include "mlir/Dialect/LLVMIR/LLVMDialect.h" +#include "mlir/Dialect/LLVMIR/Transforms/Legalize.h" #include "mlir/IR/Block.h" #include "mlir/IR/Module.h" #include "mlir/IR/Value.h" @@ -55,6 +56,8 @@ if (!llvmModule) return nullptr; + LLVM::ensureDistinctSuccessors(m); + T translator(m, std::move(llvmModule)); translator.convertGlobals(); if (failed(translator.convertFunctions())) diff --git a/mlir/lib/Conversion/StandardToLLVM/ConvertStandardToLLVM.cpp b/mlir/lib/Conversion/StandardToLLVM/ConvertStandardToLLVM.cpp --- a/mlir/lib/Conversion/StandardToLLVM/ConvertStandardToLLVM.cpp +++ b/mlir/lib/Conversion/StandardToLLVM/ConvertStandardToLLVM.cpp @@ -2721,53 +2721,6 @@ } // namespace -static void ensureDistinctSuccessors(Block &bb) { - auto *terminator = bb.getTerminator(); - - // Find repeated successors with arguments. - llvm::SmallDenseMap> successorPositions; - for (int i = 0, e = terminator->getNumSuccessors(); i < e; ++i) { - Block *successor = terminator->getSuccessor(i); - // Blocks with no arguments are safe even if they appear multiple times - // because they don't need PHI nodes. - if (successor->getNumArguments() == 0) - continue; - successorPositions[successor].push_back(i); - } - - // If a successor appears for the second or more time in the terminator, - // create a new dummy block that unconditionally branches to the original - // destination, and retarget the terminator to branch to this new block. - // There is no need to pass arguments to the dummy block because it will be - // dominated by the original block and can therefore use any values defined in - // the original block. - for (const auto &successor : successorPositions) { - const auto &positions = successor.second; - // Start from the second occurrence of a block in the successor list. - for (auto position = std::next(positions.begin()), end = positions.end(); - position != end; ++position) { - auto *dummyBlock = new Block(); - bb.getParent()->push_back(dummyBlock); - auto builder = OpBuilder(dummyBlock); - SmallVector operands( - terminator->getSuccessorOperands(*position)); - builder.create(terminator->getLoc(), successor.first, operands); - terminator->setSuccessor(dummyBlock, *position); - for (int i = 0, e = terminator->getNumSuccessorOperands(*position); i < e; - ++i) - terminator->eraseSuccessorOperand(*position, i); - } - } -} - -void mlir::LLVM::ensureDistinctSuccessors(ModuleOp m) { - for (auto f : m.getOps()) { - for (auto &bb : f.getBlocks()) { - ::ensureDistinctSuccessors(bb); - } - } -} - /// Collect a set of patterns to convert from the Standard dialect to LLVM. void mlir::populateStdToLLVMNonMemoryConversionPatterns( LLVMTypeConverter &converter, OwningRewritePatternList &patterns) { @@ -2963,7 +2916,6 @@ } ModuleOp m = getModule(); - LLVM::ensureDistinctSuccessors(m); LLVMTypeConverterCustomization customs; customs.funcArgConverter = useBarePtrCallConv ? barePtrFuncArgTypeConverter diff --git a/mlir/lib/Dialect/LLVMIR/CMakeLists.txt b/mlir/lib/Dialect/LLVMIR/CMakeLists.txt --- a/mlir/lib/Dialect/LLVMIR/CMakeLists.txt +++ b/mlir/lib/Dialect/LLVMIR/CMakeLists.txt @@ -1,3 +1,5 @@ +add_subdirectory(Transforms) + add_mlir_dialect_library(MLIRLLVMIR IR/LLVMDialect.cpp diff --git a/mlir/lib/Dialect/LLVMIR/Transforms/CMakeLists.txt b/mlir/lib/Dialect/LLVMIR/Transforms/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/mlir/lib/Dialect/LLVMIR/Transforms/CMakeLists.txt @@ -0,0 +1,9 @@ +add_mlir_dialect_library(MLIRLLVMIRTransforms + Legalize.cpp + ) + +target_link_libraries(MLIRLLVMIRTransforms + MLIRIR + MLIRLLVMIR + MLIRPass + ) diff --git a/mlir/lib/Dialect/LLVMIR/Transforms/Legalize.cpp b/mlir/lib/Dialect/LLVMIR/Transforms/Legalize.cpp new file mode 100644 --- /dev/null +++ b/mlir/lib/Dialect/LLVMIR/Transforms/Legalize.cpp @@ -0,0 +1,79 @@ +//===- Legalize.cpp - Make the LLVM dialect convertible to LLVM IR --------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "mlir/Dialect/LLVMIR/Transforms/Legalize.h" +#include "mlir/Dialect/LLVMIR/LLVMDialect.h" +#include "mlir/IR/Block.h" +#include "mlir/IR/Builders.h" +#include "mlir/IR/Module.h" +#include "mlir/Pass/Pass.h" + +using namespace mlir; + +static void ensureDistinctSuccessors(Block &bb) { + auto *terminator = bb.getTerminator(); + + // Find repeated successors with arguments. + llvm::SmallDenseMap> successorPositions; + for (int i = 0, e = terminator->getNumSuccessors(); i < e; ++i) { + Block *successor = terminator->getSuccessor(i); + // Blocks with no arguments are safe even if they appear multiple times + // because they don't need PHI nodes. + if (successor->getNumArguments() == 0) + continue; + successorPositions[successor].push_back(i); + } + + // If a successor appears for the second or more time in the terminator, + // create a new dummy block that unconditionally branches to the original + // destination, and retarget the terminator to branch to this new block. + // There is no need to pass arguments to the dummy block because it will be + // dominated by the original block and can therefore use any values defined in + // the original block. + for (const auto &successor : successorPositions) { + const auto &positions = successor.second; + // Start from the second occurrence of a block in the successor list. + for (auto position = std::next(positions.begin()), end = positions.end(); + position != end; ++position) { + auto *dummyBlock = new Block(); + bb.getParent()->push_back(dummyBlock); + auto builder = OpBuilder(dummyBlock); + SmallVector operands( + terminator->getSuccessorOperands(*position)); + builder.create(terminator->getLoc(), successor.first, + operands); + terminator->setSuccessor(dummyBlock, *position); + for (int i = 0, e = terminator->getNumSuccessorOperands(*position); i < e; + ++i) + terminator->eraseSuccessorOperand(*position, i); + } + } +} + +void mlir::LLVM::ensureDistinctSuccessors(Operation *op) { + op->walk([](LLVMFuncOp f) { + for (auto &bb : f.getBlocks()) { + ::ensureDistinctSuccessors(bb); + } + }); +} + +namespace { +struct LLVMLegalizePass : public OperationPass { + void runOnOperation() override { + LLVM::ensureDistinctSuccessors(getOperation()); + } +}; +} // end namespace + +std::unique_ptr LLVM::createLegalizePass() { + return std::make_unique(); +} + +static PassRegistration + pass("llvm-legalize", "Legalize LLVM dialect to be convertible to LLVM IR");