-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[CIR] Upstream support for cir.indirectBr #169967
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
@llvm/pr-subscribers-clangir @llvm/pr-subscribers-clang Author: None (Andres-Salamanca) ChangesThis PR upstreams support for the 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:
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]
|
This PR upstreams support for the
cir.indirectBroperation, which is used to implement GCC’s labels-as-valuesindirect goto.To ensure correct lowering, we introduce precise bookkeeping to associate each
block_addressoperation with its correspondinglabelop. This is required because ablock_addressmay be emitted before thelabelit refers to. In such cases, the reference is deferred and later resolved byresolveBlockAddresses, which guarantees that allindirectBrsuccessors are emitted in the correct and fully resolved order.