use of org.graalvm.compiler.nodes.ValuePhiNode in project graal by oracle.
the class EarlyReadEliminationTest method testBadLoop.
@Test
public void testBadLoop() {
ValueNode result = getReturn("testBadLoopSnippet", false).result();
assertDeepEquals(0, result.graph().getNodes().filter(LoadFieldNode.class).count());
assertTrue(result instanceof ProxyNode);
assertTrue(((ProxyNode) result).value() instanceof ValuePhiNode);
}
use of org.graalvm.compiler.nodes.ValuePhiNode in project graal by oracle.
the class FrameStateBuilder method createValuePhi.
private ValuePhiNode createValuePhi(ValueNode currentValue, ValueNode otherValue, AbstractMergeNode block) {
ValuePhiNode phi = graph.addWithoutUnique(new ValuePhiNode(currentValue.stamp(NodeView.DEFAULT).unrestricted(), block));
for (int i = 0; i < block.phiPredecessorCount(); i++) {
phi.addInput(currentValue);
}
phi.addInput(otherValue);
assert phi.valueCount() == block.phiPredecessorCount() + 1;
return phi;
}
use of org.graalvm.compiler.nodes.ValuePhiNode in project graal by oracle.
the class LoopFragmentInside method patchPeeling.
private void patchPeeling(LoopFragmentInside peel) {
LoopBeginNode loopBegin = loop().loopBegin();
StructuredGraph graph = loopBegin.graph();
List<PhiNode> newPhis = new LinkedList<>();
NodeBitMap usagesToPatch = nodes.copy();
for (LoopExitNode exit : exits()) {
markStateNodes(exit, usagesToPatch);
for (ProxyNode proxy : exit.proxies()) {
usagesToPatch.markAndGrow(proxy);
}
}
markStateNodes(loopBegin, usagesToPatch);
List<PhiNode> oldPhis = loopBegin.phis().snapshot();
for (PhiNode phi : oldPhis) {
if (phi.hasNoUsages()) {
continue;
}
ValueNode first;
if (loopBegin.loopEnds().count() == 1) {
// back edge value
ValueNode b = phi.valueAt(loopBegin.loopEnds().first());
// corresponding value in the peel
first = peel.prim(b);
} else {
first = peel.mergedInitializers.get(phi);
}
// create a new phi (we don't patch the old one since some usages of the old one may
// still be valid)
PhiNode newPhi = patchPhi(graph, phi, loopBegin);
newPhi.addInput(first);
for (LoopEndNode end : loopBegin.orderedLoopEnds()) {
newPhi.addInput(phi.valueAt(end));
}
peel.putDuplicatedNode(phi, newPhi);
newPhis.add(newPhi);
for (Node usage : phi.usages().snapshot()) {
// patch only usages that should use the new phi ie usages that were peeled
if (usagesToPatch.isMarkedAndGrow(usage)) {
usage.replaceFirstInput(phi, newPhi);
}
}
}
// new corresponding phis
for (PhiNode phi : newPhis) {
for (int i = 0; i < phi.valueCount(); i++) {
ValueNode v = phi.valueAt(i);
if (loopBegin.isPhiAtMerge(v)) {
PhiNode newV = peel.getDuplicatedNode((ValuePhiNode) v);
if (newV != null) {
phi.setValueAt(i, newV);
}
}
}
}
boolean progress = true;
while (progress) {
progress = false;
int i = 0;
outer: while (i < oldPhis.size()) {
PhiNode oldPhi = oldPhis.get(i);
for (Node usage : oldPhi.usages()) {
if (usage instanceof PhiNode && oldPhis.contains(usage)) {
// Do not mark.
} else {
// Mark alive by removing from delete set.
oldPhis.remove(i);
progress = true;
continue outer;
}
}
i++;
}
}
for (PhiNode deadPhi : oldPhis) {
deadPhi.clearInputs();
}
for (PhiNode deadPhi : oldPhis) {
if (deadPhi.isAlive()) {
GraphUtil.killWithUnusedFloatingInputs(deadPhi);
}
}
}
use of org.graalvm.compiler.nodes.ValuePhiNode in project graal by oracle.
the class InferStamps method inferStamps.
/**
* Infer the stamps for all Object nodes in the graph, to make the stamps as precise as
* possible. For example, this propagates the word-type through phi functions. To handle phi
* functions at loop headers, the stamp inference is called until a fix point is reached.
* <p>
* This method can be used when it is needed that stamps are inferred before the first run of
* the canonicalizer. For example, word type rewriting must run before the first run of the
* canonicalizer because many nodes are not prepared to see the word type during
* canonicalization.
*/
public static void inferStamps(StructuredGraph graph) {
/*
* We want to make the stamps more precise. For cyclic phi functions, this means we have to
* ignore the initial stamp because the imprecise stamp would always propagate around the
* cycle. We therefore set the stamp to an illegal stamp, which is automatically ignored
* when the phi function performs the "meet" operator on its input stamps.
*/
for (Node n : graph.getNodes()) {
if (n instanceof ValuePhiNode) {
ValueNode node = (ValueNode) n;
if (node.stamp(NodeView.DEFAULT) instanceof ObjectStamp) {
assert node.stamp(NodeView.DEFAULT).hasValues() : "We assume all Phi and Proxy stamps are legal before the analysis";
node.setStamp(node.stamp(NodeView.DEFAULT).empty());
}
}
}
boolean stampChanged;
// The algorithm is not guaranteed to reach a stable state.
int z = 0;
do {
stampChanged = false;
/*
* We could use GraphOrder.forwardGraph() to process the nodes in a defined order and
* propagate long def-use chains in fewer iterations. However, measurements showed that
* we have few iterations anyway, and the overhead of computing the order is much higher
* than the benefit.
*/
for (Node n : graph.getNodes()) {
if (n instanceof ValueNode) {
ValueNode node = (ValueNode) n;
if (node.stamp(NodeView.DEFAULT) instanceof ObjectStamp) {
stampChanged |= node.inferStamp();
}
}
}
++z;
} while (stampChanged && z < 10000);
/*
* Check that all the illegal stamps we introduced above are correctly replaced with real
* stamps again.
*/
assert checkNoEmptyStamp(graph);
}
use of org.graalvm.compiler.nodes.ValuePhiNode in project graal by oracle.
the class JNIJavaCallWrapperMethod method loadAndUnboxArguments.
private List<Pair<ValueNode, ResolvedJavaType>> loadAndUnboxArguments(JNIGraphKit kit, HostedProviders providers, ResolvedJavaMethod invokeMethod, Signature invokeSignature) {
MetaAccessProvider metaAccess = providers.getMetaAccess();
List<Pair<ValueNode, ResolvedJavaType>> args = new ArrayList<>();
int javaIndex = 0;
javaIndex += metaAccess.lookupJavaType(JNIEnvironment.class).getJavaKind().getSlotCount();
if (!invokeMethod.isStatic()) {
JavaKind kind = metaAccess.lookupJavaType(JNIObjectHandle.class).getJavaKind();
ValueNode handle = kit.loadLocal(javaIndex, kind);
ValueNode unboxed = kit.unboxHandle(handle);
ValueNode receiver;
ResolvedJavaType receiverClass = invokeMethod.getDeclaringClass();
if (invokeMethod.isConstructor()) {
/*
* Our target method is a constructor and we might be called via `NewObject`, in
* which case we need to allocate the object before calling the constructor. We can
* detect when this is the case because unlike with `Call<Type>Method`, we are
* passed the object hub of our target class in place of the receiver object.
*/
Constant hub = providers.getConstantReflection().asObjectHub(receiverClass);
ConstantNode hubNode = kit.createConstant(hub, JavaKind.Object);
kit.startIf(kit.unique(new ObjectEqualsNode(unboxed, hubNode)), BranchProbabilityNode.FAST_PATH_PROBABILITY);
kit.thenPart();
ValueNode created = kit.append(new NewInstanceNode(receiverClass, true));
AbstractMergeNode merge = kit.endIf();
receiver = kit.unique(new ValuePhiNode(StampFactory.object(), merge, new ValueNode[] { created, unboxed }));
} else {
receiver = unboxed;
}
args.add(Pair.create(receiver, receiverClass));
}
javaIndex += metaAccess.lookupJavaType(JNIObjectHandle.class).getJavaKind().getSlotCount();
if (nonVirtual) {
javaIndex += metaAccess.lookupJavaType(JNIObjectHandle.class).getJavaKind().getSlotCount();
}
javaIndex += metaAccess.lookupJavaType(JNIMethodId.class).getJavaKind().getSlotCount();
int count = invokeSignature.getParameterCount(false);
if (callVariant == CallVariant.VARARGS) {
for (int i = 0; i < count; i++) {
ResolvedJavaType type = (ResolvedJavaType) invokeSignature.getParameterType(i, null);
JavaKind kind = type.getJavaKind();
JavaKind loadKind = kind;
if (loadKind == JavaKind.Float) {
// C varargs promote float to double
loadKind = JavaKind.Double;
}
ValueNode value = kit.loadLocal(javaIndex, loadKind);
if (kind == JavaKind.Float) {
value = kit.unique(new FloatConvertNode(FloatConvert.D2F, value));
} else if (kind.isObject()) {
value = kit.unboxHandle(value);
}
args.add(Pair.create(value, type));
javaIndex += loadKind.getSlotCount();
}
} else if (callVariant == CallVariant.ARRAY) {
ResolvedJavaType elementType = metaAccess.lookupJavaType(JNIValue.class);
int elementSize = SizeOf.get(JNIValue.class);
ValueNode array = kit.loadLocal(javaIndex, elementType.getJavaKind());
for (int i = 0; i < count; i++) {
ResolvedJavaType type = (ResolvedJavaType) invokeSignature.getParameterType(i, null);
JavaKind readKind = type.getJavaKind();
StructFieldInfo fieldInfo = getJNIValueOffsetOf(elementType, readKind);
int offset = i * elementSize + fieldInfo.getOffsetInfo().getProperty();
ConstantNode offsetConstant = kit.createConstant(JavaConstant.forInt(offset), providers.getWordTypes().getWordKind());
OffsetAddressNode address = kit.unique(new OffsetAddressNode(array, offsetConstant));
LocationIdentity locationIdentity = fieldInfo.getLocationIdentity();
if (locationIdentity == null) {
locationIdentity = LocationIdentity.any();
}
Stamp readStamp = getNarrowStamp(providers, readKind);
ValueNode value = kit.append(new CInterfaceReadNode(address, locationIdentity, readStamp, BarrierType.NONE, "args[" + i + "]"));
JavaKind stackKind = readKind.getStackKind();
if (readKind != stackKind) {
assert stackKind.getBitCount() > readKind.getBitCount() : "read kind must be narrower than stack kind";
if (readKind.isUnsigned()) {
// needed or another op may illegally sign-extend
value = kit.unique(new ZeroExtendNode(value, stackKind.getBitCount()));
} else {
value = kit.unique(new SignExtendNode(value, stackKind.getBitCount()));
}
} else if (readKind.isObject()) {
value = kit.unboxHandle(value);
}
args.add(Pair.create(value, type));
}
} else if (callVariant == CallVariant.VA_LIST) {
ValueNode valist = kit.loadLocal(javaIndex, metaAccess.lookupJavaType(WordBase.class).getJavaKind());
for (int i = 0; i < count; i++) {
ResolvedJavaType type = (ResolvedJavaType) invokeSignature.getParameterType(i, null);
JavaKind loadKind = type.getJavaKind();
if (loadKind.isObject()) {
loadKind = providers.getWordTypes().getWordKind();
}
ValueNode value = kit.append(new VaListNextArgNode(loadKind, valist));
if (type.getJavaKind().isObject()) {
value = kit.unboxHandle(value);
}
args.add(Pair.create(value, type));
}
} else {
throw VMError.unsupportedFeature("Call variant: " + callVariant);
}
return args;
}
Aggregations