Index: llvm/include/llvm/Analysis/InstructionSimplify.h =================================================================== --- llvm/include/llvm/Analysis/InstructionSimplify.h +++ llvm/include/llvm/Analysis/InstructionSimplify.h @@ -117,6 +117,10 @@ // deprecated. // Please use the SimplifyQuery versions in new code. +/// Given operand for an FNeg, fold the result or return null. +Value *SimplifyFNegInst(Value *Op, FastMathFlags FMF, + const SimplifyQuery &Q); + /// Given operands for an Add, fold the result or return null. Value *SimplifyAddInst(Value *LHS, Value *RHS, bool isNSW, bool isNUW, const SimplifyQuery &Q); @@ -227,6 +231,15 @@ Value *SimplifyCmpInst(unsigned Predicate, Value *LHS, Value *RHS, const SimplifyQuery &Q); +/// Given operand for a UnaryOperator, fold the result or return null. +Value *SimplifyUnOp(unsigned Opcode, Value *Op, const SimplifyQuery &Q); + +/// Given operand for an FP UnaryOperator, fold the result or return null. +/// In contrast to SimplifyUnOp, try to use FastMathFlag when folding the +/// result. In case we don't need FastMathFlags, simply fall to SimplifyUnOp. +Value *SimplifyFPUnOp(unsigned Opcode, Value *Op, FastMathFlags FMF, + const SimplifyQuery &Q); + /// Given operands for a BinaryOperator, fold the result or return null. Value *SimplifyBinOp(unsigned Opcode, Value *LHS, Value *RHS, const SimplifyQuery &Q); Index: llvm/lib/Analysis/InstructionSimplify.cpp =================================================================== --- llvm/lib/Analysis/InstructionSimplify.cpp +++ llvm/lib/Analysis/InstructionSimplify.cpp @@ -51,6 +51,9 @@ STATISTIC(NumReassoc, "Number of reassociations"); static Value *SimplifyAndInst(Value *, Value *, const SimplifyQuery &, unsigned); +static Value *SimplifyUnOp(unsigned, Value *, const SimplifyQuery &, unsigned); +static Value *SimplifyFPUnOp(unsigned, Value *, const FastMathFlags &, + const SimplifyQuery &, unsigned); static Value *SimplifyBinOp(unsigned, Value *, Value *, const SimplifyQuery &, unsigned); static Value *SimplifyFPBinOp(unsigned, Value *, Value *, const FastMathFlags &, @@ -4245,6 +4248,33 @@ return ::SimplifyShuffleVectorInst(Op0, Op1, Mask, RetTy, Q, RecursionLimit); } +static Constant *foldConstant(Instruction::UnaryOps Opcode, + Value *&Op, const SimplifyQuery &Q) { + if (auto *C = dyn_cast(Op)) + return ConstantFoldUnaryOpOperand(Opcode, C, Q.DL); + return nullptr; +} + +/// Given the operand for an FNeg, see if we can fold the result. If not, this +/// returns null. +static Value *SimplifyFNegInst(Value *Op, FastMathFlags FMF, + const SimplifyQuery &Q, unsigned MaxRecurse) { + if (Constant *C = foldConstant(Instruction::FNeg, Op, Q)) + return C; + + Value *X; + // fneg (fneg X) ==> X + if (match(Op, m_FNeg(m_Value(X)))) + return X; + + return nullptr; +} + +Value *llvm::SimplifyFNegInst(Value *Op, FastMathFlags FMF, + const SimplifyQuery &Q) { + return ::SimplifyFNegInst(Op, FMF, Q, RecursionLimit); +} + static Constant *propagateNaN(Constant *In) { // If the input is a vector with undef elements, just return a default NaN. if (!In->isNaN()) @@ -4472,6 +4502,38 @@ //=== Helper functions for higher up the class hierarchy. +/// Given the operand for a UnaryOperator, see if we can fold the result. +/// If not, this returns null. +static Value *SimplifyUnOp(unsigned Opcode, Value *Op, const SimplifyQuery &Q, + unsigned MaxRecurse) { + switch (Opcode) { + case Instruction::FNeg: + return SimplifyFNegInst(Op, FastMathFlags(), Q, MaxRecurse); + default: + llvm_unreachable("Unexpected opcode"); + } +} + +/// Given the operand for a UnaryOperator, see if we can fold the result. +/// If not, this returns null. +/// In contrast to SimplifyUnOp, try to use FastMathFlag when folding the +/// result. In case we don't need FastMathFlags, simply fall to SimplifyUnOp. +static Value *SimplifyFPUnOp(unsigned Opcode, Value *Op, + const FastMathFlags &FMF, + const SimplifyQuery &Q, unsigned MaxRecurse) { + switch (Opcode) { + case Instruction::FNeg: + return SimplifyFNegInst(Op, FMF, Q, MaxRecurse); + default: + return SimplifyUnOp(Opcode, Op, Q, MaxRecurse); + } +} + +Value *llvm::SimplifyFPUnOp(unsigned Opcode, Value *Op, FastMathFlags FMF, + const SimplifyQuery &Q) { + return ::SimplifyFPUnOp(Opcode, Op, FMF, Q, RecursionLimit); +} + /// Given operands for a BinaryOperator, see if we can fold the result. /// If not, this returns null. static Value *SimplifyBinOp(unsigned Opcode, Value *LHS, Value *RHS, @@ -4959,6 +5021,9 @@ default: Result = ConstantFoldInstruction(I, Q.DL, Q.TLI); break; + case Instruction::FNeg: + Result = SimplifyFNegInst(I->getOperand(0), I->getFastMathFlags(), Q); + break; case Instruction::FAdd: Result = SimplifyFAddInst(I->getOperand(0), I->getOperand(1), I->getFastMathFlags(), Q); Index: llvm/test/Analysis/ConstantFolding/fneg.ll =================================================================== --- llvm/test/Analysis/ConstantFolding/fneg.ll +++ llvm/test/Analysis/ConstantFolding/fneg.ll @@ -17,17 +17,6 @@ ret float %r } -define float @fneg_fneg_var(float %a) { -; CHECK-LABEL: @fneg_fneg_var( -; CHECK-NEXT: [[R:%.*]] = fneg float [[A:%.*]] -; CHECK-NEXT: [[R1:%.*]] = fneg float [[R]] -; CHECK-NEXT: ret float [[R1]] -; - %r = fneg float %a - %r1 = fneg float %r - ret float %r1 -} - define <4 x float> @fneg_constant_elts_v4f32() { ; CHECK-LABEL: @fneg_constant_elts_v4f32( ; CHECK-NEXT: ret <4 x float> Index: llvm/test/Transforms/InstSimplify/floating-point-arithmetic.ll =================================================================== --- llvm/test/Transforms/InstSimplify/floating-point-arithmetic.ll +++ llvm/test/Transforms/InstSimplify/floating-point-arithmetic.ll @@ -1,6 +1,15 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -instsimplify -S | FileCheck %s +define float @fneg_fneg_var(float %a) { +; CHECK-LABEL: @fneg_fneg_var( +; CHECK-NEXT: ret float [[A:%.*]] +; + %r = fneg float %a + %r1 = fneg float %r + ret float %r1 +} + define <2 x float> @fsub_negzero_vec_undef_elts(<2 x float> %x) { ; CHECK-LABEL: @fsub_negzero_vec_undef_elts( ; CHECK-NEXT: ret <2 x float> [[X:%.*]]