5#ifndef V8_COMPILER_NODE_MATCHERS_H_
6#define V8_COMPILER_NODE_MATCHERS_H_
36 return op()->HasProperty(property);
44#define DEFINE_IS_OPCODE(Opcode, ...) \
45 bool Is##Opcode() const { return opcode() == IrOpcode::k##Opcode; }
47#undef DEFINE_IS_OPCODE
66template <
typename T, IrOpcode::Value kOpcode>
100 :
NodeMatcher(node), resolved_value_(), has_resolved_value_(false) {
110 :
NodeMatcher(node), resolved_value_(), has_resolved_value_(false) {
112 if (node->opcode() == IrOpcode::kInt32Constant) {
115 }
else if (node->opcode() == IrOpcode::kInt64Constant) {
124 :
NodeMatcher(node), resolved_value_(), has_resolved_value_(false) {
126 if (node->opcode() == IrOpcode::kInt32Constant) {
129 }
else if (node->opcode() == IrOpcode::kInt64Constant) {
136template <
typename T, IrOpcode::Value kOpcode>
140 bool Is(
const T& value)
const {
168#if V8_ENABLE_WEBASSEMBLY
169using V128ConstMatcher =
172#if V8_HOST_ARCH_32_BIT
182template <
typename T, IrOpcode::Value kOpcode>
186 bool Is(
const T& value)
const {
226template <IrOpcode::Value kHeapConstantOpcode>
228 :
public ValueMatcher<IndirectHandle<HeapObject>, kHeapConstantOpcode> {
255 :
public ValueMatcher<ExternalReference, IrOpcode::kExternalConstant> {
266template <
typename Object>
285template <
typename Left,
typename Right, MachineRepresentation rep>
305 return left().HasResolvedValue() &&
right().HasResolvedValue();
330 if (
left().HasResolvedValue() && !
right().HasResolvedValue()) {
369 if (node->InputCount() < 2)
return;
371 if (node->opcode() == kShiftOpcode) {
372 if (m.right().HasResolvedValue()) {
373 typename BinopMatcher::RightMatcher::ValueType value =
374 m.right().ResolvedValue();
375 if (value >= 0 && value <= 3) {
376 scale_ = static_cast<int>(value);
379 }
else if (node->opcode() == kMulOpcode) {
380 if (m.right().HasResolvedValue()) {
381 typename BinopMatcher::RightMatcher::ValueType value =
382 m.right().ResolvedValue();
385 } else if (value == 2) {
387 } else if (value == 4) {
389 } else if (value == 8) {
391 } else if (allow_power_of_two_plus_one) {
394 power_of_two_plus_one_ = true;
395 } else if (value == 5) {
397 power_of_two_plus_one_ = true;
398 } else if (value == 9) {
400 power_of_two_plus_one_ = true;
408 int scale()
const {
return scale_; }
432 power_of_two_plus_one_(false) {
433 Initialize(node, allow_input_swap);
438 power_of_two_plus_one_(false) {
439 Initialize(node, node->op()->HasProperty(Operator::kCommutative));
445 return this->left().node()->InputAt(0);
457 scale_ = left_matcher.
scale();
462 if (!allow_input_swap) {
468 scale_ = right_matcher.
scale();
474 if ((this->left().opcode() != kSubOpcode &&
475 this->left().opcode() != kAddOpcode) &&
476 (this->right().opcode() == kAddOpcode ||
477 this->right().opcode() == kSubOpcode)) {
488 IrOpcode::kInt32Mul, IrOpcode::kWord32Shl>;
491 IrOpcode::kInt64Mul, IrOpcode::kWord64Shl>;
505template <
class AddMatcher>
512 displacement_(nullptr),
514 Initialize(node, options);
522 displacement_(nullptr),
524 Initialize(node, AddressOption::kAllowScale |
525 (node->op()->HasProperty(Operator::kCommutative)
526 ? AddressOption::kAllowInputSwap
527 : AddressOption::kAllowNone));
532 int scale()
const {
return scale_; }
562 if (node->InputCount() < 2)
return;
563 AddMatcher m(node, options & AddressOption::kAllowInputSwap);
564 Node* left =
m.left().node();
565 Node* right =
m.right().node();
568 Node* index =
nullptr;
569 Node* scale_expression =
nullptr;
570 bool power_of_two_plus_one =
false;
573 if (
m.HasIndexInput() && OwnedByAddressingOperand(left)) {
574 index =
m.IndexInput();
576 scale_expression = left;
577 power_of_two_plus_one =
m.power_of_two_plus_one();
578 bool match_found =
false;
579 if (right->opcode() == AddMatcher::kSubOpcode &&
580 OwnedByAddressingOperand(right)) {
582 if (right_matcher.
right().HasResolvedValue()) {
591 if (right->opcode() == AddMatcher::kAddOpcode &&
592 OwnedByAddressingOperand(right)) {
594 if (right_matcher.
right().HasResolvedValue()) {
602 }
else if (
m.right().HasResolvedValue()) {
611 bool match_found =
false;
612 if (left->
opcode() == AddMatcher::kSubOpcode &&
613 OwnedByAddressingOperand(left)) {
615 Node* left_left = left_matcher.
left().node();
616 Node* left_right = left_matcher.
right().node();
617 if (left_matcher.
right().HasResolvedValue()) {
619 OwnedByAddressingOperand(left_left)) {
623 scale_expression = left_left;
639 if (left->
opcode() == AddMatcher::kAddOpcode &&
640 OwnedByAddressingOperand(left)) {
642 Node* left_left = left_matcher.
left().node();
643 Node* left_right = left_matcher.
right().node();
645 OwnedByAddressingOperand(left_left)) {
646 if (left_matcher.
right().HasResolvedValue()) {
650 scale_expression = left_left;
654 }
else if (
m.right().HasResolvedValue()) {
659 scale_expression = left_left;
674 if (left_matcher.
right().HasResolvedValue()) {
679 }
else if (
m.right().HasResolvedValue()) {
697 if (
m.right().HasResolvedValue()) {
710 if (
displacement->opcode() == IrOpcode::kInt32Constant) {
721 if (power_of_two_plus_one) {
722 if (
base !=
nullptr) {
727 index = scale_expression;
733 if (!(options & AddressOption::kAllowScale) &&
scale != 0) {
734 index = scale_expression;
748 for (
auto use : node->use_edges()) {
749 Node* from = use.from();
750 switch (from->opcode()) {
751 case IrOpcode::kLoad:
752 case IrOpcode::kLoadImmutable:
753 case IrOpcode::kProtectedLoad:
754 case IrOpcode::kLoadTrapOnNull:
755 case IrOpcode::kInt32Add:
756 case IrOpcode::kInt64Add:
759 case IrOpcode::kInt32Sub:
761 if (from->InputAt(1)->opcode() != IrOpcode::kInt32Constant)
764 case IrOpcode::kInt64Sub:
766 if (from->InputAt(1)->opcode() != IrOpcode::kInt64Constant)
769 case IrOpcode::kStore:
770 case IrOpcode::kProtectedStore:
771 case IrOpcode::kStoreTrapOnNull:
773 if (from->InputAt(2) == node)
return false;
793 bool Matched()
const {
return if_true_ && if_false_; }
810 return if_true_->OwnedBy(
node()) && if_false_->OwnedBy(
node());
819 DCHECK(IrOpcode::IsPhiOpcode(phi->opcode()));
822 return phi->InputAt(if_true_ == Merge()->InputAt(0) ? 0 : 1);
826 DCHECK(IrOpcode::IsPhiOpcode(phi->opcode()));
829 return phi->InputAt(if_true_ == Merge()->InputAt(0) ? 1 : 0);
838#if V8_ENABLE_WEBASSEMBLY
839struct LoadTransformMatcher
840 :
ValueMatcher<LoadTransformParameters, IrOpcode::kLoadTransform> {
842 bool Is(LoadTransformation t) {
843 return HasResolvedValue() && ResolvedValue().transformation == t;
#define DEFINE_OPERATORS_FOR_FLAGS(Type)
interpreter::OperandScale scale
constexpr bool IsInfinite() const
V8_INLINE Address address() const
static constexpr MachineRepresentation PointerRepresentation()
static bool IsValueIdentity(Node *node, Node **out_value)
constexpr IrOpcode::Value opcode() const
const Operator * op() const
void ReplaceInput(int index, Node *new_to)
Node * InputAt(int index) const
bool OwnedBy(Node const *owner) const
DisplacementMode displacement_mode
constexpr bool IsPowerOfTwo(T value)
constexpr bool IsInRange(T value, U lower_limit, U higher_limit)
Int64Matcher IntPtrMatcher
FloatMatcher< double, IrOpcode::kFloat64Constant > Float64Matcher
IntMatcher< uint32_t, IrOpcode::kInt32Constant > Uint32Matcher
Uint64Matcher UintPtrMatcher
IntMatcher< int32_t, IrOpcode::kInt32Constant > Int32Matcher
IntMatcher< uint64_t, IrOpcode::kInt64Constant > Uint64Matcher
FloatMatcher< float, IrOpcode::kFloat32Constant > Float32Matcher
ref_traits< T >::ref_type MakeRefAssumeMemoryFence(JSHeapBroker *broker, Tagged< T > object)
IntMatcher< int64_t, IrOpcode::kInt64Constant > Int64Matcher
T const & OpParameter(const Operator *op)
Node * SkipValueIdentities(Node *node)
HeapObjectMatcherImpl< IrOpcode::kCompressedHeapConstant > CompressedHeapObjectMatcher
HeapObjectMatcherImpl< IrOpcode::kHeapConstant > HeapObjectMatcher
bool Is(IndirectHandle< U > value)
static constexpr bool is_direct_handle_v
#define DEFINE_IS_OPCODE(Opcode,...)
#define NON_EXPORTED_BASE(code)
#define DCHECK_NOT_NULL(val)
#define DCHECK(condition)
#define DCHECK_EQ(v1, v2)
#define V8_EXPORT_PRIVATE
void Initialize(Node *node, bool allow_input_swap)
bool power_of_two_plus_one() const
bool HasIndexInput() const
AddMatcher(Node *node, bool allow_input_swap)
bool power_of_two_plus_one_
Node * IndexInput() const
DisplacementMode displacement_mode_
BaseWithIndexAndDisplacementMatcher(Node *node, AddressOptions options)
Node * displacement() const
BaseWithIndexAndDisplacementMatcher(Node *node)
DisplacementMode displacement_mode() const
static bool OwnedByAddressingOperand(Node *node)
void Initialize(Node *node, AddressOptions options)
bool LeftEqualsRight() const
const Left & left() const
bool OwnsInput(Node *input)
BinopMatcher(Node *node, bool allow_input_swap)
void PutConstantOnRight()
static constexpr MachineRepresentation representation
const Right & right() const
bool IfProjectionsAreOwned() const
Node * TrueInputOf(Node *phi) const
Node * FalseInputOf(Node *phi) const
bool Is(const ExternalReference &value) const
ExternalReferenceMatcher(Node *node)
bool IsInRange(const T &low, const T &high) const
bool IsPositiveOrNegativePowerOf2() const
bool Is(const T &value) const
bool Is(IndirectHandle< HeapObject > const &value) const
HeapObjectRef Ref(JSHeapBroker *broker) const
HeapObjectMatcherImpl(Node *node)
bool IsNegativePowerOf2() const
bool Is(const T &value) const
bool IsMultipleOf(T n) const
bool IsInRange(const T &low, const T &high) const
IntPtrMatcher const index_
IntPtrMatcher const & index() const
Object const & object() const
bool Equals(const Node *node) const
bool HasProperty(Operator::Property property) const
IrOpcode::Value opcode() const
bool IsComparison() const
const Operator * op() const
Node * InputAt(int index) const
ScaleMatcher(Node *node, bool allow_power_of_two_plus_one=false)
bool power_of_two_plus_one_
bool power_of_two_plus_one() const
const T & ResolvedValue() const
bool HasResolvedValue() const