if (ExpoF->isNegative() && (!Pow->hasApproxFunc() && !Pow->hasAllowReassoc()))
return nullptr;
+ // If we have a pow() library call (accesses memory) and we can't guarantee
+ // that the base is not an infinity, give up:
+ // pow(-Inf, 0.5) is optionally required to have a result of +Inf (not setting
+ // errno), but sqrt(-Inf) is required by various standards to set errno.
+ if (!Pow->doesNotAccessMemory() && !Pow->hasNoInfs() &&
+ !isKnownNeverInfinity(Base, TLI))
+ return nullptr;
+
Sqrt = getSqrtCall(Base, Attrs, Pow->doesNotAccessMemory(), Mod, B, TLI);
if (!Sqrt)
return nullptr;
; in the cases below where pow is transformed into another function call.
declare float @powf(float, float) nounwind readonly
+declare float @llvm.pow.f32(float, float)
declare double @pow(double, double) nounwind readonly
declare double @llvm.pow.f64(double, double)
declare <2 x float> @llvm.pow.v2f32(<2 x float>, <2 x float>) nounwind readonly
; Check pow(x, 0.5) -> fabs(sqrt(x)), where x != -infinity.
-define float @powf_libcall_to_select_sqrt(float %x) {
-; CHECK-LABEL: @powf_libcall_to_select_sqrt(
-; ANY-NEXT: [[SQRTF:%.*]] = call float @sqrtf(float [[X:%.*]])
-; ANY-NEXT: [[ABS:%.*]] = call float @llvm.fabs.f32(float [[SQRTF]])
-; ANY-NEXT: [[ISINF:%.*]] = fcmp oeq float [[X]], 0xFFF0000000000000
-; ANY-NEXT: [[TMP1:%.*]] = select i1 [[ISINF]], float 0x7FF0000000000000, float [[ABS]]
-; ANY-NEXT: ret float [[TMP1]]
-; VC32-NEXT: [[POW:%.*]] = call float @powf(float [[X:%.*]], float 5.000000e-01)
+define float @powf_libcall_half_ninf(float %x) {
+; CHECK-LABEL: @powf_libcall_half_ninf(
+; ANY-NEXT: [[SQRTF:%.*]] = call ninf float @sqrtf(float [[X:%.*]])
+; ANY-NEXT: [[ABS:%.*]] = call ninf float @llvm.fabs.f32(float [[SQRTF]])
+; ANY-NEXT: ret float [[ABS]]
+; VC32-NEXT: [[POW:%.*]] = call ninf float @powf(float [[X:%.*]], float 5.000000e-01)
; VC32-NEXT: ret float [[POW]]
-; VC51-NEXT: [[POW:%.*]] = call float @powf(float [[X:%.*]], float 5.000000e-01)
+; VC51-NEXT: [[POW:%.*]] = call ninf float @powf(float [[X:%.*]], float 5.000000e-01)
; VC51-NEXT: ret float [[POW]]
-; VC64-NEXT: [[SQRTF:%.*]] = call float @sqrtf(float [[X:%.*]])
-; VC64-NEXT: [[ABS:%.*]] = call float @llvm.fabs.f32(float [[SQRTF]])
-; VC64-NEXT: [[ISINF:%.*]] = fcmp oeq float [[X]], 0xFFF0000000000000
-; VC64-NEXT: [[TMP1:%.*]] = select i1 [[ISINF]], float 0x7FF0000000000000, float [[ABS]]
-; VC64-NEXT: ret float [[TMP1]]
-; VC83-NEXT: [[SQRTF:%.*]] = call float @sqrtf(float [[X:%.*]])
-; VC83-NEXT: [[ABS:%.*]] = call float @llvm.fabs.f32(float [[SQRTF]])
-; VC83-NEXT: [[ISINF:%.*]] = fcmp oeq float [[X]], 0xFFF0000000000000
-; VC83-NEXT: [[TMP1:%.*]] = select i1 [[ISINF]], float 0x7FF0000000000000, float [[ABS]]
-; VC83-NEXT: ret float [[TMP1]]
-; NOLIB-NEXT: [[POW:%.*]] = call float @powf(float [[X:%.*]], float 5.000000e-01)
+; VC64-NEXT: [[SQRTF:%.*]] = call ninf float @sqrtf(float [[X:%.*]])
+; VC64-NEXT: [[ABS:%.*]] = call ninf float @llvm.fabs.f32(float [[SQRTF]])
+; VC64-NEXT: ret float [[ABS]]
+; VC83-NEXT: [[SQRTF:%.*]] = call ninf float @sqrtf(float [[X:%.*]])
+; VC83-NEXT: [[ABS:%.*]] = call ninf float @llvm.fabs.f32(float [[SQRTF]])
+; VC83-NEXT: ret float [[ABS]]
+; NOLIB-NEXT: [[POW:%.*]] = call ninf float @powf(float [[X:%.*]], float 5.000000e-01)
; NOLIB-NEXT: ret float [[POW]]
;
- %retval = call float @powf(float %x, float 0.5)
+ %retval = call ninf float @powf(float %x, float 0.5)
ret float %retval
}
-define double @pow_libcall_to_select_sqrt(double %x) {
-; CHECK-LABEL: @pow_libcall_to_select_sqrt(
-; LIB-NEXT: [[SQRT:%.*]] = call double @sqrt(double [[X:%.*]])
-; LIB-NEXT: [[ABS:%.*]] = call double @llvm.fabs.f64(double [[SQRT]])
-; LIB-NEXT: [[ISINF:%.*]] = fcmp oeq double [[X]], 0xFFF0000000000000
-; LIB-NEXT: [[TMP1:%.*]] = select i1 [[ISINF]], double 0x7FF0000000000000, double [[ABS]]
-; LIB-NEXT: ret double [[TMP1]]
-; NOLIB-NEXT: [[POW:%.*]] = call double @pow(double [[X:%.*]], double 5.000000e-01)
-; NOLIB-NEXT: ret double [[POW]]
+; Check pow(x, 0.5) where x may be -infinity does not call a library sqrt function.
+
+define double @pow_libcall_half_no_FMF(double %x) {
+; CHECK-LABEL: @pow_libcall_half_no_FMF(
+; CHECK-NEXT: [[POW:%.*]] = call double @pow(double [[X:%.*]], double 5.000000e-01)
+; CHECK-NEXT: ret double [[POW]]
;
%retval = call double @pow(double %x, double 0.5)
ret double %retval
define float @test_simplify9(float %x) {
; CHECK-LABEL: @test_simplify9(
-; ANY-NEXT: ret float 0x7FF0000000000000
-; VC32-NEXT: [[POW:%.*]] = call float @powf(float 0xFFF0000000000000, float 5.000000e-01)
-; VC32-NEXT: ret float [[POW]]
-; VC51-NEXT: [[POW:%.*]] = call float @powf(float 0xFFF0000000000000, float 5.000000e-01)
-; VC51-NEXT: ret float [[POW]]
-; VC64-NEXT: ret float 0x7FF0000000000000
-; VC83-NEXT: ret float 0x7FF0000000000000
-; NOLIB-NEXT: [[POW:%.*]] = call float @powf(float 0xFFF0000000000000, float 5.000000e-01)
-; NOLIB-NEXT: ret float [[POW]]
+; CHECK-NEXT: ret float 0x7FF0000000000000
;
- %retval = call float @powf(float 0xFFF0000000000000, float 0.5)
+ %retval = call float @llvm.pow.f32(float 0xFFF0000000000000, float 0.5)
ret float %retval
}
define double @test_simplify10(double %x) {
; CHECK-LABEL: @test_simplify10(
-; LIB-NEXT: ret double 0x7FF0000000000000
-; NOLIB-NEXT: [[POW:%.*]] = call double @pow(double 0xFFF0000000000000, double 5.000000e-01)
-; NOLIB-NEXT: ret double [[POW]]
+; CHECK-NEXT: ret double 0x7FF0000000000000
;
- %retval = call double @pow(double 0xFFF0000000000000, double 0.5)
+ %retval = call double @llvm.pow.f64(double 0xFFF0000000000000, double 0.5)
ret double %retval
}
ret <2 x double> %r
}
-define double @test_simplify17(double %x) {
-; CHECK-LABEL: @test_simplify17(
+define double @pow_intrinsic_half_no_FMF(double %x) {
+; CHECK-LABEL: @pow_intrinsic_half_no_FMF(
; CHECK-NEXT: [[SQRT:%.*]] = call double @llvm.sqrt.f64(double [[X:%.*]])
; CHECK-NEXT: [[ABS:%.*]] = call double @llvm.fabs.f64(double [[SQRT]])
; CHECK-NEXT: [[ISINF:%.*]] = fcmp oeq double [[X]], 0xFFF0000000000000
; Check the libcall and the intrinsic for each case with differing FMF.
-; The transform to sqrt is allowed as long as we deal with -0.0 and -INF.
+; The transform to sqrt is not allowed if we risk setting errno due to -INF.
define double @pow_libcall_half_no_FMF(double %x) {
; CHECK-LABEL: @pow_libcall_half_no_FMF(
-; CHECK-NEXT: [[SQRT:%.*]] = call double @sqrt(double [[X:%.*]])
-; CHECK-NEXT: [[ABS:%.*]] = call double @llvm.fabs.f64(double [[SQRT]])
-; CHECK-NEXT: [[ISINF:%.*]] = fcmp oeq double [[X]], 0xFFF0000000000000
-; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[ISINF]], double 0x7FF0000000000000, double [[ABS]]
-; CHECK-NEXT: ret double [[TMP1]]
+; CHECK-NEXT: [[POW:%.*]] = call double @pow(double [[X:%.*]], double 5.000000e-01)
+; CHECK-NEXT: ret double [[POW]]
;
%pow = call double @pow(double %x, double 5.0e-01)
ret double %pow
}
+; The transform to (non-errno setting) sqrt is allowed as long as we deal with -0.0 and -INF.
+
define double @pow_intrinsic_half_no_FMF(double %x) {
; CHECK-LABEL: @pow_intrinsic_half_no_FMF(
; CHECK-NEXT: [[SQRT:%.*]] = call double @llvm.sqrt.f64(double [[X:%.*]])
ret double %pow
}
-; This makes no difference, but FMF are propagated.
+; `afn` makes no difference, but FMF are propagated/retained.
+
+; (As above) the transform to sqrt may generate EDOM due to -INF. Generally, EDOM implies
+; formation of a NaN (which then propagates). `afn` may justify returning NaN (along with
+; setting EDOM); however, the conservatively correct approach is to avoid both the NaN and
+; the EDOM.
define double @pow_libcall_half_approx(double %x) {
; CHECK-LABEL: @pow_libcall_half_approx(
-; CHECK-NEXT: [[SQRT:%.*]] = call afn double @sqrt(double [[X:%.*]])
-; CHECK-NEXT: [[ABS:%.*]] = call afn double @llvm.fabs.f64(double [[SQRT]])
-; CHECK-NEXT: [[ISINF:%.*]] = fcmp afn oeq double [[X]], 0xFFF0000000000000
-; CHECK-NEXT: [[TMP1:%.*]] = select afn i1 [[ISINF]], double 0x7FF0000000000000, double [[ABS]]
-; CHECK-NEXT: ret double [[TMP1]]
+; CHECK-NEXT: [[POW:%.*]] = call afn double @pow(double [[X:%.*]], double 5.000000e-01)
+; CHECK-NEXT: ret double [[POW]]
;
%pow = call afn double @pow(double %x, double 5.0e-01)
ret double %pow
}
+; (As above) the transform to (non-errno setting) sqrt is allowed as long as we deal with -0.0
+; and -INF.
+
define <2 x double> @pow_intrinsic_half_approx(<2 x double> %x) {
; CHECK-LABEL: @pow_intrinsic_half_approx(
; CHECK-NEXT: [[SQRT:%.*]] = call afn <2 x double> @llvm.sqrt.v2f64(<2 x double> [[X:%.*]])
ret <2 x double> %pow
}
-; If we can disregard -0.0, no need for fabs.
+; If we can disregard -0.0, no need for fabs, but still (because of -INF) cannot use library sqrt.
define double @pow_libcall_half_nsz(double %x) {
; CHECK-LABEL: @pow_libcall_half_nsz(
-; CHECK-NEXT: [[SQRT:%.*]] = call nsz double @sqrt(double [[X:%.*]])
-; CHECK-NEXT: [[ISINF:%.*]] = fcmp nsz oeq double [[X]], 0xFFF0000000000000
-; CHECK-NEXT: [[TMP1:%.*]] = select nsz i1 [[ISINF]], double 0x7FF0000000000000, double [[SQRT]]
-; CHECK-NEXT: ret double [[TMP1]]
+; CHECK-NEXT: [[POW:%.*]] = call nsz double @pow(double [[X:%.*]], double 5.000000e-01)
+; CHECK-NEXT: ret double [[POW]]
;
%pow = call nsz double @pow(double %x, double 5.0e-01)
ret double %pow
ret float %pow
}
+; If we can disregard INFs, a call to a library sqrt is okay.
; Transform to sqrt+fdiv because 'reassoc' allows an extra rounding step.
; Use 'fabs' to handle -0.0 correctly.
-; Use 'select' to handle -INF correctly.
-define float @pow_libcall_neghalf_reassoc(float %x) {
-; CHECK-LABEL: @pow_libcall_neghalf_reassoc(
-; CHECK-NEXT: [[SQRTF:%.*]] = call reassoc float @sqrtf(float [[X:%.*]])
-; CHECK-NEXT: [[ABS:%.*]] = call reassoc float @llvm.fabs.f32(float [[SQRTF]])
-; CHECK-NEXT: [[ISINF:%.*]] = fcmp reassoc oeq float [[X]], 0xFFF0000000000000
-; CHECK-NEXT: [[ABS_OP:%.*]] = fdiv reassoc float 1.000000e+00, [[ABS]]
-; CHECK-NEXT: [[RECIPROCAL:%.*]] = select i1 [[ISINF]], float 0.000000e+00, float [[ABS_OP]]
+define float @pow_libcall_neghalf_reassoc_ninf(float %x) {
+; CHECK-LABEL: @pow_libcall_neghalf_reassoc_ninf(
+; CHECK-NEXT: [[SQRTF:%.*]] = call reassoc ninf float @sqrtf(float [[X:%.*]])
+; CHECK-NEXT: [[ABS:%.*]] = call reassoc ninf float @llvm.fabs.f32(float [[SQRTF]])
+; CHECK-NEXT: [[RECIPROCAL:%.*]] = fdiv reassoc ninf float 1.000000e+00, [[ABS]]
; CHECK-NEXT: ret float [[RECIPROCAL]]
;
- %pow = call reassoc float @powf(float %x, float -5.0e-01)
+ %pow = call reassoc ninf float @powf(float %x, float -5.0e-01)
ret float %pow
}
-; Transform to sqrt+fdiv because 'afn' allows an extra rounding step.
-; Use 'fabs' to handle -0.0 correctly.
-; Use 'select' to handle -INF correctly.
+; If we cannot disregard INFs, a call to a library sqrt is not okay.
define float @pow_libcall_neghalf_afn(float %x) {
; CHECK-LABEL: @pow_libcall_neghalf_afn(
-; CHECK-NEXT: [[SQRTF:%.*]] = call afn float @sqrtf(float [[X:%.*]])
-; CHECK-NEXT: [[ABS:%.*]] = call afn float @llvm.fabs.f32(float [[SQRTF]])
-; CHECK-NEXT: [[ISINF:%.*]] = fcmp afn oeq float [[X]], 0xFFF0000000000000
-; CHECK-NEXT: [[ABS_OP:%.*]] = fdiv afn float 1.000000e+00, [[ABS]]
-; CHECK-NEXT: [[RECIPROCAL:%.*]] = select i1 [[ISINF]], float 0.000000e+00, float [[ABS_OP]]
-; CHECK-NEXT: ret float [[RECIPROCAL]]
+; CHECK-NEXT: [[POW:%.*]] = call afn float @powf(float [[X:%.*]], float -5.000000e-01)
+; CHECK-NEXT: ret float [[POW]]
;
%pow = call afn float @powf(float %x, float -5.0e-01)
ret float %pow
ret <2 x double> %pow
}
-; If we can disregard -0.0, no need for fabs.
+; If we can disregard -0.0, no need for fabs, but still (because of -INF) cannot use library sqrt.
define double @pow_libcall_neghalf_nsz(double %x) {
; CHECK-LABEL: @pow_libcall_neghalf_nsz(
-; CHECK-NEXT: [[SQRT:%.*]] = call nsz afn double @sqrt(double [[X:%.*]])
-; CHECK-NEXT: [[ISINF:%.*]] = fcmp nsz afn oeq double [[X]], 0xFFF0000000000000
-; CHECK-NEXT: [[SQRT_OP:%.*]] = fdiv nsz afn double 1.000000e+00, [[SQRT]]
-; CHECK-NEXT: [[RECIPROCAL:%.*]] = select i1 [[ISINF]], double 0.000000e+00, double [[SQRT_OP]]
-; CHECK-NEXT: ret double [[RECIPROCAL]]
+; CHECK-NEXT: [[POW:%.*]] = call nsz afn double @pow(double [[X:%.*]], double -5.000000e-01)
+; CHECK-NEXT: ret double [[POW]]
;
%pow = call afn nsz double @pow(double %x, double -5.0e-01)
ret double %pow
; MINGW64-NOT: float @powf
; MINGW64: float @sqrtf
; MINGW64: float @llvm.fabs.f32(
- %1 = call float @powf(float %x, float 0.5)
+ %1 = call ninf float @powf(float %x, float 0.5)
ret float %1
}