1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-25 12:12:47 +01:00
llvm-mirror/test/Transforms/IndVarSimplify/no-iv-rewrite.ll
Roman Lebedev eb30ce19c4 [NFCI] SCEVExpander: emit intrinsics for integral {u,s}{min,max} SCEV expressions
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
2021-03-06 21:52:46 +03:00

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
}