[clang] [CIR] Upstream support for cir.indirectBr (PR #169967)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Nov 28 16:41:53 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clangir
@llvm/pr-subscribers-clang
Author: None (Andres-Salamanca)
<details>
<summary>Changes</summary>
This PR upstreams support for the `cir.indirectBr` operation, which is used to implement GCC’s labels-as-values `indirect goto`.
To ensure correct lowering, we introduce precise bookkeeping to associate each `block_address` operation with its corresponding `label` op. This is required because a `block_address` may be emitted before the `label` it refers to. In such cases, the reference is deferred and later resolved by `resolveBlockAddresses`, which guarantees that all `indirectBr` successors are emitted in the correct and fully resolved order.
---
Patch is 25.35 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/169967.diff
12 Files Affected:
- (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+61)
- (modified) clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp (+15-4)
- (modified) clang/lib/CIR/CodeGen/CIRGenFunction.cpp (+53)
- (modified) clang/lib/CIR/CodeGen/CIRGenFunction.h (+12)
- (modified) clang/lib/CIR/CodeGen/CIRGenModule.cpp (+38)
- (modified) clang/lib/CIR/CodeGen/CIRGenModule.h (+17-1)
- (modified) clang/lib/CIR/CodeGen/CIRGenStmt.cpp (+19-2)
- (modified) clang/lib/CIR/Dialect/IR/CIRDialect.cpp (+59)
- (modified) clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp (+1-1)
- (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+6)
- (modified) clang/test/CIR/CodeGen/label-values.c (+73-14)
- (added) clang/test/CIR/IR/indirect-br.cir (+46)
``````````diff
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: ^bb...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/169967
More information about the cfe-commits
mailing list