1313 INSN(ldr, 0b01, 0);
1314 INSN(ldrsw, 0b10, 0);
1315
1316 #undef INSN
1317
1318 #define INSN(NAME, opc, V) \
1319 void NAME(FloatRegister Rt, address dest) { \
1320 long offset = (dest - pc()) >> 2; \
1321 starti; \
1322 f(opc, 31, 30), f(0b011, 29, 27), f(V, 26), f(0b00, 25, 24), \
1323 sf(offset, 23, 5); \
1324 rf((Register)Rt, 0); \
1325 }
1326
1327 INSN(ldrs, 0b00, 1);
1328 INSN(ldrd, 0b01, 1);
1329 INSN(ldrq, 0b10, 1);
1330
1331 #undef INSN
1332
1333 #define INSN(NAME, opc, V) \
1334 void NAME(address dest, prfop op = PLDL1KEEP) { \
1335 long offset = (dest - pc()) >> 2; \
1336 starti; \
1337 f(opc, 31, 30), f(0b011, 29, 27), f(V, 26), f(0b00, 25, 24), \
1338 sf(offset, 23, 5); \
1339 f(op, 4, 0); \
1340 } \
1341 void NAME(Label &L, prfop op = PLDL1KEEP) { \
1342 wrap_label(L, op, &Assembler::NAME); \
1343 }
1344
1345 INSN(prfm, 0b11, 0);
1346
1347 #undef INSN
1348
1349 // Load/store
1350 void ld_st1(int opc, int p1, int V, int L,
1351 Register Rt1, Register Rt2, Address adr, bool no_allocate) {
1352 starti;
1450 INSN(prfm, 0b11, 0b10); // FIXME: PRFM should not be used with
1451 // writeback modes, but the assembler
1452 // doesn't enfore that.
1453
1454 #undef INSN
1455
1456 #define INSN(NAME, size, op) \
1457 void NAME(FloatRegister Rt, const Address &adr) { \
1458 ld_st2((Register)Rt, adr, size, op, 1); \
1459 }
1460
1461 INSN(strd, 0b11, 0b00);
1462 INSN(strs, 0b10, 0b00);
1463 INSN(ldrd, 0b11, 0b01);
1464 INSN(ldrs, 0b10, 0b01);
1465 INSN(strq, 0b00, 0b10);
1466 INSN(ldrq, 0x00, 0b11);
1467
1468 #undef INSN
1469
1470 enum shift_kind { LSL, LSR, ASR, ROR };
1471
1472 void op_shifted_reg(unsigned decode,
1473 enum shift_kind kind, unsigned shift,
1474 unsigned size, unsigned op) {
1475 f(size, 31);
1476 f(op, 30, 29);
1477 f(decode, 28, 24);
1478 f(shift, 15, 10);
1479 f(kind, 23, 22);
1480 }
1481
1482 // Logical (shifted register)
1483 #define INSN(NAME, size, op, N) \
1484 void NAME(Register Rd, Register Rn, Register Rm, \
1485 enum shift_kind kind = LSL, unsigned shift = 0) { \
1486 starti; \
1487 guarantee(size == 1 || shift < 32, "incorrect shift"); \
1488 f(N, 21); \
1489 zrf(Rm, 16), zrf(Rn, 5), zrf(Rd, 0); \
1824 INSN(fcvts, 0b000, 0b00, 0b000101); // Single-precision to double-precision
1825
1826 private:
1827 INSN(i_fmovd, 0b000, 0b01, 0b000000);
1828 public:
1829 INSN(fabsd, 0b000, 0b01, 0b000001);
1830 INSN(fnegd, 0b000, 0b01, 0b000010);
1831 INSN(fsqrtd, 0b000, 0b01, 0b000011);
1832 INSN(fcvtd, 0b000, 0b01, 0b000100); // Double-precision to single-precision
1833
1834 void fmovd(FloatRegister Vd, FloatRegister Vn) {
1835 assert(Vd != Vn, "should be");
1836 i_fmovd(Vd, Vn);
1837 }
1838
1839 void fmovs(FloatRegister Vd, FloatRegister Vn) {
1840 assert(Vd != Vn, "should be");
1841 i_fmovs(Vd, Vn);
1842 }
1843
1844 #undef INSN
1845
1846 // Floating-point data-processing (2 source)
1847 void data_processing(unsigned op31, unsigned type, unsigned opcode,
1848 FloatRegister Vd, FloatRegister Vn, FloatRegister Vm) {
1849 starti;
1850 f(op31, 31, 29);
1851 f(0b11110, 28, 24);
1852 f(type, 23, 22), f(1, 21), f(opcode, 15, 12), f(0b10, 11, 10);
1853 rf(Vm, 16), rf(Vn, 5), rf(Vd, 0);
1854 }
1855
1856 #define INSN(NAME, op31, type, opcode) \
1857 void NAME(FloatRegister Vd, FloatRegister Vn, FloatRegister Vm) { \
1858 data_processing(op31, type, opcode, Vd, Vn, Vm); \
1859 }
1860
1861 INSN(fmuls, 0b000, 0b00, 0b0000);
1862 INSN(fdivs, 0b000, 0b00, 0b0001);
1863 INSN(fadds, 0b000, 0b00, 0b0010);
1960
1961 #undef INSN
1962
1963 #define INSN(NAME, op31, type, rmode, opcode) \
1964 void NAME(FloatRegister Vd, Register Rn) { \
1965 float_int_convert(op31, type, rmode, opcode, (Register)Vd, Rn); \
1966 }
1967
1968 INSN(fmovs, 0b000, 0b00, 0b00, 0b111);
1969 INSN(fmovd, 0b100, 0b01, 0b00, 0b111);
1970
1971 INSN(scvtfws, 0b000, 0b00, 0b00, 0b010);
1972 INSN(scvtfs, 0b100, 0b00, 0b00, 0b010);
1973 INSN(scvtfwd, 0b000, 0b01, 0b00, 0b010);
1974 INSN(scvtfd, 0b100, 0b01, 0b00, 0b010);
1975
1976 // INSN(fmovhid, 0b100, 0b10, 0b01, 0b111);
1977
1978 #undef INSN
1979
1980 // Floating-point compare
1981 void float_compare(unsigned op31, unsigned type,
1982 unsigned op, unsigned op2,
1983 FloatRegister Vn, FloatRegister Vm = (FloatRegister)0) {
1984 starti;
1985 f(op31, 31, 29);
1986 f(0b11110, 28, 24);
1987 f(type, 23, 22), f(1, 21);
1988 f(op, 15, 14), f(0b1000, 13, 10), f(op2, 4, 0);
1989 rf(Vn, 5), rf(Vm, 16);
1990 }
1991
1992
1993 #define INSN(NAME, op31, type, op, op2) \
1994 void NAME(FloatRegister Vn, FloatRegister Vm) { \
1995 float_compare(op31, type, op, op2, Vn, Vm); \
1996 }
1997
1998 #define INSN1(NAME, op31, type, op, op2) \
1999 void NAME(FloatRegister Vn, double d) { \
2074 INSN(frintxh, 0b11, 0b110);
2075 INSN(frintzh, 0b11, 0b011);
2076
2077 INSN(frintas, 0b00, 0b100);
2078 INSN(frintis, 0b00, 0b111);
2079 INSN(frintms, 0b00, 0b010);
2080 INSN(frintns, 0b00, 0b000);
2081 INSN(frintps, 0b00, 0b001);
2082 INSN(frintxs, 0b00, 0b110);
2083 INSN(frintzs, 0b00, 0b011);
2084
2085 INSN(frintad, 0b01, 0b100);
2086 INSN(frintid, 0b01, 0b111);
2087 INSN(frintmd, 0b01, 0b010);
2088 INSN(frintnd, 0b01, 0b000);
2089 INSN(frintpd, 0b01, 0b001);
2090 INSN(frintxd, 0b01, 0b110);
2091 INSN(frintzd, 0b01, 0b011);
2092 #undef INSN
2093
2094 /* SIMD extensions
2095 *
2096 * We just use FloatRegister in the following. They are exactly the same
2097 * as SIMD registers.
2098 */
2099 public:
2100
2101 enum SIMD_Arrangement {
2102 T8B, T16B, T4H, T8H, T2S, T4S, T1D, T2D, T1Q
2103 };
2104
2105 enum SIMD_RegVariant {
2106 B, H, S, D, Q
2107 };
2108
2109 private:
2110 static short SIMD_Size_in_bytes[];
2111
2112 public:
2113 #define INSN(NAME, op) \
2114 void NAME(FloatRegister Rt, SIMD_RegVariant T, const Address &adr) { \
2115 ld_st2((Register)Rt, adr, (int)T & 3, op + ((T==Q) ? 0b10:0b00), 1); \
2116 } \
2117
2118 INSN(ldr, 1);
2119 INSN(str, 0);
2120
2121 #undef INSN
2122
2123 private:
2124
2125 void ld_st(FloatRegister Vt, SIMD_Arrangement T, Register Xn, int op1, int op2) {
2126 starti;
2127 f(0,31), f((int)T & 1, 30);
2128 f(op1, 29, 21), f(0, 20, 16), f(op2, 15, 12);
2246 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \
2247 guarantee(T != T1Q && T != T1D, "incorrect arrangement"); \
2248 if (!acceptT2D) guarantee(T != T2D, "incorrect arrangement"); \
2249 starti; \
2250 f(0, 31), f((int)T & 1, 30), f(opc, 29), f(0b01110, 28, 24); \
2251 f((int)T >> 1, 23, 22), f(1, 21), rf(Vm, 16), f(opc2, 15, 10); \
2252 rf(Vn, 5), rf(Vd, 0); \
2253 }
2254
2255 INSN(addv, 0, 0b100001, true); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
2256 INSN(subv, 1, 0b100001, true); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
2257 INSN(mulv, 0, 0b100111, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2258 INSN(mlav, 0, 0b100101, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2259 INSN(mlsv, 1, 0b100101, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2260 INSN(sshl, 0, 0b010001, true); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
2261 INSN(ushl, 1, 0b010001, true); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
2262 INSN(addpv, 0, 0b101111, true); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
2263 INSN(smullv, 0, 0b110000, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2264 INSN(umullv, 1, 0b110000, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2265 INSN(umlalv, 1, 0b100000, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2266
2267 #undef INSN
2268
2269 #define INSN(NAME, opc, opc2, accepted) \
2270 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn) { \
2271 guarantee(T != T1Q && T != T1D, "incorrect arrangement"); \
2272 if (accepted < 3) guarantee(T != T2D, "incorrect arrangement"); \
2273 if (accepted < 2) guarantee(T != T2S, "incorrect arrangement"); \
2274 if (accepted < 1) guarantee(T == T8B || T == T16B, "incorrect arrangement"); \
2275 starti; \
2276 f(0, 31), f((int)T & 1, 30), f(opc, 29), f(0b01110, 28, 24); \
2277 f((int)T >> 1, 23, 22), f(opc2, 21, 10); \
2278 rf(Vn, 5), rf(Vd, 0); \
2279 }
2280
2281 INSN(absr, 0, 0b100000101110, 3); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
2282 INSN(negr, 1, 0b100000101110, 3); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
2283 INSN(notr, 1, 0b100000010110, 0); // accepted arrangements: T8B, T16B
2284 INSN(addv, 0, 0b110001101110, 1); // accepted arrangements: T8B, T16B, T4H, T8H, T4S
2285 INSN(cls, 0, 0b100000010010, 2); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2286 INSN(clz, 1, 0b100000010010, 2); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2287 INSN(cnt, 0, 0b100000010110, 0); // accepted arrangements: T8B, T16B
2288 INSN(uaddlp, 1, 0b100000001010, 2); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2289 INSN(uaddlv, 1, 0b110000001110, 1); // accepted arrangements: T8B, T16B, T4H, T8H, T4S
2290
2291 #undef INSN
2292
2293 #define INSN(NAME, opc) \
2294 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn) { \
2295 starti; \
2296 assert(T == T4S, "arrangement must be T4S"); \
2297 f(0, 31), f((int)T & 1, 30), f(0b101110, 29, 24), f(opc, 23), \
2298 f(T == T4S ? 0 : 1, 22), f(0b110000111110, 21, 10); rf(Vn, 5), rf(Vd, 0); \
2299 }
2300
2301 INSN(fmaxv, 0);
2302 INSN(fminv, 1);
2303
2304 #undef INSN
2329 INSN(bici, 1, 1);
2330
2331 #undef INSN
2332
2333 #define INSN(NAME, op1, op2, op3) \
2334 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \
2335 starti; \
2336 assert(T == T2S || T == T4S || T == T2D, "invalid arrangement"); \
2337 f(0, 31), f((int)T & 1, 30), f(op1, 29), f(0b01110, 28, 24), f(op2, 23); \
2338 f(T==T2D ? 1:0, 22); f(1, 21), rf(Vm, 16), f(op3, 15, 10), rf(Vn, 5), rf(Vd, 0); \
2339 }
2340
2341 INSN(fadd, 0, 0, 0b110101);
2342 INSN(fdiv, 1, 0, 0b111111);
2343 INSN(fmul, 1, 0, 0b110111);
2344 INSN(fsub, 0, 1, 0b110101);
2345 INSN(fmla, 0, 0, 0b110011);
2346 INSN(fmls, 0, 1, 0b110011);
2347 INSN(fmax, 0, 0, 0b111101);
2348 INSN(fmin, 0, 1, 0b111101);
2349
2350 #undef INSN
2351
2352 #define INSN(NAME, opc) \
2353 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \
2354 starti; \
2355 assert(T == T4S, "arrangement must be T4S"); \
2356 f(0b01011110000, 31, 21), rf(Vm, 16), f(opc, 15, 10), rf(Vn, 5), rf(Vd, 0); \
2357 }
2358
2359 INSN(sha1c, 0b000000);
2360 INSN(sha1m, 0b001000);
2361 INSN(sha1p, 0b000100);
2362 INSN(sha1su0, 0b001100);
2363 INSN(sha256h2, 0b010100);
2364 INSN(sha256h, 0b010000);
2365 INSN(sha256su1, 0b011000);
2366
2367 #undef INSN
2368
2404 }
2405
2406 // FMLA/FMLS - Vector - Scalar
2407 INSN(fmlavs, 0, 0b0001);
2408 INSN(fmlsvs, 0, 0b0101);
2409 // FMULX - Vector - Scalar
2410 INSN(fmulxvs, 1, 0b1001);
2411
2412 #undef INSN
2413
2414 // Floating-point Reciprocal Estimate
2415 void frecpe(FloatRegister Vd, FloatRegister Vn, SIMD_RegVariant type) {
2416 assert(type == D || type == S, "Wrong type for frecpe");
2417 starti;
2418 f(0b010111101, 31, 23);
2419 f(type == D ? 1 : 0, 22);
2420 f(0b100001110110, 21, 10);
2421 rf(Vn, 5), rf(Vd, 0);
2422 }
2423
2424 // (double) {a, b} -> (a + b)
2425 void faddpd(FloatRegister Vd, FloatRegister Vn) {
2426 starti;
2427 f(0b0111111001110000110110, 31, 10);
2428 rf(Vn, 5), rf(Vd, 0);
2429 }
2430
2431 void ins(FloatRegister Vd, SIMD_RegVariant T, FloatRegister Vn, int didx, int sidx) {
2432 starti;
2433 assert(T != Q, "invalid register variant");
2434 f(0b01101110000, 31, 21), f(((didx<<1)|1)<<(int)T, 20, 16), f(0, 15);
2435 f(sidx<<(int)T, 14, 11), f(1, 10), rf(Vn, 5), rf(Vd, 0);
2436 }
2437
2438 void umov(Register Rd, FloatRegister Vn, SIMD_RegVariant T, int idx) {
2439 starti;
2440 f(0, 31), f(T==D ? 1:0, 30), f(0b001110000, 29, 21);
2441 f(((idx<<1)|1)<<(int)T, 20, 16), f(0b001111, 15, 10);
2442 rf(Vn, 5), rf(Rd, 0);
2443 }
2444
2445 #define INSN(NAME, opc, opc2, isSHR) \
2446 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, int shift){ \
2447 starti; \
2448 /* The encodings for the immh:immb fields (bits 22:16) in *SHR are \
2449 * 0001 xxx 8B/16B, shift = 16 - UInt(immh:immb) \
2450 * 001x xxx 4H/8H, shift = 32 - UInt(immh:immb) \
2451 * 01xx xxx 2S/4S, shift = 64 - UInt(immh:immb) \
2452 * 1xxx xxx 1D/2D, shift = 128 - UInt(immh:immb) \
2453 * (1D is RESERVED) \
2454 * for SHL shift is calculated as: \
2455 * 0001 xxx 8B/16B, shift = UInt(immh:immb) - 8 \
2456 * 001x xxx 4H/8H, shift = UInt(immh:immb) - 16 \
2457 * 01xx xxx 2S/4S, shift = UInt(immh:immb) - 32 \
2458 * 1xxx xxx 1D/2D, shift = UInt(immh:immb) - 64 \
2459 * (1D is RESERVED) \
2460 */ \
2461 assert((1 << ((T>>1)+3)) > shift, "Invalid Shift value"); \
2462 int cVal = (1 << (((T >> 1) + 3) + (isSHR ? 1 : 0))); \
2463 int encodedShift = isSHR ? cVal - shift : cVal + shift; \
2464 f(0, 31), f(T & 1, 30), f(opc, 29), f(0b011110, 28, 23), \
2465 f(encodedShift, 22, 16); f(opc2, 15, 10), rf(Vn, 5), rf(Vd, 0); \
2466 }
2467
2468 INSN(shl, 0, 0b010101, /* isSHR = */ false);
2469 INSN(sshr, 0, 0b000001, /* isSHR = */ true);
2470 INSN(ushr, 1, 0b000001, /* isSHR = */ true);
2471
2472 #undef INSN
2473
2474 private:
2475 void _ushll(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb, int shift) {
2476 starti;
2477 /* The encodings for the immh:immb fields (bits 22:16) are
2478 * 0001 xxx 8H, 8B/16b shift = xxx
2479 * 001x xxx 4S, 4H/8H shift = xxxx
2480 * 01xx xxx 2D, 2S/4S shift = xxxxx
2481 * 1xxx xxx RESERVED
2482 */
2483 assert((Tb >> 1) + 1 == (Ta >> 1), "Incompatible arrangement");
2484 assert((1 << ((Tb>>1)+3)) > shift, "Invalid shift value");
2485 f(0, 31), f(Tb & 1, 30), f(0b1011110, 29, 23), f((1 << ((Tb>>1)+3))|shift, 22, 16);
2486 f(0b101001, 15, 10), rf(Vn, 5), rf(Vd, 0);
2487 }
2488
2489 public:
2490 void ushll(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb, int shift) {
2491 assert(Tb == T8B || Tb == T4H || Tb == T2S, "invalid arrangement");
2492 _ushll(Vd, Ta, Vn, Tb, shift);
2493 }
2494
2495 void ushll2(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb, int shift) {
2496 assert(Tb == T16B || Tb == T8H || Tb == T4S, "invalid arrangement");
2497 _ushll(Vd, Ta, Vn, Tb, shift);
2498 }
2499
2500 // Move from general purpose register
2501 // mov Vd.T[index], Rn
2502 void mov(FloatRegister Vd, SIMD_Arrangement T, int index, Register Xn) {
2503 starti;
2504 f(0b01001110000, 31, 21), f(((1 << (T >> 1)) | (index << ((T >> 1) + 1))), 20, 16);
2505 f(0b000111, 15, 10), zrf(Xn, 5), rf(Vd, 0);
2506 }
2507
2508 // Move to general purpose register
2509 // mov Rd, Vn.T[index]
2510 void mov(Register Xd, FloatRegister Vn, SIMD_Arrangement T, int index) {
2511 guarantee(T >= T2S && T < T1Q, "only D and S arrangements are supported");
2512 starti;
2513 f(0, 31), f((T >= T1D) ? 1:0, 30), f(0b001110000, 29, 21);
2514 f(((1 << (T >> 1)) | (index << ((T >> 1) + 1))), 20, 16);
2515 f(0b001111, 15, 10), rf(Vn, 5), rf(Xd, 0);
2516 }
2517
2526 }
2527
2528 public:
2529 void pmull(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, FloatRegister Vm, SIMD_Arrangement Tb) {
2530 assert(Tb == T1D || Tb == T8B, "pmull assumes T1D or T8B as the second size specifier");
2531 _pmull(Vd, Ta, Vn, Vm, Tb);
2532 }
2533
2534 void pmull2(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, FloatRegister Vm, SIMD_Arrangement Tb) {
2535 assert(Tb == T2D || Tb == T16B, "pmull2 assumes T2D or T16B as the second size specifier");
2536 _pmull(Vd, Ta, Vn, Vm, Tb);
2537 }
2538
2539 void uqxtn(FloatRegister Vd, SIMD_Arrangement Tb, FloatRegister Vn, SIMD_Arrangement Ta) {
2540 starti;
2541 int size_b = (int)Tb >> 1;
2542 int size_a = (int)Ta >> 1;
2543 assert(size_b < 3 && size_b == size_a - 1, "Invalid size specifier");
2544 f(0, 31), f(Tb & 1, 30), f(0b101110, 29, 24), f(size_b, 23, 22);
2545 f(0b100001010010, 21, 10), rf(Vn, 5), rf(Vd, 0);
2546 }
2547
2548 void dup(FloatRegister Vd, SIMD_Arrangement T, Register Xs)
2549 {
2550 starti;
2551 assert(T != T1D, "reserved encoding");
2552 f(0,31), f((int)T & 1, 30), f(0b001110000, 29, 21);
2553 f((1 << (T >> 1)), 20, 16), f(0b000011, 15, 10), zrf(Xs, 5), rf(Vd, 0);
2554 }
2555
2556 void dup(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, int index = 0)
2557 {
2558 starti;
2559 assert(T != T1D, "reserved encoding");
2560 f(0, 31), f((int)T & 1, 30), f(0b001110000, 29, 21);
2561 f(((1 << (T >> 1)) | (index << ((T >> 1) + 1))), 20, 16);
2562 f(0b000001, 15, 10), rf(Vn, 5), rf(Vd, 0);
2563 }
2564
2565 // AdvSIMD ZIP/UZP/TRN
|
1313 INSN(ldr, 0b01, 0);
1314 INSN(ldrsw, 0b10, 0);
1315
1316 #undef INSN
1317
1318 #define INSN(NAME, opc, V) \
1319 void NAME(FloatRegister Rt, address dest) { \
1320 long offset = (dest - pc()) >> 2; \
1321 starti; \
1322 f(opc, 31, 30), f(0b011, 29, 27), f(V, 26), f(0b00, 25, 24), \
1323 sf(offset, 23, 5); \
1324 rf((Register)Rt, 0); \
1325 }
1326
1327 INSN(ldrs, 0b00, 1);
1328 INSN(ldrd, 0b01, 1);
1329 INSN(ldrq, 0b10, 1);
1330
1331 #undef INSN
1332
1333 #define INSN(NAME, size, opc) \
1334 void NAME(FloatRegister Rt, Register Rn) { \
1335 starti; \
1336 f(size, 31, 30), f(0b111100, 29, 24), f(opc, 23, 22), f(0, 21); \
1337 f(0, 20, 12), f(0b01, 11, 10); \
1338 rf(Rn, 5), rf((Register)Rt, 0); \
1339 }
1340
1341 INSN(ldrs, 0b10, 0b01);
1342 INSN(ldrd, 0b11, 0b01);
1343 INSN(ldrq, 0b00, 0b11);
1344
1345 #undef INSN
1346
1347
1348 #define INSN(NAME, opc, V) \
1349 void NAME(address dest, prfop op = PLDL1KEEP) { \
1350 long offset = (dest - pc()) >> 2; \
1351 starti; \
1352 f(opc, 31, 30), f(0b011, 29, 27), f(V, 26), f(0b00, 25, 24), \
1353 sf(offset, 23, 5); \
1354 f(op, 4, 0); \
1355 } \
1356 void NAME(Label &L, prfop op = PLDL1KEEP) { \
1357 wrap_label(L, op, &Assembler::NAME); \
1358 }
1359
1360 INSN(prfm, 0b11, 0);
1361
1362 #undef INSN
1363
1364 // Load/store
1365 void ld_st1(int opc, int p1, int V, int L,
1366 Register Rt1, Register Rt2, Address adr, bool no_allocate) {
1367 starti;
1465 INSN(prfm, 0b11, 0b10); // FIXME: PRFM should not be used with
1466 // writeback modes, but the assembler
1467 // doesn't enfore that.
1468
1469 #undef INSN
1470
1471 #define INSN(NAME, size, op) \
1472 void NAME(FloatRegister Rt, const Address &adr) { \
1473 ld_st2((Register)Rt, adr, size, op, 1); \
1474 }
1475
1476 INSN(strd, 0b11, 0b00);
1477 INSN(strs, 0b10, 0b00);
1478 INSN(ldrd, 0b11, 0b01);
1479 INSN(ldrs, 0b10, 0b01);
1480 INSN(strq, 0b00, 0b10);
1481 INSN(ldrq, 0x00, 0b11);
1482
1483 #undef INSN
1484
1485 /* SIMD extensions
1486 *
1487 * We just use FloatRegister in the following. They are exactly the same
1488 * as SIMD registers.
1489 */
1490 public:
1491
1492 enum SIMD_Arrangement {
1493 T8B, T16B, T4H, T8H, T2S, T4S, T1D, T2D, T1Q
1494 };
1495
1496 enum SIMD_RegVariant {
1497 B, H, S, D, Q
1498 };
1499
1500 enum shift_kind { LSL, LSR, ASR, ROR };
1501
1502 void op_shifted_reg(unsigned decode,
1503 enum shift_kind kind, unsigned shift,
1504 unsigned size, unsigned op) {
1505 f(size, 31);
1506 f(op, 30, 29);
1507 f(decode, 28, 24);
1508 f(shift, 15, 10);
1509 f(kind, 23, 22);
1510 }
1511
1512 // Logical (shifted register)
1513 #define INSN(NAME, size, op, N) \
1514 void NAME(Register Rd, Register Rn, Register Rm, \
1515 enum shift_kind kind = LSL, unsigned shift = 0) { \
1516 starti; \
1517 guarantee(size == 1 || shift < 32, "incorrect shift"); \
1518 f(N, 21); \
1519 zrf(Rm, 16), zrf(Rn, 5), zrf(Rd, 0); \
1854 INSN(fcvts, 0b000, 0b00, 0b000101); // Single-precision to double-precision
1855
1856 private:
1857 INSN(i_fmovd, 0b000, 0b01, 0b000000);
1858 public:
1859 INSN(fabsd, 0b000, 0b01, 0b000001);
1860 INSN(fnegd, 0b000, 0b01, 0b000010);
1861 INSN(fsqrtd, 0b000, 0b01, 0b000011);
1862 INSN(fcvtd, 0b000, 0b01, 0b000100); // Double-precision to single-precision
1863
1864 void fmovd(FloatRegister Vd, FloatRegister Vn) {
1865 assert(Vd != Vn, "should be");
1866 i_fmovd(Vd, Vn);
1867 }
1868
1869 void fmovs(FloatRegister Vd, FloatRegister Vn) {
1870 assert(Vd != Vn, "should be");
1871 i_fmovs(Vd, Vn);
1872 }
1873
1874 private:
1875 void _fcvt_narrow_extend(FloatRegister Vd, SIMD_Arrangement Ta,
1876 FloatRegister Vn, SIMD_Arrangement Tb, bool do_extend) {
1877 assert((do_extend && (Tb >> 1) + 1 == (Ta >> 1))
1878 || (!do_extend && (Ta >> 1) + 1 == (Tb >> 1)), "Incompatible arrangement");
1879 starti;
1880 int op30 = (do_extend ? Tb : Ta) & 1;
1881 int op22 = ((do_extend ? Ta : Tb) >> 1) & 1;
1882 f(0, 31), f(op30, 30), f(0b0011100, 29, 23), f(op22, 22);
1883 f(0b100001011, 21, 13), f(do_extend ? 1 : 0, 12), f(0b10, 11, 10);
1884 rf(Vn, 5), rf(Vd, 0);
1885 }
1886
1887 public:
1888 void fcvtl(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb) {
1889 assert(Tb == T4H || Tb == T8H|| Tb == T2S || Tb == T4S, "invalid arrangement");
1890 _fcvt_narrow_extend(Vd, Ta, Vn, Tb, true);
1891 }
1892
1893 void fcvtn(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb) {
1894 assert(Ta == T4H || Ta == T8H|| Ta == T2S || Ta == T4S, "invalid arrangement");
1895 _fcvt_narrow_extend(Vd, Ta, Vn, Tb, false);
1896 }
1897
1898 #undef INSN
1899
1900 // Floating-point data-processing (2 source)
1901 void data_processing(unsigned op31, unsigned type, unsigned opcode,
1902 FloatRegister Vd, FloatRegister Vn, FloatRegister Vm) {
1903 starti;
1904 f(op31, 31, 29);
1905 f(0b11110, 28, 24);
1906 f(type, 23, 22), f(1, 21), f(opcode, 15, 12), f(0b10, 11, 10);
1907 rf(Vm, 16), rf(Vn, 5), rf(Vd, 0);
1908 }
1909
1910 #define INSN(NAME, op31, type, opcode) \
1911 void NAME(FloatRegister Vd, FloatRegister Vn, FloatRegister Vm) { \
1912 data_processing(op31, type, opcode, Vd, Vn, Vm); \
1913 }
1914
1915 INSN(fmuls, 0b000, 0b00, 0b0000);
1916 INSN(fdivs, 0b000, 0b00, 0b0001);
1917 INSN(fadds, 0b000, 0b00, 0b0010);
2014
2015 #undef INSN
2016
2017 #define INSN(NAME, op31, type, rmode, opcode) \
2018 void NAME(FloatRegister Vd, Register Rn) { \
2019 float_int_convert(op31, type, rmode, opcode, (Register)Vd, Rn); \
2020 }
2021
2022 INSN(fmovs, 0b000, 0b00, 0b00, 0b111);
2023 INSN(fmovd, 0b100, 0b01, 0b00, 0b111);
2024
2025 INSN(scvtfws, 0b000, 0b00, 0b00, 0b010);
2026 INSN(scvtfs, 0b100, 0b00, 0b00, 0b010);
2027 INSN(scvtfwd, 0b000, 0b01, 0b00, 0b010);
2028 INSN(scvtfd, 0b100, 0b01, 0b00, 0b010);
2029
2030 // INSN(fmovhid, 0b100, 0b10, 0b01, 0b111);
2031
2032 #undef INSN
2033
2034 enum sign_kind { SIGNED, UNSIGNED };
2035
2036 private:
2037 void _xcvtf_scalar_integer(sign_kind sign, unsigned sz,
2038 FloatRegister Rd, FloatRegister Rn) {
2039 starti;
2040 f(0b01, 31, 30), f(sign == SIGNED ? 0 : 1, 29);
2041 f(0b111100, 27, 23), f((sz >> 1) & 1, 22), f(0b100001110110, 21, 10);
2042 rf(Rn, 5), rf(Rd, 0);
2043 }
2044
2045 public:
2046 #define INSN(NAME, sign, sz) \
2047 void NAME(FloatRegister Rd, FloatRegister Rn) { \
2048 _xcvtf_scalar_integer(sign, sz, Rd, Rn); \
2049 }
2050
2051 INSN(scvtfs, SIGNED, 0);
2052 INSN(scvtfd, SIGNED, 1);
2053
2054 #undef INSN
2055
2056 private:
2057 void _xcvtf_vector_integer(sign_kind sign, SIMD_Arrangement T,
2058 FloatRegister Rd, FloatRegister Rn) {
2059 assert(T == T2S || T == T4S || T == T2D, "invalid arrangement");
2060 starti;
2061 f(0, 31), f(T & 1, 30), f(sign == SIGNED ? 0 : 1, 29);
2062 f(0b011100, 28, 23), f((T >> 1) & 1, 22), f(0b100001110110, 21, 10);
2063 rf(Rn, 5), rf(Rd, 0);
2064 }
2065
2066 public:
2067 void scvtfv(SIMD_Arrangement T, FloatRegister Rd, FloatRegister Rn) {
2068 _xcvtf_vector_integer(SIGNED, T, Rd, Rn);
2069 }
2070
2071 // Floating-point compare
2072 void float_compare(unsigned op31, unsigned type,
2073 unsigned op, unsigned op2,
2074 FloatRegister Vn, FloatRegister Vm = (FloatRegister)0) {
2075 starti;
2076 f(op31, 31, 29);
2077 f(0b11110, 28, 24);
2078 f(type, 23, 22), f(1, 21);
2079 f(op, 15, 14), f(0b1000, 13, 10), f(op2, 4, 0);
2080 rf(Vn, 5), rf(Vm, 16);
2081 }
2082
2083
2084 #define INSN(NAME, op31, type, op, op2) \
2085 void NAME(FloatRegister Vn, FloatRegister Vm) { \
2086 float_compare(op31, type, op, op2, Vn, Vm); \
2087 }
2088
2089 #define INSN1(NAME, op31, type, op, op2) \
2090 void NAME(FloatRegister Vn, double d) { \
2165 INSN(frintxh, 0b11, 0b110);
2166 INSN(frintzh, 0b11, 0b011);
2167
2168 INSN(frintas, 0b00, 0b100);
2169 INSN(frintis, 0b00, 0b111);
2170 INSN(frintms, 0b00, 0b010);
2171 INSN(frintns, 0b00, 0b000);
2172 INSN(frintps, 0b00, 0b001);
2173 INSN(frintxs, 0b00, 0b110);
2174 INSN(frintzs, 0b00, 0b011);
2175
2176 INSN(frintad, 0b01, 0b100);
2177 INSN(frintid, 0b01, 0b111);
2178 INSN(frintmd, 0b01, 0b010);
2179 INSN(frintnd, 0b01, 0b000);
2180 INSN(frintpd, 0b01, 0b001);
2181 INSN(frintxd, 0b01, 0b110);
2182 INSN(frintzd, 0b01, 0b011);
2183 #undef INSN
2184
2185 private:
2186 static short SIMD_Size_in_bytes[];
2187
2188 public:
2189 #define INSN(NAME, op) \
2190 void NAME(FloatRegister Rt, SIMD_RegVariant T, const Address &adr) { \
2191 ld_st2((Register)Rt, adr, (int)T & 3, op + ((T==Q) ? 0b10:0b00), 1); \
2192 } \
2193
2194 INSN(ldr, 1);
2195 INSN(str, 0);
2196
2197 #undef INSN
2198
2199 private:
2200
2201 void ld_st(FloatRegister Vt, SIMD_Arrangement T, Register Xn, int op1, int op2) {
2202 starti;
2203 f(0,31), f((int)T & 1, 30);
2204 f(op1, 29, 21), f(0, 20, 16), f(op2, 15, 12);
2322 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \
2323 guarantee(T != T1Q && T != T1D, "incorrect arrangement"); \
2324 if (!acceptT2D) guarantee(T != T2D, "incorrect arrangement"); \
2325 starti; \
2326 f(0, 31), f((int)T & 1, 30), f(opc, 29), f(0b01110, 28, 24); \
2327 f((int)T >> 1, 23, 22), f(1, 21), rf(Vm, 16), f(opc2, 15, 10); \
2328 rf(Vn, 5), rf(Vd, 0); \
2329 }
2330
2331 INSN(addv, 0, 0b100001, true); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
2332 INSN(subv, 1, 0b100001, true); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
2333 INSN(mulv, 0, 0b100111, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2334 INSN(mlav, 0, 0b100101, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2335 INSN(mlsv, 1, 0b100101, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2336 INSN(sshl, 0, 0b010001, true); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
2337 INSN(ushl, 1, 0b010001, true); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
2338 INSN(addpv, 0, 0b101111, true); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
2339 INSN(smullv, 0, 0b110000, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2340 INSN(umullv, 1, 0b110000, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2341 INSN(umlalv, 1, 0b100000, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2342 INSN(maxv, 0, 0b011001, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2343 INSN(minv, 0, 0b011011, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2344 INSN(cmeq, 1, 0b100011, true); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
2345 INSN(cmgt, 0, 0b001101, true); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
2346 INSN(cmge, 0, 0b001111, true); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
2347
2348 #undef INSN
2349
2350 #define INSN(NAME, opc, opc2, accepted) \
2351 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn) { \
2352 guarantee(T != T1Q && T != T1D, "incorrect arrangement"); \
2353 if (accepted < 3) guarantee(T != T2D, "incorrect arrangement"); \
2354 if (accepted < 2) guarantee(T != T2S, "incorrect arrangement"); \
2355 if (accepted < 1) guarantee(T == T8B || T == T16B, "incorrect arrangement"); \
2356 starti; \
2357 f(0, 31), f((int)T & 1, 30), f(opc, 29), f(0b01110, 28, 24); \
2358 f((int)T >> 1, 23, 22), f(opc2, 21, 10); \
2359 rf(Vn, 5), rf(Vd, 0); \
2360 }
2361
2362 INSN(absr, 0, 0b100000101110, 3); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
2363 INSN(negr, 1, 0b100000101110, 3); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
2364 INSN(notr, 1, 0b100000010110, 0); // accepted arrangements: T8B, T16B
2365 INSN(addv, 0, 0b110001101110, 1); // accepted arrangements: T8B, T16B, T4H, T8H, T4S
2366 INSN(smaxv, 0, 0b110000101010, 1); // accepted arrangements: T8B, T16B, T4H, T8H, T4S
2367 INSN(sminv, 0, 0b110001101010, 1); // accepted arrangements: T8B, T16B, T4H, T8H, T4S
2368 INSN(cls, 0, 0b100000010010, 2); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2369 INSN(clz, 1, 0b100000010010, 2); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2370 INSN(cnt, 0, 0b100000010110, 0); // accepted arrangements: T8B, T16B
2371 INSN(uaddlp, 1, 0b100000001010, 2); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S
2372 INSN(uaddlv, 1, 0b110000001110, 1); // accepted arrangements: T8B, T16B, T4H, T8H, T4S
2373
2374 #undef INSN
2375
2376 #define INSN(NAME, opc) \
2377 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn) { \
2378 starti; \
2379 assert(T == T4S, "arrangement must be T4S"); \
2380 f(0, 31), f((int)T & 1, 30), f(0b101110, 29, 24), f(opc, 23), \
2381 f(T == T4S ? 0 : 1, 22), f(0b110000111110, 21, 10); rf(Vn, 5), rf(Vd, 0); \
2382 }
2383
2384 INSN(fmaxv, 0);
2385 INSN(fminv, 1);
2386
2387 #undef INSN
2412 INSN(bici, 1, 1);
2413
2414 #undef INSN
2415
2416 #define INSN(NAME, op1, op2, op3) \
2417 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \
2418 starti; \
2419 assert(T == T2S || T == T4S || T == T2D, "invalid arrangement"); \
2420 f(0, 31), f((int)T & 1, 30), f(op1, 29), f(0b01110, 28, 24), f(op2, 23); \
2421 f(T==T2D ? 1:0, 22); f(1, 21), rf(Vm, 16), f(op3, 15, 10), rf(Vn, 5), rf(Vd, 0); \
2422 }
2423
2424 INSN(fadd, 0, 0, 0b110101);
2425 INSN(fdiv, 1, 0, 0b111111);
2426 INSN(fmul, 1, 0, 0b110111);
2427 INSN(fsub, 0, 1, 0b110101);
2428 INSN(fmla, 0, 0, 0b110011);
2429 INSN(fmls, 0, 1, 0b110011);
2430 INSN(fmax, 0, 0, 0b111101);
2431 INSN(fmin, 0, 1, 0b111101);
2432 INSN(fcmeq, 0, 0, 0b111001);
2433 INSN(fcmgt, 1, 1, 0b111001);
2434 INSN(fcmge, 1, 0, 0b111001);
2435
2436 #undef INSN
2437
2438 #define INSN(NAME, opc) \
2439 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \
2440 starti; \
2441 assert(T == T4S, "arrangement must be T4S"); \
2442 f(0b01011110000, 31, 21), rf(Vm, 16), f(opc, 15, 10), rf(Vn, 5), rf(Vd, 0); \
2443 }
2444
2445 INSN(sha1c, 0b000000);
2446 INSN(sha1m, 0b001000);
2447 INSN(sha1p, 0b000100);
2448 INSN(sha1su0, 0b001100);
2449 INSN(sha256h2, 0b010100);
2450 INSN(sha256h, 0b010000);
2451 INSN(sha256su1, 0b011000);
2452
2453 #undef INSN
2454
2490 }
2491
2492 // FMLA/FMLS - Vector - Scalar
2493 INSN(fmlavs, 0, 0b0001);
2494 INSN(fmlsvs, 0, 0b0101);
2495 // FMULX - Vector - Scalar
2496 INSN(fmulxvs, 1, 0b1001);
2497
2498 #undef INSN
2499
2500 // Floating-point Reciprocal Estimate
2501 void frecpe(FloatRegister Vd, FloatRegister Vn, SIMD_RegVariant type) {
2502 assert(type == D || type == S, "Wrong type for frecpe");
2503 starti;
2504 f(0b010111101, 31, 23);
2505 f(type == D ? 1 : 0, 22);
2506 f(0b100001110110, 21, 10);
2507 rf(Vn, 5), rf(Vd, 0);
2508 }
2509
2510 // (long) {a, b} -> (a + b)
2511 void addpd(FloatRegister Vd, FloatRegister Vn) {
2512 starti;
2513 f(0b0101111011110001101110, 31, 10);
2514 rf(Vn, 5), rf(Vd, 0);
2515 }
2516
2517 // (Floating-point) {a, b} -> (a + b)
2518 void faddp(FloatRegister Vd, FloatRegister Vn, SIMD_RegVariant type) {
2519 assert(type == D || type == S, "Wrong type for faddp");
2520 starti;
2521 f(0b011111100, 31, 23);
2522 f(type == D ? 1 : 0, 22);
2523 f(0b110000110110, 21, 10);
2524 rf(Vn, 5), rf(Vd, 0);
2525 }
2526
2527 void ins(FloatRegister Vd, SIMD_RegVariant T, FloatRegister Vn, int didx, int sidx) {
2528 starti;
2529 assert(T != Q, "invalid register variant");
2530 f(0b01101110000, 31, 21), f(((didx<<1)|1)<<(int)T, 20, 16), f(0, 15);
2531 f(sidx<<(int)T, 14, 11), f(1, 10), rf(Vn, 5), rf(Vd, 0);
2532 }
2533
2534 void umov(Register Rd, FloatRegister Vn, SIMD_RegVariant T, int idx) {
2535 starti;
2536 f(0, 31), f(T==D ? 1:0, 30), f(0b001110000, 29, 21);
2537 f(((idx<<1)|1)<<(int)T, 20, 16), f(0b001111, 15, 10);
2538 rf(Vn, 5), rf(Rd, 0);
2539 }
2540
2541 void smov(Register Rd, FloatRegister Vn, SIMD_RegVariant T, int idx) {
2542 starti;
2543 f(0, 31), f(T==D ? 1:0, 30), f(0b001110000, 29, 21);
2544 f(((idx<<1)|1)<<(int)T, 20, 16), f(0b001011, 15, 10);
2545 rf(Vn, 5), rf(Rd, 0);
2546 }
2547
2548
2549 #define INSN(NAME, opc, opc2, isSHR) \
2550 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, int shift){ \
2551 starti; \
2552 /* The encodings for the immh:immb fields (bits 22:16) in *SHR are \
2553 * 0001 xxx 8B/16B, shift = 16 - UInt(immh:immb) \
2554 * 001x xxx 4H/8H, shift = 32 - UInt(immh:immb) \
2555 * 01xx xxx 2S/4S, shift = 64 - UInt(immh:immb) \
2556 * 1xxx xxx 1D/2D, shift = 128 - UInt(immh:immb) \
2557 * (1D is RESERVED) \
2558 * for SHL shift is calculated as: \
2559 * 0001 xxx 8B/16B, shift = UInt(immh:immb) - 8 \
2560 * 001x xxx 4H/8H, shift = UInt(immh:immb) - 16 \
2561 * 01xx xxx 2S/4S, shift = UInt(immh:immb) - 32 \
2562 * 1xxx xxx 1D/2D, shift = UInt(immh:immb) - 64 \
2563 * (1D is RESERVED) \
2564 */ \
2565 assert((1 << ((T>>1)+3)) > shift, "Invalid Shift value"); \
2566 int cVal = (1 << (((T >> 1) + 3) + (isSHR ? 1 : 0))); \
2567 int encodedShift = isSHR ? cVal - shift : cVal + shift; \
2568 f(0, 31), f(T & 1, 30), f(opc, 29), f(0b011110, 28, 23), \
2569 f(encodedShift, 22, 16); f(opc2, 15, 10), rf(Vn, 5), rf(Vd, 0); \
2570 }
2571
2572 INSN(shl, 0, 0b010101, /* isSHR = */ false);
2573 INSN(sshr, 0, 0b000001, /* isSHR = */ true);
2574 INSN(ushr, 1, 0b000001, /* isSHR = */ true);
2575
2576 #undef INSN
2577
2578 private:
2579 void _xshll(sign_kind sign, FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb, int shift) {
2580 starti;
2581 /* The encodings for the immh:immb fields (bits 22:16) are
2582 * 0001 xxx 8H, 8B/16B shift = xxx
2583 * 001x xxx 4S, 4H/8H shift = xxxx
2584 * 01xx xxx 2D, 2S/4S shift = xxxxx
2585 * 1xxx xxx RESERVED
2586 */
2587 assert((Tb >> 1) + 1 == (Ta >> 1), "Incompatible arrangement");
2588 assert((1 << ((Tb>>1)+3)) > shift, "Invalid shift value");
2589 f(0, 31), f(Tb & 1, 30), f(sign == SIGNED ? 0 : 1, 29), f(0b011110, 28, 23);
2590 f((1 << ((Tb>>1)+3))|shift, 22, 16);
2591 f(0b101001, 15, 10), rf(Vn, 5), rf(Vd, 0);
2592 }
2593
2594 public:
2595 void ushll(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb, int shift) {
2596 assert(Tb == T8B || Tb == T4H || Tb == T2S, "invalid arrangement");
2597 _xshll(UNSIGNED, Vd, Ta, Vn, Tb, shift);
2598 }
2599
2600 void ushll2(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb, int shift) {
2601 assert(Tb == T16B || Tb == T8H || Tb == T4S, "invalid arrangement");
2602 _xshll(UNSIGNED, Vd, Ta, Vn, Tb, shift);
2603 }
2604
2605 void uxtl(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb) {
2606 ushll(Vd, Ta, Vn, Tb, 0);
2607 }
2608
2609 void sshll(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb, int shift) {
2610 assert(Tb == T8B || Tb == T4H || Tb == T2S, "invalid arrangement");
2611 _xshll(SIGNED, Vd, Ta, Vn, Tb, shift);
2612 }
2613
2614 void sshll2(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb, int shift) {
2615 assert(Tb == T16B || Tb == T8H || Tb == T4S, "invalid arrangement");
2616 _xshll(SIGNED, Vd, Ta, Vn, Tb, shift);
2617 }
2618
2619 void sxtl(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb) {
2620 sshll(Vd, Ta, Vn, Tb, 0);
2621 }
2622
2623 // Move from general purpose register
2624 // mov Vd.T[index], Rn
2625 void mov(FloatRegister Vd, SIMD_Arrangement T, int index, Register Xn) {
2626 starti;
2627 f(0b01001110000, 31, 21), f(((1 << (T >> 1)) | (index << ((T >> 1) + 1))), 20, 16);
2628 f(0b000111, 15, 10), zrf(Xn, 5), rf(Vd, 0);
2629 }
2630
2631 // Move to general purpose register
2632 // mov Rd, Vn.T[index]
2633 void mov(Register Xd, FloatRegister Vn, SIMD_Arrangement T, int index) {
2634 guarantee(T >= T2S && T < T1Q, "only D and S arrangements are supported");
2635 starti;
2636 f(0, 31), f((T >= T1D) ? 1:0, 30), f(0b001110000, 29, 21);
2637 f(((1 << (T >> 1)) | (index << ((T >> 1) + 1))), 20, 16);
2638 f(0b001111, 15, 10), rf(Vn, 5), rf(Xd, 0);
2639 }
2640
2649 }
2650
2651 public:
2652 void pmull(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, FloatRegister Vm, SIMD_Arrangement Tb) {
2653 assert(Tb == T1D || Tb == T8B, "pmull assumes T1D or T8B as the second size specifier");
2654 _pmull(Vd, Ta, Vn, Vm, Tb);
2655 }
2656
2657 void pmull2(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, FloatRegister Vm, SIMD_Arrangement Tb) {
2658 assert(Tb == T2D || Tb == T16B, "pmull2 assumes T2D or T16B as the second size specifier");
2659 _pmull(Vd, Ta, Vn, Vm, Tb);
2660 }
2661
2662 void uqxtn(FloatRegister Vd, SIMD_Arrangement Tb, FloatRegister Vn, SIMD_Arrangement Ta) {
2663 starti;
2664 int size_b = (int)Tb >> 1;
2665 int size_a = (int)Ta >> 1;
2666 assert(size_b < 3 && size_b == size_a - 1, "Invalid size specifier");
2667 f(0, 31), f(Tb & 1, 30), f(0b101110, 29, 24), f(size_b, 23, 22);
2668 f(0b100001010010, 21, 10), rf(Vn, 5), rf(Vd, 0);
2669 }
2670
2671 void xtn(FloatRegister Vd, SIMD_Arrangement Tb, FloatRegister Vn, SIMD_Arrangement Ta) {
2672 starti;
2673 int size_b = (int)Tb >> 1;
2674 int size_a = (int)Ta >> 1;
2675 assert(size_b < 3 && size_b == size_a - 1, "Invalid size specifier");
2676 f(0, 31), f(Tb & 1, 30), f(0b001110, 29, 24), f(size_b, 23, 22);
2677 f(0b100001001010, 21, 10), rf(Vn, 5), rf(Vd, 0);
2678 }
2679
2680 void dup(FloatRegister Vd, SIMD_Arrangement T, Register Xs)
2681 {
2682 starti;
2683 assert(T != T1D, "reserved encoding");
2684 f(0,31), f((int)T & 1, 30), f(0b001110000, 29, 21);
2685 f((1 << (T >> 1)), 20, 16), f(0b000011, 15, 10), zrf(Xs, 5), rf(Vd, 0);
2686 }
2687
2688 void dup(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, int index = 0)
2689 {
2690 starti;
2691 assert(T != T1D, "reserved encoding");
2692 f(0, 31), f((int)T & 1, 30), f(0b001110000, 29, 21);
2693 f(((1 << (T >> 1)) | (index << ((T >> 1) + 1))), 20, 16);
2694 f(0b000001, 15, 10), rf(Vn, 5), rf(Vd, 0);
2695 }
2696
2697 // AdvSIMD ZIP/UZP/TRN
|