diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp --- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -5927,6 +5927,9 @@ if (ShiftAmt.uge(VTBitWidth)) return SDValue(); + if (!TLI.hasBitTest(Srl.getOperand(0), Srl.getOperand(1))) + return SDValue(); + // Turn this into a bit-test pattern using mask op + setcc: // and (not (srl X, C)), 1 --> (and X, 1< &Ops) const override; bool isFPImmLegal(const APFloat &Imm, EVT VT, diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -1245,6 +1245,12 @@ !isa(Y); } +bool RISCVTargetLowering::hasBitTest(SDValue X, SDValue Y) const { + // We can use ANDI+SEQZ/SNEZ as a bit test. Y contains the bit position. + auto *C = dyn_cast(Y); + return C && C->getAPIntValue().ule(10); +} + /// Check if sinking \p I's operands to I's basic block is profitable, because /// the operands can be folded into a target instruction, e.g. /// splats of scalars can fold into vector instructions. diff --git a/llvm/test/CodeGen/RISCV/bittest.ll b/llvm/test/CodeGen/RISCV/bittest.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/bittest.ll @@ -0,0 +1,189 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV64I +; RUN: llc -mtriple=riscv64 -mattr=+zbs -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV64ZBS + +define signext i32 @bittest_7_i32(i32 signext %a) nounwind { +; RV64I-LABEL: bittest_7_i32: +; RV64I: # %bb.0: +; RV64I-NEXT: andi a0, a0, 128 +; RV64I-NEXT: seqz a0, a0 +; RV64I-NEXT: ret +; +; RV64ZBS-LABEL: bittest_7_i32: +; RV64ZBS: # %bb.0: +; RV64ZBS-NEXT: andi a0, a0, 128 +; RV64ZBS-NEXT: seqz a0, a0 +; RV64ZBS-NEXT: ret + %shr = lshr i32 %a, 7 + %not = xor i32 %shr, -1 + %and = and i32 %not, 1 + ret i32 %and +} + +define signext i32 @bittest_10_i32(i32 signext %a) nounwind { +; RV64I-LABEL: bittest_10_i32: +; RV64I: # %bb.0: +; RV64I-NEXT: andi a0, a0, 1024 +; RV64I-NEXT: seqz a0, a0 +; RV64I-NEXT: ret +; +; RV64ZBS-LABEL: bittest_10_i32: +; RV64ZBS: # %bb.0: +; RV64ZBS-NEXT: andi a0, a0, 1024 +; RV64ZBS-NEXT: seqz a0, a0 +; RV64ZBS-NEXT: ret + %shr = lshr i32 %a, 10 + %not = xor i32 %shr, -1 + %and = and i32 %not, 1 + ret i32 %and +} + +define signext i32 @bittest_11_i32(i32 signext %a) nounwind { +; RV64I-LABEL: bittest_11_i32: +; RV64I: # %bb.0: +; RV64I-NEXT: srli a0, a0, 11 +; RV64I-NEXT: not a0, a0 +; RV64I-NEXT: andi a0, a0, 1 +; RV64I-NEXT: ret +; +; RV64ZBS-LABEL: bittest_11_i32: +; RV64ZBS: # %bb.0: +; RV64ZBS-NEXT: bexti a0, a0, 11 +; RV64ZBS-NEXT: xori a0, a0, 1 +; RV64ZBS-NEXT: ret + %shr = lshr i32 %a, 11 + %not = xor i32 %shr, -1 + %and = and i32 %not, 1 + ret i32 %and +} + +define signext i32 @bittest_31_i32(i32 signext %a) nounwind { +; RV64I-LABEL: bittest_31_i32: +; RV64I: # %bb.0: +; RV64I-NEXT: not a0, a0 +; RV64I-NEXT: srliw a0, a0, 31 +; RV64I-NEXT: ret +; +; RV64ZBS-LABEL: bittest_31_i32: +; RV64ZBS: # %bb.0: +; RV64ZBS-NEXT: not a0, a0 +; RV64ZBS-NEXT: srliw a0, a0, 31 +; RV64ZBS-NEXT: ret + %shr = lshr i32 %a, 31 + %not = xor i32 %shr, -1 + %and = and i32 %not, 1 + ret i32 %and +} + +define i64 @bittest_7_i64(i64 %a) nounwind { +; RV64I-LABEL: bittest_7_i64: +; RV64I: # %bb.0: +; RV64I-NEXT: andi a0, a0, 128 +; RV64I-NEXT: seqz a0, a0 +; RV64I-NEXT: ret +; +; RV64ZBS-LABEL: bittest_7_i64: +; RV64ZBS: # %bb.0: +; RV64ZBS-NEXT: andi a0, a0, 128 +; RV64ZBS-NEXT: seqz a0, a0 +; RV64ZBS-NEXT: ret + %shr = lshr i64 %a, 7 + %not = xor i64 %shr, -1 + %and = and i64 %not, 1 + ret i64 %and +} + +define i64 @bittest_10_i64(i64 %a) nounwind { +; RV64I-LABEL: bittest_10_i64: +; RV64I: # %bb.0: +; RV64I-NEXT: andi a0, a0, 1024 +; RV64I-NEXT: seqz a0, a0 +; RV64I-NEXT: ret +; +; RV64ZBS-LABEL: bittest_10_i64: +; RV64ZBS: # %bb.0: +; RV64ZBS-NEXT: andi a0, a0, 1024 +; RV64ZBS-NEXT: seqz a0, a0 +; RV64ZBS-NEXT: ret + %shr = lshr i64 %a, 10 + %not = xor i64 %shr, -1 + %and = and i64 %not, 1 + ret i64 %and +} + +define i64 @bittest_11_i64(i64 %a) nounwind { +; RV64I-LABEL: bittest_11_i64: +; RV64I: # %bb.0: +; RV64I-NEXT: srli a0, a0, 11 +; RV64I-NEXT: not a0, a0 +; RV64I-NEXT: andi a0, a0, 1 +; RV64I-NEXT: ret +; +; RV64ZBS-LABEL: bittest_11_i64: +; RV64ZBS: # %bb.0: +; RV64ZBS-NEXT: bexti a0, a0, 11 +; RV64ZBS-NEXT: xori a0, a0, 1 +; RV64ZBS-NEXT: ret + %shr = lshr i64 %a, 11 + %not = xor i64 %shr, -1 + %and = and i64 %not, 1 + ret i64 %and +} + +define i64 @bittest_31_i64(i64 %a) nounwind { +; RV64I-LABEL: bittest_31_i64: +; RV64I: # %bb.0: +; RV64I-NEXT: srli a0, a0, 31 +; RV64I-NEXT: not a0, a0 +; RV64I-NEXT: andi a0, a0, 1 +; RV64I-NEXT: ret +; +; RV64ZBS-LABEL: bittest_31_i64: +; RV64ZBS: # %bb.0: +; RV64ZBS-NEXT: bexti a0, a0, 31 +; RV64ZBS-NEXT: xori a0, a0, 1 +; RV64ZBS-NEXT: ret + %shr = lshr i64 %a, 31 + %not = xor i64 %shr, -1 + %and = and i64 %not, 1 + ret i64 %and +} + +define i64 @bittest_32_i64(i64 %a) nounwind { +; RV64I-LABEL: bittest_32_i64: +; RV64I: # %bb.0: +; RV64I-NEXT: srli a0, a0, 32 +; RV64I-NEXT: not a0, a0 +; RV64I-NEXT: andi a0, a0, 1 +; RV64I-NEXT: ret +; +; RV64ZBS-LABEL: bittest_32_i64: +; RV64ZBS: # %bb.0: +; RV64ZBS-NEXT: bexti a0, a0, 32 +; RV64ZBS-NEXT: xori a0, a0, 1 +; RV64ZBS-NEXT: ret + %shr = lshr i64 %a, 32 + %not = xor i64 %shr, -1 + %and = and i64 %not, 1 + ret i64 %and +} + +define i64 @bittest_63_i64(i64 %a) nounwind { +; RV64I-LABEL: bittest_63_i64: +; RV64I: # %bb.0: +; RV64I-NEXT: not a0, a0 +; RV64I-NEXT: srli a0, a0, 63 +; RV64I-NEXT: ret +; +; RV64ZBS-LABEL: bittest_63_i64: +; RV64ZBS: # %bb.0: +; RV64ZBS-NEXT: not a0, a0 +; RV64ZBS-NEXT: srli a0, a0, 63 +; RV64ZBS-NEXT: ret + %shr = lshr i64 %a, 63 + %not = xor i64 %shr, -1 + %and = and i64 %not, 1 + ret i64 %and +} 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 @@ -355,86 +355,6 @@ ret i64 %and } -define i32 @bexti_xor_i32(i32 %a) nounwind { -; RV32I-LABEL: bexti_xor_i32: -; RV32I: # %bb.0: -; RV32I-NEXT: srli a0, a0, 7 -; RV32I-NEXT: not a0, a0 -; RV32I-NEXT: andi a0, a0, 1 -; RV32I-NEXT: ret -; -; RV32ZBS-LABEL: bexti_xor_i32: -; RV32ZBS: # %bb.0: -; RV32ZBS-NEXT: bexti a0, a0, 7 -; RV32ZBS-NEXT: xori a0, a0, 1 -; RV32ZBS-NEXT: ret - %shr = lshr i32 %a, 7 - %not = xor i32 %shr, -1 - %and = and i32 %not, 1 - ret i32 %and -} - -define i64 @bexti_xor_i64(i64 %a) nounwind { -; RV32I-LABEL: bexti_xor_i64: -; RV32I: # %bb.0: -; RV32I-NEXT: srli a0, a0, 7 -; RV32I-NEXT: not a0, a0 -; RV32I-NEXT: andi a0, a0, 1 -; RV32I-NEXT: li a1, 0 -; RV32I-NEXT: ret -; -; RV32ZBS-LABEL: bexti_xor_i64: -; RV32ZBS: # %bb.0: -; RV32ZBS-NEXT: bexti a0, a0, 7 -; RV32ZBS-NEXT: xori a0, a0, 1 -; RV32ZBS-NEXT: li a1, 0 -; RV32ZBS-NEXT: ret - %shr = lshr i64 %a, 7 - %not = xor i64 %shr, -1 - %and = and i64 %not, 1 - ret i64 %and -} - -define i32 @bexti_xor_i32_1(i32 %a) nounwind { -; RV32I-LABEL: bexti_xor_i32_1: -; RV32I: # %bb.0: -; RV32I-NEXT: srli a0, a0, 7 -; RV32I-NEXT: not a0, a0 -; RV32I-NEXT: andi a0, a0, 1 -; RV32I-NEXT: ret -; -; RV32ZBS-LABEL: bexti_xor_i32_1: -; RV32ZBS: # %bb.0: -; RV32ZBS-NEXT: bexti a0, a0, 7 -; RV32ZBS-NEXT: xori a0, a0, 1 -; RV32ZBS-NEXT: ret - %shr = lshr i32 %a, 7 - %and = and i32 %shr, 1 - %xor = xor i32 %and, 1 - ret i32 %xor -} - -define i64 @bexti_xor_i64_1(i64 %a) nounwind { -; RV32I-LABEL: bexti_xor_i64_1: -; RV32I: # %bb.0: -; RV32I-NEXT: srli a0, a0, 7 -; RV32I-NEXT: not a0, a0 -; RV32I-NEXT: andi a0, a0, 1 -; RV32I-NEXT: li a1, 0 -; RV32I-NEXT: ret -; -; RV32ZBS-LABEL: bexti_xor_i64_1: -; RV32ZBS: # %bb.0: -; RV32ZBS-NEXT: bexti a0, a0, 7 -; RV32ZBS-NEXT: xori a0, a0, 1 -; RV32ZBS-NEXT: li a1, 0 -; RV32ZBS-NEXT: ret - %shr = lshr i64 %a, 7 - %and = and i64 %shr, 1 - %xor = xor i64 %and, 1 - ret i64 %xor -} - define i32 @bclri_i32_10(i32 %a) nounwind { ; RV32I-LABEL: bclri_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 @@ -438,82 +438,6 @@ ret i64 %and } -define signext i32 @bexti_xor_i32(i32 signext %a) nounwind { -; RV64I-LABEL: bexti_xor_i32: -; RV64I: # %bb.0: -; RV64I-NEXT: srli a0, a0, 7 -; RV64I-NEXT: not a0, a0 -; RV64I-NEXT: andi a0, a0, 1 -; RV64I-NEXT: ret -; -; RV64ZBS-LABEL: bexti_xor_i32: -; RV64ZBS: # %bb.0: -; RV64ZBS-NEXT: bexti a0, a0, 7 -; RV64ZBS-NEXT: xori a0, a0, 1 -; RV64ZBS-NEXT: ret - %shr = lshr i32 %a, 7 - %not = xor i32 %shr, -1 - %and = and i32 %not, 1 - ret i32 %and -} - -define i64 @bexti_xor_i64(i64 %a) nounwind { -; RV64I-LABEL: bexti_xor_i64: -; RV64I: # %bb.0: -; RV64I-NEXT: srli a0, a0, 7 -; RV64I-NEXT: not a0, a0 -; RV64I-NEXT: andi a0, a0, 1 -; RV64I-NEXT: ret -; -; RV64ZBS-LABEL: bexti_xor_i64: -; RV64ZBS: # %bb.0: -; RV64ZBS-NEXT: bexti a0, a0, 7 -; RV64ZBS-NEXT: xori a0, a0, 1 -; RV64ZBS-NEXT: ret - %shr = lshr i64 %a, 7 - %not = xor i64 %shr, -1 - %and = and i64 %not, 1 - ret i64 %and -} - -define signext i32 @bexti_xor_i32_1(i32 signext %a) nounwind { -; RV64I-LABEL: bexti_xor_i32_1: -; RV64I: # %bb.0: -; RV64I-NEXT: srli a0, a0, 7 -; RV64I-NEXT: not a0, a0 -; RV64I-NEXT: andi a0, a0, 1 -; RV64I-NEXT: ret -; -; RV64ZBS-LABEL: bexti_xor_i32_1: -; RV64ZBS: # %bb.0: -; RV64ZBS-NEXT: bexti a0, a0, 7 -; RV64ZBS-NEXT: xori a0, a0, 1 -; RV64ZBS-NEXT: ret - %shr = lshr i32 %a, 7 - %and = and i32 %shr, 1 - %xor = xor i32 %and, 1 - ret i32 %xor -} - -define i64 @bexti_xor_i64_1(i64 %a) nounwind { -; RV64I-LABEL: bexti_xor_i64_1: -; RV64I: # %bb.0: -; RV64I-NEXT: srli a0, a0, 7 -; RV64I-NEXT: not a0, a0 -; RV64I-NEXT: andi a0, a0, 1 -; RV64I-NEXT: ret -; -; RV64ZBS-LABEL: bexti_xor_i64_1: -; RV64ZBS: # %bb.0: -; RV64ZBS-NEXT: bexti a0, a0, 7 -; RV64ZBS-NEXT: xori a0, a0, 1 -; RV64ZBS-NEXT: ret - %shr = lshr i64 %a, 7 - %and = and i64 %shr, 1 - %xor = xor i64 %and, 1 - ret i64 %xor -} - define signext i32 @bclri_i32_10(i32 signext %a) nounwind { ; RV64I-LABEL: bclri_i32_10: ; RV64I: # %bb.0: