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/generic-node-inl.h" | 5 #include "src/compiler/generic-node-inl.h" |
6 #include "src/compiler/instruction-selector-impl.h" | 6 #include "src/compiler/instruction-selector-impl.h" |
7 #include "src/compiler/node-matchers.h" | 7 #include "src/compiler/node-matchers.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 X64-specific methods for generating operands. | 13 // Adds X64-specific methods for generating operands. |
14 class X64OperandGenerator FINAL : public OperandGenerator { | 14 class X64OperandGenerator FINAL : public OperandGenerator { |
15 public: | 15 public: |
16 explicit X64OperandGenerator(InstructionSelector* selector) | 16 explicit X64OperandGenerator(InstructionSelector* selector) |
17 : OperandGenerator(selector) {} | 17 : OperandGenerator(selector) {} |
18 | 18 |
19 InstructionOperand* TempRegister(Register reg) { | 19 InstructionOperand* TempRegister(Register reg) { |
20 return new (zone()) UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER, | 20 return new (zone()) UnallocatedOperand(UnallocatedOperand::FIXED_REGISTER, |
21 Register::ToAllocationIndex(reg)); | 21 Register::ToAllocationIndex(reg)); |
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 return true; | 27 return true; |
| 28 case IrOpcode::kInt64Constant: { |
| 29 const int64_t value = OpParameter<int64_t>(node); |
| 30 return value == static_cast<int64_t>(static_cast<int32_t>(value)); |
| 31 } |
28 default: | 32 default: |
29 return false; | 33 return false; |
30 } | 34 } |
31 } | 35 } |
32 | 36 |
33 bool CanBeBetterLeftOperand(Node* node) const { | 37 bool CanBeBetterLeftOperand(Node* node) const { |
34 return !selector()->IsLive(node); | 38 return !selector()->IsLive(node); |
35 } | 39 } |
36 }; | 40 }; |
37 | 41 |
38 | 42 |
39 // Get the AddressingMode of scale factor N from the AddressingMode of scale | |
40 // factor 1. | |
41 static AddressingMode AdjustAddressingMode(AddressingMode base_mode, | |
42 int power) { | |
43 DCHECK(0 <= power && power < 4); | |
44 return static_cast<AddressingMode>(static_cast<int>(base_mode) + power); | |
45 } | |
46 | |
47 | |
48 class AddressingModeMatcher { | |
49 public: | |
50 AddressingModeMatcher(X64OperandGenerator* g, Node* base, Node* index) | |
51 : base_operand_(NULL), | |
52 index_operand_(NULL), | |
53 displacement_operand_(NULL), | |
54 mode_(kMode_None) { | |
55 Int32Matcher index_imm(index); | |
56 if (index_imm.HasValue()) { | |
57 int32_t value = index_imm.Value(); | |
58 if (value == 0) { | |
59 mode_ = kMode_MR; | |
60 } else { | |
61 mode_ = kMode_MRI; | |
62 index_operand_ = g->UseImmediate(index); | |
63 } | |
64 base_operand_ = g->UseRegister(base); | |
65 } else { | |
66 // Compute base operand. | |
67 Int64Matcher base_imm(base); | |
68 if (!base_imm.HasValue() || base_imm.Value() != 0) { | |
69 base_operand_ = g->UseRegister(base); | |
70 } | |
71 // Compute index and displacement. | |
72 IndexAndDisplacementMatcher matcher(index); | |
73 index_operand_ = g->UseRegister(matcher.index_node()); | |
74 if (matcher.displacement() != 0) { | |
75 displacement_operand_ = g->TempImmediate(matcher.displacement()); | |
76 } | |
77 // Compute mode with scale factor one. | |
78 if (base_operand_ == NULL) { | |
79 if (displacement_operand_ == NULL) { | |
80 mode_ = kMode_M1; | |
81 } else { | |
82 mode_ = kMode_M1I; | |
83 } | |
84 } else { | |
85 if (displacement_operand_ == NULL) { | |
86 mode_ = kMode_MR1; | |
87 } else { | |
88 mode_ = kMode_MR1I; | |
89 } | |
90 } | |
91 // Adjust mode to actual scale factor. | |
92 mode_ = AdjustAddressingMode(mode_, matcher.power()); | |
93 } | |
94 DCHECK_NE(kMode_None, mode_); | |
95 } | |
96 | |
97 size_t SetInputs(InstructionOperand** inputs) { | |
98 size_t input_count = 0; | |
99 // Compute inputs_ and input_count. | |
100 if (base_operand_ != NULL) { | |
101 inputs[input_count++] = base_operand_; | |
102 } | |
103 if (index_operand_ != NULL) { | |
104 inputs[input_count++] = index_operand_; | |
105 } | |
106 if (displacement_operand_ != NULL) { | |
107 // Pure displacement mode not supported by x64. | |
108 DCHECK_NE(static_cast<int>(input_count), 0); | |
109 inputs[input_count++] = displacement_operand_; | |
110 } | |
111 DCHECK_NE(static_cast<int>(input_count), 0); | |
112 return input_count; | |
113 } | |
114 | |
115 static const int kMaxInputCount = 3; | |
116 InstructionOperand* base_operand_; | |
117 InstructionOperand* index_operand_; | |
118 InstructionOperand* displacement_operand_; | |
119 AddressingMode mode_; | |
120 }; | |
121 | |
122 | |
123 static void VisitRRFloat64(InstructionSelector* selector, ArchOpcode opcode, | |
124 Node* node) { | |
125 X64OperandGenerator g(selector); | |
126 selector->Emit(opcode, g.DefineAsRegister(node), | |
127 g.UseRegister(node->InputAt(0))); | |
128 } | |
129 | |
130 | |
131 void InstructionSelector::VisitLoad(Node* node) { | 43 void InstructionSelector::VisitLoad(Node* node) { |
132 MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node)); | 44 MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node)); |
133 MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node)); | 45 MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node)); |
134 Node* base = node->InputAt(0); | 46 X64OperandGenerator g(this); |
135 Node* index = node->InputAt(1); | 47 Node* const base = node->InputAt(0); |
| 48 Node* const index = node->InputAt(1); |
136 | 49 |
137 ArchOpcode opcode; | 50 ArchOpcode opcode; |
138 // TODO(titzer): signed/unsigned small loads | |
139 switch (rep) { | 51 switch (rep) { |
140 case kRepFloat32: | 52 case kRepFloat32: |
141 opcode = kX64Movss; | 53 opcode = kX64Movss; |
142 break; | 54 break; |
143 case kRepFloat64: | 55 case kRepFloat64: |
144 opcode = kX64Movsd; | 56 opcode = kX64Movsd; |
145 break; | 57 break; |
146 case kRepBit: // Fall through. | 58 case kRepBit: // Fall through. |
147 case kRepWord8: | 59 case kRepWord8: |
148 opcode = typ == kTypeInt32 ? kX64Movsxbl : kX64Movzxbl; | 60 opcode = typ == kTypeInt32 ? kX64Movsxbl : kX64Movzxbl; |
149 break; | 61 break; |
150 case kRepWord16: | 62 case kRepWord16: |
151 opcode = typ == kTypeInt32 ? kX64Movsxwl : kX64Movzxwl; | 63 opcode = typ == kTypeInt32 ? kX64Movsxwl : kX64Movzxwl; |
152 break; | 64 break; |
153 case kRepWord32: | 65 case kRepWord32: |
154 opcode = kX64Movl; | 66 opcode = kX64Movl; |
155 break; | 67 break; |
156 case kRepTagged: // Fall through. | 68 case kRepTagged: // Fall through. |
157 case kRepWord64: | 69 case kRepWord64: |
158 opcode = kX64Movq; | 70 opcode = kX64Movq; |
159 break; | 71 break; |
160 default: | 72 default: |
161 UNREACHABLE(); | 73 UNREACHABLE(); |
162 return; | 74 return; |
163 } | 75 } |
164 | 76 if (g.CanBeImmediate(base)) { |
165 X64OperandGenerator g(this); | 77 // load [#base + %index] |
166 AddressingModeMatcher matcher(&g, base, index); | 78 Emit(opcode | AddressingModeField::encode(kMode_MRI), |
167 InstructionCode code = opcode | AddressingModeField::encode(matcher.mode_); | 79 g.DefineAsRegister(node), g.UseRegister(index), g.UseImmediate(base)); |
168 InstructionOperand* outputs[] = {g.DefineAsRegister(node)}; | 80 } else if (g.CanBeImmediate(index)) { |
169 InstructionOperand* inputs[AddressingModeMatcher::kMaxInputCount]; | 81 // load [%base + #index] |
170 size_t input_count = matcher.SetInputs(inputs); | 82 Emit(opcode | AddressingModeField::encode(kMode_MRI), |
171 Emit(code, 1, outputs, input_count, inputs); | 83 g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index)); |
| 84 } else { |
| 85 // load [%base + %index*1] |
| 86 Emit(opcode | AddressingModeField::encode(kMode_MR1), |
| 87 g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(index)); |
| 88 } |
172 } | 89 } |
173 | 90 |
174 | 91 |
175 void InstructionSelector::VisitStore(Node* node) { | 92 void InstructionSelector::VisitStore(Node* node) { |
176 X64OperandGenerator g(this); | 93 X64OperandGenerator g(this); |
177 Node* base = node->InputAt(0); | 94 Node* base = node->InputAt(0); |
178 Node* index = node->InputAt(1); | 95 Node* index = node->InputAt(1); |
179 Node* value = node->InputAt(2); | 96 Node* value = node->InputAt(2); |
180 | 97 |
181 StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node); | 98 StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node); |
(...skipping 29 matching lines...) Expand all Loading... |
211 opcode = kX64Movl; | 128 opcode = kX64Movl; |
212 break; | 129 break; |
213 case kRepTagged: // Fall through. | 130 case kRepTagged: // Fall through. |
214 case kRepWord64: | 131 case kRepWord64: |
215 opcode = kX64Movq; | 132 opcode = kX64Movq; |
216 break; | 133 break; |
217 default: | 134 default: |
218 UNREACHABLE(); | 135 UNREACHABLE(); |
219 return; | 136 return; |
220 } | 137 } |
221 | 138 InstructionOperand* value_operand = |
222 InstructionOperand* val; | 139 g.CanBeImmediate(value) ? g.UseImmediate(value) : g.UseRegister(value); |
223 if (g.CanBeImmediate(value)) { | 140 if (g.CanBeImmediate(base)) { |
224 val = g.UseImmediate(value); | 141 // store [#base + %index], %|#value |
| 142 Emit(opcode | AddressingModeField::encode(kMode_MRI), nullptr, |
| 143 g.UseRegister(index), g.UseImmediate(base), value_operand); |
| 144 } else if (g.CanBeImmediate(index)) { |
| 145 // store [%base + #index], %|#value |
| 146 Emit(opcode | AddressingModeField::encode(kMode_MRI), nullptr, |
| 147 g.UseRegister(base), g.UseImmediate(index), value_operand); |
225 } else { | 148 } else { |
226 val = g.UseRegister(value); | 149 // store [%base + %index*1], %|#value |
| 150 Emit(opcode | AddressingModeField::encode(kMode_MR1), nullptr, |
| 151 g.UseRegister(base), g.UseRegister(index), value_operand); |
227 } | 152 } |
228 | |
229 AddressingModeMatcher matcher(&g, base, index); | |
230 InstructionCode code = opcode | AddressingModeField::encode(matcher.mode_); | |
231 InstructionOperand* inputs[AddressingModeMatcher::kMaxInputCount + 1]; | |
232 size_t input_count = matcher.SetInputs(inputs); | |
233 inputs[input_count++] = val; | |
234 Emit(code, 0, static_cast<InstructionOperand**>(NULL), input_count, inputs); | |
235 } | 153 } |
236 | 154 |
237 | 155 |
238 // Shared routine for multiple binary operations. | 156 // Shared routine for multiple binary operations. |
239 static void VisitBinop(InstructionSelector* selector, Node* node, | 157 static void VisitBinop(InstructionSelector* selector, Node* node, |
240 InstructionCode opcode, FlagsContinuation* cont) { | 158 InstructionCode opcode, FlagsContinuation* cont) { |
241 X64OperandGenerator g(selector); | 159 X64OperandGenerator g(selector); |
242 Int32BinopMatcher m(node); | 160 Int32BinopMatcher m(node); |
243 Node* left = m.left().node(); | 161 Node* left = m.left().node(); |
244 Node* right = m.right().node(); | 162 Node* right = m.right().node(); |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
335 X64OperandGenerator g(this); | 253 X64OperandGenerator g(this); |
336 Uint64BinopMatcher m(node); | 254 Uint64BinopMatcher m(node); |
337 if (m.right().Is(-1)) { | 255 if (m.right().Is(-1)) { |
338 Emit(kX64Not, g.DefineSameAsFirst(node), g.UseRegister(m.left().node())); | 256 Emit(kX64Not, g.DefineSameAsFirst(node), g.UseRegister(m.left().node())); |
339 } else { | 257 } else { |
340 VisitBinop(this, node, kX64Xor); | 258 VisitBinop(this, node, kX64Xor); |
341 } | 259 } |
342 } | 260 } |
343 | 261 |
344 | 262 |
| 263 namespace { |
| 264 |
345 // Shared routine for multiple 32-bit shift operations. | 265 // Shared routine for multiple 32-bit shift operations. |
346 // TODO(bmeurer): Merge this with VisitWord64Shift using template magic? | 266 // TODO(bmeurer): Merge this with VisitWord64Shift using template magic? |
347 static void VisitWord32Shift(InstructionSelector* selector, Node* node, | 267 void VisitWord32Shift(InstructionSelector* selector, Node* node, |
348 ArchOpcode opcode) { | 268 ArchOpcode opcode) { |
349 X64OperandGenerator g(selector); | 269 X64OperandGenerator g(selector); |
350 Node* left = node->InputAt(0); | 270 Int32BinopMatcher m(node); |
351 Node* right = node->InputAt(1); | 271 Node* left = m.left().node(); |
| 272 Node* right = m.right().node(); |
352 | 273 |
353 if (g.CanBeImmediate(right)) { | 274 if (g.CanBeImmediate(right)) { |
354 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left), | 275 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left), |
355 g.UseImmediate(right)); | 276 g.UseImmediate(right)); |
356 } else { | 277 } else { |
357 Int32BinopMatcher m(node); | |
358 if (m.right().IsWord32And()) { | 278 if (m.right().IsWord32And()) { |
359 Int32BinopMatcher mright(right); | 279 Int32BinopMatcher mright(right); |
360 if (mright.right().Is(0x1F)) { | 280 if (mright.right().Is(0x1F)) { |
361 right = mright.left().node(); | 281 right = mright.left().node(); |
362 } | 282 } |
363 } | 283 } |
364 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left), | 284 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left), |
365 g.UseFixed(right, rcx)); | 285 g.UseFixed(right, rcx)); |
366 } | 286 } |
367 } | 287 } |
368 | 288 |
369 | 289 |
370 // Shared routine for multiple 64-bit shift operations. | 290 // Shared routine for multiple 64-bit shift operations. |
371 // TODO(bmeurer): Merge this with VisitWord32Shift using template magic? | 291 // TODO(bmeurer): Merge this with VisitWord32Shift using template magic? |
372 static void VisitWord64Shift(InstructionSelector* selector, Node* node, | 292 void VisitWord64Shift(InstructionSelector* selector, Node* node, |
373 ArchOpcode opcode) { | 293 ArchOpcode opcode) { |
374 X64OperandGenerator g(selector); | 294 X64OperandGenerator g(selector); |
375 Node* left = node->InputAt(0); | 295 Int64BinopMatcher m(node); |
376 Node* right = node->InputAt(1); | 296 Node* left = m.left().node(); |
| 297 Node* right = m.right().node(); |
377 | 298 |
378 if (g.CanBeImmediate(right)) { | 299 if (g.CanBeImmediate(right)) { |
379 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left), | 300 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left), |
380 g.UseImmediate(right)); | 301 g.UseImmediate(right)); |
381 } else { | 302 } else { |
382 Int64BinopMatcher m(node); | |
383 if (m.right().IsWord64And()) { | 303 if (m.right().IsWord64And()) { |
384 Int64BinopMatcher mright(right); | 304 Int64BinopMatcher mright(right); |
385 if (mright.right().Is(0x3F)) { | 305 if (mright.right().Is(0x3F)) { |
386 right = mright.left().node(); | 306 right = mright.left().node(); |
387 } | 307 } |
388 } | 308 } |
389 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left), | 309 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left), |
390 g.UseFixed(right, rcx)); | 310 g.UseFixed(right, rcx)); |
391 } | 311 } |
392 } | 312 } |
393 | 313 |
| 314 } // namespace |
| 315 |
394 | 316 |
395 void InstructionSelector::VisitWord32Shl(Node* node) { | 317 void InstructionSelector::VisitWord32Shl(Node* node) { |
396 VisitWord32Shift(this, node, kX64Shl32); | 318 VisitWord32Shift(this, node, kX64Shl32); |
397 } | 319 } |
398 | 320 |
399 | 321 |
400 void InstructionSelector::VisitWord64Shl(Node* node) { | 322 void InstructionSelector::VisitWord64Shl(Node* node) { |
401 VisitWord64Shift(this, node, kX64Shl); | 323 VisitWord64Shift(this, node, kX64Shl); |
402 } | 324 } |
403 | 325 |
(...skipping 21 matching lines...) Expand all Loading... |
425 void InstructionSelector::VisitWord32Ror(Node* node) { | 347 void InstructionSelector::VisitWord32Ror(Node* node) { |
426 VisitWord32Shift(this, node, kX64Ror32); | 348 VisitWord32Shift(this, node, kX64Ror32); |
427 } | 349 } |
428 | 350 |
429 | 351 |
430 void InstructionSelector::VisitWord64Ror(Node* node) { | 352 void InstructionSelector::VisitWord64Ror(Node* node) { |
431 VisitWord64Shift(this, node, kX64Ror); | 353 VisitWord64Shift(this, node, kX64Ror); |
432 } | 354 } |
433 | 355 |
434 | 356 |
435 static bool TryEmitLeaMultAdd(InstructionSelector* selector, Node* node, | |
436 ArchOpcode opcode) { | |
437 int32_t displacement_value; | |
438 Node* left; | |
439 { | |
440 Int32BinopMatcher m32(node); | |
441 left = m32.left().node(); | |
442 if (m32.right().HasValue()) { | |
443 displacement_value = m32.right().Value(); | |
444 } else { | |
445 Int64BinopMatcher m64(node); | |
446 if (!m64.right().HasValue()) { | |
447 return false; | |
448 } | |
449 int64_t value_64 = m64.right().Value(); | |
450 displacement_value = static_cast<int32_t>(value_64); | |
451 if (displacement_value != value_64) return false; | |
452 } | |
453 } | |
454 LeaMultiplyMatcher lmm(left); | |
455 if (!lmm.Matches()) return false; | |
456 AddressingMode mode; | |
457 size_t input_count; | |
458 X64OperandGenerator g(selector); | |
459 InstructionOperand* index = g.UseRegister(lmm.Left()); | |
460 InstructionOperand* displacement = g.TempImmediate(displacement_value); | |
461 InstructionOperand* inputs[] = {index, displacement, displacement}; | |
462 if (lmm.Displacement() != 0) { | |
463 input_count = 3; | |
464 inputs[1] = index; | |
465 mode = kMode_MR1I; | |
466 } else { | |
467 input_count = 2; | |
468 mode = kMode_M1I; | |
469 } | |
470 mode = AdjustAddressingMode(mode, lmm.Power()); | |
471 InstructionOperand* outputs[] = {g.DefineAsRegister(node)}; | |
472 selector->Emit(opcode | AddressingModeField::encode(mode), 1, outputs, | |
473 input_count, inputs); | |
474 return true; | |
475 } | |
476 | |
477 | |
478 void InstructionSelector::VisitInt32Add(Node* node) { | 357 void InstructionSelector::VisitInt32Add(Node* node) { |
479 if (TryEmitLeaMultAdd(this, node, kX64Lea32)) return; | |
480 VisitBinop(this, node, kX64Add32); | 358 VisitBinop(this, node, kX64Add32); |
481 } | 359 } |
482 | 360 |
483 | 361 |
484 void InstructionSelector::VisitInt64Add(Node* node) { | 362 void InstructionSelector::VisitInt64Add(Node* node) { |
485 if (TryEmitLeaMultAdd(this, node, kX64Lea)) return; | |
486 VisitBinop(this, node, kX64Add); | 363 VisitBinop(this, node, kX64Add); |
487 } | 364 } |
488 | 365 |
489 | 366 |
490 void InstructionSelector::VisitInt32Sub(Node* node) { | 367 void InstructionSelector::VisitInt32Sub(Node* node) { |
491 X64OperandGenerator g(this); | 368 X64OperandGenerator g(this); |
492 Int32BinopMatcher m(node); | 369 Int32BinopMatcher m(node); |
493 if (m.left().Is(0)) { | 370 if (m.left().Is(0)) { |
494 Emit(kX64Neg32, g.DefineSameAsFirst(node), g.UseRegister(m.right().node())); | 371 Emit(kX64Neg32, g.DefineSameAsFirst(node), g.UseRegister(m.right().node())); |
495 } else { | 372 } else { |
496 VisitBinop(this, node, kX64Sub32); | 373 VisitBinop(this, node, kX64Sub32); |
497 } | 374 } |
498 } | 375 } |
499 | 376 |
500 | 377 |
501 void InstructionSelector::VisitInt64Sub(Node* node) { | 378 void InstructionSelector::VisitInt64Sub(Node* node) { |
502 X64OperandGenerator g(this); | 379 X64OperandGenerator g(this); |
503 Int64BinopMatcher m(node); | 380 Int64BinopMatcher m(node); |
504 if (m.left().Is(0)) { | 381 if (m.left().Is(0)) { |
505 Emit(kX64Neg, g.DefineSameAsFirst(node), g.UseRegister(m.right().node())); | 382 Emit(kX64Neg, g.DefineSameAsFirst(node), g.UseRegister(m.right().node())); |
506 } else { | 383 } else { |
507 VisitBinop(this, node, kX64Sub); | 384 VisitBinop(this, node, kX64Sub); |
508 } | 385 } |
509 } | 386 } |
510 | 387 |
511 | 388 |
512 static bool TryEmitLeaMult(InstructionSelector* selector, Node* node, | 389 namespace { |
513 ArchOpcode opcode) { | |
514 LeaMultiplyMatcher lea(node); | |
515 // Try to match lea. | |
516 if (!lea.Matches()) return false; | |
517 AddressingMode mode; | |
518 size_t input_count; | |
519 X64OperandGenerator g(selector); | |
520 InstructionOperand* left = g.UseRegister(lea.Left()); | |
521 InstructionOperand* inputs[] = {left, left}; | |
522 if (lea.Displacement() != 0) { | |
523 input_count = 2; | |
524 mode = kMode_MR1; | |
525 } else { | |
526 input_count = 1; | |
527 mode = kMode_M1; | |
528 } | |
529 mode = AdjustAddressingMode(mode, lea.Power()); | |
530 InstructionOperand* outputs[] = {g.DefineAsRegister(node)}; | |
531 selector->Emit(opcode | AddressingModeField::encode(mode), 1, outputs, | |
532 input_count, inputs); | |
533 return true; | |
534 } | |
535 | 390 |
536 | 391 void VisitMul(InstructionSelector* selector, Node* node, ArchOpcode opcode) { |
537 static void VisitMul(InstructionSelector* selector, Node* node, | |
538 ArchOpcode opcode) { | |
539 X64OperandGenerator g(selector); | 392 X64OperandGenerator g(selector); |
540 Int32BinopMatcher m(node); | 393 Int32BinopMatcher m(node); |
541 Node* left = m.left().node(); | 394 Node* left = m.left().node(); |
542 Node* right = m.right().node(); | 395 Node* right = m.right().node(); |
543 if (g.CanBeImmediate(right)) { | 396 if (g.CanBeImmediate(right)) { |
544 selector->Emit(opcode, g.DefineAsRegister(node), g.Use(left), | 397 selector->Emit(opcode, g.DefineAsRegister(node), g.Use(left), |
545 g.UseImmediate(right)); | 398 g.UseImmediate(right)); |
546 } else { | 399 } else { |
547 if (g.CanBeBetterLeftOperand(right)) { | 400 if (g.CanBeBetterLeftOperand(right)) { |
548 std::swap(left, right); | 401 std::swap(left, right); |
549 } | 402 } |
550 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left), | 403 selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left), |
551 g.Use(right)); | 404 g.Use(right)); |
552 } | 405 } |
553 } | 406 } |
554 | 407 |
| 408 } // namespace |
| 409 |
555 | 410 |
556 void InstructionSelector::VisitInt32Mul(Node* node) { | 411 void InstructionSelector::VisitInt32Mul(Node* node) { |
557 if (TryEmitLeaMult(this, node, kX64Lea32)) return; | |
558 VisitMul(this, node, kX64Imul32); | 412 VisitMul(this, node, kX64Imul32); |
559 } | 413 } |
560 | 414 |
561 | 415 |
562 void InstructionSelector::VisitInt64Mul(Node* node) { | 416 void InstructionSelector::VisitInt64Mul(Node* node) { |
563 if (TryEmitLeaMult(this, node, kX64Lea)) return; | |
564 VisitMul(this, node, kX64Imul); | 417 VisitMul(this, node, kX64Imul); |
565 } | 418 } |
566 | 419 |
567 | 420 |
568 void InstructionSelector::VisitInt32MulHigh(Node* node) { | 421 void InstructionSelector::VisitInt32MulHigh(Node* node) { |
569 X64OperandGenerator g(this); | 422 X64OperandGenerator g(this); |
570 InstructionOperand* temps[] = {g.TempRegister(rax)}; | 423 InstructionOperand* temps[] = {g.TempRegister(rax)}; |
571 Emit(kX64ImulHigh32, g.DefineAsFixed(node, rdx), | 424 Emit(kX64ImulHigh32, g.DefineAsFixed(node, rdx), |
572 g.UseFixed(node->InputAt(0), rax), g.UseUniqueRegister(node->InputAt(1)), | 425 g.UseFixed(node->InputAt(0), rax), g.UseUniqueRegister(node->InputAt(1)), |
573 arraysize(temps), temps); | 426 arraysize(temps), temps); |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
665 | 518 |
666 | 519 |
667 void InstructionSelector::VisitChangeInt32ToInt64(Node* node) { | 520 void InstructionSelector::VisitChangeInt32ToInt64(Node* node) { |
668 X64OperandGenerator g(this); | 521 X64OperandGenerator g(this); |
669 Emit(kX64Movsxlq, g.DefineAsRegister(node), g.Use(node->InputAt(0))); | 522 Emit(kX64Movsxlq, g.DefineAsRegister(node), g.Use(node->InputAt(0))); |
670 } | 523 } |
671 | 524 |
672 | 525 |
673 void InstructionSelector::VisitChangeUint32ToUint64(Node* node) { | 526 void InstructionSelector::VisitChangeUint32ToUint64(Node* node) { |
674 X64OperandGenerator g(this); | 527 X64OperandGenerator g(this); |
675 Emit(kX64Movl, g.DefineAsRegister(node), g.Use(node->InputAt(0))); | 528 Node* value = node->InputAt(0); |
| 529 switch (value->opcode()) { |
| 530 case IrOpcode::kWord32And: |
| 531 case IrOpcode::kWord32Or: |
| 532 case IrOpcode::kWord32Xor: |
| 533 case IrOpcode::kWord32Shl: |
| 534 case IrOpcode::kWord32Shr: |
| 535 case IrOpcode::kWord32Sar: |
| 536 case IrOpcode::kWord32Ror: |
| 537 case IrOpcode::kWord32Equal: |
| 538 case IrOpcode::kInt32Add: |
| 539 case IrOpcode::kInt32Sub: |
| 540 case IrOpcode::kInt32Mul: |
| 541 case IrOpcode::kInt32MulHigh: |
| 542 case IrOpcode::kInt32Div: |
| 543 case IrOpcode::kInt32LessThan: |
| 544 case IrOpcode::kInt32LessThanOrEqual: |
| 545 case IrOpcode::kInt32Mod: |
| 546 case IrOpcode::kUint32Div: |
| 547 case IrOpcode::kUint32LessThan: |
| 548 case IrOpcode::kUint32LessThanOrEqual: |
| 549 case IrOpcode::kUint32Mod: { |
| 550 // These 32-bit operations implicitly zero-extend to 64-bit on x64, so the |
| 551 // zero-extension is a no-op. |
| 552 Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value)); |
| 553 return; |
| 554 } |
| 555 default: |
| 556 break; |
| 557 } |
| 558 Emit(kX64Movl, g.DefineAsRegister(node), g.Use(value)); |
676 } | 559 } |
677 | 560 |
678 | 561 |
679 void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) { | 562 void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) { |
680 X64OperandGenerator g(this); | 563 X64OperandGenerator g(this); |
681 Emit(kSSECvtsd2ss, g.DefineAsRegister(node), g.Use(node->InputAt(0))); | 564 Emit(kSSECvtsd2ss, g.DefineAsRegister(node), g.Use(node->InputAt(0))); |
682 } | 565 } |
683 | 566 |
684 | 567 |
685 void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) { | 568 void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) { |
686 X64OperandGenerator g(this); | 569 X64OperandGenerator g(this); |
687 Emit(kX64Movl, g.DefineAsRegister(node), g.Use(node->InputAt(0))); | 570 Node* value = node->InputAt(0); |
| 571 if (CanCover(node, value)) { |
| 572 switch (value->opcode()) { |
| 573 case IrOpcode::kWord64Sar: |
| 574 case IrOpcode::kWord64Shr: { |
| 575 Int64BinopMatcher m(value); |
| 576 if (m.right().Is(32)) { |
| 577 Emit(kX64Shr, g.DefineSameAsFirst(node), |
| 578 g.UseRegister(m.left().node()), g.TempImmediate(32)); |
| 579 return; |
| 580 } |
| 581 break; |
| 582 } |
| 583 default: |
| 584 break; |
| 585 } |
| 586 } |
| 587 Emit(kX64Movl, g.DefineAsRegister(node), g.Use(value)); |
688 } | 588 } |
689 | 589 |
690 | 590 |
691 void InstructionSelector::VisitFloat64Add(Node* node) { | 591 void InstructionSelector::VisitFloat64Add(Node* node) { |
692 X64OperandGenerator g(this); | 592 X64OperandGenerator g(this); |
693 Emit(kSSEFloat64Add, g.DefineSameAsFirst(node), | 593 Emit(kSSEFloat64Add, g.DefineSameAsFirst(node), |
694 g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1))); | 594 g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1))); |
695 } | 595 } |
696 | 596 |
697 | 597 |
(...skipping 26 matching lines...) Expand all Loading... |
724 temps); | 624 temps); |
725 } | 625 } |
726 | 626 |
727 | 627 |
728 void InstructionSelector::VisitFloat64Sqrt(Node* node) { | 628 void InstructionSelector::VisitFloat64Sqrt(Node* node) { |
729 X64OperandGenerator g(this); | 629 X64OperandGenerator g(this); |
730 Emit(kSSEFloat64Sqrt, g.DefineAsRegister(node), g.Use(node->InputAt(0))); | 630 Emit(kSSEFloat64Sqrt, g.DefineAsRegister(node), g.Use(node->InputAt(0))); |
731 } | 631 } |
732 | 632 |
733 | 633 |
| 634 namespace { |
| 635 |
| 636 void VisitRRFloat64(InstructionSelector* selector, ArchOpcode opcode, |
| 637 Node* node) { |
| 638 X64OperandGenerator g(selector); |
| 639 selector->Emit(opcode, g.DefineAsRegister(node), |
| 640 g.UseRegister(node->InputAt(0))); |
| 641 } |
| 642 |
| 643 } // namespace |
| 644 |
| 645 |
734 void InstructionSelector::VisitFloat64Floor(Node* node) { | 646 void InstructionSelector::VisitFloat64Floor(Node* node) { |
735 DCHECK(CpuFeatures::IsSupported(SSE4_1)); | 647 DCHECK(CpuFeatures::IsSupported(SSE4_1)); |
736 VisitRRFloat64(this, kSSEFloat64Floor, node); | 648 VisitRRFloat64(this, kSSEFloat64Floor, node); |
737 } | 649 } |
738 | 650 |
739 | 651 |
740 void InstructionSelector::VisitFloat64Ceil(Node* node) { | 652 void InstructionSelector::VisitFloat64Ceil(Node* node) { |
741 DCHECK(CpuFeatures::IsSupported(SSE4_1)); | 653 DCHECK(CpuFeatures::IsSupported(SSE4_1)); |
742 VisitRRFloat64(this, kSSEFloat64Ceil, node); | 654 VisitRRFloat64(this, kSSEFloat64Ceil, node); |
743 } | 655 } |
(...skipping 402 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1146 if (CpuFeatures::IsSupported(SSE4_1)) { | 1058 if (CpuFeatures::IsSupported(SSE4_1)) { |
1147 return MachineOperatorBuilder::kFloat64Floor | | 1059 return MachineOperatorBuilder::kFloat64Floor | |
1148 MachineOperatorBuilder::kFloat64Ceil | | 1060 MachineOperatorBuilder::kFloat64Ceil | |
1149 MachineOperatorBuilder::kFloat64RoundTruncate; | 1061 MachineOperatorBuilder::kFloat64RoundTruncate; |
1150 } | 1062 } |
1151 return MachineOperatorBuilder::kNoFlags; | 1063 return MachineOperatorBuilder::kNoFlags; |
1152 } | 1064 } |
1153 } // namespace compiler | 1065 } // namespace compiler |
1154 } // namespace internal | 1066 } // namespace internal |
1155 } // namespace v8 | 1067 } // namespace v8 |
OLD | NEW |