| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/compiler/machine-operator-reducer.h" | 5 #include "src/compiler/machine-operator-reducer.h" |
| 6 | 6 |
| 7 #include "src/base/bits.h" | 7 #include "src/base/bits.h" |
| 8 #include "src/base/division-by-constant.h" | 8 #include "src/base/division-by-constant.h" |
| 9 #include "src/codegen.h" | 9 #include "src/codegen.h" |
| 10 #include "src/compiler/generic-node-inl.h" | 10 #include "src/compiler/generic-node-inl.h" |
| (...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 235 } | 235 } |
| 236 case IrOpcode::kWord32Ror: { | 236 case IrOpcode::kWord32Ror: { |
| 237 Int32BinopMatcher m(node); | 237 Int32BinopMatcher m(node); |
| 238 if (m.right().Is(0)) return Replace(m.left().node()); // x ror 0 => x | 238 if (m.right().Is(0)) return Replace(m.left().node()); // x ror 0 => x |
| 239 if (m.IsFoldable()) { // K ror K => K | 239 if (m.IsFoldable()) { // K ror K => K |
| 240 return ReplaceInt32( | 240 return ReplaceInt32( |
| 241 base::bits::RotateRight32(m.left().Value(), m.right().Value())); | 241 base::bits::RotateRight32(m.left().Value(), m.right().Value())); |
| 242 } | 242 } |
| 243 break; | 243 break; |
| 244 } | 244 } |
| 245 case IrOpcode::kWord32Equal: { | 245 case IrOpcode::kWord32Equal: |
| 246 Int32BinopMatcher m(node); | 246 return ReduceWord32Equal(node); |
| 247 if (m.IsFoldable()) { // K == K => K | 247 case IrOpcode::kWord64Equal: |
| 248 return ReplaceBool(m.left().Value() == m.right().Value()); | 248 return ReduceWord64Equal(node); |
| 249 } | |
| 250 if (m.left().IsInt32Sub() && m.right().Is(0)) { // x - y == 0 => x == y | |
| 251 Int32BinopMatcher msub(m.left().node()); | |
| 252 node->ReplaceInput(0, msub.left().node()); | |
| 253 node->ReplaceInput(1, msub.right().node()); | |
| 254 return Changed(node); | |
| 255 } | |
| 256 // TODO(turbofan): fold HeapConstant, ExternalReference, pointer compares | |
| 257 if (m.LeftEqualsRight()) return ReplaceBool(true); // x == x => true | |
| 258 break; | |
| 259 } | |
| 260 case IrOpcode::kWord64Equal: { | |
| 261 Int64BinopMatcher m(node); | |
| 262 if (m.IsFoldable()) { // K == K => K | |
| 263 return ReplaceBool(m.left().Value() == m.right().Value()); | |
| 264 } | |
| 265 if (m.left().IsInt64Sub() && m.right().Is(0)) { // x - y == 0 => x == y | |
| 266 Int64BinopMatcher msub(m.left().node()); | |
| 267 node->ReplaceInput(0, msub.left().node()); | |
| 268 node->ReplaceInput(1, msub.right().node()); | |
| 269 return Changed(node); | |
| 270 } | |
| 271 // TODO(turbofan): fold HeapConstant, ExternalReference, pointer compares | |
| 272 if (m.LeftEqualsRight()) return ReplaceBool(true); // x == x => true | |
| 273 break; | |
| 274 } | |
| 275 case IrOpcode::kInt32Add: { | 249 case IrOpcode::kInt32Add: { |
| 276 Int32BinopMatcher m(node); | 250 Int32BinopMatcher m(node); |
| 277 if (m.right().Is(0)) return Replace(m.left().node()); // x + 0 => x | 251 if (m.right().Is(0)) return Replace(m.left().node()); // x + 0 => x |
| 278 if (m.IsFoldable()) { // K + K => K | 252 if (m.IsFoldable()) { // K + K => K |
| 279 return ReplaceInt32(static_cast<uint32_t>(m.left().Value()) + | 253 return ReplaceInt32(static_cast<uint32_t>(m.left().Value()) + |
| 280 static_cast<uint32_t>(m.right().Value())); | 254 static_cast<uint32_t>(m.right().Value())); |
| 281 } | 255 } |
| 282 break; | 256 break; |
| 283 } | 257 } |
| 284 case IrOpcode::kInt32Sub: { | 258 case IrOpcode::kInt32Sub: { |
| (...skipping 27 matching lines...) Expand all Loading... |
| 312 break; | 286 break; |
| 313 } | 287 } |
| 314 case IrOpcode::kInt32Div: | 288 case IrOpcode::kInt32Div: |
| 315 return ReduceInt32Div(node); | 289 return ReduceInt32Div(node); |
| 316 case IrOpcode::kUint32Div: | 290 case IrOpcode::kUint32Div: |
| 317 return ReduceUint32Div(node); | 291 return ReduceUint32Div(node); |
| 318 case IrOpcode::kInt32Mod: | 292 case IrOpcode::kInt32Mod: |
| 319 return ReduceInt32Mod(node); | 293 return ReduceInt32Mod(node); |
| 320 case IrOpcode::kUint32Mod: | 294 case IrOpcode::kUint32Mod: |
| 321 return ReduceUint32Mod(node); | 295 return ReduceUint32Mod(node); |
| 322 case IrOpcode::kInt32LessThan: { | 296 case IrOpcode::kInt32LessThan: |
| 323 Int32BinopMatcher m(node); | 297 return ReduceInt32LessThan(node); |
| 324 if (m.IsFoldable()) { // K < K => K | 298 case IrOpcode::kInt32LessThanOrEqual: |
| 325 return ReplaceBool(m.left().Value() < m.right().Value()); | 299 return ReduceInt32LessThanOrEqual(node); |
| 326 } | 300 case IrOpcode::kUint32LessThan: |
| 327 if (m.left().IsInt32Sub() && m.right().Is(0)) { // x - y < 0 => x < y | 301 return ReduceUint32LessThan(node); |
| 328 Int32BinopMatcher msub(m.left().node()); | 302 case IrOpcode::kUint32LessThanOrEqual: |
| 329 node->ReplaceInput(0, msub.left().node()); | 303 return ReduceUint32LessThanOrEqual(node); |
| 330 node->ReplaceInput(1, msub.right().node()); | |
| 331 return Changed(node); | |
| 332 } | |
| 333 if (m.left().Is(0) && m.right().IsInt32Sub()) { // 0 < x - y => y < x | |
| 334 Int32BinopMatcher msub(m.right().node()); | |
| 335 node->ReplaceInput(0, msub.right().node()); | |
| 336 node->ReplaceInput(1, msub.left().node()); | |
| 337 return Changed(node); | |
| 338 } | |
| 339 if (m.LeftEqualsRight()) return ReplaceBool(false); // x < x => false | |
| 340 break; | |
| 341 } | |
| 342 case IrOpcode::kInt32LessThanOrEqual: { | |
| 343 Int32BinopMatcher m(node); | |
| 344 if (m.IsFoldable()) { // K <= K => K | |
| 345 return ReplaceBool(m.left().Value() <= m.right().Value()); | |
| 346 } | |
| 347 if (m.left().IsInt32Sub() && m.right().Is(0)) { // x - y <= 0 => x <= y | |
| 348 Int32BinopMatcher msub(m.left().node()); | |
| 349 node->ReplaceInput(0, msub.left().node()); | |
| 350 node->ReplaceInput(1, msub.right().node()); | |
| 351 return Changed(node); | |
| 352 } | |
| 353 if (m.left().Is(0) && m.right().IsInt32Sub()) { // 0 <= x - y => y <= x | |
| 354 Int32BinopMatcher msub(m.right().node()); | |
| 355 node->ReplaceInput(0, msub.right().node()); | |
| 356 node->ReplaceInput(1, msub.left().node()); | |
| 357 return Changed(node); | |
| 358 } | |
| 359 if (m.LeftEqualsRight()) return ReplaceBool(true); // x <= x => true | |
| 360 break; | |
| 361 } | |
| 362 case IrOpcode::kUint32LessThan: { | |
| 363 Uint32BinopMatcher m(node); | |
| 364 if (m.left().Is(kMaxUInt32)) return ReplaceBool(false); // M < x => false | |
| 365 if (m.right().Is(0)) return ReplaceBool(false); // x < 0 => false | |
| 366 if (m.IsFoldable()) { // K < K => K | |
| 367 return ReplaceBool(m.left().Value() < m.right().Value()); | |
| 368 } | |
| 369 if (m.LeftEqualsRight()) return ReplaceBool(false); // x < x => false | |
| 370 if (m.left().IsWord32Sar() && m.right().HasValue()) { | |
| 371 Int32BinopMatcher mleft(m.left().node()); | |
| 372 if (mleft.right().HasValue()) { | |
| 373 // (x >> K) < C => x < (C << K) | (2^K - 1) | |
| 374 // when C < (M >> K) | |
| 375 const uint32_t c = m.right().Value(); | |
| 376 const uint32_t k = mleft.right().Value() & 0x1f; | |
| 377 if (c < static_cast<uint32_t>(kMaxInt >> k)) { | |
| 378 node->ReplaceInput(0, mleft.left().node()); | |
| 379 node->ReplaceInput(1, Uint32Constant((c << k) | ((1 << k) - 1))); | |
| 380 return Changed(node); | |
| 381 } | |
| 382 } | |
| 383 } | |
| 384 break; | |
| 385 } | |
| 386 case IrOpcode::kUint32LessThanOrEqual: { | |
| 387 Uint32BinopMatcher m(node); | |
| 388 if (m.left().Is(0)) return ReplaceBool(true); // 0 <= x => true | |
| 389 if (m.right().Is(kMaxUInt32)) return ReplaceBool(true); // x <= M => true | |
| 390 if (m.IsFoldable()) { // K <= K => K | |
| 391 return ReplaceBool(m.left().Value() <= m.right().Value()); | |
| 392 } | |
| 393 if (m.LeftEqualsRight()) return ReplaceBool(true); // x <= x => true | |
| 394 break; | |
| 395 } | |
| 396 case IrOpcode::kFloat64Add: { | 304 case IrOpcode::kFloat64Add: { |
| 397 Float64BinopMatcher m(node); | 305 Float64BinopMatcher m(node); |
| 398 if (m.right().IsNaN()) { // x + NaN => NaN | 306 if (m.right().IsNaN()) { // x + NaN => NaN |
| 399 return Replace(m.right().node()); | 307 return Replace(m.right().node()); |
| 400 } | 308 } |
| 401 if (m.IsFoldable()) { // K + K => K | 309 if (m.IsFoldable()) { // K + K => K |
| 402 return ReplaceFloat64(m.left().Value() + m.right().Value()); | 310 return ReplaceFloat64(m.left().Value() + m.right().Value()); |
| 403 } | 311 } |
| 404 break; | 312 break; |
| 405 } | 313 } |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 531 } | 439 } |
| 532 break; | 440 break; |
| 533 } | 441 } |
| 534 default: | 442 default: |
| 535 break; | 443 break; |
| 536 } | 444 } |
| 537 return NoChange(); | 445 return NoChange(); |
| 538 } | 446 } |
| 539 | 447 |
| 540 | 448 |
| 449 static bool MatchBinopConstant(Node** left, int32_t* right) { |
| 450 Int32BinopMatcher m(*left); |
| 451 if (!m.right().HasValue()) return false; |
| 452 *right = m.right().Value(); |
| 453 *left = m.left().node(); |
| 454 return true; |
| 455 } |
| 456 |
| 457 |
| 458 Reduction MachineOperatorReducer::ReduceCompare32(Node* compare) { |
| 459 Int32BinopMatcher m(compare); |
| 460 bool is_left_constant = false; |
| 461 Node* node = NULL; |
| 462 int32_t value = 0; |
| 463 if (m.left().HasValue()) { |
| 464 value = m.left().Value(); |
| 465 node = m.right().node(); |
| 466 is_left_constant = true; |
| 467 } else if (m.right().HasValue()) { |
| 468 value = m.right().Value(); |
| 469 node = m.left().node(); |
| 470 is_left_constant = false; |
| 471 } else { |
| 472 // No constant to fold. |
| 473 return NoChange(); |
| 474 } |
| 475 bool done; |
| 476 do { |
| 477 done = true; |
| 478 int32_t temp = 0; |
| 479 switch (node->opcode()) { |
| 480 case IrOpcode::kInt32Add: |
| 481 if (MatchBinopConstant(&node, &temp)) { |
| 482 value -= temp; |
| 483 done = false; |
| 484 } |
| 485 break; |
| 486 case IrOpcode::kInt32Sub: |
| 487 if (MatchBinopConstant(&node, &temp)) { |
| 488 value += temp; |
| 489 done = false; |
| 490 } |
| 491 break; |
| 492 default: |
| 493 break; |
| 494 } |
| 495 } while (!done); |
| 496 // No change occured. |
| 497 if (node == m.right().node() || node == m.left().node()) { |
| 498 return NoChange(); |
| 499 } |
| 500 int node_input = 0; |
| 501 int const_input = 1; |
| 502 if (is_left_constant) { |
| 503 std::swap(node_input, const_input); |
| 504 } |
| 505 compare->ReplaceInput(node_input, node); |
| 506 compare->ReplaceInput(const_input, Int32Constant(value)); |
| 507 return Changed(compare); |
| 508 } |
| 509 |
| 510 |
| 511 Reduction MachineOperatorReducer::ReduceWord32Equal(Node* node) { |
| 512 Int32BinopMatcher m(node); |
| 513 if (m.IsFoldable()) { // K == K => K |
| 514 return ReplaceBool(m.left().Value() == m.right().Value()); |
| 515 } |
| 516 if (m.left().IsInt32Sub() && m.right().Is(0)) { // x - y == 0 => x == y |
| 517 Int32BinopMatcher msub(m.left().node()); |
| 518 node->ReplaceInput(0, msub.left().node()); |
| 519 node->ReplaceInput(1, msub.right().node()); |
| 520 return Changed(node); |
| 521 } |
| 522 // TODO(turbofan): fold HeapConstant, ExternalReference, pointer compares |
| 523 if (m.LeftEqualsRight()) return ReplaceBool(true); // x == x => true |
| 524 return ReduceCompare32(node); |
| 525 } |
| 526 |
| 527 |
| 528 Reduction MachineOperatorReducer::ReduceWord64Equal(Node* node) { |
| 529 Int64BinopMatcher m(node); |
| 530 if (m.IsFoldable()) { // K == K => K |
| 531 return ReplaceBool(m.left().Value() == m.right().Value()); |
| 532 } |
| 533 if (m.left().IsInt64Sub() && m.right().Is(0)) { // x - y == 0 => x == y |
| 534 Int64BinopMatcher msub(m.left().node()); |
| 535 node->ReplaceInput(0, msub.left().node()); |
| 536 node->ReplaceInput(1, msub.right().node()); |
| 537 return Changed(node); |
| 538 } |
| 539 // TODO(turbofan): fold HeapConstant, ExternalReference, pointer compares |
| 540 if (m.LeftEqualsRight()) return ReplaceBool(true); // x == x => true |
| 541 // TODO(turbofan): add ReduceComputableCompare64? |
| 542 return NoChange(); |
| 543 } |
| 544 |
| 545 |
| 546 Reduction MachineOperatorReducer::ReduceInt32LessThan(Node* node) { |
| 547 Int32BinopMatcher m(node); |
| 548 if (m.IsFoldable()) { // K < K => K |
| 549 return ReplaceBool(m.left().Value() < m.right().Value()); |
| 550 } |
| 551 if (m.left().IsInt32Sub() && m.right().Is(0)) { // x - y < 0 => x < y |
| 552 Int32BinopMatcher msub(m.left().node()); |
| 553 node->ReplaceInput(0, msub.left().node()); |
| 554 node->ReplaceInput(1, msub.right().node()); |
| 555 return Changed(node); |
| 556 } |
| 557 if (m.left().Is(0) && m.right().IsInt32Sub()) { // 0 < x - y => y < x |
| 558 Int32BinopMatcher msub(m.right().node()); |
| 559 node->ReplaceInput(0, msub.right().node()); |
| 560 node->ReplaceInput(1, msub.left().node()); |
| 561 return Changed(node); |
| 562 } |
| 563 if (m.LeftEqualsRight()) return ReplaceBool(false); // x < x => false |
| 564 return ReduceCompare32(node); |
| 565 } |
| 566 |
| 567 |
| 568 Reduction MachineOperatorReducer::ReduceInt32LessThanOrEqual(Node* node) { |
| 569 Int32BinopMatcher m(node); |
| 570 if (m.IsFoldable()) { // K <= K => K |
| 571 return ReplaceBool(m.left().Value() <= m.right().Value()); |
| 572 } |
| 573 if (m.left().IsInt32Sub() && m.right().Is(0)) { // x - y <= 0 => x <= y |
| 574 Int32BinopMatcher msub(m.left().node()); |
| 575 node->ReplaceInput(0, msub.left().node()); |
| 576 node->ReplaceInput(1, msub.right().node()); |
| 577 return Changed(node); |
| 578 } |
| 579 if (m.left().Is(0) && m.right().IsInt32Sub()) { // 0 <= x - y => y <= x |
| 580 Int32BinopMatcher msub(m.right().node()); |
| 581 node->ReplaceInput(0, msub.right().node()); |
| 582 node->ReplaceInput(1, msub.left().node()); |
| 583 return Changed(node); |
| 584 } |
| 585 if (m.LeftEqualsRight()) return ReplaceBool(true); // x <= x => true |
| 586 return ReduceCompare32(node); |
| 587 } |
| 588 |
| 589 |
| 590 Reduction MachineOperatorReducer::ReduceUint32LessThan(Node* node) { |
| 591 Uint32BinopMatcher m(node); |
| 592 if (m.left().Is(kMaxUInt32)) return ReplaceBool(false); // M < x => false |
| 593 if (m.right().Is(0)) return ReplaceBool(false); // x < 0 => false |
| 594 if (m.IsFoldable()) { // K < K => K |
| 595 return ReplaceBool(m.left().Value() < m.right().Value()); |
| 596 } |
| 597 if (m.LeftEqualsRight()) return ReplaceBool(false); // x < x => false |
| 598 if (m.left().IsWord32Sar() && m.right().HasValue()) { |
| 599 Int32BinopMatcher mleft(m.left().node()); |
| 600 if (mleft.right().HasValue()) { |
| 601 // (x >> K) < C => x < (C << K) | (2^K - 1) |
| 602 // when C < (M >> K) |
| 603 const uint32_t c = m.right().Value(); |
| 604 const uint32_t k = mleft.right().Value() & 0x1f; |
| 605 if (c < static_cast<uint32_t>(kMaxInt >> k)) { |
| 606 node->ReplaceInput(0, mleft.left().node()); |
| 607 node->ReplaceInput(1, Uint32Constant((c << k) | ((1 << k) - 1))); |
| 608 return Changed(node); |
| 609 } |
| 610 } |
| 611 } |
| 612 return ReduceCompare32(node); |
| 613 } |
| 614 |
| 615 |
| 616 Reduction MachineOperatorReducer::ReduceUint32LessThanOrEqual(Node* node) { |
| 617 Uint32BinopMatcher m(node); |
| 618 if (m.left().Is(0)) return ReplaceBool(true); // 0 <= x => true |
| 619 if (m.right().Is(kMaxUInt32)) return ReplaceBool(true); // x <= M => true |
| 620 if (m.IsFoldable()) { // K <= K => K |
| 621 return ReplaceBool(m.left().Value() <= m.right().Value()); |
| 622 } |
| 623 if (m.LeftEqualsRight()) return ReplaceBool(true); // x <= x => true |
| 624 return ReduceCompare32(node); |
| 625 } |
| 626 |
| 627 |
| 541 Reduction MachineOperatorReducer::ReduceInt32Div(Node* node) { | 628 Reduction MachineOperatorReducer::ReduceInt32Div(Node* node) { |
| 542 Int32BinopMatcher m(node); | 629 Int32BinopMatcher m(node); |
| 543 if (m.left().Is(0)) return Replace(m.left().node()); // 0 / x => 0 | 630 if (m.left().Is(0)) return Replace(m.left().node()); // 0 / x => 0 |
| 544 if (m.right().Is(0)) return Replace(m.right().node()); // x / 0 => 0 | 631 if (m.right().Is(0)) return Replace(m.right().node()); // x / 0 => 0 |
| 545 if (m.right().Is(1)) return Replace(m.left().node()); // x / 1 => x | 632 if (m.right().Is(1)) return Replace(m.left().node()); // x / 1 => x |
| 546 if (m.IsFoldable()) { // K / K => K | 633 if (m.IsFoldable()) { // K / K => K |
| 547 return ReplaceInt32( | 634 return ReplaceInt32( |
| 548 base::bits::SignedDiv32(m.left().Value(), m.right().Value())); | 635 base::bits::SignedDiv32(m.left().Value(), m.right().Value())); |
| 549 } | 636 } |
| 550 if (m.LeftEqualsRight()) { // x / x => x != 0 | 637 if (m.LeftEqualsRight()) { // x / x => x != 0 |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 718 MachineOperatorBuilder* MachineOperatorReducer::machine() const { | 805 MachineOperatorBuilder* MachineOperatorReducer::machine() const { |
| 719 return jsgraph()->machine(); | 806 return jsgraph()->machine(); |
| 720 } | 807 } |
| 721 | 808 |
| 722 | 809 |
| 723 Graph* MachineOperatorReducer::graph() const { return jsgraph()->graph(); } | 810 Graph* MachineOperatorReducer::graph() const { return jsgraph()->graph(); } |
| 724 | 811 |
| 725 } // namespace compiler | 812 } // namespace compiler |
| 726 } // namespace internal | 813 } // namespace internal |
| 727 } // namespace v8 | 814 } // namespace v8 |
| OLD | NEW |