1 /*
   2  * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 package compiler.intrinsics.mathexact;
  25 
  26 import jdk.test.lib.Utils;
  27 
  28 import java.util.Random;
  29 
  30 /**
  31  * The class depends on Utils class from testlibrary package.
  32  * It uses factory method that obtains random generator.
  33  */
  34 public class Verify {
  35     public static String throwWord(boolean threw) {
  36         return (threw ? "threw" : "didn't throw");
  37     }
  38 
  39     public static void verifyResult(UnaryMethod method, int result1, int result2, boolean exception1, boolean exception2, int value) {
  40         if (exception1 != exception2) {
  41             throw new RuntimeException("Intrinsic version [" + method.name() + "]" + throwWord(exception1) + " exception, NonIntrinsic version" + throwWord(exception2) + " for: " + value);
  42         }
  43         if (result1 != result2) {
  44             throw new RuntimeException("Intrinsic version [" + method.name() + "] returned: " + result1 + " while NonIntrinsic version returned: " + result2);
  45         }
  46     }
  47 
  48     public static void verifyResult(UnaryLongMethod method, long result1, long result2, boolean exception1, boolean exception2, long value) {
  49         if (exception1 != exception2) {
  50             throw new RuntimeException("Intrinsic version [" + method.name() + "]" + throwWord(exception1) + " exception, NonIntrinsic version" + throwWord(exception2) + " for: " + value);
  51         }
  52         if (result1 != result2) {
  53             throw new RuntimeException("Intrinsic version [" + method.name() + "] returned: " + result1 + " while NonIntrinsic version returned: " + result2);
  54         }
  55     }
  56 
  57     private static void verifyResult(BinaryMethod method, int result1, int result2, boolean exception1, boolean exception2, int a, int b) {
  58         if (exception1 != exception2) {
  59             throw new RuntimeException("Intrinsic version [" + method.name() + "]" + throwWord(exception1) + " exception, NonIntrinsic version " + throwWord(exception2) + " for: " + a + " + " + b);
  60         }
  61         if (result1 != result2) {
  62             throw new RuntimeException("Intrinsic version [" + method.name() + "] returned: " + result1 + " while NonIntrinsic version returned: " + result2);
  63         }
  64     }
  65 
  66     private static void verifyResult(BinaryLongMethod method, long result1, long result2, boolean exception1, boolean exception2, long a, long b) {
  67         if (exception1 != exception2) {
  68             throw new RuntimeException("Intrinsic version [" + method.name() + "]" + throwWord(exception1) + " exception, NonIntrinsic version " + throwWord(exception2) + " for: " + a + " + " + b);
  69         }
  70         if (result1 != result2) {
  71             throw new RuntimeException("Intrinsic version [" + method.name() + "] returned: " + result1 + " while NonIntrinsic version returned: " + result2);
  72         }
  73     }
  74 
  75 
  76     public static void verifyUnary(int a, UnaryMethod method) {
  77         boolean exception1 = false, exception2 = false;
  78         int result1 = 0, result2 = 0;
  79         try {
  80             result1 = method.checkMethod(a);
  81         } catch (ArithmeticException e) {
  82             exception1 = true;
  83         }
  84         try {
  85             result2 = method.safeMethod(a);
  86         } catch (ArithmeticException e) {
  87             exception2 = true;
  88         }
  89 
  90         verifyResult(method, result1, result2, exception1, exception2, a);
  91     }
  92 
  93     public static void verifyUnary(long a, UnaryLongMethod method) {
  94         boolean exception1 = false, exception2 = false;
  95         long result1 = 0, result2 = 0;
  96         try {
  97             result1 = method.checkMethod(a);
  98         } catch (ArithmeticException e) {
  99             exception1 = true;
 100         }
 101         try {
 102             result2 = method.safeMethod(a);
 103         } catch (ArithmeticException e) {
 104             exception2 = true;
 105         }
 106 
 107         verifyResult(method, result1, result2, exception1, exception2, a);
 108     }
 109 
 110 
 111     public static void verifyBinary(int a, int b, BinaryMethod method) {
 112         boolean exception1 = false, exception2 = false;
 113         int result1 = 0, result2 = 0;
 114         try {
 115             result1 = method.checkMethod(a, b);
 116         } catch (ArithmeticException e) {
 117             exception1 = true;
 118         }
 119         try {
 120             result2 = method.safeMethod(a, b);
 121         } catch (ArithmeticException e) {
 122             exception2 = true;
 123         }
 124 
 125         verifyResult(method, result1, result2, exception1, exception2, a, b);
 126     }
 127 
 128     public static void verifyBinary(long a, long b, BinaryLongMethod method) {
 129         boolean exception1 = false, exception2 = false;
 130         long result1 = 0, result2 = 0;
 131         try {
 132             result1 = method.checkMethod(a, b);
 133         } catch (ArithmeticException e) {
 134             exception1 = true;
 135         }
 136         try {
 137             result2 = method.safeMethod(a, b);
 138         } catch (ArithmeticException e) {
 139             exception2 = true;
 140         }
 141 
 142         verifyResult(method, result1, result2, exception1, exception2, a, b);
 143     }
 144 
 145 
 146     public static class LoadTest {
 147         public static Random rnd = Utils.getRandomInstance();
 148         public static int[] values = new int[256];
 149 
 150         public static void init() {
 151             for (int i = 0; i < values.length; ++i) {
 152                 values[i] = rnd.nextInt();
 153             }
 154         }
 155 
 156         public static void verify(BinaryMethod method) {
 157             for (int i = 0; i < 50000; ++i) {
 158                 Verify.verifyBinary(values[i & 255], values[i & 255] - i, method);
 159                 Verify.verifyBinary(values[i & 255] + i, values[i & 255] - i, method);
 160                 Verify.verifyBinary(values[i & 255], values[i & 255], method);
 161                 if ((i & 1) == 1 && i > 5) {
 162                     Verify.verifyBinary(values[i & 255] + i, values[i & 255] - i, method);
 163                 } else {
 164                     Verify.verifyBinary(values[i & 255] - i, values[i & 255] + i, method);
 165                 }
 166                 Verify.verifyBinary(values[i & 255], values[(i + 1) & 255], method);
 167             }
 168         }
 169     }
 170 
 171     public static class NonConstantTest {
 172         public static Random rnd = Utils.getRandomInstance();
 173         public static int[] values = new int[] { Integer.MAX_VALUE, Integer.MIN_VALUE };
 174 
 175         public static void verify(BinaryMethod method) {
 176             for (int i = 0; i < 50000; ++i) {
 177                 int rnd1 = rnd.nextInt(), rnd2 = rnd.nextInt();
 178                 Verify.verifyBinary(rnd1, rnd2, method);
 179                 Verify.verifyBinary(rnd1, rnd2 + 1, method);
 180                 Verify.verifyBinary(rnd1 + 1, rnd2, method);
 181                 Verify.verifyBinary(rnd1 - 1, rnd2, method);
 182                 Verify.verifyBinary(rnd1, rnd2 - 1, method);
 183                 Verify.verifyBinary(0, values[0], method);
 184                 Verify.verifyBinary(values[0], 0, method);
 185                 Verify.verifyBinary(0, values[1], method);
 186                 Verify.verifyBinary(values[1], 0, method);
 187             }
 188         }
 189     }
 190 
 191     public static class NonConstantLongTest {
 192         public static long[] values = { Long.MIN_VALUE, Long.MAX_VALUE, 0, Long.MAX_VALUE - 1831 };
 193         public static Random rnd = Utils.getRandomInstance();
 194 
 195         public static void verify(BinaryLongMethod method) {
 196             for (int i = 0; i < 50000; ++i) {
 197                 long rnd1 = rnd.nextLong(), rnd2 = rnd.nextLong();
 198                 Verify.verifyBinary(rnd1, rnd2, method);
 199                 Verify.verifyBinary(rnd1, rnd2 + 1, method);
 200                 Verify.verifyBinary(rnd1 + 1, rnd2, method);
 201                 Verify.verifyBinary(rnd1 - 1, rnd2, method);
 202                 Verify.verifyBinary(rnd1, rnd2 - 1, method);
 203                 Verify.verifyBinary(rnd1 + Long.MAX_VALUE - rnd2, rnd2 + 1, method);
 204                 Verify.verifyBinary(values[0], values[2], method);
 205                 Verify.verifyBinary(values[1], values[2], method);
 206                 Verify.verifyBinary(values[3], 74L, method);
 207             }
 208         }
 209     }
 210 
 211     public static class LoopDependentTest {
 212         public static Random rnd = Utils.getRandomInstance();
 213 
 214         public static void verify(BinaryMethod method) {
 215             int rnd1 = rnd.nextInt(), rnd2 = rnd.nextInt();
 216             runTest(rnd1, rnd2, method);
 217         }
 218 
 219         private static void runTest(int rnd1, int rnd2, BinaryMethod method) {
 220             for (int i = 0; i < 50000; ++i) {
 221                 Verify.verifyBinary(rnd1 + i, rnd2 + i, method);
 222                 Verify.verifyBinary(rnd1 + i, rnd2 + (i & 0xff), method);
 223                 Verify.verifyBinary(rnd1 - i, rnd2 - (i & 0xff), method);
 224                 Verify.verifyBinary(rnd1 + i + 1, rnd2 + i + 2, method);
 225                 Verify.verifyBinary(rnd1 + i * 2, rnd2 + i, method);
 226             }
 227         }
 228     }
 229 
 230     public static class ConstantTest {
 231         public static void verify(BinaryMethod method) {
 232             for (int i = 0; i < 50000; ++i) {
 233                 Verify.verifyBinary(5, 7, method);
 234                 Verify.verifyBinary(Integer.MAX_VALUE, 1, method);
 235                 Verify.verifyBinary(Integer.MIN_VALUE, -1, method);
 236                 Verify.verifyBinary(Integer.MAX_VALUE, -1, method);
 237                 Verify.verifyBinary(Integer.MIN_VALUE, 1, method);
 238                 Verify.verifyBinary(Integer.MAX_VALUE / 2, Integer.MAX_VALUE / 2, method);
 239                 Verify.verifyBinary(Integer.MAX_VALUE / 2, (Integer.MAX_VALUE / 2) + 3, method);
 240                 Verify.verifyBinary(Integer.MAX_VALUE, Integer.MIN_VALUE, method);
 241             }
 242         }
 243     }
 244 
 245     public static class ConstantLongTest {
 246         public static void verify(BinaryLongMethod method) {
 247             for (int i = 0; i < 50000; ++i) {
 248                 Verify.verifyBinary(5, 7, method);
 249                 Verify.verifyBinary(Long.MAX_VALUE, 1, method);
 250                 Verify.verifyBinary(Long.MIN_VALUE, -1, method);
 251                 Verify.verifyBinary(Long.MAX_VALUE, -1, method);
 252                 Verify.verifyBinary(Long.MIN_VALUE, 1, method);
 253                 Verify.verifyBinary(Long.MAX_VALUE / 2, Long.MAX_VALUE / 2, method);
 254                 Verify.verifyBinary(Long.MAX_VALUE / 2, (Long.MAX_VALUE / 2) + 3, method);
 255                 Verify.verifyBinary(Long.MAX_VALUE, Long.MIN_VALUE, method);
 256             }
 257         }
 258     }
 259 
 260     public static interface BinaryMethod {
 261         int safeMethod(int a, int b);
 262         int checkMethod(int a, int b);
 263         int unchecked(int a, int b);
 264         String name();
 265     }
 266 
 267     public static interface UnaryMethod {
 268         int safeMethod(int value);
 269         int checkMethod(int value);
 270         int unchecked(int value);
 271         String name();
 272     }
 273 
 274     public static interface BinaryLongMethod {
 275         long safeMethod(long a, long b);
 276         long checkMethod(long a, long b);
 277         long unchecked(long a, long b);
 278         String name();
 279     }
 280 
 281     public static interface UnaryLongMethod {
 282         long safeMethod(long value);
 283         long checkMethod(long value);
 284         long unchecked(long value);
 285         String name();
 286     }
 287 
 288     public static class UnaryToBinary implements BinaryMethod {
 289         private final UnaryMethod method;
 290         public UnaryToBinary(UnaryMethod method) {
 291             this.method = method;
 292         }
 293 
 294         @Override
 295         public int safeMethod(int a, int b) {
 296             return method.safeMethod(a);
 297         }
 298 
 299         @Override
 300         public int checkMethod(int a, int b) {
 301             return method.checkMethod(a);
 302         }
 303 
 304         @Override
 305         public int unchecked(int a, int b) {
 306             return method.unchecked(a);
 307 
 308         }
 309 
 310         @Override
 311         public String name() {
 312             return method.name();
 313         }
 314     }
 315 
 316     public static class UnaryToBinaryLong implements BinaryLongMethod {
 317         private final UnaryLongMethod method;
 318         public UnaryToBinaryLong(UnaryLongMethod method) {
 319             this.method = method;
 320         }
 321 
 322         @Override
 323         public long safeMethod(long a, long b) {
 324             return method.safeMethod(a);
 325         }
 326 
 327         @Override
 328         public long checkMethod(long a, long b) {
 329             return method.checkMethod(a);
 330         }
 331 
 332         @Override
 333         public long unchecked(long a, long b) {
 334             return method.unchecked(a);
 335 
 336         }
 337 
 338         @Override
 339         public String name() {
 340             return method.name();
 341         }
 342     }
 343 
 344 
 345     public static class AddExactI implements BinaryMethod {
 346         @Override
 347         public int safeMethod(int x, int y) {
 348             int r = x + y;
 349             // HD 2-12 Overflow iff both arguments have the opposite sign of the result
 350             if (((x ^ r) & (y ^ r)) < 0) {
 351                 throw new ArithmeticException("integer overflow");
 352             }
 353             return r;
 354 
 355         }
 356 
 357         @Override
 358         public int checkMethod(int a, int b) {
 359             return Math.addExact(a, b);
 360         }
 361 
 362         @Override
 363         public String name() {
 364             return "addExact";
 365         }
 366 
 367         @Override
 368         public int unchecked(int a, int b) {
 369             return a + b;
 370         }
 371     }
 372 
 373     public static class AddExactL implements BinaryLongMethod {
 374         @Override
 375         public long safeMethod(long x, long y) {
 376             long r = x + y;
 377             // HD 2-12 Overflow iff both arguments have the opposite sign of the result
 378             if (((x ^ r) & (y ^ r)) < 0) {
 379                 throw new ArithmeticException("integer overflow");
 380             }
 381             return r;
 382 
 383         }
 384 
 385         @Override
 386         public long checkMethod(long a, long b) {
 387             return Math.addExact(a, b);
 388         }
 389 
 390         @Override
 391         public String name() {
 392             return "addExactLong";
 393         }
 394 
 395         @Override
 396         public long unchecked(long a, long b) {
 397             return a + b;
 398         }
 399     }
 400 
 401     public static class MulExactI implements BinaryMethod {
 402         @Override
 403         public int safeMethod(int x, int y) {
 404             long r = (long)x * (long)y;
 405             if ((int)r != r) {
 406                 throw new ArithmeticException("integer overflow");
 407             }
 408             return (int)r;
 409 
 410         }
 411 
 412         @Override
 413         public int checkMethod(int a, int b) {
 414             return Math.multiplyExact(a, b);
 415         }
 416 
 417         @Override
 418         public int unchecked(int a, int b) {
 419             return a * b;
 420         }
 421 
 422         @Override
 423         public String name() {
 424             return "multiplyExact";
 425         }
 426     }
 427 
 428     public static class MulExactL implements BinaryLongMethod {
 429         @Override
 430         public long safeMethod(long x, long y) {
 431             long r = x * y;
 432             long ax = Math.abs(x);
 433             long ay = Math.abs(y);
 434             if (((ax | ay) >>> 31 != 0)) {
 435                 // Some bits greater than 2^31 that might cause overflow
 436                 // Check the result using the divide operator
 437                 // and check for the special case of Long.MIN_VALUE * -1
 438                 if (((y != 0) && (r / y != x)) ||
 439                         (x == Long.MIN_VALUE && y == -1)) {
 440                     throw new ArithmeticException("long overflow");
 441                 }
 442             }
 443             return r;
 444         }
 445 
 446         @Override
 447         public long checkMethod(long a, long b) {
 448             return Math.multiplyExact(a, b);
 449         }
 450 
 451         @Override
 452         public long unchecked(long a, long b) {
 453             return a * b;
 454         }
 455 
 456         @Override
 457         public String name() {
 458             return "multiplyExact";
 459         }
 460     }
 461 
 462     public static class NegExactL implements UnaryLongMethod {
 463         @Override
 464         public long safeMethod(long a) {
 465             if (a == Long.MIN_VALUE) {
 466                 throw new ArithmeticException("long overflow");
 467             }
 468 
 469             return -a;
 470 
 471         }
 472 
 473         @Override
 474         public long checkMethod(long value) {
 475             return Math.negateExact(value);
 476         }
 477 
 478         @Override
 479         public long unchecked(long value) {
 480             return -value;
 481         }
 482 
 483         @Override
 484         public String name() {
 485             return "negateExactLong";
 486         }
 487     }
 488 
 489     public static class NegExactI implements UnaryMethod {
 490         @Override
 491         public int safeMethod(int a) {
 492             if (a == Integer.MIN_VALUE) {
 493                 throw new ArithmeticException("integer overflow");
 494             }
 495 
 496             return -a;
 497 
 498         }
 499 
 500         @Override
 501         public int checkMethod(int value) {
 502             return Math.negateExact(value);
 503         }
 504 
 505         @Override
 506         public int unchecked(int value) {
 507             return -value;
 508         }
 509 
 510         @Override
 511         public String name() {
 512             return "negateExact";
 513         }
 514     }
 515 
 516     public static class SubExactI implements BinaryMethod {
 517         @Override
 518         public int safeMethod(int x, int y) {
 519             int r = x - y;
 520             // HD 2-12 Overflow iff the arguments have different signs and
 521             // the sign of the result is different than the sign of x
 522             if (((x ^ y) & (x ^ r)) < 0) {
 523                 throw new ArithmeticException("integer overflow");
 524             }
 525             return r;
 526         }
 527 
 528         @Override
 529         public int checkMethod(int a, int b) {
 530             return Math.subtractExact(a, b);
 531         }
 532 
 533         @Override
 534         public int unchecked(int a, int b) {
 535             return a - b;
 536         }
 537 
 538         @Override
 539         public String name() {
 540             return "subtractExact";
 541         }
 542     }
 543 
 544     public static class SubExactL implements BinaryLongMethod {
 545         @Override
 546         public long safeMethod(long x, long y) {
 547             long r = x - y;
 548             // HD 2-12 Overflow iff the arguments have different signs and
 549             // the sign of the result is different than the sign of x
 550             if (((x ^ y) & (x ^ r)) < 0) {
 551                 throw new ArithmeticException("integer overflow");
 552             }
 553             return r;
 554         }
 555 
 556         @Override
 557         public long checkMethod(long a, long b) {
 558             return Math.subtractExact(a, b);
 559         }
 560 
 561         @Override
 562         public long unchecked(long a, long b) {
 563             return a - b;
 564         }
 565 
 566         @Override
 567         public String name() {
 568             return "subtractExactLong";
 569         }
 570     }
 571 
 572     static class IncExactL implements UnaryLongMethod {
 573         @Override
 574         public long safeMethod(long a) {
 575             if (a == Long.MAX_VALUE) {
 576                 throw new ArithmeticException("long overflow");
 577             }
 578 
 579             return a + 1L;
 580 
 581         }
 582 
 583         @Override
 584         public long checkMethod(long value) {
 585             return Math.incrementExact(value);
 586         }
 587 
 588         @Override
 589         public long unchecked(long value) {
 590             return value + 1;
 591         }
 592 
 593         @Override
 594         public String name() {
 595             return "incrementExactLong";
 596         }
 597     }
 598 
 599     static class IncExactI implements UnaryMethod {
 600         @Override
 601         public int safeMethod(int a) {
 602             if (a == Integer.MAX_VALUE) {
 603                 throw new ArithmeticException("integer overflow");
 604             }
 605 
 606             return a + 1;
 607         }
 608 
 609         @Override
 610         public int checkMethod(int value) {
 611             return Math.incrementExact(value);
 612         }
 613 
 614         @Override
 615         public int unchecked(int value) {
 616             return value + 1;
 617         }
 618 
 619         @Override
 620         public String name() {
 621             return "incrementExact";
 622         }
 623     }
 624 
 625     static class DecExactL implements UnaryLongMethod {
 626         @Override
 627         public long safeMethod(long a) {
 628             if (a == Long.MIN_VALUE) {
 629                 throw new ArithmeticException("long overflow");
 630             }
 631 
 632             return a - 1L;
 633         }
 634 
 635         @Override
 636         public long checkMethod(long value) {
 637             return Math.decrementExact(value);
 638         }
 639 
 640         @Override
 641         public long unchecked(long value) {
 642             return value - 1;
 643         }
 644 
 645         @Override
 646         public String name() {
 647             return "decExactLong";
 648         }
 649     }
 650 
 651     static class DecExactI implements UnaryMethod {
 652         @Override
 653         public int safeMethod(int a) {
 654             if (a == Integer.MIN_VALUE) {
 655                 throw new ArithmeticException("integer overflow");
 656             }
 657 
 658             return a - 1;
 659         }
 660 
 661         @Override
 662         public int checkMethod(int value) {
 663             return Math.decrementExact(value);
 664         }
 665 
 666         @Override
 667         public int unchecked(int value) {
 668             return value - 1;
 669         }
 670 
 671         @Override
 672         public String name() {
 673             return "decrementExact";
 674         }
 675     }
 676 
 677 }