changeset 22785:3077ac9a6b0d

Split LIR matching rules out of NodeLIRBuilder to allow independent subclasses
author Christian Wimmer <christian.wimmer@oracle.com>
date Thu, 08 Oct 2015 09:28:11 -0700
parents 2c244f95fcbf
children fc5e7703e588
files graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeMatchRules.java graal/com.oracle.graal.compiler.match.processor/src/com/oracle/graal/compiler/match/processor/MatchProcessor.java graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCNodeLIRBuilder.java graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCNodeMatchRules.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeMatchRules.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchGenerator.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatementSet.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java
diffstat 15 files changed, 744 insertions(+), 569 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Thu Oct 08 17:24:58 2015 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Thu Oct 08 09:28:11 2015 -0700
@@ -23,50 +23,18 @@
 
 package com.oracle.graal.compiler.amd64;
 
-import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.ADD;
-import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.AND;
-import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.OR;
-import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.SUB;
-import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.XOR;
-import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSX;
-import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSXB;
-import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSXD;
-import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.DWORD;
-import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.QWORD;
-import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.SD;
-import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.SS;
 import jdk.internal.jvmci.amd64.AMD64;
-import jdk.internal.jvmci.amd64.AMD64Kind;
 import jdk.internal.jvmci.code.CallingConvention;
-import jdk.internal.jvmci.common.JVMCIError;
 import jdk.internal.jvmci.meta.AllocatableValue;
-import jdk.internal.jvmci.meta.JavaConstant;
-import jdk.internal.jvmci.meta.JavaKind;
 import jdk.internal.jvmci.meta.JavaType;
-import jdk.internal.jvmci.meta.LIRKind;
-import jdk.internal.jvmci.meta.PlatformKind;
 import jdk.internal.jvmci.meta.Value;
 
-import com.oracle.graal.asm.NumUtil;
-import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp;
-import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp;
-import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
-import com.oracle.graal.asm.amd64.AMD64Assembler.SSEOp;
-import com.oracle.graal.compiler.common.calc.Condition;
 import com.oracle.graal.compiler.gen.NodeLIRBuilder;
-import com.oracle.graal.compiler.match.ComplexMatchResult;
-import com.oracle.graal.compiler.match.MatchRule;
-import com.oracle.graal.debug.Debug;
 import com.oracle.graal.lir.LIRFrameState;
-import com.oracle.graal.lir.LabelRef;
-import com.oracle.graal.lir.amd64.AMD64AddressValue;
-import com.oracle.graal.lir.amd64.AMD64BinaryConsumer;
 import com.oracle.graal.lir.amd64.AMD64BreakpointOp;
 import com.oracle.graal.lir.amd64.AMD64Call;
-import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp;
 import com.oracle.graal.lir.gen.LIRGeneratorTool;
 import com.oracle.graal.nodes.BreakpointNode;
-import com.oracle.graal.nodes.ConstantNode;
 import com.oracle.graal.nodes.DeoptimizingNode;
 import com.oracle.graal.nodes.FixedNode;
 import com.oracle.graal.nodes.FixedWithNextNode;
@@ -74,25 +42,14 @@
 import com.oracle.graal.nodes.IndirectCallTargetNode;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.ValueNode;
-import com.oracle.graal.nodes.calc.CompareNode;
 import com.oracle.graal.nodes.calc.FixedBinaryNode;
-import com.oracle.graal.nodes.calc.FloatConvertNode;
 import com.oracle.graal.nodes.calc.IntegerDivNode;
 import com.oracle.graal.nodes.calc.IntegerRemNode;
-import com.oracle.graal.nodes.calc.LeftShiftNode;
-import com.oracle.graal.nodes.calc.NarrowNode;
-import com.oracle.graal.nodes.calc.ReinterpretNode;
-import com.oracle.graal.nodes.calc.SignExtendNode;
-import com.oracle.graal.nodes.calc.UnsignedRightShiftNode;
-import com.oracle.graal.nodes.calc.ZeroExtendNode;
-import com.oracle.graal.nodes.extended.UnsafeCastNode;
-import com.oracle.graal.nodes.memory.Access;
-import com.oracle.graal.nodes.memory.WriteNode;
 
 public abstract class AMD64NodeLIRBuilder extends NodeLIRBuilder {
 
-    public AMD64NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen) {
-        super(graph, gen);
+    public AMD64NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen, AMD64NodeMatchRules nodeMatchRules) {
+        super(graph, gen, nodeMatchRules);
     }
 
     @Override
@@ -144,352 +101,6 @@
         return false;
     }
 
