1 /* 2 * Copyright (C) 2016 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 // 18 // Test on loop optimizations, in particular dynamic BCE. In all cases, 19 // bounds check on a[] is resolved statically. Bounds checks on b[] 20 // exercise various different scenarios. In all cases, loop-based 21 // dynamic BCE is better than the dominator-based BCE, since it 22 // generates the test outside the loop. 23 // 24 public class Main { 25 26 /// CHECK-START: void Main.oneConstantIndex(int[], int[]) BCE (before) 27 /// CHECK-DAG: BoundsCheck loop:<<Loop:B\d+>> 28 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 29 // 30 /// CHECK-START: void Main.oneConstantIndex(int[], int[]) BCE (after) 31 /// CHECK-DAG: Deoptimize loop:none 32 /// CHECK-DAG: Deoptimize loop:none 33 /// CHECK-NOT: Deoptimize 34 // 35 /// CHECK-START: void Main.oneConstantIndex(int[], int[]) BCE (after) 36 /// CHECK-NOT: BoundsCheck oneConstantIndex(int[] a, int[] b)37 public static void oneConstantIndex(int[] a, int[] b) { 38 // Dynamic bce on b requires two deopts: one null and one bound. 39 for (int i = 0; i < a.length; i++) { 40 a[i] = b[1]; 41 } 42 } 43 44 /// CHECK-START: void Main.multipleConstantIndices(int[], int[]) BCE (before) 45 /// CHECK-DAG: BoundsCheck loop:<<Loop:B\d+>> 46 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 47 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 48 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 49 // 50 /// CHECK-START: void Main.multipleConstantIndices(int[], int[]) BCE (after) 51 /// CHECK-DAG: Deoptimize loop:none 52 /// CHECK-DAG: Deoptimize loop:none 53 /// CHECK-NOT: Deoptimize 54 // 55 /// CHECK-START: void Main.multipleConstantIndices(int[], int[]) BCE (after) 56 /// CHECK-NOT: BoundsCheck multipleConstantIndices(int[] a, int[] b)57 public static void multipleConstantIndices(int[] a, int[] b) { 58 // Dynamic bce on b requires two deopts: one null and one bound. 59 for (int i = 0; i < a.length; i++) { 60 a[i] = b[0] + b[1] + b[2]; 61 } 62 } 63 64 /// CHECK-START: void Main.oneInvariantIndex(int[], int[], int) BCE (before) 65 /// CHECK-DAG: BoundsCheck loop:<<Loop:B\d+>> 66 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 67 // 68 /// CHECK-START: void Main.oneInvariantIndex(int[], int[], int) BCE (after) 69 /// CHECK-DAG: Deoptimize loop:none 70 /// CHECK-DAG: Deoptimize loop:none 71 /// CHECK-NOT: Deoptimize 72 // 73 /// CHECK-START: void Main.oneInvariantIndex(int[], int[], int) BCE (after) 74 /// CHECK-NOT: BoundsCheck oneInvariantIndex(int[] a, int[] b, int c)75 public static void oneInvariantIndex(int[] a, int[] b, int c) { 76 // Dynamic bce on b requires two deopts: one null and one bound. 77 for (int i = 0; i < a.length; i++) { 78 a[i] = b[c]; 79 } 80 } 81 82 /// CHECK-START: void Main.multipleInvariantIndices(int[], int[], int) BCE (before) 83 /// CHECK-DAG: BoundsCheck loop:<<Loop:B\d+>> 84 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 85 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 86 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 87 // 88 /// CHECK-START: void Main.multipleInvariantIndices(int[], int[], int) BCE (after) 89 /// CHECK-DAG: Deoptimize loop:none 90 /// CHECK-DAG: Deoptimize loop:none 91 /// CHECK-DAG: Deoptimize loop:none 92 /// CHECK-NOT: Deoptimize 93 // 94 /// CHECK-START: void Main.multipleInvariantIndices(int[], int[], int) BCE (after) 95 /// CHECK-NOT: BoundsCheck multipleInvariantIndices(int[] a, int[] b, int c)96 public static void multipleInvariantIndices(int[] a, int[] b, int c) { 97 // Dynamic bce on b requires three deopts: one null and two bounds. 98 for (int i = 0; i < a.length; i++) { 99 a[i] = b[c-1] + b[c] + b[c+1]; 100 } 101 } 102 103 /// CHECK-START: void Main.oneUnitStride(int[], int[]) BCE (before) 104 /// CHECK-DAG: BoundsCheck loop:<<Loop:B\d+>> 105 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 106 // 107 /// CHECK-START: void Main.oneUnitStride(int[], int[]) BCE (after) 108 /// CHECK-DAG: Deoptimize loop:none 109 /// CHECK-DAG: Deoptimize loop:none 110 /// CHECK-DAG: Deoptimize loop:none 111 /// CHECK-NOT: Deoptimize 112 // 113 /// CHECK-START: void Main.oneUnitStride(int[], int[]) BCE (after) 114 /// CHECK-NOT: BoundsCheck oneUnitStride(int[] a, int[] b)115 public static void oneUnitStride(int[] a, int[] b) { 116 // Dynamic bce on b requires three deopts: one null and two bounds. 117 for (int i = 0; i < a.length; i++) { 118 a[i] = b[i]; 119 } 120 } 121 122 /// CHECK-START: void Main.multipleUnitStrides(int[], int[]) BCE (before) 123 /// CHECK-DAG: BoundsCheck loop:<<Loop:B\d+>> 124 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 125 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 126 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 127 // 128 /// CHECK-START: void Main.multipleUnitStrides(int[], int[]) BCE (after) 129 /// CHECK-DAG: Deoptimize loop:none 130 /// CHECK-DAG: Deoptimize loop:none 131 /// CHECK-DAG: Deoptimize loop:none 132 /// CHECK-DAG: Deoptimize loop:none 133 /// CHECK-NOT: Deoptimize 134 // 135 /// CHECK-START: void Main.multipleUnitStrides(int[], int[]) instruction_simplifier$after_bce (after) 136 /// CHECK-DAG: Deoptimize loop:none 137 /// CHECK-DAG: Deoptimize loop:none 138 /// CHECK-DAG: Deoptimize loop:none 139 /// CHECK-NOT: Deoptimize 140 // 141 /// CHECK-START: void Main.multipleUnitStrides(int[], int[]) BCE (after) 142 /// CHECK-NOT: BoundsCheck multipleUnitStrides(int[] a, int[] b)143 public static void multipleUnitStrides(int[] a, int[] b) { 144 // Dynamic bce on b requires four deopts: one null and three bounds. 145 // One redundant deopt is removed by simplifier. 146 // TODO: range information could remove another 147 for (int i = 1; i < a.length - 1; i++) { 148 a[i] = b[i-1] + b[i] + b[i+1]; 149 } 150 } 151 152 /// CHECK-START: void Main.multipleUnitStridesConditional(int[], int[]) BCE (before) 153 /// CHECK-DAG: BoundsCheck loop:<<Loop:B\d+>> 154 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 155 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 156 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 157 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 158 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 159 // 160 /// CHECK-START: void Main.multipleUnitStridesConditional(int[], int[]) BCE (after) 161 /// CHECK-DAG: Deoptimize loop:none 162 /// CHECK-DAG: Deoptimize loop:none 163 /// CHECK-DAG: Deoptimize loop:none 164 /// CHECK-DAG: Deoptimize loop:none 165 /// CHECK-NOT: Deoptimize 166 // 167 /// CHECK-START: void Main.multipleUnitStridesConditional(int[], int[]) instruction_simplifier$after_bce (after) 168 /// CHECK-DAG: Deoptimize loop:none 169 /// CHECK-DAG: Deoptimize loop:none 170 /// CHECK-DAG: Deoptimize loop:none 171 /// CHECK-NOT: Deoptimize 172 // 173 /// CHECK-START: void Main.multipleUnitStridesConditional(int[], int[]) BCE (after) 174 /// CHECK-NOT: BoundsCheck multipleUnitStridesConditional(int[] a, int[] b)175 public static void multipleUnitStridesConditional(int[] a, int[] b) { 176 // Dynamic bce on b requires four deopts: one null and three bounds. 177 // The two conditional references may be included, since they are in range. 178 // One redundant deopt is removed by simplifier. 179 for (int i = 2; i < a.length - 2; i++) { 180 int t = b[i-2] + b[i] + b[i+2] + (((i & 1) == 0) ? b[i+1] : b[i-1]); 181 a[i] = t; 182 } 183 } 184 185 /// CHECK-START: void Main.shifter(int[]) BCE (before) 186 /// CHECK-DAG: BoundsCheck loop:<<Loop:B\d+>> 187 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 188 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 189 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 190 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 191 // 192 /// CHECK-START: void Main.shifter(int[]) BCE (after) 193 /// CHECK-DAG: Deoptimize loop:none 194 /// CHECK-DAG: Deoptimize loop:none 195 /// CHECK-DAG: Deoptimize loop:none 196 /// CHECK-DAG: Deoptimize loop:none 197 /// CHECK-NOT: Deoptimize 198 // 199 /// CHECK-START: void Main.shifter(int[]) instruction_simplifier$after_bce (after) 200 /// CHECK-DAG: Deoptimize loop:none 201 /// CHECK-DAG: Deoptimize loop:none 202 /// CHECK-NOT: Deoptimize 203 // 204 /// CHECK-START: void Main.shifter(int[]) BCE (after) 205 /// CHECK-NOT: BoundsCheck shifter(int[] x)206 public static void shifter(int[] x) { 207 // Real-life example: should have four deopts: one null and three bounds. 208 // Two redundant deopts are removed by simplifier. 209 for (int i = 16; i < 80; i++) { 210 int t = x[i - 3] ^ x[i - 8] ^ x[i - 14] ^ x[i - 16]; 211 x[i] = t << 1 | t >>> 31; 212 } 213 } 214 215 /// CHECK-START: void Main.stencil(int[], int, int) BCE (before) 216 /// CHECK-DAG: BoundsCheck loop:<<Loop:B\d+>> 217 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 218 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 219 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 220 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 221 // 222 /// CHECK-START: void Main.stencil(int[], int, int) BCE (after) 223 /// CHECK-DAG: Deoptimize loop:none 224 /// CHECK-DAG: Deoptimize loop:none 225 /// CHECK-DAG: Deoptimize loop:none 226 /// CHECK-DAG: Deoptimize loop:none 227 /// CHECK-NOT: Deoptimize 228 // 229 /// CHECK-START: void Main.stencil(int[], int, int) BCE (after) 230 /// CHECK-NOT: BoundsCheck stencil(int[] array, int start, int end)231 public static void stencil(int[] array, int start, int end) { 232 // Real-life example: should have four deopts: one null and three bounds. 233 for (int i = end; i >= start; i--) { 234 array[i] = (array[i-2] + array[i-1] + array[i] + array[i+1] + array[i+2]) / 5; 235 } 236 } 237 238 /// CHECK-START: void Main.shortBound1(int[], short) BCE (before) 239 /// CHECK-DAG: BoundsCheck loop:{{B\d+}} 240 // 241 /// CHECK-START: void Main.shortBound1(int[], short) BCE (after) 242 /// CHECK-DAG: Deoptimize loop:none 243 /// CHECK-DAG: Deoptimize loop:none 244 /// CHECK-DAG: Deoptimize loop:none 245 /// CHECK-NOT: Deoptimize 246 // 247 /// CHECK-START: void Main.shortBound1(int[], short) BCE (after) 248 /// CHECK-NOT: BoundsCheck shortBound1(int[] array, short s)249 public static void shortBound1(int[] array, short s) { 250 // Lower precision bound will appear in deopt arithmetic 251 // and follows normal implicit widening conversion. 252 for (int i = 0; i < s; i++) { 253 array[i] = 222; 254 } 255 } 256 257 /// CHECK-START: void Main.shortBound2(int[], short) BCE (before) 258 /// CHECK-DAG: BoundsCheck loop:{{B\d+}} 259 // 260 /// CHECK-START: void Main.shortBound2(int[], short) BCE (after) 261 /// CHECK-DAG: Deoptimize loop:none 262 /// CHECK-DAG: Deoptimize loop:none 263 /// CHECK-DAG: Deoptimize loop:none 264 /// CHECK-NOT: Deoptimize 265 // 266 /// CHECK-START: void Main.shortBound2(int[], short) BCE (after) 267 /// CHECK-NOT: BoundsCheck shortBound2(int[] array, short s)268 public static void shortBound2(int[] array, short s) { 269 // Lower precision bound will appear in deopt arithmetic 270 // and follows normal implicit widening conversion. 271 for (int i = 0; s > i; i++) { 272 array[i] = 444; 273 } 274 } 275 276 /// CHECK-START: void Main.narrowingFromLong(int[], int) BCE (before) 277 /// CHECK-DAG: BoundsCheck loop:{{B\d+}} 278 // 279 /// CHECK-START: void Main.narrowingFromLong(int[], int) BCE (after) 280 /// CHECK-DAG: BoundsCheck loop:{{B\d+}} narrowingFromLong(int[] array, int n)281 public static void narrowingFromLong(int[] array, int n) { 282 // Parallel induction in long precision that is narrowed provides type 283 // conversion challenges for BCE in deopt arithmetic when combined 284 // with the int loop induction. Therefore, currently skipped. 285 long l = 0; 286 for (int i = 0; i < n; i++, l++) { 287 array[(int)l] = 888; 288 } 289 } 290 291 // 292 // Verifier. 293 // 294 main(String[] args)295 public static void main(String[] args) { 296 int[] a = new int[10]; 297 int b[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 298 int b1[] = { 100 }; 299 300 oneConstantIndex(a, b); 301 for (int i = 0; i < a.length; i++) { 302 expectEquals(2, a[i]); 303 } 304 try { 305 oneConstantIndex(a, b1); 306 throw new Error("Should throw AIOOBE"); 307 } catch (ArrayIndexOutOfBoundsException e) { 308 } 309 310 multipleConstantIndices(a, b); 311 for (int i = 0; i < a.length; i++) { 312 expectEquals(6, a[i]); 313 } 314 try { 315 multipleConstantIndices(a, b1); 316 throw new Error("Should throw AIOOBE"); 317 } catch (ArrayIndexOutOfBoundsException e) { 318 } 319 320 oneInvariantIndex(a, b, 1); 321 for (int i = 0; i < a.length; i++) { 322 expectEquals(2, a[i]); 323 } 324 try { 325 oneInvariantIndex(a, b1, 1); 326 throw new Error("Should throw AIOOBE"); 327 } catch (ArrayIndexOutOfBoundsException e) { 328 } 329 330 multipleInvariantIndices(a, b, 1); 331 for (int i = 0; i < a.length; i++) { 332 expectEquals(6, a[i]); 333 } 334 try { 335 multipleInvariantIndices(a, b1, 1); 336 throw new Error("Should throw AIOOBE"); 337 } catch (ArrayIndexOutOfBoundsException e) { 338 } 339 340 oneUnitStride(a, b); 341 for (int i = 0; i < a.length; i++) { 342 expectEquals(i + 1, a[i]); 343 } 344 try { 345 oneUnitStride(a, b1); 346 throw new Error("Should throw AIOOBE"); 347 } catch (ArrayIndexOutOfBoundsException e) { 348 expectEquals(100, a[0]); 349 } 350 351 multipleUnitStrides(a, b); 352 for (int i = 1; i < a.length - 1; i++) { 353 expectEquals(3 * i + 3, a[i]); 354 } 355 try { 356 multipleUnitStrides(a, b1); 357 throw new Error("Should throw AIOOBE"); 358 } catch (ArrayIndexOutOfBoundsException e) { 359 } 360 361 multipleUnitStridesConditional(a, b); 362 for (int i = 2; i < a.length - 2; i++) { 363 int e = 3 * i + 3 + (((i & 1) == 0) ? i + 2 : i); 364 expectEquals(e, a[i]); 365 } 366 try { 367 multipleUnitStridesConditional(a, b1); 368 throw new Error("Should throw AIOOBE"); 369 } catch (ArrayIndexOutOfBoundsException e) { 370 } 371 372 shortBound1(a, (short)a.length); 373 for (int i = 0; i < a.length; i++) { 374 expectEquals(222, a[i]); 375 } 376 shortBound2(a, (short)a.length); 377 for (int i = 0; i < a.length; i++) { 378 expectEquals(444, a[i]); 379 } 380 381 try { 382 shortBound1(a, (short)(a.length + 1)); 383 throw new Error("Should throw AIOOBE"); 384 } catch (ArrayIndexOutOfBoundsException e) { 385 } 386 for (int i = 0; i < a.length; i++) { 387 expectEquals(222, a[i]); 388 } 389 390 try { 391 shortBound2(a, (short)(a.length + 1)); 392 throw new Error("Should throw AIOOBE"); 393 } catch (ArrayIndexOutOfBoundsException e) { 394 } 395 for (int i = 0; i < a.length; i++) { 396 expectEquals(444, a[i]); 397 } 398 399 narrowingFromLong(a, a.length); 400 for (int i = 0; i < a.length; i++) { 401 expectEquals(888, a[i]); 402 } 403 404 System.out.println("passed"); 405 } 406 expectEquals(int expected, int result)407 private static void expectEquals(int expected, int result) { 408 if (expected != result) { 409 throw new Error("Expected: " + expected + ", found: " + result); 410 } 411 } 412 } 413