[v4,5/9] riscv: thead: Add support for the XTheadBb ISA extension

Message ID 20230302083534.4076244-6-christoph.muellner@vrull.eu
State Committed
Headers
Series RISC-V: Add XThead* extension support |

Commit Message

Christoph Müllner March 2, 2023, 8:35 a.m. UTC
  From: Christoph Müllner <christoph.muellner@vrull.eu>

This patch adds support for the XTheadBb ISA extension.
Thus, there is a functional overlap of the new instructions with
existing Bitmanip instruction, which allows a good amount of code
sharing. However, the vendor extensions are cleanly separated from
the standard extensions (e.g. by using INSN expand pattern that
will re-emit RTL that matches the patterns of either Bitmanip or
XThead INSNs).

gcc/ChangeLog:

	* config/riscv/bitmanip.md (clzdi2): New expand.
	(clzsi2): New expand.
	(ctz<mode>2): New expand.
	(popcount<mode>2): New expand.
	(<bitmanip_optab>si2): Rename INSN.
	(*<bitmanip_optab>si2): Hide INSN name.
	(<bitmanip_optab>di2): Rename INSN.
	(*<bitmanip_optab>di2): Hide INSN name.
	(rotrsi3): Remove INSN.
	(rotr<mode>3): Add expand.
	(*rotrsi3): New INSN.
	(rotrdi3): Rename INSN.
	(*rotrdi3): Hide INSN name.
	(rotrsi3_sext): Rename INSN.
	(*rotrsi3_sext): Hide INSN name.
	(bswap<mode>2): Remove INSN.
	(bswapdi2): Add expand.
	(bswapsi2): Add expand.
	(*bswap<mode>2): Hide INSN name.
	* config/riscv/riscv.cc (riscv_rtx_costs): Add costs for sign
	extraction.
	* config/riscv/riscv.md (extv<mode>): New expand.
	(extzv<mode>): New expand.
	* config/riscv/thead.md (*th_srri<mode>3): New INSN.
	(*th_ext<mode>): New INSN.
	(*th_extu<mode>): New INSN.
	(*th_clz<mode>2): New INSN.
	(*th_rev<mode>2): New INSN.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/xtheadbb-ext.c: New test.
	* gcc.target/riscv/xtheadbb-extu-2.c: New test.
	* gcc.target/riscv/xtheadbb-extu.c: New test.
	* gcc.target/riscv/xtheadbb-ff1.c: New test.
	* gcc.target/riscv/xtheadbb-rev.c: New test.
	* gcc.target/riscv/xtheadbb-srri.c: New test.

Changes in v4:
- Replace 'immediate_operand' by 'const_int_operand'
- Add number of arguments to pattern names
- Merge th_srri<mode>3 patterns
- Merge th_rev<mode>2 patterns
- Improve coverage of th.srri test

Changes for v2:
- Merge all XTheadB* support patches
- Remove useless operand sanity checks for extv<mode> and extzv<mode>
- Prefer c.andi over th.extu if possible
- Add ff1 tests for clz/ctz
- Fix ext/extu test cases
- Enable tests for RV32

Signed-off-by: Christoph Müllner <christoph.muellner@vrull.eu>
---
 gcc/config/riscv/bitmanip.md                  | 52 ++++++++++++++--
 gcc/config/riscv/riscv.cc                     |  9 +++
 gcc/config/riscv/riscv.md                     | 20 ++++++
 gcc/config/riscv/thead.md                     | 61 +++++++++++++++++++
 gcc/testsuite/gcc.target/riscv/xtheadbb-ext.c | 20 ++++++
 .../gcc.target/riscv/xtheadbb-extu-2.c        | 22 +++++++
 .../gcc.target/riscv/xtheadbb-extu.c          | 22 +++++++
 gcc/testsuite/gcc.target/riscv/xtheadbb-ff1.c | 18 ++++++
 gcc/testsuite/gcc.target/riscv/xtheadbb-rev.c | 45 ++++++++++++++
 .../gcc.target/riscv/xtheadbb-srri.c          | 25 ++++++++
 10 files changed, 288 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-ext.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-extu-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-extu.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-ff1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-rev.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadbb-srri.c
  

Comments

