Skip to content

Commit 0d9ff0b

Browse files
fhahnkcloudy0717
authored andcommitted
[LV] Add more tests for argmin finding the first index.
Add more test coverage for supporting argmin/argmax with strict predicates, in preparation for follow up to 99addbf.
1 parent 6fda75a commit 0d9ff0b

File tree

2 files changed

+262
-0
lines changed

2 files changed

+262
-0
lines changed
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals none --version 5
2+
; RUN: opt -passes=loop-vectorize -force-vector-width=4 -force-vector-interleave=1 -S %s | FileCheck %s
3+
4+
; Test cases for selecting the first index with the minimum value.
5+
6+
define i64 @test_vectorize_select_smin_first_idx(ptr %src, i64 %n) {
7+
; CHECK-LABEL: define i64 @test_vectorize_select_smin_first_idx(
8+
; CHECK-SAME: ptr [[SRC:%.*]], i64 [[N:%.*]]) {
9+
; CHECK-NEXT: [[ENTRY:.*]]:
10+
; CHECK-NEXT: br label %[[LOOP:.*]]
11+
; CHECK: [[LOOP]]:
12+
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
13+
; CHECK-NEXT: [[MIN_IDX:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[MIN_IDX_NEXT:%.*]], %[[LOOP]] ]
14+
; CHECK-NEXT: [[MIN_VAL:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[MIN_VAL_NEXT:%.*]], %[[LOOP]] ]
15+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i64, ptr [[SRC]], i64 [[IV]]
16+
; CHECK-NEXT: [[L:%.*]] = load i64, ptr [[GEP]], align 4
17+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[MIN_VAL]], [[L]]
18+
; CHECK-NEXT: [[MIN_VAL_NEXT]] = tail call i64 @llvm.smin.i64(i64 [[MIN_VAL]], i64 [[L]])
19+
; CHECK-NEXT: [[MIN_IDX_NEXT]] = select i1 [[CMP]], i64 [[IV]], i64 [[MIN_IDX]]
20+
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
21+
; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]]
22+
; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label %[[EXIT:.*]], label %[[LOOP]]
23+
; CHECK: [[EXIT]]:
24+
; CHECK-NEXT: [[RES:%.*]] = phi i64 [ [[MIN_IDX_NEXT]], %[[LOOP]] ]
25+
; CHECK-NEXT: ret i64 [[RES]]
26+
;
27+
entry:
28+
br label %loop
29+
30+
loop:
31+
%iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
32+
%min.idx = phi i64 [ 0, %entry ], [ %min.idx.next, %loop ]
33+
%min.val = phi i64 [ 0, %entry ], [ %min.val.next, %loop ]
34+
%gep = getelementptr i64, ptr %src, i64 %iv
35+
%l = load i64, ptr %gep
36+
%cmp = icmp sgt i64 %min.val, %l
37+
%min.val.next = tail call i64 @llvm.smin.i64(i64 %min.val, i64 %l)
38+
%min.idx.next = select i1 %cmp, i64 %iv, i64 %min.idx
39+
%iv.next = add nuw nsw i64 %iv, 1
40+
%exitcond.not = icmp eq i64 %iv.next, %n
41+
br i1 %exitcond.not, label %exit, label %loop
42+
43+
exit:
44+
%res = phi i64 [ %min.idx.next, %loop ]
45+
ret i64 %res
46+
}
47+
48+
define i64 @test_vectorize_select_smin_first_idx_signed_sentinel_possible(ptr %src, i64 %n) {
49+
; CHECK-LABEL: define i64 @test_vectorize_select_smin_first_idx_signed_sentinel_possible(
50+
; CHECK-SAME: ptr [[SRC:%.*]], i64 [[N:%.*]]) {
51+
; CHECK-NEXT: [[ENTRY:.*]]:
52+
; CHECK-NEXT: br label %[[LOOP:.*]]
53+
; CHECK: [[LOOP]]:
54+
; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[INDEX_NEXT:%.*]], %[[LOOP]] ]
55+
; CHECK-NEXT: [[MIN_IDX:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[MIN_IDX_NEXT:%.*]], %[[LOOP]] ]
56+
; CHECK-NEXT: [[MIN_VAL:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[MIN_VAL_NEXT:%.*]], %[[LOOP]] ]
57+
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr i64, ptr [[SRC]], i64 [[INDEX]]
58+
; CHECK-NEXT: [[L:%.*]] = load i64, ptr [[TMP0]], align 4
59+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[MIN_VAL]], [[L]]
60+
; CHECK-NEXT: [[MIN_VAL_NEXT]] = tail call i64 @llvm.smin.i64(i64 [[MIN_VAL]], i64 [[L]])
61+
; CHECK-NEXT: [[MIN_IDX_NEXT]] = select i1 [[CMP]], i64 [[INDEX]], i64 [[MIN_IDX]]
62+
; CHECK-NEXT: [[INDEX_NEXT]] = add nuw nsw i64 [[INDEX]], 1
63+
; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i64 [[INDEX_NEXT]], 100
64+
; CHECK-NEXT: br i1 [[TMP4]], label %[[EXIT:.*]], label %[[LOOP]]
65+
; CHECK: [[EXIT]]:
66+
; CHECK-NEXT: [[RDX_SELECT:%.*]] = phi i64 [ [[MIN_IDX_NEXT]], %[[LOOP]] ]
67+
; CHECK-NEXT: ret i64 [[RDX_SELECT]]
68+
;
69+
entry:
70+
br label %loop
71+
72+
loop:
73+
%iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
74+
%min.idx = phi i64 [ 0, %entry ], [ %min.idx.next, %loop ]
75+
%min.val = phi i64 [ 0, %entry ], [ %min.val.next, %loop ]
76+
%gep = getelementptr i64, ptr %src, i64 %iv
77+
%l = load i64, ptr %gep
78+
%cmp = icmp sgt i64 %min.val, %l
79+
%min.val.next = tail call i64 @llvm.smin.i64(i64 %min.val, i64 %l)
80+
%min.idx.next = select i1 %cmp, i64 %iv, i64 %min.idx
81+
%iv.next = add nuw nsw i64 %iv, 1
82+
%exitcond.not = icmp eq i64 %iv.next, 100
83+
br i1 %exitcond.not, label %exit, label %loop
84+
85+
exit:
86+
%res = phi i64 [ %min.idx.next, %loop ]
87+
ret i64 %res
88+
}
89+
90+
define i64 @test_vectorize_select_smin_first_idx_cond_flipped(ptr %src, i64 %n) {
91+
; CHECK-LABEL: define i64 @test_vectorize_select_smin_first_idx_cond_flipped(
92+
; CHECK-SAME: ptr [[SRC:%.*]], i64 [[N:%.*]]) {
93+
; CHECK-NEXT: [[ENTRY:.*]]:
94+
; CHECK-NEXT: br label %[[LOOP:.*]]
95+
; CHECK: [[LOOP]]:
96+
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
97+
; CHECK-NEXT: [[MIN_IDX:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[MIN_IDX_NEXT:%.*]], %[[LOOP]] ]
98+
; CHECK-NEXT: [[MIN_VAL:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[MIN_VAL_NEXT:%.*]], %[[LOOP]] ]
99+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i64, ptr [[SRC]], i64 [[IV]]
100+
; CHECK-NEXT: [[L:%.*]] = load i64, ptr [[GEP]], align 4
101+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[L]], [[MIN_VAL]]
102+
; CHECK-NEXT: [[MIN_VAL_NEXT]] = tail call i64 @llvm.smin.i64(i64 [[MIN_VAL]], i64 [[L]])
103+
; CHECK-NEXT: [[MIN_IDX_NEXT]] = select i1 [[CMP]], i64 [[IV]], i64 [[MIN_IDX]]
104+
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
105+
; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]]
106+
; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label %[[EXIT:.*]], label %[[LOOP]]
107+
; CHECK: [[EXIT]]:
108+
; CHECK-NEXT: [[RES:%.*]] = phi i64 [ [[MIN_IDX_NEXT]], %[[LOOP]] ]
109+
; CHECK-NEXT: ret i64 [[RES]]
110+
;
111+
entry:
112+
br label %loop
113+
114+
loop:
115+
%iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
116+
%min.idx = phi i64 [ 0, %entry ], [ %min.idx.next, %loop ]
117+
%min.val = phi i64 [ 0, %entry ], [ %min.val.next, %loop ]
118+
%gep = getelementptr i64, ptr %src, i64 %iv
119+
%l = load i64, ptr %gep
120+
%cmp = icmp slt i64 %l, %min.val
121+
%min.val.next = tail call i64 @llvm.smin.i64(i64 %min.val, i64 %l)
122+
%min.idx.next = select i1 %cmp, i64 %iv, i64 %min.idx
123+
%iv.next = add nuw nsw i64 %iv, 1
124+
%exitcond.not = icmp eq i64 %iv.next, %n
125+
br i1 %exitcond.not, label %exit, label %loop
126+
127+
exit:
128+
%res = phi i64 [ %min.idx.next, %loop ]
129+
ret i64 %res
130+
}
131+
132+
define i32 @test_vectorize_select_smin_first_idx_trunc_may_match_sentinel(ptr %src, i64 %n) {
133+
; CHECK-LABEL: define i32 @test_vectorize_select_smin_first_idx_trunc_may_match_sentinel(
134+
; CHECK-SAME: ptr [[SRC:%.*]], i64 [[N:%.*]]) {
135+
; CHECK-NEXT: [[ENTRY:.*]]:
136+
; CHECK-NEXT: br label %[[LOOP:.*]]
137+
; CHECK: [[LOOP]]:
138+
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
139+
; CHECK-NEXT: [[MIN_IDX:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[MIN_IDX_NEXT:%.*]], %[[LOOP]] ]
140+
; CHECK-NEXT: [[MIN_VAL:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[MIN_VAL_NEXT:%.*]], %[[LOOP]] ]
141+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i64, ptr [[SRC]], i64 [[IV]]
142+
; CHECK-NEXT: [[L:%.*]] = load i64, ptr [[GEP]], align 4
143+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[MIN_VAL]], [[L]]
144+
; CHECK-NEXT: [[MIN_VAL_NEXT]] = tail call i64 @llvm.smin.i64(i64 [[MIN_VAL]], i64 [[L]])
145+
; CHECK-NEXT: [[T:%.*]] = trunc i64 [[IV]] to i32
146+
; CHECK-NEXT: [[MIN_IDX_NEXT]] = select i1 [[CMP]], i32 [[T]], i32 [[MIN_IDX]]
147+
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
148+
; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]]
149+
; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label %[[EXIT:.*]], label %[[LOOP]]
150+
; CHECK: [[EXIT]]:
151+
; CHECK-NEXT: [[RES:%.*]] = phi i32 [ [[MIN_IDX_NEXT]], %[[LOOP]] ]
152+
; CHECK-NEXT: ret i32 [[RES]]
153+
;
154+
entry:
155+
br label %loop
156+
157+
loop:
158+
%iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
159+
%min.idx = phi i32 [ 0, %entry ], [ %min.idx.next, %loop ]
160+
%min.val = phi i64 [ 0, %entry ], [ %min.val.next, %loop ]
161+
%gep = getelementptr i64, ptr %src, i64 %iv
162+
%l = load i64, ptr %gep
163+
%cmp = icmp sgt i64 %min.val, %l
164+
%min.val.next = tail call i64 @llvm.smin.i64(i64 %min.val, i64 %l)
165+
%t = trunc i64 %iv to i32
166+
%min.idx.next = select i1 %cmp, i32 %t, i32 %min.idx
167+
%iv.next = add nuw nsw i64 %iv, 1
168+
%exitcond.not = icmp eq i64 %iv.next, %n
169+
br i1 %exitcond.not, label %exit, label %loop
170+
171+
exit:
172+
%res = phi i32 [ %min.idx.next, %loop ]
173+
ret i32 %res
174+
}
175+
176+
define i32 @test_vectorize_select_smin_first_idx_trunc_valid(ptr %src, i64 %n) {
177+
; CHECK-LABEL: define i32 @test_vectorize_select_smin_first_idx_trunc_valid(
178+
; CHECK-SAME: ptr [[SRC:%.*]], i64 [[N:%.*]]) {
179+
; CHECK-NEXT: [[ENTRY:.*]]:
180+
; CHECK-NEXT: br label %[[LOOP:.*]]
181+
; CHECK: [[LOOP]]:
182+
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
183+
; CHECK-NEXT: [[MIN_IDX:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[MIN_IDX_NEXT:%.*]], %[[LOOP]] ]
184+
; CHECK-NEXT: [[MIN_VAL:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[MIN_VAL_NEXT:%.*]], %[[LOOP]] ]
185+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i64, ptr [[SRC]], i64 [[IV]]
186+
; CHECK-NEXT: [[L:%.*]] = load i64, ptr [[GEP]], align 4
187+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[MIN_VAL]], [[L]]
188+
; CHECK-NEXT: [[MIN_VAL_NEXT]] = tail call i64 @llvm.smin.i64(i64 [[MIN_VAL]], i64 [[L]])
189+
; CHECK-NEXT: [[T:%.*]] = trunc i64 [[IV]] to i32
190+
; CHECK-NEXT: [[MIN_IDX_NEXT]] = select i1 [[CMP]], i32 [[T]], i32 [[MIN_IDX]]
191+
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
192+
; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i64 [[IV_NEXT]], 100
193+
; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label %[[EXIT:.*]], label %[[LOOP]]
194+
; CHECK: [[EXIT]]:
195+
; CHECK-NEXT: [[RES:%.*]] = phi i32 [ [[MIN_IDX_NEXT]], %[[LOOP]] ]
196+
; CHECK-NEXT: ret i32 [[RES]]
197+
;
198+
entry:
199+
br label %loop
200+
201+
loop:
202+
%iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
203+
%min.idx = phi i32 [ 0, %entry ], [ %min.idx.next, %loop ]
204+
%min.val = phi i64 [ 0, %entry ], [ %min.val.next, %loop ]
205+
%gep = getelementptr i64, ptr %src, i64 %iv
206+
%l = load i64, ptr %gep
207+
%cmp = icmp sgt i64 %min.val, %l
208+
%min.val.next = tail call i64 @llvm.smin.i64(i64 %min.val, i64 %l)
209+
%t = trunc i64 %iv to i32
210+
%min.idx.next = select i1 %cmp, i32 %t, i32 %min.idx
211+
%iv.next = add nuw nsw i64 %iv, 1
212+
%exitcond.not = icmp eq i64 %iv.next, 100
213+
br i1 %exitcond.not, label %exit, label %loop
214+
215+
exit:
216+
%res = phi i32 [ %min.idx.next, %loop ]
217+
ret i32 %res
218+
}

