Index: include/polly/ScopInfo.h =================================================================== --- include/polly/ScopInfo.h +++ include/polly/ScopInfo.h @@ -1142,6 +1142,9 @@ ScopStmt(const ScopStmt &) = delete; const ScopStmt &operator=(const ScopStmt &) = delete; + /// Create the ScopStmt from another ScopStmt. + ScopStmt(ScopStmt *Original, isl_set *NewDomain, int CopyNo); + /// Create the ScopStmt from a BasicBlock. ScopStmt(Scop &parent, BasicBlock &bb, Loop *SurroundingLoop, std::vector Instructions); @@ -2196,6 +2199,9 @@ /// @return The count of copy statements added to this Scop. unsigned getCopyStmtsNum() { return CopyStmtsNum; } + /// Create a new SCoP statement for @p ScopStmt. + isl_id *copyScopStmt(ScopStmt *NewStmt, isl_set *NewDomain, int CopyNo); + /// Create a new copy statement. /// /// A new statement will be created and added to the statement vector. Index: lib/Analysis/DependenceInfo.cpp =================================================================== --- lib/Analysis/DependenceInfo.cpp +++ lib/Analysis/DependenceInfo.cpp @@ -417,7 +417,8 @@ dbgs() << "MustWrite: " << MustWrite << '\n'; dbgs() << "MayWrite: " << MayWrite << '\n'; dbgs() << "ReductionTagMap: " << ReductionTagMap << '\n'; - dbgs() << "TaggedStmtDomain: " << TaggedStmtDomain << '\n';); + dbgs() << "TaggedStmtDomain: " << isl_union_set_to_str(TaggedStmtDomain) + << '\n';); Schedule = S.getScheduleTree(); Index: lib/Analysis/ScopInfo.cpp =================================================================== --- lib/Analysis/ScopInfo.cpp +++ lib/Analysis/ScopInfo.cpp @@ -1643,6 +1643,30 @@ } } +ScopStmt::ScopStmt(ScopStmt *Original, isl_set *NewDomain, int CopyNo) + : Parent(*(Original->getParent())), InvalidDomain(nullptr), Domain(nullptr), + BB(Original->getBasicBlock()), R(Original->getRegion()), Build(nullptr), + SurroundingLoop(Original->getSurroundingLoop()) { + BaseName = getIslCompatibleName(Original->getBaseName(), "_copy_no_", + std::to_string(CopyNo)); + Domain = NewDomain; + isl_id *Id = isl_id_alloc(getIslCtx(), getBaseName(), this); + Domain = isl_set_set_tuple_id(Domain, isl_id_copy(Id)); + + for (MemoryAccess *Access : Original->MemAccs) { + isl_map *NewAccessRel = Access->getAccessRelation(); + NewAccessRel = + isl_map_set_tuple_name(NewAccessRel, isl_dim_in, getBaseName()); + NewAccessRel = + isl_map_set_tuple_id(NewAccessRel, isl_dim_in, isl_id_copy(Id)); + MemoryAccess *NewAccess = + new MemoryAccess(this, Access->getType(), NewAccessRel); + Parent.addAccessFunction(NewAccess); + addAccess(NewAccess); + } + isl_id_free(Id); +} + ScopStmt::ScopStmt(Scop &parent, Region &R, Loop *SurroundingLoop) : Parent(parent), InvalidDomain(nullptr), Domain(nullptr), BB(nullptr), R(&R), Build(nullptr), SurroundingLoop(SurroundingLoop) { @@ -4661,6 +4685,12 @@ return isl::multi_union_pw_aff(isl::union_pw_multi_aff(Result)); } +isl_id *Scop::copyScopStmt(ScopStmt *NewStmt, isl_set *NewDomain, int CopyNo) { + assert(NewStmt && "Unexpected nullptr!"); + Stmts.emplace_back(NewStmt, NewDomain, CopyNo); + return Stmts.back().getDomainId(); +} + void Scop::addScopStmt(BasicBlock *BB, Loop *SurroundingLoop, std::vector Instructions) { assert(BB && "Unexpected nullptr!"); Index: lib/Exchange/JSONExporter.cpp =================================================================== --- lib/Exchange/JSONExporter.cpp +++ lib/Exchange/JSONExporter.cpp @@ -16,6 +16,7 @@ #include "polly/Options.h" #include "polly/ScopInfo.h" #include "polly/ScopPass.h" +#include "polly/Support/GICHelper.h" #include "polly/Support/ScopLocation.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/RegionInfo.h" @@ -29,6 +30,7 @@ #include "isl/printer.h" #include "isl/set.h" #include "isl/union_map.h" +#include "isl/union_set.h" #include "json/reader.h" #include "json/writer.h" #include @@ -324,6 +326,137 @@ return true; } +// Struct containing the info required for the copying of the statements in the +// scop and the schedule. +struct copy_info { + isl_union_map *NewSchedule; + Scop *S; +}; + +// finds the ScopStmt corresponding to Map. +ScopStmt *findStmtFromMap(Scop *S, isl_map *Map) { + isl_map *Universe; + isl_set *StmtDomain, *MapDomain; + ScopStmt *CurrentStmt; + + Universe = isl_map_universe(isl_map_get_space(Map)); + MapDomain = isl_map_domain(Universe); + + for (ScopStmt &Stmt : *S) { + StmtDomain = isl_map_domain(Stmt.getSchedule()); + if (isl_set_is_equal(StmtDomain, MapDomain)) { + CurrentStmt = &Stmt; + isl_set_free(StmtDomain); + break; + } + isl_set_free(StmtDomain); + } + + isl_set_free(MapDomain); + isl_map_free(Map); + + return CurrentStmt; +} + +// Transforms the schedule of the scopstmt, adds it to newSchedule and adds the +// required ScopStmts to S. +static isl_stat makeStmtSingleValued(__isl_take isl_map *MapToAdd, void *User) { + struct copy_info *Data = (copy_info *)User; + isl_union_map *NewSchedule = Data->NewSchedule; + Scop *S = Data->S; + + isl_map *LexMin; + isl_set *Domain, *SourceDomain; + ScopStmt *CurrentStmt; + std::string Name; + isl_id *Id; + int i = 0; + + CurrentStmt = findStmtFromMap(S, isl_map_copy(MapToAdd)); + SourceDomain = CurrentStmt->getDomain(); + DEBUG(dbgs() << "Original Domain:" << SourceDomain << "\n"); + + while (!isl_map_is_empty(MapToAdd)) { + assert(i < 11 && "More than 10 copies required!"); + + assert((LexMin = isl_map_lexmin(isl_map_copy(MapToAdd))) && + "Map is not lower-bounded!"); + MapToAdd = isl_map_subtract(MapToAdd, isl_map_copy(LexMin)); + + if (i != 0) { + Name = getIslCompatibleName( + (std::string)isl_map_get_tuple_name(LexMin, isl_dim_in), "_copy_no_", + std::to_string(i)); + + Domain = isl_map_domain(isl_map_copy(LexMin)); + Domain = isl_set_intersect(Domain, isl_set_copy(SourceDomain)); + Domain = isl_set_set_tuple_name(Domain, Name.c_str()); + DEBUG(dbgs() << "New Domain:" << Domain << "\n"); + + LexMin = isl_map_set_tuple_name(LexMin, isl_dim_in, Name.c_str()); + + Id = S->copyScopStmt(CurrentStmt, Domain, i); + LexMin = isl_map_set_tuple_id(LexMin, isl_dim_in, Id); + } + assert((NewSchedule = isl_union_map_add_map(NewSchedule, LexMin)) && + "Adding to schedule failed!"); + + i++; + } + isl_map_free(MapToAdd); + isl_set_free(SourceDomain); + + return isl_stat_ok; +} + +/// Makes a single-valued schedule and adds the required ScopStmts to the +/// Scop. +/// +/// @param OldSchedule The non-single-valued schedule to be made single-valued. +/// +/// @param S The Scop where the new ScopStmts need to be added. +/// +/// @returns isl_union_map the new single valued schedule. +isl_union_map *makeScheduleSingleValued(isl_union_map *OldSchedule, Scop &S) { + isl_union_map *NewSchedule = + isl_union_map_empty(isl_union_map_get_space(OldSchedule)); + struct copy_info CopyData = {NewSchedule, &S}; + + assert(isl_union_map_foreach_map(OldSchedule, &makeStmtSingleValued, + &CopyData) >= 0 && + "error during fixing schedule!"); + + DEBUG(dbgs() << "\nNew Map:\n" << CopyData.NewSchedule << "\n\n"); + + isl_union_map_free(OldSchedule); + return CopyData.NewSchedule; +} + +static isl_stat basicMapIsBounded(__isl_take isl_basic_map *Map, void *User) { + if (isl_basic_map_image_is_bounded(Map)) { + isl_basic_map_free(Map); + return isl_stat_ok; + } + isl_basic_map_free(Map); + return isl_stat_error; +} + +static isl_stat mapIsBounded(__isl_take isl_map *Map, void *User) { + if (isl_map_foreach_basic_map(Map, basicMapIsBounded, NULL) == isl_stat_ok) { + isl_map_free(Map); + return isl_stat_ok; + } + isl_map_free(Map); + return isl_stat_error; +} + +bool unionMapIsBounded(isl_union_map *Map) { + if (isl_union_map_foreach_map(Map, &mapIsBounded, NULL) == isl_stat_ok) { + return true; + } + return false; +} + bool JSONImporter::importSchedule(Scop &S, Json::Value &JScop, const Dependences &D) { StatementToIslMapTy NewSchedule; @@ -399,7 +532,29 @@ ScheduleMap = isl_union_map_add_map(ScheduleMap, Stmt.getSchedule()); } - S.setSchedule(ScheduleMap); + // Check if the map is single valued. + if (!isl_union_map_is_single_valued(ScheduleMap)) { + DEBUG( + dbgs() << "JScop file contains a schedule that is not single valued\n"); + + // Not Yet Finished, when ScheduleMap can be fixed by + // makeScheduleSingleValued, the new ScheduleMap will be passed. + if (!unionMapIsBounded(ScheduleMap)) { + DEBUG(dbgs() << "JScop file contains a schedule that is not bounded\n"); + isl_union_map_free(ScheduleMap); + return false; + } + ScheduleMap = makeScheduleSingleValued(ScheduleMap, S); + + S.setSchedule(ScheduleMap); + + const Dependences &NewD = + getAnalysis().recomputeDependences( + Dependences::AL_Statement); + DEBUG(dbgs() << "\nNew dependences:\n"; NewD.dump();); + } else { + S.setSchedule(ScheduleMap); + } return true; } @@ -744,17 +899,17 @@ if (!Success) return false; - Success = importSchedule(S, jscop, D); + Success = importArrays(S, jscop); if (!Success) return false; - Success = importArrays(S, jscop); + Success = importAccesses(S, jscop, DL); if (!Success) return false; - Success = importAccesses(S, jscop, DL); + Success = importSchedule(S, jscop, D); if (!Success) return false; Index: test/ScopDetect/recomputation.ll =================================================================== --- test/ScopDetect/recomputation.ll +++ test/ScopDetect/recomputation.ll @@ -0,0 +1,139 @@ +; RUN: opt -polly-import-jscop -polly-import-jscop-dir=%S -polly-import-jscop-postfix=recompute -polly-ast -debug -polly-process-unprofitable -disable-polly-legality < %s 2>&1 | FileCheck %s + +; void double_convolution(int* restrict Input, int* restrict Kernel1, int* restrict Intermediate, +; int* restrict Kernel2, int* restrict Output){ +; +; for (int m1 = 0; m1 < 96; m1++){ +; Intermediate[m1] = 0; +; } +; +; for (int m1 = 0; m1 < 94; m1++){ +; Output[m1] = 0; +; } +; +; for (int m1 = 0; m1 < 96; m1++){ +; for(int k1 = 0; k1 < 5; k1++){ +; Intermediate[m1] += Input[ m1 + k1 ] * Kernel1[k1]; +; } +; } +; +; for (int m2 = 0; m2 < 94; m2++){ +; for(int k2 = 0; k2 < 3; k2++){ +; Output[m2] += Intermediate[ m2 + k2 ] * Kernel2[k2]; +; } +; } +; } + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +define void @double_convolution(i32* noalias %Input, i32* noalias %Kernel1, i32* noalias %Intermediate, i32* noalias %Kernel2, i32* noalias %Output) #0 { +entry: + br label %entry.split + +entry.split: ; preds = %entry + br label %for.body + +for.cond2.preheader: ; preds = %for.body + br label %for.body4 + +for.body: ; preds = %entry.split, %for.body + %indvars.iv21 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next22, %for.body ] + %arrayidx = getelementptr inbounds i32, i32* %Intermediate, i64 %indvars.iv21 + store i32 0, i32* %arrayidx, align 4 + %indvars.iv.next22 = add nuw nsw i64 %indvars.iv21, 1 + %exitcond23 = icmp ne i64 %indvars.iv.next22, 96 + br i1 %exitcond23, label %for.body, label %for.cond2.preheader + +for.cond11.preheader: ; preds = %for.body4 + br label %for.cond14.preheader + +for.body4: ; preds = %for.cond2.preheader, %for.body4 + %indvars.iv18 = phi i64 [ 0, %for.cond2.preheader ], [ %indvars.iv.next19, %for.body4 ] + %arrayidx6 = getelementptr inbounds i32, i32* %Output, i64 %indvars.iv18 + store i32 0, i32* %arrayidx6, align 4 + %indvars.iv.next19 = add nuw nsw i64 %indvars.iv18, 1 + %exitcond20 = icmp ne i64 %indvars.iv.next19, 94 + br i1 %exitcond20, label %for.body4, label %for.cond11.preheader + +for.cond14.preheader: ; preds = %for.cond11.preheader, %for.inc27 + %indvars.iv15 = phi i64 [ 0, %for.cond11.preheader ], [ %indvars.iv.next16, %for.inc27 ] + br label %for.body16 + +for.cond30.preheader: ; preds = %for.inc27 + br label %for.cond33.preheader + +for.body16: ; preds = %for.cond14.preheader, %for.body16 + %indvars.iv11 = phi i64 [ 0, %for.cond14.preheader ], [ %indvars.iv.next12, %for.body16 ] + %0 = add nuw nsw i64 %indvars.iv11, %indvars.iv15 + %arrayidx18 = getelementptr inbounds i32, i32* %Input, i64 %0 + %1 = load i32, i32* %arrayidx18, align 4 + %arrayidx20 = getelementptr inbounds i32, i32* %Kernel1, i64 %indvars.iv11 + %2 = load i32, i32* %arrayidx20, align 4 + %mul = mul nsw i32 %2, %1 + %arrayidx22 = getelementptr inbounds i32, i32* %Intermediate, i64 %indvars.iv15 + %3 = load i32, i32* %arrayidx22, align 4 + %add23 = add nsw i32 %3, %mul + store i32 %add23, i32* %arrayidx22, align 4 + %indvars.iv.next12 = add nuw nsw i64 %indvars.iv11, 1 + %exitcond14 = icmp ne i64 %indvars.iv.next12, 5 + br i1 %exitcond14, label %for.body16, label %for.inc27 + +for.inc27: ; preds = %for.body16 + %indvars.iv.next16 = add nuw nsw i64 %indvars.iv15, 1 + %exitcond17 = icmp ne i64 %indvars.iv.next16, 96 + br i1 %exitcond17, label %for.cond14.preheader, label %for.cond30.preheader + +for.cond33.preheader: ; preds = %for.cond30.preheader, %for.inc48 + %indvars.iv8 = phi i64 [ 0, %for.cond30.preheader ], [ %indvars.iv.next9, %for.inc48 ] + br label %for.body35 + +for.body35: ; preds = %for.cond33.preheader, %for.body35 + %indvars.iv = phi i64 [ 0, %for.cond33.preheader ], [ %indvars.iv.next, %for.body35 ] + %4 = add nuw nsw i64 %indvars.iv, %indvars.iv8 + %arrayidx38 = getelementptr inbounds i32, i32* %Intermediate, i64 %4 + %5 = load i32, i32* %arrayidx38, align 4 + %arrayidx40 = getelementptr inbounds i32, i32* %Kernel2, i64 %indvars.iv + %6 = load i32, i32* %arrayidx40, align 4 + %mul41 = mul nsw i32 %6, %5 + %arrayidx43 = getelementptr inbounds i32, i32* %Output, i64 %indvars.iv8 + %7 = load i32, i32* %arrayidx43, align 4 + %add44 = add nsw i32 %7, %mul41 + store i32 %add44, i32* %arrayidx43, align 4 + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + %exitcond = icmp ne i64 %indvars.iv.next, 3 + br i1 %exitcond, label %for.body35, label %for.inc48 + +for.inc48: ; preds = %for.body35 + %indvars.iv.next9 = add nuw nsw i64 %indvars.iv8, 1 + %exitcond10 = icmp ne i64 %indvars.iv.next9, 94 + br i1 %exitcond10, label %for.cond33.preheader, label %for.end50 + +for.end50: ; preds = %for.inc48 + ret void +} + +; CHECK: JScop file contains a schedule that is not single valued +; CHECK-NOT: JScop file contains a schedule that is not bounded +; CHECK: if (1) +; CHECK: { +; CHECK-NEXT: for (int c2 = 0; c2 <= 95; c2 += 1) +; CHECK-NEXT: Stmt0(c2); +; CHECK-NEXT: for (int c2 = 0; c2 <= 93; c2 += 1) +; CHECK-NEXT: Stmt2(c2); +; CHECK-NEXT: for (int c1 = 0; c1 <= 93; c1 += 4) { +; CHECK-NEXT: if (c1 >= 4) +; CHECK-NEXT: for (int c3 = c1; c3 <= c1 + 1; c3 += 1) +; CHECK-NEXT: for (int c4 = 0; c4 <= 4; c4 += 1) +; CHECK-NEXT: Stmt5_copy_no_1(c3, c4); +; CHECK-NEXT: if (c1 == 0) +; CHECK-NEXT: for (int c3 = 0; c3 <= 4; c3 += 1) +; CHECK-NEXT: for (int c4 = 0; c4 <= 4; c4 += 1) +; CHECK-NEXT: Stmt5(c3, c4); +; CHECK-NEXT: for (int c3 = max(5, c1 + 2); c3 <= min(95, c1 + 5); c3 += 1) +; CHECK-NEXT: for (int c4 = 0; c4 <= 4; c4 += 1) +; CHECK-NEXT: Stmt5(c3, c4); +; CHECK-NEXT: for (int c3 = c1; c3 <= min(93, c1 + 3); c3 += 1) +; CHECK-NEXT: for (int c4 = 0; c4 <= 2; c4 += 1) +; CHECK-NEXT: Stmt9(c3, c4); +; CHECK-NEXT: } +; CHECK-NEXT: } Index: test/ScopDetect/recomputation_unbound.ll =================================================================== --- test/ScopDetect/recomputation_unbound.ll +++ test/ScopDetect/recomputation_unbound.ll @@ -0,0 +1,119 @@ +; RUN: opt -polly-import-jscop -polly-import-jscop-dir=%S -polly-import-jscop-postfix=unbound -polly-ast -debug -polly-process-unprofitable -disable-polly-legality < %s 2>&1 | FileCheck %s + +; void double_convolution(int* restrict Input, int* restrict Kernel1, int* restrict Intermediate, +; int* restrict Kernel2, int* restrict Output){ +; +; for (int m1 = 0; m1 < 96; m1++){ +; Intermediate[m1] = 0; +; } +; +; for (int m1 = 0; m1 < 94; m1++){ +; Output[m1] = 0; +; } +; +; for (int m1 = 0; m1 < 96; m1++){ +; for(int k1 = 0; k1 < 5; k1++){ +; Intermediate[m1] += Input[ m1 + k1 ] * Kernel1[k1]; +; } +; } +; +; for (int m2 = 0; m2 < 94; m2++){ +; for(int k2 = 0; k2 < 3; k2++){ +; Output[m2] += Intermediate[ m2 + k2 ] * Kernel2[k2]; +; } +; } +; } + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +define void @double_convolution(i32* noalias %Input, i32* noalias %Kernel1, i32* noalias %Intermediate, i32* noalias %Kernel2, i32* noalias %Output) #0 { +entry: + br label %entry.split + +entry.split: ; preds = %entry + br label %for.body + +for.cond2.preheader: ; preds = %for.body + br label %for.body4 + +for.body: ; preds = %entry.split, %for.body + %indvars.iv21 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next22, %for.body ] + %arrayidx = getelementptr inbounds i32, i32* %Intermediate, i64 %indvars.iv21 + store i32 0, i32* %arrayidx, align 4 + %indvars.iv.next22 = add nuw nsw i64 %indvars.iv21, 1 + %exitcond23 = icmp ne i64 %indvars.iv.next22, 96 + br i1 %exitcond23, label %for.body, label %for.cond2.preheader + +for.cond11.preheader: ; preds = %for.body4 + br label %for.cond14.preheader + +for.body4: ; preds = %for.cond2.preheader, %for.body4 + %indvars.iv18 = phi i64 [ 0, %for.cond2.preheader ], [ %indvars.iv.next19, %for.body4 ] + %arrayidx6 = getelementptr inbounds i32, i32* %Output, i64 %indvars.iv18 + store i32 0, i32* %arrayidx6, align 4 + %indvars.iv.next19 = add nuw nsw i64 %indvars.iv18, 1 + %exitcond20 = icmp ne i64 %indvars.iv.next19, 94 + br i1 %exitcond20, label %for.body4, label %for.cond11.preheader + +for.cond14.preheader: ; preds = %for.cond11.preheader, %for.inc27 + %indvars.iv15 = phi i64 [ 0, %for.cond11.preheader ], [ %indvars.iv.next16, %for.inc27 ] + br label %for.body16 + +for.cond30.preheader: ; preds = %for.inc27 + br label %for.cond33.preheader + +for.body16: ; preds = %for.cond14.preheader, %for.body16 + %indvars.iv11 = phi i64 [ 0, %for.cond14.preheader ], [ %indvars.iv.next12, %for.body16 ] + %0 = add nuw nsw i64 %indvars.iv11, %indvars.iv15 + %arrayidx18 = getelementptr inbounds i32, i32* %Input, i64 %0 + %1 = load i32, i32* %arrayidx18, align 4 + %arrayidx20 = getelementptr inbounds i32, i32* %Kernel1, i64 %indvars.iv11 + %2 = load i32, i32* %arrayidx20, align 4 + %mul = mul nsw i32 %2, %1 + %arrayidx22 = getelementptr inbounds i32, i32* %Intermediate, i64 %indvars.iv15 + %3 = load i32, i32* %arrayidx22, align 4 + %add23 = add nsw i32 %3, %mul + store i32 %add23, i32* %arrayidx22, align 4 + %indvars.iv.next12 = add nuw nsw i64 %indvars.iv11, 1 + %exitcond14 = icmp ne i64 %indvars.iv.next12, 5 + br i1 %exitcond14, label %for.body16, label %for.inc27 + +for.inc27: ; preds = %for.body16 + %indvars.iv.next16 = add nuw nsw i64 %indvars.iv15, 1 + %exitcond17 = icmp ne i64 %indvars.iv.next16, 96 + br i1 %exitcond17, label %for.cond14.preheader, label %for.cond30.preheader + +for.cond33.preheader: ; preds = %for.cond30.preheader, %for.inc48 + %indvars.iv8 = phi i64 [ 0, %for.cond30.preheader ], [ %indvars.iv.next9, %for.inc48 ] + br label %for.body35 + +for.body35: ; preds = %for.cond33.preheader, %for.body35 + %indvars.iv = phi i64 [ 0, %for.cond33.preheader ], [ %indvars.iv.next, %for.body35 ] + %4 = add nuw nsw i64 %indvars.iv, %indvars.iv8 + %arrayidx38 = getelementptr inbounds i32, i32* %Intermediate, i64 %4 + %5 = load i32, i32* %arrayidx38, align 4 + %arrayidx40 = getelementptr inbounds i32, i32* %Kernel2, i64 %indvars.iv + %6 = load i32, i32* %arrayidx40, align 4 + %mul41 = mul nsw i32 %6, %5 + %arrayidx43 = getelementptr inbounds i32, i32* %Output, i64 %indvars.iv8 + %7 = load i32, i32* %arrayidx43, align 4 + %add44 = add nsw i32 %7, %mul41 + store i32 %add44, i32* %arrayidx43, align 4 + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + %exitcond = icmp ne i64 %indvars.iv.next, 3 + br i1 %exitcond, label %for.body35, label %for.inc48 + +for.inc48: ; preds = %for.body35 + %indvars.iv.next9 = add nuw nsw i64 %indvars.iv8, 1 + %exitcond10 = icmp ne i64 %indvars.iv.next9, 94 + br i1 %exitcond10, label %for.cond33.preheader, label %for.end50 + +for.end50: ; preds = %for.inc48 + ret void +} + +; CHECK: JScop file contains a schedule that is not single valued +; CHECK: JScop file contains a schedule that is not bounded +; CHECK-NOT: Stmt0_copy_no_1 +; CHECK-NOT: Stmt2_copy_no_1 +; CHECK-NOT: Stmt5_copy_no_1