11cb0ef41Sopenharmony_ci// Copyright 2014 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#ifndef V8_COMPILER_NODE_MATCHERS_H_
61cb0ef41Sopenharmony_ci#define V8_COMPILER_NODE_MATCHERS_H_
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ci#include <cmath>
91cb0ef41Sopenharmony_ci#include <limits>
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_ci#include "src/base/bounds.h"
121cb0ef41Sopenharmony_ci#include "src/base/compiler-specific.h"
131cb0ef41Sopenharmony_ci#include "src/base/numbers/double.h"
141cb0ef41Sopenharmony_ci#include "src/codegen/external-reference.h"
151cb0ef41Sopenharmony_ci#include "src/common/globals.h"
161cb0ef41Sopenharmony_ci#include "src/compiler/common-operator.h"
171cb0ef41Sopenharmony_ci#include "src/compiler/machine-operator.h"
181cb0ef41Sopenharmony_ci#include "src/compiler/node.h"
191cb0ef41Sopenharmony_ci#include "src/compiler/opcodes.h"
201cb0ef41Sopenharmony_ci#include "src/compiler/operator.h"
211cb0ef41Sopenharmony_ci#include "src/objects/heap-object.h"
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_cinamespace v8 {
241cb0ef41Sopenharmony_cinamespace internal {
251cb0ef41Sopenharmony_cinamespace compiler {
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_ciclass JSHeapBroker;
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ci// A pattern matcher for nodes.
301cb0ef41Sopenharmony_cistruct NodeMatcher {
311cb0ef41Sopenharmony_ci  explicit NodeMatcher(Node* node) : node_(node) {}
321cb0ef41Sopenharmony_ci
331cb0ef41Sopenharmony_ci  Node* node() const { return node_; }
341cb0ef41Sopenharmony_ci  const Operator* op() const { return node()->op(); }
351cb0ef41Sopenharmony_ci  IrOpcode::Value opcode() const { return node()->opcode(); }
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ci  bool HasProperty(Operator::Property property) const {
381cb0ef41Sopenharmony_ci    return op()->HasProperty(property);
391cb0ef41Sopenharmony_ci  }
401cb0ef41Sopenharmony_ci  Node* InputAt(int index) const { return node()->InputAt(index); }
411cb0ef41Sopenharmony_ci
421cb0ef41Sopenharmony_ci  bool Equals(const Node* node) const { return node_ == node; }
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_ci  bool IsComparison() const;
451cb0ef41Sopenharmony_ci
461cb0ef41Sopenharmony_ci#define DEFINE_IS_OPCODE(Opcode, ...) \
471cb0ef41Sopenharmony_ci  bool Is##Opcode() const { return opcode() == IrOpcode::k##Opcode; }
481cb0ef41Sopenharmony_ci  ALL_OP_LIST(DEFINE_IS_OPCODE)
491cb0ef41Sopenharmony_ci#undef DEFINE_IS_OPCODE
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_ci private:
521cb0ef41Sopenharmony_ci  Node* node_;
531cb0ef41Sopenharmony_ci};
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ciinline Node* SkipValueIdentities(Node* node) {
561cb0ef41Sopenharmony_ci#ifdef DEBUG
571cb0ef41Sopenharmony_ci  bool seen_fold_constant = false;
581cb0ef41Sopenharmony_ci#endif
591cb0ef41Sopenharmony_ci  do {
601cb0ef41Sopenharmony_ci#ifdef DEBUG
611cb0ef41Sopenharmony_ci    if (node->opcode() == IrOpcode::kFoldConstant) {
621cb0ef41Sopenharmony_ci      DCHECK(!seen_fold_constant);
631cb0ef41Sopenharmony_ci      seen_fold_constant = true;
641cb0ef41Sopenharmony_ci    }
651cb0ef41Sopenharmony_ci#endif
661cb0ef41Sopenharmony_ci  } while (NodeProperties::IsValueIdentity(node, &node));
671cb0ef41Sopenharmony_ci  DCHECK_NOT_NULL(node);
681cb0ef41Sopenharmony_ci  return node;
691cb0ef41Sopenharmony_ci}
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ci// A pattern matcher for abitrary value constants.
721cb0ef41Sopenharmony_ci//
731cb0ef41Sopenharmony_ci// Note that value identities on the input node are skipped when matching. The
741cb0ef41Sopenharmony_ci// resolved value may not be a parameter of the input node. The node() method
751cb0ef41Sopenharmony_ci// returns the unmodified input node. This is by design, as reducers may wish to
761cb0ef41Sopenharmony_ci// match value constants but delay reducing the node until a later phase. For
771cb0ef41Sopenharmony_ci// example, binary operator reducers may opt to keep FoldConstant operands while
781cb0ef41Sopenharmony_ci// applying a reduction that match on the constant value of the FoldConstant.
791cb0ef41Sopenharmony_citemplate <typename T, IrOpcode::Value kOpcode>
801cb0ef41Sopenharmony_cistruct ValueMatcher : public NodeMatcher {
811cb0ef41Sopenharmony_ci  using ValueType = T;
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ci  explicit ValueMatcher(Node* node)
841cb0ef41Sopenharmony_ci      : NodeMatcher(node), resolved_value_(), has_resolved_value_(false) {
851cb0ef41Sopenharmony_ci    node = SkipValueIdentities(node);
861cb0ef41Sopenharmony_ci    has_resolved_value_ = node->opcode() == kOpcode;
871cb0ef41Sopenharmony_ci    if (has_resolved_value_) {
881cb0ef41Sopenharmony_ci      resolved_value_ = OpParameter<T>(node->op());
891cb0ef41Sopenharmony_ci    }
901cb0ef41Sopenharmony_ci  }
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_ci  bool HasResolvedValue() const { return has_resolved_value_; }
931cb0ef41Sopenharmony_ci  const T& ResolvedValue() const {
941cb0ef41Sopenharmony_ci    CHECK(HasResolvedValue());
951cb0ef41Sopenharmony_ci    return resolved_value_;
961cb0ef41Sopenharmony_ci  }
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_ci private:
991cb0ef41Sopenharmony_ci  T resolved_value_;
1001cb0ef41Sopenharmony_ci  bool has_resolved_value_;
1011cb0ef41Sopenharmony_ci};
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_citemplate <>
1041cb0ef41Sopenharmony_ciinline ValueMatcher<uint32_t, IrOpcode::kInt32Constant>::ValueMatcher(
1051cb0ef41Sopenharmony_ci    Node* node)
1061cb0ef41Sopenharmony_ci    : NodeMatcher(node), resolved_value_(), has_resolved_value_(false) {
1071cb0ef41Sopenharmony_ci  node = SkipValueIdentities(node);
1081cb0ef41Sopenharmony_ci  has_resolved_value_ = node->opcode() == IrOpcode::kInt32Constant;
1091cb0ef41Sopenharmony_ci  if (has_resolved_value_) {
1101cb0ef41Sopenharmony_ci    resolved_value_ = static_cast<uint32_t>(OpParameter<int32_t>(node->op()));
1111cb0ef41Sopenharmony_ci  }
1121cb0ef41Sopenharmony_ci}
1131cb0ef41Sopenharmony_ci
1141cb0ef41Sopenharmony_citemplate <>
1151cb0ef41Sopenharmony_ciinline ValueMatcher<int64_t, IrOpcode::kInt64Constant>::ValueMatcher(Node* node)
1161cb0ef41Sopenharmony_ci    : NodeMatcher(node), resolved_value_(), has_resolved_value_(false) {
1171cb0ef41Sopenharmony_ci  node = SkipValueIdentities(node);
1181cb0ef41Sopenharmony_ci  if (node->opcode() == IrOpcode::kInt32Constant) {
1191cb0ef41Sopenharmony_ci    resolved_value_ = OpParameter<int32_t>(node->op());
1201cb0ef41Sopenharmony_ci    has_resolved_value_ = true;
1211cb0ef41Sopenharmony_ci  } else if (node->opcode() == IrOpcode::kInt64Constant) {
1221cb0ef41Sopenharmony_ci    resolved_value_ = OpParameter<int64_t>(node->op());
1231cb0ef41Sopenharmony_ci    has_resolved_value_ = true;
1241cb0ef41Sopenharmony_ci  }
1251cb0ef41Sopenharmony_ci}
1261cb0ef41Sopenharmony_ci
1271cb0ef41Sopenharmony_citemplate <>
1281cb0ef41Sopenharmony_ciinline ValueMatcher<uint64_t, IrOpcode::kInt64Constant>::ValueMatcher(
1291cb0ef41Sopenharmony_ci    Node* node)
1301cb0ef41Sopenharmony_ci    : NodeMatcher(node), resolved_value_(), has_resolved_value_(false) {
1311cb0ef41Sopenharmony_ci  node = SkipValueIdentities(node);
1321cb0ef41Sopenharmony_ci  if (node->opcode() == IrOpcode::kInt32Constant) {
1331cb0ef41Sopenharmony_ci    resolved_value_ = static_cast<uint32_t>(OpParameter<int32_t>(node->op()));
1341cb0ef41Sopenharmony_ci    has_resolved_value_ = true;
1351cb0ef41Sopenharmony_ci  } else if (node->opcode() == IrOpcode::kInt64Constant) {
1361cb0ef41Sopenharmony_ci    resolved_value_ = static_cast<uint64_t>(OpParameter<int64_t>(node->op()));
1371cb0ef41Sopenharmony_ci    has_resolved_value_ = true;
1381cb0ef41Sopenharmony_ci  }
1391cb0ef41Sopenharmony_ci}
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci// A pattern matcher for integer constants.
1421cb0ef41Sopenharmony_citemplate <typename T, IrOpcode::Value kOpcode>
1431cb0ef41Sopenharmony_cistruct IntMatcher final : public ValueMatcher<T, kOpcode> {
1441cb0ef41Sopenharmony_ci  explicit IntMatcher(Node* node) : ValueMatcher<T, kOpcode>(node) {}
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_ci  bool Is(const T& value) const {
1471cb0ef41Sopenharmony_ci    return this->HasResolvedValue() && this->ResolvedValue() == value;
1481cb0ef41Sopenharmony_ci  }
1491cb0ef41Sopenharmony_ci  bool IsInRange(const T& low, const T& high) const {
1501cb0ef41Sopenharmony_ci    return this->HasResolvedValue() &&
1511cb0ef41Sopenharmony_ci           base::IsInRange(this->ResolvedValue(), low, high);
1521cb0ef41Sopenharmony_ci  }
1531cb0ef41Sopenharmony_ci  bool IsMultipleOf(T n) const {
1541cb0ef41Sopenharmony_ci    return this->HasResolvedValue() && (this->ResolvedValue() % n) == 0;
1551cb0ef41Sopenharmony_ci  }
1561cb0ef41Sopenharmony_ci  bool IsPowerOf2() const {
1571cb0ef41Sopenharmony_ci    return this->HasResolvedValue() && this->ResolvedValue() > 0 &&
1581cb0ef41Sopenharmony_ci           (this->ResolvedValue() & (this->ResolvedValue() - 1)) == 0;
1591cb0ef41Sopenharmony_ci  }
1601cb0ef41Sopenharmony_ci  bool IsNegativePowerOf2() const {
1611cb0ef41Sopenharmony_ci    return this->HasResolvedValue() && this->ResolvedValue() < 0 &&
1621cb0ef41Sopenharmony_ci           ((this->ResolvedValue() == std::numeric_limits<T>::min()) ||
1631cb0ef41Sopenharmony_ci            (-this->ResolvedValue() & (-this->ResolvedValue() - 1)) == 0);
1641cb0ef41Sopenharmony_ci  }
1651cb0ef41Sopenharmony_ci  bool IsNegative() const {
1661cb0ef41Sopenharmony_ci    return this->HasResolvedValue() && this->ResolvedValue() < 0;
1671cb0ef41Sopenharmony_ci  }
1681cb0ef41Sopenharmony_ci};
1691cb0ef41Sopenharmony_ci
1701cb0ef41Sopenharmony_ciusing Int32Matcher = IntMatcher<int32_t, IrOpcode::kInt32Constant>;
1711cb0ef41Sopenharmony_ciusing Uint32Matcher = IntMatcher<uint32_t, IrOpcode::kInt32Constant>;
1721cb0ef41Sopenharmony_ciusing Int64Matcher = IntMatcher<int64_t, IrOpcode::kInt64Constant>;
1731cb0ef41Sopenharmony_ciusing Uint64Matcher = IntMatcher<uint64_t, IrOpcode::kInt64Constant>;
1741cb0ef41Sopenharmony_ciusing V128ConstMatcher =
1751cb0ef41Sopenharmony_ci    ValueMatcher<S128ImmediateParameter, IrOpcode::kS128Const>;
1761cb0ef41Sopenharmony_ci#if V8_HOST_ARCH_32_BIT
1771cb0ef41Sopenharmony_ciusing IntPtrMatcher = Int32Matcher;
1781cb0ef41Sopenharmony_ciusing UintPtrMatcher = Uint32Matcher;
1791cb0ef41Sopenharmony_ci#else
1801cb0ef41Sopenharmony_ciusing IntPtrMatcher = Int64Matcher;
1811cb0ef41Sopenharmony_ciusing UintPtrMatcher = Uint64Matcher;
1821cb0ef41Sopenharmony_ci#endif
1831cb0ef41Sopenharmony_ci
1841cb0ef41Sopenharmony_ci
1851cb0ef41Sopenharmony_ci// A pattern matcher for floating point constants.
1861cb0ef41Sopenharmony_citemplate <typename T, IrOpcode::Value kOpcode>
1871cb0ef41Sopenharmony_cistruct FloatMatcher final : public ValueMatcher<T, kOpcode> {
1881cb0ef41Sopenharmony_ci  explicit FloatMatcher(Node* node) : ValueMatcher<T, kOpcode>(node) {}
1891cb0ef41Sopenharmony_ci
1901cb0ef41Sopenharmony_ci  bool Is(const T& value) const {
1911cb0ef41Sopenharmony_ci    return this->HasResolvedValue() && this->ResolvedValue() == value;
1921cb0ef41Sopenharmony_ci  }
1931cb0ef41Sopenharmony_ci  bool IsInRange(const T& low, const T& high) const {
1941cb0ef41Sopenharmony_ci    return this->HasResolvedValue() && low <= this->ResolvedValue() &&
1951cb0ef41Sopenharmony_ci           this->ResolvedValue() <= high;
1961cb0ef41Sopenharmony_ci  }
1971cb0ef41Sopenharmony_ci  bool IsMinusZero() const {
1981cb0ef41Sopenharmony_ci    return this->Is(0.0) && std::signbit(this->ResolvedValue());
1991cb0ef41Sopenharmony_ci  }
2001cb0ef41Sopenharmony_ci  bool IsNegative() const {
2011cb0ef41Sopenharmony_ci    return this->HasResolvedValue() && this->ResolvedValue() < 0.0;
2021cb0ef41Sopenharmony_ci  }
2031cb0ef41Sopenharmony_ci  bool IsNaN() const {
2041cb0ef41Sopenharmony_ci    return this->HasResolvedValue() && std::isnan(this->ResolvedValue());
2051cb0ef41Sopenharmony_ci  }
2061cb0ef41Sopenharmony_ci  bool IsZero() const {
2071cb0ef41Sopenharmony_ci    return this->Is(0.0) && !std::signbit(this->ResolvedValue());
2081cb0ef41Sopenharmony_ci  }
2091cb0ef41Sopenharmony_ci  bool IsNormal() const {
2101cb0ef41Sopenharmony_ci    return this->HasResolvedValue() && std::isnormal(this->ResolvedValue());
2111cb0ef41Sopenharmony_ci  }
2121cb0ef41Sopenharmony_ci  bool IsInteger() const {
2131cb0ef41Sopenharmony_ci    return this->HasResolvedValue() &&
2141cb0ef41Sopenharmony_ci           std::nearbyint(this->ResolvedValue()) == this->ResolvedValue();
2151cb0ef41Sopenharmony_ci  }
2161cb0ef41Sopenharmony_ci  bool IsPositiveOrNegativePowerOf2() const {
2171cb0ef41Sopenharmony_ci    if (!this->HasResolvedValue() || (this->ResolvedValue() == 0.0)) {
2181cb0ef41Sopenharmony_ci      return false;
2191cb0ef41Sopenharmony_ci    }
2201cb0ef41Sopenharmony_ci    base::Double value = base::Double(this->ResolvedValue());
2211cb0ef41Sopenharmony_ci    return !value.IsInfinite() && base::bits::IsPowerOfTwo(value.Significand());
2221cb0ef41Sopenharmony_ci  }
2231cb0ef41Sopenharmony_ci};
2241cb0ef41Sopenharmony_ci
2251cb0ef41Sopenharmony_ciusing Float32Matcher = FloatMatcher<float, IrOpcode::kFloat32Constant>;
2261cb0ef41Sopenharmony_ciusing Float64Matcher = FloatMatcher<double, IrOpcode::kFloat64Constant>;
2271cb0ef41Sopenharmony_ciusing NumberMatcher = FloatMatcher<double, IrOpcode::kNumberConstant>;
2281cb0ef41Sopenharmony_ci
2291cb0ef41Sopenharmony_ci// A pattern matcher for heap object constants.
2301cb0ef41Sopenharmony_citemplate <IrOpcode::Value kHeapConstantOpcode>
2311cb0ef41Sopenharmony_cistruct HeapObjectMatcherImpl final
2321cb0ef41Sopenharmony_ci    : public ValueMatcher<Handle<HeapObject>, kHeapConstantOpcode> {
2331cb0ef41Sopenharmony_ci  explicit HeapObjectMatcherImpl(Node* node)
2341cb0ef41Sopenharmony_ci      : ValueMatcher<Handle<HeapObject>, kHeapConstantOpcode>(node) {}
2351cb0ef41Sopenharmony_ci
2361cb0ef41Sopenharmony_ci  bool Is(Handle<HeapObject> const& value) const {
2371cb0ef41Sopenharmony_ci    return this->HasResolvedValue() &&
2381cb0ef41Sopenharmony_ci           this->ResolvedValue().address() == value.address();
2391cb0ef41Sopenharmony_ci  }
2401cb0ef41Sopenharmony_ci
2411cb0ef41Sopenharmony_ci  HeapObjectRef Ref(JSHeapBroker* broker) const {
2421cb0ef41Sopenharmony_ci    // TODO(jgruber,chromium:1209798): Using kAssumeMemoryFence works around
2431cb0ef41Sopenharmony_ci    // the fact that the graph stores handles (and not refs). The assumption is
2441cb0ef41Sopenharmony_ci    // that any handle inserted into the graph is safe to read; but we don't
2451cb0ef41Sopenharmony_ci    // preserve the reason why it is safe to read. Thus we must over-approximate
2461cb0ef41Sopenharmony_ci    // here and assume the existence of a memory fence. In the future, we should
2471cb0ef41Sopenharmony_ci    // consider having the graph store ObjectRefs or ObjectData pointer instead,
2481cb0ef41Sopenharmony_ci    // which would make new ref construction here unnecessary.
2491cb0ef41Sopenharmony_ci    return MakeRefAssumeMemoryFence(broker, this->ResolvedValue());
2501cb0ef41Sopenharmony_ci  }
2511cb0ef41Sopenharmony_ci};
2521cb0ef41Sopenharmony_ci
2531cb0ef41Sopenharmony_ciusing HeapObjectMatcher = HeapObjectMatcherImpl<IrOpcode::kHeapConstant>;
2541cb0ef41Sopenharmony_ciusing CompressedHeapObjectMatcher =
2551cb0ef41Sopenharmony_ci    HeapObjectMatcherImpl<IrOpcode::kCompressedHeapConstant>;
2561cb0ef41Sopenharmony_ci
2571cb0ef41Sopenharmony_ci// A pattern matcher for external reference constants.
2581cb0ef41Sopenharmony_cistruct ExternalReferenceMatcher final
2591cb0ef41Sopenharmony_ci    : public ValueMatcher<ExternalReference, IrOpcode::kExternalConstant> {
2601cb0ef41Sopenharmony_ci  explicit ExternalReferenceMatcher(Node* node)
2611cb0ef41Sopenharmony_ci      : ValueMatcher<ExternalReference, IrOpcode::kExternalConstant>(node) {}
2621cb0ef41Sopenharmony_ci  bool Is(const ExternalReference& value) const {
2631cb0ef41Sopenharmony_ci    return this->HasResolvedValue() && this->ResolvedValue() == value;
2641cb0ef41Sopenharmony_ci  }
2651cb0ef41Sopenharmony_ci};
2661cb0ef41Sopenharmony_ci
2671cb0ef41Sopenharmony_ci
2681cb0ef41Sopenharmony_ci// For shorter pattern matching code, this struct matches the inputs to
2691cb0ef41Sopenharmony_ci// machine-level load operations.
2701cb0ef41Sopenharmony_citemplate <typename Object>
2711cb0ef41Sopenharmony_cistruct LoadMatcher : public NodeMatcher {
2721cb0ef41Sopenharmony_ci  explicit LoadMatcher(Node* node)
2731cb0ef41Sopenharmony_ci      : NodeMatcher(node), object_(InputAt(0)), index_(InputAt(1)) {}
2741cb0ef41Sopenharmony_ci
2751cb0ef41Sopenharmony_ci  using ObjectMatcher = Object;
2761cb0ef41Sopenharmony_ci
2771cb0ef41Sopenharmony_ci  Object const& object() const { return object_; }
2781cb0ef41Sopenharmony_ci  IntPtrMatcher const& index() const { return index_; }
2791cb0ef41Sopenharmony_ci
2801cb0ef41Sopenharmony_ci private:
2811cb0ef41Sopenharmony_ci  Object const object_;
2821cb0ef41Sopenharmony_ci  IntPtrMatcher const index_;
2831cb0ef41Sopenharmony_ci};
2841cb0ef41Sopenharmony_ci
2851cb0ef41Sopenharmony_ci
2861cb0ef41Sopenharmony_ci// For shorter pattern matching code, this struct matches both the left and
2871cb0ef41Sopenharmony_ci// right hand sides of a binary operation and can put constants on the right
2881cb0ef41Sopenharmony_ci// if they appear on the left hand side of a commutative operation.
2891cb0ef41Sopenharmony_citemplate <typename Left, typename Right>
2901cb0ef41Sopenharmony_cistruct BinopMatcher : public NodeMatcher {
2911cb0ef41Sopenharmony_ci  explicit BinopMatcher(Node* node)
2921cb0ef41Sopenharmony_ci      : NodeMatcher(node), left_(InputAt(0)), right_(InputAt(1)) {
2931cb0ef41Sopenharmony_ci    if (HasProperty(Operator::kCommutative)) PutConstantOnRight();
2941cb0ef41Sopenharmony_ci  }
2951cb0ef41Sopenharmony_ci  BinopMatcher(Node* node, bool allow_input_swap)
2961cb0ef41Sopenharmony_ci      : NodeMatcher(node), left_(InputAt(0)), right_(InputAt(1)) {
2971cb0ef41Sopenharmony_ci    if (allow_input_swap) PutConstantOnRight();
2981cb0ef41Sopenharmony_ci  }
2991cb0ef41Sopenharmony_ci
3001cb0ef41Sopenharmony_ci  using LeftMatcher = Left;
3011cb0ef41Sopenharmony_ci  using RightMatcher = Right;
3021cb0ef41Sopenharmony_ci
3031cb0ef41Sopenharmony_ci  const Left& left() const { return left_; }
3041cb0ef41Sopenharmony_ci  const Right& right() const { return right_; }
3051cb0ef41Sopenharmony_ci
3061cb0ef41Sopenharmony_ci  bool IsFoldable() const {
3071cb0ef41Sopenharmony_ci    return left().HasResolvedValue() && right().HasResolvedValue();
3081cb0ef41Sopenharmony_ci  }
3091cb0ef41Sopenharmony_ci  bool LeftEqualsRight() const { return left().node() == right().node(); }
3101cb0ef41Sopenharmony_ci
3111cb0ef41Sopenharmony_ci  bool OwnsInput(Node* input) {
3121cb0ef41Sopenharmony_ci    for (Node* use : input->uses()) {
3131cb0ef41Sopenharmony_ci      if (use != node()) {
3141cb0ef41Sopenharmony_ci        return false;
3151cb0ef41Sopenharmony_ci      }
3161cb0ef41Sopenharmony_ci    }
3171cb0ef41Sopenharmony_ci    return true;
3181cb0ef41Sopenharmony_ci  }
3191cb0ef41Sopenharmony_ci
3201cb0ef41Sopenharmony_ci protected:
3211cb0ef41Sopenharmony_ci  void SwapInputs() {
3221cb0ef41Sopenharmony_ci    std::swap(left_, right_);
3231cb0ef41Sopenharmony_ci    // TODO(turbofan): This modification should notify the reducers using
3241cb0ef41Sopenharmony_ci    // BinopMatcher. Alternatively, all reducers (especially value numbering)
3251cb0ef41Sopenharmony_ci    // could ignore the ordering for commutative binops.
3261cb0ef41Sopenharmony_ci    node()->ReplaceInput(0, left().node());
3271cb0ef41Sopenharmony_ci    node()->ReplaceInput(1, right().node());
3281cb0ef41Sopenharmony_ci  }
3291cb0ef41Sopenharmony_ci
3301cb0ef41Sopenharmony_ci private:
3311cb0ef41Sopenharmony_ci  void PutConstantOnRight() {
3321cb0ef41Sopenharmony_ci    if (left().HasResolvedValue() && !right().HasResolvedValue()) {
3331cb0ef41Sopenharmony_ci      SwapInputs();
3341cb0ef41Sopenharmony_ci    }
3351cb0ef41Sopenharmony_ci  }
3361cb0ef41Sopenharmony_ci
3371cb0ef41Sopenharmony_ci  Left left_;
3381cb0ef41Sopenharmony_ci  Right right_;
3391cb0ef41Sopenharmony_ci};
3401cb0ef41Sopenharmony_ci
3411cb0ef41Sopenharmony_ciusing Int32BinopMatcher = BinopMatcher<Int32Matcher, Int32Matcher>;
3421cb0ef41Sopenharmony_ciusing Uint32BinopMatcher = BinopMatcher<Uint32Matcher, Uint32Matcher>;
3431cb0ef41Sopenharmony_ciusing Int64BinopMatcher = BinopMatcher<Int64Matcher, Int64Matcher>;
3441cb0ef41Sopenharmony_ciusing Uint64BinopMatcher = BinopMatcher<Uint64Matcher, Uint64Matcher>;
3451cb0ef41Sopenharmony_ciusing IntPtrBinopMatcher = BinopMatcher<IntPtrMatcher, IntPtrMatcher>;
3461cb0ef41Sopenharmony_ciusing UintPtrBinopMatcher = BinopMatcher<UintPtrMatcher, UintPtrMatcher>;
3471cb0ef41Sopenharmony_ciusing Float32BinopMatcher = BinopMatcher<Float32Matcher, Float32Matcher>;
3481cb0ef41Sopenharmony_ciusing Float64BinopMatcher = BinopMatcher<Float64Matcher, Float64Matcher>;
3491cb0ef41Sopenharmony_ciusing NumberBinopMatcher = BinopMatcher<NumberMatcher, NumberMatcher>;
3501cb0ef41Sopenharmony_ciusing HeapObjectBinopMatcher =
3511cb0ef41Sopenharmony_ci    BinopMatcher<HeapObjectMatcher, HeapObjectMatcher>;
3521cb0ef41Sopenharmony_ciusing CompressedHeapObjectBinopMatcher =
3531cb0ef41Sopenharmony_ci    BinopMatcher<CompressedHeapObjectMatcher, CompressedHeapObjectMatcher>;
3541cb0ef41Sopenharmony_ci
3551cb0ef41Sopenharmony_citemplate <class BinopMatcher, IrOpcode::Value kMulOpcode,
3561cb0ef41Sopenharmony_ci          IrOpcode::Value kShiftOpcode>
3571cb0ef41Sopenharmony_cistruct ScaleMatcher {
3581cb0ef41Sopenharmony_ci  explicit ScaleMatcher(Node* node, bool allow_power_of_two_plus_one = false)
3591cb0ef41Sopenharmony_ci      : scale_(-1), power_of_two_plus_one_(false) {
3601cb0ef41Sopenharmony_ci    if (node->InputCount() < 2) return;
3611cb0ef41Sopenharmony_ci    BinopMatcher m(node);
3621cb0ef41Sopenharmony_ci    if (node->opcode() == kShiftOpcode) {
3631cb0ef41Sopenharmony_ci      if (m.right().HasResolvedValue()) {
3641cb0ef41Sopenharmony_ci        typename BinopMatcher::RightMatcher::ValueType value =
3651cb0ef41Sopenharmony_ci            m.right().ResolvedValue();
3661cb0ef41Sopenharmony_ci        if (value >= 0 && value <= 3) {
3671cb0ef41Sopenharmony_ci          scale_ = static_cast<int>(value);
3681cb0ef41Sopenharmony_ci        }
3691cb0ef41Sopenharmony_ci      }
3701cb0ef41Sopenharmony_ci    } else if (node->opcode() == kMulOpcode) {
3711cb0ef41Sopenharmony_ci      if (m.right().HasResolvedValue()) {
3721cb0ef41Sopenharmony_ci        typename BinopMatcher::RightMatcher::ValueType value =
3731cb0ef41Sopenharmony_ci            m.right().ResolvedValue();
3741cb0ef41Sopenharmony_ci        if (value == 1) {
3751cb0ef41Sopenharmony_ci          scale_ = 0;
3761cb0ef41Sopenharmony_ci        } else if (value == 2) {
3771cb0ef41Sopenharmony_ci          scale_ = 1;
3781cb0ef41Sopenharmony_ci        } else if (value == 4) {
3791cb0ef41Sopenharmony_ci          scale_ = 2;
3801cb0ef41Sopenharmony_ci        } else if (value == 8) {
3811cb0ef41Sopenharmony_ci          scale_ = 3;
3821cb0ef41Sopenharmony_ci        } else if (allow_power_of_two_plus_one) {
3831cb0ef41Sopenharmony_ci          if (value == 3) {
3841cb0ef41Sopenharmony_ci            scale_ = 1;
3851cb0ef41Sopenharmony_ci            power_of_two_plus_one_ = true;
3861cb0ef41Sopenharmony_ci          } else if (value == 5) {
3871cb0ef41Sopenharmony_ci            scale_ = 2;
3881cb0ef41Sopenharmony_ci            power_of_two_plus_one_ = true;
3891cb0ef41Sopenharmony_ci          } else if (value == 9) {
3901cb0ef41Sopenharmony_ci            scale_ = 3;
3911cb0ef41Sopenharmony_ci            power_of_two_plus_one_ = true;
3921cb0ef41Sopenharmony_ci          }
3931cb0ef41Sopenharmony_ci        }
3941cb0ef41Sopenharmony_ci      }
3951cb0ef41Sopenharmony_ci    }
3961cb0ef41Sopenharmony_ci  }
3971cb0ef41Sopenharmony_ci
3981cb0ef41Sopenharmony_ci  bool matches() const { return scale_ != -1; }
3991cb0ef41Sopenharmony_ci  int scale() const { return scale_; }
4001cb0ef41Sopenharmony_ci  bool power_of_two_plus_one() const { return power_of_two_plus_one_; }
4011cb0ef41Sopenharmony_ci
4021cb0ef41Sopenharmony_ci private:
4031cb0ef41Sopenharmony_ci  int scale_;
4041cb0ef41Sopenharmony_ci  bool power_of_two_plus_one_;
4051cb0ef41Sopenharmony_ci};
4061cb0ef41Sopenharmony_ci
4071cb0ef41Sopenharmony_ciusing Int32ScaleMatcher =
4081cb0ef41Sopenharmony_ci    ScaleMatcher<Int32BinopMatcher, IrOpcode::kInt32Mul, IrOpcode::kWord32Shl>;
4091cb0ef41Sopenharmony_ciusing Int64ScaleMatcher =
4101cb0ef41Sopenharmony_ci    ScaleMatcher<Int64BinopMatcher, IrOpcode::kInt64Mul, IrOpcode::kWord64Shl>;
4111cb0ef41Sopenharmony_ci
4121cb0ef41Sopenharmony_citemplate <class BinopMatcher, IrOpcode::Value AddOpcode,
4131cb0ef41Sopenharmony_ci          IrOpcode::Value SubOpcode, IrOpcode::Value kMulOpcode,
4141cb0ef41Sopenharmony_ci          IrOpcode::Value kShiftOpcode>
4151cb0ef41Sopenharmony_cistruct AddMatcher : public BinopMatcher {
4161cb0ef41Sopenharmony_ci  static const IrOpcode::Value kAddOpcode = AddOpcode;
4171cb0ef41Sopenharmony_ci  static const IrOpcode::Value kSubOpcode = SubOpcode;
4181cb0ef41Sopenharmony_ci  using Matcher = ScaleMatcher<BinopMatcher, kMulOpcode, kShiftOpcode>;
4191cb0ef41Sopenharmony_ci
4201cb0ef41Sopenharmony_ci  AddMatcher(Node* node, bool allow_input_swap)
4211cb0ef41Sopenharmony_ci      : BinopMatcher(node, allow_input_swap),
4221cb0ef41Sopenharmony_ci        scale_(-1),
4231cb0ef41Sopenharmony_ci        power_of_two_plus_one_(false) {
4241cb0ef41Sopenharmony_ci    Initialize(node, allow_input_swap);
4251cb0ef41Sopenharmony_ci  }
4261cb0ef41Sopenharmony_ci  explicit AddMatcher(Node* node)
4271cb0ef41Sopenharmony_ci      : BinopMatcher(node, node->op()->HasProperty(Operator::kCommutative)),
4281cb0ef41Sopenharmony_ci        scale_(-1),
4291cb0ef41Sopenharmony_ci        power_of_two_plus_one_(false) {
4301cb0ef41Sopenharmony_ci    Initialize(node, node->op()->HasProperty(Operator::kCommutative));
4311cb0ef41Sopenharmony_ci  }
4321cb0ef41Sopenharmony_ci
4331cb0ef41Sopenharmony_ci  bool HasIndexInput() const { return scale_ != -1; }
4341cb0ef41Sopenharmony_ci  Node* IndexInput() const {
4351cb0ef41Sopenharmony_ci    DCHECK(HasIndexInput());
4361cb0ef41Sopenharmony_ci    return this->left().node()->InputAt(0);
4371cb0ef41Sopenharmony_ci  }
4381cb0ef41Sopenharmony_ci  int scale() const {
4391cb0ef41Sopenharmony_ci    DCHECK(HasIndexInput());
4401cb0ef41Sopenharmony_ci    return scale_;
4411cb0ef41Sopenharmony_ci  }
4421cb0ef41Sopenharmony_ci  bool power_of_two_plus_one() const { return power_of_two_plus_one_; }
4431cb0ef41Sopenharmony_ci
4441cb0ef41Sopenharmony_ci private:
4451cb0ef41Sopenharmony_ci  void Initialize(Node* node, bool allow_input_swap) {
4461cb0ef41Sopenharmony_ci    Matcher left_matcher(this->left().node(), true);
4471cb0ef41Sopenharmony_ci    if (left_matcher.matches()) {
4481cb0ef41Sopenharmony_ci      scale_ = left_matcher.scale();
4491cb0ef41Sopenharmony_ci      power_of_two_plus_one_ = left_matcher.power_of_two_plus_one();
4501cb0ef41Sopenharmony_ci      return;
4511cb0ef41Sopenharmony_ci    }
4521cb0ef41Sopenharmony_ci
4531cb0ef41Sopenharmony_ci    if (!allow_input_swap) {
4541cb0ef41Sopenharmony_ci      return;
4551cb0ef41Sopenharmony_ci    }
4561cb0ef41Sopenharmony_ci
4571cb0ef41Sopenharmony_ci    Matcher right_matcher(this->right().node(), true);
4581cb0ef41Sopenharmony_ci    if (right_matcher.matches()) {
4591cb0ef41Sopenharmony_ci      scale_ = right_matcher.scale();
4601cb0ef41Sopenharmony_ci      power_of_two_plus_one_ = right_matcher.power_of_two_plus_one();
4611cb0ef41Sopenharmony_ci      this->SwapInputs();
4621cb0ef41Sopenharmony_ci      return;
4631cb0ef41Sopenharmony_ci    }
4641cb0ef41Sopenharmony_ci
4651cb0ef41Sopenharmony_ci    if ((this->left().opcode() != kSubOpcode &&
4661cb0ef41Sopenharmony_ci         this->left().opcode() != kAddOpcode) &&
4671cb0ef41Sopenharmony_ci        (this->right().opcode() == kAddOpcode ||
4681cb0ef41Sopenharmony_ci         this->right().opcode() == kSubOpcode)) {
4691cb0ef41Sopenharmony_ci      this->SwapInputs();
4701cb0ef41Sopenharmony_ci    }
4711cb0ef41Sopenharmony_ci  }
4721cb0ef41Sopenharmony_ci
4731cb0ef41Sopenharmony_ci  int scale_;
4741cb0ef41Sopenharmony_ci  bool power_of_two_plus_one_;
4751cb0ef41Sopenharmony_ci};
4761cb0ef41Sopenharmony_ci
4771cb0ef41Sopenharmony_ciusing Int32AddMatcher =
4781cb0ef41Sopenharmony_ci    AddMatcher<Int32BinopMatcher, IrOpcode::kInt32Add, IrOpcode::kInt32Sub,
4791cb0ef41Sopenharmony_ci               IrOpcode::kInt32Mul, IrOpcode::kWord32Shl>;
4801cb0ef41Sopenharmony_ciusing Int64AddMatcher =
4811cb0ef41Sopenharmony_ci    AddMatcher<Int64BinopMatcher, IrOpcode::kInt64Add, IrOpcode::kInt64Sub,
4821cb0ef41Sopenharmony_ci               IrOpcode::kInt64Mul, IrOpcode::kWord64Shl>;
4831cb0ef41Sopenharmony_ci
4841cb0ef41Sopenharmony_cienum DisplacementMode { kPositiveDisplacement, kNegativeDisplacement };
4851cb0ef41Sopenharmony_ci
4861cb0ef41Sopenharmony_cienum class AddressOption : uint8_t {
4871cb0ef41Sopenharmony_ci  kAllowNone = 0u,
4881cb0ef41Sopenharmony_ci  kAllowInputSwap = 1u << 0,
4891cb0ef41Sopenharmony_ci  kAllowScale = 1u << 1,
4901cb0ef41Sopenharmony_ci  kAllowAll = kAllowInputSwap | kAllowScale
4911cb0ef41Sopenharmony_ci};
4921cb0ef41Sopenharmony_ci
4931cb0ef41Sopenharmony_ciusing AddressOptions = base::Flags<AddressOption, uint8_t>;
4941cb0ef41Sopenharmony_ciDEFINE_OPERATORS_FOR_FLAGS(AddressOptions)
4951cb0ef41Sopenharmony_ci
4961cb0ef41Sopenharmony_citemplate <class AddMatcher>
4971cb0ef41Sopenharmony_cistruct BaseWithIndexAndDisplacementMatcher {
4981cb0ef41Sopenharmony_ci  BaseWithIndexAndDisplacementMatcher(Node* node, AddressOptions options)
4991cb0ef41Sopenharmony_ci      : matches_(false),
5001cb0ef41Sopenharmony_ci        index_(nullptr),
5011cb0ef41Sopenharmony_ci        scale_(0),
5021cb0ef41Sopenharmony_ci        base_(nullptr),
5031cb0ef41Sopenharmony_ci        displacement_(nullptr),
5041cb0ef41Sopenharmony_ci        displacement_mode_(kPositiveDisplacement) {
5051cb0ef41Sopenharmony_ci    Initialize(node, options);
5061cb0ef41Sopenharmony_ci  }
5071cb0ef41Sopenharmony_ci
5081cb0ef41Sopenharmony_ci  explicit BaseWithIndexAndDisplacementMatcher(Node* node)
5091cb0ef41Sopenharmony_ci      : matches_(false),
5101cb0ef41Sopenharmony_ci        index_(nullptr),
5111cb0ef41Sopenharmony_ci        scale_(0),
5121cb0ef41Sopenharmony_ci        base_(nullptr),
5131cb0ef41Sopenharmony_ci        displacement_(nullptr),
5141cb0ef41Sopenharmony_ci        displacement_mode_(kPositiveDisplacement) {
5151cb0ef41Sopenharmony_ci    Initialize(node, AddressOption::kAllowScale |
5161cb0ef41Sopenharmony_ci                         (node->op()->HasProperty(Operator::kCommutative)
5171cb0ef41Sopenharmony_ci                              ? AddressOption::kAllowInputSwap
5181cb0ef41Sopenharmony_ci                              : AddressOption::kAllowNone));
5191cb0ef41Sopenharmony_ci  }
5201cb0ef41Sopenharmony_ci
5211cb0ef41Sopenharmony_ci  bool matches() const { return matches_; }
5221cb0ef41Sopenharmony_ci  Node* index() const { return index_; }
5231cb0ef41Sopenharmony_ci  int scale() const { return scale_; }
5241cb0ef41Sopenharmony_ci  Node* base() const { return base_; }
5251cb0ef41Sopenharmony_ci  Node* displacement() const { return displacement_; }
5261cb0ef41Sopenharmony_ci  DisplacementMode displacement_mode() const { return displacement_mode_; }
5271cb0ef41Sopenharmony_ci
5281cb0ef41Sopenharmony_ci private:
5291cb0ef41Sopenharmony_ci  bool matches_;
5301cb0ef41Sopenharmony_ci  Node* index_;
5311cb0ef41Sopenharmony_ci  int scale_;
5321cb0ef41Sopenharmony_ci  Node* base_;
5331cb0ef41Sopenharmony_ci  Node* displacement_;
5341cb0ef41Sopenharmony_ci  DisplacementMode displacement_mode_;
5351cb0ef41Sopenharmony_ci
5361cb0ef41Sopenharmony_ci  void Initialize(Node* node, AddressOptions options) {
5371cb0ef41Sopenharmony_ci    // The BaseWithIndexAndDisplacementMatcher canonicalizes the order of
5381cb0ef41Sopenharmony_ci    // displacements and scale factors that are used as inputs, so instead of
5391cb0ef41Sopenharmony_ci    // enumerating all possible patterns by brute force, checking for node
5401cb0ef41Sopenharmony_ci    // clusters using the following templates in the following order suffices to
5411cb0ef41Sopenharmony_ci    // find all of the interesting cases (S = index * scale, B = base input, D =
5421cb0ef41Sopenharmony_ci    // displacement input):
5431cb0ef41Sopenharmony_ci    // (S + (B + D))
5441cb0ef41Sopenharmony_ci    // (S + (B + B))
5451cb0ef41Sopenharmony_ci    // (S + D)
5461cb0ef41Sopenharmony_ci    // (S + B)
5471cb0ef41Sopenharmony_ci    // ((S + D) + B)
5481cb0ef41Sopenharmony_ci    // ((S + B) + D)
5491cb0ef41Sopenharmony_ci    // ((B + D) + B)
5501cb0ef41Sopenharmony_ci    // ((B + B) + D)
5511cb0ef41Sopenharmony_ci    // (B + D)
5521cb0ef41Sopenharmony_ci    // (B + B)
5531cb0ef41Sopenharmony_ci    if (node->InputCount() < 2) return;
5541cb0ef41Sopenharmony_ci    AddMatcher m(node, options & AddressOption::kAllowInputSwap);
5551cb0ef41Sopenharmony_ci    Node* left = m.left().node();
5561cb0ef41Sopenharmony_ci    Node* right = m.right().node();
5571cb0ef41Sopenharmony_ci    Node* displacement = nullptr;
5581cb0ef41Sopenharmony_ci    Node* base = nullptr;
5591cb0ef41Sopenharmony_ci    Node* index = nullptr;
5601cb0ef41Sopenharmony_ci    Node* scale_expression = nullptr;
5611cb0ef41Sopenharmony_ci    bool power_of_two_plus_one = false;
5621cb0ef41Sopenharmony_ci    DisplacementMode displacement_mode = kPositiveDisplacement;
5631cb0ef41Sopenharmony_ci    int scale = 0;
5641cb0ef41Sopenharmony_ci    if (m.HasIndexInput() && OwnedByAddressingOperand(left)) {
5651cb0ef41Sopenharmony_ci      index = m.IndexInput();
5661cb0ef41Sopenharmony_ci      scale = m.scale();
5671cb0ef41Sopenharmony_ci      scale_expression = left;
5681cb0ef41Sopenharmony_ci      power_of_two_plus_one = m.power_of_two_plus_one();
5691cb0ef41Sopenharmony_ci      bool match_found = false;
5701cb0ef41Sopenharmony_ci      if (right->opcode() == AddMatcher::kSubOpcode &&
5711cb0ef41Sopenharmony_ci          OwnedByAddressingOperand(right)) {
5721cb0ef41Sopenharmony_ci        AddMatcher right_matcher(right);
5731cb0ef41Sopenharmony_ci        if (right_matcher.right().HasResolvedValue()) {
5741cb0ef41Sopenharmony_ci          // (S + (B - D))
5751cb0ef41Sopenharmony_ci          base = right_matcher.left().node();
5761cb0ef41Sopenharmony_ci          displacement = right_matcher.right().node();
5771cb0ef41Sopenharmony_ci          displacement_mode = kNegativeDisplacement;
5781cb0ef41Sopenharmony_ci          match_found = true;
5791cb0ef41Sopenharmony_ci        }
5801cb0ef41Sopenharmony_ci      }
5811cb0ef41Sopenharmony_ci      if (!match_found) {
5821cb0ef41Sopenharmony_ci        if (right->opcode() == AddMatcher::kAddOpcode &&
5831cb0ef41Sopenharmony_ci            OwnedByAddressingOperand(right)) {
5841cb0ef41Sopenharmony_ci          AddMatcher right_matcher(right);
5851cb0ef41Sopenharmony_ci          if (right_matcher.right().HasResolvedValue()) {
5861cb0ef41Sopenharmony_ci            // (S + (B + D))
5871cb0ef41Sopenharmony_ci            base = right_matcher.left().node();
5881cb0ef41Sopenharmony_ci            displacement = right_matcher.right().node();
5891cb0ef41Sopenharmony_ci          } else {
5901cb0ef41Sopenharmony_ci            // (S + (B + B))
5911cb0ef41Sopenharmony_ci            base = right;
5921cb0ef41Sopenharmony_ci          }
5931cb0ef41Sopenharmony_ci        } else if (m.right().HasResolvedValue()) {
5941cb0ef41Sopenharmony_ci          // (S + D)
5951cb0ef41Sopenharmony_ci          displacement = right;
5961cb0ef41Sopenharmony_ci        } else {
5971cb0ef41Sopenharmony_ci          // (S + B)
5981cb0ef41Sopenharmony_ci          base = right;
5991cb0ef41Sopenharmony_ci        }
6001cb0ef41Sopenharmony_ci      }
6011cb0ef41Sopenharmony_ci    } else {
6021cb0ef41Sopenharmony_ci      bool match_found = false;
6031cb0ef41Sopenharmony_ci      if (left->opcode() == AddMatcher::kSubOpcode &&
6041cb0ef41Sopenharmony_ci          OwnedByAddressingOperand(left)) {
6051cb0ef41Sopenharmony_ci        AddMatcher left_matcher(left);
6061cb0ef41Sopenharmony_ci        Node* left_left = left_matcher.left().node();
6071cb0ef41Sopenharmony_ci        Node* left_right = left_matcher.right().node();
6081cb0ef41Sopenharmony_ci        if (left_matcher.right().HasResolvedValue()) {
6091cb0ef41Sopenharmony_ci          if (left_matcher.HasIndexInput() &&
6101cb0ef41Sopenharmony_ci              OwnedByAddressingOperand(left_left)) {
6111cb0ef41Sopenharmony_ci            // ((S - D) + B)
6121cb0ef41Sopenharmony_ci            index = left_matcher.IndexInput();
6131cb0ef41Sopenharmony_ci            scale = left_matcher.scale();
6141cb0ef41Sopenharmony_ci            scale_expression = left_left;
6151cb0ef41Sopenharmony_ci            power_of_two_plus_one = left_matcher.power_of_two_plus_one();
6161cb0ef41Sopenharmony_ci            displacement = left_right;
6171cb0ef41Sopenharmony_ci            displacement_mode = kNegativeDisplacement;
6181cb0ef41Sopenharmony_ci            base = right;
6191cb0ef41Sopenharmony_ci          } else {
6201cb0ef41Sopenharmony_ci            // ((B - D) + B)
6211cb0ef41Sopenharmony_ci            index = left_left;
6221cb0ef41Sopenharmony_ci            displacement = left_right;
6231cb0ef41Sopenharmony_ci            displacement_mode = kNegativeDisplacement;
6241cb0ef41Sopenharmony_ci            base = right;
6251cb0ef41Sopenharmony_ci          }
6261cb0ef41Sopenharmony_ci          match_found = true;
6271cb0ef41Sopenharmony_ci        }
6281cb0ef41Sopenharmony_ci      }
6291cb0ef41Sopenharmony_ci      if (!match_found) {
6301cb0ef41Sopenharmony_ci        if (left->opcode() == AddMatcher::kAddOpcode &&
6311cb0ef41Sopenharmony_ci            OwnedByAddressingOperand(left)) {
6321cb0ef41Sopenharmony_ci          AddMatcher left_matcher(left);
6331cb0ef41Sopenharmony_ci          Node* left_left = left_matcher.left().node();
6341cb0ef41Sopenharmony_ci          Node* left_right = left_matcher.right().node();
6351cb0ef41Sopenharmony_ci          if (left_matcher.HasIndexInput() &&
6361cb0ef41Sopenharmony_ci              OwnedByAddressingOperand(left_left)) {
6371cb0ef41Sopenharmony_ci            if (left_matcher.right().HasResolvedValue()) {
6381cb0ef41Sopenharmony_ci              // ((S + D) + B)
6391cb0ef41Sopenharmony_ci              index = left_matcher.IndexInput();
6401cb0ef41Sopenharmony_ci              scale = left_matcher.scale();
6411cb0ef41Sopenharmony_ci              scale_expression = left_left;
6421cb0ef41Sopenharmony_ci              power_of_two_plus_one = left_matcher.power_of_two_plus_one();
6431cb0ef41Sopenharmony_ci              displacement = left_right;
6441cb0ef41Sopenharmony_ci              base = right;
6451cb0ef41Sopenharmony_ci            } else if (m.right().HasResolvedValue()) {
6461cb0ef41Sopenharmony_ci              if (left->OwnedBy(node)) {
6471cb0ef41Sopenharmony_ci                // ((S + B) + D)
6481cb0ef41Sopenharmony_ci                index = left_matcher.IndexInput();
6491cb0ef41Sopenharmony_ci                scale = left_matcher.scale();
6501cb0ef41Sopenharmony_ci                scale_expression = left_left;
6511cb0ef41Sopenharmony_ci                power_of_two_plus_one = left_matcher.power_of_two_plus_one();
6521cb0ef41Sopenharmony_ci                base = left_right;
6531cb0ef41Sopenharmony_ci                displacement = right;
6541cb0ef41Sopenharmony_ci              } else {
6551cb0ef41Sopenharmony_ci                // (B + D)
6561cb0ef41Sopenharmony_ci                base = left;
6571cb0ef41Sopenharmony_ci                displacement = right;
6581cb0ef41Sopenharmony_ci              }
6591cb0ef41Sopenharmony_ci            } else {
6601cb0ef41Sopenharmony_ci              // (B + B)
6611cb0ef41Sopenharmony_ci              index = left;
6621cb0ef41Sopenharmony_ci              base = right;
6631cb0ef41Sopenharmony_ci            }
6641cb0ef41Sopenharmony_ci          } else {
6651cb0ef41Sopenharmony_ci            if (left_matcher.right().HasResolvedValue()) {
6661cb0ef41Sopenharmony_ci              // ((B + D) + B)
6671cb0ef41Sopenharmony_ci              index = left_left;
6681cb0ef41Sopenharmony_ci              displacement = left_right;
6691cb0ef41Sopenharmony_ci              base = right;
6701cb0ef41Sopenharmony_ci            } else if (m.right().HasResolvedValue()) {
6711cb0ef41Sopenharmony_ci              if (left->OwnedBy(node)) {
6721cb0ef41Sopenharmony_ci                // ((B + B) + D)
6731cb0ef41Sopenharmony_ci                index = left_left;
6741cb0ef41Sopenharmony_ci                base = left_right;
6751cb0ef41Sopenharmony_ci                displacement = right;
6761cb0ef41Sopenharmony_ci              } else {
6771cb0ef41Sopenharmony_ci                // (B + D)
6781cb0ef41Sopenharmony_ci                base = left;
6791cb0ef41Sopenharmony_ci                displacement = right;
6801cb0ef41Sopenharmony_ci              }
6811cb0ef41Sopenharmony_ci            } else {
6821cb0ef41Sopenharmony_ci              // (B + B)
6831cb0ef41Sopenharmony_ci              index = left;
6841cb0ef41Sopenharmony_ci              base = right;
6851cb0ef41Sopenharmony_ci            }
6861cb0ef41Sopenharmony_ci          }
6871cb0ef41Sopenharmony_ci        } else {
6881cb0ef41Sopenharmony_ci          if (m.right().HasResolvedValue()) {
6891cb0ef41Sopenharmony_ci            // (B + D)
6901cb0ef41Sopenharmony_ci            base = left;
6911cb0ef41Sopenharmony_ci            displacement = right;
6921cb0ef41Sopenharmony_ci          } else {
6931cb0ef41Sopenharmony_ci            // (B + B)
6941cb0ef41Sopenharmony_ci            base = left;
6951cb0ef41Sopenharmony_ci            index = right;
6961cb0ef41Sopenharmony_ci          }
6971cb0ef41Sopenharmony_ci        }
6981cb0ef41Sopenharmony_ci      }
6991cb0ef41Sopenharmony_ci    }
7001cb0ef41Sopenharmony_ci    int64_t value = 0;
7011cb0ef41Sopenharmony_ci    if (displacement != nullptr) {
7021cb0ef41Sopenharmony_ci      switch (displacement->opcode()) {
7031cb0ef41Sopenharmony_ci        case IrOpcode::kInt32Constant: {
7041cb0ef41Sopenharmony_ci          value = OpParameter<int32_t>(displacement->op());
7051cb0ef41Sopenharmony_ci          break;
7061cb0ef41Sopenharmony_ci        }
7071cb0ef41Sopenharmony_ci        case IrOpcode::kInt64Constant: {
7081cb0ef41Sopenharmony_ci          value = OpParameter<int64_t>(displacement->op());
7091cb0ef41Sopenharmony_ci          break;
7101cb0ef41Sopenharmony_ci        }
7111cb0ef41Sopenharmony_ci        default:
7121cb0ef41Sopenharmony_ci          UNREACHABLE();
7131cb0ef41Sopenharmony_ci          break;
7141cb0ef41Sopenharmony_ci      }
7151cb0ef41Sopenharmony_ci      if (value == 0) {
7161cb0ef41Sopenharmony_ci        displacement = nullptr;
7171cb0ef41Sopenharmony_ci      }
7181cb0ef41Sopenharmony_ci    }
7191cb0ef41Sopenharmony_ci    if (power_of_two_plus_one) {
7201cb0ef41Sopenharmony_ci      if (base != nullptr) {
7211cb0ef41Sopenharmony_ci        // If the scale requires explicitly using the index as the base, but a
7221cb0ef41Sopenharmony_ci        // base is already part of the match, then the (1 << N + 1) scale factor
7231cb0ef41Sopenharmony_ci        // can't be folded into the match and the entire index * scale
7241cb0ef41Sopenharmony_ci        // calculation must be computed separately.
7251cb0ef41Sopenharmony_ci        index = scale_expression;
7261cb0ef41Sopenharmony_ci        scale = 0;
7271cb0ef41Sopenharmony_ci      } else {
7281cb0ef41Sopenharmony_ci        base = index;
7291cb0ef41Sopenharmony_ci      }
7301cb0ef41Sopenharmony_ci    }
7311cb0ef41Sopenharmony_ci    if (!(options & AddressOption::kAllowScale) && scale != 0) {
7321cb0ef41Sopenharmony_ci      index = scale_expression;
7331cb0ef41Sopenharmony_ci      scale = 0;
7341cb0ef41Sopenharmony_ci    }
7351cb0ef41Sopenharmony_ci    base_ = base;
7361cb0ef41Sopenharmony_ci    displacement_ = displacement;
7371cb0ef41Sopenharmony_ci    displacement_mode_ = displacement_mode;
7381cb0ef41Sopenharmony_ci    index_ = index;
7391cb0ef41Sopenharmony_ci    scale_ = scale;
7401cb0ef41Sopenharmony_ci    matches_ = true;
7411cb0ef41Sopenharmony_ci  }
7421cb0ef41Sopenharmony_ci
7431cb0ef41Sopenharmony_ci  // Warning: When {node} is used by a Add/Sub instruction, this function does
7441cb0ef41Sopenharmony_ci  // not guarantee the Add/Sub will be part of a addressing operand.
7451cb0ef41Sopenharmony_ci  static bool OwnedByAddressingOperand(Node* node) {
7461cb0ef41Sopenharmony_ci    for (auto use : node->use_edges()) {
7471cb0ef41Sopenharmony_ci      Node* from = use.from();
7481cb0ef41Sopenharmony_ci      switch (from->opcode()) {
7491cb0ef41Sopenharmony_ci        case IrOpcode::kLoad:
7501cb0ef41Sopenharmony_ci        case IrOpcode::kLoadImmutable:
7511cb0ef41Sopenharmony_ci        case IrOpcode::kProtectedLoad:
7521cb0ef41Sopenharmony_ci        case IrOpcode::kInt32Add:
7531cb0ef41Sopenharmony_ci        case IrOpcode::kInt64Add:
7541cb0ef41Sopenharmony_ci          // Skip addressing uses.
7551cb0ef41Sopenharmony_ci          break;
7561cb0ef41Sopenharmony_ci        case IrOpcode::kInt32Sub:
7571cb0ef41Sopenharmony_ci          // If the subtrahend is not a constant, it is not an addressing use.
7581cb0ef41Sopenharmony_ci          if (from->InputAt(1)->opcode() != IrOpcode::kInt32Constant)
7591cb0ef41Sopenharmony_ci            return false;
7601cb0ef41Sopenharmony_ci          break;
7611cb0ef41Sopenharmony_ci        case IrOpcode::kInt64Sub:
7621cb0ef41Sopenharmony_ci          // If the subtrahend is not a constant, it is not an addressing use.
7631cb0ef41Sopenharmony_ci          if (from->InputAt(1)->opcode() != IrOpcode::kInt64Constant)
7641cb0ef41Sopenharmony_ci            return false;
7651cb0ef41Sopenharmony_ci          break;
7661cb0ef41Sopenharmony_ci        case IrOpcode::kStore:
7671cb0ef41Sopenharmony_ci        case IrOpcode::kProtectedStore:
7681cb0ef41Sopenharmony_ci          // If the stored value is this node, it is not an addressing use.
7691cb0ef41Sopenharmony_ci          if (from->InputAt(2) == node) return false;
7701cb0ef41Sopenharmony_ci          // Otherwise it is used as an address and skipped.
7711cb0ef41Sopenharmony_ci          break;
7721cb0ef41Sopenharmony_ci        default:
7731cb0ef41Sopenharmony_ci          // Non-addressing use found.
7741cb0ef41Sopenharmony_ci          return false;
7751cb0ef41Sopenharmony_ci      }
7761cb0ef41Sopenharmony_ci    }
7771cb0ef41Sopenharmony_ci    return true;
7781cb0ef41Sopenharmony_ci  }
7791cb0ef41Sopenharmony_ci};
7801cb0ef41Sopenharmony_ci
7811cb0ef41Sopenharmony_ciusing BaseWithIndexAndDisplacement32Matcher =
7821cb0ef41Sopenharmony_ci    BaseWithIndexAndDisplacementMatcher<Int32AddMatcher>;
7831cb0ef41Sopenharmony_ciusing BaseWithIndexAndDisplacement64Matcher =
7841cb0ef41Sopenharmony_ci    BaseWithIndexAndDisplacementMatcher<Int64AddMatcher>;
7851cb0ef41Sopenharmony_ci
7861cb0ef41Sopenharmony_cistruct V8_EXPORT_PRIVATE BranchMatcher : public NON_EXPORTED_BASE(NodeMatcher) {
7871cb0ef41Sopenharmony_ci  explicit BranchMatcher(Node* branch);
7881cb0ef41Sopenharmony_ci
7891cb0ef41Sopenharmony_ci  bool Matched() const { return if_true_ && if_false_; }
7901cb0ef41Sopenharmony_ci
7911cb0ef41Sopenharmony_ci  Node* Branch() const { return node(); }
7921cb0ef41Sopenharmony_ci  Node* IfTrue() const { return if_true_; }
7931cb0ef41Sopenharmony_ci  Node* IfFalse() const { return if_false_; }
7941cb0ef41Sopenharmony_ci
7951cb0ef41Sopenharmony_ci private:
7961cb0ef41Sopenharmony_ci  Node* if_true_;
7971cb0ef41Sopenharmony_ci  Node* if_false_;
7981cb0ef41Sopenharmony_ci};
7991cb0ef41Sopenharmony_ci
8001cb0ef41Sopenharmony_cistruct V8_EXPORT_PRIVATE DiamondMatcher
8011cb0ef41Sopenharmony_ci    : public NON_EXPORTED_BASE(NodeMatcher) {
8021cb0ef41Sopenharmony_ci  explicit DiamondMatcher(Node* merge);
8031cb0ef41Sopenharmony_ci
8041cb0ef41Sopenharmony_ci  bool Matched() const { return branch_; }
8051cb0ef41Sopenharmony_ci  bool IfProjectionsAreOwned() const {
8061cb0ef41Sopenharmony_ci    return if_true_->OwnedBy(node()) && if_false_->OwnedBy(node());
8071cb0ef41Sopenharmony_ci  }
8081cb0ef41Sopenharmony_ci
8091cb0ef41Sopenharmony_ci  Node* Branch() const { return branch_; }
8101cb0ef41Sopenharmony_ci  Node* IfTrue() const { return if_true_; }
8111cb0ef41Sopenharmony_ci  Node* IfFalse() const { return if_false_; }
8121cb0ef41Sopenharmony_ci  Node* Merge() const { return node(); }
8131cb0ef41Sopenharmony_ci
8141cb0ef41Sopenharmony_ci  Node* TrueInputOf(Node* phi) const {
8151cb0ef41Sopenharmony_ci    DCHECK(IrOpcode::IsPhiOpcode(phi->opcode()));
8161cb0ef41Sopenharmony_ci    DCHECK_EQ(3, phi->InputCount());
8171cb0ef41Sopenharmony_ci    DCHECK_EQ(Merge(), phi->InputAt(2));
8181cb0ef41Sopenharmony_ci    return phi->InputAt(if_true_ == Merge()->InputAt(0) ? 0 : 1);
8191cb0ef41Sopenharmony_ci  }
8201cb0ef41Sopenharmony_ci
8211cb0ef41Sopenharmony_ci  Node* FalseInputOf(Node* phi) const {
8221cb0ef41Sopenharmony_ci    DCHECK(IrOpcode::IsPhiOpcode(phi->opcode()));
8231cb0ef41Sopenharmony_ci    DCHECK_EQ(3, phi->InputCount());
8241cb0ef41Sopenharmony_ci    DCHECK_EQ(Merge(), phi->InputAt(2));
8251cb0ef41Sopenharmony_ci    return phi->InputAt(if_true_ == Merge()->InputAt(0) ? 1 : 0);
8261cb0ef41Sopenharmony_ci  }
8271cb0ef41Sopenharmony_ci
8281cb0ef41Sopenharmony_ci private:
8291cb0ef41Sopenharmony_ci  Node* branch_;
8301cb0ef41Sopenharmony_ci  Node* if_true_;
8311cb0ef41Sopenharmony_ci  Node* if_false_;
8321cb0ef41Sopenharmony_ci};
8331cb0ef41Sopenharmony_ci
8341cb0ef41Sopenharmony_cistruct LoadTransformMatcher
8351cb0ef41Sopenharmony_ci    : ValueMatcher<LoadTransformParameters, IrOpcode::kLoadTransform> {
8361cb0ef41Sopenharmony_ci  explicit LoadTransformMatcher(Node* node) : ValueMatcher(node) {}
8371cb0ef41Sopenharmony_ci  bool Is(LoadTransformation t) {
8381cb0ef41Sopenharmony_ci    return HasResolvedValue() && ResolvedValue().transformation == t;
8391cb0ef41Sopenharmony_ci  }
8401cb0ef41Sopenharmony_ci};
8411cb0ef41Sopenharmony_ci
8421cb0ef41Sopenharmony_ci}  // namespace compiler
8431cb0ef41Sopenharmony_ci}  // namespace internal
8441cb0ef41Sopenharmony_ci}  // namespace v8
8451cb0ef41Sopenharmony_ci
8461cb0ef41Sopenharmony_ci#endif  // V8_COMPILER_NODE_MATCHERS_H_
847