Skip to content

[LegacyPM] Drop analysis groups #101670

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

Merged
merged 1 commit into from
Aug 2, 2024
Merged
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
118 changes: 0 additions & 118 deletions llvm/docs/WritingAnLLVMPass.rst
Original file line number Diff line number Diff line change
Expand Up @@ -580,124 +580,6 @@ it is active. For example:
// A DominatorSet is active. This code will update it.
}

Implementing Analysis Groups
----------------------------

Now that we understand the basics of how passes are defined, how they are used,
and how they are required from other passes, it's time to get a little bit
fancier. All of the pass relationships that we have seen so far are very
simple: one pass depends on one other specific pass to be run before it can
run. For many applications, this is great, for others, more flexibility is
required.

In particular, some analyses are defined such that there is a single simple
interface to the analysis results, but multiple ways of calculating them.
Consider alias analysis for example. The most trivial alias analysis returns
"may alias" for any alias query. The most sophisticated analysis a
flow-sensitive, context-sensitive interprocedural analysis that can take a
significant amount of time to execute (and obviously, there is a lot of room
between these two extremes for other implementations). To cleanly support
situations like this, the LLVM Pass Infrastructure supports the notion of
Analysis Groups.

Analysis Group Concepts
^^^^^^^^^^^^^^^^^^^^^^^

An Analysis Group is a single simple interface that may be implemented by
multiple different passes. Analysis Groups can be given human readable names
just like passes, but unlike passes, they need not derive from the ``Pass``
class. An analysis group may have one or more implementations, one of which is
the "default" implementation.

Analysis groups are used by client passes just like other passes are: the
``AnalysisUsage::addRequired()`` and ``Pass::getAnalysis()`` methods. In order
to resolve this requirement, the :ref:`PassManager
<writing-an-llvm-pass-passmanager>` scans the available passes to see if any
implementations of the analysis group are available. If none is available, the
default implementation is created for the pass to use. All standard rules for
:ref:`interaction between passes <writing-an-llvm-pass-interaction>` still
apply.

Although :ref:`Pass Registration <writing-an-llvm-pass-registration>` is
optional for normal passes, all analysis group implementations must be
registered, and must use the :ref:`INITIALIZE_AG_PASS
<writing-an-llvm-pass-RegisterAnalysisGroup>` template to join the
implementation pool. Also, a default implementation of the interface **must**
be registered with :ref:`RegisterAnalysisGroup
<writing-an-llvm-pass-RegisterAnalysisGroup>`.

As a concrete example of an Analysis Group in action, consider the
`AliasAnalysis <https://llvm.org/doxygen/classllvm_1_1AliasAnalysis.html>`_
analysis group. The default implementation of the alias analysis interface
(the `basic-aa <https://llvm.org/doxygen/structBasicAliasAnalysis.html>`_ pass)
just does a few simple checks that don't require significant analysis to
compute (such as: two different globals can never alias each other, etc).
Passes that use the `AliasAnalysis
<https://llvm.org/doxygen/classllvm_1_1AliasAnalysis.html>`_ interface (for
example the `gvn <https://llvm.org/doxygen/classllvm_1_1GVN.html>`_ pass), do not
care which implementation of alias analysis is actually provided, they just use
the designated interface.

From the user's perspective, commands work just like normal. Issuing the
command ``opt -gvn ...`` will cause the ``basic-aa`` class to be instantiated
and added to the pass sequence. Issuing the command ``opt -somefancyaa -gvn
...`` will cause the ``gvn`` pass to use the ``somefancyaa`` alias analysis
(which doesn't actually exist, it's just a hypothetical example) instead.

.. _writing-an-llvm-pass-RegisterAnalysisGroup:

Using ``RegisterAnalysisGroup``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The ``RegisterAnalysisGroup`` template is used to register the analysis group
itself, while the ``INITIALIZE_AG_PASS`` is used to add pass implementations to
the analysis group. First, an analysis group should be registered, with a
human readable name provided for it. Unlike registration of passes, there is
no command line argument to be specified for the Analysis Group Interface
itself, because it is "abstract":

.. code-block:: c++

static RegisterAnalysisGroup<AliasAnalysis> A("Alias Analysis");

Once the analysis is registered, passes can declare that they are valid
implementations of the interface by using the following code:

.. code-block:: c++

namespace {
// Declare that we implement the AliasAnalysis interface
INITIALIZE_AG_PASS(FancyAA, AliasAnalysis , "somefancyaa",
"A more complex alias analysis implementation",
false, // Is CFG Only?
true, // Is Analysis?
false); // Is default Analysis Group implementation?
}

