Line data Source code
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 : // TODO(turbofan): Move ExternalReference out of assembler.h
11 : #include "src/assembler.h"
12 : #include "src/base/compiler-specific.h"
13 : #include "src/compiler/node.h"
14 : #include "src/compiler/operator.h"
15 : #include "src/double.h"
16 : #include "src/globals.h"
17 :
18 : namespace v8 {
19 : namespace internal {
20 : namespace compiler {
21 :
22 : // A pattern matcher for nodes.
23 : struct NodeMatcher {
24 95272131 : explicit NodeMatcher(Node* node) : node_(node) {}
25 :
26 43922128 : Node* node() const { return node_; }
27 19834185 : const Operator* op() const { return node()->op(); }
28 88939130 : IrOpcode::Value opcode() const { return node()->opcode(); }
29 :
30 : bool HasProperty(Operator::Property property) const {
31 : return op()->HasProperty(property);
32 : }
33 : Node* InputAt(int index) const { return node()->InputAt(index); }
34 :
35 20679 : bool Equals(const Node* node) const { return node_ == node; }
36 :
37 : bool IsComparison() const;
38 :
39 : #define DEFINE_IS_OPCODE(Opcode) \
40 : bool Is##Opcode() const { return opcode() == IrOpcode::k##Opcode; }
41 : ALL_OP_LIST(DEFINE_IS_OPCODE)
42 : #undef DEFINE_IS_OPCODE
43 :
44 : private:
45 : Node* node_;
46 : };
47 :
48 :
49 : // A pattern matcher for abitrary value constants.
50 : template <typename T, IrOpcode::Value kOpcode>
51 : struct ValueMatcher : public NodeMatcher {
52 : typedef T ValueType;
53 :
54 : explicit ValueMatcher(Node* node)
55 38310642 : : NodeMatcher(node), value_(), has_value_(opcode() == kOpcode) {
56 27139102 : if (has_value_) {
57 10084148 : value_ = OpParameter<T>(node);
58 : }
59 : }
60 :
61 : bool HasValue() const { return has_value_; }
62 : const T& Value() const {
63 : DCHECK(HasValue());
64 : return value_;
65 : }
66 :
67 : private:
68 : T value_;
69 : bool has_value_;
70 : };
71 :
72 :
73 : template <>
74 : inline ValueMatcher<uint32_t, IrOpcode::kInt32Constant>::ValueMatcher(
75 : Node* node)
76 : : NodeMatcher(node),
77 : value_(),
78 1819148 : has_value_(opcode() == IrOpcode::kInt32Constant) {
79 1028692 : if (has_value_) {
80 521675 : value_ = static_cast<uint32_t>(OpParameter<int32_t>(node));
81 : }
82 : }
83 :
84 :
85 : template <>
86 : inline ValueMatcher<int64_t, IrOpcode::kInt64Constant>::ValueMatcher(Node* node)
87 41993264 : : NodeMatcher(node), value_(), has_value_(false) {
88 44518985 : if (opcode() == IrOpcode::kInt32Constant) {
89 635558 : value_ = OpParameter<int32_t>(node);
90 561069 : has_value_ = true;
91 43883427 : } else if (opcode() == IrOpcode::kInt64Constant) {
92 18511029 : value_ = OpParameter<int64_t>(node);
93 17546258 : has_value_ = true;
94 : }
95 : }
96 :
97 :
98 : template <>
99 : inline ValueMatcher<uint64_t, IrOpcode::kInt64Constant>::ValueMatcher(
100 : Node* node)
101 63120 : : NodeMatcher(node), value_(), has_value_(false) {
102 89330 : if (opcode() == IrOpcode::kInt32Constant) {
103 58 : value_ = static_cast<uint32_t>(OpParameter<int32_t>(node));
104 6 : has_value_ = true;
105 89272 : } else if (opcode() == IrOpcode::kInt64Constant) {
106 62638 : value_ = static_cast<uint64_t>(OpParameter<int64_t>(node));
107 62638 : has_value_ = true;
108 : }
109 : }
110 :
111 :
112 : // A pattern matcher for integer constants.
113 : template <typename T, IrOpcode::Value kOpcode>
114 : struct IntMatcher final : public ValueMatcher<T, kOpcode> {
115 : explicit IntMatcher(Node* node) : ValueMatcher<T, kOpcode>(node) {}
116 :
117 : bool Is(const T& value) const {
118 8378287 : return this->HasValue() && this->Value() == value;
119 : }
120 : bool IsInRange(const T& low, const T& high) const {
121 342210 : return this->HasValue() && low <= this->Value() && this->Value() <= high;
122 : }
123 : bool IsMultipleOf(T n) const {
124 17674 : return this->HasValue() && (this->Value() % n) == 0;
125 : }
126 : bool IsPowerOf2() const {
127 : return this->HasValue() && this->Value() > 0 &&
128 11282 : (this->Value() & (this->Value() - 1)) == 0;
129 : }
130 : bool IsNegativePowerOf2() const {
131 465228 : return this->HasValue() && this->Value() < 0 &&
132 465228 : (-this->Value() & (-this->Value() - 1)) == 0;
133 : }
134 2438 : bool IsNegative() const { return this->HasValue() && this->Value() < 0; }
135 : };
136 :
137 : typedef IntMatcher<int32_t, IrOpcode::kInt32Constant> Int32Matcher;
138 : typedef IntMatcher<uint32_t, IrOpcode::kInt32Constant> Uint32Matcher;
139 : typedef IntMatcher<int64_t, IrOpcode::kInt64Constant> Int64Matcher;
140 : typedef IntMatcher<uint64_t, IrOpcode::kInt64Constant> Uint64Matcher;
141 : #if V8_HOST_ARCH_32_BIT
142 : typedef Int32Matcher IntPtrMatcher;
143 : typedef Uint32Matcher UintPtrMatcher;
144 : #else
145 : typedef Int64Matcher IntPtrMatcher;
146 : typedef Uint64Matcher UintPtrMatcher;
147 : #endif
148 :
149 :
150 : // A pattern matcher for floating point constants.
151 : template <typename T, IrOpcode::Value kOpcode>
152 : struct FloatMatcher final : public ValueMatcher<T, kOpcode> {
153 : explicit FloatMatcher(Node* node) : ValueMatcher<T, kOpcode>(node) {}
154 :
155 : bool Is(const T& value) const {
156 449326 : return this->HasValue() && this->Value() == value;
157 : }
158 : bool IsInRange(const T& low, const T& high) const {
159 2279 : return this->HasValue() && low <= this->Value() && this->Value() <= high;
160 : }
161 45424 : bool IsMinusZero() const {
162 54011 : return this->Is(0.0) && std::signbit(this->Value());
163 : }
164 : bool IsNegative() const { return this->HasValue() && this->Value() < 0.0; }
165 522461 : bool IsNaN() const { return this->HasValue() && std::isnan(this->Value()); }
166 12 : bool IsZero() const { return this->Is(0.0) && !std::signbit(this->Value()); }
167 : bool IsNormal() const {
168 36707 : return this->HasValue() && std::isnormal(this->Value());
169 : }
170 : bool IsInteger() const {
171 7852 : return this->HasValue() && std::nearbyint(this->Value()) == this->Value();
172 : }
173 10104 : bool IsPositiveOrNegativePowerOf2() const {
174 10104 : if (!this->HasValue() || (this->Value() == 0.0)) {
175 : return false;
176 : }
177 10104 : Double value = Double(this->Value());
178 20208 : return !value.IsInfinite() && base::bits::IsPowerOfTwo(value.Significand());
179 : }
180 : };
181 :
182 : typedef FloatMatcher<float, IrOpcode::kFloat32Constant> Float32Matcher;
183 : typedef FloatMatcher<double, IrOpcode::kFloat64Constant> Float64Matcher;
184 : typedef FloatMatcher<double, IrOpcode::kNumberConstant> NumberMatcher;
185 :
186 :
187 : // A pattern matcher for heap object constants.
188 : struct HeapObjectMatcher final
189 : : public ValueMatcher<Handle<HeapObject>, IrOpcode::kHeapConstant> {
190 : explicit HeapObjectMatcher(Node* node)
191 : : ValueMatcher<Handle<HeapObject>, IrOpcode::kHeapConstant>(node) {}
192 :
193 188890 : bool Is(Handle<HeapObject> const& value) const {
194 247870 : return this->HasValue() && this->Value().address() == value.address();
195 : }
196 : };
197 :
198 :
199 : // A pattern matcher for external reference constants.
200 : struct ExternalReferenceMatcher final
201 : : public ValueMatcher<ExternalReference, IrOpcode::kExternalConstant> {
202 : explicit ExternalReferenceMatcher(Node* node)
203 : : ValueMatcher<ExternalReference, IrOpcode::kExternalConstant>(node) {}
204 : bool Is(const ExternalReference& value) const {
205 666286 : return this->HasValue() && this->Value() == value;
206 : }
207 : };
208 :
209 :
210 : // For shorter pattern matching code, this struct matches the inputs to
211 : // machine-level load operations.
212 : template <typename Object>
213 : struct LoadMatcher : public NodeMatcher {
214 4213408 : explicit LoadMatcher(Node* node)
215 4213408 : : NodeMatcher(node), object_(InputAt(0)), index_(InputAt(1)) {}
216 :
217 : typedef Object ObjectMatcher;
218 :
219 : Object const& object() const { return object_; }
220 : IntPtrMatcher const& index() const { return index_; }
221 :
222 : private:
223 : Object const object_;
224 : IntPtrMatcher const index_;
225 : };
226 :
227 :
228 : // For shorter pattern matching code, this struct matches both the left and
229 : // right hand sides of a binary operation and can put constants on the right
230 : // if they appear on the left hand side of a commutative operation.
231 : template <typename Left, typename Right>
232 : struct BinopMatcher : public NodeMatcher {
233 19834185 : explicit BinopMatcher(Node* node)
234 : : NodeMatcher(node), left_(InputAt(0)), right_(InputAt(1)) {
235 19834185 : if (HasProperty(Operator::kCommutative)) PutConstantOnRight();
236 19834193 : }
237 7277971 : BinopMatcher(Node* node, bool allow_input_swap)
238 : : NodeMatcher(node), left_(InputAt(0)), right_(InputAt(1)) {
239 7277971 : if (allow_input_swap) PutConstantOnRight();
240 7277977 : }
241 :
242 : typedef Left LeftMatcher;
243 : typedef Right RightMatcher;
244 :
245 : const Left& left() const { return left_; }
246 : const Right& right() const { return right_; }
247 :
248 5327586 : bool IsFoldable() const { return left().HasValue() && right().HasValue(); }
249 : bool LeftEqualsRight() const { return left().node() == right().node(); }
250 :
251 : protected:
252 411564 : void SwapInputs() {
253 : std::swap(left_, right_);
254 : // TODO(tebbi): This modification should notify the reducers using
255 : // BinopMatcher. Alternatively, all reducers (especially value numbering)
256 : // could ignore the ordering for commutative binops.
257 411564 : node()->ReplaceInput(0, left().node());
258 411564 : node()->ReplaceInput(1, right().node());
259 411564 : }
260 :
261 : private:
262 17214894 : void PutConstantOnRight() {
263 17214894 : if (left().HasValue() && !right().HasValue()) {
264 184645 : SwapInputs();
265 : }
266 17214893 : }
267 :
268 : Left left_;
269 : Right right_;
270 : };
271 :
272 : typedef BinopMatcher<Int32Matcher, Int32Matcher> Int32BinopMatcher;
273 : typedef BinopMatcher<Uint32Matcher, Uint32Matcher> Uint32BinopMatcher;
274 : typedef BinopMatcher<Int64Matcher, Int64Matcher> Int64BinopMatcher;
275 : typedef BinopMatcher<Uint64Matcher, Uint64Matcher> Uint64BinopMatcher;
276 : typedef BinopMatcher<IntPtrMatcher, IntPtrMatcher> IntPtrBinopMatcher;
277 : typedef BinopMatcher<UintPtrMatcher, UintPtrMatcher> UintPtrBinopMatcher;
278 : typedef BinopMatcher<Float32Matcher, Float32Matcher> Float32BinopMatcher;
279 : typedef BinopMatcher<Float64Matcher, Float64Matcher> Float64BinopMatcher;
280 : typedef BinopMatcher<NumberMatcher, NumberMatcher> NumberBinopMatcher;
281 : typedef BinopMatcher<HeapObjectMatcher, HeapObjectMatcher>
282 : HeapObjectBinopMatcher;
283 :
284 : template <class BinopMatcher, IrOpcode::Value kMulOpcode,
285 : IrOpcode::Value kShiftOpcode>
286 : struct ScaleMatcher {
287 19817844 : explicit ScaleMatcher(Node* node, bool allow_power_of_two_plus_one = false)
288 14543569 : : scale_(-1), power_of_two_plus_one_(false) {
289 23812854 : if (node->InputCount() < 2) return;
290 5274284 : BinopMatcher m(node);
291 5274275 : if (node->opcode() == kShiftOpcode) {
292 622333 : if (m.right().HasValue()) {
293 : typename BinopMatcher::RightMatcher::ValueType value =
294 617189 : m.right().Value();
295 617189 : if (value >= 0 && value <= 3) {
296 332100 : scale_ = static_cast<int>(value);
297 : }
298 : }
299 4651942 : } else if (node->opcode() == kMulOpcode) {
300 112632 : if (m.right().HasValue()) {
301 : typename BinopMatcher::RightMatcher::ValueType value =
302 110135 : m.right().Value();
303 110135 : if (value == 1) {
304 1747 : scale_ = 0;
305 108388 : } else if (value == 2) {
306 2785 : scale_ = 1;
307 105603 : } else if (value == 4) {
308 357 : scale_ = 2;
309 105246 : } else if (value == 8) {
310 327 : scale_ = 3;
311 104919 : } else if (allow_power_of_two_plus_one) {
312 104919 : if (value == 3) {
313 52599 : scale_ = 1;
314 52599 : power_of_two_plus_one_ = true;
315 52320 : } else if (value == 5) {
316 2745 : scale_ = 2;
317 2745 : power_of_two_plus_one_ = true;
318 49575 : } else if (value == 9) {
319 337 : scale_ = 3;
320 337 : power_of_two_plus_one_ = true;
321 : }
322 : }
323 : }
324 : }
325 : }
326 :
327 : bool matches() const { return scale_ != -1; }
328 : int scale() const { return scale_; }
329 : bool power_of_two_plus_one() const { return power_of_two_plus_one_; }
330 :
331 : private:
332 : int scale_;
333 : bool power_of_two_plus_one_;
334 : };
335 :
336 : typedef ScaleMatcher<Int32BinopMatcher, IrOpcode::kInt32Mul,
337 : IrOpcode::kWord32Shl> Int32ScaleMatcher;
338 : typedef ScaleMatcher<Int64BinopMatcher, IrOpcode::kInt64Mul,
339 : IrOpcode::kWord64Shl> Int64ScaleMatcher;
340 :
341 : template <class BinopMatcher, IrOpcode::Value AddOpcode,
342 : IrOpcode::Value SubOpcode, IrOpcode::Value kMulOpcode,
343 : IrOpcode::Value kShiftOpcode>
344 : struct AddMatcher : public BinopMatcher {
345 : static const IrOpcode::Value kAddOpcode = AddOpcode;
346 : static const IrOpcode::Value kSubOpcode = SubOpcode;
347 : typedef ScaleMatcher<BinopMatcher, kMulOpcode, kShiftOpcode> Matcher;
348 :
349 6910783 : AddMatcher(Node* node, bool allow_input_swap)
350 : : BinopMatcher(node, allow_input_swap),
351 : scale_(-1),
352 6910783 : power_of_two_plus_one_(false) {
353 6910806 : Initialize(node, allow_input_swap);
354 6910774 : }
355 734360 : explicit AddMatcher(Node* node)
356 : : BinopMatcher(node, node->op()->HasProperty(Operator::kCommutative)),
357 : scale_(-1),
358 367180 : power_of_two_plus_one_(false) {
359 367180 : Initialize(node, node->op()->HasProperty(Operator::kCommutative));
360 367180 : }
361 :
362 : bool HasIndexInput() const { return scale_ != -1; }
363 : Node* IndexInput() const {
364 : DCHECK(HasIndexInput());
365 : return this->left().node()->InputAt(0);
366 : }
367 : int scale() const {
368 : DCHECK(HasIndexInput());
369 : return scale_;
370 : }
371 : bool power_of_two_plus_one() const { return power_of_two_plus_one_; }
372 :
373 : private:
374 7277964 : void Initialize(Node* node, bool allow_input_swap) {
375 7277964 : Matcher left_matcher(this->left().node(), true);
376 7277958 : if (left_matcher.matches()) {
377 321892 : scale_ = left_matcher.scale();
378 321892 : power_of_two_plus_one_ = left_matcher.power_of_two_plus_one();
379 713063 : return;
380 : }
381 :
382 6956066 : if (!allow_input_swap) {
383 : return;
384 : }
385 :
386 6932774 : Matcher right_matcher(this->right().node(), true);
387 6932772 : if (right_matcher.matches()) {
388 45987 : scale_ = right_matcher.scale();
389 45987 : power_of_two_plus_one_ = right_matcher.power_of_two_plus_one();
390 45987 : this->SwapInputs();
391 45987 : return;
392 : }
393 :
394 7051717 : if (this->right().opcode() == kAddOpcode &&
395 : this->left().opcode() != kAddOpcode) {
396 164127 : this->SwapInputs();
397 6739806 : } else if (this->right().opcode() == kSubOpcode &&
398 : this->left().opcode() != kSubOpcode) {
399 16806 : this->SwapInputs();
400 : }
401 : }
402 :
403 : int scale_;
404 : bool power_of_two_plus_one_;
405 : };
406 :
407 : typedef AddMatcher<Int32BinopMatcher, IrOpcode::kInt32Add, IrOpcode::kInt32Sub,
408 : IrOpcode::kInt32Mul, IrOpcode::kWord32Shl>
409 : Int32AddMatcher;
410 : typedef AddMatcher<Int64BinopMatcher, IrOpcode::kInt64Add, IrOpcode::kInt64Sub,
411 : IrOpcode::kInt64Mul, IrOpcode::kWord64Shl>
412 : Int64AddMatcher;
413 :
414 : enum DisplacementMode { kPositiveDisplacement, kNegativeDisplacement };
415 :
416 : enum class AddressOption : uint8_t {
417 : kAllowNone = 0u,
418 : kAllowInputSwap = 1u << 0,
419 : kAllowScale = 1u << 1,
420 : kAllowAll = kAllowInputSwap | kAllowScale
421 : };
422 :
423 : typedef base::Flags<AddressOption, uint8_t> AddressOptions;
424 : DEFINE_OPERATORS_FOR_FLAGS(AddressOptions);
425 :
426 : template <class AddMatcher>
427 : struct BaseWithIndexAndDisplacementMatcher {
428 : BaseWithIndexAndDisplacementMatcher(Node* node, AddressOptions options)
429 : : matches_(false),
430 : index_(nullptr),
431 : scale_(0),
432 : base_(nullptr),
433 : displacement_(nullptr),
434 5714478 : displacement_mode_(kPositiveDisplacement) {
435 5714478 : Initialize(node, options);
436 : }
437 :
438 2392640 : explicit BaseWithIndexAndDisplacementMatcher(Node* node)
439 : : matches_(false),
440 : index_(nullptr),
441 : scale_(0),
442 : base_(nullptr),
443 : displacement_(nullptr),
444 1196320 : displacement_mode_(kPositiveDisplacement) {
445 1196320 : Initialize(node, AddressOption::kAllowScale |
446 : (node->op()->HasProperty(Operator::kCommutative)
447 : ? AddressOption::kAllowInputSwap
448 1196320 : : AddressOption::kAllowNone));
449 1196327 : }
450 :
451 : bool matches() const { return matches_; }
452 : Node* index() const { return index_; }
453 : int scale() const { return scale_; }
454 : Node* base() const { return base_; }
455 : Node* displacement() const { return displacement_; }
456 : DisplacementMode displacement_mode() const { return displacement_mode_; }
457 :
458 : private:
459 : bool matches_;
460 : Node* index_;
461 : int scale_;
462 : Node* base_;
463 : Node* displacement_;
464 : DisplacementMode displacement_mode_;
465 :
466 6910787 : void Initialize(Node* node, AddressOptions options) {
467 : // The BaseWithIndexAndDisplacementMatcher canonicalizes the order of
468 : // displacements and scale factors that are used as inputs, so instead of
469 : // enumerating all possible patterns by brute force, checking for node
470 : // clusters using the following templates in the following order suffices to
471 : // find all of the interesting cases (S = index * scale, B = base input, D =
472 : // displacement input):
473 : // (S + (B + D))
474 : // (S + (B + B))
475 : // (S + D)
476 : // (S + B)
477 : // ((S + D) + B)
478 : // ((S + B) + D)
479 : // ((B + D) + B)
480 : // ((B + B) + D)
481 : // (B + D)
482 : // (B + B)
483 6910789 : if (node->InputCount() < 2) return;
484 6910785 : AddMatcher m(node, options & AddressOption::kAllowInputSwap);
485 13461478 : Node* left = m.left().node();
486 354497 : Node* right = m.right().node();
487 6613027 : Node* displacement = nullptr;
488 : Node* base = nullptr;
489 : Node* index = nullptr;
490 : Node* scale_expression = nullptr;
491 : bool power_of_two_plus_one = false;
492 : DisplacementMode displacement_mode = kPositiveDisplacement;
493 : int scale = 0;
494 6910791 : if (m.HasIndexInput() && left->OwnedByAddressingOperand()) {
495 : index = m.IndexInput();
496 177253 : scale = m.scale();
497 : scale_expression = left;
498 177253 : power_of_two_plus_one = m.power_of_two_plus_one();
499 : bool match_found = false;
500 177265 : if (right->opcode() == AddMatcher::kSubOpcode &&
501 12 : right->OwnedByAddressingOperand()) {
502 8 : AddMatcher right_matcher(right);
503 8 : if (right_matcher.right().HasValue()) {
504 : // (S + (B - D))
505 : base = right_matcher.left().node();
506 : displacement = right_matcher.right().node();
507 : displacement_mode = kNegativeDisplacement;
508 : match_found = true;
509 : }
510 : }
511 177253 : if (!match_found) {
512 181650 : if (right->opcode() == AddMatcher::kAddOpcode &&
513 4406 : right->OwnedByAddressingOperand()) {
514 4381 : AddMatcher right_matcher(right);
515 4381 : if (right_matcher.right().HasValue()) {
516 : // (S + (B + D))
517 : base = right_matcher.left().node();
518 : displacement = right_matcher.right().node();
519 : } else {
520 : // (S + (B + B))
521 : base = right;
522 : }
523 172863 : } else if (m.right().HasValue()) {
524 : // (S + D)
525 : displacement = right;
526 : } else {
527 : // (S + B)
528 : base = right;
529 : }
530 : }
531 : } else {
532 : bool match_found = false;
533 6772410 : if (left->opcode() == AddMatcher::kSubOpcode &&
534 38872 : left->OwnedByAddressingOperand()) {
535 20691 : AddMatcher left_matcher(left);
536 1748 : Node* left_left = left_matcher.left().node();
537 : Node* left_right = left_matcher.right().node();
538 20691 : if (left_matcher.right().HasValue()) {
539 17870 : if (left_matcher.HasIndexInput() && left_left->OwnedBy(left)) {
540 : // ((S - D) + B)
541 : index = left_matcher.IndexInput();
542 : scale = left_matcher.scale();
543 : scale_expression = left_left;
544 0 : power_of_two_plus_one = left_matcher.power_of_two_plus_one();
545 : displacement = left_right;
546 : displacement_mode = kNegativeDisplacement;
547 : base = right;
548 : } else {
549 : // ((B - D) + B)
550 : index = left_left;
551 : displacement = left_right;
552 : displacement_mode = kNegativeDisplacement;
553 : base = right;
554 : }
555 : match_found = true;
556 : }
557 : }
558 6733538 : if (!match_found) {
559 7197573 : if (left->opcode() == AddMatcher::kAddOpcode &&
560 480180 : left->OwnedByAddressingOperand()) {
561 342100 : AddMatcher left_matcher(left);
562 173299 : Node* left_left = left_matcher.left().node();
563 : Node* left_right = left_matcher.right().node();
564 515399 : if (left_matcher.HasIndexInput() && left_left->OwnedBy(left)) {
565 172889 : if (left_matcher.right().HasValue()) {
566 : // ((S + D) + B)
567 : index = left_matcher.IndexInput();
568 : scale = left_matcher.scale();
569 : scale_expression = left_left;
570 171563 : power_of_two_plus_one = left_matcher.power_of_two_plus_one();
571 : displacement = left_right;
572 : base = right;
573 1326 : } else if (m.right().HasValue()) {
574 890 : if (left->OwnedBy(node)) {
575 : // ((S + B) + D)
576 : index = left_matcher.IndexInput();
577 : scale = left_matcher.scale();
578 : scale_expression = left_left;
579 844 : power_of_two_plus_one = left_matcher.power_of_two_plus_one();
580 : base = left_right;
581 : displacement = right;
582 : } else {
583 : // (B + D)
584 : base = left;
585 : displacement = right;
586 : }
587 : } else {
588 : // (B + B)
589 : index = left;
590 : base = right;
591 : }
592 : } else {
593 169211 : if (left_matcher.right().HasValue()) {
594 : // ((B + D) + B)
595 : index = left_left;
596 : displacement = left_right;
597 : base = right;
598 22307 : } else if (m.right().HasValue()) {
599 9657 : if (left->OwnedBy(node)) {
600 : // ((B + B) + D)
601 : index = left_left;
602 : base = left_right;
603 : displacement = right;
604 : } else {
605 : // (B + D)
606 : base = left;
607 : displacement = right;
608 : }
609 : } else {
610 : // (B + B)
611 : index = left;
612 : base = right;
613 : }
614 : }
615 : } else {
616 6375293 : if (m.right().HasValue()) {
617 : // (B + D)
618 : base = left;
619 : displacement = right;
620 : } else {
621 : // (B + B)
622 : base = left;
623 : index = right;
624 : }
625 : }
626 : }
627 : }
628 : int64_t value = 0;
629 6910791 : if (displacement != nullptr) {
630 6613027 : switch (displacement->opcode()) {
631 : case IrOpcode::kInt32Constant: {
632 523489 : value = OpParameter<int32_t>(displacement);
633 523489 : break;
634 : }
635 : case IrOpcode::kInt64Constant: {
636 6089538 : value = OpParameter<int64_t>(displacement);
637 6089538 : break;
638 : }
639 : default:
640 0 : UNREACHABLE();
641 : break;
642 : }
643 6613027 : if (value == 0) {
644 : displacement = nullptr;
645 : }
646 : }
647 6910791 : if (power_of_two_plus_one) {
648 44930 : if (base != nullptr) {
649 : // If the scale requires explicitly using the index as the base, but a
650 : // base is already part of the match, then the (1 << N + 1) scale factor
651 : // can't be folded into the match and the entire index * scale
652 : // calculation must be computed separately.
653 : index = scale_expression;
654 : scale = 0;
655 : } else {
656 : base = index;
657 : }
658 : }
659 6910791 : if (!(options & AddressOption::kAllowScale) && scale != 0) {
660 : index = scale_expression;
661 : scale = 0;
662 : }
663 6910791 : base_ = base;
664 6910791 : displacement_ = displacement;
665 6910791 : displacement_mode_ = displacement_mode;
666 6910791 : index_ = index;
667 6910791 : scale_ = scale;
668 6910791 : matches_ = true;
669 : }
670 : };
671 :
672 : typedef BaseWithIndexAndDisplacementMatcher<Int32AddMatcher>
673 : BaseWithIndexAndDisplacement32Matcher;
674 : typedef BaseWithIndexAndDisplacementMatcher<Int64AddMatcher>
675 : BaseWithIndexAndDisplacement64Matcher;
676 :
677 : struct V8_EXPORT_PRIVATE BranchMatcher : public NON_EXPORTED_BASE(NodeMatcher) {
678 : explicit BranchMatcher(Node* branch);
679 :
680 15 : bool Matched() const { return if_true_ && if_false_; }
681 :
682 : Node* Branch() const { return node(); }
683 : Node* IfTrue() const { return if_true_; }
684 : Node* IfFalse() const { return if_false_; }
685 :
686 : private:
687 : Node* if_true_;
688 : Node* if_false_;
689 : };
690 :
691 : struct V8_EXPORT_PRIVATE DiamondMatcher
692 : : public NON_EXPORTED_BASE(NodeMatcher) {
693 : explicit DiamondMatcher(Node* merge);
694 :
695 4 : bool Matched() const { return branch_; }
696 : bool IfProjectionsAreOwned() const {
697 : return if_true_->OwnedBy(node()) && if_false_->OwnedBy(node());
698 : }
699 :
700 : Node* Branch() const { return branch_; }
701 : Node* IfTrue() const { return if_true_; }
702 : Node* IfFalse() const { return if_false_; }
703 : Node* Merge() const { return node(); }
704 :
705 : Node* TrueInputOf(Node* phi) const {
706 : DCHECK(IrOpcode::IsPhiOpcode(phi->opcode()));
707 : DCHECK_EQ(3, phi->InputCount());
708 : DCHECK_EQ(Merge(), phi->InputAt(2));
709 : return phi->InputAt(if_true_ == Merge()->InputAt(0) ? 0 : 1);
710 : }
711 :
712 : Node* FalseInputOf(Node* phi) const {
713 : DCHECK(IrOpcode::IsPhiOpcode(phi->opcode()));
714 : DCHECK_EQ(3, phi->InputCount());
715 : DCHECK_EQ(Merge(), phi->InputAt(2));
716 : return phi->InputAt(if_true_ == Merge()->InputAt(0) ? 1 : 0);
717 : }
718 :
719 : private:
720 : Node* branch_;
721 : Node* if_true_;
722 : Node* if_false_;
723 : };
724 :
725 : } // namespace compiler
726 : } // namespace internal
727 : } // namespace v8
728 :
729 : #endif // V8_COMPILER_NODE_MATCHERS_H_
|