https://github.com/Andres-Salamanca updated https://github.com/llvm/llvm-project/pull/178106
>From ed1eff3ca0fda93935fe8f43f9f230be38d3a2cd Mon Sep 17 00:00:00 2001 From: Andres Salamanca <[email protected]> Date: Mon, 26 Jan 2026 21:11:09 -0500 Subject: [PATCH 1/2] [CIR] Add lowering for BlockAddressOp, IndirectBrOp and LabelOp --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 4 +- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 98 ++++++++++++++++++- clang/test/CIR/CodeGen/label-values.c | 78 ++++++++++++++- 3 files changed, 171 insertions(+), 9 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 35fd624b89743..3c2fc3facf2a3 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -1503,7 +1503,7 @@ def CIR_LabelOp : CIR_Op<"label", [AlwaysSpeculatable]> { let hasVerifier = 1; let customLLVMLoweringConstructorDecl = - LoweringBuilders<(ins "[[maybe_unused]] LLVMBlockAddressInfo &":$blockInfoAddr)>; + LoweringBuilders<(ins "LLVMBlockAddressInfo &":$blockInfoAddr)>; } //===----------------------------------------------------------------------===// @@ -6075,7 +6075,7 @@ def CIR_BlockAddressOp : CIR_Op<"block_address", [Pure]> { }]; let customLLVMLoweringConstructorDecl = - LoweringBuilders<(ins "[[maybe_unused]] LLVMBlockAddressInfo &":$blockInfoAddr)>; + LoweringBuilders<(ins "LLVMBlockAddressInfo &":$blockInfoAddr)>; } //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 769a053c4e586..692b098912529 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -703,6 +703,8 @@ struct ConvertCIRToLLVMPass void processCIRAttrs(mlir::ModuleOp module); + void resolveBlockAddressOp(LLVMBlockAddressInfo &blockInfoAddr); + StringRef getDescription() const override { return "Convert the prepared CIR dialect module to LLVM dialect"; } @@ -3249,6 +3251,24 @@ mlir::LogicalResult CIRToLLVMObjSizeOpLowering::matchAndRewrite( return mlir::LogicalResult::success(); } +void ConvertCIRToLLVMPass::resolveBlockAddressOp( + LLVMBlockAddressInfo &blockInfoAddr) { + + mlir::ModuleOp module = getOperation(); + mlir::OpBuilder opBuilder(module.getContext()); + for (auto &[blockAddOp, blockInfo] : + blockInfoAddr.getUnresolvedBlockAddress()) { + mlir::LLVM::BlockTagOp resolvedLabel = + blockInfoAddr.lookupBlockTag(blockInfo); + assert(resolvedLabel && "expected BlockTagOp to already be emitted"); + auto fnSym = blockInfo.getFunc(); + auto blkAddTag = mlir::LLVM::BlockAddressAttr::get( + opBuilder.getContext(), fnSym, resolvedLabel.getTagAttr()); + blockAddOp.setBlockAddrAttr(blkAddTag); + } + blockInfoAddr.clearUnresolvedMap(); +} + void ConvertCIRToLLVMPass::processCIRAttrs(mlir::ModuleOp module) { // Lower the module attributes to LLVM equivalents. if (mlir::Attribute tripleAttr = @@ -3315,6 +3335,7 @@ void ConvertCIRToLLVMPass::runOnOperation() { return std::make_pair(dtorAttr.getName(), dtorAttr.getPriority()); }); + resolveBlockAddressOp(blockInfoAddr); } mlir::LogicalResult CIRToLLVMBrOpLowering::matchAndRewrite( @@ -4330,19 +4351,90 @@ mlir::LogicalResult CIRToLLVMVAArgOpLowering::matchAndRewrite( mlir::LogicalResult CIRToLLVMLabelOpLowering::matchAndRewrite( cir::LabelOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { - return mlir::failure(); + mlir::MLIRContext *ctx = rewriter.getContext(); + mlir::Block *block = op->getBlock(); + // A BlockTagOp cannot reside in the entry block. The address of the entry + // block cannot be taken + if (block->isEntryBlock()) { + mlir::Block *newBlock = + rewriter.splitBlock(op->getBlock(), mlir::Block::iterator(op)); + rewriter.setInsertionPointToEnd(block); + mlir::LLVM::BrOp::create(rewriter, op.getLoc(), newBlock); + } + auto tagAttr = + mlir::LLVM::BlockTagAttr::get(ctx, blockInfoAddr.getTagIndex()); + rewriter.setInsertionPoint(op); + + auto blockTagOp = + mlir::LLVM::BlockTagOp::create(rewriter, op->getLoc(), tagAttr); + mlir::LLVM::LLVMFuncOp func = op->getParentOfType<mlir::LLVM::LLVMFuncOp>(); + auto blockInfoAttr = + cir::BlockAddrInfoAttr::get(ctx, func.getSymName(), op.getLabel()); + blockInfoAddr.mapBlockTag(blockInfoAttr, blockTagOp); + rewriter.eraseOp(op); + + return mlir::success(); } mlir::LogicalResult CIRToLLVMBlockAddressOpLowering::matchAndRewrite( cir::BlockAddressOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { - return mlir::failure(); + mlir::MLIRContext *ctx = rewriter.getContext(); + + mlir::LLVM::BlockTagOp matchLabel = + blockInfoAddr.lookupBlockTag(op.getBlockAddrInfoAttr()); + mlir::LLVM::BlockTagAttr tagAttr; + if (!matchLabel) + // If the BlockTagOp has not been emitted yet, use a placeholder. + // This will later be replaced with the correct tag index during + // `resolveBlockAddressOp`. + tagAttr = {}; + else + tagAttr = matchLabel.getTag(); + + auto blkAddr = mlir::LLVM::BlockAddressAttr::get( + rewriter.getContext(), op.getBlockAddrInfoAttr().getFunc(), tagAttr); + rewriter.setInsertionPoint(op); + auto newOp = mlir::LLVM::BlockAddressOp::create( + rewriter, op.getLoc(), mlir::LLVM::LLVMPointerType::get(ctx), blkAddr); + if (!matchLabel) + blockInfoAddr.addUnresolvedBlockAddress(newOp, op.getBlockAddrInfoAttr()); + rewriter.replaceOp(op, newOp); + return mlir::success(); } mlir::LogicalResult CIRToLLVMIndirectBrOpLowering::matchAndRewrite( cir::IndirectBrOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { - return mlir::failure(); + + llvm::SmallVector<mlir::Block *, 8> successors; + llvm::SmallVector<mlir::ValueRange, 8> succOperands; + bool poison = op.getPoison(); + for (mlir::Block *succ : op->getSuccessors()) { + successors.push_back(succ); + } + + for (mlir::ValueRange operand : op.getSuccOperands()) { + succOperands.push_back(operand); + } + + auto llvmPtrType = mlir::LLVM::LLVMPointerType::get(rewriter.getContext()); + mlir::Value targetAddr; + if (!poison) { + targetAddr = mlir::LLVM::BitcastOp::create(rewriter, op.getLoc(), + llvmPtrType, adaptor.getAddr()); + } else { + targetAddr = + mlir::LLVM::PoisonOp::create(rewriter, op->getLoc(), llvmPtrType); + // Remove the block argument to avoid generating an empty PHI during + // lowering. + op->getBlock()->eraseArgument(0); + } + + auto newOp = mlir::LLVM::IndirectBrOp::create( + rewriter, op.getLoc(), targetAddr, succOperands, successors); + rewriter.replaceOp(op, newOp); + return mlir::success(); } mlir::LogicalResult CIRToLLVMAwaitOpLowering::matchAndRewrite( diff --git a/clang/test/CIR/CodeGen/label-values.c b/clang/test/CIR/CodeGen/label-values.c index 750ef1f6889bf..8ba0dd72f9ef5 100644 --- a/clang/test/CIR/CodeGen/label-values.c +++ b/clang/test/CIR/CodeGen/label-values.c @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir // RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll // RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG @@ -23,6 +25,17 @@ void A(void) { // CIR: cir.label "LABEL_A" // CIR: cir.return +// LLVM: define dso_local void @A() +// LLVM: [[PTR:%.*]] = alloca ptr, i64 1, align 8 +// LLVM: store ptr blockaddress(@A, %[[LABEL_A:.*]]), ptr [[PTR]], align 8 +// LLVM: [[BLOCKADD:%.*]] = load ptr, ptr [[PTR]], align 8 +// LLVM: br label %[[indirectgoto:.*]] +// LLVM: [[indirectgoto]]: ; preds = %[[ENTRY:.*]] +// LLVM: [[PHI:%.*]] = phi ptr [ [[BLOCKADD]], %[[ENTRY]] ] +// LLVM: indirectbr ptr [[PHI]], [label %[[LABEL_A]]] +// LLVM: [[LABEL_A]]: ; preds = %[[indirectgoto]] +// LLVM: ret void + // OGCG: define dso_local void @A() // OGCG: [[PTR:%.*]] = alloca ptr, align 8 // OGCG: store ptr blockaddress(@A, %LABEL_A), ptr [[PTR]], align 8 @@ -54,6 +67,17 @@ void B(void) { // CIR-NEXT: ^bb1 // CIR: ] +// LLVM: define dso_local void @B +// LLVM: %[[PTR:.*]] = alloca ptr, i64 1, align 8 +// LLVM: br label %[[LABEL_B:.*]] +// LLVM: [[LABEL_B]]: +// LLVM: store ptr blockaddress(@B, %[[LABEL_B]]), ptr %[[PTR]], align 8 +// LLVM: [[BLOCKADD:%.*]] = load ptr, ptr %[[PTR]], align 8 +// LLVM: br label %[[indirectgoto:.*]] +// LLVM: [[indirectgoto]]: +// LLVM: [[PHI:%.*]] = phi ptr [ [[BLOCKADD]], %[[LABEL_B]] ] +// LLVM: indirectbr ptr [[PHI]], [label %[[LABEL_B]]] + // OGCG: define dso_local void @B // OGCG: [[PTR:%.*]] = alloca ptr, align 8 // OGCG: br label %LABEL_B @@ -95,6 +119,21 @@ void C(int x) { // CIR: cir.label "LABEL_B" // CIR: cir.br ^bb3 +// LLVM: define dso_local void @C(i32 %0) +// LLVM: [[COND:%.*]] = select i1 [[CMP:%.*]], ptr blockaddress(@C, %[[LABEL_A:.*]]), ptr blockaddress(@C, %[[LABEL_B:.*]]) +// LLVM: store ptr [[COND]], ptr [[PTR:%.*]], align 8 +// LLVM: [[BLOCKADD:%.*]] = load ptr, ptr [[PTR]], align 8 +// LLVM: br label %[[indirectgoto:.*]] +// LLVM: [[indirectgoto]]: +// LLVM: [[PHI:%.*]] = phi ptr [ [[BLOCKADD]], %[[ENTRY:.*]] ] +// LLVM: indirectbr ptr [[PHI]], [label %[[LABEL_A]], label %[[LABEL_B]]] +// LLVM: [[LABEL_A]]: +// LLVM: br label %[[RET:.*]] +// LLVM: [[RET]]: +// LLVM: ret void +// LLVM: [[LABEL_B]]: +// LLVM: br label %[[RET]] + // OGCG: define dso_local void @C // OGCG: [[COND:%.*]] = select i1 [[CMP:%.*]], ptr blockaddress(@C, %LABEL_A), ptr blockaddress(@C, %LABEL_B) // OGCG: store ptr [[COND]], ptr [[PTR:%.*]], align 8 @@ -140,6 +179,21 @@ void D(void) { // CIR: cir.store align(8) %[[BLK3]], %[[PTR3]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>> // CIR: cir.return +// LLVM: define dso_local void @D +// LLVM: %[[PTR:.*]] = alloca ptr, i64 1, align 8 +// LLVM: %[[PTR2:.*]] = alloca ptr, i64 1, align 8 +// LLVM: %[[PTR3:.*]] = alloca ptr, i64 1, align 8 +// LLVM: store ptr blockaddress(@D, %[[LABEL_A:.*]]), ptr %[[PTR]], align 8 +// LLVM: store ptr blockaddress(@D, %[[LABEL_A]]), ptr %[[PTR2]], align 8 +// LLVM: %[[BLOCKADD:.*]] = load ptr, ptr %[[PTR2]], align 8 +// LLVM: br label %[[indirectgoto:.*]] +// LLVM: [[indirectgoto]]: +// LLVM: [[PHI:%.*]] = phi ptr [ %[[BLOCKADD]], %[[ENTRY:.*]] ] +// LLVM: indirectbr ptr [[PHI]], [label %[[LABEL_A]], label %[[LABEL_A]], label %[[LABEL_A]]] +// LLVM: [[LABEL_A]]: +// LLVM: store ptr blockaddress(@D, %[[LABEL_A]]), ptr %[[PTR3]], align 8 +// LLVM: ret void + // OGCG: define dso_local void @D // OGCG: %[[PTR:.*]] = alloca ptr, align 8 // OGCG: %[[PTR2:.*]] = alloca ptr, align 8 @@ -186,19 +240,35 @@ void E(void) { //CIR: ^bb5: // 2 preds: ^bb1, ^bb4 //CIR: cir.label "LABEL_D" +// LLVM: define dso_local void @E() +// LLVM: store ptr blockaddress(@E, %[[LABEL_D:.*]]) +// LLVM: store ptr blockaddress(@E, %[[LABEL_C:.*]]) +// LLVM: br label %[[LABEL_A:.*]] +// LLVM: [[indirectgoto:.*]]: ; No predecessors! +// LLVM: indirectbr ptr poison, [label %[[LABEL_D]], label %[[LABEL_C]], label %[[LABEL_B:.*]], label %[[LABEL_A]]] +// LLVM: [[LABEL_A]]: +// LLVM: br label %[[LABEL_B]] +// LLVM: [[LABEL_B]]: +// LLVM: store ptr blockaddress(@E, %[[LABEL_B]]) +// LLVM: store ptr blockaddress(@E, %[[LABEL_A]]) +// LLVM: br label %[[LABEL_C]] +// LLVM: [[LABEL_C]]: +// LLVM: br label %[[LABEL_D]] +// LLVM: [[LABEL_D]]: + // OGCG: define dso_local void @E() #0 { // OGCG: store ptr blockaddress(@E, %LABEL_D), ptr %ptr, align 8 // OGCG: store ptr blockaddress(@E, %LABEL_C), ptr %ptr2, align 8 // OGCG: br label %LABEL_A -// OGCG: A: ; preds = %indirectgoto, %entry +// OGCG: LABEL_A: ; preds = %indirectgoto, %entry // OGCG: br label %LABEL_B -// OGCG: B: ; preds = %indirectgoto, %LABEL_A +// OGCG: LABEL_B: ; preds = %indirectgoto, %LABEL_A // OGCG: store ptr blockaddress(@E, %LABEL_B), ptr %ptr3, align 8 // OGCG: store ptr blockaddress(@E, %LABEL_A), ptr %ptr4, align 8 // OGCG: br label %LABEL_C -// OGCG: C: ; preds = %LABEL_B, %indirectgoto +// OGCG: LABEL_C: ; preds = %LABEL_B, %indirectgoto // OGCG: br label %LABEL_D -// OGCG: D: ; preds = %LABEL_C, %indirectgoto +// OGCG: LABEL_D: ; preds = %LABEL_C, %indirectgoto // OGCG: ret void // OGCG: indirectgoto: ; No predecessors! // OGCG: indirectbr ptr poison, [label %LABEL_D, label %LABEL_C, label %LABEL_B, label %LABEL_A] >From 33ce9c18351e41024aa863cd4f93f08d1a786a73 Mon Sep 17 00:00:00 2001 From: Andres Salamanca <[email protected]> Date: Tue, 27 Jan 2026 18:48:24 -0500 Subject: [PATCH 2/2] Address review feedback --- clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 692b098912529..b5e11051de5e7 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -3261,7 +3261,7 @@ void ConvertCIRToLLVMPass::resolveBlockAddressOp( mlir::LLVM::BlockTagOp resolvedLabel = blockInfoAddr.lookupBlockTag(blockInfo); assert(resolvedLabel && "expected BlockTagOp to already be emitted"); - auto fnSym = blockInfo.getFunc(); + mlir::FlatSymbolRefAttr fnSym = blockInfo.getFunc(); auto blkAddTag = mlir::LLVM::BlockAddressAttr::get( opBuilder.getContext(), fnSym, resolvedLabel.getTagAttr()); blockAddOp.setBlockAddrAttr(blkAddTag); @@ -4410,9 +4410,8 @@ mlir::LogicalResult CIRToLLVMIndirectBrOpLowering::matchAndRewrite( llvm::SmallVector<mlir::Block *, 8> successors; llvm::SmallVector<mlir::ValueRange, 8> succOperands; bool poison = op.getPoison(); - for (mlir::Block *succ : op->getSuccessors()) { + for (mlir::Block *succ : op->getSuccessors()) successors.push_back(succ); - } for (mlir::ValueRange operand : op.getSuccOperands()) { succOperands.push_back(operand); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
