diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoB.td b/llvm/lib/Target/RISCV/RISCVInstrInfoB.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfoB.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoB.td @@ -128,6 +128,49 @@ SDLoc(N), N->getValueType(0)); }]>; +// Check if (and r, i) can be optimized to (BCLRI (BCLRI r, i0), i1), +// in which i = ~((1<hasOneUse()) + return false; + // The immediate should not be a simm12. + if (isInt<12>(N->getSExtValue())) + return false; + // The immediate must have exactly two bits clear. + return countPopulation(N->getZExtValue()) == Subtarget->getXLen() - 2; +}]>; + +def BCLRITwoBitsMaskLow : SDNodeXFormgetTargetConstant(countTrailingZeros(~N->getZExtValue()), + SDLoc(N), N->getValueType(0)); +}]>; + +def BCLRITwoBitsMaskHigh : SDNodeXFormgetSExtValue(); + if (!Subtarget->is64Bit()) + I |= 0xffffffffull << 32; + return CurDAG->getTargetConstant(63 - countLeadingZeros(~I), SDLoc(N), + N->getValueType(0)); +}]>; + +// Check if (and r, i) can be optimized to (BCLRI (ANDI r, i0), i1), +// in which i = i0 & ~(1<hasOneUse()) + return false; + // The immediate should not be a simm12. + if (isInt<12>(N->getSExtValue())) + return false; + // There should be only one clear bit from bit 11 to the top. + uint64_t I = N->getZExtValue() | 0x7ff; + return Subtarget->is64Bit() ? isPowerOf2_64(~I) : isPowerOf2_32(~I); +}]>; + +def BCLRIANDIMaskLow : SDNodeXFormgetTargetConstant((N->getZExtValue() & 0x7ff) | ~0x7ffull, + SDLoc(N), N->getValueType(0)); +}]>; + //===----------------------------------------------------------------------===// // Instruction class templates //===----------------------------------------------------------------------===// @@ -777,6 +820,12 @@ def : Pat<(xor GPR:$r, BSETINVORIMask:$i), (BINVI (XORI GPR:$r, (BSETINVORIMaskLow BSETINVORIMask:$i)), (BSETINVTwoBitsMaskHigh BSETINVORIMask:$i))>; +def : Pat<(and GPR:$r, BCLRITwoBitsMask:$i), + (BCLRI (BCLRI GPR:$r, (BCLRITwoBitsMaskLow BCLRITwoBitsMask:$i)), + (BCLRITwoBitsMaskHigh BCLRITwoBitsMask:$i))>; +def : Pat<(and GPR:$r, BCLRIANDIMask:$i), + (BCLRI (ANDI GPR:$r, (BCLRIANDIMaskLow BCLRIANDIMask:$i)), + (BCLRITwoBitsMaskHigh BCLRIANDIMask:$i))>; } // There's no encoding for roli in the the 'B' extension as it can be diff --git a/llvm/test/CodeGen/RISCV/rv32zbs.ll b/llvm/test/CodeGen/RISCV/rv32zbs.ll --- a/llvm/test/CodeGen/RISCV/rv32zbs.ll +++ b/llvm/test/CodeGen/RISCV/rv32zbs.ll @@ -560,16 +560,14 @@ ; ; RV32IB-LABEL: sbclri_i32_large0: ; RV32IB: # %bb.0: -; RV32IB-NEXT: lui a1, 1044480 -; RV32IB-NEXT: addi a1, a1, -256 -; RV32IB-NEXT: and a0, a0, a1 +; RV32IB-NEXT: andi a0, a0, -256 +; RV32IB-NEXT: bclri a0, a0, 24 ; RV32IB-NEXT: ret ; ; RV32IBS-LABEL: sbclri_i32_large0: ; RV32IBS: # %bb.0: -; RV32IBS-NEXT: lui a1, 1044480 -; RV32IBS-NEXT: addi a1, a1, -256 -; RV32IBS-NEXT: and a0, a0, a1 +; RV32IBS-NEXT: andi a0, a0, -256 +; RV32IBS-NEXT: bclri a0, a0, 24 ; RV32IBS-NEXT: ret %and = and i32 %a, -16777472 ret i32 %and @@ -585,21 +583,65 @@ ; ; RV32IB-LABEL: sbclri_i32_large1: ; RV32IB: # %bb.0: -; RV32IB-NEXT: lui a1, 1044464 -; RV32IB-NEXT: addi a1, a1, -1 -; RV32IB-NEXT: and a0, a0, a1 +; RV32IB-NEXT: bclri a0, a0, 16 +; RV32IB-NEXT: bclri a0, a0, 24 ; RV32IB-NEXT: ret ; ; RV32IBS-LABEL: sbclri_i32_large1: ; RV32IBS: # %bb.0: -; RV32IBS-NEXT: lui a1, 1044464 -; RV32IBS-NEXT: addi a1, a1, -1 -; RV32IBS-NEXT: and a0, a0, a1 +; RV32IBS-NEXT: bclri a0, a0, 16 +; RV32IBS-NEXT: bclri a0, a0, 24 ; RV32IBS-NEXT: ret %and = and i32 %a, -16842753 ret i32 %and } +define i32 @sbclri_i32_large2(i32 %0) { +; RV32I-LABEL: sbclri_i32_large2: +; RV32I: # %bb.0: +; RV32I-NEXT: lui a1, 524288 +; RV32I-NEXT: addi a1, a1, -5 +; RV32I-NEXT: and a0, a0, a1 +; RV32I-NEXT: ret +; +; RV32IB-LABEL: sbclri_i32_large2: +; RV32IB: # %bb.0: +; RV32IB-NEXT: bclri a0, a0, 2 +; RV32IB-NEXT: bclri a0, a0, 31 +; RV32IB-NEXT: ret +; +; RV32IBS-LABEL: sbclri_i32_large2: +; RV32IBS: # %bb.0: +; RV32IBS-NEXT: bclri a0, a0, 2 +; RV32IBS-NEXT: bclri a0, a0, 31 +; RV32IBS-NEXT: ret + %2 = and i32 %0, 2147483643 + ret i32 %2 +} + +define i32 @sbclri_i32_large3(i32 %0) { +; RV32I-LABEL: sbclri_i32_large3: +; RV32I: # %bb.0: +; RV32I-NEXT: lui a1, 524288 +; RV32I-NEXT: addi a1, a1, -6 +; RV32I-NEXT: and a0, a0, a1 +; RV32I-NEXT: ret +; +; RV32IB-LABEL: sbclri_i32_large3: +; RV32IB: # %bb.0: +; RV32IB-NEXT: andi a0, a0, -6 +; RV32IB-NEXT: bclri a0, a0, 31 +; RV32IB-NEXT: ret +; +; RV32IBS-LABEL: sbclri_i32_large3: +; RV32IBS: # %bb.0: +; RV32IBS-NEXT: andi a0, a0, -6 +; RV32IBS-NEXT: bclri a0, a0, 31 +; RV32IBS-NEXT: ret + %2 = and i32 %0, 2147483642 + ret i32 %2 +} + define i32 @sbseti_i32_10(i32 %a) nounwind { ; RV32I-LABEL: sbseti_i32_10: ; RV32I: # %bb.0: diff --git a/llvm/test/CodeGen/RISCV/rv64zbs.ll b/llvm/test/CodeGen/RISCV/rv64zbs.ll --- a/llvm/test/CodeGen/RISCV/rv64zbs.ll +++ b/llvm/test/CodeGen/RISCV/rv64zbs.ll @@ -810,16 +810,14 @@ ; ; RV64IB-LABEL: sbclri_i64_large0: ; RV64IB: # %bb.0: -; RV64IB-NEXT: lui a1, 1044480 -; RV64IB-NEXT: addiw a1, a1, -256 -; RV64IB-NEXT: and a0, a0, a1 +; RV64IB-NEXT: andi a0, a0, -256 +; RV64IB-NEXT: bclri a0, a0, 24 ; RV64IB-NEXT: ret ; ; RV64IBS-LABEL: sbclri_i64_large0: ; RV64IBS: # %bb.0: -; RV64IBS-NEXT: lui a1, 1044480 -; RV64IBS-NEXT: addiw a1, a1, -256 -; RV64IBS-NEXT: and a0, a0, a1 +; RV64IBS-NEXT: andi a0, a0, -256 +; RV64IBS-NEXT: bclri a0, a0, 24 ; RV64IBS-NEXT: ret %and = and i64 %a, -16777472 ret i64 %and @@ -835,16 +833,14 @@ ; ; RV64IB-LABEL: sbclri_i64_large1: ; RV64IB: # %bb.0: -; RV64IB-NEXT: lui a1, 1044464 -; RV64IB-NEXT: addiw a1, a1, -1 -; RV64IB-NEXT: and a0, a0, a1 +; RV64IB-NEXT: bclri a0, a0, 16 +; RV64IB-NEXT: bclri a0, a0, 24 ; RV64IB-NEXT: ret ; ; RV64IBS-LABEL: sbclri_i64_large1: ; RV64IBS: # %bb.0: -; RV64IBS-NEXT: lui a1, 1044464 -; RV64IBS-NEXT: addiw a1, a1, -1 -; RV64IBS-NEXT: and a0, a0, a1 +; RV64IBS-NEXT: bclri a0, a0, 16 +; RV64IBS-NEXT: bclri a0, a0, 24 ; RV64IBS-NEXT: ret %and = and i64 %a, -16842753 ret i64 %and