[polly] r264118 - [ScopInfo] Fix domains after loops.

Tobias Grosser via llvm-commits llvm-commits at lists.llvm.org
Sun Mar 27 09:59:38 PDT 2016


On 03/27/2016 02:34 PM, Johannes Doerfert via llvm-commits wrote:
> Hey Michael,
>
> I think this patch needs some more discussion. Could you revert it and
> we start a new thread to tackle the problem? There is also a chance that
> the problem in the lnt fails is something different [PR26683] that was
> prevented from happening due to the domain simplification of this patch.
> Nevertheless, I think we need to change the domain generation part you
> modified here (wrt. your comment about
> isl_set_drop_constraints_involving_dims) and use a simplification scheme
> similar to D18450.

Hi Michael,

thanks again for all your work on this bug until now. This seems to be 
indeed a rather difficult problem. I had another look, also with the 
goal to answer a question Johannes raised: Does this change simplify the 
domains only or indeed fixes a correctness issue with these domains?

I was personally convinced this change was indeed a correctness fix. To
show this I went again to the test case you committed 
(loop-succ-cond.ll). It seems for this test case there is no correctness 
issue. The domain before your patch was:

	count <= 0 or (count > 0 and p_1 >= 0)

which means only for count > 0 and p_1 < 0, this condition would be 
false. However, for count > 0, the zext from %count to %p_1 would result
in %p_1 being positive as well. Consequently, this condition will not 
arise and the domain is -- just because of the zext -- correct.

Now, Polly currently does not look at the zext and in fact the same 
problem should be visible even without exploiting zext. I made p_1 a new 
parameter (loop-succ-cond-2.ll) to make it very clear that there is no 
relation between the two parameters.

Without your patch we again get { Stmt_if_end12[] : count <= 0 or (count 
 > 0 and count2 >= 0)} and we again see that count > 0 and count2 < 0 is 
the only condition that is missing. However, when looking further, in 
case of count2 being smaller than 0 we will run into the 'nsw' in the 
induction variable increment:

   %indvars.iv.next64 = add nsw i63 %indvars.iv63, 1

So this specific parameter configuration actually triggers undefined 
behavior. Which means the domain is still correct. Now, we can obviously 
drop the nsw to make this behavior defined (loop-succ-cond-3.ll). 
However, as soon as we drop the 'nsw' the condition
count > 0 and count2 <= 0 shows up in the invalid context, as Polly
correctly derives that these parameters would result in an infinite 
loop. We could avoid an infinite loop by using sge instead of eq in the 
exit condition (loop-succ-cond-4.ll), but in this case the old code
suddenly does produce an unconstrained domain for
Stmt_if_end12. You seem to have already realized this as you state in
the commit message: "is logically impossible for non-infinite loops"

For what I tried, it seems the domains we generate have already been 
correct before this patch thanks to the non-infinite-loop assumption we 
take. Johannes/Michael, did I miss anything in my reasoning?

As both of you stated, there are still good reason to simplify such 
domains. However, I think it is still important to understand if there
inherent correctness issues involved or if this change is important 
mostly for not causing trouble with error hoisting or the complexity of
domains.

Best,
Tobias
-------------- next part --------------
; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
; RUN: opt %loadPolly -polly-codegen -S < %s

; Bugpoint-reduced from
; test-suite/SingleSource/Benchmarks/Adobe-C++/loop_unroll.cpp
;
; Check that the loop %loop_start does not narrow the domain (the domain when
; entering and leaving the loop must be identical)
;
; What happened in detail:
;
; 1) if.end5 checks %count whether there will be at least one iteration of
;    loop_start. The domain condition added to loop_start therefore is
;      [count] -> { [] : count > 0 }
; 2) The loop exit condition of loop_start tests whether
;    %indvars.iv.next64 == %0 (which is zext i32 %count to i64, NOT %count
;    itself). %0 and %count have to be treated as independent parameters. The
;    loop exit condition is
;      [p_0] -> { [i0] : i0 = p_0 - 1 }
; 3) Normalized loop induction variables are always non-negative. The domain
;    condition for this is loop
;      { [i0] : i0 >= 0 }
; 4) The intersection of all three sets (condition of executing/entering loop,
;    non-negative induction variables, loop exit condition) is
;      [count, p_0] -> { [i0] : count > 0 and i0 >= 0 and i0 = p_0 - 1 }
; 5) from which ISL can derive
;     [count, p_0] -> { [i0] : p_0 > 0 }
; 6) if.end5 is either executed when skipping the loop
;    (domain [count] -> { [] : count <= 0 })
;    or though the loop.
; 7) Assuming the loop is guaranteed to exit, Polly computes the after-the-loop
;    domain by taking the loop exit condition and projecting-out the induction
;    variable. This yields
;       [count, p_0] -> { [] : count > 0 and p_0 > 0 }
; 8) The disjunction of both cases, 6) and 7)
;    (the two incoming edges of if.end12) is
;      [count, p_0] -> { [] : count <= 0 or (count > 0 and p_0 > 0) }
; 9) Notice that if.end12 is logically _always_ executed in every scop
;    execution. Both cases of if.end5 will eventually land in if.end12

define void @func(i64 %count, i64 %count2, float* %A) {
entry:
  br i1 undef, label %if.end5.preheader, label %for.end

if.end5.preheader:
  %cmp6 = icmp sgt i64 %count, 0
  br label %if.end5

if.end5:
  br i1 %cmp6, label %loop_start, label %if.end12

loop_start:
  %indvars.iv63 = phi i64 [ %indvars.iv.next64, %loop_start ], [ 0, %if.end5 ]
  %add8 = add i32 undef, undef
  store float 0.0, float* %A
  %indvars.iv.next64 = add nsw i64 %indvars.iv63, 1
  %cmp9 = icmp eq i64 %indvars.iv.next64, %count2
  br i1 %cmp9, label %if.end12, label %loop_start

if.end12:
  store float 0.0, float* %A
  br label %for.end

for.end:
  ret void
}


; CHECK:      Statements {
; CHECK-NEXT:     Stmt_if_end12
; CHECK-NEXT:         Domain :=
; CHECK-NEXT:             [count, p_1] -> { Stmt_if_end12[] };
; CHECK-NEXT:         Schedule :=
; CHECK-NEXT:             [count, p_1] -> { Stmt_if_end12[] -> [] };
; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
; CHECK-NEXT:             [count, p_1] -> { Stmt_if_end12[] -> MemRef_A[0] };
; CHECK-NEXT: }
-------------- next part --------------
; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
; RUN: opt %loadPolly -polly-codegen -S < %s

; Bugpoint-reduced from
; test-suite/SingleSource/Benchmarks/Adobe-C++/loop_unroll.cpp
;
; Check that the loop %loop_start does not narrow the domain (the domain when
; entering and leaving the loop must be identical)
;
; What happened in detail:
;
; 1) if.end5 checks %count whether there will be at least one iteration of
;    loop_start. The domain condition added to loop_start therefore is
;      [count] -> { [] : count > 0 }
; 2) The loop exit condition of loop_start tests whether
;    %indvars.iv.next64 == %0 (which is zext i32 %count to i64, NOT %count
;    itself). %0 and %count have to be treated as independent parameters. The
;    loop exit condition is
;      [p_0] -> { [i0] : i0 = p_0 - 1 }
; 3) Normalized loop induction variables are always non-negative. The domain
;    condition for this is loop
;      { [i0] : i0 >= 0 }
; 4) The intersection of all three sets (condition of executing/entering loop,
;    non-negative induction variables, loop exit condition) is
;      [count, p_0] -> { [i0] : count > 0 and i0 >= 0 and i0 = p_0 - 1 }
; 5) from which ISL can derive
;     [count, p_0] -> { [i0] : p_0 > 0 }
; 6) if.end5 is either executed when skipping the loop
;    (domain [count] -> { [] : count <= 0 })
;    or though the loop.
; 7) Assuming the loop is guaranteed to exit, Polly computes the after-the-loop
;    domain by taking the loop exit condition and projecting-out the induction
;    variable. This yields
;       [count, p_0] -> { [] : count > 0 and p_0 > 0 }
; 8) The disjunction of both cases, 6) and 7)
;    (the two incoming edges of if.end12) is
;      [count, p_0] -> { [] : count <= 0 or (count > 0 and p_0 > 0) }
; 9) Notice that if.end12 is logically _always_ executed in every scop
;    execution. Both cases of if.end5 will eventually land in if.end12

