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: IntermediateAddress 38 /// CHECK: ArrayGet [<<Array>>,<<Index>>] 39 40 41 /// CHECK-START-ARM: int Main.constantIndexGet(int[]) instruction_simplifier_arm (before) 42 /// CHECK: <<Array:l\d+>> NullCheck 43 /// CHECK: <<Index:i\d+>> BoundsCheck 44 /// CHECK: ArrayGet [<<Array>>,<<Index>>] 45 46 /// CHECK-START-ARM: int Main.constantIndexGet(int[]) instruction_simplifier_arm (after) 47 /// CHECK: <<Array:l\d+>> NullCheck 48 /// CHECK: <<Index:i\d+>> BoundsCheck 49 /// CHECK-NOT: IntermediateAddress 50 /// CHECK: ArrayGet [<<Array>>,<<Index>>] 51 constantIndexGet(int array[])52 public static int constantIndexGet(int array[]) { 53 return array[1]; 54 } 55 56 /** 57 * Test that HArraySet with a constant index is not split. 58 */ 59 60 /// CHECK-START-ARM64: void Main.constantIndexSet(int[]) instruction_simplifier_arm64 (before) 61 /// CHECK: <<Const2:i\d+>> IntConstant 2 62 /// CHECK: <<Array:l\d+>> NullCheck 63 /// CHECK: <<Index:i\d+>> BoundsCheck 64 /// CHECK: ArraySet [<<Array>>,<<Index>>,<<Const2>>] 65 66 /// CHECK-START-ARM64: void Main.constantIndexSet(int[]) instruction_simplifier_arm64 (after) 67 /// CHECK: <<Const2:i\d+>> IntConstant 2 68 /// CHECK: <<Array:l\d+>> NullCheck 69 /// CHECK: <<Index:i\d+>> BoundsCheck 70 /// CHECK-NOT: IntermediateAddress 71 /// CHECK: ArraySet [<<Array>>,<<Index>>,<<Const2>>] 72 73 74 /// CHECK-START-ARM: void Main.constantIndexSet(int[]) instruction_simplifier_arm (before) 75 /// CHECK: <<Const2:i\d+>> IntConstant 2 76 /// CHECK: <<Array:l\d+>> NullCheck 77 /// CHECK: <<Index:i\d+>> BoundsCheck 78 /// CHECK: ArraySet [<<Array>>,<<Index>>,<<Const2>>] 79 80 /// CHECK-START-ARM: void Main.constantIndexSet(int[]) instruction_simplifier_arm (after) 81 /// CHECK: <<Const2:i\d+>> IntConstant 2 82 /// CHECK: <<Array:l\d+>> NullCheck 83 /// CHECK: <<Index:i\d+>> BoundsCheck 84 /// CHECK-NOT: IntermediateAddress 85 /// CHECK: ArraySet [<<Array>>,<<Index>>,<<Const2>>] 86 constantIndexSet(int array[])87 public static void constantIndexSet(int array[]) { 88 array[1] = 2; 89 } 90 91 /** 92 * Test basic splitting of HArrayGet. 93 */ 94 95 /// CHECK-START-ARM64: int Main.get(int[], int) instruction_simplifier_arm64 (before) 96 /// CHECK: <<Array:l\d+>> NullCheck 97 /// CHECK: <<Index:i\d+>> BoundsCheck 98 /// CHECK: ArrayGet [<<Array>>,<<Index>>] 99 100 /// CHECK-START-ARM64: int Main.get(int[], int) instruction_simplifier_arm64 (after) 101 /// CHECK: <<DataOffset:i\d+>> IntConstant 102 /// CHECK: <<Array:l\d+>> NullCheck 103 /// CHECK: <<Index:i\d+>> BoundsCheck 104 /// CHECK: <<Address:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 105 /// CHECK-NEXT: ArrayGet [<<Address>>,<<Index>>] 106 107 108 /// CHECK-START-ARM: int Main.get(int[], int) instruction_simplifier_arm (before) 109 /// CHECK: <<Array:l\d+>> NullCheck 110 /// CHECK: <<Index:i\d+>> BoundsCheck 111 /// CHECK: ArrayGet [<<Array>>,<<Index>>] 112 113 /// CHECK-START-ARM: int Main.get(int[], int) instruction_simplifier_arm (after) 114 /// CHECK: <<DataOffset:i\d+>> IntConstant 115 /// CHECK: <<Array:l\d+>> NullCheck 116 /// CHECK: <<Index:i\d+>> BoundsCheck 117 /// CHECK: <<Address:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 118 /// CHECK-NEXT: ArrayGet [<<Address>>,<<Index>>] 119 get(int array[], int index)120 public static int get(int array[], int index) { 121 return array[index]; 122 } 123 124 /** 125 * Test basic splitting of HArraySet. 126 */ 127 128 /// CHECK-START-ARM64: void Main.set(int[], int, int) instruction_simplifier_arm64 (before) 129 /// CHECK: ParameterValue 130 /// CHECK: ParameterValue 131 /// CHECK: <<Arg:i\d+>> ParameterValue 132 /// CHECK: <<Array:l\d+>> NullCheck 133 /// CHECK: <<Index:i\d+>> BoundsCheck 134 /// CHECK: ArraySet [<<Array>>,<<Index>>,<<Arg>>] 135 136 /// CHECK-START-ARM64: void Main.set(int[], int, int) instruction_simplifier_arm64 (after) 137 /// CHECK: ParameterValue 138 /// CHECK: ParameterValue 139 /// CHECK: <<Arg:i\d+>> ParameterValue 140 /// CHECK: <<DataOffset:i\d+>> IntConstant 141 /// CHECK: <<Array:l\d+>> NullCheck 142 /// CHECK: <<Index:i\d+>> BoundsCheck 143 /// CHECK: <<Address:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 144 /// CHECK-NEXT: ArraySet [<<Address>>,<<Index>>,<<Arg>>] 145 146 147 /// CHECK-START-ARM: void Main.set(int[], int, int) instruction_simplifier_arm (before) 148 /// CHECK: ParameterValue 149 /// CHECK: ParameterValue 150 /// CHECK: <<Arg:i\d+>> ParameterValue 151 /// CHECK: <<Array:l\d+>> NullCheck 152 /// CHECK: <<Index:i\d+>> BoundsCheck 153 /// CHECK: ArraySet [<<Array>>,<<Index>>,<<Arg>>] 154 155 /// CHECK-START-ARM: void Main.set(int[], int, int) instruction_simplifier_arm (after) 156 /// CHECK: ParameterValue 157 /// CHECK: ParameterValue 158 /// CHECK: <<Arg:i\d+>> ParameterValue 159 /// CHECK: <<DataOffset:i\d+>> IntConstant 160 /// CHECK: <<Array:l\d+>> NullCheck 161 /// CHECK: <<Index:i\d+>> BoundsCheck 162 /// CHECK: <<Address:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 163 /// CHECK-NEXT: ArraySet [<<Address>>,<<Index>>,<<Arg>>] 164 set(int array[], int index, int value)165 public static void set(int array[], int index, int value) { 166 array[index] = value; 167 } 168 169 /** 170 * Check that the intermediate address can be shared after GVN. 171 */ 172 173 /// CHECK-START-ARM64: void Main.getSet(int[], int) instruction_simplifier_arm64 (before) 174 /// CHECK: <<Const1:i\d+>> IntConstant 1 175 /// CHECK: <<Array:l\d+>> NullCheck 176 /// CHECK: <<Index:i\d+>> BoundsCheck 177 /// CHECK: <<ArrayGet:i\d+>> ArrayGet [<<Array>>,<<Index>>] 178 /// CHECK: <<Add:i\d+>> Add [<<ArrayGet>>,<<Const1>>] 179 /// CHECK: ArraySet [<<Array>>,<<Index>>,<<Add>>] 180 181 /// CHECK-START-ARM64: void Main.getSet(int[], int) instruction_simplifier_arm64 (after) 182 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 183 /// CHECK-DAG: <<DataOffset:i\d+>> IntConstant 184 /// CHECK: <<Array:l\d+>> NullCheck 185 /// CHECK: <<Index:i\d+>> BoundsCheck 186 /// CHECK: <<Address1:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 187 /// CHECK-NEXT: <<ArrayGet:i\d+>> ArrayGet [<<Address1>>,<<Index>>] 188 /// CHECK: <<Add:i\d+>> Add [<<ArrayGet>>,<<Const1>>] 189 /// CHECK: <<Address2:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 190 /// CHECK-NEXT: ArraySet [<<Address2>>,<<Index>>,<<Add>>] 191 192 /// CHECK-START-ARM64: void Main.getSet(int[], int) GVN$after_arch (after) 193 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 194 /// CHECK-DAG: <<DataOffset:i\d+>> IntConstant 195 /// CHECK: <<Array:l\d+>> NullCheck 196 /// CHECK: <<Index:i\d+>> BoundsCheck 197 /// CHECK: <<Address:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 198 /// CHECK: <<ArrayGet:i\d+>> ArrayGet [<<Address>>,<<Index>>] 199 /// CHECK: <<Add:i\d+>> Add [<<ArrayGet>>,<<Const1>>] 200 /// CHECK-NOT: IntermediateAddress 201 /// CHECK: ArraySet [<<Address>>,<<Index>>,<<Add>>] 202 203 204 /// CHECK-START-ARM: void Main.getSet(int[], int) instruction_simplifier_arm (before) 205 /// CHECK: <<Const1:i\d+>> IntConstant 1 206 /// CHECK: <<Array:l\d+>> NullCheck 207 /// CHECK: <<Index:i\d+>> BoundsCheck 208 /// CHECK: <<ArrayGet:i\d+>> ArrayGet [<<Array>>,<<Index>>] 209 /// CHECK: <<Add:i\d+>> Add [<<ArrayGet>>,<<Const1>>] 210 /// CHECK: ArraySet [<<Array>>,<<Index>>,<<Add>>] 211 212 /// CHECK-START-ARM: void Main.getSet(int[], int) instruction_simplifier_arm (after) 213 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 214 /// CHECK-DAG: <<DataOffset:i\d+>> IntConstant 215 /// CHECK: <<Array:l\d+>> NullCheck 216 /// CHECK: <<Index:i\d+>> BoundsCheck 217 /// CHECK: <<Address1:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 218 /// CHECK-NEXT: <<ArrayGet:i\d+>> ArrayGet [<<Address1>>,<<Index>>] 219 /// CHECK: <<Add:i\d+>> Add [<<ArrayGet>>,<<Const1>>] 220 /// CHECK: <<Address2:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 221 /// CHECK-NEXT: ArraySet [<<Address2>>,<<Index>>,<<Add>>] 222 223 /// CHECK-START-ARM: void Main.getSet(int[], int) GVN$after_arch (after) 224 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 225 /// CHECK-DAG: <<DataOffset:i\d+>> IntConstant 226 /// CHECK: <<Array:l\d+>> NullCheck 227 /// CHECK: <<Index:i\d+>> BoundsCheck 228 /// CHECK: <<Address:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 229 /// CHECK: <<ArrayGet:i\d+>> ArrayGet [<<Address>>,<<Index>>] 230 /// CHECK: <<Add:i\d+>> Add [<<ArrayGet>>,<<Const1>>] 231 /// CHECK-NOT: IntermediateAddress 232 /// CHECK: ArraySet [<<Address>>,<<Index>>,<<Add>>] getSet(int array[], int index)233 public static void getSet(int array[], int index) { 234 array[index] = array[index] + 1; 235 } 236 237 /** 238 * Check that the intermediate address computation is not reordered or merged 239 * across IRs that can trigger GC. 240 */ 241 242 /// CHECK-START-ARM64: int[] Main.accrossGC(int[], int) instruction_simplifier_arm64 (before) 243 /// CHECK: <<Const1:i\d+>> IntConstant 1 244 /// CHECK: <<Array:l\d+>> NullCheck 245 /// CHECK: <<Index:i\d+>> BoundsCheck 246 /// CHECK: <<ArrayGet:i\d+>> ArrayGet [<<Array>>,<<Index>>] 247 /// CHECK: <<Add:i\d+>> Add [<<ArrayGet>>,<<Const1>>] 248 /// CHECK: NewArray 249 /// CHECK: ArraySet [<<Array>>,<<Index>>,<<Add>>] 250 251 /// CHECK-START-ARM64: int[] Main.accrossGC(int[], int) instruction_simplifier_arm64 (after) 252 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 253 /// CHECK-DAG: <<DataOffset:i\d+>> IntConstant 254 /// CHECK: <<Array:l\d+>> NullCheck 255 /// CHECK: <<Index:i\d+>> BoundsCheck 256 /// CHECK: <<Address1:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 257 /// CHECK-NEXT: <<ArrayGet:i\d+>> ArrayGet [<<Address1>>,<<Index>>] 258 /// CHECK: <<Add:i\d+>> Add [<<ArrayGet>>,<<Const1>>] 259 /// CHECK: NewArray 260 /// CHECK: <<Address2:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 261 /// CHECK-NEXT: ArraySet [<<Address2>>,<<Index>>,<<Add>>] 262 263 /// CHECK-START-ARM64: int[] Main.accrossGC(int[], int) GVN$after_arch (after) 264 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 265 /// CHECK-DAG: <<DataOffset:i\d+>> IntConstant 266 /// CHECK: <<Array:l\d+>> NullCheck 267 /// CHECK: <<Index:i\d+>> BoundsCheck 268 /// CHECK: <<Address1:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 269 /// CHECK: <<ArrayGet:i\d+>> ArrayGet [<<Address1>>,<<Index>>] 270 /// CHECK: <<Add:i\d+>> Add [<<ArrayGet>>,<<Const1>>] 271 /// CHECK: NewArray 272 /// CHECK: <<Address2:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 273 /// CHECK: ArraySet [<<Address2>>,<<Index>>,<<Add>>] 274 275 276 /// CHECK-START-ARM: int[] Main.accrossGC(int[], int) instruction_simplifier_arm (before) 277 /// CHECK: <<Const1:i\d+>> IntConstant 1 278 /// CHECK: <<Array:l\d+>> NullCheck 279 /// CHECK: <<Index:i\d+>> BoundsCheck 280 /// CHECK: <<ArrayGet:i\d+>> ArrayGet [<<Array>>,<<Index>>] 281 /// CHECK: <<Add:i\d+>> Add [<<ArrayGet>>,<<Const1>>] 282 /// CHECK: NewArray 283 /// CHECK: ArraySet [<<Array>>,<<Index>>,<<Add>>] 284 285 /// CHECK-START-ARM: int[] Main.accrossGC(int[], int) instruction_simplifier_arm (after) 286 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 287 /// CHECK-DAG: <<DataOffset:i\d+>> IntConstant 288 /// CHECK: <<Array:l\d+>> NullCheck 289 /// CHECK: <<Index:i\d+>> BoundsCheck 290 /// CHECK: <<Address1:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 291 /// CHECK-NEXT: <<ArrayGet:i\d+>> ArrayGet [<<Address1>>,<<Index>>] 292 /// CHECK: <<Add:i\d+>> Add [<<ArrayGet>>,<<Const1>>] 293 /// CHECK: NewArray 294 /// CHECK: <<Address2:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 295 /// CHECK-NEXT: ArraySet [<<Address2>>,<<Index>>,<<Add>>] 296 297 /// CHECK-START-ARM: int[] Main.accrossGC(int[], int) GVN$after_arch (after) 298 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 299 /// CHECK-DAG: <<DataOffset:i\d+>> IntConstant 300 /// CHECK: <<Array:l\d+>> NullCheck 301 /// CHECK: <<Index:i\d+>> BoundsCheck 302 /// CHECK: <<Address1:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 303 /// CHECK: <<ArrayGet:i\d+>> ArrayGet [<<Address1>>,<<Index>>] 304 /// CHECK: <<Add:i\d+>> Add [<<ArrayGet>>,<<Const1>>] 305 /// CHECK: NewArray 306 /// CHECK: <<Address2:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 307 /// CHECK: ArraySet [<<Address2>>,<<Index>>,<<Add>>] 308 accrossGC(int array[], int index)309 public static int[] accrossGC(int array[], int index) { 310 int tmp = array[index] + 1; 311 int[] new_array = new int[1]; 312 array[index] = tmp; 313 return new_array; 314 } 315 316 /** 317 * Test that the intermediate address is shared between array accesses after 318 * the bounds check have been removed by BCE. 319 */ 320 // For checker tests `instruction_simplifier_<arch> (after)` below, by the time we reach 321 // the architecture-specific instruction simplifier, BCE has removed the bounds checks in 322 // the loop. 323 324 // Note that we do not care that the `DataOffset` is `12`. But if we do not 325 // specify it and any other `IntConstant` appears before that instruction, 326 // checker will match the previous `IntConstant`, and we will thus fail the 327 // check. 328 329 /// CHECK-START-ARM64: int Main.canMergeAfterBCE1() instruction_simplifier_arm64 (before) 330 /// CHECK: <<Const7:i\d+>> IntConstant 7 331 /// CHECK: <<Array:l\d+>> NewArray 332 /// CHECK: <<Index:i\d+>> Phi 333 /// CHECK: If 334 // -------------- Loop 335 /// CHECK: <<ArrayGet:i\d+>> ArrayGet [<<Array>>,<<Index>>] 336 /// CHECK: <<Div:i\d+>> Div [<<ArrayGet>>,<<Const7>>] 337 /// CHECK: ArraySet [<<Array>>,<<Index>>,<<Div>>] 338 339 /// CHECK-START-ARM64: int Main.canMergeAfterBCE1() instruction_simplifier_arm64 (after) 340 /// CHECK-DAG: <<Const7:i\d+>> IntConstant 7 341 /// CHECK-DAG: <<DataOffset:i\d+>> IntConstant 12 342 /// CHECK: <<Array:l\d+>> NewArray 343 /// CHECK: <<Index:i\d+>> Phi 344 /// CHECK: If 345 // -------------- Loop 346 /// CHECK: <<Address1:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 347 /// CHECK-NEXT: <<ArrayGet:i\d+>> ArrayGet [<<Address1>>,<<Index>>] 348 /// CHECK: <<Div:i\d+>> Div [<<ArrayGet>>,<<Const7>>] 349 /// CHECK: <<Address2:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 350 /// CHECK-NEXT: ArraySet [<<Address2>>,<<Index>>,<<Div>>] 351 352 /// CHECK-START-ARM64: int Main.canMergeAfterBCE1() GVN$after_arch (after) 353 /// CHECK-DAG: <<Const7:i\d+>> IntConstant 7 354 /// CHECK-DAG: <<DataOffset:i\d+>> IntConstant 12 355 /// CHECK: <<Array:l\d+>> NewArray 356 /// CHECK: <<Index:i\d+>> Phi 357 /// CHECK: If 358 // -------------- Loop 359 /// CHECK: <<Address:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 360 /// CHECK: <<ArrayGet:i\d+>> ArrayGet [<<Address>>,<<Index>>] 361 /// CHECK: <<Div:i\d+>> Div [<<ArrayGet>>,<<Const7>>] 362 /// CHECK-NOT: IntermediateAddress 363 /// CHECK: ArraySet [<<Address>>,<<Index>>,<<Div>>] 364 365 366 /// CHECK-START-ARM: int Main.canMergeAfterBCE1() instruction_simplifier_arm (before) 367 /// CHECK: <<Const7:i\d+>> IntConstant 7 368 /// CHECK: <<Array:l\d+>> NewArray 369 /// CHECK: <<Index:i\d+>> Phi 370 /// CHECK: If 371 // -------------- Loop 372 /// CHECK: <<ArrayGet:i\d+>> ArrayGet [<<Array>>,<<Index>>] 373 /// CHECK: <<Div:i\d+>> Div [<<ArrayGet>>,<<Const7>>] 374 /// CHECK: ArraySet [<<Array>>,<<Index>>,<<Div>>] 375 376 /// CHECK-START-ARM: int Main.canMergeAfterBCE1() instruction_simplifier_arm (after) 377 /// CHECK-DAG: <<Const7:i\d+>> IntConstant 7 378 /// CHECK-DAG: <<DataOffset:i\d+>> IntConstant 12 379 /// CHECK: <<Array:l\d+>> NewArray 380 /// CHECK: <<Index:i\d+>> Phi 381 /// CHECK: If 382 // -------------- Loop 383 /// CHECK: <<Address1:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 384 /// CHECK-NEXT: <<ArrayGet:i\d+>> ArrayGet [<<Address1>>,<<Index>>] 385 /// CHECK: <<Div:i\d+>> Div [<<ArrayGet>>,<<Const7>>] 386 /// CHECK: <<Address2:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 387 /// CHECK-NEXT: ArraySet [<<Address2>>,<<Index>>,<<Div>>] 388 389 /// CHECK-START-ARM: int Main.canMergeAfterBCE1() GVN$after_arch (after) 390 /// CHECK-DAG: <<Const7:i\d+>> IntConstant 7 391 /// CHECK-DAG: <<DataOffset:i\d+>> IntConstant 12 392 /// CHECK: <<Array:l\d+>> NewArray 393 /// CHECK: <<Index:i\d+>> Phi 394 /// CHECK: If 395 // -------------- Loop 396 /// CHECK: <<Address:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 397 /// CHECK: <<ArrayGet:i\d+>> ArrayGet [<<Address>>,<<Index>>] 398 /// CHECK: <<Div:i\d+>> Div [<<ArrayGet>>,<<Const7>>] 399 /// CHECK-NOT: IntermediateAddress 400 /// CHECK: ArraySet [<<Address>>,<<Index>>,<<Div>>] 401 canMergeAfterBCE1()402 public static int canMergeAfterBCE1() { 403 int[] array = {0, 7, 14, 21, 28, 35, 42}; 404 for (int i = 0; i < array.length; i++) { 405 array[i] = array[i] / 7; 406 } 407 return array[array.length - 1]; 408 } 409 410 /** 411 * This test case is similar to `canMergeAfterBCE1`, but with different 412 * indexes for the accesses. 413 */ 414 415 /// CHECK-START-ARM64: int Main.canMergeAfterBCE2() instruction_simplifier_arm64 (before) 416 /// CHECK: <<Const1:i\d+>> IntConstant 1 417 /// CHECK: <<Array:l\d+>> NewArray 418 /// CHECK: <<Index:i\d+>> Phi 419 /// CHECK: If 420 // -------------- Loop 421 /// CHECK-DAG: <<Index1:i\d+>> Add [<<Index>>,<<Const1>>] 422 /// CHECK-DAG: <<ArrayGetI:i\d+>> ArrayGet [<<Array>>,<<Index>>] 423 /// CHECK-DAG: <<ArrayGetI1:i\d+>> ArrayGet [<<Array>>,<<Index1>>] 424 /// CHECK: <<Shl:i\d+>> Shl [<<ArrayGetI>>,<<ArrayGetI1>>] 425 /// CHECK: ArraySet [<<Array>>,<<Index1>>,<<Shl>>] 426 427 // Note that we do not care that the `DataOffset` is `12`. But if we do not 428 // specify it and any other `IntConstant` appears before that instruction, 429 // checker will match the previous `IntConstant`, and we will thus fail the 430 // check. 431 432 /// CHECK-START-ARM64: int Main.canMergeAfterBCE2() instruction_simplifier_arm64 (after) 433 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 434 /// CHECK-DAG: <<DataOffset:i\d+>> IntConstant 12 435 /// CHECK: <<Array:l\d+>> NewArray 436 /// CHECK: <<Index:i\d+>> Phi 437 /// CHECK: If 438 // -------------- Loop 439 /// CHECK-DAG: <<Index1:i\d+>> Add [<<Index>>,<<Const1>>] 440 /// CHECK-DAG: <<Address1:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 441 /// CHECK-DAG: <<ArrayGetI:i\d+>> ArrayGet [<<Address1>>,<<Index>>] 442 /// CHECK-DAG: <<Address2:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 443 /// CHECK-DAG: <<ArrayGetI1:i\d+>> ArrayGet [<<Address2>>,<<Index1>>] 444 /// CHECK: <<Shl:i\d+>> Shl [<<ArrayGetI>>,<<ArrayGetI1>>] 445 /// CHECK: <<Address3:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 446 /// CHECK: ArraySet [<<Address3>>,<<Index1>>,<<Shl>>] 447 448 /// CHECK-START-ARM64: int Main.canMergeAfterBCE2() GVN$after_arch (after) 449 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 450 /// CHECK-DAG: <<DataOffset:i\d+>> IntConstant 12 451 /// CHECK: <<Array:l\d+>> NewArray 452 /// CHECK: <<Index:i\d+>> Phi 453 /// CHECK: If 454 // -------------- Loop 455 /// CHECK-DAG: <<Index1:i\d+>> Add [<<Index>>,<<Const1>>] 456 /// CHECK-DAG: <<Address:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 457 /// CHECK-DAG: <<ArrayGetI:i\d+>> ArrayGet [<<Address>>,<<Index>>] 458 /// CHECK-DAG: <<ArrayGetI1:i\d+>> ArrayGet [<<Address>>,<<Index1>>] 459 /// CHECK: <<Shl:i\d+>> Shl [<<ArrayGetI>>,<<ArrayGetI1>>] 460 /// CHECK: ArraySet [<<Address>>,<<Index1>>,<<Shl>>] 461 462 // There should be only one intermediate address computation in the loop. 463 464 /// CHECK-START-ARM64: int Main.canMergeAfterBCE2() GVN$after_arch (after) 465 /// CHECK: IntermediateAddress 466 /// CHECK-NOT: IntermediateAddress 467 468 469 /// CHECK-START-ARM: int Main.canMergeAfterBCE2() instruction_simplifier_arm (before) 470 /// CHECK: <<Const1:i\d+>> IntConstant 1 471 /// CHECK: <<Array:l\d+>> NewArray 472 /// CHECK: <<Index:i\d+>> Phi 473 /// CHECK: If 474 // -------------- Loop 475 /// CHECK-DAG: <<Index1:i\d+>> Add [<<Index>>,<<Const1>>] 476 /// CHECK-DAG: <<ArrayGetI:i\d+>> ArrayGet [<<Array>>,<<Index>>] 477 /// CHECK-DAG: <<ArrayGetI1:i\d+>> ArrayGet [<<Array>>,<<Index1>>] 478 /// CHECK: <<Shl:i\d+>> Shl [<<ArrayGetI>>,<<ArrayGetI1>>] 479 /// CHECK: ArraySet [<<Array>>,<<Index1>>,<<Shl>>] 480 481 /// CHECK-START-ARM: int Main.canMergeAfterBCE2() instruction_simplifier_arm (after) 482 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 483 /// CHECK-DAG: <<DataOffset:i\d+>> IntConstant 12 484 /// CHECK: <<Array:l\d+>> NewArray 485 /// CHECK: <<Index:i\d+>> Phi 486 /// CHECK: If 487 // -------------- Loop 488 /// CHECK-DAG: <<Index1:i\d+>> Add [<<Index>>,<<Const1>>] 489 /// CHECK-DAG: <<Address1:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 490 /// CHECK-DAG: <<ArrayGetI:i\d+>> ArrayGet [<<Address1>>,<<Index>>] 491 /// CHECK-DAG: <<Address2:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 492 /// CHECK-DAG: <<ArrayGetI1:i\d+>> ArrayGet [<<Address2>>,<<Index1>>] 493 /// CHECK: <<Shl:i\d+>> Shl [<<ArrayGetI>>,<<ArrayGetI1>>] 494 /// CHECK: <<Address3:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 495 /// CHECK: ArraySet [<<Address3>>,<<Index1>>,<<Shl>>] 496 497 /// CHECK-START-ARM: int Main.canMergeAfterBCE2() GVN$after_arch (after) 498 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 499 /// CHECK-DAG: <<DataOffset:i\d+>> IntConstant 12 500 /// CHECK: <<Array:l\d+>> NewArray 501 /// CHECK: <<Index:i\d+>> Phi 502 /// CHECK: If 503 // -------------- Loop 504 /// CHECK-DAG: <<Index1:i\d+>> Add [<<Index>>,<<Const1>>] 505 /// CHECK-DAG: <<Address:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 506 /// CHECK-DAG: <<ArrayGetI:i\d+>> ArrayGet [<<Address>>,<<Index>>] 507 /// CHECK-DAG: <<ArrayGetI1:i\d+>> ArrayGet [<<Address>>,<<Index1>>] 508 /// CHECK: <<Shl:i\d+>> Shl [<<ArrayGetI>>,<<ArrayGetI1>>] 509 /// CHECK: ArraySet [<<Address>>,<<Index1>>,<<Shl>>] 510 511 /// CHECK-START-ARM: int Main.canMergeAfterBCE2() GVN$after_arch (after) 512 /// CHECK: IntermediateAddress 513 /// CHECK-NOT: IntermediateAddress 514 canMergeAfterBCE2()515 public static int canMergeAfterBCE2() { 516 int[] array = {128, 64, 32, 8, 4, 2 }; 517 for (int i = 0; i < array.length - 1; i++) { 518 array[i + 1] = array[i] << array[i + 1]; 519 } 520 return array[array.length - 1]; 521 } 522 523 /// CHECK-START-ARM: int Main.checkLongFloatDouble() instruction_simplifier_arm (before) 524 /// CHECK-DAG: <<Array1:l\d+>> NewArray 525 /// CHECK-DAG: <<Array2:l\d+>> NewArray 526 /// CHECK-DAG: <<Array3:l\d+>> NewArray 527 /// CHECK-DAG: <<Index:i\d+>> Phi 528 /// CHECK-DAG: ArrayGet [<<Array1>>,<<Index>>] 529 /// CHECK-DAG: ArrayGet [<<Array2>>,<<Index>>] 530 /// CHECK-DAG: ArrayGet [<<Array3>>,<<Index>>] 531 532 /// CHECK-START-ARM: int Main.checkLongFloatDouble() instruction_simplifier_arm (after) 533 /// CHECK-DAG: <<Array1:l\d+>> NewArray 534 /// CHECK-DAG: <<Array2:l\d+>> NewArray 535 /// CHECK-DAG: <<Array3:l\d+>> NewArray 536 /// CHECK-DAG: <<Index:i\d+>> Phi 537 /// CHECK-DAG: ArrayGet [<<Array1>>,<<Index>>] 538 /// CHECK-DAG: ArrayGet [<<Array2>>,<<Index>>] 539 /// CHECK-DAG: ArrayGet [<<Array3>>,<<Index>>] 540 541 /// CHECK-START-ARM: int Main.checkLongFloatDouble() instruction_simplifier_arm (after) 542 /// CHECK-NOT: IntermediateAddress checkLongFloatDouble()543 public static int checkLongFloatDouble() { 544 long[] array_long = {0, 1, 2, 3}; 545 float[] array_float = {(float)0.0, (float)1.0, (float)2.0, (float)3.0}; 546 double[] array_double = {0.0, 1.0, 2.0, 3.0}; 547 double s = 0.0; 548 549 for (int i = 0; i < 4; i++) { 550 s += (double)array_long[i] + (double)array_float[i] + array_double[i]; 551 } 552 return (int)s; 553 } 554 555 // 556 // Check that IntermediateAddress can be shared across BoundsCheck, DivZeroCheck and NullCheck - 557 // instruction which have fatal slow paths. 558 // 559 /// CHECK-START-{ARM,ARM64}: void Main.checkGVNForFatalChecks(int, int, char[], int[]) GVN$after_arch (before) 560 /// CHECK: IntermediateAddress 561 /// CHECK: IntermediateAddress 562 // 563 /// CHECK-NOT: IntermediateAddress 564 565 /// CHECK-START-{ARM,ARM64}: void Main.checkGVNForFatalChecks(int, int, char[], int[]) GVN$after_arch (after) 566 /// CHECK: IntermediateAddress 567 // 568 /// CHECK-NOT: IntermediateAddress checkGVNForFatalChecks(int begin, int end, char[] buf1, int[] buf2)569 public final static void checkGVNForFatalChecks(int begin, int end, char[] buf1, int[] buf2) { 570 buf1[begin] = 'a'; 571 buf2[0] = begin / end; 572 buf1[end] = 'n'; 573 } 574 575 // 576 // Check that IntermediateAddress can be shared for object ArrayGets. 577 // 578 /// CHECK-START-ARM64: int Main.checkObjectArrayGet(int, java.lang.Integer[], java.lang.Integer[]) instruction_simplifier_arm64 (before) 579 /// CHECK: <<Parameter:l\d+>> ParameterValue 580 /// CHECK: <<Array:l\d+>> NullCheck [<<Parameter>>] 581 /// CHECK: ArrayGet [<<Array>>,{{i\d+}}] 582 /// CHECK: ArrayGet [<<Array>>,{{i\d+}}] 583 /// CHECK: ArraySet [<<Array>>,{{i\d+}},{{l\d+}}] 584 /// CHECK: ArrayGet [<<Array>>,{{i\d+}}] 585 /// CHECK: ArraySet [<<Array>>,{{i\d+}},{{l\d+}}] 586 /// CHECK: ArraySet [<<Array>>,{{i\d+}},{{l\d+}}] 587 588 /// CHECK-START-ARM64: int Main.checkObjectArrayGet(int, java.lang.Integer[], java.lang.Integer[]) instruction_simplifier_arm64 (after) 589 /// CHECK: <<Parameter:l\d+>> ParameterValue 590 /// CHECK: <<DataOffset:i\d+>> IntConstant 12 591 /// CHECK: <<Array:l\d+>> NullCheck [<<Parameter>>] 592 /// CHECK: <<IntAddr1:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 593 /// CHECK: ArrayGet [<<IntAddr1>>,{{i\d+}}] 594 /// CHECK: <<IntAddr2:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 595 /// CHECK: ArrayGet [<<IntAddr2>>,{{i\d+}}] 596 /// CHECK: ArraySet [<<Array>>,{{i\d+}},{{l\d+}}] 597 /// CHECK: <<IntAddr3:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 598 /// CHECK: ArrayGet [<<IntAddr3>>,{{i\d+}}] 599 /// CHECK: ArraySet [<<Array>>,{{i\d+}},{{l\d+}}] 600 /// CHECK: ArraySet [<<Array>>,{{i\d+}},{{l\d+}}] 601 // 602 /// CHECK-NOT: IntermediateAddress 603 604 /// CHECK-START-ARM64: int Main.checkObjectArrayGet(int, java.lang.Integer[], java.lang.Integer[]) GVN$after_arch (after) 605 /// CHECK: <<Parameter:l\d+>> ParameterValue 606 /// CHECK: <<DataOffset:i\d+>> IntConstant 12 607 /// CHECK: <<Array:l\d+>> NullCheck [<<Parameter>>] 608 /// CHECK: <<IntAddr1:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 609 /// CHECK: ArrayGet [<<IntAddr1>>,{{i\d+}}] 610 /// CHECK: ArrayGet [<<IntAddr1>>,{{i\d+}}] 611 /// CHECK: ArraySet [<<Array>>,{{i\d+}},{{l\d+}}] 612 /// CHECK: <<IntAddr3:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] 613 /// CHECK: ArrayGet [<<IntAddr3>>,{{i\d+}}] 614 /// CHECK: ArraySet [<<Array>>,{{i\d+}},{{l\d+}}] 615 /// CHECK: ArraySet [<<Array>>,{{i\d+}},{{l\d+}}] 616 // 617 /// CHECK-NOT: IntermediateAddress checkObjectArrayGet(int index, Integer[] a, Integer[] b)618 public final static int checkObjectArrayGet(int index, Integer[] a, Integer[] b) { 619 Integer five = Integer.valueOf(5); 620 int tmp1 = a[index]; 621 tmp1 += a[index + 1]; 622 a[index + 1] = five; 623 tmp1 += a[index + 2]; 624 a[index + 2] = five; 625 a[index + 3] = five; 626 return tmp1; 627 } 628 629 /// CHECK-START-ARM64: int Main.testIntAddressObjDisasm(java.lang.Integer[], int) disassembly (after) 630 /// CHECK: <<IntAddr:i\d+>> IntermediateAddress 631 /// CHECK: add w<<AddrReg:\d+>>, {{w\d+}}, #0xc 632 /// CHECK: ArrayGet [<<IntAddr>>,{{i\d+}}] 633 /// CHECK: ldr {{w\d+}}, [x<<AddrReg>>, x{{\d+}}, lsl #2] 634 /// CHECK: ArrayGet [<<IntAddr>>,{{i\d+}}] 635 /// CHECK: ldr {{w\d+}}, [x<<AddrReg>>, x{{\d+}}, lsl #2] 636 637 /// CHECK-START-ARM64: int Main.testIntAddressObjDisasm(java.lang.Integer[], int) disassembly (after) 638 /// CHECK: add {{w\d+}}, {{w\d+}}, #0xc 639 /// CHECK-NOT: add {{w\d+}}, {{w\d+}}, #0xc testIntAddressObjDisasm(Integer[] obj, int x)640 private int testIntAddressObjDisasm(Integer[] obj, int x) { 641 return obj[x] + obj[x + 1]; 642 } 643 644 public final static int ARRAY_SIZE = 128; 645 main(String[] args)646 public static void main(String[] args) { 647 int[] array = {123, 456, 789}; 648 649 assertIntEquals(456, constantIndexGet(array)); 650 651 constantIndexSet(array); 652 assertIntEquals(2, array[1]); 653 654 assertIntEquals(789, get(array, 2)); 655 656 set(array, 1, 456); 657 assertIntEquals(456, array[1]); 658 659 getSet(array, 0); 660 assertIntEquals(124, array[0]); 661 662 accrossGC(array, 0); 663 assertIntEquals(125, array[0]); 664 665 assertIntEquals(6, canMergeAfterBCE1()); 666 assertIntEquals(2097152, canMergeAfterBCE2()); 667 668 assertIntEquals(18, checkLongFloatDouble()); 669 670 char[] c1 = new char[ARRAY_SIZE]; 671 int[] i1 = new int[ARRAY_SIZE]; 672 checkGVNForFatalChecks(1, 2, c1, i1); 673 assertIntEquals('n', c1[2]); 674 } 675 } 676