diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -2634,7 +2634,11 @@ // when 'Swap' is true: // fold (X > +/-0.0) ? X : -X or (X >= +/-0.0) ? X : -X to fabs(X) // fold (X < +/-0.0) ? X : -X or (X <= +/-0.0) ? X : -X to -fabs(X) - if (!SI.hasNoSignedZeros()) + // + // Note: We require "nnan" for this fold because fcmp ignores the signbit + // of NAN, but IEEE-754 specifies the signbit of NAN values with + // fneg/fabs operations. + if (!SI.hasNoSignedZeros() || !SI.hasNoNaNs()) return nullptr; if (Swap) diff --git a/llvm/test/Transforms/InstCombine/fabs.ll b/llvm/test/Transforms/InstCombine/fabs.ll --- a/llvm/test/Transforms/InstCombine/fabs.ll +++ b/llvm/test/Transforms/InstCombine/fabs.ll @@ -349,10 +349,15 @@ ret fp128 %fabs } +; This is not fabs because that could produce a different signbit for a NAN input. +; PR59279 + define float @select_nsz_fcmp_ogt_fneg(float %a) { ; CHECK-LABEL: @select_nsz_fcmp_ogt_fneg( -; CHECK-NEXT: [[TMP1:%.*]] = call nsz float @llvm.fabs.f32(float [[A:%.*]]) -; CHECK-NEXT: ret float [[TMP1]] +; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[A:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt float [[A]], 0.000000e+00 +; CHECK-NEXT: [[R:%.*]] = select nsz i1 [[CMP]], float [[A]], float [[FNEG]] +; CHECK-NEXT: ret float [[R]] ; %fneg = fneg float %a %cmp = fcmp ogt float %a, %fneg @@ -445,12 +450,15 @@ ret half %fabs } -; X < 0.0 ? -X : X --> fabs(X) +; This is not fabs because that could produce a different signbit for a NAN input. +; PR59279 define double @select_nsz_fcmp_olt_zero_unary_fneg(double %x) { ; CHECK-LABEL: @select_nsz_fcmp_olt_zero_unary_fneg( -; CHECK-NEXT: [[TMP1:%.*]] = call nsz double @llvm.fabs.f64(double [[X:%.*]]) -; CHECK-NEXT: ret double [[TMP1]] +; CHECK-NEXT: [[LTZERO:%.*]] = fcmp olt double [[X:%.*]], 0.000000e+00 +; CHECK-NEXT: [[NEGX:%.*]] = fneg double [[X]] +; CHECK-NEXT: [[FABS:%.*]] = select nsz i1 [[LTZERO]], double [[NEGX]], double [[X]] +; CHECK-NEXT: ret double [[FABS]] ; %ltzero = fcmp olt double %x, 0.0 %negx = fneg double %x @@ -458,6 +466,8 @@ ret double %fabs } +; X < 0.0 ? -X : X --> fabs(X) + define double @select_nsz_nnan_fcmp_olt_zero_unary_fneg(double %x) { ; CHECK-LABEL: @select_nsz_nnan_fcmp_olt_zero_unary_fneg( ; CHECK-NEXT: [[TMP1:%.*]] = call nnan nsz double @llvm.fabs.f64(double [[X:%.*]]) @@ -743,12 +753,15 @@ ret float %fabs } -; X > 0.0 ? X : (-X) --> fabs(X) +; This is not fabs because that could produce a different signbit for a NAN input. +; PR59279 define <2 x float> @select_nsz_fcmp_ogt_zero_unary_fneg(<2 x float> %x) { ; CHECK-LABEL: @select_nsz_fcmp_ogt_zero_unary_fneg( -; CHECK-NEXT: [[TMP1:%.*]] = call nsz <2 x float> @llvm.fabs.v2f32(<2 x float> [[X:%.*]]) -; CHECK-NEXT: ret <2 x float> [[TMP1]] +; CHECK-NEXT: [[GTZERO:%.*]] = fcmp ogt <2 x float> [[X:%.*]], zeroinitializer +; CHECK-NEXT: [[NEGX:%.*]] = fneg <2 x float> [[X]] +; CHECK-NEXT: [[FABS:%.*]] = select nsz <2 x i1> [[GTZERO]], <2 x float> [[X]], <2 x float> [[NEGX]] +; CHECK-NEXT: ret <2 x float> [[FABS]] ; %gtzero = fcmp ogt <2 x float> %x, zeroinitializer %negx = fneg <2 x float> %x @@ -756,6 +769,8 @@ ret <2 x float> %fabs } +; X > 0.0 ? X : (-X) --> fabs(X) + define <2 x float> @select_nsz_nnan_fcmp_ogt_zero_unary_fneg(<2 x float> %x) { ; CHECK-LABEL: @select_nsz_nnan_fcmp_ogt_zero_unary_fneg( ; CHECK-NEXT: [[TMP1:%.*]] = call nnan nsz <2 x float> @llvm.fabs.v2f32(<2 x float> [[X:%.*]]) diff --git a/llvm/test/Transforms/InstCombine/fneg-fabs.ll b/llvm/test/Transforms/InstCombine/fneg-fabs.ll --- a/llvm/test/Transforms/InstCombine/fneg-fabs.ll +++ b/llvm/test/Transforms/InstCombine/fneg-fabs.ll @@ -44,10 +44,14 @@ ; Tests with various predicate types. +; This is not fabs because that could produce a different signbit for a NAN input. +; PR59279 + define double @select_nsz_nfabs_ult(double %x) { ; CHECK-LABEL: @select_nsz_nfabs_ult( -; CHECK-NEXT: [[TMP1:%.*]] = call nsz double @llvm.fabs.f64(double [[X:%.*]]) -; CHECK-NEXT: [[SEL:%.*]] = fneg nsz double [[TMP1]] +; CHECK-NEXT: [[CMP:%.*]] = fcmp ult double [[X:%.*]], 0.000000e+00 +; CHECK-NEXT: [[NEGX:%.*]] = fneg double [[X]] +; CHECK-NEXT: [[SEL:%.*]] = select nsz i1 [[CMP]], double [[X]], double [[NEGX]] ; CHECK-NEXT: ret double [[SEL]] ; %cmp = fcmp ult double %x, 0.000000e+00 @@ -68,10 +72,14 @@ ret double %sel } +; This is not fabs because that could produce a different signbit for a NAN input. +; PR59279 + define double @select_nsz_nfabs_ole(double %x) { ; CHECK-LABEL: @select_nsz_nfabs_ole( -; CHECK-NEXT: [[TMP1:%.*]] = call nsz double @llvm.fabs.f64(double [[X:%.*]]) -; CHECK-NEXT: [[SEL:%.*]] = fneg nsz double [[TMP1]] +; CHECK-NEXT: [[CMP:%.*]] = fcmp ole double [[X:%.*]], 0.000000e+00 +; CHECK-NEXT: [[NEGX:%.*]] = fneg double [[X]] +; CHECK-NEXT: [[SEL:%.*]] = select nsz i1 [[CMP]], double [[X]], double [[NEGX]] ; CHECK-NEXT: ret double [[SEL]] ; %cmp = fcmp ole double %x, 0.000000e+00 @@ -92,10 +100,14 @@ ret double %sel } +; This is not fabs because that could produce a different signbit for a NAN input. +; PR59279 + define double @select_nsz_nfabs_ule(double %x) { ; CHECK-LABEL: @select_nsz_nfabs_ule( -; CHECK-NEXT: [[TMP1:%.*]] = call nsz double @llvm.fabs.f64(double [[X:%.*]]) -; CHECK-NEXT: [[SEL:%.*]] = fneg nsz double [[TMP1]] +; CHECK-NEXT: [[CMP:%.*]] = fcmp ule double [[X:%.*]], 0.000000e+00 +; CHECK-NEXT: [[NEGX:%.*]] = fneg double [[X]] +; CHECK-NEXT: [[SEL:%.*]] = select nsz i1 [[CMP]], double [[X]], double [[NEGX]] ; CHECK-NEXT: ret double [[SEL]] ; %cmp = fcmp ule double %x, 0.000000e+00 @@ -157,11 +169,14 @@ ret double %sel } -; Tests with various predicate types. +; This is not fabs because that could produce a different signbit for a NAN input. +; PR59279 + define double @select_nsz_nfabs_ogt(double %x) { ; CHECK-LABEL: @select_nsz_nfabs_ogt( -; CHECK-NEXT: [[TMP1:%.*]] = call nsz double @llvm.fabs.f64(double [[X:%.*]]) -; CHECK-NEXT: [[SEL:%.*]] = fneg nsz double [[TMP1]] +; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt double [[X:%.*]], 0.000000e+00 +; CHECK-NEXT: [[NEGX:%.*]] = fneg double [[X]] +; CHECK-NEXT: [[SEL:%.*]] = select nsz i1 [[CMP]], double [[NEGX]], double [[X]] ; CHECK-NEXT: ret double [[SEL]] ; %cmp = fcmp ogt double %x, 0.000000e+00 @@ -170,6 +185,8 @@ ret double %sel } +; Tests with various predicate types. + define double @select_nsz_nnan_nfabs_ogt(double %x) { ; CHECK-LABEL: @select_nsz_nnan_nfabs_ogt( ; CHECK-NEXT: [[TMP1:%.*]] = call nnan nsz double @llvm.fabs.f64(double [[X:%.*]]) @@ -182,10 +199,14 @@ ret double %sel } +; This is not fabs because that could produce a different signbit for a NAN input. +; PR59279 + define double @select_nsz_nfabs_ugt(double %x) { ; CHECK-LABEL: @select_nsz_nfabs_ugt( -; CHECK-NEXT: [[TMP1:%.*]] = call nsz double @llvm.fabs.f64(double [[X:%.*]]) -; CHECK-NEXT: [[SEL:%.*]] = fneg nsz double [[TMP1]] +; CHECK-NEXT: [[CMP:%.*]] = fcmp ugt double [[X:%.*]], 0.000000e+00 +; CHECK-NEXT: [[NEGX:%.*]] = fneg double [[X]] +; CHECK-NEXT: [[SEL:%.*]] = select nsz i1 [[CMP]], double [[NEGX]], double [[X]] ; CHECK-NEXT: ret double [[SEL]] ; %cmp = fcmp ugt double %x, 0.000000e+00 @@ -206,10 +227,14 @@ ret double %sel } +; This is not fabs because that could produce a different signbit for a NAN input. +; PR59279 + define double @select_nsz_nfabs_oge(double %x) { ; CHECK-LABEL: @select_nsz_nfabs_oge( -; CHECK-NEXT: [[TMP1:%.*]] = call nsz double @llvm.fabs.f64(double [[X:%.*]]) -; CHECK-NEXT: [[SEL:%.*]] = fneg nsz double [[TMP1]] +; CHECK-NEXT: [[CMP:%.*]] = fcmp oge double [[X:%.*]], 0.000000e+00 +; CHECK-NEXT: [[NEGX:%.*]] = fneg double [[X]] +; CHECK-NEXT: [[SEL:%.*]] = select nsz i1 [[CMP]], double [[NEGX]], double [[X]] ; CHECK-NEXT: ret double [[SEL]] ; %cmp = fcmp oge double %x, 0.000000e+00 @@ -230,10 +255,14 @@ ret double %sel } +; This is not fabs because that could produce a different signbit for a NAN input. +; PR59279 + define double @select_nsz_nfabs_uge(double %x) { ; CHECK-LABEL: @select_nsz_nfabs_uge( -; CHECK-NEXT: [[TMP1:%.*]] = call nsz double @llvm.fabs.f64(double [[X:%.*]]) -; CHECK-NEXT: [[SEL:%.*]] = fneg nsz double [[TMP1]] +; CHECK-NEXT: [[CMP:%.*]] = fcmp uge double [[X:%.*]], 0.000000e+00 +; CHECK-NEXT: [[NEGX:%.*]] = fneg double [[X]] +; CHECK-NEXT: [[SEL:%.*]] = select nsz i1 [[CMP]], double [[NEGX]], double [[X]] ; CHECK-NEXT: ret double [[SEL]] ; %cmp = fcmp uge double %x, 0.000000e+00 diff --git a/llvm/test/Transforms/InstCombine/fneg.ll b/llvm/test/Transforms/InstCombine/fneg.ll --- a/llvm/test/Transforms/InstCombine/fneg.ll +++ b/llvm/test/Transforms/InstCombine/fneg.ll @@ -742,10 +742,14 @@ ret float %fneg1 } +; This is not fabs because that could produce a different signbit for a NAN input. +; PR59279 + define float @fnabs_2_nsz(float %a) { ; CHECK-LABEL: @fnabs_2_nsz( -; CHECK-NEXT: [[TMP1:%.*]] = call nsz float @llvm.fabs.f32(float [[A:%.*]]) -; CHECK-NEXT: [[FNEG1:%.*]] = fneg float [[TMP1]] +; CHECK-NEXT: [[CMP:%.*]] = fcmp olt float [[A:%.*]], 0.000000e+00 +; CHECK-NEXT: [[A_NEG:%.*]] = fneg float [[A]] +; CHECK-NEXT: [[FNEG1:%.*]] = select nsz i1 [[CMP]], float [[A]], float [[A_NEG]] ; CHECK-NEXT: ret float [[FNEG1]] ; %fneg = fneg float %a