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);
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(),
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.
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
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
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>
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
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
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>
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
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
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