blob: 5f3aa8b33b2b6872498af84971e09e9736f653d3 [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt -passes="loop-idiom" < %s -S | FileCheck %s
; Check that we can form memmove when the loop index variable is sign or zero
; extended.
define void @move_up_dec_loop_zext(i16 %n, ptr %p) {
; CHECK-LABEL: define void @move_up_dec_loop_zext(
; CHECK-SAME: i16 [[N:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[TMP0:%.*]] = zext i16 [[N]] to i64
; CHECK-NEXT: [[TMP1:%.*]] = add i16 [[N]], -1
; CHECK-NEXT: [[SMIN:%.*]] = call i16 @llvm.smin.i16(i16 [[TMP1]], i16 0)
; CHECK-NEXT: [[TMP2:%.*]] = sub i16 [[TMP1]], [[SMIN]]
; CHECK-NEXT: [[TMP3:%.*]] = zext i16 [[TMP2]] to i64
; CHECK-NEXT: [[TMP4:%.*]] = sub i64 [[TMP0]], [[TMP3]]
; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr i8, ptr [[P]], i64 [[TMP4]]
; CHECK-NEXT: [[TMP5:%.*]] = add i64 [[TMP0]], -1
; CHECK-NEXT: [[TMP6:%.*]] = sub i64 [[TMP5]], [[TMP3]]
; CHECK-NEXT: [[SCEVGEP1:%.*]] = getelementptr i8, ptr [[P]], i64 [[TMP6]]
; CHECK-NEXT: [[TMP7:%.*]] = add nuw nsw i64 [[TMP3]], 1
; CHECK-NEXT: call void @llvm.memmove.p0.p0.i64(ptr align 1 [[SCEVGEP]], ptr align 1 [[SCEVGEP1]], i64 [[TMP7]], i1 false)
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV:%.*]] = phi i16 [ [[IV_NEXT:%.*]], %[[LOOP]] ], [ [[N]], %[[ENTRY]] ]
; CHECK-NEXT: [[IV_EXT:%.*]] = zext nneg i16 [[IV]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub nuw nsw i64 [[IV_EXT]], 1
; CHECK-NEXT: [[SRC:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 [[SUB]]
; CHECK-NEXT: [[DST:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 [[IV_EXT]]
; CHECK-NEXT: [[VAL:%.*]] = load i8, ptr [[SRC]], align 1
; CHECK-NEXT: [[IV_NEXT]] = add i16 [[IV]], -1
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i16 [[IV_NEXT]], 0
; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP]], label %[[EXIT:.*]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%iv = phi i16 [ %iv.next, %loop ], [ %n, %entry ]
%iv.ext = zext nneg i16 %iv to i64
%sub = sub nuw nsw i64 %iv.ext, 1
%src = getelementptr inbounds nuw i8, ptr %p, i64 %sub
%dst = getelementptr inbounds nuw i8, ptr %p, i64 %iv.ext
%val = load i8, ptr %src, align 1
store i8 %val, ptr %dst, align 1
%iv.next = add i16 %iv, -1
%cmp = icmp sgt i16 %iv.next, 0
br i1 %cmp, label %loop, label %exit
exit:
ret void
}
define void @move_down_inc_loop_zext(i16 %n, ptr %p) {
; CHECK-LABEL: define void @move_down_inc_loop_zext(
; CHECK-SAME: i16 [[N:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr nuw i8, ptr [[P]], i64 1
; CHECK-NEXT: [[SMAX:%.*]] = call i16 @llvm.smax.i16(i16 [[N]], i16 2)
; CHECK-NEXT: [[TMP0:%.*]] = zext nneg i16 [[SMAX]] to i64
; CHECK-NEXT: [[TMP1:%.*]] = add nsw i64 [[TMP0]], -1
; CHECK-NEXT: call void @llvm.memmove.p0.p0.i64(ptr align 1 [[P]], ptr align 1 [[SCEVGEP]], i64 [[TMP1]], i1 false)
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV:%.*]] = phi i16 [ [[IV_NEXT:%.*]], %[[LOOP]] ], [ 1, %[[ENTRY]] ]
; CHECK-NEXT: [[IV_EXT:%.*]] = zext nneg i16 [[IV]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub nuw nsw i64 [[IV_EXT]], 1
; CHECK-NEXT: [[SRC:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 [[IV_EXT]]
; CHECK-NEXT: [[DST:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 [[SUB]]
; CHECK-NEXT: [[VAL:%.*]] = load i8, ptr [[SRC]], align 1
; CHECK-NEXT: [[IV_NEXT]] = add i16 [[IV]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i16 [[IV_NEXT]], [[N]]
; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP]], label %[[EXIT:.*]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%iv = phi i16 [ %iv.next, %loop ], [ 1, %entry ]
%iv.ext = zext nneg i16 %iv to i64
%sub = sub nuw nsw i64 %iv.ext, 1
%src = getelementptr inbounds nuw i8, ptr %p, i64 %iv.ext
%dst = getelementptr inbounds nuw i8, ptr %p, i64 %sub
%val = load i8, ptr %src, align 1
store i8 %val, ptr %dst, align 1
%iv.next = add i16 %iv, 1
%cmp = icmp slt i16 %iv.next, %n
br i1 %cmp, label %loop, label %exit
exit:
ret void
}
define void @move_up_dec_loop_sext(i16 %n, ptr %p) {
; CHECK-LABEL: define void @move_up_dec_loop_sext(
; CHECK-SAME: i16 [[N:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[TMP0:%.*]] = sext i16 [[N]] to i64
; CHECK-NEXT: [[TMP1:%.*]] = add i16 [[N]], -1
; CHECK-NEXT: [[TMP8:%.*]] = add nsw i16 [[N]], -1
; CHECK-NEXT: [[SMIN:%.*]] = call i16 @llvm.smin.i16(i16 [[TMP8]], i16 0)
; CHECK-NEXT: [[TMP2:%.*]] = sub i16 [[TMP1]], [[SMIN]]
; CHECK-NEXT: [[TMP3:%.*]] = zext i16 [[TMP2]] to i64
; CHECK-NEXT: [[TMP4:%.*]] = sub i64 [[TMP0]], [[TMP3]]
; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr i8, ptr [[P]], i64 [[TMP4]]
; CHECK-NEXT: [[TMP5:%.*]] = add i64 [[TMP0]], -1
; CHECK-NEXT: [[TMP6:%.*]] = sub i64 [[TMP5]], [[TMP3]]
; CHECK-NEXT: [[SCEVGEP1:%.*]] = getelementptr i8, ptr [[P]], i64 [[TMP6]]
; CHECK-NEXT: [[TMP7:%.*]] = add nuw nsw i64 [[TMP3]], 1
; CHECK-NEXT: call void @llvm.memmove.p0.p0.i64(ptr align 1 [[SCEVGEP]], ptr align 1 [[SCEVGEP1]], i64 [[TMP7]], i1 false)
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV:%.*]] = phi i16 [ [[IV_NEXT:%.*]], %[[LOOP]] ], [ [[N]], %[[ENTRY]] ]
; CHECK-NEXT: [[IV_EXT:%.*]] = sext i16 [[IV]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub nuw nsw i64 [[IV_EXT]], 1
; CHECK-NEXT: [[SRC:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 [[SUB]]
; CHECK-NEXT: [[DST:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 [[IV_EXT]]
; CHECK-NEXT: [[VAL:%.*]] = load i8, ptr [[SRC]], align 1
; CHECK-NEXT: [[IV_NEXT]] = add nsw i16 [[IV]], -1
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i16 [[IV_NEXT]], 0
; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP]], label %[[EXIT:.*]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%iv = phi i16 [ %iv.next, %loop ], [ %n, %entry ]
%iv.ext = sext i16 %iv to i64
%sub = sub nuw nsw i64 %iv.ext, 1
%src = getelementptr inbounds nuw i8, ptr %p, i64 %sub
%dst = getelementptr inbounds nuw i8, ptr %p, i64 %iv.ext
%val = load i8, ptr %src, align 1
store i8 %val, ptr %dst, align 1
%iv.next = add nsw i16 %iv, -1
%cmp = icmp sgt i16 %iv.next, 0
br i1 %cmp, label %loop, label %exit
exit:
ret void
}
define void @move_down_inc_loop_sext(i16 %n, ptr %p) {
; CHECK-LABEL: define void @move_down_inc_loop_sext(
; CHECK-SAME: i16 [[N:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr nuw i8, ptr [[P]], i64 1
; CHECK-NEXT: [[SMAX:%.*]] = call i16 @llvm.smax.i16(i16 [[N]], i16 2)
; CHECK-NEXT: [[TMP0:%.*]] = zext nneg i16 [[SMAX]] to i64
; CHECK-NEXT: [[TMP1:%.*]] = add nsw i64 [[TMP0]], -1
; CHECK-NEXT: call void @llvm.memmove.p0.p0.i64(ptr align 1 [[P]], ptr align 1 [[SCEVGEP]], i64 [[TMP1]], i1 false)
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV:%.*]] = phi i16 [ [[IV_NEXT:%.*]], %[[LOOP]] ], [ 1, %[[ENTRY]] ]
; CHECK-NEXT: [[IV_EXT:%.*]] = sext i16 [[IV]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub nuw nsw i64 [[IV_EXT]], 1
; CHECK-NEXT: [[SRC:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 [[IV_EXT]]
; CHECK-NEXT: [[DST:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 [[SUB]]
; CHECK-NEXT: [[VAL:%.*]] = load i8, ptr [[SRC]], align 1
; CHECK-NEXT: [[IV_NEXT]] = add nsw i16 [[IV]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i16 [[IV_NEXT]], [[N]]
; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP]], label %[[EXIT:.*]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%iv = phi i16 [ %iv.next, %loop ], [ 1, %entry ]
%iv.ext = sext i16 %iv to i64
%sub = sub nuw nsw i64 %iv.ext, 1
%src = getelementptr inbounds nuw i8, ptr %p, i64 %iv.ext
%dst = getelementptr inbounds nuw i8, ptr %p, i64 %sub
%val = load i8, ptr %src, align 1
store i8 %val, ptr %dst, align 1
%iv.next = add nsw i16 %iv, 1
%cmp = icmp slt i16 %iv.next, %n
br i1 %cmp, label %loop, label %exit
exit:
ret void
}
; In the following tests the load reads from the location that was stored to in
; the previous loop iteration, so using memmove is not valid.
define void @move_down_dec_loop_zext(i16 %n, ptr %p) {
; CHECK-LABEL: define void @move_down_dec_loop_zext(
; CHECK-SAME: i16 [[N:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV:%.*]] = phi i16 [ [[IV_NEXT:%.*]], %[[LOOP]] ], [ [[N]], %[[ENTRY]] ]
; CHECK-NEXT: [[IV_EXT:%.*]] = zext nneg i16 [[IV]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub nuw nsw i64 [[IV_EXT]], 1
; CHECK-NEXT: [[SRC:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 [[IV_EXT]]
; CHECK-NEXT: [[DST:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 [[SUB]]
; CHECK-NEXT: [[VAL:%.*]] = load i8, ptr [[SRC]], align 1
; CHECK-NEXT: store i8 [[VAL]], ptr [[DST]], align 1
; CHECK-NEXT: [[IV_NEXT]] = add i16 [[IV]], -1
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i16 [[IV_NEXT]], 0
; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP]], label %[[EXIT:.*]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%iv = phi i16 [ %iv.next, %loop ], [ %n, %entry ]
%iv.ext = zext nneg i16 %iv to i64
%sub = sub nuw nsw i64 %iv.ext, 1
%src = getelementptr inbounds nuw i8, ptr %p, i64 %iv.ext
%dst = getelementptr inbounds nuw i8, ptr %p, i64 %sub
%val = load i8, ptr %src, align 1
store i8 %val, ptr %dst, align 1
%iv.next = add i16 %iv, -1
%cmp = icmp sgt i16 %iv.next, 0
br i1 %cmp, label %loop, label %exit
exit:
ret void
}
define void @move_up_inc_loop_zext(i16 %n, ptr %p) {
; CHECK-LABEL: define void @move_up_inc_loop_zext(
; CHECK-SAME: i16 [[N:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV:%.*]] = phi i16 [ [[IV_NEXT:%.*]], %[[LOOP]] ], [ 1, %[[ENTRY]] ]
; CHECK-NEXT: [[IV_EXT:%.*]] = zext nneg i16 [[IV]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub nuw nsw i64 [[IV_EXT]], 1
; CHECK-NEXT: [[SRC:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 [[SUB]]
; CHECK-NEXT: [[DST:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 [[IV_EXT]]
; CHECK-NEXT: [[VAL:%.*]] = load i8, ptr [[SRC]], align 1
; CHECK-NEXT: store i8 [[VAL]], ptr [[DST]], align 1
; CHECK-NEXT: [[IV_NEXT]] = add i16 [[IV]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i16 [[IV_NEXT]], [[N]]
; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP]], label %[[EXIT:.*]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%iv = phi i16 [ %iv.next, %loop ], [ 1, %entry ]
%iv.ext = zext nneg i16 %iv to i64
%sub = sub nuw nsw i64 %iv.ext, 1
%src = getelementptr inbounds nuw i8, ptr %p, i64 %sub
%dst = getelementptr inbounds nuw i8, ptr %p, i64 %iv.ext
%val = load i8, ptr %src, align 1
store i8 %val, ptr %dst, align 1
%iv.next = add i16 %iv, 1
%cmp = icmp slt i16 %iv.next, %n
br i1 %cmp, label %loop, label %exit
exit:
ret void
}
define void @move_down_dec_loop_sext(i16 %n, ptr %p) {
; CHECK-LABEL: define void @move_down_dec_loop_sext(
; CHECK-SAME: i16 [[N:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV:%.*]] = phi i16 [ [[IV_NEXT:%.*]], %[[LOOP]] ], [ [[N]], %[[ENTRY]] ]
; CHECK-NEXT: [[IV_EXT:%.*]] = sext i16 [[IV]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub nuw nsw i64 [[IV_EXT]], 1
; CHECK-NEXT: [[SRC:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 [[IV_EXT]]
; CHECK-NEXT: [[DST:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 [[SUB]]
; CHECK-NEXT: [[VAL:%.*]] = load i8, ptr [[SRC]], align 1
; CHECK-NEXT: store i8 [[VAL]], ptr [[DST]], align 1
; CHECK-NEXT: [[IV_NEXT]] = add nsw i16 [[IV]], -1
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i16 [[IV_NEXT]], 0
; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP]], label %[[EXIT:.*]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%iv = phi i16 [ %iv.next, %loop ], [ %n, %entry ]
%iv.ext = sext i16 %iv to i64
%sub = sub nuw nsw i64 %iv.ext, 1
%src = getelementptr inbounds nuw i8, ptr %p, i64 %iv.ext
%dst = getelementptr inbounds nuw i8, ptr %p, i64 %sub
%val = load i8, ptr %src, align 1
store i8 %val, ptr %dst, align 1
%iv.next = add nsw i16 %iv, -1
%cmp = icmp sgt i16 %iv.next, 0
br i1 %cmp, label %loop, label %exit
exit:
ret void
}
define void @move_up_inc_loop_sext(i16 %n, ptr %p) {
; CHECK-LABEL: define void @move_up_inc_loop_sext(
; CHECK-SAME: i16 [[N:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV:%.*]] = phi i16 [ [[IV_NEXT:%.*]], %[[LOOP]] ], [ 1, %[[ENTRY]] ]
; CHECK-NEXT: [[IV_EXT:%.*]] = sext i16 [[IV]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub nuw nsw i64 [[IV_EXT]], 1
; CHECK-NEXT: [[SRC:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 [[SUB]]
; CHECK-NEXT: [[DST:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 [[IV_EXT]]
; CHECK-NEXT: [[VAL:%.*]] = load i8, ptr [[SRC]], align 1
; CHECK-NEXT: store i8 [[VAL]], ptr [[DST]], align 1
; CHECK-NEXT: [[IV_NEXT]] = add nsw i16 [[IV]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i16 [[IV_NEXT]], [[N]]
; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP]], label %[[EXIT:.*]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%iv = phi i16 [ %iv.next, %loop ], [ 1, %entry ]
%iv.ext = sext i16 %iv to i64
%sub = sub nuw nsw i64 %iv.ext, 1
%src = getelementptr inbounds nuw i8, ptr %p, i64 %sub
%dst = getelementptr inbounds nuw i8, ptr %p, i64 %iv.ext
%val = load i8, ptr %src, align 1
store i8 %val, ptr %dst, align 1
%iv.next = add nsw i16 %iv, 1
%cmp = icmp slt i16 %iv.next, %n
br i1 %cmp, label %loop, label %exit
exit:
ret void
}