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