[flang-commits] [flang] 520e5db - [flang][driver] Add print function name Plugin example

Andrzej Warzynski via flang-commits flang-commits at lists.llvm.org
Thu Aug 19 01:26:02 PDT 2021


Author: Stuart Ellis
Date: 2021-08-19T08:25:34Z
New Revision: 520e5db26a4a9fcb418d9ef2da813155038caade

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

LOG: [flang][driver] Add print function name Plugin example

Replacing Hello World example Plugin with one that counts and prints the names of
functions and subroutines.
This involves changing the `PluginParseTreeAction` Plugin base class to
inherit from `PrescanAndSemaAction` class to get access to the Parse Tree
so that the Plugin can walk it.
Additionally, there are tests of this new Plugin to check it prints the correct
things in different circumstances.

Depends on: D106137

Reviewed By: awarzynski

Differential Revision: https://reviews.llvm.org/D107089

Added: 
    flang/examples/PrintFlangFunctionNames/CMakeLists.txt
    flang/examples/PrintFlangFunctionNames/PrintFlangFunctionNames.cpp
    flang/test/Driver/plugin-invalid-name.f90
    flang/test/Examples/print-fns-calls.f90
    flang/test/Examples/print-fns-definitions.f90
    flang/test/Examples/print-fns-interfaces.f90

Modified: 
    flang/examples/CMakeLists.txt
    flang/include/flang/Frontend/FrontendActions.h
    flang/test/CMakeLists.txt

Removed: 
    flang/examples/HelloWorld/CMakeLists.txt
    flang/examples/HelloWorld/HelloWorldPlugin.cpp
    flang/test/Driver/plugin-example.f90


################################################################################
diff  --git a/flang/examples/CMakeLists.txt b/flang/examples/CMakeLists.txt
index c4ef3bf20d4b..41a29fbda1f4 100644
--- a/flang/examples/CMakeLists.txt
+++ b/flang/examples/CMakeLists.txt
@@ -11,4 +11,4 @@ target_link_libraries(external-hello-world
   FortranRuntime
 )
 
-add_subdirectory(HelloWorld)
+add_subdirectory(PrintFlangFunctionNames)

diff  --git a/flang/examples/HelloWorld/HelloWorldPlugin.cpp b/flang/examples/HelloWorld/HelloWorldPlugin.cpp
deleted file mode 100644
index 11100384aed9..000000000000
--- a/flang/examples/HelloWorld/HelloWorldPlugin.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-//===-- HelloWorldPlugin.cpp ----------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// Basic example Flang plugin which simply prints a Hello World statement
-//
-//===----------------------------------------------------------------------===//
-
-#include "flang/Frontend/FrontendActions.h"
-#include "flang/Frontend/FrontendPluginRegistry.h"
-
-using namespace Fortran::frontend;
-
-class HelloWorldFlangPlugin : public PluginParseTreeAction {
-  void ExecuteAction() override {
-    llvm::outs() << "Hello World from your new Flang plugin\n";
-  }
-};
-
-static FrontendPluginRegistry::Add<HelloWorldFlangPlugin> X(
-    "-hello-world", "Hello World Plugin example");

diff  --git a/flang/examples/HelloWorld/CMakeLists.txt b/flang/examples/PrintFlangFunctionNames/CMakeLists.txt
similarity index 72%
rename from flang/examples/HelloWorld/CMakeLists.txt
rename to flang/examples/PrintFlangFunctionNames/CMakeLists.txt
index 8552284c8052..6b107b4e1ea5 100644
--- a/flang/examples/HelloWorld/CMakeLists.txt
+++ b/flang/examples/PrintFlangFunctionNames/CMakeLists.txt
@@ -1,7 +1,7 @@
 # TODO: Note that this is currently only available on Linux.
 # On Windows, we would also have to specify e.g. `PLUGIN_TOOL`.
 add_llvm_library(
-    flangHelloWorldPlugin
+    flangPrintFunctionNames
     MODULE
-    HelloWorldPlugin.cpp
+    PrintFlangFunctionNames.cpp
 )

