changeset 14037:ffc6847d87c6

GraphKit: add support for if-then-else constructs
author Christian Wimmer <christian.wimmer@oracle.com>
date Thu, 27 Feb 2014 17:11:28 -0800
parents 6db511bddb84
children af0519781660
files graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXWrapperBuilder.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java
diffstat 2 files changed, 170 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXWrapperBuilder.java	Thu Feb 27 17:04:24 2014 -0800
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXWrapperBuilder.java	Thu Feb 27 17:11:28 2014 -0800
@@ -237,7 +237,7 @@
             int javaParameterOffset = javaParameterOffsetsInKernelParametersBuffer[javaParametersIndex];
             LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, javaParameter.kind(), javaParameterOffset, getGraph());
             append(new WriteNode(buf, javaParameter, location, BarrierType.NONE, false, false));
-            updateDimArg(method, providers, sig, sigIndex++, args, javaParameter);
+            updateDimArg(method, sig, sigIndex++, args, javaParameter);
         }
         if (returnKind != Kind.Void) {
             LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, bufSize - wordSize, getGraph());
@@ -324,7 +324,7 @@
      * Updates the {@code dimX}, {@code dimY} or {@code dimZ} argument passed to the kernel if
      * {@code javaParameter} is annotated with {@link ParallelOver}.
      */
