Skip to content

[RISCV][GlobalISel][TargetLowering] Change SSUBO to do (LHS < RHS) XOR (RESULT < 0) #150872

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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
30 changes: 18 additions & 12 deletions llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8874,18 +8874,24 @@ LegalizerHelper::lowerSADDO_SSUBO(MachineInstr &MI) {

auto Zero = MIRBuilder.buildConstant(Ty, 0);

// For an addition, the result should be less than one of the operands (LHS)
// if and only if the other operand (RHS) is negative, otherwise there will
// be overflow.
// For a subtraction, the result should be less than one of the operands
// (LHS) if and only if the other operand (RHS) is (non-zero) positive,
// otherwise there will be overflow.
auto ResultLowerThanLHS =
MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, NewDst0, LHS);
auto ConditionRHS = MIRBuilder.buildICmp(
IsAdd ? CmpInst::ICMP_SLT : CmpInst::ICMP_SGT, BoolTy, RHS, Zero);

MIRBuilder.buildXor(Dst1, ConditionRHS, ResultLowerThanLHS);
if (IsAdd) {
// For addition, the result should be less than one of the operands (LHS)
// if and only if the other operand (RHS) is negative, otherwise there will
// be overflow.
auto ResultLowerThanLHS =
MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, NewDst0, LHS);
auto RHSNegative =
MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, RHS, Zero);
MIRBuilder.buildXor(Dst1, RHSNegative, ResultLowerThanLHS);
} else {
// For subtraction, overflow occurs when the signed comparison of operands
// doesn't match the sign of the result
auto LHSLessThanRHS =
MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, LHS, RHS);
auto ResultNegative =
MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, NewDst0, Zero);
MIRBuilder.buildXor(Dst1, LHSLessThanRHS, ResultNegative);
}

MIRBuilder.buildCopy(Dst0, NewDst0);
MI.eraseFromParent();
Expand Down
32 changes: 19 additions & 13 deletions llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11441,19 +11441,25 @@ void TargetLowering::expandSADDSUBO(

SDValue Zero = DAG.getConstant(0, dl, LHS.getValueType());

// For an addition, the result should be less than one of the operands (LHS)
// if and only if the other operand (RHS) is negative, otherwise there will
// be overflow.
// For a subtraction, the result should be less than one of the operands
// (LHS) if and only if the other operand (RHS) is (non-zero) positive,
// otherwise there will be overflow.
SDValue ResultLowerThanLHS = DAG.getSetCC(dl, OType, Result, LHS, ISD::SETLT);
SDValue ConditionRHS =
DAG.getSetCC(dl, OType, RHS, Zero, IsAdd ? ISD::SETLT : ISD::SETGT);

Overflow = DAG.getBoolExtOrTrunc(
DAG.getNode(ISD::XOR, dl, OType, ConditionRHS, ResultLowerThanLHS), dl,
ResultType, ResultType);
if (IsAdd) {
// For addition, the result should be less than one of the operands (LHS)
// if and only if the other operand (RHS) is negative, otherwise there will
// be overflow.
SDValue ResultLowerThanLHS =
DAG.getSetCC(dl, OType, Result, LHS, ISD::SETLT);
SDValue ConditionRHS = DAG.getSetCC(dl, OType, RHS, Zero, ISD::SETLT);
Overflow = DAG.getBoolExtOrTrunc(
DAG.getNode(ISD::XOR, dl, OType, ConditionRHS, ResultLowerThanLHS), dl,
ResultType, ResultType);
} else {
// For subtraction, overflow occurs when the signed comparison of operands
// doesn't match the sign of the result
SDValue LHSLessThanRHS = DAG.getSetCC(dl, OType, LHS, RHS, ISD::SETLT);
SDValue ResultNegative = DAG.getSetCC(dl, OType, Result, Zero, ISD::SETLT);
Overflow = DAG.getBoolExtOrTrunc(
DAG.getNode(ISD::XOR, dl, OType, LHSLessThanRHS, ResultNegative), dl,
ResultType, ResultType);
}
}

bool TargetLowering::expandMULO(SDNode *Node, SDValue &Result,
Expand Down
29 changes: 29 additions & 0 deletions llvm/lib/Target/RISCV/RISCVISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14497,6 +14497,35 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N,
Results.push_back(customLegalizeToWOp(N, DAG, ExtOpc));
break;
}
case ISD::SSUBO: {
assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
"Unexpected custom legalisation");

// If the RHS is a constant, we can simplify the below. Otherwise
// use the default legalization.
if (!isa<ConstantSDNode>(N->getOperand(1)))
return;

SDValue LHS = DAG.getNode(ISD::SIGN_EXTEND, DL, MVT::i64, N->getOperand(0));
SDValue RHS = DAG.getNode(ISD::SIGN_EXTEND, DL, MVT::i64, N->getOperand(1));
SDValue Res = DAG.getNode(ISD::SUB, DL, MVT::i64, LHS, RHS);
Res = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i64, Res,
DAG.getValueType(MVT::i32));

SDValue Zero = DAG.getConstant(0, DL, MVT::i64);

// For subtraction, overflow occurs when the signed comparison of operands
// doesn't match the sign of the result
EVT OType = N->getValueType(1);
SDValue LHSLessThanRHS = DAG.getSetCC(DL, OType, LHS, RHS, ISD::SETLT);
SDValue ResultNegative = DAG.getSetCC(DL, OType, Res, Zero, ISD::SETLT);
SDValue Overflow =
DAG.getNode(ISD::XOR, DL, OType, LHSLessThanRHS, ResultNegative);

Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Res));
Results.push_back(Overflow);
return;
}
case ISD::SADDO: {
assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
"Unexpected custom legalisation");
Expand Down
Loading