[llvm] 10b12d4 - Reland [docs][NewPM] Add docs for writing NPM passes

Arthur Eubanks via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 14 16:08:54 PDT 2020


Author: Arthur Eubanks
Date: 2020-09-14T16:06:19-07:00
New Revision: 10b12d4035de40e5eaedddda82d9c533854eefcb

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

LOG: Reland [docs][NewPM] Add docs for writing NPM passes

As to not conflict with the legacy PM example passes under
llvm/lib/Transforms/Hello, this is under HelloNew. This makes the
CMakeLists.txt and general directory structure less confusing for people
following the example.

Much of the doc structure was taken from WritinAnLLVMPass.rst.

This adds a HelloWorld pass which simply prints out each function name.

More will follow after this, e.g. passes over different units of IR, analyses.
https://llvm.org/docs/WritingAnLLVMPass.html contains a lot more.

Relanded with missing "Support" dependency in LLVMBuild.txt.

Reviewed By: ychen, asbirlea

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

Added: 
    llvm/docs/WritingAnLLVMNewPMPass.rst
    llvm/include/llvm/Transforms/HelloNew/HelloWorld.h
    llvm/lib/Transforms/HelloNew/CMakeLists.txt
    llvm/lib/Transforms/HelloNew/HelloWorld.cpp
    llvm/lib/Transforms/HelloNew/LLVMBuild.txt
    llvm/test/Transforms/HelloNew/helloworld.ll
    llvm/utils/gn/secondary/llvm/lib/Transforms/HelloNew/BUILD.gn

Modified: 
    llvm/docs/UserGuides.rst
    llvm/docs/WritingAnLLVMPass.rst
    llvm/lib/Passes/LLVMBuild.txt
    llvm/lib/Passes/PassBuilder.cpp
    llvm/lib/Passes/PassRegistry.def
    llvm/lib/Transforms/CMakeLists.txt
    llvm/lib/Transforms/LLVMBuild.txt
    llvm/utils/gn/secondary/llvm/lib/Passes/BUILD.gn

Removed: 
    


################################################################################
diff  --git a/llvm/docs/UserGuides.rst b/llvm/docs/UserGuides.rst
index 2e0cffb711ef..00e99db297f7 100644
--- a/llvm/docs/UserGuides.rst
+++ b/llvm/docs/UserGuides.rst
@@ -54,6 +54,7 @@ intermediate LLVM representation.
    TableGenFundamentals
    Vectorizers
    WritingAnLLVMPass
+   WritingAnLLVMNewPMPass
    WritingAnLLVMBackend
    yaml2obj
 
@@ -107,6 +108,10 @@ Optimizations
 :doc:`WritingAnLLVMPass`
    Information on how to write LLVM transformations and analyses.
 
+:doc:`WritingAnLLVMNewPMPass`
+   Information on how to write LLVM transformations under the new pass
+   manager.
+
 :doc:`Passes`
    A list of optimizations and analyses implemented in LLVM.
 

