Skip to content

Commit 9d24a8e

Browse files
committed
[PhaseOrdering] Add test for missed vectorization with vector::at calls.
This test illustrates missed vectorization of loops with multiple std::vector::at calls, like int sum(std::vector<int> *A, std::vector<int> *B, int N) { int cost = 0; for (int i = 0; i < N; ++i) cost += A->at(i) + B->at(i); return cost; } https://clang.godbolt.org/z/KbYoaPhvq (cherry-picked from 39cc0b8c68b8d316954ecfac0d1f8498ea42866c)
1 parent 4185752 commit 9d24a8e

File tree

1 file changed

+196
-0
lines changed

1 file changed

+196
-0
lines changed
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2+
; RUN: opt -O2 -mtriple=arm64-apple-ios -S %s | FileCheck %s
3+
4+
%vec = type { i64*, i64* }
5+
6+
; Test to ensure a loop with multiple loads guarded by runtime-checks (like
7+
; from multiple calls to C++'s std::vector::at) can be vectorized after
8+
; hoisting the runtime checks out of the loop.
9+
10+
define i64 @sum_2_at_with_int_conversion(%vec* %A, %vec* %B, i64 %N) {
11+
; CHECK-LABEL: @sum_2_at_with_int_conversion(
12+
; CHECK-NEXT: entry:
13+
; CHECK-NEXT: [[GEP_START_I:%.*]] = getelementptr [[VEC:%.*]], %vec* [[A:%.*]], i64 0, i32 0
14+
; CHECK-NEXT: [[START_I:%.*]] = load i64*, i64** [[GEP_START_I]], align 8
15+
; CHECK-NEXT: [[GEP_END_I:%.*]] = getelementptr [[VEC]], %vec* [[A]], i64 0, i32 1
16+
; CHECK-NEXT: [[END_I:%.*]] = load i64*, i64** [[GEP_END_I]], align 8
17+
; CHECK-NEXT: [[START_INT_I:%.*]] = ptrtoint i64* [[START_I]] to i64
18+
; CHECK-NEXT: [[END_INT_I:%.*]] = ptrtoint i64* [[END_I]] to i64
19+
; CHECK-NEXT: [[SUB_I:%.*]] = sub i64 [[END_INT_I]], [[START_INT_I]]
20+
; CHECK-NEXT: [[GEP_START_I1:%.*]] = getelementptr [[VEC]], %vec* [[B:%.*]], i64 0, i32 0
21+
; CHECK-NEXT: [[GEP_END_I3:%.*]] = getelementptr [[VEC]], %vec* [[B]], i64 0, i32 1
22+
; CHECK-NEXT: br label [[LOOP:%.*]]
23+
; CHECK: loop:
24+
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[AT_WITH_INT_CONVERSION_EXIT12:%.*]] ]
25+
; CHECK-NEXT: [[SUM:%.*]] = phi i64 [ 0, [[ENTRY]] ], [ [[SUM_NEXT:%.*]], [[AT_WITH_INT_CONVERSION_EXIT12]] ]
26+
; CHECK-NEXT: [[INRANGE_I:%.*]] = icmp ult i64 [[SUB_I]], [[IV]]
27+
; CHECK-NEXT: br i1 [[INRANGE_I]], label [[ERROR_I:%.*]], label [[AT_WITH_INT_CONVERSION_EXIT:%.*]]
28+
; CHECK: error.i:
29+
; CHECK-NEXT: tail call void @error()
30+
; CHECK-NEXT: unreachable
31+
; CHECK: at_with_int_conversion.exit:
32+
; CHECK-NEXT: [[START_I2:%.*]] = load i64*, i64** [[GEP_START_I1]], align 8
33+
; CHECK-NEXT: [[END_I4:%.*]] = load i64*, i64** [[GEP_END_I3]], align 8
34+
; CHECK-NEXT: [[START_INT_I5:%.*]] = ptrtoint i64* [[START_I2]] to i64
35+
; CHECK-NEXT: [[END_INT_I6:%.*]] = ptrtoint i64* [[END_I4]] to i64
36+
; CHECK-NEXT: [[SUB_I7:%.*]] = sub i64 [[END_INT_I6]], [[START_INT_I5]]
37+
; CHECK-NEXT: [[INRANGE_I8:%.*]] = icmp ult i64 [[SUB_I7]], [[IV]]
38+
; CHECK-NEXT: br i1 [[INRANGE_I8]], label [[ERROR_I11:%.*]], label [[AT_WITH_INT_CONVERSION_EXIT12]]
39+
; CHECK: error.i11:
40+
; CHECK-NEXT: tail call void @error()
41+
; CHECK-NEXT: unreachable
42+
; CHECK: at_with_int_conversion.exit12:
43+
; CHECK-NEXT: [[GEP_IDX_I:%.*]] = getelementptr i64, i64* [[START_I]], i64 [[IV]]
44+
; CHECK-NEXT: [[LV_I:%.*]] = load i64, i64* [[GEP_IDX_I]], align 4
45+
; CHECK-NEXT: [[GEP_IDX_I9:%.*]] = getelementptr i64, i64* [[START_I2]], i64 [[IV]]
46+
; CHECK-NEXT: [[LV_I10:%.*]] = load i64, i64* [[GEP_IDX_I9]], align 4
47+
; CHECK-NEXT: [[ADD:%.*]] = add i64 [[LV_I]], [[SUM]]
48+
; CHECK-NEXT: [[SUM_NEXT]] = add i64 [[ADD]], [[LV_I10]]
49+
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
50+
; CHECK-NEXT: [[C:%.*]] = icmp slt i64 [[IV]], [[N:%.*]]
51+
; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
52+
; CHECK: exit:
53+
; CHECK-NEXT: ret i64 [[SUM_NEXT]]
54+
;
55+
entry:
56+
br label %loop
57+
58+
loop:
59+
%iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
60+
%sum = phi i64 [ 0, %entry ], [ %sum.next, %loop ]
61+
%a = call i64 @at_with_int_conversion(%vec* %A, i64 %iv)
62+
%b = call i64 @at_with_int_conversion(%vec* %B, i64 %iv)
63+
%add = add i64 %a, %b
64+
%sum.next = add i64 %sum, %add
65+
%iv.next = add nuw nsw i64 %iv, 1
66+
%c = icmp slt i64 %iv, %N
67+
br i1 %c, label %loop, label %exit
68+
69+
exit:
70+
ret i64 %sum.next
71+
}
72+
73+
define i64 @sum_3_at_with_int_conversion(%vec* %A, %vec* %B, %vec* %C, i64 %N) {
74+
; CHECK-LABEL: @sum_3_at_with_int_conversion(
75+
; CHECK-NEXT: entry:
76+
; CHECK-NEXT: [[GEP_START_I:%.*]] = getelementptr [[VEC:%.*]], %vec* [[A:%.*]], i64 0, i32 0
77+
; CHECK-NEXT: [[START_I:%.*]] = load i64*, i64** [[GEP_START_I]], align 8
78+
; CHECK-NEXT: [[GEP_END_I:%.*]] = getelementptr [[VEC]], %vec* [[A]], i64 0, i32 1
79+
; CHECK-NEXT: [[END_I:%.*]] = load i64*, i64** [[GEP_END_I]], align 8
80+
; CHECK-NEXT: [[START_INT_I:%.*]] = ptrtoint i64* [[START_I]] to i64
81+
; CHECK-NEXT: [[END_INT_I:%.*]] = ptrtoint i64* [[END_I]] to i64
82+
; CHECK-NEXT: [[SUB_I:%.*]] = sub i64 [[END_INT_I]], [[START_INT_I]]
83+
; CHECK-NEXT: [[GEP_START_I1:%.*]] = getelementptr [[VEC]], %vec* [[B:%.*]], i64 0, i32 0
84+
; CHECK-NEXT: [[GEP_END_I3:%.*]] = getelementptr [[VEC]], %vec* [[B]], i64 0, i32 1
85+
; CHECK-NEXT: [[GEP_START_I13:%.*]] = getelementptr [[VEC]], %vec* [[C:%.*]], i64 0, i32 0
86+
; CHECK-NEXT: [[GEP_END_I15:%.*]] = getelementptr [[VEC]], %vec* [[C]], i64 0, i32 1
87+
; CHECK-NEXT: br label [[LOOP:%.*]]
88+
; CHECK: loop:
89+
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[AT_WITH_INT_CONVERSION_EXIT24:%.*]] ]
90+
; CHECK-NEXT: [[SUM:%.*]] = phi i64 [ 0, [[ENTRY]] ], [ [[SUM_NEXT:%.*]], [[AT_WITH_INT_CONVERSION_EXIT24]] ]
91+
; CHECK-NEXT: [[INRANGE_I:%.*]] = icmp ult i64 [[SUB_I]], [[IV]]
92+
; CHECK-NEXT: br i1 [[INRANGE_I]], label [[ERROR_I:%.*]], label [[AT_WITH_INT_CONVERSION_EXIT:%.*]]
93+
; CHECK: error.i:
94+
; CHECK-NEXT: tail call void @error()
95+
; CHECK-NEXT: unreachable
96+
; CHECK: at_with_int_conversion.exit:
97+
; CHECK-NEXT: [[GEP_IDX_I:%.*]] = getelementptr i64, i64* [[START_I]], i64 [[IV]]
98+
; CHECK-NEXT: [[LV_I:%.*]] = load i64, i64* [[GEP_IDX_I]], align 4
99+
; CHECK-NEXT: [[START_I2:%.*]] = load i64*, i64** [[GEP_START_I1]], align 8
100+
; CHECK-NEXT: [[END_I4:%.*]] = load i64*, i64** [[GEP_END_I3]], align 8
101+
; CHECK-NEXT: [[START_INT_I5:%.*]] = ptrtoint i64* [[START_I2]] to i64
102+
; CHECK-NEXT: [[END_INT_I6:%.*]] = ptrtoint i64* [[END_I4]] to i64
103+
; CHECK-NEXT: [[SUB_I7:%.*]] = sub i64 [[END_INT_I6]], [[START_INT_I5]]
104+
; CHECK-NEXT: [[INRANGE_I8:%.*]] = icmp ult i64 [[SUB_I7]], [[IV]]
105+
; CHECK-NEXT: br i1 [[INRANGE_I8]], label [[ERROR_I11:%.*]], label [[AT_WITH_INT_CONVERSION_EXIT12:%.*]]
106+
; CHECK: error.i11:
107+
; CHECK-NEXT: tail call void @error()
108+
; CHECK-NEXT: unreachable
109+
; CHECK: at_with_int_conversion.exit12:
110+
; CHECK-NEXT: [[START_I14:%.*]] = load i64*, i64** [[GEP_START_I13]], align 8
111+
; CHECK-NEXT: [[END_I16:%.*]] = load i64*, i64** [[GEP_END_I15]], align 8
112+
; CHECK-NEXT: [[START_INT_I17:%.*]] = ptrtoint i64* [[START_I14]] to i64
113+
; CHECK-NEXT: [[END_INT_I18:%.*]] = ptrtoint i64* [[END_I16]] to i64
114+
; CHECK-NEXT: [[SUB_I19:%.*]] = sub i64 [[END_INT_I18]], [[START_INT_I17]]
115+
; CHECK-NEXT: [[INRANGE_I20:%.*]] = icmp ult i64 [[SUB_I19]], [[IV]]
116+
; CHECK-NEXT: br i1 [[INRANGE_I20]], label [[ERROR_I23:%.*]], label [[AT_WITH_INT_CONVERSION_EXIT24]]
117+
; CHECK: error.i23:
118+
; CHECK-NEXT: tail call void @error()
119+
; CHECK-NEXT: unreachable
120+
; CHECK: at_with_int_conversion.exit24:
121+
; CHECK-NEXT: [[GEP_IDX_I9:%.*]] = getelementptr i64, i64* [[START_I2]], i64 [[IV]]
122+
; CHECK-NEXT: [[LV_I10:%.*]] = load i64, i64* [[GEP_IDX_I9]], align 4
123+
; CHECK-NEXT: [[GEP_IDX_I21:%.*]] = getelementptr i64, i64* [[START_I14]], i64 [[IV]]
124+
; CHECK-NEXT: [[LV_I22:%.*]] = load i64, i64* [[GEP_IDX_I21]], align 4
125+
; CHECK-NEXT: [[ADD_1:%.*]] = add i64 [[LV_I]], [[SUM]]
126+
; CHECK-NEXT: [[ADD_2:%.*]] = add i64 [[ADD_1]], [[LV_I10]]
127+
; CHECK-NEXT: [[SUM_NEXT]] = add i64 [[ADD_2]], [[LV_I22]]
128+
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
129+
; CHECK-NEXT: [[COND:%.*]] = icmp slt i64 [[IV]], [[N:%.*]]
130+
; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]]
131+
; CHECK: exit:
132+
; CHECK-NEXT: ret i64 [[SUM_NEXT]]
133+
;
134+
entry:
135+
br label %loop
136+
137+
loop:
138+
%iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
139+
%sum = phi i64 [ 0, %entry ], [ %sum.next, %loop ]
140+
%a = call i64 @at_with_int_conversion(%vec* %A, i64 %iv)
141+
%b = call i64 @at_with_int_conversion(%vec* %B, i64 %iv)
142+
%c = call i64 @at_with_int_conversion(%vec* %C, i64 %iv)
143+
%add.1 = add i64 %a, %b
144+
%add.2 = add i64 %add.1, %c
145+
%sum.next = add i64 %sum, %add.2
146+
%iv.next = add nuw nsw i64 %iv, 1
147+
%cond = icmp slt i64 %iv, %N
148+
br i1 %cond, label %loop, label %exit
149+
150+
exit:
151+
ret i64 %sum.next
152+
}
153+
154+
155+
define i64 @at_with_int_conversion(%vec* %ptr, i64 %idx) {
156+
; CHECK-LABEL: @at_with_int_conversion(
157+
; CHECK-NEXT: [[GEP_START:%.*]] = getelementptr [[VEC:%.*]], %vec* [[PTR:%.*]], i64 0, i32 0
158+
; CHECK-NEXT: [[START:%.*]] = load i64*, i64** [[GEP_START]], align 8
159+
; CHECK-NEXT: [[GEP_END:%.*]] = getelementptr [[VEC]], %vec* [[PTR]], i64 0, i32 1
160+
; CHECK-NEXT: [[END:%.*]] = load i64*, i64** [[GEP_END]], align 8
161+
; CHECK-NEXT: [[START_INT:%.*]] = ptrtoint i64* [[START]] to i64
162+
; CHECK-NEXT: [[END_INT:%.*]] = ptrtoint i64* [[END]] to i64
163+
; CHECK-NEXT: [[SUB:%.*]] = sub i64 [[END_INT]], [[START_INT]]
164+
; CHECK-NEXT: [[INRANGE:%.*]] = icmp ult i64 [[SUB]], [[IDX:%.*]]
165+
; CHECK-NEXT: br i1 [[INRANGE]], label [[ERROR:%.*]], label [[EXIT:%.*]]
166+
; CHECK: exit:
167+
; CHECK-NEXT: [[GEP_IDX:%.*]] = getelementptr i64, i64* [[START]], i64 [[IDX]]
168+
; CHECK-NEXT: [[LV:%.*]] = load i64, i64* [[GEP_IDX]], align 4
169+
; CHECK-NEXT: ret i64 [[LV]]
170+
; CHECK: error:
171+
; CHECK-NEXT: tail call void @error()
172+
; CHECK-NEXT: unreachable
173+
;
174+
%gep.start = getelementptr %vec, %vec* %ptr, i64 0, i32 0
175+
%start = load i64*, i64** %gep.start
176+
%gep.end = getelementptr %vec, %vec* %ptr, i64 0, i32 1
177+
%end = load i64*, i64** %gep.end
178+
%start.int = ptrtoint i64* %start to i64
179+
%end.int = ptrtoint i64* %end to i64
180+
%sub = sub i64 %end.int, %start.int
181+
%inrange = icmp ugt i64 %idx, %sub
182+
br i1 %inrange, label %error, label %exit
183+
184+
exit:
185+
%gep.idx = getelementptr i64, i64* %start, i64 %idx
186+
%lv = load i64, i64* %gep.idx
187+
ret i64 %lv
188+
189+
error:
190+
call void @error()
191+
unreachable
192+
}
193+
194+
declare void @error()
195+
196+

0 commit comments

Comments
 (0)