diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h --- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h +++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h @@ -86,6 +86,14 @@ return selectShiftMask(N, 32, ShAmt); } + bool selectCondOp(SDValue N, bool Inverse, SDValue &Val); + bool selectCondOp(SDValue N, SDValue &Val) { + return selectCondOp(N, /*Inverse*/ false, Val); + } + bool selectInverseCondOp(SDValue N, SDValue &Val) { + return selectCondOp(N, /*Inverse*/ true, Val); + } + bool selectSExtBits(SDValue N, unsigned Bits, SDValue &Val); template bool selectSExtBits(SDValue N, SDValue &Val) { return selectSExtBits(N, Bits, Val); diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp --- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp @@ -2423,6 +2423,72 @@ return true; } +/// Some instructions have a condition operand that is compared against zero. +/// Since RISC-V doesn't have seteq/setne instructions, we can use this +/// property to avoid a seqz or snez instruction after an xor/addi/xori. +/// When \p Inverse is false, we match seteq or any unknown operation. When +/// \p Inverse is true, we only match setne. +bool RISCVDAGToDAGISel::selectCondOp(SDValue N, bool Inverse, SDValue &Val) { + // Start with this node as the output. + Val = N; + + // If the node isn't a setcc, there's nothing we can do. Return success + // if we aren't looking for an inverse condition. + if (N->getOpcode() != ISD::SETCC) + return !Inverse; + + // If it isn't an equality comparison, we also can't do anything. + ISD::CondCode CCVal = cast(N->getOperand(2))->get(); + if (!isIntEqualitySetCC(CCVal)) + return !Inverse; + + // This ComplexPattern occurs in pairs with both polarities of Inverse. + // If this isn't the one we're looking for, let the other polarity match it. + if (isTrueWhenEqual(CCVal) != Inverse) + return false; + + SDValue LHS = N->getOperand(0); + SDValue RHS = N->getOperand(1); + + // If the RHS side is 0, we don't need any extra instructions, return the LHS. + if (isNullConstant(RHS)) { + Val = LHS; + return true; + } + + SDLoc DL(N); + + if (auto *C = dyn_cast(RHS)) { + int64_t CVal = C->getSExtValue(); + // If the RHS is -2048, we can use xori to produce 0 if the LHS is -2048 and + // non-zero otherwise. + if (CVal == -2048) { + Val = + SDValue(CurDAG->getMachineNode( + RISCV::XORI, DL, N->getValueType(0), LHS, + CurDAG->getTargetConstant(CVal, DL, N->getValueType(0))), + 0); + return true; + } + // If the RHS is [-2047,2048], we can use addi with -RHS to produce 0 if the + // LHS is equal to the RHS and non-zero otherwise. + if (isInt<12>(CVal) || CVal == 2048) { + Val = + SDValue(CurDAG->getMachineNode( + RISCV::ADDI, DL, N->getValueType(0), LHS, + CurDAG->getTargetConstant(-CVal, DL, N->getValueType(0))), + 0); + return true; + } + } + + // If nothing else we can XOR the LHS and RHS to produce zero if they are + // equal and a non-zero value if they aren't. + Val = SDValue( + CurDAG->getMachineNode(RISCV::XOR, DL, N->getValueType(0), LHS, RHS), 0); + return true; +} + bool RISCVDAGToDAGISel::selectSExtBits(SDValue N, unsigned Bits, SDValue &Val) { if (N.getOpcode() == ISD::SIGN_EXTEND_INREG && cast(N.getOperand(1))->getVT().getSizeInBits() == Bits) { diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -1870,6 +1870,15 @@ (AddiPairImmSmall AddiPair:$rs2))>; } +// Some instructions have a condition operand that is compared against zero. +// Since RISC-V doesn't have seteq/setne instructions, we can use this +// property to avoid a seqz or snez instruction after an xor/addi/xori. +// condop matches a setne or any unknown operation. +// invcondop only matches a seteq. +// This ComplexPatterns must be used in pairs. +def condop : ComplexPattern; +def invcondop : ComplexPattern; + /// Empty pseudo for RISCVInitUndefPass let hasSideEffects = 0, mayLoad = 0, mayStore = 0, Size = 0, isCodeGenOnly = 1 in { def PseudoRVVInitUndefM1 : Pseudo<(outs VR:$vd), (ins), [], "">; diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXVentana.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXVentana.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfoXVentana.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXVentana.td @@ -30,46 +30,14 @@ let Predicates = [IsRV64, HasVendorXVentanaCondOps] in { // Directly use MASKC/MASKCN in case of any of the operands being 0. -def : Pat<(select GPR:$rc, GPR:$rs1, (i64 0)), - (VT_MASKC $rs1, $rc)>; -def : Pat<(select GPR:$rc, (i64 0), GPR:$rs1), - (VT_MASKCN $rs1, $rc)>; - -def : Pat<(select (i64 (setne GPR:$rc, (i64 0))), GPR:$rs1, (i64 0)), - (VT_MASKC GPR:$rs1, GPR:$rc)>; -def : Pat<(select (i64 (seteq GPR:$rc, (i64 0))), GPR:$rs1, (i64 0)), - (VT_MASKCN GPR:$rs1, GPR:$rc)>; -def : Pat<(select (i64 (setne GPR:$rc, (i64 0))), (i64 0), GPR:$rs1), - (VT_MASKCN GPR:$rs1, GPR:$rc)>; -def : Pat<(select (i64 (seteq GPR:$rc, (i64 0))), (i64 0), GPR:$rs1), - (VT_MASKC GPR:$rs1, GPR:$rc)>; - -def : Pat<(select (i64 (setne GPR:$x, simm12_plus1:$y)), GPR:$rs1, (i64 0)), - (VT_MASKC GPR:$rs1, (ADDI GPR:$x, (NegImm simm12_plus1:$y)))>; -def : Pat<(select (i64 (seteq GPR:$x, simm12_plus1:$y)), GPR:$rs1, (i64 0)), - (VT_MASKCN GPR:$rs1, (ADDI GPR:$x, (NegImm simm12_plus1:$y)))>; -def : Pat<(select (i64 (setne GPR:$x, simm12_plus1:$y)), (i64 0), GPR:$rs1), - (VT_MASKCN GPR:$rs1, (ADDI GPR:$x, (NegImm simm12_plus1:$y)))>; -def : Pat<(select (i64 (seteq GPR:$x, simm12_plus1:$y)), (i64 0), GPR:$rs1), - (VT_MASKC GPR:$rs1, (ADDI GPR:$x, (NegImm simm12_plus1:$y)))>; - -def : Pat<(select (i64 (setne GPR:$x, (i64 -2048))), GPR:$rs1, (i64 0)), - (VT_MASKC GPR:$rs1, (XORI GPR:$x, -2048))>; -def : Pat<(select (i64 (seteq GPR:$x, (i64 -2048))), GPR:$rs1, (i64 0)), - (VT_MASKCN GPR:$rs1, (XORI GPR:$x, -2048))>; -def : Pat<(select (i64 (setne GPR:$x, (i64 -2048))), (i64 0), GPR:$rs1), - (VT_MASKCN GPR:$rs1, (XORI GPR:$x, -2048))>; -def : Pat<(select (i64 (seteq GPR:$x, (i64 -2048))), (i64 0), GPR:$rs1), - (VT_MASKC GPR:$rs1, (XORI GPR:$x, -2048))>; - -def : Pat<(select (i64 (setne GPR:$x, GPR:$y)), GPR:$rs1, (i64 0)), - (VT_MASKC GPR:$rs1, (XOR GPR:$x, GPR:$y))>; -def : Pat<(select (i64 (seteq GPR:$x, GPR:$y)), GPR:$rs1, (i64 0)), - (VT_MASKCN GPR:$rs1, (XOR GPR:$x, GPR:$y))>; -def : Pat<(select (i64 (setne GPR:$x, GPR:$y)), (i64 0), GPR:$rs1), - (VT_MASKCN GPR:$rs1, (XOR GPR:$x, GPR:$y))>; -def : Pat<(select (i64 (seteq GPR:$x, GPR:$y)), (i64 0), GPR:$rs1), - (VT_MASKC GPR:$rs1, (XOR GPR:$x, GPR:$y))>; +def : Pat<(select condop:$rc, GPR:$rs1, (i64 0)), + (VT_MASKC GPR:$rs1, condop:$rc)>; +def : Pat<(select invcondop:$rc, GPR:$rs1, (i64 0)), + (VT_MASKCN GPR:$rs1, invcondop:$rc)>; +def : Pat<(select condop:$rc, (i64 0), GPR:$rs1), + (VT_MASKCN GPR:$rs1, condop:$rc)>; +def : Pat<(select invcondop:$rc, (i64 0), GPR:$rs1), + (VT_MASKC GPR:$rs1, invcondop:$rc)>; // Conditional AND operation patterns. def : Pat<(i64 (select GPR:$rc, (and GPR:$rs1, GPR:$rs2), GPR:$rs1)),