changeset 15547:cab432461b8b

use NodeClass.Position when matching graphs, rearrange MatchableNode annotations, improve error reporting
author Tom Rodriguez <tom.rodriguez@oracle.com>
date Wed, 07 May 2014 10:58:26 -0700
parents 240083895914
children 23dbc25b10a8
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.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/MatchNodeAdapter.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/MatchStatement.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatementSet.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNode.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNodeImport.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNodes.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/HotSpotNodeLIRBuilder.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotMatchableNodes.java
diffstat 13 files changed, 315 insertions(+), 434 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Wed May 07 15:31:04 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Wed May 07 10:58:26 2014 -0700
@@ -56,6 +56,36 @@
 /**
  * This class traverses the HIR instructions and generates LIR instructions from them.
  */
+@MatchableNode(nodeClass = ConstantNode.class, shareable = true)
+@MatchableNode(nodeClass = FloatConvertNode.class, inputs = {"input"})
+@MatchableNode(nodeClass = FloatSubNode.class, inputs = {"x", "y"})
+@MatchableNode(nodeClass = FloatingReadNode.class, inputs = {"object", "location"})
+@MatchableNode(nodeClass = IfNode.class, inputs = {"condition"})
+@MatchableNode(nodeClass = IntegerSubNode.class, inputs = {"x", "y"})
+@MatchableNode(nodeClass = LeftShiftNode.class, inputs = {"x", "y"})
+@MatchableNode(nodeClass = NarrowNode.class, inputs = {"input"})
+@MatchableNode(nodeClass = ReadNode.class, inputs = {"object", "location"})
+@MatchableNode(nodeClass = ReinterpretNode.class, inputs = {"value"})
+@MatchableNode(nodeClass = SignExtendNode.class, inputs = {"input"})
+@MatchableNode(nodeClass = UnsignedRightShiftNode.class, inputs = {"x", "y"})
+@MatchableNode(nodeClass = WriteNode.class, inputs = {"object", "location", "value"})
+@MatchableNode(nodeClass = ZeroExtendNode.class, inputs = {"input"})
+@MatchableNode(nodeClass = AndNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = FloatAddNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = FloatEqualsNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = FloatLessThanNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = FloatMulNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = IntegerAddNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = IntegerBelowThanNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = IntegerEqualsNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = IntegerLessThanNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = IntegerMulNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = IntegerTestNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = ObjectEqualsNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = OrNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = XorNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = PiNode.class, inputs = {"object"})
+@MatchableNode(nodeClass = ConstantLocationNode.class, shareable = true)
 public abstract class NodeLIRBuilder implements NodeLIRBuilderTool {
 
     private final NodeMap<Value> nodeOperands;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/GraalMatchableNodes.java	Wed May 07 15:31:04 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,160 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.compiler.match;
-
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
-
-/**
- * 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(nodeClass = ConstantNode.class, inputs = 0, shareable = true)
-@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 = 2, adapter = GraalMatchableNodes.AccessAdapter.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 = 2, adapter = GraalMatchableNodes.AccessAdapter.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 = 3, 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)
-@MatchableNode(nodeClass = PiNode.class, inputs = 1, adapter = GraalMatchableNodes.PiNodeAdapter.class)
-@MatchableNode(nodeClass = ConstantLocationNode.class, shareable = true)
-public class GraalMatchableNodes {
-    public static class PiNodeAdapter extends MatchNodeAdapter {
-        @Override
-        public ValueNode getInput(int input, ValueNode node) {
-            if (input == 0) {
-                return ((PiNode) node).object();
-            }
-            throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    public static class BinaryNodeAdapter extends MatchNodeAdapter {
-        @Override
-        public ValueNode getInput(int input, ValueNode node) {
-            if (input == 0) {
-                return ((BinaryNode) node).x();
-            }
-            if (input == 1) {
-                return ((BinaryNode) node).y();
-            }
-            throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    public static class WriteNodeAdapter extends MatchNodeAdapter {
-        @Override
-        public ValueNode getInput(int input, ValueNode node) {
-            if (input == 0) {
-                return ((WriteNode) node).object();
-            }
-            if (input == 1) {
-                return ((WriteNode) node).location();
-            }
-            if (input == 2) {
-                return ((WriteNode) node).value();
-            }
-            throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    public static class ConvertNodeAdapter extends MatchNodeAdapter {
-        @Override
-        public ValueNode getInput(int input, ValueNode node) {
-            if (input == 0) {
-                return ((ConvertNode) node).getInput();
-            }
-            throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    public static class ReinterpretNodeAdapter extends MatchNodeAdapter {
-        @Override
-        public ValueNode getInput(int input, ValueNode node) {
-            if (input == 0) {
-                return ((ReinterpretNode) node).value();
-            }
-            throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    public static class IfNodeAdapter extends MatchNodeAdapter {
-        @Override
-        public ValueNode getInput(int input, ValueNode node) {
-            if (input == 0) {
-                return ((IfNode) node).condition();
-            }
-            throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    public static class AccessAdapter extends MatchNodeAdapter {
-
-        @Override
-        public ValueNode getInput(int input, ValueNode node) {
-            if (input == 0) {
-                return ((Access) node).object();
-            }
-            if (input == 1) {
-                return ((Access) node).accessLocation();
-            }
-            throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    public static class BinaryOpLogicNodeAdapter extends MatchNodeAdapter {
-        @Override
-        public ValueNode getInput(int input, ValueNode node) {
-            if (input == 0) {
-                return ((BinaryOpLogicNode) node).x();
-            }
-            if (input == 1) {
-                return ((BinaryOpLogicNode) node).y();
-            }
-            throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchNodeAdapter.java	Wed May 07 15:31:04 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.compiler.match;
-
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.nodes.*;
-
-/**
- * Helper class to visit the matchable inputs of a node in a specified order. This may not be needed
- * in the end since this could probably be done using the inputs iterator but it simplifies things
- * for the moment.
- */
-public class MatchNodeAdapter {
-    @SuppressWarnings("unused")
-    public ValueNode getInput(int input, ValueNode node) {
-        throw GraalInternalError.shouldNotReachHere();
-    }
-}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java	Wed May 07 15:31:04 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java	Wed May 07 10:58:26 2014 -0700
@@ -22,8 +22,10 @@
  */
 package com.oracle.graal.compiler.match;
 
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.Node.Verbosity;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 
 /**
@@ -124,11 +126,9 @@
     private final MatchPattern[] patterns;
 
     /**
-     * Helper class to visit the inputs.
+     * The inputs to match the patterns against.
      */
-    private final MatchNodeAdapter adapter;
-
-    private static final MatchPattern[] EMPTY_PATTERNS = new MatchPattern[0];
+    private final NodeClass.Position[] inputs;
 
     /**
      * Can there only be one user of the node. Constant nodes can be matched even if there are other
@@ -136,6 +136,8 @@
      */
     private final boolean singleUser;
 
+    private static final MatchPattern[] EMPTY_PATTERNS = new MatchPattern[0];
+
     public MatchPattern(String name, boolean singleUser) {
         this(null, name, singleUser);
     }
@@ -145,37 +147,28 @@
         this.name = name;
         this.singleUser = singleUser;
         this.patterns = EMPTY_PATTERNS;
-        this.adapter = null;
+        this.inputs = null;
     }
 
-    public MatchPattern(Class<? extends ValueNode> nodeClass, String name, MatchPattern first, MatchNodeAdapter adapter, boolean singleUser) {
-        this.nodeClass = nodeClass;
-        this.name = name;
-        this.singleUser = singleUser;
-        this.patterns = new MatchPattern[1];
-        patterns[0] = first;
-        this.adapter = adapter;
-    }
-
-    public MatchPattern(Class<? extends ValueNode> nodeClass, String name, MatchPattern first, MatchPattern second, MatchNodeAdapter adapter, boolean singleUser) {
+    private MatchPattern(Class<? extends ValueNode> nodeClass, String name, boolean singleUser, MatchPattern[] patterns, NodeClass.Position[] inputs) {
+        assert inputs == null || inputs.length == patterns.length;
         this.nodeClass = nodeClass;
         this.name = name;
         this.singleUser = singleUser;
-        this.patterns = new MatchPattern[2];
-        patterns[0] = first;
-        patterns[1] = second;
-        this.adapter = adapter;
+        this.patterns = patterns;
+        this.inputs = inputs;
     }
 
-    public MatchPattern(Class<? extends ValueNode> nodeClass, String name, MatchPattern first, MatchPattern second, MatchPattern third, MatchNodeAdapter adapter, boolean singleUser) {
-        this.nodeClass = nodeClass;
-        this.name = name;
-        this.singleUser = singleUser;
-        this.patterns = new MatchPattern[3];
-        patterns[0] = first;
-        patterns[1] = second;
-        patterns[2] = third;
-        this.adapter = adapter;
+    public MatchPattern(Class<? extends ValueNode> nodeClass, String name, MatchPattern first, NodeClass.Position[] inputs, boolean singleUser) {
+        this(nodeClass, name, singleUser, new MatchPattern[]{first}, inputs);
+    }
+
+    public MatchPattern(Class<? extends ValueNode> nodeClass, String name, MatchPattern first, MatchPattern second, NodeClass.Position[] inputs, boolean singleUser) {
+        this(nodeClass, name, singleUser, new MatchPattern[]{first, second}, inputs);
+    }
+
+    public MatchPattern(Class<? extends ValueNode> nodeClass, String name, MatchPattern first, MatchPattern second, MatchPattern third, NodeClass.Position[] inputs, boolean singleUser) {
+        this(nodeClass, name, singleUser, new MatchPattern[]{first, second, third}, inputs);
     }
 
     Class<? extends ValueNode> nodeClass() {
@@ -204,6 +197,36 @@
         return result;
     }
 
+    /**
+     * Convert a list of field names into {@link com.oracle.graal.graph.NodeClass.Position} objects
+     * that can be used to read them during a match. The names should already have been confirmed to
+     * exist in the type.
+     *
+     * @param theClass
+     * @param names
+     * @return an array of Position objects corresponding to the named fields.
+     */
+    public static NodeClass.Position[] findPositions(Class<? extends ValueNode> theClass, String[] names) {
+        NodeClass.Position[] result = new NodeClass.Position[names.length];
+        NodeClass nodeClass = NodeClass.get(theClass);
+        for (int i = 0; i < names.length; i++) {
+            for (NodeClass.Position position : nodeClass.getFirstLevelInputPositions()) {
+                String name = nodeClass.getName(position);
+                if (name.endsWith("#NDF")) {
+                    name = name.substring(0, name.length() - 4);
+                }
+                if (name.equals(names[i])) {
+                    result[i] = position;
+                    break;
+                }
+            }
+            if (result[i] == null) {
+                throw new GraalInternalError("unknown field \"%s\" in class %s", names[i], theClass);
+            }
+        }
+        return result;
+    }
+
     private Result matchUsage(ValueNode node, MatchContext context, boolean atRoot) {
         Result result = matchType(node);
         if (result != Result.OK) {
@@ -221,7 +244,7 @@
         }
 
         for (int input = 0; input < patterns.length; input++) {
-            result = patterns[input].matchUsage(adapter.getInput(input, node), context, false);
+            result = patterns[input].matchUsage(getInput(input, node), context, false);
             if (result != Result.OK) {
                 return result;
             }
@@ -255,7 +278,7 @@
         }
 
         for (int input = 0; input < patterns.length; input++) {
-            result = patterns[input].matchShape(adapter.getInput(input, node), statement, false);
+            result = patterns[input].matchShape(getInput(input, node), statement, false);
             if (result != Result.OK) {
                 return result;
             }
@@ -279,13 +302,17 @@
             sb.append(result);
             for (int input = 0; input < patterns.length; input++) {
                 sb.append(" ");
-                sb.append(patterns[input].formatMatch(adapter.getInput(input, root)));
+                sb.append(patterns[input].formatMatch(getInput(input, root)));
             }
             sb.append(")");
             return sb.toString();
         }
     }
 
+    private ValueNode getInput(int index, ValueNode node) {
+        return (ValueNode) inputs[index].get(node);
+    }
+
     @Override
     public String toString() {
         if (nodeClass == null) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java	Wed May 07 15:31:04 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java	Wed May 07 10:58:26 2014 -0700
@@ -50,7 +50,8 @@
  *     }
  * </pre>
  */
-@SupportedAnnotationTypes({"com.oracle.graal.compiler.match.MatchRule", "com.oracle.graal.compiler.match.MatchRules", "com.oracle.graal.compiler.match.MatchableNode"})
+@SupportedAnnotationTypes({"com.oracle.graal.compiler.match.MatchRule", "com.oracle.graal.compiler.match.MatchRules", "com.oracle.graal.compiler.match.MatchableNode",
+                "com.oracle.graal.compiler.match.MatchableNodes"})
 public class MatchProcessor extends AbstractProcessor {
 
     public MatchProcessor() {
@@ -72,6 +73,8 @@
         }
     }
 
+    private static Pattern tokenizer = Pattern.compile("\\s*([()=]|[A-Za-z][A-Za-z0-9]*)\\s*");
+
     private class RuleParser {
         private ArrayList<TypeDescriptor> capturedTypes = new ArrayList<>();
 
@@ -95,7 +98,7 @@
                 m.region(m.end(), m.regionEnd());
             }
             if (end != m.regionEnd()) {
-                throw new RuleParseError("Unnexpected tokens :" + rule.substring(m.end(), m.regionEnd()));
+                throw new RuleParseError("Unexpected tokens :" + rule.substring(m.end(), m.regionEnd()));
             }
             tokens = list.toArray(new String[0]);
 
@@ -129,14 +132,14 @@
             if (peek("(").equals("(")) {
                 next();
                 MatchDescriptor descriptor = parseType(true);
-                for (int n = 0; n < descriptor.nodeType.inputs; n++) {
+                for (int n = 0; n < descriptor.nodeType.inputs.length; n++) {
                     if (peek("(").equals("(")) {
                         descriptor.inputs[n] = parseExpression();
                     } else {
                         descriptor.inputs[n] = parseType(false);
                     }
                 }
-                for (int n = 0; n < descriptor.nodeType.inputs; n++) {
+                for (int n = 0; n < descriptor.nodeType.inputs.length; n++) {
                     if (descriptor.inputs[n] == null) {
                         throw new RuleParseError("not enough inputs for " + descriptor.name);
                     }
@@ -201,7 +204,63 @@
         }
     }
 
-    static Pattern tokenizer = Pattern.compile("\\s*([()=]|[A-Za-z][A-Za-z0-9]*)\\s*");
+    /**
+     * Set to true to enable logging to a local file during annotation processing. There's no normal
+     * channel for any debug messages and debugging annotation processors requires some special
+     * setup.
+     */
+    private static final boolean DEBUG = false;
+
+    private static final String MATCHPROCESSOR_LOG = "/tmp/matchprocessor.log";
+
+    private static PrintWriter log;
+
+    /**
+     * Logging facility for the debugging the annotation processor.
+     */
+
+    private static synchronized PrintWriter getLog() {
+        if (log == null) {
+            try {
+                log = new PrintWriter(new FileWriter(MATCHPROCESSOR_LOG, true));
+            } catch (IOException e) {
+                // Do nothing
+            }
+        }
+        return log;
+    }
+
+    private static synchronized void logMessage(String format, Object... args) {
+        if (!DEBUG) {
+            return;
+        }
+        PrintWriter bw = getLog();
+        if (bw != null) {
+            bw.printf(format, args);
+            bw.flush();
+        }
+    }
+
+    private static synchronized void logException(Throwable t) {
+        if (!DEBUG) {
+            return;
+        }
+        PrintWriter bw = getLog();
+        if (bw != null) {
+            t.printStackTrace(bw);
+            bw.flush();
+        }
+    }
+
+    /**
+     * Bugs in an annotation processor can cause silent failure so try to report any exception
+     * throws as errors.
+     */
+    private void reportExceptionThrow(Element element, Throwable t) {
+        logMessage("throw for %s:\n", element);
+        logException(t);
+        processingEnv.getMessager().printMessage(Kind.ERROR, "Exception throw during processing: " + t.toString() + " " + Arrays.toString(Arrays.copyOf(t.getStackTrace(), 4)), element);
+    }
 
     static class TypeDescriptor {
         final TypeMirror mirror;
@@ -210,25 +269,21 @@
          * The name uses in match expressions to refer to this type.
          */
         final String shortName;
+
         /**
-         * The {@link ValueNode} class represented by this type.
+         * The simple name of the {@link ValueNode} class represented by this type.
          */
         final String nodeClass;
 
         /**
-         * The {@link ValueNode} class represented by this type.
+         * The package of {@link ValueNode} class represented by this type.
          */
         final String nodePackage;
 
         /**
-         * Expected number of matchable inputs. Should be less <= 2 at the moment.
+         * The matchable inputs of the node.
          */
-        final int inputs;
-
-        /**
-         * An adapter class to read the proper matchable inputs of the class.
-         */
-        final String adapter;
+        final String[] inputs;
 
         /**
          * Should swapped variants of this match be generated. The user of the match is expected to
@@ -245,16 +300,15 @@
 
         final Set<Element> originatingElements = new HashSet<>();
 
-        TypeDescriptor(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, int inputs, String adapter, boolean commutative, boolean shareable) {
+        TypeDescriptor(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, String[] inputs, boolean commutative, boolean shareable) {
             this.mirror = mirror;
             this.shortName = shortName;
             this.nodeClass = nodeClass;
             this.nodePackage = nodePackage;
             this.inputs = inputs;
-            this.adapter = adapter;
             this.commutative = commutative;
             this.shareable = shareable;
-            assert !commutative || inputs == 2;
+            assert !commutative || inputs.length == 2;
         }
     }
 
@@ -279,8 +333,12 @@
 
     private TypeMirror matchRuleTypeMirror;
 
-    private void declareType(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, int inputs, String adapter, boolean commutative, boolean shareable, Element element) {
-        TypeDescriptor descriptor = new TypeDescriptor(mirror, shortName, nodeClass, nodePackage, inputs, adapter, commutative, shareable);
+    private TypeMirror matchableNodeTypeMirror;
+
+    private TypeMirror matchableNodesTypeMirror;
+
+    private void declareType(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, String[] inputs, boolean commutative, boolean shareable, Element element) {
+        TypeDescriptor descriptor = new TypeDescriptor(mirror, shortName, nodeClass, nodePackage, inputs, commutative, shareable);
         descriptor.originatingElements.add(element);
         knownTypes.put(shortName, descriptor);
         if (!requiredPackages.contains(descriptor.nodePackage)) {
@@ -305,12 +363,33 @@
             this.nodeType = nodeType;
             this.name = name;
             if (forExpression) {
-                this.inputs = new MatchDescriptor[nodeType.inputs];
+                this.inputs = new MatchDescriptor[nodeType.inputs.length];
             } else {
                 this.inputs = new MatchDescriptor[0];
             }
         }
 
+        List<String> recurseVariants(int index) {
+            if (inputs.length == 0) {
+                return new ArrayList<>();
+            }
+            List<String> currentVariants = inputs[index].generateVariants();
+            if (index == inputs.length - 1) {
+                return currentVariants;
+            }
+            List<String> subVariants = recurseVariants(index + 1);
+            List<String> result = new ArrayList<>();
+            for (String current : currentVariants) {
+                for (String sub : subVariants) {
+                    result.add(current + ", " + sub);
+                    if (nodeType.commutative) {
+                        result.add(sub + ", " + current);
+                    }
+                }
+            }
+            return result;
+        }
+
         /**
          * Recursively generate all the variants of this rule pattern. Currently that just means to
          * swap the inputs for commutative rules, producing all possible permutations.
@@ -321,32 +400,15 @@
             String prefix = formatPrefix();
             String suffix = formatSuffix();
             ArrayList<String> variants = new ArrayList<>();
-            if (inputs.length == 3) {
-                for (String first : inputs[0].generateVariants()) {
-                    for (String second : inputs[1].generateVariants()) {
-                        for (String third : inputs[2].generateVariants()) {
-                            variants.add(prefix + ", " + first + ", " + second + ", " + third + suffix);
-                        }
-                    }
-                }
-            } else if (inputs.length == 2) {
-                // Generate this version and a swapped version
-                for (String first : inputs[0].generateVariants()) {
-                    for (String second : inputs[1].generateVariants()) {
-                        variants.add(prefix + ", " + first + ", " + second + suffix);
-                        if (nodeType.commutative) {
-                            variants.add(prefix + ", " + second + ", " + first + suffix);
-                        }
-                    }
-                }
-            } else if (inputs.length == 1) {
-                for (String first : inputs[0].generateVariants()) {
-                    variants.add(prefix + ", " + first + suffix);
+            if (inputs.length > 0) {
+                for (String var : recurseVariants(0)) {
+                    variants.add(prefix + ", " + var + suffix);
                 }
             } else {
                 assert inputs.length == 0;
                 variants.add(prefix + suffix);
             }
+
             return variants;
         }
 
@@ -360,11 +422,11 @@
 
         private String formatSuffix() {
             if (nodeType != null) {
-                if (inputs.length != nodeType.inputs) {
+                if (inputs.length != nodeType.inputs.length) {
                     return ", true)";
                 } else {
-                    if (nodeType.adapter != null) {
-                        return ", " + nodeType.adapter + "," + !nodeType.shareable + ")";
+                    if (nodeType.inputs.length > 0) {
+                        return ", MatchPattern.findPositions(" + nodeType.nodeClass + ".class, new String[]{\"" + String.join("\", \"", nodeType.inputs) + "\"})," + !nodeType.shareable + ")";
                     }
                     if (nodeType.shareable) {
                         return ", false)";
@@ -580,32 +642,20 @@
         if (roundEnv.processingOver()) {
             return true;
         }
+        logMessage("Starting round %s\n", roundEnv);
         matchRulesTypeMirror = processingEnv.getElementUtils().getTypeElement(MatchRules.class.getCanonicalName()).asType();
         matchRuleTypeMirror = processingEnv.getElementUtils().getTypeElement(MatchRule.class.getCanonicalName()).asType();
 
-        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 valueTypeMirror = processingEnv.getElementUtils().getTypeElement(ValueNode.class.getName()).asType();
-            valueType = new TypeDescriptor(valueTypeMirror, "Value", ValueNode.class.getSimpleName(), ValueNode.class.getPackage().getName(), 0, null, false, false);
+        matchableNodeTypeMirror = processingEnv.getElementUtils().getTypeElement(MatchableNode.class.getCanonicalName()).asType();
+        matchableNodesTypeMirror = processingEnv.getElementUtils().getTypeElement(MatchableNodes.class.getCanonicalName()).asType();
 
-            // Import default definitions
-            processMatchableNode(processingEnv.getElementUtils().getTypeElement(GraalMatchableNodes.class.getName()));
-            for (Element element : roundEnv.getElementsAnnotatedWith(MatchableNodeImport.class)) {
-                // Import any other definitions required by this element
-                String[] imports = element.getAnnotation(MatchableNodeImport.class).value();
-                for (String m : imports) {
-                    TypeElement el = processingEnv.getElementUtils().getTypeElement(m);
-                    processMatchableNode(el);
-                }
-            }
+        try {
+            // Define a TypeDescriptor for the generic node but don't enter it into the nodeTypes
+            // table since it shouldn't be mentioned in match rules.
+            TypeMirror valueTypeMirror = processingEnv.getElementUtils().getTypeElement(ValueNode.class.getName()).asType();
+            valueType = new TypeDescriptor(valueTypeMirror, "Value", ValueNode.class.getSimpleName(), ValueNode.class.getPackage().getName(), new String[0], false, false);
 
-            // Process any local MatchableNode declarations
-            for (Element element : roundEnv.getElementsAnnotatedWith(MatchableNode.class)) {
-                processMatchableNode(element);
-            }
-
-            Map<TypeElement, MatchRuleDescriptor> map = new HashMap<>();
+            Map<TypeElement, MatchRuleDescriptor> map = new LinkedHashMap<>();
 
             for (Element element : roundEnv.getElementsAnnotatedWith(MatchRule.class)) {
                 processMatchRule(map, element, findAnnotationMirror(element, matchRuleTypeMirror));
@@ -632,46 +682,23 @@
         if (!processedMatchableNode.contains(element)) {
             try {
                 processedMatchableNode.add(element);
+
+                AnnotationMirror mirror = findAnnotationMirror(element, matchableNodesTypeMirror);
+                if (mirror == null) {
+                    mirror = findAnnotationMirror(element, matchableNodeTypeMirror);
+                }
+                if (mirror == null) {
+                    return;
+                }
                 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(), matchable.shareable(), element);
+                List<AnnotationMirror> mirrors = null;
+                if (typeUtils().isSameType(mirror.getAnnotationType(), matchableNodesTypeMirror)) {
+                    // Unpack the mirrors for a repeatable annotation
+                    mirrors = getAnnotationValueList(AnnotationMirror.class, mirror, "value");
+                }
+                int i = 0;
+                for (MatchableNode matchableNode : element.getAnnotationsByType(MatchableNode.class)) {
+                    processMatchableNode(element, topDeclaringType, matchableNode, mirrors != null ? mirrors.get(i++) : mirror);
                 }
             } catch (Throwable t) {
                 reportExceptionThrow(element, t);
@@ -679,8 +706,52 @@
         }
     }
 
-    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 processMatchableNode(Element element, TypeElement topDeclaringType, MatchableNode matchable, AnnotationMirror mirror) throws GraalInternalError {
+        logMessage("processMatchableNode %s %s %s\n", topDeclaringType, element, matchable);
+        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);
+
+        Types typeUtils = processingEnv.getTypeUtils();
+        TypeElement nodeClassElement = (TypeElement) typeUtils.asElement(nodeClassMirror);
+        for (String input : matchable.inputs()) {
+            boolean ok = false;
+            TypeElement current = nodeClassElement;
+            while (!ok && current != null) {
+                for (Element fieldElement : ElementFilter.fieldsIn(current.getEnclosedElements())) {
+                    if (fieldElement.getSimpleName().toString().equals(input)) {
+                        ok = true;
+                        break;
+                    }
+                }
+                TypeMirror theSuper = current.getSuperclass();
+                current = (TypeElement) typeUtils.asElement(theSuper);
+            }
+            if (!ok) {
+                String msg = String.format("Input named \"%s\" doesn't exist in %s", input, nodeClassElement.getSimpleName());
+                processingEnv.getMessager().printMessage(Kind.ERROR, msg, element, mirror);
+            }
+        }
+
+        declareType(nodeClassMirror, shortName, nodeClass, nodePackage, matchable.inputs(), matchable.commutative(), matchable.shareable(), element);
     }
 
     private void processMatchRule(Map<TypeElement, MatchRuleDescriptor> map, Element element, AnnotationMirror mirror) {
@@ -691,22 +762,22 @@
                 // The annotation element type should ensure this is true.
                 assert element instanceof ExecutableElement;
 
+                findMatchableNodes(element);
+
                 TypeElement topDeclaringType = topDeclaringType(element);
                 MatchRuleDescriptor info = map.get(topDeclaringType);
                 if (info == null) {
                     info = new MatchRuleDescriptor(topDeclaringType);
                     map.put(topDeclaringType, info);
                 }
+                List<AnnotationMirror> mirrors = null;
                 if (typeUtils().isSameType(mirror.getAnnotationType(), matchRulesTypeMirror)) {
-                    List<AnnotationMirror> value = getAnnotationValueList(AnnotationMirror.class, mirror, "value");
-                    int i = 0;
-                    for (MatchRule matchRule : element.getAnnotationsByType(MatchRule.class)) {
-                        processMethodMatchRule((ExecutableElement) element, info, matchRule, value.get(i++));
-                    }
-                } else {
-                    for (MatchRule matchRule : element.getAnnotationsByType(MatchRule.class)) {
-                        processMethodMatchRule((ExecutableElement) element, info, matchRule, mirror);
-                    }
+                    // Unpack the mirrors for a repeatable annotation
+                    mirrors = getAnnotationValueList(AnnotationMirror.class, mirror, "value");
+                }
+                int i = 0;
+                for (MatchRule matchRule : element.getAnnotationsByType(MatchRule.class)) {
+                    processMethodMatchRule((ExecutableElement) element, info, matchRule, mirrors != null ? mirrors.get(i++) : mirror);
                 }
             } catch (Throwable t) {
                 reportExceptionThrow(element, t);
@@ -714,11 +785,41 @@
         }
     }
 
+    /**
+     * Search the super types of element for MatchableNode definitions. Any superclass or super
+     * interface can contain definitions of matchable nodes.
+     *
+     * @param element
+     */
+    private void findMatchableNodes(Element element) {
+        processMatchableNode(element);
+        Element enclosing = element.getEnclosingElement();
+        while (enclosing != null) {
+            if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) {
+                TypeElement current = (TypeElement) enclosing;
+                while (current != null) {
+                    processMatchableNode(current);
+                    for (TypeMirror intf : current.getInterfaces()) {
+                        Element interfaceElement = typeUtils().asElement(intf);
+                        processMatchableNode(interfaceElement);
+                        // Recurse
+                        findMatchableNodes(interfaceElement);
+                    }
+                    TypeMirror theSuper = current.getSuperclass();
+                    current = (TypeElement) typeUtils().asElement(theSuper);
+                }
+            }
+            enclosing = enclosing.getEnclosingElement();
+        }
+    }
+
     private Types typeUtils() {
         return processingEnv.getTypeUtils();
     }
 
     private void processMethodMatchRule(ExecutableElement method, MatchRuleDescriptor info, MatchRule matchRule, AnnotationMirror mirror) {
+        logMessage("processMethodMatchRule %s %s\n", method, mirror);
+
         Types typeUtils = typeUtils();
 
         if (!method.getModifiers().contains(Modifier.PUBLIC)) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java	Wed May 07 15:31:04 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java	Wed May 07 10:58:26 2014 -0700
@@ -30,7 +30,8 @@
 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.*;
+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;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatementSet.java	Wed May 07 15:31:04 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatementSet.java	Wed May 07 10:58:26 2014 -0700
@@ -34,7 +34,7 @@
     public Class<? extends NodeLIRBuilder> forClass();
 
     /**
-     * @return the {@link MatchStatement}s available with this {@link NodeLIRBuilder} subclass.
+     * @return the {@link MatchStatement}s available for this {@link NodeLIRBuilder} subclass.
      */
     public List<MatchStatement> statements();
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNode.java	Wed May 07 15:31:04 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNode.java	Wed May 07 10:58:26 2014 -0700
@@ -27,7 +27,9 @@
 import com.oracle.graal.nodes.*;
 
 /**
- * Describes the properties of a node for use when building a {@link MatchPattern}.
+ * Describes the properties of a node for use when building a {@link MatchPattern}. These
+ * declarations are required when parsing a {@link MatchRule}. They are expected to be found on a
+ * super type of the holder of the method declaring the {@link MatchRule}.
  */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.TYPE)
@@ -42,15 +44,9 @@
     Class<? extends ValueNode> nodeClass();
 
     /**
-     * The number of matchable inputs, which may be less than the real number of inputs.
+     * The names of the inputs in the order they should appear in the match.
      */
-    int inputs() default 0;
-
-    /**
-     * A helper class to visit the inputs in a specified order. Should be a subclass of
-     * {@link MatchNodeAdapter}.
-     */
-    Class<?> adapter() default MatchableNode.class;
+    String[] inputs() default {};
 
     /**
      * Can a pattern be matched with the operands swapped. This will cause swapped versions of
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNodeImport.java	Wed May 07 15:31:04 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.compiler.match;
-
-import java.lang.annotation.*;
-
-/**
- * A list of classes which contain one or more {@link MatchableNode} annotations describing nodes
- * that may be used in match expressions. Those {@link MatchableNode} declarations are parsed before
- * processing any {@link MatchRule}s.
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
-public @interface MatchableNodeImport {
-    String[] value() default {};
-}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNodes.java	Wed May 07 15:31:04 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNodes.java	Wed May 07 10:58:26 2014 -0700
@@ -25,7 +25,7 @@
 import java.lang.annotation.*;
 
 /**
- * The repeatable representation of {@link MatchableNode}. Should never be used directly.
+ * The repeatable representation of {@link MatchableNode}.
  */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.TYPE)
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Wed May 07 15:31:04 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Wed May 07 10:58:26 2014 -0700
@@ -55,7 +55,6 @@
 /**
  * LIR generator specialized for AMD64 HotSpot.
  */
-@MatchableNodeImport({"com.oracle.graal.hotspot.nodes.HotSpotMatchableNodes"})
 public class AMD64HotSpotNodeLIRBuilder extends AMD64NodeLIRBuilder implements HotSpotNodeLIRBuilder {
 
     private static ValueNode filterCompression(ValueNode node) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotNodeLIRBuilder.java	Wed May 07 15:31:04 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotNodeLIRBuilder.java	Wed May 07 10:58:26 2014 -0700
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.hotspot;
 
+import com.oracle.graal.compiler.match.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
@@ -31,6 +32,7 @@
  * This interface defines the contract a HotSpot backend LIR generator needs to fulfill in addition
  * to abstract methods from {@link LIRGenerator} and {@link NodeLIRBuilderTool}.
  */
+@MatchableNode(nodeClass = CompressionNode.class, inputs = {"input"})
 public interface HotSpotNodeLIRBuilder {
 
     void emitPatchReturnAddress(ValueNode address);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotMatchableNodes.java	Wed May 07 15:31:04 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.nodes;
-
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.match.*;
-import com.oracle.graal.nodes.*;
-
-@MatchableNode(nodeClass = CompressionNode.class, inputs = 1, adapter = HotSpotMatchableNodes.CompressionNodeAdapter.class)
-public class HotSpotMatchableNodes {
-    public static class CompressionNodeAdapter extends MatchNodeAdapter {
-        @Override
-        public ValueNode getInput(int input, ValueNode node) {
-            if (input == 0) {
-                return ((CompressionNode) node).getInput();
-            }
-            throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-}