[clang] [CIR] Upstream support for cir.indirectbr (PR #169967)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Dec 3 15:58:23 PST 2025
https://github.com/Andres-Salamanca updated https://github.com/llvm/llvm-project/pull/169967
>From 13eb8a04845074675980d5e7923b81c331e29c7b Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Fri, 28 Nov 2025 19:27:31 -0500
Subject: [PATCH 1/4] [CIR] Upstream support for cir.indirectBr
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 61 +++++++++++++
clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 19 +++-
clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 53 ++++++++++++
clang/lib/CIR/CodeGen/CIRGenFunction.h | 12 +++
clang/lib/CIR/CodeGen/CIRGenModule.cpp | 38 ++++++++
clang/lib/CIR/CodeGen/CIRGenModule.h | 18 +++-
clang/lib/CIR/CodeGen/CIRGenStmt.cpp | 21 ++++-
clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 59 +++++++++++++
.../Dialect/Transforms/CIRCanonicalize.cpp | 2 +-
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 6 ++
clang/test/CIR/CodeGen/label-values.c | 86 ++++++++++++++++---
clang/test/CIR/IR/indirect-br.cir | 46 ++++++++++
12 files changed, 399 insertions(+), 22 deletions(-)
create mode 100644 clang/test/CIR/IR/indirect-br.cir
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index ae199f35cb10e..71c35d24cf744 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1462,6 +1462,67 @@ def CIR_BrCondOp : CIR_Op<"brcond", [
}];
}
+//===----------------------------------------------------------------------===//
+// IndirectBrOp
+//===----------------------------------------------------------------------===//
+
+def CIR_IndirectBrOp : CIR_Op<"indirectbr", [
+ DeclareOpInterfaceMethods<BranchOpInterface>
+ , SameVariadicOperandSize, Terminator, Pure]> {
+ let summary = "Indirect branch";
+ let description = [{
+ The `cir.indirectbr` operation represents an indirect branch to one of
+ several possible successor blocks. The target block is computed from
+ the value of the given address operand.
+
+ This operation is typically generated when handling constructs like
+ the GCC extension `&&label` combined with an indirect `goto *ptr;`.
+
+ The `poison` attribute is used to mark an `indirectbr` that was created
+ but is known to be invalid for instance, when a label address was
+ taken but no indirect branch was ever emitted.
+
+ Example:
+
+ ```mlir
+ %0 = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["ptr", init]
+ %1 = cir.block_address <@A, "A"> : !cir.ptr<!void>
+ cir.store align(8) %1, %0 : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
+ %2 = cir.load align(8) %0 : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
+ cir.br ^bb1(%2 : !cir.ptr<!void>)
+ ^bb1(%3: !cir.ptr<!void>):
+ cir.indirectbr %3 : <!void>, [
+ ^bb2
+ ]
+ ```
+ or with a poison:
+
+ ```mlir
+ cir.indirectbr %0 poison : <!void>, [
+ ^bb3,
+ ^bb2
+ ]
+ ```
+ }];
+
+ let arguments = (ins
+ CIR_VoidPtrType:$addr,
+ UnitAttr:$poison,
+ VariadicOfVariadic<AnyType, "indbr_operand_segments">:$succOperands,
+ DenseI32ArrayAttr:$indbr_operand_segments
+ );
+
+ let successors = (successor VariadicSuccessor<AnySuccessor>:$successors);
+ let assemblyFormat = [{
+ $addr ( `poison` $poison^ )? `:` type($addr) `,`
+ custom<IndirectBrOpSucessors>(ref(type($addr)),
+ $successors,
+ $succOperands,
+ type($succOperands))
+ attr-dict
+ }];
+}
+
//===----------------------------------------------------------------------===//
// Common loop op definitions
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 3e9d3db768bea..cfed8a5694d34 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -174,11 +174,22 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
mlir::Value VisitAddrLabelExpr(const AddrLabelExpr *e) {
auto func = cast<cir::FuncOp>(cgf.curFn);
- auto blockInfoAttr = cir::BlockAddrInfoAttr::get(
+ cir::BlockAddrInfoAttr blockInfoAttr = cir::BlockAddrInfoAttr::get(
&cgf.getMLIRContext(), func.getSymName(), e->getLabel()->getName());
- return cir::BlockAddressOp::create(builder, cgf.getLoc(e->getSourceRange()),
- cgf.convertType(e->getType()),
- blockInfoAttr);
+ cir::BlockAddressOp blockAddressOp = cir::BlockAddressOp::create(
+ builder, cgf.getLoc(e->getSourceRange()), cgf.convertType(e->getType()),
+ blockInfoAttr);
+ cir::LabelOp resolvedLabel = cgf.cgm.lookupBlockAddressInfo(blockInfoAttr);
+ if (!resolvedLabel) {
+ cgf.cgm.mapUnresolvedBlockAddress(blockAddressOp);
+ // Still add the op to maintain insertion order it will be resolved in
+ // resolveBlockAddresses
+ cgf.cgm.mapResolvedBlockAddress(blockAddressOp, nullptr);
+ } else {
+ cgf.cgm.mapResolvedBlockAddress(blockAddressOp, resolvedLabel);
+ }
+ cgf.getIndirectGotoBlock();
+ return blockAddressOp;
}
mlir::Value VisitIntegerLiteral(const IntegerLiteral *e) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 22128ed3521f8..f737783b3bf14 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -531,7 +531,49 @@ void CIRGenFunction::startFunction(GlobalDecl gd, QualType returnType,
}
}
+void CIRGenFunction::resolveBlockAddresses() {
+
+ for (cir::BlockAddressOp &blockAddress : cgm.unresolvedBlockAddressToLabel) {
+ cir::LabelOp labelOp =
+ cgm.lookupBlockAddressInfo(blockAddress.getBlockAddrInfo());
+ assert(labelOp && "expected cir.labelOp to already be emitted");
+ cgm.updateResolvedBlockAddress(blockAddress, labelOp);
+ }
+ cgm.unresolvedBlockAddressToLabel.clear();
+}
+
+void CIRGenFunction::finishIndirectBranch() {
+ if (!indirectGotoBlock)
+ return;
+ llvm::SmallVector<mlir::Block *> succesors;
+ llvm::SmallVector<mlir::ValueRange> rangeOperands;
+ mlir::OpBuilder::InsertionGuard guard(builder);
+ builder.setInsertionPointToEnd(indirectGotoBlock);
+ for (auto &[blockAdd, labelOp] : cgm.blockAddressToLabel) {
+ succesors.push_back(labelOp->getBlock());
+ rangeOperands.push_back(labelOp->getBlock()->getArguments());
+ }
+ cir::IndirectBrOp::create(builder, builder.getUnknownLoc(),
+ indirectGotoBlock->getArgument(0), false,
+ rangeOperands, succesors);
+ cgm.blockAddressToLabel.clear();
+}
+
void CIRGenFunction::finishFunction(SourceLocation endLoc) {
+ // Resolve block address-to-label mappings, then emit the indirect branch
+ // with the corresponding targets.
+ resolveBlockAddresses();
+ finishIndirectBranch();
+
+ // If a label address was taken but no indirect goto was used, we can't remove
+ // the block argument here. Instead, we mark the 'indirectbr' op
+ // as poison so that the cleanup can be deferred to lowering, since the
+ // verifier doesn't allow the 'indirectbr' target address to be null.
+ if (indirectGotoBlock && indirectGotoBlock->hasNoPredecessors()) {
+ auto indrBr = cast<cir::IndirectBrOp>(indirectGotoBlock->front());
+ indrBr.setPoison(true);
+ }
+
// Pop any cleanups that might have been associated with the
// parameters. Do this in whatever block we're currently in; it's
// important to do this before we enter the return block or return
@@ -1086,6 +1128,17 @@ CIRGenFunction::emitArrayLength(const clang::ArrayType *origArrayType,
return builder.getConstInt(*currSrcLoc, sizeTy, countFromCLAs);
}
+void CIRGenFunction::getIndirectGotoBlock() {
+ // If we already made the indirect branch for indirect goto, return its block.
+ if (indirectGotoBlock)
+ return;
+
+ mlir::OpBuilder::InsertionGuard guard(builder);
+ indirectGotoBlock =
+ builder.createBlock(builder.getBlock()->getParent(), {}, {voidPtrTy},
+ {builder.getUnknownLoc()});
+}
+
mlir::Value CIRGenFunction::emitAlignmentAssumption(
mlir::Value ptrValue, QualType ty, SourceLocation loc,
SourceLocation assumptionLoc, int64_t alignment, mlir::Value offsetValue) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 91b5ffa8b9ff9..e8b2a32cde0f5 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -654,6 +654,14 @@ class CIRGenFunction : public CIRGenTypeCache {
return JumpDest(target, ehStack.getInnermostNormalCleanup(),
nextCleanupDestIndex++);
}
+ /// IndirectBranch - The first time an indirect goto is seen we create a block
+ /// reserved for the indirect branch. Unlike before,the actual 'indirectbr'
+ /// is emitted at the end of the function, once all block destinations have
+ /// been resolved.
+ mlir::Block *indirectGotoBlock = nullptr;
+
+ void resolveBlockAddresses();
+ void finishIndirectBranch();
/// Perform the usual unary conversions on the specified expression and
/// compare the result against zero, returning an Int1Ty value.
@@ -1388,6 +1396,8 @@ class CIRGenFunction : public CIRGenTypeCache {
int64_t getAccessedFieldNo(unsigned idx, mlir::ArrayAttr elts);
+ void getIndirectGotoBlock();
+
RValue emitCall(const CIRGenFunctionInfo &funcInfo,
const CIRGenCallee &callee, ReturnValueSlot returnValue,
const CallArgList &args, cir::CIRCallOpInterface *callOp,
@@ -1571,6 +1581,8 @@ class CIRGenFunction : public CIRGenTypeCache {
mlir::LogicalResult emitGotoStmt(const clang::GotoStmt &s);
+ mlir::LogicalResult emitIndirectGotoStmt(const IndirectGotoStmt &s);
+
void emitImplicitAssignmentOperatorBody(FunctionArgList &args);
void emitInitializerForField(clang::FieldDecl *field, LValue lhs,
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 1d8e4a3b444ee..131e6ed29a3b4 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -2498,3 +2498,41 @@ DiagnosticBuilder CIRGenModule::errorNYI(SourceRange loc,
llvm::StringRef feature) {
return errorNYI(loc.getBegin(), feature) << loc;
}
+
+void CIRGenModule::mapBlockAddress(cir::BlockAddrInfoAttr blockInfo,
+ cir::LabelOp label) {
+ auto result = blockAddressInfoToLabel.try_emplace(blockInfo, label);
+ (void)result;
+ assert(result.second &&
+ "attempting to map a blockaddress info that is already mapped");
+}
+
+void CIRGenModule::mapUnresolvedBlockAddress(cir::BlockAddressOp op) {
+ auto result = unresolvedBlockAddressToLabel.insert(op);
+ (void)result;
+ assert(result.second &&
+ "attempting to map a blockaddress operation that is already mapped");
+}
+
+void CIRGenModule::mapResolvedBlockAddress(cir::BlockAddressOp op,
+ cir::LabelOp label) {
+ auto result = blockAddressToLabel.try_emplace(op, label);
+ (void)result;
+ assert(result.second &&
+ "attempting to map a blockaddress operation that is already mapped");
+}
+
+void CIRGenModule::updateResolvedBlockAddress(cir::BlockAddressOp op,
+ cir::LabelOp newLabel) {
+ auto *it = blockAddressToLabel.find(op);
+ assert(it != blockAddressToLabel.end() &&
+ "trying to update a blockaddress not previously mapped");
+ assert(!it->second && "blockaddress already has a resolved label");
+
+ it->second = newLabel;
+}
+
+cir::LabelOp
+CIRGenModule::lookupBlockAddressInfo(cir::BlockAddrInfoAttr blockInfo) {
+ return blockAddressInfoToLabel.lookup(blockInfo);
+}
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h
index d7aee8ebf4d7a..59eb5f8938129 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -126,7 +126,23 @@ class CIRGenModule : public CIRGenTypeCache {
/// the pointers are supposed to be uniqued, should be fine. Revisit this if
/// it ends up taking too much memory.
llvm::DenseMap<const clang::FieldDecl *, llvm::StringRef> lambdaFieldToName;
-
+ /// Map BlockAddrInfoAttr (function name, label name) to the corresponding CIR
+ /// LabelOp. This provides the main lookup table used to resolve block
+ /// addresses into their label operations.
+ llvm::DenseMap<cir::BlockAddrInfoAttr, cir::LabelOp> blockAddressInfoToLabel;
+ /// Map CIR BlockAddressOps directly to their resolved LabelOps.
+ /// Used once a block address has been successfully lowered to a label.
+ llvm::MapVector<cir::BlockAddressOp, cir::LabelOp> blockAddressToLabel;
+ /// Track CIR BlockAddressOps that cannot be resolved immediately
+ /// because their LabelOp has not yet been emitted. These entries
+ /// are solved later once the corresponding label is available.
+ llvm::DenseSet<cir::BlockAddressOp> unresolvedBlockAddressToLabel;
+ cir::LabelOp lookupBlockAddressInfo(cir::BlockAddrInfoAttr blockInfo);
+ void mapBlockAddress(cir::BlockAddrInfoAttr blockInfo, cir::LabelOp label);
+ void mapUnresolvedBlockAddress(cir::BlockAddressOp op);
+ void mapResolvedBlockAddress(cir::BlockAddressOp op, cir::LabelOp);
+ void updateResolvedBlockAddress(cir::BlockAddressOp op,
+ cir::LabelOp newLabel);
/// Tell the consumer that this variable has been instantiated.
void handleCXXStaticMemberVarInstantiation(VarDecl *vd);
diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index 7bb8c2153056a..09801bd7f1888 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -203,6 +203,7 @@ mlir::LogicalResult CIRGenFunction::emitStmt(const Stmt *s,
return emitCoroutineBody(cast<CoroutineBodyStmt>(*s));
case Stmt::CoreturnStmtClass:
case Stmt::IndirectGotoStmtClass:
+ return emitIndirectGotoStmt(cast<IndirectGotoStmt>(*s));
case Stmt::OMPParallelDirectiveClass:
case Stmt::OMPTaskwaitDirectiveClass:
case Stmt::OMPTaskyieldDirectiveClass:
@@ -555,6 +556,17 @@ mlir::LogicalResult CIRGenFunction::emitGotoStmt(const clang::GotoStmt &s) {
return mlir::success();
}
+mlir::LogicalResult
+CIRGenFunction::emitIndirectGotoStmt(const IndirectGotoStmt &s) {
+ mlir::Value val = emitScalarExpr(s.getTarget());
+ assert(indirectGotoBlock &&
+ "If you jumping to a indirect branch should be alareadye emitted");
+ cir::BrOp::create(builder, getLoc(s.getSourceRange()), indirectGotoBlock,
+ val);
+ builder.createBlock(builder.getBlock()->getParent());
+ return mlir::success();
+}
+
mlir::LogicalResult
CIRGenFunction::emitContinueStmt(const clang::ContinueStmt &s) {
builder.createContinue(getLoc(s.getKwLoc()));
@@ -581,9 +593,14 @@ mlir::LogicalResult CIRGenFunction::emitLabel(const clang::LabelDecl &d) {
}
builder.setInsertionPointToEnd(labelBlock);
- cir::LabelOp::create(builder, getLoc(d.getSourceRange()), d.getName());
+ cir::LabelOp label =
+ cir::LabelOp::create(builder, getLoc(d.getSourceRange()), d.getName());
builder.setInsertionPointToEnd(labelBlock);
-
+ auto func = cast<cir::FuncOp>(curFn);
+ cgm.mapBlockAddress(cir::BlockAddrInfoAttr::get(builder.getContext(),
+ func.getSymNameAttr(),
+ label.getLabelAttr()),
+ label);
// FIXME: emit debug info for labels, incrementProfileCounter
assert(!cir::MissingFeatures::ehstackBranches());
assert(!cir::MissingFeatures::incrementProfileCounter());
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 396d97ddd794e..ec8cae62d6bc8 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -1247,6 +1247,65 @@ Block *cir::BrOp::getSuccessorForOperands(ArrayRef<Attribute>) {
return getDest();
}
+//===----------------------------------------------------------------------===//
+// IndirectBrCondOp
+//===----------------------------------------------------------------------===//
+
+mlir::SuccessorOperands
+cir::IndirectBrOp::getSuccessorOperands(unsigned index) {
+ assert(index < getNumSuccessors() && "invalid successor index");
+ return mlir::SuccessorOperands(getSuccOperandsMutable()[index]);
+}
+
+ParseResult parseIndirectBrOpSucessors(
+ OpAsmParser &parser, Type &flagType,
+ SmallVectorImpl<Block *> &succOperandBlocks,
+ SmallVectorImpl<SmallVector<OpAsmParser::UnresolvedOperand>> &succOperands,
+ SmallVectorImpl<SmallVector<Type>> &succOperandsTypes) {
+ if (failed(parser.parseCommaSeparatedList(
+ OpAsmParser::Delimiter::Square,
+ [&]() {
+ Block *destination = nullptr;
+ SmallVector<OpAsmParser::UnresolvedOperand> operands;
+ SmallVector<Type> operandTypes;
+
+ if (parser.parseSuccessor(destination).failed())
+ return failure();
+
+ if (succeeded(parser.parseOptionalLParen())) {
+ if (failed(parser.parseOperandList(
+ operands, OpAsmParser::Delimiter::None)) ||
+ failed(parser.parseColonTypeList(operandTypes)) ||
+ failed(parser.parseRParen()))
+ return failure();
+ }
+ succOperandBlocks.push_back(destination);
+ succOperands.emplace_back(operands);
+ succOperandsTypes.emplace_back(operandTypes);
+ return success();
+ },
+ "successor blocks")))
+ return failure();
+ return success();
+}
+
+void printIndirectBrOpSucessors(OpAsmPrinter &p, cir::IndirectBrOp op,
+ Type flagType, SuccessorRange succs,
+ OperandRangeRange succOperands,
+ const TypeRangeRange &succOperandsTypes) {
+ p << "[";
+ llvm::interleave(
+ llvm::zip(succs, succOperands),
+ [&](auto i) {
+ p.printNewline();
+ p.printSuccessorAndUseList(std::get<0>(i), std::get<1>(i));
+ },
+ [&] { p << ','; });
+ if (!succOperands.empty())
+ p.printNewline();
+ p << "]";
+}
+
//===----------------------------------------------------------------------===//
// BrCondOp
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp b/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp
index 2ef09b74dc968..0749c5e79e3ff 100644
--- a/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp
@@ -52,7 +52,7 @@ struct RemoveRedundantBranches : public OpRewritePattern<BrOp> {
Block *block = op.getOperation()->getBlock();
Block *dest = op.getDest();
- if (isa<cir::LabelOp>(dest->front()))
+ if (isa<cir::LabelOp, cir::IndirectBrOp>(dest->front()))
return failure();
// Single edge between blocks: merge it.
if (block->getNumSuccessors() == 1 &&
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 40e14474890dc..44478a0863155 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -4103,6 +4103,12 @@ mlir::LogicalResult CIRToLLVMBlockAddressOpLowering::matchAndRewrite(
return mlir::failure();
}
+mlir::LogicalResult CIRToLLVMIndirectBrOpLowering::matchAndRewrite(
+ cir::IndirectBrOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ return mlir::failure();
+}
+
mlir::LogicalResult CIRToLLVMAwaitOpLowering::matchAndRewrite(
cir::AwaitOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
diff --git a/clang/test/CIR/CodeGen/label-values.c b/clang/test/CIR/CodeGen/label-values.c
index 0305442a38471..237ba057cfc7e 100644
--- a/clang/test/CIR/CodeGen/label-values.c
+++ b/clang/test/CIR/CodeGen/label-values.c
@@ -3,6 +3,7 @@
void A(void) {
void *ptr = &&LABEL_A;
+ goto *ptr;
LABEL_A:
return;
}
@@ -10,31 +11,43 @@ void A(void) {
// CIR: [[PTR:%.*]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["ptr", init] {alignment = 8 : i64}
// CIR: [[BLOCK:%.*]] = cir.block_address <@A, "LABEL_A"> : !cir.ptr<!void>
// CIR: cir.store align(8) [[BLOCK]], [[PTR]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
-// CIR: cir.br ^bb1
-// CIR: ^bb1: // pred: ^bb0
+// CIR: [[BLOCKADD:%.*]] = cir.load align(8) [[PTR]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
+// CIR: cir.br ^bb1([[BLOCKADD]] : !cir.ptr<!void>)
+// CIR: ^bb1([[PHI:%.*]]: !cir.ptr<!void> {{.*}}): // pred: ^bb0
+// CIR: cir.indirectbr [[PHI]] : <!void>, [
+// CIR: ^bb2
+// CIR: ]
+// CIR: ^bb2: // pred: ^bb1
// CIR: cir.label "LABEL_A"
// CIR: cir.return
void B(void) {
LABEL_B:
void *ptr = &&LABEL_B;
+ goto *ptr;
}
// CIR: cir.func {{.*}} @B()
// CIR: [[PTR:%.*]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["ptr", init] {alignment = 8 : i64}
// CIR: cir.br ^bb1
-// CIR: ^bb1:
+// CIR: ^bb1: // 2 preds: ^bb0, ^bb2
// CIR: cir.label "LABEL_B"
// CIR: [[BLOCK:%.*]] = cir.block_address <@B, "LABEL_B"> : !cir.ptr<!void>
// CIR: cir.store align(8) [[BLOCK]], [[PTR]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
-// CIR: cir.return
+// CIR: [[BLOCKADD:%.*]] = cir.load align(8) [[PTR]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
+// CIR: cir.br ^bb2([[BLOCKADD]] : !cir.ptr<!void>)
+// CIR: ^bb2([[PHI:%.*]]: !cir.ptr<!void> {{.*}}): // pred: ^bb1
+// CIR: cir.indirectbr [[PHI]] : <!void>, [
+// CIR-NEXT: ^bb1
+// CIR: ]
void C(int x) {
- void *ptr = (x == 0) ? &&LABEL_A : &&LABEL_B;
+ void *ptr = (x == 0) ? &&LABEL_A : &&LABEL_B;
+ goto *ptr;
LABEL_A:
- return;
+ return;
LABEL_B:
- return;
+ return;
}
// CIR: cir.func {{.*}} @C
@@ -42,19 +55,26 @@ void C(int x) {
// CIR: [[BLOCK2:%.*]] = cir.block_address <@C, "LABEL_B"> : !cir.ptr<!void>
// CIR: [[COND:%.*]] = cir.select if [[CMP:%.*]] then [[BLOCK1]] else [[BLOCK2]] : (!cir.bool, !cir.ptr<!void>, !cir.ptr<!void>) -> !cir.ptr<!void>
// CIR: cir.store align(8) [[COND]], [[PTR:%.*]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
-// CIR: cir.br ^bb1
-// CIR: ^bb1: // pred: ^bb0
+// CIR: [[BLOCKADD:%.*]] = cir.load align(8) [[PTR]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
+// CIR: cir.br ^bb1([[BLOCKADD]] : !cir.ptr<!void>)
+// CIR: ^bb1([[PHI:%.*]]: !cir.ptr<!void> {{.*}}): // pred: ^bb0
+// CIR: cir.indirectbr [[PHI]] : <!void>, [
+// CIR-NEXT: ^bb2,
+// CIR-NEXT: ^bb4
+// CIR: ]
+// CIR: ^bb2: // pred: ^bb1
// CIR: cir.label "LABEL_A"
-// CIR: cir.br ^bb2
-// CIR: ^bb2: // 2 preds: ^bb1, ^bb3
+// CIR: cir.br ^bb3
+// CIR: ^bb3: // 2 preds: ^bb2, ^bb4
// CIR: cir.return
-// CIR: ^bb3: // no predecessors
+// CIR: ^bb4: // pred: ^bb1
// CIR: cir.label "LABEL_B"
-// CIR: cir.br ^bb2
+// CIR: cir.br ^bb3
void D(void) {
void *ptr = &&LABEL_A;
void *ptr2 = &&LABEL_A;
+ goto *ptr2;
LABEL_A:
void *ptr3 = &&LABEL_A;
return;
@@ -69,8 +89,46 @@ void D(void) {
// CIR: %[[BLK2:.*]] = cir.block_address <@D, "LABEL_A"> : !cir.ptr<!void>
// CIR: cir.store align(8) %[[BLK2]], %[[PTR2]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
// CIR: cir.br ^bb1
-// CIR: ^bb1: // pred: ^bb0
+// CIR: ^bb1([[PHI:%*.]]: !cir.ptr<!void> {{.*}}): // pred: ^bb0
+// CIR: cir.indirectbr [[PHI]] : <!void>, [
+// CIR-DAG: ^bb2,
+// CIR-DAG: ^bb2,
+// CIR-DAG: ^bb2
+// CIR: ]
+// CIR: ^bb2: // 3 preds: ^bb1, ^bb1, ^bb1
// CIR: cir.label "LABEL_A"
// CIR: %[[BLK3:.*]] = cir.block_address <@D, "LABEL_A"> : !cir.ptr<!void>
// CIR: cir.store align(8) %[[BLK3]], %[[PTR3]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
// CIR: cir.return
+
+
+// This test checks that CIR preserves insertion order of blockaddresses
+// for indirectbr, even if some were resolved immediately and others later.
+void E(void) {
+ void *ptr = &&LABEL_D;
+ void *ptr2 = &&LABEL_C;
+LABEL_A:
+LABEL_B:
+ void *ptr3 = &&LABEL_B;
+ void *ptr4 = &&LABEL_A;
+LABEL_C:
+LABEL_D:
+ return;
+}
+
+//CIR: cir.func dso_local @E()
+//CIR: ^bb1({{.*}}: !cir.ptr<!void> {{.*}}): // no predecessors
+//CIR: cir.indirectbr {{.*}} poison : <!void>, [
+//CIR-NEXT: ^bb5,
+//CIR-NEXT: ^bb4,
+//CIR-NEXT: ^bb3,
+//CIR-NEXT: ^bb2
+//CIR: ]
+//CIR: ^bb2: // 2 preds: ^bb0, ^bb1
+//CIR: cir.label "LABEL_A"
+//CIR: ^bb3: // 2 preds: ^bb1, ^bb2
+//CIR: cir.label "LABEL_B"
+//CIR: ^bb4: // 2 preds: ^bb1, ^bb3
+//CIR: cir.label "LABEL_C"
+//CIR: ^bb5: // 2 preds: ^bb1, ^bb4
+//CIR: cir.label "LABEL_D"
diff --git a/clang/test/CIR/IR/indirect-br.cir b/clang/test/CIR/IR/indirect-br.cir
new file mode 100644
index 0000000000000..e091e31dc3f5f
--- /dev/null
+++ b/clang/test/CIR/IR/indirect-br.cir
@@ -0,0 +1,46 @@
+// RUN: cir-opt %s --verify-roundtrip | FileCheck %s
+
+!void = !cir.void
+
+cir.func @E() {
+ %0 = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["ptr", init] {alignment = 8 : i64}
+ %1 = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["ptr2", init] {alignment = 8 : i64}
+ %2 = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["ptr3", init] {alignment = 8 : i64}
+ %3 = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["ptr4", init] {alignment = 8 : i64}
+ %4 = cir.block_address <@E, "D"> : !cir.ptr<!void>
+ cir.store align(8) %4, %0 : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
+ %5 = cir.block_address <@E, "C"> : !cir.ptr<!void>
+ cir.store align(8) %5, %1 : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
+ %6 = cir.load align(8) %0 : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
+ cir.br ^bb1(%6 : !cir.ptr<!void>)
+^bb1(%7: !cir.ptr<!void>): // pred: ^bb0
+ cir.indirectbr %7 : <!void>, [
+ ^bb5,
+ ^bb4,
+ ^bb3,
+ ^bb2
+ ]
+^bb2: // pred: ^bb1
+ cir.label "A"
+ cir.br ^bb3
+^bb3: // 2 preds: ^bb1, ^bb2
+ cir.label "B"
+ %8 = cir.block_address <@E, "B"> : !cir.ptr<!void>
+ cir.store align(8) %8, %2 : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
+ %9 = cir.block_address <@E, "A"> : !cir.ptr<!void>
+ cir.store align(8) %9, %3 : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
+ cir.br ^bb4
+^bb4: // 2 preds: ^bb1, ^bb3
+ cir.label "C"
+ cir.br ^bb5
+^bb5: // 2 preds: ^bb1, ^bb4
+ cir.label "D"
+ cir.return
+}
+
+// CHECK: cir.indirectbr %7 : <!void>, [
+// CHECK: ^bb5,
+// CHECK: ^bb4,
+// CHECK: ^bb3,
+// CHECK: ^bb2
+// CHECK: ]
>From 9cf288572c3a79c4e1ced8ff0ed48839a624c407 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Mon, 1 Dec 2025 19:25:27 -0500
Subject: [PATCH 2/4] Apply reviews
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 6 +-
clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 2 +-
clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 3 +-
clang/lib/CIR/CodeGen/CIRGenFunction.h | 2 +-
clang/lib/CIR/CodeGen/CIRGenModule.cpp | 10 ++-
clang/test/CIR/CodeGen/label-values.c | 70 ++++++++++++++++++++
6 files changed, 80 insertions(+), 13 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 71c35d24cf744..9293ce118d8a9 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1467,8 +1467,8 @@ def CIR_BrCondOp : CIR_Op<"brcond", [
//===----------------------------------------------------------------------===//
def CIR_IndirectBrOp : CIR_Op<"indirectbr", [
- DeclareOpInterfaceMethods<BranchOpInterface>
- , SameVariadicOperandSize, Terminator, Pure]> {
+ DeclareOpInterfaceMethods<BranchOpInterface>,
+ SameVariadicOperandSize, Terminator, Pure]> {
let summary = "Indirect branch";
let description = [{
The `cir.indirectbr` operation represents an indirect branch to one of
@@ -1479,7 +1479,7 @@ def CIR_IndirectBrOp : CIR_Op<"indirectbr", [
the GCC extension `&&label` combined with an indirect `goto *ptr;`.
The `poison` attribute is used to mark an `indirectbr` that was created
- but is known to be invalid for instance, when a label address was
+ but is known to be invalid, for instance when a label address was
taken but no indirect branch was ever emitted.
Example:
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index cfed8a5694d34..9043ecab42f15 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -188,7 +188,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
} else {
cgf.cgm.mapResolvedBlockAddress(blockAddressOp, resolvedLabel);
}
- cgf.getIndirectGotoBlock();
+ cgf.instantiateIndirectGotoBlock();
return blockAddressOp;
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index f737783b3bf14..492cbb69fabb3 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -532,7 +532,6 @@ void CIRGenFunction::startFunction(GlobalDecl gd, QualType returnType,
}
void CIRGenFunction::resolveBlockAddresses() {
-
for (cir::BlockAddressOp &blockAddress : cgm.unresolvedBlockAddressToLabel) {
cir::LabelOp labelOp =
cgm.lookupBlockAddressInfo(blockAddress.getBlockAddrInfo());
@@ -1128,7 +1127,7 @@ CIRGenFunction::emitArrayLength(const clang::ArrayType *origArrayType,
return builder.getConstInt(*currSrcLoc, sizeTy, countFromCLAs);
}
-void CIRGenFunction::getIndirectGotoBlock() {
+void CIRGenFunction::instantiateIndirectGotoBlock() {
// If we already made the indirect branch for indirect goto, return its block.
if (indirectGotoBlock)
return;
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index e8b2a32cde0f5..16c1813a8513d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1396,7 +1396,7 @@ class CIRGenFunction : public CIRGenTypeCache {
int64_t getAccessedFieldNo(unsigned idx, mlir::ArrayAttr elts);
- void getIndirectGotoBlock();
+ void instantiateIndirectGotoBlock();
RValue emitCall(const CIRGenFunctionInfo &funcInfo,
const CIRGenCallee &callee, ReturnValueSlot returnValue,
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 131e6ed29a3b4..e1894c040dd53 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -2501,23 +2501,21 @@ DiagnosticBuilder CIRGenModule::errorNYI(SourceRange loc,
void CIRGenModule::mapBlockAddress(cir::BlockAddrInfoAttr blockInfo,
cir::LabelOp label) {
- auto result = blockAddressInfoToLabel.try_emplace(blockInfo, label);
- (void)result;
+ [[maybe_unused]] auto result =
+ blockAddressInfoToLabel.try_emplace(blockInfo, label);
assert(result.second &&
"attempting to map a blockaddress info that is already mapped");
}
void CIRGenModule::mapUnresolvedBlockAddress(cir::BlockAddressOp op) {
- auto result = unresolvedBlockAddressToLabel.insert(op);
- (void)result;
+ [[maybe_unused]] auto result = unresolvedBlockAddressToLabel.insert(op);
assert(result.second &&
"attempting to map a blockaddress operation that is already mapped");
}
void CIRGenModule::mapResolvedBlockAddress(cir::BlockAddressOp op,
cir::LabelOp label) {
- auto result = blockAddressToLabel.try_emplace(op, label);
- (void)result;
+ [[maybe_unused]] auto result = blockAddressToLabel.try_emplace(op, label);
assert(result.second &&
"attempting to map a blockaddress operation that is already mapped");
}
diff --git a/clang/test/CIR/CodeGen/label-values.c b/clang/test/CIR/CodeGen/label-values.c
index 237ba057cfc7e..29b07a74dcc37 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 -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
void A(void) {
void *ptr = &&LABEL_A;
@@ -21,6 +23,17 @@ void A(void) {
// CIR: cir.label "LABEL_A"
// CIR: cir.return
+// OGCG: define dso_local void @A()
+// OGCG: [[PTR:%.*]] = alloca ptr, align 8
+// OGCG: store ptr blockaddress(@A, %LABEL_A), ptr [[PTR]], align 8
+// OGCG: [[BLOCKADD:%.*]] = load ptr, ptr [[PTR]], align 8
+// OGCG: br label %indirectgoto
+// OGCG: LABEL_A: ; preds = %indirectgoto
+// OGCG: ret void
+// OGCG: indirectgoto: ; preds = %entry
+// OGCG: %indirect.goto.dest = phi ptr [ [[BLOCKADD]], %entry ]
+// OGCG: indirectbr ptr %indirect.goto.dest, [label %LABEL_A]
+
void B(void) {
LABEL_B:
void *ptr = &&LABEL_B;
@@ -41,6 +54,17 @@ void B(void) {
// CIR-NEXT: ^bb1
// CIR: ]
+// OGCG: define dso_local void @B
+// OGCG: [[PTR:%.*]] = alloca ptr, align 8
+// OGCG: br label %LABEL_B
+// OGCG: LABEL_B: ; preds = %indirectgoto, %entry
+// OGCG: store ptr blockaddress(@B, %LABEL_B), ptr [[PTR]], align 8
+// OGCG: [[BLOCKADD:%.*]] = load ptr, ptr [[PTR]], align 8
+// OGCG: br label %indirectgoto
+// OGCG: indirectgoto: ; preds = %LABEL_B
+// OGCG: %indirect.goto.dest = phi ptr [ [[BLOCKADD]], %LABEL_B ]
+// OGCG: indirectbr ptr %indirect.goto.dest, [label %LABEL_B]
+
void C(int x) {
void *ptr = (x == 0) ? &&LABEL_A : &&LABEL_B;
goto *ptr;
@@ -71,6 +95,21 @@ void C(int x) {
// CIR: cir.label "LABEL_B"
// CIR: cir.br ^bb3
+// 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
+// OGCG: [[BLOCKADD:%.*]] = load ptr, ptr [[PTR]], align 8
+// OGCG: br label %indirectgoto
+// OGCG: LABEL_A: ; preds = %indirectgoto
+// OGCG: br label %return
+// OGCG: LABEL_B: ; preds = %indirectgoto
+// OGCG: br label %return
+// OGCG: return: ; preds = %LABEL_B, %LABEL_A
+// OGCG: ret void
+// OGCG: indirectgoto: ; preds = %entry
+// OGCG: %indirect.goto.dest = phi ptr [ [[BLOCKADD]], %entry ]
+// OGCG: indirectbr ptr %indirect.goto.dest, [label %LABEL_A, label %LABEL_B]
+
void D(void) {
void *ptr = &&LABEL_A;
void *ptr2 = &&LABEL_A;
@@ -101,6 +140,20 @@ void D(void) {
// CIR: cir.store align(8) %[[BLK3]], %[[PTR3]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
// CIR: cir.return
+// OGCG: define dso_local void @D
+// OGCG: %[[PTR:.*]] = alloca ptr, align 8
+// OGCG: %[[PTR2:.*]] = alloca ptr, align 8
+// OGCG: %[[PTR3:.*]] = alloca ptr, align 8
+// OGCG: store ptr blockaddress(@D, %LABEL_A), ptr %[[PTR]], align 8
+// OGCG: store ptr blockaddress(@D, %LABEL_A), ptr %[[PTR2]], align 8
+// OGCG: %[[BLOCKADD:.*]] = load ptr, ptr %[[PTR2]], align 8
+// OGCG: br label %indirectgoto
+// OGCG: LABEL_A: ; preds = %indirectgoto, %indirectgoto, %indirectgoto
+// OGCG: store ptr blockaddress(@D, %LABEL_A), ptr %[[PTR3]], align 8
+// OGCG: ret void
+// OGCG: indirectgoto: ; preds = %entry
+// OGCG: %indirect.goto.dest = phi ptr [ %[[BLOCKADD]], %entry ]
+// OGCG: indirectbr ptr %indirect.goto.dest, [label %LABEL_A, label %LABEL_A, label %LABEL_A]
// This test checks that CIR preserves insertion order of blockaddresses
// for indirectbr, even if some were resolved immediately and others later.
@@ -132,3 +185,20 @@ void E(void) {
//CIR: cir.label "LABEL_C"
//CIR: ^bb5: // 2 preds: ^bb1, ^bb4
//CIR: cir.label "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: br label %LABEL_B
+// OGCG: 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: br label %LABEL_D
+// OGCG: 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 16f6eea26e78d57c85ffa4a43837e37bd2bd3f94 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Mon, 1 Dec 2025 20:13:53 -0500
Subject: [PATCH 3/4] Format indirectbr TableGen
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 9293ce118d8a9..445a05550ca36 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1468,7 +1468,8 @@ def CIR_BrCondOp : CIR_Op<"brcond", [
def CIR_IndirectBrOp : CIR_Op<"indirectbr", [
DeclareOpInterfaceMethods<BranchOpInterface>,
- SameVariadicOperandSize, Terminator, Pure]> {
+ SameVariadicOperandSize, Terminator, Pure]
+> {
let summary = "Indirect branch";
let description = [{
The `cir.indirectbr` operation represents an indirect branch to one of
>From abe7c76de3af2c02d89dc1f25bcfff6fb7802ffe Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Tue, 2 Dec 2025 21:53:00 -0500
Subject: [PATCH 4/4] Apply reviews
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 33 ++++++--------------
clang/test/CIR/CodeGen/label-values.c | 12 +++----
clang/test/CIR/IR/indirect-br.cir | 4 +--
3 files changed, 18 insertions(+), 31 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 445a05550ca36..dc57d86ec7c30 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1466,10 +1466,10 @@ def CIR_BrCondOp : CIR_Op<"brcond", [
// IndirectBrOp
//===----------------------------------------------------------------------===//
-def CIR_IndirectBrOp : CIR_Op<"indirectbr", [
+def CIR_IndirectBrOp : CIR_Op<"indirect_br", [
DeclareOpInterfaceMethods<BranchOpInterface>,
- SameVariadicOperandSize, Terminator, Pure]
-> {
+ SameVariadicOperandSize, Terminator, Pure
+]> {
let summary = "Indirect branch";
let description = [{
The `cir.indirectbr` operation represents an indirect branch to one of
@@ -1486,22 +1486,9 @@ def CIR_IndirectBrOp : CIR_Op<"indirectbr", [
Example:
```mlir
- %0 = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["ptr", init]
- %1 = cir.block_address <@A, "A"> : !cir.ptr<!void>
- cir.store align(8) %1, %0 : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
- %2 = cir.load align(8) %0 : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
- cir.br ^bb1(%2 : !cir.ptr<!void>)
- ^bb1(%3: !cir.ptr<!void>):
- cir.indirectbr %3 : <!void>, [
- ^bb2
- ]
- ```
- or with a poison:
-
- ```mlir
+ %0 = cir.block_address <@A, "A"> : !cir.ptr<!void>
cir.indirectbr %0 poison : <!void>, [
- ^bb3,
- ^bb2
+ ^bb1
]
```
}];
@@ -1509,17 +1496,17 @@ def CIR_IndirectBrOp : CIR_Op<"indirectbr", [
let arguments = (ins
CIR_VoidPtrType:$addr,
UnitAttr:$poison,
- VariadicOfVariadic<AnyType, "indbr_operand_segments">:$succOperands,
- DenseI32ArrayAttr:$indbr_operand_segments
+ VariadicOfVariadic<AnyType, "operand_segments">:$succ_operands,
+ DenseI32ArrayAttr:$operand_segments
);
let successors = (successor VariadicSuccessor<AnySuccessor>:$successors);
let assemblyFormat = [{
- $addr ( `poison` $poison^ )? `:` type($addr) `,`
+ $addr ( `poison` $poison^ )? `:` qualified(type($addr)) `,`
custom<IndirectBrOpSucessors>(ref(type($addr)),
$successors,
- $succOperands,
- type($succOperands))
+ $succ_operands,
+ type($succ_operands))
attr-dict
}];
}
diff --git a/clang/test/CIR/CodeGen/label-values.c b/clang/test/CIR/CodeGen/label-values.c
index 29b07a74dcc37..750ef1f6889bf 100644
--- a/clang/test/CIR/CodeGen/label-values.c
+++ b/clang/test/CIR/CodeGen/label-values.c
@@ -16,7 +16,7 @@ void A(void) {
// CIR: [[BLOCKADD:%.*]] = cir.load align(8) [[PTR]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
// CIR: cir.br ^bb1([[BLOCKADD]] : !cir.ptr<!void>)
// CIR: ^bb1([[PHI:%.*]]: !cir.ptr<!void> {{.*}}): // pred: ^bb0
-// CIR: cir.indirectbr [[PHI]] : <!void>, [
+// CIR: cir.indirect_br [[PHI]] : !cir.ptr<!void>, [
// CIR: ^bb2
// CIR: ]
// CIR: ^bb2: // pred: ^bb1
@@ -50,7 +50,7 @@ void B(void) {
// CIR: [[BLOCKADD:%.*]] = cir.load align(8) [[PTR]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
// CIR: cir.br ^bb2([[BLOCKADD]] : !cir.ptr<!void>)
// CIR: ^bb2([[PHI:%.*]]: !cir.ptr<!void> {{.*}}): // pred: ^bb1
-// CIR: cir.indirectbr [[PHI]] : <!void>, [
+// CIR: cir.indirect_br [[PHI]] : !cir.ptr<!void>, [
// CIR-NEXT: ^bb1
// CIR: ]
@@ -82,7 +82,7 @@ void C(int x) {
// CIR: [[BLOCKADD:%.*]] = cir.load align(8) [[PTR]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
// CIR: cir.br ^bb1([[BLOCKADD]] : !cir.ptr<!void>)
// CIR: ^bb1([[PHI:%.*]]: !cir.ptr<!void> {{.*}}): // pred: ^bb0
-// CIR: cir.indirectbr [[PHI]] : <!void>, [
+// CIR: cir.indirect_br [[PHI]] : !cir.ptr<!void>, [
// CIR-NEXT: ^bb2,
// CIR-NEXT: ^bb4
// CIR: ]
@@ -129,7 +129,7 @@ void D(void) {
// CIR: cir.store align(8) %[[BLK2]], %[[PTR2]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
// CIR: cir.br ^bb1
// CIR: ^bb1([[PHI:%*.]]: !cir.ptr<!void> {{.*}}): // pred: ^bb0
-// CIR: cir.indirectbr [[PHI]] : <!void>, [
+// CIR: cir.indirect_br [[PHI]] : !cir.ptr<!void>, [
// CIR-DAG: ^bb2,
// CIR-DAG: ^bb2,
// CIR-DAG: ^bb2
@@ -169,9 +169,9 @@ void E(void) {
return;
}
-//CIR: cir.func dso_local @E()
+//CIR: cir.func {{.*}} @E()
//CIR: ^bb1({{.*}}: !cir.ptr<!void> {{.*}}): // no predecessors
-//CIR: cir.indirectbr {{.*}} poison : <!void>, [
+//CIR: cir.indirect_br {{.*}} poison : !cir.ptr<!void>, [
//CIR-NEXT: ^bb5,
//CIR-NEXT: ^bb4,
//CIR-NEXT: ^bb3,
diff --git a/clang/test/CIR/IR/indirect-br.cir b/clang/test/CIR/IR/indirect-br.cir
index e091e31dc3f5f..56c5ce99ef5a6 100644
--- a/clang/test/CIR/IR/indirect-br.cir
+++ b/clang/test/CIR/IR/indirect-br.cir
@@ -14,7 +14,7 @@ cir.func @E() {
%6 = cir.load align(8) %0 : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
cir.br ^bb1(%6 : !cir.ptr<!void>)
^bb1(%7: !cir.ptr<!void>): // pred: ^bb0
- cir.indirectbr %7 : <!void>, [
+ cir.indirect_br %7 : !cir.ptr<!void>, [
^bb5,
^bb4,
^bb3,
@@ -38,7 +38,7 @@ cir.func @E() {
cir.return
}
-// CHECK: cir.indirectbr %7 : <!void>, [
+// CHECK: cir.indirect_br %7 : !cir.ptr<!void>, [
// CHECK: ^bb5,
// CHECK: ^bb4,
// CHECK: ^bb3,
More information about the cfe-commits
mailing list