[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