1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-18 18:42:46 +02:00

[InstCombine] fold fcmp-of-copysign idiom

As discussed in:
https://llvm.org/PR49179
...this pattern shows up in library code.
There are several potential generalizations as noted,
but we need to be careful that we get FP special-values
right, and it's not clear how much variation we should
expect to see from this exact idiom.
This commit is contained in:
Sanjay Patel 2021-02-17 10:16:12 -05:00
parent 06ead2a50a
commit a2b8bdd4e5
2 changed files with 36 additions and 4 deletions

View File

@ -6267,6 +6267,26 @@ Instruction *InstCombinerImpl::visitFCmpInst(FCmpInst &I) {
}
}
// Convert a sign-bit test of an FP value into a cast and integer compare.
// TODO: Simplify if the copysign constant is 0.0 or NaN.
// TODO: Handle non-zero compare constants.
// TODO: Handle other predicates.
const APFloat *C;
if (match(Op0, m_OneUse(m_Intrinsic<Intrinsic::copysign>(m_APFloat(C),
m_Value(X)))) &&
match(Op1, m_AnyZeroFP()) && !C->isZero() && !C->isNaN()) {
Type *IntType = Builder.getIntNTy(X->getType()->getScalarSizeInBits());
if (auto *VecTy = dyn_cast<VectorType>(OpType))
IntType = VectorType::get(IntType, VecTy->getElementCount());
// copysign(non-zero constant, X) < 0.0 --> (bitcast X) < 0
if (Pred == FCmpInst::FCMP_OLT) {
Value *IntX = Builder.CreateBitCast(X, IntType);
return new ICmpInst(ICmpInst::ICMP_SLT, IntX,
ConstantInt::getNullValue(IntType));
}
}
if (I.getType()->isVectorTy())
if (Instruction *Res = foldVectorCmp(I, Builder))
return Res;

View File

@ -583,8 +583,8 @@ define <2 x i1> @test27_recipX_gt_vecsplat(<2 x float> %X) {
define i1 @is_signbit_set(double %x) {
; CHECK-LABEL: @is_signbit_set(
; CHECK-NEXT: [[S:%.*]] = call double @llvm.copysign.f64(double 1.000000e+00, double [[X:%.*]])
; CHECK-NEXT: [[R:%.*]] = fcmp olt double [[S]], 0.000000e+00
; CHECK-NEXT: [[TMP1:%.*]] = bitcast double [[X:%.*]] to i64
; CHECK-NEXT: [[R:%.*]] = icmp slt i64 [[TMP1]], 0
; CHECK-NEXT: ret i1 [[R]]
;
%s = call double @llvm.copysign.f64(double 1.0, double %x)
@ -592,10 +592,12 @@ define i1 @is_signbit_set(double %x) {
ret i1 %r
}
; Vectors are ok; the sign of zero in the compare doesn't matter; the copysign constant can be any non-zero number.
define <2 x i1> @is_signbit_set_anyzero(<2 x double> %x) {
; CHECK-LABEL: @is_signbit_set_anyzero(
; CHECK-NEXT: [[S:%.*]] = call <2 x double> @llvm.copysign.v2f64(<2 x double> <double 4.200000e+01, double 4.200000e+01>, <2 x double> [[X:%.*]])
; CHECK-NEXT: [[R:%.*]] = fcmp olt <2 x double> [[S]], zeroinitializer
; CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x double> [[X:%.*]] to <2 x i64>
; CHECK-NEXT: [[R:%.*]] = icmp slt <2 x i64> [[TMP1]], zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[R]]
;
%s = call <2 x double> @llvm.copysign.v2f64(<2 x double> <double 42.0, double 42.0>, <2 x double> %x)
@ -603,6 +605,8 @@ define <2 x i1> @is_signbit_set_anyzero(<2 x double> %x) {
ret <2 x i1> %r
}
; TODO: Handle different predicates.
define i1 @is_signbit_clear(double %x) {
; CHECK-LABEL: @is_signbit_clear(
; CHECK-NEXT: [[S:%.*]] = call double @llvm.copysign.f64(double -4.200000e+01, double [[X:%.*]])
@ -614,6 +618,8 @@ define i1 @is_signbit_clear(double %x) {
ret i1 %r
}
; Negative test - uses
define i1 @is_signbit_set_extra_use(double %x, double* %p) {
; CHECK-LABEL: @is_signbit_set_extra_use(
; CHECK-NEXT: [[S:%.*]] = call double @llvm.copysign.f64(double 1.000000e+00, double [[X:%.*]])
@ -627,6 +633,8 @@ define i1 @is_signbit_set_extra_use(double %x, double* %p) {
ret i1 %r
}
; TODO: Handle non-zero compare constant.
define i1 @is_signbit_clear_nonzero(double %x) {
; CHECK-LABEL: @is_signbit_clear_nonzero(
; CHECK-NEXT: [[S:%.*]] = call double @llvm.copysign.f64(double -4.200000e+01, double [[X:%.*]])
@ -638,6 +646,8 @@ define i1 @is_signbit_clear_nonzero(double %x) {
ret i1 %r
}
; TODO: Handle zero copysign constant.
define i1 @is_signbit_set_simplify_zero(double %x) {
; CHECK-LABEL: @is_signbit_set_simplify_zero(
; CHECK-NEXT: [[S:%.*]] = call double @llvm.copysign.f64(double 0.000000e+00, double [[X:%.*]])
@ -649,6 +659,8 @@ define i1 @is_signbit_set_simplify_zero(double %x) {
ret i1 %r
}
; TODO: Handle NaN copysign constant.
define i1 @is_signbit_set_simplify_nan(double %x) {
; CHECK-LABEL: @is_signbit_set_simplify_nan(
; CHECK-NEXT: [[S:%.*]] = call double @llvm.copysign.f64(double 0xFFFFFFFFFFFFFFFF, double [[X:%.*]])