Some VFPU instructions do not support certain overlaps between source and destination registers. Return an error whenever the overlap is not acceptable for a given instruction and register pair.
Add more VFPU vector instructions with prefix register overlap decorators. Signed-off-by: David Guillen Fandos <[email protected]> --- gas/config/tc-mips.c | 80 ++++++++++++++++++- gas/testsuite/gas/mips/allegrex-vfpu-errors.l | 38 +++++++++ gas/testsuite/gas/mips/allegrex-vfpu-errors.s | 39 +++++++++ gas/testsuite/gas/mips/allegrex-vfpu.d | 51 ++++++++++++ gas/testsuite/gas/mips/allegrex-vfpu.s | 52 ++++++++++++ include/opcode/mips.h | 19 ++++- opcodes/mips-formats.h | 30 ++++--- opcodes/mips-opc.c | 63 ++++++++++++++- 8 files changed, 353 insertions(+), 19 deletions(-) diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index 930edceb6ec..79afc9fc9b1 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -106,7 +106,7 @@ static char *mips_flags_frag; #define FCSR 31 -#define ILLEGAL_REG (32) +#define ILLEGAL_REG (~0U) #define AT mips_opts.at @@ -6819,6 +6819,52 @@ match_vu0_suffix_operand (struct mips_arg_info *arg, return true; } +/* Returns whether a pair of dest/src registers are compatible. */ +static bfd_boolean +vfpu_reg_is_compat (unsigned int dst_reg, unsigned int dst_rsize, + unsigned int src_reg, unsigned int src_rsize, + bool accept_partial) +{ + static const unsigned short vreg_usage[4][16] = { + { 0x0001, 0x0010, 0x0100, 0x1000, + 0x0002, 0x0020, 0x0200, 0x2000, + 0x0004, 0x0040, 0x0400, 0x4000, + 0x0008, 0x0080, 0x0800, 0x8000 }, + { 0x0003, 0x0030, 0x0300, 0x3000, + 0x0011, 0x0022, 0x0044, 0x0088, + 0x000c, 0x00c0, 0x0c00, 0xc000, + 0x1100, 0x2200, 0x4400, 0x8800 }, + { 0x0007, 0x0070, 0x0700, 0x7000, + 0x0111, 0x0222, 0x0444, 0x0888, + 0x000e, 0x00e0, 0x0e00, 0xe000, + 0x1110, 0x2220, 0x4440, 0x8880 }, + { 0x000f, 0x00f0, 0x0f00, 0xf000, + 0x1111, 0x2222, 0x4444, 0x8888, + 0x000f, 0x00f0, 0x0f00, 0xf000, + 0x1111, 0x2222, 0x4444, 0x8888 }, + }; + + unsigned int dmtx = (dst_reg >> 2) & 7; + unsigned int smtx = (src_reg >> 2) & 7; + if (dmtx == smtx) + { + unsigned int sidx = src_reg & 3; + unsigned int didx = dst_reg & 3; + unsigned int sfsl = (src_reg >> 5) & 3; + unsigned int dfsl = (dst_reg >> 5) & 3; + unsigned int dmap = vreg_usage[dst_rsize][(dfsl << 2) | didx]; + unsigned int smap = vreg_usage[src_rsize][(sfsl << 2) | sidx]; + + if (dmap & smap) { + /* There's overlap, if partial is allowed, check for compatibility. */ + return (accept_partial && dmap == smap + && ((src_reg & 0x32) == (dst_reg & 0x32))); + } + } + return true; +} + + /* Generates a VFPU prefix immediate for a given reg type and size. */ static bfd_boolean calculate_vfpu_prefix_imm (struct mips_arg_info *arg, @@ -6915,6 +6961,7 @@ match_vfpu_reg_operand (struct mips_arg_info *arg, { const struct mips_vfpu_reg_operand *regvfpuop; enum mips_vfpu_reg_shape rshape; + enum mips_vfpu_reg_type rtype; unsigned int uval = arg->token->u.reg_vfpu.regno; /* Validate register type, to ensure we use the right register prefix */ @@ -6931,8 +6978,9 @@ match_vfpu_reg_operand (struct mips_arg_info *arg, if (arg->token->type != OT_REG_VFPU || uval >= 128) return false; - rshape = arg->token->u.reg_vfpu.shape; regvfpuop = (struct mips_vfpu_reg_operand*)operand; + rshape = arg->token->u.reg_vfpu.shape; + rtype = regvfpuop->regtype; if (rshape != val_shap[regvfpuop->rsize].gen && rshape != val_shap[regvfpuop->rsize].spc) @@ -6943,6 +6991,31 @@ match_vfpu_reg_operand (struct mips_arg_info *arg, return false; } + if (rtype == OP_VFPU_REG_D && regvfpuop->regcompat != OP_VFPU_REGCOMPAT_ALL) + { + arg->dest_regno = uval | (regvfpuop->rsize << 8); + if (regvfpuop->regcompat == OP_VFPU_REGCOMPAT_SAME) + arg->dest_regno |= 0x8000; + } + + if ((rtype == OP_VFPU_REG_S || rtype == OP_VFPU_REG_T) + && (arg->dest_regno != ILLEGAL_REG)) + { + /* The destination register could be incompatible with source regs. */ + unsigned int dreg = arg->dest_regno & 0x7f; + unsigned int drsize = (arg->dest_regno >> 8) & 3; + bool canpartial = arg->dest_regno & 0x8000; + + if (!vfpu_reg_is_compat (dreg, drsize, uval, regvfpuop->rsize, canpartial)) + { + set_insn_error_ss(arg->argnum, + "Invalid dest and %s register overlap (%s is allowed)", + rtype == OP_VFPU_REG_S ? "source" : "target", + canpartial ? "identical overlap" : "no overlap"); + return false; + } + } + insn_insert_operand (arg->insn, operand, uval); ++arg->token; @@ -6954,7 +7027,6 @@ match_vfpu_reg_operand (struct mips_arg_info *arg, struct mips_opcode *pop; bfd_reloc_code_real_type unused_reloc[3] = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED}; - enum mips_vfpu_reg_type rtype = regvfpuop->regtype; const char *pfxmemo = rtype == OP_VFPU_REG_S ? "vpfxs" : rtype == OP_VFPU_REG_T ? "vpfxt" : "vpfxd"; @@ -6977,7 +7049,7 @@ match_vfpu_reg_operand (struct mips_arg_info *arg, pop = (struct mips_opcode *) str_hash_find (op_hash, pfxmemo); create_insn (&pfxinstr, pop); - if (!calculate_vfpu_prefix_imm (arg, regvfpuop->regtype, regvfpuop->rsize, + if (!calculate_vfpu_prefix_imm (arg, rtype, regvfpuop->rsize, pfx_lim, &imm24)) return false; diff --git a/gas/testsuite/gas/mips/allegrex-vfpu-errors.l b/gas/testsuite/gas/mips/allegrex-vfpu-errors.l index 497e7f8aed6..0c113567857 100644 --- a/gas/testsuite/gas/mips/allegrex-vfpu-errors.l +++ b/gas/testsuite/gas/mips/allegrex-vfpu-errors.l @@ -20,3 +20,41 @@ .*:22: Error: invalid source prefix \(only swizzle allowed\) `vabs.q R000,R000\[0,x,x,x\]' .*:23: Error: invalid source prefix \(only swizzle allowed\) `vneg.q R000,R000\[0,x,x,x\]' .*:24: Error: invalid source prefix \(only swizzle allowed\) `vt4444.q R000,R000\[-x,x,x,x\]' +.*:25: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vsin.p C000,R000' +.*:26: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vsin.t R000,R010' +.*:27: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vsin.q C000,R000' +.*:28: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vasin.p C100,R100' +.*:29: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vasin.t R100,R110' +.*:30: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vasin.q C100,R100' +.*:31: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vnsin.p C200,R200' +.*:32: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vnsin.t R200,R210' +.*:33: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vnsin.q C200,R200' +.*:34: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vcos.p C700,R700' +.*:35: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vcos.t R700,R710' +.*:36: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vcos.q C700,R700' +.*:37: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vrcp.p C600,R600' +.*:38: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vrcp.t R600,R610' +.*:39: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vrcp.q C600,R600' +.*:40: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vrsq.p C000,R000' +.*:41: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vrsq.t R000,R010' +.*:42: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vrsq.q C000,R000' +.*:43: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vnrcp.p C000,R000' +.*:44: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vnrcp.t R000,R010' +.*:45: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vnrcp.q C000,R000' +.*:46: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vexp2.p C000,R000' +.*:47: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vexp2.t R000,R010' +.*:48: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vexp2.q C000,R000' +.*:49: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vrexp2.p C000,R000' +.*:50: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vrexp2.t R000,R010' +.*:51: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vrexp2.q C000,R000' +.*:52: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vlog2.p C000,R000' +.*:53: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vlog2.t R000,R010' +.*:54: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vlog2.q C000,R000' +.*:55: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vsqrt.p C000,R000' +.*:56: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vsqrt.t R000,R010' +.*:57: Error: Invalid dest and source register overlap \(identical overlap is allowed\) `vsqrt.q C000,R000' +.*:58: Error: Invalid dest and target register overlap \(identical overlap is allowed\) `vdiv.p C000,C000,R000' +.*:59: Error: Invalid dest and target register overlap \(identical overlap is allowed\) `vdiv.t C000,C000,R000' +.*:60: Error: Invalid dest and target register overlap \(identical overlap is allowed\) `vdiv.q C000,C000,R000' +.*:61: Error: Invalid dest and source register overlap \(no overlap is allowed\) `vcrsp.t R000,R000,R100' +.*:62: Error: Invalid dest and source register overlap \(no overlap is allowed\) `vqmul.q R000,R000,R100' diff --git a/gas/testsuite/gas/mips/allegrex-vfpu-errors.s b/gas/testsuite/gas/mips/allegrex-vfpu-errors.s index 67024c61348..25193f0ac4a 100644 --- a/gas/testsuite/gas/mips/allegrex-vfpu-errors.s +++ b/gas/testsuite/gas/mips/allegrex-vfpu-errors.s @@ -22,6 +22,45 @@ vabs.q R000, R000[0,x,x,x] vneg.q R000, R000[0,x,x,x] vt4444.q R000, R000[-x,x,x,x] + vsin.p C000, R000 + vsin.t R000, R010 + vsin.q C000, R000 + vasin.p C100, R100 + vasin.t R100, R110 + vasin.q C100, R100 + vnsin.p C200, R200 + vnsin.t R200, R210 + vnsin.q C200, R200 + vcos.p C700, R700 + vcos.t R700, R710 + vcos.q C700, R700 + vrcp.p C600, R600 + vrcp.t R600, R610 + vrcp.q C600, R600 + vrsq.p C000, R000 + vrsq.t R000, R010 + vrsq.q C000, R000 + vnrcp.p C000, R000 + vnrcp.t R000, R010 + vnrcp.q C000, R000 + vexp2.p C000, R000 + vexp2.t R000, R010 + vexp2.q C000, R000 + vrexp2.p C000, R000 + vrexp2.t R000, R010 + vrexp2.q C000, R000 + vlog2.p C000, R000 + vlog2.t R000, R010 + vlog2.q C000, R000 + vsqrt.p C000, R000 + vsqrt.t R000, R010 + vsqrt.q C000, R000 + vdiv.p C000, C000, R000 + vdiv.t C000, C000, R000 + vdiv.q C000, C000, R000 + vcrsp.t R000, R000, R100 + vqmul.q R000, R000, R100 + # Force some (non-delay-slot) zero bytes, to make 'objdump' print ... .align 4, 0 diff --git a/gas/testsuite/gas/mips/allegrex-vfpu.d b/gas/testsuite/gas/mips/allegrex-vfpu.d index ce91768e006..277b65707f7 100644 --- a/gas/testsuite/gas/mips/allegrex-vfpu.d +++ b/gas/testsuite/gas/mips/allegrex-vfpu.d @@ -128,4 +128,55 @@ Disassembly of section .text: 0x000001dc de000100 vpfxd m,,, 0x000001e0 dc000050 vpfxs x,x,y,y 0x000001e4 d03ea0a0 vi2us.q R000.p,R000.q +0x000001e8 d0171717 vasin.s S530.s,S530.s +0x000001ec d01764e4 vasin.p R120.p,R120.p +0x000001f0 d017e464 vasin.t R110.t,R110.t +0x000001f4 d017a4a4 vasin.q R100.q,R100.q +0x000001f8 d0131717 vcos.s S530.s,S530.s +0x000001fc d01364e4 vcos.p R120.p,R120.p +0x00000200 d013e464 vcos.t R110.t,R110.t +0x00000204 d013a4a4 vcos.q R100.q,R100.q +0x00000208 f2e6e564 vcrsp.t R110.t,R111.t,R112.t +0x0000020c 6684a404 vcrs.t C100.t,R100.t,C100.t +0x00000210 63971717 vdiv.s S530.s,S530.s,S530.s +0x00000214 63e464e4 vdiv.p R120.p,R120.p,R120.p +0x00000218 63e4e464 vdiv.t R110.t,R110.t,R110.t +0x0000021c 63a4a4a4 vdiv.q R100.q,R100.q,R100.q +0x00000220 d0141717 vexp2.s S530.s,S530.s +0x00000224 d01464e4 vexp2.p R120.p,R120.p +0x00000228 d014e464 vexp2.t R110.t,R110.t +0x0000022c d014a4a4 vexp2.q R100.q,R100.q +0x00000230 d0151717 vlog2.s S530.s,S530.s +0x00000234 d01564e4 vlog2.p R120.p,R120.p +0x00000238 d015e464 vlog2.t R110.t,R110.t +0x0000023c d015a4a4 vlog2.q R100.q,R100.q +0x00000240 d0181717 vnrcp.s S530.s,S530.s +0x00000244 d01864e4 vnrcp.p R120.p,R120.p +0x00000248 d018e464 vnrcp.t R110.t,R110.t +0x0000024c d018a4a4 vnrcp.q R100.q,R100.q +0x00000250 d01a1717 vnsin.s S530.s,S530.s +0x00000254 d01a64e4 vnsin.p R120.p,R120.p +0x00000258 d01ae464 vnsin.t R110.t,R110.t +0x0000025c d01aa4a4 vnsin.q R100.q,R100.q +0x00000260 f2a8a0a4 vqmul.q R100.q,R000.q,R200.q +0x00000264 d0101717 vrcp.s S530.s,S530.s +0x00000268 d01064e4 vrcp.p R120.p,R120.p +0x0000026c d010e464 vrcp.t R110.t,R110.t +0x00000270 d010a4a4 vrcp.q R100.q,R100.q +0x00000274 d01c1717 vrexp2.s S530.s,S530.s +0x00000278 d01c64e4 vrexp2.p R120.p,R120.p +0x0000027c d01ce464 vrexp2.t R110.t,R110.t +0x00000280 d01ca4a4 vrexp2.q R100.q,R100.q +0x00000284 d0111717 vrsq.s S530.s,S530.s +0x00000288 d01164e4 vrsq.p R120.p,R120.p +0x0000028c d011e464 vrsq.t R110.t,R110.t +0x00000290 d011a4a4 vrsq.q R100.q,R100.q +0x00000294 d0121717 vsin.s S530.s,S530.s +0x00000298 d01264e4 vsin.p R120.p,R120.p +0x0000029c d012e464 vsin.t R110.t,R110.t +0x000002a0 d012a4a4 vsin.q R100.q,R100.q +0x000002a4 d0161717 vsqrt.s S530.s,S530.s +0x000002a8 d01664e4 vsqrt.p R120.p,R120.p +0x000002ac d016e464 vsqrt.t R110.t,R110.t +0x000002b0 d016a4a4 vsqrt.q R100.q,R100.q \.\.\. diff --git a/gas/testsuite/gas/mips/allegrex-vfpu.s b/gas/testsuite/gas/mips/allegrex-vfpu.s index c40acb84ca9..1bba03ca974 100644 --- a/gas/testsuite/gas/mips/allegrex-vfpu.s +++ b/gas/testsuite/gas/mips/allegrex-vfpu.s @@ -114,6 +114,58 @@ vt5650.q R000, R000[w,z,y,x] vi2us.q R000[m,], R000[x,x,y,y] + vasin.s S530, S530 + vasin.p R120, R120 + vasin.t R110, R110 + vasin.q R100, R100 + vcos.s S530, S530 + vcos.p R120, R120 + vcos.t R110, R110 + vcos.q R100, R100 + vcrsp.t R110, R111, R112 + vcrs.t C100, R100, C100 + vdiv.s S530, S530, S530 + vdiv.p R120, R120, R120 + vdiv.t R110, R110, R110 + vdiv.q R100, R100, R100 + vexp2.s S530, S530 + vexp2.p R120, R120 + vexp2.t R110, R110 + vexp2.q R100, R100 + vlog2.s S530, S530 + vlog2.p R120, R120 + vlog2.t R110, R110 + vlog2.q R100, R100 + vnrcp.s S530, S530 + vnrcp.p R120, R120 + vnrcp.t R110, R110 + vnrcp.q R100, R100 + vnsin.s S530, S530 + vnsin.p R120, R120 + vnsin.t R110, R110 + vnsin.q R100, R100 + vqmul.q R100, R000, R200 + vrcp.s S530, S530 + vrcp.p R120, R120 + vrcp.t R110, R110 + vrcp.q R100, R100 + vrexp2.s S530, S530 + vrexp2.p R120, R120 + vrexp2.t R110, R110 + vrexp2.q R100, R100 + vrsq.s S530, S530 + vrsq.p R120, R120 + vrsq.t R110, R110 + vrsq.q R100, R100 + vsin.s S530, S530 + vsin.p R120, R120 + vsin.t R110, R110 + vsin.q R100, R100 + vsqrt.s S530, S530 + vsqrt.p R120, R120 + vsqrt.t R110, R110 + vsqrt.q R100, R100 + # Force some (non-delay-slot) zero bytes, to make 'objdump' print ... .align 4, 0 .space 16 diff --git a/include/opcode/mips.h b/include/opcode/mips.h index 0a8f1fd0f1c..b90f8ea33f7 100644 --- a/include/opcode/mips.h +++ b/include/opcode/mips.h @@ -264,6 +264,18 @@ enum mips_vfpu_regpfx_compat { OP_VFPU_PFXCOMPAT_LIMITED }; +/* Enumerates the types of VFPU register-register compatibility. */ +enum mips_vfpu_regdst_compat { + /* All registers are allowed. */ + OP_VFPU_REGCOMPAT_ALL, + + /* Identical overlap is allowed. */ + OP_VFPU_REGCOMPAT_SAME, + + /* No overlap whatsover is allowed. */ + OP_VFPU_REGCOMPAT_NONE +}; + /* Base class for all operands. */ struct mips_operand @@ -408,11 +420,14 @@ struct mips_vfpu_reg_operand /* Register (sub)type. */ enum mips_vfpu_reg_type regtype; + /* Register access size. */ + unsigned int rsize; + /* Register-prefix compatibility. */ enum mips_vfpu_regpfx_compat pfxcompat; - /* Register access size. */ - unsigned int rsize; + /* Register-register compatibility. */ + enum mips_vfpu_regdst_compat regcompat; }; /* Return true if the assembly syntax allows OPERAND to be omitted. */ diff --git a/opcodes/mips-formats.h b/opcodes/mips-formats.h index 00e11de1fad..9d91d83b730 100644 --- a/opcodes/mips-formats.h +++ b/opcodes/mips-formats.h @@ -112,34 +112,44 @@ return &op.root; \ } -#define VFPU_REGEXP(OP, SIZE, LSB, RTYPE, RSIZE, PFXCOMPAT) \ +#define VFPU_REGEXP(OP, SIZE, LSB, RTYPE, RSIZE, PFX_COMPAT, REG_COMPAT) \ { \ static const struct mips_vfpu_reg_operand op[] = { \ - { { OP_VFPU_##OP, SIZE, LSB }, OP_VFPU_REG_##RTYPE, PFXCOMPAT, 0 }, \ - { { OP_VFPU_##OP, SIZE, LSB }, OP_VFPU_REG_##RTYPE, PFXCOMPAT, 1 }, \ - { { OP_VFPU_##OP, SIZE, LSB }, OP_VFPU_REG_##RTYPE, PFXCOMPAT, 2 }, \ - { { OP_VFPU_##OP, SIZE, LSB }, OP_VFPU_REG_##RTYPE, PFXCOMPAT, 3 }, \ + { { OP_VFPU_##OP, SIZE, LSB }, OP_VFPU_REG_##RTYPE, 0, \ + OP_VFPU_PFXCOMPAT_##PFX_COMPAT, OP_VFPU_REGCOMPAT_##REG_COMPAT}, \ + { { OP_VFPU_##OP, SIZE, LSB }, OP_VFPU_REG_##RTYPE, 1, \ + OP_VFPU_PFXCOMPAT_##PFX_COMPAT, OP_VFPU_REGCOMPAT_##REG_COMPAT}, \ + { { OP_VFPU_##OP, SIZE, LSB }, OP_VFPU_REG_##RTYPE, 2, \ + OP_VFPU_PFXCOMPAT_##PFX_COMPAT, OP_VFPU_REGCOMPAT_##REG_COMPAT}, \ + { { OP_VFPU_##OP, SIZE, LSB }, OP_VFPU_REG_##RTYPE, 3, \ + OP_VFPU_PFXCOMPAT_##PFX_COMPAT, OP_VFPU_REGCOMPAT_##REG_COMPAT}, \ }; \ return &op[RSIZE].root; \ } -#define VFPU_REG(SIZE, LSB, RTYPE, RSIZE, PFX_COMPAT) \ +#define VFPU_REG(SIZE, LSB, RTYPE, RSIZE, PFX_COMPAT, REG_COMPAT) \ { \ switch (PFX_COMPAT) \ { \ case 'a': \ - VFPU_REGEXP(REG, SIZE, LSB, RTYPE, RSIZE, OP_VFPU_PFXCOMPAT_ALL) \ + VFPU_REGEXP(REG, SIZE, LSB, RTYPE, RSIZE, ALL, REG_COMPAT) \ case 'n': \ - VFPU_REGEXP(REG, SIZE, LSB, RTYPE, RSIZE, OP_VFPU_PFXCOMPAT_NONE) \ + VFPU_REGEXP(REG, SIZE, LSB, RTYPE, RSIZE, NONE, REG_COMPAT) \ case 'l': \ - VFPU_REGEXP(REG, SIZE, LSB, RTYPE, RSIZE, OP_VFPU_PFXCOMPAT_LIMITED) \ + VFPU_REGEXP(REG, SIZE, LSB, RTYPE, RSIZE, LIMITED, REG_COMPAT) \ default: \ abort(); \ } \ } +#define VFPU_SREG(SIZE, LSB, RTYPE, RSIZE, PFX_COMPAT) \ + VFPU_REG(SIZE, LSB, RTYPE, RSIZE, PFX_COMPAT, ALL) + +#define VFPU_DREG(SIZE, LSB, RTYPE, RSIZE, PFX_COMPAT, REG_COMPAT) \ + VFPU_REG(SIZE, LSB, RTYPE, RSIZE, PFX_COMPAT, REG_COMPAT) + #define VFPU_PFX(SIZE, LSB, RTYPE, RSIZE) \ - VFPU_REGEXP(PFX, SIZE, LSB, RTYPE, RSIZE, OP_VFPU_PFXCOMPAT_ALL) + VFPU_REGEXP(PFX, SIZE, LSB, RTYPE, RSIZE, ALL, ALL) #define PCREL(SIZE, LSB, IS_SIGNED, SHIFT, ALIGN_LOG2, INCLUDE_ISA_BIT, \ FLIP_ISA_BIT) \ diff --git a/opcodes/mips-opc.c b/opcodes/mips-opc.c index b5dd46f9cf4..847ad0f30e5 100644 --- a/opcodes/mips-opc.c +++ b/opcodes/mips-opc.c @@ -145,16 +145,22 @@ decode_mips_operand (const char *p) case '?': switch (p[1]) { - case 'd': VFPU_REG(7, 0, D, p[2] - '0', p[3]); - case 's': VFPU_REG(7, 8, S, p[2] - '0', p[3]); - case 't': VFPU_REG(7, 16, T, p[2] - '0', p[3]); + case 's': VFPU_SREG(7, 8, S, p[2] - '0', p[3]); + case 't': VFPU_SREG(7, 16, T, p[2] - '0', p[3]); + case 'd': VFPU_DREG(7, 0, D, p[2] - '0', p[3], ALL); + case 'D': VFPU_DREG(7, 0, D, p[2] - '0', p[3], SAME); + case 'i': VFPU_DREG(7, 0, D, p[2] - '0', p[3], NONE); case 'p': switch (p[2]) { case 'd': VFPU_PFX(24, 0, D, 3); case 's': VFPU_PFX(24, 0, S, 3); case 't': VFPU_PFX(24, 0, T, 3); + default: + abort(); } + default: + abort(); } break; @@ -695,12 +701,30 @@ const struct mips_opcode mips_builtin_opcodes[] = {"vadd.q", "?d3a,?s3a,?t3a", 0x60008080, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vadd.s", "?d0a,?s0a,?t0a", 0x60000000, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vadd.t", "?d2a,?s2a,?t2a", 0x60008000, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vasin.p", "?D1n,?s1n", 0xd0170080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vasin.q", "?D3n,?s3n", 0xd0178080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vasin.s", "?D0n,?s0n", 0xd0170000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vasin.t", "?D2n,?s2n", 0xd0178000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vavg.p", "?d0a,?s1a", 0xd0470080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vavg.q", "?d0a,?s3a", 0xd0478080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vavg.t", "?d0a,?s2a", 0xd0478000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vcos.p", "?D1n,?s1n", 0xd0130080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vcos.q", "?D3n,?s3n", 0xd0138080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vcos.s", "?D0n,?s0n", 0xd0130000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vcos.t", "?D2n,?s2n", 0xd0138000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vcrsp.t", "?i2n,?s2n,?t2n", 0xf2808000, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vcrs.t", "?d2a,?s2n,?t2n", 0x66808000, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vdiv.p", "?D1n,?s1n,?t1n", 0x63800080, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vdiv.q", "?D3n,?s3n,?t3n", 0x63808080, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vdiv.s", "?D0n,?s0n,?t0n", 0x63800000, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vdiv.t", "?D2n,?s2n,?t2n", 0x63808000, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vdot.p", "?d0a,?s1a,?t1a", 0x64800080, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vdot.q", "?d0a,?s3a,?t3a", 0x64808080, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vdot.t", "?d0a,?s2a,?t2a", 0x64808000, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vexp2.p", "?D1n,?s1n", 0xd0140080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vexp2.q", "?D3n,?s3n", 0xd0148080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vexp2.s", "?D0n,?s0n", 0xd0140000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vexp2.t", "?D2n,?s2n", 0xd0148000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vfad.p", "?d0a,?s1a", 0xd0460080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vfad.q", "?d0a,?s3a", 0xd0468080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vfad.t", "?d0a,?s2a", 0xd0468000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, @@ -709,6 +733,10 @@ const struct mips_opcode mips_builtin_opcodes[] = {"vi2us.q", "?d1l,?s3l", 0xd03e8080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vidt.p", "?d1a", 0xd0030080, 0xffffff80, WR_C2, 0, ALX, 0, 0 }, {"vidt.q", "?d3a", 0xd0038080, 0xffffff80, WR_C2, 0, ALX, 0, 0 }, +{"vlog2.p", "?D1n,?s1n", 0xd0150080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vlog2.q", "?D3n,?s3n", 0xd0158080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vlog2.s", "?D0n,?s0n", 0xd0150000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vlog2.t", "?D2n,?s2n", 0xd0158000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vmax.p", "?d1a,?s1a,?t1a", 0x6d800080, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vmax.q", "?d3a,?s3a,?t3a", 0x6d808080, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vmax.s", "?d0a,?s0a,?t0a", 0x6d800000, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 }, @@ -729,6 +757,14 @@ const struct mips_opcode mips_builtin_opcodes[] = {"vneg.q", "?d3a,?s3l", 0xd0028080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vneg.s", "?d0a,?s0l", 0xd0020000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vneg.t", "?d2a,?s2l", 0xd0028000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vnrcp.p", "?D1n,?s1n", 0xd0180080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vnrcp.q", "?D3n,?s3n", 0xd0188080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vnrcp.s", "?D0n,?s0n", 0xd0180000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vnrcp.t", "?D2n,?s2n", 0xd0188000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vnsin.p", "?D1n,?s1n", 0xd01a0080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vnsin.q", "?D3n,?s3n", 0xd01a8080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vnsin.s", "?D0n,?s0n", 0xd01a0000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vnsin.t", "?D2n,?s2n", 0xd01a8000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vocp.p", "?d1a,?s1n", 0xd0440080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vocp.q", "?d3a,?s3n", 0xd0448080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vocp.s", "?d0a,?s0n", 0xd0440000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, @@ -740,6 +776,19 @@ const struct mips_opcode mips_builtin_opcodes[] = {"vpfxd", "?pd.", 0xde000000, 0xff000000, CP, ALXPFX, ALX, 0, 0 }, {"vpfxs", "?ps.", 0xdc000000, 0xff000000, CP, ALXPFX, ALX, 0, 0 }, {"vpfxt", "?pt.", 0xdd000000, 0xff000000, CP, ALXPFX, ALX, 0, 0 }, +{"vqmul.q", "?i3n,?s3n,?t3n", 0xf2808080, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vrcp.p", "?D1n,?s1n", 0xd0100080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vrcp.q", "?D3n,?s3n", 0xd0108080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vrcp.s", "?D0n,?s0n", 0xd0100000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vrcp.t", "?D2n,?s2n", 0xd0108000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vrexp2.p", "?D1n,?s1n", 0xd01c0080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vrexp2.q", "?D3n,?s3n", 0xd01c8080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vrexp2.s", "?D0n,?s0n", 0xd01c0000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vrexp2.t", "?D2n,?s2n", 0xd01c8000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vrsq.p", "?D1n,?s1n", 0xd0110080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vrsq.q", "?D3n,?s3n", 0xd0118080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vrsq.s", "?D0n,?s0n", 0xd0110000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vrsq.t", "?D2n,?s2n", 0xd0118000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vsat0.p", "?d1n,?s1a", 0xd0040080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vsat0.q", "?d3n,?s3a", 0xd0048080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vsat0.s", "?d0n,?s0a", 0xd0040000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, @@ -763,10 +812,18 @@ const struct mips_opcode mips_builtin_opcodes[] = {"vsgn.q", "?d3a,?s3a", 0xd04a8080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vsgn.s", "?d0a,?s0a", 0xd04a0000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vsgn.t", "?d2a,?s2a", 0xd04a8000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vsin.p", "?D1n,?s1n", 0xd0120080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vsin.q", "?D3n,?s3n", 0xd0128080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vsin.s", "?D0n,?s0n", 0xd0120000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vsin.t", "?D2n,?s2n", 0xd0128000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vslt.p", "?d1a,?s1a,?t1a", 0x6f800080, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vslt.q", "?d3a,?s3a,?t3a", 0x6f808080, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vslt.s", "?d0a,?s0a,?t0a", 0x6f800000, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vslt.t", "?d2a,?s2a,?t2a", 0x6f808000, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vsqrt.p", "?D1n,?s1n", 0xd0160080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vsqrt.q", "?D3n,?s3n", 0xd0168080, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vsqrt.s", "?D0n,?s0n", 0xd0160000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, +{"vsqrt.t", "?D2n,?s2n", 0xd0168000, 0xffff8080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vsub.p", "?d1a,?s1a,?t1a", 0x60800080, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vsub.q", "?d3a,?s3a,?t3a", 0x60808080, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 }, {"vsub.s", "?d0a,?s0a,?t0a", 0x60800000, 0xff808080, RD_C2|WR_C2, 0, ALX, 0, 0 }, -- 2.51.1
