Author: Andy Kaylor Date: 2025-03-11T15:47:02-07:00 New Revision: 701148f05a7b90ed6b8c4fc38db4c2b0c9241ffc
URL: https://github.com/llvm/llvm-project/commit/701148f05a7b90ed6b8c4fc38db4c2b0c9241ffc DIFF: https://github.com/llvm/llvm-project/commit/701148f05a7b90ed6b8c4fc38db4c2b0c9241ffc.diff LOG: [CIR] Upstream initial support for CIR flattening (#130648) The ClangIR CFG has to be flat before it can be lowered to LLVM IR. That is, there can be no nested regions and all blocks in a region must belong to the parent region. Currently only cir.scope operations violate these rules, so the initial implementation of the cir-flatten-cfg pass only has to transform scope operations. Added: clang/include/clang/CIR/Dialect/Passes.h clang/include/clang/CIR/Dialect/Passes.td clang/lib/CIR/Dialect/Transforms/CMakeLists.txt clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp clang/lib/CIR/Dialect/Transforms/PassDetail.h clang/lib/CIR/Lowering/CIRPasses.cpp clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVMIR.cpp Modified: clang/include/clang/CIR/Dialect/CMakeLists.txt clang/include/clang/CIR/Dialect/IR/CIROps.td clang/include/clang/CIR/MissingFeatures.h clang/lib/CIR/Dialect/CMakeLists.txt clang/lib/CIR/Dialect/IR/CIRDialect.cpp clang/lib/CIR/Dialect/IR/CMakeLists.txt clang/lib/CIR/Lowering/CMakeLists.txt clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h clang/test/CIR/Lowering/func-simple.cpp Removed: ################################################################################ diff --git a/clang/include/clang/CIR/Dialect/CMakeLists.txt b/clang/include/clang/CIR/Dialect/CMakeLists.txt index f33061b2d87cf..3d4e6586e1c62 100644 --- a/clang/include/clang/CIR/Dialect/CMakeLists.txt +++ b/clang/include/clang/CIR/Dialect/CMakeLists.txt @@ -1 +1,7 @@ add_subdirectory(IR) + +set(LLVM_TARGET_DEFINITIONS Passes.td) +mlir_tablegen(Passes.h.inc -gen-pass-decls -name CIR) +mlir_tablegen(Passes.capi.h.inc -gen-pass-capi-header --prefix CIR) +mlir_tablegen(Passes.capi.cpp.inc -gen-pass-capi-impl --prefix CIR) +add_public_tablegen_target(MLIRCIRPassIncGen) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index e2ab50c78ec2d..77c43e5ace64a 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -428,6 +428,46 @@ def ScopeOp : CIR_Op<"scope", [ ]; } +//===----------------------------------------------------------------------===// +// BrOp +//===----------------------------------------------------------------------===// + +def BrOp : CIR_Op<"br", + [DeclareOpInterfaceMethods<BranchOpInterface, ["getSuccessorForOperands"]>, + Pure, Terminator]> { + let summary = "Unconditional branch"; + let description = [{ + The `cir.br` branches unconditionally to a block. Used to represent C/C++ + goto's and general block branching. + + Note that for source level `goto`'s crossing scope boundaries, those are + usually represented with the "symbolic" `cir.goto` operation. + + Example: + + ```mlir + ... + cir.br ^bb3 + ^bb3: + cir.return + ``` + }]; + + let builders = [ + OpBuilder<(ins "mlir::Block *":$dest, + CArg<"mlir::ValueRange", "{}">:$destOperands), [{ + $_state.addSuccessors(dest); + $_state.addOperands(destOperands); + }]> + ]; + + let arguments = (ins Variadic<CIR_AnyType>:$destOperands); + let successors = (successor AnySuccessor:$dest); + let assemblyFormat = [{ + $dest (`(` $destOperands^ `:` type($destOperands) `)`)? attr-dict + }]; +} + //===----------------------------------------------------------------------===// // GlobalOp //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/Dialect/Passes.h b/clang/include/clang/CIR/Dialect/Passes.h new file mode 100644 index 0000000000000..b691849dfc563 --- /dev/null +++ b/clang/include/clang/CIR/Dialect/Passes.h @@ -0,0 +1,39 @@ +//===- Passes.h - CIR pass entry points -------------------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This header file defines prototypes that expose pass constructors. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_CIR_DIALECT_PASSES_H +#define CLANG_CIR_DIALECT_PASSES_H + +#include "mlir/Pass/Pass.h" + +namespace clang { +class ASTContext; +} +namespace mlir { + +std::unique_ptr<Pass> createCIRFlattenCFGPass(); + +void populateCIRPreLoweringPasses(mlir::OpPassManager &pm); + +//===----------------------------------------------------------------------===// +// Registration +//===----------------------------------------------------------------------===// + +void registerCIRDialectTranslation(mlir::MLIRContext &context); + +/// Generate the code for registering passes. +#define GEN_PASS_REGISTRATION +#include "clang/CIR/Dialect/Passes.h.inc" + +} // namespace mlir + +#endif // CLANG_CIR_DIALECT_PASSES_H diff --git a/clang/include/clang/CIR/Dialect/Passes.td b/clang/include/clang/CIR/Dialect/Passes.td new file mode 100644 index 0000000000000..84b7ecba2630a --- /dev/null +++ b/clang/include/clang/CIR/Dialect/Passes.td @@ -0,0 +1,28 @@ +//===----------------------------------------------------------------------===// +// +// 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 CLANG_CIR_DIALECT_PASSES_TD +#define CLANG_CIR_DIALECT_PASSES_TD + +include "mlir/Pass/PassBase.td" + +def CIRFlattenCFG : Pass<"cir-flatten-cfg"> { + let summary = "Produces flatten CFG"; + let description = [{ + This pass transforms CIR by inlining all the nested regions. Thus, + the following conditions are true after the pass applied: + - there are no nested regions in any function body + - all the blocks in a function belong to the parent region + In other words, this pass removes such CIR operations like IfOp, LoopOp, + ScopeOp and etc. and produces a flat CIR. + }]; + let constructor = "mlir::createCIRFlattenCFGPass()"; + let dependentDialects = ["cir::CIRDialect"]; +} + +#endif // CLANG_CIR_DIALECT_PASSES_TD diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index d20cd0560a7c1..ddfe654009644 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -82,6 +82,7 @@ struct MissingFeatures { static bool objCLifetime() { return false; } static bool emitNullabilityCheck() { return false; } static bool astVarDeclInterface() { return false; } + static bool stackSaveOp() { return false; } }; } // namespace cir diff --git a/clang/lib/CIR/Dialect/CMakeLists.txt b/clang/lib/CIR/Dialect/CMakeLists.txt index f33061b2d87cf..9f57627c321fb 100644 --- a/clang/lib/CIR/Dialect/CMakeLists.txt +++ b/clang/lib/CIR/Dialect/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(IR) +add_subdirectory(Transforms) diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 5ad369b40cda1..d041791770d82 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -268,6 +268,19 @@ LogicalResult cir::ScopeOp::verify() { return success(); } +//===----------------------------------------------------------------------===// +// BrOp +//===----------------------------------------------------------------------===// + +mlir::SuccessorOperands cir::BrOp::getSuccessorOperands(unsigned index) { + assert(index == 0 && "invalid successor index"); + return mlir::SuccessorOperands(getDestOperandsMutable()); +} + +Block *cir::BrOp::getSuccessorForOperands(ArrayRef<Attribute>) { + return getDest(); +} + //===----------------------------------------------------------------------===// // GlobalOp //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/IR/CMakeLists.txt b/clang/lib/CIR/Dialect/IR/CMakeLists.txt index e3a6fc6e80ecc..aa5ea52a5e93f 100644 --- a/clang/lib/CIR/Dialect/IR/CMakeLists.txt +++ b/clang/lib/CIR/Dialect/IR/CMakeLists.txt @@ -11,6 +11,7 @@ add_clang_library(MLIRCIR LINK_LIBS PUBLIC MLIRIR + MLIRCIRInterfaces MLIRDLTIDialect MLIRDataLayoutInterfaces MLIRFuncDialect diff --git a/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt b/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt new file mode 100644 index 0000000000000..aa27074cc6131 --- /dev/null +++ b/clang/lib/CIR/Dialect/Transforms/CMakeLists.txt @@ -0,0 +1,18 @@ +add_clang_library(MLIRCIRTransforms + FlattenCFG.cpp + + DEPENDS + MLIRCIRPassIncGen + + LINK_LIBS PUBLIC + clangAST + clangBasic + + MLIRAnalysis + MLIRIR + MLIRPass + MLIRTransformUtils + + MLIRCIR + MLIRCIRInterfaces +) diff --git a/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp b/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp new file mode 100644 index 0000000000000..b01d3d4d43e65 --- /dev/null +++ b/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp @@ -0,0 +1,117 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements pass that inlines CIR operations regions into the parent +// function region. +// +//===----------------------------------------------------------------------===// + +#include "PassDetail.h" +#include "mlir/Dialect/Func/IR/FuncOps.h" +#include "mlir/IR/PatternMatch.h" +#include "mlir/Support/LogicalResult.h" +#include "mlir/Transforms/DialectConversion.h" +#include "mlir/Transforms/GreedyPatternRewriteDriver.h" +#include "clang/CIR/Dialect/IR/CIRDialect.h" +#include "clang/CIR/Dialect/Passes.h" +#include "clang/CIR/MissingFeatures.h" + +using namespace mlir; +using namespace cir; + +namespace { + +struct CIRFlattenCFGPass : public CIRFlattenCFGBase<CIRFlattenCFGPass> { + + CIRFlattenCFGPass() = default; + void runOnOperation() override; +}; + +class CIRScopeOpFlattening : public mlir::OpRewritePattern<cir::ScopeOp> { +public: + using OpRewritePattern<cir::ScopeOp>::OpRewritePattern; + + mlir::LogicalResult + matchAndRewrite(cir::ScopeOp scopeOp, + mlir::PatternRewriter &rewriter) const override { + mlir::OpBuilder::InsertionGuard guard(rewriter); + mlir::Location loc = scopeOp.getLoc(); + + // Empty scope: just remove it. + // TODO: Remove this logic once CIR uses MLIR infrastructure to remove + // trivially dead operations. MLIR canonicalizer is too aggressive and we + // need to either (a) make sure all our ops model all side-effects and/or + // (b) have more options in the canonicalizer in MLIR to temper + // aggressiveness level. + if (scopeOp.isEmpty()) { + rewriter.eraseOp(scopeOp); + return mlir::success(); + } + + // Split the current block before the ScopeOp to create the inlining + // point. + mlir::Block *currentBlock = rewriter.getInsertionBlock(); + mlir::Block *continueBlock = + rewriter.splitBlock(currentBlock, rewriter.getInsertionPoint()); + if (scopeOp.getNumResults() > 0) + continueBlock->addArguments(scopeOp.getResultTypes(), loc); + + // Inline body region. + mlir::Block *beforeBody = &scopeOp.getScopeRegion().front(); + mlir::Block *afterBody = &scopeOp.getScopeRegion().back(); + rewriter.inlineRegionBefore(scopeOp.getScopeRegion(), continueBlock); + + // Save stack and then branch into the body of the region. + rewriter.setInsertionPointToEnd(currentBlock); + assert(!cir::MissingFeatures::stackSaveOp()); + rewriter.create<cir::BrOp>(loc, mlir::ValueRange(), beforeBody); + + // Replace the scopeop return with a branch that jumps out of the body. + // Stack restore before leaving the body region. + rewriter.setInsertionPointToEnd(afterBody); + if (auto yieldOp = dyn_cast<cir::YieldOp>(afterBody->getTerminator())) { + rewriter.replaceOpWithNewOp<cir::BrOp>(yieldOp, yieldOp.getArgs(), + continueBlock); + } + + // Replace the op with values return from the body region. + rewriter.replaceOp(scopeOp, continueBlock->getArguments()); + + return mlir::success(); + } +}; + +void populateFlattenCFGPatterns(RewritePatternSet &patterns) { + patterns.add<CIRScopeOpFlattening>(patterns.getContext()); +} + +void CIRFlattenCFGPass::runOnOperation() { + RewritePatternSet patterns(&getContext()); + populateFlattenCFGPatterns(patterns); + + // Collect operations to apply patterns. + llvm::SmallVector<Operation *, 16> ops; + getOperation()->walk<mlir::WalkOrder::PostOrder>([&](Operation *op) { + if (isa<ScopeOp>(op)) + ops.push_back(op); + }); + + // Apply patterns. + if (applyOpPatternsGreedily(ops, std::move(patterns)).failed()) + signalPassFailure(); +} + +} // namespace + +namespace mlir { + +std::unique_ptr<Pass> createCIRFlattenCFGPass() { + return std::make_unique<CIRFlattenCFGPass>(); +} + +} // namespace mlir diff --git a/clang/lib/CIR/Dialect/Transforms/PassDetail.h b/clang/lib/CIR/Dialect/Transforms/PassDetail.h new file mode 100644 index 0000000000000..600dde56d679f --- /dev/null +++ b/clang/lib/CIR/Dialect/Transforms/PassDetail.h @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// 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 CIR_DIALECT_TRANSFORMS_PASSDETAIL_H +#define CIR_DIALECT_TRANSFORMS_PASSDETAIL_H + +#include "mlir/IR/Dialect.h" +#include "mlir/Pass/Pass.h" + +namespace cir { +class CIRDialect; +} // namespace cir + +namespace mlir { +// Forward declaration from Dialect.h +template <typename ConcreteDialect> +void registerDialect(DialectRegistry ®istry); + +#define GEN_PASS_CLASSES +#include "clang/CIR/Dialect/Passes.h.inc" + +} // namespace mlir + +#endif // CIR_DIALECT_TRANSFORMS_PASSDETAIL_H diff --git a/clang/lib/CIR/Lowering/CIRPasses.cpp b/clang/lib/CIR/Lowering/CIRPasses.cpp new file mode 100644 index 0000000000000..235acbfee8967 --- /dev/null +++ b/clang/lib/CIR/Lowering/CIRPasses.cpp @@ -0,0 +1,24 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements machinery for any CIR <-> CIR passes used by clang. +// +//===----------------------------------------------------------------------===// + +// #include "clang/AST/ASTContext.h" +#include "clang/CIR/Dialect/Passes.h" + +#include "mlir/Pass/PassManager.h" + +namespace mlir { + +void populateCIRPreLoweringPasses(OpPassManager &pm) { + pm.addPass(createCIRFlattenCFGPass()); +} + +} // namespace mlir diff --git a/clang/lib/CIR/Lowering/CMakeLists.txt b/clang/lib/CIR/Lowering/CMakeLists.txt index 95c304ded9183..09e48862df63c 100644 --- a/clang/lib/CIR/Lowering/CMakeLists.txt +++ b/clang/lib/CIR/Lowering/CMakeLists.txt @@ -1 +1,20 @@ +set(LLVM_LINK_COMPONENTS + Core + Support + ) + +get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS) + +add_clang_library(clangCIRLoweringCommon + CIRPasses.cpp + + LINK_LIBS + clangCIR + ${dialect_libs} + MLIRCIR + MLIRCIRTransforms + MLIRTransforms + MLIRSupport + ) + add_subdirectory(DirectToLLVM) diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt b/clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt index c11ecb82183d0..7baff3412a84e 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt +++ b/clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt @@ -7,6 +7,7 @@ get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS) add_clang_library(clangCIRLoweringDirectToLLVM LowerToLLVM.cpp + LowerToLLVMIR.cpp DEPENDS MLIRCIREnumsGen @@ -14,9 +15,10 @@ add_clang_library(clangCIRLoweringDirectToLLVM MLIRCIROpInterfacesIncGen LINK_LIBS - MLIRIR + clangCIRLoweringCommon ${dialect_libs} MLIRCIR MLIRBuiltinToLLVMIRTranslation MLIRLLVMToLLVMIRTranslation + MLIRIR ) diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 3200527bd03af..79ec0696eb180 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -12,6 +12,8 @@ #include "LowerToLLVM.h" +#include <deque> + #include "mlir/Conversion/LLVMCommon/TypeConverter.h" #include "mlir/Dialect/DLTI/DLTI.h" #include "mlir/Dialect/Func/IR/FuncOps.h" @@ -25,11 +27,13 @@ #include "mlir/Target/LLVMIR/Export.h" #include "mlir/Transforms/DialectConversion.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" +#include "clang/CIR/Dialect/Passes.h" #include "clang/CIR/MissingFeatures.h" #include "clang/CIR/Passes.h" #include "llvm/ADT/TypeSwitch.h" #include "llvm/IR/Module.h" #include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TimeProfiler.h" using namespace cir; @@ -135,6 +139,7 @@ mlir::LLVM::Linkage convertLinkage(cir::GlobalLinkageKind linkage) { case CIR::WeakODRLinkage: return LLVM::WeakODR; }; + llvm_unreachable("Unknown CIR linkage type"); } class CIRAttrToValue { @@ -603,6 +608,69 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter &converter, }); } +// The applyPartialConversion function traverses blocks in the dominance order, +// so it does not lower and operations that are not reachachable from the +// operations passed in as arguments. Since we do need to lower such code in +// order to avoid verification errors occur, we cannot just pass the module op +// to applyPartialConversion. We must build a set of unreachable ops and +// explicitly add them, along with the module, to the vector we pass to +// applyPartialConversion. +// +// For instance, this CIR code: +// +// cir.func @foo(%arg0: !s32i) -> !s32i { +// %4 = cir.cast(int_to_bool, %arg0 : !s32i), !cir.bool +// cir.if %4 { +// %5 = cir.const #cir.int<1> : !s32i +// cir.return %5 : !s32i +// } else { +// %5 = cir.const #cir.int<0> : !s32i +// cir.return %5 : !s32i +// } +// cir.return %arg0 : !s32i +// } +// +// contains an unreachable return operation (the last one). After the flattening +// pass it will be placed into the unreachable block. The possible error +// after the lowering pass is: error: 'cir.return' op expects parent op to be +// one of 'cir.func, cir.scope, cir.if ... The reason that this operation was +// not lowered and the new parent is llvm.func. +// +// In the future we may want to get rid of this function and use a DCE pass or +// something similar. But for now we need to guarantee the absence of the +// dialect verification errors. +static void collectUnreachable(mlir::Operation *parent, + llvm::SmallVector<mlir::Operation *> &ops) { + + llvm::SmallVector<mlir::Block *> unreachableBlocks; + parent->walk([&](mlir::Block *blk) { // check + if (blk->hasNoPredecessors() && !blk->isEntryBlock()) + unreachableBlocks.push_back(blk); + }); + + std::set<mlir::Block *> visited; + for (mlir::Block *root : unreachableBlocks) { + // We create a work list for each unreachable block. + // Thus we traverse operations in some order. + std::deque<mlir::Block *> workList; + workList.push_back(root); + + while (!workList.empty()) { + mlir::Block *blk = workList.back(); + workList.pop_back(); + if (visited.count(blk)) + continue; + visited.emplace(blk); + + for (mlir::Operation &op : *blk) + ops.push_back(&op); + + for (mlir::Block *succ : blk->getSuccessors()) + workList.push_back(succ); + } + } +} + void ConvertCIRToLLVMPass::processCIRAttrs(mlir::ModuleOp module) { // Lower the module attributes to LLVM equivalents. if (mlir::Attribute tripleAttr = @@ -630,7 +698,13 @@ void ConvertCIRToLLVMPass::runOnOperation() { patterns.add<CIRToLLVMGlobalOpLowering>(converter, patterns.getContext(), dl); patterns.add<CIRToLLVMConstantOpLowering>(converter, patterns.getContext(), dl); - patterns.add<CIRToLLVMFuncOpLowering>(converter, patterns.getContext()); + patterns.add< + // clang-format off + CIRToLLVMBrOpLowering, + CIRToLLVMFuncOpLowering, + CIRToLLVMTrapOpLowering + // clang-format on + >(converter, patterns.getContext()); processCIRAttrs(module); @@ -640,9 +714,36 @@ void ConvertCIRToLLVMPass::runOnOperation() { target.addIllegalDialect<mlir::BuiltinDialect, cir::CIRDialect, mlir::func::FuncDialect>(); - if (failed(applyPartialConversion(module, target, std::move(patterns)))) { + llvm::SmallVector<mlir::Operation *> ops; + ops.push_back(module); + collectUnreachable(module, ops); + + if (failed(applyPartialConversion(ops, target, std::move(patterns)))) signalPassFailure(); - } +} + +mlir::LogicalResult CIRToLLVMBrOpLowering::matchAndRewrite( + cir::BrOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(op, adaptor.getOperands(), + op.getDest()); + return mlir::LogicalResult::success(); +} + +mlir::LogicalResult CIRToLLVMTrapOpLowering::matchAndRewrite( + cir::TrapOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + mlir::Location loc = op->getLoc(); + rewriter.eraseOp(op); + + rewriter.create<mlir::LLVM::Trap>(loc); + + // Note that the call to llvm.trap is not a terminator in LLVM dialect. + // So we must emit an additional llvm.unreachable to terminate the current + // block. + rewriter.create<mlir::LLVM::UnreachableOp>(loc); + + return mlir::success(); } std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() { @@ -650,6 +751,7 @@ std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() { } void populateCIRToLLVMPasses(mlir::OpPassManager &pm) { + mlir::populateCIRPreLoweringPasses(pm); pm.addPass(createConvertCIRToLLVMPass()); } @@ -670,6 +772,7 @@ lowerDirectlyFromCIRToLLVMIR(mlir::ModuleOp mlirModule, LLVMContext &llvmCtx) { mlir::registerBuiltinDialectTranslation(*mlirCtx); mlir::registerLLVMDialectTranslation(*mlirCtx); + mlir::registerCIRDialectTranslation(*mlirCtx); llvm::TimeTraceScope translateScope("translateModuleToLLVMIR"); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h index a694047e3616b..d090bbe4f2e10 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h @@ -136,6 +136,24 @@ class CIRToLLVMGlobalOpLowering cir::GlobalOp op, mlir::ConversionPatternRewriter &rewriter) const; }; +class CIRToLLVMBrOpLowering : public mlir::OpConversionPattern<cir::BrOp> { +public: + using mlir::OpConversionPattern<cir::BrOp>::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::BrOp op, OpAdaptor, + mlir::ConversionPatternRewriter &) const override; +}; + +class CIRToLLVMTrapOpLowering : public mlir::OpConversionPattern<cir::TrapOp> { +public: + using mlir::OpConversionPattern<cir::TrapOp>::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::TrapOp op, OpAdaptor, + mlir::ConversionPatternRewriter &) const override; +}; + } // namespace direct } // namespace cir diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVMIR.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVMIR.cpp new file mode 100644 index 0000000000000..30b9eaaca2d37 --- /dev/null +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVMIR.cpp @@ -0,0 +1,68 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements lowering of CIR attributes and operations directly to +// LLVMIR. +// +//===----------------------------------------------------------------------===// + +#include "mlir/Dialect/LLVMIR/LLVMDialect.h" +#include "mlir/IR/DialectRegistry.h" +#include "mlir/Target/LLVMIR/LLVMTranslationInterface.h" +#include "mlir/Target/LLVMIR/ModuleTranslation.h" +#include "clang/CIR/Dialect/IR/CIRAttrs.h" +#include "clang/CIR/Dialect/IR/CIRDialect.h" +#include "clang/CIR/MissingFeatures.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/IR/Constant.h" +#include "llvm/IR/GlobalVariable.h" + +using namespace llvm; + +namespace cir { +namespace direct { + +/// Implementation of the dialect interface that converts CIR attributes to LLVM +/// IR metadata. +class CIRDialectLLVMIRTranslationInterface + : public mlir::LLVMTranslationDialectInterface { +public: + using LLVMTranslationDialectInterface::LLVMTranslationDialectInterface; + + /// Translates the given operation to LLVM IR using the provided IR builder + /// and saving the state in `moduleTranslation`. + mlir::LogicalResult convertOperation( + mlir::Operation *op, llvm::IRBuilderBase &builder, + mlir::LLVM::ModuleTranslation &moduleTranslation) const final { + + if (auto cirOp = llvm::dyn_cast<mlir::LLVM::ZeroOp>(op)) + moduleTranslation.mapValue(cirOp.getResult()) = + llvm::Constant::getNullValue( + moduleTranslation.convertType(cirOp.getType())); + + return mlir::success(); + } +}; + +void registerCIRDialectTranslation(mlir::DialectRegistry ®istry) { + registry.insert<cir::CIRDialect>(); + registry.addExtension(+[](mlir::MLIRContext *ctx, cir::CIRDialect *dialect) { + dialect->addInterfaces<CIRDialectLLVMIRTranslationInterface>(); + }); +} + +} // namespace direct +} // namespace cir + +namespace mlir { +void registerCIRDialectTranslation(mlir::MLIRContext &context) { + mlir::DialectRegistry registry; + cir::direct::registerCIRDialectTranslation(registry); + context.appendDialectRegistry(registry); +} +} // namespace mlir diff --git a/clang/test/CIR/Lowering/func-simple.cpp b/clang/test/CIR/Lowering/func-simple.cpp index 1429ec270774b..32d75cdd2c15d 100644 --- a/clang/test/CIR/Lowering/func-simple.cpp +++ b/clang/test/CIR/Lowering/func-simple.cpp @@ -13,6 +13,26 @@ int intfunc() { return 42; } // CHECK: define{{.*}} i32 @intfunc() // CHECK: ret i32 42 +int scopes() { + { + { + return 99; + } + } +} +// CHECK: define{{.*}} i32 @scopes() { +// CHECK: br label %[[LABEL1:.*]] +// CHECK: [[LABEL1]]: +// CHECK: br label %[[LABEL2:.*]] +// CHECK: [[LABEL2]]: +// CHECK: ret i32 99 +// CHECK: [[LABEL3:.*]]: +// CHECK: br label %[[LABEL4:.*]] +// CHECK: [[LABEL4]]: +// CHECK: call void @llvm.trap() +// CHECK: unreachable +// CHECK: } + long longfunc() { return 42l; } // CHECK: define{{.*}} i64 @longfunc() { // CHECK: ret i64 42 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits