[llvm] [RISCV] Efficiently lower (select cond, u, rot[r/l](u, rot.amt)) using zicond extension (PR #143768)

Ryan Buchner via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 3 12:18:44 PDT 2025


https://github.com/bababuck updated https://github.com/llvm/llvm-project/pull/143768

>From 8229f5dd409f55d4f4f55c3c5bdbf5c3b3a538e6 Mon Sep 17 00:00:00 2001
From: bababuck <buchner.ryan at gmail.com>
Date: Wed, 28 May 2025 12:57:28 -0700
Subject: [PATCH] [RISCV] Efficiently lower (select cond, u, rot[r/l](u,
 rot.amt)) using zicond extension

The following lowering now occurs:
(select cond, u, rotr(u, rot.amt)) -> (rotr u, (czero_nez rot.amt, cond))

This same pattern holds for any other operations with an identity of 0 (i.e. op(x, 0) = x).
---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp |  4 +
 llvm/test/CodeGen/RISCV/zicond-opts.ll      | 82 +++++++++------------
 2 files changed, 38 insertions(+), 48 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index dac6ed6d40199..6e7047cf962cf 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -18339,6 +18339,8 @@ static bool combine_CC(SDValue &LHS, SDValue &RHS, SDValue &CC, const SDLoc &DL,
 // (select C, (sub Y, X), Y) -> (sub Y, (select C, X, 0)).
 // (select C, (or Y, X), Y)  -> (or Y, (select C, X, 0)).
 // (select C, (xor Y, X), Y) -> (xor Y, (select C, X, 0)).
+// (select C, (rotl Y, X), Y) -> (rotl Y, (select C, X, 0)).
+// (select C, (rotr Y, X), Y) -> (rotr Y, (select C, X, 0)).
 static SDValue tryFoldSelectIntoOp(SDNode *N, SelectionDAG &DAG,
                                    SDValue TrueVal, SDValue FalseVal,
                                    bool Swapped) {
@@ -18351,6 +18353,8 @@ static SDValue tryFoldSelectIntoOp(SDNode *N, SelectionDAG &DAG,
   case ISD::SRA:
   case ISD::SRL:
   case ISD::SUB:
+  case ISD::ROTL:
+  case ISD::ROTR:
     Commutative = false;
     break;
   case ISD::ADD:
diff --git a/llvm/test/CodeGen/RISCV/zicond-opts.ll b/llvm/test/CodeGen/RISCV/zicond-opts.ll
index 2512ba803cf48..35b06c4f4fb41 100644
--- a/llvm/test/CodeGen/RISCV/zicond-opts.ll
+++ b/llvm/test/CodeGen/RISCV/zicond-opts.ll
@@ -62,37 +62,30 @@ define i64 @rotate_l_nez(i64 %x, i64 %rot.amt, i1 %cond) {
 ; RV32ZICOND-LABEL: rotate_l_nez:
 ; RV32ZICOND:       # %bb.0:
 ; RV32ZICOND-NEXT:    andi a4, a4, 1
-; RV32ZICOND-NEXT:    bexti a3, a2, 5
-; RV32ZICOND-NEXT:    not a5, a2
-; RV32ZICOND-NEXT:    czero.nez a6, a1, a3
-; RV32ZICOND-NEXT:    czero.eqz a7, a0, a3
-; RV32ZICOND-NEXT:    czero.nez t0, a0, a3
-; RV32ZICOND-NEXT:    czero.eqz a3, a1, a3
-; RV32ZICOND-NEXT:    czero.eqz a0, a0, a4
-; RV32ZICOND-NEXT:    czero.eqz a1, a1, a4
-; RV32ZICOND-NEXT:    or a6, a7, a6
-; RV32ZICOND-NEXT:    or a3, a3, t0
-; RV32ZICOND-NEXT:    sll a7, a6, a2
-; RV32ZICOND-NEXT:    srli t0, a3, 1
-; RV32ZICOND-NEXT:    sll a2, a3, a2
-; RV32ZICOND-NEXT:    srli a3, a6, 1
-; RV32ZICOND-NEXT:    srl a6, t0, a5
-; RV32ZICOND-NEXT:    srl a3, a3, a5
-; RV32ZICOND-NEXT:    or a5, a7, a6
-; RV32ZICOND-NEXT:    or a2, a2, a3
 ; RV32ZICOND-NEXT:    czero.nez a2, a2, a4
-; RV32ZICOND-NEXT:    czero.nez a3, a5, a4
-; RV32ZICOND-NEXT:    or a0, a0, a2
-; RV32ZICOND-NEXT:    or a1, a1, a3
+; RV32ZICOND-NEXT:    bexti a3, a2, 5
+; RV32ZICOND-NEXT:    czero.nez a4, a0, a3
+; RV32ZICOND-NEXT:    czero.eqz a5, a1, a3
+; RV32ZICOND-NEXT:    czero.nez a1, a1, a3
+; RV32ZICOND-NEXT:    czero.eqz a0, a0, a3
+; RV32ZICOND-NEXT:    not a3, a2
+; RV32ZICOND-NEXT:    or a4, a5, a4
+; RV32ZICOND-NEXT:    or a0, a0, a1
+; RV32ZICOND-NEXT:    sll a1, a4, a2
+; RV32ZICOND-NEXT:    srli a5, a0, 1
+; RV32ZICOND-NEXT:    sll a2, a0, a2
+; RV32ZICOND-NEXT:    srli a4, a4, 1
+; RV32ZICOND-NEXT:    srl a0, a5, a3
+; RV32ZICOND-NEXT:    srl a3, a4, a3
+; RV32ZICOND-NEXT:    or a0, a1, a0
+; RV32ZICOND-NEXT:    or a1, a2, a3
 ; RV32ZICOND-NEXT:    ret
 ;
 ; RV64ZICOND-LABEL: rotate_l_nez:
 ; RV64ZICOND:       # %bb.0:
 ; RV64ZICOND-NEXT:    andi a2, a2, 1
-; RV64ZICOND-NEXT:    rol a1, a0, a1
 ; RV64ZICOND-NEXT:    czero.nez a1, a1, a2
-; RV64ZICOND-NEXT:    czero.eqz a0, a0, a2
-; RV64ZICOND-NEXT:    or a0, a0, a1
+; RV64ZICOND-NEXT:    rol a0, a0, a1
 ; RV64ZICOND-NEXT:    ret
   %6 = call i64 @llvm.fshl.i64(i64 %x, i64 %x, i64 %rot.amt)
   %7 = select i1 %cond, i64 %x, i64 %6
@@ -104,37 +97,30 @@ define i64 @rotate_l_eqz(i64 %x, i64 %rot.amt, i1 %cond) {
 ; RV32ZICOND-LABEL: rotate_l_eqz:
 ; RV32ZICOND:       # %bb.0:
 ; RV32ZICOND-NEXT:    andi a4, a4, 1
-; RV32ZICOND-NEXT:    bexti a3, a2, 5
-; RV32ZICOND-NEXT:    not a5, a2
-; RV32ZICOND-NEXT:    czero.nez a6, a1, a3
-; RV32ZICOND-NEXT:    czero.eqz a7, a0, a3
-; RV32ZICOND-NEXT:    czero.nez t0, a0, a3
-; RV32ZICOND-NEXT:    czero.eqz a3, a1, a3
-; RV32ZICOND-NEXT:    czero.nez a0, a0, a4
-; RV32ZICOND-NEXT:    czero.nez a1, a1, a4
-; RV32ZICOND-NEXT:    or a6, a7, a6
-; RV32ZICOND-NEXT:    or a3, a3, t0
-; RV32ZICOND-NEXT:    sll a7, a6, a2
-; RV32ZICOND-NEXT:    srli t0, a3, 1
-; RV32ZICOND-NEXT:    sll a2, a3, a2
-; RV32ZICOND-NEXT:    srli a3, a6, 1
-; RV32ZICOND-NEXT:    srl a6, t0, a5
-; RV32ZICOND-NEXT:    srl a3, a3, a5
-; RV32ZICOND-NEXT:    or a5, a7, a6
-; RV32ZICOND-NEXT:    or a2, a2, a3
 ; RV32ZICOND-NEXT:    czero.eqz a2, a2, a4
-; RV32ZICOND-NEXT:    czero.eqz a3, a5, a4
-; RV32ZICOND-NEXT:    or a0, a2, a0
-; RV32ZICOND-NEXT:    or a1, a3, a1
+; RV32ZICOND-NEXT:    bexti a3, a2, 5
+; RV32ZICOND-NEXT:    czero.nez a4, a0, a3
+; RV32ZICOND-NEXT:    czero.eqz a5, a1, a3
+; RV32ZICOND-NEXT:    czero.nez a1, a1, a3
+; RV32ZICOND-NEXT:    czero.eqz a0, a0, a3
+; RV32ZICOND-NEXT:    not a3, a2
+; RV32ZICOND-NEXT:    or a4, a5, a4
+; RV32ZICOND-NEXT:    or a0, a0, a1
+; RV32ZICOND-NEXT:    sll a1, a4, a2
+; RV32ZICOND-NEXT:    srli a5, a0, 1
+; RV32ZICOND-NEXT:    sll a2, a0, a2
+; RV32ZICOND-NEXT:    srli a4, a4, 1
+; RV32ZICOND-NEXT:    srl a0, a5, a3
+; RV32ZICOND-NEXT:    srl a3, a4, a3
+; RV32ZICOND-NEXT:    or a0, a1, a0
+; RV32ZICOND-NEXT:    or a1, a2, a3
 ; RV32ZICOND-NEXT:    ret
 ;
 ; RV64ZICOND-LABEL: rotate_l_eqz:
 ; RV64ZICOND:       # %bb.0:
 ; RV64ZICOND-NEXT:    andi a2, a2, 1
-; RV64ZICOND-NEXT:    rol a1, a0, a1
-; RV64ZICOND-NEXT:    czero.nez a0, a0, a2
 ; RV64ZICOND-NEXT:    czero.eqz a1, a1, a2
-; RV64ZICOND-NEXT:    or a0, a1, a0
+; RV64ZICOND-NEXT:    rol a0, a0, a1
 ; RV64ZICOND-NEXT:    ret
   %6 = call i64 @llvm.fshl.i64(i64 %x, i64 %x, i64 %rot.amt)
   %7 = select i1 %cond, i64 %6, i64 %x



More information about the llvm-commits mailing list