blob: 73c807f749523c0d98f2fc9f91fc8023e731d93d [file] [log] [blame]
/*
* Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.nodes;
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
import java.util.Map;
import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.type.AbstractObjectStamp;
import org.graalvm.compiler.core.common.type.FloatStamp;
import org.graalvm.compiler.core.common.type.IntegerStamp;
import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.graph.iterators.NodeIterable;
import org.graalvm.compiler.lir.ConstantValue;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodeinfo.Verbosity;
import org.graalvm.compiler.nodes.calc.FloatingNode;
import org.graalvm.compiler.nodes.spi.LIRLowerable;
import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
import jdk.vm.ci.code.CodeUtil;
import jdk.vm.ci.meta.Constant;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.MetaAccessProvider;
import jdk.vm.ci.meta.PrimitiveConstant;
/**
* The {@code ConstantNode} represents a {@link Constant constant}.
*/
@NodeInfo(nameTemplate = "C({p#rawvalue})", cycles = CYCLES_0, size = SIZE_1)
public final class ConstantNode extends FloatingNode implements LIRLowerable {
public static final NodeClass<ConstantNode> TYPE = NodeClass.create(ConstantNode.class);
protected final Constant value;
private final int stableDimension;
private final boolean isDefaultStable;
private static ConstantNode createPrimitive(JavaConstant value) {
assert value.getJavaKind() != JavaKind.Object;
return new ConstantNode(value, StampFactory.forConstant(value));
}
/**
* Constructs a new node representing the specified constant.
*
* @param value the constant
*/
public ConstantNode(Constant value, Stamp stamp) {
this(value, stamp, 0, false);
}
private ConstantNode(Constant value, Stamp stamp, int stableDimension, boolean isDefaultStable) {
super(TYPE, stamp);
assert stamp != null && stamp.isCompatible(value) : stamp + " " + value;
this.value = value;
this.stableDimension = stableDimension;
if (stableDimension == 0) {
/*
* Ensure that isDefaultStable has a canonical value to avoid having two constant nodes
* that only differ in this field. The value of isDefaultStable is only used when we
* have a stable array dimension.
*/
this.isDefaultStable = false;
} else {
this.isDefaultStable = isDefaultStable;
}
}
/**
* @return the constant value represented by this node
*/
public Constant getValue() {
return value;
}
/**
* @return the number of stable dimensions if this is a stable array, otherwise 0
*/
public int getStableDimension() {
return stableDimension;
}
/**
* @return true if this is a stable array and the default elements are considered stable
*/
public boolean isDefaultStable() {
return isDefaultStable;
}
/**
* Gathers all the {@link ConstantNode}s that are inputs to the
* {@linkplain StructuredGraph#getNodes() live nodes} in a given graph.
*/
public static NodeIterable<ConstantNode> getConstantNodes(StructuredGraph graph) {
return graph.getNodes().filter(ConstantNode.class);
}
/**
* Replaces this node at its usages with another node.
*/
public void replace(StructuredGraph graph, Node replacement) {
assert graph == graph();
replaceAtUsagesAndDelete(replacement);
}
@Override
public void generate(NodeLIRBuilderTool gen) {
LIRKind kind = gen.getLIRGeneratorTool().getLIRKind(stamp());
if (onlyUsedInVirtualState()) {
gen.setResult(this, new ConstantValue(kind, value));
} else {
gen.setResult(this, gen.getLIRGeneratorTool().emitConstant(kind, value));
}
}
private boolean onlyUsedInVirtualState() {
for (Node n : this.usages()) {
if (n instanceof VirtualState) {
// Only virtual usage.
} else {
return false;
}
}
return true;
}
public static ConstantNode forConstant(JavaConstant constant, MetaAccessProvider metaAccess, StructuredGraph graph) {
if (constant.getJavaKind().getStackKind() == JavaKind.Int && constant.getJavaKind() != JavaKind.Int) {
return forInt(constant.asInt(), graph);
}
if (constant.getJavaKind() == JavaKind.Object) {
return unique(graph, new ConstantNode(constant, StampFactory.forConstant(constant, metaAccess)));
} else {
return unique(graph, createPrimitive(constant));
}
}
public static ConstantNode forConstant(JavaConstant constant, int stableDimension, boolean isDefaultStable, MetaAccessProvider metaAccess) {
if (constant.getJavaKind().getStackKind() == JavaKind.Int && constant.getJavaKind() != JavaKind.Int) {
return forInt(constant.asInt());
}
if (constant.getJavaKind() == JavaKind.Object) {
return new ConstantNode(constant, StampFactory.forConstant(constant, metaAccess), stableDimension, isDefaultStable);
} else {
assert stableDimension == 0;
return createPrimitive(constant);
}
}
public static ConstantNode forConstant(JavaConstant array, MetaAccessProvider metaAccess) {
return forConstant(array, 0, false, metaAccess);
}
public static ConstantNode forConstant(Stamp stamp, Constant constant, MetaAccessProvider metaAccess, StructuredGraph graph) {
return graph.unique(new ConstantNode(constant, stamp.constant(constant, metaAccess)));
}
public static ConstantNode forConstant(Stamp stamp, Constant constant, int stableDimension, boolean isDefaultStable, MetaAccessProvider metaAccess) {
return new ConstantNode(constant, stamp.constant(constant, metaAccess), stableDimension, isDefaultStable);
}
public static ConstantNode forConstant(Stamp stamp, Constant constant, MetaAccessProvider metaAccess) {
return new ConstantNode(constant, stamp.constant(constant, metaAccess));
}
/**
* Returns a node for a Java primitive.
*/
public static ConstantNode forPrimitive(JavaConstant constant, StructuredGraph graph) {
assert constant.getJavaKind() != JavaKind.Object;
return forConstant(constant, null, graph);
}
/**
* Returns a node for a Java primitive.
*/
public static ConstantNode forPrimitive(JavaConstant constant) {
assert constant.getJavaKind() != JavaKind.Object;
return forConstant(constant, null);
}
/**
* Returns a node for a primitive of a given type.
*/
public static ConstantNode forPrimitive(Stamp stamp, JavaConstant constant, StructuredGraph graph) {
if (stamp instanceof IntegerStamp) {
assert constant.getJavaKind().isNumericInteger() && stamp.getStackKind() == constant.getJavaKind().getStackKind();
IntegerStamp istamp = (IntegerStamp) stamp;
return forIntegerBits(istamp.getBits(), constant, graph);
} else {
assert constant.getJavaKind().isNumericFloat() && stamp.getStackKind() == constant.getJavaKind();
return forPrimitive(constant, graph);
}
}
/**
* Returns a node for a primitive of a given type.
*/
public static ConstantNode forPrimitive(Stamp stamp, Constant constant) {
if (stamp instanceof IntegerStamp) {
PrimitiveConstant primitive = (PrimitiveConstant) constant;
assert primitive.getJavaKind().isNumericInteger() && stamp.getStackKind() == primitive.getJavaKind().getStackKind();
IntegerStamp istamp = (IntegerStamp) stamp;
return forIntegerBits(istamp.getBits(), primitive);
} else if (stamp instanceof FloatStamp) {
PrimitiveConstant primitive = (PrimitiveConstant) constant;
assert primitive.getJavaKind().isNumericFloat() && stamp.getStackKind() == primitive.getJavaKind();
return forConstant(primitive, null);
} else {
assert !(stamp instanceof AbstractObjectStamp);
return new ConstantNode(constant, stamp.constant(constant, null));
}
}
/**
* Returns a node for a double constant.
*
* @param d the double value for which to create the instruction
* @return a node for a double constant
*/
public static ConstantNode forDouble(double d, StructuredGraph graph) {
return unique(graph, createPrimitive(JavaConstant.forDouble(d)));
}
/**
* Returns a node for a double constant.
*
* @param d the double value for which to create the instruction
* @return a node for a double constant
*/
public static ConstantNode forDouble(double d) {
return createPrimitive(JavaConstant.forDouble(d));
}
/**
* Returns a node for a float constant.
*
* @param f the float value for which to create the instruction
* @return a node for a float constant
*/
public static ConstantNode forFloat(float f, StructuredGraph graph) {
return unique(graph, createPrimitive(JavaConstant.forFloat(f)));
}
/**
* Returns a node for a float constant.
*
* @param f the float value for which to create the instruction
* @return a node for a float constant
*/
public static ConstantNode forFloat(float f) {
return createPrimitive(JavaConstant.forFloat(f));
}
/**
* Returns a node for an long constant.
*
* @param i the long value for which to create the instruction
* @return a node for an long constant
*/
public static ConstantNode forLong(long i, StructuredGraph graph) {
return unique(graph, createPrimitive(JavaConstant.forLong(i)));
}
/**
* Returns a node for an long constant.
*
* @param i the long value for which to create the instruction
* @return a node for an long constant
*/
public static ConstantNode forLong(long i) {
return createPrimitive(JavaConstant.forLong(i));
}
/**
* Returns a node for an integer constant.
*
* @param i the integer value for which to create the instruction
* @return a node for an integer constant
*/
public static ConstantNode forInt(int i, StructuredGraph graph) {
return unique(graph, createPrimitive(JavaConstant.forInt(i)));
}
/**
* Returns a node for an integer constant.
*
* @param i the integer value for which to create the instruction
* @return a node for an integer constant
*/
public static ConstantNode forInt(int i) {
return createPrimitive(JavaConstant.forInt(i));
}
/**
* Returns a node for a boolean constant.
*
* @param i the boolean value for which to create the instruction
* @return a node representing the boolean
*/
public static ConstantNode forBoolean(boolean i, StructuredGraph graph) {
return unique(graph, createPrimitive(JavaConstant.forInt(i ? 1 : 0)));
}
/**
* Returns a node for a boolean constant.
*
* @param i the boolean value for which to create the instruction
* @return a node representing the boolean
*/
public static ConstantNode forBoolean(boolean i) {
return createPrimitive(JavaConstant.forInt(i ? 1 : 0));
}
/**
* Returns a node for a byte constant.
*
* @param i the byte value for which to create the instruction
* @return a node representing the byte
*/
public static ConstantNode forByte(byte i, StructuredGraph graph) {
return unique(graph, createPrimitive(JavaConstant.forInt(i)));
}
/**
* Returns a node for a char constant.
*
* @param i the char value for which to create the instruction
* @return a node representing the char
*/
public static ConstantNode forChar(char i, StructuredGraph graph) {
return unique(graph, createPrimitive(JavaConstant.forInt(i)));
}
/**
* Returns a node for a short constant.
*
* @param i the short value for which to create the instruction
* @return a node representing the short
*/
public static ConstantNode forShort(short i, StructuredGraph graph) {
return unique(graph, createPrimitive(JavaConstant.forInt(i)));
}
private static ConstantNode unique(StructuredGraph graph, ConstantNode node) {
return graph.unique(node);
}
private static ConstantNode forIntegerBits(int bits, JavaConstant constant, StructuredGraph graph) {
long value = constant.asLong();
long bounds = CodeUtil.signExtend(value, bits);
return unique(graph, new ConstantNode(constant, StampFactory.forInteger(bits, bounds, bounds)));
}
/**
* Returns a node for a constant integer that's not directly representable as Java primitive
* (e.g. short).
*/
public static ConstantNode forIntegerBits(int bits, long value, StructuredGraph graph) {
return forIntegerBits(bits, JavaConstant.forPrimitiveInt(bits, value), graph);
}
private static ConstantNode forIntegerBits(int bits, JavaConstant constant) {
long value = constant.asLong();
long bounds = CodeUtil.signExtend(value, bits);
return new ConstantNode(constant, StampFactory.forInteger(bits, bounds, bounds));
}
/**
* Returns a node for a constant integer that's not directly representable as Java primitive
* (e.g. short).
*/
public static ConstantNode forIntegerBits(int bits, long value) {
return forIntegerBits(bits, JavaConstant.forPrimitiveInt(bits, value));
}
/**
* Returns a node for a constant integer that's compatible to a given stamp.
*/
public static ConstantNode forIntegerStamp(Stamp stamp, long value, StructuredGraph graph) {
if (stamp instanceof IntegerStamp) {
IntegerStamp intStamp = (IntegerStamp) stamp;
return forIntegerBits(intStamp.getBits(), value, graph);
} else {
return forIntegerKind(stamp.getStackKind(), value, graph);
}
}
/**
* Returns a node for a constant integer that's compatible to a given stamp.
*/
public static ConstantNode forIntegerStamp(Stamp stamp, long value) {
if (stamp instanceof IntegerStamp) {
IntegerStamp intStamp = (IntegerStamp) stamp;
return forIntegerBits(intStamp.getBits(), value);
} else {
return forIntegerKind(stamp.getStackKind(), value);
}
}
public static ConstantNode forIntegerKind(JavaKind kind, long value, StructuredGraph graph) {
switch (kind) {
case Byte:
case Short:
case Int:
return ConstantNode.forInt((int) value, graph);
case Long:
return ConstantNode.forLong(value, graph);
default:
throw GraalError.shouldNotReachHere("unknown kind " + kind);
}
}
public static ConstantNode forIntegerKind(JavaKind kind, long value) {
switch (kind) {
case Byte:
case Short:
case Int:
return createPrimitive(JavaConstant.forInt((int) value));
case Long:
return createPrimitive(JavaConstant.forLong(value));
default:
throw GraalError.shouldNotReachHere("unknown kind " + kind);
}
}
public static ConstantNode forFloatingKind(JavaKind kind, double value, StructuredGraph graph) {
switch (kind) {
case Float:
return ConstantNode.forFloat((float) value, graph);
case Double:
return ConstantNode.forDouble(value, graph);
default:
throw GraalError.shouldNotReachHere("unknown kind " + kind);
}
}
public static ConstantNode forFloatingKind(JavaKind kind, double value) {
switch (kind) {
case Float:
return ConstantNode.forFloat((float) value);
case Double:
return ConstantNode.forDouble(value);
default:
throw GraalError.shouldNotReachHere("unknown kind " + kind);
}
}
/**
* Returns a node for a constant double that's compatible to a given stamp.
*/
public static ConstantNode forFloatingStamp(Stamp stamp, double value, StructuredGraph graph) {
return forFloatingKind(stamp.getStackKind(), value, graph);
}
/**
* Returns a node for a constant double that's compatible to a given stamp.
*/
public static ConstantNode forFloatingStamp(Stamp stamp, double value) {
return forFloatingKind(stamp.getStackKind(), value);
}
public static ConstantNode defaultForKind(JavaKind kind, StructuredGraph graph) {
return unique(graph, defaultForKind(kind));
}
public static ConstantNode defaultForKind(JavaKind kind) {
switch (kind) {
case Boolean:
case Byte:
case Char:
case Short:
case Int:
return ConstantNode.forInt(0);
case Double:
return ConstantNode.forDouble(0.0);
case Float:
return ConstantNode.forFloat(0.0f);
case Long:
return ConstantNode.forLong(0L);
case Object:
return ConstantNode.forConstant(JavaConstant.NULL_POINTER, null);
default:
return null;
}
}
@Override
public Map<Object, Object> getDebugProperties(Map<Object, Object> map) {
Map<Object, Object> properties = super.getDebugProperties(map);
properties.put("rawvalue", value.toValueString());
return properties;
}
@Override
public String toString(Verbosity verbosity) {
if (verbosity == Verbosity.Name) {
return super.toString(Verbosity.Name) + "(" + value.toValueString() + ")";
} else {
return super.toString(verbosity);
}
}
}