blob: 06cf79fd7a7ea4c47e31a4762262bdbb3a576b93 [file] [log] [blame]
Mingyao Yang8df69d42015-10-22 15:40:58 -07001/*
2 * Copyright (C) 2015 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
17class Circle {
18 Circle(double radius) {
19 this.radius = radius;
20 }
Mingyao Yange58bdca2016-10-28 11:07:24 -070021 public double getRadius() {
22 return radius;
23 }
Mingyao Yang8df69d42015-10-22 15:40:58 -070024 public double getArea() {
25 return radius * radius * Math.PI;
26 }
27 private double radius;
Mingyao Yangfb8464a2015-11-02 10:56:59 -080028}
Mingyao Yang8df69d42015-10-22 15:40:58 -070029
30class TestClass {
Mingyao Yang8ab1d642015-12-03 14:11:15 -080031 static {
32 sTestClassObj = new TestClass(-1, -2);
33 }
Mingyao Yang8df69d42015-10-22 15:40:58 -070034 TestClass() {
35 }
36 TestClass(int i, int j) {
37 this.i = i;
38 this.j = j;
39 }
40 int i;
41 int j;
42 volatile int k;
43 TestClass next;
Mingyao Yangfb8464a2015-11-02 10:56:59 -080044 String str;
Vladimir Marko4307cd72020-07-17 14:35:56 +010045 byte b;
Mingyao Yang8df69d42015-10-22 15:40:58 -070046 static int si;
Mingyao Yang8ab1d642015-12-03 14:11:15 -080047 static TestClass sTestClassObj;
Mingyao Yangfb8464a2015-11-02 10:56:59 -080048}
Mingyao Yang8df69d42015-10-22 15:40:58 -070049
50class SubTestClass extends TestClass {
51 int k;
Mingyao Yangfb8464a2015-11-02 10:56:59 -080052}
Mingyao Yang8df69d42015-10-22 15:40:58 -070053
54class TestClass2 {
55 int i;
56 int j;
Vladimir Marko3224f382020-06-23 14:19:53 +010057 int k;
58 int l;
59 int m;
Mingyao Yangfb8464a2015-11-02 10:56:59 -080060}
61
David Brazdilecf52df2015-12-14 16:58:08 +000062class TestClass3 {
63 float floatField = 8.0f;
64 boolean test1 = true;
65}
66
Alex Light3a73ffb2021-01-25 14:11:05 +000067// Chosen to have different values with (x + 1) * 10 and (x - 1) * 10. This
68// means we can easily make sure that different code is in fact executed on
69// escape and non-escape paths.
70// Negative so that high-bits will be set for all the 64-bit values allowing us
71// to easily check for truncation.
72class TestClass4 {
73 float floatField = -3.0f;
74 double doubleField = -3.0d;
75 short shortField = -3;
76 int intField = -3;
77 byte byteField = -3;
78 long longField = -3l;
79}
80
Mingyao Yangfb8464a2015-11-02 10:56:59 -080081class Finalizable {
82 static boolean sVisited = false;
Mingyao Yang025c1a62017-10-30 11:19:57 -070083 static final int VALUE1 = 0xbeef;
84 static final int VALUE2 = 0xcafe;
Mingyao Yangfb8464a2015-11-02 10:56:59 -080085 int i;
86
87 protected void finalize() {
Mingyao Yang025c1a62017-10-30 11:19:57 -070088 if (i != VALUE1) {
Mingyao Yangfb8464a2015-11-02 10:56:59 -080089 System.out.println("Where is the beef?");
90 }
91 sVisited = true;
92 }
93}
Mingyao Yang8df69d42015-10-22 15:40:58 -070094
Mingyao Yang062157f2016-03-02 10:15:36 -080095interface Filter {
96 public boolean isValid(int i);
97}
98
Mingyao Yang8df69d42015-10-22 15:40:58 -070099public class Main {
Alex Light3a73ffb2021-01-25 14:11:05 +0000100 static void $noinline$Escape4(TestClass4 o) {
101 o.floatField += 1.0f;
102 o.doubleField += 1.0d;
103 o.byteField += 1;
104 o.shortField += 1;
105 o.intField += 1;
106 o.longField += 1;
107 }
Mingyao Yang8df69d42015-10-22 15:40:58 -0700108
Alex Light86fe9b82020-11-16 16:54:01 +0000109 static Object ESCAPE = null;
110 static void $noinline$Escape(TestClass o) {
Alex Light3a73ffb2021-01-25 14:11:05 +0000111 if (o == null) {
112 return;
113 }
Alex Light86fe9b82020-11-16 16:54:01 +0000114 ESCAPE = o;
115 o.next.i++;
116 }
117
Mingyao Yang8df69d42015-10-22 15:40:58 -0700118 /// CHECK-START: double Main.calcCircleArea(double) load_store_elimination (before)
119 /// CHECK: NewInstance
120 /// CHECK: InstanceFieldSet
121 /// CHECK: InstanceFieldGet
122
123 /// CHECK-START: double Main.calcCircleArea(double) load_store_elimination (after)
Mingyao Yang062157f2016-03-02 10:15:36 -0800124 /// CHECK-NOT: NewInstance
Mingyao Yangfb8464a2015-11-02 10:56:59 -0800125 /// CHECK-NOT: InstanceFieldSet
Mingyao Yang8df69d42015-10-22 15:40:58 -0700126 /// CHECK-NOT: InstanceFieldGet
127
128 static double calcCircleArea(double radius) {
129 return new Circle(radius).getArea();
130 }
131
132 /// CHECK-START: int Main.test1(TestClass, TestClass) load_store_elimination (before)
133 /// CHECK: InstanceFieldSet
134 /// CHECK: InstanceFieldSet
135 /// CHECK: InstanceFieldGet
136 /// CHECK: InstanceFieldGet
137
138 /// CHECK-START: int Main.test1(TestClass, TestClass) load_store_elimination (after)
139 /// CHECK: InstanceFieldSet
140 /// CHECK: InstanceFieldSet
141 /// CHECK-NOT: NullCheck
142 /// CHECK-NOT: InstanceFieldGet
143
144 // Different fields shouldn't alias.
145 static int test1(TestClass obj1, TestClass obj2) {
146 obj1.i = 1;
147 obj2.j = 2;
148 return obj1.i + obj2.j;
149 }
150
151 /// CHECK-START: int Main.test2(TestClass) load_store_elimination (before)
152 /// CHECK: InstanceFieldSet
153 /// CHECK: InstanceFieldSet
154 /// CHECK: InstanceFieldGet
155
156 /// CHECK-START: int Main.test2(TestClass) load_store_elimination (after)
157 /// CHECK: InstanceFieldSet
158 /// CHECK-NOT: NullCheck
159 /// CHECK-NOT: InstanceFieldSet
160 /// CHECK-NOT: InstanceFieldGet
161
162 // Redundant store of the same value.
163 static int test2(TestClass obj) {
164 obj.j = 1;
165 obj.j = 1;
166 return obj.j;
167 }
168
169 /// CHECK-START: int Main.test3(TestClass) load_store_elimination (before)
Mingyao Yang8ab1d642015-12-03 14:11:15 -0800170 /// CHECK: StaticFieldGet
171 /// CHECK: NewInstance
172 /// CHECK: InstanceFieldSet
173 /// CHECK: InstanceFieldSet
Mingyao Yang8df69d42015-10-22 15:40:58 -0700174 /// CHECK: InstanceFieldSet
175 /// CHECK: InstanceFieldSet
Vladimir Marko3224f382020-06-23 14:19:53 +0100176 /// CHECK: InstanceFieldSet
Mingyao Yang8df69d42015-10-22 15:40:58 -0700177 /// CHECK: InstanceFieldGet
178 /// CHECK: InstanceFieldGet
179 /// CHECK: InstanceFieldGet
180 /// CHECK: InstanceFieldGet
181
182 /// CHECK-START: int Main.test3(TestClass) load_store_elimination (after)
Mingyao Yang8ab1d642015-12-03 14:11:15 -0800183 /// CHECK: StaticFieldGet
184 /// CHECK: NewInstance
185 /// CHECK: InstanceFieldSet
186 /// CHECK: InstanceFieldSet
187 /// CHECK: InstanceFieldSet
188 /// CHECK: InstanceFieldSet
Vladimir Marko3224f382020-06-23 14:19:53 +0100189 /// CHECK: InstanceFieldSet
190
191 /// CHECK-START: int Main.test3(TestClass) load_store_elimination (after)
Mingyao Yang8df69d42015-10-22 15:40:58 -0700192 /// CHECK-NOT: InstanceFieldGet
193
Mingyao Yang8ab1d642015-12-03 14:11:15 -0800194 // A new allocation (even non-singleton) shouldn't alias with pre-existing values.
Mingyao Yang8df69d42015-10-22 15:40:58 -0700195 static int test3(TestClass obj) {
Mingyao Yang8ab1d642015-12-03 14:11:15 -0800196 TestClass obj1 = TestClass.sTestClassObj;
197 TestClass obj2 = new TestClass(); // Cannot alias with obj or obj1 which pre-exist.
198 obj.next = obj2; // Make obj2 a non-singleton.
199 // All stores below need to stay since obj/obj1/obj2 are not singletons.
Mingyao Yang8df69d42015-10-22 15:40:58 -0700200 obj.i = 1;
Mingyao Yang8ab1d642015-12-03 14:11:15 -0800201 obj1.j = 2;
202 // Following stores won't kill values of obj.i and obj1.j.
Mingyao Yang8df69d42015-10-22 15:40:58 -0700203 obj2.i = 3;
204 obj2.j = 4;
Mingyao Yang8ab1d642015-12-03 14:11:15 -0800205 return obj.i + obj1.j + obj2.i + obj2.j;
Mingyao Yang8df69d42015-10-22 15:40:58 -0700206 }
207
Vladimir Markob122cd62020-06-11 09:15:21 +0000208 /// CHECK-START: int Main.test4(TestClass, boolean) load_store_elimination (before)
209 /// CHECK-DAG: InstanceFieldSet
210 /// CHECK-DAG: InstanceFieldSet
211 /// CHECK-DAG: InstanceFieldGet
212 /// CHECK-DAG: Return
213
214 /// CHECK-START: int Main.test4(TestClass, boolean) load_store_elimination (after)
215 /// CHECK-DAG: InstanceFieldSet
216 /// CHECK-DAG: InstanceFieldSet
217 /// CHECK-DAG: Return
218
219 /// CHECK-START: int Main.test4(TestClass, boolean) load_store_elimination (after)
220 /// CHECK: NullCheck
221 /// CHECK: NullCheck
222 /// CHECK-NOT: NullCheck
223
224 /// CHECK-START: int Main.test4(TestClass, boolean) load_store_elimination (after)
225 /// CHECK-NOT: InstanceFieldGet
Vladimir Marko3224f382020-06-23 14:19:53 +0100226 /// CHECK-NOT: Phi
Vladimir Markob122cd62020-06-11 09:15:21 +0000227
228 // Set and merge the same value in two branches.
229 static int test4(TestClass obj, boolean b) {
230 if (b) {
231 obj.i = 1;
232 } else {
233 obj.i = 1;
234 }
235 return obj.i;
236 }
237
238 /// CHECK-START: int Main.test5(TestClass, boolean) load_store_elimination (before)
Vladimir Marko3224f382020-06-23 14:19:53 +0100239 /// CHECK-DAG: <<Int1:i\d+>> IntConstant 1
240 /// CHECK-DAG: <<Int2:i\d+>> IntConstant 2
241 /// CHECK-DAG: <<Obj:l\d+>> ParameterValue
242 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int1>>]
243 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int2>>]
244 /// CHECK-DAG: <<GetField:i\d+>> InstanceFieldGet [{{l\d+}}]
245 /// CHECK-DAG: Return [<<GetField>>]
Vladimir Markob122cd62020-06-11 09:15:21 +0000246
247 /// CHECK-START: int Main.test5(TestClass, boolean) load_store_elimination (after)
Vladimir Marko3224f382020-06-23 14:19:53 +0100248 /// CHECK-DAG: <<Int1:i\d+>> IntConstant 1
249 /// CHECK-DAG: <<Int2:i\d+>> IntConstant 2
250 /// CHECK-DAG: <<Obj:l\d+>> ParameterValue
251 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int1>>]
252 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int2>>]
253 /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Arg1:i\d+>>,<<Arg2:i\d+>>]
254 /// CHECK-DAG: Return [<<Phi>>]
255 /// CHECK-EVAL: set(["<<Arg1>>","<<Arg2>>"]) == set(["<<Int1>>","<<Int2>>"])
256
257 /// CHECK-START: int Main.test5(TestClass, boolean) load_store_elimination (after)
258 /// CHECK-NOT: InstanceFieldGet
Vladimir Markob122cd62020-06-11 09:15:21 +0000259
260 // Set and merge different values in two branches.
261 static int test5(TestClass obj, boolean b) {
262 if (b) {
263 obj.i = 1;
264 } else {
265 obj.i = 2;
266 }
267 return obj.i;
268 }
269
Mingyao Yang8df69d42015-10-22 15:40:58 -0700270 /// CHECK-START: int Main.test6(TestClass, TestClass, boolean) load_store_elimination (before)
Vladimir Marko3224f382020-06-23 14:19:53 +0100271 /// CHECK-DAG: InstanceFieldSet
272 /// CHECK-DAG: InstanceFieldSet
273 /// CHECK-DAG: InstanceFieldSet
274 /// CHECK-DAG: InstanceFieldGet
275 /// CHECK-DAG: InstanceFieldGet
Mingyao Yang8df69d42015-10-22 15:40:58 -0700276
277 /// CHECK-START: int Main.test6(TestClass, TestClass, boolean) load_store_elimination (after)
Vladimir Marko3224f382020-06-23 14:19:53 +0100278 /// CHECK-DAG: InstanceFieldSet
279 /// CHECK-DAG: InstanceFieldSet
280 /// CHECK-DAG: InstanceFieldSet
281 /// CHECK-DAG: InstanceFieldGet
282
283 /// CHECK-START: int Main.test6(TestClass, TestClass, boolean) load_store_elimination (after)
Mingyao Yang8df69d42015-10-22 15:40:58 -0700284 /// CHECK: InstanceFieldGet
Mingyao Yang8df69d42015-10-22 15:40:58 -0700285 /// CHECK-NOT: InstanceFieldGet
286
287 // Setting the same value doesn't clear the value for aliased locations.
288 static int test6(TestClass obj1, TestClass obj2, boolean b) {
289 obj1.i = 1;
290 obj1.j = 2;
291 if (b) {
292 obj2.j = 2;
293 }
294 return obj1.j + obj2.j;
295 }
296
297 /// CHECK-START: int Main.test7(TestClass) load_store_elimination (before)
298 /// CHECK: InstanceFieldSet
299 /// CHECK: InstanceFieldGet
300
301 /// CHECK-START: int Main.test7(TestClass) load_store_elimination (after)
302 /// CHECK: InstanceFieldSet
303 /// CHECK: InstanceFieldGet
304
305 // Invocation should kill values in non-singleton heap locations.
306 static int test7(TestClass obj) {
307 obj.i = 1;
308 System.out.print("");
309 return obj.i;
310 }
311
312 /// CHECK-START: int Main.test8() load_store_elimination (before)
313 /// CHECK: NewInstance
314 /// CHECK: InstanceFieldSet
315 /// CHECK: InvokeVirtual
316 /// CHECK: InstanceFieldGet
317
318 /// CHECK-START: int Main.test8() load_store_elimination (after)
Mingyao Yang062157f2016-03-02 10:15:36 -0800319 /// CHECK-NOT: NewInstance
Mingyao Yangfb8464a2015-11-02 10:56:59 -0800320 /// CHECK-NOT: InstanceFieldSet
Mingyao Yang8df69d42015-10-22 15:40:58 -0700321 /// CHECK: InvokeVirtual
322 /// CHECK-NOT: NullCheck
323 /// CHECK-NOT: InstanceFieldGet
324
325 // Invocation should not kill values in singleton heap locations.
326 static int test8() {
327 TestClass obj = new TestClass();
328 obj.i = 1;
329 System.out.print("");
330 return obj.i;
331 }
332
333 /// CHECK-START: int Main.test9(TestClass) load_store_elimination (before)
334 /// CHECK: NewInstance
335 /// CHECK: InstanceFieldSet
336 /// CHECK: InstanceFieldSet
337 /// CHECK: InstanceFieldGet
338
339 /// CHECK-START: int Main.test9(TestClass) load_store_elimination (after)
340 /// CHECK: NewInstance
341 /// CHECK: InstanceFieldSet
342 /// CHECK: InstanceFieldSet
343 /// CHECK: InstanceFieldGet
344
345 // Invocation should kill values in non-singleton heap locations.
346 static int test9(TestClass obj) {
347 TestClass obj2 = new TestClass();
348 obj2.i = 1;
349 obj.next = obj2;
350 System.out.print("");
351 return obj2.i;
352 }
353
Vladimir Markofaada5e2020-06-10 10:38:40 +0000354 /// CHECK-START: int Main.test10(TestClass) load_store_elimination (before)
355 /// CHECK-DAG: StaticFieldGet
356 /// CHECK-DAG: InstanceFieldGet
357 /// CHECK-DAG: StaticFieldSet
358 /// CHECK-DAG: InstanceFieldGet
359
360 /// CHECK-START: int Main.test10(TestClass) load_store_elimination (after)
361 /// CHECK-DAG: StaticFieldGet
362 /// CHECK-DAG: InstanceFieldGet
363 /// CHECK-DAG: StaticFieldSet
364
365 /// CHECK-START: int Main.test10(TestClass) load_store_elimination (after)
366 /// CHECK: NullCheck
367 /// CHECK-NOT: NullCheck
368
369 /// CHECK-START: int Main.test10(TestClass) load_store_elimination (after)
370 /// CHECK: InstanceFieldGet
371 /// CHECK-NOT: InstanceFieldGet
372
373 // Static fields shouldn't alias with instance fields.
374 static int test10(TestClass obj) {
375 TestClass.si += obj.i;
376 return obj.i;
377 }
378
Mingyao Yang8df69d42015-10-22 15:40:58 -0700379 /// CHECK-START: int Main.test11(TestClass) load_store_elimination (before)
380 /// CHECK: InstanceFieldSet
381 /// CHECK: InstanceFieldGet
382
383 /// CHECK-START: int Main.test11(TestClass) load_store_elimination (after)
384 /// CHECK: InstanceFieldSet
385 /// CHECK-NOT: NullCheck
386 /// CHECK-NOT: InstanceFieldGet
387
388 // Loop without heap writes.
Mingyao Yang8df69d42015-10-22 15:40:58 -0700389 static int test11(TestClass obj) {
390 obj.i = 1;
391 int sum = 0;
392 for (int i = 0; i < 10; i++) {
393 sum += obj.i;
394 }
395 return sum;
396 }
397
398 /// CHECK-START: int Main.test12(TestClass, TestClass) load_store_elimination (before)
399 /// CHECK: InstanceFieldSet
400 /// CHECK: InstanceFieldGet
401 /// CHECK: InstanceFieldSet
402
403 /// CHECK-START: int Main.test12(TestClass, TestClass) load_store_elimination (after)
404 /// CHECK: InstanceFieldSet
405 /// CHECK: InstanceFieldGet
406 /// CHECK: InstanceFieldSet
407
408 // Loop with heap writes.
409 static int test12(TestClass obj1, TestClass obj2) {
410 obj1.i = 1;
411 int sum = 0;
412 for (int i = 0; i < 10; i++) {
413 sum += obj1.i;
414 obj2.i = sum;
415 }
416 return sum;
417 }
418
419 /// CHECK-START: int Main.test13(TestClass, TestClass2) load_store_elimination (before)
420 /// CHECK: InstanceFieldSet
421 /// CHECK: InstanceFieldSet
422 /// CHECK: InstanceFieldGet
423 /// CHECK: InstanceFieldGet
424
425 /// CHECK-START: int Main.test13(TestClass, TestClass2) load_store_elimination (after)
426 /// CHECK: InstanceFieldSet
427 /// CHECK: InstanceFieldSet
428 /// CHECK-NOT: NullCheck
429 /// CHECK-NOT: InstanceFieldGet
430
431 // Different classes shouldn't alias.
432 static int test13(TestClass obj1, TestClass2 obj2) {
433 obj1.i = 1;
434 obj2.i = 2;
435 return obj1.i + obj2.i;
436 }
437
438 /// CHECK-START: int Main.test14(TestClass, SubTestClass) load_store_elimination (before)
439 /// CHECK: InstanceFieldSet
440 /// CHECK: InstanceFieldSet
441 /// CHECK: InstanceFieldGet
442
443 /// CHECK-START: int Main.test14(TestClass, SubTestClass) load_store_elimination (after)
444 /// CHECK: InstanceFieldSet
445 /// CHECK: InstanceFieldSet
446 /// CHECK: InstanceFieldGet
447
448 // Subclass may alias with super class.
449 static int test14(TestClass obj1, SubTestClass obj2) {
450 obj1.i = 1;
451 obj2.i = 2;
452 return obj1.i;
453 }
454
455 /// CHECK-START: int Main.test15() load_store_elimination (before)
456 /// CHECK: StaticFieldSet
457 /// CHECK: StaticFieldSet
458 /// CHECK: StaticFieldGet
459
460 /// CHECK-START: int Main.test15() load_store_elimination (after)
461 /// CHECK: <<Const2:i\d+>> IntConstant 2
462 /// CHECK: StaticFieldSet
Mingyao Yang8df69d42015-10-22 15:40:58 -0700463 /// CHECK: Return [<<Const2>>]
464
Vladimir Marko3224f382020-06-23 14:19:53 +0100465 /// CHECK-START: int Main.test15() load_store_elimination (after)
466 /// CHECK-NOT: StaticFieldGet
467
Mingyao Yang8df69d42015-10-22 15:40:58 -0700468 // Static field access from subclass's name.
469 static int test15() {
470 TestClass.si = 1;
471 SubTestClass.si = 2;
472 return TestClass.si;
473 }
474
475 /// CHECK-START: int Main.test16() load_store_elimination (before)
476 /// CHECK: NewInstance
477 /// CHECK: InstanceFieldSet
478 /// CHECK: InstanceFieldSet
479 /// CHECK: InstanceFieldGet
480 /// CHECK: InstanceFieldGet
481
482 /// CHECK-START: int Main.test16() load_store_elimination (after)
Mingyao Yang062157f2016-03-02 10:15:36 -0800483 /// CHECK-NOT: NewInstance
Mingyao Yangfb8464a2015-11-02 10:56:59 -0800484 /// CHECK-NOT: InstanceFieldSet
485 /// CHECK-NOT: InstanceFieldGet
Mingyao Yang8df69d42015-10-22 15:40:58 -0700486
487 // Test inlined constructor.
488 static int test16() {
489 TestClass obj = new TestClass(1, 2);
490 return obj.i + obj.j;
491 }
492
493 /// CHECK-START: int Main.test17() load_store_elimination (before)
494 /// CHECK: NewInstance
495 /// CHECK: InstanceFieldSet
496 /// CHECK: InstanceFieldGet
497
498 /// CHECK-START: int Main.test17() load_store_elimination (after)
499 /// CHECK: <<Const0:i\d+>> IntConstant 0
Mingyao Yang062157f2016-03-02 10:15:36 -0800500 /// CHECK-NOT: NewInstance
Mingyao Yangfb8464a2015-11-02 10:56:59 -0800501 /// CHECK-NOT: InstanceFieldSet
502 /// CHECK-NOT: InstanceFieldGet
Mingyao Yang8df69d42015-10-22 15:40:58 -0700503 /// CHECK: Return [<<Const0>>]
504
505 // Test getting default value.
506 static int test17() {
507 TestClass obj = new TestClass();
508 obj.j = 1;
509 return obj.i;
510 }
511
512 /// CHECK-START: int Main.test18(TestClass) load_store_elimination (before)
513 /// CHECK: InstanceFieldSet
514 /// CHECK: InstanceFieldGet
515
516 /// CHECK-START: int Main.test18(TestClass) load_store_elimination (after)
517 /// CHECK: InstanceFieldSet
518 /// CHECK: InstanceFieldGet
519
520 // Volatile field load/store shouldn't be eliminated.
521 static int test18(TestClass obj) {
522 obj.k = 1;
523 return obj.k;
524 }
525
526 /// CHECK-START: float Main.test19(float[], float[]) load_store_elimination (before)
David Brazdil4833f5a2015-12-16 10:37:39 +0000527 /// CHECK: {{f\d+}} ArrayGet
528 /// CHECK: {{f\d+}} ArrayGet
Mingyao Yang8df69d42015-10-22 15:40:58 -0700529
530 /// CHECK-START: float Main.test19(float[], float[]) load_store_elimination (after)
David Brazdil4833f5a2015-12-16 10:37:39 +0000531 /// CHECK: {{f\d+}} ArrayGet
532 /// CHECK-NOT: {{f\d+}} ArrayGet
Mingyao Yang8df69d42015-10-22 15:40:58 -0700533
David Brazdil4833f5a2015-12-16 10:37:39 +0000534 // I/F, J/D aliasing should not happen any more and LSE should eliminate the load.
Mingyao Yang8df69d42015-10-22 15:40:58 -0700535 static float test19(float[] fa1, float[] fa2) {
536 fa1[0] = fa2[0];
537 return fa1[0];
538 }
539
540 /// CHECK-START: TestClass Main.test20() load_store_elimination (before)
541 /// CHECK: NewInstance
542 /// CHECK: InstanceFieldSet
543
544 /// CHECK-START: TestClass Main.test20() load_store_elimination (after)
545 /// CHECK: NewInstance
546 /// CHECK-NOT: InstanceFieldSet
547
548 // Storing default heap value is redundant if the heap location has the
549 // default heap value.
550 static TestClass test20() {
551 TestClass obj = new TestClass();
552 obj.i = 0;
553 return obj;
554 }
555
Mingyao Yang803cbb92015-12-01 12:24:36 -0800556 /// CHECK-START: void Main.test21(TestClass) load_store_elimination (before)
Mingyao Yangfb8464a2015-11-02 10:56:59 -0800557 /// CHECK: NewInstance
558 /// CHECK: InstanceFieldSet
Mingyao Yang803cbb92015-12-01 12:24:36 -0800559 /// CHECK: InstanceFieldSet
560 /// CHECK: InstanceFieldSet
561 /// CHECK: InstanceFieldGet
562 /// CHECK: InstanceFieldGet
Mingyao Yangfb8464a2015-11-02 10:56:59 -0800563
Mingyao Yang803cbb92015-12-01 12:24:36 -0800564 /// CHECK-START: void Main.test21(TestClass) load_store_elimination (after)
Vladimir Marko3224f382020-06-23 14:19:53 +0100565 /// CHECK-DAG: InstanceFieldSet
566 /// CHECK-DAG: Phi
567
568 /// CHECK-START: void Main.test21(TestClass) load_store_elimination (after)
569 /// CHECK-NOT: NewInstance
570 /// CHECK-NOT: InstanceFieldGet
Mingyao Yangfb8464a2015-11-02 10:56:59 -0800571
572 // Loop side effects can kill heap values, stores need to be kept in that case.
Mingyao Yang803cbb92015-12-01 12:24:36 -0800573 static void test21(TestClass obj0) {
Mingyao Yangfb8464a2015-11-02 10:56:59 -0800574 TestClass obj = new TestClass();
Mingyao Yang803cbb92015-12-01 12:24:36 -0800575 obj0.str = "abc";
Mingyao Yangfb8464a2015-11-02 10:56:59 -0800576 obj.str = "abc";
Vladimir Marko3224f382020-06-23 14:19:53 +0100577 // Note: This loop is transformed by the loop optimization pass, therefore we
578 // are not checking the exact number of InstanceFieldSet and Phi instructions.
Mingyao Yangfb8464a2015-11-02 10:56:59 -0800579 for (int i = 0; i < 2; i++) {
Mingyao Yang803cbb92015-12-01 12:24:36 -0800580 // Generate some loop side effect that writes into obj.
581 obj.str = "def";
Mingyao Yangfb8464a2015-11-02 10:56:59 -0800582 }
Vladimir Marko3224f382020-06-23 14:19:53 +0100583 $noinline$printSubstrings00(obj0.str, obj.str);
584 }
585
586 static void $noinline$printSubstrings00(String str1, String str2) {
587 System.out.print(str1.substring(0, 0) + str2.substring(0, 0));
Mingyao Yangfb8464a2015-11-02 10:56:59 -0800588 }
589
590 /// CHECK-START: int Main.test22() load_store_elimination (before)
591 /// CHECK: NewInstance
592 /// CHECK: InstanceFieldSet
593 /// CHECK: NewInstance
594 /// CHECK: InstanceFieldSet
595 /// CHECK: InstanceFieldGet
596 /// CHECK: NewInstance
597 /// CHECK: InstanceFieldSet
598 /// CHECK: InstanceFieldGet
599 /// CHECK: InstanceFieldGet
600
601 /// CHECK-START: int Main.test22() load_store_elimination (after)
Mingyao Yang062157f2016-03-02 10:15:36 -0800602 /// CHECK-NOT: NewInstance
Mingyao Yang803cbb92015-12-01 12:24:36 -0800603 /// CHECK-NOT: InstanceFieldSet
Mingyao Yangfb8464a2015-11-02 10:56:59 -0800604 /// CHECK-NOT: InstanceFieldGet
605
Mingyao Yang803cbb92015-12-01 12:24:36 -0800606 // For a singleton, loop side effects can kill its field values only if:
607 // (1) it dominiates the loop header, and
608 // (2) its fields are stored into inside a loop.
Mingyao Yangfb8464a2015-11-02 10:56:59 -0800609 static int test22() {
610 int sum = 0;
611 TestClass obj1 = new TestClass();
Mingyao Yang803cbb92015-12-01 12:24:36 -0800612 obj1.i = 2; // This store can be eliminated since obj1 is never stored into inside a loop.
Mingyao Yangfb8464a2015-11-02 10:56:59 -0800613 for (int i = 0; i < 2; i++) {
614 TestClass obj2 = new TestClass();
Mingyao Yang803cbb92015-12-01 12:24:36 -0800615 obj2.i = 3; // This store can be eliminated since the singleton is inside the loop.
Mingyao Yangfb8464a2015-11-02 10:56:59 -0800616 sum += obj2.i;
617 }
618 TestClass obj3 = new TestClass();
Mingyao Yang803cbb92015-12-01 12:24:36 -0800619 obj3.i = 5; // This store can be eliminated since the singleton is created after the loop.
Mingyao Yangfb8464a2015-11-02 10:56:59 -0800620 sum += obj1.i + obj3.i;
621 return sum;
622 }
623
Vladimir Markob122cd62020-06-11 09:15:21 +0000624 /// CHECK-START: int Main.test23(boolean) load_store_elimination (before)
Vladimir Marko3224f382020-06-23 14:19:53 +0100625 /// CHECK-DAG: <<Int1:i\d+>> IntConstant 1
626 /// CHECK-DAG: <<Int2:i\d+>> IntConstant 2
627 /// CHECK-DAG: <<Int3:i\d+>> IntConstant 3
628 /// CHECK-DAG: <<Obj:l\d+>> NewInstance
629 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Int3>>]
630 /// CHECK-DAG: <<Add1:i\d+>> Add [<<Get1:i\d+>>,<<Int1>>]
631 /// CHECK-DAG: <<Get1>> InstanceFieldGet [<<Obj>>]
632 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Add1>>]
633 /// CHECK-DAG: <<Add2:i\d+>> Add [<<Get2:i\d+>>,<<Int2>>]
634 /// CHECK-DAG: <<Get2>> InstanceFieldGet [<<Obj>>]
635 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Add2>>]
636 /// CHECK-DAG: Return [<<Get3:i\d+>>]
637 /// CHECK-DAG: <<Get3>> InstanceFieldGet [<<Obj>>]
Vladimir Markob122cd62020-06-11 09:15:21 +0000638
639 /// CHECK-START: int Main.test23(boolean) load_store_elimination (after)
Vladimir Marko3224f382020-06-23 14:19:53 +0100640 /// CHECK-DAG: <<Int1:i\d+>> IntConstant 1
641 /// CHECK-DAG: <<Int2:i\d+>> IntConstant 2
642 /// CHECK-DAG: <<Int3:i\d+>> IntConstant 3
643 /// CHECK-DAG: <<Add1:i\d+>> Add [<<Int3>>,<<Int1>>]
644 /// CHECK-DAG: <<Add2:i\d+>> Add [<<Int3>>,<<Int2>>]
645 /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Arg1:i\d+>>,<<Arg2:i\d+>>]
646 /// CHECK-DAG: Return [<<Phi>>]
647 /// CHECK-EVAL: set(["<<Arg1>>","<<Arg2>>"]) == set(["<<Add1>>","<<Add2>>"])
Vladimir Markob122cd62020-06-11 09:15:21 +0000648
649 /// CHECK-START: int Main.test23(boolean) load_store_elimination (after)
Vladimir Marko3224f382020-06-23 14:19:53 +0100650 /// CHECK-NOT: NewInstance
Vladimir Markob122cd62020-06-11 09:15:21 +0000651 /// CHECK-NOT: InstanceFieldSet
Vladimir Markob122cd62020-06-11 09:15:21 +0000652 /// CHECK-NOT: InstanceFieldGet
653
Vladimir Marko3224f382020-06-23 14:19:53 +0100654 // Test heap value merging from multiple branches.
Vladimir Markob122cd62020-06-11 09:15:21 +0000655 static int test23(boolean b) {
656 TestClass obj = new TestClass();
657 obj.i = 3; // This store can be eliminated since the value flows into each branch.
658 if (b) {
Vladimir Marko3224f382020-06-23 14:19:53 +0100659 obj.i += 1; // This store can be eliminated after replacing the load below with a Phi.
Vladimir Markob122cd62020-06-11 09:15:21 +0000660 } else {
Vladimir Marko3224f382020-06-23 14:19:53 +0100661 obj.i += 2; // This store can be eliminated after replacing the load below with a Phi.
Vladimir Markob122cd62020-06-11 09:15:21 +0000662 }
Vladimir Marko3224f382020-06-23 14:19:53 +0100663 return obj.i; // This load is eliminated by creating a Phi.
Vladimir Markob122cd62020-06-11 09:15:21 +0000664 }
665
666 /// CHECK-START: float Main.test24() load_store_elimination (before)
667 /// CHECK-DAG: <<True:i\d+>> IntConstant 1
668 /// CHECK-DAG: <<Float8:f\d+>> FloatConstant 8
669 /// CHECK-DAG: <<Float42:f\d+>> FloatConstant 42
670 /// CHECK-DAG: <<Obj:l\d+>> NewInstance
671 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<True>>]
672 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Float8>>]
673 /// CHECK-DAG: <<GetTest:z\d+>> InstanceFieldGet [<<Obj>>]
674 /// CHECK-DAG: <<GetField:f\d+>> InstanceFieldGet [<<Obj>>]
675 /// CHECK-DAG: <<Select:f\d+>> Select [<<Float42>>,<<GetField>>,<<GetTest>>]
676 /// CHECK-DAG: Return [<<Select>>]
677
678 /// CHECK-START: float Main.test24() load_store_elimination (after)
679 /// CHECK-DAG: <<True:i\d+>> IntConstant 1
680 /// CHECK-DAG: <<Float8:f\d+>> FloatConstant 8
681 /// CHECK-DAG: <<Float42:f\d+>> FloatConstant 42
682 /// CHECK-DAG: <<Select:f\d+>> Select [<<Float42>>,<<Float8>>,<<True>>]
683 /// CHECK-DAG: Return [<<Select>>]
684
Vladimir Marko3224f382020-06-23 14:19:53 +0100685 /// CHECK-START: float Main.test24() load_store_elimination (after)
686 /// CHECK-NOT: NewInstance
687 /// CHECK-NOT: InstanceFieldGet
Vladimir Markob122cd62020-06-11 09:15:21 +0000688 static float test24() {
689 float a = 42.0f;
690 TestClass3 obj = new TestClass3();
691 if (obj.test1) {
692 a = obj.floatField;
693 }
694 return a;
695 }
696
Vladimir Marko3224f382020-06-23 14:19:53 +0100697 /// CHECK-START: int Main.test25(boolean, boolean, boolean) load_store_elimination (before)
698 /// CHECK-DAG: <<Int1:i\d+>> IntConstant 1
699 /// CHECK-DAG: <<Int2:i\d+>> IntConstant 2
700 /// CHECK-DAG: <<Int3:i\d+>> IntConstant 3
701 /// CHECK-DAG: <<Int5:i\d+>> IntConstant 5
702 /// CHECK-DAG: <<Int6:i\d+>> IntConstant 6
703 /// CHECK-DAG: <<Obj:l\d+>> NewInstance
704 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Int1>>]
705 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Int2>>]
706 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Int3>>]
707 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Int5>>]
708 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Int6>>]
709 /// CHECK-DAG: <<GetField:i\d+>> InstanceFieldGet [<<Obj>>]
710 /// CHECK-DAG: Return [<<GetField>>]
711
712 /// CHECK-START: int Main.test25(boolean, boolean, boolean) load_store_elimination (after)
713 /// CHECK-DAG: <<Int1:i\d+>> IntConstant 1
714 /// CHECK-DAG: <<Int2:i\d+>> IntConstant 2
715 /// CHECK-DAG: <<Int3:i\d+>> IntConstant 3
716 /// CHECK-DAG: <<Int5:i\d+>> IntConstant 5
717 /// CHECK-DAG: <<Int6:i\d+>> IntConstant 6
718 /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Arg1:i\d+>>,<<Arg2:i\d+>>,<<Arg3:i\d+>>,<<Arg4:i\d+>>,<<Arg5:i\d+>>]
719 /// CHECK-DAG: Return [<<Phi>>]
720 /// CHECK-EVAL: set(["<<Arg1>>","<<Arg2>>","<<Arg3>>","<<Arg4>>","<<Arg5>>"]) == set(["<<Int1>>","<<Int2>>","<<Int3>>","<<Int5>>","<<Int6>>"])
721
722 /// CHECK-START: int Main.test25(boolean, boolean, boolean) load_store_elimination (after)
723 /// CHECK-NOT: NewInstance
724 /// CHECK-NOT: InstanceFieldSet
725 /// CHECK-NOT: InstanceFieldGet
726
727 // Test heap value merging from nested branches.
728 static int test25(boolean b, boolean c, boolean d) {
729 TestClass obj = new TestClass();
730 if (b) {
731 if (c) {
732 obj.i = 1;
733 } else {
734 if (d) {
735 obj.i = 2;
736 } else {
737 obj.i = 3;
738 }
739 }
740 } else {
741 if (c) {
742 obj.i = 5;
743 } else {
744 obj.i = 6;
745 }
746 }
747 return obj.i;
748 }
749
750 /// CHECK-START: float Main.test26(int) load_store_elimination (before)
751 /// CHECK-DAG: <<Float0:f\d+>> FloatConstant 0
752 /// CHECK-DAG: <<Float1:f\d+>> FloatConstant 1
753 /// CHECK-DAG: <<Float2:f\d+>> FloatConstant 2
754 /// CHECK-DAG: <<Float3:f\d+>> FloatConstant 3
755 /// CHECK-DAG: <<Float8:f\d+>> FloatConstant 8
756 /// CHECK-DAG: <<Obj:l\d+>> NewInstance
757 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Float8>>]
758 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Float0>>]
759 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Float1>>]
760 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Float2>>]
761 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Float3>>]
762 /// CHECK-DAG: <<GetField:f\d+>> InstanceFieldGet [<<Obj>>]
763 /// CHECK-DAG: Return [<<GetField>>]
764
765 /// CHECK-START: float Main.test26(int) load_store_elimination (after)
766 /// CHECK-DAG: <<Float0:f\d+>> FloatConstant 0
767 /// CHECK-DAG: <<Float1:f\d+>> FloatConstant 1
768 /// CHECK-DAG: <<Float2:f\d+>> FloatConstant 2
769 /// CHECK-DAG: <<Float3:f\d+>> FloatConstant 3
770 /// CHECK-DAG: <<Float8:f\d+>> FloatConstant 8
771 /// CHECK-DAG: <<Phi:f\d+>> Phi [<<Arg1:f\d+>>,<<Arg2:f\d+>>,<<Arg3:f\d+>>,<<Arg4:f\d+>>]
772 /// CHECK-DAG: Return [<<Phi>>]
773 /// CHECK-EVAL: set(["<<Arg1>>","<<Arg2>>","<<Arg3>>","<<Arg4>>"]) == set(["<<Float0>>","<<Float1>>","<<Float2>>","<<Float3>>"])
774
775 /// CHECK-START: float Main.test26(int) load_store_elimination (after)
776 /// CHECK-NOT: NewInstance
777 /// CHECK-NOT: InstanceFieldSet
778 /// CHECK-NOT: InstanceFieldGet
779
780 // Test heap value merging from switch statement.
781 static float test26(int b) {
782 TestClass3 obj = new TestClass3();
783 switch (b) {
784 case 1:
785 obj.floatField = 3.0f;
786 break;
787 case 2:
788 obj.floatField = 2.0f;
789 break;
790 case 3:
791 obj.floatField = 1.0f;
792 break;
793 default:
794 obj.floatField = 0.0f;
795 break;
796 }
797 return obj.floatField;
798 }
799
800 /// CHECK-START: int Main.test27(boolean, boolean) load_store_elimination (before)
801 /// CHECK-DAG: <<Int1:i\d+>> IntConstant 1
802 /// CHECK-DAG: <<Obj:l\d+>> NewInstance
803 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Int1>>]
804 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Int1>>]
805 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Int1>>]
806 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Int1>>]
807 /// CHECK-DAG: <<GetField:i\d+>> InstanceFieldGet [<<Obj>>]
808 /// CHECK-DAG: Return [<<GetField>>]
809
810 /// CHECK-START: int Main.test27(boolean, boolean) load_store_elimination (after)
811 /// CHECK-DAG: <<Int1:i\d+>> IntConstant 1
812 /// CHECK-DAG: Return [<<Int1>>]
813
814 /// CHECK-START: int Main.test27(boolean, boolean) load_store_elimination (after)
815 /// CHECK-NOT: NewInstance
816 /// CHECK-NOT: InstanceFieldSet
817 /// CHECK-NOT: InstanceFieldGet
818 /// CHECK-NOT: Phi
819
820 // Test merging same value from nested branches.
821 static int test27(boolean b, boolean c) {
822 TestClass obj = new TestClass();
823 if (b) {
824 if (c) {
825 obj.i = 1;
826 } else {
827 obj.i = 1;
828 }
829 } else {
830 if (c) {
831 obj.i = 1;
832 } else {
833 obj.i = 1;
834 }
835 }
836 return obj.i;
837 }
838
839 /// CHECK-START: int Main.test28(boolean, boolean) load_store_elimination (before)
840 /// CHECK-DAG: <<Int0:i\d+>> IntConstant 0
841 /// CHECK-DAG: <<Int5:i\d+>> IntConstant 5
842 /// CHECK-DAG: <<Int6:i\d+>> IntConstant 6
843 /// CHECK-DAG: <<Array:l\d+>> NewArray
844 /// CHECK-DAG: ArraySet [<<Array>>,<<Int0>>,<<Int5>>]
845 /// CHECK-DAG: ArraySet [<<Array>>,<<Int0>>,<<Int6>>]
846 /// CHECK-DAG: <<GetIndex:i\d+>> ArrayGet [<<Array>>,<<Int0>>]
847 /// CHECK-DAG: Return [<<GetIndex>>]
848
849 /// CHECK-START: int Main.test28(boolean, boolean) load_store_elimination (after)
850 /// CHECK-DAG: <<Int0:i\d+>> IntConstant 0
851 /// CHECK-DAG: <<Int5:i\d+>> IntConstant 5
852 /// CHECK-DAG: <<Int6:i\d+>> IntConstant 6
853 /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Arg1:i\d+>>,<<Arg2:i\d+>>,<<Arg3:i\d+>>]
854 /// CHECK-DAG: Return [<<Phi>>]
855 /// CHECK-EVAL: set(["<<Arg1>>","<<Arg2>>","<<Arg3>>"]) == set(["<<Int0>>","<<Int5>>","<<Int6>>"])
856
857 /// CHECK-START: int Main.test28(boolean, boolean) load_store_elimination (after)
858 /// CHECK-NOT: NewArray
859 /// CHECK-NOT: ArraySet
860 /// CHECK-NOT: ArrayGet
861
862 // Test merging array stores in branches.
863 static int test28(boolean b, boolean c) {
864 int[] array = new int[1];
865 if (b) {
866 if (c) {
867 array[0] = 5;
868 } else {
869 array[0] = 6;
870 }
871 } else { /* Default value: 0. */ }
872 return array[0];
873 }
874
875 /// CHECK-START: float Main.test29(boolean) load_store_elimination (before)
876 /// CHECK-DAG: <<Float2:f\d+>> FloatConstant 2
877 /// CHECK-DAG: <<Float5:f\d+>> FloatConstant 5
878 /// CHECK-DAG: <<Float8:f\d+>> FloatConstant 8
879 /// CHECK-DAG: <<Obj:l\d+>> NewInstance
880 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Float8>>]
881 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Float2>>]
882 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Float5>>]
883 /// CHECK-DAG: <<GetField:f\d+>> InstanceFieldGet [<<Obj>>]
884 /// CHECK-DAG: Return [<<GetField>>]
885
886 /// CHECK-START: float Main.test29(boolean) load_store_elimination (after)
887 /// CHECK-DAG: <<Float2:f\d+>> FloatConstant 2
888 /// CHECK-DAG: <<Float5:f\d+>> FloatConstant 5
889 /// CHECK-DAG: <<Float8:f\d+>> FloatConstant 8
890 /// CHECK-DAG: <<Phi:f\d+>> Phi [<<Arg1:f\d+>>,<<Arg2:f\d+>>]
891 /// CHECK-DAG: Return [<<Phi>>]
892 /// CHECK-EVAL: set(["<<Arg1>>","<<Arg2>>"]) == set(["<<Float5>>","<<Float2>>"])
893
894 /// CHECK-START: float Main.test29(boolean) load_store_elimination (after)
895 /// CHECK-NOT: NewInstance
896 /// CHECK-NOT: InstanceFieldSet
897 /// CHECK-NOT: InstanceFieldGet
898
899 // Test implicit type conversion in branches.
900 static float test29(boolean b) {
901 TestClass3 obj = new TestClass3();
902 if (b) {
903 obj.floatField = 5; // Int
904 } else {
905 obj.floatField = 2L; // Long
906 }
907 return obj.floatField;
908 }
909
910 /// CHECK-START: int Main.test30(TestClass, boolean) load_store_elimination (before)
911 /// CHECK-DAG: <<Int1:i\d+>> IntConstant 1
912 /// CHECK-DAG: <<Int2:i\d+>> IntConstant 2
913 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int1>>]
914 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int2>>]
915 /// CHECK-DAG: <<GetField:i\d+>> InstanceFieldGet [{{l\d+}}]
916 /// CHECK-DAG: Return [<<GetField>>]
917
918 /// CHECK-START: int Main.test30(TestClass, boolean) load_store_elimination (after)
919 /// CHECK-DAG: <<Int1:i\d+>> IntConstant 1
920 /// CHECK-DAG: <<Int2:i\d+>> IntConstant 2
921 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int1>>]
922 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int2>>]
923 /// CHECK-DAG: <<GetField:i\d+>> InstanceFieldGet [{{l\d+}}]
924 /// CHECK-DAG: Return [<<GetField>>]
925
926 /// CHECK-START: int Main.test30(TestClass, boolean) load_store_elimination (after)
927 /// CHECK-NOT: Phi
928
929 // Don't merge different values in two branches for different variables.
930 static int test30(TestClass obj, boolean b) {
931 if (b) {
932 obj.i = 1;
933 } else {
934 obj.j = 2;
935 }
936 return obj.i;
937 }
938
939 /// CHECK-START: int Main.test31(boolean, boolean) load_store_elimination (before)
940 /// CHECK-DAG: <<Int2:i\d+>> IntConstant 2
941 /// CHECK-DAG: <<Int5:i\d+>> IntConstant 5
942 /// CHECK-DAG: <<Int6:i\d+>> IntConstant 6
943 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int5>>] field_name:{{.*TestClass.i}}
944 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int6>>] field_name:{{.*TestClass.i}}
945 /// CHECK-DAG: <<Get1:i\d+>> InstanceFieldGet [{{l\d+}}] field_name:{{.*TestClass.i}}
946 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Get1>>] field_name:{{.*TestClass.j}}
947 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int2>>] field_name:{{.*TestClass.i}}
948 /// CHECK-DAG: <<Get2:i\d+>> InstanceFieldGet [{{l\d+}}]
949 /// CHECK-DAG: Return [<<Get2>>]
950
951 /// CHECK-START: int Main.test31(boolean, boolean) load_store_elimination (after)
952 /// CHECK-DAG: <<Int2:i\d+>> IntConstant 2
953 /// CHECK-DAG: <<Int5:i\d+>> IntConstant 5
954 /// CHECK-DAG: <<Int6:i\d+>> IntConstant 6
955 /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Int5>>,<<Int6>>]
956 /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Phi1>>,<<Int2>>]
957 /// CHECK-DAG: Return [<<Phi2>>]
958
959 /// CHECK-START: int Main.test31(boolean, boolean) load_store_elimination (after)
960 /// CHECK-NOT: NewInstance
961 /// CHECK-NOT: InstanceFieldSet
962 /// CHECK-NOT: InstanceFieldGet
963
964 // Test nested branches that can't be flattened.
965 static int test31(boolean b, boolean c) {
966 TestClass obj = new TestClass();
967 if (b) {
968 if (c) {
969 obj.i = 5;
970 } else {
971 obj.i = 6;
972 }
973 obj.j = obj.i;
974 } else {
975 obj.i = 2;
976 }
977 return obj.i;
978 }
979
980 /// CHECK-START: int Main.test32(int) load_store_elimination (before)
981 /// CHECK-DAG: <<Int1:i\d+>> IntConstant 1
982 /// CHECK-DAG: <<Int10:i\d+>> IntConstant 10
983 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int1>>] field_name:{{.*TestClass2.i}}
984 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int1>>] field_name:{{.*TestClass2.j}}
985 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int1>>] field_name:{{.*TestClass2.k}}
986 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int1>>] field_name:{{.*TestClass2.l}}
987 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int1>>] field_name:{{.*TestClass2.m}}
988 /// CHECK-DAG: Return [<<Int10>>]
989
990 /// CHECK-START: int Main.test32(int) load_store_elimination (after)
991 /// CHECK-DAG: <<Int10:i\d+>> IntConstant 10
992 /// CHECK-DAG: Return [<<Int10>>]
993
994 /// CHECK-START: int Main.test32(int) load_store_elimination (after)
995 /// CHECK-NOT: NewInstance
996 /// CHECK-NOT: InstanceFieldGet
997 /// CHECK-NOT: InstanceFieldSet
998 /// CHECK-NOT: Phi
999
1000 // Test no unused Phi instructions are created.
1001 static int test32(int i) {
1002 TestClass2 obj = new TestClass2();
1003 // By default, i/j/k/l/m are initialized to 0.
1004 switch (i) {
1005 case 1: obj.i = 1; break;
1006 case 2: obj.j = 1; break;
1007 case 3: obj.k = 1; break;
1008 case 4: obj.l = 1; break;
1009 case 5: obj.m = 1; break;
1010 }
1011 // So here, each variable has value Phi [0,1,1,1,1,1].
1012 // But since no heap values are used, we should not be creating these Phis.
1013 return 10;
1014 }
1015
1016 /// CHECK-START: int Main.test33(TestClass, boolean) load_store_elimination (before)
1017 /// CHECK-DAG: InstanceFieldSet
1018 /// CHECK-DAG: InstanceFieldSet
1019 /// CHECK-DAG: <<Phi:i\d+>> Phi
1020 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Phi>>]
1021
1022 /// CHECK-START: int Main.test33(TestClass, boolean) load_store_elimination (after)
1023 /// CHECK-DAG: InstanceFieldSet
1024 /// CHECK-DAG: Phi
1025
1026 /// CHECK-START: int Main.test33(TestClass, boolean) load_store_elimination (after)
1027 /// CHECK: InstanceFieldSet
1028 /// CHECK-NOT: InstanceFieldSet
1029
1030 // Test eliminating non-observable stores.
1031 static int test33(TestClass obj, boolean x) {
1032 int phi;
1033 if (x) {
1034 obj.i = 1;
1035 phi = 1;
1036 } else {
1037 obj.i = 2;
1038 phi = 2;
1039 }
1040 obj.i = phi;
1041 return phi;
1042 }
1043
1044 /// CHECK-START: int Main.test34(TestClass, boolean, boolean) load_store_elimination (before)
1045 /// CHECK-DAG: InstanceFieldSet
1046 /// CHECK-DAG: InstanceFieldSet
1047 /// CHECK-DAG: <<Phi:i\d+>> Phi
1048 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Phi>>]
1049
1050 /// CHECK-START: int Main.test34(TestClass, boolean, boolean) load_store_elimination (after)
1051 /// CHECK-DAG: InstanceFieldSet
1052 /// CHECK-DAG: InstanceFieldSet
1053 /// CHECK-DAG: Phi
1054
1055 /// CHECK-START: int Main.test34(TestClass, boolean, boolean) load_store_elimination (after)
1056 /// CHECK: InstanceFieldSet
1057 /// CHECK: InstanceFieldSet
1058 /// CHECK-NOT: InstanceFieldSet
1059
1060 // Test eliminating a store that writes a Phi equivalent to merged
1061 // heap values of observable stores.
1062 static int test34(TestClass obj, boolean x, boolean y) {
1063 int phi;
1064 if (x) {
1065 obj.i = 1;
1066 phi = 1;
1067 if (y) {
1068 return 3;
1069 }
1070 } else {
1071 obj.i = 2;
1072 phi = 2;
1073 if (y) {
1074 return 4;
1075 }
1076 }
1077 obj.i = phi;
1078 return phi;
1079 }
1080
1081 /// CHECK-START: int Main.test35(TestClass, boolean, boolean) load_store_elimination (before)
1082 /// CHECK-DAG: InstanceFieldSet
1083 /// CHECK-DAG: InstanceFieldSet
1084 /// CHECK-DAG: InstanceFieldSet
1085 /// CHECK-DAG: InstanceFieldSet
1086 /// CHECK-DAG: InstanceFieldGet
1087
1088 /// CHECK-START: int Main.test35(TestClass, boolean, boolean) load_store_elimination (after)
1089 /// CHECK-DAG: InstanceFieldSet
1090 /// CHECK-DAG: InstanceFieldSet
1091 /// CHECK-DAG: InstanceFieldSet
1092 /// CHECK-DAG: InstanceFieldSet
1093 /// CHECK-DAG: Phi
1094 /// CHECK-DAG: Phi
1095 /// CHECK-DAG: Phi
1096
1097 /// CHECK-START: int Main.test35(TestClass, boolean, boolean) load_store_elimination (after)
1098 /// CHECK-NOT: InstanceFieldGet
1099
1100 // Test Phi creation for load elimination.
1101 static int test35(TestClass obj, boolean x, boolean y) {
1102 if (x) {
1103 obj.i = 1;
1104 } else {
1105 obj.i = 2;
1106 }
1107 if (y) {
1108 if (x) {
1109 obj.i = 3;
1110 }
1111 obj.j = 5;
1112 }
1113 return obj.i;
1114 }
1115
1116 /// CHECK-START: int Main.test36(TestClass, boolean) load_store_elimination (before)
1117 /// CHECK-DAG: InstanceFieldSet
1118 /// CHECK-DAG: InstanceFieldSet
1119 /// CHECK-DAG: Phi
1120 /// CHECK-DAG: InstanceFieldGet
1121
1122 /// CHECK-START: int Main.test36(TestClass, boolean) load_store_elimination (after)
1123 /// CHECK-DAG: InstanceFieldSet
1124 /// CHECK-DAG: InstanceFieldSet
1125 /// CHECK-DAG: Phi
1126
1127 /// CHECK-START: int Main.test36(TestClass, boolean) load_store_elimination (after)
1128 /// CHECK-NOT: InstanceFieldGet
1129
1130 /// CHECK-START: int Main.test36(TestClass, boolean) load_store_elimination (after)
1131 /// CHECK: Phi
1132 /// CHECK-NOT: Phi
1133
1134 // Test Phi matching for load elimination.
1135 static int test36(TestClass obj, boolean x) {
1136 int phi;
1137 if (x) {
1138 obj.i = 1;
1139 phi = 1;
1140 } else {
1141 obj.i = 2;
1142 phi = 2;
1143 }
1144 // The load is replaced by the existing Phi instead of constructing a new one.
1145 return obj.i + phi;
1146 }
1147
1148 /// CHECK-START: int Main.test37(TestClass, boolean) load_store_elimination (before)
1149 /// CHECK-DAG: InstanceFieldSet
1150 /// CHECK-DAG: InstanceFieldGet
1151 /// CHECK-DAG: InstanceFieldSet
1152
1153 /// CHECK-START: int Main.test37(TestClass, boolean) load_store_elimination (after)
1154 /// CHECK-DAG: InstanceFieldSet
1155 /// CHECK-DAG: InstanceFieldGet
1156 /// CHECK-DAG: InstanceFieldSet
1157
1158 // Test preserving observable stores.
1159 static int test37(TestClass obj, boolean x) {
1160 if (x) {
1161 obj.i = 1;
1162 }
1163 int tmp = obj.i; // The store above must be kept.
1164 obj.i = 2;
1165 return tmp;
1166 }
1167
1168 /// CHECK-START: int Main.test38(TestClass, boolean) load_store_elimination (before)
1169 /// CHECK-DAG: InstanceFieldSet
1170 /// CHECK-DAG: InstanceFieldSet
1171 /// CHECK-DAG: InstanceFieldSet
1172 /// CHECK-DAG: InstanceFieldSet
1173
1174 /// CHECK-START: int Main.test38(TestClass, boolean) load_store_elimination (after)
1175 /// CHECK: InstanceFieldSet
1176 /// CHECK-NOT: InstanceFieldSet
1177
1178 // Test eliminating store of the same value after eliminating non-observable stores.
1179 static int test38(TestClass obj, boolean x) {
1180 obj.i = 1;
1181 if (x) {
1182 return 1; // The store above must be kept.
1183 }
1184 obj.i = 2; // Not observable, shall be eliminated.
1185 obj.i = 3; // Not observable, shall be eliminated.
1186 obj.i = 1; // After eliminating the non-observable stores above, this stores the
1187 // same value that is already stored in `obj.i` and shall be eliminated.
1188 return 2;
1189 }
1190
1191 /// CHECK-START: int Main.test39(TestClass, boolean) load_store_elimination (before)
1192 /// CHECK-DAG: NewInstance
1193 /// CHECK-DAG: InstanceFieldSet
1194 /// CHECK-DAG: NewInstance
1195 /// CHECK-DAG: InstanceFieldSet
1196 /// CHECK-DAG: InstanceFieldGet
1197 /// CHECK-DAG: InstanceFieldGet
1198
1199 /// CHECK-START: int Main.test39(TestClass, boolean) load_store_elimination (after)
1200 /// CHECK-DAG: NewInstance
1201 /// CHECK-DAG: InstanceFieldSet
1202 /// CHECK-DAG: NewInstance
1203 /// CHECK-DAG: InstanceFieldSet
1204 /// CHECK-DAG: Phi
1205 /// CHECK-DAG: InstanceFieldGet
1206
1207 /// CHECK-START: int Main.test39(TestClass, boolean) load_store_elimination (after)
1208 /// CHECK: InstanceFieldGet
1209 /// CHECK-NOT: InstanceFieldGet
1210
1211 // Test creating a reference Phi for load elimination.
1212 static int test39(TestClass obj, boolean x) {
1213 obj.next = new TestClass(1, 2);
1214 if (x) {
1215 obj.next = new SubTestClass();
1216 }
1217 return obj.next.i;
1218 }
1219
Vladimir Marko4307cd72020-07-17 14:35:56 +01001220 /// CHECK-START: int Main.$noinline$testConversion1(TestClass, int) load_store_elimination (before)
1221 /// CHECK-DAG: InstanceFieldSet
1222 /// CHECK-DAG: InstanceFieldSet
1223 /// CHECK-DAG: InstanceFieldGet
1224 /// CHECK-DAG: InstanceFieldSet
1225 /// CHECK-DAG: InstanceFieldGet
1226
1227 /// CHECK-START: int Main.$noinline$testConversion1(TestClass, int) load_store_elimination (after)
1228 /// CHECK-DAG: InstanceFieldSet
1229 /// CHECK-DAG: InstanceFieldSet
1230 /// CHECK-DAG: TypeConversion
1231 /// CHECK-DAG: InstanceFieldSet
Vladimir Marko3224f382020-06-23 14:19:53 +01001232 /// CHECK-DAG: Phi
1233
1234 /// CHECK-START: int Main.$noinline$testConversion1(TestClass, int) load_store_elimination (after)
1235 /// CHECK: Phi
1236 /// CHECK-NOT: Phi
1237
1238 // Test tracking values containing type conversion.
1239 // Regression test for b/161521389 .
Vladimir Marko4307cd72020-07-17 14:35:56 +01001240 static int $noinline$testConversion1(TestClass obj, int x) {
1241 obj.i = x;
1242 if ((x & 1) != 0) {
1243 obj.b = (byte) x;
1244 obj.i = obj.b;
1245 }
1246 return obj.i;
1247 }
1248
1249 /// CHECK-START: int Main.$noinline$testConversion2(TestClass, int) load_store_elimination (before)
1250 /// CHECK-DAG: InstanceFieldSet
1251 /// CHECK-DAG: InstanceFieldSet
1252 /// CHECK-DAG: InstanceFieldGet
1253 /// CHECK-DAG: InstanceFieldSet
Vladimir Marko3224f382020-06-23 14:19:53 +01001254 /// CHECK-DAG: TypeConversion
1255 /// CHECK-DAG: Phi
Vladimir Marko4307cd72020-07-17 14:35:56 +01001256 /// CHECK-DAG: InstanceFieldGet
1257
1258 /// CHECK-START: int Main.$noinline$testConversion2(TestClass, int) load_store_elimination (after)
1259 /// CHECK-DAG: InstanceFieldSet
1260 /// CHECK-DAG: InstanceFieldSet
1261 /// CHECK-DAG: TypeConversion
1262 /// CHECK-DAG: InstanceFieldSet
Vladimir Marko3224f382020-06-23 14:19:53 +01001263 /// CHECK-DAG: Phi
1264 /// CHECK-DAG: Phi
1265
1266 /// CHECK-START: int Main.$noinline$testConversion2(TestClass, int) load_store_elimination (after)
1267 /// CHECK: Phi
1268 /// CHECK: Phi
1269 /// CHECK-NOT: Phi
Vladimir Marko4307cd72020-07-17 14:35:56 +01001270
1271 /// CHECK-START: int Main.$noinline$testConversion2(TestClass, int) load_store_elimination (after)
1272 /// CHECK: TypeConversion
1273 /// CHECK-NOT: TypeConversion
Vladimir Marko3224f382020-06-23 14:19:53 +01001274
1275 /// CHECK-START: int Main.$noinline$testConversion2(TestClass, int) load_store_elimination (after)
1276 /// CHECK-NOT: InstanceFieldGet
1277
1278 // Test moving type conversion when needed.
Vladimir Marko4307cd72020-07-17 14:35:56 +01001279 static int $noinline$testConversion2(TestClass obj, int x) {
1280 int tmp = 0;
1281 obj.i = x;
1282 if ((x & 1) != 0) {
1283 // The instruction simplifier can remove this TypeConversion if there are
1284 // no environment uses. Currently, there is an environment use in NullCheck,
1285 // so this TypeConversion remains and GVN removes the second TypeConversion
1286 // below. Since we really want to test that the TypeConversion from below
1287 // can be moved and used for the load of `obj.b`, we have a similar test
1288 // written in smali in 530-checker-lse3, StoreLoad.test3(int), except that
1289 // it's using static fields (which would not help with the environment use).
1290 obj.b = (byte) x;
1291 obj.i = obj.b;
1292 tmp = (byte) x;
1293 }
1294 return obj.i + tmp;
1295 }
1296
Vladimir Marko3224f382020-06-23 14:19:53 +01001297 /// CHECK-START: int Main.$noinline$testConversion3(TestClass, int) load_store_elimination (before)
1298 /// CHECK-DAG: InstanceFieldSet
1299 /// CHECK-DAG: Phi
1300 /// CHECK-DAG: InstanceFieldSet
1301 /// CHECK-DAG: InstanceFieldGet
1302 /// CHECK-DAG: InstanceFieldSet
1303 /// CHECK-DAG: InstanceFieldGet
1304
1305 /// CHECK-START: int Main.$noinline$testConversion3(TestClass, int) load_store_elimination (after)
1306 /// CHECK-DAG: InstanceFieldSet
1307 /// CHECK-DAG: Phi
1308 /// CHECK-DAG: Phi
1309 /// CHECK-DAG: InstanceFieldSet
1310 /// CHECK-DAG: TypeConversion
1311 /// CHECK-DAG: InstanceFieldSet
1312
1313 /// CHECK-START: int Main.$noinline$testConversion3(TestClass, int) load_store_elimination (after)
1314 /// CHECK: Phi
1315 /// CHECK: Phi
1316 /// CHECK-NOT: Phi
1317
1318 /// CHECK-START: int Main.$noinline$testConversion3(TestClass, int) load_store_elimination (after)
1319 /// CHECK: TypeConversion
1320 /// CHECK-NOT: TypeConversion
1321
1322 /// CHECK-START: int Main.$noinline$testConversion3(TestClass, int) load_store_elimination (after)
1323 /// CHECK-NOT: InstanceFieldGet
1324
1325 // Test tracking values containing type conversion with loop.
1326 static int $noinline$testConversion3(TestClass obj, int x) {
1327 obj.i = x;
1328 for (int i = 0; i < x; ++i) {
1329 obj.b = (byte) i;
1330 obj.i = obj.b;
1331 }
1332 return obj.i;
1333 }
1334
1335 /// CHECK-START: int Main.$noinline$testConversion4(TestClass, int) load_store_elimination (before)
1336 /// CHECK-DAG: InstanceFieldSet
1337 /// CHECK-DAG: Phi
1338 /// CHECK-DAG: Phi
1339 /// CHECK-DAG: InstanceFieldSet
1340 /// CHECK-DAG: InstanceFieldGet
1341 /// CHECK-DAG: InstanceFieldSet
1342 /// CHECK-DAG: TypeConversion
1343 /// CHECK-DAG: InstanceFieldGet
1344
1345 /// CHECK-START: int Main.$noinline$testConversion4(TestClass, int) load_store_elimination (after)
1346 /// CHECK-DAG: InstanceFieldSet
1347 /// CHECK-DAG: Phi
1348 /// CHECK-DAG: Phi
1349 /// CHECK-DAG: InstanceFieldSet
1350 /// CHECK-DAG: TypeConversion
1351 /// CHECK-DAG: InstanceFieldSet
1352
1353 /// CHECK-START: int Main.$noinline$testConversion4(TestClass, int) load_store_elimination (after)
1354 /// CHECK: Phi
1355 /// CHECK: Phi
1356 /// CHECK-NOT: Phi
1357
1358 /// CHECK-START: int Main.$noinline$testConversion4(TestClass, int) load_store_elimination (after)
1359 /// CHECK: TypeConversion
1360 /// CHECK-NOT: TypeConversion
1361
1362 /// CHECK-START: int Main.$noinline$testConversion4(TestClass, int) load_store_elimination (after)
1363 /// CHECK-NOT: InstanceFieldGet
1364
1365 // Test moving type conversion when needed with loop.
1366 static int $noinline$testConversion4(TestClass obj, int x) {
1367 int tmp = x;
1368 obj.i = x;
1369 for (int i = 0; i < x; ++i) {
1370 obj.b = (byte) i;
1371 obj.i = obj.b;
1372 tmp = (byte) i;
1373 }
1374 return obj.i + tmp;
1375 }
1376
Mingyao Yangfb8464a2015-11-02 10:56:59 -08001377 /// CHECK-START: void Main.testFinalizable() load_store_elimination (before)
1378 /// CHECK: NewInstance
1379 /// CHECK: InstanceFieldSet
Mingyao Yang025c1a62017-10-30 11:19:57 -07001380 /// CHECK: InstanceFieldSet
Mingyao Yangfb8464a2015-11-02 10:56:59 -08001381
1382 /// CHECK-START: void Main.testFinalizable() load_store_elimination (after)
1383 /// CHECK: NewInstance
1384 /// CHECK: InstanceFieldSet
Mingyao Yang025c1a62017-10-30 11:19:57 -07001385 /// CHECK-NOT: InstanceFieldSet
Mingyao Yangfb8464a2015-11-02 10:56:59 -08001386
Mingyao Yang025c1a62017-10-30 11:19:57 -07001387 // Allocations of finalizable objects cannot be eliminated.
Mingyao Yangfb8464a2015-11-02 10:56:59 -08001388 static void testFinalizable() {
1389 Finalizable finalizable = new Finalizable();
Mingyao Yang025c1a62017-10-30 11:19:57 -07001390 finalizable.i = Finalizable.VALUE2;
1391 finalizable.i = Finalizable.VALUE1;
Mingyao Yangfb8464a2015-11-02 10:56:59 -08001392 }
1393
1394 static java.lang.ref.WeakReference<Object> getWeakReference() {
1395 return new java.lang.ref.WeakReference<>(new Object());
1396 }
1397
1398 static void testFinalizableByForcingGc() {
1399 testFinalizable();
1400 java.lang.ref.WeakReference<Object> reference = getWeakReference();
1401
1402 Runtime runtime = Runtime.getRuntime();
1403 for (int i = 0; i < 20; ++i) {
1404 runtime.gc();
1405 System.runFinalization();
1406 try {
1407 Thread.sleep(1);
1408 } catch (InterruptedException e) {
1409 throw new AssertionError(e);
1410 }
1411
1412 // Check to see if the weak reference has been garbage collected.
1413 if (reference.get() == null) {
1414 // A little bit more sleep time to make sure.
1415 try {
1416 Thread.sleep(100);
1417 } catch (InterruptedException e) {
1418 throw new AssertionError(e);
1419 }
1420 if (!Finalizable.sVisited) {
1421 System.out.println("finalize() not called.");
1422 }
1423 return;
1424 }
1425 }
1426 System.out.println("testFinalizableByForcingGc() failed to force gc.");
1427 }
1428
Mingyao Yang40bcb932016-02-03 05:46:57 -08001429 /// CHECK-START: int Main.$noinline$testHSelect(boolean) load_store_elimination (before)
Mingyao Yange5c71f92016-02-02 20:10:32 -08001430 /// CHECK: InstanceFieldSet
1431 /// CHECK: Select
1432
Mingyao Yang40bcb932016-02-03 05:46:57 -08001433 /// CHECK-START: int Main.$noinline$testHSelect(boolean) load_store_elimination (after)
Mingyao Yange5c71f92016-02-02 20:10:32 -08001434 /// CHECK: InstanceFieldSet
1435 /// CHECK: Select
1436
1437 // Test that HSelect creates alias.
Mingyao Yang062157f2016-03-02 10:15:36 -08001438 static int $noinline$testHSelect(boolean b) {
Mingyao Yange5c71f92016-02-02 20:10:32 -08001439 TestClass obj = new TestClass();
1440 TestClass obj2 = null;
1441 obj.i = 0xdead;
1442 if (b) {
1443 obj2 = obj;
1444 }
1445 return obj2.i;
1446 }
1447
Mingyao Yang062157f2016-03-02 10:15:36 -08001448 static int sumWithFilter(int[] array, Filter f) {
1449 int sum = 0;
1450 for (int i = 0; i < array.length; i++) {
1451 if (f.isValid(array[i])) {
1452 sum += array[i];
1453 }
1454 }
1455 return sum;
1456 }
1457
1458 /// CHECK-START: int Main.sumWithinRange(int[], int, int) load_store_elimination (before)
Vladimir Marko3224f382020-06-23 14:19:53 +01001459 /// CHECK-DAG: NewInstance
1460 /// CHECK-DAG: InstanceFieldSet
1461 /// CHECK-DAG: InstanceFieldSet
1462 /// CHECK-DAG: InstanceFieldGet
1463 /// CHECK-DAG: InstanceFieldGet
Mingyao Yang062157f2016-03-02 10:15:36 -08001464
1465 /// CHECK-START: int Main.sumWithinRange(int[], int, int) load_store_elimination (after)
1466 /// CHECK-NOT: NewInstance
1467 /// CHECK-NOT: InstanceFieldSet
1468 /// CHECK-NOT: InstanceFieldGet
1469
1470 // A lambda-style allocation can be eliminated after inlining.
1471 static int sumWithinRange(int[] array, final int low, final int high) {
1472 Filter filter = new Filter() {
1473 public boolean isValid(int i) {
1474 return (i >= low) && (i <= high);
1475 }
1476 };
1477 return sumWithFilter(array, filter);
1478 }
1479
Mingyao Yang0a845202016-10-14 16:26:08 -07001480 private static int mI = 0;
1481 private static float mF = 0f;
1482
1483 /// CHECK-START: float Main.testAllocationEliminationWithLoops() load_store_elimination (before)
1484 /// CHECK: NewInstance
1485 /// CHECK: NewInstance
1486 /// CHECK: NewInstance
1487
1488 /// CHECK-START: float Main.testAllocationEliminationWithLoops() load_store_elimination (after)
1489 /// CHECK-NOT: NewInstance
1490
1491 private static float testAllocationEliminationWithLoops() {
1492 for (int i0 = 0; i0 < 5; i0++) {
1493 for (int i1 = 0; i1 < 5; i1++) {
1494 for (int i2 = 0; i2 < 5; i2++) {
1495 int lI0 = ((int) new Integer(((int) new Integer(mI))));
1496 if (((boolean) new Boolean(false))) {
1497 for (int i3 = 576 - 1; i3 >= 0; i3--) {
1498 mF -= 976981405.0f;
1499 }
1500 }
1501 }
1502 }
1503 }
1504 return 1.0f;
1505 }
1506
Mingyao Yangeb2d2d346e2017-03-02 13:26:17 -08001507 /// CHECK-START: TestClass2 Main.testStoreStore() load_store_elimination (before)
1508 /// CHECK: NewInstance
1509 /// CHECK: InstanceFieldSet
1510 /// CHECK: InstanceFieldSet
1511 /// CHECK: InstanceFieldSet
1512 /// CHECK: InstanceFieldSet
1513
1514 /// CHECK-START: TestClass2 Main.testStoreStore() load_store_elimination (after)
1515 /// CHECK: NewInstance
1516 /// CHECK: InstanceFieldSet
1517 /// CHECK: InstanceFieldSet
1518 /// CHECK-NOT: InstanceFieldSet
1519
1520 private static TestClass2 testStoreStore() {
1521 TestClass2 obj = new TestClass2();
1522 obj.i = 41;
1523 obj.j = 42;
1524 obj.i = 41;
1525 obj.j = 43;
1526 return obj;
1527 }
1528
Mingyao Yanga3540532018-01-25 12:17:28 -08001529 /// CHECK-START: void Main.testStoreStore2(TestClass2) load_store_elimination (before)
1530 /// CHECK: InstanceFieldSet
1531 /// CHECK: InstanceFieldSet
1532 /// CHECK: InstanceFieldSet
1533 /// CHECK: InstanceFieldSet
1534
1535 /// CHECK-START: void Main.testStoreStore2(TestClass2) load_store_elimination (after)
1536 /// CHECK: InstanceFieldSet
1537 /// CHECK: InstanceFieldSet
1538 /// CHECK-NOT: InstanceFieldSet
1539
1540 private static void testStoreStore2(TestClass2 obj) {
1541 obj.i = 41;
1542 obj.j = 42;
1543 obj.i = 43;
1544 obj.j = 44;
1545 }
1546
1547 /// CHECK-START: void Main.testStoreStore3(TestClass2, boolean) load_store_elimination (before)
1548 /// CHECK: InstanceFieldSet
1549 /// CHECK: InstanceFieldSet
1550 /// CHECK: InstanceFieldSet
1551 /// CHECK: InstanceFieldSet
1552
1553 /// CHECK-START: void Main.testStoreStore3(TestClass2, boolean) load_store_elimination (after)
1554 /// CHECK: InstanceFieldSet
1555 /// CHECK: InstanceFieldSet
1556 /// CHECK: InstanceFieldSet
1557 /// CHECK-NOT: InstanceFieldSet
1558
Vladimir Marko3224f382020-06-23 14:19:53 +01001559 /// CHECK-START: void Main.testStoreStore3(TestClass2, boolean) load_store_elimination (after)
1560 /// CHECK-NOT: Phi
1561
Mingyao Yanga3540532018-01-25 12:17:28 -08001562 private static void testStoreStore3(TestClass2 obj, boolean flag) {
1563 obj.i = 41;
1564 obj.j = 42; // redundant since it's overwritten in both branches below.
1565 if (flag) {
1566 obj.j = 43;
1567 } else {
1568 obj.j = 44;
1569 }
1570 }
1571
1572 /// CHECK-START: void Main.testStoreStore4() load_store_elimination (before)
1573 /// CHECK: StaticFieldSet
1574 /// CHECK: StaticFieldSet
1575
1576 /// CHECK-START: void Main.testStoreStore4() load_store_elimination (after)
1577 /// CHECK: StaticFieldSet
1578 /// CHECK-NOT: StaticFieldSet
1579
1580 private static void testStoreStore4() {
1581 TestClass.si = 61;
1582 TestClass.si = 62;
1583 }
1584
1585 /// CHECK-START: int Main.testStoreStore5(TestClass2, TestClass2) load_store_elimination (before)
1586 /// CHECK: InstanceFieldSet
1587 /// CHECK: InstanceFieldGet
1588 /// CHECK: InstanceFieldSet
1589
1590 /// CHECK-START: int Main.testStoreStore5(TestClass2, TestClass2) load_store_elimination (after)
1591 /// CHECK: InstanceFieldSet
1592 /// CHECK: InstanceFieldGet
1593 /// CHECK: InstanceFieldSet
1594
1595 private static int testStoreStore5(TestClass2 obj1, TestClass2 obj2) {
1596 obj1.i = 71; // This store is needed since obj2.i may load from it.
1597 int i = obj2.i;
1598 obj1.i = 72;
1599 return i;
1600 }
1601
1602 /// CHECK-START: int Main.testStoreStore6(TestClass2, TestClass2) load_store_elimination (before)
1603 /// CHECK: InstanceFieldSet
1604 /// CHECK: InstanceFieldGet
1605 /// CHECK: InstanceFieldSet
1606
1607 /// CHECK-START: int Main.testStoreStore6(TestClass2, TestClass2) load_store_elimination (after)
1608 /// CHECK-NOT: InstanceFieldSet
1609 /// CHECK: InstanceFieldGet
1610 /// CHECK: InstanceFieldSet
1611
1612 private static int testStoreStore6(TestClass2 obj1, TestClass2 obj2) {
1613 obj1.i = 81; // This store is not needed since obj2.j cannot load from it.
1614 int j = obj2.j;
1615 obj1.i = 82;
1616 return j;
1617 }
1618
1619 /// CHECK-START: int Main.testNoSideEffects(int[]) load_store_elimination (before)
1620 /// CHECK: ArraySet
1621 /// CHECK: ArraySet
1622 /// CHECK: ArraySet
1623 /// CHECK: ArrayGet
1624
1625 /// CHECK-START: int Main.testNoSideEffects(int[]) load_store_elimination (after)
1626 /// CHECK: ArraySet
1627 /// CHECK: ArraySet
1628 /// CHECK-NOT: ArraySet
1629 /// CHECK-NOT: ArrayGet
1630
1631 private static int testNoSideEffects(int[] array) {
1632 array[0] = 101;
1633 array[1] = 102;
1634 int bitCount = Integer.bitCount(0x3456);
1635 array[1] = 103;
1636 return array[0] + bitCount;
1637 }
1638
1639 /// CHECK-START: void Main.testThrow(TestClass2, java.lang.Exception) load_store_elimination (before)
1640 /// CHECK: InstanceFieldSet
1641 /// CHECK: Throw
1642
1643 /// CHECK-START: void Main.testThrow(TestClass2, java.lang.Exception) load_store_elimination (after)
1644 /// CHECK: InstanceFieldSet
1645 /// CHECK: Throw
1646
1647 // Make sure throw keeps the store.
1648 private static void testThrow(TestClass2 obj, Exception e) throws Exception {
1649 obj.i = 55;
1650 throw e;
1651 }
1652
Mingyao Yangeb2d2d346e2017-03-02 13:26:17 -08001653 /// CHECK-START: int Main.testStoreStoreWithDeoptimize(int[]) load_store_elimination (before)
1654 /// CHECK: NewInstance
1655 /// CHECK: InstanceFieldSet
1656 /// CHECK: InstanceFieldSet
1657 /// CHECK: InstanceFieldSet
1658 /// CHECK: InstanceFieldSet
1659 /// CHECK: Deoptimize
1660 /// CHECK: ArraySet
1661 /// CHECK: ArraySet
1662 /// CHECK: ArraySet
1663 /// CHECK: ArraySet
1664 /// CHECK: ArrayGet
1665 /// CHECK: ArrayGet
1666 /// CHECK: ArrayGet
1667 /// CHECK: ArrayGet
1668
1669 /// CHECK-START: int Main.testStoreStoreWithDeoptimize(int[]) load_store_elimination (after)
1670 /// CHECK: NewInstance
1671 /// CHECK: InstanceFieldSet
1672 /// CHECK: InstanceFieldSet
1673 /// CHECK-NOT: InstanceFieldSet
1674 /// CHECK: Deoptimize
1675 /// CHECK: ArraySet
1676 /// CHECK: ArraySet
1677 /// CHECK: ArraySet
1678 /// CHECK: ArraySet
1679 /// CHECK-NOT: ArrayGet
1680
1681 private static int testStoreStoreWithDeoptimize(int[] arr) {
1682 TestClass2 obj = new TestClass2();
1683 obj.i = 41;
1684 obj.j = 42;
1685 obj.i = 41;
1686 obj.j = 43;
1687 arr[0] = 1; // One HDeoptimize here.
1688 arr[1] = 1;
1689 arr[2] = 1;
1690 arr[3] = 1;
1691 return arr[0] + arr[1] + arr[2] + arr[3];
1692 }
1693
Mingyao Yang58d9bfc2016-11-01 13:31:58 -07001694 /// CHECK-START: double Main.getCircleArea(double, boolean) load_store_elimination (before)
1695 /// CHECK: NewInstance
1696
1697 /// CHECK-START: double Main.getCircleArea(double, boolean) load_store_elimination (after)
1698 /// CHECK-NOT: NewInstance
1699
1700 private static double getCircleArea(double radius, boolean b) {
1701 double area = 0d;
1702 if (b) {
1703 area = new Circle(radius).getArea();
1704 }
1705 return area;
1706 }
1707
Mingyao Yange58bdca2016-10-28 11:07:24 -07001708 /// CHECK-START: double Main.testDeoptimize(int[], double[], double) load_store_elimination (before)
1709 /// CHECK: Deoptimize
1710 /// CHECK: NewInstance
1711 /// CHECK: Deoptimize
1712 /// CHECK: NewInstance
1713
1714 /// CHECK-START: double Main.testDeoptimize(int[], double[], double) load_store_elimination (after)
1715 /// CHECK: Deoptimize
1716 /// CHECK: NewInstance
1717 /// CHECK: Deoptimize
1718 /// CHECK-NOT: NewInstance
1719
1720 private static double testDeoptimize(int[] iarr, double[] darr, double radius) {
1721 iarr[0] = 1; // One HDeoptimize here. Not triggered.
1722 iarr[1] = 1;
1723 Circle circle1 = new Circle(radius);
1724 iarr[2] = 1;
1725 darr[0] = circle1.getRadius(); // One HDeoptimize here, which holds circle1 live. Triggered.
1726 darr[1] = circle1.getRadius();
1727 darr[2] = circle1.getRadius();
1728 darr[3] = circle1.getRadius();
1729 return new Circle(Math.PI).getArea();
1730 }
1731
Mingyao Yang86974902017-03-01 14:03:51 -08001732 /// CHECK-START: int Main.testAllocationEliminationOfArray1() load_store_elimination (before)
1733 /// CHECK: NewArray
1734 /// CHECK: ArraySet
1735 /// CHECK: ArraySet
1736 /// CHECK: ArrayGet
1737 /// CHECK: ArrayGet
1738 /// CHECK: ArrayGet
1739 /// CHECK: ArrayGet
1740
1741 /// CHECK-START: int Main.testAllocationEliminationOfArray1() load_store_elimination (after)
1742 /// CHECK-NOT: NewArray
1743 /// CHECK-NOT: ArraySet
1744 /// CHECK-NOT: ArrayGet
1745 private static int testAllocationEliminationOfArray1() {
1746 int[] array = new int[4];
1747 array[2] = 4;
1748 array[3] = 7;
1749 return array[0] + array[1] + array[2] + array[3];
1750 }
1751
1752 /// CHECK-START: int Main.testAllocationEliminationOfArray2() load_store_elimination (before)
1753 /// CHECK: NewArray
1754 /// CHECK: ArraySet
1755 /// CHECK: ArraySet
1756 /// CHECK: ArrayGet
1757
1758 /// CHECK-START: int Main.testAllocationEliminationOfArray2() load_store_elimination (after)
1759 /// CHECK: NewArray
1760 /// CHECK: ArraySet
1761 /// CHECK: ArraySet
1762 /// CHECK: ArrayGet
1763 private static int testAllocationEliminationOfArray2() {
1764 // Cannot eliminate array allocation since array is accessed with non-constant
Aart Bik0148de42017-09-05 09:25:01 -07001765 // index (only 3 elements to prevent vectorization of the reduction).
1766 int[] array = new int[3];
1767 array[1] = 4;
1768 array[2] = 7;
Mingyao Yang86974902017-03-01 14:03:51 -08001769 int sum = 0;
1770 for (int e : array) {
1771 sum += e;
1772 }
1773 return sum;
1774 }
1775
1776 /// CHECK-START: int Main.testAllocationEliminationOfArray3(int) load_store_elimination (before)
1777 /// CHECK: NewArray
1778 /// CHECK: ArraySet
1779 /// CHECK: ArrayGet
1780
1781 /// CHECK-START: int Main.testAllocationEliminationOfArray3(int) load_store_elimination (after)
1782 /// CHECK-NOT: NewArray
1783 /// CHECK-NOT: ArraySet
1784 /// CHECK-NOT: ArrayGet
1785 private static int testAllocationEliminationOfArray3(int i) {
1786 int[] array = new int[4];
1787 array[i] = 4;
1788 return array[i];
1789 }
1790
1791 /// CHECK-START: int Main.testAllocationEliminationOfArray4(int) load_store_elimination (before)
1792 /// CHECK: NewArray
1793 /// CHECK: ArraySet
1794 /// CHECK: ArraySet
1795 /// CHECK: ArrayGet
1796 /// CHECK: ArrayGet
1797
1798 /// CHECK-START: int Main.testAllocationEliminationOfArray4(int) load_store_elimination (after)
1799 /// CHECK: NewArray
1800 /// CHECK: ArraySet
1801 /// CHECK: ArraySet
1802 /// CHECK: ArrayGet
1803 /// CHECK-NOT: ArrayGet
1804 private static int testAllocationEliminationOfArray4(int i) {
1805 // Cannot eliminate array allocation due to index aliasing between 1 and i.
1806 int[] array = new int[4];
1807 array[1] = 2;
1808 array[i] = 4;
1809 return array[1] + array[i];
1810 }
1811
Mingyao Yang7cf9af22018-02-06 15:02:42 -08001812 /// CHECK-START: int Main.testAllocationEliminationOfArray5(int) load_store_elimination (before)
1813 /// CHECK: NewArray
1814 /// CHECK: ArraySet
1815 /// CHECK: ArrayGet
1816
1817 /// CHECK-START: int Main.testAllocationEliminationOfArray5(int) load_store_elimination (after)
1818 /// CHECK: NewArray
1819 /// CHECK-NOT: ArraySet
1820 /// CHECK-NOT: ArrayGet
1821 private static int testAllocationEliminationOfArray5(int i) {
1822 // Cannot eliminate array allocation due to unknown i that may
1823 // cause NegativeArraySizeException.
1824 int[] array = new int[i];
1825 array[1] = 12;
1826 return array[1];
1827 }
1828
Mingyao Yang46721ef2017-10-05 14:45:17 -07001829 /// CHECK-START: int Main.testExitMerge(boolean) load_store_elimination (before)
Vladimir Marko3224f382020-06-23 14:19:53 +01001830 /// CHECK-DAG: NewInstance
Vladimir Markoe7e123a2021-10-28 11:15:08 +01001831 /// CHECK-DAG: InstanceFieldSet field_name:TestClass.i
1832 /// CHECK-DAG: InstanceFieldGet field_name:TestClass.i
Vladimir Marko3224f382020-06-23 14:19:53 +01001833 /// CHECK-DAG: Return
Vladimir Markoe7e123a2021-10-28 11:15:08 +01001834 /// CHECK-DAG: InstanceFieldSet field_name:TestClass.i
Vladimir Marko3224f382020-06-23 14:19:53 +01001835 /// CHECK-DAG: Throw
Mingyao Yang46721ef2017-10-05 14:45:17 -07001836
1837 /// CHECK-START: int Main.testExitMerge(boolean) load_store_elimination (after)
Vladimir Marko3224f382020-06-23 14:19:53 +01001838 /// CHECK-DAG: Return
1839 /// CHECK-DAG: Throw
1840
1841 /// CHECK-START: int Main.testExitMerge(boolean) load_store_elimination (after)
Vladimir Markoe7e123a2021-10-28 11:15:08 +01001842 /// CHECK-NOT: InstanceFieldSet field_name:TestClass.i
1843 /// CHECK-NOT: InstanceFieldGet field_name:TestClass.i
Vladimir Marko3224f382020-06-23 14:19:53 +01001844
1845 /// CHECK-START: int Main.testExitMerge(boolean) load_store_elimination (after)
1846 /// CHECK: NewInstance
1847 /// CHECK-NOT: NewInstance
Mingyao Yang46721ef2017-10-05 14:45:17 -07001848 private static int testExitMerge(boolean cond) {
1849 TestClass obj = new TestClass();
1850 if (cond) {
1851 obj.i = 1;
1852 return obj.i + 1;
1853 } else {
1854 obj.i = 2;
Vladimir Marko3224f382020-06-23 14:19:53 +01001855 throw new Error(); // Note: We have a NewInstance here.
Mingyao Yang46721ef2017-10-05 14:45:17 -07001856 }
1857 }
1858
1859 /// CHECK-START: int Main.testExitMerge2(boolean) load_store_elimination (before)
Vladimir Marko3224f382020-06-23 14:19:53 +01001860 /// CHECK-DAG: NewInstance
1861 /// CHECK-DAG: InstanceFieldSet
1862 /// CHECK-DAG: InstanceFieldGet
1863 /// CHECK-DAG: InstanceFieldSet
1864 /// CHECK-DAG: InstanceFieldGet
Mingyao Yang46721ef2017-10-05 14:45:17 -07001865
1866 /// CHECK-START: int Main.testExitMerge2(boolean) load_store_elimination (after)
1867 /// CHECK-NOT: NewInstance
1868 /// CHECK-NOT: InstanceFieldSet
1869 /// CHECK-NOT: InstanceFieldGet
1870 private static int testExitMerge2(boolean cond) {
1871 TestClass obj = new TestClass();
1872 int res;
1873 if (cond) {
1874 obj.i = 1;
1875 res = obj.i + 1;
1876 } else {
1877 obj.i = 2;
1878 res = obj.j + 2;
1879 }
1880 return res;
1881 }
1882
Mingyao Yang206070c2017-11-29 23:01:58 -08001883 /// CHECK-START: void Main.testStoreSameValue() load_store_elimination (before)
1884 /// CHECK: NewArray
1885 /// CHECK: ArrayGet
1886 /// CHECK: ArraySet
1887
1888 /// CHECK-START: void Main.testStoreSameValue() load_store_elimination (after)
1889 /// CHECK: NewArray
1890 /// CHECK-NOT: ArrayGet
1891 /// CHECK-NOT: ArraySet
1892 private static void testStoreSameValue() {
1893 Object[] array = new Object[2];
1894 sArray = array;
1895 Object obj = array[0];
Vladimir Marko3224f382020-06-23 14:19:53 +01001896 array[1] = obj; // Store the same value as the default value.
Mingyao Yang206070c2017-11-29 23:01:58 -08001897 }
1898
Vladimir Marko4307cd72020-07-17 14:35:56 +01001899 /// CHECK-START: int Main.$noinline$testByteArrayDefaultValue() load_store_elimination (before)
1900 /// CHECK-DAG: NewArray
1901 /// CHECK-DAG: <<Value:b\d+>> ArrayGet
1902 /// CHECK-DAG: Return [<<Value>>]
1903
1904 /// CHECK-START: int Main.$noinline$testByteArrayDefaultValue() load_store_elimination (after)
1905 /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
1906 /// CHECK-DAG: Return [<<Const0>>]
1907
1908 /// CHECK-START: int Main.$noinline$testByteArrayDefaultValue() load_store_elimination (after)
1909 /// CHECK-NOT: NewArray
1910 /// CHECK-NOT: ArrayGet
1911 /// CHECK-NOT: TypeConversion
1912 private static int $noinline$testByteArrayDefaultValue() {
1913 byte[] array = new byte[2];
1914 array[1] = 1; // FIXME: Without any stores, LSA tells LSE not to run.
1915 return array[0];
1916 }
1917
Mingyao Yang206070c2017-11-29 23:01:58 -08001918 static Object[] sArray;
1919
Aart Bik4dc09e72018-05-11 14:40:31 -07001920 /// CHECK-START: int Main.testLocalArrayMerge1(boolean) load_store_elimination (before)
1921 /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
1922 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
1923 /// CHECK-DAG: <<A:l\d+>> NewArray
1924 /// CHECK-DAG: ArraySet [<<A>>,<<Const0>>,<<Const0>>]
1925 /// CHECK-DAG: ArraySet [<<A>>,<<Const0>>,<<Const1>>]
1926 /// CHECK-DAG: ArraySet [<<A>>,<<Const0>>,<<Const1>>]
1927 /// CHECK-DAG: <<Get:i\d+>> ArrayGet [<<A>>,<<Const0>>]
1928 /// CHECK-DAG: Return [<<Get>>]
1929 //
1930 /// CHECK-START: int Main.testLocalArrayMerge1(boolean) load_store_elimination (after)
1931 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
1932 /// CHECK-DAG: Return [<<Const1>>]
1933 //
1934 /// CHECK-START: int Main.testLocalArrayMerge1(boolean) load_store_elimination (after)
1935 /// CHECK-NOT: NewArray
1936 /// CHECK-NOT: ArraySet
1937 /// CHECK-NOT: ArrayGet
1938 private static int testLocalArrayMerge1(boolean x) {
1939 // The explicit store can be removed right away
1940 // since it is equivalent to the default.
1941 int[] a = { 0 };
1942 // The diamond pattern stores/load can be replaced
1943 // by the direct value.
1944 if (x) {
1945 a[0] = 1;
1946 } else {
1947 a[0] = 1;
1948 }
1949 return a[0];
1950 }
1951
1952 /// CHECK-START: int Main.testLocalArrayMerge2(boolean) load_store_elimination (before)
1953 /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
1954 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
1955 /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2
1956 /// CHECK-DAG: <<Const3:i\d+>> IntConstant 3
1957 /// CHECK-DAG: <<A:l\d+>> NewArray
1958 /// CHECK-DAG: ArraySet [<<A>>,<<Const0>>,<<Const1>>]
1959 /// CHECK-DAG: ArraySet [<<A>>,<<Const0>>,<<Const2>>]
1960 /// CHECK-DAG: ArraySet [<<A>>,<<Const0>>,<<Const3>>]
1961 /// CHECK-DAG: <<Get:i\d+>> ArrayGet [<<A>>,<<Const0>>]
1962 /// CHECK-DAG: Return [<<Get>>]
Vladimir Marko3224f382020-06-23 14:19:53 +01001963
Aart Bik4dc09e72018-05-11 14:40:31 -07001964 /// CHECK-START: int Main.testLocalArrayMerge2(boolean) load_store_elimination (after)
Vladimir Marko3224f382020-06-23 14:19:53 +01001965 /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2
1966 /// CHECK-DAG: <<Const3:i\d+>> IntConstant 3
1967 /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Arg1:i\d+>>,<<Arg2:i\d+>>]
1968 /// CHECK-DAG: Return [<<Phi>>]
1969 /// CHECK-EVAL: set(["<<Arg1>>","<<Arg2>>"]) == set(["<<Const2>>","<<Const3>>"])
1970
Aart Bik4dc09e72018-05-11 14:40:31 -07001971 /// CHECK-START: int Main.testLocalArrayMerge2(boolean) load_store_elimination (after)
Vladimir Marko3224f382020-06-23 14:19:53 +01001972 /// CHECK-NOT: NewArray
Aart Bik4dc09e72018-05-11 14:40:31 -07001973 /// CHECK-NOT: ArraySet
Vladimir Marko3224f382020-06-23 14:19:53 +01001974 /// CHECK-NOT: ArrayGet
Aart Bik4dc09e72018-05-11 14:40:31 -07001975 private static int testLocalArrayMerge2(boolean x) {
1976 // The explicit store can be removed eventually even
1977 // though it is not equivalent to the default.
1978 int[] a = { 1 };
Vladimir Marko3224f382020-06-23 14:19:53 +01001979 // The load after the diamond pattern is eliminated and replaced with a Phi,
1980 // stores are then also eliminated.
Aart Bik4dc09e72018-05-11 14:40:31 -07001981 if (x) {
1982 a[0] = 2;
1983 } else {
1984 a[0] = 3;
1985 }
1986 return a[0];
1987 }
1988
Vladimir Marko3224f382020-06-23 14:19:53 +01001989 /// CHECK-START: int Main.testLocalArrayMerge3(boolean) load_store_elimination (before)
Aart Bik4dc09e72018-05-11 14:40:31 -07001990 /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
1991 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
1992 /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2
1993 /// CHECK-DAG: <<A:l\d+>> NewArray
1994 /// CHECK-DAG: ArraySet [<<A>>,<<Const0>>,<<Const1>>]
1995 /// CHECK-DAG: ArraySet [<<A>>,<<Const0>>,<<Const2>>]
1996 /// CHECK-DAG: <<Get:i\d+>> ArrayGet [<<A>>,<<Const0>>]
1997 /// CHECK-DAG: Return [<<Get>>]
Vladimir Marko3224f382020-06-23 14:19:53 +01001998
1999 /// CHECK-START: int Main.testLocalArrayMerge3(boolean) load_store_elimination (after)
2000 /// CHECK-NOT: NewArray
2001 /// CHECK-NOT: ArraySet
2002 /// CHECK-NOT: ArrayGet
Aart Bik4dc09e72018-05-11 14:40:31 -07002003 private static int testLocalArrayMerge3(boolean x) {
Aart Bik4dc09e72018-05-11 14:40:31 -07002004 int[] a = { 1 };
2005 if (x) {
2006 a[0] = 2;
2007 }
2008 return a[0];
2009 }
2010
2011 /// CHECK-START: int Main.testLocalArrayMerge4(boolean) load_store_elimination (before)
2012 /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
2013 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
2014 /// CHECK-DAG: <<A:l\d+>> NewArray
2015 /// CHECK-DAG: ArraySet [<<A>>,<<Const0>>,<<Const0>>]
2016 /// CHECK-DAG: ArraySet [<<A>>,<<Const0>>,<<Const1>>]
2017 /// CHECK-DAG: ArraySet [<<A>>,<<Const0>>,<<Const1>>]
2018 /// CHECK-DAG: <<Get1:b\d+>> ArrayGet [<<A>>,<<Const0>>]
2019 /// CHECK-DAG: <<Get2:a\d+>> ArrayGet [<<A>>,<<Const0>>]
2020 /// CHECK-DAG: <<Add:i\d+>> Add [<<Get1>>,<<Get2>>]
2021 /// CHECK-DAG: Return [<<Add>>]
2022 //
2023 /// CHECK-START: int Main.testLocalArrayMerge4(boolean) load_store_elimination (after)
2024 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
2025 /// CHECK-DAG: <<Cnv1:b\d+>> TypeConversion [<<Const1>>]
2026 /// CHECK-DAG: <<Cnv2:a\d+>> TypeConversion [<<Const1>>]
2027 /// CHECK-DAG: <<Add:i\d+>> Add [<<Cnv1>>,<<Cnv2>>]
2028 /// CHECK-DAG: Return [<<Add>>]
2029 //
2030 /// CHECK-START: int Main.testLocalArrayMerge4(boolean) load_store_elimination (after)
2031 /// CHECK-NOT: NewArray
2032 /// CHECK-NOT: ArraySet
2033 /// CHECK-NOT: ArrayGet
2034 private static int testLocalArrayMerge4(boolean x) {
2035 byte[] a = { 0 };
2036 if (x) {
2037 a[0] = 1;
2038 } else {
2039 a[0] = 1;
2040 }
2041 // Differently typed (signed vs unsigned),
2042 // but same reference.
2043 return a[0] + (a[0] & 0xff);
2044 }
2045
Vladimir Marko3224f382020-06-23 14:19:53 +01002046 /// CHECK-START: int Main.testLocalArrayMerge5(int[], boolean) load_store_elimination (before)
2047 /// CHECK: ArraySet
2048 /// CHECK: ArraySet
2049 /// CHECK: ArraySet
2050
2051 /// CHECK-START: int Main.testLocalArrayMerge5(int[], boolean) load_store_elimination (after)
2052 /// CHECK-NOT: ArraySet
2053
2054 // Test eliminating store of the same value after eliminating non-observable stores.
2055 private static int testLocalArrayMerge5(int[] a, boolean x) {
2056 int old = a[0];
2057 if (x) {
2058 a[0] = 1;
2059 } else {
2060 a[0] = 1;
2061 }
2062 // This store makes the stores above dead and they will be eliminated.
2063 // That makes this store unnecessary as we're storing the same value already
2064 // present in this location, so it shall also be eliminated.
2065 a[0] = old;
2066 return old;
2067 }
2068
2069 /// CHECK-START: int Main.testLocalArrayMerge6(int[], boolean, boolean) load_store_elimination (before)
2070 /// CHECK-DAG: ArraySet
2071 /// CHECK-DAG: ArraySet
2072 /// CHECK-DAG: ArraySet
2073 /// CHECK-DAG: ArrayGet
2074 /// CHECK-DAG: ArrayGet
2075
2076 /// CHECK-START: int Main.testLocalArrayMerge6(int[], boolean, boolean) load_store_elimination (after)
2077 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
2078 /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2
2079 /// CHECK-DAG: <<Const3:i\d+>> IntConstant 3
2080 /// CHECK-DAG: ArraySet
2081 /// CHECK-DAG: ArraySet
2082 /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Arg1:i\d+>>,<<Arg2:i\d+>>]
2083 /// CHECK-DAG: Return [<<Phi>>]
2084 /// CHECK-DAG: <<Sub:i\d+>> Sub [<<Const3>>,<<Phi>>]
2085 /// CHECK-DAG: Return [<<Sub>>]
2086 /// CHECK-EVAL: set(["<<Arg1>>","<<Arg2>>"]) == set(["<<Const1>>","<<Const2>>"])
2087
2088 /// CHECK-START: int Main.testLocalArrayMerge6(int[], boolean, boolean) load_store_elimination (after)
2089 /// CHECK: Phi
2090 /// CHECK-NOT: Phi
2091
2092 /// CHECK-START: int Main.testLocalArrayMerge6(int[], boolean, boolean) load_store_elimination (after)
2093 /// CHECK-NOT: ArrayGet
2094
2095 // Test that we create a single Phi for eliminating two loads in different blocks.
2096 private static int testLocalArrayMerge6(int[] a, boolean x, boolean y) {
2097 a[0] = 0;
2098 if (x) {
2099 a[0] = 1;
2100 } else {
2101 a[0] = 2;
2102 }
2103 // Phi for load elimination is created here.
2104 if (y) {
2105 return a[0];
2106 } else {
2107 return 3 - a[0];
2108 }
2109 }
2110
2111 /// CHECK-START: int Main.testLocalArrayMerge7(int[], boolean, boolean) load_store_elimination (before)
2112 /// CHECK-DAG: ArraySet
2113 /// CHECK-DAG: ArraySet
2114 /// CHECK-DAG: ArraySet
2115 /// CHECK-DAG: ArrayGet
2116 /// CHECK-DAG: ArraySet
2117 /// CHECK-DAG: ArrayGet
2118
2119 /// CHECK-START: int Main.testLocalArrayMerge7(int[], boolean, boolean) load_store_elimination (after)
2120 /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
2121 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
2122 /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2
2123 /// CHECK-DAG: ArraySet
2124 /// CHECK-DAG: ArraySet
2125 /// CHECK-DAG: ArraySet
2126 /// CHECK-DAG: ArraySet
2127 /// CHECK-DAG: Return [<<Phi2:i\d+>>]
2128 /// CHECK-DAG: <<Phi2>> Phi [<<Arg3:i\d+>>,<<Arg4:i\d+>>]
2129 /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Arg1:i\d+>>,<<Arg2:i\d+>>]
2130 /// CHECK-EVAL: set(["<<Arg1>>","<<Arg2>>"]) == set(["<<Const1>>","<<Const2>>"])
2131 /// CHECK-EVAL: set(["<<Arg3>>","<<Arg4>>"]) == set(["<<Const0>>","<<Phi1>>"])
2132
2133 /// CHECK-START: int Main.testLocalArrayMerge7(int[], boolean, boolean) load_store_elimination (after)
2134 /// CHECK-NOT: ArrayGet
2135
2136 // Test Phi creation for load elimination.
2137 private static int testLocalArrayMerge7(int[] a, boolean x, boolean y) {
2138 a[1] = 0;
2139 if (x) {
2140 if (y) {
2141 a[0] = 1;
2142 } else {
2143 a[0] = 2;
2144 }
2145 a[1] = a[0];
2146 }
2147 return a[1];
2148 }
2149
Vladimir Markocbeedc82020-08-25 14:31:10 +01002150 /// CHECK-START: int Main.testLocalArrayMerge8(boolean) load_store_elimination (before)
2151 /// CHECK-DAG: NewArray
2152 /// CHECK-DAG: ArraySet
2153 /// CHECK-DAG: ArraySet
2154 /// CHECK-DAG: ArraySet
2155 /// CHECK-DAG: ArraySet
2156 /// CHECK-DAG: ArrayGet
2157 /// CHECK-DAG: ArrayGet
2158
2159 /// CHECK-START: int Main.testLocalArrayMerge8(boolean) load_store_elimination (after)
2160 /// CHECK-NOT: NewArray
2161 /// CHECK-NOT: ArraySet
2162 /// CHECK-NOT: ArrayGet
2163
2164 // Test Merging default value and an identical value.
2165 private static int testLocalArrayMerge8(boolean x) {
2166 int[] a = new int[2];
2167 if (x) {
2168 a[0] = 1; // Make sure the store below is not eliminated immediately as
2169 // storing the same value already present in the heap location.
2170 a[0] = 0; // Store the same value as default value to test merging with
2171 // the default value from else-block.
2172 } else {
2173 // Do the same as then-block for a different heap location to avoid
2174 // relying on block ordering. (Test both `default+0` and `0+default`.)
2175 a[1] = 1;
2176 a[1] = 0;
2177 }
2178 return a[0] + a[1];
2179 }
2180
Vladimir Markofab6f1c2020-07-14 16:25:05 +01002181 /// CHECK-START: void Main.$noinline$testThrowingArraySet(java.lang.Object[], java.lang.Object) load_store_elimination (before)
2182 /// CHECK-DAG: ArrayGet
2183 /// CHECK-DAG: ArraySet
2184 /// CHECK-DAG: ArraySet
2185 /// CHECK-DAG: ArraySet
2186 /// CHECK-DAG: ArraySet
2187
2188 /// CHECK-START: void Main.$noinline$testThrowingArraySet(java.lang.Object[], java.lang.Object) load_store_elimination (after)
2189 /// CHECK-DAG: ArrayGet
2190 /// CHECK-DAG: ArraySet
2191 /// CHECK-DAG: ArraySet
2192 /// CHECK-DAG: ArraySet
2193 /// CHECK-DAG: ArraySet
2194 private static void $noinline$testThrowingArraySet(Object[] a, Object o) {
2195 Object olda0 = a[0];
2196 a[0] = null;
2197 a[1] = olda0;
2198 a[0] = o;
2199 a[1] = null;
2200 }
2201
Vladimir Marko3224f382020-06-23 14:19:53 +01002202 /// CHECK-START: int Main.testLoop1(TestClass, int) load_store_elimination (before)
2203 /// CHECK-DAG: InstanceFieldSet
2204 /// CHECK-DAG: InstanceFieldSet
2205 /// CHECK-DAG: InstanceFieldGet
2206 /// CHECK-DAG: Phi
2207
2208 /// CHECK-START: int Main.testLoop1(TestClass, int) load_store_elimination (after)
2209 /// CHECK-DAG: InstanceFieldSet
2210 /// CHECK-DAG: InstanceFieldSet
2211 /// CHECK-DAG: Phi
2212 /// CHECK-DAG: Phi
2213
2214 /// CHECK-START: int Main.testLoop1(TestClass, int) load_store_elimination (after)
2215 /// CHECK-NOT: InstanceFieldGet
2216
2217 // Test Phi creation for load elimination with loop.
2218 private static int testLoop1(TestClass obj, int n) {
2219 obj.i = 0;
2220 for (int i = 0; i < n; ++i) {
2221 obj.i = i;
2222 }
2223 return obj.i;
2224 }
2225
2226 /// CHECK-START: int Main.testLoop2(TestClass, int) load_store_elimination (before)
2227 /// CHECK-DAG: InstanceFieldSet
2228 /// CHECK-DAG: InstanceFieldSet
2229 /// CHECK-DAG: InstanceFieldGet
2230 /// CHECK-DAG: Phi
2231
2232 /// CHECK-START: int Main.testLoop2(TestClass, int) load_store_elimination (after)
2233 /// CHECK-DAG: InstanceFieldSet
2234 /// CHECK-DAG: InstanceFieldSet
2235
2236 /// CHECK-START: int Main.testLoop2(TestClass, int) load_store_elimination (after)
2237 /// CHECK-NOT: InstanceFieldGet
2238
2239 /// CHECK-START: int Main.testLoop2(TestClass, int) load_store_elimination (after)
2240 /// CHECK: Phi
2241 /// CHECK-NOT: Phi
2242
2243 // Test that we do not create any Phis for load elimination when
2244 // the heap value was not modified in the loop.
2245 private static int testLoop2(TestClass obj, int n) {
2246 obj.i = 1;
2247 for (int i = 0; i < n; ++i) {
2248 obj.j = i;
2249 }
2250 return obj.i;
2251 }
2252
2253 /// CHECK-START: int Main.testLoop3(TestClass, int) load_store_elimination (before)
2254 /// CHECK-DAG: InstanceFieldSet
2255 /// CHECK-DAG: InstanceFieldSet
2256 /// CHECK-DAG: InstanceFieldGet
2257
2258 /// CHECK-START: int Main.testLoop3(TestClass, int) load_store_elimination (after)
2259 /// CHECK: InstanceFieldSet
2260 /// CHECK-NOT: InstanceFieldSet
2261
2262 /// CHECK-START: int Main.testLoop3(TestClass, int) load_store_elimination (after)
2263 /// CHECK-NOT: InstanceFieldGet
2264
2265 // Test elimination of a store in the loop that stores the same value that was already
2266 // stored before the loop and eliminating the load of that value after the loop.
2267 private static int testLoop3(TestClass obj, int n) {
2268 obj.i = 1;
2269 for (int i = 0; i < n; ++i) {
2270 obj.i = 1;
2271 }
2272 return obj.i;
2273 }
2274
2275 /// CHECK-START: int Main.testLoop4(TestClass, int) load_store_elimination (before)
2276 /// CHECK-DAG: InstanceFieldSet
2277 /// CHECK-DAG: InstanceFieldSet
2278
2279 /// CHECK-START: int Main.testLoop4(TestClass, int) load_store_elimination (after)
2280 /// CHECK: InstanceFieldSet
2281 /// CHECK-NOT: InstanceFieldSet
2282
2283 /// CHECK-START: int Main.testLoop4(TestClass, int) load_store_elimination (after)
2284 /// CHECK-NOT: InstanceFieldGet
2285
2286 // Test store elimination in the loop that stores the same value that was already
2287 // stored before the loop, without any loads of that value.
2288 private static int testLoop4(TestClass obj, int n) {
2289 obj.i = 1;
2290 for (int i = 0; i < n; ++i) {
2291 obj.i = 1;
2292 }
2293 return n;
2294 }
2295
2296 /// CHECK-START: int Main.testLoop5(TestClass, int) load_store_elimination (before)
2297 /// CHECK-DAG: InstanceFieldSet
2298 /// CHECK-DAG: InstanceFieldSet
2299 /// CHECK-DAG: InstanceFieldGet
2300 /// CHECK-DAG: InstanceFieldGet
2301 /// CHECK-DAG: InstanceFieldSet
2302 /// CHECK-DAG: InstanceFieldSet
2303 /// CHECK-DAG: InstanceFieldGet
2304
2305 /// CHECK-START: int Main.testLoop5(TestClass, int) load_store_elimination (after)
2306 /// CHECK: InstanceFieldSet
2307 /// CHECK: InstanceFieldSet
2308 /// CHECK-NOT: InstanceFieldSet
2309
2310 /// CHECK-START: int Main.testLoop5(TestClass, int) load_store_elimination (after)
2311 /// CHECK-NOT: InstanceFieldGet
2312
2313 // Test eliminating loads and stores that just shuffle the same value between
2314 // different heap locations.
2315 private static int testLoop5(TestClass obj, int n) {
2316 // Initialize both `obj.i` and `obj.j` to the same value and then swap these values
2317 // in the loop. We should be able to determine that the values are always the same.
2318 obj.i = n;
2319 obj.j = n;
2320 for (int i = 0; i < n; ++i) {
2321 if ((i & 1) != 0) {
2322 int tmp = obj.i;
2323 obj.i = obj.j;
2324 obj.j = tmp;
2325 }
2326 }
2327 return obj.i;
2328 }
2329
2330 /// CHECK-START: int Main.testLoop6(TestClass, int) load_store_elimination (before)
2331 /// CHECK-DAG: InstanceFieldSet
2332 /// CHECK-DAG: InstanceFieldSet
2333 /// CHECK-DAG: InstanceFieldGet
2334 /// CHECK-DAG: InstanceFieldGet
2335 /// CHECK-DAG: InstanceFieldSet
2336 /// CHECK-DAG: InstanceFieldSet
2337 /// CHECK-DAG: InstanceFieldSet
2338 /// CHECK-DAG: InstanceFieldGet
2339
2340 /// CHECK-START: int Main.testLoop6(TestClass, int) load_store_elimination (after)
2341 /// CHECK: InstanceFieldSet
2342 /// CHECK: InstanceFieldSet
2343 /// CHECK-NOT: InstanceFieldSet
2344
2345 /// CHECK-START: int Main.testLoop6(TestClass, int) load_store_elimination (after)
2346 /// CHECK-NOT: InstanceFieldGet
2347
2348 // Test eliminating loads and stores that just shuffle the same value between
2349 // different heap locations, or store the same value.
2350 private static int testLoop6(TestClass obj, int n) {
2351 // Initialize both `obj.i` and `obj.j` to the same value and then swap these values
2352 // in the loop or set `obj.i` to the same value. We should be able to determine
2353 // that the values are always the same.
2354 obj.i = n;
2355 obj.j = n;
2356 for (int i = 0; i < n; ++i) {
2357 if ((i & 1) != 0) {
2358 int tmp = obj.i;
2359 obj.i = obj.j;
2360 obj.j = tmp;
2361 } else {
2362 obj.i = n;
2363 }
2364 }
2365 return obj.i;
2366 }
2367
2368 /// CHECK-START: int Main.testLoop7(int) load_store_elimination (before)
2369 /// CHECK-DAG: NewInstance
2370 /// CHECK-DAG: InstanceFieldGet
2371 /// CHECK-DAG: InstanceFieldGet
2372 /// CHECK-DAG: InstanceFieldSet
2373 /// CHECK-DAG: InstanceFieldSet
2374 /// CHECK-DAG: InstanceFieldSet
2375 /// CHECK-DAG: InstanceFieldGet
2376
2377 /// CHECK-START: int Main.testLoop7(int) load_store_elimination (after)
2378 /// CHECK-NOT: NewInstance
2379 /// CHECK-NOT: InstanceFieldSet
2380 /// CHECK-NOT: InstanceFieldGet
2381
2382 // Test eliminating loads and stores that just shuffle the default value between
2383 // different heap locations, or store the same value.
2384 private static int testLoop7(int n) {
2385 // Leave both `obj.i` and `obj.j` initialized to the default value and then
2386 // swap these values in the loop or set some to the identical value 0.
2387 // We should be able to determine that the values are always the same.
2388 TestClass obj = new TestClass();
2389 for (int i = 0; i < n; ++i) {
2390 if ((i & 1) != 0) {
2391 int tmp = obj.i;
2392 obj.i = obj.j;
2393 obj.j = tmp;
2394 } else {
2395 obj.i = 0;
2396 }
2397 }
2398 return obj.i;
2399 }
2400
2401 /// CHECK-START: int Main.testLoop8(int) load_store_elimination (before)
2402 /// CHECK-DAG: NewInstance
2403 /// CHECK-DAG: InstanceFieldGet
2404 /// CHECK-DAG: InstanceFieldGet
2405 /// CHECK-DAG: InstanceFieldSet
2406 /// CHECK-DAG: InstanceFieldSet
2407 /// CHECK-DAG: InstanceFieldSet
2408 /// CHECK-DAG: InstanceFieldSet
2409 /// CHECK-DAG: InstanceFieldGet
2410
2411 /// CHECK-START: int Main.testLoop8(int) load_store_elimination (after)
2412 /// CHECK-NOT: NewInstance
2413 /// CHECK-NOT: InstanceFieldSet
2414 /// CHECK-NOT: InstanceFieldGet
2415
2416 /// CHECK-START: int Main.testLoop8(int) load_store_elimination (after)
2417 /// CHECK: Phi
2418 /// CHECK: Phi
2419 /// CHECK-NOT: Phi
2420
2421 // Test eliminating loads and stores that just shuffle the same value between
2422 // different heap locations, or store the same value. The value is loaded
2423 // after conditionally setting a different value after the loop to test that
2424 // this does not cause creation of excessive Phis.
2425 private static int testLoop8(int n) {
2426 // Leave both `obj.i` and `obj.j` initialized to the default value and then
2427 // swap these values in the loop or set some to the identical value 0.
2428 // We should be able to determine that the values are always the same.
2429 TestClass obj = new TestClass();
2430 for (int i = 0; i < n; ++i) {
2431 if ((i & 1) != 0) {
2432 int tmp = obj.i;
2433 obj.i = obj.j;
2434 obj.j = tmp;
2435 } else {
2436 obj.i = 0;
2437 }
2438 }
2439 // Up to this point, `obj.i` is always 0 but the Phi placeholder below
2440 // must not be included in that determination despite using lazy search
2441 // for Phi placeholders triggered by the `obj.i` load below.
2442 if ((n & 1) == 0) {
2443 obj.i = 1;
2444 }
2445 return obj.i;
2446 }
2447
2448 /// CHECK-START: int Main.testLoop9(TestClass, int) load_store_elimination (before)
2449 /// CHECK-DAG: NewInstance
2450 /// CHECK-DAG: InstanceFieldSet
2451 /// CHECK-DAG: InstanceFieldSet
2452 /// CHECK-DAG: Phi
2453 /// CHECK-DAG: InstanceFieldGet
2454 /// CHECK-DAG: InstanceFieldGet
2455 /// CHECK-DAG: InstanceFieldSet
2456 /// CHECK-DAG: InstanceFieldSet
2457 /// CHECK-DAG: InvokeStaticOrDirect
2458 /// CHECK-DAG: InstanceFieldGet
2459
2460 /// CHECK-START: int Main.testLoop9(TestClass, int) load_store_elimination (after)
2461 /// CHECK-DAG: InstanceFieldSet
2462 /// CHECK-DAG: Phi
2463 /// CHECK-DAG: Phi
2464 /// CHECK-DAG: InstanceFieldGet
2465 /// CHECK-DAG: InstanceFieldSet
2466 /// CHECK-DAG: Phi
2467
2468 /// CHECK-START: int Main.testLoop9(TestClass, int) load_store_elimination (after)
2469 /// CHECK: InstanceFieldSet
2470 /// CHECK: InstanceFieldSet
2471 /// CHECK-NOT: InstanceFieldSet
2472
2473 /// CHECK-START: int Main.testLoop9(TestClass, int) load_store_elimination (after)
2474 /// CHECK-NOT: NewInstance
2475
2476 /// CHECK-START: int Main.testLoop9(TestClass, int) load_store_elimination (after)
2477 /// CHECK: InstanceFieldGet
2478 /// CHECK-NOT: InstanceFieldGet
2479
2480 /// CHECK-START: int Main.testLoop9(TestClass, int) load_store_elimination (after)
2481 /// CHECK: Phi
2482 /// CHECK: Phi
2483 /// CHECK: Phi
2484 /// CHECK-NOT: Phi
2485
2486 // Test that unknown value flowing through a loop back-edge prevents
2487 // elimination of a load but that load can be used as an input to a Phi
2488 // created to eliminate another load.
2489 private static int testLoop9(TestClass obj, int n) {
2490 TestClass obj0 = new TestClass();
2491 // Initialize both `obj.i` and `obj0.i` to the same value and then swap these values
2492 // in the loop or clobber `obj.i`. We should determine that the `obj.i` load in the
2493 // loop must be kept but the `obj0.i` load can be replaced by a Phi chain.
2494 obj0.i = n;
2495 obj.i = n;
2496 for (int i = 0; i < n; ++i) {
2497 if ((i & 1) != 0) {
2498 int tmp = obj0.i;
2499 obj0.i = obj.i; // Load cannot be eliminated.
2500 obj.i = tmp;
2501 } else {
2502 $noinline$clobberObservables(); // Makes obj.i unknown.
2503 }
2504 }
2505 return obj0.i;
2506 }
2507
2508 /// CHECK-START: int Main.testLoop10(TestClass, int) load_store_elimination (before)
2509 /// CHECK-DAG: InstanceFieldSet
2510 /// CHECK-DAG: InstanceFieldGet
2511 /// CHECK-DAG: InstanceFieldSet
2512 /// CHECK-DAG: InstanceFieldGet
2513
2514 /// CHECK-START: int Main.testLoop10(TestClass, int) load_store_elimination (after)
2515 /// CHECK-DAG: InstanceFieldSet
2516 /// CHECK-DAG: InstanceFieldGet
2517 /// CHECK-DAG: InstanceFieldSet
2518
2519 /// CHECK-START: int Main.testLoop10(TestClass, int) load_store_elimination (after)
2520 /// CHECK: InstanceFieldGet
2521 /// CHECK-NOT: InstanceFieldGet
2522
2523 // Test load elimination after finding a non-eliminated load depending
2524 // on loop Phi placeholder.
2525 private static int testLoop10(TestClass obj, int n) {
2526 obj.i = 1;
2527 for (int i = 0; i < n; ++i) {
2528 $noinline$clobberObservables();
2529 }
2530 int i1 = obj.i;
2531 obj.j = 2; // Use write side effects to stop GVN from eliminating the load below.
2532 int i2 = obj.i;
2533 return i1 + i2;
2534 }
2535
2536 /// CHECK-START: int Main.testLoop11(TestClass, int) load_store_elimination (before)
2537 /// CHECK-DAG: InstanceFieldSet
2538 /// CHECK-DAG: Phi
2539 /// CHECK-DAG: InstanceFieldSet
2540 /// CHECK-DAG: InstanceFieldSet
2541 /// CHECK-DAG: InstanceFieldGet
2542
2543 /// CHECK-START: int Main.testLoop11(TestClass, int) load_store_elimination (after)
2544 /// CHECK-DAG: InstanceFieldSet
2545 /// CHECK-DAG: Phi
2546 /// CHECK-DAG: Phi
2547 /// CHECK-DAG: InstanceFieldSet
2548 /// CHECK-DAG: InstanceFieldSet
2549 /// CHECK-DAG: Phi
2550
2551 /// CHECK-START: int Main.testLoop11(TestClass, int) load_store_elimination (after)
2552 /// CHECK: Phi
2553 /// CHECK: Phi
2554 /// CHECK: Phi
2555 /// CHECK-NOT: Phi
2556
2557 /// CHECK-START: int Main.testLoop11(TestClass, int) load_store_elimination (after)
2558 /// CHECK-NOT: InstanceFieldGet
2559
2560 // Test load elimination creating two Phis that depend on each other.
2561 private static int testLoop11(TestClass obj, int n) {
2562 obj.i = 1;
2563 for (int i = 0; i < n; ++i) {
2564 if ((i & 1) != 0) {
2565 obj.i = 2;
2566 } else {
2567 obj.i = 3;
2568 }
2569 // There shall be a Phi created here for `obj.i` before the "++i".
2570 // This Phi and the loop Phi that shall be created for `obj.i` depend on each other.
2571 }
2572 return obj.i;
2573 }
2574
2575 /// CHECK-START: int Main.testLoop12(TestClass, int) load_store_elimination (before)
2576 /// CHECK-DAG: InstanceFieldSet
2577 /// CHECK-DAG: Phi
2578 /// CHECK-DAG: InstanceFieldSet
2579 /// CHECK-DAG: InstanceFieldSet
2580 /// CHECK-DAG: InstanceFieldGet
2581
2582 /// CHECK-START: int Main.testLoop12(TestClass, int) load_store_elimination (after)
2583 /// CHECK-DAG: InstanceFieldSet
2584 /// CHECK-DAG: Phi
2585 /// CHECK-DAG: Phi
2586 /// CHECK-DAG: InstanceFieldSet
2587 /// CHECK-DAG: InstanceFieldSet
2588
2589 /// CHECK-START: int Main.testLoop12(TestClass, int) load_store_elimination (after)
2590 /// CHECK: Phi
2591 /// CHECK: Phi
2592 /// CHECK-NOT: Phi
2593
2594 /// CHECK-START: int Main.testLoop12(TestClass, int) load_store_elimination (after)
2595 /// CHECK-NOT: InstanceFieldGet
2596
2597 // Test load elimination creating a single Phi with more than 2 inputs.
2598 private static int testLoop12(TestClass obj, int n) {
2599 obj.i = 1;
2600 for (int i = 0; i < n; ) {
2601 // Do the loop variable increment first, so that there are back-edges
2602 // directly from the "then" and "else" blocks below.
2603 ++i;
2604 if ((i & 1) != 0) {
2605 obj.i = 2;
2606 } else {
2607 obj.i = 3;
2608 }
2609 }
2610 return obj.i;
2611 }
2612
2613 /// CHECK-START: int Main.testLoop13(TestClass, int) load_store_elimination (before)
2614 /// CHECK-DAG: NewArray
2615 /// CHECK-DAG: Phi
2616 /// CHECK-DAG: ArrayGet
2617 /// CHECK-DAG: ArraySet
2618 /// CHECK-DAG: ArrayGet
2619 /// CHECK-DAG: ArraySet
2620 /// CHECK-DAG: InstanceFieldGet
2621 /// CHECK-DAG: ArraySet
2622 /// CHECK-DAG: ArrayGet
2623
2624 /// CHECK-START: int Main.testLoop13(TestClass, int) load_store_elimination (after)
2625 /// CHECK-DAG: Phi
2626 /// CHECK-DAG: Phi
2627 /// CHECK-DAG: Phi
2628 /// CHECK-DAG: Phi
2629 /// CHECK-DAG: InstanceFieldGet
2630
2631 /// CHECK-START: int Main.testLoop13(TestClass, int) load_store_elimination (after)
2632 /// CHECK-NOT: NewArray
2633 /// CHECK-NOT: ArrayGet
2634 /// CHECK-NOT: ArraySet
2635
2636 /// CHECK-START: int Main.testLoop13(TestClass, int) load_store_elimination (after)
2637 /// CHECK: Phi
2638 /// CHECK: Phi
2639 /// CHECK: Phi
2640 /// CHECK: Phi
2641 /// CHECK-NOT: Phi
2642
2643 // Test eliminating array allocation, loads and stores and creating loop Phis.
2644 private static int testLoop13(TestClass obj, int n) {
2645 int[] a = new int[3];
2646 for (int i = 0; i < n; ++i) {
2647 a[0] = a[1];
2648 a[1] = a[2];
2649 a[2] = obj.i;
2650 }
2651 return a[0];
2652 }
2653
2654 /// CHECK-START: int Main.testLoop14(TestClass2, int) load_store_elimination (before)
2655 /// CHECK-DAG: NewArray
2656 /// CHECK-DAG: InstanceFieldSet field_name:TestClass2.i
2657 /// CHECK-DAG: Phi
2658 /// CHECK-DAG: ArrayGet
2659 /// CHECK-DAG: ArraySet
2660 /// CHECK-DAG: ArrayGet
2661 /// CHECK-DAG: ArraySet
2662 /// CHECK-DAG: InstanceFieldGet field_name:TestClass2.i
2663 /// CHECK-DAG: InstanceFieldSet field_name:TestClass2.j
2664 /// CHECK-DAG: InstanceFieldGet field_name:TestClass2.i
2665 /// CHECK-DAG: ArraySet
2666 /// CHECK-DAG: InstanceFieldSet field_name:TestClass2.k
2667 /// CHECK-DAG: InstanceFieldSet field_name:TestClass2.j
2668 /// CHECK-DAG: InstanceFieldGet field_name:TestClass2.i
2669 /// CHECK-DAG: InstanceFieldSet field_name:TestClass2.k
2670 /// CHECK-DAG: ArrayGet
2671
2672 /// CHECK-START: int Main.testLoop14(TestClass2, int) load_store_elimination (after)
2673 /// CHECK-DAG: InstanceFieldSet field_name:TestClass2.i
2674 /// CHECK-DAG: Phi
2675 /// CHECK-DAG: Phi
2676 /// CHECK-DAG: Phi
2677 /// CHECK-DAG: Phi
2678 /// CHECK-DAG: InstanceFieldGet field_name:TestClass2.i
2679 /// CHECK-DAG: InstanceFieldSet field_name:TestClass2.j
2680 /// CHECK-DAG: InstanceFieldSet field_name:TestClass2.k
2681 /// CHECK-DAG: InstanceFieldSet field_name:TestClass2.j
2682 /// CHECK-DAG: InstanceFieldSet field_name:TestClass2.k
2683
2684 /// CHECK-START: int Main.testLoop14(TestClass2, int) load_store_elimination (after)
2685 /// CHECK-NOT: NewArray
2686
2687 /// CHECK-START: int Main.testLoop14(TestClass2, int) load_store_elimination (after)
2688 /// CHECK: InstanceFieldGet field_name:TestClass2.i
2689 /// CHECK-NOT: InstanceFieldGet field_name:TestClass2.i
2690
2691 /// CHECK-START: int Main.testLoop14(TestClass2, int) load_store_elimination (after)
2692 /// CHECK: Phi
2693 /// CHECK: Phi
2694 /// CHECK: Phi
2695 /// CHECK: Phi
2696 /// CHECK-NOT: Phi
2697
2698 // Test load elimination in a loop after determing that the first field load
2699 // (depending on loop Phi placeholder) cannot be eliminated.
2700 private static int testLoop14(TestClass2 obj, int n) {
2701 int[] a = new int[3];
2702 obj.i = 1;
2703 for (int i = 0; i < n; ++i) {
2704 a[0] = a[1];
2705 a[1] = a[2];
2706 int i1 = obj.i;
2707 obj.j = 2; // Use write side effects to stop GVN from eliminating the load below.
2708 int i2 = obj.i;
2709 a[2] = i1;
2710 if ((i & 2) != 0) {
2711 obj.k = i2;
2712 } else {
2713 obj.j = 3; // Use write side effects to stop GVN from eliminating the load below.
2714 obj.k = obj.i;
2715 $noinline$clobberObservables(); // Make obj.i unknown.
2716 }
2717 }
2718 return a[0];
2719 }
2720
2721 /// CHECK-START: int Main.testLoop15(int) load_store_elimination (before)
2722 /// CHECK-DAG: NewArray
Artem Serov2558abe2020-10-14 18:01:37 +01002723 /// CHECK-IF: hasIsaFeature("sve")
2724 //
2725 /// CHECK-DAG: VecPredWhile
2726 /// CHECK-DAG: VecStore
2727 //
2728 /// CHECK-ELSE:
2729 //
2730 /// CHECK-DAG: ArraySet
2731 //
2732 /// CHECK-FI:
2733 //
Vladimir Marko3224f382020-06-23 14:19:53 +01002734 /// CHECK-DAG: ArrayGet
2735
2736 /// CHECK-START: int Main.testLoop15(int) load_store_elimination (after)
2737 /// CHECK-DAG: NewArray
Artem Serov2558abe2020-10-14 18:01:37 +01002738 /// CHECK-IF: hasIsaFeature("sve")
2739 //
2740 /// CHECK-DAG: VecPredWhile
2741 /// CHECK-DAG: VecStore
2742 //
2743 /// CHECK-ELSE:
2744 //
2745 /// CHECK-DAG: ArraySet
2746 //
2747 /// CHECK-FI:
2748 //
Vladimir Marko3224f382020-06-23 14:19:53 +01002749 /// CHECK-DAG: ArrayGet
Vladimir Marko3224f382020-06-23 14:19:53 +01002750 // Test that aliasing array store in the loop is not eliminated
2751 // when a loop Phi placeholder is marked for keeping.
2752 private static int testLoop15(int n) {
2753 int[] a = new int[n + 1];
2754 for (int i = 0; i < n; ++i) {
2755 a[i] = 1; // Cannot be eliminated due to aliasing.
2756 }
2757 return a[0];
2758 }
2759
2760 /// CHECK-START: int Main.testLoop16(TestClass, int) load_store_elimination (before)
2761 /// CHECK-DAG: InstanceFieldSet
2762 /// CHECK-DAG: Phi
2763 /// CHECK-DAG: InstanceFieldSet
2764 /// CHECK-DAG: InstanceFieldGet
2765
2766 /// CHECK-START: int Main.testLoop16(TestClass, int) load_store_elimination (after)
2767 /// CHECK-DAG: InstanceFieldSet
2768 /// CHECK-DAG: Phi
2769 /// CHECK-DAG: InstanceFieldSet
2770
2771 /// CHECK-START: int Main.testLoop16(TestClass, int) load_store_elimination (after)
2772 /// CHECK-NOT: InstanceFieldGet
2773
2774 /// CHECK-START: int Main.testLoop16(TestClass, int) load_store_elimination (after)
2775 /// CHECK: Phi
2776 /// CHECK-NOT: Phi
2777
2778 // Test that we match an existing loop Phi for eliminating a load.
2779 static int testLoop16(TestClass obj, int n) {
2780 obj.i = 0;
2781 for (int i = 0; i < n; ) {
2782 ++i;
2783 obj.i = i;
2784 }
2785 // The load is replaced by the existing Phi instead of constructing a new one.
2786 return obj.i;
2787 }
2788
2789 /// CHECK-START: int Main.testLoop17(TestClass, int) load_store_elimination (before)
2790 /// CHECK-DAG: InstanceFieldSet
2791 /// CHECK-DAG: Phi
2792 /// CHECK-DAG: InstanceFieldSet
2793 /// CHECK-DAG: InstanceFieldSet
2794 /// CHECK-DAG: Phi
2795 /// CHECK-DAG: InstanceFieldGet
2796
2797 /// CHECK-START: int Main.testLoop17(TestClass, int) load_store_elimination (after)
2798 /// CHECK-DAG: InstanceFieldSet
2799 /// CHECK-DAG: Phi
2800 /// CHECK-DAG: InstanceFieldSet
2801 /// CHECK-DAG: InstanceFieldSet
2802 /// CHECK-DAG: Phi
2803
2804 /// CHECK-START: int Main.testLoop17(TestClass, int) load_store_elimination (after)
2805 /// CHECK-NOT: InstanceFieldGet
2806
2807 /// CHECK-START: int Main.testLoop17(TestClass, int) load_store_elimination (after)
2808 /// CHECK: Phi
2809 /// CHECK: Phi
2810 /// CHECK-NOT: Phi
2811
2812 // Test that we match an existing non-loop Phi for eliminating a load,
2813 // one input of the Phi being invariant across a preceding loop.
2814 static int testLoop17(TestClass obj, int n) {
2815 obj.i = 1;
2816 int phi = 1;
2817 for (int i = 0; i < n; ++i) {
2818 obj.j = 2; // Unrelated.
2819 }
2820 if ((n & 1) != 0) {
2821 obj.i = 2;
2822 phi = 2;
2823 }
2824 // The load is replaced by the existing Phi instead of constructing a new one.
2825 return obj.i + phi;
2826 }
2827
2828 /// CHECK-START: int Main.testLoop18(TestClass, int) load_store_elimination (before)
2829 /// CHECK-DAG: NewArray
2830 /// CHECK-DAG: Phi
2831 /// CHECK-DAG: ArrayGet
2832 /// CHECK-DAG: InstanceFieldSet
2833
2834 /// CHECK-START: int Main.testLoop18(TestClass, int) load_store_elimination (after)
2835 /// CHECK-DAG: NewArray
2836 /// CHECK-DAG: Phi
2837 /// CHECK-DAG: InstanceFieldSet
2838
2839 /// CHECK-START: int Main.testLoop18(TestClass, int) load_store_elimination (after)
2840 /// CHECK-NOT: ArrayGet
2841
2842 // Test eliminating a load of the default value in a loop
2843 // with the array index being defined inside the loop.
2844 static int testLoop18(TestClass obj, int n) {
2845 // The NewArray is kept as it may throw for negative n.
2846 // TODO: Eliminate constructor fence even though the NewArray is kept.
2847 int[] a0 = new int[n];
2848 for (int i = 0; i < n; ++i) {
2849 obj.i = a0[i];
2850 }
2851 return n;
2852 }
2853
2854 /// CHECK-START: int Main.testLoop19(TestClass, int) load_store_elimination (before)
2855 /// CHECK-DAG: NewArray
2856 /// CHECK-DAG: Phi
2857 /// CHECK-DAG: ArrayGet
2858 /// CHECK-DAG: InstanceFieldSet
2859 /// CHECK-DAG: ArraySet
2860
2861 /// CHECK-START: int Main.testLoop19(TestClass, int) load_store_elimination (after)
2862 /// CHECK-DAG: NewArray
2863 /// CHECK-DAG: Phi
2864 /// CHECK-DAG: InstanceFieldSet
2865
2866 /// CHECK-START: int Main.testLoop19(TestClass, int) load_store_elimination (after)
2867 /// CHECK-NOT: ArrayGet
2868 /// CHECK-NOT: ArraySet
2869
2870 // Test eliminating a load of the default value and store of an identical value
2871 // in a loop with the array index being defined inside the loop.
2872 static int testLoop19(TestClass obj, int n) {
2873 // The NewArray is kept as it may throw for negative n.
2874 // TODO: Eliminate constructor fence even though the NewArray is kept.
2875 int[] a0 = new int[n];
2876 for (int i = 0; i < n; ++i) {
2877 obj.i = a0[i];
2878 a0[i] = 0; // Store the same value as default.
2879 }
2880 return n;
2881 }
2882
2883 /// CHECK-START: int Main.testLoop20(TestClass, int) load_store_elimination (before)
2884 /// CHECK-DAG: NewArray
2885 /// CHECK-DAG: Phi
2886 /// CHECK-DAG: ArrayGet
2887 /// CHECK-DAG: InstanceFieldSet
2888 /// CHECK-DAG: ArraySet
2889
2890 /// CHECK-START: int Main.testLoop20(TestClass, int) load_store_elimination (after)
2891 /// CHECK-DAG: NewArray
2892 /// CHECK-DAG: Phi
2893 /// CHECK-DAG: InstanceFieldSet
2894
2895 /// CHECK-START: int Main.testLoop20(TestClass, int) load_store_elimination (after)
2896 /// CHECK-NOT: ArrayGet
2897 /// CHECK-NOT: ArraySet
2898
2899 // Test eliminating a load of the default value and a conditional store of an
2900 // identical value in a loop with the array index being defined inside the loop.
2901 static int testLoop20(TestClass obj, int n) {
2902 // The NewArray is kept as it may throw for negative n.
2903 // TODO: Eliminate constructor fence even though the NewArray is kept.
2904 int[] a0 = new int[n];
2905 for (int i = 0; i < n; ++i) {
2906 obj.i = a0[i];
2907 if ((i & 1) != 0) {
2908 a0[i] = 0; // Store the same value as default.
2909 }
2910 }
2911 return n;
2912 }
2913
2914 /// CHECK-START: int Main.testLoop21(TestClass, int) load_store_elimination (before)
2915 /// CHECK-DAG: InstanceFieldSet
2916 /// CHECK-DAG: InstanceFieldGet
2917 /// CHECK-DAG: InstanceFieldSet
2918 /// CHECK-DAG: InstanceFieldGet
2919 /// CHECK-DAG: InstanceFieldSet
2920 /// CHECK-DAG: InstanceFieldGet
2921 /// CHECK-DAG: InstanceFieldSet
2922
2923 /// CHECK-START: int Main.testLoop21(TestClass, int) load_store_elimination (before)
2924 /// CHECK-NOT: Phi
2925
2926 /// CHECK-START: int Main.testLoop21(TestClass, int) load_store_elimination (after)
2927 /// CHECK-NOT: InstanceFieldGet
2928
2929 /// CHECK-START: int Main.testLoop21(TestClass, int) load_store_elimination (after)
2930 /// CHECK: InstanceFieldSet
2931 /// CHECK: InstanceFieldSet
2932 /// CHECK: InstanceFieldSet
2933 /// CHECK-NOT: InstanceFieldSet
2934
2935 /// CHECK-START: int Main.testLoop21(TestClass, int) load_store_elimination (after)
2936 /// CHECK: Phi
2937 /// CHECK-NOT: Phi
2938
2939 // Test load elimination when an instance field is used as the loop variable.
2940 static int testLoop21(TestClass obj, int n) {
2941 for (obj.i = 0; obj.i < n; ++obj.i) {
2942 obj.j = 0; // Use write side effects to stop GVN from eliminating the load below.
2943 obj.j = obj.i;
2944 }
2945 return n;
2946 }
2947
2948 /// CHECK-START: int Main.testLoop22(TestClass, int) load_store_elimination (before)
2949 /// CHECK-DAG: InstanceFieldSet
2950 /// CHECK-DAG: InstanceFieldGet
2951 /// CHECK-DAG: InstanceFieldSet
2952 /// CHECK-DAG: InstanceFieldGet
2953 /// CHECK-DAG: InstanceFieldSet
2954 /// CHECK-DAG: InstanceFieldGet
2955 /// CHECK-DAG: InstanceFieldSet
2956 /// CHECK-DAG: InstanceFieldSet
2957
2958 /// CHECK-START: int Main.testLoop22(TestClass, int) load_store_elimination (before)
2959 /// CHECK-NOT: Phi
2960
2961 /// CHECK-START: int Main.testLoop22(TestClass, int) load_store_elimination (after)
2962 /// CHECK-NOT: InstanceFieldGet
2963
2964 /// CHECK-START: int Main.testLoop22(TestClass, int) load_store_elimination (after)
2965 /// CHECK: InstanceFieldSet
2966 /// CHECK: InstanceFieldSet
2967 /// CHECK-NOT: InstanceFieldSet
2968
2969 /// CHECK-START: int Main.testLoop22(TestClass, int) load_store_elimination (after)
2970 /// CHECK: Phi
2971 /// CHECK-NOT: Phi
2972
2973 // Test load and store elimination when an instance field is used as the loop
2974 // variable and then overwritten after the loop.
2975 static int testLoop22(TestClass obj, int n) {
2976 for (obj.i = 0; obj.i < n; ++obj.i) {
2977 obj.j = 0; // Use write side effects to stop GVN from eliminating the load below.
2978 obj.j = obj.i;
2979 }
2980 obj.i = 0;
2981 return n;
2982 }
2983
2984 /// CHECK-START: int Main.testLoop23(TestClass, int) load_store_elimination (before)
2985 /// CHECK-DAG: InstanceFieldSet
2986 /// CHECK-DAG: Phi
2987 /// CHECK-DAG: Phi
2988 /// CHECK-DAG: InstanceFieldSet
2989 /// CHECK-DAG: InstanceFieldSet
2990 /// CHECK-DAG: Phi
2991 /// CHECK-DAG: InstanceFieldSet
2992
2993 /// CHECK-START: int Main.testLoop23(TestClass, int) load_store_elimination (after)
2994 /// CHECK-DAG: Phi
2995 /// CHECK-DAG: Phi
2996 /// CHECK-DAG: Phi
2997 /// CHECK-DAG: InstanceFieldSet
2998
2999 /// CHECK-START: int Main.testLoop23(TestClass, int) load_store_elimination (after)
3000 /// CHECK: InstanceFieldSet
3001 /// CHECK-NOT: InstanceFieldSet
3002
3003 // Test elimination of non-observable stores.
3004 static int testLoop23(TestClass obj, int n) {
3005 obj.i = -1;
3006 int phi = -1;
3007 for (int i = 0; i < n; ++i) {
3008 obj.i = i;
3009 phi = i;
3010 }
3011 if ((n & 1) != 0) {
3012 obj.i = 2;
3013 phi = 2;
3014 }
3015 obj.i = phi; // This store shall be kept, the stores above shall be eliminated.
3016 return phi;
3017 }
3018
3019 /// CHECK-START: int Main.testLoop24(TestClass, int) load_store_elimination (before)
3020 /// CHECK-DAG: InstanceFieldSet
3021 /// CHECK-DAG: Phi
3022 /// CHECK-DAG: Phi
3023 /// CHECK-DAG: InstanceFieldSet
3024 /// CHECK-DAG: InstanceFieldSet
3025 /// CHECK-DAG: Phi
3026 /// CHECK-DAG: InstanceFieldSet
3027
3028 /// CHECK-START: int Main.testLoop24(TestClass, int) load_store_elimination (after)
3029 /// CHECK-DAG: InstanceFieldSet
3030 /// CHECK-DAG: Phi
3031 /// CHECK-DAG: Phi
3032 /// CHECK-DAG: InstanceFieldSet
3033 /// CHECK-DAG: InstanceFieldSet
3034 /// CHECK-DAG: Phi
3035
3036 /// CHECK-START: int Main.testLoop24(TestClass, int) load_store_elimination (after)
3037 /// CHECK: InstanceFieldSet
3038 /// CHECK: InstanceFieldSet
3039 /// CHECK: InstanceFieldSet
3040 /// CHECK-NOT: InstanceFieldSet
3041
3042 // Test matching Phis for store elimination.
3043 static int testLoop24(TestClass obj, int n) {
3044 obj.i = -1;
3045 int phi = -1;
3046 for (int i = 0; i < n; ++i) {
3047 obj.i = i;
3048 phi = i;
3049 }
3050 if ((n & 1) != 0) {
3051 obj.i = 2;
3052 phi = 2;
3053 }
3054 if (n == 3) {
3055 return -2; // Make the above stores observable.
3056 }
3057 // As the stores above are observable and kept, we match the merged
3058 // heap value with existing Phis and determine that we're storing
3059 // the same value that's already there, so we eliminate this store.
3060 obj.i = phi;
3061 return phi;
3062 }
3063
3064 /// CHECK-START: int Main.testLoop25(TestClass, int) load_store_elimination (before)
3065 /// CHECK-DAG: InstanceFieldSet
3066 /// CHECK-DAG: Phi
3067 /// CHECK-DAG: Phi
3068 /// CHECK-DAG: InstanceFieldSet
3069 /// CHECK-DAG: Phi
3070 /// CHECK-DAG: InstanceFieldGet
3071 /// CHECK-DAG: InstanceFieldSet
3072
3073 /// CHECK-START: int Main.testLoop25(TestClass, int) load_store_elimination (after)
3074 /// CHECK-DAG: InstanceFieldSet
3075 /// CHECK-DAG: Phi
3076 /// CHECK-DAG: Phi
3077 /// CHECK-DAG: Phi
3078 /// CHECK-DAG: InstanceFieldSet
3079 /// CHECK-DAG: Phi
3080 /// CHECK-DAG: Phi
3081 /// CHECK-DAG: InstanceFieldSet
3082
3083 /// CHECK-START: int Main.testLoop25(TestClass, int) load_store_elimination (after)
3084 /// CHECK-NOT: InstanceFieldGet
3085
3086 // Test that we do not match multiple dependent Phis for load and store elimination.
3087 static int testLoop25(TestClass obj, int n) {
3088 obj.i = 1;
3089 int phi = 1;
3090 for (int i = 0; i < n; ++i) {
3091 if ((i & 1) != 0) {
3092 obj.i = 2;
3093 phi = 2;
3094 }
3095 // There is a Phi here for the variable `phi` before the "++i".
3096 // This Phi and the loop Phi for `phi` depend on each other.
3097 }
3098 if (n == 3) {
3099 return -1; // Make above stores observable.
3100 }
3101 // We're not matching multiple Phi placeholders to existing Phis. Therefore the load
3102 // below requires 2 extra Phis to be created and the store below shall not be eliminated
3103 // even though it stores the same value that's already present in the heap location.
3104 int tmp = obj.i;
3105 obj.i = phi;
3106 return tmp + phi;
3107 }
3108
3109 /// CHECK-START: int Main.testLoop26(TestClass, int) load_store_elimination (before)
3110 /// CHECK-DAG: NewInstance
3111 /// CHECK-DAG: InstanceFieldSet
3112 /// CHECK-DAG: Phi
3113 /// CHECK-DAG: NewInstance
3114 /// CHECK-DAG: InstanceFieldSet
3115 /// CHECK-DAG: InstanceFieldGet
3116 /// CHECK-DAG: InstanceFieldGet
3117
3118 /// CHECK-START: int Main.testLoop26(TestClass, int) load_store_elimination (after)
3119 /// CHECK-DAG: NewInstance
3120 /// CHECK-DAG: InstanceFieldSet
3121 /// CHECK-DAG: Phi
3122 /// CHECK-DAG: Phi
3123 /// CHECK-DAG: NewInstance
3124 /// CHECK-DAG: InstanceFieldSet
3125 /// CHECK-DAG: InstanceFieldGet
3126
3127 /// CHECK-START: int Main.testLoop26(TestClass, int) load_store_elimination (after)
3128 /// CHECK: InstanceFieldGet
3129 /// CHECK-NOT: InstanceFieldGet
3130
3131 // Test load elimination creating a reference Phi.
3132 static int testLoop26(TestClass obj, int n) {
3133 obj.next = new TestClass(1, 2);
3134 for (int i = 0; i < n; ++i) {
3135 obj.next = new SubTestClass();
3136 }
3137 return obj.next.i;
3138 }
3139
3140 /// CHECK-START: int Main.testLoop27(TestClass, int) load_store_elimination (before)
3141 /// CHECK-DAG: NewInstance
3142 /// CHECK-DAG: InstanceFieldSet
3143 /// CHECK-DAG: Phi
3144 /// CHECK-DAG: NewInstance
3145 /// CHECK-DAG: InstanceFieldSet
3146 /// CHECK-DAG: InstanceFieldGet
3147 /// CHECK-DAG: InstanceFieldGet
3148
3149 /// CHECK-START: int Main.testLoop27(TestClass, int) load_store_elimination (after)
3150 /// CHECK-DAG: NewInstance
3151 /// CHECK-DAG: InstanceFieldSet
3152 /// CHECK-DAG: Phi
3153 /// CHECK-DAG: Phi
3154 /// CHECK-DAG: NewInstance
3155 /// CHECK-DAG: InstanceFieldSet
3156 /// CHECK-DAG: Phi
3157 /// CHECK-DAG: InstanceFieldGet
3158
3159 /// CHECK-START: int Main.testLoop27(TestClass, int) load_store_elimination (after)
3160 /// CHECK: InstanceFieldGet
3161 /// CHECK-NOT: InstanceFieldGet
3162
3163 // Test load elimination creating two reference Phis that depend on each other.
3164 static int testLoop27(TestClass obj, int n) {
3165 obj.next = new TestClass(1, 2);
3166 for (int i = 0; i < n; ++i) {
3167 if ((i & 1) != 0) {
3168 obj.next = new SubTestClass();
3169 }
3170 // There shall be a Phi created here for `obj.next` before the "++i".
3171 // This Phi and the loop Phi that shall be created for `obj.next` depend on each other.
3172 }
3173 return obj.next.i;
3174 }
3175
3176 /// CHECK-START: int Main.testLoop28(TestClass, int) load_store_elimination (before)
3177 /// CHECK-DAG: InstanceFieldSet
3178 /// CHECK-DAG: NewArray
3179 /// CHECK-DAG: Phi
3180 /// CHECK-DAG: ArrayGet
3181 /// CHECK-DAG: ArraySet
3182 /// CHECK-DAG: ArrayGet
3183 /// CHECK-DAG: ArraySet
3184 /// CHECK-DAG: InstanceFieldGet
3185 /// CHECK-DAG: ArraySet
3186 /// CHECK-DAG: ArrayGet
3187
3188 /// CHECK-START: int Main.testLoop28(TestClass, int) load_store_elimination (after)
3189 /// CHECK-DAG: InstanceFieldSet
3190 /// CHECK-DAG: Phi
3191 /// CHECK-DAG: Phi
3192 /// CHECK-DAG: Phi
3193 /// CHECK-DAG: Phi
3194 /// CHECK-DAG: InstanceFieldGet
3195
3196 /// CHECK-START: int Main.testLoop28(TestClass, int) load_store_elimination (after)
3197 /// CHECK-NOT: NewArray
3198 /// CHECK-NOT: ArrayGet
3199 /// CHECK-NOT: ArraySet
3200
3201 /// CHECK-START: int Main.testLoop28(TestClass, int) load_store_elimination (after)
3202 /// CHECK: Phi
3203 /// CHECK: Phi
3204 /// CHECK: Phi
3205 /// CHECK: Phi
3206 /// CHECK-NOT: Phi
3207
3208 // Test eliminating array allocation, loads and stores and creating loop Phis
3209 // after determining that a field load depending on loop Phi placeholder cannot
3210 // be eliminated.
3211 private static int testLoop28(TestClass obj, int n) {
3212 obj.i = 1;
3213 int[] a = new int[3];
3214 for (int i = 0; i < n; ++i) {
3215 a[0] = a[1];
3216 a[1] = a[2];
3217 a[2] = obj.i;
3218 $noinline$clobberObservables();
3219 }
3220 return a[0];
3221 }
3222
3223 /// CHECK-START: int Main.testLoop29(int) load_store_elimination (before)
3224 /// CHECK-DAG: NewArray
3225 /// CHECK-DAG: Phi
3226 /// CHECK-DAG: Phi
3227 /// CHECK-DAG: ArrayGet
3228 /// CHECK-DAG: ArraySet
3229
3230 /// CHECK-START: int Main.testLoop29(int) load_store_elimination (after)
3231 /// CHECK-DAG: NewArray
3232 /// CHECK-DAG: Phi
3233 /// CHECK-DAG: Phi
3234 /// CHECK-DAG: ArrayGet
3235 /// CHECK-DAG: ArraySet
3236
3237 // Test that ArraySet with non-default value prevents matching ArrayGet for
3238 // the same array to default value even when the ArraySet is using an index
3239 // offset by one, making LSA declare that the two heap locations do not alias.
3240 private static int testLoop29(int n) {
3241 int[] a = new int[4];
3242 int sum = 0;
3243 for (int i = 0; i < n; ) {
3244 int value = a[i] + 1;
3245 sum += value;
3246 ++i;
3247 a[i] = value;
3248 }
3249 return sum;
3250 }
3251
3252 /// CHECK-START: int Main.testLoop30(int) load_store_elimination (before)
3253 /// CHECK-DAG: NewArray
3254 /// CHECK-DAG: Phi
3255 /// CHECK-DAG: Phi
3256 /// CHECK-DAG: ArrayGet
3257 /// CHECK-DAG: ArraySet
3258
3259 /// CHECK-START: int Main.testLoop30(int) load_store_elimination (after)
3260 /// CHECK-NOT: ArrayGet
3261 /// CHECK-NOT: ArraySet
3262
3263 // Test that ArraySet with default value does not prevent matching ArrayGet
3264 // for the same array to the default value.
3265 private static int testLoop30(int n) {
3266 int[] a = new int[4]; // NewArray is kept due to environment use by Deoptimize.
3267 int sum = 0;
3268 for (int i = 0; i < n; ) {
3269 int value = a[i] + 1;
3270 sum += value;
3271 ++i;
3272 a[i] = 0;
3273 }
3274 return sum;
3275 }
3276
3277 /// CHECK-START: int Main.testLoop31(int) load_store_elimination (before)
3278 /// CHECK-DAG: NewArray
3279 /// CHECK-DAG: Phi
3280 /// CHECK-DAG: Phi
3281 /// CHECK-DAG: ArrayGet
3282 /// CHECK-DAG: ArraySet
3283
3284 /// CHECK-START: int Main.testLoop31(int) load_store_elimination (after)
3285 /// CHECK-NOT: ArrayGet
3286 /// CHECK-NOT: ArraySet
3287
3288 // Test that ArraySet with default value read from the array does not
3289 // prevent matching ArrayGet for the same array to the default value.
3290 private static int testLoop31(int n) {
3291 int[] a = new int[4]; // NewArray is kept due to environment use by Deoptimize.
3292 int sum = 0;
3293 for (int i = 0; i < n; ) {
3294 int value = a[i];
3295 sum += value;
3296 ++i;
3297 a[i] = value;
3298 }
3299 return sum;
3300 }
3301
3302 /// CHECK-START: int Main.testLoop32(TestClass, int) load_store_elimination (before)
3303 /// CHECK-DAG: InstanceFieldSet
3304 /// CHECK-DAG: Phi
3305 /// CHECK-DAG: Phi
3306 /// CHECK-DAG: InstanceFieldSet
3307 /// CHECK-DAG: InstanceFieldSet
3308 /// CHECK-DAG: Phi
3309 /// CHECK-DAG: InstanceFieldSet
3310
3311 /// CHECK-START: int Main.testLoop32(TestClass, int) load_store_elimination (after)
3312 /// CHECK-DAG: InstanceFieldSet
3313 /// CHECK-DAG: Phi
3314 /// CHECK-DAG: Phi
3315 /// CHECK-DAG: InstanceFieldSet
3316 /// CHECK-DAG: InstanceFieldSet
3317 /// CHECK-DAG: Phi
3318
3319 /// CHECK-START: int Main.testLoop32(TestClass, int) load_store_elimination (after)
3320 /// CHECK: InstanceFieldSet
3321 /// CHECK: InstanceFieldSet
3322 /// CHECK: InstanceFieldSet
3323 /// CHECK-NOT: InstanceFieldSet
3324
3325 // Test matching Phis for store elimination.
3326 static int testLoop32(TestClass obj, int n) {
3327 obj.i = -1;
3328 int phi = -1;
3329 for (int i = 0; i < n; ) {
3330 ++i;
3331 if ((i & 1) != 0) {
3332 obj.i = i;
3333 phi = i;
3334 }
3335 }
3336 if ((n & 1) != 0) {
3337 obj.i = 2;
3338 phi = 2;
3339 }
3340 if (n == 3) {
3341 return -2; // Make the above stores observable.
3342 }
3343 // As the stores above are observable and kept, we match the merged
3344 // heap value with existing Phis and determine that we're storing
3345 // the same value that's already there, so we eliminate this store.
3346 obj.i = phi;
3347 return phi;
3348 }
3349
3350 // CHECK-START: int Main.testLoop33(TestClass, int) load_store_elimination (before)
3351 // CHECK-DAG: InstanceFieldSet
3352 // CHECK-DAG: NewArray
3353 // CHECK-DAG: Phi
3354 // CHECK-DAG: ArrayGet
3355 // CHECK-DAG: InstanceFieldSet
3356 // CHECK-DAG: Phi
3357 // CHECK-DAG: ArrayGet
3358 // CHECK-DAG: InstanceFieldGet
3359 // CHECK-DAG: InstanceFieldSet
3360 // CHECK-DAG: InstanceFieldGet
3361
3362 // CHECK-START: int Main.testLoop33(TestClass, int) load_store_elimination (after)
3363 // CHECK-DAG: InstanceFieldSet
3364 // CHECK-DAG: Phi
3365 // CHECK-DAG: InstanceFieldSet
3366 // CHECK-DAG: Phi
3367 // CHECK-DAG: InstanceFieldGet
3368 // CHECK-DAG: InstanceFieldSet
3369 // CHECK-DAG: InstanceFieldGet
3370
3371 // CHECK-START: int Main.testLoop33(TestClass, int) load_store_elimination (after)
3372 // CHECK-NOT: ArrayGet
3373
3374 // Test that when processing Phi placeholder with unknown input, we allow materialized
3375 // default value in pre-header for array location with index defined in the loop.
3376 static int testLoop33(TestClass obj, int n) {
3377 obj.i = 0;
3378 int[] a0 = new int[n];
3379 for (int i = 0; i < n; ++i) {
3380 obj.i = a0[i];
3381 $noinline$clobberObservables(); // Make `obj.i` unknown.
3382 }
3383 for (int i = 0; i < n; ++i) {
3384 int zero = a0[i];
3385 int unknown = obj.i;
3386 obj.j += zero + unknown;
3387 }
3388 return obj.j;
3389 }
3390
Vladimir Marko0571d472020-09-22 10:14:39 +01003391 /// CHECK-START: int Main.testLoop34(int) load_store_elimination (before)
3392 /// CHECK-DAG: NewArray
3393 /// CHECK-DAG: Phi
3394 /// CHECK-DAG: Phi
3395 /// CHECK-DAG: ArrayGet
3396 /// CHECK-DAG: ArraySet
3397
3398 /// CHECK-START: int Main.testLoop34(int) load_store_elimination (after)
3399 /// CHECK-DAG: NewArray
3400 /// CHECK-DAG: Phi
3401 /// CHECK-DAG: Phi
3402 /// CHECK-DAG: ArrayGet
3403 /// CHECK-DAG: ArraySet
3404
3405 // Test that ArraySet with non-default value prevents matching ArrayGet for
3406 // the same array to default value even when the ArraySet is using an index
3407 // offset by one, making LSA declare that the two heap locations do not alias.
3408 // Also test that the ArraySet is not eliminated.
3409 private static int testLoop34(int n) {
3410 int[] a = new int[n + 1];
3411 int sum = 0;
3412 for (int i = 0; i < n; ) {
3413 int value = a[i] + 1;
3414 sum += value;
3415 ++i;
3416 a[i] = value;
3417 }
3418 return sum;
3419 }
3420
3421 /// CHECK-START: int Main.testLoop35(int) load_store_elimination (before)
3422 /// CHECK-DAG: NewArray
3423 /// CHECK-DAG: Phi
3424 /// CHECK-DAG: Phi
3425 /// CHECK-DAG: ArrayGet
3426 /// CHECK-DAG: ArraySet
3427 /// CHECK-DAG: ArraySet
3428
3429 /// CHECK-START: int Main.testLoop35(int) load_store_elimination (after)
3430 /// CHECK-DAG: NewArray
3431 /// CHECK-DAG: Phi
3432 /// CHECK-DAG: Phi
3433 /// CHECK-DAG: ArrayGet
3434 /// CHECK-DAG: ArraySet
3435
3436 /// CHECK-START: int Main.testLoop35(int) load_store_elimination (after)
3437 /// CHECK: ArraySet
3438 /// CHECK-NOT: ArraySet
3439
3440 // Test that ArraySet with non-default value prevents matching ArrayGet for
3441 // the same array to default value even when the ArraySet is using an index
3442 // offset by one, making LSA declare that the two heap locations do not alias.
3443 // Also test that the ArraySet is not eliminated and that a store after the
3444 // loop is eliminated.
3445 private static int testLoop35(int n) {
3446 int[] a = new int[n + 1];
3447 int sum = 0;
3448 for (int i = 0; i < n; ) {
3449 int value = a[i] + 1;
3450 sum += value;
3451 ++i;
3452 a[i] = value;
3453 }
3454 a[0] = 1;
3455 return sum;
3456 }
3457
Vladimir Markodac82392021-05-10 15:44:24 +00003458 /// CHECK-START: int Main.testLoop36(int) load_store_elimination (before)
3459 /// CHECK-DAG: ArraySet
3460 /// CHECK-DAG: Deoptimize
3461 /// CHECK-DAG: ArrayGet
3462 /// CHECK-DAG: ArrayGet
3463 /// CHECK-DAG: ArrayGet
3464 /// CHECK-DAG: ArrayGet
3465
3466 /// CHECK-START: int Main.testLoop36(int) load_store_elimination (before)
3467 /// CHECK-NOT: BoundsCheck
3468
3469 /// CHECK-START: int Main.testLoop36(int) load_store_elimination (after)
3470 /// CHECK-DAG: ArraySet
3471 /// CHECK-DAG: Deoptimize
3472 /// CHECK-DAG: ArrayGet
3473 /// CHECK-DAG: ArrayGet
3474 /// CHECK-DAG: ArrayGet
3475 /// CHECK-DAG: ArrayGet
3476
3477 // Regression test for b/187487955.
3478 // We previously failed a DCHECK() during the search for kept stores when
3479 // we encountered two array locations for the same array and considered
3480 // non-aliasing by LSA when only one of the array locations had index
3481 // defined inside the loop. Note that this situation requires that BCE
3482 // eliminates BoundsCheck instructions, otherwise LSA considers those
3483 // locations aliasing.
3484 private static int testLoop36(int n) {
3485 int[] a = new int[n];
3486 int zero = 0;
3487 int i = 0;
3488 for (; i < n; ++i) {
3489 a[i] = i;
3490 // Extra instructions to avoid loop unrolling.
3491 zero = (((zero ^ 1) + 2) ^ 1) - 2;
3492 zero = (((zero ^ 4) + 8) ^ 4) - 8;
3493 }
3494 // Use 4 loads with consecutive fixed offsets from the loop Phi for `i`.
3495 // BCE shall replace BoundsChecks with Deoptimize, so that indexes here are
3496 // the Phi plus/minus a constant, something that LSA considers non-aliasing
3497 // with the Phi (LSA does not take different loop iterations into account)
3498 // but LSE must consider aliasing across dfferent loop iterations.
3499 return a[i - 1] + a[i - 2] + a[i - 3] + a[i - 4] + zero;
3500 }
3501
3502 /// CHECK-START: int Main.testLoop37(int) load_store_elimination (before)
3503 /// CHECK-DAG: ArraySet
3504 /// CHECK-DAG: Deoptimize
3505 /// CHECK-DAG: ArrayGet
3506 /// CHECK-DAG: ArrayGet
3507 /// CHECK-DAG: ArrayGet
3508 /// CHECK-DAG: ArrayGet
3509
3510 /// CHECK-START: int Main.testLoop37(int) load_store_elimination (before)
3511 /// CHECK-NOT: BoundsCheck
3512
3513 /// CHECK-START: int Main.testLoop37(int) load_store_elimination (after)
3514 /// CHECK-DAG: ArraySet
3515 /// CHECK-DAG: Deoptimize
3516 /// CHECK-DAG: ArrayGet
3517 /// CHECK-DAG: ArrayGet
3518 /// CHECK-DAG: ArrayGet
3519 /// CHECK-DAG: ArrayGet
3520
3521 // Similar to testLoop36 but the writes are done via a different reference to the same array.
3522 // We previously used a reference comparison for back-edge aliasing analysis but this test
3523 // has different references and therefore needs `HeapLocationCollector::CanReferencesAlias()`.
3524 private static int testLoop37(int n) {
3525 int[] a = new int[n];
3526 int[] b = $noinline$returnArg(a);
3527 int zero = 0;
3528 int i = 0;
3529 for (; i < n; ++i) {
3530 b[i] = i;
3531 // Extra instructions to avoid loop unrolling.
3532 zero = (((zero ^ 1) + 2) ^ 1) - 2;
3533 zero = (((zero ^ 4) + 8) ^ 4) - 8;
3534 }
3535 // Use 4 loads with consecutive fixed offsets from the loop Phi for `i`.
3536 // BCE shall replace BoundsChecks with Deoptimize, so that indexes here are
3537 // the Phi plus/minus a constant, something that LSA considers non-aliasing
3538 // with the Phi (LSA does not take different loop iterations into account)
3539 // but LSE must consider aliasing across dfferent loop iterations.
3540 return a[i - 1] + a[i - 2] + a[i - 3] + a[i - 4] + zero;
3541 }
3542
3543 private static int[] $noinline$returnArg(int[] a) {
3544 return a;
3545 }
3546
3547 /// CHECK-START: int Main.testLoop38(int, int[]) load_store_elimination (before)
3548 /// CHECK-DAG: ArraySet
3549 /// CHECK-DAG: Deoptimize
3550 /// CHECK-DAG: ArrayGet
3551 /// CHECK-DAG: ArrayGet
3552 /// CHECK-DAG: ArrayGet
3553 /// CHECK-DAG: ArrayGet
3554
3555 /// CHECK-START: int Main.testLoop38(int, int[]) load_store_elimination (before)
3556 /// CHECK-NOT: BoundsCheck
3557
3558 /// CHECK-START: int Main.testLoop38(int, int[]) load_store_elimination (after)
3559 /// CHECK-DAG: ArraySet
3560 /// CHECK-DAG: Deoptimize
3561
3562 /// CHECK-START: int Main.testLoop38(int, int[]) load_store_elimination (after)
3563 /// CHECK-NOT: ArrayGet
3564
3565 // Similar to testLoop37 but writing to a different array that exists before allocating `a`,
3566 // so that `HeapLocationCollector::CanReferencesAlias()` returns false and all the ArrayGet
3567 // instructions are actually eliminated.
3568 private static int testLoop38(int n, int[] b) {
3569 int[] a = new int[n];
3570 int zero = 0;
3571 int i = 0;
3572 for (; i < n; ++i) {
3573 b[i] = i;
3574 // Extra instructions to avoid loop unrolling.
3575 zero = (((zero ^ 1) + 2) ^ 1) - 2;
3576 zero = (((zero ^ 4) + 8) ^ 4) - 8;
3577 }
3578 // Use 4 loads with consecutive fixed offsets from the loop Phi for `i`.
3579 // BCE shall replace BoundsChecks with Deoptimize, so that indexes here are
3580 // the Phi plus/minus a constant, something that LSA considers non-aliasing
3581 // with the Phi (LSA does not take different loop iterations into account)
3582 // but LSE must consider aliasing across dfferent loop iterations.
3583 return a[i - 1] + a[i - 2] + a[i - 3] + a[i - 4] + zero;
3584 }
3585
Vladimir Marko3224f382020-06-23 14:19:53 +01003586 /// CHECK-START: int Main.testNestedLoop1(TestClass, int) load_store_elimination (before)
3587 /// CHECK-DAG: InstanceFieldSet
3588 /// CHECK-DAG: InstanceFieldGet
3589
3590 /// CHECK-START: int Main.testNestedLoop1(TestClass, int) load_store_elimination (after)
3591 /// CHECK-DAG: InstanceFieldSet
3592 /// CHECK-DAG: InstanceFieldGet
3593
3594 // Test heap value clobbering in nested loop.
3595 private static int testNestedLoop1(TestClass obj, int n) {
3596 obj.i = 1;
3597 for (int i = 0; i < n; ++i) {
3598 for (int j = i + 1; j < n; ++j) {
3599 $noinline$clobberObservables();
3600 }
3601 }
3602 return obj.i;
3603 }
3604
3605 /// CHECK-START: int Main.testNestedLoop2(TestClass, int) load_store_elimination (before)
3606 /// CHECK-DAG: InstanceFieldSet
3607 /// CHECK-DAG: InstanceFieldSet
3608 /// CHECK-DAG: Phi
3609 /// CHECK-DAG: InstanceFieldGet
3610 /// CHECK-DAG: Phi
3611 /// CHECK-DAG: InstanceFieldSet
3612 /// CHECK-DAG: InstanceFieldGet
3613
3614 /// CHECK-START: int Main.testNestedLoop2(TestClass, int) load_store_elimination (after)
3615 /// CHECK-DAG: InstanceFieldSet
3616 /// CHECK-DAG: InstanceFieldSet
3617 /// CHECK-DAG: Phi
3618 /// CHECK-DAG: Phi
3619 /// CHECK-DAG: InstanceFieldGet
3620 /// CHECK-DAG: Phi
3621 /// CHECK-DAG: InstanceFieldSet
3622
3623 /// CHECK-START: int Main.testNestedLoop2(TestClass, int) load_store_elimination (after)
3624 /// CHECK: InstanceFieldGet
3625 /// CHECK-NOT: InstanceFieldGet
3626
3627 /// CHECK-START: int Main.testNestedLoop2(TestClass, int) load_store_elimination (after)
3628 /// CHECK: Phi
3629 /// CHECK: Phi
3630 /// CHECK: Phi
3631 /// CHECK-NOT: Phi
3632
3633 // Test heap value clobbering in the nested loop and load elimination for a heap
3634 // location then set to known value before the end of the outer loop.
3635 private static int testNestedLoop2(TestClass obj, int n) {
3636 obj.i = 1;
3637 obj.j = 2;
3638 for (int i = 0; i < n; ++i) {
3639 int tmp = obj.j;
3640 for (int j = i + 1; j < n; ++j) {
3641 $noinline$clobberObservables();
3642 }
3643 obj.i = tmp;
3644 }
3645 return obj.i;
3646 }
3647
3648 /// CHECK-START: int Main.testNestedLoop3(TestClass, int) load_store_elimination (before)
3649 /// CHECK-DAG: InstanceFieldSet
3650 /// CHECK-DAG: Phi
3651 /// CHECK-DAG: InstanceFieldSet
3652 /// CHECK-DAG: Phi
3653 /// CHECK-DAG: InstanceFieldGet
3654 /// CHECK-DAG: InstanceFieldSet
3655 /// CHECK-DAG: InstanceFieldGet
3656
3657 /// CHECK-START: int Main.testNestedLoop3(TestClass, int) load_store_elimination (after)
3658 /// CHECK-DAG: InstanceFieldSet
3659 /// CHECK-DAG: Phi
3660 /// CHECK-DAG: Phi
3661 /// CHECK-DAG: InstanceFieldSet
3662 /// CHECK-DAG: Phi
3663 /// CHECK-DAG: InstanceFieldGet
3664 /// CHECK-DAG: InstanceFieldSet
3665
3666 /// CHECK-START: int Main.testNestedLoop3(TestClass, int) load_store_elimination (after)
3667 /// CHECK: InstanceFieldGet
3668 /// CHECK-NOT: InstanceFieldGet
3669
3670 /// CHECK-START: int Main.testNestedLoop3(TestClass, int) load_store_elimination (after)
3671 /// CHECK: Phi
3672 /// CHECK: Phi
3673 /// CHECK: Phi
3674 /// CHECK-NOT: Phi
3675
3676 // Test heap value clobbering in the nested loop and load elimination for a heap
3677 // location then set to known value before the end of the outer loop.
3678 private static int testNestedLoop3(TestClass obj, int n) {
3679 obj.i = 1;
3680 for (int i = 0; i < n; ++i) {
3681 obj.j = 2;
3682 for (int j = i + 1; j < n; ++j) {
3683 $noinline$clobberObservables();
3684 }
3685 obj.i = obj.j;
3686 }
3687 return obj.i;
3688 }
3689
3690 /// CHECK-START: int Main.testNestedLoop4(TestClass, int) load_store_elimination (before)
3691 /// CHECK-DAG: InstanceFieldSet
3692 /// CHECK-DAG: Phi
3693 /// CHECK-DAG: Phi
3694 /// CHECK-DAG: InstanceFieldSet
3695 /// CHECK-DAG: InstanceFieldGet
3696
3697 /// CHECK-START: int Main.testNestedLoop4(TestClass, int) load_store_elimination (after)
3698 /// CHECK-DAG: InstanceFieldSet
3699 /// CHECK-DAG: Phi
3700 /// CHECK-DAG: Phi
3701 /// CHECK-DAG: Phi
3702 /// CHECK-DAG: Phi
3703 /// CHECK-DAG: InstanceFieldSet
3704
3705 /// CHECK-START: int Main.testNestedLoop4(TestClass, int) load_store_elimination (after)
3706 /// CHECK-NOT: InstanceFieldGet
3707
3708 /// CHECK-START: int Main.testNestedLoop4(TestClass, int) load_store_elimination (after)
3709 /// CHECK: Phi
3710 /// CHECK: Phi
3711 /// CHECK: Phi
3712 /// CHECK: Phi
3713 /// CHECK-NOT: Phi
3714
3715 // Test creating loop Phis for both inner and outer loop to eliminate a load.
3716 private static int testNestedLoop4(TestClass obj, int n) {
3717 obj.i = 1;
3718 for (int i = 0; i < n; ++i) {
3719 for (int j = i + 1; j < n; ++j) {
3720 obj.i = 2;
3721 }
3722 }
3723 return obj.i;
3724 }
3725
3726 /// CHECK-START: int Main.testNestedLoop5(TestClass, int) load_store_elimination (before)
3727 /// CHECK-DAG: InstanceFieldSet
3728 /// CHECK-DAG: Phi
3729 /// CHECK-DAG: InstanceFieldSet
3730 /// CHECK-DAG: Phi
3731 /// CHECK-DAG: InstanceFieldSet
3732 /// CHECK-DAG: InstanceFieldGet
3733
3734 /// CHECK-START: int Main.testNestedLoop5(TestClass, int) load_store_elimination (after)
3735 /// CHECK-DAG: InstanceFieldSet
3736 /// CHECK-DAG: Phi
3737 /// CHECK-DAG: Phi
3738 /// CHECK-DAG: InstanceFieldSet
3739 /// CHECK-DAG: Phi
3740 /// CHECK-DAG: InstanceFieldSet
3741
3742 /// CHECK-START: int Main.testNestedLoop5(TestClass, int) load_store_elimination (after)
3743 /// CHECK-NOT: InstanceFieldGet
3744
3745 /// CHECK-START: int Main.testNestedLoop5(TestClass, int) load_store_elimination (after)
3746 /// CHECK: Phi
3747 /// CHECK: Phi
3748 /// CHECK: Phi
3749 /// CHECK-NOT: Phi
3750
3751 // Test creating a loop Phi for outer loop to eliminate a load.
3752 private static int testNestedLoop5(TestClass obj, int n) {
3753 obj.i = 1;
3754 for (int i = 0; i < n; ++i) {
3755 obj.i = 2;
3756 for (int j = i + 1; j < n; ++j) {
3757 obj.j = 3; // Unrelated.
3758 }
3759 }
3760 return obj.i;
3761 }
3762
3763 /// CHECK-START: int Main.testNestedLoop6(TestClass, int) load_store_elimination (before)
3764 /// CHECK-DAG: InstanceFieldSet
3765 /// CHECK-DAG: InstanceFieldSet
3766 /// CHECK-DAG: Phi
3767 /// CHECK-DAG: Phi
3768 /// CHECK-DAG: InstanceFieldGet
3769 /// CHECK-DAG: InstanceFieldSet
3770 /// CHECK-DAG: InstanceFieldGet
3771
3772 /// CHECK-START: int Main.testNestedLoop6(TestClass, int) load_store_elimination (after)
3773 /// CHECK-DAG: InstanceFieldSet
3774 /// CHECK-DAG: InstanceFieldSet
3775 /// CHECK-DAG: Phi
3776 /// CHECK-DAG: Phi
3777 /// CHECK-DAG: Phi
3778 /// CHECK-DAG: Phi
3779 /// CHECK-DAG: InstanceFieldGet
3780 /// CHECK-DAG: InstanceFieldSet
3781
3782 /// CHECK-START: int Main.testNestedLoop6(TestClass, int) load_store_elimination (after)
3783 /// CHECK: InstanceFieldGet
3784 /// CHECK-NOT: InstanceFieldGet
3785
3786 /// CHECK-START: int Main.testNestedLoop6(TestClass, int) load_store_elimination (after)
3787 /// CHECK: Phi
3788 /// CHECK: Phi
3789 /// CHECK: Phi
3790 /// CHECK: Phi
3791 /// CHECK-NOT: Phi
3792
3793 // Test heap value clobbering in the nested loop and load elimination for a heap
3794 // location then set to known value before the end of that inner loop.
3795 private static int testNestedLoop6(TestClass obj, int n) {
3796 obj.i = 1;
3797 obj.j = 2;
3798 for (int i = 0; i < n; ++i) {
3799 for (int j = i + 1; j < n; ++j) {
3800 int tmp = obj.j;
3801 $noinline$clobberObservables();
3802 obj.i = tmp;
3803 }
3804 }
3805 return obj.i;
3806 }
3807
3808 /// CHECK-START: int Main.testNestedLoop7(TestClass, int) load_store_elimination (before)
3809 /// CHECK-DAG: NewArray
3810 /// CHECK-DAG: Phi
3811 /// CHECK-DAG: Phi
3812 /// CHECK-DAG: ArrayGet
3813 /// CHECK-DAG: InstanceFieldSet
3814
3815 /// CHECK-START: int Main.testNestedLoop7(TestClass, int) load_store_elimination (after)
3816 /// CHECK-DAG: NewArray
3817 /// CHECK-DAG: Phi
3818 /// CHECK-DAG: Phi
3819 /// CHECK-DAG: InstanceFieldSet
3820
3821 /// CHECK-START: int Main.testNestedLoop7(TestClass, int) load_store_elimination (after)
3822 /// CHECK-NOT: ArrayGet
3823
3824 // Test load elimination in inner loop reading default value that is loop invariant
3825 // with an index defined inside the inner loop.
3826 private static int testNestedLoop7(TestClass obj, int n) {
3827 // The NewArray is kept as it may throw for negative n.
3828 // TODO: Eliminate constructor fence even though the NewArray is kept.
3829 int[] a0 = new int[n];
3830 for (int i = 0; i < n; ++i) {
3831 for (int j = i + 1; j < n; ++j) {
3832 obj.i = a0[j];
3833 }
3834 }
3835 return n;
3836 }
3837
3838 /// CHECK-START: int Main.testNestedLoop8(TestClass, int) load_store_elimination (before)
3839 /// CHECK-DAG: NewInstance
3840 /// CHECK-DAG: InstanceFieldSet
3841 /// CHECK-DAG: Phi
3842 /// CHECK-DAG: Phi
3843 /// CHECK-DAG: NewInstance
3844 /// CHECK-DAG: InstanceFieldSet
3845 /// CHECK-DAG: InstanceFieldGet
3846 /// CHECK-DAG: InstanceFieldGet
3847
3848 /// CHECK-START: int Main.testNestedLoop8(TestClass, int) load_store_elimination (after)
3849 /// CHECK-DAG: NewInstance
3850 /// CHECK-DAG: InstanceFieldSet
3851 /// CHECK-DAG: Phi
3852 /// CHECK-DAG: Phi
3853 /// CHECK-DAG: Phi
3854 /// CHECK-DAG: Phi
3855 /// CHECK-DAG: NewInstance
3856 /// CHECK-DAG: InstanceFieldSet
3857 /// CHECK-DAG: InstanceFieldGet
3858
3859 /// CHECK-START: int Main.testNestedLoop8(TestClass, int) load_store_elimination (after)
3860 /// CHECK: InstanceFieldGet
3861 /// CHECK-NOT: InstanceFieldGet
3862
3863 // Test reference type propagation for Phis created for outer and inner loop.
3864 private static int testNestedLoop8(TestClass obj, int n) {
3865 obj.next = new SubTestClass();
3866 for (int i = 0; i < n; ++i) {
3867 for (int j = i + 1; j < n; ++j) {
3868 obj.next = new TestClass();
3869 }
3870 }
3871 // The Phis created in both loop headers for replacing `obj.next` depend on each other.
3872 return obj.next.i;
3873 }
3874
Alex Light9dec90a2020-09-14 17:58:28 -07003875
3876 /// CHECK-START: long Main.testOverlapLoop(int) load_store_elimination (before)
3877 /// CHECK-DAG: NewArray
3878 /// CHECK-DAG: ArraySet
3879 /// CHECK-DAG: If
3880 /// CHECK-DAG: ArrayGet
3881 /// CHECK-DAG: ArrayGet
3882 /// CHECK-DAG: ArraySet
3883 /// CHECK-DAG: ArrayGet
3884 /// CHECK-DAG: Goto
3885
3886 /// CHECK-START: long Main.testOverlapLoop(int) load_store_elimination (after)
3887 /// CHECK-DAG: NewArray
3888 /// CHECK-DAG: ArraySet
3889 /// CHECK-DAG: If
3890 /// CHECK-DAG: ArrayGet
3891 /// CHECK-DAG: ArrayGet
3892 /// CHECK-DAG: ArraySet
3893 /// CHECK-DAG: Goto
3894 /// CHECK-NOT: ArrayGet
3895
3896 // Test that we don't incorrectly remove writes needed by later loop iterations
3897 // NB This is fibonacci numbers
3898 private static long testOverlapLoop(int cnt) {
3899 long[] w = new long[cnt];
3900 w[1] = 1;
3901 long t = 1;
3902 for (int i = 2; i < cnt; ++i) {
3903 w[i] = w[i - 1] + w[i - 2];
3904 t = w[i];
3905 }
3906 return t;
3907 }
3908
Alex Light86fe9b82020-11-16 16:54:01 +00003909 private static boolean $noinline$getBoolean(boolean val) {
3910 return val;
3911 }
3912
3913 /// CHECK-START: int Main.$noinline$testPartialEscape1(TestClass, boolean) load_store_elimination (before)
3914 /// CHECK-DAG: ParameterValue
3915 /// CHECK-DAG: NewInstance
3916 /// CHECK-DAG: InvokeStaticOrDirect
3917 /// CHECK-DAG: InstanceFieldSet
3918 /// CHECK-DAG: InvokeStaticOrDirect
3919 /// CHECK-DAG: InstanceFieldGet
3920 /// CHECK-DAG: InstanceFieldGet
3921 /// CHECK-DAG: InstanceFieldSet
3922 /// CHECK-DAG: InstanceFieldGet
3923 /// CHECK-DAG: InstanceFieldGet
3924 /// CHECK-DAG: Phi
3925 //
3926 /// CHECK-NOT: NewInstance
3927 /// CHECK-NOT: InvokeStaticOrDirect
3928 /// CHECK-NOT: InstanceFieldSet
3929 /// CHECK-NOT: InstanceFieldGet
3930 //
3931 /// CHECK-START: int Main.$noinline$testPartialEscape1(TestClass, boolean) load_store_elimination (after)
3932 /// CHECK-DAG: ParameterValue
3933 /// CHECK-DAG: NewInstance
3934 /// CHECK-DAG: Phi
3935 //
3936 /// CHECK-START: int Main.$noinline$testPartialEscape1(TestClass, boolean) load_store_elimination (after)
3937 /// CHECK: InvokeStaticOrDirect
3938 /// CHECK: InvokeStaticOrDirect
3939 //
3940 /// CHECK-NOT: InvokeStaticOrDirect
3941
3942 /// CHECK-START: int Main.$noinline$testPartialEscape1(TestClass, boolean) load_store_elimination (after)
3943 /// CHECK: InstanceFieldSet
3944 //
3945 /// CHECK-NOT: InstanceFieldSet
3946 //
3947 /// CHECK-START: int Main.$noinline$testPartialEscape1(TestClass, boolean) load_store_elimination (after)
3948 /// CHECK: InstanceFieldGet
3949 /// CHECK: InstanceFieldGet
3950 /// CHECK: InstanceFieldGet
3951 //
3952 /// CHECK-NOT: InstanceFieldGet
3953 private static int $noinline$testPartialEscape1(TestClass obj, boolean escape) {
3954 TestClass i = new SubTestClass();
3955 int res;
3956 if ($noinline$getBoolean(escape)) {
3957 i.next = obj;
3958 $noinline$Escape(i);
3959 res = i.next.i;
3960 } else {
3961 i.next = obj;
3962 res = i.next.i;
3963 }
3964 return res;
3965 }
3966
Vladimir Marko3224f382020-06-23 14:19:53 +01003967 private static void $noinline$clobberObservables() {}
3968
Alex Light9dec90a2020-09-14 17:58:28 -07003969 static void assertLongEquals(long result, long expected) {
3970 if (expected != result) {
3971 throw new Error("Expected: " + expected + ", found: " + result);
3972 }
3973 }
3974
Mingyao Yang062157f2016-03-02 10:15:36 -08003975 static void assertIntEquals(int result, int expected) {
Mingyao Yang8df69d42015-10-22 15:40:58 -07003976 if (expected != result) {
3977 throw new Error("Expected: " + expected + ", found: " + result);
3978 }
3979 }
3980
Mingyao Yang062157f2016-03-02 10:15:36 -08003981 static void assertFloatEquals(float result, float expected) {
Mingyao Yang8df69d42015-10-22 15:40:58 -07003982 if (expected != result) {
3983 throw new Error("Expected: " + expected + ", found: " + result);
3984 }
3985 }
3986
Mingyao Yang062157f2016-03-02 10:15:36 -08003987 static void assertDoubleEquals(double result, double expected) {
Mingyao Yang8df69d42015-10-22 15:40:58 -07003988 if (expected != result) {
3989 throw new Error("Expected: " + expected + ", found: " + result);
3990 }
3991 }
3992
Vladimir Markob122cd62020-06-11 09:15:21 +00003993 public static void main(String[] args) {
Mingyao Yang8df69d42015-10-22 15:40:58 -07003994 assertDoubleEquals(Math.PI * Math.PI * Math.PI, calcCircleArea(Math.PI));
3995 assertIntEquals(test1(new TestClass(), new TestClass()), 3);
3996 assertIntEquals(test2(new TestClass()), 1);
3997 TestClass obj1 = new TestClass();
3998 TestClass obj2 = new TestClass();
3999 obj1.next = obj2;
4000 assertIntEquals(test3(obj1), 10);
Vladimir Markob122cd62020-06-11 09:15:21 +00004001 assertIntEquals(test4(new TestClass(), true), 1);
4002 assertIntEquals(test4(new TestClass(), false), 1);
4003 assertIntEquals(test5(new TestClass(), true), 1);
4004 assertIntEquals(test5(new TestClass(), false), 2);
Mingyao Yang8df69d42015-10-22 15:40:58 -07004005 assertIntEquals(test6(new TestClass(), new TestClass(), true), 4);
4006 assertIntEquals(test6(new TestClass(), new TestClass(), false), 2);
4007 assertIntEquals(test7(new TestClass()), 1);
4008 assertIntEquals(test8(), 1);
4009 obj1 = new TestClass();
4010 obj2 = new TestClass();
4011 obj1.next = obj2;
4012 assertIntEquals(test9(new TestClass()), 1);
Vladimir Markofaada5e2020-06-10 10:38:40 +00004013 assertIntEquals(test10(new TestClass(3, 4)), 3);
Mingyao Yang8df69d42015-10-22 15:40:58 -07004014 assertIntEquals(TestClass.si, 3);
4015 assertIntEquals(test11(new TestClass()), 10);
4016 assertIntEquals(test12(new TestClass(), new TestClass()), 10);
4017 assertIntEquals(test13(new TestClass(), new TestClass2()), 3);
4018 SubTestClass obj3 = new SubTestClass();
4019 assertIntEquals(test14(obj3, obj3), 2);
4020 assertIntEquals(test15(), 2);
4021 assertIntEquals(test16(), 3);
4022 assertIntEquals(test17(), 0);
4023 assertIntEquals(test18(new TestClass()), 1);
4024 float[] fa1 = { 0.8f };
4025 float[] fa2 = { 1.8f };
4026 assertFloatEquals(test19(fa1, fa2), 1.8f);
4027 assertFloatEquals(test20().i, 0);
Mingyao Yang803cbb92015-12-01 12:24:36 -08004028 test21(new TestClass());
Mingyao Yangfb8464a2015-11-02 10:56:59 -08004029 assertIntEquals(test22(), 13);
Vladimir Markob122cd62020-06-11 09:15:21 +00004030 assertIntEquals(test23(true), 4);
4031 assertIntEquals(test23(false), 5);
4032 assertFloatEquals(test24(), 8.0f);
Vladimir Marko3224f382020-06-23 14:19:53 +01004033 assertIntEquals(test25(false, true, true), 5);
4034 assertIntEquals(test25(true, false, true), 2);
4035 assertFloatEquals(test26(5), 0.0f);
4036 assertFloatEquals(test26(3), 1.0f);
4037 assertIntEquals(test27(false, true), 1);
4038 assertIntEquals(test27(true, false), 1);
4039 assertIntEquals(test28(false, true), 0);
4040 assertIntEquals(test28(true, true), 5);
4041 assertFloatEquals(test29(true), 5.0f);
4042 assertFloatEquals(test29(false), 2.0f);
4043 assertIntEquals(test30(new TestClass(), true), 1);
4044 assertIntEquals(test30(new TestClass(), false), 0);
4045 assertIntEquals(test31(true, true), 5);
4046 assertIntEquals(test31(true, false), 6);
4047 assertIntEquals(test32(1), 10);
4048 assertIntEquals(test32(2), 10);
4049 assertIntEquals(test33(new TestClass(), true), 1);
4050 assertIntEquals(test33(new TestClass(), false), 2);
4051 assertIntEquals(test34(new TestClass(), true, true), 3);
4052 assertIntEquals(test34(new TestClass(), false, true), 4);
4053 assertIntEquals(test34(new TestClass(), true, false), 1);
4054 assertIntEquals(test34(new TestClass(), false, false), 2);
4055 assertIntEquals(test35(new TestClass(), true, true), 3);
4056 assertIntEquals(test35(new TestClass(), false, true), 2);
4057 assertIntEquals(test35(new TestClass(), true, false), 1);
4058 assertIntEquals(test35(new TestClass(), false, false), 2);
4059 assertIntEquals(test36(new TestClass(), true), 2);
4060 assertIntEquals(test36(new TestClass(), false), 4);
4061 assertIntEquals(test37(new TestClass(), true), 1);
4062 assertIntEquals(test37(new TestClass(), false), 0);
4063 assertIntEquals(test38(new TestClass(), true), 1);
4064 assertIntEquals(test38(new TestClass(), false), 2);
4065 assertIntEquals(test39(new TestClass(), true), 0);
4066 assertIntEquals(test39(new TestClass(), false), 1);
4067
Mingyao Yangfb8464a2015-11-02 10:56:59 -08004068 testFinalizableByForcingGc();
Mingyao Yang40bcb932016-02-03 05:46:57 -08004069 assertIntEquals($noinline$testHSelect(true), 0xdead);
Mingyao Yang062157f2016-03-02 10:15:36 -08004070 int[] array = {2, 5, 9, -1, -3, 10, 8, 4};
4071 assertIntEquals(sumWithinRange(array, 1, 5), 11);
Mingyao Yang0a845202016-10-14 16:26:08 -07004072 assertFloatEquals(testAllocationEliminationWithLoops(), 1.0f);
4073 assertFloatEquals(mF, 0f);
Mingyao Yang58d9bfc2016-11-01 13:31:58 -07004074 assertDoubleEquals(Math.PI * Math.PI * Math.PI, getCircleArea(Math.PI, true));
4075 assertDoubleEquals(0d, getCircleArea(Math.PI, false));
Mingyao Yange58bdca2016-10-28 11:07:24 -07004076
Vladimir Marko4307cd72020-07-17 14:35:56 +01004077 assertIntEquals($noinline$testConversion1(new TestClass(), 300), 300);
4078 assertIntEquals($noinline$testConversion1(new TestClass(), 301), 45);
4079 assertIntEquals($noinline$testConversion2(new TestClass(), 300), 300);
4080 assertIntEquals($noinline$testConversion2(new TestClass(), 301), 90);
Vladimir Marko3224f382020-06-23 14:19:53 +01004081 assertIntEquals($noinline$testConversion3(new TestClass(), 0), 0);
4082 assertIntEquals($noinline$testConversion3(new TestClass(), 1), 0);
4083 assertIntEquals($noinline$testConversion3(new TestClass(), 128), 127);
4084 assertIntEquals($noinline$testConversion3(new TestClass(), 129), -128);
4085 assertIntEquals($noinline$testConversion4(new TestClass(), 0), 0);
4086 assertIntEquals($noinline$testConversion4(new TestClass(), 1), 0);
4087 assertIntEquals($noinline$testConversion4(new TestClass(), 128), 254);
4088 assertIntEquals($noinline$testConversion4(new TestClass(), 129), -256);
Vladimir Marko4307cd72020-07-17 14:35:56 +01004089
Mingyao Yange58bdca2016-10-28 11:07:24 -07004090 int[] iarray = {0, 0, 0};
4091 double[] darray = {0d, 0d, 0d};
4092 try {
4093 assertDoubleEquals(Math.PI * Math.PI * Math.PI, testDeoptimize(iarray, darray, Math.PI));
4094 } catch (Exception e) {
Vladimir Markob122cd62020-06-11 09:15:21 +00004095 System.out.println(e.getClass().getName());
Mingyao Yange58bdca2016-10-28 11:07:24 -07004096 }
4097 assertIntEquals(iarray[0], 1);
4098 assertIntEquals(iarray[1], 1);
4099 assertIntEquals(iarray[2], 1);
4100 assertDoubleEquals(darray[0], Math.PI);
4101 assertDoubleEquals(darray[1], Math.PI);
4102 assertDoubleEquals(darray[2], Math.PI);
Mingyao Yang86974902017-03-01 14:03:51 -08004103
4104 assertIntEquals(testAllocationEliminationOfArray1(), 11);
4105 assertIntEquals(testAllocationEliminationOfArray2(), 11);
4106 assertIntEquals(testAllocationEliminationOfArray3(2), 4);
4107 assertIntEquals(testAllocationEliminationOfArray4(2), 6);
Mingyao Yang7cf9af22018-02-06 15:02:42 -08004108 assertIntEquals(testAllocationEliminationOfArray5(2), 12);
4109 try {
4110 testAllocationEliminationOfArray5(-2);
4111 } catch (NegativeArraySizeException e) {
4112 System.out.println("Got NegativeArraySizeException.");
4113 }
Mingyao Yangeb2d2d346e2017-03-02 13:26:17 -08004114
4115 assertIntEquals(testStoreStore().i, 41);
4116 assertIntEquals(testStoreStore().j, 43);
Mingyao Yang293f1c02017-11-08 15:22:17 -08004117
Mingyao Yang46721ef2017-10-05 14:45:17 -07004118 assertIntEquals(testExitMerge(true), 2);
4119 assertIntEquals(testExitMerge2(true), 2);
4120 assertIntEquals(testExitMerge2(false), 2);
4121
Mingyao Yanga3540532018-01-25 12:17:28 -08004122 TestClass2 testclass2 = new TestClass2();
4123 testStoreStore2(testclass2);
4124 assertIntEquals(testclass2.i, 43);
4125 assertIntEquals(testclass2.j, 44);
4126
4127 testStoreStore3(testclass2, true);
4128 assertIntEquals(testclass2.i, 41);
4129 assertIntEquals(testclass2.j, 43);
4130 testStoreStore3(testclass2, false);
4131 assertIntEquals(testclass2.i, 41);
4132 assertIntEquals(testclass2.j, 44);
4133
4134 testStoreStore4();
4135 assertIntEquals(TestClass.si, 62);
4136
4137 int ret = testStoreStore5(testclass2, testclass2);
4138 assertIntEquals(testclass2.i, 72);
4139 assertIntEquals(ret, 71);
4140
4141 testclass2.j = 88;
4142 ret = testStoreStore6(testclass2, testclass2);
4143 assertIntEquals(testclass2.i, 82);
4144 assertIntEquals(ret, 88);
4145
4146 ret = testNoSideEffects(iarray);
Mingyao Yang293f1c02017-11-08 15:22:17 -08004147 assertIntEquals(iarray[0], 101);
Mingyao Yanga3540532018-01-25 12:17:28 -08004148 assertIntEquals(iarray[1], 103);
Mingyao Yang293f1c02017-11-08 15:22:17 -08004149 assertIntEquals(ret, 108);
Mingyao Yanga3540532018-01-25 12:17:28 -08004150
4151 try {
4152 testThrow(testclass2, new Exception());
4153 } catch (Exception e) {}
4154 assertIntEquals(testclass2.i, 55);
4155
4156 assertIntEquals(testStoreStoreWithDeoptimize(new int[4]), 4);
Aart Bik4dc09e72018-05-11 14:40:31 -07004157
Vladimir Marko4307cd72020-07-17 14:35:56 +01004158 assertIntEquals($noinline$testByteArrayDefaultValue(), 0);
4159
Aart Bik4dc09e72018-05-11 14:40:31 -07004160 assertIntEquals(testLocalArrayMerge1(true), 1);
4161 assertIntEquals(testLocalArrayMerge1(false), 1);
4162 assertIntEquals(testLocalArrayMerge2(true), 2);
4163 assertIntEquals(testLocalArrayMerge2(false), 3);
4164 assertIntEquals(testLocalArrayMerge3(true), 2);
4165 assertIntEquals(testLocalArrayMerge3(false), 1);
4166 assertIntEquals(testLocalArrayMerge4(true), 2);
4167 assertIntEquals(testLocalArrayMerge4(false), 2);
Vladimir Marko3224f382020-06-23 14:19:53 +01004168 assertIntEquals(testLocalArrayMerge5(new int[]{ 7 }, true), 7);
4169 assertIntEquals(testLocalArrayMerge5(new int[]{ 9 }, false), 9);
4170 assertIntEquals(testLocalArrayMerge6(new int[1], true, true), 1);
4171 assertIntEquals(testLocalArrayMerge6(new int[1], true, false), 2);
4172 assertIntEquals(testLocalArrayMerge6(new int[1], false, true), 2);
4173 assertIntEquals(testLocalArrayMerge6(new int[1], false, false), 1);
4174 assertIntEquals(testLocalArrayMerge7(new int[2], true, true), 1);
4175 assertIntEquals(testLocalArrayMerge7(new int[2], true, false), 2);
4176 assertIntEquals(testLocalArrayMerge7(new int[2], false, true), 0);
4177 assertIntEquals(testLocalArrayMerge7(new int[2], false, false), 0);
Vladimir Markocbeedc82020-08-25 14:31:10 +01004178 assertIntEquals(testLocalArrayMerge8(true), 0);
4179 assertIntEquals(testLocalArrayMerge8(false), 0);
Vladimir Markofab6f1c2020-07-14 16:25:05 +01004180
4181 TestClass[] tca = new TestClass[] { new TestClass(), null };
4182 try {
4183 $noinline$testThrowingArraySet(tca, new TestClass2());
4184 } catch (ArrayStoreException expected) {
4185 if (tca[0] != null) {
4186 throw new Error("tca[0] is not null");
4187 }
4188 if (tca[1] == null) {
4189 throw new Error("tca[1] is null");
4190 }
4191 }
Mingyao Yang40bcb932016-02-03 05:46:57 -08004192
Vladimir Marko3224f382020-06-23 14:19:53 +01004193 assertIntEquals(testLoop1(new TestClass(), 0), 0);
4194 assertIntEquals(testLoop1(new TestClass(), 1), 0);
4195 assertIntEquals(testLoop1(new TestClass(), 2), 1);
4196 assertIntEquals(testLoop1(new TestClass(), 3), 2);
4197 assertIntEquals(testLoop2(new TestClass(), 0), 1);
4198 assertIntEquals(testLoop2(new TestClass(), 1), 1);
4199 assertIntEquals(testLoop2(new TestClass(), 2), 1);
4200 assertIntEquals(testLoop2(new TestClass(), 3), 1);
4201 assertIntEquals(testLoop3(new TestClass(), 0), 1);
4202 assertIntEquals(testLoop3(new TestClass(), 1), 1);
4203 assertIntEquals(testLoop3(new TestClass(), 2), 1);
4204 assertIntEquals(testLoop3(new TestClass(), 3), 1);
4205 assertIntEquals(testLoop4(new TestClass(), 0), 0);
4206 assertIntEquals(testLoop4(new TestClass(), 1), 1);
4207 assertIntEquals(testLoop4(new TestClass(), 2), 2);
4208 assertIntEquals(testLoop4(new TestClass(), 3), 3);
4209 assertIntEquals(testLoop5(new TestClass(), 0), 0);
4210 assertIntEquals(testLoop5(new TestClass(), 1), 1);
4211 assertIntEquals(testLoop5(new TestClass(), 2), 2);
4212 assertIntEquals(testLoop5(new TestClass(), 3), 3);
4213 assertIntEquals(testLoop6(new TestClass(), 0), 0);
4214 assertIntEquals(testLoop6(new TestClass(), 1), 1);
4215 assertIntEquals(testLoop6(new TestClass(), 2), 2);
4216 assertIntEquals(testLoop6(new TestClass(), 3), 3);
4217 assertIntEquals(testLoop7(0), 0);
4218 assertIntEquals(testLoop7(1), 0);
4219 assertIntEquals(testLoop7(2), 0);
4220 assertIntEquals(testLoop7(3), 0);
4221 assertIntEquals(testLoop8(0), 1);
4222 assertIntEquals(testLoop8(1), 0);
4223 assertIntEquals(testLoop8(2), 1);
4224 assertIntEquals(testLoop8(3), 0);
4225 assertIntEquals(testLoop9(new TestClass(), 0), 0);
4226 assertIntEquals(testLoop9(new TestClass(), 1), 1);
4227 assertIntEquals(testLoop9(new TestClass(), 2), 2);
4228 assertIntEquals(testLoop9(new TestClass(), 3), 3);
4229 assertIntEquals(testLoop10(new TestClass(), 0), 2);
4230 assertIntEquals(testLoop10(new TestClass(), 1), 2);
4231 assertIntEquals(testLoop10(new TestClass(), 2), 2);
4232 assertIntEquals(testLoop10(new TestClass(), 3), 2);
4233 assertIntEquals(testLoop11(new TestClass(), 0), 1);
4234 assertIntEquals(testLoop11(new TestClass(), 1), 3);
4235 assertIntEquals(testLoop11(new TestClass(), 2), 2);
4236 assertIntEquals(testLoop11(new TestClass(), 3), 3);
4237 assertIntEquals(testLoop12(new TestClass(), 0), 1);
4238 assertIntEquals(testLoop12(new TestClass(), 1), 2);
4239 assertIntEquals(testLoop12(new TestClass(), 2), 3);
4240 assertIntEquals(testLoop12(new TestClass(), 3), 2);
4241 assertIntEquals(testLoop13(new TestClass(1, 2), 0), 0);
4242 assertIntEquals(testLoop13(new TestClass(1, 2), 1), 0);
4243 assertIntEquals(testLoop13(new TestClass(1, 2), 2), 0);
4244 assertIntEquals(testLoop13(new TestClass(1, 2), 3), 1);
4245 assertIntEquals(testLoop14(new TestClass2(), 0), 0);
4246 assertIntEquals(testLoop14(new TestClass2(), 1), 0);
4247 assertIntEquals(testLoop14(new TestClass2(), 2), 0);
4248 assertIntEquals(testLoop14(new TestClass2(), 3), 1);
4249 assertIntEquals(testLoop15(0), 0);
4250 assertIntEquals(testLoop15(1), 1);
4251 assertIntEquals(testLoop15(2), 1);
4252 assertIntEquals(testLoop15(3), 1);
4253 assertIntEquals(testLoop16(new TestClass(), 0), 0);
4254 assertIntEquals(testLoop16(new TestClass(), 1), 1);
4255 assertIntEquals(testLoop16(new TestClass(), 2), 2);
4256 assertIntEquals(testLoop16(new TestClass(), 3), 3);
4257 assertIntEquals(testLoop17(new TestClass(), 0), 2);
4258 assertIntEquals(testLoop17(new TestClass(), 1), 4);
4259 assertIntEquals(testLoop17(new TestClass(), 2), 2);
4260 assertIntEquals(testLoop17(new TestClass(), 3), 4);
4261 assertIntEquals(testLoop18(new TestClass(), 0), 0);
4262 assertIntEquals(testLoop18(new TestClass(), 1), 1);
4263 assertIntEquals(testLoop18(new TestClass(), 2), 2);
4264 assertIntEquals(testLoop18(new TestClass(), 3), 3);
4265 assertIntEquals(testLoop19(new TestClass(), 0), 0);
4266 assertIntEquals(testLoop19(new TestClass(), 1), 1);
4267 assertIntEquals(testLoop19(new TestClass(), 2), 2);
4268 assertIntEquals(testLoop19(new TestClass(), 3), 3);
4269 assertIntEquals(testLoop20(new TestClass(), 0), 0);
4270 assertIntEquals(testLoop20(new TestClass(), 1), 1);
4271 assertIntEquals(testLoop20(new TestClass(), 2), 2);
4272 assertIntEquals(testLoop20(new TestClass(), 3), 3);
4273 assertIntEquals(testLoop21(new TestClass(), 0), 0);
4274 assertIntEquals(testLoop21(new TestClass(), 1), 1);
4275 assertIntEquals(testLoop21(new TestClass(), 2), 2);
4276 assertIntEquals(testLoop21(new TestClass(), 3), 3);
4277 assertIntEquals(testLoop22(new TestClass(), 0), 0);
4278 assertIntEquals(testLoop22(new TestClass(), 1), 1);
4279 assertIntEquals(testLoop22(new TestClass(), 2), 2);
4280 assertIntEquals(testLoop22(new TestClass(), 3), 3);
4281 assertIntEquals(testLoop23(new TestClass(), 0), -1);
4282 assertIntEquals(testLoop23(new TestClass(), 1), 2);
4283 assertIntEquals(testLoop23(new TestClass(), 2), 1);
4284 assertIntEquals(testLoop23(new TestClass(), 3), 2);
4285 assertIntEquals(testLoop24(new TestClass(), 0), -1);
4286 assertIntEquals(testLoop24(new TestClass(), 1), 2);
4287 assertIntEquals(testLoop24(new TestClass(), 2), 1);
4288 assertIntEquals(testLoop24(new TestClass(), 3), -2);
4289 assertIntEquals(testLoop25(new TestClass(), 0), 2);
4290 assertIntEquals(testLoop25(new TestClass(), 1), 2);
4291 assertIntEquals(testLoop25(new TestClass(), 2), 4);
4292 assertIntEquals(testLoop25(new TestClass(), 3), -1);
4293 assertIntEquals(testLoop26(new TestClass(), 0), 1);
4294 assertIntEquals(testLoop26(new TestClass(), 1), 0);
4295 assertIntEquals(testLoop26(new TestClass(), 2), 0);
4296 assertIntEquals(testLoop26(new TestClass(), 3), 0);
4297 assertIntEquals(testLoop27(new TestClass(), 0), 1);
4298 assertIntEquals(testLoop27(new TestClass(), 1), 1);
4299 assertIntEquals(testLoop27(new TestClass(), 2), 0);
4300 assertIntEquals(testLoop27(new TestClass(), 3), 0);
4301 assertIntEquals(testLoop28(new TestClass(1, 2), 0), 0);
4302 assertIntEquals(testLoop28(new TestClass(1, 2), 1), 0);
4303 assertIntEquals(testLoop28(new TestClass(1, 2), 2), 0);
4304 assertIntEquals(testLoop28(new TestClass(1, 2), 3), 1);
4305 assertIntEquals(testLoop29(0), 0);
4306 assertIntEquals(testLoop29(1), 1);
4307 assertIntEquals(testLoop29(2), 3);
4308 assertIntEquals(testLoop29(3), 6);
4309 assertIntEquals(testLoop30(0), 0);
4310 assertIntEquals(testLoop30(1), 1);
4311 assertIntEquals(testLoop30(2), 2);
4312 assertIntEquals(testLoop30(3), 3);
4313 assertIntEquals(testLoop31(0), 0);
4314 assertIntEquals(testLoop31(1), 0);
4315 assertIntEquals(testLoop31(2), 0);
4316 assertIntEquals(testLoop31(3), 0);
4317 assertIntEquals(testLoop32(new TestClass(), 0), -1);
4318 assertIntEquals(testLoop32(new TestClass(), 1), 2);
4319 assertIntEquals(testLoop32(new TestClass(), 2), 1);
4320 assertIntEquals(testLoop32(new TestClass(), 3), -2);
4321 assertIntEquals(testLoop33(new TestClass(), 0), 0);
4322 assertIntEquals(testLoop33(new TestClass(), 1), 0);
4323 assertIntEquals(testLoop33(new TestClass(), 2), 0);
4324 assertIntEquals(testLoop33(new TestClass(), 3), 0);
Vladimir Marko0571d472020-09-22 10:14:39 +01004325 assertIntEquals(testLoop34(0), 0);
4326 assertIntEquals(testLoop34(1), 1);
4327 assertIntEquals(testLoop34(2), 3);
4328 assertIntEquals(testLoop34(3), 6);
4329 assertIntEquals(testLoop35(0), 0);
4330 assertIntEquals(testLoop35(1), 1);
4331 assertIntEquals(testLoop35(2), 3);
4332 assertIntEquals(testLoop35(3), 6);
Vladimir Markodac82392021-05-10 15:44:24 +00004333 assertIntEquals(testLoop36(4), 6);
4334 assertIntEquals(testLoop37(4), 6);
4335 assertIntEquals(testLoop38(4, new int[4]), 0);
Vladimir Marko3224f382020-06-23 14:19:53 +01004336
4337 assertIntEquals(testNestedLoop1(new TestClass(), 0), 1);
4338 assertIntEquals(testNestedLoop1(new TestClass(), 1), 1);
4339 assertIntEquals(testNestedLoop1(new TestClass(), 2), 1);
4340 assertIntEquals(testNestedLoop1(new TestClass(), 3), 1);
4341 assertIntEquals(testNestedLoop2(new TestClass(), 0), 1);
4342 assertIntEquals(testNestedLoop2(new TestClass(), 1), 2);
4343 assertIntEquals(testNestedLoop2(new TestClass(), 2), 2);
4344 assertIntEquals(testNestedLoop2(new TestClass(), 3), 2);
4345 assertIntEquals(testNestedLoop3(new TestClass(), 0), 1);
4346 assertIntEquals(testNestedLoop3(new TestClass(), 1), 2);
4347 assertIntEquals(testNestedLoop3(new TestClass(), 2), 2);
4348 assertIntEquals(testNestedLoop3(new TestClass(), 3), 2);
4349 assertIntEquals(testNestedLoop4(new TestClass(), 0), 1);
4350 assertIntEquals(testNestedLoop4(new TestClass(), 1), 1);
4351 assertIntEquals(testNestedLoop4(new TestClass(), 2), 2);
4352 assertIntEquals(testNestedLoop4(new TestClass(), 3), 2);
4353 assertIntEquals(testNestedLoop5(new TestClass(), 0), 1);
4354 assertIntEquals(testNestedLoop5(new TestClass(), 1), 2);
4355 assertIntEquals(testNestedLoop5(new TestClass(), 2), 2);
4356 assertIntEquals(testNestedLoop5(new TestClass(), 3), 2);
4357 assertIntEquals(testNestedLoop6(new TestClass(), 0), 1);
4358 assertIntEquals(testNestedLoop6(new TestClass(), 1), 1);
4359 assertIntEquals(testNestedLoop6(new TestClass(), 2), 2);
4360 assertIntEquals(testNestedLoop6(new TestClass(), 3), 2);
4361 assertIntEquals(testNestedLoop7(new TestClass(), 0), 0);
4362 assertIntEquals(testNestedLoop7(new TestClass(), 1), 1);
4363 assertIntEquals(testNestedLoop7(new TestClass(), 2), 2);
4364 assertIntEquals(testNestedLoop7(new TestClass(), 3), 3);
4365 assertIntEquals(testNestedLoop8(new TestClass(), 0), 0);
4366 assertIntEquals(testNestedLoop8(new TestClass(), 1), 0);
4367 assertIntEquals(testNestedLoop8(new TestClass(), 2), 0);
4368 assertIntEquals(testNestedLoop8(new TestClass(), 3), 0);
Alex Light9dec90a2020-09-14 17:58:28 -07004369 assertLongEquals(testOverlapLoop(10), 34l);
4370 assertLongEquals(testOverlapLoop(50), 7778742049l);
Alex Light86fe9b82020-11-16 16:54:01 +00004371 assertIntEquals($noinline$testPartialEscape1(new TestClass(), true), 1);
4372 assertIntEquals($noinline$testPartialEscape1(new TestClass(), false), 0);
Vladimir Marko3224f382020-06-23 14:19:53 +01004373 }
Mingyao Yang8df69d42015-10-22 15:40:58 -07004374}