[llvm] [RISCV] Lower (select c, (1 << X) + 1, 0) -> (shXadd c, c) (PR #158969)
Piotr Fusik via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 16 04:03:57 PDT 2025
https://github.com/pfusik created https://github.com/llvm/llvm-project/pull/158969
None
>From cd1e45ba4e9003c4ef60b48e38d6ee20adc2580b Mon Sep 17 00:00:00 2001
From: Piotr Fusik <p.fusik at samsung.com>
Date: Tue, 16 Sep 2025 12:31:33 +0200
Subject: [PATCH 1/2] [RISCV][test] Add (select c, (1 << N) + 1, 0)
---
llvm/test/CodeGen/RISCV/rv32zba.ll | 63 ++++++++++++++++++++++++++++++
llvm/test/CodeGen/RISCV/rv64zba.ll | 30 ++++++++++++++
llvm/test/CodeGen/RISCV/xqciac.ll | 22 +++++++++++
3 files changed, 115 insertions(+)
diff --git a/llvm/test/CodeGen/RISCV/rv32zba.ll b/llvm/test/CodeGen/RISCV/rv32zba.ll
index ab099103b4216..71e16d33db502 100644
--- a/llvm/test/CodeGen/RISCV/rv32zba.ll
+++ b/llvm/test/CodeGen/RISCV/rv32zba.ll
@@ -1136,3 +1136,66 @@ define i32 @mul_neg8(i32 %a) {
%c = mul i32 %a, -8
ret i32 %c
}
+
+define i32 @select3i32(i1 zeroext %x) {
+; CHECK-LABEL: select3i32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: neg a0, a0
+; CHECK-NEXT: andi a0, a0, 3
+; CHECK-NEXT: ret
+ %select = select i1 %x, i32 3, i32 0
+ ret i32 %select
+}
+
+define i32 @select5i32(i1 zeroext %x) {
+; CHECK-LABEL: select5i32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: neg a0, a0
+; CHECK-NEXT: andi a0, a0, 5
+; CHECK-NEXT: ret
+ %select = select i1 %x, i32 5, i32 0
+ ret i32 %select
+}
+
+define i32 @select9i32(i1 zeroext %x) {
+; CHECK-LABEL: select9i32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: neg a0, a0
+; CHECK-NEXT: andi a0, a0, 9
+; CHECK-NEXT: ret
+ %select = select i1 %x, i32 9, i32 0
+ ret i32 %select
+}
+
+define i64 @select3i64(i1 zeroext %x) {
+; CHECK-LABEL: select3i64:
+; CHECK: # %bb.0:
+; CHECK-NEXT: neg a0, a0
+; CHECK-NEXT: andi a0, a0, 3
+; CHECK-NEXT: li a1, 0
+; CHECK-NEXT: ret
+ %select = select i1 %x, i64 3, i64 0
+ ret i64 %select
+}
+
+define i64 @select5i64(i1 zeroext %x) {
+; CHECK-LABEL: select5i64:
+; CHECK: # %bb.0:
+; CHECK-NEXT: neg a0, a0
+; CHECK-NEXT: andi a0, a0, 5
+; CHECK-NEXT: li a1, 0
+; CHECK-NEXT: ret
+ %select = select i1 %x, i64 5, i64 0
+ ret i64 %select
+}
+
+define i64 @select9i64(i1 zeroext %x) {
+; CHECK-LABEL: select9i64:
+; CHECK: # %bb.0:
+; CHECK-NEXT: neg a0, a0
+; CHECK-NEXT: andi a0, a0, 9
+; CHECK-NEXT: li a1, 0
+; CHECK-NEXT: ret
+ %select = select i1 %x, i64 9, i64 0
+ ret i64 %select
+}
diff --git a/llvm/test/CodeGen/RISCV/rv64zba.ll b/llvm/test/CodeGen/RISCV/rv64zba.ll
index b46f7cc440b7a..54c8cd77326d9 100644
--- a/llvm/test/CodeGen/RISCV/rv64zba.ll
+++ b/llvm/test/CodeGen/RISCV/rv64zba.ll
@@ -4576,3 +4576,33 @@ define i64 @append_32ones(i64 %x) {
%o = or i64 %s, 4294967295
ret i64 %o
}
+
+define i32 @select3(i1 zeroext %x) {
+; CHECK-LABEL: select3:
+; CHECK: # %bb.0:
+; CHECK-NEXT: neg a0, a0
+; CHECK-NEXT: andi a0, a0, 3
+; CHECK-NEXT: ret
+ %select = select i1 %x, i32 3, i32 0
+ ret i32 %select
+}
+
+define i32 @select5(i1 zeroext %x) {
+; CHECK-LABEL: select5:
+; CHECK: # %bb.0:
+; CHECK-NEXT: neg a0, a0
+; CHECK-NEXT: andi a0, a0, 5
+; CHECK-NEXT: ret
+ %select = select i1 %x, i32 5, i32 0
+ ret i32 %select
+}
+
+define i32 @select9(i1 zeroext %x) {
+; CHECK-LABEL: select9:
+; CHECK: # %bb.0:
+; CHECK-NEXT: neg a0, a0
+; CHECK-NEXT: andi a0, a0, 9
+; CHECK-NEXT: ret
+ %select = select i1 %x, i32 9, i32 0
+ ret i32 %select
+}
diff --git a/llvm/test/CodeGen/RISCV/xqciac.ll b/llvm/test/CodeGen/RISCV/xqciac.ll
index ec83fd7a28f32..e75f18d27f6e2 100644
--- a/llvm/test/CodeGen/RISCV/xqciac.ll
+++ b/llvm/test/CodeGen/RISCV/xqciac.ll
@@ -599,3 +599,25 @@ define i32 @add_shl_moreOneUse_4(i32 %x) {
%add = add i32 %mul, %or
ret i32 %add
}
+
+define i32 @select65(i1 zeroext %x) {
+; RV32IM-LABEL: select65:
+; RV32IM: # %bb.0:
+; RV32IM-NEXT: neg a0, a0
+; RV32IM-NEXT: andi a0, a0, 65
+; RV32IM-NEXT: ret
+;
+; RV32IMXQCIAC-LABEL: select65:
+; RV32IMXQCIAC: # %bb.0:
+; RV32IMXQCIAC-NEXT: neg a0, a0
+; RV32IMXQCIAC-NEXT: andi a0, a0, 65
+; RV32IMXQCIAC-NEXT: ret
+;
+; RV32IZBAMXQCIAC-LABEL: select65:
+; RV32IZBAMXQCIAC: # %bb.0:
+; RV32IZBAMXQCIAC-NEXT: neg a0, a0
+; RV32IZBAMXQCIAC-NEXT: andi a0, a0, 65
+; RV32IZBAMXQCIAC-NEXT: ret
+ %select = select i1 %x, i32 65, i32 0
+ ret i32 %select
+}
>From 6a62335227d0d8de90979503ef3aea522a0e1fcc Mon Sep 17 00:00:00 2001
From: Piotr Fusik <p.fusik at samsung.com>
Date: Tue, 16 Sep 2025 12:32:09 +0200
Subject: [PATCH 2/2] [RISCV] Lower (select c, (1 << N) + 1, 0) -> (c << N) + c
---
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 20 ++-
llvm/test/CodeGen/RISCV/rv32zba.ll | 132 +++++++++++++++-----
llvm/test/CodeGen/RISCV/rv64zba.ll | 60 ++++++---
llvm/test/CodeGen/RISCV/xqciac.ll | 6 +-
4 files changed, 162 insertions(+), 56 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 9d90eb0a65218..cb20959e9dcc8 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -9150,10 +9150,22 @@ static SDValue lowerSelectToBinOp(SDNode *N, SelectionDAG &DAG,
DAG.getNode(ISD::ADD, DL, VT, CondV, DAG.getAllOnesConstant(DL, VT));
return DAG.getNode(ISD::AND, DL, VT, Neg, DAG.getFreeze(FalseV));
}
- // (select c, y, 0) -> -c & y
- if (isNullConstant(FalseV) && (!HasCZero || isSimm12Constant(TrueV))) {
- SDValue Neg = DAG.getNegative(CondV, DL, VT);
- return DAG.getNode(ISD::AND, DL, VT, Neg, DAG.getFreeze(TrueV));
+ if (isNullConstant(FalseV)) {
+ // (select c, (1 << ShAmount) + 1, 0) -> (c << ShAmount) + c
+ if (auto *TrueC = dyn_cast<ConstantSDNode>(TrueV)) {
+ uint64_t TrueM1 = TrueC->getZExtValue() - 1;
+ if (isPowerOf2_64(TrueM1)) {
+ unsigned ShAmount = Log2_64(TrueM1);
+ if (Subtarget.hasShlAdd(ShAmount))
+ return DAG.getNode(RISCVISD::SHL_ADD, DL, VT, CondV,
+ DAG.getConstant(ShAmount, DL, VT), CondV);
+ }
+ }
+ // (select c, y, 0) -> -c & y
+ if (!HasCZero || isSimm12Constant(TrueV)) {
+ SDValue Neg = DAG.getNegative(CondV, DL, VT);
+ return DAG.getNode(ISD::AND, DL, VT, Neg, DAG.getFreeze(TrueV));
+ }
}
}
diff --git a/llvm/test/CodeGen/RISCV/rv32zba.ll b/llvm/test/CodeGen/RISCV/rv32zba.ll
index 71e16d33db502..0d490682d1ff3 100644
--- a/llvm/test/CodeGen/RISCV/rv32zba.ll
+++ b/llvm/test/CodeGen/RISCV/rv32zba.ll
@@ -1138,64 +1138,130 @@ define i32 @mul_neg8(i32 %a) {
}
define i32 @select3i32(i1 zeroext %x) {
-; CHECK-LABEL: select3i32:
-; CHECK: # %bb.0:
-; CHECK-NEXT: neg a0, a0
-; CHECK-NEXT: andi a0, a0, 3
-; CHECK-NEXT: ret
+; RV32I-LABEL: select3i32:
+; RV32I: # %bb.0:
+; RV32I-NEXT: neg a0, a0
+; RV32I-NEXT: andi a0, a0, 3
+; RV32I-NEXT: ret
+;
+; RV32ZBA-LABEL: select3i32:
+; RV32ZBA: # %bb.0:
+; RV32ZBA-NEXT: sh1add a0, a0, a0
+; RV32ZBA-NEXT: ret
+;
+; RV32XANDESPERF-LABEL: select3i32:
+; RV32XANDESPERF: # %bb.0:
+; RV32XANDESPERF-NEXT: nds.lea.h a0, a0, a0
+; RV32XANDESPERF-NEXT: ret
%select = select i1 %x, i32 3, i32 0
ret i32 %select
}
define i32 @select5i32(i1 zeroext %x) {
-; CHECK-LABEL: select5i32:
-; CHECK: # %bb.0:
-; CHECK-NEXT: neg a0, a0
-; CHECK-NEXT: andi a0, a0, 5
-; CHECK-NEXT: ret
+; RV32I-LABEL: select5i32:
+; RV32I: # %bb.0:
+; RV32I-NEXT: neg a0, a0
+; RV32I-NEXT: andi a0, a0, 5
+; RV32I-NEXT: ret
+;
+; RV32ZBA-LABEL: select5i32:
+; RV32ZBA: # %bb.0:
+; RV32ZBA-NEXT: sh2add a0, a0, a0
+; RV32ZBA-NEXT: ret
+;
+; RV32XANDESPERF-LABEL: select5i32:
+; RV32XANDESPERF: # %bb.0:
+; RV32XANDESPERF-NEXT: nds.lea.w a0, a0, a0
+; RV32XANDESPERF-NEXT: ret
%select = select i1 %x, i32 5, i32 0
ret i32 %select
}
define i32 @select9i32(i1 zeroext %x) {
-; CHECK-LABEL: select9i32:
-; CHECK: # %bb.0:
-; CHECK-NEXT: neg a0, a0
-; CHECK-NEXT: andi a0, a0, 9
-; CHECK-NEXT: ret
+; RV32I-LABEL: select9i32:
+; RV32I: # %bb.0:
+; RV32I-NEXT: neg a0, a0
+; RV32I-NEXT: andi a0, a0, 9
+; RV32I-NEXT: ret
+;
+; RV32ZBA-LABEL: select9i32:
+; RV32ZBA: # %bb.0:
+; RV32ZBA-NEXT: sh3add a0, a0, a0
+; RV32ZBA-NEXT: ret
+;
+; RV32XANDESPERF-LABEL: select9i32:
+; RV32XANDESPERF: # %bb.0:
+; RV32XANDESPERF-NEXT: nds.lea.d a0, a0, a0
+; RV32XANDESPERF-NEXT: ret
%select = select i1 %x, i32 9, i32 0
ret i32 %select
}
define i64 @select3i64(i1 zeroext %x) {
-; CHECK-LABEL: select3i64:
-; CHECK: # %bb.0:
-; CHECK-NEXT: neg a0, a0
-; CHECK-NEXT: andi a0, a0, 3
-; CHECK-NEXT: li a1, 0
-; CHECK-NEXT: ret
+; RV32I-LABEL: select3i64:
+; RV32I: # %bb.0:
+; RV32I-NEXT: neg a0, a0
+; RV32I-NEXT: andi a0, a0, 3
+; RV32I-NEXT: li a1, 0
+; RV32I-NEXT: ret
+;
+; RV32ZBA-LABEL: select3i64:
+; RV32ZBA: # %bb.0:
+; RV32ZBA-NEXT: sh1add a0, a0, a0
+; RV32ZBA-NEXT: li a1, 0
+; RV32ZBA-NEXT: ret
+;
+; RV32XANDESPERF-LABEL: select3i64:
+; RV32XANDESPERF: # %bb.0:
+; RV32XANDESPERF-NEXT: nds.lea.h a0, a0, a0
+; RV32XANDESPERF-NEXT: li a1, 0
+; RV32XANDESPERF-NEXT: ret
%select = select i1 %x, i64 3, i64 0
ret i64 %select
}
define i64 @select5i64(i1 zeroext %x) {
-; CHECK-LABEL: select5i64:
-; CHECK: # %bb.0:
-; CHECK-NEXT: neg a0, a0
-; CHECK-NEXT: andi a0, a0, 5
-; CHECK-NEXT: li a1, 0
-; CHECK-NEXT: ret
+; RV32I-LABEL: select5i64:
+; RV32I: # %bb.0:
+; RV32I-NEXT: neg a0, a0
+; RV32I-NEXT: andi a0, a0, 5
+; RV32I-NEXT: li a1, 0
+; RV32I-NEXT: ret
+;
+; RV32ZBA-LABEL: select5i64:
+; RV32ZBA: # %bb.0:
+; RV32ZBA-NEXT: sh2add a0, a0, a0
+; RV32ZBA-NEXT: li a1, 0
+; RV32ZBA-NEXT: ret
+;
+; RV32XANDESPERF-LABEL: select5i64:
+; RV32XANDESPERF: # %bb.0:
+; RV32XANDESPERF-NEXT: nds.lea.w a0, a0, a0
+; RV32XANDESPERF-NEXT: li a1, 0
+; RV32XANDESPERF-NEXT: ret
%select = select i1 %x, i64 5, i64 0
ret i64 %select
}
define i64 @select9i64(i1 zeroext %x) {
-; CHECK-LABEL: select9i64:
-; CHECK: # %bb.0:
-; CHECK-NEXT: neg a0, a0
-; CHECK-NEXT: andi a0, a0, 9
-; CHECK-NEXT: li a1, 0
-; CHECK-NEXT: ret
+; RV32I-LABEL: select9i64:
+; RV32I: # %bb.0:
+; RV32I-NEXT: neg a0, a0
+; RV32I-NEXT: andi a0, a0, 9
+; RV32I-NEXT: li a1, 0
+; RV32I-NEXT: ret
+;
+; RV32ZBA-LABEL: select9i64:
+; RV32ZBA: # %bb.0:
+; RV32ZBA-NEXT: sh3add a0, a0, a0
+; RV32ZBA-NEXT: li a1, 0
+; RV32ZBA-NEXT: ret
+;
+; RV32XANDESPERF-LABEL: select9i64:
+; RV32XANDESPERF: # %bb.0:
+; RV32XANDESPERF-NEXT: nds.lea.d a0, a0, a0
+; RV32XANDESPERF-NEXT: li a1, 0
+; RV32XANDESPERF-NEXT: ret
%select = select i1 %x, i64 9, i64 0
ret i64 %select
}
diff --git a/llvm/test/CodeGen/RISCV/rv64zba.ll b/llvm/test/CodeGen/RISCV/rv64zba.ll
index 54c8cd77326d9..95f9f7116fe68 100644
--- a/llvm/test/CodeGen/RISCV/rv64zba.ll
+++ b/llvm/test/CodeGen/RISCV/rv64zba.ll
@@ -4578,31 +4578,61 @@ define i64 @append_32ones(i64 %x) {
}
define i32 @select3(i1 zeroext %x) {
-; CHECK-LABEL: select3:
-; CHECK: # %bb.0:
-; CHECK-NEXT: neg a0, a0
-; CHECK-NEXT: andi a0, a0, 3
-; CHECK-NEXT: ret
+; RV64I-LABEL: select3:
+; RV64I: # %bb.0:
+; RV64I-NEXT: neg a0, a0
+; RV64I-NEXT: andi a0, a0, 3
+; RV64I-NEXT: ret
+;
+; RV64ZBA-LABEL: select3:
+; RV64ZBA: # %bb.0:
+; RV64ZBA-NEXT: sh1add a0, a0, a0
+; RV64ZBA-NEXT: ret
+;
+; RV64XANDESPERF-LABEL: select3:
+; RV64XANDESPERF: # %bb.0:
+; RV64XANDESPERF-NEXT: nds.lea.h a0, a0, a0
+; RV64XANDESPERF-NEXT: ret
%select = select i1 %x, i32 3, i32 0
ret i32 %select
}
define i32 @select5(i1 zeroext %x) {
-; CHECK-LABEL: select5:
-; CHECK: # %bb.0:
-; CHECK-NEXT: neg a0, a0
-; CHECK-NEXT: andi a0, a0, 5
-; CHECK-NEXT: ret
+; RV64I-LABEL: select5:
+; RV64I: # %bb.0:
+; RV64I-NEXT: neg a0, a0
+; RV64I-NEXT: andi a0, a0, 5
+; RV64I-NEXT: ret
+;
+; RV64ZBA-LABEL: select5:
+; RV64ZBA: # %bb.0:
+; RV64ZBA-NEXT: sh2add a0, a0, a0
+; RV64ZBA-NEXT: ret
+;
+; RV64XANDESPERF-LABEL: select5:
+; RV64XANDESPERF: # %bb.0:
+; RV64XANDESPERF-NEXT: nds.lea.w a0, a0, a0
+; RV64XANDESPERF-NEXT: ret
%select = select i1 %x, i32 5, i32 0
ret i32 %select
}
define i32 @select9(i1 zeroext %x) {
-; CHECK-LABEL: select9:
-; CHECK: # %bb.0:
-; CHECK-NEXT: neg a0, a0
-; CHECK-NEXT: andi a0, a0, 9
-; CHECK-NEXT: ret
+; RV64I-LABEL: select9:
+; RV64I: # %bb.0:
+; RV64I-NEXT: neg a0, a0
+; RV64I-NEXT: andi a0, a0, 9
+; RV64I-NEXT: ret
+;
+; RV64ZBA-LABEL: select9:
+; RV64ZBA: # %bb.0:
+; RV64ZBA-NEXT: sh3add a0, a0, a0
+; RV64ZBA-NEXT: ret
+;
+; RV64XANDESPERF-LABEL: select9:
+; RV64XANDESPERF: # %bb.0:
+; RV64XANDESPERF-NEXT: nds.lea.d a0, a0, a0
+; RV64XANDESPERF-NEXT: ret
%select = select i1 %x, i32 9, i32 0
ret i32 %select
}
diff --git a/llvm/test/CodeGen/RISCV/xqciac.ll b/llvm/test/CodeGen/RISCV/xqciac.ll
index e75f18d27f6e2..918468bdf03d3 100644
--- a/llvm/test/CodeGen/RISCV/xqciac.ll
+++ b/llvm/test/CodeGen/RISCV/xqciac.ll
@@ -609,14 +609,12 @@ define i32 @select65(i1 zeroext %x) {
;
; RV32IMXQCIAC-LABEL: select65:
; RV32IMXQCIAC: # %bb.0:
-; RV32IMXQCIAC-NEXT: neg a0, a0
-; RV32IMXQCIAC-NEXT: andi a0, a0, 65
+; RV32IMXQCIAC-NEXT: qc.shladd a0, a0, a0, 6
; RV32IMXQCIAC-NEXT: ret
;
; RV32IZBAMXQCIAC-LABEL: select65:
; RV32IZBAMXQCIAC: # %bb.0:
-; RV32IZBAMXQCIAC-NEXT: neg a0, a0
-; RV32IZBAMXQCIAC-NEXT: andi a0, a0, 65
+; RV32IZBAMXQCIAC-NEXT: qc.shladd a0, a0, a0, 6
; RV32IZBAMXQCIAC-NEXT: ret
%select = select i1 %x, i32 65, i32 0
ret i32 %select
More information about the llvm-commits
mailing list