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 93693956 : explicit NodeMatcher(Node* node) : node_(node) {}
25 :
26 43312960 : Node* node() const { return node_; }
27 19470244 : const Operator* op() const { return node()->op(); }
28 87039301 : 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 2665 : 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 38188176 : : NodeMatcher(node), value_(), has_value_(opcode() == kOpcode) {
56 27040962 : if (has_value_) {
57 10625905 : 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 1731735 : has_value_(opcode() == IrOpcode::kInt32Constant) {
79 981823 : if (has_value_) {
80 612917 : 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 40696980 : : NodeMatcher(node), value_(), has_value_(false) {
88 43188364 : if (opcode() == IrOpcode::kInt32Constant) {
89 411705 : value_ = OpParameter<int32_t>(node);
90 409636 : has_value_ = true;
91 42776659 : } else if (opcode() == IrOpcode::kInt64Constant) {
92 18760304 : value_ = OpParameter<int64_t>(node);
93 17766662 : has_value_ = true;
94 : }
95 : }
96 :
97 :
98 : template <>
99 : inline ValueMatcher<uint64_t, IrOpcode::kInt64Constant>::ValueMatcher(
100 : Node* node)
101 70486 : : NodeMatcher(node), value_(), has_value_(false) {
102 70486 : if (opcode() == IrOpcode::kInt32Constant) {
103 7 : value_ = static_cast<uint32_t>(OpParameter<int32_t>(node));
104 7 : has_value_ = true;
105 70479 : } else if (opcode() == IrOpcode::kInt64Constant) {
106 69758 : value_ = static_cast<uint64_t>(OpParameter<int64_t>(node));
107 69758 : 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 8161260 : return this->HasValue() && this->Value() == value;
119 : }
120 : bool IsInRange(const T& low, const T& high) const {
121 368168 : return this->HasValue() && low <= this->Value() && this->Value() <= high;
122 : }
123 : bool IsMultipleOf(T n) const {
124 18596 : return this->HasValue() && (this->Value() % n) == 0;
125 : }
126 : bool IsPowerOf2() const {
127 : return this->HasValue() && this->Value() > 0 &&
128 14692 : (this->Value() & (this->Value() - 1)) == 0;
129 : }
130 : bool IsNegativePowerOf2() const {
131 497274 : return this->HasValue() && this->Value() < 0 &&
132 497274 : (-this->Value() & (-this->Value() - 1)) == 0;
133 : }
134 2112 : 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 494468 : return this->HasValue() && this->Value() == value;
157 : }
158 : bool IsInRange(const T& low, const T& high) const {
159 58 : return this->HasValue() && low <= this->Value() && this->Value() <= high;
160 : }
161 53153 : bool IsMinusZero() const {
162 62729 : return this->Is(0.0) && std::signbit(this->Value());
163 : }
164 : bool IsNegative() const { return this->HasValue() && this->Value() < 0.0; }
165 570780 : 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 42507 : return this->HasValue() && std::isnormal(this->Value());
169 : }
170 : bool IsInteger() const {
171 133 : return this->HasValue() && std::nearbyint(this->Value()) == this->Value();
172 : }
173 12659 : bool IsPositiveOrNegativePowerOf2() const {
174 12659 : if (!this->HasValue() || (this->Value() == 0.0)) {
175 : return false;
176 : }
177 12659 : Double value = Double(this->Value());
178 : return !value.IsInfinite() &&
179 25318 : base::bits::IsPowerOfTwo64(value.Significand());
180 : }
181 : };
182 :
183 : typedef FloatMatcher<float, IrOpcode::kFloat32Constant> Float32Matcher;
184 : typedef FloatMatcher<double, IrOpcode::kFloat64Constant> Float64Matcher;
185 : typedef FloatMatcher<double, IrOpcode::kNumberConstant> NumberMatcher;
186 :
187 :
188 : // A pattern matcher for heap object constants.
189 : struct HeapObjectMatcher final
190 : : public ValueMatcher<Handle<HeapObject>, IrOpcode::kHeapConstant> {
191 : explicit HeapObjectMatcher(Node* node)
192 : : ValueMatcher<Handle<HeapObject>, IrOpcode::kHeapConstant>(node) {}
193 :
194 205706 : bool Is(Handle<HeapObject> const& value) const {
195 279339 : return this->HasValue() && this->Value().address() == value.address();
196 : }
197 : };
198 :
199 :
200 : // A pattern matcher for external reference constants.
201 : struct ExternalReferenceMatcher final
202 : : public ValueMatcher<ExternalReference, IrOpcode::kExternalConstant> {
203 : explicit ExternalReferenceMatcher(Node* node)
204 : : ValueMatcher<ExternalReference, IrOpcode::kExternalConstant>(node) {}
205 : bool Is(const ExternalReference& value) const {
206 523250 : return this->HasValue() && this->Value() == value;
207 : }
208 : };
209 :
210 :
211 : // For shorter pattern matching code, this struct matches the inputs to
212 : // machine-level load operations.
213 : template <typename Object>
214 : struct LoadMatcher : public NodeMatcher {
215 4605010 : explicit LoadMatcher(Node* node)
216 4605010 : : NodeMatcher(node), object_(InputAt(0)), index_(InputAt(1)) {}
217 :
218 : typedef Object ObjectMatcher;
219 :
220 : Object const& object() const { return object_; }
221 : IntPtrMatcher const& index() const { return index_; }
222 :
223 : private:
224 : Object const object_;
225 : IntPtrMatcher const index_;
226 : };
227 :
228 :
229 : // For shorter pattern matching code, this struct matches both the left and
230 : // right hand sides of a binary operation and can put constants on the right
231 : // if they appear on the left hand side of a commutative operation.
232 : template <typename Left, typename Right>
233 : struct BinopMatcher : public NodeMatcher {
234 19470244 : explicit BinopMatcher(Node* node)
235 : : NodeMatcher(node), left_(InputAt(0)), right_(InputAt(1)) {
236 19470244 : if (HasProperty(Operator::kCommutative)) PutConstantOnRight();
237 19470240 : }
238 6791069 : BinopMatcher(Node* node, bool allow_input_swap)
239 : : NodeMatcher(node), left_(InputAt(0)), right_(InputAt(1)) {
240 6791069 : if (allow_input_swap) PutConstantOnRight();
241 6791066 : }
242 :
243 : typedef Left LeftMatcher;
244 : typedef Right RightMatcher;
245 :
246 : const Left& left() const { return left_; }
247 : const Right& right() const { return right_; }
248 :
249 6031619 : bool IsFoldable() const { return left().HasValue() && right().HasValue(); }
250 : bool LeftEqualsRight() const { return left().node() == right().node(); }
251 :
252 : protected:
253 795750 : void SwapInputs() {
254 : std::swap(left_, right_);
255 : // TODO(tebbi): This modification should notify the reducers using
256 : // BinopMatcher. Alternatively, all reducers (especially value numbering)
257 : // could ignore the ordering for commutative binops.
258 795750 : node()->ReplaceInput(0, left().node());
259 795750 : node()->ReplaceInput(1, right().node());
260 795750 : }
261 :
262 : private:
263 17130384 : void PutConstantOnRight() {
264 17130384 : if (left().HasValue() && !right().HasValue()) {
265 398625 : SwapInputs();
266 : }
267 17130384 : }
268 :
269 : Left left_;
270 : Right right_;
271 : };
272 :
273 : typedef BinopMatcher<Int32Matcher, Int32Matcher> Int32BinopMatcher;
274 : typedef BinopMatcher<Uint32Matcher, Uint32Matcher> Uint32BinopMatcher;
275 : typedef BinopMatcher<Int64Matcher, Int64Matcher> Int64BinopMatcher;
276 : typedef BinopMatcher<Uint64Matcher, Uint64Matcher> Uint64BinopMatcher;
277 : typedef BinopMatcher<IntPtrMatcher, IntPtrMatcher> IntPtrBinopMatcher;
278 : typedef BinopMatcher<UintPtrMatcher, UintPtrMatcher> UintPtrBinopMatcher;
279 : typedef BinopMatcher<Float32Matcher, Float32Matcher> Float32BinopMatcher;
280 : typedef BinopMatcher<Float64Matcher, Float64Matcher> Float64BinopMatcher;
281 : typedef BinopMatcher<NumberMatcher, NumberMatcher> NumberBinopMatcher;
282 : typedef BinopMatcher<HeapObjectMatcher, HeapObjectMatcher>
283 : HeapObjectBinopMatcher;
284 :
285 : template <class BinopMatcher, IrOpcode::Value kMulOpcode,
286 : IrOpcode::Value kShiftOpcode>
287 : struct ScaleMatcher {
288 18220068 : explicit ScaleMatcher(Node* node, bool allow_power_of_two_plus_one = false)
289 13584785 : : scale_(-1), power_of_two_plus_one_(false) {
290 22534295 : if (node->InputCount() < 2) return;
291 4635275 : BinopMatcher m(node);
292 4635283 : if (node->opcode() == kShiftOpcode) {
293 624418 : if (m.right().HasValue()) {
294 : typename BinopMatcher::RightMatcher::ValueType value =
295 619247 : m.right().Value();
296 619247 : if (value >= 0 && value <= 3) {
297 332550 : scale_ = static_cast<int>(value);
298 : }
299 : }
300 4010865 : } else if (node->opcode() == kMulOpcode) {
301 109524 : if (m.right().HasValue()) {
302 : typename BinopMatcher::RightMatcher::ValueType value =
303 107403 : m.right().Value();
304 107403 : if (value == 1) {
305 1998 : scale_ = 0;
306 105405 : } else if (value == 2) {
307 6399 : scale_ = 1;
308 99006 : } else if (value == 4) {
309 337 : scale_ = 2;
310 98669 : } else if (value == 8) {
311 6424 : scale_ = 3;
312 92245 : } else if (allow_power_of_two_plus_one) {
313 92245 : if (value == 3) {
314 37320 : scale_ = 1;
315 37320 : power_of_two_plus_one_ = true;
316 54925 : } else if (value == 5) {
317 2080 : scale_ = 2;
318 2080 : power_of_two_plus_one_ = true;
319 52845 : } else if (value == 9) {
320 390 : scale_ = 3;
321 390 : power_of_two_plus_one_ = true;
322 : }
323 : }
324 : }
325 : }
326 : }
327 :
328 : bool matches() const { return scale_ != -1; }
329 : int scale() const { return scale_; }
330 : bool power_of_two_plus_one() const { return power_of_two_plus_one_; }
331 :
332 : private:
333 : int scale_;
334 : bool power_of_two_plus_one_;
335 : };
336 :
337 : typedef ScaleMatcher<Int32BinopMatcher, IrOpcode::kInt32Mul,
338 : IrOpcode::kWord32Shl> Int32ScaleMatcher;
339 : typedef ScaleMatcher<Int64BinopMatcher, IrOpcode::kInt64Mul,
340 : IrOpcode::kWord64Shl> Int64ScaleMatcher;
341 :
342 : template <class BinopMatcher, IrOpcode::Value AddOpcode,
343 : IrOpcode::Value SubOpcode, IrOpcode::Value kMulOpcode,
344 : IrOpcode::Value kShiftOpcode>
345 : struct AddMatcher : public BinopMatcher {
346 : static const IrOpcode::Value kAddOpcode = AddOpcode;
347 : static const IrOpcode::Value kSubOpcode = SubOpcode;
348 : typedef ScaleMatcher<BinopMatcher, kMulOpcode, kShiftOpcode> Matcher;
349 :
350 6389127 : AddMatcher(Node* node, bool allow_input_swap)
351 : : BinopMatcher(node, allow_input_swap),
352 : scale_(-1),
353 6389127 : power_of_two_plus_one_(false) {
354 6389168 : Initialize(node, allow_input_swap);
355 6389151 : }
356 803854 : explicit AddMatcher(Node* node)
357 : : BinopMatcher(node, node->op()->HasProperty(Operator::kCommutative)),
358 : scale_(-1),
359 401927 : power_of_two_plus_one_(false) {
360 401927 : Initialize(node, node->op()->HasProperty(Operator::kCommutative));
361 401927 : }
362 :
363 : bool HasIndexInput() const { return scale_ != -1; }
364 : Node* IndexInput() const {
365 : DCHECK(HasIndexInput());
366 : return this->left().node()->InputAt(0);
367 : }
368 : int scale() const {
369 : DCHECK(HasIndexInput());
370 : return scale_;
371 : }
372 : bool power_of_two_plus_one() const { return power_of_two_plus_one_; }
373 :
374 : private:
375 6791089 : void Initialize(Node* node, bool allow_input_swap) {
376 6791089 : Matcher left_matcher(this->left().node(), true);
377 6791086 : if (left_matcher.matches()) {
378 312426 : scale_ = left_matcher.scale();
379 312426 : power_of_two_plus_one_ = left_matcher.power_of_two_plus_one();
380 699087 : return;
381 : }
382 :
383 6478660 : if (!allow_input_swap) {
384 : return;
385 : }
386 :
387 6463538 : Matcher right_matcher(this->right().node(), true);
388 6463531 : if (right_matcher.matches()) {
389 59113 : scale_ = right_matcher.scale();
390 59113 : power_of_two_plus_one_ = right_matcher.power_of_two_plus_one();
391 59113 : this->SwapInputs();
392 59113 : return;
393 : }
394 :
395 6720777 : if (this->right().opcode() == kAddOpcode &&
396 : this->left().opcode() != kAddOpcode) {
397 315407 : this->SwapInputs();
398 6111632 : } else if (this->right().opcode() == kSubOpcode &&
399 : this->left().opcode() != kSubOpcode) {
400 22605 : this->SwapInputs();
401 : }
402 : }
403 :
404 : int scale_;
405 : bool power_of_two_plus_one_;
406 : };
407 :
408 : typedef AddMatcher<Int32BinopMatcher, IrOpcode::kInt32Add, IrOpcode::kInt32Sub,
409 : IrOpcode::kInt32Mul, IrOpcode::kWord32Shl>
410 : Int32AddMatcher;
411 : typedef AddMatcher<Int64BinopMatcher, IrOpcode::kInt64Add, IrOpcode::kInt64Sub,
412 : IrOpcode::kInt64Mul, IrOpcode::kWord64Shl>
413 : Int64AddMatcher;
414 :
415 : enum DisplacementMode { kPositiveDisplacement, kNegativeDisplacement };
416 :
417 : enum class AddressOption : uint8_t {
418 : kAllowNone = 0u,
419 : kAllowInputSwap = 1u << 0,
420 : kAllowScale = 1u << 1,
421 : kAllowAll = kAllowInputSwap | kAllowScale
422 : };
423 :
424 : typedef base::Flags<AddressOption, uint8_t> AddressOptions;
425 : DEFINE_OPERATORS_FOR_FLAGS(AddressOptions);
426 :
427 : template <class AddMatcher>
428 : struct BaseWithIndexAndDisplacementMatcher {
429 : BaseWithIndexAndDisplacementMatcher(Node* node, AddressOptions options)
430 : : matches_(false),
431 : index_(nullptr),
432 : scale_(0),
433 : base_(nullptr),
434 : displacement_(nullptr),
435 5173401 : displacement_mode_(kPositiveDisplacement) {
436 5173401 : Initialize(node, options);
437 : }
438 :
439 2431688 : explicit BaseWithIndexAndDisplacementMatcher(Node* node)
440 : : matches_(false),
441 : index_(nullptr),
442 : scale_(0),
443 : base_(nullptr),
444 : displacement_(nullptr),
445 1215844 : displacement_mode_(kPositiveDisplacement) {
446 1215844 : Initialize(node, AddressOption::kAllowScale |
447 : (node->op()->HasProperty(Operator::kCommutative)
448 : ? AddressOption::kAllowInputSwap
449 1215844 : : AddressOption::kAllowNone));
450 1215863 : }
451 :
452 : bool matches() const { return matches_; }
453 : Node* index() const { return index_; }
454 : int scale() const { return scale_; }
455 : Node* base() const { return base_; }
456 : Node* displacement() const { return displacement_; }
457 : DisplacementMode displacement_mode() const { return displacement_mode_; }
458 :
459 : private:
460 : bool matches_;
461 : Node* index_;
462 : int scale_;
463 : Node* base_;
464 : Node* displacement_;
465 : DisplacementMode displacement_mode_;
466 :
467 6389125 : void Initialize(Node* node, AddressOptions options) {
468 : // The BaseWithIndexAndDisplacementMatcher canonicalizes the order of
469 : // displacements and scale factors that are used as inputs, so instead of
470 : // enumerating all possible patterns by brute force, checking for node
471 : // clusters using the following templates in the following order suffices to
472 : // find all of the interesting cases (S = index * scale, B = base input, D =
473 : // displacement input):
474 : // (S + (B + D))
475 : // (S + (B + B))
476 : // (S + D)
477 : // (S + B)
478 : // ((S + D) + B)
479 : // ((S + B) + D)
480 : // ((B + D) + B)
481 : // ((B + B) + D)
482 : // (B + D)
483 : // (B + B)
484 6389125 : if (node->InputCount() < 2) return;
485 6389125 : AddMatcher m(node, options & AddressOption::kAllowInputSwap);
486 12501441 : Node* left = m.left().node();
487 270662 : Node* right = m.right().node();
488 6184729 : Node* displacement = nullptr;
489 : Node* base = nullptr;
490 : Node* index = nullptr;
491 : Node* scale_expression = nullptr;
492 : bool power_of_two_plus_one = false;
493 : DisplacementMode displacement_mode = kPositiveDisplacement;
494 : int scale = 0;
495 6389152 : if (m.HasIndexInput() && left->OwnedByAddressingOperand()) {
496 : index = m.IndexInput();
497 135331 : scale = m.scale();
498 : scale_expression = left;
499 135331 : power_of_two_plus_one = m.power_of_two_plus_one();
500 : bool match_found = false;
501 135331 : if (right->opcode() == AddMatcher::kSubOpcode &&
502 0 : right->OwnedByAddressingOperand()) {
503 0 : AddMatcher right_matcher(right);
504 0 : if (right_matcher.right().HasValue()) {
505 : // (S + (B - D))
506 : base = right_matcher.left().node();
507 : displacement = right_matcher.right().node();
508 : displacement_mode = kNegativeDisplacement;
509 : match_found = true;
510 : }
511 : }
512 135331 : if (!match_found) {
513 139555 : if (right->opcode() == AddMatcher::kAddOpcode &&
514 4224 : right->OwnedByAddressingOperand()) {
515 4217 : AddMatcher right_matcher(right);
516 4217 : if (right_matcher.right().HasValue()) {
517 : // (S + (B + D))
518 : base = right_matcher.left().node();
519 : displacement = right_matcher.right().node();
520 : } else {
521 : // (S + (B + B))
522 : base = right;
523 : }
524 131114 : } else if (m.right().HasValue()) {
525 : // (S + D)
526 : displacement = right;
527 : } else {
528 : // (S + B)
529 : base = right;
530 : }
531 : }
532 : } else {
533 : bool match_found = false;
534 6281148 : if (left->opcode() == AddMatcher::kSubOpcode &&
535 27327 : left->OwnedByAddressingOperand()) {
536 13324 : AddMatcher left_matcher(left);
537 1347 : Node* left_left = left_matcher.left().node();
538 : Node* left_right = left_matcher.right().node();
539 13324 : if (left_matcher.right().HasValue()) {
540 12892 : if (left_matcher.HasIndexInput() && left_left->OwnedBy(left)) {
541 : // ((S - D) + B)
542 : index = left_matcher.IndexInput();
543 : scale = left_matcher.scale();
544 : scale_expression = left_left;
545 43 : power_of_two_plus_one = left_matcher.power_of_two_plus_one();
546 : displacement = left_right;
547 : displacement_mode = kNegativeDisplacement;
548 : base = right;
549 : } else {
550 : // ((B - D) + B)
551 : index = left_left;
552 : displacement = left_right;
553 : displacement_mode = kNegativeDisplacement;
554 : base = right;
555 : }
556 : match_found = true;
557 : }
558 : }
559 6253821 : if (!match_found) {
560 6749299 : if (left->opcode() == AddMatcher::kAddOpcode &&
561 507038 : left->OwnedByAddressingOperand()) {
562 384386 : AddMatcher left_matcher(left);
563 226518 : Node* left_left = left_matcher.left().node();
564 : Node* left_right = left_matcher.right().node();
565 610904 : if (left_matcher.HasIndexInput() && left_left->OwnedBy(left)) {
566 226101 : if (left_matcher.right().HasValue()) {
567 : // ((S + D) + B)
568 : index = left_matcher.IndexInput();
569 : scale = left_matcher.scale();
570 : scale_expression = left_left;
571 225018 : power_of_two_plus_one = left_matcher.power_of_two_plus_one();
572 : displacement = left_right;
573 : base = right;
574 1083 : } else if (m.right().HasValue()) {
575 578 : if (left->OwnedBy(node)) {
576 : // ((S + B) + D)
577 : index = left_matcher.IndexInput();
578 : scale = left_matcher.scale();
579 : scale_expression = left_left;
580 534 : power_of_two_plus_one = left_matcher.power_of_two_plus_one();
581 : base = left_right;
582 : displacement = right;
583 : } else {
584 : // (B + D)
585 : base = left;
586 : displacement = right;
587 : }
588 : } else {
589 : // (B + B)
590 : index = left;
591 : base = right;
592 : }
593 : } else {
594 158285 : if (left_matcher.right().HasValue()) {
595 : // ((B + D) + B)
596 : index = left_left;
597 : displacement = left_right;
598 : base = right;
599 14941 : } else if (m.right().HasValue()) {
600 4781 : if (left->OwnedBy(node)) {
601 : // ((B + B) + D)
602 : index = left_left;
603 : base = left_right;
604 : displacement = right;
605 : } else {
606 : // (B + D)
607 : base = left;
608 : displacement = right;
609 : }
610 : } else {
611 : // (B + B)
612 : index = left;
613 : base = right;
614 : }
615 : }
616 : } else {
617 5857875 : if (m.right().HasValue()) {
618 : // (B + D)
619 : base = left;
620 : displacement = right;
621 : } else {
622 : // (B + B)
623 : base = left;
624 : index = right;
625 : }
626 : }
627 : }
628 : }
629 : int64_t value = 0;
630 6389152 : if (displacement != nullptr) {
631 6184729 : switch (displacement->opcode()) {
632 : case IrOpcode::kInt32Constant: {
633 449276 : value = OpParameter<int32_t>(displacement);
634 449276 : break;
635 : }
636 : case IrOpcode::kInt64Constant: {
637 5735453 : value = OpParameter<int64_t>(displacement);
638 5735453 : break;
639 : }
640 : default:
641 0 : UNREACHABLE();
642 : break;
643 : }
644 6184729 : if (value == 0) {
645 : displacement = nullptr;
646 : }
647 : }
648 6389152 : if (power_of_two_plus_one) {
649 31857 : if (base != nullptr) {
650 : // If the scale requires explicitly using the index as the base, but a
651 : // base is already part of the match, then the (1 << N + 1) scale factor
652 : // can't be folded into the match and the entire index * scale
653 : // calculation must be computed separately.
654 : index = scale_expression;
655 : scale = 0;
656 : } else {
657 : base = index;
658 : }
659 : }
660 6389152 : if (!(options & AddressOption::kAllowScale) && scale != 0) {
661 : index = scale_expression;
662 : scale = 0;
663 : }
664 6389152 : base_ = base;
665 6389152 : displacement_ = displacement;
666 6389152 : displacement_mode_ = displacement_mode;
667 6389152 : index_ = index;
668 6389152 : scale_ = scale;
669 6389152 : matches_ = true;
670 : }
671 : };
672 :
673 : typedef BaseWithIndexAndDisplacementMatcher<Int32AddMatcher>
674 : BaseWithIndexAndDisplacement32Matcher;
675 : typedef BaseWithIndexAndDisplacementMatcher<Int64AddMatcher>
676 : BaseWithIndexAndDisplacement64Matcher;
677 :
678 : struct V8_EXPORT_PRIVATE BranchMatcher : public NON_EXPORTED_BASE(NodeMatcher) {
679 : explicit BranchMatcher(Node* branch);
680 :
681 : bool Matched() const { return if_true_ && if_false_; }
682 :
683 : Node* Branch() const { return node(); }
684 : Node* IfTrue() const { return if_true_; }
685 : Node* IfFalse() const { return if_false_; }
686 :
687 : private:
688 : Node* if_true_;
689 : Node* if_false_;
690 : };
691 :
692 : struct V8_EXPORT_PRIVATE DiamondMatcher
693 : : public NON_EXPORTED_BASE(NodeMatcher) {
694 : explicit DiamondMatcher(Node* merge);
695 :
696 : bool Matched() const { return branch_; }
697 : bool IfProjectionsAreOwned() const {
698 : return if_true_->OwnedBy(node()) && if_false_->OwnedBy(node());
699 : }
700 :
701 : Node* Branch() const { return branch_; }
702 : Node* IfTrue() const { return if_true_; }
703 : Node* IfFalse() const { return if_false_; }
704 : Node* Merge() const { return node(); }
705 :
706 : Node* TrueInputOf(Node* phi) const {
707 : DCHECK(IrOpcode::IsPhiOpcode(phi->opcode()));
708 : DCHECK_EQ(3, phi->InputCount());
709 : DCHECK_EQ(Merge(), phi->InputAt(2));
710 : return phi->InputAt(if_true_ == Merge()->InputAt(0) ? 0 : 1);
711 : }
712 :
713 : Node* FalseInputOf(Node* phi) const {
714 : DCHECK(IrOpcode::IsPhiOpcode(phi->opcode()));
715 : DCHECK_EQ(3, phi->InputCount());
716 : DCHECK_EQ(Merge(), phi->InputAt(2));
717 : return phi->InputAt(if_true_ == Merge()->InputAt(0) ? 1 : 0);
718 : }
719 :
720 : private:
721 : Node* branch_;
722 : Node* if_true_;
723 : Node* if_false_;
724 : };
725 :
726 : } // namespace compiler
727 : } // namespace internal
728 : } // namespace v8
729 :
730 : #endif // V8_COMPILER_NODE_MATCHERS_H_
|