[llvm] [RISCV] Combine (srl (clmul (zext.w X), (zext.w Y)), 31). (PR #228848)

Craig Topper via llvm-commits llvm-commits at lists.llvm.org
Sun Oct 4 00:38:47 PDT 2026


https://github.com/topperc created https://github.com/llvm/llvm-project/pull/228848

into (srl (clmulr (shl X, 32), (shl Y, 32)), 32).

Stacked on #228846.

>From 44aceaca0aeb7876ad3c93ab89d9ebfd25aa6244 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Sat, 3 Oct 2026 19:04:22 -0700
Subject: [PATCH 1/4] [RISCV] Add Zbc RUN lines to clmulh.ll and clmulr.ll. NFC

---
 llvm/test/CodeGen/RISCV/clmulh.ll |  368 ++++++++++
 llvm/test/CodeGen/RISCV/clmulr.ll | 1037 ++++++++++++++++++++++++-----
 2 files changed, 1244 insertions(+), 161 deletions(-)

diff --git a/llvm/test/CodeGen/RISCV/clmulh.ll b/llvm/test/CodeGen/RISCV/clmulh.ll
index 5c09f34444e730e..568c18f5a162f46 100644
--- a/llvm/test/CodeGen/RISCV/clmulh.ll
+++ b/llvm/test/CodeGen/RISCV/clmulh.ll
@@ -5,6 +5,8 @@
 ; RUN: llc -mtriple=riscv64 -mattr=+m -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,CHECK-M,RV64IM
 ; RUN: llc -mtriple=riscv32 -mattr=+m,+zbs -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,CHECK-ZBS,RV32IMZBS
 ; RUN: llc -mtriple=riscv64 -mattr=+m,+zbs -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,CHECK-ZBS,RV64IMZBS
+; RUN: llc -mtriple=riscv32 -mattr=+m,+zbc -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,CHECK-ZBC,RV32IMZBC
+; RUN: llc -mtriple=riscv64 -mattr=+m,+zbc -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,CHECK-ZBC,RV64IMZBC
 ; RUN: llc -mtriple=riscv32 -mattr=+m,+zvbc -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,CHECK-ZVBC,RV32IMZVBC
 ; RUN: llc -mtriple=riscv64 -mattr=+m,+zvbc -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,CHECK-ZVBC,RV64IMZVBC
 
@@ -78,6 +80,14 @@ define i4 @clmulh_i4(i4 %a, i4 %b) nounwind {
 ; CHECK-ZBS-NEXT:    srli a0, a0, 4
 ; CHECK-ZBS-NEXT:    ret
 ;
+; CHECK-ZBC-LABEL: clmulh_i4:
+; CHECK-ZBC:       # %bb.0:
+; CHECK-ZBC-NEXT:    andi a1, a1, 15
+; CHECK-ZBC-NEXT:    andi a0, a0, 15
+; CHECK-ZBC-NEXT:    clmul a0, a0, a1
+; CHECK-ZBC-NEXT:    srli a0, a0, 4
+; CHECK-ZBC-NEXT:    ret
+;
 ; RV32IMZVBC-LABEL: clmulh_i4:
 ; RV32IMZVBC:       # %bb.0:
 ; RV32IMZVBC-NEXT:    andi a2, a1, 4
@@ -189,6 +199,14 @@ define i4 @clmulh_i4_bitreverse(i4 %a, i4 %b) nounwind {
 ; CHECK-ZBS-NEXT:    srli a0, a0, 4
 ; CHECK-ZBS-NEXT:    ret
 ;
+; CHECK-ZBC-LABEL: clmulh_i4_bitreverse:
+; CHECK-ZBC:       # %bb.0:
+; CHECK-ZBC-NEXT:    andi a1, a1, 15
+; CHECK-ZBC-NEXT:    andi a0, a0, 15
+; CHECK-ZBC-NEXT:    clmul a0, a0, a1
+; CHECK-ZBC-NEXT:    srli a0, a0, 4
+; CHECK-ZBC-NEXT:    ret
+;
 ; RV32IMZVBC-LABEL: clmulh_i4_bitreverse:
 ; RV32IMZVBC:       # %bb.0:
 ; RV32IMZVBC-NEXT:    andi a2, a1, 4
@@ -388,6 +406,14 @@ define i8 @clmulh_i8(i8 %a, i8 %b) nounwind {
 ; CHECK-ZBS-NEXT:    srli a0, a0, 8
 ; CHECK-ZBS-NEXT:    ret
 ;
+; CHECK-ZBC-LABEL: clmulh_i8:
+; CHECK-ZBC:       # %bb.0:
+; CHECK-ZBC-NEXT:    zext.b a1, a1
+; CHECK-ZBC-NEXT:    zext.b a0, a0
+; CHECK-ZBC-NEXT:    clmul a0, a0, a1
+; CHECK-ZBC-NEXT:    srli a0, a0, 8
+; CHECK-ZBC-NEXT:    ret
+;
 ; RV32IMZVBC-LABEL: clmulh_i8:
 ; RV32IMZVBC:       # %bb.0:
 ; RV32IMZVBC-NEXT:    zext.b a0, a0
@@ -927,6 +953,16 @@ define i16 @clmulh_i16(i16 %a, i16 %b) nounwind {
 ; RV64IMZBS-NEXT:    srli a0, a0, 16
 ; RV64IMZBS-NEXT:    ret
 ;
+; CHECK-ZBC-LABEL: clmulh_i16:
+; CHECK-ZBC:       # %bb.0:
+; CHECK-ZBC-NEXT:    lui a2, 16
+; CHECK-ZBC-NEXT:    addi a2, a2, -1
+; CHECK-ZBC-NEXT:    and a1, a1, a2
+; CHECK-ZBC-NEXT:    and a0, a0, a2
+; CHECK-ZBC-NEXT:    clmul a0, a0, a1
+; CHECK-ZBC-NEXT:    srli a0, a0, 16
+; CHECK-ZBC-NEXT:    ret
+;
 ; RV32IMZVBC-LABEL: clmulh_i16:
 ; RV32IMZVBC:       # %bb.0:
 ; RV32IMZVBC-NEXT:    addi sp, sp, -16
@@ -1994,6 +2030,19 @@ define i32 @clmulh_i32(i32 %a, i32 %b) nounwind {
 ; RV64IMZBS-NEXT:    addi sp, sp, 32
 ; RV64IMZBS-NEXT:    ret
 ;
+; RV32IMZBC-LABEL: clmulh_i32:
+; RV32IMZBC:       # %bb.0:
+; RV32IMZBC-NEXT:    clmulh a0, a0, a1
+; RV32IMZBC-NEXT:    ret
+;
+; RV64IMZBC-LABEL: clmulh_i32:
+; RV64IMZBC:       # %bb.0:
+; RV64IMZBC-NEXT:    slli a1, a1, 32
+; RV64IMZBC-NEXT:    slli a0, a0, 32
+; RV64IMZBC-NEXT:    clmulh a0, a0, a1
+; RV64IMZBC-NEXT:    srli a0, a0, 32
+; RV64IMZBC-NEXT:    ret
+;
 ; RV32IMZVBC-LABEL: clmulh_i32:
 ; RV32IMZVBC:       # %bb.0:
 ; RV32IMZVBC-NEXT:    addi sp, sp, -48
@@ -2342,6 +2391,16 @@ define void @commutative_clmulh_i8(i8 %x, i8 %y, ptr %p0, ptr %p1) {
 ; CHECK-ZBS-NEXT:    sb a0, 0(a3)
 ; CHECK-ZBS-NEXT:    ret
 ;
+; CHECK-ZBC-LABEL: commutative_clmulh_i8:
+; CHECK-ZBC:       # %bb.0:
+; CHECK-ZBC-NEXT:    zext.b a0, a0
+; CHECK-ZBC-NEXT:    zext.b a1, a1
+; CHECK-ZBC-NEXT:    clmul a0, a1, a0
+; CHECK-ZBC-NEXT:    srli a0, a0, 8
+; CHECK-ZBC-NEXT:    sb a0, 0(a2)
+; CHECK-ZBC-NEXT:    sb a0, 0(a3)
+; CHECK-ZBC-NEXT:    ret
+;
 ; RV32IMZVBC-LABEL: commutative_clmulh_i8:
 ; RV32IMZVBC:       # %bb.0:
 ; RV32IMZVBC-NEXT:    zext.b a1, a1
@@ -8299,6 +8358,315 @@ define void @commutative_clmulh_v2i64(<2 x i64> %x, <2 x i64> %y, ptr %p0, ptr %
 ; RV64IMZBS-NEXT:    addi sp, sp, 128
 ; RV64IMZBS-NEXT:    ret
 ;
+; RV32IMZBC-LABEL: commutative_clmulh_v2i64:
+; RV32IMZBC:       # %bb.0:
+; RV32IMZBC-NEXT:    addi sp, sp, -16
+; RV32IMZBC-NEXT:    sw s0, 12(sp) # 4-byte Folded Spill
+; RV32IMZBC-NEXT:    sw s1, 8(sp) # 4-byte Folded Spill
+; RV32IMZBC-NEXT:    sw s2, 4(sp) # 4-byte Folded Spill
+; RV32IMZBC-NEXT:    sw s3, 0(sp) # 4-byte Folded Spill
+; RV32IMZBC-NEXT:    lw a4, 4(a0)
+; RV32IMZBC-NEXT:    lui a6, 16
+; RV32IMZBC-NEXT:    lw t3, 8(a0)
+; RV32IMZBC-NEXT:    lw a5, 12(a0)
+; RV32IMZBC-NEXT:    lw t5, 0(a1)
+; RV32IMZBC-NEXT:    addi a7, a6, -256
+; RV32IMZBC-NEXT:    srli a6, a4, 8
+; RV32IMZBC-NEXT:    srli t0, a4, 24
+; RV32IMZBC-NEXT:    and t1, a4, a7
+; RV32IMZBC-NEXT:    and a6, a6, a7
+; RV32IMZBC-NEXT:    slli t1, t1, 8
+; RV32IMZBC-NEXT:    slli t2, a4, 24
+; RV32IMZBC-NEXT:    or a6, a6, t0
+; RV32IMZBC-NEXT:    or t0, t2, t1
+; RV32IMZBC-NEXT:    or a6, t0, a6
+; RV32IMZBC-NEXT:    lui t0, 61681
+; RV32IMZBC-NEXT:    srli t1, a6, 4
+; RV32IMZBC-NEXT:    addi t0, t0, -241
+; RV32IMZBC-NEXT:    and t1, t1, t0
+; RV32IMZBC-NEXT:    and a6, a6, t0
+; RV32IMZBC-NEXT:    slli a6, a6, 4
+; RV32IMZBC-NEXT:    lui t2, 209715
+; RV32IMZBC-NEXT:    or a6, t1, a6
+; RV32IMZBC-NEXT:    addi t1, t2, 819
+; RV32IMZBC-NEXT:    srli t2, a6, 2
+; RV32IMZBC-NEXT:    and a6, a6, t1
+; RV32IMZBC-NEXT:    and t2, t2, t1
+; RV32IMZBC-NEXT:    slli a6, a6, 2
+; RV32IMZBC-NEXT:    lw t6, 0(a0)
+; RV32IMZBC-NEXT:    or s0, t2, a6
+; RV32IMZBC-NEXT:    lw a6, 4(a1)
+; RV32IMZBC-NEXT:    lw t4, 8(a1)
+; RV32IMZBC-NEXT:    lw a0, 12(a1)
+; RV32IMZBC-NEXT:    srli s1, s0, 1
+; RV32IMZBC-NEXT:    lui t2, 349525
+; RV32IMZBC-NEXT:    srli a1, t5, 8
+; RV32IMZBC-NEXT:    and a1, a1, a7
+; RV32IMZBC-NEXT:    srli s2, t5, 24
+; RV32IMZBC-NEXT:    or s2, a1, s2
+; RV32IMZBC-NEXT:    and a1, t5, a7
+; RV32IMZBC-NEXT:    slli s3, a1, 8
+; RV32IMZBC-NEXT:    slli t5, t5, 24
+; RV32IMZBC-NEXT:    addi a1, t2, 1365
+; RV32IMZBC-NEXT:    or t5, t5, s3
+; RV32IMZBC-NEXT:    and s1, s1, a1
+; RV32IMZBC-NEXT:    or t5, t5, s2
+; RV32IMZBC-NEXT:    srli s2, t5, 4
+; RV32IMZBC-NEXT:    and t5, t5, t0
+; RV32IMZBC-NEXT:    and s2, s2, t0
+; RV32IMZBC-NEXT:    slli t5, t5, 4
+; RV32IMZBC-NEXT:    and s0, s0, a1
+; RV32IMZBC-NEXT:    or t5, s2, t5
+; RV32IMZBC-NEXT:    srli s2, t5, 2
+; RV32IMZBC-NEXT:    and t5, t5, t1
+; RV32IMZBC-NEXT:    and s2, s2, t1
+; RV32IMZBC-NEXT:    slli t5, t5, 2
+; RV32IMZBC-NEXT:    slli s0, s0, 1
+; RV32IMZBC-NEXT:    or s2, s2, t5
+; RV32IMZBC-NEXT:    or t5, s1, s0
+; RV32IMZBC-NEXT:    srli s0, s2, 1
+; RV32IMZBC-NEXT:    and s0, s0, a1
+; RV32IMZBC-NEXT:    srli s1, t6, 8
+; RV32IMZBC-NEXT:    and s1, s1, a7
+; RV32IMZBC-NEXT:    srli s3, t6, 24
+; RV32IMZBC-NEXT:    or s1, s1, s3
+; RV32IMZBC-NEXT:    and s3, t6, a7
+; RV32IMZBC-NEXT:    slli s3, s3, 8
+; RV32IMZBC-NEXT:    slli t6, t6, 24
+; RV32IMZBC-NEXT:    and s2, s2, a1
+; RV32IMZBC-NEXT:    or t6, t6, s3
+; RV32IMZBC-NEXT:    slli s2, s2, 1
+; RV32IMZBC-NEXT:    or t6, t6, s1
+; RV32IMZBC-NEXT:    srli s1, t6, 4
+; RV32IMZBC-NEXT:    and t6, t6, t0
+; RV32IMZBC-NEXT:    and s1, s1, t0
+; RV32IMZBC-NEXT:    slli t6, t6, 4
+; RV32IMZBC-NEXT:    or s0, s0, s2
+; RV32IMZBC-NEXT:    or t6, s1, t6
+; RV32IMZBC-NEXT:    srli s1, t6, 2
+; RV32IMZBC-NEXT:    and t6, t6, t1
+; RV32IMZBC-NEXT:    and s1, s1, t1
+; RV32IMZBC-NEXT:    slli t6, t6, 2
+; RV32IMZBC-NEXT:    or t6, s1, t6
+; RV32IMZBC-NEXT:    srli s1, a6, 8
+; RV32IMZBC-NEXT:    and s1, s1, a7
+; RV32IMZBC-NEXT:    srli s2, a6, 24
+; RV32IMZBC-NEXT:    or s1, s1, s2
+; RV32IMZBC-NEXT:    and s2, a6, a7
+; RV32IMZBC-NEXT:    slli s2, s2, 8
+; RV32IMZBC-NEXT:    slli s3, a6, 24
+; RV32IMZBC-NEXT:    or s2, s3, s2
+; RV32IMZBC-NEXT:    srli s3, t6, 1
+; RV32IMZBC-NEXT:    and s3, s3, a1
+; RV32IMZBC-NEXT:    or s1, s2, s1
+; RV32IMZBC-NEXT:    srli s2, s1, 4
+; RV32IMZBC-NEXT:    and s1, s1, t0
+; RV32IMZBC-NEXT:    and s2, s2, t0
+; RV32IMZBC-NEXT:    slli s1, s1, 4
+; RV32IMZBC-NEXT:    and t6, t6, a1
+; RV32IMZBC-NEXT:    or s1, s2, s1
+; RV32IMZBC-NEXT:    srli s2, s1, 2
+; RV32IMZBC-NEXT:    and s1, s1, t1
+; RV32IMZBC-NEXT:    and s2, s2, t1
+; RV32IMZBC-NEXT:    slli s1, s1, 2
+; RV32IMZBC-NEXT:    slli t6, t6, 1
+; RV32IMZBC-NEXT:    or s1, s2, s1
+; RV32IMZBC-NEXT:    srli s2, s1, 1
+; RV32IMZBC-NEXT:    and s1, s1, a1
+; RV32IMZBC-NEXT:    and s2, s2, a1
+; RV32IMZBC-NEXT:    slli s1, s1, 1
+; RV32IMZBC-NEXT:    or t6, s3, t6
+; RV32IMZBC-NEXT:    or s1, s2, s1
+; RV32IMZBC-NEXT:    clmul s0, s0, t5
+; RV32IMZBC-NEXT:    clmul t6, s1, t6
+; RV32IMZBC-NEXT:    clmulh t5, s1, t5
+; RV32IMZBC-NEXT:    xor t6, t6, s0
+; RV32IMZBC-NEXT:    xor t5, t5, t6
+; RV32IMZBC-NEXT:    srli t6, t5, 8
+; RV32IMZBC-NEXT:    and t6, t6, a7
+; RV32IMZBC-NEXT:    srli s0, t5, 24
+; RV32IMZBC-NEXT:    and s1, t5, a7
+; RV32IMZBC-NEXT:    slli t5, t5, 24
+; RV32IMZBC-NEXT:    slli s1, s1, 8
+; RV32IMZBC-NEXT:    or t6, t6, s0
+; RV32IMZBC-NEXT:    or t5, t5, s1
+; RV32IMZBC-NEXT:    or t5, t5, t6
+; RV32IMZBC-NEXT:    srli t6, t5, 4
+; RV32IMZBC-NEXT:    and t5, t5, t0
+; RV32IMZBC-NEXT:    and t6, t6, t0
+; RV32IMZBC-NEXT:    slli t5, t5, 4
+; RV32IMZBC-NEXT:    or t5, t6, t5
+; RV32IMZBC-NEXT:    srli t6, t5, 2
+; RV32IMZBC-NEXT:    and t6, t6, t1
+; RV32IMZBC-NEXT:    and t5, t5, t1
+; RV32IMZBC-NEXT:    srli s0, a5, 8
+; RV32IMZBC-NEXT:    slli t5, t5, 2
+; RV32IMZBC-NEXT:    and s0, s0, a7
+; RV32IMZBC-NEXT:    srli s1, a5, 24
+; RV32IMZBC-NEXT:    and s2, a5, a7
+; RV32IMZBC-NEXT:    slli s2, s2, 8
+; RV32IMZBC-NEXT:    slli s3, a5, 24
+; RV32IMZBC-NEXT:    or s0, s0, s1
+; RV32IMZBC-NEXT:    or s1, s3, s2
+; RV32IMZBC-NEXT:    or t5, t6, t5
+; RV32IMZBC-NEXT:    or s0, s1, s0
+; RV32IMZBC-NEXT:    srli t6, s0, 4
+; RV32IMZBC-NEXT:    and s0, s0, t0
+; RV32IMZBC-NEXT:    and s1, t6, t0
+; RV32IMZBC-NEXT:    slli s0, s0, 4
+; RV32IMZBC-NEXT:    srli t6, t5, 1
+; RV32IMZBC-NEXT:    or s0, s1, s0
+; RV32IMZBC-NEXT:    srli s1, s0, 2
+; RV32IMZBC-NEXT:    and s0, s0, t1
+; RV32IMZBC-NEXT:    and s1, s1, t1
+; RV32IMZBC-NEXT:    slli s0, s0, 2
+; RV32IMZBC-NEXT:    or s0, s1, s0
+; RV32IMZBC-NEXT:    srli s1, t4, 8
+; RV32IMZBC-NEXT:    and s1, s1, a7
+; RV32IMZBC-NEXT:    srli s2, t4, 24
+; RV32IMZBC-NEXT:    or s1, s1, s2
+; RV32IMZBC-NEXT:    and s2, t4, a7
+; RV32IMZBC-NEXT:    slli s2, s2, 8
+; RV32IMZBC-NEXT:    slli t4, t4, 24
+; RV32IMZBC-NEXT:    srli s3, s0, 1
+; RV32IMZBC-NEXT:    or t4, t4, s2
+; RV32IMZBC-NEXT:    and s2, s3, a1
+; RV32IMZBC-NEXT:    or t4, t4, s1
+; RV32IMZBC-NEXT:    srli s1, t4, 4
+; RV32IMZBC-NEXT:    and t4, t4, t0
+; RV32IMZBC-NEXT:    and s1, s1, t0
+; RV32IMZBC-NEXT:    slli t4, t4, 4
+; RV32IMZBC-NEXT:    and s0, s0, a1
+; RV32IMZBC-NEXT:    or t4, s1, t4
+; RV32IMZBC-NEXT:    srli s1, t4, 2
+; RV32IMZBC-NEXT:    and t4, t4, t1
+; RV32IMZBC-NEXT:    and s1, s1, t1
+; RV32IMZBC-NEXT:    slli t4, t4, 2
+; RV32IMZBC-NEXT:    slli s0, s0, 1
+; RV32IMZBC-NEXT:    or s1, s1, t4
+; RV32IMZBC-NEXT:    or t4, s2, s0
+; RV32IMZBC-NEXT:    srli s0, s1, 1
+; RV32IMZBC-NEXT:    and s0, s0, a1
+; RV32IMZBC-NEXT:    srli s2, t3, 8
+; RV32IMZBC-NEXT:    and s2, s2, a7
+; RV32IMZBC-NEXT:    srli s3, t3, 24
+; RV32IMZBC-NEXT:    or s2, s2, s3
+; RV32IMZBC-NEXT:    and s3, t3, a7
+; RV32IMZBC-NEXT:    slli s3, s3, 8
+; RV32IMZBC-NEXT:    slli t3, t3, 24
+; RV32IMZBC-NEXT:    and s1, s1, a1
+; RV32IMZBC-NEXT:    or t3, t3, s3
+; RV32IMZBC-NEXT:    slli s1, s1, 1
+; RV32IMZBC-NEXT:    or t3, t3, s2
+; RV32IMZBC-NEXT:    srli s2, t3, 4
+; RV32IMZBC-NEXT:    and t3, t3, t0
+; RV32IMZBC-NEXT:    and s2, s2, t0
+; RV32IMZBC-NEXT:    slli t3, t3, 4
+; RV32IMZBC-NEXT:    or s0, s0, s1
+; RV32IMZBC-NEXT:    or t3, s2, t3
+; RV32IMZBC-NEXT:    srli s1, t3, 2
+; RV32IMZBC-NEXT:    and t3, t3, t1
+; RV32IMZBC-NEXT:    and s1, s1, t1
+; RV32IMZBC-NEXT:    slli t3, t3, 2
+; RV32IMZBC-NEXT:    or t3, s1, t3
+; RV32IMZBC-NEXT:    srli s1, a0, 8
+; RV32IMZBC-NEXT:    and s1, s1, a7
+; RV32IMZBC-NEXT:    srli s2, a0, 24
+; RV32IMZBC-NEXT:    or s1, s1, s2
+; RV32IMZBC-NEXT:    and s2, a0, a7
+; RV32IMZBC-NEXT:    slli s2, s2, 8
+; RV32IMZBC-NEXT:    slli s3, a0, 24
+; RV32IMZBC-NEXT:    or s2, s3, s2
+; RV32IMZBC-NEXT:    srli s3, t3, 1
+; RV32IMZBC-NEXT:    and s3, s3, a1
+; RV32IMZBC-NEXT:    or s1, s2, s1
+; RV32IMZBC-NEXT:    srli s2, s1, 4
+; RV32IMZBC-NEXT:    and s1, s1, t0
+; RV32IMZBC-NEXT:    and s2, s2, t0
+; RV32IMZBC-NEXT:    slli s1, s1, 4
+; RV32IMZBC-NEXT:    and t3, t3, a1
+; RV32IMZBC-NEXT:    or s1, s2, s1
+; RV32IMZBC-NEXT:    srli s2, s1, 2
+; RV32IMZBC-NEXT:    and s1, s1, t1
+; RV32IMZBC-NEXT:    and s2, s2, t1
+; RV32IMZBC-NEXT:    slli s1, s1, 2
+; RV32IMZBC-NEXT:    slli t3, t3, 1
+; RV32IMZBC-NEXT:    or s1, s2, s1
+; RV32IMZBC-NEXT:    srli s2, s1, 1
+; RV32IMZBC-NEXT:    and s1, s1, a1
+; RV32IMZBC-NEXT:    and s2, s2, a1
+; RV32IMZBC-NEXT:    slli s1, s1, 1
+; RV32IMZBC-NEXT:    or t3, s3, t3
+; RV32IMZBC-NEXT:    or s1, s2, s1
+; RV32IMZBC-NEXT:    clmul s0, s0, t4
+; RV32IMZBC-NEXT:    clmul t3, s1, t3
+; RV32IMZBC-NEXT:    addi t2, t2, 1364
+; RV32IMZBC-NEXT:    clmulh t4, s1, t4
+; RV32IMZBC-NEXT:    and t6, t6, t2
+; RV32IMZBC-NEXT:    xor t3, t3, s0
+; RV32IMZBC-NEXT:    and t5, t5, a1
+; RV32IMZBC-NEXT:    xor t3, t4, t3
+; RV32IMZBC-NEXT:    slli t5, t5, 1
+; RV32IMZBC-NEXT:    srli t4, t3, 8
+; RV32IMZBC-NEXT:    or t5, t6, t5
+; RV32IMZBC-NEXT:    and t4, t4, a7
+; RV32IMZBC-NEXT:    srli t6, t3, 24
+; RV32IMZBC-NEXT:    and a7, t3, a7
+; RV32IMZBC-NEXT:    slli t3, t3, 24
+; RV32IMZBC-NEXT:    slli a7, a7, 8
+; RV32IMZBC-NEXT:    or t4, t4, t6
+; RV32IMZBC-NEXT:    or a7, t3, a7
+; RV32IMZBC-NEXT:    srli t3, t5, 1
+; RV32IMZBC-NEXT:    or a7, a7, t4
+; RV32IMZBC-NEXT:    srli t4, a7, 4
+; RV32IMZBC-NEXT:    and a7, a7, t0
+; RV32IMZBC-NEXT:    and t0, t4, t0
+; RV32IMZBC-NEXT:    slli a7, a7, 4
+; RV32IMZBC-NEXT:    clmulr t4, a6, a4
+; RV32IMZBC-NEXT:    or a7, t0, a7
+; RV32IMZBC-NEXT:    srli t0, a7, 2
+; RV32IMZBC-NEXT:    and a7, a7, t1
+; RV32IMZBC-NEXT:    and t0, t0, t1
+; RV32IMZBC-NEXT:    slli a7, a7, 2
+; RV32IMZBC-NEXT:    slli t4, t4, 31
+; RV32IMZBC-NEXT:    or a7, t0, a7
+; RV32IMZBC-NEXT:    srli t0, a7, 1
+; RV32IMZBC-NEXT:    and a1, a7, a1
+; RV32IMZBC-NEXT:    and a7, t0, t2
+; RV32IMZBC-NEXT:    slli a1, a1, 1
+; RV32IMZBC-NEXT:    or a1, a7, a1
+; RV32IMZBC-NEXT:    clmulr a7, a0, a5
+; RV32IMZBC-NEXT:    or t0, t3, t4
+; RV32IMZBC-NEXT:    srli a1, a1, 1
+; RV32IMZBC-NEXT:    slli a7, a7, 31
+; RV32IMZBC-NEXT:    clmulh a4, a6, a4
+; RV32IMZBC-NEXT:    or a1, a1, a7
+; RV32IMZBC-NEXT:    clmulh a0, a0, a5
+; RV32IMZBC-NEXT:    sw t0, 0(a2)
+; RV32IMZBC-NEXT:    sw a4, 4(a2)
+; RV32IMZBC-NEXT:    sw a1, 8(a2)
+; RV32IMZBC-NEXT:    sw a0, 12(a2)
+; RV32IMZBC-NEXT:    sw t0, 0(a3)
+; RV32IMZBC-NEXT:    sw a4, 4(a3)
+; RV32IMZBC-NEXT:    sw a1, 8(a3)
+; RV32IMZBC-NEXT:    sw a0, 12(a3)
+; RV32IMZBC-NEXT:    lw s0, 12(sp) # 4-byte Folded Reload
+; RV32IMZBC-NEXT:    lw s1, 8(sp) # 4-byte Folded Reload
+; RV32IMZBC-NEXT:    lw s2, 4(sp) # 4-byte Folded Reload
+; RV32IMZBC-NEXT:    lw s3, 0(sp) # 4-byte Folded Reload
+; RV32IMZBC-NEXT:    addi sp, sp, 16
+; RV32IMZBC-NEXT:    ret
+;
+; RV64IMZBC-LABEL: commutative_clmulh_v2i64:
+; RV64IMZBC:       # %bb.0:
+; RV64IMZBC-NEXT:    clmulh a0, a2, a0
+; RV64IMZBC-NEXT:    clmulh a1, a3, a1
+; RV64IMZBC-NEXT:    sd a0, 0(a4)
+; RV64IMZBC-NEXT:    sd a1, 8(a4)
+; RV64IMZBC-NEXT:    sd a0, 0(a5)
+; RV64IMZBC-NEXT:    sd a1, 8(a5)
+; RV64IMZBC-NEXT:    ret
+;
 ; CHECK-ZVBC-LABEL: commutative_clmulh_v2i64:
 ; CHECK-ZVBC:       # %bb.0:
 ; CHECK-ZVBC-NEXT:    vsetivli zero, 2, e64, m2, ta, ma
diff --git a/llvm/test/CodeGen/RISCV/clmulr.ll b/llvm/test/CodeGen/RISCV/clmulr.ll
index 229ce8df00e1597..23cf4093d99bf52 100644
--- a/llvm/test/CodeGen/RISCV/clmulr.ll
+++ b/llvm/test/CodeGen/RISCV/clmulr.ll
@@ -5,35 +5,101 @@
 ; RUN: llc -mtriple=riscv64 -mattr=+m -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,CHECK-M,RV64IM
 ; RUN: llc -mtriple=riscv32 -mattr=+m,+zbs -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,CHECK-ZBS,RV32IMZBS
 ; RUN: llc -mtriple=riscv64 -mattr=+m,+zbs -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,CHECK-ZBS,RV64IMZBS
+; RUN: llc -mtriple=riscv32 -mattr=+m,+zbc -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,CHECK-ZBC,RV32IMZBC
+; RUN: llc -mtriple=riscv64 -mattr=+m,+zbc -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,CHECK-ZBC,RV64IMZBC
 
 define i4 @clmulr_i4(i4 %a, i4 %b) nounwind {
-; CHECK-LABEL: clmulr_i4:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    andi a0, a0, 15
-; CHECK-NEXT:    andi a2, a1, 2
-; CHECK-NEXT:    andi a3, a1, 1
-; CHECK-NEXT:    slli a4, a0, 1
-; CHECK-NEXT:    seqz a2, a2
-; CHECK-NEXT:    seqz a3, a3
-; CHECK-NEXT:    addi a2, a2, -1
-; CHECK-NEXT:    addi a3, a3, -1
-; CHECK-NEXT:    and a2, a2, a4
-; CHECK-NEXT:    and a3, a3, a0
-; CHECK-NEXT:    slli a4, a0, 2
-; CHECK-NEXT:    andi a5, a1, 4
-; CHECK-NEXT:    seqz a5, a5
-; CHECK-NEXT:    andi a1, a1, 8
-; CHECK-NEXT:    addi a5, a5, -1
-; CHECK-NEXT:    seqz a1, a1
-; CHECK-NEXT:    slli a0, a0, 3
-; CHECK-NEXT:    addi a1, a1, -1
-; CHECK-NEXT:    and a4, a5, a4
-; CHECK-NEXT:    and a0, a1, a0
-; CHECK-NEXT:    xor a2, a3, a2
-; CHECK-NEXT:    xor a0, a4, a0
-; CHECK-NEXT:    xor a0, a2, a0
-; CHECK-NEXT:    srli a0, a0, 3
-; CHECK-NEXT:    ret
+; CHECK-I-LABEL: clmulr_i4:
+; CHECK-I:       # %bb.0:
+; CHECK-I-NEXT:    andi a0, a0, 15
+; CHECK-I-NEXT:    andi a2, a1, 2
+; CHECK-I-NEXT:    andi a3, a1, 1
+; CHECK-I-NEXT:    slli a4, a0, 1
+; CHECK-I-NEXT:    seqz a2, a2
+; CHECK-I-NEXT:    seqz a3, a3
+; CHECK-I-NEXT:    addi a2, a2, -1
+; CHECK-I-NEXT:    addi a3, a3, -1
+; CHECK-I-NEXT:    and a2, a2, a4
+; CHECK-I-NEXT:    and a3, a3, a0
+; CHECK-I-NEXT:    slli a4, a0, 2
+; CHECK-I-NEXT:    andi a5, a1, 4
+; CHECK-I-NEXT:    seqz a5, a5
+; CHECK-I-NEXT:    andi a1, a1, 8
+; CHECK-I-NEXT:    addi a5, a5, -1
+; CHECK-I-NEXT:    seqz a1, a1
+; CHECK-I-NEXT:    slli a0, a0, 3
+; CHECK-I-NEXT:    addi a1, a1, -1
+; CHECK-I-NEXT:    and a4, a5, a4
+; CHECK-I-NEXT:    and a0, a1, a0
+; CHECK-I-NEXT:    xor a2, a3, a2
+; CHECK-I-NEXT:    xor a0, a4, a0
+; CHECK-I-NEXT:    xor a0, a2, a0
+; CHECK-I-NEXT:    srli a0, a0, 3
+; CHECK-I-NEXT:    ret
+;
+; CHECK-M-LABEL: clmulr_i4:
+; CHECK-M:       # %bb.0:
+; CHECK-M-NEXT:    andi a0, a0, 15
+; CHECK-M-NEXT:    andi a2, a1, 2
+; CHECK-M-NEXT:    andi a3, a1, 1
+; CHECK-M-NEXT:    slli a4, a0, 1
+; CHECK-M-NEXT:    seqz a2, a2
+; CHECK-M-NEXT:    seqz a3, a3
+; CHECK-M-NEXT:    addi a2, a2, -1
+; CHECK-M-NEXT:    addi a3, a3, -1
+; CHECK-M-NEXT:    and a2, a2, a4
+; CHECK-M-NEXT:    and a3, a3, a0
+; CHECK-M-NEXT:    slli a4, a0, 2
+; CHECK-M-NEXT:    andi a5, a1, 4
+; CHECK-M-NEXT:    seqz a5, a5
+; CHECK-M-NEXT:    andi a1, a1, 8
+; CHECK-M-NEXT:    addi a5, a5, -1
+; CHECK-M-NEXT:    seqz a1, a1
+; CHECK-M-NEXT:    slli a0, a0, 3
+; CHECK-M-NEXT:    addi a1, a1, -1
+; CHECK-M-NEXT:    and a4, a5, a4
+; CHECK-M-NEXT:    and a0, a1, a0
+; CHECK-M-NEXT:    xor a2, a3, a2
+; CHECK-M-NEXT:    xor a0, a4, a0
+; CHECK-M-NEXT:    xor a0, a2, a0
+; CHECK-M-NEXT:    srli a0, a0, 3
+; CHECK-M-NEXT:    ret
+;
+; CHECK-ZBS-LABEL: clmulr_i4:
+; CHECK-ZBS:       # %bb.0:
+; CHECK-ZBS-NEXT:    andi a0, a0, 15
+; CHECK-ZBS-NEXT:    andi a2, a1, 2
+; CHECK-ZBS-NEXT:    andi a3, a1, 1
+; CHECK-ZBS-NEXT:    slli a4, a0, 1
+; CHECK-ZBS-NEXT:    seqz a2, a2
+; CHECK-ZBS-NEXT:    seqz a3, a3
+; CHECK-ZBS-NEXT:    addi a2, a2, -1
+; CHECK-ZBS-NEXT:    addi a3, a3, -1
+; CHECK-ZBS-NEXT:    and a2, a2, a4
+; CHECK-ZBS-NEXT:    and a3, a3, a0
+; CHECK-ZBS-NEXT:    slli a4, a0, 2
+; CHECK-ZBS-NEXT:    andi a5, a1, 4
+; CHECK-ZBS-NEXT:    seqz a5, a5
+; CHECK-ZBS-NEXT:    andi a1, a1, 8
+; CHECK-ZBS-NEXT:    addi a5, a5, -1
+; CHECK-ZBS-NEXT:    seqz a1, a1
+; CHECK-ZBS-NEXT:    slli a0, a0, 3
+; CHECK-ZBS-NEXT:    addi a1, a1, -1
+; CHECK-ZBS-NEXT:    and a4, a5, a4
+; CHECK-ZBS-NEXT:    and a0, a1, a0
+; CHECK-ZBS-NEXT:    xor a2, a3, a2
+; CHECK-ZBS-NEXT:    xor a0, a4, a0
+; CHECK-ZBS-NEXT:    xor a0, a2, a0
+; CHECK-ZBS-NEXT:    srli a0, a0, 3
+; CHECK-ZBS-NEXT:    ret
+;
+; CHECK-ZBC-LABEL: clmulr_i4:
+; CHECK-ZBC:       # %bb.0:
+; CHECK-ZBC-NEXT:    andi a1, a1, 15
+; CHECK-ZBC-NEXT:    andi a0, a0, 15
+; CHECK-ZBC-NEXT:    clmul a0, a0, a1
+; CHECK-ZBC-NEXT:    srli a0, a0, 3
+; CHECK-ZBC-NEXT:    ret
   %a.ext = zext i4 %a to i8
   %b.ext = zext i4 %b to i8
   %clmul = call i8 @llvm.clmul.i8(i8 %a.ext, i8 %b.ext)
@@ -43,33 +109,97 @@ define i4 @clmulr_i4(i4 %a, i4 %b) nounwind {
 }
 
 define i4 @clmulr_i4_bitreverse(i4 %a, i4 %b) nounwind {
-; CHECK-LABEL: clmulr_i4_bitreverse:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    andi a0, a0, 15
-; CHECK-NEXT:    andi a2, a1, 2
-; CHECK-NEXT:    andi a3, a1, 1
-; CHECK-NEXT:    slli a4, a0, 1
-; CHECK-NEXT:    seqz a2, a2
-; CHECK-NEXT:    seqz a3, a3
-; CHECK-NEXT:    addi a2, a2, -1
-; CHECK-NEXT:    addi a3, a3, -1
-; CHECK-NEXT:    and a2, a2, a4
-; CHECK-NEXT:    and a3, a3, a0
-; CHECK-NEXT:    slli a4, a0, 2
-; CHECK-NEXT:    andi a5, a1, 4
-; CHECK-NEXT:    seqz a5, a5
-; CHECK-NEXT:    andi a1, a1, 8
-; CHECK-NEXT:    addi a5, a5, -1
-; CHECK-NEXT:    seqz a1, a1
-; CHECK-NEXT:    slli a0, a0, 3
-; CHECK-NEXT:    addi a1, a1, -1
-; CHECK-NEXT:    and a4, a5, a4
-; CHECK-NEXT:    and a0, a1, a0
-; CHECK-NEXT:    xor a2, a3, a2
-; CHECK-NEXT:    xor a0, a4, a0
-; CHECK-NEXT:    xor a0, a2, a0
-; CHECK-NEXT:    srli a0, a0, 3
-; CHECK-NEXT:    ret
+; CHECK-I-LABEL: clmulr_i4_bitreverse:
+; CHECK-I:       # %bb.0:
+; CHECK-I-NEXT:    andi a0, a0, 15
+; CHECK-I-NEXT:    andi a2, a1, 2
+; CHECK-I-NEXT:    andi a3, a1, 1
+; CHECK-I-NEXT:    slli a4, a0, 1
+; CHECK-I-NEXT:    seqz a2, a2
+; CHECK-I-NEXT:    seqz a3, a3
+; CHECK-I-NEXT:    addi a2, a2, -1
+; CHECK-I-NEXT:    addi a3, a3, -1
+; CHECK-I-NEXT:    and a2, a2, a4
+; CHECK-I-NEXT:    and a3, a3, a0
+; CHECK-I-NEXT:    slli a4, a0, 2
+; CHECK-I-NEXT:    andi a5, a1, 4
+; CHECK-I-NEXT:    seqz a5, a5
+; CHECK-I-NEXT:    andi a1, a1, 8
+; CHECK-I-NEXT:    addi a5, a5, -1
+; CHECK-I-NEXT:    seqz a1, a1
+; CHECK-I-NEXT:    slli a0, a0, 3
+; CHECK-I-NEXT:    addi a1, a1, -1
+; CHECK-I-NEXT:    and a4, a5, a4
+; CHECK-I-NEXT:    and a0, a1, a0
+; CHECK-I-NEXT:    xor a2, a3, a2
+; CHECK-I-NEXT:    xor a0, a4, a0
+; CHECK-I-NEXT:    xor a0, a2, a0
+; CHECK-I-NEXT:    srli a0, a0, 3
+; CHECK-I-NEXT:    ret
+;
+; CHECK-M-LABEL: clmulr_i4_bitreverse:
+; CHECK-M:       # %bb.0:
+; CHECK-M-NEXT:    andi a0, a0, 15
+; CHECK-M-NEXT:    andi a2, a1, 2
+; CHECK-M-NEXT:    andi a3, a1, 1
+; CHECK-M-NEXT:    slli a4, a0, 1
+; CHECK-M-NEXT:    seqz a2, a2
+; CHECK-M-NEXT:    seqz a3, a3
+; CHECK-M-NEXT:    addi a2, a2, -1
+; CHECK-M-NEXT:    addi a3, a3, -1
+; CHECK-M-NEXT:    and a2, a2, a4
+; CHECK-M-NEXT:    and a3, a3, a0
+; CHECK-M-NEXT:    slli a4, a0, 2
+; CHECK-M-NEXT:    andi a5, a1, 4
+; CHECK-M-NEXT:    seqz a5, a5
+; CHECK-M-NEXT:    andi a1, a1, 8
+; CHECK-M-NEXT:    addi a5, a5, -1
+; CHECK-M-NEXT:    seqz a1, a1
+; CHECK-M-NEXT:    slli a0, a0, 3
+; CHECK-M-NEXT:    addi a1, a1, -1
+; CHECK-M-NEXT:    and a4, a5, a4
+; CHECK-M-NEXT:    and a0, a1, a0
+; CHECK-M-NEXT:    xor a2, a3, a2
+; CHECK-M-NEXT:    xor a0, a4, a0
+; CHECK-M-NEXT:    xor a0, a2, a0
+; CHECK-M-NEXT:    srli a0, a0, 3
+; CHECK-M-NEXT:    ret
+;
+; CHECK-ZBS-LABEL: clmulr_i4_bitreverse:
+; CHECK-ZBS:       # %bb.0:
+; CHECK-ZBS-NEXT:    andi a0, a0, 15
+; CHECK-ZBS-NEXT:    andi a2, a1, 2
+; CHECK-ZBS-NEXT:    andi a3, a1, 1
+; CHECK-ZBS-NEXT:    slli a4, a0, 1
+; CHECK-ZBS-NEXT:    seqz a2, a2
+; CHECK-ZBS-NEXT:    seqz a3, a3
+; CHECK-ZBS-NEXT:    addi a2, a2, -1
+; CHECK-ZBS-NEXT:    addi a3, a3, -1
+; CHECK-ZBS-NEXT:    and a2, a2, a4
+; CHECK-ZBS-NEXT:    and a3, a3, a0
+; CHECK-ZBS-NEXT:    slli a4, a0, 2
+; CHECK-ZBS-NEXT:    andi a5, a1, 4
+; CHECK-ZBS-NEXT:    seqz a5, a5
+; CHECK-ZBS-NEXT:    andi a1, a1, 8
+; CHECK-ZBS-NEXT:    addi a5, a5, -1
+; CHECK-ZBS-NEXT:    seqz a1, a1
+; CHECK-ZBS-NEXT:    slli a0, a0, 3
+; CHECK-ZBS-NEXT:    addi a1, a1, -1
+; CHECK-ZBS-NEXT:    and a4, a5, a4
+; CHECK-ZBS-NEXT:    and a0, a1, a0
+; CHECK-ZBS-NEXT:    xor a2, a3, a2
+; CHECK-ZBS-NEXT:    xor a0, a4, a0
+; CHECK-ZBS-NEXT:    xor a0, a2, a0
+; CHECK-ZBS-NEXT:    srli a0, a0, 3
+; CHECK-ZBS-NEXT:    ret
+;
+; CHECK-ZBC-LABEL: clmulr_i4_bitreverse:
+; CHECK-ZBC:       # %bb.0:
+; CHECK-ZBC-NEXT:    andi a1, a1, 15
+; CHECK-ZBC-NEXT:    andi a0, a0, 15
+; CHECK-ZBC-NEXT:    clmul a0, a0, a1
+; CHECK-ZBC-NEXT:    srli a0, a0, 3
+; CHECK-ZBC-NEXT:    ret
   %a.rev = call i4 @llvm.bitreverse.i4(i4 %a)
   %b.rev = call i4 @llvm.bitreverse.i4(i4 %b)
   %res.rev = call i4 @llvm.clmul.i4(i4 %a.rev, i4 %b.rev)
@@ -78,57 +208,169 @@ define i4 @clmulr_i4_bitreverse(i4 %a, i4 %b) nounwind {
 }
 
 define i8 @clmulr_i8(i8 %a, i8 %b) nounwind {
-; CHECK-LABEL: clmulr_i8:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    zext.b a0, a0
-; CHECK-NEXT:    andi a2, a1, 2
-; CHECK-NEXT:    andi a3, a1, 1
-; CHECK-NEXT:    seqz a2, a2
-; CHECK-NEXT:    slli a4, a0, 1
-; CHECK-NEXT:    addi a2, a2, -1
-; CHECK-NEXT:    seqz a3, a3
-; CHECK-NEXT:    and a2, a2, a4
-; CHECK-NEXT:    addi a3, a3, -1
-; CHECK-NEXT:    andi a4, a1, 4
-; CHECK-NEXT:    slli a5, a0, 2
-; CHECK-NEXT:    seqz a4, a4
-; CHECK-NEXT:    addi a4, a4, -1
-; CHECK-NEXT:    andi a6, a1, 8
-; CHECK-NEXT:    and a4, a4, a5
-; CHECK-NEXT:    seqz a5, a6
-; CHECK-NEXT:    slli a6, a0, 3
-; CHECK-NEXT:    addi a5, a5, -1
-; CHECK-NEXT:    and a5, a5, a6
-; CHECK-NEXT:    and a3, a3, a0
-; CHECK-NEXT:    xor a2, a3, a2
-; CHECK-NEXT:    xor a4, a4, a5
-; CHECK-NEXT:    xor a2, a2, a4
-; CHECK-NEXT:    andi a3, a1, 16
-; CHECK-NEXT:    slli a4, a0, 4
-; CHECK-NEXT:    seqz a3, a3
-; CHECK-NEXT:    addi a3, a3, -1
-; CHECK-NEXT:    andi a5, a1, 32
-; CHECK-NEXT:    and a3, a3, a4
-; CHECK-NEXT:    seqz a4, a5
-; CHECK-NEXT:    slli a5, a0, 5
-; CHECK-NEXT:    addi a4, a4, -1
-; CHECK-NEXT:    and a4, a4, a5
-; CHECK-NEXT:    andi a5, a1, 64
-; CHECK-NEXT:    xor a3, a3, a4
-; CHECK-NEXT:    seqz a4, a5
-; CHECK-NEXT:    slli a5, a0, 6
-; CHECK-NEXT:    addi a4, a4, -1
-; CHECK-NEXT:    and a4, a4, a5
-; CHECK-NEXT:    andi a1, a1, 128
-; CHECK-NEXT:    xor a3, a3, a4
-; CHECK-NEXT:    seqz a1, a1
-; CHECK-NEXT:    slli a0, a0, 7
-; CHECK-NEXT:    addi a1, a1, -1
-; CHECK-NEXT:    xor a2, a2, a3
-; CHECK-NEXT:    and a0, a1, a0
-; CHECK-NEXT:    xor a0, a2, a0
-; CHECK-NEXT:    srli a0, a0, 7
-; CHECK-NEXT:    ret
+; CHECK-I-LABEL: clmulr_i8:
+; CHECK-I:       # %bb.0:
+; CHECK-I-NEXT:    zext.b a0, a0
+; CHECK-I-NEXT:    andi a2, a1, 2
+; CHECK-I-NEXT:    andi a3, a1, 1
+; CHECK-I-NEXT:    seqz a2, a2
+; CHECK-I-NEXT:    slli a4, a0, 1
+; CHECK-I-NEXT:    addi a2, a2, -1
+; CHECK-I-NEXT:    seqz a3, a3
+; CHECK-I-NEXT:    and a2, a2, a4
+; CHECK-I-NEXT:    addi a3, a3, -1
+; CHECK-I-NEXT:    andi a4, a1, 4
+; CHECK-I-NEXT:    slli a5, a0, 2
+; CHECK-I-NEXT:    seqz a4, a4
+; CHECK-I-NEXT:    addi a4, a4, -1
+; CHECK-I-NEXT:    andi a6, a1, 8
+; CHECK-I-NEXT:    and a4, a4, a5
+; CHECK-I-NEXT:    seqz a5, a6
+; CHECK-I-NEXT:    slli a6, a0, 3
+; CHECK-I-NEXT:    addi a5, a5, -1
+; CHECK-I-NEXT:    and a5, a5, a6
+; CHECK-I-NEXT:    and a3, a3, a0
+; CHECK-I-NEXT:    xor a2, a3, a2
+; CHECK-I-NEXT:    xor a4, a4, a5
+; CHECK-I-NEXT:    xor a2, a2, a4
+; CHECK-I-NEXT:    andi a3, a1, 16
+; CHECK-I-NEXT:    slli a4, a0, 4
+; CHECK-I-NEXT:    seqz a3, a3
+; CHECK-I-NEXT:    addi a3, a3, -1
+; CHECK-I-NEXT:    andi a5, a1, 32
+; CHECK-I-NEXT:    and a3, a3, a4
+; CHECK-I-NEXT:    seqz a4, a5
+; CHECK-I-NEXT:    slli a5, a0, 5
+; CHECK-I-NEXT:    addi a4, a4, -1
+; CHECK-I-NEXT:    and a4, a4, a5
+; CHECK-I-NEXT:    andi a5, a1, 64
+; CHECK-I-NEXT:    xor a3, a3, a4
+; CHECK-I-NEXT:    seqz a4, a5
+; CHECK-I-NEXT:    slli a5, a0, 6
+; CHECK-I-NEXT:    addi a4, a4, -1
+; CHECK-I-NEXT:    and a4, a4, a5
+; CHECK-I-NEXT:    andi a1, a1, 128
+; CHECK-I-NEXT:    xor a3, a3, a4
+; CHECK-I-NEXT:    seqz a1, a1
+; CHECK-I-NEXT:    slli a0, a0, 7
+; CHECK-I-NEXT:    addi a1, a1, -1
+; CHECK-I-NEXT:    xor a2, a2, a3
+; CHECK-I-NEXT:    and a0, a1, a0
+; CHECK-I-NEXT:    xor a0, a2, a0
+; CHECK-I-NEXT:    srli a0, a0, 7
+; CHECK-I-NEXT:    ret
+;
+; CHECK-M-LABEL: clmulr_i8:
+; CHECK-M:       # %bb.0:
+; CHECK-M-NEXT:    zext.b a0, a0
+; CHECK-M-NEXT:    andi a2, a1, 2
+; CHECK-M-NEXT:    andi a3, a1, 1
+; CHECK-M-NEXT:    seqz a2, a2
+; CHECK-M-NEXT:    slli a4, a0, 1
+; CHECK-M-NEXT:    addi a2, a2, -1
+; CHECK-M-NEXT:    seqz a3, a3
+; CHECK-M-NEXT:    and a2, a2, a4
+; CHECK-M-NEXT:    addi a3, a3, -1
+; CHECK-M-NEXT:    andi a4, a1, 4
+; CHECK-M-NEXT:    slli a5, a0, 2
+; CHECK-M-NEXT:    seqz a4, a4
+; CHECK-M-NEXT:    addi a4, a4, -1
+; CHECK-M-NEXT:    andi a6, a1, 8
+; CHECK-M-NEXT:    and a4, a4, a5
+; CHECK-M-NEXT:    seqz a5, a6
+; CHECK-M-NEXT:    slli a6, a0, 3
+; CHECK-M-NEXT:    addi a5, a5, -1
+; CHECK-M-NEXT:    and a5, a5, a6
+; CHECK-M-NEXT:    and a3, a3, a0
+; CHECK-M-NEXT:    xor a2, a3, a2
+; CHECK-M-NEXT:    xor a4, a4, a5
+; CHECK-M-NEXT:    xor a2, a2, a4
+; CHECK-M-NEXT:    andi a3, a1, 16
+; CHECK-M-NEXT:    slli a4, a0, 4
+; CHECK-M-NEXT:    seqz a3, a3
+; CHECK-M-NEXT:    addi a3, a3, -1
+; CHECK-M-NEXT:    andi a5, a1, 32
+; CHECK-M-NEXT:    and a3, a3, a4
+; CHECK-M-NEXT:    seqz a4, a5
+; CHECK-M-NEXT:    slli a5, a0, 5
+; CHECK-M-NEXT:    addi a4, a4, -1
+; CHECK-M-NEXT:    and a4, a4, a5
+; CHECK-M-NEXT:    andi a5, a1, 64
+; CHECK-M-NEXT:    xor a3, a3, a4
+; CHECK-M-NEXT:    seqz a4, a5
+; CHECK-M-NEXT:    slli a5, a0, 6
+; CHECK-M-NEXT:    addi a4, a4, -1
+; CHECK-M-NEXT:    and a4, a4, a5
+; CHECK-M-NEXT:    andi a1, a1, 128
+; CHECK-M-NEXT:    xor a3, a3, a4
+; CHECK-M-NEXT:    seqz a1, a1
+; CHECK-M-NEXT:    slli a0, a0, 7
+; CHECK-M-NEXT:    addi a1, a1, -1
+; CHECK-M-NEXT:    xor a2, a2, a3
+; CHECK-M-NEXT:    and a0, a1, a0
+; CHECK-M-NEXT:    xor a0, a2, a0
+; CHECK-M-NEXT:    srli a0, a0, 7
+; CHECK-M-NEXT:    ret
+;
+; CHECK-ZBS-LABEL: clmulr_i8:
+; CHECK-ZBS:       # %bb.0:
+; CHECK-ZBS-NEXT:    zext.b a0, a0
+; CHECK-ZBS-NEXT:    andi a2, a1, 2
+; CHECK-ZBS-NEXT:    andi a3, a1, 1
+; CHECK-ZBS-NEXT:    seqz a2, a2
+; CHECK-ZBS-NEXT:    slli a4, a0, 1
+; CHECK-ZBS-NEXT:    addi a2, a2, -1
+; CHECK-ZBS-NEXT:    seqz a3, a3
+; CHECK-ZBS-NEXT:    and a2, a2, a4
+; CHECK-ZBS-NEXT:    addi a3, a3, -1
+; CHECK-ZBS-NEXT:    andi a4, a1, 4
+; CHECK-ZBS-NEXT:    slli a5, a0, 2
+; CHECK-ZBS-NEXT:    seqz a4, a4
+; CHECK-ZBS-NEXT:    addi a4, a4, -1
+; CHECK-ZBS-NEXT:    andi a6, a1, 8
+; CHECK-ZBS-NEXT:    and a4, a4, a5
+; CHECK-ZBS-NEXT:    seqz a5, a6
+; CHECK-ZBS-NEXT:    slli a6, a0, 3
+; CHECK-ZBS-NEXT:    addi a5, a5, -1
+; CHECK-ZBS-NEXT:    and a5, a5, a6
+; CHECK-ZBS-NEXT:    and a3, a3, a0
+; CHECK-ZBS-NEXT:    xor a2, a3, a2
+; CHECK-ZBS-NEXT:    xor a4, a4, a5
+; CHECK-ZBS-NEXT:    xor a2, a2, a4
+; CHECK-ZBS-NEXT:    andi a3, a1, 16
+; CHECK-ZBS-NEXT:    slli a4, a0, 4
+; CHECK-ZBS-NEXT:    seqz a3, a3
+; CHECK-ZBS-NEXT:    addi a3, a3, -1
+; CHECK-ZBS-NEXT:    andi a5, a1, 32
+; CHECK-ZBS-NEXT:    and a3, a3, a4
+; CHECK-ZBS-NEXT:    seqz a4, a5
+; CHECK-ZBS-NEXT:    slli a5, a0, 5
+; CHECK-ZBS-NEXT:    addi a4, a4, -1
+; CHECK-ZBS-NEXT:    and a4, a4, a5
+; CHECK-ZBS-NEXT:    andi a5, a1, 64
+; CHECK-ZBS-NEXT:    xor a3, a3, a4
+; CHECK-ZBS-NEXT:    seqz a4, a5
+; CHECK-ZBS-NEXT:    slli a5, a0, 6
+; CHECK-ZBS-NEXT:    addi a4, a4, -1
+; CHECK-ZBS-NEXT:    and a4, a4, a5
+; CHECK-ZBS-NEXT:    andi a1, a1, 128
+; CHECK-ZBS-NEXT:    xor a3, a3, a4
+; CHECK-ZBS-NEXT:    seqz a1, a1
+; CHECK-ZBS-NEXT:    slli a0, a0, 7
+; CHECK-ZBS-NEXT:    addi a1, a1, -1
+; CHECK-ZBS-NEXT:    xor a2, a2, a3
+; CHECK-ZBS-NEXT:    and a0, a1, a0
+; CHECK-ZBS-NEXT:    xor a0, a2, a0
+; CHECK-ZBS-NEXT:    srli a0, a0, 7
+; CHECK-ZBS-NEXT:    ret
+;
+; CHECK-ZBC-LABEL: clmulr_i8:
+; CHECK-ZBC:       # %bb.0:
+; CHECK-ZBC-NEXT:    zext.b a1, a1
+; CHECK-ZBC-NEXT:    zext.b a0, a0
+; CHECK-ZBC-NEXT:    clmul a0, a0, a1
+; CHECK-ZBC-NEXT:    srli a0, a0, 7
+; CHECK-ZBC-NEXT:    ret
   %a.ext = zext i8 %a to i16
   %b.ext = zext i8 %b to i16
   %clmul = call i16 @llvm.clmul.i16(i16 %a.ext, i16 %b.ext)
@@ -605,6 +847,16 @@ define i16 @clmulr_i16(i16 %a, i16 %b) nounwind {
 ; RV64IMZBS-NEXT:    or a0, a2, a0
 ; RV64IMZBS-NEXT:    srli a0, a0, 15
 ; RV64IMZBS-NEXT:    ret
+;
+; CHECK-ZBC-LABEL: clmulr_i16:
+; CHECK-ZBC:       # %bb.0:
+; CHECK-ZBC-NEXT:    lui a2, 16
+; CHECK-ZBC-NEXT:    addi a2, a2, -1
+; CHECK-ZBC-NEXT:    and a1, a1, a2
+; CHECK-ZBC-NEXT:    and a0, a0, a2
+; CHECK-ZBC-NEXT:    clmul a0, a0, a1
+; CHECK-ZBC-NEXT:    srli a0, a0, 15
+; CHECK-ZBC-NEXT:    ret
   %a.ext = zext i16 %a to i32
   %b.ext = zext i16 %b to i32
   %clmul = call i32 @llvm.clmul.i32(i32 %a.ext, i32 %b.ext)
@@ -1585,6 +1837,19 @@ define i32 @clmulr_i32(i32 %a, i32 %b) nounwind {
 ; RV64IMZBS-NEXT:    ld s2, 8(sp) # 8-byte Folded Reload
 ; RV64IMZBS-NEXT:    addi sp, sp, 32
 ; RV64IMZBS-NEXT:    ret
+;
+; RV32IMZBC-LABEL: clmulr_i32:
+; RV32IMZBC:       # %bb.0:
+; RV32IMZBC-NEXT:    clmulr a0, a0, a1
+; RV32IMZBC-NEXT:    ret
+;
+; RV64IMZBC-LABEL: clmulr_i32:
+; RV64IMZBC:       # %bb.0:
+; RV64IMZBC-NEXT:    slli a1, a1, 32
+; RV64IMZBC-NEXT:    slli a0, a0, 32
+; RV64IMZBC-NEXT:    clmulh a0, a0, a1
+; RV64IMZBC-NEXT:    srli a0, a0, 31
+; RV64IMZBC-NEXT:    ret
   %a.ext = zext i32 %a to i64
   %b.ext = zext i32 %b to i64
   %clmul = call i64 @llvm.clmul.i64(i64 %a.ext, i64 %b.ext)
@@ -1596,59 +1861,177 @@ define i32 @clmulr_i32(i32 %a, i32 %b) nounwind {
 declare i8 @use(i8, i1)
 
 define void @commutative_clmulr_i8(i8 %x, i8 %y, ptr %p0, ptr %p1) nounwind {
-; CHECK-LABEL: commutative_clmulr_i8:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    zext.b a1, a1
-; CHECK-NEXT:    andi a4, a0, 2
-; CHECK-NEXT:    slli a5, a1, 1
-; CHECK-NEXT:    seqz a4, a4
-; CHECK-NEXT:    addi a4, a4, -1
-; CHECK-NEXT:    andi a6, a0, 1
-; CHECK-NEXT:    and a4, a4, a5
-; CHECK-NEXT:    seqz a5, a6
-; CHECK-NEXT:    addi a5, a5, -1
-; CHECK-NEXT:    andi a6, a0, 4
-; CHECK-NEXT:    slli a7, a1, 2
-; CHECK-NEXT:    seqz a6, a6
-; CHECK-NEXT:    addi a6, a6, -1
-; CHECK-NEXT:    andi t0, a0, 8
-; CHECK-NEXT:    and a6, a6, a7
-; CHECK-NEXT:    seqz a7, t0
-; CHECK-NEXT:    slli t0, a1, 3
-; CHECK-NEXT:    addi a7, a7, -1
-; CHECK-NEXT:    and a7, a7, t0
-; CHECK-NEXT:    and a5, a5, a1
-; CHECK-NEXT:    xor a4, a5, a4
-; CHECK-NEXT:    xor a5, a6, a7
-; CHECK-NEXT:    xor a4, a4, a5
-; CHECK-NEXT:    andi a5, a0, 16
-; CHECK-NEXT:    slli a6, a1, 4
-; CHECK-NEXT:    seqz a5, a5
-; CHECK-NEXT:    addi a5, a5, -1
-; CHECK-NEXT:    andi a7, a0, 32
-; CHECK-NEXT:    and a5, a5, a6
-; CHECK-NEXT:    seqz a6, a7
-; CHECK-NEXT:    slli a7, a1, 5
-; CHECK-NEXT:    addi a6, a6, -1
-; CHECK-NEXT:    and a6, a6, a7
-; CHECK-NEXT:    andi a7, a0, 64
-; CHECK-NEXT:    xor a5, a5, a6
-; CHECK-NEXT:    seqz a6, a7
-; CHECK-NEXT:    slli a7, a1, 6
-; CHECK-NEXT:    addi a6, a6, -1
-; CHECK-NEXT:    and a6, a6, a7
-; CHECK-NEXT:    andi a0, a0, 128
-; CHECK-NEXT:    xor a5, a5, a6
-; CHECK-NEXT:    seqz a0, a0
-; CHECK-NEXT:    slli a1, a1, 7
-; CHECK-NEXT:    addi a0, a0, -1
-; CHECK-NEXT:    xor a4, a4, a5
-; CHECK-NEXT:    and a0, a0, a1
-; CHECK-NEXT:    xor a0, a4, a0
-; CHECK-NEXT:    srli a0, a0, 7
-; CHECK-NEXT:    sb a0, 0(a2)
-; CHECK-NEXT:    sb a0, 0(a3)
-; CHECK-NEXT:    ret
+; CHECK-I-LABEL: commutative_clmulr_i8:
+; CHECK-I:       # %bb.0:
+; CHECK-I-NEXT:    zext.b a1, a1
+; CHECK-I-NEXT:    andi a4, a0, 2
+; CHECK-I-NEXT:    slli a5, a1, 1
+; CHECK-I-NEXT:    seqz a4, a4
+; CHECK-I-NEXT:    addi a4, a4, -1
+; CHECK-I-NEXT:    andi a6, a0, 1
+; CHECK-I-NEXT:    and a4, a4, a5
+; CHECK-I-NEXT:    seqz a5, a6
+; CHECK-I-NEXT:    addi a5, a5, -1
+; CHECK-I-NEXT:    andi a6, a0, 4
+; CHECK-I-NEXT:    slli a7, a1, 2
+; CHECK-I-NEXT:    seqz a6, a6
+; CHECK-I-NEXT:    addi a6, a6, -1
+; CHECK-I-NEXT:    andi t0, a0, 8
+; CHECK-I-NEXT:    and a6, a6, a7
+; CHECK-I-NEXT:    seqz a7, t0
+; CHECK-I-NEXT:    slli t0, a1, 3
+; CHECK-I-NEXT:    addi a7, a7, -1
+; CHECK-I-NEXT:    and a7, a7, t0
+; CHECK-I-NEXT:    and a5, a5, a1
+; CHECK-I-NEXT:    xor a4, a5, a4
+; CHECK-I-NEXT:    xor a5, a6, a7
+; CHECK-I-NEXT:    xor a4, a4, a5
+; CHECK-I-NEXT:    andi a5, a0, 16
+; CHECK-I-NEXT:    slli a6, a1, 4
+; CHECK-I-NEXT:    seqz a5, a5
+; CHECK-I-NEXT:    addi a5, a5, -1
+; CHECK-I-NEXT:    andi a7, a0, 32
+; CHECK-I-NEXT:    and a5, a5, a6
+; CHECK-I-NEXT:    seqz a6, a7
+; CHECK-I-NEXT:    slli a7, a1, 5
+; CHECK-I-NEXT:    addi a6, a6, -1
+; CHECK-I-NEXT:    and a6, a6, a7
+; CHECK-I-NEXT:    andi a7, a0, 64
+; CHECK-I-NEXT:    xor a5, a5, a6
+; CHECK-I-NEXT:    seqz a6, a7
+; CHECK-I-NEXT:    slli a7, a1, 6
+; CHECK-I-NEXT:    addi a6, a6, -1
+; CHECK-I-NEXT:    and a6, a6, a7
+; CHECK-I-NEXT:    andi a0, a0, 128
+; CHECK-I-NEXT:    xor a5, a5, a6
+; CHECK-I-NEXT:    seqz a0, a0
+; CHECK-I-NEXT:    slli a1, a1, 7
+; CHECK-I-NEXT:    addi a0, a0, -1
+; CHECK-I-NEXT:    xor a4, a4, a5
+; CHECK-I-NEXT:    and a0, a0, a1
+; CHECK-I-NEXT:    xor a0, a4, a0
+; CHECK-I-NEXT:    srli a0, a0, 7
+; CHECK-I-NEXT:    sb a0, 0(a2)
+; CHECK-I-NEXT:    sb a0, 0(a3)
+; CHECK-I-NEXT:    ret
+;
+; CHECK-M-LABEL: commutative_clmulr_i8:
+; CHECK-M:       # %bb.0:
+; CHECK-M-NEXT:    zext.b a1, a1
+; CHECK-M-NEXT:    andi a4, a0, 2
+; CHECK-M-NEXT:    slli a5, a1, 1
+; CHECK-M-NEXT:    seqz a4, a4
+; CHECK-M-NEXT:    addi a4, a4, -1
+; CHECK-M-NEXT:    andi a6, a0, 1
+; CHECK-M-NEXT:    and a4, a4, a5
+; CHECK-M-NEXT:    seqz a5, a6
+; CHECK-M-NEXT:    addi a5, a5, -1
+; CHECK-M-NEXT:    andi a6, a0, 4
+; CHECK-M-NEXT:    slli a7, a1, 2
+; CHECK-M-NEXT:    seqz a6, a6
+; CHECK-M-NEXT:    addi a6, a6, -1
+; CHECK-M-NEXT:    andi t0, a0, 8
+; CHECK-M-NEXT:    and a6, a6, a7
+; CHECK-M-NEXT:    seqz a7, t0
+; CHECK-M-NEXT:    slli t0, a1, 3
+; CHECK-M-NEXT:    addi a7, a7, -1
+; CHECK-M-NEXT:    and a7, a7, t0
+; CHECK-M-NEXT:    and a5, a5, a1
+; CHECK-M-NEXT:    xor a4, a5, a4
+; CHECK-M-NEXT:    xor a5, a6, a7
+; CHECK-M-NEXT:    xor a4, a4, a5
+; CHECK-M-NEXT:    andi a5, a0, 16
+; CHECK-M-NEXT:    slli a6, a1, 4
+; CHECK-M-NEXT:    seqz a5, a5
+; CHECK-M-NEXT:    addi a5, a5, -1
+; CHECK-M-NEXT:    andi a7, a0, 32
+; CHECK-M-NEXT:    and a5, a5, a6
+; CHECK-M-NEXT:    seqz a6, a7
+; CHECK-M-NEXT:    slli a7, a1, 5
+; CHECK-M-NEXT:    addi a6, a6, -1
+; CHECK-M-NEXT:    and a6, a6, a7
+; CHECK-M-NEXT:    andi a7, a0, 64
+; CHECK-M-NEXT:    xor a5, a5, a6
+; CHECK-M-NEXT:    seqz a6, a7
+; CHECK-M-NEXT:    slli a7, a1, 6
+; CHECK-M-NEXT:    addi a6, a6, -1
+; CHECK-M-NEXT:    and a6, a6, a7
+; CHECK-M-NEXT:    andi a0, a0, 128
+; CHECK-M-NEXT:    xor a5, a5, a6
+; CHECK-M-NEXT:    seqz a0, a0
+; CHECK-M-NEXT:    slli a1, a1, 7
+; CHECK-M-NEXT:    addi a0, a0, -1
+; CHECK-M-NEXT:    xor a4, a4, a5
+; CHECK-M-NEXT:    and a0, a0, a1
+; CHECK-M-NEXT:    xor a0, a4, a0
+; CHECK-M-NEXT:    srli a0, a0, 7
+; CHECK-M-NEXT:    sb a0, 0(a2)
+; CHECK-M-NEXT:    sb a0, 0(a3)
+; CHECK-M-NEXT:    ret
+;
+; CHECK-ZBS-LABEL: commutative_clmulr_i8:
+; CHECK-ZBS:       # %bb.0:
+; CHECK-ZBS-NEXT:    zext.b a1, a1
+; CHECK-ZBS-NEXT:    andi a4, a0, 2
+; CHECK-ZBS-NEXT:    slli a5, a1, 1
+; CHECK-ZBS-NEXT:    seqz a4, a4
+; CHECK-ZBS-NEXT:    addi a4, a4, -1
+; CHECK-ZBS-NEXT:    andi a6, a0, 1
+; CHECK-ZBS-NEXT:    and a4, a4, a5
+; CHECK-ZBS-NEXT:    seqz a5, a6
+; CHECK-ZBS-NEXT:    addi a5, a5, -1
+; CHECK-ZBS-NEXT:    andi a6, a0, 4
+; CHECK-ZBS-NEXT:    slli a7, a1, 2
+; CHECK-ZBS-NEXT:    seqz a6, a6
+; CHECK-ZBS-NEXT:    addi a6, a6, -1
+; CHECK-ZBS-NEXT:    andi t0, a0, 8
+; CHECK-ZBS-NEXT:    and a6, a6, a7
+; CHECK-ZBS-NEXT:    seqz a7, t0
+; CHECK-ZBS-NEXT:    slli t0, a1, 3
+; CHECK-ZBS-NEXT:    addi a7, a7, -1
+; CHECK-ZBS-NEXT:    and a7, a7, t0
+; CHECK-ZBS-NEXT:    and a5, a5, a1
+; CHECK-ZBS-NEXT:    xor a4, a5, a4
+; CHECK-ZBS-NEXT:    xor a5, a6, a7
+; CHECK-ZBS-NEXT:    xor a4, a4, a5
+; CHECK-ZBS-NEXT:    andi a5, a0, 16
+; CHECK-ZBS-NEXT:    slli a6, a1, 4
+; CHECK-ZBS-NEXT:    seqz a5, a5
+; CHECK-ZBS-NEXT:    addi a5, a5, -1
+; CHECK-ZBS-NEXT:    andi a7, a0, 32
+; CHECK-ZBS-NEXT:    and a5, a5, a6
+; CHECK-ZBS-NEXT:    seqz a6, a7
+; CHECK-ZBS-NEXT:    slli a7, a1, 5
+; CHECK-ZBS-NEXT:    addi a6, a6, -1
+; CHECK-ZBS-NEXT:    and a6, a6, a7
+; CHECK-ZBS-NEXT:    andi a7, a0, 64
+; CHECK-ZBS-NEXT:    xor a5, a5, a6
+; CHECK-ZBS-NEXT:    seqz a6, a7
+; CHECK-ZBS-NEXT:    slli a7, a1, 6
+; CHECK-ZBS-NEXT:    addi a6, a6, -1
+; CHECK-ZBS-NEXT:    and a6, a6, a7
+; CHECK-ZBS-NEXT:    andi a0, a0, 128
+; CHECK-ZBS-NEXT:    xor a5, a5, a6
+; CHECK-ZBS-NEXT:    seqz a0, a0
+; CHECK-ZBS-NEXT:    slli a1, a1, 7
+; CHECK-ZBS-NEXT:    addi a0, a0, -1
+; CHECK-ZBS-NEXT:    xor a4, a4, a5
+; CHECK-ZBS-NEXT:    and a0, a0, a1
+; CHECK-ZBS-NEXT:    xor a0, a4, a0
+; CHECK-ZBS-NEXT:    srli a0, a0, 7
+; CHECK-ZBS-NEXT:    sb a0, 0(a2)
+; CHECK-ZBS-NEXT:    sb a0, 0(a3)
+; CHECK-ZBS-NEXT:    ret
+;
+; CHECK-ZBC-LABEL: commutative_clmulr_i8:
+; CHECK-ZBC:       # %bb.0:
+; CHECK-ZBC-NEXT:    zext.b a0, a0
+; CHECK-ZBC-NEXT:    zext.b a1, a1
+; CHECK-ZBC-NEXT:    clmul a0, a1, a0
+; CHECK-ZBC-NEXT:    srli a0, a0, 7
+; CHECK-ZBC-NEXT:    sb a0, 0(a2)
+; CHECK-ZBC-NEXT:    sb a0, 0(a3)
+; CHECK-ZBC-NEXT:    ret
   %x.ext = zext i8 %x to i16
   %y.ext = zext i8 %y to i16
   %clmul_xy = call i16 @llvm.clmul.i16(i16 %x.ext, i16 %y.ext)
@@ -1894,6 +2277,42 @@ define void @mul_use_commutative_clmul_i8(i8 %x, i8 %y, ptr %p0, ptr %p1) nounwi
 ; RV64IMZBS-NEXT:    ld s1, 8(sp) # 8-byte Folded Reload
 ; RV64IMZBS-NEXT:    addi sp, sp, 32
 ; RV64IMZBS-NEXT:    ret
+;
+; RV32IMZBC-LABEL: mul_use_commutative_clmul_i8:
+; RV32IMZBC:       # %bb.0:
+; RV32IMZBC-NEXT:    addi sp, sp, -16
+; RV32IMZBC-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
+; RV32IMZBC-NEXT:    sw s0, 8(sp) # 4-byte Folded Spill
+; RV32IMZBC-NEXT:    sw s1, 4(sp) # 4-byte Folded Spill
+; RV32IMZBC-NEXT:    mv s0, a3
+; RV32IMZBC-NEXT:    clmul s1, a0, a1
+; RV32IMZBC-NEXT:    sb s1, 0(a2)
+; RV32IMZBC-NEXT:    mv a0, s1
+; RV32IMZBC-NEXT:    call use
+; RV32IMZBC-NEXT:    sb s1, 0(s0)
+; RV32IMZBC-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
+; RV32IMZBC-NEXT:    lw s0, 8(sp) # 4-byte Folded Reload
+; RV32IMZBC-NEXT:    lw s1, 4(sp) # 4-byte Folded Reload
+; RV32IMZBC-NEXT:    addi sp, sp, 16
+; RV32IMZBC-NEXT:    ret
+;
+; RV64IMZBC-LABEL: mul_use_commutative_clmul_i8:
+; RV64IMZBC:       # %bb.0:
+; RV64IMZBC-NEXT:    addi sp, sp, -32
+; RV64IMZBC-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
+; RV64IMZBC-NEXT:    sd s0, 16(sp) # 8-byte Folded Spill
+; RV64IMZBC-NEXT:    sd s1, 8(sp) # 8-byte Folded Spill
+; RV64IMZBC-NEXT:    mv s0, a3
+; RV64IMZBC-NEXT:    clmul s1, a0, a1
+; RV64IMZBC-NEXT:    sb s1, 0(a2)
+; RV64IMZBC-NEXT:    mv a0, s1
+; RV64IMZBC-NEXT:    call use
+; RV64IMZBC-NEXT:    sb s1, 0(s0)
+; RV64IMZBC-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
+; RV64IMZBC-NEXT:    ld s0, 16(sp) # 8-byte Folded Reload
+; RV64IMZBC-NEXT:    ld s1, 8(sp) # 8-byte Folded Reload
+; RV64IMZBC-NEXT:    addi sp, sp, 32
+; RV64IMZBC-NEXT:    ret
   %xy = call i8 @llvm.clmul.i8(i8 %x, i8 %y)
   %yx = call i8 @llvm.clmul.i8(i8 %y, i8 %x)
   store i8 %xy, ptr %p0
@@ -7788,6 +8207,304 @@ define void @commutative_clmulr_v2i64(<2 x i64> %x, <2 x i64> %y, ptr %p0, ptr %
 ; RV64IMZBS-NEXT:    ld s11, 24(sp) # 8-byte Folded Reload
 ; RV64IMZBS-NEXT:    addi sp, sp, 128
 ; RV64IMZBS-NEXT:    ret
+;
+; RV32IMZBC-LABEL: commutative_clmulr_v2i64:
+; RV32IMZBC:       # %bb.0:
+; RV32IMZBC-NEXT:    addi sp, sp, -16
+; RV32IMZBC-NEXT:    sw s0, 12(sp) # 4-byte Folded Spill
+; RV32IMZBC-NEXT:    sw s1, 8(sp) # 4-byte Folded Spill
+; RV32IMZBC-NEXT:    sw s2, 4(sp) # 4-byte Folded Spill
+; RV32IMZBC-NEXT:    lw a4, 4(a0)
+; RV32IMZBC-NEXT:    lui a6, 16
+; RV32IMZBC-NEXT:    lw t2, 8(a0)
+; RV32IMZBC-NEXT:    lw a5, 12(a0)
+; RV32IMZBC-NEXT:    lw t4, 0(a1)
+; RV32IMZBC-NEXT:    addi a6, a6, -256
+; RV32IMZBC-NEXT:    srli a7, a4, 8
+; RV32IMZBC-NEXT:    srli t0, a4, 24
+; RV32IMZBC-NEXT:    and t1, a4, a6
+; RV32IMZBC-NEXT:    and a7, a7, a6
+; RV32IMZBC-NEXT:    slli t1, t1, 8
+; RV32IMZBC-NEXT:    slli t3, a4, 24
+; RV32IMZBC-NEXT:    or a7, a7, t0
+; RV32IMZBC-NEXT:    or t0, t3, t1
+; RV32IMZBC-NEXT:    or a7, t0, a7
+; RV32IMZBC-NEXT:    lui t0, 61681
+; RV32IMZBC-NEXT:    srli t1, a7, 4
+; RV32IMZBC-NEXT:    addi t0, t0, -241
+; RV32IMZBC-NEXT:    and t1, t1, t0
+; RV32IMZBC-NEXT:    and a7, a7, t0
+; RV32IMZBC-NEXT:    slli a7, a7, 4
+; RV32IMZBC-NEXT:    lui t3, 209715
+; RV32IMZBC-NEXT:    or a7, t1, a7
+; RV32IMZBC-NEXT:    addi t1, t3, 819
+; RV32IMZBC-NEXT:    srli t3, a7, 2
+; RV32IMZBC-NEXT:    and a7, a7, t1
+; RV32IMZBC-NEXT:    and t3, t3, t1
+; RV32IMZBC-NEXT:    slli a7, a7, 2
+; RV32IMZBC-NEXT:    lw t5, 0(a0)
+; RV32IMZBC-NEXT:    or t6, t3, a7
+; RV32IMZBC-NEXT:    lw a7, 4(a1)
+; RV32IMZBC-NEXT:    lw t3, 8(a1)
+; RV32IMZBC-NEXT:    lw a0, 12(a1)
+; RV32IMZBC-NEXT:    srli s0, t6, 1
+; RV32IMZBC-NEXT:    lui a1, 349525
+; RV32IMZBC-NEXT:    srli s1, t4, 8
+; RV32IMZBC-NEXT:    and s1, s1, a6
+; RV32IMZBC-NEXT:    srli s2, t4, 24
+; RV32IMZBC-NEXT:    or s1, s1, s2
+; RV32IMZBC-NEXT:    and s2, t4, a6
+; RV32IMZBC-NEXT:    slli s2, s2, 8
+; RV32IMZBC-NEXT:    slli t4, t4, 24
+; RV32IMZBC-NEXT:    addi a1, a1, 1365
+; RV32IMZBC-NEXT:    or t4, t4, s2
+; RV32IMZBC-NEXT:    and s0, s0, a1
+; RV32IMZBC-NEXT:    or t4, t4, s1
+; RV32IMZBC-NEXT:    srli s1, t4, 4
+; RV32IMZBC-NEXT:    and t4, t4, t0
+; RV32IMZBC-NEXT:    and s1, s1, t0
+; RV32IMZBC-NEXT:    slli t4, t4, 4
+; RV32IMZBC-NEXT:    and t6, t6, a1
+; RV32IMZBC-NEXT:    or t4, s1, t4
+; RV32IMZBC-NEXT:    srli s1, t4, 2
+; RV32IMZBC-NEXT:    and t4, t4, t1
+; RV32IMZBC-NEXT:    and s1, s1, t1
+; RV32IMZBC-NEXT:    slli t4, t4, 2
+; RV32IMZBC-NEXT:    slli t6, t6, 1
+; RV32IMZBC-NEXT:    or s1, s1, t4
+; RV32IMZBC-NEXT:    or t4, s0, t6
+; RV32IMZBC-NEXT:    srli t6, s1, 1
+; RV32IMZBC-NEXT:    and t6, t6, a1
+; RV32IMZBC-NEXT:    srli s0, t5, 8
+; RV32IMZBC-NEXT:    and s0, s0, a6
+; RV32IMZBC-NEXT:    srli s2, t5, 24
+; RV32IMZBC-NEXT:    or s0, s0, s2
+; RV32IMZBC-NEXT:    and s2, t5, a6
+; RV32IMZBC-NEXT:    slli s2, s2, 8
+; RV32IMZBC-NEXT:    slli t5, t5, 24
+; RV32IMZBC-NEXT:    and s1, s1, a1
+; RV32IMZBC-NEXT:    or t5, t5, s2
+; RV32IMZBC-NEXT:    slli s1, s1, 1
+; RV32IMZBC-NEXT:    or t5, t5, s0
+; RV32IMZBC-NEXT:    srli s0, t5, 4
+; RV32IMZBC-NEXT:    and t5, t5, t0
+; RV32IMZBC-NEXT:    and s0, s0, t0
+; RV32IMZBC-NEXT:    slli t5, t5, 4
+; RV32IMZBC-NEXT:    or t6, t6, s1
+; RV32IMZBC-NEXT:    or t5, s0, t5
+; RV32IMZBC-NEXT:    srli s0, t5, 2
+; RV32IMZBC-NEXT:    and t5, t5, t1
+; RV32IMZBC-NEXT:    and s0, s0, t1
+; RV32IMZBC-NEXT:    slli t5, t5, 2
+; RV32IMZBC-NEXT:    or t5, s0, t5
+; RV32IMZBC-NEXT:    srli s0, a7, 8
+; RV32IMZBC-NEXT:    and s0, s0, a6
+; RV32IMZBC-NEXT:    srli s1, a7, 24
+; RV32IMZBC-NEXT:    or s0, s0, s1
+; RV32IMZBC-NEXT:    and s1, a7, a6
+; RV32IMZBC-NEXT:    slli s1, s1, 8
+; RV32IMZBC-NEXT:    slli s2, a7, 24
+; RV32IMZBC-NEXT:    or s1, s2, s1
+; RV32IMZBC-NEXT:    srli s2, t5, 1
+; RV32IMZBC-NEXT:    and s2, s2, a1
+; RV32IMZBC-NEXT:    or s0, s1, s0
+; RV32IMZBC-NEXT:    srli s1, s0, 4
+; RV32IMZBC-NEXT:    and s0, s0, t0
+; RV32IMZBC-NEXT:    and s1, s1, t0
+; RV32IMZBC-NEXT:    slli s0, s0, 4
+; RV32IMZBC-NEXT:    and t5, t5, a1
+; RV32IMZBC-NEXT:    or s0, s1, s0
+; RV32IMZBC-NEXT:    srli s1, s0, 2
+; RV32IMZBC-NEXT:    and s0, s0, t1
+; RV32IMZBC-NEXT:    and s1, s1, t1
+; RV32IMZBC-NEXT:    slli s0, s0, 2
+; RV32IMZBC-NEXT:    slli t5, t5, 1
+; RV32IMZBC-NEXT:    or s0, s1, s0
+; RV32IMZBC-NEXT:    srli s1, s0, 1
+; RV32IMZBC-NEXT:    and s0, s0, a1
+; RV32IMZBC-NEXT:    and s1, s1, a1
+; RV32IMZBC-NEXT:    slli s0, s0, 1
+; RV32IMZBC-NEXT:    or t5, s2, t5
+; RV32IMZBC-NEXT:    or s0, s1, s0
+; RV32IMZBC-NEXT:    clmul t6, t6, t4
+; RV32IMZBC-NEXT:    clmul t5, s0, t5
+; RV32IMZBC-NEXT:    clmulh t4, s0, t4
+; RV32IMZBC-NEXT:    xor t5, t5, t6
+; RV32IMZBC-NEXT:    xor t4, t4, t5
+; RV32IMZBC-NEXT:    srli t5, t4, 8
+; RV32IMZBC-NEXT:    and t5, t5, a6
+; RV32IMZBC-NEXT:    srli t6, t4, 24
+; RV32IMZBC-NEXT:    and s0, t4, a6
+; RV32IMZBC-NEXT:    slli t4, t4, 24
+; RV32IMZBC-NEXT:    slli s0, s0, 8
+; RV32IMZBC-NEXT:    or t5, t5, t6
+; RV32IMZBC-NEXT:    or t4, t4, s0
+; RV32IMZBC-NEXT:    or t4, t4, t5
+; RV32IMZBC-NEXT:    srli t5, t4, 4
+; RV32IMZBC-NEXT:    and t5, t5, t0
+; RV32IMZBC-NEXT:    and t4, t4, t0
+; RV32IMZBC-NEXT:    srli t6, a5, 8
+; RV32IMZBC-NEXT:    slli t4, t4, 4
+; RV32IMZBC-NEXT:    and t6, t6, a6
+; RV32IMZBC-NEXT:    srli s0, a5, 24
+; RV32IMZBC-NEXT:    and s1, a5, a6
+; RV32IMZBC-NEXT:    slli s1, s1, 8
+; RV32IMZBC-NEXT:    slli s2, a5, 24
+; RV32IMZBC-NEXT:    or t6, t6, s0
+; RV32IMZBC-NEXT:    or s0, s2, s1
+; RV32IMZBC-NEXT:    or t4, t5, t4
+; RV32IMZBC-NEXT:    or t5, s0, t6
+; RV32IMZBC-NEXT:    srli t6, t5, 4
+; RV32IMZBC-NEXT:    and t5, t5, t0
+; RV32IMZBC-NEXT:    and t6, t6, t0
+; RV32IMZBC-NEXT:    slli s0, t5, 4
+; RV32IMZBC-NEXT:    srli t5, t4, 2
+; RV32IMZBC-NEXT:    or t6, t6, s0
+; RV32IMZBC-NEXT:    srli s0, t6, 2
+; RV32IMZBC-NEXT:    and t6, t6, t1
+; RV32IMZBC-NEXT:    and s0, s0, t1
+; RV32IMZBC-NEXT:    slli t6, t6, 2
+; RV32IMZBC-NEXT:    or t6, s0, t6
+; RV32IMZBC-NEXT:    srli s0, t3, 8
+; RV32IMZBC-NEXT:    and s0, s0, a6
+; RV32IMZBC-NEXT:    srli s1, t3, 24
+; RV32IMZBC-NEXT:    or s0, s0, s1
+; RV32IMZBC-NEXT:    and s1, t3, a6
+; RV32IMZBC-NEXT:    slli s1, s1, 8
+; RV32IMZBC-NEXT:    slli t3, t3, 24
+; RV32IMZBC-NEXT:    srli s2, t6, 1
+; RV32IMZBC-NEXT:    or t3, t3, s1
+; RV32IMZBC-NEXT:    and s1, s2, a1
+; RV32IMZBC-NEXT:    or t3, t3, s0
+; RV32IMZBC-NEXT:    srli s0, t3, 4
+; RV32IMZBC-NEXT:    and t3, t3, t0
+; RV32IMZBC-NEXT:    and s0, s0, t0
+; RV32IMZBC-NEXT:    slli t3, t3, 4
+; RV32IMZBC-NEXT:    and t6, t6, a1
+; RV32IMZBC-NEXT:    or t3, s0, t3
+; RV32IMZBC-NEXT:    srli s0, t3, 2
+; RV32IMZBC-NEXT:    and t3, t3, t1
+; RV32IMZBC-NEXT:    and s0, s0, t1
+; RV32IMZBC-NEXT:    slli t3, t3, 2
+; RV32IMZBC-NEXT:    slli t6, t6, 1
+; RV32IMZBC-NEXT:    or s0, s0, t3
+; RV32IMZBC-NEXT:    or t3, s1, t6
+; RV32IMZBC-NEXT:    srli t6, s0, 1
+; RV32IMZBC-NEXT:    and t6, t6, a1
+; RV32IMZBC-NEXT:    srli s1, t2, 8
+; RV32IMZBC-NEXT:    and s1, s1, a6
+; RV32IMZBC-NEXT:    srli s2, t2, 24
+; RV32IMZBC-NEXT:    or s1, s1, s2
+; RV32IMZBC-NEXT:    and s2, t2, a6
+; RV32IMZBC-NEXT:    slli s2, s2, 8
+; RV32IMZBC-NEXT:    slli t2, t2, 24
+; RV32IMZBC-NEXT:    and s0, s0, a1
+; RV32IMZBC-NEXT:    or t2, t2, s2
+; RV32IMZBC-NEXT:    slli s0, s0, 1
+; RV32IMZBC-NEXT:    or t2, t2, s1
+; RV32IMZBC-NEXT:    srli s1, t2, 4
+; RV32IMZBC-NEXT:    and t2, t2, t0
+; RV32IMZBC-NEXT:    and s1, s1, t0
+; RV32IMZBC-NEXT:    slli t2, t2, 4
+; RV32IMZBC-NEXT:    or t6, t6, s0
+; RV32IMZBC-NEXT:    or t2, s1, t2
+; RV32IMZBC-NEXT:    srli s0, t2, 2
+; RV32IMZBC-NEXT:    and t2, t2, t1
+; RV32IMZBC-NEXT:    and s0, s0, t1
+; RV32IMZBC-NEXT:    slli t2, t2, 2
+; RV32IMZBC-NEXT:    or t2, s0, t2
+; RV32IMZBC-NEXT:    srli s0, a0, 8
+; RV32IMZBC-NEXT:    and s0, s0, a6
+; RV32IMZBC-NEXT:    srli s1, a0, 24
+; RV32IMZBC-NEXT:    or s0, s0, s1
+; RV32IMZBC-NEXT:    and s1, a0, a6
+; RV32IMZBC-NEXT:    slli s1, s1, 8
+; RV32IMZBC-NEXT:    slli s2, a0, 24
+; RV32IMZBC-NEXT:    or s1, s2, s1
+; RV32IMZBC-NEXT:    srli s2, t2, 1
+; RV32IMZBC-NEXT:    and s2, s2, a1
+; RV32IMZBC-NEXT:    or s0, s1, s0
+; RV32IMZBC-NEXT:    srli s1, s0, 4
+; RV32IMZBC-NEXT:    and s0, s0, t0
+; RV32IMZBC-NEXT:    and s1, s1, t0
+; RV32IMZBC-NEXT:    slli s0, s0, 4
+; RV32IMZBC-NEXT:    and t2, t2, a1
+; RV32IMZBC-NEXT:    or s0, s1, s0
+; RV32IMZBC-NEXT:    srli s1, s0, 2
+; RV32IMZBC-NEXT:    and s0, s0, t1
+; RV32IMZBC-NEXT:    and s1, s1, t1
+; RV32IMZBC-NEXT:    slli s0, s0, 2
+; RV32IMZBC-NEXT:    slli t2, t2, 1
+; RV32IMZBC-NEXT:    or s0, s1, s0
+; RV32IMZBC-NEXT:    srli s1, s0, 1
+; RV32IMZBC-NEXT:    and s0, s0, a1
+; RV32IMZBC-NEXT:    and s1, s1, a1
+; RV32IMZBC-NEXT:    slli s0, s0, 1
+; RV32IMZBC-NEXT:    or t2, s2, t2
+; RV32IMZBC-NEXT:    or s0, s1, s0
+; RV32IMZBC-NEXT:    clmul t6, t6, t3
+; RV32IMZBC-NEXT:    clmul t2, s0, t2
+; RV32IMZBC-NEXT:    and t5, t5, t1
+; RV32IMZBC-NEXT:    clmulh t3, s0, t3
+; RV32IMZBC-NEXT:    and t4, t4, t1
+; RV32IMZBC-NEXT:    xor t2, t2, t6
+; RV32IMZBC-NEXT:    slli t4, t4, 2
+; RV32IMZBC-NEXT:    xor t2, t3, t2
+; RV32IMZBC-NEXT:    or t3, t5, t4
+; RV32IMZBC-NEXT:    srli t4, t2, 8
+; RV32IMZBC-NEXT:    srli t5, t3, 1
+; RV32IMZBC-NEXT:    and t4, t4, a6
+; RV32IMZBC-NEXT:    srli t6, t2, 24
+; RV32IMZBC-NEXT:    and a6, t2, a6
+; RV32IMZBC-NEXT:    slli t2, t2, 24
+; RV32IMZBC-NEXT:    slli a6, a6, 8
+; RV32IMZBC-NEXT:    or t4, t4, t6
+; RV32IMZBC-NEXT:    or a6, t2, a6
+; RV32IMZBC-NEXT:    and t2, t5, a1
+; RV32IMZBC-NEXT:    or a6, a6, t4
+; RV32IMZBC-NEXT:    srli t4, a6, 4
+; RV32IMZBC-NEXT:    and a6, a6, t0
+; RV32IMZBC-NEXT:    and t0, t4, t0
+; RV32IMZBC-NEXT:    slli a6, a6, 4
+; RV32IMZBC-NEXT:    and t3, t3, a1
+; RV32IMZBC-NEXT:    or a6, t0, a6
+; RV32IMZBC-NEXT:    srli t0, a6, 2
+; RV32IMZBC-NEXT:    and a6, a6, t1
+; RV32IMZBC-NEXT:    and t0, t0, t1
+; RV32IMZBC-NEXT:    slli a6, a6, 2
+; RV32IMZBC-NEXT:    slli t3, t3, 1
+; RV32IMZBC-NEXT:    or a6, t0, a6
+; RV32IMZBC-NEXT:    or t0, t2, t3
+; RV32IMZBC-NEXT:    srli t1, a6, 1
+; RV32IMZBC-NEXT:    and t1, t1, a1
+; RV32IMZBC-NEXT:    and a1, a6, a1
+; RV32IMZBC-NEXT:    slli a1, a1, 1
+; RV32IMZBC-NEXT:    clmulr a4, a7, a4
+; RV32IMZBC-NEXT:    or a1, t1, a1
+; RV32IMZBC-NEXT:    clmulr a0, a0, a5
+; RV32IMZBC-NEXT:    sw t0, 0(a2)
+; RV32IMZBC-NEXT:    sw a4, 4(a2)
+; RV32IMZBC-NEXT:    sw a1, 8(a2)
+; RV32IMZBC-NEXT:    sw a0, 12(a2)
+; RV32IMZBC-NEXT:    sw t0, 0(a3)
+; RV32IMZBC-NEXT:    sw a4, 4(a3)
+; RV32IMZBC-NEXT:    sw a1, 8(a3)
+; RV32IMZBC-NEXT:    sw a0, 12(a3)
+; RV32IMZBC-NEXT:    lw s0, 12(sp) # 4-byte Folded Reload
+; RV32IMZBC-NEXT:    lw s1, 8(sp) # 4-byte Folded Reload
+; RV32IMZBC-NEXT:    lw s2, 4(sp) # 4-byte Folded Reload
+; RV32IMZBC-NEXT:    addi sp, sp, 16
+; RV32IMZBC-NEXT:    ret
+;
+; RV64IMZBC-LABEL: commutative_clmulr_v2i64:
+; RV64IMZBC:       # %bb.0:
+; RV64IMZBC-NEXT:    clmulr a0, a2, a0
+; RV64IMZBC-NEXT:    clmulr a1, a3, a1
+; RV64IMZBC-NEXT:    sd a0, 0(a4)
+; RV64IMZBC-NEXT:    sd a1, 8(a4)
+; RV64IMZBC-NEXT:    sd a0, 0(a5)
+; RV64IMZBC-NEXT:    sd a1, 8(a5)
+; RV64IMZBC-NEXT:    ret
   %x.ext = zext <2 x i64> %x to <2 x i128>
   %y.ext = zext <2 x i64> %y to <2 x i128>
   %clmul_xy = call <2 x i128> @llvm.clmul.v2i128(<2 x i128> %x.ext, <2 x i128> %y.ext)
@@ -7801,6 +8518,4 @@ define void @commutative_clmulr_v2i64(<2 x i64> %x, <2 x i64> %y, ptr %p0, ptr %
   ret void
 }
 ;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
-; CHECK-I: {{.*}}
-; CHECK-M: {{.*}}
-; CHECK-ZBS: {{.*}}
+; CHECK: {{.*}}

>From d7f11271645cafdec58b9d0c58e544637a007a23 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Sat, 3 Oct 2026 19:10:41 -0700
Subject: [PATCH 2/4] [RISCV] Change custom promotion of riscv_clmulh/r

Instead of using shl+shl+clmul(h/r)+srl, use and+and+clmul(h/r)+srl.

This matches type promotion of ISD::CLMUL(H/R). The ands may be
able to fold into loads or removed via known bits.

ISel will convert and+and+clmul to shl+shl+clmulh if the ands
aren't removed.

This leaves some regressions for clmulr that will be dealt with
in a follow up.

This is an alternative to #228669.
---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 25 +++++----------------
 1 file changed, 6 insertions(+), 19 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 3892e62f715cf09..6c97594ad869ef3 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -18282,28 +18282,15 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N,
       if (!Subtarget.is64Bit() || N->getValueType(0) != MVT::i32)
         return;
 
-      // Extend inputs to XLen, and shift by 32. This will add 64 trailing zeros
-      // to the full 128-bit clmul result of multiplying two xlen values.
-      // Perform clmulr or clmulh on the shifted values. Finally, extract the
-      // upper 32 bits.
-      //
-      // The alternative is to mask the inputs to 32 bits and use clmul, but
-      // that requires two shifts to mask each input without zext.w.
-      // FIXME: If the inputs are known zero extended or could be freely
-      // zero extended, the mask form would be better.
+      // Zero extend the inputs, use a clmul, then shift the result.
       SDValue NewOp0 =
-          DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(1));
+          DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i64, N->getOperand(1));
       SDValue NewOp1 =
-          DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(2));
-      NewOp0 = DAG.getNode(ISD::SHL, DL, MVT::i64, NewOp0,
-                           DAG.getConstant(32, DL, MVT::i64));
-      NewOp1 = DAG.getNode(ISD::SHL, DL, MVT::i64, NewOp1,
-                           DAG.getConstant(32, DL, MVT::i64));
-      unsigned Opc =
-          IntNo == Intrinsic::riscv_clmulh ? ISD::CLMULH : ISD::CLMULR;
-      SDValue Res = DAG.getNode(Opc, DL, MVT::i64, NewOp0, NewOp1);
+          DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i64, N->getOperand(2));
+      unsigned ShAmt = IntNo == Intrinsic::riscv_clmulh ? 32 : 31;
+      SDValue Res = DAG.getNode(ISD::CLMUL, DL, MVT::i64, NewOp0, NewOp1);
       Res = DAG.getNode(ISD::SRL, DL, MVT::i64, Res,
-                        DAG.getConstant(32, DL, MVT::i64));
+                        DAG.getConstant(ShAmt, DL, MVT::i64));
       Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Res));
       return;
     }

>From 2856bc336b7cc2b66b1e1d81eb5fd29a41b4e904 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Sun, 4 Oct 2026 00:23:26 -0700
Subject: [PATCH 3/4] fixup! commit tests

---
 llvm/test/CodeGen/RISCV/rv64zbc-intrinsic.ll      | 12 ++++++------
 llvm/test/CodeGen/RISCV/rv64zbc-zbkc-intrinsic.ll |  8 +++-----
 2 files changed, 9 insertions(+), 11 deletions(-)

diff --git a/llvm/test/CodeGen/RISCV/rv64zbc-intrinsic.ll b/llvm/test/CodeGen/RISCV/rv64zbc-intrinsic.ll
index 4b969aef9750750..a49426166872000 100644
--- a/llvm/test/CodeGen/RISCV/rv64zbc-intrinsic.ll
+++ b/llvm/test/CodeGen/RISCV/rv64zbc-intrinsic.ll
@@ -16,8 +16,9 @@ define signext i32 @clmul32r(i32 signext %a, i32 signext %b) nounwind {
 ; RV64ZBC:       # %bb.0:
 ; RV64ZBC-NEXT:    slli a1, a1, 32
 ; RV64ZBC-NEXT:    slli a0, a0, 32
-; RV64ZBC-NEXT:    clmulr a0, a0, a1
-; RV64ZBC-NEXT:    srai a0, a0, 32
+; RV64ZBC-NEXT:    clmulh a0, a0, a1
+; RV64ZBC-NEXT:    srli a0, a0, 31
+; RV64ZBC-NEXT:    sext.w a0, a0
 ; RV64ZBC-NEXT:    ret
   %tmp = call i32 @llvm.riscv.clmulr.i32(i32 %a, i32 %b)
   ret i32 %tmp
@@ -28,10 +29,9 @@ define signext i32 @clmul32r(i32 signext %a, i32 signext %b) nounwind {
 define signext i32 @clmul32r_zext(i32 zeroext %a, i32 zeroext %b) nounwind {
 ; RV64ZBC-LABEL: clmul32r_zext:
 ; RV64ZBC:       # %bb.0:
-; RV64ZBC-NEXT:    slli a1, a1, 32
-; RV64ZBC-NEXT:    slli a0, a0, 32
-; RV64ZBC-NEXT:    clmulr a0, a0, a1
-; RV64ZBC-NEXT:    srai a0, a0, 32
+; RV64ZBC-NEXT:    clmul a0, a0, a1
+; RV64ZBC-NEXT:    srli a0, a0, 31
+; RV64ZBC-NEXT:    sext.w a0, a0
 ; RV64ZBC-NEXT:    ret
   %tmp = call i32 @llvm.riscv.clmulr.i32(i32 %a, i32 %b)
   ret i32 %tmp
diff --git a/llvm/test/CodeGen/RISCV/rv64zbc-zbkc-intrinsic.ll b/llvm/test/CodeGen/RISCV/rv64zbc-zbkc-intrinsic.ll
index bd97872d4bba490..b0af0567d40deae 100644
--- a/llvm/test/CodeGen/RISCV/rv64zbc-zbkc-intrinsic.ll
+++ b/llvm/test/CodeGen/RISCV/rv64zbc-zbkc-intrinsic.ll
@@ -40,7 +40,7 @@ define signext i32 @clmul32h(i32 signext %a, i32 signext %b) nounwind {
 ; RV64ZBC-ZBKC-NEXT:    slli a1, a1, 32
 ; RV64ZBC-ZBKC-NEXT:    slli a0, a0, 32
 ; RV64ZBC-ZBKC-NEXT:    clmulh a0, a0, a1
-; RV64ZBC-ZBKC-NEXT:    srai a0, a0, 32
+; RV64ZBC-ZBKC-NEXT:    srli a0, a0, 32
 ; RV64ZBC-ZBKC-NEXT:    ret
   %tmp = call i32 @llvm.riscv.clmulh.i32(i32 %a, i32 %b)
   ret i32 %tmp
@@ -51,10 +51,8 @@ define signext i32 @clmul32h(i32 signext %a, i32 signext %b) nounwind {
 define signext i32 @clmul32h_zext(i32 zeroext %a, i32 zeroext %b) nounwind {
 ; RV64ZBC-ZBKC-LABEL: clmul32h_zext:
 ; RV64ZBC-ZBKC:       # %bb.0:
-; RV64ZBC-ZBKC-NEXT:    slli a1, a1, 32
-; RV64ZBC-ZBKC-NEXT:    slli a0, a0, 32
-; RV64ZBC-ZBKC-NEXT:    clmulh a0, a0, a1
-; RV64ZBC-ZBKC-NEXT:    srai a0, a0, 32
+; RV64ZBC-ZBKC-NEXT:    clmul a0, a0, a1
+; RV64ZBC-ZBKC-NEXT:    srli a0, a0, 32
 ; RV64ZBC-ZBKC-NEXT:    ret
   %tmp = call i32 @llvm.riscv.clmulh.i32(i32 %a, i32 %b)
   ret i32 %tmp

>From 145d0eaa250a1b2d160f406a9abcf22b010d8bc6 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Sun, 4 Oct 2026 00:35:12 -0700
Subject: [PATCH 4/4] [RISCV] Combine (srl (clmul (zext.w X), (zext.w Y)), 31).

into (srl (clmulr (shl X, 32), (shl Y, 32)), 32).

Stacked on #228846.
---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp  | 39 +++++++++++++++++++-
 llvm/test/CodeGen/RISCV/clmulr.ll            |  4 +-
 llvm/test/CodeGen/RISCV/rv64zbc-intrinsic.ll | 10 ++---
 3 files changed, 43 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 6c97594ad869ef3..bcebcef35a6aa6c 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -2047,6 +2047,9 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
   if (Subtarget.hasStdExtZbkb())
     setTargetDAGCombine(ISD::BITREVERSE);
 
+  if (Subtarget.hasStdExtZbc() && Subtarget.is64Bit())
+    setTargetDAGCombine(ISD::SRL);
+
   if (Subtarget.hasStdExtFOrZfinx())
     setTargetDAGCombine({ISD::ZERO_EXTEND, ISD::FP_TO_SINT, ISD::FP_TO_UINT,
                          ISD::FP_TO_SINT_SAT, ISD::FP_TO_UINT_SAT});
@@ -22931,6 +22934,36 @@ static SDValue performVEXT_VLCombine(SDNode *N,
   return DCI.DAG.getNode(Opcode, SDLoc(N), DstVT, Src, Mask, VL);
 }
 
+// Combine (srl (clmul (and X, 0xffffffff), (and Y, 0xffffffff)), 31) ->
+// (srl (clmulr (shl X, 32), (shl Y, 32)), 32). This avoids needing two
+// shifts to zero extend each input.
+static SDValue performSRLCombine(SDNode *N,
+                                 TargetLowering::DAGCombinerInfo &DCI,
+                                 const RISCVSubtarget &Subtarget) {
+  assert(N->getOpcode() == ISD::SRL && "Unexpected opcode");
+
+  if (!DCI.isAfterLegalizeDAG() || N->getValueType(0) != MVT::i64 ||
+      !Subtarget.is64Bit() || !Subtarget.hasStdExtZbc())
+    return SDValue();
+
+  SelectionDAG &DAG = DCI.DAG;
+
+  using namespace SDPatternMatch;
+  SDValue X, Y;
+  if (!sd_match(N, m_Srl(m_OneUse(m_Clmul(
+                             m_And(m_Value(X), m_SpecificInt(0xffffffff)),
+                             m_And(m_Value(Y), m_SpecificInt(0xffffffff)))),
+                         m_SpecificInt(31))))
+    return SDValue();
+
+  SDLoc DL(N);
+  SDValue ShAmt = DAG.getConstant(32, DL, MVT::i64);
+  X = DAG.getNode(ISD::SHL, DL, MVT::i64, X, ShAmt);
+  Y = DAG.getNode(ISD::SHL, DL, MVT::i64, Y, ShAmt);
+  SDValue Res = DAG.getNode(ISD::CLMULR, DL, MVT::i64, X, Y);
+  return DAG.getNode(ISD::SRL, DL, MVT::i64, Res, ShAmt);
+}
+
 static SDValue performSRACombine(SDNode *N, SelectionDAG &DAG,
                                  const RISCVSubtarget &Subtarget) {
   assert(N->getOpcode() == ISD::SRA && "Unexpected opcode");
@@ -25532,10 +25565,12 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N,
     [[fallthrough]];
   case ISD::SRL:
   case ISD::SHL: {
-    if (N->getOpcode() == ISD::SHL) {
+    if (N->getOpcode() == ISD::SRL)
+      if (SDValue V = performSRLCombine(N, DCI, Subtarget))
+        return V;
+    if (N->getOpcode() == ISD::SHL)
       if (SDValue V = performSHLCombine(N, DCI, Subtarget))
         return V;
-    }
     SDValue ShAmt = N->getOperand(1);
     if (ShAmt.getOpcode() == RISCVISD::SPLAT_VECTOR_SPLIT_I64_VL) {
       // We don't need the upper 32 bits of a 64-bit element for a shift amount.
diff --git a/llvm/test/CodeGen/RISCV/clmulr.ll b/llvm/test/CodeGen/RISCV/clmulr.ll
index 23cf4093d99bf52..dbfe692d0b1b971 100644
--- a/llvm/test/CodeGen/RISCV/clmulr.ll
+++ b/llvm/test/CodeGen/RISCV/clmulr.ll
@@ -1847,8 +1847,8 @@ define i32 @clmulr_i32(i32 %a, i32 %b) nounwind {
 ; RV64IMZBC:       # %bb.0:
 ; RV64IMZBC-NEXT:    slli a1, a1, 32
 ; RV64IMZBC-NEXT:    slli a0, a0, 32
-; RV64IMZBC-NEXT:    clmulh a0, a0, a1
-; RV64IMZBC-NEXT:    srli a0, a0, 31
+; RV64IMZBC-NEXT:    clmulr a0, a0, a1
+; RV64IMZBC-NEXT:    srli a0, a0, 32
 ; RV64IMZBC-NEXT:    ret
   %a.ext = zext i32 %a to i64
   %b.ext = zext i32 %b to i64
diff --git a/llvm/test/CodeGen/RISCV/rv64zbc-intrinsic.ll b/llvm/test/CodeGen/RISCV/rv64zbc-intrinsic.ll
index a49426166872000..01c615d961e7445 100644
--- a/llvm/test/CodeGen/RISCV/rv64zbc-intrinsic.ll
+++ b/llvm/test/CodeGen/RISCV/rv64zbc-intrinsic.ll
@@ -16,9 +16,8 @@ define signext i32 @clmul32r(i32 signext %a, i32 signext %b) nounwind {
 ; RV64ZBC:       # %bb.0:
 ; RV64ZBC-NEXT:    slli a1, a1, 32
 ; RV64ZBC-NEXT:    slli a0, a0, 32
-; RV64ZBC-NEXT:    clmulh a0, a0, a1
-; RV64ZBC-NEXT:    srli a0, a0, 31
-; RV64ZBC-NEXT:    sext.w a0, a0
+; RV64ZBC-NEXT:    clmulr a0, a0, a1
+; RV64ZBC-NEXT:    srai a0, a0, 32
 ; RV64ZBC-NEXT:    ret
   %tmp = call i32 @llvm.riscv.clmulr.i32(i32 %a, i32 %b)
   ret i32 %tmp
@@ -55,9 +54,8 @@ define signext i32 @llvm_clmulr_i32(i32 signext %a, i32 signext %b) nounwind {
 ; RV64ZBC:       # %bb.0:
 ; RV64ZBC-NEXT:    slli a1, a1, 32
 ; RV64ZBC-NEXT:    slli a0, a0, 32
-; RV64ZBC-NEXT:    clmulh a0, a0, a1
-; RV64ZBC-NEXT:    srli a0, a0, 31
-; RV64ZBC-NEXT:    sext.w a0, a0
+; RV64ZBC-NEXT:    clmulr a0, a0, a1
+; RV64ZBC-NEXT:    srai a0, a0, 32
 ; RV64ZBC-NEXT:    ret
   %tmp1 = zext i32 %a to i64
   %tmp2 = zext i32 %b to i64



More information about the llvm-commits mailing list