001/*
002 * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.compiler.common.type;
024
025import static com.oracle.graal.compiler.common.calc.FloatConvert.*;
026
027import java.nio.*;
028import java.util.function.*;
029
030import jdk.internal.jvmci.common.*;
031import jdk.internal.jvmci.meta.*;
032
033import com.oracle.graal.compiler.common.spi.*;
034import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp;
035import com.oracle.graal.compiler.common.type.ArithmeticOpTable.FloatConvertOp;
036import com.oracle.graal.compiler.common.type.ArithmeticOpTable.UnaryOp;
037
038public class FloatStamp extends PrimitiveStamp {
039
040    private final double lowerBound;
041    private final double upperBound;
042    private final boolean nonNaN;
043
044    protected FloatStamp(int bits) {
045        this(bits, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, false);
046    }
047
048    public FloatStamp(int bits, double lowerBound, double upperBound, boolean nonNaN) {
049        super(bits, OPS);
050        assert bits == 64 || (bits == 32 && (Double.isNaN(lowerBound) || (float) lowerBound == lowerBound) && (Double.isNaN(upperBound) || (float) upperBound == upperBound));
051        assert Double.isNaN(lowerBound) == Double.isNaN(upperBound);
052        this.lowerBound = lowerBound;
053        this.upperBound = upperBound;
054        this.nonNaN = nonNaN;
055    }
056
057    @Override
058    public Stamp unrestricted() {
059        return new FloatStamp(getBits());
060    }
061
062    @Override
063    public Stamp empty() {
064        return new FloatStamp(getBits(), Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, true);
065    }
066
067    @Override
068    public Stamp constant(Constant c, MetaAccessProvider meta) {
069        JavaConstant jc = (JavaConstant) c;
070        assert jc.getKind().isNumericFloat() && jc.getKind().getBitCount() == getBits();
071        return StampFactory.forConstant(jc);
072    }
073
074    @Override
075    public SerializableConstant deserialize(ByteBuffer buffer) {
076        switch (getBits()) {
077            case 32:
078                return JavaConstant.forFloat(buffer.getFloat());
079            case 64:
080                return JavaConstant.forDouble(buffer.getDouble());
081            default:
082                throw JVMCIError.shouldNotReachHere();
083        }
084    }
085
086    @Override
087    public boolean hasValues() {
088        return lowerBound <= upperBound || !nonNaN;
089    }
090
091    @Override
092    public Kind getStackKind() {
093        if (getBits() > 32) {
094            return Kind.Double;
095        } else {
096            return Kind.Float;
097        }
098    }
099
100    @Override
101    public LIRKind getLIRKind(LIRKindTool tool) {
102        return tool.getFloatingKind(getBits());
103    }
104
105    @Override
106    public ResolvedJavaType javaType(MetaAccessProvider metaAccess) {
107        switch (getBits()) {
108            case 32:
109                return metaAccess.lookupJavaType(Float.TYPE);
110            case 64:
111                return metaAccess.lookupJavaType(Double.TYPE);
112            default:
113                throw JVMCIError.shouldNotReachHere();
114        }
115    }
116
117    /**
118     * The (inclusive) lower bound on the value described by this stamp.
119     */
120    public double lowerBound() {
121        return lowerBound;
122    }
123
124    /**
125     * The (inclusive) upper bound on the value described by this stamp.
126     */
127    public double upperBound() {
128        return upperBound;
129    }
130
131    public boolean isNonNaN() {
132        return nonNaN;
133    }
134
135    public boolean isNaN() {
136        return Double.isNaN(lowerBound);
137    }
138
139    public boolean isUnrestricted() {
140        return lowerBound == Double.NEGATIVE_INFINITY && upperBound == Double.POSITIVE_INFINITY && !nonNaN;
141    }
142
143    public boolean contains(double value) {
144        if (Double.isNaN(value)) {
145            return !nonNaN;
146        } else {
147            return value >= lowerBound && value <= upperBound;
148        }
149    }
150
151    @Override
152    public String toString() {
153        StringBuilder str = new StringBuilder();
154        str.append('f');
155        str.append(getBits());
156        str.append(nonNaN ? "!" : "");
157        if (lowerBound == upperBound) {
158            str.append(" [").append(lowerBound).append(']');
159        } else if (lowerBound != Double.NEGATIVE_INFINITY || upperBound != Double.POSITIVE_INFINITY) {
160            str.append(" [").append(lowerBound).append(" - ").append(upperBound).append(']');
161        }
162        return str.toString();
163    }
164
165    private static double meetBounds(double a, double b, DoubleBinaryOperator op) {
166        if (Double.isNaN(a)) {
167            return b;
168        } else if (Double.isNaN(b)) {
169            return a;
170        } else {
171            return op.applyAsDouble(a, b);
172        }
173    }
174
175    @Override
176    public Stamp meet(Stamp otherStamp) {
177        if (otherStamp == this) {
178            return this;
179        }
180        FloatStamp other = (FloatStamp) otherStamp;
181        assert getBits() == other.getBits();
182        double meetUpperBound = meetBounds(upperBound, other.upperBound, Math::max);
183        double meetLowerBound = meetBounds(lowerBound, other.lowerBound, Math::min);
184        boolean meetNonNaN = nonNaN && other.nonNaN;
185        if (Double.compare(meetLowerBound, lowerBound) == 0 && Double.compare(meetUpperBound, upperBound) == 0 && meetNonNaN == nonNaN) {
186            return this;
187        } else if (Double.compare(meetLowerBound, other.lowerBound) == 0 && Double.compare(meetUpperBound, other.upperBound) == 0 && meetNonNaN == other.nonNaN) {
188            return other;
189        } else {
190            return new FloatStamp(getBits(), meetLowerBound, meetUpperBound, meetNonNaN);
191        }
192    }
193
194    @Override
195    public Stamp join(Stamp otherStamp) {
196        if (otherStamp == this) {
197            return this;
198        }
199        FloatStamp other = (FloatStamp) otherStamp;
200        assert getBits() == other.getBits();
201        double joinUpperBound = Math.min(upperBound, other.upperBound);
202        double joinLowerBound = Math.max(lowerBound, other.lowerBound);
203        boolean joinNonNaN = nonNaN || other.nonNaN;
204        if (Double.compare(joinLowerBound, lowerBound) == 0 && Double.compare(joinUpperBound, upperBound) == 0 && joinNonNaN == nonNaN) {
205            return this;
206        } else if (Double.compare(joinLowerBound, other.lowerBound) == 0 && Double.compare(joinUpperBound, other.upperBound) == 0 && joinNonNaN == other.nonNaN) {
207            return other;
208        } else {
209            return new FloatStamp(getBits(), joinLowerBound, joinUpperBound, joinNonNaN);
210        }
211    }
212
213    @Override
214    public int hashCode() {
215        final int prime = 31;
216        int result = 1;
217        long temp;
218        result = prime * result + super.hashCode();
219        temp = Double.doubleToLongBits(lowerBound);
220        result = prime * result + (int) (temp ^ (temp >>> 32));
221        result = prime * result + (nonNaN ? 1231 : 1237);
222        temp = Double.doubleToLongBits(upperBound);
223        result = prime * result + (int) (temp ^ (temp >>> 32));
224        return result;
225    }
226
227    @Override
228    public boolean isCompatible(Stamp stamp) {
229        if (this == stamp) {
230            return true;
231        }
232        if (stamp instanceof FloatStamp) {
233            FloatStamp other = (FloatStamp) stamp;
234            return getBits() == other.getBits();
235        }
236        return false;
237    }
238
239    @Override
240    public boolean equals(Object obj) {
241        if (this == obj) {
242            return true;
243        }
244        if (obj == null || getClass() != obj.getClass() || !super.equals(obj)) {
245            return false;
246        }
247        FloatStamp other = (FloatStamp) obj;
248        if (Double.doubleToLongBits(lowerBound) != Double.doubleToLongBits(other.lowerBound)) {
249            return false;
250        }
251        if (Double.doubleToLongBits(upperBound) != Double.doubleToLongBits(other.upperBound)) {
252            return false;
253        }
254        if (nonNaN != other.nonNaN) {
255            return false;
256        }
257        return super.equals(other);
258    }
259
260    @Override
261    public JavaConstant asConstant() {
262        if (nonNaN && Double.compare(lowerBound, upperBound) == 0) {
263            switch (getBits()) {
264                case 32:
265                    return JavaConstant.forFloat((float) lowerBound);
266                case 64:
267                    return JavaConstant.forDouble(lowerBound);
268            }
269        }
270        return null;
271    }
272
273    private static final ArithmeticOpTable OPS = new ArithmeticOpTable(
274
275    new UnaryOp.Neg() {
276
277        @Override
278        public Constant foldConstant(Constant c) {
279            PrimitiveConstant value = (PrimitiveConstant) c;
280            switch (value.getKind()) {
281                case Float:
282                    return JavaConstant.forFloat(-value.asFloat());
283                case Double:
284                    return JavaConstant.forDouble(-value.asDouble());
285                default:
286                    throw JVMCIError.shouldNotReachHere();
287            }
288        }
289
290        @Override
291        public Stamp foldStamp(Stamp s) {
292            FloatStamp stamp = (FloatStamp) s;
293            return new FloatStamp(stamp.getBits(), -stamp.upperBound(), -stamp.lowerBound(), stamp.isNonNaN());
294        }
295    },
296
297    new BinaryOp.Add(false, true) {
298
299        @Override
300        public Constant foldConstant(Constant const1, Constant const2) {
301            PrimitiveConstant a = (PrimitiveConstant) const1;
302            PrimitiveConstant b = (PrimitiveConstant) const2;
303            assert a.getKind() == b.getKind();
304            switch (a.getKind()) {
305                case Float:
306                    return JavaConstant.forFloat(a.asFloat() + b.asFloat());
307                case Double:
308                    return JavaConstant.forDouble(a.asDouble() + b.asDouble());
309                default:
310                    throw JVMCIError.shouldNotReachHere();
311            }
312        }
313
314        @Override
315        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
316            // TODO
317            return stamp1.unrestricted();
318        }
319
320        @Override
321        public boolean isNeutral(Constant value) {
322            PrimitiveConstant n = (PrimitiveConstant) value;
323            switch (n.getKind()) {
324                case Float:
325                    return Float.compare(n.asFloat(), -0.0f) == 0;
326                case Double:
327                    return Double.compare(n.asDouble(), -0.0) == 0;
328                default:
329                    throw JVMCIError.shouldNotReachHere();
330            }
331        }
332    },
333
334    new BinaryOp.Sub(false, false) {
335
336        @Override
337        public Constant foldConstant(Constant const1, Constant const2) {
338            PrimitiveConstant a = (PrimitiveConstant) const1;
339            PrimitiveConstant b = (PrimitiveConstant) const2;
340            assert a.getKind() == b.getKind();
341            switch (a.getKind()) {
342                case Float:
343                    return JavaConstant.forFloat(a.asFloat() - b.asFloat());
344                case Double:
345                    return JavaConstant.forDouble(a.asDouble() - b.asDouble());
346                default:
347                    throw JVMCIError.shouldNotReachHere();
348            }
349        }
350
351        @Override
352        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
353            // TODO
354            return stamp1.unrestricted();
355        }
356
357        @Override
358        public boolean isNeutral(Constant value) {
359            PrimitiveConstant n = (PrimitiveConstant) value;
360            switch (n.getKind()) {
361                case Float:
362                    return Float.compare(n.asFloat(), 0.0f) == 0;
363                case Double:
364                    return Double.compare(n.asDouble(), 0.0) == 0;
365                default:
366                    throw JVMCIError.shouldNotReachHere();
367            }
368        }
369    },
370
371    new BinaryOp.Mul(false, true) {
372
373        @Override
374        public Constant foldConstant(Constant const1, Constant const2) {
375            PrimitiveConstant a = (PrimitiveConstant) const1;
376            PrimitiveConstant b = (PrimitiveConstant) const2;
377            assert a.getKind() == b.getKind();
378            switch (a.getKind()) {
379                case Float:
380                    return JavaConstant.forFloat(a.asFloat() * b.asFloat());
381                case Double:
382                    return JavaConstant.forDouble(a.asDouble() * b.asDouble());
383                default:
384                    throw JVMCIError.shouldNotReachHere();
385            }
386        }
387
388        @Override
389        public Stamp foldStamp(Stamp a, Stamp b) {
390            // TODO
391            return a.unrestricted();
392        }
393
394        @Override
395        public boolean isNeutral(Constant value) {
396            PrimitiveConstant n = (PrimitiveConstant) value;
397            switch (n.getKind()) {
398                case Float:
399                    return Float.compare(n.asFloat(), 1.0f) == 0;
400                case Double:
401                    return Double.compare(n.asDouble(), 1.0) == 0;
402                default:
403                    throw JVMCIError.shouldNotReachHere();
404            }
405        }
406    },
407
408    new BinaryOp.Div(false, false) {
409
410        @Override
411        public Constant foldConstant(Constant const1, Constant const2) {
412            PrimitiveConstant a = (PrimitiveConstant) const1;
413            PrimitiveConstant b = (PrimitiveConstant) const2;
414            assert a.getKind() == b.getKind();
415            switch (a.getKind()) {
416                case Float:
417                    return JavaConstant.forFloat(a.asFloat() / b.asFloat());
418                case Double:
419                    return JavaConstant.forDouble(a.asDouble() / b.asDouble());
420                default:
421                    throw JVMCIError.shouldNotReachHere();
422            }
423        }
424
425        @Override
426        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
427            // TODO
428            return stamp1.unrestricted();
429        }
430
431        @Override
432        public boolean isNeutral(Constant value) {
433            PrimitiveConstant n = (PrimitiveConstant) value;
434            switch (n.getKind()) {
435                case Float:
436                    return Float.compare(n.asFloat(), 1.0f) == 0;
437                case Double:
438                    return Double.compare(n.asDouble(), 1.0) == 0;
439                default:
440                    throw JVMCIError.shouldNotReachHere();
441            }
442        }
443    },
444
445    new BinaryOp.Rem(false, false) {
446
447        @Override
448        public Constant foldConstant(Constant const1, Constant const2) {
449            PrimitiveConstant a = (PrimitiveConstant) const1;
450            PrimitiveConstant b = (PrimitiveConstant) const2;
451            assert a.getKind() == b.getKind();
452            switch (a.getKind()) {
453                case Float:
454                    return JavaConstant.forFloat(a.asFloat() % b.asFloat());
455                case Double:
456                    return JavaConstant.forDouble(a.asDouble() % b.asDouble());
457                default:
458                    throw JVMCIError.shouldNotReachHere();
459            }
460        }
461
462        @Override
463        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
464            // TODO
465            return stamp1.unrestricted();
466        }
467    },
468
469    new UnaryOp.Not() {
470
471        @Override
472        public Constant foldConstant(Constant c) {
473            PrimitiveConstant value = (PrimitiveConstant) c;
474            switch (value.getKind()) {
475                case Float:
476                    int f = Float.floatToRawIntBits(value.asFloat());
477                    return JavaConstant.forFloat(Float.intBitsToFloat(~f));
478                case Double:
479                    long d = Double.doubleToRawLongBits(value.asDouble());
480                    return JavaConstant.forDouble(Double.longBitsToDouble(~d));
481                default:
482                    throw JVMCIError.shouldNotReachHere();
483            }
484        }
485
486        @Override
487        public Stamp foldStamp(Stamp s) {
488            return s.unrestricted();
489        }
490    },
491
492    new BinaryOp.And(true, true) {
493
494        @Override
495        public Constant foldConstant(Constant const1, Constant const2) {
496            PrimitiveConstant a = (PrimitiveConstant) const1;
497            PrimitiveConstant b = (PrimitiveConstant) const2;
498            assert a.getKind() == b.getKind();
499            switch (a.getKind()) {
500                case Float:
501                    int fa = Float.floatToRawIntBits(a.asFloat());
502                    int fb = Float.floatToRawIntBits(b.asFloat());
503                    return JavaConstant.forFloat(Float.intBitsToFloat(fa & fb));
504                case Double:
505                    long da = Double.doubleToRawLongBits(a.asDouble());
506                    long db = Double.doubleToRawLongBits(b.asDouble());
507                    return JavaConstant.forDouble(Double.longBitsToDouble(da & db));
508                default:
509                    throw JVMCIError.shouldNotReachHere();
510            }
511        }
512
513        @Override
514        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
515            return stamp1.unrestricted();
516        }
517
518        @Override
519        public boolean isNeutral(Constant n) {
520            PrimitiveConstant value = (PrimitiveConstant) n;
521            switch (value.getKind()) {
522                case Float:
523                    return Float.floatToRawIntBits(value.asFloat()) == 0xFFFFFFFF;
524                case Double:
525                    return Double.doubleToRawLongBits(value.asDouble()) == 0xFFFFFFFFFFFFFFFFL;
526                default:
527                    throw JVMCIError.shouldNotReachHere();
528            }
529        }
530    },
531
532    new BinaryOp.Or(true, true) {
533
534        @Override
535        public Constant foldConstant(Constant const1, Constant const2) {
536            PrimitiveConstant a = (PrimitiveConstant) const1;
537            PrimitiveConstant b = (PrimitiveConstant) const2;
538            assert a.getKind() == b.getKind();
539            switch (a.getKind()) {
540                case Float:
541                    int fa = Float.floatToRawIntBits(a.asFloat());
542                    int fb = Float.floatToRawIntBits(b.asFloat());
543                    return JavaConstant.forFloat(Float.intBitsToFloat(fa | fb));
544                case Double:
545                    long da = Double.doubleToRawLongBits(a.asDouble());
546                    long db = Double.doubleToRawLongBits(b.asDouble());
547                    return JavaConstant.forDouble(Double.longBitsToDouble(da | db));
548                default:
549                    throw JVMCIError.shouldNotReachHere();
550            }
551        }
552
553        @Override
554        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
555            return stamp1.unrestricted();
556        }
557
558        @Override
559        public boolean isNeutral(Constant n) {
560            PrimitiveConstant value = (PrimitiveConstant) n;
561            switch (value.getKind()) {
562                case Float:
563                    return Float.floatToRawIntBits(value.asFloat()) == 0;
564                case Double:
565                    return Double.doubleToRawLongBits(value.asDouble()) == 0L;
566                default:
567                    throw JVMCIError.shouldNotReachHere();
568            }
569        }
570    },
571
572    new BinaryOp.Xor(true, true) {
573
574        @Override
575        public Constant foldConstant(Constant const1, Constant const2) {
576            PrimitiveConstant a = (PrimitiveConstant) const1;
577            PrimitiveConstant b = (PrimitiveConstant) const2;
578            assert a.getKind() == b.getKind();
579            switch (a.getKind()) {
580                case Float:
581                    int fa = Float.floatToRawIntBits(a.asFloat());
582                    int fb = Float.floatToRawIntBits(b.asFloat());
583                    return JavaConstant.forFloat(Float.intBitsToFloat(fa ^ fb));
584                case Double:
585                    long da = Double.doubleToRawLongBits(a.asDouble());
586                    long db = Double.doubleToRawLongBits(b.asDouble());
587                    return JavaConstant.forDouble(Double.longBitsToDouble(da ^ db));
588                default:
589                    throw JVMCIError.shouldNotReachHere();
590            }
591        }
592
593        @Override
594        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
595            return stamp1.unrestricted();
596        }
597
598        @Override
599        public boolean isNeutral(Constant n) {
600            PrimitiveConstant value = (PrimitiveConstant) n;
601            switch (value.getKind()) {
602                case Float:
603                    return Float.floatToRawIntBits(value.asFloat()) == 0;
604                case Double:
605                    return Double.doubleToRawLongBits(value.asDouble()) == 0L;
606                default:
607                    throw JVMCIError.shouldNotReachHere();
608            }
609        }
610    },
611
612    null, null, null,
613
614    new UnaryOp.Abs() {
615
616        @Override
617        public Constant foldConstant(Constant c) {
618            PrimitiveConstant value = (PrimitiveConstant) c;
619            switch (value.getKind()) {
620                case Float:
621                    return JavaConstant.forFloat(Math.abs(value.asFloat()));
622                case Double:
623                    return JavaConstant.forDouble(Math.abs(value.asDouble()));
624                default:
625                    throw JVMCIError.shouldNotReachHere();
626            }
627        }
628
629        @Override
630        public Stamp foldStamp(Stamp s) {
631            FloatStamp stamp = (FloatStamp) s;
632            if (stamp.isNaN()) {
633                return stamp;
634            }
635            return new FloatStamp(stamp.getBits(), 0, Math.max(-stamp.lowerBound(), stamp.upperBound()), stamp.isNonNaN());
636        }
637    },
638
639    new UnaryOp.Sqrt() {
640
641        @Override
642        public Constant foldConstant(Constant c) {
643            PrimitiveConstant value = (PrimitiveConstant) c;
644            switch (value.getKind()) {
645                case Float:
646                    return JavaConstant.forFloat((float) Math.sqrt(value.asFloat()));
647                case Double:
648                    return JavaConstant.forDouble(Math.sqrt(value.asDouble()));
649                default:
650                    throw JVMCIError.shouldNotReachHere();
651            }
652        }
653
654        @Override
655        public Stamp foldStamp(Stamp s) {
656            return s.unrestricted();
657        }
658    },
659
660    null, null, null,
661
662    new FloatConvertOp(F2I) {
663
664        @Override
665        public Constant foldConstant(Constant c) {
666            PrimitiveConstant value = (PrimitiveConstant) c;
667            return JavaConstant.forInt((int) value.asFloat());
668        }
669
670        @Override
671        public Stamp foldStamp(Stamp stamp) {
672            FloatStamp floatStamp = (FloatStamp) stamp;
673            assert floatStamp.getBits() == 32;
674            boolean mustHaveZero = !floatStamp.isNonNaN();
675            int lowerBound = (int) floatStamp.lowerBound();
676            int upperBound = (int) floatStamp.upperBound();
677            if (mustHaveZero) {
678                if (lowerBound > 0) {
679                    lowerBound = 0;
680                } else if (upperBound < 0) {
681                    upperBound = 0;
682                }
683            }
684            return StampFactory.forInteger(Kind.Int, lowerBound, upperBound);
685        }
686    },
687
688    new FloatConvertOp(F2L) {
689
690        @Override
691        public Constant foldConstant(Constant c) {
692            PrimitiveConstant value = (PrimitiveConstant) c;
693            return JavaConstant.forLong((long) value.asFloat());
694        }
695
696        @Override
697        public Stamp foldStamp(Stamp stamp) {
698            FloatStamp floatStamp = (FloatStamp) stamp;
699            assert floatStamp.getBits() == 32;
700            boolean mustHaveZero = !floatStamp.isNonNaN();
701            long lowerBound = (long) floatStamp.lowerBound();
702            long upperBound = (long) floatStamp.upperBound();
703            if (mustHaveZero) {
704                if (lowerBound > 0) {
705                    lowerBound = 0;
706                } else if (upperBound < 0) {
707                    upperBound = 0;
708                }
709            }
710            return StampFactory.forInteger(Kind.Long, lowerBound, upperBound);
711        }
712    },
713
714    new FloatConvertOp(D2I) {
715
716        @Override
717        public Constant foldConstant(Constant c) {
718            PrimitiveConstant value = (PrimitiveConstant) c;
719            return JavaConstant.forInt((int) value.asDouble());
720        }
721
722        @Override
723        public Stamp foldStamp(Stamp stamp) {
724            FloatStamp floatStamp = (FloatStamp) stamp;
725            assert floatStamp.getBits() == 64;
726            boolean mustHaveZero = !floatStamp.isNonNaN();
727            int lowerBound = (int) floatStamp.lowerBound();
728            int upperBound = (int) floatStamp.upperBound();
729            if (mustHaveZero) {
730                if (lowerBound > 0) {
731                    lowerBound = 0;
732                } else if (upperBound < 0) {
733                    upperBound = 0;
734                }
735            }
736            return StampFactory.forInteger(Kind.Int, lowerBound, upperBound);
737        }
738    },
739
740    new FloatConvertOp(D2L) {
741
742        @Override
743        public Constant foldConstant(Constant c) {
744            PrimitiveConstant value = (PrimitiveConstant) c;
745            return JavaConstant.forLong((long) value.asDouble());
746        }
747
748        @Override
749        public Stamp foldStamp(Stamp stamp) {
750            FloatStamp floatStamp = (FloatStamp) stamp;
751            assert floatStamp.getBits() == 64;
752            boolean mustHaveZero = !floatStamp.isNonNaN();
753            long lowerBound = (long) floatStamp.lowerBound();
754            long upperBound = (long) floatStamp.upperBound();
755            if (mustHaveZero) {
756                if (lowerBound > 0) {
757                    lowerBound = 0;
758                } else if (upperBound < 0) {
759                    upperBound = 0;
760                }
761            }
762            return StampFactory.forInteger(Kind.Long, lowerBound, upperBound);
763        }
764    },
765
766    new FloatConvertOp(F2D) {
767
768        @Override
769        public Constant foldConstant(Constant c) {
770            PrimitiveConstant value = (PrimitiveConstant) c;
771            return JavaConstant.forDouble(value.asFloat());
772        }
773
774        @Override
775        public Stamp foldStamp(Stamp stamp) {
776            FloatStamp floatStamp = (FloatStamp) stamp;
777            assert floatStamp.getBits() == 32;
778            return StampFactory.forFloat(Kind.Double, floatStamp.lowerBound(), floatStamp.upperBound(), floatStamp.isNonNaN());
779        }
780    },
781
782    new FloatConvertOp(D2F) {
783
784        @Override
785        public Constant foldConstant(Constant c) {
786            PrimitiveConstant value = (PrimitiveConstant) c;
787            return JavaConstant.forFloat((float) value.asDouble());
788        }
789
790        @Override
791        public Stamp foldStamp(Stamp stamp) {
792            FloatStamp floatStamp = (FloatStamp) stamp;
793            assert floatStamp.getBits() == 64;
794            return StampFactory.forFloat(Kind.Float, (float) floatStamp.lowerBound(), (float) floatStamp.upperBound(), floatStamp.isNonNaN());
795        }
796    });
797}