forked from OSchip/llvm-project
Fix fmul combines with constant splat vectors
Fixes things like fmul x, 2 -> fadd x, x llvm-svn: 215820
This commit is contained in:
parent
e020f117ce
commit
6cc00429ff
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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" }
|
Loading…
Reference in New Issue