Record assumptions first and add them later
authorJohannes Doerfert <doerfert@cs.uni-saarland.de>
Tue, 12 Apr 2016 13:27:35 +0000 (13:27 +0000)
committerJohannes Doerfert <doerfert@cs.uni-saarland.de>
Tue, 12 Apr 2016 13:27:35 +0000 (13:27 +0000)
There are three reasons why we want to record assumptions first before we
add them to the assumed/invalid context:

  1) If the SCoP is not profitable or otherwise invalid without the
     assumed/invalid context we do not have to compute it.
  2) Information about the context are gathered rather late in the SCoP
     construction (basically after we know all parameters), thus the user
     might see overly complicated assumptions to be taken while they would
     have been simplified later on.
  3) Currently we cannot take assumptions at any point but have to wait,
     e.g., for the domain generation to finish. This makes wrapping
     assumptions much more complicated as they need to be and it will
     have a similar effect on "signed-unsigned" assumptions later.

llvm-svn: 266068

polly/include/polly/ScopInfo.h
polly/lib/Analysis/ScopInfo.cpp
polly/test/ScopInfo/NonAffine/non-affine-loop-condition-dependent-access_3.ll
polly/test/ScopInfo/long-sequence-of-error-blocks-2.ll
polly/test/ScopInfo/long-sequence-of-error-blocks.ll
polly/test/ScopInfo/loop-multiexit-succ-cond.ll
polly/test/ScopInfo/pointer-comparison-no-nsw.ll
polly/test/ScopInfo/pointer-comparison.ll
polly/test/ScopInfo/remarks.ll
polly/test/ScopInfo/user_provided_assumptions.ll
polly/test/ScopInfo/user_provided_non_dominating_assumptions.ll

index 5c102e0..521aa5e 100644 (file)
@@ -1384,6 +1384,34 @@ private:
   /// need to be "false". Otherwise they behave the same.
   isl_set *InvalidContext;
 
+  /// @brief Helper struct to remember assumptions.
+  struct Assumption {
+
+    /// @brief The kind of the assumption (e.g., WRAPPING).
+    AssumptionKind Kind;
+
+    /// @brief Flag to distinguish assumptions and restrictions.
+    AssumptionSign Sign;
+
+    /// @brief The valid/invalid context if this is an assumption/restriction.
+    isl_set *Set;
+
+    /// @brief The location that caused this assumption.
+    DebugLoc Loc;
+  };
+
+  /// @brief Collection to hold taken assumptions.
+  ///
+  /// There are two reasons why we want to record assumptions first before we
+  /// add them to the assumed/invalid context:
+  ///   1) If the SCoP is not profitable or otherwise invalid without the
+  ///      assumed/invalid context we do not have to compute it.
+  ///   2) Information about the context are gathered rather late in the SCoP
+  ///      construction (basically after we know all parameters), thus the user
+  ///      might see overly complicated assumptions to be taken while they will
+  ///      only be simplified later on.
+  SmallVector<Assumption, 8> RecordedAssumptions;
+
   /// @brief The schedule of the SCoP
   ///
   /// The schedule of the SCoP describes the execution order of the statements
@@ -1926,6 +1954,23 @@ public:
   void addAssumption(AssumptionKind Kind, __isl_take isl_set *Set, DebugLoc Loc,
                      AssumptionSign Sign);
 
+  /// @brief Record an assumption for later addition to the assumed context.
+  ///
+  /// This function will add the assumption to the RecordedAssumptions. This
+  /// collection will be added (@see addAssumption) to the assumed context once
+  /// all paramaters are known and the context is fully build.
+  ///
+  /// @param Kind The assumption kind describing the underlying cause.
+  /// @param Set  The relations between parameters that are assumed to hold.
+  /// @param Loc  The location in the source that caused this assumption.
+  /// @param Sign Enum to indicate if the assumptions in @p Set are positive
+  ///             (needed/assumptions) or negative (invalid/restrictions).
+  void recordAssumption(AssumptionKind Kind, __isl_take isl_set *Set,
+                        DebugLoc Loc, AssumptionSign Sign);
+
+  /// @brief Add all recorded assumptions to the assumed context.
+  void addRecordedAssumptions();
+
   /// @brief Mark the scop as invalid.
   ///
   /// This method adds an assumption to the scop that is always invalid. As a
