[polly] r262404 - Fix non-synthesizable loop exit values.

Michael Kruse via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 1 13:44:06 PST 2016


Author: meinersbur
Date: Tue Mar  1 15:44:06 2016
New Revision: 262404

URL: http://llvm.org/viewvc/llvm-project?rev=262404&view=rev
Log:
Fix non-synthesizable loop exit values.

Polly recognizes affine loops that ScalarEvolution does not, in
particular those with loop conditions that depend on hoisted invariant
loads. Check for SCEVAddRec dependencies on such loops and do not
consider their exit values as synthesizable because SCEVExpander would
generate them as expressions that depend on the original induction
variables. These are not available in generated code.

Added:
    polly/trunk/test/Isl/CodeGen/unpredictable-loop-unsynthesizable.ll
Modified:
    polly/trunk/include/polly/ScopDetection.h
    polly/trunk/include/polly/Support/SCEVValidator.h
    polly/trunk/include/polly/Support/ScopHelper.h
    polly/trunk/lib/Analysis/ScopDetection.cpp
    polly/trunk/lib/Analysis/ScopInfo.cpp
    polly/trunk/lib/CodeGen/BlockGenerators.cpp
    polly/trunk/lib/CodeGen/IslNodeBuilder.cpp
    polly/trunk/lib/Support/SCEVValidator.cpp
    polly/trunk/lib/Support/ScopHelper.cpp

Modified: polly/trunk/include/polly/ScopDetection.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/ScopDetection.h?rev=262404&r1=262403&r2=262404&view=diff
==============================================================================
--- polly/trunk/include/polly/ScopDetection.h (original)
+++ polly/trunk/include/polly/ScopDetection.h Tue Mar  1 15:44:06 2016
@@ -146,9 +146,9 @@ public:
 
     /// @brief The set of base pointers with non-affine accesses.
     ///
-    /// This set contains all base pointers which are used in memory accesses
-    /// that can not be detected as affine accesses.
-    SetVector<const SCEVUnknown *> NonAffineAccesses;
+    /// This set contains all base pointers and the locations where they are
+    /// used for memory accesses that can not be detected as affine accesses.
+    SetVector<std::pair<const SCEVUnknown *, Loop *>> NonAffineAccesses;
     BaseToElSize ElementSize;
 
     /// @brief The region has at least one load instruction.
@@ -252,11 +252,12 @@ private:
   /// @param Context     The current detection context.
   /// @param Sizes       The sizes of the different array dimensions.
   /// @param BasePointer The base pointer we are interested in.
+  /// @param Scope       The location where @p BasePointer is being used.
   /// @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;
+                          const SCEVUnknown *BasePointer, Loop *Scope) const;
 
   /// @brief Derive access functions for a given base pointer.
   ///
@@ -276,10 +277,11 @@ private:
   ///
   /// @param Context     The current detection context.
   /// @param basepointer the base pointer we are interested in.
+  /// @param Scope       The location where @p BasePointer is being used.
   /// @param True if consistent (multi-dimensional) array accesses could be
   ///        derived for this array.
   bool hasBaseAffineAccesses(DetectionContext &Context,
-                             const SCEVUnknown *BasePointer) const;
+                             const SCEVUnknown *BasePointer, Loop *Scope) const;
 
   // Delinearize all non affine memory accesses and return false when there
   // exists a non affine memory access that cannot be delinearized. Return true

