xref: /aosp_15_r20/art/test/445-checker-licm/src/Main.java (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker public class Main {
18*795d594fSAndroid Build Coastguard Worker   static class ValueHolder {
getValue()19*795d594fSAndroid Build Coastguard Worker     static int getValue() {
20*795d594fSAndroid Build Coastguard Worker       return 1;
21*795d594fSAndroid Build Coastguard Worker     }
22*795d594fSAndroid Build Coastguard Worker   }
23*795d594fSAndroid Build Coastguard Worker 
24*795d594fSAndroid Build Coastguard Worker   /// CHECK-START: int Main.div() licm (before)
25*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG: Div loop:{{B\d+}}
26*795d594fSAndroid Build Coastguard Worker 
27*795d594fSAndroid Build Coastguard Worker   /// CHECK-START: int Main.div() licm (after)
28*795d594fSAndroid Build Coastguard Worker   /// CHECK-NOT: Div loop:{{B\d+}}
29*795d594fSAndroid Build Coastguard Worker 
30*795d594fSAndroid Build Coastguard Worker   /// CHECK-START: int Main.div() licm (after)
31*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG: Div loop:none
32*795d594fSAndroid Build Coastguard Worker 
div()33*795d594fSAndroid Build Coastguard Worker   public static int div() {
34*795d594fSAndroid Build Coastguard Worker     int result = 0;
35*795d594fSAndroid Build Coastguard Worker     for (int i = 0; i < 10; ++i) {
36*795d594fSAndroid Build Coastguard Worker       result += staticField / 42;
37*795d594fSAndroid Build Coastguard Worker     }
38*795d594fSAndroid Build Coastguard Worker     return result;
39*795d594fSAndroid Build Coastguard Worker   }
40*795d594fSAndroid Build Coastguard Worker 
41*795d594fSAndroid Build Coastguard Worker   /// CHECK-START: int Main.innerDiv() licm (before)
42*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG: Div loop:{{B\d+}}
43*795d594fSAndroid Build Coastguard Worker 
44*795d594fSAndroid Build Coastguard Worker   /// CHECK-START: int Main.innerDiv() licm (after)
45*795d594fSAndroid Build Coastguard Worker   /// CHECK-NOT: Div loop:{{B\d+}}
46*795d594fSAndroid Build Coastguard Worker 
47*795d594fSAndroid Build Coastguard Worker   /// CHECK-START: int Main.innerDiv() licm (after)
48*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG: Div loop:none
49*795d594fSAndroid Build Coastguard Worker 
innerDiv()50*795d594fSAndroid Build Coastguard Worker   public static int innerDiv() {
51*795d594fSAndroid Build Coastguard Worker     int result = 0;
52*795d594fSAndroid Build Coastguard Worker     for (int i = 0; i < 10; ++i) {
53*795d594fSAndroid Build Coastguard Worker       for (int j = 0; j < 10; ++j) {
54*795d594fSAndroid Build Coastguard Worker         result += staticField / 42;
55*795d594fSAndroid Build Coastguard Worker       }
56*795d594fSAndroid Build Coastguard Worker     }
57*795d594fSAndroid Build Coastguard Worker     return result;
58*795d594fSAndroid Build Coastguard Worker   }
59*795d594fSAndroid Build Coastguard Worker 
60*795d594fSAndroid Build Coastguard Worker   /// CHECK-START: int Main.innerMul() licm (before)
61*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG: Mul loop:B4
62*795d594fSAndroid Build Coastguard Worker 
63*795d594fSAndroid Build Coastguard Worker   /// CHECK-START: int Main.innerMul() licm (after)
64*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG: Mul loop:B2
65*795d594fSAndroid Build Coastguard Worker 
innerMul()66*795d594fSAndroid Build Coastguard Worker   public static int innerMul() {
67*795d594fSAndroid Build Coastguard Worker     int result = 0;
68*795d594fSAndroid Build Coastguard Worker     for (int i = 0; i < 10; ++i) {
69*795d594fSAndroid Build Coastguard Worker       for (int j = 0; j < 10; ++j) {
70*795d594fSAndroid Build Coastguard Worker         // The operation has been hoisted out of the inner loop.
71*795d594fSAndroid Build Coastguard Worker         // Note that we depend on the compiler's block numbering to
72*795d594fSAndroid Build Coastguard Worker         // check if it has been moved.
73*795d594fSAndroid Build Coastguard Worker         result += staticField * i;
74*795d594fSAndroid Build Coastguard Worker       }
75*795d594fSAndroid Build Coastguard Worker     }
76*795d594fSAndroid Build Coastguard Worker     return result;
77*795d594fSAndroid Build Coastguard Worker   }
78*795d594fSAndroid Build Coastguard Worker 
79*795d594fSAndroid Build Coastguard Worker   /// CHECK-START: int Main.divByA(int, int) licm (before)
80*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG: Div loop:{{B\d+}}
81*795d594fSAndroid Build Coastguard Worker 
82*795d594fSAndroid Build Coastguard Worker   /// CHECK-START: int Main.divByA(int, int) licm (after)
83*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG: Div loop:{{B\d+}}
84*795d594fSAndroid Build Coastguard Worker 
divByA(int a, int b)85*795d594fSAndroid Build Coastguard Worker   public static int divByA(int a, int b) {
86*795d594fSAndroid Build Coastguard Worker     int result = 0;
87*795d594fSAndroid Build Coastguard Worker     while (b < 5) {
88*795d594fSAndroid Build Coastguard Worker       // a might be null, so we can't hoist the operation.
89*795d594fSAndroid Build Coastguard Worker       result += staticField / a;
90*795d594fSAndroid Build Coastguard Worker       b++;
91*795d594fSAndroid Build Coastguard Worker     }
92*795d594fSAndroid Build Coastguard Worker     return result;
93*795d594fSAndroid Build Coastguard Worker   }
94*795d594fSAndroid Build Coastguard Worker 
95*795d594fSAndroid Build Coastguard Worker   /// CHECK-START: int Main.arrayLength(int[]) licm (before)
96*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG: <<NullCheck:l\d+>> NullCheck loop:{{B\d+}}
97*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG:                    ArrayLength [<<NullCheck>>] loop:{{B\d+}}
98*795d594fSAndroid Build Coastguard Worker 
99*795d594fSAndroid Build Coastguard Worker   /// CHECK-START: int Main.arrayLength(int[]) licm (after)
100*795d594fSAndroid Build Coastguard Worker   /// CHECK-NOT:                    NullCheck loop:{{B\d+}}
101*795d594fSAndroid Build Coastguard Worker   /// CHECK-NOT:                    ArrayLength loop:{{B\d+}}
102*795d594fSAndroid Build Coastguard Worker 
103*795d594fSAndroid Build Coastguard Worker   /// CHECK-START: int Main.arrayLength(int[]) licm (after)
104*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG: <<NullCheck:l\d+>> NullCheck loop:none
105*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG:                    ArrayLength [<<NullCheck>>] loop:none
106*795d594fSAndroid Build Coastguard Worker 
arrayLength(int[] array)107*795d594fSAndroid Build Coastguard Worker   public static int arrayLength(int[] array) {
108*795d594fSAndroid Build Coastguard Worker     int result = 0;
109*795d594fSAndroid Build Coastguard Worker     for (int i = 0; i < array.length; ++i) {
110*795d594fSAndroid Build Coastguard Worker       result += array[i];
111*795d594fSAndroid Build Coastguard Worker     }
112*795d594fSAndroid Build Coastguard Worker     return result;
113*795d594fSAndroid Build Coastguard Worker   }
114*795d594fSAndroid Build Coastguard Worker 
115*795d594fSAndroid Build Coastguard Worker   /// CHECK-START: int Main.clinitCheck() licm (before)
116*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG: <<LoadClass:l\d+>> LoadClass loop:<<Loop:B\d+>>
117*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG:                    ClinitCheck [<<LoadClass>>] loop:<<Loop>>
118*795d594fSAndroid Build Coastguard Worker 
119*795d594fSAndroid Build Coastguard Worker   /// CHECK-START: int Main.clinitCheck() licm (after)
120*795d594fSAndroid Build Coastguard Worker   /// CHECK-NOT:                    LoadClass loop:{{B\d+}}
121*795d594fSAndroid Build Coastguard Worker   /// CHECK-NOT:                    ClinitCheck loop:{{B\d+}}
122*795d594fSAndroid Build Coastguard Worker 
123*795d594fSAndroid Build Coastguard Worker   /// CHECK-START: int Main.clinitCheck() licm (after)
124*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG: <<LoadClass:l\d+>> LoadClass loop:none
125*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG:                    ClinitCheck [<<LoadClass>>] loop:none
126*795d594fSAndroid Build Coastguard Worker 
clinitCheck()127*795d594fSAndroid Build Coastguard Worker   public static int clinitCheck() {
128*795d594fSAndroid Build Coastguard Worker     int i = 0;
129*795d594fSAndroid Build Coastguard Worker     int sum = 0;
130*795d594fSAndroid Build Coastguard Worker     do {
131*795d594fSAndroid Build Coastguard Worker       sum += ValueHolder.getValue();
132*795d594fSAndroid Build Coastguard Worker       i++;
133*795d594fSAndroid Build Coastguard Worker     } while (i < 10);
134*795d594fSAndroid Build Coastguard Worker     return sum;
135*795d594fSAndroid Build Coastguard Worker   }
136*795d594fSAndroid Build Coastguard Worker 
137*795d594fSAndroid Build Coastguard Worker   /// CHECK-START: int Main.divAndIntrinsic(int[]) licm (before)
138*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG: Div loop:{{B\d+}}
139*795d594fSAndroid Build Coastguard Worker 
140*795d594fSAndroid Build Coastguard Worker   /// CHECK-START: int Main.divAndIntrinsic(int[]) licm (after)
141*795d594fSAndroid Build Coastguard Worker   /// CHECK-NOT: Div loop:{{B\d+}}
142*795d594fSAndroid Build Coastguard Worker 
143*795d594fSAndroid Build Coastguard Worker   /// CHECK-START: int Main.divAndIntrinsic(int[]) licm (after)
144*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG: Div loop:none
145*795d594fSAndroid Build Coastguard Worker 
divAndIntrinsic(int[] array)146*795d594fSAndroid Build Coastguard Worker   public static int divAndIntrinsic(int[] array) {
147*795d594fSAndroid Build Coastguard Worker     int result = 0;
148*795d594fSAndroid Build Coastguard Worker     for (int i = 0; i < array.length; i++) {
149*795d594fSAndroid Build Coastguard Worker       // An intrinsic call, unlike a general method call, cannot modify the field value.
150*795d594fSAndroid Build Coastguard Worker       // As a result, the invariant division on the field can be moved out of the loop.
151*795d594fSAndroid Build Coastguard Worker       result += (staticField / 42) + Math.abs(array[i]);
152*795d594fSAndroid Build Coastguard Worker     }
153*795d594fSAndroid Build Coastguard Worker     return result;
154*795d594fSAndroid Build Coastguard Worker   }
155*795d594fSAndroid Build Coastguard Worker 
156*795d594fSAndroid Build Coastguard Worker   /// CHECK-START: int Main.invariantBoundIntrinsic(int) licm (before)
157*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG: Abs loop:{{B\d+}}
158*795d594fSAndroid Build Coastguard Worker 
159*795d594fSAndroid Build Coastguard Worker   /// CHECK-START: int Main.invariantBoundIntrinsic(int) licm (after)
160*795d594fSAndroid Build Coastguard Worker   /// CHECK-NOT: Abs loop:{{B\d+}}
161*795d594fSAndroid Build Coastguard Worker 
162*795d594fSAndroid Build Coastguard Worker   /// CHECK-START: int Main.invariantBoundIntrinsic(int) licm (after)
163*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG: Abs loop:none
164*795d594fSAndroid Build Coastguard Worker 
invariantBoundIntrinsic(int x)165*795d594fSAndroid Build Coastguard Worker   public static int invariantBoundIntrinsic(int x) {
166*795d594fSAndroid Build Coastguard Worker     int result = 0;
167*795d594fSAndroid Build Coastguard Worker     // The intrinsic call to abs used as loop bound is invariant.
168*795d594fSAndroid Build Coastguard Worker     // As a result, the call itself can be moved out of the loop header.
169*795d594fSAndroid Build Coastguard Worker     for (int i = 0; i < Math.abs(x); i++) {
170*795d594fSAndroid Build Coastguard Worker       result += i;
171*795d594fSAndroid Build Coastguard Worker     }
172*795d594fSAndroid Build Coastguard Worker     return result;
173*795d594fSAndroid Build Coastguard Worker   }
174*795d594fSAndroid Build Coastguard Worker 
175*795d594fSAndroid Build Coastguard Worker   /// CHECK-START: int Main.invariantBodyIntrinsic(int, int) licm (before)
176*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG: Max loop:{{B\d+}}
177*795d594fSAndroid Build Coastguard Worker 
178*795d594fSAndroid Build Coastguard Worker   /// CHECK-START: int Main.invariantBodyIntrinsic(int, int) licm (after)
179*795d594fSAndroid Build Coastguard Worker   /// CHECK-NOT: Max loop:{{B\d+}}
180*795d594fSAndroid Build Coastguard Worker 
181*795d594fSAndroid Build Coastguard Worker   /// CHECK-START: int Main.invariantBodyIntrinsic(int, int) licm (after)
182*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG: Max loop:none
183*795d594fSAndroid Build Coastguard Worker 
invariantBodyIntrinsic(int x, int y)184*795d594fSAndroid Build Coastguard Worker   public static int invariantBodyIntrinsic(int x, int y) {
185*795d594fSAndroid Build Coastguard Worker     int result = 0;
186*795d594fSAndroid Build Coastguard Worker     for (int i = 0; i < 10; i++) {
187*795d594fSAndroid Build Coastguard Worker       // The intrinsic call to max used inside the loop is invariant.
188*795d594fSAndroid Build Coastguard Worker       // As a result, the call itself can be moved out of the loop body.
189*795d594fSAndroid Build Coastguard Worker       result += Math.max(x, y);
190*795d594fSAndroid Build Coastguard Worker     }
191*795d594fSAndroid Build Coastguard Worker     return result;
192*795d594fSAndroid Build Coastguard Worker   }
193*795d594fSAndroid Build Coastguard Worker 
194*795d594fSAndroid Build Coastguard Worker   //
195*795d594fSAndroid Build Coastguard Worker   // All operations up to the null check can be hoisted out of the
196*795d594fSAndroid Build Coastguard Worker   // loop. The null check itself sees the induction in its environment.
197*795d594fSAndroid Build Coastguard Worker   //
198*795d594fSAndroid Build Coastguard Worker   /// CHECK-START: int Main.doWhile(int) licm (before)
199*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG: <<Add:i\d+>> Add                 loop:<<Loop:B\d+>> outer_loop:none
200*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG:              LoadClass           loop:<<Loop>>      outer_loop:none
201*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG: <<Get:l\d+>> StaticFieldGet      loop:<<Loop>>      outer_loop:none
202*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG:              NullCheck [<<Get>>] env:[[<<Add>>,<<Get>>,{{i\d+}}]] loop:<<Loop>> outer_loop:none
203*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG:              ArrayLength         loop:<<Loop>>      outer_loop:none
204*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG:              BoundsCheck         loop:<<Loop>>      outer_loop:none
205*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG:              ArrayGet            loop:<<Loop>>      outer_loop:none
206*795d594fSAndroid Build Coastguard Worker   //
207*795d594fSAndroid Build Coastguard Worker   /// CHECK-START: int Main.doWhile(int) licm (after)
208*795d594fSAndroid Build Coastguard Worker   /// CHECK-NOT: LoadClass      loop:{{B\d+}}
209*795d594fSAndroid Build Coastguard Worker   /// CHECK-NOT: StaticFieldGet loop:{{B\d+}}
210*795d594fSAndroid Build Coastguard Worker   //
211*795d594fSAndroid Build Coastguard Worker   /// CHECK-START: int Main.doWhile(int) licm (after)
212*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG:              LoadClass           loop:none
213*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG: <<Get:l\d+>> StaticFieldGet      loop:none
214*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG: <<Add:i\d+>> Add                 loop:<<Loop:B\d+>> outer_loop:none
215*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG:              NullCheck [<<Get>>] env:[[<<Add>>,<<Get>>,{{i\d+}}]] loop:<<Loop>> outer_loop:none
216*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG:              ArrayLength         loop:<<Loop>>      outer_loop:none
217*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG:              BoundsCheck         loop:<<Loop>>      outer_loop:none
218*795d594fSAndroid Build Coastguard Worker   /// CHECK-DAG:              ArrayGet            loop:<<Loop>>      outer_loop:none
doWhile(int k)219*795d594fSAndroid Build Coastguard Worker   public static int doWhile(int k) {
220*795d594fSAndroid Build Coastguard Worker     int i = k;
221*795d594fSAndroid Build Coastguard Worker     do {
222*795d594fSAndroid Build Coastguard Worker       i += 2;
223*795d594fSAndroid Build Coastguard Worker     } while (staticArray[i] == 0);
224*795d594fSAndroid Build Coastguard Worker     return i;
225*795d594fSAndroid Build Coastguard Worker   }
226*795d594fSAndroid Build Coastguard Worker 
227*795d594fSAndroid Build Coastguard Worker   public static int staticField = 42;
228*795d594fSAndroid Build Coastguard Worker 
229*795d594fSAndroid Build Coastguard Worker   public static int[] staticArray = null;
230*795d594fSAndroid Build Coastguard Worker 
assertEquals(int expected, int actual)231*795d594fSAndroid Build Coastguard Worker   public static void assertEquals(int expected, int actual) {
232*795d594fSAndroid Build Coastguard Worker     if (expected != actual) {
233*795d594fSAndroid Build Coastguard Worker       throw new Error("Expected " + expected + ", got " + actual);
234*795d594fSAndroid Build Coastguard Worker     }
235*795d594fSAndroid Build Coastguard Worker   }
236*795d594fSAndroid Build Coastguard Worker 
main(String[] args)237*795d594fSAndroid Build Coastguard Worker   public static void main(String[] args) {
238*795d594fSAndroid Build Coastguard Worker     assertEquals(10, div());
239*795d594fSAndroid Build Coastguard Worker     assertEquals(100, innerDiv());
240*795d594fSAndroid Build Coastguard Worker     assertEquals(18900, innerMul());
241*795d594fSAndroid Build Coastguard Worker     assertEquals(105, divByA(2, 0));
242*795d594fSAndroid Build Coastguard Worker     assertEquals(12, arrayLength(new int[] { 4, 8 }));
243*795d594fSAndroid Build Coastguard Worker     assertEquals(10, clinitCheck());
244*795d594fSAndroid Build Coastguard Worker     assertEquals(21, divAndIntrinsic(new int[] { 4, -2, 8, -3 }));
245*795d594fSAndroid Build Coastguard Worker     assertEquals(45, invariantBoundIntrinsic(-10));
246*795d594fSAndroid Build Coastguard Worker     assertEquals(30, invariantBodyIntrinsic(2, 3));
247*795d594fSAndroid Build Coastguard Worker 
248*795d594fSAndroid Build Coastguard Worker     staticArray = null;
249*795d594fSAndroid Build Coastguard Worker     try {
250*795d594fSAndroid Build Coastguard Worker       doWhile(0);
251*795d594fSAndroid Build Coastguard Worker       throw new Error("Expected NPE");
252*795d594fSAndroid Build Coastguard Worker     } catch (NullPointerException e) {
253*795d594fSAndroid Build Coastguard Worker     }
254*795d594fSAndroid Build Coastguard Worker     staticArray = new int[5];
255*795d594fSAndroid Build Coastguard Worker     staticArray[4] = 1;
256*795d594fSAndroid Build Coastguard Worker     assertEquals(4, doWhile(-2));
257*795d594fSAndroid Build Coastguard Worker     assertEquals(4, doWhile(0));
258*795d594fSAndroid Build Coastguard Worker     assertEquals(4, doWhile(2));
259*795d594fSAndroid Build Coastguard Worker     try {
260*795d594fSAndroid Build Coastguard Worker       doWhile(1);
261*795d594fSAndroid Build Coastguard Worker       throw new Error("Expected IOOBE");
262*795d594fSAndroid Build Coastguard Worker     } catch (IndexOutOfBoundsException e) {
263*795d594fSAndroid Build Coastguard Worker     }
264*795d594fSAndroid Build Coastguard Worker 
265*795d594fSAndroid Build Coastguard Worker     System.out.println("passed");
266*795d594fSAndroid Build Coastguard Worker   }
267*795d594fSAndroid Build Coastguard Worker }
268