diff  --git a/flang/examples/PrintFlangFunctionNames/PrintFlangFunctionNames.cpp b/flang/examples/PrintFlangFunctionNames/PrintFlangFunctionNames.cpp
new file mode 100644
index 000000000000..0afbf9f35e53
--- /dev/null
+++ b/flang/examples/PrintFlangFunctionNames/PrintFlangFunctionNames.cpp
@@ -0,0 +1,81 @@
+//===-- PrintFlangFunctionNames.cpp ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Small example Flang plugin to count/print Functions & Subroutines names.
+// It walks the Parse Tree using a Visitor struct that has Post functions for
+// FunctionStmt and SubroutineStmt to access the names of functions &
+// subroutines. It also has Pre functions for FunctionSubprogram and
+// SubroutineSubprogram so a Bool can be set to show that it is the definition
+// of a function/subroutine, and not print those that are in an Interface.
+// This plugin does not recognise Statement Functions or Module Procedures,
+// which could be dealt with through StmtFunctionStmt and MpSubprogramStmt nodes
+// respectively.
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Frontend/CompilerInstance.h"
+#include "flang/Frontend/FrontendActions.h"
+#include "flang/Frontend/FrontendPluginRegistry.h"
+#include "flang/Parser/dump-parse-tree.h"
+#include "flang/Parser/parsing.h"
+
+using namespace Fortran::frontend;
+
+class PrintFunctionNamesAction : public PluginParseTreeAction {
+
+  // Visitor struct that defines Pre/Post functions for 
diff erent types of nodes
+  struct ParseTreeVisitor {
+    template <typename A> bool Pre(const A &) { return true; }
+    template <typename A> void Post(const A &) {}
+
+    bool Pre(const Fortran::parser::FunctionSubprogram &) {
+      isInSubprogram_ = true;
+      return true;
+    }
+    void Post(const Fortran::parser::FunctionStmt &f) {
+      if (isInSubprogram_) {
+        llvm::outs() << "Function:\t"
+                     << std::get<Fortran::parser::Name>(f.t).ToString() << "\n";
+        fcounter++;
+        isInSubprogram_ = false;
+      }
+    }
+
+    bool Pre(const Fortran::parser::SubroutineSubprogram &) {
+      isInSubprogram_ = true;
+      return true;
+    }
+    void Post(const Fortran::parser::SubroutineStmt &s) {
+      if (isInSubprogram_) {
+        llvm::outs() << "Subroutine:\t"
+                     << std::get<Fortran::parser::Name>(s.t).ToString() << "\n";
+        scounter++;
+        isInSubprogram_ = false;
+      }
+    }
+
+    int fcounter{0};
+    int scounter{0};
+
+  private:
+    bool isInSubprogram_{false};
+  };
+
+  void ExecuteAction() override {
+    auto &parseTree{instance().parsing().parseTree()};
+
+    ParseTreeVisitor visitor;
+    Fortran::parser::Walk(parseTree, visitor);
+
+    llvm::outs() << "\n====   Functions: " << visitor.fcounter << " ====\n";
+    llvm::outs() << "==== Subroutines: " << visitor.scounter << " ====\n";
+  }
+};
+
+static FrontendPluginRegistry::Add<PrintFunctionNamesAction> X(
+    "print-fns", "Print Function names");

diff  --git a/flang/include/flang/Frontend/FrontendActions.h b/flang/include/flang/Frontend/FrontendActions.h
index 43fd1f0f6596..ec9d9f79c694 100644
--- a/flang/include/flang/Frontend/FrontendActions.h
+++ b/flang/include/flang/Frontend/FrontendActions.h
@@ -30,10 +30,6 @@ struct MeasurementVisitor {
 // Custom Consumer Actions
 //===----------------------------------------------------------------------===//
 
-class PluginParseTreeAction : public FrontendAction {
-  void ExecuteAction() override;
-};
-
 class InputOutputTestAction : public FrontendAction {
   void ExecuteAction() override;
 };
@@ -131,6 +127,10 @@ class ParseSyntaxOnlyAction : public PrescanAndSemaAction {
   void ExecuteAction() override;
 };
 
+class PluginParseTreeAction : public PrescanAndSemaAction {
+  void ExecuteAction() override;
+};
+
 } // namespace Fortran::frontend
 
 #endif // LLVM_FLANG_FRONTEND_FRONTENDACTIONS_H

diff  --git a/flang/test/CMakeLists.txt b/flang/test/CMakeLists.txt
index d7a7dccdc172..1d0bef1cbe66 100644
--- a/flang/test/CMakeLists.txt
+++ b/flang/test/CMakeLists.txt
@@ -56,7 +56,9 @@ if (FLANG_INCLUDE_TESTS)
 endif()
 
 if (FLANG_BUILD_EXAMPLES)
-  list(APPEND FLANG_TEST_DEPENDS flangHelloWorldPlugin)
+  list(APPEND FLANG_TEST_DEPENDS
+    flangPrintFunctionNames
+    )
 endif ()
 
 add_custom_target(flang-test-depends DEPENDS ${FLANG_TEST_DEPENDS})

diff  --git a/flang/test/Driver/plugin-example.f90 b/flang/test/Driver/plugin-example.f90
deleted file mode 100644
index 73a48e34e72c..000000000000
--- a/flang/test/Driver/plugin-example.f90
+++ /dev/null
@@ -1,11 +0,0 @@
-! Check that loading and running the Hello World plugin example results in the correct print statement
-! Also check that when a plugin name isn't found, the error diagnostic is correct
-! This requires that the examples are built (FLANG_BUILD_EXAMPLES=ON)
-
-! REQUIRES: plugins, examples, shell
-
-! RUN: %flang_fc1 -load %llvmshlibdir/flangHelloWorldPlugin%pluginext -plugin -hello-world %s 2>&1 | FileCheck %s
-! CHECK: Hello World from your new Flang plugin
-
-! RUN: not %flang_fc1 -load %llvmshlibdir/flangHelloWorldPlugin%pluginext -plugin -wrong-name %s 2>&1 | FileCheck %s --check-prefix=ERROR
-! ERROR: error: unable to find plugin '-wrong-name'

