[llvm] [RISCV] Use bseti 31 for (or X, -2147483648) when upper 32 bits aren't used. (PR #159678)
Craig Topper via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 18 16:49:00 PDT 2025
https://github.com/topperc updated https://github.com/llvm/llvm-project/pull/159678
>From c7fa8d22ac59e76b229dacaa488aa2145248c43f Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Thu, 18 Sep 2025 15:55:36 -0700
Subject: [PATCH 1/3] Pre-commit test
---
llvm/test/CodeGen/RISCV/rv64zbs.ll | 38 +++++++++++++++++++++++++++++-
1 file changed, 37 insertions(+), 1 deletion(-)
diff --git a/llvm/test/CodeGen/RISCV/rv64zbs.ll b/llvm/test/CodeGen/RISCV/rv64zbs.ll
index a8b06b2af5764..d58b8480412c0 100644
--- a/llvm/test/CodeGen/RISCV/rv64zbs.ll
+++ b/llvm/test/CodeGen/RISCV/rv64zbs.ll
@@ -547,10 +547,22 @@ define signext i32 @bclri_i32_31(i32 signext %a) nounwind {
; CHECK-NEXT: slli a0, a0, 33
; CHECK-NEXT: srli a0, a0, 33
; CHECK-NEXT: ret
- %and = and i32 %a, -2147483649
+ %and = and i32 %a, 2147483647
ret i32 %and
}
+define signext i32 @bclri_i32_31_allWUsers(i32 signext %a) nounwind {
+; CHECK-LABEL: bclri_i32_31_allWUsers:
+; CHECK: # %bb.0:
+; CHECK-NEXT: slli a0, a0, 33
+; CHECK-NEXT: srli a0, a0, 33
+; CHECK-NEXT: addiw a0, a0, 1
+; CHECK-NEXT: ret
+ %and = and i32 %a, 2147483647
+ %add = add i32 %and, 1
+ ret i32 %add
+}
+
define i64 @bclri_i64_10(i64 %a) nounwind {
; CHECK-LABEL: bclri_i64_10:
; CHECK: # %bb.0:
@@ -724,6 +736,18 @@ define signext i32 @bseti_i32_31(i32 signext %a) nounwind {
ret i32 %or
}
+define signext i32 @bseti_i32_31_allWUsers(i32 signext %a) nounwind {
+; CHECK-LABEL: bseti_i32_31_allWUsers:
+; CHECK: # %bb.0:
+; CHECK-NEXT: lui a1, 524288
+; CHECK-NEXT: or a0, a0, a1
+; CHECK-NEXT: addiw a0, a0, 1
+; CHECK-NEXT: ret
+ %or = or i32 %a, 2147483648
+ %add = add i32 %or, 1
+ ret i32 %add
+}
+
define i64 @bseti_i64_10(i64 %a) nounwind {
; CHECK-LABEL: bseti_i64_10:
; CHECK: # %bb.0:
@@ -862,6 +886,18 @@ define signext i32 @binvi_i32_31(i32 signext %a) nounwind {
ret i32 %xor
}
+define void @binvi_i32_31_allWUsers(i32 signext %a, ptr %p) nounwind {
+; CHECK-LABEL: binvi_i32_31_allWUsers:
+; CHECK: # %bb.0:
+; CHECK-NEXT: lui a2, 524288
+; CHECK-NEXT: xor a0, a0, a2
+; CHECK-NEXT: sw a0, 0(a1)
+; CHECK-NEXT: ret
+ %xor = xor i32 %a, 2147483648
+ store i32 %xor, ptr %p
+ ret void
+}
+
define i64 @binvi_i64_10(i64 %a) nounwind {
; CHECK-LABEL: binvi_i64_10:
; CHECK: # %bb.0:
>From 078305192b4dd2ceeacdf0cdeeeee78466e8b4ad Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Thu, 18 Sep 2025 15:57:36 -0700
Subject: [PATCH 2/3] [RISCV] Use bseti 31 for (or X, -2147483648) when upper
32 bits aren't used.
If the original type was i32, type legalization will sign extend
the constant. This prevents it from having a single bit set or clear
so other patterns can't match. If the upper bits aren't used, we
can ignore the sign extension.
Similar for bclri and binvi.
---
llvm/lib/Target/RISCV/RISCVInstrInfoZb.td | 13 ++++++
llvm/test/CodeGen/RISCV/rv64zbs.ll | 54 +++++++++++++++--------
2 files changed, 49 insertions(+), 18 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td
index a2b4302e19edc..9b98588073212 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td
@@ -574,6 +574,19 @@ def : Pat<(XLenVT (and GPR:$r, BCLRIANDIMask:$i)),
(BCLRITwoBitsMaskHigh BCLRIANDIMask:$i))>;
} // Predicates = [HasStdExtZbs]
+let Predicates = [HasStdExtZbs, IsRV64] in {
+// If the original code was setting, clearing, or inverting bit 31 or an i32,
+// type legalization might have sign extended the constant so it doesn't have a
+// single 0 or 1 bit. If the upper 32 bits aren't used by later instructions we
+// can still use bseti/bclri.
+def : Pat<(binop_allwusers<and> GPR:$rs1, (XLenVT 2147483647)),
+ (BCLRI GPR:$rs1, 31)>;
+def : Pat<(binop_allwusers<or> GPR:$rs1, (XLenVT -2147483648)),
+ (BSETI GPR:$rs1, 31)>;
+def : Pat<(binop_allwusers<xor> GPR:$rs1, (XLenVT -2147483648)),
+ (BINVI GPR:$rs1, 31)>;
+}
+
let Predicates = [HasStdExtZbb] in
def : PatGpr<riscv_orc_b, ORC_B>;
diff --git a/llvm/test/CodeGen/RISCV/rv64zbs.ll b/llvm/test/CodeGen/RISCV/rv64zbs.ll
index d58b8480412c0..b4edcf6cc55cf 100644
--- a/llvm/test/CodeGen/RISCV/rv64zbs.ll
+++ b/llvm/test/CodeGen/RISCV/rv64zbs.ll
@@ -552,12 +552,18 @@ define signext i32 @bclri_i32_31(i32 signext %a) nounwind {
}
define signext i32 @bclri_i32_31_allWUsers(i32 signext %a) nounwind {
-; CHECK-LABEL: bclri_i32_31_allWUsers:
-; CHECK: # %bb.0:
-; CHECK-NEXT: slli a0, a0, 33
-; CHECK-NEXT: srli a0, a0, 33
-; CHECK-NEXT: addiw a0, a0, 1
-; CHECK-NEXT: ret
+; RV64I-LABEL: bclri_i32_31_allWUsers:
+; RV64I: # %bb.0:
+; RV64I-NEXT: slli a0, a0, 33
+; RV64I-NEXT: srli a0, a0, 33
+; RV64I-NEXT: addiw a0, a0, 1
+; RV64I-NEXT: ret
+;
+; RV64ZBS-LABEL: bclri_i32_31_allWUsers:
+; RV64ZBS: # %bb.0:
+; RV64ZBS-NEXT: bclri a0, a0, 31
+; RV64ZBS-NEXT: addiw a0, a0, 1
+; RV64ZBS-NEXT: ret
%and = and i32 %a, 2147483647
%add = add i32 %and, 1
ret i32 %add
@@ -737,12 +743,18 @@ define signext i32 @bseti_i32_31(i32 signext %a) nounwind {
}
define signext i32 @bseti_i32_31_allWUsers(i32 signext %a) nounwind {
-; CHECK-LABEL: bseti_i32_31_allWUsers:
-; CHECK: # %bb.0:
-; CHECK-NEXT: lui a1, 524288
-; CHECK-NEXT: or a0, a0, a1
-; CHECK-NEXT: addiw a0, a0, 1
-; CHECK-NEXT: ret
+; RV64I-LABEL: bseti_i32_31_allWUsers:
+; RV64I: # %bb.0:
+; RV64I-NEXT: lui a1, 524288
+; RV64I-NEXT: or a0, a0, a1
+; RV64I-NEXT: addiw a0, a0, 1
+; RV64I-NEXT: ret
+;
+; RV64ZBS-LABEL: bseti_i32_31_allWUsers:
+; RV64ZBS: # %bb.0:
+; RV64ZBS-NEXT: bseti a0, a0, 31
+; RV64ZBS-NEXT: addiw a0, a0, 1
+; RV64ZBS-NEXT: ret
%or = or i32 %a, 2147483648
%add = add i32 %or, 1
ret i32 %add
@@ -887,12 +899,18 @@ define signext i32 @binvi_i32_31(i32 signext %a) nounwind {
}
define void @binvi_i32_31_allWUsers(i32 signext %a, ptr %p) nounwind {
-; CHECK-LABEL: binvi_i32_31_allWUsers:
-; CHECK: # %bb.0:
-; CHECK-NEXT: lui a2, 524288
-; CHECK-NEXT: xor a0, a0, a2
-; CHECK-NEXT: sw a0, 0(a1)
-; CHECK-NEXT: ret
+; RV64I-LABEL: binvi_i32_31_allWUsers:
+; RV64I: # %bb.0:
+; RV64I-NEXT: lui a2, 524288
+; RV64I-NEXT: xor a0, a0, a2
+; RV64I-NEXT: sw a0, 0(a1)
+; RV64I-NEXT: ret
+;
+; RV64ZBS-LABEL: binvi_i32_31_allWUsers:
+; RV64ZBS: # %bb.0:
+; RV64ZBS-NEXT: binvi a0, a0, 31
+; RV64ZBS-NEXT: sw a0, 0(a1)
+; RV64ZBS-NEXT: ret
%xor = xor i32 %a, 2147483648
store i32 %xor, ptr %p
ret void
>From 623a10bf08781f719b9f4fdf45b15fac27362bbe Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Thu, 18 Sep 2025 16:48:52 -0700
Subject: [PATCH 3/3] Update llvm/lib/Target/RISCV/RISCVInstrInfoZb.td
Co-authored-by: Sam Elliott <sam at lenary.co.uk>
---
llvm/lib/Target/RISCV/RISCVInstrInfoZb.td | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td
index 9b98588073212..ce21d831250b2 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td
@@ -575,7 +575,7 @@ def : Pat<(XLenVT (and GPR:$r, BCLRIANDIMask:$i)),
} // Predicates = [HasStdExtZbs]
let Predicates = [HasStdExtZbs, IsRV64] in {
-// If the original code was setting, clearing, or inverting bit 31 or an i32,
+// If the original code was setting, clearing, or inverting bit 31 of an i32,
// type legalization might have sign extended the constant so it doesn't have a
// single 0 or 1 bit. If the upper 32 bits aren't used by later instructions we
// can still use bseti/bclri.
More information about the llvm-commits
mailing list