Jeff Law March 5, 2023, 5:41 p.m. UTC | #1
On 3/2/23 01:35, Christoph Muellner wrote:
> From: Christoph Müllner <christoph.muellner@vrull.eu>
> 
> This patch adds support for the XTheadBb ISA extension.
> Thus, there is a functional overlap of the new instructions with
> existing Bitmanip instruction, which allows a good amount of code
> sharing. However, the vendor extensions are cleanly separated from
> the standard extensions (e.g. by using INSN expand pattern that
> will re-emit RTL that matches the patterns of either Bitmanip or
> XThead INSNs).
> 

> diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
> index d6c2265e9d4..fc8ce9f5226 100644
> --- a/gcc/config/riscv/riscv.md
> +++ b/gcc/config/riscv/riscv.md
> @@ -3087,6 +3087,26 @@ (define_insn "riscv_prefetchi_<mode>"
>     "prefetch.i\t%a0"
>   )
>   
> +(define_expand "extv<mode>"
> +  [(set (match_operand:GPR 0 "register_operand" "=r")
> +	(sign_extract:GPR (match_operand:GPR 1 "register_operand" "r")
> +			 (match_operand 2 "const_int_operand")
> +			 (match_operand 3 "const_int_operand")))]
> +  "TARGET_XTHEADBB"
> +)
> +
> +(define_expand "extzv<mode>"
> +  [(set (match_operand:GPR 0 "register_operand" "=r")
> +	(zero_extract:GPR (match_operand:GPR 1 "register_operand" "r")
> +			 (match_operand 2 "const_int_operand")
> +			 (match_operand 3 "const_int_operand")))]
> +  "TARGET_XTHEADBB"
> +{
> +  if (TARGET_XTHEADBB
> +      && (INTVAL (operands[2]) < 8) && (INTVAL (operands[3]) == 0))
> +    FAIL;
> +})
Note that bitmanip has single bit extractions which probably should be 
handed by extzv rather than relying strictly on the combiner to 
synthesize them.  Similarly for single bit insertions.

I've actually got a TODO on Raphael's plate to see how renaming the 
existing bitmanip bit extraction to extzv affects code generation.  I'm 
not offhand sure where it is on his priority list yet.

I guess the wider point is the ext and ins expanders should probably be 
accepting single bit extractions/insertions when ZBS is enabled.

Jeff
  

Patch

diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md
index 14d18edbe62..ca0c98ee686 100644
--- a/gcc/config/riscv/bitmanip.md
+++ b/gcc/config/riscv/bitmanip.md
@@ -185,6 +185,26 @@  (define_insn "*slliuw"
 
 ;; ZBB extension.
 
+(define_expand "clzdi2"
+  [(set (match_operand:DI 0 "register_operand")
+	(clz:DI (match_operand:DI 1 "register_operand")))]
+  "TARGET_64BIT && (TARGET_ZBB || TARGET_XTHEADBB)")
+
+(define_expand "clzsi2"
+  [(set (match_operand:SI 0 "register_operand")
+	(clz:SI (match_operand:SI 1 "register_operand")))]
+  "TARGET_ZBB || (!TARGET_64BIT && TARGET_XTHEADBB)")
+
+(define_expand "ctz<mode>2"
+  [(set (match_operand:GPR 0 "register_operand")
+	(ctz:GPR (match_operand:GPR 1 "register_operand")))]
+  "TARGET_ZBB")
+
+(define_expand "popcount<mode>2"
+  [(set (match_operand:GPR 0 "register_operand")
+	(popcount:GPR (match_operand:GPR 1 "register_operand")))]
+  "TARGET_ZBB")
+
 (define_insn "*<optab>_not<mode>"
   [(set (match_operand:X 0 "register_operand" "=r")
         (bitmanip_bitwise:X (not:X (match_operand:X 1 "register_operand" "r"))
@@ -216,7 +236,7 @@  (define_insn "*xor_not<mode>"
   [(set_attr "type" "bitmanip")
    (set_attr "mode" "<X:MODE>")])
 
-(define_insn "<bitmanip_optab>si2"
+(define_insn "*<bitmanip_optab>si2"
   [(set (match_operand:SI 0 "register_operand" "=r")
         (clz_ctz_pcnt:SI (match_operand:SI 1 "register_operand" "r")))]
   "TARGET_ZBB"
@@ -233,7 +253,7 @@  (define_insn "*<bitmanip_optab>disi2"
   [(set_attr "type" "bitmanip")
    (set_attr "mode" "SI")])
 
-(define_insn "<bitmanip_optab>di2"
+(define_insn "*<bitmanip_optab>di2"
   [(set (match_operand:DI 0 "register_operand" "=r")
         (clz_ctz_pcnt:DI (match_operand:DI 1 "register_operand" "r")))]
   "TARGET_64BIT && TARGET_ZBB"
@@ -273,7 +293,17 @@  (define_insn "*zero_extendhi<GPR:mode>2_zbb"
   [(set_attr "type" "bitmanip,load")
    (set_attr "mode" "HI")])
 
-(define_insn "rotrsi3"
+(define_expand "rotr<mode>3"
+  [(set (match_operand:GPR 0 "register_operand")
+	(rotatert:GPR (match_operand:GPR 1 "register_operand")
+		     (match_operand:QI 2 "arith_operand")))]
+  "TARGET_ZBB || TARGET_XTHEADBB"
+{
+  if (TARGET_XTHEADBB && !immediate_operand (operands[2], VOIDmode))
+    FAIL;
+})
+
+(define_insn "*rotrsi3"
   [(set (match_operand:SI 0 "register_operand" "=r")
 	(rotatert:SI (match_operand:SI 1 "register_operand" "r")
 		     (match_operand:QI 2 "arith_operand" "rI")))]
@@ -281,7 +311,7 @@  (define_insn "rotrsi3"
   "ror%i2%~\t%0,%1,%2"
   [(set_attr "type" "bitmanip")])
 
-(define_insn "rotrdi3"
+(define_insn "*rotrdi3"
   [(set (match_operand:DI 0 "register_operand" "=r")
 	(rotatert:DI (match_operand:DI 1 "register_operand" "r")
 		     (match_operand:QI 2 "arith_operand" "rI")))]
@@ -289,7 +319,7 @@  (define_insn "rotrdi3"
   "ror%i2\t%0,%1,%2"
   [(set_attr "type" "bitmanip")])
 
-(define_insn "rotrsi3_sext"
+(define_insn "*rotrsi3_sext"
   [(set (match_operand:DI 0 "register_operand" "=r")
 	(sign_extend:DI (rotatert:SI (match_operand:SI 1 "register_operand" "r")
 				     (match_operand:QI 2 "register_operand" "r"))))]
@@ -329,7 +359,17 @@  (define_insn "orcb<mode>2"
   "TARGET_ZBB"
   "orc.b\t%0,%1")
 
-(define_insn "bswap<mode>2"
+(define_expand "bswapdi2"
+  [(set (match_operand:DI 0 "register_operand")
+	(bswap:DI (match_operand:DI 1 "register_operand")))]
+  "TARGET_64BIT && (TARGET_ZBB || TARGET_XTHEADBB)")
+
+(define_expand "bswapsi2"
+  [(set (match_operand:SI 0 "register_operand")
+	(bswap:SI (match_operand:SI 1 "register_operand")))]
+  "(!TARGET_64BIT && TARGET_ZBB) || TARGET_XTHEADBB")
+
+(define_insn "*bswap<mode>2"
   [(set (match_operand:X 0 "register_operand" "=r")
         (bswap:X (match_operand:X 1 "register_operand" "r")))]
   "TARGET_ZBB"
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index e35bc0a745b..7613bae8024 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -2408,6 +2408,15 @@  riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
 	  *total = COSTS_N_INSNS (SINGLE_SHIFT_COST);
 	  return true;
 	}
+      gcc_fallthrough ();
+    case SIGN_EXTRACT:
+      if (TARGET_XTHEADBB && outer_code == SET
+	  && CONST_INT_P (XEXP (x, 1))
+	  && CONST_INT_P (XEXP (x, 2)))
+	{
+	  *total = COSTS_N_INSNS (SINGLE_SHIFT_COST);
+	  return true;
+	}
       return false;
 
     case ASHIFT:
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index d6c2265e9d4..fc8ce9f5226 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -3087,6 +3087,26 @@  (define_insn "riscv_prefetchi_<mode>"
   "prefetch.i\t%a0"
 )
 
+(define_expand "extv<mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=r")
+	(sign_extract:GPR (match_operand:GPR 1 "register_operand" "r")
+			 (match_operand 2 "const_int_operand")
+			 (match_operand 3 "const_int_operand")))]
+  "TARGET_XTHEADBB"
+)
+
+(define_expand "extzv<mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=r")
+	(zero_extract:GPR (match_operand:GPR 1 "register_operand" "r")
+			 (match_operand 2 "const_int_operand")
+			 (match_operand 3 "const_int_operand")))]
+  "TARGET_XTHEADBB"
+{
+  if (TARGET_XTHEADBB
+      && (INTVAL (operands[2]) < 8) && (INTVAL (operands[3]) == 0))
+    FAIL;
+})
+
 (include "bitmanip.md")
 (include "sync.md")
 (include "peephole.md")
diff --git a/gcc/config/riscv/thead.md b/gcc/config/riscv/thead.md
index 3842a194d16..372d4603543 100644
--- a/gcc/config/riscv/thead.md
+++ b/gcc/config/riscv/thead.md
@@ -30,6 +30,67 @@  (define_insn "*th_addsl<mode>4"
   [(set_attr "type" "bitmanip")
    (set_attr "mode" "<X:MODE>")])
 
+;; XTheadBb
+
+(define_insn "*th_srri<mode>3"
+  [(set (match_operand:GPR 0 "register_operand" "=r")
+	(rotatert:GPR (match_operand:GPR 1 "register_operand" "r")
+		     (match_operand 2 "const_int_operand" "n")))]
+  "TARGET_XTHEADBB && (TARGET_64BIT || <MODE>mode == SImode)"
+  {
+    bool wform = TARGET_64BIT && (<MODE>mode == SImode);
+    operands[2] = GEN_INT (INTVAL (operands[2])
+                  & (GET_MODE_BITSIZE (<MODE>mode) - 1));
+    return wform ? "th.srriw\t%0,%1,%2" : "th.srri\t%0,%1,%2";
+  }
+  [(set_attr "type" "bitmanip")
+   (set_attr "mode" "<GPR:MODE>")])
+
+(define_insn "*th_ext<mode>4"
+  [(set (match_operand:GPR 0 "register_operand" "=r")
+	(sign_extract:GPR (match_operand:GPR 1 "register_operand" "r")
+			(match_operand 2 "const_int_operand")
+			(match_operand 3 "const_int_operand")))]
+  "TARGET_XTHEADBB"
+{
+  operands[2] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3]) - 1);
+  return "th.ext\t%0,%1,%2,%3";
+}
+  [(set_attr "type" "bitmanip")
+   (set_attr "mode" "<GPR:MODE>")])
+
+(define_insn "*th_extu<mode>4"
+  [(set (match_operand:GPR 0 "register_operand" "=r")
+	(zero_extract:GPR (match_operand:GPR 1 "register_operand" "r")
+			(match_operand 2 "const_int_operand")
+			(match_operand 3 "const_int_operand")))]
+  "TARGET_XTHEADBB"
+{
+  operands[2] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3]) - 1);
+  return "th.extu\t%0,%1,%2,%3";
+}
+  [(set_attr "type" "bitmanip")
+   (set_attr "mode" "<GPR:MODE>")])
+
+(define_insn "*th_clz<mode>2"
+  [(set (match_operand:X 0 "register_operand" "=r")
+	(clz:X (match_operand:X 1 "register_operand" "r")))]
+  "TARGET_XTHEADBB"
+  "th.ff1\t%0,%1"
+  [(set_attr "type" "bitmanip")
+   (set_attr "mode" "<X:MODE>")])
+
+(define_insn "*th_rev<mode>2"
+  [(set (match_operand:GPR 0 "register_operand" "=r")
+	(bswap:GPR (match_operand:GPR 1 "register_operand" "r")))]
+  "TARGET_XTHEADBB && (TARGET_64BIT || <MODE>mode == SImode)"
+  {
+    bool wform = TARGET_64BIT && (<MODE>mode == SImode);
+    return wform ? "th.revw\t%0,%1" : "th.rev\t%0,%1";
+  }
+  [(set_attr "type" "bitmanip")
+   (set_attr "mode" "<GPR:MODE>")])
+
 ;; XTheadBs
 
 (define_insn "*th_tst<mode>3"
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadbb-ext.c b/gcc/testsuite/gcc.target/riscv/xtheadbb-ext.c
new file mode 100644
index 00000000000..60fb7d44e39
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadbb-ext.c
@@ -0,0 +1,20 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadbb" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadbb" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Og" } } */
+
+struct bar
+{
+  long a:9;
+  long b:26;
+  long c:22;
+};
+
+long
+foo (struct bar *s)
+{
+  return s->b;
+}
+
+/* { dg-final { scan-assembler "th.ext\t" } } */
+/* { dg-final { scan-assembler-not "andi" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadbb-extu-2.c b/gcc/testsuite/gcc.target/riscv/xtheadbb-extu-2.c
new file mode 100644
index 00000000000..029be93f401
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadbb-extu-2.c
@@ -0,0 +1,22 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadbb" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadbb" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Og" } } */
+
+struct bar
+{
+  unsigned long a:6;
+  unsigned long b:26;
+  unsigned long c:22;
+};
+
+/* We prefer andi over th.extu because it can be compressed.  */
+
+unsigned long
+foo (struct bar *s)
+{
+  return s->a;
+}
+
+/* { dg-final { scan-assembler-not "th.extu\t" } } */
+/* { dg-final { scan-assembler "andi\t" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadbb-extu.c b/gcc/testsuite/gcc.target/riscv/xtheadbb-extu.c
new file mode 100644
index 00000000000..e0492f1f5ad
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadbb-extu.c
@@ -0,0 +1,22 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadbb" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadbb" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Og" } } */
+
+struct bar
+{
+  unsigned long a:5;
+  unsigned long b:26;
+  unsigned long c:22;
+};
+
+unsigned long
+foo (struct bar *s)
+{
+  return s->b;
+}
+
+/* { dg-final { scan-assembler "th.extu\t" } } */
+/* { dg-final { scan-assembler-not "andi" } } */
+/* { dg-final { scan-assembler-not "slli" } } */
+/* { dg-final { scan-assembler-not "srli" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadbb-ff1.c b/gcc/testsuite/gcc.target/riscv/xtheadbb-ff1.c
new file mode 100644
index 00000000000..72038c4e281
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadbb-ff1.c
@@ -0,0 +1,18 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadbb" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadbb" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Og" } } */
+
+int
+foo (unsigned long a)
+{
+  return __builtin_clzl (a);
+}
+
+int
+bar (unsigned long a)
+{
+  return __builtin_ctzl (a);
+}
+
+/* { dg-final { scan-assembler-times "th.ff1\t" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadbb-rev.c b/gcc/testsuite/gcc.target/riscv/xtheadbb-rev.c
new file mode 100644
index 00000000000..411d52007d2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadbb-rev.c
@@ -0,0 +1,45 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadbb" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadbb" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" } } */
+
+unsigned int
+foo32 (unsigned int x)
+{
+  return (((x << 24) & 0xff000000)
+	  | ((x << 8) & 0xff0000)
+	  | ((x >> 8) & 0xff00)
+	  | ((x >> 24) & 0xff));
+}
+
+unsigned int
+foo32_1 (unsigned int x)
+{
+  return __builtin_bswap32 (x);
+}
+
+#if __riscv_xlen == 64
+unsigned long
+foo64 (unsigned long x)
+{
+  return (((x << 56) & 0xff00000000000000ull)
+	  | ((x << 40) & 0xff000000000000ull)
+	  | ((x << 24) & 0xff0000000000ull)
+	  | ((x << 8) & 0xff00000000ull)
+	  | ((x >> 8) & 0xff000000)
+	  | ((x >> 24) & 0xff0000)
+	  | ((x >> 40) & 0xff00)
+	  | ((x >> 56) & 0xff));
+}
+
+unsigned long
+foo64_1 (unsigned long x)
+{
+  return __builtin_bswap64 (x);
+}
+#endif
+
+/* { dg-final { scan-assembler-times "th.rev\t" 2 { target { rv32 } } } } */
+
+/* { dg-final { scan-assembler-times "th.revw\t" 2 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times "th.rev\t" 2 { target { rv64 } } } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadbb-srri.c b/gcc/testsuite/gcc.target/riscv/xtheadbb-srri.c
new file mode 100644
index 00000000000..973ed175f17
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadbb-srri.c
@@ -0,0 +1,25 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_xtheadbb" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_xtheadbb" { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+unsigned long
+foo1 (unsigned long rs1)
+{
+    unsigned sz = sizeof(unsigned long) * 8;
+    unsigned shamt = sz - 11;
+    return (rs1 << shamt) | (rs1 >> (sz - shamt));
+}
+
+unsigned int
+foo2 (unsigned int rs1)
+{
+    unsigned sz = sizeof(unsigned int) * 8;
+    unsigned shamt = sz - 11;
+    return (rs1 << shamt) | (rs1 >> (sz - shamt));
+}
+
+/* { dg-final { scan-assembler-times "th.srri\t" 2 { target { rv32 } } } } */
+
+/* { dg-final { scan-assembler-times "th.srri\t" 1 { target { rv64 } } } } */
+/* { dg-final { scan-assembler-times "th.srriw\t" 1 { target { rv64 } } } } */