Author: adams381
Date: 2026-06-25T17:51:19-05:00
New Revision: c5804067b7e622299d75ac420bdbac52c613c05c

URL: 
https://github.com/llvm/llvm-project/commit/c5804067b7e622299d75ac420bdbac52c613c05c
DIFF: 
https://github.com/llvm/llvm-project/commit/c5804067b7e622299d75ac420bdbac52c613c05c.diff

LOG: [CIR] Wire const goto labels into indirect branch (#201644)

A computed goto through a constant dispatch table -- the GNU static
dispatch-table idiom `static const void *tbl[] = {&&L1, &&L2}; goto *tbl[i];`
-- reached `errorNYI("Indirect goto without a goto block")` in
`emitIndirectGotoStmt`. #203644 emits the label-address constant (the
value-like `#cir.block_addr_info`) into the table, but it takes a label's
address in a constant context without registering the label as address-taken,
so no indirect-goto block exists for the following `goto *tbl[i]` to branch to.
(#203644 landed the constant attribute, its lowering, and the GotoSolver label
retention; this is the remaining dispatch wiring.)

`VisitAddrLabelExpr` in the constant emitter now records each label via
`takeAddressOfConstantLabel`, which instantiates the indirect-goto block and
tracks the label; `finishIndirectBranch` then adds those labels as
`cir.indirect_br` successors alongside the existing op-form labels. A label
named more than once in a table is kept as a distinct successor each time, to
match classic codegen.

Registering the label needs a non-const `CIRGenFunction`, so 
`VisitAddrLabelExpr`
`const_cast`s `emitter.cgf` -- the same thing classic Clang does
(`ConstantEmitter::CGF` is non-const), matching the existing cast at
`CIRGenExprConstant.cpp:929`.

New test `goto-address-label-table.c` covers CIR, the CIR-lowered LLVM, and
classic OGCG: a plain table, a duplicate-label table, a label whose address is
taken but never reached by a goto, and one reached through both a constant table
and a runtime block-address.

Added: 
    clang/test/CIR/CodeGen/goto-address-label-table.c

Modified: 
    clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
    clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
    clang/lib/CIR/CodeGen/CIRGenFunction.cpp
    clang/lib/CIR/CodeGen/CIRGenFunction.h
    clang/lib/CIR/CodeGen/CIRGenModule.cpp
    clang/lib/CIR/CodeGen/CIRGenModule.h
    clang/lib/CIR/CodeGen/CIRGenStmt.cpp
    clang/test/CIR/CodeGen/label-values.c

Removed: 
    


