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 : #include "src/base/compiler-specific.h"
11 : #include "src/compiler/node.h"
12 : #include "src/compiler/operator.h"
13 : #include "src/double.h"
14 : #include "src/external-reference.h"
15 : #include "src/globals.h"
16 : #include "src/objects/heap-object.h"
17 :
18 : namespace v8 {
19 : namespace internal {
20 : namespace compiler {
21 :
22 : class JSHeapBroker;
23 :
24 : // A pattern matcher for nodes.
25 : struct NodeMatcher {
26 155344087 : explicit NodeMatcher(Node* node) : node_(node) {}
27 :
28 90689827 : Node* node() const { return node_; }
29 33228206 : const Operator* op() const { return node()->op(); }
30 158168667 : IrOpcode::Value opcode() const { return node()->opcode(); }
31 :
32 : bool HasProperty(Operator::Property property) const {
33 : return op()->HasProperty(property);
34 : }
35 : Node* InputAt(int index) const { return node()->InputAt(index); }
36 :
37 740 : bool Equals(const Node* node) const { return node_ == node; }
38 :
39 : bool IsComparison() const;
40 :
41 : #define DEFINE_IS_OPCODE(Opcode) \
42 : bool Is##Opcode() const { return opcode() == IrOpcode::k##Opcode; }
43 : ALL_OP_LIST(DEFINE_IS_OPCODE)
44 : #undef DEFINE_IS_OPCODE
45 :
46 : private:
47 : Node* node_;
48 : };
49 :
50 :
51 : // A pattern matcher for abitrary value constants.
52 : template <typename T, IrOpcode::Value kOpcode>
53 : struct ValueMatcher : public NodeMatcher {
54 : typedef T ValueType;
55 :
56 10104782 : explicit ValueMatcher(Node* node)
57 51183706 : : NodeMatcher(node), value_(), has_value_(opcode() == kOpcode) {
58 34760205 : if (has_value_) {
59 12743343 : value_ = OpParameter<T>(node->op());
60 : }
61 : }
62 :
63 : bool HasValue() const { return has_value_; }
64 : const T& Value() const {
65 : DCHECK(HasValue());
66 : return value_;
67 : }
68 :
69 : private:
70 : T value_;
71 : bool has_value_;
72 : };
73 :
74 :
75 : template <>
76 : inline ValueMatcher<uint32_t, IrOpcode::kInt32Constant>::ValueMatcher(
77 711873 : Node* node)
78 : : NodeMatcher(node),
79 : value_(),
80 3591315 : has_value_(opcode() == IrOpcode::kInt32Constant) {
81 2259635 : if (has_value_) {
82 1226891 : value_ = static_cast<uint32_t>(OpParameter<int32_t>(node->op()));
83 : }
84 : }
85 :
86 :
87 : template <>
88 : inline ValueMatcher<int64_t, IrOpcode::kInt64Constant>::ValueMatcher(Node* node)
89 75709909 : : NodeMatcher(node), value_(), has_value_(false) {
90 83302237 : if (opcode() == IrOpcode::kInt32Constant) {
91 6686015 : value_ = OpParameter<int32_t>(node->op());
92 6450050 : has_value_ = true;
93 76616222 : } else if (opcode() == IrOpcode::kInt64Constant) {
94 26216761 : value_ = OpParameter<int64_t>(node->op());
95 24241987 : has_value_ = true;
96 : }
97 : }
98 :
99 :
100 : template <>
101 : inline ValueMatcher<uint64_t, IrOpcode::kInt64Constant>::ValueMatcher(
102 : Node* node)
103 95704 : : NodeMatcher(node), value_(), has_value_(false) {
104 156274 : if (opcode() == IrOpcode::kInt32Constant) {
105 5 : value_ = static_cast<uint32_t>(OpParameter<int32_t>(node->op()));
106 5 : has_value_ = true;
107 156269 : } else if (opcode() == IrOpcode::kInt64Constant) {
108 129140 : value_ = static_cast<uint64_t>(OpParameter<int64_t>(node->op()));
109 73762 : has_value_ = true;
110 : }
111 : }
112 :
113 :
114 : // A pattern matcher for integer constants.
115 : template <typename T, IrOpcode::Value kOpcode>
116 : struct IntMatcher final : public ValueMatcher<T, kOpcode> {
117 : explicit IntMatcher(Node* node) : ValueMatcher<T, kOpcode>(node) {}
118 :
119 : bool Is(const T& value) const {
120 12813522 : return this->HasValue() && this->Value() == value;
121 : }
122 : bool IsInRange(const T& low, const T& high) const {
123 727831 : return this->HasValue() && low <= this->Value() && this->Value() <= high;
124 : }
125 : bool IsMultipleOf(T n) const {
126 16797 : return this->HasValue() && (this->Value() % n) == 0;
127 : }
128 : bool IsPowerOf2() const {
129 : return this->HasValue() && this->Value() > 0 &&
130 26002 : (this->Value() & (this->Value() - 1)) == 0;
131 : }
132 : bool IsNegativePowerOf2() const {
133 601283 : return this->HasValue() && this->Value() < 0 &&
134 : ((this->Value() == kMinInt) ||
135 601283 : (-this->Value() & (-this->Value() - 1)) == 0);
136 : }
137 3462 : bool IsNegative() const { return this->HasValue() && this->Value() < 0; }
138 : };
139 :
140 : typedef IntMatcher<int32_t, IrOpcode::kInt32Constant> Int32Matcher;
141 : typedef IntMatcher<uint32_t, IrOpcode::kInt32Constant> Uint32Matcher;
142 : typedef IntMatcher<int64_t, IrOpcode::kInt64Constant> Int64Matcher;
143 : typedef IntMatcher<uint64_t, IrOpcode::kInt64Constant> Uint64Matcher;
144 : #if V8_HOST_ARCH_32_BIT
145 : typedef Int32Matcher IntPtrMatcher;
146 : typedef Uint32Matcher UintPtrMatcher;
147 : #else
148 : typedef Int64Matcher IntPtrMatcher;
149 : typedef Uint64Matcher UintPtrMatcher;
150 : #endif
151 :
152 :
153 : // A pattern matcher for floating point constants.
154 : template <typename T, IrOpcode::Value kOpcode>
155 : struct FloatMatcher final : public ValueMatcher<T, kOpcode> {
156 : explicit FloatMatcher(Node* node) : ValueMatcher<T, kOpcode>(node) {}
157 :
158 : bool Is(const T& value) const {
159 336061 : return this->HasValue() && this->Value() == value;
160 : }
161 : bool IsInRange(const T& low, const T& high) const {
162 2227 : return this->HasValue() && low <= this->Value() && this->Value() <= high;
163 : }
164 23543 : bool IsMinusZero() const {
165 32069 : return this->Is(0.0) && std::signbit(this->Value());
166 : }
167 : bool IsNegative() const { return this->HasValue() && this->Value() < 0.0; }
168 305256 : bool IsNaN() const { return this->HasValue() && std::isnan(this->Value()); }
169 12 : bool IsZero() const { return this->Is(0.0) && !std::signbit(this->Value()); }
170 : bool IsNormal() const {
171 36482 : return this->HasValue() && std::isnormal(this->Value());
172 : }
173 : bool IsInteger() const {
174 6962 : return this->HasValue() && std::nearbyint(this->Value()) == this->Value();
175 : }
176 9396 : bool IsPositiveOrNegativePowerOf2() const {
177 9396 : if (!this->HasValue() || (this->Value() == 0.0)) {
178 : return false;
179 : }
180 9396 : Double value = Double(this->Value());
181 18792 : return !value.IsInfinite() && base::bits::IsPowerOfTwo(value.Significand());
182 : }
183 : };
184 :
185 : typedef FloatMatcher<float, IrOpcode::kFloat32Constant> Float32Matcher;
186 : typedef FloatMatcher<double, IrOpcode::kFloat64Constant> Float64Matcher;
187 : typedef FloatMatcher<double, IrOpcode::kNumberConstant> NumberMatcher;
188 :
189 :
190 : // A pattern matcher for heap object constants.
191 : struct HeapObjectMatcher final
192 : : public ValueMatcher<Handle<HeapObject>, IrOpcode::kHeapConstant> {
193 : explicit HeapObjectMatcher(Node* node)
194 : : ValueMatcher<Handle<HeapObject>, IrOpcode::kHeapConstant>(node) {}
195 :
196 242129 : bool Is(Handle<HeapObject> const& value) const {
197 415358 : return this->HasValue() && this->Value().address() == value.address();
198 : }
199 :
200 : ObjectRef Ref(JSHeapBroker* broker) const {
201 1050090 : return ObjectRef(broker, this->Value());
202 : }
203 : };
204 :
205 :
206 : // A pattern matcher for external reference constants.
207 : struct ExternalReferenceMatcher final
208 : : public ValueMatcher<ExternalReference, IrOpcode::kExternalConstant> {
209 : explicit ExternalReferenceMatcher(Node* node)
210 : : ValueMatcher<ExternalReference, IrOpcode::kExternalConstant>(node) {}
211 : bool Is(const ExternalReference& value) const {
212 554400 : return this->HasValue() && this->Value() == value;
213 : }
214 : };
215 :
216 :
217 : // For shorter pattern matching code, this struct matches the inputs to
218 : // machine-level load operations.
219 : template <typename Object>
220 : struct LoadMatcher : public NodeMatcher {
221 3840857 : explicit LoadMatcher(Node* node)
222 3862605 : : NodeMatcher(node), object_(InputAt(0)), index_(InputAt(1)) {}
223 :
224 : typedef Object ObjectMatcher;
225 :
226 : Object const& object() const { return object_; }
227 : IntPtrMatcher const& index() const { return index_; }
228 :
229 : private:
230 : Object const object_;
231 : IntPtrMatcher const index_;
232 : };
233 :
234 :
235 : // For shorter pattern matching code, this struct matches both the left and
236 : // right hand sides of a binary operation and can put constants on the right
237 : // if they appear on the left hand side of a commutative operation.
238 : template <typename Left, typename Right>
239 : struct BinopMatcher : public NodeMatcher {
240 33228206 : explicit BinopMatcher(Node* node)
241 : : NodeMatcher(node), left_(InputAt(0)), right_(InputAt(1)) {
242 33228206 : if (HasProperty(Operator::kCommutative)) PutConstantOnRight();
243 33228186 : }
244 14409757 : BinopMatcher(Node* node, bool allow_input_swap)
245 : : NodeMatcher(node), left_(InputAt(0)), right_(InputAt(1)) {
246 14409757 : if (allow_input_swap) PutConstantOnRight();
247 14409782 : }
248 :
249 : typedef Left LeftMatcher;
250 : typedef Right RightMatcher;
251 :
252 : const Left& left() const { return left_; }
253 : const Right& right() const { return right_; }
254 :
255 9019518 : bool IsFoldable() const { return left().HasValue() && right().HasValue(); }
256 : bool LeftEqualsRight() const { return left().node() == right().node(); }
257 :
258 : protected:
259 744177 : void SwapInputs() {
260 : std::swap(left_, right_);
261 : // TODO(tebbi): This modification should notify the reducers using
262 : // BinopMatcher. Alternatively, all reducers (especially value numbering)
263 : // could ignore the ordering for commutative binops.
264 744177 : node()->ReplaceInput(0, left().node());
265 744183 : node()->ReplaceInput(1, right().node());
266 744181 : }
267 :
268 : private:
269 29922709 : void PutConstantOnRight() {
270 29922709 : if (left().HasValue() && !right().HasValue()) {
271 302650 : SwapInputs();
272 : }
273 29922710 : }
274 :
275 : Left left_;
276 : Right right_;
277 : };
278 :
279 : typedef BinopMatcher<Int32Matcher, Int32Matcher> Int32BinopMatcher;
280 : typedef BinopMatcher<Uint32Matcher, Uint32Matcher> Uint32BinopMatcher;
281 : typedef BinopMatcher<Int64Matcher, Int64Matcher> Int64BinopMatcher;
282 : typedef BinopMatcher<Uint64Matcher, Uint64Matcher> Uint64BinopMatcher;
283 : typedef BinopMatcher<IntPtrMatcher, IntPtrMatcher> IntPtrBinopMatcher;
284 : typedef BinopMatcher<UintPtrMatcher, UintPtrMatcher> UintPtrBinopMatcher;
285 : typedef BinopMatcher<Float32Matcher, Float32Matcher> Float32BinopMatcher;
286 : typedef BinopMatcher<Float64Matcher, Float64Matcher> Float64BinopMatcher;
287 : typedef BinopMatcher<NumberMatcher, NumberMatcher> NumberBinopMatcher;
288 : typedef BinopMatcher<HeapObjectMatcher, HeapObjectMatcher>
289 : HeapObjectBinopMatcher;
290 :
291 : template <class BinopMatcher, IrOpcode::Value kMulOpcode,
292 : IrOpcode::Value kShiftOpcode>
293 : struct ScaleMatcher {
294 40518973 : explicit ScaleMatcher(Node* node, bool allow_power_of_two_plus_one = false)
295 28755766 : : scale_(-1), power_of_two_plus_one_(false) {
296 45748342 : if (node->InputCount() < 2) return;
297 11763190 : BinopMatcher m(node);
298 11763207 : if (node->opcode() == kShiftOpcode) {
299 1105540 : if (m.right().HasValue()) {
300 : typename BinopMatcher::RightMatcher::ValueType value =
301 1097804 : m.right().Value();
302 1097804 : if (value >= 0 && value <= 3) {
303 689043 : scale_ = static_cast<int>(value);
304 : }
305 : }
306 10657667 : } else if (node->opcode() == kMulOpcode) {
307 171908 : if (m.right().HasValue()) {
308 : typename BinopMatcher::RightMatcher::ValueType value =
309 166046 : m.right().Value();
310 166046 : if (value == 1) {
311 2101 : scale_ = 0;
312 163945 : } else if (value == 2) {
313 1974 : scale_ = 1;
314 161971 : } else if (value == 4) {
315 927 : scale_ = 2;
316 161044 : } else if (value == 8) {
317 2078 : scale_ = 3;
318 158966 : } else if (allow_power_of_two_plus_one) {
319 158966 : if (value == 3) {
320 72583 : scale_ = 1;
321 72583 : power_of_two_plus_one_ = true;
322 86383 : } else if (value == 5) {
323 4197 : scale_ = 2;
324 4197 : power_of_two_plus_one_ = true;
325 82186 : } else if (value == 9) {
326 1022 : scale_ = 3;
327 1022 : power_of_two_plus_one_ = true;
328 : }
329 : }
330 : }
331 : }
332 : }
333 :
334 : bool matches() const { return scale_ != -1; }
335 : int scale() const { return scale_; }
336 : bool power_of_two_plus_one() const { return power_of_two_plus_one_; }
337 :
338 : private:
339 : int scale_;
340 : bool power_of_two_plus_one_;
341 : };
342 :
343 : typedef ScaleMatcher<Int32BinopMatcher, IrOpcode::kInt32Mul,
344 : IrOpcode::kWord32Shl> Int32ScaleMatcher;
345 : typedef ScaleMatcher<Int64BinopMatcher, IrOpcode::kInt64Mul,
346 : IrOpcode::kWord64Shl> Int64ScaleMatcher;
347 :
348 : template <class BinopMatcher, IrOpcode::Value AddOpcode,
349 : IrOpcode::Value SubOpcode, IrOpcode::Value kMulOpcode,
350 : IrOpcode::Value kShiftOpcode>
351 : struct AddMatcher : public BinopMatcher {
352 : static const IrOpcode::Value kAddOpcode = AddOpcode;
353 : static const IrOpcode::Value kSubOpcode = SubOpcode;
354 : typedef ScaleMatcher<BinopMatcher, kMulOpcode, kShiftOpcode> Matcher;
355 :
356 13784508 : AddMatcher(Node* node, bool allow_input_swap)
357 : : BinopMatcher(node, allow_input_swap),
358 : scale_(-1),
359 13784508 : power_of_two_plus_one_(false) {
360 13784570 : Initialize(node, allow_input_swap);
361 13784618 : }
362 1250476 : explicit AddMatcher(Node* node)
363 : : BinopMatcher(node, node->op()->HasProperty(Operator::kCommutative)),
364 : scale_(-1),
365 625249 : power_of_two_plus_one_(false) {
366 625227 : Initialize(node, node->op()->HasProperty(Operator::kCommutative));
367 625240 : }
368 :
369 : bool HasIndexInput() const { return scale_ != -1; }
370 : Node* IndexInput() const {
371 : DCHECK(HasIndexInput());
372 : return this->left().node()->InputAt(0);
373 : }
374 : int scale() const {
375 : DCHECK(HasIndexInput());
376 : return scale_;
377 : }
378 : bool power_of_two_plus_one() const { return power_of_two_plus_one_; }
379 :
380 : private:
381 14409797 : void Initialize(Node* node, bool allow_input_swap) {
382 14409797 : Matcher left_matcher(this->left().node(), true);
383 14409808 : if (left_matcher.matches()) {
384 604923 : scale_ = left_matcher.scale();
385 604923 : power_of_two_plus_one_ = left_matcher.power_of_two_plus_one();
386 1309347 : return;
387 : }
388 :
389 13804885 : if (!allow_input_swap) {
390 : return;
391 : }
392 :
393 13795882 : Matcher right_matcher(this->right().node(), true);
394 13795849 : if (right_matcher.matches()) {
395 90498 : scale_ = right_matcher.scale();
396 90498 : power_of_two_plus_one_ = right_matcher.power_of_two_plus_one();
397 90498 : this->SwapInputs();
398 90498 : return;
399 : }
400 :
401 26740616 : if ((this->left().opcode() != kSubOpcode &&
402 : this->left().opcode() != kAddOpcode) &&
403 : (this->right().opcode() == kAddOpcode ||
404 : this->right().opcode() == kSubOpcode)) {
405 351032 : this->SwapInputs();
406 : }
407 : }
408 :
409 : int scale_;
410 : bool power_of_two_plus_one_;
411 : };
412 :
413 : typedef AddMatcher<Int32BinopMatcher, IrOpcode::kInt32Add, IrOpcode::kInt32Sub,
414 : IrOpcode::kInt32Mul, IrOpcode::kWord32Shl>
415 : Int32AddMatcher;
416 : typedef AddMatcher<Int64BinopMatcher, IrOpcode::kInt64Add, IrOpcode::kInt64Sub,
417 : IrOpcode::kInt64Mul, IrOpcode::kWord64Shl>
418 : Int64AddMatcher;
419 :
420 : enum DisplacementMode { kPositiveDisplacement, kNegativeDisplacement };
421 :
422 : enum class AddressOption : uint8_t {
423 : kAllowNone = 0u,
424 : kAllowInputSwap = 1u << 0,
425 : kAllowScale = 1u << 1,
426 : kAllowAll = kAllowInputSwap | kAllowScale
427 : };
428 :
429 : typedef base::Flags<AddressOption, uint8_t> AddressOptions;
430 : DEFINE_OPERATORS_FOR_FLAGS(AddressOptions);
431 :
432 : template <class AddMatcher>
433 : struct BaseWithIndexAndDisplacementMatcher {
434 : BaseWithIndexAndDisplacementMatcher(Node* node, AddressOptions options)
435 : : matches_(false),
436 : index_(nullptr),
437 : scale_(0),
438 : base_(nullptr),
439 : displacement_(nullptr),
440 11348255 : displacement_mode_(kPositiveDisplacement) {
441 11348255 : Initialize(node, options);
442 : }
443 :
444 4872584 : explicit BaseWithIndexAndDisplacementMatcher(Node* node)
445 : : matches_(false),
446 : index_(nullptr),
447 : scale_(0),
448 : base_(nullptr),
449 : displacement_(nullptr),
450 2436292 : displacement_mode_(kPositiveDisplacement) {
451 2436292 : Initialize(node, AddressOption::kAllowScale |
452 : (node->op()->HasProperty(Operator::kCommutative)
453 : ? AddressOption::kAllowInputSwap
454 2436292 : : AddressOption::kAllowNone));
455 2436350 : }
456 :
457 : bool matches() const { return matches_; }
458 : Node* index() const { return index_; }
459 : int scale() const { return scale_; }
460 : Node* base() const { return base_; }
461 : Node* displacement() const { return displacement_; }
462 : DisplacementMode displacement_mode() const { return displacement_mode_; }
463 :
464 : private:
465 : bool matches_;
466 : Node* index_;
467 : int scale_;
468 : Node* base_;
469 : Node* displacement_;
470 : DisplacementMode displacement_mode_;
471 :
472 13784509 : void Initialize(Node* node, AddressOptions options) {
473 : // The BaseWithIndexAndDisplacementMatcher canonicalizes the order of
474 : // displacements and scale factors that are used as inputs, so instead of
475 : // enumerating all possible patterns by brute force, checking for node
476 : // clusters using the following templates in the following order suffices to
477 : // find all of the interesting cases (S = index * scale, B = base input, D =
478 : // displacement input):
479 : // (S + (B + D))
480 : // (S + (B + B))
481 : // (S + D)
482 : // (S + B)
483 : // ((S + D) + B)
484 : // ((S + B) + D)
485 : // ((B + D) + B)
486 : // ((B + B) + D)
487 : // (B + D)
488 : // (B + B)
489 13784511 : if (node->InputCount() < 2) return;
490 13784507 : AddMatcher m(node, options & AddressOption::kAllowInputSwap);
491 26901204 : Node* left = m.left().node();
492 710846 : Node* right = m.right().node();
493 12858347 : Node* displacement = nullptr;
494 : Node* base = nullptr;
495 : Node* index = nullptr;
496 : Node* scale_expression = nullptr;
497 : bool power_of_two_plus_one = false;
498 : DisplacementMode displacement_mode = kPositiveDisplacement;
499 : int scale = 0;
500 13784632 : if (m.HasIndexInput() && OwnedByAddressingOperand(left)) {
501 : index = m.IndexInput();
502 : scale = m.scale();
503 : scale_expression = left;
504 355427 : power_of_two_plus_one = m.power_of_two_plus_one();
505 : bool match_found = false;
506 355439 : if (right->opcode() == AddMatcher::kSubOpcode &&
507 12 : OwnedByAddressingOperand(right)) {
508 8 : AddMatcher right_matcher(right);
509 8 : if (right_matcher.right().HasValue()) {
510 : // (S + (B - D))
511 : base = right_matcher.left().node();
512 : displacement = right_matcher.right().node();
513 : displacement_mode = kNegativeDisplacement;
514 : match_found = true;
515 : }
516 : }
517 355427 : if (!match_found) {
518 367465 : if (right->opcode() == AddMatcher::kAddOpcode &&
519 12046 : OwnedByAddressingOperand(right)) {
520 10225 : AddMatcher right_matcher(right);
521 10225 : if (right_matcher.right().HasValue()) {
522 : // (S + (B + D))
523 : base = right_matcher.left().node();
524 : displacement = right_matcher.right().node();
525 : } else {
526 : // (S + (B + B))
527 : base = right;
528 : }
529 345194 : } else if (m.right().HasValue()) {
530 : // (S + D)
531 : displacement = right;
532 : } else {
533 : // (S + B)
534 : base = right;
535 : }
536 : }
537 : } else {
538 : bool match_found = false;
539 13433629 : if (left->opcode() == AddMatcher::kSubOpcode &&
540 4424 : OwnedByAddressingOperand(left)) {
541 2266 : AddMatcher left_matcher(left);
542 0 : Node* left_left = left_matcher.left().node();
543 : Node* left_right = left_matcher.right().node();
544 2266 : if (left_matcher.right().HasValue()) {
545 4 : if (left_matcher.HasIndexInput() && left_left->OwnedBy(left)) {
546 : // ((S - D) + B)
547 : index = left_matcher.IndexInput();
548 : scale = left_matcher.scale();
549 : scale_expression = left_left;
550 0 : power_of_two_plus_one = left_matcher.power_of_two_plus_one();
551 : displacement = left_right;
552 : displacement_mode = kNegativeDisplacement;
553 : base = right;
554 : } else {
555 : // ((B - D) + B)
556 : index = left_left;
557 : displacement = left_right;
558 : displacement_mode = kNegativeDisplacement;
559 : base = right;
560 : }
561 : match_found = true;
562 : }
563 : }
564 13429205 : if (!match_found) {
565 14383565 : if (left->opcode() == AddMatcher::kAddOpcode &&
566 954394 : OwnedByAddressingOperand(left)) {
567 612766 : AddMatcher left_matcher(left);
568 324302 : Node* left_left = left_matcher.left().node();
569 : Node* left_right = left_matcher.right().node();
570 937026 : if (left_matcher.HasIndexInput() && left_left->OwnedBy(left)) {
571 309435 : if (left_matcher.right().HasValue()) {
572 : // ((S + D) + B)
573 : index = left_matcher.IndexInput();
574 : scale = left_matcher.scale();
575 : scale_expression = left_left;
576 297484 : power_of_two_plus_one = left_matcher.power_of_two_plus_one();
577 : displacement = left_right;
578 : base = right;
579 11951 : } else if (m.right().HasValue()) {
580 11239 : if (left->OwnedBy(node)) {
581 : // ((S + B) + D)
582 : index = left_matcher.IndexInput();
583 : scale = left_matcher.scale();
584 : scale_expression = left_left;
585 2799 : power_of_two_plus_one = left_matcher.power_of_two_plus_one();
586 : base = left_right;
587 : displacement = right;
588 : } else {
589 : // (B + D)
590 : base = left;
591 : displacement = right;
592 : }
593 : } else {
594 : // (B + B)
595 : index = left;
596 : base = right;
597 : }
598 : } else {
599 303289 : if (left_matcher.right().HasValue()) {
600 : // ((B + D) + B)
601 : index = left_left;
602 : displacement = left_right;
603 : base = right;
604 62986 : } else if (m.right().HasValue()) {
605 31615 : if (left->OwnedBy(node)) {
606 : // ((B + B) + D)
607 : index = left_left;
608 : base = left_right;
609 : displacement = right;
610 : } else {
611 : // (B + D)
612 : base = left;
613 : displacement = right;
614 : }
615 : } else {
616 : // (B + B)
617 : index = left;
618 : base = right;
619 : }
620 : }
621 : } else {
622 12816405 : if (m.right().HasValue()) {
623 : // (B + D)
624 : base = left;
625 : displacement = right;
626 : } else {
627 : // (B + B)
628 : base = left;
629 : index = right;
630 : }
631 : }
632 : }
633 : }
634 : int64_t value = 0;
635 13784620 : if (displacement != nullptr) {
636 12858347 : switch (displacement->opcode()) {
637 : case IrOpcode::kInt32Constant: {
638 3710873 : value = OpParameter<int32_t>(displacement->op());
639 3710873 : break;
640 : }
641 : case IrOpcode::kInt64Constant: {
642 9147474 : value = OpParameter<int64_t>(displacement->op());
643 9147474 : break;
644 : }
645 : default:
646 0 : UNREACHABLE();
647 : break;
648 : }
649 12858347 : if (value == 0) {
650 : displacement = nullptr;
651 : }
652 : }
653 13784620 : if (power_of_two_plus_one) {
654 52369 : if (base != nullptr) {
655 : // If the scale requires explicitly using the index as the base, but a
656 : // base is already part of the match, then the (1 << N + 1) scale factor
657 : // can't be folded into the match and the entire index * scale
658 : // calculation must be computed separately.
659 : index = scale_expression;
660 : scale = 0;
661 : } else {
662 : base = index;
663 : }
664 : }
665 13784620 : if (!(options & AddressOption::kAllowScale) && scale != 0) {
666 : index = scale_expression;
667 : scale = 0;
668 : }
669 13784620 : base_ = base;
670 13784620 : displacement_ = displacement;
671 13784620 : displacement_mode_ = displacement_mode;
672 13784620 : index_ = index;
673 13784620 : scale_ = scale;
674 13784620 : matches_ = true;
675 : }
676 :
677 1340196 : static bool OwnedByAddressingOperand(Node* node) {
678 5218341 : for (auto use : node->use_edges()) {
679 2897462 : Node* from = use.from();
680 2897462 : switch (from->opcode()) {
681 : case IrOpcode::kLoad:
682 : case IrOpcode::kPoisonedLoad:
683 : case IrOpcode::kProtectedLoad:
684 : case IrOpcode::kInt32Add:
685 : case IrOpcode::kInt64Add:
686 : // Skip addressing uses.
687 : break;
688 : case IrOpcode::kStore:
689 : case IrOpcode::kProtectedStore:
690 : // If the stored value is this node, it is not an addressing use.
691 285605 : if (from->InputAt(2) == node) return false;
692 : // Otherwise it is used as an address and skipped.
693 : break;
694 : default:
695 : // Non-addressing use found.
696 : return false;
697 : }
698 : }
699 980683 : return true;
700 : }
701 : };
702 :
703 : typedef BaseWithIndexAndDisplacementMatcher<Int32AddMatcher>
704 : BaseWithIndexAndDisplacement32Matcher;
705 : typedef BaseWithIndexAndDisplacementMatcher<Int64AddMatcher>
706 : BaseWithIndexAndDisplacement64Matcher;
707 :
708 : struct V8_EXPORT_PRIVATE BranchMatcher : public NON_EXPORTED_BASE(NodeMatcher) {
709 : explicit BranchMatcher(Node* branch);
710 :
711 15 : bool Matched() const { return if_true_ && if_false_; }
712 :
713 : Node* Branch() const { return node(); }
714 : Node* IfTrue() const { return if_true_; }
715 : Node* IfFalse() const { return if_false_; }
716 :
717 : private:
718 : Node* if_true_;
719 : Node* if_false_;
720 : };
721 :
722 : struct V8_EXPORT_PRIVATE DiamondMatcher
723 : : public NON_EXPORTED_BASE(NodeMatcher) {
724 : explicit DiamondMatcher(Node* merge);
725 :
726 4 : bool Matched() const { return branch_; }
727 : bool IfProjectionsAreOwned() const {
728 : return if_true_->OwnedBy(node()) && if_false_->OwnedBy(node());
729 : }
730 :
731 : Node* Branch() const { return branch_; }
732 : Node* IfTrue() const { return if_true_; }
733 : Node* IfFalse() const { return if_false_; }
734 : Node* Merge() const { return node(); }
735 :
736 : Node* TrueInputOf(Node* phi) const {
737 : DCHECK(IrOpcode::IsPhiOpcode(phi->opcode()));
738 : DCHECK_EQ(3, phi->InputCount());
739 : DCHECK_EQ(Merge(), phi->InputAt(2));
740 : return phi->InputAt(if_true_ == Merge()->InputAt(0) ? 0 : 1);
741 : }
742 :
743 : Node* FalseInputOf(Node* phi) const {
744 : DCHECK(IrOpcode::IsPhiOpcode(phi->opcode()));
745 : DCHECK_EQ(3, phi->InputCount());
746 : DCHECK_EQ(Merge(), phi->InputAt(2));
747 : return phi->InputAt(if_true_ == Merge()->InputAt(0) ? 1 : 0);
748 : }
749 :
750 : private:
751 : Node* branch_;
752 : Node* if_true_;
753 : Node* if_false_;
754 : };
755 :
756 : template <class BinopMatcher, IrOpcode::Value expected_opcode>
757 : struct WasmStackCheckMatcher {
758 1301773 : explicit WasmStackCheckMatcher(Node* compare) : compare_(compare) {}
759 :
760 1301780 : bool Matched() {
761 2603560 : if (compare_->opcode() != expected_opcode) return false;
762 382677 : BinopMatcher m(compare_);
763 382683 : return MatchedInternal(m.left(), m.right());
764 : }
765 :
766 : private:
767 382673 : bool MatchedInternal(const typename BinopMatcher::LeftMatcher& l,
768 : const typename BinopMatcher::RightMatcher& r) {
769 : // In wasm, the stack check is performed by loading the value given by
770 : // the address of a field stored in the instance object. That object is
771 : // passed as a parameter.
772 404458 : if (l.IsLoad() && r.IsLoadStackPointer()) {
773 21749 : LoadMatcher<LoadMatcher<NodeMatcher>> mleft(l.node());
774 65252 : if (mleft.object().IsLoad() && mleft.index().Is(0) &&
775 : mleft.object().object().IsParameter()) {
776 21751 : return true;
777 : }
778 : }
779 : return false;
780 : }
781 : Node* compare_;
782 : };
783 :
784 : template <class BinopMatcher, IrOpcode::Value expected_opcode>
785 : struct StackCheckMatcher {
786 : StackCheckMatcher(Isolate* isolate, Node* compare)
787 1761163 : : isolate_(isolate), compare_(compare) {
788 : DCHECK_NOT_NULL(isolate);
789 : }
790 1761152 : bool Matched() {
791 : // TODO(jgruber): Ideally, we could be more flexible here and also match the
792 : // same pattern with switched operands (i.e.: left is LoadStackPointer and
793 : // right is the js_stack_limit load). But to be correct in all cases, we'd
794 : // then have to invert the outcome of the stack check comparison.
795 3522304 : if (compare_->opcode() != expected_opcode) return false;
796 853618 : BinopMatcher m(compare_);
797 853602 : return MatchedInternal(m.left(), m.right());
798 : }
799 :
800 : private:
801 853601 : bool MatchedInternal(const typename BinopMatcher::LeftMatcher& l,
802 : const typename BinopMatcher::RightMatcher& r) {
803 1408048 : if (l.IsLoad() && r.IsLoadStackPointer()) {
804 554419 : LoadMatcher<ExternalReferenceMatcher> mleft(l.node());
805 : ExternalReference js_stack_limit =
806 554417 : ExternalReference::address_of_stack_limit(isolate_);
807 1108828 : if (mleft.object().Is(js_stack_limit) && mleft.index().Is(0)) return true;
808 : }
809 : return false;
810 : }
811 :
812 : Isolate* isolate_;
813 : Node* compare_;
814 : };
815 :
816 : } // namespace compiler
817 : } // namespace internal
818 : } // namespace v8
819 :
820 : #endif // V8_COMPILER_NODE_MATCHERS_H_
|