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 < 2) guarantee(T != T2S && T != T2D, "incorrect arrangement"); \
2273 if (accepted == 0) guarantee(T == T8B || T == T16B, "incorrect arrangement"); \
2274 starti; \
2275 f(0, 31), f((int)T & 1, 30), f(opc, 29), f(0b01110, 28, 24); \
2276 f((int)T >> 1, 23, 22), f(opc2, 21, 10); \
2277 rf(Vn, 5), rf(Vd, 0); \
2278 }
2279
2280 INSN(absr, 0, 0b100000101110, 1); // accepted arrangements: T8B, T16B, T4H, T8H, T4S
2281 INSN(negr, 1, 0b100000101110, 2); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D
2282 INSN(notr, 1, 0b100000010110, 0); // accepted arrangements: T8B, T16B
2283 INSN(addv, 0, 0b110001101110, 1); // accepted arrangements: T8B, T16B, T4H, T8H, T4S
2284 INSN(cls, 0, 0b100000010010, 1); // accepted arrangements: T8B, T16B, T4H, T8H, T4S
2285 INSN(clz, 1, 0b100000010010, 1); // accepted arrangements: T8B, T16B, T4H, T8H, T4S
2286 INSN(cnt, 0, 0b100000010110, 0); // accepted arrangements: T8B, T16B
2287 INSN(uaddlv, 1, 0b110000001110, 1); // accepted arrangements: T8B, T16B, T4H, T8H, T4S
2288
2289 #undef INSN
2290
2291 #define INSN(NAME, opc) \
2292 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn) { \
2293 starti; \
2294 assert(T == T4S, "arrangement must be T4S"); \
2295 f(0, 31), f((int)T & 1, 30), f(0b101110, 29, 24), f(opc, 23), \
2296 f(T == T4S ? 0 : 1, 22), f(0b110000111110, 21, 10); rf(Vn, 5), rf(Vd, 0); \
2297 }
2298
2299 INSN(fmaxv, 0);
2300 INSN(fminv, 1);
2301
2302 #undef INSN
2303
2304 #define INSN(NAME, op0, cmode0) \
2305 void NAME(FloatRegister Vd, SIMD_Arrangement T, unsigned imm8, unsigned lsl = 0) { \
2327 INSN(bici, 1, 1);
2328
2329 #undef INSN
2330
2331 #define INSN(NAME, op1, op2, op3) \
2332 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \
2333 starti; \
2334 assert(T == T2S || T == T4S || T == T2D, "invalid arrangement"); \
2335 f(0, 31), f((int)T & 1, 30), f(op1, 29), f(0b01110, 28, 24), f(op2, 23); \
2336 f(T==T2D ? 1:0, 22); f(1, 21), rf(Vm, 16), f(op3, 15, 10), rf(Vn, 5), rf(Vd, 0); \
2337 }
2338
2339 INSN(fadd, 0, 0, 0b110101);
2340 INSN(fdiv, 1, 0, 0b111111);
2341 INSN(fmul, 1, 0, 0b110111);
2342 INSN(fsub, 0, 1, 0b110101);
2343 INSN(fmla, 0, 0, 0b110011);
2344 INSN(fmls, 0, 1, 0b110011);
2345 INSN(fmax, 0, 0, 0b111101);
2346 INSN(fmin, 0, 1, 0b111101);
2347
2348 #undef INSN
2349
2350 #define INSN(NAME, opc) \
2351 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \
2352 starti; \
2353 assert(T == T4S, "arrangement must be T4S"); \
2354 f(0b01011110000, 31, 21), rf(Vm, 16), f(opc, 15, 10), rf(Vn, 5), rf(Vd, 0); \
2355 }
2356
2357 INSN(sha1c, 0b000000);
2358 INSN(sha1m, 0b001000);
2359 INSN(sha1p, 0b000100);
2360 INSN(sha1su0, 0b001100);
2361 INSN(sha256h2, 0b010100);
2362 INSN(sha256h, 0b010000);
2363 INSN(sha256su1, 0b011000);
2364
2365 #undef INSN
2366
2402 }
2403
2404 // FMLA/FMLS - Vector - Scalar
2405 INSN(fmlavs, 0, 0b0001);
2406 INSN(fmlsvs, 0, 0b0101);
2407 // FMULX - Vector - Scalar
2408 INSN(fmulxvs, 1, 0b1001);
2409
2410 #undef INSN
2411
2412 // Floating-point Reciprocal Estimate
2413 void frecpe(FloatRegister Vd, FloatRegister Vn, SIMD_RegVariant type) {
2414 assert(type == D || type == S, "Wrong type for frecpe");
2415 starti;
2416 f(0b010111101, 31, 23);
2417 f(type == D ? 1 : 0, 22);
2418 f(0b100001110110, 21, 10);
2419 rf(Vn, 5), rf(Vd, 0);
2420 }
2421
2422 // (double) {a, b} -> (a + b)
2423 void faddpd(FloatRegister Vd, FloatRegister Vn) {
2424 starti;
2425 f(0b0111111001110000110110, 31, 10);
2426 rf(Vn, 5), rf(Vd, 0);
2427 }
2428
2429 void ins(FloatRegister Vd, SIMD_RegVariant T, FloatRegister Vn, int didx, int sidx) {
2430 starti;
2431 assert(T != Q, "invalid register variant");
2432 f(0b01101110000, 31, 21), f(((didx<<1)|1)<<(int)T, 20, 16), f(0, 15);
2433 f(sidx<<(int)T, 14, 11), f(1, 10), rf(Vn, 5), rf(Vd, 0);
2434 }
2435
2436 void umov(Register Rd, FloatRegister Vn, SIMD_RegVariant T, int idx) {
2437 starti;
2438 f(0, 31), f(T==D ? 1:0, 30), f(0b001110000, 29, 21);
2439 f(((idx<<1)|1)<<(int)T, 20, 16), f(0b001111, 15, 10);
2440 rf(Vn, 5), rf(Rd, 0);
2441 }
2442
2443 #define INSN(NAME, opc, opc2, isSHR) \
2444 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, int shift){ \
2445 starti; \
2446 /* The encodings for the immh:immb fields (bits 22:16) in *SHR are \
2447 * 0001 xxx 8B/16B, shift = 16 - UInt(immh:immb) \
2448 * 001x xxx 4H/8H, shift = 32 - UInt(immh:immb) \
2449 * 01xx xxx 2S/4S, shift = 64 - UInt(immh:immb) \
2450 * 1xxx xxx 1D/2D, shift = 128 - UInt(immh:immb) \
2451 * (1D is RESERVED) \
2452 * for SHL shift is calculated as: \
2453 * 0001 xxx 8B/16B, shift = UInt(immh:immb) - 8 \
2454 * 001x xxx 4H/8H, shift = UInt(immh:immb) - 16 \
2455 * 01xx xxx 2S/4S, shift = UInt(immh:immb) - 32 \
2456 * 1xxx xxx 1D/2D, shift = UInt(immh:immb) - 64 \
2457 * (1D is RESERVED) \
2458 */ \
2459 assert((1 << ((T>>1)+3)) > shift, "Invalid Shift value"); \
2460 int cVal = (1 << (((T >> 1) + 3) + (isSHR ? 1 : 0))); \
2461 int encodedShift = isSHR ? cVal - shift : cVal + shift; \
2462 f(0, 31), f(T & 1, 30), f(opc, 29), f(0b011110, 28, 23), \
2463 f(encodedShift, 22, 16); f(opc2, 15, 10), rf(Vn, 5), rf(Vd, 0); \
2464 }
2465
2466 INSN(shl, 0, 0b010101, /* isSHR = */ false);
2467 INSN(sshr, 0, 0b000001, /* isSHR = */ true);
2468 INSN(ushr, 1, 0b000001, /* isSHR = */ true);
2469
2470 #undef INSN
2471
2472 private:
2473 void _ushll(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb, int shift) {
2474 starti;
2475 /* The encodings for the immh:immb fields (bits 22:16) are
2476 * 0001 xxx 8H, 8B/16b shift = xxx
2477 * 001x xxx 4S, 4H/8H shift = xxxx
2478 * 01xx xxx 2D, 2S/4S shift = xxxxx
2479 * 1xxx xxx RESERVED
2480 */
2481 assert((Tb >> 1) + 1 == (Ta >> 1), "Incompatible arrangement");
2482 assert((1 << ((Tb>>1)+3)) > shift, "Invalid shift value");
2483 f(0, 31), f(Tb & 1, 30), f(0b1011110, 29, 23), f((1 << ((Tb>>1)+3))|shift, 22, 16);
2484 f(0b101001, 15, 10), rf(Vn, 5), rf(Vd, 0);
2485 }
2486
2487 public:
2488 void ushll(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb, int shift) {
2489 assert(Tb == T8B || Tb == T4H || Tb == T2S, "invalid arrangement");
2490 _ushll(Vd, Ta, Vn, Tb, shift);
2491 }
2492
2493 void ushll2(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb, int shift) {
2494 assert(Tb == T16B || Tb == T8H || Tb == T4S, "invalid arrangement");
2495 _ushll(Vd, Ta, Vn, Tb, shift);
2496 }
2497
2498 // Move from general purpose register
2499 // mov Vd.T[index], Rn
2500 void mov(FloatRegister Vd, SIMD_Arrangement T, int index, Register Xn) {
2501 starti;
2502 f(0b01001110000, 31, 21), f(((1 << (T >> 1)) | (index << ((T >> 1) + 1))), 20, 16);
2503 f(0b000111, 15, 10), zrf(Xn, 5), rf(Vd, 0);
2504 }
2505
2506 // Move to general purpose register
2507 // mov Rd, Vn.T[index]
2508 void mov(Register Xd, FloatRegister Vn, SIMD_Arrangement T, int index) {
2509 guarantee(T >= T2S && T < T1Q, "only D and S arrangements are supported");
2510 starti;
2511 f(0, 31), f((T >= T1D) ? 1:0, 30), f(0b001110000, 29, 21);
2512 f(((1 << (T >> 1)) | (index << ((T >> 1) + 1))), 20, 16);
2513 f(0b001111, 15, 10), rf(Vn, 5), rf(Xd, 0);
2514 }
2515
2524 }
2525
2526 public:
2527 void pmull(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, FloatRegister Vm, SIMD_Arrangement Tb) {
2528 assert(Tb == T1D || Tb == T8B, "pmull assumes T1D or T8B as the second size specifier");
2529 _pmull(Vd, Ta, Vn, Vm, Tb);
2530 }
2531
2532 void pmull2(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, FloatRegister Vm, SIMD_Arrangement Tb) {
2533 assert(Tb == T2D || Tb == T16B, "pmull2 assumes T2D or T16B as the second size specifier");
2534 _pmull(Vd, Ta, Vn, Vm, Tb);
2535 }
2536
2537 void uqxtn(FloatRegister Vd, SIMD_Arrangement Tb, FloatRegister Vn, SIMD_Arrangement Ta) {
2538 starti;
2539 int size_b = (int)Tb >> 1;
2540 int size_a = (int)Ta >> 1;
2541 assert(size_b < 3 && size_b == size_a - 1, "Invalid size specifier");
2542 f(0, 31), f(Tb & 1, 30), f(0b101110, 29, 24), f(size_b, 23, 22);
2543 f(0b100001010010, 21, 10), rf(Vn, 5), rf(Vd, 0);
2544 }
2545
2546 void dup(FloatRegister Vd, SIMD_Arrangement T, Register Xs)
2547 {
2548 starti;
2549 assert(T != T1D, "reserved encoding");
2550 f(0,31), f((int)T & 1, 30), f(0b001110000, 29, 21);
2551 f((1 << (T >> 1)), 20, 16), f(0b000011, 15, 10), zrf(Xs, 5), rf(Vd, 0);
2552 }
2553
2554 void dup(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, int index = 0)
2555 {
2556 starti;
2557 assert(T != T1D, "reserved encoding");
2558 f(0, 31), f((int)T & 1, 30), f(0b001110000, 29, 21);
2559 f(((1 << (T >> 1)) | (index << ((T >> 1) + 1))), 20, 16);
2560 f(0b000001, 15, 10), rf(Vn, 5), rf(Vd, 0);
2561 }
2562
2563 // 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 == 2) guarantee(T != T2D, "incorrect arrangement"); \
2354 if (accepted == 1) guarantee(T != T2S && T != T2D, "incorrect arrangement"); \
2355 if (accepted == 0) 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(uaddlv, 1, 0b110000001110, 1); // accepted arrangements: T8B, T16B, T4H, T8H, T4S
2372
2373 #undef INSN
2374
2375 #define INSN(NAME, opc) \
2376 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn) { \
2377 starti; \
2378 assert(T == T4S, "arrangement must be T4S"); \
2379 f(0, 31), f((int)T & 1, 30), f(0b101110, 29, 24), f(opc, 23), \
2380 f(T == T4S ? 0 : 1, 22), f(0b110000111110, 21, 10); rf(Vn, 5), rf(Vd, 0); \
2381 }
2382
2383 INSN(fmaxv, 0);
2384 INSN(fminv, 1);
2385
2386 #undef INSN
2387
2388 #define INSN(NAME, op0, cmode0) \
2389 void NAME(FloatRegister Vd, SIMD_Arrangement T, unsigned imm8, unsigned lsl = 0) { \
2411 INSN(bici, 1, 1);
2412
2413 #undef INSN
2414
2415 #define INSN(NAME, op1, op2, op3) \
2416 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \
2417 starti; \
2418 assert(T == T2S || T == T4S || T == T2D, "invalid arrangement"); \
2419 f(0, 31), f((int)T & 1, 30), f(op1, 29), f(0b01110, 28, 24), f(op2, 23); \
2420 f(T==T2D ? 1:0, 22); f(1, 21), rf(Vm, 16), f(op3, 15, 10), rf(Vn, 5), rf(Vd, 0); \
2421 }
2422
2423 INSN(fadd, 0, 0, 0b110101);
2424 INSN(fdiv, 1, 0, 0b111111);
2425 INSN(fmul, 1, 0, 0b110111);
2426 INSN(fsub, 0, 1, 0b110101);
2427 INSN(fmla, 0, 0, 0b110011);
2428 INSN(fmls, 0, 1, 0b110011);
2429 INSN(fmax, 0, 0, 0b111101);
2430 INSN(fmin, 0, 1, 0b111101);
2431 INSN(fcmeq, 0, 0, 0b111001);
2432 INSN(fcmgt, 1, 1, 0b111001);
2433 INSN(fcmge, 1, 0, 0b111001);
2434
2435 #undef INSN
2436
2437 #define INSN(NAME, opc) \
2438 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \
2439 starti; \
2440 assert(T == T4S, "arrangement must be T4S"); \
2441 f(0b01011110000, 31, 21), rf(Vm, 16), f(opc, 15, 10), rf(Vn, 5), rf(Vd, 0); \
2442 }
2443
2444 INSN(sha1c, 0b000000);
2445 INSN(sha1m, 0b001000);
2446 INSN(sha1p, 0b000100);
2447 INSN(sha1su0, 0b001100);
2448 INSN(sha256h2, 0b010100);
2449 INSN(sha256h, 0b010000);
2450 INSN(sha256su1, 0b011000);
2451
2452 #undef INSN
2453
2489 }
2490
2491 // FMLA/FMLS - Vector - Scalar
2492 INSN(fmlavs, 0, 0b0001);
2493 INSN(fmlsvs, 0, 0b0101);
2494 // FMULX - Vector - Scalar
2495 INSN(fmulxvs, 1, 0b1001);
2496
2497 #undef INSN
2498
2499 // Floating-point Reciprocal Estimate
2500 void frecpe(FloatRegister Vd, FloatRegister Vn, SIMD_RegVariant type) {
2501 assert(type == D || type == S, "Wrong type for frecpe");
2502 starti;
2503 f(0b010111101, 31, 23);
2504 f(type == D ? 1 : 0, 22);
2505 f(0b100001110110, 21, 10);
2506 rf(Vn, 5), rf(Vd, 0);
2507 }
2508
2509 // (long) {a, b} -> (a + b)
2510 void addpd(FloatRegister Vd, FloatRegister Vn) {
2511 starti;
2512 f(0b0101111011110001101110, 31, 10);
2513 rf(Vn, 5), rf(Vd, 0);
2514 }
2515
2516 // (Floating-point) {a, b} -> (a + b)
2517 void faddp(FloatRegister Vd, FloatRegister Vn, SIMD_RegVariant type) {
2518 assert(type == D || type == S, "Wrong type for faddp");
2519 starti;
2520 f(0b011111100, 31, 23);
2521 f(type == D ? 1 : 0, 22);
2522 f(0b110000110110, 21, 10);
2523 rf(Vn, 5), rf(Vd, 0);
2524 }
2525
2526 void ins(FloatRegister Vd, SIMD_RegVariant T, FloatRegister Vn, int didx, int sidx) {
2527 starti;
2528 assert(T != Q, "invalid register variant");
2529 f(0b01101110000, 31, 21), f(((didx<<1)|1)<<(int)T, 20, 16), f(0, 15);
2530 f(sidx<<(int)T, 14, 11), f(1, 10), rf(Vn, 5), rf(Vd, 0);
2531 }
2532
2533 void umov(Register Rd, FloatRegister Vn, SIMD_RegVariant T, int idx) {
2534 starti;
2535 f(0, 31), f(T==D ? 1:0, 30), f(0b001110000, 29, 21);
2536 f(((idx<<1)|1)<<(int)T, 20, 16), f(0b001111, 15, 10);
2537 rf(Vn, 5), rf(Rd, 0);
2538 }
2539
2540 void smov(Register Rd, FloatRegister Vn, SIMD_RegVariant T, int idx) {
2541 starti;
2542 f(0, 31), f(T==D ? 1:0, 30), f(0b001110000, 29, 21);
2543 f(((idx<<1)|1)<<(int)T, 20, 16), f(0b001011, 15, 10);
2544 rf(Vn, 5), rf(Rd, 0);
2545 }
2546
2547
2548 #define INSN(NAME, opc, opc2, isSHR) \
2549 void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, int shift){ \
2550 starti; \
2551 /* The encodings for the immh:immb fields (bits 22:16) in *SHR are \
2552 * 0001 xxx 8B/16B, shift = 16 - UInt(immh:immb) \
2553 * 001x xxx 4H/8H, shift = 32 - UInt(immh:immb) \
2554 * 01xx xxx 2S/4S, shift = 64 - UInt(immh:immb) \
2555 * 1xxx xxx 1D/2D, shift = 128 - UInt(immh:immb) \
2556 * (1D is RESERVED) \
2557 * for SHL shift is calculated as: \
2558 * 0001 xxx 8B/16B, shift = UInt(immh:immb) - 8 \
2559 * 001x xxx 4H/8H, shift = UInt(immh:immb) - 16 \
2560 * 01xx xxx 2S/4S, shift = UInt(immh:immb) - 32 \
2561 * 1xxx xxx 1D/2D, shift = UInt(immh:immb) - 64 \
2562 * (1D is RESERVED) \
2563 */ \
2564 assert((1 << ((T>>1)+3)) > shift, "Invalid Shift value"); \
2565 int cVal = (1 << (((T >> 1) + 3) + (isSHR ? 1 : 0))); \
2566 int encodedShift = isSHR ? cVal - shift : cVal + shift; \
2567 f(0, 31), f(T & 1, 30), f(opc, 29), f(0b011110, 28, 23), \
2568 f(encodedShift, 22, 16); f(opc2, 15, 10), rf(Vn, 5), rf(Vd, 0); \
2569 }
2570
2571 INSN(shl, 0, 0b010101, /* isSHR = */ false);
2572 INSN(sshr, 0, 0b000001, /* isSHR = */ true);
2573 INSN(ushr, 1, 0b000001, /* isSHR = */ true);
2574
2575 #undef INSN
2576
2577 private:
2578 void _xshll(sign_kind sign, FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb, int shift) {
2579 starti;
2580 /* The encodings for the immh:immb fields (bits 22:16) are
2581 * 0001 xxx 8H, 8B/16B shift = xxx
2582 * 001x xxx 4S, 4H/8H shift = xxxx
2583 * 01xx xxx 2D, 2S/4S shift = xxxxx
2584 * 1xxx xxx RESERVED
2585 */
2586 assert((Tb >> 1) + 1 == (Ta >> 1), "Incompatible arrangement");
2587 assert((1 << ((Tb>>1)+3)) > shift, "Invalid shift value");
2588 f(0, 31), f(Tb & 1, 30), f(sign == SIGNED ? 0 : 1, 29), f(0b011110, 28, 23);
2589 f((1 << ((Tb>>1)+3))|shift, 22, 16);
2590 f(0b101001, 15, 10), rf(Vn, 5), rf(Vd, 0);
2591 }
2592
2593 public:
2594 void ushll(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb, int shift) {
2595 assert(Tb == T8B || Tb == T4H || Tb == T2S, "invalid arrangement");
2596 _xshll(UNSIGNED, Vd, Ta, Vn, Tb, shift);
2597 }
2598
2599 void ushll2(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb, int shift) {
2600 assert(Tb == T16B || Tb == T8H || Tb == T4S, "invalid arrangement");
2601 _xshll(UNSIGNED, Vd, Ta, Vn, Tb, shift);
2602 }
2603
2604 void uxtl(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb) {
2605 ushll(Vd, Ta, Vn, Tb, 0);
2606 }
2607
2608 void sshll(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb, int shift) {
2609 assert(Tb == T8B || Tb == T4H || Tb == T2S, "invalid arrangement");
2610 _xshll(SIGNED, Vd, Ta, Vn, Tb, shift);
2611 }
2612
2613 void sshll2(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb, int shift) {
2614 assert(Tb == T16B || Tb == T8H || Tb == T4S, "invalid arrangement");
2615 _xshll(SIGNED, Vd, Ta, Vn, Tb, shift);
2616 }
2617
2618 void sxtl(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb) {
2619 sshll(Vd, Ta, Vn, Tb, 0);
2620 }
2621
2622 // Move from general purpose register
2623 // mov Vd.T[index], Rn
2624 void mov(FloatRegister Vd, SIMD_Arrangement T, int index, Register Xn) {
2625 starti;
2626 f(0b01001110000, 31, 21), f(((1 << (T >> 1)) | (index << ((T >> 1) + 1))), 20, 16);
2627 f(0b000111, 15, 10), zrf(Xn, 5), rf(Vd, 0);
2628 }
2629
2630 // Move to general purpose register
2631 // mov Rd, Vn.T[index]
2632 void mov(Register Xd, FloatRegister Vn, SIMD_Arrangement T, int index) {
2633 guarantee(T >= T2S && T < T1Q, "only D and S arrangements are supported");
2634 starti;
2635 f(0, 31), f((T >= T1D) ? 1:0, 30), f(0b001110000, 29, 21);
2636 f(((1 << (T >> 1)) | (index << ((T >> 1) + 1))), 20, 16);
2637 f(0b001111, 15, 10), rf(Vn, 5), rf(Xd, 0);
2638 }
2639
2648 }
2649
2650 public:
2651 void pmull(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, FloatRegister Vm, SIMD_Arrangement Tb) {
2652 assert(Tb == T1D || Tb == T8B, "pmull assumes T1D or T8B as the second size specifier");
2653 _pmull(Vd, Ta, Vn, Vm, Tb);
2654 }
2655
2656 void pmull2(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, FloatRegister Vm, SIMD_Arrangement Tb) {
2657 assert(Tb == T2D || Tb == T16B, "pmull2 assumes T2D or T16B as the second size specifier");
2658 _pmull(Vd, Ta, Vn, Vm, Tb);
2659 }
2660
2661 void uqxtn(FloatRegister Vd, SIMD_Arrangement Tb, FloatRegister Vn, SIMD_Arrangement Ta) {
2662 starti;
2663 int size_b = (int)Tb >> 1;
2664 int size_a = (int)Ta >> 1;
2665 assert(size_b < 3 && size_b == size_a - 1, "Invalid size specifier");
2666 f(0, 31), f(Tb & 1, 30), f(0b101110, 29, 24), f(size_b, 23, 22);
2667 f(0b100001010010, 21, 10), rf(Vn, 5), rf(Vd, 0);
2668 }
2669
2670 void xtn(FloatRegister Vd, SIMD_Arrangement Tb, FloatRegister Vn, SIMD_Arrangement Ta) {
2671 starti;
2672 int size_b = (int)Tb >> 1;
2673 int size_a = (int)Ta >> 1;
2674 assert(size_b < 3 && size_b == size_a - 1, "Invalid size specifier");
2675 f(0, 31), f(Tb & 1, 30), f(0b001110, 29, 24), f(size_b, 23, 22);
2676 f(0b100001001010, 21, 10), rf(Vn, 5), rf(Vd, 0);
2677 }
2678
2679 void dup(FloatRegister Vd, SIMD_Arrangement T, Register Xs)
2680 {
2681 starti;
2682 assert(T != T1D, "reserved encoding");
2683 f(0,31), f((int)T & 1, 30), f(0b001110000, 29, 21);
2684 f((1 << (T >> 1)), 20, 16), f(0b000011, 15, 10), zrf(Xs, 5), rf(Vd, 0);
2685 }
2686
2687 void dup(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, int index = 0)
2688 {
2689 starti;
2690 assert(T != T1D, "reserved encoding");
2691 f(0, 31), f((int)T & 1, 30), f(0b001110000, 29, 21);
2692 f(((1 << (T >> 1)) | (index << ((T >> 1) + 1))), 20, 16);
2693 f(0b000001, 15, 10), rf(Vn, 5), rf(Vd, 0);
2694 }
2695
2696 // AdvSIMD ZIP/UZP/TRN
|