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/adapters.h" | 5 #include "src/base/adapters.h" |
6 #include "src/base/bits.h" | 6 #include "src/base/bits.h" |
7 #include "src/compiler/instruction-selector-impl.h" | 7 #include "src/compiler/instruction-selector-impl.h" |
8 #include "src/compiler/node-matchers.h" | 8 #include "src/compiler/node-matchers.h" |
9 #include "src/compiler/node-properties.h" | 9 #include "src/compiler/node-properties.h" |
10 | 10 |
(...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
331 selector->Emit(kArmMls, result_operand, div_operand, right_operand, | 331 selector->Emit(kArmMls, result_operand, div_operand, right_operand, |
332 left_operand); | 332 left_operand); |
333 } else { | 333 } else { |
334 InstructionOperand mul_operand = g.TempRegister(); | 334 InstructionOperand mul_operand = g.TempRegister(); |
335 selector->Emit(kArmMul, mul_operand, div_operand, right_operand); | 335 selector->Emit(kArmMul, mul_operand, div_operand, right_operand); |
336 selector->Emit(kArmSub | AddressingModeField::encode(kMode_Operand2_R), | 336 selector->Emit(kArmSub | AddressingModeField::encode(kMode_Operand2_R), |
337 result_operand, left_operand, mul_operand); | 337 result_operand, left_operand, mul_operand); |
338 } | 338 } |
339 } | 339 } |
340 | 340 |
| 341 void EmitLoad(InstructionSelector* selector, InstructionCode opcode, |
| 342 InstructionOperand* output, Node* base, Node* index) { |
| 343 ArmOperandGenerator g(selector); |
| 344 InstructionOperand inputs[3]; |
| 345 size_t input_count = 2; |
| 346 |
| 347 inputs[0] = g.UseRegister(base); |
| 348 if (g.CanBeImmediate(index, opcode)) { |
| 349 inputs[1] = g.UseImmediate(index); |
| 350 opcode |= AddressingModeField::encode(kMode_Offset_RI); |
| 351 } else if ((opcode == kArmLdr) && |
| 352 TryMatchLSLImmediate(selector, &opcode, index, &inputs[1], |
| 353 &inputs[2])) { |
| 354 input_count = 3; |
| 355 } else { |
| 356 inputs[1] = g.UseRegister(index); |
| 357 opcode |= AddressingModeField::encode(kMode_Offset_RR); |
| 358 } |
| 359 selector->Emit(opcode, 1, output, input_count, inputs); |
| 360 } |
| 361 |
| 362 void EmitStore(InstructionSelector* selector, InstructionCode opcode, |
| 363 size_t input_count, InstructionOperand* inputs, |
| 364 Node* index) { |
| 365 ArmOperandGenerator g(selector); |
| 366 |
| 367 if (g.CanBeImmediate(index, opcode)) { |
| 368 inputs[input_count++] = g.UseImmediate(index); |
| 369 opcode |= AddressingModeField::encode(kMode_Offset_RI); |
| 370 } else if ((opcode == kArmStr) && |
| 371 TryMatchLSLImmediate(selector, &opcode, index, &inputs[2], |
| 372 &inputs[3])) { |
| 373 input_count = 4; |
| 374 } else { |
| 375 inputs[input_count++] = g.UseRegister(index); |
| 376 opcode |= AddressingModeField::encode(kMode_Offset_RR); |
| 377 } |
| 378 selector->Emit(opcode, 0, nullptr, input_count, inputs); |
| 379 } |
| 380 |
341 } // namespace | 381 } // namespace |
342 | 382 |
343 | 383 |
344 void InstructionSelector::VisitLoad(Node* node) { | 384 void InstructionSelector::VisitLoad(Node* node) { |
345 LoadRepresentation load_rep = LoadRepresentationOf(node->op()); | 385 LoadRepresentation load_rep = LoadRepresentationOf(node->op()); |
346 ArmOperandGenerator g(this); | 386 ArmOperandGenerator g(this); |
347 Node* base = node->InputAt(0); | 387 Node* base = node->InputAt(0); |
348 Node* index = node->InputAt(1); | 388 Node* index = node->InputAt(1); |
349 InstructionOperand inputs[3]; | |
350 size_t input_count = 0; | |
351 InstructionOperand outputs[1]; | |
352 | 389 |
353 InstructionCode opcode = kArchNop; | 390 InstructionCode opcode = kArchNop; |
354 switch (load_rep.representation()) { | 391 switch (load_rep.representation()) { |
355 case MachineRepresentation::kFloat32: | 392 case MachineRepresentation::kFloat32: |
356 opcode = kArmVldrF32; | 393 opcode = kArmVldrF32; |
357 break; | 394 break; |
358 case MachineRepresentation::kFloat64: | 395 case MachineRepresentation::kFloat64: |
359 opcode = kArmVldrF64; | 396 opcode = kArmVldrF64; |
360 break; | 397 break; |
361 case MachineRepresentation::kBit: // Fall through. | 398 case MachineRepresentation::kBit: // Fall through. |
362 case MachineRepresentation::kWord8: | 399 case MachineRepresentation::kWord8: |
363 opcode = load_rep.IsUnsigned() ? kArmLdrb : kArmLdrsb; | 400 opcode = load_rep.IsUnsigned() ? kArmLdrb : kArmLdrsb; |
364 break; | 401 break; |
365 case MachineRepresentation::kWord16: | 402 case MachineRepresentation::kWord16: |
366 opcode = load_rep.IsUnsigned() ? kArmLdrh : kArmLdrsh; | 403 opcode = load_rep.IsUnsigned() ? kArmLdrh : kArmLdrsh; |
367 break; | 404 break; |
368 case MachineRepresentation::kTagged: // Fall through. | 405 case MachineRepresentation::kTagged: // Fall through. |
369 case MachineRepresentation::kWord32: | 406 case MachineRepresentation::kWord32: |
370 opcode = kArmLdr; | 407 opcode = kArmLdr; |
371 break; | 408 break; |
372 case MachineRepresentation::kWord64: // Fall through. | 409 case MachineRepresentation::kWord64: // Fall through. |
373 case MachineRepresentation::kSimd128: // Fall through. | 410 case MachineRepresentation::kSimd128: // Fall through. |
374 case MachineRepresentation::kNone: | 411 case MachineRepresentation::kNone: |
375 UNREACHABLE(); | 412 UNREACHABLE(); |
376 return; | 413 return; |
377 } | 414 } |
378 | 415 |
379 outputs[0] = g.DefineAsRegister(node); | 416 InstructionOperand output = g.DefineAsRegister(node); |
380 inputs[0] = g.UseRegister(base); | 417 EmitLoad(this, opcode, &output, base, index); |
381 | |
382 if (g.CanBeImmediate(index, opcode)) { | |
383 input_count = 2; | |
384 inputs[1] = g.UseImmediate(index); | |
385 opcode |= AddressingModeField::encode(kMode_Offset_RI); | |
386 } else if ((opcode == kArmLdr) && | |
387 TryMatchLSLImmediate(this, &opcode, index, &inputs[1], | |
388 &inputs[2])) { | |
389 input_count = 3; | |
390 } else { | |
391 input_count = 2; | |
392 inputs[1] = g.UseRegister(index); | |
393 opcode |= AddressingModeField::encode(kMode_Offset_RR); | |
394 } | |
395 | |
396 Emit(opcode, arraysize(outputs), outputs, input_count, inputs); | |
397 } | 418 } |
398 | 419 |
399 | 420 |
400 void InstructionSelector::VisitStore(Node* node) { | 421 void InstructionSelector::VisitStore(Node* node) { |
401 ArmOperandGenerator g(this); | 422 ArmOperandGenerator g(this); |
402 Node* base = node->InputAt(0); | 423 Node* base = node->InputAt(0); |
403 Node* index = node->InputAt(1); | 424 Node* index = node->InputAt(1); |
404 Node* value = node->InputAt(2); | 425 Node* value = node->InputAt(2); |
405 | 426 |
406 StoreRepresentation store_rep = StoreRepresentationOf(node->op()); | 427 StoreRepresentation store_rep = StoreRepresentationOf(node->op()); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
438 record_write_mode = RecordWriteMode::kValueIsAny; | 459 record_write_mode = RecordWriteMode::kValueIsAny; |
439 break; | 460 break; |
440 } | 461 } |
441 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()}; | 462 InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()}; |
442 size_t const temp_count = arraysize(temps); | 463 size_t const temp_count = arraysize(temps); |
443 InstructionCode code = kArchStoreWithWriteBarrier; | 464 InstructionCode code = kArchStoreWithWriteBarrier; |
444 code |= AddressingModeField::encode(addressing_mode); | 465 code |= AddressingModeField::encode(addressing_mode); |
445 code |= MiscField::encode(static_cast<int>(record_write_mode)); | 466 code |= MiscField::encode(static_cast<int>(record_write_mode)); |
446 Emit(code, 0, nullptr, input_count, inputs, temp_count, temps); | 467 Emit(code, 0, nullptr, input_count, inputs, temp_count, temps); |
447 } else { | 468 } else { |
448 InstructionOperand inputs[4]; | |
449 size_t input_count = 0; | |
450 | |
451 InstructionCode opcode = kArchNop; | 469 InstructionCode opcode = kArchNop; |
452 switch (rep) { | 470 switch (rep) { |
453 case MachineRepresentation::kFloat32: | 471 case MachineRepresentation::kFloat32: |
454 opcode = kArmVstrF32; | 472 opcode = kArmVstrF32; |
455 break; | 473 break; |
456 case MachineRepresentation::kFloat64: | 474 case MachineRepresentation::kFloat64: |
457 opcode = kArmVstrF64; | 475 opcode = kArmVstrF64; |
458 break; | 476 break; |
459 case MachineRepresentation::kBit: // Fall through. | 477 case MachineRepresentation::kBit: // Fall through. |
460 case MachineRepresentation::kWord8: | 478 case MachineRepresentation::kWord8: |
461 opcode = kArmStrb; | 479 opcode = kArmStrb; |
462 break; | 480 break; |
463 case MachineRepresentation::kWord16: | 481 case MachineRepresentation::kWord16: |
464 opcode = kArmStrh; | 482 opcode = kArmStrh; |
465 break; | 483 break; |
466 case MachineRepresentation::kTagged: // Fall through. | 484 case MachineRepresentation::kTagged: // Fall through. |
467 case MachineRepresentation::kWord32: | 485 case MachineRepresentation::kWord32: |
468 opcode = kArmStr; | 486 opcode = kArmStr; |
469 break; | 487 break; |
470 case MachineRepresentation::kWord64: // Fall through. | 488 case MachineRepresentation::kWord64: // Fall through. |
471 case MachineRepresentation::kSimd128: // Fall through. | 489 case MachineRepresentation::kSimd128: // Fall through. |
472 case MachineRepresentation::kNone: | 490 case MachineRepresentation::kNone: |
473 UNREACHABLE(); | 491 UNREACHABLE(); |
474 return; | 492 return; |
475 } | 493 } |
476 | 494 |
477 inputs[0] = g.UseRegister(value); | 495 InstructionOperand inputs[4]; |
478 inputs[1] = g.UseRegister(base); | 496 size_t input_count = 0; |
479 | 497 inputs[input_count++] = g.UseRegister(value); |
480 if (g.CanBeImmediate(index, opcode)) { | 498 inputs[input_count++] = g.UseRegister(base); |
481 input_count = 3; | 499 EmitStore(this, opcode, input_count, inputs, index); |
482 inputs[2] = g.UseImmediate(index); | |
483 opcode |= AddressingModeField::encode(kMode_Offset_RI); | |
484 } else if ((opcode == kArmStr) && | |
485 TryMatchLSLImmediate(this, &opcode, index, &inputs[2], | |
486 &inputs[3])) { | |
487 input_count = 4; | |
488 } else { | |
489 input_count = 3; | |
490 inputs[2] = g.UseRegister(index); | |
491 opcode |= AddressingModeField::encode(kMode_Offset_RR); | |
492 } | |
493 Emit(opcode, 0, nullptr, input_count, inputs); | |
494 } | 500 } |
495 } | 501 } |
496 | 502 |
497 // Architecture supports unaligned access, therefore VisitLoad is used instead | 503 void InstructionSelector::VisitUnalignedLoad(Node* node) { |
498 void InstructionSelector::VisitUnalignedLoad(Node* node) { UNREACHABLE(); } | 504 UnalignedLoadRepresentation load_rep = |
| 505 UnalignedLoadRepresentationOf(node->op()); |
| 506 ArmOperandGenerator g(this); |
| 507 Node* base = node->InputAt(0); |
| 508 Node* index = node->InputAt(1); |
499 | 509 |
500 // Architecture supports unaligned access, therefore VisitStore is used instead | 510 InstructionCode opcode = kArmLdr; |
501 void InstructionSelector::VisitUnalignedStore(Node* node) { UNREACHABLE(); } | 511 // Only floating point loads need to be specially handled; integer loads |
| 512 // support unaligned access. We support unaligned FP loads by loading to |
| 513 // integer registers first, then moving to the destination FP register. |
| 514 switch (load_rep.representation()) { |
| 515 case MachineRepresentation::kFloat32: { |
| 516 InstructionOperand temp = g.TempRegister(); |
| 517 EmitLoad(this, opcode, &temp, base, index); |
| 518 Emit(kArmVmovF32U32, g.DefineAsRegister(node), temp); |
| 519 return; |
| 520 } |
| 521 case MachineRepresentation::kFloat64: { |
| 522 // TODO(arm): use vld1.8 for this when NEON is available. |
| 523 // Compute the address of the least-significant half of the FP value. |
| 524 // We assume that the base node is unlikely to be an encodable immediate |
| 525 // or the result of a shift operation, so only consider the addressing |
| 526 // mode that should be used for the index node. |
| 527 InstructionCode add_opcode = kArmAdd; |
| 528 InstructionOperand inputs[3]; |
| 529 inputs[0] = g.UseRegister(base); |
| 530 |
| 531 size_t input_count; |
| 532 if (TryMatchImmediateOrShift(this, &add_opcode, index, &input_count, |
| 533 &inputs[1])) { |
| 534 // input_count has been set by TryMatchImmediateOrShift(), so increment |
| 535 // it to account for the base register in inputs[0]. |
| 536 input_count++; |
| 537 } else { |
| 538 add_opcode |= AddressingModeField::encode(kMode_Operand2_R); |
| 539 inputs[1] = g.UseRegister(index); |
| 540 input_count = 2; // Base register and index. |
| 541 } |
| 542 |
| 543 InstructionOperand addr = g.TempRegister(); |
| 544 Emit(add_opcode, 1, &addr, input_count, inputs); |
| 545 |
| 546 // Load both halves and move to an FP register. |
| 547 InstructionOperand fp_lo = g.TempRegister(); |
| 548 InstructionOperand fp_hi = g.TempRegister(); |
| 549 opcode |= AddressingModeField::encode(kMode_Offset_RI); |
| 550 Emit(opcode, fp_lo, addr, g.TempImmediate(0)); |
| 551 Emit(opcode, fp_hi, addr, g.TempImmediate(4)); |
| 552 Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), fp_lo, fp_hi); |
| 553 return; |
| 554 } |
| 555 default: |
| 556 // All other cases should support unaligned accesses. |
| 557 UNREACHABLE(); |
| 558 return; |
| 559 } |
| 560 } |
| 561 |
| 562 void InstructionSelector::VisitUnalignedStore(Node* node) { |
| 563 ArmOperandGenerator g(this); |
| 564 Node* base = node->InputAt(0); |
| 565 Node* index = node->InputAt(1); |
| 566 Node* value = node->InputAt(2); |
| 567 |
| 568 InstructionOperand inputs[4]; |
| 569 size_t input_count = 0; |
| 570 |
| 571 UnalignedStoreRepresentation store_rep = |
| 572 UnalignedStoreRepresentationOf(node->op()); |
| 573 |
| 574 // Only floating point stores need to be specially handled; integer stores |
| 575 // support unaligned access. We support unaligned FP stores by moving the |
| 576 // value to integer registers first, then storing to the destination address. |
| 577 switch (store_rep) { |
| 578 case MachineRepresentation::kFloat32: { |
| 579 inputs[input_count++] = g.TempRegister(); |
| 580 Emit(kArmVmovU32F32, inputs[0], g.UseRegister(value)); |
| 581 inputs[input_count++] = g.UseRegister(base); |
| 582 EmitStore(this, kArmStr, input_count, inputs, index); |
| 583 return; |
| 584 } |
| 585 case MachineRepresentation::kFloat64: { |
| 586 // TODO(arm): use vst1.8 for this when NEON is available. |
| 587 // Store a 64-bit floating point value using two 32-bit integer stores. |
| 588 // Computing the store address here would require three live temporary |
| 589 // registers (fp<63:32>, fp<31:0>, address), so compute base + 4 after |
| 590 // storing the least-significant half of the value. |
| 591 |
| 592 // First, move the 64-bit FP value into two temporary integer registers. |
| 593 InstructionOperand fp[] = {g.TempRegister(), g.TempRegister()}; |
| 594 inputs[input_count++] = g.UseRegister(value); |
| 595 Emit(kArmVmovU32U32F64, arraysize(fp), fp, input_count, |
| 596 inputs); |
| 597 |
| 598 // Store the least-significant half. |
| 599 inputs[0] = fp[0]; // Low 32-bits of FP value. |
| 600 inputs[input_count++] = g.UseRegister(base); // First store base address. |
| 601 EmitStore(this, kArmStr, input_count, inputs, index); |
| 602 |
| 603 // Store the most-significant half. |
| 604 InstructionOperand base4 = g.TempRegister(); |
| 605 Emit(kArmAdd | AddressingModeField::encode(kMode_Operand2_I), base4, |
| 606 g.UseRegister(base), g.TempImmediate(4)); // Compute base + 4. |
| 607 inputs[0] = fp[1]; // High 32-bits of FP value. |
| 608 inputs[1] = base4; // Second store base + 4 address. |
| 609 EmitStore(this, kArmStr, input_count, inputs, index); |
| 610 return; |
| 611 } |
| 612 default: |
| 613 // All other cases should support unaligned accesses. |
| 614 UNREACHABLE(); |
| 615 return; |
| 616 } |
| 617 } |
502 | 618 |
503 void InstructionSelector::VisitCheckedLoad(Node* node) { | 619 void InstructionSelector::VisitCheckedLoad(Node* node) { |
504 CheckedLoadRepresentation load_rep = CheckedLoadRepresentationOf(node->op()); | 620 CheckedLoadRepresentation load_rep = CheckedLoadRepresentationOf(node->op()); |
505 ArmOperandGenerator g(this); | 621 ArmOperandGenerator g(this); |
506 Node* const buffer = node->InputAt(0); | 622 Node* const buffer = node->InputAt(0); |
507 Node* const offset = node->InputAt(1); | 623 Node* const offset = node->InputAt(1); |
508 Node* const length = node->InputAt(2); | 624 Node* const length = node->InputAt(2); |
509 ArchOpcode opcode = kArchNop; | 625 ArchOpcode opcode = kArchNop; |
510 switch (load_rep.representation()) { | 626 switch (load_rep.representation()) { |
511 case MachineRepresentation::kWord8: | 627 case MachineRepresentation::kWord8: |
(...skipping 1657 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2169 MachineOperatorBuilder::kFloat64RoundTiesEven | | 2285 MachineOperatorBuilder::kFloat64RoundTiesEven | |
2170 MachineOperatorBuilder::kFloat32Neg | | 2286 MachineOperatorBuilder::kFloat32Neg | |
2171 MachineOperatorBuilder::kFloat64Neg; | 2287 MachineOperatorBuilder::kFloat64Neg; |
2172 } | 2288 } |
2173 return flags; | 2289 return flags; |
2174 } | 2290 } |
2175 | 2291 |
2176 // static | 2292 // static |
2177 MachineOperatorBuilder::AlignmentRequirements | 2293 MachineOperatorBuilder::AlignmentRequirements |
2178 InstructionSelector::AlignmentRequirements() { | 2294 InstructionSelector::AlignmentRequirements() { |
| 2295 Vector<MachineType> req_aligned = Vector<MachineType>::New(2); |
| 2296 req_aligned[0] = MachineType::Float32(); |
| 2297 req_aligned[1] = MachineType::Float64(); |
2179 return MachineOperatorBuilder::AlignmentRequirements:: | 2298 return MachineOperatorBuilder::AlignmentRequirements:: |
2180 FullUnalignedAccessSupport(); | 2299 SomeUnalignedAccessUnsupported(req_aligned, req_aligned); |
2181 } | 2300 } |
2182 | 2301 |
2183 } // namespace compiler | 2302 } // namespace compiler |
2184 } // namespace internal | 2303 } // namespace internal |
2185 } // namespace v8 | 2304 } // namespace v8 |
OLD | NEW |