diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -769,6 +769,16 @@ if (Value *V = lowerObjectSizeCall(II, DL, &TLI, /*MustSucceed=*/false)) return replaceInstUsesWith(CI, V); return nullptr; + case Intrinsic::abs: { + Value *IIOperand = II->getArgOperand(0); + // abs(-x) -> abs(x) + // TODO: Copy nsw if it was present on the neg? + Value *X; + if (match(IIOperand, m_Neg(m_Value(X)))) + return replaceOperand(*II, 0, X); + + break; + } case Intrinsic::bswap: { Value *IIOperand = II->getArgOperand(0); Value *X = nullptr; diff --git a/llvm/test/Transforms/InstCombine/abs-intrinsic.ll b/llvm/test/Transforms/InstCombine/abs-intrinsic.ll --- a/llvm/test/Transforms/InstCombine/abs-intrinsic.ll +++ b/llvm/test/Transforms/InstCombine/abs-intrinsic.ll @@ -165,3 +165,23 @@ %c2 = icmp sge <4 x i32> %abs, zeroinitializer ret <4 x i1> %c2 } + +define i32 @abs_of_neg(i32 %x) { +; CHECK-LABEL: @abs_of_neg( +; CHECK-NEXT: [[B:%.*]] = call i32 @llvm.abs.i32(i32 [[X:%.*]], i1 false) +; CHECK-NEXT: ret i32 [[B]] +; + %a = sub i32 0, %x + %b = call i32 @llvm.abs.i32(i32 %a, i1 false) + ret i32 %b +} + +define <4 x i32> @abs_of_neg_vec(<4 x i32> %x) { +; CHECK-LABEL: @abs_of_neg_vec( +; CHECK-NEXT: [[B:%.*]] = call <4 x i32> @llvm.abs.v4i32(<4 x i32> [[X:%.*]], i1 false) +; CHECK-NEXT: ret <4 x i32> [[B]] +; + %a = sub nsw <4 x i32> zeroinitializer, %x + %b = call <4 x i32> @llvm.abs.v4i32(<4 x i32> %a, i1 false) + ret <4 x i32> %b +}