# HG changeset patch # User Lukas Stadler # Date 1331744346 -3600 # Node ID 5bdaa08ba96b0259f90ef5fadfa83693e6dc1e03 # Parent 77aa8141ba416983b9eb8f27bd7cf46ccfbc83b1 add and enable new PropagateTypeCachePhase, add type system tests diff -r 77aa8141ba41 -r 5bdaa08ba96b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Wed Mar 14 17:55:33 2012 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Wed Mar 14 17:59:06 2012 +0100 @@ -150,7 +150,7 @@ new CanonicalizerPhase(target, runtime, assumptions).apply(graph); } - new PropagateTypesPhase(target, runtime, assumptions).apply(graph); + new PropagateTypeCachePhase(target, runtime, assumptions).apply(graph); } if (GraalOptions.Inline && !plan.isPhaseDisabled(InliningPhase.class)) { @@ -164,7 +164,7 @@ } if (GraalOptions.PropagateTypes) { - new PropagateTypesPhase(target, runtime, assumptions).apply(graph); + new PropagateTypeCachePhase(target, runtime, assumptions).apply(graph); } plan.runPhases(PhasePosition.HIGH_LEVEL, graph); @@ -198,6 +198,13 @@ new ReadEliminationPhase().apply(graph); } } + + if (GraalOptions.PropagateTypes) { + new PropagateTypeCachePhase(target, runtime, assumptions).apply(graph); + } + if (GraalOptions.OptGVN) { + new GlobalValueNumberingPhase().apply(graph); + } new DeadCodeEliminationPhase().apply(graph); plan.runPhases(PhasePosition.MID_LEVEL, graph); diff -r 77aa8141ba41 -r 5bdaa08ba96b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java Wed Mar 14 17:55:33 2012 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java Wed Mar 14 17:59:06 2012 +0100 @@ -147,7 +147,7 @@ public static boolean AssumeVerifiedBytecode = true; // Code generator settings - public static boolean PropagateTypes = ____; + public static boolean PropagateTypes = true; public static boolean UseBranchPrediction = true; public static boolean UseExceptionProbability = true; public static boolean AllowExplicitExceptionChecks = true; diff -r 77aa8141ba41 -r 5bdaa08ba96b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/types/PropagateTypeCachePhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/types/PropagateTypeCachePhase.java Wed Mar 14 17:59:06 2012 +0100 @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2012, 2012, 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 com.oracle.graal.compiler.types; + +import java.io.*; +import java.util.*; + +import com.oracle.max.cri.ci.*; +import com.oracle.max.cri.ri.*; +import com.oracle.graal.compiler.phases.*; +import com.oracle.graal.compiler.schedule.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.lir.cfg.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.types.*; +import com.oracle.graal.nodes.spi.types.TypeCanonicalizable.Result; + +public class PropagateTypeCachePhase extends Phase { + + private static final boolean DUMP = false; + + private final CiTarget target; + private final RiRuntime runtime; + private final CiAssumptions assumptions; + + private NodeWorkList changedNodes; + private StructuredGraph currentGraph; + private SchedulePhase schedule; + + private TypeFeedbackChanged changed = new TypeFeedbackChanged(); + private static PrintStream out = System.out; + + private int changes = 0; + +// private static int totalChanges = 0; +// +// static { +// Runtime.getRuntime().addShutdownHook(new Thread() { +// @Override +// public void run() { +// System.out.println("Total changes: " + totalChanges); +// } +// }); +// } + + public PropagateTypeCachePhase(CiTarget target, RiRuntime runtime, CiAssumptions assumptions) { + this.target = target; + this.runtime = runtime; + this.assumptions = assumptions; + } + + @Override + protected void run(StructuredGraph graph) { + +// if (!graph.method().holder().name().contains("IntegerAddNode") || !graph.method().name().equals("canonical")) { +// return; +// } + +// if (!graph.method().name().equals("notifySourceElementRequestor")) { +// return; +// } + +// if (graph.method().holder().name().contains("jj_3R_75")) { +// return; +// } + + this.currentGraph = graph; + new DeadCodeEliminationPhase().apply(graph); + + for (GuardNode guard : graph.getNodes(GuardNode.class)) { + if (guard.condition() != null && guard.condition().usages().size() > 1) { + BooleanNode clone = (BooleanNode) guard.condition().copyWithInputs(); + if (DUMP) { + out.println("replaced!! " + clone); + } + guard.setCondition(clone); + } + } + for (FixedGuardNode guard : graph.getNodes(FixedGuardNode.class)) { + for (int i = 0; i < guard.conditions().size(); i++) { + BooleanNode condition = guard.conditions().get(i); + if (condition != null && condition.usages().size() > 1) { + BooleanNode clone = (BooleanNode) condition.copyWithInputs(); + if (DUMP) { + out.println("replaced!! " + clone); + } + guard.conditions().set(i, clone); + } + } + } + + changedNodes = graph.createNodeWorkList(false, 10); + + schedule = new SchedulePhase(); + schedule.apply(graph); + + new Iterator().apply(schedule.getCFG().getStartBlock()); + + Debug.dump(graph, "After PropagateType iteration"); + if (changes > 0) { +// totalChanges += changes; +// out.println(graph.method() + ": " + changes + " changes"); + } + + CanonicalizerPhase.canonicalize(graph, changedNodes, runtime, target, assumptions); +// outputGraph(graph); + } + + public void outputGraph(StructuredGraph graph) { + SchedulePhase printSchedule = new SchedulePhase(); + printSchedule.apply(graph); + for (Block block : printSchedule.getCFG().getBlocks()) { + System.out.print("Block " + block + " "); + if (block == printSchedule.getCFG().getStartBlock()) { + out.print("* "); + } + System.out.print("-> "); + for (Block succ : block.getSuccessors()) { + out.print(succ + " "); + } + System.out.println(); + for (Node node : printSchedule.getNodesFor().get(block)) { + out.println(" " + node + " (" + node.usages().size() + ")"); + } + } + } + + private class Iterator extends PostOrderBlockIterator { + + private final HashMap caches = new HashMap<>(); + + @Override + protected void block(Block block) { + if (DUMP) { + out.println("======= block B" + block.getId()); + } + final TypeFeedbackCache cache; + if (block.getPredecessors().isEmpty()) { + cache = new TypeFeedbackCache(runtime, currentGraph, changed); + } else { + if (block.getPredecessors().size() == 1) { + cache = caches.get(block.getPredecessors().get(0)).clone(); + Node lastInstruction = block.getPredecessors().get(0).getEndNode(); + if (lastInstruction instanceof ControlSplitNode && lastInstruction instanceof SplitTypeFeedbackProvider) { + ControlSplitNode split = (ControlSplitNode) lastInstruction; + int successorIndex = -1; + for (int i = 0; i < split.blockSuccessorCount(); i++) { + if (split.blockSuccessor(i) == block.getBeginNode()) { + successorIndex = i; + break; + } + } + assert successorIndex != -1; + changed.node = block.getBeginNode(); + ((SplitTypeFeedbackProvider) split).typeFeedback(successorIndex, cache); + if (DUMP) { + out.println("split (edge " + successorIndex + ") " + split + ": " + cache); + } + changed.node = null; + } + } else { + TypeFeedbackCache[] cacheList = new TypeFeedbackCache[block.getPredecessors().size()]; + MergeNode merge = (MergeNode) block.getBeginNode(); + for (int i = 0; i < block.getPredecessors().size(); i++) { + Block predecessor = block.getPredecessors().get(i); + TypeFeedbackCache other = caches.get(predecessor); + int endIndex = merge.forwardEndIndex((EndNode) predecessor.getEndNode()); + cacheList[endIndex] = other; + } + changed.node = merge; + cache = TypeFeedbackCache.meet(cacheList, merge.phis()); + changed.node = null; + if (DUMP) { + out.println("merge " + merge + ": " + cache); + } + } + } + processNodes(block, cache); + } + + private void processNodes(Block block, TypeFeedbackCache cache) { + for (Node node : schedule.nodesFor(block)) { + if (node.isAlive()) { + if (DUMP) { + out.println(node); + } + if (node instanceof TypeCanonicalizable) { + Result canonical = ((TypeCanonicalizable) node).canonical(cache); + + if (canonical != null) { + changes++; +// System.out.print("!"); + if (DUMP) { + out.println("TypeCanonicalizable: replacing " + node + " with " + canonical); + } + if (canonical.dependencies.length > 0) { + for (Node usage : node.usages()) { + if (usage instanceof ValueNode) { + for (Node dependency : canonical.dependencies) { + // TODO(lstadler) dead dependencies should be handled differently + if (dependency.isAlive()) { + ((ValueNode) usage).dependencies().add(dependency); + } + } + } + } + } + ValueNode replacement = canonical.replacement; + currentGraph.replaceFloating((FloatingNode) node, replacement); + changedNodes.addAll(replacement.usages()); + } + } + if (node.isAlive() && node instanceof TypeFeedbackProvider) { + changed.node = node; + ((TypeFeedbackProvider) node).typeFeedback(cache); + if (DUMP) { + out.println(" " + cache); + } + changed.node = null; + } + } + } + caches.put(block, cache); + } + + @Override + protected void loopHeaderInitial(Block block) { + if (DUMP) { + out.println("======= loop block B" + block.getId()); + } + assert block.getPredecessors().get(0) == block.getDominator(); + TypeFeedbackCache cache = caches.get(block.getPredecessors().get(0)).clone(); + processNodes(block, cache); + } + + @Override + protected boolean loopHeader(Block block, int loopVisitedCount) { + if (DUMP) { + out.println("======= loop again block B" + block.getId()); + } + if (loopVisitedCount == 1) { + TypeFeedbackCache[] cacheList = new TypeFeedbackCache[block.getPredecessors().size()]; + LoopBeginNode loop = (LoopBeginNode) block.getBeginNode(); + for (int i = 0; i < block.getPredecessors().size(); i++) { + Block predecessor = block.getPredecessors().get(i); + TypeFeedbackCache other = caches.get(predecessor); + int endIndex; + if (loop.forwardEnd() == predecessor.getEndNode()) { + endIndex = 0; + } else { + endIndex = loop.orderedLoopEnds().indexOf(predecessor.getEndNode()) + 1; + assert endIndex != 0; + } + cacheList[endIndex] = other; + } + TypeFeedbackCache cache = TypeFeedbackCache.meet(cacheList, loop.phis()); + if (DUMP) { + out.println("loop merge " + loop + ": " + cache); + } + processNodes(block, cache); + return true; + } else { + return false; + } + } + } + +} diff -r 77aa8141ba41 -r 5bdaa08ba96b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/types/PropagateTypesPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/types/PropagateTypesPhase.java Wed Mar 14 17:55:33 2012 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/types/PropagateTypesPhase.java Wed Mar 14 17:59:06 2012 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2012, 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 @@ -39,6 +39,7 @@ import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.util.*; public class PropagateTypesPhase extends Phase { @@ -56,7 +57,7 @@ @Override protected void run(StructuredGraph graph) { - +/* new DeadCodeEliminationPhase().apply(graph); changedNodes = graph.createNodeWorkList(false, 10); @@ -72,9 +73,9 @@ new UnscheduleNodes(graph.start()).apply(); - CanonicalizerPhase.canonicalize(graph, changedNodes, runtime, target, assumptions); + CanonicalizerPhase.canonicalize(graph, changedNodes, runtime, target, assumptions);*/ } - +/* private class PiNodeList { public final PiNodeList last; @@ -104,6 +105,48 @@ } } + private static RiResolvedType mergeSuperType(RiResolvedType type1, RiResolvedType type2) { + Set superTypes = new HashSet<>(); + + RiResolvedType current = type1; + while (current != null) { + superTypes.add(current); + current = current.superType(); + } + + current = type2; + while (current != null) { + if (superTypes.contains(current)) { + return current; + } + current = current.superType(); + } + + return null; + } + + private static RiResolvedType mergeType(RiResolvedType type1, RiResolvedType type2) { + if (type1 == null || type2 == null) { + return null; + } + if (type1.isInterface() && !type2.isInterface()) { + if (type1.toJava().isAssignableFrom(type2.toJava())) { + return type1; + } else { + return null; + } + } else if (type2.isInterface() && !type1.isInterface()) { + if (type2.toJava().isAssignableFrom(type1.toJava())) { + return type2; + } else { + return null; + } + } else { + // both are either types or interfaces + return mergeSuperType(type1, type2); + } + } + private class TypeInfo implements MergeableState { private HashMap piNodes = new HashMap<>(); @@ -112,6 +155,16 @@ this.piNodes.putAll(piNodes); } + public ValueNode getNode(ValueNode value) { + PiNodeList list = piNodes.get(value); + if (list == null) { + return value; + } else { + return list.replacement; + } + } + + @Override public TypeInfo clone() { return new TypeInfo(piNodes); @@ -138,6 +191,28 @@ newPiNodes.put(entry.getKey(), list); } } + + for (PhiNode phi : merge.phis()) { + if (phi.kind() == CiKind.Object && phi.valueCount() == (withStates.size() + 1)) { + ValueNode node = getNode(phi.valueAt(0)); + RiResolvedType type = node.declaredType(); + boolean nonNull = node.stamp().nonNull(); + for (int i = 1; i < phi.valueCount(); i++) { + node = withStates.get(i - 1).getNode(phi.valueAt(i)); + type = mergeType(type, node.declaredType()); + nonNull &= node.stamp().nonNull(); + } + if (type != null) { + if (nonNull) { + phi.setStamp(StampFactory.declaredNonNull(type)); + } else { + phi.setStamp(StampFactory.declared(type)); + } + } else if (nonNull) { + phi.setStamp(StampFactory.objectNonNull()); + } + } + } piNodes = newPiNodes; } return true; @@ -166,7 +241,7 @@ if (value.declaredType() != instanceOf.targetClass() || !value.stamp().nonNull()) { PiNode piNode = node.graph().unique(new PiNode(value, (BeginNode) node, StampFactory.declaredNonNull(instanceOf.targetClass()))); PiNodeList list = piNodes.get(value); - piNodes.put(value, new PiNodeList(piNode, list)); + piNodes.put(GraphUtil.producingInstruction(value), new PiNodeList(piNode, list)); } } } else if (ifNode.compare() instanceof CompareNode) { @@ -176,7 +251,7 @@ if (compare.y().isConstant()) { ValueNode value = compare.x(); PiNodeList list = piNodes.get(value); - piNodes.put(value, new PiNodeList(compare.y(), list)); + piNodes.put(GraphUtil.producingInstruction(value), new PiNodeList(compare.y(), list)); } } else if ((node == ifNode.trueSuccessor() && compare.condition() == Condition.NE) || (node == ifNode.falseSuccessor() && compare.condition() == Condition.EQ)) { if (!compare.x().isConstant() && compare.y().isNullConstant() && !compare.x().stamp().nonNull()) { @@ -190,7 +265,7 @@ piNode = node.graph().unique(new PiNode(value, (BeginNode) node, StampFactory.objectNonNull())); } PiNodeList list = piNodes.get(value); - piNodes.put(value, new PiNodeList(piNode, list)); + piNodes.put(GraphUtil.producingInstruction(value), new PiNodeList(piNode, list)); } } } @@ -225,13 +300,14 @@ @Override protected void node(ScheduledNode node) { + if (node instanceof Canonicalizable || node instanceof Invoke) { NodeClassIterator iter = node.inputs().iterator(); ArrayList changedInputs = new ArrayList<>(); while (iter.hasNext()) { Position pos = iter.nextPosition(); Node value = pos.get(node); - PiNodeList list = state.piNodes.get(value); + PiNodeList list = value == null ? null : state.piNodes.get(GraphUtil.producingInstruction(value)); if (list != null) { changedInputs.add(list.replacement instanceof PiNode ? value : null); pos.set(node, list.replacement); @@ -261,4 +337,5 @@ } } } + */ } diff -r 77aa8141ba41 -r 5bdaa08ba96b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java Wed Mar 14 17:55:33 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java Wed Mar 14 17:59:06 2012 +0100 @@ -39,7 +39,8 @@ @Data public final CiConstant value; protected ConstantNode(CiConstant value) { - this(value, null); + super(StampFactory.forConstant(value)); + this.value = value; } /** @@ -65,7 +66,11 @@ } public static ConstantNode forCiConstant(CiConstant constant, RiRuntime runtime, Graph graph) { - return graph.unique(new ConstantNode(constant, runtime)); + if (constant.kind == CiKind.Object) { + return graph.unique(new ConstantNode(constant, runtime)); + } else { + return graph.unique(new ConstantNode(constant)); + } } /** diff -r 77aa8141ba41 -r 5bdaa08ba96b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java Wed Mar 14 17:55:33 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java Wed Mar 14 17:59:06 2012 +0100 @@ -28,7 +28,7 @@ import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; -public final class FixedGuardNode extends FixedWithNextNode implements Simplifiable, Lowerable, LIRLowerable { +public final class FixedGuardNode extends FixedWithNextNode implements Simplifiable, Lowerable, LIRLowerable, Node.IterableNodeType { @Input private final NodeInputList conditions; diff -r 77aa8141ba41 -r 5bdaa08ba96b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java Wed Mar 14 17:55:33 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java Wed Mar 14 17:59:06 2012 +0100 @@ -115,7 +115,12 @@ } public NodeIterable phis() { - return this.usages().filter(PhiNode.class); + return this.usages().filter(new NodePredicate() { + @Override + public boolean apply(Node n) { + return n instanceof PhiNode && ((PhiNode) n).merge() == MergeNode.this; + } + }).filter(PhiNode.class); } @Override diff -r 77aa8141ba41 -r 5bdaa08ba96b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java Wed Mar 14 17:55:33 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java Wed Mar 14 17:59:06 2012 +0100 @@ -41,7 +41,7 @@ } public ArrayLengthNode(ValueNode array) { - super(StampFactory.intValue()); + super(StampFactory.positiveInt()); this.array = array; } diff -r 77aa8141ba41 -r 5bdaa08ba96b graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphTest.java Wed Mar 14 17:55:33 2012 +0100 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphTest.java Wed Mar 14 17:59:06 2012 +0100 @@ -55,6 +55,7 @@ protected final GraalRuntime runtime; public GraphTest() { + Debug.enable(); this.runtime = GraalRuntimeAccess.getGraalRuntime(); } @@ -62,7 +63,7 @@ if (expected.getNodeCount() != graph.getNodeCount()) { Debug.dump(expected, "Node count not matching - expected"); Debug.dump(graph, "Node count not matching - actual"); - Assert.fail("Graphs do not have the same number of nodes"); + Assert.fail("Graphs do not have the same number of nodes: " + expected.getNodeCount() + " vs. " + graph.getNodeCount()); } } diff -r 77aa8141ba41 -r 5bdaa08ba96b graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/ScalarTypeSystemTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/ScalarTypeSystemTest.java Wed Mar 14 17:55:33 2012 +0100 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/ScalarTypeSystemTest.java Wed Mar 14 17:59:06 2012 +0100 @@ -27,6 +27,7 @@ import org.junit.*; import com.oracle.graal.compiler.phases.*; +import com.oracle.graal.compiler.types.*; import com.oracle.graal.debug.*; import com.oracle.graal.nodes.*; @@ -43,7 +44,7 @@ } } - @Test(expected = AssertionFailedError.class) + @Test public void test1() { test("test1Snippet", "referenceSnippet1"); } @@ -60,7 +61,7 @@ } } - @Test(expected = AssertionFailedError.class) + @Test public void test2() { test("test2Snippet", "referenceSnippet1"); } @@ -77,7 +78,7 @@ } } - @Test(expected = AssertionFailedError.class) + @Test public void test3() { test("test3Snippet", "referenceSnippet2"); } @@ -102,7 +103,7 @@ } } - @Test(expected = AssertionFailedError.class) + @Test public void test4() { test("test4Snippet", "referenceSnippet2"); } @@ -119,7 +120,7 @@ } } - @Test(expected = AssertionFailedError.class) + @Test public void test5() { test("test5Snippet", "referenceSnippet3"); } @@ -162,9 +163,12 @@ } private void test(String snippet, String referenceSnippet) { + StructuredGraph graph = parse(snippet); Debug.dump(graph, "Graph"); + System.out.println("==================== " + snippet); new CanonicalizerPhase(null, runtime(), null).apply(graph); + new PropagateTypeCachePhase(null, null, null).apply(graph); StructuredGraph referenceGraph = parse(referenceSnippet); assertEquals(referenceGraph, graph); } diff -r 77aa8141ba41 -r 5bdaa08ba96b graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/TypeSystemTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/TypeSystemTest.java Wed Mar 14 17:55:33 2012 +0100 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/TypeSystemTest.java Wed Mar 14 17:59:06 2012 +0100 @@ -22,14 +22,21 @@ */ package com.oracle.graal.compiler.tests; +import java.io.*; + +import junit.framework.Assert; + import org.junit.*; import com.oracle.graal.compiler.phases.*; +import com.oracle.graal.compiler.schedule.*; import com.oracle.graal.compiler.types.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; +import com.oracle.graal.lir.cfg.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.printer.*; /** * In the following tests, the scalar type system of the compiler should be complete enough to see the relation between the different conditions. @@ -60,12 +67,181 @@ return 1; } + @Test + public void test3() { + test("test3Snippet", "referenceSnippet3"); + } + + public static int referenceSnippet3(Object o) { + if (o == null) { + return 1; + } else { + return 2; + } + } + + @SuppressWarnings("unused") + public static int test3Snippet(Object o) { + if (o == null) { + if (o != null) { + return 3; + } else { + return 1; + } + } else { + return 2; + } + } + + @Test + public void test4() { + test("test4Snippet", "referenceSnippet3"); + } + + public static final Object constantObject1 = "1"; + public static final Object constantObject2 = "2"; + public static final Object constantObject3 = "3"; + + public static int test4Snippet(Object o) { + if (o == null) { + if (o == constantObject1) { + return 3; + } else { + return 1; + } + } else { + return 2; + } + } + +// @Test + public void test5() { + test("test5Snippet", "referenceSnippet5"); + } + + public static int referenceSnippet5(Object o, Object a) { + if (o == null) { + if (a == constantObject1 || a == constantObject2) { + return 1; + } + } else { + if (a == constantObject2 || a == constantObject3) { + if (a != null) { + return 11; + } + return 2; + } + } + if (a == constantObject1) { + return 3; + } + return 5; + } + + public static int test5Snippet(Object o, Object a) { + if (o == null) { + if (a == constantObject1 || a == constantObject2) { + if (a == null) { + return 10; + } + return 1; + } + } else { + if (a == constantObject2 || a == constantObject3) { + if (a != null) { + return 11; + } + return 2; + } + } + if (a == constantObject1) { + return 3; + } + if (a == constantObject2) { + return 4; + } + return 5; + } + + @Test + public void test6() { + test("test6Snippet", CheckCastNode.class); + } + + public static int test6Snippet(int i) throws IOException { + Object o = null; + + if (i == 5) { + o = new FileInputStream("asdf"); + } + if (i < 10) { + o = new ByteArrayInputStream(new byte[]{1, 2, 3}); + } + if (i > 0) { + o = new BufferedInputStream(null); + } + + return ((InputStream) o).available(); + } + + private void test(String snippet, String referenceSnippet) { + + StructuredGraph graph = parse(snippet); + Debug.dump(graph, "Graph"); + System.out.println("==================== " + snippet); + new CanonicalizerPhase(null, runtime(), null).apply(graph); + new PropagateTypeCachePhase(null, runtime(), null).apply(graph); + new CanonicalizerPhase(null, runtime(), null).apply(graph); + new GlobalValueNumberingPhase().apply(graph); + StructuredGraph referenceGraph = parse(referenceSnippet); + new CanonicalizerPhase(null, runtime(), null).apply(referenceGraph); + new GlobalValueNumberingPhase().apply(referenceGraph); + assertEquals(referenceGraph, graph); + } + + @Override + protected void assertEquals(StructuredGraph expected, StructuredGraph graph) { + if (expected.getNodeCount() != graph.getNodeCount()) { + Debug.dump(expected, "Node count not matching - expected"); + Debug.dump(graph, "Node count not matching - actual"); + System.out.println("================ expected"); + outputGraph(expected); + System.out.println("================ actual"); + outputGraph(graph); + new IdealGraphPrinterDumpHandler().dump(graph, "asdf"); + Assert.fail("Graphs do not have the same number of nodes: " + expected.getNodeCount() + " vs. " + graph.getNodeCount()); + } + } + + public static void outputGraph(StructuredGraph graph) { + SchedulePhase schedule = new SchedulePhase(); + schedule.apply(graph); + for (Block block : schedule.getCFG().getBlocks()) { + System.out.print("Block " + block + " "); + if (block == schedule.getCFG().getStartBlock()) { + System.out.print("* "); + } + System.out.print("-> "); + for (Block succ : block.getSuccessors()) { + System.out.print(succ + " "); + } + System.out.println(); + for (Node node : schedule.getNodesFor().get(block)) { + System.out.println(" " + node + " (" + node.usages().size() + ")"); + } + } + } + + private void test(String snippet, Class clazz) { StructuredGraph graph = parse(snippet); Debug.dump(graph, "Graph"); new CanonicalizerPhase(null, runtime(), null).apply(graph); - new PropagateTypesPhase(null, null, null).apply(graph); + new PropagateTypeCachePhase(null, runtime(), null).apply(graph); Debug.dump(graph, "Graph"); + if (graph.getNodes(clazz).iterator().hasNext()) { + outputGraph(graph); + } Assert.assertFalse("shouldn't have nodes of type " + clazz, graph.getNodes(clazz).iterator().hasNext()); } }