# HG changeset patch # User Gilles Duboscq # Date 1337766931 -7200 # Node ID 16c27447923ce431628995785c696773a85aa5bc # Parent 1d63466ba795776d08e318a9b03f73f190cfe081# Parent 1422376443673dd0b484a3f788964a7fb54fc76f Merge diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Wed May 23 11:55:31 2012 +0200 @@ -381,11 +381,11 @@ if (instr instanceof GuardNode) { GuardNode guardNode = (GuardNode) instr; - if (guardNode.condition() instanceof NullCheckNode) { - NullCheckNode nullCheckNode = (NullCheckNode) guardNode.condition(); - if (!nullCheckNode.expectedNull && nextInstr instanceof Access) { + if (guardNode.condition() instanceof IsNullNode && guardNode.negated()) { + IsNullNode isNullNode = (IsNullNode) guardNode.condition(); + if (nextInstr instanceof Access) { Access access = (Access) nextInstr; - if (nullCheckNode.object() == access.object() && canBeNullCheck(access.location())) { + if (isNullNode.object() == access.object() && canBeNullCheck(access.location())) { //TTY.println("implicit null check"); access.setNullCheck(true); continue; @@ -404,6 +404,8 @@ if (instr instanceof ValueNode) { try { doRoot((ValueNode) instr); + } catch (GraalInternalError e) { + throw e.addContext(instr); } catch (Throwable e) { throw new GraalInternalError(e).addContext(instr); } @@ -667,25 +669,29 @@ } @Override - public void emitGuardCheck(BooleanNode comp, RiDeoptReason deoptReason, RiDeoptAction action, long leafGraphId) { - if (comp instanceof NullCheckNode && !((NullCheckNode) comp).expectedNull) { - emitNullCheckGuard((NullCheckNode) comp, leafGraphId); - } else if (comp instanceof ConstantNode && comp.asConstant().asBoolean()) { + public void emitGuardCheck(BooleanNode comp, RiDeoptReason deoptReason, RiDeoptAction action, boolean negated, long leafGraphId) { + if (comp instanceof IsNullNode && negated) { + emitNullCheckGuard(((IsNullNode) comp).object(), leafGraphId); + } else if (comp instanceof ConstantNode && (comp.asConstant().asBoolean() != negated)) { // True constant, nothing to emit. // False constants are handled within emitBranch. } else { // Fall back to a normal branch. LIRDebugInfo info = state(leafGraphId); LabelRef stubEntry = createDeoptStub(action, deoptReason, info, comp); - emitBranch(comp, null, stubEntry, info); + if (negated) { + emitBranch(comp, stubEntry, null, info); + } else { + emitBranch(comp, null, stubEntry, info); + } } } - protected abstract void emitNullCheckGuard(NullCheckNode node, long leafGraphId); + protected abstract void emitNullCheckGuard(ValueNode object, long leafGraphId); public void emitBranch(BooleanNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRDebugInfo info) { - if (node instanceof NullCheckNode) { - emitNullCheckBranch((NullCheckNode) node, trueSuccessor, falseSuccessor, info); + if (node instanceof IsNullNode) { + emitNullCheckBranch((IsNullNode) node, trueSuccessor, falseSuccessor, info); } else if (node instanceof CompareNode) { emitCompareBranch((CompareNode) node, trueSuccessor, falseSuccessor, info); } else if (node instanceof InstanceOfNode) { @@ -699,9 +705,8 @@ } } - private void emitNullCheckBranch(NullCheckNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRDebugInfo info) { - Condition cond = node.expectedNull ? Condition.NE : Condition.EQ; - emitBranch(operand(node.object()), CiConstant.NULL_OBJECT, cond, false, falseSuccessor, info); + private void emitNullCheckBranch(IsNullNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRDebugInfo info) { + emitBranch(operand(node.object()), CiConstant.NULL_OBJECT, Condition.NE, false, falseSuccessor, info); if (trueSuccessor != null) { emitJump(trueSuccessor, null); } @@ -717,7 +722,7 @@ private void emitInstanceOfBranch(InstanceOfNode x, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRDebugInfo info) { XirArgument obj = toXirArgument(x.object()); XirSnippet snippet = xir.genInstanceOf(site(x, x.object()), obj, toXirArgument(x.targetClassInstruction()), x.targetClass(), x.profile()); - emitXir(snippet, x, info, null, false, x.negated() ? falseSuccessor : trueSuccessor, x.negated() ? trueSuccessor : falseSuccessor); + emitXir(snippet, x, info, null, false, trueSuccessor, falseSuccessor); } public void emitConstantBranch(boolean value, LabelRef trueSuccessorBlock, LabelRef falseSuccessorBlock, LIRDebugInfo info) { @@ -745,8 +750,8 @@ } public Variable emitConditional(BooleanNode node, CiValue trueValue, CiValue falseValue) { - if (node instanceof NullCheckNode) { - return emitNullCheckConditional((NullCheckNode) node, trueValue, falseValue); + if (node instanceof IsNullNode) { + return emitNullCheckConditional((IsNullNode) node, trueValue, falseValue); } else if (node instanceof CompareNode) { return emitCompareConditional((CompareNode) node, trueValue, falseValue); } else if (node instanceof InstanceOfNode) { @@ -758,15 +763,14 @@ } } - private Variable emitNullCheckConditional(NullCheckNode node, CiValue trueValue, CiValue falseValue) { - Condition cond = node.expectedNull ? Condition.EQ : Condition.NE; - return emitCMove(operand(node.object()), CiConstant.NULL_OBJECT, cond, false, trueValue, falseValue); + private Variable emitNullCheckConditional(IsNullNode node, CiValue trueValue, CiValue falseValue) { + return emitCMove(operand(node.object()), CiConstant.NULL_OBJECT, Condition.EQ, false, trueValue, falseValue); } private Variable emitInstanceOfConditional(InstanceOfNode x, CiValue trueValue, CiValue falseValue) { XirArgument obj = toXirArgument(x.object()); - XirArgument trueArg = toXirArgument(x.negated() ? falseValue : trueValue); - XirArgument falseArg = toXirArgument(x.negated() ? trueValue : falseValue); + XirArgument trueArg = toXirArgument(trueValue); + XirArgument falseArg = toXirArgument(falseValue); XirSnippet snippet = xir.genMaterializeInstanceOf(site(x, x.object()), obj, toXirArgument(x.targetClassInstruction()), trueArg, falseArg, x.targetClass(), x.profile()); return (Variable) emitXir(snippet, null, null, false); } diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/CheckCastEliminationPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/CheckCastEliminationPhase.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/CheckCastEliminationPhase.java Wed May 23 11:55:31 2012 +0200 @@ -44,6 +44,7 @@ private static final DebugMetric metricInstanceOfRemoved = Debug.metric("InstanceOfRemoved"); private static final DebugMetric metricNullCheckRemoved = Debug.metric("NullCheckRemoved"); private static final DebugMetric metricNullCheckGuardRemoved = Debug.metric("NullCheckGuardRemoved"); + private static final DebugMetric metricGuardsReplaced = Debug.metric("GuardsReplaced"); private StructuredGraph graph; @@ -58,17 +59,23 @@ private IdentityHashMap knownTypes; private HashSet knownNotNull; private HashSet knownNull; + private IdentityHashMap trueConditions; + private IdentityHashMap falseConditions; public State() { this.knownTypes = new IdentityHashMap<>(); this.knownNotNull = new HashSet<>(); this.knownNull = new HashSet<>(); + this.trueConditions = new IdentityHashMap<>(); + this.falseConditions = new IdentityHashMap<>(); } - public State(IdentityHashMap knownTypes, HashSet knownNotNull, HashSet knownNull) { - this.knownTypes = new IdentityHashMap<>(knownTypes); - this.knownNotNull = new HashSet<>(knownNotNull); - this.knownNull = new HashSet<>(knownNull); + public State(State other) { + this.knownTypes = new IdentityHashMap<>(other.knownTypes); + this.knownNotNull = new HashSet<>(other.knownNotNull); + this.knownNull = new HashSet<>(other.knownNull); + this.trueConditions = new IdentityHashMap<>(other.trueConditions); + this.falseConditions = new IdentityHashMap<>(other.falseConditions); } @Override @@ -76,6 +83,8 @@ IdentityHashMap newKnownTypes = new IdentityHashMap<>(); HashSet newKnownNotNull = new HashSet<>(); HashSet newKnownNull = new HashSet<>(); + IdentityHashMap newTrueConditions = new IdentityHashMap<>(); + IdentityHashMap newFalseConditions = new IdentityHashMap<>(); for (Map.Entry entry : knownTypes.entrySet()) { ValueNode node = entry.getKey(); @@ -116,6 +125,43 @@ newKnownNull.add(node); } } + for (Map.Entry entry : trueConditions.entrySet()) { + BooleanNode check = entry.getKey(); + ValueNode guard = entry.getValue(); + + for (State other : withStates) { + ValueNode otherGuard = other.trueConditions.get(check); + if (otherGuard == null) { + guard = null; + break; + } + if (otherGuard != guard) { + guard = merge; + } + } + if (guard != null) { + newTrueConditions.put(check, guard); + } + } + for (Map.Entry entry : falseConditions.entrySet()) { + BooleanNode check = entry.getKey(); + ValueNode guard = entry.getValue(); + + for (State other : withStates) { + ValueNode otherGuard = other.falseConditions.get(check); + if (otherGuard == null) { + guard = null; + break; + } + if (otherGuard != guard) { + guard = merge; + } + } + if (guard != null) { + newFalseConditions.put(check, guard); + } + } + /* // this piece of code handles phis (merges the types and knownNull/knownNotNull of the values) if (!(merge instanceof LoopBeginNode)) { @@ -150,6 +196,8 @@ this.knownTypes = newKnownTypes; this.knownNotNull = newKnownNotNull; this.knownNull = newKnownNull; + this.trueConditions = newTrueConditions; + this.falseConditions = newFalseConditions; return true; } @@ -172,7 +220,7 @@ @Override public State clone() { - return new State(knownTypes, knownNotNull, knownNull); + return new State(this); } } @@ -217,21 +265,29 @@ Node pred = node.predecessor(); if (pred != null && pred instanceof IfNode) { IfNode ifNode = (IfNode) pred; + if (!(ifNode.compare() instanceof ConstantNode)) { + boolean isTrue = (node == ifNode.trueSuccessor()); + if (isTrue) { + state.trueConditions.put(ifNode.compare(), begin); + } else { + state.falseConditions.put(ifNode.compare(), begin); + } + } if (ifNode.compare() instanceof InstanceOfNode) { InstanceOfNode instanceOf = (InstanceOfNode) ifNode.compare(); - if ((node == ifNode.trueSuccessor()) != instanceOf.negated()) { + if ((node == ifNode.trueSuccessor())) { ValueNode object = instanceOf.object(); state.knownNotNull.add(object); state.knownTypes.put(object, tighten(instanceOf.targetClass(), state.getNodeType(object))); metricInstanceOfRegistered.increment(); } - } else if (ifNode.compare() instanceof NullCheckNode) { - NullCheckNode nullCheck = (NullCheckNode) ifNode.compare(); - boolean isNotNull = (node == ifNode.trueSuccessor()) != nullCheck.expectedNull; - if (isNotNull) { + } else if (ifNode.compare() instanceof IsNullNode) { + IsNullNode nullCheck = (IsNullNode) ifNode.compare(); + boolean isNull = (node == ifNode.trueSuccessor()); + if (isNull) { + state.knownNull.add(nullCheck.object()); + } else { state.knownNotNull.add(nullCheck.object()); - } else { - state.knownNull.add(nullCheck.object()); } metricNullCheckRegistered.increment(); } else if (ifNode.compare() instanceof IsTypeNode) { @@ -246,22 +302,36 @@ } } for (GuardNode guard : begin.guards().snapshot()) { - boolean removeCheck = false; - if (guard.condition() instanceof NullCheckNode) { - NullCheckNode nullCheck = (NullCheckNode) guard.condition(); - if (state.knownNotNull.contains(nullCheck.object()) && !nullCheck.expectedNull) { - removeCheck = true; - } else if (state.knownNull.contains(nullCheck.object()) && nullCheck.expectedNull) { - removeCheck = true; + BooleanNode condition = guard.condition(); + ValueNode existingGuards = guard.negated() ? state.falseConditions.get(condition) : state.trueConditions.get(condition); + if (existingGuards != null) { + guard.replaceAtUsages(existingGuards); + GraphUtil.killWithUnusedFloatingInputs(guard); + metricGuardsReplaced.increment(); + } else { + boolean removeCheck = false; + if (condition instanceof IsNullNode) { + IsNullNode isNull = (IsNullNode) condition; + if (guard.negated() && state.knownNotNull.contains(isNull.object())) { + removeCheck = true; + } else if (!guard.negated() && state.knownNull.contains(isNull.object())) { + removeCheck = true; + } + if (removeCheck) { + metricNullCheckGuardRemoved.increment(); + } } if (removeCheck) { - metricNullCheckGuardRemoved.increment(); + guard.replaceAtUsages(begin); + GraphUtil.killWithUnusedFloatingInputs(guard); + } else { + if (guard.negated()) { + state.falseConditions.put(condition, guard); + } else { + state.trueConditions.put(condition, guard); + } } } - if (removeCheck) { - guard.replaceAtUsages(begin); - GraphUtil.killWithUnusedFloatingInputs(guard); - } } } else if (node instanceof CheckCastNode) { CheckCastNode checkCast = (CheckCastNode) node; @@ -281,30 +351,37 @@ IfNode ifNode = (IfNode) node; BooleanNode replaceWith = null; BooleanNode compare = ifNode.compare(); - if (compare instanceof InstanceOfNode) { - InstanceOfNode instanceOf = (InstanceOfNode) compare; - ValueNode object = instanceOf.object(); - if (state.knownNull.contains(object)) { - replaceWith = ConstantNode.forBoolean(instanceOf.negated(), graph); - } else if (state.knownNotNull.contains(object)) { - RiResolvedType type = state.getNodeType(object); - if (type != null && type.isSubtypeOf(instanceOf.targetClass())) { - replaceWith = ConstantNode.forBoolean(!instanceOf.negated(), graph); + + if (state.trueConditions.containsKey(compare)) { + replaceWith = ConstantNode.forBoolean(true, graph); + } else if (state.falseConditions.containsKey(compare)) { + replaceWith = ConstantNode.forBoolean(false, graph); + } else { + if (compare instanceof InstanceOfNode) { + InstanceOfNode instanceOf = (InstanceOfNode) compare; + ValueNode object = instanceOf.object(); + if (state.knownNull.contains(object)) { + replaceWith = ConstantNode.forBoolean(false, graph); + } else if (state.knownNotNull.contains(object)) { + RiResolvedType type = state.getNodeType(object); + if (type != null && type.isSubtypeOf(instanceOf.targetClass())) { + replaceWith = ConstantNode.forBoolean(true, graph); + } } - } - if (replaceWith != null) { - metricInstanceOfRemoved.increment(); - } - } else if (compare instanceof NullCheckNode) { - NullCheckNode nullCheck = (NullCheckNode) compare; - ValueNode object = nullCheck.object(); - if (state.knownNull.contains(object)) { - replaceWith = ConstantNode.forBoolean(nullCheck.expectedNull, graph); - } else if (state.knownNotNull.contains(object)) { - replaceWith = ConstantNode.forBoolean(!nullCheck.expectedNull, graph); - } - if (replaceWith != null) { - metricNullCheckRemoved.increment(); + if (replaceWith != null) { + metricInstanceOfRemoved.increment(); + } + } else if (compare instanceof IsNullNode) { + IsNullNode isNull = (IsNullNode) compare; + ValueNode object = isNull.object(); + if (state.knownNull.contains(object)) { + replaceWith = ConstantNode.forBoolean(true, graph); + } else if (state.knownNotNull.contains(object)) { + replaceWith = ConstantNode.forBoolean(false, graph); + } + if (replaceWith != null) { + metricNullCheckRemoved.increment(); + } } } if (replaceWith != null) { diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ConvertDeoptimizeToGuardPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ConvertDeoptimizeToGuardPhase.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ConvertDeoptimizeToGuardPhase.java Wed May 23 11:55:31 2012 +0200 @@ -78,13 +78,14 @@ IfNode ifNode = (IfNode) deoptBegin.predecessor(); BeginNode otherBegin = ifNode.trueSuccessor(); BooleanNode conditionNode = ifNode.compare(); + boolean negated = false; if (deoptBegin == ifNode.trueSuccessor()) { - conditionNode = conditionNode.negate(); + negated = true; otherBegin = ifNode.falseSuccessor(); } BeginNode ifBlockBegin = findBeginNode(ifNode); Debug.log("Converting %s on %-5s branch of %s to guard for remaining branch %s. IfBegin=%s", deopt, deoptBegin == ifNode.trueSuccessor() ? "true" : "false", ifNode, otherBegin, ifBlockBegin); - FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.reason(), deopt.action(), deopt.leafGraphId())); + FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.reason(), deopt.action(), negated, deopt.leafGraphId())); otherBegin.replaceAtUsages(ifBlockBegin); FixedNode next = otherBegin.next(); otherBegin.setNext(null); diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java Wed May 23 11:55:31 2012 +0200 @@ -284,8 +284,8 @@ if (usage instanceof FixedNode) { record.localWeight += ((FixedNode) usage).probability(); } - if (usage instanceof NullCheckNode) { - assert ((NullCheckNode) usage).object() == node; + if (usage instanceof IsNullNode) { + assert ((IsNullNode) usage).object() == node; return null; } else if (usage instanceof IsTypeNode) { assert ((IsTypeNode) usage).objectClass() == node; diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java Wed May 23 11:55:31 2012 +0200 @@ -28,6 +28,7 @@ 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.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.max.cri.ci.*; @@ -38,6 +39,40 @@ */ public class LoweringPhase extends Phase { + private class LoweringToolBase implements CiLoweringTool { + + @Override + public GraalRuntime getRuntime() { + return runtime; + } + + @Override + public Node getGuardAnchor() { + throw new UnsupportedOperationException(); + } + + @Override + public Node createNullCheckGuard(ValueNode object, long leafGraphId) { + return createGuard(object.graph().unique(new IsNullNode(object)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, true, leafGraphId); + } + + @Override + public Node createGuard(Node condition, RiDeoptReason deoptReason, RiDeoptAction action, long leafGraphId) { + return createGuard(condition, deoptReason, action, false, leafGraphId); + } + + @Override + public Node createGuard(Node condition, RiDeoptReason deoptReason, RiDeoptAction action, boolean negated, long leafGraphId) { + // TODO (thomaswue): Document why this must not be called on floating nodes. + throw new UnsupportedOperationException(); + } + + @Override + public CiAssumptions assumptions() { + return assumptions; + } + } + private final GraalRuntime runtime; private final CiAssumptions assumptions; @@ -45,6 +80,7 @@ this.runtime = runtime; this.assumptions = assumptions; } + @Override protected void run(final StructuredGraph graph) { // Step 1: repeatedly lower fixed nodes until no new ones are created @@ -66,29 +102,7 @@ // Step 2: lower the floating nodes processed.negate(); - final CiLoweringTool loweringTool = new CiLoweringTool() { - - @Override - public Node getGuardAnchor() { - throw new UnsupportedOperationException(); - } - - @Override - public GraalRuntime getRuntime() { - return runtime; - } - - @Override - public Node createGuard(Node condition, RiDeoptReason deoptReason, RiDeoptAction action, long leafGraphId) { - // TODO (thomaswue): Document why this must not be called on floating nodes. - throw new UnsupportedOperationException(); - } - - @Override - public CiAssumptions assumptions() { - return assumptions; - } - }; + final CiLoweringTool loweringTool = new LoweringToolBase(); for (Node node : processed) { if (node instanceof Lowerable) { assert !(node instanceof FixedNode) || node.predecessor() == null : node; @@ -105,29 +119,7 @@ processBlock(cfg.getStartBlock(), activeGuards, processed, null); processed.negate(); - final CiLoweringTool loweringTool = new CiLoweringTool() { - - @Override - public Node getGuardAnchor() { - throw new UnsupportedOperationException(); - } - - @Override - public GraalRuntime getRuntime() { - return runtime; - } - - @Override - public Node createGuard(Node condition, RiDeoptReason deoptReason, RiDeoptAction action, long leafGraphId) { - // TODO (thomaswue): Document why this must not be called on floating nodes. - throw new UnsupportedOperationException(); - } - - @Override - public CiAssumptions assumptions() { - return assumptions; - } - }; + final CiLoweringTool loweringTool = new LoweringToolBase(); for (Node node : processed) { if (node instanceof CheckCastNode) { // This is a checkcast that was created while lowering some other node (e.g. StoreIndexed). @@ -172,7 +164,7 @@ private void process(final Block b, final NodeBitMap activeGuards, NodeBitMap processed, final Node anchor) { - final CiLoweringTool loweringTool = new CiLoweringTool() { + final CiLoweringTool loweringTool = new LoweringToolBase() { @Override public Node getGuardAnchor() { @@ -180,12 +172,7 @@ } @Override - public GraalRuntime getRuntime() { - return runtime; - } - - @Override - public Node createGuard(Node condition, RiDeoptReason deoptReason, RiDeoptAction action, long leafGraphId) { + public Node createGuard(Node condition, RiDeoptReason deoptReason, RiDeoptAction action, boolean negated, long leafGraphId) { FixedNode guardAnchor = (FixedNode) getGuardAnchor(); if (GraalOptions.OptEliminateGuards) { for (Node usage : condition.usages()) { @@ -194,18 +181,13 @@ } } } - GuardNode newGuard = guardAnchor.graph().unique(new GuardNode((BooleanNode) condition, guardAnchor, deoptReason, action, leafGraphId)); + GuardNode newGuard = guardAnchor.graph().unique(new GuardNode((BooleanNode) condition, guardAnchor, deoptReason, action, negated, leafGraphId)); if (GraalOptions.OptEliminateGuards) { activeGuards.grow(); activeGuards.mark(newGuard); } return newGuard; } - - @Override - public CiAssumptions assumptions() { - return assumptions; - } }; // Lower the instructions of this block. diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64LIRGenerator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64LIRGenerator.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64LIRGenerator.java Wed May 23 11:55:31 2012 +0200 @@ -578,8 +578,8 @@ } @Override - protected void emitNullCheckGuard(NullCheckNode node, long leafGraphId) { - Variable value = load(operand(node.object())); + protected void emitNullCheckGuard(ValueNode object, long leafGraphId) { + Variable value = load(operand(object)); LIRDebugInfo info = state(leafGraphId); append(new NullCheckOp(value, info)); } diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/types/PropagateTypeCachePhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/types/PropagateTypeCachePhase.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/types/PropagateTypeCachePhase.java Wed May 23 11:55:31 2012 +0200 @@ -99,15 +99,13 @@ } } 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); + BooleanNode condition = guard.condition(); + if (condition != null && condition.usages().size() > 1) { + BooleanNode clone = (BooleanNode) condition.copyWithInputs(); + if (DUMP) { + out.println("replaced!! " + clone); } + guard.setCondition(clone); } } diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java Wed May 23 11:55:31 2012 +0200 @@ -27,14 +27,10 @@ import java.util.concurrent.*; import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.loop.*; import com.oracle.graal.compiler.phases.*; -import com.oracle.graal.compiler.phases.CanonicalizerPhase.IsImmutablePredicate; import com.oracle.graal.cri.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; -import com.oracle.graal.graph.Node.*; -import com.oracle.graal.lir.cfg.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.PhiNode.PhiType; import com.oracle.graal.nodes.calc.*; @@ -907,167 +903,13 @@ } } - /** - * Performs replacement of a node with a snippet graph. - * @param replacee the node that will be replaced - * @param anchor the control flow replacee - * @param snippetGraph the graph that the replacee will be replaced with - * @param explodeLoops specifies if all the loops in the snippet graph are counted loops that must be completely unrolled - * @param args - */ - public static void inlineSnippet(final RiRuntime runtime, - final Node replacee, - final FixedWithNextNode anchor, - final StructuredGraph snippetGraph, - final boolean explodeLoops, - final IsImmutablePredicate immutabilityPredicate, - final Object... args) { - Debug.scope("InliningSnippet", snippetGraph.method(), new Runnable() { - @Override - public void run() { - inlineSnippet0(runtime, replacee, anchor, snippetGraph, explodeLoops, immutabilityPredicate, args); - } - }); - } - private static void inlineSnippet0(RiRuntime runtime, - Node replacee, - FixedWithNextNode anchor, - StructuredGraph snippetGraph, - boolean explodeLoops, - IsImmutablePredicate immutabilityPredicate, - Object... args) { - - Debug.dump(replacee.graph(), "Before lowering %s", replacee); - - // Copy snippet graph, replacing parameters with given args in the process - StructuredGraph snippetCopy = new StructuredGraph(snippetGraph.name, snippetGraph.method()); - IdentityHashMap replacements = new IdentityHashMap<>(); - replacements.put(snippetGraph.start(), snippetCopy.start()); - int localCount = 0; - for (LocalNode local : snippetGraph.getNodes(LocalNode.class)) { - int index = local.index(); - if (args[index] instanceof CiConstant) { - CiConstant arg = (CiConstant) args[index]; - assert arg.kind.stackKind() == local.kind() : arg.kind + " != " + local.kind(); - ConstantNode argNode = ConstantNode.forCiConstant(arg, runtime, snippetCopy); - replacements.put(local, argNode); - args[index] = null; - } else { - assert args[index] instanceof ValueNode; - } - localCount++; - } - assert localCount == args.length : "snippet argument count mismatch"; - snippetCopy.addDuplicates(snippetGraph.getNodes(), replacements); - if (!replacements.isEmpty()) { - new CanonicalizerPhase(null, runtime, null, 0, immutabilityPredicate).apply(snippetCopy); - } - - // Explode all loops in the snippet if requested - if (explodeLoops && snippetCopy.hasLoops()) { - ControlFlowGraph cfg = ControlFlowGraph.compute(snippetCopy, true, true, false, false); - for (Loop loop : cfg.getLoops()) { - LoopBeginNode loopBegin = loop.loopBegin(); - SuperBlock wholeLoop = LoopTransformUtil.wholeLoop(loop); - Debug.dump(snippetCopy, "Before exploding loop %s", loopBegin); - int peel = 0; - while (!loopBegin.isDeleted()) { - int mark = snippetCopy.getMark(); - LoopTransformUtil.peel(loop, wholeLoop); - Debug.dump(snippetCopy, "After peel %d", peel); - new CanonicalizerPhase(null, runtime, null, mark, immutabilityPredicate).apply(snippetCopy); - peel++; - } - Debug.dump(snippetCopy, "After exploding loop %s", loopBegin); - } - new DeadCodeEliminationPhase().apply(snippetCopy); - } - - // Gather the nodes in the snippet that are to be inlined - ArrayList nodes = new ArrayList<>(); - ReturnNode returnNode = null; - StartNode entryPointNode = snippetCopy.start(); - FixedNode firstCFGNode = entryPointNode.next(); - replacements.clear(); - for (Node node : snippetCopy.getNodes()) { - if (node == entryPointNode || node == entryPointNode.stateAfter()) { - // Do nothing. - } else if (node instanceof LocalNode) { - LocalNode local = (LocalNode) node; - int index = local.index(); - assert args[index] instanceof ValueNode; - ValueNode arg = (ValueNode) args[index]; - assert arg.kind() == local.kind(); - replacements.put(node, arg); - args[index] = null; - } else { - nodes.add(node); - if (node instanceof ReturnNode) { - returnNode = (ReturnNode) node; - } - } - } - - // Inline the gathered snippet nodes - StructuredGraph graph = (StructuredGraph) replacee.graph(); - int mark = graph.getMark(); - Map duplicates = graph.addDuplicates(nodes, replacements); - Debug.dump(graph, "After inlining snippet %s", snippetCopy.method()); - - // Remove all frame states from the inlined snippet graph. Snippets must be atomic (i.e. free - // of side-effects that prevent deoptimizing to a point before the snippet). - for (Node node : graph.getNewNodes(mark)) { - if (node instanceof StateSplit) { - StateSplit stateSplit = (StateSplit) node; - FrameState frameState = stateSplit.stateAfter(); - assert !stateSplit.hasSideEffect() : "snippets cannot contain side-effecting node " + node + "\n " + frameState.toString(Verbosity.Debugger); - if (frameState != null) { - stateSplit.setStateAfter(null); - } - } - } - - Debug.dump(graph, "After removing frame states"); - - // Rewire the control flow graph around the replacee - FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode); - anchor.replaceAtPredecessors(firstCFGNodeDuplicate); - FixedNode next = anchor.next(); - anchor.setNext(null); - - // Replace all usages of the replacee with the value returned by the snippet - Node returnValue = null; - if (returnNode != null) { - if (returnNode.result() instanceof LocalNode) { - returnValue = replacements.get(returnNode.result()); - } else { - returnValue = duplicates.get(returnNode.result()); - } - assert returnValue != null || replacee.usages().isEmpty(); - replacee.replaceAtUsages(returnValue); - - Node returnDuplicate = duplicates.get(returnNode); - returnDuplicate.clearInputs(); - returnDuplicate.replaceAndDelete(next); - } - - // Remove the replacee from its graph - replacee.clearInputs(); - replacee.replaceAtUsages(null); - if (replacee instanceof FixedNode) { - GraphUtil.killCFG((FixedNode) replacee); - } else { - replacee.safeDelete(); - } - } - public static void receiverNullCheck(Invoke invoke) { MethodCallTargetNode callTarget = invoke.callTarget(); StructuredGraph graph = (StructuredGraph) invoke.graph(); NodeInputList parameters = callTarget.arguments(); ValueNode firstParam = parameters.size() <= 0 ? null : parameters.get(0); if (!callTarget.isStatic() && firstParam.kind() == CiKind.Object && !firstParam.stamp().nonNull()) { - graph.addBeforeFixed(invoke.node(), graph.add(new FixedGuardNode(graph.unique(new NullCheckNode(firstParam, false)), RiDeoptReason.ClassCastException, RiDeoptAction.InvalidateReprofile, invoke.leafGraphId()))); + graph.addBeforeFixed(invoke.node(), graph.add(new FixedGuardNode(graph.unique(new IsNullNode(firstParam)), RiDeoptReason.ClassCastException, RiDeoptAction.InvalidateReprofile, true, invoke.leafGraphId()))); } } } diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java Wed May 23 11:55:31 2012 +0200 @@ -509,7 +509,11 @@ * @param replacements the replacement map (can be null if no replacement is to be performed) * @return a map which associates the original nodes from {@code nodes} to their duplicates */ + @SuppressWarnings("all") public Map addDuplicates(Iterable newNodes, Map replacements) { + if (replacements == null) { + replacements = Collections.emptyMap(); + } return NodeClass.addGraphDuplicate(this, newNodes, replacements); } } diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotKlassOop.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotKlassOop.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotKlassOop.java Wed May 23 11:55:31 2012 +0200 @@ -40,7 +40,7 @@ */ public final Class javaMirror; - HotSpotKlassOop(Compiler compiler, Class javaMirror) { + public HotSpotKlassOop(Compiler compiler, Class javaMirror) { super(compiler); this.javaMirror = javaMirror; } diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java Wed May 23 11:55:31 2012 +0200 @@ -28,10 +28,8 @@ import java.util.*; import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.phases.CanonicalizerPhase.IsImmutablePredicate; import com.oracle.graal.compiler.phases.*; import com.oracle.graal.compiler.target.*; -import com.oracle.graal.compiler.util.*; import com.oracle.graal.cri.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; @@ -65,7 +63,7 @@ final HotSpotRegisterConfig regConfig; private final HotSpotRegisterConfig globalStubRegConfig; private final Compiler compiler; - private RiResolvedMethod checkcastSnippet; + private CheckCastSnippets.Templates checkcasts; public HotSpotRuntime(HotSpotVMConfig config, Compiler compiler) { this.config = config; @@ -81,15 +79,7 @@ Snippets.install(this, compiler.getTarget(), new UnsafeSnippets()); Snippets.install(this, compiler.getTarget(), new ArrayCopySnippets()); Snippets.install(this, compiler.getTarget(), new CheckCastSnippets()); - try { - if (GraalOptions.CheckcastCounters) { - checkcastSnippet = getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastWithCounters", Object.class, Object.class, Object[].class, boolean.class, Counter.class)); - } else { - checkcastSnippet = getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcast", Object.class, Object.class, Object[].class, boolean.class)); - } - } catch (NoSuchMethodException e) { - throw new GraalInternalError(e); - } + checkcasts = new CheckCastSnippets.Templates(this); } @@ -294,7 +284,7 @@ int displacement = ((HotSpotField) field.field()).offset(); assert field.kind() != CiKind.Illegal; ReadNode memoryRead = graph.add(new ReadNode(field.object(), LocationNode.create(field.field(), field.field().kind(true), displacement, graph), field.stamp())); - memoryRead.dependencies().add(tool.createGuard(graph.unique(new NullCheckNode(field.object(), false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, field.leafGraphId())); + memoryRead.dependencies().add(tool.createNullCheckGuard(field.object(), field.leafGraphId())); graph.replaceFixedWithFixed(field, memoryRead); if (field.isVolatile()) { MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ)); @@ -306,7 +296,7 @@ StoreFieldNode storeField = (StoreFieldNode) n; HotSpotField field = (HotSpotField) storeField.field(); WriteNode memoryWrite = graph.add(new WriteNode(storeField.object(), storeField.value(), LocationNode.create(storeField.field(), storeField.field().kind(true), field.offset(), graph))); - memoryWrite.dependencies().add(tool.createGuard(graph.unique(new NullCheckNode(storeField.object(), false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, storeField.leafGraphId())); + memoryWrite.dependencies().add(tool.createNullCheckGuard(storeField.object(), storeField.leafGraphId())); memoryWrite.setStateAfter(storeField.stateAfter()); graph.replaceFixedWithFixed(storeField, memoryWrite); @@ -370,7 +360,7 @@ assert elementType.name().equals("Ljava/lang/Object;") : elementType.name(); } } else { - Node guard = tool.createGuard(graph.unique(new NullCheckNode(array, false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, StructuredGraph.INVALID_GRAPH_ID); + Node guard = tool.createNullCheckGuard(array, StructuredGraph.INVALID_GRAPH_ID); FloatingReadNode arrayClass = graph.unique(new FloatingReadNode(array, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.hubOffset, graph), null, StampFactory.objectNonNull())); arrayClass.dependencies().add(guard); FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.arrayClassElementOffset, graph), null, StampFactory.objectNonNull())); @@ -394,7 +384,7 @@ IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, load.loadKind(), load.displacement(), load.offset(), graph); location.setIndexScalingEnabled(false); ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp())); - memoryRead.dependencies().add(tool.createGuard(graph.unique(new NullCheckNode(load.object(), false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, StructuredGraph.INVALID_GRAPH_ID)); + memoryRead.dependencies().add(tool.createNullCheckGuard(load.object(), StructuredGraph.INVALID_GRAPH_ID)); graph.replaceFixedWithFixed(load, memoryRead); } else if (n instanceof UnsafeStoreNode) { UnsafeStoreNode store = (UnsafeStoreNode) n; @@ -411,35 +401,34 @@ ReadHubNode objectClassNode = (ReadHubNode) n; LocationNode location = LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.hubOffset, graph); ReadNode memoryRead = graph.add(new ReadNode(objectClassNode.object(), location, StampFactory.objectNonNull())); - memoryRead.dependencies().add(tool.createGuard(graph.unique(new NullCheckNode(objectClassNode.object(), false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, StructuredGraph.INVALID_GRAPH_ID)); + memoryRead.dependencies().add(tool.createNullCheckGuard(objectClassNode.object(), StructuredGraph.INVALID_GRAPH_ID)); graph.replaceFixed(objectClassNode, memoryRead); } else if (n instanceof CheckCastNode) { if (shouldLowerCheckcast(graph)) { - final Map hintHubsSet = new IdentityHashMap<>(); - IsImmutablePredicate immutabilityPredicate = new IsImmutablePredicate() { - public boolean apply(CiConstant constant) { - return hintHubsSet.containsKey(constant); - } - }; CheckCastNode checkcast = (CheckCastNode) n; ValueNode hub = checkcast.targetClassInstruction(); ValueNode object = checkcast.object(); TypeCheckHints hints = new TypeCheckHints(checkcast.targetClass(), checkcast.profile(), tool.assumptions(), GraalOptions.CheckcastMinHintHitProbability, GraalOptions.CheckcastMaxHints); - StructuredGraph snippetGraph = (StructuredGraph) checkcastSnippet.compilerStorage().get(Graph.class); - assert snippetGraph != null : CheckCastSnippets.class.getSimpleName() + " should be installed"; HotSpotKlassOop[] hintHubs = new HotSpotKlassOop[hints.types.length]; for (int i = 0; i < hintHubs.length; i++) { hintHubs[i] = ((HotSpotType) hints.types[i]).klassOop(); } - final CiConstant hintHubsConst = CiConstant.forObject(hintHubs); - hintHubsSet.put(hintHubsConst, hintHubsConst); Debug.log("Lowering checkcast in %s: node=%s, hintsHubs=%s, exact=%b", graph, checkcast, Arrays.toString(hints.types), hints.exact); + + final Counter noHintsCounter; if (GraalOptions.CheckcastCounters) { - Counter noHintsCounter = checkcast.targetClass() == null ? Counter.noHints_unknown : checkcast.targetClass().isInterface() ? Counter.noHints_iface : Counter.noHints_class; - InliningUtil.inlineSnippet(this, checkcast, checkcast, snippetGraph, true, immutabilityPredicate, hub, object, hintHubsConst, CiConstant.forBoolean(hints.exact), CiConstant.forObject(noHintsCounter)); + if (checkcast.targetClass() == null) { + noHintsCounter = Counter.noHints_unknown; + } else if (checkcast.targetClass().isInterface()) { + noHintsCounter = Counter.noHints_iface; + } else { + noHintsCounter = Counter.noHints_class; + } } else { - InliningUtil.inlineSnippet(this, checkcast, checkcast, snippetGraph, true, immutabilityPredicate, hub, object, hintHubsConst, CiConstant.forBoolean(hints.exact)); + noHintsCounter = null; } + boolean checkNull = !object.stamp().nonNull(); + checkcasts.get(hintHubs.length, hints.exact, checkNull, noHintsCounter).instantiate(this, checkcast, checkcast, hub, object, hintHubs, noHintsCounter); new DeadCodeEliminationPhase().apply(graph); } } else { @@ -470,7 +459,7 @@ private static Node createBoundsCheck(AccessIndexedNode n, CiLoweringTool tool) { StructuredGraph graph = (StructuredGraph) n.graph(); ArrayLengthNode arrayLength = graph.add(new ArrayLengthNode(n.array())); - Node guard = tool.createGuard(graph.unique(new CompareNode(n.index(), Condition.BT, arrayLength)), RiDeoptReason.BoundsCheckException, RiDeoptAction.InvalidateReprofile, n.leafGraphId()); + Node guard = tool.createGuard(graph.unique(new IntegerBelowThanNode(n.index(), arrayLength)), RiDeoptReason.BoundsCheckException, RiDeoptAction.InvalidateReprofile, n.leafGraphId()); graph.addBeforeFixed(n, arrayLength); return guard; diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java Wed May 23 11:55:31 2012 +0200 @@ -22,9 +22,11 @@ */ package com.oracle.graal.hotspot.snippets; import static com.oracle.graal.hotspot.snippets.CheckCastSnippets.Counter.*; +import static com.oracle.graal.snippets.SnippetTemplate.*; import java.io.*; import java.util.*; +import java.util.concurrent.*; import sun.misc.*; @@ -33,6 +35,7 @@ import com.oracle.graal.graph.Node.Fold; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.hotspot.ri.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; @@ -52,11 +55,12 @@ * @param object the object whose type is being checked against {@code hub} * @param hintHubs the hubs of objects that have been profiled during previous executions * @param hintsAreExact specifies if {@code hintHubs} contains all subtypes of {@code hub} + * @param checkNull specifies if {@code object} may be null * @return {@code object} if the type check succeeds * @throws ClassCastException if the type check fails */ @Snippet - public static Object checkcast(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact) { + public static Object checkcast(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, boolean checkNull, @SuppressWarnings("unused") Counter ignore) { if (object == null) { return object; } @@ -108,7 +112,7 @@ /** * Increments this counter if counters are enabled. The body of this method has been carefully crafted * such that it contains no safepoints and no calls, neither of which are permissible in a snippet. - * Also, increments are not guaranteed to be atomic but that's acceptable for a counter like this. + * Also, increments are not guaranteed to be atomic which is acceptable for a counter. */ void inc() { if (ENABLED) { @@ -120,11 +124,8 @@ static final boolean ENABLED = GraalOptions.CheckcastCounters; } - /** - * @see #checkcast(Object, Object, Object[], boolean) - */ @Snippet - public static Object checkcastWithCounters(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, Counter noHintsCounter) { + public static Object checkcastWithCounters(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, @SuppressWarnings("unused") boolean checkNull, Counter noHintsCounter) { if (object == null) { isNull.inc(); return object; @@ -169,11 +170,6 @@ return CompilerImpl.getInstance().getConfig().hubOffset; } - @Fold - private static boolean isInterface(RiResolvedType type) { - return type.isInterface(); - } - public static void printCounter(PrintStream out, Counter c, long total) { double percent = total == 0D ? 0D : ((double) (c.count * 100)) / total; out.println(String.format("%16s: %5.2f%%%10d // %s", c.name(), percent, c.count, c.description)); @@ -208,4 +204,55 @@ printCounter(out, c, total); } } + + /** + * Templates for partially specialized checkcast snippet graphs. + */ + public static class Templates { + + private final ConcurrentHashMap templates; + private final RiResolvedMethod method; + private final RiRuntime runtime; + + public Templates(RiRuntime runtime) { + this.runtime = runtime; + this.templates = new ConcurrentHashMap<>(); + try { + Class[] parameterTypes = {Object.class, Object.class, Object[].class, boolean.class, boolean.class, Counter.class}; + String name = GraalOptions.CheckcastCounters ? "checkcastWithCounters" : "checkcast"; + method = runtime.getRiMethod(CheckCastSnippets.class.getDeclaredMethod(name, parameterTypes)); + } catch (NoSuchMethodException e) { + throw new GraalInternalError(e); + } + } + + /** + * Gets a checkcast snippet specialized for a given set od inputs. + */ + public SnippetTemplate get(int nHints, boolean isExact, boolean checkNull, Counter noHintsCounter) { + Integer key = key(nHints, isExact, checkNull); + SnippetTemplate result = templates.get(key); + if (result == null) { + HotSpotKlassOop[] hints = new HotSpotKlassOop[nHints]; + Arrays.fill(hints, new HotSpotKlassOop(null, Templates.class)); + result = SnippetTemplate.create(runtime, method, _, _, hints, isExact, checkNull, noHintsCounter); + templates.put(key, result); + } + return result; + } + + /** + * Creates a canonical key for a combination of specialization parameters. + */ + private static Integer key(int nHints, boolean isExact, boolean checkNull) { + int key = nHints << 2; + if (isExact) { + key |= 2; + } + if (checkNull) { + key |= 1; + } + return key; + } + } } diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Wed May 23 11:55:31 2012 +0200 @@ -516,10 +516,32 @@ probability = 0.5; } - CompareNode condition = currentGraph.unique(new CompareNode(x, cond, y)); + // the mirroring and negation operations get the condition into canonical form + boolean mirror = cond.canonicalMirror(); + boolean negate = cond.canonicalNegate(); + + ValueNode a = mirror ? y : x; + ValueNode b = mirror ? x : y; + + CompareNode condition; + assert !a.kind().isFloatOrDouble(); + if (cond == Condition.EQ || cond == Condition.NE) { + if (a.kind() == CiKind.Object) { + condition = new ObjectEqualsNode(a, b); + } else { + condition = new IntegerEqualsNode(a, b); + } + } else { + assert a.kind() != CiKind.Object && !cond.isUnsigned(); + condition = new IntegerLessThanNode(a, b); + } + condition = currentGraph.unique(condition); + BeginNode trueSuccessor = createBlockTarget(probability, trueBlock, frameState); BeginNode falseSuccessor = createBlockTarget(1 - probability, falseBlock, frameState); - append(currentGraph.add(new IfNode(condition, trueSuccessor, falseSuccessor, probability))); + + IfNode ifNode = negate ? new IfNode(condition, falseSuccessor, trueSuccessor, 1 - probability) : new IfNode(condition, trueSuccessor, falseSuccessor, probability); + append(currentGraph.add(ifNode)); } private void genIfZero(Condition cond) { @@ -543,7 +565,7 @@ private void genThrow() { ValueNode exception = frameState.apop(); - FixedGuardNode node = currentGraph.add(new FixedGuardNode(currentGraph.unique(new NullCheckNode(exception, false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, graphId)); + FixedGuardNode node = currentGraph.add(new FixedGuardNode(currentGraph.unique(new IsNullNode(exception)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, true, graphId)); append(node); append(handleException(exception, bci())); } @@ -613,7 +635,7 @@ frameState.apush(checkCast); } else { ValueNode object = frameState.apop(); - append(currentGraph.add(new FixedGuardNode(currentGraph.unique(new CompareNode(object, Condition.EQ, ConstantNode.forObject(null, runtime, currentGraph))), RiDeoptReason.Unresolved, RiDeoptAction.InvalidateRecompile, graphId))); + append(currentGraph.add(new FixedGuardNode(currentGraph.unique(new IsNullNode(object)), RiDeoptReason.Unresolved, RiDeoptAction.InvalidateRecompile, graphId))); frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); } } @@ -625,14 +647,14 @@ if (type instanceof RiResolvedType) { RiResolvedType resolvedType = (RiResolvedType) type; ConstantNode hub = appendConstant(resolvedType.getEncoding(RiType.Representation.ObjectHub)); - InstanceOfNode instanceOfNode = new InstanceOfNode(hub, (RiResolvedType) type, object, getProfileForTypeCheck(resolvedType), false); + InstanceOfNode instanceOfNode = new InstanceOfNode(hub, (RiResolvedType) type, object, getProfileForTypeCheck(resolvedType)); frameState.ipush(append(MaterializeNode.create(currentGraph.unique(instanceOfNode), currentGraph))); } else { - BlockPlaceholderNode trueSucc = currentGraph.add(new BlockPlaceholderNode()); + BlockPlaceholderNode successor = currentGraph.add(new BlockPlaceholderNode()); DeoptimizeNode deopt = currentGraph.add(new DeoptimizeNode(RiDeoptAction.InvalidateRecompile, RiDeoptReason.Unresolved, graphId)); - IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new NullCheckNode(object, true)), trueSucc, deopt, 1)); + IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new IsNullNode(object)), successor, deopt, 0)); append(ifNode); - lastInstr = trueSucc; + lastInstr = successor; frameState.ipush(appendConstant(CiConstant.INT_0)); } } @@ -734,18 +756,18 @@ private void emitNullCheck(ValueNode receiver) { BlockPlaceholderNode trueSucc = currentGraph.add(new BlockPlaceholderNode()); BlockPlaceholderNode falseSucc = currentGraph.add(new BlockPlaceholderNode()); - IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new NullCheckNode(receiver, false)), trueSucc, falseSucc, 1)); + IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new IsNullNode(receiver)), trueSucc, falseSucc, 1)); append(ifNode); - lastInstr = trueSucc; + lastInstr = falseSucc; if (GraalOptions.OmitHotExceptionStacktrace) { ValueNode exception = ConstantNode.forObject(new NullPointerException(), runtime, currentGraph); - falseSucc.setNext(handleException(exception, bci())); + trueSucc.setNext(handleException(exception, bci())); } else { RuntimeCallNode call = currentGraph.add(new RuntimeCallNode(CiRuntimeCall.CreateNullPointerException)); call.setStateAfter(frameState.create(bci())); - falseSucc.setNext(call); + trueSucc.setNext(call); call.setNext(handleException(call, bci())); } } @@ -753,7 +775,7 @@ private void emitBoundsCheck(ValueNode index, ValueNode length) { BlockPlaceholderNode trueSucc = currentGraph.add(new BlockPlaceholderNode()); BlockPlaceholderNode falseSucc = currentGraph.add(new BlockPlaceholderNode()); - IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new CompareNode(index, Condition.BT, length)), trueSucc, falseSucc, 1)); + IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new IntegerBelowThanNode(index, length)), trueSucc, falseSucc, 1)); append(ifNode); lastInstr = trueSucc; @@ -1023,7 +1045,7 @@ ValueNode local = frameState.loadLocal(localIndex); JsrScope scope = currentBlock.jsrScope; int retAddress = scope.nextReturnAddress(); - append(currentGraph.add(new FixedGuardNode(currentGraph.unique(new CompareNode(local, Condition.EQ, ConstantNode.forJsr(retAddress, currentGraph))), RiDeoptReason.JavaSubroutineMismatch, RiDeoptAction.InvalidateReprofile, graphId))); + append(currentGraph.add(new FixedGuardNode(currentGraph.unique(new IntegerEqualsNode(local, ConstantNode.forJsr(retAddress, currentGraph))), RiDeoptReason.JavaSubroutineMismatch, RiDeoptAction.InvalidateReprofile, graphId))); if (!successor.jsrScope.equals(scope.pop())) { throw new JsrNotSupportedBailout("unstructured control flow (ret leaves more than one scope)"); } @@ -1391,7 +1413,7 @@ FixedNode catchSuccessor = createTarget(block.successors.get(0), frameState); FixedNode nextDispatch = createTarget(nextBlock, frameState); ValueNode exception = frameState.stackAt(0); - IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new InstanceOfNode(typeInstruction, (RiResolvedType) catchType, exception, false)), catchSuccessor, nextDispatch, 0.5)); + IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new InstanceOfNode(typeInstruction, (RiResolvedType) catchType, exception)), catchSuccessor, nextDispatch, 0.5)); append(ifNode); } } diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.nodes/src/com/oracle/graal/cri/CiLoweringTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/cri/CiLoweringTool.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/cri/CiLoweringTool.java Wed May 23 11:55:31 2012 +0200 @@ -23,13 +23,16 @@ package com.oracle.graal.cri; import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ri.*; public interface CiLoweringTool { GraalRuntime getRuntime(); Node getGuardAnchor(); + Node createNullCheckGuard(ValueNode object, long leafGraphId); Node createGuard(Node condition, RiDeoptReason deoptReason, RiDeoptAction action, long leafGraphId); + Node createGuard(Node condition, RiDeoptReason deoptReason, RiDeoptAction action, boolean negated, long leafGraphId); CiAssumptions assumptions(); } diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BooleanNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BooleanNode.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BooleanNode.java Wed May 23 11:55:31 2012 +0200 @@ -24,6 +24,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -37,5 +38,13 @@ super(stamp, dependencies); } - public abstract BooleanNode negate(); + /** + * Tells all usages of this node to negate their effect. For example, IfNodes should switch their true and false successors. + */ + public void negateUsages() { + for (Node n : usages().snapshot()) { + assert n instanceof Negatable; + ((Negatable) n).negate(); + } + } } diff -r 1d63466ba795 -r 16c27447923c 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 May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java Wed May 23 11:55:31 2012 +0200 @@ -227,9 +227,4 @@ return super.toString(verbosity); } } - - @Override - public BooleanNode negate() { - return ConstantNode.forBoolean(!value.asBoolean(), graph()); - } } diff -r 1d63466ba795 -r 16c27447923c 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 May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java Wed May 23 11:55:31 2012 +0200 @@ -28,64 +28,76 @@ import com.oracle.graal.nodes.type.*; import com.oracle.max.cri.ri.*; -public final class FixedGuardNode extends FixedWithNextNode implements Simplifiable, Lowerable, LIRLowerable, Node.IterableNodeType { +public final class FixedGuardNode extends FixedWithNextNode implements Simplifiable, Lowerable, LIRLowerable, Node.IterableNodeType, Negatable { - @Input private final NodeInputList conditions; + @Input private BooleanNode condition; private final RiDeoptReason deoptReason; private final RiDeoptAction action; + private boolean negated; private final long leafGraphId; + public BooleanNode condition() { + return condition; + } + + public void setCondition(BooleanNode x) { + updateUsages(condition, x); + condition = x; + } + public FixedGuardNode(BooleanNode condition, RiDeoptReason deoptReason, RiDeoptAction action, long leafGraphId) { + this(condition, deoptReason, action, false, leafGraphId); + } + + public FixedGuardNode(BooleanNode condition, RiDeoptReason deoptReason, RiDeoptAction action, boolean negated, long leafGraphId) { super(StampFactory.illegal()); this.action = action; + this.negated = negated; this.leafGraphId = leafGraphId; - this.conditions = new NodeInputList<>(this, new BooleanNode[] {condition}); + this.condition = condition; this.deoptReason = deoptReason; } @Override + public String toString(Verbosity verbosity) { + if (verbosity == Verbosity.Name && negated) { + return "!" + super.toString(verbosity); + } else { + return super.toString(verbosity); + } + } + + @Override public void generate(LIRGeneratorTool gen) { - for (BooleanNode condition : conditions()) { - gen.emitGuardCheck(condition, deoptReason, action, leafGraphId); - } - } - - public void addCondition(BooleanNode x) { - conditions.add(x); - } - - public NodeInputList conditions() { - return conditions; + gen.emitGuardCheck(condition, deoptReason, action, negated, leafGraphId); } @Override public void simplify(SimplifierTool tool) { - for (BooleanNode n : conditions.snapshot()) { - if (n instanceof ConstantNode) { - ConstantNode c = (ConstantNode) n; - if (c.asConstant().asBoolean()) { - conditions.remove(n); - } else { - FixedNode next = this.next(); - if (next != null) { - tool.deleteBranch(next); - } - setNext(graph().add(new DeoptimizeNode(RiDeoptAction.InvalidateRecompile, deoptReason, leafGraphId))); - return; + if (condition instanceof ConstantNode) { + ConstantNode c = (ConstantNode) condition; + if (c.asConstant().asBoolean() != negated) { + ((StructuredGraph) graph()).removeFixed(this); + } else { + FixedNode next = this.next(); + if (next != null) { + tool.deleteBranch(next); } + setNext(graph().add(new DeoptimizeNode(RiDeoptAction.InvalidateRecompile, deoptReason, leafGraphId))); + return; } } - if (conditions.isEmpty()) { - ((StructuredGraph) graph()).removeFixed(this); - } } @Override public void lower(CiLoweringTool tool) { AnchorNode newAnchor = graph().add(new AnchorNode()); - for (BooleanNode b : conditions) { - newAnchor.dependencies().add(tool.createGuard(b, deoptReason, action, leafGraphId)); - } + newAnchor.dependencies().add(tool.createGuard(condition, deoptReason, action, negated, leafGraphId)); ((StructuredGraph) graph()).replaceFixedWithFixed(this, newAnchor); } + + @Override + public void negate() { + negated = !negated; + } } diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java Wed May 23 11:55:31 2012 +0200 @@ -40,12 +40,13 @@ * maximum flexibility for the guard node and guarantees that deoptimization occurs only if the control flow would have * reached the guarded node (without taking exceptions into account). */ -public final class GuardNode extends FloatingNode implements Canonicalizable, LIRLowerable, TypeFeedbackProvider, Node.IterableNodeType { +public final class GuardNode extends FloatingNode implements Canonicalizable, LIRLowerable, TypeFeedbackProvider, Node.IterableNodeType, Negatable { @Input private BooleanNode condition; @Input(notDataflow = true) private FixedNode anchor; private final RiDeoptReason reason; private final RiDeoptAction action; + private boolean negated; private final long leafGraphId; public FixedNode anchor() { @@ -69,6 +70,10 @@ condition = x; } + public boolean negated() { + return negated; + } + public RiDeoptReason reason() { return reason; } @@ -77,25 +82,35 @@ return action; } - public GuardNode(BooleanNode condition, FixedNode anchor, RiDeoptReason reason, RiDeoptAction action, long leafGraphId) { + public GuardNode(BooleanNode condition, FixedNode anchor, RiDeoptReason reason, RiDeoptAction action, boolean negated, long leafGraphId) { super(StampFactory.illegal()); this.condition = condition; this.anchor = anchor; this.reason = reason; this.action = action; + this.negated = negated; this.leafGraphId = leafGraphId; } @Override + public String toString(Verbosity verbosity) { + if (verbosity == Verbosity.Name && negated) { + return "!" + super.toString(verbosity); + } else { + return super.toString(verbosity); + } + } + + @Override public void generate(LIRGeneratorTool gen) { - gen.emitGuardCheck(condition(), reason(), action(), leafGraphId); + gen.emitGuardCheck(condition(), reason(), action(), negated(), leafGraphId); } @Override public ValueNode canonical(CanonicalizerTool tool) { if (condition() instanceof ConstantNode) { ConstantNode c = (ConstantNode) condition(); - if (c.asConstant().asBoolean()) { + if (c.asConstant().asBoolean() != negated) { if (!dependencies().isEmpty()) { for (Node usage : usages()) { if (usage instanceof ValueNode) { @@ -116,4 +131,9 @@ ((ConditionalTypeFeedbackProvider) condition).typeFeedback(tool); } } + + @Override + public void negate() { + negated = !negated; + } } diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Wed May 23 11:55:31 2012 +0200 @@ -33,12 +33,10 @@ * The {@code IfNode} represents a branch that can go one of two directions depending on the outcome of a * comparison. */ -public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable, SplitTypeFeedbackProvider { +public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable, SplitTypeFeedbackProvider, Negatable { public static final int TRUE_EDGE = 0; public static final int FALSE_EDGE = 1; - private static final BeginNode[] EMPTY_IF_SUCCESSORS = new BeginNode[] {null, null}; - @Input private BooleanNode compare; public BooleanNode compare() { @@ -55,11 +53,6 @@ this.compare = condition; } - public IfNode(BooleanNode condition, double probability) { - super(StampFactory.illegal(), EMPTY_IF_SUCCESSORS, new double[] {probability, 1 - probability}); - this.compare = condition; - } - /** * Gets the true successor. * @@ -193,4 +186,17 @@ ((ConditionalTypeFeedbackProvider) compare).typeFeedback(blockSuccessor == TRUE_EDGE ? tool : tool.negate()); } } + + @Override + public void negate() { + BeginNode trueSucc = trueSuccessor(); + BeginNode falseSucc = falseSuccessor(); + setTrueSuccessor(null); + setFalseSuccessor(null); + setTrueSuccessor(falseSucc); + setFalseSuccessor(trueSucc); + double prop = branchProbability[TRUE_EDGE]; + branchProbability[TRUE_EDGE] = branchProbability[FALSE_EDGE]; + branchProbability[FALSE_EDGE] = prop; + } } diff -r 1d63466ba795 -r 16c27447923c 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 May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java Wed May 23 11:55:31 2012 +0200 @@ -81,7 +81,7 @@ int predIndex = phiPredecessorIndex(pred); assert predIndex != -1; deleteEnd(pred); - for (PhiNode phi : phis()) { + for (PhiNode phi : phis().snapshot()) { ValueNode removedValue = phi.valueAt(predIndex); phi.removeInput(predIndex); if (removedValue != null && removedValue.isAlive() && removedValue.usages().isEmpty() && GraphUtil.isFloatingNode().apply(removedValue)) { diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java Wed May 23 11:55:31 2012 +0200 @@ -22,12 +22,12 @@ */ package com.oracle.graal.nodes.calc; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ri.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.spi.types.*; -import com.oracle.graal.nodes.type.*; /* TODO (thomaswue/gdub) For high-level optimization purpose the compare node should be a boolean *value* (it is currently only a helper node) * But in the back-end the comparison should not always be materialized (for example in x86 the comparison result will not be in a register but in a flag) @@ -35,14 +35,11 @@ * Compare should probably be made a value (so that it can be canonicalized for example) and in later stages some Compare usage should be transformed * into variants that do not materialize the value (CompareIf, CompareGuard...) */ -public final class CompareNode extends BooleanNode implements Canonicalizable, LIRLowerable, ConditionalTypeFeedbackProvider, TypeCanonicalizable { +public abstract class CompareNode extends BooleanNode implements Canonicalizable, LIRLowerable { @Input private ValueNode x; @Input private ValueNode y; - private final Condition condition; - private final boolean unorderedIsTrue; - public ValueNode x() { return x; } @@ -55,27 +52,11 @@ * Constructs a new Compare instruction. * * @param x the instruction producing the first input to the instruction - * @param condition the condition (comparison operation) * @param y the instruction that produces the second input to this instruction - * @param graph */ - public CompareNode(ValueNode x, Condition condition, ValueNode y) { - this(x, condition, false, y); - } - - /** - * Constructs a new Compare instruction. - * - * @param x the instruction producing the first input to the instruction - * @param condition the condition (comparison operation) - * @param y the instruction that produces the second input to this instruction - * @param graph - */ - public CompareNode(ValueNode x, Condition condition, boolean unorderedIsTrue, ValueNode y) { + public CompareNode(ValueNode x, ValueNode y) { super(StampFactory.illegal()); assert (x == null && y == null) || x.kind() == y.kind(); - this.condition = condition; - this.unorderedIsTrue = unorderedIsTrue; this.x = x; this.y = y; } @@ -85,44 +66,27 @@ * * @return the condition */ - public Condition condition() { - return condition; - } + public abstract Condition condition(); /** - * Checks whether unordered inputs mean true or false. + * Checks whether unordered inputs mean true or false (only applies to float operations). * * @return {@code true} if unordered inputs produce true */ - public boolean unorderedIsTrue() { - return unorderedIsTrue; - } - - @Override - public BooleanNode negate() { - return graph().unique(new CompareNode(x(), condition.negate(), !unorderedIsTrue, y())); - } + public abstract boolean unorderedIsTrue(); @Override public void generate(LIRGeneratorTool gen) { } - @Override - public String toString(Verbosity verbosity) { - if (verbosity == Verbosity.Name) { - return super.toString(Verbosity.Name) + " " + condition.operator; - } else { - return super.toString(verbosity); - } - } - private ValueNode optimizeMaterialize(CiConstant constant, MaterializeNode materializeNode, RiRuntime runtime) { + private ValueNode optimizeMaterialize(CiConstant constant, MaterializeNode materializeNode, RiRuntime runtime, Condition cond) { CiConstant trueConstant = materializeNode.trueValue().asConstant(); CiConstant falseConstant = materializeNode.falseValue().asConstant(); if (falseConstant != null && trueConstant != null) { - Boolean trueResult = condition().foldCondition(trueConstant, constant, runtime, unorderedIsTrue()); - Boolean falseResult = condition().foldCondition(falseConstant, constant, runtime, unorderedIsTrue()); + Boolean trueResult = cond.foldCondition(trueConstant, constant, runtime, unorderedIsTrue()); + Boolean falseResult = cond.foldCondition(falseConstant, constant, runtime, unorderedIsTrue()); if (trueResult != null && falseResult != null) { boolean trueUnboxedResult = trueResult; @@ -135,7 +99,8 @@ return materializeNode.condition(); } else { assert falseUnboxedResult == true; - return materializeNode.condition().negate(); + negateUsages(); + return materializeNode.condition(); } } @@ -144,160 +109,27 @@ return this; } - private ValueNode optimizeNormalizeCmp(CiConstant constant, NormalizeCompareNode normalizeNode) { - if (constant.kind == CiKind.Int && constant.asInt() == 0) { - Condition cond = condition(); - boolean isLess = cond == Condition.LE || cond == Condition.LT || cond == Condition.BE || cond == Condition.BT; - boolean canonUnorderedIsTrue = cond != Condition.EQ && (cond == Condition.NE || !(isLess ^ normalizeNode.isUnorderedLess)); - CompareNode result = graph().unique(new CompareNode(normalizeNode.x(), cond, canonUnorderedIsTrue, normalizeNode.y())); - return result; - } - return this; + protected ValueNode optimizeNormalizeCmp(CiConstant constant, NormalizeCompareNode normalizeNode, boolean mirrored) { + throw new GraalInternalError("NormalizeCompareNode connected to %s (%s %s %s)", this, constant, normalizeNode, mirrored); } - @Override public ValueNode canonical(CanonicalizerTool tool) { - if (x().isConstant() && !y().isConstant()) { // move constants to the left (y) - return graph().unique(new CompareNode(y(), condition.mirror(), unorderedIsTrue(), x())); - } else if (x().isConstant() && y().isConstant()) { - CiConstant constX = x().asConstant(); - CiConstant constY = y().asConstant(); - Boolean result = condition().foldCondition(constX, constY, tool.runtime(), unorderedIsTrue()); - if (result != null) { - return ConstantNode.forBoolean(result, graph()); - } - } - - if (y().isConstant()) { - if (x() instanceof MaterializeNode) { - return optimizeMaterialize(y().asConstant(), (MaterializeNode) x(), tool.runtime()); - } else if (x() instanceof NormalizeCompareNode) { - return optimizeNormalizeCmp(y().asConstant(), (NormalizeCompareNode) x()); - } + if (x().isConstant() && y().isConstant()) { + return ConstantNode.forBoolean(condition().foldCondition(x().asConstant(), y().asConstant(), tool.runtime(), unorderedIsTrue()), graph()); } - - if (x() == y() && x().kind() != CiKind.Float && x().kind() != CiKind.Double) { - return ConstantNode.forBoolean(condition().check(1, 1), graph()); - } - if ((condition == Condition.NE || condition == Condition.EQ) && x().kind() == CiKind.Object) { - ValueNode object = null; - if (x().isNullConstant()) { - object = y(); - } else if (y().isNullConstant()) { - object = x(); + if (x().isConstant()) { + if (y() instanceof MaterializeNode) { + return optimizeMaterialize(x().asConstant(), (MaterializeNode) y(), tool.runtime(), condition().mirror()); + } else if (y() instanceof NormalizeCompareNode) { + return optimizeNormalizeCmp(x().asConstant(), (NormalizeCompareNode) y(), true); } - if (object != null) { - return graph().unique(new NullCheckNode(object, condition == Condition.EQ)); - } else { - Stamp xStamp = x.stamp(); - Stamp yStamp = y.stamp(); - if (xStamp.alwaysDistinct(yStamp)) { - return ConstantNode.forBoolean(condition == Condition.NE, graph()); - } + } else if (y().isConstant()) { + if (x() instanceof MaterializeNode) { + return optimizeMaterialize(y().asConstant(), (MaterializeNode) x(), tool.runtime(), condition()); + } else if (x() instanceof NormalizeCompareNode) { + return optimizeNormalizeCmp(y().asConstant(), (NormalizeCompareNode) x(), false); } } return this; } - - @Override - public void typeFeedback(TypeFeedbackTool tool) { - CiKind kind = x().kind(); - assert y().kind() == kind; - if (kind == CiKind.Object) { - assert condition == Condition.EQ || condition == Condition.NE; - if (y().isConstant() && !x().isConstant()) { - tool.addObject(x()).constantBound(condition, y().asConstant()); - } else if (x().isConstant() && !y().isConstant()) { - tool.addObject(y()).constantBound(condition.mirror(), x().asConstant()); - } else if (!x().isConstant() && !y.isConstant()) { - tool.addObject(x()).valueBound(condition, y()); - tool.addObject(y()).valueBound(condition.mirror(), x()); - } else { - // both are constant, this should be canonicalized... - } - } else if (kind == CiKind.Int || kind == CiKind.Long) { - if (y().isConstant() && !x().isConstant()) { - tool.addScalar(x()).constantBound(condition, y().asConstant()); - } else if (x().isConstant() && !y().isConstant()) { - tool.addScalar(y()).constantBound(condition.mirror(), x().asConstant()); - } else if (!x().isConstant() && !y.isConstant()) { - tool.addScalar(x()).valueBound(condition, y(), tool.queryScalar(y())); - tool.addScalar(y()).valueBound(condition.mirror(), x(), tool.queryScalar(x())); - } else { - // both are constant, this should be canonicalized... - } - } else if (kind == CiKind.Float || kind == CiKind.Double) { - // nothing yet... - } - } - - @Override - public Result canonical(TypeFeedbackTool tool) { - CiKind kind = x().kind(); - if (kind == CiKind.Int || kind == CiKind.Long) { - ScalarTypeQuery queryX = tool.queryScalar(x()); - if (y().isConstant() && !x().isConstant()) { - if (queryX.constantBound(condition, y().asConstant())) { - return new Result(ConstantNode.forBoolean(true, graph()), queryX); - } else if (queryX.constantBound(condition.negate(), y().asConstant())) { - return new Result(ConstantNode.forBoolean(false, graph()), queryX); - } - } else { - ScalarTypeQuery queryY = tool.queryScalar(y()); - if (x().isConstant() && !y().isConstant()) { - if (queryY.constantBound(condition.mirror(), x().asConstant())) { - return new Result(ConstantNode.forBoolean(true, graph()), queryY); - } else if (queryY.constantBound(condition.mirror().negate(), x().asConstant())) { - return new Result(ConstantNode.forBoolean(false, graph()), queryY); - } - } else if (!x().isConstant() && !y.isConstant()) { - if (condition == Condition.BT || condition == Condition.BE) { - if (queryY.constantBound(Condition.GE, new CiConstant(kind, 0))) { - if (queryX.constantBound(Condition.GE, new CiConstant(kind, 0))) { - if (queryX.valueBound(condition == Condition.BT ? Condition.LT : Condition.LE, y())) { - return new Result(ConstantNode.forBoolean(true, graph()), queryX, queryY); - } - } - } - } - - if (queryX.valueBound(condition, y())) { - return new Result(ConstantNode.forBoolean(true, graph()), queryX); - } else if (queryX.valueBound(condition.negate(), y())) { - return new Result(ConstantNode.forBoolean(false, graph()), queryX); - } - } else { - // both are constant, this should be canonicalized... - } - } - } else if (kind == CiKind.Object) { - assert condition == Condition.EQ || condition == Condition.NE; - ObjectTypeQuery queryX = tool.queryObject(x()); - if (y().isConstant() && !x().isConstant()) { - if (queryX.constantBound(condition, y().asConstant())) { - return new Result(ConstantNode.forBoolean(true, graph()), queryX); - } else if (queryX.constantBound(condition.negate(), y().asConstant())) { - return new Result(ConstantNode.forBoolean(false, graph()), queryX); - } - } else { - ObjectTypeQuery queryY = tool.queryObject(y()); - if (x().isConstant() && !y().isConstant()) { - if (queryY.constantBound(condition.mirror(), x().asConstant())) { - return new Result(ConstantNode.forBoolean(true, graph()), queryY); - } else if (queryY.constantBound(condition.mirror().negate(), x().asConstant())) { - return new Result(ConstantNode.forBoolean(false, graph()), queryY); - } - } else if (!x().isConstant() && !y.isConstant()) { - if (queryX.valueBound(condition, y())) { - return new Result(ConstantNode.forBoolean(true, graph()), queryX); - } else if (queryX.valueBound(condition.negate(), y())) { - return new Result(ConstantNode.forBoolean(false, graph()), queryX); - } - } else { - // both are constant, this should be canonicalized... - } - } - } - return null; - } } diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/Condition.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/Condition.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/Condition.java Wed May 23 11:55:31 2012 +0200 @@ -224,6 +224,13 @@ } /** + * Returns true if this condition represents an unsigned comparison. EQ and NE are not considered to be unsigned. + */ + public final boolean isUnsigned() { + return this == Condition.BT || this == Condition.BE || this == Condition.AT || this == Condition.AE; + } + + /** * Checks if this conditional operation is commutative. * @return {@code true} if this operation is commutative */ @@ -239,6 +246,19 @@ * @return {@link Boolean#TRUE} if the comparison is known to be true, * {@link Boolean#FALSE} if the comparison is known to be false */ + public boolean foldCondition(CiConstant lt, CiConstant rt, RiRuntime runtime) { + assert !lt.kind.isFloatOrDouble() && !rt.kind.isFloatOrDouble(); + return foldCondition(lt, rt, runtime, false); + } + + /** + * Attempts to fold a comparison between two constants and return the result. + * @param lt the constant on the left side of the comparison + * @param rt the constant on the right side of the comparison + * @param runtime the RiRuntime (might be needed to compare runtime-specific types) + * @param unorderedIsTrue true if an undecided float comparison should result in "true" + * @return true if the comparison is known to be true, false if the comparison is known to be false + */ public boolean foldCondition(CiConstant lt, CiConstant rt, RiRuntime runtime, boolean unorderedIsTrue) { switch (lt.kind) { case Boolean: diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java Wed May 23 11:55:31 2012 +0200 @@ -29,7 +29,7 @@ * The {@code ConditionalNode} class represents a comparison that yields one of two values. Note that these nodes are not * built directly from the bytecode but are introduced by canonicalization. */ -public class ConditionalNode extends BinaryNode implements Canonicalizable, LIRLowerable { +public class ConditionalNode extends BinaryNode implements Canonicalizable, LIRLowerable, Negatable { @Input private BooleanNode condition; @@ -72,4 +72,9 @@ public void generate(LIRGeneratorTool generator) { generator.emitConditional(this); } + + @Override + public void negate() { + ((StructuredGraph) graph()).replaceFloating(this, graph().unique(new ConditionalNode(condition, falseValue(), trueValue()))); + } } diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java Wed May 23 11:55:31 2012 +0200 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2011, 2011, 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.nodes.calc; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; + +@NodeInfo(shortName = "==") +public final class FloatEqualsNode extends CompareNode { + + /** + * Constructs a new floating point equality comparison node. + * + * @param x the instruction producing the first input to the instruction + * @param y the instruction that produces the second input to this instruction + */ + public FloatEqualsNode(ValueNode x, ValueNode y) { + super(x, y); + assert x.kind().isFloatOrDouble(); + assert y.kind().isFloatOrDouble(); + } + + @Override + public Condition condition() { + return Condition.EQ; + } + + @Override + public boolean unorderedIsTrue() { + return false; + } +} diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java Wed May 23 11:55:31 2012 +0200 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2011, 2011, 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.nodes.calc; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; + +@NodeInfo(shortName = "<") +public final class FloatLessThanNode extends CompareNode { + + private final boolean unorderedIsTrue; + + /** + * Constructs a new floating point comparison node. + * + * @param x the instruction producing the first input to the instruction + * @param y the instruction that produces the second input to this instruction + * @param unorderedIsTrue whether a comparison that is undecided (involving NaNs, etc.) leads to a "true" result + */ + public FloatLessThanNode(ValueNode x, ValueNode y, boolean unorderedIsTrue) { + super(x, y); + assert x.kind().isFloatOrDouble(); + assert y.kind().isFloatOrDouble(); + this.unorderedIsTrue = unorderedIsTrue; + } + + @Override + public Condition condition() { + return Condition.LT; + } + + @Override + public boolean unorderedIsTrue() { + return unorderedIsTrue; + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + if (x() == y() && !unorderedIsTrue()) { + return ConstantNode.forBoolean(false, graph()); + } + return super.canonical(tool); + } +} diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java Wed May 23 11:55:31 2012 +0200 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2011, 2011, 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.nodes.calc; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.max.cri.ci.*; + +@NodeInfo(shortName = "|<|") +public final class IntegerBelowThanNode extends CompareNode { + + /** + * Constructs a new unsigned integer comparison node. + * + * @param x the instruction producing the first input to the instruction + * @param y the instruction that produces the second input to this instruction + */ + public IntegerBelowThanNode(ValueNode x, ValueNode y) { + super(x, y); + assert !x.kind().isFloatOrDouble() && x.kind() != CiKind.Object; + assert !y.kind().isFloatOrDouble() && y.kind() != CiKind.Object; + } + + @Override + public Condition condition() { + return Condition.BT; + } + + @Override + public boolean unorderedIsTrue() { + return false; + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + if (x() == y()) { + return ConstantNode.forBoolean(false, graph()); + } + return super.canonical(tool); + } +} diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java Wed May 23 11:55:31 2012 +0200 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2011, 2011, 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.nodes.calc; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.max.cri.ci.*; + +@NodeInfo(shortName = "==") +public final class IntegerEqualsNode extends CompareNode { + + /** + * Constructs a new integer equality comparison node. + * + * @param x the instruction producing the first input to the instruction + * @param y the instruction that produces the second input to this instruction + */ + public IntegerEqualsNode(ValueNode x, ValueNode y) { + super(x, y); + assert !x.kind().isFloatOrDouble() && x.kind() != CiKind.Object; + assert !y.kind().isFloatOrDouble() && y.kind() != CiKind.Object; + } + + @Override + public Condition condition() { + return Condition.EQ; + } + + @Override + public boolean unorderedIsTrue() { + return false; + } + + @Override + protected ValueNode optimizeNormalizeCmp(CiConstant constant, NormalizeCompareNode normalizeNode, boolean mirrored) { + if (constant.kind == CiKind.Int && constant.asInt() == 0) { + ValueNode a = mirrored ? normalizeNode.y() : normalizeNode.x(); + ValueNode b = mirrored ? normalizeNode.x() : normalizeNode.y(); + + if (normalizeNode.x().kind().isFloatOrDouble()) { + return graph().unique(new FloatEqualsNode(a, b)); + } else { + return graph().unique(new IntegerEqualsNode(a, b)); + } + } + return this; + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + if (x() == y()) { + return ConstantNode.forBoolean(true, graph()); + } + return super.canonical(tool); + } +} diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java Wed May 23 11:55:31 2012 +0200 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2011, 2011, 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.nodes.calc; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.max.cri.ci.*; + +@NodeInfo(shortName = "<") +public final class IntegerLessThanNode extends CompareNode { + + /** + * Constructs a new integer comparison node. + * + * @param x the instruction producing the first input to the instruction + * @param y the instruction that produces the second input to this instruction + */ + public IntegerLessThanNode(ValueNode x, ValueNode y) { + super(x, y); + assert !x.kind().isFloatOrDouble() && x.kind() != CiKind.Object; + assert !y.kind().isFloatOrDouble() && y.kind() != CiKind.Object; + } + + @Override + public Condition condition() { + return Condition.LT; + } + + @Override + public boolean unorderedIsTrue() { + return false; + } + + @Override + protected ValueNode optimizeNormalizeCmp(CiConstant constant, NormalizeCompareNode normalizeNode, boolean mirrored) { + assert condition() == Condition.LT; + if (constant.kind == CiKind.Int && constant.asInt() == 0) { + ValueNode a = mirrored ? normalizeNode.y() : normalizeNode.x(); + ValueNode b = mirrored ? normalizeNode.x() : normalizeNode.y(); + + if (normalizeNode.x().kind().isFloatOrDouble()) { + return graph().unique(new FloatLessThanNode(a, b, mirrored ^ normalizeNode.isUnorderedLess)); + } else { + return graph().unique(new IntegerLessThanNode(a, b)); + } + } + return this; + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + if (x() == y()) { + return ConstantNode.forBoolean(false, graph()); + } + return super.canonical(tool); + } +} diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java Wed May 23 11:55:31 2012 +0200 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2009, 2011, 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.nodes.calc; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.max.cri.ci.*; + +/** + * An IsNullNode will be true if the supplied value is null, and false if it is non-null. + */ +public final class IsNullNode extends BooleanNode implements Canonicalizable, LIRLowerable { + + @Input private ValueNode object; + + public ValueNode object() { + return object; + } + + /** + * Constructs a new IsNullNode instruction. + * + * @param object the instruction producing the object to check against null + */ + public IsNullNode(ValueNode object) { + super(StampFactory.illegal()); + assert object.kind() == CiKind.Object : object.kind(); + this.object = object; + } + + @Override + public void generate(LIRGeneratorTool gen) { + // Nothing to do. + } + + @Override + public boolean verify() { + assertTrue(object() != null, "is null input must not be null"); + assertTrue(object().kind().isObject(), "is null input must be an object"); + return super.verify(); + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + CiConstant constant = object().asConstant(); + if (constant != null) { + assert constant.kind == CiKind.Object; + return ConstantNode.forBoolean(constant.isNull(), graph()); + } + if (object.stamp().nonNull()) { + return ConstantNode.forBoolean(false, graph()); + } + return this; + } +} diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java Wed May 23 11:55:31 2012 +0200 @@ -31,8 +31,7 @@ */ public final class NegateNode extends FloatingNode implements Canonicalizable, LIRLowerable { - @Input - private ValueNode x; + @Input private ValueNode x; public ValueNode x() { return x; diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java Wed May 23 11:55:31 2012 +0200 @@ -28,7 +28,8 @@ import com.oracle.graal.nodes.spi.*; /** - * Returns -1, 0, or 1 if either x < y, x == y, or x > y. + * Returns -1, 0, or 1 if either x < y, x == y, or x > y. If the comparison is undecided (one of the inputs is NaN), the + * result is 1 if isUnorderedLess is false and -1 if isUnorderedLess is true. */ public final class NormalizeCompareNode extends BinaryNode implements Lowerable { public final boolean isUnorderedLess; @@ -48,10 +49,17 @@ public void lower(CiLoweringTool tool) { StructuredGraph graph = (StructuredGraph) graph(); - CompareNode equalComp = graph.unique(new CompareNode(x(), Condition.EQ, false, y())); + BooleanNode equalComp; + BooleanNode lessComp; + if (x().kind().isFloatOrDouble()) { + equalComp = graph.unique(new FloatEqualsNode(x(), y())); + lessComp = graph.unique(new FloatLessThanNode(x(), y(), isUnorderedLess)); + } else { + equalComp = graph.unique(new IntegerEqualsNode(x(), y())); + lessComp = graph.unique(new IntegerLessThanNode(x(), y())); + } + MaterializeNode equalValue = MaterializeNode.create(equalComp, graph, ConstantNode.forInt(0, graph), ConstantNode.forInt(1, graph)); - - CompareNode lessComp = graph.unique(new CompareNode(x(), Condition.LT, isUnorderedLess, y())); MaterializeNode value = MaterializeNode.create(lessComp, graph, ConstantNode.forInt(-1, graph), equalValue); graph.replaceFloating(this, value); diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NullCheckNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NullCheckNode.java Wed May 23 10:09:39 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2009, 2011, 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.nodes.calc; - -import com.oracle.max.cri.ci.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.spi.types.*; -import com.oracle.graal.nodes.type.*; - -/** - * A NullCheckNode will be true if the supplied value is non-null, and false if it is null. - * This behavior can be inverted by setting {@link #expectedNull} to true. - */ -public final class NullCheckNode extends BooleanNode implements Canonicalizable, LIRLowerable, ConditionalTypeFeedbackProvider, TypeCanonicalizable { - - @Input private ValueNode object; - public final boolean expectedNull; - - public ValueNode object() { - return object; - } - - /** - * Constructs a new NullCheck instruction. - * - * @param object the instruction producing the object to check against null - * @param expectedNull True when this node checks that the value is null, false when this node checks for non-null - */ - public NullCheckNode(ValueNode object, boolean expectedNull) { - super(StampFactory.illegal()); - assert object.kind() == CiKind.Object : object.kind(); - this.object = object; - this.expectedNull = expectedNull; - } - - @Override - public void generate(LIRGeneratorTool gen) { - // Nothing to do. - } - - @Override - public boolean verify() { - assertTrue(object() != null, "null check input must not be null"); - assertTrue(object().kind().isObject(), "null check input must be an object"); - return super.verify(); - } - - @Override - public ValueNode canonical(CanonicalizerTool tool) { - CiConstant constant = object().asConstant(); - if (constant != null) { - assert constant.kind == CiKind.Object; - return ConstantNode.forBoolean(constant.isNull() == expectedNull, graph()); - } - if (object.stamp().nonNull()) { - return ConstantNode.forBoolean(!expectedNull, graph()); - } - return this; - } - - @Override - public BooleanNode negate() { - return graph().unique(new NullCheckNode(object(), !expectedNull)); - } - - @Override - public void typeFeedback(TypeFeedbackTool tool) { - Condition expectedCondition = expectedNull ? Condition.EQ : Condition.NE; - tool.addObject(object()).constantBound(expectedCondition, CiConstant.NULL_OBJECT); - } - - @Override - public Result canonical(TypeFeedbackTool tool) { - Condition expectedCondition = expectedNull ? Condition.EQ : Condition.NE; - ObjectTypeQuery query = tool.queryObject(object()); - if (query.constantBound(expectedCondition, CiConstant.NULL_OBJECT)) { - return new Result(ConstantNode.forBoolean(true, graph()), query); - } else if (query.constantBound(expectedCondition.negate(), CiConstant.NULL_OBJECT)) { - return new Result(ConstantNode.forBoolean(false, graph()), query); - } - return null; - } -} diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java Wed May 23 11:55:31 2012 +0200 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2011, 2011, 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.nodes.calc; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.max.cri.ci.*; + +@NodeInfo(shortName = "==") +public final class ObjectEqualsNode extends CompareNode { + + /** + * Constructs a new object equality comparison node. + * + * @param x the instruction producing the first input to the instruction + * @param y the instruction that produces the second input to this instruction + */ + public ObjectEqualsNode(ValueNode x, ValueNode y) { + super(x, y); + assert x.kind() == CiKind.Object; + assert y.kind() == CiKind.Object; + } + + @Override + public Condition condition() { + return Condition.EQ; + } + + @Override + public boolean unorderedIsTrue() { + return false; + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + if (x() == y()) { + return ConstantNode.forBoolean(true, graph()); + } + + if (x().isNullConstant()) { + return graph().unique(new IsNullNode(y())); + } else if (y().isNullConstant()) { + return graph().unique(new IsNullNode(x())); + } + if (x().stamp().alwaysDistinct(y().stamp())) { + return ConstantNode.forBoolean(false, graph()); + } + + return super.canonical(tool); + } +} diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeReadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeReadNode.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeReadNode.java Wed May 23 11:55:31 2012 +0200 @@ -25,11 +25,8 @@ import com.oracle.graal.cri.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; -import com.oracle.max.cri.ri.*; - public class SafeReadNode extends SafeAccessNode implements Lowerable { @@ -41,7 +38,7 @@ @Override public void lower(CiLoweringTool tool) { StructuredGraph graph = (StructuredGraph) graph(); - Node guard = tool.createGuard(graph.unique(new NullCheckNode(object(), false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, leafGraphId()); + Node guard = tool.createNullCheckGuard(object(), leafGraphId()); ReadNode read = graph.add(new ReadNode(object(), location(), stamp())); read.dependencies().add(guard); diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java Wed May 23 11:55:31 2012 +0200 @@ -25,14 +25,11 @@ import com.oracle.graal.cri.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.max.cri.ci.*; -import com.oracle.max.cri.ri.*; - -public class SafeWriteNode extends SafeAccessNode implements StateSplit, Lowerable{ +public class SafeWriteNode extends SafeAccessNode implements StateSplit, Lowerable { @Input private ValueNode value; @Input(notDataflow = true) private FrameState stateAfter; @@ -63,7 +60,7 @@ @Override public void lower(CiLoweringTool tool) { StructuredGraph graph = (StructuredGraph) graph(); - Node guard = tool.createGuard(graph.unique(new NullCheckNode(object(), false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, leafGraphId()); + Node guard = tool.createNullCheckGuard(object(), leafGraphId()); WriteNode write = graph.add(new WriteNode(object(), value(), location())); write.dependencies().add(guard); graph.replaceFixedWithFixed(this, write); diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java Wed May 23 11:55:31 2012 +0200 @@ -35,16 +35,11 @@ */ public final class InstanceOfNode extends BooleanNode implements Canonicalizable, LIRLowerable, ConditionalTypeFeedbackProvider, TypeCanonicalizable { - private final boolean negated; @Input private ValueNode object; @Input private ValueNode targetClassInstruction; private final RiResolvedType targetClass; private final RiTypeProfile profile; - public boolean negated() { - return negated; - } - /** * Constructs a new InstanceOfNode. * @@ -52,17 +47,16 @@ * @param targetClass the class which is the target of the instanceof check * @param object the instruction producing the object input to this instruction */ - public InstanceOfNode(ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object, boolean negated) { - this(targetClassInstruction, targetClass, object, null, negated); + public InstanceOfNode(ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object) { + this(targetClassInstruction, targetClass, object, null); } - public InstanceOfNode(ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object, RiTypeProfile profile, boolean negated) { + public InstanceOfNode(ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object, RiTypeProfile profile) { super(StampFactory.illegal()); this.targetClassInstruction = targetClassInstruction; this.targetClass = targetClass; this.object = object; this.profile = profile; - this.negated = negated; assert targetClass != null; } @@ -81,16 +75,17 @@ if (subType) { if (object().stamp().nonNull()) { // the instanceOf matches, so return true (or false, for the negated case) - return ConstantNode.forBoolean(!negated, graph()); + return ConstantNode.forBoolean(true, graph()); } else { // the instanceof matches if the object is non-null, so return true (or false, for the negated case) depending on the null-ness. - return graph().unique(new NullCheckNode(object(), negated)); + negateUsages(); + return graph().unique(new IsNullNode(object())); } } else { // since this type check failed for an exact type we know that it can never succeed at run time. // we also don't care about null values, since they will also make the check fail. // so return false (or true, for the negated case) - return ConstantNode.forBoolean(negated, graph()); + return ConstantNode.forBoolean(false, graph()); } } else { RiResolvedType declared = object().declaredType(); @@ -100,10 +95,11 @@ if (subType) { if (object().stamp().nonNull()) { // the instanceOf matches, so return true (or false, for the negated case) - return ConstantNode.forBoolean(!negated, graph()); + return ConstantNode.forBoolean(true, graph()); } else { // the instanceof matches if the object is non-null, so return true (or false, for the negated case) depending on the null-ness. - return graph().unique(new NullCheckNode(object(), negated)); + negateUsages(); + return graph().unique(new IsNullNode(object())); } } else { // since the subtype comparison was only performed on a declared type we don't really know if it might be true at run time... @@ -115,7 +111,7 @@ if (constant != null) { assert constant.kind == CiKind.Object; if (constant.isNull()) { - return ConstantNode.forBoolean(negated, graph()); + return ConstantNode.forBoolean(false, graph()); } else { assert false : "non-null constants are always expected to provide an exactType"; } @@ -124,40 +120,22 @@ } @Override - public BooleanNode negate() { - return graph().unique(new InstanceOfNode(targetClassInstruction(), targetClass(), object(), profile(), !negated)); - } - - @Override public void typeFeedback(TypeFeedbackTool tool) { - if (negated) { - tool.addObject(object()).notDeclaredType(targetClass(), true); - } else { - tool.addObject(object()).declaredType(targetClass(), true); - } - } - - @Override - public String toString(Verbosity verbosity) { - if (verbosity == Verbosity.Name && negated) { - return "!" + super.toString(Verbosity.Name); - } else { - return super.toString(verbosity); - } + tool.addObject(object()).declaredType(targetClass(), true); } @Override public Result canonical(TypeFeedbackTool tool) { ObjectTypeQuery query = tool.queryObject(object()); if (query.constantBound(Condition.EQ, CiConstant.NULL_OBJECT)) { - return new Result(ConstantNode.forBoolean(negated, graph()), query); + return new Result(ConstantNode.forBoolean(false, graph()), query); } else if (targetClass() != null) { if (query.notDeclaredType(targetClass())) { - return new Result(ConstantNode.forBoolean(negated, graph()), query); + return new Result(ConstantNode.forBoolean(false, graph()), query); } if (query.constantBound(Condition.NE, CiConstant.NULL_OBJECT)) { if (query.declaredType(targetClass())) { - return new Result(ConstantNode.forBoolean(!negated, graph()), query); + return new Result(ConstantNode.forBoolean(true, graph()), query); } } } diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/IsTypeNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/IsTypeNode.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/IsTypeNode.java Wed May 23 11:55:31 2012 +0200 @@ -77,9 +77,4 @@ // constants return the correct exactType, so they are handled by the code above return this; } - - @Override - public BooleanNode negate() { - throw new Error("unimplemented"); - } } diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java Wed May 23 11:55:31 2012 +0200 @@ -37,8 +37,8 @@ public abstract boolean canAnalyze(Node node); public boolean escape(Node node, Node usage) { - if (usage instanceof NullCheckNode) { - assert ((NullCheckNode) usage).object() == node; + if (usage instanceof IsNullNode) { + assert ((IsNullNode) usage).object() == node; return false; } else if (usage instanceof IsTypeNode) { assert ((IsTypeNode) usage).objectClass() == node; @@ -107,9 +107,9 @@ public void beforeUpdate(Node node, Node usage) { // IsNonNullNode and IsTypeNode should have been eliminated by the CanonicalizerPhase, but we can't rely on this - if (usage instanceof NullCheckNode) { - NullCheckNode x = (NullCheckNode) usage; - ((StructuredGraph) x.graph()).replaceFloating(x, ConstantNode.forBoolean(!x.expectedNull, node.graph())); + if (usage instanceof IsNullNode) { + IsNullNode x = (IsNullNode) usage; + ((StructuredGraph) x.graph()).replaceFloating(x, ConstantNode.forBoolean(false, node.graph())); } else if (usage instanceof IsTypeNode) { IsTypeNode x = (IsTypeNode) usage; assert x.type() == ((ValueNode) node).exactType(); diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java Wed May 23 11:55:31 2012 +0200 @@ -88,7 +88,7 @@ public abstract void emitIf(IfNode i); public abstract void emitConditional(ConditionalNode i); - public abstract void emitGuardCheck(BooleanNode comp, RiDeoptReason deoptReason, RiDeoptAction deoptAction, long leafGraphId); + public abstract void emitGuardCheck(BooleanNode comp, RiDeoptReason deoptReason, RiDeoptAction deoptAction, boolean negated, long leafGraphId); public abstract void emitLookupSwitch(LookupSwitchNode i); public abstract void emitTableSwitch(TableSwitchNode i); diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Negatable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Negatable.java Wed May 23 11:55:31 2012 +0200 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 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.nodes.spi; + +import com.oracle.graal.nodes.*; + +/** + * This interface marks a node as being able to negate its effect, this is intended for nodes that depend on a + * BooleanNode condition. The canonical representation of has, for example, no way to represent a != b. If such an + * expression appears during canonicalization the negated expression will be created (a == b) and the usages will be + * negated, using this interface's {@link #negate()} method. + */ +public interface Negatable { + + /** + * Tells this node that a condition it depends has been negated, and that it thus needs to invert its own effect. + * For example, an {@link IfNode} would switch its true and false successors. + */ + void negate(); +} diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java Wed May 23 11:55:31 2012 +0200 @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2011, 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.snippets; + +import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.*; + +import com.oracle.graal.compiler.loop.*; +import com.oracle.graal.compiler.phases.*; +import com.oracle.graal.compiler.phases.CanonicalizerPhase.IsImmutablePredicate; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node.Verbosity; +import com.oracle.graal.lir.cfg.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.util.*; +import com.oracle.max.cri.ci.*; +import com.oracle.max.cri.ri.*; + +/** + * A snippet template is a graph created by parsing a snippet method and then + * specialized by binding constants to some of the snippet arguments and applying + * transformations such as canonicalization and loop peeling. + */ +public class SnippetTemplate { + + /** + * Special value denoting a non-specialized argument. + */ + public static final Object _ = new Object() { + @Override + public String toString() { + return "_"; + } + }; + + /** + * Creates a snippet template. + * + * @param runtime + * @param method the snippet method to create the initial graph from + * @param args the arguments used to specialize the graph + */ + public static SnippetTemplate create(final RiRuntime runtime, final RiResolvedMethod method, final Object... args) { + return Debug.scope("SnippetSpecialization", method, new Callable() { + @Override + public SnippetTemplate call() throws Exception { + assert Modifier.isStatic(method.accessFlags()) : "snippet method must be static: " + method; + RiSignature signature = method.signature(); + assert signature.argumentCount(false) == args.length : "snippet method expects " + signature.argumentCount(false) + " arguments, " + args.length + " given"; + StructuredGraph snippetGraph = (StructuredGraph) method.compilerStorage().get(Graph.class); + + final Map constantArrays = new IdentityHashMap<>(); + IsImmutablePredicate immutabilityPredicate = new IsImmutablePredicate() { + public boolean apply(CiConstant constant) { + return constantArrays.containsKey(constant); + } + }; + + // Copy snippet graph, replacing parameters with given args in the process + StructuredGraph snippetCopy = new StructuredGraph(snippetGraph.name, snippetGraph.method()); + IdentityHashMap replacements = new IdentityHashMap<>(); + replacements.put(snippetGraph.start(), snippetCopy.start()); + int localCount = 0; + for (LocalNode local : snippetGraph.getNodes(LocalNode.class)) { + int index = local.index(); + Object arg = args[index]; + if (arg != _) { + CiKind kind = signature.argumentKindAt(index, false); + assert kind.isObject() || (arg != null && kind.toBoxedJavaClass() == arg.getClass()) : + "arg " + index + " for " + method + " has wrong kind: expected " + kind + ", got " + (arg == null ? "null" : arg.getClass().getSimpleName()); + CiConstant specializationArg = CiConstant.forBoxed(kind, arg); + if (kind.isObject()) { + assert arg == null || signature.argumentTypeAt(index, method.holder()).resolve(method.holder()).toJava().isInstance(arg) : + String.format("argument %d is of wrong type: expected %s, got %s", index, signature.argumentTypeAt(index, method.holder()).resolve(method.holder()).toJava().getName(), arg.getClass().getName()); + if (arg != null) { + if (arg.getClass().isArray()) { + constantArrays.put(specializationArg, specializationArg); + } + } + } + + ConstantNode argNode = ConstantNode.forCiConstant(specializationArg, runtime, snippetCopy); + replacements.put(local, argNode); + } + localCount++; + } + assert localCount == args.length : "snippet argument count mismatch"; + snippetCopy.addDuplicates(snippetGraph.getNodes(), replacements); + + Debug.dump(snippetCopy, "Before specialization"); + + if (!replacements.isEmpty()) { + new CanonicalizerPhase(null, runtime, null, 0, immutabilityPredicate).apply(snippetCopy); + } + + // Explode all loops in the snippet + if (snippetCopy.hasLoops()) { + ControlFlowGraph cfg = ControlFlowGraph.compute(snippetCopy, true, true, false, false); + for (Loop loop : cfg.getLoops()) { + LoopBeginNode loopBegin = loop.loopBegin(); + SuperBlock wholeLoop = LoopTransformUtil.wholeLoop(loop); + Debug.dump(snippetCopy, "Before exploding loop %s", loopBegin); + int peel = 0; + while (!loopBegin.isDeleted()) { + int mark = snippetCopy.getMark(); + LoopTransformUtil.peel(loop, wholeLoop); + Debug.dump(snippetCopy, "After peel %d", peel); + new CanonicalizerPhase(null, runtime, null, mark, immutabilityPredicate).apply(snippetCopy); + peel++; + } + Debug.dump(snippetCopy, "After exploding loop %s", loopBegin); + } + } + + // Remove all frame states from inlined snippet graph. Snippets must be atomic (i.e. free + // of side-effects that prevent deoptimizing to a point before the snippet). + for (Node node : snippetCopy.getNodes()) { + if (node instanceof StateSplit) { + StateSplit stateSplit = (StateSplit) node; + FrameState frameState = stateSplit.stateAfter(); + assert !stateSplit.hasSideEffect() : "snippets cannot contain side-effecting node " + node + "\n " + frameState.toString(Verbosity.Debugger); + if (frameState != null) { + stateSplit.setStateAfter(null); + } + } + } + + new DeadCodeEliminationPhase().apply(snippetCopy); + return new SnippetTemplate(args, snippetCopy); + } + }); + } + + SnippetTemplate(Object[] args, StructuredGraph graph) { + Object[] flattenedArgs = flatten(args); + this.graph = graph; + this.parameters = new Object[flattenedArgs.length]; + + // Find the constant nodes corresponding to the flattened positional parameters + for (ConstantNode node : graph.getNodes().filter(ConstantNode.class)) { + if (node.kind().isObject()) { + CiConstant constant = node.asConstant(); + if (constant.kind.isObject() && !constant.isNull()) { + for (int i = 0; i < flattenedArgs.length; i++) { + if (flattenedArgs[i] == constant.asObject()) { + parameters[i] = node; + } + } + } + } + } + + // Find the local nodes corresponding to the flattened positional parameters + int localIndex = 0; + for (int i = 0; i < flattenedArgs.length; i++) { + if (flattenedArgs[i] == _) { + for (LocalNode local : graph.getNodes(LocalNode.class)) { + if (local.index() == localIndex) { + assert parameters[i] == null; + parameters[i] = local; + } + } + localIndex++; + } else { + Object param = parameters[i]; + if (param == null) { + parameters[i] = flattenedArgs[i]; + } else { + assert param instanceof ConstantNode; + assert ((ConstantNode) param).kind().isObject(); + } + } + } + + nodes = new ArrayList<>(graph.getNodeCount()); + ReturnNode retNode = null; + StartNode entryPointNode = graph.start(); + for (Node node : graph.getNodes()) { + if (node == entryPointNode || node == entryPointNode.stateAfter()) { + // Do nothing. + } else { + nodes.add(node); + if (node instanceof ReturnNode) { + retNode = (ReturnNode) node; + } + } + } + this.returnNode = retNode; + } + + /** + * The graph built from the snippet method. + */ + public final StructuredGraph graph; + + /** + * The flattened positional parameters of this snippet. + * A {@link LocalNode} element is bound to a {@link ValueNode} to be supplied during + * instantiation, a {@link ConstantNode} is replaced by an object constant and any + * other element denotes an input fixed during specialization. + */ + public final Object[] parameters; + + /** + * The return node (if any) of the snippet. + */ + public final ReturnNode returnNode; + + /** + * The nodes to be inlined when this specialization is instantiated. + */ + public final ArrayList nodes; + + private IdentityHashMap replacements(StructuredGraph replaceeGraph, RiRuntime runtime, Object... args) { + Object[] flattenedArgs = flatten(args); + IdentityHashMap replacements = new IdentityHashMap<>(); + assert parameters.length >= flattenedArgs.length; + for (int i = 0; i < flattenedArgs.length; i++) { + Object param = parameters[i]; + Object arg = flattenedArgs[i]; + if (arg == null) { + assert !(param instanceof ValueNode) : param; + } else if (arg instanceof ValueNode) { + assert param instanceof LocalNode; + replacements.put((LocalNode) param, (ValueNode) arg); + } else { + replacements.put((ConstantNode) param, ConstantNode.forObject(arg, runtime, replaceeGraph)); + } + } + return replacements; + } + + /** + * Replaces a given node with this specialized snippet. + * + * @param runtime + * @param replacee the node that will be replaced + * @param anchor the control flow replacee + * @param args the arguments to be bound to the flattened positional parameters of the snippet + */ + public void instantiate(RiRuntime runtime, + Node replacee, + FixedWithNextNode anchor, Object... args) { + + // Inline the snippet nodes, replacing parameters with the given args in the process + String name = graph.name == null ? "{copy}" : graph.name + "{copy}"; + StructuredGraph graphCopy = new StructuredGraph(name, graph.method()); + StartNode entryPointNode = graph.start(); + FixedNode firstCFGNode = entryPointNode.next(); + StructuredGraph replaceeGraph = (StructuredGraph) replacee.graph(); + IdentityHashMap replacements = replacements(replaceeGraph, runtime, args); + Map duplicates = replaceeGraph.addDuplicates(nodes, replacements); + Debug.dump(replaceeGraph, "After inlining snippet %s", graphCopy.method()); + + // Re-wire the control flow graph around the replacee + FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode); + anchor.replaceAtPredecessors(firstCFGNodeDuplicate); + FixedNode next = anchor.next(); + anchor.setNext(null); + + // Replace all usages of the replacee with the value returned by the snippet + Node returnValue = null; + if (returnNode != null) { + if (returnNode.result() instanceof LocalNode) { + returnValue = replacements.get(returnNode.result()); + } else { + returnValue = duplicates.get(returnNode.result()); + } + assert returnValue != null || replacee.usages().isEmpty(); + replacee.replaceAtUsages(returnValue); + + Node returnDuplicate = duplicates.get(returnNode); + returnDuplicate.clearInputs(); + returnDuplicate.replaceAndDelete(next); + } + + // Remove the replacee from its graph + replacee.clearInputs(); + replacee.replaceAtUsages(null); + if (replacee instanceof FixedNode) { + GraphUtil.killCFG((FixedNode) replacee); + } else { + replacee.safeDelete(); + } + + Debug.dump(replaceeGraph, "After lowering %s with %s", replacee, this); + } + + /** + * Flattens a list of objects by replacing any array in {@code args} with its elements. + */ + private static Object[] flatten(Object... args) { + List list = new ArrayList<>(args.length * 2); + for (Object o : args) { + if (o instanceof Object[]) { + list.addAll(Arrays.asList((Object[]) o)); + } else { + list.add(o); + } + } + return list.toArray(new Object[list.size()]); + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(graph.toString()).append('('); + for (int i = 0; i < parameters.length; i++) { + Object param = parameters[i]; + if (param instanceof ConstantNode) { + buf.append(((ConstantNode) param).asConstant().asObject()); + } else if (param instanceof LocalNode) { + buf.append('_'); + } else { + buf.append(param); + } + if (i != parameters.length - 1) { + buf.append(", "); + } + } + return buf.append(')').toString(); + } +} diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/BoxingEliminationTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/BoxingEliminationTest.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/BoxingEliminationTest.java Wed May 23 11:55:31 2012 +0200 @@ -22,8 +22,6 @@ */ package com.oracle.graal.compiler.tests; -import static com.oracle.graal.graph.iterators.NodePredicates.*; - import java.util.*; import org.junit.*; @@ -32,24 +30,28 @@ import com.oracle.graal.compiler.phases.*; import com.oracle.graal.compiler.phases.PhasePlan.PhasePosition; import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; /** - * In the following tests, the usages of local variable "a" are replaced with the integer constant 0. - * Then boxing elimination is applied and it is verified that the resulting graph is equal to the - * graph of the method that just has a "return 1" statement in it. + * In the following tests, the usages of local variable "a" are replaced with the integer constant 0. Then boxing + * elimination is applied and it is verified that the resulting graph is equal to the graph of the method that just has + * a "return 1" statement in it. */ public class BoxingEliminationTest extends GraphTest { + private static final Short s = 2; - private static final String REFERENCE_SNIPPET = "referenceSnippet"; @SuppressWarnings("all") - public static short referenceSnippet(short a) { + public static short referenceSnippet1() { return 1; } + @SuppressWarnings("all") + public static short referenceSnippet2() { + return 2; + } + public static Short boxedShort() { return 1; } @@ -64,30 +66,31 @@ @Test public void test1() { - test("test1Snippet"); + test("test1Snippet", "referenceSnippet1"); } @SuppressWarnings("all") - public static short test1Snippet(short a) { + public static short test1Snippet() { return boxedShort(); } @Test public void test2() { - test("test2Snippet"); + test("test2Snippet", "referenceSnippet1"); } @SuppressWarnings("all") - public static short test2Snippet(short a) { + public static short test2Snippet() { return (Short) boxedObject(); } + @Test public void test3() { - test("test3Snippet"); + test("test3Snippet", "referenceSnippet1"); } @SuppressWarnings("all") - public static short test3Snippet(short a) { + public static short test3Snippet() { short b = boxedShort(); if (b < 0) { b = boxedShort(); @@ -97,15 +100,15 @@ @Test public void test4() { - test("test4Snippet"); + test("test4Snippet", "referenceSnippet2"); } @SuppressWarnings("all") - public static short test4Snippet(short a) { + public static short test4Snippet() { return constantBoxedShort(); } - private void test(final String snippet) { + private void test(final String snippet, final String referenceSnippet) { Debug.scope("BoxingEliminationTest", new DebugDumpScope(snippet), new Runnable() { @Override public void run() { @@ -115,11 +118,6 @@ PhasePlan phasePlan = getDefaultPhasePlan(); phasePlan.addPhase(PhasePosition.AFTER_PARSING, identifyBoxingPhase); identifyBoxingPhase.apply(graph); - LocalNode local = graph.getNodes(LocalNode.class).iterator().next(); - ConstantNode constant = ConstantNode.forShort((short) 0, graph); - for (Node n : local.usages().filter(isNotA(FrameState.class)).snapshot()) { - n.replaceFirstInput(local, constant); - } Collection hints = new ArrayList<>(); for (Invoke invoke : graph.getInvokes()) { hints.add(invoke); @@ -133,7 +131,7 @@ new ExpandBoxingNodesPhase(pool).apply(graph); new CanonicalizerPhase(null, runtime(), null).apply(graph); new DeadCodeEliminationPhase().apply(graph); - StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET); + StructuredGraph referenceGraph = parse(referenceSnippet); assertEquals(referenceGraph, graph); } }); diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompareCanonicalizerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompareCanonicalizerTest.java Wed May 23 11:55:31 2012 +0200 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 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.tests; + +import org.junit.*; + +import com.oracle.graal.compiler.phases.*; +import com.oracle.graal.nodes.*; + +public class CompareCanonicalizerTest extends GraphTest { + + @Test + public void testCanonicalComparison() { + StructuredGraph referenceGraph = parse("referenceCanonicalComparison"); + for (int i = 1; i < 4; i++) { + StructuredGraph graph = parse("canonicalCompare" + i); + assertEquals(referenceGraph, graph); + } + new CanonicalizerPhase(null, runtime(), null).apply(referenceGraph); + for (int i = 1; i < 4; i++) { + StructuredGraph graph = parse("canonicalCompare" + i); + new CanonicalizerPhase(null, runtime(), null).apply(graph); + assertEquals(referenceGraph, graph); + } + } + + public static int referenceCanonicalComparison(int a, int b) { + if (a < b) { + return 1; + } else { + return 2; + } + } + + public static int canonicalCompare1(int a, int b) { + if (a >= b) { + return 2; + } else { + return 1; + } + } + + public static int canonicalCompare2(int a, int b) { + if (b > a) { + return 1; + } else { + return 2; + } + } + + public static int canonicalCompare3(int a, int b) { + if (b <= a) { + return 2; + } else { + return 1; + } + } +} diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/ConditionTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/ConditionTest.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/ConditionTest.java Wed May 23 11:55:31 2012 +0200 @@ -41,7 +41,7 @@ for (Condition c2 : Condition.values()) { boolean implies = c1.implies(c2); if (implies) { - for (int i = 0; i < 10000; i++) { + for (int i = 0; i < 1000; i++) { CiConstant a = CiConstant.forInt(rand.nextInt()); CiConstant b = CiConstant.forInt(i < 100 ? a.asInt() : rand.nextInt()); boolean result1 = c1.foldCondition(a, b, null, false); @@ -63,7 +63,7 @@ Condition join = c1.join(c2); assertTrue(join == c2.join(c1)); if (join != null) { - for (int i = 0; i < 10000; i++) { + for (int i = 0; i < 1000; i++) { CiConstant a = CiConstant.forInt(rand.nextInt()); CiConstant b = CiConstant.forInt(i < 100 ? a.asInt() : rand.nextInt()); boolean result1 = c1.foldCondition(a, b, null, false); @@ -86,7 +86,7 @@ Condition meet = c1.meet(c2); assertTrue(meet == c2.meet(c1)); if (meet != null) { - for (int i = 0; i < 10000; i++) { + for (int i = 0; i < 1000; i++) { CiConstant a = CiConstant.forInt(rand.nextInt()); CiConstant b = CiConstant.forInt(i < 100 ? a.asInt() : rand.nextInt()); boolean result1 = c1.foldCondition(a, b, null, false); diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/DegeneratedLoopsTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/DegeneratedLoopsTest.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/DegeneratedLoopsTest.java Wed May 23 11:55:31 2012 +0200 @@ -22,13 +22,10 @@ */ package com.oracle.graal.compiler.tests; -import static com.oracle.graal.graph.iterators.NodePredicates.*; - import org.junit.*; import com.oracle.graal.compiler.phases.*; import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; /** @@ -42,7 +39,7 @@ @SuppressWarnings("all") public static int referenceSnippet(int a) { - return 1; + return a; } @Test @@ -79,16 +76,12 @@ private void test(String snippet) { StructuredGraph graph = parse(snippet); Debug.dump(graph, "Graph"); - LocalNode local = graph.getNodes(LocalNode.class).iterator().next(); - ConstantNode constant = ConstantNode.forInt(0, graph); - for (Node n : local.usages().filter(isNotA(FrameState.class)).snapshot()) { - n.replaceFirstInput(local, constant); - } for (Invoke invoke : graph.getInvokes()) { invoke.intrinsify(null); } new CanonicalizerPhase(null, runtime(), null).apply(graph); - StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET); Debug.dump(referenceGraph, "Graph"); + StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET); + Debug.dump(referenceGraph, "Graph"); assertEquals(referenceGraph, graph); } } diff -r 1d63466ba795 -r 16c27447923c 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 May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphTest.java Wed May 23 11:55:31 2012 +0200 @@ -30,9 +30,13 @@ import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.phases.*; import com.oracle.graal.compiler.phases.PhasePlan.PhasePosition; +import com.oracle.graal.compiler.schedule.*; import com.oracle.graal.cri.*; import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node.Verbosity; import com.oracle.graal.java.*; +import com.oracle.graal.lir.cfg.*; import com.oracle.graal.nodes.*; import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ri.*; @@ -65,13 +69,55 @@ } protected void assertEquals(StructuredGraph expected, StructuredGraph graph) { + String expectedString = getCanonicalGraphString(expected); + String actualString = getCanonicalGraphString(graph); + String mismatchString = "mismatch in graphs:\n========= expected =========\n" + expectedString + "\n\n========= actual =========\n" + actualString; + 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: " + expected.getNodeCount() + " vs. " + graph.getNodeCount()); + Assert.fail("Graphs do not have the same number of nodes: " + expected.getNodeCount() + " vs. " + graph.getNodeCount() + "\n" + mismatchString); + } + if (!expectedString.equals(actualString)) { + Debug.dump(expected, "mismatching graphs - expected"); + Debug.dump(graph, "mismatching graphs - actual"); + Assert.fail(mismatchString); } } + private static String getCanonicalGraphString(StructuredGraph graph) { + SchedulePhase schedule = new SchedulePhase(); + schedule.apply(graph); + + NodeMap canonicalId = graph.createNodeMap(); + int nextId = 0; + + StringBuilder result = new StringBuilder(); + for (Block block : schedule.getCFG().getBlocks()) { + result.append("Block " + block + " "); + if (block == schedule.getCFG().getStartBlock()) { + result.append("* "); + } + result.append("-> "); + for (Block succ : block.getSuccessors()) { + result.append(succ + " "); + } + result.append("\n"); + for (Node node : schedule.getBlockToNodesMap().get(block)) { + int id; + if (canonicalId.get(node) != null) { + id = canonicalId.get(node); + } else { + id = nextId++; + canonicalId.set(node, id); + } + String name = node instanceof ConstantNode ? node.toString(Verbosity.Name) : node.getClass().getSimpleName(); + result.append(" " + id + "|" + name + " (" + node.usages().size() + ")\n"); + } + } + return result.toString(); + } + protected GraalRuntime runtime() { return runtime; } diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/InstanceOfCanonicalizerTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/InstanceOfCanonicalizerTest.java Wed May 23 10:09:39 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -/* - * Copyright (c) 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.tests; - -import org.junit.*; - -import com.oracle.graal.compiler.phases.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.java.*; - -public class InstanceOfCanonicalizerTest extends GraphTest { - - /** - * The problem tested here is the following: When canonicalizing a negated instanceof for which the exact type - * suggests that the instanceof is true, we still need to check if the value is null. (because this would make the - * instanceof false, and thus the negated instanceof true). - * - * This test case is constructed by replacing an instanceof with its negated counterpart, since negated instanceof - * operations will only be created in complicated cases. - */ - @Test - public void test1() { - StructuredGraph graph = parse("testSnippet1"); - Debug.dump(graph, "Graph"); - for (Node node : graph.getNodes().snapshot()) { - if (node instanceof InstanceOfNode) { - graph.replaceFloating((InstanceOfNode) node, ((InstanceOfNode) node).negate()); - } - } - new CanonicalizerPhase(null, runtime(), null).apply(graph); - Debug.dump(graph, "Graph"); - for (Node node : graph.getNodes()) { - if (node instanceof InstanceOfNode) { - Assert.fail("InstanceOfNode should have been canonicalized"); - } else if (node instanceof ReturnNode) { - ReturnNode ret = (ReturnNode) node; - Assert.assertTrue("return value should be a MaterializeNode " + ret.result(), ret.result() instanceof MaterializeNode); - MaterializeNode materialize = (MaterializeNode) ret.result(); - Assert.assertTrue("return value should depend on nullness of parameter " + materialize.condition(), materialize.condition() instanceof NullCheckNode); - } - - } - } - - @SuppressWarnings("all") - public static boolean testSnippet1(String s) { - return s instanceof String; - } -} diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/InvokeTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/InvokeTest.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/InvokeTest.java Wed May 23 11:55:31 2012 +0200 @@ -22,15 +22,12 @@ */ package com.oracle.graal.compiler.tests; -import static com.oracle.graal.graph.iterators.NodePredicates.*; - import java.util.*; import org.junit.*; import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.phases.*; -import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; /** @@ -42,13 +39,17 @@ private static final String REFERENCE_SNIPPET = "referenceSnippet"; - @SuppressWarnings("all") - public static int referenceSnippet(int a) { + public static int const1() { return 1; } - public static int const1() { - return 1; + public static int const7() { + return 7; + } + + @SuppressWarnings("all") + public static int referenceSnippet() { + return 7; } @Test @@ -57,8 +58,8 @@ } @SuppressWarnings("all") - public static int test1Snippet(int a) { - return const1(); + public static int test1Snippet() { + return const7(); } @Test @@ -67,17 +68,12 @@ } @SuppressWarnings("all") - public static int test2Snippet(int a) { + public static int test2Snippet() { return const1() + const1() + const1() + const1() + const1() + const1() + const1(); } private void test(String snippet) { StructuredGraph graph = parse(snippet); - LocalNode local = graph.getNodes(LocalNode.class).iterator().next(); - ConstantNode constant = ConstantNode.forInt(0, graph); - for (Node n : local.usages().filter(isNotA(FrameState.class)).snapshot()) { - n.replaceFirstInput(local, constant); - } Collection hints = new ArrayList<>(); for (Invoke invoke : graph.getInvokes()) { hints.add(invoke); diff -r 1d63466ba795 -r 16c27447923c 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 May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/ScalarTypeSystemTest.java Wed May 23 11:55:31 2012 +0200 @@ -27,7 +27,6 @@ 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.*; @@ -44,7 +43,7 @@ } } - @Test + @Test(expected = AssertionFailedError.class) public void test1() { test("test1Snippet", "referenceSnippet1"); } @@ -61,7 +60,7 @@ } } - @Test + @Test(expected = AssertionFailedError.class) public void test2() { test("test2Snippet", "referenceSnippet1"); } @@ -78,7 +77,7 @@ } } - @Test + @Test(expected = AssertionFailedError.class) public void test3() { test("test3Snippet", "referenceSnippet2"); } @@ -163,12 +162,12 @@ } private void test(String snippet, String referenceSnippet) { - StructuredGraph graph = parse(snippet); Debug.dump(graph, "Graph"); - System.out.println("==================== " + snippet); +// TypeSystemTest.outputGraph(graph); new CanonicalizerPhase(null, runtime(), null).apply(graph); - new PropagateTypeCachePhase(null, null, null).apply(graph); + new CheckCastEliminationPhase().apply(graph); + new CanonicalizerPhase(null, runtime(), null).apply(graph); StructuredGraph referenceGraph = parse(referenceSnippet); assertEquals(referenceGraph, graph); } diff -r 1d63466ba795 -r 16c27447923c 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 May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/TypeSystemTest.java Wed May 23 11:55:31 2012 +0200 @@ -26,7 +26,7 @@ import junit.framework.Assert; -import org.junit.*; +import org.junit.Test; import com.oracle.graal.compiler.phases.*; import com.oracle.graal.compiler.schedule.*; @@ -36,7 +36,6 @@ 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. @@ -184,31 +183,33 @@ return ((InputStream) o).available(); } + @SuppressWarnings("unused") 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); + // TODO(ls) temporarily disabled, reintroduce when a proper type system is available + if (false) { + StructuredGraph graph = parse(snippet); + Debug.dump(graph, "Graph"); + 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"); +// 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()); } } @@ -232,16 +233,17 @@ } } - + @SuppressWarnings("unused") private void test(String snippet, Class clazz) { - StructuredGraph graph = parse(snippet); - Debug.dump(graph, "Graph"); - new CanonicalizerPhase(null, runtime(), null).apply(graph); - new PropagateTypeCachePhase(null, runtime(), null).apply(graph); - Debug.dump(graph, "Graph"); - if (graph.getNodes(clazz).iterator().hasNext()) { - outputGraph(graph); + // TODO(ls) temporarily disabled, reintroduce when a proper type system is available + if (false) { + StructuredGraph graph = parse(snippet); + Debug.dump(graph, "Graph"); + new CanonicalizerPhase(null, runtime(), null).apply(graph); + new PropagateTypeCachePhase(null, runtime(), null).apply(graph); + new CanonicalizerPhase(null, runtime(), null).apply(graph); + Debug.dump(graph, "Graph"); + Assert.assertFalse("shouldn't have nodes of type " + clazz, graph.getNodes(clazz).iterator().hasNext()); } - Assert.assertFalse("shouldn't have nodes of type " + clazz, graph.getNodes(clazz).iterator().hasNext()); } } diff -r 1d63466ba795 -r 16c27447923c graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiConstant.java --- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiConstant.java Wed May 23 10:09:39 2012 +0200 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiConstant.java Wed May 23 11:55:31 2012 +0200 @@ -473,6 +473,8 @@ */ public static CiConstant forBoxed(CiKind kind, Object value) { switch (kind) { + case Boolean: + return forBoolean((Boolean) value); case Byte: return forByte((Byte) value); case Char: