Skip to content

Commit d6d26c7

Browse files
committed
[TargetLowering] Change subtraction to do (LHS < RHS) XOR (RESULT < 0)
Taking inspiration from the way ARM detects overflow, we should check the LHS and RHS as well as the difference when detecting subtraction.
1 parent 837b2d4 commit d6d26c7

23 files changed

+3079
-3355
lines changed

llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8874,18 +8874,24 @@ LegalizerHelper::lowerSADDO_SSUBO(MachineInstr &MI) {
88748874

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

8877-
// For an addition, the result should be less than one of the operands (LHS)
8878-
// if and only if the other operand (RHS) is negative, otherwise there will
8879-
// be overflow.
8880-
// For a subtraction, the result should be less than one of the operands
8881-
// (LHS) if and only if the other operand (RHS) is (non-zero) positive,
8882-
// otherwise there will be overflow.
8883-
auto ResultLowerThanLHS =
8884-
MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, NewDst0, LHS);
8885-
auto ConditionRHS = MIRBuilder.buildICmp(
8886-
IsAdd ? CmpInst::ICMP_SLT : CmpInst::ICMP_SGT, BoolTy, RHS, Zero);
8887-
8888-
MIRBuilder.buildXor(Dst1, ConditionRHS, ResultLowerThanLHS);
8877+
if (IsAdd) {
8878+
// For addition, the result should be less than one of the operands (LHS)
8879+
// if and only if the other operand (RHS) is negative, otherwise there will
8880+
// be overflow.
8881+
auto ResultLowerThanLHS =
8882+
MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, NewDst0, LHS);
8883+
auto RHSNegative =
8884+
MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, RHS, Zero);
8885+
MIRBuilder.buildXor(Dst1, RHSNegative, ResultLowerThanLHS);
8886+
} else {
8887+
// For subtraction, overflow occurs when the signed comparison of operands
8888+
// doesn't match the sign of the result
8889+
auto LHSLessThanRHS =
8890+
MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, LHS, RHS);
8891+
auto ResultNegative =
8892+
MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, NewDst0, Zero);
8893+
MIRBuilder.buildXor(Dst1, LHSLessThanRHS, ResultNegative);
8894+
}
88898895

88908896
MIRBuilder.buildCopy(Dst0, NewDst0);
88918897
MI.eraseFromParent();

llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11441,19 +11441,25 @@ void TargetLowering::expandSADDSUBO(
1144111441

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

11444-
// For an addition, the result should be less than one of the operands (LHS)
11445-
// if and only if the other operand (RHS) is negative, otherwise there will
11446-
// be overflow.
11447-
// For a subtraction, the result should be less than one of the operands
11448-
// (LHS) if and only if the other operand (RHS) is (non-zero) positive,
11449-
// otherwise there will be overflow.
11450-
SDValue ResultLowerThanLHS = DAG.getSetCC(dl, OType, Result, LHS, ISD::SETLT);
11451-
SDValue ConditionRHS =
11452-
DAG.getSetCC(dl, OType, RHS, Zero, IsAdd ? ISD::SETLT : ISD::SETGT);
11453-
11454-
Overflow = DAG.getBoolExtOrTrunc(
11455-
DAG.getNode(ISD::XOR, dl, OType, ConditionRHS, ResultLowerThanLHS), dl,
11456-
ResultType, ResultType);
11444+
if (IsAdd) {
11445+
// For addition, the result should be less than one of the operands (LHS)
11446+
// if and only if the other operand (RHS) is negative, otherwise there will
11447+
// be overflow.
11448+
SDValue ResultLowerThanLHS =
11449+
DAG.getSetCC(dl, OType, Result, LHS, ISD::SETLT);
11450+
SDValue ConditionRHS = DAG.getSetCC(dl, OType, RHS, Zero, ISD::SETLT);
11451+
Overflow = DAG.getBoolExtOrTrunc(
11452+
DAG.getNode(ISD::XOR, dl, OType, ConditionRHS, ResultLowerThanLHS), dl,
11453+
ResultType, ResultType);
11454+
} else {
11455+
// For subtraction, overflow occurs when the signed comparison of operands
11456+
// doesn't match the sign of the result
11457+
SDValue LHSLessThanRHS = DAG.getSetCC(dl, OType, LHS, RHS, ISD::SETLT);
11458+
SDValue ResultNegative = DAG.getSetCC(dl, OType, Result, Zero, ISD::SETLT);
11459+
Overflow = DAG.getBoolExtOrTrunc(
11460+
DAG.getNode(ISD::XOR, dl, OType, LHSLessThanRHS, ResultNegative), dl,
11461+
ResultType, ResultType);
11462+
}
1145711463
}
1145811464

1145911465
bool TargetLowering::expandMULO(SDNode *Node, SDValue &Result,

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14497,6 +14497,35 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N,
1449714497
Results.push_back(customLegalizeToWOp(N, DAG, ExtOpc));
1449814498
break;
1449914499
}
14500+
case ISD::SSUBO: {
14501+
assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
14502+
"Unexpected custom legalisation");
14503+
14504+
// If the RHS is a constant, we can simplify the below. Otherwise
14505+
// use the default legalization.
14506+
if (!isa<ConstantSDNode>(N->getOperand(1)))
14507+
return;
14508+
14509+
SDValue LHS = DAG.getNode(ISD::SIGN_EXTEND, DL, MVT::i64, N->getOperand(0));
14510+
SDValue RHS = DAG.getNode(ISD::SIGN_EXTEND, DL, MVT::i64, N->getOperand(1));
14511+
SDValue Res = DAG.getNode(ISD::SUB, DL, MVT::i64, LHS, RHS);
14512+
Res = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i64, Res,
14513+
DAG.getValueType(MVT::i32));
14514+
14515+
SDValue Zero = DAG.getConstant(0, DL, MVT::i64);
14516+
14517+
// For subtraction, overflow occurs when the signed comparison of operands
14518+
// doesn't match the sign of the result
14519+
EVT OType = N->getValueType(1);
14520+
SDValue LHSLessThanRHS = DAG.getSetCC(DL, OType, LHS, RHS, ISD::SETLT);
14521+
SDValue ResultNegative = DAG.getSetCC(DL, OType, Res, Zero, ISD::SETLT);
14522+
SDValue Overflow =
14523+
DAG.getNode(ISD::XOR, DL, OType, LHSLessThanRHS, ResultNegative);
14524+
14525+
Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Res));
14526+
Results.push_back(Overflow);
14527+
return;
14528+
}
1450014529
case ISD::SADDO: {
1450114530
assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
1450214531
"Unexpected custom legalisation");

0 commit comments

Comments
 (0)