OLD | NEW |
---|---|
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // | 2 // |
3 // Redistribution and use in source and binary forms, with or without | 3 // Redistribution and use in source and binary forms, with or without |
4 // modification, are permitted provided that the following conditions are | 4 // modification, are permitted provided that the following conditions are |
5 // met: | 5 // met: |
6 // | 6 // |
7 // * Redistributions of source code must retain the above copyright | 7 // * Redistributions of source code must retain the above copyright |
8 // notice, this list of conditions and the following disclaimer. | 8 // notice, this list of conditions and the following disclaimer. |
9 // * Redistributions in binary form must reproduce the above | 9 // * Redistributions in binary form must reproduce the above |
10 // copyright notice, this list of conditions and the following | 10 // copyright notice, this list of conditions and the following |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
83 index = kRegListSizeInBits - 1 - index; | 83 index = kRegListSizeInBits - 1 - index; |
84 DCHECK((1 << index) & list_); | 84 DCHECK((1 << index) & list_); |
85 Remove(index); | 85 Remove(index); |
86 return CPURegister::Create(index, size_, type_); | 86 return CPURegister::Create(index, size_, type_); |
87 } | 87 } |
88 | 88 |
89 | 89 |
90 void CPURegList::RemoveCalleeSaved() { | 90 void CPURegList::RemoveCalleeSaved() { |
91 if (type() == CPURegister::kRegister) { | 91 if (type() == CPURegister::kRegister) { |
92 Remove(GetCalleeSaved(RegisterSizeInBits())); | 92 Remove(GetCalleeSaved(RegisterSizeInBits())); |
93 } else if (type() == CPURegister::kFPRegister) { | 93 } else if (type() == CPURegister::kVRegister) { |
94 Remove(GetCalleeSavedFP(RegisterSizeInBits())); | 94 Remove(GetCalleeSavedV(RegisterSizeInBits())); |
95 } else { | 95 } else { |
96 DCHECK(type() == CPURegister::kNoRegister); | 96 DCHECK(type() == CPURegister::kNoRegister); |
97 DCHECK(IsEmpty()); | 97 DCHECK(IsEmpty()); |
98 // The list must already be empty, so do nothing. | 98 // The list must already be empty, so do nothing. |
99 } | 99 } |
100 } | 100 } |
101 | 101 |
102 | 102 |
103 CPURegList CPURegList::GetCalleeSaved(int size) { | 103 CPURegList CPURegList::GetCalleeSaved(int size) { |
104 return CPURegList(CPURegister::kRegister, size, 19, 29); | 104 return CPURegList(CPURegister::kRegister, size, 19, 29); |
105 } | 105 } |
106 | 106 |
107 | 107 CPURegList CPURegList::GetCalleeSavedV(int size) { |
108 CPURegList CPURegList::GetCalleeSavedFP(int size) { | 108 return CPURegList(CPURegister::kVRegister, size, 8, 15); |
109 return CPURegList(CPURegister::kFPRegister, size, 8, 15); | |
110 } | 109 } |
111 | 110 |
112 | 111 |
113 CPURegList CPURegList::GetCallerSaved(int size) { | 112 CPURegList CPURegList::GetCallerSaved(int size) { |
114 // Registers x0-x18 and lr (x30) are caller-saved. | 113 // Registers x0-x18 and lr (x30) are caller-saved. |
115 CPURegList list = CPURegList(CPURegister::kRegister, size, 0, 18); | 114 CPURegList list = CPURegList(CPURegister::kRegister, size, 0, 18); |
116 list.Combine(lr); | 115 list.Combine(lr); |
117 return list; | 116 return list; |
118 } | 117 } |
119 | 118 |
120 | 119 CPURegList CPURegList::GetCallerSavedV(int size) { |
121 CPURegList CPURegList::GetCallerSavedFP(int size) { | |
122 // Registers d0-d7 and d16-d31 are caller-saved. | 120 // Registers d0-d7 and d16-d31 are caller-saved. |
123 CPURegList list = CPURegList(CPURegister::kFPRegister, size, 0, 7); | 121 CPURegList list = CPURegList(CPURegister::kVRegister, size, 0, 7); |
124 list.Combine(CPURegList(CPURegister::kFPRegister, size, 16, 31)); | 122 list.Combine(CPURegList(CPURegister::kVRegister, size, 16, 31)); |
125 return list; | 123 return list; |
126 } | 124 } |
127 | 125 |
128 | 126 |
129 // This function defines the list of registers which are associated with a | 127 // This function defines the list of registers which are associated with a |
130 // safepoint slot. Safepoint register slots are saved contiguously on the stack. | 128 // safepoint slot. Safepoint register slots are saved contiguously on the stack. |
131 // MacroAssembler::SafepointRegisterStackIndex handles mapping from register | 129 // MacroAssembler::SafepointRegisterStackIndex handles mapping from register |
132 // code to index in the safepoint register slots. Any change here can affect | 130 // code to index in the safepoint register slots. Any change here can affect |
133 // this mapping. | 131 // this mapping. |
134 CPURegList CPURegList::GetSafepointSavedRegisters() { | 132 CPURegList CPURegList::GetSafepointSavedRegisters() { |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
228 | 226 |
229 RegList unique_regs = 0; | 227 RegList unique_regs = 0; |
230 RegList unique_fpregs = 0; | 228 RegList unique_fpregs = 0; |
231 | 229 |
232 const CPURegister regs[] = {reg1, reg2, reg3, reg4, reg5, reg6, reg7, reg8}; | 230 const CPURegister regs[] = {reg1, reg2, reg3, reg4, reg5, reg6, reg7, reg8}; |
233 | 231 |
234 for (unsigned i = 0; i < arraysize(regs); i++) { | 232 for (unsigned i = 0; i < arraysize(regs); i++) { |
235 if (regs[i].IsRegister()) { | 233 if (regs[i].IsRegister()) { |
236 number_of_valid_regs++; | 234 number_of_valid_regs++; |
237 unique_regs |= regs[i].Bit(); | 235 unique_regs |= regs[i].Bit(); |
238 } else if (regs[i].IsFPRegister()) { | 236 } else if (regs[i].IsVRegister()) { |
239 number_of_valid_fpregs++; | 237 number_of_valid_fpregs++; |
240 unique_fpregs |= regs[i].Bit(); | 238 unique_fpregs |= regs[i].Bit(); |
241 } else { | 239 } else { |
242 DCHECK(!regs[i].IsValid()); | 240 DCHECK(!regs[i].IsValid()); |
243 } | 241 } |
244 } | 242 } |
245 | 243 |
246 int number_of_unique_regs = | 244 int number_of_unique_regs = |
247 CountSetBits(unique_regs, sizeof(unique_regs) * kBitsPerByte); | 245 CountSetBits(unique_regs, sizeof(unique_regs) * kBitsPerByte); |
248 int number_of_unique_fpregs = | 246 int number_of_unique_fpregs = |
(...skipping 16 matching lines...) Expand all Loading... | |
265 match &= !reg2.IsValid() || reg2.IsSameSizeAndType(reg1); | 263 match &= !reg2.IsValid() || reg2.IsSameSizeAndType(reg1); |
266 match &= !reg3.IsValid() || reg3.IsSameSizeAndType(reg1); | 264 match &= !reg3.IsValid() || reg3.IsSameSizeAndType(reg1); |
267 match &= !reg4.IsValid() || reg4.IsSameSizeAndType(reg1); | 265 match &= !reg4.IsValid() || reg4.IsSameSizeAndType(reg1); |
268 match &= !reg5.IsValid() || reg5.IsSameSizeAndType(reg1); | 266 match &= !reg5.IsValid() || reg5.IsSameSizeAndType(reg1); |
269 match &= !reg6.IsValid() || reg6.IsSameSizeAndType(reg1); | 267 match &= !reg6.IsValid() || reg6.IsSameSizeAndType(reg1); |
270 match &= !reg7.IsValid() || reg7.IsSameSizeAndType(reg1); | 268 match &= !reg7.IsValid() || reg7.IsSameSizeAndType(reg1); |
271 match &= !reg8.IsValid() || reg8.IsSameSizeAndType(reg1); | 269 match &= !reg8.IsValid() || reg8.IsSameSizeAndType(reg1); |
272 return match; | 270 return match; |
273 } | 271 } |
274 | 272 |
273 bool AreSameFormat(const VRegister& reg1, const VRegister& reg2, | |
274 const VRegister& reg3, const VRegister& reg4) { | |
275 DCHECK(reg1.IsValid()); | |
276 bool match = true; | |
277 match &= !reg2.IsValid() || reg2.IsSameFormat(reg1); | |
278 match &= !reg3.IsValid() || reg3.IsSameFormat(reg1); | |
279 match &= !reg4.IsValid() || reg4.IsSameFormat(reg1); | |
280 return match; | |
bbudge
2017/01/31 01:41:31
Rather than use integer & operator, could you retu
martyn.capewell
2017/02/03 11:01:31
Done.
| |
281 } | |
282 | |
283 bool AreConsecutive(const VRegister& reg1, const VRegister& reg2, | |
284 const VRegister& reg3, const VRegister& reg4) { | |
285 DCHECK(reg1.IsValid()); | |
286 if (!reg2.IsValid()) { | |
bbudge
2017/01/31 01:41:31
DCHECK(!reg3.IsValid() && !reg4.IsValid()) ?
simi
martyn.capewell
2017/02/03 11:01:31
Done.
| |
287 return true; | |
288 } else if (reg2.code() != ((reg1.code() + 1) % kNumberOfVRegisters)) { | |
289 return false; | |
290 } | |
291 | |
292 if (!reg3.IsValid()) { | |
293 return true; | |
294 } else if (reg3.code() != ((reg2.code() + 1) % kNumberOfVRegisters)) { | |
295 return false; | |
296 } | |
297 | |
298 if (!reg4.IsValid()) { | |
299 return true; | |
300 } else if (reg4.code() != ((reg3.code() + 1) % kNumberOfVRegisters)) { | |
301 return false; | |
302 } | |
303 | |
304 return true; | |
305 } | |
275 | 306 |
276 void Immediate::InitializeHandle(Handle<Object> handle) { | 307 void Immediate::InitializeHandle(Handle<Object> handle) { |
277 AllowDeferredHandleDereference using_raw_address; | 308 AllowDeferredHandleDereference using_raw_address; |
278 | 309 |
279 // Verify all Objects referred by code are NOT in new space. | 310 // Verify all Objects referred by code are NOT in new space. |
280 Object* obj = *handle; | 311 Object* obj = *handle; |
281 if (obj->IsHeapObject()) { | 312 if (obj->IsHeapObject()) { |
282 value_ = reinterpret_cast<intptr_t>(handle.location()); | 313 value_ = reinterpret_cast<intptr_t>(handle.location()); |
283 rmode_ = RelocInfo::EMBEDDED_OBJECT; | 314 rmode_ = RelocInfo::EMBEDDED_OBJECT; |
284 } else { | 315 } else { |
(...skipping 1475 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1760 } | 1791 } |
1761 | 1792 |
1762 void Assembler::stlxrh(const Register& rs, const Register& rt, | 1793 void Assembler::stlxrh(const Register& rs, const Register& rt, |
1763 const Register& rn) { | 1794 const Register& rn) { |
1764 DCHECK(rs.Is32Bits()); | 1795 DCHECK(rs.Is32Bits()); |
1765 DCHECK(rt.Is32Bits()); | 1796 DCHECK(rt.Is32Bits()); |
1766 DCHECK(rn.Is64Bits()); | 1797 DCHECK(rn.Is64Bits()); |
1767 Emit(STLXR_h | Rs(rs) | Rt2(x31) | Rn(rn) | Rt(rt)); | 1798 Emit(STLXR_h | Rs(rs) | Rt2(x31) | Rn(rn) | Rt(rt)); |
1768 } | 1799 } |
1769 | 1800 |
1801 void Assembler::NEON3DifferentL(const VRegister& vd, const VRegister& vn, | |
1802 const VRegister& vm, NEON3DifferentOp vop) { | |
1803 DCHECK(AreSameFormat(vn, vm)); | |
1804 DCHECK((vn.Is1H() && vd.Is1S()) || (vn.Is1S() && vd.Is1D()) || | |
1805 (vn.Is8B() && vd.Is8H()) || (vn.Is4H() && vd.Is4S()) || | |
1806 (vn.Is2S() && vd.Is2D()) || (vn.Is16B() && vd.Is8H()) || | |
1807 (vn.Is8H() && vd.Is4S()) || (vn.Is4S() && vd.Is2D())); | |
1808 Instr format, op = vop; | |
1809 if (vd.IsScalar()) { | |
1810 op |= NEON_Q | NEONScalar; | |
1811 format = SFormat(vn); | |
1812 } else { | |
1813 format = VFormat(vn); | |
1814 } | |
1815 Emit(format | op | Rm(vm) | Rn(vn) | Rd(vd)); | |
1816 } | |
1817 | |
1818 void Assembler::NEON3DifferentW(const VRegister& vd, const VRegister& vn, | |
1819 const VRegister& vm, NEON3DifferentOp vop) { | |
1820 DCHECK(AreSameFormat(vd, vn)); | |
1821 DCHECK((vm.Is8B() && vd.Is8H()) || (vm.Is4H() && vd.Is4S()) || | |
1822 (vm.Is2S() && vd.Is2D()) || (vm.Is16B() && vd.Is8H()) || | |
1823 (vm.Is8H() && vd.Is4S()) || (vm.Is4S() && vd.Is2D())); | |
1824 Emit(VFormat(vm) | vop | Rm(vm) | Rn(vn) | Rd(vd)); | |
1825 } | |
1826 | |
1827 void Assembler::NEON3DifferentHN(const VRegister& vd, const VRegister& vn, | |
1828 const VRegister& vm, NEON3DifferentOp vop) { | |
1829 DCHECK(AreSameFormat(vm, vn)); | |
1830 DCHECK((vd.Is8B() && vn.Is8H()) || (vd.Is4H() && vn.Is4S()) || | |
1831 (vd.Is2S() && vn.Is2D()) || (vd.Is16B() && vn.Is8H()) || | |
1832 (vd.Is8H() && vn.Is4S()) || (vd.Is4S() && vn.Is2D())); | |
1833 Emit(VFormat(vd) | vop | Rm(vm) | Rn(vn) | Rd(vd)); | |
1834 } | |
1835 | |
1836 #define NEON_3DIFF_LONG_LIST(V) \ | |
1837 V(pmull, NEON_PMULL, vn.IsVector() && vn.Is8B()) \ | |
1838 V(pmull2, NEON_PMULL2, vn.IsVector() && vn.Is16B()) \ | |
1839 V(saddl, NEON_SADDL, vn.IsVector() && vn.IsD()) \ | |
1840 V(saddl2, NEON_SADDL2, vn.IsVector() && vn.IsQ()) \ | |
1841 V(sabal, NEON_SABAL, vn.IsVector() && vn.IsD()) \ | |
1842 V(sabal2, NEON_SABAL2, vn.IsVector() && vn.IsQ()) \ | |
1843 V(uabal, NEON_UABAL, vn.IsVector() && vn.IsD()) \ | |
1844 V(uabal2, NEON_UABAL2, vn.IsVector() && vn.IsQ()) \ | |
1845 V(sabdl, NEON_SABDL, vn.IsVector() && vn.IsD()) \ | |
1846 V(sabdl2, NEON_SABDL2, vn.IsVector() && vn.IsQ()) \ | |
1847 V(uabdl, NEON_UABDL, vn.IsVector() && vn.IsD()) \ | |
1848 V(uabdl2, NEON_UABDL2, vn.IsVector() && vn.IsQ()) \ | |
1849 V(smlal, NEON_SMLAL, vn.IsVector() && vn.IsD()) \ | |
1850 V(smlal2, NEON_SMLAL2, vn.IsVector() && vn.IsQ()) \ | |
1851 V(umlal, NEON_UMLAL, vn.IsVector() && vn.IsD()) \ | |
1852 V(umlal2, NEON_UMLAL2, vn.IsVector() && vn.IsQ()) \ | |
1853 V(smlsl, NEON_SMLSL, vn.IsVector() && vn.IsD()) \ | |
1854 V(smlsl2, NEON_SMLSL2, vn.IsVector() && vn.IsQ()) \ | |
1855 V(umlsl, NEON_UMLSL, vn.IsVector() && vn.IsD()) \ | |
1856 V(umlsl2, NEON_UMLSL2, vn.IsVector() && vn.IsQ()) \ | |
1857 V(smull, NEON_SMULL, vn.IsVector() && vn.IsD()) \ | |
1858 V(smull2, NEON_SMULL2, vn.IsVector() && vn.IsQ()) \ | |
1859 V(umull, NEON_UMULL, vn.IsVector() && vn.IsD()) \ | |
1860 V(umull2, NEON_UMULL2, vn.IsVector() && vn.IsQ()) \ | |
1861 V(ssubl, NEON_SSUBL, vn.IsVector() && vn.IsD()) \ | |
1862 V(ssubl2, NEON_SSUBL2, vn.IsVector() && vn.IsQ()) \ | |
1863 V(uaddl, NEON_UADDL, vn.IsVector() && vn.IsD()) \ | |
1864 V(uaddl2, NEON_UADDL2, vn.IsVector() && vn.IsQ()) \ | |
1865 V(usubl, NEON_USUBL, vn.IsVector() && vn.IsD()) \ | |
1866 V(usubl2, NEON_USUBL2, vn.IsVector() && vn.IsQ()) \ | |
1867 V(sqdmlal, NEON_SQDMLAL, vn.Is1H() || vn.Is1S() || vn.Is4H() || vn.Is2S()) \ | |
1868 V(sqdmlal2, NEON_SQDMLAL2, vn.Is1H() || vn.Is1S() || vn.Is8H() || vn.Is4S()) \ | |
1869 V(sqdmlsl, NEON_SQDMLSL, vn.Is1H() || vn.Is1S() || vn.Is4H() || vn.Is2S()) \ | |
1870 V(sqdmlsl2, NEON_SQDMLSL2, vn.Is1H() || vn.Is1S() || vn.Is8H() || vn.Is4S()) \ | |
1871 V(sqdmull, NEON_SQDMULL, vn.Is1H() || vn.Is1S() || vn.Is4H() || vn.Is2S()) \ | |
1872 V(sqdmull2, NEON_SQDMULL2, vn.Is1H() || vn.Is1S() || vn.Is8H() || vn.Is4S()) | |
1873 | |
1874 #define DEFINE_ASM_FUNC(FN, OP, AS) \ | |
1875 void Assembler::FN(const VRegister& vd, const VRegister& vn, \ | |
1876 const VRegister& vm) { \ | |
1877 DCHECK(AS); \ | |
1878 NEON3DifferentL(vd, vn, vm, OP); \ | |
1879 } | |
1880 NEON_3DIFF_LONG_LIST(DEFINE_ASM_FUNC) | |
1881 #undef DEFINE_ASM_FUNC | |
1882 | |
1883 #define NEON_3DIFF_HN_LIST(V) \ | |
1884 V(addhn, NEON_ADDHN, vd.IsD()) \ | |
1885 V(addhn2, NEON_ADDHN2, vd.IsQ()) \ | |
1886 V(raddhn, NEON_RADDHN, vd.IsD()) \ | |
1887 V(raddhn2, NEON_RADDHN2, vd.IsQ()) \ | |
1888 V(subhn, NEON_SUBHN, vd.IsD()) \ | |
1889 V(subhn2, NEON_SUBHN2, vd.IsQ()) \ | |
1890 V(rsubhn, NEON_RSUBHN, vd.IsD()) \ | |
1891 V(rsubhn2, NEON_RSUBHN2, vd.IsQ()) | |
1892 | |
1893 #define DEFINE_ASM_FUNC(FN, OP, AS) \ | |
1894 void Assembler::FN(const VRegister& vd, const VRegister& vn, \ | |
1895 const VRegister& vm) { \ | |
1896 DCHECK(AS); \ | |
1897 NEON3DifferentHN(vd, vn, vm, OP); \ | |
1898 } | |
1899 NEON_3DIFF_HN_LIST(DEFINE_ASM_FUNC) | |
1900 #undef DEFINE_ASM_FUNC | |
1901 | |
1902 void Assembler::NEONPerm(const VRegister& vd, const VRegister& vn, | |
1903 const VRegister& vm, NEONPermOp op) { | |
1904 DCHECK(AreSameFormat(vd, vn, vm)); | |
1905 DCHECK(!vd.Is1D()); | |
1906 Emit(VFormat(vd) | op | Rm(vm) | Rn(vn) | Rd(vd)); | |
1907 } | |
1908 | |
1909 void Assembler::trn1(const VRegister& vd, const VRegister& vn, | |
1910 const VRegister& vm) { | |
1911 NEONPerm(vd, vn, vm, NEON_TRN1); | |
1912 } | |
1913 | |
1914 void Assembler::trn2(const VRegister& vd, const VRegister& vn, | |
1915 const VRegister& vm) { | |
1916 NEONPerm(vd, vn, vm, NEON_TRN2); | |
1917 } | |
1918 | |
1919 void Assembler::uzp1(const VRegister& vd, const VRegister& vn, | |
1920 const VRegister& vm) { | |
1921 NEONPerm(vd, vn, vm, NEON_UZP1); | |
1922 } | |
1923 | |
1924 void Assembler::uzp2(const VRegister& vd, const VRegister& vn, | |
1925 const VRegister& vm) { | |
1926 NEONPerm(vd, vn, vm, NEON_UZP2); | |
1927 } | |
1928 | |
1929 void Assembler::zip1(const VRegister& vd, const VRegister& vn, | |
1930 const VRegister& vm) { | |
1931 NEONPerm(vd, vn, vm, NEON_ZIP1); | |
1932 } | |
1933 | |
1934 void Assembler::zip2(const VRegister& vd, const VRegister& vn, | |
1935 const VRegister& vm) { | |
1936 NEONPerm(vd, vn, vm, NEON_ZIP2); | |
1937 } | |
1938 | |
1939 void Assembler::NEONShiftImmediate(const VRegister& vd, const VRegister& vn, | |
1940 NEONShiftImmediateOp op, int immh_immb) { | |
1941 DCHECK(AreSameFormat(vd, vn)); | |
1942 Instr q, scalar; | |
1943 if (vn.IsScalar()) { | |
1944 q = NEON_Q; | |
1945 scalar = NEONScalar; | |
1946 } else { | |
1947 q = vd.IsD() ? 0 : NEON_Q; | |
1948 scalar = 0; | |
1949 } | |
1950 Emit(q | op | scalar | immh_immb | Rn(vn) | Rd(vd)); | |
1951 } | |
1952 | |
1953 void Assembler::NEONShiftLeftImmediate(const VRegister& vd, const VRegister& vn, | |
1954 int shift, NEONShiftImmediateOp op) { | |
1955 int laneSizeInBits = vn.LaneSizeInBits(); | |
1956 DCHECK((shift >= 0) && (shift < laneSizeInBits)); | |
1957 NEONShiftImmediate(vd, vn, op, (laneSizeInBits + shift) << 16); | |
1958 } | |
1959 | |
1960 void Assembler::NEONShiftRightImmediate(const VRegister& vd, | |
1961 const VRegister& vn, int shift, | |
1962 NEONShiftImmediateOp op) { | |
1963 int laneSizeInBits = vn.LaneSizeInBits(); | |
1964 DCHECK((shift >= 1) && (shift <= laneSizeInBits)); | |
1965 NEONShiftImmediate(vd, vn, op, ((2 * laneSizeInBits) - shift) << 16); | |
1966 } | |
1967 | |
1968 void Assembler::NEONShiftImmediateL(const VRegister& vd, const VRegister& vn, | |
1969 int shift, NEONShiftImmediateOp op) { | |
1970 int laneSizeInBits = vn.LaneSizeInBits(); | |
1971 DCHECK((shift >= 0) && (shift < laneSizeInBits)); | |
1972 int immh_immb = (laneSizeInBits + shift) << 16; | |
1973 | |
1974 DCHECK((vn.Is8B() && vd.Is8H()) || (vn.Is4H() && vd.Is4S()) || | |
1975 (vn.Is2S() && vd.Is2D()) || (vn.Is16B() && vd.Is8H()) || | |
1976 (vn.Is8H() && vd.Is4S()) || (vn.Is4S() && vd.Is2D())); | |
1977 Instr q; | |
1978 q = vn.IsD() ? 0 : NEON_Q; | |
1979 Emit(q | op | immh_immb | Rn(vn) | Rd(vd)); | |
1980 } | |
1981 | |
1982 void Assembler::NEONShiftImmediateN(const VRegister& vd, const VRegister& vn, | |
1983 int shift, NEONShiftImmediateOp op) { | |
1984 Instr q, scalar; | |
1985 int laneSizeInBits = vd.LaneSizeInBits(); | |
1986 DCHECK((shift >= 1) && (shift <= laneSizeInBits)); | |
1987 int immh_immb = (2 * laneSizeInBits - shift) << 16; | |
1988 | |
1989 if (vn.IsScalar()) { | |
1990 DCHECK((vd.Is1B() && vn.Is1H()) || (vd.Is1H() && vn.Is1S()) || | |
1991 (vd.Is1S() && vn.Is1D())); | |
1992 q = NEON_Q; | |
1993 scalar = NEONScalar; | |
1994 } else { | |
1995 DCHECK((vd.Is8B() && vn.Is8H()) || (vd.Is4H() && vn.Is4S()) || | |
1996 (vd.Is2S() && vn.Is2D()) || (vd.Is16B() && vn.Is8H()) || | |
1997 (vd.Is8H() && vn.Is4S()) || (vd.Is4S() && vn.Is2D())); | |
1998 scalar = 0; | |
1999 q = vd.IsD() ? 0 : NEON_Q; | |
2000 } | |
2001 Emit(q | op | scalar | immh_immb | Rn(vn) | Rd(vd)); | |
2002 } | |
2003 | |
2004 void Assembler::shl(const VRegister& vd, const VRegister& vn, int shift) { | |
2005 DCHECK(vd.IsVector() || vd.Is1D()); | |
2006 NEONShiftLeftImmediate(vd, vn, shift, NEON_SHL); | |
2007 } | |
2008 | |
2009 void Assembler::sli(const VRegister& vd, const VRegister& vn, int shift) { | |
2010 DCHECK(vd.IsVector() || vd.Is1D()); | |
2011 NEONShiftLeftImmediate(vd, vn, shift, NEON_SLI); | |
2012 } | |
2013 | |
2014 void Assembler::sqshl(const VRegister& vd, const VRegister& vn, int shift) { | |
2015 NEONShiftLeftImmediate(vd, vn, shift, NEON_SQSHL_imm); | |
2016 } | |
2017 | |
2018 void Assembler::sqshlu(const VRegister& vd, const VRegister& vn, int shift) { | |
2019 NEONShiftLeftImmediate(vd, vn, shift, NEON_SQSHLU); | |
2020 } | |
2021 | |
2022 void Assembler::uqshl(const VRegister& vd, const VRegister& vn, int shift) { | |
2023 NEONShiftLeftImmediate(vd, vn, shift, NEON_UQSHL_imm); | |
2024 } | |
2025 | |
2026 void Assembler::sshll(const VRegister& vd, const VRegister& vn, int shift) { | |
2027 DCHECK(vn.IsD()); | |
2028 NEONShiftImmediateL(vd, vn, shift, NEON_SSHLL); | |
2029 } | |
2030 | |
2031 void Assembler::sshll2(const VRegister& vd, const VRegister& vn, int shift) { | |
2032 DCHECK(vn.IsQ()); | |
2033 NEONShiftImmediateL(vd, vn, shift, NEON_SSHLL); | |
2034 } | |
2035 | |
2036 void Assembler::sxtl(const VRegister& vd, const VRegister& vn) { | |
2037 sshll(vd, vn, 0); | |
2038 } | |
2039 | |
2040 void Assembler::sxtl2(const VRegister& vd, const VRegister& vn) { | |
2041 sshll2(vd, vn, 0); | |
2042 } | |
2043 | |
2044 void Assembler::ushll(const VRegister& vd, const VRegister& vn, int shift) { | |
2045 DCHECK(vn.IsD()); | |
2046 NEONShiftImmediateL(vd, vn, shift, NEON_USHLL); | |
2047 } | |
2048 | |
2049 void Assembler::ushll2(const VRegister& vd, const VRegister& vn, int shift) { | |
2050 DCHECK(vn.IsQ()); | |
2051 NEONShiftImmediateL(vd, vn, shift, NEON_USHLL); | |
2052 } | |
2053 | |
2054 void Assembler::uxtl(const VRegister& vd, const VRegister& vn) { | |
2055 ushll(vd, vn, 0); | |
2056 } | |
2057 | |
2058 void Assembler::uxtl2(const VRegister& vd, const VRegister& vn) { | |
2059 ushll2(vd, vn, 0); | |
2060 } | |
2061 | |
2062 void Assembler::sri(const VRegister& vd, const VRegister& vn, int shift) { | |
2063 DCHECK(vd.IsVector() || vd.Is1D()); | |
2064 NEONShiftRightImmediate(vd, vn, shift, NEON_SRI); | |
2065 } | |
2066 | |
2067 void Assembler::sshr(const VRegister& vd, const VRegister& vn, int shift) { | |
2068 DCHECK(vd.IsVector() || vd.Is1D()); | |
2069 NEONShiftRightImmediate(vd, vn, shift, NEON_SSHR); | |
2070 } | |
2071 | |
2072 void Assembler::ushr(const VRegister& vd, const VRegister& vn, int shift) { | |
2073 DCHECK(vd.IsVector() || vd.Is1D()); | |
2074 NEONShiftRightImmediate(vd, vn, shift, NEON_USHR); | |
2075 } | |
2076 | |
2077 void Assembler::srshr(const VRegister& vd, const VRegister& vn, int shift) { | |
2078 DCHECK(vd.IsVector() || vd.Is1D()); | |
2079 NEONShiftRightImmediate(vd, vn, shift, NEON_SRSHR); | |
2080 } | |
2081 | |
2082 void Assembler::urshr(const VRegister& vd, const VRegister& vn, int shift) { | |
2083 DCHECK(vd.IsVector() || vd.Is1D()); | |
2084 NEONShiftRightImmediate(vd, vn, shift, NEON_URSHR); | |
2085 } | |
2086 | |
2087 void Assembler::ssra(const VRegister& vd, const VRegister& vn, int shift) { | |
2088 DCHECK(vd.IsVector() || vd.Is1D()); | |
2089 NEONShiftRightImmediate(vd, vn, shift, NEON_SSRA); | |
2090 } | |
2091 | |
2092 void Assembler::usra(const VRegister& vd, const VRegister& vn, int shift) { | |
2093 DCHECK(vd.IsVector() || vd.Is1D()); | |
2094 NEONShiftRightImmediate(vd, vn, shift, NEON_USRA); | |
2095 } | |
2096 | |
2097 void Assembler::srsra(const VRegister& vd, const VRegister& vn, int shift) { | |
2098 DCHECK(vd.IsVector() || vd.Is1D()); | |
2099 NEONShiftRightImmediate(vd, vn, shift, NEON_SRSRA); | |
2100 } | |
2101 | |
2102 void Assembler::ursra(const VRegister& vd, const VRegister& vn, int shift) { | |
2103 DCHECK(vd.IsVector() || vd.Is1D()); | |
2104 NEONShiftRightImmediate(vd, vn, shift, NEON_URSRA); | |
2105 } | |
2106 | |
2107 void Assembler::shrn(const VRegister& vd, const VRegister& vn, int shift) { | |
2108 DCHECK(vn.IsVector() && vd.IsD()); | |
2109 NEONShiftImmediateN(vd, vn, shift, NEON_SHRN); | |
2110 } | |
2111 | |
2112 void Assembler::shrn2(const VRegister& vd, const VRegister& vn, int shift) { | |
2113 DCHECK(vn.IsVector() && vd.IsQ()); | |
2114 NEONShiftImmediateN(vd, vn, shift, NEON_SHRN); | |
2115 } | |
2116 | |
2117 void Assembler::rshrn(const VRegister& vd, const VRegister& vn, int shift) { | |
2118 DCHECK(vn.IsVector() && vd.IsD()); | |
2119 NEONShiftImmediateN(vd, vn, shift, NEON_RSHRN); | |
2120 } | |
2121 | |
2122 void Assembler::rshrn2(const VRegister& vd, const VRegister& vn, int shift) { | |
2123 DCHECK(vn.IsVector() && vd.IsQ()); | |
2124 NEONShiftImmediateN(vd, vn, shift, NEON_RSHRN); | |
2125 } | |
2126 | |
2127 void Assembler::sqshrn(const VRegister& vd, const VRegister& vn, int shift) { | |
2128 DCHECK(vd.IsD() || (vn.IsScalar() && vd.IsScalar())); | |
2129 NEONShiftImmediateN(vd, vn, shift, NEON_SQSHRN); | |
2130 } | |
2131 | |
2132 void Assembler::sqshrn2(const VRegister& vd, const VRegister& vn, int shift) { | |
2133 DCHECK(vn.IsVector() && vd.IsQ()); | |
2134 NEONShiftImmediateN(vd, vn, shift, NEON_SQSHRN); | |
2135 } | |
2136 | |
2137 void Assembler::sqrshrn(const VRegister& vd, const VRegister& vn, int shift) { | |
2138 DCHECK(vd.IsD() || (vn.IsScalar() && vd.IsScalar())); | |
2139 NEONShiftImmediateN(vd, vn, shift, NEON_SQRSHRN); | |
2140 } | |
2141 | |
2142 void Assembler::sqrshrn2(const VRegister& vd, const VRegister& vn, int shift) { | |
2143 DCHECK(vn.IsVector() && vd.IsQ()); | |
2144 NEONShiftImmediateN(vd, vn, shift, NEON_SQRSHRN); | |
2145 } | |
2146 | |
2147 void Assembler::sqshrun(const VRegister& vd, const VRegister& vn, int shift) { | |
2148 DCHECK(vd.IsD() || (vn.IsScalar() && vd.IsScalar())); | |
2149 NEONShiftImmediateN(vd, vn, shift, NEON_SQSHRUN); | |
2150 } | |
2151 | |
2152 void Assembler::sqshrun2(const VRegister& vd, const VRegister& vn, int shift) { | |
2153 DCHECK(vn.IsVector() && vd.IsQ()); | |
2154 NEONShiftImmediateN(vd, vn, shift, NEON_SQSHRUN); | |
2155 } | |
2156 | |
2157 void Assembler::sqrshrun(const VRegister& vd, const VRegister& vn, int shift) { | |
2158 DCHECK(vd.IsD() || (vn.IsScalar() && vd.IsScalar())); | |
2159 NEONShiftImmediateN(vd, vn, shift, NEON_SQRSHRUN); | |
2160 } | |
2161 | |
2162 void Assembler::sqrshrun2(const VRegister& vd, const VRegister& vn, int shift) { | |
2163 DCHECK(vn.IsVector() && vd.IsQ()); | |
2164 NEONShiftImmediateN(vd, vn, shift, NEON_SQRSHRUN); | |
2165 } | |
2166 | |
2167 void Assembler::uqshrn(const VRegister& vd, const VRegister& vn, int shift) { | |
2168 DCHECK(vd.IsD() || (vn.IsScalar() && vd.IsScalar())); | |
2169 NEONShiftImmediateN(vd, vn, shift, NEON_UQSHRN); | |
2170 } | |
2171 | |
2172 void Assembler::uqshrn2(const VRegister& vd, const VRegister& vn, int shift) { | |
2173 DCHECK(vn.IsVector() && vd.IsQ()); | |
2174 NEONShiftImmediateN(vd, vn, shift, NEON_UQSHRN); | |
2175 } | |
2176 | |
2177 void Assembler::uqrshrn(const VRegister& vd, const VRegister& vn, int shift) { | |
2178 DCHECK(vd.IsD() || (vn.IsScalar() && vd.IsScalar())); | |
2179 NEONShiftImmediateN(vd, vn, shift, NEON_UQRSHRN); | |
2180 } | |
2181 | |
2182 void Assembler::uqrshrn2(const VRegister& vd, const VRegister& vn, int shift) { | |
2183 DCHECK(vn.IsVector() && vd.IsQ()); | |
2184 NEONShiftImmediateN(vd, vn, shift, NEON_UQRSHRN); | |
2185 } | |
2186 | |
2187 void Assembler::uaddw(const VRegister& vd, const VRegister& vn, | |
2188 const VRegister& vm) { | |
2189 DCHECK(vm.IsD()); | |
2190 NEON3DifferentW(vd, vn, vm, NEON_UADDW); | |
2191 } | |
2192 | |
2193 void Assembler::uaddw2(const VRegister& vd, const VRegister& vn, | |
2194 const VRegister& vm) { | |
2195 DCHECK(vm.IsQ()); | |
2196 NEON3DifferentW(vd, vn, vm, NEON_UADDW2); | |
2197 } | |
2198 | |
2199 void Assembler::saddw(const VRegister& vd, const VRegister& vn, | |
2200 const VRegister& vm) { | |
2201 DCHECK(vm.IsD()); | |
2202 NEON3DifferentW(vd, vn, vm, NEON_SADDW); | |
2203 } | |
2204 | |
2205 void Assembler::saddw2(const VRegister& vd, const VRegister& vn, | |
2206 const VRegister& vm) { | |
2207 DCHECK(vm.IsQ()); | |
2208 NEON3DifferentW(vd, vn, vm, NEON_SADDW2); | |
2209 } | |
2210 | |
2211 void Assembler::usubw(const VRegister& vd, const VRegister& vn, | |
2212 const VRegister& vm) { | |
2213 DCHECK(vm.IsD()); | |
2214 NEON3DifferentW(vd, vn, vm, NEON_USUBW); | |
2215 } | |
2216 | |
2217 void Assembler::usubw2(const VRegister& vd, const VRegister& vn, | |
2218 const VRegister& vm) { | |
2219 DCHECK(vm.IsQ()); | |
2220 NEON3DifferentW(vd, vn, vm, NEON_USUBW2); | |
2221 } | |
2222 | |
2223 void Assembler::ssubw(const VRegister& vd, const VRegister& vn, | |
2224 const VRegister& vm) { | |
2225 DCHECK(vm.IsD()); | |
2226 NEON3DifferentW(vd, vn, vm, NEON_SSUBW); | |
2227 } | |
2228 | |
2229 void Assembler::ssubw2(const VRegister& vd, const VRegister& vn, | |
2230 const VRegister& vm) { | |
2231 DCHECK(vm.IsQ()); | |
2232 NEON3DifferentW(vd, vn, vm, NEON_SSUBW2); | |
2233 } | |
2234 | |
1770 void Assembler::mov(const Register& rd, const Register& rm) { | 2235 void Assembler::mov(const Register& rd, const Register& rm) { |
1771 // Moves involving the stack pointer are encoded as add immediate with | 2236 // Moves involving the stack pointer are encoded as add immediate with |
1772 // second operand of zero. Otherwise, orr with first operand zr is | 2237 // second operand of zero. Otherwise, orr with first operand zr is |
1773 // used. | 2238 // used. |
1774 if (rd.IsSP() || rm.IsSP()) { | 2239 if (rd.IsSP() || rm.IsSP()) { |
1775 add(rd, rm, 0); | 2240 add(rd, rm, 0); |
1776 } else { | 2241 } else { |
1777 orr(rd, AppropriateZeroRegFor(rd), rm); | 2242 orr(rd, AppropriateZeroRegFor(rd), rm); |
1778 } | 2243 } |
1779 } | 2244 } |
1780 | 2245 |
2246 void Assembler::ins(const VRegister& vd, int vd_index, const Register& rn) { | |
2247 // We support vd arguments of the form vd.VxT() or vd.T(), where x is the | |
2248 // number of lanes, and T is b, h, s or d. | |
2249 int lane_size = vd.LaneSizeInBytes(); | |
2250 NEONFormatField format; | |
2251 switch (lane_size) { | |
2252 case 1: | |
2253 format = NEON_16B; | |
2254 DCHECK(rn.IsW()); | |
2255 break; | |
2256 case 2: | |
2257 format = NEON_8H; | |
2258 DCHECK(rn.IsW()); | |
2259 break; | |
2260 case 4: | |
2261 format = NEON_4S; | |
2262 DCHECK(rn.IsW()); | |
2263 break; | |
2264 default: | |
2265 DCHECK_EQ(lane_size, 8); | |
2266 DCHECK(rn.IsX()); | |
2267 format = NEON_2D; | |
2268 break; | |
2269 } | |
2270 | |
2271 DCHECK((0 <= vd_index) && | |
2272 (vd_index < LaneCountFromFormat(static_cast<VectorFormat>(format)))); | |
2273 Emit(NEON_INS_GENERAL | ImmNEON5(format, vd_index) | Rn(rn) | Rd(vd)); | |
2274 } | |
2275 | |
2276 void Assembler::mov(const Register& rd, const VRegister& vn, int vn_index) { | |
2277 DCHECK_GE(vn.SizeInBytes(), 4); | |
2278 umov(rd, vn, vn_index); | |
2279 } | |
2280 | |
2281 void Assembler::smov(const Register& rd, const VRegister& vn, int vn_index) { | |
2282 // We support vn arguments of the form vn.VxT() or vn.T(), where x is the | |
2283 // number of lanes, and T is b, h, s. | |
2284 int lane_size = vn.LaneSizeInBytes(); | |
2285 NEONFormatField format; | |
2286 Instr q = 0; | |
2287 switch (lane_size) { | |
2288 case 1: | |
2289 format = NEON_16B; | |
2290 break; | |
2291 case 2: | |
2292 format = NEON_8H; | |
2293 break; | |
2294 default: | |
2295 DCHECK_EQ(lane_size, 4); | |
2296 DCHECK(rd.IsX()); | |
2297 format = NEON_4S; | |
2298 break; | |
2299 } | |
2300 q = rd.IsW() ? 0 : NEON_Q; | |
2301 DCHECK((0 <= vn_index) && | |
2302 (vn_index < LaneCountFromFormat(static_cast<VectorFormat>(format)))); | |
2303 Emit(q | NEON_SMOV | ImmNEON5(format, vn_index) | Rn(vn) | Rd(rd)); | |
2304 } | |
2305 | |
2306 void Assembler::cls(const VRegister& vd, const VRegister& vn) { | |
2307 DCHECK(AreSameFormat(vd, vn)); | |
2308 DCHECK(!vd.Is1D() && !vd.Is2D()); | |
2309 Emit(VFormat(vn) | NEON_CLS | Rn(vn) | Rd(vd)); | |
2310 } | |
2311 | |
2312 void Assembler::clz(const VRegister& vd, const VRegister& vn) { | |
2313 DCHECK(AreSameFormat(vd, vn)); | |
2314 DCHECK(!vd.Is1D() && !vd.Is2D()); | |
2315 Emit(VFormat(vn) | NEON_CLZ | Rn(vn) | Rd(vd)); | |
2316 } | |
2317 | |
2318 void Assembler::cnt(const VRegister& vd, const VRegister& vn) { | |
2319 DCHECK(AreSameFormat(vd, vn)); | |
2320 DCHECK(vd.Is8B() || vd.Is16B()); | |
2321 Emit(VFormat(vn) | NEON_CNT | Rn(vn) | Rd(vd)); | |
2322 } | |
2323 | |
2324 void Assembler::rev16(const VRegister& vd, const VRegister& vn) { | |
2325 DCHECK(AreSameFormat(vd, vn)); | |
2326 DCHECK(vd.Is8B() || vd.Is16B()); | |
2327 Emit(VFormat(vn) | NEON_REV16 | Rn(vn) | Rd(vd)); | |
2328 } | |
2329 | |
2330 void Assembler::rev32(const VRegister& vd, const VRegister& vn) { | |
2331 DCHECK(AreSameFormat(vd, vn)); | |
2332 DCHECK(vd.Is8B() || vd.Is16B() || vd.Is4H() || vd.Is8H()); | |
2333 Emit(VFormat(vn) | NEON_REV32 | Rn(vn) | Rd(vd)); | |
2334 } | |
2335 | |
2336 void Assembler::rev64(const VRegister& vd, const VRegister& vn) { | |
2337 DCHECK(AreSameFormat(vd, vn)); | |
2338 DCHECK(!vd.Is1D() && !vd.Is2D()); | |
2339 Emit(VFormat(vn) | NEON_REV64 | Rn(vn) | Rd(vd)); | |
2340 } | |
2341 | |
2342 void Assembler::ursqrte(const VRegister& vd, const VRegister& vn) { | |
2343 DCHECK(AreSameFormat(vd, vn)); | |
2344 DCHECK(vd.Is2S() || vd.Is4S()); | |
2345 Emit(VFormat(vn) | NEON_URSQRTE | Rn(vn) | Rd(vd)); | |
2346 } | |
2347 | |
2348 void Assembler::urecpe(const VRegister& vd, const VRegister& vn) { | |
2349 DCHECK(AreSameFormat(vd, vn)); | |
2350 DCHECK(vd.Is2S() || vd.Is4S()); | |
2351 Emit(VFormat(vn) | NEON_URECPE | Rn(vn) | Rd(vd)); | |
2352 } | |
2353 | |
2354 void Assembler::NEONAddlp(const VRegister& vd, const VRegister& vn, | |
2355 NEON2RegMiscOp op) { | |
2356 DCHECK((op == NEON_SADDLP) || (op == NEON_UADDLP) || (op == NEON_SADALP) || | |
2357 (op == NEON_UADALP)); | |
2358 | |
2359 DCHECK((vn.Is8B() && vd.Is4H()) || (vn.Is4H() && vd.Is2S()) || | |
2360 (vn.Is2S() && vd.Is1D()) || (vn.Is16B() && vd.Is8H()) || | |
2361 (vn.Is8H() && vd.Is4S()) || (vn.Is4S() && vd.Is2D())); | |
2362 Emit(VFormat(vn) | op | Rn(vn) | Rd(vd)); | |
2363 } | |
2364 | |
2365 void Assembler::saddlp(const VRegister& vd, const VRegister& vn) { | |
2366 NEONAddlp(vd, vn, NEON_SADDLP); | |
2367 } | |
2368 | |
2369 void Assembler::uaddlp(const VRegister& vd, const VRegister& vn) { | |
2370 NEONAddlp(vd, vn, NEON_UADDLP); | |
2371 } | |
2372 | |
2373 void Assembler::sadalp(const VRegister& vd, const VRegister& vn) { | |
2374 NEONAddlp(vd, vn, NEON_SADALP); | |
2375 } | |
2376 | |
2377 void Assembler::uadalp(const VRegister& vd, const VRegister& vn) { | |
2378 NEONAddlp(vd, vn, NEON_UADALP); | |
2379 } | |
2380 | |
2381 void Assembler::NEONAcrossLanesL(const VRegister& vd, const VRegister& vn, | |
2382 NEONAcrossLanesOp op) { | |
2383 DCHECK((vn.Is8B() && vd.Is1H()) || (vn.Is16B() && vd.Is1H()) || | |
2384 (vn.Is4H() && vd.Is1S()) || (vn.Is8H() && vd.Is1S()) || | |
2385 (vn.Is4S() && vd.Is1D())); | |
2386 Emit(VFormat(vn) | op | Rn(vn) | Rd(vd)); | |
2387 } | |
2388 | |
2389 void Assembler::saddlv(const VRegister& vd, const VRegister& vn) { | |
2390 NEONAcrossLanesL(vd, vn, NEON_SADDLV); | |
2391 } | |
2392 | |
2393 void Assembler::uaddlv(const VRegister& vd, const VRegister& vn) { | |
2394 NEONAcrossLanesL(vd, vn, NEON_UADDLV); | |
2395 } | |
2396 | |
2397 void Assembler::NEONAcrossLanes(const VRegister& vd, const VRegister& vn, | |
2398 NEONAcrossLanesOp op) { | |
2399 DCHECK((vn.Is8B() && vd.Is1B()) || (vn.Is16B() && vd.Is1B()) || | |
2400 (vn.Is4H() && vd.Is1H()) || (vn.Is8H() && vd.Is1H()) || | |
2401 (vn.Is4S() && vd.Is1S())); | |
2402 if ((op & NEONAcrossLanesFPFMask) == NEONAcrossLanesFPFixed) { | |
2403 Emit(FPFormat(vn) | op | Rn(vn) | Rd(vd)); | |
2404 } else { | |
2405 Emit(VFormat(vn) | op | Rn(vn) | Rd(vd)); | |
2406 } | |
2407 } | |
2408 | |
2409 #define NEON_ACROSSLANES_LIST(V) \ | |
2410 V(fmaxv, NEON_FMAXV, vd.Is1S()) \ | |
2411 V(fminv, NEON_FMINV, vd.Is1S()) \ | |
2412 V(fmaxnmv, NEON_FMAXNMV, vd.Is1S()) \ | |
2413 V(fminnmv, NEON_FMINNMV, vd.Is1S()) \ | |
2414 V(addv, NEON_ADDV, true) \ | |
2415 V(smaxv, NEON_SMAXV, true) \ | |
2416 V(sminv, NEON_SMINV, true) \ | |
2417 V(umaxv, NEON_UMAXV, true) \ | |
2418 V(uminv, NEON_UMINV, true) | |
2419 | |
2420 #define DEFINE_ASM_FUNC(FN, OP, AS) \ | |
2421 void Assembler::FN(const VRegister& vd, const VRegister& vn) { \ | |
2422 DCHECK(AS); \ | |
2423 NEONAcrossLanes(vd, vn, OP); \ | |
2424 } | |
2425 NEON_ACROSSLANES_LIST(DEFINE_ASM_FUNC) | |
2426 #undef DEFINE_ASM_FUNC | |
2427 | |
2428 void Assembler::mov(const VRegister& vd, int vd_index, const Register& rn) { | |
2429 ins(vd, vd_index, rn); | |
2430 } | |
2431 | |
2432 void Assembler::umov(const Register& rd, const VRegister& vn, int vn_index) { | |
2433 // We support vn arguments of the form vn.VxT() or vn.T(), where x is the | |
2434 // number of lanes, and T is b, h, s or d. | |
2435 int lane_size = vn.LaneSizeInBytes(); | |
2436 NEONFormatField format; | |
2437 Instr q = 0; | |
2438 switch (lane_size) { | |
2439 case 1: | |
2440 format = NEON_16B; | |
2441 DCHECK(rd.IsW()); | |
2442 break; | |
2443 case 2: | |
2444 format = NEON_8H; | |
2445 DCHECK(rd.IsW()); | |
2446 break; | |
2447 case 4: | |
2448 format = NEON_4S; | |
2449 DCHECK(rd.IsW()); | |
2450 break; | |
2451 default: | |
2452 DCHECK_EQ(lane_size, 8); | |
2453 DCHECK(rd.IsX()); | |
2454 format = NEON_2D; | |
2455 q = NEON_Q; | |
2456 break; | |
2457 } | |
2458 | |
2459 DCHECK((0 <= vn_index) && | |
2460 (vn_index < LaneCountFromFormat(static_cast<VectorFormat>(format)))); | |
2461 Emit(q | NEON_UMOV | ImmNEON5(format, vn_index) | Rn(vn) | Rd(rd)); | |
2462 } | |
2463 | |
2464 void Assembler::mov(const VRegister& vd, const VRegister& vn, int vn_index) { | |
2465 DCHECK(vd.IsScalar()); | |
2466 dup(vd, vn, vn_index); | |
2467 } | |
2468 | |
2469 void Assembler::dup(const VRegister& vd, const Register& rn) { | |
2470 DCHECK(!vd.Is1D()); | |
2471 DCHECK_EQ(vd.Is2D(), rn.IsX()); | |
2472 Instr q = vd.IsD() ? 0 : NEON_Q; | |
2473 Emit(q | NEON_DUP_GENERAL | ImmNEON5(VFormat(vd), 0) | Rn(rn) | Rd(vd)); | |
2474 } | |
2475 | |
2476 void Assembler::ins(const VRegister& vd, int vd_index, const VRegister& vn, | |
2477 int vn_index) { | |
2478 DCHECK(AreSameFormat(vd, vn)); | |
2479 // We support vd arguments of the form vd.VxT() or vd.T(), where x is the | |
2480 // number of lanes, and T is b, h, s or d. | |
2481 int lane_size = vd.LaneSizeInBytes(); | |
2482 NEONFormatField format; | |
2483 switch (lane_size) { | |
2484 case 1: | |
2485 format = NEON_16B; | |
2486 break; | |
2487 case 2: | |
2488 format = NEON_8H; | |
2489 break; | |
2490 case 4: | |
2491 format = NEON_4S; | |
2492 break; | |
2493 default: | |
2494 DCHECK_EQ(lane_size, 8); | |
2495 format = NEON_2D; | |
2496 break; | |
2497 } | |
2498 | |
2499 DCHECK((0 <= vd_index) && | |
2500 (vd_index < LaneCountFromFormat(static_cast<VectorFormat>(format)))); | |
2501 DCHECK((0 <= vn_index) && | |
2502 (vn_index < LaneCountFromFormat(static_cast<VectorFormat>(format)))); | |
2503 Emit(NEON_INS_ELEMENT | ImmNEON5(format, vd_index) | | |
2504 ImmNEON4(format, vn_index) | Rn(vn) | Rd(vd)); | |
2505 } | |
2506 | |
2507 void Assembler::NEONTable(const VRegister& vd, const VRegister& vn, | |
2508 const VRegister& vm, NEONTableOp op) { | |
2509 DCHECK(vd.Is16B() || vd.Is8B()); | |
2510 DCHECK(vn.Is16B()); | |
2511 DCHECK(AreSameFormat(vd, vm)); | |
2512 Emit(op | (vd.IsQ() ? NEON_Q : 0) | Rm(vm) | Rn(vn) | Rd(vd)); | |
2513 } | |
2514 | |
2515 void Assembler::tbl(const VRegister& vd, const VRegister& vn, | |
2516 const VRegister& vm) { | |
2517 NEONTable(vd, vn, vm, NEON_TBL_1v); | |
2518 } | |
2519 | |
2520 void Assembler::tbl(const VRegister& vd, const VRegister& vn, | |
2521 const VRegister& vn2, const VRegister& vm) { | |
2522 USE(vn2); | |
2523 DCHECK(AreSameFormat(vn, vn2)); | |
2524 DCHECK(AreConsecutive(vn, vn2)); | |
2525 NEONTable(vd, vn, vm, NEON_TBL_2v); | |
2526 } | |
2527 | |
2528 void Assembler::tbl(const VRegister& vd, const VRegister& vn, | |
2529 const VRegister& vn2, const VRegister& vn3, | |
2530 const VRegister& vm) { | |
2531 USE(vn2); | |
2532 USE(vn3); | |
2533 DCHECK(AreSameFormat(vn, vn2, vn3)); | |
2534 DCHECK(AreConsecutive(vn, vn2, vn3)); | |
2535 NEONTable(vd, vn, vm, NEON_TBL_3v); | |
2536 } | |
2537 | |
2538 void Assembler::tbl(const VRegister& vd, const VRegister& vn, | |
2539 const VRegister& vn2, const VRegister& vn3, | |
2540 const VRegister& vn4, const VRegister& vm) { | |
2541 USE(vn2); | |
2542 USE(vn3); | |
2543 USE(vn4); | |
2544 DCHECK(AreSameFormat(vn, vn2, vn3, vn4)); | |
2545 DCHECK(AreConsecutive(vn, vn2, vn3, vn4)); | |
2546 NEONTable(vd, vn, vm, NEON_TBL_4v); | |
2547 } | |
2548 | |
2549 void Assembler::tbx(const VRegister& vd, const VRegister& vn, | |
2550 const VRegister& vm) { | |
2551 NEONTable(vd, vn, vm, NEON_TBX_1v); | |
2552 } | |
2553 | |
2554 void Assembler::tbx(const VRegister& vd, const VRegister& vn, | |
2555 const VRegister& vn2, const VRegister& vm) { | |
2556 USE(vn2); | |
2557 DCHECK(AreSameFormat(vn, vn2)); | |
2558 DCHECK(AreConsecutive(vn, vn2)); | |
2559 NEONTable(vd, vn, vm, NEON_TBX_2v); | |
2560 } | |
2561 | |
2562 void Assembler::tbx(const VRegister& vd, const VRegister& vn, | |
2563 const VRegister& vn2, const VRegister& vn3, | |
2564 const VRegister& vm) { | |
2565 USE(vn2); | |
2566 USE(vn3); | |
2567 DCHECK(AreSameFormat(vn, vn2, vn3)); | |
2568 DCHECK(AreConsecutive(vn, vn2, vn3)); | |
2569 NEONTable(vd, vn, vm, NEON_TBX_3v); | |
2570 } | |
2571 | |
2572 void Assembler::tbx(const VRegister& vd, const VRegister& vn, | |
2573 const VRegister& vn2, const VRegister& vn3, | |
2574 const VRegister& vn4, const VRegister& vm) { | |
2575 USE(vn2); | |
2576 USE(vn3); | |
2577 USE(vn4); | |
2578 DCHECK(AreSameFormat(vn, vn2, vn3, vn4)); | |
2579 DCHECK(AreConsecutive(vn, vn2, vn3, vn4)); | |
2580 NEONTable(vd, vn, vm, NEON_TBX_4v); | |
2581 } | |
2582 | |
2583 void Assembler::mov(const VRegister& vd, int vd_index, const VRegister& vn, | |
2584 int vn_index) { | |
2585 ins(vd, vd_index, vn, vn_index); | |
2586 } | |
1781 | 2587 |
1782 void Assembler::mvn(const Register& rd, const Operand& operand) { | 2588 void Assembler::mvn(const Register& rd, const Operand& operand) { |
1783 orn(rd, AppropriateZeroRegFor(rd), operand); | 2589 orn(rd, AppropriateZeroRegFor(rd), operand); |
1784 } | 2590 } |
1785 | 2591 |
1786 | |
1787 void Assembler::mrs(const Register& rt, SystemRegister sysreg) { | 2592 void Assembler::mrs(const Register& rt, SystemRegister sysreg) { |
1788 DCHECK(rt.Is64Bits()); | 2593 DCHECK(rt.Is64Bits()); |
1789 Emit(MRS | ImmSystemRegister(sysreg) | Rt(rt)); | 2594 Emit(MRS | ImmSystemRegister(sysreg) | Rt(rt)); |
1790 } | 2595 } |
1791 | 2596 |
1792 | |
1793 void Assembler::msr(SystemRegister sysreg, const Register& rt) { | 2597 void Assembler::msr(SystemRegister sysreg, const Register& rt) { |
1794 DCHECK(rt.Is64Bits()); | 2598 DCHECK(rt.Is64Bits()); |
1795 Emit(MSR | Rt(rt) | ImmSystemRegister(sysreg)); | 2599 Emit(MSR | Rt(rt) | ImmSystemRegister(sysreg)); |
1796 } | 2600 } |
1797 | 2601 |
1798 | 2602 void Assembler::hint(SystemHint code) { Emit(HINT | ImmHint(code) | Rt(xzr)); } |
1799 void Assembler::hint(SystemHint code) { | 2603 |
1800 Emit(HINT | ImmHint(code) | Rt(xzr)); | 2604 // NEON structure loads and stores. |
1801 } | 2605 Instr Assembler::LoadStoreStructAddrModeField(const MemOperand& addr) { |
1802 | 2606 Instr addr_field = RnSP(addr.base()); |
2607 | |
2608 if (addr.IsPostIndex()) { | |
2609 static_assert(NEONLoadStoreMultiStructPostIndex == | |
2610 static_cast<NEONLoadStoreMultiStructPostIndexOp>( | |
2611 NEONLoadStoreSingleStructPostIndex), | |
2612 "Opcodes must match for NEON post index memop."); | |
2613 | |
2614 addr_field |= NEONLoadStoreMultiStructPostIndex; | |
2615 if (addr.offset() == 0) { | |
2616 addr_field |= RmNot31(addr.regoffset()); | |
2617 } else { | |
2618 // The immediate post index addressing mode is indicated by rm = 31. | |
2619 // The immediate is implied by the number of vector registers used. | |
2620 addr_field |= (0x1f << Rm_offset); | |
2621 } | |
2622 } else { | |
2623 DCHECK(addr.IsImmediateOffset() && (addr.offset() == 0)); | |
2624 } | |
2625 return addr_field; | |
2626 } | |
2627 | |
2628 void Assembler::LoadStoreStructVerify(const VRegister& vt, | |
2629 const MemOperand& addr, Instr op) { | |
2630 #ifdef DEBUG | |
2631 // Assert that addressing mode is either offset (with immediate 0), post | |
2632 // index by immediate of the size of the register list, or post index by a | |
2633 // value in a core register. | |
2634 if (addr.IsImmediateOffset()) { | |
2635 DCHECK_EQ(addr.offset(), 0); | |
2636 } else { | |
2637 int offset = vt.SizeInBytes(); | |
2638 switch (op) { | |
2639 case NEON_LD1_1v: | |
2640 case NEON_ST1_1v: | |
2641 offset *= 1; | |
2642 break; | |
2643 case NEONLoadStoreSingleStructLoad1: | |
2644 case NEONLoadStoreSingleStructStore1: | |
2645 case NEON_LD1R: | |
2646 offset = (offset / vt.LaneCount()) * 1; | |
2647 break; | |
2648 | |
2649 case NEON_LD1_2v: | |
2650 case NEON_ST1_2v: | |
2651 case NEON_LD2: | |
2652 case NEON_ST2: | |
2653 offset *= 2; | |
2654 break; | |
2655 case NEONLoadStoreSingleStructLoad2: | |
2656 case NEONLoadStoreSingleStructStore2: | |
2657 case NEON_LD2R: | |
2658 offset = (offset / vt.LaneCount()) * 2; | |
2659 break; | |
2660 | |
2661 case NEON_LD1_3v: | |
2662 case NEON_ST1_3v: | |
2663 case NEON_LD3: | |
2664 case NEON_ST3: | |
2665 offset *= 3; | |
2666 break; | |
2667 case NEONLoadStoreSingleStructLoad3: | |
2668 case NEONLoadStoreSingleStructStore3: | |
2669 case NEON_LD3R: | |
2670 offset = (offset / vt.LaneCount()) * 3; | |
2671 break; | |
2672 | |
2673 case NEON_LD1_4v: | |
2674 case NEON_ST1_4v: | |
2675 case NEON_LD4: | |
2676 case NEON_ST4: | |
2677 offset *= 4; | |
2678 break; | |
2679 case NEONLoadStoreSingleStructLoad4: | |
2680 case NEONLoadStoreSingleStructStore4: | |
2681 case NEON_LD4R: | |
2682 offset = (offset / vt.LaneCount()) * 4; | |
2683 break; | |
2684 default: | |
2685 UNREACHABLE(); | |
2686 } | |
2687 DCHECK(!addr.regoffset().Is(NoReg) || addr.offset() == offset); | |
2688 } | |
2689 #else | |
2690 USE(vt); | |
2691 USE(addr); | |
2692 USE(op); | |
2693 #endif | |
2694 } | |
2695 | |
2696 void Assembler::LoadStoreStruct(const VRegister& vt, const MemOperand& addr, | |
2697 NEONLoadStoreMultiStructOp op) { | |
2698 LoadStoreStructVerify(vt, addr, op); | |
2699 DCHECK(vt.IsVector() || vt.Is1D()); | |
2700 Emit(op | LoadStoreStructAddrModeField(addr) | LSVFormat(vt) | Rt(vt)); | |
2701 } | |
2702 | |
2703 void Assembler::LoadStoreStructSingleAllLanes(const VRegister& vt, | |
2704 const MemOperand& addr, | |
2705 NEONLoadStoreSingleStructOp op) { | |
2706 LoadStoreStructVerify(vt, addr, op); | |
2707 Emit(op | LoadStoreStructAddrModeField(addr) | LSVFormat(vt) | Rt(vt)); | |
2708 } | |
2709 | |
2710 void Assembler::ld1(const VRegister& vt, const MemOperand& src) { | |
2711 LoadStoreStruct(vt, src, NEON_LD1_1v); | |
2712 } | |
2713 | |
2714 void Assembler::ld1(const VRegister& vt, const VRegister& vt2, | |
2715 const MemOperand& src) { | |
2716 USE(vt2); | |
2717 DCHECK(AreSameFormat(vt, vt2)); | |
2718 DCHECK(AreConsecutive(vt, vt2)); | |
2719 LoadStoreStruct(vt, src, NEON_LD1_2v); | |
2720 } | |
2721 | |
2722 void Assembler::ld1(const VRegister& vt, const VRegister& vt2, | |
2723 const VRegister& vt3, const MemOperand& src) { | |
2724 USE(vt2); | |
2725 USE(vt3); | |
2726 DCHECK(AreSameFormat(vt, vt2, vt3)); | |
2727 DCHECK(AreConsecutive(vt, vt2, vt3)); | |
2728 LoadStoreStruct(vt, src, NEON_LD1_3v); | |
2729 } | |
2730 | |
2731 void Assembler::ld1(const VRegister& vt, const VRegister& vt2, | |
2732 const VRegister& vt3, const VRegister& vt4, | |
2733 const MemOperand& src) { | |
2734 USE(vt2); | |
2735 USE(vt3); | |
2736 USE(vt4); | |
2737 DCHECK(AreSameFormat(vt, vt2, vt3, vt4)); | |
2738 DCHECK(AreConsecutive(vt, vt2, vt3, vt4)); | |
2739 LoadStoreStruct(vt, src, NEON_LD1_4v); | |
2740 } | |
2741 | |
2742 void Assembler::ld2(const VRegister& vt, const VRegister& vt2, | |
2743 const MemOperand& src) { | |
2744 USE(vt2); | |
2745 DCHECK(AreSameFormat(vt, vt2)); | |
2746 DCHECK(AreConsecutive(vt, vt2)); | |
2747 LoadStoreStruct(vt, src, NEON_LD2); | |
2748 } | |
2749 | |
2750 void Assembler::ld2(const VRegister& vt, const VRegister& vt2, int lane, | |
2751 const MemOperand& src) { | |
2752 USE(vt2); | |
2753 DCHECK(AreSameFormat(vt, vt2)); | |
2754 DCHECK(AreConsecutive(vt, vt2)); | |
2755 LoadStoreStructSingle(vt, lane, src, NEONLoadStoreSingleStructLoad2); | |
2756 } | |
2757 | |
2758 void Assembler::ld2r(const VRegister& vt, const VRegister& vt2, | |
2759 const MemOperand& src) { | |
2760 USE(vt2); | |
2761 DCHECK(AreSameFormat(vt, vt2)); | |
2762 DCHECK(AreConsecutive(vt, vt2)); | |
2763 LoadStoreStructSingleAllLanes(vt, src, NEON_LD2R); | |
2764 } | |
2765 | |
2766 void Assembler::ld3(const VRegister& vt, const VRegister& vt2, | |
2767 const VRegister& vt3, const MemOperand& src) { | |
2768 USE(vt2); | |
2769 USE(vt3); | |
2770 DCHECK(AreSameFormat(vt, vt2, vt3)); | |
2771 DCHECK(AreConsecutive(vt, vt2, vt3)); | |
2772 LoadStoreStruct(vt, src, NEON_LD3); | |
2773 } | |
2774 | |
2775 void Assembler::ld3(const VRegister& vt, const VRegister& vt2, | |
2776 const VRegister& vt3, int lane, const MemOperand& src) { | |
2777 USE(vt2); | |
2778 USE(vt3); | |
2779 DCHECK(AreSameFormat(vt, vt2, vt3)); | |
2780 DCHECK(AreConsecutive(vt, vt2, vt3)); | |
2781 LoadStoreStructSingle(vt, lane, src, NEONLoadStoreSingleStructLoad3); | |
2782 } | |
2783 | |
2784 void Assembler::ld3r(const VRegister& vt, const VRegister& vt2, | |
2785 const VRegister& vt3, const MemOperand& src) { | |
2786 USE(vt2); | |
2787 USE(vt3); | |
2788 DCHECK(AreSameFormat(vt, vt2, vt3)); | |
2789 DCHECK(AreConsecutive(vt, vt2, vt3)); | |
2790 LoadStoreStructSingleAllLanes(vt, src, NEON_LD3R); | |
2791 } | |
2792 | |
2793 void Assembler::ld4(const VRegister& vt, const VRegister& vt2, | |
2794 const VRegister& vt3, const VRegister& vt4, | |
2795 const MemOperand& src) { | |
2796 USE(vt2); | |
2797 USE(vt3); | |
2798 USE(vt4); | |
2799 DCHECK(AreSameFormat(vt, vt2, vt3, vt4)); | |
2800 DCHECK(AreConsecutive(vt, vt2, vt3, vt4)); | |
2801 LoadStoreStruct(vt, src, NEON_LD4); | |
2802 } | |
2803 | |
2804 void Assembler::ld4(const VRegister& vt, const VRegister& vt2, | |
2805 const VRegister& vt3, const VRegister& vt4, int lane, | |
2806 const MemOperand& src) { | |
2807 USE(vt2); | |
2808 USE(vt3); | |
2809 USE(vt4); | |
2810 DCHECK(AreSameFormat(vt, vt2, vt3, vt4)); | |
2811 DCHECK(AreConsecutive(vt, vt2, vt3, vt4)); | |
2812 LoadStoreStructSingle(vt, lane, src, NEONLoadStoreSingleStructLoad4); | |
2813 } | |
2814 | |
2815 void Assembler::ld4r(const VRegister& vt, const VRegister& vt2, | |
2816 const VRegister& vt3, const VRegister& vt4, | |
2817 const MemOperand& src) { | |
2818 USE(vt2); | |
2819 USE(vt3); | |
2820 USE(vt4); | |
2821 DCHECK(AreSameFormat(vt, vt2, vt3, vt4)); | |
2822 DCHECK(AreConsecutive(vt, vt2, vt3, vt4)); | |
2823 LoadStoreStructSingleAllLanes(vt, src, NEON_LD4R); | |
2824 } | |
2825 | |
2826 void Assembler::st1(const VRegister& vt, const MemOperand& src) { | |
2827 LoadStoreStruct(vt, src, NEON_ST1_1v); | |
2828 } | |
2829 | |
2830 void Assembler::st1(const VRegister& vt, const VRegister& vt2, | |
2831 const MemOperand& src) { | |
2832 USE(vt2); | |
2833 DCHECK(AreSameFormat(vt, vt2)); | |
2834 DCHECK(AreConsecutive(vt, vt2)); | |
2835 LoadStoreStruct(vt, src, NEON_ST1_2v); | |
2836 } | |
2837 | |
2838 void Assembler::st1(const VRegister& vt, const VRegister& vt2, | |
2839 const VRegister& vt3, const MemOperand& src) { | |
2840 USE(vt2); | |
2841 USE(vt3); | |
2842 DCHECK(AreSameFormat(vt, vt2, vt3)); | |
2843 DCHECK(AreConsecutive(vt, vt2, vt3)); | |
2844 LoadStoreStruct(vt, src, NEON_ST1_3v); | |
2845 } | |
2846 | |
2847 void Assembler::st1(const VRegister& vt, const VRegister& vt2, | |
2848 const VRegister& vt3, const VRegister& vt4, | |
2849 const MemOperand& src) { | |
2850 USE(vt2); | |
2851 USE(vt3); | |
2852 USE(vt4); | |
2853 DCHECK(AreSameFormat(vt, vt2, vt3, vt4)); | |
2854 DCHECK(AreConsecutive(vt, vt2, vt3, vt4)); | |
2855 LoadStoreStruct(vt, src, NEON_ST1_4v); | |
2856 } | |
2857 | |
2858 void Assembler::st2(const VRegister& vt, const VRegister& vt2, | |
2859 const MemOperand& dst) { | |
2860 USE(vt2); | |
2861 DCHECK(AreSameFormat(vt, vt2)); | |
2862 DCHECK(AreConsecutive(vt, vt2)); | |
2863 LoadStoreStruct(vt, dst, NEON_ST2); | |
2864 } | |
2865 | |
2866 void Assembler::st2(const VRegister& vt, const VRegister& vt2, int lane, | |
2867 const MemOperand& dst) { | |
2868 USE(vt2); | |
2869 DCHECK(AreSameFormat(vt, vt2)); | |
2870 DCHECK(AreConsecutive(vt, vt2)); | |
2871 LoadStoreStructSingle(vt, lane, dst, NEONLoadStoreSingleStructStore2); | |
2872 } | |
2873 | |
2874 void Assembler::st3(const VRegister& vt, const VRegister& vt2, | |
2875 const VRegister& vt3, const MemOperand& dst) { | |
2876 USE(vt2); | |
2877 USE(vt3); | |
2878 DCHECK(AreSameFormat(vt, vt2, vt3)); | |
2879 DCHECK(AreConsecutive(vt, vt2, vt3)); | |
2880 LoadStoreStruct(vt, dst, NEON_ST3); | |
2881 } | |
2882 | |
2883 void Assembler::st3(const VRegister& vt, const VRegister& vt2, | |
2884 const VRegister& vt3, int lane, const MemOperand& dst) { | |
2885 USE(vt2); | |
2886 USE(vt3); | |
2887 DCHECK(AreSameFormat(vt, vt2, vt3)); | |
2888 DCHECK(AreConsecutive(vt, vt2, vt3)); | |
2889 LoadStoreStructSingle(vt, lane, dst, NEONLoadStoreSingleStructStore3); | |
2890 } | |
2891 | |
2892 void Assembler::st4(const VRegister& vt, const VRegister& vt2, | |
2893 const VRegister& vt3, const VRegister& vt4, | |
2894 const MemOperand& dst) { | |
2895 USE(vt2); | |
2896 USE(vt3); | |
2897 USE(vt4); | |
2898 DCHECK(AreSameFormat(vt, vt2, vt3, vt4)); | |
2899 DCHECK(AreConsecutive(vt, vt2, vt3, vt4)); | |
2900 LoadStoreStruct(vt, dst, NEON_ST4); | |
2901 } | |
2902 | |
2903 void Assembler::st4(const VRegister& vt, const VRegister& vt2, | |
2904 const VRegister& vt3, const VRegister& vt4, int lane, | |
2905 const MemOperand& dst) { | |
2906 USE(vt2); | |
2907 USE(vt3); | |
2908 USE(vt4); | |
2909 DCHECK(AreSameFormat(vt, vt2, vt3, vt4)); | |
2910 DCHECK(AreConsecutive(vt, vt2, vt3, vt4)); | |
2911 LoadStoreStructSingle(vt, lane, dst, NEONLoadStoreSingleStructStore4); | |
2912 } | |
2913 | |
2914 void Assembler::LoadStoreStructSingle(const VRegister& vt, uint32_t lane, | |
2915 const MemOperand& addr, | |
2916 NEONLoadStoreSingleStructOp op) { | |
2917 LoadStoreStructVerify(vt, addr, op); | |
2918 | |
2919 // We support vt arguments of the form vt.VxT() or vt.T(), where x is the | |
2920 // number of lanes, and T is b, h, s or d. | |
2921 unsigned lane_size = vt.LaneSizeInBytes(); | |
2922 DCHECK_LT(lane, kQRegSize / lane_size); | |
2923 | |
2924 // Lane size is encoded in the opcode field. Lane index is encoded in the Q, | |
2925 // S and size fields. | |
2926 lane *= lane_size; | |
2927 | |
2928 // Encodings for S[0]/D[0] and S[2]/D[1] are distinguished using the least- | |
2929 // significant bit of the size field, so we increment lane here to account for | |
2930 // that. | |
2931 if (lane_size == 8) lane++; | |
2932 | |
2933 Instr size = (lane << NEONLSSize_offset) & NEONLSSize_mask; | |
2934 Instr s = (lane << (NEONS_offset - 2)) & NEONS_mask; | |
2935 Instr q = (lane << (NEONQ_offset - 3)) & NEONQ_mask; | |
2936 | |
2937 Instr instr = op; | |
2938 switch (lane_size) { | |
2939 case 1: | |
2940 instr |= NEONLoadStoreSingle_b; | |
2941 break; | |
2942 case 2: | |
2943 instr |= NEONLoadStoreSingle_h; | |
2944 break; | |
2945 case 4: | |
2946 instr |= NEONLoadStoreSingle_s; | |
2947 break; | |
2948 default: | |
2949 DCHECK_EQ(lane_size, 8U); | |
2950 instr |= NEONLoadStoreSingle_d; | |
2951 } | |
2952 | |
2953 Emit(instr | LoadStoreStructAddrModeField(addr) | q | size | s | Rt(vt)); | |
2954 } | |
2955 | |
2956 void Assembler::ld1(const VRegister& vt, int lane, const MemOperand& src) { | |
2957 LoadStoreStructSingle(vt, lane, src, NEONLoadStoreSingleStructLoad1); | |
2958 } | |
2959 | |
2960 void Assembler::ld1r(const VRegister& vt, const MemOperand& src) { | |
2961 LoadStoreStructSingleAllLanes(vt, src, NEON_LD1R); | |
2962 } | |
2963 | |
2964 void Assembler::st1(const VRegister& vt, int lane, const MemOperand& dst) { | |
2965 LoadStoreStructSingle(vt, lane, dst, NEONLoadStoreSingleStructStore1); | |
2966 } | |
1803 | 2967 |
1804 void Assembler::dmb(BarrierDomain domain, BarrierType type) { | 2968 void Assembler::dmb(BarrierDomain domain, BarrierType type) { |
1805 Emit(DMB | ImmBarrierDomain(domain) | ImmBarrierType(type)); | 2969 Emit(DMB | ImmBarrierDomain(domain) | ImmBarrierType(type)); |
1806 } | 2970 } |
1807 | 2971 |
1808 | |
1809 void Assembler::dsb(BarrierDomain domain, BarrierType type) { | 2972 void Assembler::dsb(BarrierDomain domain, BarrierType type) { |
1810 Emit(DSB | ImmBarrierDomain(domain) | ImmBarrierType(type)); | 2973 Emit(DSB | ImmBarrierDomain(domain) | ImmBarrierType(type)); |
1811 } | 2974 } |
1812 | 2975 |
1813 | |
1814 void Assembler::isb() { | 2976 void Assembler::isb() { |
1815 Emit(ISB | ImmBarrierDomain(FullSystem) | ImmBarrierType(BarrierAll)); | 2977 Emit(ISB | ImmBarrierDomain(FullSystem) | ImmBarrierType(BarrierAll)); |
1816 } | 2978 } |
1817 | 2979 |
1818 | 2980 void Assembler::fmov(const VRegister& vd, double imm) { |
1819 void Assembler::fmov(FPRegister fd, double imm) { | 2981 if (vd.IsScalar()) { |
1820 DCHECK(fd.Is64Bits()); | 2982 DCHECK(vd.Is1D()); |
1821 DCHECK(IsImmFP64(imm)); | 2983 Emit(FMOV_d_imm | Rd(vd) | ImmFP(imm)); |
1822 Emit(FMOV_d_imm | Rd(fd) | ImmFP64(imm)); | 2984 } else { |
1823 } | 2985 DCHECK(vd.Is2D()); |
1824 | 2986 Instr op = NEONModifiedImmediate_MOVI | NEONModifiedImmediateOpBit; |
1825 | 2987 Emit(NEON_Q | op | ImmNEONFP(imm) | NEONCmode(0xf) | Rd(vd)); |
1826 void Assembler::fmov(FPRegister fd, float imm) { | 2988 } |
1827 DCHECK(fd.Is32Bits()); | 2989 } |
1828 DCHECK(IsImmFP32(imm)); | 2990 |
1829 Emit(FMOV_s_imm | Rd(fd) | ImmFP32(imm)); | 2991 void Assembler::fmov(const VRegister& vd, float imm) { |
1830 } | 2992 if (vd.IsScalar()) { |
1831 | 2993 DCHECK(vd.Is1S()); |
1832 | 2994 Emit(FMOV_s_imm | Rd(vd) | ImmFP(imm)); |
1833 void Assembler::fmov(Register rd, FPRegister fn) { | 2995 } else { |
1834 DCHECK(rd.SizeInBits() == fn.SizeInBits()); | 2996 DCHECK(vd.Is2S() | vd.Is4S()); |
2997 Instr op = NEONModifiedImmediate_MOVI; | |
2998 Instr q = vd.Is4S() ? NEON_Q : 0; | |
2999 Emit(q | op | ImmNEONFP(imm) | NEONCmode(0xf) | Rd(vd)); | |
3000 } | |
3001 } | |
3002 | |
3003 void Assembler::fmov(const Register& rd, const VRegister& fn) { | |
3004 DCHECK_EQ(rd.SizeInBits(), fn.SizeInBits()); | |
1835 FPIntegerConvertOp op = rd.Is32Bits() ? FMOV_ws : FMOV_xd; | 3005 FPIntegerConvertOp op = rd.Is32Bits() ? FMOV_ws : FMOV_xd; |
1836 Emit(op | Rd(rd) | Rn(fn)); | 3006 Emit(op | Rd(rd) | Rn(fn)); |
1837 } | 3007 } |
1838 | 3008 |
1839 | 3009 void Assembler::fmov(const VRegister& vd, const Register& rn) { |
1840 void Assembler::fmov(FPRegister fd, Register rn) { | 3010 DCHECK_EQ(vd.SizeInBits(), rn.SizeInBits()); |
1841 DCHECK(fd.SizeInBits() == rn.SizeInBits()); | 3011 FPIntegerConvertOp op = vd.Is32Bits() ? FMOV_sw : FMOV_dx; |
1842 FPIntegerConvertOp op = fd.Is32Bits() ? FMOV_sw : FMOV_dx; | 3012 Emit(op | Rd(vd) | Rn(rn)); |
1843 Emit(op | Rd(fd) | Rn(rn)); | 3013 } |
1844 } | 3014 |
1845 | 3015 void Assembler::fmov(const VRegister& vd, const VRegister& vn) { |
1846 | 3016 DCHECK_EQ(vd.SizeInBits(), vn.SizeInBits()); |
1847 void Assembler::fmov(FPRegister fd, FPRegister fn) { | 3017 Emit(FPType(vd) | FMOV | Rd(vd) | Rn(vn)); |
1848 DCHECK(fd.SizeInBits() == fn.SizeInBits()); | 3018 } |
1849 Emit(FPType(fd) | FMOV | Rd(fd) | Rn(fn)); | 3019 |
1850 } | 3020 void Assembler::fmov(const VRegister& vd, int index, const Register& rn) { |
1851 | 3021 DCHECK((index == 1) && vd.Is1D() && rn.IsX()); |
1852 | 3022 USE(index); |
1853 void Assembler::fadd(const FPRegister& fd, | 3023 Emit(FMOV_d1_x | Rd(vd) | Rn(rn)); |
1854 const FPRegister& fn, | 3024 } |
1855 const FPRegister& fm) { | 3025 |
1856 FPDataProcessing2Source(fd, fn, fm, FADD); | 3026 void Assembler::fmov(const Register& rd, const VRegister& vn, int index) { |
1857 } | 3027 DCHECK((index == 1) && vn.Is1D() && rd.IsX()); |
1858 | 3028 USE(index); |
1859 | 3029 Emit(FMOV_x_d1 | Rd(rd) | Rn(vn)); |
1860 void Assembler::fsub(const FPRegister& fd, | 3030 } |
1861 const FPRegister& fn, | 3031 |
1862 const FPRegister& fm) { | 3032 void Assembler::fmadd(const VRegister& fd, const VRegister& fn, |
1863 FPDataProcessing2Source(fd, fn, fm, FSUB); | 3033 const VRegister& fm, const VRegister& fa) { |
1864 } | |
1865 | |
1866 | |
1867 void Assembler::fmul(const FPRegister& fd, | |
1868 const FPRegister& fn, | |
1869 const FPRegister& fm) { | |
1870 FPDataProcessing2Source(fd, fn, fm, FMUL); | |
1871 } | |
1872 | |
1873 | |
1874 void Assembler::fmadd(const FPRegister& fd, | |
1875 const FPRegister& fn, | |
1876 const FPRegister& fm, | |
1877 const FPRegister& fa) { | |
1878 FPDataProcessing3Source(fd, fn, fm, fa, fd.Is32Bits() ? FMADD_s : FMADD_d); | 3034 FPDataProcessing3Source(fd, fn, fm, fa, fd.Is32Bits() ? FMADD_s : FMADD_d); |
1879 } | 3035 } |
1880 | 3036 |
1881 | 3037 void Assembler::fmsub(const VRegister& fd, const VRegister& fn, |
1882 void Assembler::fmsub(const FPRegister& fd, | 3038 const VRegister& fm, const VRegister& fa) { |
1883 const FPRegister& fn, | |
1884 const FPRegister& fm, | |
1885 const FPRegister& fa) { | |
1886 FPDataProcessing3Source(fd, fn, fm, fa, fd.Is32Bits() ? FMSUB_s : FMSUB_d); | 3039 FPDataProcessing3Source(fd, fn, fm, fa, fd.Is32Bits() ? FMSUB_s : FMSUB_d); |
1887 } | 3040 } |
1888 | 3041 |
1889 | 3042 void Assembler::fnmadd(const VRegister& fd, const VRegister& fn, |
1890 void Assembler::fnmadd(const FPRegister& fd, | 3043 const VRegister& fm, const VRegister& fa) { |
1891 const FPRegister& fn, | |
1892 const FPRegister& fm, | |
1893 const FPRegister& fa) { | |
1894 FPDataProcessing3Source(fd, fn, fm, fa, fd.Is32Bits() ? FNMADD_s : FNMADD_d); | 3044 FPDataProcessing3Source(fd, fn, fm, fa, fd.Is32Bits() ? FNMADD_s : FNMADD_d); |
1895 } | 3045 } |
1896 | 3046 |
1897 | 3047 void Assembler::fnmsub(const VRegister& fd, const VRegister& fn, |
1898 void Assembler::fnmsub(const FPRegister& fd, | 3048 const VRegister& fm, const VRegister& fa) { |
1899 const FPRegister& fn, | |
1900 const FPRegister& fm, | |
1901 const FPRegister& fa) { | |
1902 FPDataProcessing3Source(fd, fn, fm, fa, fd.Is32Bits() ? FNMSUB_s : FNMSUB_d); | 3049 FPDataProcessing3Source(fd, fn, fm, fa, fd.Is32Bits() ? FNMSUB_s : FNMSUB_d); |
1903 } | 3050 } |
1904 | 3051 |
1905 | 3052 void Assembler::fnmul(const VRegister& vd, const VRegister& vn, |
1906 void Assembler::fdiv(const FPRegister& fd, | 3053 const VRegister& vm) { |
1907 const FPRegister& fn, | 3054 DCHECK(AreSameSizeAndType(vd, vn, vm)); |
1908 const FPRegister& fm) { | 3055 Instr op = vd.Is1S() ? FNMUL_s : FNMUL_d; |
1909 FPDataProcessing2Source(fd, fn, fm, FDIV); | 3056 Emit(FPType(vd) | op | Rm(vm) | Rn(vn) | Rd(vd)); |
1910 } | 3057 } |
1911 | 3058 |
1912 | 3059 void Assembler::fcmp(const VRegister& fn, const VRegister& fm) { |
1913 void Assembler::fmax(const FPRegister& fd, | 3060 DCHECK_EQ(fn.SizeInBits(), fm.SizeInBits()); |
1914 const FPRegister& fn, | |
1915 const FPRegister& fm) { | |
1916 FPDataProcessing2Source(fd, fn, fm, FMAX); | |
1917 } | |
1918 | |
1919 | |
1920 void Assembler::fmaxnm(const FPRegister& fd, | |
1921 const FPRegister& fn, | |
1922 const FPRegister& fm) { | |
1923 FPDataProcessing2Source(fd, fn, fm, FMAXNM); | |
1924 } | |
1925 | |
1926 | |
1927 void Assembler::fmin(const FPRegister& fd, | |
1928 const FPRegister& fn, | |
1929 const FPRegister& fm) { | |
1930 FPDataProcessing2Source(fd, fn, fm, FMIN); | |
1931 } | |
1932 | |
1933 | |
1934 void Assembler::fminnm(const FPRegister& fd, | |
1935 const FPRegister& fn, | |
1936 const FPRegister& fm) { | |
1937 FPDataProcessing2Source(fd, fn, fm, FMINNM); | |
1938 } | |
1939 | |
1940 | |
1941 void Assembler::fabs(const FPRegister& fd, | |
1942 const FPRegister& fn) { | |
1943 DCHECK(fd.SizeInBits() == fn.SizeInBits()); | |
1944 FPDataProcessing1Source(fd, fn, FABS); | |
1945 } | |
1946 | |
1947 | |
1948 void Assembler::fneg(const FPRegister& fd, | |
1949 const FPRegister& fn) { | |
1950 DCHECK(fd.SizeInBits() == fn.SizeInBits()); | |
1951 FPDataProcessing1Source(fd, fn, FNEG); | |
1952 } | |
1953 | |
1954 | |
1955 void Assembler::fsqrt(const FPRegister& fd, | |
1956 const FPRegister& fn) { | |
1957 DCHECK(fd.SizeInBits() == fn.SizeInBits()); | |
1958 FPDataProcessing1Source(fd, fn, FSQRT); | |
1959 } | |
1960 | |
1961 | |
1962 void Assembler::frinta(const FPRegister& fd, | |
1963 const FPRegister& fn) { | |
1964 DCHECK(fd.SizeInBits() == fn.SizeInBits()); | |
1965 FPDataProcessing1Source(fd, fn, FRINTA); | |
1966 } | |
1967 | |
1968 | |
1969 void Assembler::frintm(const FPRegister& fd, | |
1970 const FPRegister& fn) { | |
1971 DCHECK(fd.SizeInBits() == fn.SizeInBits()); | |
1972 FPDataProcessing1Source(fd, fn, FRINTM); | |
1973 } | |
1974 | |
1975 | |
1976 void Assembler::frintn(const FPRegister& fd, | |
1977 const FPRegister& fn) { | |
1978 DCHECK(fd.SizeInBits() == fn.SizeInBits()); | |
1979 FPDataProcessing1Source(fd, fn, FRINTN); | |
1980 } | |
1981 | |
1982 | |
1983 void Assembler::frintp(const FPRegister& fd, const FPRegister& fn) { | |
1984 DCHECK(fd.SizeInBits() == fn.SizeInBits()); | |
1985 FPDataProcessing1Source(fd, fn, FRINTP); | |
1986 } | |
1987 | |
1988 | |
1989 void Assembler::frintz(const FPRegister& fd, | |
1990 const FPRegister& fn) { | |
1991 DCHECK(fd.SizeInBits() == fn.SizeInBits()); | |
1992 FPDataProcessing1Source(fd, fn, FRINTZ); | |
1993 } | |
1994 | |
1995 | |
1996 void Assembler::fcmp(const FPRegister& fn, | |
1997 const FPRegister& fm) { | |
1998 DCHECK(fn.SizeInBits() == fm.SizeInBits()); | |
1999 Emit(FPType(fn) | FCMP | Rm(fm) | Rn(fn)); | 3061 Emit(FPType(fn) | FCMP | Rm(fm) | Rn(fn)); |
2000 } | 3062 } |
2001 | 3063 |
2002 | 3064 void Assembler::fcmp(const VRegister& fn, double value) { |
2003 void Assembler::fcmp(const FPRegister& fn, | |
2004 double value) { | |
2005 USE(value); | 3065 USE(value); |
2006 // Although the fcmp instruction can strictly only take an immediate value of | 3066 // Although the fcmp instruction can strictly only take an immediate value of |
2007 // +0.0, we don't need to check for -0.0 because the sign of 0.0 doesn't | 3067 // +0.0, we don't need to check for -0.0 because the sign of 0.0 doesn't |
2008 // affect the result of the comparison. | 3068 // affect the result of the comparison. |
2009 DCHECK(value == 0.0); | 3069 DCHECK_EQ(value, 0.0); |
2010 Emit(FPType(fn) | FCMP_zero | Rn(fn)); | 3070 Emit(FPType(fn) | FCMP_zero | Rn(fn)); |
2011 } | 3071 } |
2012 | 3072 |
2013 | 3073 void Assembler::fccmp(const VRegister& fn, const VRegister& fm, |
2014 void Assembler::fccmp(const FPRegister& fn, | 3074 StatusFlags nzcv, Condition cond) { |
2015 const FPRegister& fm, | 3075 DCHECK_EQ(fn.SizeInBits(), fm.SizeInBits()); |
2016 StatusFlags nzcv, | |
2017 Condition cond) { | |
2018 DCHECK(fn.SizeInBits() == fm.SizeInBits()); | |
2019 Emit(FPType(fn) | FCCMP | Rm(fm) | Cond(cond) | Rn(fn) | Nzcv(nzcv)); | 3076 Emit(FPType(fn) | FCCMP | Rm(fm) | Cond(cond) | Rn(fn) | Nzcv(nzcv)); |
2020 } | 3077 } |
2021 | 3078 |
2022 | 3079 void Assembler::fcsel(const VRegister& fd, const VRegister& fn, |
2023 void Assembler::fcsel(const FPRegister& fd, | 3080 const VRegister& fm, Condition cond) { |
2024 const FPRegister& fn, | 3081 DCHECK_EQ(fd.SizeInBits(), fn.SizeInBits()); |
2025 const FPRegister& fm, | 3082 DCHECK_EQ(fd.SizeInBits(), fm.SizeInBits()); |
2026 Condition cond) { | |
2027 DCHECK(fd.SizeInBits() == fn.SizeInBits()); | |
2028 DCHECK(fd.SizeInBits() == fm.SizeInBits()); | |
2029 Emit(FPType(fd) | FCSEL | Rm(fm) | Cond(cond) | Rn(fn) | Rd(fd)); | 3083 Emit(FPType(fd) | FCSEL | Rm(fm) | Cond(cond) | Rn(fn) | Rd(fd)); |
2030 } | 3084 } |
2031 | 3085 |
2032 | 3086 void Assembler::NEONFPConvertToInt(const Register& rd, const VRegister& vn, |
2033 void Assembler::FPConvertToInt(const Register& rd, | 3087 Instr op) { |
2034 const FPRegister& fn, | 3088 Emit(SF(rd) | FPType(vn) | op | Rn(vn) | Rd(rd)); |
2035 FPIntegerConvertOp op) { | 3089 } |
2036 Emit(SF(rd) | FPType(fn) | op | Rn(fn) | Rd(rd)); | 3090 |
2037 } | 3091 void Assembler::NEONFPConvertToInt(const VRegister& vd, const VRegister& vn, |
2038 | 3092 Instr op) { |
2039 | 3093 if (vn.IsScalar()) { |
2040 void Assembler::fcvt(const FPRegister& fd, | 3094 DCHECK((vd.Is1S() && vn.Is1S()) || (vd.Is1D() && vn.Is1D())); |
2041 const FPRegister& fn) { | 3095 op |= NEON_Q | NEONScalar; |
2042 if (fd.Is64Bits()) { | 3096 } |
2043 // Convert float to double. | 3097 Emit(FPFormat(vn) | op | Rn(vn) | Rd(vd)); |
2044 DCHECK(fn.Is32Bits()); | 3098 } |
2045 FPDataProcessing1Source(fd, fn, FCVT_ds); | 3099 |
2046 } else { | 3100 void Assembler::fcvt(const VRegister& vd, const VRegister& vn) { |
2047 // Convert double to float. | 3101 FPDataProcessing1SourceOp op; |
2048 DCHECK(fn.Is64Bits()); | 3102 if (vd.Is1D()) { |
2049 FPDataProcessing1Source(fd, fn, FCVT_sd); | 3103 DCHECK(vn.Is1S() || vn.Is1H()); |
2050 } | 3104 op = vn.Is1S() ? FCVT_ds : FCVT_dh; |
2051 } | 3105 } else if (vd.Is1S()) { |
2052 | 3106 DCHECK(vn.Is1D() || vn.Is1H()); |
2053 | 3107 op = vn.Is1D() ? FCVT_sd : FCVT_sh; |
2054 void Assembler::fcvtau(const Register& rd, const FPRegister& fn) { | 3108 } else { |
2055 FPConvertToInt(rd, fn, FCVTAU); | 3109 DCHECK(vd.Is1H()); |
2056 } | 3110 DCHECK(vn.Is1D() || vn.Is1S()); |
2057 | 3111 op = vn.Is1D() ? FCVT_hd : FCVT_hs; |
2058 | 3112 } |
2059 void Assembler::fcvtas(const Register& rd, const FPRegister& fn) { | 3113 FPDataProcessing1Source(vd, vn, op); |
2060 FPConvertToInt(rd, fn, FCVTAS); | 3114 } |
2061 } | 3115 |
2062 | 3116 void Assembler::fcvtl(const VRegister& vd, const VRegister& vn) { |
2063 | 3117 DCHECK((vd.Is4S() && vn.Is4H()) || (vd.Is2D() && vn.Is2S())); |
2064 void Assembler::fcvtmu(const Register& rd, const FPRegister& fn) { | 3118 Instr format = vd.Is2D() ? (1 << NEONSize_offset) : 0; |
2065 FPConvertToInt(rd, fn, FCVTMU); | 3119 Emit(format | NEON_FCVTL | Rn(vn) | Rd(vd)); |
2066 } | 3120 } |
2067 | 3121 |
2068 | 3122 void Assembler::fcvtl2(const VRegister& vd, const VRegister& vn) { |
2069 void Assembler::fcvtms(const Register& rd, const FPRegister& fn) { | 3123 DCHECK((vd.Is4S() && vn.Is8H()) || (vd.Is2D() && vn.Is4S())); |
2070 FPConvertToInt(rd, fn, FCVTMS); | 3124 Instr format = vd.Is2D() ? (1 << NEONSize_offset) : 0; |
2071 } | 3125 Emit(NEON_Q | format | NEON_FCVTL | Rn(vn) | Rd(vd)); |
2072 | 3126 } |
2073 | 3127 |
2074 void Assembler::fcvtnu(const Register& rd, const FPRegister& fn) { | 3128 void Assembler::fcvtn(const VRegister& vd, const VRegister& vn) { |
2075 FPConvertToInt(rd, fn, FCVTNU); | 3129 DCHECK((vn.Is4S() && vd.Is4H()) || (vn.Is2D() && vd.Is2S())); |
2076 } | 3130 Instr format = vn.Is2D() ? (1 << NEONSize_offset) : 0; |
2077 | 3131 Emit(format | NEON_FCVTN | Rn(vn) | Rd(vd)); |
2078 | 3132 } |
2079 void Assembler::fcvtns(const Register& rd, const FPRegister& fn) { | 3133 |
2080 FPConvertToInt(rd, fn, FCVTNS); | 3134 void Assembler::fcvtn2(const VRegister& vd, const VRegister& vn) { |
2081 } | 3135 DCHECK((vn.Is4S() && vd.Is8H()) || (vn.Is2D() && vd.Is4S())); |
2082 | 3136 Instr format = vn.Is2D() ? (1 << NEONSize_offset) : 0; |
2083 | 3137 Emit(NEON_Q | format | NEON_FCVTN | Rn(vn) | Rd(vd)); |
2084 void Assembler::fcvtzu(const Register& rd, const FPRegister& fn) { | 3138 } |
2085 FPConvertToInt(rd, fn, FCVTZU); | 3139 |
2086 } | 3140 void Assembler::fcvtxn(const VRegister& vd, const VRegister& vn) { |
2087 | 3141 Instr format = 1 << NEONSize_offset; |
2088 | 3142 if (vd.IsScalar()) { |
2089 void Assembler::fcvtzs(const Register& rd, const FPRegister& fn) { | 3143 DCHECK(vd.Is1S() && vn.Is1D()); |
2090 FPConvertToInt(rd, fn, FCVTZS); | 3144 Emit(format | NEON_FCVTXN_scalar | Rn(vn) | Rd(vd)); |
2091 } | 3145 } else { |
2092 | 3146 DCHECK(vd.Is2S() && vn.Is2D()); |
2093 | 3147 Emit(format | NEON_FCVTXN | Rn(vn) | Rd(vd)); |
2094 void Assembler::scvtf(const FPRegister& fd, | 3148 } |
2095 const Register& rn, | 3149 } |
2096 unsigned fbits) { | 3150 |
3151 void Assembler::fcvtxn2(const VRegister& vd, const VRegister& vn) { | |
3152 DCHECK(vd.Is4S() && vn.Is2D()); | |
3153 Instr format = 1 << NEONSize_offset; | |
3154 Emit(NEON_Q | format | NEON_FCVTXN | Rn(vn) | Rd(vd)); | |
3155 } | |
3156 | |
3157 #define NEON_FP2REGMISC_FCVT_LIST(V) \ | |
3158 V(fcvtnu, NEON_FCVTNU, FCVTNU) \ | |
3159 V(fcvtns, NEON_FCVTNS, FCVTNS) \ | |
3160 V(fcvtpu, NEON_FCVTPU, FCVTPU) \ | |
3161 V(fcvtps, NEON_FCVTPS, FCVTPS) \ | |
3162 V(fcvtmu, NEON_FCVTMU, FCVTMU) \ | |
3163 V(fcvtms, NEON_FCVTMS, FCVTMS) \ | |
3164 V(fcvtau, NEON_FCVTAU, FCVTAU) \ | |
3165 V(fcvtas, NEON_FCVTAS, FCVTAS) | |
3166 | |
3167 #define DEFINE_ASM_FUNCS(FN, VEC_OP, SCA_OP) \ | |
3168 void Assembler::FN(const Register& rd, const VRegister& vn) { \ | |
3169 NEONFPConvertToInt(rd, vn, SCA_OP); \ | |
3170 } \ | |
3171 void Assembler::FN(const VRegister& vd, const VRegister& vn) { \ | |
3172 NEONFPConvertToInt(vd, vn, VEC_OP); \ | |
3173 } | |
3174 NEON_FP2REGMISC_FCVT_LIST(DEFINE_ASM_FUNCS) | |
3175 #undef DEFINE_ASM_FUNCS | |
3176 | |
3177 void Assembler::scvtf(const VRegister& vd, const VRegister& vn, int fbits) { | |
3178 DCHECK_GE(fbits, 0); | |
2097 if (fbits == 0) { | 3179 if (fbits == 0) { |
2098 Emit(SF(rn) | FPType(fd) | SCVTF | Rn(rn) | Rd(fd)); | 3180 NEONFP2RegMisc(vd, vn, NEON_SCVTF); |
2099 } else { | 3181 } else { |
2100 Emit(SF(rn) | FPType(fd) | SCVTF_fixed | FPScale(64 - fbits) | Rn(rn) | | 3182 DCHECK(vd.Is1D() || vd.Is1S() || vd.Is2D() || vd.Is2S() || vd.Is4S()); |
2101 Rd(fd)); | 3183 NEONShiftRightImmediate(vd, vn, fbits, NEON_SCVTF_imm); |
2102 } | 3184 } |
2103 } | 3185 } |
2104 | 3186 |
2105 | 3187 void Assembler::ucvtf(const VRegister& vd, const VRegister& vn, int fbits) { |
2106 void Assembler::ucvtf(const FPRegister& fd, | 3188 DCHECK_GE(fbits, 0); |
2107 const Register& rn, | 3189 if (fbits == 0) { |
2108 unsigned fbits) { | 3190 NEONFP2RegMisc(vd, vn, NEON_UCVTF); |
3191 } else { | |
3192 DCHECK(vd.Is1D() || vd.Is1S() || vd.Is2D() || vd.Is2S() || vd.Is4S()); | |
3193 NEONShiftRightImmediate(vd, vn, fbits, NEON_UCVTF_imm); | |
3194 } | |
3195 } | |
3196 | |
3197 void Assembler::scvtf(const VRegister& vd, const Register& rn, int fbits) { | |
3198 DCHECK_GE(fbits, 0); | |
3199 if (fbits == 0) { | |
3200 Emit(SF(rn) | FPType(vd) | SCVTF | Rn(rn) | Rd(vd)); | |
3201 } else { | |
3202 Emit(SF(rn) | FPType(vd) | SCVTF_fixed | FPScale(64 - fbits) | Rn(rn) | | |
3203 Rd(vd)); | |
3204 } | |
3205 } | |
3206 | |
3207 void Assembler::ucvtf(const VRegister& fd, const Register& rn, int fbits) { | |
3208 DCHECK_GE(fbits, 0); | |
2109 if (fbits == 0) { | 3209 if (fbits == 0) { |
2110 Emit(SF(rn) | FPType(fd) | UCVTF | Rn(rn) | Rd(fd)); | 3210 Emit(SF(rn) | FPType(fd) | UCVTF | Rn(rn) | Rd(fd)); |
2111 } else { | 3211 } else { |
2112 Emit(SF(rn) | FPType(fd) | UCVTF_fixed | FPScale(64 - fbits) | Rn(rn) | | 3212 Emit(SF(rn) | FPType(fd) | UCVTF_fixed | FPScale(64 - fbits) | Rn(rn) | |
2113 Rd(fd)); | 3213 Rd(fd)); |
2114 } | 3214 } |
2115 } | 3215 } |
2116 | 3216 |
3217 void Assembler::NEON3Same(const VRegister& vd, const VRegister& vn, | |
3218 const VRegister& vm, NEON3SameOp vop) { | |
3219 DCHECK(AreSameFormat(vd, vn, vm)); | |
3220 DCHECK(vd.IsVector() || !vd.IsQ()); | |
3221 | |
3222 Instr format, op = vop; | |
3223 if (vd.IsScalar()) { | |
3224 op |= NEON_Q | NEONScalar; | |
3225 format = SFormat(vd); | |
3226 } else { | |
3227 format = VFormat(vd); | |
3228 } | |
3229 | |
3230 Emit(format | op | Rm(vm) | Rn(vn) | Rd(vd)); | |
3231 } | |
3232 | |
3233 void Assembler::NEONFP3Same(const VRegister& vd, const VRegister& vn, | |
3234 const VRegister& vm, Instr op) { | |
3235 DCHECK(AreSameFormat(vd, vn, vm)); | |
3236 Emit(FPFormat(vd) | op | Rm(vm) | Rn(vn) | Rd(vd)); | |
3237 } | |
3238 | |
3239 #define NEON_FP2REGMISC_LIST(V) \ | |
3240 V(fabs, NEON_FABS, FABS) \ | |
3241 V(fneg, NEON_FNEG, FNEG) \ | |
3242 V(fsqrt, NEON_FSQRT, FSQRT) \ | |
3243 V(frintn, NEON_FRINTN, FRINTN) \ | |
3244 V(frinta, NEON_FRINTA, FRINTA) \ | |
3245 V(frintp, NEON_FRINTP, FRINTP) \ | |
3246 V(frintm, NEON_FRINTM, FRINTM) \ | |
3247 V(frintx, NEON_FRINTX, FRINTX) \ | |
3248 V(frintz, NEON_FRINTZ, FRINTZ) \ | |
3249 V(frinti, NEON_FRINTI, FRINTI) \ | |
3250 V(frsqrte, NEON_FRSQRTE, NEON_FRSQRTE_scalar) \ | |
3251 V(frecpe, NEON_FRECPE, NEON_FRECPE_scalar) | |
3252 | |
3253 #define DEFINE_ASM_FUNC(FN, VEC_OP, SCA_OP) \ | |
3254 void Assembler::FN(const VRegister& vd, const VRegister& vn) { \ | |
3255 Instr op; \ | |
3256 if (vd.IsScalar()) { \ | |
3257 DCHECK(vd.Is1S() || vd.Is1D()); \ | |
3258 op = SCA_OP; \ | |
3259 } else { \ | |
3260 DCHECK(vd.Is2S() || vd.Is2D() || vd.Is4S()); \ | |
3261 op = VEC_OP; \ | |
3262 } \ | |
3263 NEONFP2RegMisc(vd, vn, op); \ | |
3264 } | |
3265 NEON_FP2REGMISC_LIST(DEFINE_ASM_FUNC) | |
3266 #undef DEFINE_ASM_FUNC | |
3267 | |
3268 void Assembler::shll(const VRegister& vd, const VRegister& vn, int shift) { | |
3269 DCHECK((vd.Is8H() && vn.Is8B() && shift == 8) || | |
3270 (vd.Is4S() && vn.Is4H() && shift == 16) || | |
3271 (vd.Is2D() && vn.Is2S() && shift == 32)); | |
3272 USE(shift); | |
3273 Emit(VFormat(vn) | NEON_SHLL | Rn(vn) | Rd(vd)); | |
3274 } | |
3275 | |
3276 void Assembler::shll2(const VRegister& vd, const VRegister& vn, int shift) { | |
3277 USE(shift); | |
3278 DCHECK((vd.Is8H() && vn.Is16B() && shift == 8) || | |
3279 (vd.Is4S() && vn.Is8H() && shift == 16) || | |
3280 (vd.Is2D() && vn.Is4S() && shift == 32)); | |
3281 Emit(VFormat(vn) | NEON_SHLL | Rn(vn) | Rd(vd)); | |
3282 } | |
3283 | |
3284 void Assembler::NEONFP2RegMisc(const VRegister& vd, const VRegister& vn, | |
3285 NEON2RegMiscOp vop, double value) { | |
3286 DCHECK(AreSameFormat(vd, vn)); | |
3287 DCHECK_EQ(value, 0.0); | |
3288 USE(value); | |
3289 | |
3290 Instr op = vop; | |
3291 if (vd.IsScalar()) { | |
3292 DCHECK(vd.Is1S() || vd.Is1D()); | |
3293 op |= NEON_Q | NEONScalar; | |
3294 } else { | |
3295 DCHECK(vd.Is2S() || vd.Is2D() || vd.Is4S()); | |
3296 } | |
3297 | |
3298 Emit(FPFormat(vd) | op | Rn(vn) | Rd(vd)); | |
3299 } | |
3300 | |
3301 void Assembler::fcmeq(const VRegister& vd, const VRegister& vn, double value) { | |
3302 NEONFP2RegMisc(vd, vn, NEON_FCMEQ_zero, value); | |
3303 } | |
3304 | |
3305 void Assembler::fcmge(const VRegister& vd, const VRegister& vn, double value) { | |
3306 NEONFP2RegMisc(vd, vn, NEON_FCMGE_zero, value); | |
3307 } | |
3308 | |
3309 void Assembler::fcmgt(const VRegister& vd, const VRegister& vn, double value) { | |
3310 NEONFP2RegMisc(vd, vn, NEON_FCMGT_zero, value); | |
3311 } | |
3312 | |
3313 void Assembler::fcmle(const VRegister& vd, const VRegister& vn, double value) { | |
3314 NEONFP2RegMisc(vd, vn, NEON_FCMLE_zero, value); | |
3315 } | |
3316 | |
3317 void Assembler::fcmlt(const VRegister& vd, const VRegister& vn, double value) { | |
3318 NEONFP2RegMisc(vd, vn, NEON_FCMLT_zero, value); | |
3319 } | |
3320 | |
3321 void Assembler::frecpx(const VRegister& vd, const VRegister& vn) { | |
3322 DCHECK(vd.IsScalar()); | |
3323 DCHECK(AreSameFormat(vd, vn)); | |
3324 DCHECK(vd.Is1S() || vd.Is1D()); | |
3325 Emit(FPFormat(vd) | NEON_FRECPX_scalar | Rn(vn) | Rd(vd)); | |
3326 } | |
3327 | |
3328 void Assembler::fcvtzs(const Register& rd, const VRegister& vn, int fbits) { | |
3329 DCHECK(vn.Is1S() || vn.Is1D()); | |
3330 DCHECK((fbits >= 0) && (fbits <= rd.SizeInBits())); | |
3331 if (fbits == 0) { | |
3332 Emit(SF(rd) | FPType(vn) | FCVTZS | Rn(vn) | Rd(rd)); | |
3333 } else { | |
3334 Emit(SF(rd) | FPType(vn) | FCVTZS_fixed | FPScale(64 - fbits) | Rn(vn) | | |
3335 Rd(rd)); | |
3336 } | |
3337 } | |
3338 | |
3339 void Assembler::fcvtzs(const VRegister& vd, const VRegister& vn, int fbits) { | |
3340 DCHECK_GE(fbits, 0); | |
3341 if (fbits == 0) { | |
3342 NEONFP2RegMisc(vd, vn, NEON_FCVTZS); | |
3343 } else { | |
3344 DCHECK(vd.Is1D() || vd.Is1S() || vd.Is2D() || vd.Is2S() || vd.Is4S()); | |
3345 NEONShiftRightImmediate(vd, vn, fbits, NEON_FCVTZS_imm); | |
3346 } | |
3347 } | |
3348 | |
3349 void Assembler::fcvtzu(const Register& rd, const VRegister& vn, int fbits) { | |
3350 DCHECK(vn.Is1S() || vn.Is1D()); | |
3351 DCHECK((fbits >= 0) && (fbits <= rd.SizeInBits())); | |
3352 if (fbits == 0) { | |
3353 Emit(SF(rd) | FPType(vn) | FCVTZU | Rn(vn) | Rd(rd)); | |
3354 } else { | |
3355 Emit(SF(rd) | FPType(vn) | FCVTZU_fixed | FPScale(64 - fbits) | Rn(vn) | | |
3356 Rd(rd)); | |
3357 } | |
3358 } | |
3359 | |
3360 void Assembler::fcvtzu(const VRegister& vd, const VRegister& vn, int fbits) { | |
3361 DCHECK_GE(fbits, 0); | |
3362 if (fbits == 0) { | |
3363 NEONFP2RegMisc(vd, vn, NEON_FCVTZU); | |
3364 } else { | |
3365 DCHECK(vd.Is1D() || vd.Is1S() || vd.Is2D() || vd.Is2S() || vd.Is4S()); | |
3366 NEONShiftRightImmediate(vd, vn, fbits, NEON_FCVTZU_imm); | |
3367 } | |
3368 } | |
3369 | |
3370 void Assembler::NEONFP2RegMisc(const VRegister& vd, const VRegister& vn, | |
3371 Instr op) { | |
3372 DCHECK(AreSameFormat(vd, vn)); | |
3373 Emit(FPFormat(vd) | op | Rn(vn) | Rd(vd)); | |
3374 } | |
3375 | |
3376 void Assembler::NEON2RegMisc(const VRegister& vd, const VRegister& vn, | |
3377 NEON2RegMiscOp vop, int value) { | |
3378 DCHECK(AreSameFormat(vd, vn)); | |
3379 DCHECK_EQ(value, 0); | |
3380 USE(value); | |
3381 | |
3382 Instr format, op = vop; | |
3383 if (vd.IsScalar()) { | |
3384 op |= NEON_Q | NEONScalar; | |
3385 format = SFormat(vd); | |
3386 } else { | |
3387 format = VFormat(vd); | |
3388 } | |
3389 | |
3390 Emit(format | op | Rn(vn) | Rd(vd)); | |
3391 } | |
3392 | |
3393 void Assembler::cmeq(const VRegister& vd, const VRegister& vn, int value) { | |
3394 DCHECK(vd.IsVector() || vd.Is1D()); | |
3395 NEON2RegMisc(vd, vn, NEON_CMEQ_zero, value); | |
3396 } | |
3397 | |
3398 void Assembler::cmge(const VRegister& vd, const VRegister& vn, int value) { | |
3399 DCHECK(vd.IsVector() || vd.Is1D()); | |
3400 NEON2RegMisc(vd, vn, NEON_CMGE_zero, value); | |
3401 } | |
3402 | |
3403 void Assembler::cmgt(const VRegister& vd, const VRegister& vn, int value) { | |
3404 DCHECK(vd.IsVector() || vd.Is1D()); | |
3405 NEON2RegMisc(vd, vn, NEON_CMGT_zero, value); | |
3406 } | |
3407 | |
3408 void Assembler::cmle(const VRegister& vd, const VRegister& vn, int value) { | |
3409 DCHECK(vd.IsVector() || vd.Is1D()); | |
3410 NEON2RegMisc(vd, vn, NEON_CMLE_zero, value); | |
3411 } | |
3412 | |
3413 void Assembler::cmlt(const VRegister& vd, const VRegister& vn, int value) { | |
3414 DCHECK(vd.IsVector() || vd.Is1D()); | |
3415 NEON2RegMisc(vd, vn, NEON_CMLT_zero, value); | |
3416 } | |
3417 | |
3418 #define NEON_3SAME_LIST(V) \ | |
3419 V(add, NEON_ADD, vd.IsVector() || vd.Is1D()) \ | |
3420 V(addp, NEON_ADDP, vd.IsVector() || vd.Is1D()) \ | |
3421 V(sub, NEON_SUB, vd.IsVector() || vd.Is1D()) \ | |
3422 V(cmeq, NEON_CMEQ, vd.IsVector() || vd.Is1D()) \ | |
3423 V(cmge, NEON_CMGE, vd.IsVector() || vd.Is1D()) \ | |
3424 V(cmgt, NEON_CMGT, vd.IsVector() || vd.Is1D()) \ | |
3425 V(cmhi, NEON_CMHI, vd.IsVector() || vd.Is1D()) \ | |
3426 V(cmhs, NEON_CMHS, vd.IsVector() || vd.Is1D()) \ | |
3427 V(cmtst, NEON_CMTST, vd.IsVector() || vd.Is1D()) \ | |
3428 V(sshl, NEON_SSHL, vd.IsVector() || vd.Is1D()) \ | |
3429 V(ushl, NEON_USHL, vd.IsVector() || vd.Is1D()) \ | |
3430 V(srshl, NEON_SRSHL, vd.IsVector() || vd.Is1D()) \ | |
3431 V(urshl, NEON_URSHL, vd.IsVector() || vd.Is1D()) \ | |
3432 V(sqdmulh, NEON_SQDMULH, vd.IsLaneSizeH() || vd.IsLaneSizeS()) \ | |
3433 V(sqrdmulh, NEON_SQRDMULH, vd.IsLaneSizeH() || vd.IsLaneSizeS()) \ | |
3434 V(shadd, NEON_SHADD, vd.IsVector() && !vd.IsLaneSizeD()) \ | |
3435 V(uhadd, NEON_UHADD, vd.IsVector() && !vd.IsLaneSizeD()) \ | |
3436 V(srhadd, NEON_SRHADD, vd.IsVector() && !vd.IsLaneSizeD()) \ | |
3437 V(urhadd, NEON_URHADD, vd.IsVector() && !vd.IsLaneSizeD()) \ | |
3438 V(shsub, NEON_SHSUB, vd.IsVector() && !vd.IsLaneSizeD()) \ | |
3439 V(uhsub, NEON_UHSUB, vd.IsVector() && !vd.IsLaneSizeD()) \ | |
3440 V(smax, NEON_SMAX, vd.IsVector() && !vd.IsLaneSizeD()) \ | |
3441 V(smaxp, NEON_SMAXP, vd.IsVector() && !vd.IsLaneSizeD()) \ | |
3442 V(smin, NEON_SMIN, vd.IsVector() && !vd.IsLaneSizeD()) \ | |
3443 V(sminp, NEON_SMINP, vd.IsVector() && !vd.IsLaneSizeD()) \ | |
3444 V(umax, NEON_UMAX, vd.IsVector() && !vd.IsLaneSizeD()) \ | |
3445 V(umaxp, NEON_UMAXP, vd.IsVector() && !vd.IsLaneSizeD()) \ | |
3446 V(umin, NEON_UMIN, vd.IsVector() && !vd.IsLaneSizeD()) \ | |
3447 V(uminp, NEON_UMINP, vd.IsVector() && !vd.IsLaneSizeD()) \ | |
3448 V(saba, NEON_SABA, vd.IsVector() && !vd.IsLaneSizeD()) \ | |
3449 V(sabd, NEON_SABD, vd.IsVector() && !vd.IsLaneSizeD()) \ | |
3450 V(uaba, NEON_UABA, vd.IsVector() && !vd.IsLaneSizeD()) \ | |
3451 V(uabd, NEON_UABD, vd.IsVector() && !vd.IsLaneSizeD()) \ | |
3452 V(mla, NEON_MLA, vd.IsVector() && !vd.IsLaneSizeD()) \ | |
3453 V(mls, NEON_MLS, vd.IsVector() && !vd.IsLaneSizeD()) \ | |
3454 V(mul, NEON_MUL, vd.IsVector() && !vd.IsLaneSizeD()) \ | |
3455 V(and_, NEON_AND, vd.Is8B() || vd.Is16B()) \ | |
3456 V(orr, NEON_ORR, vd.Is8B() || vd.Is16B()) \ | |
3457 V(orn, NEON_ORN, vd.Is8B() || vd.Is16B()) \ | |
3458 V(eor, NEON_EOR, vd.Is8B() || vd.Is16B()) \ | |
3459 V(bic, NEON_BIC, vd.Is8B() || vd.Is16B()) \ | |
3460 V(bit, NEON_BIT, vd.Is8B() || vd.Is16B()) \ | |
3461 V(bif, NEON_BIF, vd.Is8B() || vd.Is16B()) \ | |
3462 V(bsl, NEON_BSL, vd.Is8B() || vd.Is16B()) \ | |
3463 V(pmul, NEON_PMUL, vd.Is8B() || vd.Is16B()) \ | |
3464 V(uqadd, NEON_UQADD, true) \ | |
3465 V(sqadd, NEON_SQADD, true) \ | |
3466 V(uqsub, NEON_UQSUB, true) \ | |
3467 V(sqsub, NEON_SQSUB, true) \ | |
3468 V(sqshl, NEON_SQSHL, true) \ | |
3469 V(uqshl, NEON_UQSHL, true) \ | |
3470 V(sqrshl, NEON_SQRSHL, true) \ | |
3471 V(uqrshl, NEON_UQRSHL, true) | |
3472 | |
3473 #define DEFINE_ASM_FUNC(FN, OP, AS) \ | |
3474 void Assembler::FN(const VRegister& vd, const VRegister& vn, \ | |
3475 const VRegister& vm) { \ | |
3476 DCHECK(AS); \ | |
3477 NEON3Same(vd, vn, vm, OP); \ | |
3478 } | |
3479 NEON_3SAME_LIST(DEFINE_ASM_FUNC) | |
3480 #undef DEFINE_ASM_FUNC | |
3481 | |
3482 #define NEON_FP3SAME_LIST(V) \ | |
3483 V(fadd, NEON_FADD, FADD) \ | |
3484 V(fsub, NEON_FSUB, FSUB) \ | |
3485 V(fmul, NEON_FMUL, FMUL) \ | |
3486 V(fdiv, NEON_FDIV, FDIV) \ | |
3487 V(fmax, NEON_FMAX, FMAX) \ | |
3488 V(fmaxnm, NEON_FMAXNM, FMAXNM) \ | |
3489 V(fmin, NEON_FMIN, FMIN) \ | |
3490 V(fminnm, NEON_FMINNM, FMINNM) \ | |
3491 V(fmulx, NEON_FMULX, NEON_FMULX_scalar) \ | |
3492 V(frecps, NEON_FRECPS, NEON_FRECPS_scalar) \ | |
3493 V(frsqrts, NEON_FRSQRTS, NEON_FRSQRTS_scalar) \ | |
3494 V(fabd, NEON_FABD, NEON_FABD_scalar) \ | |
3495 V(fmla, NEON_FMLA, 0) \ | |
3496 V(fmls, NEON_FMLS, 0) \ | |
3497 V(facge, NEON_FACGE, NEON_FACGE_scalar) \ | |
3498 V(facgt, NEON_FACGT, NEON_FACGT_scalar) \ | |
3499 V(fcmeq, NEON_FCMEQ, NEON_FCMEQ_scalar) \ | |
3500 V(fcmge, NEON_FCMGE, NEON_FCMGE_scalar) \ | |
3501 V(fcmgt, NEON_FCMGT, NEON_FCMGT_scalar) \ | |
3502 V(faddp, NEON_FADDP, 0) \ | |
3503 V(fmaxp, NEON_FMAXP, 0) \ | |
3504 V(fminp, NEON_FMINP, 0) \ | |
3505 V(fmaxnmp, NEON_FMAXNMP, 0) \ | |
3506 V(fminnmp, NEON_FMINNMP, 0) | |
3507 | |
3508 #define DEFINE_ASM_FUNC(FN, VEC_OP, SCA_OP) \ | |
3509 void Assembler::FN(const VRegister& vd, const VRegister& vn, \ | |
3510 const VRegister& vm) { \ | |
3511 Instr op; \ | |
3512 if ((SCA_OP != 0) && vd.IsScalar()) { \ | |
3513 DCHECK(vd.Is1S() || vd.Is1D()); \ | |
3514 op = SCA_OP; \ | |
3515 } else { \ | |
3516 DCHECK(vd.IsVector()); \ | |
3517 DCHECK(vd.Is2S() || vd.Is2D() || vd.Is4S()); \ | |
3518 op = VEC_OP; \ | |
3519 } \ | |
3520 NEONFP3Same(vd, vn, vm, op); \ | |
3521 } | |
3522 NEON_FP3SAME_LIST(DEFINE_ASM_FUNC) | |
3523 #undef DEFINE_ASM_FUNC | |
3524 | |
3525 void Assembler::addp(const VRegister& vd, const VRegister& vn) { | |
3526 DCHECK((vd.Is1D() && vn.Is2D())); | |
3527 Emit(SFormat(vd) | NEON_ADDP_scalar | Rn(vn) | Rd(vd)); | |
3528 } | |
3529 | |
3530 void Assembler::faddp(const VRegister& vd, const VRegister& vn) { | |
3531 DCHECK((vd.Is1S() && vn.Is2S()) || (vd.Is1D() && vn.Is2D())); | |
3532 Emit(FPFormat(vd) | NEON_FADDP_scalar | Rn(vn) | Rd(vd)); | |
3533 } | |
3534 | |
3535 void Assembler::fmaxp(const VRegister& vd, const VRegister& vn) { | |
3536 DCHECK((vd.Is1S() && vn.Is2S()) || (vd.Is1D() && vn.Is2D())); | |
3537 Emit(FPFormat(vd) | NEON_FMAXP_scalar | Rn(vn) | Rd(vd)); | |
3538 } | |
3539 | |
3540 void Assembler::fminp(const VRegister& vd, const VRegister& vn) { | |
3541 DCHECK((vd.Is1S() && vn.Is2S()) || (vd.Is1D() && vn.Is2D())); | |
3542 Emit(FPFormat(vd) | NEON_FMINP_scalar | Rn(vn) | Rd(vd)); | |
3543 } | |
3544 | |
3545 void Assembler::fmaxnmp(const VRegister& vd, const VRegister& vn) { | |
3546 DCHECK((vd.Is1S() && vn.Is2S()) || (vd.Is1D() && vn.Is2D())); | |
3547 Emit(FPFormat(vd) | NEON_FMAXNMP_scalar | Rn(vn) | Rd(vd)); | |
3548 } | |
3549 | |
3550 void Assembler::fminnmp(const VRegister& vd, const VRegister& vn) { | |
3551 DCHECK((vd.Is1S() && vn.Is2S()) || (vd.Is1D() && vn.Is2D())); | |
3552 Emit(FPFormat(vd) | NEON_FMINNMP_scalar | Rn(vn) | Rd(vd)); | |
3553 } | |
3554 | |
3555 void Assembler::orr(const VRegister& vd, const int imm8, const int left_shift) { | |
3556 NEONModifiedImmShiftLsl(vd, imm8, left_shift, NEONModifiedImmediate_ORR); | |
3557 } | |
3558 | |
3559 void Assembler::mov(const VRegister& vd, const VRegister& vn) { | |
3560 DCHECK(AreSameFormat(vd, vn)); | |
3561 if (vd.IsD()) { | |
3562 orr(vd.V8B(), vn.V8B(), vn.V8B()); | |
3563 } else { | |
3564 DCHECK(vd.IsQ()); | |
3565 orr(vd.V16B(), vn.V16B(), vn.V16B()); | |
3566 } | |
3567 } | |
3568 | |
3569 void Assembler::bic(const VRegister& vd, const int imm8, const int left_shift) { | |
3570 NEONModifiedImmShiftLsl(vd, imm8, left_shift, NEONModifiedImmediate_BIC); | |
3571 } | |
3572 | |
3573 void Assembler::movi(const VRegister& vd, const uint64_t imm, Shift shift, | |
3574 const int shift_amount) { | |
3575 DCHECK((shift == LSL) || (shift == MSL)); | |
3576 if (vd.Is2D() || vd.Is1D()) { | |
3577 DCHECK_EQ(shift_amount, 0); | |
3578 int imm8 = 0; | |
3579 for (int i = 0; i < 8; ++i) { | |
3580 int byte = (imm >> (i * 8)) & 0xff; | |
3581 DCHECK((byte == 0) || (byte == 0xff)); | |
3582 if (byte == 0xff) { | |
3583 imm8 |= (1 << i); | |
3584 } | |
3585 } | |
3586 Instr q = vd.Is2D() ? NEON_Q : 0; | |
3587 Emit(q | NEONModImmOp(1) | NEONModifiedImmediate_MOVI | | |
3588 ImmNEONabcdefgh(imm8) | NEONCmode(0xe) | Rd(vd)); | |
3589 } else if (shift == LSL) { | |
3590 NEONModifiedImmShiftLsl(vd, static_cast<int>(imm), shift_amount, | |
3591 NEONModifiedImmediate_MOVI); | |
3592 } else { | |
3593 NEONModifiedImmShiftMsl(vd, static_cast<int>(imm), shift_amount, | |
3594 NEONModifiedImmediate_MOVI); | |
3595 } | |
3596 } | |
3597 | |
3598 void Assembler::mvn(const VRegister& vd, const VRegister& vn) { | |
3599 DCHECK(AreSameFormat(vd, vn)); | |
3600 if (vd.IsD()) { | |
3601 not_(vd.V8B(), vn.V8B()); | |
3602 } else { | |
3603 DCHECK(vd.IsQ()); | |
3604 not_(vd.V16B(), vn.V16B()); | |
3605 } | |
3606 } | |
3607 | |
3608 void Assembler::mvni(const VRegister& vd, const int imm8, Shift shift, | |
3609 const int shift_amount) { | |
3610 DCHECK((shift == LSL) || (shift == MSL)); | |
3611 if (shift == LSL) { | |
3612 NEONModifiedImmShiftLsl(vd, imm8, shift_amount, NEONModifiedImmediate_MVNI); | |
3613 } else { | |
3614 NEONModifiedImmShiftMsl(vd, imm8, shift_amount, NEONModifiedImmediate_MVNI); | |
3615 } | |
3616 } | |
3617 | |
3618 void Assembler::NEONFPByElement(const VRegister& vd, const VRegister& vn, | |
3619 const VRegister& vm, int vm_index, | |
3620 NEONByIndexedElementOp vop) { | |
3621 DCHECK(AreSameFormat(vd, vn)); | |
3622 DCHECK((vd.Is2S() && vm.Is1S()) || (vd.Is4S() && vm.Is1S()) || | |
3623 (vd.Is1S() && vm.Is1S()) || (vd.Is2D() && vm.Is1D()) || | |
3624 (vd.Is1D() && vm.Is1D())); | |
3625 DCHECK((vm.Is1S() && (vm_index < 4)) || (vm.Is1D() && (vm_index < 2))); | |
3626 | |
3627 Instr op = vop; | |
3628 int index_num_bits = vm.Is1S() ? 2 : 1; | |
3629 if (vd.IsScalar()) { | |
3630 op |= NEON_Q | NEONScalar; | |
3631 } | |
3632 | |
3633 Emit(FPFormat(vd) | op | ImmNEONHLM(vm_index, index_num_bits) | Rm(vm) | | |
3634 Rn(vn) | Rd(vd)); | |
3635 } | |
3636 | |
3637 void Assembler::NEONByElement(const VRegister& vd, const VRegister& vn, | |
3638 const VRegister& vm, int vm_index, | |
3639 NEONByIndexedElementOp vop) { | |
3640 DCHECK(AreSameFormat(vd, vn)); | |
3641 DCHECK((vd.Is4H() && vm.Is1H()) || (vd.Is8H() && vm.Is1H()) || | |
3642 (vd.Is1H() && vm.Is1H()) || (vd.Is2S() && vm.Is1S()) || | |
3643 (vd.Is4S() && vm.Is1S()) || (vd.Is1S() && vm.Is1S())); | |
3644 DCHECK((vm.Is1H() && (vm.code() < 16) && (vm_index < 8)) || | |
3645 (vm.Is1S() && (vm_index < 4))); | |
3646 | |
3647 Instr format, op = vop; | |
3648 int index_num_bits = vm.Is1H() ? 3 : 2; | |
3649 if (vd.IsScalar()) { | |
3650 op |= NEONScalar | NEON_Q; | |
3651 format = SFormat(vn); | |
3652 } else { | |
3653 format = VFormat(vn); | |
3654 } | |
3655 Emit(format | op | ImmNEONHLM(vm_index, index_num_bits) | Rm(vm) | Rn(vn) | | |
3656 Rd(vd)); | |
3657 } | |
3658 | |
3659 void Assembler::NEONByElementL(const VRegister& vd, const VRegister& vn, | |
3660 const VRegister& vm, int vm_index, | |
3661 NEONByIndexedElementOp vop) { | |
3662 DCHECK((vd.Is4S() && vn.Is4H() && vm.Is1H()) || | |
3663 (vd.Is4S() && vn.Is8H() && vm.Is1H()) || | |
3664 (vd.Is1S() && vn.Is1H() && vm.Is1H()) || | |
3665 (vd.Is2D() && vn.Is2S() && vm.Is1S()) || | |
3666 (vd.Is2D() && vn.Is4S() && vm.Is1S()) || | |
3667 (vd.Is1D() && vn.Is1S() && vm.Is1S())); | |
3668 | |
3669 DCHECK((vm.Is1H() && (vm.code() < 16) && (vm_index < 8)) || | |
3670 (vm.Is1S() && (vm_index < 4))); | |
3671 | |
3672 Instr format, op = vop; | |
3673 int index_num_bits = vm.Is1H() ? 3 : 2; | |
3674 if (vd.IsScalar()) { | |
3675 op |= NEONScalar | NEON_Q; | |
3676 format = SFormat(vn); | |
3677 } else { | |
3678 format = VFormat(vn); | |
3679 } | |
3680 Emit(format | op | ImmNEONHLM(vm_index, index_num_bits) | Rm(vm) | Rn(vn) | | |
3681 Rd(vd)); | |
3682 } | |
3683 | |
3684 #define NEON_BYELEMENT_LIST(V) \ | |
3685 V(mul, NEON_MUL_byelement, vn.IsVector()) \ | |
3686 V(mla, NEON_MLA_byelement, vn.IsVector()) \ | |
3687 V(mls, NEON_MLS_byelement, vn.IsVector()) \ | |
3688 V(sqdmulh, NEON_SQDMULH_byelement, true) \ | |
3689 V(sqrdmulh, NEON_SQRDMULH_byelement, true) | |
3690 | |
3691 #define DEFINE_ASM_FUNC(FN, OP, AS) \ | |
3692 void Assembler::FN(const VRegister& vd, const VRegister& vn, \ | |
3693 const VRegister& vm, int vm_index) { \ | |
3694 DCHECK(AS); \ | |
3695 NEONByElement(vd, vn, vm, vm_index, OP); \ | |
3696 } | |
3697 NEON_BYELEMENT_LIST(DEFINE_ASM_FUNC) | |
3698 #undef DEFINE_ASM_FUNC | |
3699 | |
3700 #define NEON_FPBYELEMENT_LIST(V) \ | |
3701 V(fmul, NEON_FMUL_byelement) \ | |
3702 V(fmla, NEON_FMLA_byelement) \ | |
3703 V(fmls, NEON_FMLS_byelement) \ | |
3704 V(fmulx, NEON_FMULX_byelement) | |
3705 | |
3706 #define DEFINE_ASM_FUNC(FN, OP) \ | |
3707 void Assembler::FN(const VRegister& vd, const VRegister& vn, \ | |
3708 const VRegister& vm, int vm_index) { \ | |
3709 NEONFPByElement(vd, vn, vm, vm_index, OP); \ | |
3710 } | |
3711 NEON_FPBYELEMENT_LIST(DEFINE_ASM_FUNC) | |
3712 #undef DEFINE_ASM_FUNC | |
3713 | |
3714 #define NEON_BYELEMENT_LONG_LIST(V) \ | |
3715 V(sqdmull, NEON_SQDMULL_byelement, vn.IsScalar() || vn.IsD()) \ | |
3716 V(sqdmull2, NEON_SQDMULL_byelement, vn.IsVector() && vn.IsQ()) \ | |
3717 V(sqdmlal, NEON_SQDMLAL_byelement, vn.IsScalar() || vn.IsD()) \ | |
3718 V(sqdmlal2, NEON_SQDMLAL_byelement, vn.IsVector() && vn.IsQ()) \ | |
3719 V(sqdmlsl, NEON_SQDMLSL_byelement, vn.IsScalar() || vn.IsD()) \ | |
3720 V(sqdmlsl2, NEON_SQDMLSL_byelement, vn.IsVector() && vn.IsQ()) \ | |
3721 V(smull, NEON_SMULL_byelement, vn.IsVector() && vn.IsD()) \ | |
3722 V(smull2, NEON_SMULL_byelement, vn.IsVector() && vn.IsQ()) \ | |
3723 V(umull, NEON_UMULL_byelement, vn.IsVector() && vn.IsD()) \ | |
3724 V(umull2, NEON_UMULL_byelement, vn.IsVector() && vn.IsQ()) \ | |
3725 V(smlal, NEON_SMLAL_byelement, vn.IsVector() && vn.IsD()) \ | |
3726 V(smlal2, NEON_SMLAL_byelement, vn.IsVector() && vn.IsQ()) \ | |
3727 V(umlal, NEON_UMLAL_byelement, vn.IsVector() && vn.IsD()) \ | |
3728 V(umlal2, NEON_UMLAL_byelement, vn.IsVector() && vn.IsQ()) \ | |
3729 V(smlsl, NEON_SMLSL_byelement, vn.IsVector() && vn.IsD()) \ | |
3730 V(smlsl2, NEON_SMLSL_byelement, vn.IsVector() && vn.IsQ()) \ | |
3731 V(umlsl, NEON_UMLSL_byelement, vn.IsVector() && vn.IsD()) \ | |
3732 V(umlsl2, NEON_UMLSL_byelement, vn.IsVector() && vn.IsQ()) | |
3733 | |
3734 #define DEFINE_ASM_FUNC(FN, OP, AS) \ | |
3735 void Assembler::FN(const VRegister& vd, const VRegister& vn, \ | |
3736 const VRegister& vm, int vm_index) { \ | |
3737 DCHECK(AS); \ | |
3738 NEONByElementL(vd, vn, vm, vm_index, OP); \ | |
3739 } | |
3740 NEON_BYELEMENT_LONG_LIST(DEFINE_ASM_FUNC) | |
3741 #undef DEFINE_ASM_FUNC | |
3742 | |
3743 void Assembler::suqadd(const VRegister& vd, const VRegister& vn) { | |
3744 NEON2RegMisc(vd, vn, NEON_SUQADD); | |
3745 } | |
3746 | |
3747 void Assembler::usqadd(const VRegister& vd, const VRegister& vn) { | |
3748 NEON2RegMisc(vd, vn, NEON_USQADD); | |
3749 } | |
3750 | |
3751 void Assembler::abs(const VRegister& vd, const VRegister& vn) { | |
3752 DCHECK(vd.IsVector() || vd.Is1D()); | |
3753 NEON2RegMisc(vd, vn, NEON_ABS); | |
3754 } | |
3755 | |
3756 void Assembler::sqabs(const VRegister& vd, const VRegister& vn) { | |
3757 NEON2RegMisc(vd, vn, NEON_SQABS); | |
3758 } | |
3759 | |
3760 void Assembler::neg(const VRegister& vd, const VRegister& vn) { | |
3761 DCHECK(vd.IsVector() || vd.Is1D()); | |
3762 NEON2RegMisc(vd, vn, NEON_NEG); | |
3763 } | |
3764 | |
3765 void Assembler::sqneg(const VRegister& vd, const VRegister& vn) { | |
3766 NEON2RegMisc(vd, vn, NEON_SQNEG); | |
3767 } | |
3768 | |
3769 void Assembler::NEONXtn(const VRegister& vd, const VRegister& vn, | |
3770 NEON2RegMiscOp vop) { | |
3771 Instr format, op = vop; | |
3772 if (vd.IsScalar()) { | |
3773 DCHECK((vd.Is1B() && vn.Is1H()) || (vd.Is1H() && vn.Is1S()) || | |
3774 (vd.Is1S() && vn.Is1D())); | |
3775 op |= NEON_Q | NEONScalar; | |
3776 format = SFormat(vd); | |
3777 } else { | |
3778 DCHECK((vd.Is8B() && vn.Is8H()) || (vd.Is4H() && vn.Is4S()) || | |
3779 (vd.Is2S() && vn.Is2D()) || (vd.Is16B() && vn.Is8H()) || | |
3780 (vd.Is8H() && vn.Is4S()) || (vd.Is4S() && vn.Is2D())); | |
3781 format = VFormat(vd); | |
3782 } | |
3783 Emit(format | op | Rn(vn) | Rd(vd)); | |
3784 } | |
3785 | |
3786 void Assembler::xtn(const VRegister& vd, const VRegister& vn) { | |
3787 DCHECK(vd.IsVector() && vd.IsD()); | |
3788 NEONXtn(vd, vn, NEON_XTN); | |
3789 } | |
3790 | |
3791 void Assembler::xtn2(const VRegister& vd, const VRegister& vn) { | |
3792 DCHECK(vd.IsVector() && vd.IsQ()); | |
3793 NEONXtn(vd, vn, NEON_XTN); | |
3794 } | |
3795 | |
3796 void Assembler::sqxtn(const VRegister& vd, const VRegister& vn) { | |
3797 DCHECK(vd.IsScalar() || vd.IsD()); | |
3798 NEONXtn(vd, vn, NEON_SQXTN); | |
3799 } | |
3800 | |
3801 void Assembler::sqxtn2(const VRegister& vd, const VRegister& vn) { | |
3802 DCHECK(vd.IsVector() && vd.IsQ()); | |
3803 NEONXtn(vd, vn, NEON_SQXTN); | |
3804 } | |
3805 | |
3806 void Assembler::sqxtun(const VRegister& vd, const VRegister& vn) { | |
3807 DCHECK(vd.IsScalar() || vd.IsD()); | |
3808 NEONXtn(vd, vn, NEON_SQXTUN); | |
3809 } | |
3810 | |
3811 void Assembler::sqxtun2(const VRegister& vd, const VRegister& vn) { | |
3812 DCHECK(vd.IsVector() && vd.IsQ()); | |
3813 NEONXtn(vd, vn, NEON_SQXTUN); | |
3814 } | |
3815 | |
3816 void Assembler::uqxtn(const VRegister& vd, const VRegister& vn) { | |
3817 DCHECK(vd.IsScalar() || vd.IsD()); | |
3818 NEONXtn(vd, vn, NEON_UQXTN); | |
3819 } | |
3820 | |
3821 void Assembler::uqxtn2(const VRegister& vd, const VRegister& vn) { | |
3822 DCHECK(vd.IsVector() && vd.IsQ()); | |
3823 NEONXtn(vd, vn, NEON_UQXTN); | |
3824 } | |
3825 | |
3826 // NEON NOT and RBIT are distinguised by bit 22, the bottom bit of "size". | |
3827 void Assembler::not_(const VRegister& vd, const VRegister& vn) { | |
3828 DCHECK(AreSameFormat(vd, vn)); | |
3829 DCHECK(vd.Is8B() || vd.Is16B()); | |
3830 Emit(VFormat(vd) | NEON_RBIT_NOT | Rn(vn) | Rd(vd)); | |
3831 } | |
3832 | |
3833 void Assembler::rbit(const VRegister& vd, const VRegister& vn) { | |
3834 DCHECK(AreSameFormat(vd, vn)); | |
3835 DCHECK(vd.Is8B() || vd.Is16B()); | |
3836 Emit(VFormat(vn) | (1 << NEONSize_offset) | NEON_RBIT_NOT | Rn(vn) | Rd(vd)); | |
3837 } | |
3838 | |
3839 void Assembler::ext(const VRegister& vd, const VRegister& vn, | |
3840 const VRegister& vm, int index) { | |
3841 DCHECK(AreSameFormat(vd, vn, vm)); | |
3842 DCHECK(vd.Is8B() || vd.Is16B()); | |
3843 DCHECK((0 <= index) && (index < vd.LaneCount())); | |
3844 Emit(VFormat(vd) | NEON_EXT | Rm(vm) | ImmNEONExt(index) | Rn(vn) | Rd(vd)); | |
3845 } | |
3846 | |
3847 void Assembler::dup(const VRegister& vd, const VRegister& vn, int vn_index) { | |
3848 Instr q, scalar; | |
3849 | |
3850 // We support vn arguments of the form vn.VxT() or vn.T(), where x is the | |
3851 // number of lanes, and T is b, h, s or d. | |
3852 int lane_size = vn.LaneSizeInBytes(); | |
3853 NEONFormatField format; | |
3854 switch (lane_size) { | |
3855 case 1: | |
3856 format = NEON_16B; | |
3857 break; | |
3858 case 2: | |
3859 format = NEON_8H; | |
3860 break; | |
3861 case 4: | |
3862 format = NEON_4S; | |
3863 break; | |
3864 default: | |
3865 DCHECK_EQ(lane_size, 8); | |
3866 format = NEON_2D; | |
3867 break; | |
3868 } | |
3869 | |
3870 if (vd.IsScalar()) { | |
3871 q = NEON_Q; | |
3872 scalar = NEONScalar; | |
3873 } else { | |
3874 DCHECK(!vd.Is1D()); | |
3875 q = vd.IsD() ? 0 : NEON_Q; | |
3876 scalar = 0; | |
3877 } | |
3878 Emit(q | scalar | NEON_DUP_ELEMENT | ImmNEON5(format, vn_index) | Rn(vn) | | |
3879 Rd(vd)); | |
3880 } | |
2117 | 3881 |
2118 void Assembler::dcptr(Label* label) { | 3882 void Assembler::dcptr(Label* label) { |
2119 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE); | 3883 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE); |
2120 if (label->is_bound()) { | 3884 if (label->is_bound()) { |
2121 // The label is bound, so it does not need to be updated and the internal | 3885 // The label is bound, so it does not need to be updated and the internal |
2122 // reference should be emitted. | 3886 // reference should be emitted. |
2123 // | 3887 // |
2124 // In this case, label->pos() returns the offset of the label from the | 3888 // In this case, label->pos() returns the offset of the label from the |
2125 // start of the buffer. | 3889 // start of the buffer. |
2126 internal_reference_positions_.push_back(pc_offset()); | 3890 internal_reference_positions_.push_back(pc_offset()); |
(...skipping 24 matching lines...) Expand all Loading... | |
2151 offset >>= kInstructionSizeLog2; | 3915 offset >>= kInstructionSizeLog2; |
2152 DCHECK(is_int32(offset)); | 3916 DCHECK(is_int32(offset)); |
2153 uint32_t high16 = unsigned_bitextract_32(31, 16, offset); | 3917 uint32_t high16 = unsigned_bitextract_32(31, 16, offset); |
2154 uint32_t low16 = unsigned_bitextract_32(15, 0, offset); | 3918 uint32_t low16 = unsigned_bitextract_32(15, 0, offset); |
2155 | 3919 |
2156 brk(high16); | 3920 brk(high16); |
2157 brk(low16); | 3921 brk(low16); |
2158 } | 3922 } |
2159 } | 3923 } |
2160 | 3924 |
2161 | |
2162 // Note: | |
2163 // Below, a difference in case for the same letter indicates a | 3925 // Below, a difference in case for the same letter indicates a |
2164 // negated bit. | 3926 // negated bit. If b is 1, then B is 0. |
2165 // If b is 1, then B is 0. | 3927 uint32_t Assembler::FPToImm8(double imm) { |
2166 Instr Assembler::ImmFP32(float imm) { | |
2167 DCHECK(IsImmFP32(imm)); | |
2168 // bits: aBbb.bbbc.defg.h000.0000.0000.0000.0000 | |
2169 uint32_t bits = float_to_rawbits(imm); | |
2170 // bit7: a000.0000 | |
2171 uint32_t bit7 = ((bits >> 31) & 0x1) << 7; | |
2172 // bit6: 0b00.0000 | |
2173 uint32_t bit6 = ((bits >> 29) & 0x1) << 6; | |
2174 // bit5_to_0: 00cd.efgh | |
2175 uint32_t bit5_to_0 = (bits >> 19) & 0x3f; | |
2176 | |
2177 return (bit7 | bit6 | bit5_to_0) << ImmFP_offset; | |
2178 } | |
2179 | |
2180 | |
2181 Instr Assembler::ImmFP64(double imm) { | |
2182 DCHECK(IsImmFP64(imm)); | 3928 DCHECK(IsImmFP64(imm)); |
2183 // bits: aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000 | 3929 // bits: aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000 |
2184 // 0000.0000.0000.0000.0000.0000.0000.0000 | 3930 // 0000.0000.0000.0000.0000.0000.0000.0000 |
2185 uint64_t bits = double_to_rawbits(imm); | 3931 uint64_t bits = bit_cast<uint64_t>(imm); |
2186 // bit7: a000.0000 | 3932 // bit7: a000.0000 |
2187 uint64_t bit7 = ((bits >> 63) & 0x1) << 7; | 3933 uint64_t bit7 = ((bits >> 63) & 0x1) << 7; |
2188 // bit6: 0b00.0000 | 3934 // bit6: 0b00.0000 |
2189 uint64_t bit6 = ((bits >> 61) & 0x1) << 6; | 3935 uint64_t bit6 = ((bits >> 61) & 0x1) << 6; |
2190 // bit5_to_0: 00cd.efgh | 3936 // bit5_to_0: 00cd.efgh |
2191 uint64_t bit5_to_0 = (bits >> 48) & 0x3f; | 3937 uint64_t bit5_to_0 = (bits >> 48) & 0x3f; |
2192 | 3938 |
2193 return static_cast<Instr>((bit7 | bit6 | bit5_to_0) << ImmFP_offset); | 3939 return static_cast<uint32_t>(bit7 | bit6 | bit5_to_0); |
2194 } | 3940 } |
2195 | 3941 |
3942 Instr Assembler::ImmFP(double imm) { return FPToImm8(imm) << ImmFP_offset; } | |
3943 Instr Assembler::ImmNEONFP(double imm) { | |
3944 return ImmNEONabcdefgh(FPToImm8(imm)); | |
3945 } | |
2196 | 3946 |
2197 // Code generation helpers. | 3947 // Code generation helpers. |
2198 void Assembler::MoveWide(const Register& rd, | 3948 void Assembler::MoveWide(const Register& rd, uint64_t imm, int shift, |
2199 uint64_t imm, | |
2200 int shift, | |
2201 MoveWideImmediateOp mov_op) { | 3949 MoveWideImmediateOp mov_op) { |
2202 // Ignore the top 32 bits of an immediate if we're moving to a W register. | 3950 // Ignore the top 32 bits of an immediate if we're moving to a W register. |
2203 if (rd.Is32Bits()) { | 3951 if (rd.Is32Bits()) { |
2204 // Check that the top 32 bits are zero (a positive 32-bit number) or top | 3952 // Check that the top 32 bits are zero (a positive 32-bit number) or top |
2205 // 33 bits are one (a negative 32-bit number, sign extended to 64 bits). | 3953 // 33 bits are one (a negative 32-bit number, sign extended to 64 bits). |
2206 DCHECK(((imm >> kWRegSizeInBits) == 0) || | 3954 DCHECK(((imm >> kWRegSizeInBits) == 0) || |
2207 ((imm >> (kWRegSizeInBits - 1)) == 0x1ffffffff)); | 3955 ((imm >> (kWRegSizeInBits - 1)) == 0x1ffffffff)); |
2208 imm &= kWRegMask; | 3956 imm &= kWRegMask; |
2209 } | 3957 } |
2210 | 3958 |
(...skipping 21 matching lines...) Expand all Loading... | |
2232 shift = 3; | 3980 shift = 3; |
2233 } | 3981 } |
2234 } | 3982 } |
2235 | 3983 |
2236 DCHECK(is_uint16(imm)); | 3984 DCHECK(is_uint16(imm)); |
2237 | 3985 |
2238 Emit(SF(rd) | MoveWideImmediateFixed | mov_op | Rd(rd) | | 3986 Emit(SF(rd) | MoveWideImmediateFixed | mov_op | Rd(rd) | |
2239 ImmMoveWide(static_cast<int>(imm)) | ShiftMoveWide(shift)); | 3987 ImmMoveWide(static_cast<int>(imm)) | ShiftMoveWide(shift)); |
2240 } | 3988 } |
2241 | 3989 |
2242 | 3990 void Assembler::AddSub(const Register& rd, const Register& rn, |
2243 void Assembler::AddSub(const Register& rd, | 3991 const Operand& operand, FlagsUpdate S, AddSubOp op) { |
2244 const Register& rn, | 3992 DCHECK_EQ(rd.SizeInBits(), rn.SizeInBits()); |
2245 const Operand& operand, | |
2246 FlagsUpdate S, | |
2247 AddSubOp op) { | |
2248 DCHECK(rd.SizeInBits() == rn.SizeInBits()); | |
2249 DCHECK(!operand.NeedsRelocation(this)); | 3993 DCHECK(!operand.NeedsRelocation(this)); |
2250 if (operand.IsImmediate()) { | 3994 if (operand.IsImmediate()) { |
2251 int64_t immediate = operand.ImmediateValue(); | 3995 int64_t immediate = operand.ImmediateValue(); |
2252 DCHECK(IsImmAddSub(immediate)); | 3996 DCHECK(IsImmAddSub(immediate)); |
2253 Instr dest_reg = (S == SetFlags) ? Rd(rd) : RdSP(rd); | 3997 Instr dest_reg = (S == SetFlags) ? Rd(rd) : RdSP(rd); |
2254 Emit(SF(rd) | AddSubImmediateFixed | op | Flags(S) | | 3998 Emit(SF(rd) | AddSubImmediateFixed | op | Flags(S) | |
2255 ImmAddSub(static_cast<int>(immediate)) | dest_reg | RnSP(rn)); | 3999 ImmAddSub(static_cast<int>(immediate)) | dest_reg | RnSP(rn)); |
2256 } else if (operand.IsShiftedRegister()) { | 4000 } else if (operand.IsShiftedRegister()) { |
2257 DCHECK(operand.reg().SizeInBits() == rd.SizeInBits()); | 4001 DCHECK_EQ(operand.reg().SizeInBits(), rd.SizeInBits()); |
2258 DCHECK(operand.shift() != ROR); | 4002 DCHECK_NE(operand.shift(), ROR); |
2259 | 4003 |
2260 // For instructions of the form: | 4004 // For instructions of the form: |
2261 // add/sub wsp, <Wn>, <Wm> [, LSL #0-3 ] | 4005 // add/sub wsp, <Wn>, <Wm> [, LSL #0-3 ] |
2262 // add/sub <Wd>, wsp, <Wm> [, LSL #0-3 ] | 4006 // add/sub <Wd>, wsp, <Wm> [, LSL #0-3 ] |
2263 // add/sub wsp, wsp, <Wm> [, LSL #0-3 ] | 4007 // add/sub wsp, wsp, <Wm> [, LSL #0-3 ] |
2264 // adds/subs <Wd>, wsp, <Wm> [, LSL #0-3 ] | 4008 // adds/subs <Wd>, wsp, <Wm> [, LSL #0-3 ] |
2265 // or their 64-bit register equivalents, convert the operand from shifted to | 4009 // or their 64-bit register equivalents, convert the operand from shifted to |
2266 // extended register mode, and emit an add/sub extended instruction. | 4010 // extended register mode, and emit an add/sub extended instruction. |
2267 if (rn.IsSP() || rd.IsSP()) { | 4011 if (rn.IsSP() || rd.IsSP()) { |
2268 DCHECK(!(rd.IsSP() && (S == SetFlags))); | 4012 DCHECK(!(rd.IsSP() && (S == SetFlags))); |
2269 DataProcExtendedRegister(rd, rn, operand.ToExtendedRegister(), S, | 4013 DataProcExtendedRegister(rd, rn, operand.ToExtendedRegister(), S, |
2270 AddSubExtendedFixed | op); | 4014 AddSubExtendedFixed | op); |
2271 } else { | 4015 } else { |
2272 DataProcShiftedRegister(rd, rn, operand, S, AddSubShiftedFixed | op); | 4016 DataProcShiftedRegister(rd, rn, operand, S, AddSubShiftedFixed | op); |
2273 } | 4017 } |
2274 } else { | 4018 } else { |
2275 DCHECK(operand.IsExtendedRegister()); | 4019 DCHECK(operand.IsExtendedRegister()); |
2276 DataProcExtendedRegister(rd, rn, operand, S, AddSubExtendedFixed | op); | 4020 DataProcExtendedRegister(rd, rn, operand, S, AddSubExtendedFixed | op); |
2277 } | 4021 } |
2278 } | 4022 } |
2279 | 4023 |
2280 | 4024 void Assembler::AddSubWithCarry(const Register& rd, const Register& rn, |
2281 void Assembler::AddSubWithCarry(const Register& rd, | 4025 const Operand& operand, FlagsUpdate S, |
2282 const Register& rn, | |
2283 const Operand& operand, | |
2284 FlagsUpdate S, | |
2285 AddSubWithCarryOp op) { | 4026 AddSubWithCarryOp op) { |
2286 DCHECK(rd.SizeInBits() == rn.SizeInBits()); | 4027 DCHECK_EQ(rd.SizeInBits(), rn.SizeInBits()); |
2287 DCHECK(rd.SizeInBits() == operand.reg().SizeInBits()); | 4028 DCHECK_EQ(rd.SizeInBits(), operand.reg().SizeInBits()); |
2288 DCHECK(operand.IsShiftedRegister() && (operand.shift_amount() == 0)); | 4029 DCHECK(operand.IsShiftedRegister() && (operand.shift_amount() == 0)); |
2289 DCHECK(!operand.NeedsRelocation(this)); | 4030 DCHECK(!operand.NeedsRelocation(this)); |
2290 Emit(SF(rd) | op | Flags(S) | Rm(operand.reg()) | Rn(rn) | Rd(rd)); | 4031 Emit(SF(rd) | op | Flags(S) | Rm(operand.reg()) | Rn(rn) | Rd(rd)); |
2291 } | 4032 } |
2292 | 4033 |
2293 | |
2294 void Assembler::hlt(int code) { | 4034 void Assembler::hlt(int code) { |
2295 DCHECK(is_uint16(code)); | 4035 DCHECK(is_uint16(code)); |
2296 Emit(HLT | ImmException(code)); | 4036 Emit(HLT | ImmException(code)); |
2297 } | 4037 } |
2298 | 4038 |
2299 | |
2300 void Assembler::brk(int code) { | 4039 void Assembler::brk(int code) { |
2301 DCHECK(is_uint16(code)); | 4040 DCHECK(is_uint16(code)); |
2302 Emit(BRK | ImmException(code)); | 4041 Emit(BRK | ImmException(code)); |
2303 } | 4042 } |
2304 | 4043 |
2305 | |
2306 void Assembler::EmitStringData(const char* string) { | 4044 void Assembler::EmitStringData(const char* string) { |
2307 size_t len = strlen(string) + 1; | 4045 size_t len = strlen(string) + 1; |
2308 DCHECK(RoundUp(len, kInstructionSize) <= static_cast<size_t>(kGap)); | 4046 DCHECK_LE(RoundUp(len, kInstructionSize), static_cast<size_t>(kGap)); |
2309 EmitData(string, static_cast<int>(len)); | 4047 EmitData(string, static_cast<int>(len)); |
2310 // Pad with NULL characters until pc_ is aligned. | 4048 // Pad with NULL characters until pc_ is aligned. |
2311 const char pad[] = {'\0', '\0', '\0', '\0'}; | 4049 const char pad[] = {'\0', '\0', '\0', '\0'}; |
2312 STATIC_ASSERT(sizeof(pad) == kInstructionSize); | 4050 static_assert(sizeof(pad) == kInstructionSize, |
4051 "Size of padding must match instruction size."); | |
2313 EmitData(pad, RoundUp(pc_offset(), kInstructionSize) - pc_offset()); | 4052 EmitData(pad, RoundUp(pc_offset(), kInstructionSize) - pc_offset()); |
2314 } | 4053 } |
2315 | 4054 |
2316 | 4055 |
2317 void Assembler::debug(const char* message, uint32_t code, Instr params) { | 4056 void Assembler::debug(const char* message, uint32_t code, Instr params) { |
2318 #ifdef USE_SIMULATOR | 4057 #ifdef USE_SIMULATOR |
2319 // Don't generate simulator specific code if we are building a snapshot, which | 4058 // Don't generate simulator specific code if we are building a snapshot, which |
2320 // might be run on real hardware. | 4059 // might be run on real hardware. |
2321 if (!serializer_enabled()) { | 4060 if (!serializer_enabled()) { |
2322 // The arguments to the debug marker need to be contiguous in memory, so | 4061 // The arguments to the debug marker need to be contiguous in memory, so |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2419 } | 4158 } |
2420 | 4159 |
2421 | 4160 |
2422 void Assembler::DataProcessing1Source(const Register& rd, | 4161 void Assembler::DataProcessing1Source(const Register& rd, |
2423 const Register& rn, | 4162 const Register& rn, |
2424 DataProcessing1SourceOp op) { | 4163 DataProcessing1SourceOp op) { |
2425 DCHECK(rd.SizeInBits() == rn.SizeInBits()); | 4164 DCHECK(rd.SizeInBits() == rn.SizeInBits()); |
2426 Emit(SF(rn) | op | Rn(rn) | Rd(rd)); | 4165 Emit(SF(rn) | op | Rn(rn) | Rd(rd)); |
2427 } | 4166 } |
2428 | 4167 |
2429 | 4168 void Assembler::FPDataProcessing1Source(const VRegister& vd, |
2430 void Assembler::FPDataProcessing1Source(const FPRegister& fd, | 4169 const VRegister& vn, |
2431 const FPRegister& fn, | |
2432 FPDataProcessing1SourceOp op) { | 4170 FPDataProcessing1SourceOp op) { |
2433 Emit(FPType(fn) | op | Rn(fn) | Rd(fd)); | 4171 Emit(FPType(vn) | op | Rn(vn) | Rd(vd)); |
2434 } | 4172 } |
2435 | 4173 |
2436 | 4174 void Assembler::FPDataProcessing2Source(const VRegister& fd, |
2437 void Assembler::FPDataProcessing2Source(const FPRegister& fd, | 4175 const VRegister& fn, |
2438 const FPRegister& fn, | 4176 const VRegister& fm, |
2439 const FPRegister& fm, | |
2440 FPDataProcessing2SourceOp op) { | 4177 FPDataProcessing2SourceOp op) { |
2441 DCHECK(fd.SizeInBits() == fn.SizeInBits()); | 4178 DCHECK(fd.SizeInBits() == fn.SizeInBits()); |
2442 DCHECK(fd.SizeInBits() == fm.SizeInBits()); | 4179 DCHECK(fd.SizeInBits() == fm.SizeInBits()); |
2443 Emit(FPType(fd) | op | Rm(fm) | Rn(fn) | Rd(fd)); | 4180 Emit(FPType(fd) | op | Rm(fm) | Rn(fn) | Rd(fd)); |
2444 } | 4181 } |
2445 | 4182 |
2446 | 4183 void Assembler::FPDataProcessing3Source(const VRegister& fd, |
2447 void Assembler::FPDataProcessing3Source(const FPRegister& fd, | 4184 const VRegister& fn, |
2448 const FPRegister& fn, | 4185 const VRegister& fm, |
2449 const FPRegister& fm, | 4186 const VRegister& fa, |
2450 const FPRegister& fa, | |
2451 FPDataProcessing3SourceOp op) { | 4187 FPDataProcessing3SourceOp op) { |
2452 DCHECK(AreSameSizeAndType(fd, fn, fm, fa)); | 4188 DCHECK(AreSameSizeAndType(fd, fn, fm, fa)); |
2453 Emit(FPType(fd) | op | Rm(fm) | Rn(fn) | Rd(fd) | Ra(fa)); | 4189 Emit(FPType(fd) | op | Rm(fm) | Rn(fn) | Rd(fd) | Ra(fa)); |
2454 } | 4190 } |
2455 | 4191 |
4192 void Assembler::NEONModifiedImmShiftLsl(const VRegister& vd, const int imm8, | |
4193 const int left_shift, | |
4194 NEONModifiedImmediateOp op) { | |
4195 DCHECK(vd.Is8B() || vd.Is16B() || vd.Is4H() || vd.Is8H() || vd.Is2S() || | |
4196 vd.Is4S()); | |
4197 DCHECK((left_shift == 0) || (left_shift == 8) || (left_shift == 16) || | |
4198 (left_shift == 24)); | |
4199 DCHECK(is_uint8(imm8)); | |
4200 | |
4201 int cmode_1, cmode_2, cmode_3; | |
4202 if (vd.Is8B() || vd.Is16B()) { | |
4203 DCHECK_EQ(op, NEONModifiedImmediate_MOVI); | |
4204 cmode_1 = 1; | |
4205 cmode_2 = 1; | |
4206 cmode_3 = 1; | |
4207 } else { | |
4208 cmode_1 = (left_shift >> 3) & 1; | |
4209 cmode_2 = left_shift >> 4; | |
4210 cmode_3 = 0; | |
4211 if (vd.Is4H() || vd.Is8H()) { | |
4212 DCHECK((left_shift == 0) || (left_shift == 8)); | |
4213 cmode_3 = 1; | |
4214 } | |
4215 } | |
4216 int cmode = (cmode_3 << 3) | (cmode_2 << 2) | (cmode_1 << 1); | |
4217 | |
4218 Instr q = vd.IsQ() ? NEON_Q : 0; | |
4219 | |
4220 Emit(q | op | ImmNEONabcdefgh(imm8) | NEONCmode(cmode) | Rd(vd)); | |
4221 } | |
4222 | |
4223 void Assembler::NEONModifiedImmShiftMsl(const VRegister& vd, const int imm8, | |
4224 const int shift_amount, | |
4225 NEONModifiedImmediateOp op) { | |
4226 DCHECK(vd.Is2S() || vd.Is4S()); | |
4227 DCHECK((shift_amount == 8) || (shift_amount == 16)); | |
4228 DCHECK(is_uint8(imm8)); | |
4229 | |
4230 int cmode_0 = (shift_amount >> 4) & 1; | |
4231 int cmode = 0xc | cmode_0; | |
4232 | |
4233 Instr q = vd.IsQ() ? NEON_Q : 0; | |
4234 | |
4235 Emit(q | op | ImmNEONabcdefgh(imm8) | NEONCmode(cmode) | Rd(vd)); | |
4236 } | |
2456 | 4237 |
2457 void Assembler::EmitShift(const Register& rd, | 4238 void Assembler::EmitShift(const Register& rd, |
2458 const Register& rn, | 4239 const Register& rn, |
2459 Shift shift, | 4240 Shift shift, |
2460 unsigned shift_amount) { | 4241 unsigned shift_amount) { |
2461 switch (shift) { | 4242 switch (shift) { |
2462 case LSL: | 4243 case LSL: |
2463 lsl(rd, rn, shift_amount); | 4244 lsl(rd, rn, shift_amount); |
2464 break; | 4245 break; |
2465 case LSR: | 4246 case LSR: |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2545 return is_uint12(immediate) || | 4326 return is_uint12(immediate) || |
2546 (is_uint12(immediate >> 12) && ((immediate & 0xfff) == 0)); | 4327 (is_uint12(immediate >> 12) && ((immediate & 0xfff) == 0)); |
2547 } | 4328 } |
2548 | 4329 |
2549 void Assembler::LoadStore(const CPURegister& rt, | 4330 void Assembler::LoadStore(const CPURegister& rt, |
2550 const MemOperand& addr, | 4331 const MemOperand& addr, |
2551 LoadStoreOp op) { | 4332 LoadStoreOp op) { |
2552 Instr memop = op | Rt(rt) | RnSP(addr.base()); | 4333 Instr memop = op | Rt(rt) | RnSP(addr.base()); |
2553 | 4334 |
2554 if (addr.IsImmediateOffset()) { | 4335 if (addr.IsImmediateOffset()) { |
2555 LSDataSize size = CalcLSDataSize(op); | 4336 unsigned size = CalcLSDataSize(op); |
2556 if (IsImmLSScaled(addr.offset(), size)) { | 4337 if (IsImmLSScaled(addr.offset(), size)) { |
2557 int offset = static_cast<int>(addr.offset()); | 4338 int offset = static_cast<int>(addr.offset()); |
2558 // Use the scaled addressing mode. | 4339 // Use the scaled addressing mode. |
2559 Emit(LoadStoreUnsignedOffsetFixed | memop | | 4340 Emit(LoadStoreUnsignedOffsetFixed | memop | |
2560 ImmLSUnsigned(offset >> size)); | 4341 ImmLSUnsigned(offset >> size)); |
2561 } else if (IsImmLSUnscaled(addr.offset())) { | 4342 } else if (IsImmLSUnscaled(addr.offset())) { |
2562 int offset = static_cast<int>(addr.offset()); | 4343 int offset = static_cast<int>(addr.offset()); |
2563 // Use the unscaled addressing mode. | 4344 // Use the unscaled addressing mode. |
2564 Emit(LoadStoreUnscaledOffsetFixed | memop | ImmLS(offset)); | 4345 Emit(LoadStoreUnscaledOffsetFixed | memop | ImmLS(offset)); |
2565 } else { | 4346 } else { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2598 UNREACHABLE(); | 4379 UNREACHABLE(); |
2599 } | 4380 } |
2600 } | 4381 } |
2601 } | 4382 } |
2602 | 4383 |
2603 | 4384 |
2604 bool Assembler::IsImmLSUnscaled(int64_t offset) { | 4385 bool Assembler::IsImmLSUnscaled(int64_t offset) { |
2605 return is_int9(offset); | 4386 return is_int9(offset); |
2606 } | 4387 } |
2607 | 4388 |
2608 | 4389 bool Assembler::IsImmLSScaled(int64_t offset, unsigned size) { |
2609 bool Assembler::IsImmLSScaled(int64_t offset, LSDataSize size) { | |
2610 bool offset_is_size_multiple = (((offset >> size) << size) == offset); | 4390 bool offset_is_size_multiple = (((offset >> size) << size) == offset); |
2611 return offset_is_size_multiple && is_uint12(offset >> size); | 4391 return offset_is_size_multiple && is_uint12(offset >> size); |
2612 } | 4392 } |
2613 | 4393 |
2614 | 4394 bool Assembler::IsImmLSPair(int64_t offset, unsigned size) { |
2615 bool Assembler::IsImmLSPair(int64_t offset, LSDataSize size) { | |
2616 bool offset_is_size_multiple = (((offset >> size) << size) == offset); | 4395 bool offset_is_size_multiple = (((offset >> size) << size) == offset); |
2617 return offset_is_size_multiple && is_int7(offset >> size); | 4396 return offset_is_size_multiple && is_int7(offset >> size); |
2618 } | 4397 } |
2619 | 4398 |
2620 | 4399 |
2621 bool Assembler::IsImmLLiteral(int64_t offset) { | 4400 bool Assembler::IsImmLLiteral(int64_t offset) { |
2622 int inst_size = static_cast<int>(kInstructionSizeLog2); | 4401 int inst_size = static_cast<int>(kInstructionSizeLog2); |
2623 bool offset_is_inst_multiple = | 4402 bool offset_is_inst_multiple = |
2624 (((offset >> inst_size) << inst_size) == offset); | 4403 (((offset >> inst_size) << inst_size) == offset); |
2625 return offset_is_inst_multiple && is_intn(offset, ImmLLiteral_width); | 4404 return offset_is_inst_multiple && is_intn(offset, ImmLLiteral_width); |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2836 | 4615 |
2837 | 4616 |
2838 bool Assembler::IsImmConditionalCompare(int64_t immediate) { | 4617 bool Assembler::IsImmConditionalCompare(int64_t immediate) { |
2839 return is_uint5(immediate); | 4618 return is_uint5(immediate); |
2840 } | 4619 } |
2841 | 4620 |
2842 | 4621 |
2843 bool Assembler::IsImmFP32(float imm) { | 4622 bool Assembler::IsImmFP32(float imm) { |
2844 // Valid values will have the form: | 4623 // Valid values will have the form: |
2845 // aBbb.bbbc.defg.h000.0000.0000.0000.0000 | 4624 // aBbb.bbbc.defg.h000.0000.0000.0000.0000 |
2846 uint32_t bits = float_to_rawbits(imm); | 4625 uint32_t bits = bit_cast<uint32_t>(imm); |
2847 // bits[19..0] are cleared. | 4626 // bits[19..0] are cleared. |
2848 if ((bits & 0x7ffff) != 0) { | 4627 if ((bits & 0x7ffff) != 0) { |
2849 return false; | 4628 return false; |
2850 } | 4629 } |
2851 | 4630 |
2852 // bits[29..25] are all set or all cleared. | 4631 // bits[29..25] are all set or all cleared. |
2853 uint32_t b_pattern = (bits >> 16) & 0x3e00; | 4632 uint32_t b_pattern = (bits >> 16) & 0x3e00; |
2854 if (b_pattern != 0 && b_pattern != 0x3e00) { | 4633 if (b_pattern != 0 && b_pattern != 0x3e00) { |
2855 return false; | 4634 return false; |
2856 } | 4635 } |
2857 | 4636 |
2858 // bit[30] and bit[29] are opposite. | 4637 // bit[30] and bit[29] are opposite. |
2859 if (((bits ^ (bits << 1)) & 0x40000000) == 0) { | 4638 if (((bits ^ (bits << 1)) & 0x40000000) == 0) { |
2860 return false; | 4639 return false; |
2861 } | 4640 } |
2862 | 4641 |
2863 return true; | 4642 return true; |
2864 } | 4643 } |
2865 | 4644 |
2866 | 4645 |
2867 bool Assembler::IsImmFP64(double imm) { | 4646 bool Assembler::IsImmFP64(double imm) { |
2868 // Valid values will have the form: | 4647 // Valid values will have the form: |
2869 // aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000 | 4648 // aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000 |
2870 // 0000.0000.0000.0000.0000.0000.0000.0000 | 4649 // 0000.0000.0000.0000.0000.0000.0000.0000 |
2871 uint64_t bits = double_to_rawbits(imm); | 4650 uint64_t bits = bit_cast<uint64_t>(imm); |
2872 // bits[47..0] are cleared. | 4651 // bits[47..0] are cleared. |
2873 if ((bits & 0xffffffffffffL) != 0) { | 4652 if ((bits & 0xffffffffffffL) != 0) { |
2874 return false; | 4653 return false; |
2875 } | 4654 } |
2876 | 4655 |
2877 // bits[61..54] are all set or all cleared. | 4656 // bits[61..54] are all set or all cleared. |
2878 uint32_t b_pattern = (bits >> 48) & 0x3fc0; | 4657 uint32_t b_pattern = (bits >> 48) & 0x3fc0; |
2879 if (b_pattern != 0 && b_pattern != 0x3fc0) { | 4658 if (b_pattern != 0 && b_pattern != 0x3fc0) { |
2880 return false; | 4659 return false; |
2881 } | 4660 } |
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3212 movk(scratch, (target_offset >> 32) & 0xFFFF, 32); | 4991 movk(scratch, (target_offset >> 32) & 0xFFFF, 32); |
3213 DCHECK((target_offset >> 48) == 0); | 4992 DCHECK((target_offset >> 48) == 0); |
3214 add(rd, rd, scratch); | 4993 add(rd, rd, scratch); |
3215 } | 4994 } |
3216 | 4995 |
3217 | 4996 |
3218 } // namespace internal | 4997 } // namespace internal |
3219 } // namespace v8 | 4998 } // namespace v8 |
3220 | 4999 |
3221 #endif // V8_TARGET_ARCH_ARM64 | 5000 #endif // V8_TARGET_ARCH_ARM64 |
OLD | NEW |