Skip to content

Commit ffaa6f2

Browse files
authored
[RISCV] Custom legalize i32 saddo/ssubo on RV64 to return a sign extended value for the data result. (#172112)
This is consistent with how we handle regular ADD/SUB and helps with computeNumSignBits optimizations. Fixes #172089
1 parent 7fa062a commit ffaa6f2

File tree

5 files changed

+50
-45
lines changed

5 files changed

+50
-45
lines changed

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
358358
setOperationAction(
359359
{ISD::SADDSAT, ISD::SSUBSAT, ISD::UADDSAT, ISD::USUBSAT}, MVT::i32,
360360
Custom);
361-
setOperationAction(ISD::SADDO, MVT::i32, Custom);
361+
setOperationAction({ISD::SADDO, ISD::SSUBO}, MVT::i32, Custom);
362362
}
363363
if (!Subtarget.hasStdExtZmmul()) {
364364
setOperationAction({ISD::MUL, ISD::MULHS, ISD::MULHU}, XLenVT, Expand);
@@ -15060,35 +15060,42 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N,
1506015060
Results.push_back(customLegalizeToWOp(N, DAG, ExtOpc));
1506115061
break;
1506215062
}
15063-
case ISD::SADDO: {
15063+
case ISD::SADDO:
15064+
case ISD::SSUBO: {
1506415065
assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
1506515066
"Unexpected custom legalisation");
1506615067

15067-
// If the RHS is a constant, we can simplify ConditionRHS below. Otherwise
15068-
// use the default legalization.
15069-
if (!isa<ConstantSDNode>(N->getOperand(1)))
15070-
return;
15071-
15068+
// This is similar to the default legalization, but we return the
15069+
// sext_inreg instead of the add/sub.
15070+
bool IsAdd = N->getOpcode() == ISD::SADDO;
1507215071
SDValue LHS = DAG.getNode(ISD::SIGN_EXTEND, DL, MVT::i64, N->getOperand(0));
1507315072
SDValue RHS = DAG.getNode(ISD::SIGN_EXTEND, DL, MVT::i64, N->getOperand(1));
15074-
SDValue Res = DAG.getNode(ISD::ADD, DL, MVT::i64, LHS, RHS);
15075-
Res = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i64, Res,
15076-
DAG.getValueType(MVT::i32));
15073+
SDValue Op =
15074+
DAG.getNode(IsAdd ? ISD::ADD : ISD::SUB, DL, MVT::i64, LHS, RHS);
15075+
SDValue Res = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i64, Op,
15076+
DAG.getValueType(MVT::i32));
1507715077

15078-
SDValue Zero = DAG.getConstant(0, DL, MVT::i64);
15078+
SDValue Overflow;
1507915079

15080-
// For an addition, the result should be less than one of the operands (LHS)
15081-
// if and only if the other operand (RHS) is negative, otherwise there will
15082-
// be overflow.
15083-
// For a subtraction, the result should be less than one of the operands
15084-
// (LHS) if and only if the other operand (RHS) is (non-zero) positive,
15085-
// otherwise there will be overflow.
15086-
EVT OType = N->getValueType(1);
15087-
SDValue ResultLowerThanLHS = DAG.getSetCC(DL, OType, Res, LHS, ISD::SETLT);
15088-
SDValue ConditionRHS = DAG.getSetCC(DL, OType, RHS, Zero, ISD::SETLT);
15080+
// If the RHS is a constant, we can simplify ConditionRHS below. Otherwise
15081+
// use the default legalization.
15082+
if (IsAdd && isa<ConstantSDNode>(N->getOperand(1))) {
15083+
SDValue Zero = DAG.getConstant(0, DL, MVT::i64);
15084+
15085+
// For an addition, the result should be less than one of the operands
15086+
// (LHS) if and only if the other operand (RHS) is negative, otherwise
15087+
// there will be overflow.
15088+
EVT OType = N->getValueType(1);
15089+
SDValue ResultLowerThanLHS =
15090+
DAG.getSetCC(DL, OType, Res, LHS, ISD::SETLT);
15091+
SDValue ConditionRHS = DAG.getSetCC(DL, OType, RHS, Zero, ISD::SETLT);
15092+
15093+
Overflow =
15094+
DAG.getNode(ISD::XOR, DL, OType, ConditionRHS, ResultLowerThanLHS);
15095+
} else {
15096+
Overflow = DAG.getSetCC(DL, N->getValueType(1), Res, Op, ISD::SETNE);
15097+
}
1508915098

15090-
SDValue Overflow =
15091-
DAG.getNode(ISD::XOR, DL, OType, ConditionRHS, ResultLowerThanLHS);
1509215099
Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Res));
1509315100
Results.push_back(Overflow);
1509415101
return;

