# HG changeset patch # User Tom Rodriguez # Date 1398886047 25200 # Node ID 100306ae985b25cf78c8d83819b536d1de180940 # Parent 625f779255a73391af07dde2c3e757986df4a5f6 switch MatchRule from class to method annotation and fix review feedback diff -r 625f779255a7 -r 100306ae985b graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java Wed Apr 30 11:27:59 2014 -0700 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java Wed Apr 30 12:27:27 2014 -0700 @@ -40,24 +40,6 @@ } }; - /** - * This is the Value of a node which was matched as part of a complex match. The value isn't - * actually useable but this marks it as having been evaluated. - */ - @SuppressWarnings("serial") public static Value INTERIOR_MATCH = new Value(Kind.Illegal) { - - @Override - public String toString() { - return "INTERIOR_MATCH"; - } - - @Override - public boolean equals(Object other) { - // This class is a singleton - return other != null && getClass() == other.getClass(); - } - }; - private final Kind kind; private final PlatformKind platformKind; diff -r 625f779255a7 -r 100306ae985b graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java --- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java Wed Apr 30 11:27:59 2014 -0700 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java Wed Apr 30 12:27:27 2014 -0700 @@ -182,20 +182,16 @@ // Only imm32 as long return null; } - return new ComplexMatchResult() { - public Value evaluate(NodeLIRBuilder builder) { - gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), constant, getState(access))); - gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability)); - return null; - } + return builder -> { + gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), constant, getState(access))); + gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability)); + return null; }; } else { - return new ComplexMatchResult() { - public Value evaluate(NodeLIRBuilder builder) { - gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), operand(value), getState(access))); - gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability)); - return null; - } + return builder -> { + gen.append(new AMD64TestMemoryOp(kind, makeAddress(access), operand(value), getState(access))); + gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability)); + return null; }; } } @@ -320,8 +316,6 @@ throw GraalInternalError.shouldNotReachHere(); } - static Object lock = new Object(); - private AMD64Arithmetic getOp(ValueNode operation, Access access) { Kind memoryKind = getMemoryKind(access); if (operation.getClass() == IntegerAddNode.class) { @@ -391,17 +385,10 @@ return null; } - @MatchRule("(If (IntegerTest=compare Read=access value))") - @MatchRule("(If (IntegerTest=compare FloatingRead=access value))") - public static class IfIntegerTest extends AMD64MatchGenerator { - IfNode root; - Access access; - ValueNode value; - - @Override - public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { - return gen.emitIntegerTestBranchMemory(root, value, access); - } + @MatchRule("(If (IntegerTest Read=access value))") + @MatchRule("(If (IntegerTest FloatingRead=access value))") + public ComplexMatchResult integerTestBranchMemory(IfNode root, Access access, ValueNode value) { + return emitIntegerTestBranchMemory(root, value, access); } @MatchRule("(If (IntegerEquals=compare value Read=access))") @@ -414,62 +401,32 @@ @MatchRule("(If (FloatEquals=compare value FloatingRead=access))") @MatchRule("(If (FloatLessThan=compare value Read=access))") @MatchRule("(If (FloatLessThan=compare value FloatingRead=access))") - public static class IfCompareMemory extends AMD64MatchGenerator { - IfNode root; - Access access; - ValueNode value; - CompareNode compare; - - @Override - public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { - return gen.emitCompareBranchMemory(root, compare, value, access); - } + public ComplexMatchResult ifCompareMemory(IfNode root, CompareNode compare, ValueNode value, Access access) { + return emitCompareBranchMemory(root, compare, value, access); } @MatchRule("(Or (LeftShift=lshift value Constant) (UnsignedRightShift=rshift value Constant))") - public static class RotateLeftConstant extends AMD64MatchGenerator { - LeftShiftNode lshift; - UnsignedRightShiftNode rshift; - - @Override - public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { - if ((lshift.getShiftAmountMask() & (lshift.y().asConstant().asInt() + rshift.y().asConstant().asInt())) == 0) { - return builder -> gen.getLIRGeneratorTool().emitRol(gen.operand(lshift.x()), gen.operand(lshift.y())); - } - return null; + public ComplexMatchResult rotateLeftConstant(LeftShiftNode lshift, UnsignedRightShiftNode rshift) { + if ((lshift.getShiftAmountMask() & (lshift.y().asConstant().asInt() + rshift.y().asConstant().asInt())) == 0) { + return builder -> getLIRGeneratorTool().emitRol(operand(lshift.x()), operand(lshift.y())); } - + return null; } - @MatchRule("(Or (LeftShift=lshift value (IntegerSub Constant=delta shiftAmount)) (UnsignedRightShift value shiftAmount))") - public static class RotateRightVariable extends AMD64MatchGenerator { - ValueNode value; - ValueNode shiftAmount; - ConstantNode delta; - - @Override - public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { - if (delta.asConstant().asLong() == 0 || delta.asConstant().asLong() == 32) { - return builder -> gen.getLIRGeneratorTool().emitRor(gen.operand(value), gen.operand(shiftAmount)); - } - return null; + @MatchRule("(Or (LeftShift value (IntegerSub Constant=delta shiftAmount)) (UnsignedRightShift value shiftAmount))") + public ComplexMatchResult rotateRightVariable(ValueNode value, ConstantNode delta, ValueNode shiftAmount) { + if (delta.asConstant().asLong() == 0 || delta.asConstant().asLong() == 32) { + return builder -> getLIRGeneratorTool().emitRor(operand(value), operand(shiftAmount)); } - + return null; } @MatchRule("(Or (LeftShift value shiftAmount) (UnsignedRightShift value (IntegerSub Constant=delta shiftAmount)))") - public static class RotateLeftVariable extends AMD64MatchGenerator { - ValueNode value; - ValueNode shiftAmount; - ConstantNode delta; - - @Override - public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { - if (delta.asConstant().asLong() == 0 || delta.asConstant().asLong() == 32) { - return builder -> gen.getLIRGeneratorTool().emitRol(gen.operand(value), gen.operand(shiftAmount)); - } - return null; + public ComplexMatchResult rotateLeftVariable(ValueNode value, ValueNode shiftAmount, ConstantNode delta) { + if (delta.asConstant().asLong() == 0 || delta.asConstant().asLong() == 32) { + return builder -> getLIRGeneratorTool().emitRol(operand(value), operand(shiftAmount)); } + return null; } @MatchRule("(IntegerAdd value Read=access)") @@ -490,121 +447,61 @@ @MatchRule("(Or value FloatingRead=access)") @MatchRule("(Xor value FloatingRead=access)") @MatchRule("(And value FloatingRead=access)") - public static class BinaryRead extends AMD64MatchGenerator { - BinaryNode root; - Access access; - ValueNode value; - - @Override - public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { - AMD64Arithmetic op = gen.getOp(root, access); - if (op != null) { - return builder -> gen.getLIRGeneratorTool().emitBinaryMemory(op, gen.getMemoryKind(access), gen.getLIRGeneratorTool().asAllocatable(gen.operand(value)), gen.makeAddress(access), - gen.getState(access)); - } - return null; + public ComplexMatchResult binaryRead(BinaryNode root, ValueNode value, Access access) { + AMD64Arithmetic op = getOp(root, access); + if (op != null) { + return builder -> getLIRGeneratorTool().emitBinaryMemory(op, getMemoryKind(access), getLIRGeneratorTool().asAllocatable(operand(value)), makeAddress(access), getState(access)); } + return null; } @MatchRule("(Write Narrow=narrow value)") - public static class WriteNarrow extends AMD64MatchGenerator { - WriteNode root; - NarrowNode narrow; - - @Override - public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { - return new ComplexMatchResult() { - @Override - public Value evaluate(NodeLIRBuilder builder) { - PlatformKind writeKind = gen.getLIRGeneratorTool().getPlatformKind(root.value().stamp()); - Value address = root.location().generateAddress(builder, gen.getLIRGeneratorTool(), gen.operand(root.object())); - Value v = gen.operand(narrow.getInput()); - gen.getLIRGeneratorTool().emitStore(writeKind, address, v, gen.state(root)); - return null; - } - }; - } + public ComplexMatchResult writeNarrow(WriteNode root, NarrowNode narrow) { + return builder -> { + PlatformKind writeKind = getLIRGeneratorTool().getPlatformKind(root.value().stamp()); + Value address = root.location().generateAddress(builder, getLIRGeneratorTool(), operand(root.object())); + Value v = operand(narrow.getInput()); + getLIRGeneratorTool().emitStore(writeKind, address, v, state(root)); + return null; + }; } @MatchRule("(SignExtend Read=access)") @MatchRule("(SignExtend FloatingRead=access)") - public static class SignExtend extends AMD64MatchGenerator { - Access access; - SignExtendNode root; - - @Override - public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { - return gen.emitSignExtendMemory(access, root.getInputBits(), root.getResultBits()); - } - } - - static abstract class AMD64MatchGenerator implements MatchGenerator { - public AMD64MatchGenerator() { - } - - public ComplexMatchResult match(NodeLIRBuilder gen) { - return match((AMD64NodeLIRBuilder) gen); - } - - abstract public ComplexMatchResult match(AMD64NodeLIRBuilder gen); + public ComplexMatchResult signExtend(SignExtendNode root, Access access) { + return emitSignExtendMemory(access, root.getInputBits(), root.getResultBits()); } @MatchRule("(ZeroExtend Read=access)") @MatchRule("(ZeroExtend FloatingRead=access)") - public static class ZeroExtend extends AMD64MatchGenerator { - Access access; - ZeroExtendNode root; - - @Override - public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { - Kind memoryKind = gen.getMemoryKind(access); - if (memoryKind.getBitCount() != root.getInputBits() && !memoryKind.isUnsigned()) { - /* - * The memory being read from is signed and smaller than the result size so this is - * a sign extension to inputBits followed by a zero extension to resultBits which - * can't be expressed in a memory operation. - */ - return null; - } - return new ComplexMatchResult() { - public Value evaluate(NodeLIRBuilder unused) { - return gen.getLIRGeneratorTool().emitZeroExtendMemory(memoryKind == Kind.Short ? Kind.Char : memoryKind, root.getResultBits(), gen.makeAddress(access), gen.getState(access)); - } - }; + public ComplexMatchResult zeroExtend(ZeroExtendNode root, Access access) { + Kind memoryKind = getMemoryKind(access); + if (memoryKind.getBitCount() != root.getInputBits() && !memoryKind.isUnsigned()) { + /* + * The memory being read from is signed and smaller than the result size so this is a + * sign extension to inputBits followed by a zero extension to resultBits which can't be + * expressed in a memory operation. + */ + return null; } + return builder -> getLIRGeneratorTool().emitZeroExtendMemory(memoryKind == Kind.Short ? Kind.Char : memoryKind, root.getResultBits(), makeAddress(access), getState(access)); } @MatchRule("(FloatConvert Read=access)") @MatchRule("(FloatConvert FloatingRead=access)") - public static class FloatConvert extends AMD64MatchGenerator { - Access access; - FloatConvertNode root; + public ComplexMatchResult floatConvert(FloatConvertNode root, Access access) { + return builder -> emitFloatConvertMemory(root, access); - @Override - public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { - return new ComplexMatchResult() { - public Value evaluate(NodeLIRBuilder builder) { - return gen.emitFloatConvertMemory(root, access); - } - }; - } } @MatchRule("(Reinterpret Read=access)") @MatchRule("(Reinterpret FloatingRead=access)") - public static class Reinterpret extends AMD64MatchGenerator { - Access access; - ReinterpretNode root; + public ComplexMatchResult reinterpret(ReinterpretNode root, Access access) { + return builder -> { + PlatformKind kind = getLIRGeneratorTool().getPlatformKind(root.stamp()); + return emitReinterpretMemory(kind, access); + }; - @Override - public ComplexMatchResult match(AMD64NodeLIRBuilder gen) { - return new ComplexMatchResult() { - public Value evaluate(NodeLIRBuilder builder) { - PlatformKind kind = gen.getLIRGeneratorTool().getPlatformKind(root.stamp()); - return gen.emitReinterpretMemory(kind, access); - } - }; - } } @Override diff -r 625f779255a7 -r 100306ae985b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java Wed Apr 30 11:27:59 2014 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java Wed Apr 30 12:27:27 2014 -0700 @@ -70,6 +70,8 @@ return enabled; } }; + @Option(help = "Enable more verbose log output when available") + public static final OptionValue LogVerbose = new OptionValue<>(false); // @formatter:on public static boolean areDebugScopePatternsEnabled() { @@ -150,7 +152,7 @@ /** * Extracts a {@link JavaMethod} from an opaque debug context. - * + * * @return the {@link JavaMethod} represented by {@code context} or null */ public static JavaMethod asJavaMethod(Object context) { diff -r 625f779255a7 -r 100306ae985b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java Wed Apr 30 11:27:59 2014 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java Wed Apr 30 12:27:27 2014 -0700 @@ -170,7 +170,7 @@ * ValueNodes. */ public void setMatchResult(ValueNode x, Value operand) { - assert operand.equals(Value.INTERIOR_MATCH) || operand instanceof ComplexMatchValue; + assert operand.equals(ComplexMatchValue.INTERIOR_MATCH) || operand instanceof ComplexMatchValue; assert operand instanceof ComplexMatchValue || x.usages().count() == 1 : "interior matches must be single user"; assert nodeOperands != null && nodeOperands.get(x) == null : "operand cannot be set twice"; assert !(x instanceof VirtualObjectNode); @@ -237,7 +237,7 @@ throw new GraalGraphInternalError(e).addContext(instr); } } - } else if (Value.INTERIOR_MATCH.equals(operand)) { + } else if (ComplexMatchValue.INTERIOR_MATCH.equals(operand)) { // Doesn't need to be evaluated Debug.log("interior match for %s", valueNode); } else if (operand instanceof ComplexMatchValue) { @@ -285,7 +285,7 @@ List statements = matchRules.get(node.getClass()); if (statements != null) { for (MatchStatement statement : statements) { - if (statement.generate(this, node, nodes)) { + if (statement.generate(this, index, node, nodes)) { // Found a match so skip to the next break; } diff -r 625f779255a7 -r 100306ae985b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchResult.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchResult.java Wed Apr 30 11:27:59 2014 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchResult.java Wed Apr 30 12:27:27 2014 -0700 @@ -25,10 +25,10 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.gen.*; -/* - * A closure that can be evaluated to produce the LIR for some complex match. Using a closure - * allows normal evaluation in NodeLIRBuilder for all the simple nodes with the complex nodes - * evaluated at the proper time. +/** + * A closure that can be evaluated to produce the LIR for some complex match. Using a closure allows + * normal evaluation in NodeLIRBuilder for all the simple nodes with the complex nodes evaluated at + * the proper time. */ public interface ComplexMatchResult { Value evaluate(NodeLIRBuilder gen); diff -r 625f779255a7 -r 100306ae985b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchValue.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchValue.java Wed Apr 30 11:27:59 2014 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchValue.java Wed Apr 30 12:27:27 2014 -0700 @@ -31,10 +31,25 @@ * usually occur here. */ public class ComplexMatchValue extends Value { + private static final long serialVersionUID = -4734670273590368770L; + /** - * + * This is the Value of a node which was matched as part of a complex match. The value isn't + * actually useable but this marks it as having been evaluated. */ - private static final long serialVersionUID = -4734670273590368770L; + @SuppressWarnings("serial") public static Value INTERIOR_MATCH = new Value(Kind.Illegal) { + + @Override + public String toString() { + return "INTERIOR_MATCH"; + } + + @Override + public boolean equals(Object other) { + // This class is a singleton + return other != null && getClass() == other.getClass(); + } + }; final ComplexMatchResult result; diff -r 625f779255a7 -r 100306ae985b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/GraalMatchableNodes.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/GraalMatchableNodes.java Wed Apr 30 11:27:59 2014 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/GraalMatchableNodes.java Wed Apr 30 12:27:27 2014 -0700 @@ -30,34 +30,34 @@ * Helper class to describe the matchable nodes in the core Graal IR. These could possibly live in * their respective classes but for simplicity in the {@link MatchProcessor} they are grouped here. */ -@MatchableNode(shortName = "Constant", value = ConstantNode.class, inputs = 0) -@MatchableNode(shortName = "FloatConvert", value = FloatConvertNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class) -@MatchableNode(shortName = "FloatSub", value = FloatSubNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class) -@MatchableNode(shortName = "FloatingRead", value = FloatingReadNode.class, inputs = 1, adapter = GraalMatchableNodes.ReadNodeAdapter.class) -@MatchableNode(shortName = "If", value = IfNode.class, inputs = 1, adapter = GraalMatchableNodes.IfNodeAdapter.class) -@MatchableNode(shortName = "IntegerSub", value = IntegerSubNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class) -@MatchableNode(shortName = "LeftShift", value = LeftShiftNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class) -@MatchableNode(shortName = "Narrow", value = NarrowNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class) -@MatchableNode(shortName = "Read", value = ReadNode.class, inputs = 1, adapter = GraalMatchableNodes.ReadNodeAdapter.class) -@MatchableNode(shortName = "Reinterpret", value = ReinterpretNode.class, inputs = 1, adapter = GraalMatchableNodes.ReinterpretNodeAdapter.class) -@MatchableNode(shortName = "SignExtend", value = SignExtendNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class) -@MatchableNode(shortName = "UnsignedRightShift", value = UnsignedRightShiftNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class) -@MatchableNode(shortName = "Write", value = WriteNode.class, inputs = 2, adapter = GraalMatchableNodes.WriteNodeAdapter.class) -@MatchableNode(shortName = "ZeroExtend", value = ZeroExtendNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class) -@MatchableNode(shortName = "And", value = AndNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) -@MatchableNode(shortName = "FloatAdd", value = FloatAddNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) -@MatchableNode(shortName = "FloatEquals", value = FloatEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) -@MatchableNode(shortName = "FloatLessThan", value = FloatLessThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) -@MatchableNode(shortName = "FloatMul", value = FloatMulNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) -@MatchableNode(shortName = "IntegerAdd", value = IntegerAddNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) -@MatchableNode(shortName = "IntegerBelowThan", value = IntegerBelowThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) -@MatchableNode(shortName = "IntegerEquals", value = IntegerEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) -@MatchableNode(shortName = "IntegerLessThan", value = IntegerLessThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) -@MatchableNode(shortName = "IntegerMul", value = IntegerMulNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) -@MatchableNode(shortName = "IntegerTest", value = IntegerTestNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) -@MatchableNode(shortName = "ObjectEquals", value = ObjectEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) -@MatchableNode(shortName = "Or", value = OrNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) -@MatchableNode(shortName = "Xor", value = XorNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) +@MatchableNode(nodeClass = ConstantNode.class, inputs = 0) +@MatchableNode(nodeClass = FloatConvertNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class) +@MatchableNode(nodeClass = FloatSubNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class) +@MatchableNode(nodeClass = FloatingReadNode.class, inputs = 1, adapter = GraalMatchableNodes.ReadNodeAdapter.class) +@MatchableNode(nodeClass = IfNode.class, inputs = 1, adapter = GraalMatchableNodes.IfNodeAdapter.class) +@MatchableNode(nodeClass = IntegerSubNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class) +@MatchableNode(nodeClass = LeftShiftNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class) +@MatchableNode(nodeClass = NarrowNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class) +@MatchableNode(nodeClass = ReadNode.class, inputs = 1, adapter = GraalMatchableNodes.ReadNodeAdapter.class) +@MatchableNode(nodeClass = ReinterpretNode.class, inputs = 1, adapter = GraalMatchableNodes.ReinterpretNodeAdapter.class) +@MatchableNode(nodeClass = SignExtendNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class) +@MatchableNode(nodeClass = UnsignedRightShiftNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class) +@MatchableNode(nodeClass = WriteNode.class, inputs = 2, adapter = GraalMatchableNodes.WriteNodeAdapter.class) +@MatchableNode(nodeClass = ZeroExtendNode.class, inputs = 1, adapter = GraalMatchableNodes.ConvertNodeAdapter.class) +@MatchableNode(nodeClass = AndNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) +@MatchableNode(nodeClass = FloatAddNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) +@MatchableNode(nodeClass = FloatEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) +@MatchableNode(nodeClass = FloatLessThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) +@MatchableNode(nodeClass = FloatMulNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) +@MatchableNode(nodeClass = IntegerAddNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) +@MatchableNode(nodeClass = IntegerBelowThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) +@MatchableNode(nodeClass = IntegerEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) +@MatchableNode(nodeClass = IntegerLessThanNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) +@MatchableNode(nodeClass = IntegerMulNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) +@MatchableNode(nodeClass = IntegerTestNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) +@MatchableNode(nodeClass = ObjectEqualsNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryOpLogicNodeAdapter.class, commutative = true) +@MatchableNode(nodeClass = OrNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) +@MatchableNode(nodeClass = XorNode.class, inputs = 2, adapter = GraalMatchableNodes.BinaryNodeAdapter.class, commutative = true) public class GraalMatchableNodes { public static class BinaryNodeAdapter extends MatchNodeAdapter { @Override diff -r 625f779255a7 -r 100306ae985b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchContext.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchContext.java Wed Apr 30 11:27:59 2014 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchContext.java Wed Apr 30 12:27:27 2014 -0700 @@ -22,10 +22,10 @@ */ package com.oracle.graal.compiler.match; -import java.lang.reflect.*; +import static com.oracle.graal.compiler.GraalDebugConfig.*; + import java.util.*; -import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.match.MatchPattern.Result; @@ -38,24 +38,41 @@ * Container for state captured during a match. */ public class MatchContext { - private final ArrayList consumed = new ArrayList<>(); - private final List nodes; + private final ValueNode root; - private List names; - private List> types; - private List values; + + private final List nodes; + private final MatchStatement rule; + + private Map namedNodes; + + private ArrayList consumed; + private int startIndex; + private int endIndex; + private final NodeLIRBuilder builder; - public MatchContext(NodeLIRBuilder builder, MatchStatement rule, ValueNode node, List nodes) { + private static class NamedNode { + final Class type; + final ValueNode value; + + NamedNode(Class type, ValueNode value) { + this.type = type; + this.value = value; + } + } + + public MatchContext(NodeLIRBuilder builder, MatchStatement rule, int index, ValueNode node, List nodes) { this.builder = builder; this.rule = rule; this.root = node; this.nodes = nodes; - // The root should be the last index since all the inputs must be scheduled before. - startIndex = endIndex = nodes.indexOf(node); + assert index == nodes.indexOf(node); + // The root should be the last index since all the inputs must be scheduled before it. + startIndex = endIndex = index; } public ValueNode getRoot() { @@ -63,19 +80,16 @@ } public Result captureNamedValue(String name, Class type, ValueNode value) { - if (names == null) { - names = new ArrayList<>(2); - values = new ArrayList<>(2); - types = new ArrayList<>(2); + if (namedNodes == null) { + namedNodes = new HashMap<>(2); } - int index = names.indexOf(name); - if (index == -1) { - names.add(name); - values.add(value); - types.add(type); + NamedNode current = namedNodes.get(name); + if (current == null) { + current = new NamedNode(type, value); + namedNodes.put(name, current); return Result.OK; } else { - if (values.get(index) != value) { + if (current.value != value || current.type != type) { return Result.NAMED_VALUE_MISMATCH(value, rule.getPattern()); } return Result.OK; @@ -85,20 +99,19 @@ public Result validate() { // Ensure that there's no unsafe work in between these operations. for (int i = startIndex; i <= endIndex; i++) { - ScheduledNode node = getNodes().get(i); + ScheduledNode node = nodes.get(i); if (node instanceof ConstantNode || node instanceof LocationNode || node instanceof VirtualObjectNode || node instanceof ParameterNode) { // these can be evaluated lazily so don't worry about them. This should probably be // captured by some interface that indicates that their generate method is empty. continue; - } else if (!consumed.contains(node) && node != root) { - // This is too verbose for normal logging. - // Debug.log("unexpected node %s", node); - // for (int j = startIndex; j <= endIndex; j++) { - // ScheduledNode theNode = getNodes().get(j); - // Debug.log("%s(%s) %1s", (consumed.contains(theNode) || theNode == root) ? "*" : - // " ", - // theNode.usages().count(), theNode); - // } + } else if (consumed == null || !consumed.contains(node) && node != root) { + if (LogVerbose.getValue()) { + Debug.log("unexpected node %s", node); + for (int j = startIndex; j <= endIndex; j++) { + ScheduledNode theNode = nodes.get(j); + Debug.log("%s(%s) %1s", (consumed.contains(theNode) || theNode == root) ? "*" : " ", theNode.usages().count(), theNode); + } + } return Result.NOT_SAFE(node, rule.getPattern()); } } @@ -106,56 +119,24 @@ } /** - * Transfers the captured value into the MatchGenerator instance. The reflective information - * should really be generated and checking during construction of the MatchStatement but this is - * ok for now. - */ - public void transferState(MatchGenerator generator) { - try { - for (int i = 0; i < names.size(); i++) { - String name = names.get(i); - try { - Field field = generator.getClass().getDeclaredField(name); - field.setAccessible(true); - field.set(generator, values.get(i)); - } catch (NoSuchFieldException e) { - // Doesn't exist so the generator doesn't care about the value. - } - } - } catch (SecurityException | IllegalArgumentException | IllegalAccessException e) { - throw new GraalInternalError(e); - } - try { - Field field = generator.getClass().getDeclaredField("root"); - field.setAccessible(true); - field.set(generator, getRoot()); - } catch (NoSuchFieldException e) { - // Doesn't exist - } catch (SecurityException | IllegalAccessException | IllegalArgumentException e) { - throw new GraalInternalError(e); - } - } - - public void setResult(ComplexMatchResult result) { - setResult(new ComplexMatchValue(result)); - } - - /** * Mark the interior nodes with INTERIOR_MATCH and set the Value of the root to be the result. * During final LIR generation it will be evaluated to produce the actual LIR value. * * @param result */ - public void setResult(ComplexMatchValue result) { + public void setResult(ComplexMatchResult result) { + ComplexMatchValue value = new ComplexMatchValue(result); Debug.log("matched %s %s", rule.getName(), rule.getPattern()); - // Debug.log("%s", rule.formatMatch(root)); - for (ValueNode node : consumed) { - // All the interior nodes should be skipped during the normal doRoot calls in - // NodeLIRBuilder so mark them as interior matches. The root of the match will get a - // closure which will be evaluated to produce the final LIR. - getBuilder().setMatchResult(node, Value.INTERIOR_MATCH); + Debug.log("with nodes %s", rule.formatMatch(root)); + if (consumed != null) { + for (ValueNode node : consumed) { + // All the interior nodes should be skipped during the normal doRoot calls in + // NodeLIRBuilder so mark them as interior matches. The root of the match will get a + // closure which will be evaluated to produce the final LIR. + builder.setMatchResult(node, ComplexMatchValue.INTERIOR_MATCH); + } } - getBuilder().setMatchResult(root, result); + builder.setMatchResult(root, value); } /** @@ -164,28 +145,43 @@ * @return Result.OK if the node can be safely consumed. */ public Result consume(ValueNode node) { - if (node.usages().count() != 1) { - return Result.TOO_MANY_USERS(node, rule.getPattern()); - } + assert node.usages().count() <= 1 : "should have already been checked"; - if (getBuilder().hasOperand(node)) { + if (builder.hasOperand(node)) { return Result.ALREADY_USED(node, rule.getPattern()); } - int index = getNodes().indexOf(node); + int index = nodes.indexOf(node); if (index == -1) { return Result.NOT_IN_BLOCK(node, rule.getPattern()); } startIndex = Math.min(startIndex, index); + if (consumed == null) { + consumed = new ArrayList<>(2); + } consumed.add(node); return Result.OK; } - private NodeLIRBuilder getBuilder() { - return builder; + /** + * Return the named node. It's an error if the + * + * @param name the name of a node in the match rule + * @return the matched node + * @throws GraalInternalError is the named node doesn't exist. + */ + public ValueNode namedNode(String name) { + if (namedNodes != null) { + NamedNode value = namedNodes.get(name); + if (value != null) { + return value.value; + } + } + throw new GraalInternalError("missing node %s", name); } - private List getNodes() { - return nodes; + @Override + public String toString() { + return String.format("%s %s (%d, %d) consumed %s", rule, root, startIndex, endIndex, consumed != null ? Arrays.toString(consumed.toArray()) : ""); } } diff -r 625f779255a7 -r 100306ae985b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java Wed Apr 30 11:27:59 2014 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java Wed Apr 30 12:27:27 2014 -0700 @@ -22,6 +22,7 @@ */ package com.oracle.graal.compiler.match; +import com.oracle.graal.debug.*; import com.oracle.graal.graph.Node.Verbosity; import com.oracle.graal.nodes.*; @@ -47,7 +48,9 @@ */ static class Result { final MatchResultCode code; + final ScheduledNode node; + final MatchPattern matcher; Result(MatchResultCode result, ScheduledNode node, MatchPattern matcher) { @@ -56,29 +59,42 @@ this.matcher = matcher; } + private static final DebugMetric MatchResult_WRONG_CLASS = Debug.metric("MatchResult_WRONG_CLASS"); + private static final DebugMetric MatchResult_NAMED_VALUE_MISMATCH = Debug.metric("MatchResult_NAMED_VALUE_MISMATCH"); + private static final DebugMetric MatchResult_TOO_MANY_USERS = Debug.metric("MatchResult_TOO_MANY_USERS"); + private static final DebugMetric MatchResult_NOT_IN_BLOCK = Debug.metric("MatchResult_NOT_IN_BLOCK"); + private static final DebugMetric MatchResult_NOT_SAFE = Debug.metric("MatchResult_NOT_SAFE"); + private static final DebugMetric MatchResult_ALREADY_USED = Debug.metric("MatchResult_ALREADY_USED"); + static final Result OK = new Result(MatchResultCode.OK, null, null); static Result WRONG_CLASS(ValueNode node, MatchPattern matcher) { + MatchResult_WRONG_CLASS.increment(); return new Result(MatchResultCode.WRONG_CLASS, node, matcher); } static Result NAMED_VALUE_MISMATCH(ValueNode node, MatchPattern matcher) { + MatchResult_NAMED_VALUE_MISMATCH.increment(); return new Result(MatchResultCode.NAMED_VALUE_MISMATCH, node, matcher); } static Result TOO_MANY_USERS(ValueNode node, MatchPattern matcher) { + MatchResult_TOO_MANY_USERS.increment(); return new Result(MatchResultCode.TOO_MANY_USERS, node, matcher); } static Result NOT_IN_BLOCK(ScheduledNode node, MatchPattern matcher) { + MatchResult_NOT_IN_BLOCK.increment(); return new Result(MatchResultCode.NOT_IN_BLOCK, node, matcher); } static Result NOT_SAFE(ScheduledNode node, MatchPattern matcher) { + MatchResult_NOT_SAFE.increment(); return new Result(MatchResultCode.NOT_SAFE, node, matcher); } static Result ALREADY_USED(ValueNode node, MatchPattern matcher) { + MatchResult_ALREADY_USED.increment(); return new Result(MatchResultCode.ALREADY_USED, node, matcher); } @@ -143,14 +159,32 @@ return nodeClass; } - Result match(ValueNode node, MatchContext context) { - return matchTree(node, context, true); + private Result matchType(ValueNode node) { + if (nodeClass != null && node.getClass() != nodeClass) { + return Result.WRONG_CLASS(node, this); + } + return Result.OK; } - private Result matchTree(ValueNode node, MatchContext context, boolean atRoot) { - Result result = Result.OK; - if (nodeClass != null && node.getClass() != nodeClass) { - return Result.WRONG_CLASS(node, this); + /** + * Match any named nodes and ensure that the consumed nodes can be safely merged. + * + * @param node + * @param context + * @return Result.OK is the pattern can be safely matched. + */ + Result matchUsage(ValueNode node, MatchContext context) { + Result result = matchUsage(node, context, true); + if (result == Result.OK) { + result = context.validate(); + } + return result; + } + + private Result matchUsage(ValueNode node, MatchContext context, boolean atRoot) { + Result result = matchType(node); + if (result != Result.OK) { + return result; } if (singleUser && !atRoot) { result = context.consume(node); @@ -164,9 +198,43 @@ } if (first != null) { - result = first.matchTree(adapter.getFirstInput(node), context, false); + result = first.matchUsage(adapter.getFirstInput(node), context, false); if (result == Result.OK && second != null) { - result = second.matchTree(adapter.getSecondInput(node), context, false); + result = second.matchUsage(adapter.getSecondInput(node), context, false); + } + } + + return result; + } + + /** + * Recursively match the shape of the tree without worry about named values. Most matches fail + * at this point so it's performed first. + * + * @param node + * @param statement + * @return Result.OK if the shape of the pattern matches. + */ + public Result matchShape(ValueNode node, MatchStatement statement) { + return matchShape(node, statement, true); + } + + private Result matchShape(ValueNode node, MatchStatement statement, boolean atRoot) { + Result result = matchType(node); + if (result != Result.OK) { + return result; + } + + if (singleUser && !atRoot) { + if (node.usages().count() > 1) { + return Result.TOO_MANY_USERS(node, statement.getPattern()); + } + } + + if (first != null) { + result = first.matchShape(adapter.getFirstInput(node), statement, false); + if (result == Result.OK && second != null) { + result = second.matchShape(adapter.getSecondInput(node), statement, false); } } @@ -195,7 +263,8 @@ String pre = first != null || second != null ? "(" : ""; String post = first != null || second != null ? ")" : ""; String nodeName = nodeClass.getSimpleName(); - return pre + nodeName + (name != null ? "=\"" + name + "\"" : "") + (first != null ? (" " + first.toString()) : "") + (second != null ? (" " + second.toString()) : "") + post; + nodeName = nodeName.substring(0, nodeName.length() - 4); + return pre + nodeName + (name != null ? "=" + name : "") + (first != null ? (" " + first.toString()) : "") + (second != null ? (" " + second.toString()) : "") + post; } } } diff -r 625f779255a7 -r 100306ae985b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java Wed Apr 30 11:27:59 2014 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java Wed Apr 30 12:27:27 2014 -0700 @@ -30,6 +30,7 @@ import javax.lang.model.*; import javax.lang.model.element.*; import javax.lang.model.type.*; +import javax.lang.model.util.*; import javax.tools.Diagnostic.Kind; import javax.tools.*; @@ -63,14 +64,23 @@ private static class RuleParseError extends RuntimeException { private static final long serialVersionUID = 6456128283609257490L; - RuleParseError(String message) { - super(message); + RuleParseError(String format, Object... args) { + super(String.format(format, args)); } } private class RuleParser { - final String[] tokens; - int current; + private ArrayList capturedTypes = new ArrayList<>(); + + private ArrayList capturedNames = new ArrayList<>(); + + private final String[] tokens; + + private int current; + + private MatchDescriptor matchDescriptor; + + private final Set originatingElements = new HashSet<>(); RuleParser(String rule) { Matcher m = tokenizer.matcher(rule); @@ -82,16 +92,29 @@ m.region(m.end(), m.regionEnd()); } if (end != m.regionEnd()) { - throw new RuleParseError("unexpected tokens :" + rule.substring(m.end(), m.regionEnd())); + throw new RuleParseError("Unnexpected tokens :" + rule.substring(m.end(), m.regionEnd())); } tokens = list.toArray(new String[0]); + + matchDescriptor = parseExpression(); + if (!done()) { + throw new RuleParseError("didn't consume all tokens"); + } + capturedNames.add(0, "root"); + capturedTypes.add(0, matchDescriptor.nodeType); } String next() { return tokens[current++]; } - String peek() { + String peek(String name) { + if (current >= tokens.length) { + if (name == null) { + throw new RuleParseError("Out of tokens"); + } + throw new RuleParseError("Out of tokens looking for %s", name); + } return tokens[current]; } @@ -99,13 +122,13 @@ return current == tokens.length; } - private MatchDescriptor parseSexp() { - if (peek().equals("(")) { + private MatchDescriptor parseExpression() { + if (peek("(").equals("(")) { next(); MatchDescriptor descriptor = parseType(true); for (int n = 0; n < descriptor.nodeType.inputs; n++) { - if (peek().equals("(")) { - descriptor.inputs[n] = parseSexp(); + if (peek("(").equals("(")) { + descriptor.inputs[n] = parseExpression(); } else { descriptor.inputs[n] = parseType(false); } @@ -115,46 +138,70 @@ throw new RuleParseError("not enough inputs for " + descriptor.name); } } - if (peek().equals(")")) { + if (peek(")").equals(")")) { next(); return descriptor; } } - throw new RuleParseError("didn't swallow sexp at: " + peek()); + throw new RuleParseError("Extra tokens following match pattern: " + peek(null)); } - private MatchDescriptor parseType(boolean sexp) { + private MatchDescriptor parseType(boolean forExpression) { TypeDescriptor type = null; String name = null; - if (Character.isUpperCase(peek().charAt(0))) { + if (Character.isUpperCase(peek("node type or name").charAt(0))) { String token = next(); - type = types.get(token); + type = knownTypes.get(token); if (type == null) { - throw new RuleParseError("unknown node type: " + token); + throw new RuleParseError("Unknown node type: " + token); } - if (peek().equals("=")) { + if (peek("=").equals("=")) { next(); name = next(); } - } else { + originatingElements.addAll(type.originatingElements); + } else if (Character.isLowerCase(peek("name").charAt(0))) { name = next(); - type = null; + type = valueType; + } else { + throw new RuleParseError("Unexpected token \"%s\" when looking for name or node type", peek(null)); } - return new MatchDescriptor(type, name, sexp); + if (name != null) { + if (!capturedNames.contains(name)) { + capturedNames.add(name); + capturedTypes.add(type); + } else { + int index = capturedNames.indexOf(name); + if (capturedTypes.get(index) != type) { + throw new RuleParseError("Captured node \"%s\" has differing types", name); + } + } + } + return new MatchDescriptor(type, name, forExpression); } - ArrayList generateVariants() { - MatchDescriptor descriptor = parseSexp(); - if (!done()) { - throw new RuleParseError("didn't consume all tokens"); - } - return descriptor.generateVariants(); + List generateVariants() { + return matchDescriptor.generateVariants(); + } + + /** + * + * @return the list of node types which are captured by name + */ + public ArrayList capturedTypes() { + return capturedTypes; + } + + public ArrayList capturedNames() { + return capturedNames; } } static Pattern tokenizer = Pattern.compile("\\s*([()=]|[A-Za-z][A-Za-z0-9]*)\\s*"); static class TypeDescriptor { + final TypeMirror mirror; + /** * The name uses in match expressions to refer to this type. */ @@ -192,7 +239,10 @@ */ final boolean cloneable; - TypeDescriptor(String shortName, String nodeClass, String nodePackage, int inputs, String adapter, boolean commutative) { + final Set originatingElements = new HashSet<>(); + + TypeDescriptor(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, int inputs, String adapter, boolean commutative) { + this.mirror = mirror; this.shortName = shortName; this.nodeClass = nodeClass; this.nodePackage = nodePackage; @@ -204,14 +254,28 @@ } } - HashMap types = new HashMap<>(); - ArrayList packages = new ArrayList<>(); + /** + * The types which are know for purpose of parsing MatchRule expressions. + */ + Map knownTypes = new HashMap<>(); + + /** + * The set of packages which must be imported to refer to the known classes. + */ + List requiredPackages = new ArrayList<>(); - private void declareType(String shortName, String nodeClass, String nodePackage, int inputs, String adapter, boolean commutative) { - TypeDescriptor descriptor = new TypeDescriptor(shortName, nodeClass, nodePackage, inputs, adapter, commutative); - types.put(shortName, descriptor); - if (!packages.contains(descriptor.nodePackage)) { - packages.add(descriptor.nodePackage); + /** + * The automatically generated wrapper class for a method based MatchRule. + */ + private Map invokers = new LinkedHashMap<>(); + private TypeDescriptor valueType; + + private void declareType(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, int inputs, String adapter, boolean commutative, Element element) { + TypeDescriptor descriptor = new TypeDescriptor(mirror, shortName, nodeClass, nodePackage, inputs, adapter, commutative); + descriptor.originatingElements.add(element); + knownTypes.put(shortName, descriptor); + if (!requiredPackages.contains(descriptor.nodePackage)) { + requiredPackages.add(descriptor.nodePackage); } } @@ -226,22 +290,28 @@ throw new GraalInternalError("can't find package for %s", type); } - static class MatchDescriptor { + class MatchDescriptor { TypeDescriptor nodeType; String name; MatchDescriptor[] inputs; - MatchDescriptor(TypeDescriptor nodeType, String name, boolean sexp) { + MatchDescriptor(TypeDescriptor nodeType, String name, boolean forExpression) { this.nodeType = nodeType; this.name = name; - if (sexp) { + if (forExpression) { this.inputs = new MatchDescriptor[nodeType.inputs]; } else { this.inputs = new MatchDescriptor[0]; } } - ArrayList generateVariants() { + /** + * Recursively generate all the variants of this rule pattern. Currently that just means to + * swap the inputs for commutative rules, producing all possible permutations. + * + * @return a list of Strings which will construct pattern matchers for this rule. + */ + List generateVariants() { String prefix = formatPrefix(); String suffix = formatSuffix(); ArrayList variants = new ArrayList<>(); @@ -266,7 +336,7 @@ } private String formatPrefix() { - if (nodeType == null) { + if (nodeType == valueType) { return String.format("new MatchPattern(%s, false", name != null ? ("\"" + name + "\"") : "null"); } else { return String.format("new MatchPattern(%s.class, %s", nodeType.nodeClass, name != null ? ("\"" + name + "\"") : "null"); @@ -291,15 +361,25 @@ } + /** + * Strip the package off a class name leaving the full class name including any outer classes. + */ + static String fullClassName(Element element) { + assert element.getKind() == ElementKind.CLASS || element.getKind() == ElementKind.INTERFACE : element; + String pkg = findPackage(element); + return ((TypeElement) element).getQualifiedName().toString().substring(pkg.length() + 1); + } + private void createFiles(MatchRuleDescriptor info) { String pkg = ((PackageElement) info.topDeclaringType.getEnclosingElement()).getQualifiedName().toString(); Name topDeclaringClass = info.topDeclaringType.getSimpleName(); - String optionsClassName = topDeclaringClass + "_" + MatchStatementSet.class.getSimpleName(); + String matchStatementClassName = topDeclaringClass + "_" + MatchStatementSet.class.getSimpleName(); Element[] originatingElements = info.originatingElements.toArray(new Element[info.originatingElements.size()]); + Types typeUtils = processingEnv.getTypeUtils(); Filer filer = processingEnv.getFiler(); - try (PrintWriter out = createSourceFile(pkg, optionsClassName, filer, originatingElements)) { + try (PrintWriter out = createSourceFile(pkg, matchStatementClassName, filer, originatingElements)) { out.println("// CheckStyle: stop header check"); out.println("// GENERATED CONTENT - DO NOT EDIT"); @@ -307,29 +387,56 @@ out.println("package " + pkg + ";"); out.println(""); out.println("import java.util.*;"); + out.println("import java.lang.reflect.*;"); out.println("import " + MatchStatementSet.class.getPackage().getName() + ".*;"); + out.println("import " + GraalInternalError.class.getName() + ";"); out.println("import " + NodeLIRBuilder.class.getName() + ";"); - for (String p : packages) { + for (String p : requiredPackages) { out.println("import " + p + ".*;"); } out.println(""); - out.println("public class " + optionsClassName + " implements " + MatchStatementSet.class.getSimpleName() + " {"); + out.println("public class " + matchStatementClassName + " implements " + MatchStatementSet.class.getSimpleName() + " {"); + + // Generate declarations for the reflective invocation of the code generation methods. + for (MethodInvokerItem invoker : invokers.values()) { + StringBuilder args = new StringBuilder(); + StringBuilder types = new StringBuilder(); + int count = invoker.fields.size(); + for (VariableElement arg : invoker.fields) { + args.append('"'); + args.append(arg.getSimpleName()); + args.append('"'); + types.append(fullClassName(typeUtils.asElement(arg.asType()))); + types.append(".class"); + if (count-- > 1) { + args.append(", "); + types.append(", "); + } + } + out.printf(" private static final String[] %s = new String[] {%s};\n", invoker.argumentsListName(), args); + out.printf(" private static final Method %s;\n", invoker.reflectiveMethodName()); + out.printf(" static {\n"); + out.printf(" Method result = null;\n"); + out.printf(" try {\n"); + out.printf(" result = %s.class.getDeclaredMethod(\"%s\", %s);\n", invoker.nodeLIRBuilderClass, invoker.methodName, types); + out.printf(" } catch (Exception e) {\n"); + out.printf(" throw new GraalInternalError(e);\n"); + out.printf(" }\n"); + out.printf(" %s = result;\n", invoker.reflectiveMethodName()); + out.printf(" }\n"); + + out.println(); + + } + String desc = MatchStatement.class.getSimpleName(); out.println(" // CheckStyle: stop line length check"); - out.println(" private static final List<" + desc + "> options = Collections.unmodifiableList(Arrays.asList("); + out.println(" private static final List<" + desc + "> statements = Collections.unmodifiableList(Arrays.asList("); int i = 0; - for (MatchRuleItem option : info.options) { - String optionValue; - if (option.field.getModifiers().contains(Modifier.PRIVATE)) { - optionValue = "field(" + option.declaringClass + ".class, \"" + option.field.getSimpleName() + "\")"; - } else { - optionValue = option.declaringClass + "." + option.field.getSimpleName(); - } - String name = option.name; - Name fieldName = option.field.getSimpleName(); - String comma = i == info.options.size() - 1 ? "" : ","; - out.printf(" new MatchStatement(\"%s\", %s, %s.class)%s\n", fieldName, name, optionValue, comma); + for (MatchRuleItem matchRule : info.matchRules) { + String comma = i == info.matchRules.size() - 1 ? "" : ","; + out.printf(" %s%s\n", matchRule.ruleBuilder(), comma); i++; } out.println(" ));"); @@ -342,13 +449,13 @@ out.println(); out.println(" @Override"); out.println(" public List<" + desc + "> statements() {"); - out.println(" return options;"); + out.println(" return statements;"); out.println(" }"); out.println("}"); } try { - createProviderFile(pkg, optionsClassName, originatingElements); + createProviderFile(pkg, matchStatementClassName, originatingElements); } catch (IOException e) { processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), info.topDeclaringType); } @@ -378,34 +485,57 @@ } } - static class MatchRuleItem implements Comparable { + /** + * Used to generate the MatchStatement constructor invocation. + */ + static class MatchRuleItem { + private final String matchPattern; + private final MethodInvokerItem invoker; - final String name; - final String declaringClass; - final TypeElement field; - - public MatchRuleItem(String name, String declaringClass, TypeElement field) { - this.name = name; - this.declaringClass = declaringClass; - this.field = field; + public MatchRuleItem(String matchPattern, MethodInvokerItem invoker) { + this.matchPattern = matchPattern; + this.invoker = invoker; } - @Override - public int compareTo(MatchRuleItem other) { - return name.compareTo(other.name); + /** + * @return a string which will construct the MatchStatement instance to match this pattern. + */ + public String ruleBuilder() { + return String.format("new MatchStatement(\"%s\", %s, %s, %s)", invoker.name, matchPattern, invoker.reflectiveMethodName(), invoker.argumentsListName()); + } + } + + /** + * Used to generate the declarations needed for reflective invocation of the code generation + * method. + */ + static class MethodInvokerItem { + final String name; + final String nodeLIRBuilderClass; + final String methodName; + final List fields; + + MethodInvokerItem(String name, String nodeLIRBuilderClass, String methodName, List fields) { + this.name = name; + this.nodeLIRBuilderClass = nodeLIRBuilderClass; + this.methodName = methodName; + this.fields = fields; } - @Override - public String toString() { - return declaringClass + "." + field; + String reflectiveMethodName() { + return methodName + "_invoke"; + } + + String argumentsListName() { + return methodName + "_arguments"; } } static class MatchRuleDescriptor { final TypeElement topDeclaringType; - final List options = new ArrayList<>(); - final Set originatingElements = new HashSet<>(); + final List matchRules = new ArrayList<>(); + private final Set originatingElements = new HashSet<>(); public MatchRuleDescriptor(TypeElement topDeclaringType) { this.topDeclaringType = topDeclaringType; @@ -428,6 +558,11 @@ } try { + // Define a TypeDescriptor the generic node but don't enter it into the nodeTypes table + // since it shouldn't mentioned in match rules. + TypeMirror mirror = processingEnv.getElementUtils().getTypeElement(ValueNode.class.getName()).asType(); + valueType = new TypeDescriptor(mirror, "Value", ValueNode.class.getSimpleName(), ValueNode.class.getPackage().getName(), 0, null, false); + // Import default definitions processMatchableNode(processingEnv.getElementUtils().getTypeElement(GraalMatchableNodes.class.getName())); for (Element element : roundEnv.getElementsAnnotatedWith(MatchableNodeImport.class)) { @@ -457,7 +592,7 @@ } } catch (Throwable t) { - processingEnv.getMessager().printMessage(Kind.ERROR, "Exception throw during processing: " + t); + processingEnv.getMessager().printMessage(Kind.ERROR, "Exception throw during processing: " + t.toString() + " " + Arrays.toString(Arrays.copyOf(t.getStackTrace(), 2))); } return true; @@ -468,107 +603,170 @@ */ private void processMatchableNode(Element element) { if (!processedMatchableNode.contains(element)) { - processedMatchableNode.add(element); - TypeElement topDeclaringType = topDeclaringType(element); - MatchableNode[] matchables = element.getAnnotationsByType(MatchableNode.class); - for (MatchableNode matchable : matchables) { - String nodeClass; - String nodePackage; - String shortName = matchable.shortName(); - TypeMirror nodeClassMirror = null; - try { - matchable.value(); - } catch (MirroredTypeException e) { - nodeClassMirror = e.getTypeMirror(); - } - if (nodeClassMirror == null) { - throw new GraalInternalError("Can't get mirror for node class %s", element); + try { + processedMatchableNode.add(element); + TypeElement topDeclaringType = topDeclaringType(element); + MatchableNode[] matchables = element.getAnnotationsByType(MatchableNode.class); + for (MatchableNode matchable : matchables) { + String nodeClass; + String nodePackage; + TypeMirror nodeClassMirror = null; + try { + matchable.nodeClass(); + } catch (MirroredTypeException e) { + nodeClassMirror = e.getTypeMirror(); + } + if (nodeClassMirror == null) { + throw new GraalInternalError("Can't get mirror for node class %s", element); + } + if (nodeClassMirror.toString().equals(MatchableNode.class.getName())) { + nodeClass = topDeclaringType.getQualifiedName().toString(); + } else { + nodeClass = nodeClassMirror.toString(); + } + nodePackage = findPackage(processingEnv.getElementUtils().getTypeElement(nodeClass)); + assert nodeClass.startsWith(nodePackage); + nodeClass = nodeClass.substring(nodePackage.length() + 1); + assert nodeClass.endsWith("Node"); + String shortName = nodeClass.substring(0, nodeClass.length() - 4); + + TypeMirror nodeAdapterMirror = null; + try { + matchable.adapter(); + } catch (MirroredTypeException e) { + nodeAdapterMirror = e.getTypeMirror(); + } + if (nodeAdapterMirror == null) { + throw new GraalInternalError("Can't get mirror for adapter %s", element); + } + String nodeAdapter = null; + if (!nodeAdapterMirror.toString().equals(MatchableNode.class.getName())) { + nodeAdapter = String.format("new %s()", nodeAdapterMirror.toString()); + } + + declareType(nodeClassMirror, shortName, nodeClass, nodePackage, matchable.inputs(), nodeAdapter, matchable.commutative(), element); } - if (nodeClassMirror.toString().equals(MatchableNode.class.getName())) { - nodeClass = topDeclaringType.getQualifiedName().toString(); - } else { - nodeClass = nodeClassMirror.toString(); - } - nodePackage = findPackage(processingEnv.getElementUtils().getTypeElement(nodeClass)); - assert nodeClass.startsWith(nodePackage); - nodeClass = nodeClass.substring(nodePackage.length() + 1); - - TypeMirror nodeAdapterMirror = null; - try { - matchable.adapter(); - } catch (MirroredTypeException e) { - nodeAdapterMirror = e.getTypeMirror(); - } - if (nodeAdapterMirror == null) { - throw new GraalInternalError("Can't get mirror for adapter %s", element); - } - String nodeAdapter = null; - if (!nodeAdapterMirror.toString().equals(MatchableNode.class.getName())) { - nodeAdapter = String.format("new %s()", nodeAdapterMirror.toString()); - } - - declareType(shortName, nodeClass, nodePackage, matchable.inputs(), nodeAdapter, matchable.commutative()); + } catch (Throwable t) { + reportExceptionThrow(element, t); } } } + private void reportExceptionThrow(Element element, Throwable t) { + processingEnv.getMessager().printMessage(Kind.ERROR, "Exception throw during processing: " + t.toString() + " " + Arrays.toString(Arrays.copyOf(t.getStackTrace(), 2)), element); + } + private void processMatchRule(Map map, Element element) { if (!processedMatchRule.contains(element)) { - processedMatchRule.add(element); - TypeElement topDeclaringType = topDeclaringType(element); - MatchRuleDescriptor options = map.get(topDeclaringType); - if (options == null) { - options = new MatchRuleDescriptor(topDeclaringType); - map.put(topDeclaringType, options); - } - MatchRule[] matchRules = element.getAnnotationsByType(MatchRule.class); - for (MatchRule matchRule : matchRules) { - processMatchRule(element, options, matchRule); + try { + processedMatchRule.add(element); + + // The annotation element type should ensure this is true. + assert element instanceof ExecutableElement; + + TypeElement topDeclaringType = topDeclaringType(element); + MatchRuleDescriptor info = map.get(topDeclaringType); + if (info == null) { + info = new MatchRuleDescriptor(topDeclaringType); + map.put(topDeclaringType, info); + } + for (MatchRule matchRule : element.getAnnotationsByType(MatchRule.class)) { + System.err.println(matchRule); + processMethodMatchRule((ExecutableElement) element, info, matchRule); + } + } catch (Throwable t) { + reportExceptionThrow(element, t); } } } - private void processMatchRule(Element element, MatchRuleDescriptor info, MatchRule matchRule) { - assert element instanceof TypeElement; - assert element.getKind() == ElementKind.CLASS; - TypeElement field = (TypeElement) element; + private void processMethodMatchRule(ExecutableElement method, MatchRuleDescriptor info, MatchRule matchRule) { + Types typeUtils = processingEnv.getTypeUtils(); - TypeMirror fieldType = field.asType(); - if (fieldType.getKind() != TypeKind.DECLARED) { - processingEnv.getMessager().printMessage(Kind.ERROR, "Option field must be of type " + MatchRule.class.getName(), element); + if (!method.getModifiers().contains(Modifier.PUBLIC)) { + String msg = String.format("MatchRule method %s must be public", method.getSimpleName()); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, method); + return; + } + if (method.getModifiers().contains(Modifier.STATIC)) { + String msg = String.format("MatchRule method %s must be non-static", method.getSimpleName()); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, method); return; } - Element enclosing = element.getEnclosingElement(); - String declaringClass = ""; - String separator = ""; - Set originatingElementsList = info.originatingElements; - originatingElementsList.add(field); - while (enclosing != null) { - if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) { - if (enclosing.getModifiers().contains(Modifier.PRIVATE)) { - String msg = String.format("Option field cannot be declared in a private %s %s", enclosing.getKind().name().toLowerCase(), enclosing); - processingEnv.getMessager().printMessage(Kind.ERROR, msg, element); + try { + TypeMirror returnType = method.getReturnType(); + if (!typeUtils.isSameType(returnType, processingEnv.getElementUtils().getTypeElement(ComplexMatchResult.class.getName()).asType())) { + String msg = String.format("MatchRule method return type must be %s", ComplexMatchResult.class.getName()); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, method); + return; + } + + String rule = matchRule.value(); + RuleParser parser = new RuleParser(rule); + ArrayList expectedTypes = parser.capturedTypes(); + ArrayList expectedNames = parser.capturedNames(); + List actualParameters = method.getParameters(); + if (expectedTypes.size() + 1 < actualParameters.size()) { + String msg = String.format("Too many arguments for match method %s %s", expectedTypes.size() + 1, actualParameters.size()); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, method); + return; + } + + // Walk through the parameters to the method and see if they exist in the match rule. + // The order doesn't matter but only names mentioned in the rule can be used and they + // must be assignment compatible. + for (VariableElement parameter : actualParameters) { + String name = parameter.getSimpleName().toString(); + int nameIndex = expectedNames.indexOf(name); + if (nameIndex == -1) { + String msg = String.format("Argument \"%s\" isn't captured in the match rule", name); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, method); + return; + } + TypeMirror type = parameter.asType(); + if (!typeUtils.isAssignable(expectedTypes.get(nameIndex).mirror, type)) { + String msg = String.format("Captured value \"%s\" of type %s is not assignable to argument of type %s", name, expectedTypes.get(nameIndex).mirror, type); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, method); return; } - originatingElementsList.add(enclosing); - declaringClass = enclosing.getSimpleName() + separator + declaringClass; - separator = "."; - } else { - assert enclosing.getKind() == ElementKind.PACKAGE; + } + + MethodInvokerItem invoker = invokers.get(method); + if (invoker == null) { + invoker = new MethodInvokerItem(method.getSimpleName().toString(), topDeclaringType(method).getSimpleName().toString(), method.getSimpleName().toString(), actualParameters); + invokers.put(method, invoker); } - enclosing = enclosing.getEnclosingElement(); - } - String rule = matchRule.value(); - try { - ArrayList matches = new RuleParser(rule).generateVariants(); + Element enclosing = method.getEnclosingElement(); + String declaringClass = ""; + String separator = ""; + Set originatingElementsList = info.originatingElements; + originatingElementsList.add(method); + while (enclosing != null) { + if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) { + if (enclosing.getModifiers().contains(Modifier.PRIVATE)) { + String msg = String.format("MatchRule cannot be declared in a private %s %s", enclosing.getKind().name().toLowerCase(), enclosing); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, method); + return; + } + originatingElementsList.add(enclosing); + declaringClass = enclosing.getSimpleName() + separator + declaringClass; + separator = "."; + } else { + assert enclosing.getKind() == ElementKind.PACKAGE; + } + enclosing = enclosing.getEnclosingElement(); + } + + originatingElementsList.addAll(parser.originatingElements); + + List matches = parser.generateVariants(); for (String match : matches) { - info.options.add(new MatchRuleItem(match, declaringClass, field)); + info.matchRules.add(new MatchRuleItem(match, invoker)); } } catch (RuleParseError e) { - processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), element); + processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), method); } } - } diff -r 625f779255a7 -r 100306ae985b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRule.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRule.java Wed Apr 30 11:27:59 2014 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRule.java Wed Apr 30 12:27:27 2014 -0700 @@ -43,7 +43,7 @@ */ @Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) +@Target(ElementType.METHOD) @Repeatable(value = MatchRules.class) public @interface MatchRule { String value(); diff -r 625f779255a7 -r 100306ae985b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java Wed Apr 30 11:27:59 2014 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java Wed Apr 30 12:27:27 2014 -0700 @@ -22,9 +22,15 @@ */ package com.oracle.graal.compiler.match; +import static com.oracle.graal.compiler.GraalDebugConfig.*; + import java.util.*; +import java.util.Map.Entry; +import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.*; import com.oracle.graal.nodes.*; public class MatchRuleRegistry { @@ -69,6 +75,18 @@ registry.put(theClass, rules); assert registry.get(theClass) == rules; result = rules; + + if (LogVerbose.getValue()) { + try (Scope s = Debug.scope("MatchComplexExpressions")) { + Debug.log("Match rules for %s", theClass.getSimpleName()); + for (Entry, List> entry : result.entrySet()) { + Debug.log(" For node class: %s", entry.getKey()); + for (MatchStatement statement : entry.getValue()) { + Debug.log(" %s", statement.getPattern()); + } + } + } + } } if (result.size() == 0) { diff -r 625f779255a7 -r 100306ae985b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRules.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRules.java Wed Apr 30 11:27:59 2014 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRules.java Wed Apr 30 12:27:27 2014 -0700 @@ -28,7 +28,7 @@ * The repeatable representation of {@link MatchRule}. Should never be used directly. */ @Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) +@Target(ElementType.METHOD) public @interface MatchRules { MatchRule[] value(); } diff -r 625f779255a7 -r 100306ae985b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java Wed Apr 30 11:27:59 2014 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java Wed Apr 30 12:27:27 2014 -0700 @@ -22,12 +22,20 @@ */ package com.oracle.graal.compiler.match; +import static com.oracle.graal.compiler.GraalDebugConfig.*; + +import java.lang.reflect.*; import java.util.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.match.MatchPattern.MatchResultCode; import com.oracle.graal.compiler.match.MatchPattern.Result; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node.Verbosity; import com.oracle.graal.nodes.*; /** @@ -36,20 +44,34 @@ */ public class MatchStatement { + private static final DebugMetric MatchStatementSuccess = Debug.metric("MatchStatementSuccess"); + + /** + * A printable name for this statement. Usually it's just the name of the method doing the + * emission. + */ private final String name; + + /** + * The actual match pattern. + */ private final MatchPattern pattern; - private final Class generatorClass; + + /** + * The method in the {@link NodeLIRBuilder} subclass that will actually do the code emission. + */ + private Method generatorMethod; - public MatchStatement(String name, MatchPattern pattern) { + /** + * The name of arguments in the order they are expected to be passed to the generator method. + */ + private String[] arguments; + + public MatchStatement(String name, MatchPattern pattern, Method generator, String[] arguments) { this.name = name; this.pattern = pattern; - this.generatorClass = null; - } - - public MatchStatement(String name, MatchPattern pattern, Class generator) { - this.name = name; - this.pattern = pattern; - this.generatorClass = generator; + this.generatorMethod = generator; + this.arguments = arguments; } /** @@ -61,37 +83,56 @@ * @return true if the statement matched something and set a {@link ComplexMatchResult} to be * evaluated by the NodeLIRBuilder. */ - public boolean generate(NodeLIRBuilder builder, ValueNode node, List nodes) { - MatchContext context = new MatchContext(builder, this, node, nodes); - Result result = pattern.match(node, context); - if (result == Result.OK) { - result = context.validate(); + public boolean generate(NodeLIRBuilder builder, int index, ValueNode node, List nodes) { + assert index == nodes.indexOf(node); + // Check that the basic shape matches + Result result = pattern.matchShape(node, this); + if (result != Result.OK) { + return false; } + // Now ensure that the other safety constraints are matched. + MatchContext context = new MatchContext(builder, this, index, node, nodes); + result = pattern.matchUsage(node, context); if (result == Result.OK) { - MatchGenerator generator = null; try { - generator = generatorClass.newInstance(); - // Transfer values into gen - context.transferState(generator); - ComplexMatchResult value = generator.match(builder); + // Invoke the generator method and set the result if it's non null. + ComplexMatchResult value = (ComplexMatchResult) generatorMethod.invoke(builder, buildArgList(context)); if (value != null) { context.setResult(value); + MatchStatementSuccess.increment(); return true; } - } catch (InstantiationException | IllegalAccessException e) { + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { throw new GraalInternalError(e); } } else { - // This is fairly verbose for normal usage. - // if (result.code != MatchResultCode.WRONG_CLASS) { - // // Don't bother logging if it's just the wrong shape. - // Debug.log("while matching %s|%s %s %s %s", context.getRoot().toString(Verbosity.Id), - // context.getRoot().getClass().getSimpleName(), getName(), result, node.graph()); - // } + if (LogVerbose.getValue() && result.code != MatchResultCode.WRONG_CLASS) { + Debug.log("while matching %s|%s %s %s", context.getRoot().toString(Verbosity.Id), context.getRoot().getClass().getSimpleName(), getName(), result); + } } return false; } + /** + * @param context + * @return the ValueNodes captured by the match rule in the order expected by the + * generatorMethod + */ + private Object[] buildArgList(MatchContext context) { + Object[] result = new Object[arguments.length]; + for (int i = 0; i < arguments.length; i++) { + if ("root".equals(arguments[i])) { + result[i] = context.getRoot(); + } else { + result[i] = context.namedNode(arguments[i]); + if (result[i] == null) { + throw new GraalGraphInternalError("Can't find named node %s", arguments[i]); + } + } + } + return result; + } + public String formatMatch(ValueNode root) { return pattern.formatMatch(root); } diff -r 625f779255a7 -r 100306ae985b graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNode.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNode.java Wed Apr 30 11:27:59 2014 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNode.java Wed Apr 30 12:27:27 2014 -0700 @@ -27,7 +27,7 @@ import com.oracle.graal.nodes.*; /** - * Describes the properties of a node for use when building a {@link MatchPattern}s. + * Describes the properties of a node for use when building a {@link MatchPattern}. */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @@ -39,13 +39,7 @@ * if they were directly on the node being described but that may complicate the annotation * processing. */ - Class value(); - - /** - * The name used in match patterns. Defaults to class.getSimpleName() with the word Node removed - * from the end. - */ - String shortName() default ""; + Class nodeClass(); /** * The number of matchable inputs, which may be less than the real number of inputs. diff -r 625f779255a7 -r 100306ae985b graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java Wed Apr 30 11:27:59 2014 -0700 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java Wed Apr 30 12:27:27 2014 -0700 @@ -244,39 +244,17 @@ setResult(x, result); } - /** - * Helper class to convert the NodeLIRBuilder into the current subclass. - */ - static abstract class AMD64HotSpotMatchGenerator implements MatchGenerator { - public AMD64HotSpotMatchGenerator() { - } - - public ComplexMatchResult match(NodeLIRBuilder gen) { - return match((AMD64HotSpotNodeLIRBuilder) gen); - } - - abstract public ComplexMatchResult match(AMD64HotSpotNodeLIRBuilder gen); - } - @MatchRule("(If (ObjectEquals=compare Constant=value (Compression Read=access)))") @MatchRule("(If (ObjectEquals=compare Constant=value (Compression FloatingRead=access)))") @MatchRule("(If (ObjectEquals=compare (Compression value) (Compression Read=access)))") @MatchRule("(If (ObjectEquals=compare (Compression value) (Compression FloatingRead=access)))") - public static class IfCompareMemory extends AMD64HotSpotMatchGenerator { - IfNode root; - Access access; - ValueNode value; - CompareNode compare; - - @Override - public ComplexMatchResult match(AMD64HotSpotNodeLIRBuilder gen) { - if (HotSpotGraalRuntime.runtime().getConfig().useCompressedOops) { - return builder -> { - gen.emitCompareCompressedMemory(root, value, access, compare); - return null; - }; - } - return null; + public ComplexMatchResult ifCompareCompressedMemory(IfNode root, CompareNode compare, ValueNode value, Access access) { + if (HotSpotGraalRuntime.runtime().getConfig().useCompressedOops) { + return builder -> { + emitCompareCompressedMemory(root, value, access, compare); + return null; + }; } + return null; } } diff -r 625f779255a7 -r 100306ae985b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotMatchableNodes.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotMatchableNodes.java Wed Apr 30 11:27:59 2014 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotMatchableNodes.java Wed Apr 30 12:27:27 2014 -0700 @@ -25,7 +25,7 @@ import com.oracle.graal.compiler.match.*; import com.oracle.graal.nodes.*; -@MatchableNode(shortName = "Compression", value = CompressionNode.class, inputs = 1, adapter = HotSpotMatchableNodes.CompressionNodeAdapter.class) +@MatchableNode(nodeClass = CompressionNode.class, inputs = 1, adapter = HotSpotMatchableNodes.CompressionNodeAdapter.class) public class HotSpotMatchableNodes { public static class CompressionNodeAdapter extends MatchNodeAdapter { @Override diff -r 625f779255a7 -r 100306ae985b graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java Wed Apr 30 11:27:59 2014 -0700 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java Wed Apr 30 12:27:27 2014 -0700 @@ -497,7 +497,7 @@ break; case IROR: assert asIntReg(src).equals(AMD64.rcx); - masm.roll(asIntReg(dst)); + masm.rorl(asIntReg(dst)); break; case LADD: