================
@@ -30,53 +30,113 @@ struct GotoSolverPass : public
impl::GotoSolverBase<GotoSolverPass> {
};
static void process(cir::FuncOp func,
- const llvm::StringSet<> &globalBlockAddrLabel) {
+ llvm::ArrayRef<StringRef> globalBlockAddrLabels) {
mlir::OpBuilder rewriter(func.getContext());
llvm::StringMap<Block *> labels;
llvm::SmallVector<cir::GotoOp, 4> gotos;
- llvm::SmallSet<StringRef, 4> blockAddrLabel;
+ llvm::SmallVector<cir::IndirectGotoOp> indirectGotos;
+ // Labels whose address is taken by a cir.block_address op in this function,
+ // in IR order.
+ llvm::SmallVector<StringRef> opBlockAddrLabels;
func.getBody().walk([&](mlir::Operation *op) {
if (auto lab = dyn_cast<cir::LabelOp>(op)) {
labels.try_emplace(lab.getLabel(), lab->getBlock());
} else if (auto goTo = dyn_cast<cir::GotoOp>(op)) {
gotos.push_back(goTo);
+ } else if (auto indirect = dyn_cast<cir::IndirectGotoOp>(op)) {
+ indirectGotos.push_back(indirect);
} else if (auto blockAddr = dyn_cast<cir::BlockAddressOp>(op)) {
- blockAddrLabel.insert(blockAddr.getBlockAddrInfo().getLabel());
+ opBlockAddrLabels.push_back(blockAddr.getBlockAddrInfo().getLabel());
}
});
+ // Address-taken labels in a deterministic order: those referenced from
+ // global initializers first (in initializer order), then those taken by a
+ // cir.block_address op (in IR order). A label may be named more than once
(a
+ // dispatch table can list it twice); a block only needs to be a successor
+ // once, so keep the first occurrence.
+ llvm::SmallVector<StringRef> addrTakenLabels;
+ llvm::StringSet<> addrTaken;
+ auto noteAddrTaken = [&](StringRef name) {
+ if (addrTaken.insert(name).second)
+ addrTakenLabels.push_back(name);
+ };
+ for (StringRef name : globalBlockAddrLabels)
+ noteAddrTaken(name);
+ for (StringRef name : opBlockAddrLabels)
+ noteAddrTaken(name);
+
+ // Drop LabelOps whose address is never taken; the rest may be
indirect-branch
+ // successors and must survive.
for (auto &lab : labels) {
- StringRef labelName = lab.getKey();
- Block *block = lab.getValue();
- // Keep labels whose address is taken either by a cir.block_address op in
- // this function or by a block-address attribute used elsewhere (e.g. in a
- // global initializer).
- if (!blockAddrLabel.contains(labelName) &&
- !globalBlockAddrLabel.contains(labelName)) {
- // erase the LabelOp inside the block if safe
- if (auto lab = dyn_cast<cir::LabelOp>(&block->front())) {
- lab.erase();
- }
+ if (!addrTaken.contains(lab.getKey())) {
+ if (auto labelOp = dyn_cast<cir::LabelOp>(&lab.getValue()->front()))
+ labelOp.erase();
}
}
+ // Resolve regular symbolic gotos to direct branches.
for (auto goTo : gotos) {
mlir::OpBuilder::InsertionGuard guard(rewriter);
rewriter.setInsertionPoint(goTo);
Block *dest = labels[goTo.getLabel()];
cir::BrOp::create(rewriter, goTo.getLoc(), dest);
goTo.erase();
}
+
+ // A label whose address is merely taken still emits its address constant; an
+ // indirect branch is only needed when the function actually branches with a
+ // `goto *expr`.
+ if (indirectGotos.empty())
+ return;
+
+ // Resolve indirect gotos. FlattenCFG has already merged the nested scopes
+ // into one region, so the shared indirect-branch block and its successors
all
+ // live in func's body now -- the cross-region branch that broke a nested
+ // `goto *` during CIRGen cannot arise here.
+ // The shared block represents every `goto *expr` that funnels into it, so
+ // fuse their locations when there is more than one.
+ llvm::SmallVector<mlir::Location> gotoLocs;
+ for (cir::IndirectGotoOp indirect : indirectGotos)
+ gotoLocs.push_back(indirect.getLoc());
+ mlir::Location loc = gotoLocs.size() == 1
+ ? gotoLocs.front()
+ : mlir::FusedLoc::get(func.getContext(), gotoLocs);
----------------
andykaylor wrote:
```suggestion
mlir::Location loc = mlir::FusedLoc::get(func.getContext(), gotoLocs);
```
A FusedLoc with one location is fine.
https://github.com/llvm/llvm-project/pull/206176
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits