mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 03:33:20 +01:00
05c5b8d72c
When legal, extending trip count in the loop control logic generates better code compared to truncating IV. This is because (1) extending trip count is a loop invariant operation (see genLoopLimit where we prove trip count is loop invariant). (2) Scalar Evolution seems to have problems understanding trunc when computing loop trip count. So removing them allows better analysis performed in Scalar Evolution. (In particular this fixes PR 28363 which is the motivation for this change). I am not going to perform any performance test. Any degradation caused by this should be an indication of a bug elsewhere. To prove legality, we rely on SCEV to prove zext(trunc(IV)) == IV (or similarly for sext). If this holds, we can prove equivalence of trunc(IV)==ExitCnt (1) and IV == zext(ExitCnt). Simply take zext of boths sides of (1) and apply the proven equivalence. This commit contains changes in a newly added testcase which was not included in the previous commit (which was reverted later on). https://reviews.llvm.org/D23075 llvm-svn: 278421
156 lines
4.8 KiB
LLVM
156 lines
4.8 KiB
LLVM
; RUN: opt < %s -indvars -S | FileCheck %s
|
|
|
|
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-n8:16:32:64"
|
|
|
|
; IV with constant start, preinc and postinc sign extends, with and without NSW.
|
|
; IV rewrite only removes one sext. WidenIVs removes all three.
|
|
define void @postincConstIV(i8* %base, i32 %limit) nounwind {
|
|
entry:
|
|
br label %loop
|
|
; CHECK: loop:
|
|
; CHECK-NOT: sext
|
|
; CHECK: exit:
|
|
loop:
|
|
%iv = phi i32 [ %postiv, %loop ], [ 0, %entry ]
|
|
%ivnsw = phi i32 [ %postivnsw, %loop ], [ 0, %entry ]
|
|
%preofs = sext i32 %iv to i64
|
|
%preadr = getelementptr i8, i8* %base, i64 %preofs
|
|
store i8 0, i8* %preadr
|
|
%postiv = add i32 %iv, 1
|
|
%postofs = sext i32 %postiv to i64
|
|
%postadr = getelementptr i8, i8* %base, i64 %postofs
|
|
store i8 0, i8* %postadr
|
|
%postivnsw = add nsw i32 %ivnsw, 1
|
|
%postofsnsw = sext i32 %postivnsw to i64
|
|
%postadrnsw = getelementptr inbounds i8, i8* %base, i64 %postofsnsw
|
|
store i8 0, i8* %postadrnsw
|
|
%cond = icmp sgt i32 %limit, %iv
|
|
br i1 %cond, label %loop, label %exit
|
|
exit:
|
|
br label %return
|
|
return:
|
|
ret void
|
|
}
|
|
|
|
; IV with nonconstant start, preinc and postinc sign extends,
|
|
; with and without NSW.
|
|
; As with postincConstIV, WidenIVs removes all three sexts.
|
|
define void @postincVarIV(i8* %base, i32 %init, i32 %limit) nounwind {
|
|
entry:
|
|
%precond = icmp sgt i32 %limit, %init
|
|
br i1 %precond, label %loop, label %return
|
|
; CHECK: loop:
|
|
; CHECK-NOT: sext
|
|
; CHECK: wide.trip.count = sext
|
|
; CHECK-NOT: sext
|
|
; CHECK: exit:
|
|
loop:
|
|
%iv = phi i32 [ %postiv, %loop ], [ %init, %entry ]
|
|
%ivnsw = phi i32 [ %postivnsw, %loop ], [ %init, %entry ]
|
|
%preofs = sext i32 %iv to i64
|
|
%preadr = getelementptr i8, i8* %base, i64 %preofs
|
|
store i8 0, i8* %preadr
|
|
%postiv = add i32 %iv, 1
|
|
%postofs = sext i32 %postiv to i64
|
|
%postadr = getelementptr i8, i8* %base, i64 %postofs
|
|
store i8 0, i8* %postadr
|
|
%postivnsw = add nsw i32 %ivnsw, 1
|
|
%postofsnsw = sext i32 %postivnsw to i64
|
|
%postadrnsw = getelementptr i8, i8* %base, i64 %postofsnsw
|
|
store i8 0, i8* %postadrnsw
|
|
%cond = icmp sgt i32 %limit, %postiv
|
|
br i1 %cond, label %loop, label %exit
|
|
exit:
|
|
br label %return
|
|
return:
|
|
ret void
|
|
}
|
|
|
|
; Test sign extend elimination in the inner and outer loop.
|
|
; %outercount is straightforward to widen, besides being in an outer loop.
|
|
; %innercount is currently blocked by lcssa, so is not widened.
|
|
; %inneriv can be widened only after proving it has no signed-overflow
|
|
; based on the loop test.
|
|
define void @nestedIV(i8* %address, i32 %limit) nounwind {
|
|
entry:
|
|
%limitdec = add i32 %limit, -1
|
|
br label %outerloop
|
|
|
|
; CHECK: outerloop:
|
|
;
|
|
; Eliminate %ofs1 after widening outercount.
|
|
; CHECK-NOT: sext
|
|
; CHECK: getelementptr
|
|
;
|
|
; IV rewriting hoists a gep into this block. We don't like that.
|
|
; CHECK-NOT: getelementptr
|
|
outerloop:
|
|
%outercount = phi i32 [ %outerpostcount, %outermerge ], [ 0, %entry ]
|
|
%innercount = phi i32 [ %innercount.merge, %outermerge ], [ 0, %entry ]
|
|
|
|
%outercountdec = add i32 %outercount, -1
|
|
%ofs1 = sext i32 %outercountdec to i64
|
|
%adr1 = getelementptr i8, i8* %address, i64 %ofs1
|
|
store i8 0, i8* %adr1
|
|
|
|
br label %innerpreheader
|
|
|
|
innerpreheader:
|
|
%innerprecmp = icmp sgt i32 %limitdec, %innercount
|
|
br i1 %innerprecmp, label %innerloop, label %outermerge
|
|
|
|
; CHECK: innerloop:
|
|
;
|
|
; Eliminate %ofs2 after widening inneriv.
|
|
; Eliminate %ofs3 after normalizing sext(innerpostiv)
|
|
; CHECK-NOT: sext
|
|
; CHECK: getelementptr
|
|
;
|
|
; FIXME: We should check that indvars does not increase the number of
|
|
; IVs in this loop. sext elimination plus LFTR currently results in 2 final
|
|
; IVs. Waiting to remove LFTR.
|
|
innerloop:
|
|
%inneriv = phi i32 [ %innerpostiv, %innerloop ], [ %innercount, %innerpreheader ]
|
|
%innerpostiv = add i32 %inneriv, 1
|
|
|
|
%ofs2 = sext i32 %inneriv to i64
|
|
%adr2 = getelementptr i8, i8* %address, i64 %ofs2
|
|
store i8 0, i8* %adr2
|
|
|
|
%ofs3 = sext i32 %innerpostiv to i64
|
|
%adr3 = getelementptr i8, i8* %address, i64 %ofs3
|
|
store i8 0, i8* %adr3
|
|
|
|
%innercmp = icmp sgt i32 %limitdec, %innerpostiv
|
|
br i1 %innercmp, label %innerloop, label %innerexit
|
|
|
|
innerexit:
|
|
%innercount.lcssa = phi i32 [ %innerpostiv, %innerloop ]
|
|
br label %outermerge
|
|
|
|
; CHECK: outermerge:
|
|
;
|
|
; Eliminate %ofs4 after widening outercount
|
|
; CHECK-NOT: sext
|
|
; CHECK: getelementptr
|
|
;
|
|
; TODO: Eliminate %ofs5 after removing lcssa
|
|
outermerge:
|
|
%innercount.merge = phi i32 [ %innercount.lcssa, %innerexit ], [ %innercount, %innerpreheader ]
|
|
|
|
%ofs4 = sext i32 %outercount to i64
|
|
%adr4 = getelementptr i8, i8* %address, i64 %ofs4
|
|
store i8 0, i8* %adr4
|
|
|
|
%ofs5 = sext i32 %innercount.merge to i64
|
|
%adr5 = getelementptr i8, i8* %address, i64 %ofs5
|
|
store i8 0, i8* %adr5
|
|
|
|
%outerpostcount = add i32 %outercount, 1
|
|
%tmp47 = icmp slt i32 %outerpostcount, %limit
|
|
br i1 %tmp47, label %outerloop, label %return
|
|
|
|
return:
|
|
ret void
|
|
}
|