Index: llvm/include/llvm/IR/InstrTypes.h =================================================================== --- llvm/include/llvm/IR/InstrTypes.h +++ llvm/include/llvm/IR/InstrTypes.h @@ -225,39 +225,39 @@ static BinaryOperator *CreateWithCopiedFlags(BinaryOps Opc, Value *V1, Value *V2, - BinaryOperator *CopyBO, + Instruction *CopyO, const Twine &Name = "") { BinaryOperator *BO = Create(Opc, V1, V2, Name); - BO->copyIRFlags(CopyBO); + BO->copyIRFlags(CopyO); return BO; } static BinaryOperator *CreateFAddFMF(Value *V1, Value *V2, - BinaryOperator *FMFSource, + Instruction *FMFSource, const Twine &Name = "") { return CreateWithCopiedFlags(Instruction::FAdd, V1, V2, FMFSource, Name); } static BinaryOperator *CreateFSubFMF(Value *V1, Value *V2, - BinaryOperator *FMFSource, + Instruction *FMFSource, const Twine &Name = "") { return CreateWithCopiedFlags(Instruction::FSub, V1, V2, FMFSource, Name); } static BinaryOperator *CreateFMulFMF(Value *V1, Value *V2, - BinaryOperator *FMFSource, + Instruction *FMFSource, const Twine &Name = "") { return CreateWithCopiedFlags(Instruction::FMul, V1, V2, FMFSource, Name); } static BinaryOperator *CreateFDivFMF(Value *V1, Value *V2, - BinaryOperator *FMFSource, + Instruction *FMFSource, const Twine &Name = "") { return CreateWithCopiedFlags(Instruction::FDiv, V1, V2, FMFSource, Name); } static BinaryOperator *CreateFRemFMF(Value *V1, Value *V2, - BinaryOperator *FMFSource, + Instruction *FMFSource, const Twine &Name = "") { return CreateWithCopiedFlags(Instruction::FRem, V1, V2, FMFSource, Name); } - static BinaryOperator *CreateFNegFMF(Value *Op, BinaryOperator *FMFSource, + static BinaryOperator *CreateFNegFMF(Value *Op, Instruction *FMFSource, const Twine &Name = "") { Value *Zero = ConstantFP::getNegativeZero(Op->getType()); return CreateWithCopiedFlags(Instruction::FSub, Zero, Op, FMFSource); Index: llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -1821,6 +1821,32 @@ return Changed ? &I : nullptr; } +static Instruction *foldFNegIntoConstant(Instruction &I) { + Value *X; + Constant *C; + + // Fold negation into constant operand. This is limited with one-use because + // fneg is assumed better for analysis and cheaper in codegen than fmul/fdiv. + // -(X * C) --> X * (-C) + if (match(&I, m_FNeg(m_OneUse(m_FMul(m_Value(X), m_Constant(C)))))) + return BinaryOperator::CreateFMulFMF(X, ConstantExpr::getFNeg(C), &I); + // -(X / C) --> X / (-C) + if (match(&I, m_FNeg(m_OneUse(m_FDiv(m_Value(X), m_Constant(C)))))) + return BinaryOperator::CreateFDivFMF(X, ConstantExpr::getFNeg(C), &I); + // -(C / X) --> (-C) / X + if (match(&I, m_FNeg(m_OneUse(m_FDiv(m_Constant(C), m_Value(X)))))) + return BinaryOperator::CreateFDivFMF(ConstantExpr::getFNeg(C), X, &I); + + return nullptr; +} + +Instruction *InstCombiner::visitFNeg(UnaryOperator &I) { + if (Instruction *X = foldFNegIntoConstant(I)) + return X; + + return nullptr; +} + Instruction *InstCombiner::visitFSub(BinaryOperator &I) { if (Value *V = SimplifyFSubInst(I.getOperand(0), I.getOperand(1), I.getFastMathFlags(), @@ -1836,21 +1862,12 @@ if (I.hasNoSignedZeros() && match(Op0, m_PosZeroFP())) return BinaryOperator::CreateFNegFMF(Op1, &I); + if (Instruction *X = foldFNegIntoConstant(I)) + return X; + Value *X, *Y; Constant *C; - // Fold negation into constant operand. This is limited with one-use because - // fneg is assumed better for analysis and cheaper in codegen than fmul/fdiv. - // -(X * C) --> X * (-C) - if (match(&I, m_FNeg(m_OneUse(m_FMul(m_Value(X), m_Constant(C)))))) - return BinaryOperator::CreateFMulFMF(X, ConstantExpr::getFNeg(C), &I); - // -(X / C) --> X / (-C) - if (match(&I, m_FNeg(m_OneUse(m_FDiv(m_Value(X), m_Constant(C)))))) - return BinaryOperator::CreateFDivFMF(X, ConstantExpr::getFNeg(C), &I); - // -(C / X) --> (-C) / X - if (match(&I, m_FNeg(m_OneUse(m_FDiv(m_Constant(C), m_Value(X)))))) - return BinaryOperator::CreateFDivFMF(ConstantExpr::getFNeg(C), X, &I); - // If Op0 is not -0.0 or we can ignore -0.0: Z - (X - Y) --> Z + (Y - X) // Canonicalize to fadd to make analysis easier. // This can also help codegen because fadd is commutative. Index: llvm/lib/Transforms/InstCombine/InstCombineInternal.h =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineInternal.h +++ llvm/lib/Transforms/InstCombine/InstCombineInternal.h @@ -347,6 +347,7 @@ // I - Change was made, I is still valid, I may be dead though // otherwise - Change was made, replace I with returned instruction // + Instruction *visitFNeg(UnaryOperator &I); Instruction *visitAdd(BinaryOperator &I); Instruction *visitFAdd(BinaryOperator &I); Value *OptimizePointerDifference(Value *LHS, Value *RHS, Type *Ty); Index: llvm/test/Transforms/InstCombine/fneg.ll =================================================================== --- llvm/test/Transforms/InstCombine/fneg.ll +++ llvm/test/Transforms/InstCombine/fneg.ll @@ -17,8 +17,7 @@ define float @fmul_fneg(float %x) { ; CHECK-LABEL: @fmul_fneg( -; CHECK-NEXT: [[M:%.*]] = fmul float [[X:%.*]], 4.200000e+01 -; CHECK-NEXT: [[R:%.*]] = fneg float [[M]] +; CHECK-NEXT: [[R:%.*]] = fmul float [[X:%.*]], -4.200000e+01 ; CHECK-NEXT: ret float [[R]] ; %m = fmul float %x, 42.0 @@ -40,8 +39,7 @@ define float @fmul_fneg_fmf(float %x) { ; CHECK-LABEL: @fmul_fneg_fmf( -; CHECK-NEXT: [[M:%.*]] = fmul float [[X:%.*]], 4.200000e+01 -; CHECK-NEXT: [[R:%.*]] = fneg reassoc nsz float [[M]] +; CHECK-NEXT: [[R:%.*]] = fmul reassoc nsz float [[X:%.*]], -4.200000e+01 ; CHECK-NEXT: ret float [[R]] ; %m = fmul float %x, 42.0 @@ -91,8 +89,7 @@ define <4 x double> @fmul_fneg_vec(<4 x double> %x) { ; CHECK-LABEL: @fmul_fneg_vec( -; CHECK-NEXT: [[M:%.*]] = fmul <4 x double> [[X:%.*]], -; CHECK-NEXT: [[R:%.*]] = fneg <4 x double> [[M]] +; CHECK-NEXT: [[R:%.*]] = fmul <4 x double> [[X:%.*]], ; CHECK-NEXT: ret <4 x double> [[R]] ; %m = fmul <4 x double> %x, @@ -114,8 +111,7 @@ define float @fdiv_op1_constant_fneg(float %x) { ; CHECK-LABEL: @fdiv_op1_constant_fneg( -; CHECK-NEXT: [[D:%.*]] = fdiv float [[X:%.*]], -4.200000e+01 -; CHECK-NEXT: [[R:%.*]] = fneg float [[D]] +; CHECK-NEXT: [[R:%.*]] = fdiv float [[X:%.*]], 4.200000e+01 ; CHECK-NEXT: ret float [[R]] ; %d = fdiv float %x, -42.0 @@ -137,8 +133,7 @@ define float @fdiv_op1_constant_fneg_fmf(float %x) { ; CHECK-LABEL: @fdiv_op1_constant_fneg_fmf( -; CHECK-NEXT: [[D:%.*]] = fdiv float [[X:%.*]], -4.200000e+01 -; CHECK-NEXT: [[R:%.*]] = fneg nnan float [[D]] +; CHECK-NEXT: [[R:%.*]] = fdiv nnan float [[X:%.*]], 4.200000e+01 ; CHECK-NEXT: ret float [[R]] ; %d = fdiv float %x, -42.0 @@ -188,8 +183,7 @@ define <4 x double> @fdiv_op1_constant_fneg_vec(<4 x double> %x) { ; CHECK-LABEL: @fdiv_op1_constant_fneg_vec( -; CHECK-NEXT: [[D:%.*]] = fdiv <4 x double> [[X:%.*]], -; CHECK-NEXT: [[R:%.*]] = fneg <4 x double> [[D]] +; CHECK-NEXT: [[R:%.*]] = fdiv <4 x double> [[X:%.*]], ; CHECK-NEXT: ret <4 x double> [[R]] ; %d = fdiv <4 x double> %x, @@ -211,8 +205,7 @@ define float @fdiv_op0_constant_fneg(float %x) { ; CHECK-LABEL: @fdiv_op0_constant_fneg( -; CHECK-NEXT: [[D:%.*]] = fdiv float 4.200000e+01, [[X:%.*]] -; CHECK-NEXT: [[R:%.*]] = fneg float [[D]] +; CHECK-NEXT: [[R:%.*]] = fdiv float -4.200000e+01, [[X:%.*]] ; CHECK-NEXT: ret float [[R]] ; %d = fdiv float 42.0, %x @@ -234,8 +227,7 @@ define float @fdiv_op0_constant_fneg_fmf(float %x) { ; CHECK-LABEL: @fdiv_op0_constant_fneg_fmf( -; CHECK-NEXT: [[D:%.*]] = fdiv float 4.200000e+01, [[X:%.*]] -; CHECK-NEXT: [[R:%.*]] = fneg fast float [[D]] +; CHECK-NEXT: [[R:%.*]] = fdiv fast float -4.200000e+01, [[X:%.*]] ; CHECK-NEXT: ret float [[R]] ; %d = fdiv float 42.0, %x @@ -285,8 +277,7 @@ define <4 x double> @fdiv_op0_constant_fneg_vec(<4 x double> %x) { ; CHECK-LABEL: @fdiv_op0_constant_fneg_vec( -; CHECK-NEXT: [[D:%.*]] = fdiv <4 x double> , [[X:%.*]] -; CHECK-NEXT: [[R:%.*]] = fneg <4 x double> [[D]] +; CHECK-NEXT: [[R:%.*]] = fdiv <4 x double> , [[X:%.*]] ; CHECK-NEXT: ret <4 x double> [[R]] ; %d = fdiv <4 x double> , %x