################################################################################
diff  --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
index c29b66ac2f8bc..eddb00c6fb2c1 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
@@ -1521,10 +1521,18 @@ ConstantLValueEmitter::VisitPredefinedExpr(const 
PredefinedExpr *e) {
 
 ConstantLValue
 ConstantLValueEmitter::VisitAddrLabelExpr(const AddrLabelExpr *e) {
-  auto func = cast<cir::FuncOp>(emitter.cgf->curFn);
-  return cir::BlockAddrInfoAttr::get(cgm.getBuilder().getContext(),
-                                     func.getSymName(),
-                                     e->getLabel()->getName());
+  // A label address taken in a constant context, e.g. a static computed-goto
+  // dispatch table `static const void *tbl[] = {&&L1, &&L2}`.  Besides 
emitting
+  // the constant, register the label as address-taken so a following
+  // `goto *tbl[i]` lists it among the indirect branch's successors.  A label 
is
+  // always function-local, so cgf is set here.
+  assert(emitter.cgf && "label address in a constant requires a function");
+  CIRGenFunction &cgf = *const_cast<CIRGenFunction *>(emitter.cgf);
+  auto func = cast<cir::FuncOp>(cgf.curFn);
+  cir::BlockAddrInfoAttr info = cir::BlockAddrInfoAttr::get(
+      &cgf.getMLIRContext(), func.getSymName(), e->getLabel()->getName());
+  cgf.indirectGotoTargets.push_back(info);
+  return info;
 }
 
 ConstantLValue ConstantLValueEmitter::VisitCallExpr(const CallExpr *e) {

diff  --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 5e8bb9df83ab3..774cfc8ef7ab6 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -211,16 +211,7 @@ class ScalarExprEmitter : public 
StmtVisitor<ScalarExprEmitter, mlir::Value> {
     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.instantiateIndirectGotoBlock();
+    cgf.indirectGotoTargets.push_back(blockInfoAttr);
     return blockAddressOp;
   }
 

diff  --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp 
b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 6606cf74c7dea..d0aedc0689404 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -604,48 +604,42 @@ 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() {
+  // The block is created on the first `goto *expr`, so if it is absent the
+  // function has no indirect goto and nothing needs wiring -- a label whose
+  // address is merely taken still emits its address constant on its own.
   if (!indirectGotoBlock)
     return;
-  llvm::SmallVector<mlir::Block *> succesors;
+
+  // Every label is emitted by now, so each address-taken label resolves to its
+  // LabelOp.  A label may be named more than once (a dispatch table can list 
it
+  // twice), but a block only needs to appear once in the successor list, so
+  // duplicates are dropped.
+  llvm::SmallVector<mlir::Block *> successors;
   llvm::SmallVector<mlir::ValueRange> rangeOperands;
+  llvm::SmallPtrSet<mlir::Block *, 8> seen;
+  for (cir::BlockAddrInfoAttr info : indirectGotoTargets) {
+    cir::LabelOp labelOp = cgm.lookupBlockAddressInfo(info);
+    assert(labelOp && "expected cir.label to be emitted for block address");
+    mlir::Block *dest = labelOp->getBlock();
+    if (!seen.insert(dest).second)
+      continue;
+    successors.push_back(dest);
+    rangeOperands.push_back(dest->getArguments());
+  }
+
   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();
+                            rangeOperands, successors);
+  indirectGotoTargets.clear();
 }
 
 void CIRGenFunction::finishFunction(SourceLocation endLoc) {
-  // Resolve block address-to-label mappings, then emit the indirect branch
-  // with the corresponding targets.
-  resolveBlockAddresses();
+  // Emit the indirect branch with all resolved label destinations.
   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

diff  --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 0ce6005ccac88..322355fde3957 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -725,12 +725,17 @@ class CIRGenFunction : public CIRGenTypeCache {
   };
 
   /// 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.
+  /// reserved for the indirect branch.  The actual `cir.indirect_br` is 
emitted
+  /// at the end of the function, once every label destination is known.
   mlir::Block *indirectGotoBlock = nullptr;
 
-  void resolveBlockAddresses();
+  /// Labels whose address is taken in this function (via `&&label`, as either
+  /// an operation or a constant initializer).  The indirect branch block is
+  /// created lazily on the first `goto *expr`; these targets are resolved to
+  /// their LabelOps and wired as `cir.indirect_br` successors in
+  /// finishIndirectBranch.
+  llvm::SmallVector<cir::BlockAddrInfoAttr> indirectGotoTargets;
+
   void finishIndirectBranch();
 
   /// Perform the usual unary conversions on the specified expression and

diff  --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp 
b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 3f71b0013be62..69dfadf58aa49 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -3881,29 +3881,6 @@ void 
CIRGenModule::mapBlockAddress(cir::BlockAddrInfoAttr blockInfo,
          "attempting to map a blockaddress info that is already mapped");
 }
 
-void CIRGenModule::mapUnresolvedBlockAddress(cir::BlockAddressOp op) {
-  [[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) {
-  [[maybe_unused]] auto result = blockAddressToLabel.try_emplace(op, label);
-  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 c6fef5dde5fd9..144f8c7b9f3e7 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -195,19 +195,8 @@ class CIRGenModule : public CIRGenTypeCache {
   /// 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);
 
   /// Add a global value to the llvmUsed list.
   void addUsedGlobal(cir::CIRGlobalValueInterface gv);

diff  --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp 
b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index a2c999f584399..d3acac5801e74 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -707,13 +707,10 @@ mlir::LogicalResult CIRGenFunction::emitGotoStmt(const 
clang::GotoStmt &s) {
 mlir::LogicalResult
 CIRGenFunction::emitIndirectGotoStmt(const IndirectGotoStmt &s) {
   mlir::Value val = emitScalarExpr(s.getTarget());
-  if (!indirectGotoBlock) {
-    // If the target labels were emitted as constants, we have more work to do.
-    // This diagnostic is here to flag the condition, but the changes may end
-    // up being implemented elsewhere.
-    cgm.errorNYI(s.getSourceRange(), "Indirect goto without a goto block");
-    return mlir::failure();
-  }
+  // Create the shared indirect-branch block on first use.  Its successors are
+  // every address-taken label, wired in finishIndirectBranch once all labels
+  // are emitted.
+  instantiateIndirectGotoBlock();
   cir::BrOp::create(builder, getLoc(s.getSourceRange()), indirectGotoBlock,
                     val);
   builder.createBlock(builder.getBlock()->getParent());

diff  --git a/clang/test/CIR/CodeGen/goto-address-label-table.c 
b/clang/test/CIR/CodeGen/goto-address-label-table.c
new file mode 100644
index 0000000000000..2e273a7c392e9
--- /dev/null
+++ b/clang/test/CIR/CodeGen/goto-address-label-table.c
@@ -0,0 +1,104 @@
+// 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-prefixes=LLVM,LLVMCIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s --check-prefixes=LLVM,OGCG
+
+// CIR-DAG: cir.global "private" internal dso_local @f.tbl = 
#cir.const_array<[#cir.block_addr_info<@f, "L1"> : !cir.ptr<!void>, 
#cir.block_addr_info<@f, "L2"> : !cir.ptr<!void>]> : !cir.array<!cir.ptr<!void> 
x 2>
+// CIR-DAG: cir.global "private" internal dso_local @g.tbl = 
#cir.const_array<[#cir.block_addr_info<@g, "A"> : !cir.ptr<!void>, 
#cir.block_addr_info<@g, "A"> : !cir.ptr<!void>, #cir.block_addr_info<@g, "B"> 
: !cir.ptr<!void>]> : !cir.array<!cir.ptr<!void> x 3>
+// CIR-DAG: cir.global "private" internal dso_local @h.tbl = 
#cir.const_array<[#cir.block_addr_info<@h, "L1"> : !cir.ptr<!void>]> : 
!cir.array<!cir.ptr<!void> x 1>
+// CIR-DAG: cir.global "private" internal dso_local @m.ctbl = 
#cir.const_array<[#cir.block_addr_info<@m, "A2"> : !cir.ptr<!void>]> : 
!cir.array<!cir.ptr<!void> x 1>
+
+// LLVM-DAG: @f.tbl = internal global [2 x ptr] [ptr blockaddress(@f, 
%[[FL1:[0-9a-zA-Z_.]+]]), ptr blockaddress(@f, %[[FL2:[0-9a-zA-Z_.]+]])], align 
16
+// LLVM-DAG: @g.tbl = internal global [3 x ptr] [ptr blockaddress(@g, 
%[[GA:[0-9a-zA-Z_.]+]]), ptr blockaddress(@g, %[[GA]]), ptr blockaddress(@g, 
%[[GB:[0-9a-zA-Z_.]+]])], align 16
+// LLVM-DAG: @h.tbl = internal global [1 x ptr] [ptr blockaddress(@h, 
%{{[0-9a-zA-Z_.]+}})], align 8
+// LLVM-DAG: @m.ctbl = internal global [1 x ptr] [ptr blockaddress(@m, 
%[[MA2:[0-9a-zA-Z_.]+]])], align 8
+
+int f(int x) {
+  static const void *tbl[] = {&&L1, &&L2};
+  goto *tbl[x];
+L1:
+  return 1;
+L2:
+  return 2;
+}
+
+// CIR-LABEL: cir.func {{.*}} @f
+// CIR:   %[[TBL:.*]] = cir.get_global @f.tbl
+// CIR:   cir.indirect_br %{{.*}} : !cir.ptr<!void>, [
+// CIR-NEXT: ^[[L1BB:.*]],
+// CIR-NEXT: ^[[L2BB:.*]]
+// CIR:   ]
+// CIR: ^[[L1BB]]:
+// CIR:   cir.label "L1"
+// CIR: ^[[L2BB]]:
+// CIR:   cir.label "L2"
+
+// LLVM-LABEL: define dso_local i32 @f(
+// LLVM:   indirectbr ptr %{{.*}}, [label %[[FL1]], label %[[FL2]]]
+
+// A appears twice in g's table, but a block only needs to be listed once as an
+// indirect-branch successor, so CIR drops the duplicate (classic keeps it).
+int g(int x) {
+  static const void *tbl[] = {&&A, &&A, &&B};
+  goto *tbl[x];
+A:
+  return 1;
+B:
+  return 2;
+}
+
+// CIR-LABEL: cir.func {{.*}} @g
+// CIR:   cir.indirect_br %{{.*}} : !cir.ptr<!void>, [
+// CIR-NEXT: ^[[ABB:.*]],
+// CIR-NEXT: ^[[BBB:.*]]
+// CIR:   ]
+// CIR: ^[[ABB]]:
+// CIR:   cir.label "A"
+// CIR: ^[[BBB]]:
+// CIR:   cir.label "B"
+
+// LLVM-LABEL: define dso_local i32 @g(
+// LLVMCIR:   indirectbr ptr %{{.*}}, [label %[[GA]], label %[[GB]]]
+// OGCG:   indirectbr ptr %{{.*}}, [label %[[GA]], label %[[GA]], label 
%[[GB]]]
+
+// h takes a label address but never executes a `goto *`, so CIR emits no
+// indirect branch (classic still emits a dead poisoned indirectbr).
+int h(int x) {
+  static const void *tbl[] = {&&L1};
+  (void)tbl;
+  return x;
+L1:
+  return 0;
+}
+
+// CIR-LABEL: cir.func {{.*}} @h
+// CIR-NOT: cir.indirect_br
+
+// LLVM-LABEL: define dso_local i32 @h(
+// LLVMCIR-NOT: indirectbr
+// OGCG:   indirectbr ptr poison, [label %{{.+}}]
+
+// A2's address comes from a constant table, B2's from a runtime block-address
+// op; both feed the same indirect branch.
+int m(int sel) {
+  static const void *ctbl[] = {&&A2};
+  void *p = &&B2;
+  void *t = (void *)ctbl[0];
+  void *dest = sel ? t : p;
+  goto *dest;
+A2:
+  return 1;
+B2:
+  return 2;
+}
+
+// CIR-LABEL: cir.func {{.*}} @m
+// CIR:   cir.block_address <@m, "B2">
+// CIR:   cir.indirect_br
+// CIR-DAG:   cir.label "A2"
+// CIR-DAG:   cir.label "B2"
+
+// LLVM-LABEL: define dso_local i32 @m(
+// LLVM:   indirectbr ptr %{{.*}}, [label %[[MA2]], label %{{.+}}]

