blob: 5ce87f6b0fcd06527b62cff5f31b90771f0a620e [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals none --version 6
; RUN: opt -passes=loop-vectorize -force-vector-width=4 -force-vector-interleave=1 -S %s | FileCheck %s
; i32 element, i32 index, strict argmax (signed).
define i32 @argmax_s32_i32idx(ptr %a, i32 %init, i32 %n) {
; CHECK-LABEL: define i32 @argmax_s32_i32idx(
; CHECK-SAME: ptr [[A:%.*]], i32 [[INIT:%.*]], i32 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[C:%.*]] = icmp sgt i32 [[N]], 1
; CHECK-NEXT: call void @llvm.assume(i1 [[C]])
; CHECK-NEXT: [[N_EXT:%.*]] = zext nneg i32 [[N]] to i64
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 1, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[MAX_VAL:%.*]] = phi i32 [ [[INIT]], %[[ENTRY]] ], [ [[MAX_VAL_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[MAX_IDX:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[MAX_IDX_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[IV]]
; CHECK-NEXT: [[L:%.*]] = load i32, ptr [[GEP]], align 4
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[L]], [[MAX_VAL]]
; CHECK-NEXT: [[T:%.*]] = trunc nuw nsw i64 [[IV]] to i32
; CHECK-NEXT: [[MAX_IDX_NEXT]] = select i1 [[CMP]], i32 [[T]], i32 [[MAX_IDX]]
; CHECK-NEXT: [[MAX_VAL_NEXT]] = tail call i32 @llvm.smax.i32(i32 [[L]], i32 [[MAX_VAL]])
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
; CHECK-NEXT: [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], [[N_EXT]]
; CHECK-NEXT: br i1 [[EC]], label %[[EXIT:.*]], label %[[LOOP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[MAX_IDX_NEXT]], %[[LOOP]] ]
; CHECK-NEXT: ret i32 [[R]]
;
entry:
%c = icmp sgt i32 %n, 1
call void @llvm.assume(i1 %c)
%n.ext = zext nneg i32 %n to i64
br label %loop
loop:
%iv = phi i64 [ 1, %entry ], [ %iv.next, %loop ]
%max.val = phi i32 [ %init, %entry ], [ %max.val.next, %loop ]
%max.idx = phi i32 [ 0, %entry ], [ %max.idx.next, %loop ]
%gep = getelementptr inbounds i32, ptr %a, i64 %iv
%l = load i32, ptr %gep
%cmp = icmp sgt i32 %l, %max.val
%t = trunc nuw nsw i64 %iv to i32
%max.idx.next = select i1 %cmp, i32 %t, i32 %max.idx
%max.val.next = tail call i32 @llvm.smax.i32(i32 %l, i32 %max.val)
%iv.next = add nuw nsw i64 %iv, 1
%ec = icmp eq i64 %iv.next, %n.ext
br i1 %ec, label %exit, label %loop
exit:
%r = phi i32 [ %max.idx.next, %loop ]
ret i32 %r
}
; i32 element, i32 index, strict argmin (signed).
define i32 @argmin_s32_i32idx(ptr %a, i32 %init, i32 %n) {
; CHECK-LABEL: define i32 @argmin_s32_i32idx(
; CHECK-SAME: ptr [[A:%.*]], i32 [[INIT:%.*]], i32 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[C:%.*]] = icmp sgt i32 [[N]], 1
; CHECK-NEXT: call void @llvm.assume(i1 [[C]])
; CHECK-NEXT: [[N_EXT:%.*]] = zext nneg i32 [[N]] to i64
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 1, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[MIN_VAL:%.*]] = phi i32 [ [[INIT]], %[[ENTRY]] ], [ [[MIN_VAL_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[MIN_IDX:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[MIN_IDX_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[IV]]
; CHECK-NEXT: [[L:%.*]] = load i32, ptr [[GEP]], align 4
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[L]], [[MIN_VAL]]
; CHECK-NEXT: [[T:%.*]] = trunc nuw nsw i64 [[IV]] to i32
; CHECK-NEXT: [[MIN_IDX_NEXT]] = select i1 [[CMP]], i32 [[T]], i32 [[MIN_IDX]]
; CHECK-NEXT: [[MIN_VAL_NEXT]] = tail call i32 @llvm.smin.i32(i32 [[L]], i32 [[MIN_VAL]])
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
; CHECK-NEXT: [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], [[N_EXT]]
; CHECK-NEXT: br i1 [[EC]], label %[[EXIT:.*]], label %[[LOOP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[MIN_IDX_NEXT]], %[[LOOP]] ]
; CHECK-NEXT: ret i32 [[R]]
;
entry:
%c = icmp sgt i32 %n, 1
call void @llvm.assume(i1 %c)
%n.ext = zext nneg i32 %n to i64
br label %loop
loop:
%iv = phi i64 [ 1, %entry ], [ %iv.next, %loop ]
%min.val = phi i32 [ %init, %entry ], [ %min.val.next, %loop ]
%min.idx = phi i32 [ 0, %entry ], [ %min.idx.next, %loop ]
%gep = getelementptr inbounds i32, ptr %a, i64 %iv
%l = load i32, ptr %gep
%cmp = icmp slt i32 %l, %min.val
%t = trunc nuw nsw i64 %iv to i32
%min.idx.next = select i1 %cmp, i32 %t, i32 %min.idx
%min.val.next = tail call i32 @llvm.smin.i32(i32 %l, i32 %min.val)
%iv.next = add nuw nsw i64 %iv, 1
%ec = icmp eq i64 %iv.next, %n.ext
br i1 %ec, label %exit, label %loop
exit:
%r = phi i32 [ %min.idx.next, %loop ]
ret i32 %r
}
; i32 element, i32 index, strict argmax (unsigned).
define i32 @argmax_u32_i32idx(ptr %a, i32 %init, i32 %n) {
; CHECK-LABEL: define i32 @argmax_u32_i32idx(
; CHECK-SAME: ptr [[A:%.*]], i32 [[INIT:%.*]], i32 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[C:%.*]] = icmp sgt i32 [[N]], 1
; CHECK-NEXT: call void @llvm.assume(i1 [[C]])
; CHECK-NEXT: [[N_EXT:%.*]] = zext nneg i32 [[N]] to i64
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 1, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[MAX_VAL:%.*]] = phi i32 [ [[INIT]], %[[ENTRY]] ], [ [[MAX_VAL_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[MAX_IDX:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[MAX_IDX_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[IV]]
; CHECK-NEXT: [[L:%.*]] = load i32, ptr [[GEP]], align 4
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[L]], [[MAX_VAL]]
; CHECK-NEXT: [[T:%.*]] = trunc nuw nsw i64 [[IV]] to i32
; CHECK-NEXT: [[MAX_IDX_NEXT]] = select i1 [[CMP]], i32 [[T]], i32 [[MAX_IDX]]
; CHECK-NEXT: [[MAX_VAL_NEXT]] = tail call i32 @llvm.umax.i32(i32 [[L]], i32 [[MAX_VAL]])
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
; CHECK-NEXT: [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], [[N_EXT]]
; CHECK-NEXT: br i1 [[EC]], label %[[EXIT:.*]], label %[[LOOP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[MAX_IDX_NEXT]], %[[LOOP]] ]
; CHECK-NEXT: ret i32 [[R]]
;
entry:
%c = icmp sgt i32 %n, 1
call void @llvm.assume(i1 %c)
%n.ext = zext nneg i32 %n to i64
br label %loop
loop:
%iv = phi i64 [ 1, %entry ], [ %iv.next, %loop ]
%max.val = phi i32 [ %init, %entry ], [ %max.val.next, %loop ]
%max.idx = phi i32 [ 0, %entry ], [ %max.idx.next, %loop ]
%gep = getelementptr inbounds i32, ptr %a, i64 %iv
%l = load i32, ptr %gep
%cmp = icmp ugt i32 %l, %max.val
%t = trunc nuw nsw i64 %iv to i32
%max.idx.next = select i1 %cmp, i32 %t, i32 %max.idx
%max.val.next = tail call i32 @llvm.umax.i32(i32 %l, i32 %max.val)
%iv.next = add nuw nsw i64 %iv, 1
%ec = icmp eq i64 %iv.next, %n.ext
br i1 %ec, label %exit, label %loop
exit:
%r = phi i32 [ %max.idx.next, %loop ]
ret i32 %r
}
; i8 element, i32 index, strict argmax (signed).
define i32 @argmax_s8_i32idx(ptr %a, i8 %init, i32 %n) {
; CHECK-LABEL: define i32 @argmax_s8_i32idx(
; CHECK-SAME: ptr [[A:%.*]], i8 [[INIT:%.*]], i32 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[C:%.*]] = icmp sgt i32 [[N]], 1
; CHECK-NEXT: call void @llvm.assume(i1 [[C]])
; CHECK-NEXT: [[N_EXT:%.*]] = zext nneg i32 [[N]] to i64
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 1, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[MAX_VAL:%.*]] = phi i8 [ [[INIT]], %[[ENTRY]] ], [ [[MAX_VAL_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[MAX_IDX:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[MAX_IDX_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[IV]]
; CHECK-NEXT: [[L:%.*]] = load i8, ptr [[GEP]], align 1
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[L]], [[MAX_VAL]]
; CHECK-NEXT: [[T:%.*]] = trunc nuw nsw i64 [[IV]] to i32
; CHECK-NEXT: [[MAX_IDX_NEXT]] = select i1 [[CMP]], i32 [[T]], i32 [[MAX_IDX]]
; CHECK-NEXT: [[MAX_VAL_NEXT]] = tail call i8 @llvm.smax.i8(i8 [[L]], i8 [[MAX_VAL]])
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
; CHECK-NEXT: [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], [[N_EXT]]
; CHECK-NEXT: br i1 [[EC]], label %[[EXIT:.*]], label %[[LOOP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[MAX_IDX_NEXT]], %[[LOOP]] ]
; CHECK-NEXT: ret i32 [[R]]
;
entry:
%c = icmp sgt i32 %n, 1
call void @llvm.assume(i1 %c)
%n.ext = zext nneg i32 %n to i64
br label %loop
loop:
%iv = phi i64 [ 1, %entry ], [ %iv.next, %loop ]
%max.val = phi i8 [ %init, %entry ], [ %max.val.next, %loop ]
%max.idx = phi i32 [ 0, %entry ], [ %max.idx.next, %loop ]
%gep = getelementptr inbounds i8, ptr %a, i64 %iv
%l = load i8, ptr %gep
%cmp = icmp sgt i8 %l, %max.val
%t = trunc nuw nsw i64 %iv to i32
%max.idx.next = select i1 %cmp, i32 %t, i32 %max.idx
%max.val.next = tail call i8 @llvm.smax.i8(i8 %l, i8 %max.val)
%iv.next = add nuw nsw i64 %iv, 1
%ec = icmp eq i64 %iv.next, %n.ext
br i1 %ec, label %exit, label %loop
exit:
%r = phi i32 [ %max.idx.next, %loop ]
ret i32 %r
}
; i16 element, i32 index, strict argmax (signed).
define i32 @argmax_s16_i32idx(ptr %a, i16 %init, i32 %n) {
; CHECK-LABEL: define i32 @argmax_s16_i32idx(
; CHECK-SAME: ptr [[A:%.*]], i16 [[INIT:%.*]], i32 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[C:%.*]] = icmp sgt i32 [[N]], 1
; CHECK-NEXT: call void @llvm.assume(i1 [[C]])
; CHECK-NEXT: [[N_EXT:%.*]] = zext nneg i32 [[N]] to i64
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 1, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[MAX_VAL:%.*]] = phi i16 [ [[INIT]], %[[ENTRY]] ], [ [[MAX_VAL_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[MAX_IDX:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[MAX_IDX_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i16, ptr [[A]], i64 [[IV]]
; CHECK-NEXT: [[L:%.*]] = load i16, ptr [[GEP]], align 2
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i16 [[L]], [[MAX_VAL]]
; CHECK-NEXT: [[T:%.*]] = trunc nuw nsw i64 [[IV]] to i32
; CHECK-NEXT: [[MAX_IDX_NEXT]] = select i1 [[CMP]], i32 [[T]], i32 [[MAX_IDX]]
; CHECK-NEXT: [[MAX_VAL_NEXT]] = tail call i16 @llvm.smax.i16(i16 [[L]], i16 [[MAX_VAL]])
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
; CHECK-NEXT: [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], [[N_EXT]]
; CHECK-NEXT: br i1 [[EC]], label %[[EXIT:.*]], label %[[LOOP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[MAX_IDX_NEXT]], %[[LOOP]] ]
; CHECK-NEXT: ret i32 [[R]]
;
entry:
%c = icmp sgt i32 %n, 1
call void @llvm.assume(i1 %c)
%n.ext = zext nneg i32 %n to i64
br label %loop
loop:
%iv = phi i64 [ 1, %entry ], [ %iv.next, %loop ]
%max.val = phi i16 [ %init, %entry ], [ %max.val.next, %loop ]
%max.idx = phi i32 [ 0, %entry ], [ %max.idx.next, %loop ]
%gep = getelementptr inbounds i16, ptr %a, i64 %iv
%l = load i16, ptr %gep
%cmp = icmp sgt i16 %l, %max.val
%t = trunc nuw nsw i64 %iv to i32
%max.idx.next = select i1 %cmp, i32 %t, i32 %max.idx
%max.val.next = tail call i16 @llvm.smax.i16(i16 %l, i16 %max.val)
%iv.next = add nuw nsw i64 %iv, 1
%ec = icmp eq i64 %iv.next, %n.ext
br i1 %ec, label %exit, label %loop
exit:
%r = phi i32 [ %max.idx.next, %loop ]
ret i32 %r
}
; i64 element, i32 index, strict argmax (signed).
define i32 @argmax_s64_i32idx(ptr %a, i64 %init, i32 %n) {
; CHECK-LABEL: define i32 @argmax_s64_i32idx(
; CHECK-SAME: ptr [[A:%.*]], i64 [[INIT:%.*]], i32 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[C:%.*]] = icmp sgt i32 [[N]], 1
; CHECK-NEXT: call void @llvm.assume(i1 [[C]])
; CHECK-NEXT: [[N_EXT:%.*]] = zext nneg i32 [[N]] to i64
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 1, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[MAX_VAL:%.*]] = phi i64 [ [[INIT]], %[[ENTRY]] ], [ [[MAX_VAL_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[MAX_IDX:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[MAX_IDX_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i64, ptr [[A]], i64 [[IV]]
; CHECK-NEXT: [[L:%.*]] = load i64, ptr [[GEP]], align 4
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[L]], [[MAX_VAL]]
; CHECK-NEXT: [[T:%.*]] = trunc nuw nsw i64 [[IV]] to i32
; CHECK-NEXT: [[MAX_IDX_NEXT]] = select i1 [[CMP]], i32 [[T]], i32 [[MAX_IDX]]
; CHECK-NEXT: [[MAX_VAL_NEXT]] = tail call i64 @llvm.smax.i64(i64 [[L]], i64 [[MAX_VAL]])
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
; CHECK-NEXT: [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], [[N_EXT]]
; CHECK-NEXT: br i1 [[EC]], label %[[EXIT:.*]], label %[[LOOP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[MAX_IDX_NEXT]], %[[LOOP]] ]
; CHECK-NEXT: ret i32 [[R]]
;
entry:
%c = icmp sgt i32 %n, 1
call void @llvm.assume(i1 %c)
%n.ext = zext nneg i32 %n to i64
br label %loop
loop:
%iv = phi i64 [ 1, %entry ], [ %iv.next, %loop ]
%max.val = phi i64 [ %init, %entry ], [ %max.val.next, %loop ]
%max.idx = phi i32 [ 0, %entry ], [ %max.idx.next, %loop ]
%gep = getelementptr inbounds i64, ptr %a, i64 %iv
%l = load i64, ptr %gep
%cmp = icmp sgt i64 %l, %max.val
%t = trunc nuw nsw i64 %iv to i32
%max.idx.next = select i1 %cmp, i32 %t, i32 %max.idx
%max.val.next = tail call i64 @llvm.smax.i64(i64 %l, i64 %max.val)
%iv.next = add nuw nsw i64 %iv, 1
%ec = icmp eq i64 %iv.next, %n.ext
br i1 %ec, label %exit, label %loop
exit:
%r = phi i32 [ %max.idx.next, %loop ]
ret i32 %r
}
; i32 index with an unconstrained i64 trip count.
define i32 @argmax_s32_i32idx_unknown_i64_tc(ptr %a, i32 %init, i64 %n) {
; CHECK-LABEL: define i32 @argmax_s32_i32idx_unknown_i64_tc(
; CHECK-SAME: ptr [[A:%.*]], i32 [[INIT:%.*]], i64 [[N:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 1, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[MAX_VAL:%.*]] = phi i32 [ [[INIT]], %[[ENTRY]] ], [ [[MAX_VAL_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[MAX_IDX:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[MAX_IDX_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[IV]]
; CHECK-NEXT: [[L:%.*]] = load i32, ptr [[GEP]], align 4
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[L]], [[MAX_VAL]]
; CHECK-NEXT: [[T:%.*]] = trunc i64 [[IV]] to i32
; CHECK-NEXT: [[MAX_IDX_NEXT]] = select i1 [[CMP]], i32 [[T]], i32 [[MAX_IDX]]
; CHECK-NEXT: [[MAX_VAL_NEXT]] = tail call i32 @llvm.smax.i32(i32 [[L]], i32 [[MAX_VAL]])
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
; CHECK-NEXT: [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]]
; CHECK-NEXT: br i1 [[EC]], label %[[EXIT:.*]], label %[[LOOP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[MAX_IDX_NEXT]], %[[LOOP]] ]
; CHECK-NEXT: ret i32 [[R]]
;
entry:
br label %loop
loop:
%iv = phi i64 [ 1, %entry ], [ %iv.next, %loop ]
%max.val = phi i32 [ %init, %entry ], [ %max.val.next, %loop ]
%max.idx = phi i32 [ 0, %entry ], [ %max.idx.next, %loop ]
%gep = getelementptr inbounds i32, ptr %a, i64 %iv
%l = load i32, ptr %gep
%cmp = icmp sgt i32 %l, %max.val
%t = trunc i64 %iv to i32
%max.idx.next = select i1 %cmp, i32 %t, i32 %max.idx
%max.val.next = tail call i32 @llvm.smax.i32(i32 %l, i32 %max.val)
%iv.next = add nuw nsw i64 %iv, 1
%ec = icmp eq i64 %iv.next, %n
br i1 %ec, label %exit, label %loop
exit:
%r = phi i32 [ %max.idx.next, %loop ]
ret i32 %r
}
; Sentinel boundary: i16 index at trip count 65536 hits the UMin sentinel.
; FIXME: currently indistinguishable from below_sentinel: both bail out in
; handleFirstArgMinOrMax before the sentinel is ever computed.
define i32 @argmax_s32_i16idx_at_sentinel(ptr %a, i32 %init) {
; CHECK-LABEL: define i32 @argmax_s32_i16idx_at_sentinel(
; CHECK-SAME: ptr [[A:%.*]], i32 [[INIT:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 1, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[MAX_VAL:%.*]] = phi i32 [ [[INIT]], %[[ENTRY]] ], [ [[MAX_VAL_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[MAX_IDX:%.*]] = phi i16 [ 0, %[[ENTRY]] ], [ [[MAX_IDX_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[IV]]
; CHECK-NEXT: [[L:%.*]] = load i32, ptr [[GEP]], align 4
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[L]], [[MAX_VAL]]
; CHECK-NEXT: [[T:%.*]] = trunc i64 [[IV]] to i16
; CHECK-NEXT: [[MAX_IDX_NEXT]] = select i1 [[CMP]], i16 [[T]], i16 [[MAX_IDX]]
; CHECK-NEXT: [[MAX_VAL_NEXT]] = tail call i32 @llvm.smax.i32(i32 [[L]], i32 [[MAX_VAL]])
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
; CHECK-NEXT: [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], 65536
; CHECK-NEXT: br i1 [[EC]], label %[[EXIT:.*]], label %[[LOOP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[R:%.*]] = phi i16 [ [[MAX_IDX_NEXT]], %[[LOOP]] ]
; CHECK-NEXT: [[RE:%.*]] = zext i16 [[R]] to i32
; CHECK-NEXT: ret i32 [[RE]]
;
entry:
br label %loop
loop:
%iv = phi i64 [ 1, %entry ], [ %iv.next, %loop ]
%max.val = phi i32 [ %init, %entry ], [ %max.val.next, %loop ]
%max.idx = phi i16 [ 0, %entry ], [ %max.idx.next, %loop ]
%gep = getelementptr inbounds i32, ptr %a, i64 %iv
%l = load i32, ptr %gep
%cmp = icmp sgt i32 %l, %max.val
%t = trunc i64 %iv to i16
%max.idx.next = select i1 %cmp, i16 %t, i16 %max.idx
%max.val.next = tail call i32 @llvm.smax.i32(i32 %l, i32 %max.val)
%iv.next = add nuw nsw i64 %iv, 1
%ec = icmp eq i64 %iv.next, 65536
br i1 %ec, label %exit, label %loop
exit:
%r = phi i16 [ %max.idx.next, %loop ]
%re = zext i16 %r to i32
ret i32 %re
}
; Sentinel boundary: i16 index at trip count 65535, just below the sentinel.
define i32 @argmax_s32_i16idx_below_sentinel(ptr %a, i32 %init) {
; CHECK-LABEL: define i32 @argmax_s32_i16idx_below_sentinel(
; CHECK-SAME: ptr [[A:%.*]], i32 [[INIT:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 1, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[MAX_VAL:%.*]] = phi i32 [ [[INIT]], %[[ENTRY]] ], [ [[MAX_VAL_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[MAX_IDX:%.*]] = phi i16 [ 0, %[[ENTRY]] ], [ [[MAX_IDX_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[IV]]
; CHECK-NEXT: [[L:%.*]] = load i32, ptr [[GEP]], align 4
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[L]], [[MAX_VAL]]
; CHECK-NEXT: [[T:%.*]] = trunc i64 [[IV]] to i16
; CHECK-NEXT: [[MAX_IDX_NEXT]] = select i1 [[CMP]], i16 [[T]], i16 [[MAX_IDX]]
; CHECK-NEXT: [[MAX_VAL_NEXT]] = tail call i32 @llvm.smax.i32(i32 [[L]], i32 [[MAX_VAL]])
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
; CHECK-NEXT: [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], 65535
; CHECK-NEXT: br i1 [[EC]], label %[[EXIT:.*]], label %[[LOOP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[R:%.*]] = phi i16 [ [[MAX_IDX_NEXT]], %[[LOOP]] ]
; CHECK-NEXT: [[RE:%.*]] = zext i16 [[R]] to i32
; CHECK-NEXT: ret i32 [[RE]]
;
entry:
br label %loop
loop:
%iv = phi i64 [ 1, %entry ], [ %iv.next, %loop ]
%max.val = phi i32 [ %init, %entry ], [ %max.val.next, %loop ]
%max.idx = phi i16 [ 0, %entry ], [ %max.idx.next, %loop ]
%gep = getelementptr inbounds i32, ptr %a, i64 %iv
%l = load i32, ptr %gep
%cmp = icmp sgt i32 %l, %max.val
%t = trunc i64 %iv to i16
%max.idx.next = select i1 %cmp, i16 %t, i16 %max.idx
%max.val.next = tail call i32 @llvm.smax.i32(i32 %l, i32 %max.val)
%iv.next = add nuw nsw i64 %iv, 1
%ec = icmp eq i64 %iv.next, 65535
br i1 %ec, label %exit, label %loop
exit:
%r = phi i16 [ %max.idx.next, %loop ]
%re = zext i16 %r to i32
ret i32 %re
}
; A non-canonical IV (start 5, step 3) with a narrow index.
define i32 @argmax_s32_i32idx_non_canonical_iv(ptr %a, i32 %init) {
; CHECK-LABEL: define i32 @argmax_s32_i32idx_non_canonical_iv(
; CHECK-SAME: ptr [[A:%.*]], i32 [[INIT:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 5, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[MAX_VAL:%.*]] = phi i32 [ [[INIT]], %[[ENTRY]] ], [ [[MAX_VAL_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[MAX_IDX:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[MAX_IDX_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[IV]]
; CHECK-NEXT: [[L:%.*]] = load i32, ptr [[GEP]], align 4
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[L]], [[MAX_VAL]]
; CHECK-NEXT: [[T:%.*]] = trunc i64 [[IV]] to i32
; CHECK-NEXT: [[MAX_IDX_NEXT]] = select i1 [[CMP]], i32 [[T]], i32 [[MAX_IDX]]
; CHECK-NEXT: [[MAX_VAL_NEXT]] = tail call i32 @llvm.smax.i32(i32 [[L]], i32 [[MAX_VAL]])
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 3
; CHECK-NEXT: [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], 3005
; CHECK-NEXT: br i1 [[EC]], label %[[EXIT:.*]], label %[[LOOP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[MAX_IDX_NEXT]], %[[LOOP]] ]
; CHECK-NEXT: ret i32 [[R]]
;
entry:
br label %loop
loop:
%iv = phi i64 [ 5, %entry ], [ %iv.next, %loop ]
%max.val = phi i32 [ %init, %entry ], [ %max.val.next, %loop ]
%max.idx = phi i32 [ 0, %entry ], [ %max.idx.next, %loop ]
%gep = getelementptr inbounds i32, ptr %a, i64 %iv
%l = load i32, ptr %gep
%cmp = icmp sgt i32 %l, %max.val
%t = trunc i64 %iv to i32
%max.idx.next = select i1 %cmp, i32 %t, i32 %max.idx
%max.val.next = tail call i32 @llvm.smax.i32(i32 %l, i32 %max.val)
%iv.next = add nuw nsw i64 %iv, 3
%ec = icmp eq i64 %iv.next, 3005
br i1 %ec, label %exit, label %loop
exit:
%r = phi i32 [ %max.idx.next, %loop ]
ret i32 %r
}