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