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 @@ -2032,6 +2032,10 @@ virtual bool isProfitableToCombineMinNumMaxNum(EVT VT) const { return true; } + // For some targets, e.g., SystemZ, have instruction to perform such operation + // directly. + virtual bool isProfitableToConvertNegatedAbs(EVT VT) const { return false; } + /// Return true if a select of constants (select Cond, C1, C2) should be /// transformed into simple math ops with the condition value. For example: /// select Cond, C1, C1-1 --> add (zext Cond), C1-1 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 @@ -3209,6 +3209,20 @@ // 0 - X --> X if X is 0 or the minimum signed value. return N1; } + + // Convert 0 - abs(x) -> Y = sra (X, size(X)-1); sub (Y, xor (X, Y)). + if (N1->getOpcode() == ISD::ABS && + !TLI.isOperationLegalOrCustom(ISD::ABS, VT) && + TLI.isProfitableToConvertNegatedAbs(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); + } } // Canonicalize (sub -1, x) -> ~x, i.e. (xor x, -1) diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.h b/llvm/lib/Target/PowerPC/PPCISelLowering.h --- a/llvm/lib/Target/PowerPC/PPCISelLowering.h +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.h @@ -933,6 +933,8 @@ return true; } + bool isProfitableToConvertNegatedAbs(EVT VT) const override { return true; } + bool decomposeMulByConstant(LLVMContext &Context, EVT VT, SDValue C) const override; 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 @@ -9,9 +9,8 @@ ; CHECK-LE-LABEL: neg_abs: ; CHECK-LE: # %bb.0: ; CHECK-LE-NEXT: sradi r4, r3, 63 -; CHECK-LE-NEXT: add r3, r3, r4 ; CHECK-LE-NEXT: xor r3, r3, r4 -; CHECK-LE-NEXT: neg r3, r3 +; CHECK-LE-NEXT: sub r3, r4, r3 ; CHECK-LE-NEXT: blr %abs = tail call i64 @llvm.abs.i64(i64 %x, i1 true) %neg = sub nsw i64 0, %abs