From f86c930cc96756f4d565f1746dca8cc42037b5ce Mon Sep 17 00:00:00 2001 From: "Kevin P. Neal" Date: Wed, 6 Oct 2021 13:49:24 -0400 Subject: [PATCH] [FPEnv][InstSimplify] Fold constrained X + -0.0 ==> X Currently the fadd optimizations in InstSimplify don't know how to do this "X + -0.0 ==> X" fold when using the constrained intrinsics. This adds the support. This commit is derived from D106362 with some improvements from D107285. Differential Revision: https://reviews.llvm.org/D111085 --- llvm/include/llvm/IR/FPEnv.h | 6 ++++++ llvm/lib/Analysis/InstructionSimplify.cpp | 20 +++++++++++++++---- .../Transforms/InstSimplify/strictfp-fadd.ll | 16 ++++++--------- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/llvm/include/llvm/IR/FPEnv.h b/llvm/include/llvm/IR/FPEnv.h index 621540000b5c..81c5f371e65a 100644 --- a/llvm/include/llvm/IR/FPEnv.h +++ b/llvm/include/llvm/IR/FPEnv.h @@ -58,5 +58,11 @@ Optional ExceptionBehaviorToStr(fp::ExceptionBehavior); inline bool isDefaultFPEnvironment(fp::ExceptionBehavior EB, RoundingMode RM) { return EB == fp::ebIgnore && RM == RoundingMode::NearestTiesToEven; } + +/// Returns true if the rounding mode RM may be QRM at compile time or +/// at run time. +inline bool canRoundingModeBe(RoundingMode RM, RoundingMode QRM) { + return RM == QRM || RM == RoundingMode::Dynamic; +} } #endif diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index 556250e527b0..0f114b50bf9c 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -4935,6 +4935,11 @@ static Constant *simplifyFPOp(ArrayRef Ops, FastMathFlags FMF, return nullptr; } +// TODO: Move this out to a header file: +static inline bool canIgnoreSNaN(fp::ExceptionBehavior EB, FastMathFlags FMF) { + return (EB == fp::ebIgnore || FMF.noNaNs()); +} + /// Given operands for an FAdd, see if we can fold the result. If not, this /// returns null. static Value * @@ -4949,13 +4954,20 @@ SimplifyFAddInst(Value *Op0, Value *Op1, FastMathFlags FMF, if (Constant *C = simplifyFPOp({Op0, Op1}, FMF, Q, ExBehavior, Rounding)) return C; + // fadd X, -0 ==> X + // With strict/constrained FP, we have these possible edge cases that do + // not simplify to Op0: + // fadd SNaN, -0.0 --> QNaN + // fadd +0.0, -0.0 --> -0.0 (but only with round toward negative) + if (canIgnoreSNaN(ExBehavior, FMF) && + (!canRoundingModeBe(Rounding, RoundingMode::TowardNegative) || + FMF.noSignedZeros())) + if (match(Op1, m_NegZeroFP())) + return Op0; + if (!isDefaultFPEnvironment(ExBehavior, Rounding)) return nullptr; - // fadd X, -0 ==> X - if (match(Op1, m_NegZeroFP())) - return Op0; - // fadd X, 0 ==> X, when we know X is not -0 if (match(Op1, m_PosZeroFP()) && (FMF.noSignedZeros() || CannotBeNegativeZero(Op0, Q.TLI))) diff --git a/llvm/test/Transforms/InstSimplify/strictfp-fadd.ll b/llvm/test/Transforms/InstSimplify/strictfp-fadd.ll index 8f917ba70854..0d836b6e7042 100644 --- a/llvm/test/Transforms/InstSimplify/strictfp-fadd.ll +++ b/llvm/test/Transforms/InstSimplify/strictfp-fadd.ll @@ -101,8 +101,7 @@ define <2 x float> @fadd_vec_x_n0_dynamic(<2 x float> %a) #0 { ; Test one of the remaining rounding modes and the rest will be fine. define float @fadd_x_n0_towardzero(float %a) #0 { ; CHECK-LABEL: @fadd_x_n0_towardzero( -; CHECK-NEXT: [[RET:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[A:%.*]], float -0.000000e+00, metadata !"round.towardzero", metadata !"fpexcept.ignore") #[[ATTR0]] -; CHECK-NEXT: ret float [[RET]] +; CHECK-NEXT: ret float [[A:%.*]] ; %ret = call float @llvm.experimental.constrained.fadd.f32(float %a, float -0.0, metadata !"round.towardzero", metadata !"fpexcept.ignore") #0 ret float %ret @@ -112,8 +111,7 @@ define float @fadd_x_n0_towardzero(float %a) #0 { ; Test one of the remaining rounding modes and the rest will be fine. define <2 x float> @fadd_vec_x_n0_towardzero(<2 x float> %a) #0 { ; CHECK-LABEL: @fadd_vec_x_n0_towardzero( -; CHECK-NEXT: [[RET:%.*]] = call <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> [[A:%.*]], <2 x float> , metadata !"round.towardzero", metadata !"fpexcept.ignore") #[[ATTR0]] -; CHECK-NEXT: ret <2 x float> [[RET]] +; CHECK-NEXT: ret <2 x float> [[A:%.*]] ; %ret = call <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> %a, <2 x float>, metadata !"round.towardzero", metadata !"fpexcept.ignore") #0 ret <2 x float> %ret @@ -121,8 +119,7 @@ define <2 x float> @fadd_vec_x_n0_towardzero(<2 x float> %a) #0 { define float @fadd_nnan_x_n0_ebmaytrap(float %a) #0 { ; CHECK-LABEL: @fadd_nnan_x_n0_ebmaytrap( -; CHECK-NEXT: [[RET:%.*]] = call nnan float @llvm.experimental.constrained.fadd.f32(float [[A:%.*]], float -0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.maytrap") #[[ATTR0]] -; CHECK-NEXT: ret float [[RET]] +; CHECK-NEXT: ret float [[A:%.*]] ; %ret = call nnan float @llvm.experimental.constrained.fadd.f32(float %a, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.maytrap") #0 ret float %ret @@ -130,8 +127,7 @@ define float @fadd_nnan_x_n0_ebmaytrap(float %a) #0 { define <2 x float> @fadd_vec_nnan_x_n0_ebmaytrap(<2 x float> %a) #0 { ; CHECK-LABEL: @fadd_vec_nnan_x_n0_ebmaytrap( -; CHECK-NEXT: [[RET:%.*]] = call nnan <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> [[A:%.*]], <2 x float> , metadata !"round.tonearest", metadata !"fpexcept.maytrap") #[[ATTR0]] -; CHECK-NEXT: ret <2 x float> [[RET]] +; CHECK-NEXT: ret <2 x float> [[A:%.*]] ; %ret = call nnan <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> %a, <2 x float>, metadata !"round.tonearest", metadata !"fpexcept.maytrap") #0 ret <2 x float> %ret @@ -140,7 +136,7 @@ define <2 x float> @fadd_vec_nnan_x_n0_ebmaytrap(<2 x float> %a) #0 { define float @fadd_nnan_x_n0_ebstrict(float %a) #0 { ; CHECK-LABEL: @fadd_nnan_x_n0_ebstrict( ; CHECK-NEXT: [[RET:%.*]] = call nnan float @llvm.experimental.constrained.fadd.f32(float [[A:%.*]], float -0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.strict") #[[ATTR0]] -; CHECK-NEXT: ret float [[RET]] +; CHECK-NEXT: ret float [[A]] ; %ret = call nnan float @llvm.experimental.constrained.fadd.f32(float %a, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.strict") #0 ret float %ret @@ -149,7 +145,7 @@ define float @fadd_nnan_x_n0_ebstrict(float %a) #0 { define <2 x float> @fadd_vec_nnan_x_n0_ebstrict(<2 x float> %a) #0 { ; CHECK-LABEL: @fadd_vec_nnan_x_n0_ebstrict( ; CHECK-NEXT: [[RET:%.*]] = call nnan <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> [[A:%.*]], <2 x float> , metadata !"round.tonearest", metadata !"fpexcept.strict") #[[ATTR0]] -; CHECK-NEXT: ret <2 x float> [[RET]] +; CHECK-NEXT: ret <2 x float> [[A]] ; %ret = call nnan <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> %a, <2 x float>, metadata !"round.tonearest", metadata !"fpexcept.strict") #0 ret <2 x float> %ret