Skip to content

Commit

Permalink
[LoopNest]: Analysis to discover properties of a loop nest.
Browse files Browse the repository at this point in the history
Summary: This patch adds an analysis pass to collect loop nests and
summarize properties of the nest (e.g the nest depth, whether the nest
is perfect, what's the innermost loop, etc...).

The motivation for this patch was discussed at the latest meeting of the
LLVM loop group (https://ibm.box.com/v/llvm-loop-nest-analysis) where we
discussed
the unimodular loop transformation framework ( “A Loop Transformation
Theory and an Algorithm to Maximize Parallelism”, Michael E. Wolf and
Monica S. Lam, IEEE TPDS, October 1991). The unimodular framework
provides a convenient way to unify legality checking and code generation
for several loop nest transformations (e.g. loop reversal, loop
interchange, loop skewing) and their compositions. Given that the
unimodular framework is applicable to perfect loop nests this is one
property of interest we expose in this analysis. Several other utility
functions are also provided. In the future other properties of interest
can be added in a centralized place.
Authored By: etiotto
Reviewer: Meinersbur, bmahjour, kbarton, Whitney, dmgreen, fhahn,
reames, hfinkel, jdoerfert, ppc-slack
Reviewed By: Meinersbur
Subscribers: bryanpkc, ppc-slack, mgorny, hiraditya, llvm-commits
Tag: LLVM
Differential Revision: https://reviews.llvm.org/D68789
  • Loading branch information
Whitney Tsang committed Mar 3, 2020
1 parent 876d133 commit 3a063d6
Show file tree
Hide file tree
Showing 10 changed files with 1,459 additions and 0 deletions.
162 changes: 162 additions & 0 deletions llvm/include/llvm/Analysis/LoopNestAnalysis.h
@@ -0,0 +1,162 @@
//===- llvm/Analysis/LoopNestAnalysis.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 file defines the interface for the loop nest analysis.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_ANALYSIS_LOOPNESTANALYSIS_H
#define LLVM_ANALYSIS_LOOPNESTANALYSIS_H

#include "llvm/Analysis/LoopPass.h"
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/Transforms/Scalar/LoopPassManager.h"

namespace llvm {

using LoopVectorTy = SmallVector<Loop *, 8>;

/// This class represents a loop nest and can be used to query its properties.
class LoopNest {
public:
/// Construct a loop nest rooted by loop \p Root.
LoopNest(Loop &Root, ScalarEvolution &SE);

LoopNest() = delete;
LoopNest &operator=(const LoopNest &) = delete;

/// Construct a LoopNest object.
static std::unique_ptr<LoopNest> getLoopNest(Loop &Root, ScalarEvolution &SE);

/// Return true if the given loops \p OuterLoop and \p InnerLoop are
/// perfectly nested with respect to each other, and false otherwise.
/// Example:
/// \code
/// for(i)
/// for(j)
/// for(k)
/// \endcode
/// arePerfectlyNested(loop_i, loop_j, SE) would return true.
/// arePerfectlyNested(loop_j, loop_k, SE) would return true.
/// arePerfectlyNested(loop_i, loop_k, SE) would return false.
static bool arePerfectlyNested(const Loop &OuterLoop, const Loop &InnerLoop,
ScalarEvolution &SE);

/// Return the maximum nesting depth of the loop nest rooted by loop \p Root.
/// For example given the loop nest:
/// \code
/// for(i) // loop at level 1 and Root of the nest
/// for(j) // loop at level 2
/// <code>
/// for(k) // loop at level 3
/// \endcode
/// getMaxPerfectDepth(Loop_i) would return 2.
static unsigned getMaxPerfectDepth(const Loop &Root, ScalarEvolution &SE);

/// Return the outermost loop in the loop nest.
Loop &getOutermostLoop() const { return *Loops.front(); }

/// Return the innermost loop in the loop nest if the nest has only one
/// innermost loop, and a nullptr otherwise.
/// Note: the innermost loop returned is not necessarily perfectly nested.
Loop *getInnermostLoop() const {
if (Loops.size() == 1)
return Loops.back();

// The loops in the 'Loops' vector have been collected in breadth first
// order, therefore if the last 2 loops in it have the same nesting depth
// there isn't a unique innermost loop in the nest.
Loop *LastLoop = Loops.back();
auto SecondLastLoopIter = ++Loops.rbegin();
return (LastLoop->getLoopDepth() == (*SecondLastLoopIter)->getLoopDepth())
? nullptr
: LastLoop;
}

/// Return the loop at the given \p Index.
Loop *getLoop(unsigned Index) const {
assert(Index < Loops.size() && "Index is out of bounds");
return Loops[Index];
}

/// Return the number of loops in the nest.
size_t getNumLoops() const { return Loops.size(); }

/// Get the loops in the nest.
ArrayRef<Loop *> getLoops() const { return Loops; }

/// Retrieve a vector of perfect loop nests contained in the current loop
/// nest. For example, given the following nest containing 4 loops, this
/// member function would return {{L1,L2},{L3,L4}}.
/// \code
/// for(i) // L1
/// for(j) // L2
/// <code>
/// for(k) // L3
/// for(l) // L4
/// \endcode
SmallVector<LoopVectorTy, 4> getPerfectLoops(ScalarEvolution &SE) const;

/// Return the loop nest depth (i.e. the loop depth of the 'deepest' loop)
/// For example given the loop nest:
/// \code
/// for(i) // loop at level 1 and Root of the nest
/// for(j1) // loop at level 2
/// for(k) // loop at level 3
/// for(j2) // loop at level 2
/// \endcode
/// getNestDepth() would return 3.
unsigned getNestDepth() const {
int NestDepth =
Loops.back()->getLoopDepth() - Loops.front()->getLoopDepth() + 1;
assert(NestDepth > 0 && "Expecting NestDepth to be at least 1");
return NestDepth;
}

/// Return the maximum perfect nesting depth.
unsigned getMaxPerfectDepth() const { return MaxPerfectDepth; }

/// Return true if all loops in the loop nest are in simplify form.
bool areAllLoopsSimplifyForm() const {
return llvm::all_of(Loops,
[](const Loop *L) { return L->isLoopSimplifyForm(); });
}

protected:
const unsigned MaxPerfectDepth; // maximum perfect nesting depth level.
LoopVectorTy Loops; // the loops in the nest (in breadth first order).
};

raw_ostream &operator<<(raw_ostream &, const LoopNest &);

/// This analysis provides information for a loop nest. The analysis runs on
/// demand and can be initiated via AM.getResult<LoopNestAnalysis>.
class LoopNestAnalysis : public AnalysisInfoMixin<LoopNestAnalysis> {
friend AnalysisInfoMixin<LoopNestAnalysis>;
static AnalysisKey Key;

public:
using Result = LoopNest;
Result run(Loop &L, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR);
};

/// Printer pass for the \c LoopNest results.
class LoopNestPrinterPass : public PassInfoMixin<LoopNestPrinterPass> {
raw_ostream &OS;

public:
explicit LoopNestPrinterPass(raw_ostream &OS) : OS(OS) {}

PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR, LPMUpdater &U);
};

} // namespace llvm

#endif // LLVM_ANALYSIS_LOOPNESTANALYSIS_H
1 change: 1 addition & 0 deletions llvm/lib/Analysis/CMakeLists.txt
Expand Up @@ -53,6 +53,7 @@ add_llvm_component_library(LLVMAnalysis
LoopAccessAnalysis.cpp
LoopAnalysisManager.cpp
LoopCacheAnalysis.cpp
LoopNestAnalysis.cpp
LoopUnrollAnalyzer.cpp
LoopInfo.cpp
LoopPass.cpp
Expand Down

0 comments on commit 3a063d6

Please sign in to comment.