diff  --git a/flang/test/Driver/plugin-invalid-name.f90 b/flang/test/Driver/plugin-invalid-name.f90
new file mode 100644
index 000000000000..55fc423b5e8f
--- /dev/null
+++ b/flang/test/Driver/plugin-invalid-name.f90
@@ -0,0 +1,7 @@
+! Check the correct error diagnostic is reported when a plugin name isn't found
+
+! REQUIRES: plugins, shell
+
+! RUN: not %flang_fc1 -plugin -wrong-name %s 2>&1 | FileCheck %s --check-prefix=ERROR
+
+! ERROR: error: unable to find plugin '-wrong-name'

diff  --git a/flang/test/Examples/print-fns-calls.f90 b/flang/test/Examples/print-fns-calls.f90
new file mode 100644
index 000000000000..4702e1b56a57
--- /dev/null
+++ b/flang/test/Examples/print-fns-calls.f90
@@ -0,0 +1,21 @@
+! Check the Flang Print Function Names example plugin doesn't count/print function/subroutine calls (should only count definitions)
+! This requires that the examples are built (FLANG_BUILD_EXAMPLES=ON) to access flangPrintFunctionNames.so
+
+! REQUIRES: plugins, examples, shell
+
+! RUN: %flang_fc1 -load %llvmshlibdir/flangPrintFunctionNames%pluginext -plugin print-fns %s 2>&1 | FileCheck %s
+
+!-----------------------------
+! EXPECTED OUTPUT: Counts == 0
+!-----------------------------
+! CHECK: ==== Functions: 0 ====
+! CHECK-NEXT: ==== Subroutines: 0 ====
+
+!-----------------------------
+! INPUT
+!-----------------------------
+program main
+    call subroutine1
+    fn1 = function1()
+    fn2 = function2()
+end program main

diff  --git a/flang/test/Examples/print-fns-definitions.f90 b/flang/test/Examples/print-fns-definitions.f90
new file mode 100644
index 000000000000..fc8fcb29f97b
--- /dev/null
+++ b/flang/test/Examples/print-fns-definitions.f90
@@ -0,0 +1,40 @@
+! Check the Flang Print Function Names example plugin prints and counts function/subroutine definitions
+! This includes internal and external Function/Subroutines, but not Statement Functions
+! This requires that the examples are built (FLANG_BUILD_EXAMPLES=ON) to access flangPrintFunctionNames.so
+
+! REQUIRES: plugins, examples, shell
+
+! RUN: %flang_fc1 -load %llvmshlibdir/flangPrintFunctionNames%pluginext -plugin print-fns %s 2>&1 | FileCheck %s
+
+!-------------------------------------------------
+! EXPECTED OUTPUT: Names printed and counts != 0
+!-------------------------------------------------
+! CHECK: Function: external_func1
+! CHECK-NEXT: Function: external_func2
+! CHECK-NEXT: Subroutine: external_subr
+! CHECK-NEXT: Function: internal_func
+! CHECK-NEXT: Subroutine: internal_subr
+! CHECK-EMPTY:
+! CHECK-NEXT: ==== Functions: 3 ====
+! CHECK-NEXT: ==== Subroutines: 2 ====
+
+!--------------------------
+! INPUT
+!--------------------------
+function external_func1()
+end function
+
+function external_func2()
+end function
+
+subroutine external_subr
+end subroutine
+
+program main
+contains
+    function internal_func()
+    end function
+
+    subroutine internal_subr
+    end subroutine
+end program main

diff  --git a/flang/test/Examples/print-fns-interfaces.f90 b/flang/test/Examples/print-fns-interfaces.f90
new file mode 100644
index 000000000000..39a2bf3e465f
--- /dev/null
+++ b/flang/test/Examples/print-fns-interfaces.f90
@@ -0,0 +1,26 @@
+! Check the Flang Print Function Names example plugin doesn't count/print Functions/Subroutines in interfaces
+! (It should only count definitions, which will appear elsewhere for interfaced functions/subroutines)
+! This requires that the examples are built (FLANG_BUILD_EXAMPLES=ON) to access flangPrintFunctionNames.so
+
+! REQUIRES: plugins, examples, shell
+
+! RUN: %flang_fc1 -load %llvmshlibdir/flangPrintFunctionNames%pluginext -plugin print-fns %s 2>&1 | FileCheck %s
+
+!-----------------------------
+! EXPECTED OUTPUT: Counts == 0
+!-----------------------------
+! CHECK: ==== Functions: 0 ====
+! CHECK-NEXT: ==== Subroutines: 0 ====
+
+!--------------------------
+! INPUT
+!--------------------------
+program main
+    interface
+        function interface_func()
+        end function
+
+        subroutine interface_subr()
+        end subroutine
+    end interface
+end program main


        


More information about the flang-commits mailing list