Chromium Code Reviews| 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/instruction-selector-impl.h" | 5 #include "src/compiler/instruction-selector-impl.h" |
| 6 #include "src/compiler/node-matchers.h" | 6 #include "src/compiler/node-matchers.h" |
| 7 | 7 |
| 8 namespace v8 { | 8 namespace v8 { |
| 9 namespace internal { | 9 namespace internal { |
| 10 namespace compiler { | 10 namespace compiler { |
| 11 | 11 |
| 12 // Adds X64-specific methods for generating operands. | 12 // Adds X64-specific methods for generating operands. |
| 13 class X64OperandGenerator FINAL : public OperandGenerator { | 13 class X64OperandGenerator FINAL : public OperandGenerator { |
| 14 public: | 14 public: |
| 15 explicit X64OperandGenerator(InstructionSelector* selector) | 15 explicit X64OperandGenerator(InstructionSelector* selector) |
| 16 : OperandGenerator(selector) {} | 16 : OperandGenerator(selector) {} |
| 17 | 17 |
| 18 InstructionOperand* TempRegister(Register reg) { | 18 InstructionOperand* TempRegister(Register reg) { |
| 19 return new (zone()) UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER, | 19 return new (zone()) UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER, |
| 20 Register::ToAllocationIndex(reg)); | 20 Register::ToAllocationIndex(reg)); |
| 21 } | 21 } |
| 22 | 22 |
| 23 InstructionOperand* UseByteRegister(Node* node) { | |
| 24 // TODO(dcarney): relax constraint. | |
| 25 return UseFixed(node, rdx); | |
| 26 } | |
| 27 | |
| 28 InstructionOperand* UseImmediate64(Node* node) { return UseImmediate(node); } | 23 InstructionOperand* UseImmediate64(Node* node) { return UseImmediate(node); } |
| 29 | 24 |
| 30 bool CanBeImmediate(Node* node) { | 25 bool CanBeImmediate(Node* node) { |
| 31 switch (node->opcode()) { | 26 switch (node->opcode()) { |
| 32 case IrOpcode::kInt32Constant: | 27 case IrOpcode::kInt32Constant: |
| 33 return true; | 28 return true; |
| 34 default: | 29 default: |
| 35 return false; | 30 return false; |
| 36 } | 31 } |
| 37 } | 32 } |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 52 return false; | 47 return false; |
| 53 } | 48 } |
| 54 } | 49 } |
| 55 | 50 |
| 56 bool CanBeBetterLeftOperand(Node* node) const { | 51 bool CanBeBetterLeftOperand(Node* node) const { |
| 57 return !selector()->IsLive(node); | 52 return !selector()->IsLive(node); |
| 58 } | 53 } |
| 59 }; | 54 }; |
| 60 | 55 |
| 61 | 56 |
| 57 // Matches nodes of form [x * N] for N in {1,2,4,8} | |
| 58 class ScaleFactorMatcher : public NodeMatcher { | |
| 59 public: | |
| 60 explicit ScaleFactorMatcher(Node* node) | |
| 61 : NodeMatcher(node), matches_(false), power_(0) { | |
| 62 Match(); | |
| 63 } | |
| 64 | |
| 65 bool matches() { return matches_; } | |
| 66 int power() { | |
| 67 DCHECK(matches_); | |
| 68 return power_; | |
| 69 } | |
| 70 Node* left() { | |
| 71 DCHECK(matches_); | |
| 72 return InputAt(0); | |
| 73 } | |
| 74 | |
| 75 private: | |
| 76 void Match() { | |
| 77 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.
| |
| 78 // Assume reduction has put constant on right. | |
| 79 Int32Matcher right_matcher(InputAt(1)); | |
| 80 if (!right_matcher.HasValue()) return; | |
| 81 int32_t right_value = right_matcher.Value(); | |
| 82 switch (right_value) { | |
| 83 case 8: | |
| 84 power_++; // Fall through. | |
| 85 case 4: | |
| 86 power_++; // Fall through. | |
| 87 case 2: | |
| 88 power_++; // Fall through. | |
| 89 case 1: | |
| 90 break; | |
| 91 default: | |
| 92 return; | |
| 93 } | |
| 94 matches_ = true; | |
| 95 } | |
| 96 | |
| 97 bool matches_; | |
| 98 int power_; | |
| 99 }; | |
| 100 | |
| 101 | |
| 102 // Matches nodes of form: | |
| 103 // [x * N] | |
| 104 // [x * N + K] | |
| 105 // [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
| |
| 106 // [x] -- fallback case | |
| 107 // for N in {1,2,4,8} and K int32_t | |
| 108 class IndexAndDisplacementMatcher : public NodeMatcher { | |
| 109 public: | |
| 110 explicit IndexAndDisplacementMatcher(Node* node) | |
| 111 : NodeMatcher(node), index_node_(node), displacement_(0), power_(0) { | |
| 112 Match(); | |
| 113 } | |
| 114 | |
| 115 Node* index_node() { return index_node_; } | |
| 116 int displacement() { return displacement_; } | |
| 117 AddressingMode GetMode(AddressingMode one) { | |
| 118 return static_cast<AddressingMode>(static_cast<int>(one) + power_); | |
| 119 } | |
| 120 | |
| 121 private: | |
| 122 void Match() { | |
| 123 if (opcode() == IrOpcode::kInt32Add) { | |
|
titzer
2014/09/26 11:04:12
Here also.
dcarney
2014/09/26 12:49:51
Done.
| |
| 124 // Assume reduction has put constant on the right. | |
| 125 Int32Matcher right_matcher(InputAt(1)); | |
| 126 if (right_matcher.HasValue()) { | |
| 127 displacement_ = right_matcher.Value(); | |
| 128 index_node_ = InputAt(0); | |
| 129 } | |
| 130 } | |
| 131 // Test scale factor. | |
| 132 ScaleFactorMatcher scale_matcher(index_node_); | |
| 133 if (scale_matcher.matches()) { | |
| 134 index_node_ = scale_matcher.left(); | |
| 135 power_ = scale_matcher.power(); | |
| 136 } | |
| 137 } | |
| 138 | |
| 139 Node* index_node_; | |
| 140 int displacement_; | |
| 141 int power_; | |
| 142 }; | |
| 143 | |
| 144 | |
| 145 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
| |
| 146 public: | |
| 147 AddressingModeMatcher(X64OperandGenerator* g, Node* base, Node* index) | |
| 148 : base_operand_(NULL), | |
| 149 index_operand_(NULL), | |
| 150 displacement_operand_(NULL), | |
| 151 mode_(kMode_None) { | |
| 152 Int32Matcher index_imm(index); | |
| 153 if (index_imm.HasValue()) { | |
| 154 int32_t value = index_imm.Value(); | |
| 155 if (value == 0) { | |
| 156 mode_ = kMode_MR; | |
| 157 } else { | |
| 158 mode_ = kMode_MRI; | |
| 159 index_operand_ = g->UseImmediate(index); | |
| 160 } | |
| 161 base_operand_ = g->UseRegister(base); | |
| 162 } else { | |
| 163 // Compute base operand. | |
| 164 Int32Matcher base_imm(base); | |
| 165 if (!base_imm.HasValue() || base_imm.Value() != 0) { | |
| 166 base_operand_ = g->UseRegister(base); | |
| 167 } | |
| 168 // Compute index and displacement. | |
| 169 IndexAndDisplacementMatcher matcher(index); | |
| 170 index_operand_ = g->UseRegister(matcher.index_node()); | |
| 171 if (matcher.displacement() != 0) { | |
| 172 displacement_operand_ = g->TempImmediate(matcher.displacement()); | |
| 173 } | |
| 174 // Compute mode with scale factor one. | |
| 175 if (base_operand_ == NULL) { | |
| 176 if (displacement_operand_ == NULL) { | |
| 177 mode_ = kMode_M1; | |
| 178 } else { | |
| 179 mode_ = kMode_M1I; | |
| 180 } | |
| 181 } else { | |
| 182 if (displacement_operand_ == NULL) { | |
| 183 mode_ = kMode_MR1; | |
| 184 } else { | |
| 185 mode_ = kMode_MR1I; | |
| 186 } | |
| 187 } | |
| 188 // Adjust mode to actual scale factor. | |
| 189 mode_ = matcher.GetMode(mode_); | |
| 190 } | |
| 191 DCHECK_NE(kMode_None, mode_); | |
| 192 } | |
| 193 | |
| 194 size_t SetInputs(InstructionOperand** inputs) { | |
| 195 size_t input_count = 0; | |
| 196 // Compute inputs_ and input_count. | |
| 197 if (base_operand_ != NULL) { | |
| 198 inputs[input_count++] = base_operand_; | |
| 199 } | |
| 200 if (index_operand_ != NULL) { | |
| 201 inputs[input_count++] = index_operand_; | |
| 202 } | |
| 203 if (displacement_operand_ != NULL) { | |
| 204 // Pure displacement mode not supported by x64. | |
| 205 DCHECK_NE(input_count, 0); | |
| 206 inputs[input_count++] = displacement_operand_; | |
| 207 } | |
| 208 DCHECK_NE(input_count, 0); | |
| 209 return input_count; | |
| 210 } | |
| 211 | |
| 212 static const int kMaxInputCount = 3; | |
| 213 InstructionOperand* base_operand_; | |
| 214 InstructionOperand* index_operand_; | |
| 215 InstructionOperand* displacement_operand_; | |
| 216 AddressingMode mode_; | |
| 217 }; | |
| 218 | |
| 219 | |
| 62 void InstructionSelector::VisitLoad(Node* node) { | 220 void InstructionSelector::VisitLoad(Node* node) { |
| 63 MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node)); | 221 MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node)); |
| 64 MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node)); | 222 MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node)); |
| 65 X64OperandGenerator g(this); | |
| 66 Node* base = node->InputAt(0); | 223 Node* base = node->InputAt(0); |
| 67 Node* index = node->InputAt(1); | 224 Node* index = node->InputAt(1); |
| 68 | 225 |
| 69 ArchOpcode opcode; | 226 ArchOpcode opcode; |
| 70 // TODO(titzer): signed/unsigned small loads | 227 // TODO(titzer): signed/unsigned small loads |
| 71 switch (rep) { | 228 switch (rep) { |
| 72 case kRepFloat32: | 229 case kRepFloat32: |
| 73 opcode = kX64Movss; | 230 opcode = kX64Movss; |
| 74 break; | 231 break; |
| 75 case kRepFloat64: | 232 case kRepFloat64: |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 86 opcode = kX64Movl; | 243 opcode = kX64Movl; |
| 87 break; | 244 break; |
| 88 case kRepTagged: // Fall through. | 245 case kRepTagged: // Fall through. |
| 89 case kRepWord64: | 246 case kRepWord64: |
| 90 opcode = kX64Movq; | 247 opcode = kX64Movq; |
| 91 break; | 248 break; |
| 92 default: | 249 default: |
| 93 UNREACHABLE(); | 250 UNREACHABLE(); |
| 94 return; | 251 return; |
| 95 } | 252 } |
| 96 if (g.CanBeImmediate(base)) { | 253 |
| 97 // load [#base + %index] | 254 X64OperandGenerator g(this); |
| 98 Emit(opcode | AddressingModeField::encode(kMode_MRI), | 255 AddressingModeMatcher matcher(&g, base, index); |
| 99 g.DefineAsRegister(node), g.UseRegister(index), g.UseImmediate(base)); | 256 InstructionCode code = opcode | AddressingModeField::encode(matcher.mode_); |
| 100 } else if (g.CanBeImmediate(index)) { // load [%base + #index] | 257 InstructionOperand* outputs[] = {g.DefineAsRegister(node)}; |
| 101 Emit(opcode | AddressingModeField::encode(kMode_MRI), | 258 InstructionOperand* inputs[AddressingModeMatcher::kMaxInputCount]; |
| 102 g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index)); | 259 int input_count = matcher.SetInputs(inputs); |
| 103 } else { // load [%base + %index + K] | 260 Emit(code, 1, outputs, input_count, inputs); |
| 104 Emit(opcode | AddressingModeField::encode(kMode_MR1I), | |
| 105 g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(index)); | |
| 106 } | |
| 107 // TODO(turbofan): addressing modes [r+r*{2,4,8}+K] | |
| 108 } | 261 } |
| 109 | 262 |
| 110 | 263 |
| 111 void InstructionSelector::VisitStore(Node* node) { | 264 void InstructionSelector::VisitStore(Node* node) { |
| 112 X64OperandGenerator g(this); | 265 X64OperandGenerator g(this); |
| 113 Node* base = node->InputAt(0); | 266 Node* base = node->InputAt(0); |
| 114 Node* index = node->InputAt(1); | 267 Node* index = node->InputAt(1); |
| 115 Node* value = node->InputAt(2); | 268 Node* value = node->InputAt(2); |
| 116 | 269 |
| 117 StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node); | 270 StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node); |
| 118 MachineType rep = RepresentationOf(store_rep.machine_type()); | 271 MachineType rep = RepresentationOf(store_rep.machine_type()); |
| 119 if (store_rep.write_barrier_kind() == kFullWriteBarrier) { | 272 if (store_rep.write_barrier_kind() == kFullWriteBarrier) { |
| 120 DCHECK(rep == kRepTagged); | 273 DCHECK(rep == kRepTagged); |
| 121 // TODO(dcarney): refactor RecordWrite function to take temp registers | 274 // TODO(dcarney): refactor RecordWrite function to take temp registers |
| 122 // and pass them here instead of using fixed regs | 275 // and pass them here instead of using fixed regs |
| 123 // TODO(dcarney): handle immediate indices. | 276 // TODO(dcarney): handle immediate indices. |
| 124 InstructionOperand* temps[] = {g.TempRegister(rcx), g.TempRegister(rdx)}; | 277 InstructionOperand* temps[] = {g.TempRegister(rcx), g.TempRegister(rdx)}; |
| 125 Emit(kX64StoreWriteBarrier, NULL, g.UseFixed(base, rbx), | 278 Emit(kX64StoreWriteBarrier, NULL, g.UseFixed(base, rbx), |
| 126 g.UseFixed(index, rcx), g.UseFixed(value, rdx), arraysize(temps), | 279 g.UseFixed(index, rcx), g.UseFixed(value, rdx), arraysize(temps), |
| 127 temps); | 280 temps); |
| 128 return; | 281 return; |
| 129 } | 282 } |
| 130 DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind()); | 283 DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind()); |
| 131 InstructionOperand* val; | |
| 132 if (g.CanBeImmediate(value)) { | |
| 133 val = g.UseImmediate(value); | |
| 134 } else if (rep == kRepWord8 || rep == kRepBit) { | |
| 135 val = g.UseByteRegister(value); | |
| 136 } else { | |
| 137 val = g.UseRegister(value); | |
| 138 } | |
| 139 ArchOpcode opcode; | 284 ArchOpcode opcode; |
| 140 switch (rep) { | 285 switch (rep) { |
| 141 case kRepFloat32: | 286 case kRepFloat32: |
| 142 opcode = kX64Movss; | 287 opcode = kX64Movss; |
| 143 break; | 288 break; |
| 144 case kRepFloat64: | 289 case kRepFloat64: |
| 145 opcode = kX64Movsd; | 290 opcode = kX64Movsd; |
| 146 break; | 291 break; |
| 147 case kRepBit: // Fall through. | 292 case kRepBit: // Fall through. |
| 148 case kRepWord8: | 293 case kRepWord8: |
| 149 opcode = kX64Movb; | 294 opcode = kX64Movb; |
| 150 break; | 295 break; |
| 151 case kRepWord16: | 296 case kRepWord16: |
| 152 opcode = kX64Movw; | 297 opcode = kX64Movw; |
| 153 break; | 298 break; |
| 154 case kRepWord32: | 299 case kRepWord32: |
| 155 opcode = kX64Movl; | 300 opcode = kX64Movl; |
| 156 break; | 301 break; |
| 157 case kRepTagged: // Fall through. | 302 case kRepTagged: // Fall through. |
| 158 case kRepWord64: | 303 case kRepWord64: |
| 159 opcode = kX64Movq; | 304 opcode = kX64Movq; |
| 160 break; | 305 break; |
| 161 default: | 306 default: |
| 162 UNREACHABLE(); | 307 UNREACHABLE(); |
| 163 return; | 308 return; |
| 164 } | 309 } |
| 165 if (g.CanBeImmediate(base)) { | 310 |
| 166 // store [#base + %index], %|#value | 311 InstructionOperand* val; |
| 167 Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL, | 312 if (g.CanBeImmediate(value)) { |
| 168 g.UseRegister(index), g.UseImmediate(base), val); | 313 val = g.UseImmediate(value); |
| 169 } else if (g.CanBeImmediate(index)) { // store [%base + #index], %|#value | 314 } else { |
| 170 Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL, | 315 val = g.UseRegister(value); |
| 171 g.UseRegister(base), g.UseImmediate(index), val); | |
| 172 } else { // store [%base + %index], %|#value | |
| 173 Emit(opcode | AddressingModeField::encode(kMode_MR1I), NULL, | |
| 174 g.UseRegister(base), g.UseRegister(index), val); | |
| 175 } | 316 } |
| 176 // TODO(turbofan): addressing modes [r+r*{2,4,8}+K] | 317 |
| 318 AddressingModeMatcher matcher(&g, base, index); | |
| 319 InstructionCode code = opcode | AddressingModeField::encode(matcher.mode_); | |
| 320 InstructionOperand* inputs[AddressingModeMatcher::kMaxInputCount + 1]; | |
| 321 int input_count = matcher.SetInputs(inputs); | |
| 322 inputs[input_count++] = val; | |
| 323 Emit(code, 0, static_cast<InstructionOperand**>(NULL), input_count, inputs); | |
| 177 } | 324 } |
| 178 | 325 |
| 179 | 326 |
| 180 // Shared routine for multiple binary operations. | 327 // Shared routine for multiple binary operations. |
| 181 static void VisitBinop(InstructionSelector* selector, Node* node, | 328 static void VisitBinop(InstructionSelector* selector, Node* node, |
| 182 InstructionCode opcode, FlagsContinuation* cont) { | 329 InstructionCode opcode, FlagsContinuation* cont) { |
| 183 X64OperandGenerator g(selector); | 330 X64OperandGenerator g(selector); |
| 184 Int32BinopMatcher m(node); | 331 Int32BinopMatcher m(node); |
| 185 Node* left = m.left().node(); | 332 Node* left = m.left().node(); |
| 186 Node* right = m.right().node(); | 333 Node* right = m.right().node(); |
| (...skipping 508 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 695 if (descriptor->NeedsFrameState()) { | 842 if (descriptor->NeedsFrameState()) { |
| 696 frame_state_descriptor = GetFrameStateDescriptor( | 843 frame_state_descriptor = GetFrameStateDescriptor( |
| 697 call->InputAt(static_cast<int>(descriptor->InputCount()))); | 844 call->InputAt(static_cast<int>(descriptor->InputCount()))); |
| 698 } | 845 } |
| 699 | 846 |
| 700 CallBuffer buffer(zone(), descriptor, frame_state_descriptor); | 847 CallBuffer buffer(zone(), descriptor, frame_state_descriptor); |
| 701 | 848 |
| 702 // Compute InstructionOperands for inputs and outputs. | 849 // Compute InstructionOperands for inputs and outputs. |
| 703 InitializeCallBuffer(call, &buffer, true, true); | 850 InitializeCallBuffer(call, &buffer, true, true); |
| 704 | 851 |
| 705 // TODO(dcarney): stack alignment for c calls. | |
| 706 // TODO(dcarney): shadow space on window for c calls. | |
| 707 // Push any stack arguments. | 852 // Push any stack arguments. |
| 708 for (NodeVectorRIter input = buffer.pushed_nodes.rbegin(); | 853 for (NodeVectorRIter input = buffer.pushed_nodes.rbegin(); |
| 709 input != buffer.pushed_nodes.rend(); input++) { | 854 input != buffer.pushed_nodes.rend(); input++) { |
| 710 // TODO(titzer): handle pushing double parameters. | 855 // TODO(titzer): handle pushing double parameters. |
| 711 Emit(kX64Push, NULL, | 856 Emit(kX64Push, NULL, |
| 712 g.CanBeImmediate(*input) ? g.UseImmediate(*input) : g.Use(*input)); | 857 g.CanBeImmediate(*input) ? g.UseImmediate(*input) : g.Use(*input)); |
| 713 } | 858 } |
| 714 | 859 |
| 715 // Select the appropriate opcode based on the call type. | 860 // Select the appropriate opcode based on the call type. |
| 716 InstructionCode opcode; | 861 InstructionCode opcode; |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 736 call_instr->MarkAsCall(); | 881 call_instr->MarkAsCall(); |
| 737 if (deoptimization != NULL) { | 882 if (deoptimization != NULL) { |
| 738 DCHECK(continuation != NULL); | 883 DCHECK(continuation != NULL); |
| 739 call_instr->MarkAsControl(); | 884 call_instr->MarkAsControl(); |
| 740 } | 885 } |
| 741 } | 886 } |
| 742 | 887 |
| 743 } // namespace compiler | 888 } // namespace compiler |
| 744 } // namespace internal | 889 } // namespace internal |
| 745 } // namespace v8 | 890 } // namespace v8 |
| OLD | NEW |