https://github.com/Andres-Salamanca updated 
https://github.com/llvm/llvm-project/pull/169967

>From cd4fde36ffbe2b6d78687e45e1313ba03ffefd3a Mon Sep 17 00:00:00 2001
From: Andres Salamanca <[email protected]>
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         | 87 ++++++++++++++++---
 clang/test/CIR/IR/indirect-br.cir             | 46 ++++++++++
 12 files changed, 400 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 a19c4f951fff9..76d44c29b7da8 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1433,6 +1433,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 7c94743d5ffc6..d5bcafc9c81f4 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 33bdfa315a9ea..ed8663d51aa10 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 9adac089ea28b..f4b7cceef5f85 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -634,6 +634,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.
@@ -1360,6 +1368,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,
@@ -1543,6 +1553,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 809c24f8aa670..a9a1b300a79dd 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -2496,3 +2496,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 6600d086f8f61..fb1993c933cf2 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 6bf543cf794b7..b7d1a97185879 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -1116,6 +1116,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 6136d48204e0c..76ddc360206b5 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -4057,6 +4057,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 41178e3f62f20..2d773770910fe 100644
--- a/clang/test/CIR/CodeGen/label-values.c
+++ b/clang/test/CIR/CodeGen/label-values.c
@@ -3,38 +3,52 @@
 
 void A(void) {
   void *ptr = &&LABEL_A;
+  goto *ptr;
 LABEL_A:
   return;
 }
+
 // CIR:  cir.func dso_local @A
 // 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 dso_local @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 dso_local @C
@@ -42,19 +56,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 +90,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 dd563f8eeb5b64a9800b4dbb131f31b6f3442745 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <[email protected]>
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 76d44c29b7da8..e4724f5b41e04 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1438,8 +1438,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
@@ -1450,7 +1450,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 d5bcafc9c81f4..66c255130b1cd 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 ed8663d51aa10..173de03fe2191 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 f4b7cceef5f85..263ea6e51b6b5 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1368,7 +1368,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 a9a1b300a79dd..e431083d8ba5a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -2499,23 +2499,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 2d773770910fe..5a1f912ba3a3f 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;
@@ -22,6 +24,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;
@@ -42,6 +55,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;
@@ -72,6 +96,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;
@@ -102,6 +141,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.
@@ -133,3 +186,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 336ceff326c80456ada90be6d4b5d4b946e16369 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <[email protected]>
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 e4724f5b41e04..5bed913b0da6b 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1439,7 +1439,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 90dd12df84e3c0a6f5d9c939619ab13fb578a5f0 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <[email protected]>
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 5bed913b0da6b..cbda9147fec09 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1437,10 +1437,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
@@ -1457,22 +1457,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
       ]
     ```
   }];
@@ -1480,17 +1467,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 5a1f912ba3a3f..19fec90b9b18a 100644
--- a/clang/test/CIR/CodeGen/label-values.c
+++ b/clang/test/CIR/CodeGen/label-values.c
@@ -17,7 +17,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
@@ -51,7 +51,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:    ]
 
@@ -83,7 +83,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:    ]
@@ -130,7 +130,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
@@ -170,9 +170,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,

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to