• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #ifndef V8_COMPILER_NODE_MATCHERS_H_
6 #define V8_COMPILER_NODE_MATCHERS_H_
7 
8 #include <cmath>
9 #include <limits>
10 
11 #include "src/base/compiler-specific.h"
12 #include "src/codegen/external-reference.h"
13 #include "src/common/globals.h"
14 #include "src/compiler/common-operator.h"
15 #include "src/compiler/node.h"
16 #include "src/compiler/operator.h"
17 #include "src/numbers/double.h"
18 #include "src/objects/heap-object.h"
19 
20 namespace v8 {
21 namespace internal {
22 namespace compiler {
23 
24 class JSHeapBroker;
25 
26 // A pattern matcher for nodes.
27 struct NodeMatcher {
NodeMatcherNodeMatcher28   explicit NodeMatcher(Node* node) : node_(node) {}
29 
nodeNodeMatcher30   Node* node() const { return node_; }
opNodeMatcher31   const Operator* op() const { return node()->op(); }
opcodeNodeMatcher32   IrOpcode::Value opcode() const { return node()->opcode(); }
33 
HasPropertyNodeMatcher34   bool HasProperty(Operator::Property property) const {
35     return op()->HasProperty(property);
36   }
InputAtNodeMatcher37   Node* InputAt(int index) const { return node()->InputAt(index); }
38 
EqualsNodeMatcher39   bool Equals(const Node* node) const { return node_ == node; }
40 
41   bool IsComparison() const;
42 
43 #define DEFINE_IS_OPCODE(Opcode, ...) \
44   bool Is##Opcode() const { return opcode() == IrOpcode::k##Opcode; }
45   ALL_OP_LIST(DEFINE_IS_OPCODE)
46 #undef DEFINE_IS_OPCODE
47 
48  private:
49   Node* node_;
50 };
51 
SkipValueIdentities(Node * node)52 inline Node* SkipValueIdentities(Node* node) {
53 #ifdef DEBUG
54   bool seen_fold_constant = false;
55 #endif
56   do {
57 #ifdef DEBUG
58     if (node->opcode() == IrOpcode::kFoldConstant) {
59       DCHECK(!seen_fold_constant);
60       seen_fold_constant = true;
61     }
62 #endif
63   } while (NodeProperties::IsValueIdentity(node, &node));
64   DCHECK_NOT_NULL(node);
65   return node;
66 }
67 
68 // A pattern matcher for abitrary value constants.
69 //
70 // Note that value identities on the input node are skipped when matching. The
71 // resolved value may not be a parameter of the input node. The node() method
72 // returns the unmodified input node. This is by design, as reducers may wish to
73 // match value constants but delay reducing the node until a later phase. For
74 // example, binary operator reducers may opt to keep FoldConstant operands while
75 // applying a reduction that match on the constant value of the FoldConstant.
76 template <typename T, IrOpcode::Value kOpcode>
77 struct ValueMatcher : public NodeMatcher {
78   using ValueType = T;
79 
ValueMatcherValueMatcher80   explicit ValueMatcher(Node* node)
81       : NodeMatcher(node), resolved_value_(), has_resolved_value_(false) {
82     node = SkipValueIdentities(node);
83     has_resolved_value_ = node->opcode() == kOpcode;
84     if (has_resolved_value_) {
85       resolved_value_ = OpParameter<T>(node->op());
86     }
87   }
88 
HasResolvedValueValueMatcher89   bool HasResolvedValue() const { return has_resolved_value_; }
ResolvedValueValueMatcher90   const T& ResolvedValue() const {
91     CHECK(HasResolvedValue());
92     return resolved_value_;
93   }
94 
95  private:
96   T resolved_value_;
97   bool has_resolved_value_;
98 };
99 
100 template <>
ValueMatcher(Node * node)101 inline ValueMatcher<uint32_t, IrOpcode::kInt32Constant>::ValueMatcher(
102     Node* node)
103     : NodeMatcher(node), resolved_value_(), has_resolved_value_(false) {
104   node = SkipValueIdentities(node);
105   has_resolved_value_ = node->opcode() == IrOpcode::kInt32Constant;
106   if (has_resolved_value_) {
107     resolved_value_ = static_cast<uint32_t>(OpParameter<int32_t>(node->op()));
108   }
109 }
110 
111 template <>
ValueMatcher(Node * node)112 inline ValueMatcher<int64_t, IrOpcode::kInt64Constant>::ValueMatcher(Node* node)
113     : NodeMatcher(node), resolved_value_(), has_resolved_value_(false) {
114   node = SkipValueIdentities(node);
115   if (node->opcode() == IrOpcode::kInt32Constant) {
116     resolved_value_ = OpParameter<int32_t>(node->op());
117     has_resolved_value_ = true;
118   } else if (node->opcode() == IrOpcode::kInt64Constant) {
119     resolved_value_ = OpParameter<int64_t>(node->op());
120     has_resolved_value_ = true;
121   }
122 }
123 
124 template <>
ValueMatcher(Node * node)125 inline ValueMatcher<uint64_t, IrOpcode::kInt64Constant>::ValueMatcher(
126     Node* node)
127     : NodeMatcher(node), resolved_value_(), has_resolved_value_(false) {
128   node = SkipValueIdentities(node);
129   if (node->opcode() == IrOpcode::kInt32Constant) {
130     resolved_value_ = static_cast<uint32_t>(OpParameter<int32_t>(node->op()));
131     has_resolved_value_ = true;
132   } else if (node->opcode() == IrOpcode::kInt64Constant) {
133     resolved_value_ = static_cast<uint64_t>(OpParameter<int64_t>(node->op()));
134     has_resolved_value_ = true;
135   }
136 }
137 
138 // A pattern matcher for integer constants.
139 template <typename T, IrOpcode::Value kOpcode>
140 struct IntMatcher final : public ValueMatcher<T, kOpcode> {
IntMatcherfinal141   explicit IntMatcher(Node* node) : ValueMatcher<T, kOpcode>(node) {}
142 
Isfinal143   bool Is(const T& value) const {
144     return this->HasResolvedValue() && this->ResolvedValue() == value;
145   }
IsInRangefinal146   bool IsInRange(const T& low, const T& high) const {
147     return this->HasResolvedValue() && low <= this->ResolvedValue() &&
148            this->ResolvedValue() <= high;
149   }
IsMultipleOffinal150   bool IsMultipleOf(T n) const {
151     return this->HasResolvedValue() && (this->ResolvedValue() % n) == 0;
152   }
IsPowerOf2final153   bool IsPowerOf2() const {
154     return this->HasResolvedValue() && this->ResolvedValue() > 0 &&
155            (this->ResolvedValue() & (this->ResolvedValue() - 1)) == 0;
156   }
IsNegativePowerOf2final157   bool IsNegativePowerOf2() const {
158     return this->HasResolvedValue() && this->ResolvedValue() < 0 &&
159            ((this->ResolvedValue() == std::numeric_limits<T>::min()) ||
160             (-this->ResolvedValue() & (-this->ResolvedValue() - 1)) == 0);
161   }
IsNegativefinal162   bool IsNegative() const {
163     return this->HasResolvedValue() && this->ResolvedValue() < 0;
164   }
165 };
166 
167 using Int32Matcher = IntMatcher<int32_t, IrOpcode::kInt32Constant>;
168 using Uint32Matcher = IntMatcher<uint32_t, IrOpcode::kInt32Constant>;
169 using Int64Matcher = IntMatcher<int64_t, IrOpcode::kInt64Constant>;
170 using Uint64Matcher = IntMatcher<uint64_t, IrOpcode::kInt64Constant>;
171 #if V8_HOST_ARCH_32_BIT
172 using IntPtrMatcher = Int32Matcher;
173 using UintPtrMatcher = Uint32Matcher;
174 #else
175 using IntPtrMatcher = Int64Matcher;
176 using UintPtrMatcher = Uint64Matcher;
177 #endif
178 
179 
180 // A pattern matcher for floating point constants.
181 template <typename T, IrOpcode::Value kOpcode>
182 struct FloatMatcher final : public ValueMatcher<T, kOpcode> {
FloatMatcherfinal183   explicit FloatMatcher(Node* node) : ValueMatcher<T, kOpcode>(node) {}
184 
Isfinal185   bool Is(const T& value) const {
186     return this->HasResolvedValue() && this->ResolvedValue() == value;
187   }
IsInRangefinal188   bool IsInRange(const T& low, const T& high) const {
189     return this->HasResolvedValue() && low <= this->ResolvedValue() &&
190            this->ResolvedValue() <= high;
191   }
IsMinusZerofinal192   bool IsMinusZero() const {
193     return this->Is(0.0) && std::signbit(this->ResolvedValue());
194   }
IsNegativefinal195   bool IsNegative() const {
196     return this->HasResolvedValue() && this->ResolvedValue() < 0.0;
197   }
IsNaNfinal198   bool IsNaN() const {
199     return this->HasResolvedValue() && std::isnan(this->ResolvedValue());
200   }
IsZerofinal201   bool IsZero() const {
202     return this->Is(0.0) && !std::signbit(this->ResolvedValue());
203   }
IsNormalfinal204   bool IsNormal() const {
205     return this->HasResolvedValue() && std::isnormal(this->ResolvedValue());
206   }
IsIntegerfinal207   bool IsInteger() const {
208     return this->HasResolvedValue() &&
209            std::nearbyint(this->ResolvedValue()) == this->ResolvedValue();
210   }
IsPositiveOrNegativePowerOf2final211   bool IsPositiveOrNegativePowerOf2() const {
212     if (!this->HasResolvedValue() || (this->ResolvedValue() == 0.0)) {
213       return false;
214     }
215     Double value = Double(this->ResolvedValue());
216     return !value.IsInfinite() && base::bits::IsPowerOfTwo(value.Significand());
217   }
218 };
219 
220 using Float32Matcher = FloatMatcher<float, IrOpcode::kFloat32Constant>;
221 using Float64Matcher = FloatMatcher<double, IrOpcode::kFloat64Constant>;
222 using NumberMatcher = FloatMatcher<double, IrOpcode::kNumberConstant>;
223 
224 // A pattern matcher for heap object constants.
225 template <IrOpcode::Value kHeapConstantOpcode>
226 struct HeapObjectMatcherImpl final
227     : public ValueMatcher<Handle<HeapObject>, kHeapConstantOpcode> {
HeapObjectMatcherImplfinal228   explicit HeapObjectMatcherImpl(Node* node)
229       : ValueMatcher<Handle<HeapObject>, kHeapConstantOpcode>(node) {}
230 
Isfinal231   bool Is(Handle<HeapObject> const& value) const {
232     return this->HasResolvedValue() &&
233            this->ResolvedValue().address() == value.address();
234   }
235 
Reffinal236   HeapObjectRef Ref(JSHeapBroker* broker) const {
237     return HeapObjectRef(broker, this->ResolvedValue());
238   }
239 };
240 
241 using HeapObjectMatcher = HeapObjectMatcherImpl<IrOpcode::kHeapConstant>;
242 using CompressedHeapObjectMatcher =
243     HeapObjectMatcherImpl<IrOpcode::kCompressedHeapConstant>;
244 
245 // A pattern matcher for external reference constants.
246 struct ExternalReferenceMatcher final
247     : public ValueMatcher<ExternalReference, IrOpcode::kExternalConstant> {
ExternalReferenceMatcherfinal248   explicit ExternalReferenceMatcher(Node* node)
249       : ValueMatcher<ExternalReference, IrOpcode::kExternalConstant>(node) {}
Isfinal250   bool Is(const ExternalReference& value) const {
251     return this->HasResolvedValue() && this->ResolvedValue() == value;
252   }
253 };
254 
255 
256 // For shorter pattern matching code, this struct matches the inputs to
257 // machine-level load operations.
258 template <typename Object>
259 struct LoadMatcher : public NodeMatcher {
LoadMatcherLoadMatcher260   explicit LoadMatcher(Node* node)
261       : NodeMatcher(node), object_(InputAt(0)), index_(InputAt(1)) {}
262 
263   using ObjectMatcher = Object;
264 
objectLoadMatcher265   Object const& object() const { return object_; }
indexLoadMatcher266   IntPtrMatcher const& index() const { return index_; }
267 
268  private:
269   Object const object_;
270   IntPtrMatcher const index_;
271 };
272 
273 
274 // For shorter pattern matching code, this struct matches both the left and
275 // right hand sides of a binary operation and can put constants on the right
276 // if they appear on the left hand side of a commutative operation.
277 template <typename Left, typename Right>
278 struct BinopMatcher : public NodeMatcher {
BinopMatcherBinopMatcher279   explicit BinopMatcher(Node* node)
280       : NodeMatcher(node), left_(InputAt(0)), right_(InputAt(1)) {
281     if (HasProperty(Operator::kCommutative)) PutConstantOnRight();
282   }
BinopMatcherBinopMatcher283   BinopMatcher(Node* node, bool allow_input_swap)
284       : NodeMatcher(node), left_(InputAt(0)), right_(InputAt(1)) {
285     if (allow_input_swap) PutConstantOnRight();
286   }
287 
288   using LeftMatcher = Left;
289   using RightMatcher = Right;
290 
leftBinopMatcher291   const Left& left() const { return left_; }
rightBinopMatcher292   const Right& right() const { return right_; }
293 
IsFoldableBinopMatcher294   bool IsFoldable() const {
295     return left().HasResolvedValue() && right().HasResolvedValue();
296   }
LeftEqualsRightBinopMatcher297   bool LeftEqualsRight() const { return left().node() == right().node(); }
298 
OwnsInputBinopMatcher299   bool OwnsInput(Node* input) {
300     for (Node* use : input->uses()) {
301       if (use != node()) {
302         return false;
303       }
304     }
305     return true;
306   }
307 
308  protected:
SwapInputsBinopMatcher309   void SwapInputs() {
310     std::swap(left_, right_);
311     // TODO(tebbi): This modification should notify the reducers using
312     // BinopMatcher. Alternatively, all reducers (especially value numbering)
313     // could ignore the ordering for commutative binops.
314     node()->ReplaceInput(0, left().node());
315     node()->ReplaceInput(1, right().node());
316   }
317 
318  private:
PutConstantOnRightBinopMatcher319   void PutConstantOnRight() {
320     if (left().HasResolvedValue() && !right().HasResolvedValue()) {
321       SwapInputs();
322     }
323   }
324 
325   Left left_;
326   Right right_;
327 };
328 
329 using Int32BinopMatcher = BinopMatcher<Int32Matcher, Int32Matcher>;
330 using Uint32BinopMatcher = BinopMatcher<Uint32Matcher, Uint32Matcher>;
331 using Int64BinopMatcher = BinopMatcher<Int64Matcher, Int64Matcher>;
332 using Uint64BinopMatcher = BinopMatcher<Uint64Matcher, Uint64Matcher>;
333 using IntPtrBinopMatcher = BinopMatcher<IntPtrMatcher, IntPtrMatcher>;
334 using UintPtrBinopMatcher = BinopMatcher<UintPtrMatcher, UintPtrMatcher>;
335 using Float32BinopMatcher = BinopMatcher<Float32Matcher, Float32Matcher>;
336 using Float64BinopMatcher = BinopMatcher<Float64Matcher, Float64Matcher>;
337 using NumberBinopMatcher = BinopMatcher<NumberMatcher, NumberMatcher>;
338 using HeapObjectBinopMatcher =
339     BinopMatcher<HeapObjectMatcher, HeapObjectMatcher>;
340 using CompressedHeapObjectBinopMatcher =
341     BinopMatcher<CompressedHeapObjectMatcher, CompressedHeapObjectMatcher>;
342 
343 template <class BinopMatcher, IrOpcode::Value kMulOpcode,
344           IrOpcode::Value kShiftOpcode>
345 struct ScaleMatcher {
346   explicit ScaleMatcher(Node* node, bool allow_power_of_two_plus_one = false)
347       : scale_(-1), power_of_two_plus_one_(false) {
348     if (node->InputCount() < 2) return;
349     BinopMatcher m(node);
350     if (node->opcode() == kShiftOpcode) {
351       if (m.right().HasResolvedValue()) {
352         typename BinopMatcher::RightMatcher::ValueType value =
353             m.right().ResolvedValue();
354         if (value >= 0 && value <= 3) {
355           scale_ = static_cast<int>(value);
356         }
357       }
358     } else if (node->opcode() == kMulOpcode) {
359       if (m.right().HasResolvedValue()) {
360         typename BinopMatcher::RightMatcher::ValueType value =
361             m.right().ResolvedValue();
362         if (value == 1) {
363           scale_ = 0;
364         } else if (value == 2) {
365           scale_ = 1;
366         } else if (value == 4) {
367           scale_ = 2;
368         } else if (value == 8) {
369           scale_ = 3;
370         } else if (allow_power_of_two_plus_one) {
371           if (value == 3) {
372             scale_ = 1;
373             power_of_two_plus_one_ = true;
374           } else if (value == 5) {
375             scale_ = 2;
376             power_of_two_plus_one_ = true;
377           } else if (value == 9) {
378             scale_ = 3;
379             power_of_two_plus_one_ = true;
380           }
381         }
382       }
383     }
384   }
385 
matchesScaleMatcher386   bool matches() const { return scale_ != -1; }
scaleScaleMatcher387   int scale() const { return scale_; }
power_of_two_plus_oneScaleMatcher388   bool power_of_two_plus_one() const { return power_of_two_plus_one_; }
389 
390  private:
391   int scale_;
392   bool power_of_two_plus_one_;
393 };
394 
395 using Int32ScaleMatcher =
396     ScaleMatcher<Int32BinopMatcher, IrOpcode::kInt32Mul, IrOpcode::kWord32Shl>;
397 using Int64ScaleMatcher =
398     ScaleMatcher<Int64BinopMatcher, IrOpcode::kInt64Mul, IrOpcode::kWord64Shl>;
399 
400 template <class BinopMatcher, IrOpcode::Value AddOpcode,
401           IrOpcode::Value SubOpcode, IrOpcode::Value kMulOpcode,
402           IrOpcode::Value kShiftOpcode>
403 struct AddMatcher : public BinopMatcher {
404   static const IrOpcode::Value kAddOpcode = AddOpcode;
405   static const IrOpcode::Value kSubOpcode = SubOpcode;
406   using Matcher = ScaleMatcher<BinopMatcher, kMulOpcode, kShiftOpcode>;
407 
AddMatcherAddMatcher408   AddMatcher(Node* node, bool allow_input_swap)
409       : BinopMatcher(node, allow_input_swap),
410         scale_(-1),
411         power_of_two_plus_one_(false) {
412     Initialize(node, allow_input_swap);
413   }
AddMatcherAddMatcher414   explicit AddMatcher(Node* node)
415       : BinopMatcher(node, node->op()->HasProperty(Operator::kCommutative)),
416         scale_(-1),
417         power_of_two_plus_one_(false) {
418     Initialize(node, node->op()->HasProperty(Operator::kCommutative));
419   }
420 
HasIndexInputAddMatcher421   bool HasIndexInput() const { return scale_ != -1; }
IndexInputAddMatcher422   Node* IndexInput() const {
423     DCHECK(HasIndexInput());
424     return this->left().node()->InputAt(0);
425   }
scaleAddMatcher426   int scale() const {
427     DCHECK(HasIndexInput());
428     return scale_;
429   }
power_of_two_plus_oneAddMatcher430   bool power_of_two_plus_one() const { return power_of_two_plus_one_; }
431 
432  private:
InitializeAddMatcher433   void Initialize(Node* node, bool allow_input_swap) {
434     Matcher left_matcher(this->left().node(), true);
435     if (left_matcher.matches()) {
436       scale_ = left_matcher.scale();
437       power_of_two_plus_one_ = left_matcher.power_of_two_plus_one();
438       return;
439     }
440 
441     if (!allow_input_swap) {
442       return;
443     }
444 
445     Matcher right_matcher(this->right().node(), true);
446     if (right_matcher.matches()) {
447       scale_ = right_matcher.scale();
448       power_of_two_plus_one_ = right_matcher.power_of_two_plus_one();
449       this->SwapInputs();
450       return;
451     }
452 
453     if ((this->left().opcode() != kSubOpcode &&
454          this->left().opcode() != kAddOpcode) &&
455         (this->right().opcode() == kAddOpcode ||
456          this->right().opcode() == kSubOpcode)) {
457       this->SwapInputs();
458     }
459   }
460 
461   int scale_;
462   bool power_of_two_plus_one_;
463 };
464 
465 using Int32AddMatcher =
466     AddMatcher<Int32BinopMatcher, IrOpcode::kInt32Add, IrOpcode::kInt32Sub,
467                IrOpcode::kInt32Mul, IrOpcode::kWord32Shl>;
468 using Int64AddMatcher =
469     AddMatcher<Int64BinopMatcher, IrOpcode::kInt64Add, IrOpcode::kInt64Sub,
470                IrOpcode::kInt64Mul, IrOpcode::kWord64Shl>;
471 
472 enum DisplacementMode { kPositiveDisplacement, kNegativeDisplacement };
473 
474 enum class AddressOption : uint8_t {
475   kAllowNone = 0u,
476   kAllowInputSwap = 1u << 0,
477   kAllowScale = 1u << 1,
478   kAllowAll = kAllowInputSwap | kAllowScale
479 };
480 
481 using AddressOptions = base::Flags<AddressOption, uint8_t>;
482 DEFINE_OPERATORS_FOR_FLAGS(AddressOptions)
483 
484 template <class AddMatcher>
485 struct BaseWithIndexAndDisplacementMatcher {
BaseWithIndexAndDisplacementMatcherBaseWithIndexAndDisplacementMatcher486   BaseWithIndexAndDisplacementMatcher(Node* node, AddressOptions options)
487       : matches_(false),
488         index_(nullptr),
489         scale_(0),
490         base_(nullptr),
491         displacement_(nullptr),
492         displacement_mode_(kPositiveDisplacement) {
493     Initialize(node, options);
494   }
495 
BaseWithIndexAndDisplacementMatcherBaseWithIndexAndDisplacementMatcher496   explicit BaseWithIndexAndDisplacementMatcher(Node* node)
497       : matches_(false),
498         index_(nullptr),
499         scale_(0),
500         base_(nullptr),
501         displacement_(nullptr),
502         displacement_mode_(kPositiveDisplacement) {
503     Initialize(node, AddressOption::kAllowScale |
504                          (node->op()->HasProperty(Operator::kCommutative)
505                               ? AddressOption::kAllowInputSwap
506                               : AddressOption::kAllowNone));
507   }
508 
matchesBaseWithIndexAndDisplacementMatcher509   bool matches() const { return matches_; }
indexBaseWithIndexAndDisplacementMatcher510   Node* index() const { return index_; }
scaleBaseWithIndexAndDisplacementMatcher511   int scale() const { return scale_; }
baseBaseWithIndexAndDisplacementMatcher512   Node* base() const { return base_; }
displacementBaseWithIndexAndDisplacementMatcher513   Node* displacement() const { return displacement_; }
displacement_modeBaseWithIndexAndDisplacementMatcher514   DisplacementMode displacement_mode() const { return displacement_mode_; }
515 
516  private:
517   bool matches_;
518   Node* index_;
519   int scale_;
520   Node* base_;
521   Node* displacement_;
522   DisplacementMode displacement_mode_;
523 
InitializeBaseWithIndexAndDisplacementMatcher524   void Initialize(Node* node, AddressOptions options) {
525     // The BaseWithIndexAndDisplacementMatcher canonicalizes the order of
526     // displacements and scale factors that are used as inputs, so instead of
527     // enumerating all possible patterns by brute force, checking for node
528     // clusters using the following templates in the following order suffices to
529     // find all of the interesting cases (S = index * scale, B = base input, D =
530     // displacement input):
531     // (S + (B + D))
532     // (S + (B + B))
533     // (S + D)
534     // (S + B)
535     // ((S + D) + B)
536     // ((S + B) + D)
537     // ((B + D) + B)
538     // ((B + B) + D)
539     // (B + D)
540     // (B + B)
541     if (node->InputCount() < 2) return;
542     AddMatcher m(node, options & AddressOption::kAllowInputSwap);
543     Node* left = m.left().node();
544     Node* right = m.right().node();
545     Node* displacement = nullptr;
546     Node* base = nullptr;
547     Node* index = nullptr;
548     Node* scale_expression = nullptr;
549     bool power_of_two_plus_one = false;
550     DisplacementMode displacement_mode = kPositiveDisplacement;
551     int scale = 0;
552     if (m.HasIndexInput() && OwnedByAddressingOperand(left)) {
553       index = m.IndexInput();
554       scale = m.scale();
555       scale_expression = left;
556       power_of_two_plus_one = m.power_of_two_plus_one();
557       bool match_found = false;
558       if (right->opcode() == AddMatcher::kSubOpcode &&
559           OwnedByAddressingOperand(right)) {
560         AddMatcher right_matcher(right);
561         if (right_matcher.right().HasResolvedValue()) {
562           // (S + (B - D))
563           base = right_matcher.left().node();
564           displacement = right_matcher.right().node();
565           displacement_mode = kNegativeDisplacement;
566           match_found = true;
567         }
568       }
569       if (!match_found) {
570         if (right->opcode() == AddMatcher::kAddOpcode &&
571             OwnedByAddressingOperand(right)) {
572           AddMatcher right_matcher(right);
573           if (right_matcher.right().HasResolvedValue()) {
574             // (S + (B + D))
575             base = right_matcher.left().node();
576             displacement = right_matcher.right().node();
577           } else {
578             // (S + (B + B))
579             base = right;
580           }
581         } else if (m.right().HasResolvedValue()) {
582           // (S + D)
583           displacement = right;
584         } else {
585           // (S + B)
586           base = right;
587         }
588       }
589     } else {
590       bool match_found = false;
591       if (left->opcode() == AddMatcher::kSubOpcode &&
592           OwnedByAddressingOperand(left)) {
593         AddMatcher left_matcher(left);
594         Node* left_left = left_matcher.left().node();
595         Node* left_right = left_matcher.right().node();
596         if (left_matcher.right().HasResolvedValue()) {
597           if (left_matcher.HasIndexInput() && left_left->OwnedBy(left)) {
598             // ((S - D) + B)
599             index = left_matcher.IndexInput();
600             scale = left_matcher.scale();
601             scale_expression = left_left;
602             power_of_two_plus_one = left_matcher.power_of_two_plus_one();
603             displacement = left_right;
604             displacement_mode = kNegativeDisplacement;
605             base = right;
606           } else {
607             // ((B - D) + B)
608             index = left_left;
609             displacement = left_right;
610             displacement_mode = kNegativeDisplacement;
611             base = right;
612           }
613           match_found = true;
614         }
615       }
616       if (!match_found) {
617         if (left->opcode() == AddMatcher::kAddOpcode &&
618             OwnedByAddressingOperand(left)) {
619           AddMatcher left_matcher(left);
620           Node* left_left = left_matcher.left().node();
621           Node* left_right = left_matcher.right().node();
622           if (left_matcher.HasIndexInput() && left_left->OwnedBy(left)) {
623             if (left_matcher.right().HasResolvedValue()) {
624               // ((S + D) + B)
625               index = left_matcher.IndexInput();
626               scale = left_matcher.scale();
627               scale_expression = left_left;
628               power_of_two_plus_one = left_matcher.power_of_two_plus_one();
629               displacement = left_right;
630               base = right;
631             } else if (m.right().HasResolvedValue()) {
632               if (left->OwnedBy(node)) {
633                 // ((S + B) + D)
634                 index = left_matcher.IndexInput();
635                 scale = left_matcher.scale();
636                 scale_expression = left_left;
637                 power_of_two_plus_one = left_matcher.power_of_two_plus_one();
638                 base = left_right;
639                 displacement = right;
640               } else {
641                 // (B + D)
642                 base = left;
643                 displacement = right;
644               }
645             } else {
646               // (B + B)
647               index = left;
648               base = right;
649             }
650           } else {
651             if (left_matcher.right().HasResolvedValue()) {
652               // ((B + D) + B)
653               index = left_left;
654               displacement = left_right;
655               base = right;
656             } else if (m.right().HasResolvedValue()) {
657               if (left->OwnedBy(node)) {
658                 // ((B + B) + D)
659                 index = left_left;
660                 base = left_right;
661                 displacement = right;
662               } else {
663                 // (B + D)
664                 base = left;
665                 displacement = right;
666               }
667             } else {
668               // (B + B)
669               index = left;
670               base = right;
671             }
672           }
673         } else {
674           if (m.right().HasResolvedValue()) {
675             // (B + D)
676             base = left;
677             displacement = right;
678           } else {
679             // (B + B)
680             base = left;
681             index = right;
682           }
683         }
684       }
685     }
686     int64_t value = 0;
687     if (displacement != nullptr) {
688       switch (displacement->opcode()) {
689         case IrOpcode::kInt32Constant: {
690           value = OpParameter<int32_t>(displacement->op());
691           break;
692         }
693         case IrOpcode::kInt64Constant: {
694           value = OpParameter<int64_t>(displacement->op());
695           break;
696         }
697         default:
698           UNREACHABLE();
699           break;
700       }
701       if (value == 0) {
702         displacement = nullptr;
703       }
704     }
705     if (power_of_two_plus_one) {
706       if (base != nullptr) {
707         // If the scale requires explicitly using the index as the base, but a
708         // base is already part of the match, then the (1 << N + 1) scale factor
709         // can't be folded into the match and the entire index * scale
710         // calculation must be computed separately.
711         index = scale_expression;
712         scale = 0;
713       } else {
714         base = index;
715       }
716     }
717     if (!(options & AddressOption::kAllowScale) && scale != 0) {
718       index = scale_expression;
719       scale = 0;
720     }
721     base_ = base;
722     displacement_ = displacement;
723     displacement_mode_ = displacement_mode;
724     index_ = index;
725     scale_ = scale;
726     matches_ = true;
727   }
728 
OwnedByAddressingOperandBaseWithIndexAndDisplacementMatcher729   static bool OwnedByAddressingOperand(Node* node) {
730     for (auto use : node->use_edges()) {
731       Node* from = use.from();
732       switch (from->opcode()) {
733         case IrOpcode::kLoad:
734         case IrOpcode::kPoisonedLoad:
735         case IrOpcode::kProtectedLoad:
736         case IrOpcode::kInt32Add:
737         case IrOpcode::kInt64Add:
738           // Skip addressing uses.
739           break;
740         case IrOpcode::kStore:
741         case IrOpcode::kProtectedStore:
742           // If the stored value is this node, it is not an addressing use.
743           if (from->InputAt(2) == node) return false;
744           // Otherwise it is used as an address and skipped.
745           break;
746         default:
747           // Non-addressing use found.
748           return false;
749       }
750     }
751     return true;
752   }
753 };
754 
755 using BaseWithIndexAndDisplacement32Matcher =
756     BaseWithIndexAndDisplacementMatcher<Int32AddMatcher>;
757 using BaseWithIndexAndDisplacement64Matcher =
758     BaseWithIndexAndDisplacementMatcher<Int64AddMatcher>;
759 
760 struct V8_EXPORT_PRIVATE BranchMatcher : public NON_EXPORTED_BASE(NodeMatcher) {
761   explicit BranchMatcher(Node* branch);
762 
MatchedBranchMatcher763   bool Matched() const { return if_true_ && if_false_; }
764 
BranchBranchMatcher765   Node* Branch() const { return node(); }
IfTrueBranchMatcher766   Node* IfTrue() const { return if_true_; }
IfFalseBranchMatcher767   Node* IfFalse() const { return if_false_; }
768 
769  private:
770   Node* if_true_;
771   Node* if_false_;
772 };
773 
774 struct V8_EXPORT_PRIVATE DiamondMatcher
775     : public NON_EXPORTED_BASE(NodeMatcher) {
776   explicit DiamondMatcher(Node* merge);
777 
MatchedDiamondMatcher778   bool Matched() const { return branch_; }
IfProjectionsAreOwnedDiamondMatcher779   bool IfProjectionsAreOwned() const {
780     return if_true_->OwnedBy(node()) && if_false_->OwnedBy(node());
781   }
782 
BranchDiamondMatcher783   Node* Branch() const { return branch_; }
IfTrueDiamondMatcher784   Node* IfTrue() const { return if_true_; }
IfFalseDiamondMatcher785   Node* IfFalse() const { return if_false_; }
MergeDiamondMatcher786   Node* Merge() const { return node(); }
787 
TrueInputOfDiamondMatcher788   Node* TrueInputOf(Node* phi) const {
789     DCHECK(IrOpcode::IsPhiOpcode(phi->opcode()));
790     DCHECK_EQ(3, phi->InputCount());
791     DCHECK_EQ(Merge(), phi->InputAt(2));
792     return phi->InputAt(if_true_ == Merge()->InputAt(0) ? 0 : 1);
793   }
794 
FalseInputOfDiamondMatcher795   Node* FalseInputOf(Node* phi) const {
796     DCHECK(IrOpcode::IsPhiOpcode(phi->opcode()));
797     DCHECK_EQ(3, phi->InputCount());
798     DCHECK_EQ(Merge(), phi->InputAt(2));
799     return phi->InputAt(if_true_ == Merge()->InputAt(0) ? 1 : 0);
800   }
801 
802  private:
803   Node* branch_;
804   Node* if_true_;
805   Node* if_false_;
806 };
807 
808 }  // namespace compiler
809 }  // namespace internal
810 }  // namespace v8
811 
812 #endif  // V8_COMPILER_NODE_MATCHERS_H_
813