llvm-project/polly/test/ScopInfo/complex-loop-nesting.ll

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

72 lines
3.2 KiB
LLVM
Raw Normal View History

; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
[ScopDetect] Reject loop with multiple exit blocks. The current statement domain derivation algorithm does not (always) consider that different exit blocks of a loop can have different conditions to be reached. From the code for (int i = n; ; i-=2) { if (i <= 0) goto even; if (i <= 1) goto odd; A[i] = i; } even: A[0] = 42; return; odd: A[1] = 21; return; Polly currently derives the following domains: Stmt_even_critedge Domain := [n] -> { Stmt_even_critedge[] }; Stmt_odd Domain := [n] -> { Stmt_odd[] : (1 + n) mod 2 = 0 and n > 0 }; while the domain for the odd case is correct, Stmt_even is assumed to be executed unconditionally, which is obviously wrong. While projecting out the loop dimension in `adjustDomainDimensions`, it does not consider that there are other exit condition that have matched before. I don't know a how to fix this without changing a lot of code. Therefore This patch rejects loops with multiple exist blocks to fix the miscompile of test-suite's uuencode. The odd condition is transformed by LLVM to %cmp1 = icmp eq i64 %indvars.iv, 1 such that the project_out in adjustDomainDimensions() indeed only matches for odd n (using this condition only, we'd have an infinite loop otherwise). The even condition manifests as %cmp = icmp slt i64 %indvars.iv, 3 Because buildDomainsWithBranchConstraints() does not consider other exit conditions, it has to assume that the induction variable will eventually be lower than 3 and taking this exit. IMHO we need to reuse the algorithm that determines the number of iterations (addLoopBoundsToHeaderDomain) to determine which exit condition applies first. It has to happen in buildDomainsWithBranchConstraints() because the result will need to propagate to successor BBs. Currently addLoopBoundsToHeaderDomain() just look for union of all backedge conditions (which means leaving not the loop here). The patch in llvm.org/PR35465 changes it to look for exit conditions instead. This is required because there might be other exit conditions that do not alternatively go back to the loop header. Differential Revision: https://reviews.llvm.org/D45649 llvm-svn: 330858
2018-04-26 02:53:33 +08:00
;
; The SCoP contains a loop with multiple exit blocks (BBs after leaving
; the loop). The current implementation of deriving their domain derives
; only a common domain for all of the exit blocks. We disabled loops with
; multiple exit blocks until this is fixed.
; XFAIL: *
;
; CHECK: Statements {
; CHECK-NEXT: Stmt_for_body_outer
; CHECK-NEXT: Domain :=
2016-01-15 23:54:45 +08:00
; CHECK-NEXT: { Stmt_for_body_outer[i0] : 0 <= i0 <= 257 };
; CHECK-NEXT: Schedule :=
; CHECK-NEXT: { Stmt_for_body_outer[i0] -> [i0, 0, 0, 0] };
; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
; CHECK-NEXT: { Stmt_for_body_outer[i0] -> MemRef_A[i0] };
; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0]
; CHECK-NEXT: { Stmt_for_body_outer[i0] -> MemRef_A[i0] };
; CHECK-NEXT: Stmt_for_body
; CHECK-NEXT: Domain :=
2016-01-15 23:54:45 +08:00
; CHECK-NEXT: { Stmt_for_body[257, i1] : 0 <= i1 <= 1025; Stmt_for_body[i0, 0] : 0 <= i0 <= 256 };
; CHECK-NEXT: Schedule :=
; CHECK-NEXT: { Stmt_for_body[257, i1] -> [257, 1, i1, 0]; Stmt_for_body[i0, 0] -> [i0, 1, 0, 0] : i0 <= 256 };
; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
; CHECK-NEXT: { Stmt_for_body[i0, i1] -> MemRef_A[i1] };
; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0]
; CHECK-NEXT: { Stmt_for_body[i0, i1] -> MemRef_A[i1] };
; CHECK-NEXT: Stmt_for_inc
; CHECK-NEXT: Domain :=
2016-01-15 23:54:45 +08:00
; CHECK-NEXT: { Stmt_for_inc[257, i1] : 0 <= i1 <= 1025 };
; CHECK-NEXT: Schedule :=
; CHECK-NEXT: { Stmt_for_inc[i0, i1] -> [257, 1, i1, 1] };
; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
; CHECK-NEXT: { Stmt_for_inc[i0, i1] -> MemRef_A[i1] };
; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0]
; CHECK-NEXT: { Stmt_for_inc[i0, i1] -> MemRef_A[i1] };
; CHECK-NEXT: }
target datalayout = "e-m:e-i64:64-i128:128-n8:16:32:64-S128"
define void @foo(i32* %A) {
entry:
br label %for.body.outer
for.body.outer: ; preds = %for.body, %entry
%indvar = phi i32 [0, %entry], [%indvar.next, %for.body]
%addr = getelementptr i32, i32* %A, i32 %indvar
%val = load i32, i32* %addr
%indvar.next = add i32 %indvar, 1
store i32 %val, i32* %addr
br label %for.body
for.body: ; preds = %for.inc, %for.body.outer
%indvar.2 = phi i32 [0, %for.body.outer], [%indvar.2.next, %for.inc]
%addr.2 = getelementptr i32, i32* %A, i32 %indvar.2
%val.2 = load i32, i32* %addr.2
%indvar.2.next = add i32 %indvar.2, 1
store i32 %val.2, i32* %addr.2
%cond.1 = icmp sle i32 %indvar, 256
br i1 %cond.1, label %for.body.outer, label %for.inc
for.inc: ; preds = %for.body
%addr.3 = getelementptr i32, i32* %A, i32 %indvar.2
%val.3 = load i32, i32* %addr.3
store i32 %val.3, i32* %addr.3
%cond = icmp sle i32 %indvar.2, 1024
br i1 %cond, label %for.body, label %for.end
for.end: ; preds = %for.inc
ret void
}