Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(648)

Side by Side Diff: src/compiler/x64/instruction-selector-x64.cc

Issue 704713003: [turbofan] Optimize add operations to use 'leal' instruction on x64 (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Tweaks Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | test/unittests/compiler/x64/instruction-selector-x64-unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/generic-node-inl.h" 5 #include "src/compiler/generic-node-inl.h"
6 #include "src/compiler/instruction-selector-impl.h" 6 #include "src/compiler/instruction-selector-impl.h"
7 #include "src/compiler/node-matchers.h" 7 #include "src/compiler/node-matchers.h"
8 8
9 namespace v8 { 9 namespace v8 {
10 namespace internal { 10 namespace internal {
(...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after
357 357
358 void InstructionSelector::VisitWord32Ror(Node* node) { 358 void InstructionSelector::VisitWord32Ror(Node* node) {
359 VisitWord32Shift(this, node, kX64Ror32); 359 VisitWord32Shift(this, node, kX64Ror32);
360 } 360 }
361 361
362 362
363 void InstructionSelector::VisitWord64Ror(Node* node) { 363 void InstructionSelector::VisitWord64Ror(Node* node) {
364 VisitWord64Shift(this, node, kX64Ror); 364 VisitWord64Shift(this, node, kX64Ror);
365 } 365 }
366 366
367 namespace {
368
369 struct MemoryOperandMatcher FINAL
370 : public ValueMatcher<int32_t, IrOpcode::kInt32Add> {
titzer 2014/11/05 13:16:09 What do you inherit from ValueMatcher here?
371 explicit MemoryOperandMatcher(InstructionSelector* selector, Node* node)
372 : ValueMatcher<int32_t, IrOpcode::kInt32Add>(node),
373 is_memory_operand_(false),
374 scaled_(NULL),
375 unscaled_(NULL),
376 constant_(NULL),
377 scale_factor_(1) {
378 MatchMemoryOperand(selector);
titzer 2014/11/05 13:16:09 This method is only used in the constructor and I
379 }
380
381 bool IsMemoryOperand() const { return is_memory_operand_; }
382
383 AddressingMode GenerateMemoryOperand(X64OperandGenerator* g,
384 InstructionOperand* inputs[],
385 size_t* input_count) {
386 AddressingMode mode = kMode_MRI;
387 if (unscaled_ != NULL) {
388 inputs[(*input_count)++] = g->UseRegister(unscaled_);
389 if (scaled_ != NULL) {
390 inputs[(*input_count)++] = g->UseRegister(scaled_);
391 if (constant_ != NULL) {
392 inputs[(*input_count)++] = g->UseImmediate(constant_);
393 if (scale_factor_ == 1) {
titzer 2014/11/05 13:16:09 This pattern with switching on the scale factor co
394 mode = kMode_MR1I;
395 } else if (scale_factor_ == 2) {
396 mode = kMode_MR2I;
397 } else if (scale_factor_ == 4) {
398 mode = kMode_MR4I;
399 } else if (scale_factor_ == 8) {
400 mode = kMode_MR8I;
401 } else {
402 UNREACHABLE();
403 }
404 } else {
405 if (scale_factor_ == 1) {
406 mode = kMode_MR1;
407 } else if (scale_factor_ == 2) {
408 mode = kMode_MR2;
409 } else if (scale_factor_ == 4) {
410 mode = kMode_MR4;
411 } else if (scale_factor_ == 8) {
412 mode = kMode_MR8;
413 } else {
414 UNREACHABLE();
415 }
416 }
417 } else {
418 DCHECK(constant_ != NULL);
419 inputs[(*input_count)++] = g->UseImmediate(constant_);
420 mode = kMode_MRI;
421 }
422 } else {
423 DCHECK(scaled_ != NULL);
424 inputs[(*input_count)++] = g->UseRegister(scaled_);
425 if (constant_ != NULL) {
426 inputs[(*input_count)++] = g->UseImmediate(constant_);
427 if (scale_factor_ == 1) {
428 mode = kMode_M1I;
429 } else if (scale_factor_ == 2) {
430 mode = kMode_M2I;
431 } else if (scale_factor_ == 4) {
432 mode = kMode_M4I;
433 } else if (scale_factor_ == 8) {
434 mode = kMode_M8I;
435 } else {
436 UNREACHABLE();
437 }
438 } else {
439 if (scale_factor_ == 1) {
440 mode = kMode_M1;
441 } else if (scale_factor_ == 2) {
442 mode = kMode_M2;
443 } else if (scale_factor_ == 4) {
444 mode = kMode_M4;
445 } else if (scale_factor_ == 8) {
446 mode = kMode_M8;
447 } else {
448 UNREACHABLE();
449 }
450 }
451 }
452 return mode;
453 }
454
455 private:
456 static bool TryCombine(InstructionSelector* selector, Node* use, Node* node,
titzer 2014/11/05 13:16:09 This is tough to follow, partly because of the poi
457 Node** constant, Node** unscaled, Node** scaled,
458 int* scale_factor) {
459 X64OperandGenerator g(selector);
460 if (g.CanBeImmediate(node) && *constant == NULL) {
461 *constant = node;
titzer 2014/11/05 13:16:08 Why would the constant already be non-null and why
462 } else {
463 if (selector->CanCover(use, node) && *scaled == NULL) {
464 if (node->opcode() == IrOpcode::kInt32Mul) {
465 Int32BinopMatcher m(node);
466 Int32Matcher leftm(m.left().node());
467 Int32Matcher rightm(m.right().node());
468 if (leftm.IsPowerOf2() && leftm.Value() <= 8) {
titzer 2014/11/05 13:16:09 This can't happen because Int32BinopMatcher puts c
469 *scale_factor = leftm.Value();
470 *scaled = m.right().node();
471 return true;
472 }
473 if (rightm.IsPowerOf2() && rightm.Value() <= 8) {
474 *scale_factor = rightm.Value();
475 *scaled = m.left().node();
476 return true;
477 }
478 }
479 if (node->opcode() == IrOpcode::kWord32Shl) {
480 Int32BinopMatcher m(node);
481 Int32Matcher rightm(m.right().node());
482 if (rightm.HasValue() && rightm.Value() <= 3 && rightm.Value() >= 0) {
483 *scale_factor = 1 << rightm.Value();
484 *scaled = m.left().node();
485 return true;
486 }
487 }
488 }
489 if (*unscaled == NULL) {
490 *unscaled = node;
491 } else if (*scaled == NULL) {
492 *scaled = node;
493 } else {
494 return false;
titzer 2014/11/05 13:16:09 So we can return false if scaled and unscaled are
495 }
496 }
497 return true;
498 }
499
500 void MatchMemoryOperand(InstructionSelector* selector) {
501 if (node()->opcode() != IrOpcode::kInt32Add) return;
502
503 Node* node = this->node();
504 Int32BinopMatcher m(node);
505 Node* left = m.left().node();
506 Node* right = m.right().node();
507
508 is_memory_operand_ = true;
509
510 bool handled_left = false;
511 if (left->opcode() == IrOpcode::kInt32Add &&
512 selector->CanCover(node, left)) {
513 Int32BinopMatcher leftm(left);
514 Node* deeper_left = leftm.left().node();
515 Node* deeper_right = leftm.right().node();
516 CHECK(TryCombine(selector, left, deeper_left, &constant_, &unscaled_,
517 &scaled_, &scale_factor_));
518 CHECK(TryCombine(selector, left, deeper_right, &constant_, &unscaled_,
519 &scaled_, &scale_factor_));
520 // Combining the operands of the left side's add still need to keep at
521 // least one operand free for the right side, or the right operand needs
522 // to be constant. Otherwise, back out the match of the left operand
523 // altogether.
524 if (unscaled_ == NULL || scaled_ == NULL) {
525 handled_left = true;
526 } else {
527 X64OperandGenerator g(selector);
528 if (constant_ == NULL && g.CanBeImmediate(right)) {
529 constant_ = right;
530 return;
531 }
532 constant_ = NULL;
533 unscaled_ = NULL;
534 scaled_ = NULL;
535 scale_factor_ = 1;
536 }
537 }
538 // If the left operand wasn't an add, just add it to the operand as-is.
539 if (!handled_left) {
540 CHECK(TryCombine(selector, node, left, &constant_, &unscaled_, &scaled_,
541 &scale_factor_));
542 }
543
544 bool handled_right = false;
545 if (right->opcode() == IrOpcode::kInt32Add &&
546 selector->CanCover(node, right)) {
titzer 2014/11/05 13:16:09 What happens if we handled left already here?
547 Int32BinopMatcher rightm(right);
548 Node* deeper_left = rightm.left().node();
549 Node* deeper_right = rightm.right().node();
550 Node* constant_copy = constant_;
551 Node* unscaled_copy = unscaled_;
552 Node* scaled_copy = scaled_;
553 int scale_factor_copy = scale_factor_;
554 // If it's not possible to find a home for both the right add's operands,
555 // then abort the attempt to combine the right operand into the memory
556 // operand.
557 if (TryCombine(selector, right, deeper_left, &constant_copy,
558 &unscaled_copy, &scaled_copy, &scale_factor_copy) &&
559 TryCombine(selector, right, deeper_right, &constant_copy,
560 &unscaled_copy, &scaled_copy, &scale_factor_copy)) {
561 handled_right = true;
562 constant_ = constant_copy;
563 unscaled_ = unscaled_copy;
564 scaled_ = scaled_copy;
565 scale_factor_ = scale_factor_copy;
566 }
567 }
568
569 // If the right operand was either not an add or the add couldn't not be
570 // folded into the base node's memory operand, then just use the right
571 // operand as-is.
572 if (!handled_right) {
573 TryCombine(selector, node, right, &constant_, &unscaled_, &scaled_,
574 &scale_factor_);
575 }
576 }
577
578 bool is_memory_operand_;
579 Node* scaled_;
580 Node* unscaled_;
581 Node* constant_;
582 int scale_factor_;
583 };
584
585 } // namespace
586
587
588 static bool TryLeaInt32Add(InstructionSelector* selector, Node* node) {
589 MemoryOperandMatcher m(selector, node);
590 if (!m.IsMemoryOperand()) return false;
591
592 X64OperandGenerator g(selector);
593 InstructionOperand* inputs[4];
594 size_t input_count = 0;
595
596 AddressingMode mode = m.GenerateMemoryOperand(&g, inputs, &input_count);
597
598 DCHECK_NE(0, static_cast<int>(input_count));
599 DCHECK_GE(arraysize(inputs), input_count);
600
601 InstructionOperand* outputs[1];
602 outputs[0] = g.DefineAsRegister(node);
603
604 InstructionCode opcode = AddressingModeField::encode(mode) | kX64Lea32;
605
606 selector->Emit(opcode, 1, outputs, input_count, inputs);
607
608 return true;
609 }
610
367 611
368 void InstructionSelector::VisitInt32Add(Node* node) { 612 void InstructionSelector::VisitInt32Add(Node* node) {
613 if (TryLeaInt32Add(this, node)) return;
titzer 2014/11/05 13:16:09 I think this would be more readable if it was inli
369 VisitBinop(this, node, kX64Add32); 614 VisitBinop(this, node, kX64Add32);
370 } 615 }
371 616
372 617
373 void InstructionSelector::VisitInt64Add(Node* node) { 618 void InstructionSelector::VisitInt64Add(Node* node) {
374 VisitBinop(this, node, kX64Add); 619 VisitBinop(this, node, kX64Add);
375 } 620 }
376 621
377 622
378 void InstructionSelector::VisitInt32Sub(Node* node) { 623 void InstructionSelector::VisitInt32Sub(Node* node) {
(...skipping 704 matching lines...) Expand 10 before | Expand all | Expand 10 after
1083 if (CpuFeatures::IsSupported(SSE4_1)) { 1328 if (CpuFeatures::IsSupported(SSE4_1)) {
1084 return MachineOperatorBuilder::kFloat64Floor | 1329 return MachineOperatorBuilder::kFloat64Floor |
1085 MachineOperatorBuilder::kFloat64Ceil | 1330 MachineOperatorBuilder::kFloat64Ceil |
1086 MachineOperatorBuilder::kFloat64RoundTruncate; 1331 MachineOperatorBuilder::kFloat64RoundTruncate;
1087 } 1332 }
1088 return MachineOperatorBuilder::kNoFlags; 1333 return MachineOperatorBuilder::kNoFlags;
1089 } 1334 }
1090 } // namespace compiler 1335 } // namespace compiler
1091 } // namespace internal 1336 } // namespace internal
1092 } // namespace v8 1337 } // namespace v8
OLDNEW
« no previous file with comments | « no previous file | test/unittests/compiler/x64/instruction-selector-x64-unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698