diff --git a/gcc/simplify-rtx.cc b/gcc/simplify-rtx.cc
index dda8fc689e7935734b2369f1d299c386cdd870ee..c478bd060fc6d6c26f9b65dec3515c89b0fd486b 100644
--- a/gcc/simplify-rtx.cc
+++ b/gcc/simplify-rtx.cc
@@ -4494,6 +4494,60 @@ simplify_context::simplify_binary_operation_1 (rtx_code code,
 	    return simplify_gen_binary (code, mode, op0,
 					gen_int_shift_amount (mode, val));
 	}
+
+      /* Simplify:
+
+	   (code:M1
+	     (subreg:M1
+	       ([al]shiftrt:M2
+		 (subreg:M2
+		   (ashift:M1 X C1))
+		 C2))
+	     C3)
+
+	 to:
+
+	   (code:M1
+	     ([al]shiftrt:M1
+	       (ashift:M1 X C1+N)
+	       C2+N)
+	     C3)
+
+	 where M1 is N bits wider than M2.  Optimizing the (subreg:M1 ...)
+	 directly would be arithmetically correct, but restricting the
+	 simplification to shifts by constants is more conservative,
+	 since it is more likely to lead to further simplifications.  */
+      if (is_a<scalar_int_mode> (mode, &int_mode)
+	  && paradoxical_subreg_p (op0)
+	  && is_a<scalar_int_mode> (GET_MODE (SUBREG_REG (op0)), &inner_mode)
+	  && (GET_CODE (SUBREG_REG (op0)) == ASHIFTRT
+	      || GET_CODE (SUBREG_REG (op0)) == LSHIFTRT)
+	  && CONST_INT_P (op1))
+	{
+	  auto xcode = GET_CODE (SUBREG_REG (op0));
+	  rtx xop0 = XEXP (SUBREG_REG (op0), 0);
+	  rtx xop1 = XEXP (SUBREG_REG (op0), 1);
+	  if (SUBREG_P (xop0)
+	      && GET_MODE (SUBREG_REG (xop0)) == mode
+	      && GET_CODE (SUBREG_REG (xop0)) == ASHIFT
+	      && CONST_INT_P (xop1)
+	      && UINTVAL (xop1) < GET_MODE_PRECISION (inner_mode))
+	    {
+	      rtx yop0 = XEXP (SUBREG_REG (xop0), 0);
+	      rtx yop1 = XEXP (SUBREG_REG (xop0), 1);
+	      if (CONST_INT_P (yop1)
+		  && UINTVAL (yop1) < GET_MODE_PRECISION (inner_mode))
+		{
+		  auto bias = (GET_MODE_BITSIZE (int_mode)
+			       - GET_MODE_BITSIZE (inner_mode));
+		  tem = simplify_gen_binary (ASHIFT, mode, yop0,
+					     GEN_INT (INTVAL (yop1) + bias));
+		  tem = simplify_gen_binary (xcode, mode, tem,
+					     GEN_INT (INTVAL (xop1) + bias));
+		  return simplify_gen_binary (code, mode, tem, op1);
+		}
+	    }
+	}
       break;
 
     case SS_ASHIFT:
diff --git a/gcc/testsuite/gcc.target/riscv/pr109592.c b/gcc/testsuite/gcc.target/riscv/pr109592.c
new file mode 100644
index 0000000000000000000000000000000000000000..2b388c4f7a1a84e8c2e7c450ac95665abd798fe9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr109592.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zbb -mabi=lp64d" } */
+
+int sextb32(int x) { return (x << 24) >> 24; }
+
+/* { dg-final { scan-assembler-times {sext.b} 1 } } */
+/* { dg-final { scan-assembler-not {slli} } } */
+/* { dg-final { scan-assembler-not {srai} } } */
+
diff --git a/gcc/testsuite/gcc.target/riscv/sign-extend-rshift.c b/gcc/testsuite/gcc.target/riscv/sign-extend-rshift.c
index 86f40375722195a570394d14444d46e9cb134179..bcb015efe03d6df68b6b81cda8507275a9f89361 100644
--- a/gcc/testsuite/gcc.target/riscv/sign-extend-rshift.c
+++ b/gcc/testsuite/gcc.target/riscv/sign-extend-rshift.c
@@ -84,7 +84,7 @@ SLONG_EXT_SSHORT_RSHIFT_N_SLONG(63)
 
 #if __riscv_xlen == 64
 // Below "slli ((32+16)-N); srai (32+16)" for rv64
-//    or "slli (16-N); sraiw 16" for rv64
+//    or "slli (16-N); srai 16" for rv64
 SINT_EXT_SSHORT_RSHIFT_N_SINT(1)
 SINT_EXT_SSHORT_RSHIFT_N_SINT(7)
 SINT_EXT_SSHORT_RSHIFT_N_SINT(8)
@@ -104,7 +104,7 @@ SINT_EXT_SSHORT_RSHIFT_N_SINT(31)
 
 // Below "slli (16-N); srai 16" for rv32
 // Below "slli ((32+16)-N); srai (32+16)" for rv64
-//    or "slli (16-N); sraiw 16" for rv64
+//    or "slli (16-N); srai 16" for rv64
 SINT_EXT_SSHORT_RSHIFT_N_SLONG(9)
 SINT_EXT_SSHORT_RSHIFT_N_SLONG(15)
 
@@ -119,5 +119,5 @@ SLONG_EXT_SSHORT_RSHIFT_N_SINT(15)
 /* { dg-final { scan-assembler-times "srai\t" 26 { target { rv32 } } } } */
 
 /* { dg-final { scan-assembler-times "slli\t" 44 { target { rv64 } } } } */
-/* { dg-final { scan-assembler-times "srai\t" 51 { target { rv64 } } } } */
-/* { dg-final { scan-assembler-times "sraiw\t" 10 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times "srai\t" 58 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times "sraiw\t" 3 { target { rv64 } } } } */