diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h --- a/llvm/include/llvm/CodeGen/TargetLowering.h +++ b/llvm/include/llvm/CodeGen/TargetLowering.h @@ -4393,8 +4393,10 @@ /// (ABS x) -> (XOR (ADD x, (SRA x, type_size)), (SRA x, type_size)) /// \param N Node to expand /// \param Result output after conversion + /// \param IsNegative indicate negated abs /// \returns True, if the expansion was successful, false otherwise - bool expandABS(SDNode *N, SDValue &Result, SelectionDAG &DAG) const; + bool expandABS(SDNode *N, SDValue &Result, SelectionDAG &DAG, + bool IsNegative = false) const; /// Turn load of vector type into a load of the individual elements. /// \param LD load to expand diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp --- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -3193,18 +3193,12 @@ return N1; } - // Convert 0 - abs(x) -> Y = sra (X, size(X)-1); sub (Y, xor (X, Y)). + // Convert 0 - abs(x). + SDValue Result; if (N1->getOpcode() == ISD::ABS && - !TLI.isOperationLegalOrCustom(ISD::ABS, VT)) { - SDValue X = N1->getOperand(0); - SDValue Shift = - DAG.getNode(ISD::SRA, DL, VT, X, - DAG.getConstant(BitWidth - 1, DL, getShiftAmountTy(VT))); - SDValue Xor = DAG.getNode(ISD::XOR, DL, VT, X, Shift); - AddToWorklist(Shift.getNode()); - AddToWorklist(Xor.getNode()); - return DAG.getNode(ISD::SUB, DL, VT, Shift, Xor); - } + !TLI.isOperationLegalOrCustom(ISD::ABS, VT) && + TLI.expandABS(N1.getNode(), Result, DAG, true)) + return Result; } // Canonicalize (sub -1, x) -> ~x, i.e. (xor x, -1) diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp --- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -6816,14 +6816,15 @@ } bool TargetLowering::expandABS(SDNode *N, SDValue &Result, - SelectionDAG &DAG) const { + SelectionDAG &DAG, bool IsNegative) const { SDLoc dl(N); EVT VT = N->getValueType(0); EVT ShVT = getShiftAmountTy(VT, DAG.getDataLayout()); SDValue Op = N->getOperand(0); // abs(x) -> smax(x,sub(0,x)) - if (isOperationLegal(ISD::SUB, VT) && isOperationLegal(ISD::SMAX, VT)) { + if (!IsNegative && isOperationLegal(ISD::SUB, VT) && + isOperationLegal(ISD::SMAX, VT)) { SDValue Zero = DAG.getConstant(0, dl, VT); Result = DAG.getNode(ISD::SMAX, dl, VT, Op, DAG.getNode(ISD::SUB, dl, VT, Zero, Op)); @@ -6831,24 +6832,42 @@ } // abs(x) -> umin(x,sub(0,x)) - if (isOperationLegal(ISD::SUB, VT) && isOperationLegal(ISD::UMIN, VT)) { + if (!IsNegative && isOperationLegal(ISD::SUB, VT) && + isOperationLegal(ISD::UMIN, VT)) { SDValue Zero = DAG.getConstant(0, dl, VT); Result = DAG.getNode(ISD::UMIN, dl, VT, Op, DAG.getNode(ISD::SUB, dl, VT, Zero, Op)); return true; } + // 0 - abs(x) -> smin(x, sub(0,x)) + if (IsNegative && isOperationLegal(ISD::SUB, VT) && + isOperationLegal(ISD::SMIN, VT)) { + SDValue Zero = DAG.getConstant(0, dl, VT); + Result = DAG.getNode(ISD::SMIN, dl, VT, Op, + DAG.getNode(ISD::SUB, dl, VT, Zero, Op)); + return true; + } + // Only expand vector types if we have the appropriate vector operations. - if (VT.isVector() && (!isOperationLegalOrCustom(ISD::SRA, VT) || - !isOperationLegalOrCustom(ISD::ADD, VT) || - !isOperationLegalOrCustomOrPromote(ISD::XOR, VT))) + if (VT.isVector() && + (!isOperationLegalOrCustom(ISD::SRA, VT) || + (!IsNegative && !isOperationLegalOrCustom(ISD::ADD, VT)) || + (IsNegative && !isOperationLegalOrCustom(ISD::SUB, VT)) || + !isOperationLegalOrCustomOrPromote(ISD::XOR, VT))) return false; SDValue Shift = DAG.getNode(ISD::SRA, dl, VT, Op, DAG.getConstant(VT.getScalarSizeInBits() - 1, dl, ShVT)); - SDValue Add = DAG.getNode(ISD::ADD, dl, VT, Op, Shift); - Result = DAG.getNode(ISD::XOR, dl, VT, Add, Shift); + if (!IsNegative) { + SDValue Add = DAG.getNode(ISD::ADD, dl, VT, Op, Shift); + Result = DAG.getNode(ISD::XOR, dl, VT, Add, Shift); + } else { + // 0 - abs(x) -> Y = sra (X, size(X)-1); sub (Y, xor (X, Y)) + SDValue Xor = DAG.getNode(ISD::XOR, dl, VT, Op, Shift); + Result = DAG.getNode(ISD::SUB, dl, VT, Shift, Xor); + } return true; } diff --git a/llvm/test/CodeGen/PowerPC/neg-abs.ll b/llvm/test/CodeGen/PowerPC/neg-abs.ll --- a/llvm/test/CodeGen/PowerPC/neg-abs.ll +++ b/llvm/test/CodeGen/PowerPC/neg-abs.ll @@ -24,13 +24,9 @@ define <2 x i64> @neg_abs_v2i64(<2 x i64> %0) { ; CHECK-LE-LABEL: neg_abs_v2i64: ; CHECK-LE: # %bb.0: -; CHECK-LE-NEXT: addis r3, r2, .LCPI1_0@toc@ha -; CHECK-LE-NEXT: addi r3, r3, .LCPI1_0@toc@l -; CHECK-LE-NEXT: lxvd2x vs0, 0, r3 -; CHECK-LE-NEXT: xxswapd vs35, vs0 -; CHECK-LE-NEXT: vsrad v3, v2, v3 -; CHECK-LE-NEXT: xxlxor vs34, vs34, vs35 -; CHECK-LE-NEXT: vsubudm v2, v3, v2 +; CHECK-LE-NEXT: xxlxor vs35, vs35, vs35 +; CHECK-LE-NEXT: vsubudm v3, v3, v2 +; CHECK-LE-NEXT: vminsd v2, v2, v3 ; CHECK-LE-NEXT: blr %abs = call <2 x i64> @llvm.abs.v2i64(<2 x i64> %0, i1 true) %neg.abs = sub <2 x i64> zeroinitializer, %abs @@ -40,12 +36,9 @@ define <4 x i32> @neg_abs_v4i32(<4 x i32> %0) { ; CHECK-LE-LABEL: neg_abs_v4i32: ; CHECK-LE: # %bb.0: -; CHECK-LE-NEXT: vspltisw v3, -16 -; CHECK-LE-NEXT: vspltisw v4, 15 -; CHECK-LE-NEXT: vsubuwm v3, v4, v3 -; CHECK-LE-NEXT: vsraw v3, v2, v3 -; CHECK-LE-NEXT: xxlxor vs34, vs34, vs35 -; CHECK-LE-NEXT: vsubuwm v2, v3, v2 +; CHECK-LE-NEXT: xxlxor vs35, vs35, vs35 +; CHECK-LE-NEXT: vsubuwm v3, v3, v2 +; CHECK-LE-NEXT: vminsw v2, v2, v3 ; CHECK-LE-NEXT: blr %abs = call <4 x i32> @llvm.abs.v4i32(<4 x i32> %0, i1 true) %neg.abs = sub <4 x i32> zeroinitializer, %abs @@ -55,10 +48,9 @@ define <8 x i16> @neg_abs_v8i16(<8 x i16> %0) { ; CHECK-LE-LABEL: neg_abs_v8i16: ; CHECK-LE: # %bb.0: -; CHECK-LE-NEXT: vspltish v3, 15 -; CHECK-LE-NEXT: vsrah v3, v2, v3 -; CHECK-LE-NEXT: xxlxor vs34, vs34, vs35 -; CHECK-LE-NEXT: vsubuhm v2, v3, v2 +; CHECK-LE-NEXT: xxlxor vs35, vs35, vs35 +; CHECK-LE-NEXT: vsubuhm v3, v3, v2 +; CHECK-LE-NEXT: vminsh v2, v2, v3 ; CHECK-LE-NEXT: blr %abs = call <8 x i16> @llvm.abs.v8i16(<8 x i16> %0, i1 true) %neg.abs = sub <8 x i16> zeroinitializer, %abs @@ -68,10 +60,9 @@ define <16 x i8> @neg_abs_v16i8(<16 x i8> %0) { ; CHECK-LE-LABEL: neg_abs_v16i8: ; CHECK-LE: # %bb.0: -; CHECK-LE-NEXT: vspltisb v3, 7 -; CHECK-LE-NEXT: vsrab v3, v2, v3 -; CHECK-LE-NEXT: xxlxor vs34, vs34, vs35 -; CHECK-LE-NEXT: vsububm v2, v3, v2 +; CHECK-LE-NEXT: xxlxor vs35, vs35, vs35 +; CHECK-LE-NEXT: vsububm v3, v3, v2 +; CHECK-LE-NEXT: vminsb v2, v2, v3 ; CHECK-LE-NEXT: blr %abs = call <16 x i8> @llvm.abs.v16i8(<16 x i8> %0, i1 true) %neg.abs = sub <16 x i8> zeroinitializer, %abs