llvm/test/CodeGen/RISCV/sadd_sat.ll

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,15 @@ define signext i32 @func(i32 signext %x, i32 signext %y) nounwind {
2121
;
2222
; RV64I-LABEL: func:
2323
; RV64I: # %bb.0:
24-
; RV64I-NEXT: add a2, a0, a1
24+
; RV64I-NEXT: mv a2, a0
2525
; RV64I-NEXT: addw a0, a0, a1
26-
; RV64I-NEXT: beq a0, a2, .LBB0_2
26+
; RV64I-NEXT: add a1, a2, a1
27+
; RV64I-NEXT: beq a0, a1, .LBB0_2
2728
; RV64I-NEXT: # %bb.1:
28-
; RV64I-NEXT: srli a0, a0, 31
29-
; RV64I-NEXT: li a1, 1
30-
; RV64I-NEXT: slli a1, a1, 31
31-
; RV64I-NEXT: xor a2, a0, a1
29+
; RV64I-NEXT: sraiw a0, a1, 31
30+
; RV64I-NEXT: lui a1, 524288
31+
; RV64I-NEXT: xor a0, a0, a1
3232
; RV64I-NEXT: .LBB0_2:
33-
; RV64I-NEXT: sext.w a0, a2
3433
; RV64I-NEXT: ret
3534
;
3635
; RV64IZbb-LABEL: func:

llvm/test/CodeGen/RISCV/sadd_sat_plus.ll

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ define i32 @func32(i32 %x, i32 %y, i32 %z) nounwind {
2222
;
2323
; RV64I-LABEL: func32:
2424
; RV64I: # %bb.0:
25-
; RV64I-NEXT: sext.w a0, a0
2625
; RV64I-NEXT: mulw a1, a1, a2
27-
; RV64I-NEXT: addw a2, a0, a1
28-
; RV64I-NEXT: add a0, a0, a1
29-
; RV64I-NEXT: beq a2, a0, .LBB0_2
26+
; RV64I-NEXT: sext.w a2, a0
27+
; RV64I-NEXT: addw a0, a2, a1
28+
; RV64I-NEXT: add a1, a2, a1
29+
; RV64I-NEXT: beq a0, a1, .LBB0_2
3030
; RV64I-NEXT: # %bb.1:
31-
; RV64I-NEXT: sraiw a0, a0, 31
31+
; RV64I-NEXT: sraiw a0, a1, 31
3232
; RV64I-NEXT: lui a1, 524288
3333
; RV64I-NEXT: xor a0, a0, a1
3434
; RV64I-NEXT: .LBB0_2:

llvm/test/CodeGen/RISCV/ssub_sat.ll

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,15 @@ define signext i32 @func(i32 signext %x, i32 signext %y) nounwind {
2121
;
2222
; RV64I-LABEL: func:
2323
; RV64I: # %bb.0:
24-
; RV64I-NEXT: sub a2, a0, a1
24+
; RV64I-NEXT: mv a2, a0
2525
; RV64I-NEXT: subw a0, a0, a1
26+
; RV64I-NEXT: sub a2, a2, a1
2627
; RV64I-NEXT: beq a0, a2, .LBB0_2
2728
; RV64I-NEXT: # %bb.1:
28-
; RV64I-NEXT: srli a0, a0, 31
29-
; RV64I-NEXT: li a1, 1
30-
; RV64I-NEXT: slli a1, a1, 31
31-
; RV64I-NEXT: xor a2, a0, a1
29+
; RV64I-NEXT: sraiw a0, a2, 31
30+
; RV64I-NEXT: lui a1, 524288
31+
; RV64I-NEXT: xor a0, a0, a1
3232
; RV64I-NEXT: .LBB0_2:
33-
; RV64I-NEXT: sext.w a0, a2
3433
; RV64I-NEXT: ret
3534
;
3635
; RV64IZbb-LABEL: func:

llvm/test/CodeGen/RISCV/ssub_sat_plus.ll

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ define i32 @func32(i32 %x, i32 %y, i32 %z) nounwind {
2222
;
2323
; RV64I-LABEL: func32:
2424
; RV64I: # %bb.0:
25-
; RV64I-NEXT: sext.w a0, a0
2625
; RV64I-NEXT: mulw a1, a1, a2
27-
; RV64I-NEXT: subw a2, a0, a1
28-
; RV64I-NEXT: sub a0, a0, a1
29-
; RV64I-NEXT: beq a2, a0, .LBB0_2
26+
; RV64I-NEXT: sext.w a2, a0
27+
; RV64I-NEXT: subw a0, a2, a1
28+
; RV64I-NEXT: sub a1, a2, a1
29+
; RV64I-NEXT: beq a0, a1, .LBB0_2
3030
; RV64I-NEXT: # %bb.1:
31-
; RV64I-NEXT: sraiw a0, a0, 31
31+
; RV64I-NEXT: sraiw a0, a1, 31
3232
; RV64I-NEXT: lui a1, 524288
3333
; RV64I-NEXT: xor a0, a0, a1
3434
; RV64I-NEXT: .LBB0_2:

0 commit comments

Comments
 (0)