Modified: polly/trunk/include/polly/Support/SCEVValidator.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/Support/SCEVValidator.h?rev=262404&r1=262403&r2=262404&view=diff
==============================================================================
--- polly/trunk/include/polly/Support/SCEVValidator.h (original)
+++ polly/trunk/include/polly/Support/SCEVValidator.h Tue Mar  1 15:44:06 2016
@@ -46,7 +46,11 @@ void findValues(const llvm::SCEV *Expr,
 ///
 /// @param S The SCEV to analyze.
 /// @param R The region in which we look for dependences.
-bool hasScalarDepsInsideRegion(const llvm::SCEV *S, const llvm::Region *R);
+/// @param Scope Location where the value is needed.
+/// @param AllowLoops Whether loop recurrences outside the loop that are in the
+///                   region count as dependence.
+bool hasScalarDepsInsideRegion(const llvm::SCEV *S, const llvm::Region *R,
+                               llvm::Loop *Scope, bool AllowLoops);
 bool isAffineExpr(const llvm::Region *R, const llvm::SCEV *Expression,
                   llvm::ScalarEvolution &SE, const llvm::Value *BaseAddress = 0,
                   InvariantLoadsSetTy *ILS = nullptr);

Modified: polly/trunk/include/polly/Support/ScopHelper.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/Support/ScopHelper.h?rev=262404&r1=262403&r2=262404&view=diff
==============================================================================
--- polly/trunk/include/polly/Support/ScopHelper.h (original)
+++ polly/trunk/include/polly/Support/ScopHelper.h Tue Mar  1 15:44:06 2016
@@ -22,6 +22,7 @@
 
 namespace llvm {
 class LoopInfo;
+class Loop;
 class ScalarEvolution;
 class SCEV;
 class Region;
@@ -391,11 +392,13 @@ bool isIgnoredIntrinsic(const llvm::Valu
 /// @param LI The LoopInfo analysis.
 /// @param SE The scalar evolution database.
 /// @param R The region out of which SSA names are parameters.
+/// @param Scope Location where the value would by synthesized.
 /// @return If the instruction I can be regenerated from its
 ///         scalar evolution representation, return true,
 ///         otherwise return false.
 bool canSynthesize(const llvm::Value *V, const llvm::LoopInfo *LI,
-                   llvm::ScalarEvolution *SE, const llvm::Region *R);
+                   llvm::ScalarEvolution *SE, const llvm::Region *R,
+                   llvm::Loop *Scope);
 
 /// @brief Return the block in which a value is used.
 ///

Modified: polly/trunk/lib/Analysis/ScopDetection.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Analysis/ScopDetection.cpp?rev=262404&r1=262403&r2=262404&view=diff
==============================================================================
--- polly/trunk/lib/Analysis/ScopDetection.cpp (original)
+++ polly/trunk/lib/Analysis/ScopDetection.cpp Tue Mar  1 15:44:06 2016
@@ -716,7 +716,8 @@ ScopDetection::getDelinearizationTerms(D
 
 bool ScopDetection::hasValidArraySizes(DetectionContext &Context,
                                        SmallVectorImpl<const SCEV *> &Sizes,
-                                       const SCEVUnknown *BasePointer) const {
+                                       const SCEVUnknown *BasePointer,
+                                       Loop *Scope) const {
   Value *BaseValue = BasePointer->getValue();
   Region &CurRegion = Context.CurRegion;
   for (const SCEV *DelinearizedSize : Sizes) {
@@ -733,7 +734,7 @@ bool ScopDetection::hasValidArraySizes(D
         continue;
       }
     }
-    if (hasScalarDepsInsideRegion(DelinearizedSize, &CurRegion))
+    if (hasScalarDepsInsideRegion(DelinearizedSize, &CurRegion, Scope, false))
       return invalid<ReportNonAffineAccess>(
           Context, /*Assert=*/true, DelinearizedSize,
           Context.Accesses[BasePointer].front().first, BaseValue);
@@ -813,8 +814,9 @@ bool ScopDetection::computeAccessFunctio
   return true;
 }
 
-bool ScopDetection::hasBaseAffineAccesses(
-    DetectionContext &Context, const SCEVUnknown *BasePointer) const {
+bool ScopDetection::hasBaseAffineAccesses(DetectionContext &Context,
+                                          const SCEVUnknown *BasePointer,
+                                          Loop *Scope) const {
   auto Shape = std::shared_ptr<ArrayShape>(new ArrayShape(BasePointer));
 
   auto Terms = getDelinearizationTerms(Context, BasePointer);
@@ -822,7 +824,8 @@ bool ScopDetection::hasBaseAffineAccesse
   SE->findArrayDimensions(Terms, Shape->DelinearizedSizes,
                           Context.ElementSize[BasePointer]);
 
-  if (!hasValidArraySizes(Context, Shape->DelinearizedSizes, BasePointer))
+  if (!hasValidArraySizes(Context, Shape->DelinearizedSizes, BasePointer,
+                          Scope))
     return false;
 
   return computeAccessFunctions(Context, BasePointer, Shape);
@@ -834,13 +837,16 @@ bool ScopDetection::hasAffineMemoryAcces
   if (Context.HasUnknownAccess && !Context.NonAffineAccesses.empty())
     return AllowNonAffine;
 
-  for (const SCEVUnknown *BasePointer : Context.NonAffineAccesses)
-    if (!hasBaseAffineAccesses(Context, BasePointer)) {
+  for (auto &Pair : Context.NonAffineAccesses) {
+    auto *BasePointer = Pair.first;
+    auto *Scope = Pair.second;
+    if (!hasBaseAffineAccesses(Context, BasePointer, Scope)) {
       if (KeepGoing)
         continue;
       else
         return false;
     }
+  }
   return true;
 }
 
@@ -901,7 +907,8 @@ bool ScopDetection::isValidAccess(Instru
     Context.Accesses[BP].push_back({Inst, AF});
 
     if (!IsAffine)
-      Context.NonAffineAccesses.insert(BP);
+      Context.NonAffineAccesses.insert(
+          std::make_pair(BP, LI->getLoopFor(Inst->getParent())));
   } else if (!AllowNonAffine && !IsAffine) {
     return invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, AF, Inst,
                                           BV);

Modified: polly/trunk/lib/Analysis/ScopInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Analysis/ScopInfo.cpp?rev=262404&r1=262403&r2=262404&view=diff
==============================================================================
--- polly/trunk/lib/Analysis/ScopInfo.cpp (original)
+++ polly/trunk/lib/Analysis/ScopInfo.cpp Tue Mar  1 15:44:06 2016
@@ -3741,7 +3741,8 @@ void ScopInfo::buildPHIAccesses(PHINode
   // If we can synthesize a PHI we can skip it, however only if it is in
   // the region. If it is not it can only be in the exit block of the region.
   // In this case we model the operands but not the PHI itself.
-  if (!IsExitBlock && canSynthesize(PHI, LI, SE, &R))
+  auto *Scope = LI->getLoopFor(PHI->getParent());
+  if (!IsExitBlock && canSynthesize(PHI, LI, SE, &R, Scope))
     return;
 
   // PHI nodes are modeled as if they had been demoted prior to the SCoP
@@ -4219,7 +4220,8 @@ void ScopInfo::ensureValueRead(Value *V,
   // If the instruction can be synthesized and the user is in the region we do
   // not need to add a value dependences.
   Region &ScopRegion = scop->getRegion();
-  if (canSynthesize(V, LI, SE, &ScopRegion))
+  auto *Scope = LI->getLoopFor(UserBB);
+  if (canSynthesize(V, LI, SE, &ScopRegion, Scope))
     return;
 
   // Do not build scalar dependences for required invariant loads as we will

Modified: polly/trunk/lib/CodeGen/BlockGenerators.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/CodeGen/BlockGenerators.cpp?rev=262404&r1=262403&r2=262404&view=diff
==============================================================================
--- polly/trunk/lib/CodeGen/BlockGenerators.cpp (original)
+++ polly/trunk/lib/CodeGen/BlockGenerators.cpp Tue Mar  1 15:44:06 2016
@@ -238,7 +238,7 @@ void BlockGenerator::generateScalarStore
 bool BlockGenerator::canSyntheziseInStmt(ScopStmt &Stmt, Instruction *Inst) {
   Loop *L = getLoopForStmt(Stmt);
   return (Stmt.isBlockStmt() || !Stmt.getRegion()->contains(L)) &&
-         canSynthesize(Inst, &LI, &SE, &Stmt.getParent()->getRegion());
+         canSynthesize(Inst, &LI, &SE, &Stmt.getParent()->getRegion(), L);
 }
 
 void BlockGenerator::copyInstruction(ScopStmt &Stmt, Instruction *Inst,

Modified: polly/trunk/lib/CodeGen/IslNodeBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/CodeGen/IslNodeBuilder.cpp?rev=262404&r1=262403&r2=262404&view=diff
==============================================================================
--- polly/trunk/lib/CodeGen/IslNodeBuilder.cpp (original)
+++ polly/trunk/lib/CodeGen/IslNodeBuilder.cpp Tue Mar  1 15:44:06 2016
@@ -191,14 +191,15 @@ struct SubtreeReferences {
 static int findReferencesInBlock(struct SubtreeReferences &References,
                                  const ScopStmt *Stmt, const BasicBlock *BB) {
   for (const Instruction &Inst : *BB)
-    for (Value *SrcVal : Inst.operands())
-      if (canSynthesize(SrcVal, &References.LI, &References.SE,
-                        &References.R)) {
-        References.SCEVs.insert(
-            References.SE.getSCEVAtScope(SrcVal, References.LI.getLoopFor(BB)));
+    for (Value *SrcVal : Inst.operands()) {
+      auto *Scope = References.LI.getLoopFor(BB);
+      if (canSynthesize(SrcVal, &References.LI, &References.SE, &References.R,
+                        Scope)) {
+        References.SCEVs.insert(References.SE.getSCEVAtScope(SrcVal, Scope));
         continue;
       } else if (Value *NewVal = References.GlobalMap.lookup(SrcVal))
         References.Values.insert(NewVal);
+    }
   return 0;
 }
 

Modified: polly/trunk/lib/Support/SCEVValidator.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Support/SCEVValidator.cpp?rev=262404&r1=262403&r2=262404&view=diff
==============================================================================
--- polly/trunk/lib/Support/SCEVValidator.cpp (original)
+++ polly/trunk/lib/Support/SCEVValidator.cpp Tue Mar  1 15:44:06 2016
@@ -423,13 +423,18 @@ public:
 struct SCEVInRegionDependences
     : public SCEVVisitor<SCEVInRegionDependences, bool> {
 public:
-  /// Returns true when the SCEV has SSA names defined in region R.
-  static bool hasDependences(const SCEV *S, const Region *R) {
-    SCEVInRegionDependences Ignore(R);
+  /// Returns true when the SCEV has SSA names defined in region R. It @p
+  /// AllowLoops is false, loop dependences are checked as well. AddRec SCEVs
+  /// are only allowed within its loop (current loop determined by @p Scope),
+  /// not outside of it unless AddRec's loop is not even in the region.
+  static bool hasDependences(const SCEV *S, const Region *R, Loop *Scope,
+                             bool AllowLoops) {
+    SCEVInRegionDependences Ignore(R, Scope, AllowLoops);
     return Ignore.visit(S);
   }
 
-  SCEVInRegionDependences(const Region *R) : R(R) {}
+  SCEVInRegionDependences(const Region *R, Loop *Scope, bool AllowLoops)
+      : R(R), Scope(Scope), AllowLoops(AllowLoops) {}
 
   bool visit(const SCEV *Expr) {
     return SCEVVisitor<SCEVInRegionDependences, bool>::visit(Expr);
@@ -476,6 +481,14 @@ public:
   }
 
   bool visitAddRecExpr(const SCEVAddRecExpr *Expr) {
+    if (!AllowLoops) {
+      if (!Scope)
+        return true;
+      auto *L = Expr->getLoop();
+      if (R->contains(L) && !L->contains(Scope))
+        return true;
+    }
+
     for (size_t i = 0; i < Expr->getNumOperands(); ++i)
       if (visit(Expr->getOperand(i)))
         return true;
@@ -511,6 +524,8 @@ public:
 
 private:
   const Region *R;
+  Loop *Scope;
+  bool AllowLoops;
 };
 
 namespace polly {
@@ -556,8 +571,9 @@ void findValues(const SCEV *Expr, SetVec
   ST.visitAll(Expr);
 }
 
-bool hasScalarDepsInsideRegion(const SCEV *Expr, const Region *R) {
-  return SCEVInRegionDependences::hasDependences(Expr, R);
+bool hasScalarDepsInsideRegion(const SCEV *Expr, const Region *R,
+                               llvm::Loop *Scope, bool AllowLoops) {
+  return SCEVInRegionDependences::hasDependences(Expr, R, Scope, AllowLoops);
 }
 
 bool isAffineExpr(const Region *R, const SCEV *Expr, ScalarEvolution &SE,

Modified: polly/trunk/lib/Support/ScopHelper.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Support/ScopHelper.cpp?rev=262404&r1=262403&r2=262404&view=diff
==============================================================================
--- polly/trunk/lib/Support/ScopHelper.cpp (original)
+++ polly/trunk/lib/Support/ScopHelper.cpp Tue Mar  1 15:44:06 2016
@@ -436,13 +436,13 @@ bool polly::isIgnoredIntrinsic(const Val
 }
 
 bool polly::canSynthesize(const Value *V, const llvm::LoopInfo *LI,
-                          ScalarEvolution *SE, const Region *R) {
+                          ScalarEvolution *SE, const Region *R, Loop *Scope) {
   if (!V || !SE->isSCEVable(V->getType()))
     return false;
 
-  if (const SCEV *Scev = SE->getSCEV(const_cast<Value *>(V)))
+  if (const SCEV *Scev = SE->getSCEVAtScope(const_cast<Value *>(V), Scope))
     if (!isa<SCEVCouldNotCompute>(Scev))
-      if (!hasScalarDepsInsideRegion(Scev, R))
+      if (!hasScalarDepsInsideRegion(Scev, R, Scope, false))
         return true;
 
   return false;

Added: polly/trunk/test/Isl/CodeGen/unpredictable-loop-unsynthesizable.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/Isl/CodeGen/unpredictable-loop-unsynthesizable.ll?rev=262404&view=auto
==============================================================================
--- polly/trunk/test/Isl/CodeGen/unpredictable-loop-unsynthesizable.ll (added)
+++ polly/trunk/test/Isl/CodeGen/unpredictable-loop-unsynthesizable.ll Tue Mar  1 15:44:06 2016
@@ -0,0 +1,59 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-codegen -analyze < %s
+
+; The loop for.body is a scop with invariant load hoisting, but does not
+; terminate predictably for ScalarEvolution. The scalar %1 therefore is not
+; synthesizable using SCEVExpander. We therefore must have Stmt_for_end_loopexit
+; to catch the induction variable at loop exit. We also check for not crashing
+; at codegen because SCEVExpander would use the original induction variable in
+; generated code.
+
+%struct.bit_stream_struc.3.43.51.71.83.91.99.107.154 = type { i8*, i32, %struct._IO_FILE.1.41.49.69.81.89.97.105.153*, i8*, i32, i64, i32, i32 }
+%struct._IO_FILE.1.41.49.69.81.89.97.105.153 = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct._IO_marker.0.40.48.68.80.88.96.104.152*, %struct._IO_FILE.1.41.49.69.81.89.97.105.153*, i32, i32, i64, i16, i8, [1 x i8], i8*, i64, i8*, i8*, i8*, i8*, i64, i32, [20 x i8] }
+%struct._IO_marker.0.40.48.68.80.88.96.104.152 = type { %struct._IO_marker.0.40.48.68.80.88.96.104.152*, %struct._IO_FILE.1.41.49.69.81.89.97.105.153*, i32 }
+
+define i32 @copy_buffer(%struct.bit_stream_struc.3.43.51.71.83.91.99.107.154* nocapture %bs) {
+entry:
+  %buf_byte_idx5.phi.trans.insert = getelementptr inbounds %struct.bit_stream_struc.3.43.51.71.83.91.99.107.154, %struct.bit_stream_struc.3.43.51.71.83.91.99.107.154* %bs, i64 0, i32 6
+  br i1 undef, label %for.body, label %cleanup
+
+for.body:
+  %indvars.iv28 = phi i64 [ %indvars.iv.next29, %for.body ], [ 0, %entry ]
+  %indvars.iv.next29 = add nuw nsw i64 %indvars.iv28, 1
+  %0 = load i32, i32* %buf_byte_idx5.phi.trans.insert, align 8
+  %cmp6 = icmp sgt i32 0, %0
+  br i1 %cmp6, label %for.body, label %for.end.loopexit
+
+for.end.loopexit:
+  %1 = trunc i64 %indvars.iv.next29 to i32
+  br label %cleanup
+
+cleanup:
+  %retval.0 = phi i32 [ 0, %entry ], [ %1, %for.end.loopexit ]
+  ret i32 %retval.0
+}
+
+
+; CHECK:      Invariant Accesses: {
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:             [p_0_loaded_from_bs] -> { Stmt_for_body[i0] -> MemRef_bs[11] };
+; CHECK-NEXT:         Execution Context: [p_0_loaded_from_bs] -> {  :  }
+; CHECK-NEXT: }
+; CHECK:      Statements {
+; CHECK-NEXT:     Stmt_for_body
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [p_0_loaded_from_bs] -> { Stmt_for_body[0] : p_0_loaded_from_bs >= 0 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [p_0_loaded_from_bs] -> { Stmt_for_body[i0] -> [0, 0] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [p_0_loaded_from_bs] -> { Stmt_for_body[i0] -> MemRef_indvars_iv_next29[] };
+; CHECK-NEXT:     Stmt_for_end_loopexit
+; CHECK-NEXT:         Domain :=
+; CHECK-NEXT:             [p_0_loaded_from_bs] -> { Stmt_for_end_loopexit[] : p_0_loaded_from_bs >= 0 };
+; CHECK-NEXT:         Schedule :=
+; CHECK-NEXT:             [p_0_loaded_from_bs] -> { Stmt_for_end_loopexit[] -> [1, 0] };
+; CHECK-NEXT:         ReadAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [p_0_loaded_from_bs] -> { Stmt_for_end_loopexit[] -> MemRef_indvars_iv_next29[] };
+; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:             [p_0_loaded_from_bs] -> { Stmt_for_end_loopexit[] -> MemRef_1[] };
+; CHECK-NEXT: }




More information about the llvm-commits mailing list