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 @@ -303,6 +303,9 @@ setOperationAction(ISD::CTTZ, XLenVT, Expand); setOperationAction(ISD::CTLZ, XLenVT, Expand); setOperationAction(ISD::CTPOP, XLenVT, Expand); + + if (Subtarget.is64Bit()) + setOperationAction(ISD::ABS, MVT::i32, Custom); } if (Subtarget.hasStdExtZbt()) { @@ -6622,6 +6625,34 @@ Results.push_back(expandAddSubSat(N, DAG)); return; } + case ISD::ABS: { + assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() && + "Unexpected custom legalisation"); + DAG.getNode(ISD::SIGN_EXTEND, DL, MVT::i64, N->getOperand(0)); + + // Expand abs to Y = (sraiw X, 31); subw(xor(X, Y), Y) + + SDValue Src = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(0)); + + // Freeze the source so we can increase it's use count. + Src = DAG.getFreeze(Src); + + // Copy sign bit to all bits using the sraiw pattern. + SDValue SignFill = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i64, Src, + DAG.getValueType(MVT::i32)); + SignFill = DAG.getNode(ISD::SRA, DL, MVT::i64, SignFill, + DAG.getConstant(31, DL, MVT::i64)); + + SDValue NewRes = DAG.getNode(ISD::XOR, DL, MVT::i64, Src, SignFill); + NewRes = DAG.getNode(ISD::SUB, DL, MVT::i64, NewRes, SignFill); + + // NOTE: The result is only required to be anyextended, but sext is + // consistent with type legalization of sub. + NewRes = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i64, NewRes, + DAG.getValueType(MVT::i32)); + Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, NewRes)); + return; + } case ISD::BITCAST: { EVT VT = N->getValueType(0); assert(VT.isInteger() && !VT.isVector() && "Unexpected VT!"); diff --git a/llvm/test/CodeGen/RISCV/neg-abs.ll b/llvm/test/CodeGen/RISCV/neg-abs.ll --- a/llvm/test/CodeGen/RISCV/neg-abs.ll +++ b/llvm/test/CodeGen/RISCV/neg-abs.ll @@ -255,15 +255,11 @@ ; ; RV64I-LABEL: neg_abs32_multiuse: ; RV64I: # %bb.0: -; RV64I-NEXT: sext.w a3, a0 ; RV64I-NEXT: sraiw a2, a0, 31 -; RV64I-NEXT: xor a4, a0, a2 -; RV64I-NEXT: subw a2, a2, a4 -; RV64I-NEXT: srai a3, a3, 63 -; RV64I-NEXT: xor a0, a0, a3 -; RV64I-NEXT: subw a0, a0, a3 -; RV64I-NEXT: sw a0, 0(a1) -; RV64I-NEXT: mv a0, a2 +; RV64I-NEXT: xor a3, a0, a2 +; RV64I-NEXT: subw a0, a2, a3 +; RV64I-NEXT: subw a2, a3, a2 +; RV64I-NEXT: sw a2, 0(a1) ; RV64I-NEXT: ret ; ; RV64ZBB-LABEL: neg_abs32_multiuse: @@ -279,15 +275,11 @@ ; ; RV64IBT-LABEL: neg_abs32_multiuse: ; RV64IBT: # %bb.0: -; RV64IBT-NEXT: sext.w a3, a0 ; RV64IBT-NEXT: sraiw a2, a0, 31 -; RV64IBT-NEXT: xor a4, a0, a2 -; RV64IBT-NEXT: subw a2, a2, a4 -; RV64IBT-NEXT: srai a3, a3, 63 -; RV64IBT-NEXT: xor a0, a0, a3 -; RV64IBT-NEXT: subw a0, a0, a3 -; RV64IBT-NEXT: sw a0, 0(a1) -; RV64IBT-NEXT: mv a0, a2 +; RV64IBT-NEXT: xor a3, a0, a2 +; RV64IBT-NEXT: subw a0, a2, a3 +; RV64IBT-NEXT: subw a2, a3, a2 +; RV64IBT-NEXT: sw a2, 0(a1) ; RV64IBT-NEXT: ret %abs = tail call i32 @llvm.abs.i32(i32 %x, i1 true) store i32 %abs, i32* %y diff --git a/llvm/test/CodeGen/RISCV/rv64zbb.ll b/llvm/test/CodeGen/RISCV/rv64zbb.ll --- a/llvm/test/CodeGen/RISCV/rv64zbb.ll +++ b/llvm/test/CodeGen/RISCV/rv64zbb.ll @@ -945,10 +945,9 @@ define i32 @abs_i32(i32 %x) { ; RV64I-LABEL: abs_i32: ; RV64I: # %bb.0: -; RV64I-NEXT: sext.w a0, a0 -; RV64I-NEXT: srai a1, a0, 63 +; RV64I-NEXT: sraiw a1, a0, 31 ; RV64I-NEXT: xor a0, a0, a1 -; RV64I-NEXT: sub a0, a0, a1 +; RV64I-NEXT: subw a0, a0, a1 ; RV64I-NEXT: ret ; ; RV64ZBB-LABEL: abs_i32: @@ -965,7 +964,7 @@ define signext i32 @abs_i32_sext(i32 signext %x) { ; RV64I-LABEL: abs_i32_sext: ; RV64I: # %bb.0: -; RV64I-NEXT: srai a1, a0, 63 +; RV64I-NEXT: sraiw a1, a0, 31 ; RV64I-NEXT: xor a0, a0, a1 ; RV64I-NEXT: subw a0, a0, a1 ; RV64I-NEXT: ret