define void @func(i64 %count, i64 %count2, float* %A) {
entry:
  br i1 undef, label %if.end5.preheader, label %for.end

if.end5.preheader:
  %cmp6 = icmp sgt i64 %count, 0
  br label %if.end5

if.end5:
  br i1 %cmp6, label %loop_start, label %if.end12

loop_start:
  %indvars.iv63 = phi i64 [ %indvars.iv.next64, %loop_start ], [ 0, %if.end5 ]
  %add8 = add i32 undef, undef
  store float 0.0, float* %A
  %indvars.iv.next64 = add i64 %indvars.iv63, 1
  %cmp9 = icmp eq i64 %indvars.iv.next64, %count2
  br i1 %cmp9, label %if.end12, label %loop_start

if.end12:
  store float 0.0, float* %A
  br label %for.end

for.end:
  ret void
}


; CHECK:      Statements {
; CHECK-NEXT:     Stmt_if_end12
; CHECK-NEXT:         Domain :=
; CHECK-NEXT:             [count, p_1] -> { Stmt_if_end12[] };
; CHECK-NEXT:         Schedule :=
; CHECK-NEXT:             [count, p_1] -> { Stmt_if_end12[] -> [] };
; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
; CHECK-NEXT:             [count, p_1] -> { Stmt_if_end12[] -> MemRef_A[0] };
; CHECK-NEXT: }
-------------- next part --------------
; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
; RUN: opt %loadPolly -polly-codegen -S < %s

; Bugpoint-reduced from
; test-suite/SingleSource/Benchmarks/Adobe-C++/loop_unroll.cpp
;
; Check that the loop %loop_start does not narrow the domain (the domain when
; entering and leaving the loop must be identical)
;
; What happened in detail:
;
; 1) if.end5 checks %count whether there will be at least one iteration of
;    loop_start. The domain condition added to loop_start therefore is
;      [count] -> { [] : count > 0 }
; 2) The loop exit condition of loop_start tests whether
;    %indvars.iv.next64 == %0 (which is zext i32 %count to i64, NOT %count
;    itself). %0 and %count have to be treated as independent parameters. The
;    loop exit condition is
;      [p_0] -> { [i0] : i0 = p_0 - 1 }
; 3) Normalized loop induction variables are always non-negative. The domain
;    condition for this is loop
;      { [i0] : i0 >= 0 }
; 4) The intersection of all three sets (condition of executing/entering loop,
;    non-negative induction variables, loop exit condition) is
;      [count, p_0] -> { [i0] : count > 0 and i0 >= 0 and i0 = p_0 - 1 }
; 5) from which ISL can derive
;     [count, p_0] -> { [i0] : p_0 > 0 }
; 6) if.end5 is either executed when skipping the loop
;    (domain [count] -> { [] : count <= 0 })
;    or though the loop.
; 7) Assuming the loop is guaranteed to exit, Polly computes the after-the-loop
;    domain by taking the loop exit condition and projecting-out the induction
;    variable. This yields
;       [count, p_0] -> { [] : count > 0 and p_0 > 0 }
; 8) The disjunction of both cases, 6) and 7)
;    (the two incoming edges of if.end12) is
;      [count, p_0] -> { [] : count <= 0 or (count > 0 and p_0 > 0) }
; 9) Notice that if.end12 is logically _always_ executed in every scop
;    execution. Both cases of if.end5 will eventually land in if.end12

define void @func(i64 %count, i64 %count2, float* %A) {
entry:
  br i1 undef, label %if.end5.preheader, label %for.end

if.end5.preheader:
  %cmp6 = icmp sgt i64 %count, 0
  br label %if.end5

if.end5:
  br i1 %cmp6, label %loop_start, label %if.end12

loop_start:
  %indvars.iv63 = phi i64 [ %indvars.iv.next64, %loop_start ], [ 0, %if.end5 ]
  %add8 = add i32 undef, undef
  store float 0.0, float* %A
  %indvars.iv.next64 = add i64 %indvars.iv63, 1
  %cmp9 = icmp sge i64 %indvars.iv.next64, %count2
  br i1 %cmp9, label %if.end12, label %loop_start

if.end12:
  store float 0.0, float* %A
  br label %for.end

for.end:
  ret void
}


; CHECK:      Statements {
; CHECK-NEXT:     Stmt_if_end12
; CHECK-NEXT:         Domain :=
; CHECK-NEXT:             [count, p_1] -> { Stmt_if_end12[] };
; CHECK-NEXT:         Schedule :=
; CHECK-NEXT:             [count, p_1] -> { Stmt_if_end12[] -> [] };
; CHECK-NEXT:         MustWriteAccess :=    [Reduction Type: NONE] [Scalar: 0]
; CHECK-NEXT:             [count, p_1] -> { Stmt_if_end12[] -> MemRef_A[0] };
; CHECK-NEXT: }


More information about the llvm-commits mailing list