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/base/bits.h" | 5 #include "src/base/bits.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 #include "src/compiler/node-properties.h" | 8 #include "src/compiler/node-properties.h" |
9 | 9 |
10 namespace v8 { | 10 namespace v8 { |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
92 selector->Emit(opcode, g.DefineAsRegister(node), | 92 selector->Emit(opcode, g.DefineAsRegister(node), |
93 g.UseRegister(node->InputAt(0)), | 93 g.UseRegister(node->InputAt(0)), |
94 g.UseRegister(node->InputAt(1))); | 94 g.UseRegister(node->InputAt(1))); |
95 } | 95 } |
96 | 96 |
97 | 97 |
98 template <IrOpcode::Value kOpcode, int kImmMin, int kImmMax, | 98 template <IrOpcode::Value kOpcode, int kImmMin, int kImmMax, |
99 AddressingMode kImmMode, AddressingMode kRegMode> | 99 AddressingMode kImmMode, AddressingMode kRegMode> |
100 bool TryMatchShift(InstructionSelector* selector, | 100 bool TryMatchShift(InstructionSelector* selector, |
101 InstructionCode* opcode_return, Node* node, | 101 InstructionCode* opcode_return, Node* node, |
102 InstructionOperand** value_return, | 102 InstructionOperand* value_return, |
103 InstructionOperand** shift_return) { | 103 InstructionOperand* shift_return) { |
104 ArmOperandGenerator g(selector); | 104 ArmOperandGenerator g(selector); |
105 if (node->opcode() == kOpcode) { | 105 if (node->opcode() == kOpcode) { |
106 Int32BinopMatcher m(node); | 106 Int32BinopMatcher m(node); |
107 *value_return = g.UseRegister(m.left().node()); | 107 *value_return = g.UseRegister(m.left().node()); |
108 if (m.right().IsInRange(kImmMin, kImmMax)) { | 108 if (m.right().IsInRange(kImmMin, kImmMax)) { |
109 *opcode_return |= AddressingModeField::encode(kImmMode); | 109 *opcode_return |= AddressingModeField::encode(kImmMode); |
110 *shift_return = g.UseImmediate(m.right().node()); | 110 *shift_return = g.UseImmediate(m.right().node()); |
111 } else { | 111 } else { |
112 *opcode_return |= AddressingModeField::encode(kRegMode); | 112 *opcode_return |= AddressingModeField::encode(kRegMode); |
113 *shift_return = g.UseRegister(m.right().node()); | 113 *shift_return = g.UseRegister(m.right().node()); |
114 } | 114 } |
115 return true; | 115 return true; |
116 } | 116 } |
117 return false; | 117 return false; |
118 } | 118 } |
119 | 119 |
120 | 120 |
121 bool TryMatchROR(InstructionSelector* selector, InstructionCode* opcode_return, | 121 bool TryMatchROR(InstructionSelector* selector, InstructionCode* opcode_return, |
122 Node* node, InstructionOperand** value_return, | 122 Node* node, InstructionOperand* value_return, |
123 InstructionOperand** shift_return) { | 123 InstructionOperand* shift_return) { |
124 return TryMatchShift<IrOpcode::kWord32Ror, 1, 31, kMode_Operand2_R_ROR_I, | 124 return TryMatchShift<IrOpcode::kWord32Ror, 1, 31, kMode_Operand2_R_ROR_I, |
125 kMode_Operand2_R_ROR_R>(selector, opcode_return, node, | 125 kMode_Operand2_R_ROR_R>(selector, opcode_return, node, |
126 value_return, shift_return); | 126 value_return, shift_return); |
127 } | 127 } |
128 | 128 |
129 | 129 |
130 bool TryMatchASR(InstructionSelector* selector, InstructionCode* opcode_return, | 130 bool TryMatchASR(InstructionSelector* selector, InstructionCode* opcode_return, |
131 Node* node, InstructionOperand** value_return, | 131 Node* node, InstructionOperand* value_return, |
132 InstructionOperand** shift_return) { | 132 InstructionOperand* shift_return) { |
133 return TryMatchShift<IrOpcode::kWord32Sar, 1, 32, kMode_Operand2_R_ASR_I, | 133 return TryMatchShift<IrOpcode::kWord32Sar, 1, 32, kMode_Operand2_R_ASR_I, |
134 kMode_Operand2_R_ASR_R>(selector, opcode_return, node, | 134 kMode_Operand2_R_ASR_R>(selector, opcode_return, node, |
135 value_return, shift_return); | 135 value_return, shift_return); |
136 } | 136 } |
137 | 137 |
138 | 138 |
139 bool TryMatchLSL(InstructionSelector* selector, InstructionCode* opcode_return, | 139 bool TryMatchLSL(InstructionSelector* selector, InstructionCode* opcode_return, |
140 Node* node, InstructionOperand** value_return, | 140 Node* node, InstructionOperand* value_return, |
141 InstructionOperand** shift_return) { | 141 InstructionOperand* shift_return) { |
142 return TryMatchShift<IrOpcode::kWord32Shl, 0, 31, kMode_Operand2_R_LSL_I, | 142 return TryMatchShift<IrOpcode::kWord32Shl, 0, 31, kMode_Operand2_R_LSL_I, |
143 kMode_Operand2_R_LSL_R>(selector, opcode_return, node, | 143 kMode_Operand2_R_LSL_R>(selector, opcode_return, node, |
144 value_return, shift_return); | 144 value_return, shift_return); |
145 } | 145 } |
146 | 146 |
147 | 147 |
148 bool TryMatchLSR(InstructionSelector* selector, InstructionCode* opcode_return, | 148 bool TryMatchLSR(InstructionSelector* selector, InstructionCode* opcode_return, |
149 Node* node, InstructionOperand** value_return, | 149 Node* node, InstructionOperand* value_return, |
150 InstructionOperand** shift_return) { | 150 InstructionOperand* shift_return) { |
151 return TryMatchShift<IrOpcode::kWord32Shr, 1, 32, kMode_Operand2_R_LSR_I, | 151 return TryMatchShift<IrOpcode::kWord32Shr, 1, 32, kMode_Operand2_R_LSR_I, |
152 kMode_Operand2_R_LSR_R>(selector, opcode_return, node, | 152 kMode_Operand2_R_LSR_R>(selector, opcode_return, node, |
153 value_return, shift_return); | 153 value_return, shift_return); |
154 } | 154 } |
155 | 155 |
156 | 156 |
157 bool TryMatchShift(InstructionSelector* selector, | 157 bool TryMatchShift(InstructionSelector* selector, |
158 InstructionCode* opcode_return, Node* node, | 158 InstructionCode* opcode_return, Node* node, |
159 InstructionOperand** value_return, | 159 InstructionOperand* value_return, |
160 InstructionOperand** shift_return) { | 160 InstructionOperand* shift_return) { |
161 return ( | 161 return ( |
162 TryMatchASR(selector, opcode_return, node, value_return, shift_return) || | 162 TryMatchASR(selector, opcode_return, node, value_return, shift_return) || |
163 TryMatchLSL(selector, opcode_return, node, value_return, shift_return) || | 163 TryMatchLSL(selector, opcode_return, node, value_return, shift_return) || |
164 TryMatchLSR(selector, opcode_return, node, value_return, shift_return) || | 164 TryMatchLSR(selector, opcode_return, node, value_return, shift_return) || |
165 TryMatchROR(selector, opcode_return, node, value_return, shift_return)); | 165 TryMatchROR(selector, opcode_return, node, value_return, shift_return)); |
166 } | 166 } |
167 | 167 |
168 | 168 |
169 bool TryMatchImmediateOrShift(InstructionSelector* selector, | 169 bool TryMatchImmediateOrShift(InstructionSelector* selector, |
170 InstructionCode* opcode_return, Node* node, | 170 InstructionCode* opcode_return, Node* node, |
171 size_t* input_count_return, | 171 size_t* input_count_return, |
172 InstructionOperand** inputs) { | 172 InstructionOperand* inputs) { |
173 ArmOperandGenerator g(selector); | 173 ArmOperandGenerator g(selector); |
174 if (g.CanBeImmediate(node, *opcode_return)) { | 174 if (g.CanBeImmediate(node, *opcode_return)) { |
175 *opcode_return |= AddressingModeField::encode(kMode_Operand2_I); | 175 *opcode_return |= AddressingModeField::encode(kMode_Operand2_I); |
176 inputs[0] = g.UseImmediate(node); | 176 inputs[0] = g.UseImmediate(node); |
177 *input_count_return = 1; | 177 *input_count_return = 1; |
178 return true; | 178 return true; |
179 } | 179 } |
180 if (TryMatchShift(selector, opcode_return, node, &inputs[0], &inputs[1])) { | 180 if (TryMatchShift(selector, opcode_return, node, &inputs[0], &inputs[1])) { |
181 *input_count_return = 2; | 181 *input_count_return = 2; |
182 return true; | 182 return true; |
183 } | 183 } |
184 return false; | 184 return false; |
185 } | 185 } |
186 | 186 |
187 | 187 |
188 void VisitBinop(InstructionSelector* selector, Node* node, | 188 void VisitBinop(InstructionSelector* selector, Node* node, |
189 InstructionCode opcode, InstructionCode reverse_opcode, | 189 InstructionCode opcode, InstructionCode reverse_opcode, |
190 FlagsContinuation* cont) { | 190 FlagsContinuation* cont) { |
191 ArmOperandGenerator g(selector); | 191 ArmOperandGenerator g(selector); |
192 Int32BinopMatcher m(node); | 192 Int32BinopMatcher m(node); |
193 InstructionOperand* inputs[5]; | 193 InstructionOperand inputs[5]; |
194 size_t input_count = 0; | 194 size_t input_count = 0; |
195 InstructionOperand* outputs[2]; | 195 InstructionOperand outputs[2]; |
196 size_t output_count = 0; | 196 size_t output_count = 0; |
197 | 197 |
198 if (m.left().node() == m.right().node()) { | 198 if (m.left().node() == m.right().node()) { |
199 // If both inputs refer to the same operand, enforce allocating a register | 199 // If both inputs refer to the same operand, enforce allocating a register |
200 // for both of them to ensure that we don't end up generating code like | 200 // for both of them to ensure that we don't end up generating code like |
201 // this: | 201 // this: |
202 // | 202 // |
203 // mov r0, r1, asr #16 | 203 // mov r0, r1, asr #16 |
204 // adds r0, r0, r1, asr #16 | 204 // adds r0, r0, r1, asr #16 |
205 // bvs label | 205 // bvs label |
206 InstructionOperand* const input = g.UseRegister(m.left().node()); | 206 InstructionOperand const input = g.UseRegister(m.left().node()); |
207 opcode |= AddressingModeField::encode(kMode_Operand2_R); | 207 opcode |= AddressingModeField::encode(kMode_Operand2_R); |
208 inputs[input_count++] = input; | 208 inputs[input_count++] = input; |
209 inputs[input_count++] = input; | 209 inputs[input_count++] = input; |
210 } else if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(), | 210 } else if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(), |
211 &input_count, &inputs[1])) { | 211 &input_count, &inputs[1])) { |
212 inputs[0] = g.UseRegister(m.left().node()); | 212 inputs[0] = g.UseRegister(m.left().node()); |
213 input_count++; | 213 input_count++; |
214 } else if (TryMatchImmediateOrShift(selector, &reverse_opcode, | 214 } else if (TryMatchImmediateOrShift(selector, &reverse_opcode, |
215 m.left().node(), &input_count, | 215 m.left().node(), &input_count, |
216 &inputs[1])) { | 216 &inputs[1])) { |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
302 Node* index = node->InputAt(1); | 302 Node* index = node->InputAt(1); |
303 Node* value = node->InputAt(2); | 303 Node* value = node->InputAt(2); |
304 | 304 |
305 StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node); | 305 StoreRepresentation store_rep = OpParameter<StoreRepresentation>(node); |
306 MachineType rep = RepresentationOf(store_rep.machine_type()); | 306 MachineType rep = RepresentationOf(store_rep.machine_type()); |
307 if (store_rep.write_barrier_kind() == kFullWriteBarrier) { | 307 if (store_rep.write_barrier_kind() == kFullWriteBarrier) { |
308 DCHECK(rep == kRepTagged); | 308 DCHECK(rep == kRepTagged); |
309 // TODO(dcarney): refactor RecordWrite function to take temp registers | 309 // TODO(dcarney): refactor RecordWrite function to take temp registers |
310 // and pass them here instead of using fixed regs | 310 // and pass them here instead of using fixed regs |
311 // TODO(dcarney): handle immediate indices. | 311 // TODO(dcarney): handle immediate indices. |
312 InstructionOperand* temps[] = {g.TempRegister(r5), g.TempRegister(r6)}; | 312 InstructionOperand temps[] = {g.TempRegister(r5), g.TempRegister(r6)}; |
313 Emit(kArmStoreWriteBarrier, NULL, g.UseFixed(base, r4), | 313 Emit(kArmStoreWriteBarrier, g.NoOutput(), g.UseFixed(base, r4), |
314 g.UseFixed(index, r5), g.UseFixed(value, r6), arraysize(temps), | 314 g.UseFixed(index, r5), g.UseFixed(value, r6), arraysize(temps), temps); |
315 temps); | |
316 return; | 315 return; |
317 } | 316 } |
318 DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind()); | 317 DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind()); |
319 | 318 |
320 ArchOpcode opcode; | 319 ArchOpcode opcode; |
321 switch (rep) { | 320 switch (rep) { |
322 case kRepFloat32: | 321 case kRepFloat32: |
323 opcode = kArmVstrF32; | 322 opcode = kArmVstrF32; |
324 break; | 323 break; |
325 case kRepFloat64: | 324 case kRepFloat64: |
326 opcode = kArmVstrF64; | 325 opcode = kArmVstrF64; |
327 break; | 326 break; |
328 case kRepBit: // Fall through. | 327 case kRepBit: // Fall through. |
329 case kRepWord8: | 328 case kRepWord8: |
330 opcode = kArmStrb; | 329 opcode = kArmStrb; |
331 break; | 330 break; |
332 case kRepWord16: | 331 case kRepWord16: |
333 opcode = kArmStrh; | 332 opcode = kArmStrh; |
334 break; | 333 break; |
335 case kRepTagged: // Fall through. | 334 case kRepTagged: // Fall through. |
336 case kRepWord32: | 335 case kRepWord32: |
337 opcode = kArmStr; | 336 opcode = kArmStr; |
338 break; | 337 break; |
339 default: | 338 default: |
340 UNREACHABLE(); | 339 UNREACHABLE(); |
341 return; | 340 return; |
342 } | 341 } |
343 | 342 |
344 if (g.CanBeImmediate(index, opcode)) { | 343 if (g.CanBeImmediate(index, opcode)) { |
345 Emit(opcode | AddressingModeField::encode(kMode_Offset_RI), NULL, | 344 Emit(opcode | AddressingModeField::encode(kMode_Offset_RI), g.NoOutput(), |
346 g.UseRegister(base), g.UseImmediate(index), g.UseRegister(value)); | 345 g.UseRegister(base), g.UseImmediate(index), g.UseRegister(value)); |
347 } else { | 346 } else { |
348 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), NULL, | 347 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), g.NoOutput(), |
349 g.UseRegister(base), g.UseRegister(index), g.UseRegister(value)); | 348 g.UseRegister(base), g.UseRegister(index), g.UseRegister(value)); |
350 } | 349 } |
351 } | 350 } |
352 | 351 |
353 | 352 |
354 void InstructionSelector::VisitCheckedLoad(Node* node) { | 353 void InstructionSelector::VisitCheckedLoad(Node* node) { |
355 MachineType rep = RepresentationOf(OpParameter<MachineType>(node)); | 354 MachineType rep = RepresentationOf(OpParameter<MachineType>(node)); |
356 MachineType typ = TypeOf(OpParameter<MachineType>(node)); | 355 MachineType typ = TypeOf(OpParameter<MachineType>(node)); |
357 ArmOperandGenerator g(this); | 356 ArmOperandGenerator g(this); |
358 Node* const buffer = node->InputAt(0); | 357 Node* const buffer = node->InputAt(0); |
(...skipping 13 matching lines...) Expand all Loading... |
372 case kRepFloat32: | 371 case kRepFloat32: |
373 opcode = kCheckedLoadFloat32; | 372 opcode = kCheckedLoadFloat32; |
374 break; | 373 break; |
375 case kRepFloat64: | 374 case kRepFloat64: |
376 opcode = kCheckedLoadFloat64; | 375 opcode = kCheckedLoadFloat64; |
377 break; | 376 break; |
378 default: | 377 default: |
379 UNREACHABLE(); | 378 UNREACHABLE(); |
380 return; | 379 return; |
381 } | 380 } |
382 InstructionOperand* offset_operand = g.UseRegister(offset); | 381 InstructionOperand offset_operand = g.UseRegister(offset); |
383 InstructionOperand* length_operand = g.CanBeImmediate(length, kArmCmp) | 382 InstructionOperand length_operand = g.CanBeImmediate(length, kArmCmp) |
384 ? g.UseImmediate(length) | 383 ? g.UseImmediate(length) |
385 : g.UseRegister(length); | 384 : g.UseRegister(length); |
386 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), | 385 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), |
387 g.DefineAsRegister(node), offset_operand, length_operand, | 386 g.DefineAsRegister(node), offset_operand, length_operand, |
388 g.UseRegister(buffer), offset_operand); | 387 g.UseRegister(buffer), offset_operand); |
389 } | 388 } |
390 | 389 |
391 | 390 |
392 void InstructionSelector::VisitCheckedStore(Node* node) { | 391 void InstructionSelector::VisitCheckedStore(Node* node) { |
393 MachineType rep = RepresentationOf(OpParameter<MachineType>(node)); | 392 MachineType rep = RepresentationOf(OpParameter<MachineType>(node)); |
394 ArmOperandGenerator g(this); | 393 ArmOperandGenerator g(this); |
395 Node* const buffer = node->InputAt(0); | 394 Node* const buffer = node->InputAt(0); |
(...skipping 14 matching lines...) Expand all Loading... |
410 case kRepFloat32: | 409 case kRepFloat32: |
411 opcode = kCheckedStoreFloat32; | 410 opcode = kCheckedStoreFloat32; |
412 break; | 411 break; |
413 case kRepFloat64: | 412 case kRepFloat64: |
414 opcode = kCheckedStoreFloat64; | 413 opcode = kCheckedStoreFloat64; |
415 break; | 414 break; |
416 default: | 415 default: |
417 UNREACHABLE(); | 416 UNREACHABLE(); |
418 return; | 417 return; |
419 } | 418 } |
420 InstructionOperand* offset_operand = g.UseRegister(offset); | 419 InstructionOperand offset_operand = g.UseRegister(offset); |
421 InstructionOperand* length_operand = g.CanBeImmediate(length, kArmCmp) | 420 InstructionOperand length_operand = g.CanBeImmediate(length, kArmCmp) |
422 ? g.UseImmediate(length) | 421 ? g.UseImmediate(length) |
423 : g.UseRegister(length); | 422 : g.UseRegister(length); |
424 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), nullptr, | 423 Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), g.NoOutput(), |
425 offset_operand, length_operand, g.UseRegister(value), | 424 offset_operand, length_operand, g.UseRegister(value), |
426 g.UseRegister(buffer), offset_operand); | 425 g.UseRegister(buffer), offset_operand); |
427 } | 426 } |
428 | 427 |
429 | 428 |
430 namespace { | 429 namespace { |
431 | 430 |
432 void EmitBic(InstructionSelector* selector, Node* node, Node* left, | 431 void EmitBic(InstructionSelector* selector, Node* node, Node* left, |
433 Node* right) { | 432 Node* right) { |
434 ArmOperandGenerator g(selector); | 433 ArmOperandGenerator g(selector); |
435 InstructionCode opcode = kArmBic; | 434 InstructionCode opcode = kArmBic; |
436 InstructionOperand* value_operand; | 435 InstructionOperand value_operand; |
437 InstructionOperand* shift_operand; | 436 InstructionOperand shift_operand; |
438 if (TryMatchShift(selector, &opcode, right, &value_operand, &shift_operand)) { | 437 if (TryMatchShift(selector, &opcode, right, &value_operand, &shift_operand)) { |
439 selector->Emit(opcode, g.DefineAsRegister(node), g.UseRegister(left), | 438 selector->Emit(opcode, g.DefineAsRegister(node), g.UseRegister(left), |
440 value_operand, shift_operand); | 439 value_operand, shift_operand); |
441 return; | 440 return; |
442 } | 441 } |
443 selector->Emit(opcode | AddressingModeField::encode(kMode_Operand2_R), | 442 selector->Emit(opcode | AddressingModeField::encode(kMode_Operand2_R), |
444 g.DefineAsRegister(node), g.UseRegister(left), | 443 g.DefineAsRegister(node), g.UseRegister(left), |
445 g.UseRegister(right)); | 444 g.UseRegister(right)); |
446 } | 445 } |
447 | 446 |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
528 void InstructionSelector::VisitWord32Or(Node* node) { | 527 void InstructionSelector::VisitWord32Or(Node* node) { |
529 VisitBinop(this, node, kArmOrr, kArmOrr); | 528 VisitBinop(this, node, kArmOrr, kArmOrr); |
530 } | 529 } |
531 | 530 |
532 | 531 |
533 void InstructionSelector::VisitWord32Xor(Node* node) { | 532 void InstructionSelector::VisitWord32Xor(Node* node) { |
534 ArmOperandGenerator g(this); | 533 ArmOperandGenerator g(this); |
535 Int32BinopMatcher m(node); | 534 Int32BinopMatcher m(node); |
536 if (m.right().Is(-1)) { | 535 if (m.right().Is(-1)) { |
537 InstructionCode opcode = kArmMvn; | 536 InstructionCode opcode = kArmMvn; |
538 InstructionOperand* value_operand; | 537 InstructionOperand value_operand; |
539 InstructionOperand* shift_operand; | 538 InstructionOperand shift_operand; |
540 if (TryMatchShift(this, &opcode, m.left().node(), &value_operand, | 539 if (TryMatchShift(this, &opcode, m.left().node(), &value_operand, |
541 &shift_operand)) { | 540 &shift_operand)) { |
542 Emit(opcode, g.DefineAsRegister(node), value_operand, shift_operand); | 541 Emit(opcode, g.DefineAsRegister(node), value_operand, shift_operand); |
543 return; | 542 return; |
544 } | 543 } |
545 Emit(opcode | AddressingModeField::encode(kMode_Operand2_R), | 544 Emit(opcode | AddressingModeField::encode(kMode_Operand2_R), |
546 g.DefineAsRegister(node), g.UseRegister(m.left().node())); | 545 g.DefineAsRegister(node), g.UseRegister(m.left().node())); |
547 return; | 546 return; |
548 } | 547 } |
549 VisitBinop(this, node, kArmEor, kArmEor); | 548 VisitBinop(this, node, kArmEor, kArmEor); |
550 } | 549 } |
551 | 550 |
552 | 551 |
553 namespace { | 552 namespace { |
554 | 553 |
555 template <typename TryMatchShift> | 554 template <typename TryMatchShift> |
556 void VisitShift(InstructionSelector* selector, Node* node, | 555 void VisitShift(InstructionSelector* selector, Node* node, |
557 TryMatchShift try_match_shift, FlagsContinuation* cont) { | 556 TryMatchShift try_match_shift, FlagsContinuation* cont) { |
558 ArmOperandGenerator g(selector); | 557 ArmOperandGenerator g(selector); |
559 InstructionCode opcode = kArmMov; | 558 InstructionCode opcode = kArmMov; |
560 InstructionOperand* inputs[4]; | 559 InstructionOperand inputs[4]; |
561 size_t input_count = 2; | 560 size_t input_count = 2; |
562 InstructionOperand* outputs[2]; | 561 InstructionOperand outputs[2]; |
563 size_t output_count = 0; | 562 size_t output_count = 0; |
564 | 563 |
565 CHECK(try_match_shift(selector, &opcode, node, &inputs[0], &inputs[1])); | 564 CHECK(try_match_shift(selector, &opcode, node, &inputs[0], &inputs[1])); |
566 | 565 |
567 if (cont->IsBranch()) { | 566 if (cont->IsBranch()) { |
568 inputs[input_count++] = g.Label(cont->true_block()); | 567 inputs[input_count++] = g.Label(cont->true_block()); |
569 inputs[input_count++] = g.Label(cont->false_block()); | 568 inputs[input_count++] = g.Label(cont->false_block()); |
570 } | 569 } |
571 | 570 |
572 outputs[output_count++] = g.DefineAsRegister(node); | 571 outputs[output_count++] = g.DefineAsRegister(node); |
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
802 | 801 |
803 void InstructionSelector::VisitInt32MulHigh(Node* node) { | 802 void InstructionSelector::VisitInt32MulHigh(Node* node) { |
804 ArmOperandGenerator g(this); | 803 ArmOperandGenerator g(this); |
805 Emit(kArmSmmul, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)), | 804 Emit(kArmSmmul, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)), |
806 g.UseRegister(node->InputAt(1))); | 805 g.UseRegister(node->InputAt(1))); |
807 } | 806 } |
808 | 807 |
809 | 808 |
810 void InstructionSelector::VisitUint32MulHigh(Node* node) { | 809 void InstructionSelector::VisitUint32MulHigh(Node* node) { |
811 ArmOperandGenerator g(this); | 810 ArmOperandGenerator g(this); |
812 InstructionOperand* outputs[] = {g.TempRegister(), g.DefineAsRegister(node)}; | 811 InstructionOperand outputs[] = {g.TempRegister(), g.DefineAsRegister(node)}; |
813 InstructionOperand* inputs[] = {g.UseRegister(node->InputAt(0)), | 812 InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0)), |
814 g.UseRegister(node->InputAt(1))}; | 813 g.UseRegister(node->InputAt(1))}; |
815 Emit(kArmUmull, arraysize(outputs), outputs, arraysize(inputs), inputs); | 814 Emit(kArmUmull, arraysize(outputs), outputs, arraysize(inputs), inputs); |
816 } | 815 } |
817 | 816 |
818 | 817 |
819 static void EmitDiv(InstructionSelector* selector, ArchOpcode div_opcode, | 818 static void EmitDiv(InstructionSelector* selector, ArchOpcode div_opcode, |
820 ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode, | 819 ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode, |
821 InstructionOperand* result_operand, | 820 InstructionOperand result_operand, |
822 InstructionOperand* left_operand, | 821 InstructionOperand left_operand, |
823 InstructionOperand* right_operand) { | 822 InstructionOperand right_operand) { |
824 ArmOperandGenerator g(selector); | 823 ArmOperandGenerator g(selector); |
825 if (selector->IsSupported(SUDIV)) { | 824 if (selector->IsSupported(SUDIV)) { |
826 selector->Emit(div_opcode, result_operand, left_operand, right_operand); | 825 selector->Emit(div_opcode, result_operand, left_operand, right_operand); |
827 return; | 826 return; |
828 } | 827 } |
829 InstructionOperand* left_double_operand = g.TempDoubleRegister(); | 828 InstructionOperand left_double_operand = g.TempDoubleRegister(); |
830 InstructionOperand* right_double_operand = g.TempDoubleRegister(); | 829 InstructionOperand right_double_operand = g.TempDoubleRegister(); |
831 InstructionOperand* result_double_operand = g.TempDoubleRegister(); | 830 InstructionOperand result_double_operand = g.TempDoubleRegister(); |
832 selector->Emit(f64i32_opcode, left_double_operand, left_operand); | 831 selector->Emit(f64i32_opcode, left_double_operand, left_operand); |
833 selector->Emit(f64i32_opcode, right_double_operand, right_operand); | 832 selector->Emit(f64i32_opcode, right_double_operand, right_operand); |
834 selector->Emit(kArmVdivF64, result_double_operand, left_double_operand, | 833 selector->Emit(kArmVdivF64, result_double_operand, left_double_operand, |
835 right_double_operand); | 834 right_double_operand); |
836 selector->Emit(i32f64_opcode, result_operand, result_double_operand); | 835 selector->Emit(i32f64_opcode, result_operand, result_double_operand); |
837 } | 836 } |
838 | 837 |
839 | 838 |
840 static void VisitDiv(InstructionSelector* selector, Node* node, | 839 static void VisitDiv(InstructionSelector* selector, Node* node, |
841 ArchOpcode div_opcode, ArchOpcode f64i32_opcode, | 840 ArchOpcode div_opcode, ArchOpcode f64i32_opcode, |
(...skipping 14 matching lines...) Expand all Loading... |
856 void InstructionSelector::VisitUint32Div(Node* node) { | 855 void InstructionSelector::VisitUint32Div(Node* node) { |
857 VisitDiv(this, node, kArmUdiv, kArmVcvtF64U32, kArmVcvtU32F64); | 856 VisitDiv(this, node, kArmUdiv, kArmVcvtF64U32, kArmVcvtU32F64); |
858 } | 857 } |
859 | 858 |
860 | 859 |
861 static void VisitMod(InstructionSelector* selector, Node* node, | 860 static void VisitMod(InstructionSelector* selector, Node* node, |
862 ArchOpcode div_opcode, ArchOpcode f64i32_opcode, | 861 ArchOpcode div_opcode, ArchOpcode f64i32_opcode, |
863 ArchOpcode i32f64_opcode) { | 862 ArchOpcode i32f64_opcode) { |
864 ArmOperandGenerator g(selector); | 863 ArmOperandGenerator g(selector); |
865 Int32BinopMatcher m(node); | 864 Int32BinopMatcher m(node); |
866 InstructionOperand* div_operand = g.TempRegister(); | 865 InstructionOperand div_operand = g.TempRegister(); |
867 InstructionOperand* result_operand = g.DefineAsRegister(node); | 866 InstructionOperand result_operand = g.DefineAsRegister(node); |
868 InstructionOperand* left_operand = g.UseRegister(m.left().node()); | 867 InstructionOperand left_operand = g.UseRegister(m.left().node()); |
869 InstructionOperand* right_operand = g.UseRegister(m.right().node()); | 868 InstructionOperand right_operand = g.UseRegister(m.right().node()); |
870 EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode, div_operand, | 869 EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode, div_operand, |
871 left_operand, right_operand); | 870 left_operand, right_operand); |
872 if (selector->IsSupported(MLS)) { | 871 if (selector->IsSupported(MLS)) { |
873 selector->Emit(kArmMls, result_operand, div_operand, right_operand, | 872 selector->Emit(kArmMls, result_operand, div_operand, right_operand, |
874 left_operand); | 873 left_operand); |
875 return; | 874 return; |
876 } | 875 } |
877 InstructionOperand* mul_operand = g.TempRegister(); | 876 InstructionOperand mul_operand = g.TempRegister(); |
878 selector->Emit(kArmMul, mul_operand, div_operand, right_operand); | 877 selector->Emit(kArmMul, mul_operand, div_operand, right_operand); |
879 selector->Emit(kArmSub, result_operand, left_operand, mul_operand); | 878 selector->Emit(kArmSub, result_operand, left_operand, mul_operand); |
880 } | 879 } |
881 | 880 |
882 | 881 |
883 void InstructionSelector::VisitInt32Mod(Node* node) { | 882 void InstructionSelector::VisitInt32Mod(Node* node) { |
884 VisitMod(this, node, kArmSdiv, kArmVcvtF64S32, kArmVcvtS32F64); | 883 VisitMod(this, node, kArmSdiv, kArmVcvtF64S32, kArmVcvtS32F64); |
885 } | 884 } |
886 | 885 |
887 | 886 |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1034 // Compute InstructionOperands for inputs and outputs. | 1033 // Compute InstructionOperands for inputs and outputs. |
1035 // TODO(turbofan): on ARM64 it's probably better to use the code object in a | 1034 // TODO(turbofan): on ARM64 it's probably better to use the code object in a |
1036 // register if there are multiple uses of it. Improve constant pool and the | 1035 // register if there are multiple uses of it. Improve constant pool and the |
1037 // heuristics in the register allocator for where to emit constants. | 1036 // heuristics in the register allocator for where to emit constants. |
1038 InitializeCallBuffer(node, &buffer, true, false); | 1037 InitializeCallBuffer(node, &buffer, true, false); |
1039 | 1038 |
1040 // TODO(dcarney): might be possible to use claim/poke instead | 1039 // TODO(dcarney): might be possible to use claim/poke instead |
1041 // Push any stack arguments. | 1040 // Push any stack arguments. |
1042 for (auto i = buffer.pushed_nodes.rbegin(); i != buffer.pushed_nodes.rend(); | 1041 for (auto i = buffer.pushed_nodes.rbegin(); i != buffer.pushed_nodes.rend(); |
1043 ++i) { | 1042 ++i) { |
1044 Emit(kArmPush, nullptr, g.UseRegister(*i)); | 1043 Emit(kArmPush, g.NoOutput(), g.UseRegister(*i)); |
1045 } | 1044 } |
1046 | 1045 |
1047 // Select the appropriate opcode based on the call type. | 1046 // Select the appropriate opcode based on the call type. |
1048 InstructionCode opcode; | 1047 InstructionCode opcode; |
1049 switch (descriptor->kind()) { | 1048 switch (descriptor->kind()) { |
1050 case CallDescriptor::kCallCodeObject: { | 1049 case CallDescriptor::kCallCodeObject: { |
1051 opcode = kArchCallCodeObject; | 1050 opcode = kArchCallCodeObject; |
1052 break; | 1051 break; |
1053 } | 1052 } |
1054 case CallDescriptor::kCallJSFunction: | 1053 case CallDescriptor::kCallJSFunction: |
1055 opcode = kArchCallJSFunction; | 1054 opcode = kArchCallJSFunction; |
1056 break; | 1055 break; |
1057 default: | 1056 default: |
1058 UNREACHABLE(); | 1057 UNREACHABLE(); |
1059 return; | 1058 return; |
1060 } | 1059 } |
1061 opcode |= MiscField::encode(descriptor->flags()); | 1060 opcode |= MiscField::encode(descriptor->flags()); |
1062 | 1061 |
1063 // Emit the call instruction. | 1062 // Emit the call instruction. |
1064 InstructionOperand** first_output = | 1063 InstructionOperand* first_output = |
1065 buffer.outputs.size() > 0 ? &buffer.outputs.front() : NULL; | 1064 buffer.outputs.size() > 0 ? &buffer.outputs.front() : NULL; |
1066 Instruction* call_instr = | 1065 Instruction* call_instr = |
1067 Emit(opcode, buffer.outputs.size(), first_output, | 1066 Emit(opcode, buffer.outputs.size(), first_output, |
1068 buffer.instruction_args.size(), &buffer.instruction_args.front()); | 1067 buffer.instruction_args.size(), &buffer.instruction_args.front()); |
1069 call_instr->MarkAsCall(); | 1068 call_instr->MarkAsCall(); |
1070 } | 1069 } |
1071 | 1070 |
1072 | 1071 |
1073 namespace { | 1072 namespace { |
1074 | 1073 |
1075 // Shared routine for multiple float compare operations. | 1074 // Shared routine for multiple float compare operations. |
1076 void VisitFloat64Compare(InstructionSelector* selector, Node* node, | 1075 void VisitFloat64Compare(InstructionSelector* selector, Node* node, |
1077 FlagsContinuation* cont) { | 1076 FlagsContinuation* cont) { |
1078 ArmOperandGenerator g(selector); | 1077 ArmOperandGenerator g(selector); |
1079 Float64BinopMatcher m(node); | 1078 Float64BinopMatcher m(node); |
1080 InstructionOperand* rhs = m.right().Is(0.0) ? g.UseImmediate(m.right().node()) | 1079 InstructionOperand rhs = m.right().Is(0.0) ? g.UseImmediate(m.right().node()) |
1081 : g.UseRegister(m.right().node()); | 1080 : g.UseRegister(m.right().node()); |
1082 if (cont->IsBranch()) { | 1081 if (cont->IsBranch()) { |
1083 selector->Emit(cont->Encode(kArmVcmpF64), nullptr, | 1082 selector->Emit(cont->Encode(kArmVcmpF64), g.NoOutput(), |
1084 g.UseRegister(m.left().node()), rhs, | 1083 g.UseRegister(m.left().node()), rhs, |
1085 g.Label(cont->true_block()), | 1084 g.Label(cont->true_block()), |
1086 g.Label(cont->false_block()))->MarkAsControl(); | 1085 g.Label(cont->false_block()))->MarkAsControl(); |
1087 } else { | 1086 } else { |
1088 DCHECK(cont->IsSet()); | 1087 DCHECK(cont->IsSet()); |
1089 selector->Emit(cont->Encode(kArmVcmpF64), | 1088 selector->Emit(cont->Encode(kArmVcmpF64), |
1090 g.DefineAsRegister(cont->result()), | 1089 g.DefineAsRegister(cont->result()), |
1091 g.UseRegister(m.left().node()), rhs); | 1090 g.UseRegister(m.left().node()), rhs); |
1092 } | 1091 } |
1093 } | 1092 } |
1094 | 1093 |
1095 | 1094 |
1096 // Shared routine for multiple word compare operations. | 1095 // Shared routine for multiple word compare operations. |
1097 void VisitWordCompare(InstructionSelector* selector, Node* node, | 1096 void VisitWordCompare(InstructionSelector* selector, Node* node, |
1098 InstructionCode opcode, FlagsContinuation* cont) { | 1097 InstructionCode opcode, FlagsContinuation* cont) { |
1099 ArmOperandGenerator g(selector); | 1098 ArmOperandGenerator g(selector); |
1100 Int32BinopMatcher m(node); | 1099 Int32BinopMatcher m(node); |
1101 InstructionOperand* inputs[5]; | 1100 InstructionOperand inputs[5]; |
1102 size_t input_count = 0; | 1101 size_t input_count = 0; |
1103 InstructionOperand* outputs[1]; | 1102 InstructionOperand outputs[1]; |
1104 size_t output_count = 0; | 1103 size_t output_count = 0; |
1105 | 1104 |
1106 if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(), | 1105 if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(), |
1107 &input_count, &inputs[1])) { | 1106 &input_count, &inputs[1])) { |
1108 inputs[0] = g.UseRegister(m.left().node()); | 1107 inputs[0] = g.UseRegister(m.left().node()); |
1109 input_count++; | 1108 input_count++; |
1110 } else if (TryMatchImmediateOrShift(selector, &opcode, m.left().node(), | 1109 } else if (TryMatchImmediateOrShift(selector, &opcode, m.left().node(), |
1111 &input_count, &inputs[1])) { | 1110 &input_count, &inputs[1])) { |
1112 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute(); | 1111 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute(); |
1113 inputs[0] = g.UseRegister(m.right().node()); | 1112 inputs[0] = g.UseRegister(m.right().node()); |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1227 default: | 1226 default: |
1228 break; | 1227 break; |
1229 } | 1228 } |
1230 break; | 1229 break; |
1231 } | 1230 } |
1232 | 1231 |
1233 // Continuation could not be combined with a compare, emit compare against 0. | 1232 // Continuation could not be combined with a compare, emit compare against 0. |
1234 ArmOperandGenerator g(selector); | 1233 ArmOperandGenerator g(selector); |
1235 InstructionCode const opcode = | 1234 InstructionCode const opcode = |
1236 cont->Encode(kArmTst) | AddressingModeField::encode(kMode_Operand2_R); | 1235 cont->Encode(kArmTst) | AddressingModeField::encode(kMode_Operand2_R); |
1237 InstructionOperand* const value_operand = g.UseRegister(value); | 1236 InstructionOperand const value_operand = g.UseRegister(value); |
1238 if (cont->IsBranch()) { | 1237 if (cont->IsBranch()) { |
1239 selector->Emit(opcode, nullptr, value_operand, value_operand, | 1238 selector->Emit(opcode, g.NoOutput(), value_operand, value_operand, |
1240 g.Label(cont->true_block()), | 1239 g.Label(cont->true_block()), |
1241 g.Label(cont->false_block()))->MarkAsControl(); | 1240 g.Label(cont->false_block()))->MarkAsControl(); |
1242 } else { | 1241 } else { |
1243 selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand, | 1242 selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand, |
1244 value_operand); | 1243 value_operand); |
1245 } | 1244 } |
1246 } | 1245 } |
1247 | 1246 |
1248 } // namespace | 1247 } // namespace |
1249 | 1248 |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1339 MachineOperatorBuilder::kFloat64Ceil | | 1338 MachineOperatorBuilder::kFloat64Ceil | |
1340 MachineOperatorBuilder::kFloat64RoundTruncate | | 1339 MachineOperatorBuilder::kFloat64RoundTruncate | |
1341 MachineOperatorBuilder::kFloat64RoundTiesAway; | 1340 MachineOperatorBuilder::kFloat64RoundTiesAway; |
1342 } | 1341 } |
1343 return flags; | 1342 return flags; |
1344 } | 1343 } |
1345 | 1344 |
1346 } // namespace compiler | 1345 } // namespace compiler |
1347 } // namespace internal | 1346 } // namespace internal |
1348 } // namespace v8 | 1347 } // namespace v8 |
OLD | NEW |