================
@@ -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

Reply via email to