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