diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c index 5759d3a5fc4..7d7c0f8066e 100644 --- a/gas/config/tc-riscv.c +++ b/gas/config/tc-riscv.c @@ -1430,6 +1430,8 @@ validate_riscv_insn (const struct riscv_opcode *opc, int length) case 'f': switch (*++oparg) { + case 'M': /* Fall through. */ + case 'm': USE_BITS (OP_MASK_RM, OP_SH_RM); break; case 'v': USE_BITS (OP_MASK_RS1, OP_SH_RS1); break; default: goto unknown_validate_operand; @@ -3526,6 +3528,33 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr, case 'f': switch (*++oparg) { + case 'M': + case 'm': + /* Optional rounding mode (widening conversion) + 'M': operand either disallowed or not recommended + (considered to be non-useful to normal software). + 'm': operand allowed for compatibility reasons + (display a warning instead). */ + if (*asarg == '\0') + { + INSERT_OPERAND (RM, *ip, 0); + continue; + } + else if (*asarg == ',' && asarg++ + && arg_lookup (&asarg, riscv_rm, + ARRAY_SIZE (riscv_rm), ®no)) + { + INSERT_OPERAND (RM, *ip, regno); + if (*oparg == 'M') + as_bad (_ ("rounding mode cannot be specified " + "on widening conversion")); + else + as_warn ( + _ ("specifying a rounding mode is strongly " + "discourged on widening conversion")); + continue; + } + break; case 'v': /* FLI.[HSDQ] value field for 'Zfa' extension. */ if (!arg_lookup (&asarg, riscv_fli_symval, diff --git a/gas/testsuite/gas/riscv/rounding-dis-widening-na.d b/gas/testsuite/gas/riscv/rounding-dis-widening-na.d new file mode 100644 index 00000000000..3330b1db83d --- /dev/null +++ b/gas/testsuite/gas/riscv/rounding-dis-widening-na.d @@ -0,0 +1,13 @@ +#as: -march=rv32ifd +#source: rounding-dis-widening.s +#objdump: -d -M no-aliases + +.*:[ ]+file format .* + + +Disassembly of section .text: + +0+000 : +[ ]+[0-9a-f]+:[ ]+420100d3[ ]+fcvt\.d\.s[ ]+ft1,ft2 +[ ]+[0-9a-f]+:[ ]+420100d3[ ]+fcvt\.d\.s[ ]+ft1,ft2 +[ ]+[0-9a-f]+:[ ]+420170d3[ ]+fcvt\.d\.s[ ]+ft1,ft2,dyn diff --git a/gas/testsuite/gas/riscv/rounding-dis-widening.d b/gas/testsuite/gas/riscv/rounding-dis-widening.d new file mode 100644 index 00000000000..8fb31ab39ef --- /dev/null +++ b/gas/testsuite/gas/riscv/rounding-dis-widening.d @@ -0,0 +1,13 @@ +#as: -march=rv32ifd +#source: rounding-dis-widening.s +#objdump: -d + +.*:[ ]+file format .* + + +Disassembly of section .text: + +0+000 : +[ ]+[0-9a-f]+:[ ]+420100d3[ ]+fcvt\.d\.s[ ]+ft1,ft2 +[ ]+[0-9a-f]+:[ ]+420100d3[ ]+fcvt\.d\.s[ ]+ft1,ft2 +[ ]+[0-9a-f]+:[ ]+420170d3[ ]+fcvt\.d\.s[ ]+ft1,ft2 diff --git a/gas/testsuite/gas/riscv/rounding-dis-widening.s b/gas/testsuite/gas/riscv/rounding-dis-widening.s new file mode 100644 index 00000000000..17443b0a034 --- /dev/null +++ b/gas/testsuite/gas/riscv/rounding-dis-widening.s @@ -0,0 +1,8 @@ +target: + fcvt.d.s ft1, ft2 + # Standard encoding: + # - 2nd operand is the rounding mode (RNE [0b000] is preferred). + # - 6th operand (additional function) is zero for FCVT.D.S. + .insn r OP_FP, 0x0, 0x21, ft1, ft2, f0 + # Non-standard encoding + .insn r OP_FP, 0x7, 0x21, ft1, ft2, f0 diff --git a/gas/testsuite/gas/riscv/rounding-fail.d b/gas/testsuite/gas/riscv/rounding-fail.d index 0d0a55818ca..7857ab75145 100644 --- a/gas/testsuite/gas/riscv/rounding-fail.d +++ b/gas/testsuite/gas/riscv/rounding-fail.d @@ -1,3 +1,3 @@ -#as: -march=rv32ifd +#as: -march=rv32ifdq_zfh #source: rounding-fail.s #error_output: rounding-fail.l diff --git a/gas/testsuite/gas/riscv/rounding-fail.l b/gas/testsuite/gas/riscv/rounding-fail.l index ea46e7c2d5a..69d359a0eba 100644 --- a/gas/testsuite/gas/riscv/rounding-fail.l +++ b/gas/testsuite/gas/riscv/rounding-fail.l @@ -1,3 +1,16 @@ .*: Assembler messages: .*: Error: illegal operands `fadd.s fa1,fa1,fa1,' .*: Error: illegal operands `fadd.d fa1,fa1,fa1,' +.*: Error: illegal operands `fadd.s fa1,fa1,fa1,unknown' +.*: Error: illegal operands `fadd.d fa1,fa1,fa1,unknown' +.*: Error: rounding mode cannot be specified on widening conversion +.*: Error: rounding mode cannot be specified on widening conversion +.*: Error: rounding mode cannot be specified on widening conversion +.*: Error: rounding mode cannot be specified on widening conversion +.*: Error: rounding mode cannot be specified on widening conversion +.*: Error: rounding mode cannot be specified on widening conversion +.*: Error: rounding mode cannot be specified on widening conversion +.*: Error: rounding mode cannot be specified on widening conversion +.*: Error: rounding mode cannot be specified on widening conversion +.*: Error: rounding mode cannot be specified on widening conversion +.*: Error: illegal operands `fcvt\.q\.wu ft1,t0,unknown' diff --git a/gas/testsuite/gas/riscv/rounding-fail.s b/gas/testsuite/gas/riscv/rounding-fail.s index d18f53efb50..b9bb29d69c1 100644 --- a/gas/testsuite/gas/riscv/rounding-fail.s +++ b/gas/testsuite/gas/riscv/rounding-fail.s @@ -1,3 +1,23 @@ target: + # Empty rounding mode fadd.s fa1,fa1,fa1, fadd.d fa1,fa1,fa1, + # Invalid rounding mode + fadd.s fa1,fa1,fa1,unknown + fadd.d fa1,fa1,fa1,unknown + + # Rounding mode cannot be specified on widening conversion + # unless we have supported in the past. + fcvt.s.h ft1,ft2,dyn + fcvt.d.h ft1,ft2,dyn + fcvt.q.h ft1,ft2,dyn + fcvt.d.s ft1,ft2,dyn + fcvt.q.s ft1,ft2,dyn + fcvt.q.d ft1,ft2,dyn + fcvt.d.w ft1,t0,dyn + fcvt.d.wu ft1,t0,dyn + fcvt.q.w ft1,t0,dyn + fcvt.q.wu ft1,t0,dyn + + # Different error message because of an invalid rounding mode + fcvt.q.wu ft1,t0,unknown diff --git a/gas/testsuite/gas/riscv/rounding-fcvt.q.l-na.d b/gas/testsuite/gas/riscv/rounding-fcvt.q.l-na.d new file mode 100644 index 00000000000..6f7a10f6c75 --- /dev/null +++ b/gas/testsuite/gas/riscv/rounding-fcvt.q.l-na.d @@ -0,0 +1,15 @@ +#as: -march=rv64ifdq +#source: rounding-fcvt.q.l.s +#warning_output: rounding-fcvt.q.l.l +#objdump: -d -M no-aliases + +.*:[ ]+file format .* + + +Disassembly of section .text: + +0+000 : +[ ]+[0-9a-f]+:[ ]+d62280d3[ ]+fcvt\.q\.l[ ]+ft1,t0 +[ ]+[0-9a-f]+:[ ]+d622f0d3[ ]+fcvt\.q\.l[ ]+ft1,t0,dyn +[ ]+[0-9a-f]+:[ ]+d63280d3[ ]+fcvt\.q\.lu[ ]+ft1,t0 +[ ]+[0-9a-f]+:[ ]+d632f0d3[ ]+fcvt\.q\.lu[ ]+ft1,t0,dyn diff --git a/gas/testsuite/gas/riscv/rounding-fcvt.q.l.d b/gas/testsuite/gas/riscv/rounding-fcvt.q.l.d new file mode 100644 index 00000000000..80b6320e873 --- /dev/null +++ b/gas/testsuite/gas/riscv/rounding-fcvt.q.l.d @@ -0,0 +1,15 @@ +#as: -march=rv64ifdq +#source: rounding-fcvt.q.l.s +#warning_output: rounding-fcvt.q.l.l +#objdump: -d + +.*:[ ]+file format .* + + +Disassembly of section .text: + +0+000 : +[ ]+[0-9a-f]+:[ ]+d62280d3[ ]+fcvt\.q\.l[ ]+ft1,t0 +[ ]+[0-9a-f]+:[ ]+d622f0d3[ ]+fcvt\.q\.l[ ]+ft1,t0 +[ ]+[0-9a-f]+:[ ]+d63280d3[ ]+fcvt\.q\.lu[ ]+ft1,t0 +[ ]+[0-9a-f]+:[ ]+d632f0d3[ ]+fcvt\.q\.lu[ ]+ft1,t0 diff --git a/gas/testsuite/gas/riscv/rounding-fcvt.q.l.l b/gas/testsuite/gas/riscv/rounding-fcvt.q.l.l new file mode 100644 index 00000000000..22df262891e --- /dev/null +++ b/gas/testsuite/gas/riscv/rounding-fcvt.q.l.l @@ -0,0 +1,3 @@ +.*: Assembler messages: +.*: Warning: specifying a rounding mode is strongly discourged on widening conversion +.*: Warning: specifying a rounding mode is strongly discourged on widening conversion diff --git a/gas/testsuite/gas/riscv/rounding-fcvt.q.l.s b/gas/testsuite/gas/riscv/rounding-fcvt.q.l.s new file mode 100644 index 00000000000..ec60e53f7ad --- /dev/null +++ b/gas/testsuite/gas/riscv/rounding-fcvt.q.l.s @@ -0,0 +1,5 @@ +target: + fcvt.q.l ft1,t0 + fcvt.q.l ft1,t0,dyn + fcvt.q.lu ft1,t0 + fcvt.q.lu ft1,t0,dyn diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c index 216916e9426..71e154540f3 100644 --- a/opcodes/riscv-dis.c +++ b/opcodes/riscv-dis.c @@ -601,6 +601,20 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info case 'f': switch (*++oparg) { + case 'M': /* Fall through. */ + case 'm': + /* Optional rounding mode (widening conversion) + which defaults to RNE (0b000). + Display non-default rounding mode if: + 1. rounding mode is invalid or + 2. 'no-aliases' option is specified. */ + if (EXTRACT_OPERAND (RM, l) == 0 + || (!no_aliases && riscv_rm[EXTRACT_OPERAND (RM, l)])) + break; + print (info->stream, dis_style_text, ","); + arg_print (info, EXTRACT_OPERAND (RM, l), riscv_rm, + ARRAY_SIZE (riscv_rm)); + break; case 'v': if (riscv_fli_symval[rs1]) print (info->stream, dis_style_text, "%s", diff --git a/opcodes/riscv-opc.c b/opcodes/riscv-opc.c index 8e0ae85eb06..4283ee25cd8 100644 --- a/opcodes/riscv-opc.c +++ b/opcodes/riscv-opc.c @@ -702,9 +702,9 @@ const struct riscv_opcode riscv_opcodes[] = {"fcvt.h.w", 0, INSN_CLASS_ZFH_INX, "D,s,m", MATCH_FCVT_H_W, MASK_FCVT_H_W, match_opcode, 0 }, {"fcvt.h.wu", 0, INSN_CLASS_ZFH_INX, "D,s", MATCH_FCVT_H_WU|MASK_RM, MASK_FCVT_H_WU|MASK_RM, match_opcode, 0 }, {"fcvt.h.wu", 0, INSN_CLASS_ZFH_INX, "D,s,m", MATCH_FCVT_H_WU, MASK_FCVT_H_WU, match_opcode, 0 }, -{"fcvt.s.h", 0, INSN_CLASS_ZFHMIN_INX, "D,S", MATCH_FCVT_S_H, MASK_FCVT_S_H|MASK_RM, match_opcode, 0 }, -{"fcvt.d.h", 0, INSN_CLASS_ZFHMIN_AND_D_INX, "D,S", MATCH_FCVT_D_H, MASK_FCVT_D_H|MASK_RM, match_opcode, 0 }, -{"fcvt.q.h", 0, INSN_CLASS_ZFHMIN_AND_Q_INX, "D,S", MATCH_FCVT_Q_H, MASK_FCVT_Q_H|MASK_RM, match_opcode, 0 }, +{"fcvt.s.h", 0, INSN_CLASS_ZFHMIN_INX, "D,SWfM", MATCH_FCVT_S_H, MASK_FCVT_S_H, match_opcode, 0 }, +{"fcvt.d.h", 0, INSN_CLASS_ZFHMIN_AND_D_INX, "D,SWfM", MATCH_FCVT_D_H, MASK_FCVT_D_H, match_opcode, 0 }, +{"fcvt.q.h", 0, INSN_CLASS_ZFHMIN_AND_Q_INX, "D,SWfM", MATCH_FCVT_Q_H, MASK_FCVT_Q_H, match_opcode, 0 }, {"fcvt.h.s", 0, INSN_CLASS_ZFHMIN_INX, "D,S", MATCH_FCVT_H_S|MASK_RM, MASK_FCVT_H_S|MASK_RM, match_opcode, 0 }, {"fcvt.h.s", 0, INSN_CLASS_ZFHMIN_INX, "D,S,m", MATCH_FCVT_H_S, MASK_FCVT_H_S, match_opcode, 0 }, {"fcvt.h.d", 0, INSN_CLASS_ZFHMIN_AND_D_INX, "D,S", MATCH_FCVT_H_D|MASK_RM, MASK_FCVT_H_D|MASK_RM, match_opcode, 0 }, @@ -843,9 +843,9 @@ const struct riscv_opcode riscv_opcodes[] = {"fcvt.w.d", 0, INSN_CLASS_D_INX, "d,S,m", MATCH_FCVT_W_D, MASK_FCVT_W_D, match_opcode, 0 }, {"fcvt.wu.d", 0, INSN_CLASS_D_INX, "d,S", MATCH_FCVT_WU_D|MASK_RM, MASK_FCVT_WU_D|MASK_RM, match_opcode, 0 }, {"fcvt.wu.d", 0, INSN_CLASS_D_INX, "d,S,m", MATCH_FCVT_WU_D, MASK_FCVT_WU_D, match_opcode, 0 }, -{"fcvt.d.w", 0, INSN_CLASS_D_INX, "D,s", MATCH_FCVT_D_W, MASK_FCVT_D_W|MASK_RM, match_opcode, 0 }, -{"fcvt.d.wu", 0, INSN_CLASS_D_INX, "D,s", MATCH_FCVT_D_WU, MASK_FCVT_D_WU|MASK_RM, match_opcode, 0 }, -{"fcvt.d.s", 0, INSN_CLASS_D_INX, "D,S", MATCH_FCVT_D_S, MASK_FCVT_D_S|MASK_RM, match_opcode, 0 }, +{"fcvt.d.w", 0, INSN_CLASS_D_INX, "D,sWfM", MATCH_FCVT_D_W, MASK_FCVT_D_W, match_opcode, 0 }, +{"fcvt.d.wu", 0, INSN_CLASS_D_INX, "D,sWfM", MATCH_FCVT_D_WU, MASK_FCVT_D_WU, match_opcode, 0 }, +{"fcvt.d.s", 0, INSN_CLASS_D_INX, "D,SWfM", MATCH_FCVT_D_S, MASK_FCVT_D_S, match_opcode, 0 }, {"fcvt.s.d", 0, INSN_CLASS_D_INX, "D,S", MATCH_FCVT_S_D|MASK_RM, MASK_FCVT_S_D|MASK_RM, match_opcode, 0 }, {"fcvt.s.d", 0, INSN_CLASS_D_INX, "D,S,m", MATCH_FCVT_S_D, MASK_FCVT_S_D, match_opcode, 0 }, {"fclass.d", 0, INSN_CLASS_D_INX, "d,S", MATCH_FCLASS_D, MASK_FCLASS_D, match_opcode, 0 }, @@ -900,10 +900,10 @@ const struct riscv_opcode riscv_opcodes[] = {"fcvt.w.q", 0, INSN_CLASS_Q_INX, "d,S,m", MATCH_FCVT_W_Q, MASK_FCVT_W_Q, match_opcode, 0 }, {"fcvt.wu.q", 0, INSN_CLASS_Q_INX, "d,S", MATCH_FCVT_WU_Q|MASK_RM, MASK_FCVT_WU_Q|MASK_RM, match_opcode, 0 }, {"fcvt.wu.q", 0, INSN_CLASS_Q_INX, "d,S,m", MATCH_FCVT_WU_Q, MASK_FCVT_WU_Q, match_opcode, 0 }, -{"fcvt.q.w", 0, INSN_CLASS_Q_INX, "D,s", MATCH_FCVT_Q_W, MASK_FCVT_Q_W|MASK_RM, match_opcode, 0 }, -{"fcvt.q.wu", 0, INSN_CLASS_Q_INX, "D,s", MATCH_FCVT_Q_WU, MASK_FCVT_Q_WU|MASK_RM, match_opcode, 0 }, -{"fcvt.q.s", 0, INSN_CLASS_Q_INX, "D,S", MATCH_FCVT_Q_S, MASK_FCVT_Q_S|MASK_RM, match_opcode, 0 }, -{"fcvt.q.d", 0, INSN_CLASS_Q_INX, "D,S", MATCH_FCVT_Q_D, MASK_FCVT_Q_D|MASK_RM, match_opcode, 0 }, +{"fcvt.q.w", 0, INSN_CLASS_Q_INX, "D,sWfM", MATCH_FCVT_Q_W, MASK_FCVT_Q_W, match_opcode, 0 }, +{"fcvt.q.wu", 0, INSN_CLASS_Q_INX, "D,sWfM", MATCH_FCVT_Q_WU, MASK_FCVT_Q_WU, match_opcode, 0 }, +{"fcvt.q.s", 0, INSN_CLASS_Q_INX, "D,SWfM", MATCH_FCVT_Q_S, MASK_FCVT_Q_S, match_opcode, 0 }, +{"fcvt.q.d", 0, INSN_CLASS_Q_INX, "D,SWfM", MATCH_FCVT_Q_D, MASK_FCVT_Q_D, match_opcode, 0 }, {"fcvt.s.q", 0, INSN_CLASS_Q_INX, "D,S", MATCH_FCVT_S_Q|MASK_RM, MASK_FCVT_S_Q|MASK_RM, match_opcode, 0 }, {"fcvt.s.q", 0, INSN_CLASS_Q_INX, "D,S,m", MATCH_FCVT_S_Q, MASK_FCVT_S_Q, match_opcode, 0 }, {"fcvt.d.q", 0, INSN_CLASS_Q_INX, "D,S", MATCH_FCVT_D_Q|MASK_RM, MASK_FCVT_D_Q|MASK_RM, match_opcode, 0 }, @@ -918,10 +918,8 @@ const struct riscv_opcode riscv_opcodes[] = {"fcvt.l.q", 64, INSN_CLASS_Q_INX, "d,S,m", MATCH_FCVT_L_Q, MASK_FCVT_L_Q, match_opcode, 0 }, {"fcvt.lu.q", 64, INSN_CLASS_Q_INX, "d,S", MATCH_FCVT_LU_Q|MASK_RM, MASK_FCVT_LU_Q|MASK_RM, match_opcode, 0 }, {"fcvt.lu.q", 64, INSN_CLASS_Q_INX, "d,S,m", MATCH_FCVT_LU_Q, MASK_FCVT_LU_Q, match_opcode, 0 }, -{"fcvt.q.l", 64, INSN_CLASS_Q_INX, "D,s", MATCH_FCVT_Q_L, MASK_FCVT_Q_L|MASK_RM, match_opcode, 0 }, -{"fcvt.q.l", 64, INSN_CLASS_Q_INX, "D,s,m", MATCH_FCVT_Q_L, MASK_FCVT_Q_L, match_opcode, 0 }, -{"fcvt.q.lu", 64, INSN_CLASS_Q_INX, "D,s", MATCH_FCVT_Q_LU, MASK_FCVT_Q_LU|MASK_RM, match_opcode, 0 }, -{"fcvt.q.lu", 64, INSN_CLASS_Q_INX, "D,s,m", MATCH_FCVT_Q_LU, MASK_FCVT_Q_LU, match_opcode, 0 }, +{"fcvt.q.l", 64, INSN_CLASS_Q_INX, "D,sWfm", MATCH_FCVT_Q_L, MASK_FCVT_Q_L, match_opcode, 0 }, +{"fcvt.q.lu", 64, INSN_CLASS_Q_INX, "D,sWfm", MATCH_FCVT_Q_LU, MASK_FCVT_Q_LU, match_opcode, 0 }, /* Compressed instructions. */ {"c.unimp", 0, INSN_CLASS_C, "", 0, 0xffffU, match_opcode, 0 },