This just shows a class ``FancyAA`` that uses the ``INITIALIZE_AG_PASS`` macro
both to register and to "join" the `AliasAnalysis
<https://llvm.org/doxygen/classllvm_1_1AliasAnalysis.html>`_ analysis group.
Every implementation of an analysis group should join using this macro.

.. code-block:: c++

namespace {
// Declare that we implement the AliasAnalysis interface
INITIALIZE_AG_PASS(BasicAA, AliasAnalysis, "basic-aa",
"Basic Alias Analysis (default AA impl)",
false, // Is CFG Only?
true, // Is Analysis?
true); // Is default Analysis Group implementation?
}

Here we show how the default implementation is specified (using the final
argument to the ``INITIALIZE_AG_PASS`` template). There must be exactly one
default implementation available at all times for an Analysis Group to be used.
Only default implementation can derive from ``ImmutablePass``. Here we declare
that the `BasicAliasAnalysis
<https://llvm.org/doxygen/structBasicAliasAnalysis.html>`_ pass is the default
implementation for the interface.

Pass Statistics
===============

Expand Down
3 changes: 1 addition & 2 deletions llvm/include/llvm/Pass.h
Original file line number Diff line number Diff line change
Expand Up @@ -276,8 +276,7 @@ class ModulePass : public Pass {

//===----------------------------------------------------------------------===//
/// ImmutablePass class - This class is used to provide information that does
/// not need to be run. This is useful for things like target information and
/// "basic" versions of AnalysisGroups.
/// not need to be run. This is useful for things like target information.
///
class ImmutablePass : public ModulePass {
public:
Expand Down
28 changes: 1 addition & 27 deletions llvm/include/llvm/PassInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ class PassInfo {
const void *PassID;
const bool IsCFGOnlyPass = false; // Pass only looks at the CFG.
const bool IsAnalysis; // True if an analysis pass.
const bool IsAnalysisGroup; // True if an analysis group.
std::vector<const PassInfo *> ItfImpl; // Interfaces implemented by this pass
NormalCtor_t NormalCtor = nullptr;

public:
Expand All @@ -47,13 +45,7 @@ class PassInfo {
PassInfo(StringRef name, StringRef arg, const void *pi, NormalCtor_t normal,
bool isCFGOnly, bool is_analysis)
: PassName(name), PassArgument(arg), PassID(pi), IsCFGOnlyPass(isCFGOnly),
IsAnalysis(is_analysis), IsAnalysisGroup(false), NormalCtor(normal) {}

/// PassInfo ctor - Do not call this directly, this should only be invoked
/// through RegisterPass. This version is for use by analysis groups; it
/// does not auto-register the pass.
PassInfo(StringRef name, const void *pi)
: PassName(name), PassID(pi), IsAnalysis(false), IsAnalysisGroup(true) {}
IsAnalysis(is_analysis), NormalCtor(normal) {}

PassInfo(const PassInfo &) = delete;
PassInfo &operator=(const PassInfo &) = delete;
Expand All @@ -73,9 +65,6 @@ class PassInfo {
/// Return true if this PassID implements the specified ID pointer.
bool isPassID(const void *IDPtr) const { return PassID == IDPtr; }

/// isAnalysisGroup - Return true if this is an analysis group, not a normal
/// pass.
bool isAnalysisGroup() const { return IsAnalysisGroup; }
bool isAnalysis() const { return IsAnalysis; }

/// isCFGOnlyPass - return true if this pass only looks at the CFG for the
Expand All @@ -94,25 +83,10 @@ class PassInfo {

/// createPass() - Use this method to create an instance of this pass.
Pass *createPass() const {
assert((!isAnalysisGroup() || NormalCtor) &&
"No default implementation found for analysis group!");
assert(NormalCtor &&
"Cannot call createPass on PassInfo without default ctor!");
return NormalCtor();
}

/// addInterfaceImplemented - This method is called when this pass is
/// registered as a member of an analysis group with the RegisterAnalysisGroup
/// template.
void addInterfaceImplemented(const PassInfo *ItfPI) {
ItfImpl.push_back(ItfPI);
}

/// getInterfacesImplemented - Return a list of all of the analysis group
/// interfaces implemented by this pass.
const std::vector<const PassInfo*> &getInterfacesImplemented() const {
return ItfImpl;
}
};

} // end namespace llvm
Expand Down
7 changes: 0 additions & 7 deletions llvm/include/llvm/PassRegistry.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,6 @@ class PassRegistry {
/// registry. Required in order to use the pass with a PassManager.
void registerPass(const PassInfo &PI, bool ShouldFree = false);

/// registerAnalysisGroup - Register an analysis group (or a pass implementing
// an analysis group) with the registry. Like registerPass, this is required
// in order for a PassManager to be able to use this group/pass.
void registerAnalysisGroup(const void *InterfaceID, const void *PassID,
PassInfo &Registeree, bool isDefault,
bool ShouldFree = false);

/// enumerateWith - Enumerate the registered passes, calling the provided
/// PassRegistrationListener's passEnumerate() callback on each of them.
void enumerateWith(PassRegistrationListener *L);
Expand Down
91 changes: 0 additions & 91 deletions llvm/include/llvm/PassSupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@ class Pass;
static void *initialize##passName##PassOnce(PassRegistry &Registry) {

#define INITIALIZE_PASS_DEPENDENCY(depName) initialize##depName##Pass(Registry);
#define INITIALIZE_AG_DEPENDENCY(depName) \
initialize##depName##AnalysisGroup(Registry);

#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis) \
PassInfo *PI = new PassInfo( \
Expand Down Expand Up @@ -117,95 +115,6 @@ template <typename passName> struct RegisterPass : public PassInfo {
}
};

/// RegisterAnalysisGroup - Register a Pass as a member of an analysis _group_.
/// Analysis groups are used to define an interface (which need not derive from
/// Pass) that is required by passes to do their job. Analysis Groups differ
/// from normal analyses because any available implementation of the group will
/// be used if it is available.
///
/// If no analysis implementing the interface is available, a default
/// implementation is created and added. A pass registers itself as the default
/// implementation by specifying 'true' as the second template argument of this
/// class.
///
/// In addition to registering itself as an analysis group member, a pass must
/// register itself normally as well. Passes may be members of multiple groups
/// and may still be "required" specifically by name.
///
/// The actual interface may also be registered as well (by not specifying the
/// second template argument). The interface should be registered to associate
/// a nice name with the interface.
class RegisterAGBase : public PassInfo {
public:
RegisterAGBase(StringRef Name, const void *InterfaceID,
const void *PassID = nullptr, bool isDefault = false);
};

template <typename Interface, bool Default = false>
struct RegisterAnalysisGroup : public RegisterAGBase {
explicit RegisterAnalysisGroup(PassInfo &RPB)
: RegisterAGBase(RPB.getPassName(), &Interface::ID, RPB.getTypeInfo(),
Default) {}

explicit RegisterAnalysisGroup(const char *Name)
: RegisterAGBase(Name, &Interface::ID) {}
};

#define INITIALIZE_ANALYSIS_GROUP(agName, name, defaultPass) \
static void *initialize##agName##AnalysisGroupOnce(PassRegistry &Registry) { \
initialize##defaultPass##Pass(Registry); \
PassInfo *AI = new PassInfo(name, &agName::ID); \
Registry.registerAnalysisGroup(&agName::ID, 0, *AI, false, true); \
return AI; \
} \
static llvm::once_flag Initialize##agName##AnalysisGroupFlag; \
void llvm::initialize##agName##AnalysisGroup(PassRegistry &Registry) { \
llvm::call_once(Initialize##agName##AnalysisGroupFlag, \
initialize##agName##AnalysisGroupOnce, \
std::ref(Registry)); \
}

#define INITIALIZE_AG_PASS(passName, agName, arg, name, cfg, analysis, def) \
static void *initialize##passName##PassOnce(PassRegistry &Registry) { \
if (!def) \
initialize##agName##AnalysisGroup(Registry); \
PassInfo *PI = new PassInfo( \
name, arg, &passName::ID, \
PassInfo::NormalCtor_t(callDefaultCtor<passName>), cfg, analysis); \
Registry.registerPass(*PI, true); \
\
PassInfo *AI = new PassInfo(name, &agName::ID); \
Registry.registerAnalysisGroup(&agName::ID, &passName::ID, *AI, def, \
true); \
return AI; \
} \
static llvm::once_flag Initialize##passName##PassFlag; \
void llvm::initialize##passName##Pass(PassRegistry &Registry) { \
llvm::call_once(Initialize##passName##PassFlag, \
initialize##passName##PassOnce, std::ref(Registry)); \
}

#define INITIALIZE_AG_PASS_BEGIN(passName, agName, arg, n, cfg, analysis, def) \
static void *initialize##passName##PassOnce(PassRegistry &Registry) { \
if (!def) \
initialize##agName##AnalysisGroup(Registry);

#define INITIALIZE_AG_PASS_END(passName, agName, arg, n, cfg, analysis, def) \
PassInfo *PI = new PassInfo( \
n, arg, &passName::ID, \
PassInfo::NormalCtor_t(callDefaultCtor<passName>), cfg, analysis); \
Registry.registerPass(*PI, true); \
\
PassInfo *AI = new PassInfo(n, &agName::ID); \
Registry.registerAnalysisGroup(&agName::ID, &passName::ID, *AI, def, true); \
return AI; \
} \
static llvm::once_flag Initialize##passName##PassFlag; \
void llvm::initialize##passName##Pass(PassRegistry &Registry) { \
llvm::call_once(Initialize##passName##PassFlag, \
initialize##passName##PassOnce, std::ref(Registry)); \
}

//===---------------------------------------------------------------------------
/// PassRegistrationListener class - This class is meant to be derived from by
/// clients that are interested in which passes get registered and unregistered
Expand Down
42 changes: 5 additions & 37 deletions llvm/lib/IR/LegacyPassManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -808,13 +808,6 @@ void PMTopLevelManager::addImmutablePass(ImmutablePass *P) {
// doing lookups.
AnalysisID AID = P->getPassID();
ImmutablePassMap[AID] = P;

// Also add any interfaces implemented by the immutable pass to the map for
// fast lookup.
const PassInfo *PassInf = findAnalysisPassInfo(AID);
assert(PassInf && "Expected all immutable passes to be initialized");
for (const PassInfo *ImmPI : PassInf->getInterfacesImplemented())
ImmutablePassMap[ImmPI->getTypeInfo()] = P;
}

// Print passes managed by this top level manager.
Expand Down Expand Up @@ -844,8 +837,7 @@ void PMTopLevelManager::dumpArguments() const {
for (ImmutablePass *P : ImmutablePasses)
if (const PassInfo *PI = findAnalysisPassInfo(P->getPassID())) {
assert(PI && "Expected all immutable passes to be initialized");
if (!PI->isAnalysisGroup())
dbgs() << " -" << PI->getPassArgument();
dbgs() << " -" << PI->getPassArgument();
}
for (PMDataManager *PM : PassManagers)
PM->dumpPassArguments();
Expand Down Expand Up @@ -878,15 +870,6 @@ void PMDataManager::recordAvailableAnalysis(Pass *P) {
AnalysisID PI = P->getPassID();

AvailableAnalysis[PI] = P;

assert(!AvailableAnalysis.empty());

// This pass is the current implementation of all of the interfaces it
// implements as well.
const PassInfo *PInf = TPM->findAnalysisPassInfo(PI);
if (!PInf) return;
for (const PassInfo *PI : PInf->getInterfacesImplemented())
AvailableAnalysis[PI->getTypeInfo()] = P;
}

// Return true if P preserves high level analysis used by other
Expand Down Expand Up @@ -1004,20 +987,8 @@ void PMDataManager::freePass(Pass *P, StringRef Msg,
P->releaseMemory();
}

AnalysisID PI = P->getPassID();
if (const PassInfo *PInf = TPM->findAnalysisPassInfo(PI)) {
// Remove the pass itself (if it is not already removed).
AvailableAnalysis.erase(PI);

// Remove all interfaces this pass implements, for which it is also
// listed as the available implementation.
for (const PassInfo *PI : PInf->getInterfacesImplemented()) {
DenseMap<AnalysisID, Pass *>::iterator Pos =
AvailableAnalysis.find(PI->getTypeInfo());
if (Pos != AvailableAnalysis.end() && Pos->second == P)
AvailableAnalysis.erase(Pos);
}
}
// Remove the pass itself (if it is not already removed).
AvailableAnalysis.erase(P->getPassID());
}

/// Add pass P into the PassVector. Update
Expand Down Expand Up @@ -1173,11 +1144,8 @@ void PMDataManager::dumpPassArguments() const {
for (Pass *P : PassVector) {
if (PMDataManager *PMD = P->getAsPMDataManager())
PMD->dumpPassArguments();
else
if (const PassInfo *PI =
TPM->findAnalysisPassInfo(P->getPassID()))
if (!PI->isAnalysisGroup())
dbgs() << " -" << PI->getPassArgument();
else if (const PassInfo *PI = TPM->findAnalysisPassInfo(P->getPassID()))
dbgs() << " -" << PI->getPassArgument();
}
}

Expand Down
Loading
Loading