Index: llvm/include/llvm/IR/IRBuilder.h =================================================================== --- llvm/include/llvm/IR/IRBuilder.h +++ llvm/include/llvm/IR/IRBuilder.h @@ -940,6 +940,14 @@ return CreateBinaryIntrinsic(Intrinsic::maximum, LHS, RHS, nullptr, Name); } + /// Create call to the copysign intrinsic. + CallInst *CreateCopySign(Value *LHS, Value *RHS, + Instruction *FMFSource = nullptr, + const Twine &Name = "") { + return CreateBinaryIntrinsic(Intrinsic::copysign, LHS, RHS, FMFSource, + Name); + } + /// Create a call to the arithmetic_fence intrinsic. CallInst *CreateArithmeticFence(Value *Val, Type *DstType, const Twine &Name = "") { Index: llvm/include/llvm/IR/PatternMatch.h =================================================================== --- llvm/include/llvm/IR/PatternMatch.h +++ llvm/include/llvm/IR/PatternMatch.h @@ -2206,6 +2206,12 @@ return m_Intrinsic(Op0); } +template +inline typename m_Intrinsic_Ty::Ty m_CopySign(const Opnd0 &Op0, + const Opnd1 &Op1) { + return m_Intrinsic(Op0, Op1); +} + //===----------------------------------------------------------------------===// // Matchers for two-operands operators with the operators in either order // Index: llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -2008,6 +2008,16 @@ return replaceOperand(*II, 0, TVal); } + Value *Magnitude, *Sign; + if (match(II->getArgOperand(0), + m_CopySign(m_Value(Magnitude), m_Value(Sign)))) { + // fabs (copysign x, y) -> (fabs x) + CallInst *AbsSign = + Builder.CreateCall(II->getCalledFunction(), {Magnitude}); + AbsSign->copyFastMathFlags(II); + return replaceInstUsesWith(*II, AbsSign); + } + [[fallthrough]]; } case Intrinsic::ceil: Index: llvm/test/Transforms/InstCombine/copysign-fneg-fabs.ll =================================================================== --- llvm/test/Transforms/InstCombine/copysign-fneg-fabs.ll +++ llvm/test/Transforms/InstCombine/copysign-fneg-fabs.ll @@ -79,9 +79,8 @@ define half @fneg_fabs_copysign(half %x, half %y) { ; CHECK-LABEL: @fneg_fabs_copysign( -; CHECK-NEXT: [[COPYSIGN:%.*]] = call half @llvm.copysign.f16(half [[X:%.*]], half [[Y:%.*]]) -; CHECK-NEXT: [[FABS_COPYSIGN:%.*]] = call half @llvm.fabs.f16(half [[COPYSIGN]]) -; CHECK-NEXT: [[FNEG_FABS_COPYSIGN:%.*]] = fneg half [[FABS_COPYSIGN]] +; CHECK-NEXT: [[TMP1:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) +; CHECK-NEXT: [[FNEG_FABS_COPYSIGN:%.*]] = fneg half [[TMP1]] ; CHECK-NEXT: ret half [[FNEG_FABS_COPYSIGN]] ; %copysign = call half @llvm.copysign.f16(half %x, half %y) @@ -93,9 +92,8 @@ ; https://alive2.llvm.org/ce/z/Ft-7ea define half @fabs_copysign(half %x, half %y) { ; CHECK-LABEL: @fabs_copysign( -; CHECK-NEXT: [[COPYSIGN:%.*]] = call half @llvm.copysign.f16(half [[X:%.*]], half [[Y:%.*]]) -; CHECK-NEXT: [[FABS_COPYSIGN:%.*]] = call half @llvm.fabs.f16(half [[COPYSIGN]]) -; CHECK-NEXT: ret half [[FABS_COPYSIGN]] +; CHECK-NEXT: [[TMP1:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) +; CHECK-NEXT: ret half [[TMP1]] ; %copysign = call half @llvm.copysign.f16(half %x, half %y) %fabs.copysign = call half @llvm.fabs.f16(half %copysign) @@ -115,9 +113,8 @@ define <2 x half> @fneg_fabs_copysign_vector(<2 x half> %x, <2 x half> %y) { ; CHECK-LABEL: @fneg_fabs_copysign_vector( -; CHECK-NEXT: [[COPYSIGN:%.*]] = call <2 x half> @llvm.copysign.v2f16(<2 x half> [[X:%.*]], <2 x half> [[Y:%.*]]) -; CHECK-NEXT: [[FABS_COPYSIGN:%.*]] = call <2 x half> @llvm.fabs.v2f16(<2 x half> [[COPYSIGN]]) -; CHECK-NEXT: [[FNEG_FABS_COPYSIGN:%.*]] = fneg <2 x half> [[FABS_COPYSIGN]] +; CHECK-NEXT: [[TMP1:%.*]] = call <2 x half> @llvm.fabs.v2f16(<2 x half> [[X:%.*]]) +; CHECK-NEXT: [[FNEG_FABS_COPYSIGN:%.*]] = fneg <2 x half> [[TMP1]] ; CHECK-NEXT: ret <2 x half> [[FNEG_FABS_COPYSIGN]] ; %copysign = call <2 x half> @llvm.copysign.v2f16(<2 x half> %x, <2 x half> %y) @@ -128,9 +125,8 @@ define <2 x half> @fabs_copysign_vector(<2 x half> %x, <2 x half> %y) { ; CHECK-LABEL: @fabs_copysign_vector( -; CHECK-NEXT: [[COPYSIGN:%.*]] = call <2 x half> @llvm.copysign.v2f16(<2 x half> [[X:%.*]], <2 x half> [[Y:%.*]]) -; CHECK-NEXT: [[FABS_COPYSIGN:%.*]] = call <2 x half> @llvm.fabs.v2f16(<2 x half> [[COPYSIGN]]) -; CHECK-NEXT: ret <2 x half> [[FABS_COPYSIGN]] +; CHECK-NEXT: [[TMP1:%.*]] = call <2 x half> @llvm.fabs.v2f16(<2 x half> [[X:%.*]]) +; CHECK-NEXT: ret <2 x half> [[TMP1]] ; %copysign = call <2 x half> @llvm.copysign.v2f16(<2 x half> %x, <2 x half> %y) %fabs.copysign = call <2 x half> @llvm.fabs.v2f16(<2 x half> %copysign) @@ -150,9 +146,8 @@ define half @fneg_fabs_copysign_flags(half %x, half %y) { ; CHECK-LABEL: @fneg_fabs_copysign_flags( -; CHECK-NEXT: [[COPYSIGN:%.*]] = call nnan ninf nsz half @llvm.copysign.f16(half [[X:%.*]], half [[Y:%.*]]) -; CHECK-NEXT: [[FABS_COPYSIGN:%.*]] = call nnan ninf afn half @llvm.fabs.f16(half [[COPYSIGN]]) -; CHECK-NEXT: [[FNEG_FABS_COPYSIGN:%.*]] = fneg reassoc ninf half [[FABS_COPYSIGN]] +; CHECK-NEXT: [[TMP1:%.*]] = call nnan ninf afn half @llvm.fabs.f16(half [[X:%.*]]) +; CHECK-NEXT: [[FNEG_FABS_COPYSIGN:%.*]] = fneg reassoc ninf half [[TMP1]] ; CHECK-NEXT: ret half [[FNEG_FABS_COPYSIGN]] ; %copysign = call nnan nsz ninf half @llvm.copysign.f16(half %x, half %y) @@ -175,9 +170,8 @@ define half @fneg_fabs_copysign_flags_none_fabs(half %x, half %y) { ; CHECK-LABEL: @fneg_fabs_copysign_flags_none_fabs( -; CHECK-NEXT: [[COPYSIGN:%.*]] = call nnan ninf nsz half @llvm.copysign.f16(half [[X:%.*]], half [[Y:%.*]]) -; CHECK-NEXT: [[FABS_COPYSIGN:%.*]] = call half @llvm.fabs.f16(half [[COPYSIGN]]) -; CHECK-NEXT: [[FNEG_FABS_COPYSIGN:%.*]] = fneg fast half [[FABS_COPYSIGN]] +; CHECK-NEXT: [[TMP1:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) +; CHECK-NEXT: [[FNEG_FABS_COPYSIGN:%.*]] = fneg fast half [[TMP1]] ; CHECK-NEXT: ret half [[FNEG_FABS_COPYSIGN]] ; %copysign = call nnan nsz ninf half @llvm.copysign.f16(half %x, half %y) @@ -188,9 +182,8 @@ define half @fabs_copysign_flags(half %x, half %y) { ; CHECK-LABEL: @fabs_copysign_flags( -; CHECK-NEXT: [[COPYSIGN:%.*]] = call nnan half @llvm.copysign.f16(half [[X:%.*]], half [[Y:%.*]]) -; CHECK-NEXT: [[FABS_COPYSIGN:%.*]] = call nnan nsz half @llvm.fabs.f16(half [[COPYSIGN]]) -; CHECK-NEXT: ret half [[FABS_COPYSIGN]] +; CHECK-NEXT: [[TMP1:%.*]] = call nnan nsz half @llvm.fabs.f16(half [[X:%.*]]) +; CHECK-NEXT: ret half [[TMP1]] ; %copysign = call nnan half @llvm.copysign.f16(half %x, half %y) %fabs.copysign = call nsz nnan half @llvm.fabs.f16(half %copysign) @@ -199,9 +192,8 @@ define half @fabs_copysign_all_flags(half %x, half %y) { ; CHECK-LABEL: @fabs_copysign_all_flags( -; CHECK-NEXT: [[COPYSIGN:%.*]] = call fast half @llvm.copysign.f16(half [[X:%.*]], half [[Y:%.*]]) -; CHECK-NEXT: [[FABS_COPYSIGN:%.*]] = call fast half @llvm.fabs.f16(half [[COPYSIGN]]) -; CHECK-NEXT: ret half [[FABS_COPYSIGN]] +; CHECK-NEXT: [[TMP1:%.*]] = call fast half @llvm.fabs.f16(half [[X:%.*]]) +; CHECK-NEXT: ret half [[TMP1]] ; %copysign = call fast half @llvm.copysign.f16(half %x, half %y) %fabs.copysign = call fast half @llvm.fabs.f16(half %copysign) @@ -212,8 +204,8 @@ ; CHECK-LABEL: @fabs_copysign_no_flags_copysign_user( ; CHECK-NEXT: [[COPYSIGN:%.*]] = call half @llvm.copysign.f16(half [[X:%.*]], half [[Y:%.*]]) ; CHECK-NEXT: store half [[COPYSIGN]], ptr [[PTR:%.*]], align 2 -; CHECK-NEXT: [[FABS_COPYSIGN:%.*]] = call fast half @llvm.fabs.f16(half [[COPYSIGN]]) -; CHECK-NEXT: ret half [[FABS_COPYSIGN]] +; CHECK-NEXT: [[TMP1:%.*]] = call fast half @llvm.fabs.f16(half [[X]]) +; CHECK-NEXT: ret half [[TMP1]] ; %copysign = call half @llvm.copysign.f16(half %x, half %y) store half %copysign, ptr %ptr @@ -223,9 +215,8 @@ define half @fneg_fabs_copysign_drop_flags(half %x, half %y) { ; CHECK-LABEL: @fneg_fabs_copysign_drop_flags( -; CHECK-NEXT: [[COPYSIGN:%.*]] = call nnan half @llvm.copysign.f16(half [[X:%.*]], half [[Y:%.*]]) -; CHECK-NEXT: [[FABS_COPYSIGN:%.*]] = call ninf half @llvm.fabs.f16(half [[COPYSIGN]]) -; CHECK-NEXT: [[FNEG_FABS_COPYSIGN:%.*]] = fneg nsz half [[FABS_COPYSIGN]] +; CHECK-NEXT: [[TMP1:%.*]] = call ninf half @llvm.fabs.f16(half [[X:%.*]]) +; CHECK-NEXT: [[FNEG_FABS_COPYSIGN:%.*]] = fneg nsz half [[TMP1]] ; CHECK-NEXT: ret half [[FNEG_FABS_COPYSIGN]] ; %copysign = call nnan half @llvm.copysign.f16(half %x, half %y) @@ -251,8 +242,8 @@ ; CHECK-LABEL: @fabs_copysign_multi_use( ; CHECK-NEXT: [[COPYSIGN:%.*]] = call half @llvm.copysign.f16(half [[X:%.*]], half [[Y:%.*]]) ; CHECK-NEXT: store half [[COPYSIGN]], ptr [[PTR:%.*]], align 2 -; CHECK-NEXT: [[FABS_COPYSIGN:%.*]] = call half @llvm.fabs.f16(half [[COPYSIGN]]) -; CHECK-NEXT: ret half [[FABS_COPYSIGN]] +; CHECK-NEXT: [[TMP1:%.*]] = call half @llvm.fabs.f16(half [[X]]) +; CHECK-NEXT: ret half [[TMP1]] ; %copysign = call half @llvm.copysign.f16(half %x, half %y) store half %copysign, ptr %ptr @@ -264,8 +255,8 @@ ; CHECK-LABEL: @fabs_flags_copysign_multi_use( ; CHECK-NEXT: [[COPYSIGN:%.*]] = call half @llvm.copysign.f16(half [[X:%.*]], half [[Y:%.*]]) ; CHECK-NEXT: store half [[COPYSIGN]], ptr [[PTR:%.*]], align 2 -; CHECK-NEXT: [[FABS_COPYSIGN:%.*]] = call nnan ninf half @llvm.fabs.f16(half [[COPYSIGN]]) -; CHECK-NEXT: ret half [[FABS_COPYSIGN]] +; CHECK-NEXT: [[TMP1:%.*]] = call nnan ninf half @llvm.fabs.f16(half [[X]]) +; CHECK-NEXT: ret half [[TMP1]] ; %copysign = call half @llvm.copysign.f16(half %x, half %y) store half %copysign, ptr %ptr @@ -275,10 +266,9 @@ define half @fneg_fabs_copysign_multi_use_fabs(half %x, half %y, ptr %ptr) { ; CHECK-LABEL: @fneg_fabs_copysign_multi_use_fabs( -; CHECK-NEXT: [[COPYSIGN:%.*]] = call half @llvm.copysign.f16(half [[X:%.*]], half [[Y:%.*]]) -; CHECK-NEXT: [[FABS_COPYSIGN:%.*]] = call half @llvm.fabs.f16(half [[COPYSIGN]]) -; CHECK-NEXT: store half [[FABS_COPYSIGN]], ptr [[PTR:%.*]], align 2 -; CHECK-NEXT: ret half [[FABS_COPYSIGN]] +; CHECK-NEXT: [[TMP1:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) +; CHECK-NEXT: store half [[TMP1]], ptr [[PTR:%.*]], align 2 +; CHECK-NEXT: ret half [[TMP1]] ; %copysign = call half @llvm.copysign.f16(half %x, half %y) %fabs.copysign = call half @llvm.fabs.f16(half %copysign)