use of org.graalvm.compiler.nodes.ValuePhiNode in project graal by oracle.
the class JNIJavaCallWrapperMethod method buildGraph.
@Override
public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers, Purpose purpose) {
UniverseMetaAccess metaAccess = (UniverseMetaAccess) providers.getMetaAccess();
JNIGraphKit kit = new JNIGraphKit(debug, providers, method);
StructuredGraph graph = kit.getGraph();
FrameStateBuilder state = new FrameStateBuilder(null, method, graph);
state.initializeForMethodStart(null, true, providers.getGraphBuilderPlugins());
JavaKind vmThreadKind = metaAccess.lookupJavaType(JNIEnvironment.class).getJavaKind();
ValueNode vmThread = kit.loadLocal(0, vmThreadKind);
kit.append(new CEntryPointEnterNode(EnterAction.Enter, vmThread));
ResolvedJavaMethod invokeMethod = providers.getMetaAccess().lookupJavaMethod(reflectMethod);
Signature invokeSignature = invokeMethod.getSignature();
List<Pair<ValueNode, ResolvedJavaType>> argsWithTypes = loadAndUnboxArguments(kit, providers, invokeMethod, invokeSignature);
JavaKind returnKind = invokeSignature.getReturnKind();
if (invokeMethod.isConstructor()) {
// return `this` to implement NewObject
assert returnKind == JavaKind.Void;
returnKind = JavaKind.Object;
}
IfNode ifNode = kit.startIf(null, BranchProbabilityNode.FAST_PATH_PROBABILITY);
kit.thenPart();
LogicNode typeChecks = LogicConstantNode.tautology(kit.getGraph());
ValueNode[] args = new ValueNode[argsWithTypes.size()];
for (int i = 0; i < argsWithTypes.size(); i++) {
ValueNode value = argsWithTypes.get(i).getLeft();
ResolvedJavaType type = argsWithTypes.get(i).getRight();
if (!type.isPrimitive() && !type.isJavaLangObject()) {
TypeReference typeRef = TypeReference.createTrusted(kit.getAssumptions(), type);
LogicNode instanceOf = kit.unique(InstanceOfNode.createAllowNull(typeRef, value, null, null));
typeChecks = LogicNode.and(typeChecks, instanceOf, BranchProbabilityNode.FAST_PATH_PROBABILITY);
FixedGuardNode guard = kit.append(new FixedGuardNode(instanceOf, DeoptimizationReason.ClassCastException, DeoptimizationAction.None, false));
value = kit.append(PiNode.create(value, StampFactory.object(typeRef), guard));
}
args[i] = value;
}
// safe because logic nodes are floating
ifNode.setCondition(typeChecks);
InvokeKind kind = //
invokeMethod.isStatic() ? //
InvokeKind.Static : ((nonVirtual || invokeMethod.isConstructor()) ? InvokeKind.Special : InvokeKind.Virtual);
ValueNode invokeResult = createInvoke(kit, invokeMethod, kind, state, kit.bci(), args);
if (invokeMethod.isConstructor()) {
// return `this` to implement NewObject
invokeResult = args[0];
}
// illegal parameter types
kit.elsePart();
ConstantNode exceptionObject = kit.createObject(cachedArgumentClassCastException);
kit.retainPendingException(exceptionObject);
ValueNode typeMismatchValue = null;
if (returnKind != JavaKind.Void) {
typeMismatchValue = kit.unique(ConstantNode.defaultForKind(returnKind.getStackKind()));
}
AbstractMergeNode merge = kit.endIf();
ValueNode returnValue = null;
if (returnKind != JavaKind.Void) {
ValueNode[] inputs = { invokeResult, typeMismatchValue };
returnValue = kit.getGraph().addWithoutUnique(new ValuePhiNode(invokeResult.stamp(NodeView.DEFAULT), merge, inputs));
state.push(returnKind, returnValue);
}
merge.setStateAfter(state.create(kit.bci(), merge));
if (returnKind != JavaKind.Void) {
state.pop(returnKind);
if (returnKind.isObject()) {
returnValue = kit.boxObjectInLocalHandle(returnValue);
}
}
kit.append(new CEntryPointLeaveNode(LeaveAction.Leave));
kit.createReturn(returnValue, returnKind);
assert graph.verify();
return graph;
}
use of org.graalvm.compiler.nodes.ValuePhiNode in project graal by oracle.
the class JNIJavaCallWrapperMethod method createInvoke.
private static ValueNode createInvoke(JNIGraphKit kit, ResolvedJavaMethod invokeMethod, InvokeKind kind, FrameStateBuilder state, int bci, ValueNode... args) {
int exceptionEdgeBci = kit.bci();
InvokeWithExceptionNode invoke = kit.startInvokeWithException(invokeMethod, kind, state, bci, exceptionEdgeBci, args);
kit.exceptionPart();
ExceptionObjectNode exceptionObject = kit.exceptionObject();
kit.retainPendingException(exceptionObject);
ValueNode exceptionValue = null;
if (invoke.getStackKind() != JavaKind.Void) {
exceptionValue = kit.unique(ConstantNode.defaultForKind(invoke.getStackKind()));
}
AbstractMergeNode merge = kit.endInvokeWithException();
ValueNode returnValue = null;
JavaKind returnKind = invokeMethod.getSignature().getReturnKind();
if (invoke.getStackKind() != JavaKind.Void) {
ValueNode[] inputs = { invoke, exceptionValue };
returnValue = kit.getGraph().addWithoutUnique(new ValuePhiNode(invoke.stamp(NodeView.DEFAULT), merge, inputs));
state.push(returnKind, returnValue);
}
merge.setStateAfter(state.create(bci, merge));
if (invoke.getStackKind() != JavaKind.Void) {
state.pop(returnKind);
}
return returnValue;
}
use of org.graalvm.compiler.nodes.ValuePhiNode in project graal by oracle.
the class JNIPrimitiveArrayOperationMethod method newArray.
private ValueNode newArray(HostedProviders providers, JNIGraphKit kit, List<ValueNode> arguments) {
ResolvedJavaType elementType = providers.getMetaAccess().lookupJavaType(elementKind.toJavaClass());
ValueNode length = arguments.get(1);
ConstantNode zero = kit.createInt(0);
kit.startIf(new IntegerLessThanNode(length, zero), BranchProbabilityNode.VERY_SLOW_PATH_PROBABILITY);
kit.thenPart();
ValueNode nullHandle = kit.createConstant(JavaConstant.INT_0, providers.getWordTypes().getWordKind());
kit.elsePart();
ValueNode array = kit.append(new NewArrayNode(elementType, length, true));
ValueNode arrayHandle = kit.boxObjectInLocalHandle(array);
AbstractMergeNode merge = kit.endIf();
Stamp handleStamp = providers.getWordTypes().getWordStamp(providers.getMetaAccess().lookupJavaType(JNIObjectHandle.class));
return kit.unique(new ValuePhiNode(handleStamp, merge, new ValueNode[] { nullHandle, arrayHandle }));
}
use of org.graalvm.compiler.nodes.ValuePhiNode in project graal by oracle.
the class LoopFragment method mergeEarlyExits.
/**
* Merges the early exits (i.e. loop exits) that were duplicated as part of this fragment, with
* the original fragment's exits.
*/
protected void mergeEarlyExits() {
assert isDuplicate();
StructuredGraph graph = graph();
for (AbstractBeginNode earlyExit : LoopFragment.toHirBlocks(original().loop().loop().getExits())) {
LoopExitNode loopEarlyExit = (LoopExitNode) earlyExit;
FixedNode next = loopEarlyExit.next();
if (loopEarlyExit.isDeleted() || !this.original().contains(loopEarlyExit)) {
continue;
}
AbstractBeginNode newEarlyExit = getDuplicatedNode(loopEarlyExit);
if (newEarlyExit == null) {
continue;
}
MergeNode merge = graph.add(new MergeNode());
EndNode originalEnd = graph.add(new EndNode());
EndNode newEnd = graph.add(new EndNode());
merge.addForwardEnd(originalEnd);
merge.addForwardEnd(newEnd);
loopEarlyExit.setNext(originalEnd);
newEarlyExit.setNext(newEnd);
merge.setNext(next);
FrameState exitState = loopEarlyExit.stateAfter();
if (exitState != null) {
FrameState originalExitState = exitState;
exitState = exitState.duplicateWithVirtualState();
loopEarlyExit.setStateAfter(exitState);
merge.setStateAfter(originalExitState);
/*
* Using the old exit's state as the merge's state is necessary because some of the
* VirtualState nodes contained in the old exit's state may be shared by other
* dominated VirtualStates. Those dominated virtual states need to see the
* proxy->phi update that are applied below.
*
* We now update the original fragment's nodes accordingly:
*/
originalExitState.applyToVirtual(node -> original.nodes.clearAndGrow(node));
exitState.applyToVirtual(node -> original.nodes.markAndGrow(node));
}
FrameState finalExitState = exitState;
for (Node anchored : loopEarlyExit.anchored().snapshot()) {
anchored.replaceFirstInput(loopEarlyExit, merge);
}
boolean newEarlyExitIsLoopExit = newEarlyExit instanceof LoopExitNode;
for (ProxyNode vpn : loopEarlyExit.proxies().snapshot()) {
if (vpn.hasNoUsages()) {
continue;
}
if (vpn.value() == null) {
assert vpn instanceof GuardProxyNode;
vpn.replaceAtUsages(null);
continue;
}
final ValueNode replaceWith;
ValueNode newVpn = prim(newEarlyExitIsLoopExit ? vpn : vpn.value());
if (newVpn != null) {
PhiNode phi;
if (vpn instanceof ValueProxyNode) {
phi = graph.addWithoutUnique(new ValuePhiNode(vpn.stamp(NodeView.DEFAULT), merge));
} else if (vpn instanceof GuardProxyNode) {
phi = graph.addWithoutUnique(new GuardPhiNode(merge));
} else {
throw GraalError.shouldNotReachHere();
}
phi.addInput(vpn);
phi.addInput(newVpn);
replaceWith = phi;
} else {
replaceWith = vpn.value();
}
vpn.replaceAtMatchingUsages(replaceWith, usage -> {
if (merge.isPhiAtMerge(usage)) {
return false;
}
if (usage instanceof VirtualState) {
VirtualState stateUsage = (VirtualState) usage;
if (finalExitState != null && finalExitState.isPartOfThisState(stateUsage)) {
return false;
}
}
return true;
});
}
}
}
use of org.graalvm.compiler.nodes.ValuePhiNode in project graal by oracle.
the class LoopEx method findInductionVariables.
/**
* Collect all the basic induction variables for the loop and the find any induction variables
* which are derived from the basic ones.
*
* @param loop
* @return a map from node to induction variable
*/
private static EconomicMap<Node, InductionVariable> findInductionVariables(LoopEx loop) {
EconomicMap<Node, InductionVariable> ivs = EconomicMap.create(Equivalence.IDENTITY);
Queue<InductionVariable> scanQueue = new LinkedList<>();
LoopBeginNode loopBegin = loop.loopBegin();
AbstractEndNode forwardEnd = loopBegin.forwardEnd();
for (PhiNode phi : loopBegin.valuePhis()) {
ValueNode backValue = phi.singleBackValueOrThis();
if (backValue == phi) {
continue;
}
ValueNode stride = addSub(loop, backValue, phi);
if (stride != null) {
BasicInductionVariable biv = new BasicInductionVariable(loop, (ValuePhiNode) phi, phi.valueAt(forwardEnd), stride, (BinaryArithmeticNode<?>) backValue);
ivs.put(phi, biv);
scanQueue.add(biv);
}
}
while (!scanQueue.isEmpty()) {
InductionVariable baseIv = scanQueue.remove();
ValueNode baseIvNode = baseIv.valueNode();
for (ValueNode op : baseIvNode.usages().filter(ValueNode.class)) {
if (loop.isOutsideLoop(op)) {
continue;
}
if (op.usages().count() == 1 && op.usages().first() == baseIvNode) {
/*
* This is just the base induction variable increment with no other uses so
* don't bother reporting it.
*/
continue;
}
InductionVariable iv = null;
ValueNode offset = addSub(loop, op, baseIvNode);
ValueNode scale;
if (offset != null) {
iv = new DerivedOffsetInductionVariable(loop, baseIv, offset, (BinaryArithmeticNode<?>) op);
} else if (op instanceof NegateNode) {
iv = new DerivedScaledInductionVariable(loop, baseIv, (NegateNode) op);
} else if ((scale = mul(loop, op, baseIvNode)) != null) {
iv = new DerivedScaledInductionVariable(loop, baseIv, scale, op);
} else {
boolean isValidConvert = op instanceof PiNode || op instanceof SignExtendNode;
if (!isValidConvert && op instanceof ZeroExtendNode) {
ZeroExtendNode zeroExtendNode = (ZeroExtendNode) op;
isValidConvert = zeroExtendNode.isInputAlwaysPositive() || ((IntegerStamp) zeroExtendNode.stamp(NodeView.DEFAULT)).isPositive();
}
if (isValidConvert) {
iv = new DerivedConvertedInductionVariable(loop, baseIv, op.stamp(NodeView.DEFAULT), op);
}
}
if (iv != null) {
ivs.put(op, iv);
scanQueue.offer(iv);
}
}
}
return ivs;
}
Aggregations