Skip to content

[CodeGen] Support MachineFunctionProperties in PassConcept #79749

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 28 additions & 13 deletions llvm/include/llvm/CodeGen/MachinePassManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,13 @@

#include "llvm/ADT/FunctionExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/MachinePassManagerInternal.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Support/Error.h"

#include <map>

namespace llvm {
class Module;
class Function;
class MachineFunction;

extern template class AnalysisManager<MachineFunction>;

Expand All @@ -43,7 +41,18 @@ extern template class AnalysisManager<MachineFunction>;
/// automatically mixes in \c PassInfoMixin.
template <typename DerivedT>
struct MachinePassInfoMixin : public PassInfoMixin<DerivedT> {
// TODO: Add MachineFunctionProperties support.
// MachineFunctionProperties support
static MachineFunctionProperties getRequiredProperties() {
return MachineFunctionProperties();
}

static MachineFunctionProperties getSetProperties() {
return MachineFunctionProperties();
}

static MachineFunctionProperties getClearedProperties() {
return MachineFunctionProperties();
}
Copy link
Contributor Author

@paperchalice paperchalice Jan 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merge them into PassInfoMixin seems better but impossible (at least in C++17).

};

/// An AnalysisManager<MachineFunction> that also exposes IR analysis results.
Expand Down Expand Up @@ -170,6 +179,18 @@ class MachineFunctionPassManager
addRunOnModule<PassT>(P);
}

// Avoid diamond problem. Both MachinePassInfoMixin and PassManager inherit
// PassInfoMixin.
static MachineFunctionProperties getRequiredProperties() {
return MachineFunctionProperties();
}
static MachineFunctionProperties getSetProperties() {
return MachineFunctionProperties();
}
static MachineFunctionProperties getClearedProperties() {
return MachineFunctionProperties();
}

