[llvm] [DA][NFC] clang-format DependenceAnalysis (PR #151505)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 5 11:44:17 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-analysis
Author: Michael Kruse (Meinersbur)
<details>
<summary>Changes</summary>
To avoid noise in PRs such as #<!-- -->146383.
---
Patch is 140.46 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/151505.diff
2 Files Affected:
- (modified) llvm/include/llvm/Analysis/DependenceAnalysis.h (+858-942)
- (modified) llvm/lib/Analysis/DependenceAnalysis.cpp (+189-295)
``````````diff
diff --git a/llvm/include/llvm/Analysis/DependenceAnalysis.h b/llvm/include/llvm/Analysis/DependenceAnalysis.h
index f98bd684149f9..84b9f0464966b 100644
--- a/llvm/include/llvm/Analysis/DependenceAnalysis.h
+++ b/llvm/include/llvm/Analysis/DependenceAnalysis.h
@@ -47,994 +47,910 @@
#include "llvm/Support/Compiler.h"
namespace llvm {
- class AAResults;
- template <typename T> class ArrayRef;
- class Loop;
- class LoopInfo;
- class SCEVConstant;
- class raw_ostream;
-
- /// Dependence - This class represents a dependence between two memory
- /// memory references in a function. It contains minimal information and
- /// is used in the very common situation where the compiler is unable to
- /// determine anything beyond the existence of a dependence; that is, it
- /// represents a confused dependence (see also FullDependence). In most
- /// cases (for output, flow, and anti dependences), the dependence implies
- /// an ordering, where the source must precede the destination; in contrast,
- /// input dependences are unordered.
- ///
- /// When a dependence graph is built, each Dependence will be a member of
- /// the set of predecessor edges for its destination instruction and a set
- /// if successor edges for its source instruction. These sets are represented
- /// as singly-linked lists, with the "next" fields stored in the dependence
- /// itelf.
- class LLVM_ABI Dependence {
- protected:
- Dependence(Dependence &&) = default;
- Dependence &operator=(Dependence &&) = default;
-
- public:
- Dependence(Instruction *Source, Instruction *Destination,
- const SCEVUnionPredicate &A)
- : Src(Source), Dst(Destination), Assumptions(A) {}
- virtual ~Dependence() = default;
-
- /// Dependence::DVEntry - Each level in the distance/direction vector
- /// has a direction (or perhaps a union of several directions), and
- /// perhaps a distance.
- struct DVEntry {
- enum : unsigned char {
- NONE = 0,
- LT = 1,
- EQ = 2,
- LE = 3,
- GT = 4,
- NE = 5,
- GE = 6,
- ALL = 7
- };
- unsigned char Direction : 3; // Init to ALL, then refine.
- bool Scalar : 1; // Init to true.
- bool PeelFirst : 1; // Peeling the first iteration will break dependence.
- bool PeelLast : 1; // Peeling the last iteration will break the dependence.
- bool Splitable : 1; // Splitting the loop will break dependence.
- const SCEV *Distance = nullptr; // NULL implies no distance available.
- DVEntry()
- : Direction(ALL), Scalar(true), PeelFirst(false), PeelLast(false),
- Splitable(false) {}
+class AAResults;
+template <typename T> class ArrayRef;
+class Loop;
+class LoopInfo;
+class SCEVConstant;
+class raw_ostream;
+
+/// Dependence - This class represents a dependence between two memory
+/// memory references in a function. It contains minimal information and
+/// is used in the very common situation where the compiler is unable to
+/// determine anything beyond the existence of a dependence; that is, it
+/// represents a confused dependence (see also FullDependence). In most
+/// cases (for output, flow, and anti dependences), the dependence implies
+/// an ordering, where the source must precede the destination; in contrast,
+/// input dependences are unordered.
+///
+/// When a dependence graph is built, each Dependence will be a member of
+/// the set of predecessor edges for its destination instruction and a set
+/// if successor edges for its source instruction. These sets are represented
+/// as singly-linked lists, with the "next" fields stored in the dependence
+/// itelf.
+class LLVM_ABI Dependence {
+protected:
+ Dependence(Dependence &&) = default;
+ Dependence &operator=(Dependence &&) = default;
+
+public:
+ Dependence(Instruction *Source, Instruction *Destination,
+ const SCEVUnionPredicate &A)
+ : Src(Source), Dst(Destination), Assumptions(A) {}
+ virtual ~Dependence() = default;
+
+ /// Dependence::DVEntry - Each level in the distance/direction vector
+ /// has a direction (or perhaps a union of several directions), and
+ /// perhaps a distance.
+ struct DVEntry {
+ enum : unsigned char {
+ NONE = 0,
+ LT = 1,
+ EQ = 2,
+ LE = 3,
+ GT = 4,
+ NE = 5,
+ GE = 6,
+ ALL = 7
};
+ unsigned char Direction : 3; // Init to ALL, then refine.
+ bool Scalar : 1; // Init to true.
+ bool PeelFirst : 1; // Peeling the first iteration will break dependence.
+ bool PeelLast : 1; // Peeling the last iteration will break the dependence.
+ bool Splitable : 1; // Splitting the loop will break dependence.
+ const SCEV *Distance = nullptr; // NULL implies no distance available.
+ DVEntry()
+ : Direction(ALL), Scalar(true), PeelFirst(false), PeelLast(false),
+ Splitable(false) {}
+ };
- /// getSrc - Returns the source instruction for this dependence.
- ///
- Instruction *getSrc() const { return Src; }
-
- /// getDst - Returns the destination instruction for this dependence.
- ///
- Instruction *getDst() const { return Dst; }
-
- /// isInput - Returns true if this is an input dependence.
- ///
- bool isInput() const;
+ /// getSrc - Returns the source instruction for this dependence.
+ Instruction *getSrc() const { return Src; }
- /// isOutput - Returns true if this is an output dependence.
- ///
- bool isOutput() const;
+ /// getDst - Returns the destination instruction for this dependence.
+ Instruction *getDst() const { return Dst; }
- /// isFlow - Returns true if this is a flow (aka true) dependence.
- ///
- bool isFlow() const;
+ /// isInput - Returns true if this is an input dependence.
+ bool isInput() const;
- /// isAnti - Returns true if this is an anti dependence.
- ///
- bool isAnti() const;
+ /// isOutput - Returns true if this is an output dependence.
+ bool isOutput() const;
- /// isOrdered - Returns true if dependence is Output, Flow, or Anti
- ///
- bool isOrdered() const { return isOutput() || isFlow() || isAnti(); }
+ /// isFlow - Returns true if this is a flow (aka true) dependence.
+ bool isFlow() const;
- /// isUnordered - Returns true if dependence is Input
- ///
- bool isUnordered() const { return isInput(); }
+ /// isAnti - Returns true if this is an anti dependence.
+ bool isAnti() const;
- /// isLoopIndependent - Returns true if this is a loop-independent
- /// dependence.
- virtual bool isLoopIndependent() const { return true; }
+ /// isOrdered - Returns true if dependence is Output, Flow, or Anti
+ bool isOrdered() const { return isOutput() || isFlow() || isAnti(); }
- /// isConfused - Returns true if this dependence is confused
- /// (the compiler understands nothing and makes worst-case
- /// assumptions).
- virtual bool isConfused() const { return true; }
+ /// isUnordered - Returns true if dependence is Input
+ bool isUnordered() const { return isInput(); }
- /// isConsistent - Returns true if this dependence is consistent
- /// (occurs every time the source and destination are executed).
- virtual bool isConsistent() const { return false; }
+ /// isLoopIndependent - Returns true if this is a loop-independent
+ /// dependence.
+ virtual bool isLoopIndependent() const { return true; }
- /// getLevels - Returns the number of common loops surrounding the
- /// source and destination of the dependence.
- virtual unsigned getLevels() const { return 0; }
+ /// isConfused - Returns true if this dependence is confused
+ /// (the compiler understands nothing and makes worst-case assumptions).
+ virtual bool isConfused() const { return true; }
- /// getDirection - Returns the direction associated with a particular
- /// level.
- virtual unsigned getDirection(unsigned Level) const { return DVEntry::ALL; }
+ /// isConsistent - Returns true if this dependence is consistent
+ /// (occurs every time the source and destination are executed).
+ virtual bool isConsistent() const { return false; }
- /// getDistance - Returns the distance (or NULL) associated with a
- /// particular level.
- virtual const SCEV *getDistance(unsigned Level) const { return nullptr; }
+ /// getLevels - Returns the number of common loops surrounding the
+ /// source and destination of the dependence.
+ virtual unsigned getLevels() const { return 0; }
- /// Check if the direction vector is negative. A negative direction
- /// vector means Src and Dst are reversed in the actual program.
- virtual bool isDirectionNegative() const { return false; }
+ /// getDirection - Returns the direction associated with a particular level.
+ virtual unsigned getDirection(unsigned Level) const { return DVEntry::ALL; }
- /// If the direction vector is negative, normalize the direction
- /// vector to make it non-negative. Normalization is done by reversing
- /// Src and Dst, plus reversing the dependence directions and distances
- /// in the vector.
- virtual bool normalize(ScalarEvolution *SE) { return false; }
+ /// getDistance - Returns the distance (or NULL) associated with a particular
+ /// level.
+ virtual const SCEV *getDistance(unsigned Level) const { return nullptr; }
- /// isPeelFirst - Returns true if peeling the first iteration from
- /// this loop will break this dependence.
- virtual bool isPeelFirst(unsigned Level) const { return false; }
+ /// Check if the direction vector is negative. A negative direction
+ /// vector means Src and Dst are reversed in the actual program.
+ virtual bool isDirectionNegative() const { return false; }
+
+ /// If the direction vector is negative, normalize the direction
+ /// vector to make it non-negative. Normalization is done by reversing
+ /// Src and Dst, plus reversing the dependence directions and distances
+ /// in the vector.
+ virtual bool normalize(ScalarEvolution *SE) { return false; }
- /// isPeelLast - Returns true if peeling the last iteration from
- /// this loop will break this dependence.
- virtual bool isPeelLast(unsigned Level) const { return false; }
+ /// isPeelFirst - Returns true if peeling the first iteration from
+ /// this loop will break this dependence.
+ virtual bool isPeelFirst(unsigned Level) const { return false; }
- /// isSplitable - Returns true if splitting this loop will break
- /// the dependence.
- virtual bool isSplitable(unsigned Level) const { return false; }
+ /// isPeelLast - Returns true if peeling the last iteration from
+ /// this loop will break this dependence.
+ virtual bool isPeelLast(unsigned Level) const { return false; }
- /// isScalar - Returns true if a particular level is scalar; that is,
- /// if no subscript in the source or destination mention the induction
- /// variable associated with the loop at this level.
- virtual bool isScalar(unsigned Level) const;
+ /// isSplitable - Returns true if splitting this loop will break the
+ /// dependence.
+ virtual bool isSplitable(unsigned Level) const { return false; }
- /// getNextPredecessor - Returns the value of the NextPredecessor
- /// field.
- const Dependence *getNextPredecessor() const { return NextPredecessor; }
+ /// isScalar - Returns true if a particular level is scalar; that is,
+ /// if no subscript in the source or destination mention the induction
+ /// variable associated with the loop at this level.
+ virtual bool isScalar(unsigned Level) const;
+
+ /// getNextPredecessor - Returns the value of the NextPredecessor field.
+ const Dependence *getNextPredecessor() const { return NextPredecessor; }
+
+ /// getNextSuccessor - Returns the value of the NextSuccessor field.
+ const Dependence *getNextSuccessor() const { return NextSuccessor; }
+
+ /// setNextPredecessor - Sets the value of the NextPredecessor
+ /// field.
+ void setNextPredecessor(const Dependence *pred) { NextPredecessor = pred; }
+
+ /// setNextSuccessor - Sets the value of the NextSuccessor field.
+ void setNextSuccessor(const Dependence *succ) { NextSuccessor = succ; }
+
+ /// getRuntimeAssumptions - Returns the runtime assumptions under which this
+ /// Dependence relation is valid.
+ SCEVUnionPredicate getRuntimeAssumptions() const { return Assumptions; }
+
+ /// dump - For debugging purposes, dumps a dependence to OS.
+ void dump(raw_ostream &OS) const;
+
+protected:
+ Instruction *Src, *Dst;
+
+private:
+ SCEVUnionPredicate Assumptions;
+ const Dependence *NextPredecessor = nullptr, *NextSuccessor = nullptr;
+ friend class DependenceInfo;
+};
+
+/// FullDependence - This class represents a dependence between two memory
+/// references in a function. It contains detailed information about the
+/// dependence (direction vectors, etc.) and is used when the compiler is
+/// able to accurately analyze the interaction of the references; that is,
+/// it is not a confused dependence (see Dependence). In most cases
+/// (for output, flow, and anti dependences), the dependence implies an
+/// ordering, where the source must precede the destination; in contrast,
+/// input dependences are unordered.
+class LLVM_ABI FullDependence final : public Dependence {
+public:
+ FullDependence(Instruction *Source, Instruction *Destination,
+ const SCEVUnionPredicate &Assumes,
+ bool PossiblyLoopIndependent, unsigned Levels);
+
+ /// isLoopIndependent - Returns true if this is a loop-independent
+ /// dependence.
+ bool isLoopIndependent() const override { return LoopIndependent; }
+
+ /// isConfused - Returns true if this dependence is confused
+ /// (the compiler understands nothing and makes worst-case
+ /// assumptions).
+ bool isConfused() const override { return false; }
+
+ /// isConsistent - Returns true if this dependence is consistent
+ /// (occurs every time the source and destination are executed).
+ bool isConsistent() const override { return Consistent; }
+
+ /// getLevels - Returns the number of common loops surrounding the
+ /// source and destination of the dependence.
+ unsigned getLevels() const override { return Levels; }
+
+ /// getDirection - Returns the direction associated with a particular
+ /// level.
+ unsigned getDirection(unsigned Level) const override;
+
+ /// getDistance - Returns the distance (or NULL) associated with a
+ /// particular level.
+ const SCEV *getDistance(unsigned Level) const override;
+
+ /// Check if the direction vector is negative. A negative direction
+ /// vector means Src and Dst are reversed in the actual program.
+ bool isDirectionNegative() const override;
+
+ /// If the direction vector is negative, normalize the direction
+ /// vector to make it non-negative. Normalization is done by reversing
+ /// Src and Dst, plus reversing the dependence directions and distances
+ /// in the vector.
+ bool normalize(ScalarEvolution *SE) override;
+
+ /// isPeelFirst - Returns true if peeling the first iteration from
+ /// this loop will break this dependence.
+ bool isPeelFirst(unsigned Level) const override;
+
+ /// isPeelLast - Returns true if peeling the last iteration from
+ /// this loop will break this dependence.
+ bool isPeelLast(unsigned Level) const override;
+
+ /// isSplitable - Returns true if splitting the loop will break
+ /// the dependence.
+ bool isSplitable(unsigned Level) const override;
+
+ /// isScalar - Returns true if a particular level is scalar; that is,
+ /// if no subscript in the source or destination mention the induction
+ /// variable associated with the loop at this level.
+ bool isScalar(unsigned Level) const override;
+
+private:
+ unsigned short Levels;
+ bool LoopIndependent;
+ bool Consistent; // Init to true, then refine.
+ std::unique_ptr<DVEntry[]> DV;
+ friend class DependenceInfo;
+};
+
+/// DependenceInfo - This class is the main dependence-analysis driver.
+class DependenceInfo {
+public:
+ DependenceInfo(Function *F, AAResults *AA, ScalarEvolution *SE, LoopInfo *LI)
+ : AA(AA), SE(SE), LI(LI), F(F) {}
+
+ /// Handle transitive invalidation when the cached analysis results go away.
+ LLVM_ABI bool invalidate(Function &F, const PreservedAnalyses &PA,
+ FunctionAnalysisManager::Invalidator &Inv);
+
+ /// depends - Tests for a dependence between the Src and Dst instructions.
+ /// Returns NULL if no dependence; otherwise, returns a Dependence (or a
+ /// FullDependence) with as much information as can be gleaned. By default,
+ /// the dependence test collects a set of runtime assumptions that cannot be
+ /// solved at compilation time. By default UnderRuntimeAssumptions is false
+ /// for a safe approximation of the dependence relation that does not
+ /// require runtime checks.
+ LLVM_ABI std::unique_ptr<Dependence>
+ depends(Instruction *Src, Instruction *Dst,
+ bool UnderRuntimeAssumptions = false);
+
+ /// getSplitIteration - Give a dependence that's splittable at some
+ /// particular level, return the iteration that should be used to split
+ /// the loop.
+ ///
+ /// Generally, the dependence analyzer will be used to build
+ /// a dependence graph for a function (basically a map from instructions
+ /// to dependences). Looking for cycles in the graph shows us loops
+ /// that cannot be trivially vectorized/parallelized.
+ ///
+ /// We can try to improve the situation by examining all the dependences
+ /// that make up the cycle, looking for ones we can break.
+ /// Sometimes, peeling the first or last iteration of a loop will break
+ /// dependences, and there are flags for those possibilities.
+ /// Sometimes, splitting a loop at some other iteration will do the trick,
+ /// and we've got a flag for that case. Rather than waste the space to
+ /// record the exact iteration (since we rarely know), we provide
+ /// a method that calculates the iteration. It's a drag that it must work
+ /// from scratch, but wonderful in that it's possible.
+ ///
+ /// Here's an example:
+ ///
+ /// for (i = 0; i < 10; i++)
+ /// A[i] = ...
+ /// ... = A[11 - i]
+ ///
+ /// There's a loop-carried flow dependence from the store to the load,
+ /// found by the weak-crossing SIV test. The dependence will have a flag,
+ /// indicating that the dependence can be broken by splitting the loop.
+ /// Calling getSplitIteration will return 5.
+ /// Splitting the loop breaks the dependence, like so:
+ ///
+ /// for (i = 0; i <= 5; i++)
+ /// A[i] = ...
+ /// ... = A[11 - i]
+ /// for (i = 6; i < 10; i++)
+ /// A[i] = ...
+ /// ... = A[11 - i]
+ ///
+ /// breaks the dependence and allows us to vectorize/parallelize
+ /// both loops.
+ LLVM_ABI const SCEV *getSplitIteration(const Dependence &Dep, unsigned Level);
+
+ Function *getFunction() const { return F; }
+
+ /// getRuntimeAssumptions - Returns all the runtime assumptions under which
+ /// the dependence test is valid.
+ LLVM_ABI SCEVUnionPredicate getRuntimeAssumptions() const;
+
+private:
+ AAResults *AA;
+ ScalarEvolution *SE;
+ LoopInfo *LI;
+ Function *F;
+ SmallVector<const SCEVPredicate *, 4> Assumptions;
+
+ /// Subscript - This private struct represents a pair of subscripts from
+ /// a pair of potentially multi-dimensional array references. We use a
+ /// vector of them to guide subscript partitioning.
+ struct Subscript {
+ const SCEV *Src;
+ const SCEV *Dst;
+ enum ClassificationKind { ZIV, SIV, RDIV, MIV, NonLinear } Classification;
+ SmallBitVector Loops;
+ SmallBitVector GroupLoops;
+ SmallBitVector Group;
+ };
- /// getNextSuccessor - Returns the value of the NextSuccessor
- /// field.
- const Dependence *getNextSuccessor() const { return NextSuccessor; }
+ struct CoefficientInfo {
+ const SCEV *Coeff;
+ const SCEV *PosPart;
+ const SCEV *NegPart;
+ const SCEV *Iterations;
+ };
- /// setNextPredecessor - Sets the value of the NextPredecessor
- /// field.
- void setNextPredecessor(const Dependence *pred) { NextPredecessor = pred; }
+ struct BoundInfo {
+ const SCEV *Iterations;
+ const SCEV *Upper[8];
+ const SCEV *Lower[8];
+ unsigned char Direction;
+ unsigned char DirSet;
+ };
- /// setNextSuccessor - ...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/151505
More information about the llvm-commits
mailing list