Fix fmul combines with constant splat vectors

Fixes things like fmul x, 2 -> fadd x, x

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@215820 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Matt Arsenault 2014-08-16 10:14:19 +00:00
parent a3805f1c73
commit 5f8a9ae17c
3 changed files with 129 additions and 13 deletions

View File

@ -701,6 +701,27 @@ static ConstantSDNode *isConstOrConstSplat(SDValue N) {
return nullptr;
}
// \brief Returns the SDNode if it is a constant splat BuildVector or constant
// float.
static ConstantFPSDNode *isConstOrConstSplatFP(SDValue N) {
if (ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(N))
return CN;
if (BuildVectorSDNode *BV = dyn_cast<BuildVectorSDNode>(N)) {
BitVector UndefElements;
ConstantFPSDNode *CN = BV->getConstantFPSplatNode(&UndefElements);
// BuildVectors can truncate their operands. Ignore that case here.
// FIXME: We blindly ignore splats which include undef which is overly
// pessimistic.
if (CN && UndefElements.none() &&
CN->getValueType(0) == N.getValueType().getScalarType())
return CN;
}
return nullptr;
}
SDValue DAGCombiner::ReassociateOps(unsigned Opc, SDLoc DL,
SDValue N0, SDValue N1) {
EVT VT = N0.getValueType();
@ -6830,8 +6851,8 @@ SDValue DAGCombiner::visitFSUB(SDNode *N) {
SDValue DAGCombiner::visitFMUL(SDNode *N) {
SDValue N0 = N->getOperand(0);
SDValue N1 = N->getOperand(1);
ConstantFPSDNode *N0CFP = dyn_cast<ConstantFPSDNode>(N0);
ConstantFPSDNode *N1CFP = dyn_cast<ConstantFPSDNode>(N1);
ConstantFPSDNode *N0CFP = isConstOrConstSplatFP(N0);
ConstantFPSDNode *N1CFP = isConstOrConstSplatFP(N1);
EVT VT = N->getValueType(0);
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
@ -6851,13 +6872,10 @@ SDValue DAGCombiner::visitFMUL(SDNode *N) {
if (DAG.getTarget().Options.UnsafeFPMath &&
N1CFP && N1CFP->getValueAPF().isZero())
return N1;
// fold (fmul A, 0) -> 0, vector edition.
if (DAG.getTarget().Options.UnsafeFPMath &&
ISD::isBuildVectorAllZeros(N1.getNode()))
return N1;
// fold (fmul A, 1.0) -> A
if (N1CFP && N1CFP->isExactlyValue(1.0))
return N0;
// fold (fmul X, 2.0) -> (fadd X, X)
if (N1CFP && N1CFP->isExactlyValue(+2.0))
return DAG.getNode(ISD::FADD, SDLoc(N), VT, N0, N0);
@ -6883,10 +6901,11 @@ SDValue DAGCombiner::visitFMUL(SDNode *N) {
// If allowed, fold (fmul (fmul x, c1), c2) -> (fmul x, (fmul c1, c2))
if (DAG.getTarget().Options.UnsafeFPMath &&
N1CFP && N0.getOpcode() == ISD::FMUL &&
N0.getNode()->hasOneUse() && isa<ConstantFPSDNode>(N0.getOperand(1)))
N0.getNode()->hasOneUse() && isConstOrConstSplatFP(N0.getOperand(1))) {
return DAG.getNode(ISD::FMUL, SDLoc(N), VT, N0.getOperand(0),
DAG.getNode(ISD::FMUL, SDLoc(N), VT,
N0.getOperand(1), N1));
}
return SDValue();
}

View File

@ -276,8 +276,8 @@ define void @fexp2_v4f32_2(<4 x float>* %c, <4 x float>* %a) nounwind {
; CHECK-DAG: ld.w [[R1:\$w[0-9]+]], 0($5)
%2 = tail call <4 x float> @llvm.exp2.v4f32 (<4 x float> %1)
%3 = fmul <4 x float> <float 2.0, float 2.0, float 2.0, float 2.0>, %2
; CHECK-DAG: lui [[R3:\$[0-9]+]], 16384
; CHECK-DAG: fill.w [[R4:\$w[0-9]+]], [[R3]]
; CHECK-DAG: ldi.w [[R3:\$w[0-9]+]], 1
; CHECK-DAG: ffint_u.w [[R4:\$w[0-9]+]], [[R3]]
; CHECK-DAG: fexp2.w [[R5:\$w[0-9]+]], [[R4]], [[R1]]
store <4 x float> %3, <4 x float>* %c
; CHECK-DAG: st.w [[R5]], 0($4)
@ -287,16 +287,14 @@ define void @fexp2_v4f32_2(<4 x float>* %c, <4 x float>* %a) nounwind {
}
define void @fexp2_v2f64_2(<2 x double>* %c, <2 x double>* %a) nounwind {
; CHECK: .8byte 4611686018427387904
; CHECK-NEXT: .8byte 4611686018427387904
; CHECK: fexp2_v2f64_2:
%1 = load <2 x double>* %a
; CHECK-DAG: ld.d [[R1:\$w[0-9]+]], 0($5)
%2 = tail call <2 x double> @llvm.exp2.v2f64 (<2 x double> %1)
%3 = fmul <2 x double> <double 2.0, double 2.0>, %2
; CHECK-DAG: addiu [[G_PTR:\$[0-9]+]], {{.*}}, %lo($
; CHECK-DAG: ld.d [[R3:\$w[0-9]+]], 0([[G_PTR]])
; CHECK-DAG: ldi.d [[R2:\$w[0-9]+]], 1
; CHECK-DAG: ffint_u.d [[R3:\$w[0-9]+]], [[R2]]
; CHECK-DAG: fexp2.d [[R4:\$w[0-9]+]], [[R3]], [[R1]]
store <2 x double> %3, <2 x double>* %c
; CHECK-DAG: st.d [[R4]], 0($4)

View File

@ -0,0 +1,99 @@
; RUN: llc -march=x86-64 < %s | FileCheck %s
; CHECK-LABEL: fmul2_f32:
; CHECK: addss %xmm0, %xmm0
define float @fmul2_f32(float %x) {
%y = fmul float %x, 2.0
ret float %y
}
; fmul 2.0, x -> fadd x, x for vectors.
; CHECK-LABEL: fmul2_v4f32:
; CHECK: addps %xmm0, %xmm0
; CHECK-NEXT: retq
define <4 x float> @fmul2_v4f32(<4 x float> %x) {
%y = fmul <4 x float> %x, <float 2.0, float 2.0, float 2.0, float 2.0>
ret <4 x float> %y
}
; CHECK-LABEL: constant_fold_fmul_v4f32:
; CHECK: movaps
; CHECK-NEXT: ret
define <4 x float> @constant_fold_fmul_v4f32(<4 x float> %x) {
%y = fmul <4 x float> <float 4.0, float 4.0, float 4.0, float 4.0>, <float 2.0, float 2.0, float 2.0, float 2.0>
ret <4 x float> %y
}
; CHECK-LABEL: fmul0_v4f32:
; CHECK: xorps %xmm0, %xmm0
; CHECK-NEXT: retq
define <4 x float> @fmul0_v4f32(<4 x float> %x) #0 {
%y = fmul <4 x float> %x, <float 0.0, float 0.0, float 0.0, float 0.0>
ret <4 x float> %y
}
; CHECK-LABEL: fmul_c2_c4_v4f32:
; CHECK-NOT: addps
; CHECK: mulps
; CHECK-NOT: mulps
; CHECK-NEXT: ret
define <4 x float> @fmul_c2_c4_v4f32(<4 x float> %x) #0 {
%y = fmul <4 x float> %x, <float 2.0, float 2.0, float 2.0, float 2.0>
%z = fmul <4 x float> %y, <float 4.0, float 4.0, float 4.0, float 4.0>
ret <4 x float> %z
}
; CHECK-LABEL: fmul_c3_c4_v4f32:
; CHECK-NOT: addps
; CHECK: mulps
; CHECK-NOT: mulps
; CHECK-NEXT: ret
define <4 x float> @fmul_c3_c4_v4f32(<4 x float> %x) #0 {
%y = fmul <4 x float> %x, <float 3.0, float 3.0, float 3.0, float 3.0>
%z = fmul <4 x float> %y, <float 4.0, float 4.0, float 4.0, float 4.0>
ret <4 x float> %z
}
; CHECK-LABEL: fmul_c2_c4_f32:
; CHECK-NOT: addss
; CHECK: mulss
; CHECK-NOT: mulss
; CHECK-NEXT: ret
define float @fmul_c2_c4_f32(float %x) #0 {
%y = fmul float %x, 2.0
%z = fmul float %y, 4.0
ret float %z
}
; CHECK-LABEL: fmul_c3_c4_f32:
; CHECK-NOT: addss
; CHECK: mulss
; CHECK-NOT: mulss
; CHECK-NET: ret
define float @fmul_c3_c4_f32(float %x) #0 {
%y = fmul float %x, 3.0
%z = fmul float %y, 4.0
ret float %z
}
; CHECK-LABEL: fmul_fneg_fneg_f32:
; CHECK: mulss %xmm1, %xmm0
; CHECK-NEXT: retq
define float @fmul_fneg_fneg_f32(float %x, float %y) {
%x.neg = fsub float -0.0, %x
%y.neg = fsub float -0.0, %y
%mul = fmul float %x.neg, %y.neg
ret float %mul
}
; CHECK-LABEL: fmul_fneg_fneg_v4f32:
; CHECK: mulps %xmm1, %xmm0
; CHECK-NEXT: retq
define <4 x float> @fmul_fneg_fneg_v4f32(<4 x float> %x, <4 x float> %y) {
%x.neg = fsub <4 x float> <float -0.0, float -0.0, float -0.0, float -0.0>, %x
%y.neg = fsub <4 x float> <float -0.0, float -0.0, float -0.0, float -0.0>, %y
%mul = fmul <4 x float> %x.neg, %y.neg
ret <4 x float> %mul
}
attributes #0 = { "less-precise-fpmad"="true" "no-infs-fp-math"="true" "no-nans-fp-math"="true" "unsafe-fp-math"="true" }