[flang-commits] [flang] [flang] Add support for lowering directives at the CONTAINS level (PR #95123)

via flang-commits flang-commits at lists.llvm.org
Tue Jun 11 07:55:21 PDT 2024


https://github.com/vdonaldson updated https://github.com/llvm/llvm-project/pull/95123

>From 18211e7b01fbf88e075fb299cc780b6449e1eadc Mon Sep 17 00:00:00 2001
From: V Donaldson <vdonaldson at nvidia.com>
Date: Mon, 10 Jun 2024 14:13:05 -0700
Subject: [PATCH 1/2] [flang] Add support for lowering directives at the
 CONTAINS level

There is currently support for lowering directives that appear outside
of a module or procedure, or inside the body of a module or procedure.
Extend this to support directives at the CONTAINS level of a module or
procedure, such as directives 3, 5, 7 9, and 10 in:

    !dir$ some directive 1
    module m
      !dir$ some directive 2
    contains
      !dir$ some directive 3
      subroutine p
        !dir$ some directive 4
      contains
        !dir$ some directive 5
        subroutine s1
          !dir$ some directive 6
        end subroutine s1
        !dir$ some directive 7
        subroutine s2
          !dir$ some directive 8
        end subroutine s2
        !dir$ some directive 9
      end subroutine p
      !dir$ some directive 10
    end module m
    !dir$ some directive 11

This is done by looking for CONTAINS statements at the module or
procedure level, while ignoring CONTAINS statements at the derived
type level.
---
 flang/include/flang/Lower/PFTBuilder.h |  17 +--
 flang/lib/Lower/Bridge.cpp             |  68 ++++++-----
 flang/lib/Lower/PFTBuilder.cpp         | 149 ++++++++++++++++---------
 flang/test/Lower/pre-fir-tree09.f90    | 100 +++++++++++++++++
 4 files changed, 243 insertions(+), 91 deletions(-)
 create mode 100644 flang/test/Lower/pre-fir-tree09.f90

diff --git a/flang/include/flang/Lower/PFTBuilder.h b/flang/include/flang/Lower/PFTBuilder.h
index 9913f584133fa..83200eb6351a8 100644
--- a/flang/include/flang/Lower/PFTBuilder.h
+++ b/flang/include/flang/Lower/PFTBuilder.h
@@ -31,11 +31,14 @@
 
 namespace Fortran::lower::pft {
 
+struct CompilerDirectiveUnit;
 struct Evaluation;
-struct Program;
-struct ModuleLikeUnit;
 struct FunctionLikeUnit;
+struct ModuleLikeUnit;
+struct Program;
 
+using ContainedUnit = std::variant<CompilerDirectiveUnit, FunctionLikeUnit>;
+using ContainedUnitList = std::list<ContainedUnit>;
 using EvaluationList = std::list<Evaluation>;
 
 /// Provide a variant like container that can hold references. It can hold
@@ -594,8 +597,8 @@ VariableList getDependentVariableList(const Fortran::semantics::Symbol &);
 
 void dump(VariableList &, std::string s = {}); // `s` is an optional dump label
 
-/// Function-like units may contain evaluations (executable statements) and
-/// nested function-like units (internal procedures and function statements).
+/// Function-like units may contain evaluations (executable statements),
+/// directives, and internal (nested) function-like units.
 struct FunctionLikeUnit : public ProgramUnit {
   // wrapper statements for function-like syntactic structures
   using FunctionStatement =
@@ -697,10 +700,10 @@ struct FunctionLikeUnit : public ProgramUnit {
   std::optional<FunctionStatement> beginStmt;
   FunctionStatement endStmt;
   const semantics::Scope *scope;
-  EvaluationList evaluationList;
   LabelEvalMap labelEvaluationMap;
   SymbolLabelMap assignSymbolLabelMap;
-  std::list<FunctionLikeUnit> nestedFunctions;
+  ContainedUnitList containedUnitList;
+  EvaluationList evaluationList;
   /// <Symbol, Evaluation> pairs for each entry point. The pair at index 0
   /// is the primary entry point; remaining pairs are alternate entry points.
   /// The primary entry point symbol is Null for an anonymous program.
@@ -746,7 +749,7 @@ struct ModuleLikeUnit : public ProgramUnit {
 
   ModuleStatement beginStmt;
   ModuleStatement endStmt;
-  std::list<FunctionLikeUnit> nestedFunctions;
+  ContainedUnitList containedUnitList;
   EvaluationList evaluationList;
 };
 
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 202efa57d4a36..9ecbbc73dce07 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -302,28 +302,32 @@ class FirConverter : public Fortran::lower::AbstractConverter {
     bool hasMainProgram = false;
     const Fortran::semantics::Symbol *globalOmpRequiresSymbol = nullptr;
     for (Fortran::lower::pft::Program::Units &u : pft.getUnits()) {
-      std::visit(Fortran::common::visitors{
-                     [&](Fortran::lower::pft::FunctionLikeUnit &f) {
-                       if (f.isMainProgram())
-                         hasMainProgram = true;
-                       declareFunction(f);
-                       if (!globalOmpRequiresSymbol)
-                         globalOmpRequiresSymbol = f.getScope().symbol();
-                     },
-                     [&](Fortran::lower::pft::ModuleLikeUnit &m) {
-                       lowerModuleDeclScope(m);
-                       for (Fortran::lower::pft::FunctionLikeUnit &f :
-                            m.nestedFunctions)
-                         declareFunction(f);
-                     },
-                     [&](Fortran::lower::pft::BlockDataUnit &b) {
-                       if (!globalOmpRequiresSymbol)
-                         globalOmpRequiresSymbol = b.symTab.symbol();
-                     },
-                     [&](Fortran::lower::pft::CompilerDirectiveUnit &d) {},
-                     [&](Fortran::lower::pft::OpenACCDirectiveUnit &d) {},
-                 },
-                 u);
+      std::visit(
+          Fortran::common::visitors{
+              [&](Fortran::lower::pft::FunctionLikeUnit &f) {
+                if (f.isMainProgram())
+                  hasMainProgram = true;
+                declareFunction(f);
+                if (!globalOmpRequiresSymbol)
+                  globalOmpRequiresSymbol = f.getScope().symbol();
+              },
+              [&](Fortran::lower::pft::ModuleLikeUnit &m) {
+                lowerModuleDeclScope(m);
+                for (Fortran::lower::pft::ContainedUnit &unit :
+                     m.containedUnitList)
+                  if (auto *f =
+                          std::get_if<Fortran::lower::pft::FunctionLikeUnit>(
+                              &unit))
+                    declareFunction(*f);
+              },
+              [&](Fortran::lower::pft::BlockDataUnit &b) {
+                if (!globalOmpRequiresSymbol)
+                  globalOmpRequiresSymbol = b.symTab.symbol();
+              },
+              [&](Fortran::lower::pft::CompilerDirectiveUnit &d) {},
+              [&](Fortran::lower::pft::OpenACCDirectiveUnit &d) {},
+          },
+          u);
     }
 
     // Create definitions of intrinsic module constants.
@@ -387,13 +391,15 @@ class FirConverter : public Fortran::lower::AbstractConverter {
 
     // Compute the set of host associated entities from the nested functions.
     llvm::SetVector<const Fortran::semantics::Symbol *> escapeHost;
-    for (Fortran::lower::pft::FunctionLikeUnit &f : funit.nestedFunctions)
-      collectHostAssociatedVariables(f, escapeHost);
+    for (Fortran::lower::pft::ContainedUnit &unit : funit.containedUnitList)
+      if (auto *f = std::get_if<Fortran::lower::pft::FunctionLikeUnit>(&unit))
+        collectHostAssociatedVariables(*f, escapeHost);
     funit.setHostAssociatedSymbols(escapeHost);
 
     // Declare internal procedures
-    for (Fortran::lower::pft::FunctionLikeUnit &f : funit.nestedFunctions)
-      declareFunction(f);
+    for (Fortran::lower::pft::ContainedUnit &unit : funit.containedUnitList)
+      if (auto *f = std::get_if<Fortran::lower::pft::FunctionLikeUnit>(&unit))
+        declareFunction(*f);
   }
 
   /// Get the scope that is defining or using \p sym. The returned scope is not
@@ -5356,8 +5362,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
       endNewFunction(funit);
     }
     funit.setActiveEntry(0);
-    for (Fortran::lower::pft::FunctionLikeUnit &f : funit.nestedFunctions)
-      lowerFunc(f); // internal procedure
+    for (Fortran::lower::pft::ContainedUnit &unit : funit.containedUnitList)
+      if (auto *f = std::get_if<Fortran::lower::pft::FunctionLikeUnit>(&unit))
+        lowerFunc(*f); // internal procedure
   }
 
   /// Lower module variable definitions to fir::globalOp and OpenMP/OpenACC
@@ -5381,8 +5388,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
 
   /// Lower functions contained in a module.
   void lowerMod(Fortran::lower::pft::ModuleLikeUnit &mod) {
-    for (Fortran::lower::pft::FunctionLikeUnit &f : mod.nestedFunctions)
-      lowerFunc(f);
+    for (Fortran::lower::pft::ContainedUnit &unit : mod.containedUnitList)
+      if (auto *f = std::get_if<Fortran::lower::pft::FunctionLikeUnit>(&unit))
+        lowerFunc(*f);
   }
 
   void setCurrentPosition(const Fortran::parser::CharBlock &position) {
diff --git a/flang/lib/Lower/PFTBuilder.cpp b/flang/lib/Lower/PFTBuilder.cpp
index f196b9c5a0cbc..df2c31381a0e7 100644
--- a/flang/lib/Lower/PFTBuilder.cpp
+++ b/flang/lib/Lower/PFTBuilder.cpp
@@ -209,6 +209,20 @@ class PFTBuilder {
     }
   }
 
+  bool Pre(const parser::SpecificationPart &) {
+    ++specificationPartLevel;
+    return true;
+  }
+  void Post(const parser::SpecificationPart &) { --specificationPartLevel; }
+
+  bool Pre(const parser::ContainsStmt &) {
+    if (!specificationPartLevel) {
+      assert(containsStmtStack.size() && "empty contains stack");
+      containsStmtStack.back() = true;
+    }
+    return false;
+  }
+
   // Module like
   bool Pre(const parser::Module &node) { return enterModule(node); }
   bool Pre(const parser::Submodule &node) { return enterModule(node); }
@@ -249,15 +263,21 @@ class PFTBuilder {
         whereBody.u);
   }
 
-  // CompilerDirective have special handling in case they are top level
-  // directives (i.e. they do not belong to a ProgramUnit).
+  // A CompilerDirective may appear outside any program unit, after a module
+  // or function contains statement, or inside a module or function.
   bool Pre(const parser::CompilerDirective &directive) {
-    assert(pftParentStack.size() > 0 &&
-           "At least the Program must be a parent");
-    if (pftParentStack.back().isA<lower::pft::Program>()) {
-      addUnit(
-          lower::pft::CompilerDirectiveUnit(directive, pftParentStack.back()));
+    assert(pftParentStack.size() > 0 && "no program");
+    lower::pft::PftNode &node = pftParentStack.back();
+    if (node.isA<lower::pft::Program>()) {
+      addUnit(lower::pft::CompilerDirectiveUnit(directive, node));
       return false;
+    } else if ((node.isA<lower::pft::ModuleLikeUnit>() ||
+                node.isA<lower::pft::FunctionLikeUnit>())) {
+      assert(containsStmtStack.size() && "empty contains stack");
+      if (containsStmtStack.back()) {
+        addContainedUnit(lower::pft::CompilerDirectiveUnit{directive, node});
+        return false;
+      }
     }
     return enterConstructOrDirective(directive);
   }
@@ -277,9 +297,10 @@ class PFTBuilder {
   /// Initialize a new module-like unit and make it the builder's focus.
   template <typename A>
   bool enterModule(const A &mod) {
-    Fortran::lower::pft::ModuleLikeUnit &unit =
+    lower::pft::ModuleLikeUnit &unit =
         addUnit(lower::pft::ModuleLikeUnit{mod, pftParentStack.back()});
-    functionList = &unit.nestedFunctions;
+    containsStmtStack.push_back(false);
+    containedUnitList = &unit.containedUnitList;
     pushEvaluationList(&unit.evaluationList);
     pftParentStack.emplace_back(unit);
     LLVM_DEBUG(dumpScope(&unit.getScope()));
@@ -287,6 +308,7 @@ class PFTBuilder {
   }
 
   void exitModule() {
+    containsStmtStack.pop_back();
     if (!evaluationListStack.empty())
       popEvaluationList();
     pftParentStack.pop_back();
@@ -344,12 +366,13 @@ class PFTBuilder {
                      const semantics::SemanticsContext &semanticsContext) {
     cleanModuleEvaluationList();
     endFunctionBody(); // enclosing host subprogram body, if any
-    Fortran::lower::pft::FunctionLikeUnit &unit =
-        addFunction(lower::pft::FunctionLikeUnit{func, pftParentStack.back(),
-                                                 semanticsContext});
+    lower::pft::FunctionLikeUnit &unit =
+        addContainedUnit(lower::pft::FunctionLikeUnit{
+            func, pftParentStack.back(), semanticsContext});
     labelEvaluationMap = &unit.labelEvaluationMap;
     assignSymbolLabelMap = &unit.assignSymbolLabelMap;
-    functionList = &unit.nestedFunctions;
+    containsStmtStack.push_back(false);
+    containedUnitList = &unit.containedUnitList;
     pushEvaluationList(&unit.evaluationList);
     pftParentStack.emplace_back(unit);
     LLVM_DEBUG(dumpScope(&unit.getScope()));
@@ -361,6 +384,7 @@ class PFTBuilder {
     endFunctionBody();
     analyzeBranches(nullptr, *evaluationListStack.back()); // add branch links
     processEntryPoints();
+    containsStmtStack.pop_back();
     popEvaluationList();
     labelEvaluationMap = nullptr;
     assignSymbolLabelMap = nullptr;
@@ -371,7 +395,7 @@ class PFTBuilder {
   /// Initialize a new construct or directive and make it the builder's focus.
   template <typename A>
   bool enterConstructOrDirective(const A &constructOrDirective) {
-    Fortran::lower::pft::Evaluation &eval = addEvaluation(
+    lower::pft::Evaluation &eval = addEvaluation(
         lower::pft::Evaluation{constructOrDirective, pftParentStack.back()});
     eval.evaluationList.reset(new lower::pft::EvaluationList);
     pushEvaluationList(eval.evaluationList.get());
@@ -381,7 +405,7 @@ class PFTBuilder {
   }
 
   void exitConstructOrDirective() {
-    auto isOpenMPLoopConstruct = [](Fortran::lower::pft::Evaluation *eval) {
+    auto isOpenMPLoopConstruct = [](lower::pft::Evaluation *eval) {
       if (const auto *ompConstruct = eval->getIf<parser::OpenMPConstruct>())
         if (std::holds_alternative<parser::OpenMPLoopConstruct>(
                 ompConstruct->u))
@@ -396,8 +420,7 @@ class PFTBuilder {
       // construct region must have an exit target inside the region.
       // This is not applicable to the OpenMP loop construct since the
       // end of the loop is an available target inside the region.
-      Fortran::lower::pft::EvaluationList &evaluationList =
-          *eval->evaluationList;
+      lower::pft::EvaluationList &evaluationList = *eval->evaluationList;
       if (!evaluationList.empty() && evaluationList.back().isConstruct()) {
         static const parser::ContinueStmt exitTarget{};
         addEvaluation(
@@ -413,15 +436,15 @@ class PFTBuilder {
   void resetFunctionState() {
     if (!pftParentStack.empty()) {
       pftParentStack.back().visit(common::visitors{
+          [&](lower::pft::ModuleLikeUnit &p) {
+            containedUnitList = &p.containedUnitList;
+          },
           [&](lower::pft::FunctionLikeUnit &p) {
-            functionList = &p.nestedFunctions;
+            containedUnitList = &p.containedUnitList;
             labelEvaluationMap = &p.labelEvaluationMap;
             assignSymbolLabelMap = &p.assignSymbolLabelMap;
           },
-          [&](lower::pft::ModuleLikeUnit &p) {
-            functionList = &p.nestedFunctions;
-          },
-          [&](auto &) { functionList = nullptr; },
+          [&](auto &) { containedUnitList = nullptr; },
       });
     }
   }
@@ -433,12 +456,11 @@ class PFTBuilder {
   }
 
   template <typename A>
-  A &addFunction(A &&func) {
-    if (functionList) {
-      functionList->emplace_back(std::move(func));
-      return functionList->back();
-    }
-    return addUnit(std::move(func));
+  A &addContainedUnit(A &&unit) {
+    if (!containedUnitList)
+      return addUnit(std::move(unit));
+    containedUnitList->emplace_back(std::move(unit));
+    return std::get<A>(containedUnitList->back());
   }
 
   // ActionStmt has a couple of non-conforming cases, explicitly handled here.
@@ -459,7 +481,6 @@ class PFTBuilder {
 
   /// Append an Evaluation to the end of the current list.
   lower::pft::Evaluation &addEvaluation(lower::pft::Evaluation &&eval) {
-    assert(functionList && "not in a function");
     assert(!evaluationListStack.empty() && "empty evaluation list stack");
     if (!constructAndDirectiveStack.empty())
       eval.parentConstruct = constructAndDirectiveStack.back();
@@ -499,15 +520,15 @@ class PFTBuilder {
 
   /// push a new list on the stack of Evaluation lists
   void pushEvaluationList(lower::pft::EvaluationList *evaluationList) {
-    assert(functionList && "not in a function");
     assert(evaluationList && evaluationList->empty() &&
-           "evaluation list isn't correct");
+           "invalid evaluation list");
     evaluationListStack.emplace_back(evaluationList);
   }
 
   /// pop the current list and return to the last Evaluation list
   void popEvaluationList() {
-    assert(functionList && "not in a function");
+    assert(!evaluationListStack.empty() &&
+           "trying to pop an empty evaluationListStack");
     evaluationListStack.pop_back();
   }
 
@@ -1089,9 +1110,8 @@ class PFTBuilder {
   std::vector<lower::pft::PftNode> pftParentStack;
   const semantics::SemanticsContext &semanticsContext;
 
-  /// functionList points to the internal or module procedure function list
-  /// of a FunctionLikeUnit or a ModuleLikeUnit. It may be null.
-  std::list<lower::pft::FunctionLikeUnit> *functionList{};
+  llvm::SmallVector<bool> containsStmtStack{};
+  lower::pft::ContainedUnitList *containedUnitList{};
   std::vector<lower::pft::Evaluation *> constructAndDirectiveStack{};
   std::vector<lower::pft::Evaluation *> doConstructStack{};
   /// evaluationListStack is the current nested construct evaluationList state.
@@ -1099,6 +1119,7 @@ class PFTBuilder {
   llvm::DenseMap<parser::Label, lower::pft::Evaluation *> *labelEvaluationMap{};
   lower::pft::SymbolLabelMap *assignSymbolLabelMap{};
   std::map<std::string, lower::pft::Evaluation *> constructNameMap{};
+  int specificationPartLevel{};
   lower::pft::Evaluation *lastLexicalEvaluation{};
 };
 
@@ -1201,11 +1222,15 @@ class PFTDumper {
       outputStream << " -> " << eval.controlSuccessor->printIndex;
     else if (eval.isA<parser::EntryStmt>() && eval.lexicalSuccessor)
       outputStream << " -> " << eval.lexicalSuccessor->printIndex;
+    bool extraNewline = false;
     if (!eval.position.empty())
       outputStream << ": " << eval.position.ToString();
-    else if (auto *dir = eval.getIf<Fortran::parser::CompilerDirective>())
+    else if (auto *dir = eval.getIf<parser::CompilerDirective>()) {
+      extraNewline = dir->source.ToString().back() == '\n';
       outputStream << ": !" << dir->source.ToString();
-    outputStream << '\n';
+    }
+    if (!extraNewline)
+      outputStream << '\n';
     if (eval.hasNestedEvaluations()) {
       dumpEvaluationList(outputStream, *eval.evaluationList, indent + 1);
       outputStream << indentString << "<<End " << name << bang << ">>\n";
@@ -1265,13 +1290,7 @@ class PFTDumper {
       outputStream << ": " << header;
     outputStream << '\n';
     dumpEvaluationList(outputStream, functionLikeUnit.evaluationList);
-    if (!functionLikeUnit.nestedFunctions.empty()) {
-      outputStream << "\nContains\n";
-      for (const lower::pft::FunctionLikeUnit &func :
-           functionLikeUnit.nestedFunctions)
-        dumpFunctionLikeUnit(outputStream, func);
-      outputStream << "End Contains\n";
-    }
+    dumpContainedUnitList(outputStream, functionLikeUnit.containedUnitList);
     outputStream << "End " << unitKind << ' ' << name << "\n\n";
   }
 
@@ -1298,11 +1317,8 @@ class PFTDumper {
     });
     outputStream << unitKind << ' ' << name << ": " << header << '\n';
     dumpEvaluationList(outputStream, moduleLikeUnit.evaluationList);
-    outputStream << "Contains\n";
-    for (const lower::pft::FunctionLikeUnit &func :
-         moduleLikeUnit.nestedFunctions)
-      dumpFunctionLikeUnit(outputStream, func);
-    outputStream << "End Contains\nEnd " << unitKind << ' ' << name << "\n\n";
+    dumpContainedUnitList(outputStream, moduleLikeUnit.containedUnitList);
+    outputStream << "End " << unitKind << ' ' << name << "\n\n";
   }
 
   // Top level directives
@@ -1311,9 +1327,34 @@ class PFTDumper {
       const lower::pft::CompilerDirectiveUnit &directive) {
     outputStream << getNodeIndex(directive) << " ";
     outputStream << "CompilerDirective: !";
-    outputStream << directive.get<Fortran::parser::CompilerDirective>()
-                        .source.ToString();
-    outputStream << "\nEnd CompilerDirective\n\n";
+    bool extraNewline =
+        directive.get<parser::CompilerDirective>().source.ToString().back() ==
+        'n';
+    outputStream
+        << directive.get<parser::CompilerDirective>().source.ToString();
+    if (!extraNewline)
+      outputStream << "\n";
+    outputStream << "\n";
+  }
+
+  void dumpContainedUnitList(
+      llvm::raw_ostream &outputStream,
+      const lower::pft::ContainedUnitList &containedUnitList) {
+    if (containedUnitList.empty())
+      return;
+    outputStream << "\nContains\n";
+    for (const lower::pft::ContainedUnit &unit : containedUnitList)
+      if (const auto *func = std::get_if<lower::pft::FunctionLikeUnit>(&unit)) {
+        dumpFunctionLikeUnit(outputStream, *func);
+      } else if (const auto *dir =
+                     std::get_if<lower::pft::CompilerDirectiveUnit>(&unit)) {
+        outputStream << getNodeIndex(*dir) << " ";
+        dumpEvaluation(outputStream,
+                       lower::pft::Evaluation{
+                           dir->get<parser::CompilerDirective>(), dir->parent});
+        outputStream << "\n";
+      }
+    outputStream << "End Contains\n";
   }
 
   void
@@ -1321,8 +1362,8 @@ class PFTDumper {
                            const lower::pft::OpenACCDirectiveUnit &directive) {
     outputStream << getNodeIndex(directive) << " ";
     outputStream << "OpenACCDirective: !$acc ";
-    outputStream << directive.get<Fortran::parser::OpenACCRoutineConstruct>()
-                        .source.ToString();
+    outputStream
+        << directive.get<parser::OpenACCRoutineConstruct>().source.ToString();
     outputStream << "\nEnd OpenACCDirective\n\n";
   }
 
diff --git a/flang/test/Lower/pre-fir-tree09.f90 b/flang/test/Lower/pre-fir-tree09.f90
new file mode 100644
index 0000000000000..15d7672725ab5
--- /dev/null
+++ b/flang/test/Lower/pre-fir-tree09.f90
@@ -0,0 +1,100 @@
+! RUN: bbc -pft-test -o %t %s | FileCheck %s
+
+module mm
+  !dir$ some directive 1
+  type t
+    logical :: tag
+  contains
+    final :: fin
+  end type
+  !dir$ some directive 2
+
+contains
+  !dir$ some directive 3
+  subroutine fin(x)
+    type(t), intent(inout) :: x
+    x%tag =.true.
+    !dir$ some directive 4
+    call s1
+    call s2
+    print*, 'fin', x
+
+  contains
+    !dir$ some directive 5
+    subroutine s1
+      print*, 's1'
+      !dir$ some directive 6
+    end subroutine s1
+
+    !dir$ some directive 7
+    subroutine s2
+      !dir$ some directive 8
+      if (.true.) then
+        !dir$ some directive 9
+        print*, 's2'
+        !dir$ some directive 10
+      endif
+      !dir$ some directive 11
+    end subroutine s2
+    !dir$ some directive 12
+  end subroutine fin
+  !dir$ some directive 13
+end module mm
+!dir$ some directive 14
+
+end
+
+! CHECK:  Module mm: module mm
+! CHECK:    CompilerDirective: !some directive 1
+! CHECK:    CompilerDirective: !some directive 2
+
+! CHECK:  Contains
+! CHECK:  CompilerDirective: !some directive 3
+
+! CHECK:  Subroutine fin: subroutine fin(x)
+! CHECK:    AssignmentStmt: x%tag =.true.
+! CHECK:    CompilerDirective: !some directive 4
+! CHECK:    CallStmt: call s1
+! CHECK:    CallStmt: call s2
+! CHECK:    PrintStmt: print*, 'fin', x
+! CHECK:    EndSubroutineStmt: end subroutine fin
+
+! CHECK:  Contains
+! CHECK:  CompilerDirective: !some directive 5
+
+! CHECK:  Subroutine s1: subroutine s1
+! CHECK:    PrintStmt: print*, 's1'
+! CHECK:    CompilerDirective: !some directive 6
+! CHECK:    EndSubroutineStmt: end subroutine s1
+! CHECK:  End Subroutine s1
+
+! CHECK:  CompilerDirective: !some directive 7
+
+! CHECK:  Subroutine s2: subroutine s2
+! CHECK:    CompilerDirective: !some directive 8
+! CHECK:    <<IfConstruct>> -> 7
+! CHECK:      IfThenStmt -> 7: if(.true.) then
+! CHECK:      ^CompilerDirective: !some directive 9
+! CHECK:      PrintStmt: print*, 's2'
+! CHECK:      CompilerDirective: !some directive 10
+! CHECK:      EndIfStmt: endif
+! CHECK:    <<End IfConstruct>>
+! CHECK:    CompilerDirective: !some directive 11
+! CHECK:    EndSubroutineStmt: end subroutine s2
+! CHECK:  End Subroutine s2
+
+! CHECK:  CompilerDirective: !some directive 12
+
+! CHECK:  End Contains
+! CHECK:  End Subroutine fin
+
+! CHECK:  CompilerDirective: !some directive 13
+
+! CHECK:  End Contains
+! CHECK:  End Module mm
+
+! CHECK:  CompilerDirective: !some directive 14
+
+! CHECK:  Program <anonymous>
+! CHECK:    EndProgramStmt: end
+! CHECK:  End Program <anonymous>

>From cc8331878fc859912a1ba1719cab83223240d6a6 Mon Sep 17 00:00:00 2001
From: V Donaldson <vdonaldson at nvidia.com>
Date: Tue, 11 Jun 2024 07:53:01 -0700
Subject: [PATCH 2/2] Review update

---
 flang/lib/Lower/PFTBuilder.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/flang/lib/Lower/PFTBuilder.cpp b/flang/lib/Lower/PFTBuilder.cpp
index df2c31381a0e7..fc34895d1ec75 100644
--- a/flang/lib/Lower/PFTBuilder.cpp
+++ b/flang/lib/Lower/PFTBuilder.cpp
@@ -1329,7 +1329,7 @@ class PFTDumper {
     outputStream << "CompilerDirective: !";
     bool extraNewline =
         directive.get<parser::CompilerDirective>().source.ToString().back() ==
-        'n';
+        '\n';
     outputStream
         << directive.get<parser::CompilerDirective>().source.ToString();
     if (!extraNewline)



More information about the flang-commits mailing list