Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,7 @@ namespace {

SDValue foldAddToAvg(SDNode *N, const SDLoc &DL);
SDValue foldSubToAvg(SDNode *N, const SDLoc &DL);
SDValue foldLogicSetCCToMul(SDNode *N, const SDLoc &DL);

SDValue SimplifyNodeWithTwoResults(SDNode *N, unsigned LoOp,
unsigned HiOp);
Expand Down Expand Up @@ -6648,6 +6649,61 @@ static unsigned getMinMaxOpcodeForFP(SDValue Operand1, SDValue Operand2,
return ISD::DELETED_NODE;
}

// Fold the following patterns for small integers in -Oz mode.
// (X == 0) || (Y == 0) --> (X * Y) == 0
// (X != 0) && (Y != 0) --> (X * Y) != 0
SDValue DAGCombiner::foldLogicSetCCToMul(SDNode *N, const SDLoc &DL) {
if (!DAG.getMachineFunction().getFunction().hasMinSize())
return SDValue();

unsigned Opcode = N->getOpcode();
SDValue N0 = N->getOperand(0);
SDValue N1 = N->getOperand(1);

ISD::CondCode ExpectedCC;
if (Opcode == ISD::OR) {
ExpectedCC = ISD::SETEQ;
} else if (Opcode == ISD::AND) {
ExpectedCC = ISD::SETNE;
} else {
return SDValue();
}

if (N0.getOpcode() != ISD::SETCC || N1.getOpcode() != ISD::SETCC)
return SDValue();

SDValue A = N0.getOperand(0);
SDValue B = N1.getOperand(0);
SDValue C0 = N0.getOperand(1);
SDValue C1 = N1.getOperand(1);
ISD::CondCode CC0 = cast<CondCodeSDNode>(N0.getOperand(2))->get();
ISD::CondCode CC1 = cast<CondCodeSDNode>(N1.getOperand(2))->get();

if (CC0 != ExpectedCC || CC1 != ExpectedCC ||
!A.getValueType().isScalarInteger() ||
A.getValueType() != B.getValueType() || !isNullConstant(C0) ||
!isNullConstant(C1))
return SDValue();

const TargetLowering &TLI = DAG.getTargetLoweringInfo();
if (!TLI.isOperationLegalOrCustom(ISD::MUL, A.getValueType()))
return SDValue();

unsigned BitWidth = A.getValueSizeInBits();
KnownBits KnownA = DAG.computeKnownBits(A);
KnownBits KnownB = DAG.computeKnownBits(B);

if (KnownA.countMaxActiveBits() + KnownB.countMaxActiveBits() > BitWidth)
return SDValue();

SDNodeFlags Flags;
Flags.setNoUnsignedWrap(true);

SDValue Mul = DAG.getNode(ISD::MUL, DL, A.getValueType(), A, B, Flags);

return DAG.getSetCC(DL, N->getValueType(0), Mul, C0, ExpectedCC);
}

static SDValue foldAndOrOfSETCC(SDNode *LogicOp, SelectionDAG &DAG) {
using AndOrSETCCFoldKind = TargetLowering::AndOrSETCCFoldKind;
assert(
Expand Down Expand Up @@ -7555,6 +7611,9 @@ SDValue DAGCombiner::visitAND(SDNode *N) {
if (N1C && DAG.MaskedValueIsZero(SDValue(N, 0), APInt::getAllOnes(BitWidth)))
return DAG.getConstant(0, DL, VT);

if (SDValue R = foldLogicSetCCToMul(N, DL))
return R;

if (SDValue R = foldAndOrOfSETCC(N, DAG))
return R;

Expand Down Expand Up @@ -8520,6 +8579,9 @@ SDValue DAGCombiner::visitOR(SDNode *N) {
if (N1C && DAG.MaskedValueIsZero(N0, ~N1C->getAPIntValue()))
return N1;

if (SDValue R = foldLogicSetCCToMul(N, DL))
return R;

if (SDValue R = foldAndOrOfSETCC(N, DAG))
return R;

Expand Down
131 changes: 131 additions & 0 deletions llvm/test/CodeGen/RISCV/fold-zero-check-minsize.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=riscv64 -mattr=+m -enable-machine-outliner=never < %s | FileCheck %s

define i1 @fold_or_eq_zero_i16(i16 zeroext %a, i16 zeroext %b) minsize {
; CHECK-LABEL: fold_or_eq_zero_i16:
; CHECK: # %bb.0:
; CHECK-NEXT: mul a0, a0, a1
; CHECK-NEXT: seqz a0, a0
; CHECK-NEXT: ret
entry:
%cmp1 = icmp eq i16 %a, 0
%cmp2 = icmp eq i16 %b, 0
%or = or i1 %cmp1, %cmp2
ret i1 %or
}

define i1 @fold_and_ne_zero_i16(i16 zeroext %a, i16 zeroext %b) minsize {
; CHECK-LABEL: fold_and_ne_zero_i16:
; CHECK: # %bb.0:
; CHECK-NEXT: mul a0, a0, a1
; CHECK-NEXT: snez a0, a0
; CHECK-NEXT: ret
entry:
%cmp1 = icmp ne i16 %a, 0
%cmp2 = icmp ne i16 %b, 0
%and = and i1 %cmp1, %cmp2
ret i1 %and
}

define i1 @negative_fold_potential_overflow_i64(i64 %a, i64 %b) minsize {
; CHECK-LABEL: negative_fold_potential_overflow_i64:
; CHECK: # %bb.0:
; CHECK-NEXT: seqz a0, a0
; CHECK-NEXT: seqz a1, a1
; CHECK-NEXT: or a0, a0, a1
; CHECK-NEXT: ret
entry:
%cmp1 = icmp eq i64 %a, 0
%cmp2 = icmp eq i64 %b, 0
%or = or i1 %cmp1, %cmp2
ret i1 %or
}

define i1 @negative_fold_no_minsize(i16 zeroext %a, i16 zeroext %b) {
; CHECK-LABEL: negative_fold_no_minsize:
; CHECK: # %bb.0:
; CHECK-NEXT: seqz a0, a0
; CHECK-NEXT: seqz a1, a1
; CHECK-NEXT: or a0, a0, a1
; CHECK-NEXT: ret
entry:
%cmp1 = icmp eq i16 %a, 0
%cmp2 = icmp eq i16 %b, 0
%or = or i1 %cmp1, %cmp2
ret i1 %or
}

define i1 @negative_fold_mismatched_predicates(i16 zeroext %a, i16 zeroext %b) minsize {
; CHECK-LABEL: negative_fold_mismatched_predicates:
; CHECK: # %bb.0:
; CHECK-NEXT: seqz a0, a0
; CHECK-NEXT: snez a1, a1
; CHECK-NEXT: or a0, a0, a1
; CHECK-NEXT: ret
entry:
%cmp1 = icmp eq i16 %a, 0
%cmp2 = icmp ne i16 %b, 0
%or = or i1 %cmp1, %cmp2
ret i1 %or
}

define i1 @negative_fold_lhs_nonzero_constant(i16 zeroext %a, i16 zeroext %b) minsize {
; CHECK-LABEL: negative_fold_lhs_nonzero_constant:
; CHECK: # %bb.0:
; CHECK-NEXT: addi a0, a0, -1
; CHECK-NEXT: seqz a0, a0
; CHECK-NEXT: seqz a1, a1
; CHECK-NEXT: or a0, a0, a1
; CHECK-NEXT: ret
entry:
%cmp1 = icmp eq i16 %a, 1;
%cmp2 = icmp eq i16 %b, 0
%or = or i1 %cmp1, %cmp2
ret i1 %or
}

define i1 @negative_fold_rhs_nonzero_constant(i16 zeroext %a, i16 zeroext %b) minsize {
; CHECK-LABEL: negative_fold_rhs_nonzero_constant:
; CHECK: # %bb.0:
; CHECK-NEXT: seqz a0, a0
; CHECK-NEXT: addi a1, a1, -1
; CHECK-NEXT: seqz a1, a1
; CHECK-NEXT: or a0, a0, a1
; CHECK-NEXT: ret
entry:
%cmp1 = icmp eq i16 %a, 0;
%cmp2 = icmp eq i16 %b, 1
%or = or i1 %cmp1, %cmp2
ret i1 %or
}

define i1 @negative_fold_type_mismatch(i16 zeroext %a, i32 signext %b) minsize {
; CHECK-LABEL: negative_fold_type_mismatch:
; CHECK: # %bb.0:
; CHECK-NEXT: seqz a0, a0
; CHECK-NEXT: seqz a1, a1
; CHECK-NEXT: or a0, a0, a1
; CHECK-NEXT: ret
entry:
%cmp1 = icmp eq i16 %a, 0
%cmp2 = icmp eq i32 %b, 0
%or = or i1 %cmp1, %cmp2
ret i1 %or
}

define i1 @fold_nsw_unsafe_proof(i8 zeroext %a, i8 zeroext %b) minsize {
; CHECK-LABEL: fold_nsw_unsafe_proof:
; CHECK: # %bb.0:
; CHECK-NEXT: andi a0, a0, 15
; CHECK-NEXT: andi a1, a1, 15
; CHECK-NEXT: mul a0, a0, a1
; CHECK-NEXT: seqz a0, a0
; CHECK-NEXT: ret
entry:
%a.masked = and i8 %a, 15
%b.masked = and i8 %b, 15
%cmp1 = icmp eq i8 %a.masked, 0
%cmp2 = icmp eq i8 %b.masked, 0
%or = or i1 %cmp1, %cmp2
ret i1 %or
}