< prev index next >

src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchPattern.java

Print this page




  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 
  25 package org.graalvm.compiler.core.match;
  26 
  27 import org.graalvm.compiler.debug.CounterKey;
  28 import org.graalvm.compiler.debug.DebugContext;
  29 import org.graalvm.compiler.graph.Node;
  30 import org.graalvm.compiler.graph.Position;
  31 import org.graalvm.compiler.nodeinfo.InputType;
  32 import org.graalvm.compiler.nodeinfo.Verbosity;

  33 
  34 /**
  35  * A simple recursive pattern matcher for a DAG of nodes.
  36  */
  37 
  38 public class MatchPattern {
  39 
  40     enum MatchResultCode {
  41         OK,
  42         WRONG_CLASS,
  43         NAMED_VALUE_MISMATCH,
  44         TOO_MANY_USERS,
  45         NOT_IN_BLOCK,
  46         NOT_SAFE,
  47         ALREADY_USED,

  48     }
  49 
  50     /**
  51      * A descriptive result for match failures. This can be helpful for debugging why a match
  52      * doesn't work as expected.
  53      */
  54     static class Result {
  55         final MatchResultCode code;
  56 
  57         final Node node;
  58 
  59         final MatchPattern matcher;
  60 
  61         Result(MatchResultCode result, Node node, MatchPattern matcher) {
  62             this.code = result;
  63             this.node = node;
  64             this.matcher = matcher;
  65         }
  66 
  67         private static final CounterKey MatchResult_WRONG_CLASS = DebugContext.counter("MatchResult_WRONG_CLASS");
  68         private static final CounterKey MatchResult_NAMED_VALUE_MISMATCH = DebugContext.counter("MatchResult_NAMED_VALUE_MISMATCH");
  69         private static final CounterKey MatchResult_TOO_MANY_USERS = DebugContext.counter("MatchResult_TOO_MANY_USERS");
  70         private static final CounterKey MatchResult_NOT_IN_BLOCK = DebugContext.counter("MatchResult_NOT_IN_BLOCK");
  71         private static final CounterKey MatchResult_NOT_SAFE = DebugContext.counter("MatchResult_NOT_SAFE");
  72         private static final CounterKey MatchResult_ALREADY_USED = DebugContext.counter("MatchResult_ALREADY_USED");

  73 
  74         static final Result OK = new Result(MatchResultCode.OK, null, null);
  75         private static final Result CACHED_WRONG_CLASS = new Result(MatchResultCode.WRONG_CLASS, null, null);
  76         private static final Result CACHED_NAMED_VALUE_MISMATCH = new Result(MatchResultCode.NAMED_VALUE_MISMATCH, null, null);
  77         private static final Result CACHED_TOO_MANY_USERS = new Result(MatchResultCode.TOO_MANY_USERS, null, null);
  78         private static final Result CACHED_NOT_IN_BLOCK = new Result(MatchResultCode.NOT_IN_BLOCK, null, null);
  79         private static final Result CACHED_NOT_SAFE = new Result(MatchResultCode.NOT_SAFE, null, null);
  80         private static final Result CACHED_ALREADY_USED = new Result(MatchResultCode.ALREADY_USED, null, null);

  81 
  82         static Result wrongClass(Node node, MatchPattern matcher) {
  83             MatchResult_WRONG_CLASS.increment(node.getDebug());
  84             return node.getDebug().isLogEnabled() ? new Result(MatchResultCode.WRONG_CLASS, node, matcher) : CACHED_WRONG_CLASS;
  85         }
  86 
  87         static Result namedValueMismatch(Node node, MatchPattern matcher) {
  88             MatchResult_NAMED_VALUE_MISMATCH.increment(node.getDebug());
  89             return node.getDebug().isLogEnabled() ? new Result(MatchResultCode.NAMED_VALUE_MISMATCH, node, matcher) : CACHED_NAMED_VALUE_MISMATCH;
  90         }
  91 
  92         static Result tooManyUsers(Node node, MatchPattern matcher) {
  93             MatchResult_TOO_MANY_USERS.increment(node.getDebug());
  94             return node.getDebug().isLogEnabled() ? new Result(MatchResultCode.TOO_MANY_USERS, node, matcher) : CACHED_TOO_MANY_USERS;
  95         }
  96 
  97         static Result notInBlock(Node node, MatchPattern matcher) {
  98             MatchResult_NOT_IN_BLOCK.increment(node.getDebug());
  99             return node.getDebug().isLogEnabled() ? new Result(MatchResultCode.NOT_IN_BLOCK, node, matcher) : CACHED_NOT_IN_BLOCK;
 100         }
 101 
 102         static Result notSafe(Node node, MatchPattern matcher) {
 103             MatchResult_NOT_SAFE.increment(node.getDebug());
 104             return node.getDebug().isLogEnabled() ? new Result(MatchResultCode.NOT_SAFE, node, matcher) : CACHED_NOT_SAFE;
 105         }
 106 
 107         static Result alreadyUsed(Node node, MatchPattern matcher) {
 108             MatchResult_ALREADY_USED.increment(node.getDebug());
 109             return node.getDebug().isLogEnabled() ? new Result(MatchResultCode.ALREADY_USED, node, matcher) : CACHED_ALREADY_USED;
 110         }
 111 





 112         @Override
 113         public String toString() {
 114             if (code == MatchResultCode.OK) {
 115                 return "OK";
 116             }
 117             if (node == null) {
 118                 return code.toString();
 119             } else {
 120                 return code + " " + node.toString(Verbosity.Id) + "|" + node.getClass().getSimpleName() + " " + matcher;
 121             }
 122         }
 123     }
 124 
 125     /**
 126      * The expected type of the node. It must match exactly.
 127      */
 128     private final Class<? extends Node> nodeClass;
 129 
 130     /**
 131      * An optional name for this node. A name can occur multiple times in a match and that name must
 132      * always refer to the same node of the match will fail.
 133      */
 134     private final String name;
 135 
 136     /**
 137      * Patterns to match the inputs.
 138      */
 139     private final MatchPattern[] patterns;
 140 
 141     /**
 142      * The inputs to match the patterns against.
 143      */
 144     private final Position[] inputs;
 145 
 146     /**
 147      * Can there only be one user of the node. Constant nodes can be matched even if there are other
 148      * users.
 149      */
 150     private final boolean singleUser;
 151 






 152     private static final MatchPattern[] EMPTY_PATTERNS = new MatchPattern[0];
 153 
 154     public MatchPattern(String name, boolean singleUser) {
 155         this(null, name, singleUser);
 156     }
 157 
 158     public MatchPattern(Class<? extends Node> nodeClass, String name, boolean singleUser) {
 159         this.nodeClass = nodeClass;
 160         this.name = name;
 161         this.singleUser = singleUser;

 162         this.patterns = EMPTY_PATTERNS;
 163         this.inputs = null;

 164     }
 165 
 166     private MatchPattern(Class<? extends Node> nodeClass, String name, boolean singleUser, MatchPattern[] patterns, Position[] inputs) {
 167         assert inputs == null || inputs.length == patterns.length;
 168         this.nodeClass = nodeClass;
 169         this.name = name;
 170         this.singleUser = singleUser;

 171         this.patterns = patterns;
 172         this.inputs = inputs;

 173     }
 174 
 175     public MatchPattern(Class<? extends Node> nodeClass, String name, MatchPattern first, Position[] inputs, boolean singleUser) {
 176         this(nodeClass, name, singleUser, new MatchPattern[]{first}, inputs);
 177     }
 178 
 179     public MatchPattern(Class<? extends Node> nodeClass, String name, MatchPattern first, MatchPattern second, Position[] inputs, boolean singleUser) {
 180         this(nodeClass, name, singleUser, new MatchPattern[]{first, second}, inputs);
 181     }
 182 
 183     public MatchPattern(Class<? extends Node> nodeClass, String name, MatchPattern first, MatchPattern second, MatchPattern third, Position[] inputs, boolean singleUser) {
 184         this(nodeClass, name, singleUser, new MatchPattern[]{first, second, third}, inputs);
 185     }
 186 
 187     Class<? extends Node> nodeClass() {
 188         return nodeClass;
 189     }
 190 
 191     private Result matchType(Node node) {
 192         if (nodeClass != null && node.getClass() != nodeClass) {
 193             return Result.wrongClass(node, this);
 194         }
 195         return Result.OK;
 196     }
 197 
 198     /**
 199      * Match any named nodes and ensure that the consumed nodes can be safely merged.
 200      *
 201      * @param node
 202      * @param context
 203      * @return Result.OK is the pattern can be safely matched.
 204      */
 205     Result matchUsage(Node node, MatchContext context) {
 206         Result result = matchUsage(node, context, true);
 207         if (result == Result.OK) {
 208             result = context.validate();
 209         }
 210         return result;
 211     }
 212 
 213     private Result matchUsage(Node node, MatchContext context, boolean atRoot) {
 214         Result result = matchType(node);
 215         if (result != Result.OK) {
 216             return result;
 217         }
 218         if (singleUser && !atRoot) {
 219             result = context.consume(node);
 220             if (result != Result.OK) {
 221                 return result;
 222             }
 223         }
 224 
 225         if (name != null) {
 226             result = context.captureNamedValue(name, nodeClass, node);
 227         }
 228 
 229         for (int input = 0; input < patterns.length; input++) {
 230             result = patterns[input].matchUsage(getInput(input, node), context, false);
 231             if (result != Result.OK) {
 232                 return result;
 233             }
 234         }
 235 
 236         return result;
 237     }
 238 
 239     /**




  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 
  25 package org.graalvm.compiler.core.match;
  26 
  27 import org.graalvm.compiler.debug.CounterKey;
  28 import org.graalvm.compiler.debug.DebugContext;
  29 import org.graalvm.compiler.graph.Node;
  30 import org.graalvm.compiler.graph.Position;
  31 import org.graalvm.compiler.nodeinfo.InputType;
  32 import org.graalvm.compiler.nodeinfo.Verbosity;
  33 import org.graalvm.compiler.nodes.calc.FloatingNode;
  34 
  35 /**
  36  * A simple recursive pattern matcher for a DAG of nodes.
  37  */
  38 
  39 public class MatchPattern {
  40 
  41     enum MatchResultCode {
  42         OK,
  43         WRONG_CLASS,
  44         NAMED_VALUE_MISMATCH,
  45         TOO_MANY_USERS,
  46         NOT_IN_BLOCK,
  47         NOT_SAFE,
  48         ALREADY_USED,
  49         TOO_LATE,
  50     }
  51 
  52     /**
  53      * A descriptive result for match failures. This can be helpful for debugging why a match
  54      * doesn't work as expected.
  55      */
  56     static class Result {
  57         final MatchResultCode code;
  58 
  59         final Node node;
  60 
  61         final MatchPattern matcher;
  62 
  63         Result(MatchResultCode result, Node node, MatchPattern matcher) {
  64             this.code = result;
  65             this.node = node;
  66             this.matcher = matcher;
  67         }
  68 
  69         private static final CounterKey MatchResult_WRONG_CLASS = DebugContext.counter("MatchResult_WRONG_CLASS");
  70         private static final CounterKey MatchResult_NAMED_VALUE_MISMATCH = DebugContext.counter("MatchResult_NAMED_VALUE_MISMATCH");
  71         private static final CounterKey MatchResult_TOO_MANY_USERS = DebugContext.counter("MatchResult_TOO_MANY_USERS");
  72         private static final CounterKey MatchResult_NOT_IN_BLOCK = DebugContext.counter("MatchResult_NOT_IN_BLOCK");
  73         private static final CounterKey MatchResult_NOT_SAFE = DebugContext.counter("MatchResult_NOT_SAFE");
  74         private static final CounterKey MatchResult_ALREADY_USED = DebugContext.counter("MatchResult_ALREADY_USED");
  75         private static final CounterKey MatchResult_TOO_LATE = DebugContext.counter("MatchResult_TOO_LATE");
  76 
  77         static final Result OK = new Result(MatchResultCode.OK, null, null);
  78         private static final Result CACHED_WRONG_CLASS = new Result(MatchResultCode.WRONG_CLASS, null, null);
  79         private static final Result CACHED_NAMED_VALUE_MISMATCH = new Result(MatchResultCode.NAMED_VALUE_MISMATCH, null, null);
  80         private static final Result CACHED_TOO_MANY_USERS = new Result(MatchResultCode.TOO_MANY_USERS, null, null);
  81         private static final Result CACHED_NOT_IN_BLOCK = new Result(MatchResultCode.NOT_IN_BLOCK, null, null);
  82         private static final Result CACHED_NOT_SAFE = new Result(MatchResultCode.NOT_SAFE, null, null);
  83         private static final Result CACHED_ALREADY_USED = new Result(MatchResultCode.ALREADY_USED, null, null);
  84         private static final Result CACHED_TOO_LATE = new Result(MatchResultCode.TOO_LATE, null, null);
  85 
  86         static Result wrongClass(Node node, MatchPattern matcher) {
  87             MatchResult_WRONG_CLASS.increment(node.getDebug());
  88             return node.getDebug().isLogEnabled() ? new Result(MatchResultCode.WRONG_CLASS, node, matcher) : CACHED_WRONG_CLASS;
  89         }
  90 
  91         static Result namedValueMismatch(Node node, MatchPattern matcher) {
  92             MatchResult_NAMED_VALUE_MISMATCH.increment(node.getDebug());
  93             return node.getDebug().isLogEnabled() ? new Result(MatchResultCode.NAMED_VALUE_MISMATCH, node, matcher) : CACHED_NAMED_VALUE_MISMATCH;
  94         }
  95 
  96         static Result tooManyUsers(Node node, MatchPattern matcher) {
  97             MatchResult_TOO_MANY_USERS.increment(node.getDebug());
  98             return node.getDebug().isLogEnabled() ? new Result(MatchResultCode.TOO_MANY_USERS, node, matcher) : CACHED_TOO_MANY_USERS;
  99         }
 100 
 101         static Result notInBlock(Node node, MatchPattern matcher) {
 102             MatchResult_NOT_IN_BLOCK.increment(node.getDebug());
 103             return node.getDebug().isLogEnabled() ? new Result(MatchResultCode.NOT_IN_BLOCK, node, matcher) : CACHED_NOT_IN_BLOCK;
 104         }
 105 
 106         static Result notSafe(Node node, MatchPattern matcher) {
 107             MatchResult_NOT_SAFE.increment(node.getDebug());
 108             return node.getDebug().isLogEnabled() ? new Result(MatchResultCode.NOT_SAFE, node, matcher) : CACHED_NOT_SAFE;
 109         }
 110 
 111         static Result alreadyUsed(Node node, MatchPattern matcher) {
 112             MatchResult_ALREADY_USED.increment(node.getDebug());
 113             return node.getDebug().isLogEnabled() ? new Result(MatchResultCode.ALREADY_USED, node, matcher) : CACHED_ALREADY_USED;
 114         }
 115 
 116         static Result tooLate(Node node, MatchPattern matcher) {
 117             MatchResult_TOO_LATE.increment(node.getDebug());
 118             return node.getDebug().isLogEnabled() ? new Result(MatchResultCode.TOO_LATE, node, matcher) : CACHED_TOO_LATE;
 119         }
 120 
 121         @Override
 122         public String toString() {
 123             if (code == MatchResultCode.OK) {
 124                 return "OK";
 125             }
 126             if (node == null) {
 127                 return code.toString();
 128             } else {
 129                 return code + " " + node.toString(Verbosity.Id) + "|" + node.getClass().getSimpleName() + " " + matcher;
 130             }
 131         }
 132     }
 133 
 134     /**
 135      * The expected type of the node. It must match exactly.
 136      */
 137     private final Class<? extends Node> nodeClass;
 138 
 139     /**
 140      * An optional name for this node. A name can occur multiple times in a match and that name must
 141      * always refer to the same node of the match will fail.
 142      */
 143     private final String name;
 144 
 145     /**
 146      * Patterns to match the inputs.
 147      */
 148     private final MatchPattern[] patterns;
 149 
 150     /**
 151      * The inputs to match the patterns against.
 152      */
 153     private final Position[] inputs;
 154 
 155     /**
 156      * Can there only be one user of the node. Constant nodes can be matched even if there are other
 157      * users.
 158      */
 159     private final boolean singleUser;
 160 
 161     /**
 162      * Can this node be subsumed into a match even if there are side effecting nodes between this
 163      * node and the match.
 164      */
 165     private final boolean ignoresSideEffects;
 166 
 167     private static final MatchPattern[] EMPTY_PATTERNS = new MatchPattern[0];
 168 
 169     public MatchPattern(String name, boolean singleUser, boolean ignoresSideEffects) {
 170         this(null, name, singleUser, ignoresSideEffects);
 171     }
 172 
 173     public MatchPattern(Class<? extends Node> nodeClass, String name, boolean singleUser, boolean ignoresSideEffects) {
 174         this.nodeClass = nodeClass;
 175         this.name = name;
 176         this.singleUser = singleUser;
 177         this.ignoresSideEffects = ignoresSideEffects;
 178         this.patterns = EMPTY_PATTERNS;
 179         this.inputs = null;
 180         assert !ignoresSideEffects || FloatingNode.class.isAssignableFrom(nodeClass);
 181     }
 182 
 183     private MatchPattern(Class<? extends Node> nodeClass, String name, boolean singleUser, boolean ignoresSideEffects, MatchPattern[] patterns, Position[] inputs) {
 184         assert inputs == null || inputs.length == patterns.length;
 185         this.nodeClass = nodeClass;
 186         this.name = name;
 187         this.singleUser = singleUser;
 188         this.ignoresSideEffects = ignoresSideEffects;
 189         this.patterns = patterns;
 190         this.inputs = inputs;
 191         assert !ignoresSideEffects || FloatingNode.class.isAssignableFrom(nodeClass);
 192     }
 193 
 194     public MatchPattern(Class<? extends Node> nodeClass, String name, MatchPattern first, Position[] inputs, boolean singleUser, boolean ignoresSideEffects) {
 195         this(nodeClass, name, singleUser, ignoresSideEffects, new MatchPattern[]{first}, inputs);
 196     }
 197 
 198     public MatchPattern(Class<? extends Node> nodeClass, String name, MatchPattern first, MatchPattern second, Position[] inputs, boolean singleUser, boolean ignoresSideEffects) {
 199         this(nodeClass, name, singleUser, ignoresSideEffects, new MatchPattern[]{first, second}, inputs);
 200     }
 201 
 202     public MatchPattern(Class<? extends Node> nodeClass, String name, MatchPattern first, MatchPattern second, MatchPattern third, Position[] inputs, boolean singleUser, boolean ignoresSideEffects) {
 203         this(nodeClass, name, singleUser, ignoresSideEffects, new MatchPattern[]{first, second, third}, inputs);
 204     }
 205 
 206     Class<? extends Node> nodeClass() {
 207         return nodeClass;
 208     }
 209 
 210     private Result matchType(Node node) {
 211         if (nodeClass != null && node.getClass() != nodeClass) {
 212             return Result.wrongClass(node, this);
 213         }
 214         return Result.OK;
 215     }
 216 
 217     /**
 218      * Match any named nodes and ensure that the consumed nodes can be safely merged.
 219      *
 220      * @param node
 221      * @param context
 222      * @return Result.OK is the pattern can be safely matched.
 223      */
 224     Result matchUsage(Node node, MatchContext context) {
 225         Result result = matchUsage(node, context, true);
 226         if (result == Result.OK) {
 227             result = context.validate();
 228         }
 229         return result;
 230     }
 231 
 232     private Result matchUsage(Node node, MatchContext context, boolean atRoot) {
 233         Result result = matchType(node);
 234         if (result != Result.OK) {
 235             return result;
 236         }
 237         if (singleUser) {
 238             result = context.consume(node, ignoresSideEffects, atRoot);
 239             if (result != Result.OK) {
 240                 return result;
 241             }
 242         }
 243 
 244         if (name != null) {
 245             result = context.captureNamedValue(name, nodeClass, node);
 246         }
 247 
 248         for (int input = 0; input < patterns.length; input++) {
 249             result = patterns[input].matchUsage(getInput(input, node), context, false);
 250             if (result != Result.OK) {
 251                 return result;
 252             }
 253         }
 254 
 255         return result;
 256     }
 257 
 258     /**


< prev index next >