• 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 
assertIntEquals(int expected, int result)19   public static void assertIntEquals(int expected, int result) {
20     if (expected != result) {
21       throw new Error("Expected: " + expected + ", found: " + result);
22     }
23   }
24 
25   /**
26    * Test that HArrayGet with a constant index is not split.
27    */
28 
29   /// CHECK-START-ARM64: int Main.constantIndexGet(int[]) instruction_simplifier_arm64 (before)
30   /// CHECK:             <<Array:l\d+>>         NullCheck
31   /// CHECK:             <<Index:i\d+>>         BoundsCheck
32   /// CHECK:                                    ArrayGet [<<Array>>,<<Index>>]
33 
34   /// CHECK-START-ARM64: int Main.constantIndexGet(int[]) instruction_simplifier_arm64 (after)
35   /// CHECK:             <<Array:l\d+>>         NullCheck
36   /// CHECK:             <<Index:i\d+>>         BoundsCheck
37   /// CHECK-NOT:                                Arm64IntermediateAddress
38   /// CHECK:                                    ArrayGet [<<Array>>,<<Index>>]
39 
constantIndexGet(int array[])40   public static int constantIndexGet(int array[]) {
41     return array[1];
42   }
43 
44   /**
45    * Test that HArraySet with a constant index is not split.
46    */
47 
48   /// CHECK-START-ARM64: void Main.constantIndexSet(int[]) instruction_simplifier_arm64 (before)
49   /// CHECK:             <<Const2:i\d+>>        IntConstant 2
50   /// CHECK:             <<Array:l\d+>>         NullCheck
51   /// CHECK:             <<Index:i\d+>>         BoundsCheck
52   /// CHECK:                                    ArraySet [<<Array>>,<<Index>>,<<Const2>>]
53 
54   /// CHECK-START-ARM64: void Main.constantIndexSet(int[]) instruction_simplifier_arm64 (after)
55   /// CHECK:             <<Const2:i\d+>>        IntConstant 2
56   /// CHECK:             <<Array:l\d+>>         NullCheck
57   /// CHECK:             <<Index:i\d+>>         BoundsCheck
58   /// CHECK-NOT:                                Arm64IntermediateAddress
59   /// CHECK:                                    ArraySet [<<Array>>,<<Index>>,<<Const2>>]
60 
61 
constantIndexSet(int array[])62   public static void constantIndexSet(int array[]) {
63     array[1] = 2;
64   }
65 
66   /**
67    * Test basic splitting of HArrayGet.
68    */
69 
70   /// CHECK-START-ARM64: int Main.get(int[], int) instruction_simplifier_arm64 (before)
71   /// CHECK:             <<Array:l\d+>>         NullCheck
72   /// CHECK:             <<Index:i\d+>>         BoundsCheck
73   /// CHECK:                                    ArrayGet [<<Array>>,<<Index>>]
74 
75   /// CHECK-START-ARM64: int Main.get(int[], int) instruction_simplifier_arm64 (after)
76   /// CHECK:             <<DataOffset:i\d+>>    IntConstant
77   /// CHECK:             <<Array:l\d+>>         NullCheck
78   /// CHECK:             <<Index:i\d+>>         BoundsCheck
79   /// CHECK:             <<Address:l\d+>>       Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
80   /// CHECK-NEXT:                               ArrayGet [<<Address>>,<<Index>>]
81 
get(int array[], int index)82   public static int get(int array[], int index) {
83     return array[index];
84   }
85 
86   /**
87    * Test basic splitting of HArraySet.
88    */
89 
90   /// CHECK-START-ARM64: void Main.set(int[], int, int) instruction_simplifier_arm64 (before)
91   /// CHECK:                                    ParameterValue
92   /// CHECK:                                    ParameterValue
93   /// CHECK:             <<Arg:i\d+>>           ParameterValue
94   /// CHECK:             <<Array:l\d+>>         NullCheck
95   /// CHECK:             <<Index:i\d+>>         BoundsCheck
96   /// CHECK:                                    ArraySet [<<Array>>,<<Index>>,<<Arg>>]
97 
98   /// CHECK-START-ARM64: void Main.set(int[], int, int) instruction_simplifier_arm64 (after)
99   /// CHECK:                                    ParameterValue
100   /// CHECK:                                    ParameterValue
101   /// CHECK:             <<Arg:i\d+>>           ParameterValue
102   /// CHECK:             <<DataOffset:i\d+>>    IntConstant
103   /// CHECK:             <<Array:l\d+>>         NullCheck
104   /// CHECK:             <<Index:i\d+>>         BoundsCheck
105   /// CHECK:             <<Address:l\d+>>       Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
106   /// CHECK-NEXT:                               ArraySet [<<Address>>,<<Index>>,<<Arg>>]
107 
set(int array[], int index, int value)108   public static void set(int array[], int index, int value) {
109     array[index] = value;
110   }
111 
112   /**
113    * Check that the intermediate address can be shared after GVN.
114    */
115 
116   /// CHECK-START-ARM64: void Main.getSet(int[], int) instruction_simplifier_arm64 (before)
117   /// CHECK:             <<Const1:i\d+>>        IntConstant 1
118   /// CHECK:             <<Array:l\d+>>         NullCheck
119   /// CHECK:             <<Index:i\d+>>         BoundsCheck
120   /// CHECK:             <<ArrayGet:i\d+>>      ArrayGet [<<Array>>,<<Index>>]
121   /// CHECK:             <<Add:i\d+>>           Add [<<ArrayGet>>,<<Const1>>]
122   /// CHECK:                                    ArraySet [<<Array>>,<<Index>>,<<Add>>]
123 
124   /// CHECK-START-ARM64: void Main.getSet(int[], int) instruction_simplifier_arm64 (after)
125   /// CHECK-DAG:         <<Const1:i\d+>>        IntConstant 1
126   /// CHECK-DAG:         <<DataOffset:i\d+>>    IntConstant
127   /// CHECK:             <<Array:l\d+>>         NullCheck
128   /// CHECK:             <<Index:i\d+>>         BoundsCheck
129   /// CHECK:             <<Address1:l\d+>>      Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
130   /// CHECK-NEXT:        <<ArrayGet:i\d+>>      ArrayGet [<<Address1>>,<<Index>>]
131   /// CHECK:             <<Add:i\d+>>           Add [<<ArrayGet>>,<<Const1>>]
132   /// CHECK:             <<Address2:l\d+>>      Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
133   /// CHECK-NEXT:                               ArraySet [<<Address2>>,<<Index>>,<<Add>>]
134 
135   /// CHECK-START-ARM64: void Main.getSet(int[], int) GVN_after_arch (after)
136   /// CHECK-DAG:         <<Const1:i\d+>>        IntConstant 1
137   /// CHECK-DAG:         <<DataOffset:i\d+>>    IntConstant
138   /// CHECK:             <<Array:l\d+>>         NullCheck
139   /// CHECK:             <<Index:i\d+>>         BoundsCheck
140   /// CHECK:             <<Address:l\d+>>       Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
141   /// CHECK:             <<ArrayGet:i\d+>>      ArrayGet [<<Address>>,<<Index>>]
142   /// CHECK:             <<Add:i\d+>>           Add [<<ArrayGet>>,<<Const1>>]
143   /// CHECK-NOT:                                Arm64IntermediateAddress
144   /// CHECK:                                    ArraySet [<<Address>>,<<Index>>,<<Add>>]
145 
getSet(int array[], int index)146   public static void getSet(int array[], int index) {
147     array[index] = array[index] + 1;
148   }
149 
150   /**
151    * Check that the intermediate address computation is not reordered or merged
152    * across IRs that can trigger GC.
153    */
154 
155   /// CHECK-START-ARM64: int[] Main.accrossGC(int[], int) instruction_simplifier_arm64 (before)
156   /// CHECK:             <<Const1:i\d+>>        IntConstant 1
157   /// CHECK:             <<Array:l\d+>>         NullCheck
158   /// CHECK:             <<Index:i\d+>>         BoundsCheck
159   /// CHECK:             <<ArrayGet:i\d+>>      ArrayGet [<<Array>>,<<Index>>]
160   /// CHECK:             <<Add:i\d+>>           Add [<<ArrayGet>>,<<Const1>>]
161   /// CHECK:                                    NewArray
162   /// CHECK:                                    ArraySet [<<Array>>,<<Index>>,<<Add>>]
163 
164   /// CHECK-START-ARM64: int[] Main.accrossGC(int[], int) instruction_simplifier_arm64 (after)
165   /// CHECK-DAG:         <<Const1:i\d+>>        IntConstant 1
166   /// CHECK-DAG:         <<DataOffset:i\d+>>    IntConstant
167   /// CHECK:             <<Array:l\d+>>         NullCheck
168   /// CHECK:             <<Index:i\d+>>         BoundsCheck
169   /// CHECK:             <<Address1:l\d+>>      Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
170   /// CHECK-NEXT:        <<ArrayGet:i\d+>>      ArrayGet [<<Address1>>,<<Index>>]
171   /// CHECK:             <<Add:i\d+>>           Add [<<ArrayGet>>,<<Const1>>]
172   /// CHECK:                                    NewArray
173   /// CHECK:             <<Address2:l\d+>>      Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
174   /// CHECK-NEXT:                               ArraySet [<<Address2>>,<<Index>>,<<Add>>]
175 
176   /// CHECK-START-ARM64: int[] Main.accrossGC(int[], int) GVN_after_arch (after)
177   /// CHECK-DAG:         <<Const1:i\d+>>        IntConstant 1
178   /// CHECK-DAG:         <<DataOffset:i\d+>>    IntConstant
179   /// CHECK:             <<Array:l\d+>>         NullCheck
180   /// CHECK:             <<Index:i\d+>>         BoundsCheck
181   /// CHECK:             <<Address1:l\d+>>      Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
182   /// CHECK:             <<ArrayGet:i\d+>>      ArrayGet [<<Address1>>,<<Index>>]
183   /// CHECK:             <<Add:i\d+>>           Add [<<ArrayGet>>,<<Const1>>]
184   /// CHECK:                                    NewArray
185   /// CHECK:             <<Address2:l\d+>>      Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
186   /// CHECK:                                    ArraySet [<<Address2>>,<<Index>>,<<Add>>]
187 
accrossGC(int array[], int index)188   public static int[] accrossGC(int array[], int index) {
189     int tmp = array[index] + 1;
190     int[] new_array = new int[1];
191     array[index] = tmp;
192     return new_array;
193   }
194 
195   /**
196    * Test that the intermediate address is shared between array accesses after
197    * the bounds check have been removed by BCE.
198    */
199 
200   /// CHECK-START-ARM64: int Main.canMergeAfterBCE1() instruction_simplifier_arm64 (before)
201   /// CHECK:             <<Const1:i\d+>>        IntConstant 1
202   /// CHECK:             <<Array:l\d+>>         NewArray
203   /// CHECK:             <<Index:i\d+>>         Phi
204   /// CHECK:                                    If
205   //  -------------- Loop
206   /// CHECK:             <<ArrayGet:i\d+>>      ArrayGet [<<Array>>,<<Index>>]
207   /// CHECK:             <<Add:i\d+>>           Add [<<ArrayGet>>,<<Const1>>]
208   /// CHECK:                                    ArraySet [<<Array>>,<<Index>>,<<Add>>]
209 
210   // By the time we reach the architecture-specific instruction simplifier, BCE
211   // has removed the bounds checks in the loop.
212 
213   // Note that we do not care that the `DataOffset` is `12`. But if we do not
214   // specify it and any other `IntConstant` appears before that instruction,
215   // checker will match the previous `IntConstant`, and we will thus fail the
216   // check.
217 
218   /// CHECK-START-ARM64: int Main.canMergeAfterBCE1() instruction_simplifier_arm64 (after)
219   /// CHECK-DAG:         <<Const1:i\d+>>        IntConstant 1
220   /// CHECK-DAG:         <<DataOffset:i\d+>>    IntConstant 12
221   /// CHECK:             <<Array:l\d+>>         NewArray
222   /// CHECK:             <<Index:i\d+>>         Phi
223   /// CHECK:                                    If
224   //  -------------- Loop
225   /// CHECK:             <<Address1:l\d+>>      Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
226   /// CHECK-NEXT:        <<ArrayGet:i\d+>>      ArrayGet [<<Address1>>,<<Index>>]
227   /// CHECK:             <<Add:i\d+>>           Add [<<ArrayGet>>,<<Const1>>]
228   /// CHECK:             <<Address2:l\d+>>      Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
229   /// CHECK-NEXT:                               ArraySet [<<Address2>>,<<Index>>,<<Add>>]
230 
231   /// CHECK-START-ARM64: int Main.canMergeAfterBCE1() GVN_after_arch (after)
232   /// CHECK-DAG:         <<Const1:i\d+>>        IntConstant 1
233   /// CHECK-DAG:         <<DataOffset:i\d+>>    IntConstant 12
234   /// CHECK:             <<Array:l\d+>>         NewArray
235   /// CHECK:             <<Index:i\d+>>         Phi
236   /// CHECK:                                    If
237   //  -------------- Loop
238   /// CHECK:             <<Address:l\d+>>       Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
239   /// CHECK:             <<ArrayGet:i\d+>>      ArrayGet [<<Address>>,<<Index>>]
240   /// CHECK:             <<Add:i\d+>>           Add [<<ArrayGet>>,<<Const1>>]
241   /// CHECK-NOT:                                Arm64IntermediateAddress
242   /// CHECK:                                    ArraySet [<<Address>>,<<Index>>,<<Add>>]
243 
canMergeAfterBCE1()244   public static int canMergeAfterBCE1() {
245     int[] array = {0, 1, 2, 3};
246     for (int i = 0; i < array.length; i++) {
247       array[i] = array[i] + 1;
248     }
249     return array[array.length - 1];
250   }
251 
252   /**
253    * This test case is similar to `canMergeAfterBCE1`, but with different
254    * indexes for the accesses.
255    */
256 
257   /// CHECK-START-ARM64: int Main.canMergeAfterBCE2() instruction_simplifier_arm64 (before)
258   /// CHECK:             <<Const1:i\d+>>        IntConstant 1
259   /// CHECK:             <<Array:l\d+>>         NewArray
260   /// CHECK:             <<Index:i\d+>>         Phi
261   /// CHECK:                                    If
262   //  -------------- Loop
263   /// CHECK-DAG:         <<Index1:i\d+>>        Add [<<Index>>,<<Const1>>]
264   /// CHECK-DAG:         <<ArrayGetI:i\d+>>     ArrayGet [<<Array>>,<<Index>>]
265   /// CHECK-DAG:         <<ArrayGetI1:i\d+>>    ArrayGet [<<Array>>,<<Index1>>]
266   /// CHECK:             <<Add:i\d+>>           Add [<<ArrayGetI>>,<<ArrayGetI1>>]
267   /// CHECK:                                    ArraySet [<<Array>>,<<Index1>>,<<Add>>]
268 
269   // Note that we do not care that the `DataOffset` is `12`. But if we do not
270   // specify it and any other `IntConstant` appears before that instruction,
271   // checker will match the previous `IntConstant`, and we will thus fail the
272   // check.
273 
274   /// CHECK-START-ARM64: int Main.canMergeAfterBCE2() instruction_simplifier_arm64 (after)
275   /// CHECK-DAG:         <<Const1:i\d+>>        IntConstant 1
276   /// CHECK-DAG:         <<DataOffset:i\d+>>    IntConstant 12
277   /// CHECK:             <<Array:l\d+>>         NewArray
278   /// CHECK:             <<Index:i\d+>>         Phi
279   /// CHECK:                                    If
280   //  -------------- Loop
281   /// CHECK-DAG:         <<Index1:i\d+>>        Add [<<Index>>,<<Const1>>]
282   /// CHECK-DAG:         <<Address1:l\d+>>      Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
283   /// CHECK-DAG:         <<ArrayGetI:i\d+>>     ArrayGet [<<Address1>>,<<Index>>]
284   /// CHECK-DAG:         <<Address2:l\d+>>      Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
285   /// CHECK-DAG:         <<ArrayGetI1:i\d+>>    ArrayGet [<<Address2>>,<<Index1>>]
286   /// CHECK:             <<Add:i\d+>>           Add [<<ArrayGetI>>,<<ArrayGetI1>>]
287   /// CHECK:             <<Address3:l\d+>>      Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
288   /// CHECK:                                    ArraySet [<<Address3>>,<<Index1>>,<<Add>>]
289 
290   /// CHECK-START-ARM64: int Main.canMergeAfterBCE2() GVN_after_arch (after)
291   /// CHECK-DAG:         <<Const1:i\d+>>        IntConstant 1
292   /// CHECK-DAG:         <<DataOffset:i\d+>>    IntConstant 12
293   /// CHECK:             <<Array:l\d+>>         NewArray
294   /// CHECK:             <<Index:i\d+>>         Phi
295   /// CHECK:                                    If
296   //  -------------- Loop
297   /// CHECK-DAG:         <<Index1:i\d+>>        Add [<<Index>>,<<Const1>>]
298   /// CHECK-DAG:         <<Address:l\d+>>       Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
299   /// CHECK-DAG:         <<ArrayGetI:i\d+>>     ArrayGet [<<Address>>,<<Index>>]
300   /// CHECK-DAG:         <<ArrayGetI1:i\d+>>    ArrayGet [<<Address>>,<<Index1>>]
301   /// CHECK:             <<Add:i\d+>>           Add [<<ArrayGetI>>,<<ArrayGetI1>>]
302   /// CHECK:                                    ArraySet [<<Address>>,<<Index1>>,<<Add>>]
303 
304   // There should be only one intermediate address computation in the loop.
305 
306   /// CHECK-START-ARM64: int Main.canMergeAfterBCE2() GVN_after_arch (after)
307   /// CHECK:                                    Arm64IntermediateAddress
308   /// CHECK-NOT:                                Arm64IntermediateAddress
309 
canMergeAfterBCE2()310   public static int canMergeAfterBCE2() {
311     int[] array = {0, 1, 2, 3};
312     for (int i = 0; i < array.length - 1; i++) {
313       array[i + 1] = array[i] + array[i + 1];
314     }
315     return array[array.length - 1];
316   }
317 
318 
main(String[] args)319   public static void main(String[] args) {
320     int[] array = {123, 456, 789};
321 
322     assertIntEquals(456, constantIndexGet(array));
323 
324     constantIndexSet(array);
325     assertIntEquals(2, array[1]);
326 
327     assertIntEquals(789, get(array, 2));
328 
329     set(array, 1, 456);
330     assertIntEquals(456, array[1]);
331 
332     getSet(array, 0);
333     assertIntEquals(124, array[0]);
334 
335     accrossGC(array, 0);
336     assertIntEquals(125, array[0]);
337 
338     assertIntEquals(4, canMergeAfterBCE1());
339     assertIntEquals(6, canMergeAfterBCE2());
340   }
341 }
342