From c7fa8d22ac59e76b229dacaa488aa2145248c43f Mon Sep 17 00:00:00 2001 From: Craig Topper 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 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 GPR:$rs1, (XLenVT 2147483647)), + (BCLRI GPR:$rs1, 31)>; +def : Pat<(binop_allwusers GPR:$rs1, (XLenVT -2147483648)), + (BSETI GPR:$rs1, 31)>; +def : Pat<(binop_allwusers GPR:$rs1, (XLenVT -2147483648)), + (BINVI GPR:$rs1, 31)>; +} + let Predicates = [HasStdExtZbb] in def : PatGpr; 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 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 --- 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.