Chromium Code Reviews| 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 0447b794ffe6ee151d0ddfa6a4aec6525fb4fbf7..7a797618297d2779a8ff291ea4266db1e5a4d7ac 100644 |
| --- a/src/compiler/x64/instruction-selector-x64.cc |
| +++ b/src/compiler/x64/instruction-selector-x64.cc |
| @@ -20,11 +20,6 @@ class X64OperandGenerator FINAL : public OperandGenerator { |
| Register::ToAllocationIndex(reg)); |
| } |
| - InstructionOperand* UseByteRegister(Node* node) { |
| - // TODO(dcarney): relax constraint. |
| - return UseFixed(node, rdx); |
| - } |
| - |
| InstructionOperand* UseImmediate64(Node* node) { return UseImmediate(node); } |
| bool CanBeImmediate(Node* node) { |
| @@ -59,10 +54,172 @@ class X64OperandGenerator FINAL : public OperandGenerator { |
| }; |
| +// Matches nodes of form [x * N] for N in {1,2,4,8} |
| +class ScaleFactorMatcher : public NodeMatcher { |
| + public: |
| + explicit ScaleFactorMatcher(Node* node) |
| + : NodeMatcher(node), matches_(false), power_(0) { |
| + Match(); |
| + } |
| + |
| + bool matches() { return matches_; } |
| + int power() { |
| + DCHECK(matches_); |
| + return power_; |
| + } |
| + Node* left() { |
| + DCHECK(matches_); |
| + return InputAt(0); |
| + } |
| + |
| + private: |
| + void Match() { |
| + if (opcode() != IrOpcode::kInt32Mul) return; |
|
titzer
2014/09/26 11:04:11
I think you can use an Int32BinopMatcher here. It
dcarney
2014/09/26 12:49:51
Done.
|
| + // Assume reduction has put constant on right. |
| + Int32Matcher right_matcher(InputAt(1)); |
| + if (!right_matcher.HasValue()) return; |
| + int32_t right_value = right_matcher.Value(); |
| + switch (right_value) { |
| + case 8: |
| + power_++; // Fall through. |
| + case 4: |
| + power_++; // Fall through. |
| + case 2: |
| + power_++; // Fall through. |
| + case 1: |
| + break; |
| + default: |
| + return; |
| + } |
| + matches_ = true; |
| + } |
| + |
| + bool matches_; |
| + int power_; |
| +}; |
| + |
| + |
| +// Matches nodes of form: |
| +// [x * N] |
| +// [x * N + K] |
| +// [x + K] |
|
titzer
2014/09/26 11:04:12
This case is redundant since N can be 1.
dcarney
2014/09/26 12:49:51
yeah. but it's matched differently. so i list it
|
| +// [x] -- fallback case |
| +// for N in {1,2,4,8} and K int32_t |
| +class IndexAndDisplacementMatcher : public NodeMatcher { |
| + public: |
| + explicit IndexAndDisplacementMatcher(Node* node) |
| + : NodeMatcher(node), index_node_(node), displacement_(0), power_(0) { |
| + Match(); |
| + } |
| + |
| + Node* index_node() { return index_node_; } |
| + int displacement() { return displacement_; } |
| + AddressingMode GetMode(AddressingMode one) { |
| + return static_cast<AddressingMode>(static_cast<int>(one) + power_); |
| + } |
| + |
| + private: |
| + void Match() { |
| + if (opcode() == IrOpcode::kInt32Add) { |
|
titzer
2014/09/26 11:04:12
Here also.
dcarney
2014/09/26 12:49:51
Done.
|
| + // Assume reduction has put constant on the right. |
| + Int32Matcher right_matcher(InputAt(1)); |
| + if (right_matcher.HasValue()) { |
| + displacement_ = right_matcher.Value(); |
| + index_node_ = InputAt(0); |
| + } |
| + } |
| + // Test scale factor. |
| + ScaleFactorMatcher scale_matcher(index_node_); |
| + if (scale_matcher.matches()) { |
| + index_node_ = scale_matcher.left(); |
| + power_ = scale_matcher.power(); |
| + } |
| + } |
| + |
| + Node* index_node_; |
| + int displacement_; |
| + int power_; |
| +}; |
| + |
| + |
| +class AddressingModeMatcher { |
|
titzer
2014/09/26 11:04:11
Is it possible to inline IndexAndDisplacement matc
dcarney
2014/09/26 12:49:51
yeah. but i want the 2 above matcher classes to be
|
| + public: |
| + AddressingModeMatcher(X64OperandGenerator* g, Node* base, Node* index) |
| + : base_operand_(NULL), |
| + index_operand_(NULL), |
| + displacement_operand_(NULL), |
| + mode_(kMode_None) { |
| + Int32Matcher index_imm(index); |
| + if (index_imm.HasValue()) { |
| + int32_t value = index_imm.Value(); |
| + if (value == 0) { |
| + mode_ = kMode_MR; |
| + } else { |
| + mode_ = kMode_MRI; |
| + index_operand_ = g->UseImmediate(index); |
| + } |
| + base_operand_ = g->UseRegister(base); |
| + } else { |
| + // Compute base operand. |
| + Int32Matcher base_imm(base); |
| + if (!base_imm.HasValue() || base_imm.Value() != 0) { |
| + base_operand_ = g->UseRegister(base); |
| + } |
| + // Compute index and displacement. |
| + IndexAndDisplacementMatcher matcher(index); |
| + index_operand_ = g->UseRegister(matcher.index_node()); |
| + if (matcher.displacement() != 0) { |
| + displacement_operand_ = g->TempImmediate(matcher.displacement()); |
| + } |
| + // Compute mode with scale factor one. |
| + if (base_operand_ == NULL) { |
| + if (displacement_operand_ == NULL) { |
| + mode_ = kMode_M1; |
| + } else { |
| + mode_ = kMode_M1I; |
| + } |
| + } else { |
| + if (displacement_operand_ == NULL) { |
| + mode_ = kMode_MR1; |
| + } else { |
| + mode_ = kMode_MR1I; |
| + } |
| + } |
| + // Adjust mode to actual scale factor. |
| + mode_ = matcher.GetMode(mode_); |
| + } |
| + DCHECK_NE(kMode_None, mode_); |
| + } |
| + |
| + size_t SetInputs(InstructionOperand** inputs) { |
| + size_t input_count = 0; |
| + // Compute inputs_ and input_count. |
| + if (base_operand_ != NULL) { |
| + inputs[input_count++] = base_operand_; |
| + } |
| + if (index_operand_ != NULL) { |
| + inputs[input_count++] = index_operand_; |
| + } |
| + if (displacement_operand_ != NULL) { |
| + // Pure displacement mode not supported by x64. |
| + DCHECK_NE(input_count, 0); |
| + inputs[input_count++] = displacement_operand_; |
| + } |
| + DCHECK_NE(input_count, 0); |
| + return input_count; |
| + } |
| + |
| + static const int kMaxInputCount = 3; |
| + InstructionOperand* base_operand_; |
| + InstructionOperand* index_operand_; |
| + InstructionOperand* displacement_operand_; |
| + AddressingMode mode_; |
| +}; |
| + |
| + |
| void InstructionSelector::VisitLoad(Node* node) { |
| MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node)); |
| MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node)); |
| - X64OperandGenerator g(this); |
| Node* base = node->InputAt(0); |
| Node* index = node->InputAt(1); |
| @@ -93,18 +250,14 @@ void InstructionSelector::VisitLoad(Node* node) { |
| UNREACHABLE(); |
| return; |
| } |
| - if (g.CanBeImmediate(base)) { |
| - // load [#base + %index] |
| - Emit(opcode | AddressingModeField::encode(kMode_MRI), |
| - g.DefineAsRegister(node), g.UseRegister(index), g.UseImmediate(base)); |
| - } else if (g.CanBeImmediate(index)) { // load [%base + #index] |
| - Emit(opcode | AddressingModeField::encode(kMode_MRI), |
| - g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index)); |
| - } else { // load [%base + %index + K] |
| - Emit(opcode | AddressingModeField::encode(kMode_MR1I), |
| - g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(index)); |
| - } |
| - // TODO(turbofan): addressing modes [r+r*{2,4,8}+K] |
| + |
| + X64OperandGenerator g(this); |
| + AddressingModeMatcher matcher(&g, base, index); |
| + InstructionCode code = opcode | AddressingModeField::encode(matcher.mode_); |
| + InstructionOperand* outputs[] = {g.DefineAsRegister(node)}; |
| + InstructionOperand* inputs[AddressingModeMatcher::kMaxInputCount]; |
| + int input_count = matcher.SetInputs(inputs); |
| + Emit(code, 1, outputs, input_count, inputs); |
| } |
| @@ -128,14 +281,6 @@ void InstructionSelector::VisitStore(Node* node) { |
| return; |
| } |
| DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind()); |
| - InstructionOperand* val; |
| - if (g.CanBeImmediate(value)) { |
| - val = g.UseImmediate(value); |
| - } else if (rep == kRepWord8 || rep == kRepBit) { |
| - val = g.UseByteRegister(value); |
| - } else { |
| - val = g.UseRegister(value); |
| - } |
| ArchOpcode opcode; |
| switch (rep) { |
| case kRepFloat32: |
| @@ -162,18 +307,20 @@ void InstructionSelector::VisitStore(Node* node) { |
| UNREACHABLE(); |
| return; |
| } |
| - if (g.CanBeImmediate(base)) { |
| - // store [#base + %index], %|#value |
| - Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL, |
| - g.UseRegister(index), g.UseImmediate(base), val); |
| - } else if (g.CanBeImmediate(index)) { // store [%base + #index], %|#value |
| - Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL, |
| - g.UseRegister(base), g.UseImmediate(index), val); |
| - } else { // store [%base + %index], %|#value |
| - Emit(opcode | AddressingModeField::encode(kMode_MR1I), NULL, |
| - g.UseRegister(base), g.UseRegister(index), val); |
| + |
| + InstructionOperand* val; |
| + if (g.CanBeImmediate(value)) { |
| + val = g.UseImmediate(value); |
| + } else { |
| + val = g.UseRegister(value); |
| } |
| - // TODO(turbofan): addressing modes [r+r*{2,4,8}+K] |
| + |
| + AddressingModeMatcher matcher(&g, base, index); |
| + InstructionCode code = opcode | AddressingModeField::encode(matcher.mode_); |
| + InstructionOperand* inputs[AddressingModeMatcher::kMaxInputCount + 1]; |
| + int input_count = matcher.SetInputs(inputs); |
| + inputs[input_count++] = val; |
| + Emit(code, 0, static_cast<InstructionOperand**>(NULL), input_count, inputs); |
| } |
| @@ -702,8 +849,6 @@ void InstructionSelector::VisitCall(Node* call, BasicBlock* continuation, |
| // Compute InstructionOperands for inputs and outputs. |
| InitializeCallBuffer(call, &buffer, true, true); |
| - // TODO(dcarney): stack alignment for c calls. |
| - // TODO(dcarney): shadow space on window for c calls. |
| // Push any stack arguments. |
| for (NodeVectorRIter input = buffer.pushed_nodes.rbegin(); |
| input != buffer.pushed_nodes.rend(); input++) { |