Condition.java revision 12651:6ef01bd40ce2
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 */ 23package org.graalvm.compiler.core.common.calc; 24 25import org.graalvm.compiler.debug.GraalError; 26 27import jdk.vm.ci.meta.Constant; 28import jdk.vm.ci.meta.ConstantReflectionProvider; 29import jdk.vm.ci.meta.JavaConstant; 30import jdk.vm.ci.meta.PrimitiveConstant; 31 32/** 33 * Condition codes used in conditionals. 34 */ 35public 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} 642