blob: 2fdee2ae94e9d50b6e4c8b4487d67ea858a68dd7 [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt -mtriple=x86_64 -loop-reduce -S < %s | FileCheck %s
declare i1 @otherfn(ptr)
; The use of %ptr in %gep outside the loop uses a fixup of 8 which is
; incompatible with the use inside the loop as an argument to a call. We
; therefore can't merge the two, as it would cause an assertion failure.
define i64 @invalid_offset_outside_loop(ptr %ptr.arg, i64 %iv.arg) {
; CHECK-LABEL: define i64 @invalid_offset_outside_loop(
; CHECK-SAME: ptr [[PTR_ARG:%.*]], i64 [[IV_ARG:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[TMP0:%.*]] = add i64 [[IV_ARG]], -2
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], %[[LOOP_INC:.*]] ], [ [[TMP0]], %[[ENTRY]] ]
; CHECK-NEXT: [[PTR:%.*]] = phi ptr [ [[PTR_ARG]], %[[ENTRY]] ], [ [[PTR_NEXT:%.*]], %[[LOOP_INC]] ]
; CHECK-NEXT: [[CALL:%.*]] = call i1 @otherfn(ptr [[PTR]])
; CHECK-NEXT: br i1 [[CALL]], label %[[EXIT:.*]], label %[[LOOP_INC]]
; CHECK: [[LOOP_INC]]:
; CHECK-NEXT: [[PTR_NEXT]] = getelementptr i8, ptr [[PTR]], i64 16
; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -1
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], -3
; CHECK-NEXT: br i1 [[EXITCOND]], label %[[EXIT]], label %[[LOOP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[TMP1:%.*]] = add i64 [[LSR_IV]], 2
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i64 [[TMP1]], [[IV_ARG]]
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i64 [[LSR_IV]], -1
; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[CMP1]], i64 1, i64 2
; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[CMP2]], i64 [[SEL1]], i64 3
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[PTR]], i64 8
; CHECK-NEXT: store i64 [[SEL2]], ptr [[GEP]], align 8
; CHECK-NEXT: ret i64 [[LSR_IV]]
;
entry:
br label %loop
loop:
%ptr = phi ptr [ %ptr.arg, %entry ], [ %ptr.next, %loop.inc ]
%iv = phi i64 [ %iv.arg, %entry ], [ %iv.next, %loop.inc ]
%call = call i1 @otherfn(ptr %ptr)
br i1 %call, label %exit, label %loop.inc
loop.inc:
%ptr.next = getelementptr i8, ptr %ptr, i64 16
%iv.next = add i64 %iv, -1
%exitcond = icmp eq i64 %iv, 0
br i1 %exitcond, label %exit, label %loop
exit:
%cmp1 = icmp slt i64 %iv, %iv.arg
%cmp2 = icmp eq i64 %iv, 1
%sel1 = select i1 %cmp1, i64 1, i64 2
%sel2 = select i1 %cmp2, i64 %sel1, i64 3
%gep = getelementptr i8, ptr %ptr, i64 8
store i64 %sel2, ptr %gep, align 8
%sub = add i64 %iv, -2
ret i64 %sub
}
; Stream 0 has two in-loop loads at relative offsets {-2^30, 0}, which makes
; GenerateConstantOffsets produce formulae with BaseOffset +2^30. The exit
; block loads at +1.5*2^30 past the post-inc pointer; x86 accepts that as a
; disp32, so the merge gate isLegalUse(LU.MinOffset, LU.MaxOffset, ...,
; Formulae[0]) passes, but 2^30 + 1.5*2^30 = 2.5*2^30 does not fit in a
; signed 32-bit displacement, so the +2^30 formulae become illegal once the
; outside-loop fixup is merged in. The test is sized so that the merge itself
; drops EstimateSearchSpaceComplexity() below ComplexityLimit, so no later
; narrowing step deletes the now-illegal formulae before Solve().
define i32 @illegal_formula_after_merge(ptr %p, i64 %n) {
; CHECK-LABEL: define i32 @illegal_formula_after_merge(
; CHECK-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[P0_LOAD:%.*]] = load ptr, ptr [[P]], align 8
; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr ptr, ptr [[P]], i64 1
; CHECK-NEXT: [[P1_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX1]], align 8
; CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr ptr, ptr [[P]], i64 2
; CHECK-NEXT: [[P2_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX2]], align 8
; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr ptr, ptr [[P]], i64 3
; CHECK-NEXT: [[P3_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX3]], align 8
; CHECK-NEXT: [[SCEVGEP2:%.*]] = getelementptr i8, ptr [[P3_LOAD]], i64 128
; CHECK-NEXT: [[SCEVGEP4:%.*]] = getelementptr i8, ptr [[P2_LOAD]], i64 128
; CHECK-NEXT: [[SCEVGEP6:%.*]] = getelementptr i8, ptr [[P1_LOAD]], i64 128
; CHECK-NEXT: br label %[[FOR_BODY:.*]]
; CHECK: [[FOR_BODY]]:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], %[[FOR_BODY]] ], [ 0, %[[ENTRY]] ]
; CHECK-NEXT: [[RET_0:%.*]] = phi i32 [ [[RET_2B:%.*]], %[[FOR_BODY]] ], [ 0, %[[ENTRY]] ]
; CHECK-NEXT: [[TMP0:%.*]] = shl i64 [[IV]], 2
; CHECK-NEXT: [[SCEVGEP10:%.*]] = getelementptr i8, ptr [[P0_LOAD]], i64 [[TMP0]]
; CHECK-NEXT: [[SCEVGEP11:%.*]] = getelementptr i8, ptr [[SCEVGEP10]], i64 128
; CHECK-NEXT: [[VAL0:%.*]] = load i32, ptr [[SCEVGEP11]], align 4
; CHECK-NEXT: [[RET_1:%.*]] = add nsw i32 [[VAL0]], [[RET_0]]
; CHECK-NEXT: [[TMP1:%.*]] = shl i64 [[IV]], 2
; CHECK-NEXT: [[SCEVGEP8:%.*]] = getelementptr i8, ptr [[P0_LOAD]], i64 [[TMP1]]
; CHECK-NEXT: [[SCEVGEP9:%.*]] = getelementptr i8, ptr [[SCEVGEP8]], i64 -1073741696
; CHECK-NEXT: [[VAL0B:%.*]] = load i32, ptr [[SCEVGEP9]], align 4
; CHECK-NEXT: [[RET_1B:%.*]] = add nsw i32 [[VAL0B]], [[RET_1]]
; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[IV]], 2
; CHECK-NEXT: [[SCEVGEP7:%.*]] = getelementptr i8, ptr [[SCEVGEP6]], i64 [[TMP2]]
; CHECK-NEXT: [[VAL1:%.*]] = load i32, ptr [[SCEVGEP7]], align 4
; CHECK-NEXT: [[RET_2:%.*]] = add nsw i32 [[VAL1]], [[RET_1B]]
; CHECK-NEXT: [[TMP3:%.*]] = shl i64 [[IV]], 2
; CHECK-NEXT: [[SCEVGEP5:%.*]] = getelementptr i8, ptr [[SCEVGEP4]], i64 [[TMP3]]
; CHECK-NEXT: [[VAL2:%.*]] = load i32, ptr [[SCEVGEP5]], align 4
; CHECK-NEXT: [[RET_2A:%.*]] = add nsw i32 [[VAL2]], [[RET_2]]
; CHECK-NEXT: [[TMP4:%.*]] = shl i64 [[IV]], 2
; CHECK-NEXT: [[SCEVGEP3:%.*]] = getelementptr i8, ptr [[SCEVGEP2]], i64 [[TMP4]]
; CHECK-NEXT: [[VAL3:%.*]] = load i32, ptr [[SCEVGEP3]], align 4
; CHECK-NEXT: [[RET_2C:%.*]] = add nsw i32 [[VAL3]], [[RET_2A]]
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
; CHECK-NEXT: [[RET_2B]] = add nsw i32 [[RET_2C]], 1
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[N]], [[IV_NEXT]]
; CHECK-NEXT: br i1 [[EXITCOND]], label %[[EXIT:.*]], label %[[FOR_BODY]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[TMP5:%.*]] = shl i64 [[IV_NEXT]], 2
; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr i8, ptr [[P0_LOAD]], i64 [[TMP5]]
; CHECK-NEXT: [[SCEVGEP1:%.*]] = getelementptr i8, ptr [[SCEVGEP]], i64 1610612864
; CHECK-NEXT: [[VALFAR:%.*]] = load i32, ptr [[SCEVGEP1]], align 4
; CHECK-NEXT: [[RET_3:%.*]] = add nsw i32 [[RET_2B]], [[VALFAR]]
; CHECK-NEXT: ret i32 [[RET_3]]
;
entry:
%p0.load = load ptr, ptr %p, align 8
%arrayidx1 = getelementptr ptr, ptr %p, i64 1
%p1.load = load ptr, ptr %arrayidx1, align 8
%arrayidx2 = getelementptr ptr, ptr %p, i64 2
%p2.load = load ptr, ptr %arrayidx2, align 8
%arrayidx3 = getelementptr ptr, ptr %p, i64 3
%p3.load = load ptr, ptr %arrayidx3, align 8
br label %for.body
for.body:
%iv = phi i64 [ %iv.next, %for.body ], [ 0, %entry ]
%off = phi i64 [ %off.next, %for.body ], [ 32, %entry ]
%ret.0 = phi i32 [ %ret.2b, %for.body ], [ 0, %entry ]
%p0 = getelementptr i32, ptr %p0.load, i64 %off
%val0 = load i32, ptr %p0, align 4
%ret.1 = add nsw i32 %val0, %ret.0
%p0.low = getelementptr i8, ptr %p0, i64 -1073741824
%val0b = load i32, ptr %p0.low, align 4
%ret.1b = add nsw i32 %val0b, %ret.1
%p1 = getelementptr i32, ptr %p1.load, i64 %off
%val1 = load i32, ptr %p1, align 4
%ret.2 = add nsw i32 %val1, %ret.1b
%p2 = getelementptr i32, ptr %p2.load, i64 %off
%val2 = load i32, ptr %p2, align 4
%ret.2a = add nsw i32 %val2, %ret.2
%p3 = getelementptr i32, ptr %p3.load, i64 %off
%val3 = load i32, ptr %p3, align 4
%ret.2c = add nsw i32 %val3, %ret.2a
%iv.next = add nuw nsw i64 %iv, 1
%off.next = add nuw nsw i64 %off, 1
%exitcond = icmp eq i64 %iv.next, %n
%ret.2b = add nsw i32 %ret.2c, 1
br i1 %exitcond, label %exit, label %for.body
exit:
%p0.last = getelementptr i32, ptr %p0.load, i64 %off.next
%p0.far = getelementptr i8, ptr %p0.last, i64 1610612736
%valfar = load i32, ptr %p0.far, align 4
%ret.3 = add nsw i32 %ret.2b, %valfar
ret i32 %ret.3
}