changeset 14611:1d853e629891

fixed canonicalization of ArrayEqualsNode, added Virtualizable implementation
author Lukas Stadler <lukas.stadler@oracle.com>
date Wed, 19 Mar 2014 12:01:30 +0100
parents aef9e4224076
children 3c8de2692867 abf7cf57df5e
files graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java
diffstat 2 files changed, 129 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java	Wed Mar 19 09:08:22 2014 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java	Wed Mar 19 12:01:30 2014 +0100
@@ -29,8 +29,12 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.nodes.*;
+import com.oracle.graal.virtual.phases.ea.*;
 
 /**
  * Tests {@link ArraysSubstitutions}.
@@ -350,4 +354,90 @@
         }
     }
 
+    @Test
+    public void testConstants() {
+        test("testConstantsSnippet");
+    }
+
+    public static final int[] constantArray1 = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9};
+    public static final int[] constantArray2 = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9};
+
+    public static boolean testConstantsSnippet() {
+        constantArray2[0] = 10;
+        try {
+            return Arrays.equals(constantArray1, constantArray2);
+        } finally {
+            constantArray2[0] = 1;
+        }
+    }
+
+    @Test
+    public void testCanonicalLength() {
+        StructuredGraph graph = parse("testCanonicalLengthSnippet");
+        Assumptions assumptions = new Assumptions(false);
+        HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
+
+        Assert.assertTrue(graph.getNodes(ReturnNode.class).first().result().asConstant().asLong() == 0);
+    }
+
+    public static final int[] constantArray3 = new int[]{1, 2, 3};
+
+    public static boolean testCanonicalLengthSnippet() {
+        return Arrays.equals(constantArray1, constantArray3);
+    }
+
+    @Test
+    public void testCanonicalEqual() {
+        StructuredGraph graph = parse("testCanonicalEqualSnippet");
+        Assumptions assumptions = new Assumptions(false);
+        HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
+
+        Assert.assertTrue(graph.getNodes(ReturnNode.class).first().result().asConstant().asLong() == 1);
+    }
+
+    public static boolean testCanonicalEqualSnippet() {
+        return Arrays.equals(constantArray1, constantArray1);
+    }
+
+    @Test
+    public void testVirtualEqual() {
+        StructuredGraph graph = parse("testVirtualEqualSnippet");
+        Assumptions assumptions = new Assumptions(false);
+        HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
+        new PartialEscapePhase(false, new CanonicalizerPhase(false)).apply(graph, context);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
+
+        Assert.assertTrue(graph.getNodes(ReturnNode.class).first().result().asConstant().asLong() == 1);
+    }
+
+    public static boolean testVirtualEqualSnippet() {
+        int[] array1 = new int[]{1, 2, 3, 4};
+        int[] array2 = new int[]{1, 2, 3, 4};
+        return Arrays.equals(array1, array2);
+    }
+
+    @Test
+    public void testVirtualNotEqual() {
+        StructuredGraph graph = parse("testVirtualNotEqualSnippet");
+        Assumptions assumptions = new Assumptions(false);
+        HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
+        new PartialEscapePhase(false, new CanonicalizerPhase(false)).apply(graph, context);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
+
+        Assert.assertTrue(graph.getNodes(ReturnNode.class).first().result().asConstant().asLong() == 0);
+    }
+
+    public static boolean testVirtualNotEqualSnippet(int x) {
+        int[] array1 = new int[]{1, 2, 100, x};
+        int[] array2 = new int[]{1, 2, 3, 4};
+        return Arrays.equals(array1, array2);
+    }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java	Wed Mar 19 09:08:22 2014 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java	Wed Mar 19 12:01:30 2014 +0100
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.replacements.nodes;
 
-import java.util.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
@@ -31,12 +29,14 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
 
 /**
  * Compares two arrays with the same length.
  */
-public class ArrayEqualsNode extends FixedWithNextNode implements LIRGenLowerable, Canonicalizable {
+public class ArrayEqualsNode extends FixedWithNextNode implements LIRGenLowerable, Canonicalizable, Virtualizable {
 
     /** {@link Kind} of the arrays to compare. */
     private final Kind kind;
@@ -65,42 +65,45 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (!array1.isConstant() || !array2.isConstant()) {
-            return this;
+        if (usages().isEmpty()) {
+            return null;
         }
+        if (GraphUtil.unproxify(array1) == GraphUtil.unproxify(array2)) {
+            return ConstantNode.forBoolean(true, graph());
+        }
+        return this;
+    }
 
-        Object a1 = array1.asConstant().asObject();
-        Object a2 = array2.asConstant().asObject();
-        boolean x;
-        switch (kind) {
-            case Boolean:
-                x = Arrays.equals((boolean[]) a1, (boolean[]) a2);
-                break;
-            case Byte:
-                x = Arrays.equals((byte[]) a1, (byte[]) a2);
-                break;
-            case Char:
-                x = Arrays.equals((char[]) a1, (char[]) a2);
-                break;
-            case Short:
-                x = Arrays.equals((short[]) a1, (short[]) a2);
-                break;
-            case Int:
-                x = Arrays.equals((int[]) a1, (int[]) a2);
-                break;
-            case Long:
-                x = Arrays.equals((long[]) a1, (long[]) a2);
-                break;
-            case Float:
-                x = Arrays.equals((float[]) a1, (float[]) a2);
-                break;
-            case Double:
-                x = Arrays.equals((double[]) a1, (double[]) a2);
-                break;
-            default:
-                throw GraalInternalError.shouldNotReachHere("unknown kind " + kind);
+    public void virtualize(VirtualizerTool tool) {
+        State state1 = tool.getObjectState(array1);
+        if (state1 != null) {
+            State state2 = tool.getObjectState(array2);
+            if (state2 != null) {
+                if (state1.getVirtualObject() == state2.getVirtualObject()) {
+                    // the same virtual objects will always have the same contents
+                    tool.replaceWithValue(ConstantNode.forBoolean(true, graph()));
+                } else if (state1.getVirtualObject().entryCount() == state2.getVirtualObject().entryCount()) {
+                    int entryCount = state1.getVirtualObject().entryCount();
+                    boolean allEqual = true;
+                    for (int i = 0; i < entryCount; i++) {
+                        ValueNode entry1 = state1.getEntry(i);
+                        ValueNode entry2 = state2.getEntry(i);
+                        if (entry1 != entry2) {
+                            // the contents might be different
+                            allEqual = false;
+                        }
+                        if (entry1.stamp().alwaysDistinct(entry2.stamp())) {
+                            // the contents are different
+                            tool.replaceWithValue(ConstantNode.forBoolean(false, graph()));
+                            return;
+                        }
+                    }
+                    if (allEqual) {
+                        tool.replaceWithValue(ConstantNode.forBoolean(true, graph()));
+                    }
+                }
+            }
         }
-        return ConstantNode.forBoolean(x, graph());
     }
 
     @NodeIntrinsic