-
Notifications
You must be signed in to change notification settings - Fork 14.7k
[DA][NFC] clang-format DependenceAnalysis #151505
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
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-llvm-analysis Author: Michael Kruse (Meinersbur) ChangesTo 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:
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]
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks! All my comments are nitpicky, so feel free to ignore them if they don't make sense to you.
std::unique_ptr<DependenceInfo> info; | ||
}; // class DependenceAnalysisWrapperPass | ||
/// getPositivePart - X^+ = max(X, 0). | ||
/// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we remove this line as well?
/// DependenceAnalysis wrapper pass. | ||
LLVM_ABI FunctionPass *createDependenceAnalysisWrapperPass(); | ||
/// getNegativePart - X^- = min(X, 0). | ||
/// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as getPositivePart
?
/// Compare to see if S is less than Size, using | ||
/// | ||
/// isKnownNegative(S - max(Size, 1)) | ||
/// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this intentional? I'm okay with it if it is, but it doesn't look like a change made by clang-format.
APInt A2 = A0 - Q * A1; | ||
A0 = A1; | ||
A1 = A2; | ||
APInt B2 = B0 - Q * B1; | ||
B0 = B1; | ||
B1 = B2; | ||
G0 = G1; | ||
G1 = R; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Not a change request] In this specific case, the former is more readable to me...
const SCEV *AbsDelta = | ||
SE->isKnownNonNegative(Delta) ? Delta : SE->getNegativeSCEV(Delta); | ||
SE->isKnownNonNegative(Delta) ? Delta : SE->getNegativeSCEV(Delta); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not the topic of this PR, but this logic is clearly incorrect... (!isKnownNonNegative(Delta)
doesn't imply that Delta
is negative)
Bound[K].Lower[Dependence::DVEntry::ALL] = nullptr; // Represents -infinity | ||
Bound[K].Upper[Dependence::DVEntry::ALL] = nullptr; // Represents +infinity |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are the comment edits intentional? Seems the same comments exist elsewhere as well.
To avoid noise in PRs such as #146383.