[polly] r253951 - ScopInfo: Split hasAffineMemoryAccesses() into multiple functions [NFC]

Tobias Grosser via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 23 21:00:36 PST 2015


Author: grosser
Date: Mon Nov 23 23:00:36 2015
New Revision: 253951

URL: http://llvm.org/viewvc/llvm-project?rev=253951&view=rev
Log:
ScopInfo: Split hasAffineMemoryAccesses() into multiple functions [NFC]

This makes the overall code more readable.

Modified:
    polly/trunk/include/polly/ScopDetection.h
    polly/trunk/lib/Analysis/ScopDetection.cpp

Modified: polly/trunk/include/polly/ScopDetection.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/ScopDetection.h?rev=253951&r1=253950&r2=253951&view=diff
==============================================================================
--- polly/trunk/include/polly/ScopDetection.h (original)
+++ polly/trunk/include/polly/ScopDetection.h Mon Nov 23 23:00:36 2015
@@ -222,6 +222,50 @@ private:
   /// @returns True if the subregion can be over approximated, false otherwise.
   bool addOverApproximatedRegion(Region *AR, DetectionContext &Context) const;
 
+  /// @brief Find for a given base pointer terms that hint towards dimension
+  ///        sizes of a multi-dimensional array.
+  ///
+  /// @param Context      The current detection context.
+  /// @param BasePointer  A base pointer indicating the virtual array we are
+  ///                     interested in.
+  SmallVector<const SCEV *, 4>
+  getDelinearizationTerms(DetectionContext &Context,
+                          const SCEVUnknown *BasePointer) const;
+
+  /// @brief Check if the dimension size of a delinearized array is valid.
+  ///
+  /// @param Context     The current detection context.
+  /// @param Sizes       The sizes of the different array dimensions.
+  /// @param BasePointer The base pointer we are interested in.
+  /// @returns True if one or more array sizes could be derived - meaning: we
+  ///          see this array as multi-dimensional.
+  bool hasValidArraySizes(DetectionContext &Context,
+                          SmallVectorImpl<const SCEV *> &Sizes,
+                          const SCEVUnknown *BasePointer) const;
+
+  /// @brief Derive access functions for a given base pointer.
+  ///
+  /// @param Context     The current detection context.
+  /// @param Sizes       The sizes of the different array dimensions.
+  /// @param BasePointer The base pointer of all the array for which to compute
+  ///                    access functions.
+  /// @param Shape       The shape that describes the derived array sizes and
+  ///                    which should be filled with newly computed access
+  ///                    functions.
+  /// @returns True if a set of affine access functions could be derived.
+  bool computeAccessFunctions(DetectionContext &Context,
+                              const SCEVUnknown *BasePointer,
+                              std::shared_ptr<ArrayShape> Shape) const;
+
+  /// @brief Check if all accesses to a given BasePointer are affine.
+  ///
+  /// @param Context     The current detection context.
+  /// @param basepointer the base pointer we are interested in.
+  /// @param True if consistent (multi-dimensional) array accesses could be
+  ///        derived for this array.
+  bool hasBaseAffineAccesses(DetectionContext &Context,
+                             const SCEVUnknown *BasePointer) const;
+
   // Delinearize all non affine memory accesses and return false when there
   // exists a non affine memory access that cannot be delinearized. Return true
   // when all array accesses are affine after delinearization.

