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 #include "src/compiler/node-properties.h" | 7 #include "src/compiler/node-properties.h" |
8 | 8 |
9 namespace v8 { | 9 namespace v8 { |
10 namespace internal { | 10 namespace internal { |
11 namespace compiler { | 11 namespace compiler { |
12 | 12 |
13 // Adds IA32-specific methods for generating operands. | 13 // Adds IA32-specific methods for generating operands. |
14 class IA32OperandGenerator FINAL : public OperandGenerator { | 14 class IA32OperandGenerator FINAL : public OperandGenerator { |
15 public: | 15 public: |
16 explicit IA32OperandGenerator(InstructionSelector* selector) | 16 explicit IA32OperandGenerator(InstructionSelector* selector) |
17 : OperandGenerator(selector) {} | 17 : OperandGenerator(selector) {} |
18 | 18 |
19 InstructionOperand* UseByteRegister(Node* node) { | 19 InstructionOperand UseByteRegister(Node* node) { |
20 // TODO(dcarney): relax constraint. | 20 // TODO(dcarney): relax constraint. |
21 return UseFixed(node, edx); | 21 return UseFixed(node, edx); |
22 } | 22 } |
23 | 23 |
24 bool CanBeImmediate(Node* node) { | 24 bool CanBeImmediate(Node* node) { |
25 switch (node->opcode()) { | 25 switch (node->opcode()) { |
26 case IrOpcode::kInt32Constant: | 26 case IrOpcode::kInt32Constant: |
27 case IrOpcode::kNumberConstant: | 27 case IrOpcode::kNumberConstant: |
28 case IrOpcode::kExternalConstant: | 28 case IrOpcode::kExternalConstant: |
29 return true; | 29 return true; |
30 case IrOpcode::kHeapConstant: { | 30 case IrOpcode::kHeapConstant: { |
31 // Constants in new space cannot be used as immediates in V8 because | 31 // Constants in new space cannot be used as immediates in V8 because |
32 // the GC does not scan code objects when collecting the new generation. | 32 // the GC does not scan code objects when collecting the new generation. |
33 Unique<HeapObject> value = OpParameter<Unique<HeapObject> >(node); | 33 Unique<HeapObject> value = OpParameter<Unique<HeapObject> >(node); |
34 Isolate* isolate = value.handle()->GetIsolate(); | 34 Isolate* isolate = value.handle()->GetIsolate(); |
35 return !isolate->heap()->InNewSpace(*value.handle()); | 35 return !isolate->heap()->InNewSpace(*value.handle()); |
36 } | 36 } |
37 default: | 37 default: |
38 return false; | 38 return false; |
39 } | 39 } |
40 } | 40 } |
41 | 41 |
42 AddressingMode GenerateMemoryOperandInputs(Node* index, int scale, Node* base, | 42 AddressingMode GenerateMemoryOperandInputs(Node* index, int scale, Node* base, |
43 Node* displacement_node, | 43 Node* displacement_node, |
44 InstructionOperand* inputs[], | 44 InstructionOperand inputs[], |
45 size_t* input_count) { | 45 size_t* input_count) { |
46 AddressingMode mode = kMode_MRI; | 46 AddressingMode mode = kMode_MRI; |
47 int32_t displacement = (displacement_node == NULL) | 47 int32_t displacement = (displacement_node == NULL) |
48 ? 0 | 48 ? 0 |
49 : OpParameter<int32_t>(displacement_node); | 49 : OpParameter<int32_t>(displacement_node); |
50 if (base != NULL) { | 50 if (base != NULL) { |
51 if (base->opcode() == IrOpcode::kInt32Constant) { | 51 if (base->opcode() == IrOpcode::kInt32Constant) { |
52 displacement += OpParameter<int32_t>(base); | 52 displacement += OpParameter<int32_t>(base); |
53 base = NULL; | 53 base = NULL; |
54 } | 54 } |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
92 } | 92 } |
93 } else { | 93 } else { |
94 inputs[(*input_count)++] = TempImmediate(displacement); | 94 inputs[(*input_count)++] = TempImmediate(displacement); |
95 return kMode_MI; | 95 return kMode_MI; |
96 } | 96 } |
97 } | 97 } |
98 return mode; | 98 return mode; |
99 } | 99 } |
100 | 100 |
101 AddressingMode GetEffectiveAddressMemoryOperand(Node* node, | 101 AddressingMode GetEffectiveAddressMemoryOperand(Node* node, |
102 InstructionOperand* inputs[], | 102 InstructionOperand inputs[], |
103 size_t* input_count) { | 103 size_t* input_count) { |
104 BaseWithIndexAndDisplacement32Matcher m(node, true); | 104 BaseWithIndexAndDisplacement32Matcher m(node, true); |
105 DCHECK(m.matches()); | 105 DCHECK(m.matches()); |
106 if ((m.displacement() == NULL || CanBeImmediate(m.displacement()))) { | 106 if ((m.displacement() == NULL || CanBeImmediate(m.displacement()))) { |
107 return GenerateMemoryOperandInputs(m.index(), m.scale(), m.base(), | 107 return GenerateMemoryOperandInputs(m.index(), m.scale(), m.base(), |
108 m.displacement(), inputs, input_count); | 108 m.displacement(), inputs, input_count); |
109 } else { | 109 } else { |
110 inputs[(*input_count)++] = UseRegister(node->InputAt(0)); | 110 inputs[(*input_count)++] = UseRegister(node->InputAt(0)); |
111 inputs[(*input_count)++] = UseRegister(node->InputAt(1)); | 111 inputs[(*input_count)++] = UseRegister(node->InputAt(1)); |
112 return kMode_MR1; | 112 return kMode_MR1; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
150 case kRepTagged: // Fall through. | 150 case kRepTagged: // Fall through. |
151 case kRepWord32: | 151 case kRepWord32: |
152 opcode = kIA32Movl; | 152 opcode = kIA32Movl; |
153 break; | 153 break; |
154 default: | 154 default: |
155 UNREACHABLE(); | 155 UNREACHABLE(); |
156 return; | 156 return; |
157 } | 157 } |
158 | 158 |
159 IA32OperandGenerator g(this); | 159 IA32OperandGenerator g(this); |
160 InstructionOperand* outputs[1]; | 160 InstructionOperand outputs[1]; |
161 outputs[0] = g.DefineAsRegister(node); | 161 outputs[0] = g.DefineAsRegister(node); |
162 InstructionOperand* inputs[3]; | 162 InstructionOperand inputs[3]; |
163 size_t input_count = 0; | 163 size_t input_count = 0; |
164 AddressingMode mode = | 164 AddressingMode mode = |
165 g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count); | 165 g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count); |
166 InstructionCode code = opcode | AddressingModeField::encode(mode); | 166 InstructionCode code = opcode | AddressingModeField::encode(mode); |
167 Emit(code, 1, outputs, input_count, inputs); | 167 Emit(code, 1, outputs, input_count, inputs); |
168 } | 168 } |
169 | 169 |
170 | 170 |
171 void InstructionSelector::VisitStore(Node* node) { | 171 void InstructionSelector::VisitStore(Node* node) { |
172 IA32OperandGenerator g(this); | 172 IA32OperandGenerator g(this); |
173 Node* base = node->InputAt(0); | 173 Node* base = node->InputAt(0); |
174 Node* index = node->InputAt(1); | 174 Node* index = node->InputAt(1); |
175 Node* value = node->InputAt(2); | 175 Node* value = node->InputAt(2); |
176 | 176 |
177 StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node); | 177 StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node); |
178 MachineType rep = RepresentationOf(store_rep.machine_type()); | 178 MachineType rep = RepresentationOf(store_rep.machine_type()); |
179 if (store_rep.write_barrier_kind() == kFullWriteBarrier) { | 179 if (store_rep.write_barrier_kind() == kFullWriteBarrier) { |
180 DCHECK_EQ(kRepTagged, rep); | 180 DCHECK_EQ(kRepTagged, rep); |
181 // TODO(dcarney): refactor RecordWrite function to take temp registers | 181 // TODO(dcarney): refactor RecordWrite function to take temp registers |
182 // and pass them here instead of using fixed regs | 182 // and pass them here instead of using fixed regs |
183 // TODO(dcarney): handle immediate indices. | 183 // TODO(dcarney): handle immediate indices. |
184 InstructionOperand* temps[] = {g.TempRegister(ecx), g.TempRegister(edx)}; | 184 InstructionOperand temps[] = {g.TempRegister(ecx), g.TempRegister(edx)}; |
185 Emit(kIA32StoreWriteBarrier, NULL, g.UseFixed(base, ebx), | 185 Emit(kIA32StoreWriteBarrier, g.NoOutput(), g.UseFixed(base, ebx), |
186 g.UseFixed(index, ecx), g.UseFixed(value, edx), arraysize(temps), | 186 g.UseFixed(index, ecx), g.UseFixed(value, edx), arraysize(temps), |
187 temps); | 187 temps); |
188 return; | 188 return; |
189 } | 189 } |
190 DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind()); | 190 DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind()); |
191 | 191 |
192 ArchOpcode opcode; | 192 ArchOpcode opcode; |
193 switch (rep) { | 193 switch (rep) { |
194 case kRepFloat32: | 194 case kRepFloat32: |
195 opcode = kIA32Movss; | 195 opcode = kIA32Movss; |
(...skipping 10 matching lines...) Expand all Loading... |
206 break; | 206 break; |
207 case kRepTagged: // Fall through. | 207 case kRepTagged: // Fall through. |
208 case kRepWord32: | 208 case kRepWord32: |
209 opcode = kIA32Movl; | 209 opcode = kIA32Movl; |
210 break; | 210 break; |
211 default: | 211 default: |
212 UNREACHABLE(); | 212 UNREACHABLE(); |
213 return; | 213 return; |
214 } | 214 } |
215 | 215 |
216 InstructionOperand* val; | 216 InstructionOperand val; |
217 if (g.CanBeImmediate(value)) { | 217 if (g.CanBeImmediate(value)) { |
218 val = g.UseImmediate(value); | 218 val = g.UseImmediate(value); |
219 } else if (rep == kRepWord8 || rep == kRepBit) { | 219 } else if (rep == kRepWord8 || rep == kRepBit) { |
220 val = g.UseByteRegister(value); | 220 val = g.UseByteRegister(value); |
221 } else { | 221 } else { |
222 val = g.UseRegister(value); | 222 val = g.UseRegister(value); |
223 } | 223 } |
224 | 224 |
225 InstructionOperand* inputs[4]; | 225 InstructionOperand inputs[4]; |
226 size_t input_count = 0; | 226 size_t input_count = 0; |
227 AddressingMode mode = | 227 AddressingMode mode = |
228 g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count); | 228 g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count); |
229 InstructionCode code = opcode | AddressingModeField::encode(mode); | 229 InstructionCode code = opcode | AddressingModeField::encode(mode); |
230 inputs[input_count++] = val; | 230 inputs[input_count++] = val; |
231 Emit(code, 0, static_cast<InstructionOperand**>(NULL), input_count, inputs); | 231 Emit(code, 0, static_cast<InstructionOperand*>(NULL), input_count, inputs); |
232 } | 232 } |
233 | 233 |
234 | 234 |
235 void InstructionSelector::VisitCheckedLoad(Node* node) { | 235 void InstructionSelector::VisitCheckedLoad(Node* node) { |
236 MachineType rep = RepresentationOf(OpParameter<MachineType>(node)); | 236 MachineType rep = RepresentationOf(OpParameter<MachineType>(node)); |
237 MachineType typ = TypeOf(OpParameter<MachineType>(node)); | 237 MachineType typ = TypeOf(OpParameter<MachineType>(node)); |
238 IA32OperandGenerator g(this); | 238 IA32OperandGenerator g(this); |
239 Node* const buffer = node->InputAt(0); | 239 Node* const buffer = node->InputAt(0); |
240 Node* const offset = node->InputAt(1); | 240 Node* const offset = node->InputAt(1); |
241 Node* const length = node->InputAt(2); | 241 Node* const length = node->InputAt(2); |
(...skipping 11 matching lines...) Expand all Loading... |
253 case kRepFloat32: | 253 case kRepFloat32: |
254 opcode = kCheckedLoadFloat32; | 254 opcode = kCheckedLoadFloat32; |
255 break; | 255 break; |
256 case kRepFloat64: | 256 case kRepFloat64: |
257 opcode = kCheckedLoadFloat64; | 257 opcode = kCheckedLoadFloat64; |
258 break; | 258 break; |
259 default: | 259 default: |
260 UNREACHABLE(); | 260 UNREACHABLE(); |
261 return; | 261 return; |
262 } | 262 } |
263 InstructionOperand* offset_operand = g.UseRegister(offset); | 263 InstructionOperand offset_operand = g.UseRegister(offset); |
264 InstructionOperand* length_operand = | 264 InstructionOperand length_operand = |
265 g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length); | 265 g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length); |
266 if (g.CanBeImmediate(buffer)) { | 266 if (g.CanBeImmediate(buffer)) { |
267 Emit(opcode | AddressingModeField::encode(kMode_MRI), | 267 Emit(opcode | AddressingModeField::encode(kMode_MRI), |
268 g.DefineAsRegister(node), offset_operand, length_operand, | 268 g.DefineAsRegister(node), offset_operand, length_operand, |
269 offset_operand, g.UseImmediate(buffer)); | 269 offset_operand, g.UseImmediate(buffer)); |
270 } else { | 270 } else { |
271 Emit(opcode | AddressingModeField::encode(kMode_MR1), | 271 Emit(opcode | AddressingModeField::encode(kMode_MR1), |
272 g.DefineAsRegister(node), offset_operand, length_operand, | 272 g.DefineAsRegister(node), offset_operand, length_operand, |
273 g.UseRegister(buffer), offset_operand); | 273 g.UseRegister(buffer), offset_operand); |
274 } | 274 } |
(...skipping 21 matching lines...) Expand all Loading... |
296 case kRepFloat32: | 296 case kRepFloat32: |
297 opcode = kCheckedStoreFloat32; | 297 opcode = kCheckedStoreFloat32; |
298 break; | 298 break; |
299 case kRepFloat64: | 299 case kRepFloat64: |
300 opcode = kCheckedStoreFloat64; | 300 opcode = kCheckedStoreFloat64; |
301 break; | 301 break; |
302 default: | 302 default: |
303 UNREACHABLE(); | 303 UNREACHABLE(); |
304 return; | 304 return; |
305 } | 305 } |
306 InstructionOperand* value_operand = | 306 InstructionOperand value_operand = |
307 g.CanBeImmediate(value) | 307 g.CanBeImmediate(value) |
308 ? g.UseImmediate(value) | 308 ? g.UseImmediate(value) |
309 : ((rep == kRepWord8 || rep == kRepBit) ? g.UseByteRegister(value) | 309 : ((rep == kRepWord8 || rep == kRepBit) ? g.UseByteRegister(value) |
310 : g.UseRegister(value)); | 310 : g.UseRegister(value)); |
311 InstructionOperand* offset_operand = g.UseRegister(offset); | 311 InstructionOperand offset_operand = g.UseRegister(offset); |
312 InstructionOperand* length_operand = | 312 InstructionOperand length_operand = |
313 g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length); | 313 g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length); |
314 if (g.CanBeImmediate(buffer)) { | 314 if (g.CanBeImmediate(buffer)) { |
315 Emit(opcode | AddressingModeField::encode(kMode_MRI), nullptr, | 315 Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(), |
316 offset_operand, length_operand, value_operand, offset_operand, | 316 offset_operand, length_operand, value_operand, offset_operand, |
317 g.UseImmediate(buffer)); | 317 g.UseImmediate(buffer)); |
318 } else { | 318 } else { |
319 Emit(opcode | AddressingModeField::encode(kMode_MR1), nullptr, | 319 Emit(opcode | AddressingModeField::encode(kMode_MR1), g.NoOutput(), |
320 offset_operand, length_operand, value_operand, g.UseRegister(buffer), | 320 offset_operand, length_operand, value_operand, g.UseRegister(buffer), |
321 offset_operand); | 321 offset_operand); |
322 } | 322 } |
323 } | 323 } |
324 | 324 |
325 | 325 |
326 // Shared routine for multiple binary operations. | 326 // Shared routine for multiple binary operations. |
327 static void VisitBinop(InstructionSelector* selector, Node* node, | 327 static void VisitBinop(InstructionSelector* selector, Node* node, |
328 InstructionCode opcode, FlagsContinuation* cont) { | 328 InstructionCode opcode, FlagsContinuation* cont) { |
329 IA32OperandGenerator g(selector); | 329 IA32OperandGenerator g(selector); |
330 Int32BinopMatcher m(node); | 330 Int32BinopMatcher m(node); |
331 Node* left = m.left().node(); | 331 Node* left = m.left().node(); |
332 Node* right = m.right().node(); | 332 Node* right = m.right().node(); |
333 InstructionOperand* inputs[4]; | 333 InstructionOperand inputs[4]; |
334 size_t input_count = 0; | 334 size_t input_count = 0; |
335 InstructionOperand* outputs[2]; | 335 InstructionOperand outputs[2]; |
336 size_t output_count = 0; | 336 size_t output_count = 0; |
337 | 337 |
338 // TODO(turbofan): match complex addressing modes. | 338 // TODO(turbofan): match complex addressing modes. |
339 if (left == right) { | 339 if (left == right) { |
340 // If both inputs refer to the same operand, enforce allocating a register | 340 // If both inputs refer to the same operand, enforce allocating a register |
341 // for both of them to ensure that we don't end up generating code like | 341 // for both of them to ensure that we don't end up generating code like |
342 // this: | 342 // this: |
343 // | 343 // |
344 // mov eax, [ebp-0x10] | 344 // mov eax, [ebp-0x10] |
345 // add eax, [ebp-0x10] | 345 // add eax, [ebp-0x10] |
346 // jo label | 346 // jo label |
347 InstructionOperand* const input = g.UseRegister(left); | 347 InstructionOperand const input = g.UseRegister(left); |
348 inputs[input_count++] = input; | 348 inputs[input_count++] = input; |
349 inputs[input_count++] = input; | 349 inputs[input_count++] = input; |
350 } else if (g.CanBeImmediate(right)) { | 350 } else if (g.CanBeImmediate(right)) { |
351 inputs[input_count++] = g.UseRegister(left); | 351 inputs[input_count++] = g.UseRegister(left); |
352 inputs[input_count++] = g.UseImmediate(right); | 352 inputs[input_count++] = g.UseImmediate(right); |
353 } else { | 353 } else { |
354 if (node->op()->HasProperty(Operator::kCommutative) && | 354 if (node->op()->HasProperty(Operator::kCommutative) && |
355 g.CanBeBetterLeftOperand(right)) { | 355 g.CanBeBetterLeftOperand(right)) { |
356 std::swap(left, right); | 356 std::swap(left, right); |
357 } | 357 } |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
433 ArchOpcode opcode) { | 433 ArchOpcode opcode) { |
434 IA32OperandGenerator g(selector); | 434 IA32OperandGenerator g(selector); |
435 selector->Emit(opcode, g.DefineAsFixed(node, edx), | 435 selector->Emit(opcode, g.DefineAsFixed(node, edx), |
436 g.UseFixed(node->InputAt(0), eax), | 436 g.UseFixed(node->InputAt(0), eax), |
437 g.UseUniqueRegister(node->InputAt(1))); | 437 g.UseUniqueRegister(node->InputAt(1))); |
438 } | 438 } |
439 | 439 |
440 | 440 |
441 void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode opcode) { | 441 void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode opcode) { |
442 IA32OperandGenerator g(selector); | 442 IA32OperandGenerator g(selector); |
443 InstructionOperand* temps[] = {g.TempRegister(edx)}; | 443 InstructionOperand temps[] = {g.TempRegister(edx)}; |
444 selector->Emit(opcode, g.DefineAsFixed(node, eax), | 444 selector->Emit(opcode, g.DefineAsFixed(node, eax), |
445 g.UseFixed(node->InputAt(0), eax), | 445 g.UseFixed(node->InputAt(0), eax), |
446 g.UseUnique(node->InputAt(1)), arraysize(temps), temps); | 446 g.UseUnique(node->InputAt(1)), arraysize(temps), temps); |
447 } | 447 } |
448 | 448 |
449 | 449 |
450 void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode opcode) { | 450 void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode opcode) { |
451 IA32OperandGenerator g(selector); | 451 IA32OperandGenerator g(selector); |
452 selector->Emit(opcode, g.DefineAsFixed(node, edx), | 452 selector->Emit(opcode, g.DefineAsFixed(node, edx), |
453 g.UseFixed(node->InputAt(0), eax), | 453 g.UseFixed(node->InputAt(0), eax), |
454 g.UseUnique(node->InputAt(1))); | 454 g.UseUnique(node->InputAt(1))); |
455 } | 455 } |
456 | 456 |
457 void EmitLea(InstructionSelector* selector, Node* result, Node* index, | 457 void EmitLea(InstructionSelector* selector, Node* result, Node* index, |
458 int scale, Node* base, Node* displacement) { | 458 int scale, Node* base, Node* displacement) { |
459 IA32OperandGenerator g(selector); | 459 IA32OperandGenerator g(selector); |
460 InstructionOperand* inputs[4]; | 460 InstructionOperand inputs[4]; |
461 size_t input_count = 0; | 461 size_t input_count = 0; |
462 AddressingMode mode = g.GenerateMemoryOperandInputs( | 462 AddressingMode mode = g.GenerateMemoryOperandInputs( |
463 index, scale, base, displacement, inputs, &input_count); | 463 index, scale, base, displacement, inputs, &input_count); |
464 | 464 |
465 DCHECK_NE(0, static_cast<int>(input_count)); | 465 DCHECK_NE(0, static_cast<int>(input_count)); |
466 DCHECK_GE(arraysize(inputs), input_count); | 466 DCHECK_GE(arraysize(inputs), input_count); |
467 | 467 |
468 InstructionOperand* outputs[1]; | 468 InstructionOperand outputs[1]; |
469 outputs[0] = g.DefineAsRegister(result); | 469 outputs[0] = g.DefineAsRegister(result); |
470 | 470 |
471 InstructionCode opcode = AddressingModeField::encode(mode) | kIA32Lea; | 471 InstructionCode opcode = AddressingModeField::encode(mode) | kIA32Lea; |
472 | 472 |
473 selector->Emit(opcode, 1, outputs, input_count, inputs); | 473 selector->Emit(opcode, 1, outputs, input_count, inputs); |
474 } | 474 } |
475 | 475 |
476 } // namespace | 476 } // namespace |
477 | 477 |
478 | 478 |
(...skipping 24 matching lines...) Expand all Loading... |
503 } | 503 } |
504 | 504 |
505 | 505 |
506 void InstructionSelector::VisitInt32Add(Node* node) { | 506 void InstructionSelector::VisitInt32Add(Node* node) { |
507 IA32OperandGenerator g(this); | 507 IA32OperandGenerator g(this); |
508 | 508 |
509 // Try to match the Add to a lea pattern | 509 // Try to match the Add to a lea pattern |
510 BaseWithIndexAndDisplacement32Matcher m(node); | 510 BaseWithIndexAndDisplacement32Matcher m(node); |
511 if (m.matches() && | 511 if (m.matches() && |
512 (m.displacement() == NULL || g.CanBeImmediate(m.displacement()))) { | 512 (m.displacement() == NULL || g.CanBeImmediate(m.displacement()))) { |
513 InstructionOperand* inputs[4]; | 513 InstructionOperand inputs[4]; |
514 size_t input_count = 0; | 514 size_t input_count = 0; |
515 AddressingMode mode = g.GenerateMemoryOperandInputs( | 515 AddressingMode mode = g.GenerateMemoryOperandInputs( |
516 m.index(), m.scale(), m.base(), m.displacement(), inputs, &input_count); | 516 m.index(), m.scale(), m.base(), m.displacement(), inputs, &input_count); |
517 | 517 |
518 DCHECK_NE(0, static_cast<int>(input_count)); | 518 DCHECK_NE(0, static_cast<int>(input_count)); |
519 DCHECK_GE(arraysize(inputs), input_count); | 519 DCHECK_GE(arraysize(inputs), input_count); |
520 | 520 |
521 InstructionOperand* outputs[1]; | 521 InstructionOperand outputs[1]; |
522 outputs[0] = g.DefineAsRegister(node); | 522 outputs[0] = g.DefineAsRegister(node); |
523 | 523 |
524 InstructionCode opcode = AddressingModeField::encode(mode) | kIA32Lea; | 524 InstructionCode opcode = AddressingModeField::encode(mode) | kIA32Lea; |
525 Emit(opcode, 1, outputs, input_count, inputs); | 525 Emit(opcode, 1, outputs, input_count, inputs); |
526 return; | 526 return; |
527 } | 527 } |
528 | 528 |
529 // No lea pattern match, use add | 529 // No lea pattern match, use add |
530 VisitBinop(this, node, kIA32Add); | 530 VisitBinop(this, node, kIA32Add); |
531 } | 531 } |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
675 g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1))); | 675 g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1))); |
676 } else { | 676 } else { |
677 Emit(kSSEFloat64Div, g.DefineSameAsFirst(node), | 677 Emit(kSSEFloat64Div, g.DefineSameAsFirst(node), |
678 g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1))); | 678 g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1))); |
679 } | 679 } |
680 } | 680 } |
681 | 681 |
682 | 682 |
683 void InstructionSelector::VisitFloat64Mod(Node* node) { | 683 void InstructionSelector::VisitFloat64Mod(Node* node) { |
684 IA32OperandGenerator g(this); | 684 IA32OperandGenerator g(this); |
685 InstructionOperand* temps[] = {g.TempRegister(eax)}; | 685 InstructionOperand temps[] = {g.TempRegister(eax)}; |
686 Emit(kSSEFloat64Mod, g.DefineSameAsFirst(node), | 686 Emit(kSSEFloat64Mod, g.DefineSameAsFirst(node), |
687 g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)), 1, | 687 g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)), 1, |
688 temps); | 688 temps); |
689 } | 689 } |
690 | 690 |
691 | 691 |
692 void InstructionSelector::VisitFloat64Sqrt(Node* node) { | 692 void InstructionSelector::VisitFloat64Sqrt(Node* node) { |
693 IA32OperandGenerator g(this); | 693 IA32OperandGenerator g(this); |
694 Emit(kSSEFloat64Sqrt, g.DefineAsRegister(node), g.Use(node->InputAt(0))); | 694 Emit(kSSEFloat64Sqrt, g.DefineAsRegister(node), g.Use(node->InputAt(0))); |
695 } | 695 } |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
731 | 731 |
732 CallBuffer buffer(zone(), descriptor, frame_state_descriptor); | 732 CallBuffer buffer(zone(), descriptor, frame_state_descriptor); |
733 | 733 |
734 // Compute InstructionOperands for inputs and outputs. | 734 // Compute InstructionOperands for inputs and outputs. |
735 InitializeCallBuffer(node, &buffer, true, true); | 735 InitializeCallBuffer(node, &buffer, true, true); |
736 | 736 |
737 // Push any stack arguments. | 737 // Push any stack arguments. |
738 for (auto i = buffer.pushed_nodes.rbegin(); i != buffer.pushed_nodes.rend(); | 738 for (auto i = buffer.pushed_nodes.rbegin(); i != buffer.pushed_nodes.rend(); |
739 ++i) { | 739 ++i) { |
740 // TODO(titzer): handle pushing double parameters. | 740 // TODO(titzer): handle pushing double parameters. |
741 InstructionOperand* value = | 741 InstructionOperand value = |
742 g.CanBeImmediate(*i) ? g.UseImmediate(*i) : IsSupported(ATOM) | 742 g.CanBeImmediate(*i) ? g.UseImmediate(*i) : IsSupported(ATOM) |
743 ? g.UseRegister(*i) | 743 ? g.UseRegister(*i) |
744 : g.Use(*i); | 744 : g.Use(*i); |
745 Emit(kIA32Push, nullptr, value); | 745 Emit(kIA32Push, g.NoOutput(), value); |
746 } | 746 } |
747 | 747 |
748 // Select the appropriate opcode based on the call type. | 748 // Select the appropriate opcode based on the call type. |
749 InstructionCode opcode; | 749 InstructionCode opcode; |
750 switch (descriptor->kind()) { | 750 switch (descriptor->kind()) { |
751 case CallDescriptor::kCallCodeObject: { | 751 case CallDescriptor::kCallCodeObject: { |
752 opcode = kArchCallCodeObject; | 752 opcode = kArchCallCodeObject; |
753 break; | 753 break; |
754 } | 754 } |
755 case CallDescriptor::kCallJSFunction: | 755 case CallDescriptor::kCallJSFunction: |
756 opcode = kArchCallJSFunction; | 756 opcode = kArchCallJSFunction; |
757 break; | 757 break; |
758 default: | 758 default: |
759 UNREACHABLE(); | 759 UNREACHABLE(); |
760 return; | 760 return; |
761 } | 761 } |
762 opcode |= MiscField::encode(descriptor->flags()); | 762 opcode |= MiscField::encode(descriptor->flags()); |
763 | 763 |
764 // Emit the call instruction. | 764 // Emit the call instruction. |
765 InstructionOperand** first_output = | 765 InstructionOperand* first_output = |
766 buffer.outputs.size() > 0 ? &buffer.outputs.front() : NULL; | 766 buffer.outputs.size() > 0 ? &buffer.outputs.front() : NULL; |
767 Instruction* call_instr = | 767 Instruction* call_instr = |
768 Emit(opcode, buffer.outputs.size(), first_output, | 768 Emit(opcode, buffer.outputs.size(), first_output, |
769 buffer.instruction_args.size(), &buffer.instruction_args.front()); | 769 buffer.instruction_args.size(), &buffer.instruction_args.front()); |
770 call_instr->MarkAsCall(); | 770 call_instr->MarkAsCall(); |
771 } | 771 } |
772 | 772 |
773 | 773 |
774 namespace { | 774 namespace { |
775 | 775 |
776 // Shared routine for multiple compare operations. | 776 // Shared routine for multiple compare operations. |
777 void VisitCompare(InstructionSelector* selector, InstructionCode opcode, | 777 void VisitCompare(InstructionSelector* selector, InstructionCode opcode, |
778 InstructionOperand* left, InstructionOperand* right, | 778 InstructionOperand left, InstructionOperand right, |
779 FlagsContinuation* cont) { | 779 FlagsContinuation* cont) { |
780 IA32OperandGenerator g(selector); | 780 IA32OperandGenerator g(selector); |
781 if (cont->IsBranch()) { | 781 if (cont->IsBranch()) { |
782 selector->Emit(cont->Encode(opcode), NULL, left, right, | 782 selector->Emit(cont->Encode(opcode), g.NoOutput(), left, right, |
783 g.Label(cont->true_block()), | 783 g.Label(cont->true_block()), |
784 g.Label(cont->false_block()))->MarkAsControl(); | 784 g.Label(cont->false_block()))->MarkAsControl(); |
785 } else { | 785 } else { |
786 DCHECK(cont->IsSet()); | 786 DCHECK(cont->IsSet()); |
787 // TODO(titzer): Needs byte register. | 787 // TODO(titzer): Needs byte register. |
788 selector->Emit(cont->Encode(opcode), g.DefineAsRegister(cont->result()), | 788 selector->Emit(cont->Encode(opcode), g.DefineAsRegister(cont->result()), |
789 left, right); | 789 left, right); |
790 } | 790 } |
791 } | 791 } |
792 | 792 |
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1008 MachineOperatorBuilder::kFloat64Ceil | | 1008 MachineOperatorBuilder::kFloat64Ceil | |
1009 MachineOperatorBuilder::kFloat64RoundTruncate | | 1009 MachineOperatorBuilder::kFloat64RoundTruncate | |
1010 MachineOperatorBuilder::kWord32ShiftIsSafe; | 1010 MachineOperatorBuilder::kWord32ShiftIsSafe; |
1011 } | 1011 } |
1012 return MachineOperatorBuilder::Flag::kNoFlags; | 1012 return MachineOperatorBuilder::Flag::kNoFlags; |
1013 } | 1013 } |
1014 | 1014 |
1015 } // namespace compiler | 1015 } // namespace compiler |
1016 } // namespace internal | 1016 } // namespace internal |
1017 } // namespace v8 | 1017 } // namespace v8 |
OLD | NEW |