Skip to content

Conversation

Andres-Salamanca
Copy link
Contributor

This PR introduces the cir.indirectbr operation to support GCC’s labels-as-values extension, which allows goto statements to jump to computed block addresses. The implementation creates a dedicated block that hosts the indirectbr, where the target address is provided through a PHI Node, similar to how classic code generation handles indirect gotos.

// made a zero entry PHI node, which is illegal, zap it now.
assert(!cir::MissingFeatures::indirectBranch() && "NYI");
// If a label address was taken but no indirect goto was used, we mark the
// 'indirectbr' as poison. During lowering, the associated PHI is removed,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MLIR does not use PHIs, comment needs update!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

// If a label address was taken but no indirect goto was used, we mark the
// 'indirectbr' as poison. During lowering, the associated PHI is removed,
// since the verifier does not allow a null addr.
if (indirectGotoBlock) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (indirectGotoBlock) {
// since the verifier does not allow a null addr.
if (indirectGotoBlock && indirectGotoBlock->hasNoPredecessors()) {
auto indrBr = cast<cir::IndirectBrOp>(indirectGotoBlock->front());
indrBr.setPoison(true);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

SmallVectorImpl<Block *> &succOperandBlocks,
SmallVectorImpl<SmallVector<OpAsmParser::UnresolvedOperand>> &succOperands,
SmallVectorImpl<SmallVector<Type>> &succOperandsTypes) {
if (failed(parser.parseCommaSeparatedList(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was there anything specific that you couldn't do in tablegen that required custom parsing / printing? If we can auto-generate that's always preferable

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got inspiration from cir.switch.flat, where we do something similar. As far as I know, there isn’t a way in TableGen to match each successor with its corresponding operand to handle cases like this:

cir.indirectbr %0 : <!void>, [
  ^bb2(%1 : !s32i),
  ^bb1
]

I also wanted to format it so that each successor appears on its own line. If you have an example of how this could be done in TableGen, I’d be happy to take a look.

Block *dest = op.getDest();

if (isa<cir::LabelOp>(dest->front()))
if (isa<cir::LabelOp, cir::IndirectBrOp>(dest->front()))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a test added for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, not explicitly, but there are tests that indirectly verify this. for example in this case, since the block containing the cir.indirectbr operation has only one predecessor, it was trying to merge ^bb1 into ^bb0. This is also done to maintain consistency with the classic codegen.

    cir.func dso_local @A() extra(#fn_attr) {
    %0 = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["ptr", init] {alignment = 8 : i64}
    %1 = cir.blockaddress <@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>):  // pred: ^bb0
    cir.indirectbr %3 : <!void>, [
    ^bb2
    ]
  ^bb2:  // pred: ^bb1
    cir.label "A"
    cir.return
  } 

// global codegen, followed by running CIR passes.
gen->HandleTranslationUnit(C);

// posiblya d a dump here for debug ?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like left overs

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops! 😖

} else {
targetAddr =
mlir::LLVM::PoisonOp::create(rewriter, op->getLoc(), llvmPtrType);
op->getBlock()->getArgument(0).dropAllUses();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why all drops and erasing needed? Please mention in a comment

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the drop wasn’t necessary, but erasing is, because when the block gets lowered it outputs something like:

%6 = phi ptr

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants