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

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 -= 8;
regis 2013/07/29 21:48:04 Opportunity for cleanup: Use Instr::kPCReadOffset
zra 2013/08/01 15:15:58 Done.
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 -= 8;
regis 2013/07/29 21:48:04 ditto
zra 2013/08/01 15:15:58 Done.
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) + 8);
regis 2013/07/29 21:48:04 ditto
zra 2013/08/01 15:15:58 Done.
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 TMP, high
regis 2013/07/29 21:48:04 For clarity, I would use the name IP instead of TM
zra 2013/08/01 15:15:58 Renamed all instances in this file.
1762 ((movw & 0xfff0f000) == 0xe300c000)) { // movw TMP, 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(TMP, low);
1790 movt(TMP, high);
1791 if (link) {
1792 blx(TMP, cond);
1793 } else {
1794 bx(TMP, 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 764 matching lines...) Expand 10 before | Expand all | Expand 10 after
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