blob: dcad054a7c4c8a2fad2f32779afecd84e8397c15 [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt -S -mtriple=aarch64-none-elf -loop-reduce < %s | FileCheck %s
; These tests check that the presence of uses of a pointer outside a loop don't
; cause a different transformation inside the loop.
define i32 @postinc_inloop_no_outsideloop(ptr %p, i64 %n) {
; CHECK-LABEL: define i32 @postinc_inloop_no_outsideloop(
; CHECK-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[P0_LOAD:%.*]] = load ptr, ptr [[P]], align 8
; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds nuw ptr, ptr [[P]], i64 1
; CHECK-NEXT: [[P1_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX1]], align 8
; CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds nuw ptr, ptr [[P]], i64 2
; CHECK-NEXT: [[P2_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX2]], align 8
; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds nuw ptr, ptr [[P]], i64 3
; CHECK-NEXT: [[P3_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX3]], align 8
; CHECK-NEXT: [[P0_START:%.*]] = getelementptr inbounds nuw i32, ptr [[P0_LOAD]], i64 32
; CHECK-NEXT: [[P1_START:%.*]] = getelementptr inbounds nuw i32, ptr [[P1_LOAD]], i64 32
; CHECK-NEXT: [[P2_START:%.*]] = getelementptr inbounds nuw i32, ptr [[P2_LOAD]], i64 32
; CHECK-NEXT: [[P3_START:%.*]] = getelementptr inbounds nuw i32, ptr [[P3_LOAD]], i64 32
; CHECK-NEXT: br label %[[FOR_BODY:.*]]
; CHECK: [[FOR_BODY]]:
; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], %[[FOR_BODY]] ], [ [[N]], %[[ENTRY]] ]
; CHECK-NEXT: [[P3:%.*]] = phi ptr [ [[P3_NEXT:%.*]], %[[FOR_BODY]] ], [ [[P3_START]], %[[ENTRY]] ]
; CHECK-NEXT: [[P2:%.*]] = phi ptr [ [[P2_NEXT:%.*]], %[[FOR_BODY]] ], [ [[P2_START]], %[[ENTRY]] ]
; CHECK-NEXT: [[P1:%.*]] = phi ptr [ [[P1_NEXT:%.*]], %[[FOR_BODY]] ], [ [[P1_START]], %[[ENTRY]] ]
; CHECK-NEXT: [[P0:%.*]] = phi ptr [ [[P0_NEXT:%.*]], %[[FOR_BODY]] ], [ [[P0_START]], %[[ENTRY]] ]
; CHECK-NEXT: [[RET_0:%.*]] = phi i32 [ [[RET_4:%.*]], %[[FOR_BODY]] ], [ 0, %[[ENTRY]] ]
; CHECK-NEXT: [[P0_NEXT]] = getelementptr inbounds nuw i32, ptr [[P0]], i64 4
; CHECK-NEXT: [[VAL0:%.*]] = load i32, ptr [[P0]], align 4
; CHECK-NEXT: [[RET_1:%.*]] = add nsw i32 [[VAL0]], [[RET_0]]
; CHECK-NEXT: [[P1_NEXT]] = getelementptr inbounds nuw i32, ptr [[P1]], i64 4
; CHECK-NEXT: [[VAL1:%.*]] = load i32, ptr [[P1]], align 4
; CHECK-NEXT: [[RET_2:%.*]] = add nsw i32 [[VAL1]], [[RET_1]]
; CHECK-NEXT: [[P2_NEXT]] = getelementptr inbounds nuw i32, ptr [[P2]], i64 4
; CHECK-NEXT: [[VAL2:%.*]] = load i32, ptr [[P2]], align 4
; CHECK-NEXT: [[RET_3:%.*]] = add nsw i32 [[VAL2]], [[RET_2]]
; CHECK-NEXT: [[P3_NEXT]] = getelementptr inbounds nuw i32, ptr [[P3]], i64 4
; CHECK-NEXT: [[VAL3:%.*]] = load i32, ptr [[P3]], align 4
; CHECK-NEXT: [[RET_4]] = add nsw i32 [[VAL3]], [[RET_3]]
; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -1
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0
; CHECK-NEXT: br i1 [[EXITCOND]], label %[[EXIT:.*]], label %[[FOR_BODY]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret i32 [[RET_4]]
;
entry:
%p0.load = load ptr, ptr %p, align 8
%arrayidx1 = getelementptr inbounds nuw ptr, ptr %p, i64 1
%p1.load = load ptr, ptr %arrayidx1, align 8
%arrayidx2 = getelementptr inbounds nuw ptr, ptr %p, i64 2
%p2.load = load ptr, ptr %arrayidx2, align 8
%arrayidx3 = getelementptr inbounds nuw ptr, ptr %p, i64 3
%p3.load = load ptr, ptr %arrayidx3, align 8
%p0.start = getelementptr inbounds nuw i32, ptr %p0.load, i64 32
%p1.start = getelementptr inbounds nuw i32, ptr %p1.load, i64 32
%p2.start = getelementptr inbounds nuw i32, ptr %p2.load, i64 32
%p3.start = getelementptr inbounds nuw i32, ptr %p3.load, i64 32
br label %for.body
for.body:
%iv = phi i64 [ %iv.next, %for.body ], [ 0, %entry ]
%p3 = phi ptr [ %p3.next, %for.body ], [ %p3.start, %entry ]
%p2 = phi ptr [ %p2.next, %for.body ], [ %p2.start, %entry ]
%p1 = phi ptr [ %p1.next, %for.body ], [ %p1.start, %entry ]
%p0 = phi ptr [ %p0.next, %for.body ], [ %p0.start, %entry ]
%ret.0 = phi i32 [ %ret.4, %for.body ], [ 0, %entry ]
%p0.next = getelementptr inbounds nuw i32, ptr %p0, i64 4
%val0 = load i32, ptr %p0, align 4
%ret.1 = add nsw i32 %val0, %ret.0
%p1.next = getelementptr inbounds nuw i32, ptr %p1, i64 4
%val1 = load i32, ptr %p1, align 4
%ret.2 = add nsw i32 %val1, %ret.1
%p2.next = getelementptr inbounds nuw i32, ptr %p2, i64 4
%val2 = load i32, ptr %p2, align 4
%ret.3 = add nsw i32 %val2, %ret.2
%p3.next = getelementptr inbounds nuw i32, ptr %p3, i64 4
%val3 = load i32, ptr %p3, align 4
%ret.4 = add nsw i32 %val3, %ret.3
%iv.next = add nuw nsw i64 %iv, 1
%exitcond = icmp eq i64 %iv.next, %n
br i1 %exitcond, label %exit, label %for.body
exit:
ret i32 %ret.4
}
define i32 @postinc_inloop_postinc_outsideloop(ptr %p, i64 %n) {
; CHECK-LABEL: define i32 @postinc_inloop_postinc_outsideloop(
; CHECK-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[P0_LOAD:%.*]] = load ptr, ptr [[P]], align 8
; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds nuw ptr, ptr [[P]], i64 1
; CHECK-NEXT: [[P1_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX1]], align 8
; CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds nuw ptr, ptr [[P]], i64 2
; CHECK-NEXT: [[P2_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX2]], align 8
; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds nuw ptr, ptr [[P]], i64 3
; CHECK-NEXT: [[P3_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX3]], align 8
; CHECK-NEXT: [[P0_START:%.*]] = getelementptr inbounds nuw i32, ptr [[P0_LOAD]], i64 32
; CHECK-NEXT: [[P1_START:%.*]] = getelementptr inbounds nuw i32, ptr [[P1_LOAD]], i64 32
; CHECK-NEXT: [[P2_START:%.*]] = getelementptr inbounds nuw i32, ptr [[P2_LOAD]], i64 32
; CHECK-NEXT: [[P3_START:%.*]] = getelementptr inbounds nuw i32, ptr [[P3_LOAD]], i64 32
; CHECK-NEXT: br label %[[FOR_BODY:.*]]
; CHECK: [[FOR_BODY]]:
; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], %[[FOR_BODY]] ], [ [[N]], %[[ENTRY]] ]
; CHECK-NEXT: [[P3:%.*]] = phi ptr [ [[P3_NEXT:%.*]], %[[FOR_BODY]] ], [ [[P3_START]], %[[ENTRY]] ]
; CHECK-NEXT: [[P2:%.*]] = phi ptr [ [[P2_NEXT:%.*]], %[[FOR_BODY]] ], [ [[P2_START]], %[[ENTRY]] ]
; CHECK-NEXT: [[P1:%.*]] = phi ptr [ [[P1_NEXT:%.*]], %[[FOR_BODY]] ], [ [[P1_START]], %[[ENTRY]] ]
; CHECK-NEXT: [[P0:%.*]] = phi ptr [ [[P0_NEXT:%.*]], %[[FOR_BODY]] ], [ [[P0_START]], %[[ENTRY]] ]
; CHECK-NEXT: [[RET_0:%.*]] = phi i32 [ [[RET_4:%.*]], %[[FOR_BODY]] ], [ 0, %[[ENTRY]] ]
; CHECK-NEXT: [[P0_NEXT]] = getelementptr inbounds nuw i32, ptr [[P0]], i64 4
; CHECK-NEXT: [[VAL0:%.*]] = load i32, ptr [[P0]], align 4
; CHECK-NEXT: [[RET_1:%.*]] = add nsw i32 [[VAL0]], [[RET_0]]
; CHECK-NEXT: [[P1_NEXT]] = getelementptr inbounds nuw i32, ptr [[P1]], i64 4
; CHECK-NEXT: [[VAL1:%.*]] = load i32, ptr [[P1]], align 4
; CHECK-NEXT: [[RET_2:%.*]] = add nsw i32 [[VAL1]], [[RET_1]]
; CHECK-NEXT: [[P2_NEXT]] = getelementptr inbounds nuw i32, ptr [[P2]], i64 4
; CHECK-NEXT: [[VAL2:%.*]] = load i32, ptr [[P2]], align 4
; CHECK-NEXT: [[RET_3:%.*]] = add nsw i32 [[VAL2]], [[RET_2]]
; CHECK-NEXT: [[P3_NEXT]] = getelementptr inbounds nuw i32, ptr [[P3]], i64 4
; CHECK-NEXT: [[VAL3:%.*]] = load i32, ptr [[P3]], align 4
; CHECK-NEXT: [[RET_4]] = add nsw i32 [[VAL3]], [[RET_3]]
; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -1
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0
; CHECK-NEXT: br i1 [[EXITCOND]], label %[[EXIT:.*]], label %[[FOR_BODY]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: store ptr [[P0_NEXT]], ptr [[P]], align 8
; CHECK-NEXT: store ptr [[P1_NEXT]], ptr [[ARRAYIDX1]], align 8
; CHECK-NEXT: store ptr [[P2_NEXT]], ptr [[ARRAYIDX2]], align 8
; CHECK-NEXT: store ptr [[P3_NEXT]], ptr [[ARRAYIDX3]], align 8
; CHECK-NEXT: ret i32 [[RET_4]]
;
entry:
%p0.load = load ptr, ptr %p, align 8
%arrayidx1 = getelementptr inbounds nuw ptr, ptr %p, i64 1
%p1.load = load ptr, ptr %arrayidx1, align 8
%arrayidx2 = getelementptr inbounds nuw ptr, ptr %p, i64 2
%p2.load = load ptr, ptr %arrayidx2, align 8
%arrayidx3 = getelementptr inbounds nuw ptr, ptr %p, i64 3
%p3.load = load ptr, ptr %arrayidx3, align 8
%p0.start = getelementptr inbounds nuw i32, ptr %p0.load, i64 32
%p1.start = getelementptr inbounds nuw i32, ptr %p1.load, i64 32
%p2.start = getelementptr inbounds nuw i32, ptr %p2.load, i64 32
%p3.start = getelementptr inbounds nuw i32, ptr %p3.load, i64 32
br label %for.body
for.body:
%iv = phi i64 [ %iv.next, %for.body ], [ 0, %entry ]
%p3 = phi ptr [ %p3.next, %for.body ], [ %p3.start, %entry ]
%p2 = phi ptr [ %p2.next, %for.body ], [ %p2.start, %entry ]
%p1 = phi ptr [ %p1.next, %for.body ], [ %p1.start, %entry ]
%p0 = phi ptr [ %p0.next, %for.body ], [ %p0.start, %entry ]
%ret.0 = phi i32 [ %ret.4, %for.body ], [ 0, %entry ]
%p0.next = getelementptr inbounds nuw i32, ptr %p0, i64 4
%val0 = load i32, ptr %p0, align 4
%ret.1 = add nsw i32 %val0, %ret.0
%p1.next = getelementptr inbounds nuw i32, ptr %p1, i64 4
%val1 = load i32, ptr %p1, align 4
%ret.2 = add nsw i32 %val1, %ret.1
%p2.next = getelementptr inbounds nuw i32, ptr %p2, i64 4
%val2 = load i32, ptr %p2, align 4
%ret.3 = add nsw i32 %val2, %ret.2
%p3.next = getelementptr inbounds nuw i32, ptr %p3, i64 4
%val3 = load i32, ptr %p3, align 4
%ret.4 = add nsw i32 %val3, %ret.3
%iv.next = add nuw nsw i64 %iv, 1
%exitcond = icmp eq i64 %iv.next, %n
br i1 %exitcond, label %exit, label %for.body
exit:
store ptr %p0.next, ptr %p, align 8
store ptr %p1.next, ptr %arrayidx1, align 8
store ptr %p2.next, ptr %arrayidx2, align 8
store ptr %p3.next, ptr %arrayidx3, align 8
ret i32 %ret.4
}
define i32 @offset_inloop_no_outsideloop(ptr %p, i64 %n) {
; CHECK-LABEL: define i32 @offset_inloop_no_outsideloop(
; CHECK-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[P0_LOAD:%.*]] = load ptr, ptr [[P]], align 8
; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds nuw ptr, ptr [[P]], i64 1
; CHECK-NEXT: [[P1_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX1]], align 8
; CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds nuw ptr, ptr [[P]], i64 2
; CHECK-NEXT: [[P2_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX2]], align 8
; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds nuw ptr, ptr [[P]], i64 3
; CHECK-NEXT: [[P3_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX3]], align 8
; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr nuw i8, ptr [[P3_LOAD]], i64 128
; CHECK-NEXT: [[SCEVGEP3:%.*]] = getelementptr nuw i8, ptr [[P2_LOAD]], i64 128
; CHECK-NEXT: [[SCEVGEP6:%.*]] = getelementptr nuw i8, ptr [[P1_LOAD]], i64 128
; CHECK-NEXT: [[SCEVGEP9:%.*]] = getelementptr nuw i8, ptr [[P0_LOAD]], i64 128
; CHECK-NEXT: br label %[[FOR_BODY:.*]]
; CHECK: [[FOR_BODY]]:
; CHECK-NEXT: [[LSR_IV10:%.*]] = phi ptr [ [[SCEVGEP11:%.*]], %[[FOR_BODY]] ], [ [[SCEVGEP9]], %[[ENTRY]] ]
; CHECK-NEXT: [[LSR_IV7:%.*]] = phi ptr [ [[SCEVGEP8:%.*]], %[[FOR_BODY]] ], [ [[SCEVGEP6]], %[[ENTRY]] ]
; CHECK-NEXT: [[LSR_IV4:%.*]] = phi ptr [ [[SCEVGEP5:%.*]], %[[FOR_BODY]] ], [ [[SCEVGEP3]], %[[ENTRY]] ]
; CHECK-NEXT: [[LSR_IV1:%.*]] = phi ptr [ [[SCEVGEP2:%.*]], %[[FOR_BODY]] ], [ [[SCEVGEP]], %[[ENTRY]] ]
; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], %[[FOR_BODY]] ], [ [[N]], %[[ENTRY]] ]
; CHECK-NEXT: [[RET_0:%.*]] = phi i32 [ [[RET_4:%.*]], %[[FOR_BODY]] ], [ 0, %[[ENTRY]] ]
; CHECK-NEXT: [[VAL0:%.*]] = load i32, ptr [[LSR_IV10]], align 4
; CHECK-NEXT: [[RET_1:%.*]] = add nsw i32 [[VAL0]], [[RET_0]]
; CHECK-NEXT: [[VAL1:%.*]] = load i32, ptr [[LSR_IV7]], align 4
; CHECK-NEXT: [[RET_2:%.*]] = add nsw i32 [[VAL1]], [[RET_1]]
; CHECK-NEXT: [[VAL2:%.*]] = load i32, ptr [[LSR_IV4]], align 4
; CHECK-NEXT: [[RET_3:%.*]] = add nsw i32 [[VAL2]], [[RET_2]]
; CHECK-NEXT: [[VAL3:%.*]] = load i32, ptr [[LSR_IV1]], align 4
; CHECK-NEXT: [[RET_4]] = add nsw i32 [[VAL3]], [[RET_3]]
; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -1
; CHECK-NEXT: [[SCEVGEP2]] = getelementptr i8, ptr [[LSR_IV1]], i64 4
; CHECK-NEXT: [[SCEVGEP5]] = getelementptr i8, ptr [[LSR_IV4]], i64 4
; CHECK-NEXT: [[SCEVGEP8]] = getelementptr i8, ptr [[LSR_IV7]], i64 4
; CHECK-NEXT: [[SCEVGEP11]] = getelementptr i8, ptr [[LSR_IV10]], i64 4
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0
; CHECK-NEXT: br i1 [[EXITCOND]], label %[[EXIT:.*]], label %[[FOR_BODY]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret i32 [[RET_4]]
;
entry:
%p0.load = load ptr, ptr %p, align 8
%arrayidx1 = getelementptr inbounds nuw ptr, ptr %p, i64 1
%p1.load = load ptr, ptr %arrayidx1, align 8
%arrayidx2 = getelementptr inbounds nuw ptr, ptr %p, i64 2
%p2.load = load ptr, ptr %arrayidx2, align 8
%arrayidx3 = getelementptr inbounds nuw 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.4, %for.body ], [ 0, %entry ]
%p0 = getelementptr inbounds nuw i32, ptr %p0.load, i64 %off
%val0 = load i32, ptr %p0, align 4
%ret.1 = add nsw i32 %val0, %ret.0
%p1 = getelementptr inbounds nuw i32, ptr %p1.load, i64 %off
%val1 = load i32, ptr %p1, align 4
%ret.2 = add nsw i32 %val1, %ret.1
%p2 = getelementptr inbounds nuw i32, ptr %p2.load, i64 %off
%val2 = load i32, ptr %p2, align 4
%ret.3 = add nsw i32 %val2, %ret.2
%p3 = getelementptr inbounds nuw i32, ptr %p3.load, i64 %off
%val3 = load i32, ptr %p3, align 4
%ret.4 = add nsw i32 %val3, %ret.3
%iv.next = add nuw nsw i64 %iv, 1
%off.next = add nuw nsw i64 %off, 1
%exitcond = icmp eq i64 %iv.next, %n
br i1 %exitcond, label %exit, label %for.body
exit:
ret i32 %ret.4
}
define i32 @offset_inloop_offset_outsideloop(ptr %p, i64 %n) {
; CHECK-LABEL: define i32 @offset_inloop_offset_outsideloop(
; CHECK-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[P0_LOAD:%.*]] = load ptr, ptr [[P]], align 8
; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds nuw ptr, ptr [[P]], i64 1
; CHECK-NEXT: [[P1_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX1]], align 8
; CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds nuw ptr, ptr [[P]], i64 2
; CHECK-NEXT: [[P2_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX2]], align 8
; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds nuw ptr, ptr [[P]], i64 3
; CHECK-NEXT: [[P3_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX3]], align 8
; CHECK-NEXT: [[SCEVGEP16:%.*]] = getelementptr nuw i8, ptr [[P0_LOAD]], i64 128
; CHECK-NEXT: [[SCEVGEP3:%.*]] = getelementptr nuw i8, ptr [[P1_LOAD]], i64 128
; CHECK-NEXT: [[SCEVGEP6:%.*]] = getelementptr nuw i8, ptr [[P2_LOAD]], i64 128
; CHECK-NEXT: [[SCEVGEP9:%.*]] = getelementptr nuw i8, ptr [[P3_LOAD]], i64 128
; CHECK-NEXT: br label %[[FOR_BODY:.*]]
; CHECK: [[FOR_BODY]]:
; CHECK-NEXT: [[LSR_IV10:%.*]] = phi ptr [ [[SCEVGEP11:%.*]], %[[FOR_BODY]] ], [ [[SCEVGEP9]], %[[ENTRY]] ]
; CHECK-NEXT: [[LSR_IV7:%.*]] = phi ptr [ [[SCEVGEP8:%.*]], %[[FOR_BODY]] ], [ [[SCEVGEP6]], %[[ENTRY]] ]
; CHECK-NEXT: [[LSR_IV4:%.*]] = phi ptr [ [[SCEVGEP5:%.*]], %[[FOR_BODY]] ], [ [[SCEVGEP3]], %[[ENTRY]] ]
; CHECK-NEXT: [[LSR_IV1:%.*]] = phi ptr [ [[SCEVGEP2:%.*]], %[[FOR_BODY]] ], [ [[SCEVGEP16]], %[[ENTRY]] ]
; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], %[[FOR_BODY]] ], [ [[N]], %[[ENTRY]] ]
; CHECK-NEXT: [[RET_0:%.*]] = phi i32 [ [[RET_4:%.*]], %[[FOR_BODY]] ], [ 0, %[[ENTRY]] ]
; CHECK-NEXT: [[VAL0:%.*]] = load i32, ptr [[LSR_IV1]], align 4
; CHECK-NEXT: [[RET_1:%.*]] = add nsw i32 [[VAL0]], [[RET_0]]
; CHECK-NEXT: [[VAL1:%.*]] = load i32, ptr [[LSR_IV4]], align 4
; CHECK-NEXT: [[RET_2:%.*]] = add nsw i32 [[VAL1]], [[RET_1]]
; CHECK-NEXT: [[VAL2:%.*]] = load i32, ptr [[LSR_IV7]], align 4
; CHECK-NEXT: [[RET_3:%.*]] = add nsw i32 [[VAL2]], [[RET_2]]
; CHECK-NEXT: [[VAL3:%.*]] = load i32, ptr [[LSR_IV10]], align 4
; CHECK-NEXT: [[RET_4]] = add nsw i32 [[VAL3]], [[RET_3]]
; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -1
; CHECK-NEXT: [[SCEVGEP2]] = getelementptr i8, ptr [[LSR_IV1]], i64 4
; CHECK-NEXT: [[SCEVGEP5]] = getelementptr i8, ptr [[LSR_IV4]], i64 4
; CHECK-NEXT: [[SCEVGEP8]] = getelementptr i8, ptr [[LSR_IV7]], i64 4
; CHECK-NEXT: [[SCEVGEP11]] = getelementptr i8, ptr [[LSR_IV10]], i64 4
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0
; CHECK-NEXT: br i1 [[EXITCOND]], label %[[EXIT:.*]], label %[[FOR_BODY]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: store ptr [[SCEVGEP2]], ptr [[P]], align 8
; CHECK-NEXT: store ptr [[SCEVGEP5]], ptr [[ARRAYIDX1]], align 8
; CHECK-NEXT: store ptr [[SCEVGEP8]], ptr [[ARRAYIDX2]], align 8
; CHECK-NEXT: store ptr [[SCEVGEP11]], ptr [[ARRAYIDX3]], align 8
; CHECK-NEXT: ret i32 [[RET_4]]
;
entry:
%p0.load = load ptr, ptr %p, align 8
%arrayidx1 = getelementptr inbounds nuw ptr, ptr %p, i64 1
%p1.load = load ptr, ptr %arrayidx1, align 8
%arrayidx2 = getelementptr inbounds nuw ptr, ptr %p, i64 2
%p2.load = load ptr, ptr %arrayidx2, align 8
%arrayidx3 = getelementptr inbounds nuw 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.4, %for.body ], [ 0, %entry ]
%p0 = getelementptr inbounds nuw i32, ptr %p0.load, i64 %off
%val0 = load i32, ptr %p0, align 4
%ret.1 = add nsw i32 %val0, %ret.0
%p1 = getelementptr inbounds nuw i32, ptr %p1.load, i64 %off
%val1 = load i32, ptr %p1, align 4
%ret.2 = add nsw i32 %val1, %ret.1
%p2 = getelementptr inbounds nuw i32, ptr %p2.load, i64 %off
%val2 = load i32, ptr %p2, align 4
%ret.3 = add nsw i32 %val2, %ret.2
%p3 = getelementptr inbounds nuw i32, ptr %p3.load, i64 %off
%val3 = load i32, ptr %p3, align 4
%ret.4 = add nsw i32 %val3, %ret.3
%iv.next = add nuw nsw i64 %iv, 1
%off.next = add nuw nsw i64 %off, 1
%exitcond = icmp eq i64 %iv.next, %n
br i1 %exitcond, label %exit, label %for.body
exit:
%p0.last = getelementptr inbounds nuw i32, ptr %p0.load, i64 %off.next
store ptr %p0.last, ptr %p, align 8
%p1.last = getelementptr inbounds nuw i32, ptr %p1.load, i64 %off.next
store ptr %p1.last, ptr %arrayidx1, align 8
%p2.last = getelementptr inbounds nuw i32, ptr %p2.load, i64 %off.next
store ptr %p2.last, ptr %arrayidx2, align 8
%p3.last = getelementptr inbounds nuw i32, ptr %p3.load, i64 %off.next
store ptr %p3.last, ptr %arrayidx3, align 8
ret i32 %ret.4
}
define i32 @postinc_inloop_offset_outsideloop(ptr %p, i64 %n) {
; CHECK-LABEL: define i32 @postinc_inloop_offset_outsideloop(
; CHECK-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[P0_LOAD:%.*]] = load ptr, ptr [[P]], align 8
; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds nuw ptr, ptr [[P]], i64 1
; CHECK-NEXT: [[P1_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX1]], align 8
; CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds nuw ptr, ptr [[P]], i64 2
; CHECK-NEXT: [[P2_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX2]], align 8
; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds nuw ptr, ptr [[P]], i64 3
; CHECK-NEXT: [[P3_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX3]], align 8
; CHECK-NEXT: [[P0_START:%.*]] = getelementptr inbounds nuw i32, ptr [[P0_LOAD]], i64 32
; CHECK-NEXT: [[P1_START:%.*]] = getelementptr inbounds nuw i32, ptr [[P1_LOAD]], i64 32
; CHECK-NEXT: [[P2_START:%.*]] = getelementptr inbounds nuw i32, ptr [[P2_LOAD]], i64 32
; CHECK-NEXT: [[P3_START:%.*]] = getelementptr inbounds nuw i32, ptr [[P3_LOAD]], i64 32
; CHECK-NEXT: br label %[[FOR_BODY:.*]]
; CHECK: [[FOR_BODY]]:
; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], %[[FOR_BODY]] ], [ [[N]], %[[ENTRY]] ]
; CHECK-NEXT: [[P3:%.*]] = phi ptr [ [[P3_NEXT:%.*]], %[[FOR_BODY]] ], [ [[P3_START]], %[[ENTRY]] ]
; CHECK-NEXT: [[P2:%.*]] = phi ptr [ [[P2_NEXT:%.*]], %[[FOR_BODY]] ], [ [[P2_START]], %[[ENTRY]] ]
; CHECK-NEXT: [[P1:%.*]] = phi ptr [ [[P1_NEXT:%.*]], %[[FOR_BODY]] ], [ [[P1_START]], %[[ENTRY]] ]
; CHECK-NEXT: [[P0:%.*]] = phi ptr [ [[P0_NEXT:%.*]], %[[FOR_BODY]] ], [ [[P0_START]], %[[ENTRY]] ]
; CHECK-NEXT: [[RET_0:%.*]] = phi i32 [ [[RET_4:%.*]], %[[FOR_BODY]] ], [ 0, %[[ENTRY]] ]
; CHECK-NEXT: [[P0_NEXT]] = getelementptr inbounds nuw i32, ptr [[P0]], i64 4
; CHECK-NEXT: [[VAL0:%.*]] = load i32, ptr [[P0]], align 4
; CHECK-NEXT: [[RET_1:%.*]] = add nsw i32 [[VAL0]], [[RET_0]]
; CHECK-NEXT: [[P1_NEXT]] = getelementptr inbounds nuw i32, ptr [[P1]], i64 4
; CHECK-NEXT: [[VAL1:%.*]] = load i32, ptr [[P1]], align 4
; CHECK-NEXT: [[RET_2:%.*]] = add nsw i32 [[VAL1]], [[RET_1]]
; CHECK-NEXT: [[P2_NEXT]] = getelementptr inbounds nuw i32, ptr [[P2]], i64 4
; CHECK-NEXT: [[VAL2:%.*]] = load i32, ptr [[P2]], align 4
; CHECK-NEXT: [[RET_3:%.*]] = add nsw i32 [[VAL2]], [[RET_2]]
; CHECK-NEXT: [[P3_NEXT]] = getelementptr inbounds nuw i32, ptr [[P3]], i64 4
; CHECK-NEXT: [[VAL3:%.*]] = load i32, ptr [[P3]], align 4
; CHECK-NEXT: [[RET_4]] = add nsw i32 [[VAL3]], [[RET_3]]
; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -1
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0
; CHECK-NEXT: br i1 [[EXITCOND]], label %[[EXIT:.*]], label %[[FOR_BODY]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: store ptr [[P0_NEXT]], ptr [[P]], align 8
; CHECK-NEXT: store ptr [[P1_NEXT]], ptr [[ARRAYIDX1]], align 8
; CHECK-NEXT: store ptr [[P2_NEXT]], ptr [[ARRAYIDX2]], align 8
; CHECK-NEXT: store ptr [[P3_NEXT]], ptr [[ARRAYIDX3]], align 8
; CHECK-NEXT: ret i32 [[RET_4]]
;
entry:
%p0.load = load ptr, ptr %p, align 8
%arrayidx1 = getelementptr inbounds nuw ptr, ptr %p, i64 1
%p1.load = load ptr, ptr %arrayidx1, align 8
%arrayidx2 = getelementptr inbounds nuw ptr, ptr %p, i64 2
%p2.load = load ptr, ptr %arrayidx2, align 8
%arrayidx3 = getelementptr inbounds nuw ptr, ptr %p, i64 3
%p3.load = load ptr, ptr %arrayidx3, align 8
%p0.start = getelementptr inbounds nuw i32, ptr %p0.load, i64 32
%p1.start = getelementptr inbounds nuw i32, ptr %p1.load, i64 32
%p2.start = getelementptr inbounds nuw i32, ptr %p2.load, i64 32
%p3.start = getelementptr inbounds nuw i32, ptr %p3.load, i64 32
br label %for.body
for.body:
%iv = phi i64 [ %iv.next, %for.body ], [ 0, %entry ]
%p3 = phi ptr [ %p3.next, %for.body ], [ %p3.start, %entry ]
%p2 = phi ptr [ %p2.next, %for.body ], [ %p2.start, %entry ]
%p1 = phi ptr [ %p1.next, %for.body ], [ %p1.start, %entry ]
%p0 = phi ptr [ %p0.next, %for.body ], [ %p0.start, %entry ]
%off = phi i64 [ %off.next, %for.body ], [ 32, %entry ]
%ret.0 = phi i32 [ %ret.4, %for.body ], [ 0, %entry ]
%p0.next = getelementptr inbounds nuw i32, ptr %p0, i64 4
%val0 = load i32, ptr %p0, align 4
%ret.1 = add nsw i32 %val0, %ret.0
%p1.next = getelementptr inbounds nuw i32, ptr %p1, i64 4
%val1 = load i32, ptr %p1, align 4
%ret.2 = add nsw i32 %val1, %ret.1
%p2.next = getelementptr inbounds nuw i32, ptr %p2, i64 4
%val2 = load i32, ptr %p2, align 4
%ret.3 = add nsw i32 %val2, %ret.2
%p3.next = getelementptr inbounds nuw i32, ptr %p3, i64 4
%val3 = load i32, ptr %p3, align 4
%ret.4 = add nsw i32 %val3, %ret.3
%iv.next = add nuw nsw i64 %iv, 1
%off.next = add nuw nsw i64 %off, 4
%exitcond = icmp eq i64 %iv.next, %n
br i1 %exitcond, label %exit, label %for.body
exit:
%p0.last = getelementptr inbounds nuw i32, ptr %p0.load, i64 %off.next
store ptr %p0.last, ptr %p, align 8
%p1.last = getelementptr inbounds nuw i32, ptr %p1.load, i64 %off.next
store ptr %p1.last, ptr %arrayidx1, align 8
%p2.last = getelementptr inbounds nuw i32, ptr %p2.load, i64 %off.next
store ptr %p2.last, ptr %arrayidx2, align 8
%p3.last = getelementptr inbounds nuw i32, ptr %p3.load, i64 %off.next
store ptr %p3.last, ptr %arrayidx3, align 8
ret i32 %ret.4
}
define i32 @offset_inloop_postinc_outsideloop(ptr %p, i64 %n) {
; CHECK-LABEL: define i32 @offset_inloop_postinc_outsideloop(
; CHECK-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[P0_LOAD:%.*]] = load ptr, ptr [[P]], align 8
; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds nuw ptr, ptr [[P]], i64 1
; CHECK-NEXT: [[P1_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX1]], align 8
; CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds nuw ptr, ptr [[P]], i64 2
; CHECK-NEXT: [[P2_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX2]], align 8
; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds nuw ptr, ptr [[P]], i64 3
; CHECK-NEXT: [[P3_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX3]], align 8
; CHECK-NEXT: [[P0_START:%.*]] = getelementptr inbounds nuw i32, ptr [[P0_LOAD]], i64 32
; CHECK-NEXT: [[P1_START:%.*]] = getelementptr inbounds nuw i32, ptr [[P1_LOAD]], i64 32
; CHECK-NEXT: [[P2_START:%.*]] = getelementptr inbounds nuw i32, ptr [[P2_LOAD]], i64 32
; CHECK-NEXT: [[P3_START:%.*]] = getelementptr inbounds nuw i32, ptr [[P3_LOAD]], i64 32
; CHECK-NEXT: br label %[[FOR_BODY:.*]]
; CHECK: [[FOR_BODY]]:
; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], %[[FOR_BODY]] ], [ [[N]], %[[ENTRY]] ]
; CHECK-NEXT: [[P3_LOOP:%.*]] = phi ptr [ [[P3_NEXT:%.*]], %[[FOR_BODY]] ], [ [[P3_START]], %[[ENTRY]] ]
; CHECK-NEXT: [[P2_LOOP:%.*]] = phi ptr [ [[P2_NEXT:%.*]], %[[FOR_BODY]] ], [ [[P2_START]], %[[ENTRY]] ]
; CHECK-NEXT: [[P1_LOOP:%.*]] = phi ptr [ [[P1_NEXT:%.*]], %[[FOR_BODY]] ], [ [[P1_START]], %[[ENTRY]] ]
; CHECK-NEXT: [[P0_LOOP:%.*]] = phi ptr [ [[P0_NEXT:%.*]], %[[FOR_BODY]] ], [ [[P0_START]], %[[ENTRY]] ]
; CHECK-NEXT: [[RET_0:%.*]] = phi i32 [ [[RET_4:%.*]], %[[FOR_BODY]] ], [ 0, %[[ENTRY]] ]
; CHECK-NEXT: [[VAL0:%.*]] = load i32, ptr [[P0_LOOP]], align 4
; CHECK-NEXT: [[RET_1:%.*]] = add nsw i32 [[VAL0]], [[RET_0]]
; CHECK-NEXT: [[VAL1:%.*]] = load i32, ptr [[P1_LOOP]], align 4
; CHECK-NEXT: [[RET_2:%.*]] = add nsw i32 [[VAL1]], [[RET_1]]
; CHECK-NEXT: [[VAL2:%.*]] = load i32, ptr [[P2_LOOP]], align 4
; CHECK-NEXT: [[RET_3:%.*]] = add nsw i32 [[VAL2]], [[RET_2]]
; CHECK-NEXT: [[VAL3:%.*]] = load i32, ptr [[P3_LOOP]], align 4
; CHECK-NEXT: [[RET_4]] = add nsw i32 [[VAL3]], [[RET_3]]
; CHECK-NEXT: [[P0_NEXT]] = getelementptr inbounds nuw i32, ptr [[P0_LOOP]], i64 4
; CHECK-NEXT: [[P1_NEXT]] = getelementptr inbounds nuw i32, ptr [[P1_LOOP]], i64 4
; CHECK-NEXT: [[P2_NEXT]] = getelementptr inbounds nuw i32, ptr [[P2_LOOP]], i64 4
; CHECK-NEXT: [[P3_NEXT]] = getelementptr inbounds nuw i32, ptr [[P3_LOOP]], i64 4
; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -1
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0
; CHECK-NEXT: br i1 [[EXITCOND]], label %[[EXIT:.*]], label %[[FOR_BODY]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: store ptr [[P0_NEXT]], ptr [[P]], align 8
; CHECK-NEXT: store ptr [[P1_NEXT]], ptr [[ARRAYIDX1]], align 8
; CHECK-NEXT: store ptr [[P2_NEXT]], ptr [[ARRAYIDX2]], align 8
; CHECK-NEXT: store ptr [[P3_NEXT]], ptr [[ARRAYIDX3]], align 8
; CHECK-NEXT: ret i32 [[RET_4]]
;
entry:
%p0.load = load ptr, ptr %p, align 8
%arrayidx1 = getelementptr inbounds nuw ptr, ptr %p, i64 1
%p1.load = load ptr, ptr %arrayidx1, align 8
%arrayidx2 = getelementptr inbounds nuw ptr, ptr %p, i64 2
%p2.load = load ptr, ptr %arrayidx2, align 8
%arrayidx3 = getelementptr inbounds nuw ptr, ptr %p, i64 3
%p3.load = load ptr, ptr %arrayidx3, align 8
%p0.start = getelementptr inbounds nuw i32, ptr %p0.load, i64 32
%p1.start = getelementptr inbounds nuw i32, ptr %p1.load, i64 32
%p2.start = getelementptr inbounds nuw i32, ptr %p2.load, i64 32
%p3.start = getelementptr inbounds nuw i32, ptr %p3.load, i64 32
br label %for.body
for.body:
%iv = phi i64 [ %iv.next, %for.body ], [ 0, %entry ]
%p3.loop = phi ptr [ %p3.next, %for.body ], [ %p3.start, %entry ]
%p2.loop = phi ptr [ %p2.next, %for.body ], [ %p2.start, %entry ]
%p1.loop = phi ptr [ %p1.next, %for.body ], [ %p1.start, %entry ]
%p0.loop = phi ptr [ %p0.next, %for.body ], [ %p0.start, %entry ]
%off = phi i64 [ %off.next, %for.body ], [ 32, %entry ]
%ret.0 = phi i32 [ %ret.4, %for.body ], [ 0, %entry ]
%p0 = getelementptr inbounds nuw i32, ptr %p0.load, i64 %off
%val0 = load i32, ptr %p0, align 4
%ret.1 = add nsw i32 %val0, %ret.0
%p1 = getelementptr inbounds nuw i32, ptr %p1.load, i64 %off
%val1 = load i32, ptr %p1, align 4
%ret.2 = add nsw i32 %val1, %ret.1
%p2 = getelementptr inbounds nuw i32, ptr %p2.load, i64 %off
%val2 = load i32, ptr %p2, align 4
%ret.3 = add nsw i32 %val2, %ret.2
%p3 = getelementptr inbounds nuw i32, ptr %p3.load, i64 %off
%val3 = load i32, ptr %p3, align 4
%ret.4 = add nsw i32 %val3, %ret.3
%p0.next = getelementptr inbounds nuw i32, ptr %p0.loop, i64 4
%p1.next = getelementptr inbounds nuw i32, ptr %p1.loop, i64 4
%p2.next = getelementptr inbounds nuw i32, ptr %p2.loop, i64 4
%p3.next = getelementptr inbounds nuw i32, ptr %p3.loop, i64 4
%iv.next = add nuw nsw i64 %iv, 1
%off.next = add nuw nsw i64 %off, 4
%exitcond = icmp eq i64 %iv.next, %n
br i1 %exitcond, label %exit, label %for.body
exit:
store ptr %p0.next, ptr %p, align 8
store ptr %p1.next, ptr %arrayidx1, align 8
store ptr %p2.next, ptr %arrayidx2, align 8
store ptr %p3.next, ptr %arrayidx3, align 8
ret i32 %ret.4
}
; iv_sub.next has the same formula as exitcond, but we shouldn't merge them as
; it would cause an assertion failure later
define i32 @icmpzero_merging(ptr %p, i64 %n) {
; CHECK-LABEL: define i32 @icmpzero_merging(
; CHECK-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[P0_LOAD:%.*]] = load ptr, ptr [[P]], align 8
; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds nuw ptr, ptr [[P]], i64 1
; CHECK-NEXT: [[P1_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX1]], align 8
; CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds nuw ptr, ptr [[P]], i64 2
; CHECK-NEXT: [[P2_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX2]], align 8
; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds nuw ptr, ptr [[P]], i64 3
; CHECK-NEXT: [[P3_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX3]], align 8
; CHECK-NEXT: [[SCEVGEP14:%.*]] = getelementptr nuw i8, ptr [[P0_LOAD]], i64 128
; CHECK-NEXT: [[SCEVGEP2:%.*]] = getelementptr nuw i8, ptr [[P1_LOAD]], i64 128
; CHECK-NEXT: [[SCEVGEP5:%.*]] = getelementptr nuw i8, ptr [[P2_LOAD]], i64 128
; CHECK-NEXT: [[SCEVGEP8:%.*]] = getelementptr nuw i8, ptr [[P3_LOAD]], i64 128
; CHECK-NEXT: br label %[[FOR_BODY:.*]]
; CHECK: [[FOR_BODY]]:
; CHECK-NEXT: [[LSR_IV9:%.*]] = phi ptr [ [[SCEVGEP10:%.*]], %[[FOR_BODY]] ], [ [[SCEVGEP8]], %[[ENTRY]] ]
; CHECK-NEXT: [[LSR_IV6:%.*]] = phi ptr [ [[SCEVGEP7:%.*]], %[[FOR_BODY]] ], [ [[SCEVGEP5]], %[[ENTRY]] ]
; CHECK-NEXT: [[LSR_IV3:%.*]] = phi ptr [ [[SCEVGEP4:%.*]], %[[FOR_BODY]] ], [ [[SCEVGEP2]], %[[ENTRY]] ]
; CHECK-NEXT: [[LSR_IV:%.*]] = phi ptr [ [[SCEVGEP1:%.*]], %[[FOR_BODY]] ], [ [[SCEVGEP14]], %[[ENTRY]] ]
; CHECK-NEXT: [[IV_SUB:%.*]] = phi i64 [ [[IV_SUB_NEXT:%.*]], %[[FOR_BODY]] ], [ [[N]], %[[ENTRY]] ]
; CHECK-NEXT: [[RET_0:%.*]] = phi i32 [ [[RET_4:%.*]], %[[FOR_BODY]] ], [ 0, %[[ENTRY]] ]
; CHECK-NEXT: [[VAL0:%.*]] = load i32, ptr [[LSR_IV]], align 4
; CHECK-NEXT: [[RET_1:%.*]] = add nsw i32 [[VAL0]], [[RET_0]]
; CHECK-NEXT: [[VAL1:%.*]] = load i32, ptr [[LSR_IV3]], align 4
; CHECK-NEXT: [[RET_2:%.*]] = add nsw i32 [[VAL1]], [[RET_1]]
; CHECK-NEXT: [[VAL2:%.*]] = load i32, ptr [[LSR_IV6]], align 4
; CHECK-NEXT: [[RET_3:%.*]] = add nsw i32 [[VAL2]], [[RET_2]]
; CHECK-NEXT: [[VAL3:%.*]] = load i32, ptr [[LSR_IV9]], align 4
; CHECK-NEXT: [[RET_4]] = add nsw i32 [[VAL3]], [[RET_3]]
; CHECK-NEXT: [[IV_SUB_NEXT]] = add i64 [[IV_SUB]], -1
; CHECK-NEXT: [[SCEVGEP1]] = getelementptr i8, ptr [[LSR_IV]], i64 4
; CHECK-NEXT: [[SCEVGEP4]] = getelementptr i8, ptr [[LSR_IV3]], i64 4
; CHECK-NEXT: [[SCEVGEP7]] = getelementptr i8, ptr [[LSR_IV6]], i64 4
; CHECK-NEXT: [[SCEVGEP10]] = getelementptr i8, ptr [[LSR_IV9]], i64 4
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[IV_SUB_NEXT]], 0
; CHECK-NEXT: br i1 [[EXITCOND]], label %[[EXIT:.*]], label %[[FOR_BODY]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: store ptr [[SCEVGEP1]], ptr [[P]], align 8
; CHECK-NEXT: store ptr [[SCEVGEP4]], ptr [[ARRAYIDX1]], align 8
; CHECK-NEXT: store ptr [[SCEVGEP7]], ptr [[ARRAYIDX2]], align 8
; CHECK-NEXT: store ptr [[SCEVGEP10]], ptr [[ARRAYIDX3]], align 8
; CHECK-NEXT: [[ARRAYIDX4:%.*]] = getelementptr inbounds nuw i64, ptr [[P]], i64 4
; CHECK-NEXT: store i64 [[IV_SUB_NEXT]], ptr [[ARRAYIDX4]], align 8
; CHECK-NEXT: ret i32 [[RET_4]]
;
entry:
%p0.load = load ptr, ptr %p, align 8
%arrayidx1 = getelementptr inbounds nuw ptr, ptr %p, i64 1
%p1.load = load ptr, ptr %arrayidx1, align 8
%arrayidx2 = getelementptr inbounds nuw ptr, ptr %p, i64 2
%p2.load = load ptr, ptr %arrayidx2, align 8
%arrayidx3 = getelementptr inbounds nuw 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 ]
%iv_sub = phi i64 [ %iv_sub.next, %for.body], [ %n, %entry ]
%off = phi i64 [ %off.next, %for.body ], [ 32, %entry ]
%ret.0 = phi i32 [ %ret.4, %for.body ], [ 0, %entry ]
%p0 = getelementptr inbounds nuw i32, ptr %p0.load, i64 %off
%val0 = load i32, ptr %p0, align 4
%ret.1 = add nsw i32 %val0, %ret.0
%p1 = getelementptr inbounds nuw i32, ptr %p1.load, i64 %off
%val1 = load i32, ptr %p1, align 4
%ret.2 = add nsw i32 %val1, %ret.1
%p2 = getelementptr inbounds nuw i32, ptr %p2.load, i64 %off
%val2 = load i32, ptr %p2, align 4
%ret.3 = add nsw i32 %val2, %ret.2
%p3 = getelementptr inbounds nuw i32, ptr %p3.load, i64 %off
%val3 = load i32, ptr %p3, align 4
%ret.4 = add nsw i32 %val3, %ret.3
%iv.next = add nuw nsw i64 %iv, 1
%iv_sub.next = add nuw i64 %iv_sub, -1
%off.next = add nuw nsw i64 %off, 1
%exitcond = icmp eq i64 %iv.next, %n
br i1 %exitcond, label %exit, label %for.body
exit:
%p0.last = getelementptr inbounds nuw i32, ptr %p0.load, i64 %off.next
store ptr %p0.last, ptr %p, align 8
%p1.last = getelementptr inbounds nuw i32, ptr %p1.load, i64 %off.next
store ptr %p1.last, ptr %arrayidx1, align 8
%p2.last = getelementptr inbounds nuw i32, ptr %p2.load, i64 %off.next
store ptr %p2.last, ptr %arrayidx2, align 8
%p3.last = getelementptr inbounds nuw i32, ptr %p3.load, i64 %off.next
store ptr %p3.last, ptr %arrayidx3, align 8
%arrayidx4 = getelementptr inbounds nuw i64, ptr %p, i64 4
store i64 %iv_sub.next, ptr %arrayidx4, align 8
ret i32 %ret.4
}
; Here the compare outside the loop has the same formula as the one inside the
; loop, but the one outside is ICmpZero whereas the one inside is Basic. We
; shouldn't merge these as the compare outside the loop wouldn't be transformed
; correctly when it's converted to down-counting form.
define i1 @icmpzero_outside_loop(ptr %p, i64 %n) {
; CHECK-LABEL: define i1 @icmpzero_outside_loop(
; CHECK-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[P0_LOAD:%.*]] = load ptr, ptr [[P]], align 8
; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds nuw ptr, ptr [[P]], i64 1
; CHECK-NEXT: [[P1_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX1]], align 8
; CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds nuw ptr, ptr [[P]], i64 2
; CHECK-NEXT: [[P2_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX2]], align 8
; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds nuw ptr, ptr [[P]], i64 3
; CHECK-NEXT: [[P3_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX3]], align 8
; CHECK-NEXT: [[TMP0:%.*]] = add i64 [[N]], 1
; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr nuw i8, ptr [[P0_LOAD]], i64 128
; CHECK-NEXT: [[SCEVGEP3:%.*]] = getelementptr nuw i8, ptr [[P1_LOAD]], i64 128
; CHECK-NEXT: [[SCEVGEP6:%.*]] = getelementptr nuw i8, ptr [[P2_LOAD]], i64 128
; CHECK-NEXT: [[SCEVGEP9:%.*]] = getelementptr nuw i8, ptr [[P3_LOAD]], i64 128
; CHECK-NEXT: br label %[[FOR_BODY:.*]]
; CHECK: [[FOR_BODY]]:
; CHECK-NEXT: [[LSR_IV10:%.*]] = phi ptr [ [[SCEVGEP11:%.*]], %[[FOR_BODY]] ], [ [[SCEVGEP9]], %[[ENTRY]] ]
; CHECK-NEXT: [[LSR_IV7:%.*]] = phi ptr [ [[SCEVGEP8:%.*]], %[[FOR_BODY]] ], [ [[SCEVGEP6]], %[[ENTRY]] ]
; CHECK-NEXT: [[LSR_IV4:%.*]] = phi ptr [ [[SCEVGEP5:%.*]], %[[FOR_BODY]] ], [ [[SCEVGEP3]], %[[ENTRY]] ]
; CHECK-NEXT: [[LSR_IV1:%.*]] = phi ptr [ [[SCEVGEP2:%.*]], %[[FOR_BODY]] ], [ [[SCEVGEP]], %[[ENTRY]] ]
; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], %[[FOR_BODY]] ], [ [[TMP0]], %[[ENTRY]] ]
; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -1
; CHECK-NEXT: [[SCEVGEP2]] = getelementptr i8, ptr [[LSR_IV1]], i64 4
; CHECK-NEXT: [[SCEVGEP5]] = getelementptr i8, ptr [[LSR_IV4]], i64 4
; CHECK-NEXT: [[SCEVGEP8]] = getelementptr i8, ptr [[LSR_IV7]], i64 4
; CHECK-NEXT: [[SCEVGEP11]] = getelementptr i8, ptr [[LSR_IV10]], i64 4
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ult i64 [[LSR_IV_NEXT]], 1
; CHECK-NEXT: br i1 [[EXITCOND]], label %[[EXIT:.*]], label %[[FOR_BODY]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: store ptr [[SCEVGEP2]], ptr [[P]], align 8
; CHECK-NEXT: store ptr [[SCEVGEP5]], ptr [[ARRAYIDX1]], align 8
; CHECK-NEXT: store ptr [[SCEVGEP8]], ptr [[ARRAYIDX2]], align 8
; CHECK-NEXT: store ptr [[SCEVGEP11]], ptr [[ARRAYIDX3]], align 8
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0
; CHECK-NEXT: ret i1 [[CMP]]
;
entry:
%p0.load = load ptr, ptr %p, align 8
%arrayidx1 = getelementptr inbounds nuw ptr, ptr %p, i64 1
%p1.load = load ptr, ptr %arrayidx1, align 8
%arrayidx2 = getelementptr inbounds nuw ptr, ptr %p, i64 2
%p2.load = load ptr, ptr %arrayidx2, align 8
%arrayidx3 = getelementptr inbounds nuw 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.4, %for.body ], [ 0, %entry ]
%p0 = getelementptr inbounds nuw i32, ptr %p0.load, i64 %off
%val0 = load i32, ptr %p0, align 4
%ret.1 = add nsw i32 %val0, %ret.0
%p1 = getelementptr inbounds nuw i32, ptr %p1.load, i64 %off
%val1 = load i32, ptr %p1, align 4
%ret.2 = add nsw i32 %val1, %ret.1
%p2 = getelementptr inbounds nuw i32, ptr %p2.load, i64 %off
%val2 = load i32, ptr %p2, align 4
%ret.3 = add nsw i32 %val2, %ret.2
%p3 = getelementptr inbounds nuw i32, ptr %p3.load, i64 %off
%val3 = load i32, ptr %p3, align 4
%ret.4 = add nsw i32 %val3, %ret.3
%iv.next = add nuw nsw i64 %iv, 1
%off.next = add nuw nsw i64 %off, 1
%sub = sub i64 %n, %iv
%exitcond = icmp ult i64 %sub, 1
br i1 %exitcond, label %exit, label %for.body
exit:
%p0.last = getelementptr inbounds nuw i32, ptr %p0.load, i64 %off.next
store ptr %p0.last, ptr %p, align 8
%p1.last = getelementptr inbounds nuw i32, ptr %p1.load, i64 %off.next
store ptr %p1.last, ptr %arrayidx1, align 8
%p2.last = getelementptr inbounds nuw i32, ptr %p2.load, i64 %off.next
store ptr %p2.last, ptr %arrayidx2, align 8
%p3.last = getelementptr inbounds nuw i32, ptr %p3.load, i64 %off.next
store ptr %p3.last, ptr %arrayidx3, align 8
%cmp = icmp eq i64 %iv, %n
ret i1 %cmp
}
; Here the conditions inside and outside the loop are both icmpzero, and we
; expect them to be combined into the same LSRUse right from the start.
define i1 @icmpzero_inside_outside_loop(ptr %p, i64 %n) {
; CHECK-LABEL: define i1 @icmpzero_inside_outside_loop(
; CHECK-SAME: ptr [[P:%.*]], i64 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[P0_LOAD:%.*]] = load ptr, ptr [[P]], align 8
; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds nuw ptr, ptr [[P]], i64 1
; CHECK-NEXT: [[P1_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX1]], align 8
; CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds nuw ptr, ptr [[P]], i64 2
; CHECK-NEXT: [[P2_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX2]], align 8
; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds nuw ptr, ptr [[P]], i64 3
; CHECK-NEXT: [[P3_LOAD:%.*]] = load ptr, ptr [[ARRAYIDX3]], align 8
; CHECK-NEXT: [[TMP0:%.*]] = add i64 [[N]], 1
; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr nuw i8, ptr [[P0_LOAD]], i64 128
; CHECK-NEXT: [[SCEVGEP3:%.*]] = getelementptr nuw i8, ptr [[P1_LOAD]], i64 128
; CHECK-NEXT: [[SCEVGEP6:%.*]] = getelementptr nuw i8, ptr [[P2_LOAD]], i64 128
; CHECK-NEXT: [[SCEVGEP9:%.*]] = getelementptr nuw i8, ptr [[P3_LOAD]], i64 128
; CHECK-NEXT: br label %[[FOR_BODY:.*]]
; CHECK: [[FOR_BODY]]:
; CHECK-NEXT: [[LSR_IV10:%.*]] = phi ptr [ [[SCEVGEP11:%.*]], %[[FOR_BODY]] ], [ [[SCEVGEP9]], %[[ENTRY]] ]
; CHECK-NEXT: [[LSR_IV7:%.*]] = phi ptr [ [[SCEVGEP8:%.*]], %[[FOR_BODY]] ], [ [[SCEVGEP6]], %[[ENTRY]] ]
; CHECK-NEXT: [[LSR_IV4:%.*]] = phi ptr [ [[SCEVGEP5:%.*]], %[[FOR_BODY]] ], [ [[SCEVGEP3]], %[[ENTRY]] ]
; CHECK-NEXT: [[LSR_IV1:%.*]] = phi ptr [ [[SCEVGEP2:%.*]], %[[FOR_BODY]] ], [ [[SCEVGEP]], %[[ENTRY]] ]
; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], %[[FOR_BODY]] ], [ [[TMP0]], %[[ENTRY]] ]
; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -1
; CHECK-NEXT: [[SCEVGEP2]] = getelementptr i8, ptr [[LSR_IV1]], i64 4
; CHECK-NEXT: [[SCEVGEP5]] = getelementptr i8, ptr [[LSR_IV4]], i64 4
; CHECK-NEXT: [[SCEVGEP8]] = getelementptr i8, ptr [[LSR_IV7]], i64 4
; CHECK-NEXT: [[SCEVGEP11]] = getelementptr i8, ptr [[LSR_IV10]], i64 4
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0
; CHECK-NEXT: br i1 [[EXITCOND]], label %[[EXIT:.*]], label %[[FOR_BODY]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: store ptr [[SCEVGEP2]], ptr [[P]], align 8
; CHECK-NEXT: store ptr [[SCEVGEP5]], ptr [[ARRAYIDX1]], align 8
; CHECK-NEXT: store ptr [[SCEVGEP8]], ptr [[ARRAYIDX2]], align 8
; CHECK-NEXT: store ptr [[SCEVGEP11]], ptr [[ARRAYIDX3]], align 8
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0
; CHECK-NEXT: ret i1 [[CMP]]
;
entry:
%p0.load = load ptr, ptr %p, align 8
%arrayidx1 = getelementptr inbounds nuw ptr, ptr %p, i64 1
%p1.load = load ptr, ptr %arrayidx1, align 8
%arrayidx2 = getelementptr inbounds nuw ptr, ptr %p, i64 2
%p2.load = load ptr, ptr %arrayidx2, align 8
%arrayidx3 = getelementptr inbounds nuw 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.4, %for.body ], [ 0, %entry ]
%p0 = getelementptr inbounds nuw i32, ptr %p0.load, i64 %off
%val0 = load i32, ptr %p0, align 4
%ret.1 = add nsw i32 %val0, %ret.0
%p1 = getelementptr inbounds nuw i32, ptr %p1.load, i64 %off
%val1 = load i32, ptr %p1, align 4
%ret.2 = add nsw i32 %val1, %ret.1
%p2 = getelementptr inbounds nuw i32, ptr %p2.load, i64 %off
%val2 = load i32, ptr %p2, align 4
%ret.3 = add nsw i32 %val2, %ret.2
%p3 = getelementptr inbounds nuw i32, ptr %p3.load, i64 %off
%val3 = load i32, ptr %p3, align 4
%ret.4 = add nsw i32 %val3, %ret.3
%iv.next = add nuw nsw i64 %iv, 1
%off.next = add nuw nsw i64 %off, 1
%exitcond = icmp eq i64 %iv, %n
br i1 %exitcond, label %exit, label %for.body
exit:
%p0.last = getelementptr inbounds nuw i32, ptr %p0.load, i64 %off.next
store ptr %p0.last, ptr %p, align 8
%p1.last = getelementptr inbounds nuw i32, ptr %p1.load, i64 %off.next
store ptr %p1.last, ptr %arrayidx1, align 8
%p2.last = getelementptr inbounds nuw i32, ptr %p2.load, i64 %off.next
store ptr %p2.last, ptr %arrayidx2, align 8
%p3.last = getelementptr inbounds nuw i32, ptr %p3.load, i64 %off.next
store ptr %p3.last, ptr %arrayidx3, align 8
%cmp = icmp eq i64 %iv, %n
ret i1 %cmp
}