Modified: polly/trunk/lib/Analysis/ScopDetection.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Analysis/ScopDetection.cpp?rev=253951&r1=253950&r2=253951&view=diff
==============================================================================
--- polly/trunk/lib/Analysis/ScopDetection.cpp (original)
+++ polly/trunk/lib/Analysis/ScopDetection.cpp Mon Nov 23 23:00:36 2015
@@ -487,142 +487,170 @@ bool ScopDetection::isInvariant(const Va
 
 MapInsnToMemAcc InsnToMemAcc;
 
-bool ScopDetection::hasAffineMemoryAccesses(DetectionContext &Context) const {
-  Region &CurRegion = Context.CurRegion;
-
-  for (const SCEVUnknown *BasePointer : Context.NonAffineAccesses) {
-    Value *BaseValue = BasePointer->getValue();
-    auto Shape = std::shared_ptr<ArrayShape>(new ArrayShape(BasePointer));
-    bool BasePtrHasNonAffine = false;
-
-    // First step: collect parametric terms in all array references.
-    SmallVector<const SCEV *, 4> Terms;
-    for (const auto &Pair : Context.Accesses[BasePointer]) {
-      // In case the outermost expression is a plain add, we check if any of its
-      // terms has the form 4 * %inst * %param * %param ..., aka a term that
-      // contains a product between a parameter and an instruction that is
-      // inside the scop. Such instructions, if allowed at all, are instructions
-      // SCEV can not represent, but Polly is still looking through. As a
-      // result, these instructions can depend on induction variables and are
-      // most likely no array sizes. However, terms that are multiplied with
-      // them are likely candidates for array sizes.
-      if (auto *AF = dyn_cast<SCEVAddExpr>(Pair.second)) {
-        for (auto Op : AF->operands()) {
-          if (auto *AF2 = dyn_cast<SCEVAddRecExpr>(Op))
-            SE->collectParametricTerms(AF2, Terms);
-          if (auto *AF2 = dyn_cast<SCEVMulExpr>(Op)) {
-            SmallVector<const SCEV *, 0> Operands;
-
-            for (auto *MulOp : AF2->operands()) {
-              if (auto *Const = dyn_cast<SCEVConstant>(MulOp))
-                Operands.push_back(Const);
-              if (auto *Unknown = dyn_cast<SCEVUnknown>(MulOp)) {
-                if (auto *Inst = dyn_cast<Instruction>(Unknown->getValue())) {
-                  if (!Context.CurRegion.contains(Inst))
-                    Operands.push_back(MulOp);
-
-                } else {
+SmallVector<const SCEV *, 4>
+ScopDetection::getDelinearizationTerms(DetectionContext &Context,
+                                       const SCEVUnknown *BasePointer) const {
+  SmallVector<const SCEV *, 4> Terms;
+  for (const auto &Pair : Context.Accesses[BasePointer]) {
+    // In case the outermost expression is a plain add, we check if any of its
+    // terms has the form 4 * %inst * %param * %param ..., aka a term that
+    // contains a product between a parameter and an instruction that is
+    // inside the scop. Such instructions, if allowed at all, are instructions
+    // SCEV can not represent, but Polly is still looking through. As a
+    // result, these instructions can depend on induction variables and are
+    // most likely no array sizes. However, terms that are multiplied with
+    // them are likely candidates for array sizes.
+    if (auto *AF = dyn_cast<SCEVAddExpr>(Pair.second)) {
+      for (auto Op : AF->operands()) {
+        if (auto *AF2 = dyn_cast<SCEVAddRecExpr>(Op))
+          SE->collectParametricTerms(AF2, Terms);
+        if (auto *AF2 = dyn_cast<SCEVMulExpr>(Op)) {
+          SmallVector<const SCEV *, 0> Operands;
+
+          for (auto *MulOp : AF2->operands()) {
+            if (auto *Const = dyn_cast<SCEVConstant>(MulOp))
+              Operands.push_back(Const);
+            if (auto *Unknown = dyn_cast<SCEVUnknown>(MulOp)) {
+              if (auto *Inst = dyn_cast<Instruction>(Unknown->getValue())) {
+                if (!Context.CurRegion.contains(Inst))
                   Operands.push_back(MulOp);
-                }
+
+              } else {
+                Operands.push_back(MulOp);
               }
             }
-            if (Operands.size())
-              Terms.push_back(SE->getMulExpr(Operands));
           }
+          if (Operands.size())
+            Terms.push_back(SE->getMulExpr(Operands));
         }
       }
-      if (Terms.empty())
-        SE->collectParametricTerms(Pair.second, Terms);
     }
+    if (Terms.empty())
+      SE->collectParametricTerms(Pair.second, Terms);
+  }
+  return Terms;
+}
 
-    // Second step: find array shape.
-    SE->findArrayDimensions(Terms, Shape->DelinearizedSizes,
-                            Context.ElementSize[BasePointer]);
-
-    for (const SCEV *DelinearizedSize : Shape->DelinearizedSizes) {
-      if (!isAffine(DelinearizedSize, Context, nullptr)) {
-        Shape->DelinearizedSizes.clear();
-        break;
-      }
-      if (auto *Unknown = dyn_cast<SCEVUnknown>(DelinearizedSize)) {
-        auto *V = dyn_cast<Value>(Unknown->getValue());
-        if (auto *Load = dyn_cast<LoadInst>(V)) {
-          if (Context.CurRegion.contains(Load) &&
-              isHoistableLoad(Load, CurRegion, *LI, *SE))
-            Context.RequiredILS.insert(Load);
-          continue;
-        }
-      }
-      if (hasScalarDepsInsideRegion(DelinearizedSize, &CurRegion))
-        invalid<ReportNonAffineAccess>(
-            Context, /*Assert=*/true, DelinearizedSize,
-            Context.Accesses[BasePointer].front().first, BaseValue);
+bool ScopDetection::hasValidArraySizes(DetectionContext &Context,
+                                       SmallVectorImpl<const SCEV *> &Sizes,
+                                       const SCEVUnknown *BasePointer) const {
+  Value *BaseValue = BasePointer->getValue();
+  Region &CurRegion = Context.CurRegion;
+  for (const SCEV *DelinearizedSize : Sizes) {
+    if (!isAffine(DelinearizedSize, Context, nullptr)) {
+      Sizes.clear();
+      break;
     }
-
-    // No array shape derived.
-    if (Shape->DelinearizedSizes.empty()) {
-      if (AllowNonAffine)
+    if (auto *Unknown = dyn_cast<SCEVUnknown>(DelinearizedSize)) {
+      auto *V = dyn_cast<Value>(Unknown->getValue());
+      if (auto *Load = dyn_cast<LoadInst>(V)) {
+        if (Context.CurRegion.contains(Load) &&
+            isHoistableLoad(Load, CurRegion, *LI, *SE))
+          Context.RequiredILS.insert(Load);
         continue;
-
-      for (const auto &Pair : Context.Accesses[BasePointer]) {
-        const Instruction *Insn = Pair.first;
-        const SCEV *AF = Pair.second;
-
-        if (!isAffine(AF, Context, BaseValue)) {
-          invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, AF, Insn,
-                                         BaseValue);
-          if (!KeepGoing)
-            return false;
-        }
       }
-      continue;
     }
+    if (hasScalarDepsInsideRegion(DelinearizedSize, &CurRegion))
+      invalid<ReportNonAffineAccess>(
+          Context, /*Assert=*/true, DelinearizedSize,
+          Context.Accesses[BasePointer].front().first, BaseValue);
+  }
+
+  // No array shape derived.
+  if (Sizes.empty()) {
+    if (AllowNonAffine)
+      return true;
 
-    // Third step: compute the access functions for each subscript.
-    //
-    // We first store the resulting memory accesses in TempMemoryAccesses. Only
-    // if the access functions for all memory accesses have been successfully
-    // delinearized we continue. Otherwise, we either report a failure or, if
-    // non-affine accesses are allowed, we drop the information. In case the
-    // information is dropped the memory accesses need to be overapproximated
-    // when translated to a polyhedral representation.
-    MapInsnToMemAcc TempMemoryAccesses;
     for (const auto &Pair : Context.Accesses[BasePointer]) {
       const Instruction *Insn = Pair.first;
-      auto *AF = Pair.second;
-      bool IsNonAffine = false;
-      TempMemoryAccesses.insert(std::make_pair(Insn, MemAcc(Insn, Shape)));
-      MemAcc *Acc = &TempMemoryAccesses.find(Insn)->second;
-
-      if (!AF) {
-        if (isAffine(Pair.second, Context, BaseValue))
-          Acc->DelinearizedSubscripts.push_back(Pair.second);
-        else
-          IsNonAffine = true;
-      } else {
-        SE->computeAccessFunctions(AF, Acc->DelinearizedSubscripts,
-                                   Shape->DelinearizedSizes);
-        if (Acc->DelinearizedSubscripts.size() == 0)
-          IsNonAffine = true;
-        for (const SCEV *S : Acc->DelinearizedSubscripts)
-          if (!isAffine(S, Context, BaseValue))
-            IsNonAffine = true;
-      }
+      const SCEV *AF = Pair.second;
 
-      // (Possibly) report non affine access
-      if (IsNonAffine) {
-        BasePtrHasNonAffine = true;
-        if (!AllowNonAffine)
-          invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, Pair.second,
-                                         Insn, BaseValue);
-        if (!KeepGoing && !AllowNonAffine)
+      if (!isAffine(AF, Context, BaseValue)) {
+        invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, AF, Insn,
+                                       BaseValue);
+        if (!KeepGoing)
           return false;
       }
     }
+    return false;
+  }
+  return true;
+}
+
+// We first store the resulting memory accesses in TempMemoryAccesses. Only
+// if the access functions for all memory accesses have been successfully
+// delinearized we continue. Otherwise, we either report a failure or, if
+// non-affine accesses are allowed, we drop the information. In case the
+// information is dropped the memory accesses need to be overapproximated
+// when translated to a polyhedral representation.
+bool ScopDetection::computeAccessFunctions(
+    DetectionContext &Context, const SCEVUnknown *BasePointer,
+    std::shared_ptr<ArrayShape> Shape) const {
+  Value *BaseValue = BasePointer->getValue();
+  bool BasePtrHasNonAffine = false;
+  MapInsnToMemAcc TempMemoryAccesses;
+  for (const auto &Pair : Context.Accesses[BasePointer]) {
+    const Instruction *Insn = Pair.first;
+    auto *AF = Pair.second;
+    bool IsNonAffine = false;
+    TempMemoryAccesses.insert(std::make_pair(Insn, MemAcc(Insn, Shape)));
+    MemAcc *Acc = &TempMemoryAccesses.find(Insn)->second;
+
+    if (!AF) {
+      if (isAffine(Pair.second, Context, BaseValue))
+        Acc->DelinearizedSubscripts.push_back(Pair.second);
+      else
+        IsNonAffine = true;
+    } else {
+      SE->computeAccessFunctions(AF, Acc->DelinearizedSubscripts,
+                                 Shape->DelinearizedSizes);
+      if (Acc->DelinearizedSubscripts.size() == 0)
+        IsNonAffine = true;
+      for (const SCEV *S : Acc->DelinearizedSubscripts)
+        if (!isAffine(S, Context, BaseValue))
+          IsNonAffine = true;
+    }
 
-    if (!BasePtrHasNonAffine)
-      InsnToMemAcc.insert(TempMemoryAccesses.begin(), TempMemoryAccesses.end());
+    // (Possibly) report non affine access
+    if (IsNonAffine) {
+      BasePtrHasNonAffine = true;
+      if (!AllowNonAffine)
+        invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, Pair.second,
+                                       Insn, BaseValue);
+      if (!KeepGoing && !AllowNonAffine)
+        return false;
+    }
   }
+
+  if (!BasePtrHasNonAffine)
+    InsnToMemAcc.insert(TempMemoryAccesses.begin(), TempMemoryAccesses.end());
+
+  return true;
+}
+
+bool ScopDetection::hasBaseAffineAccesses(
+    DetectionContext &Context, const SCEVUnknown *BasePointer) const {
+  auto Shape = std::shared_ptr<ArrayShape>(new ArrayShape(BasePointer));
+
+  auto Terms = getDelinearizationTerms(Context, BasePointer);
+
+  SE->findArrayDimensions(Terms, Shape->DelinearizedSizes,
+                          Context.ElementSize[BasePointer]);
+
+  if (!hasValidArraySizes(Context, Shape->DelinearizedSizes, BasePointer))
+    return false;
+
+  return computeAccessFunctions(Context, BasePointer, Shape);
+}
+
+bool ScopDetection::hasAffineMemoryAccesses(DetectionContext &Context) const {
+  for (const SCEVUnknown *BasePointer : Context.NonAffineAccesses)
+    if (!hasBaseAffineAccesses(Context, BasePointer)) {
+      if (KeepGoing)
+        continue;
+      else
+        return false;
+    }
   return true;
 }
 




More information about the llvm-commits mailing list