-    protected LIRFrameState getState(Access access) {
-        if (access instanceof DeoptimizingNode) {
-            return state((DeoptimizingNode) access);
-        }
-        return null;
-    }
-
-    protected AMD64Kind getMemoryKind(Access access) {
-        return (AMD64Kind) gen.getLIRKind(access.asNode().stamp()).getPlatformKind();
-    }
-
-    protected OperandSize getMemorySize(Access access) {
-        switch (getMemoryKind(access)) {
-            case BYTE:
-                return OperandSize.BYTE;
-            case WORD:
-                return OperandSize.WORD;
-            case DWORD:
-                return OperandSize.DWORD;
-            case QWORD:
-                return OperandSize.QWORD;
-            case SINGLE:
-                return OperandSize.SS;
-            case DOUBLE:
-                return OperandSize.SD;
-            default:
-                throw JVMCIError.shouldNotReachHere("unsupported memory access type " + getMemoryKind(access));
-        }
-    }
-
-    protected ValueNode uncast(ValueNode value) {
-        if (value instanceof UnsafeCastNode) {
-            UnsafeCastNode cast = (UnsafeCastNode) value;
-            return cast.getOriginalNode();
-        }
-        return value;
-    }
-
-    protected ComplexMatchResult emitCompareBranchMemory(IfNode ifNode, CompareNode compare, ValueNode value, Access access) {
-        Condition cond = compare.condition();
-        AMD64Kind kind = getMemoryKind(access);
-
-        if (value.isConstant()) {
-            JavaConstant constant = value.asJavaConstant();
-            if (kind == AMD64Kind.QWORD && !NumUtil.isInt(constant.asLong())) {
-                // Only imm32 as long
-                return null;
-            }
-            if (kind.isXMM()) {
-                Debug.log("Skipping constant compares for float kinds");
-                return null;
-            }
-            if (constant.getJavaKind() == JavaKind.Object && !constant.isNull()) {
-                Debug.log("Skipping constant compares for Object kinds");
-                return null;
-            }
-        }
-
-        // emitCompareBranchMemory expects the memory on the right, so mirror the condition if
-        // that's not true. It might be mirrored again the actual compare is emitted but that's
-        // ok.
-        Condition finalCondition = uncast(compare.getX()) == access ? cond.mirror() : cond;
-        return new ComplexMatchResult() {
-            public Value evaluate(NodeLIRBuilder builder) {
-                LabelRef trueLabel = getLIRBlock(ifNode.trueSuccessor());
-                LabelRef falseLabel = getLIRBlock(ifNode.falseSuccessor());
-                boolean unorderedIsTrue = compare.unorderedIsTrue();
-                double trueLabelProbability = ifNode.probability(ifNode.trueSuccessor());
-                Value other;
-                if (value.isConstant()) {
-                    other = gen.emitJavaConstant(value.asJavaConstant());
-                } else {
-                    other = operand(value);
-                }
-
-                AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress());
-                getLIRGeneratorTool().emitCompareBranchMemory(kind, other, address, getState(access), finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability);
-                return null;
-            }
-        };
-    }
-
-    private ComplexMatchResult emitIntegerTestBranchMemory(IfNode x, ValueNode value, Access access) {
-        LabelRef trueLabel = getLIRBlock(x.trueSuccessor());
-        LabelRef falseLabel = getLIRBlock(x.falseSuccessor());
-        double trueLabelProbability = x.probability(x.trueSuccessor());
-        AMD64Kind kind = getMemoryKind(access);
-        OperandSize size = kind == AMD64Kind.QWORD ? QWORD : DWORD;
-        if (value.isConstant()) {
-            JavaConstant constant = value.asJavaConstant();
-            if (kind == AMD64Kind.QWORD && !NumUtil.isInt(constant.asLong())) {
-                // Only imm32 as long
-                return null;
-            }
-            return builder -> {
-                AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress());
-                gen.append(new AMD64BinaryConsumer.MemoryConstOp(AMD64MIOp.TEST, size, address, (int) constant.asLong(), getState(access)));
-                gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability));
-                return null;
-            };
-        } else {
-            return builder -> {
-                AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress());
-                gen.append(new AMD64BinaryConsumer.MemoryRMOp(AMD64RMOp.TEST, size, gen.asAllocatable(operand(value)), address, getState(access)));
-                gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability));
-                return null;
-            };
-        }
-    }
-
-    protected ComplexMatchResult emitConvertMemoryOp(PlatformKind kind, AMD64RMOp op, OperandSize size, Access access) {
-        return builder -> {
-            AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress());
-            LIRFrameState state = getState(access);
-            return getLIRGeneratorTool().emitConvertMemoryOp(kind, op, size, address, state);
-        };
-    }
-
-    private ComplexMatchResult emitSignExtendMemory(Access access, int fromBits, int toBits) {
-        assert fromBits <= toBits && toBits <= 64;
-        AMD64Kind kind = null;
-        AMD64RMOp op;
-        OperandSize size;
-        if (fromBits == toBits) {
-            return null;
-        } else if (toBits > 32) {
-            kind = AMD64Kind.QWORD;
-            size = OperandSize.QWORD;
-            // sign extend to 64 bits
-            switch (fromBits) {
-                case 8:
-                    op = MOVSXB;
-                    break;
-                case 16:
-                    op = MOVSX;
-                    break;
-                case 32:
-                    op = MOVSXD;
-                    break;
-                default:
-                    throw JVMCIError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
-            }
-        } else {
-            kind = AMD64Kind.DWORD;
-            size = OperandSize.DWORD;
-            // sign extend to 32 bits (smaller values are internally represented as 32 bit values)
-            switch (fromBits) {
-                case 8:
-                    op = MOVSXB;
-                    break;
-                case 16:
-                    op = MOVSX;
-                    break;
-                case 32:
-                    return null;
-                default:
-                    throw JVMCIError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
-            }
-        }
-        if (kind != null && op != null) {
-            return emitConvertMemoryOp(kind, op, size, access);
-        }
-        return null;
-    }
-
-    private Value emitReinterpretMemory(LIRKind to, Access access) {
-        AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress());
-        LIRFrameState state = getState(access);
-        return getLIRGeneratorTool().emitLoad(to, address, state);
-    }
-
-    @MatchRule("(If (IntegerTest Read=access value))")
-    @MatchRule("(If (IntegerTest FloatingRead=access value))")
-    public ComplexMatchResult integerTestBranchMemory(IfNode root, Access access, ValueNode value) {
-        return emitIntegerTestBranchMemory(root, value, access);
-    }
-
-    @MatchRule("(If (IntegerEquals=compare value Read=access))")
-    @MatchRule("(If (IntegerLessThan=compare value Read=access))")
-    @MatchRule("(If (IntegerBelow=compare value Read=access))")
-    @MatchRule("(If (IntegerEquals=compare value FloatingRead=access))")
-    @MatchRule("(If (IntegerLessThan=compare value FloatingRead=access))")
-    @MatchRule("(If (IntegerBelow=compare value FloatingRead=access))")
-    @MatchRule("(If (FloatEquals=compare value Read=access))")
-    @MatchRule("(If (FloatEquals=compare value FloatingRead=access))")
-    @MatchRule("(If (FloatLessThan=compare value Read=access))")
-    @MatchRule("(If (FloatLessThan=compare value FloatingRead=access))")
-    public ComplexMatchResult ifCompareMemory(IfNode root, CompareNode compare, ValueNode value, Access access) {
-        return emitCompareBranchMemory(root, compare, value, access);
-    }
-
-    @MatchRule("(Or (LeftShift=lshift value Constant) (UnsignedRightShift=rshift value Constant))")
-    public ComplexMatchResult rotateLeftConstant(LeftShiftNode lshift, UnsignedRightShiftNode rshift) {
-        if ((lshift.getShiftAmountMask() & (lshift.getY().asJavaConstant().asInt() + rshift.getY().asJavaConstant().asInt())) == 0) {
-            return builder -> getLIRGeneratorTool().emitRol(operand(lshift.getX()), operand(lshift.getY()));
-        }
-        return null;
-    }
-
-    @MatchRule("(Or (LeftShift value (Sub Constant=delta shiftAmount)) (UnsignedRightShift value shiftAmount))")
-    public ComplexMatchResult rotateRightVariable(ValueNode value, ConstantNode delta, ValueNode shiftAmount) {
-        if (delta.asJavaConstant().asLong() == 0 || delta.asJavaConstant().asLong() == 32) {
-            return builder -> getLIRGeneratorTool().emitRor(operand(value), operand(shiftAmount));
-        }
-        return null;
-    }
-
-    @MatchRule("(Or (LeftShift value shiftAmount) (UnsignedRightShift value (Sub Constant=delta shiftAmount)))")
-    public ComplexMatchResult rotateLeftVariable(ValueNode value, ValueNode shiftAmount, ConstantNode delta) {
-        if (delta.asJavaConstant().asLong() == 0 || delta.asJavaConstant().asLong() == 32) {
-            return builder -> getLIRGeneratorTool().emitRol(operand(value), operand(shiftAmount));
-        }
-        return null;
-    }
-
-    private ComplexMatchResult binaryRead(AMD64RMOp op, OperandSize size, ValueNode value, Access access) {
-        return builder -> getLIRGeneratorTool().emitBinaryMemory(op, size, getLIRGeneratorTool().asAllocatable(operand(value)), (AMD64AddressValue) operand(access.getAddress()), getState(access));
-    }
-
-    @MatchRule("(Add value Read=access)")
-    @MatchRule("(Add value FloatingRead=access)")
-    public ComplexMatchResult addMemory(ValueNode value, Access access) {
-        OperandSize size = getMemorySize(access);
-        if (size.isXmmType()) {
-            return binaryRead(SSEOp.ADD, size, value, access);
-        } else {
-            return binaryRead(ADD.getRMOpcode(size), size, value, access);
-        }
-    }
-
-    @MatchRule("(Sub value Read=access)")
-    @MatchRule("(Sub value FloatingRead=access)")
-    public ComplexMatchResult subMemory(ValueNode value, Access access) {
-        OperandSize size = getMemorySize(access);
-        if (size.isXmmType()) {
-            return binaryRead(SSEOp.SUB, size, value, access);
-        } else {
-            return binaryRead(SUB.getRMOpcode(size), size, value, access);
-        }
-    }
-
-    @MatchRule("(Mul value Read=access)")
-    @MatchRule("(Mul value FloatingRead=access)")
-    public ComplexMatchResult mulMemory(ValueNode value, Access access) {
-        OperandSize size = getMemorySize(access);
-        if (size.isXmmType()) {
-            return binaryRead(SSEOp.MUL, size, value, access);
-        } else {
-            return binaryRead(AMD64RMOp.IMUL, size, value, access);
-        }
-    }
-
-    @MatchRule("(And value Read=access)")
-    @MatchRule("(And value FloatingRead=access)")
-    public ComplexMatchResult andMemory(ValueNode value, Access access) {
-        OperandSize size = getMemorySize(access);
-        if (size.isXmmType()) {
-            return null;
-        } else {
-            return binaryRead(AND.getRMOpcode(size), size, value, access);
-        }
-    }
-
-    @MatchRule("(Or value Read=access)")
-    @MatchRule("(Or value FloatingRead=access)")
-    public ComplexMatchResult orMemory(ValueNode value, Access access) {
-        OperandSize size = getMemorySize(access);
-        if (size.isXmmType()) {
-            return null;
-        } else {
-            return binaryRead(OR.getRMOpcode(size), size, value, access);
-        }
-    }
-
-    @MatchRule("(Xor value Read=access)")
-    @MatchRule("(Xor value FloatingRead=access)")
-    public ComplexMatchResult xorMemory(ValueNode value, Access access) {
-        OperandSize size = getMemorySize(access);
-        if (size.isXmmType()) {
-            return null;
-        } else {
-            return binaryRead(XOR.getRMOpcode(size), size, value, access);
-        }
-    }
-
-    @MatchRule("(Write object Narrow=narrow)")
-    public ComplexMatchResult writeNarrow(WriteNode root, NarrowNode narrow) {
-        return builder -> {
-            LIRKind writeKind = getLIRGeneratorTool().getLIRKind(root.value().stamp());
-            getLIRGeneratorTool().emitStore(writeKind, operand(root.getAddress()), operand(narrow.getValue()), state(root));
-            return null;
-        };
-    }
-
-    @MatchRule("(SignExtend Read=access)")
-    @MatchRule("(SignExtend FloatingRead=access)")
-    public ComplexMatchResult signExtend(SignExtendNode root, Access access) {
-        return emitSignExtendMemory(access, root.getInputBits(), root.getResultBits());
-    }
-
-    @MatchRule("(ZeroExtend Read=access)")
-    @MatchRule("(ZeroExtend FloatingRead=access)")
-    public ComplexMatchResult zeroExtend(ZeroExtendNode root, Access access) {
-        AMD64Kind memoryKind = getMemoryKind(access);
-        return builder -> getLIRGeneratorTool().emitZeroExtendMemory(memoryKind, root.getResultBits(), (AMD64AddressValue) operand(access.getAddress()), getState(access));
-    }
-
-    @MatchRule("(FloatConvert Read=access)")
-    @MatchRule("(FloatConvert FloatingRead=access)")
-    public ComplexMatchResult floatConvert(FloatConvertNode root, Access access) {
-        switch (root.getFloatConvert()) {
-            case D2F:
-                return emitConvertMemoryOp(AMD64Kind.SINGLE, SSEOp.CVTSD2SS, SD, access);
-            case D2I:
-                return emitConvertMemoryOp(AMD64Kind.DWORD, SSEOp.CVTTSD2SI, DWORD, access);
-            case D2L:
-                return emitConvertMemoryOp(AMD64Kind.QWORD, SSEOp.CVTTSD2SI, QWORD, access);
-            case F2D:
-                return emitConvertMemoryOp(AMD64Kind.DOUBLE, SSEOp.CVTSS2SD, SS, access);
-            case F2I:
-                return emitConvertMemoryOp(AMD64Kind.DWORD, SSEOp.CVTTSS2SI, DWORD, access);
-            case F2L:
-                return emitConvertMemoryOp(AMD64Kind.QWORD, SSEOp.CVTTSS2SI, QWORD, access);
-            case I2D:
-                return emitConvertMemoryOp(AMD64Kind.DOUBLE, SSEOp.CVTSI2SD, DWORD, access);
-            case I2F:
-                return emitConvertMemoryOp(AMD64Kind.SINGLE, SSEOp.CVTSI2SS, DWORD, access);
-            case L2D:
-                return emitConvertMemoryOp(AMD64Kind.DOUBLE, SSEOp.CVTSI2SD, QWORD, access);
-            case L2F:
-                return emitConvertMemoryOp(AMD64Kind.SINGLE, SSEOp.CVTSI2SS, QWORD, access);
-            default:
-                throw JVMCIError.shouldNotReachHere();
-        }
-    }
-
-    @MatchRule("(Reinterpret Read=access)")
-    @MatchRule("(Reinterpret FloatingRead=access)")
-    public ComplexMatchResult reinterpret(ReinterpretNode root, Access access) {
-        return builder -> {
-            LIRKind kind = getLIRGeneratorTool().getLIRKind(root.stamp());
-            return emitReinterpretMemory(kind, access);
-        };
-
-    }
-
     @Override
     public void visitBreakpointNode(BreakpointNode node) {
         JavaType[] sig = new JavaType[node.arguments().size()];
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeMatchRules.java	Thu Oct 08 09:28:11 2015 -0700
@@ -0,0 +1,435 @@
+/*
+ * Copyright (c) 2009, 2015, 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.amd64;
+
+import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.ADD;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.AND;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.OR;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.SUB;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.XOR;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSX;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSXB;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSXD;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.DWORD;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.QWORD;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.SD;
+import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.SS;
+import jdk.internal.jvmci.amd64.AMD64Kind;
+import jdk.internal.jvmci.common.JVMCIError;
+import jdk.internal.jvmci.meta.JavaConstant;
+import jdk.internal.jvmci.meta.JavaKind;
+import jdk.internal.jvmci.meta.LIRKind;
+import jdk.internal.jvmci.meta.PlatformKind;
+import jdk.internal.jvmci.meta.Value;
+
+import com.oracle.graal.asm.NumUtil;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
+import com.oracle.graal.asm.amd64.AMD64Assembler.SSEOp;
+import com.oracle.graal.compiler.common.calc.Condition;
+import com.oracle.graal.compiler.gen.NodeLIRBuilder;
+import com.oracle.graal.compiler.gen.NodeMatchRules;
+import com.oracle.graal.compiler.match.ComplexMatchResult;
+import com.oracle.graal.compiler.match.MatchRule;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.lir.LIRFrameState;
+import com.oracle.graal.lir.LabelRef;
+import com.oracle.graal.lir.amd64.AMD64AddressValue;
+import com.oracle.graal.lir.amd64.AMD64BinaryConsumer;
+import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp;
+import com.oracle.graal.lir.gen.LIRGeneratorTool;
+import com.oracle.graal.nodes.ConstantNode;
+import com.oracle.graal.nodes.DeoptimizingNode;
+import com.oracle.graal.nodes.IfNode;
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.calc.CompareNode;
+import com.oracle.graal.nodes.calc.FloatConvertNode;
+import com.oracle.graal.nodes.calc.LeftShiftNode;
+import com.oracle.graal.nodes.calc.NarrowNode;
+import com.oracle.graal.nodes.calc.ReinterpretNode;
+import com.oracle.graal.nodes.calc.SignExtendNode;
+import com.oracle.graal.nodes.calc.UnsignedRightShiftNode;
+import com.oracle.graal.nodes.calc.ZeroExtendNode;
+import com.oracle.graal.nodes.extended.UnsafeCastNode;
+import com.oracle.graal.nodes.memory.Access;
+import com.oracle.graal.nodes.memory.WriteNode;
+
+public class AMD64NodeMatchRules extends NodeMatchRules {
+
+    public AMD64NodeMatchRules(LIRGeneratorTool gen) {
+        super(gen);
+    }
+
+    protected LIRFrameState getState(Access access) {
+        if (access instanceof DeoptimizingNode) {
+            return state((DeoptimizingNode) access);
+        }
+        return null;
+    }
+
+    protected AMD64Kind getMemoryKind(Access access) {
+        return (AMD64Kind) gen.getLIRKind(access.asNode().stamp()).getPlatformKind();
+    }
+
+    protected OperandSize getMemorySize(Access access) {
+        switch (getMemoryKind(access)) {
+            case BYTE:
+                return OperandSize.BYTE;
+            case WORD:
+                return OperandSize.WORD;
+            case DWORD:
+                return OperandSize.DWORD;
+            case QWORD:
+                return OperandSize.QWORD;
+            case SINGLE:
+                return OperandSize.SS;
+            case DOUBLE:
+                return OperandSize.SD;
+            default:
+                throw JVMCIError.shouldNotReachHere("unsupported memory access type " + getMemoryKind(access));
+        }
+    }
+
+    protected ValueNode uncast(ValueNode value) {
+        if (value instanceof UnsafeCastNode) {
+            UnsafeCastNode cast = (UnsafeCastNode) value;
+            return cast.getOriginalNode();
+        }
+        return value;
+    }
+
+    protected ComplexMatchResult emitCompareBranchMemory(IfNode ifNode, CompareNode compare, ValueNode value, Access access) {
+        Condition cond = compare.condition();
+        AMD64Kind kind = getMemoryKind(access);
+
+        if (value.isConstant()) {
+            JavaConstant constant = value.asJavaConstant();
+            if (kind == AMD64Kind.QWORD && !NumUtil.isInt(constant.asLong())) {
+                // Only imm32 as long
+                return null;
+            }
+            if (kind.isXMM()) {
+                Debug.log("Skipping constant compares for float kinds");
+                return null;
+            }
+            if (constant.getJavaKind() == JavaKind.Object && !constant.isNull()) {
+                Debug.log("Skipping constant compares for Object kinds");
+                return null;
+            }
+        }
+
+        // emitCompareBranchMemory expects the memory on the right, so mirror the condition if
+        // that's not true. It might be mirrored again the actual compare is emitted but that's
+        // ok.
+        Condition finalCondition = uncast(compare.getX()) == access ? cond.mirror() : cond;
+        return new ComplexMatchResult() {
+            public Value evaluate(NodeLIRBuilder builder) {
+                LabelRef trueLabel = getLIRBlock(ifNode.trueSuccessor());
+                LabelRef falseLabel = getLIRBlock(ifNode.falseSuccessor());
+                boolean unorderedIsTrue = compare.unorderedIsTrue();
+                double trueLabelProbability = ifNode.probability(ifNode.trueSuccessor());
+                Value other;
+                if (value.isConstant()) {
+                    other = gen.emitJavaConstant(value.asJavaConstant());
+                } else {
+                    other = operand(value);
+                }
+
+                AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress());
+                getLIRGeneratorTool().emitCompareBranchMemory(kind, other, address, getState(access), finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability);
+                return null;
+            }
+        };
+    }
+
+    private ComplexMatchResult emitIntegerTestBranchMemory(IfNode x, ValueNode value, Access access) {
+        LabelRef trueLabel = getLIRBlock(x.trueSuccessor());
+        LabelRef falseLabel = getLIRBlock(x.falseSuccessor());
+        double trueLabelProbability = x.probability(x.trueSuccessor());
+        AMD64Kind kind = getMemoryKind(access);
+        OperandSize size = kind == AMD64Kind.QWORD ? QWORD : DWORD;
+        if (value.isConstant()) {
+            JavaConstant constant = value.asJavaConstant();
+            if (kind == AMD64Kind.QWORD && !NumUtil.isInt(constant.asLong())) {
+                // Only imm32 as long
+                return null;
+            }
+            return builder -> {
+                AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress());
+                gen.append(new AMD64BinaryConsumer.MemoryConstOp(AMD64MIOp.TEST, size, address, (int) constant.asLong(), getState(access)));
+                gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability));
+                return null;
+            };
+        } else {
+            return builder -> {
+                AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress());
+                gen.append(new AMD64BinaryConsumer.MemoryRMOp(AMD64RMOp.TEST, size, gen.asAllocatable(operand(value)), address, getState(access)));
+                gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability));
+                return null;
+            };
+        }
+    }
+
+    protected ComplexMatchResult emitConvertMemoryOp(PlatformKind kind, AMD64RMOp op, OperandSize size, Access access) {
+        return builder -> {
+            AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress());
+            LIRFrameState state = getState(access);
+            return getLIRGeneratorTool().emitConvertMemoryOp(kind, op, size, address, state);
+        };
+    }
+
+    private ComplexMatchResult emitSignExtendMemory(Access access, int fromBits, int toBits) {
+        assert fromBits <= toBits && toBits <= 64;
+        AMD64Kind kind = null;
+        AMD64RMOp op;
+        OperandSize size;
+        if (fromBits == toBits) {
+            return null;
+        } else if (toBits > 32) {
+            kind = AMD64Kind.QWORD;
+            size = OperandSize.QWORD;
+            // sign extend to 64 bits
+            switch (fromBits) {
+                case 8:
+                    op = MOVSXB;
+                    break;
+                case 16:
+                    op = MOVSX;
+                    break;
+                case 32:
+                    op = MOVSXD;
+                    break;
+                default:
+                    throw JVMCIError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
+            }
+        } else {
+            kind = AMD64Kind.DWORD;
+            size = OperandSize.DWORD;
+            // sign extend to 32 bits (smaller values are internally represented as 32 bit values)
+            switch (fromBits) {
+                case 8:
+                    op = MOVSXB;
+                    break;
+                case 16:
+                    op = MOVSX;
+                    break;
+                case 32:
+                    return null;
+                default:
+                    throw JVMCIError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
+            }
+        }
+        if (kind != null && op != null) {
+            return emitConvertMemoryOp(kind, op, size, access);
+        }
+        return null;
+    }
+
+    private Value emitReinterpretMemory(LIRKind to, Access access) {
+        AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress());
+        LIRFrameState state = getState(access);
+        return getLIRGeneratorTool().emitLoad(to, address, state);
+    }
+
+    @MatchRule("(If (IntegerTest Read=access value))")
+    @MatchRule("(If (IntegerTest FloatingRead=access value))")
+    public ComplexMatchResult integerTestBranchMemory(IfNode root, Access access, ValueNode value) {
+        return emitIntegerTestBranchMemory(root, value, access);
+    }
+
+    @MatchRule("(If (IntegerEquals=compare value Read=access))")
+    @MatchRule("(If (IntegerLessThan=compare value Read=access))")
+    @MatchRule("(If (IntegerBelow=compare value Read=access))")
+    @MatchRule("(If (IntegerEquals=compare value FloatingRead=access))")
+    @MatchRule("(If (IntegerLessThan=compare value FloatingRead=access))")
+    @MatchRule("(If (IntegerBelow=compare value FloatingRead=access))")
+    @MatchRule("(If (FloatEquals=compare value Read=access))")
+    @MatchRule("(If (FloatEquals=compare value FloatingRead=access))")
+    @MatchRule("(If (FloatLessThan=compare value Read=access))")
+    @MatchRule("(If (FloatLessThan=compare value FloatingRead=access))")
+    public ComplexMatchResult ifCompareMemory(IfNode root, CompareNode compare, ValueNode value, Access access) {
+        return emitCompareBranchMemory(root, compare, value, access);
+    }
+
+    @MatchRule("(Or (LeftShift=lshift value Constant) (UnsignedRightShift=rshift value Constant))")
+    public ComplexMatchResult rotateLeftConstant(LeftShiftNode lshift, UnsignedRightShiftNode rshift) {
+        if ((lshift.getShiftAmountMask() & (lshift.getY().asJavaConstant().asInt() + rshift.getY().asJavaConstant().asInt())) == 0) {
+            return builder -> getLIRGeneratorTool().emitRol(operand(lshift.getX()), operand(lshift.getY()));
+        }
+        return null;
+    }
+
+    @MatchRule("(Or (LeftShift value (Sub Constant=delta shiftAmount)) (UnsignedRightShift value shiftAmount))")
+    public ComplexMatchResult rotateRightVariable(ValueNode value, ConstantNode delta, ValueNode shiftAmount) {
+        if (delta.asJavaConstant().asLong() == 0 || delta.asJavaConstant().asLong() == 32) {
+            return builder -> getLIRGeneratorTool().emitRor(operand(value), operand(shiftAmount));
+        }
+        return null;
+    }
+
+    @MatchRule("(Or (LeftShift value shiftAmount) (UnsignedRightShift value (Sub Constant=delta shiftAmount)))")
+    public ComplexMatchResult rotateLeftVariable(ValueNode value, ValueNode shiftAmount, ConstantNode delta) {
+        if (delta.asJavaConstant().asLong() == 0 || delta.asJavaConstant().asLong() == 32) {
+            return builder -> getLIRGeneratorTool().emitRol(operand(value), operand(shiftAmount));
+        }
+        return null;
+    }
+
+    private ComplexMatchResult binaryRead(AMD64RMOp op, OperandSize size, ValueNode value, Access access) {
+        return builder -> getLIRGeneratorTool().emitBinaryMemory(op, size, getLIRGeneratorTool().asAllocatable(operand(value)), (AMD64AddressValue) operand(access.getAddress()), getState(access));
+    }
+
+    @MatchRule("(Add value Read=access)")
+    @MatchRule("(Add value FloatingRead=access)")
+    public ComplexMatchResult addMemory(ValueNode value, Access access) {
+        OperandSize size = getMemorySize(access);
+        if (size.isXmmType()) {
+            return binaryRead(SSEOp.ADD, size, value, access);
+        } else {
+            return binaryRead(ADD.getRMOpcode(size), size, value, access);
+        }
+    }
+
+    @MatchRule("(Sub value Read=access)")
+    @MatchRule("(Sub value FloatingRead=access)")
+    public ComplexMatchResult subMemory(ValueNode value, Access access) {
+        OperandSize size = getMemorySize(access);
+        if (size.isXmmType()) {
+            return binaryRead(SSEOp.SUB, size, value, access);
+        } else {
+            return binaryRead(SUB.getRMOpcode(size), size, value, access);
+        }
+    }
+
+    @MatchRule("(Mul value Read=access)")
+    @MatchRule("(Mul value FloatingRead=access)")
+    public ComplexMatchResult mulMemory(ValueNode value, Access access) {
+        OperandSize size = getMemorySize(access);
+        if (size.isXmmType()) {
+            return binaryRead(SSEOp.MUL, size, value, access);
+        } else {
+            return binaryRead(AMD64RMOp.IMUL, size, value, access);
+        }
+    }
+
+    @MatchRule("(And value Read=access)")
+    @MatchRule("(And value FloatingRead=access)")
+    public ComplexMatchResult andMemory(ValueNode value, Access access) {
+        OperandSize size = getMemorySize(access);
+        if (size.isXmmType()) {
+            return null;
+        } else {
+            return binaryRead(AND.getRMOpcode(size), size, value, access);
+        }
+    }
+
+    @MatchRule("(Or value Read=access)")
+    @MatchRule("(Or value FloatingRead=access)")
+    public ComplexMatchResult orMemory(ValueNode value, Access access) {
+        OperandSize size = getMemorySize(access);
+        if (size.isXmmType()) {
+            return null;
+        } else {
+            return binaryRead(OR.getRMOpcode(size), size, value, access);
+        }
+    }
+
+    @MatchRule("(Xor value Read=access)")
+    @MatchRule("(Xor value FloatingRead=access)")
+    public ComplexMatchResult xorMemory(ValueNode value, Access access) {
+        OperandSize size = getMemorySize(access);
+        if (size.isXmmType()) {
+            return null;
+        } else {
+            return binaryRead(XOR.getRMOpcode(size), size, value, access);
+        }
+    }
+
+    @MatchRule("(Write object Narrow=narrow)")
+    public ComplexMatchResult writeNarrow(WriteNode root, NarrowNode narrow) {
+        return builder -> {
+            LIRKind writeKind = getLIRGeneratorTool().getLIRKind(root.value().stamp());
+            getLIRGeneratorTool().emitStore(writeKind, operand(root.getAddress()), operand(narrow.getValue()), state(root));
+            return null;
+        };
+    }
+
+    @MatchRule("(SignExtend Read=access)")
+    @MatchRule("(SignExtend FloatingRead=access)")
+    public ComplexMatchResult signExtend(SignExtendNode root, Access access) {
+        return emitSignExtendMemory(access, root.getInputBits(), root.getResultBits());
+    }
+
+    @MatchRule("(ZeroExtend Read=access)")
+    @MatchRule("(ZeroExtend FloatingRead=access)")
+    public ComplexMatchResult zeroExtend(ZeroExtendNode root, Access access) {
+        AMD64Kind memoryKind = getMemoryKind(access);
+        return builder -> getLIRGeneratorTool().emitZeroExtendMemory(memoryKind, root.getResultBits(), (AMD64AddressValue) operand(access.getAddress()), getState(access));
+    }
+
+    @MatchRule("(FloatConvert Read=access)")
+    @MatchRule("(FloatConvert FloatingRead=access)")
+    public ComplexMatchResult floatConvert(FloatConvertNode root, Access access) {
+        switch (root.getFloatConvert()) {
+            case D2F:
+                return emitConvertMemoryOp(AMD64Kind.SINGLE, SSEOp.CVTSD2SS, SD, access);
+            case D2I:
+                return emitConvertMemoryOp(AMD64Kind.DWORD, SSEOp.CVTTSD2SI, DWORD, access);
+            case D2L:
+                return emitConvertMemoryOp(AMD64Kind.QWORD, SSEOp.CVTTSD2SI, QWORD, access);
+            case F2D:
+                return emitConvertMemoryOp(AMD64Kind.DOUBLE, SSEOp.CVTSS2SD, SS, access);
+            case F2I:
+                return emitConvertMemoryOp(AMD64Kind.DWORD, SSEOp.CVTTSS2SI, DWORD, access);
+            case F2L:
+                return emitConvertMemoryOp(AMD64Kind.QWORD, SSEOp.CVTTSS2SI, QWORD, access);
+            case I2D:
+                return emitConvertMemoryOp(AMD64Kind.DOUBLE, SSEOp.CVTSI2SD, DWORD, access);
+            case I2F:
+                return emitConvertMemoryOp(AMD64Kind.SINGLE, SSEOp.CVTSI2SS, DWORD, access);
+            case L2D:
+                return emitConvertMemoryOp(AMD64Kind.DOUBLE, SSEOp.CVTSI2SD, QWORD, access);
+            case L2F:
+                return emitConvertMemoryOp(AMD64Kind.SINGLE, SSEOp.CVTSI2SS, QWORD, access);
+            default:
+                throw JVMCIError.shouldNotReachHere();
+        }
+    }
+
+    @MatchRule("(Reinterpret Read=access)")
+    @MatchRule("(Reinterpret FloatingRead=access)")
+    public ComplexMatchResult reinterpret(ReinterpretNode root, Access access) {
+        return builder -> {
+            LIRKind kind = getLIRGeneratorTool().getLIRKind(root.stamp());
+            return emitReinterpretMemory(kind, access);
+        };
+
+    }
+
+    @Override
+    public AMD64LIRGenerator getLIRGeneratorTool() {
+        return (AMD64LIRGenerator) gen;
+    }
+}
--- a/graal/com.oracle.graal.compiler.match.processor/src/com/oracle/graal/compiler/match/processor/MatchProcessor.java	Thu Oct 08 17:24:58 2015 +0200
+++ b/graal/com.oracle.graal.compiler.match.processor/src/com/oracle/graal/compiler/match/processor/MatchProcessor.java	Thu Oct 08 09:28:11 2015 -0700
@@ -66,7 +66,7 @@
 import jdk.internal.jvmci.common.JVMCIError;
 import jdk.internal.jvmci.service.ServiceProvider;
 
-import com.oracle.graal.compiler.gen.NodeLIRBuilder;
+import com.oracle.graal.compiler.gen.NodeMatchRules;
 import com.oracle.graal.compiler.match.ComplexMatchResult;
 import com.oracle.graal.compiler.match.MatchRule;
 import com.oracle.graal.compiler.match.MatchRules;
@@ -520,7 +520,7 @@
             out.println("");
             out.println("import java.util.*;");
             out.println("import " + MatchStatementSet.class.getPackage().getName() + ".*;");
-            out.println("import " + NodeLIRBuilder.class.getName() + ";");
+            out.println("import " + NodeMatchRules.class.getName() + ";");
             out.println("import " + Position.class.getName() + ";");
             out.println("import " + ServiceProvider.class.getName() + ";");
             for (String p : info.requiredPackages) {
@@ -552,8 +552,8 @@
                 out.printf("    private static final String[] %s = new String[] {%s};\n", invoker.argumentsListName(), args);
                 out.printf("    private static final class %s implements MatchGenerator {\n", invoker.wrapperClass());
                 out.printf("        static MatchGenerator instance = new %s();\n", invoker.wrapperClass());
-                out.printf("        public ComplexMatchResult match(NodeLIRBuilder builder, Object...args) {\n");
-                out.printf("            return ((%s) builder).%s(%s);\n", invoker.nodeLIRBuilderClass, invoker.methodName, types);
+                out.printf("        public ComplexMatchResult match(NodeMatchRules nodeMatchRules, Object...args) {\n");
+                out.printf("            return ((%s) nodeMatchRules).%s(%s);\n", invoker.nodeLIRBuilderClass, invoker.methodName, types);
                 out.printf("        }\n");
                 out.printf("        public String getName() {\n");
                 out.printf("             return \"%s\";\n", invoker.methodName);
@@ -565,7 +565,7 @@
 
             String desc = MatchStatement.class.getSimpleName();
 
-            out.println("    public Class<? extends NodeLIRBuilder> forClass() {");
+            out.println("    public Class<? extends NodeMatchRules> forClass() {");
             out.println("        return " + topDeclaringClass + ".class;");
             out.println("    }");
             out.println();
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCNodeLIRBuilder.java	Thu Oct 08 17:24:58 2015 +0200
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCNodeLIRBuilder.java	Thu Oct 08 09:28:11 2015 -0700
@@ -23,41 +23,27 @@
 
 package com.oracle.graal.compiler.sparc;
 
-import static jdk.internal.jvmci.sparc.SPARCKind.BYTE;
-import static jdk.internal.jvmci.sparc.SPARCKind.DWORD;
-import static jdk.internal.jvmci.sparc.SPARCKind.HWORD;
-import static jdk.internal.jvmci.sparc.SPARCKind.WORD;
 import jdk.internal.jvmci.code.CallingConvention;
-import jdk.internal.jvmci.common.JVMCIError;
 import jdk.internal.jvmci.meta.JavaType;
-import jdk.internal.jvmci.meta.LIRKind;
 import jdk.internal.jvmci.meta.Value;
-import jdk.internal.jvmci.sparc.SPARCKind;
 
 import com.oracle.graal.compiler.gen.NodeLIRBuilder;
-import com.oracle.graal.compiler.match.ComplexMatchResult;
-import com.oracle.graal.compiler.match.MatchRule;
-import com.oracle.graal.lir.LIRFrameState;
 import com.oracle.graal.lir.LabelRef;
 import com.oracle.graal.lir.StandardOp.JumpOp;
 import com.oracle.graal.lir.gen.LIRGeneratorTool;
 import com.oracle.graal.lir.sparc.SPARCBreakpointOp;
 import com.oracle.graal.lir.sparc.SPARCJumpOp;
 import com.oracle.graal.nodes.BreakpointNode;
-import com.oracle.graal.nodes.DeoptimizingNode;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.ValueNode;
-import com.oracle.graal.nodes.calc.SignExtendNode;
-import com.oracle.graal.nodes.calc.ZeroExtendNode;
-import com.oracle.graal.nodes.memory.Access;
 
 /**
  * This class implements the SPARC specific portion of the LIR generator.
  */
 public abstract class SPARCNodeLIRBuilder extends NodeLIRBuilder {
 
-    public SPARCNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
-        super(graph, lirGen);
+    public SPARCNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen, SPARCNodeMatchRules nodeMatchRules) {
+        super(graph, lirGen, nodeMatchRules);
     }
 
     @Override
@@ -83,94 +69,6 @@
         return new SPARCJumpOp(ref);
     }
 
-    protected LIRFrameState getState(Access access) {
-        if (access instanceof DeoptimizingNode) {
-            return state((DeoptimizingNode) access);
-        }
-        return null;
-    }
-
-    private ComplexMatchResult emitSignExtendMemory(Access access, int fromBits, int toBits) {
-        assert fromBits <= toBits && toBits <= 64;
-        SPARCKind toKind = null;
-        SPARCKind fromKind = null;
-        if (fromBits == toBits) {
-            return null;
-        } else if (toBits > WORD.getSizeInBits()) {
-            toKind = DWORD;
-        } else if (toBits > HWORD.getSizeInBits()) {
-            toKind = WORD;
-        } else if (toBits > BYTE.getSizeInBits()) {
-            toKind = HWORD;
-        }
-        switch (fromBits) {
-            case 8:
-                fromKind = BYTE;
-                break;
-            case 16:
-                fromKind = HWORD;
-                break;
-            case 32:
-                fromKind = WORD;
-                break;
-            default:
-                throw JVMCIError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
-        }
-        SPARCKind localFromKind = fromKind;
-        SPARCKind localToKind = toKind;
-        return builder -> {
-            Value v = getLIRGeneratorTool().emitSignExtendLoad(LIRKind.value(localFromKind), operand(access.getAddress()), getState(access));
-            return getLIRGeneratorTool().emitReinterpret(LIRKind.value(localToKind), v);
-        };
-    }
-
-    private ComplexMatchResult emitZeroExtendMemory(Access access, int fromBits, int toBits) {
-        assert fromBits <= toBits && toBits <= 64;
-        SPARCKind toKind = null;
-        SPARCKind fromKind = null;
-        if (fromBits == toBits) {
-            return null;
-        } else if (toBits > WORD.getSizeInBits()) {
-            toKind = DWORD;
-        } else if (toBits > HWORD.getSizeInBits()) {
-            toKind = WORD;
-        } else if (toBits > BYTE.getSizeInBits()) {
-            toKind = HWORD;
-        }
-        switch (fromBits) {
-            case 8:
-                fromKind = BYTE;
-                break;
-            case 16:
-                fromKind = HWORD;
-                break;
-            case 32:
-                fromKind = WORD;
-                break;
-            default:
-                throw JVMCIError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
-        }
-        SPARCKind localFromKind = fromKind;
-        SPARCKind localToKind = toKind;
-        return builder -> {
-            // Loads are always zero extending load
-            Value v = getLIRGeneratorTool().emitLoad(LIRKind.value(localFromKind), operand(access.getAddress()), getState(access));
-            return getLIRGeneratorTool().emitReinterpret(LIRKind.value(localToKind), v);
-        };
-    }
-
-    @MatchRule("(SignExtend Read=access)")
-    @MatchRule("(SignExtend FloatingRead=access)")
-    public ComplexMatchResult signExtend(SignExtendNode root, Access access) {
-        return emitSignExtendMemory(access, root.getInputBits(), root.getResultBits());
-    }
-
-    @MatchRule("(ZeroExtend Read=access)")
-    @MatchRule("(ZeroExtend FloatingRead=access)")
-    public ComplexMatchResult zeroExtend(ZeroExtendNode root, Access access) {
-        return emitZeroExtendMemory(access, root.getInputBits(), root.getResultBits());
-    }
-
     @Override
     public SPARCLIRGenerator getLIRGeneratorTool() {
         return (SPARCLIRGenerator) super.getLIRGeneratorTool();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCNodeMatchRules.java	Thu Oct 08 09:28:11 2015 -0700
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2009, 2015, 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.sparc;
+
+import static jdk.internal.jvmci.sparc.SPARCKind.BYTE;
+import static jdk.internal.jvmci.sparc.SPARCKind.DWORD;
+import static jdk.internal.jvmci.sparc.SPARCKind.HWORD;
+import static jdk.internal.jvmci.sparc.SPARCKind.WORD;
+import jdk.internal.jvmci.common.JVMCIError;
+import jdk.internal.jvmci.meta.LIRKind;
+import jdk.internal.jvmci.meta.Value;
+import jdk.internal.jvmci.sparc.SPARCKind;
+
+import com.oracle.graal.compiler.gen.NodeMatchRules;
+import com.oracle.graal.compiler.match.ComplexMatchResult;
+import com.oracle.graal.compiler.match.MatchRule;
+import com.oracle.graal.lir.LIRFrameState;
+import com.oracle.graal.lir.gen.LIRGeneratorTool;
+import com.oracle.graal.nodes.DeoptimizingNode;
+import com.oracle.graal.nodes.calc.SignExtendNode;
+import com.oracle.graal.nodes.calc.ZeroExtendNode;
+import com.oracle.graal.nodes.memory.Access;
+
+/**
+ * This class implements the SPARC specific portion of the LIR generator.
+ */
+public class SPARCNodeMatchRules extends NodeMatchRules {
+
+    public SPARCNodeMatchRules(LIRGeneratorTool gen) {
+        super(gen);
+    }
+
+    protected LIRFrameState getState(Access access) {
+        if (access instanceof DeoptimizingNode) {
+            return state((DeoptimizingNode) access);
+        }
+        return null;
+    }
+
+    private ComplexMatchResult emitSignExtendMemory(Access access, int fromBits, int toBits) {
+        assert fromBits <= toBits && toBits <= 64;
+        SPARCKind toKind = null;
+        SPARCKind fromKind = null;
+        if (fromBits == toBits) {
+            return null;
+        } else if (toBits > WORD.getSizeInBits()) {
+            toKind = DWORD;
+        } else if (toBits > HWORD.getSizeInBits()) {
+            toKind = WORD;
+        } else if (toBits > BYTE.getSizeInBits()) {
+            toKind = HWORD;
+        }
+        switch (fromBits) {
+            case 8:
+                fromKind = BYTE;
+                break;
+            case 16:
+                fromKind = HWORD;
+                break;
+            case 32:
+                fromKind = WORD;
+                break;
+            default:
+                throw JVMCIError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
+        }
+        SPARCKind localFromKind = fromKind;
+        SPARCKind localToKind = toKind;
+        return builder -> {
+            Value v = getLIRGeneratorTool().emitSignExtendLoad(LIRKind.value(localFromKind), operand(access.getAddress()), getState(access));
+            return getLIRGeneratorTool().emitReinterpret(LIRKind.value(localToKind), v);
+        };
+    }
+
+    private ComplexMatchResult emitZeroExtendMemory(Access access, int fromBits, int toBits) {
+        assert fromBits <= toBits && toBits <= 64;
+        SPARCKind toKind = null;
+        SPARCKind fromKind = null;
+        if (fromBits == toBits) {
+            return null;
+        } else if (toBits > WORD.getSizeInBits()) {
+            toKind = DWORD;
+        } else if (toBits > HWORD.getSizeInBits()) {
+            toKind = WORD;
+        } else if (toBits > BYTE.getSizeInBits()) {
+            toKind = HWORD;
+        }
+        switch (fromBits) {
+            case 8:
+                fromKind = BYTE;
+                break;
+            case 16:
+                fromKind = HWORD;
+                break;
+            case 32:
+                fromKind = WORD;
+                break;
+            default:
+                throw JVMCIError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
+        }
+        SPARCKind localFromKind = fromKind;
+        SPARCKind localToKind = toKind;
+        return builder -> {
+            // Loads are always zero extending load
+            Value v = getLIRGeneratorTool().emitLoad(LIRKind.value(localFromKind), operand(access.getAddress()), getState(access));
+            return getLIRGeneratorTool().emitReinterpret(LIRKind.value(localToKind), v);
+        };
+    }
+
+    @MatchRule("(SignExtend Read=access)")
+    @MatchRule("(SignExtend FloatingRead=access)")
+    public ComplexMatchResult signExtend(SignExtendNode root, Access access) {
+        return emitSignExtendMemory(access, root.getInputBits(), root.getResultBits());
+    }
+
+    @MatchRule("(ZeroExtend Read=access)")
+    @MatchRule("(ZeroExtend FloatingRead=access)")
+    public ComplexMatchResult zeroExtend(ZeroExtendNode root, Access access) {
+        return emitZeroExtendMemory(access, root.getInputBits(), root.getResultBits());
+    }
+
+    @Override
+    public SPARCLIRGenerator getLIRGeneratorTool() {
+        return (SPARCLIRGenerator) super.getLIRGeneratorTool();
+    }
+}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Thu Oct 08 17:24:58 2015 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Thu Oct 08 09:28:11 2015 -0700
@@ -54,7 +54,6 @@
 import com.oracle.graal.compiler.match.ComplexMatchValue;
 import com.oracle.graal.compiler.match.MatchRuleRegistry;
 import com.oracle.graal.compiler.match.MatchStatement;
-import com.oracle.graal.compiler.match.MatchableNode;
 import com.oracle.graal.debug.Debug;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.TTY;
@@ -79,7 +78,6 @@
 import com.oracle.graal.nodes.AbstractBeginNode;
 import com.oracle.graal.nodes.AbstractEndNode;
 import com.oracle.graal.nodes.AbstractMergeNode;
-import com.oracle.graal.nodes.ConstantNode;
 import com.oracle.graal.nodes.DeoptimizingNode;
 import com.oracle.graal.nodes.DirectCallTargetNode;
 import com.oracle.graal.nodes.FixedNode;
@@ -95,41 +93,18 @@
 import com.oracle.graal.nodes.LoweredCallTargetNode;
 import com.oracle.graal.nodes.ParameterNode;
 import com.oracle.graal.nodes.PhiNode;
-import com.oracle.graal.nodes.PiNode;
 import com.oracle.graal.nodes.SimpleInfopointNode;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.nodes.ValueNode;
 import com.oracle.graal.nodes.ValuePhiNode;
-import com.oracle.graal.nodes.calc.AddNode;
-import com.oracle.graal.nodes.calc.AndNode;
 import com.oracle.graal.nodes.calc.CompareNode;
 import com.oracle.graal.nodes.calc.ConditionalNode;
-import com.oracle.graal.nodes.calc.FloatConvertNode;
-import com.oracle.graal.nodes.calc.FloatEqualsNode;
-import com.oracle.graal.nodes.calc.FloatLessThanNode;
-import com.oracle.graal.nodes.calc.IntegerBelowNode;
-import com.oracle.graal.nodes.calc.IntegerEqualsNode;
-import com.oracle.graal.nodes.calc.IntegerLessThanNode;
 import com.oracle.graal.nodes.calc.IntegerTestNode;
 import com.oracle.graal.nodes.calc.IsNullNode;
-import com.oracle.graal.nodes.calc.LeftShiftNode;
-import com.oracle.graal.nodes.calc.MulNode;
-import com.oracle.graal.nodes.calc.NarrowNode;
-import com.oracle.graal.nodes.calc.ObjectEqualsNode;
-import com.oracle.graal.nodes.calc.OrNode;
-import com.oracle.graal.nodes.calc.ReinterpretNode;
-import com.oracle.graal.nodes.calc.SignExtendNode;
-import com.oracle.graal.nodes.calc.SubNode;
-import com.oracle.graal.nodes.calc.UnsignedRightShiftNode;
-import com.oracle.graal.nodes.calc.XorNode;
-import com.oracle.graal.nodes.calc.ZeroExtendNode;
 import com.oracle.graal.nodes.cfg.Block;
 import com.oracle.graal.nodes.cfg.ControlFlowGraph;
 import com.oracle.graal.nodes.extended.IntegerSwitchNode;
 import com.oracle.graal.nodes.extended.SwitchNode;
-import com.oracle.graal.nodes.memory.FloatingReadNode;
-import com.oracle.graal.nodes.memory.ReadNode;
-import com.oracle.graal.nodes.memory.WriteNode;
 import com.oracle.graal.nodes.spi.ArithmeticLIRLowerable;
 import com.oracle.graal.nodes.spi.LIRLowerable;
 import com.oracle.graal.nodes.spi.NodeLIRBuilderTool;
@@ -139,32 +114,6 @@
 /**
  * This class traverses the HIR instructions and generates LIR instructions from them.
  */
-@MatchableNode(nodeClass = ConstantNode.class, shareable = true)
-@MatchableNode(nodeClass = FloatConvertNode.class, inputs = {"value"})
-@MatchableNode(nodeClass = FloatingReadNode.class, inputs = {"address"})
-@MatchableNode(nodeClass = IfNode.class, inputs = {"condition"})
-@MatchableNode(nodeClass = SubNode.class, inputs = {"x", "y"})
-@MatchableNode(nodeClass = LeftShiftNode.class, inputs = {"x", "y"})
-@MatchableNode(nodeClass = NarrowNode.class, inputs = {"value"})
-@MatchableNode(nodeClass = ReadNode.class, inputs = {"address"})
-@MatchableNode(nodeClass = ReinterpretNode.class, inputs = {"value"})
-@MatchableNode(nodeClass = SignExtendNode.class, inputs = {"value"})
-@MatchableNode(nodeClass = UnsignedRightShiftNode.class, inputs = {"x", "y"})
-@MatchableNode(nodeClass = WriteNode.class, inputs = {"address", "value"})
-@MatchableNode(nodeClass = ZeroExtendNode.class, inputs = {"value"})
-@MatchableNode(nodeClass = AndNode.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 = AddNode.class, inputs = {"x", "y"}, commutative = true)
-@MatchableNode(nodeClass = IntegerBelowNode.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 = MulNode.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"})
 public abstract class NodeLIRBuilder implements NodeLIRBuilderTool, LIRGenerationDebugContext {
 
     private final NodeMap<Value> nodeOperands;
@@ -175,15 +124,24 @@
     private ValueNode currentInstruction;
     private ValueNode lastInstructionPrinted; // Debugging only
 
+    private final NodeMatchRules nodeMatchRules;
     private Map<Class<? extends Node>, List<MatchStatement>> matchRules;
 
-    public NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen) {
+    public NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen, NodeMatchRules nodeMatchRules) {
         this.gen = gen;
+        this.nodeMatchRules = nodeMatchRules;
         this.nodeOperands = graph.createNodeMap();
         this.debugInfoBuilder = createDebugInfoBuilder(graph, this);
         if (MatchExpressions.getValue()) {
-            matchRules = MatchRuleRegistry.lookup(getClass());
+            matchRules = MatchRuleRegistry.lookup(nodeMatchRules.getClass());
         }
+
+        assert nodeMatchRules.lirBuilder == null;
+        nodeMatchRules.lirBuilder = this;
+    }
+
+    public NodeMatchRules getNodeMatchRules() {
+        return nodeMatchRules;
     }
 
     @SuppressWarnings({"unused"})
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeMatchRules.java	Thu Oct 08 09:28:11 2015 -0700
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2009, 2015, 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.gen;
+
+import jdk.internal.jvmci.meta.Value;
+
+import com.oracle.graal.compiler.match.MatchableNode;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.lir.LIRFrameState;
+import com.oracle.graal.lir.LIRInstruction;
+import com.oracle.graal.lir.LabelRef;
+import com.oracle.graal.lir.gen.LIRGeneratorTool;
+import com.oracle.graal.nodes.ConstantNode;
+import com.oracle.graal.nodes.DeoptimizingNode;
+import com.oracle.graal.nodes.FixedNode;
+import com.oracle.graal.nodes.IfNode;
+import com.oracle.graal.nodes.PiNode;
+import com.oracle.graal.nodes.calc.AddNode;
+import com.oracle.graal.nodes.calc.AndNode;
+import com.oracle.graal.nodes.calc.FloatConvertNode;
+import com.oracle.graal.nodes.calc.FloatEqualsNode;
+import com.oracle.graal.nodes.calc.FloatLessThanNode;
+import com.oracle.graal.nodes.calc.IntegerBelowNode;
+import com.oracle.graal.nodes.calc.IntegerEqualsNode;
+import com.oracle.graal.nodes.calc.IntegerLessThanNode;
+import com.oracle.graal.nodes.calc.IntegerTestNode;
+import com.oracle.graal.nodes.calc.LeftShiftNode;
+import com.oracle.graal.nodes.calc.MulNode;
+import com.oracle.graal.nodes.calc.NarrowNode;
+import com.oracle.graal.nodes.calc.ObjectEqualsNode;
+import com.oracle.graal.nodes.calc.OrNode;
+import com.oracle.graal.nodes.calc.ReinterpretNode;
+import com.oracle.graal.nodes.calc.SignExtendNode;
+import com.oracle.graal.nodes.calc.SubNode;
+import com.oracle.graal.nodes.calc.UnsignedRightShiftNode;
+import com.oracle.graal.nodes.calc.XorNode;
+import com.oracle.graal.nodes.calc.ZeroExtendNode;
+import com.oracle.graal.nodes.memory.FloatingReadNode;
+import com.oracle.graal.nodes.memory.ReadNode;
+import com.oracle.graal.nodes.memory.WriteNode;
+
+@MatchableNode(nodeClass = ConstantNode.class, shareable = true)
+@MatchableNode(nodeClass = FloatConvertNode.class, inputs = {"value"})
+@MatchableNode(nodeClass = FloatingReadNode.class, inputs = {"address"})
+@MatchableNode(nodeClass = IfNode.class, inputs = {"condition"})
+@MatchableNode(nodeClass = SubNode.class, inputs = {"x", "y"})
+@MatchableNode(nodeClass = LeftShiftNode.class, inputs = {"x", "y"})
+@MatchableNode(nodeClass = NarrowNode.class, inputs = {"value"})
+@MatchableNode(nodeClass = ReadNode.class, inputs = {"address"})
+@MatchableNode(nodeClass = ReinterpretNode.class, inputs = {"value"})
+@MatchableNode(nodeClass = SignExtendNode.class, inputs = {"value"})
+@MatchableNode(nodeClass = UnsignedRightShiftNode.class, inputs = {"x", "y"})
+@MatchableNode(nodeClass = WriteNode.class, inputs = {"address", "value"})
+@MatchableNode(nodeClass = ZeroExtendNode.class, inputs = {"value"})
+@MatchableNode(nodeClass = AndNode.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 = AddNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = IntegerBelowNode.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 = MulNode.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"})
+public abstract class NodeMatchRules {
+
+    NodeLIRBuilder lirBuilder;
+    protected final LIRGeneratorTool gen;
+
+    protected NodeMatchRules(LIRGeneratorTool gen) {
+        this.gen = gen;
+    }
+
+    protected LIRGeneratorTool getLIRGeneratorTool() {
+        return gen;
+    }
+
+    /*
+     * For now we do not want to expose the full lirBuilder to subclasses, so we delegate the few
+     * methods that are actually needed. If the list grows too long, exposing lirBuilder might be
+     * the better approach.
+     */
+
+    protected final Value operand(Node node) {
+        return lirBuilder.operand(node);
+    }
+
+    protected final LIRFrameState state(DeoptimizingNode deopt) {
+        return lirBuilder.state(deopt);
+    }
+
+    protected final LabelRef getLIRBlock(FixedNode b) {
+        return lirBuilder.getLIRBlock(b);
+    }
+
+    protected final void append(LIRInstruction op) {
+        lirBuilder.append(op);
+    }
+}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchGenerator.java	Thu Oct 08 17:24:58 2015 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchGenerator.java	Thu Oct 08 09:28:11 2015 -0700
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.compiler.match;
 
-import com.oracle.graal.compiler.gen.NodeLIRBuilder;
+import com.oracle.graal.compiler.gen.NodeMatchRules;
 
 /**
  * Code generator for complex match patterns.
@@ -32,7 +32,7 @@
      * @returns null if the match can't be generated or a {@link ComplexMatchResult} that can be
      *          evaluated during LIR generation to produce the final LIR value.
      */
-    ComplexMatchResult match(NodeLIRBuilder gen, Object... args);
+    ComplexMatchResult match(NodeMatchRules matchRules, Object... args);
 
     /**
      * @return a descriptive name meaningful to the user.
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java	Thu Oct 08 17:24:58 2015 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java	Thu Oct 08 09:28:11 2015 -0700
@@ -33,7 +33,7 @@
 import jdk.internal.jvmci.common.JVMCIError;
 import jdk.internal.jvmci.service.Services;
 
-import com.oracle.graal.compiler.gen.NodeLIRBuilder;
+import com.oracle.graal.compiler.gen.NodeMatchRules;
 import com.oracle.graal.debug.Debug;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.Edges;
@@ -68,7 +68,7 @@
         return result;
     }
 
-    private static final HashMap<Class<? extends NodeLIRBuilder>, Map<Class<? extends Node>, List<MatchStatement>>> registry = new HashMap<>();
+    private static final HashMap<Class<? extends NodeMatchRules>, Map<Class<? extends Node>, List<MatchStatement>>> registry = new HashMap<>();
 
     /**
      * Collect all the {@link MatchStatement}s defined by the superclass chain of theClass.
@@ -77,7 +77,7 @@
      * @return the set of {@link MatchStatement}s applicable to theClass.
      */
     @SuppressWarnings("try")
-    public static synchronized Map<Class<? extends Node>, List<MatchStatement>> lookup(Class<? extends NodeLIRBuilder> theClass) {
+    public static synchronized Map<Class<? extends Node>, List<MatchStatement>> lookup(Class<? extends NodeMatchRules> theClass) {
         Map<Class<? extends Node>, List<MatchStatement>> result = registry.get(theClass);
 
         if (result == null) {
@@ -109,8 +109,8 @@
      * This is a separate, public method so that external clients can create rules with a custom
      * lookup and without the default caching behavior.
      */
-    public static Map<Class<? extends Node>, List<MatchStatement>> createRules(Class<? extends NodeLIRBuilder> theClass) {
-        HashMap<Class<? extends NodeLIRBuilder>, MatchStatementSet> matchSets = new HashMap<>();
+    public static Map<Class<? extends Node>, List<MatchStatement>> createRules(Class<? extends NodeMatchRules> theClass) {
+        HashMap<Class<? extends NodeMatchRules>, MatchStatementSet> matchSets = new HashMap<>();
         Iterable<MatchStatementSet> sl = Services.load(MatchStatementSet.class);
         for (MatchStatementSet rules : sl) {
             matchSets.put(rules.forClass(), rules);
@@ -135,7 +135,7 @@
                 }
             }
             currentClass = currentClass.getSuperclass();
-        } while (currentClass != NodeLIRBuilder.class);
+        } while (currentClass != NodeMatchRules.class);
         return rules;
     }
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java	Thu Oct 08 17:24:58 2015 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java	Thu Oct 08 09:28:11 2015 -0700
@@ -94,7 +94,7 @@
         result = pattern.matchUsage(node, context);
         if (result == Result.OK) {
             // Invoke the generator method and set the result if it's non null.
-            ComplexMatchResult value = generatorMethod.match(builder, buildArgList(context));
+            ComplexMatchResult value = generatorMethod.match(builder.getNodeMatchRules(), buildArgList(context));
             if (value != null) {
                 context.setResult(value);
                 MatchStatementSuccess.increment();
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatementSet.java	Thu Oct 08 17:24:58 2015 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatementSet.java	Thu Oct 08 09:28:11 2015 -0700
@@ -25,13 +25,14 @@
 import java.util.List;
 
 import com.oracle.graal.compiler.gen.NodeLIRBuilder;
+import com.oracle.graal.compiler.gen.NodeMatchRules;
 
 public interface MatchStatementSet {
     /**
      * @return the {@link NodeLIRBuilder} subclass which defined this set of {@link MatchStatement}
      *         instances.
      */
-    Class<? extends NodeLIRBuilder> forClass();
+    Class<? extends NodeMatchRules> forClass();
 
     /**
      * @return the {@link MatchStatement}s available for this {@link NodeLIRBuilder} subclass.
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Thu Oct 08 17:24:58 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Thu Oct 08 09:28:11 2015 -0700
@@ -50,6 +50,7 @@
 import com.oracle.graal.asm.amd64.AMD64Address;
 import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag;
 import com.oracle.graal.asm.amd64.AMD64MacroAssembler;
+import com.oracle.graal.compiler.amd64.AMD64NodeMatchRules;
 import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
 import com.oracle.graal.compiler.gen.BytecodeLIRBuilder;
 import com.oracle.graal.compiler.gen.BytecodeParserTool;
@@ -105,7 +106,7 @@
 
     @Override
     public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
-        return new AMD64HotSpotNodeLIRBuilder(graph, lirGen);
+        return new AMD64HotSpotNodeLIRBuilder(graph, lirGen, new AMD64NodeMatchRules(lirGen));
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Thu Oct 08 17:24:58 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Thu Oct 08 09:28:11 2015 -0700
@@ -40,6 +40,7 @@
 import jdk.internal.jvmci.meta.Value;
 
 import com.oracle.graal.compiler.amd64.AMD64NodeLIRBuilder;
+import com.oracle.graal.compiler.amd64.AMD64NodeMatchRules;
 import com.oracle.graal.compiler.common.spi.ForeignCallLinkage;
 import com.oracle.graal.compiler.gen.DebugInfoBuilder;
 import com.oracle.graal.debug.Debug;
@@ -68,8 +69,8 @@
  */
 public class AMD64HotSpotNodeLIRBuilder extends AMD64NodeLIRBuilder implements HotSpotNodeLIRBuilder {
 
-    public AMD64HotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen) {
-        super(graph, gen);
+    public AMD64HotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen, AMD64NodeMatchRules nodeMatchRules) {
+        super(graph, gen, nodeMatchRules);
         assert gen instanceof AMD64HotSpotLIRGenerator;
         assert getDebugInfoBuilder() instanceof HotSpotDebugInfoBuilder;
         ((AMD64HotSpotLIRGenerator) gen).setLockStack(((HotSpotDebugInfoBuilder) getDebugInfoBuilder()).lockStack());
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Thu Oct 08 17:24:58 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Thu Oct 08 09:28:11 2015 -0700
@@ -64,6 +64,7 @@
 import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx;
 import com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig;
 import com.oracle.graal.compiler.common.cfg.AbstractBlockBase;
+import com.oracle.graal.compiler.sparc.SPARCNodeMatchRules;
 import com.oracle.graal.debug.Debug;
 import com.oracle.graal.debug.DebugMetric;
 import com.oracle.graal.hotspot.HotSpotGraalRuntimeProvider;
@@ -144,7 +145,7 @@
 
     @Override
     public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
-        return new SPARCHotSpotNodeLIRBuilder(graph, lirGen);
+        return new SPARCHotSpotNodeLIRBuilder(graph, lirGen, new SPARCNodeMatchRules(lirGen));
     }
 
     /**
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java	Thu Oct 08 17:24:58 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java	Thu Oct 08 09:28:11 2015 -0700
@@ -39,6 +39,7 @@
 import com.oracle.graal.compiler.common.spi.ForeignCallLinkage;
 import com.oracle.graal.compiler.gen.DebugInfoBuilder;
 import com.oracle.graal.compiler.sparc.SPARCNodeLIRBuilder;
+import com.oracle.graal.compiler.sparc.SPARCNodeMatchRules;
 import com.oracle.graal.debug.Debug;
 import com.oracle.graal.hotspot.HotSpotDebugInfoBuilder;
 import com.oracle.graal.hotspot.HotSpotLockStack;
@@ -61,8 +62,8 @@
 
 public class SPARCHotSpotNodeLIRBuilder extends SPARCNodeLIRBuilder implements HotSpotNodeLIRBuilder {
 
-    public SPARCHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
-        super(graph, lirGen);
+    public SPARCHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen, SPARCNodeMatchRules nodeMatchRules) {
+        super(graph, lirGen, nodeMatchRules);
         assert gen instanceof SPARCHotSpotLIRGenerator;
         assert getDebugInfoBuilder() instanceof HotSpotDebugInfoBuilder;
         ((SPARCHotSpotLIRGenerator) gen).setLockStack(((HotSpotDebugInfoBuilder) getDebugInfoBuilder()).lockStack());