From af0babc90a5c35cbecce4cc4a27e0396fe03f588 Mon Sep 17 00:00:00 2001 From: Sanjay Patel Date: Mon, 2 Dec 2019 09:21:59 -0500 Subject: [PATCH] [InstCombine] fold copysign with constant sign argument to (fneg+)fabs If the sign of the sign argument is known (this could be extended to use ValueTracking), then we can use fneg+fabs to clear/set the sign bit of the magnitude argument. http://llvm.org/docs/LangRef.html#llvm-copysign-intrinsic This transform is already done in DAGCombiner, but we can do it sooner in IR as suggested in PR44153: https://bugs.llvm.org/show_bug.cgi?id=44153 We have effectively no analysis for copysign in IR, so we are taking the unusual step of increasing the number of IR instructions for the negative constant case. Differential Revision: https://reviews.llvm.org/D70792 --- .../InstCombine/InstCombineCalls.cpp | 15 +++++++++++++++ llvm/test/Transforms/InstCombine/copysign.ll | 18 ++++++++++-------- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index 23ca03ff68b0..536e84b4a35e 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -2279,6 +2279,21 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { break; } + case Intrinsic::copysign: { + const APFloat *C; + if (match(II->getArgOperand(1), m_APFloat(C))) { + // If we know the sign bit of the sign argument, reduce to FABS/FNABS: + // copysign X, PosC --> fabs X + // copysign X, NegC --> fneg (fabs X) + Value *Fabs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, + II->getArgOperand(0), II); + if (C->isNegative()) + Fabs = Builder.CreateFNegFMF(Fabs, II); + + return replaceInstUsesWith(*II, Fabs); + } + break; + } case Intrinsic::fabs: { Value *Cond; Constant *LHS, *RHS; diff --git a/llvm/test/Transforms/InstCombine/copysign.ll b/llvm/test/Transforms/InstCombine/copysign.ll index 5d30f346807d..49ca1b87d0de 100644 --- a/llvm/test/Transforms/InstCombine/copysign.ll +++ b/llvm/test/Transforms/InstCombine/copysign.ll @@ -6,8 +6,8 @@ declare <3 x double> @llvm.copysign.v3f64(<3 x double>, <3 x double>) define float @positive_sign_arg(float %x) { ; CHECK-LABEL: @positive_sign_arg( -; CHECK-NEXT: [[R:%.*]] = call arcp float @llvm.copysign.f32(float [[X:%.*]], float 0.000000e+00) -; CHECK-NEXT: ret float [[R]] +; CHECK-NEXT: [[TMP1:%.*]] = call arcp float @llvm.fabs.f32(float [[X:%.*]]) +; CHECK-NEXT: ret float [[TMP1]] ; %r = call arcp float @llvm.copysign.f32(float %x, float 0.0) ret float %r @@ -15,8 +15,8 @@ define float @positive_sign_arg(float %x) { define <3 x double> @positive_sign_arg_vec_splat(<3 x double> %x) { ; CHECK-LABEL: @positive_sign_arg_vec_splat( -; CHECK-NEXT: [[R:%.*]] = call ninf <3 x double> @llvm.copysign.v3f64(<3 x double> [[X:%.*]], <3 x double> ) -; CHECK-NEXT: ret <3 x double> [[R]] +; CHECK-NEXT: [[TMP1:%.*]] = call ninf <3 x double> @llvm.fabs.v3f64(<3 x double> [[X:%.*]]) +; CHECK-NEXT: ret <3 x double> [[TMP1]] ; %r = call ninf <3 x double> @llvm.copysign.v3f64(<3 x double> %x, <3 x double> ) ret <3 x double> %r @@ -24,8 +24,9 @@ define <3 x double> @positive_sign_arg_vec_splat(<3 x double> %x) { define float @negative_sign_arg(float %x) { ; CHECK-LABEL: @negative_sign_arg( -; CHECK-NEXT: [[R:%.*]] = call nnan float @llvm.copysign.f32(float [[X:%.*]], float -0.000000e+00) -; CHECK-NEXT: ret float [[R]] +; CHECK-NEXT: [[TMP1:%.*]] = call nnan float @llvm.fabs.f32(float [[X:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = fneg nnan float [[TMP1]] +; CHECK-NEXT: ret float [[TMP2]] ; %r = call nnan float @llvm.copysign.f32(float %x, float -0.0) ret float %r @@ -33,8 +34,9 @@ define float @negative_sign_arg(float %x) { define <3 x double> @negative_sign_arg_vec_splat(<3 x double> %x) { ; CHECK-LABEL: @negative_sign_arg_vec_splat( -; CHECK-NEXT: [[R:%.*]] = call fast <3 x double> @llvm.copysign.v3f64(<3 x double> [[X:%.*]], <3 x double> ) -; CHECK-NEXT: ret <3 x double> [[R]] +; CHECK-NEXT: [[TMP1:%.*]] = call fast <3 x double> @llvm.fabs.v3f64(<3 x double> [[X:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = fneg fast <3 x double> [[TMP1]] +; CHECK-NEXT: ret <3 x double> [[TMP2]] ; %r = call fast <3 x double> @llvm.copysign.v3f64(<3 x double> %x, <3 x double> ) ret <3 x double> %r