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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | test/unittests/compiler/x64/instruction-selector-x64-unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/compiler/x64/instruction-selector-x64.cc
diff --git a/src/compiler/x64/instruction-selector-x64.cc b/src/compiler/x64/instruction-selector-x64.cc
index c70944bc86d085509da1b3cdb44305f4043212df..1269e2e346e83859c407e2f036b0929666bb8088 100644
--- a/src/compiler/x64/instruction-selector-x64.cc
+++ b/src/compiler/x64/instruction-selector-x64.cc
@@ -364,8 +364,253 @@ void InstructionSelector::VisitWord64Ror(Node* node) {
VisitWord64Shift(this, node, kX64Ror);
}
+namespace {
+
+struct MemoryOperandMatcher FINAL
+ : public ValueMatcher<int32_t, IrOpcode::kInt32Add> {
titzer 2014/11/05 13:16:09 What do you inherit from ValueMatcher here?
+ explicit MemoryOperandMatcher(InstructionSelector* selector, Node* node)
+ : ValueMatcher<int32_t, IrOpcode::kInt32Add>(node),
+ is_memory_operand_(false),
+ scaled_(NULL),
+ unscaled_(NULL),
+ constant_(NULL),
+ scale_factor_(1) {
+ MatchMemoryOperand(selector);
titzer 2014/11/05 13:16:09 This method is only used in the constructor and I
+ }
+
+ bool IsMemoryOperand() const { return is_memory_operand_; }
+
+ AddressingMode GenerateMemoryOperand(X64OperandGenerator* g,
+ InstructionOperand* inputs[],
+ size_t* input_count) {
+ AddressingMode mode = kMode_MRI;
+ if (unscaled_ != NULL) {
+ inputs[(*input_count)++] = g->UseRegister(unscaled_);
+ if (scaled_ != NULL) {
+ inputs[(*input_count)++] = g->UseRegister(scaled_);
+ if (constant_ != NULL) {
+ inputs[(*input_count)++] = g->UseImmediate(constant_);
+ if (scale_factor_ == 1) {
titzer 2014/11/05 13:16:09 This pattern with switching on the scale factor co
+ mode = kMode_MR1I;
+ } else if (scale_factor_ == 2) {
+ mode = kMode_MR2I;
+ } else if (scale_factor_ == 4) {
+ mode = kMode_MR4I;
+ } else if (scale_factor_ == 8) {
+ mode = kMode_MR8I;
+ } else {
+ UNREACHABLE();
+ }
+ } else {
+ if (scale_factor_ == 1) {
+ mode = kMode_MR1;
+ } else if (scale_factor_ == 2) {
+ mode = kMode_MR2;
+ } else if (scale_factor_ == 4) {
+ mode = kMode_MR4;
+ } else if (scale_factor_ == 8) {
+ mode = kMode_MR8;
+ } else {
+ UNREACHABLE();
+ }
+ }
+ } else {
+ DCHECK(constant_ != NULL);
+ inputs[(*input_count)++] = g->UseImmediate(constant_);
+ mode = kMode_MRI;
+ }
+ } else {
+ DCHECK(scaled_ != NULL);
+ inputs[(*input_count)++] = g->UseRegister(scaled_);
+ if (constant_ != NULL) {
+ inputs[(*input_count)++] = g->UseImmediate(constant_);
+ if (scale_factor_ == 1) {
+ mode = kMode_M1I;
+ } else if (scale_factor_ == 2) {
+ mode = kMode_M2I;
+ } else if (scale_factor_ == 4) {
+ mode = kMode_M4I;
+ } else if (scale_factor_ == 8) {
+ mode = kMode_M8I;
+ } else {
+ UNREACHABLE();
+ }
+ } else {
+ if (scale_factor_ == 1) {
+ mode = kMode_M1;
+ } else if (scale_factor_ == 2) {
+ mode = kMode_M2;
+ } else if (scale_factor_ == 4) {
+ mode = kMode_M4;
+ } else if (scale_factor_ == 8) {
+ mode = kMode_M8;
+ } else {
+ UNREACHABLE();
+ }
+ }
+ }
+ return mode;
+ }
+
+ private:
+ 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
+ Node** constant, Node** unscaled, Node** scaled,
+ int* scale_factor) {
+ X64OperandGenerator g(selector);
+ if (g.CanBeImmediate(node) && *constant == NULL) {
+ *constant = node;
titzer 2014/11/05 13:16:08 Why would the constant already be non-null and why
+ } else {
+ if (selector->CanCover(use, node) && *scaled == NULL) {
+ if (node->opcode() == IrOpcode::kInt32Mul) {
+ Int32BinopMatcher m(node);
+ Int32Matcher leftm(m.left().node());
+ Int32Matcher rightm(m.right().node());
+ if (leftm.IsPowerOf2() && leftm.Value() <= 8) {
titzer 2014/11/05 13:16:09 This can't happen because Int32BinopMatcher puts c
+ *scale_factor = leftm.Value();
+ *scaled = m.right().node();
+ return true;
+ }
+ if (rightm.IsPowerOf2() && rightm.Value() <= 8) {
+ *scale_factor = rightm.Value();
+ *scaled = m.left().node();
+ return true;
+ }
+ }
+ if (node->opcode() == IrOpcode::kWord32Shl) {
+ Int32BinopMatcher m(node);
+ Int32Matcher rightm(m.right().node());
+ if (rightm.HasValue() && rightm.Value() <= 3 && rightm.Value() >= 0) {
+ *scale_factor = 1 << rightm.Value();
+ *scaled = m.left().node();
+ return true;
+ }
+ }
+ }
+ if (*unscaled == NULL) {
+ *unscaled = node;
+ } else if (*scaled == NULL) {
+ *scaled = node;
+ } else {
+ return false;
titzer 2014/11/05 13:16:09 So we can return false if scaled and unscaled are
+ }
+ }
+ return true;
+ }
+
+ void MatchMemoryOperand(InstructionSelector* selector) {
+ if (node()->opcode() != IrOpcode::kInt32Add) return;
+
+ Node* node = this->node();
+ Int32BinopMatcher m(node);
+ Node* left = m.left().node();
+ Node* right = m.right().node();
+
+ is_memory_operand_ = true;
+
+ bool handled_left = false;
+ if (left->opcode() == IrOpcode::kInt32Add &&
+ selector->CanCover(node, left)) {
+ Int32BinopMatcher leftm(left);
+ Node* deeper_left = leftm.left().node();
+ Node* deeper_right = leftm.right().node();
+ CHECK(TryCombine(selector, left, deeper_left, &constant_, &unscaled_,
+ &scaled_, &scale_factor_));
+ CHECK(TryCombine(selector, left, deeper_right, &constant_, &unscaled_,
+ &scaled_, &scale_factor_));
+ // Combining the operands of the left side's add still need to keep at
+ // least one operand free for the right side, or the right operand needs
+ // to be constant. Otherwise, back out the match of the left operand
+ // altogether.
+ if (unscaled_ == NULL || scaled_ == NULL) {
+ handled_left = true;
+ } else {
+ X64OperandGenerator g(selector);
+ if (constant_ == NULL && g.CanBeImmediate(right)) {
+ constant_ = right;
+ return;
+ }
+ constant_ = NULL;
+ unscaled_ = NULL;
+ scaled_ = NULL;
+ scale_factor_ = 1;
+ }
+ }
+ // If the left operand wasn't an add, just add it to the operand as-is.
+ if (!handled_left) {
+ CHECK(TryCombine(selector, node, left, &constant_, &unscaled_, &scaled_,
+ &scale_factor_));
+ }
+
+ bool handled_right = false;
+ if (right->opcode() == IrOpcode::kInt32Add &&
+ selector->CanCover(node, right)) {
titzer 2014/11/05 13:16:09 What happens if we handled left already here?
+ Int32BinopMatcher rightm(right);
+ Node* deeper_left = rightm.left().node();
+ Node* deeper_right = rightm.right().node();
+ Node* constant_copy = constant_;
+ Node* unscaled_copy = unscaled_;
+ Node* scaled_copy = scaled_;
+ int scale_factor_copy = scale_factor_;
+ // If it's not possible to find a home for both the right add's operands,
+ // then abort the attempt to combine the right operand into the memory
+ // operand.
+ if (TryCombine(selector, right, deeper_left, &constant_copy,
+ &unscaled_copy, &scaled_copy, &scale_factor_copy) &&
+ TryCombine(selector, right, deeper_right, &constant_copy,
+ &unscaled_copy, &scaled_copy, &scale_factor_copy)) {
+ handled_right = true;
+ constant_ = constant_copy;
+ unscaled_ = unscaled_copy;
+ scaled_ = scaled_copy;
+ scale_factor_ = scale_factor_copy;
+ }
+ }
+
+ // If the right operand was either not an add or the add couldn't not be
+ // folded into the base node's memory operand, then just use the right
+ // operand as-is.
+ if (!handled_right) {
+ TryCombine(selector, node, right, &constant_, &unscaled_, &scaled_,
+ &scale_factor_);
+ }
+ }
+
+ bool is_memory_operand_;
+ Node* scaled_;
+ Node* unscaled_;
+ Node* constant_;
+ int scale_factor_;
+};
+
+} // namespace
+
+
+static bool TryLeaInt32Add(InstructionSelector* selector, Node* node) {
+ MemoryOperandMatcher m(selector, node);
+ if (!m.IsMemoryOperand()) return false;
+
+ X64OperandGenerator g(selector);
+ InstructionOperand* inputs[4];
+ size_t input_count = 0;
+
+ AddressingMode mode = m.GenerateMemoryOperand(&g, inputs, &input_count);
+
+ DCHECK_NE(0, static_cast<int>(input_count));
+ DCHECK_GE(arraysize(inputs), input_count);
+
+ InstructionOperand* outputs[1];
+ outputs[0] = g.DefineAsRegister(node);
+
+ InstructionCode opcode = AddressingModeField::encode(mode) | kX64Lea32;
+
+ selector->Emit(opcode, 1, outputs, input_count, inputs);
+
+ return true;
+}
+
void InstructionSelector::VisitInt32Add(Node* node) {
+ if (TryLeaInt32Add(this, node)) return;
titzer 2014/11/05 13:16:09 I think this would be more readable if it was inli
VisitBinop(this, node, kX64Add32);
}
« 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