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

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

Issue 183803024: Adds support for ARMv6. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Added tests. Created 6 years, 9 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
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/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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698