private:
template <typename PassT>
using has_init_t = decltype(std::declval<PassT &>().doInitialization(
Expand All @@ -183,9 +204,7 @@ class MachineFunctionPassManager
template <typename PassT>
std::enable_if_t<is_detected<has_init_t, PassT>::value>
addDoInitialization(PassConceptT *Pass) {
using PassModelT =
detail::PassModel<MachineFunction, PassT, PreservedAnalyses,
MachineFunctionAnalysisManager>;
using PassModelT = detail::MachinePassModel<PassT>;
auto *P = static_cast<PassModelT *>(Pass);
InitializationFuncs.emplace_back(
[=](Module &M, MachineFunctionAnalysisManager &MFAM) {
Expand All @@ -205,9 +224,7 @@ class MachineFunctionPassManager
template <typename PassT>
std::enable_if_t<is_detected<has_fini_t, PassT>::value>
addDoFinalization(PassConceptT *Pass) {
using PassModelT =
detail::PassModel<MachineFunction, PassT, PreservedAnalyses,
MachineFunctionAnalysisManager>;
using PassModelT = detail::MachinePassModel<PassT>;
auto *P = static_cast<PassModelT *>(Pass);
FinalizationFuncs.emplace_back(
[=](Module &M, MachineFunctionAnalysisManager &MFAM) {
Expand Down Expand Up @@ -236,9 +253,7 @@ class MachineFunctionPassManager
"machine module pass needs to define machine function pass "
"api. sorry.");

using PassModelT =
detail::PassModel<MachineFunction, PassT, PreservedAnalyses,
MachineFunctionAnalysisManager>;
using PassModelT = detail::MachinePassModel<PassT>;
auto *P = static_cast<PassModelT *>(Pass);
MachineModulePasses.emplace(
Passes.size() - 1,
Expand Down
68 changes: 68 additions & 0 deletions llvm/include/llvm/CodeGen/MachinePassManagerInternal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//===- MachinePassManagerInternal.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
//
//===----------------------------------------------------------------------===//
/// \file
///
/// This header provides internal APIs and implementation details used by the
/// pass management interfaces exposed in MachinePassManager.h. Most of them are
/// copied from PassManagerInternal.h.
/// See also PassManagerInternal.h.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CODEGEN_MACHINEPASSMANAGERINTERNAL_H
#define LLVM_CODEGEN_MACHINEPASSMANAGERINTERNAL_H

#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/IR/PassManager.h"

namespace llvm {

class MachineFunctionAnalysisManager;

using MachinePassConcept =
detail::PassConcept<MachineFunction, MachineFunctionAnalysisManager>;

namespace detail {

/// Template for the abstract base class used to dispatch
/// polymorphically over pass objects. See also \c PassConcept.
template <>
struct PassConcept<MachineFunction, MachineFunctionAnalysisManager>
: public PassConceptBase<MachineFunction, MachineFunctionAnalysisManager> {
/// MachineFunction Properties.
PassConcept(MachineFunctionProperties RequiredProperties,
MachineFunctionProperties SetProperties,
MachineFunctionProperties ClearedProperties)
: RequiredProperties(RequiredProperties), SetProperties(SetProperties),
ClearedProperties(ClearedProperties) {}

MachineFunctionProperties RequiredProperties = MachineFunctionProperties();
MachineFunctionProperties SetProperties = MachineFunctionProperties();
MachineFunctionProperties ClearedProperties = MachineFunctionProperties();
};

template <typename IRUnitT, typename PassT, typename PreservedAnalysesT,
typename AnalysisManagerT, typename... ExtraArgTs>
template <typename MachineFunctionT, typename>
PassModel<IRUnitT, PassT, PreservedAnalysesT, AnalysisManagerT, ExtraArgTs...>::
PassModel(PassT Pass, MachineFunctionProperties RequiredProperties,
MachineFunctionProperties SetProperties,
MachineFunctionProperties ClearedProperties)
: PassConcept<MachineFunction, MachineFunctionAnalysisManager>(
RequiredProperties, SetProperties, ClearedProperties),
Pass(std::move(Pass)) {}

template <typename PassT>
using MachinePassModel = PassModel<MachineFunction, PassT, PreservedAnalyses,
MachineFunctionAnalysisManager>;

} // namespace detail

} // namespace llvm

#endif // LLVM_CODEGEN_MACHINEPASSMANAGERINTERNAL_H
57 changes: 54 additions & 3 deletions llvm/include/llvm/IR/PassManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -576,8 +576,14 @@ class PassManager : public PassInfoMixin<
ExtraArgTs...>;
// Do not use make_unique or emplace_back, they cause too many template
// instantiations, causing terrible compile times.
Passes.push_back(std::unique_ptr<PassConceptT>(
new PassModelT(std::forward<PassT>(Pass))));
if constexpr (std::is_same_v<IRUnitT, MachineFunction>) {
Passes.push_back(std::unique_ptr<PassConceptT>(new PassModelT(
std::forward<PassT>(Pass), PassT::getRequiredProperties(),
PassT::getSetProperties(), PassT::getClearedProperties())));
} else {
Passes.push_back(std::unique_ptr<PassConceptT>(
new PassModelT(std::forward<PassT>(Pass))));
}
}

/// When adding a pass manager pass that has the same type as this pass
Expand Down Expand Up @@ -1292,9 +1298,37 @@ struct RequireAnalysisPass
OS << "require<" << PassName << '>';
}
static bool isRequired() { return true; }

// MachineFunctionPass interface, define them separately to prevent
// dependency on CodeGen
template <typename MachineFunctionT = IRUnitT,
typename MachineFunctionPropertiesT = MachineFunctionProperties,
typename = std::enable_if_t<
std::is_same_v<MachineFunctionT, MachineFunction>>>
static MachineFunctionPropertiesT getRequiredProperties() {
return MachineFunctionPropertiesT();
}

template <typename MachineFunctionT = IRUnitT,
typename MachineFunctionPropertiesT = MachineFunctionProperties,
typename = std::enable_if_t<
std::is_same_v<MachineFunctionT, MachineFunction>>>
static MachineFunctionPropertiesT getSetProperties() {
return MachineFunctionPropertiesT();
}

template <typename MachineFunctionT = IRUnitT,
typename MachineFunctionPropertiesT = MachineFunctionProperties,
typename = std::enable_if_t<
std::is_same_v<MachineFunctionT, MachineFunction>>>
static MachineFunctionPropertiesT getClearedProperties() {
return MachineFunctionPropertiesT();
}
};

/// A no-op pass template which simply forces a specific analysis result
template <typename DerivedT> struct MachineFunctionAnalysisInfoMixin;

/// A no-op IR pass template which simply forces a specific analysis result
/// to be invalidated.
template <typename AnalysisT>
struct InvalidateAnalysisPass
Expand All @@ -1317,6 +1351,23 @@ struct InvalidateAnalysisPass
auto PassName = MapClassName2PassName(ClassName);
OS << "invalidate<" << PassName << '>';
}

// MachineFunctionPass interface, define them separately to prevent
// dependency on CodeGen
template <typename MachineFunctionPropertiesT = MachineFunctionProperties>
static MachineFunctionPropertiesT getRequiredProperties() {
return MachineFunctionPropertiesT();
}

template <typename MachineFunctionPropertiesT = MachineFunctionProperties>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, are these templates just to work around the IR -> CodeGen depenency? that's not great

let me try some things locally, like making a completely separate MachineFunctionPassManager

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh I see that PassModel in PassManagerInternal.h also does this...

static MachineFunctionPropertiesT getSetProperties() {
return MachineFunctionPropertiesT();
}

template <typename MachineFunctionPropertiesT = MachineFunctionProperties>
static MachineFunctionPropertiesT getClearedProperties() {
return MachineFunctionPropertiesT();
}
};

/// A utility pass that does nothing, but preserves no analyses.
Expand Down
17 changes: 15 additions & 2 deletions llvm/include/llvm/IR/PassManagerInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,18 @@ namespace llvm {
template <typename IRUnitT> class AllAnalysesOn;
template <typename IRUnitT, typename... ExtraArgTs> class AnalysisManager;
class PreservedAnalyses;
class MachineFunction;
class MachineFunctionProperties;

// Implementation details of the pass manager interfaces.
namespace detail {

/// Template for the abstract base class used to dispatch
/// polymorphically over pass objects.
template <typename IRUnitT, typename AnalysisManagerT, typename... ExtraArgTs>
struct PassConcept {
struct PassConceptBase {
// Boiler plate necessary for the container of derived classes.
virtual ~PassConcept() = default;
virtual ~PassConceptBase() = default;

/// The polymorphic API which runs the pass over a given IR entity.
///
Expand All @@ -60,6 +62,10 @@ struct PassConcept {
virtual bool isRequired() const = 0;
};

template <typename IRUnitT, typename AnalysisManagerT, typename... ExtraArgTs>
struct PassConcept
: public PassConceptBase<IRUnitT, AnalysisManagerT, ExtraArgTs...> {};

/// A template wrapper used to implement the polymorphic API.
///
/// Can be instantiated for any object which provides a \c run method accepting
Expand All @@ -69,6 +75,13 @@ template <typename IRUnitT, typename PassT, typename PreservedAnalysesT,
typename AnalysisManagerT, typename... ExtraArgTs>
struct PassModel : PassConcept<IRUnitT, AnalysisManagerT, ExtraArgTs...> {
explicit PassModel(PassT Pass) : Pass(std::move(Pass)) {}

template <typename MachineFunctionT = IRUnitT,
typename = std::enable_if_t<
std::is_same_v<MachineFunctionT, MachineFunction>>>
explicit PassModel(PassT Pass, MachineFunctionProperties RequiredProperties,
MachineFunctionProperties SetProperties,
MachineFunctionProperties ClearedProperties);
// We have to explicitly define all the special member functions because MSVC
// refuses to generate them.
PassModel(const PassModel &Arg) : Pass(Arg.Pass) {}
Expand Down
6 changes: 4 additions & 2 deletions llvm/unittests/CodeGen/PassManagerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ AnalysisKey TestMachineFunctionAnalysis::Key;
const std::string DoInitErrMsg = "doInitialization failed";
const std::string DoFinalErrMsg = "doFinalization failed";

struct TestMachineFunctionPass : public PassInfoMixin<TestMachineFunctionPass> {
struct TestMachineFunctionPass
: public MachinePassInfoMixin<TestMachineFunctionPass> {
TestMachineFunctionPass(int &Count, std::vector<int> &BeforeInitialization,
std::vector<int> &BeforeFinalization,
std::vector<int> &MachineFunctionPassCount)
Expand Down Expand Up @@ -139,7 +140,8 @@ struct TestMachineFunctionPass : public PassInfoMixin<TestMachineFunctionPass> {
std::vector<int> &MachineFunctionPassCount;
};

struct TestMachineModulePass : public PassInfoMixin<TestMachineModulePass> {
struct TestMachineModulePass
: public MachinePassInfoMixin<TestMachineModulePass> {
TestMachineModulePass(int &Count, std::vector<int> &MachineModulePassCount)
: Count(Count), MachineModulePassCount(MachineModulePassCount) {}

Expand Down