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 * Regression tests for loop optimizations. 19 */ 20 public class Main { 21 ensureJitCompiled(Class<?> cls, String methodName)22 private static native void ensureJitCompiled(Class<?> cls, String methodName); 23 24 /// CHECK-START: int Main.earlyExitFirst(int) loop_optimization (before) 25 /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none 26 /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none 27 // 28 /// CHECK-START: int Main.earlyExitFirst(int) loop_optimization (after) 29 /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none 30 /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none earlyExitFirst(int m)31 static int earlyExitFirst(int m) { 32 int k = 0; 33 for (int i = 0; i < 10; i++) { 34 if (i == m) { 35 return k; 36 } 37 k++; 38 } 39 return k; 40 } 41 42 /// CHECK-START: int Main.earlyExitLast(int) loop_optimization (before) 43 /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none 44 /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none 45 // 46 /// CHECK-START: int Main.earlyExitLast(int) loop_optimization (after) 47 /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none 48 /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none earlyExitLast(int m)49 static int earlyExitLast(int m) { 50 int k = 0; 51 for (int i = 0; i < 10; i++) { 52 k++; 53 if (i == m) { 54 return k; 55 } 56 } 57 return k; 58 } 59 60 /// CHECK-START: int Main.earlyExitNested() loop_optimization (before) 61 /// CHECK-DAG: Phi loop:<<Loop1:B\d+>> outer_loop:none 62 /// CHECK-DAG: Phi loop:<<Loop1>> outer_loop:none 63 /// CHECK-DAG: Phi loop:<<Loop2:B\d+>> outer_loop:<<Loop1>> 64 /// CHECK-DAG: Phi loop:<<Loop2>> outer_loop:<<Loop1>> 65 // 66 /// CHECK-START: int Main.earlyExitNested() loop_optimization (after) 67 /// CHECK-DAG: Phi loop:<<Loop1:B\d+>> outer_loop:none 68 /// CHECK-DAG: Phi loop:<<Loop1>> outer_loop:none 69 // 70 /// CHECK-START: int Main.earlyExitNested() loop_optimization (after) 71 /// CHECK-NOT: Phi loop:{{B\d+}} outer_loop:{{B\d+}} earlyExitNested()72 static int earlyExitNested() { 73 int offset = 0; 74 for (int i = 0; i < 2; i++) { 75 int start = offset; 76 // This loop can be removed. 77 for (int j = 0; j < 2; j++) { 78 offset++; 79 } 80 if (i == 1) { 81 return start; 82 } 83 } 84 return 0; 85 } 86 87 // Regression test for b/33774618: transfer operations involving 88 // narrowing linear induction should be done correctly. 89 // 90 /// CHECK-START: int Main.transferNarrowWrap() loop_optimization (before) 91 /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none 92 /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none 93 /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none 94 /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none 95 // 96 /// CHECK-START: int Main.transferNarrowWrap() loop_optimization (after) 97 /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none 98 /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none 99 /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none 100 /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none transferNarrowWrap()101 static int transferNarrowWrap() { 102 short x = 0; 103 int w = 10; 104 int v = 3; 105 for (int i = 0; i < 10; i++) { 106 v = w + 1; // transfer on wrap-around 107 w = x; // wrap-around 108 x += 2; // narrowing linear 109 } 110 return v; 111 } 112 113 // Regression test for b/33774618: transfer operations involving 114 // narrowing linear induction should be done correctly 115 // (currently rejected, could be improved). 116 // 117 /// CHECK-START: int Main.polynomialShort() loop_optimization (before) 118 /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none 119 /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none 120 // 121 /// CHECK-START: int Main.polynomialShort() loop_optimization (after) 122 /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none 123 /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none polynomialShort()124 static int polynomialShort() { 125 int x = 0; 126 for (short i = 0; i < 10; i++) { 127 x = x - i; // polynomial on narrowing linear 128 } 129 return x; 130 } 131 132 // Regression test for b/33774618: transfer operations involving 133 // narrowing linear induction should be done correctly 134 // (currently rejected, could be improved). 135 // 136 /// CHECK-START: int Main.polynomialIntFromLong() loop_optimization (before) 137 /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none 138 /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none 139 // 140 /// CHECK-START: int Main.polynomialIntFromLong() loop_optimization (after) 141 /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none 142 /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none polynomialIntFromLong()143 static int polynomialIntFromLong() { 144 int x = 0; 145 for (long i = 0; i < 10; i++) { 146 x = x - (int) i; // polynomial on narrowing linear 147 } 148 return x; 149 } 150 151 /// CHECK-START: int Main.polynomialInt() loop_optimization (before) 152 /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none 153 /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none 154 // 155 /// CHECK-START: int Main.polynomialInt() loop_optimization (after) 156 /// CHECK-NOT: Phi 157 // 158 /// CHECK-START: int Main.polynomialInt() instruction_simplifier$after_bce (after) 159 /// CHECK-DAG: <<Int:i\d+>> IntConstant -45 loop:none 160 /// CHECK-DAG: Return [<<Int>>] loop:none polynomialInt()161 static int polynomialInt() { 162 int x = 0; 163 for (int i = 0; i < 10; i++) { 164 x = x - i; 165 } 166 return x; 167 } 168 169 // Regression test for b/34779592 (found with fuzz testing): overflow for last value 170 // of division truncates to zero, for multiplication it simply truncates. 171 // 172 /// CHECK-START: int Main.geoIntDivLastValue(int) loop_optimization (before) 173 /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none 174 /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none 175 // 176 /// CHECK-START: int Main.geoIntDivLastValue(int) loop_optimization (after) 177 /// CHECK-NOT: Phi 178 // 179 /// CHECK-START: int Main.geoIntDivLastValue(int) instruction_simplifier$after_bce (after) 180 /// CHECK-DAG: <<Int:i\d+>> IntConstant 0 loop:none 181 /// CHECK-DAG: Return [<<Int>>] loop:none geoIntDivLastValue(int x)182 static int geoIntDivLastValue(int x) { 183 for (int i = 0; i < 2; i++) { 184 x /= 1081788608; 185 } 186 return x; 187 } 188 189 /// CHECK-START: int Main.geoIntMulLastValue(int) loop_optimization (before) 190 /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none 191 /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none 192 // 193 /// CHECK-START: int Main.geoIntMulLastValue(int) loop_optimization (after) 194 /// CHECK-NOT: Phi 195 // 196 /// CHECK-START: int Main.geoIntMulLastValue(int) instruction_simplifier$after_bce (after) 197 /// CHECK-DAG: <<Par:i\d+>> ParameterValue loop:none 198 /// CHECK-DAG: <<Int:i\d+>> IntConstant -194211840 loop:none 199 /// CHECK-DAG: <<Mul:i\d+>> Mul [<<Par>>,<<Int>>] loop:none 200 /// CHECK-DAG: Return [<<Mul>>] loop:none geoIntMulLastValue(int x)201 static int geoIntMulLastValue(int x) { 202 for (int i = 0; i < 2; i++) { 203 x *= 1081788608; 204 } 205 return x; 206 } 207 208 /// CHECK-START: long Main.geoLongDivLastValue(long) loop_optimization (before) 209 /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none 210 /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none 211 // 212 /// CHECK-START: long Main.geoLongDivLastValue(long) loop_optimization (after) 213 /// CHECK-NOT: Phi 214 // 215 /// CHECK-START: long Main.geoLongDivLastValue(long) instruction_simplifier$after_bce (after) 216 /// CHECK-DAG: <<Long:j\d+>> LongConstant 0 loop:none 217 /// CHECK-DAG: Return [<<Long>>] loop:none 218 // 219 // Tests overflow in the divisor (while updating intermediate result). geoLongDivLastValue(long x)220 static long geoLongDivLastValue(long x) { 221 for (int i = 0; i < 10; i++) { 222 x /= 1081788608; 223 } 224 return x; 225 } 226 227 /// CHECK-START: long Main.geoLongDivLastValue() loop_optimization (before) 228 /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none 229 /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none 230 // 231 /// CHECK-START: long Main.geoLongDivLastValue() loop_optimization (after) 232 /// CHECK-NOT: Phi 233 // 234 /// CHECK-START: long Main.geoLongDivLastValue() instruction_simplifier$after_bce (after) 235 /// CHECK-DAG: <<Long:j\d+>> LongConstant 0 loop:none 236 /// CHECK-DAG: Return [<<Long>>] loop:none 237 // 238 // Tests overflow in the divisor (while updating base). geoLongDivLastValue()239 static long geoLongDivLastValue() { 240 long x = -1; 241 for (int i2 = 0; i2 < 2; i2++) { 242 x /= (Long.MAX_VALUE); 243 } 244 return x; 245 } 246 247 /// CHECK-START: long Main.geoLongMulLastValue(long) loop_optimization (before) 248 /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none 249 /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none 250 // 251 /// CHECK-START: long Main.geoLongMulLastValue(long) loop_optimization (after) 252 /// CHECK-NOT: Phi 253 // 254 /// CHECK-START: long Main.geoLongMulLastValue(long) instruction_simplifier$after_bce (after) 255 /// CHECK-DAG: <<Par:j\d+>> ParameterValue loop:none 256 /// CHECK-DAG: <<Long:j\d+>> LongConstant -8070450532247928832 loop:none 257 /// CHECK-DAG: <<Mul:j\d+>> Mul [<<Par>>,<<Long>>] loop:none 258 /// CHECK-DAG: Return [<<Mul>>] loop:none geoLongMulLastValue(long x)259 static long geoLongMulLastValue(long x) { 260 for (int i = 0; i < 10; i++) { 261 x *= 1081788608; 262 } 263 return x; 264 } 265 266 // If vectorized, the narrowing subscript should not cause 267 // type inconsistencies in the synthesized code. narrowingSubscript(float[] a)268 static void narrowingSubscript(float[] a) { 269 float val = 2.0f; 270 for (long i = 0; i < a.length; i++) { 271 a[(int) i] += val; 272 } 273 } 274 275 // If vectorized, invariant stride should be recognized 276 // as a reduction, not a unit stride in outer loop. reduc(int[] xx, int[] yy)277 static void reduc(int[] xx, int[] yy) { 278 for (int i0 = 0; i0 < 2; i0++) { 279 for (int i1 = 0; i1 < 469; i1++) { 280 xx[i0] -= (++yy[i1]); 281 } 282 } 283 } 284 285 /// CHECK-START: void Main.string2Bytes(char[], java.lang.String) loop_optimization (before) 286 /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none 287 /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none 288 // 289 /// CHECK-START-ARM: void Main.string2Bytes(char[], java.lang.String) loop_optimization (after) 290 /// CHECK-NOT: VecLoad 291 // 292 /// CHECK-START-ARM64: void Main.string2Bytes(char[], java.lang.String) loop_optimization (after) 293 /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none 294 /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none 295 // 296 // NOTE: should correctly deal with compressed and uncompressed cases. string2Bytes(char[] a, String b)297 private static void string2Bytes(char[] a, String b) { 298 int min = Math.min(a.length, b.length()); 299 for (int i = 0; i < min; i++) { 300 a[i] = b.charAt(i); 301 } 302 } 303 304 /// CHECK-START-ARM: void Main.$noinline$stringToShorts(short[], java.lang.String) loop_optimization (after) 305 /// CHECK-NOT: VecLoad 306 307 /// CHECK-START-ARM64: void Main.$noinline$stringToShorts(short[], java.lang.String) loop_optimization (after) 308 /// CHECK-DAG: VecLoad loop:<<Loop:B\d+>> outer_loop:none 309 /// CHECK-DAG: VecStore loop:<<Loop>> outer_loop:none $noinline$stringToShorts(short[] dest, String src)310 private static void $noinline$stringToShorts(short[] dest, String src) { 311 int min = Math.min(dest.length, src.length()); 312 for (int i = 0; i < min; ++i) { 313 dest[i] = (short) src.charAt(i); 314 } 315 } 316 317 // A strange function that does not inline. $noinline$foo(boolean x, int n)318 private static void $noinline$foo(boolean x, int n) { 319 if (n < 0) 320 throw new Error("oh no"); 321 if (n > 100) { 322 $noinline$foo(!x, n - 1); 323 $noinline$foo(!x, n - 2); 324 $noinline$foo(!x, n - 3); 325 $noinline$foo(!x, n - 4); 326 } 327 } 328 329 // A loop with environment uses of x (the terminating condition). As exposed by bug 330 // b/37247891, the loop can be unrolled, but should handle the (unlikely, but clearly 331 // not impossible) environment uses of the terminating condition in a correct manner. envUsesInCond()332 private static void envUsesInCond() { 333 boolean x = false; 334 for (int i = 0; !(x = i >= 1); i++) { 335 $noinline$foo(true, i); 336 } 337 } 338 339 /// CHECK-START: void Main.oneBoth(short[], char[]) loop_optimization (before) 340 /// CHECK-DAG: <<One:i\d+>> IntConstant 1 loop:none 341 /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none 342 /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<One>>] loop:<<Loop>> outer_loop:none 343 /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<One>>] loop:<<Loop>> outer_loop:none 344 // 345 /// CHECK-START-ARM: void Main.oneBoth(short[], char[]) loop_optimization (after) 346 /// CHECK-DAG: <<One:i\d+>> IntConstant 1 loop:none 347 /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<One>>] loop:none 348 /// CHECK-DAG: VecStore [{{l\d+}},<<Phi:i\d+>>,<<Repl>>] loop:<<Loop:B\d+>> outer_loop:none 349 /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<Repl>>] loop:<<Loop>> outer_loop:none 350 // 351 /// CHECK-START-ARM64: void Main.oneBoth(short[], char[]) loop_optimization (after) 352 /// CHECK-DAG: <<One:i\d+>> IntConstant 1 loop:none 353 /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<One>>] loop:none 354 /// CHECK-DAG: VecStore [{{l\d+}},<<Phi:i\d+>>,<<Repl>>] loop:<<Loop:B\d+>> outer_loop:none 355 /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<Repl>>] loop:<<Loop>> outer_loop:none 356 // 357 // Bug b/37764324: integral same-length packed types can be mixed freely. oneBoth(short[] a, char[] b)358 private static void oneBoth(short[] a, char[] b) { 359 for (int i = 0; i < Math.min(a.length, b.length); i++) { 360 a[i] = 1; 361 b[i] = 1; 362 } 363 } 364 365 // Bug b/37768917: potential dynamic BCE vs. loop optimizations 366 // case should be deal with correctly (used to DCHECK fail). arrayInTripCount(int[] a, byte[] b, int n)367 private static void arrayInTripCount(int[] a, byte[] b, int n) { 368 for (int k = 0; k < n; k++) { 369 for (int i = 0, u = a[0]; i < u; i++) { 370 b[i] += 2; 371 } 372 } 373 } 374 375 /// CHECK-START: void Main.typeConv(byte[], byte[]) loop_optimization (before) 376 /// CHECK-DAG: <<One:i\d+>> IntConstant 1 loop:none 377 /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none 378 /// CHECK-DAG: <<Get:b\d+>> ArrayGet [{{l\d+}},<<Phi>>] loop:<<Loop>> outer_loop:none 379 /// CHECK-DAG: <<Add:i\d+>> Add [<<Get>>,<<One>>] loop:<<Loop>> outer_loop:none 380 /// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<Add>>] loop:<<Loop>> outer_loop:none 381 /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none 382 // 383 /// CHECK-START-ARM: void Main.typeConv(byte[], byte[]) loop_optimization (after) 384 /// CHECK-DAG: <<One:i\d+>> IntConstant 1 loop:none 385 /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<One>>] loop:none 386 /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1:i\d+>>] loop:<<Loop1:B\d+>> outer_loop:none 387 /// CHECK-DAG: <<Vadd:d\d+>> VecAdd [<<Load>>,<<Repl>>] loop:<<Loop1>> outer_loop:none 388 /// CHECK-DAG: VecStore [{{l\d+}},<<Phi1>>,<<Vadd>>] loop:<<Loop1>> outer_loop:none 389 /// CHECK-DAG: <<Get:b\d+>> ArrayGet [{{l\d+}},<<Phi2:i\d+>>] loop:<<Loop2:B\d+>> outer_loop:none 390 /// CHECK-DAG: <<Add:i\d+>> Add [<<Get>>,<<One>>] loop:<<Loop2>> outer_loop:none 391 /// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<Add>>] loop:<<Loop2>> outer_loop:none 392 /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi2>>,<<Cnv>>] loop:<<Loop2>> outer_loop:none 393 // 394 /// CHECK-START-ARM64: void Main.typeConv(byte[], byte[]) loop_optimization (after) 395 /// CHECK-DAG: <<One:i\d+>> IntConstant 1 loop:none 396 /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<One>>] loop:none 397 /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1:i\d+>>] loop:<<Loop1:B\d+>> outer_loop:none 398 /// CHECK-DAG: <<Vadd:d\d+>> VecAdd [<<Load>>,<<Repl>>] loop:<<Loop1>> outer_loop:none 399 /// CHECK-DAG: VecStore [{{l\d+}},<<Phi1>>,<<Vadd>>] loop:<<Loop1>> outer_loop:none 400 /// CHECK-DAG: <<Get:b\d+>> ArrayGet [{{l\d+}},<<Phi2:i\d+>>] loop:<<Loop2:B\d+>> outer_loop:none 401 /// CHECK-DAG: <<Add:i\d+>> Add [<<Get>>,<<One>>] loop:<<Loop2>> outer_loop:none 402 /// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<Add>>] loop:<<Loop2>> outer_loop:none 403 /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi2>>,<<Cnv>>] loop:<<Loop2>> outer_loop:none 404 // 405 // Scalar code in cleanup loop uses correct byte type on array get and type conversion. typeConv(byte[] a, byte[] b)406 private static void typeConv(byte[] a, byte[] b) { 407 int len = Math.min(a.length, b.length); 408 for (int i = 0; i < len; i++) { 409 a[i] = (byte) (b[i] + 1); 410 } 411 } 412 413 // Environment of an instruction, removed during SimplifyInduction, should be adjusted. 414 // 415 /// CHECK-START: void Main.inductionMax(int[]) loop_optimization (before) 416 /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none 417 /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none 418 // 419 /// CHECK-START: void Main.inductionMax(int[]) loop_optimization (after) 420 /// CHECK-NOT: Phi inductionMax(int[] a)421 private static void inductionMax(int[] a) { 422 int s = 0; 423 for (int i = 0; i < 10; i++) { 424 s = Math.max(s, 5); 425 } 426 } 427 428 /// CHECK-START: int Main.feedsIntoDeopt(int[]) loop_optimization (before) 429 /// CHECK-DAG: Phi loop:<<Loop1:B\d+>> outer_loop:none 430 /// CHECK-DAG: Phi loop:<<Loop1>> outer_loop:none 431 /// CHECK-DAG: Phi loop:<<Loop2:B\d+>> outer_loop:none 432 // 433 /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>" 434 // 435 /// CHECK-START: int Main.feedsIntoDeopt(int[]) loop_optimization (after) 436 /// CHECK-DAG: Phi loop:{{B\d+}} outer_loop:none 437 /// CHECK-NOT: Phi feedsIntoDeopt(int[] a)438 static int feedsIntoDeopt(int[] a) { 439 // Reduction should be removed. 440 int r = 0; 441 for (int i = 0; i < 100; i++) { 442 r += 10; 443 } 444 // Even though uses feed into deopts of BCE. 445 for (int i = 1; i < 100; i++) { 446 a[i] = a[i - 1]; 447 } 448 return r; 449 } 450 absCanBeNegative(int x)451 static int absCanBeNegative(int x) { 452 int a[] = { 1, 2, 3 }; 453 int y = 0; 454 for (int i = Math.abs(x); i < a.length; i++) { 455 y += a[i]; 456 } 457 return y; 458 } 459 460 // b/65478356: sum up 2-dim array. sum(int[][] a)461 static int sum(int[][] a) { 462 int sum = 0; 463 for (int y = 0; y < a.length; y++) { 464 int[] aa = a[y]; 465 for (int x = 0; x < aa.length; x++) { 466 sum += aa[x]; 467 } 468 } 469 return sum; 470 } 471 472 // Large loop body should not break unrolling computation. largeBody(int[] x)473 static void largeBody(int[] x) { 474 for (int i = 0; i < 100; i++) { 475 x[i] = x[i] * 1 + x[i] * 2 + x[i] * 3 + x[i] * 4 + x[i] * 5 + x[i] * 6 + 476 x[i] * 7 + x[i] * 8 + x[i] * 9 + x[i] * 10 + x[i] * 11 + x[i] * 12 + 477 x[i] * 13 + x[i] * 14 + x[i] * 15 + x[i] * 1 + x[i] * 2 + x[i] * 3 + x[i] * 4 + 478 x[i] * 5 + x[i] * 6 + x[i] * 7 + x[i] * 8 + x[i] * 9 + x[i] * 10 + x[i] * 11 + 479 x[i] * 12 + x[i] * 13 + x[i] * 14 + x[i] * 15 + x[i] * 1 + x[i] * 2 + x[i] * 3 + 480 x[i] * 4 + x[i] * 5; 481 } 482 } 483 484 // Mixed of 16-bit and 8-bit array references. castAndNarrow(byte[] x, char[] y)485 static void castAndNarrow(byte[] x, char[] y) { 486 for (int i = 0; i < x.length; i++) { 487 x[i] = (byte) ((short) y[i] + 1); 488 } 489 } 490 491 // Avoid bad scheduler-SIMD interaction. doNotMoveSIMD()492 static int doNotMoveSIMD() { 493 int sum = 0; 494 for (int j = 0; j <= 8; j++) { 495 int[] a = new int[17]; // a[i] = 0; 496 // ConstructorFence ? 497 for (int i = 0; i < a.length; i++) { 498 a[i] += 1; // a[i] = 1; 499 } 500 for (int i = 0; i < a.length; i++) { 501 sum += a[i]; // expect a[i] = 1; 502 } 503 } 504 return sum; 505 } 506 507 // Ensure spilling saves full SIMD values. reduction32Values(int[] a, int[] b, int[] c, int[] d)508 private static final int reduction32Values(int[] a, int[] b, int[] c, int[] d) { 509 int s0 = 0; 510 int s1 = 0; 511 int s2 = 0; 512 int s3 = 0; 513 int s4 = 0; 514 int s5 = 0; 515 int s6 = 0; 516 int s7 = 0; 517 int s8 = 0; 518 int s9 = 0; 519 int s10 = 0; 520 int s11 = 0; 521 int s12 = 0; 522 int s13 = 0; 523 int s14 = 0; 524 int s15 = 0; 525 int s16 = 0; 526 int s17 = 0; 527 int s18 = 0; 528 int s19 = 0; 529 int s20 = 0; 530 int s21 = 0; 531 int s22 = 0; 532 int s23 = 0; 533 int s24 = 0; 534 int s25 = 0; 535 int s26 = 0; 536 int s27 = 0; 537 int s28 = 0; 538 int s29 = 0; 539 int s30 = 0; 540 int s31 = 0; 541 for (int i = 1; i < 100; i++) { 542 s0 += a[i]; 543 s1 += b[i]; 544 s2 += c[i]; 545 s3 += d[i]; 546 s4 += a[i]; 547 s5 += b[i]; 548 s6 += c[i]; 549 s7 += d[i]; 550 s8 += a[i]; 551 s9 += b[i]; 552 s10 += c[i]; 553 s11 += d[i]; 554 s12 += a[i]; 555 s13 += b[i]; 556 s14 += c[i]; 557 s15 += d[i]; 558 s16 += a[i]; 559 s17 += b[i]; 560 s18 += c[i]; 561 s19 += d[i]; 562 s20 += a[i]; 563 s21 += b[i]; 564 s22 += c[i]; 565 s23 += d[i]; 566 s24 += a[i]; 567 s25 += b[i]; 568 s26 += c[i]; 569 s27 += d[i]; 570 s28 += a[i]; 571 s29 += b[i]; 572 s30 += c[i]; 573 s31 += d[i]; 574 } 575 return s0 + s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10 + s11 + s12 + s13 + s14 + s15 + 576 s16 + s17 + s18 + s19 + s20 + s21 + s22 + s23 + 577 s24 + s25 + s26 + s27 + s28 + s29 + s30 + s31; 578 } 579 reductionIntoReplication()580 public static int reductionIntoReplication() { 581 int[] a = { 1, 2, 3, 4 }; 582 int x = 0; 583 for (int i = 0; i < 4; i++) { 584 x += a[i]; 585 } 586 for (int i = 0; i < 4; i++) { 587 a[i] = x; 588 } 589 return a[3]; 590 } 591 main(String[] args)592 public static void main(String[] args) { 593 System.loadLibrary(args[0]); 594 595 expectEquals(10, earlyExitFirst(-1)); 596 for (int i = 0; i <= 10; i++) { 597 expectEquals(i, earlyExitFirst(i)); 598 } 599 expectEquals(10, earlyExitFirst(11)); 600 601 expectEquals(10, earlyExitLast(-1)); 602 for (int i = 0; i < 10; i++) { 603 expectEquals(i + 1, earlyExitLast(i)); 604 } 605 expectEquals(10, earlyExitLast(10)); 606 expectEquals(10, earlyExitLast(11)); 607 608 expectEquals(2, earlyExitNested()); 609 610 expectEquals(17, transferNarrowWrap()); 611 expectEquals(-45, polynomialShort()); 612 expectEquals(-45, polynomialIntFromLong()); 613 expectEquals(-45, polynomialInt()); 614 615 expectEquals(0, geoIntDivLastValue(0)); 616 expectEquals(0, geoIntDivLastValue(1)); 617 expectEquals(0, geoIntDivLastValue(2)); 618 expectEquals(0, geoIntDivLastValue(1081788608)); 619 expectEquals(0, geoIntDivLastValue(-1081788608)); 620 expectEquals(0, geoIntDivLastValue(2147483647)); 621 expectEquals(0, geoIntDivLastValue(-2147483648)); 622 623 expectEquals( 0, geoIntMulLastValue(0)); 624 expectEquals( -194211840, geoIntMulLastValue(1)); 625 expectEquals( -388423680, geoIntMulLastValue(2)); 626 expectEquals(-1041498112, geoIntMulLastValue(1081788608)); 627 expectEquals( 1041498112, geoIntMulLastValue(-1081788608)); 628 expectEquals( 194211840, geoIntMulLastValue(2147483647)); 629 expectEquals( 0, geoIntMulLastValue(-2147483648)); 630 631 expectEquals(0L, geoLongDivLastValue(0L)); 632 expectEquals(0L, geoLongDivLastValue(1L)); 633 expectEquals(0L, geoLongDivLastValue(2L)); 634 expectEquals(0L, geoLongDivLastValue(1081788608L)); 635 expectEquals(0L, geoLongDivLastValue(-1081788608L)); 636 expectEquals(0L, geoLongDivLastValue(2147483647L)); 637 expectEquals(0L, geoLongDivLastValue(-2147483648L)); 638 expectEquals(0L, geoLongDivLastValue(9223372036854775807L)); 639 expectEquals(0L, geoLongDivLastValue(-9223372036854775808L)); 640 641 expectEquals(0L, geoLongDivLastValue()); 642 643 expectEquals( 0L, geoLongMulLastValue(0L)); 644 expectEquals(-8070450532247928832L, geoLongMulLastValue(1L)); 645 expectEquals( 2305843009213693952L, geoLongMulLastValue(2L)); 646 expectEquals( 0L, geoLongMulLastValue(1081788608L)); 647 expectEquals( 0L, geoLongMulLastValue(-1081788608L)); 648 expectEquals( 8070450532247928832L, geoLongMulLastValue(2147483647L)); 649 expectEquals( 0L, geoLongMulLastValue(-2147483648L)); 650 expectEquals( 8070450532247928832L, geoLongMulLastValue(9223372036854775807L)); 651 expectEquals( 0L, geoLongMulLastValue(-9223372036854775808L)); 652 653 float[] a = new float[16]; 654 narrowingSubscript(a); 655 for (int i = 0; i < 16; i++) { 656 expectEquals(2.0f, a[i]); 657 } 658 659 int[] xx = new int[2]; 660 int[] yy = new int[469]; 661 reduc(xx, yy); 662 expectEquals(-469, xx[0]); 663 expectEquals(-938, xx[1]); 664 for (int i = 0; i < 469; i++) { 665 expectEquals(2, yy[i]); 666 } 667 668 char[] aa = new char[23]; 669 String bb = "hello world how are you"; 670 string2Bytes(aa, bb); 671 for (int i = 0; i < aa.length; i++) { 672 expectEquals(aa[i], bb.charAt(i)); 673 } 674 String cc = "\u1010\u2020llo world how are y\u3030\u4040"; 675 string2Bytes(aa, cc); 676 for (int i = 0; i < aa.length; i++) { 677 expectEquals(aa[i], cc.charAt(i)); 678 } 679 680 short[] s2s = new short[12]; 681 $noinline$stringToShorts(s2s, "abcdefghijkl"); 682 for (int i = 0; i < s2s.length; ++i) { 683 expectEquals((short) "abcdefghijkl".charAt(i), s2s[i]); 684 } 685 686 envUsesInCond(); 687 688 short[] dd = new short[23]; 689 oneBoth(dd, aa); 690 for (int i = 0; i < aa.length; i++) { 691 expectEquals(aa[i], 1); 692 expectEquals(dd[i], 1); 693 } 694 695 xx[0] = 10; 696 byte[] bt = new byte[10]; 697 arrayInTripCount(xx, bt, 20); 698 for (int i = 0; i < bt.length; i++) { 699 expectEquals(40, bt[i]); 700 } 701 702 byte[] b1 = new byte[259]; // few extra iterations 703 byte[] b2 = new byte[259]; 704 for (int i = 0; i < 259; i++) { 705 b1[i] = 0; 706 b2[i] = (byte) i; 707 } 708 typeConv(b1, b2); 709 for (int i = 0; i < 259; i++) { 710 expectEquals((byte)(i + 1), b1[i]); 711 } 712 713 inductionMax(yy); 714 715 int[] f = new int[100]; 716 f[0] = 11; 717 expectEquals(1000, feedsIntoDeopt(f)); 718 for (int i = 0; i < 100; i++) { 719 expectEquals(11, f[i]); 720 } 721 722 expectEquals(0, absCanBeNegative(-3)); 723 expectEquals(3, absCanBeNegative(-2)); 724 expectEquals(5, absCanBeNegative(-1)); 725 expectEquals(6, absCanBeNegative(0)); 726 expectEquals(5, absCanBeNegative(1)); 727 expectEquals(3, absCanBeNegative(2)); 728 expectEquals(0, absCanBeNegative(3)); 729 expectEquals(0, absCanBeNegative(Integer.MAX_VALUE)); 730 // Abs(min_int) = min_int. 731 int verify = 0; 732 try { 733 absCanBeNegative(Integer.MIN_VALUE); 734 verify = 1; 735 } catch (ArrayIndexOutOfBoundsException e) { 736 verify = 2; 737 } 738 expectEquals(2, verify); 739 740 int[][] x = new int[128][128]; 741 for (int i = 0; i < 128; i++) { 742 for (int j = 0; j < 128; j++) { 743 x[i][j] = -i - j; 744 } 745 } 746 expectEquals(-2080768, sum(x)); 747 748 largeBody(f); 749 for (int i = 0; i < 100; i++) { 750 expectEquals(2805, f[i]); 751 } 752 753 char[] cx = new char[259]; 754 for (int i = 0; i < 259; i++) { 755 cx[i] = (char) (i - 100); 756 } 757 castAndNarrow(b1, cx); 758 for (int i = 0; i < 259; i++) { 759 expectEquals((byte)((short) cx[i] + 1), b1[i]); 760 } 761 762 expectEquals(153, doNotMoveSIMD()); 763 764 // This test exposed SIMDization issues on x86 and x86_64 765 // so we make sure the test runs with JIT enabled. 766 ensureJitCompiled(Main.class, "reduction32Values"); 767 { 768 int[] a1 = new int[100]; 769 int[] a2 = new int[100]; 770 int[] a3 = new int[100]; 771 int[] a4 = new int[100]; 772 for (int i = 0; i < 100; i++) { 773 a1[i] = i; 774 a2[i] = 1; 775 a3[i] = 100 - i; 776 a4[i] = i % 16; 777 } 778 expectEquals(85800, reduction32Values(a1, a2, a3, a4)); 779 } 780 781 expectEquals(10, reductionIntoReplication()); 782 783 System.out.println("passed"); 784 } 785 expectEquals(int expected, int result)786 private static void expectEquals(int expected, int result) { 787 if (expected != result) { 788 throw new Error("Expected: " + expected + ", found: " + result); 789 } 790 } 791 expectEquals(long expected, long result)792 private static void expectEquals(long expected, long result) { 793 if (expected != result) { 794 throw new Error("Expected: " + expected + ", found: " + result); 795 } 796 } 797 expectEquals(float expected, float result)798 private static void expectEquals(float expected, float result) { 799 if (expected != result) { 800 throw new Error("Expected: " + expected + ", found: " + result); 801 } 802 } 803 } 804