// (sub x, (select cond, 0, c))
// -> (select cond, x, (sub x, c)) [AllOnes=0]
static SDValue combineSelectAndUse(SDNode *N, SDValue Slct, SDValue OtherOp,
- SelectionDAG &DAG, bool AllOnes) {
+ SelectionDAG &DAG, bool AllOnes,
+ const RISCVSubtarget &Subtarget) {
EVT VT = N->getValueType(0);
// Skip vectors.
if (VT.isVector())
return SDValue();
- if ((Slct.getOpcode() != ISD::SELECT &&
+ if (!Subtarget.hasShortForwardBranchOpt() ||
+ (Slct.getOpcode() != ISD::SELECT &&
Slct.getOpcode() != RISCVISD::SELECT_CC) ||
!Slct.hasOneUse())
return SDValue();
// Attempt combineSelectAndUse on each operand of a commutative operator N.
static SDValue combineSelectAndUseCommutative(SDNode *N, SelectionDAG &DAG,
- bool AllOnes) {
+ bool AllOnes,
+ const RISCVSubtarget &Subtarget) {
SDValue N0 = N->getOperand(0);
SDValue N1 = N->getOperand(1);
- if (SDValue Result = combineSelectAndUse(N, N0, N1, DAG, AllOnes))
+ if (SDValue Result = combineSelectAndUse(N, N0, N1, DAG, AllOnes, Subtarget))
return Result;
- if (SDValue Result = combineSelectAndUse(N, N1, N0, DAG, AllOnes))
+ if (SDValue Result = combineSelectAndUse(N, N1, N0, DAG, AllOnes, Subtarget))
return Result;
return SDValue();
}
return V;
// fold (add (select lhs, rhs, cc, 0, y), x) ->
// (select lhs, rhs, cc, x, (add x, y))
- return combineSelectAndUseCommutative(N, DAG, /*AllOnes*/ false);
+ return combineSelectAndUseCommutative(N, DAG, /*AllOnes*/ false, Subtarget);
}
// Try to turn a sub boolean RHS and constant LHS into an addi.
return DAG.getNode(ISD::ADD, DL, VT, NewLHS, NewRHS);
}
-static SDValue performSUBCombine(SDNode *N, SelectionDAG &DAG) {
+static SDValue performSUBCombine(SDNode *N, SelectionDAG &DAG,
+ const RISCVSubtarget &Subtarget) {
if (SDValue V = combineSubOfBoolean(N, DAG))
return V;
// (select lhs, rhs, cc, x, (sub x, y))
SDValue N0 = N->getOperand(0);
SDValue N1 = N->getOperand(1);
- return combineSelectAndUse(N, N1, N0, DAG, /*AllOnes*/ false);
+ return combineSelectAndUse(N, N1, N0, DAG, /*AllOnes*/ false, Subtarget);
}
// Apply DeMorgan's law to (and/or (xor X, 1), (xor Y, 1)) if X and Y are 0/1.
// fold (and (select lhs, rhs, cc, -1, y), x) ->
// (select lhs, rhs, cc, x, (and x, y))
- return combineSelectAndUseCommutative(N, DAG, /*AllOnes*/ true);
+ return combineSelectAndUseCommutative(N, DAG, /*AllOnes*/ true, Subtarget);
}
static SDValue performORCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI,
// fold (or (select cond, 0, y), x) ->
// (select cond, x, (or x, y))
- return combineSelectAndUseCommutative(N, DAG, /*AllOnes*/ false);
+ return combineSelectAndUseCommutative(N, DAG, /*AllOnes*/ false, Subtarget);
}
-static SDValue performXORCombine(SDNode *N, SelectionDAG &DAG) {
+static SDValue performXORCombine(SDNode *N, SelectionDAG &DAG,
+ const RISCVSubtarget &Subtarget) {
SDValue N0 = N->getOperand(0);
SDValue N1 = N->getOperand(1);
return V;
// fold (xor (select cond, 0, y), x) ->
// (select cond, x, (xor x, y))
- return combineSelectAndUseCommutative(N, DAG, /*AllOnes*/ false);
+ return combineSelectAndUseCommutative(N, DAG, /*AllOnes*/ false, Subtarget);
}
// Replace (seteq (i64 (and X, 0xffffffff)), C1) with
case ISD::ADD:
return performADDCombine(N, DAG, Subtarget);
case ISD::SUB:
- return performSUBCombine(N, DAG);
+ return performSUBCombine(N, DAG, Subtarget);
case ISD::AND:
return performANDCombine(N, DCI, Subtarget);
case ISD::OR:
return performORCombine(N, DCI, Subtarget);
case ISD::XOR:
- return performXORCombine(N, DAG);
+ return performXORCombine(N, DAG, Subtarget);
case ISD::FADD:
case ISD::UMAX:
case ISD::UMIN:
; RUN: | FileCheck -check-prefix=RV32I %s
; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefix=RV64I %s
+; RUN: llc -mtriple=riscv64 -mcpu=sifive-u74 -verify-machineinstrs < %s \
+; RUN: | FileCheck -check-prefix=SFB64 %s
; InstCombine canonicalizes (c ? x | y : x) to (x | (c ? y : 0)) similar for
; other binary operations using their identity value as the constant.
define signext i32 @and_select_all_ones_i32(i1 zeroext %c, i32 signext %x, i32 %y) {
; RV32I-LABEL: and_select_all_ones_i32:
; RV32I: # %bb.0:
-; RV32I-NEXT: beqz a0, .LBB0_2
-; RV32I-NEXT: # %bb.1:
-; RV32I-NEXT: and a2, a2, a1
-; RV32I-NEXT: .LBB0_2:
-; RV32I-NEXT: mv a0, a2
+; RV32I-NEXT: addi a0, a0, -1
+; RV32I-NEXT: or a0, a0, a1
+; RV32I-NEXT: and a0, a0, a2
; RV32I-NEXT: ret
;
; RV64I-LABEL: and_select_all_ones_i32:
; RV64I: # %bb.0:
-; RV64I-NEXT: beqz a0, .LBB0_2
-; RV64I-NEXT: # %bb.1:
-; RV64I-NEXT: and a2, a2, a1
-; RV64I-NEXT: .LBB0_2:
-; RV64I-NEXT: sext.w a0, a2
+; RV64I-NEXT: addi a0, a0, -1
+; RV64I-NEXT: or a0, a0, a1
+; RV64I-NEXT: and a0, a0, a2
+; RV64I-NEXT: sext.w a0, a0
; RV64I-NEXT: ret
+;
+; SFB64-LABEL: and_select_all_ones_i32:
+; SFB64: # %bb.0:
+; SFB64-NEXT: and a1, a1, a2
+; SFB64-NEXT: bnez a0, .LBB0_2
+; SFB64-NEXT: # %bb.1:
+; SFB64-NEXT: mv a1, a2
+; SFB64-NEXT: .LBB0_2:
+; SFB64-NEXT: sext.w a0, a1
+; SFB64-NEXT: ret
%a = select i1 %c, i32 %x, i32 -1
%b = and i32 %a, %y
ret i32 %b
define i64 @and_select_all_ones_i64(i1 zeroext %c, i64 %x, i64 %y) {
; RV32I-LABEL: and_select_all_ones_i64:
; RV32I: # %bb.0:
-; RV32I-NEXT: bnez a0, .LBB1_2
-; RV32I-NEXT: # %bb.1:
-; RV32I-NEXT: and a3, a3, a1
-; RV32I-NEXT: and a4, a4, a2
-; RV32I-NEXT: .LBB1_2:
-; RV32I-NEXT: mv a0, a3
-; RV32I-NEXT: mv a1, a4
+; RV32I-NEXT: neg a0, a0
+; RV32I-NEXT: or a2, a0, a2
+; RV32I-NEXT: or a0, a0, a1
+; RV32I-NEXT: and a0, a3, a0
+; RV32I-NEXT: and a1, a4, a2
; RV32I-NEXT: ret
;
; RV64I-LABEL: and_select_all_ones_i64:
; RV64I: # %bb.0:
-; RV64I-NEXT: bnez a0, .LBB1_2
-; RV64I-NEXT: # %bb.1:
-; RV64I-NEXT: and a2, a2, a1
-; RV64I-NEXT: .LBB1_2:
-; RV64I-NEXT: mv a0, a2
+; RV64I-NEXT: neg a0, a0
+; RV64I-NEXT: or a0, a0, a1
+; RV64I-NEXT: and a0, a2, a0
; RV64I-NEXT: ret
+;
+; SFB64-LABEL: and_select_all_ones_i64:
+; SFB64: # %bb.0:
+; SFB64-NEXT: and a1, a1, a2
+; SFB64-NEXT: beqz a0, .LBB1_2
+; SFB64-NEXT: # %bb.1:
+; SFB64-NEXT: mv a1, a2
+; SFB64-NEXT: .LBB1_2:
+; SFB64-NEXT: mv a0, a1
+; SFB64-NEXT: ret
%a = select i1 %c, i64 -1, i64 %x
%b = and i64 %y, %a
ret i64 %b
; RV32I: # %bb.0:
; RV32I-NEXT: neg a0, a0
; RV32I-NEXT: and a0, a0, a1
-; RV32I-NEXT: or a0, a0, a2
+; RV32I-NEXT: or a0, a2, a0
; RV32I-NEXT: ret
;
; RV64I-LABEL: or_select_all_zeros_i32:
; RV64I: # %bb.0:
; RV64I-NEXT: neg a0, a0
; RV64I-NEXT: and a0, a0, a1
-; RV64I-NEXT: or a0, a0, a2
+; RV64I-NEXT: or a0, a2, a0
; RV64I-NEXT: ret
+;
+; SFB64-LABEL: or_select_all_zeros_i32:
+; SFB64: # %bb.0:
+; SFB64-NEXT: or a1, a1, a2
+; SFB64-NEXT: bnez a0, .LBB2_2
+; SFB64-NEXT: # %bb.1:
+; SFB64-NEXT: mv a1, a2
+; SFB64-NEXT: .LBB2_2:
+; SFB64-NEXT: mv a0, a1
+; SFB64-NEXT: ret
%a = select i1 %c, i32 %x, i32 0
%b = or i32 %y, %a
ret i32 %b
define i64 @or_select_all_zeros_i64(i1 zeroext %c, i64 %x, i64 %y) {
; RV32I-LABEL: or_select_all_zeros_i64:
; RV32I: # %bb.0:
-; RV32I-NEXT: bnez a0, .LBB3_2
-; RV32I-NEXT: # %bb.1:
-; RV32I-NEXT: or a3, a3, a1
-; RV32I-NEXT: or a4, a4, a2
-; RV32I-NEXT: .LBB3_2:
-; RV32I-NEXT: mv a0, a3
-; RV32I-NEXT: mv a1, a4
+; RV32I-NEXT: addi a0, a0, -1
+; RV32I-NEXT: and a2, a0, a2
+; RV32I-NEXT: and a0, a0, a1
+; RV32I-NEXT: or a0, a0, a3
+; RV32I-NEXT: or a1, a2, a4
; RV32I-NEXT: ret
;
; RV64I-LABEL: or_select_all_zeros_i64:
; RV64I: # %bb.0:
-; RV64I-NEXT: bnez a0, .LBB3_2
-; RV64I-NEXT: # %bb.1:
-; RV64I-NEXT: or a2, a2, a1
-; RV64I-NEXT: .LBB3_2:
-; RV64I-NEXT: mv a0, a2
+; RV64I-NEXT: addi a0, a0, -1
+; RV64I-NEXT: and a0, a0, a1
+; RV64I-NEXT: or a0, a0, a2
; RV64I-NEXT: ret
+;
+; SFB64-LABEL: or_select_all_zeros_i64:
+; SFB64: # %bb.0:
+; SFB64-NEXT: or a1, a1, a2
+; SFB64-NEXT: beqz a0, .LBB3_2
+; SFB64-NEXT: # %bb.1:
+; SFB64-NEXT: mv a1, a2
+; SFB64-NEXT: .LBB3_2:
+; SFB64-NEXT: mv a0, a1
+; SFB64-NEXT: ret
%a = select i1 %c, i64 0, i64 %x
%b = or i64 %a, %y
ret i64 %b
define signext i32 @xor_select_all_zeros_i32(i1 zeroext %c, i32 signext %x, i32 signext %y) {
; RV32I-LABEL: xor_select_all_zeros_i32:
; RV32I: # %bb.0:
-; RV32I-NEXT: bnez a0, .LBB4_2
-; RV32I-NEXT: # %bb.1:
-; RV32I-NEXT: xor a2, a2, a1
-; RV32I-NEXT: .LBB4_2:
-; RV32I-NEXT: mv a0, a2
+; RV32I-NEXT: addi a0, a0, -1
+; RV32I-NEXT: and a0, a0, a1
+; RV32I-NEXT: xor a0, a2, a0
; RV32I-NEXT: ret
;
; RV64I-LABEL: xor_select_all_zeros_i32:
; RV64I: # %bb.0:
-; RV64I-NEXT: bnez a0, .LBB4_2
-; RV64I-NEXT: # %bb.1:
-; RV64I-NEXT: xor a2, a2, a1
-; RV64I-NEXT: .LBB4_2:
-; RV64I-NEXT: mv a0, a2
+; RV64I-NEXT: addi a0, a0, -1
+; RV64I-NEXT: and a0, a0, a1
+; RV64I-NEXT: xor a0, a2, a0
; RV64I-NEXT: ret
+;
+; SFB64-LABEL: xor_select_all_zeros_i32:
+; SFB64: # %bb.0:
+; SFB64-NEXT: xor a1, a1, a2
+; SFB64-NEXT: beqz a0, .LBB4_2
+; SFB64-NEXT: # %bb.1:
+; SFB64-NEXT: mv a1, a2
+; SFB64-NEXT: .LBB4_2:
+; SFB64-NEXT: mv a0, a1
+; SFB64-NEXT: ret
%a = select i1 %c, i32 0, i32 %x
%b = xor i32 %y, %a
ret i32 %b
define i64 @xor_select_all_zeros_i64(i1 zeroext %c, i64 %x, i64 %y) {
; RV32I-LABEL: xor_select_all_zeros_i64:
; RV32I: # %bb.0:
-; RV32I-NEXT: neg a5, a0
-; RV32I-NEXT: and a0, a5, a1
+; RV32I-NEXT: neg a0, a0
+; RV32I-NEXT: and a2, a0, a2
+; RV32I-NEXT: and a0, a0, a1
; RV32I-NEXT: xor a0, a0, a3
-; RV32I-NEXT: and a1, a5, a2
-; RV32I-NEXT: xor a1, a1, a4
+; RV32I-NEXT: xor a1, a2, a4
; RV32I-NEXT: ret
;
; RV64I-LABEL: xor_select_all_zeros_i64:
; RV64I-NEXT: and a0, a0, a1
; RV64I-NEXT: xor a0, a0, a2
; RV64I-NEXT: ret
+;
+; SFB64-LABEL: xor_select_all_zeros_i64:
+; SFB64: # %bb.0:
+; SFB64-NEXT: xor a1, a1, a2
+; SFB64-NEXT: bnez a0, .LBB5_2
+; SFB64-NEXT: # %bb.1:
+; SFB64-NEXT: mv a1, a2
+; SFB64-NEXT: .LBB5_2:
+; SFB64-NEXT: mv a0, a1
+; SFB64-NEXT: ret
%a = select i1 %c, i64 %x, i64 0
%b = xor i64 %a, %y
ret i64 %b
define signext i32 @add_select_all_zeros_i32(i1 zeroext %c, i32 signext %x, i32 signext %y) {
; RV32I-LABEL: add_select_all_zeros_i32:
; RV32I: # %bb.0:
-; RV32I-NEXT: bnez a0, .LBB6_2
-; RV32I-NEXT: # %bb.1:
-; RV32I-NEXT: add a2, a2, a1
-; RV32I-NEXT: .LBB6_2:
-; RV32I-NEXT: mv a0, a2
+; RV32I-NEXT: addi a0, a0, -1
+; RV32I-NEXT: and a0, a0, a1
+; RV32I-NEXT: add a0, a2, a0
; RV32I-NEXT: ret
;
; RV64I-LABEL: add_select_all_zeros_i32:
; RV64I: # %bb.0:
-; RV64I-NEXT: bnez a0, .LBB6_2
-; RV64I-NEXT: # %bb.1:
-; RV64I-NEXT: addw a2, a2, a1
-; RV64I-NEXT: .LBB6_2:
-; RV64I-NEXT: mv a0, a2
+; RV64I-NEXT: addi a0, a0, -1
+; RV64I-NEXT: and a0, a0, a1
+; RV64I-NEXT: addw a0, a2, a0
; RV64I-NEXT: ret
+;
+; SFB64-LABEL: add_select_all_zeros_i32:
+; SFB64: # %bb.0:
+; SFB64-NEXT: addw a1, a1, a2
+; SFB64-NEXT: beqz a0, .LBB6_2
+; SFB64-NEXT: # %bb.1:
+; SFB64-NEXT: mv a1, a2
+; SFB64-NEXT: .LBB6_2:
+; SFB64-NEXT: mv a0, a1
+; SFB64-NEXT: ret
%a = select i1 %c, i32 0, i32 %x
%b = add i32 %y, %a
ret i32 %b
define i64 @add_select_all_zeros_i64(i1 zeroext %c, i64 %x, i64 %y) {
; RV32I-LABEL: add_select_all_zeros_i64:
; RV32I: # %bb.0:
-; RV32I-NEXT: beqz a0, .LBB7_2
-; RV32I-NEXT: # %bb.1:
-; RV32I-NEXT: add a2, a4, a2
-; RV32I-NEXT: add a1, a3, a1
-; RV32I-NEXT: sltu a4, a1, a3
-; RV32I-NEXT: add a4, a2, a4
-; RV32I-NEXT: mv a3, a1
-; RV32I-NEXT: .LBB7_2:
-; RV32I-NEXT: mv a0, a3
-; RV32I-NEXT: mv a1, a4
+; RV32I-NEXT: neg a0, a0
+; RV32I-NEXT: and a2, a0, a2
+; RV32I-NEXT: and a1, a0, a1
+; RV32I-NEXT: add a0, a1, a3
+; RV32I-NEXT: sltu a1, a0, a1
+; RV32I-NEXT: add a2, a2, a4
+; RV32I-NEXT: add a1, a2, a1
; RV32I-NEXT: ret
;
; RV64I-LABEL: add_select_all_zeros_i64:
; RV64I: # %bb.0:
-; RV64I-NEXT: beqz a0, .LBB7_2
-; RV64I-NEXT: # %bb.1:
-; RV64I-NEXT: add a2, a2, a1
-; RV64I-NEXT: .LBB7_2:
-; RV64I-NEXT: mv a0, a2
+; RV64I-NEXT: neg a0, a0
+; RV64I-NEXT: and a0, a0, a1
+; RV64I-NEXT: add a0, a0, a2
; RV64I-NEXT: ret
+;
+; SFB64-LABEL: add_select_all_zeros_i64:
+; SFB64: # %bb.0:
+; SFB64-NEXT: add a1, a1, a2
+; SFB64-NEXT: bnez a0, .LBB7_2
+; SFB64-NEXT: # %bb.1:
+; SFB64-NEXT: mv a1, a2
+; SFB64-NEXT: .LBB7_2:
+; SFB64-NEXT: mv a0, a1
+; SFB64-NEXT: ret
%a = select i1 %c, i64 %x, i64 0
%b = add i64 %a, %y
ret i64 %b
define signext i32 @sub_select_all_zeros_i32(i1 zeroext %c, i32 signext %x, i32 signext %y) {
; RV32I-LABEL: sub_select_all_zeros_i32:
; RV32I: # %bb.0:
-; RV32I-NEXT: bnez a0, .LBB8_2
-; RV32I-NEXT: # %bb.1:
-; RV32I-NEXT: sub a2, a2, a1
-; RV32I-NEXT: .LBB8_2:
-; RV32I-NEXT: mv a0, a2
+; RV32I-NEXT: addi a0, a0, -1
+; RV32I-NEXT: and a0, a0, a1
+; RV32I-NEXT: sub a0, a2, a0
; RV32I-NEXT: ret
;
; RV64I-LABEL: sub_select_all_zeros_i32:
; RV64I: # %bb.0:
-; RV64I-NEXT: bnez a0, .LBB8_2
-; RV64I-NEXT: # %bb.1:
-; RV64I-NEXT: subw a2, a2, a1
-; RV64I-NEXT: .LBB8_2:
-; RV64I-NEXT: mv a0, a2
+; RV64I-NEXT: addi a0, a0, -1
+; RV64I-NEXT: and a0, a0, a1
+; RV64I-NEXT: subw a0, a2, a0
; RV64I-NEXT: ret
+;
+; SFB64-LABEL: sub_select_all_zeros_i32:
+; SFB64: # %bb.0:
+; SFB64-NEXT: subw a1, a2, a1
+; SFB64-NEXT: beqz a0, .LBB8_2
+; SFB64-NEXT: # %bb.1:
+; SFB64-NEXT: mv a1, a2
+; SFB64-NEXT: .LBB8_2:
+; SFB64-NEXT: mv a0, a1
+; SFB64-NEXT: ret
%a = select i1 %c, i32 0, i32 %x
%b = sub i32 %y, %a
ret i32 %b
define i64 @sub_select_all_zeros_i64(i1 zeroext %c, i64 %x, i64 %y) {
; RV32I-LABEL: sub_select_all_zeros_i64:
; RV32I: # %bb.0:
-; RV32I-NEXT: beqz a0, .LBB9_2
-; RV32I-NEXT: # %bb.1:
-; RV32I-NEXT: sltu a0, a3, a1
+; RV32I-NEXT: neg a0, a0
+; RV32I-NEXT: and a2, a0, a2
+; RV32I-NEXT: and a0, a0, a1
+; RV32I-NEXT: sltu a1, a3, a0
; RV32I-NEXT: sub a4, a4, a2
-; RV32I-NEXT: sub a4, a4, a0
-; RV32I-NEXT: sub a3, a3, a1
-; RV32I-NEXT: .LBB9_2:
-; RV32I-NEXT: mv a0, a3
-; RV32I-NEXT: mv a1, a4
+; RV32I-NEXT: sub a1, a4, a1
+; RV32I-NEXT: sub a0, a3, a0
; RV32I-NEXT: ret
;
; RV64I-LABEL: sub_select_all_zeros_i64:
; RV64I: # %bb.0:
-; RV64I-NEXT: beqz a0, .LBB9_2
-; RV64I-NEXT: # %bb.1:
-; RV64I-NEXT: sub a2, a2, a1
-; RV64I-NEXT: .LBB9_2:
-; RV64I-NEXT: mv a0, a2
+; RV64I-NEXT: neg a0, a0
+; RV64I-NEXT: and a0, a0, a1
+; RV64I-NEXT: sub a0, a2, a0
; RV64I-NEXT: ret
+;
+; SFB64-LABEL: sub_select_all_zeros_i64:
+; SFB64: # %bb.0:
+; SFB64-NEXT: sub a1, a2, a1
+; SFB64-NEXT: bnez a0, .LBB9_2
+; SFB64-NEXT: # %bb.1:
+; SFB64-NEXT: mv a1, a2
+; SFB64-NEXT: .LBB9_2:
+; SFB64-NEXT: mv a0, a1
+; SFB64-NEXT: ret
%a = select i1 %c, i64 %x, i64 0
%b = sub i64 %y, %a
ret i64 %b