Use schedule trees to represent execution order of statements
authorTobias Grosser <tobias@grosser.es>
Tue, 14 Jul 2015 09:33:13 +0000 (09:33 +0000)
committerTobias Grosser <tobias@grosser.es>
Tue, 14 Jul 2015 09:33:13 +0000 (09:33 +0000)
Instead of flat schedules, we now use so-called schedule trees to represent the
execution order of the statements in a SCoP. Schedule trees make it a lot easier
to analyze, understand and modify properties of a schedule, as specific nodes
in the tree can be choosen and possibly replaced.

This patch does not yet fully move our DependenceInfo pass to schedule trees,
as some additional performance analysis is needed here. (In general schedule
trees should be faster in compile-time, as the more structured representation
is generally easier to analyze and work with). We also can not yet perform the
reduction analysis on schedule trees.

For more information regarding schedule trees, please see Section 6 of
https://lirias.kuleuven.be/handle/123456789/497238

llvm-svn: 242130

30 files changed:
polly/include/polly/ScopInfo.h
polly/lib/Analysis/DependenceInfo.cpp
polly/lib/Analysis/ScopInfo.cpp
polly/lib/CodeGen/IslAst.cpp
polly/lib/CodeGen/IslNodeBuilder.cpp
polly/lib/Exchange/JSONExporter.cpp
polly/lib/Transform/ScheduleOptimizer.cpp
polly/test/DeadCodeElimination/chained_iterations.ll
polly/test/DeadCodeElimination/chained_iterations_2.ll
polly/test/DeadCodeElimination/computeout.ll
polly/test/DeadCodeElimination/dead_iteration_elimination.ll
polly/test/DeadCodeElimination/non-affine-affine-mix.ll
polly/test/DeadCodeElimination/null_schedule.ll
polly/test/DependenceInfo/reduction_simple_iv_debug_wrapped_dependences.ll
polly/test/Isl/Ast/reduction_modulo_schedule_multiple_dimensions_4.ll
polly/test/Isl/Ast/simple-run-time-condition.ll
polly/test/Isl/CodeGen/loop_with_condition.ll
polly/test/Isl/CodeGen/loop_with_condition_2.ll
polly/test/Isl/CodeGen/loop_with_condition_ineq.ll
polly/test/Isl/CodeGen/loop_with_condition_nested.ll
polly/test/Isl/CodeGen/phi_conditional_simple_1.ll
polly/test/Isl/CodeGen/sequential_loops.ll
polly/test/ScheduleOptimizer/computeout.ll
polly/test/ScheduleOptimizer/line-tiling.ll
polly/test/ScheduleOptimizer/one-dimensional-band.ll
polly/test/ScheduleOptimizer/prevectorization.ll
polly/test/ScheduleOptimizer/rectangular-tiling.ll
polly/test/ScopInfo/NonAffine/non-affine-loop-condition-dependent-access_2.ll
polly/test/ScopInfo/NonAffine/non_affine_loop_used_later.ll
polly/test/ScopInfo/pointer-type-expressions.ll

index acf485b..d3aba3d 100644 (file)
@@ -51,6 +51,7 @@ struct isl_space;
 struct isl_ast_build;
 struct isl_constraint;
 struct isl_pw_multi_aff;
+struct isl_schedule;
 
 namespace polly {
 
@@ -422,13 +423,11 @@ public:
 
   /// Create the ScopStmt from a BasicBlock.
   ScopStmt(Scop &parent, TempScop &tempScop, const Region &CurRegion,
-           BasicBlock &bb, SmallVectorImpl<Loop *> &NestLoops,
-           SmallVectorImpl<unsigned> &ScheduleVec);
+           BasicBlock &bb, SmallVectorImpl<Loop *> &NestLoops);
 
   /// Create an overapproximating ScopStmt for the region @p R.
   ScopStmt(Scop &parent, TempScop &tempScop, const Region &CurRegion, Region &R,
-           SmallVectorImpl<Loop *> &NestLoops,
-           SmallVectorImpl<unsigned> &ScheduleVec);
+           SmallVectorImpl<Loop *> &NestLoops);
 
 private:
   /// Polyhedral description
@@ -458,36 +457,6 @@ private:
   /// instance.
   isl_set *Domain;
 
-  /// The schedule map describes the execution order of the statement
-  /// instances.
-  ///
-  /// A statement and its iteration domain do not give any information about the
-  /// order in time in which the different statement instances are executed.
-  /// This information is provided by the schedule.
-  ///
-  /// The schedule maps every instance of each statement into a multi
-  /// dimensional schedule space. This space can be seen as a multi
-  /// dimensional clock.
-  ///
-  /// Example:
-  ///
-  /// <S,(5,4)>  may be mapped to (5,4) by this schedule:
-  ///
-  /// s0 = i (Year of execution)
-  /// s1 = j (Day of execution)
-  ///
-  /// or to (9, 20) by this schedule:
-  ///
-  /// s0 = i + j (Year of execution)
-  /// s1 = 20 (Day of execution)
-  ///
-  /// The order statement instances are executed is defined by the
-  /// schedule vectors they are mapped to. A statement instance
-  /// <A, (i, j, ..)> is executed before a statement instance <B, (i', ..)>, if
-  /// the schedule vector of A is lexicographic smaller than the schedule
-  /// vector of B.
-  isl_map *Schedule;
-
   /// The memory accesses of this statement.
   ///
   /// The only side effects of a statement are its memory accesses.
@@ -530,7 +499,6 @@ private:
   __isl_give isl_set *addLoopBoundsToDomain(__isl_take isl_set *Domain,
                                             TempScop &tempScop);
   __isl_give isl_set *buildDomain(TempScop &tempScop, const Region &CurRegion);
-  void buildSchedule(SmallVectorImpl<unsigned> &ScheduleVec);
 
   /// @brief Create the accesses for instructions in @p Block.
   ///
@@ -612,7 +580,6 @@ public:
   ///
   /// @return The schedule function of this ScopStmt.
   __isl_give isl_map *getSchedule() const;
-  void setSchedule(__isl_take isl_map *Schedule);
 
   /// @brief Get an isl string representing this schedule.
   std::string getScheduleStr() const;
@@ -679,7 +646,6 @@ public:
 
   unsigned getNumParams() const;
   unsigned getNumIterators() const;
-  unsigned getNumSchedule() const;
 
   Scop *getParent() { return &Parent; }
   const Scop *getParent() const { return &Parent; }
@@ -800,6 +766,42 @@ private:
   /// this scop and that need to be code generated as a run-time test.
   isl_set *AssumedContext;
 
+  /// @brief The schedule of the SCoP
+  ///
+  /// The schedule of the SCoP describes the execution order of the statements
+  /// in the scop by assigning each statement instance a possibly
+  /// multi-dimensional execution time. The schedule is stored as a tree of
+  /// schedule nodes.
+  ///
+  /// The most common nodes in a schedule tree are so-called band nodes. Band
+  /// nodes map statement instances into a multi dimensional schedule space.
+  /// This space can be seen as a multi-dimensional clock.
+  ///
+  /// Example:
+  ///
+  /// <S,(5,4)>  may be mapped to (5,4) by this schedule:
+  ///
+  /// s0 = i (Year of execution)
+  /// s1 = j (Day of execution)
+  ///
+  /// or to (9, 20) by this schedule:
+  ///
+  /// s0 = i + j (Year of execution)
+  /// s1 = 20 (Day of execution)
+  ///
+  /// The order statement instances are executed is defined by the
+  /// schedule vectors they are mapped to. A statement instance
+  /// <A, (i, j, ..)> is executed before a statement instance <B, (i', ..)>, if
+  /// the schedule vector of A is lexicographic smaller than the schedule
+  /// vector of B.
+  ///
+  /// Besides band nodes, schedule trees contain additional nodes that specify
+  /// a textual ordering between two subtrees or filter nodes that filter the
+  /// set of statement instances that will be scheduled in a subtree. There
+  /// are also several other nodes. A full description of the different nodes
+  /// in a schedule tree is given in the isl manual.
+  isl_schedule *Schedule;
+
   /// @brief The set of minimal/maximal accesses for each alias group.
   ///
   /// When building runtime alias checks we look at all memory instructions and
@@ -850,18 +852,23 @@ private:
   /// @param tempScop   The temp SCoP we use as model.
   /// @param CurRegion  The SCoP region.
   /// @param NestLoops  A vector of all surrounding loops.
-  /// @param Schedule   The position of the new statement as schedule.
-  void addScopStmt(BasicBlock *BB, Region *R, TempScop &tempScop,
-                   const Region &CurRegion, SmallVectorImpl<Loop *> &NestLoops,
-                   SmallVectorImpl<unsigned> &Schedule);
-
-  /// Build the Scop and Statement with precalculated scop information.
-  void buildScop(TempScop &TempScop, const Region &CurRegion,
-                 // Loops in Scop containing CurRegion
-                 SmallVectorImpl<Loop *> &NestLoops,
-                 // The schedule numbers
-                 SmallVectorImpl<unsigned> &Schedule, LoopInfo &LI,
-                 ScopDetection &SD);
+  ScopStmt *addScopStmt(BasicBlock *BB, Region *R, TempScop &tempScop,
+                        const Region &CurRegion,
+                        SmallVectorImpl<Loop *> &NestLoops);
+
+  /// @brief Build Scop and ScopStmts from a given TempScop.
+  ///
+  /// @param TempScop  The temporary scop that is translated into an actual
+  ///                  scop.
+  /// @param CurRegion The subregion of the current scop that we are currently
+  ///                  translating.
+  /// @param NestLoop  The set of loops that surround the current subregion.
+  /// @param LI        The LoopInfo object.
+  /// @param SD        The ScopDetection object.
+  __isl_give isl_schedule *buildScop(TempScop &TempScop,
+                                     const Region &CurRegion,
+                                     SmallVectorImpl<Loop *> &NestLoops,
+                                     LoopInfo &LI, ScopDetection &SD);
 
   /// @name Helper function for printing the Scop.
   ///
@@ -938,18 +945,6 @@ public:
   /// @return The maximum depth of the loop.
   inline unsigned getMaxLoopDepth() const { return MaxLoopDepth; }
 
-  /// @brief Get the schedule dimension number of this Scop.
-  ///
-  /// @return The schedule dimension number of this Scop.
-  inline unsigned getScheduleDim() const {
-    unsigned maxScheduleDim = 0;
-
-    for (const ScopStmt &Stmt : *this)
-      maxScheduleDim = std::max(maxScheduleDim, Stmt.getNumSchedule());
-
-    return maxScheduleDim;
-  }
-
   /// @brief Mark the SCoP as optimized by the scheduler.
   void markAsOptimized() { IsOptimized = true; }
 
@@ -990,13 +985,6 @@ public:
   /// @returns True if __no__ error occurred, false otherwise.
   bool buildAliasGroups(AliasAnalysis &AA);
 
-  //// @brief Drop all constant dimensions from statment schedules.
-  ///
-  ///  Schedule dimensions that are constant accross the scop do not carry
-  ///  any information, but would cost compile time due to the increased number
-  ///  of schedule dimensions. To not pay this cost, we remove them.
-  void dropConstantScheduleDims();
-
   /// @brief Return all alias groups for this SCoP.
   const MinMaxVectorVectorTy &getAliasGroups() const {
     return MinMaxAliasGroups;
@@ -1064,7 +1052,7 @@ public:
   isl_ctx *getIslCtx() const;
 
   /// @brief Get a union set containing the iteration domains of all statements.
-  __isl_give isl_union_set *getDomains();
+  __isl_give isl_union_set *getDomains() const;
 
   /// @brief Get a union map of all may-writes performed in the SCoP.
   __isl_give isl_union_map *getMayWrites();
@@ -1079,7 +1067,20 @@ public:
   __isl_give isl_union_map *getReads();
 
   /// @brief Get the schedule of all the statements in the SCoP.
-  __isl_give isl_union_map *getSchedule();
+  __isl_give isl_union_map *getSchedule() const;
+
+  /// @brief Get a schedule tree describing the schedule of all statements.
+  __isl_give isl_schedule *getScheduleTree() const;
+
+  /// @brief Update the current schedule
+  ///
+  /// @brief NewSchedule The new schedule (given as a flat union-map).
+  void setSchedule(__isl_take isl_union_map *NewSchedule);
+
+  /// @brief Update the current schedule
+  ///
+  /// @brief NewSchedule The new schedule (given as schedule tree).
+  void setScheduleTree(__isl_take isl_schedule *NewSchedule);
 
   /// @brief Intersects the domains of all statements in the SCoP.
   ///
index afb4ab7..9dd745c 100644 (file)
@@ -45,7 +45,7 @@ static cl::opt<int> OptComputeOut(
     "polly-dependences-computeout",
     cl::desc("Bound the dependence analysis by a maximal amount of "
              "computational steps (0 means no bound)"),
-    cl::Hidden, cl::init(410000), cl::ZeroOrMore, cl::cat(PollyCategory));
+    cl::Hidden, cl::init(500000), cl::ZeroOrMore, cl::cat(PollyCategory));
 
 static cl::opt<bool> LegalityCheckDisabled(
     "disable-polly-legality", cl::desc("Disable polly legality check"),
@@ -220,15 +220,31 @@ void Dependences::addPrivatizationDependences() {
 }
 
 void Dependences::calculateDependences(Scop &S) {
-  isl_union_map *Read, *Write, *MayWrite, *AccessSchedule, *StmtSchedule,
-      *ScheduleMap;
+  isl_union_map *Read, *Write, *MayWrite, *AccessSchedule, *StmtSchedule;
+  isl_schedule *Schedule;
 
   DEBUG(dbgs() << "Scop: \n" << S << "\n");
 
   collectInfo(S, &Read, &Write, &MayWrite, &AccessSchedule, &StmtSchedule);
 
-  ScheduleMap =
-      isl_union_map_union(AccessSchedule, isl_union_map_copy(StmtSchedule));
+  // TODO: Compute dependences directly on the schedule tree
+  //
+  // We currently don't do this yet, as the compile-time performance
+  // implications are not 100% understood (we see some regressions).
+  if (false && isl_union_map_is_empty(AccessSchedule)) {
+    isl_union_map_free(AccessSchedule);
+    Schedule = S.getScheduleTree();
+  } else {
+    auto *ScheduleMap =
+        isl_union_map_union(AccessSchedule, isl_union_map_copy(StmtSchedule));
+    Schedule = isl_schedule_from_domain(
+        isl_union_map_domain(isl_union_map_copy(ScheduleMap)));
+    if (!isl_union_map_is_empty(ScheduleMap))
+      Schedule = isl_schedule_insert_partial_schedule(
+          Schedule, isl_multi_union_pw_aff_from_union_map(ScheduleMap));
+    else
+      isl_union_map_free(ScheduleMap);
+  }
 
   Read = isl_union_map_coalesce(Read);
   Write = isl_union_map_coalesce(Write);
@@ -241,16 +257,10 @@ void Dependences::calculateDependences(Scop &S) {
 
   DEBUG(dbgs() << "Read: " << Read << "\n";
         dbgs() << "Write: " << Write << "\n";
-        dbgs() << "MayWrite: " << MayWrite << "\n";
-        dbgs() << "Schedule: " << ScheduleMap << "\n");
+        dbgs() << "MayWrite: " << MayWrite << "\n");
 
   RAW = WAW = WAR = RED = nullptr;
 
-  auto *Schedule = isl_schedule_from_domain(
-      isl_union_map_domain(isl_union_map_copy(ScheduleMap)));
-  Schedule = isl_schedule_insert_partial_schedule(
-      Schedule, isl_multi_union_pw_aff_from_union_map(ScheduleMap));
-
   if (OptAnalysisType == VALUE_BASED_ANALYSIS) {
     isl_union_access_info *AI;
     isl_union_flow *Flow;
index 6ecedfa..5771c9b 100644 (file)
@@ -40,6 +40,8 @@
 #include "isl/map.h"
 #include "isl/options.h"
 #include "isl/printer.h"
+#include "isl/schedule.h"
+#include "isl/schedule_node.h"
 #include "isl/set.h"
 #include "isl/union_map.h"
 #include "isl/union_set.h"
@@ -846,44 +848,34 @@ void MemoryAccess::setNewAccessRelation(isl_map *newAccess) {
 
 //===----------------------------------------------------------------------===//
 
-isl_map *ScopStmt::getSchedule() const { return isl_map_copy(Schedule); }
+isl_map *ScopStmt::getSchedule() const {
+  isl_set *Domain = getDomain();
+  if (isl_set_is_empty(Domain)) {
+    isl_set_free(Domain);
+    return isl_map_from_aff(
+        isl_aff_zero_on_domain(isl_local_space_from_space(getDomainSpace())));
+  }
+  auto *Schedule = getParent()->getSchedule();
+  Schedule = isl_union_map_intersect_domain(
+      Schedule, isl_union_set_from_set(isl_set_copy(Domain)));
+  if (isl_union_map_is_empty(Schedule)) {
+    isl_set_free(Domain);
+    isl_union_map_free(Schedule);
+    return isl_map_from_aff(
+        isl_aff_zero_on_domain(isl_local_space_from_space(getDomainSpace())));
+  }
+  auto *M = isl_map_from_union_map(Schedule);
+  M = isl_map_coalesce(M);
+  M = isl_map_gist_domain(M, Domain);
+  M = isl_map_coalesce(M);
+  return M;
+}
 
 void ScopStmt::restrictDomain(__isl_take isl_set *NewDomain) {
   assert(isl_set_is_subset(NewDomain, Domain) &&
          "New domain is not a subset of old domain!");
   isl_set_free(Domain);
   Domain = NewDomain;
-  Schedule = isl_map_intersect_domain(Schedule, isl_set_copy(Domain));
-}
-
-void ScopStmt::setSchedule(__isl_take isl_map *NewSchedule) {
-  assert(NewSchedule && "New schedule is nullptr");
-  isl_map_free(Schedule);
-  Schedule = NewSchedule;
-}
-
-void ScopStmt::buildSchedule(SmallVectorImpl<unsigned> &ScheduleVec) {
-  unsigned NbIterators = getNumIterators();
-  unsigned NbScheduleDims = Parent.getMaxLoopDepth() * 2 + 1;
-
-  isl_space *Space = isl_space_set_alloc(getIslCtx(), 0, NbScheduleDims);
-
-  Schedule = isl_map_from_domain_and_range(isl_set_universe(getDomainSpace()),
-                                           isl_set_universe(Space));
-
-  // Loop dimensions.
-  for (unsigned i = 0; i < NbIterators; ++i)
-    Schedule = isl_map_equate(Schedule, isl_dim_out, 2 * i + 1, isl_dim_in, i);
-
-  // Constant dimensions
-  for (unsigned i = 0; i < NbIterators + 1; ++i)
-    Schedule = isl_map_fix_si(Schedule, isl_dim_out, 2 * i, ScheduleVec[i]);
-
-  // Fill schedule dimensions.
-  for (unsigned i = 2 * NbIterators + 1; i < NbScheduleDims; ++i)
-    Schedule = isl_map_fix_si(Schedule, isl_dim_out, i, 0);
-
-  Schedule = isl_map_align_params(Schedule, Parent.getParamSpace());
 }
 
 void ScopStmt::buildAccesses(TempScop &tempScop, BasicBlock *Block,
@@ -916,7 +908,6 @@ void ScopStmt::realignParams() {
     MA->realignParams();
 
   Domain = isl_set_align_params(Domain, Parent.getParamSpace());
-  Schedule = isl_map_align_params(Schedule, Parent.getParamSpace());
 }
 
 __isl_give isl_set *ScopStmt::buildConditionSet(const Comparison &Comp) {
@@ -1075,8 +1066,7 @@ void ScopStmt::deriveAssumptions(BasicBlock *Block) {
 }
 
 ScopStmt::ScopStmt(Scop &parent, TempScop &tempScop, const Region &CurRegion,
-                   Region &R, SmallVectorImpl<Loop *> &Nest,
-                   SmallVectorImpl<unsigned> &ScheduleVec)
+                   Region &R, SmallVectorImpl<Loop *> &Nest)
     : Parent(parent), BB(nullptr), R(&R), Build(nullptr),
       NestLoops(Nest.size()) {
   // Setup the induction variables.
@@ -1086,7 +1076,6 @@ ScopStmt::ScopStmt(Scop &parent, TempScop &tempScop, const Region &CurRegion,
   BaseName = getIslCompatibleName("Stmt_", R.getNameStr(), "");
 
   Domain = buildDomain(tempScop, CurRegion);
-  buildSchedule(ScheduleVec);
 
   BasicBlock *EntryBB = R.getEntry();
   for (BasicBlock *Block : R.blocks()) {
@@ -1097,8 +1086,7 @@ ScopStmt::ScopStmt(Scop &parent, TempScop &tempScop, const Region &CurRegion,
 }
 
 ScopStmt::ScopStmt(Scop &parent, TempScop &tempScop, const Region &CurRegion,
-                   BasicBlock &bb, SmallVectorImpl<Loop *> &Nest,
-                   SmallVectorImpl<unsigned> &ScheduleVec)
+                   BasicBlock &bb, SmallVectorImpl<Loop *> &Nest)
     : Parent(parent), BB(&bb), R(nullptr), Build(nullptr),
       NestLoops(Nest.size()) {
   // Setup the induction variables.
@@ -1108,7 +1096,6 @@ ScopStmt::ScopStmt(Scop &parent, TempScop &tempScop, const Region &CurRegion,
   BaseName = getIslCompatibleName("Stmt_", &bb, "");
 
   Domain = buildDomain(tempScop, CurRegion);
-  buildSchedule(ScheduleVec);
   buildAccesses(tempScop, BB);
   deriveAssumptions(BB);
   checkForReductions();
@@ -1246,17 +1233,16 @@ void ScopStmt::checkForReductions() {
 std::string ScopStmt::getDomainStr() const { return stringFromIslObj(Domain); }
 
 std::string ScopStmt::getScheduleStr() const {
-  return stringFromIslObj(Schedule);
+  auto *S = getSchedule();
+  auto Str = stringFromIslObj(S);
+  isl_map_free(S);
+  return Str;
 }
 
 unsigned ScopStmt::getNumParams() const { return Parent.getNumParams(); }
 
 unsigned ScopStmt::getNumIterators() const { return NestLoops.size(); }
 
-unsigned ScopStmt::getNumSchedule() const {
-  return isl_map_dim(Schedule, isl_dim_out);
-}
-
 const char *ScopStmt::getBaseName() const { return BaseName.c_str(); }
 
 const Loop *ScopStmt::getLoopForDimension(unsigned Dimension) const {
@@ -1278,7 +1264,6 @@ __isl_give isl_id *ScopStmt::getDomainId() const {
 ScopStmt::~ScopStmt() {
   DeleteContainerSeconds(InstructionToAccess);
   isl_set_free(Domain);
-  isl_map_free(Schedule);
 }
 
 void ScopStmt::print(raw_ostream &OS) const {
@@ -1667,39 +1652,6 @@ static unsigned getMaxLoopDepthInRegion(const Region &R, LoopInfo &LI,
   return MaxLD - MinLD + 1;
 }
 
-void Scop::dropConstantScheduleDims() {
-  isl_union_map *FullSchedule = getSchedule();
-
-  if (isl_union_map_n_map(FullSchedule) == 0) {
-    isl_union_map_free(FullSchedule);
-    return;
-  }
-
-  isl_set *ScheduleSpace =
-      isl_set_from_union_set(isl_union_map_range(FullSchedule));
-  isl_map *DropDimMap = isl_set_identity(isl_set_copy(ScheduleSpace));
-
-  int NumDimsDropped = 0;
-  for (unsigned i = 0; i < isl_set_dim(ScheduleSpace, isl_dim_set); i += 2) {
-    isl_val *FixedVal =
-        isl_set_plain_get_val_if_fixed(ScheduleSpace, isl_dim_set, i);
-    if (isl_val_is_int(FixedVal)) {
-      DropDimMap =
-          isl_map_project_out(DropDimMap, isl_dim_out, i - NumDimsDropped, 1);
-      NumDimsDropped++;
-    }
-    isl_val_free(FixedVal);
-  }
-
-  for (ScopStmt &Stmt : *this) {
-    isl_map *Schedule = Stmt.getSchedule();
-    Schedule = isl_map_apply_range(Schedule, isl_map_copy(DropDimMap));
-    Stmt.setSchedule(Schedule);
-  }
-  isl_set_free(ScheduleSpace);
-  isl_map_free(DropDimMap);
-}
-
 Scop::Scop(TempScop &tempScop, LoopInfo &LI, ScalarEvolution &ScalarEvolution,
            ScopDetection &SD, isl_ctx *Context)
     : SE(&ScalarEvolution), R(tempScop.getMaxRegion()), IsOptimized(false),
@@ -1709,18 +1661,16 @@ Scop::Scop(TempScop &tempScop, LoopInfo &LI, ScalarEvolution &ScalarEvolution,
   buildContext();
 
   SmallVector<Loop *, 8> NestLoops;
-  SmallVector<unsigned, 8> Schedule;
-
-  Schedule.assign(MaxLoopDepth + 1, 0);
 
   // Build the iteration domain, access functions and schedule functions
   // traversing the region tree.
-  buildScop(tempScop, getRegion(), NestLoops, Schedule, LI, SD);
+  Schedule = buildScop(tempScop, getRegion(), NestLoops, LI, SD);
+  if (!Schedule)
+    Schedule = isl_schedule_empty(getParamSpace());
 
   realignParams();
   addParameterBounds();
   simplifyAssumedContext();
-  dropConstantScheduleDims();
 
   assert(NestLoops.empty() && "NestLoops not empty at top level!");
 }
@@ -1728,6 +1678,7 @@ Scop::Scop(TempScop &tempScop, LoopInfo &LI, ScalarEvolution &ScalarEvolution,
 Scop::~Scop() {
   isl_set_free(Context);
   isl_set_free(AssumedContext);
+  isl_schedule_free(Schedule);
 
   // Free the alias groups
   for (MinMaxVectorTy *MinMaxAccesses : MinMaxAliasGroups) {
@@ -1861,10 +1812,10 @@ void Scop::dump() const { print(dbgs()); }
 
 isl_ctx *Scop::getIslCtx() const { return IslCtx; }
 
-__isl_give isl_union_set *Scop::getDomains() {
+__isl_give isl_union_set *Scop::getDomains() const {
   isl_union_set *Domain = isl_union_set_empty(getParamSpace());
 
-  for (ScopStmt &Stmt : *this)
+  for (const ScopStmt &Stmt : *this)
     Domain = isl_union_set_add_set(Domain, Stmt.getDomain());
 
   return Domain;
@@ -1939,13 +1890,29 @@ __isl_give isl_union_map *Scop::getReads() {
   return isl_union_map_coalesce(Read);
 }
 
-__isl_give isl_union_map *Scop::getSchedule() {
-  isl_union_map *Schedule = isl_union_map_empty(getParamSpace());
+__isl_give isl_union_map *Scop::getSchedule() const {
+  auto Tree = getScheduleTree();
+  auto S = isl_schedule_get_map(Tree);
+  isl_schedule_free(Tree);
+  return S;
+}
 
-  for (ScopStmt &Stmt : *this)
-    Schedule = isl_union_map_add_map(Schedule, Stmt.getSchedule());
+__isl_give isl_schedule *Scop::getScheduleTree() const {
+  return isl_schedule_intersect_domain(isl_schedule_copy(Schedule),
+                                       getDomains());
+}
 
-  return isl_union_map_coalesce(Schedule);
+void Scop::setSchedule(__isl_take isl_union_map *NewSchedule) {
+  auto *S = isl_schedule_from_domain(getDomains());
+  S = isl_schedule_insert_partial_schedule(
+      S, isl_multi_union_pw_aff_from_union_map(NewSchedule));
+  isl_schedule_free(Schedule);
+  Schedule = S;
+}
+
+void Scop::setScheduleTree(__isl_take isl_schedule *NewSchedule) {
+  isl_schedule_free(Schedule);
+  Schedule = NewSchedule;
 }
 
 bool Scop::restrictDomains(__isl_take isl_union_set *Domain) {
@@ -1985,33 +1952,87 @@ bool Scop::isTrivialBB(BasicBlock *BB, TempScop &tempScop) {
   return true;
 }
 
-void Scop::addScopStmt(BasicBlock *BB, Region *R, TempScop &tempScop,
-                       const Region &CurRegion,
-                       SmallVectorImpl<Loop *> &NestLoops,
-                       SmallVectorImpl<unsigned> &ScheduleVec) {
+struct MapToDimensionDataTy {
+  int N;
+  isl_union_pw_multi_aff *Res;
+};
+
+// @brief Create a function that maps the elements of 'Set' to its N-th
+//        dimension.
+//
+// The result is added to 'User->Res'.
+//
+// @param Set The input set.
+// @param N   The dimension to map to.
+//
+// @returns   Zero if no error occurred, non-zero otherwise.
+static isl_stat mapToDimension_AddSet(__isl_take isl_set *Set, void *User) {
+  struct MapToDimensionDataTy *Data = (struct MapToDimensionDataTy *)User;
+  int Dim;
+  isl_space *Space;
+  isl_pw_multi_aff *PMA;
+
+  Dim = isl_set_dim(Set, isl_dim_set);
+  Space = isl_set_get_space(Set);
+  PMA = isl_pw_multi_aff_project_out_map(Space, isl_dim_set, Data->N,
+                                         Dim - Data->N);
+  if (Data->N > 1)
+    PMA = isl_pw_multi_aff_drop_dims(PMA, isl_dim_out, 0, Data->N - 1);
+  Data->Res = isl_union_pw_multi_aff_add_pw_multi_aff(Data->Res, PMA);
+
+  isl_set_free(Set);
+
+  return isl_stat_ok;
+}
+
+// @brief Create a function that maps the elements of Domain to their Nth
+//        dimension.
+//
+// @param Domain The set of elements to map.
+// @param N      The dimension to map to.
+static __isl_give isl_multi_union_pw_aff *
+mapToDimension(__isl_take isl_union_set *Domain, int N) {
+  struct MapToDimensionDataTy Data;
+  isl_space *Space;
+
+  Space = isl_union_set_get_space(Domain);
+  Data.N = N;
+  Data.Res = isl_union_pw_multi_aff_empty(Space);
+  if (isl_union_set_foreach_set(Domain, &mapToDimension_AddSet, &Data) < 0)
+    Data.Res = isl_union_pw_multi_aff_free(Data.Res);
+
+  isl_union_set_free(Domain);
+  return isl_multi_union_pw_aff_from_union_pw_multi_aff(Data.Res);
+}
+
+ScopStmt *Scop::addScopStmt(BasicBlock *BB, Region *R, TempScop &tempScop,
+                            const Region &CurRegion,
+                            SmallVectorImpl<Loop *> &NestLoops) {
+  ScopStmt *Stmt;
   if (BB) {
-    Stmts.emplace_back(*this, tempScop, CurRegion, *BB, NestLoops, ScheduleVec);
-    StmtMap[BB] = &Stmts.back();
+    Stmts.emplace_back(*this, tempScop, CurRegion, *BB, NestLoops);
+    Stmt = &Stmts.back();
+    StmtMap[BB] = Stmt;
   } else {
     assert(R && "Either basic block or a region expected.");
-    Stmts.emplace_back(*this, tempScop, CurRegion, *R, NestLoops, ScheduleVec);
-    auto *Ptr = &Stmts.back();
+    Stmts.emplace_back(*this, tempScop, CurRegion, *R, NestLoops);
+    Stmt = &Stmts.back();
     for (BasicBlock *BB : R->blocks())
-      StmtMap[BB] = Ptr;
+      StmtMap[BB] = Stmt;
+  }
+  return Stmt;
+}
+
+__isl_give isl_schedule *Scop::buildScop(TempScop &tempScop,
+                                         const Region &CurRegion,
+                                         SmallVectorImpl<Loop *> &NestLoops,
+                                         LoopInfo &LI, ScopDetection &SD) {
+  if (SD.isNonAffineSubRegion(&CurRegion, &getRegion())) {
+    auto *Stmt = addScopStmt(nullptr, const_cast<Region *>(&CurRegion),
+                             tempScop, CurRegion, NestLoops);
+    auto *Domain = Stmt->getDomain();
+    return isl_schedule_from_domain(isl_union_set_from_set(Domain));
   }
-
-  // Increasing the Schedule function is OK for the moment, because
-  // we are using a depth first iterator and the program is well structured.
-  ++ScheduleVec[NestLoops.size()];
-}
-
-void Scop::buildScop(TempScop &tempScop, const Region &CurRegion,
-                     SmallVectorImpl<Loop *> &NestLoops,
-                     SmallVectorImpl<unsigned> &ScheduleVec, LoopInfo &LI,
-                     ScopDetection &SD) {
-  if (SD.isNonAffineSubRegion(&CurRegion, &getRegion()))
-    return addScopStmt(nullptr, const_cast<Region *>(&CurRegion), tempScop,
-                       CurRegion, NestLoops, ScheduleVec);
 
   Loop *L = castToLoop(CurRegion, LI);
 
@@ -2019,30 +2040,45 @@ void Scop::buildScop(TempScop &tempScop, const Region &CurRegion,
     NestLoops.push_back(L);
 
   unsigned loopDepth = NestLoops.size();
-  assert(ScheduleVec.size() > loopDepth && "Schedule not big enough!");
+  isl_schedule *Schedule = nullptr;
 
   for (Region::const_element_iterator I = CurRegion.element_begin(),
                                       E = CurRegion.element_end();
-       I != E; ++I)
+       I != E; ++I) {
+    isl_schedule *StmtSchedule = nullptr;
     if (I->isSubRegion()) {
-      buildScop(tempScop, *I->getNodeAs<Region>(), NestLoops, ScheduleVec, LI,
-                SD);
+      StmtSchedule =
+          buildScop(tempScop, *I->getNodeAs<Region>(), NestLoops, LI, SD);
     } else {
       BasicBlock *BB = I->getNodeAs<BasicBlock>();
 
-      if (isTrivialBB(BB, tempScop))
+      if (isTrivialBB(BB, tempScop)) {
         continue;
-
-      addScopStmt(BB, nullptr, tempScop, CurRegion, NestLoops, ScheduleVec);
+      } else {
+        auto *Stmt = addScopStmt(BB, nullptr, tempScop, CurRegion, NestLoops);
+        auto *Domain = Stmt->getDomain();
+        StmtSchedule = isl_schedule_from_domain(isl_union_set_from_set(Domain));
+      }
     }
 
+    if (!Schedule)
+      Schedule = StmtSchedule;
+    else if (StmtSchedule)
+      Schedule = isl_schedule_sequence(Schedule, StmtSchedule);
+  }
+
   if (!L)
-    return;
+    return Schedule;
+
+  auto *Domain = isl_schedule_get_domain(Schedule);
+  if (!isl_union_set_is_empty(Domain)) {
+    auto *MUPA = mapToDimension(isl_union_set_copy(Domain), loopDepth);
+    Schedule = isl_schedule_insert_partial_schedule(Schedule, MUPA);
+  }
+  isl_union_set_free(Domain);
 
-  // Exiting a loop region.
-  ScheduleVec[loopDepth] = 0;
   NestLoops.pop_back();
-  ++ScheduleVec[loopDepth - 1];
+  return Schedule;
 }
 
 ScopStmt *Scop::getStmtForBasicBlock(BasicBlock *BB) const {
index c9f7ddd..9f564bc 100644 (file)
@@ -382,9 +382,6 @@ IslAst::IslAst(Scop *Scop, const Dependences &D)
 
   Build = isl_ast_build_set_at_each_domain(Build, AtEachDomain, nullptr);
 
-  isl_union_map *Schedule =
-      isl_union_map_intersect_domain(S->getSchedule(), S->getDomains());
-
   if (PerformParallelTest) {
     BuildInfo.Deps = &D;
     BuildInfo.InParallelFor = 0;
@@ -397,7 +394,7 @@ IslAst::IslAst(Scop *Scop, const Dependences &D)
 
   buildRunCondition(Build);
 
-  Root = isl_ast_build_ast_from_schedule(Build, Schedule);
+  Root = isl_ast_build_node_from_schedule(Build, S->getScheduleTree());
 
   isl_ast_build_free(Build);
 }
index 86ffe0f..240a7ae 100644 (file)
@@ -105,6 +105,8 @@ IslNodeBuilder::getUpperBound(__isl_keep isl_ast_node *For,
 unsigned IslNodeBuilder::getNumberOfIterations(__isl_keep isl_ast_node *For) {
   isl_union_map *Schedule = IslAstInfo::getSchedule(For);
   isl_set *LoopDomain = isl_set_from_union_set(isl_union_map_range(Schedule));
+  if (isl_set_is_wrapping(LoopDomain))
+    LoopDomain = isl_map_range(isl_set_unwrap(LoopDomain));
   int Dim = isl_set_dim(LoopDomain, isl_dim_set);
 
   // Calculate a map similar to the identity map, but with the last input
index d5e66f0..de9a4f3 100644 (file)
@@ -27,6 +27,7 @@
 #include "isl/map.h"
 #include "isl/printer.h"
 #include "isl/set.h"
+#include "isl/union_map.h"
 #include "json/reader.h"
 #include "json/writer.h"
 #include <memory>
@@ -260,11 +261,16 @@ bool JSONImporter::runOnScop(Scop &S) {
     return false;
   }
 
+  auto ScheduleMap = isl_union_map_empty(S.getParamSpace());
   for (ScopStmt &Stmt : S) {
     if (NewSchedule.find(&Stmt) != NewSchedule.end())
-      Stmt.setSchedule(NewSchedule[&Stmt]);
+      ScheduleMap = isl_union_map_add_map(ScheduleMap, NewSchedule[&Stmt]);
+    else
+      ScheduleMap = isl_union_map_add_map(ScheduleMap, Stmt.getSchedule());
   }
 
+  S.setSchedule(ScheduleMap);
+
   int statementIdx = 0;
   for (ScopStmt &Stmt : S) {
     int memoryAccessIdx = 0;
index 6e814da..43ed278 100644 (file)
@@ -176,8 +176,20 @@ private:
   /// @param User A pointer to forward some use information (currently unused).
   static isl_schedule_node *optimizeBand(isl_schedule_node *Node, void *User);
 
-  static __isl_give isl_union_map *
-  getScheduleMap(__isl_keep isl_schedule *Schedule);
+  /// @brief Apply post-scheduling transformations.
+  ///
+  /// This function applies a set of additional local transformations on the
+  /// schedule tree as it computed by the isl scheduler. Local transformations
+  /// applied include:
+  ///
+  ///   - Tiling
+  ///   - Prevectorization
+  ///
+  /// @param Schedule The schedule object post-transformations will be applied
+  ///                 on.
+  /// @returns        The transformed schedule.
+  static __isl_give isl_schedule *
+  addPostTransforms(__isl_take isl_schedule *Schedule);
 
   using llvm::Pass::doFinalization;
 
@@ -313,15 +325,15 @@ isl_schedule_node *IslScheduleOptimizer::optimizeBand(isl_schedule_node *Node,
   return Res;
 }
 
-__isl_give isl_union_map *
-IslScheduleOptimizer::getScheduleMap(__isl_keep isl_schedule *Schedule) {
+__isl_give isl_schedule *
+IslScheduleOptimizer::addPostTransforms(__isl_take isl_schedule *Schedule) {
   isl_schedule_node *Root = isl_schedule_get_root(Schedule);
+  isl_schedule_free(Schedule);
   Root = isl_schedule_node_map_descendant_bottom_up(
       Root, IslScheduleOptimizer::optimizeBand, NULL);
-  auto ScheduleMap = isl_schedule_node_get_subtree_schedule_union_map(Root);
-  ScheduleMap = isl_union_map_detect_equalities(ScheduleMap);
+  auto S = isl_schedule_node_get_schedule(Root);
   isl_schedule_node_free(Root);
-  return ScheduleMap;
+  return S;
 }
 
 bool IslScheduleOptimizer::isProfitableSchedule(
@@ -463,36 +475,19 @@ bool IslScheduleOptimizer::runOnScop(Scop &S) {
     isl_printer_free(P);
   });
 
-  isl_union_map *NewSchedule = getScheduleMap(Schedule);
+  isl_schedule *NewSchedule = addPostTransforms(Schedule);
+  isl_union_map *NewScheduleMap = isl_schedule_get_map(NewSchedule);
 
-  // Check if the optimizations performed were profitable, otherwise exit early.
-  if (!isProfitableSchedule(S, NewSchedule)) {
-    isl_schedule_free(Schedule);
-    isl_union_map_free(NewSchedule);
+  if (!isProfitableSchedule(S, NewScheduleMap)) {
+    isl_union_map_free(NewScheduleMap);
+    isl_schedule_free(NewSchedule);
     return false;
   }
 
+  S.setScheduleTree(NewSchedule);
   S.markAsOptimized();
 
-  for (ScopStmt &Stmt : S) {
-    isl_map *StmtSchedule;
-    isl_set *Domain = Stmt.getDomain();
-    isl_union_map *StmtBand;
-    StmtBand = isl_union_map_intersect_domain(isl_union_map_copy(NewSchedule),
-                                              isl_union_set_from_set(Domain));
-    if (isl_union_map_is_empty(StmtBand)) {
-      StmtSchedule = isl_map_from_domain(isl_set_empty(Stmt.getDomainSpace()));
-      isl_union_map_free(StmtBand);
-    } else {
-      assert(isl_union_map_n_map(StmtBand) == 1);
-      StmtSchedule = isl_map_from_union_map(StmtBand);
-    }
-
-    Stmt.setSchedule(StmtSchedule);
-  }
-
-  isl_schedule_free(Schedule);
-  isl_union_map_free(NewSchedule);
+  isl_union_map_free(NewScheduleMap);
   return false;
 }
 
index 801f46e..d6aa3b0 100644 (file)
@@ -49,13 +49,13 @@ exit.3:
   ret void
 }
 
-; CHECK: for (int c1 = 0; c1 <= 199; c1 += 1)
-; CHECK:   Stmt_for_body_1(c1);
-; CHECK: for (int c1 = 0; c1 <= 199; c1 += 1)
-; CHECK:   Stmt_for_body_2(c1);
-; CHECK: for (int c1 = 0; c1 <= 199; c1 += 1)
-; CHECK:   Stmt_for_body_3(c1);
-
-; CHECK-DCE: for (int c1 = 0; c1 <= 199; c1 += 1)
-; CHECK-DCE:   Stmt_for_body_3(c1);
+; CHECK: for (int c0 = 0; c0 <= 199; c0 += 1)
+; CHECK:   Stmt_for_body_1(c0);
+; CHECK: for (int c0 = 0; c0 <= 199; c0 += 1)
+; CHECK:   Stmt_for_body_2(c0);
+; CHECK: for (int c0 = 0; c0 <= 199; c0 += 1)
+; CHECK:   Stmt_for_body_3(c0);
+
+; CHECK-DCE: for (int c0 = 0; c0 <= 199; c0 += 1)
+; CHECK-DCE:   Stmt_for_body_3(c0);
 
index d605254..d2cbe78 100644 (file)
@@ -54,12 +54,12 @@ exit.3:
   ret void
 }
 
-; CHECK: for (int c1 = 0; c1 <= 199; c1 += 1)
-; CHECK:   Stmt_for_body_1(c1);
-; CHECK: for (int c1 = 0; c1 <= 199; c1 += 1)
-; CHECK:   Stmt_for_body_2(c1);
-; CHECK: for (int c1 = 0; c1 <= 199; c1 += 1)
-; CHECK:   Stmt_for_body_3(c1);
+; CHECK: for (int c0 = 0; c0 <= 199; c0 += 1)
+; CHECK:   Stmt_for_body_1(c0);
+; CHECK: for (int c0 = 0; c0 <= 199; c0 += 1)
+; CHECK:   Stmt_for_body_2(c0);
+; CHECK: for (int c0 = 0; c0 <= 199; c0 += 1)
+; CHECK:   Stmt_for_body_3(c0);
 
-; CHECK-DCE: for (int c1 = 0; c1 <= 199; c1 += 1)
-; CHECK-DCE:   Stmt_for_body_3(c1);
+; CHECK-DCE: for (int c0 = 0; c0 <= 199; c0 += 1)
+; CHECK-DCE:   Stmt_for_body_3(c0);
index c53b247..cd5fbea 100644 (file)
@@ -51,13 +51,13 @@ exit.3:
 }
 
 ; CHECK-NOT: Stmt_S
-; CHECK: for (int c1 = 0; c1 <= 199; c1 += 1)
-; CHECK: Stmt_S3(c1);
-
-; TIMEOUT: for (int c1 = 0; c1 <= 99; c1 += 1)
-; TIMEOUT: Stmt_S1(c1);
-; TIMEOUT: for (int c1 = 0; c1 <= 9; c1 += 1)
-; TIMEOUT: Stmt_S2(c1);
-; TIMEOUT: for (int c1 = 0; c1 <= 199; c1 += 1)
-; TIMEOUT: Stmt_S3(c1);
+; CHECK: for (int c0 = 0; c0 <= 199; c0 += 1)
+; CHECK: Stmt_S3(c0);
+
+; TIMEOUT: for (int c0 = 0; c0 <= 99; c0 += 1)
+; TIMEOUT: Stmt_S1(c0);
+; TIMEOUT: for (int c0 = 0; c0 <= 9; c0 += 1)
+; TIMEOUT: Stmt_S2(c0);
+; TIMEOUT: for (int c0 = 0; c0 <= 199; c0 += 1)
+; TIMEOUT: Stmt_S3(c0);
 
index c805616..6d0f8c5 100644 (file)
@@ -67,12 +67,12 @@ exit.4:
   ret void
 }
 
-; CHECK: for (int c1 = 50; c1 <= 99; c1 += 1)
-; CHECK:   Stmt_for_body_1(c1);
-; CHECK: for (int c1 = 110; c1 <= 199; c1 += 1)
-; CHECK:   Stmt_for_body_1(c1);
-; CHECK: for (int c1 = 0; c1 <= 49; c1 += 1)
-; CHECK:   Stmt_for_body_2(c1);
-; CHECK: for (int c1 = 0; c1 <= 69; c1 += 1)
-; CHECK:   Stmt_for_body_3(c1);
-; CHECK: for (int c1 = 0; c1 <= 9; c1 += 1)
+; CHECK: for (int c0 = 50; c0 <= 99; c0 += 1)
+; CHECK:   Stmt_for_body_1(c0);
+; CHECK: for (int c0 = 110; c0 <= 199; c0 += 1)
+; CHECK:   Stmt_for_body_1(c0);
+; CHECK: for (int c0 = 0; c0 <= 49; c0 += 1)
+; CHECK:   Stmt_for_body_2(c0);
+; CHECK: for (int c0 = 0; c0 <= 69; c0 += 1)
+; CHECK:   Stmt_for_body_3(c0);
+; CHECK: for (int c0 = 0; c0 <= 9; c0 += 1)
index b88aff1..ffe5cb0 100644 (file)
 ; the size of A and as a result S1 may write for example to A[1024], which
 ; is not overwritten by S2.
 
-; CHECK: for (int c1 = 0; c1 <= 1023; c1 += 1)
-; CHECK:   Stmt_S1(c1);
-; CHECK: for (int c1 = 0; c1 <= 1023; c1 += 1)
-; CHECK:   Stmt_S2(c1);
+; CHECK: for (int c0 = 0; c0 <= 1023; c0 += 1)
+; CHECK:   Stmt_S1(c0);
+; CHECK: for (int c0 = 0; c0 <= 1023; c0 += 1)
+; CHECK:   Stmt_S2(c0);
 
 target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64"
 
index 62b318a..ff0bbd7 100644 (file)
@@ -52,5 +52,5 @@ exit.3:
   ret void
 }
 
-; CHECK-DCE: for (int c1 = 0; c1 <= 199; c1 += 1)
-; CHECK-DCE:   Stmt_for_body_2(c1);
+; CHECK-DCE: for (int c0 = 0; c0 <= 199; c0 += 1)
+; CHECK-DCE:   Stmt_for_body_2(c0);
index 4bfa417..30e89ea 100644 (file)
@@ -4,10 +4,6 @@
 ;
 ; CHECK: Read: { [Stmt_for_cond[i0] -> MemRef_sum[0]] -> MemRef_sum[0] : i0 >= 0 and i0 <= 100 }
 ; CHECK: Write: { [Stmt_for_cond[i0] -> MemRef_sum[0]] -> MemRef_sum[0] : i0 >= 0 and i0 <= 100 }
-; CHECK: Schedule: {
-; CHECK-DAG: [Stmt_for_cond[i0] -> MemRef_sum[0]] -> [i0] : i0 <= 100 and i0 >= 0
-; CHECK-DAG: Stmt_for_cond[i0] -> [i0]
-; CHECK: }
 ; CHECK: Wrapped Dependences:
 ; CHECK: RAW dependences:
 ; CHECK:   { [Stmt_for_cond[i0] -> MemRef_sum[0]] -> [Stmt_for_cond[1 + i0] -> MemRef_sum[0]] : i0 <= 99 and i0 >= 0 }
index ff223ad..d57e177 100644 (file)
@@ -6,7 +6,7 @@
 ; CHECK:    #pragma known-parallel
 ; CHECK:    for (int c1 = 0; c1 < 2 * n; c1 += 1)
 ; CHECK:      #pragma simd reduction
-; CHECK:      for (int c3 = -1022; c3 <= 1023; c3 += 1) {
+; CHECK:      for (int c3 = -1023; c3 <= 1023; c3 += 1) {
 ; CHECK:        if (c3 <= 0 && c3 % 2 == 0) {
 ; CHECK:          Stmt_for_body3(c1, -c3);
 ; CHECK:        } else if (c3 >= 1 && (c3 - 1) % 2 == 0)
index a6ff0ee..ca0ccc4 100644 (file)
@@ -24,13 +24,13 @@ target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f3
 ; CHECK: )
 
 ; CHECK:     if (o >= 1) {
-; CHECK:       for (int c1 = 0; c1 < n; c1 += 1)
-; CHECK:         for (int c2 = 0; c2 < m; c2 += 1)
-; CHECK:           Stmt_for_j(c1, c2);
+; CHECK:       for (int c0 = 0; c0 < n; c0 += 1)
+; CHECK:         for (int c1 = 0; c1 < m; c1 += 1)
+; CHECK:           Stmt_for_j(c0, c1);
 ; CHECK:     } else
-; CHECK:       for (int c1 = 0; c1 < n; c1 += 1)
-; CHECK:         for (int c2 = 0; c2 < m; c2 += 1)
-; CHECK:           Stmt_for_j_1(c1, c2);
+; CHECK:       for (int c0 = 0; c0 < n; c0 += 1)
+; CHECK:         for (int c1 = 0; c1 < m; c1 += 1)
+; CHECK:           Stmt_for_j_1(c0, c1);
 
 ; CHECK: else
 ; CHECK:     {  /* original code */ }
index 091d3a3..bd55357 100644 (file)
@@ -166,9 +166,9 @@ define i32 @main() nounwind {
 declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) nounwind
 
 ; CHECK: for (int c0 = 0; c0 <= 1023; c0 += 1) {
-; CHECK:   if (c0 >= 513) {
-; CHECK:     Stmt_5(c0);
-; CHECK:   } else
+; CHECK:   if (c0 <= 512) {
 ; CHECK:     Stmt_4(c0);
+; CHECK:   } else
+; CHECK:     Stmt_5(c0);
 ; CHECK:   Stmt_6(c0);
 ; CHECK: }
index 8aa0492..e013a75 100644 (file)
@@ -5,10 +5,10 @@
 
 ; CHECK: #pragma simd
 ; CHECK: for (int c0 = 0; c0 <= 1023; c0 += 1) {
-; CHECK:   if (c0 >= m + 1025) {
-; CHECK:     Stmt_if_else(c0);
-; CHECK:   } else
+; CHECK:   if (m + 1024 >= c0) {
 ; CHECK:     Stmt_if_then(c0);
+; CHECK:   } else
+; CHECK:     Stmt_if_else(c0);
 ; CHECK:   Stmt_if_end(c0);
 ; CHECK: }
 
index e3a9140..d440b20 100644 (file)
@@ -166,9 +166,7 @@ define i32 @main() nounwind {
 declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) nounwind
 
 ; CHECK: for (int c0 = 0; c0 <= 1023; c0 += 1) {
-; CHECK:   if (c0 >= 513) {
-; CHECK:     Stmt_4(c0);
-; CHECK:   } else if (c0 <= 511) {
+; CHECK:   if (c0 >= 513 || c0 <= 511) {
 ; CHECK:     Stmt_4(c0);
 ; CHECK:   } else
 ; CHECK:     Stmt_5(512);
index 6fb6f4d..411c269 100644 (file)
@@ -204,10 +204,10 @@ define i32 @main() nounwind {
 declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) nounwind
 
 ; CHECK: for (int c0 = 0; c0 <= 1023; c0 += 1) {
-; CHECK:   if (c0 <= 20) {
-; CHECK:     Stmt_7(c0);
-; CHECK:   } else if (c0 <= 512)
+; CHECK:   if (c0 >= 21 && c0 <= 512) {
 ; CHECK:     Stmt_6(c0);
+; CHECK:   } else if (c0 <= 20)
+; CHECK:     Stmt_7(c0);
 ; CHECK:   Stmt_9(c0);
 ; CHECK: }
 
index 44acbc3..be01724 100644 (file)
 ;    }
 
 ; AST:    for (int c0 = 0; c0 <= 1023; c0 += 1) {
-; AST:      if (c <= -1) {
-; AST:        Stmt_if_then(c0);
-; AST:      } else if (c >= 1) {
-; AST:        Stmt_if_then(c0);
-; AST:      } else
+; AST:      if (c == 0) {
 ; AST:        Stmt_if_else(c0);
+; AST:      } else if (c <= -1 || c >= 1)
+; AST:        Stmt_if_then(c0);
 ; AST:      Stmt_if_end(c0);
 ; AST:    }
 ;
 ; CHECK-NEXT:     %phi.phiops.reload = load i32, i32* %phi.phiops
 ; CHECK-NEXT:     %scevgep
 ; CHECK-NEXT:     store i32 %phi.phiops.reload, i32*
-; CHECK-LABEL:  polly.stmt.if.then:
-; CHECK-NEXT:     store i32 1, i32* %phi.phiops
-; CHECK-NEXT:     br label %polly.merge{{[.]?}}
-; CHECK-LABEL:  polly.stmt.if.then{{.}}:
-; CHECK-NEXT:     store i32 1, i32* %phi.phiops
-; CHECK-NEXT:     br label %polly.merge{{[.]?}}
 ; CHECK-LABEL:  polly.stmt.if.else:
 ; CHECK-NEXT:     store i32 2, i32* %phi.phiops
 ; CHECK-NEXT:     br label %polly.merge{{[.]?}}
+; CHECK-LABEL:  polly.stmt.if.then:
+; CHECK-NEXT:     store i32 1, i32* %phi.phiops
+; CHECK-NEXT:     br label %polly.merge{{[.]?}}
 ;
 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
 
index f434d39..0a7d80b 100644 (file)
@@ -130,8 +130,8 @@ bb17:                                             ; preds = %bb16, %bb13, %bb7
 declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) nounwind
 
 ; CHECK: {
-; CHECK:   for (int c1 = 0; c1 <= 511; c1 += 1)
-; CHECK:     Stmt_bb2(c1);
-; CHECK:   for (int c1 = 0; c1 <= 511; c1 += 1)
-; CHECK:     Stmt_bb6(c1);
+; CHECK:   for (int c0 = 0; c0 <= 511; c0 += 1)
+; CHECK:     Stmt_bb2(c0);
+; CHECK:   for (int c0 = 0; c0 <= 511; c0 += 1)
+; CHECK:     Stmt_bb6(c0);
 ; CHECK: }
index e0813a1..17c7bb5 100644 (file)
@@ -60,10 +60,10 @@ exit.3:
 ; CHECK:   Stmt_S3(c0);
 ; CHECK: }
 
-; TIMEOUT: for (int c1 = 0; c1 <= 99; c1 += 1)
-; TIMEOUT: Stmt_S1(c1);
-; TIMEOUT: for (int c1 = 0; c1 <= 9; c1 += 1)
-; TIMEOUT: Stmt_S2(c1);
-; TIMEOUT: for (int c1 = 0; c1 <= 199; c1 += 1)
-; TIMEOUT: Stmt_S3(c1);
+; TIMEOUT: for (int c0 = 0; c0 <= 99; c0 += 1)
+; TIMEOUT: Stmt_S1(c0);
+; TIMEOUT: for (int c0 = 0; c0 <= 9; c0 += 1)
+; TIMEOUT: Stmt_S2(c0);
+; TIMEOUT: for (int c0 = 0; c0 <= 199; c0 += 1)
+; TIMEOUT: Stmt_S3(c0);
 
index 617d042..315fcc2 100644 (file)
@@ -1,4 +1,4 @@
-; RUN: opt %loadPolly -polly-detect-unprofitable -polly-opt-isl -analyze -polly-no-tiling=0 -polly-ast -polly-tile-sizes=64,1 < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-opt-isl -analyze -polly-ast -polly-tile-sizes=64,1 < %s | FileCheck %s
 
 ; CHECK: for (int c0 = 0; c0 <= 15; c0 += 1)
 ; CHECK:   for (int c1 = 0; c1 <= 511; c1 += 1)
index 2feb312..3f63353 100644 (file)
@@ -1,4 +1,4 @@
-; RUN: opt %loadPolly -polly-opt-isl -polly-ast -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-opt-isl -polly-ast -analyze -polly-no-early-exit < %s | FileCheck %s
 ;
 ;    void jacobi1d(long T, long N, float *A, float *B) {
 ;      long t, i, j;
 ; Verify that we do not tile bands that have just a single dimension.
 
 ; CHECK: for (int c0 = 0; c0 < T; c0 += 1) {
-; CHECK:   for (int c2 = 0; c2 < N - 2; c2 += 1)
-; CHECK:     Stmt_for_body3(c0, c2);
-; CHECK:   for (int c2 = 0; c2 < N - 2; c2 += 1)
-; CHECK:     Stmt_for_body15(c0, c2);
+; CHECK:   for (int c1 = 0; c1 < N - 2; c1 += 1)
+; CHECK:     Stmt_for_body3(c0, c1);
+; CHECK:   for (int c1 = 0; c1 < N - 2; c1 += 1)
+; CHECK:     Stmt_for_body15(c0, c1);
 ; CHECK: }
 
 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
index 1955128..5a5cccc 100644 (file)
@@ -55,23 +55,23 @@ for.end30:                                        ; preds = %for.inc28
 attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
 
 ; CHECK: #pragma known-parallel
-; CHECK: for (int c1 = 0; c1 <= 47; c1 += 1)
-; CHECK:   for (int c2 = 0; c2 <= 47; c2 += 1)
-; CHECK:     for (int c3 = 0; c3 <= 31; c3 += 1)
-; CHECK:       for (int c4 = 0; c4 <= 31; c4 += 4)
+; CHECK: for (int c0 = 0; c0 <= 47; c0 += 1)
+; CHECK:   for (int c1 = 0; c1 <= 47; c1 += 1)
+; CHECK:     for (int c2 = 0; c2 <= 31; c2 += 1)
+; CHECK:       for (int c3 = 0; c3 <= 31; c3 += 4)
 ; CHECK:         #pragma simd
-; CHECK:         for (int c5 = c4; c5 <= c4 + 3; c5 += 1)
-; CHECK:           Stmt_for_body3(32 * c1 + c3, 32 * c2 + c5);
+; CHECK:         for (int c4 = c3; c4 <= c3 + 3; c4 += 1)
+; CHECK:           Stmt_for_body3(32 * c0 + c2, 32 * c1 + c4);
 ; CHECK: #pragma known-parallel
-; CHECK: for (int c1 = 0; c1 <= 47; c1 += 1)
-; CHECK:   for (int c2 = 0; c2 <= 47; c2 += 1)
-; CHECK:     for (int c3 = 0; c3 <= 47; c3 += 1)
-; CHECK:       for (int c4 = 0; c4 <= 31; c4 += 1)
-; CHECK:         for (int c5 = 0; c5 <= 31; c5 += 4)
-; CHECK:           for (int c6 = 0; c6 <= 31; c6 += 1)
+; CHECK: for (int c0 = 0; c0 <= 47; c0 += 1)
+; CHECK:   for (int c1 = 0; c1 <= 47; c1 += 1)
+; CHECK:     for (int c2 = 0; c2 <= 47; c2 += 1)
+; CHECK:       for (int c3 = 0; c3 <= 31; c3 += 1)
+; CHECK:         for (int c4 = 0; c4 <= 31; c4 += 4)
+; CHECK:           for (int c5 = 0; c5 <= 31; c5 += 1)
 ; CHECK:             #pragma simd
-; CHECK:             for (int c7 = c5; c7 <= c5 + 3; c7 += 1)
-; CHECK:               Stmt_for_body8(32 * c1 + c4, 32 * c2 + c7, 32 * c3 + c6);
+; CHECK:             for (int c6 = c4; c6 <= c4 + 3; c6 += 1)
+; CHECK:               Stmt_for_body8(32 * c0 + c3, 32 * c1 + c6, 32 * c2 + c5);
 
 !llvm.ident = !{!0}
 
index 0111d03..62d4886 100644 (file)
@@ -1,5 +1,5 @@
 ; RUN: opt %loadPolly -polly-detect-unprofitable -polly-opt-isl -analyze -polly-ast -polly-tile-sizes=256,16 < %s | FileCheck %s
-; RUN: opt %loadPolly -polly-detect-unprofitable -polly-opt-isl -analyze -polly-no-tiling -polly-ast -polly-tile-sizes=256,16 < %s | FileCheck %s --check-prefix=NOTILING
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-opt-isl -analyze -polly-no-tiling -polly-ast -polly-tile-sizes=256,16 -polly-no-early-exit < %s | FileCheck %s --check-prefix=NOTILING
 
 ; CHECK: for (int c0 = 0; c0 <= 3; c0 += 1)
 ; CHECK:   for (int c1 = 0; c1 <= 31; c1 += 1)
index 22d84d6..041540b 100644 (file)
@@ -23,7 +23,7 @@
 ; INNERMOST:            Domain :=
 ; INNERMOST:                [p_0, p_1, p_2, p_3, p_4] -> { Stmt_bb16[i0] : (i0 <= 1023 - p_1 and i0 >= 0 and i0 <= 1024 + p_0) or (i0 >= 0 and i0 >= 1025 - p_1 and i0 <= 1024 + p_0) };
 ; INNERMOST:            Schedule :=
-; INNERMOST:                [p_0, p_1, p_2, p_3, p_4] -> { Stmt_bb16[i0] -> [i0] };
+; INNERMOST:                [p_0, p_1, p_2, p_3, p_4] -> { Stmt_bb16[i0] -> [i0] : i0 >= 1025 - p_1 or i0 <= 1023 - p_1 };
 ; INNERMOST:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
 ; INNERMOST:                [p_0, p_1, p_2, p_3, p_4] -> { Stmt_bb16[i0] -> MemRef_A[o0] : 4o0 = p_2 };
 ; INNERMOST:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
index a58918f..fac63fc 100644 (file)
@@ -16,9 +16,9 @@
 ; CHECK:    Statements {
 ; CHECK:      Stmt_bb2
 ; CHECK:            Domain :=
-; CHECK:                [N] -> { Stmt_bb2[i0] : i0 >= 0 and N >= 1 and i0 <= N; Stmt_bb2[0] : N <= 0 };
+; CHECK:                [N] -> { Stmt_bb2[i0] : i0 >= 0 and N >= 1 and i0 <= N; Stmt_bb2[0] : N <= 0 }
 ; CHECK:            Schedule :=
-; CHECK:                [N] -> { Stmt_bb2[i0] -> [i0, 0] };
+; CHECK:                [N] -> { Stmt_bb2[i0] -> [i0, 0] : i0 <= N and N >= 1; Stmt_bb2[0] -> [0, 0] : N <= 0 }
 ; CHECK:            ReadAccess := [Reduction Type: NONE] [Scalar: 1]
 ; CHECK:                [N] -> { Stmt_bb2[i0] -> MemRef_j_0[] };
 ; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
index d40ea47..6fe2b82 100644 (file)
@@ -43,6 +43,6 @@ return:
 ; CHECK:              (P >= 1 and i0 >= 0 and i0 <= -1 + N)
 ; CHECK:                   };
 ; CHECK:        Schedule :=
-; CHECK:            [N, P] -> { Stmt_store[i0] -> [i0] };
+; CHECK:            [N, P] -> { Stmt_store[i0] -> [i0] : P <= -1 or P >= 1 };
 ; CHECK:        MustWriteAccess := [Reduction Type: NONE]
 ; CHECK:            [N, P] -> { Stmt_store[i0] -> MemRef_a[i0] };