Chromium Code Reviews| 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 |