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