1 // RUN: %check_clang_tidy %s altera-unroll-loops %t -- -config="{CheckOptions: [{key: "altera-unroll-loops.MaxLoopIterations", value: 50}]}" -header-filter=.*
2 // RUN: %check_clang_tidy -check-suffix=MULT %s altera-unroll-loops %t -- -config="{CheckOptions: [{key: "altera-unroll-loops.MaxLoopIterations", value: 5}]}" -header-filter=.* "--" -DMULT
3 
4 #ifdef MULT
5 // For loops with *= and /= increments.
for_loop_mult_div_increments(int * A)6 void for_loop_mult_div_increments(int *A) {
7 // *=
8 #pragma unroll
9   for (int i = 2; i <= 32; i *= 2)
10     A[i]++; // OK
11 
12 #pragma unroll
13   for (int i = 2; i <= 64; i *= 2)
14     // CHECK-MESSAGES-MULT: :[[@LINE-1]]:3: warning: loop likely has a large number of iterations and thus cannot be fully unrolled; to partially unroll this loop, use the '#pragma unroll <num>' directive [altera-unroll-loops]
15     A[i]++; // Not OK
16 
17 // /=
18 #pragma unroll
19   for (int i = 32; i >= 2; i /= 2)
20     A[i]++; // OK
21 
22 #pragma unroll
23   for (int i = 64; i >= 2; i /= 2)
24     // CHECK-MESSAGES-MULT: :[[@LINE-1]]:3: warning: loop likely has a large number of iterations and thus cannot be fully unrolled; to partially unroll this loop, use the '#pragma unroll <num>' directive [altera-unroll-loops]
25     A[i]++; // Not OK
26 }
27 #else
28 // Cannot determine loop bounds for while loops.
while_loops(int * A)29 void while_loops(int *A) {
30   // Recommend unrolling loops that aren't already unrolled.
31   int j = 0;
32   while (j < 2000) {
33     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: kernel performance could be improved by unrolling this loop with a '#pragma unroll' directive [altera-unroll-loops]
34     A[1] += j;
35     j++;
36   }
37 
38   do {
39     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: kernel performance could be improved by unrolling this loop with a '#pragma unroll' directive [altera-unroll-loops]
40     A[2] += j;
41     j++;
42   } while (j < 2000);
43 
44 // If a while loop is fully unrolled, add a note recommending partial
45 // unrolling.
46 #pragma unroll
47   while (j < 2000) {
48     // CHECK-MESSAGES: :[[@LINE-1]]:3: note: full unrolling requested, but loop bounds may not be known; to partially unroll this loop, use the '#pragma unroll <num>' directive
49     A[j]++;
50   }
51 
52 #pragma unroll
53   do {
54     // CHECK-MESSAGES: :[[@LINE-1]]:3: note: full unrolling requested, but loop bounds may not be known; to partially unroll this loop, use the '#pragma unroll <num>' directive
55     A[j]++;
56   } while (j < 2000);
57 
58 // While loop is partially unrolled, no action needed.
59 #pragma unroll 4
60   while (j < 2000) {
61     A[j]++;
62   }
63 
64 #pragma unroll 4
65   do {
66     A[j]++;
67   } while (j < 2000);
68 }
69 
70 // Range-based for loops.
cxx_for_loops(int * A,int vectorSize)71 void cxx_for_loops(int *A, int vectorSize) {
72   // Loop with known array size should be unrolled.
73   int a[] = {0, 1, 2, 3, 4, 5};
74   for (int k : a) {
75     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: kernel performance could be improved by unrolling this loop with a '#pragma unroll' directive [altera-unroll-loops]
76     A[k]++;
77   }
78 
79 // Loop with known size correctly unrolled.
80 #pragma unroll
81   for (int k : a) {
82     A[k]++;
83   }
84 
85   // Loop with unknown size should be partially unrolled.
86   int b[vectorSize];
87 #pragma unroll
88   for (int k : b) {
89     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: full unrolling requested, but loop bounds are not known; to partially unroll this loop, use the '#pragma unroll <num>' directive [altera-unroll-loops]
90     k++;
91   }
92 
93 // Loop with unknown size correctly unrolled.
94 #pragma unroll 5
95   for (int k : b) {
96     k++;
97   }
98 
99   // Loop with large size should be partially unrolled.
100   int c[51];
101 #pragma unroll
102   for (int k : c) {
103     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: loop likely has a large number of iterations and thus cannot be fully unrolled; to partially unroll this loop, use the '#pragma unroll <num>' directive [altera-unroll-loops]
104     A[k]++;
105   }
106 
107 // Loop with large size correctly unrolled.
108 #pragma unroll 5
109   for (int k : c) {
110     A[k]++;
111   }
112 }
113 
114 // Simple for loops.
for_loops(int * A,int size)115 void for_loops(int *A, int size) {
116   // Recommend unrolling loops that aren't already unrolled.
117   for (int i = 0; i < 2000; ++i) {
118     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: kernel performance could be improved by unrolling this loop with a '#pragma unroll' directive [altera-unroll-loops]
119     A[0] += i;
120   }
121 
122 // Loop with known size correctly unrolled.
123 #pragma unroll
124   for (int i = 0; i < 50; ++i) {
125     A[i]++;
126   }
127 
128 // Loop with unknown size should be partially unrolled.
129 #pragma unroll
130   for (int i = 0; i < size; ++i) {
131     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: full unrolling requested, but loop bounds are not known; to partially unroll this loop, use the '#pragma unroll <num>' directive [altera-unroll-loops]
132     A[i]++;
133   }
134 
135 #pragma unroll
136   for (;;) {
137     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: full unrolling requested, but loop bounds are not known; to partially unroll this loop, use the '#pragma unroll <num>' directive [altera-unroll-loops]
138     A[0]++;
139   }
140 
141   int i = 0;
142 #pragma unroll
143   for (; i < size; ++i) {
144     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: full unrolling requested, but loop bounds are not known; to partially unroll this loop, use the '#pragma unroll <num>' directive [altera-unroll-loops]
145     A[i]++;
146   }
147 
148 #pragma unroll
149   for (int i = 0;; ++i) {
150     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: full unrolling requested, but loop bounds are not known; to partially unroll this loop, use the '#pragma unroll <num>' directive [altera-unroll-loops]
151     A[i]++;
152   }
153 
154 #pragma unroll
155   for (int i = 0; i < size;) {
156     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: full unrolling requested, but loop bounds are not known; to partially unroll this loop, use the '#pragma unroll <num>' directive [altera-unroll-loops]
157     A[i]++;
158   }
159 
160 #pragma unroll
161   for (int i = size; i < 50; ++i) {
162     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: full unrolling requested, but loop bounds are not known; to partially unroll this loop, use the '#pragma unroll <num>' directive [altera-unroll-loops]
163     A[i]++;
164   }
165 
166 #pragma unroll
167   for (int i = 0; true; ++i) {
168     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: full unrolling requested, but loop bounds are not known; to partially unroll this loop, use the '#pragma unroll <num>' directive [altera-unroll-loops]
169     A[i]++;
170   }
171 
172 #pragma unroll
173   for (int i = 0; i == i; ++i) {
174     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: full unrolling requested, but loop bounds are not known; to partially unroll this loop, use the '#pragma unroll <num>' directive [altera-unroll-loops]
175     A[i]++;
176   }
177 
178 // Loop with unknown size correctly unrolled.
179 #pragma unroll 5
180   for (int i = 0; i < size; ++i) {
181     A[i]++;
182   }
183 
184 // Loop with large size should be partially unrolled.
185 #pragma unroll
186   for (int i = 0; i < 51; ++i) {
187     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: loop likely has a large number of iterations and thus cannot be fully unrolled; to partially unroll this loop, use the '#pragma unroll <num>' directive [altera-unroll-loops]
188     A[i]++;
189   }
190 
191 // Loop with large size correctly unrolled.
192 #pragma unroll 5
193   for (int i = 0; i < 51; ++i) {
194     A[i]++;
195   }
196 }
197 
198 // For loops with different increments.
for_loop_increments(int * A)199 void for_loop_increments(int *A) {
200 // ++
201 #pragma unroll
202   for (int i = 0; i < 50; ++i)
203     A[i]++; // OK
204 
205 #pragma unroll
206   for (int i = 0; i < 51; ++i)
207     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: loop likely has a large number of iterations and thus cannot be fully unrolled; to partially unroll this loop, use the '#pragma unroll <num>' directive [altera-unroll-loops]
208     A[i]++; // Not OK
209 
210 // --
211 #pragma unroll
212   for (int i = 50; i > 0; --i)
213     A[i]++; // OK
214 
215 #pragma unroll
216   for (int i = 51; i > 0; --i)
217     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: loop likely has a large number of iterations and thus cannot be fully unrolled; to partially unroll this loop, use the '#pragma unroll <num>' directive [altera-unroll-loops]
218     A[i]++; // Not OK
219 
220 // +=
221 #pragma unroll
222   for (int i = 0; i < 100; i += 2)
223     A[i]++; // OK
224 
225 #pragma unroll
226   for (int i = 0; i < 101; i += 2)
227     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: loop likely has a large number of iterations and thus cannot be fully unrolled; to partially unroll this loop, use the '#pragma unroll <num>' directive [altera-unroll-loops]
228     A[i]++; // Not OK
229 
230 // -=
231 #pragma unroll
232   for (int i = 100; i > 0; i -= 2)
233     A[i]++; // OK
234 
235 #pragma unroll
236   for (int i = 101; i > 0; i -= 2)
237     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: loop likely has a large number of iterations and thus cannot be fully unrolled; to partially unroll this loop, use the '#pragma unroll <num>' directive [altera-unroll-loops]
238     A[i]++; // Not OK
239 }
240 
241 // Inner loops should be unrolled.
nested_simple_loops(int * A)242 void nested_simple_loops(int *A) {
243   for (int i = 0; i < 1000; ++i) {
244     for (int j = 0; j < 2000; ++j) {
245       // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: kernel performance could be improved by unrolling this loop with a '#pragma unroll' directive [altera-unroll-loops]
246       A[0] += i + j;
247     }
248   }
249 
250   for (int i = 0; i < 1000; ++i) {
251     int j = 0;
252     while (j < 2000) {
253       // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: kernel performance could be improved by unrolling this loop with a '#pragma unroll' directive [altera-unroll-loops]
254       A[1] += i + j;
255       j++;
256     }
257   }
258 
259   for (int i = 0; i < 1000; ++i) {
260     int j = 0;
261     do {
262       // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: kernel performance could be improved by unrolling this loop with a '#pragma unroll' directive [altera-unroll-loops]
263       A[2] += i + j;
264       j++;
265     } while (j < 2000);
266   }
267 
268   int i = 0;
269   while (i < 1000) {
270     for (int j = 0; j < 2000; ++j) {
271       // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: kernel performance could be improved by unrolling this loop with a '#pragma unroll' directive [altera-unroll-loops]
272       A[3] += i + j;
273     }
274     i++;
275   }
276 
277   i = 0;
278   while (i < 1000) {
279     int j = 0;
280     while (j < 2000) {
281       // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: kernel performance could be improved by unrolling this loop with a '#pragma unroll' directive [altera-unroll-loops]
282       A[4] += i + j;
283       j++;
284     }
285     i++;
286   }
287 
288   i = 0;
289   while (i < 1000) {
290     int j = 0;
291     do {
292       // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: kernel performance could be improved by unrolling this loop with a '#pragma unroll' directive [altera-unroll-loops]
293       A[5] += i + j;
294       j++;
295     } while (j < 2000);
296     i++;
297   }
298 
299   i = 0;
300   do {
301     for (int j = 0; j < 2000; ++j) {
302       // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: kernel performance could be improved by unrolling this loop with a '#pragma unroll' directive [altera-unroll-loops]
303       A[6] += i + j;
304     }
305     i++;
306   } while (i < 1000);
307 
308   i = 0;
309   do {
310     int j = 0;
311     while (j < 2000) {
312       // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: kernel performance could be improved by unrolling this loop with a '#pragma unroll' directive [altera-unroll-loops]
313       A[7] += i + j;
314       j++;
315     }
316     i++;
317   } while (i < 1000);
318 
319   i = 0;
320   do {
321     int j = 0;
322     do {
323       // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: kernel performance could be improved by unrolling this loop with a '#pragma unroll' directive [altera-unroll-loops]
324       A[8] += i + j;
325       j++;
326     } while (j < 2000);
327     i++;
328   } while (i < 1000);
329 
330   for (int i = 0; i < 100; ++i) {
331     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: kernel performance could be improved by unrolling this loop with a '#pragma unroll' directive [altera-unroll-loops]
332     A[i]++;
333   }
334 
335   i = 0;
336   while (i < 100) {
337     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: kernel performance could be improved by unrolling this loop with a '#pragma unroll' directive [altera-unroll-loops]
338     i++;
339   }
340 
341   i = 0;
342   do {
343     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: kernel performance could be improved by unrolling this loop with a '#pragma unroll' directive [altera-unroll-loops]
344     i++;
345   } while (i < 100);
346 }
347 
348 // These loops are all correctly unrolled.
unrolled_nested_simple_loops(int * A)349 void unrolled_nested_simple_loops(int *A) {
350   for (int i = 0; i < 1000; ++i) {
351 #pragma unroll
352     for (int j = 0; j < 50; ++j) {
353       A[0] += i + j;
354     }
355   }
356 
357   for (int i = 0; i < 1000; ++i) {
358     int j = 0;
359 #pragma unroll 5
360     while (j < 50) {
361       A[1] += i + j;
362       j++;
363     }
364   }
365 
366   for (int i = 0; i < 1000; ++i) {
367     int j = 0;
368 #pragma unroll 5
369     do {
370       A[2] += i + j;
371       j++;
372     } while (j < 50);
373   }
374 
375   int i = 0;
376   while (i < 1000) {
377 #pragma unroll
378     for (int j = 0; j < 50; ++j) {
379       A[3] += i + j;
380     }
381     i++;
382   }
383 
384   i = 0;
385   while (i < 1000) {
386     int j = 0;
387 #pragma unroll 5
388     while (50 > j) {
389       A[4] += i + j;
390       j++;
391     }
392     i++;
393   }
394 
395   i = 0;
396   while (1000 > i) {
397     int j = 0;
398 #pragma unroll 5
399     do {
400       A[5] += i + j;
401       j++;
402     } while (j < 50);
403     i++;
404   }
405 
406   i = 0;
407   do {
408 #pragma unroll
409     for (int j = 0; j < 50; ++j) {
410       A[6] += i + j;
411     }
412     i++;
413   } while (i < 1000);
414 
415   i = 0;
416   do {
417     int j = 0;
418 #pragma unroll 5
419     while (j < 50) {
420       A[7] += i + j;
421       j++;
422     }
423     i++;
424   } while (i < 1000);
425 
426   i = 0;
427   do {
428     int j = 0;
429 #pragma unroll 5
430     do {
431       A[8] += i + j;
432       j++;
433     } while (j < 50);
434     i++;
435   } while (i < 1000);
436 }
437 
438 // These inner loops are large and should be partially unrolled.
unrolled_nested_simple_loops_large_num_iterations(int * A)439 void unrolled_nested_simple_loops_large_num_iterations(int *A) {
440   for (int i = 0; i < 1000; ++i) {
441 #pragma unroll
442     for (int j = 0; j < 51; ++j) {
443       // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: loop likely has a large number of iterations and thus cannot be fully unrolled; to partially unroll this loop, use the '#pragma unroll <num>' directive [altera-unroll-loops]
444       A[0] += i + j;
445     }
446   }
447 
448   int i = 0;
449   while (i < 1000) {
450 #pragma unroll
451     for (int j = 0; j < 51; ++j) {
452       // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: loop likely has a large number of iterations and thus cannot be fully unrolled; to partially unroll this loop, use the '#pragma unroll <num>' directive [altera-unroll-loops]
453       A[3] += i + j;
454     }
455     i++;
456   }
457 
458   i = 0;
459   do {
460 #pragma unroll
461     for (int j = 0; j < 51; ++j) {
462       // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: loop likely has a large number of iterations and thus cannot be fully unrolled; to partially unroll this loop, use the '#pragma unroll <num>' directive [altera-unroll-loops]
463       A[6] += i + j;
464     }
465     i++;
466   } while (i < 1000);
467 
468   i = 0;
469   do {
470     int j = 0;
471 #pragma unroll
472     do {
473       // CHECK-MESSAGES: :[[@LINE-1]]:5: note: full unrolling requested, but loop bounds may not be known; to partially unroll this loop, use the '#pragma unroll <num>' directive
474       A[8] += i + j;
475       j++;
476     } while (j < 51);
477     i++;
478   } while (i < 1000);
479 
480   i = 0;
481   int a[51];
482   do {
483 #pragma unroll
484     for (int k : a) {
485       // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: loop likely has a large number of iterations and thus cannot be fully unrolled; to partially unroll this loop, use the '#pragma unroll <num>' directive [altera-unroll-loops]
486       A[k]++;
487     }
488   } while (i < 1000);
489 }
490 
491 // These loops have unknown bounds and should be partially unrolled.
fully_unrolled_unknown_bounds(int vectorSize)492 void fully_unrolled_unknown_bounds(int vectorSize) {
493   int someVector[101];
494 
495 // There is no loop condition
496 #pragma unroll
497   for (;;) {
498     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: full unrolling requested, but loop bounds are not known; to partially unroll this loop, use the '#pragma unroll <num>' directive [altera-unroll-loops]
499     someVector[0]++;
500   }
501 
502 #pragma unroll
503   for (int i = 0; 1 < 5; ++i) {
504     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: full unrolling requested, but loop bounds are not known; to partially unroll this loop, use the '#pragma unroll <num>' directive [altera-unroll-loops]
505     someVector[i]++;
506   }
507 
508 // Both sides are value-dependent
509 #pragma unroll
510   for (int i = 0; i < vectorSize; ++i) {
511     // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: full unrolling requested, but loop bounds are not known; to partially unroll this loop, use the '#pragma unroll <num>' directive [altera-unroll-loops]
512     someVector[i]++;
513   }
514 }
515 #endif
516 // There are no fix-its for this check
517