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