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 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 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 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 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 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 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 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 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 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 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