index 14e673c..97c3804 100644 (file)
@@ -668,7 +668,8 @@ void MemoryAccess::assumeNoOutOfBound() {
   const auto &Loc = getAccessInstruction()
                         ? getAccessInstruction()->getDebugLoc()
                         : DebugLoc();
-  Statement->getParent()->addAssumption(INBOUNDS, Outside, Loc, AS_ASSUMPTION);
+  Statement->getParent()->recordAssumption(INBOUNDS, Outside, Loc,
+                                           AS_ASSUMPTION);
   isl_space_free(Space);
 }
 
@@ -1419,8 +1420,8 @@ void ScopStmt::deriveAssumptionsFromGEP(GetElementPtrInst *GEP,
         isl_set_union(isl_set_copy(NotExecuted), InBound);
 
     InBoundIfExecuted = isl_set_coalesce(InBoundIfExecuted);
-    Parent.addAssumption(INBOUNDS, InBoundIfExecuted, GEP->getDebugLoc(),
-                         AS_ASSUMPTION);
+    Parent.recordAssumption(INBOUNDS, InBoundIfExecuted, GEP->getDebugLoc(),
+                            AS_ASSUMPTION);
   }
 
   isl_local_space_free(LSpace);
@@ -2639,8 +2640,8 @@ void Scop::propagateDomainConstraints(Region *R, ScopDetection &SD,
     if (containsErrorBlock(RN, getRegion(), LI, DT)) {
       IsOptimized = true;
       isl_set *DomPar = isl_set_params(isl_set_copy(Domain));
-      addAssumption(ERRORBLOCK, DomPar, BB->getTerminator()->getDebugLoc(),
-                    AS_RESTRICTION);
+      recordAssumption(ERRORBLOCK, DomPar, BB->getTerminator()->getDebugLoc(),
+                       AS_RESTRICTION);
     }
   }
 }
@@ -2740,8 +2741,8 @@ void Scop::addLoopBoundsToHeaderDomain(Loop *L, LoopInfo &LI) {
   }
 
   isl_set *UnboundedCtx = isl_set_params(Parts.first);
