[clang] [CIR] Upstream initial support for CIR flattening (PR #130648)

via cfe-commits cfe-commits at lists.llvm.org
Mon Mar 10 11:00:07 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clangir

Author: Andy Kaylor (andykaylor)

<details>
<summary>Changes</summary>

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.

---

Patch is 25.64 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/130648.diff


18 Files Affected:

- (modified) clang/include/clang/CIR/Dialect/CMakeLists.txt (+6) 
- (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+40) 
- (added) clang/include/clang/CIR/Dialect/Passes.h (+39) 
- (added) clang/include/clang/CIR/Dialect/Passes.td (+28) 
- (modified) clang/include/clang/CIR/MissingFeatures.h (+1) 
- (modified) clang/lib/CIR/Dialect/CMakeLists.txt (+1) 
- (modified) clang/lib/CIR/Dialect/IR/CIRDialect.cpp (+13) 
- (modified) clang/lib/CIR/Dialect/IR/CMakeLists.txt (+1) 
- (added) clang/lib/CIR/Dialect/Transforms/CMakeLists.txt (+18) 
- (added) clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp (+114) 
- (added) clang/lib/CIR/Dialect/Transforms/PassDetail.h (+29) 
- (added) clang/lib/CIR/Lowering/CIRPasses.cpp (+24) 
- (modified) clang/lib/CIR/Lowering/CMakeLists.txt (+19) 
- (modified) clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt (+3-1) 
- (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+99-3) 
- (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h (+18) 
- (added) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVMIR.cpp (+77) 
- (modified) clang/test/CIR/Lowering/func-simple.cpp (+20) 


``````````diff
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..260bbd51062ad
--- /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 and inline all the nested regions. Thus,
+    the next post condtions are met after the pass applied:
+    - there is not any nested region in a 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..dfe33beb0ae1a
--- /dev/null
+++ b/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp
@@ -0,0 +1,114 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+    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 &registry);
+
+#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..b320dae4c1b9f 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,6 +27,7 @@
 #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"
@@ -603,6 +606,64 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
   });
 }
 
+// The unreachable code is not lowered by applyPartialConversion function
+// since it traverses blocks in the dominance order. At the same time we
+// do need to lower such code - otherwise verification errors occur.
+// For instance, the next 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. And 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 DCE pass or
+// something similar. But 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 +691,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 +707,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
+  //...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/130648


More information about the cfe-commits mailing list