changeset 15453:100306ae985b

switch MatchRule from class to method annotation and fix review feedback
author Tom Rodriguez <tom.rodriguez@oracle.com>
date Wed, 30 Apr 2014 12:27:27 -0700
parents 625f779255a7
children 0e0c24424d14
files graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Value.java graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchResult.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/ComplexMatchValue.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/GraalMatchableNodes.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchContext.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRule.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRules.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNode.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotMatchableNodes.java graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java
diffstat 18 files changed, 720 insertions(+), 530 deletions(-) [+]
line wrap: on
line diff
--- 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;
 
--- 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
--- 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<Boolean> 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) {
--- 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<MatchStatement> 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;
                             }
--- 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);
--- 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;
 
--- 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
--- 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<ValueNode> consumed = new ArrayList<>();
-    private final List<ScheduledNode> nodes;
+
     private final ValueNode root;
-    private List<String> names;
-    private List<Class<? extends ValueNode>> types;
-    private List<ValueNode> values;
+
+    private final List<ScheduledNode> nodes;
+
     private final MatchStatement rule;
+
+    private Map<String, NamedNode> namedNodes;
+
+    private ArrayList<ValueNode> consumed;
+
     private int startIndex;
+
     private int endIndex;
+
     private final NodeLIRBuilder builder;
 
-    public MatchContext(NodeLIRBuilder builder, MatchStatement rule, ValueNode node, List<ScheduledNode> nodes) {
+    private static class NamedNode {
+        final Class<? extends ValueNode> type;
+        final ValueNode value;
+
+        NamedNode(Class<? extends ValueNode> type, ValueNode value) {
+            this.type = type;
+            this.value = value;
+        }
+    }
+
+    public MatchContext(NodeLIRBuilder builder, MatchStatement rule, int index, ValueNode node, List<ScheduledNode> 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<? extends ValueNode> 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<ScheduledNode> 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()) : "");
     }
 }
--- 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;
         }
     }
 }
--- 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<TypeDescriptor> capturedTypes = new ArrayList<>();
+
+        private ArrayList<String> capturedNames = new ArrayList<>();
+
+        private final String[] tokens;
+
+        private int current;
+
+        private MatchDescriptor matchDescriptor;
+
+        private final Set<Element> 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<String> generateVariants() {
-            MatchDescriptor descriptor = parseSexp();
-            if (!done()) {
-                throw new RuleParseError("didn't consume all tokens");
-            }
-            return descriptor.generateVariants();
+        List<String> generateVariants() {
+            return matchDescriptor.generateVariants();
+        }
+
+        /**
+         *
+         * @return the list of node types which are captured by name
+         */
+        public ArrayList<TypeDescriptor> capturedTypes() {
+            return capturedTypes;
+        }
+
+        public ArrayList<String> 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<Element> 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<String, TypeDescriptor> types = new HashMap<>();
-    ArrayList<String> packages = new ArrayList<>();
+    /**
+     * The types which are know for purpose of parsing MatchRule expressions.
+     */
+    Map<String, TypeDescriptor> knownTypes = new HashMap<>();
+
+    /**
+     * The set of packages which must be imported to refer to the known classes.
+     */
+    List<String> 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<ExecutableElement, MethodInvokerItem> 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<String> 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<String> generateVariants() {
             String prefix = formatPrefix();
             String suffix = formatSuffix();
             ArrayList<String> 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<MatchRuleItem> {
+    /**
+     * 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<? extends VariableElement> fields;
+
+        MethodInvokerItem(String name, String nodeLIRBuilderClass, String methodName, List<? extends VariableElement> 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<MatchRuleItem> options = new ArrayList<>();
-        final Set<Element> originatingElements = new HashSet<>();
+        final List<MatchRuleItem> matchRules = new ArrayList<>();
+        private final Set<Element> 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<TypeElement, MatchRuleDescriptor> 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<Element> 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<TypeDescriptor> expectedTypes = parser.capturedTypes();
+            ArrayList<String> expectedNames = parser.capturedNames();
+            List<? extends VariableElement> 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<String> matches = new RuleParser(rule).generateVariants();
+            Element enclosing = method.getEnclosingElement();
+            String declaringClass = "";
+            String separator = "";
+            Set<Element> 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<String> 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);
         }
     }
-
 }
--- 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();
--- 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<Class<? extends ValueNode>, List<MatchStatement>> 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) {
--- 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();
 }
--- 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<? extends MatchGenerator> 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<? extends MatchGenerator> 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<ScheduledNode> 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<ScheduledNode> 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);
     }
--- 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<? extends ValueNode> value();
-
-    /**
-     * The name used in match patterns. Defaults to class.getSimpleName() with the word Node removed
-     * from the end.
-     */
-    String shortName() default "";
+    Class<? extends ValueNode> nodeClass();
 
     /**
      * The number of matchable inputs, which may be less than the real number of inputs.
--- 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;
     }
 }
--- 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
--- 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: