blob: a68c383c0a021b94acf90332b093cd2beec57780 [file] [log] [blame]
Aart Bik281c6812016-08-26 11:31:48 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/**
18 * Tests on loop optimizations related to induction.
19 */
20public class Main {
21
22 static int[] a = new int[10];
23
24 /// CHECK-START: void Main.deadSingleLoop() loop_optimization (before)
25 /// CHECK-DAG: Phi loop:{{B\d+}} outer_loop:none
26 //
27 /// CHECK-START: void Main.deadSingleLoop() loop_optimization (after)
28 /// CHECK-NOT: Phi loop:{{B\d+}} outer_loop:none
29 static void deadSingleLoop() {
30 for (int i = 0; i < 4; i++) {
31 }
32 }
33
34 /// CHECK-START: void Main.deadNestedLoops() loop_optimization (before)
35 /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
36 /// CHECK-DAG: Phi loop:{{B\d+}} outer_loop:<<Loop>>
37 //
38 /// CHECK-START: void Main.deadNestedLoops() loop_optimization (after)
39 /// CHECK-NOT: Phi loop:{{B\d+}}
40 static void deadNestedLoops() {
41 for (int i = 0; i < 4; i++) {
42 for (int j = 0; j < 4; j++) {
43 }
44 }
45 }
46
47 /// CHECK-START: void Main.deadNestedAndFollowingLoops() loop_optimization (before)
48 /// CHECK-DAG: Phi loop:<<Loop1:B\d+>> outer_loop:none
49 /// CHECK-DAG: Phi loop:<<Loop2:B\d+>> outer_loop:<<Loop1>>
50 /// CHECK-DAG: Phi loop:{{B\d+}} outer_loop:<<Loop2>>
51 /// CHECK-DAG: Phi loop:{{B\d+}} outer_loop:<<Loop2>>
52 /// CHECK-DAG: Phi loop:<<Loop3:B\d+>> outer_loop:<<Loop1>>
53 /// CHECK-DAG: Phi loop:{{B\d+}} outer_loop:<<Loop3>>
54 /// CHECK-DAG: Phi loop:{{B\d+}} outer_loop:none
55 //
56 /// CHECK-START: void Main.deadNestedAndFollowingLoops() loop_optimization (after)
57 /// CHECK-NOT: Phi loop:{{B\d+}}
58 static void deadNestedAndFollowingLoops() {
59 for (int i = 0; i < 4; i++) {
60 for (int j = 0; j < 4; j++) {
61 for (int k = 0; k < 4; k++) {
62 }
63 for (int k = 0; k < 4; k++) {
64 }
65 }
66 for (int j = 0; j < 4; j++) {
67 for (int k = 0; k < 4; k++) {
68 }
69 }
70 }
71 for (int i = 0; i < 4; i++) {
72 }
73 }
74
75 /// CHECK-START: void Main.deadInduction() loop_optimization (before)
76 /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
77 /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none
78 /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
79 //
80 /// CHECK-START: void Main.deadInduction() loop_optimization (after)
81 /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
82 /// CHECK-NOT: Phi loop:<<Loop>> outer_loop:none
83 /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
84 static void deadInduction() {
85 int dead = 0;
86 for (int i = 0; i < a.length; i++) {
87 a[i] = 1;
88 dead += 5;
89 }
90 }
91
92 /// CHECK-START: void Main.deadManyInduction() loop_optimization (before)
93 /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
94 /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none
95 /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none
96 /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none
97 /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
98 //
99 /// CHECK-START: void Main.deadManyInduction() loop_optimization (after)
100 /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
101 /// CHECK-NOT: Phi loop:<<Loop>> outer_loop:none
102 /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
103 static void deadManyInduction() {
104 int dead1 = 0, dead2 = 1, dead3 = 3;
105 for (int i = 0; i < a.length; i++) {
106 dead1 += 5;
107 a[i] = 2;
108 dead2 += 10;
109 dead3 += 100;
110 }
111 }
112
113 /// CHECK-START: void Main.deadSequence() loop_optimization (before)
114 /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
115 /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none
116 /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
117 //
118 /// CHECK-START: void Main.deadSequence() loop_optimization (after)
119 /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
120 /// CHECK-NOT: Phi loop:<<Loop>> outer_loop:none
121 /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
122 static void deadSequence() {
123 int dead = 0;
124 for (int i = 0; i < a.length; i++) {
125 a[i] = 3;
126 // Increment value defined inside loop,
127 // but sequence itself not used anywhere.
128 dead += i;
129 }
130 }
131
132 /// CHECK-START: void Main.deadCycleWithException(int) loop_optimization (before)
133 /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
134 /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none
135 /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
136 /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
137 //
138 /// CHECK-START: void Main.deadCycleWithException(int) loop_optimization (after)
139 /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
140 /// CHECK-NOT: Phi loop:<<Loop>> outer_loop:none
141 /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
142 /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
143 static void deadCycleWithException(int k) {
144 int dead = 0;
145 for (int i = 0; i < a.length; i++) {
146 a[i] = 4;
147 // Increment value of dead cycle may throw exception.
148 dead += a[k];
149 }
150 }
151
152 /// CHECK-START: int Main.closedFormInductionUp() loop_optimization (before)
153 /// CHECK-DAG: <<Phi1:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
154 /// CHECK-DAG: <<Phi2:i\d+>> Phi loop:<<Loop>> outer_loop:none
155 /// CHECK-DAG: Return [<<Phi1>>] loop:none
156 //
157 /// CHECK-START: int Main.closedFormInductionUp() loop_optimization (after)
158 /// CHECK-NOT: Phi loop:B\d+ outer_loop:none
159 /// CHECK-DAG: Return loop:none
160 static int closedFormInductionUp() {
161 int closed = 12345;
162 for (int i = 0; i < 10; i++) {
163 closed += 5;
164 }
165 return closed; // only needs last value
166 }
167
168 /// CHECK-START: int Main.closedFormInductionInAndDown(int) loop_optimization (before)
169 /// CHECK-DAG: <<Phi1:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
170 /// CHECK-DAG: <<Phi2:i\d+>> Phi loop:<<Loop>> outer_loop:none
171 /// CHECK-DAG: Return [<<Phi2>>] loop:none
172 //
173 /// CHECK-START: int Main.closedFormInductionInAndDown(int) loop_optimization (after)
174 /// CHECK-NOT: Phi loop:B\d+ outer_loop:none
175 /// CHECK-DAG: Return loop:none
176 static int closedFormInductionInAndDown(int closed) {
177 for (int i = 0; i < 10; i++) {
178 closed -= 5;
179 }
180 return closed; // only needs last value
181 }
182
183 // TODO: taken test around closed form?
184 static int closedFormInductionUpN(int n) {
185 int closed = 12345;
186 for (int i = 0; i < n; i++) {
187 closed += 5;
188 }
189 return closed; // only needs last value
190 }
191
192 // TODO: taken test around closed form?
193 static int closedFormInductionInAndDownN(int closed, int n) {
194 for (int i = 0; i < n; i++) {
195 closed -= 5;
196 }
197 return closed; // only needs last value
198 }
199
200 // TODO: move closed form even further out?
201 static int closedFormNested(int n) {
202 int closed = 0;
203 for (int i = 0; i < n; i++) {
204 for (int j = 0; j < 10; j++) {
205 closed++;
206 }
207 }
208 return closed; // only needs last-value
209 }
210
211 // TODO: handle as closed/empty eventually?
212 static int mainIndexReturned(int n) {
213 int i;
214 for (i = 0; i < n; i++);
215 return i;
216 }
217
218 // If ever replaced by closed form, last value should be correct!
219 static int periodicReturned(int n) {
220 int k = 0;
221 for (int i = 0; i < n; i++) {
222 k = 1 - k;
223 }
224 return k;
225 }
226
227 // Same here.
228 private static int getSum(int n) {
229 int k = 0;
230 int sum = 0;
231 for (int i = 0; i < n; i++) {
232 k++;
233 sum += k;
234 }
235 return sum;
236 }
237
238 // Same here.
239 private static int getSum21() {
240 int k = 0;
241 int sum = 0;
242 for (int i = 0; i < 6; i++) {
243 k++;
244 sum += k;
245 }
246 return sum;
247 }
248
249 // Same here.
250 private static int closedTwice() {
251 int closed = 0;
252 for (int i = 0; i < 10; i++) {
253 closed++;
254 }
255 // Closed form of first loop defines trip count of second loop.
256 int other_closed = 0;
257 for (int i = 0; i < closed; i++) {
258 other_closed++;
259 }
260 return other_closed;
261 }
262
263 /// CHECK-START: int Main.closedFeed() loop_optimization (before)
264 /// CHECK-DAG: <<Phi1:i\d+>> Phi loop:<<Loop1:B\d+>> outer_loop:none
265 /// CHECK-DAG: <<Phi2:i\d+>> Phi loop:<<Loop1>> outer_loop:none
266 /// CHECK-DAG: <<Phi3:i\d+>> Phi loop:<<Loop2:B\d+>> outer_loop:none
267 /// CHECK-DAG: <<Phi4:i\d+>> Phi loop:<<Loop2>> outer_loop:none
268 /// CHECK-DAG: Return [<<Phi3>>] loop:none
269 /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
270 //
271 /// CHECK-START: int Main.closedFeed() loop_optimization (after)
272 /// CHECK-NOT: Phi loop:B\d+ outer_loop:none
273 /// CHECK-DAG: Return loop:none
274 private static int closedFeed() {
275 int closed = 0;
276 for (int i = 0; i < 10; i++) {
277 closed++;
278 }
279 // Closed form of first loop feeds into initial value of second loop,
280 // used when generating closed form for the latter.
281 for (int i = 0; i < 10; i++) {
282 closed++;
283 }
284 return closed;
285 }
286
287 /// CHECK-START: int Main.closedLargeUp() loop_optimization (before)
288 /// CHECK-DAG: <<Phi1:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
289 /// CHECK-DAG: <<Phi2:i\d+>> Phi loop:<<Loop>> outer_loop:none
290 /// CHECK-DAG: Return [<<Phi1>>] loop:none
291 //
292 /// CHECK-START: int Main.closedLargeUp() loop_optimization (after)
293 /// CHECK-NOT: Phi loop:B\d+ outer_loop:none
294 /// CHECK-DAG: Return loop:none
295 private static int closedLargeUp() {
296 int closed = 0;
297 for (int i = 0; i < 10; i++) {
298 closed += 0x7fffffff;
299 }
300 return closed;
301 }
302
303 /// CHECK-START: int Main.closedLargeDown() loop_optimization (before)
304 /// CHECK-DAG: <<Phi1:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
305 /// CHECK-DAG: <<Phi2:i\d+>> Phi loop:<<Loop>> outer_loop:none
306 /// CHECK-DAG: Return [<<Phi1>>] loop:none
307 //
308 /// CHECK-START: int Main.closedLargeDown() loop_optimization (after)
309 /// CHECK-NOT: Phi loop:B\d+ outer_loop:none
310 /// CHECK-DAG: Return loop:none
311 private static int closedLargeDown() {
312 int closed = 0;
313 for (int i = 0; i < 10; i++) {
314 closed -= 0x7fffffff;
315 }
316 return closed;
317 }
318
319 private static int exceptionExitBeforeAdd() {
320 int k = 0;
321 try {
322 for (int i = 0; i < 10; i++) {
323 a[i] = 0;
324 k += 10; // increment last
325 }
326 } catch(Exception e) {
327 // Flag error by returning current
328 // value of k negated.
329 return -k-1;
330 }
331 return k;
332 }
333
334 private static int exceptionExitAfterAdd() {
335 int k = 0;
336 try {
337 for (int i = 0; i < 10; i++) {
338 k += 10; // increment first
339 a[i] = 0;
340 }
341 } catch(Exception e) {
342 // Flag error by returning current
343 // value of k negated.
344 return -k-1;
345 }
346 return k;
347 }
348
349 public static void main(String[] args) {
350 deadSingleLoop();
351 deadNestedLoops();
352 deadNestedAndFollowingLoops();
353
354 deadInduction();
355 for (int i = 0; i < a.length; i++) {
356 expectEquals(1, a[i]);
357 }
358 deadManyInduction();
359 for (int i = 0; i < a.length; i++) {
360 expectEquals(2, a[i]);
361 }
362 deadSequence();
363 for (int i = 0; i < a.length; i++) {
364 expectEquals(3, a[i]);
365 }
366 try {
367 deadCycleWithException(-1);
368 throw new Error("Expected: IOOB exception");
369 } catch (IndexOutOfBoundsException e) {
370 }
371 for (int i = 0; i < a.length; i++) {
372 expectEquals(i == 0 ? 4 : 3, a[i]);
373 }
374 deadCycleWithException(0);
375 for (int i = 0; i < a.length; i++) {
376 expectEquals(4, a[i]);
377 }
378
379 int c = closedFormInductionUp();
380 expectEquals(12395, c);
381 c = closedFormInductionInAndDown(12345);
382 expectEquals(12295, c);
383 for (int n = -4; n < 10; n++) {
384 int tc = (n <= 0) ? 0 : n;
385 c = closedFormInductionUpN(n);
386 expectEquals(12345 + tc * 5, c);
387 c = closedFormInductionInAndDownN(12345, n);
388 expectEquals(12345 - tc * 5, c);
389 c = closedFormNested(n);
390 expectEquals(tc * 10, c);
391 }
392
393 for (int n = -4; n < 4; n++) {
394 int tc = (n <= 0) ? 0 : n;
395 expectEquals(tc, mainIndexReturned(n));
396 expectEquals(tc & 1, periodicReturned(n));
397 expectEquals((tc * (tc + 1)) / 2, getSum(n));
398 }
399 expectEquals(21, getSum21());
400 expectEquals(10, closedTwice());
401 expectEquals(20, closedFeed());
402 expectEquals(-10, closedLargeUp());
403 expectEquals(10, closedLargeDown());
404
405 expectEquals(100, exceptionExitBeforeAdd());
406 expectEquals(100, exceptionExitAfterAdd());
407 a = null;
408 expectEquals(-1, exceptionExitBeforeAdd());
409 expectEquals(-11, exceptionExitAfterAdd());
410 a = new int[4];
411 expectEquals(-41, exceptionExitBeforeAdd());
412 expectEquals(-51, exceptionExitAfterAdd());
413
414 System.out.println("passed");
415 }
416
417 private static void expectEquals(int expected, int result) {
418 if (expected != result) {
419 throw new Error("Expected: " + expected + ", found: " + result);
420 }
421 }
422}