5 #ifndef V8_COMPILER_NODE_MATCHERS_H_ 6 #define V8_COMPILER_NODE_MATCHERS_H_ 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" 27 Node* node()
const {
return node_; }
28 const Operator* op()
const {
return node()->op(); }
29 IrOpcode::Value opcode()
const {
return node()->opcode(); }
31 bool HasProperty(Operator::Property property)
const {
32 return op()->HasProperty(property);
34 Node* InputAt(
int index)
const {
return node()->InputAt(index); }
36 bool Equals(
const Node* node)
const {
return node_ == node; }
38 bool IsComparison()
const;
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 51 template <
typename T, IrOpcode::Value kOpcode>
56 :
NodeMatcher(node), value_(), has_value_(opcode() == kOpcode) {
58 value_ = OpParameter<T>(node->op());
62 bool HasValue()
const {
return has_value_; }
63 const T&
Value()
const {
79 has_value_(opcode() ==
IrOpcode::kInt32Constant) {
81 value_ =
static_cast<uint32_t>(OpParameter<int32_t>(node->op()));
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());
92 }
else if (opcode() == IrOpcode::kInt64Constant) {
93 value_ = OpParameter<int64_t>(node->op());
100 inline ValueMatcher<uint64_t, IrOpcode::kInt64Constant>::ValueMatcher(
102 : NodeMatcher(node), value_(), has_value_(false) {
103 if (opcode() == IrOpcode::kInt32Constant) {
104 value_ =
static_cast<uint32_t>(OpParameter<int32_t>(node->op()));
106 }
else if (opcode() == IrOpcode::kInt64Constant) {
107 value_ =
static_cast<uint64_t
>(OpParameter<int64_t>(node->op()));
114 template <
typename T, IrOpcode::Value kOpcode>
118 bool Is(
const T& value)
const {
119 return this->HasValue() && this->
Value() == value;
121 bool IsInRange(
const T& low,
const T& high)
const {
122 return this->HasValue() && low <= this->
Value() && this->
Value() <= high;
124 bool IsMultipleOf(
T n)
const {
125 return this->HasValue() && (this->
Value() % n) == 0;
127 bool IsPowerOf2()
const {
128 return this->HasValue() && this->
Value() > 0 &&
131 bool IsNegativePowerOf2()
const {
132 return this->HasValue() && this->
Value() < 0 &&
135 bool IsNegative()
const {
return this->HasValue() && this->
Value() < 0; }
142 #if V8_HOST_ARCH_32_BIT 152 template <
typename T, IrOpcode::Value kOpcode>
156 bool Is(
const T& value)
const {
157 return this->HasValue() && this->
Value() == value;
159 bool IsInRange(
const T& low,
const T& high)
const {
160 return this->HasValue() && low <= this->
Value() && this->
Value() <= high;
162 bool IsMinusZero()
const {
163 return this->Is(0.0) && std::signbit(this->
Value());
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());
171 bool IsInteger()
const {
172 return this->HasValue() && std::nearbyint(this->
Value()) == this->
Value();
174 bool IsPositiveOrNegativePowerOf2()
const {
175 if (!this->HasValue() || (this->
Value() == 0.0)) {
179 return !value.IsInfinite() && base::bits::IsPowerOfTwo(value.Significand());
190 :
public ValueMatcher<Handle<HeapObject>, IrOpcode::kHeapConstant> {
195 return this->HasValue() && this->
Value().address() == value.address();
206 :
public ValueMatcher<ExternalReference, IrOpcode::kExternalConstant> {
210 return this->HasValue() && this->
Value() == value;
217 template <
typename Object>
220 :
NodeMatcher(node), object_(InputAt(0)), index_(InputAt(1)) {}
224 Object const& object()
const {
return object_; }
236 template <
typename Left,
typename Right>
239 :
NodeMatcher(node), left_(InputAt(0)), right_(InputAt(1)) {
240 if (HasProperty(Operator::kCommutative)) PutConstantOnRight();
243 :
NodeMatcher(node), left_(InputAt(0)), right_(InputAt(1)) {
244 if (allow_input_swap) PutConstantOnRight();
247 typedef Left LeftMatcher;
248 typedef Right RightMatcher;
250 const Left& left()
const {
return left_; }
251 const Right& right()
const {
return right_; }
253 bool IsFoldable()
const {
return left().HasValue() && right().HasValue(); }
254 bool LeftEqualsRight()
const {
return left().node() == right().node(); }
258 std::swap(left_, right_);
262 node()->ReplaceInput(0, left().node());
263 node()->ReplaceInput(1, right().node());
267 void PutConstantOnRight() {
268 if (left().HasValue() && !right().HasValue()) {
289 template <
class BinopMatcher, IrOpcode::Value kMulOpcode,
290 IrOpcode::Value kShiftOpcode>
293 : scale_(-1), power_of_two_plus_one_(
false) {
294 if (node->InputCount() < 2)
return;
296 if (node->opcode() == kShiftOpcode) {
297 if (m.right().HasValue()) {
298 typename BinopMatcher::RightMatcher::ValueType value =
300 if (value >= 0 && value <= 3) {
301 scale_ =
static_cast<int>(value);
304 }
else if (node->opcode() == kMulOpcode) {
305 if (m.right().HasValue()) {
306 typename BinopMatcher::RightMatcher::ValueType value =
310 }
else if (value == 2) {
312 }
else if (value == 4) {
314 }
else if (value == 8) {
316 }
else if (allow_power_of_two_plus_one) {
319 power_of_two_plus_one_ =
true;
320 }
else if (value == 5) {
322 power_of_two_plus_one_ =
true;
323 }
else if (value == 9) {
325 power_of_two_plus_one_ =
true;
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_; }
338 bool power_of_two_plus_one_;
346 template <
class BinopMatcher, IrOpcode::Value AddOpcode,
347 IrOpcode::Value SubOpcode, IrOpcode::Value kMulOpcode,
348 IrOpcode::Value kShiftOpcode>
350 static const IrOpcode::Value kAddOpcode = AddOpcode;
351 static const IrOpcode::Value kSubOpcode = SubOpcode;
357 power_of_two_plus_one_(
false) {
358 Initialize(node, allow_input_swap);
361 :
BinopMatcher(node, node->op()->HasProperty(Operator::kCommutative)),
363 power_of_two_plus_one_(
false) {
364 Initialize(node, node->op()->HasProperty(Operator::kCommutative));
367 bool HasIndexInput()
const {
return scale_ != -1; }
368 Node* IndexInput()
const {
369 DCHECK(HasIndexInput());
370 return this->left().node()->InputAt(0);
373 DCHECK(HasIndexInput());
376 bool power_of_two_plus_one()
const {
return power_of_two_plus_one_; }
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();
387 if (!allow_input_swap) {
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();
399 if ((this->left().opcode() != kSubOpcode &&
400 this->left().opcode() != kAddOpcode) &&
401 (this->right().opcode() == kAddOpcode ||
402 this->right().opcode() == kSubOpcode)) {
408 bool power_of_two_plus_one_;
412 IrOpcode::kInt32Mul, IrOpcode::kWord32Shl>
415 IrOpcode::kInt64Mul, IrOpcode::kWord64Shl>
418 enum DisplacementMode { kPositiveDisplacement, kNegativeDisplacement };
420 enum class AddressOption : uint8_t {
422 kAllowInputSwap = 1u << 0,
423 kAllowScale = 1u << 1,
424 kAllowAll = kAllowInputSwap | kAllowScale
428 DEFINE_OPERATORS_FOR_FLAGS(AddressOptions);
430 template <
class AddMatcher>
437 displacement_(
nullptr),
438 displacement_mode_(kPositiveDisplacement) {
439 Initialize(node, options);
447 displacement_(
nullptr),
448 displacement_mode_(kPositiveDisplacement) {
449 Initialize(node, AddressOption::kAllowScale |
450 (node->op()->HasProperty(Operator::kCommutative)
451 ? AddressOption::kAllowInputSwap
452 : AddressOption::kAllowNone));
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_; }
468 DisplacementMode displacement_mode_;
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;
498 if (m.HasIndexInput() && OwnedByAddressingOperand(left)) {
499 index = m.IndexInput();
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)) {
507 if (right_matcher.right().HasValue()) {
509 base = right_matcher.left().node();
510 displacement = right_matcher.right().node();
511 displacement_mode = kNegativeDisplacement;
516 if (right->opcode() == AddMatcher::kAddOpcode &&
517 OwnedByAddressingOperand(right)) {
519 if (right_matcher.right().HasValue()) {
521 base = right_matcher.left().node();
522 displacement = right_matcher.right().node();
527 }
else if (m.right().HasValue()) {
529 displacement = right;
536 bool match_found =
false;
537 if (left->opcode() == AddMatcher::kSubOpcode &&
538 OwnedByAddressingOperand(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)) {
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;
555 displacement = left_right;
556 displacement_mode = kNegativeDisplacement;
563 if (left->opcode() == AddMatcher::kAddOpcode &&
564 OwnedByAddressingOperand(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()) {
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;
577 }
else if (m.right().HasValue()) {
578 if (left->OwnedBy(node)) {
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();
585 displacement = right;
589 displacement = right;
597 if (left_matcher.right().HasValue()) {
600 displacement = left_right;
602 }
else if (m.right().HasValue()) {
603 if (left->OwnedBy(node)) {
607 displacement = right;
611 displacement = right;
620 if (m.right().HasValue()) {
623 displacement = right;
633 if (displacement !=
nullptr) {
634 switch (displacement->opcode()) {
635 case IrOpcode::kInt32Constant: {
636 value = OpParameter<int32_t>(displacement->op());
639 case IrOpcode::kInt64Constant: {
640 value = OpParameter<int64_t>(displacement->op());
648 displacement =
nullptr;
651 if (power_of_two_plus_one) {
652 if (base !=
nullptr) {
657 index = scale_expression;
663 if (!(options & AddressOption::kAllowScale) && scale != 0) {
664 index = scale_expression;
668 displacement_ = displacement;
669 displacement_mode_ = displacement_mode;
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:
685 case IrOpcode::kStore:
687 if (from->InputAt(2) == node)
return false;
704 struct V8_EXPORT_PRIVATE
BranchMatcher :
public NON_EXPORTED_BASE(NodeMatcher) {
707 bool Matched()
const {
return if_true_ && if_false_; }
709 Node* Branch()
const {
return node(); }
710 Node* IfTrue()
const {
return if_true_; }
711 Node* IfFalse()
const {
return if_false_; }
719 :
public NON_EXPORTED_BASE(NodeMatcher) {
722 bool Matched()
const {
return branch_; }
723 bool IfProjectionsAreOwned()
const {
724 return if_true_->OwnedBy(node()) && if_false_->OwnedBy(node());
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(); }
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);
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);
752 template <
class BinopMatcher, IrOpcode::Value expected_opcode>
757 if (compare_->opcode() != expected_opcode)
return false;
759 return MatchedInternal(m.left(), m.right());
763 bool MatchedInternal(
const typename BinopMatcher::LeftMatcher& l,
764 const typename BinopMatcher::RightMatcher& r) {
768 if (l.IsLoad() && r.IsLoadStackPointer()) {
770 if (mleft.object().IsLoad() && mleft.index().Is(0) &&
771 mleft.object().object().IsParameter()) {
780 template <
class BinopMatcher, IrOpcode::Value expected_opcode>
783 : isolate_(isolate), compare_(compare) {}
789 if (compare_->opcode() != expected_opcode)
return false;
791 return MatchedInternal(m.left(), m.right());
795 bool MatchedInternal(
const typename BinopMatcher::LeftMatcher& l,
796 const typename BinopMatcher::RightMatcher& r) {
797 if (l.IsLoad() && r.IsLoadStackPointer()) {
800 ExternalReference::address_of_stack_limit(isolate_);
801 if (mleft.object().Is(js_stack_limit) && mleft.index().Is(0))
return true;
814 #endif // V8_COMPILER_NODE_MATCHERS_H_