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

Side by Side Diff: runtime/vm/assembler_arm.cc

Issue 21159002: Implements far-branches on ARM. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/assembler_arm.h ('k') | runtime/vm/assembler_mips.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/globals.h" 5 #include "vm/globals.h"
6 #if defined(TARGET_ARCH_ARM) 6 #if defined(TARGET_ARCH_ARM)
7 7
8 #include "vm/assembler.h" 8 #include "vm/assembler.h"
9 #include "vm/simulator.h" 9 #include "vm/simulator.h"
10 #include "vm/runtime_entry.h" 10 #include "vm/runtime_entry.h"
(...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after
298 static_cast<int32_t>(MOV) << kOpcodeShift | 298 static_cast<int32_t>(MOV) << kOpcodeShift |
299 static_cast<int32_t>(rd) << kRdShift | 299 static_cast<int32_t>(rd) << kRdShift |
300 so.encoding() << kShiftRegisterShift | 300 so.encoding() << kShiftRegisterShift |
301 static_cast<int32_t>(opcode) << kShiftShift | 301 static_cast<int32_t>(opcode) << kShiftShift |
302 B4 | 302 B4 |
303 static_cast<int32_t>(rm); 303 static_cast<int32_t>(rm);
304 Emit(encoding); 304 Emit(encoding);
305 } 305 }
306 306
307 307
308 void Assembler::EmitBranch(Condition cond, Label* label, bool link) {
309 if (label->IsBound()) {
310 EmitType5(cond, label->Position() - buffer_.Size(), link);
311 } else {
312 int position = buffer_.Size();
313 // Use the offset field of the branch instruction for linking the sites.
314 EmitType5(cond, label->position_, link);
315 label->LinkTo(position);
316 }
317 }
318
319
320 void Assembler::and_(Register rd, Register rn, ShifterOperand so, 308 void Assembler::and_(Register rd, Register rn, ShifterOperand so,
321 Condition cond) { 309 Condition cond) {
322 EmitType01(cond, so.type(), AND, 0, rn, rd, so); 310 EmitType01(cond, so.type(), AND, 0, rn, rd, so);
323 } 311 }
324 312
325 313
326 void Assembler::eor(Register rd, Register rn, ShifterOperand so, 314 void Assembler::eor(Register rd, Register rn, ShifterOperand so,
327 Condition cond) { 315 Condition cond) {
328 EmitType01(cond, so.type(), EOR, 0, rn, rd, so); 316 EmitType01(cond, so.type(), EOR, 0, rn, rd, so);
329 } 317 }
(...skipping 1388 matching lines...) Expand 10 before | Expand all | Expand 10 after
1718 1706
1719 1707
1720 void Assembler::CompareClassId(Register object, 1708 void Assembler::CompareClassId(Register object,
1721 intptr_t class_id, 1709 intptr_t class_id,
1722 Register scratch) { 1710 Register scratch) {
1723 LoadClassId(scratch, object); 1711 LoadClassId(scratch, object);
1724 CompareImmediate(scratch, class_id); 1712 CompareImmediate(scratch, class_id);
1725 } 1713 }
1726 1714
1727 1715
1716 static bool CanEncodeBranchOffset(int32_t offset) {
1717 offset -= Instr::kPCReadOffset;
1718 ASSERT(Utils::IsAligned(offset, 4));
1719 return Utils::IsInt(Utils::CountOneBits(kBranchOffsetMask), offset);
1720 }
1721
1722
1723 int32_t Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) {
1724 // The offset is off by 8 due to the way the ARM CPUs read PC.
1725 offset -= Instr::kPCReadOffset;
1726 ASSERT(Utils::IsAligned(offset, 4));
1727 ASSERT(Utils::IsInt(Utils::CountOneBits(kBranchOffsetMask), offset));
1728
1729 // Properly preserve only the bits supported in the instruction.
1730 offset >>= 2;
1731 offset &= kBranchOffsetMask;
1732 return (inst & ~kBranchOffsetMask) | offset;
1733 }
1734
1735
1736 int Assembler::DecodeBranchOffset(int32_t inst) {
1737 // Sign-extend, left-shift by 2, then add 8.
1738 return ((((inst & kBranchOffsetMask) << 8) >> 6) + Instr::kPCReadOffset);
1739 }
1740
1741
1742 static int32_t DecodeLoadImmediate(int32_t movt, int32_t movw) {
1743 int32_t offset = 0;
1744 offset |= (movt & 0xf0000) << 12;
1745 offset |= (movt & 0xfff) << 16;
1746 offset |= (movw & 0xf0000) >> 4;
1747 offset |= movw & 0xfff;
1748 return offset;
1749 }
1750
1751
1752 class PatchFarBranch : public AssemblerFixup {
1753 public:
1754 PatchFarBranch() {}
1755
1756 void Process(const MemoryRegion& region, int position) {
1757 const int32_t movw = region.Load<int32_t>(position);
1758 const int32_t movt = region.Load<int32_t>(position + Instr::kInstrSize);
1759 const int32_t bx = region.Load<int32_t>(position + 2 * Instr::kInstrSize);
1760
1761 if (((movt & 0xfff0f000) == 0xe340c000) && // movt IP, high
1762 ((movw & 0xfff0f000) == 0xe300c000)) { // movw IP, low
1763 const int32_t offset = DecodeLoadImmediate(movt, movw);
1764 const int32_t dest = region.start() + offset;
1765 const uint16_t dest_high = Utils::High16Bits(dest);
1766 const uint16_t dest_low = Utils::Low16Bits(dest);
1767 const int32_t patched_movt =
1768 0xe340c000 | ((dest_high >> 12) << 16) | (dest_high & 0xfff);
1769 const int32_t patched_movw =
1770 0xe300c000 | ((dest_low >> 12) << 16) | (dest_low & 0xfff);
1771
1772 region.Store<int32_t>(position, patched_movw);
1773 region.Store<int32_t>(position + Instr::kInstrSize, patched_movt);
1774 return;
1775 }
1776
1777 // If the offset loading instructions aren't there, we must have replaced
1778 // the far branch with a near one, and so these instructions should be NOPs.
1779 ASSERT((movt == Instr::kNopInstruction) &&
1780 (bx == Instr::kNopInstruction));
1781 }
1782 };
1783
1784
1785 void Assembler::EmitFarBranch(Condition cond, int32_t offset, bool link) {
1786 const uint16_t low = Utils::Low16Bits(offset);
1787 const uint16_t high = Utils::High16Bits(offset);
1788 buffer_.EmitFixup(new PatchFarBranch());
1789 movw(IP, low);
1790 movt(IP, high);
1791 if (link) {
1792 blx(IP, cond);
1793 } else {
1794 bx(IP, cond);
1795 }
1796 }
1797
1798
1799 void Assembler::EmitBranch(Condition cond, Label* label, bool link) {
1800 if (label->IsBound()) {
1801 const int32_t dest = label->Position() - buffer_.Size();
1802 if (FLAG_use_far_branches && !CanEncodeBranchOffset(dest)) {
1803 EmitFarBranch(cond, label->Position(), link);
1804 } else {
1805 EmitType5(cond, dest, link);
1806 }
1807 } else {
1808 const int position = buffer_.Size();
1809 if (FLAG_use_far_branches) {
1810 const int32_t dest = label->position_;
1811 EmitFarBranch(cond, dest, link);
1812 } else {
1813 // Use the offset field of the branch instruction for linking the sites.
1814 EmitType5(cond, label->position_, link);
1815 }
1816 label->LinkTo(position);
1817 }
1818 }
1819
1820
1728 void Assembler::Bind(Label* label) { 1821 void Assembler::Bind(Label* label) {
1729 ASSERT(!label->IsBound()); 1822 ASSERT(!label->IsBound());
1730 int bound_pc = buffer_.Size(); 1823 int bound_pc = buffer_.Size();
1731 while (label->IsLinked()) { 1824 while (label->IsLinked()) {
1732 int32_t position = label->Position(); 1825 const int32_t position = label->Position();
1733 int32_t next = buffer_.Load<int32_t>(position); 1826 int32_t dest = bound_pc - position;
1734 int32_t encoded = Assembler::EncodeBranchOffset(bound_pc - position, next); 1827 if (FLAG_use_far_branches && !CanEncodeBranchOffset(dest)) {
1735 buffer_.Store<int32_t>(position, encoded); 1828 // Far branches are enabled and we can't encode the branch offset.
1736 label->position_ = Assembler::DecodeBranchOffset(next); 1829
1830 // Grab instructions that load the offset.
1831 const int32_t movw =
1832 buffer_.Load<int32_t>(position);
1833 const int32_t movt =
1834 buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize);
1835
1836 // Change from relative to the branch to relative to the assembler buffer.
1837 dest = buffer_.Size();
1838 const uint16_t dest_high = Utils::High16Bits(dest);
1839 const uint16_t dest_low = Utils::Low16Bits(dest);
1840 const int32_t patched_movt =
1841 0xe340c000 | ((dest_high >> 12) << 16) | (dest_high & 0xfff);
1842 const int32_t patched_movw =
1843 0xe300c000 | ((dest_low >> 12) << 16) | (dest_low & 0xfff);
1844
1845 // Rewrite the instructions.
1846 buffer_.Store<int32_t>(position, patched_movw);
1847 buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize, patched_movt);
1848 label->position_ = DecodeLoadImmediate(movt, movw);
1849 } else if (FLAG_use_far_branches && CanEncodeBranchOffset(dest)) {
1850 // Far branches are enabled, but we can encode the branch offset.
1851
1852 // Grab instructions that load the offset, and the branch.
1853 const int32_t movw =
1854 buffer_.Load<int32_t>(position);
1855 const int32_t movt =
1856 buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize);
1857 const int32_t branch =
1858 buffer_.Load<int32_t>(position + 2 * Instr::kInstrSize);
1859
1860 // Grab the branch condition, and encode the link bit.
1861 const int32_t cond = branch & 0xf0000000;
1862 const int32_t link = (branch & 0x20) << 19;
1863
1864 // Encode the branch and the offset.
1865 const int32_t new_branch = cond | link | 0x0a000000;
1866 const int32_t encoded = EncodeBranchOffset(dest, new_branch);
1867
1868 // Write the encoded branch instruction followed by two nops.
1869 buffer_.Store<int32_t>(position, encoded);
1870 buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize,
1871 Instr::kNopInstruction);
1872 buffer_.Store<int32_t>(position + 2 * Instr::kInstrSize,
1873 Instr::kNopInstruction);
1874
1875 label->position_ = DecodeLoadImmediate(movt, movw);
1876 } else {
1877 int32_t next = buffer_.Load<int32_t>(position);
1878 int32_t encoded = Assembler::EncodeBranchOffset(dest, next);
1879 buffer_.Store<int32_t>(position, encoded);
1880 label->position_ = Assembler::DecodeBranchOffset(next);
1881 }
1737 } 1882 }
1738 label->BindTo(bound_pc); 1883 label->BindTo(bound_pc);
1739 } 1884 }
1740 1885
1741 1886
1742 bool Address::CanHoldLoadOffset(OperandSize type, 1887 bool Address::CanHoldLoadOffset(OperandSize type,
1743 int32_t offset, 1888 int32_t offset,
1744 int32_t* offset_mask) { 1889 int32_t* offset_mask) {
1745 switch (type) { 1890 switch (type) {
1746 case kByte: 1891 case kByte:
(...skipping 661 matching lines...) Expand 10 before | Expand all | Expand 10 after
2408 2553
2409 // On entry to a function compiled for OSR, the caller's frame pointer, the 2554 // On entry to a function compiled for OSR, the caller's frame pointer, the
2410 // stack locals, and any copied parameters are already in place. The frame 2555 // stack locals, and any copied parameters are already in place. The frame
2411 // pointer is already set up. The PC marker is not correct for the 2556 // pointer is already set up. The PC marker is not correct for the
2412 // optimized function and there may be extra space for spill slots to 2557 // optimized function and there may be extra space for spill slots to
2413 // allocate. We must also set up the pool pointer for the function. 2558 // allocate. We must also set up the pool pointer for the function.
2414 void Assembler::EnterOsrFrame(intptr_t extra_size) { 2559 void Assembler::EnterOsrFrame(intptr_t extra_size) {
2415 const intptr_t offset = CodeSize(); 2560 const intptr_t offset = CodeSize();
2416 2561
2417 Comment("EnterOsrFrame"); 2562 Comment("EnterOsrFrame");
2418 mov(TMP, ShifterOperand(PC)); 2563 mov(IP, ShifterOperand(PC));
2419 2564
2420 AddImmediate(TMP, -offset); 2565 AddImmediate(IP, -offset);
2421 str(TMP, Address(FP, kPcMarkerSlotFromFp * kWordSize)); 2566 str(IP, Address(FP, kPcMarkerSlotFromFp * kWordSize));
2422 2567
2423 // Setup pool pointer for this dart function. 2568 // Setup pool pointer for this dart function.
2424 LoadPoolPointer(); 2569 LoadPoolPointer();
2425 2570
2426 AddImmediate(SP, -extra_size); 2571 AddImmediate(SP, -extra_size);
2427 } 2572 }
2428 2573
2429 2574
2430 void Assembler::LeaveDartFrame() { 2575 void Assembler::LeaveDartFrame() {
2431 LeaveFrame((1 << PP) | (1 << FP) | (1 << LR)); 2576 LeaveFrame((1 << PP) | (1 << FP) | (1 << LR));
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
2466 Register instance_reg) { 2611 Register instance_reg) {
2467 ASSERT(failure != NULL); 2612 ASSERT(failure != NULL);
2468 if (FLAG_inline_alloc) { 2613 if (FLAG_inline_alloc) {
2469 Heap* heap = Isolate::Current()->heap(); 2614 Heap* heap = Isolate::Current()->heap();
2470 const intptr_t instance_size = cls.instance_size(); 2615 const intptr_t instance_size = cls.instance_size();
2471 LoadImmediate(instance_reg, heap->TopAddress()); 2616 LoadImmediate(instance_reg, heap->TopAddress());
2472 ldr(instance_reg, Address(instance_reg, 0)); 2617 ldr(instance_reg, Address(instance_reg, 0));
2473 AddImmediate(instance_reg, instance_size); 2618 AddImmediate(instance_reg, instance_size);
2474 2619
2475 // instance_reg: potential next object start. 2620 // instance_reg: potential next object start.
2476 LoadImmediate(TMP, heap->EndAddress()); 2621 LoadImmediate(IP, heap->EndAddress());
2477 ldr(TMP, Address(TMP, 0)); 2622 ldr(IP, Address(IP, 0));
2478 cmp(TMP, ShifterOperand(instance_reg)); 2623 cmp(IP, ShifterOperand(instance_reg));
2479 // fail if heap end unsigned less than or equal to instance_reg. 2624 // fail if heap end unsigned less than or equal to instance_reg.
2480 b(failure, LS); 2625 b(failure, LS);
2481 2626
2482 // Successfully allocated the object, now update top to point to 2627 // Successfully allocated the object, now update top to point to
2483 // next object start and store the class in the class field of object. 2628 // next object start and store the class in the class field of object.
2484 LoadImmediate(TMP, heap->TopAddress()); 2629 LoadImmediate(IP, heap->TopAddress());
2485 str(instance_reg, Address(TMP, 0)); 2630 str(instance_reg, Address(IP, 0));
2486 2631
2487 ASSERT(instance_size >= kHeapObjectTag); 2632 ASSERT(instance_size >= kHeapObjectTag);
2488 AddImmediate(instance_reg, -instance_size + kHeapObjectTag); 2633 AddImmediate(instance_reg, -instance_size + kHeapObjectTag);
2489 2634
2490 uword tags = 0; 2635 uword tags = 0;
2491 tags = RawObject::SizeTag::update(instance_size, tags); 2636 tags = RawObject::SizeTag::update(instance_size, tags);
2492 ASSERT(cls.id() != kIllegalCid); 2637 ASSERT(cls.id() != kIllegalCid);
2493 tags = RawObject::ClassIdTag::update(cls.id(), tags); 2638 tags = RawObject::ClassIdTag::update(cls.id(), tags);
2494 LoadImmediate(TMP, tags); 2639 LoadImmediate(IP, tags);
2495 str(TMP, FieldAddress(instance_reg, Object::tags_offset())); 2640 str(IP, FieldAddress(instance_reg, Object::tags_offset()));
2496 } else { 2641 } else {
2497 b(failure); 2642 b(failure);
2498 } 2643 }
2499 } 2644 }
2500 2645
2501 2646
2502 void Assembler::Stop(const char* message) { 2647 void Assembler::Stop(const char* message) {
2503 if (FLAG_print_stop_message) { 2648 if (FLAG_print_stop_message) {
2504 PushList((1 << R0) | (1 << IP) | (1 << LR)); // Preserve R0, IP, LR. 2649 PushList((1 << R0) | (1 << IP) | (1 << LR)); // Preserve R0, IP, LR.
2505 LoadImmediate(R0, reinterpret_cast<int32_t>(message)); 2650 LoadImmediate(R0, reinterpret_cast<int32_t>(message));
2506 // PrintStopMessage() preserves all registers. 2651 // PrintStopMessage() preserves all registers.
2507 BranchLink(&StubCode::PrintStopMessageLabel()); // Passing message in R0. 2652 BranchLink(&StubCode::PrintStopMessageLabel()); // Passing message in R0.
2508 PopList((1 << R0) | (1 << IP) | (1 << LR)); // Restore R0, IP, LR. 2653 PopList((1 << R0) | (1 << IP) | (1 << LR)); // Restore R0, IP, LR.
2509 } 2654 }
2510 // Emit the message address before the svc instruction, so that we can 2655 // Emit the message address before the svc instruction, so that we can
2511 // 'unstop' and continue execution in the simulator or jump to the next 2656 // 'unstop' and continue execution in the simulator or jump to the next
2512 // instruction in gdb. 2657 // instruction in gdb.
2513 Label stop; 2658 Label stop;
2514 b(&stop); 2659 b(&stop);
2515 Emit(reinterpret_cast<int32_t>(message)); 2660 Emit(reinterpret_cast<int32_t>(message));
2516 Bind(&stop); 2661 Bind(&stop);
2517 svc(kStopMessageSvcCode); 2662 svc(kStopMessageSvcCode);
2518 } 2663 }
2519 2664
2520 2665
2521 int32_t Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) {
2522 // The offset is off by 8 due to the way the ARM CPUs read PC.
2523 offset -= 8;
2524 ASSERT(Utils::IsAligned(offset, 4));
2525 ASSERT(Utils::IsInt(Utils::CountOneBits(kBranchOffsetMask), offset));
2526
2527 // Properly preserve only the bits supported in the instruction.
2528 offset >>= 2;
2529 offset &= kBranchOffsetMask;
2530 return (inst & ~kBranchOffsetMask) | offset;
2531 }
2532
2533
2534 int Assembler::DecodeBranchOffset(int32_t inst) {
2535 // Sign-extend, left-shift by 2, then add 8.
2536 return ((((inst & kBranchOffsetMask) << 8) >> 6) + 8);
2537 }
2538
2539
2540 int32_t Assembler::AddObject(const Object& obj) { 2666 int32_t Assembler::AddObject(const Object& obj) {
2541 ASSERT(obj.IsNotTemporaryScopedHandle()); 2667 ASSERT(obj.IsNotTemporaryScopedHandle());
2542 ASSERT(obj.IsOld()); 2668 ASSERT(obj.IsOld());
2543 if (object_pool_.IsNull()) { 2669 if (object_pool_.IsNull()) {
2544 // The object pool cannot be used in the vm isolate. 2670 // The object pool cannot be used in the vm isolate.
2545 ASSERT(Isolate::Current() != Dart::vm_isolate()); 2671 ASSERT(Isolate::Current() != Dart::vm_isolate());
2546 object_pool_ = GrowableObjectArray::New(Heap::kOld); 2672 object_pool_ = GrowableObjectArray::New(Heap::kOld);
2547 } 2673 }
2548 for (int i = 0; i < object_pool_.Length(); i++) { 2674 for (int i = 0; i < object_pool_.Length(); i++) {
2549 if (object_pool_.At(i) == obj.raw()) { 2675 if (object_pool_.At(i) == obj.raw()) {
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
2594 2720
2595 const char* Assembler::FpuRegisterName(FpuRegister reg) { 2721 const char* Assembler::FpuRegisterName(FpuRegister reg) {
2596 ASSERT((0 <= reg) && (reg < kNumberOfFpuRegisters)); 2722 ASSERT((0 <= reg) && (reg < kNumberOfFpuRegisters));
2597 return fpu_reg_names[reg]; 2723 return fpu_reg_names[reg];
2598 } 2724 }
2599 2725
2600 } // namespace dart 2726 } // namespace dart
2601 2727
2602 #endif // defined TARGET_ARCH_ARM 2728 #endif // defined TARGET_ARCH_ARM
2603 2729
OLDNEW
« no previous file with comments | « runtime/vm/assembler_arm.h ('k') | runtime/vm/assembler_mips.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698