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.nodes.type;
024
025import java.util.*;
026
027import jdk.internal.jvmci.meta.*;
028
029import com.oracle.graal.compiler.common.type.*;
030import com.oracle.graal.nodes.*;
031
032/**
033 * Helper class that is used to keep all stamp-related operations in one place.
034 */
035public class StampTool {
036
037    public static Stamp meet(Collection<? extends ValueNode> values) {
038        Iterator<? extends ValueNode> iterator = values.iterator();
039        if (iterator.hasNext()) {
040            Stamp stamp = iterator.next().stamp();
041            while (iterator.hasNext()) {
042                stamp = stamp.meet(iterator.next().stamp());
043            }
044            return stamp;
045        } else {
046            return StampFactory.forVoid();
047        }
048    }
049
050    /**
051     * Compute the stamp resulting from the unsigned comparison being true.
052     *
053     * @return null if it's can't be true or it nothing useful can be encoded.
054     */
055    public static Stamp unsignedCompare(Stamp stamp, Stamp stamp2) {
056        IntegerStamp x = (IntegerStamp) stamp;
057        IntegerStamp y = (IntegerStamp) stamp2;
058        if (x == x.unrestricted() && y == y.unrestricted()) {
059            // Don't know anything.
060            return null;
061        }
062        // c <| n, where c is a constant and n is known to be positive.
063        if (x.lowerBound() == x.upperBound()) {
064            if (y.isPositive()) {
065                if (x.lowerBound() == (1 << x.getBits()) - 1) {
066                    // Constant is MAX_VALUE which must fail.
067                    return null;
068                }
069                if (x.lowerBound() <= y.lowerBound()) {
070                    // Test will fail. Return illegalStamp instead?
071                    return null;
072                }
073                // If the test succeeds then this proves that n is at greater than c so the bounds
074                // are [c+1..-n.upperBound)].
075                return StampFactory.forInteger(x.getBits(), x.lowerBound() + 1, y.upperBound());
076            }
077            return null;
078        }
079        // n <| c, where c is a strictly positive constant
080        if (y.lowerBound() == y.upperBound() && y.isStrictlyPositive()) {
081            // The test proves that n is positive and less than c, [0..c-1]
082            return StampFactory.forInteger(y.getBits(), 0, y.lowerBound() - 1);
083        }
084        return null;
085    }
086
087    /**
088     * Checks whether this {@link ValueNode} represents a {@linkplain Stamp#hasValues() legal}
089     * pointer value which is known to be always null.
090     *
091     * @param node the node to check
092     * @return true if this node represents a legal object value which is known to be always null
093     */
094    public static boolean isPointerAlwaysNull(ValueNode node) {
095        return isPointerAlwaysNull(node.stamp());
096    }
097
098    /**
099     * Checks whether this {@link Stamp} represents a {@linkplain Stamp#hasValues() legal} pointer
100     * stamp whose values are known to be always null.
101     *
102     * @param stamp the stamp to check
103     * @return true if this stamp represents a legal object stamp whose values are known to be
104     *         always null
105     */
106    public static boolean isPointerAlwaysNull(Stamp stamp) {
107        if (stamp instanceof AbstractPointerStamp && stamp.hasValues()) {
108            return ((AbstractPointerStamp) stamp).alwaysNull();
109        }
110        return false;
111    }
112
113    /**
114     * Checks whether this {@link ValueNode} represents a {@linkplain Stamp#hasValues() legal}
115     * pointer value which is known to never be null.
116     *
117     * @param node the node to check
118     * @return true if this node represents a legal object value which is known to never be null
119     */
120    public static boolean isPointerNonNull(ValueNode node) {
121        return isPointerNonNull(node.stamp());
122    }
123
124    /**
125     * Checks whether this {@link Stamp} represents a {@linkplain Stamp#hasValues() legal} pointer
126     * stamp whose values are known to never be null.
127     *
128     * @param stamp the stamp to check
129     * @return true if this stamp represents a legal object stamp whose values are known to be
130     *         always null
131     */
132    public static boolean isPointerNonNull(Stamp stamp) {
133        if (stamp instanceof AbstractPointerStamp) {
134            return ((AbstractPointerStamp) stamp).nonNull();
135        }
136        return false;
137    }
138
139    /**
140     * Returns the {@linkplain ResolvedJavaType Java type} this {@linkplain ValueNode} has if it is
141     * a {@linkplain Stamp#hasValues() legal} Object value.
142     *
143     * @param node the node to check
144     * @return the Java type this value has if it is a legal Object type, null otherwise
145     */
146    public static ResolvedJavaType typeOrNull(ValueNode node) {
147        return typeOrNull(node.stamp());
148    }
149
150    /**
151     * Returns the {@linkplain ResolvedJavaType Java type} this {@linkplain Stamp} has if it is a
152     * {@linkplain Stamp#hasValues() legal} Object stamp.
153     *
154     * @param stamp the stamp to check
155     * @return the Java type this stamp has if it is a legal Object stamp, null otherwise
156     */
157    public static ResolvedJavaType typeOrNull(Stamp stamp) {
158        if (stamp instanceof AbstractObjectStamp && stamp.hasValues()) {
159            return ((AbstractObjectStamp) stamp).type();
160        }
161        return null;
162    }
163
164    /**
165     * Checks whether this {@link ValueNode} represents a {@linkplain Stamp#hasValues() legal}
166     * Object value whose Java type is known exactly. If this method returns true then the
167     * {@linkplain ResolvedJavaType Java type} returned by {@link #typeOrNull(ValueNode)} is the
168     * concrete dynamic/runtime Java type of this value.
169     *
170     * @param node the node to check
171     * @return true if this node represents a legal object value whose Java type is known exactly
172     */
173    public static boolean isExactType(ValueNode node) {
174        return isExactType(node.stamp());
175    }
176
177    /**
178     * Checks whether this {@link Stamp} represents a {@linkplain Stamp#hasValues() legal} Object
179     * stamp whose {@linkplain ResolvedJavaType Java type} is known exactly. If this method returns
180     * true then the Java type returned by {@link #typeOrNull(Stamp)} is the only concrete
181     * dynamic/runtime Java type possible for values of this stamp.
182     *
183     * @param stamp the stamp to check
184     * @return true if this node represents a legal object stamp whose Java type is known exactly
185     */
186    public static boolean isExactType(Stamp stamp) {
187        if (stamp instanceof AbstractObjectStamp && stamp.hasValues()) {
188            return ((AbstractObjectStamp) stamp).isExactType();
189        }
190        return false;
191    }
192}