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