[InstCombine] Add visitFNeg(...) visitor for unary Fneg
Also, break out a helper function, namely foldFNegIntoConstant(...), which performs transforms common between visitFNeg(...) and visitFSub(...). Differential Revision: https://reviews.llvm.org/D61693 llvm-svn: 361188
This commit is contained in:
parent
31cc510980
commit
2557ca296a
@ -225,39 +225,39 @@ public:
|
||||
|
||||
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);
|
||||
|
||||
@ -1821,15 +1821,38 @@ Instruction *InstCombiner::visitSub(BinaryOperator &I) {
|
||||
return Changed ? &I : nullptr;
|
||||
}
|
||||
|
||||
/// This eliminates floating-point negation in either 'fneg(X)' or
|
||||
/// 'fsub(-0.0, X)' form by combining into a constant operand.
|
||||
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 (Value *V = SimplifyFNegInst(I.getOperand(0), I.getFastMathFlags(),
|
||||
SQ.getWithInstruction(&I)))
|
||||
return replaceInstUsesWith(I, V);
|
||||
|
||||
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(),
|
||||
@ -1845,21 +1868,12 @@ Instruction *InstCombiner::visitFSub(BinaryOperator &I) {
|
||||
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.
|
||||
|
||||
@ -27,8 +27,7 @@ define float @fmul_fsub(float %x) {
|
||||
|
||||
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
|
||||
@ -50,8 +49,7 @@ define float @fmul_fsub_fmf(float %x) {
|
||||
|
||||
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
|
||||
@ -101,8 +99,7 @@ define <4 x double> @fmul_fsub_vec(<4 x double> %x) {
|
||||
|
||||
define <4 x double> @fmul_fneg_vec(<4 x double> %x) {
|
||||
; CHECK-LABEL: @fmul_fneg_vec(
|
||||
; CHECK-NEXT: [[M:%.*]] = fmul <4 x double> [[X:%.*]], <double 4.200000e+01, double 0xFF80000000000000, double 0x7FF0000000000000, double undef>
|
||||
; CHECK-NEXT: [[R:%.*]] = fneg <4 x double> [[M]]
|
||||
; CHECK-NEXT: [[R:%.*]] = fmul <4 x double> [[X:%.*]], <double -4.200000e+01, double 0x7F80000000000000, double 0xFFF0000000000000, double undef>
|
||||
; CHECK-NEXT: ret <4 x double> [[R]]
|
||||
;
|
||||
%m = fmul <4 x double> %x, <double 42.0, double 0x7FF80000000000000, double 0x7FF0000000000000, double undef>
|
||||
@ -124,8 +121,7 @@ define float @fdiv_op1_constant_fsub(float %x) {
|
||||
|
||||
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
|
||||
@ -147,8 +143,7 @@ define float @fdiv_op1_constant_fsub_fmf(float %x) {
|
||||
|
||||
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
|
||||
@ -198,8 +193,7 @@ define <4 x double> @fdiv_op1_constant_fsub_vec(<4 x double> %x) {
|
||||
|
||||
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:%.*]], <double -4.200000e+01, double 0xFFF800000ABCD000, double 0xFFF0000000000000, double undef>
|
||||
; CHECK-NEXT: [[R:%.*]] = fneg <4 x double> [[D]]
|
||||
; CHECK-NEXT: [[R:%.*]] = fdiv <4 x double> [[X:%.*]], <double 4.200000e+01, double 0x7FF800000ABCD000, double 0x7FF0000000000000, double undef>
|
||||
; CHECK-NEXT: ret <4 x double> [[R]]
|
||||
;
|
||||
%d = fdiv <4 x double> %x, <double -42.0, double 0xFFF800000ABCD000, double 0xFFF0000000000000, double undef>
|
||||
@ -221,8 +215,7 @@ define float @fdiv_op0_constant_fsub(float %x) {
|
||||
|
||||
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
|
||||
@ -244,8 +237,7 @@ define float @fdiv_op0_constant_fsub_fmf(float %x) {
|
||||
|
||||
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
|
||||
@ -295,8 +287,7 @@ define <4 x double> @fdiv_op0_constant_fsub_vec(<4 x double> %x) {
|
||||
|
||||
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> <double -4.200000e+01, double 0xFF80000000000000, double 0xFFF0000000000000, double undef>, [[X:%.*]]
|
||||
; CHECK-NEXT: [[R:%.*]] = fneg <4 x double> [[D]]
|
||||
; CHECK-NEXT: [[R:%.*]] = fdiv <4 x double> <double 4.200000e+01, double 0x7F80000000000000, double 0x7FF0000000000000, double undef>, [[X:%.*]]
|
||||
; CHECK-NEXT: ret <4 x double> [[R]]
|
||||
;
|
||||
%d = fdiv <4 x double> <double -42.0, double 0x7FF80000000000000, double 0xFFF0000000000000, double undef>, %x
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user