| ; 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 |
| } |