diff  --git a/clang/test/CIR/CodeGen/label-values.c 
b/clang/test/CIR/CodeGen/label-values.c
index cd54d91a57e9a..f2bc5aa5a549f 100644
--- a/clang/test/CIR/CodeGen/label-values.c
+++ b/clang/test/CIR/CodeGen/label-values.c
@@ -165,11 +165,9 @@ void D(void) {
 // CIR:    cir.br ^bb1
 // CIR:  ^bb1([[PHI:%*.]]: !cir.ptr<!void> {{.*}}):  // pred: ^bb0
 // CIR:    cir.indirect_br [[PHI]] : !cir.ptr<!void>, [
-// CIR-DAG:    ^bb2,
-// CIR-DAG:    ^bb2,
-// CIR-DAG:    ^bb2
+// CIR-NEXT:    ^bb2
 // CIR:    ]
-// CIR:  ^bb2:  // 3 preds: ^bb1, ^bb1, ^bb1
+// CIR:  ^bb2:  // pred: ^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>>
@@ -185,7 +183,7 @@ void D(void) {
 // 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:   indirectbr ptr [[PHI]], [label %[[LABEL_A]]]
 // LLVM: [[LABEL_A]]:
 // LLVM:   store ptr blockaddress(@D, %[[LABEL_A]]), ptr %[[PTR3]], align 8
 // LLVM:   ret void
@@ -205,8 +203,8 @@ void D(void) {
 // 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.
+// E takes label addresses but never executes a `goto *`, so CIR emits no
+// indirect branch (classic still emits a dead poisoned indirectbr, see OGCG).
 void E(void) {
   void *ptr = &&LABEL_D;
   void *ptr2 = &&LABEL_C;
@@ -219,38 +217,11 @@ void E(void) {
   return;
 }
 
-//CIR:  cir.func {{.*}} @E()
-//CIR:  ^bb1({{.*}}: !cir.ptr<!void> {{.*}}):  // no predecessors
-//CIR:    cir.indirect_br {{.*}} poison : !cir.ptr<!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"
+// CIR-LABEL: cir.func {{.*}} @E()
+// CIR-NOT:   cir.indirect_br
 
-// 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]]:
+// LLVM-LABEL: define dso_local void @E()
+// LLVM-NOT:   indirectbr
 
 // OGCG: define dso_local void @E() #0 {
 // OGCG:   store ptr blockaddress(@E, %LABEL_D), ptr %ptr, align 8


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

Reply via email to