diff  --git a/llvm/docs/WritingAnLLVMNewPMPass.rst b/llvm/docs/WritingAnLLVMNewPMPass.rst
new file mode 100644
index 000000000000..a876ec4ceb00
--- /dev/null
+++ b/llvm/docs/WritingAnLLVMNewPMPass.rst
@@ -0,0 +1,209 @@
+====================
+Writing an LLVM Pass
+====================
+
+.. program:: opt
+
+.. contents::
+    :local:
+
+Introduction --- What is a pass?
+================================
+
+The LLVM pass framework is an important part of the LLVM system, because LLVM
+passes are where most of the interesting parts of the compiler exist. Passes
+perform the transformations and optimizations that make up the compiler, they
+build the analysis results that are used by these transformations, and they
+are, above all, a structuring technique for compiler code.
+
+Unlike passes under the legacy pass manager where the pass interface is
+defined via inheritance, passes under the new pass manager rely on
+concept-based polymorphism, meaning there is no explicit interface (see
+comments in ``PassManager.h`` for more details). All LLVM passes inherit from
+the CRTP mix-in ``PassInfoMixin<PassT>``. The pass should have a ``run()``
+method which returns a ``PreservedAnalyses`` and takes in some unit of IR
+along with an analysis manager. For example, a function pass would have a
+``PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);`` method.
+
+We start by showing you how to construct a pass, from setting up the build,
+creating the pass, to executing and testing it. Looking at existing passes is
+always a great way to learn details.
+
+Quick Start --- Writing hello world
+===================================
+
+Here we describe how to write the "hello world" of passes. The "HelloWorld"
+pass is designed to simply print out the name of non-external functions that
+exist in the program being compiled. It does not modify the program at all,
+it just inspects it.
+
+The code below already exists; feel free to create a pass with a 
diff erent
+name alongside the HelloWorld source files.
+
+.. _writing-an-llvm-npm-pass-build:
+
+Setting up the build
+--------------------
+
+First, configure and build LLVM as described in :doc:`GettingStarted`.
+
+Next, we will reuse an existing directory (creating a new directory involves
+modifying more ``CMakeLists.txt``s and ``LLVMBuild.txt``s than we want). For
+this example, we'll use ``llvm/lib/Transforms/HelloNew/HelloWorld.cpp``,
+which has already been created. If you'd like to create your own pass, add a
+new source file into ``llvm/lib/Transforms/HelloNew/CMakeLists.txt`` under
+``HelloWorld.cpp``:
+
+.. code-block:: cmake
+
+  add_llvm_component_library(LLVMHelloWorld
+    HelloWorld.cpp
+
+    DEPENDS
+    intrinsics_gen
+    )
+
+Now that we have the build set up for a new pass, we need to write the code
+for the pass itself.
+
+.. _writing-an-llvm-npm-pass-basiccode:
+
+Basic code required
+-------------------
+
+Now that the build is setup for a new pass, we just have to write it.
+
+First we need to define the pass in a header file. We'll create
+``llvm/include/llvm/Transforms/HelloNew/HelloWorld.h``. The file should
+contain the following boilerplate:
+
+.. code-block:: c++
+
+  #ifndef LLVM_TRANSFORMS_HELLONEW_HELLOWORLD_H
+  #define LLVM_TRANSFORMS_HELLONEW_HELLOWORLD_H
+
+  #include "llvm/IR/PassManager.h"
+
+  namespace llvm {
+
+  class HelloWorldPass : public PassInfoMixin<HelloWorldPass> {
+  public:
+    PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
+  };
+
+  } // namespace llvm
+
+  #endif // LLVM_TRANSFORMS_HELLONEW_HELLOWORLD_H
+
+This creates the class for the pass with a declaration of the ``run()``
+method which actually runs the pass. Inheriting from ``PassInfoMixin<PassT>``
+sets up some more boilerplate so that we don't have to write it ourselves.
+
+Our class is in the ``llvm`` namespace so that we don't pollute the global
+namespace.
+
+Next we'll create ``llvm/lib/Transforms/HelloNew/HelloWorld.cpp``, starting
+with
+
+.. code-block:: c++
+
+  #include "llvm/Transforms/HelloNew/HelloWorld.h"
+
+... to include the header file we just created.
+
+.. code-block:: c++
+
+  using namespace llvm;
+
+... is required because the functions from the include files live in the llvm
+namespace. This should only be done in non-header files.
+
+Next we have the pass's ``run()`` definition:
+
+.. code-block:: c++
+
+  PreservedAnalyses HelloWorldPass::run(Function &F,
+                                        FunctionAnalysisManager &AM) {
+    errs() << F.getName() << "\n";
+    return PreservedAnalyses::all();
+  }
+
+... which simply prints out the name of the function to stderr. The pass
+manager will ensure that the pass will be run on every function in a module.
+The ``PreservedAnalyses`` return value says that all analyses (e.g. dominator
+tree) are still valid after this pass since we didn't modify any functions.
+
+That's it for the pass itself. Now in order to "register" the pass, we need
+to add it to a couple places. Add the following to
+``llvm\lib\Passes\PassRegistry.def`` in the ``FUNCTION_PASS`` section
+
+.. code-block:: c++
+
+  FUNCTION_PASS("helloworld", HelloWorldPass())
+
+... which adds the pass under the name "helloworld".
+
+``llvm\lib\Passes\PassRegistry.def`` is #include'd into
+``llvm\lib\Passes\PassBuilder.cpp`` multiple times for various reasons. Since
+it constructs our pass, we need to also add the proper #include in
+``llvm\lib\Passes\PassBuilder.cpp``:
+
+.. code-block:: c++
+
+  #include "llvm/Transforms/HelloNew/HelloWorld.h"
+
+This should be all the code necessary for our pass, now it's time to compile
+and run it.
+
+Running a pass with ``opt``
+---------------------------
+
+Now that you have a brand new shiny pass, we can build :program:`opt` and use
+it to run some LLVM IR through the pass.
+
+.. code-block:: console
+
+  $ ninja -C build/ opt
+  # or whatever build system/build directory you are using
+
+  $ cat /tmp/a.ll
+  define i32 @foo() {
+    %a = add i32 2, 3
+    ret i32 %a
+  }
+
+  define void @bar() {
+    ret void
+  }
+
+  $ build/bin/opt -disable-output /tmp/a.ll -passes=helloworld
+  foo
+  bar
+
+Our pass ran and printed the names of functions as expected!
+
+Testing a pass
+--------------
+
+Testing our pass is important to prevent future regressions. We'll add a lit
+test at ``llvm/test/Transforms/HelloNew/helloworld.ll``. See
+:doc:`TestingGuide` for more information on testing.
+
+.. code-block:: llvm
+
+  $ cat llvm/test/Transforms/HelloNew/helloworld.ll
+  ; RUN: opt -disable-output -passes=helloworld %s 2>&1 | FileCheck %s
+
+  ; CHECK: {{^}}foo{{$}}
+  define i32 @foo() {
+    %a = add i32 2, 3
+    ret i32 %a
+  }
+
+  ; CHECK-NEXT: {{^}}bar{{$}}
+  define void @bar() {
+    ret void
+  }
+
+  $ ninja -C build check-llvm
+  # runs our new test alongside all other llvm lit tests

diff  --git a/llvm/docs/WritingAnLLVMPass.rst b/llvm/docs/WritingAnLLVMPass.rst
index 88f481ba6b07..7a24659e6294 100644
--- a/llvm/docs/WritingAnLLVMPass.rst
+++ b/llvm/docs/WritingAnLLVMPass.rst
@@ -34,6 +34,10 @@ We start by showing you how to construct a pass, everything from setting up the
 code, to compiling, loading, and executing it.  After the basics are down, more
 advanced features are discussed.
 
+This document deals with the legacy pass manager. LLVM is transitioning to
+the new pass manager, which has its own way of defining passes. For more
+details, see :doc:`WritingAnLLVMNewPMPass`.
+
 Quick Start --- Writing hello world
 ===================================
 

diff  --git a/llvm/include/llvm/Transforms/HelloNew/HelloWorld.h b/llvm/include/llvm/Transforms/HelloNew/HelloWorld.h
new file mode 100644
index 000000000000..6c753032f913
--- /dev/null
+++ b/llvm/include/llvm/Transforms/HelloNew/HelloWorld.h
@@ -0,0 +1,23 @@
+//===-- HelloWorld.h - Example Transformations ------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_HELLONEW_HELLOWORLD_H
+#define LLVM_TRANSFORMS_HELLONEW_HELLOWORLD_H
+
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+
+class HelloWorldPass : public PassInfoMixin<HelloWorldPass> {
+public:
+  PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
+};
+
+} // namespace llvm
+
+#endif // LLVM_TRANSFORMS_HELLONEW_HELLOWORLD_H

diff  --git a/llvm/lib/Passes/LLVMBuild.txt b/llvm/lib/Passes/LLVMBuild.txt
index 3e7a39115413..f49f7828d2b9 100644
--- a/llvm/lib/Passes/LLVMBuild.txt
+++ b/llvm/lib/Passes/LLVMBuild.txt
@@ -18,4 +18,4 @@
 type = Library
 name = Passes
 parent = Libraries
-required_libraries = AggressiveInstCombine Analysis Core Coroutines IPO InstCombine ObjCARC Scalar Support Target TransformUtils Vectorize Instrumentation
+required_libraries = AggressiveInstCombine Analysis Core Coroutines HelloNew IPO InstCombine ObjCARC Scalar Support Target TransformUtils Vectorize Instrumentation

diff  --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index c47f612e7199..cd64aecd81d7 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -75,6 +75,7 @@
 #include "llvm/Transforms/Coroutines/CoroEarly.h"
 #include "llvm/Transforms/Coroutines/CoroElide.h"
 #include "llvm/Transforms/Coroutines/CoroSplit.h"
+#include "llvm/Transforms/HelloNew/HelloWorld.h"
 #include "llvm/Transforms/IPO/AlwaysInliner.h"
 #include "llvm/Transforms/IPO/ArgumentPromotion.h"
 #include "llvm/Transforms/IPO/Attributor.h"

