[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