Index: include/polly/ScopInfo.h =================================================================== --- include/polly/ScopInfo.h +++ include/polly/ScopInfo.h @@ -1189,6 +1189,8 @@ /// Initialize members after all MemoryAccesses have been added. void init(LoopInfo &LI); + void updateAccesDomain(); + private: /// Polyhedral description //@{ @@ -1351,6 +1353,8 @@ /// Set the invalid context for this statement to @p ID. void setInvalidDomain(isl::set ID); + void setDomain(isl::set ID); + /// Get the BasicBlock represented by this ScopStmt (if any). /// /// @return The BasicBlock represented by this ScopStmt, or null if the Index: lib/Analysis/ScopInfo.cpp =================================================================== --- lib/Analysis/ScopInfo.cpp +++ lib/Analysis/ScopInfo.cpp @@ -1747,6 +1747,16 @@ checkForReductions(); } +void ScopStmt::updateAccesDomain() { + for (MemoryAccess *MA : MemAccs) { + isl::map AccessRel = MA->getAccessRelation(); + isl::id Id = AccessRel.get_tuple_id(isl::dim::in); + AccessRel = AccessRel.add_dims(isl::dim::in, 1); + AccessRel = AccessRel.set_tuple_id(isl::dim::in, Id); + MA->setAccessRelation(AccessRel); + } +} + /// Collect loads which might form a reduction chain with @p StoreMA. /// /// Check if the stored value for @p StoreMA is a binary operator with one or @@ -1891,6 +1901,11 @@ void ScopStmt::setInvalidDomain(isl::set ID) { InvalidDomain = ID; } +void ScopStmt::setDomain(isl::set ID) { + collectSurroundingLoops(); + Domain = ID; +} + BasicBlock *ScopStmt::getEntryBlock() const { if (isBlockStmt()) return getBasicBlock(); 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,135 @@ return true; } +// 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(Map.get_space()); + MapDomain = Universe.domain(); + + for (ScopStmt &Stmt : S) { + StmtDomain = Stmt.getSchedule().domain(); + if (StmtDomain.is_equal(MapDomain)) { + CurrentStmt = &Stmt; + break; + } + } + + return CurrentStmt; +} + +isl::stat makeStmtSingleValued(Scop &S, isl::union_map *NewSchedule, + isl::map MapToAdd) { + isl::map LexMin; + + assert((LexMin = MapToAdd.lexmin()) && "Map is not lower-bounded!"); + if (!MapToAdd.is_equal(LexMin)) { + // non-singular valued map + int i = 0; + ScopStmt *CurrentStmt; + int dim = MapToAdd.dim(isl::dim::in); + + // schedule for dim = 0 + isl::map CurMap = LexMin.add_dims(isl::dim::in, 1); + isl::id Id = LexMin.get_tuple_id(isl::dim::in); + isl::set Domain; + isl::local_space LS = isl::local_space(CurMap.get_space()); + isl::constraint C = isl::constraint::alloc_equality(LS); + C = C.set_constant_val(isl::val(MapToAdd.get_ctx(), -i)); + C = C.set_coefficient_si(isl::dim::in, dim, 1); + i++; + + CurMap = CurMap.add_constraint(C); + CurMap = CurMap.set_tuple_id(isl::dim::in, Id); + Domain = CurMap.domain(); + *NewSchedule = NewSchedule->add_map(CurMap); + + MapToAdd = MapToAdd.subtract(LexMin); + // schedule for dim > 0 + while (!MapToAdd.is_empty()) { + assert((LexMin = MapToAdd.lexmin()) && "Map is not lower-bounded!"); + MapToAdd = MapToAdd.subtract(LexMin); + + CurMap = LexMin.add_dims(isl::dim::in, 1); + C = C.set_constant_val(isl::val(MapToAdd.get_ctx(), -i)); + CurMap = CurMap.add_constraint(C); + CurMap = CurMap.set_tuple_id(isl::dim::in, Id); + + *NewSchedule = NewSchedule->add_map(CurMap); + i++; + + Domain = Domain.unite(CurMap.domain()); + } + + // Find the new domain + CurrentStmt = findStmtFromMap(S, MapToAdd); + isl::set OrigDomain = CurrentStmt->getDomain(); + OrigDomain = OrigDomain.add_dims(isl::dim::set, 1); + OrigDomain = OrigDomain.set_tuple_id(Id); + Domain = Domain.intersect(OrigDomain); + + // Adjust the Scop + CurrentStmt->setDomain(Domain); + CurrentStmt->updateAccesDomain(); + + } else { + // singular valued map + *NewSchedule = NewSchedule->add_map(MapToAdd); + } + + 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; + NewSchedule = NewSchedule.empty(OldSchedule.get_space()); + + assert(OldSchedule.foreach_map([&S, &NewSchedule](isl::map Map) -> isl::stat { + return makeStmtSingleValued(S, &NewSchedule, Map); + }) == isl::stat::ok && + "error during fixing schedule!"); + + DEBUG(dbgs() << "\nNew Map:\n"; NewSchedule.dump(); dbgs() << "\n\n"); + + return 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; +} + +static 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; @@ -400,7 +531,31 @@ isl_union_map_add_map(ScheduleMap, Stmt.getSchedule().release()); } - 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(isl::manage(ScheduleMap), S).release(); + + S.setSchedule(ScheduleMap); + + const Dependences &NewD = + getAnalysis().recomputeDependences( + Dependences::AL_Statement); + DEBUG(dbgs() << "\nNew dependences:\n"; NewD.dump();); + } else { + S.setSchedule(ScheduleMap); + } return true; } @@ -760,17 +915,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/double_convolution___%for.body---%for.end50.jscop.recompute =================================================================== --- test/ScopDetect/double_convolution___%for.body---%for.end50.jscop.recompute +++ test/ScopDetect/double_convolution___%for.body---%for.end50.jscop.recompute @@ -0,0 +1,101 @@ +{ + "arrays" : [ + { + "name" : "MemRef0", + "sizes" : [ "*" ], + "type" : "i32" + }, + { + "name" : "MemRef1", + "sizes" : [ "*" ], + "type" : "i32" + }, + { + "name" : "MemRef2", + "sizes" : [ "*" ], + "type" : "i32" + }, + { + "name" : "MemRef3", + "sizes" : [ "*" ], + "type" : "i32" + }, + { + "name" : "MemRef4", + "sizes" : [ "*" ], + "type" : "i32" + } + ], + "context" : "{ : }", + "name" : "%for.body---%for.end50", + "statements" : [ + { + "accesses" : [ + { + "kind" : "write", + "relation" : "{ Stmt0[i0] -> MemRef0[i0] }" + } + ], + "domain" : "{ Stmt0[i0] : 0 <= i0 <= 49 }", + "name" : "Stmt0", + "schedule" : "{ Stmt0[i0] -> [0, i0, 0, 0, 0] }" + }, + { + "accesses" : [ + { + "kind" : "write", + "relation" : "{ Stmt2[i0] -> MemRef1[i0] }" + } + ], + "domain" : "{ Stmt2[i0] : 0 <= i0 <= 47 }", + "name" : "Stmt2", + "schedule" : "{ Stmt2[i0] -> [1, t, 0, i0, 0]: 0 <= t < 6 }" + }, + { + "accesses" : [ + { + "kind" : "read", + "relation" : "{ Stmt5[i0, i1] -> MemRef2[i0 + i1] }" + }, + { + "kind" : "read", + "relation" : "{ Stmt5[i0, i1] -> MemRef3[i1] }" + }, + { + "kind" : "read", + "relation" : "{ Stmt5[i0, i1] -> MemRef0[i0] }" + }, + { + "kind" : "write", + "relation" : "{ Stmt5[i0, i1] -> MemRef0[i0] }" + } + ], + "domain" : "{ Stmt5[i0, i1] : 0 <= i0 <= 49 and 0 <= i1 <= 2 }", + "name" : "Stmt5", + "schedule" : "{ Stmt5[i0, i1] -> [2, t0, 0, t1, i1]: 0 <= t0 < 6 and 0 <= t1 < 10 and i0 = t0 * 8 + t1 }" + }, + { + "accesses" : [ + { + "kind" : "read", + "relation" : "{ Stmt9[i0, i1] -> MemRef0[i0 + i1] }" + }, + { + "kind" : "read", + "relation" : "{ Stmt9[i0, i1] -> MemRef4[i1] }" + }, + { + "kind" : "read", + "relation" : "{ Stmt9[i0, i1] -> MemRef1[i0] }" + }, + { + "kind" : "write", + "relation" : "{ Stmt9[i0, i1] -> MemRef1[i0] }" + } + ], + "domain" : "{ Stmt9[i0, i1] : 0 <= i0 <= 47 and 0 <= i1 <= 2 }", + "name" : "Stmt9", + "schedule" : "{ Stmt9[i0, i1] -> [2, t0, 1, t1, i1]: 0 <= t0 < 6 and 0 <= t1 < 8 and i0 = t0 * 8 + t1 }" + } + ] +} Index: test/ScopDetect/double_convolution___%for.body---%for.end50.jscop.unbound =================================================================== --- test/ScopDetect/double_convolution___%for.body---%for.end50.jscop.unbound +++ test/ScopDetect/double_convolution___%for.body---%for.end50.jscop.unbound @@ -0,0 +1,101 @@ +{ + "arrays" : [ + { + "name" : "MemRef0", + "sizes" : [ "*" ], + "type" : "i32" + }, + { + "name" : "MemRef1", + "sizes" : [ "*" ], + "type" : "i32" + }, + { + "name" : "MemRef2", + "sizes" : [ "*" ], + "type" : "i32" + }, + { + "name" : "MemRef3", + "sizes" : [ "*" ], + "type" : "i32" + }, + { + "name" : "MemRef4", + "sizes" : [ "*" ], + "type" : "i32" + } + ], + "context" : "{ : }", + "name" : "%for.body---%for.end50", + "statements" : [ + { + "accesses" : [ + { + "kind" : "write", + "relation" : "{ Stmt0[i0] -> MemRef0[i0] }" + } + ], + "domain" : "{ Stmt0[i0] : 0 <= i0 <= 49 }", + "name" : "Stmt0", + "schedule" : "{ Stmt0[i0] -> [0, i0, 0, 0, 0] }" + }, + { + "accesses" : [ + { + "kind" : "write", + "relation" : "{ Stmt2[i0] -> MemRef1[i0] }" + } + ], + "domain" : "{ Stmt2[i0] : 0 <= i0 <= 47 }", + "name" : "Stmt2", + "schedule" : "{ Stmt2[i0] -> [1, t, 0, i0, 0]: 0 <= t }" + }, + { + "accesses" : [ + { + "kind" : "read", + "relation" : "{ Stmt5[i0, i1] -> MemRef2[i0 + i1] }" + }, + { + "kind" : "read", + "relation" : "{ Stmt5[i0, i1] -> MemRef3[i1] }" + }, + { + "kind" : "read", + "relation" : "{ Stmt5[i0, i1] -> MemRef0[i0] }" + }, + { + "kind" : "write", + "relation" : "{ Stmt5[i0, i1] -> MemRef0[i0] }" + } + ], + "domain" : "{ Stmt5[i0, i1] : 0 <= i0 <= 49 and 0 <= i1 <= 2 }", + "name" : "Stmt5", + "schedule" : "{ Stmt5[i0, i1] -> [2, t0, 0, t1, i1]: 0 <= t0 < 6 and 0 <= t1 < 10 and i0 = t0 * 8 + t1 }" + }, + { + "accesses" : [ + { + "kind" : "read", + "relation" : "{ Stmt9[i0, i1] -> MemRef0[i0 + i1] }" + }, + { + "kind" : "read", + "relation" : "{ Stmt9[i0, i1] -> MemRef4[i1] }" + }, + { + "kind" : "read", + "relation" : "{ Stmt9[i0, i1] -> MemRef1[i0] }" + }, + { + "kind" : "write", + "relation" : "{ Stmt9[i0, i1] -> MemRef1[i0] }" + } + ], + "domain" : "{ Stmt9[i0, i1] : 0 <= i0 <= 47 and 0 <= i1 <= 2 }", + "name" : "Stmt9", + "schedule" : "{ Stmt9[i0, i1] -> [2, t0, 1, t1, i1]: 0 <= t0 < 6 and 0 <= t1 < 8 and i0 = t0 * 8 + t1 }" + } + ] +} Index: test/ScopDetect/recomputation.ll =================================================================== --- test/ScopDetect/recomputation.ll +++ test/ScopDetect/recomputation.ll @@ -0,0 +1,116 @@ +; 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 < 50; m1++){ +; Intermediate[m1] = 0; +; } +; +; for (int m1 = 0; m1 < 48; m1++){ +; Output[m1] = 0; +; } +; +; for (int m1 = 0; m1 < 50; m1++){ +; for(int k1 = 0; k1 < 3; k1++){ +; Intermediate[m1] += Input[ m1 + k1 ] * Kernel1[k1]; +; } +; } +; +; for (int m2 = 0; m2 < 48; 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.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, 50 + br i1 %exitcond23, label %for.body, label %for.end + +for.end: ; preds = %for.body + br label %for.body4 + +for.body4: ; preds = %for.end, %for.body4 + %indvars.iv18 = phi i64 [ 0, %for.end ], [ %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, 48 + br i1 %exitcond20, label %for.body4, label %for.end9 + +for.end9: ; preds = %for.body4 + br label %for.body13 + +for.body13: ; preds = %for.end9, %for.inc27 + %indvars.iv15 = phi i64 [ 0, %for.end9 ], [ %indvars.iv.next16, %for.inc27 ] + br label %for.body16 + +for.body16: ; preds = %for.body13, %for.body16 + %indvars.iv11 = phi i64 [ 0, %for.body13 ], [ %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, 3 + 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, 50 + br i1 %exitcond17, label %for.body13, label %for.end29 + +for.end29: ; preds = %for.inc27 + br label %for.body32 + +for.body32: ; preds = %for.end29, %for.inc48 + %indvars.iv8 = phi i64 [ 0, %for.end29 ], [ %indvars.iv.next9, %for.inc48 ] + br label %for.body35 + +for.body35: ; preds = %for.body32, %for.body35 + %indvars.iv = phi i64 [ 0, %for.body32 ], [ %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, 48 + br i1 %exitcond10, label %for.body32, 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 Index: test/ScopDetect/recomputation_unbound.ll =================================================================== --- test/ScopDetect/recomputation_unbound.ll +++ test/ScopDetect/recomputation_unbound.ll @@ -0,0 +1,116 @@ +; 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 < 50; m1++){ +; Intermediate[m1] = 0; +; } +; +; for (int m1 = 0; m1 < 48; m1++){ +; Output[m1] = 0; +; } +; +; for (int m1 = 0; m1 < 50; m1++){ +; for(int k1 = 0; k1 < 3; k1++){ +; Intermediate[m1] += Input[ m1 + k1 ] * Kernel1[k1]; +; } +; } +; +; for (int m2 = 0; m2 < 48; 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.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, 50 + br i1 %exitcond23, label %for.body, label %for.end + +for.end: ; preds = %for.body + br label %for.body4 + +for.body4: ; preds = %for.end, %for.body4 + %indvars.iv18 = phi i64 [ 0, %for.end ], [ %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, 48 + br i1 %exitcond20, label %for.body4, label %for.end9 + +for.end9: ; preds = %for.body4 + br label %for.body13 + +for.body13: ; preds = %for.end9, %for.inc27 + %indvars.iv15 = phi i64 [ 0, %for.end9 ], [ %indvars.iv.next16, %for.inc27 ] + br label %for.body16 + +for.body16: ; preds = %for.body13, %for.body16 + %indvars.iv11 = phi i64 [ 0, %for.body13 ], [ %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, 3 + 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, 50 + br i1 %exitcond17, label %for.body13, label %for.end29 + +for.end29: ; preds = %for.inc27 + br label %for.body32 + +for.body32: ; preds = %for.end29, %for.inc48 + %indvars.iv8 = phi i64 [ 0, %for.end29 ], [ %indvars.iv.next9, %for.inc48 ] + br label %for.body35 + +for.body35: ; preds = %for.body32, %for.body35 + %indvars.iv = phi i64 [ 0, %for.body32 ], [ %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, 48 + br i1 %exitcond10, label %for.body32, 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