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}