001/* 002 * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.compiler.common.calc; 024 025import jdk.internal.jvmci.code.*; 026import jdk.internal.jvmci.common.*; 027import jdk.internal.jvmci.meta.*; 028 029/** 030 * Condition codes used in conditionals. 031 */ 032public enum Condition { 033 /** 034 * Equal. 035 */ 036 EQ("=="), 037 038 /** 039 * Not equal. 040 */ 041 NE("!="), 042 043 /** 044 * Signed less than. 045 */ 046 LT("<"), 047 048 /** 049 * Signed less than or equal. 050 */ 051 LE("<="), 052 053 /** 054 * Signed greater than. 055 */ 056 GT(">"), 057 058 /** 059 * Signed greater than or equal. 060 */ 061 GE(">="), 062 063 /** 064 * Unsigned greater than or equal ("above than or equal"). 065 */ 066 AE("|>=|"), 067 068 /** 069 * Unsigned less than or equal ("below than or equal"). 070 */ 071 BE("|<=|"), 072 073 /** 074 * Unsigned greater than ("above than"). 075 */ 076 AT("|>|"), 077 078 /** 079 * Unsigned less than ("below than"). 080 */ 081 BT("|<|"); 082 083 public final String operator; 084 085 private Condition(String operator) { 086 this.operator = operator; 087 } 088 089 public boolean check(int left, int right) { 090 switch (this) { 091 case EQ: 092 return left == right; 093 case NE: 094 return left != right; 095 case LT: 096 return left < right; 097 case LE: 098 return left <= right; 099 case GT: 100 return left > right; 101 case GE: 102 return left >= right; 103 case AE: 104 return UnsignedMath.aboveOrEqual(left, right); 105 case BE: 106 return UnsignedMath.belowOrEqual(left, right); 107 case AT: 108 return UnsignedMath.aboveThan(left, right); 109 case BT: 110 return UnsignedMath.belowThan(left, right); 111 } 112 throw new IllegalArgumentException(this.toString()); 113 } 114 115 /** 116 * Given a condition and its negation, this method returns true for one of the two and false for 117 * the other one. This can be used to keep comparisons in a canonical form. 118 * 119 * @return true if this condition is considered to be the canonical form, false otherwise. 120 */ 121 public boolean isCanonical() { 122 switch (this) { 123 case EQ: 124 return true; 125 case NE: 126 return false; 127 case LT: 128 return true; 129 case LE: 130 return false; 131 case GT: 132 return false; 133 case GE: 134 return false; 135 case BT: 136 return true; 137 case BE: 138 return false; 139 case AT: 140 return false; 141 case AE: 142 return false; 143 } 144 throw new IllegalArgumentException(this.toString()); 145 } 146 147 /** 148 * Returns true if the condition needs to be mirrored to get to a canonical condition. The 149 * result of the mirroring operation might still need to be negated to achieve a canonical form. 150 */ 151 public boolean canonicalMirror() { 152 switch (this) { 153 case EQ: 154 return false; 155 case NE: 156 return false; 157 case LT: 158 return false; 159 case LE: 160 return true; 161 case GT: 162 return true; 163 case GE: 164 return false; 165 case BT: 166 return false; 167 case BE: 168 return true; 169 case AT: 170 return true; 171 case AE: 172 return false; 173 } 174 throw new IllegalArgumentException(this.toString()); 175 } 176 177 /** 178 * Returns true if the condition needs to be negated to get to a canonical condition. The result 179 * of the negation might still need to be mirrored to achieve a canonical form. 180 */ 181 public boolean canonicalNegate() { 182 switch (this) { 183 case EQ: 184 return false; 185 case NE: 186 return true; 187 case LT: 188 return false; 189 case LE: 190 return true; 191 case GT: 192 return false; 193 case GE: 194 return true; 195 case BT: 196 return false; 197 case BE: 198 return true; 199 case AT: 200 return false; 201 case AE: 202 return true; 203 } 204 throw new IllegalArgumentException(this.toString()); 205 } 206 207 /** 208 * Negate this conditional. 209 * 210 * @return the condition that represents the negation 211 */ 212 public final Condition negate() { 213 switch (this) { 214 case EQ: 215 return NE; 216 case NE: 217 return EQ; 218 case LT: 219 return GE; 220 case LE: 221 return GT; 222 case GT: 223 return LE; 224 case GE: 225 return LT; 226 case BT: 227 return AE; 228 case BE: 229 return AT; 230 case AT: 231 return BE; 232 case AE: 233 return BT; 234 } 235 throw new IllegalArgumentException(this.toString()); 236 } 237 238 public boolean implies(Condition other) { 239 if (other == this) { 240 return true; 241 } 242 switch (this) { 243 case EQ: 244 return other == LE || other == GE || other == BE || other == AE; 245 case NE: 246 return false; 247 case LT: 248 return other == LE || other == NE; 249 case LE: 250 return false; 251 case GT: 252 return other == GE || other == NE; 253 case GE: 254 return false; 255 case BT: 256 return other == BE || other == NE; 257 case BE: 258 return false; 259 case AT: 260 return other == AE || other == NE; 261 case AE: 262 return false; 263 } 264 throw new IllegalArgumentException(this.toString()); 265 } 266 267 /** 268 * Mirror this conditional (i.e. commute "a op b" to "b op' a") 269 * 270 * @return the condition representing the equivalent commuted operation 271 */ 272 public final Condition mirror() { 273 switch (this) { 274 case EQ: 275 return EQ; 276 case NE: 277 return NE; 278 case LT: 279 return GT; 280 case LE: 281 return GE; 282 case GT: 283 return LT; 284 case GE: 285 return LE; 286 case BT: 287 return AT; 288 case BE: 289 return AE; 290 case AT: 291 return BT; 292 case AE: 293 return BE; 294 } 295 throw new IllegalArgumentException(); 296 } 297 298 /** 299 * Returns true if this condition represents an unsigned comparison. EQ and NE are not 300 * considered to be unsigned. 301 */ 302 public final boolean isUnsigned() { 303 return this == Condition.BT || this == Condition.BE || this == Condition.AT || this == Condition.AE; 304 } 305 306 /** 307 * Checks if this conditional operation is commutative. 308 * 309 * @return {@code true} if this operation is commutative 310 */ 311 public final boolean isCommutative() { 312 return this == EQ || this == NE; 313 } 314 315 /** 316 * Attempts to fold a comparison between two constants and return the result. 317 * 318 * @param lt the constant on the left side of the comparison 319 * @param rt the constant on the right side of the comparison 320 * @param constantReflection needed to compare constants 321 * @return {@link Boolean#TRUE} if the comparison is known to be true, {@link Boolean#FALSE} if 322 * the comparison is known to be false 323 */ 324 public boolean foldCondition(JavaConstant lt, JavaConstant rt, ConstantReflectionProvider constantReflection) { 325 assert !lt.getKind().isNumericFloat() && !rt.getKind().isNumericFloat(); 326 return foldCondition(lt, rt, constantReflection, false); 327 } 328 329 /** 330 * Attempts to fold a comparison between two constants and return the result. 331 * 332 * @param lt the constant on the left side of the comparison 333 * @param rt the constant on the right side of the comparison 334 * @param constantReflection needed to compare constants 335 * @param unorderedIsTrue true if an undecided float comparison should result in "true" 336 * @return true if the comparison is known to be true, false if the comparison is known to be 337 * false 338 */ 339 public boolean foldCondition(Constant lt, Constant rt, ConstantReflectionProvider constantReflection, boolean unorderedIsTrue) { 340 if (lt instanceof PrimitiveConstant) { 341 PrimitiveConstant lp = (PrimitiveConstant) lt; 342 PrimitiveConstant rp = (PrimitiveConstant) rt; 343 switch (lp.getKind()) { 344 case Boolean: 345 case Byte: 346 case Char: 347 case Short: 348 case Int: { 349 int x = lp.asInt(); 350 int y = rp.asInt(); 351 switch (this) { 352 case EQ: 353 return x == y; 354 case NE: 355 return x != y; 356 case LT: 357 return x < y; 358 case LE: 359 return x <= y; 360 case GT: 361 return x > y; 362 case GE: 363 return x >= y; 364 case AE: 365 return UnsignedMath.aboveOrEqual(x, y); 366 case BE: 367 return UnsignedMath.belowOrEqual(x, y); 368 case AT: 369 return UnsignedMath.aboveThan(x, y); 370 case BT: 371 return UnsignedMath.belowThan(x, y); 372 default: 373 throw new JVMCIError("expected condition: %s", this); 374 } 375 } 376 case Long: { 377 long x = lp.asLong(); 378 long y = rp.asLong(); 379 switch (this) { 380 case EQ: 381 return x == y; 382 case NE: 383 return x != y; 384 case LT: 385 return x < y; 386 case LE: 387 return x <= y; 388 case GT: 389 return x > y; 390 case GE: 391 return x >= y; 392 case AE: 393 return UnsignedMath.aboveOrEqual(x, y); 394 case BE: 395 return UnsignedMath.belowOrEqual(x, y); 396 case AT: 397 return UnsignedMath.aboveThan(x, y); 398 case BT: 399 return UnsignedMath.belowThan(x, y); 400 default: 401 throw new JVMCIError("expected condition: %s", this); 402 } 403 } 404 case Float: { 405 float x = lp.asFloat(); 406 float y = rp.asFloat(); 407 if (Float.isNaN(x) || Float.isNaN(y)) { 408 return unorderedIsTrue; 409 } 410 switch (this) { 411 case EQ: 412 return x == y; 413 case NE: 414 return x != y; 415 case LT: 416 return x < y; 417 case LE: 418 return x <= y; 419 case GT: 420 return x > y; 421 case GE: 422 return x >= y; 423 default: 424 throw new JVMCIError("expected condition: %s", this); 425 } 426 } 427 case Double: { 428 double x = lp.asDouble(); 429 double y = rp.asDouble(); 430 if (Double.isNaN(x) || Double.isNaN(y)) { 431 return unorderedIsTrue; 432 } 433 switch (this) { 434 case EQ: 435 return x == y; 436 case NE: 437 return x != y; 438 case LT: 439 return x < y; 440 case LE: 441 return x <= y; 442 case GT: 443 return x > y; 444 case GE: 445 return x >= y; 446 default: 447 throw new JVMCIError("expected condition: %s", this); 448 } 449 } 450 default: 451 throw new JVMCIError("expected value kind %s while folding condition: %s", lp.getKind(), this); 452 } 453 } else { 454 Boolean equal = constantReflection.constantEquals(lt, rt); 455 if (equal == null) { 456 throw new JVMCIError("could not fold %s %s %s", lt, this, rt); 457 } 458 switch (this) { 459 case EQ: 460 return equal.booleanValue(); 461 case NE: 462 return !equal.booleanValue(); 463 default: 464 throw new JVMCIError("expected condition: %s", this); 465 } 466 } 467 } 468 469 public Condition join(Condition other) { 470 if (other == this) { 471 return this; 472 } 473 switch (this) { 474 case EQ: 475 if (other == LE || other == GE || other == BE || other == AE) { 476 return EQ; 477 } else { 478 return null; 479 } 480 case NE: 481 if (other == LT || other == GT || other == BT || other == AT) { 482 return other; 483 } else if (other == LE) { 484 return LT; 485 } else if (other == GE) { 486 return GT; 487 } else if (other == BE) { 488 return BT; 489 } else if (other == AE) { 490 return AT; 491 } else { 492 return null; 493 } 494 case LE: 495 if (other == GE || other == EQ) { 496 return EQ; 497 } else if (other == NE || other == LT) { 498 return LT; 499 } else { 500 return null; 501 } 502 case LT: 503 if (other == NE || other == LE) { 504 return LT; 505 } else { 506 return null; 507 } 508 case GE: 509 if (other == LE || other == EQ) { 510 return EQ; 511 } else if (other == NE || other == GT) { 512 return GT; 513 } else { 514 return null; 515 } 516 case GT: 517 if (other == NE || other == GE) { 518 return GT; 519 } else { 520 return null; 521 } 522 case BE: 523 if (other == AE || other == EQ) { 524 return EQ; 525 } else if (other == NE || other == BT) { 526 return BT; 527 } else { 528 return null; 529 } 530 case BT: 531 if (other == NE || other == BE) { 532 return BT; 533 } else { 534 return null; 535 } 536 case AE: 537 if (other == BE || other == EQ) { 538 return EQ; 539 } else if (other == NE || other == AT) { 540 return AT; 541 } else { 542 return null; 543 } 544 case AT: 545 if (other == NE || other == AE) { 546 return AT; 547 } else { 548 return null; 549 } 550 } 551 throw new IllegalArgumentException(this.toString()); 552 } 553 554 public Condition meet(Condition other) { 555 if (other == this) { 556 return this; 557 } 558 switch (this) { 559 case EQ: 560 if (other == LE || other == GE || other == BE || other == AE) { 561 return other; 562 } else if (other == LT) { 563 return LE; 564 } else if (other == GT) { 565 return GE; 566 } else if (other == BT) { 567 return BE; 568 } else if (other == AT) { 569 return AE; 570 } else { 571 return null; 572 } 573 case NE: 574 if (other == LT || other == GT || other == BT || other == AT) { 575 return NE; 576 } else { 577 return null; 578 } 579 case LE: 580 if (other == EQ || other == LT) { 581 return LE; 582 } else { 583 return null; 584 } 585 case LT: 586 if (other == EQ || other == LE) { 587 return LE; 588 } else if (other == NE || other == GT) { 589 return NE; 590 } else { 591 return null; 592 } 593 case GE: 594 if (other == EQ || other == GT) { 595 return GE; 596 } else { 597 return null; 598 } 599 case GT: 600 if (other == EQ || other == GE) { 601 return GE; 602 } else if (other == NE || other == LT) { 603 return NE; 604 } else { 605 return null; 606 } 607 case BE: 608 if (other == EQ || other == BT) { 609 return BE; 610 } else { 611 return null; 612 } 613 case BT: 614 if (other == EQ || other == BE) { 615 return BE; 616 } else if (other == NE || other == AT) { 617 return NE; 618 } else { 619 return null; 620 } 621 case AE: 622 if (other == EQ || other == AT) { 623 return AE; 624 } else { 625 return null; 626 } 627 case AT: 628 if (other == EQ || other == AE) { 629 return AE; 630 } else if (other == NE || other == BT) { 631 return NE; 632 } else { 633 return null; 634 } 635 } 636 throw new IllegalArgumentException(this.toString()); 637 } 638}