1 /*
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 
17 class Circle {
Circle(double radius)18   Circle(double radius) {
19     this.radius = radius;
20   }
getRadius()21   public double getRadius() {
22     return radius;
23   }
getArea()24   public double getArea() {
25     return radius * radius * Math.PI;
26   }
27   private double radius;
28 }
29 
30 class TestClass {
31   static {
32     sTestClassObj = new TestClass(-1, -2);
33   }
TestClass()34   TestClass() {
35   }
TestClass(int i, int j)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;
44   String str;
45   byte b;
46   static int si;
47   static TestClass sTestClassObj;
48 }
49 
50 class SubTestClass extends TestClass {
51   int k;
52 }
53 
54 class TestClass2 {
55   int i;
56   int j;
57 }
58 
59 class TestClass3 {
60   float floatField = 8.0f;
61   boolean test1 = true;
62 }
63 
64 class Finalizable {
65   static boolean sVisited = false;
66   static final int VALUE1 = 0xbeef;
67   static final int VALUE2 = 0xcafe;
68   int i;
69 
finalize()70   protected void finalize() {
71     if (i != VALUE1) {
72       System.out.println("Where is the beef?");
73     }
74     sVisited = true;
75   }
76 }
77 
78 interface Filter {
isValid(int i)79   public boolean isValid(int i);
80 }
81 
82 public class Main {
83 
84   /// CHECK-START: double Main.calcCircleArea(double) load_store_elimination (before)
85   /// CHECK: NewInstance
86   /// CHECK: InstanceFieldSet
87   /// CHECK: InstanceFieldGet
88 
89   /// CHECK-START: double Main.calcCircleArea(double) load_store_elimination (after)
90   /// CHECK-NOT: NewInstance
91   /// CHECK-NOT: InstanceFieldSet
92   /// CHECK-NOT: InstanceFieldGet
93 
calcCircleArea(double radius)94   static double calcCircleArea(double radius) {
95     return new Circle(radius).getArea();
96   }
97 
98   /// CHECK-START: int Main.test1(TestClass, TestClass) load_store_elimination (before)
99   /// CHECK: InstanceFieldSet
100   /// CHECK: InstanceFieldSet
101   /// CHECK: InstanceFieldGet
102   /// CHECK: InstanceFieldGet
103 
104   /// CHECK-START: int Main.test1(TestClass, TestClass) load_store_elimination (after)
105   /// CHECK: InstanceFieldSet
106   /// CHECK: InstanceFieldSet
107   /// CHECK-NOT: NullCheck
108   /// CHECK-NOT: InstanceFieldGet
109 
110   // Different fields shouldn't alias.
test1(TestClass obj1, TestClass obj2)111   static int test1(TestClass obj1, TestClass obj2) {
112     obj1.i = 1;
113     obj2.j = 2;
114     return obj1.i + obj2.j;
115   }
116 
117   /// CHECK-START: int Main.test2(TestClass) load_store_elimination (before)
118   /// CHECK: InstanceFieldSet
119   /// CHECK: InstanceFieldSet
120   /// CHECK: InstanceFieldGet
121 
122   /// CHECK-START: int Main.test2(TestClass) load_store_elimination (after)
123   /// CHECK: InstanceFieldSet
124   /// CHECK-NOT: NullCheck
125   /// CHECK-NOT: InstanceFieldSet
126   /// CHECK-NOT: InstanceFieldGet
127 
128   // Redundant store of the same value.
test2(TestClass obj)129   static int test2(TestClass obj) {
130     obj.j = 1;
131     obj.j = 1;
132     return obj.j;
133   }
134 
135   /// CHECK-START: int Main.test3(TestClass) load_store_elimination (before)
136   /// CHECK: StaticFieldGet
137   /// CHECK: NewInstance
138   /// CHECK: InstanceFieldSet
139   /// CHECK: InstanceFieldSet
140   /// CHECK: InstanceFieldSet
141   /// CHECK: InstanceFieldSet
142   /// CHECK: InstanceFieldGet
143   /// CHECK: InstanceFieldGet
144   /// CHECK: InstanceFieldGet
145   /// CHECK: InstanceFieldGet
146 
147   /// CHECK-START: int Main.test3(TestClass) load_store_elimination (after)
148   /// CHECK: StaticFieldGet
149   /// CHECK: NewInstance
150   /// CHECK: InstanceFieldSet
151   /// CHECK: InstanceFieldSet
152   /// CHECK: InstanceFieldSet
153   /// CHECK: InstanceFieldSet
154   /// CHECK-NOT: InstanceFieldGet
155   /// CHECK-NOT: StaticFieldGet
156 
157   // A new allocation (even non-singleton) shouldn't alias with pre-existing values.
test3(TestClass obj)158   static int test3(TestClass obj) {
159     TestClass obj1 = TestClass.sTestClassObj;
160     TestClass obj2 = new TestClass();  // Cannot alias with obj or obj1 which pre-exist.
161     obj.next = obj2;  // Make obj2 a non-singleton.
162     // All stores below need to stay since obj/obj1/obj2 are not singletons.
163     obj.i = 1;
164     obj1.j = 2;
165     // Following stores won't kill values of obj.i and obj1.j.
166     obj2.i = 3;
167     obj2.j = 4;
168     return obj.i + obj1.j + obj2.i + obj2.j;
169   }
170 
171   /// CHECK-START: int Main.test4(TestClass, boolean) load_store_elimination (before)
172   /// CHECK-DAG: InstanceFieldSet
173   /// CHECK-DAG: InstanceFieldSet
174   /// CHECK-DAG: InstanceFieldGet
175   /// CHECK-DAG: Return
176 
177   /// CHECK-START: int Main.test4(TestClass, boolean) load_store_elimination (after)
178   /// CHECK-DAG: InstanceFieldSet
179   /// CHECK-DAG: InstanceFieldSet
180   /// CHECK-DAG: Return
181 
182   /// CHECK-START: int Main.test4(TestClass, boolean) load_store_elimination (after)
183   /// CHECK:     NullCheck
184   /// CHECK:     NullCheck
185   /// CHECK-NOT: NullCheck
186 
187   /// CHECK-START: int Main.test4(TestClass, boolean) load_store_elimination (after)
188   /// CHECK-NOT: InstanceFieldGet
189 
190   // Set and merge the same value in two branches.
test4(TestClass obj, boolean b)191   static int test4(TestClass obj, boolean b) {
192     if (b) {
193       obj.i = 1;
194     } else {
195       obj.i = 1;
196     }
197     return obj.i;
198   }
199 
200   /// CHECK-START: int Main.test5(TestClass, boolean) load_store_elimination (before)
201   /// CHECK-DAG: InstanceFieldSet
202   /// CHECK-DAG: InstanceFieldSet
203   /// CHECK-DAG: InstanceFieldGet
204   /// CHECK-DAG: Return
205 
206   /// CHECK-START: int Main.test5(TestClass, boolean) load_store_elimination (after)
207   /// CHECK-DAG: InstanceFieldSet
208   /// CHECK-DAG: InstanceFieldSet
209   /// CHECK-DAG: InstanceFieldGet
210   /// CHECK-DAG: Return
211 
212   // Set and merge different values in two branches.
test5(TestClass obj, boolean b)213   static int test5(TestClass obj, boolean b) {
214     if (b) {
215       obj.i = 1;
216     } else {
217       obj.i = 2;
218     }
219     return obj.i;
220   }
221 
222   /// CHECK-START: int Main.test6(TestClass, TestClass, boolean) load_store_elimination (before)
223   /// CHECK: InstanceFieldSet
224   /// CHECK: InstanceFieldSet
225   /// CHECK: InstanceFieldSet
226   /// CHECK: InstanceFieldGet
227   /// CHECK: InstanceFieldGet
228 
229   /// CHECK-START: int Main.test6(TestClass, TestClass, boolean) load_store_elimination (after)
230   /// CHECK: InstanceFieldSet
231   /// CHECK: InstanceFieldSet
232   /// CHECK: InstanceFieldSet
233   /// CHECK: InstanceFieldGet
234   /// CHECK-NOT: NullCheck
235   /// CHECK-NOT: InstanceFieldGet
236 
237   // Setting the same value doesn't clear the value for aliased locations.
test6(TestClass obj1, TestClass obj2, boolean b)238   static int test6(TestClass obj1, TestClass obj2, boolean b) {
239     obj1.i = 1;
240     obj1.j = 2;
241     if (b) {
242       obj2.j = 2;
243     }
244     return obj1.j + obj2.j;
245   }
246 
247   /// CHECK-START: int Main.test7(TestClass) load_store_elimination (before)
248   /// CHECK: InstanceFieldSet
249   /// CHECK: InstanceFieldGet
250 
251   /// CHECK-START: int Main.test7(TestClass) load_store_elimination (after)
252   /// CHECK: InstanceFieldSet
253   /// CHECK: InstanceFieldGet
254 
255   // Invocation should kill values in non-singleton heap locations.
test7(TestClass obj)256   static int test7(TestClass obj) {
257     obj.i = 1;
258     System.out.print("");
259     return obj.i;
260   }
261 
262   /// CHECK-START: int Main.test8() load_store_elimination (before)
263   /// CHECK: NewInstance
264   /// CHECK: InstanceFieldSet
265   /// CHECK: InvokeVirtual
266   /// CHECK: InstanceFieldGet
267 
268   /// CHECK-START: int Main.test8() load_store_elimination (after)
269   /// CHECK-NOT: NewInstance
270   /// CHECK-NOT: InstanceFieldSet
271   /// CHECK: InvokeVirtual
272   /// CHECK-NOT: NullCheck
273   /// CHECK-NOT: InstanceFieldGet
274 
275   // Invocation should not kill values in singleton heap locations.
test8()276   static int test8() {
277     TestClass obj = new TestClass();
278     obj.i = 1;
279     System.out.print("");
280     return obj.i;
281   }
282 
283   /// CHECK-START: int Main.test9(TestClass) load_store_elimination (before)
284   /// CHECK: NewInstance
285   /// CHECK: InstanceFieldSet
286   /// CHECK: InstanceFieldSet
287   /// CHECK: InstanceFieldGet
288 
289   /// CHECK-START: int Main.test9(TestClass) load_store_elimination (after)
290   /// CHECK: NewInstance
291   /// CHECK: InstanceFieldSet
292   /// CHECK: InstanceFieldSet
293   /// CHECK: InstanceFieldGet
294 
295   // Invocation should kill values in non-singleton heap locations.
test9(TestClass obj)296   static int test9(TestClass obj) {
297     TestClass obj2 = new TestClass();
298     obj2.i = 1;
299     obj.next = obj2;
300     System.out.print("");
301     return obj2.i;
302   }
303 
304   /// CHECK-START: int Main.test10(TestClass) load_store_elimination (before)
305   /// CHECK-DAG: StaticFieldGet
306   /// CHECK-DAG: InstanceFieldGet
307   /// CHECK-DAG: StaticFieldSet
308   /// CHECK-DAG: InstanceFieldGet
309 
310   /// CHECK-START: int Main.test10(TestClass) load_store_elimination (after)
311   /// CHECK-DAG: StaticFieldGet
312   /// CHECK-DAG: InstanceFieldGet
313   /// CHECK-DAG: StaticFieldSet
314 
315   /// CHECK-START: int Main.test10(TestClass) load_store_elimination (after)
316   /// CHECK:     NullCheck
317   /// CHECK-NOT: NullCheck
318 
319   /// CHECK-START: int Main.test10(TestClass) load_store_elimination (after)
320   /// CHECK:     InstanceFieldGet
321   /// CHECK-NOT: InstanceFieldGet
322 
323   // Static fields shouldn't alias with instance fields.
test10(TestClass obj)324   static int test10(TestClass obj) {
325     TestClass.si += obj.i;
326     return obj.i;
327   }
328 
329   /// CHECK-START: int Main.test11(TestClass) load_store_elimination (before)
330   /// CHECK: InstanceFieldSet
331   /// CHECK: InstanceFieldGet
332 
333   /// CHECK-START: int Main.test11(TestClass) load_store_elimination (after)
334   /// CHECK: InstanceFieldSet
335   /// CHECK-NOT: NullCheck
336   /// CHECK-NOT: InstanceFieldGet
337 
338   // Loop without heap writes.
339   // obj.i is actually hoisted to the loop pre-header by licm already.
test11(TestClass obj)340   static int test11(TestClass obj) {
341     obj.i = 1;
342     int sum = 0;
343     for (int i = 0; i < 10; i++) {
344       sum += obj.i;
345     }
346     return sum;
347   }
348 
349   /// CHECK-START: int Main.test12(TestClass, TestClass) load_store_elimination (before)
350   /// CHECK: InstanceFieldSet
351   /// CHECK: InstanceFieldGet
352   /// CHECK: InstanceFieldSet
353 
354   /// CHECK-START: int Main.test12(TestClass, TestClass) load_store_elimination (after)
355   /// CHECK: InstanceFieldSet
356   /// CHECK: InstanceFieldGet
357   /// CHECK: InstanceFieldSet
358 
359   // Loop with heap writes.
test12(TestClass obj1, TestClass obj2)360   static int test12(TestClass obj1, TestClass obj2) {
361     obj1.i = 1;
362     int sum = 0;
363     for (int i = 0; i < 10; i++) {
364       sum += obj1.i;
365       obj2.i = sum;
366     }
367     return sum;
368   }
369 
370   /// CHECK-START: int Main.test13(TestClass, TestClass2) load_store_elimination (before)
371   /// CHECK: InstanceFieldSet
372   /// CHECK: InstanceFieldSet
373   /// CHECK: InstanceFieldGet
374   /// CHECK: InstanceFieldGet
375 
376   /// CHECK-START: int Main.test13(TestClass, TestClass2) load_store_elimination (after)
377   /// CHECK: InstanceFieldSet
378   /// CHECK: InstanceFieldSet
379   /// CHECK-NOT: NullCheck
380   /// CHECK-NOT: InstanceFieldGet
381 
382   // Different classes shouldn't alias.
test13(TestClass obj1, TestClass2 obj2)383   static int test13(TestClass obj1, TestClass2 obj2) {
384     obj1.i = 1;
385     obj2.i = 2;
386     return obj1.i + obj2.i;
387   }
388 
389   /// CHECK-START: int Main.test14(TestClass, SubTestClass) load_store_elimination (before)
390   /// CHECK: InstanceFieldSet
391   /// CHECK: InstanceFieldSet
392   /// CHECK: InstanceFieldGet
393 
394   /// CHECK-START: int Main.test14(TestClass, SubTestClass) load_store_elimination (after)
395   /// CHECK: InstanceFieldSet
396   /// CHECK: InstanceFieldSet
397   /// CHECK: InstanceFieldGet
398 
399   // Subclass may alias with super class.
test14(TestClass obj1, SubTestClass obj2)400   static int test14(TestClass obj1, SubTestClass obj2) {
401     obj1.i = 1;
402     obj2.i = 2;
403     return obj1.i;
404   }
405 
406   /// CHECK-START: int Main.test15() load_store_elimination (before)
407   /// CHECK: StaticFieldSet
408   /// CHECK: StaticFieldSet
409   /// CHECK: StaticFieldGet
410 
411   /// CHECK-START: int Main.test15() load_store_elimination (after)
412   /// CHECK: <<Const2:i\d+>> IntConstant 2
413   /// CHECK: StaticFieldSet
414   /// CHECK-NOT: StaticFieldGet
415   /// CHECK: Return [<<Const2>>]
416 
417   // Static field access from subclass's name.
test15()418   static int test15() {
419     TestClass.si = 1;
420     SubTestClass.si = 2;
421     return TestClass.si;
422   }
423 
424   /// CHECK-START: int Main.test16() load_store_elimination (before)
425   /// CHECK: NewInstance
426   /// CHECK: InstanceFieldSet
427   /// CHECK: InstanceFieldSet
428   /// CHECK: InstanceFieldGet
429   /// CHECK: InstanceFieldGet
430 
431   /// CHECK-START: int Main.test16() load_store_elimination (after)
432   /// CHECK-NOT: NewInstance
433   /// CHECK-NOT: InstanceFieldSet
434   /// CHECK-NOT: InstanceFieldGet
435 
436   // Test inlined constructor.
test16()437   static int test16() {
438     TestClass obj = new TestClass(1, 2);
439     return obj.i + obj.j;
440   }
441 
442   /// CHECK-START: int Main.test17() load_store_elimination (before)
443   /// CHECK: NewInstance
444   /// CHECK: InstanceFieldSet
445   /// CHECK: InstanceFieldGet
446 
447   /// CHECK-START: int Main.test17() load_store_elimination (after)
448   /// CHECK: <<Const0:i\d+>> IntConstant 0
449   /// CHECK-NOT: NewInstance
450   /// CHECK-NOT: InstanceFieldSet
451   /// CHECK-NOT: InstanceFieldGet
452   /// CHECK: Return [<<Const0>>]
453 
454   // Test getting default value.
test17()455   static int test17() {
456     TestClass obj = new TestClass();
457     obj.j = 1;
458     return obj.i;
459   }
460 
461   /// CHECK-START: int Main.test18(TestClass) load_store_elimination (before)
462   /// CHECK: InstanceFieldSet
463   /// CHECK: InstanceFieldGet
464 
465   /// CHECK-START: int Main.test18(TestClass) load_store_elimination (after)
466   /// CHECK: InstanceFieldSet
467   /// CHECK: InstanceFieldGet
468 
469   // Volatile field load/store shouldn't be eliminated.
test18(TestClass obj)470   static int test18(TestClass obj) {
471     obj.k = 1;
472     return obj.k;
473   }
474 
475   /// CHECK-START: float Main.test19(float[], float[]) load_store_elimination (before)
476   /// CHECK:     {{f\d+}} ArrayGet
477   /// CHECK:     {{f\d+}} ArrayGet
478 
479   /// CHECK-START: float Main.test19(float[], float[]) load_store_elimination (after)
480   /// CHECK:     {{f\d+}} ArrayGet
481   /// CHECK-NOT: {{f\d+}} ArrayGet
482 
483   // I/F, J/D aliasing should not happen any more and LSE should eliminate the load.
test19(float[] fa1, float[] fa2)484   static float test19(float[] fa1, float[] fa2) {
485     fa1[0] = fa2[0];
486     return fa1[0];
487   }
488 
489   /// CHECK-START: TestClass Main.test20() load_store_elimination (before)
490   /// CHECK: NewInstance
491   /// CHECK: InstanceFieldSet
492 
493   /// CHECK-START: TestClass Main.test20() load_store_elimination (after)
494   /// CHECK: NewInstance
495   /// CHECK-NOT: InstanceFieldSet
496 
497   // Storing default heap value is redundant if the heap location has the
498   // default heap value.
test20()499   static TestClass test20() {
500     TestClass obj = new TestClass();
501     obj.i = 0;
502     return obj;
503   }
504 
505   /// CHECK-START: void Main.test21(TestClass) load_store_elimination (before)
506   /// CHECK: NewInstance
507   /// CHECK: InstanceFieldSet
508   /// CHECK: InstanceFieldSet
509   /// CHECK: InstanceFieldSet
510   /// CHECK: InstanceFieldGet
511   /// CHECK: InstanceFieldGet
512 
513   /// CHECK-START: void Main.test21(TestClass) load_store_elimination (after)
514   /// CHECK: NewInstance
515   /// CHECK: InstanceFieldSet
516   /// CHECK: InstanceFieldSet
517   /// CHECK: InstanceFieldSet
518   /// CHECK: InstanceFieldGet
519   /// CHECK: InstanceFieldGet
520 
521   // Loop side effects can kill heap values, stores need to be kept in that case.
test21(TestClass obj0)522   static void test21(TestClass obj0) {
523     TestClass obj = new TestClass();
524     obj0.str = "abc";
525     obj.str = "abc";
526     for (int i = 0; i < 2; i++) {
527       // Generate some loop side effect that writes into obj.
528       obj.str = "def";
529     }
530     System.out.print(obj0.str.substring(0, 0) + obj.str.substring(0, 0));
531   }
532 
533   /// CHECK-START: int Main.test22() load_store_elimination (before)
534   /// CHECK: NewInstance
535   /// CHECK: InstanceFieldSet
536   /// CHECK: NewInstance
537   /// CHECK: InstanceFieldSet
538   /// CHECK: InstanceFieldGet
539   /// CHECK: NewInstance
540   /// CHECK: InstanceFieldSet
541   /// CHECK: InstanceFieldGet
542   /// CHECK: InstanceFieldGet
543 
544   /// CHECK-START: int Main.test22() load_store_elimination (after)
545   /// CHECK-NOT: NewInstance
546   /// CHECK-NOT: InstanceFieldSet
547   /// CHECK-NOT: NewInstance
548   /// CHECK-NOT: InstanceFieldSet
549   /// CHECK-NOT: InstanceFieldGet
550   /// CHECK-NOT: NewInstance
551   /// CHECK-NOT: InstanceFieldSet
552   /// CHECK-NOT: InstanceFieldGet
553   /// CHECK-NOT: InstanceFieldGet
554 
555   // For a singleton, loop side effects can kill its field values only if:
556   // (1) it dominiates the loop header, and
557   // (2) its fields are stored into inside a loop.
test22()558   static int test22() {
559     int sum = 0;
560     TestClass obj1 = new TestClass();
561     obj1.i = 2;    // This store can be eliminated since obj1 is never stored into inside a loop.
562     for (int i = 0; i < 2; i++) {
563       TestClass obj2 = new TestClass();
564       obj2.i = 3;  // This store can be eliminated since the singleton is inside the loop.
565       sum += obj2.i;
566     }
567     TestClass obj3 = new TestClass();
568     obj3.i = 5;    // This store can be eliminated since the singleton is created after the loop.
569     sum += obj1.i + obj3.i;
570     return sum;
571   }
572 
573   /// CHECK-START: int Main.test23(boolean) load_store_elimination (before)
574   /// CHECK-DAG: NewInstance
575   /// CHECK-DAG: InstanceFieldSet
576   /// CHECK-DAG: InstanceFieldGet
577   /// CHECK-DAG: InstanceFieldSet
578   /// CHECK-DAG: InstanceFieldGet
579   /// CHECK-DAG: InstanceFieldSet
580   /// CHECK-DAG: InstanceFieldGet
581   /// CHECK-DAG: Return
582 
583   /// CHECK-START: int Main.test23(boolean) load_store_elimination (after)
584   /// CHECK-DAG: NewInstance
585   /// CHECK-DAG: InstanceFieldSet
586   /// CHECK-DAG: InstanceFieldSet
587   /// CHECK-DAG: InstanceFieldGet
588   /// CHECK-DAG: Return
589 
590   /// CHECK-START: int Main.test23(boolean) load_store_elimination (after)
591   /// CHECK:     InstanceFieldSet
592   /// CHECK:     InstanceFieldSet
593   /// CHECK-NOT: InstanceFieldSet
594 
595   /// CHECK-START: int Main.test23(boolean) load_store_elimination (after)
596   /// CHECK: InstanceFieldGet
597   /// CHECK-NOT: InstanceFieldGet
598 
599   /// CHECK-START: int Main.test23(boolean) load_store_elimination (after)
600   /// CHECK-DAG: <<Get:i\d+>> InstanceFieldGet
601   /// CHECK-DAG: Return [<<Get>>]
602 
603   // Test store elimination on merging.
test23(boolean b)604   static int test23(boolean b) {
605     TestClass obj = new TestClass();
606     obj.i = 3;      // This store can be eliminated since the value flows into each branch.
607     if (b) {
608       obj.i += 1;   // This store cannot be eliminated due to the merge later.
609     } else {
610       obj.i += 2;   // This store cannot be eliminated due to the merge later.
611     }
612     return obj.i;
613   }
614 
615   /// CHECK-START: float Main.test24() load_store_elimination (before)
616   /// CHECK-DAG:     <<True:i\d+>>     IntConstant 1
617   /// CHECK-DAG:     <<Float8:f\d+>>   FloatConstant 8
618   /// CHECK-DAG:     <<Float42:f\d+>>  FloatConstant 42
619   /// CHECK-DAG:     <<Obj:l\d+>>      NewInstance
620   /// CHECK-DAG:                       InstanceFieldSet [<<Obj>>,<<True>>]
621   /// CHECK-DAG:                       InstanceFieldSet [<<Obj>>,<<Float8>>]
622   /// CHECK-DAG:     <<GetTest:z\d+>>  InstanceFieldGet [<<Obj>>]
623   /// CHECK-DAG:     <<GetField:f\d+>> InstanceFieldGet [<<Obj>>]
624   /// CHECK-DAG:     <<Select:f\d+>>   Select [<<Float42>>,<<GetField>>,<<GetTest>>]
625   /// CHECK-DAG:                       Return [<<Select>>]
626 
627   /// CHECK-START: float Main.test24() load_store_elimination (after)
628   /// CHECK-DAG:     <<True:i\d+>>     IntConstant 1
629   /// CHECK-DAG:     <<Float8:f\d+>>   FloatConstant 8
630   /// CHECK-DAG:     <<Float42:f\d+>>  FloatConstant 42
631   /// CHECK-DAG:     <<Select:f\d+>>   Select [<<Float42>>,<<Float8>>,<<True>>]
632   /// CHECK-DAG:                       Return [<<Select>>]
633 
test24()634   static float test24() {
635     float a = 42.0f;
636     TestClass3 obj = new TestClass3();
637     if (obj.test1) {
638       a = obj.floatField;
639     }
640     return a;
641   }
642 
643   /// CHECK-START: int Main.$noinline$testConversion1(TestClass, int) load_store_elimination (before)
644   /// CHECK-DAG:                     InstanceFieldSet
645   /// CHECK-DAG:                     InstanceFieldSet
646   /// CHECK-DAG:                     InstanceFieldGet
647   /// CHECK-DAG:                     InstanceFieldSet
648   /// CHECK-DAG:                     InstanceFieldGet
649 
650   /// CHECK-START: int Main.$noinline$testConversion1(TestClass, int) load_store_elimination (after)
651   /// CHECK-DAG:                     InstanceFieldSet
652   /// CHECK-DAG:                     InstanceFieldSet
653   /// CHECK-DAG:                     TypeConversion
654   /// CHECK-DAG:                     InstanceFieldSet
655   /// CHECK-DAG:                     InstanceFieldGet
$noinline$testConversion1(TestClass obj, int x)656   static int $noinline$testConversion1(TestClass obj, int x) {
657     obj.i = x;
658     if ((x & 1) != 0) {
659       obj.b = (byte) x;
660       obj.i = obj.b;
661     }
662     return obj.i;
663   }
664 
665   /// CHECK-START: int Main.$noinline$testConversion2(TestClass, int) load_store_elimination (before)
666   /// CHECK-DAG:                     InstanceFieldSet
667   /// CHECK-DAG:                     InstanceFieldSet
668   /// CHECK-DAG:                     InstanceFieldGet
669   /// CHECK-DAG:                     InstanceFieldSet
670   /// CHECK-DAG:                     InstanceFieldGet
671 
672   /// CHECK-START: int Main.$noinline$testConversion2(TestClass, int) load_store_elimination (after)
673   /// CHECK-DAG:                     InstanceFieldSet
674   /// CHECK-DAG:                     InstanceFieldSet
675   /// CHECK-DAG:                     TypeConversion
676   /// CHECK-DAG:                     InstanceFieldSet
677   /// CHECK-DAG:                     InstanceFieldGet
678 
679   /// CHECK-START: int Main.$noinline$testConversion2(TestClass, int) load_store_elimination (after)
680   /// CHECK:                         TypeConversion
681   /// CHECK-NOT:                     TypeConversion
$noinline$testConversion2(TestClass obj, int x)682   static int $noinline$testConversion2(TestClass obj, int x) {
683     int tmp = 0;
684     obj.i = x;
685     if ((x & 1) != 0) {
686       // The instruction simplifier can remove this TypeConversion if there are
687       // no environment uses. Currently, there is an environment use in NullCheck,
688       // so this TypeConversion remains and GVN removes the second TypeConversion
689       // below. Since we really want to test that the TypeConversion from below
690       // can be moved and used for the load of `obj.b`, we have a similar test
691       // written in smali in 530-checker-lse3, StoreLoad.test3(int), except that
692       // it's using static fields (which would not help with the environment use).
693       obj.b = (byte) x;
694       obj.i = obj.b;
695       tmp = (byte) x;
696     }
697     return obj.i + tmp;
698   }
699 
700   /// CHECK-START: void Main.testFinalizable() load_store_elimination (before)
701   /// CHECK: NewInstance
702   /// CHECK: InstanceFieldSet
703   /// CHECK: InstanceFieldSet
704 
705   /// CHECK-START: void Main.testFinalizable() load_store_elimination (after)
706   /// CHECK: NewInstance
707   /// CHECK: InstanceFieldSet
708   /// CHECK-NOT: InstanceFieldSet
709 
710   // Allocations of finalizable objects cannot be eliminated.
testFinalizable()711   static void testFinalizable() {
712     Finalizable finalizable = new Finalizable();
713     finalizable.i = Finalizable.VALUE2;
714     finalizable.i = Finalizable.VALUE1;
715   }
716 
getWeakReference()717   static java.lang.ref.WeakReference<Object> getWeakReference() {
718     return new java.lang.ref.WeakReference<>(new Object());
719   }
720 
testFinalizableByForcingGc()721   static void testFinalizableByForcingGc() {
722     testFinalizable();
723     java.lang.ref.WeakReference<Object> reference = getWeakReference();
724 
725     Runtime runtime = Runtime.getRuntime();
726     for (int i = 0; i < 20; ++i) {
727       runtime.gc();
728       System.runFinalization();
729       try {
730         Thread.sleep(1);
731       } catch (InterruptedException e) {
732         throw new AssertionError(e);
733       }
734 
735       // Check to see if the weak reference has been garbage collected.
736       if (reference.get() == null) {
737         // A little bit more sleep time to make sure.
738         try {
739           Thread.sleep(100);
740         } catch (InterruptedException e) {
741           throw new AssertionError(e);
742         }
743         if (!Finalizable.sVisited) {
744           System.out.println("finalize() not called.");
745         }
746         return;
747       }
748     }
749     System.out.println("testFinalizableByForcingGc() failed to force gc.");
750   }
751 
752   /// CHECK-START: int Main.$noinline$testHSelect(boolean) load_store_elimination (before)
753   /// CHECK: InstanceFieldSet
754   /// CHECK: Select
755 
756   /// CHECK-START: int Main.$noinline$testHSelect(boolean) load_store_elimination (after)
757   /// CHECK: InstanceFieldSet
758   /// CHECK: Select
759 
760   // Test that HSelect creates alias.
$noinline$testHSelect(boolean b)761   static int $noinline$testHSelect(boolean b) {
762     if (sFlag) {
763       throw new Error();
764     }
765     TestClass obj = new TestClass();
766     TestClass obj2 = null;
767     obj.i = 0xdead;
768     if (b) {
769       obj2 = obj;
770     }
771     return obj2.i;
772   }
773 
sumWithFilter(int[] array, Filter f)774   static int sumWithFilter(int[] array, Filter f) {
775     int sum = 0;
776     for (int i = 0; i < array.length; i++) {
777       if (f.isValid(array[i])) {
778         sum += array[i];
779       }
780     }
781     return sum;
782   }
783 
784   /// CHECK-START: int Main.sumWithinRange(int[], int, int) load_store_elimination (before)
785   /// CHECK: NewInstance
786   /// CHECK: InstanceFieldSet
787   /// CHECK: InstanceFieldSet
788   /// CHECK: InstanceFieldGet
789   /// CHECK: InstanceFieldGet
790 
791   /// CHECK-START: int Main.sumWithinRange(int[], int, int) load_store_elimination (after)
792   /// CHECK-NOT: NewInstance
793   /// CHECK-NOT: InstanceFieldSet
794   /// CHECK-NOT: InstanceFieldGet
795 
796   // A lambda-style allocation can be eliminated after inlining.
sumWithinRange(int[] array, final int low, final int high)797   static int sumWithinRange(int[] array, final int low, final int high) {
798     Filter filter = new Filter() {
799       public boolean isValid(int i) {
800         return (i >= low) && (i <= high);
801       }
802     };
803     return sumWithFilter(array, filter);
804   }
805 
806   private static int mI = 0;
807   private static float mF = 0f;
808 
809   /// CHECK-START: float Main.testAllocationEliminationWithLoops() load_store_elimination (before)
810   /// CHECK: NewInstance
811   /// CHECK: NewInstance
812   /// CHECK: NewInstance
813 
814   /// CHECK-START: float Main.testAllocationEliminationWithLoops() load_store_elimination (after)
815   /// CHECK-NOT: NewInstance
816 
testAllocationEliminationWithLoops()817   private static float testAllocationEliminationWithLoops() {
818     for (int i0 = 0; i0 < 5; i0++) {
819       for (int i1 = 0; i1 < 5; i1++) {
820         for (int i2 = 0; i2 < 5; i2++) {
821           int lI0 = ((int) new Integer(((int) new Integer(mI))));
822           if (((boolean) new Boolean(false))) {
823             for (int i3 = 576 - 1; i3 >= 0; i3--) {
824               mF -= 976981405.0f;
825             }
826           }
827         }
828       }
829     }
830     return 1.0f;
831   }
832 
833   /// CHECK-START: TestClass2 Main.testStoreStore() load_store_elimination (before)
834   /// CHECK: NewInstance
835   /// CHECK: InstanceFieldSet
836   /// CHECK: InstanceFieldSet
837   /// CHECK: InstanceFieldSet
838   /// CHECK: InstanceFieldSet
839 
840   /// CHECK-START: TestClass2 Main.testStoreStore() load_store_elimination (after)
841   /// CHECK: NewInstance
842   /// CHECK: InstanceFieldSet
843   /// CHECK: InstanceFieldSet
844   /// CHECK-NOT: InstanceFieldSet
845 
testStoreStore()846   private static TestClass2 testStoreStore() {
847     TestClass2 obj = new TestClass2();
848     obj.i = 41;
849     obj.j = 42;
850     obj.i = 41;
851     obj.j = 43;
852     return obj;
853   }
854 
855   /// CHECK-START: void Main.testStoreStore2(TestClass2) load_store_elimination (before)
856   /// CHECK: InstanceFieldSet
857   /// CHECK: InstanceFieldSet
858   /// CHECK: InstanceFieldSet
859   /// CHECK: InstanceFieldSet
860 
861   /// CHECK-START: void Main.testStoreStore2(TestClass2) load_store_elimination (after)
862   /// CHECK: InstanceFieldSet
863   /// CHECK: InstanceFieldSet
864   /// CHECK-NOT: InstanceFieldSet
865 
testStoreStore2(TestClass2 obj)866   private static void testStoreStore2(TestClass2 obj) {
867     obj.i = 41;
868     obj.j = 42;
869     obj.i = 43;
870     obj.j = 44;
871   }
872 
873   /// CHECK-START: void Main.testStoreStore3(TestClass2, boolean) load_store_elimination (before)
874   /// CHECK: InstanceFieldSet
875   /// CHECK: InstanceFieldSet
876   /// CHECK: InstanceFieldSet
877   /// CHECK: InstanceFieldSet
878 
879   /// CHECK-START: void Main.testStoreStore3(TestClass2, boolean) load_store_elimination (after)
880   /// CHECK: InstanceFieldSet
881   /// CHECK: InstanceFieldSet
882   /// CHECK: InstanceFieldSet
883   /// CHECK-NOT: InstanceFieldSet
884 
testStoreStore3(TestClass2 obj, boolean flag)885   private static void testStoreStore3(TestClass2 obj, boolean flag) {
886     obj.i = 41;
887     obj.j = 42;    // redundant since it's overwritten in both branches below.
888     if (flag) {
889       obj.j = 43;
890     } else {
891       obj.j = 44;
892     }
893   }
894 
895   /// CHECK-START: void Main.testStoreStore4() load_store_elimination (before)
896   /// CHECK: StaticFieldSet
897   /// CHECK: StaticFieldSet
898 
899   /// CHECK-START: void Main.testStoreStore4() load_store_elimination (after)
900   /// CHECK: StaticFieldSet
901   /// CHECK-NOT: StaticFieldSet
902 
testStoreStore4()903   private static void testStoreStore4() {
904     TestClass.si = 61;
905     TestClass.si = 62;
906   }
907 
908   /// CHECK-START: int Main.testStoreStore5(TestClass2, TestClass2) load_store_elimination (before)
909   /// CHECK: InstanceFieldSet
910   /// CHECK: InstanceFieldGet
911   /// CHECK: InstanceFieldSet
912 
913   /// CHECK-START: int Main.testStoreStore5(TestClass2, TestClass2) load_store_elimination (after)
914   /// CHECK: InstanceFieldSet
915   /// CHECK: InstanceFieldGet
916   /// CHECK: InstanceFieldSet
917 
testStoreStore5(TestClass2 obj1, TestClass2 obj2)918   private static int testStoreStore5(TestClass2 obj1, TestClass2 obj2) {
919     obj1.i = 71;      // This store is needed since obj2.i may load from it.
920     int i = obj2.i;
921     obj1.i = 72;
922     return i;
923   }
924 
925   /// CHECK-START: int Main.testStoreStore6(TestClass2, TestClass2) load_store_elimination (before)
926   /// CHECK: InstanceFieldSet
927   /// CHECK: InstanceFieldGet
928   /// CHECK: InstanceFieldSet
929 
930   /// CHECK-START: int Main.testStoreStore6(TestClass2, TestClass2) load_store_elimination (after)
931   /// CHECK-NOT: InstanceFieldSet
932   /// CHECK: InstanceFieldGet
933   /// CHECK: InstanceFieldSet
934 
testStoreStore6(TestClass2 obj1, TestClass2 obj2)935   private static int testStoreStore6(TestClass2 obj1, TestClass2 obj2) {
936     obj1.i = 81;      // This store is not needed since obj2.j cannot load from it.
937     int j = obj2.j;
938     obj1.i = 82;
939     return j;
940   }
941 
942   /// CHECK-START: int Main.testNoSideEffects(int[]) load_store_elimination (before)
943   /// CHECK: ArraySet
944   /// CHECK: ArraySet
945   /// CHECK: ArraySet
946   /// CHECK: ArrayGet
947 
948   /// CHECK-START: int Main.testNoSideEffects(int[]) load_store_elimination (after)
949   /// CHECK: ArraySet
950   /// CHECK: ArraySet
951   /// CHECK-NOT: ArraySet
952   /// CHECK-NOT: ArrayGet
953 
testNoSideEffects(int[] array)954   private static int testNoSideEffects(int[] array) {
955     array[0] = 101;
956     array[1] = 102;
957     int bitCount = Integer.bitCount(0x3456);
958     array[1] = 103;
959     return array[0] + bitCount;
960   }
961 
962   /// CHECK-START: void Main.testThrow(TestClass2, java.lang.Exception) load_store_elimination (before)
963   /// CHECK: InstanceFieldSet
964   /// CHECK: Throw
965 
966   /// CHECK-START: void Main.testThrow(TestClass2, java.lang.Exception) load_store_elimination (after)
967   /// CHECK: InstanceFieldSet
968   /// CHECK: Throw
969 
970   // Make sure throw keeps the store.
testThrow(TestClass2 obj, Exception e)971   private static void testThrow(TestClass2 obj, Exception e) throws Exception {
972     obj.i = 55;
973     throw e;
974   }
975 
976   /// CHECK-START: int Main.testStoreStoreWithDeoptimize(int[]) load_store_elimination (before)
977   /// CHECK: NewInstance
978   /// CHECK: InstanceFieldSet
979   /// CHECK: InstanceFieldSet
980   /// CHECK: InstanceFieldSet
981   /// CHECK: InstanceFieldSet
982   /// CHECK: Deoptimize
983   /// CHECK: ArraySet
984   /// CHECK: ArraySet
985   /// CHECK: ArraySet
986   /// CHECK: ArraySet
987   /// CHECK: ArrayGet
988   /// CHECK: ArrayGet
989   /// CHECK: ArrayGet
990   /// CHECK: ArrayGet
991 
992   /// CHECK-START: int Main.testStoreStoreWithDeoptimize(int[]) load_store_elimination (after)
993   /// CHECK: NewInstance
994   /// CHECK: InstanceFieldSet
995   /// CHECK: InstanceFieldSet
996   /// CHECK-NOT: InstanceFieldSet
997   /// CHECK: Deoptimize
998   /// CHECK: ArraySet
999   /// CHECK: ArraySet
1000   /// CHECK: ArraySet
1001   /// CHECK: ArraySet
1002   /// CHECK-NOT: ArrayGet
1003 
testStoreStoreWithDeoptimize(int[] arr)1004   private static int testStoreStoreWithDeoptimize(int[] arr) {
1005     TestClass2 obj = new TestClass2();
1006     obj.i = 41;
1007     obj.j = 42;
1008     obj.i = 41;
1009     obj.j = 43;
1010     arr[0] = 1;  // One HDeoptimize here.
1011     arr[1] = 1;
1012     arr[2] = 1;
1013     arr[3] = 1;
1014     return arr[0] + arr[1] + arr[2] + arr[3];
1015   }
1016 
1017   /// CHECK-START: double Main.getCircleArea(double, boolean) load_store_elimination (before)
1018   /// CHECK: NewInstance
1019 
1020   /// CHECK-START: double Main.getCircleArea(double, boolean) load_store_elimination (after)
1021   /// CHECK-NOT: NewInstance
1022 
getCircleArea(double radius, boolean b)1023   private static double getCircleArea(double radius, boolean b) {
1024     double area = 0d;
1025     if (b) {
1026       area = new Circle(radius).getArea();
1027     }
1028     return area;
1029   }
1030 
1031   /// CHECK-START: double Main.testDeoptimize(int[], double[], double) load_store_elimination (before)
1032   /// CHECK: Deoptimize
1033   /// CHECK: NewInstance
1034   /// CHECK: Deoptimize
1035   /// CHECK: NewInstance
1036 
1037   /// CHECK-START: double Main.testDeoptimize(int[], double[], double) load_store_elimination (after)
1038   /// CHECK: Deoptimize
1039   /// CHECK: NewInstance
1040   /// CHECK: Deoptimize
1041   /// CHECK-NOT: NewInstance
1042 
testDeoptimize(int[] iarr, double[] darr, double radius)1043   private static double testDeoptimize(int[] iarr, double[] darr, double radius) {
1044     iarr[0] = 1;  // One HDeoptimize here. Not triggered.
1045     iarr[1] = 1;
1046     Circle circle1 = new Circle(radius);
1047     iarr[2] = 1;
1048     darr[0] = circle1.getRadius();  // One HDeoptimize here, which holds circle1 live. Triggered.
1049     darr[1] = circle1.getRadius();
1050     darr[2] = circle1.getRadius();
1051     darr[3] = circle1.getRadius();
1052     return new Circle(Math.PI).getArea();
1053   }
1054 
1055   /// CHECK-START: int Main.testAllocationEliminationOfArray1() load_store_elimination (before)
1056   /// CHECK: NewArray
1057   /// CHECK: ArraySet
1058   /// CHECK: ArraySet
1059   /// CHECK: ArrayGet
1060   /// CHECK: ArrayGet
1061   /// CHECK: ArrayGet
1062   /// CHECK: ArrayGet
1063 
1064   /// CHECK-START: int Main.testAllocationEliminationOfArray1() load_store_elimination (after)
1065   /// CHECK-NOT: NewArray
1066   /// CHECK-NOT: ArraySet
1067   /// CHECK-NOT: ArrayGet
testAllocationEliminationOfArray1()1068   private static int testAllocationEliminationOfArray1() {
1069     int[] array = new int[4];
1070     array[2] = 4;
1071     array[3] = 7;
1072     return array[0] + array[1] + array[2] + array[3];
1073   }
1074 
1075   /// CHECK-START: int Main.testAllocationEliminationOfArray2() load_store_elimination (before)
1076   /// CHECK: NewArray
1077   /// CHECK: ArraySet
1078   /// CHECK: ArraySet
1079   /// CHECK: ArrayGet
1080 
1081   /// CHECK-START: int Main.testAllocationEliminationOfArray2() load_store_elimination (after)
1082   /// CHECK: NewArray
1083   /// CHECK: ArraySet
1084   /// CHECK: ArraySet
1085   /// CHECK: ArrayGet
testAllocationEliminationOfArray2()1086   private static int testAllocationEliminationOfArray2() {
1087     // Cannot eliminate array allocation since array is accessed with non-constant
1088     // index (only 3 elements to prevent vectorization of the reduction).
1089     int[] array = new int[3];
1090     array[1] = 4;
1091     array[2] = 7;
1092     int sum = 0;
1093     for (int e : array) {
1094       sum += e;
1095     }
1096     return sum;
1097   }
1098 
1099   /// CHECK-START: int Main.testAllocationEliminationOfArray3(int) load_store_elimination (before)
1100   /// CHECK: NewArray
1101   /// CHECK: ArraySet
1102   /// CHECK: ArrayGet
1103 
1104   /// CHECK-START: int Main.testAllocationEliminationOfArray3(int) load_store_elimination (after)
1105   /// CHECK-NOT: NewArray
1106   /// CHECK-NOT: ArraySet
1107   /// CHECK-NOT: ArrayGet
testAllocationEliminationOfArray3(int i)1108   private static int testAllocationEliminationOfArray3(int i) {
1109     int[] array = new int[4];
1110     array[i] = 4;
1111     return array[i];
1112   }
1113 
1114   /// CHECK-START: int Main.testAllocationEliminationOfArray4(int) load_store_elimination (before)
1115   /// CHECK: NewArray
1116   /// CHECK: ArraySet
1117   /// CHECK: ArraySet
1118   /// CHECK: ArrayGet
1119   /// CHECK: ArrayGet
1120 
1121   /// CHECK-START: int Main.testAllocationEliminationOfArray4(int) load_store_elimination (after)
1122   /// CHECK: NewArray
1123   /// CHECK: ArraySet
1124   /// CHECK: ArraySet
1125   /// CHECK: ArrayGet
1126   /// CHECK-NOT: ArrayGet
testAllocationEliminationOfArray4(int i)1127   private static int testAllocationEliminationOfArray4(int i) {
1128     // Cannot eliminate array allocation due to index aliasing between 1 and i.
1129     int[] array = new int[4];
1130     array[1] = 2;
1131     array[i] = 4;
1132     return array[1] + array[i];
1133   }
1134 
1135   /// CHECK-START: int Main.testAllocationEliminationOfArray5(int) load_store_elimination (before)
1136   /// CHECK: NewArray
1137   /// CHECK: ArraySet
1138   /// CHECK: ArrayGet
1139 
1140   /// CHECK-START: int Main.testAllocationEliminationOfArray5(int) load_store_elimination (after)
1141   /// CHECK: NewArray
1142   /// CHECK-NOT: ArraySet
1143   /// CHECK-NOT: ArrayGet
testAllocationEliminationOfArray5(int i)1144   private static int testAllocationEliminationOfArray5(int i) {
1145     // Cannot eliminate array allocation due to unknown i that may
1146     // cause NegativeArraySizeException.
1147     int[] array = new int[i];
1148     array[1] = 12;
1149     return array[1];
1150   }
1151 
1152   /// CHECK-START: int Main.testExitMerge(boolean) load_store_elimination (before)
1153   /// CHECK: NewInstance
1154   /// CHECK: InstanceFieldSet
1155   /// CHECK: InstanceFieldGet
1156   /// CHECK: Return
1157   /// CHECK: InstanceFieldSet
1158   /// CHECK: Throw
1159 
1160   /// CHECK-START: int Main.testExitMerge(boolean) load_store_elimination (after)
1161   /// CHECK-NOT: NewInstance
1162   /// CHECK-NOT: InstanceFieldSet
1163   /// CHECK-NOT: InstanceFieldGet
1164   /// CHECK: Return
1165   /// CHECK-NOT: InstanceFieldSet
1166   /// CHECK: Throw
testExitMerge(boolean cond)1167   private static int testExitMerge(boolean cond) {
1168     TestClass obj = new TestClass();
1169     if (cond) {
1170       obj.i = 1;
1171       return obj.i + 1;
1172     } else {
1173       obj.i = 2;
1174       throw new Error();
1175     }
1176   }
1177 
1178   /// CHECK-START: int Main.testExitMerge2(boolean) load_store_elimination (before)
1179   /// CHECK: NewInstance
1180   /// CHECK: InstanceFieldSet
1181   /// CHECK: InstanceFieldGet
1182   /// CHECK: InstanceFieldSet
1183   /// CHECK: InstanceFieldGet
1184 
1185   /// CHECK-START: int Main.testExitMerge2(boolean) load_store_elimination (after)
1186   /// CHECK-NOT: NewInstance
1187   /// CHECK-NOT: InstanceFieldSet
1188   /// CHECK-NOT: InstanceFieldGet
testExitMerge2(boolean cond)1189   private static int testExitMerge2(boolean cond) {
1190     TestClass obj = new TestClass();
1191     int res;
1192     if (cond) {
1193       obj.i = 1;
1194       res = obj.i + 1;
1195     } else {
1196       obj.i = 2;
1197       res = obj.j + 2;
1198     }
1199     return res;
1200   }
1201 
1202   /// CHECK-START: void Main.testStoreSameValue() load_store_elimination (before)
1203   /// CHECK: NewArray
1204   /// CHECK: ArrayGet
1205   /// CHECK: ArraySet
1206 
1207   /// CHECK-START: void Main.testStoreSameValue() load_store_elimination (after)
1208   /// CHECK: NewArray
1209   /// CHECK-NOT: ArrayGet
1210   /// CHECK-NOT: ArraySet
testStoreSameValue()1211   private static void testStoreSameValue() {
1212     Object[] array = new Object[2];
1213     sArray = array;
1214     Object obj = array[0];
1215     array[1] = obj;    // store the same value as the defaut value.
1216   }
1217 
1218   /// CHECK-START: int Main.$noinline$testByteArrayDefaultValue() load_store_elimination (before)
1219   /// CHECK-DAG:                 NewArray
1220   /// CHECK-DAG: <<Value:b\d+>>  ArrayGet
1221   /// CHECK-DAG:                 Return [<<Value>>]
1222 
1223   /// CHECK-START: int Main.$noinline$testByteArrayDefaultValue() load_store_elimination (after)
1224   /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
1225   /// CHECK-DAG:                 Return [<<Const0>>]
1226 
1227   /// CHECK-START: int Main.$noinline$testByteArrayDefaultValue() load_store_elimination (after)
1228   /// CHECK-NOT:                 NewArray
1229   /// CHECK-NOT:                 ArrayGet
1230   /// CHECK-NOT:                 TypeConversion
$noinline$testByteArrayDefaultValue()1231   private static int $noinline$testByteArrayDefaultValue() {
1232     byte[] array = new byte[2];
1233     array[1] = 1;  // FIXME: Without any stores, LSA tells LSE not to run.
1234     return array[0];
1235   }
1236 
1237   static Object[] sArray;
1238 
1239   /// CHECK-START: int Main.testLocalArrayMerge1(boolean) load_store_elimination (before)
1240   /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
1241   /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
1242   /// CHECK-DAG: <<A:l\d+>>      NewArray
1243   /// CHECK-DAG:                 ArraySet [<<A>>,<<Const0>>,<<Const0>>]
1244   /// CHECK-DAG:                 ArraySet [<<A>>,<<Const0>>,<<Const1>>]
1245   /// CHECK-DAG:                 ArraySet [<<A>>,<<Const0>>,<<Const1>>]
1246   /// CHECK-DAG: <<Get:i\d+>>    ArrayGet [<<A>>,<<Const0>>]
1247   /// CHECK-DAG:                 Return [<<Get>>]
1248   //
1249   /// CHECK-START: int Main.testLocalArrayMerge1(boolean) load_store_elimination (after)
1250   /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
1251   /// CHECK-DAG:                 Return [<<Const1>>]
1252   //
1253   /// CHECK-START: int Main.testLocalArrayMerge1(boolean) load_store_elimination (after)
1254   /// CHECK-NOT:                 NewArray
1255   /// CHECK-NOT:                 ArraySet
1256   /// CHECK-NOT:                 ArrayGet
testLocalArrayMerge1(boolean x)1257   private static int testLocalArrayMerge1(boolean x) {
1258     // The explicit store can be removed right away
1259     // since it is equivalent to the default.
1260     int[] a = { 0 };
1261     // The diamond pattern stores/load can be replaced
1262     // by the direct value.
1263     if (x) {
1264       a[0] = 1;
1265     } else {
1266       a[0] = 1;
1267     }
1268     return a[0];
1269   }
1270 
1271   /// CHECK-START: int Main.testLocalArrayMerge2(boolean) load_store_elimination (before)
1272   /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
1273   /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
1274   /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2
1275   /// CHECK-DAG: <<Const3:i\d+>> IntConstant 3
1276   /// CHECK-DAG: <<A:l\d+>>      NewArray
1277   /// CHECK-DAG:                 ArraySet [<<A>>,<<Const0>>,<<Const1>>]
1278   /// CHECK-DAG:                 ArraySet [<<A>>,<<Const0>>,<<Const2>>]
1279   /// CHECK-DAG:                 ArraySet [<<A>>,<<Const0>>,<<Const3>>]
1280   /// CHECK-DAG: <<Get:i\d+>>    ArrayGet [<<A>>,<<Const0>>]
1281   /// CHECK-DAG:                 Return [<<Get>>]
1282   //
1283   /// CHECK-START: int Main.testLocalArrayMerge2(boolean) load_store_elimination (after)
1284   /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
1285   /// CHECK-DAG: <<A:l\d+>>      NewArray
1286   /// CHECK-DAG: <<Get:i\d+>>    ArrayGet [<<A>>,<<Const0>>]
1287   /// CHECK-DAG:                 Return [<<Get>>]
1288   //
1289   /// CHECK-START: int Main.testLocalArrayMerge2(boolean) load_store_elimination (after)
1290   /// CHECK-DAG:                 ArraySet
1291   /// CHECK-DAG:                 ArraySet
1292   /// CHECK-NOT:                 ArraySet
testLocalArrayMerge2(boolean x)1293   private static int testLocalArrayMerge2(boolean x) {
1294     // The explicit store can be removed eventually even
1295     // though it is not equivalent to the default.
1296     int[] a = { 1 };
1297     // The diamond pattern stores/load remain.
1298     if (x) {
1299       a[0] = 2;
1300     } else {
1301       a[0] = 3;
1302     }
1303     return a[0];
1304   }
1305 
1306   /// CHECK-START: int Main.testLocalArrayMerge3(boolean) load_store_elimination (after)
1307   /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
1308   /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
1309   /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2
1310   /// CHECK-DAG: <<A:l\d+>>      NewArray
1311   /// CHECK-DAG:                 ArraySet [<<A>>,<<Const0>>,<<Const1>>]
1312   /// CHECK-DAG:                 ArraySet [<<A>>,<<Const0>>,<<Const2>>]
1313   /// CHECK-DAG: <<Get:i\d+>>    ArrayGet [<<A>>,<<Const0>>]
1314   /// CHECK-DAG:                 Return [<<Get>>]
testLocalArrayMerge3(boolean x)1315   private static int testLocalArrayMerge3(boolean x) {
1316     // All stores/load remain.
1317     int[] a = { 1 };
1318     if (x) {
1319       a[0] = 2;
1320     }
1321     return a[0];
1322   }
1323 
1324   /// CHECK-START: int Main.testLocalArrayMerge4(boolean) load_store_elimination (before)
1325   /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
1326   /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
1327   /// CHECK-DAG: <<A:l\d+>>      NewArray
1328   /// CHECK-DAG:                 ArraySet [<<A>>,<<Const0>>,<<Const0>>]
1329   /// CHECK-DAG:                 ArraySet [<<A>>,<<Const0>>,<<Const1>>]
1330   /// CHECK-DAG:                 ArraySet [<<A>>,<<Const0>>,<<Const1>>]
1331   /// CHECK-DAG: <<Get1:b\d+>>   ArrayGet [<<A>>,<<Const0>>]
1332   /// CHECK-DAG: <<Get2:a\d+>>   ArrayGet [<<A>>,<<Const0>>]
1333   /// CHECK-DAG: <<Add:i\d+>>    Add [<<Get1>>,<<Get2>>]
1334   /// CHECK-DAG:                 Return [<<Add>>]
1335   //
1336   /// CHECK-START: int Main.testLocalArrayMerge4(boolean) load_store_elimination (after)
1337   /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
1338   /// CHECK-DAG: <<Cnv1:b\d+>>   TypeConversion [<<Const1>>]
1339   /// CHECK-DAG: <<Cnv2:a\d+>>   TypeConversion [<<Const1>>]
1340   /// CHECK-DAG: <<Add:i\d+>>    Add [<<Cnv1>>,<<Cnv2>>]
1341   /// CHECK-DAG:                 Return [<<Add>>]
1342   //
1343   /// CHECK-START: int Main.testLocalArrayMerge4(boolean) load_store_elimination (after)
1344   /// CHECK-NOT:                 NewArray
1345   /// CHECK-NOT:                 ArraySet
1346   /// CHECK-NOT:                 ArrayGet
testLocalArrayMerge4(boolean x)1347   private static int testLocalArrayMerge4(boolean x) {
1348     byte[] a = { 0 };
1349     if (x) {
1350       a[0] = 1;
1351     } else {
1352       a[0] = 1;
1353     }
1354     // Differently typed (signed vs unsigned),
1355     // but same reference.
1356     return a[0] + (a[0] & 0xff);
1357   }
1358 
1359   /// CHECK-START: void Main.$noinline$testThrowingArraySet(java.lang.Object[], java.lang.Object) load_store_elimination (before)
1360   /// CHECK-DAG:                 ArrayGet
1361   /// CHECK-DAG:                 ArraySet
1362   /// CHECK-DAG:                 ArraySet
1363   /// CHECK-DAG:                 ArraySet
1364   /// CHECK-DAG:                 ArraySet
1365 
1366   /// CHECK-START: void Main.$noinline$testThrowingArraySet(java.lang.Object[], java.lang.Object) load_store_elimination (after)
1367   /// CHECK-DAG:                 ArrayGet
1368   /// CHECK-DAG:                 ArraySet
1369   /// CHECK-DAG:                 ArraySet
1370   /// CHECK-DAG:                 ArraySet
1371   /// CHECK-DAG:                 ArraySet
$noinline$testThrowingArraySet(Object[] a, Object o)1372   private static void $noinline$testThrowingArraySet(Object[] a, Object o) {
1373     Object olda0 = a[0];
1374     a[0] = null;
1375     a[1] = olda0;
1376     a[0] = o;
1377     a[1] = null;
1378   }
1379 
assertIntEquals(int result, int expected)1380   static void assertIntEquals(int result, int expected) {
1381     if (expected != result) {
1382       throw new Error("Expected: " + expected + ", found: " + result);
1383     }
1384   }
1385 
assertFloatEquals(float result, float expected)1386   static void assertFloatEquals(float result, float expected) {
1387     if (expected != result) {
1388       throw new Error("Expected: " + expected + ", found: " + result);
1389     }
1390   }
1391 
assertDoubleEquals(double result, double expected)1392   static void assertDoubleEquals(double result, double expected) {
1393     if (expected != result) {
1394       throw new Error("Expected: " + expected + ", found: " + result);
1395     }
1396   }
1397 
main(String[] args)1398   public static void main(String[] args) {
1399     assertDoubleEquals(Math.PI * Math.PI * Math.PI, calcCircleArea(Math.PI));
1400     assertIntEquals(test1(new TestClass(), new TestClass()), 3);
1401     assertIntEquals(test2(new TestClass()), 1);
1402     TestClass obj1 = new TestClass();
1403     TestClass obj2 = new TestClass();
1404     obj1.next = obj2;
1405     assertIntEquals(test3(obj1), 10);
1406     assertIntEquals(test4(new TestClass(), true), 1);
1407     assertIntEquals(test4(new TestClass(), false), 1);
1408     assertIntEquals(test5(new TestClass(), true), 1);
1409     assertIntEquals(test5(new TestClass(), false), 2);
1410     assertIntEquals(test6(new TestClass(), new TestClass(), true), 4);
1411     assertIntEquals(test6(new TestClass(), new TestClass(), false), 2);
1412     assertIntEquals(test7(new TestClass()), 1);
1413     assertIntEquals(test8(), 1);
1414     obj1 = new TestClass();
1415     obj2 = new TestClass();
1416     obj1.next = obj2;
1417     assertIntEquals(test9(new TestClass()), 1);
1418     assertIntEquals(test10(new TestClass(3, 4)), 3);
1419     assertIntEquals(TestClass.si, 3);
1420     assertIntEquals(test11(new TestClass()), 10);
1421     assertIntEquals(test12(new TestClass(), new TestClass()), 10);
1422     assertIntEquals(test13(new TestClass(), new TestClass2()), 3);
1423     SubTestClass obj3 = new SubTestClass();
1424     assertIntEquals(test14(obj3, obj3), 2);
1425     assertIntEquals(test15(), 2);
1426     assertIntEquals(test16(), 3);
1427     assertIntEquals(test17(), 0);
1428     assertIntEquals(test18(new TestClass()), 1);
1429     float[] fa1 = { 0.8f };
1430     float[] fa2 = { 1.8f };
1431     assertFloatEquals(test19(fa1, fa2), 1.8f);
1432     assertFloatEquals(test20().i, 0);
1433     test21(new TestClass());
1434     assertIntEquals(test22(), 13);
1435     assertIntEquals(test23(true), 4);
1436     assertIntEquals(test23(false), 5);
1437     assertFloatEquals(test24(), 8.0f);
1438     testFinalizableByForcingGc();
1439     assertIntEquals($noinline$testHSelect(true), 0xdead);
1440     int[] array = {2, 5, 9, -1, -3, 10, 8, 4};
1441     assertIntEquals(sumWithinRange(array, 1, 5), 11);
1442     assertFloatEquals(testAllocationEliminationWithLoops(), 1.0f);
1443     assertFloatEquals(mF, 0f);
1444     assertDoubleEquals(Math.PI * Math.PI * Math.PI, getCircleArea(Math.PI, true));
1445     assertDoubleEquals(0d, getCircleArea(Math.PI, false));
1446 
1447     assertIntEquals($noinline$testConversion1(new TestClass(), 300), 300);
1448     assertIntEquals($noinline$testConversion1(new TestClass(), 301), 45);
1449     assertIntEquals($noinline$testConversion2(new TestClass(), 300), 300);
1450     assertIntEquals($noinline$testConversion2(new TestClass(), 301), 90);
1451 
1452     int[] iarray = {0, 0, 0};
1453     double[] darray = {0d, 0d, 0d};
1454     try {
1455       assertDoubleEquals(Math.PI * Math.PI * Math.PI, testDeoptimize(iarray, darray, Math.PI));
1456     } catch (Exception e) {
1457       System.out.println(e.getClass().getName());
1458     }
1459     assertIntEquals(iarray[0], 1);
1460     assertIntEquals(iarray[1], 1);
1461     assertIntEquals(iarray[2], 1);
1462     assertDoubleEquals(darray[0], Math.PI);
1463     assertDoubleEquals(darray[1], Math.PI);
1464     assertDoubleEquals(darray[2], Math.PI);
1465 
1466     assertIntEquals(testAllocationEliminationOfArray1(), 11);
1467     assertIntEquals(testAllocationEliminationOfArray2(), 11);
1468     assertIntEquals(testAllocationEliminationOfArray3(2), 4);
1469     assertIntEquals(testAllocationEliminationOfArray4(2), 6);
1470     assertIntEquals(testAllocationEliminationOfArray5(2), 12);
1471     try {
1472       testAllocationEliminationOfArray5(-2);
1473     } catch (NegativeArraySizeException e) {
1474       System.out.println("Got NegativeArraySizeException.");
1475     }
1476 
1477     assertIntEquals(testStoreStore().i, 41);
1478     assertIntEquals(testStoreStore().j, 43);
1479 
1480     assertIntEquals(testExitMerge(true), 2);
1481     assertIntEquals(testExitMerge2(true), 2);
1482     assertIntEquals(testExitMerge2(false), 2);
1483 
1484     TestClass2 testclass2 = new TestClass2();
1485     testStoreStore2(testclass2);
1486     assertIntEquals(testclass2.i, 43);
1487     assertIntEquals(testclass2.j, 44);
1488 
1489     testStoreStore3(testclass2, true);
1490     assertIntEquals(testclass2.i, 41);
1491     assertIntEquals(testclass2.j, 43);
1492     testStoreStore3(testclass2, false);
1493     assertIntEquals(testclass2.i, 41);
1494     assertIntEquals(testclass2.j, 44);
1495 
1496     testStoreStore4();
1497     assertIntEquals(TestClass.si, 62);
1498 
1499     int ret = testStoreStore5(testclass2, testclass2);
1500     assertIntEquals(testclass2.i, 72);
1501     assertIntEquals(ret, 71);
1502 
1503     testclass2.j = 88;
1504     ret = testStoreStore6(testclass2, testclass2);
1505     assertIntEquals(testclass2.i, 82);
1506     assertIntEquals(ret, 88);
1507 
1508     ret = testNoSideEffects(iarray);
1509     assertIntEquals(iarray[0], 101);
1510     assertIntEquals(iarray[1], 103);
1511     assertIntEquals(ret, 108);
1512 
1513     try {
1514       testThrow(testclass2, new Exception());
1515     } catch (Exception e) {}
1516     assertIntEquals(testclass2.i, 55);
1517 
1518     assertIntEquals(testStoreStoreWithDeoptimize(new int[4]), 4);
1519 
1520     assertIntEquals($noinline$testByteArrayDefaultValue(), 0);
1521 
1522     assertIntEquals(testLocalArrayMerge1(true), 1);
1523     assertIntEquals(testLocalArrayMerge1(false), 1);
1524     assertIntEquals(testLocalArrayMerge2(true), 2);
1525     assertIntEquals(testLocalArrayMerge2(false), 3);
1526     assertIntEquals(testLocalArrayMerge3(true), 2);
1527     assertIntEquals(testLocalArrayMerge3(false), 1);
1528     assertIntEquals(testLocalArrayMerge4(true), 2);
1529     assertIntEquals(testLocalArrayMerge4(false), 2);
1530 
1531     TestClass[] tca = new TestClass[] { new TestClass(), null };
1532     try {
1533       $noinline$testThrowingArraySet(tca, new TestClass2());
1534     } catch (ArrayStoreException expected) {
1535       if (tca[0] != null) {
1536         throw new Error("tca[0] is not null");
1537       }
1538       if (tca[1] == null) {
1539         throw new Error("tca[1] is null");
1540       }
1541     }
1542   }
1543 
1544   static boolean sFlag;
1545 }
1546