[RISCV][SelectionDAG] Enable TargetLowering::hasBitTest for masks that fit in ANDI.

Modified DAGCombiner to pass the shift the bittest input and the shift amount
to hasBitTest. This matches the other call to hasBitTest in TargetLowering.h

This is an alternative to D122454.

Reviewed By: luismarques

Differential Revision: https://reviews.llvm.org/D122458
This commit is contained in:
Craig Topper 2022-03-28 12:33:53 -07:00
parent 382de90896
commit e68257fcee
6 changed files with 201 additions and 159 deletions

View File

@ -5927,6 +5927,9 @@ static SDValue combineShiftAnd1ToBitTest(SDNode *And, SelectionDAG &DAG) {
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<<C) == 0
SDLoc DL(And);
@ -6352,9 +6355,8 @@ SDValue DAGCombiner::visitAND(SDNode *N) {
if (SDValue Shifts = unfoldExtremeBitClearingToShifts(N))
return Shifts;
if (TLI.hasBitTest(N0, N1))
if (SDValue V = combineShiftAnd1ToBitTest(N, DAG))
return V;
if (SDValue V = combineShiftAnd1ToBitTest(N, DAG))
return V;
// Recognize the following pattern:
//

View File

@ -1245,6 +1245,12 @@ bool RISCVTargetLowering::hasAndNotCompare(SDValue Y) const {
!isa<ConstantSDNode>(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<ConstantSDNode>(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.

View File

@ -346,6 +346,7 @@ public:
bool isCheapToSpeculateCttz() const override;
bool isCheapToSpeculateCtlz() const override;
bool hasAndNotCompare(SDValue Y) const override;
bool hasBitTest(SDValue X, SDValue Y) const override;
bool shouldSinkOperands(Instruction *I,
SmallVectorImpl<Use *> &Ops) const override;
bool isFPImmLegal(const APFloat &Imm, EVT VT,

View File

@ -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
}

View File

@ -355,86 +355,6 @@ define i64 @bexti_i64(i64 %a) nounwind {
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:

View File

@ -438,82 +438,6 @@ define i64 @bexti_i64(i64 %a) nounwind {
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: