diff --git a/polly/lib/Analysis/ScopDetection.cpp b/polly/lib/Analysis/ScopDetection.cpp index d67f2d1730af..f0bbf3d7b6ae 100644 --- a/polly/lib/Analysis/ScopDetection.cpp +++ b/polly/lib/Analysis/ScopDetection.cpp @@ -554,9 +554,9 @@ bool ScopDetection::isValidRegion(DetectionContext &Context) const { if (R.getEntry() == &(R.getEntry()->getParent()->getEntryBlock())) INVALID(Other, "Region containing entry block of function is invalid!"); - // Only a simple region is allowed. - if (!R.isSimple()) - INVALID(SimpleRegion, "Region not simple: " << R.getNameStr()); + // Only regions that have a single entry are allowed. + if (!R.getEnteringBlock()) + INVALID(SimpleRegion, "Region has multiple entries: " << R.getNameStr()); if (!isValidExit(Context)) return false; diff --git a/polly/lib/CodeGen/CodeGeneration.cpp b/polly/lib/CodeGen/CodeGeneration.cpp index e3e5621693e1..664638c00f6e 100644 --- a/polly/lib/CodeGen/CodeGeneration.cpp +++ b/polly/lib/CodeGen/CodeGeneration.cpp @@ -34,6 +34,7 @@ #include "polly/CodeGen/PTXGenerator.h" #include "polly/CodeGen/Utils.h" #include "polly/Support/GICHelper.h" +#include "polly/Support/ScopHelper.h" #include "llvm/IR/Module.h" #include "llvm/ADT/SetVector.h" @@ -983,7 +984,16 @@ public: bool runOnScop(Scop &S) { ParallelLoops.clear(); - assert(S.getRegion().isSimple() && "Only simple regions are supported"); + Region &R = S.getRegion(); + + assert (!R.isTopLevelRegion() && "Top level regions are not supported"); + assert (R.getEnteringBlock() && "Only support regions with a single entry"); + + if (!R.getExitingBlock()) { + BasicBlock *newExit = createSingleExitEdge(&R, this); + for (Region::const_iterator RI = R.begin(), RE = R.end(); RI != RE; ++RI) + (*RI)->replaceExitRecursive(newExit); + } BasicBlock *StartBlock = executeScopConditionally(S, this); diff --git a/polly/lib/CodeGen/IslCodeGeneration.cpp b/polly/lib/CodeGen/IslCodeGeneration.cpp index 6db09258a629..6e0d225ce16d 100644 --- a/polly/lib/CodeGen/IslCodeGeneration.cpp +++ b/polly/lib/CodeGen/IslCodeGeneration.cpp @@ -30,6 +30,7 @@ #include "polly/CodeGen/LoopGenerators.h" #include "polly/CodeGen/Utils.h" #include "polly/Support/GICHelper.h" +#include "polly/Support/ScopHelper.h" #include "llvm/IR/Module.h" #include "llvm/Analysis/LoopInfo.h" @@ -1024,7 +1025,17 @@ public: bool runOnScop(Scop &S) { IslAstInfo &AstInfo = getAnalysis(); - assert(S.getRegion().isSimple() && "Only simple regions are supported"); + + Region &R = S.getRegion(); + + assert (!R.isTopLevelRegion() && "Top level regions are not supported"); + assert (R.getEnteringBlock() && "Only support regions with a single entry"); + + if (!R.getExitingBlock()) { + BasicBlock *newExit = createSingleExitEdge(&R, this); + for (Region::const_iterator RI = R.begin(), RE = R.end(); RI != RE; ++RI) + (*RI)->replaceExitRecursive(newExit); + } BasicBlock *StartBlock = executeScopConditionally(S, this); isl_ast_node *Ast = AstInfo.getAst(); diff --git a/polly/test/Isl/CodeGen/simple_loop_non_single_exit.ll b/polly/test/Isl/CodeGen/simple_loop_non_single_exit.ll new file mode 100644 index 000000000000..ab4c2b9cbe74 --- /dev/null +++ b/polly/test/Isl/CodeGen/simple_loop_non_single_exit.ll @@ -0,0 +1,37 @@ +; RUN: opt %loadPolly -polly-codegen-isl -analyze < %s | FileCheck %s +; RUN: opt %loadPolly -polly-codegen-isl -S < %s | FileCheck %s -check-prefix=CHECK-CODE + +; void f(long A[], long N) { +; long i; +; if (true) +; for (i = 0; i < N; ++i) +; A[i] = i; +; } + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" +target triple = "x86_64-unknown-linux-gnu" + +define void @f(i64* %A, i64 %N) nounwind { +entry: + fence seq_cst + br label %next + +next: + br i1 true, label %for.i, label %return + +for.i: + %indvar = phi i64 [ 0, %next], [ %indvar.next, %for.i ] + %scevgep = getelementptr i64* %A, i64 %indvar + store i64 %indvar, i64* %scevgep + %indvar.next = add nsw i64 %indvar, 1 + %exitcond = icmp eq i64 %indvar.next, %N + br i1 %exitcond, label %return, label %for.i + +return: + fence seq_cst + ret void +} + +; CHECK: Create LLVM-IR from SCoPs' for region: 'next => polly.merge_new_and_old' +; CHECK-CODE: polly.split_new_and_old +; CHECK-CODE: polly.merge_new_and_old diff --git a/polly/test/Isl/CodeGen/simple_loop_non_single_exit_2.ll b/polly/test/Isl/CodeGen/simple_loop_non_single_exit_2.ll new file mode 100644 index 000000000000..4f09802bb7a7 --- /dev/null +++ b/polly/test/Isl/CodeGen/simple_loop_non_single_exit_2.ll @@ -0,0 +1,38 @@ +; RUN: opt %loadPolly -polly-codegen-isl -analyze < %s | FileCheck %s +; RUN: opt %loadPolly -polly-codegen-isl -S < %s | FileCheck %s -check-prefix=CHECK-CODE + +; void f(long A[], long N) { +; long i; +; if (true) +; if (true) +; for (i = 0; i < N; ++i) +; A[i] = i; +; } + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" +target triple = "x86_64-unknown-linux-gnu" + +define void @f(i64* %A, i64 %N) nounwind { +entry: + fence seq_cst + br i1 true, label %next, label %return + +next: + br i1 true, label %for.i, label %return + +for.i: + %indvar = phi i64 [ 0, %next], [ %indvar.next, %for.i ] + %scevgep = getelementptr i64* %A, i64 %indvar + store i64 %indvar, i64* %scevgep + %indvar.next = add nsw i64 %indvar, 1 + %exitcond = icmp eq i64 %indvar.next, %N + br i1 %exitcond, label %return, label %for.i + +return: + fence seq_cst + ret void +} + +; CHECK: Create LLVM-IR from SCoPs' for region: 'for.i => return' +; CHECK-CODE: polly.split_new_and_old +; CHECK-CODE: polly.merge_new_and_old diff --git a/polly/test/ScopDetect/cross_loop_non_single_exit.ll b/polly/test/ScopDetect/cross_loop_non_single_exit.ll new file mode 100644 index 000000000000..82ec1e7c9eb6 --- /dev/null +++ b/polly/test/ScopDetect/cross_loop_non_single_exit.ll @@ -0,0 +1,50 @@ +; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s +; RUN: opt %loadPolly -polly-detect -polly-codegen-scev -analyze < %s | FileCheck %s + +; void f(long A[], long N) { +; long i; +; if (true) +; for (i = 0; i < N; ++i) +; A[i] = i; +; else +; for (j = 0; j < N; ++j) +; A[j] = j; +; } + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" +target triple = "x86_64-unknown-linux-gnu" + +define void @f(i64* %A, i64 %N) nounwind { +entry: + fence seq_cst + br i1 true, label %next, label %next2 + +next2: + br i1 true, label %for.j, label %return + +for.j: + %indvar2 = phi i64 [ 0, %next2], [ %indvar2.next2, %for.j] + %scevgep2 = getelementptr i64* %A, i64 %indvar2 + store i64 %indvar2, i64* %scevgep2 + %indvar2.next2 = add nsw i64 %indvar2, 1 + %exitcond2 = icmp eq i64 %indvar2.next2, %N + br i1 %exitcond2, label %return, label %for.j + +next: + br i1 true, label %for.i, label %return + +for.i: + %indvar = phi i64 [ 0, %next], [ %indvar.next, %for.i ] + %scevgep = getelementptr i64* %A, i64 %indvar + store i64 %indvar, i64* %scevgep + %indvar.next = add nsw i64 %indvar, 1 + %exitcond = icmp eq i64 %indvar.next, %N + br i1 %exitcond, label %return, label %for.i + +return: + fence seq_cst + ret void +} + +; CHECK: Valid Region for Scop: next => return +; CHECK: Valid Region for Scop: next2 => return diff --git a/polly/test/ScopDetect/cross_loop_non_single_exit_2.ll b/polly/test/ScopDetect/cross_loop_non_single_exit_2.ll new file mode 100644 index 000000000000..730205463d36 --- /dev/null +++ b/polly/test/ScopDetect/cross_loop_non_single_exit_2.ll @@ -0,0 +1,62 @@ +; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s +; RUN: opt %loadPolly -polly-detect -polly-codegen-scev -analyze < %s | FileCheck %s + +; void f(long A[], long N) { +; long i; +; if (true) +; for (i = 0; i < N; ++i) +; A[i] = i; +; else +; for (j = 0; j < N; ++j) +; A[j] = j; +; } + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" +target triple = "x86_64-unknown-linux-gnu" + +declare i64 @foo() + +define void @f(i64* %A, i64 %N) nounwind { +entry: + fence seq_cst + br i1 true, label %next, label %next2 + +next2: + br i1 true, label %for.j, label %return + +for.j: + %indvar2 = phi i64 [ 0, %next2], [ %indvar2.next2, %for.j] + %scevgep2 = getelementptr i64* %A, i64 %indvar2 + store i64 %indvar2, i64* %scevgep2 + %indvar2.next2 = add nsw i64 %indvar2, 1 + %exitcond2 = icmp eq i64 %indvar2.next2, %N + br i1 %exitcond2, label %return, label %for.j + +next: + br i1 true, label %for.i, label %return + +for.i: + %indvar = phi i64 [ 0, %next], [ %indvar.next, %for.i ] + %scevgep = getelementptr i64* %A, i64 %indvar + store i64 %indvar, i64* %scevgep + %i = call i64 @foo() + %indvar.next = add nsw i64 %indvar, 1 + %exitcond = icmp eq i64 %indvar.next, %N + br i1 %exitcond, label %return, label %for.i + +return: + br i1 true, label %return_a, label %return_b + +return_a: + br label %return_join + +return_b: + br label %return_join + +return_join: + fence seq_cst + ret void +} + +; CHECK-NOT: Valid Region for Scop: next => return +; CHECK: Valid Region for Scop: next2 => return diff --git a/polly/test/ScopDetect/nested_loop_single_exit.ll b/polly/test/ScopDetect/nested_loop_single_exit.ll new file mode 100644 index 000000000000..216774aab0f5 --- /dev/null +++ b/polly/test/ScopDetect/nested_loop_single_exit.ll @@ -0,0 +1,47 @@ +; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s +; RUN: opt %loadPolly -polly-region-simplify -polly-detect -analyze < %s | FileCheck %s +; RUN: opt %loadPolly -polly-detect -polly-codegen-isl -analyze < %s | FileCheck %s +; RUN: opt %loadPolly -polly-region-simplify -polly-detect -polly-codegen-isl -analyze < %s | FileCheck %s + +; void f(long A[], long N) { +; long i, j; +; if (true) +; for (j = 0; j < N; ++j) +; for (i = 0; i < N; ++i) +; A[i] = i; +; } + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" +target triple = "x86_64-unknown-linux-gnu" + +define void @f(i64* %A, i64 %N) nounwind { +entry: + fence seq_cst + br label %next + +next: + br i1 true, label %for.j, label %return + +for.j: + %j.015 = phi i64 [ %inc5, %for.inc8 ], [ 0, %next ] + br label %for.i + +for.i: + %indvar = phi i64 [ 0, %for.j], [ %indvar.next, %for.i ] + %scevgep = getelementptr i64* %A, i64 %indvar + store i64 %indvar, i64* %scevgep + %indvar.next = add nsw i64 %indvar, 1 + %exitcond = icmp eq i64 %indvar.next, %N + br i1 %exitcond, label %for.inc8, label %for.i + +for.inc8: ; preds = %for.body3 + %inc5 = add nsw i64 %j.015, 1 + %exitcond16 = icmp eq i64 %inc5, %N + br i1 %exitcond16, label %return, label %for.j + +return: + fence seq_cst + ret void +} + +; CHECK: Valid Region for Scop: next => return diff --git a/polly/test/ScopDetect/simple_loop_non_single_exit.ll b/polly/test/ScopDetect/simple_loop_non_single_exit.ll index 7138fddeec2e..83cb066e1dce 100644 --- a/polly/test/ScopDetect/simple_loop_non_single_exit.ll +++ b/polly/test/ScopDetect/simple_loop_non_single_exit.ll @@ -1,7 +1,7 @@ ; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s -; RUN: opt %loadPolly -polly-region-simplify -polly-detect -analyze < %s | FileCheck %s -check-prefix=CHECK-SIMPLIFY +; RUN: opt %loadPolly -polly-region-simplify -polly-detect -analyze < %s | FileCheck %s ; RUN: opt %loadPolly -polly-detect -polly-codegen-scev -analyze < %s | FileCheck %s -; RUN: opt %loadPolly -polly-region-simplify -polly-detect -polly-codegen-scev -analyze < %s | FileCheck %s -check-prefix=CHECK-SIMPLIFY +; RUN: opt %loadPolly -polly-region-simplify -polly-detect -polly-codegen-scev -analyze < %s | FileCheck %s ; void f(long A[], long N) { ; long i; @@ -34,5 +34,4 @@ return: ret void } -; CHECK: Valid Region for Scop: for.i => return -; CHECK-SIMPLIFY: Valid Region for Scop: next => return +; CHECK: Valid Region for Scop: next => return diff --git a/polly/test/ScopDetect/simple_loop_non_single_exit_2.ll b/polly/test/ScopDetect/simple_loop_non_single_exit_2.ll index d88d9eb6e38d..1f5022f85693 100644 --- a/polly/test/ScopDetect/simple_loop_non_single_exit_2.ll +++ b/polly/test/ScopDetect/simple_loop_non_single_exit_2.ll @@ -1,7 +1,7 @@ ; RUN: opt %loadPolly -polly-detect -analyze < %s | FileCheck %s -; RUN: opt %loadPolly -polly-region-simplify -polly-detect -analyze < %s | FileCheck %s -check-prefix=CHECK-SIMPLIFY +; RUN: opt %loadPolly -polly-region-simplify -polly-detect -analyze < %s | FileCheck %s ; RUN: opt %loadPolly -polly-detect -polly-codegen-scev -analyze < %s | FileCheck %s -; RUN: opt %loadPolly -polly-region-simplify -polly-detect -polly-codegen-scev -analyze < %s | FileCheck %s -check-prefix=CHECK-SIMPLIFY +; RUN: opt %loadPolly -polly-region-simplify -polly-detect -polly-codegen-scev -analyze < %s | FileCheck %s ; void f(long A[], long N) { ; long i; @@ -35,5 +35,4 @@ return: ret void } -; CHECK: Valid Region for Scop: for.i => return -; CHECK-SIMPLIFY: Valid Region for Scop: next => return.single_exit1 +; CHECK: Valid Region for Scop: next => return