-  addAssumption(INFINITELOOP, UnboundedCtx,
-                HeaderBB->getTerminator()->getDebugLoc(), AS_RESTRICTION);
+  recordAssumption(INFINITELOOP, UnboundedCtx,
+                   HeaderBB->getTerminator()->getDebugLoc(), AS_RESTRICTION);
 }
 
 void Scop::buildAliasChecks(AliasAnalysis &AA) {
@@ -3026,6 +3027,12 @@ void Scop::init(AliasAnalysis &AA, AssumptionCache &AC, ScopDetection &SD,
   addParameterBounds();
   addUserContext();
   addWrappingContext();
+
+  // After the context was fully constructed, thus all our knowledge about
+  // the parameters is in there, we add all recorded assumptions to the
+  // assumed/invalid context.
+  addRecordedAssumptions();
+
   simplifyContexts();
   buildAliasChecks(AA);
 
@@ -3043,6 +3050,9 @@ Scop::~Scop() {
   for (auto It : DomainMap)
     isl_set_free(It.second);
 
+  for (auto &AS : RecordedAssumptions)
+    isl_set_free(AS.Set);
+
   // Free the alias groups
   for (MinMaxVectorPairTy &MinMaxAccessPair : MinMaxAliasGroups) {
     for (MinMaxAccessTy &MMA : MinMaxAccessPair.first) {
@@ -3478,6 +3488,9 @@ bool Scop::trackAssumption(AssumptionKind Kind, __isl_keep isl_set *Set,
 
 void Scop::addAssumption(AssumptionKind Kind, __isl_take isl_set *Set,
                          DebugLoc Loc, AssumptionSign Sign) {
+  // Simplify the assumptions/restrictions first.
+  Set = isl_set_gist_params(Set, getContext());
+
   if (!trackAssumption(Kind, Set, Loc, Sign)) {
     isl_set_free(Set);
     return;
@@ -3492,6 +3505,18 @@ void Scop::addAssumption(AssumptionKind Kind, __isl_take isl_set *Set,
   }
 }
 
+void Scop::recordAssumption(AssumptionKind Kind, __isl_take isl_set *Set,
+                            DebugLoc Loc, AssumptionSign Sign) {
+  RecordedAssumptions.push_back({Kind, Sign, Set, Loc});
+}
+
+void Scop::addRecordedAssumptions() {
+  while (!RecordedAssumptions.empty()) {
+    const Assumption &AS = RecordedAssumptions.pop_back_val();
+    addAssumption(AS.Kind, AS.Set, AS.Loc, AS.Sign);
+  }
+}
+
 void Scop::invalidate(AssumptionKind Kind, DebugLoc Loc) {
   addAssumption(Kind, isl_set_empty(getParamSpace()), Loc, AS_ASSUMPTION);
 }
index 0979e9a..6cd0b40 100644 (file)
@@ -24,7 +24,7 @@
 ; INNERMOST-NEXT: Assumed Context:
 ; INNERMOST-NEXT: [p_0, p_1, p_2] -> {  :  }
 ; INNERMOST-NEXT: Invalid Context:
-; INNERMOST-NEXT: [p_0, p_1, p_2] -> {  : p_0 < 0 }
+; INNERMOST-NEXT: [p_0, p_1, p_2] -> {  : 1 = 0 }
 ; INNERMOST-NEXT: p0: {0,+,{0,+,1}<nuw><nsw><%bb11>}<nuw><nsw><%bb13>
 ; INNERMOST-NEXT: p1: {0,+,1}<nuw><nsw><%bb11>
 ; INNERMOST-NEXT: p2: {0,+,1}<nuw><nsw><%bb13>
index 5238800..6c97929 100644 (file)
@@ -12,8 +12,7 @@ target triple = "x86_64-unknown-linux-gnu"
 ; CHECK:      Assumed Context:
 ; CHECK-NEXT:   [tmp17, tmp21, tmp27, tmp31, tmp37, tmp41, tmp46, tmp52, tmp56, tmp62] -> {  :  }
 ; CHECK:      Invalid Context:
-; CHECK-NEXT:   [tmp17, tmp21, tmp27, tmp31, tmp37, tmp41, tmp46, tmp52, tmp56, tmp62] -> { : (tmp17 < 0 and tmp21 < 0) or (tmp17 < 0 and tmp21 > 0) or (tmp17 > 0 and tmp21 < 0) or (tmp17 > 0 and tmp21 > 0) or (tmp37 < 0 and tmp41 < 0 and tmp46 > 0) or (tmp37 < 0 and tmp41 > 0 and tmp46 > 0) or (tmp37 > 0 and tmp41 < 0 and tmp46 > 0) or (tmp37 > 0 and tmp41 > 0 and tmp46 > 0) or (tmp27 = 3 and tmp31 <= 143) or (tmp56 = 0 and tmp52 < 0) or (tmp56 = 0 and tmp52 > 0) }
-
+; CHECK-NEXT:   [tmp17, tmp21, tmp27, tmp31, tmp37, tmp41, tmp46, tmp52, tmp56, tmp62] -> { : (tmp37 < 0 and tmp41 < 0 and tmp46 > 0) or (tmp17 < 0 and tmp21 < 0) or (tmp17 < 0 and tmp21 > 0) or (tmp17 > 0 and tmp21 < 0) or (tmp17 > 0 and tmp21 > 0) or (tmp37 < 0 and tmp41 > 0 and tmp46 > 0) or (tmp37 > 0 and tmp41 < 0 and tmp46 > 0) or (tmp37 > 0 and tmp41 > 0 and tmp46 > 0) or (tmp27 = 3 and tmp31 <= 143) or (tmp56 = 0 and tmp52 < 0) or (tmp56 = 0 and tmp52 > 0) }
 
 @global = external global [300 x i8], align 16
 @global1 = external global %struct.hoge*, align 8
index d420a62..6b904c5 100644 (file)
@@ -12,7 +12,7 @@ target triple = "x86_64-unknown-linux-gnu"
 ; CHECK:      Assumed Context:
 ; CHECK-NEXT: [tmp17, tmp21, tmp27, tmp31] -> {  :  }
 ; CHECK:      Invalid Context:
-; CHECK-NEXT: [tmp17, tmp21, tmp27, tmp31] -> {  : (tmp17 < 0 and tmp21 < 0) or (tmp17 < 0 and tmp21 > 0) or (tmp17 > 0 and tmp21 < 0) or (tmp17 > 0 and tmp21 > 0) or (tmp27 = 3 and tmp31 <= 143) }
+; CHECK-NEXT: [tmp17, tmp21, tmp27, tmp31] -> { : (tmp27 = 3 and tmp31 <= 143) or (tmp17 < 0 and tmp21 < 0) or (tmp17 < 0 and tmp21 > 0) or (tmp17 > 0 and tmp21 < 0) or (tmp17 > 0 and tmp21 > 0) }
 ;
 ; CHECK:      Statements {
 ; CHECK-NEXT:     Stmt_bb15
index d8fbb2d..368226f 100644 (file)
@@ -6,7 +6,7 @@
 ; CHECK:      Assumed Context:
 ; CHECK-NEXT:   [count1, dobreak, count2] -> {  :  }
 ; CHECK-NEXT: Invalid Context:
-; CHECK-NEXT:   [count1, dobreak, count2] -> {  : count1 <= 0 or (count1 > 0 and dobreak > 0) or (count1 > 0 and dobreak <= 0 and count2 > 0) }
+; CHECK-NEXT:   [count1, dobreak, count2] -> {  : (count1 > 0 and dobreak > 0) or count1 <= 0 or (count1 > 0 and dobreak <= 0 and count2 > 0) }
 ;
 ; CHECK:      Stmt_loop_enter
 ; CHECK-NEXT:     Domain :=
index 92519b2..d511485 100644 (file)
@@ -8,7 +8,7 @@
 ;    }
 ;
 ; CHECK:      Invalid Context:
-; CHECK-NEXT:   [A, B] -> {  : (4*floor((-A + B)/4) < -A + B and 4*floor((A - B)/4) < A - B) or (4*floor((-A + B)/4) = -A + B and B >= 9223372036854775808 + A) or (4*floor((-A + B)/4) = -A + B and B <= -4 + A) }
+; CHECK-NEXT:   [A, B] -> { : (4*floor((-A + B)/4) = -A + B and B >= 9223372036854775808 + A) or (4*floor((A - B)/4) < A - B) or (4*floor((-A + B)/4) = -A + B and B <= -4 + A) }
 ;
 ; CHECK:      Domain :=
 ; CHECK-NEXT:   [A, B] -> { Stmt_while_body[i0] : 4*floor((A - B)/4) = A - B and B >= A and i0 >= 0 and 4i0 < -A + B }
index fc65694..6069048 100644 (file)
@@ -10,7 +10,7 @@
 ;    }
 ;
 ; CHECK:      Invalid Context:
-; CHECK-NEXT:   [A, B] -> {  : (4*floor((-A + B)/4) < -A + B and 4*floor((A - B)/4) < A - B) or (4*floor((-A + B)/4) = -A + B and B >= 9223372036854775808 + A) or (4*floor((-A + B)/4) = -A + B and B <= -4 + A) }
+; CHECK-NEXT:   [A, B] -> { : (4*floor((-A + B)/4) = -A + B and B >= 9223372036854775808 + A) or (4*floor((A - B)/4) < A - B) or (4*floor((-A + B)/4) = -A + B and B <= -4 + A) }
 ;
 ; CHECK:      Domain :=
 ; CHECK-NEXT:   [A, B] -> { Stmt_while_body[i0] : 4*floor((A - B)/4) = A - B and B >= A and i0 >= 0 and 4i0 < -A + B }
index c10fe00..b45bdf8 100644 (file)
@@ -1,10 +1,10 @@
 ; RUN: opt %loadPolly -pass-remarks-analysis="polly-scops" -polly-scops -disable-output < %s 2>&1 | FileCheck %s
 ;
 ; CHECK: remark: test/ScopInfo/remarks.c:4:7: SCoP begins here.
-; CHECK: remark: test/ScopInfo/remarks.c:8:5: Finite loop restriction:    [N, M] -> {  : N > 0 and (M <= -2 or M = -1) }
-; CHECK: remark: test/ScopInfo/remarks.c:13:7: No-error restriction:    [N, M, Debug] -> {  : N > 0 and M >= 0 and (Debug < 0 or Debug > 0) }
-; CHECK: remark: test/ScopInfo/remarks.c:9:7: Inbounds assumption:    [N, M] -> {  : N <= 0 or (N > 0 and M <= 100) }
 ; CHECK: remark: <unknown>:0:0: No-overflows restriction:    [N, M, Debug] -> {  : M <= -2147483649 - N or M >= 2147483648 - N }
+; CHECK: remark: test/ScopInfo/remarks.c:9:15: Inbounds assumption:    [N, M, Debug] -> {  : N <= 0 or (N > 0 and M <= 100) }
+; CHECK: remark: test/ScopInfo/remarks.c:13:7: No-error restriction:    [N, M, Debug] -> {  : N > 0 and M >= 0 and (Debug < 0 or Debug > 0) }
+; CHECK: remark: test/ScopInfo/remarks.c:8:5: Finite loop restriction:    [N, M, Debug] -> {  : N > 0 and (M <= -2 or M = -1) }
 ; CHECK: remark: test/ScopInfo/remarks.c:9:18: Possibly aliasing pointer, use restrict keyword.
 ; CHECK: remark: test/ScopInfo/remarks.c:9:33: Possibly aliasing pointer, use restrict keyword.
 ; CHECK: remark: test/ScopInfo/remarks.c:9:15: Possibly aliasing pointer, use restrict keyword.
index 22691ab..c8db0a5 100644 (file)
@@ -9,7 +9,7 @@
 ; CHECK-NEXT: remark: <unknown>:0:0: SCoP ends here.
 
 ; SCOP:      Context:
-; SCOP-NEXT: [N, M, Debug] -> { : Debug = 0 and 0 < N <= 2147483647 and 0 < M <= 2147483647 - N and M <= 100 }
+; SCOP-NEXT: [N, M, Debug] -> { : Debug = 0 and N > 0 and 0 < M <= 2147483647 - N and M <= 100 }
 ; SCOP:      Assumed Context:
 ; SCOP-NEXT: [N, M, Debug] -> {  :  }
 ; SCOP:      Invalid Context:
index 2ee4cd6..351ffe4 100644 (file)
@@ -1,8 +1,8 @@
 ; RUN: opt %loadPolly -pass-remarks-analysis="polly-scops" -polly-scops -disable-output < %s 2>&1 | FileCheck %s
 ;
 ; CHECK:      remark: <unknown>:0:0: SCoP begins here.
-; CHECK-NEXT: remark: <unknown>:0:0: Inbounds assumption:    [i, N, p_2] -> {  : N <= i or (N > i and p_2 <= 100) }
-; CHECK-NEXT: remark: <unknown>:0:0: Inbounds assumption:    [i, N, p_2, M] -> {  : N <= i or (N > i and p_2 <= 0) or (N > i and p_2 > 0 and M >= p_2) }
+; CHECK-NEXT: remark: <unknown>:0:0: Inbounds assumption:    [i, N, p_2, M] -> {  : N <= i or (N > i and p_2 <= 100) }
+; CHECK-NEXT: remark: <unknown>:0:0: Inbounds assumption:    [i, N, p_2, M] -> { : N <= i or (N > i and p_2 > 0 and M >= p_2) or (p_2 = 0 and N > i) }
 ; CHECK-NEXT: remark: <unknown>:0:0: SCoP ends here.
 ;
 ;    void f(int *restrict A, int *restrict B, int i, int N, int M, int C[100][100]) {