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

Side by Side Diff: src/compiler/ia32/instruction-selector-ia32.cc

Issue 426233002: Land the Fan (disabled) (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Review feedback, rebase and "git cl format" Created 6 years, 4 months 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/compiler/ia32/instruction-codes-ia32.h ('k') | src/compiler/ia32/linkage-ia32.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "src/compiler/instruction-selector-impl.h"
6 #include "src/compiler/node-matchers.h"
7 #include "src/compiler/node-properties-inl.h"
8
9 namespace v8 {
10 namespace internal {
11 namespace compiler {
12
13 // Adds IA32-specific methods for generating operands.
14 class IA32OperandGenerator V8_FINAL : public OperandGenerator {
15 public:
16 explicit IA32OperandGenerator(InstructionSelector* selector)
17 : OperandGenerator(selector) {}
18
19 InstructionOperand* UseByteRegister(Node* node) {
20 // TODO(dcarney): relax constraint.
21 return UseFixed(node, edx);
22 }
23
24 bool CanBeImmediate(Node* node) {
25 switch (node->opcode()) {
26 case IrOpcode::kInt32Constant:
27 case IrOpcode::kNumberConstant:
28 case IrOpcode::kExternalConstant:
29 return true;
30 case IrOpcode::kHeapConstant: {
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.
33 Handle<HeapObject> value = ValueOf<Handle<HeapObject> >(node->op());
34 return !isolate()->heap()->InNewSpace(*value);
35 }
36 default:
37 return false;
38 }
39 }
40 };
41
42
43 void InstructionSelector::VisitLoad(Node* node) {
44 MachineRepresentation rep = OpParameter<MachineRepresentation>(node);
45 IA32OperandGenerator g(this);
46 Node* base = node->InputAt(0);
47 Node* index = node->InputAt(1);
48
49 InstructionOperand* output = rep == kMachineFloat64
50 ? g.DefineAsDoubleRegister(node)
51 : g.DefineAsRegister(node);
52 ArchOpcode opcode;
53 switch (rep) {
54 case kMachineFloat64:
55 opcode = kSSELoad;
56 break;
57 case kMachineWord8:
58 opcode = kIA32LoadWord8;
59 break;
60 case kMachineWord16:
61 opcode = kIA32LoadWord16;
62 break;
63 case kMachineTagged: // Fall through.
64 case kMachineWord32:
65 opcode = kIA32LoadWord32;
66 break;
67 default:
68 UNREACHABLE();
69 return;
70 }
71 if (g.CanBeImmediate(base)) {
72 if (Int32Matcher(index).Is(0)) { // load [#base + #0]
73 Emit(opcode | AddressingModeField::encode(kMode_MI), output,
74 g.UseImmediate(base));
75 } else { // load [#base + %index]
76 Emit(opcode | AddressingModeField::encode(kMode_MRI), output,
77 g.UseRegister(index), g.UseImmediate(base));
78 }
79 } else if (g.CanBeImmediate(index)) { // load [%base + #index]
80 Emit(opcode | AddressingModeField::encode(kMode_MRI), output,
81 g.UseRegister(base), g.UseImmediate(index));
82 } else { // load [%base + %index + K]
83 Emit(opcode | AddressingModeField::encode(kMode_MR1I), output,
84 g.UseRegister(base), g.UseRegister(index));
85 }
86 // TODO(turbofan): addressing modes [r+r*{2,4,8}+K]
87 }
88
89
90 void InstructionSelector::VisitStore(Node* node) {
91 IA32OperandGenerator g(this);
92 Node* base = node->InputAt(0);
93 Node* index = node->InputAt(1);
94 Node* value = node->InputAt(2);
95
96 StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node);
97 MachineRepresentation rep = store_rep.rep;
98 if (store_rep.write_barrier_kind == kFullWriteBarrier) {
99 ASSERT_EQ(kMachineTagged, rep);
100 // TODO(dcarney): refactor RecordWrite function to take temp registers
101 // and pass them here instead of using fixed regs
102 // TODO(dcarney): handle immediate indices.
103 InstructionOperand* temps[] = {g.TempRegister(ecx), g.TempRegister(edx)};
104 Emit(kIA32StoreWriteBarrier, NULL, g.UseFixed(base, ebx),
105 g.UseFixed(index, ecx), g.UseFixed(value, edx), ARRAY_SIZE(temps),
106 temps);
107 return;
108 }
109 ASSERT_EQ(kNoWriteBarrier, store_rep.write_barrier_kind);
110 bool is_immediate = false;
111 InstructionOperand* val;
112 if (rep == kMachineFloat64) {
113 val = g.UseDoubleRegister(value);
114 } else {
115 is_immediate = g.CanBeImmediate(value);
116 if (is_immediate) {
117 val = g.UseImmediate(value);
118 } else if (rep == kMachineWord8) {
119 val = g.UseByteRegister(value);
120 } else {
121 val = g.UseRegister(value);
122 }
123 }
124 ArchOpcode opcode;
125 switch (rep) {
126 case kMachineFloat64:
127 opcode = kSSEStore;
128 break;
129 case kMachineWord8:
130 opcode = is_immediate ? kIA32StoreWord8I : kIA32StoreWord8;
131 break;
132 case kMachineWord16:
133 opcode = is_immediate ? kIA32StoreWord16I : kIA32StoreWord16;
134 break;
135 case kMachineTagged: // Fall through.
136 case kMachineWord32:
137 opcode = is_immediate ? kIA32StoreWord32I : kIA32StoreWord32;
138 break;
139 default:
140 UNREACHABLE();
141 return;
142 }
143 if (g.CanBeImmediate(base)) {
144 if (Int32Matcher(index).Is(0)) { // store [#base], %|#value
145 Emit(opcode | AddressingModeField::encode(kMode_MI), NULL,
146 g.UseImmediate(base), val);
147 } else { // store [#base + %index], %|#value
148 Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL,
149 g.UseRegister(index), g.UseImmediate(base), val);
150 }
151 } else if (g.CanBeImmediate(index)) { // store [%base + #index], %|#value
152 Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL,
153 g.UseRegister(base), g.UseImmediate(index), val);
154 } else { // store [%base + %index], %|#value
155 Emit(opcode | AddressingModeField::encode(kMode_MR1I), NULL,
156 g.UseRegister(base), g.UseRegister(index), val);
157 }
158 // TODO(turbofan): addressing modes [r+r*{2,4,8}+K]
159 }
160
161
162 // Shared routine for multiple binary operations.
163 static inline void VisitBinop(InstructionSelector* selector, Node* node,
164 ArchOpcode opcode) {
165 IA32OperandGenerator g(selector);
166 Node* left = node->InputAt(0);
167 Node* right = node->InputAt(1);
168 // TODO(turbofan): match complex addressing modes.
169 // TODO(turbofan): if commutative, pick the non-live-in operand as the left as
170 // this might be the last use and therefore its register can be reused.
171 if (g.CanBeImmediate(right)) {
172 selector->Emit(opcode, g.DefineSameAsFirst(node), g.Use(left),
173 g.UseImmediate(right));
174 } else if (g.CanBeImmediate(left) &&
175 node->op()->HasProperty(Operator::kCommutative)) {
176 selector->Emit(opcode, g.DefineSameAsFirst(node), g.Use(right),
177 g.UseImmediate(left));
178 } else {
179 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
180 g.Use(right));
181 }
182 }
183
184
185 void InstructionSelector::VisitWord32And(Node* node) {
186 VisitBinop(this, node, kIA32And);
187 }
188
189
190 void InstructionSelector::VisitWord32Or(Node* node) {
191 VisitBinop(this, node, kIA32Or);
192 }
193
194
195 void InstructionSelector::VisitWord32Xor(Node* node) {
196 IA32OperandGenerator g(this);
197 Int32BinopMatcher m(node);
198 if (m.right().Is(-1)) {
199 Emit(kIA32Not, g.DefineSameAsFirst(node), g.Use(m.left().node()));
200 } else {
201 VisitBinop(this, node, kIA32Xor);
202 }
203 }
204
205
206 // Shared routine for multiple shift operations.
207 static inline void VisitShift(InstructionSelector* selector, Node* node,
208 ArchOpcode opcode) {
209 IA32OperandGenerator g(selector);
210 Node* left = node->InputAt(0);
211 Node* right = node->InputAt(1);
212
213 // TODO(turbofan): assembler only supports some addressing modes for shifts.
214 if (g.CanBeImmediate(right)) {
215 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
216 g.UseImmediate(right));
217 } else {
218 Int32BinopMatcher m(node);
219 if (m.right().IsWord32And()) {
220 Int32BinopMatcher mright(right);
221 if (mright.right().Is(0x1F)) {
222 right = mright.left().node();
223 }
224 }
225 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
226 g.UseFixed(right, ecx));
227 }
228 }
229
230
231 void InstructionSelector::VisitWord32Shl(Node* node) {
232 VisitShift(this, node, kIA32Shl);
233 }
234
235
236 void InstructionSelector::VisitWord32Shr(Node* node) {
237 VisitShift(this, node, kIA32Shr);
238 }
239
240
241 void InstructionSelector::VisitWord32Sar(Node* node) {
242 VisitShift(this, node, kIA32Sar);
243 }
244
245
246 void InstructionSelector::VisitInt32Add(Node* node) {
247 VisitBinop(this, node, kIA32Add);
248 }
249
250
251 void InstructionSelector::VisitInt32Sub(Node* node) {
252 IA32OperandGenerator g(this);
253 Int32BinopMatcher m(node);
254 if (m.left().Is(0)) {
255 Emit(kIA32Neg, g.DefineSameAsFirst(node), g.Use(m.right().node()));
256 } else {
257 VisitBinop(this, node, kIA32Sub);
258 }
259 }
260
261
262 void InstructionSelector::VisitInt32Mul(Node* node) {
263 IA32OperandGenerator g(this);
264 Node* left = node->InputAt(0);
265 Node* right = node->InputAt(1);
266 if (g.CanBeImmediate(right)) {
267 Emit(kIA32Imul, g.DefineAsRegister(node), g.Use(left),
268 g.UseImmediate(right));
269 } else if (g.CanBeImmediate(left)) {
270 Emit(kIA32Imul, g.DefineAsRegister(node), g.Use(right),
271 g.UseImmediate(left));
272 } else {
273 // TODO(turbofan): select better left operand.
274 Emit(kIA32Imul, g.DefineSameAsFirst(node), g.UseRegister(left),
275 g.Use(right));
276 }
277 }
278
279
280 static inline void VisitDiv(InstructionSelector* selector, Node* node,
281 ArchOpcode opcode) {
282 IA32OperandGenerator g(selector);
283 InstructionOperand* temps[] = {g.TempRegister(edx)};
284 size_t temp_count = ARRAY_SIZE(temps);
285 selector->Emit(opcode, g.DefineAsFixed(node, eax),
286 g.UseFixed(node->InputAt(0), eax),
287 g.UseUnique(node->InputAt(1)), temp_count, temps);
288 }
289
290
291 void InstructionSelector::VisitInt32Div(Node* node) {
292 VisitDiv(this, node, kIA32Idiv);
293 }
294
295
296 void InstructionSelector::VisitInt32UDiv(Node* node) {
297 VisitDiv(this, node, kIA32Udiv);
298 }
299
300
301 static inline void VisitMod(InstructionSelector* selector, Node* node,
302 ArchOpcode opcode) {
303 IA32OperandGenerator g(selector);
304 InstructionOperand* temps[] = {g.TempRegister(eax), g.TempRegister(edx)};
305 size_t temp_count = ARRAY_SIZE(temps);
306 selector->Emit(opcode, g.DefineAsFixed(node, edx),
307 g.UseFixed(node->InputAt(0), eax),
308 g.UseUnique(node->InputAt(1)), temp_count, temps);
309 }
310
311
312 void InstructionSelector::VisitInt32Mod(Node* node) {
313 VisitMod(this, node, kIA32Idiv);
314 }
315
316
317 void InstructionSelector::VisitInt32UMod(Node* node) {
318 VisitMod(this, node, kIA32Udiv);
319 }
320
321
322 void InstructionSelector::VisitConvertInt32ToFloat64(Node* node) {
323 IA32OperandGenerator g(this);
324 Emit(kSSEInt32ToFloat64, g.DefineAsDoubleRegister(node),
325 g.Use(node->InputAt(0)));
326 }
327
328
329 void InstructionSelector::VisitConvertFloat64ToInt32(Node* node) {
330 IA32OperandGenerator g(this);
331 Emit(kSSEFloat64ToInt32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
332 }
333
334
335 void InstructionSelector::VisitFloat64Add(Node* node) {
336 IA32OperandGenerator g(this);
337 Emit(kSSEFloat64Add, g.DefineSameAsFirst(node),
338 g.UseDoubleRegister(node->InputAt(0)),
339 g.UseDoubleRegister(node->InputAt(1)));
340 }
341
342
343 void InstructionSelector::VisitFloat64Sub(Node* node) {
344 IA32OperandGenerator g(this);
345 Emit(kSSEFloat64Sub, g.DefineSameAsFirst(node),
346 g.UseDoubleRegister(node->InputAt(0)),
347 g.UseDoubleRegister(node->InputAt(1)));
348 }
349
350
351 void InstructionSelector::VisitFloat64Mul(Node* node) {
352 IA32OperandGenerator g(this);
353 Emit(kSSEFloat64Mul, g.DefineSameAsFirst(node),
354 g.UseDoubleRegister(node->InputAt(0)),
355 g.UseDoubleRegister(node->InputAt(1)));
356 }
357
358
359 void InstructionSelector::VisitFloat64Div(Node* node) {
360 IA32OperandGenerator g(this);
361 Emit(kSSEFloat64Div, g.DefineSameAsFirst(node),
362 g.UseDoubleRegister(node->InputAt(0)),
363 g.UseDoubleRegister(node->InputAt(1)));
364 }
365
366
367 void InstructionSelector::VisitFloat64Mod(Node* node) {
368 IA32OperandGenerator g(this);
369 InstructionOperand* temps[] = {g.TempRegister(eax)};
370 Emit(kSSEFloat64Mod, g.DefineSameAsFirst(node),
371 g.UseDoubleRegister(node->InputAt(0)),
372 g.UseDoubleRegister(node->InputAt(1)), 1, temps);
373 }
374
375
376 // Shared routine for multiple compare operations.
377 static inline void VisitCompare(InstructionSelector* selector,
378 InstructionCode opcode,
379 InstructionOperand* left,
380 InstructionOperand* right,
381 FlagsContinuation* cont) {
382 IA32OperandGenerator g(selector);
383 if (cont->IsBranch()) {
384 selector->Emit(cont->Encode(opcode), NULL, left, right,
385 g.Label(cont->true_block()),
386 g.Label(cont->false_block()))->MarkAsControl();
387 } else {
388 ASSERT(cont->IsSet());
389 // TODO(titzer): Needs byte register.
390 selector->Emit(cont->Encode(opcode), g.DefineAsRegister(cont->result()),
391 left, right);
392 }
393 }
394
395
396 // Shared routine for multiple word compare operations.
397 static inline void VisitWordCompare(InstructionSelector* selector, Node* node,
398 InstructionCode opcode,
399 FlagsContinuation* cont, bool commutative) {
400 IA32OperandGenerator g(selector);
401 Node* left = node->InputAt(0);
402 Node* right = node->InputAt(1);
403
404 // Match immediates on left or right side of comparison.
405 if (g.CanBeImmediate(right)) {
406 VisitCompare(selector, opcode, g.Use(left), g.UseImmediate(right), cont);
407 } else if (g.CanBeImmediate(left)) {
408 if (!commutative) cont->Commute();
409 VisitCompare(selector, opcode, g.Use(right), g.UseImmediate(left), cont);
410 } else {
411 VisitCompare(selector, opcode, g.UseRegister(left), g.Use(right), cont);
412 }
413 }
414
415
416 void InstructionSelector::VisitWord32Test(Node* node, FlagsContinuation* cont) {
417 switch (node->opcode()) {
418 case IrOpcode::kInt32Sub:
419 return VisitWordCompare(this, node, kIA32Cmp, cont, false);
420 case IrOpcode::kWord32And:
421 return VisitWordCompare(this, node, kIA32Test, cont, true);
422 default:
423 break;
424 }
425
426 IA32OperandGenerator g(this);
427 VisitCompare(this, kIA32Test, g.Use(node), g.TempImmediate(-1), cont);
428 }
429
430
431 void InstructionSelector::VisitWord32Compare(Node* node,
432 FlagsContinuation* cont) {
433 VisitWordCompare(this, node, kIA32Cmp, cont, false);
434 }
435
436
437 void InstructionSelector::VisitFloat64Compare(Node* node,
438 FlagsContinuation* cont) {
439 IA32OperandGenerator g(this);
440 Node* left = node->InputAt(0);
441 Node* right = node->InputAt(1);
442 VisitCompare(this, kSSEFloat64Cmp, g.UseDoubleRegister(left), g.Use(right),
443 cont);
444 }
445
446
447 void InstructionSelector::VisitCall(Node* call, BasicBlock* continuation,
448 BasicBlock* deoptimization) {
449 IA32OperandGenerator g(this);
450 CallDescriptor* descriptor = OpParameter<CallDescriptor*>(call);
451 CallBuffer buffer(zone(), descriptor);
452
453 // Compute InstructionOperands for inputs and outputs.
454 InitializeCallBuffer(call, &buffer, true, true, continuation, deoptimization);
455
456 // Push any stack arguments.
457 for (int i = buffer.pushed_count - 1; i >= 0; --i) {
458 Node* input = buffer.pushed_nodes[i];
459 // TODO(titzer): handle pushing double parameters.
460 Emit(kIA32Push, NULL,
461 g.CanBeImmediate(input) ? g.UseImmediate(input) : g.Use(input));
462 }
463
464 // Select the appropriate opcode based on the call type.
465 InstructionCode opcode;
466 switch (descriptor->kind()) {
467 case CallDescriptor::kCallCodeObject: {
468 bool lazy_deopt = descriptor->CanLazilyDeoptimize();
469 opcode = kIA32CallCodeObject | MiscField::encode(lazy_deopt ? 1 : 0);
470 break;
471 }
472 case CallDescriptor::kCallAddress:
473 opcode = kIA32CallAddress;
474 break;
475 case CallDescriptor::kCallJSFunction:
476 opcode = kIA32CallJSFunction;
477 break;
478 default:
479 UNREACHABLE();
480 return;
481 }
482
483 // Emit the call instruction.
484 Instruction* call_instr =
485 Emit(opcode, buffer.output_count, buffer.outputs,
486 buffer.fixed_and_control_count(), buffer.fixed_and_control_args);
487
488 call_instr->MarkAsCall();
489 if (deoptimization != NULL) {
490 ASSERT(continuation != NULL);
491 call_instr->MarkAsControl();
492 }
493
494 // Caller clean up of stack for C-style calls.
495 if (descriptor->kind() == CallDescriptor::kCallAddress &&
496 buffer.pushed_count > 0) {
497 ASSERT(deoptimization == NULL && continuation == NULL);
498 Emit(kPopStack | MiscField::encode(buffer.pushed_count), NULL);
499 }
500 }
501
502 } // namespace compiler
503 } // namespace internal
504 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/ia32/instruction-codes-ia32.h ('k') | src/compiler/ia32/linkage-ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698