diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -252,6 +252,7 @@ setOperationAction({ISD::ADD, ISD::SUB, ISD::SHL, ISD::SRA, ISD::SRL}, MVT::i32, Custom); + setOperationAction(ISD::SADDO, MVT::i32, Custom); setOperationAction({ISD::UADDO, ISD::USUBO, ISD::UADDSAT, ISD::USUBSAT}, MVT::i32, Custom); } else { @@ -9033,6 +9034,39 @@ Results.push_back(customLegalizeToWOp(N, DAG, ExtOpc)); break; } + case ISD::SADDO: { + assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() && + "Unexpected custom legalisation"); + + // If the RHS is a constant, we can simplify ConditionRHS below. Otherwise + // use the default legalization. + if (!isa(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::ADD, 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 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. + EVT OType = N->getValueType(1); + SDValue ResultLowerThanLHS = DAG.getSetCC(DL, OType, Res, LHS, ISD::SETLT); + SDValue ConditionRHS = DAG.getSetCC(DL, OType, RHS, Zero, ISD::SETLT); + + SDValue Overflow = + DAG.getNode(ISD::XOR, DL, OType, ConditionRHS, ResultLowerThanLHS); + Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Res)); + Results.push_back(Overflow); + return; + } case ISD::UADDO: case ISD::USUBO: { assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() && diff --git a/llvm/test/CodeGen/RISCV/xaluo.ll b/llvm/test/CodeGen/RISCV/xaluo.ll --- a/llvm/test/CodeGen/RISCV/xaluo.ll +++ b/llvm/test/CodeGen/RISCV/xaluo.ll @@ -62,10 +62,8 @@ ; ; RV64-LABEL: saddo2.i32: ; RV64: # %bb.0: # %entry -; RV64-NEXT: addi a2, a0, 4 -; RV64-NEXT: addiw a0, a0, 4 -; RV64-NEXT: xor a0, a0, a2 -; RV64-NEXT: snez a0, a0 +; RV64-NEXT: addiw a2, a0, 4 +; RV64-NEXT: slt a0, a2, a0 ; RV64-NEXT: sw a2, 0(a1) ; RV64-NEXT: ret ; @@ -78,10 +76,8 @@ ; ; RV64ZBA-LABEL: saddo2.i32: ; RV64ZBA: # %bb.0: # %entry -; RV64ZBA-NEXT: addi a2, a0, 4 -; RV64ZBA-NEXT: addiw a0, a0, 4 -; RV64ZBA-NEXT: xor a0, a0, a2 -; RV64ZBA-NEXT: snez a0, a0 +; RV64ZBA-NEXT: addiw a2, a0, 4 +; RV64ZBA-NEXT: slt a0, a2, a0 ; RV64ZBA-NEXT: sw a2, 0(a1) ; RV64ZBA-NEXT: ret entry: @@ -104,10 +100,9 @@ ; ; RV64-LABEL: saddo3.i32: ; RV64: # %bb.0: # %entry -; RV64-NEXT: addi a2, a0, -4 -; RV64-NEXT: addiw a0, a0, -4 -; RV64-NEXT: xor a0, a0, a2 -; RV64-NEXT: snez a0, a0 +; RV64-NEXT: addiw a2, a0, -4 +; RV64-NEXT: slt a0, a2, a0 +; RV64-NEXT: xori a0, a0, 1 ; RV64-NEXT: sw a2, 0(a1) ; RV64-NEXT: ret ; @@ -121,10 +116,9 @@ ; ; RV64ZBA-LABEL: saddo3.i32: ; RV64ZBA: # %bb.0: # %entry -; RV64ZBA-NEXT: addi a2, a0, -4 -; RV64ZBA-NEXT: addiw a0, a0, -4 -; RV64ZBA-NEXT: xor a0, a0, a2 -; RV64ZBA-NEXT: snez a0, a0 +; RV64ZBA-NEXT: addiw a2, a0, -4 +; RV64ZBA-NEXT: slt a0, a2, a0 +; RV64ZBA-NEXT: xori a0, a0, 1 ; RV64ZBA-NEXT: sw a2, 0(a1) ; RV64ZBA-NEXT: ret entry: @@ -150,11 +144,9 @@ ; RV64: # %bb.0: # %entry ; RV64-NEXT: lui a2, 4096 ; RV64-NEXT: addiw a2, a2, -1 -; RV64-NEXT: add a3, a0, a2 -; RV64-NEXT: addw a0, a0, a2 -; RV64-NEXT: xor a0, a0, a3 -; RV64-NEXT: snez a0, a0 -; RV64-NEXT: sw a3, 0(a1) +; RV64-NEXT: addw a2, a0, a2 +; RV64-NEXT: slt a0, a2, a0 +; RV64-NEXT: sw a2, 0(a1) ; RV64-NEXT: ret ; ; RV32ZBA-LABEL: saddo4.i32: @@ -170,11 +162,9 @@ ; RV64ZBA: # %bb.0: # %entry ; RV64ZBA-NEXT: lui a2, 4096 ; RV64ZBA-NEXT: addiw a2, a2, -1 -; RV64ZBA-NEXT: add a3, a0, a2 -; RV64ZBA-NEXT: addw a0, a0, a2 -; RV64ZBA-NEXT: xor a0, a0, a3 -; RV64ZBA-NEXT: snez a0, a0 -; RV64ZBA-NEXT: sw a3, 0(a1) +; RV64ZBA-NEXT: addw a2, a0, a2 +; RV64ZBA-NEXT: slt a0, a2, a0 +; RV64ZBA-NEXT: sw a2, 0(a1) ; RV64ZBA-NEXT: ret entry: %t = call {i32, i1} @llvm.sadd.with.overflow.i32(i32 %v1, i32 16777215) @@ -594,10 +584,8 @@ ; ; RV64-LABEL: ssubo2.i32: ; RV64: # %bb.0: # %entry -; RV64-NEXT: addi a2, a0, 4 -; RV64-NEXT: addiw a0, a0, 4 -; RV64-NEXT: xor a0, a0, a2 -; RV64-NEXT: snez a0, a0 +; RV64-NEXT: addiw a2, a0, 4 +; RV64-NEXT: slt a0, a2, a0 ; RV64-NEXT: sw a2, 0(a1) ; RV64-NEXT: ret ; @@ -610,10 +598,8 @@ ; ; RV64ZBA-LABEL: ssubo2.i32: ; RV64ZBA: # %bb.0: # %entry -; RV64ZBA-NEXT: addi a2, a0, 4 -; RV64ZBA-NEXT: addiw a0, a0, 4 -; RV64ZBA-NEXT: xor a0, a0, a2 -; RV64ZBA-NEXT: snez a0, a0 +; RV64ZBA-NEXT: addiw a2, a0, 4 +; RV64ZBA-NEXT: slt a0, a2, a0 ; RV64ZBA-NEXT: sw a2, 0(a1) ; RV64ZBA-NEXT: ret entry: