From 30cfcbe7016a5d695c34fd2f5e959f569204e4db Mon Sep 17 00:00:00 2001 From: Vasileios Porpodas Date: Fri, 6 Sep 2024 12:21:08 -0700 Subject: [PATCH] [SandboxIR] PassManager This patch implements a simple pass manager for Sandbox IR. --- llvm/include/llvm/SandboxIR/Pass.h | 4 +- llvm/include/llvm/SandboxIR/PassManager.h | 70 +++++++++++++++++++++++ llvm/lib/SandboxIR/CMakeLists.txt | 1 + llvm/lib/SandboxIR/PassManager.cpp | 22 +++++++ llvm/unittests/SandboxIR/PassTest.cpp | 51 +++++++++++++++++ 5 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 llvm/include/llvm/SandboxIR/PassManager.h create mode 100644 llvm/lib/SandboxIR/PassManager.cpp diff --git a/llvm/include/llvm/SandboxIR/Pass.h b/llvm/include/llvm/SandboxIR/Pass.h index d659e96839213..caf1c70a84147 100644 --- a/llvm/include/llvm/SandboxIR/Pass.h +++ b/llvm/include/llvm/SandboxIR/Pass.h @@ -37,8 +37,8 @@ class Pass { Pass.print(OS); return OS; } - void print(raw_ostream &OS) const { OS << Name; } - LLVM_DUMP_METHOD void dump() const; + virtual void print(raw_ostream &OS) const { OS << Name; } + LLVM_DUMP_METHOD virtual void dump() const; #endif }; diff --git a/llvm/include/llvm/SandboxIR/PassManager.h b/llvm/include/llvm/SandboxIR/PassManager.h new file mode 100644 index 0000000000000..cb321fe699a56 --- /dev/null +++ b/llvm/include/llvm/SandboxIR/PassManager.h @@ -0,0 +1,70 @@ +//===- PassManager.h --------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// Registers and executes the Sandbox IR passes. +// +// The pass manager contains an ordered sequence of passes that it runs in +// order. The passes are owned by the PassRegistry, not by the PassManager. +// +// Note that in this design a pass manager is also a pass. So a pass manager +// runs when it is it's turn to run in its parent pass-manager pass pipeline. +// + +#ifndef LLVM_SANDBOXIR_PASSMANAGER_H +#define LLVM_SANDBOXIR_PASSMANAGER_H + +#include "llvm/ADT/STLExtras.h" +#include "llvm/SandboxIR/Pass.h" +#include "llvm/Support/Debug.h" + +namespace llvm::sandboxir { + +class Value; + +/// Base class. +template +class PassManager : public ParentPass { +protected: + /// The list of passes that this pass manager will run. + SmallVector Passes; + + PassManager(StringRef Name) : ParentPass(Name) {} + PassManager(const PassManager &) = delete; + virtual ~PassManager() = default; + PassManager &operator=(const PassManager &) = delete; + +public: + /// Adds \p Pass to the pass pipeline. + void addPass(ContainedPass *Pass) { + // TODO: Check that Pass's class type works with this PassManager type. + Passes.push_back(Pass); + } +#ifndef NDEBUG + void print(raw_ostream &OS) const override { + OS << this->getName(); + OS << "("; + interleave(Passes, OS, [&OS](auto *Pass) { OS << Pass->getName(); }, ","); + OS << ")"; + } + LLVM_DUMP_METHOD void dump() const override { + print(dbgs()); + dbgs() << "\n"; + } +#endif +}; + +class FunctionPassManager final + : public PassManager { +public: + FunctionPassManager(StringRef Name) : PassManager(Name) {} + bool runOnFunction(Function &F) final; +}; + +} // namespace llvm::sandboxir + +#endif // LLVM_SANDBOXIR_PASSMANAGER_H diff --git a/llvm/lib/SandboxIR/CMakeLists.txt b/llvm/lib/SandboxIR/CMakeLists.txt index 2f047944e0335..03474be0c7b80 100644 --- a/llvm/lib/SandboxIR/CMakeLists.txt +++ b/llvm/lib/SandboxIR/CMakeLists.txt @@ -1,5 +1,6 @@ add_llvm_component_library(LLVMSandboxIR Pass.cpp + PassManager.cpp SandboxIR.cpp Tracker.cpp Type.cpp diff --git a/llvm/lib/SandboxIR/PassManager.cpp b/llvm/lib/SandboxIR/PassManager.cpp new file mode 100644 index 0000000000000..d10f3926f7bcd --- /dev/null +++ b/llvm/lib/SandboxIR/PassManager.cpp @@ -0,0 +1,22 @@ +//===- PassManager.cpp - Runs a pipeline of Sandbox IR passes -------------===// +// +// 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/SandboxIR/PassManager.h" +#include "llvm/SandboxIR/SandboxIR.h" + +using namespace llvm::sandboxir; + +bool FunctionPassManager::runOnFunction(Function &F) { + bool Change = false; + for (FunctionPass *Pass : Passes) { + Change |= Pass->runOnFunction(F); + // TODO: run the verifier. + } + // TODO: Check ChangeAll against hashes before/after. + return Change; +} diff --git a/llvm/unittests/SandboxIR/PassTest.cpp b/llvm/unittests/SandboxIR/PassTest.cpp index 65992d8cb95ee..8e080128b15b3 100644 --- a/llvm/unittests/SandboxIR/PassTest.cpp +++ b/llvm/unittests/SandboxIR/PassTest.cpp @@ -9,6 +9,7 @@ #include "llvm/SandboxIR/Pass.h" #include "llvm/AsmParser/Parser.h" #include "llvm/IR/Module.h" +#include "llvm/SandboxIR/PassManager.h" #include "llvm/SandboxIR/SandboxIR.h" #include "llvm/Support/SourceMgr.h" #include "gtest/gtest.h" @@ -82,3 +83,53 @@ define void @foo() { EXPECT_DEATH(TestNamePass("-dash"), ".*start with.*"); #endif } + +TEST_F(PassTest, FunctionPassManager) { + auto *F = parseFunction(R"IR( +define void @foo() { + ret void +} +)IR", + "foo"); + class TestPass1 final : public FunctionPass { + unsigned &BBCnt; + + public: + TestPass1(unsigned &BBCnt) : FunctionPass("test-pass1"), BBCnt(BBCnt) {} + bool runOnFunction(Function &F) final { + for ([[maybe_unused]] auto &BB : F) + ++BBCnt; + return false; + } + }; + class TestPass2 final : public FunctionPass { + unsigned &BBCnt; + + public: + TestPass2(unsigned &BBCnt) : FunctionPass("test-pass2"), BBCnt(BBCnt) {} + bool runOnFunction(Function &F) final { + for ([[maybe_unused]] auto &BB : F) + ++BBCnt; + return false; + } + }; + unsigned BBCnt1 = 0; + unsigned BBCnt2 = 0; + TestPass1 TPass1(BBCnt1); + TestPass2 TPass2(BBCnt2); + + FunctionPassManager FPM("test-fpm"); + FPM.addPass(&TPass1); + FPM.addPass(&TPass2); + // Check runOnFunction(). + FPM.runOnFunction(*F); + EXPECT_EQ(BBCnt1, 1u); + EXPECT_EQ(BBCnt2, 1u); +#ifndef NDEBUG + // Check dump(). + std::string Buff; + llvm::raw_string_ostream SS(Buff); + FPM.print(SS); + EXPECT_EQ(Buff, "test-fpm(test-pass1,test-pass2)"); +#endif // NDEBUG +}