diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp index b55ed6647d3552..28a30090a00938 100644 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -1436,6 +1436,7 @@ bool llvm::canConstantFoldCallTo(const CallBase *Call, const Function *F) { case Intrinsic::launder_invariant_group: case Intrinsic::strip_invariant_group: case Intrinsic::masked_load: + case Intrinsic::abs: case Intrinsic::smax: case Intrinsic::smin: case Intrinsic::umax: @@ -2505,6 +2506,18 @@ static Constant *ConstantFoldScalarCall2(StringRef Name, return ConstantInt::get(Ty, C0->countTrailingZeros()); else return ConstantInt::get(Ty, C0->countLeadingZeros()); + + case Intrinsic::abs: + // Undef or minimum val operand with poison min --> undef + assert(C1 && "Must be constant int"); + if (C1->isOneValue() && (!C0 || C0->isMinSignedValue())) + return UndefValue::get(Ty); + + // Undef operand with no poison min --> 0 (sign bit must be clear) + if (C1->isNullValue() && !C0) + return Constant::getNullValue(Ty); + + return ConstantInt::get(Ty, C0->abs()); } return nullptr; diff --git a/llvm/test/Analysis/ConstantFolding/abs.ll b/llvm/test/Analysis/ConstantFolding/abs.ll index 24171b1d4c6e46..7b3a146e861433 100644 --- a/llvm/test/Analysis/ConstantFolding/abs.ll +++ b/llvm/test/Analysis/ConstantFolding/abs.ll @@ -6,8 +6,7 @@ declare <8 x i8> @llvm.abs.v8i8(<8 x i8>, i1) define i8 @undef_val_min_poison() { ; CHECK-LABEL: @undef_val_min_poison( -; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.abs.i8(i8 undef, i1 true) -; CHECK-NEXT: ret i8 [[R]] +; CHECK-NEXT: ret i8 undef ; %r = call i8 @llvm.abs.i8(i8 undef, i1 true) ret i8 %r @@ -15,8 +14,7 @@ define i8 @undef_val_min_poison() { define i8 @undef_val_min_not_poison() { ; CHECK-LABEL: @undef_val_min_not_poison( -; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.abs.i8(i8 undef, i1 false) -; CHECK-NEXT: ret i8 [[R]] +; CHECK-NEXT: ret i8 0 ; %r = call i8 @llvm.abs.i8(i8 undef, i1 false) ret i8 %r @@ -24,8 +22,7 @@ define i8 @undef_val_min_not_poison() { define i8 @min_val_min_poison() { ; CHECK-LABEL: @min_val_min_poison( -; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.abs.i8(i8 -128, i1 true) -; CHECK-NEXT: ret i8 [[R]] +; CHECK-NEXT: ret i8 undef ; %r = call i8 @llvm.abs.i8(i8 -128, i1 true) ret i8 %r @@ -33,8 +30,7 @@ define i8 @min_val_min_poison() { define i8 @min_val_min_not_poison() { ; CHECK-LABEL: @min_val_min_not_poison( -; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.abs.i8(i8 -128, i1 false) -; CHECK-NEXT: ret i8 [[R]] +; CHECK-NEXT: ret i8 -128 ; %r = call i8 @llvm.abs.i8(i8 -128, i1 false) ret i8 %r @@ -42,8 +38,7 @@ define i8 @min_val_min_not_poison() { define <8 x i8> @vec_const() { ; CHECK-LABEL: @vec_const( -; CHECK-NEXT: [[R:%.*]] = call <8 x i8> @llvm.abs.v8i8(<8 x i8> , i1 true) -; CHECK-NEXT: ret <8 x i8> [[R]] +; CHECK-NEXT: ret <8 x i8> ; %r = call <8 x i8> @llvm.abs.v8i8(<8 x i8> , i1 1) ret <8 x i8> %r