1/*
2 * Copyright (c) 2012, 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.type;
24
25import static org.graalvm.compiler.core.common.calc.FloatConvert.D2F;
26import static org.graalvm.compiler.core.common.calc.FloatConvert.D2I;
27import static org.graalvm.compiler.core.common.calc.FloatConvert.D2L;
28import static org.graalvm.compiler.core.common.calc.FloatConvert.F2D;
29import static org.graalvm.compiler.core.common.calc.FloatConvert.F2I;
30import static org.graalvm.compiler.core.common.calc.FloatConvert.F2L;
31
32import java.nio.ByteBuffer;
33import java.util.function.DoubleBinaryOperator;
34
35import org.graalvm.compiler.core.common.LIRKind;
36import org.graalvm.compiler.core.common.spi.LIRKindTool;
37import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
38import org.graalvm.compiler.core.common.type.ArithmeticOpTable.FloatConvertOp;
39import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp;
40import org.graalvm.compiler.debug.GraalError;
41
42import jdk.vm.ci.meta.Constant;
43import jdk.vm.ci.meta.JavaConstant;
44import jdk.vm.ci.meta.JavaKind;
45import jdk.vm.ci.meta.MetaAccessProvider;
46import jdk.vm.ci.meta.PrimitiveConstant;
47import jdk.vm.ci.meta.ResolvedJavaType;
48import jdk.vm.ci.meta.SerializableConstant;
49
50public class FloatStamp extends PrimitiveStamp {
51
52    private final double lowerBound;
53    private final double upperBound;
54    private final boolean nonNaN;
55
56    protected FloatStamp(int bits) {
57        this(bits, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, false);
58    }
59
60    public FloatStamp(int bits, double lowerBound, double upperBound, boolean nonNaN) {
61        super(bits, OPS);
62        assert bits == 64 || (bits == 32 && (Double.isNaN(lowerBound) || (float) lowerBound == lowerBound) && (Double.isNaN(upperBound) || (float) upperBound == upperBound));
63        assert Double.isNaN(lowerBound) == Double.isNaN(upperBound);
64        this.lowerBound = lowerBound;
65        this.upperBound = upperBound;
66        this.nonNaN = nonNaN;
67    }
68
69    @Override
70    public Stamp unrestricted() {
71        return new FloatStamp(getBits());
72    }
73
74    @Override
75    public Stamp empty() {
76        return new FloatStamp(getBits(), Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, true);
77    }
78
79    @Override
80    public Stamp constant(Constant c, MetaAccessProvider meta) {
81        JavaConstant jc = (JavaConstant) c;
82        assert jc.getJavaKind().isNumericFloat() && jc.getJavaKind().getBitCount() == getBits();
83        return StampFactory.forConstant(jc);
84    }
85
86    @Override
87    public SerializableConstant deserialize(ByteBuffer buffer) {
88        switch (getBits()) {
89            case 32:
90                return JavaConstant.forFloat(buffer.getFloat());
91            case 64:
92                return JavaConstant.forDouble(buffer.getDouble());
93            default:
94                throw GraalError.shouldNotReachHere();
95        }
96    }
97
98    @Override
99    public boolean hasValues() {
100        return lowerBound <= upperBound || !nonNaN;
101    }
102
103    @Override
104    public JavaKind getStackKind() {
105        if (getBits() > 32) {
106            return JavaKind.Double;
107        } else {
108            return JavaKind.Float;
109        }
110    }
111
112    @Override
113    public LIRKind getLIRKind(LIRKindTool tool) {
114        return tool.getFloatingKind(getBits());
115    }
116
117    @Override
118    public ResolvedJavaType javaType(MetaAccessProvider metaAccess) {
119        switch (getBits()) {
120            case 32:
121                return metaAccess.lookupJavaType(Float.TYPE);
122            case 64:
123                return metaAccess.lookupJavaType(Double.TYPE);
124            default:
125                throw GraalError.shouldNotReachHere();
126        }
127    }
128
129    /**
130     * The (inclusive) lower bound on the value described by this stamp.
131     */
132    public double lowerBound() {
133        return lowerBound;
134    }
135
136    /**
137     * The (inclusive) upper bound on the value described by this stamp.
138     */
139    public double upperBound() {
140        return upperBound;
141    }
142
143    /**
144     * Returns true if NaN is non included in the value described by this stamp.
145     */
146    public boolean isNonNaN() {
147        return nonNaN;
148    }
149
150    /**
151     * Returns true if this stamp represents the NaN value.
152     */
153    public boolean isNaN() {
154        return Double.isNaN(lowerBound);
155    }
156
157    @Override
158    public boolean isUnrestricted() {
159        return lowerBound == Double.NEGATIVE_INFINITY && upperBound == Double.POSITIVE_INFINITY && !nonNaN;
160    }
161
162    public boolean contains(double value) {
163        if (Double.isNaN(value)) {
164            return !nonNaN;
165        } else {
166            /*
167             * Don't use Double.compare for checking the bounds as -0.0 isn't correctly tracked, so
168             * the presence of 0.0 means -0.0 might also exist in the range.
169             */
170            return value >= lowerBound && value <= upperBound;
171        }
172    }
173
174    @Override
175    public String toString() {
176        StringBuilder str = new StringBuilder();
177        str.append('f');
178        str.append(getBits());
179        str.append(nonNaN ? "!" : "");
180        if (lowerBound == upperBound) {
181            str.append(" [").append(lowerBound).append(']');
182        } else if (lowerBound != Double.NEGATIVE_INFINITY || upperBound != Double.POSITIVE_INFINITY) {
183            str.append(" [").append(lowerBound).append(" - ").append(upperBound).append(']');
184        }
185        return str.toString();
186    }
187
188    private static double meetBounds(double a, double b, DoubleBinaryOperator op) {
189        if (Double.isNaN(a)) {
190            return b;
191        } else if (Double.isNaN(b)) {
192            return a;
193        } else {
194            return op.applyAsDouble(a, b);
195        }
196    }
197
198    @Override
199    public Stamp meet(Stamp otherStamp) {
200        if (otherStamp == this) {
201            return this;
202        }
203        FloatStamp other = (FloatStamp) otherStamp;
204        assert getBits() == other.getBits();
205        double meetUpperBound = meetBounds(upperBound, other.upperBound, Math::max);
206        double meetLowerBound = meetBounds(lowerBound, other.lowerBound, Math::min);
207        boolean meetNonNaN = nonNaN && other.nonNaN;
208        if (Double.compare(meetLowerBound, lowerBound) == 0 && Double.compare(meetUpperBound, upperBound) == 0 && meetNonNaN == nonNaN) {
209            return this;
210        } else if (Double.compare(meetLowerBound, other.lowerBound) == 0 && Double.compare(meetUpperBound, other.upperBound) == 0 && meetNonNaN == other.nonNaN) {
211            return other;
212        } else {
213            return new FloatStamp(getBits(), meetLowerBound, meetUpperBound, meetNonNaN);
214        }
215    }
216
217    @Override
218    public Stamp join(Stamp otherStamp) {
219        if (otherStamp == this) {
220            return this;
221        }
222        FloatStamp other = (FloatStamp) otherStamp;
223        assert getBits() == other.getBits();
224        double joinUpperBound = Math.min(upperBound, other.upperBound);
225        double joinLowerBound = Math.max(lowerBound, other.lowerBound);
226        boolean joinNonNaN = nonNaN || other.nonNaN;
227        if (Double.compare(joinLowerBound, lowerBound) == 0 && Double.compare(joinUpperBound, upperBound) == 0 && joinNonNaN == nonNaN) {
228            return this;
229        } else if (Double.compare(joinLowerBound, other.lowerBound) == 0 && Double.compare(joinUpperBound, other.upperBound) == 0 && joinNonNaN == other.nonNaN) {
230            return other;
231        } else {
232            return new FloatStamp(getBits(), joinLowerBound, joinUpperBound, joinNonNaN);
233        }
234    }
235
236    @Override
237    public int hashCode() {
238        final int prime = 31;
239        int result = 1;
240        long temp;
241        result = prime * result + super.hashCode();
242        temp = Double.doubleToLongBits(lowerBound);
243        result = prime * result + (int) (temp ^ (temp >>> 32));
244        result = prime * result + (nonNaN ? 1231 : 1237);
245        temp = Double.doubleToLongBits(upperBound);
246        result = prime * result + (int) (temp ^ (temp >>> 32));
247        return result;
248    }
249
250    @Override
251    public boolean isCompatible(Stamp stamp) {
252        if (this == stamp) {
253            return true;
254        }
255        if (stamp instanceof FloatStamp) {
256            FloatStamp other = (FloatStamp) stamp;
257            return getBits() == other.getBits();
258        }
259        return false;
260    }
261
262    @Override
263    public boolean isCompatible(Constant constant) {
264        if (constant instanceof PrimitiveConstant) {
265            PrimitiveConstant prim = (PrimitiveConstant) constant;
266            return prim.getJavaKind().isNumericFloat();
267        }
268        return false;
269    }
270
271    @Override
272    public boolean equals(Object obj) {
273        if (this == obj) {
274            return true;
275        }
276        if (obj == null || getClass() != obj.getClass() || !super.equals(obj)) {
277            return false;
278        }
279        FloatStamp other = (FloatStamp) obj;
280        if (Double.doubleToLongBits(lowerBound) != Double.doubleToLongBits(other.lowerBound)) {
281            return false;
282        }
283        if (Double.doubleToLongBits(upperBound) != Double.doubleToLongBits(other.upperBound)) {
284            return false;
285        }
286        if (nonNaN != other.nonNaN) {
287            return false;
288        }
289        return super.equals(other);
290    }
291
292    @Override
293    public JavaConstant asConstant() {
294        if (nonNaN && Double.compare(lowerBound, upperBound) == 0) {
295            switch (getBits()) {
296                case 32:
297                    return JavaConstant.forFloat((float) lowerBound);
298                case 64:
299                    return JavaConstant.forDouble(lowerBound);
300            }
301        }
302        return null;
303    }
304
305    public static final ArithmeticOpTable OPS = new ArithmeticOpTable(
306
307                    new UnaryOp.Neg() {
308
309                        @Override
310                        public Constant foldConstant(Constant c) {
311                            PrimitiveConstant value = (PrimitiveConstant) c;
312                            switch (value.getJavaKind()) {
313                                case Float:
314                                    return JavaConstant.forFloat(-value.asFloat());
315                                case Double:
316                                    return JavaConstant.forDouble(-value.asDouble());
317                                default:
318                                    throw GraalError.shouldNotReachHere();
319                            }
320                        }
321
322                        @Override
323                        public Stamp foldStamp(Stamp s) {
324                            FloatStamp stamp = (FloatStamp) s;
325                            return new FloatStamp(stamp.getBits(), -stamp.upperBound(), -stamp.lowerBound(), stamp.isNonNaN());
326                        }
327                    },
328
329                    new BinaryOp.Add(false, true) {
330
331                        @Override
332                        public Constant foldConstant(Constant const1, Constant const2) {
333                            PrimitiveConstant a = (PrimitiveConstant) const1;
334                            PrimitiveConstant b = (PrimitiveConstant) const2;
335                            assert a.getJavaKind() == b.getJavaKind();
336                            switch (a.getJavaKind()) {
337                                case Float:
338                                    return JavaConstant.forFloat(a.asFloat() + b.asFloat());
339                                case Double:
340                                    return JavaConstant.forDouble(a.asDouble() + b.asDouble());
341                                default:
342                                    throw GraalError.shouldNotReachHere();
343                            }
344                        }
345
346                        @Override
347                        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
348                            // TODO
349                            return stamp1.unrestricted();
350                        }
351
352                        @Override
353                        public boolean isNeutral(Constant value) {
354                            PrimitiveConstant n = (PrimitiveConstant) value;
355                            switch (n.getJavaKind()) {
356                                case Float:
357                                    return Float.compare(n.asFloat(), -0.0f) == 0;
358                                case Double:
359                                    return Double.compare(n.asDouble(), -0.0) == 0;
360                                default:
361                                    throw GraalError.shouldNotReachHere();
362                            }
363                        }
364                    },
365
366                    new BinaryOp.Sub(false, false) {
367
368                        @Override
369                        public Constant foldConstant(Constant const1, Constant const2) {
370                            PrimitiveConstant a = (PrimitiveConstant) const1;
371                            PrimitiveConstant b = (PrimitiveConstant) const2;
372                            assert a.getJavaKind() == b.getJavaKind();
373                            switch (a.getJavaKind()) {
374                                case Float:
375                                    return JavaConstant.forFloat(a.asFloat() - b.asFloat());
376                                case Double:
377                                    return JavaConstant.forDouble(a.asDouble() - b.asDouble());
378                                default:
379                                    throw GraalError.shouldNotReachHere();
380                            }
381                        }
382
383                        @Override
384                        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
385                            // TODO
386                            return stamp1.unrestricted();
387                        }
388
389                        @Override
390                        public boolean isNeutral(Constant value) {
391                            PrimitiveConstant n = (PrimitiveConstant) value;
392                            switch (n.getJavaKind()) {
393                                case Float:
394                                    return Float.compare(n.asFloat(), 0.0f) == 0;
395                                case Double:
396                                    return Double.compare(n.asDouble(), 0.0) == 0;
397                                default:
398                                    throw GraalError.shouldNotReachHere();
399                            }
400                        }
401                    },
402
403                    new BinaryOp.Mul(false, true) {
404
405                        @Override
406                        public Constant foldConstant(Constant const1, Constant const2) {
407                            PrimitiveConstant a = (PrimitiveConstant) const1;
408                            PrimitiveConstant b = (PrimitiveConstant) const2;
409                            assert a.getJavaKind() == b.getJavaKind();
410                            switch (a.getJavaKind()) {
411                                case Float:
412                                    return JavaConstant.forFloat(a.asFloat() * b.asFloat());
413                                case Double:
414                                    return JavaConstant.forDouble(a.asDouble() * b.asDouble());
415                                default:
416                                    throw GraalError.shouldNotReachHere();
417                            }
418                        }
419
420                        @Override
421                        public Stamp foldStamp(Stamp a, Stamp b) {
422                            // TODO
423                            return a.unrestricted();
424                        }
425
426                        @Override
427                        public boolean isNeutral(Constant value) {
428                            PrimitiveConstant n = (PrimitiveConstant) value;
429                            switch (n.getJavaKind()) {
430                                case Float:
431                                    return Float.compare(n.asFloat(), 1.0f) == 0;
432                                case Double:
433                                    return Double.compare(n.asDouble(), 1.0) == 0;
434                                default:
435                                    throw GraalError.shouldNotReachHere();
436                            }
437                        }
438                    },
439
440                    null,
441
442                    null,
443
444                    new BinaryOp.Div(false, false) {
445
446                        @Override
447                        public Constant foldConstant(Constant const1, Constant const2) {
448                            PrimitiveConstant a = (PrimitiveConstant) const1;
449                            PrimitiveConstant b = (PrimitiveConstant) const2;
450                            assert a.getJavaKind() == b.getJavaKind();
451                            switch (a.getJavaKind()) {
452                                case Float:
453                                    return JavaConstant.forFloat(a.asFloat() / b.asFloat());
454                                case Double:
455                                    return JavaConstant.forDouble(a.asDouble() / b.asDouble());
456                                default:
457                                    throw GraalError.shouldNotReachHere();
458                            }
459                        }
460
461                        @Override
462                        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
463                            // TODO
464                            return stamp1.unrestricted();
465                        }
466
467                        @Override
468                        public boolean isNeutral(Constant value) {
469                            PrimitiveConstant n = (PrimitiveConstant) value;
470                            switch (n.getJavaKind()) {
471                                case Float:
472                                    return Float.compare(n.asFloat(), 1.0f) == 0;
473                                case Double:
474                                    return Double.compare(n.asDouble(), 1.0) == 0;
475                                default:
476                                    throw GraalError.shouldNotReachHere();
477                            }
478                        }
479                    },
480
481                    new BinaryOp.Rem(false, false) {
482
483                        @Override
484                        public Constant foldConstant(Constant const1, Constant const2) {
485                            PrimitiveConstant a = (PrimitiveConstant) const1;
486                            PrimitiveConstant b = (PrimitiveConstant) const2;
487                            assert a.getJavaKind() == b.getJavaKind();
488                            switch (a.getJavaKind()) {
489                                case Float:
490                                    return JavaConstant.forFloat(a.asFloat() % b.asFloat());
491                                case Double:
492                                    return JavaConstant.forDouble(a.asDouble() % b.asDouble());
493                                default:
494                                    throw GraalError.shouldNotReachHere();
495                            }
496                        }
497
498                        @Override
499                        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
500                            // TODO
501                            return stamp1.unrestricted();
502                        }
503                    },
504
505                    new UnaryOp.Not() {
506
507                        @Override
508                        public Constant foldConstant(Constant c) {
509                            PrimitiveConstant value = (PrimitiveConstant) c;
510                            switch (value.getJavaKind()) {
511                                case Float:
512                                    int f = Float.floatToRawIntBits(value.asFloat());
513                                    return JavaConstant.forFloat(Float.intBitsToFloat(~f));
514                                case Double:
515                                    long d = Double.doubleToRawLongBits(value.asDouble());
516                                    return JavaConstant.forDouble(Double.longBitsToDouble(~d));
517                                default:
518                                    throw GraalError.shouldNotReachHere();
519                            }
520                        }
521
522                        @Override
523                        public Stamp foldStamp(Stamp s) {
524                            return s.unrestricted();
525                        }
526                    },
527
528                    new BinaryOp.And(true, true) {
529
530                        @Override
531                        public Constant foldConstant(Constant const1, Constant const2) {
532                            PrimitiveConstant a = (PrimitiveConstant) const1;
533                            PrimitiveConstant b = (PrimitiveConstant) const2;
534                            assert a.getJavaKind() == b.getJavaKind();
535                            switch (a.getJavaKind()) {
536                                case Float:
537                                    int fa = Float.floatToRawIntBits(a.asFloat());
538                                    int fb = Float.floatToRawIntBits(b.asFloat());
539                                    return JavaConstant.forFloat(Float.intBitsToFloat(fa & fb));
540                                case Double:
541                                    long da = Double.doubleToRawLongBits(a.asDouble());
542                                    long db = Double.doubleToRawLongBits(b.asDouble());
543                                    return JavaConstant.forDouble(Double.longBitsToDouble(da & db));
544                                default:
545                                    throw GraalError.shouldNotReachHere();
546                            }
547                        }
548
549                        @Override
550                        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
551                            return stamp1.unrestricted();
552                        }
553
554                        @Override
555                        public boolean isNeutral(Constant n) {
556                            PrimitiveConstant value = (PrimitiveConstant) n;
557                            switch (value.getJavaKind()) {
558                                case Float:
559                                    return Float.floatToRawIntBits(value.asFloat()) == 0xFFFFFFFF;
560                                case Double:
561                                    return Double.doubleToRawLongBits(value.asDouble()) == 0xFFFFFFFFFFFFFFFFL;
562                                default:
563                                    throw GraalError.shouldNotReachHere();
564                            }
565                        }
566                    },
567
568                    new BinaryOp.Or(true, true) {
569
570                        @Override
571                        public Constant foldConstant(Constant const1, Constant const2) {
572                            PrimitiveConstant a = (PrimitiveConstant) const1;
573                            PrimitiveConstant b = (PrimitiveConstant) const2;
574                            assert a.getJavaKind() == b.getJavaKind();
575                            switch (a.getJavaKind()) {
576                                case Float:
577                                    int fa = Float.floatToRawIntBits(a.asFloat());
578                                    int fb = Float.floatToRawIntBits(b.asFloat());
579                                    return JavaConstant.forFloat(Float.intBitsToFloat(fa | fb));
580                                case Double:
581                                    long da = Double.doubleToRawLongBits(a.asDouble());
582                                    long db = Double.doubleToRawLongBits(b.asDouble());
583                                    return JavaConstant.forDouble(Double.longBitsToDouble(da | db));
584                                default:
585                                    throw GraalError.shouldNotReachHere();
586                            }
587                        }
588
589                        @Override
590                        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
591                            return stamp1.unrestricted();
592                        }
593
594                        @Override
595                        public boolean isNeutral(Constant n) {
596                            PrimitiveConstant value = (PrimitiveConstant) n;
597                            switch (value.getJavaKind()) {
598                                case Float:
599                                    return Float.floatToRawIntBits(value.asFloat()) == 0;
600                                case Double:
601                                    return Double.doubleToRawLongBits(value.asDouble()) == 0L;
602                                default:
603                                    throw GraalError.shouldNotReachHere();
604                            }
605                        }
606                    },
607
608                    new BinaryOp.Xor(true, true) {
609
610                        @Override
611                        public Constant foldConstant(Constant const1, Constant const2) {
612                            PrimitiveConstant a = (PrimitiveConstant) const1;
613                            PrimitiveConstant b = (PrimitiveConstant) const2;
614                            assert a.getJavaKind() == b.getJavaKind();
615                            switch (a.getJavaKind()) {
616                                case Float:
617                                    int fa = Float.floatToRawIntBits(a.asFloat());
618                                    int fb = Float.floatToRawIntBits(b.asFloat());
619                                    return JavaConstant.forFloat(Float.intBitsToFloat(fa ^ fb));
620                                case Double:
621                                    long da = Double.doubleToRawLongBits(a.asDouble());
622                                    long db = Double.doubleToRawLongBits(b.asDouble());
623                                    return JavaConstant.forDouble(Double.longBitsToDouble(da ^ db));
624                                default:
625                                    throw GraalError.shouldNotReachHere();
626                            }
627                        }
628
629                        @Override
630                        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
631                            return stamp1.unrestricted();
632                        }
633
634                        @Override
635                        public boolean isNeutral(Constant n) {
636                            PrimitiveConstant value = (PrimitiveConstant) n;
637                            switch (value.getJavaKind()) {
638                                case Float:
639                                    return Float.floatToRawIntBits(value.asFloat()) == 0;
640                                case Double:
641                                    return Double.doubleToRawLongBits(value.asDouble()) == 0L;
642                                default:
643                                    throw GraalError.shouldNotReachHere();
644                            }
645                        }
646                    },
647
648                    null, null, null,
649
650                    new UnaryOp.Abs() {
651
652                        @Override
653                        public Constant foldConstant(Constant c) {
654                            PrimitiveConstant value = (PrimitiveConstant) c;
655                            switch (value.getJavaKind()) {
656                                case Float:
657                                    return JavaConstant.forFloat(Math.abs(value.asFloat()));
658                                case Double:
659                                    return JavaConstant.forDouble(Math.abs(value.asDouble()));
660                                default:
661                                    throw GraalError.shouldNotReachHere();
662                            }
663                        }
664
665                        @Override
666                        public Stamp foldStamp(Stamp s) {
667                            FloatStamp stamp = (FloatStamp) s;
668                            if (stamp.isNaN()) {
669                                return stamp;
670                            }
671                            return new FloatStamp(stamp.getBits(), 0, Math.max(-stamp.lowerBound(), stamp.upperBound()), stamp.isNonNaN());
672                        }
673                    },
674
675                    new UnaryOp.Sqrt() {
676
677                        @Override
678                        public Constant foldConstant(Constant c) {
679                            PrimitiveConstant value = (PrimitiveConstant) c;
680                            switch (value.getJavaKind()) {
681                                case Float:
682                                    return JavaConstant.forFloat((float) Math.sqrt(value.asFloat()));
683                                case Double:
684                                    return JavaConstant.forDouble(Math.sqrt(value.asDouble()));
685                                default:
686                                    throw GraalError.shouldNotReachHere();
687                            }
688                        }
689
690                        @Override
691                        public Stamp foldStamp(Stamp s) {
692                            return s.unrestricted();
693                        }
694                    },
695
696                    null, null, null,
697
698                    new FloatConvertOp(F2I) {
699
700                        @Override
701                        public Constant foldConstant(Constant c) {
702                            PrimitiveConstant value = (PrimitiveConstant) c;
703                            return JavaConstant.forInt((int) value.asFloat());
704                        }
705
706                        @Override
707                        public Stamp foldStamp(Stamp stamp) {
708                            FloatStamp floatStamp = (FloatStamp) stamp;
709                            assert floatStamp.getBits() == 32;
710                            boolean mustHaveZero = !floatStamp.isNonNaN();
711                            int lowerBound = (int) floatStamp.lowerBound();
712                            int upperBound = (int) floatStamp.upperBound();
713                            if (mustHaveZero) {
714                                if (lowerBound > 0) {
715                                    lowerBound = 0;
716                                } else if (upperBound < 0) {
717                                    upperBound = 0;
718                                }
719                            }
720                            return StampFactory.forInteger(JavaKind.Int, lowerBound, upperBound);
721                        }
722                    },
723
724                    new FloatConvertOp(F2L) {
725
726                        @Override
727                        public Constant foldConstant(Constant c) {
728                            PrimitiveConstant value = (PrimitiveConstant) c;
729                            return JavaConstant.forLong((long) value.asFloat());
730                        }
731
732                        @Override
733                        public Stamp foldStamp(Stamp stamp) {
734                            FloatStamp floatStamp = (FloatStamp) stamp;
735                            assert floatStamp.getBits() == 32;
736                            boolean mustHaveZero = !floatStamp.isNonNaN();
737                            long lowerBound = (long) floatStamp.lowerBound();
738                            long upperBound = (long) floatStamp.upperBound();
739                            if (mustHaveZero) {
740                                if (lowerBound > 0) {
741                                    lowerBound = 0;
742                                } else if (upperBound < 0) {
743                                    upperBound = 0;
744                                }
745                            }
746                            return StampFactory.forInteger(JavaKind.Long, lowerBound, upperBound);
747                        }
748                    },
749
750                    new FloatConvertOp(D2I) {
751
752                        @Override
753                        public Constant foldConstant(Constant c) {
754                            PrimitiveConstant value = (PrimitiveConstant) c;
755                            return JavaConstant.forInt((int) value.asDouble());
756                        }
757
758                        @Override
759                        public Stamp foldStamp(Stamp stamp) {
760                            FloatStamp floatStamp = (FloatStamp) stamp;
761                            assert floatStamp.getBits() == 64;
762                            boolean mustHaveZero = !floatStamp.isNonNaN();
763                            int lowerBound = (int) floatStamp.lowerBound();
764                            int upperBound = (int) floatStamp.upperBound();
765                            if (mustHaveZero) {
766                                if (lowerBound > 0) {
767                                    lowerBound = 0;
768                                } else if (upperBound < 0) {
769                                    upperBound = 0;
770                                }
771                            }
772                            return StampFactory.forInteger(JavaKind.Int, lowerBound, upperBound);
773                        }
774                    },
775
776                    new FloatConvertOp(D2L) {
777
778                        @Override
779                        public Constant foldConstant(Constant c) {
780                            PrimitiveConstant value = (PrimitiveConstant) c;
781                            return JavaConstant.forLong((long) value.asDouble());
782                        }
783
784                        @Override
785                        public Stamp foldStamp(Stamp stamp) {
786                            FloatStamp floatStamp = (FloatStamp) stamp;
787                            assert floatStamp.getBits() == 64;
788                            boolean mustHaveZero = !floatStamp.isNonNaN();
789                            long lowerBound = (long) floatStamp.lowerBound();
790                            long upperBound = (long) floatStamp.upperBound();
791                            if (mustHaveZero) {
792                                if (lowerBound > 0) {
793                                    lowerBound = 0;
794                                } else if (upperBound < 0) {
795                                    upperBound = 0;
796                                }
797                            }
798                            return StampFactory.forInteger(JavaKind.Long, lowerBound, upperBound);
799                        }
800                    },
801
802                    new FloatConvertOp(F2D) {
803
804                        @Override
805                        public Constant foldConstant(Constant c) {
806                            PrimitiveConstant value = (PrimitiveConstant) c;
807                            return JavaConstant.forDouble(value.asFloat());
808                        }
809
810                        @Override
811                        public Stamp foldStamp(Stamp stamp) {
812                            FloatStamp floatStamp = (FloatStamp) stamp;
813                            assert floatStamp.getBits() == 32;
814                            return StampFactory.forFloat(JavaKind.Double, floatStamp.lowerBound(), floatStamp.upperBound(), floatStamp.isNonNaN());
815                        }
816                    },
817
818                    new FloatConvertOp(D2F) {
819
820                        @Override
821                        public Constant foldConstant(Constant c) {
822                            PrimitiveConstant value = (PrimitiveConstant) c;
823                            return JavaConstant.forFloat((float) value.asDouble());
824                        }
825
826                        @Override
827                        public Stamp foldStamp(Stamp stamp) {
828                            FloatStamp floatStamp = (FloatStamp) stamp;
829                            assert floatStamp.getBits() == 64;
830                            return StampFactory.forFloat(JavaKind.Float, (float) floatStamp.lowerBound(), (float) floatStamp.upperBound(), floatStamp.isNonNaN());
831                        }
832                    });
833}
834