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