llvm/test/Transforms/LoopVectorize/select-umin-first-index.ll

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,50 @@ exit:
429429
ret i32 %res
430430
}
431431

432+
define i32 @test_vectorize_select_umin_idx_with_trunc_valid(ptr %src, i64 %n) {
433+
; CHECK-LABEL: define i32 @test_vectorize_select_umin_idx_with_trunc_valid(
434+
; CHECK-SAME: ptr [[SRC:%.*]], i64 [[N:%.*]]) {
435+
; CHECK-NEXT: [[ENTRY:.*]]:
436+
; CHECK-NEXT: br label %[[LOOP:.*]]
437+
; CHECK: [[LOOP]]:
438+
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
439+
; CHECK-NEXT: [[MIN_IDX:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[MIN_IDX_NEXT:%.*]], %[[LOOP]] ]
440+
; CHECK-NEXT: [[MIN_VAL:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[MIN_VAL_NEXT:%.*]], %[[LOOP]] ]
441+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i64, ptr [[SRC]], i64 [[IV]]
442+
; CHECK-NEXT: [[L:%.*]] = load i64, ptr [[GEP]], align 4
443+
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i64 [[MIN_VAL]], [[L]]
444+
; CHECK-NEXT: [[MIN_VAL_NEXT]] = tail call i64 @llvm.umin.i64(i64 [[MIN_VAL]], i64 [[L]])
445+
; CHECK-NEXT: [[TRUNC:%.*]] = trunc i64 [[IV]] to i32
446+
; CHECK-NEXT: [[MIN_IDX_NEXT]] = select i1 [[CMP]], i32 [[TRUNC]], i32 [[MIN_IDX]]
447+
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
448+
; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i64 [[IV_NEXT]], 100
449+
; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label %[[EXIT:.*]], label %[[LOOP]]
450+
; CHECK: [[EXIT]]:
451+
; CHECK-NEXT: [[RES:%.*]] = phi i32 [ [[MIN_IDX_NEXT]], %[[LOOP]] ]
452+
; CHECK-NEXT: ret i32 [[RES]]
453+
;
454+
entry:
455+
br label %loop
456+
457+
loop:
458+
%iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
459+
%min.idx = phi i32 [ 0, %entry ], [ %min.idx.next, %loop ]
460+
%min.val = phi i64 [ 0, %entry ], [ %min.val.next, %loop ]
461+
%gep = getelementptr i64, ptr %src, i64 %iv
462+
%l = load i64, ptr %gep
463+
%cmp = icmp ugt i64 %min.val, %l
464+
%min.val.next = tail call i64 @llvm.umin.i64(i64 %min.val, i64 %l)
465+
%trunc = trunc i64 %iv to i32
466+
%min.idx.next = select i1 %cmp, i32 %trunc, i32 %min.idx
467+
%iv.next = add nuw nsw i64 %iv, 1
468+
%exitcond.not = icmp eq i64 %iv.next, 100
469+
br i1 %exitcond.not, label %exit, label %loop
470+
471+
exit:
472+
%res = phi i32 [ %min.idx.next, %loop ]
473+
ret i32 %res
474+
}
475+
432476
define ptr @test_with_ptr_index(ptr %start, ptr %end) {
433477
; CHECK-LABEL: define ptr @test_with_ptr_index(
434478
; CHECK-SAME: ptr [[START:%.*]], ptr [[END:%.*]]) {

0 commit comments

Comments
 (0)