OLD | NEW |
---|---|
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/cpu.h" | 9 #include "vm/cpu.h" |
10 #include "vm/longjump.h" | 10 #include "vm/longjump.h" |
11 #include "vm/runtime_entry.h" | 11 #include "vm/runtime_entry.h" |
12 #include "vm/simulator.h" | 12 #include "vm/simulator.h" |
13 #include "vm/stack_frame.h" | 13 #include "vm/stack_frame.h" |
14 #include "vm/stub_code.h" | 14 #include "vm/stub_code.h" |
15 | 15 |
16 // An extra check since we are assuming the existence of /proc/cpuinfo below. | 16 // An extra check since we are assuming the existence of /proc/cpuinfo below. |
17 #if !defined(USING_SIMULATOR) && !defined(__linux__) && !defined(ANDROID) | 17 #if !defined(USING_SIMULATOR) && !defined(__linux__) && !defined(ANDROID) |
18 #error ARM cross-compile only supported on Linux | 18 #error ARM cross-compile only supported on Linux |
19 #endif | 19 #endif |
20 | 20 |
21 namespace dart { | 21 namespace dart { |
22 | 22 |
23 DEFINE_FLAG(bool, print_stop_message, true, "Print stop message."); | 23 DEFINE_FLAG(bool, print_stop_message, true, "Print stop message."); |
24 DECLARE_FLAG(bool, inline_alloc); | 24 DECLARE_FLAG(bool, inline_alloc); |
25 | 25 |
26 | |
27 // Instruction encoding bits. | 26 // Instruction encoding bits. |
28 enum { | 27 enum { |
29 H = 1 << 5, // halfword (or byte) | 28 H = 1 << 5, // halfword (or byte) |
30 L = 1 << 20, // load (or store) | 29 L = 1 << 20, // load (or store) |
31 S = 1 << 20, // set condition code (or leave unchanged) | 30 S = 1 << 20, // set condition code (or leave unchanged) |
32 W = 1 << 21, // writeback base register (or leave unchanged) | 31 W = 1 << 21, // writeback base register (or leave unchanged) |
33 A = 1 << 21, // accumulate in multiply instruction (or not) | 32 A = 1 << 21, // accumulate in multiply instruction (or not) |
34 B = 1 << 22, // unsigned byte (or word) | 33 B = 1 << 22, // unsigned byte (or word) |
35 D = 1 << 22, // high/lo bit of start of s/d register range | 34 D = 1 << 22, // high/lo bit of start of s/d register range |
36 N = 1 << 22, // long (or short) | 35 N = 1 << 22, // long (or short) |
(...skipping 1414 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1451 if (Address::CanHoldLoadOffset(kWord, offset, &offset_mask)) { | 1450 if (Address::CanHoldLoadOffset(kWord, offset, &offset_mask)) { |
1452 ldr(rd, Address(PP, offset), cond); | 1451 ldr(rd, Address(PP, offset), cond); |
1453 } else { | 1452 } else { |
1454 int32_t offset_hi = offset & ~offset_mask; // signed | 1453 int32_t offset_hi = offset & ~offset_mask; // signed |
1455 uint32_t offset_lo = offset & offset_mask; // unsigned | 1454 uint32_t offset_lo = offset & offset_mask; // unsigned |
1456 // Inline a simplified version of AddImmediate(rd, PP, offset_hi). | 1455 // Inline a simplified version of AddImmediate(rd, PP, offset_hi). |
1457 ShifterOperand shifter_op; | 1456 ShifterOperand shifter_op; |
1458 if (ShifterOperand::CanHold(offset_hi, &shifter_op)) { | 1457 if (ShifterOperand::CanHold(offset_hi, &shifter_op)) { |
1459 add(rd, PP, shifter_op, cond); | 1458 add(rd, PP, shifter_op, cond); |
1460 } else { | 1459 } else { |
1461 movw(rd, Utils::Low16Bits(offset_hi)); | 1460 LoadLargeImmediate(rd, offset_hi, cond); |
regis
2014/03/06 17:32:11
I would simply call LoadImmediate here.
zra
2014/03/07 19:00:17
Done.
| |
1462 const uint16_t value_high = Utils::High16Bits(offset_hi); | |
1463 if (value_high != 0) { | |
1464 movt(rd, value_high, cond); | |
1465 } | |
1466 add(rd, PP, ShifterOperand(LR), cond); | 1461 add(rd, PP, ShifterOperand(LR), cond); |
1467 } | 1462 } |
1468 ldr(rd, Address(rd, offset_lo), cond); | 1463 ldr(rd, Address(rd, offset_lo), cond); |
1469 } | 1464 } |
1470 } | 1465 } |
1471 | 1466 |
1472 | 1467 |
1473 void Assembler::LoadPoolPointer() { | 1468 void Assembler::LoadPoolPointer() { |
1474 const intptr_t object_pool_pc_dist = | 1469 const intptr_t object_pool_pc_dist = |
1475 Instructions::HeaderSize() - Instructions::object_pool_offset() + | 1470 Instructions::HeaderSize() - Instructions::object_pool_offset() + |
1476 CodeSize() + Instr::kPCReadOffset; | 1471 CodeSize() + Instr::kPCReadOffset; |
1477 LoadFromOffset(kWord, PP, PC, -object_pool_pc_dist); | 1472 LoadFromOffset(kWord, PP, PC, -object_pool_pc_dist); |
1478 } | 1473 } |
1479 | 1474 |
1480 | 1475 |
1481 void Assembler::LoadObject(Register rd, const Object& object, Condition cond) { | 1476 void Assembler::LoadObject(Register rd, const Object& object, Condition cond) { |
1482 // Smis and VM heap objects are never relocated; do not use object pool. | 1477 // Smis and VM heap objects are never relocated; do not use object pool. |
1483 if (object.IsSmi()) { | 1478 if (object.IsSmi()) { |
1484 LoadImmediate(rd, reinterpret_cast<int32_t>(object.raw()), cond); | 1479 LoadImmediate(rd, reinterpret_cast<int32_t>(object.raw()), cond); |
1485 } else if (object.InVMHeap()) { | 1480 } else if (object.InVMHeap()) { |
1486 // Make sure that class CallPattern is able to decode this load immediate. | 1481 // Make sure that class CallPattern is able to decode this load immediate. |
1487 const int32_t object_raw = reinterpret_cast<int32_t>(object.raw()); | 1482 const int32_t object_raw = reinterpret_cast<int32_t>(object.raw()); |
1488 movw(rd, Utils::Low16Bits(object_raw), cond); | 1483 LoadLargeImmediate(rd, object_raw, cond); |
regis
2014/03/06 17:32:11
ditto
zra
2014/03/07 19:00:17
Done.
| |
1489 const uint16_t value_high = Utils::High16Bits(object_raw); | |
1490 if (value_high != 0) { | |
1491 movt(rd, value_high, cond); | |
1492 } | |
1493 } else { | 1484 } else { |
1494 // Make sure that class CallPattern is able to decode this load from the | 1485 // Make sure that class CallPattern is able to decode this load from the |
1495 // object pool. | 1486 // object pool. |
1496 const int32_t offset = | 1487 const int32_t offset = |
1497 Array::data_offset() + 4*AddObject(object) - kHeapObjectTag; | 1488 Array::data_offset() + 4*AddObject(object) - kHeapObjectTag; |
1498 LoadWordFromPoolOffset(rd, offset, cond); | 1489 LoadWordFromPoolOffset(rd, offset, cond); |
1499 } | 1490 } |
1500 } | 1491 } |
1501 | 1492 |
1502 | 1493 |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1661 return (inst & ~kBranchOffsetMask) | offset; | 1652 return (inst & ~kBranchOffsetMask) | offset; |
1662 } | 1653 } |
1663 | 1654 |
1664 | 1655 |
1665 int Assembler::DecodeBranchOffset(int32_t inst) { | 1656 int Assembler::DecodeBranchOffset(int32_t inst) { |
1666 // Sign-extend, left-shift by 2, then add 8. | 1657 // Sign-extend, left-shift by 2, then add 8. |
1667 return ((((inst & kBranchOffsetMask) << 8) >> 6) + Instr::kPCReadOffset); | 1658 return ((((inst & kBranchOffsetMask) << 8) >> 6) + Instr::kPCReadOffset); |
1668 } | 1659 } |
1669 | 1660 |
1670 | 1661 |
1671 static int32_t DecodeLoadImmediate(int32_t movt, int32_t movw) { | 1662 static int32_t DecodeARMv7LoadImmediate(int32_t movt, int32_t movw) { |
1672 int32_t offset = 0; | 1663 int32_t offset = 0; |
1673 offset |= (movt & 0xf0000) << 12; | 1664 offset |= (movt & 0xf0000) << 12; |
1674 offset |= (movt & 0xfff) << 16; | 1665 offset |= (movt & 0xfff) << 16; |
1675 offset |= (movw & 0xf0000) >> 4; | 1666 offset |= (movw & 0xf0000) >> 4; |
1676 offset |= movw & 0xfff; | 1667 offset |= movw & 0xfff; |
1677 return offset; | 1668 return offset; |
1678 } | 1669 } |
1679 | 1670 |
1680 | 1671 |
1672 static int32_t DecodeARMv6LoadImmediate(int32_t mov, int32_t or1, | |
1673 int32_t or2, int32_t or3) { | |
1674 int32_t offset = 0; | |
1675 offset |= (mov & 0xff) << 24; | |
1676 offset |= (or1 & 0xff) << 16; | |
1677 offset |= (or2 & 0xff) << 8; | |
1678 offset |= (or3 & 0xff); | |
1679 return offset; | |
1680 } | |
1681 | |
1682 | |
1681 class PatchFarBranch : public AssemblerFixup { | 1683 class PatchFarBranch : public AssemblerFixup { |
1682 public: | 1684 public: |
1683 PatchFarBranch() {} | 1685 PatchFarBranch() {} |
1684 | 1686 |
1685 void Process(const MemoryRegion& region, intptr_t position) { | 1687 void Process(const MemoryRegion& region, intptr_t position) { |
1688 if (TargetCPUFeatures::arm_version() == ARMv6) { | |
1689 ProcessARMv6(region, position); | |
1690 } else { | |
1691 ASSERT(TargetCPUFeatures::arm_version() == ARMv7); | |
1692 ProcessARMv7(region, position); | |
1693 } | |
1694 } | |
1695 | |
1696 private: | |
1697 void ProcessARMv6(const MemoryRegion& region, intptr_t position) { | |
1698 const int32_t mov = region.Load<int32_t>(position); | |
1699 const int32_t or1 = region.Load<int32_t>(position + 1*Instr::kInstrSize); | |
1700 const int32_t or2 = region.Load<int32_t>(position + 2*Instr::kInstrSize); | |
1701 const int32_t or3 = region.Load<int32_t>(position + 3*Instr::kInstrSize); | |
1702 const int32_t bx = region.Load<int32_t>(position + 4*Instr::kInstrSize); | |
1703 | |
1704 if (((mov & 0xffffff00) == 0xe3a0c400) && // mov IP, (byte3 rot 4) | |
1705 ((or1 & 0xffffff00) == 0xe38cc800) && // orr IP, IP, (byte2 rot 8) | |
1706 ((or2 & 0xffffff00) == 0xe38ccc00) && // orr IP, IP, (byte1 rot 12) | |
1707 ((or3 & 0xffffff00) == 0xe38cc000)) { // orr IP, IP, byte0 | |
1708 const int32_t offset = DecodeARMv6LoadImmediate(mov, or1, or2, or3); | |
1709 const int32_t dest = region.start() + offset; | |
1710 const int32_t dest0 = (dest & 0x000000ff); | |
1711 const int32_t dest1 = (dest & 0x0000ff00) >> 8; | |
1712 const int32_t dest2 = (dest & 0x00ff0000) >> 16; | |
1713 const int32_t dest3 = (dest & 0xff000000) >> 24; | |
1714 const int32_t patched_mov = 0xe3a0c400 | dest3; | |
1715 const int32_t patched_or1 = 0xe38cc800 | dest2; | |
1716 const int32_t patched_or2 = 0xe38ccc00 | dest1; | |
1717 const int32_t patched_or3 = 0xe38cc000 | dest0; | |
1718 | |
1719 region.Store<int32_t>(position + 0 * Instr::kInstrSize, patched_mov); | |
1720 region.Store<int32_t>(position + 1 * Instr::kInstrSize, patched_or1); | |
1721 region.Store<int32_t>(position + 2 * Instr::kInstrSize, patched_or2); | |
1722 region.Store<int32_t>(position + 3 * Instr::kInstrSize, patched_or3); | |
1723 return; | |
1724 } | |
1725 | |
1726 // If the offset loading instructions aren't there, we must have replaced | |
1727 // the far branch with a near one, and so these instructions | |
1728 // should be NOPs. | |
1729 ASSERT((or1 == Instr::kNopInstruction) && | |
1730 (or2 == Instr::kNopInstruction) && | |
1731 (or3 == Instr::kNopInstruction) && | |
1732 (bx == Instr::kNopInstruction)); | |
1733 } | |
1734 | |
1735 | |
1736 void ProcessARMv7(const MemoryRegion& region, intptr_t position) { | |
1686 const int32_t movw = region.Load<int32_t>(position); | 1737 const int32_t movw = region.Load<int32_t>(position); |
1687 const int32_t movt = region.Load<int32_t>(position + Instr::kInstrSize); | 1738 const int32_t movt = region.Load<int32_t>(position + Instr::kInstrSize); |
1688 const int32_t bx = region.Load<int32_t>(position + 2 * Instr::kInstrSize); | 1739 const int32_t bx = region.Load<int32_t>(position + 2 * Instr::kInstrSize); |
1689 | 1740 |
1690 if (((movt & 0xfff0f000) == 0xe340c000) && // movt IP, high | 1741 if (((movt & 0xfff0f000) == 0xe340c000) && // movt IP, high |
1691 ((movw & 0xfff0f000) == 0xe300c000)) { // movw IP, low | 1742 ((movw & 0xfff0f000) == 0xe300c000)) { // movw IP, low |
1692 const int32_t offset = DecodeLoadImmediate(movt, movw); | 1743 const int32_t offset = DecodeARMv7LoadImmediate(movt, movw); |
1693 const int32_t dest = region.start() + offset; | 1744 const int32_t dest = region.start() + offset; |
1694 const uint16_t dest_high = Utils::High16Bits(dest); | 1745 const uint16_t dest_high = Utils::High16Bits(dest); |
1695 const uint16_t dest_low = Utils::Low16Bits(dest); | 1746 const uint16_t dest_low = Utils::Low16Bits(dest); |
1696 const int32_t patched_movt = | 1747 const int32_t patched_movt = |
1697 0xe340c000 | ((dest_high >> 12) << 16) | (dest_high & 0xfff); | 1748 0xe340c000 | ((dest_high >> 12) << 16) | (dest_high & 0xfff); |
1698 const int32_t patched_movw = | 1749 const int32_t patched_movw = |
1699 0xe300c000 | ((dest_low >> 12) << 16) | (dest_low & 0xfff); | 1750 0xe300c000 | ((dest_low >> 12) << 16) | (dest_low & 0xfff); |
1700 | 1751 |
1701 region.Store<int32_t>(position, patched_movw); | 1752 region.Store<int32_t>(position, patched_movw); |
1702 region.Store<int32_t>(position + Instr::kInstrSize, patched_movt); | 1753 region.Store<int32_t>(position + Instr::kInstrSize, patched_movt); |
1703 return; | 1754 return; |
1704 } | 1755 } |
1705 | 1756 |
1706 // If the offset loading instructions aren't there, we must have replaced | 1757 // If the offset loading instructions aren't there, we must have replaced |
1707 // the far branch with a near one, and so these instructions should be NOPs. | 1758 // the far branch with a near one, and so these instructions |
1759 // should be NOPs. | |
1708 ASSERT((movt == Instr::kNopInstruction) && | 1760 ASSERT((movt == Instr::kNopInstruction) && |
1709 (bx == Instr::kNopInstruction)); | 1761 (bx == Instr::kNopInstruction)); |
1710 } | 1762 } |
1711 | 1763 |
1712 virtual bool IsPointerOffset() const { return false; } | 1764 virtual bool IsPointerOffset() const { return false; } |
1713 }; | 1765 }; |
1714 | 1766 |
1715 | 1767 |
1716 void Assembler::EmitFarBranch(Condition cond, int32_t offset, bool link) { | 1768 void Assembler::EmitFarBranch(Condition cond, int32_t offset, bool link) { |
1717 const uint16_t low = Utils::Low16Bits(offset); | |
1718 const uint16_t high = Utils::High16Bits(offset); | |
1719 buffer_.EmitFixup(new PatchFarBranch()); | 1769 buffer_.EmitFixup(new PatchFarBranch()); |
1720 movw(IP, low); | 1770 if (TargetCPUFeatures::arm_version() == ARMv6) { |
1721 movt(IP, high); | 1771 LoadLargeImmediate(IP, offset); |
1772 } else { | |
1773 ASSERT(TargetCPUFeatures::arm_version() == ARMv7); | |
1774 const uint16_t low = Utils::Low16Bits(offset); | |
1775 const uint16_t high = Utils::High16Bits(offset); | |
1776 movw(IP, low); | |
1777 movt(IP, high); | |
regis
2014/03/06 17:32:11
Call LoadPatchableImmediate independently of the a
zra
2014/03/07 19:00:17
Done.
| |
1778 } | |
1722 if (link) { | 1779 if (link) { |
1723 blx(IP, cond); | 1780 blx(IP, cond); |
1724 } else { | 1781 } else { |
1725 bx(IP, cond); | 1782 bx(IP, cond); |
1726 } | 1783 } |
1727 } | 1784 } |
1728 | 1785 |
1729 | 1786 |
1730 void Assembler::EmitBranch(Condition cond, Label* label, bool link) { | 1787 void Assembler::EmitBranch(Condition cond, Label* label, bool link) { |
1731 if (label->IsBound()) { | 1788 if (label->IsBound()) { |
(...skipping 10 matching lines...) Expand all Loading... | |
1742 EmitFarBranch(cond, dest, link); | 1799 EmitFarBranch(cond, dest, link); |
1743 } else { | 1800 } else { |
1744 // Use the offset field of the branch instruction for linking the sites. | 1801 // Use the offset field of the branch instruction for linking the sites. |
1745 EmitType5(cond, label->position_, link); | 1802 EmitType5(cond, label->position_, link); |
1746 } | 1803 } |
1747 label->LinkTo(position); | 1804 label->LinkTo(position); |
1748 } | 1805 } |
1749 } | 1806 } |
1750 | 1807 |
1751 | 1808 |
1752 void Assembler::Bind(Label* label) { | 1809 void Assembler::BindARMv6(Label* label) { |
1753 ASSERT(!label->IsBound()); | 1810 ASSERT(!label->IsBound()); |
1754 intptr_t bound_pc = buffer_.Size(); | 1811 intptr_t bound_pc = buffer_.Size(); |
1755 while (label->IsLinked()) { | 1812 while (label->IsLinked()) { |
1756 const int32_t position = label->Position(); | 1813 const int32_t position = label->Position(); |
1757 int32_t dest = bound_pc - position; | 1814 int32_t dest = bound_pc - position; |
1758 if (use_far_branches() && !CanEncodeBranchOffset(dest)) { | 1815 if (use_far_branches() && !CanEncodeBranchOffset(dest)) { |
1759 // Far branches are enabled and we can't encode the branch offset. | 1816 // Far branches are enabled and we can't encode the branch offset. |
1760 | 1817 |
1761 // Grab instructions that load the offset. | 1818 // Grab instructions that load the offset. |
1819 const int32_t mov = | |
1820 buffer_.Load<int32_t>(position); | |
1821 const int32_t or1 = | |
1822 buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize); | |
1823 const int32_t or2 = | |
1824 buffer_.Load<int32_t>(position + 2 * Instr::kInstrSize); | |
1825 const int32_t or3 = | |
1826 buffer_.Load<int32_t>(position + 3 * Instr::kInstrSize); | |
1827 | |
1828 // Change from relative to the branch to relative to the assembler | |
1829 // buffer. | |
1830 dest = buffer_.Size(); | |
1831 const int32_t dest0 = (dest & 0x000000ff); | |
1832 const int32_t dest1 = (dest & 0x0000ff00) >> 8; | |
1833 const int32_t dest2 = (dest & 0x00ff0000) >> 16; | |
1834 const int32_t dest3 = (dest & 0xff000000) >> 24; | |
1835 const int32_t patched_mov = 0xe3a0c400 | dest3; | |
1836 const int32_t patched_or1 = 0xe38cc800 | dest2; | |
1837 const int32_t patched_or2 = 0xe38ccc00 | dest1; | |
1838 const int32_t patched_or3 = 0xe38cc000 | dest0; | |
1839 | |
1840 // Rewrite the instructions. | |
1841 buffer_.Store<int32_t>(position + 0 * Instr::kInstrSize, patched_mov); | |
1842 buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize, patched_or1); | |
1843 buffer_.Store<int32_t>(position + 2 * Instr::kInstrSize, patched_or2); | |
1844 buffer_.Store<int32_t>(position + 3 * Instr::kInstrSize, patched_or3); | |
1845 label->position_ = DecodeARMv6LoadImmediate(mov, or1, or2, or3); | |
1846 } else if (use_far_branches() && CanEncodeBranchOffset(dest)) { | |
1847 // Grab instructions that load the offset, and the branch. | |
1848 const int32_t mov = | |
1849 buffer_.Load<int32_t>(position); | |
1850 const int32_t or1 = | |
1851 buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize); | |
1852 const int32_t or2 = | |
1853 buffer_.Load<int32_t>(position + 2 * Instr::kInstrSize); | |
1854 const int32_t or3 = | |
1855 buffer_.Load<int32_t>(position + 3 * Instr::kInstrSize); | |
1856 const int32_t branch = | |
1857 buffer_.Load<int32_t>(position + 4 * Instr::kInstrSize); | |
1858 | |
1859 // Grab the branch condition, and encode the link bit. | |
1860 const int32_t cond = branch & 0xf0000000; | |
1861 const int32_t link = (branch & 0x20) << 19; | |
1862 | |
1863 // Encode the branch and the offset. | |
1864 const int32_t new_branch = cond | link | 0x0a000000; | |
1865 const int32_t encoded = EncodeBranchOffset(dest, new_branch); | |
1866 | |
1867 // Write the encoded branch instruction followed by two nops. | |
1868 buffer_.Store<int32_t>(position, encoded); | |
1869 buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize, | |
1870 Instr::kNopInstruction); | |
1871 buffer_.Store<int32_t>(position + 2 * Instr::kInstrSize, | |
1872 Instr::kNopInstruction); | |
1873 buffer_.Store<int32_t>(position + 3 * Instr::kInstrSize, | |
1874 Instr::kNopInstruction); | |
1875 buffer_.Store<int32_t>(position + 4 * Instr::kInstrSize, | |
1876 Instr::kNopInstruction); | |
1877 | |
1878 label->position_ = DecodeARMv6LoadImmediate(mov, or1, or2, or3); | |
1879 } else { | |
1880 int32_t next = buffer_.Load<int32_t>(position); | |
1881 int32_t encoded = Assembler::EncodeBranchOffset(dest, next); | |
1882 buffer_.Store<int32_t>(position, encoded); | |
1883 label->position_ = Assembler::DecodeBranchOffset(next); | |
1884 } | |
1885 } | |
1886 label->BindTo(bound_pc); | |
1887 } | |
1888 | |
1889 | |
1890 void Assembler::BindARMv7(Label* label) { | |
1891 ASSERT(!label->IsBound()); | |
1892 intptr_t bound_pc = buffer_.Size(); | |
1893 while (label->IsLinked()) { | |
1894 const int32_t position = label->Position(); | |
1895 int32_t dest = bound_pc - position; | |
1896 if (use_far_branches() && !CanEncodeBranchOffset(dest)) { | |
1897 // Far branches are enabled and we can't encode the branch offset. | |
1898 | |
1899 // Grab instructions that load the offset. | |
1762 const int32_t movw = | 1900 const int32_t movw = |
1763 buffer_.Load<int32_t>(position); | 1901 buffer_.Load<int32_t>(position); |
regis
2014/03/06 17:32:11
You added + 0 * Instr::kInstrSize below. For symm
zra
2014/03/07 19:00:17
Done.
| |
1764 const int32_t movt = | 1902 const int32_t movt = |
1765 buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize); | 1903 buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize); |
1766 | 1904 |
1767 // Change from relative to the branch to relative to the assembler buffer. | 1905 // Change from relative to the branch to relative to the assembler |
1906 // buffer. | |
1768 dest = buffer_.Size(); | 1907 dest = buffer_.Size(); |
1769 const uint16_t dest_high = Utils::High16Bits(dest); | 1908 const uint16_t dest_high = Utils::High16Bits(dest); |
1770 const uint16_t dest_low = Utils::Low16Bits(dest); | 1909 const uint16_t dest_low = Utils::Low16Bits(dest); |
1771 const int32_t patched_movt = | 1910 const int32_t patched_movt = |
1772 0xe340c000 | ((dest_high >> 12) << 16) | (dest_high & 0xfff); | 1911 0xe340c000 | ((dest_high >> 12) << 16) | (dest_high & 0xfff); |
1773 const int32_t patched_movw = | 1912 const int32_t patched_movw = |
1774 0xe300c000 | ((dest_low >> 12) << 16) | (dest_low & 0xfff); | 1913 0xe300c000 | ((dest_low >> 12) << 16) | (dest_low & 0xfff); |
1775 | 1914 |
1776 // Rewrite the instructions. | 1915 // Rewrite the instructions. |
1777 buffer_.Store<int32_t>(position, patched_movw); | 1916 buffer_.Store<int32_t>(position + 0 * Instr::kInstrSize, patched_movw); |
1778 buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize, patched_movt); | 1917 buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize, patched_movt); |
1779 label->position_ = DecodeLoadImmediate(movt, movw); | 1918 label->position_ = DecodeARMv7LoadImmediate(movt, movw); |
1780 } else if (use_far_branches() && CanEncodeBranchOffset(dest)) { | 1919 } else if (use_far_branches() && CanEncodeBranchOffset(dest)) { |
1781 // Far branches are enabled, but we can encode the branch offset. | 1920 // Far branches are enabled, but we can encode the branch offset. |
1782 | 1921 |
1783 // Grab instructions that load the offset, and the branch. | 1922 // Grab instructions that load the offset, and the branch. |
1784 const int32_t movw = | 1923 const int32_t movw = |
1785 buffer_.Load<int32_t>(position); | 1924 buffer_.Load<int32_t>(position); |
regis
2014/03/06 17:32:11
Here too? And below too? Not important.
zra
2014/03/07 19:00:17
Done.
| |
1786 const int32_t movt = | 1925 const int32_t movt = |
1787 buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize); | 1926 buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize); |
1788 const int32_t branch = | 1927 const int32_t branch = |
1789 buffer_.Load<int32_t>(position + 2 * Instr::kInstrSize); | 1928 buffer_.Load<int32_t>(position + 2 * Instr::kInstrSize); |
1790 | 1929 |
1791 // Grab the branch condition, and encode the link bit. | 1930 // Grab the branch condition, and encode the link bit. |
1792 const int32_t cond = branch & 0xf0000000; | 1931 const int32_t cond = branch & 0xf0000000; |
1793 const int32_t link = (branch & 0x20) << 19; | 1932 const int32_t link = (branch & 0x20) << 19; |
1794 | 1933 |
1795 // Encode the branch and the offset. | 1934 // Encode the branch and the offset. |
1796 const int32_t new_branch = cond | link | 0x0a000000; | 1935 const int32_t new_branch = cond | link | 0x0a000000; |
1797 const int32_t encoded = EncodeBranchOffset(dest, new_branch); | 1936 const int32_t encoded = EncodeBranchOffset(dest, new_branch); |
1798 | 1937 |
1799 // Write the encoded branch instruction followed by two nops. | 1938 // Write the encoded branch instruction followed by two nops. |
1800 buffer_.Store<int32_t>(position, encoded); | 1939 buffer_.Store<int32_t>(position, encoded); |
1801 buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize, | 1940 buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize, |
1802 Instr::kNopInstruction); | 1941 Instr::kNopInstruction); |
1803 buffer_.Store<int32_t>(position + 2 * Instr::kInstrSize, | 1942 buffer_.Store<int32_t>(position + 2 * Instr::kInstrSize, |
1804 Instr::kNopInstruction); | 1943 Instr::kNopInstruction); |
1805 | 1944 |
1806 label->position_ = DecodeLoadImmediate(movt, movw); | 1945 label->position_ = DecodeARMv7LoadImmediate(movt, movw); |
1807 } else { | 1946 } else { |
1808 int32_t next = buffer_.Load<int32_t>(position); | 1947 int32_t next = buffer_.Load<int32_t>(position); |
1809 int32_t encoded = Assembler::EncodeBranchOffset(dest, next); | 1948 int32_t encoded = Assembler::EncodeBranchOffset(dest, next); |
1810 buffer_.Store<int32_t>(position, encoded); | 1949 buffer_.Store<int32_t>(position, encoded); |
1811 label->position_ = Assembler::DecodeBranchOffset(next); | 1950 label->position_ = Assembler::DecodeBranchOffset(next); |
1812 } | 1951 } |
1813 } | 1952 } |
1814 label->BindTo(bound_pc); | 1953 label->BindTo(bound_pc); |
1815 } | 1954 } |
1816 | 1955 |
1817 | 1956 |
1957 void Assembler::Bind(Label* label) { | |
1958 if (TargetCPUFeatures::arm_version() == ARMv6) { | |
1959 BindARMv6(label); | |
1960 } else { | |
1961 ASSERT(TargetCPUFeatures::arm_version() == ARMv7); | |
1962 BindARMv7(label); | |
1963 } | |
1964 } | |
1965 | |
1966 | |
1818 bool Address::CanHoldLoadOffset(OperandSize type, | 1967 bool Address::CanHoldLoadOffset(OperandSize type, |
1819 int32_t offset, | 1968 int32_t offset, |
1820 int32_t* offset_mask) { | 1969 int32_t* offset_mask) { |
1821 switch (type) { | 1970 switch (type) { |
1822 case kByte: | 1971 case kByte: |
1823 case kHalfword: | 1972 case kHalfword: |
1824 case kUnsignedHalfword: | 1973 case kUnsignedHalfword: |
1825 case kWordPair: { | 1974 case kWordPair: { |
1826 *offset_mask = 0xff; | 1975 *offset_mask = 0xff; |
1827 return Utils::IsAbsoluteUint(8, offset); // Addressing mode 3. | 1976 return Utils::IsAbsoluteUint(8, offset); // Addressing mode 3. |
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2017 LoadImmediate(IP, label->address(), cond); // Address is never patched. | 2166 LoadImmediate(IP, label->address(), cond); // Address is never patched. |
2018 bx(IP, cond); | 2167 bx(IP, cond); |
2019 } | 2168 } |
2020 | 2169 |
2021 | 2170 |
2022 void Assembler::BranchPatchable(const ExternalLabel* label) { | 2171 void Assembler::BranchPatchable(const ExternalLabel* label) { |
2023 // Use a fixed size code sequence, since a function prologue may be patched | 2172 // Use a fixed size code sequence, since a function prologue may be patched |
2024 // with this branch sequence. | 2173 // with this branch sequence. |
2025 // Contrarily to BranchLinkPatchable, BranchPatchable requires an instruction | 2174 // Contrarily to BranchLinkPatchable, BranchPatchable requires an instruction |
2026 // cache flush upon patching. | 2175 // cache flush upon patching. |
2027 movw(IP, Utils::Low16Bits(label->address())); | 2176 if (TargetCPUFeatures::arm_version() == ARMv6) { |
2028 movt(IP, Utils::High16Bits(label->address())); | 2177 LoadLargeImmediate(IP, label->address()); |
2178 } else { | |
2179 ASSERT(TargetCPUFeatures::arm_version() == ARMv7); | |
2180 movw(IP, Utils::Low16Bits(label->address())); | |
2181 movt(IP, Utils::High16Bits(label->address())); | |
2182 } | |
regis
2014/03/06 17:32:11
LoadPatchableImmediate for both. LoadPatchableImme
zra
2014/03/07 19:00:17
Done.
| |
2029 bx(IP); | 2183 bx(IP); |
2030 } | 2184 } |
2031 | 2185 |
2032 | 2186 |
2033 void Assembler::BranchLink(const ExternalLabel* label) { | 2187 void Assembler::BranchLink(const ExternalLabel* label) { |
2034 LoadImmediate(IP, label->address()); // Target address is never patched. | 2188 LoadImmediate(IP, label->address()); // Target address is never patched. |
2035 blx(IP); // Use blx instruction so that the return branch prediction works. | 2189 blx(IP); // Use blx instruction so that the return branch prediction works. |
2036 } | 2190 } |
2037 | 2191 |
2038 | 2192 |
(...skipping 18 matching lines...) Expand all Loading... | |
2057 | 2211 |
2058 | 2212 |
2059 void Assembler::BranchLinkOffset(Register base, int32_t offset) { | 2213 void Assembler::BranchLinkOffset(Register base, int32_t offset) { |
2060 ASSERT(base != PC); | 2214 ASSERT(base != PC); |
2061 ASSERT(base != IP); | 2215 ASSERT(base != IP); |
2062 LoadFromOffset(kWord, IP, base, offset); | 2216 LoadFromOffset(kWord, IP, base, offset); |
2063 blx(IP); // Use blx instruction so that the return branch prediction works. | 2217 blx(IP); // Use blx instruction so that the return branch prediction works. |
2064 } | 2218 } |
2065 | 2219 |
2066 | 2220 |
2221 void Assembler::LoadLargeImmediate(Register rd, int32_t value, Condition cond) { | |
2222 if (TargetCPUFeatures::arm_version() == ARMv6) { | |
regis
2014/03/06 17:32:11
See my comment in the header.
zra
2014/03/07 19:00:17
Done.
| |
2223 // This sequence is patched in a few places, and should remain fixed. | |
2224 const uint32_t byte0 = (value & 0x000000ff); | |
2225 const uint32_t byte1 = (value & 0x0000ff00) >> 8; | |
2226 const uint32_t byte2 = (value & 0x00ff0000) >> 16; | |
2227 const uint32_t byte3 = (value & 0xff000000) >> 24; | |
2228 mov(rd, ShifterOperand(4, byte3), cond); | |
2229 orr(rd, rd, ShifterOperand(8, byte2), cond); | |
2230 orr(rd, rd, ShifterOperand(12, byte1), cond); | |
2231 orr(rd, rd, ShifterOperand(byte0), cond); | |
2232 } else { | |
2233 ASSERT(TargetCPUFeatures::arm_version() == ARMv7); | |
2234 movw(rd, Utils::Low16Bits(value), cond); | |
2235 const uint16_t value_high = Utils::High16Bits(value); | |
2236 if (value_high != 0) { | |
2237 movt(rd, value_high, cond); | |
2238 } | |
2239 } | |
2240 } | |
2241 | |
2242 | |
2067 void Assembler::LoadImmediate(Register rd, int32_t value, Condition cond) { | 2243 void Assembler::LoadImmediate(Register rd, int32_t value, Condition cond) { |
2068 ShifterOperand shifter_op; | 2244 ShifterOperand shifter_op; |
2069 if (ShifterOperand::CanHold(value, &shifter_op)) { | 2245 if (ShifterOperand::CanHold(value, &shifter_op)) { |
2070 mov(rd, shifter_op, cond); | 2246 mov(rd, shifter_op, cond); |
2071 } else if (ShifterOperand::CanHold(~value, &shifter_op)) { | 2247 } else if (ShifterOperand::CanHold(~value, &shifter_op)) { |
2072 mvn(rd, shifter_op, cond); | 2248 mvn(rd, shifter_op, cond); |
2073 } else { | 2249 } else { |
2074 movw(rd, Utils::Low16Bits(value), cond); | 2250 LoadLargeImmediate(rd, value, cond); |
regis
2014/03/06 17:32:11
LoadDecodableImmediate
zra
2014/03/07 19:00:17
Done.
| |
2075 const uint16_t value_high = Utils::High16Bits(value); | |
2076 if (value_high != 0) { | |
2077 movt(rd, value_high, cond); | |
2078 } | |
2079 } | 2251 } |
2080 } | 2252 } |
2081 | 2253 |
2082 | 2254 |
2083 void Assembler::LoadSImmediate(SRegister sd, float value, Condition cond) { | 2255 void Assembler::LoadSImmediate(SRegister sd, float value, Condition cond) { |
2084 if (!vmovs(sd, value, cond)) { | 2256 if (!vmovs(sd, value, cond)) { |
2085 LoadImmediate(IP, bit_cast<int32_t, float>(value), cond); | 2257 LoadImmediate(IP, bit_cast<int32_t, float>(value), cond); |
2086 vmovsr(sd, IP, cond); | 2258 vmovsr(sd, IP, cond); |
2087 } | 2259 } |
2088 } | 2260 } |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2234 vstrd(reg, Address(base, offset), cond); | 2406 vstrd(reg, Address(base, offset), cond); |
2235 } | 2407 } |
2236 | 2408 |
2237 | 2409 |
2238 void Assembler::AddImmediate(Register rd, int32_t value, Condition cond) { | 2410 void Assembler::AddImmediate(Register rd, int32_t value, Condition cond) { |
2239 AddImmediate(rd, rd, value, cond); | 2411 AddImmediate(rd, rd, value, cond); |
2240 } | 2412 } |
2241 | 2413 |
2242 | 2414 |
2243 void Assembler::AddImmediate(Register rd, Register rn, int32_t value, | 2415 void Assembler::AddImmediate(Register rd, Register rn, int32_t value, |
2244 Condition cond) { | 2416 Condition cond) { |
2245 if (value == 0) { | 2417 if (value == 0) { |
2246 if (rd != rn) { | 2418 if (rd != rn) { |
2247 mov(rd, ShifterOperand(rn), cond); | 2419 mov(rd, ShifterOperand(rn), cond); |
2248 } | 2420 } |
2249 return; | 2421 return; |
2250 } | 2422 } |
2251 // We prefer to select the shorter code sequence rather than selecting add for | 2423 // We prefer to select the shorter code sequence rather than selecting add for |
2252 // positive values and sub for negatives ones, which would slightly improve | 2424 // positive values and sub for negatives ones, which would slightly improve |
2253 // the readability of generated code for some constants. | 2425 // the readability of generated code for some constants. |
2254 ShifterOperand shifter_op; | 2426 ShifterOperand shifter_op; |
2255 if (ShifterOperand::CanHold(value, &shifter_op)) { | 2427 if (ShifterOperand::CanHold(value, &shifter_op)) { |
2256 add(rd, rn, shifter_op, cond); | 2428 add(rd, rn, shifter_op, cond); |
2257 } else if (ShifterOperand::CanHold(-value, &shifter_op)) { | 2429 } else if (ShifterOperand::CanHold(-value, &shifter_op)) { |
2258 sub(rd, rn, shifter_op, cond); | 2430 sub(rd, rn, shifter_op, cond); |
2259 } else { | 2431 } else { |
2260 ASSERT(rn != IP); | 2432 ASSERT(rn != IP); |
2261 if (ShifterOperand::CanHold(~value, &shifter_op)) { | 2433 if (ShifterOperand::CanHold(~value, &shifter_op)) { |
2262 mvn(IP, shifter_op, cond); | 2434 mvn(IP, shifter_op, cond); |
2263 add(rd, rn, ShifterOperand(IP), cond); | 2435 add(rd, rn, ShifterOperand(IP), cond); |
2264 } else if (ShifterOperand::CanHold(~(-value), &shifter_op)) { | 2436 } else if (ShifterOperand::CanHold(~(-value), &shifter_op)) { |
2265 mvn(IP, shifter_op, cond); | 2437 mvn(IP, shifter_op, cond); |
2266 sub(rd, rn, ShifterOperand(IP), cond); | 2438 sub(rd, rn, ShifterOperand(IP), cond); |
2267 } else { | 2439 } else { |
2268 movw(IP, Utils::Low16Bits(value), cond); | 2440 LoadLargeImmediate(IP, value, cond); |
regis
2014/03/06 17:32:11
LoadDecodableImmediate
zra
2014/03/07 19:00:17
Done.
| |
2269 const uint16_t value_high = Utils::High16Bits(value); | |
2270 if (value_high != 0) { | |
2271 movt(IP, value_high, cond); | |
2272 } | |
2273 add(rd, rn, ShifterOperand(IP), cond); | 2441 add(rd, rn, ShifterOperand(IP), cond); |
2274 } | 2442 } |
2275 } | 2443 } |
2276 } | 2444 } |
2277 | 2445 |
2278 | 2446 |
2279 void Assembler::AddImmediateSetFlags(Register rd, Register rn, int32_t value, | 2447 void Assembler::AddImmediateSetFlags(Register rd, Register rn, int32_t value, |
2280 Condition cond) { | 2448 Condition cond) { |
2281 ShifterOperand shifter_op; | 2449 ShifterOperand shifter_op; |
2282 if (ShifterOperand::CanHold(value, &shifter_op)) { | 2450 if (ShifterOperand::CanHold(value, &shifter_op)) { |
2283 adds(rd, rn, shifter_op, cond); | 2451 adds(rd, rn, shifter_op, cond); |
2284 } else if (ShifterOperand::CanHold(-value, &shifter_op)) { | 2452 } else if (ShifterOperand::CanHold(-value, &shifter_op)) { |
2285 subs(rd, rn, shifter_op, cond); | 2453 subs(rd, rn, shifter_op, cond); |
2286 } else { | 2454 } else { |
2287 ASSERT(rn != IP); | 2455 ASSERT(rn != IP); |
2288 if (ShifterOperand::CanHold(~value, &shifter_op)) { | 2456 if (ShifterOperand::CanHold(~value, &shifter_op)) { |
2289 mvn(IP, shifter_op, cond); | 2457 mvn(IP, shifter_op, cond); |
2290 adds(rd, rn, ShifterOperand(IP), cond); | 2458 adds(rd, rn, ShifterOperand(IP), cond); |
2291 } else if (ShifterOperand::CanHold(~(-value), &shifter_op)) { | 2459 } else if (ShifterOperand::CanHold(~(-value), &shifter_op)) { |
2292 mvn(IP, shifter_op, cond); | 2460 mvn(IP, shifter_op, cond); |
2293 subs(rd, rn, ShifterOperand(IP), cond); | 2461 subs(rd, rn, ShifterOperand(IP), cond); |
2294 } else { | 2462 } else { |
2295 movw(IP, Utils::Low16Bits(value), cond); | 2463 LoadLargeImmediate(IP, value, cond); |
regis
2014/03/06 17:32:11
LoadDecodableImmediate
zra
2014/03/07 19:00:17
Done.
| |
2296 const uint16_t value_high = Utils::High16Bits(value); | |
2297 if (value_high != 0) { | |
2298 movt(IP, value_high, cond); | |
2299 } | |
2300 adds(rd, rn, ShifterOperand(IP), cond); | 2464 adds(rd, rn, ShifterOperand(IP), cond); |
2301 } | 2465 } |
2302 } | 2466 } |
2303 } | 2467 } |
2304 | 2468 |
2305 | 2469 |
2306 void Assembler::AddImmediateWithCarry(Register rd, Register rn, int32_t value, | 2470 void Assembler::AddImmediateWithCarry(Register rd, Register rn, int32_t value, |
2307 Condition cond) { | 2471 Condition cond) { |
2308 ShifterOperand shifter_op; | 2472 ShifterOperand shifter_op; |
2309 if (ShifterOperand::CanHold(value, &shifter_op)) { | 2473 if (ShifterOperand::CanHold(value, &shifter_op)) { |
2310 adc(rd, rn, shifter_op, cond); | 2474 adc(rd, rn, shifter_op, cond); |
2311 } else if (ShifterOperand::CanHold(-value - 1, &shifter_op)) { | 2475 } else if (ShifterOperand::CanHold(-value - 1, &shifter_op)) { |
2312 sbc(rd, rn, shifter_op, cond); | 2476 sbc(rd, rn, shifter_op, cond); |
2313 } else { | 2477 } else { |
2314 ASSERT(rn != IP); | 2478 ASSERT(rn != IP); |
2315 if (ShifterOperand::CanHold(~value, &shifter_op)) { | 2479 if (ShifterOperand::CanHold(~value, &shifter_op)) { |
2316 mvn(IP, shifter_op, cond); | 2480 mvn(IP, shifter_op, cond); |
2317 adc(rd, rn, ShifterOperand(IP), cond); | 2481 adc(rd, rn, ShifterOperand(IP), cond); |
2318 } else if (ShifterOperand::CanHold(~(-value - 1), &shifter_op)) { | 2482 } else if (ShifterOperand::CanHold(~(-value - 1), &shifter_op)) { |
2319 mvn(IP, shifter_op, cond); | 2483 mvn(IP, shifter_op, cond); |
2320 sbc(rd, rn, ShifterOperand(IP), cond); | 2484 sbc(rd, rn, ShifterOperand(IP), cond); |
2321 } else { | 2485 } else { |
2322 movw(IP, Utils::Low16Bits(value), cond); | 2486 LoadLargeImmediate(IP, value, cond); |
regis
2014/03/06 17:32:11
LoadDecodableImmediate
zra
2014/03/07 19:00:17
Done.
| |
2323 const uint16_t value_high = Utils::High16Bits(value); | |
2324 if (value_high != 0) { | |
2325 movt(IP, value_high, cond); | |
2326 } | |
2327 adc(rd, rn, ShifterOperand(IP), cond); | 2487 adc(rd, rn, ShifterOperand(IP), cond); |
2328 } | 2488 } |
2329 } | 2489 } |
2330 } | 2490 } |
2331 | 2491 |
2332 | 2492 |
2333 void Assembler::AndImmediate(Register rd, Register rs, int32_t imm, | 2493 void Assembler::AndImmediate(Register rd, Register rs, int32_t imm, |
2334 Condition cond) { | 2494 Condition cond) { |
2335 ShifterOperand op; | 2495 ShifterOperand op; |
2336 if (ShifterOperand::CanHold(imm, &op)) { | 2496 if (ShifterOperand::CanHold(imm, &op)) { |
(...skipping 417 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2754 | 2914 |
2755 | 2915 |
2756 const char* Assembler::FpuRegisterName(FpuRegister reg) { | 2916 const char* Assembler::FpuRegisterName(FpuRegister reg) { |
2757 ASSERT((0 <= reg) && (reg < kNumberOfFpuRegisters)); | 2917 ASSERT((0 <= reg) && (reg < kNumberOfFpuRegisters)); |
2758 return fpu_reg_names[reg]; | 2918 return fpu_reg_names[reg]; |
2759 } | 2919 } |
2760 | 2920 |
2761 } // namespace dart | 2921 } // namespace dart |
2762 | 2922 |
2763 #endif // defined TARGET_ARCH_ARM | 2923 #endif // defined TARGET_ARCH_ARM |
OLD | NEW |