diff  --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 4b4f71a71870..1d70db306347 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -197,6 +197,7 @@ FUNCTION_PASS("ee-instrument", EntryExitInstrumenterPass(/*PostInlining=*/false)
 FUNCTION_PASS("make-guards-explicit", MakeGuardsExplicitPass())
 FUNCTION_PASS("post-inline-ee-instrument", EntryExitInstrumenterPass(/*PostInlining=*/true))
 FUNCTION_PASS("gvn-hoist", GVNHoistPass())
+FUNCTION_PASS("helloworld", HelloWorldPass())
 FUNCTION_PASS("instcombine", InstCombinePass())
 FUNCTION_PASS("instcount", InstCountPass())
 FUNCTION_PASS("instsimplify", InstSimplifyPass())

diff  --git a/llvm/lib/Transforms/CMakeLists.txt b/llvm/lib/Transforms/CMakeLists.txt
index dda5f6de11e3..2a0abebdf19b 100644
--- a/llvm/lib/Transforms/CMakeLists.txt
+++ b/llvm/lib/Transforms/CMakeLists.txt
@@ -6,6 +6,7 @@ add_subdirectory(Scalar)
 add_subdirectory(IPO)
 add_subdirectory(Vectorize)
 add_subdirectory(Hello)
+add_subdirectory(HelloNew)
 add_subdirectory(ObjCARC)
 add_subdirectory(Coroutines)
 add_subdirectory(CFGuard)

diff  --git a/llvm/lib/Transforms/HelloNew/CMakeLists.txt b/llvm/lib/Transforms/HelloNew/CMakeLists.txt
new file mode 100644
index 000000000000..a7a1a5b93b06
--- /dev/null
+++ b/llvm/lib/Transforms/HelloNew/CMakeLists.txt
@@ -0,0 +1,6 @@
+add_llvm_component_library(LLVMHelloNew
+  HelloWorld.cpp
+
+  DEPENDS
+  intrinsics_gen
+  )

diff  --git a/llvm/lib/Transforms/HelloNew/HelloWorld.cpp b/llvm/lib/Transforms/HelloNew/HelloWorld.cpp
new file mode 100644
index 000000000000..dea94f8a8f62
--- /dev/null
+++ b/llvm/lib/Transforms/HelloNew/HelloWorld.cpp
@@ -0,0 +1,17 @@
+//===-- HelloWorld.cpp - Example Transformations --------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/HelloNew/HelloWorld.h"
+
+using namespace llvm;
+
+PreservedAnalyses HelloWorldPass::run(Function &F,
+                                      FunctionAnalysisManager &AM) {
+  errs() << F.getName() << "\n";
+  return PreservedAnalyses::all();
+}

diff  --git a/llvm/lib/Transforms/HelloNew/LLVMBuild.txt b/llvm/lib/Transforms/HelloNew/LLVMBuild.txt
new file mode 100644
index 000000000000..06d3c81333b7
--- /dev/null
+++ b/llvm/lib/Transforms/HelloNew/LLVMBuild.txt
@@ -0,0 +1,22 @@
+;===- ./lib/Transforms/HelloNew/LLVMBuild.txt ------------------*- Conf -*--===;
+;
+; 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
+;
+;===------------------------------------------------------------------------===;
+;
+; This is an LLVMBuild description file for the components in this subdirectory.
+;
+; For more information on the LLVMBuild system, please see:
+;
+;   http://llvm.org/docs/LLVMBuild.html
+;
+;===------------------------------------------------------------------------===;
+
+[component_0]
+type = Library
+name = HelloNew
+parent = Transforms
+library_name = HelloNew
+required_libraries = Core Support

diff  --git a/llvm/lib/Transforms/LLVMBuild.txt b/llvm/lib/Transforms/LLVMBuild.txt
index 5fb5efcc068c..6c6a6bb317fa 100644
--- a/llvm/lib/Transforms/LLVMBuild.txt
+++ b/llvm/lib/Transforms/LLVMBuild.txt
@@ -15,7 +15,7 @@
 ;===------------------------------------------------------------------------===;
 
 [common]
-subdirectories = AggressiveInstCombine Coroutines IPO InstCombine Instrumentation Scalar Utils Vectorize ObjCARC CFGuard
+subdirectories = AggressiveInstCombine Coroutines HelloNew IPO InstCombine Instrumentation Scalar Utils Vectorize ObjCARC CFGuard
 
 [component_0]
 type = Group

diff  --git a/llvm/test/Transforms/HelloNew/helloworld.ll b/llvm/test/Transforms/HelloNew/helloworld.ll
new file mode 100644
index 000000000000..48817c24801a
--- /dev/null
+++ b/llvm/test/Transforms/HelloNew/helloworld.ll
@@ -0,0 +1,12 @@
+; RUN: opt -disable-output -passes=helloworld %s 2>&1 | FileCheck %s
+
+; CHECK: {{^}}foo{{$}}
+define i32 @foo() {
+  %a = add i32 2, 3
+  ret i32 %a
+}
+
+; CHECK-NEXT: {{^}}bar{{$}}
+define void @bar() {
+  ret void
+}

diff  --git a/llvm/utils/gn/secondary/llvm/lib/Passes/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/Passes/BUILD.gn
index 9afe48db159b..bb8a671dd6a7 100644
--- a/llvm/utils/gn/secondary/llvm/lib/Passes/BUILD.gn
+++ b/llvm/utils/gn/secondary/llvm/lib/Passes/BUILD.gn
@@ -8,6 +8,7 @@ static_library("Passes") {
     "//llvm/lib/Target",
     "//llvm/lib/Transforms/AggressiveInstCombine",
     "//llvm/lib/Transforms/Coroutines",
+    "//llvm/lib/Transforms/HelloNew",
     "//llvm/lib/Transforms/IPO",
     "//llvm/lib/Transforms/InstCombine",
     "//llvm/lib/Transforms/Instrumentation",

diff  --git a/llvm/utils/gn/secondary/llvm/lib/Transforms/HelloNew/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/Transforms/HelloNew/BUILD.gn
new file mode 100644
index 000000000000..5e6167324a4a
--- /dev/null
+++ b/llvm/utils/gn/secondary/llvm/lib/Transforms/HelloNew/BUILD.gn
@@ -0,0 +1,9 @@
+static_library("HelloNew") {
+  output_name = "LLVMHelloNew"
+  deps = [
+    "//llvm/lib/Analysis",
+    "//llvm/lib/IR",
+    "//llvm/lib/Support",
+  ]
+  sources = [ "HelloWorld.cpp" ]
+}


        


More information about the llvm-commits mailing list