mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 12:12:47 +01:00
eb30ce19c4
These intrinsics, not the icmp+select are the canonical form nowadays, so we might as well directly emit them. This should not cause any regressions, but if it does, then then they would needed to be fixed regardless. Note that this doesn't deal with `SCEVExpander::isHighCostExpansion()`, but that is a pessimization, not a correctness issue. Additionally, the non-intrinsic form has issues with undef, see https://reviews.llvm.org/D88287#2587863
531 lines
19 KiB
LLVM
531 lines
19 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt < %s -indvars -S -indvars-predicate-loops=0 | FileCheck %s
|
|
;
|
|
; Make sure that indvars isn't inserting canonical IVs.
|
|
; This is kinda hard to do until linear function test replacement is removed.
|
|
|
|
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"
|
|
|
|
; We should only have 2 IVs.
|
|
; sext should be eliminated while preserving gep inboundsness.
|
|
define i32 @sum(i32* %arr, i32 %n) nounwind {
|
|
; CHECK-LABEL: @sum(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[PRECOND:%.*]] = icmp slt i32 0, [[N:%.*]]
|
|
; CHECK-NEXT: br i1 [[PRECOND]], label [[PH:%.*]], label [[RETURN:%.*]]
|
|
; CHECK: ph:
|
|
; CHECK-NEXT: [[WIDE_TRIP_COUNT:%.*]] = zext i32 [[N]] to i64
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], [[LOOP]] ], [ 0, [[PH]] ]
|
|
; CHECK-NEXT: [[S_01:%.*]] = phi i32 [ 0, [[PH]] ], [ [[SINC:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[ADR:%.*]] = getelementptr inbounds i32, i32* [[ARR:%.*]], i64 [[INDVARS_IV]]
|
|
; CHECK-NEXT: [[VAL:%.*]] = load i32, i32* [[ADR]], align 4
|
|
; CHECK-NEXT: [[SINC]] = add nsw i32 [[S_01]], [[VAL]]
|
|
; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT]], [[WIDE_TRIP_COUNT]]
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: [[S_LCSSA:%.*]] = phi i32 [ [[SINC]], [[LOOP]] ]
|
|
; CHECK-NEXT: br label [[RETURN]]
|
|
; CHECK: return:
|
|
; CHECK-NEXT: [[S_0_LCSSA:%.*]] = phi i32 [ [[S_LCSSA]], [[EXIT]] ], [ 0, [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: ret i32 [[S_0_LCSSA]]
|
|
;
|
|
entry:
|
|
%precond = icmp slt i32 0, %n
|
|
br i1 %precond, label %ph, label %return
|
|
|
|
ph:
|
|
br label %loop
|
|
|
|
loop:
|
|
%i.02 = phi i32 [ 0, %ph ], [ %iinc, %loop ]
|
|
%s.01 = phi i32 [ 0, %ph ], [ %sinc, %loop ]
|
|
%ofs = sext i32 %i.02 to i64
|
|
%adr = getelementptr inbounds i32, i32* %arr, i64 %ofs
|
|
%val = load i32, i32* %adr
|
|
%sinc = add nsw i32 %s.01, %val
|
|
%iinc = add nsw i32 %i.02, 1
|
|
%cond = icmp slt i32 %iinc, %n
|
|
br i1 %cond, label %loop, label %exit
|
|
|
|
exit:
|
|
%s.lcssa = phi i32 [ %sinc, %loop ]
|
|
br label %return
|
|
|
|
return:
|
|
%s.0.lcssa = phi i32 [ %s.lcssa, %exit ], [ 0, %entry ]
|
|
ret i32 %s.0.lcssa
|
|
}
|
|
|
|
; We should only have 2 IVs.
|
|
; %ofs sext should be eliminated while preserving gep inboundsness.
|
|
; %vall sext should obviously not be eliminated
|
|
define i64 @suml(i32* %arr, i32 %n) nounwind {
|
|
; CHECK-LABEL: @suml(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[PRECOND:%.*]] = icmp slt i32 0, [[N:%.*]]
|
|
; CHECK-NEXT: br i1 [[PRECOND]], label [[PH:%.*]], label [[RETURN:%.*]]
|
|
; CHECK: ph:
|
|
; CHECK-NEXT: [[WIDE_TRIP_COUNT:%.*]] = zext i32 [[N]] to i64
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], [[LOOP]] ], [ 0, [[PH]] ]
|
|
; CHECK-NEXT: [[S_01:%.*]] = phi i64 [ 0, [[PH]] ], [ [[SINC:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[ADR:%.*]] = getelementptr inbounds i32, i32* [[ARR:%.*]], i64 [[INDVARS_IV]]
|
|
; CHECK-NEXT: [[VAL:%.*]] = load i32, i32* [[ADR]], align 4
|
|
; CHECK-NEXT: [[VALL:%.*]] = sext i32 [[VAL]] to i64
|
|
; CHECK-NEXT: [[SINC]] = add nsw i64 [[S_01]], [[VALL]]
|
|
; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT]], [[WIDE_TRIP_COUNT]]
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: [[S_LCSSA:%.*]] = phi i64 [ [[SINC]], [[LOOP]] ]
|
|
; CHECK-NEXT: br label [[RETURN]]
|
|
; CHECK: return:
|
|
; CHECK-NEXT: [[S_0_LCSSA:%.*]] = phi i64 [ [[S_LCSSA]], [[EXIT]] ], [ 0, [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: ret i64 [[S_0_LCSSA]]
|
|
;
|
|
entry:
|
|
%precond = icmp slt i32 0, %n
|
|
br i1 %precond, label %ph, label %return
|
|
|
|
ph:
|
|
br label %loop
|
|
|
|
loop:
|
|
%i.02 = phi i32 [ 0, %ph ], [ %iinc, %loop ]
|
|
%s.01 = phi i64 [ 0, %ph ], [ %sinc, %loop ]
|
|
%ofs = sext i32 %i.02 to i64
|
|
%adr = getelementptr inbounds i32, i32* %arr, i64 %ofs
|
|
%val = load i32, i32* %adr
|
|
%vall = sext i32 %val to i64
|
|
%sinc = add nsw i64 %s.01, %vall
|
|
%iinc = add nsw i32 %i.02, 1
|
|
%cond = icmp slt i32 %iinc, %n
|
|
br i1 %cond, label %loop, label %exit
|
|
|
|
exit:
|
|
%s.lcssa = phi i64 [ %sinc, %loop ]
|
|
br label %return
|
|
|
|
return:
|
|
%s.0.lcssa = phi i64 [ %s.lcssa, %exit ], [ 0, %entry ]
|
|
ret i64 %s.0.lcssa
|
|
}
|
|
|
|
; It's not indvars' job to perform LICM on %ofs
|
|
; Preserve exactly one pointer type IV.
|
|
; Don't create any extra adds.
|
|
; Preserve gep inboundsness, and don't factor it.
|
|
define void @outofbounds(i32* %first, i32* %last, i32 %idx) nounwind {
|
|
; CHECK-LABEL: @outofbounds(
|
|
; CHECK-NEXT: [[PRECOND:%.*]] = icmp ne i32* [[FIRST:%.*]], [[LAST:%.*]]
|
|
; CHECK-NEXT: br i1 [[PRECOND]], label [[PH:%.*]], label [[RETURN:%.*]]
|
|
; CHECK: ph:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[PTRIV:%.*]] = phi i32* [ [[FIRST]], [[PH]] ], [ [[PTRPOST:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[OFS:%.*]] = sext i32 [[IDX:%.*]] to i64
|
|
; CHECK-NEXT: [[ADR:%.*]] = getelementptr inbounds i32, i32* [[PTRIV]], i64 [[OFS]]
|
|
; CHECK-NEXT: store i32 3, i32* [[ADR]], align 4
|
|
; CHECK-NEXT: [[PTRPOST]] = getelementptr inbounds i32, i32* [[PTRIV]], i32 1
|
|
; CHECK-NEXT: [[COND:%.*]] = icmp ne i32* [[PTRPOST]], [[LAST]]
|
|
; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: br label [[RETURN]]
|
|
; CHECK: return:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%precond = icmp ne i32* %first, %last
|
|
br i1 %precond, label %ph, label %return
|
|
|
|
ph:
|
|
br label %loop
|
|
|
|
loop:
|
|
%ptriv = phi i32* [ %first, %ph ], [ %ptrpost, %loop ]
|
|
%ofs = sext i32 %idx to i64
|
|
%adr = getelementptr inbounds i32, i32* %ptriv, i64 %ofs
|
|
store i32 3, i32* %adr
|
|
%ptrpost = getelementptr inbounds i32, i32* %ptriv, i32 1
|
|
%cond = icmp ne i32* %ptrpost, %last
|
|
br i1 %cond, label %loop, label %exit
|
|
|
|
exit:
|
|
br label %return
|
|
|
|
return:
|
|
ret void
|
|
}
|
|
|
|
%structI = type { i32 }
|
|
|
|
; Preserve casts
|
|
define void @bitcastiv(i32 %start, i32 %limit, i32 %step, %structI* %base)
|
|
; CHECK-LABEL: @bitcastiv(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[NEXT:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[P:%.*]] = phi %structI* [ [[BASE:%.*]], [[ENTRY]] ], [ [[PINC:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[ADR:%.*]] = getelementptr [[STRUCTI:%.*]], %structI* [[P]], i32 0, i32 0
|
|
; CHECK-NEXT: store i32 3, i32* [[ADR]], align 4
|
|
; CHECK-NEXT: [[PP:%.*]] = bitcast %structI* [[P]] to i32*
|
|
; CHECK-NEXT: store i32 4, i32* [[PP]], align 4
|
|
; CHECK-NEXT: [[PINC]] = getelementptr [[STRUCTI]], %structI* [[P]], i32 1
|
|
; CHECK-NEXT: [[NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: [[COND:%.*]] = icmp ne i32 [[NEXT]], [[LIMIT:%.*]]
|
|
; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
nounwind
|
|
{
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [%start, %entry], [%next, %loop]
|
|
%p = phi %structI* [%base, %entry], [%pinc, %loop]
|
|
%adr = getelementptr %structI, %structI* %p, i32 0, i32 0
|
|
store i32 3, i32* %adr
|
|
%pp = bitcast %structI* %p to i32*
|
|
store i32 4, i32* %pp
|
|
%pinc = getelementptr %structI, %structI* %p, i32 1
|
|
%next = add i32 %iv, 1
|
|
%cond = icmp ne i32 %next, %limit
|
|
br i1 %cond, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Test inserting a truncate at a phi use.
|
|
define void @maxvisitor(i32 %limit, i32* %base) nounwind {
|
|
; CHECK-LABEL: @maxvisitor(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[LIMIT:%.*]], i32 1)
|
|
; CHECK-NEXT: [[WIDE_TRIP_COUNT:%.*]] = zext i32 [[SMAX]] to i64
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], [[LOOP_INC:%.*]] ], [ 0, [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: [[MAX:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[MAX_NEXT:%.*]], [[LOOP_INC]] ]
|
|
; CHECK-NEXT: [[ADR:%.*]] = getelementptr inbounds i32, i32* [[BASE:%.*]], i64 [[INDVARS_IV]]
|
|
; CHECK-NEXT: [[VAL:%.*]] = load i32, i32* [[ADR]], align 4
|
|
; CHECK-NEXT: [[CMP19:%.*]] = icmp sgt i32 [[VAL]], [[MAX]]
|
|
; CHECK-NEXT: br i1 [[CMP19]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
|
|
; CHECK: if.then:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = trunc i64 [[INDVARS_IV]] to i32
|
|
; CHECK-NEXT: br label [[LOOP_INC]]
|
|
; CHECK: if.else:
|
|
; CHECK-NEXT: br label [[LOOP_INC]]
|
|
; CHECK: loop.inc:
|
|
; CHECK-NEXT: [[MAX_NEXT]] = phi i32 [ [[TMP0]], [[IF_THEN]] ], [ [[MAX]], [[IF_ELSE]] ]
|
|
; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT]], [[WIDE_TRIP_COUNT]]
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%idx = phi i32 [ 0, %entry ], [ %idx.next, %loop.inc ]
|
|
%max = phi i32 [ 0, %entry ], [ %max.next, %loop.inc ]
|
|
%idxprom = sext i32 %idx to i64
|
|
%adr = getelementptr inbounds i32, i32* %base, i64 %idxprom
|
|
%val = load i32, i32* %adr
|
|
%cmp19 = icmp sgt i32 %val, %max
|
|
br i1 %cmp19, label %if.then, label %if.else
|
|
|
|
if.then:
|
|
br label %loop.inc
|
|
|
|
if.else:
|
|
br label %loop.inc
|
|
|
|
loop.inc:
|
|
%max.next = phi i32 [ %idx, %if.then ], [ %max, %if.else ]
|
|
%idx.next = add nsw i32 %idx, 1
|
|
%cmp = icmp slt i32 %idx.next, %limit
|
|
br i1 %cmp, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Test an edge case of removing an identity phi that directly feeds
|
|
; back to the loop iv.
|
|
define void @identityphi(i32 %limit) nounwind {
|
|
; CHECK-LABEL: @identityphi(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: br i1 undef, label [[IF_THEN:%.*]], label [[CONTROL:%.*]]
|
|
; CHECK: if.then:
|
|
; CHECK-NEXT: br label [[CONTROL]]
|
|
; CHECK: control:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[LIMIT:%.*]]
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [ 0, %entry], [ %iv.next, %control ]
|
|
br i1 undef, label %if.then, label %control
|
|
|
|
if.then:
|
|
br label %control
|
|
|
|
control:
|
|
%iv.next = phi i32 [ %iv, %loop ], [ undef, %if.then ]
|
|
%cmp = icmp slt i32 %iv.next, %limit
|
|
br i1 %cmp, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Test cloning an or, which is not an OverflowBinaryOperator.
|
|
define i64 @cloneOr(i32 %limit, i64* %base) nounwind {
|
|
; CHECK-LABEL: @cloneOr(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[HALFLIM:%.*]] = ashr i32 [[LIMIT:%.*]], 2
|
|
; CHECK-NEXT: [[TMP0:%.*]] = sext i32 [[HALFLIM]] to i64
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], [[LOOP]] ], [ 0, [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: [[ADR:%.*]] = getelementptr i64, i64* [[BASE:%.*]], i64 [[INDVARS_IV]]
|
|
; CHECK-NEXT: [[VAL:%.*]] = load i64, i64* [[ADR]], align 8
|
|
; CHECK-NEXT: [[TMP1:%.*]] = or i64 [[INDVARS_IV]], 1
|
|
; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 2
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[INDVARS_IV_NEXT]], [[TMP0]]
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: [[VAL_LCSSA:%.*]] = phi i64 [ [[VAL]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[T3_LCSSA:%.*]] = phi i64 [ [[TMP1]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[RESULT:%.*]] = and i64 [[VAL_LCSSA]], [[T3_LCSSA]]
|
|
; CHECK-NEXT: ret i64 [[RESULT]]
|
|
;
|
|
entry:
|
|
; ensure that the loop can't overflow
|
|
%halfLim = ashr i32 %limit, 2
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [ 0, %entry], [ %iv.next, %loop ]
|
|
%t1 = sext i32 %iv to i64
|
|
%adr = getelementptr i64, i64* %base, i64 %t1
|
|
%val = load i64, i64* %adr
|
|
%t2 = or i32 %iv, 1
|
|
%t3 = sext i32 %t2 to i64
|
|
%iv.next = add i32 %iv, 2
|
|
%cmp = icmp slt i32 %iv.next, %halfLim
|
|
br i1 %cmp, label %loop, label %exit
|
|
|
|
exit:
|
|
%result = and i64 %val, %t3
|
|
ret i64 %result
|
|
}
|
|
|
|
; The i induction variable looks like a wrap-around, but it really is just
|
|
; a simple affine IV. Make sure that indvars simplifies through.
|
|
; ReplaceLoopExitValue should fold the return value to constant 9.
|
|
define i32 @indirectRecurrence() nounwind {
|
|
; CHECK-LABEL: @indirectRecurrence(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[J_0:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ [[J_NEXT:%.*]], [[COND_TRUE:%.*]] ]
|
|
; CHECK-NEXT: [[TMP:%.*]] = icmp ne i32 [[J_0]], 10
|
|
; CHECK-NEXT: br i1 [[TMP]], label [[COND_TRUE]], label [[RETURN:%.*]]
|
|
; CHECK: cond_true:
|
|
; CHECK-NEXT: [[J_NEXT]] = add nuw nsw i32 [[J_0]], 1
|
|
; CHECK-NEXT: br label [[LOOP]]
|
|
; CHECK: return:
|
|
; CHECK-NEXT: ret i32 9
|
|
;
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%j.0 = phi i32 [ 1, %entry ], [ %j.next, %cond_true ]
|
|
%i.0 = phi i32 [ 0, %entry ], [ %j.0, %cond_true ]
|
|
%tmp = icmp ne i32 %j.0, 10
|
|
br i1 %tmp, label %cond_true, label %return
|
|
|
|
cond_true:
|
|
%j.next = add i32 %j.0, 1
|
|
br label %loop
|
|
|
|
return:
|
|
ret i32 %i.0
|
|
}
|
|
|
|
; Eliminate the congruent phis j, k, and l.
|
|
; Eliminate the redundant IV increments k.next and l.next.
|
|
; Two phis should remain, one starting at %init, and one at %init1.
|
|
; Two increments should remain, one by %step and one by %step1.
|
|
; Five live-outs should remain.
|
|
define i32 @isomorphic(i32 %init, i32 %step, i32 %lim) nounwind {
|
|
; CHECK-LABEL: @isomorphic(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[STEP1:%.*]] = add i32 [[STEP:%.*]], 1
|
|
; CHECK-NEXT: [[INIT1:%.*]] = add i32 [[INIT:%.*]], [[STEP1]]
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[II:%.*]] = phi i32 [ [[INIT1]], [[ENTRY:%.*]] ], [ [[II_NEXT:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[J:%.*]] = phi i32 [ [[INIT]], [[ENTRY]] ], [ [[J_NEXT:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[II_NEXT]] = add i32 [[II]], [[STEP1]]
|
|
; CHECK-NEXT: [[J_NEXT]] = add i32 [[J]], [[STEP1]]
|
|
; CHECK-NEXT: [[L_STEP:%.*]] = add i32 [[J]], [[STEP]]
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[II_NEXT]], [[LIM:%.*]]
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[LOOP]], label [[RETURN:%.*]]
|
|
; CHECK: return:
|
|
; CHECK-NEXT: [[I_LCSSA:%.*]] = phi i32 [ [[J]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[J_NEXT_LCSSA:%.*]] = phi i32 [ [[J_NEXT]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[K_NEXT_LCSSA:%.*]] = phi i32 [ [[II_NEXT]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[L_STEP_LCSSA:%.*]] = phi i32 [ [[L_STEP]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[L_NEXT_LCSSA:%.*]] = phi i32 [ [[J_NEXT]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[SUM1:%.*]] = add i32 [[I_LCSSA]], [[J_NEXT_LCSSA]]
|
|
; CHECK-NEXT: [[SUM2:%.*]] = add i32 [[SUM1]], [[K_NEXT_LCSSA]]
|
|
; CHECK-NEXT: [[SUM3:%.*]] = add i32 [[SUM1]], [[L_STEP_LCSSA]]
|
|
; CHECK-NEXT: [[SUM4:%.*]] = add i32 [[SUM1]], [[L_NEXT_LCSSA]]
|
|
; CHECK-NEXT: ret i32 [[SUM4]]
|
|
;
|
|
entry:
|
|
%step1 = add i32 %step, 1
|
|
%init1 = add i32 %init, %step1
|
|
%l.0 = sub i32 %init1, %step1
|
|
br label %loop
|
|
|
|
loop:
|
|
%ii = phi i32 [ %init1, %entry ], [ %ii.next, %loop ]
|
|
%i = phi i32 [ %init, %entry ], [ %ii, %loop ]
|
|
%j = phi i32 [ %init, %entry ], [ %j.next, %loop ]
|
|
%k = phi i32 [ %init1, %entry ], [ %k.next, %loop ]
|
|
%l = phi i32 [ %l.0, %entry ], [ %l.next, %loop ]
|
|
%ii.next = add i32 %ii, %step1
|
|
%j.next = add i32 %j, %step1
|
|
%k.next = add i32 %k, %step1
|
|
%l.step = add i32 %l, %step
|
|
%l.next = add i32 %l.step, 1
|
|
%cmp = icmp ne i32 %ii.next, %lim
|
|
br i1 %cmp, label %loop, label %return
|
|
|
|
return:
|
|
%sum1 = add i32 %i, %j.next
|
|
%sum2 = add i32 %sum1, %k.next
|
|
%sum3 = add i32 %sum1, %l.step
|
|
%sum4 = add i32 %sum1, %l.next
|
|
ret i32 %sum4
|
|
}
|
|
|
|
; Test a GEP IV that is derived from another GEP IV by a nop gep that
|
|
; lowers the type without changing the expression.
|
|
%structIF = type { i32, float }
|
|
|
|
define void @congruentgepiv(%structIF* %base) nounwind uwtable ssp {
|
|
; CHECK-LABEL: @congruentgepiv(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[PTR_IV:%.*]] = phi %structIF* [ [[PTR_INC:%.*]], [[LATCH:%.*]] ], [ [[BASE:%.*]], [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: [[INDVARS1:%.*]] = bitcast %structIF* [[PTR_IV]] to i32*
|
|
; CHECK-NEXT: store i32 4, i32* [[INDVARS1]], align 4
|
|
; CHECK-NEXT: br i1 false, label [[LATCH]], label [[EXIT:%.*]]
|
|
; CHECK: latch:
|
|
; CHECK-NEXT: [[PTR_INC]] = getelementptr inbounds [[STRUCTIF:%.*]], %structIF* [[PTR_IV]], i64 1
|
|
; CHECK-NEXT: br label [[LOOP]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%first = getelementptr inbounds %structIF, %structIF* %base, i64 0, i32 0
|
|
br label %loop
|
|
|
|
loop:
|
|
%ptr.iv = phi %structIF* [ %ptr.inc, %latch ], [ %base, %entry ]
|
|
%next = phi i32* [ %next.inc, %latch ], [ %first, %entry ]
|
|
store i32 4, i32* %next
|
|
br i1 undef, label %latch, label %exit
|
|
|
|
latch: ; preds = %for.inc50.i
|
|
%ptr.inc = getelementptr inbounds %structIF, %structIF* %ptr.iv, i64 1
|
|
%next.inc = getelementptr inbounds %structIF, %structIF* %ptr.inc, i64 0, i32 0
|
|
br label %loop
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
declare void @use32(i32 %x)
|
|
declare void @use64(i64 %x)
|
|
|
|
; Test a widened IV that is used by a phi on different paths within the loop.
|
|
define void @phiUsesTrunc() nounwind {
|
|
; CHECK-LABEL: @phiUsesTrunc(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 undef, label [[FOR_BODY_PREHEADER:%.*]], label [[FOR_END:%.*]]
|
|
; CHECK: for.body.preheader:
|
|
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
|
|
; CHECK: for.body:
|
|
; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ 1, [[FOR_BODY_PREHEADER]] ], [ [[INDVARS_IV_NEXT:%.*]], [[FOR_INC:%.*]] ]
|
|
; CHECK-NEXT: [[TMP0:%.*]] = trunc i64 [[INDVARS_IV]] to i32
|
|
; CHECK-NEXT: br i1 undef, label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
|
|
; CHECK: if.then:
|
|
; CHECK-NEXT: br i1 undef, label [[IF_THEN33:%.*]], label [[FOR_INC]]
|
|
; CHECK: if.then33:
|
|
; CHECK-NEXT: br label [[FOR_INC]]
|
|
; CHECK: if.else:
|
|
; CHECK-NEXT: br i1 undef, label [[IF_THEN97:%.*]], label [[FOR_INC]]
|
|
; CHECK: if.then97:
|
|
; CHECK-NEXT: call void @use64(i64 [[INDVARS_IV]])
|
|
; CHECK-NEXT: br label [[FOR_INC]]
|
|
; CHECK: for.inc:
|
|
; CHECK-NEXT: [[KMIN_1:%.*]] = phi i32 [ [[TMP0]], [[IF_THEN33]] ], [ 0, [[IF_THEN]] ], [ [[TMP0]], [[IF_THEN97]] ], [ 0, [[IF_ELSE]] ]
|
|
; CHECK-NEXT: call void @use32(i32 [[KMIN_1]])
|
|
; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
|
|
; CHECK-NEXT: br i1 false, label [[FOR_BODY]], label [[FOR_END_LOOPEXIT:%.*]]
|
|
; CHECK: for.end.loopexit:
|
|
; CHECK-NEXT: br label [[FOR_END]]
|
|
; CHECK: for.end:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br i1 undef, label %for.body, label %for.end
|
|
|
|
for.body:
|
|
%iv = phi i32 [ %inc, %for.inc ], [ 1, %entry ]
|
|
br i1 undef, label %if.then, label %if.else
|
|
|
|
if.then:
|
|
br i1 undef, label %if.then33, label %for.inc
|
|
|
|
if.then33:
|
|
br label %for.inc
|
|
|
|
if.else:
|
|
br i1 undef, label %if.then97, label %for.inc
|
|
|
|
if.then97:
|
|
%idxprom100 = sext i32 %iv to i64
|
|
call void @use64(i64 %idxprom100)
|
|
br label %for.inc
|
|
|
|
for.inc:
|
|
%kmin.1 = phi i32 [ %iv, %if.then33 ], [ 0, %if.then ], [ %iv, %if.then97 ], [ 0, %if.else ]
|
|
call void @use32(i32 %kmin.1)
|
|
%inc = add nsw i32 %iv, 1
|
|
br i1 undef, label %for.body, label %for.end
|
|
|
|
for.end:
|
|
ret void
|
|
}
|