diff options
author | Johannes Doerfert <doerfert@cs.uni-saarland.de> | 2015-10-11 13:21:03 +0000 |
---|---|---|
committer | Johannes Doerfert <doerfert@cs.uni-saarland.de> | 2015-10-11 13:21:03 +0000 |
commit | 9b1f9c8b61192980d6ae81f24e7b697638a11223 (patch) | |
tree | 696d8a7a602a3b25eea530a91a079286a899033d | |
parent | 2e5bbce75f4df3ab8dbcc459234635f858db1be1 (diff) | |
download | bcm5719-llvm-9b1f9c8b61192980d6ae81f24e7b697638a11223.tar.gz bcm5719-llvm-9b1f9c8b61192980d6ae81f24e7b697638a11223.zip |
Allow eager evaluated binary && and || conditions
The domain generation can handle lazy && and || by default but eager
evaluated expressions were dismissed as non-affine. With this patch we
will allow arbitrary combinations of and/or bit-operations in the
conditions of branches.
Differential Revision: http://reviews.llvm.org/D13624
llvm-svn: 249971
-rw-r--r-- | polly/lib/Analysis/ScopDetection.cpp | 11 | ||||
-rw-r--r-- | polly/lib/Analysis/ScopInfo.cpp | 60 | ||||
-rw-r--r-- | polly/test/ScopInfo/eager-binary-and-or-conditions.ll | 87 | ||||
-rw-r--r-- | polly/test/ScopInfo/multiple-binary-or-conditions.ll | 47 |
4 files changed, 190 insertions, 15 deletions
diff --git a/polly/lib/Analysis/ScopDetection.cpp b/polly/lib/Analysis/ScopDetection.cpp index 01d4a663659..775d217170d 100644 --- a/polly/lib/Analysis/ScopDetection.cpp +++ b/polly/lib/Analysis/ScopDetection.cpp @@ -340,6 +340,17 @@ bool ScopDetection::isValidSwitch(BasicBlock &BB, SwitchInst *SI, bool ScopDetection::isValidBranch(BasicBlock &BB, BranchInst *BI, Value *Condition, bool IsLoopBranch, DetectionContext &Context) const { + + if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(Condition)) { + auto Opcode = BinOp->getOpcode(); + if (Opcode == Instruction::And || Opcode == Instruction::Or) { + Value *Op0 = BinOp->getOperand(0); + Value *Op1 = BinOp->getOperand(1); + return isValidBranch(BB, BI, Op0, IsLoopBranch, Context) && + isValidBranch(BB, BI, Op1, IsLoopBranch, Context); + } + } + // Non constant conditions of branches need to be ICmpInst. if (!isa<ICmpInst>(Condition)) { if (!IsLoopBranch && AllowNonAffineSubRegions && diff --git a/polly/lib/Analysis/ScopInfo.cpp b/polly/lib/Analysis/ScopInfo.cpp index ef52bd34a1c..e1ecf350ef6 100644 --- a/polly/lib/Analysis/ScopInfo.cpp +++ b/polly/lib/Analysis/ScopInfo.cpp @@ -998,35 +998,39 @@ buildConditionSets(Scop &S, SwitchInst *SI, Loop *L, __isl_keep isl_set *Domain, isl_pw_aff_free(LHS); } -/// @brief Build the conditions sets for the terminator @p TI in the @p Domain. +/// @brief Build the conditions sets for the branch condition @p Condition in +/// the @p Domain. /// /// This will fill @p ConditionSets with the conditions under which control /// will be moved from @p TI to its successors. Hence, @p ConditionSets will /// have as many elements as @p TI has successors. static void -buildConditionSets(Scop &S, TerminatorInst *TI, Loop *L, +buildConditionSets(Scop &S, Value *Condition, TerminatorInst *TI, Loop *L, __isl_keep isl_set *Domain, SmallVectorImpl<__isl_give isl_set *> &ConditionSets) { - if (SwitchInst *SI = dyn_cast<SwitchInst>(TI)) - return buildConditionSets(S, SI, L, Domain, ConditionSets); - - assert(isa<BranchInst>(TI) && "Terminator was neither branch nor switch."); - - if (TI->getNumSuccessors() == 1) { - ConditionSets.push_back(isl_set_copy(Domain)); - return; - } - - Value *Condition = getConditionFromTerminator(TI); - assert(Condition && "No condition for Terminator"); - isl_set *ConsequenceCondSet = nullptr; if (auto *CCond = dyn_cast<ConstantInt>(Condition)) { if (CCond->isZero()) ConsequenceCondSet = isl_set_empty(isl_set_get_space(Domain)); else ConsequenceCondSet = isl_set_universe(isl_set_get_space(Domain)); + } else if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(Condition)) { + auto Opcode = BinOp->getOpcode(); + assert(Opcode == Instruction::And || Opcode == Instruction::Or); + + buildConditionSets(S, BinOp->getOperand(0), TI, L, Domain, ConditionSets); + buildConditionSets(S, BinOp->getOperand(1), TI, L, Domain, ConditionSets); + + isl_set_free(ConditionSets.pop_back_val()); + isl_set *ConsCondPart0 = ConditionSets.pop_back_val(); + isl_set_free(ConditionSets.pop_back_val()); + isl_set *ConsCondPart1 = ConditionSets.pop_back_val(); + + if (Opcode == Instruction::And) + ConsequenceCondSet = isl_set_intersect(ConsCondPart0, ConsCondPart1); + else + ConsequenceCondSet = isl_set_union(ConsCondPart0, ConsCondPart1); } else { auto *ICond = dyn_cast<ICmpInst>(Condition); assert(ICond && @@ -1051,6 +1055,32 @@ buildConditionSets(Scop &S, TerminatorInst *TI, Loop *L, isl_set_intersect(AlternativeCondSet, isl_set_copy(Domain)))); } +/// @brief Build the conditions sets for the terminator @p TI in the @p Domain. +/// +/// This will fill @p ConditionSets with the conditions under which control +/// will be moved from @p TI to its successors. Hence, @p ConditionSets will +/// have as many elements as @p TI has successors. +static void +buildConditionSets(Scop &S, TerminatorInst *TI, Loop *L, + __isl_keep isl_set *Domain, + SmallVectorImpl<__isl_give isl_set *> &ConditionSets) { + + if (SwitchInst *SI = dyn_cast<SwitchInst>(TI)) + return buildConditionSets(S, SI, L, Domain, ConditionSets); + + assert(isa<BranchInst>(TI) && "Terminator was neither branch nor switch."); + + if (TI->getNumSuccessors() == 1) { + ConditionSets.push_back(isl_set_copy(Domain)); + return; + } + + Value *Condition = getConditionFromTerminator(TI); + assert(Condition && "No condition for Terminator"); + + return buildConditionSets(S, Condition, TI, L, Domain, ConditionSets); +} + void ScopStmt::buildDomain() { isl_id *Id; diff --git a/polly/test/ScopInfo/eager-binary-and-or-conditions.ll b/polly/test/ScopInfo/eager-binary-and-or-conditions.ll new file mode 100644 index 00000000000..c36d2c08b89 --- /dev/null +++ b/polly/test/ScopInfo/eager-binary-and-or-conditions.ll @@ -0,0 +1,87 @@ +; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s +; RUN: opt %loadPolly -polly-codegen -analyze < %s +; +; void or(float *A, long n, long m) { +; for (long i = 0; i < 100; i++) { +; if (i < n || i < m) +; A[i] += i; +; } +; } +; +; void and(float *A, long n, long m) { +; for (long i = 0; i < 100; i++) { +; if (i < n && i < m) +; A[i] += i; +; } +; } +; +; CHECK: Function: or +; CHECK: Stmt_if_then +; CHECK: Domain := +; CHECK: [n, m] -> { Stmt_if_then[i0] : (i0 <= 99 and i0 >= 0 and i0 <= -1 + m) or (i0 <= 99 and i0 >= 0 and i0 <= -1 + n) }; +; +; CHECK: Function: and +; CHECK: Stmt_if_then +; CHECK: Domain := +; CHECK: [n, m] -> { Stmt_if_then[i0] : i0 <= 99 and i0 >= 0 and i0 <= -1 + m and i0 <= -1 + n } +; +; +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +; Function Attrs: nounwind uwtable +define void @or(float* nocapture %A, i64 %n, i64 %m) #0 { +entry: + br label %for.body + +for.body: ; preds = %for.inc, %entry + %i.03 = phi i64 [ 0, %entry ], [ %inc, %for.inc ] + %cmp1 = icmp slt i64 %i.03, %n + %cmp2 = icmp slt i64 %i.03, %m + %or.cond = or i1 %cmp1, %cmp2 + br i1 %or.cond, label %if.then, label %for.inc + +if.then: ; preds = %for.body + %conv = sitofp i64 %i.03 to float + %arrayidx = getelementptr inbounds float, float* %A, i64 %i.03 + %0 = load float, float* %arrayidx, align 4 + %add = fadd float %conv, %0 + store float %add, float* %arrayidx, align 4 + br label %for.inc + +for.inc: ; preds = %if.then, %for.body + %inc = add nuw nsw i64 %i.03, 1 + %exitcond = icmp eq i64 %inc, 100 + br i1 %exitcond, label %for.end, label %for.body + +for.end: ; preds = %for.inc + ret void +} + +; Function Attrs: nounwind uwtable +define void @and(float* nocapture %A, i64 %n, i64 %m) #0 { +entry: + br label %for.body + +for.body: ; preds = %for.inc, %entry + %i.03 = phi i64 [ 0, %entry ], [ %inc, %for.inc ] + %cmp1 = icmp slt i64 %i.03, %n + %cmp2 = icmp slt i64 %i.03, %m + %or.cond = and i1 %cmp1, %cmp2 + br i1 %or.cond, label %if.then, label %for.inc + +if.then: ; preds = %for.body + %conv = sitofp i64 %i.03 to float + %arrayidx = getelementptr inbounds float, float* %A, i64 %i.03 + %0 = load float, float* %arrayidx, align 4 + %add = fadd float %conv, %0 + store float %add, float* %arrayidx, align 4 + br label %for.inc + +for.inc: ; preds = %for.body, %if.then + %inc = add nuw nsw i64 %i.03, 1 + %exitcond = icmp eq i64 %inc, 100 + br i1 %exitcond, label %for.end, label %for.body + +for.end: ; preds = %for.inc + ret void +} diff --git a/polly/test/ScopInfo/multiple-binary-or-conditions.ll b/polly/test/ScopInfo/multiple-binary-or-conditions.ll new file mode 100644 index 00000000000..71efeb9807a --- /dev/null +++ b/polly/test/ScopInfo/multiple-binary-or-conditions.ll @@ -0,0 +1,47 @@ +; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s +; RUN: opt %loadPolly -polly-codegen -analyze < %s +; +; void or(float *A, long n, long m) { +; for (long i = 0; i < 100; i++) { +; if (i < n || i < m || i > p) +; A[i] += i; +; } +; } +; +; CHECK: Function: or +; CHECK: Stmt_if_then +; CHECK: Domain := +; CHECK: [n, m, p] -> { Stmt_if_then[i0] : (i0 >= 1 + p and i0 <= 99 and i0 >= 0) or (i0 <= 99 and i0 >= 0 and i0 <= -1 + m) or (i0 <= 99 and i0 >= 0 and i0 <= -1 + n) }; +; +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +; Function Attrs: nounwind uwtable +define void @or(float* nocapture %A, i64 %n, i64 %m, i64 %p) #0 { +entry: + br label %for.body + +for.body: ; preds = %for.inc, %entry + %i.03 = phi i64 [ 0, %entry ], [ %inc, %for.inc ] + %cmp1 = icmp slt i64 %i.03, %n + %cmp2 = icmp slt i64 %i.03, %m + %cmp3 = icmp sgt i64 %i.03, %p + %or.tmp = or i1 %cmp1, %cmp2 + %or.cond = or i1 %or.tmp, %cmp3 + br i1 %or.cond, label %if.then, label %for.inc + +if.then: ; preds = %for.body + %conv = sitofp i64 %i.03 to float + %arrayidx = getelementptr inbounds float, float* %A, i64 %i.03 + %0 = load float, float* %arrayidx, align 4 + %add = fadd float %conv, %0 + store float %add, float* %arrayidx, align 4 + br label %for.inc + +for.inc: ; preds = %if.then, %for.body + %inc = add nuw nsw i64 %i.03, 1 + %exitcond = icmp eq i64 %inc, 100 + br i1 %exitcond, label %for.end, label %for.body + +for.end: ; preds = %for.inc + ret void +} |