[clang] [CIR] Initial implementation of CIR-to-LLVM IR lowering pass (PR #125260)

Andy Kaylor via cfe-commits cfe-commits at lists.llvm.org
Fri Jan 31 11:08:48 PST 2025


================
@@ -22,13 +34,127 @@ using namespace llvm;
 namespace cir {
 namespace direct {
 
+struct ConvertCIRToLLVMPass
+    : public mlir::PassWrapper<ConvertCIRToLLVMPass,
+                               mlir::OperationPass<mlir::ModuleOp>> {
+  void getDependentDialects(mlir::DialectRegistry &registry) const override {
+    registry.insert<mlir::BuiltinDialect, mlir::DLTIDialect,
+                    mlir::LLVM::LLVMDialect, mlir::func::FuncDialect>();
+  }
+  void runOnOperation() final;
+
+  StringRef getDescription() const override {
+    return "Convert the prepared CIR dialect module to LLVM dialect";
+  }
+
+  StringRef getArgument() const override { return "cir-flat-to-llvm"; }
+};
+
+mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite(
+    cir::GlobalOp op, OpAdaptor adaptor,
+    mlir::ConversionPatternRewriter &rewriter) const {
+
+  // Fetch required values to create LLVM op.
+  const mlir::Type cirSymType = op.getSymType();
+
+  // This is the LLVM dialect type
+  const mlir::Type llvmType = getTypeConverter()->convertType(cirSymType);
+  // These defaults are just here until the equivalent attributes are
+  // available on cir.global ops.
+  const bool isConst = false;
+  const bool isDsoLocal = true;
+  const mlir::LLVM::Linkage linkage = mlir::LLVM::Linkage::External;
+  const StringRef symbol = op.getSymName();
+  std::optional<mlir::Attribute> init = op.getInitialValue();
+
+  SmallVector<mlir::NamedAttribute> attributes;
+
+  // Check for missing funcionalities.
+  if (!init.has_value()) {
+    rewriter.replaceOpWithNewOp<mlir::LLVM::GlobalOp>(
+        op, llvmType, isConst, linkage, symbol, mlir::Attribute(),
+        /*alignment*/ 0, /*addrSpace*/ 0, /*dsoLocal*/ isDsoLocal,
+        /*threadLocal*/ false, /*comdat*/ mlir::SymbolRefAttr(), attributes);
+    return mlir::success();
+  }
+
+  // Initializer is a constant array: convert it to a compatible llvm init.
+  if (auto intAttr = mlir::dyn_cast<cir::IntAttr>(init.value())) {
+    init = rewriter.getIntegerAttr(llvmType, intAttr.getValue());
+  } else {
+    op.emitError() << "unsupported initializer '" << init.value() << "'";
+    return mlir::failure();
+  }
+
+  // Rewrite op.
+  rewriter.replaceOpWithNewOp<mlir::LLVM::GlobalOp>(
+      op, llvmType, isConst, linkage, symbol, init.value(), /*alignment*/ 0,
+      /*addrSpace*/ 0, /*dsoLocal*/ isDsoLocal, /*threadLocal*/ false,
+      /*comdat*/ mlir::SymbolRefAttr(), attributes);
+
+  return mlir::success();
+}
+
+static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
+                                 mlir::DataLayout &dataLayout) {
+  converter.addConversion([&](cir::IntType type) -> mlir::Type {
+    // LLVM doesn't work with signed types, so we drop the CIR signs here.
+    return mlir::IntegerType::get(type.getContext(), type.getWidth());
+  });
+}
+
+void ConvertCIRToLLVMPass::runOnOperation() {
+  llvm::TimeTraceScope scope("Convert CIR to LLVM Pass");
+
+  mlir::ModuleOp module = getOperation();
+  mlir::DataLayout dl(module);
+  mlir::LLVMTypeConverter converter(&getContext());
+  prepareTypeConverter(converter, dl); // , lowerModule.get());
+
+  mlir::RewritePatternSet patterns(&getContext());
+
+  patterns.add<CIRToLLVMGlobalOpLowering>(converter, patterns.getContext(), dl);
+
+  mlir::ConversionTarget target(getContext());
+  target.addLegalOp<mlir::ModuleOp>();
+  target.addLegalDialect<mlir::LLVM::LLVMDialect>();
+  target.addIllegalDialect<mlir::BuiltinDialect, cir::CIRDialect,
+                           mlir::func::FuncDialect>();
+
+  if (failed(applyPartialConversion(module, target, std::move(patterns))))
+    signalPassFailure();
+}
+
+static std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() {
+  return std::make_unique<ConvertCIRToLLVMPass>();
+}
+
+static void populateCIRToLLVMPasses(mlir::OpPassManager &pm) {
+  pm.addPass(createConvertCIRToLLVMPass());
+}
+
 std::unique_ptr<llvm::Module>
 lowerDirectlyFromCIRToLLVMIR(mlir::ModuleOp mlirModule, LLVMContext &llvmCtx) {
   llvm::TimeTraceScope scope("lower from CIR to LLVM directly");
 
+  mlir::MLIRContext *mlirCtx = mlirModule.getContext();
+
+  mlir::PassManager pm(mlirCtx);
+  populateCIRToLLVMPasses(pm);
+
+  bool result = !mlir::failed(pm.run(mlirModule));
----------------
andykaylor wrote:

I expect reporting a fatal error here is also not what we want long term. I'll do something to clean it up.

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


More information about the cfe-commits mailing list