[llvm] [RISCV] Lower (select c, y, 0) -> (qc.muliadd c, y-1) (PR #190323)

Sudharsan Veeravalli via llvm-commits llvm-commits at lists.llvm.org
Sun Apr 5 20:46:36 PDT 2026


https://github.com/svs-quic updated https://github.com/llvm/llvm-project/pull/190323

>From d93986ce80d89e189bc8494adb08507cdbbdd31e Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <svs at qti.qualcomm.com>
Date: Fri, 3 Apr 2026 13:29:44 +0530
Subject: [PATCH 1/5] Pre-commit tests

---
 llvm/test/CodeGen/RISCV/xqciac.ll | 67 +++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/llvm/test/CodeGen/RISCV/xqciac.ll b/llvm/test/CodeGen/RISCV/xqciac.ll
index c9838823f9a9b..3085331250f0b 100644
--- a/llvm/test/CodeGen/RISCV/xqciac.ll
+++ b/llvm/test/CodeGen/RISCV/xqciac.ll
@@ -600,6 +600,28 @@ define i32 @add_shl_moreOneUse_4(i32 %x) {
   ret i32 %add
 }
 
+define i32 @select20(i1 zeroext %x) {
+; RV32IM-LABEL: select20:
+; RV32IM:       # %bb.0:
+; RV32IM-NEXT:    neg a0, a0
+; RV32IM-NEXT:    andi a0, a0, 20
+; RV32IM-NEXT:    ret
+;
+; RV32IMXQCIAC-LABEL: select20:
+; RV32IMXQCIAC:       # %bb.0:
+; RV32IMXQCIAC-NEXT:    neg a0, a0
+; RV32IMXQCIAC-NEXT:    andi a0, a0, 20
+; RV32IMXQCIAC-NEXT:    ret
+;
+; RV32IZBAMXQCIAC-LABEL: select20:
+; RV32IZBAMXQCIAC:       # %bb.0:
+; RV32IZBAMXQCIAC-NEXT:    neg a0, a0
+; RV32IZBAMXQCIAC-NEXT:    andi a0, a0, 20
+; RV32IZBAMXQCIAC-NEXT:    ret
+  %select = select i1 %x, i32 20, i32 0
+  ret i32 %select
+}
+
 define i32 @select65(i1 zeroext %x) {
 ; RV32IM-LABEL: select65:
 ; RV32IM:       # %bb.0:
@@ -619,3 +641,48 @@ define i32 @select65(i1 zeroext %x) {
   %select = select i1 %x, i32 65, i32 0
   ret i32 %select
 }
+
+
+define i32 @select1111(i1 zeroext %x) {
+; RV32IM-LABEL: select1111:
+; RV32IM:       # %bb.0:
+; RV32IM-NEXT:    neg a0, a0
+; RV32IM-NEXT:    andi a0, a0, 1111
+; RV32IM-NEXT:    ret
+;
+; RV32IMXQCIAC-LABEL: select1111:
+; RV32IMXQCIAC:       # %bb.0:
+; RV32IMXQCIAC-NEXT:    neg a0, a0
+; RV32IMXQCIAC-NEXT:    andi a0, a0, 1111
+; RV32IMXQCIAC-NEXT:    ret
+;
+; RV32IZBAMXQCIAC-LABEL: select1111:
+; RV32IZBAMXQCIAC:       # %bb.0:
+; RV32IZBAMXQCIAC-NEXT:    neg a0, a0
+; RV32IZBAMXQCIAC-NEXT:    andi a0, a0, 1111
+; RV32IZBAMXQCIAC-NEXT:    ret
+  %select = select i1 %x, i32 1111, i32 0
+  ret i32 %select
+}
+
+define i32 @select8193(i1 zeroext %x) {
+; RV32IM-LABEL: select8193:
+; RV32IM:       # %bb.0:
+; RV32IM-NEXT:    neg a0, a0
+; RV32IM-NEXT:    lui a1, 2
+; RV32IM-NEXT:    addi a1, a1, 1
+; RV32IM-NEXT:    and a0, a0, a1
+; RV32IM-NEXT:    ret
+;
+; RV32IMXQCIAC-LABEL: select8193:
+; RV32IMXQCIAC:       # %bb.0:
+; RV32IMXQCIAC-NEXT:    qc.shladd a0, a0, a0, 13
+; RV32IMXQCIAC-NEXT:    ret
+;
+; RV32IZBAMXQCIAC-LABEL: select8193:
+; RV32IZBAMXQCIAC:       # %bb.0:
+; RV32IZBAMXQCIAC-NEXT:    qc.shladd a0, a0, a0, 13
+; RV32IZBAMXQCIAC-NEXT:    ret
+  %select = select i1 %x, i32 8193, i32 0
+  ret i32 %select
+}

>From 01dbc14dc34ea25953971e5f59172f586f297780 Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <svs at qti.qualcomm.com>
Date: Fri, 3 Apr 2026 13:47:02 +0530
Subject: [PATCH 2/5] Lower (select c, y, 0) -> (qc.muliadd c, y-1)

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp |  8 +++++++-
 llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td | 10 ++++++++++
 llvm/test/CodeGen/RISCV/xqciac.ll           | 16 ++++++----------
 3 files changed, 23 insertions(+), 11 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 0650bbdedc08b..75bf9df9a2d31 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -9663,8 +9663,14 @@ static SDValue lowerSelectToBinOp(SDNode *N, SelectionDAG &DAG,
       return DAG.getNode(ISD::AND, DL, VT, Neg, DAG.getFreeze(FalseV));
     }
     if (isNullConstant(FalseV)) {
-      // (select c, (1 << ShAmount) + 1, 0) -> (c << ShAmount) + c
       if (auto *TrueC = dyn_cast<ConstantSDNode>(TrueV)) {
+        // (select c, y, 0) -> (c * (y - 1)) + c
+        int64_t TrueM2 = TrueC->getSExtValue() - 1;
+        if (isInt<12>(TrueM2) && Subtarget.hasVendorXqciac())
+          return DAG.getNode(RISCVISD::QC_MULIADD, DL, VT, CondV,
+                             CondV, DAG.getTargetConstant(TrueM2, DL, VT));
+
+        // (select c, (1 << ShAmount) + 1, 0) -> (c << ShAmount) + c
         uint64_t TrueM1 = TrueC->getZExtValue() - 1;
         if (isPowerOf2_64(TrueM1)) {
           unsigned ShAmount = Log2_64(TrueM1);
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
index c5f4e0167192e..df1488b986b3e 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
@@ -29,6 +29,12 @@ def qc_insb : RVSDNode<"QC_INSB", SDTypeProfile<1, 4, [SDTCisSameAs<0, 1>,
                                                        SDTCisInt<4>]>,
                        []>;
 
+def SDTIntMulAddOp : SDTypeProfile<1, 3, [
+  SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, SDTCisVT<0, i32>, SDTCisInt<2>
+]>;
+
+def qc_muliadd : RVSDNode<"QC_MULIADD", SDTIntMulAddOp>;
+
 def qc_e_li : RVSDNode<"QC_E_LI", SDTIntUnaryOp>;
 
 def uimm5nonzero : RISCVOp<XLenVT>,
@@ -99,6 +105,8 @@ def uimm10 : RISCVUImmLeafOp<10>;
 
 def uimm11 : RISCVUImmLeafOp<11>;
 
+def timm12 : TImmLeaf<XLenVT, [{return isInt<12>(Imm);}]>;
+
 // A 14-bit unsigned immediate where the least significant two bits are zero.
 def uimm14lsb00 : RISCVOp,
                   ImmLeaf<XLenVT, [{return isShiftedUInt<12, 2>(Imm);}]> {
@@ -1476,6 +1484,8 @@ class SelectQCbiSFB<CondCode Cond, DAGOperand InTyImm, SDNodeXForm xform>
 let Predicates = [HasVendorXqciac, IsRV32] in {
 def : Pat<(i32 (add GPRNoX0:$rd, (mul GPRNoX0:$rs1, simm12_lo:$imm12))),
           (QC_MULIADD GPRNoX0:$rd, GPRNoX0:$rs1, simm12_lo:$imm12)>;
+def : Pat<(i32 (qc_muliadd GPRNoX0:$rd, GPRNoX0:$rs1, (i32 timm12:$imm12))),
+          (QC_MULIADD GPRNoX0:$rd, GPRNoX0:$rs1, timm12:$imm12)>;
 def : Pat<(i32 (riscv_add_like_non_imm12 (shl GPRNoX0:$rs1, (i32 uimm5gt3:$imm)), GPRNoX0:$rs2)),
           (QC_SHLADD GPRNoX0:$rs1, GPRNoX0:$rs2, uimm5gt3:$imm)>;
 def : Pat<(i32 (riscv_shl_add GPRNoX0:$rs1, (i32 tuimm5gt3:$imm), GPRNoX0:$rs2)),
diff --git a/llvm/test/CodeGen/RISCV/xqciac.ll b/llvm/test/CodeGen/RISCV/xqciac.ll
index 3085331250f0b..8004f4c471581 100644
--- a/llvm/test/CodeGen/RISCV/xqciac.ll
+++ b/llvm/test/CodeGen/RISCV/xqciac.ll
@@ -609,14 +609,12 @@ define i32 @select20(i1 zeroext %x) {
 ;
 ; RV32IMXQCIAC-LABEL: select20:
 ; RV32IMXQCIAC:       # %bb.0:
-; RV32IMXQCIAC-NEXT:    neg a0, a0
-; RV32IMXQCIAC-NEXT:    andi a0, a0, 20
+; RV32IMXQCIAC-NEXT:    qc.c.muliadd a0, a0, 19
 ; RV32IMXQCIAC-NEXT:    ret
 ;
 ; RV32IZBAMXQCIAC-LABEL: select20:
 ; RV32IZBAMXQCIAC:       # %bb.0:
-; RV32IZBAMXQCIAC-NEXT:    neg a0, a0
-; RV32IZBAMXQCIAC-NEXT:    andi a0, a0, 20
+; RV32IZBAMXQCIAC-NEXT:    qc.c.muliadd a0, a0, 19
 ; RV32IZBAMXQCIAC-NEXT:    ret
   %select = select i1 %x, i32 20, i32 0
   ret i32 %select
@@ -631,12 +629,12 @@ define i32 @select65(i1 zeroext %x) {
 ;
 ; RV32IMXQCIAC-LABEL: select65:
 ; RV32IMXQCIAC:       # %bb.0:
-; RV32IMXQCIAC-NEXT:    qc.shladd a0, a0, a0, 6
+; RV32IMXQCIAC-NEXT:    qc.muliadd a0, a0, 64
 ; RV32IMXQCIAC-NEXT:    ret
 ;
 ; RV32IZBAMXQCIAC-LABEL: select65:
 ; RV32IZBAMXQCIAC:       # %bb.0:
-; RV32IZBAMXQCIAC-NEXT:    qc.shladd a0, a0, a0, 6
+; RV32IZBAMXQCIAC-NEXT:    qc.muliadd a0, a0, 64
 ; RV32IZBAMXQCIAC-NEXT:    ret
   %select = select i1 %x, i32 65, i32 0
   ret i32 %select
@@ -652,14 +650,12 @@ define i32 @select1111(i1 zeroext %x) {
 ;
 ; RV32IMXQCIAC-LABEL: select1111:
 ; RV32IMXQCIAC:       # %bb.0:
-; RV32IMXQCIAC-NEXT:    neg a0, a0
-; RV32IMXQCIAC-NEXT:    andi a0, a0, 1111
+; RV32IMXQCIAC-NEXT:    qc.muliadd a0, a0, 1110
 ; RV32IMXQCIAC-NEXT:    ret
 ;
 ; RV32IZBAMXQCIAC-LABEL: select1111:
 ; RV32IZBAMXQCIAC:       # %bb.0:
-; RV32IZBAMXQCIAC-NEXT:    neg a0, a0
-; RV32IZBAMXQCIAC-NEXT:    andi a0, a0, 1111
+; RV32IZBAMXQCIAC-NEXT:    qc.muliadd a0, a0, 1110
 ; RV32IZBAMXQCIAC-NEXT:    ret
   %select = select i1 %x, i32 1111, i32 0
   ret i32 %select

>From 34ccdbdfd339477faa67512a73238b2d2fad4b2a Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <svs at qti.qualcomm.com>
Date: Fri, 3 Apr 2026 15:03:38 +0530
Subject: [PATCH 3/5] clang-format

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 75bf9df9a2d31..2b49e0db9240d 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -9667,8 +9667,8 @@ static SDValue lowerSelectToBinOp(SDNode *N, SelectionDAG &DAG,
         // (select c, y, 0) -> (c * (y - 1)) + c
         int64_t TrueM2 = TrueC->getSExtValue() - 1;
         if (isInt<12>(TrueM2) && Subtarget.hasVendorXqciac())
-          return DAG.getNode(RISCVISD::QC_MULIADD, DL, VT, CondV,
-                             CondV, DAG.getTargetConstant(TrueM2, DL, VT));
+          return DAG.getNode(RISCVISD::QC_MULIADD, DL, VT, CondV, CondV,
+                             DAG.getTargetConstant(TrueM2, DL, VT));
 
         // (select c, (1 << ShAmount) + 1, 0) -> (c << ShAmount) + c
         uint64_t TrueM1 = TrueC->getZExtValue() - 1;

>From 7e12f46111778c4b06f52afb9aebe9a078b4d0ad Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <svs at qti.qualcomm.com>
Date: Sat, 4 Apr 2026 08:09:26 +0530
Subject: [PATCH 4/5] Fix possible UB with INT64_MIN

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 2b49e0db9240d..84f981ed84d31 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -9665,10 +9665,12 @@ static SDValue lowerSelectToBinOp(SDNode *N, SelectionDAG &DAG,
     if (isNullConstant(FalseV)) {
       if (auto *TrueC = dyn_cast<ConstantSDNode>(TrueV)) {
         // (select c, y, 0) -> (c * (y - 1)) + c
-        int64_t TrueM2 = TrueC->getSExtValue() - 1;
-        if (isInt<12>(TrueM2) && Subtarget.hasVendorXqciac())
+        int64_t MulImm = TrueC->getSExtValue();
+        if (MulImm != INT64_MIN)
+          MulImm--;
+        if (isInt<12>(MulImm) && Subtarget.hasVendorXqciac())
           return DAG.getNode(RISCVISD::QC_MULIADD, DL, VT, CondV, CondV,
-                             DAG.getTargetConstant(TrueM2, DL, VT));
+                             DAG.getTargetConstant(MulImm, DL, VT));
 
         // (select c, (1 << ShAmount) + 1, 0) -> (c << ShAmount) + c
         uint64_t TrueM1 = TrueC->getZExtValue() - 1;

>From 8df9429039c0d76c99d534fdeb19ce6e6a0ac4a2 Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <svs at qti.qualcomm.com>
Date: Sat, 4 Apr 2026 20:55:35 +0530
Subject: [PATCH 5/5] Use timm

---
 llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
index df1488b986b3e..e00d64c792ad8 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
@@ -105,8 +105,6 @@ def uimm10 : RISCVUImmLeafOp<10>;
 
 def uimm11 : RISCVUImmLeafOp<11>;
 
-def timm12 : TImmLeaf<XLenVT, [{return isInt<12>(Imm);}]>;
-
 // A 14-bit unsigned immediate where the least significant two bits are zero.
 def uimm14lsb00 : RISCVOp,
                   ImmLeaf<XLenVT, [{return isShiftedUInt<12, 2>(Imm);}]> {
@@ -1484,8 +1482,8 @@ class SelectQCbiSFB<CondCode Cond, DAGOperand InTyImm, SDNodeXForm xform>
 let Predicates = [HasVendorXqciac, IsRV32] in {
 def : Pat<(i32 (add GPRNoX0:$rd, (mul GPRNoX0:$rs1, simm12_lo:$imm12))),
           (QC_MULIADD GPRNoX0:$rd, GPRNoX0:$rs1, simm12_lo:$imm12)>;
-def : Pat<(i32 (qc_muliadd GPRNoX0:$rd, GPRNoX0:$rs1, (i32 timm12:$imm12))),
-          (QC_MULIADD GPRNoX0:$rd, GPRNoX0:$rs1, timm12:$imm12)>;
+def : Pat<(i32 (qc_muliadd GPRNoX0:$rd, GPRNoX0:$rs1, (i32 timm:$imm12))),
+          (QC_MULIADD GPRNoX0:$rd, GPRNoX0:$rs1, timm:$imm12)>;
 def : Pat<(i32 (riscv_add_like_non_imm12 (shl GPRNoX0:$rs1, (i32 uimm5gt3:$imm)), GPRNoX0:$rs2)),
           (QC_SHLADD GPRNoX0:$rs1, GPRNoX0:$rs2, uimm5gt3:$imm)>;
 def : Pat<(i32 (riscv_shl_add GPRNoX0:$rs1, (i32 tuimm5gt3:$imm), GPRNoX0:$rs2)),



More information about the llvm-commits mailing list