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