diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index bb0e18ac8d52..f0f531039415 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -1396,6 +1396,15 @@ validate_riscv_insn (const struct riscv_opcode *opc, int length)
 		  goto unknown_validate_operand;
 		}
 	      break;
+	    case 'f':
+	      switch (*++oparg)
+		{
+		case 'M': /* Fall through.  */
+		case 'm': USE_BITS (OP_MASK_RM, OP_SH_RM); break;
+		default:
+		  goto unknown_validate_operand;
+		}
+	      break;
 	    default:
 	      goto unknown_validate_operand;
 	    }
@@ -3442,6 +3451,40 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
 		      goto unknown_riscv_ip_operand;
 		    }
 		  break;
+		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), &regno))
+			{
+			  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;
+		    default:
+		      goto unknown_riscv_ip_operand;
+		    }
+		  break;
 		default:
 		  goto unknown_riscv_ip_operand;
 		}
diff --git a/gas/testsuite/gas/riscv/rounding-dis-widening-noalias.d b/gas/testsuite/gas/riscv/rounding-dis-widening-noalias.d
new file mode 100644
index 000000000000..3330b1db83db
--- /dev/null
+++ b/gas/testsuite/gas/riscv/rounding-dis-widening-noalias.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 <target>:
+[ 	]+[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 000000000000..8fb31ab39efa
--- /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 <target>:
+[ 	]+[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 000000000000..17443b0a0343
--- /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 0d0a55818caf..7857ab75145c 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 00d4d8e40fa6..69d359a0eba4 100644
--- a/gas/testsuite/gas/riscv/rounding-fail.l
+++ b/gas/testsuite/gas/riscv/rounding-fail.l
@@ -3,3 +3,14 @@
 .*: 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 6e05cbd410c9..75f9fe1965d1 100644
--- a/gas/testsuite/gas/riscv/rounding-fail.s
+++ b/gas/testsuite/gas/riscv/rounding-fail.s
@@ -4,3 +4,19 @@ target:
 	fadd.d fa1,fa1,fa1,
 	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-noalias.d b/gas/testsuite/gas/riscv/rounding-fcvt.q.l-noalias.d
new file mode 100644
index 000000000000..6f7a10f6c755
--- /dev/null
+++ b/gas/testsuite/gas/riscv/rounding-fcvt.q.l-noalias.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 <target>:
+[ 	]+[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 000000000000..80b6320e873f
--- /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 <target>:
+[ 	]+[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 000000000000..22df262891e8
--- /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 000000000000..ec60e53f7ad1
--- /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 1e6716e8e58c..e4d966a118df 100644
--- a/opcodes/riscv-dis.c
+++ b/opcodes/riscv-dis.c
@@ -592,6 +592,27 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info
 		    goto undefined_modifier;
 		  }
 		  break;
+	      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;
+		  default:
+		    goto undefined_modifier;
+		  }
+		  break;
 	      default:
 		goto undefined_modifier;
 	      }
@@ -640,6 +661,7 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info
 	      }
 	  }
 	  break;
+
 	default:
 	undefined_modifier:
 	  /* xgettext:c-format */
diff --git a/opcodes/riscv-opc.c b/opcodes/riscv-opc.c
index 653eb60f2a58..dbfb4f3918b2 100644
--- a/opcodes/riscv-opc.c
+++ b/opcodes/riscv-opc.c
@@ -659,9 +659,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 },
@@ -800,9 +800,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 },
@@ -857,10 +857,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 },
@@ -875,10 +875,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 },
