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 RemTest { expectEquals(int expected, int result)18 private static void expectEquals(int expected, int result) { 19 if (expected != result) { 20 throw new Error("Expected: " + expected + ", found: " + result); 21 } 22 } 23 expectEquals(long expected, long result)24 private static void expectEquals(long expected, long result) { 25 if (expected != result) { 26 throw new Error("Expected: " + expected + ", found: " + result); 27 } 28 } 29 main()30 public static void main() { 31 remInt(); 32 remLong(); 33 } 34 remInt()35 private static void remInt() { 36 expectEquals(0, $noinline$IntRemBy18(0)); 37 expectEquals(1, $noinline$IntRemBy18(1)); 38 expectEquals(-1, $noinline$IntRemBy18(-1)); 39 expectEquals(0, $noinline$IntRemBy18(18)); 40 expectEquals(0, $noinline$IntRemBy18(-18)); 41 expectEquals(11, $noinline$IntRemBy18(65)); 42 expectEquals(-11, $noinline$IntRemBy18(-65)); 43 44 expectEquals(0, $noinline$IntALenRemBy18(new int[0])); 45 expectEquals(1, $noinline$IntALenRemBy18(new int[1])); 46 expectEquals(0, $noinline$IntALenRemBy18(new int[18])); 47 expectEquals(11, $noinline$IntALenRemBy18(new int[65])); 48 49 expectEquals(0, $noinline$IntRemByMinus18(0)); 50 expectEquals(1, $noinline$IntRemByMinus18(1)); 51 expectEquals(-1, $noinline$IntRemByMinus18(-1)); 52 expectEquals(0, $noinline$IntRemByMinus18(18)); 53 expectEquals(0, $noinline$IntRemByMinus18(-18)); 54 expectEquals(11, $noinline$IntRemByMinus18(65)); 55 expectEquals(-11, $noinline$IntRemByMinus18(-65)); 56 57 expectEquals(0, $noinline$IntRemBy7(0)); 58 expectEquals(1, $noinline$IntRemBy7(1)); 59 expectEquals(-1, $noinline$IntRemBy7(-1)); 60 expectEquals(0, $noinline$IntRemBy7(7)); 61 expectEquals(0, $noinline$IntRemBy7(-7)); 62 expectEquals(1, $noinline$IntRemBy7(22)); 63 expectEquals(-1, $noinline$IntRemBy7(-22)); 64 65 expectEquals(0, $noinline$IntALenRemBy7(new int[0])); 66 expectEquals(1, $noinline$IntALenRemBy7(new int[1])); 67 expectEquals(0, $noinline$IntALenRemBy7(new int[7])); 68 expectEquals(1, $noinline$IntALenRemBy7(new int[22])); 69 70 expectEquals(0, $noinline$IntRemByMinus7(0)); 71 expectEquals(1, $noinline$IntRemByMinus7(1)); 72 expectEquals(-1, $noinline$IntRemByMinus7(-1)); 73 expectEquals(0, $noinline$IntRemByMinus7(7)); 74 expectEquals(0, $noinline$IntRemByMinus7(-7)); 75 expectEquals(1, $noinline$IntRemByMinus7(22)); 76 expectEquals(-1, $noinline$IntRemByMinus7(-22)); 77 78 expectEquals(0, $noinline$IntRemBy6(0)); 79 expectEquals(1, $noinline$IntRemBy6(1)); 80 expectEquals(-1, $noinline$IntRemBy6(-1)); 81 expectEquals(0, $noinline$IntRemBy6(6)); 82 expectEquals(0, $noinline$IntRemBy6(-6)); 83 expectEquals(1, $noinline$IntRemBy6(19)); 84 expectEquals(-1, $noinline$IntRemBy6(-19)); 85 86 expectEquals(0, $noinline$IntALenRemBy6(new int[0])); 87 expectEquals(1, $noinline$IntALenRemBy6(new int[1])); 88 expectEquals(0, $noinline$IntALenRemBy6(new int[6])); 89 expectEquals(1, $noinline$IntALenRemBy6(new int[19])); 90 91 expectEquals(0, $noinline$IntRemByMinus6(0)); 92 expectEquals(1, $noinline$IntRemByMinus6(1)); 93 expectEquals(-1, $noinline$IntRemByMinus6(-1)); 94 expectEquals(0, $noinline$IntRemByMinus6(6)); 95 expectEquals(0, $noinline$IntRemByMinus6(-6)); 96 expectEquals(1, $noinline$IntRemByMinus6(19)); 97 expectEquals(-1, $noinline$IntRemByMinus6(-19)); 98 99 expectEquals(1, $noinline$UnsignedIntRem01(13)); 100 expectEquals(1, $noinline$UnsignedIntRem02(13)); 101 expectEquals(1, $noinline$UnsignedIntRem03(13)); 102 expectEquals(1, $noinline$UnsignedIntRem04(13)); 103 expectEquals(1, $noinline$UnsignedIntRem05(101)); 104 expectEquals(11, $noinline$UnsignedIntRem06(101)); 105 106 expectEquals(-1, $noinline$SignedIntRem01(-13)); 107 expectEquals(-1, $noinline$SignedIntRem02(-13)); 108 expectEquals(1, $noinline$SignedIntRem03(-13)); 109 expectEquals(1, $noinline$SignedIntRem04(-13, true)); 110 expectEquals(0, $noinline$SignedIntRem05(-12, 0,-13)); 111 expectEquals(-1, $noinline$SignedIntRem06(-13)); 112 } 113 114 // A test case to check that 'lsr' and 'asr' are combined into one 'asr'. 115 // For divisor 18 seen in an MP3 decoding workload there is no need 116 // to correct the result of get_high(dividend * magic). So there are no 117 // instructions between 'lsr' and 'asr'. In such a case they can be combined 118 // into one 'asr'. 119 // 120 /// CHECK-START-ARM64: int RemTest.$noinline$IntRemBy18(int) disassembly (after) 121 /// CHECK: asr x{{\d+}}, x{{\d+}}, #34 122 /// CHECK-NEXT: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31 123 /// CHECK-NEXT: mov w{{\d+}}, #0x12 124 /// CHECK-NEXT: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}} $noinline$IntRemBy18(int v)125 private static int $noinline$IntRemBy18(int v) { 126 int r = v % 18; 127 return r; 128 } 129 130 // A test case to check that a correcting 'add' is not generated for a non-negative 131 // dividend and a positive divisor. 132 // 133 /// CHECK-START-ARM: int RemTest.$noinline$IntALenRemBy18(int[]) disassembly (after) 134 /// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 135 /// CHECK-NEXT: lsr{{s?}} r{{\d+}}, #2 136 /// CHECK-NEXT: mov{{s?}} r{{\d+}}, #18 137 /// CHECK-NEXT: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 138 // 139 /// CHECK-START-ARM64: int RemTest.$noinline$IntALenRemBy18(int[]) disassembly (after) 140 /// CHECK: lsr x{{\d+}}, x{{\d+}}, #34 141 /// CHECK-NEXT: mov w{{\d+}}, #0x12 142 /// CHECK-NEXT: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}} $noinline$IntALenRemBy18(int[] arr)143 private static int $noinline$IntALenRemBy18(int[] arr) { 144 int r = arr.length % 18; 145 return r; 146 } 147 148 // A test case to check that 'lsr' and 'asr' are combined into one 'asr'. 149 // Divisor -18 has the same property as divisor 18: no need to correct the 150 // result of get_high(dividend * magic). So there are no 151 // instructions between 'lsr' and 'asr'. In such a case they can be combined 152 // into one 'asr'. 153 // 154 /// CHECK-START-ARM64: int RemTest.$noinline$IntRemByMinus18(int) disassembly (after) 155 /// CHECK: asr x{{\d+}}, x{{\d+}}, #34 156 /// CHECK-NEXT: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31 157 /// CHECK-NEXT: mov w{{\d+}}, #0xffffffee 158 /// CHECK-NEXT: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}} $noinline$IntRemByMinus18(int v)159 private static int $noinline$IntRemByMinus18(int v) { 160 int r = v % -18; 161 return r; 162 } 163 164 // A test case to check that 'lsr' and 'add' are combined into one 'adds'. 165 // For divisor 7 seen in the core library the result of get_high(dividend * magic) 166 // must be corrected by the 'add' instruction. 167 // 168 // The test case also checks 'add' and 'add_shift' are optimized into 'adds' and 'cinc'. 169 // 170 /// CHECK-START-ARM64: int RemTest.$noinline$IntRemBy7(int) disassembly (after) 171 /// CHECK: adds x{{\d+}}, x{{\d+}}, x{{\d+}}, lsl #32 172 /// CHECK-NEXT: asr x{{\d+}}, x{{\d+}}, #34 173 /// CHECK-NEXT: cinc w{{\d+}}, w{{\d+}}, mi 174 /// CHECK-NEXT: mov w{{\d+}}, #0x7 175 /// CHECK-NEXT: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}} $noinline$IntRemBy7(int v)176 private static int $noinline$IntRemBy7(int v) { 177 int r = v % 7; 178 return r; 179 } 180 181 // A test case to check that a correcting 'add' is not generated for a non-negative 182 // dividend and a positive divisor. 183 // 184 /// CHECK-START-ARM: int RemTest.$noinline$IntALenRemBy7(int[]) disassembly (after) 185 /// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 186 /// CHECK-NEXT: add{{s?}} r{{\d+}}, r{{\d+}} 187 /// CHECK-NEXT: lsr{{s?}} r{{\d+}}, #2 188 /// CHECK-NEXT: mov{{s?}} r{{\d+}}, #7 189 /// CHECK-NEXT: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 190 // 191 /// CHECK-START-ARM64: int RemTest.$noinline$IntALenRemBy7(int[]) disassembly (after) 192 /// CHECK: lsr x{{\d+}}, x{{\d+}}, #34 193 /// CHECK-NEXT: mov w{{\d+}}, #0x7 194 /// CHECK-NEXT: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}} $noinline$IntALenRemBy7(int[] arr)195 private static int $noinline$IntALenRemBy7(int[] arr) { 196 int r = arr.length % 7; 197 return r; 198 } 199 200 // A test case to check that 'lsr' and 'add' are combined into one 'adds'. 201 // Divisor -7 has the same property as divisor 7: the result of get_high(dividend * magic) 202 // must be corrected. In this case it is a 'sub' instruction. 203 // 204 // The test case also checks 'sub' and 'add_shift' are optimized into 'subs' and 'cinc'. 205 // 206 /// CHECK-START-ARM64: int RemTest.$noinline$IntRemByMinus7(int) disassembly (after) 207 /// CHECK: subs x{{\d+}}, x{{\d+}}, x{{\d+}}, lsl #32 208 /// CHECK-NEXT: asr x{{\d+}}, x{{\d+}}, #34 209 /// CHECK-NEXT: cinc w{{\d+}}, w{{\d+}}, mi 210 /// CHECK-NEXT: mov w{{\d+}}, #0xfffffff9 211 /// CHECK-NEXT: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}} $noinline$IntRemByMinus7(int v)212 private static int $noinline$IntRemByMinus7(int v) { 213 int r = v % -7; 214 return r; 215 } 216 217 // A test case to check that 'asr' is used to get the high 32 bits of the result of 218 // 'dividend * magic'. 219 // For divisor 6 seen in the core library there is no need to correct the result of 220 // get_high(dividend * magic). Also there is no 'asr' before the final 'add' instruction 221 // which uses only the high 32 bits of the result. In such a case 'asr' getting the high 222 // 32 bits can be used as well. 223 // 224 /// CHECK-START-ARM64: int RemTest.$noinline$IntRemBy6(int) disassembly (after) 225 /// CHECK: asr x{{\d+}}, x{{\d+}}, #32 226 /// CHECK-NEXT: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31 227 /// CHECK-NEXT: mov w{{\d+}}, #0x6 228 /// CHECK-NEXT: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}} $noinline$IntRemBy6(int v)229 private static int $noinline$IntRemBy6(int v) { 230 int r = v % 6; 231 return r; 232 } 233 234 // A test case to check that a correcting 'add' is not generated for a non-negative 235 // dividend and a positive divisor. 236 // 237 /// CHECK-START-ARM: int RemTest.$noinline$IntALenRemBy6(int[]) disassembly (after) 238 /// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 239 /// CHECK-NEXT: mov{{s?}} r{{\d+}}, #6 240 /// CHECK-NEXT: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 241 // 242 /// CHECK-START-ARM64: int RemTest.$noinline$IntALenRemBy6(int[]) disassembly (after) 243 /// CHECK: lsr x{{\d+}}, x{{\d+}}, #32 244 /// CHECK-NEXT: mov w{{\d+}}, #0x6 245 /// CHECK-NEXT: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}} $noinline$IntALenRemBy6(int[] arr)246 private static int $noinline$IntALenRemBy6(int[] arr) { 247 int r = arr.length % 6; 248 return r; 249 } 250 251 // A test case to check that 'asr' is used to get the high 32 bits of the result of 252 // 'dividend * magic'. 253 // Divisor -6 has the same property as divisor 6: no need to correct the result of 254 // get_high(dividend * magic) and no 'asr' before the final 'add' instruction 255 // which uses only the high 32 bits of the result. In such a case 'asr' getting the high 256 // 32 bits can be used as well. 257 // 258 /// CHECK-START-ARM64: int RemTest.$noinline$IntRemByMinus6(int) disassembly (after) 259 /// CHECK: asr x{{\d+}}, x{{\d+}}, #32 260 /// CHECK-NEXT: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31 261 /// CHECK-NEXT: mov w{{\d+}}, #0xfffffffa 262 /// CHECK-NEXT: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}} $noinline$IntRemByMinus6(int v)263 private static int $noinline$IntRemByMinus6(int v) { 264 int r = v % -6; 265 return r; 266 } 267 $noinline$Negate(int v)268 private static int $noinline$Negate(int v) { 269 return -v; 270 } 271 $noinline$Decrement(int v)272 private static int $noinline$Decrement(int v) { 273 return v - 1; 274 } 275 $noinline$Increment(int v)276 private static int $noinline$Increment(int v) { 277 return v + 1; 278 } 279 280 // A test case to check that a correcting 'add' is not generated for a non-negative 281 // dividend and a positive divisor. 282 // 283 /// CHECK-START-ARM: int RemTest.$noinline$UnsignedIntRem01(int) disassembly (after) 284 /// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 285 /// CHECK-NEXT: mov{{s?}} r{{\d+}}, #6 286 /// CHECK-NEXT: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 287 // 288 /// CHECK-START-ARM64: int RemTest.$noinline$UnsignedIntRem01(int) disassembly (after) 289 /// CHECK: lsr x{{\d+}}, x{{\d+}}, #32 290 /// CHECK-NEXT: mov w{{\d+}}, #0x6 291 /// CHECK-NEXT: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}} $noinline$UnsignedIntRem01(int v)292 private static int $noinline$UnsignedIntRem01(int v) { 293 int c = 0; 294 if (v > 0) { 295 c = v % 6; 296 } else { 297 c = $noinline$Negate(v); // This is to prevent from using Select. 298 } 299 return c; 300 } 301 302 // A test case to check that a correcting 'add' is not generated for a non-negative 303 // dividend and a positive divisor. 304 // 305 /// CHECK-START-ARM: int RemTest.$noinline$UnsignedIntRem02(int) disassembly (after) 306 /// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 307 /// CHECK-NEXT: mov{{s?}} r{{\d+}}, #6 308 /// CHECK-NEXT: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 309 // 310 /// CHECK-START-ARM64: int RemTest.$noinline$UnsignedIntRem02(int) disassembly (after) 311 /// CHECK: lsr x{{\d+}}, x{{\d+}}, #32 312 /// CHECK-NEXT: mov w{{\d+}}, #0x6 313 /// CHECK-NEXT: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}} $noinline$UnsignedIntRem02(int v)314 private static int $noinline$UnsignedIntRem02(int v) { 315 int c = 0; 316 if (0 < v) { 317 c = v % 6; 318 } else { 319 c = $noinline$Negate(v); // This is to prevent from using Select. 320 } 321 return c; 322 } 323 324 // A test case to check that a correcting 'add' is not generated for a non-negative 325 // dividend and a positive divisor. 326 // 327 /// CHECK-START-ARM: int RemTest.$noinline$UnsignedIntRem03(int) disassembly (after) 328 /// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 329 /// CHECK-NEXT: mov{{s?}} r{{\d+}}, #6 330 /// CHECK-NEXT: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 331 // 332 /// CHECK-START-ARM64: int RemTest.$noinline$UnsignedIntRem03(int) disassembly (after) 333 /// CHECK: lsr x{{\d+}}, x{{\d+}}, #32 334 /// CHECK-NEXT: mov w{{\d+}}, #0x6 335 /// CHECK-NEXT: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}} $noinline$UnsignedIntRem03(int v)336 private static int $noinline$UnsignedIntRem03(int v) { 337 int c = 0; 338 if (v >= 0) { 339 c = v % 6; 340 } else { 341 c = $noinline$Negate(v); // This is to prevent from using Select. 342 } 343 return c; 344 } 345 346 // A test case to check that a correcting 'add' is not generated for a non-negative 347 // dividend and a positive divisor. 348 // 349 /// CHECK-START-ARM: int RemTest.$noinline$UnsignedIntRem04(int) disassembly (after) 350 /// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 351 /// CHECK-NEXT: mov{{s?}} r{{\d+}}, #6 352 /// CHECK-NEXT: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 353 // 354 /// CHECK-START-ARM64: int RemTest.$noinline$UnsignedIntRem04(int) disassembly (after) 355 /// CHECK: lsr x{{\d+}}, x{{\d+}}, #32 356 /// CHECK-NEXT: mov w{{\d+}}, #0x6 357 /// CHECK-NEXT: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}} $noinline$UnsignedIntRem04(int v)358 private static int $noinline$UnsignedIntRem04(int v) { 359 int c = 0; 360 if (0 <= v) { 361 c = v % 6; 362 } else { 363 c = $noinline$Negate(v); // This is to prevent from using Select. 364 } 365 return c; 366 } 367 368 // A test case to check that a correcting 'add' is not generated for a non-negative 369 // dividend and a positive divisor. 370 // 371 /// CHECK-START-ARM: int RemTest.$noinline$UnsignedIntRem05(int) disassembly (after) 372 /// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 373 /// CHECK-NEXT: lsr{{s?}} r{{\d+}}, #2 374 /// CHECK-NEXT: mov{{s?}} r{{\d+}}, #10 375 /// CHECK-NEXT: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 376 // 377 /// CHECK-START-ARM64: int RemTest.$noinline$UnsignedIntRem05(int) disassembly (after) 378 /// CHECK: lsr x{{\d+}}, x{{\d+}}, #34 379 /// CHECK-NEXT: mov w{{\d+}}, #0xa 380 /// CHECK-NEXT: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}} $noinline$UnsignedIntRem05(int v)381 private static int $noinline$UnsignedIntRem05(int v) { 382 int c = 0; 383 for(; v > 100; ++c) { 384 v %= 10; 385 } 386 return c; 387 } 388 389 // A test case to check that a correcting 'add' is not generated for a non-negative 390 // dividend and a positive divisor. 391 // 392 /// CHECK-START-ARM: int RemTest.$noinline$UnsignedIntRem06(int) disassembly (after) 393 /// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 394 /// CHECK-NEXT: lsr{{s?}} r{{\d+}}, r{{\d+}}, #2 395 /// CHECK: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 396 // 397 /// CHECK-START-ARM64: int RemTest.$noinline$UnsignedIntRem06(int) disassembly (after) 398 /// CHECK: smull x{{\d+}}, w{{\d+}}, w{{\d+}} 399 /// CHECK-NEXT: lsr x{{\d+}}, x{{\d+}}, #34 400 /// CHECK: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}} $noinline$UnsignedIntRem06(int v)401 private static int $noinline$UnsignedIntRem06(int v) { 402 if (v < 10) { 403 v = $noinline$Negate(v); // This is to prevent from using Select. 404 } else { 405 v = (v % 10) + (v / 10); 406 } 407 return v; 408 } 409 410 // A test case to check that a correcting 'add' is generated for a negative 411 // dividend and a positive divisor. 412 // 413 /// CHECK-START-ARM: int RemTest.$noinline$SignedIntRem01(int) disassembly (after) 414 /// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 415 /// CHECK-NEXT: sub r{{\d+}}, r{{\d+}}, asr #31 416 /// CHECK-NEXT: mov{{s?}} r{{\d+}}, #6 417 /// CHECK-NEXT: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 418 // 419 /// CHECK-START-ARM64: int RemTest.$noinline$SignedIntRem01(int) disassembly (after) 420 /// CHECK: asr x{{\d+}}, x{{\d+}}, #32 421 /// CHECK-NEXT: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31 $noinline$SignedIntRem01(int v)422 private static int $noinline$SignedIntRem01(int v) { 423 int c = 0; 424 if (v < 0) { 425 c = v % 6; 426 } else { 427 c = $noinline$Decrement(v); // This is to prevent from using Select. 428 } 429 return c; 430 } 431 432 // A test case to check that a correcting 'add' is generated for a negative 433 // dividend and a positive divisor. 434 // 435 /// CHECK-START-ARM: int RemTest.$noinline$SignedIntRem02(int) disassembly (after) 436 /// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 437 /// CHECK-NEXT: sub r{{\d+}}, r{{\d+}}, asr #31 438 /// CHECK-NEXT: mov{{s?}} r{{\d+}}, #6 439 /// CHECK-NEXT: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 440 // 441 /// CHECK-START-ARM64: int RemTest.$noinline$SignedIntRem02(int) disassembly (after) 442 /// CHECK: asr x{{\d+}}, x{{\d+}}, #32 443 /// CHECK-NEXT: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31 $noinline$SignedIntRem02(int v)444 private static int $noinline$SignedIntRem02(int v) { 445 int c = 0; 446 if (v <= 0) { 447 c = v % 6; 448 } else { 449 c = $noinline$Decrement(v); // This is to prevent from using Select. 450 } 451 return c; 452 } 453 454 // A test case to check that a correcting 'add' is generated for signed division. 455 // 456 /// CHECK-START-ARM: int RemTest.$noinline$SignedIntRem03(int) disassembly (after) 457 /// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 458 /// CHECK-NEXT: sub r{{\d+}}, r{{\d+}}, asr #31 459 /// CHECK-NEXT: mov{{s?}} r{{\d+}}, #6 460 /// CHECK-NEXT: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 461 // 462 /// CHECK-START-ARM64: int RemTest.$noinline$SignedIntRem03(int) disassembly (after) 463 /// CHECK: asr x{{\d+}}, x{{\d+}}, #32 464 /// CHECK-NEXT: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31 $noinline$SignedIntRem03(int v)465 private static int $noinline$SignedIntRem03(int v) { 466 boolean positive = (v > 0); 467 int c = v % 6; 468 if (!positive) { 469 c = $noinline$Negate(c); // This is to prevent from using Select. 470 } 471 return c; 472 } 473 474 // A test case to check that a correcting 'add' is generated for signed division. 475 // 476 /// CHECK-START-ARM: int RemTest.$noinline$SignedIntRem04(int, boolean) disassembly (after) 477 /// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 478 /// CHECK-NEXT: sub r{{\d+}}, r{{\d+}}, asr #31 479 /// CHECK-NEXT: mov{{s?}} r{{\d+}}, #6 480 /// CHECK-NEXT: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 481 // 482 /// CHECK-START-ARM64: int RemTest.$noinline$SignedIntRem04(int, boolean) disassembly (after) 483 /// CHECK: asr x{{\d+}}, x{{\d+}}, #32 484 /// CHECK-NEXT: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31 $noinline$SignedIntRem04(int v, boolean apply_rem)485 private static int $noinline$SignedIntRem04(int v, boolean apply_rem) { 486 int c = 0; 487 boolean positive = (v > 0); 488 if (apply_rem) { 489 c = v % 6; 490 } else { 491 c = $noinline$Decrement(v); // This is to prevent from using Select. 492 } 493 if (!positive) { 494 c = $noinline$Negate(c); // This is to prevent from using Select. 495 } 496 return c; 497 } 498 499 // A test case to check that a correcting 'add' is generated for signed division. 500 // 501 /// CHECK-START-ARM: int RemTest.$noinline$SignedIntRem05(int, int, int) disassembly (after) 502 /// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 503 /// CHECK-NEXT: sub r{{\d+}}, r{{\d+}}, asr #31 504 /// CHECK-NEXT: mov{{s?}} r{{\d+}}, #6 505 /// CHECK-NEXT: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 506 // 507 /// CHECK-START-ARM64: int RemTest.$noinline$SignedIntRem05(int, int, int) disassembly (after) 508 /// CHECK: asr x{{\d+}}, x{{\d+}}, #32 509 /// CHECK-NEXT: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31 $noinline$SignedIntRem05(int v, int a, int b)510 private static int $noinline$SignedIntRem05(int v, int a, int b) { 511 int c = 0; 512 513 if (v < a) 514 c = $noinline$Increment(c); // This is to prevent from using Select. 515 516 if (b < a) 517 c = $noinline$Increment(c); // This is to prevent from using Select. 518 519 if (v > b) { 520 c = v % 6; 521 } else { 522 c = $noinline$Increment(c); // This is to prevent from using Select. 523 } 524 525 return c; 526 } 527 528 // A test case to check that a correcting 'add' is generated for signed division. 529 // 530 /// CHECK-START-ARM: int RemTest.$noinline$SignedIntRem06(int) disassembly (after) 531 /// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 532 /// CHECK-NEXT: sub r{{\d+}}, r{{\d+}}, asr #31 533 /// CHECK-NEXT: mov{{s?}} r{{\d+}}, #6 534 /// CHECK-NEXT: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} 535 // 536 /// CHECK-START-ARM64: int RemTest.$noinline$SignedIntRem06(int) disassembly (after) 537 /// CHECK: asr x{{\d+}}, x{{\d+}}, #32 538 /// CHECK-NEXT: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31 $noinline$SignedIntRem06(int v)539 private static int $noinline$SignedIntRem06(int v) { 540 int c = v % 6; 541 542 if (v > 0) { 543 c = $noinline$Negate(c); // This is to prevent from using Select. 544 } 545 546 return c; 547 } 548 remLong()549 private static void remLong() { 550 expectEquals(0L, $noinline$LongRemBy18(0L)); 551 expectEquals(1L, $noinline$LongRemBy18(1L)); 552 expectEquals(-1L, $noinline$LongRemBy18(-1L)); 553 expectEquals(0L, $noinline$LongRemBy18(18L)); 554 expectEquals(0L, $noinline$LongRemBy18(-18L)); 555 expectEquals(11L, $noinline$LongRemBy18(65L)); 556 expectEquals(-11L, $noinline$LongRemBy18(-65L)); 557 558 expectEquals(0L, $noinline$LongRemByMinus18(0L)); 559 expectEquals(1L, $noinline$LongRemByMinus18(1L)); 560 expectEquals(-1L, $noinline$LongRemByMinus18(-1L)); 561 expectEquals(0L, $noinline$LongRemByMinus18(18L)); 562 expectEquals(0L, $noinline$LongRemByMinus18(-18L)); 563 expectEquals(11L, $noinline$LongRemByMinus18(65L)); 564 expectEquals(-11L, $noinline$LongRemByMinus18(-65L)); 565 566 expectEquals(0L, $noinline$LongRemBy7(0L)); 567 expectEquals(1L, $noinline$LongRemBy7(1L)); 568 expectEquals(-1L, $noinline$LongRemBy7(-1L)); 569 expectEquals(0L, $noinline$LongRemBy7(7L)); 570 expectEquals(0L, $noinline$LongRemBy7(-7L)); 571 expectEquals(1L, $noinline$LongRemBy7(22L)); 572 expectEquals(-1L, $noinline$LongRemBy7(-22L)); 573 574 expectEquals(0L, $noinline$LongRemByMinus7(0L)); 575 expectEquals(1L, $noinline$LongRemByMinus7(1L)); 576 expectEquals(-1L, $noinline$LongRemByMinus7(-1L)); 577 expectEquals(0L, $noinline$LongRemByMinus7(7L)); 578 expectEquals(0L, $noinline$LongRemByMinus7(-7L)); 579 expectEquals(1L, $noinline$LongRemByMinus7(22L)); 580 expectEquals(-1L, $noinline$LongRemByMinus7(-22L)); 581 582 expectEquals(0L, $noinline$LongRemBy6(0L)); 583 expectEquals(1L, $noinline$LongRemBy6(1L)); 584 expectEquals(-1L, $noinline$LongRemBy6(-1L)); 585 expectEquals(0L, $noinline$LongRemBy6(6L)); 586 expectEquals(0L, $noinline$LongRemBy6(-6L)); 587 expectEquals(1L, $noinline$LongRemBy6(19L)); 588 expectEquals(-1L, $noinline$LongRemBy6(-19L)); 589 590 expectEquals(0L, $noinline$LongRemByMinus6(0L)); 591 expectEquals(1L, $noinline$LongRemByMinus6(1L)); 592 expectEquals(-1L, $noinline$LongRemByMinus6(-1L)); 593 expectEquals(0L, $noinline$LongRemByMinus6(6L)); 594 expectEquals(0L, $noinline$LongRemByMinus6(-6L)); 595 expectEquals(1L, $noinline$LongRemByMinus6(19L)); 596 expectEquals(-1L, $noinline$LongRemByMinus6(-19L)); 597 598 expectEquals(0L, $noinline$LongRemBy100(0L)); 599 expectEquals(1L, $noinline$LongRemBy100(1L)); 600 expectEquals(-1L, $noinline$LongRemBy100(-1L)); 601 expectEquals(0L, $noinline$LongRemBy100(100L)); 602 expectEquals(0L, $noinline$LongRemBy100(-100L)); 603 expectEquals(1L, $noinline$LongRemBy100(101L)); 604 expectEquals(-1L, $noinline$LongRemBy100(-101L)); 605 606 expectEquals(0L, $noinline$LongRemByMinus100(0L)); 607 expectEquals(1L, $noinline$LongRemByMinus100(1L)); 608 expectEquals(-1L, $noinline$LongRemByMinus100(-1L)); 609 expectEquals(0L, $noinline$LongRemByMinus100(100L)); 610 expectEquals(0L, $noinline$LongRemByMinus100(-100L)); 611 expectEquals(1L, $noinline$LongRemByMinus100(101L)); 612 expectEquals(-1L, $noinline$LongRemByMinus100(-101L)); 613 614 expectEquals(1L, $noinline$UnsignedLongRem01(13L)); 615 expectEquals(1L, $noinline$UnsignedLongRem02(13L)); 616 expectEquals(1L, $noinline$UnsignedLongRem03(13L)); 617 expectEquals(1L, $noinline$UnsignedLongRem04(13L)); 618 expectEquals(1L, $noinline$UnsignedLongRem05(101L)); 619 expectEquals(11L, $noinline$UnsignedLongRem06(101L)); 620 621 expectEquals(-1L, $noinline$SignedLongRem01(-13L)); 622 expectEquals(-1L, $noinline$SignedLongRem02(-13L)); 623 expectEquals(1L, $noinline$SignedLongRem03(-13L)); 624 expectEquals(1L, $noinline$SignedLongRem04(-13L, true)); 625 expectEquals(0L, $noinline$SignedLongRem05(-12L, 0L,-13L)); 626 expectEquals(-1L, $noinline$SignedLongRem06(-13L)); 627 } 628 629 // Test cases for Int64 HDiv/HRem to check that optimizations implemented for Int32 are not 630 // used for Int64. The same divisors 18, -18, 7, -7, 6 and -6 are used. 631 632 /// CHECK-START-ARM64: long RemTest.$noinline$LongRemBy18(long) disassembly (after) 633 /// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}} 634 /// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63 635 /// CHECK-NEXT: mov x{{\d+}}, #0x12 636 /// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} $noinline$LongRemBy18(long v)637 private static long $noinline$LongRemBy18(long v) { 638 long r = v % 18L; 639 return r; 640 } 641 642 /// CHECK-START-ARM64: long RemTest.$noinline$LongRemByMinus18(long) disassembly (after) 643 /// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}} 644 /// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63 645 /// CHECK-NEXT: mov x{{\d+}}, #0xffffffffffffffee 646 /// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} $noinline$LongRemByMinus18(long v)647 private static long $noinline$LongRemByMinus18(long v) { 648 long r = v % -18L; 649 return r; 650 } 651 652 /// CHECK-START-ARM64: long RemTest.$noinline$LongRemBy7(long) disassembly (after) 653 /// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}} 654 /// CHECK-NEXT: asr x{{\d+}}, x{{\d+}}, #1 655 /// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63 656 /// CHECK-NEXT: mov x{{\d+}}, #0x7 657 /// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} $noinline$LongRemBy7(long v)658 private static long $noinline$LongRemBy7(long v) { 659 long r = v % 7L; 660 return r; 661 } 662 663 /// CHECK-START-ARM64: long RemTest.$noinline$LongRemByMinus7(long) disassembly (after) 664 /// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}} 665 /// CHECK-NEXT: asr x{{\d+}}, x{{\d+}}, #1 666 /// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63 667 /// CHECK-NEXT: mov x{{\d+}}, #0xfffffffffffffff9 668 /// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} $noinline$LongRemByMinus7(long v)669 private static long $noinline$LongRemByMinus7(long v) { 670 long r = v % -7L; 671 return r; 672 } 673 674 /// CHECK-START-ARM64: long RemTest.$noinline$LongRemBy6(long) disassembly (after) 675 /// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}} 676 /// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63 677 /// CHECK-NEXT: mov x{{\d+}}, #0x6 678 /// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} $noinline$LongRemBy6(long v)679 private static long $noinline$LongRemBy6(long v) { 680 long r = v % 6L; 681 return r; 682 } 683 684 /// CHECK-START-ARM64: long RemTest.$noinline$LongRemByMinus6(long) disassembly (after) 685 /// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}} 686 /// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63 687 /// CHECK-NEXT: mov x{{\d+}}, #0xfffffffffffffffa 688 /// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} $noinline$LongRemByMinus6(long v)689 private static long $noinline$LongRemByMinus6(long v) { 690 long r = v % -6L; 691 return r; 692 } 693 694 // A test to check 'add' and 'add_shift' are optimized into 'adds' and 'cinc'. 695 // 696 /// CHECK-START-ARM64: long RemTest.$noinline$LongRemBy100(long) disassembly (after) 697 /// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}} 698 /// CHECK-NEXT: adds x{{\d+}}, x{{\d+}}, x{{\d+}} 699 /// CHECK-NEXT: asr x{{\d+}}, x{{\d+}}, #6 700 /// CHECK-NEXT: cinc x{{\d+}}, x{{\d+}}, mi 701 /// CHECK-NEXT: mov x{{\d+}}, #0x64 702 /// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} $noinline$LongRemBy100(long v)703 private static long $noinline$LongRemBy100(long v) { 704 long r = v % 100L; 705 return r; 706 } 707 708 // A test to check 'sub' and 'add_shift' are optimized into 'subs' and 'cinc'. 709 // 710 /// CHECK-START-ARM64: long RemTest.$noinline$LongRemByMinus100(long) disassembly (after) 711 /// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}} 712 /// CHECK-NEXT: subs x{{\d+}}, x{{\d+}}, x{{\d+}} 713 /// CHECK-NEXT: asr x{{\d+}}, x{{\d+}}, #6 714 /// CHECK-NEXT: cinc x{{\d+}}, x{{\d+}}, mi 715 /// CHECK-NEXT: mov x{{\d+}}, #0xffffffffffffff9c 716 /// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} $noinline$LongRemByMinus100(long v)717 private static long $noinline$LongRemByMinus100(long v) { 718 long r = v % -100L; 719 return r; 720 } 721 $noinline$Negate(long v)722 private static long $noinline$Negate(long v) { 723 return -v; 724 } 725 $noinline$Decrement(long v)726 private static long $noinline$Decrement(long v) { 727 return v - 1; 728 } 729 $noinline$Increment(long v)730 private static long $noinline$Increment(long v) { 731 return v + 1; 732 } 733 734 // A test case to check that a correcting 'add' is not generated for a non-negative 735 // dividend and a positive divisor. 736 // 737 /// CHECK-START-ARM64: long RemTest.$noinline$UnsignedLongRem01(long) disassembly (after) 738 /// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}} 739 /// CHECK-NEXT: mov x{{\d+}}, #0x6 740 /// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} $noinline$UnsignedLongRem01(long v)741 private static long $noinline$UnsignedLongRem01(long v) { 742 long c = 0; 743 if (v > 0) { 744 c = v % 6; 745 } else { 746 c = $noinline$Negate(v); // This is to prevent from using Select. 747 } 748 return c; 749 } 750 751 // A test case to check that a correcting 'add' is not generated for a non-negative 752 // dividend and a positive divisor. 753 // 754 /// CHECK-START-ARM64: long RemTest.$noinline$UnsignedLongRem02(long) disassembly (after) 755 /// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}} 756 /// CHECK-NEXT: mov x{{\d+}}, #0x6 757 /// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} $noinline$UnsignedLongRem02(long v)758 private static long $noinline$UnsignedLongRem02(long v) { 759 long c = 0; 760 if (0 < v) { 761 c = v % 6; 762 } else { 763 c = $noinline$Negate(v); // This is to prevent from using Select. 764 } 765 return c; 766 } 767 768 // A test case to check that a correcting 'add' is not generated for a non-negative 769 // dividend and a positive divisor. 770 // 771 /// CHECK-START-ARM64: long RemTest.$noinline$UnsignedLongRem03(long) disassembly (after) 772 /// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}} 773 /// CHECK-NEXT: mov x{{\d+}}, #0x6 774 /// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} $noinline$UnsignedLongRem03(long v)775 private static long $noinline$UnsignedLongRem03(long v) { 776 long c = 0; 777 if (v >= 0) { 778 c = v % 6; 779 } else { 780 c = $noinline$Negate(v); // This is to prevent from using Select. 781 } 782 return c; 783 } 784 785 // A test case to check that a correcting 'add' is not generated for a non-negative 786 // dividend and a positive divisor. 787 // 788 /// CHECK-START-ARM64: long RemTest.$noinline$UnsignedLongRem04(long) disassembly (after) 789 /// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}} 790 /// CHECK-NEXT: mov x{{\d+}}, #0x6 791 /// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} $noinline$UnsignedLongRem04(long v)792 private static long $noinline$UnsignedLongRem04(long v) { 793 long c = 0; 794 if (0 <= v) { 795 c = v % 6; 796 } else { 797 c = $noinline$Negate(v); // This is to prevent from using Select. 798 } 799 return c; 800 } 801 802 // A test case to check that a correcting 'add' is not generated for a non-negative 803 // dividend and a positive divisor. 804 // 805 /// CHECK-START-ARM64: long RemTest.$noinline$UnsignedLongRem05(long) disassembly (after) 806 /// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}} 807 /// CHECK-NEXT: lsr x{{\d+}}, x{{\d+}}, #2 808 /// CHECK-NEXT: mov x{{\d+}}, #0xa 809 /// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} $noinline$UnsignedLongRem05(long v)810 private static long $noinline$UnsignedLongRem05(long v) { 811 long c = 0; 812 for(; v > 100; ++c) { 813 v %= 10; 814 } 815 return c; 816 } 817 818 // A test case to check that a correcting 'add' is not generated for a non-negative 819 // dividend and a positive divisor. 820 // 821 /// CHECK-START-ARM64: long RemTest.$noinline$UnsignedLongRem06(long) disassembly (after) 822 /// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}} 823 /// CHECK-NEXT: lsr x{{\d+}}, x{{\d+}}, #2 824 /// CHECK: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} $noinline$UnsignedLongRem06(long v)825 private static long $noinline$UnsignedLongRem06(long v) { 826 if (v < 10) { 827 v = $noinline$Negate(v); // This is to prevent from using Select. 828 } else { 829 v = (v % 10) + (v / 10); 830 } 831 return v; 832 } 833 834 // A test case to check that a correcting 'add' is generated for a negative 835 // dividend and a positive divisor. 836 // 837 /// CHECK-START-ARM64: long RemTest.$noinline$SignedLongRem01(long) disassembly (after) 838 /// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}} 839 /// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63 840 /// CHECK-NEXT: mov x{{\d+}}, #0x6 841 /// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} $noinline$SignedLongRem01(long v)842 private static long $noinline$SignedLongRem01(long v) { 843 long c = 0; 844 if (v < 0) { 845 c = v % 6; 846 } else { 847 c = $noinline$Decrement(v); // This is to prevent from using Select. 848 } 849 return c; 850 } 851 852 // A test case to check that a correcting 'add' is generated for a negative 853 // dividend and a positive divisor. 854 // 855 /// CHECK-START-ARM64: long RemTest.$noinline$SignedLongRem02(long) disassembly (after) 856 /// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}} 857 /// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63 858 /// CHECK-NEXT: mov x{{\d+}}, #0x6 859 /// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} $noinline$SignedLongRem02(long v)860 private static long $noinline$SignedLongRem02(long v) { 861 long c = 0; 862 if (v <= 0) { 863 c = v % 6; 864 } else { 865 c = $noinline$Decrement(v); // This is to prevent from using Select. 866 } 867 return c; 868 } 869 870 // A test case to check that a correcting 'add' is generated for signed division. 871 // 872 /// CHECK-START-ARM64: long RemTest.$noinline$SignedLongRem03(long) disassembly (after) 873 /// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}} 874 /// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63 875 /// CHECK-NEXT: mov x{{\d+}}, #0x6 876 /// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} $noinline$SignedLongRem03(long v)877 private static long $noinline$SignedLongRem03(long v) { 878 boolean positive = (v > 0); 879 long c = v % 6; 880 if (!positive) { 881 c = $noinline$Negate(c); // This is to prevent from using Select. 882 } 883 return c; 884 } 885 886 // A test case to check that a correcting 'add' is generated for signed division. 887 // 888 /// CHECK-START-ARM64: long RemTest.$noinline$SignedLongRem04(long, boolean) disassembly (after) 889 /// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}} 890 /// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63 891 /// CHECK-NEXT: mov x{{\d+}}, #0x6 892 /// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} $noinline$SignedLongRem04(long v, boolean apply_rem)893 private static long $noinline$SignedLongRem04(long v, boolean apply_rem) { 894 long c = 0; 895 boolean positive = (v > 0); 896 if (apply_rem) { 897 c = v % 6; 898 } else { 899 c = $noinline$Decrement(v); // This is to prevent from using Select. 900 } 901 if (!positive) { 902 c = $noinline$Negate(c); // This is to prevent from using Select. 903 } 904 return c; 905 } 906 907 // A test case to check that a correcting 'add' is generated for signed division. 908 // 909 /// CHECK-START-ARM64: long RemTest.$noinline$SignedLongRem05(long, long, long) disassembly (after) 910 /// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}} 911 /// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63 912 /// CHECK-NEXT: mov x{{\d+}}, #0x6 913 /// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} $noinline$SignedLongRem05(long v, long a, long b)914 private static long $noinline$SignedLongRem05(long v, long a, long b) { 915 long c = 0; 916 917 if (v < a) 918 c = $noinline$Increment(c); // This is to prevent from using Select. 919 920 if (b < a) 921 c = $noinline$Increment(c); // This is to prevent from using Select. 922 923 if (v > b) { 924 c = v % 6; 925 } else { 926 c = $noinline$Increment(c); // This is to prevent from using Select. 927 } 928 929 return c; 930 } 931 932 // A test case to check that a correcting 'add' is generated for signed division. 933 // 934 /// CHECK-START-ARM64: long RemTest.$noinline$SignedLongRem06(long) disassembly (after) 935 /// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}} 936 /// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63 937 /// CHECK-NEXT: mov x{{\d+}}, #0x6 938 /// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} $noinline$SignedLongRem06(long v)939 private static long $noinline$SignedLongRem06(long v) { 940 long c = v % 6; 941 942 if (v > 0) { 943 c = $noinline$Negate(c); // This is to prevent from using Select. 944 } 945 946 return c; 947 } 948 } 949