[flang-commits] [flang] d68dc18 - [flang][PFT] record every target of an assigned GO TO (#210065)

via flang-commits flang-commits at lists.llvm.org
Fri Jul 17 00:16:33 PDT 2026


Author: Kareem Ergawy
Date: 2026-07-17T09:16:28+02:00
New Revision: d68dc184b1cec0a01876b3f635bce6c25a64edf6

URL: https://github.com/llvm/llvm-project/commit/d68dc184b1cec0a01876b3f635bce6c25a64edf6
DIFF: https://github.com/llvm/llvm-project/commit/d68dc184b1cec0a01876b3f635bce6c25a64edf6.diff

LOG: [flang][PFT] record every target of an assigned GO TO (#210065)

Assigned GO TO (`go to v [, (l1, l2, ...)]`) is the third multiway
branch in the language, alongside the computed GO TO and arithmetic IF
that were addressed in PR #210012. Its PFTBuilder handler previously
did:

    [&](const parser::AssignedGotoStmt &) {
      eval.isUnstructured = true;
      markSuccessorAsNewBlock(eval);
    },

i.e. it recorded no branch targets at all -- neither `controlSuccessor`
nor `extraControlSuccessors` was populated.

Handle the assigned GO TO the same way PR #210012 handles the computed
GO TO and arithmetic IF: iterate every possible target and call
`markBranchTarget(eval, label)` for each, so that `controlSuccessor`
receives the first and `extraControlSuccessors` receives the rest.

Co-authored-by: Claude Sonnet 4.6 <noreply at anthropic.com>

Added: 
    flang/test/Lower/pre-fir-tree-assigned-goto.f90

Modified: 
    flang/lib/Lower/PFTBuilder.cpp

Removed: 
    


################################################################################
diff  --git a/flang/lib/Lower/PFTBuilder.cpp b/flang/lib/Lower/PFTBuilder.cpp
index 3a0c0c3d71075..ef86897a2bcc1 100644
--- a/flang/lib/Lower/PFTBuilder.cpp
+++ b/flang/lib/Lower/PFTBuilder.cpp
@@ -1039,10 +1039,29 @@ class PFTBuilder {
               iter->second.insert(label);
             }
           },
-          [&](const parser::AssignedGotoStmt &) {
-            // Although this statement is a branch, it doesn't have any
-            // explicit control successors. So the code at the end of the
-            // loop won't mark the successor. Do that here.
+          [&](const parser::AssignedGotoStmt &s) {
+            // Mark every possible target of the assigned GO TO so that
+            // wrappability analyses (branchesAreInternal, hasIncomingBranch)
+            // can see any escape from an enclosing construct.
+            const auto &labelList = std::get<std::list<parser::Label>>(s.t);
+            if (!labelList.empty()) {
+              // Explicit target list: `go to v, (l1, l2, ...)`.
+              for (const auto &label : labelList)
+                markBranchTarget(eval, label);
+            } else {
+              // No explicit list (`go to v`): fall back to the set of labels
+              // that have been previously ASSIGN'd to v.
+              // TODO: This may miss assignments that appear later in program
+              // order, but it matches the information available at this point
+              // in the walk.
+              const auto *sym = std::get<parser::Name>(s.t).symbol;
+              if (sym) {
+                auto iter = assignSymbolLabelMap->find(*sym);
+                if (iter != assignSymbolLabelMap->end())
+                  for (auto label : iter->second)
+                    markBranchTarget(eval, label);
+              }
+            }
             eval.isUnstructured = true;
             markSuccessorAsNewBlock(eval);
           },

diff  --git a/flang/test/Lower/pre-fir-tree-assigned-goto.f90 b/flang/test/Lower/pre-fir-tree-assigned-goto.f90
new file mode 100644
index 0000000000000..757a838d592b8
--- /dev/null
+++ b/flang/test/Lower/pre-fir-tree-assigned-goto.f90
@@ -0,0 +1,47 @@
+! RUN: bbc -pft-test -o %t %s | FileCheck %s
+
+! Verify that assigned GO TO records every reachable branch target on the
+! source evaluation, so wrappability analyses see any escape from an
+! enclosing DO/IF construct.  The dumper prints the first target after
+! "->" and any additional targets after commas -- same convention as the
+! computed GO TO and arithmetic IF coverage in
+! pre-fir-tree-multiway-branch.f90.
+!
+! Two source forms are exercised:
+!   1. `go to v, (l1, l2, ...)` -- targets come from the explicit label list.
+!   2. `go to v`                -- targets come from labels previously
+!                                  ASSIGN'd to `v` (assignSymbolLabelMap).
+
+! CHECK-LABEL: Subroutine assigned_goto_with_list
+subroutine assigned_goto_with_list(j)
+  integer :: j
+  assign 10 to j
+  ! CHECK: AssignedGotoStmt{{.*}} -> {{[0-9]+}}, {{[0-9]+}}:
+  go to j, (10, 20)
+10 print *, "ten"
+20 print *, "twenty"
+end subroutine
+
+! CHECK-LABEL: Subroutine assigned_goto_no_list
+subroutine assigned_goto_no_list(j)
+  integer :: j
+  assign 10 to j
+  assign 20 to j
+  ! CHECK: AssignedGotoStmt{{.*}} -> {{[0-9]+}}, {{[0-9]+}}:
+  go to j
+10 print *, "ten"
+20 print *, "twenty"
+end subroutine
+
+! CHECK-LABEL: Subroutine assigned_goto_repeated_label
+subroutine assigned_goto_repeated_label(j)
+  integer :: j
+  assign 10 to j
+  ! The label list repeats 10.  Dedup means the source lists exactly two
+  ! distinct successors, not three -- the trailing ':' anchors the check so
+  ! a third comma-separated target would fail the match.
+  ! CHECK: AssignedGotoStmt{{.*}} -> {{[0-9]+}}, {{[0-9]+}}:
+  go to j, (10, 10, 20)
+10 print *, "ten"
+20 print *, "twenty"
+end subroutine


        


More information about the flang-commits mailing list