-    private void updateDimArg(ResolvedJavaMethod method, HotSpotProviders providers, Signature sig, int sigIndex, Map<LaunchArg, ValueNode> launchArgs, ParameterNode javaParameter) {
+    private void updateDimArg(ResolvedJavaMethod method, Signature sig, int sigIndex, Map<LaunchArg, ValueNode> launchArgs, ParameterNode javaParameter) {
         if (sigIndex >= 0) {
             ParallelOver parallelOver = getParameterAnnotation(ParallelOver.class, sigIndex, method);
             if (parallelOver != null && sig.getParameterType(sigIndex, method.getDeclaringClass()).equals(providers.getMetaAccess().lookupJavaType(int[].class))) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Thu Feb 27 17:04:24 2014 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Thu Feb 27 17:11:28 2014 -0800
@@ -23,6 +23,7 @@
 package com.oracle.graal.replacements;
 
 import java.lang.reflect.*;
+import java.util.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
@@ -44,14 +45,24 @@
  */
 public class GraphKit {
 
-    private final Providers providers;
-    private final StructuredGraph graph;
-    private FixedWithNextNode lastFixedNode;
+    protected final Providers providers;
+    protected final StructuredGraph graph;
+    protected FixedWithNextNode lastFixedNode;
+
+    private final List<Structure> structures;
+
+    abstract static class Structure {
+    }
 
     public GraphKit(StructuredGraph graph, Providers providers) {
         this.providers = providers;
         this.graph = graph;
         this.lastFixedNode = graph.start();
+
+        structures = new ArrayList<>();
+        /* Add a dummy element, so that the access of the last element never leads to an exception. */
+        structures.add(new Structure() {
+        });
     }
 
     public StructuredGraph getGraph() {
@@ -83,31 +94,59 @@
         return result;
     }
 
+    public InvokeNode createInvoke(Class<?> declaringClass, String name, ValueNode... args) {
+        return createInvoke(declaringClass, name, InvokeKind.Static, null, FrameState.UNKNOWN_BCI, args);
+    }
+
     /**
      * Creates and appends an {@link InvokeNode} for a call to a given method with a given set of
-     * arguments.
+     * arguments. The method is looked up via reflection based on the declaring class and name.
      * 
      * @param declaringClass the class declaring the invoked method
      * @param name the name of the invoked method
      * @param args the arguments to the invocation
      */
-    public InvokeNode createInvoke(Class<?> declaringClass, String name, ValueNode... args) {
+    public InvokeNode createInvoke(Class<?> declaringClass, String name, InvokeKind invokeKind, FrameStateBuilder frameStateBuilder, int bci, ValueNode... args) {
+        boolean isStatic = invokeKind == InvokeKind.Static;
         ResolvedJavaMethod method = null;
         for (Method m : declaringClass.getDeclaredMethods()) {
-            if (Modifier.isStatic(m.getModifiers()) && m.getName().equals(name)) {
+            if (Modifier.isStatic(m.getModifiers()) == isStatic && m.getName().equals(name)) {
                 assert method == null : "found more than one method in " + declaringClass + " named " + name;
                 method = providers.getMetaAccess().lookupJavaMethod(m);
             }
         }
         assert method != null : "did not find method in " + declaringClass + " named " + name;
+        return createInvoke(method, invokeKind, frameStateBuilder, bci, args);
+    }
+
+    /**
+     * Creates and appends an {@link InvokeNode} for a call to a given method with a given set of
+     * arguments.
+     */
+    public InvokeNode createInvoke(ResolvedJavaMethod method, InvokeKind invokeKind, FrameStateBuilder frameStateBuilder, int bci, ValueNode... args) {
+        assert Modifier.isStatic(method.getModifiers()) == (invokeKind == InvokeKind.Static);
         Signature signature = method.getSignature();
         JavaType returnType = signature.getReturnType(null);
         assert checkArgs(method, args);
-        MethodCallTargetNode callTarget = graph.add(new MethodCallTargetNode(InvokeKind.Static, method, args, returnType));
-        InvokeNode invoke = append(new InvokeNode(callTarget, FrameState.UNKNOWN_BCI));
+        MethodCallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, method, args, returnType, bci));
+        InvokeNode invoke = append(new InvokeNode(callTarget, bci));
+
+        if (frameStateBuilder != null) {
+            if (invoke.kind() != Kind.Void) {
+                frameStateBuilder.push(invoke.kind(), invoke);
+            }
+            invoke.setStateAfter(frameStateBuilder.create(0));
+            if (invoke.kind() != Kind.Void) {
+                frameStateBuilder.pop(invoke.kind());
+            }
+        }
         return invoke;
     }
 
+    protected MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, JavaType returnType, @SuppressWarnings("unused") int bci) {
+        return new MethodCallTargetNode(invokeKind, targetMethod, args, returnType);
+    }
+
     /**
      * Determines if a given set of arguments is compatible with the signature of a given method.
      * 
@@ -117,14 +156,21 @@
      */
     public boolean checkArgs(ResolvedJavaMethod method, ValueNode... args) {
         Signature signature = method.getSignature();
-        if (signature.getParameterCount(false) != args.length) {
+        boolean isStatic = Modifier.isStatic(method.getModifiers());
+        if (signature.getParameterCount(!isStatic) != args.length) {
             throw new AssertionError(graph + ": wrong number of arguments to " + method);
         }
+        int paramNum = 0;
         for (int i = 0; i != args.length; i++) {
-            Kind expected = signature.getParameterKind(i).getStackKind();
+            Kind expected;
+            if (i == 0 && !isStatic) {
+                expected = Kind.Object;
+            } else {
+                expected = signature.getParameterKind(paramNum++).getStackKind();
+            }
             Kind actual = args[i].stamp().getStackKind();
             if (expected != actual) {
-                throw new AssertionError(graph + ": wrong kind of value for argument " + i + " of calls to " + method + " [" + actual + " != " + expected + "]");
+                throw new AssertionError(graph + ": wrong kind of value for argument " + i + " of call to " + method + " [" + actual + " != " + expected + "]");
             }
         }
         return true;
@@ -161,4 +207,115 @@
         StructuredGraph calleeGraph = repl.makeGraph(method, null, method, null, FrameStateProcessing.CollapseFrameForSingleSideEffect);
         InliningUtil.inline(invoke, calleeGraph, false);
     }
+
+    protected void pushStructure(Structure structure) {
+        structures.add(structure);
+    }
+
+    protected <T extends Structure> T getTopStructure(Class<T> expectedClass) {
+        return expectedClass.cast(structures.get(structures.size() - 1));
+    }
+
+    protected void popStructure() {
+        structures.remove(structures.size() - 1);
+    }
+
+    protected enum IfState {
+        CONDITION, THEN_PART, ELSE_PART, FINISHED
+    }
+
+    static class IfStructure extends Structure {
+        protected IfState state;
+        protected FixedNode thenPart;
+        protected FixedNode elsePart;
+    }
+
+    /**
+     * Starts an if-block. This call can be followed by a call to {@link #thenPart} to start
+     * emitting the code executed when the condition hold; and a call to {@link #elsePart} to start
+     * emititng the code when the condition does not hold. It must be followed by a call to
+     * {@link #endIf} to close the if-block.
+     * 
+     * @param condition The condition for the if-block
+     * @param trueProbability The estimated probability the the condition is true
+     */
+    public void startIf(LogicNode condition, double trueProbability) {
+        BeginNode thenSuccessor = graph.add(new BeginNode());
+        BeginNode elseSuccessor = graph.add(new BeginNode());
+        append(new IfNode(condition, thenSuccessor, elseSuccessor, trueProbability));
+        lastFixedNode = null;
+
+        IfStructure s = new IfStructure();
+        s.state = IfState.CONDITION;
+        s.thenPart = thenSuccessor;
+        s.elsePart = elseSuccessor;
+        pushStructure(s);
+    }
+
+    private IfStructure saveLastNode() {
+        IfStructure s = getTopStructure(IfStructure.class);
+        switch (s.state) {
+            case CONDITION:
+                assert lastFixedNode == null;
+                break;
+            case THEN_PART:
+                s.thenPart = lastFixedNode;
+                break;
+            case ELSE_PART:
+                s.elsePart = lastFixedNode;
+                break;
+            case FINISHED:
+                assert false;
+                break;
+        }
+        lastFixedNode = null;
+        return s;
+    }
+
+    public void thenPart() {
+        IfStructure s = saveLastNode();
+        lastFixedNode = (FixedWithNextNode) s.thenPart;
+        s.state = IfState.THEN_PART;
+    }
+
+    public void elsePart() {
+        IfStructure s = saveLastNode();
+        lastFixedNode = (FixedWithNextNode) s.elsePart;
+        s.state = IfState.ELSE_PART;
+    }
+
+    public void endIf() {
+        IfStructure s = saveLastNode();
+
+        FixedWithNextNode thenPart = s.thenPart instanceof FixedWithNextNode ? (FixedWithNextNode) s.thenPart : null;
+        FixedWithNextNode elsePart = s.elsePart instanceof FixedWithNextNode ? (FixedWithNextNode) s.elsePart : null;
+
+        if (thenPart != null && elsePart != null) {
+            /* Both parts are alive, we need a real merge. */
+            EndNode thenEnd = graph.add(new EndNode());
+            graph.addAfterFixed(thenPart, thenEnd);
+            EndNode elseEnd = graph.add(new EndNode());
+            graph.addAfterFixed(elsePart, elseEnd);
+
+            MergeNode merge = graph.add(new MergeNode());
+            merge.addForwardEnd(thenEnd);
+            merge.addForwardEnd(elseEnd);
+
+            lastFixedNode = merge;
+
+        } else if (thenPart != null) {
+            /* elsePart ended with a control sink, so we can continue with thenPart. */
+            lastFixedNode = thenPart;
+
+        } else if (elsePart != null) {
+            /* thenPart ended with a control sink, so we can continue with elsePart. */
+            lastFixedNode = elsePart;
+
+        } else {
+            /* Both parts ended with a control sink, so no nodes can be added after the if. */
+            assert lastFixedNode == null;
+        }
+        s.state = IfState.FINISHED;
+        popStructure();
+    }
 }