Add FNeg support to InstructionSimplify

Differential Revision: https://reviews.llvm.org/D61573

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@360053 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Cameron McInally 2019-05-06 16:05:10 +00:00
parent 0f6bb4c806
commit a0a00583bd
4 changed files with 87 additions and 11 deletions

View File

@ -117,6 +117,10 @@ struct SimplifyQuery {
// 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 *SimplifyShuffleVectorInst(Value *Op0, Value *Op1, Constant *Mask,
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);

View File

@ -51,6 +51,9 @@ STATISTIC(NumExpand, "Number of expansions");
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 @@ Value *llvm::SimplifyShuffleVectorInst(Value *Op0, Value *Op1, Constant *Mask,
return ::SimplifyShuffleVectorInst(Op0, Op1, Mask, RetTy, Q, RecursionLimit);
}
static Constant *foldConstant(Instruction::UnaryOps Opcode,
Value *&Op, const SimplifyQuery &Q) {
if (auto *C = dyn_cast<Constant>(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 @@ Value *llvm::SimplifyFRemInst(Value *Op0, Value *Op1, FastMathFlags FMF,
//=== 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 @@ Value *llvm::SimplifyInstruction(Instruction *I, const SimplifyQuery &SQ,
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);

View File

@ -17,17 +17,6 @@ define float @fneg_undef() {
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> <float 0.000000e+00, float -0.000000e+00, float 1.000000e+00, float -1.000000e+00>

View File

@ -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:%.*]]