1 /*
   2  * Copyright (c) 2009, 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 package org.graalvm.compiler.core.common.calc;
  24 
  25 import org.graalvm.compiler.debug.GraalError;
  26 
  27 import jdk.vm.ci.meta.Constant;
  28 import jdk.vm.ci.meta.ConstantReflectionProvider;
  29 import jdk.vm.ci.meta.JavaConstant;
  30 import jdk.vm.ci.meta.PrimitiveConstant;
  31 
  32 /**
  33  * Condition codes used in conditionals.
  34  */
  35 public enum Condition {
  36     /**
  37      * Equal.
  38      */
  39     EQ("=="),
  40 
  41     /**
  42      * Not equal.
  43      */
  44     NE("!="),
  45 
  46     /**
  47      * Signed less than.
  48      */
  49     LT("<"),
  50 
  51     /**
  52      * Signed less than or equal.
  53      */
  54     LE("<="),
  55 
  56     /**
  57      * Signed greater than.
  58      */
  59     GT(">"),
  60 
  61     /**
  62      * Signed greater than or equal.
  63      */
  64     GE(">="),
  65 
  66     /**
  67      * Unsigned greater than or equal ("above than or equal").
  68      */
  69     AE("|>=|"),
  70 
  71     /**
  72      * Unsigned less than or equal ("below than or equal").
  73      */
  74     BE("|<=|"),
  75 
  76     /**
  77      * Unsigned greater than ("above than").
  78      */
  79     AT("|>|"),
  80 
  81     /**
  82      * Unsigned less than ("below than").
  83      */
  84     BT("|<|");
  85 
  86     public final String operator;
  87 
  88     Condition(String operator) {
  89         this.operator = operator;
  90     }
  91 
  92     public boolean check(int left, int right) {
  93         switch (this) {
  94             case EQ:
  95                 return left == right;
  96             case NE:
  97                 return left != right;
  98             case LT:
  99                 return left < right;
 100             case LE:
 101                 return left <= right;
 102             case GT:
 103                 return left > right;
 104             case GE:
 105                 return left >= right;
 106             case AE:
 107                 return UnsignedMath.aboveOrEqual(left, right);
 108             case BE:
 109                 return UnsignedMath.belowOrEqual(left, right);
 110             case AT:
 111                 return UnsignedMath.aboveThan(left, right);
 112             case BT:
 113                 return UnsignedMath.belowThan(left, right);
 114         }
 115         throw new IllegalArgumentException(this.toString());
 116     }
 117 
 118     /**
 119      * Given a condition and its negation, this method returns true for one of the two and false for
 120      * the other one. This can be used to keep comparisons in a canonical form.
 121      *
 122      * @return true if this condition is considered to be the canonical form, false otherwise.
 123      */
 124     public boolean isCanonical() {
 125         switch (this) {
 126             case EQ:
 127                 return true;
 128             case NE:
 129                 return false;
 130             case LT:
 131                 return true;
 132             case LE:
 133                 return false;
 134             case GT:
 135                 return false;
 136             case GE:
 137                 return false;
 138             case BT:
 139                 return true;
 140             case BE:
 141                 return false;
 142             case AT:
 143                 return false;
 144             case AE:
 145                 return false;
 146         }
 147         throw new IllegalArgumentException(this.toString());
 148     }
 149 
 150     /**
 151      * Returns true if the condition needs to be mirrored to get to a canonical condition. The
 152      * result of the mirroring operation might still need to be negated to achieve a canonical form.
 153      */
 154     public boolean canonicalMirror() {
 155         switch (this) {
 156             case EQ:
 157                 return false;
 158             case NE:
 159                 return false;
 160             case LT:
 161                 return false;
 162             case LE:
 163                 return true;
 164             case GT:
 165                 return true;
 166             case GE:
 167                 return false;
 168             case BT:
 169                 return false;
 170             case BE:
 171                 return true;
 172             case AT:
 173                 return true;
 174             case AE:
 175                 return false;
 176         }
 177         throw new IllegalArgumentException(this.toString());
 178     }
 179 
 180     /**
 181      * Returns true if the condition needs to be negated to get to a canonical condition. The result
 182      * of the negation might still need to be mirrored to achieve a canonical form.
 183      */
 184     public boolean canonicalNegate() {
 185         switch (this) {
 186             case EQ:
 187                 return false;
 188             case NE:
 189                 return true;
 190             case LT:
 191                 return false;
 192             case LE:
 193                 return true;
 194             case GT:
 195                 return false;
 196             case GE:
 197                 return true;
 198             case BT:
 199                 return false;
 200             case BE:
 201                 return true;
 202             case AT:
 203                 return false;
 204             case AE:
 205                 return true;
 206         }
 207         throw new IllegalArgumentException(this.toString());
 208     }
 209 
 210     /**
 211      * Negate this conditional.
 212      *
 213      * @return the condition that represents the negation
 214      */
 215     public final Condition negate() {
 216         switch (this) {
 217             case EQ:
 218                 return NE;
 219             case NE:
 220                 return EQ;
 221             case LT:
 222                 return GE;
 223             case LE:
 224                 return GT;
 225             case GT:
 226                 return LE;
 227             case GE:
 228                 return LT;
 229             case BT:
 230                 return AE;
 231             case BE:
 232                 return AT;
 233             case AT:
 234                 return BE;
 235             case AE:
 236                 return BT;
 237         }
 238         throw new IllegalArgumentException(this.toString());
 239     }
 240 
 241     public boolean implies(Condition other) {
 242         if (other == this) {
 243             return true;
 244         }
 245         switch (this) {
 246             case EQ:
 247                 return other == LE || other == GE || other == BE || other == AE;
 248             case NE:
 249                 return false;
 250             case LT:
 251                 return other == LE || other == NE;
 252             case LE:
 253                 return false;
 254             case GT:
 255                 return other == GE || other == NE;
 256             case GE:
 257                 return false;
 258             case BT:
 259                 return other == BE || other == NE;
 260             case BE:
 261                 return false;
 262             case AT:
 263                 return other == AE || other == NE;
 264             case AE:
 265                 return false;
 266         }
 267         throw new IllegalArgumentException(this.toString());
 268     }
 269 
 270     /**
 271      * Mirror this conditional (i.e. commute "a op b" to "b op' a")
 272      *
 273      * @return the condition representing the equivalent commuted operation
 274      */
 275     public final Condition mirror() {
 276         switch (this) {
 277             case EQ:
 278                 return EQ;
 279             case NE:
 280                 return NE;
 281             case LT:
 282                 return GT;
 283             case LE:
 284                 return GE;
 285             case GT:
 286                 return LT;
 287             case GE:
 288                 return LE;
 289             case BT:
 290                 return AT;
 291             case BE:
 292                 return AE;
 293             case AT:
 294                 return BT;
 295             case AE:
 296                 return BE;
 297         }
 298         throw new IllegalArgumentException();
 299     }
 300 
 301     /**
 302      * Returns true if this condition represents an unsigned comparison. EQ and NE are not
 303      * considered to be unsigned.
 304      */
 305     public final boolean isUnsigned() {
 306         return this == Condition.BT || this == Condition.BE || this == Condition.AT || this == Condition.AE;
 307     }
 308 
 309     /**
 310      * Checks if this conditional operation is commutative.
 311      *
 312      * @return {@code true} if this operation is commutative
 313      */
 314     public final boolean isCommutative() {
 315         return this == EQ || this == NE;
 316     }
 317 
 318     /**
 319      * Attempts to fold a comparison between two constants and return the result.
 320      *
 321      * @param lt the constant on the left side of the comparison
 322      * @param rt the constant on the right side of the comparison
 323      * @param constantReflection needed to compare constants
 324      * @return {@link Boolean#TRUE} if the comparison is known to be true, {@link Boolean#FALSE} if
 325      *         the comparison is known to be false
 326      */
 327     public boolean foldCondition(JavaConstant lt, JavaConstant rt, ConstantReflectionProvider constantReflection) {
 328         assert !lt.getJavaKind().isNumericFloat() && !rt.getJavaKind().isNumericFloat();
 329         return foldCondition(lt, rt, constantReflection, false);
 330     }
 331 
 332     /**
 333      * Attempts to fold a comparison between two constants and return the result.
 334      *
 335      * @param lt the constant on the left side of the comparison
 336      * @param rt the constant on the right side of the comparison
 337      * @param constantReflection needed to compare constants
 338      * @param unorderedIsTrue true if an undecided float comparison should result in "true"
 339      * @return true if the comparison is known to be true, false if the comparison is known to be
 340      *         false
 341      */
 342     public boolean foldCondition(Constant lt, Constant rt, ConstantReflectionProvider constantReflection, boolean unorderedIsTrue) {
 343         if (lt instanceof PrimitiveConstant) {
 344             PrimitiveConstant lp = (PrimitiveConstant) lt;
 345             PrimitiveConstant rp = (PrimitiveConstant) rt;
 346             switch (lp.getJavaKind()) {
 347                 case Boolean:
 348                 case Byte:
 349                 case Char:
 350                 case Short:
 351                 case Int: {
 352                     int x = lp.asInt();
 353                     int y = rp.asInt();
 354                     switch (this) {
 355                         case EQ:
 356                             return x == y;
 357                         case NE:
 358                             return x != y;
 359                         case LT:
 360                             return x < y;
 361                         case LE:
 362                             return x <= y;
 363                         case GT:
 364                             return x > y;
 365                         case GE:
 366                             return x >= y;
 367                         case AE:
 368                             return UnsignedMath.aboveOrEqual(x, y);
 369                         case BE:
 370                             return UnsignedMath.belowOrEqual(x, y);
 371                         case AT:
 372                             return UnsignedMath.aboveThan(x, y);
 373                         case BT:
 374                             return UnsignedMath.belowThan(x, y);
 375                         default:
 376                             throw new GraalError("expected condition: %s", this);
 377                     }
 378                 }
 379                 case Long: {
 380                     long x = lp.asLong();
 381                     long y = rp.asLong();
 382                     switch (this) {
 383                         case EQ:
 384                             return x == y;
 385                         case NE:
 386                             return x != y;
 387                         case LT:
 388                             return x < y;
 389                         case LE:
 390                             return x <= y;
 391                         case GT:
 392                             return x > y;
 393                         case GE:
 394                             return x >= y;
 395                         case AE:
 396                             return UnsignedMath.aboveOrEqual(x, y);
 397                         case BE:
 398                             return UnsignedMath.belowOrEqual(x, y);
 399                         case AT:
 400                             return UnsignedMath.aboveThan(x, y);
 401                         case BT:
 402                             return UnsignedMath.belowThan(x, y);
 403                         default:
 404                             throw new GraalError("expected condition: %s", this);
 405                     }
 406                 }
 407                 case Float: {
 408                     float x = lp.asFloat();
 409                     float y = rp.asFloat();
 410                     if (Float.isNaN(x) || Float.isNaN(y)) {
 411                         return unorderedIsTrue;
 412                     }
 413                     switch (this) {
 414                         case EQ:
 415                             return x == y;
 416                         case NE:
 417                             return x != y;
 418                         case LT:
 419                             return x < y;
 420                         case LE:
 421                             return x <= y;
 422                         case GT:
 423                             return x > y;
 424                         case GE:
 425                             return x >= y;
 426                         default:
 427                             throw new GraalError("expected condition: %s", this);
 428                     }
 429                 }
 430                 case Double: {
 431                     double x = lp.asDouble();
 432                     double y = rp.asDouble();
 433                     if (Double.isNaN(x) || Double.isNaN(y)) {
 434                         return unorderedIsTrue;
 435                     }
 436                     switch (this) {
 437                         case EQ:
 438                             return x == y;
 439                         case NE:
 440                             return x != y;
 441                         case LT:
 442                             return x < y;
 443                         case LE:
 444                             return x <= y;
 445                         case GT:
 446                             return x > y;
 447                         case GE:
 448                             return x >= y;
 449                         default:
 450                             throw new GraalError("expected condition: %s", this);
 451                     }
 452                 }
 453                 default:
 454                     throw new GraalError("expected value kind %s while folding condition: %s", lp.getJavaKind(), this);
 455             }
 456         } else {
 457             Boolean equal = constantReflection.constantEquals(lt, rt);
 458             if (equal == null) {
 459                 throw new GraalError("could not fold %s %s %s", lt, this, rt);
 460             }
 461             switch (this) {
 462                 case EQ:
 463                     return equal.booleanValue();
 464                 case NE:
 465                     return !equal.booleanValue();
 466                 default:
 467                     throw new GraalError("expected condition: %s", this);
 468             }
 469         }
 470     }
 471 
 472     public Condition join(Condition other) {
 473         if (other == this) {
 474             return this;
 475         }
 476         switch (this) {
 477             case EQ:
 478                 if (other == LE || other == GE || other == BE || other == AE) {
 479                     return EQ;
 480                 } else {
 481                     return null;
 482                 }
 483             case NE:
 484                 if (other == LT || other == GT || other == BT || other == AT) {
 485                     return other;
 486                 } else if (other == LE) {
 487                     return LT;
 488                 } else if (other == GE) {
 489                     return GT;
 490                 } else if (other == BE) {
 491                     return BT;
 492                 } else if (other == AE) {
 493                     return AT;
 494                 } else {
 495                     return null;
 496                 }
 497             case LE:
 498                 if (other == GE || other == EQ) {
 499                     return EQ;
 500                 } else if (other == NE || other == LT) {
 501                     return LT;
 502                 } else {
 503                     return null;
 504                 }
 505             case LT:
 506                 if (other == NE || other == LE) {
 507                     return LT;
 508                 } else {
 509                     return null;
 510                 }
 511             case GE:
 512                 if (other == LE || other == EQ) {
 513                     return EQ;
 514                 } else if (other == NE || other == GT) {
 515                     return GT;
 516                 } else {
 517                     return null;
 518                 }
 519             case GT:
 520                 if (other == NE || other == GE) {
 521                     return GT;
 522                 } else {
 523                     return null;
 524                 }
 525             case BE:
 526                 if (other == AE || other == EQ) {
 527                     return EQ;
 528                 } else if (other == NE || other == BT) {
 529                     return BT;
 530                 } else {
 531                     return null;
 532                 }
 533             case BT:
 534                 if (other == NE || other == BE) {
 535                     return BT;
 536                 } else {
 537                     return null;
 538                 }
 539             case AE:
 540                 if (other == BE || other == EQ) {
 541                     return EQ;
 542                 } else if (other == NE || other == AT) {
 543                     return AT;
 544                 } else {
 545                     return null;
 546                 }
 547             case AT:
 548                 if (other == NE || other == AE) {
 549                     return AT;
 550                 } else {
 551                     return null;
 552                 }
 553         }
 554         throw new IllegalArgumentException(this.toString());
 555     }
 556 
 557     public Condition meet(Condition other) {
 558         if (other == this) {
 559             return this;
 560         }
 561         switch (this) {
 562             case EQ:
 563                 if (other == LE || other == GE || other == BE || other == AE) {
 564                     return other;
 565                 } else if (other == LT) {
 566                     return LE;
 567                 } else if (other == GT) {
 568                     return GE;
 569                 } else if (other == BT) {
 570                     return BE;
 571                 } else if (other == AT) {
 572                     return AE;
 573                 } else {
 574                     return null;
 575                 }
 576             case NE:
 577                 if (other == LT || other == GT || other == BT || other == AT) {
 578                     return NE;
 579                 } else {
 580                     return null;
 581                 }
 582             case LE:
 583                 if (other == EQ || other == LT) {
 584                     return LE;
 585                 } else {
 586                     return null;
 587                 }
 588             case LT:
 589                 if (other == EQ || other == LE) {
 590                     return LE;
 591                 } else if (other == NE || other == GT) {
 592                     return NE;
 593                 } else {
 594                     return null;
 595                 }
 596             case GE:
 597                 if (other == EQ || other == GT) {
 598                     return GE;
 599                 } else {
 600                     return null;
 601                 }
 602             case GT:
 603                 if (other == EQ || other == GE) {
 604                     return GE;
 605                 } else if (other == NE || other == LT) {
 606                     return NE;
 607                 } else {
 608                     return null;
 609                 }
 610             case BE:
 611                 if (other == EQ || other == BT) {
 612                     return BE;
 613                 } else {
 614                     return null;
 615                 }
 616             case BT:
 617                 if (other == EQ || other == BE) {
 618                     return BE;
 619                 } else if (other == NE || other == AT) {
 620                     return NE;
 621                 } else {
 622                     return null;
 623                 }
 624             case AE:
 625                 if (other == EQ || other == AT) {
 626                     return AE;
 627                 } else {
 628                     return null;
 629                 }
 630             case AT:
 631                 if (other == EQ || other == AE) {
 632                     return AE;
 633                 } else if (other == NE || other == BT) {
 634                     return NE;
 635                 } else {
 636                     return null;
 637                 }
 638         }
 639         throw new IllegalArgumentException(this.toString());
 640     }
 641 }