001/* 002 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.compiler.match; 024 025import static com.oracle.graal.debug.GraalDebugConfig.*; 026 027import java.util.*; 028 029import com.oracle.graal.debug.*; 030import jdk.internal.jvmci.meta.*; 031 032import com.oracle.graal.compiler.gen.*; 033import com.oracle.graal.compiler.match.MatchPattern.MatchResultCode; 034import com.oracle.graal.compiler.match.MatchPattern.Result; 035import com.oracle.graal.graph.*; 036import com.oracle.graal.nodeinfo.*; 037 038/** 039 * A named {@link MatchPattern} along with a {@link MatchGenerator} that can be evaluated to replace 040 * one or more {@link Node}s with a single {@link Value}. 041 */ 042 043public class MatchStatement { 044 private static final DebugMetric MatchStatementSuccess = Debug.metric("MatchStatementSuccess"); 045 046 /** 047 * A printable name for this statement. Usually it's just the name of the method doing the 048 * emission. 049 */ 050 private final String name; 051 052 /** 053 * The actual match pattern. 054 */ 055 private final MatchPattern pattern; 056 057 /** 058 * The method in the {@link NodeLIRBuilder} subclass that will actually do the code emission. 059 */ 060 private MatchGenerator generatorMethod; 061 062 /** 063 * The name of arguments in the order they are expected to be passed to the generator method. 064 */ 065 private String[] arguments; 066 067 public MatchStatement(String name, MatchPattern pattern, MatchGenerator generator, String[] arguments) { 068 this.name = name; 069 this.pattern = pattern; 070 this.generatorMethod = generator; 071 this.arguments = arguments; 072 } 073 074 /** 075 * Attempt to match the current statement against a Node. 076 * 077 * @param builder the current builder instance. 078 * @param node the node to be matched 079 * @param nodes the nodes in the current block 080 * @return true if the statement matched something and set a {@link ComplexMatchResult} to be 081 * evaluated by the NodeLIRBuilder. 082 */ 083 public boolean generate(NodeLIRBuilder builder, int index, Node node, List<Node> nodes) { 084 assert index == nodes.indexOf(node); 085 // Check that the basic shape matches 086 Result result = pattern.matchShape(node, this); 087 if (result != Result.OK) { 088 return false; 089 } 090 // Now ensure that the other safety constraints are matched. 091 MatchContext context = new MatchContext(builder, this, index, node, nodes); 092 result = pattern.matchUsage(node, context); 093 if (result == Result.OK) { 094 // Invoke the generator method and set the result if it's non null. 095 ComplexMatchResult value = generatorMethod.match(builder, buildArgList(context)); 096 if (value != null) { 097 context.setResult(value); 098 MatchStatementSuccess.increment(); 099 Debug.metric("MatchStatement[%s]", getName()).increment(); 100 return true; 101 } 102 // The pattern matched but some other code generation constraint disallowed code 103 // generation for the pattern. 104 if (LogVerbose.getValue()) { 105 Debug.log("while matching %s|%s %s %s returned null", context.getRoot().toString(Verbosity.Id), context.getRoot().getClass().getSimpleName(), getName(), generatorMethod.getName()); 106 Debug.log("with nodes %s", formatMatch(node)); 107 } 108 } else { 109 if (LogVerbose.getValue() && result.code != MatchResultCode.WRONG_CLASS) { 110 Debug.log("while matching %s|%s %s %s", context.getRoot().toString(Verbosity.Id), context.getRoot().getClass().getSimpleName(), getName(), result); 111 } 112 } 113 return false; 114 } 115 116 /** 117 * @param context 118 * @return the Nodes captured by the match rule in the order expected by the generatorMethod 119 */ 120 private Object[] buildArgList(MatchContext context) { 121 Object[] result = new Object[arguments.length]; 122 for (int i = 0; i < arguments.length; i++) { 123 if ("root".equals(arguments[i])) { 124 result[i] = context.getRoot(); 125 } else { 126 result[i] = context.namedNode(arguments[i]); 127 if (result[i] == null) { 128 throw new GraalGraphJVMCIError("Can't find named node %s", arguments[i]); 129 } 130 } 131 } 132 return result; 133 } 134 135 public String formatMatch(Node root) { 136 return pattern.formatMatch(root); 137 } 138 139 public MatchPattern getPattern() { 140 return pattern; 141 } 142 143 public String getName() { 144 return name; 145 } 146 147 @Override 148 public String toString() { 149 return pattern.toString(); 150 } 151}