1 /* 2 * Copyright (C) 2020 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 { expectEquals(long expected, long result)18 private static void expectEquals(long expected, long result) { 19 if (expected != result) { 20 throw new Error("Expected: " + expected + ", found: " + result); 21 } 22 } 23 expectEquals(long[] div_rem_expected, long[] result)24 private static void expectEquals(long[] div_rem_expected, long[] result) { 25 expectEquals(div_rem_expected[0], result[0]); 26 expectEquals(div_rem_expected[1], result[1]); 27 } 28 remInt()29 private static void remInt() { 30 expectEquals(1L, $noinline$IntDivRemBy18(1)); 31 expectEquals(1L << 32 | 2L, $noinline$IntDivRemBy18(20)); 32 33 expectEquals(1L, $noinline$IntRemDivBy18(1)); 34 expectEquals(1L << 32 | 2L, $noinline$IntRemDivBy18(20)); 35 36 expectEquals(1L, $noinline$IntDivRemBy18(1, false)); 37 expectEquals(1L << 32 | 2L, $noinline$IntDivRemBy18(20, true)); 38 39 expectEquals(1L, $noinline$IntDivRemByMinus18(1)); 40 expectEquals(-1L, $noinline$IntDivRemBy18(-1)); 41 expectEquals((-1L << 32) | 2L, $noinline$IntDivRemByMinus18(20)); 42 expectEquals((1L << 32) | (-2L & 0x00000000ffffffff), $noinline$IntDivRemByMinus18(-20)); 43 44 expectEquals(0L, $noinline$IntDivRemBy5(0)); 45 expectEquals(1L, $noinline$IntDivRemBy5(1)); 46 expectEquals(1L << 32, $noinline$IntDivRemBy5(5)); 47 expectEquals((1L << 32) | 1L, $noinline$IntDivRemBy5(6)); 48 expectEquals((-1L << 32) | 0x00000000ffffffff, $noinline$IntDivRemBy5(-6)); 49 expectEquals(-1L << 32, $noinline$IntDivRemBy5(-5)); 50 expectEquals(0x00000000ffffffff, $noinline$IntDivRemBy5(-1)); 51 52 expectEquals(0L, $noinline$IntDivRemByMinus5(0)); 53 expectEquals(1L, $noinline$IntDivRemByMinus5(1)); 54 expectEquals(-1L << 32, $noinline$IntDivRemByMinus5(5)); 55 expectEquals((-1L << 32) | 1L, $noinline$IntDivRemByMinus5(6)); 56 expectEquals((1L << 32) | 0x00000000ffffffff, $noinline$IntDivRemByMinus5(-6)); 57 expectEquals(1L << 32, $noinline$IntDivRemByMinus5(-5)); 58 expectEquals(0x00000000ffffffff, $noinline$IntDivRemByMinus5(-1)); 59 60 expectEquals(0L, $noinline$IntDivRemBy7(0)); 61 expectEquals(1L, $noinline$IntDivRemBy7(1)); 62 expectEquals(1L << 32, $noinline$IntDivRemBy7(7)); 63 expectEquals((1L << 32) | 1L, $noinline$IntDivRemBy7(8)); 64 expectEquals((-1L << 32) | 0x00000000ffffffff, $noinline$IntDivRemBy7(-8)); 65 expectEquals(-1L << 32, $noinline$IntDivRemBy7(-7)); 66 expectEquals(0x00000000ffffffff, $noinline$IntDivRemBy7(-1)); 67 68 expectEquals(0L, $noinline$IntDivRemByMinus7(0)); 69 expectEquals(1L, $noinline$IntDivRemByMinus7(1)); 70 expectEquals(-1L << 32, $noinline$IntDivRemByMinus7(7)); 71 expectEquals((-1L << 32) | 1L, $noinline$IntDivRemByMinus7(8)); 72 expectEquals((1L << 32) | 0x00000000ffffffff, $noinline$IntDivRemByMinus7(-8)); 73 expectEquals(1L << 32, $noinline$IntDivRemByMinus7(-7)); 74 expectEquals(0x00000000ffffffff, $noinline$IntDivRemByMinus7(-1)); 75 76 expectEquals(0L, $noinline$IntDivRemByMaxInt(0)); 77 expectEquals(1L, $noinline$IntDivRemByMaxInt(1)); 78 expectEquals(1L << 32, $noinline$IntDivRemByMaxInt(Integer.MAX_VALUE)); 79 expectEquals(Integer.MAX_VALUE - 1, $noinline$IntDivRemByMaxInt(Integer.MAX_VALUE - 1)); 80 expectEquals((-1L << 32) | 0x00000000ffffffff, $noinline$IntDivRemByMaxInt(Integer.MIN_VALUE)); 81 expectEquals(0x00000000ffffffff, $noinline$IntDivRemByMaxInt(-1)); 82 } 83 84 // A test case to check: 85 // If there is HDiv with the same inputs as HRem, it is reused. 86 // 87 /// CHECK-START: long Main.$noinline$IntDivRemBy18(int) instruction_simplifier (before) 88 /// CHECK: Div 89 /// CHECK: Rem 90 // 91 /// CHECK-START: long Main.$noinline$IntDivRemBy18(int) instruction_simplifier (after) 92 /// CHECK: Div 93 /// CHECK-NEXT: Mul 94 /// CHECK-NEXT: Sub 95 // 96 /// CHECK-START-ARM64: long Main.$noinline$IntDivRemBy18(int) disassembly (after) 97 /// CHECK: asr x{{\d+}}, x{{\d+}}, #34 98 /// CHECK-NEXT: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31 99 /// CHECK: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}} $noinline$IntDivRemBy18(int v)100 private static long $noinline$IntDivRemBy18(int v) { 101 int q = v / 18; 102 int r = v % 18; 103 return ((long)q << 32) | r; 104 } 105 106 // A test case to check: 107 // If there is HDiv with the same inputs as HRem, it is reused. 108 // 109 /// CHECK-START: long Main.$noinline$IntDivRemByMinus18(int) instruction_simplifier (before) 110 /// CHECK: Div 111 /// CHECK: Rem 112 // 113 /// CHECK-START: long Main.$noinline$IntDivRemByMinus18(int) instruction_simplifier (after) 114 /// CHECK: Div 115 /// CHECK-NEXT: Mul 116 /// CHECK-NEXT: Sub 117 // 118 /// CHECK-START-ARM64: long Main.$noinline$IntDivRemByMinus18(int) disassembly (after) 119 /// CHECK: asr x{{\d+}}, x{{\d+}}, #34 120 /// CHECK-NEXT: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31 121 /// CHECK: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}} $noinline$IntDivRemByMinus18(int v)122 private static long $noinline$IntDivRemByMinus18(int v) { 123 int q = v / -18; 124 int r = v % -18; 125 return ((long)q << 32) | r; 126 } 127 128 // A test case to check: 129 // If there is HDiv with the same inputs as HRem, it is reused. 130 // 131 /// CHECK-START: long Main.$noinline$IntRemDivBy18(int) instruction_simplifier (before) 132 /// CHECK: Rem 133 /// CHECK: Div 134 // 135 /// CHECK-START: long Main.$noinline$IntRemDivBy18(int) instruction_simplifier (after) 136 /// CHECK: Div 137 /// CHECK-NEXT: Mul 138 /// CHECK-NEXT: Sub 139 // 140 /// CHECK-START-ARM64: long Main.$noinline$IntRemDivBy18(int) disassembly (after) 141 /// CHECK: asr x{{\d+}}, x{{\d+}}, #34 142 /// CHECK-NEXT: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31 143 /// CHECK: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}} $noinline$IntRemDivBy18(int v)144 private static long $noinline$IntRemDivBy18(int v) { 145 int r = v % 18; 146 int q = v / 18; 147 return ((long)q << 32) | r; 148 } 149 150 // A test case to check: 151 // If there is HDiv with the same inputs as HRem, it is reused. 152 // 153 /// CHECK-START: long Main.$noinline$IntDivRemBy5(int) instruction_simplifier (before) 154 /// CHECK: Div 155 /// CHECK: Rem 156 // 157 /// CHECK-START: long Main.$noinline$IntDivRemBy5(int) instruction_simplifier (after) 158 /// CHECK: Div 159 /// CHECK-NEXT: Shl 160 /// CHECK-NEXT: Add 161 /// CHECK-NEXT: Sub 162 // 163 /// CHECK-START-ARM64: long Main.$noinline$IntDivRemBy5(int) disassembly (after) 164 /// CHECK: asr x{{\d+}}, x{{\d+}}, #33 165 /// CHECK-NEXT: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31 166 /// CHECK: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsl #2 167 /// CHECK: sub w{{\d+}}, w{{\d+}}, w{{\d+}} $noinline$IntDivRemBy5(int v)168 private static long $noinline$IntDivRemBy5(int v) { 169 int q = v / 5; 170 int r = v % 5; 171 return ((long)q << 32) | r; 172 } 173 174 // A test case to check: 175 // If there is HDiv with the same inputs as HRem, it is reused. 176 // 177 /// CHECK-START: long Main.$noinline$IntDivRemByMinus5(int) instruction_simplifier (before) 178 /// CHECK: Div 179 /// CHECK: Rem 180 // 181 /// CHECK-START: long Main.$noinline$IntDivRemByMinus5(int) instruction_simplifier (after) 182 /// CHECK: Div 183 /// CHECK-NEXT: Mul 184 /// CHECK-NEXT: Sub 185 // 186 /// CHECK-START-ARM64: long Main.$noinline$IntDivRemByMinus5(int) disassembly (after) 187 /// CHECK: asr x{{\d+}}, x{{\d+}}, #33 188 /// CHECK-NEXT: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31 189 /// CHECK: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}} $noinline$IntDivRemByMinus5(int v)190 private static long $noinline$IntDivRemByMinus5(int v) { 191 int q = v / -5; 192 int r = v % -5; 193 return ((long)q << 32) | r; 194 } 195 196 // A test case to check: 197 // If there is HDiv with the same inputs as HRem, it is reused. 198 // 199 /// CHECK-START: long Main.$noinline$IntDivRemBy7(int) instruction_simplifier (before) 200 /// CHECK: Div 201 /// CHECK: Rem 202 // 203 /// CHECK-START: long Main.$noinline$IntDivRemBy7(int) instruction_simplifier (after) 204 /// CHECK: Div 205 /// CHECK-NEXT: Shl 206 /// CHECK-NEXT: Sub 207 /// CHECK-NEXT: Sub 208 // 209 /// CHECK-START-ARM64: long Main.$noinline$IntDivRemBy7(int) instruction_simplifier_arm64 (after) 210 /// CHECK: Div 211 /// CHECK-NEXT: DataProcWithShifterOp 212 /// CHECK-NEXT: Add 213 // 214 /// CHECK-START-ARM64: long Main.$noinline$IntDivRemBy7(int) disassembly (after) 215 /// CHECK: asr x{{\d+}}, x{{\d+}}, #34 216 /// CHECK-NEXT: cinc w{{\d+}}, w{{\d+}}, mi 217 /// CHECK: sub w{{\d+}}, w{{\d+}}, w{{\d+}}, lsl #3 218 /// CHECK: add w{{\d+}}, w{{\d+}}, w{{\d+}} 219 // 220 /// CHECK-START-ARM: long Main.$noinline$IntDivRemBy7(int) instruction_simplifier_arm (after) 221 /// CHECK: Div 222 /// CHECK-NEXT: DataProcWithShifterOp 223 /// CHECK-NEXT: Add 224 // 225 /// CHECK-START-ARM: long Main.$noinline$IntDivRemBy7(int) disassembly (after) 226 /// CHECK: asr{{s?}} r{{\d+}}, #2 227 /// CHECK-NEXT: sub r{{\d+}}, r{{\d+}}, r{{\d+}}, asr #31 228 /// CHECK: sub r{{\d+}}, r{{\d+}}, r{{\d+}}, lsl #3 229 /// CHECK: add{{s?}} r{{\d+}}, r{{\d+}}, r{{\d+}} $noinline$IntDivRemBy7(int v)230 private static long $noinline$IntDivRemBy7(int v) { 231 int q = v / 7; 232 int r = v % 7; 233 return ((long)q << 32) | r; 234 } 235 236 // A test case to check: 237 // If there is HDiv with the same inputs as HRem, it is reused. 238 // 239 /// CHECK-START: long Main.$noinline$IntDivRemByMinus7(int) instruction_simplifier (before) 240 /// CHECK: Div 241 /// CHECK: Rem 242 // 243 /// CHECK-START: long Main.$noinline$IntDivRemByMinus7(int) instruction_simplifier (after) 244 /// CHECK: Div 245 /// CHECK-NEXT: Mul 246 /// CHECK-NEXT: Sub 247 // 248 /// CHECK-START-ARM64: long Main.$noinline$IntDivRemByMinus7(int) disassembly (after) 249 /// CHECK: asr x{{\d+}}, x{{\d+}}, #34 250 /// CHECK-NEXT: cinc w{{\d+}}, w{{\d+}}, mi 251 /// CHECK: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}} $noinline$IntDivRemByMinus7(int v)252 private static long $noinline$IntDivRemByMinus7(int v) { 253 int q = v / -7; 254 int r = v % -7; 255 return ((long)q << 32) | r; 256 } 257 258 // A test case to check: 259 // If there is HDiv with the same inputs as HRem, it is reused. 260 // 261 /// CHECK-START: long Main.$noinline$IntDivRemByMaxInt(int) instruction_simplifier (before) 262 /// CHECK: Div 263 /// CHECK-NEXT: Rem 264 // 265 /// CHECK-START: long Main.$noinline$IntDivRemByMaxInt(int) instruction_simplifier (after) 266 /// CHECK: Div 267 /// CHECK-NEXT: Shl 268 /// CHECK-NEXT: Sub 269 /// CHECK-NEXT: Sub 270 // 271 /// CHECK-START-ARM64: long Main.$noinline$IntDivRemByMaxInt(int) instruction_simplifier_arm64 (after) 272 /// CHECK: Div 273 /// CHECK-NEXT: DataProcWithShifterOp 274 /// CHECK-NEXT: Add 275 // 276 /// CHECK-START-ARM64: long Main.$noinline$IntDivRemByMaxInt(int) disassembly (after) 277 /// CHECK: asr x{{\d+}}, x{{\d+}}, #61 278 /// CHECK-NEXT: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31 279 /// CHECK: sub w{{\d+}}, w{{\d+}}, w{{\d+}}, lsl #31 280 /// CHECK: add w{{\d+}}, w{{\d+}}, w{{\d+}} 281 // 282 /// CHECK-START-ARM: long Main.$noinline$IntDivRemByMaxInt(int) instruction_simplifier_arm (after) 283 /// CHECK: Div 284 /// CHECK-NEXT: DataProcWithShifterOp 285 /// CHECK-NEXT: Add 286 // 287 /// CHECK-START-ARM: long Main.$noinline$IntDivRemByMaxInt(int) disassembly (after) 288 /// CHECK: asr{{s?}} r{{\d+}}, #29 289 /// CHECK-NEXT: sub r{{\d+}}, r{{\d+}}, r{{\d+}}, asr #31 290 /// CHECK: sub r{{\d+}}, r{{\d+}}, r{{\d+}}, lsl #31 291 /// CHECK: add{{s?}} r{{\d+}}, r{{\d+}}, r{{\d+}} $noinline$IntDivRemByMaxInt(int v)292 private static long $noinline$IntDivRemByMaxInt(int v) { 293 int q = v / Integer.MAX_VALUE; 294 int r = v % Integer.MAX_VALUE; 295 return ((long)q << 32) | r; 296 } 297 298 // A test case to check: 299 // HDiv with the same inputs as HRem but in another basic block is not reused. 300 // 301 /// CHECK-START: long Main.$noinline$IntDivRemBy18(int, boolean) instruction_simplifier (before) 302 /// CHECK: Div 303 /// CHECK: Rem 304 // 305 /// CHECK-START: long Main.$noinline$IntDivRemBy18(int, boolean) instruction_simplifier (after) 306 /// CHECK: Div 307 /// CHECK: Rem $noinline$IntDivRemBy18(int v, boolean do_division)308 private static long $noinline$IntDivRemBy18(int v, boolean do_division) { 309 long result = 0; 310 if (do_division) { 311 int q = v / 18; 312 result = (long)q << 32; 313 } 314 int r = v % 18; 315 return result | r; 316 } 317 318 // A test case to check: 319 // If there is HDiv with the same inputs as HRem, it is reused. 320 // 321 /// CHECK-START: long Main.$noinline$IntDivRem(int, int) instruction_simplifier$after_gvn (before) 322 /// CHECK: Div 323 /// CHECK-NEXT: Rem 324 // 325 /// CHECK-START: long Main.$noinline$IntDivRem(int, int) instruction_simplifier$after_gvn (after) 326 /// CHECK: Div 327 /// CHECK-NEXT: Mul 328 /// CHECK-NEXT: Sub $noinline$IntDivRem(int v, int s)329 private static long $noinline$IntDivRem(int v, int s) { 330 int q = v / s; 331 int r = v % s; 332 return ((long)q << 32) | r; 333 } 334 335 // A test case to check: 336 // If there is HDiv with the same inputs as HRem, it is reused. 337 // 338 /// CHECK-START: long Main.$noinline$IntRemDiv(int, int) instruction_simplifier$after_gvn (before) 339 /// CHECK: Rem 340 /// CHECK-NEXT: Div 341 // 342 /// CHECK-START: long Main.$noinline$IntRemDiv(int, int) instruction_simplifier$after_gvn (after) 343 /// CHECK: Div 344 /// CHECK-NEXT: Mul 345 /// CHECK-NEXT: Sub $noinline$IntRemDiv(int v, int s)346 private static long $noinline$IntRemDiv(int v, int s) { 347 int r = v % s; 348 int q = v / s; 349 return ((long)q << 32) | r; 350 } 351 352 // A test case to check: 353 // HDiv with the same inputs as HRem but in another basic block is not reused. 354 // 355 /// CHECK-START: long Main.$noinline$IntDivRem(int, int, boolean) instruction_simplifier (before) 356 /// CHECK: Div 357 /// CHECK: Rem 358 // 359 /// CHECK-START: long Main.$noinline$IntDivRem(int, int, boolean) instruction_simplifier (after) 360 /// CHECK: Div 361 /// CHECK: Rem $noinline$IntDivRem(int v, int s, boolean do_division)362 private static long $noinline$IntDivRem(int v, int s, boolean do_division) { 363 long result = 0; 364 if (do_division) { 365 int q = v / s; 366 result = (long)q << 32; 367 } 368 int r = v % s; 369 return result | r; 370 } 371 372 // A test case to check: 373 // If HRem is in a loop, the instruction simplifier postpones its optimization till 374 // loop analysis/optimizations are done. 375 // 376 /// CHECK-START: int Main.$noinline$IntRemBy18InLoop(int) instruction_simplifier (before) 377 /// CHECK: Div loop:B{{\d+}} 378 /// CHECK-NEXT: Rem loop:B{{\d+}} 379 // 380 /// CHECK-START: int Main.$noinline$IntRemBy18InLoop(int) instruction_simplifier (after) 381 /// CHECK: Div loop:B{{\d+}} 382 /// CHECK-NEXT: Rem loop:B{{\d+}} 383 // 384 /// CHECK-START: int Main.$noinline$IntRemBy18InLoop(int) instruction_simplifier$after_bce (before) 385 /// CHECK: Div loop:B{{\d+}} 386 /// CHECK-NEXT: Rem loop:B{{\d+}} 387 // 388 /// CHECK-START: int Main.$noinline$IntRemBy18InLoop(int) instruction_simplifier$after_bce (after) 389 /// CHECK-NOT: Rem 390 /// CHECK: Div loop:B{{\d+}} 391 /// CHECK-NEXT: Mul loop:B{{\d+}} 392 /// CHECK-NEXT: Sub loop:B{{\d+}} $noinline$IntRemBy18InLoop(int v)393 private static int $noinline$IntRemBy18InLoop(int v) { 394 int[] values = new int[v]; 395 for (int i = 0; i < values.length; ++i) { 396 int q = i / 18; 397 int r = i % 18; 398 values[i] = q + r; 399 } 400 return values[v - 1]; 401 } 402 403 // A test case to check: 404 // FP type HRem is not optimized by the instruction simplifier. 405 // 406 /// CHECK-START: float Main.$noinline$FloatRemBy18(float) instruction_simplifier (before) 407 /// CHECK: Div 408 /// CHECK-NEXT: Rem 409 // 410 /// CHECK-START: float Main.$noinline$FloatRemBy18(float) instruction_simplifier (after) 411 /// CHECK: Div 412 /// CHECK-NEXT: Rem $noinline$FloatRemBy18(float v)413 private static float $noinline$FloatRemBy18(float v) { 414 float q = v / 18.0f; 415 float r = v % 18.0f; 416 return q + r; 417 } 418 419 // A test case to check: 420 // FP type HRem is not optimized by the instruction simplifier. 421 // 422 /// CHECK-START: double Main.$noinline$DoubleRemBy18(double) instruction_simplifier (before) 423 /// CHECK: Div 424 /// CHECK-NEXT: Rem 425 // 426 /// CHECK-START: double Main.$noinline$DoubleRemBy18(double) instruction_simplifier (after) 427 /// CHECK: Div 428 /// CHECK-NEXT: Rem $noinline$DoubleRemBy18(double v)429 private static double $noinline$DoubleRemBy18(double v) { 430 double q = v / 18.0; 431 double r = v % 18.0; 432 return q + r; 433 } 434 435 // A test case to check: 436 // HRem with a divisor of power 2 is not optimized by the instruction simplifier because 437 // the case is optimized by the code generator. 438 // 439 /// CHECK-START: int Main.$noinline$IntRemByIntMin(int) instruction_simplifier (before) 440 /// CHECK: Div 441 /// CHECK-NEXT: Rem 442 // 443 /// CHECK-START: int Main.$noinline$IntRemByIntMin(int) instruction_simplifier (after) 444 /// CHECK: Div 445 /// CHECK-NEXT: Rem $noinline$IntRemByIntMin(int v)446 private static int $noinline$IntRemByIntMin(int v) { 447 int q = v / Integer.MIN_VALUE; 448 int r = v % Integer.MIN_VALUE; 449 return q + r; 450 } 451 remLong()452 private static void remLong() { 453 expectEquals(1L, $noinline$LongDivRemBy18(1L)); 454 expectEquals(1L << 32 | 2L, $noinline$LongDivRemBy18(20L)); 455 456 expectEquals(1L, $noinline$LongRemDivBy18(1L)); 457 expectEquals(1L << 32 | 2L, $noinline$LongRemDivBy18(20L)); 458 459 expectEquals(1L, $noinline$LongDivRemBy18(1L, false)); 460 expectEquals(1L << 32 | 2L, $noinline$LongDivRemBy18(20L, true)); 461 462 expectEquals(new long[] {0L, 1L}, $noinline$LongDivRemByMinus18(1)); 463 expectEquals(new long[] {0L, -1L}, $noinline$LongDivRemByMinus18(-1)); 464 expectEquals(new long[] {-1L, 2L}, $noinline$LongDivRemByMinus18(20)); 465 expectEquals(new long[] {1L, -2L}, $noinline$LongDivRemByMinus18(-20)); 466 467 expectEquals(new long[] {0L, 0L}, $noinline$LongDivRemBy5(0)); 468 expectEquals(new long[] {0L, 1L}, $noinline$LongDivRemBy5(1)); 469 expectEquals(new long[] {1L, 0L}, $noinline$LongDivRemBy5(5)); 470 expectEquals(new long[] {1L, 1L}, $noinline$LongDivRemBy5(6)); 471 expectEquals(new long[] {-1L, -1L}, $noinline$LongDivRemBy5(-6)); 472 expectEquals(new long[] {-1L, 0L}, $noinline$LongDivRemBy5(-5)); 473 expectEquals(new long[] {0L, -1L}, $noinline$LongDivRemBy5(-1)); 474 475 expectEquals(new long[] {0L, 0L}, $noinline$LongDivRemByMinus5(0)); 476 expectEquals(new long[] {0L, 1L}, $noinline$LongDivRemByMinus5(1)); 477 expectEquals(new long[] {-1L, 0L}, $noinline$LongDivRemByMinus5(5)); 478 expectEquals(new long[] {-1L, 1L}, $noinline$LongDivRemByMinus5(6)); 479 expectEquals(new long[] {1L, -1L}, $noinline$LongDivRemByMinus5(-6)); 480 expectEquals(new long[] {1L, 0L}, $noinline$LongDivRemByMinus5(-5)); 481 expectEquals(new long[] {0L, -1L}, $noinline$LongDivRemByMinus5(-1)); 482 483 expectEquals(new long[] {0L, 0L}, $noinline$LongDivRemBy7(0)); 484 expectEquals(new long[] {0L, 1L}, $noinline$LongDivRemBy7(1)); 485 expectEquals(new long[] {1L, 0L}, $noinline$LongDivRemBy7(7)); 486 expectEquals(new long[] {1L, 1L}, $noinline$LongDivRemBy7(8)); 487 expectEquals(new long[] {-1L, -1L}, $noinline$LongDivRemBy7(-8)); 488 expectEquals(new long[] {-1L, 0L}, $noinline$LongDivRemBy7(-7)); 489 expectEquals(new long[] {0L, -1L}, $noinline$LongDivRemBy7(-1)); 490 491 expectEquals(new long[] {0L, 0L}, $noinline$LongDivRemByMinus7(0)); 492 expectEquals(new long[] {0L, 1L}, $noinline$LongDivRemByMinus7(1)); 493 expectEquals(new long[] {-1L, 0L}, $noinline$LongDivRemByMinus7(7)); 494 expectEquals(new long[] {-1L, 1L}, $noinline$LongDivRemByMinus7(8)); 495 expectEquals(new long[] {1L, -1L}, $noinline$LongDivRemByMinus7(-8)); 496 expectEquals(new long[] {1L, 0L}, $noinline$LongDivRemByMinus7(-7)); 497 expectEquals(new long[] {0L, -1L}, $noinline$LongDivRemByMinus7(-1)); 498 499 expectEquals(new long[] {0L, 0L}, $noinline$LongDivRemByMaxLong(0)); 500 expectEquals(new long[] {0L, 1L}, $noinline$LongDivRemByMaxLong(1)); 501 expectEquals(new long[] {1L, 0L}, $noinline$LongDivRemByMaxLong(Long.MAX_VALUE)); 502 expectEquals(new long[] {0L, Long.MAX_VALUE - 1}, 503 $noinline$LongDivRemByMaxLong(Long.MAX_VALUE - 1)); 504 expectEquals(new long[] {-1L, -1L}, $noinline$LongDivRemByMaxLong(Long.MIN_VALUE)); 505 expectEquals(new long[] {0L, -1L}, $noinline$LongDivRemByMaxLong(-1)); 506 } 507 508 // A test case to check: 509 // If there is HDiv with the same inputs as HRem, it is reused. 510 // 511 /// CHECK-START: long Main.$noinline$LongDivRemBy18(long) instruction_simplifier (before) 512 /// CHECK: Div 513 /// CHECK: Rem 514 // 515 /// CHECK-START: long Main.$noinline$LongDivRemBy18(long) instruction_simplifier (after) 516 /// CHECK: Div 517 /// CHECK-NEXT: Mul 518 /// CHECK-NEXT: Sub $noinline$LongDivRemBy18(long v)519 private static long $noinline$LongDivRemBy18(long v) { 520 long q = v / 18L; 521 long r = v % 18L; 522 return (q << 32) | r; 523 } 524 525 // A test case to check: 526 // If there is HDiv with the same inputs as HRem, it is reused. 527 // 528 /// CHECK-START: long[] Main.$noinline$LongDivRemByMinus18(long) instruction_simplifier (before) 529 /// CHECK: Div 530 /// CHECK: Rem 531 // 532 /// CHECK-START: long[] Main.$noinline$LongDivRemByMinus18(long) instruction_simplifier (after) 533 /// CHECK: Div 534 /// CHECK-NEXT: Mul 535 /// CHECK-NEXT: Sub 536 // 537 /// CHECK-START-ARM64: long[] Main.$noinline$LongDivRemByMinus18(long) disassembly (after) 538 /// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}} 539 /// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63 540 /// CHECK: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} $noinline$LongDivRemByMinus18(long v)541 private static long[] $noinline$LongDivRemByMinus18(long v) { 542 long q = v / -18L; 543 long r = v % -18L; 544 return new long[] {q, r}; 545 } 546 547 // A test case to check: 548 // If there is HDiv with the same inputs as HRem, it is reused. 549 // 550 /// CHECK-START: long Main.$noinline$LongRemDivBy18(long) instruction_simplifier (before) 551 /// CHECK: Rem 552 /// CHECK: Div 553 // 554 /// CHECK-START: long Main.$noinline$LongRemDivBy18(long) instruction_simplifier (after) 555 /// CHECK: Div 556 /// CHECK-NEXT: Mul 557 /// CHECK-NEXT: Sub $noinline$LongRemDivBy18(long v)558 private static long $noinline$LongRemDivBy18(long v) { 559 long r = v % 18L; 560 long q = v / 18L; 561 return (q << 32) | r; 562 } 563 564 // A test case to check: 565 // If there is HDiv with the same inputs as HRem, it is reused. 566 // 567 /// CHECK-START: long[] Main.$noinline$LongDivRemBy5(long) instruction_simplifier (before) 568 /// CHECK: Div 569 /// CHECK: Rem 570 // 571 /// CHECK-START: long[] Main.$noinline$LongDivRemBy5(long) instruction_simplifier (after) 572 /// CHECK: Div 573 /// CHECK-NEXT: Shl 574 /// CHECK-NEXT: Add 575 /// CHECK-NEXT: Sub 576 // 577 /// CHECK-START-ARM64: long[] Main.$noinline$LongDivRemBy5(long) disassembly (after) 578 /// CHECK: asr x{{\d+}}, x{{\d+}}, #1 579 /// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63 580 /// CHECK: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsl #2 581 /// CHECK: sub x{{\d+}}, x{{\d+}}, x{{\d+}} $noinline$LongDivRemBy5(long v)582 private static long[] $noinline$LongDivRemBy5(long v) { 583 long q = v / 5L; 584 long r = v % 5L; 585 return new long[] {q, r}; 586 } 587 588 // A test case to check: 589 // If there is HDiv with the same inputs as HRem, it is reused. 590 // 591 /// CHECK-START: long[] Main.$noinline$LongDivRemByMinus5(long) instruction_simplifier (before) 592 /// CHECK: Div 593 /// CHECK: Rem 594 // 595 /// CHECK-START: long[] Main.$noinline$LongDivRemByMinus5(long) instruction_simplifier (after) 596 /// CHECK: Div 597 /// CHECK-NEXT: Mul 598 /// CHECK-NEXT: Sub 599 // 600 /// CHECK-START-ARM64: long[] Main.$noinline$LongDivRemByMinus5(long) disassembly (after) 601 /// CHECK: asr x{{\d+}}, x{{\d+}}, #1 602 /// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63 603 /// CHECK: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} $noinline$LongDivRemByMinus5(long v)604 private static long[] $noinline$LongDivRemByMinus5(long v) { 605 long q = v / -5L; 606 long r = v % -5L; 607 return new long[] {q, r}; 608 } 609 610 // A test case to check: 611 // If there is HDiv with the same inputs as HRem, it is reused. 612 // 613 /// CHECK-START: long[] Main.$noinline$LongDivRemBy7(long) instruction_simplifier (before) 614 /// CHECK: Div 615 /// CHECK: Rem 616 // 617 /// CHECK-START: long[] Main.$noinline$LongDivRemBy7(long) instruction_simplifier (after) 618 /// CHECK: Div 619 /// CHECK-NEXT: Shl 620 /// CHECK-NEXT: Sub 621 /// CHECK-NEXT: Sub 622 // 623 /// CHECK-START-ARM64: long[] Main.$noinline$LongDivRemBy7(long) instruction_simplifier_arm64 (after) 624 /// CHECK: Div 625 /// CHECK-NEXT: DataProcWithShifterOp 626 /// CHECK-NEXT: Add 627 // 628 /// CHECK-START-ARM64: long[] Main.$noinline$LongDivRemBy7(long) disassembly (after) 629 /// CHECK: asr x{{\d+}}, x{{\d+}}, #1 630 /// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63 631 /// CHECK: sub x{{\d+}}, x{{\d+}}, x{{\d+}}, lsl #3 632 /// CHECK: add x{{\d+}}, x{{\d+}}, x{{\d+}} 633 // 634 /// CHECK-START-ARM: long[] Main.$noinline$LongDivRemBy7(long) instruction_simplifier_arm (after) 635 /// CHECK: Div 636 /// CHECK-NEXT: DataProcWithShifterOp 637 /// CHECK-NEXT: Add 638 // 639 /// CHECK-START-ARM: long[] Main.$noinline$LongDivRemBy7(long) disassembly (after) 640 /// CHECK: blx lr 641 // CHECK: lsl ip, r{{\d}}, #3 642 // CHECK-NEXT: orr ip, r{{\d}}, lsr #29 643 // CHECK-NEXT: sub r{{\d}}, r{{\d}}, r{{\d}}, lsl #3 644 // CHECK-NEXT: sbc{{s?}} r{{\d}}, r{{\d}}, ip 645 /// CHECK: add{{s?}} r{{\d}}, r{{\d}} 646 /// CHECK-NEXT: adc{{s?}} r{{\d}}, r{{\d}} $noinline$LongDivRemBy7(long v)647 private static long[] $noinline$LongDivRemBy7(long v) { 648 long q = v / 7L; 649 long r = v % 7L; 650 return new long[] {q, r}; 651 } 652 653 // A test case to check: 654 // If there is HDiv with the same inputs as HRem, it is reused. 655 // 656 /// CHECK-START: long[] Main.$noinline$LongDivRemByMinus7(long) instruction_simplifier (before) 657 /// CHECK: Div 658 /// CHECK: Rem 659 // 660 /// CHECK-START: long[] Main.$noinline$LongDivRemByMinus7(long) instruction_simplifier (after) 661 /// CHECK: Div 662 /// CHECK-NEXT: Mul 663 /// CHECK-NEXT: Sub 664 // 665 /// CHECK-START-ARM64: long[] Main.$noinline$LongDivRemByMinus7(long) disassembly (after) 666 /// CHECK: asr x{{\d+}}, x{{\d+}}, #1 667 /// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63 668 /// CHECK: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} $noinline$LongDivRemByMinus7(long v)669 private static long[] $noinline$LongDivRemByMinus7(long v) { 670 long q = v / -7L; 671 long r = v % -7L; 672 return new long[] {q, r}; 673 } 674 675 // A test case to check: 676 // If there is HDiv with the same inputs as HRem, it is reused. 677 // 678 /// CHECK-START: long[] Main.$noinline$LongDivRemByMaxLong(long) instruction_simplifier (before) 679 /// CHECK: Div 680 /// CHECK: Rem 681 // 682 /// CHECK-START: long[] Main.$noinline$LongDivRemByMaxLong(long) instruction_simplifier (after) 683 /// CHECK: Div 684 /// CHECK-NEXT: Shl 685 /// CHECK-NEXT: Sub 686 /// CHECK-NEXT: Sub 687 // 688 /// CHECK-START-ARM64: long[] Main.$noinline$LongDivRemByMaxLong(long) instruction_simplifier_arm64 (after) 689 /// CHECK: Div 690 /// CHECK-NEXT: DataProcWithShifterOp 691 /// CHECK-NEXT: Add 692 // 693 /// CHECK-START-ARM64: long[] Main.$noinline$LongDivRemByMaxLong(long) disassembly (after) 694 /// CHECK: asr x{{\d+}}, x{{\d+}}, #61 695 /// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63 696 /// CHECK: sub x{{\d+}}, x{{\d+}}, x{{\d+}}, lsl #63 697 /// CHECK: add x{{\d+}}, x{{\d+}}, x{{\d+}} 698 // 699 /// CHECK-START-ARM: long[] Main.$noinline$LongDivRemByMaxLong(long) instruction_simplifier_arm (after) 700 /// CHECK: Div 701 /// CHECK-NEXT: DataProcWithShifterOp 702 /// CHECK-NEXT: Add 703 // 704 /// CHECK-START-ARM: long[] Main.$noinline$LongDivRemByMaxLong(long) disassembly (after) 705 /// CHECK: blx lr 706 // CHECK: sub r{{\d}}, r{{\d}}, r{{\d}}, lsl #31 707 // CHECK-NEXT: mov{{s?}} r{{\d}}, r{{\d}} 708 /// CHECK: add{{s?}} r{{\d}}, r{{\d}} 709 /// CHECK-NEXT: adc{{s?}} r{{\d}}, r{{\d}} $noinline$LongDivRemByMaxLong(long v)710 private static long[] $noinline$LongDivRemByMaxLong(long v) { 711 long q = v / Long.MAX_VALUE; 712 long r = v % Long.MAX_VALUE; 713 return new long[] {q, r}; 714 } 715 716 // A test case to check: 717 // HDiv with the same inputs as HRem but in another basic block is not reused. 718 // 719 /// CHECK-START: long Main.$noinline$LongDivRemBy18(long, boolean) instruction_simplifier (before) 720 /// CHECK: Div 721 /// CHECK: Rem 722 // 723 /// CHECK-START: long Main.$noinline$LongDivRemBy18(long, boolean) instruction_simplifier (after) 724 /// CHECK: Div 725 /// CHECK: Rem $noinline$LongDivRemBy18(long v, boolean do_division)726 private static long $noinline$LongDivRemBy18(long v, boolean do_division) { 727 long result = 0; 728 if (do_division) { 729 long q = v / 18L; 730 result = q << 32; 731 } 732 long r = v % 18L; 733 return result | r; 734 } 735 736 // A test case to check: 737 // If there is HDiv with the same inputs as HRem, it is reused. 738 // 739 /// CHECK-START: long Main.$noinline$LongDivRem(long, long) instruction_simplifier$after_gvn (before) 740 /// CHECK: Div 741 /// CHECK-NEXT: Rem 742 // 743 /// CHECK-START: long Main.$noinline$LongDivRem(long, long) instruction_simplifier$after_gvn (after) 744 /// CHECK: Div 745 /// CHECK-NEXT: Mul 746 /// CHECK-NEXT: Sub $noinline$LongDivRem(long v, long s)747 private static long $noinline$LongDivRem(long v, long s) { 748 long q = v / s; 749 long r = v % s; 750 return (q << 32) | r; 751 } 752 753 // A test case to check: 754 // If there is HDiv with the same inputs as HRem, it is reused. 755 // 756 /// CHECK-START: long Main.$noinline$LongRemDiv(long, long) instruction_simplifier$after_gvn (before) 757 /// CHECK: Rem 758 /// CHECK-NEXT: Div 759 // 760 /// CHECK-START: long Main.$noinline$LongRemDiv(long, long) instruction_simplifier$after_gvn (after) 761 /// CHECK: Div 762 /// CHECK-NEXT: Mul 763 /// CHECK-NEXT: Sub $noinline$LongRemDiv(long v, long s)764 private static long $noinline$LongRemDiv(long v, long s) { 765 long r = v % s; 766 long q = v / s; 767 return (q << 32) | r; 768 } 769 770 // A test case to check: 771 // HDiv with the same inputs as HRem but in another basic block is not reused. 772 // 773 /// CHECK-START: long Main.$noinline$LongDivRem(long, long, boolean) instruction_simplifier (before) 774 /// CHECK: Div 775 /// CHECK: Rem 776 // 777 /// CHECK-START: long Main.$noinline$LongDivRem(long, long, boolean) instruction_simplifier (after) 778 /// CHECK: Div 779 /// CHECK: Rem $noinline$LongDivRem(long v, long s, boolean do_division)780 private static long $noinline$LongDivRem(long v, long s, boolean do_division) { 781 long result = 0; 782 if (do_division) { 783 long q = v / s; 784 result = q << 32; 785 } 786 long r = v % s; 787 return result | r; 788 } 789 790 // A test case to check: 791 // If HRem is in a loop, the instruction simplifier postpones its optimization till 792 // loop analysis/optimizations are done. 793 // 794 /// CHECK-START: long Main.$noinline$LongRemBy18InLoop(long) instruction_simplifier (before) 795 /// CHECK: Div loop:B{{\d+}} 796 /// CHECK-NEXT: Rem loop:B{{\d+}} 797 // 798 /// CHECK-START: long Main.$noinline$LongRemBy18InLoop(long) instruction_simplifier (after) 799 /// CHECK: Div loop:B{{\d+}} 800 /// CHECK-NEXT: Rem loop:B{{\d+}} 801 // 802 /// CHECK-START: long Main.$noinline$LongRemBy18InLoop(long) instruction_simplifier$after_bce (before) 803 /// CHECK: Div loop:B{{\d+}} 804 /// CHECK-NEXT: Rem loop:B{{\d+}} 805 // 806 /// CHECK-START: long Main.$noinline$LongRemBy18InLoop(long) instruction_simplifier$after_bce (after) 807 /// CHECK-NOT: Rem 808 /// CHECK: Div loop:B{{\d+}} 809 /// CHECK-NEXT: Mul loop:B{{\d+}} 810 /// CHECK-NEXT: Sub loop:B{{\d+}} $noinline$LongRemBy18InLoop(long v)811 private static long $noinline$LongRemBy18InLoop(long v) { 812 long[] values = new long[(int)v]; 813 for (int i = 0; i < values.length; ++i) { 814 long d = (long)i; 815 long q = d / 18L; 816 long r = d % 18L; 817 values[i] = q + r; 818 } 819 return values[values.length - 1]; 820 } 821 822 // A test case to check: 823 // HRem with a divisor of power 2 is not optimized by the instruction simplifier because 824 // the case is optimized by the code generator. 825 // 826 /// CHECK-START: long Main.$noinline$LongRemByLongMin(long) instruction_simplifier (before) 827 /// CHECK: Div 828 /// CHECK-NEXT: Rem 829 // 830 /// CHECK-START: long Main.$noinline$LongRemByLongMin(long) instruction_simplifier (after) 831 /// CHECK: Div 832 /// CHECK-NEXT: Rem $noinline$LongRemByLongMin(long v)833 private static long $noinline$LongRemByLongMin(long v) { 834 long q = v / Long.MIN_VALUE; 835 long r = v % Long.MIN_VALUE; 836 return q + r; 837 } 838 main(String args[])839 public static void main(String args[]) { 840 remInt(); 841 remLong(); 842 } 843 } 844