# HG changeset patch # User Thomas Wuerthinger # Date 1399368863 -7200 # Node ID fd47de8808fc9271ceb9f3b7d1699903b8fbd3b5 # Parent a71192a503feecb38363a18325f4810db2ea6843# Parent 44d700e2fabaa5498024dc760ebaca74b2ceecf9 Merge. diff -r a71192a503fe -r fd47de8808fc graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java --- 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; diff -r a71192a503fe -r fd47de8808fc graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java --- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java 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()); diff -r a71192a503fe -r fd47de8808fc graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java 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 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 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 statements = matchRules.get(node.getClass()); if (statements != null) { diff -r a71192a503fe -r fd47de8808fc graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/GraalMatchableNodes.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/GraalMatchableNodes.java 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(); } } } diff -r a71192a503fe -r fd47de8808fc graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchContext.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchContext.java 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); diff -r a71192a503fe -r fd47de8808fc graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchNodeAdapter.java --- 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(); } } diff -r a71192a503fe -r fd47de8808fc graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java 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 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 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 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 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 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(); + } } } } diff -r a71192a503fe -r fd47de8808fc graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java 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 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 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 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 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 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 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 map, Element element) { + private void processMatchRule(Map 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 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 List getAnnotationValueList(Class expectedListType, AnnotationMirror mirror, String name) { + List values = getAnnotationValue(List.class, mirror, name); + List 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 getAnnotationValue(Class expectedType, AnnotationMirror mirror, String name) { + return resolveAnnotationValue(expectedType, getAnnotationValue(mirror, name)); + } + + @SuppressWarnings({"unchecked"}) + private static T resolveAnnotationValue(Class 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 { + + @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 vals, Void p) { + return vals; + } + + } } diff -r a71192a503fe -r fd47de8808fc graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRule.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRule.java 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. * *
- *   NAME := [a-z][a-zA-Z0-9]*
- *   NODETYPE := [A-Z][a-zA-Z0-9]*
- *   NODEORNAME :=  NODE [ = NAME ] | NAME
- *   EXPRESSION := ( NODEORNAME [ EXPRESSION | NODEORNAME [ EXPRESSION | NODEORNAME ] )
+ *   <node-name>    := [a-z][a-zA-Z0-9]*
+ *   <node-type>    := [A-Z][a-zA-Z0-9]*
+ *   <node-spec>    := <node-type> { '=' <node-name> }
+ *   <node-or-name> := <node-spec> | <node-name>
+ *   <argument>     := <node-or-name> | <match-rule>
+ *   <match-rule>   := '(' <node-spec> <argument>+ ')'
  * 
* * All matched nodes except the root of the match and {@link ConstantNode}s must have a single user. diff -r a71192a503fe -r fd47de8808fc graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java 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 { diff -r a71192a503fe -r fd47de8808fc graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java 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); } diff -r a71192a503fe -r fd47de8808fc graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNode.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchableNode.java 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; } diff -r a71192a503fe -r fd47de8808fc graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java 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; }; } diff -r a71192a503fe -r fd47de8808fc graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java --- 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) { diff -r a71192a503fe -r fd47de8808fc graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotMatchableNodes.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotMatchableNodes.java 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(); } } diff -r a71192a503fe -r fd47de8808fc graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java --- 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 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 */