changeset 15532:fd47de8808fc

Merge.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Tue, 06 May 2014 11:34:23 +0200
parents a71192a503fe (current diff) 44d700e2faba (diff)
children d6c80b8b414f
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java
diffstat 16 files changed, 530 insertions(+), 142 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Tue May 06 11:34:13 2014 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Tue May 06 11:34:23 2014 +0200
@@ -601,7 +601,7 @@
         }
     }
 
-    protected Value emitBinaryMemory(AMD64Arithmetic op, Kind kind, AllocatableValue a, AMD64AddressValue location, LIRFrameState state) {
+    public Value emitBinaryMemory(AMD64Arithmetic op, Kind kind, AllocatableValue a, AMD64AddressValue location, LIRFrameState state) {
         Variable result = newVariable(a.getKind());
         append(new BinaryMemory(op, kind, result, a, location, state));
         return result;
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Tue May 06 11:34:13 2014 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Tue May 06 11:34:23 2014 +0200
@@ -316,7 +316,7 @@
         throw GraalInternalError.shouldNotReachHere();
     }
 
-    private AMD64Arithmetic getOp(ValueNode operation, Access access) {
+    protected AMD64Arithmetic getOp(ValueNode operation, Access access) {
         Kind memoryKind = getMemoryKind(access);
         if (operation.getClass() == IntegerAddNode.class) {
             switch (memoryKind) {
@@ -455,7 +455,7 @@
         return null;
     }
 
-    @MatchRule("(Write Narrow=narrow value)")
+    @MatchRule("(Write Narrow=narrow location value)")
     public ComplexMatchResult writeNarrow(WriteNode root, NarrowNode narrow) {
         return builder -> {
             PlatformKind writeKind = getLIRGeneratorTool().getPlatformKind(root.value().stamp());
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Tue May 06 11:34:13 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Tue May 06 11:34:23 2014 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.compiler.gen;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.compiler.GraalDebugConfig.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.lir.LIR.*;
 import static com.oracle.graal.nodes.ConstantNode.*;
@@ -71,7 +72,9 @@
         this.gen = gen;
         this.nodeOperands = graph.createNodeMap();
         this.debugInfoBuilder = createDebugInfoBuilder(nodeOperands);
-        matchRules = MatchRuleRegistry.lookup(getClass());
+        if (MatchExpressions.getValue()) {
+            matchRules = MatchRuleRegistry.lookup(getClass());
+        }
     }
 
     @SuppressWarnings("hiding")
@@ -210,11 +213,9 @@
 
         List<ScheduledNode> nodes = blockMap.get(block);
 
-        if (MatchExpressions.getValue()) {
-            // Allow NodeLIRBuilder subclass to specialize code generation of any interesting groups
-            // of instructions
-            matchComplexExpressions(nodes);
-        }
+        // Allow NodeLIRBuilder subclass to specialize code generation of any interesting groups
+        // of instructions
+        matchComplexExpressions(nodes);
 
         for (int i = 0; i < nodes.size(); i++) {
             Node instr = nodes.get(i);
@@ -274,6 +275,13 @@
     protected void matchComplexExpressions(List<ScheduledNode> nodes) {
         if (matchRules != null) {
             try (Scope s = Debug.scope("MatchComplexExpressions")) {
+                if (LogVerbose.getValue()) {
+                    int i = 0;
+                    for (ScheduledNode node : nodes) {
+                        Debug.log("%d: (%s) %1S", i++, node.usages().count(), node);
+                    }
+                }
+
                 // Match the nodes in backwards order to encourage longer matches.
                 for (int index = nodes.size() - 1; index >= 0; index--) {
                     ScheduledNode snode = nodes.get(index);
@@ -281,6 +289,9 @@
                         continue;
                     }
                     ValueNode node = (ValueNode) snode;
+                    if (getOperand(node) != null) {
+                        continue;
+                    }
                     // See if this node is the root of any MatchStatements
                     List<MatchStatement> statements = matchRules.get(node.getClass());
                     if (statements != null) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/GraalMatchableNodes.java	Tue May 06 11:34:13 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/GraalMatchableNodes.java	Tue May 06 11:34:23 2014 +0200
@@ -22,6 +22,7 @@
  */
 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.*;
@@ -30,19 +31,19 @@
  * 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)
+@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 = 1, adapter = GraalMatchableNodes.ReadNodeAdapter.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 = 1, adapter = GraalMatchableNodes.ReadNodeAdapter.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 = 2, adapter = GraalMatchableNodes.WriteNodeAdapter.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)
@@ -58,74 +59,102 @@
 @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
-        protected ValueNode getFirstInput(ValueNode node) {
-            return ((BinaryNode) node).x();
-        }
-
-        @Override
-        protected ValueNode getSecondInput(ValueNode node) {
-            return ((BinaryNode) node).y();
+        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
-        protected ValueNode getFirstInput(ValueNode node) {
-            return ((WriteNode) node).object();
-        }
-
-        @Override
-        protected ValueNode getSecondInput(ValueNode node) {
-            return ((WriteNode) node).value();
+        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
-        protected ValueNode getFirstInput(ValueNode node) {
-            return ((ConvertNode) node).getInput();
+        public ValueNode getInput(int input, ValueNode node) {
+            if (input == 0) {
+                return ((ConvertNode) node).getInput();
+            }
+            throw GraalInternalError.shouldNotReachHere();
         }
     }
 
     public static class ReinterpretNodeAdapter extends MatchNodeAdapter {
-
         @Override
-        protected ValueNode getFirstInput(ValueNode node) {
-            return ((ReinterpretNode) node).value();
+        public ValueNode getInput(int input, ValueNode node) {
+            if (input == 0) {
+                return ((ReinterpretNode) node).value();
+            }
+            throw GraalInternalError.shouldNotReachHere();
         }
     }
 
     public static class IfNodeAdapter extends MatchNodeAdapter {
-
         @Override
-        protected ValueNode getFirstInput(ValueNode node) {
-            return ((IfNode) node).condition();
+        public ValueNode getInput(int input, ValueNode node) {
+            if (input == 0) {
+                return ((IfNode) node).condition();
+            }
+            throw GraalInternalError.shouldNotReachHere();
         }
     }
 
-    public static class ReadNodeAdapter extends MatchNodeAdapter {
+    public static class AccessAdapter extends MatchNodeAdapter {
 
         @Override
-        protected ValueNode getFirstInput(ValueNode node) {
-            return ((Access) node).object();
+        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
-        protected ValueNode getFirstInput(ValueNode node) {
-            return ((BinaryOpLogicNode) node).x();
-        }
-
-        @Override
-        protected ValueNode getSecondInput(ValueNode node) {
-            return ((BinaryOpLogicNode) node).y();
+        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/MatchContext.java	Tue May 06 11:34:13 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchContext.java	Tue May 06 11:34:23 2014 +0200
@@ -31,7 +31,7 @@
 import com.oracle.graal.compiler.match.MatchPattern.Result;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.virtual.*;
 
 /**
@@ -100,16 +100,16 @@
         // Ensure that there's no unsafe work in between these operations.
         for (int i = startIndex; i <= endIndex; 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.
+            if (node instanceof VirtualObjectNode || node instanceof FloatingNode) {
+                // The order of evaluation of these nodes controlled by data dependence so they
+                // don't interfere with this match.
                 continue;
-            } else if (consumed == null || !consumed.contains(node) && node != root) {
+            } 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);
+                        Debug.log("%s(%s) %1s", (consumed != null && consumed.contains(theNode) || theNode == root) ? "*" : " ", theNode.usages().count(), theNode);
                     }
                 }
                 return Result.NOT_SAFE(node, rule.getPattern());
@@ -147,14 +147,16 @@
     public Result consume(ValueNode node) {
         assert node.usages().count() <= 1 : "should have already been checked";
 
+        // Check NOT_IN_BLOCK first since that usually implies ALREADY_USED
+        int index = nodes.indexOf(node);
+        if (index == -1) {
+            return Result.NOT_IN_BLOCK(node, rule.getPattern());
+        }
+
         if (builder.hasOperand(node)) {
             return Result.ALREADY_USED(node, rule.getPattern());
         }
 
-        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);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchNodeAdapter.java	Tue May 06 11:34:13 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchNodeAdapter.java	Tue May 06 11:34:23 2014 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.compiler.match;
 
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.nodes.*;
 
 /**
@@ -31,12 +32,7 @@
  */
 public class MatchNodeAdapter {
     @SuppressWarnings("unused")
-    protected ValueNode getFirstInput(ValueNode node) {
-        throw new InternalError();
-    }
-
-    @SuppressWarnings("unused")
-    protected ValueNode getSecondInput(ValueNode node) {
-        throw new InternalError();
+    public ValueNode getInput(int input, ValueNode node) {
+        throw GraalInternalError.shouldNotReachHere();
     }
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java	Tue May 06 11:34:13 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java	Tue May 06 11:34:23 2014 +0200
@@ -111,23 +111,25 @@
      * The expected type of the node. It must match exactly.
      */
     private final Class<? extends ValueNode> nodeClass;
+
     /**
      * An optional name for this node. A name can occur multiple times in a match and that name must
      * always refer to the same node of the match will fail.
      */
     private final String name;
+
     /**
-     * An optional pattern for the first input.
+     * Patterns to match the inputs.
      */
-    private final MatchPattern first;
-    /**
-     * An optional pattern for the second input.
-     */
-    private final MatchPattern second;
+    private final MatchPattern[] patterns;
+
     /**
      * Helper class to visit the inputs.
      */
     private final MatchNodeAdapter adapter;
+
+    private static final MatchPattern[] EMPTY_PATTERNS = new MatchPattern[0];
+
     /**
      * Can there only be one user of the node. Constant nodes can be matched even if there are other
      * users.
@@ -135,23 +137,44 @@
     private final boolean singleUser;
 
     public MatchPattern(String name, boolean singleUser) {
-        this(null, name, null, null, null, singleUser);
+        this(null, name, singleUser);
     }
 
     public MatchPattern(Class<? extends ValueNode> nodeClass, String name, boolean singleUser) {
-        this(nodeClass, name, null, null, null, singleUser);
+        this.nodeClass = nodeClass;
+        this.name = name;
+        this.singleUser = singleUser;
+        this.patterns = EMPTY_PATTERNS;
+        this.adapter = null;
     }
 
     public MatchPattern(Class<? extends ValueNode> nodeClass, String name, MatchPattern first, MatchNodeAdapter adapter, boolean singleUser) {
-        this(nodeClass, name, first, null, adapter, 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) {
         this.nodeClass = nodeClass;
         this.name = name;
         this.singleUser = singleUser;
-        this.first = first;
-        this.second = second;
+        this.patterns = new MatchPattern[2];
+        patterns[0] = first;
+        patterns[1] = second;
+        this.adapter = adapter;
+    }
+
+    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;
     }
 
@@ -197,10 +220,10 @@
             result = context.captureNamedValue(name, nodeClass, node);
         }
 
-        if (first != null) {
-            result = first.matchUsage(adapter.getFirstInput(node), context, false);
-            if (result == Result.OK && second != null) {
-                result = second.matchUsage(adapter.getSecondInput(node), context, false);
+        for (int input = 0; input < patterns.length; input++) {
+            result = patterns[input].matchUsage(adapter.getInput(input, node), context, false);
+            if (result != Result.OK) {
+                return result;
             }
         }
 
@@ -231,10 +254,10 @@
             }
         }
 
-        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);
+        for (int input = 0; input < patterns.length; input++) {
+            result = patterns[input].matchShape(adapter.getInput(input, node), statement, false);
+            if (result != Result.OK) {
+                return result;
             }
         }
 
@@ -248,10 +271,18 @@
      */
     public String formatMatch(ValueNode root) {
         String result = String.format("%s", root);
-        if (first == null && second == null) {
+        if (patterns.length == 0) {
             return result;
         } else {
-            return "(" + result + (first != null ? " " + first.formatMatch(adapter.getFirstInput(root)) : "") + (second != null ? " " + second.formatMatch(adapter.getSecondInput(root)) : "") + ")";
+            StringBuilder sb = new StringBuilder();
+            sb.append("(");
+            sb.append(result);
+            for (int input = 0; input < patterns.length; input++) {
+                sb.append(" ");
+                sb.append(patterns[input].formatMatch(adapter.getInput(input, root)));
+            }
+            sb.append(")");
+            return sb.toString();
         }
     }
 
@@ -260,11 +291,21 @@
         if (nodeClass == null) {
             return name;
         } else {
-            String pre = first != null || second != null ? "(" : "";
-            String post = first != null || second != null ? ")" : "";
             String nodeName = nodeClass.getSimpleName();
             nodeName = nodeName.substring(0, nodeName.length() - 4);
-            return pre + nodeName + (name != null ? "=" + name : "") + (first != null ? (" " + first.toString()) : "") + (second != null ? (" " + second.toString()) : "") + post;
+            if (patterns.length == 0) {
+                return nodeName + (name != null ? "=" + name : "");
+            } else {
+                StringBuilder sb = new StringBuilder();
+                sb.append("(");
+                sb.append(nodeName);
+                for (int index = 0; index < patterns.length; index++) {
+                    sb.append(" ");
+                    sb.append(patterns[index].toString());
+                }
+                sb.append(")");
+                return sb.toString();
+            }
         }
     }
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java	Tue May 06 11:34:13 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java	Tue May 06 11:34:23 2014 +0200
@@ -53,6 +53,9 @@
 @SupportedAnnotationTypes({"com.oracle.graal.compiler.match.MatchRule", "com.oracle.graal.compiler.match.MatchRules", "com.oracle.graal.compiler.match.MatchableNode"})
 public class MatchProcessor extends AbstractProcessor {
 
+    public MatchProcessor() {
+    }
+
     @Override
     public SourceVersion getSupportedSourceVersion() {
         return SourceVersion.latest();
@@ -142,6 +145,7 @@
                     next();
                     return descriptor;
                 }
+                throw new RuleParseError("Too many arguments to " + descriptor.nodeType.nodeClass);
             }
             throw new RuleParseError("Extra tokens following match pattern: " + peek(null));
         }
@@ -237,11 +241,11 @@
          * Can multiple users of this node subsume it. Constants can be swallowed into a match even
          * if there are multiple users.
          */
-        final boolean cloneable;
+        final boolean shareable;
 
         final Set<Element> originatingElements = new HashSet<>();
 
-        TypeDescriptor(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, int inputs, String adapter, boolean commutative) {
+        TypeDescriptor(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, int inputs, String adapter, boolean commutative, boolean shareable) {
             this.mirror = mirror;
             this.shortName = shortName;
             this.nodeClass = nodeClass;
@@ -249,7 +253,7 @@
             this.inputs = inputs;
             this.adapter = adapter;
             this.commutative = commutative;
-            this.cloneable = (nodePackage + "." + nodeClass).equals(ConstantNode.class.getName());
+            this.shareable = shareable;
             assert !commutative || inputs == 2;
         }
     }
@@ -265,13 +269,18 @@
     List<String> requiredPackages = new ArrayList<>();
 
     /**
-     * The automatically generated wrapper class for a method based MatchRule.
+     * The java.lang.reflect.Method for invoking 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);
+    private TypeMirror matchRulesTypeMirror;
+
+    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);
         descriptor.originatingElements.add(element);
         knownTypes.put(shortName, descriptor);
         if (!requiredPackages.contains(descriptor.nodePackage)) {
@@ -279,13 +288,10 @@
         }
     }
 
-    private static String findPackage(Element type) {
-        Element enclosing = type.getEnclosingElement();
-        while (enclosing != null && enclosing.getKind() != ElementKind.PACKAGE) {
-            enclosing = enclosing.getEnclosingElement();
-        }
-        if (enclosing != null && enclosing.getKind() == ElementKind.PACKAGE) {
-            return ((PackageElement) enclosing).getQualifiedName().toString();
+    private String findPackage(Element type) {
+        PackageElement p = processingEnv.getElementUtils().getPackageOf(type);
+        if (p != null) {
+            return p.getQualifiedName().toString();
         }
         throw new GraalInternalError("can't find package for %s", type);
     }
@@ -315,7 +321,15 @@
             String prefix = formatPrefix();
             String suffix = formatSuffix();
             ArrayList<String> variants = new ArrayList<>();
-            if (inputs.length == 2) {
+            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()) {
@@ -330,6 +344,7 @@
                     variants.add(prefix + ", " + first + suffix);
                 }
             } else {
+                assert inputs.length == 0;
                 variants.add(prefix + suffix);
             }
             return variants;
@@ -349,9 +364,9 @@
                     return ", true)";
                 } else {
                     if (nodeType.adapter != null) {
-                        return ", " + nodeType.adapter + "," + !nodeType.cloneable + ")";
+                        return ", " + nodeType.adapter + "," + !nodeType.shareable + ")";
                     }
-                    if (nodeType.cloneable) {
+                    if (nodeType.shareable) {
                         return ", false)";
                     }
                 }
@@ -364,7 +379,7 @@
     /**
      * Strip the package off a class name leaving the full class name including any outer classes.
      */
-    static String fullClassName(Element element) {
+    private 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);
@@ -377,7 +392,7 @@
         String matchStatementClassName = topDeclaringClass + "_" + MatchStatementSet.class.getSimpleName();
         Element[] originatingElements = info.originatingElements.toArray(new Element[info.originatingElements.size()]);
 
-        Types typeUtils = processingEnv.getTypeUtils();
+        Types typeUtils = typeUtils();
         Filer filer = processingEnv.getFiler();
         try (PrintWriter out = createSourceFile(pkg, matchStatementClassName, filer, originatingElements)) {
 
@@ -551,17 +566,28 @@
         return topDeclaringType(enclosing);
     }
 
+    private AnnotationMirror findAnnotationMirror(Element element, TypeMirror typeMirror) {
+        for (AnnotationMirror mirror : element.getAnnotationMirrors()) {
+            if (typeUtils().isSameType(mirror.getAnnotationType(), typeMirror)) {
+                return mirror;
+            }
+        }
+        return null;
+    }
+
     @Override
     public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
         if (roundEnv.processingOver()) {
             return true;
         }
+        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 mirror = processingEnv.getElementUtils().getTypeElement(ValueNode.class.getName()).asType();
-            valueType = new TypeDescriptor(mirror, "Value", ValueNode.class.getSimpleName(), ValueNode.class.getPackage().getName(), 0, null, false);
+            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);
 
             // Import default definitions
             processMatchableNode(processingEnv.getElementUtils().getTypeElement(GraalMatchableNodes.class.getName()));
@@ -580,11 +606,12 @@
             }
 
             Map<TypeElement, MatchRuleDescriptor> map = new HashMap<>();
+
             for (Element element : roundEnv.getElementsAnnotatedWith(MatchRule.class)) {
-                processMatchRule(map, element);
+                processMatchRule(map, element, findAnnotationMirror(element, matchRuleTypeMirror));
             }
             for (Element element : roundEnv.getElementsAnnotatedWith(MatchRules.class)) {
-                processMatchRule(map, element);
+                processMatchRule(map, element, findAnnotationMirror(element, matchRulesTypeMirror));
             }
 
             for (MatchRuleDescriptor info : map.values()) {
@@ -644,7 +671,7 @@
                         nodeAdapter = String.format("new %s()", nodeAdapterMirror.toString());
                     }
 
-                    declareType(nodeClassMirror, shortName, nodeClass, nodePackage, matchable.inputs(), nodeAdapter, matchable.commutative(), element);
+                    declareType(nodeClassMirror, shortName, nodeClass, nodePackage, matchable.inputs(), nodeAdapter, matchable.commutative(), matchable.shareable(), element);
                 }
             } catch (Throwable t) {
                 reportExceptionThrow(element, t);
@@ -656,7 +683,7 @@
         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) {
+    private void processMatchRule(Map<TypeElement, MatchRuleDescriptor> map, Element element, AnnotationMirror mirror) {
         if (!processedMatchRule.contains(element)) {
             try {
                 processedMatchRule.add(element);
@@ -670,9 +697,16 @@
                     info = new MatchRuleDescriptor(topDeclaringType);
                     map.put(topDeclaringType, info);
                 }
-                for (MatchRule matchRule : element.getAnnotationsByType(MatchRule.class)) {
-                    // System.err.println(matchRule);
-                    processMethodMatchRule((ExecutableElement) element, info, matchRule);
+                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);
+                    }
                 }
             } catch (Throwable t) {
                 reportExceptionThrow(element, t);
@@ -680,8 +714,12 @@
         }
     }
 
-    private void processMethodMatchRule(ExecutableElement method, MatchRuleDescriptor info, MatchRule matchRule) {
-        Types typeUtils = processingEnv.getTypeUtils();
+    private Types typeUtils() {
+        return processingEnv.getTypeUtils();
+    }
+
+    private void processMethodMatchRule(ExecutableElement method, MatchRuleDescriptor info, MatchRule matchRule, AnnotationMirror mirror) {
+        Types typeUtils = typeUtils();
 
         if (!method.getModifiers().contains(Modifier.PUBLIC)) {
             String msg = String.format("MatchRule method %s must be public", method.getSimpleName());
@@ -766,7 +804,136 @@
                 info.matchRules.add(new MatchRuleItem(match, invoker));
             }
         } catch (RuleParseError e) {
-            processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), method);
+            processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), method, mirror);
         }
     }
+
+    // TODO borrowed from com.oracle.truffle.dsl.processor.Utils
+    @SuppressWarnings("unchecked")
+    private static <T> List<T> getAnnotationValueList(Class<T> expectedListType, AnnotationMirror mirror, String name) {
+        List<? extends AnnotationValue> values = getAnnotationValue(List.class, mirror, name);
+        List<T> result = new ArrayList<>();
+
+        if (values != null) {
+            for (AnnotationValue value : values) {
+                T annotationValue = resolveAnnotationValue(expectedListType, value);
+                if (annotationValue != null) {
+                    result.add(annotationValue);
+                }
+            }
+        }
+        return result;
+    }
+
+    private static <T> T getAnnotationValue(Class<T> expectedType, AnnotationMirror mirror, String name) {
+        return resolveAnnotationValue(expectedType, getAnnotationValue(mirror, name));
+    }
+
+    @SuppressWarnings({"unchecked"})
+    private static <T> T resolveAnnotationValue(Class<T> expectedType, AnnotationValue value) {
+        if (value == null) {
+            return null;
+        }
+
+        Object unboxedValue = value.accept(new AnnotationValueVisitorImpl(), null);
+        if (unboxedValue != null) {
+            if (expectedType == TypeMirror.class && unboxedValue instanceof String) {
+                return null;
+            }
+            if (!expectedType.isAssignableFrom(unboxedValue.getClass())) {
+                throw new ClassCastException(unboxedValue.getClass().getName() + " not assignable from " + expectedType.getName());
+            }
+        }
+        return (T) unboxedValue;
+    }
+
+    private static AnnotationValue getAnnotationValue(AnnotationMirror mirror, String name) {
+        ExecutableElement valueMethod = null;
+        for (ExecutableElement method : ElementFilter.methodsIn(mirror.getAnnotationType().asElement().getEnclosedElements())) {
+            if (method.getSimpleName().toString().equals(name)) {
+                valueMethod = method;
+                break;
+            }
+        }
+
+        if (valueMethod == null) {
+            return null;
+        }
+
+        AnnotationValue value = mirror.getElementValues().get(valueMethod);
+        if (value == null) {
+            value = valueMethod.getDefaultValue();
+        }
+
+        return value;
+    }
+
+    private static class AnnotationValueVisitorImpl extends AbstractAnnotationValueVisitor7<Object, Void> {
+
+        @Override
+        public Object visitBoolean(boolean b, Void p) {
+            return Boolean.valueOf(b);
+        }
+
+        @Override
+        public Object visitByte(byte b, Void p) {
+            return Byte.valueOf(b);
+        }
+
+        @Override
+        public Object visitChar(char c, Void p) {
+            return c;
+        }
+
+        @Override
+        public Object visitDouble(double d, Void p) {
+            return d;
+        }
+
+        @Override
+        public Object visitFloat(float f, Void p) {
+            return f;
+        }
+
+        @Override
+        public Object visitInt(int i, Void p) {
+            return i;
+        }
+
+        @Override
+        public Object visitLong(long i, Void p) {
+            return i;
+        }
+
+        @Override
+        public Object visitShort(short s, Void p) {
+            return s;
+        }
+
+        @Override
+        public Object visitString(String s, Void p) {
+            return s;
+        }
+
+        @Override
+        public Object visitType(TypeMirror t, Void p) {
+            return t;
+        }
+
+        @Override
+        public Object visitEnumConstant(VariableElement c, Void p) {
+            return c;
+        }
+
+        @Override
+        public Object visitAnnotation(AnnotationMirror a, Void p) {
+            return a;
+        }
+
+        @Override
+        public Object visitArray(List<? extends AnnotationValue> vals, Void p) {
+            return vals;
+        }
+
+    }
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRule.java	Tue May 06 11:34:13 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRule.java	Tue May 06 11:34:23 2014 +0200
@@ -27,15 +27,18 @@
 import com.oracle.graal.nodes.*;
 
 /**
- * This annotation declares a textual pattern for matching an HIR DAG. It's an s-expression with a
- * node followed by its inputs. Node types are always uppercase and lowercase words are the names of
- * nodes.
+ * This annotation declares a textual pattern for matching an HIR tree. The format is a LISP style
+ * s-expression with node types and/or names that are matched against the HIR. Node types are always
+ * uppercase and the names of nodes are always lowercase. Named nodes can be used to match trees
+ * where a node is used multiple times but only as an input to the full match.
  *
  * <pre>
- *   NAME := [a-z][a-zA-Z0-9]*
- *   NODETYPE := [A-Z][a-zA-Z0-9]*
- *   NODEORNAME :=  NODE [ = NAME ] | NAME
- *   EXPRESSION := ( NODEORNAME [ EXPRESSION | NODEORNAME [ EXPRESSION | NODEORNAME ] )
+ *   &lt;node-name&gt;    := [a-z][a-zA-Z0-9]*
+ *   &lt;node-type&gt;    := [A-Z][a-zA-Z0-9]*
+ *   &lt;node-spec&gt;    := &lt;node-type&gt; { '=' &lt;node-name&gt; }
+ *   &lt;node-or-name&gt; := &lt;node-spec&gt; | &lt;node-name&gt;
+ *   &lt;argument&gt;     := &lt;node-or-name&gt; | &lt;match-rule&gt;
+ *   &lt;match-rule&gt;   := '(' &lt;node-spec&gt; &lt;argument&gt;+ ')'
  * </pre>
  *
  * All matched nodes except the root of the match and {@link ConstantNode}s must have a single user.
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java	Tue May 06 11:34:13 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java	Tue May 06 11:34:23 2014 +0200
@@ -29,7 +29,7 @@
 
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.debug.*;
-import com.oracle.graal.debug.Debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.nodes.*;
 
 public class MatchRuleRegistry {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java	Tue May 06 11:34:13 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java	Tue May 06 11:34:23 2014 +0200
@@ -30,8 +30,7 @@
 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.MatchResultCode;
-import com.oracle.graal.compiler.match.MatchPattern.Result;
+import com.oracle.graal.compiler.match.MatchPattern.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.Verbosity;
@@ -99,8 +98,15 @@
                 if (value != null) {
                     context.setResult(value);
                     MatchStatementSuccess.increment();
+                    Debug.metric("MatchStatement[%s]", getName()).increment();
                     return true;
                 }
+                // The pattern matched but some other code generation constraint disallowed code
+                // generation for the pattern.
+                if (LogVerbose.getValue()) {
+                    Debug.log("while matching %s|%s %s %s returned null", context.getRoot().toString(Verbosity.Id), context.getRoot().getClass().getSimpleName(), getName(), generatorMethod.getName());
+                    Debug.log("with nodes %s", formatMatch(node));
+                }
             } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                 throw new GraalInternalError(e);
             }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNode.java	Tue May 06 11:34:13 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNode.java	Tue May 06 11:34:23 2014 +0200
@@ -57,4 +57,9 @@
      * patterns to be automatically generated.
      */
     boolean commutative() default false;
+
+    /**
+     * Can a node with multiple users be safely match by a rule.
+     */
+    boolean shareable() default false;
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Tue May 06 11:34:13 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Tue May 06 11:34:23 2014 +0200
@@ -41,6 +41,7 @@
 import com.oracle.graal.hotspot.amd64.AMD64HotSpotLIRGenerator.SaveRbp;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.NoOp;
 import com.oracle.graal.lir.amd64.*;
@@ -65,7 +66,7 @@
         return result;
     }
 
-    private void emitCompareCompressedMemory(IfNode ifNode, ValueNode valueNode, Access access, CompareNode compare) {
+    private void emitCompareMemoryObject(IfNode ifNode, ValueNode valueNode, Access access, CompareNode compare) {
         Value value;
         // This works by embedding the compressed form for constants, so force a constant instead of
         // respecting what operand() would return.
@@ -95,6 +96,22 @@
         getGen().emitCompareBranchMemoryCompressed(left, right, cond, trueLabel, falseLabel, trueLabelProbability, getState(access));
     }
 
+    private void emitCompareCompressedMemory(Kind kind, IfNode ifNode, ValueNode valueNode, CompressionNode compress, ConstantLocationNode location, Access access, CompareNode compare) {
+        Value value = gen.load(operand(valueNode));
+        AMD64AddressValue address = makeCompressedAddress(compress, location);
+        Condition cond = compare.condition();
+        if (access == filterCompression(compare.x())) {
+            cond = cond.mirror();
+        } else {
+            assert access == filterCompression(compare.y());
+        }
+
+        LabelRef trueLabel = getLIRBlock(ifNode.trueSuccessor());
+        LabelRef falseLabel = getLIRBlock(ifNode.falseSuccessor());
+        double trueLabelProbability = ifNode.probability(ifNode.trueSuccessor());
+        getGen().emitCompareBranchMemory(kind, value, address, getState(access), cond, compare.unorderedIsTrue(), trueLabel, falseLabel, trueLabelProbability);
+    }
+
     public AMD64HotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen) {
         super(graph, gen);
         assert gen instanceof AMD64HotSpotLIRGenerator;
@@ -244,14 +261,116 @@
         setResult(x, result);
     }
 
+    boolean canFormCompressedMemory(CompressionNode compress, ConstantLocationNode location) {
+        HotSpotVMConfig config = HotSpotGraalRuntime.runtime().getConfig();
+        if (config.useCompressedOops && compress.getEncoding().shift <= 3 && NumUtil.isInt(location.getDisplacement())) {
+            PlatformKind objectKind = compress.getInput().stamp().getPlatformKind(getGen());
+            if (objectKind == NarrowOopStamp.NarrowOop || objectKind == Kind.Int && config.narrowKlassBase == config.narrowOopBase) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private AMD64AddressValue makeCompressedAddress(CompressionNode compress, ConstantLocationNode location) {
+        assert canFormCompressedMemory(compress, location);
+        AMD64AddressValue address = getGen().emitAddress(getGen().getProviders().getRegisters().getHeapBaseRegister().asValue(), location.getDisplacement(), operand(compress.getInput()),
+                        1 << compress.getEncoding().shift);
+        return address;
+    }
+
+    @MatchRule("(If (ObjectEquals=compare Constant=value (Pi (Compression Read=access))))")
+    @MatchRule("(If (ObjectEquals=compare Constant=value (Pi (Compression FloatingRead=access))))")
+    @MatchRule("(If (ObjectEquals=compare (Compression value) (Pi (Compression Read=access))))")
+    @MatchRule("(If (ObjectEquals=compare (Compression value) (Pi (Compression FloatingRead=access))))")
     @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 ComplexMatchResult ifCompareCompressedMemory(IfNode root, CompareNode compare, ValueNode value, Access access) {
+    public ComplexMatchResult ifCompareMemoryObject(IfNode root, CompareNode compare, ValueNode value, Access access) {
         if (HotSpotGraalRuntime.runtime().getConfig().useCompressedOops) {
             return builder -> {
-                emitCompareCompressedMemory(root, value, access, compare);
+                emitCompareMemoryObject(root, value, access, compare);
+                return null;
+            };
+        }
+        return null;
+    }
+
+    @MatchRule("(If (IntegerEquals=compare value (FloatingRead=access (Compression=compress object) ConstantLocation=location)))")
+    @MatchRule("(If (IntegerLessThan=compare value (FloatingRead=access (Compression=compress object) ConstantLocation=location)))")
+    @MatchRule("(If (IntegerBelowThan=compare value (FloatingRead=access (Compression=compress object) ConstantLocation=location)))")
+    @MatchRule("(If (FloatEquals=compare value (FloatingRead=access (Compression=compress object) ConstantLocation=location)))")
+    @MatchRule("(If (FloatLessThan=compare value (FloatingRead=access (Compression=compress object) ConstantLocation=location)))")
+    @MatchRule("(If (IntegerEquals=compare value (Read=access (Compression=compress object) ConstantLocation=location)))")
+    @MatchRule("(If (IntegerLessThan=compare value (Read=access (Compression=compress object) ConstantLocation=location)))")
+    @MatchRule("(If (IntegerBelowThan=compare value (Read=access (Compression=compress object) ConstantLocation=location)))")
+    @MatchRule("(If (FloatEquals=compare value (Read=access (Compression=compress object) ConstantLocation=location)))")
+    @MatchRule("(If (FloatLessThan=compare value (Read=access (Compression=compress object) ConstantLocation=location)))")
+    public ComplexMatchResult ifCompareCompressedMemory(IfNode root, CompareNode compare, CompressionNode compress, ValueNode value, ConstantLocationNode location, Access access) {
+        if (canFormCompressedMemory(compress, location)) {
+            PlatformKind cmpKind = gen.getPlatformKind(compare.x().stamp());
+            if (cmpKind instanceof Kind) {
+                Kind kind = (Kind) cmpKind;
+                return builder -> {
+                    emitCompareCompressedMemory(kind, root, value, compress, location, access, compare);
+                    return null;
+                };
+            }
+        }
+        return null;
+    }
+
+    @MatchRule("(IntegerAdd value (Read=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(IntegerSub value (Read=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(IntegerMul value (Read=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(FloatAdd value (Read=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(FloatSub value (Read=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(FloatMul value (Read=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(Or value (Read=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(Xor value (Read=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(And value (Read=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(IntegerAdd value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(IntegerSub value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(IntegerMul value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(FloatAdd value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(FloatSub value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(FloatMul value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(Or value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(Xor value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(And value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
+    public ComplexMatchResult binaryReadCompressed(BinaryNode root, ValueNode value, Access access, CompressionNode compress, ConstantLocationNode location) {
+        if (canFormCompressedMemory(compress, location)) {
+            AMD64Arithmetic op = getOp(root, access);
+            if (op != null) {
+                return builder -> getLIRGeneratorTool().emitBinaryMemory(op, getMemoryKind(access), getLIRGeneratorTool().asAllocatable(operand(value)), makeCompressedAddress(compress, location),
+                                getState(access));
+            }
+        }
+        return null;
+    }
+
+    @MatchRule("(Read (Compression=compress object) ConstantLocation=location)")
+    @MatchRule("(Read (Pi (Compression=compress object)) ConstantLocation=location)")
+    @MatchRule("(FloatingRead (Compression=compress object) ConstantLocation=location)")
+    @MatchRule("(FloatingRead (Pi (Compression=compress object)) ConstantLocation=location)")
+    public ComplexMatchResult readCompressed(Access root, CompressionNode compress, ConstantLocationNode location) {
+        if (canFormCompressedMemory(compress, location)) {
+            PlatformKind readKind = getGen().getPlatformKind(root.asNode().stamp());
+            return builder -> {
+                return getGen().emitLoad(readKind, makeCompressedAddress(compress, location), getState(root));
+            };
+        }
+        return null;
+    }
+
+    @MatchRule("(Write (Compression=compress object) ConstantLocation=location value)")
+    @MatchRule("(Write (Pi (Compression=compress object)) ConstantLocation=location value)")
+    public ComplexMatchResult writeCompressed(Access root, CompressionNode compress, ConstantLocationNode location, ValueNode value) {
+        if (canFormCompressedMemory(compress, location)) {
+            PlatformKind readKind = getGen().getPlatformKind(value.asNode().stamp());
+            return builder -> {
+                getGen().emitStore(readKind, makeCompressedAddress(compress, location), operand(value), getState(root));
                 return null;
             };
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Tue May 06 11:34:13 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Tue May 06 11:34:23 2014 +0200
@@ -97,6 +97,10 @@
         return input;
     }
 
+    public CompressEncoding getEncoding() {
+        return encoding;
+    }
+
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (input instanceof CompressionNode) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotMatchableNodes.java	Tue May 06 11:34:13 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotMatchableNodes.java	Tue May 06 11:34:23 2014 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.match.*;
 import com.oracle.graal.nodes.*;
 
@@ -29,8 +30,11 @@
 public class HotSpotMatchableNodes {
     public static class CompressionNodeAdapter extends MatchNodeAdapter {
         @Override
-        protected ValueNode getFirstInput(ValueNode node) {
-            return ((CompressionNode) node).getInput();
+        public ValueNode getInput(int input, ValueNode node) {
+            if (input == 0) {
+                return ((CompressionNode) node).getInput();
+            }
+            throw GraalInternalError.shouldNotReachHere();
         }
     }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Tue May 06 11:34:13 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Tue May 06 11:34:23 2014 +0200
@@ -73,7 +73,7 @@
 
     /**
      * Ensures a floating node is added to or already present in the graph via {@link Graph#unique}.
-     * 
+     *
      * @return a node similar to {@code node} if one exists, otherwise {@code node}
      */
     public <T extends FloatingNode> T unique(T node) {
@@ -103,7 +103,7 @@
     /**
      * Creates and appends an {@link InvokeNode} for a call to a given method with a given set of
      * arguments. The method is looked up via reflection based on the declaring class and name.
-     * 
+     *
      * @param declaringClass the class declaring the invoked method
      * @param name the name of the invoked method
      * @param args the arguments to the invocation
@@ -151,7 +151,7 @@
 
     /**
      * Determines if a given set of arguments is compatible with the signature of a given method.
-     * 
+     *
      * @return true if {@code args} are compatible with the signature if {@code method}
      * @throws AssertionError if {@code args} are not compatible with the signature if
      *             {@code method}
@@ -186,16 +186,17 @@
     }
 
     /**
-     * {@linkplain #inline Inlines} all invocations currently in the graph.
+     * Recursively {@linkplain #inline inlines} all invocations currently in the graph.
      */
     public void inlineInvokes(SnippetReflectionProvider snippetReflection) {
-        for (InvokeNode invoke : graph.getNodes().filter(InvokeNode.class).snapshot()) {
-            inline(invoke, snippetReflection);
+        while (!graph.getNodes().filter(InvokeNode.class).isEmpty()) {
+            for (InvokeNode invoke : graph.getNodes().filter(InvokeNode.class).snapshot()) {
+                inline(invoke, snippetReflection);
+            }
         }
 
         // Clean up all code that is now dead after inlining.
         new DeadCodeEliminationPhase().apply(graph);
-        assert graph.getNodes().filter(InvokeNode.class).isEmpty();
     }
 
     /**
@@ -240,7 +241,7 @@
      * emitting the code executed when the condition hold; and a call to {@link #elsePart} to start
      * emititng the code when the condition does not hold. It must be followed by a call to
      * {@link #endIf} to close the if-block.
-     * 
+     *
      * @param condition The condition for the if-block
      * @param trueProbability The estimated probability the the condition is true
      */