1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef V8_COMPILER_NODE_MATCHERS_H_
6 #define V8_COMPILER_NODE_MATCHERS_H_
10 #include "src/compiler/node.h"
11 #include "src/compiler/operator.h"
12 #include "src/unique.h"
18 // A pattern matcher for nodes.
20 explicit NodeMatcher(Node* node) : node_(node) {}
22 Node* node() const { return node_; }
23 const Operator* op() const { return node()->op(); }
24 IrOpcode::Value opcode() const { return node()->opcode(); }
26 bool HasProperty(Operator::Property property) const {
27 return op()->HasProperty(property);
29 Node* InputAt(int index) const { return node()->InputAt(index); }
31 #define DEFINE_IS_OPCODE(Opcode) \
32 bool Is##Opcode() const { return opcode() == IrOpcode::k##Opcode; }
33 ALL_OP_LIST(DEFINE_IS_OPCODE)
34 #undef DEFINE_IS_OPCODE
41 // A pattern matcher for abitrary value constants.
42 template <typename T, IrOpcode::Value kOpcode>
43 struct ValueMatcher : public NodeMatcher {
46 explicit ValueMatcher(Node* node)
47 : NodeMatcher(node), value_(), has_value_(opcode() == kOpcode) {
49 value_ = OpParameter<T>(node);
53 bool HasValue() const { return has_value_; }
54 const T& Value() const {
59 bool Is(const T& value) const {
60 return this->HasValue() && this->Value() == value;
63 bool IsInRange(const T& low, const T& high) const {
64 return this->HasValue() && low <= this->Value() && this->Value() <= high;
74 inline ValueMatcher<int64_t, IrOpcode::kInt64Constant>::ValueMatcher(Node* node)
75 : NodeMatcher(node), value_(), has_value_(false) {
76 if (opcode() == IrOpcode::kInt32Constant) {
77 value_ = OpParameter<int32_t>(node);
79 } else if (opcode() == IrOpcode::kInt64Constant) {
80 value_ = OpParameter<int64_t>(node);
87 inline ValueMatcher<uint64_t, IrOpcode::kInt64Constant>::ValueMatcher(
89 : NodeMatcher(node), value_(), has_value_(false) {
90 if (opcode() == IrOpcode::kInt32Constant) {
91 value_ = OpParameter<uint32_t>(node);
93 } else if (opcode() == IrOpcode::kInt64Constant) {
94 value_ = OpParameter<uint64_t>(node);
100 // A pattern matcher for integer constants.
101 template <typename T, IrOpcode::Value kOpcode>
102 struct IntMatcher FINAL : public ValueMatcher<T, kOpcode> {
103 explicit IntMatcher(Node* node) : ValueMatcher<T, kOpcode>(node) {}
105 bool IsMultipleOf(T n) const {
106 return this->HasValue() && (this->Value() % n) == 0;
108 bool IsPowerOf2() const {
109 return this->HasValue() && this->Value() > 0 &&
110 (this->Value() & (this->Value() - 1)) == 0;
112 bool IsNegativePowerOf2() const {
113 return this->HasValue() && this->Value() < 0 &&
114 (-this->Value() & (-this->Value() - 1)) == 0;
118 typedef IntMatcher<int32_t, IrOpcode::kInt32Constant> Int32Matcher;
119 typedef IntMatcher<uint32_t, IrOpcode::kInt32Constant> Uint32Matcher;
120 typedef IntMatcher<int64_t, IrOpcode::kInt64Constant> Int64Matcher;
121 typedef IntMatcher<uint64_t, IrOpcode::kInt64Constant> Uint64Matcher;
122 #if V8_HOST_ARCH_32_BIT
123 typedef Int32Matcher IntPtrMatcher;
124 typedef Uint32Matcher UintPtrMatcher;
126 typedef Int64Matcher IntPtrMatcher;
127 typedef Uint64Matcher UintPtrMatcher;
131 // A pattern matcher for floating point constants.
132 template <typename T, IrOpcode::Value kOpcode>
133 struct FloatMatcher FINAL : public ValueMatcher<T, kOpcode> {
134 explicit FloatMatcher(Node* node) : ValueMatcher<T, kOpcode>(node) {}
136 bool IsMinusZero() const {
137 return this->Is(0.0) && std::signbit(this->Value());
139 bool IsNaN() const { return this->HasValue() && std::isnan(this->Value()); }
142 typedef FloatMatcher<float, IrOpcode::kFloat32Constant> Float32Matcher;
143 typedef FloatMatcher<double, IrOpcode::kFloat64Constant> Float64Matcher;
144 typedef FloatMatcher<double, IrOpcode::kNumberConstant> NumberMatcher;
147 // A pattern matcher for heap object constants.
148 template <typename T>
149 struct HeapObjectMatcher FINAL
150 : public ValueMatcher<Unique<T>, IrOpcode::kHeapConstant> {
151 explicit HeapObjectMatcher(Node* node)
152 : ValueMatcher<Unique<T>, IrOpcode::kHeapConstant>(node) {}
156 // For shorter pattern matching code, this struct matches both the left and
157 // right hand sides of a binary operation and can put constants on the right
158 // if they appear on the left hand side of a commutative operation.
159 template <typename Left, typename Right>
160 struct BinopMatcher : public NodeMatcher {
161 explicit BinopMatcher(Node* node)
162 : NodeMatcher(node), left_(InputAt(0)), right_(InputAt(1)) {
163 if (HasProperty(Operator::kCommutative)) PutConstantOnRight();
165 BinopMatcher(Node* node, bool allow_input_swap)
166 : NodeMatcher(node), left_(InputAt(0)), right_(InputAt(1)) {
167 if (allow_input_swap) PutConstantOnRight();
170 typedef Left LeftMatcher;
171 typedef Right RightMatcher;
173 const Left& left() const { return left_; }
174 const Right& right() const { return right_; }
176 bool IsFoldable() const { return left().HasValue() && right().HasValue(); }
177 bool LeftEqualsRight() const { return left().node() == right().node(); }
181 std::swap(left_, right_);
182 node()->ReplaceInput(0, left().node());
183 node()->ReplaceInput(1, right().node());
187 void PutConstantOnRight() {
188 if (left().HasValue() && !right().HasValue()) {
197 typedef BinopMatcher<Int32Matcher, Int32Matcher> Int32BinopMatcher;
198 typedef BinopMatcher<Uint32Matcher, Uint32Matcher> Uint32BinopMatcher;
199 typedef BinopMatcher<Int64Matcher, Int64Matcher> Int64BinopMatcher;
200 typedef BinopMatcher<Uint64Matcher, Uint64Matcher> Uint64BinopMatcher;
201 typedef BinopMatcher<IntPtrMatcher, IntPtrMatcher> IntPtrBinopMatcher;
202 typedef BinopMatcher<UintPtrMatcher, UintPtrMatcher> UintPtrBinopMatcher;
203 typedef BinopMatcher<Float64Matcher, Float64Matcher> Float64BinopMatcher;
204 typedef BinopMatcher<NumberMatcher, NumberMatcher> NumberBinopMatcher;
207 template <class BinopMatcher, IrOpcode::Value kMulOpcode,
208 IrOpcode::Value kShiftOpcode>
209 struct ScaleMatcher {
210 explicit ScaleMatcher(Node* node, bool allow_power_of_two_plus_one = false)
211 : scale_(-1), power_of_two_plus_one_(false) {
212 if (node->InputCount() < 2) return;
213 BinopMatcher m(node);
214 if (node->opcode() == kShiftOpcode) {
215 if (m.right().HasValue()) {
216 typename BinopMatcher::RightMatcher::ValueType value =
218 if (value >= 0 && value <= 3) {
219 scale_ = static_cast<int>(value);
222 } else if (node->opcode() == kMulOpcode) {
223 if (m.right().HasValue()) {
224 typename BinopMatcher::RightMatcher::ValueType value =
228 } else if (value == 2) {
230 } else if (value == 4) {
232 } else if (value == 8) {
234 } else if (allow_power_of_two_plus_one) {
237 power_of_two_plus_one_ = true;
238 } else if (value == 5) {
240 power_of_two_plus_one_ = true;
241 } else if (value == 9) {
243 power_of_two_plus_one_ = true;
250 bool matches() const { return scale_ != -1; }
251 int scale() const { return scale_; }
252 bool power_of_two_plus_one() const { return power_of_two_plus_one_; }
256 bool power_of_two_plus_one_;
259 typedef ScaleMatcher<Int32BinopMatcher, IrOpcode::kInt32Mul,
260 IrOpcode::kWord32Shl> Int32ScaleMatcher;
261 typedef ScaleMatcher<Int64BinopMatcher, IrOpcode::kInt64Mul,
262 IrOpcode::kWord64Shl> Int64ScaleMatcher;
265 template <class BinopMatcher, IrOpcode::Value kAddOpcode,
266 IrOpcode::Value kMulOpcode, IrOpcode::Value kShiftOpcode>
267 struct AddMatcher : public BinopMatcher {
268 static const IrOpcode::Value kOpcode = kAddOpcode;
269 typedef ScaleMatcher<BinopMatcher, kMulOpcode, kShiftOpcode> Matcher;
271 AddMatcher(Node* node, bool allow_input_swap)
272 : BinopMatcher(node, allow_input_swap),
274 power_of_two_plus_one_(false) {
275 Initialize(node, allow_input_swap);
277 explicit AddMatcher(Node* node)
278 : BinopMatcher(node, node->op()->HasProperty(Operator::kCommutative)),
280 power_of_two_plus_one_(false) {
281 Initialize(node, node->op()->HasProperty(Operator::kCommutative));
284 bool HasIndexInput() const { return scale_ != -1; }
285 Node* IndexInput() const {
286 DCHECK(HasIndexInput());
287 return this->left().node()->InputAt(0);
290 DCHECK(HasIndexInput());
293 bool power_of_two_plus_one() const { return power_of_two_plus_one_; }
296 void Initialize(Node* node, bool allow_input_swap) {
297 Matcher left_matcher(this->left().node(), true);
298 if (left_matcher.matches()) {
299 scale_ = left_matcher.scale();
300 power_of_two_plus_one_ = left_matcher.power_of_two_plus_one();
304 if (!allow_input_swap) {
308 Matcher right_matcher(this->right().node(), true);
309 if (right_matcher.matches()) {
310 scale_ = right_matcher.scale();
311 power_of_two_plus_one_ = right_matcher.power_of_two_plus_one();
316 if (this->right().opcode() == kAddOpcode &&
317 this->left().opcode() != kAddOpcode) {
323 bool power_of_two_plus_one_;
326 typedef AddMatcher<Int32BinopMatcher, IrOpcode::kInt32Add, IrOpcode::kInt32Mul,
327 IrOpcode::kWord32Shl> Int32AddMatcher;
328 typedef AddMatcher<Int64BinopMatcher, IrOpcode::kInt64Add, IrOpcode::kInt64Mul,
329 IrOpcode::kWord64Shl> Int64AddMatcher;
332 template <class AddMatcher>
333 struct BaseWithIndexAndDisplacementMatcher {
334 BaseWithIndexAndDisplacementMatcher(Node* node, bool allow_input_swap)
339 displacement_(NULL) {
340 Initialize(node, allow_input_swap);
343 explicit BaseWithIndexAndDisplacementMatcher(Node* node)
348 displacement_(NULL) {
349 Initialize(node, node->op()->HasProperty(Operator::kCommutative));
352 bool matches() const { return matches_; }
353 Node* index() const { return index_; }
354 int scale() const { return scale_; }
355 Node* base() const { return base_; }
356 Node* displacement() const { return displacement_; }
365 void Initialize(Node* node, bool allow_input_swap) {
366 // The BaseWithIndexAndDisplacementMatcher canonicalizes the order of
367 // displacements and scale factors that are used as inputs, so instead of
368 // enumerating all possible patterns by brute force, checking for node
369 // clusters using the following templates in the following order suffices to
370 // find all of the interesting cases (S = index * scale, B = base input, D =
371 // displacement input):
382 if (node->InputCount() < 2) return;
383 AddMatcher m(node, allow_input_swap);
384 Node* left = m.left().node();
385 Node* right = m.right().node();
386 Node* displacement = NULL;
389 Node* scale_expression = NULL;
390 bool power_of_two_plus_one = false;
392 if (m.HasIndexInput() && left->OwnedBy(node)) {
393 index = m.IndexInput();
395 scale_expression = left;
396 power_of_two_plus_one = m.power_of_two_plus_one();
397 if (right->opcode() == AddMatcher::kOpcode && right->OwnedBy(node)) {
398 AddMatcher right_matcher(right);
399 if (right_matcher.right().HasValue()) {
401 base = right_matcher.left().node();
402 displacement = right_matcher.right().node();
407 } else if (m.right().HasValue()) {
409 displacement = right;
415 if (left->opcode() == AddMatcher::kOpcode && left->OwnedBy(node)) {
416 AddMatcher left_matcher(left);
417 Node* left_left = left_matcher.left().node();
418 Node* left_right = left_matcher.right().node();
419 if (left_matcher.HasIndexInput() && left_left->OwnedBy(left)) {
420 if (left_matcher.right().HasValue()) {
422 index = left_matcher.IndexInput();
423 scale = left_matcher.scale();
424 scale_expression = left_left;
425 power_of_two_plus_one = left_matcher.power_of_two_plus_one();
426 displacement = left_right;
428 } else if (m.right().HasValue()) {
430 index = left_matcher.IndexInput();
431 scale = left_matcher.scale();
432 scale_expression = left_left;
433 power_of_two_plus_one = left_matcher.power_of_two_plus_one();
435 displacement = right;
442 if (left_matcher.right().HasValue()) {
445 displacement = left_right;
447 } else if (m.right().HasValue()) {
451 displacement = right;
459 if (m.right().HasValue()) {
462 displacement = right;
471 if (displacement != NULL) {
472 switch (displacement->opcode()) {
473 case IrOpcode::kInt32Constant: {
474 value = OpParameter<int32_t>(displacement);
477 case IrOpcode::kInt64Constant: {
478 value = OpParameter<int64_t>(displacement);
489 if (power_of_two_plus_one) {
491 // If the scale requires explicitly using the index as the base, but a
492 // base is already part of the match, then the (1 << N + 1) scale factor
493 // can't be folded into the match and the entire index * scale
494 // calculation must be computed separately.
495 index = scale_expression;
502 displacement_ = displacement;
509 typedef BaseWithIndexAndDisplacementMatcher<Int32AddMatcher>
510 BaseWithIndexAndDisplacement32Matcher;
511 typedef BaseWithIndexAndDisplacementMatcher<Int64AddMatcher>
512 BaseWithIndexAndDisplacement64Matcher;
514 } // namespace compiler
515 } // namespace internal
518 #endif // V8_COMPILER_NODE_MATCHERS_H_