V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
node-matchers.h
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 
10 #include "src/base/compiler-specific.h"
11 #include "src/compiler/node.h"
12 #include "src/compiler/operator.h"
13 #include "src/double.h"
14 #include "src/external-reference.h"
15 #include "src/globals.h"
16 
17 namespace v8 {
18 namespace internal {
19 namespace compiler {
20 
21 class JSHeapBroker;
22 
23 // A pattern matcher for nodes.
24 struct NodeMatcher {
25  explicit NodeMatcher(Node* node) : node_(node) {}
26 
27  Node* node() const { return node_; }
28  const Operator* op() const { return node()->op(); }
29  IrOpcode::Value opcode() const { return node()->opcode(); }
30 
31  bool HasProperty(Operator::Property property) const {
32  return op()->HasProperty(property);
33  }
34  Node* InputAt(int index) const { return node()->InputAt(index); }
35 
36  bool Equals(const Node* node) const { return node_ == node; }
37 
38  bool IsComparison() const;
39 
40 #define DEFINE_IS_OPCODE(Opcode) \
41  bool Is##Opcode() const { return opcode() == IrOpcode::k##Opcode; }
42  ALL_OP_LIST(DEFINE_IS_OPCODE)
43 #undef DEFINE_IS_OPCODE
44 
45  private:
46  Node* node_;
47 };
48 
49 
50 // A pattern matcher for abitrary value constants.
51 template <typename T, IrOpcode::Value kOpcode>
52 struct ValueMatcher : public NodeMatcher {
53  typedef T ValueType;
54 
55  explicit ValueMatcher(Node* node)
56  : NodeMatcher(node), value_(), has_value_(opcode() == kOpcode) {
57  if (has_value_) {
58  value_ = OpParameter<T>(node->op());
59  }
60  }
61 
62  bool HasValue() const { return has_value_; }
63  const T& Value() const {
64  DCHECK(HasValue());
65  return value_;
66  }
67 
68  private:
69  T value_;
70  bool has_value_;
71 };
72 
73 
74 template <>
76  Node* node)
77  : NodeMatcher(node),
78  value_(),
79  has_value_(opcode() == IrOpcode::kInt32Constant) {
80  if (has_value_) {
81  value_ = static_cast<uint32_t>(OpParameter<int32_t>(node->op()));
82  }
83 }
84 
85 
86 template <>
87 inline ValueMatcher<int64_t, IrOpcode::kInt64Constant>::ValueMatcher(Node* node)
88  : NodeMatcher(node), value_(), has_value_(false) {
89  if (opcode() == IrOpcode::kInt32Constant) {
90  value_ = OpParameter<int32_t>(node->op());
91  has_value_ = true;
92  } else if (opcode() == IrOpcode::kInt64Constant) {
93  value_ = OpParameter<int64_t>(node->op());
94  has_value_ = true;
95  }
96 }
97 
98 
99 template <>
100 inline ValueMatcher<uint64_t, IrOpcode::kInt64Constant>::ValueMatcher(
101  Node* node)
102  : NodeMatcher(node), value_(), has_value_(false) {
103  if (opcode() == IrOpcode::kInt32Constant) {
104  value_ = static_cast<uint32_t>(OpParameter<int32_t>(node->op()));
105  has_value_ = true;
106  } else if (opcode() == IrOpcode::kInt64Constant) {
107  value_ = static_cast<uint64_t>(OpParameter<int64_t>(node->op()));
108  has_value_ = true;
109  }
110 }
111 
112 
113 // A pattern matcher for integer constants.
114 template <typename T, IrOpcode::Value kOpcode>
115 struct IntMatcher final : public ValueMatcher<T, kOpcode> {
116  explicit IntMatcher(Node* node) : ValueMatcher<T, kOpcode>(node) {}
117 
118  bool Is(const T& value) const {
119  return this->HasValue() && this->Value() == value;
120  }
121  bool IsInRange(const T& low, const T& high) const {
122  return this->HasValue() && low <= this->Value() && this->Value() <= high;
123  }
124  bool IsMultipleOf(T n) const {
125  return this->HasValue() && (this->Value() % n) == 0;
126  }
127  bool IsPowerOf2() const {
128  return this->HasValue() && this->Value() > 0 &&
129  (this->Value() & (this->Value() - 1)) == 0;
130  }
131  bool IsNegativePowerOf2() const {
132  return this->HasValue() && this->Value() < 0 &&
133  (-this->Value() & (-this->Value() - 1)) == 0;
134  }
135  bool IsNegative() const { return this->HasValue() && this->Value() < 0; }
136 };
137 
142 #if V8_HOST_ARCH_32_BIT
145 #else
148 #endif
149 
150 
151 // A pattern matcher for floating point constants.
152 template <typename T, IrOpcode::Value kOpcode>
153 struct FloatMatcher final : public ValueMatcher<T, kOpcode> {
154  explicit FloatMatcher(Node* node) : ValueMatcher<T, kOpcode>(node) {}
155 
156  bool Is(const T& value) const {
157  return this->HasValue() && this->Value() == value;
158  }
159  bool IsInRange(const T& low, const T& high) const {
160  return this->HasValue() && low <= this->Value() && this->Value() <= high;
161  }
162  bool IsMinusZero() const {
163  return this->Is(0.0) && std::signbit(this->Value());
164  }
165  bool IsNegative() const { return this->HasValue() && this->Value() < 0.0; }
166  bool IsNaN() const { return this->HasValue() && std::isnan(this->Value()); }
167  bool IsZero() const { return this->Is(0.0) && !std::signbit(this->Value()); }
168  bool IsNormal() const {
169  return this->HasValue() && std::isnormal(this->Value());
170  }
171  bool IsInteger() const {
172  return this->HasValue() && std::nearbyint(this->Value()) == this->Value();
173  }
174  bool IsPositiveOrNegativePowerOf2() const {
175  if (!this->HasValue() || (this->Value() == 0.0)) {
176  return false;
177  }
178  Double value = Double(this->Value());
179  return !value.IsInfinite() && base::bits::IsPowerOfTwo(value.Significand());
180  }
181 };
182 
186 
187 
188 // A pattern matcher for heap object constants.
189 struct HeapObjectMatcher final
190  : public ValueMatcher<Handle<HeapObject>, IrOpcode::kHeapConstant> {
191  explicit HeapObjectMatcher(Node* node)
192  : ValueMatcher<Handle<HeapObject>, IrOpcode::kHeapConstant>(node) {}
193 
194  bool Is(Handle<HeapObject> const& value) const {
195  return this->HasValue() && this->Value().address() == value.address();
196  }
197 
198  ObjectRef Ref(JSHeapBroker* broker) const {
199  return ObjectRef(broker, this->Value());
200  }
201 };
202 
203 
204 // A pattern matcher for external reference constants.
206  : public ValueMatcher<ExternalReference, IrOpcode::kExternalConstant> {
207  explicit ExternalReferenceMatcher(Node* node)
209  bool Is(const ExternalReference& value) const {
210  return this->HasValue() && this->Value() == value;
211  }
212 };
213 
214 
215 // For shorter pattern matching code, this struct matches the inputs to
216 // machine-level load operations.
217 template <typename Object>
218 struct LoadMatcher : public NodeMatcher {
219  explicit LoadMatcher(Node* node)
220  : NodeMatcher(node), object_(InputAt(0)), index_(InputAt(1)) {}
221 
222  typedef Object ObjectMatcher;
223 
224  Object const& object() const { return object_; }
225  IntPtrMatcher const& index() const { return index_; }
226 
227  private:
228  Object const object_;
229  IntPtrMatcher const index_;
230 };
231 
232 
233 // For shorter pattern matching code, this struct matches both the left and
234 // right hand sides of a binary operation and can put constants on the right
235 // if they appear on the left hand side of a commutative operation.
236 template <typename Left, typename Right>
237 struct BinopMatcher : public NodeMatcher {
238  explicit BinopMatcher(Node* node)
239  : NodeMatcher(node), left_(InputAt(0)), right_(InputAt(1)) {
240  if (HasProperty(Operator::kCommutative)) PutConstantOnRight();
241  }
242  BinopMatcher(Node* node, bool allow_input_swap)
243  : NodeMatcher(node), left_(InputAt(0)), right_(InputAt(1)) {
244  if (allow_input_swap) PutConstantOnRight();
245  }
246 
247  typedef Left LeftMatcher;
248  typedef Right RightMatcher;
249 
250  const Left& left() const { return left_; }
251  const Right& right() const { return right_; }
252 
253  bool IsFoldable() const { return left().HasValue() && right().HasValue(); }
254  bool LeftEqualsRight() const { return left().node() == right().node(); }
255 
256  protected:
257  void SwapInputs() {
258  std::swap(left_, right_);
259  // TODO(tebbi): This modification should notify the reducers using
260  // BinopMatcher. Alternatively, all reducers (especially value numbering)
261  // could ignore the ordering for commutative binops.
262  node()->ReplaceInput(0, left().node());
263  node()->ReplaceInput(1, right().node());
264  }
265 
266  private:
267  void PutConstantOnRight() {
268  if (left().HasValue() && !right().HasValue()) {
269  SwapInputs();
270  }
271  }
272 
273  Left left_;
274  Right right_;
275 };
276 
288 
289 template <class BinopMatcher, IrOpcode::Value kMulOpcode,
290  IrOpcode::Value kShiftOpcode>
291 struct ScaleMatcher {
292  explicit ScaleMatcher(Node* node, bool allow_power_of_two_plus_one = false)
293  : scale_(-1), power_of_two_plus_one_(false) {
294  if (node->InputCount() < 2) return;
295  BinopMatcher m(node);
296  if (node->opcode() == kShiftOpcode) {
297  if (m.right().HasValue()) {
298  typename BinopMatcher::RightMatcher::ValueType value =
299  m.right().Value();
300  if (value >= 0 && value <= 3) {
301  scale_ = static_cast<int>(value);
302  }
303  }
304  } else if (node->opcode() == kMulOpcode) {
305  if (m.right().HasValue()) {
306  typename BinopMatcher::RightMatcher::ValueType value =
307  m.right().Value();
308  if (value == 1) {
309  scale_ = 0;
310  } else if (value == 2) {
311  scale_ = 1;
312  } else if (value == 4) {
313  scale_ = 2;
314  } else if (value == 8) {
315  scale_ = 3;
316  } else if (allow_power_of_two_plus_one) {
317  if (value == 3) {
318  scale_ = 1;
319  power_of_two_plus_one_ = true;
320  } else if (value == 5) {
321  scale_ = 2;
322  power_of_two_plus_one_ = true;
323  } else if (value == 9) {
324  scale_ = 3;
325  power_of_two_plus_one_ = true;
326  }
327  }
328  }
329  }
330  }
331 
332  bool matches() const { return scale_ != -1; }
333  int scale() const { return scale_; }
334  bool power_of_two_plus_one() const { return power_of_two_plus_one_; }
335 
336  private:
337  int scale_;
338  bool power_of_two_plus_one_;
339 };
340 
341 typedef ScaleMatcher<Int32BinopMatcher, IrOpcode::kInt32Mul,
342  IrOpcode::kWord32Shl> Int32ScaleMatcher;
343 typedef ScaleMatcher<Int64BinopMatcher, IrOpcode::kInt64Mul,
344  IrOpcode::kWord64Shl> Int64ScaleMatcher;
345 
346 template <class BinopMatcher, IrOpcode::Value AddOpcode,
347  IrOpcode::Value SubOpcode, IrOpcode::Value kMulOpcode,
348  IrOpcode::Value kShiftOpcode>
349 struct AddMatcher : public BinopMatcher {
350  static const IrOpcode::Value kAddOpcode = AddOpcode;
351  static const IrOpcode::Value kSubOpcode = SubOpcode;
353 
354  AddMatcher(Node* node, bool allow_input_swap)
355  : BinopMatcher(node, allow_input_swap),
356  scale_(-1),
357  power_of_two_plus_one_(false) {
358  Initialize(node, allow_input_swap);
359  }
360  explicit AddMatcher(Node* node)
361  : BinopMatcher(node, node->op()->HasProperty(Operator::kCommutative)),
362  scale_(-1),
363  power_of_two_plus_one_(false) {
364  Initialize(node, node->op()->HasProperty(Operator::kCommutative));
365  }
366 
367  bool HasIndexInput() const { return scale_ != -1; }
368  Node* IndexInput() const {
369  DCHECK(HasIndexInput());
370  return this->left().node()->InputAt(0);
371  }
372  int scale() const {
373  DCHECK(HasIndexInput());
374  return scale_;
375  }
376  bool power_of_two_plus_one() const { return power_of_two_plus_one_; }
377 
378  private:
379  void Initialize(Node* node, bool allow_input_swap) {
380  Matcher left_matcher(this->left().node(), true);
381  if (left_matcher.matches()) {
382  scale_ = left_matcher.scale();
383  power_of_two_plus_one_ = left_matcher.power_of_two_plus_one();
384  return;
385  }
386 
387  if (!allow_input_swap) {
388  return;
389  }
390 
391  Matcher right_matcher(this->right().node(), true);
392  if (right_matcher.matches()) {
393  scale_ = right_matcher.scale();
394  power_of_two_plus_one_ = right_matcher.power_of_two_plus_one();
395  this->SwapInputs();
396  return;
397  }
398 
399  if ((this->left().opcode() != kSubOpcode &&
400  this->left().opcode() != kAddOpcode) &&
401  (this->right().opcode() == kAddOpcode ||
402  this->right().opcode() == kSubOpcode)) {
403  this->SwapInputs();
404  }
405  }
406 
407  int scale_;
408  bool power_of_two_plus_one_;
409 };
410 
411 typedef AddMatcher<Int32BinopMatcher, IrOpcode::kInt32Add, IrOpcode::kInt32Sub,
412  IrOpcode::kInt32Mul, IrOpcode::kWord32Shl>
414 typedef AddMatcher<Int64BinopMatcher, IrOpcode::kInt64Add, IrOpcode::kInt64Sub,
415  IrOpcode::kInt64Mul, IrOpcode::kWord64Shl>
417 
418 enum DisplacementMode { kPositiveDisplacement, kNegativeDisplacement };
419 
420 enum class AddressOption : uint8_t {
421  kAllowNone = 0u,
422  kAllowInputSwap = 1u << 0,
423  kAllowScale = 1u << 1,
424  kAllowAll = kAllowInputSwap | kAllowScale
425 };
426 
427 typedef base::Flags<AddressOption, uint8_t> AddressOptions;
428 DEFINE_OPERATORS_FOR_FLAGS(AddressOptions);
429 
430 template <class AddMatcher>
433  : matches_(false),
434  index_(nullptr),
435  scale_(0),
436  base_(nullptr),
437  displacement_(nullptr),
438  displacement_mode_(kPositiveDisplacement) {
439  Initialize(node, options);
440  }
441 
443  : matches_(false),
444  index_(nullptr),
445  scale_(0),
446  base_(nullptr),
447  displacement_(nullptr),
448  displacement_mode_(kPositiveDisplacement) {
449  Initialize(node, AddressOption::kAllowScale |
450  (node->op()->HasProperty(Operator::kCommutative)
451  ? AddressOption::kAllowInputSwap
452  : AddressOption::kAllowNone));
453  }
454 
455  bool matches() const { return matches_; }
456  Node* index() const { return index_; }
457  int scale() const { return scale_; }
458  Node* base() const { return base_; }
459  Node* displacement() const { return displacement_; }
460  DisplacementMode displacement_mode() const { return displacement_mode_; }
461 
462  private:
463  bool matches_;
464  Node* index_;
465  int scale_;
466  Node* base_;
467  Node* displacement_;
468  DisplacementMode displacement_mode_;
469 
470  void Initialize(Node* node, AddressOptions options) {
471  // The BaseWithIndexAndDisplacementMatcher canonicalizes the order of
472  // displacements and scale factors that are used as inputs, so instead of
473  // enumerating all possible patterns by brute force, checking for node
474  // clusters using the following templates in the following order suffices to
475  // find all of the interesting cases (S = index * scale, B = base input, D =
476  // displacement input):
477  // (S + (B + D))
478  // (S + (B + B))
479  // (S + D)
480  // (S + B)
481  // ((S + D) + B)
482  // ((S + B) + D)
483  // ((B + D) + B)
484  // ((B + B) + D)
485  // (B + D)
486  // (B + B)
487  if (node->InputCount() < 2) return;
488  AddMatcher m(node, options & AddressOption::kAllowInputSwap);
489  Node* left = m.left().node();
490  Node* right = m.right().node();
491  Node* displacement = nullptr;
492  Node* base = nullptr;
493  Node* index = nullptr;
494  Node* scale_expression = nullptr;
495  bool power_of_two_plus_one = false;
496  DisplacementMode displacement_mode = kPositiveDisplacement;
497  int scale = 0;
498  if (m.HasIndexInput() && OwnedByAddressingOperand(left)) {
499  index = m.IndexInput();
500  scale = m.scale();
501  scale_expression = left;
502  power_of_two_plus_one = m.power_of_two_plus_one();
503  bool match_found = false;
504  if (right->opcode() == AddMatcher::kSubOpcode &&
505  OwnedByAddressingOperand(right)) {
506  AddMatcher right_matcher(right);
507  if (right_matcher.right().HasValue()) {
508  // (S + (B - D))
509  base = right_matcher.left().node();
510  displacement = right_matcher.right().node();
511  displacement_mode = kNegativeDisplacement;
512  match_found = true;
513  }
514  }
515  if (!match_found) {
516  if (right->opcode() == AddMatcher::kAddOpcode &&
517  OwnedByAddressingOperand(right)) {
518  AddMatcher right_matcher(right);
519  if (right_matcher.right().HasValue()) {
520  // (S + (B + D))
521  base = right_matcher.left().node();
522  displacement = right_matcher.right().node();
523  } else {
524  // (S + (B + B))
525  base = right;
526  }
527  } else if (m.right().HasValue()) {
528  // (S + D)
529  displacement = right;
530  } else {
531  // (S + B)
532  base = right;
533  }
534  }
535  } else {
536  bool match_found = false;
537  if (left->opcode() == AddMatcher::kSubOpcode &&
538  OwnedByAddressingOperand(left)) {
539  AddMatcher left_matcher(left);
540  Node* left_left = left_matcher.left().node();
541  Node* left_right = left_matcher.right().node();
542  if (left_matcher.right().HasValue()) {
543  if (left_matcher.HasIndexInput() && left_left->OwnedBy(left)) {
544  // ((S - D) + B)
545  index = left_matcher.IndexInput();
546  scale = left_matcher.scale();
547  scale_expression = left_left;
548  power_of_two_plus_one = left_matcher.power_of_two_plus_one();
549  displacement = left_right;
550  displacement_mode = kNegativeDisplacement;
551  base = right;
552  } else {
553  // ((B - D) + B)
554  index = left_left;
555  displacement = left_right;
556  displacement_mode = kNegativeDisplacement;
557  base = right;
558  }
559  match_found = true;
560  }
561  }
562  if (!match_found) {
563  if (left->opcode() == AddMatcher::kAddOpcode &&
564  OwnedByAddressingOperand(left)) {
565  AddMatcher left_matcher(left);
566  Node* left_left = left_matcher.left().node();
567  Node* left_right = left_matcher.right().node();
568  if (left_matcher.HasIndexInput() && left_left->OwnedBy(left)) {
569  if (left_matcher.right().HasValue()) {
570  // ((S + D) + B)
571  index = left_matcher.IndexInput();
572  scale = left_matcher.scale();
573  scale_expression = left_left;
574  power_of_two_plus_one = left_matcher.power_of_two_plus_one();
575  displacement = left_right;
576  base = right;
577  } else if (m.right().HasValue()) {
578  if (left->OwnedBy(node)) {
579  // ((S + B) + D)
580  index = left_matcher.IndexInput();
581  scale = left_matcher.scale();
582  scale_expression = left_left;
583  power_of_two_plus_one = left_matcher.power_of_two_plus_one();
584  base = left_right;
585  displacement = right;
586  } else {
587  // (B + D)
588  base = left;
589  displacement = right;
590  }
591  } else {
592  // (B + B)
593  index = left;
594  base = right;
595  }
596  } else {
597  if (left_matcher.right().HasValue()) {
598  // ((B + D) + B)
599  index = left_left;
600  displacement = left_right;
601  base = right;
602  } else if (m.right().HasValue()) {
603  if (left->OwnedBy(node)) {
604  // ((B + B) + D)
605  index = left_left;
606  base = left_right;
607  displacement = right;
608  } else {
609  // (B + D)
610  base = left;
611  displacement = right;
612  }
613  } else {
614  // (B + B)
615  index = left;
616  base = right;
617  }
618  }
619  } else {
620  if (m.right().HasValue()) {
621  // (B + D)
622  base = left;
623  displacement = right;
624  } else {
625  // (B + B)
626  base = left;
627  index = right;
628  }
629  }
630  }
631  }
632  int64_t value = 0;
633  if (displacement != nullptr) {
634  switch (displacement->opcode()) {
635  case IrOpcode::kInt32Constant: {
636  value = OpParameter<int32_t>(displacement->op());
637  break;
638  }
639  case IrOpcode::kInt64Constant: {
640  value = OpParameter<int64_t>(displacement->op());
641  break;
642  }
643  default:
644  UNREACHABLE();
645  break;
646  }
647  if (value == 0) {
648  displacement = nullptr;
649  }
650  }
651  if (power_of_two_plus_one) {
652  if (base != nullptr) {
653  // If the scale requires explicitly using the index as the base, but a
654  // base is already part of the match, then the (1 << N + 1) scale factor
655  // can't be folded into the match and the entire index * scale
656  // calculation must be computed separately.
657  index = scale_expression;
658  scale = 0;
659  } else {
660  base = index;
661  }
662  }
663  if (!(options & AddressOption::kAllowScale) && scale != 0) {
664  index = scale_expression;
665  scale = 0;
666  }
667  base_ = base;
668  displacement_ = displacement;
669  displacement_mode_ = displacement_mode;
670  index_ = index;
671  scale_ = scale;
672  matches_ = true;
673  }
674 
675  static bool OwnedByAddressingOperand(Node* node) {
676  for (auto use : node->use_edges()) {
677  Node* from = use.from();
678  switch (from->opcode()) {
679  case IrOpcode::kLoad:
680  case IrOpcode::kPoisonedLoad:
681  case IrOpcode::kInt32Add:
682  case IrOpcode::kInt64Add:
683  // Skip addressing uses.
684  break;
685  case IrOpcode::kStore:
686  // If the stored value is this node, it is not an addressing use.
687  if (from->InputAt(2) == node) return false;
688  // Otherwise it is used as an address and skipped.
689  break;
690  default:
691  // Non-addressing use found.
692  return false;
693  }
694  }
695  return true;
696  }
697 };
698 
703 
704 struct V8_EXPORT_PRIVATE BranchMatcher : public NON_EXPORTED_BASE(NodeMatcher) {
705  explicit BranchMatcher(Node* branch);
706 
707  bool Matched() const { return if_true_ && if_false_; }
708 
709  Node* Branch() const { return node(); }
710  Node* IfTrue() const { return if_true_; }
711  Node* IfFalse() const { return if_false_; }
712 
713  private:
714  Node* if_true_;
715  Node* if_false_;
716 };
717 
718 struct V8_EXPORT_PRIVATE DiamondMatcher
719  : public NON_EXPORTED_BASE(NodeMatcher) {
720  explicit DiamondMatcher(Node* merge);
721 
722  bool Matched() const { return branch_; }
723  bool IfProjectionsAreOwned() const {
724  return if_true_->OwnedBy(node()) && if_false_->OwnedBy(node());
725  }
726 
727  Node* Branch() const { return branch_; }
728  Node* IfTrue() const { return if_true_; }
729  Node* IfFalse() const { return if_false_; }
730  Node* Merge() const { return node(); }
731 
732  Node* TrueInputOf(Node* phi) const {
733  DCHECK(IrOpcode::IsPhiOpcode(phi->opcode()));
734  DCHECK_EQ(3, phi->InputCount());
735  DCHECK_EQ(Merge(), phi->InputAt(2));
736  return phi->InputAt(if_true_ == Merge()->InputAt(0) ? 0 : 1);
737  }
738 
739  Node* FalseInputOf(Node* phi) const {
740  DCHECK(IrOpcode::IsPhiOpcode(phi->opcode()));
741  DCHECK_EQ(3, phi->InputCount());
742  DCHECK_EQ(Merge(), phi->InputAt(2));
743  return phi->InputAt(if_true_ == Merge()->InputAt(0) ? 1 : 0);
744  }
745 
746  private:
747  Node* branch_;
748  Node* if_true_;
749  Node* if_false_;
750 };
751 
752 template <class BinopMatcher, IrOpcode::Value expected_opcode>
754  explicit WasmStackCheckMatcher(Node* compare) : compare_(compare) {}
755 
756  bool Matched() {
757  if (compare_->opcode() != expected_opcode) return false;
758  BinopMatcher m(compare_);
759  return MatchedInternal(m.left(), m.right());
760  }
761 
762  private:
763  bool MatchedInternal(const typename BinopMatcher::LeftMatcher& l,
764  const typename BinopMatcher::RightMatcher& r) {
765  // In wasm, the stack check is performed by loading the value given by
766  // the address of a field stored in the instance object. That object is
767  // passed as a parameter.
768  if (l.IsLoad() && r.IsLoadStackPointer()) {
769  LoadMatcher<LoadMatcher<NodeMatcher>> mleft(l.node());
770  if (mleft.object().IsLoad() && mleft.index().Is(0) &&
771  mleft.object().object().IsParameter()) {
772  return true;
773  }
774  }
775  return false;
776  }
777  Node* compare_;
778 };
779 
780 template <class BinopMatcher, IrOpcode::Value expected_opcode>
782  StackCheckMatcher(Isolate* isolate, Node* compare)
783  : isolate_(isolate), compare_(compare) {}
784  bool Matched() {
785  // TODO(jgruber): Ideally, we could be more flexible here and also match the
786  // same pattern with switched operands (i.e.: left is LoadStackPointer and
787  // right is the js_stack_limit load). But to be correct in all cases, we'd
788  // then have to invert the outcome of the stack check comparison.
789  if (compare_->opcode() != expected_opcode) return false;
790  BinopMatcher m(compare_);
791  return MatchedInternal(m.left(), m.right());
792  }
793 
794  private:
795  bool MatchedInternal(const typename BinopMatcher::LeftMatcher& l,
796  const typename BinopMatcher::RightMatcher& r) {
797  if (l.IsLoad() && r.IsLoadStackPointer()) {
799  ExternalReference js_stack_limit =
800  ExternalReference::address_of_stack_limit(isolate_);
801  if (mleft.object().Is(js_stack_limit) && mleft.index().Is(0)) return true;
802  }
803  return false;
804  }
805 
806  Isolate* isolate_;
807  Node* compare_;
808 };
809 
810 } // namespace compiler
811 } // namespace internal
812 } // namespace v8
813 
814 #endif // V8_COMPILER_NODE_MATCHERS_H_
Definition: v8.h:2119
Definition: libplatform.h:13