diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td index a2b4302e19edc..ce21d831250b2 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 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. +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 a8b06b2af5764..b4edcf6cc55cf 100644 --- a/llvm/test/CodeGen/RISCV/rv64zbs.ll +++ b/llvm/test/CodeGen/RISCV/rv64zbs.ll @@ -547,10 +547,28 @@ 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 { +; 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 +} + define i64 @bclri_i64_10(i64 %a) nounwind { ; CHECK-LABEL: bclri_i64_10: ; CHECK: # %bb.0: @@ -724,6 +742,24 @@ define signext i32 @bseti_i32_31(i32 signext %a) nounwind { ret i32 %or } +define signext i32 @bseti_i32_31_allWUsers(i32 signext %a) nounwind { +; 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 +} + define i64 @bseti_i64_10(i64 %a) nounwind { ; CHECK-LABEL: bseti_i64_10: ; CHECK: # %bb.0: @@ -862,6 +898,24 @@ 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 { +; 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 +} + define i64 @binvi_i64_10(i64 %a) nounwind { ; CHECK-LABEL: binvi_i64_10: ; CHECK: # %bb.0: