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 explicit NodeMatcher(Node* node) : node_(node) {} 25 26 Node* node() const { return node_; } 27 const Operator* op() const { return node()->op(); } 28 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 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 : NodeMatcher(node), value_(), has_value_(opcode() == kOpcode) { 56 if (has_value_) { 57 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 has_value_(opcode() == IrOpcode::kInt32Constant) { 79 if (has_value_) { 80 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 : NodeMatcher(node), value_(), has_value_(false) { 88 if (opcode() == IrOpcode::kInt32Constant) { 89 value_ = OpParameter<int32_t>(node); 90 has_value_ = true; 91 } else if (opcode() == IrOpcode::kInt64Constant) { 92 value_ = OpParameter<int64_t>(node); 93 has_value_ = true; 94 } 95 } 96 97 98 template <> 99 inline ValueMatcher<uint64_t, IrOpcode::kInt64Constant>::ValueMatcher( 100 Node* node) 101 : NodeMatcher(node), value_(), has_value_(false) { 102 if (opcode() == IrOpcode::kInt32Constant) { 103 value_ = static_cast<uint32_t>(OpParameter<int32_t>(node)); 104 has_value_ = true; 105 } else if (opcode() == IrOpcode::kInt64Constant) { 106 value_ = static_cast<uint64_t>(OpParameter<int64_t>(node)); 107 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 return this->HasValue() && this->Value() == value; 119 } 120 bool IsInRange(const T& low, const T& high) const { 121 return this->HasValue() && low <= this->Value() && this->Value() <= high; 122 } 123 bool IsMultipleOf(T n) const { 124 return this->HasValue() && (this->Value() % n) == 0; 125 } 126 bool IsPowerOf2() const { 127 return this->HasValue() && this->Value() > 0 && 128 (this->Value() & (this->Value() - 1)) == 0; 129 } 130 bool IsNegativePowerOf2() const { 131 return this->HasValue() && this->Value() < 0 && 132 (-this->Value() & (-this->Value() - 1)) == 0; 133 } 134 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 return this->HasValue() && this->Value() == value; 157 } 158 bool IsInRange(const T& low, const T& high) const { 159 return this->HasValue() && low <= this->Value() && this->Value() <= high; 160 } 161 bool IsMinusZero() const { 162 return this->Is(0.0) && std::signbit(this->Value()); 163 } 164 bool IsNegative() const { return this->HasValue() && this->Value() < 0.0; } 165 bool IsNaN() const { return this->HasValue() && std::isnan(this->Value()); } 166 bool IsZero() const { return this->Is(0.0) && !std::signbit(this->Value()); } 167 bool IsNormal() const { 168 return this->HasValue() && std::isnormal(this->Value()); 169 } 170 bool IsInteger() const { 171 return this->HasValue() && std::nearbyint(this->Value()) == this->Value(); 172 } 173 bool IsPositiveOrNegativePowerOf2() const { 174 if (!this->HasValue() || (this->Value() == 0.0)) { 175 return false; 176 } 177 Double value = Double(this->Value()); 178 return !value.IsInfinite() && 179 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 bool Is(Handle<HeapObject> const& value) const { 195 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 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 explicit LoadMatcher(Node* node) 216 : 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 explicit BinopMatcher(Node* node) 235 : NodeMatcher(node), left_(InputAt(0)), right_(InputAt(1)) { 236 if (HasProperty(Operator::kCommutative)) PutConstantOnRight(); 237 } 238 BinopMatcher(Node* node, bool allow_input_swap) 239 : NodeMatcher(node), left_(InputAt(0)), right_(InputAt(1)) { 240 if (allow_input_swap) PutConstantOnRight(); 241 } 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 bool IsFoldable() const { return left().HasValue() && right().HasValue(); } 250 bool LeftEqualsRight() const { return left().node() == right().node(); } 251 252 protected: 253 void SwapInputs() { 254 std::swap(left_, right_); 255 node()->ReplaceInput(0, left().node()); 256 node()->ReplaceInput(1, right().node()); 257 } 258 259 private: 260 void PutConstantOnRight() { 261 if (left().HasValue() && !right().HasValue()) { 262 SwapInputs(); 263 } 264 } 265 266 Left left_; 267 Right right_; 268 }; 269 270 typedef BinopMatcher<Int32Matcher, Int32Matcher> Int32BinopMatcher; 271 typedef BinopMatcher<Uint32Matcher, Uint32Matcher> Uint32BinopMatcher; 272 typedef BinopMatcher<Int64Matcher, Int64Matcher> Int64BinopMatcher; 273 typedef BinopMatcher<Uint64Matcher, Uint64Matcher> Uint64BinopMatcher; 274 typedef BinopMatcher<IntPtrMatcher, IntPtrMatcher> IntPtrBinopMatcher; 275 typedef BinopMatcher<UintPtrMatcher, UintPtrMatcher> UintPtrBinopMatcher; 276 typedef BinopMatcher<Float32Matcher, Float32Matcher> Float32BinopMatcher; 277 typedef BinopMatcher<Float64Matcher, Float64Matcher> Float64BinopMatcher; 278 typedef BinopMatcher<NumberMatcher, NumberMatcher> NumberBinopMatcher; 279 typedef BinopMatcher<HeapObjectMatcher, HeapObjectMatcher> 280 HeapObjectBinopMatcher; 281 282 template <class BinopMatcher, IrOpcode::Value kMulOpcode, 283 IrOpcode::Value kShiftOpcode> 284 struct ScaleMatcher { 285 explicit ScaleMatcher(Node* node, bool allow_power_of_two_plus_one = false) 286 : scale_(-1), power_of_two_plus_one_(false) { 287 if (node->InputCount() < 2) return; 288 BinopMatcher m(node); 289 if (node->opcode() == kShiftOpcode) { 290 if (m.right().HasValue()) { 291 typename BinopMatcher::RightMatcher::ValueType value = 292 m.right().Value(); 293 if (value >= 0 && value <= 3) { 294 scale_ = static_cast<int>(value); 295 } 296 } 297 } else if (node->opcode() == kMulOpcode) { 298 if (m.right().HasValue()) { 299 typename BinopMatcher::RightMatcher::ValueType value = 300 m.right().Value(); 301 if (value == 1) { 302 scale_ = 0; 303 } else if (value == 2) { 304 scale_ = 1; 305 } else if (value == 4) { 306 scale_ = 2; 307 } else if (value == 8) { 308 scale_ = 3; 309 } else if (allow_power_of_two_plus_one) { 310 if (value == 3) { 311 scale_ = 1; 312 power_of_two_plus_one_ = true; 313 } else if (value == 5) { 314 scale_ = 2; 315 power_of_two_plus_one_ = true; 316 } else if (value == 9) { 317 scale_ = 3; 318 power_of_two_plus_one_ = true; 319 } 320 } 321 } 322 } 323 } 324 325 bool matches() const { return scale_ != -1; } 326 int scale() const { return scale_; } 327 bool power_of_two_plus_one() const { return power_of_two_plus_one_; } 328 329 private: 330 int scale_; 331 bool power_of_two_plus_one_; 332 }; 333 334 typedef ScaleMatcher<Int32BinopMatcher, IrOpcode::kInt32Mul, 335 IrOpcode::kWord32Shl> Int32ScaleMatcher; 336 typedef ScaleMatcher<Int64BinopMatcher, IrOpcode::kInt64Mul, 337 IrOpcode::kWord64Shl> Int64ScaleMatcher; 338 339 template <class BinopMatcher, IrOpcode::Value AddOpcode, 340 IrOpcode::Value SubOpcode, IrOpcode::Value kMulOpcode, 341 IrOpcode::Value kShiftOpcode> 342 struct AddMatcher : public BinopMatcher { 343 static const IrOpcode::Value kAddOpcode = AddOpcode; 344 static const IrOpcode::Value kSubOpcode = SubOpcode; 345 typedef ScaleMatcher<BinopMatcher, kMulOpcode, kShiftOpcode> Matcher; 346 347 AddMatcher(Node* node, bool allow_input_swap) 348 : BinopMatcher(node, allow_input_swap), 349 scale_(-1), 350 power_of_two_plus_one_(false) { 351 Initialize(node, allow_input_swap); 352 } 353 explicit AddMatcher(Node* node) 354 : BinopMatcher(node, node->op()->HasProperty(Operator::kCommutative)), 355 scale_(-1), 356 power_of_two_plus_one_(false) { 357 Initialize(node, node->op()->HasProperty(Operator::kCommutative)); 358 } 359 360 bool HasIndexInput() const { return scale_ != -1; } 361 Node* IndexInput() const { 362 DCHECK(HasIndexInput()); 363 return this->left().node()->InputAt(0); 364 } 365 int scale() const { 366 DCHECK(HasIndexInput()); 367 return scale_; 368 } 369 bool power_of_two_plus_one() const { return power_of_two_plus_one_; } 370 371 private: 372 void Initialize(Node* node, bool allow_input_swap) { 373 Matcher left_matcher(this->left().node(), true); 374 if (left_matcher.matches()) { 375 scale_ = left_matcher.scale(); 376 power_of_two_plus_one_ = left_matcher.power_of_two_plus_one(); 377 return; 378 } 379 380 if (!allow_input_swap) { 381 return; 382 } 383 384 Matcher right_matcher(this->right().node(), true); 385 if (right_matcher.matches()) { 386 scale_ = right_matcher.scale(); 387 power_of_two_plus_one_ = right_matcher.power_of_two_plus_one(); 388 this->SwapInputs(); 389 return; 390 } 391 392 if (this->right().opcode() == kAddOpcode && 393 this->left().opcode() != kAddOpcode) { 394 this->SwapInputs(); 395 } else if (this->right().opcode() == kSubOpcode && 396 this->left().opcode() != kSubOpcode) { 397 this->SwapInputs(); 398 } 399 } 400 401 int scale_; 402 bool power_of_two_plus_one_; 403 }; 404 405 typedef AddMatcher<Int32BinopMatcher, IrOpcode::kInt32Add, IrOpcode::kInt32Sub, 406 IrOpcode::kInt32Mul, IrOpcode::kWord32Shl> 407 Int32AddMatcher; 408 typedef AddMatcher<Int64BinopMatcher, IrOpcode::kInt64Add, IrOpcode::kInt64Sub, 409 IrOpcode::kInt64Mul, IrOpcode::kWord64Shl> 410 Int64AddMatcher; 411 412 enum DisplacementMode { kPositiveDisplacement, kNegativeDisplacement }; 413 414 enum class AddressOption : uint8_t { 415 kAllowNone = 0u, 416 kAllowInputSwap = 1u << 0, 417 kAllowScale = 1u << 1, 418 kAllowAll = kAllowInputSwap | kAllowScale 419 }; 420 421 typedef base::Flags<AddressOption, uint8_t> AddressOptions; 422 DEFINE_OPERATORS_FOR_FLAGS(AddressOptions); 423 424 template <class AddMatcher> 425 struct BaseWithIndexAndDisplacementMatcher { 426 BaseWithIndexAndDisplacementMatcher(Node* node, AddressOptions options) 427 : matches_(false), 428 index_(nullptr), 429 scale_(0), 430 base_(nullptr), 431 displacement_(nullptr), 432 displacement_mode_(kPositiveDisplacement) { 433 Initialize(node, options); 434 } 435 436 explicit BaseWithIndexAndDisplacementMatcher(Node* node) 437 : matches_(false), 438 index_(nullptr), 439 scale_(0), 440 base_(nullptr), 441 displacement_(nullptr), 442 displacement_mode_(kPositiveDisplacement) { 443 Initialize(node, AddressOption::kAllowScale | 444 (node->op()->HasProperty(Operator::kCommutative) 445 ? AddressOption::kAllowInputSwap 446 : AddressOption::kAllowNone)); 447 } 448 449 bool matches() const { return matches_; } 450 Node* index() const { return index_; } 451 int scale() const { return scale_; } 452 Node* base() const { return base_; } 453 Node* displacement() const { return displacement_; } 454 DisplacementMode displacement_mode() const { return displacement_mode_; } 455 456 private: 457 bool matches_; 458 Node* index_; 459 int scale_; 460 Node* base_; 461 Node* displacement_; 462 DisplacementMode displacement_mode_; 463 464 void Initialize(Node* node, AddressOptions options) { 465 // The BaseWithIndexAndDisplacementMatcher canonicalizes the order of 466 // displacements and scale factors that are used as inputs, so instead of 467 // enumerating all possible patterns by brute force, checking for node 468 // clusters using the following templates in the following order suffices to 469 // find all of the interesting cases (S = index * scale, B = base input, D = 470 // displacement input): 471 // (S + (B + D)) 472 // (S + (B + B)) 473 // (S + D) 474 // (S + B) 475 // ((S + D) + B) 476 // ((S + B) + D) 477 // ((B + D) + B) 478 // ((B + B) + D) 479 // (B + D) 480 // (B + B) 481 if (node->InputCount() < 2) return; 482 AddMatcher m(node, options & AddressOption::kAllowInputSwap); 483 Node* left = m.left().node(); 484 Node* right = m.right().node(); 485 Node* displacement = nullptr; 486 Node* base = nullptr; 487 Node* index = nullptr; 488 Node* scale_expression = nullptr; 489 bool power_of_two_plus_one = false; 490 DisplacementMode displacement_mode = kPositiveDisplacement; 491 int scale = 0; 492 if (m.HasIndexInput() && left->OwnedBy(node)) { 493 index = m.IndexInput(); 494 scale = m.scale(); 495 scale_expression = left; 496 power_of_two_plus_one = m.power_of_two_plus_one(); 497 bool match_found = false; 498 if (right->opcode() == AddMatcher::kSubOpcode && right->OwnedBy(node)) { 499 AddMatcher right_matcher(right); 500 if (right_matcher.right().HasValue()) { 501 // (S + (B - D)) 502 base = right_matcher.left().node(); 503 displacement = right_matcher.right().node(); 504 displacement_mode = kNegativeDisplacement; 505 match_found = true; 506 } 507 } 508 if (!match_found) { 509 if (right->opcode() == AddMatcher::kAddOpcode && right->OwnedBy(node)) { 510 AddMatcher right_matcher(right); 511 if (right_matcher.right().HasValue()) { 512 // (S + (B + D)) 513 base = right_matcher.left().node(); 514 displacement = right_matcher.right().node(); 515 } else { 516 // (S + (B + B)) 517 base = right; 518 } 519 } else if (m.right().HasValue()) { 520 // (S + D) 521 displacement = right; 522 } else { 523 // (S + B) 524 base = right; 525 } 526 } 527 } else { 528 bool match_found = false; 529 if (left->opcode() == AddMatcher::kSubOpcode && left->OwnedBy(node)) { 530 AddMatcher left_matcher(left); 531 Node* left_left = left_matcher.left().node(); 532 Node* left_right = left_matcher.right().node(); 533 if (left_matcher.right().HasValue()) { 534 if (left_matcher.HasIndexInput() && left_left->OwnedBy(left)) { 535 // ((S - D) + B) 536 index = left_matcher.IndexInput(); 537 scale = left_matcher.scale(); 538 scale_expression = left_left; 539 power_of_two_plus_one = left_matcher.power_of_two_plus_one(); 540 displacement = left_right; 541 displacement_mode = kNegativeDisplacement; 542 base = right; 543 } else { 544 // ((B - D) + B) 545 index = left_left; 546 displacement = left_right; 547 displacement_mode = kNegativeDisplacement; 548 base = right; 549 } 550 match_found = true; 551 } 552 } 553 if (!match_found) { 554 if (left->opcode() == AddMatcher::kAddOpcode && left->OwnedBy(node)) { 555 AddMatcher left_matcher(left); 556 Node* left_left = left_matcher.left().node(); 557 Node* left_right = left_matcher.right().node(); 558 if (left_matcher.HasIndexInput() && left_left->OwnedBy(left)) { 559 if (left_matcher.right().HasValue()) { 560 // ((S + D) + B) 561 index = left_matcher.IndexInput(); 562 scale = left_matcher.scale(); 563 scale_expression = left_left; 564 power_of_two_plus_one = left_matcher.power_of_two_plus_one(); 565 displacement = left_right; 566 base = right; 567 } else if (m.right().HasValue()) { 568 // ((S + B) + D) 569 index = left_matcher.IndexInput(); 570 scale = left_matcher.scale(); 571 scale_expression = left_left; 572 power_of_two_plus_one = left_matcher.power_of_two_plus_one(); 573 base = left_right; 574 displacement = right; 575 } else { 576 // (B + B) 577 index = left; 578 base = right; 579 } 580 } else { 581 if (left_matcher.right().HasValue()) { 582 // ((B + D) + B) 583 index = left_left; 584 displacement = left_right; 585 base = right; 586 } else if (m.right().HasValue()) { 587 // ((B + B) + D) 588 index = left_left; 589 base = left_right; 590 displacement = right; 591 } else { 592 // (B + B) 593 index = left; 594 base = right; 595 } 596 } 597 } else { 598 if (m.right().HasValue()) { 599 // (B + D) 600 base = left; 601 displacement = right; 602 } else { 603 // (B + B) 604 base = left; 605 index = right; 606 } 607 } 608 } 609 } 610 int64_t value = 0; 611 if (displacement != nullptr) { 612 switch (displacement->opcode()) { 613 case IrOpcode::kInt32Constant: { 614 value = OpParameter<int32_t>(displacement); 615 break; 616 } 617 case IrOpcode::kInt64Constant: { 618 value = OpParameter<int64_t>(displacement); 619 break; 620 } 621 default: 622 UNREACHABLE(); 623 break; 624 } 625 if (value == 0) { 626 displacement = nullptr; 627 } 628 } 629 if (power_of_two_plus_one) { 630 if (base != nullptr) { 631 // If the scale requires explicitly using the index as the base, but a 632 // base is already part of the match, then the (1 << N + 1) scale factor 633 // can't be folded into the match and the entire index * scale 634 // calculation must be computed separately. 635 index = scale_expression; 636 scale = 0; 637 } else { 638 base = index; 639 } 640 } 641 if (!(options & AddressOption::kAllowScale) && scale != 0) { 642 index = scale_expression; 643 scale = 0; 644 } 645 base_ = base; 646 displacement_ = displacement; 647 displacement_mode_ = displacement_mode; 648 index_ = index; 649 scale_ = scale; 650 matches_ = true; 651 } 652 }; 653 654 typedef BaseWithIndexAndDisplacementMatcher<Int32AddMatcher> 655 BaseWithIndexAndDisplacement32Matcher; 656 typedef BaseWithIndexAndDisplacementMatcher<Int64AddMatcher> 657 BaseWithIndexAndDisplacement64Matcher; 658 659 struct V8_EXPORT_PRIVATE BranchMatcher : public NON_EXPORTED_BASE(NodeMatcher) { 660 explicit BranchMatcher(Node* branch); 661 662 bool Matched() const { return if_true_ && if_false_; } 663 664 Node* Branch() const { return node(); } 665 Node* IfTrue() const { return if_true_; } 666 Node* IfFalse() const { return if_false_; } 667 668 private: 669 Node* if_true_; 670 Node* if_false_; 671 }; 672 673 struct V8_EXPORT_PRIVATE DiamondMatcher 674 : public NON_EXPORTED_BASE(NodeMatcher) { 675 explicit DiamondMatcher(Node* merge); 676 677 bool Matched() const { return branch_; } 678 bool IfProjectionsAreOwned() const { 679 return if_true_->OwnedBy(node()) && if_false_->OwnedBy(node()); 680 } 681 682 Node* Branch() const { return branch_; } 683 Node* IfTrue() const { return if_true_; } 684 Node* IfFalse() const { return if_false_; } 685 Node* Merge() const { return node(); } 686 687 Node* TrueInputOf(Node* phi) const { 688 DCHECK(IrOpcode::IsPhiOpcode(phi->opcode())); 689 DCHECK_EQ(3, phi->InputCount()); 690 DCHECK_EQ(Merge(), phi->InputAt(2)); 691 return phi->InputAt(if_true_ == Merge()->InputAt(0) ? 0 : 1); 692 } 693 694 Node* FalseInputOf(Node* phi) const { 695 DCHECK(IrOpcode::IsPhiOpcode(phi->opcode())); 696 DCHECK_EQ(3, phi->InputCount()); 697 DCHECK_EQ(Merge(), phi->InputAt(2)); 698 return phi->InputAt(if_true_ == Merge()->InputAt(0) ? 1 : 0); 699 } 700 701 private: 702 Node* branch_; 703 Node* if_true_; 704 Node* if_false_; 705 }; 706 707 } // namespace compiler 708 } // namespace internal 709 } // namespace v8 710 711 #endif // V8_COMPILER_NODE_MATCHERS_H_ 712