| 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 |