mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-13 23:18:58 +00:00
[DAGCombine] Support FMF contract in fused multiple-and-sub too
This is a follow-on to r299096 which added support for fmadd. Subtract does not have the case where with two multiply operands we commute in order to fuse with the multiply with the fewer uses. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@299572 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
0a518c38de
commit
c0a481413e
@ -8909,23 +8909,26 @@ SDValue DAGCombiner::visitFSUBForFMACombine(SDNode *N) {
|
||||
SDLoc SL(N);
|
||||
|
||||
const TargetOptions &Options = DAG.getTarget().Options;
|
||||
bool AllowFusion =
|
||||
(Options.AllowFPOpFusion == FPOpFusion::Fast || Options.UnsafeFPMath);
|
||||
|
||||
// Floating-point multiply-add with intermediate rounding.
|
||||
bool HasFMAD = (LegalOperations && TLI.isOperationLegal(ISD::FMAD, VT));
|
||||
|
||||
// Floating-point multiply-add without intermediate rounding.
|
||||
bool HasFMA =
|
||||
AllowFusion && TLI.isFMAFasterThanFMulAndFAdd(VT) &&
|
||||
TLI.isFMAFasterThanFMulAndFAdd(VT) &&
|
||||
(!LegalOperations || TLI.isOperationLegalOrCustom(ISD::FMA, VT));
|
||||
|
||||
// No valid opcode, do not combine.
|
||||
if (!HasFMAD && !HasFMA)
|
||||
return SDValue();
|
||||
|
||||
bool AllowFusionGlobally = (Options.AllowFPOpFusion == FPOpFusion::Fast ||
|
||||
Options.UnsafeFPMath || HasFMAD);
|
||||
// If the subtraction is not contractable, do not combine.
|
||||
if (!AllowFusionGlobally && !isContractable(N))
|
||||
return SDValue();
|
||||
|
||||
const SelectionDAGTargetInfo *STI = DAG.getSubtarget().getSelectionDAGInfo();
|
||||
if (AllowFusion && STI && STI->generateFMAsInMachineCombiner(OptLevel))
|
||||
if (STI && STI->generateFMAsInMachineCombiner(OptLevel))
|
||||
return SDValue();
|
||||
|
||||
// Always prefer FMAD to FMA for precision.
|
||||
@ -8933,9 +8936,16 @@ SDValue DAGCombiner::visitFSUBForFMACombine(SDNode *N) {
|
||||
bool Aggressive = TLI.enableAggressiveFMAFusion(VT);
|
||||
bool LookThroughFPExt = TLI.isFPExtFree(VT);
|
||||
|
||||
// Is the node an FMUL and contractable either due to global flags or
|
||||
// SDNodeFlags.
|
||||
auto isContractableFMUL = [AllowFusionGlobally](SDValue N) {
|
||||
if (N.getOpcode() != ISD::FMUL)
|
||||
return false;
|
||||
return AllowFusionGlobally || isContractable(N.getNode());
|
||||
};
|
||||
|
||||
// fold (fsub (fmul x, y), z) -> (fma x, y, (fneg z))
|
||||
if (N0.getOpcode() == ISD::FMUL &&
|
||||
(Aggressive || N0->hasOneUse())) {
|
||||
if (isContractableFMUL(N0) && (Aggressive || N0->hasOneUse())) {
|
||||
return DAG.getNode(PreferredFusedOpcode, SL, VT,
|
||||
N0.getOperand(0), N0.getOperand(1),
|
||||
DAG.getNode(ISD::FNEG, SL, VT, N1));
|
||||
@ -8943,16 +8953,14 @@ SDValue DAGCombiner::visitFSUBForFMACombine(SDNode *N) {
|
||||
|
||||
// fold (fsub x, (fmul y, z)) -> (fma (fneg y), z, x)
|
||||
// Note: Commutes FSUB operands.
|
||||
if (N1.getOpcode() == ISD::FMUL &&
|
||||
(Aggressive || N1->hasOneUse()))
|
||||
if (isContractableFMUL(N1) && (Aggressive || N1->hasOneUse()))
|
||||
return DAG.getNode(PreferredFusedOpcode, SL, VT,
|
||||
DAG.getNode(ISD::FNEG, SL, VT,
|
||||
N1.getOperand(0)),
|
||||
N1.getOperand(1), N0);
|
||||
|
||||
// fold (fsub (fneg (fmul, x, y)), z) -> (fma (fneg x), y, (fneg z))
|
||||
if (N0.getOpcode() == ISD::FNEG &&
|
||||
N0.getOperand(0).getOpcode() == ISD::FMUL &&
|
||||
if (N0.getOpcode() == ISD::FNEG && isContractableFMUL(N0.getOperand(0)) &&
|
||||
(Aggressive || (N0->hasOneUse() && N0.getOperand(0).hasOneUse()))) {
|
||||
SDValue N00 = N0.getOperand(0).getOperand(0);
|
||||
SDValue N01 = N0.getOperand(0).getOperand(1);
|
||||
@ -8962,12 +8970,12 @@ SDValue DAGCombiner::visitFSUBForFMACombine(SDNode *N) {
|
||||
}
|
||||
|
||||
// Look through FP_EXTEND nodes to do more combining.
|
||||
if (AllowFusion && LookThroughFPExt) {
|
||||
if (LookThroughFPExt) {
|
||||
// fold (fsub (fpext (fmul x, y)), z)
|
||||
// -> (fma (fpext x), (fpext y), (fneg z))
|
||||
if (N0.getOpcode() == ISD::FP_EXTEND) {
|
||||
SDValue N00 = N0.getOperand(0);
|
||||
if (N00.getOpcode() == ISD::FMUL)
|
||||
if (isContractableFMUL(N00))
|
||||
return DAG.getNode(PreferredFusedOpcode, SL, VT,
|
||||
DAG.getNode(ISD::FP_EXTEND, SL, VT,
|
||||
N00.getOperand(0)),
|
||||
@ -8981,7 +8989,7 @@ SDValue DAGCombiner::visitFSUBForFMACombine(SDNode *N) {
|
||||
// Note: Commutes FSUB operands.
|
||||
if (N1.getOpcode() == ISD::FP_EXTEND) {
|
||||
SDValue N10 = N1.getOperand(0);
|
||||
if (N10.getOpcode() == ISD::FMUL)
|
||||
if (isContractableFMUL(N10))
|
||||
return DAG.getNode(PreferredFusedOpcode, SL, VT,
|
||||
DAG.getNode(ISD::FNEG, SL, VT,
|
||||
DAG.getNode(ISD::FP_EXTEND, SL, VT,
|
||||
@ -9001,7 +9009,7 @@ SDValue DAGCombiner::visitFSUBForFMACombine(SDNode *N) {
|
||||
SDValue N00 = N0.getOperand(0);
|
||||
if (N00.getOpcode() == ISD::FNEG) {
|
||||
SDValue N000 = N00.getOperand(0);
|
||||
if (N000.getOpcode() == ISD::FMUL) {
|
||||
if (isContractableFMUL(N000)) {
|
||||
return DAG.getNode(ISD::FNEG, SL, VT,
|
||||
DAG.getNode(PreferredFusedOpcode, SL, VT,
|
||||
DAG.getNode(ISD::FP_EXTEND, SL, VT,
|
||||
@ -9023,7 +9031,7 @@ SDValue DAGCombiner::visitFSUBForFMACombine(SDNode *N) {
|
||||
SDValue N00 = N0.getOperand(0);
|
||||
if (N00.getOpcode() == ISD::FP_EXTEND) {
|
||||
SDValue N000 = N00.getOperand(0);
|
||||
if (N000.getOpcode() == ISD::FMUL) {
|
||||
if (isContractableFMUL(N000)) {
|
||||
return DAG.getNode(ISD::FNEG, SL, VT,
|
||||
DAG.getNode(PreferredFusedOpcode, SL, VT,
|
||||
DAG.getNode(ISD::FP_EXTEND, SL, VT,
|
||||
@ -9043,10 +9051,9 @@ SDValue DAGCombiner::visitFSUBForFMACombine(SDNode *N) {
|
||||
// -> (fma x, y (fma u, v, (fneg z)))
|
||||
// FIXME: The UnsafeAlgebra flag should be propagated to FMA/FMAD, but FMF
|
||||
// are currently only supported on binary nodes.
|
||||
if (Options.UnsafeFPMath &&
|
||||
N0.getOpcode() == PreferredFusedOpcode &&
|
||||
N0.getOperand(2).getOpcode() == ISD::FMUL &&
|
||||
N0->hasOneUse() && N0.getOperand(2)->hasOneUse()) {
|
||||
if (Options.UnsafeFPMath && N0.getOpcode() == PreferredFusedOpcode &&
|
||||
isContractableFMUL(N0.getOperand(2)) && N0->hasOneUse() &&
|
||||
N0.getOperand(2)->hasOneUse()) {
|
||||
return DAG.getNode(PreferredFusedOpcode, SL, VT,
|
||||
N0.getOperand(0), N0.getOperand(1),
|
||||
DAG.getNode(PreferredFusedOpcode, SL, VT,
|
||||
@ -9060,9 +9067,8 @@ SDValue DAGCombiner::visitFSUBForFMACombine(SDNode *N) {
|
||||
// -> (fma (fneg y), z, (fma (fneg u), v, x))
|
||||
// FIXME: The UnsafeAlgebra flag should be propagated to FMA/FMAD, but FMF
|
||||
// are currently only supported on binary nodes.
|
||||
if (Options.UnsafeFPMath &&
|
||||
N1.getOpcode() == PreferredFusedOpcode &&
|
||||
N1.getOperand(2).getOpcode() == ISD::FMUL) {
|
||||
if (Options.UnsafeFPMath && N1.getOpcode() == PreferredFusedOpcode &&
|
||||
isContractableFMUL(N1.getOperand(2))) {
|
||||
SDValue N20 = N1.getOperand(2).getOperand(0);
|
||||
SDValue N21 = N1.getOperand(2).getOperand(1);
|
||||
return DAG.getNode(PreferredFusedOpcode, SL, VT,
|
||||
@ -9075,14 +9081,14 @@ SDValue DAGCombiner::visitFSUBForFMACombine(SDNode *N) {
|
||||
N21, N0));
|
||||
}
|
||||
|
||||
if (AllowFusion && LookThroughFPExt) {
|
||||
if (LookThroughFPExt) {
|
||||
// fold (fsub (fma x, y, (fpext (fmul u, v))), z)
|
||||
// -> (fma x, y (fma (fpext u), (fpext v), (fneg z)))
|
||||
if (N0.getOpcode() == PreferredFusedOpcode) {
|
||||
SDValue N02 = N0.getOperand(2);
|
||||
if (N02.getOpcode() == ISD::FP_EXTEND) {
|
||||
SDValue N020 = N02.getOperand(0);
|
||||
if (N020.getOpcode() == ISD::FMUL)
|
||||
if (isContractableFMUL(N020))
|
||||
return DAG.getNode(PreferredFusedOpcode, SL, VT,
|
||||
N0.getOperand(0), N0.getOperand(1),
|
||||
DAG.getNode(PreferredFusedOpcode, SL, VT,
|
||||
@ -9105,7 +9111,7 @@ SDValue DAGCombiner::visitFSUBForFMACombine(SDNode *N) {
|
||||
SDValue N00 = N0.getOperand(0);
|
||||
if (N00.getOpcode() == PreferredFusedOpcode) {
|
||||
SDValue N002 = N00.getOperand(2);
|
||||
if (N002.getOpcode() == ISD::FMUL)
|
||||
if (isContractableFMUL(N002))
|
||||
return DAG.getNode(PreferredFusedOpcode, SL, VT,
|
||||
DAG.getNode(ISD::FP_EXTEND, SL, VT,
|
||||
N00.getOperand(0)),
|
||||
@ -9126,7 +9132,7 @@ SDValue DAGCombiner::visitFSUBForFMACombine(SDNode *N) {
|
||||
if (N1.getOpcode() == PreferredFusedOpcode &&
|
||||
N1.getOperand(2).getOpcode() == ISD::FP_EXTEND) {
|
||||
SDValue N120 = N1.getOperand(2).getOperand(0);
|
||||
if (N120.getOpcode() == ISD::FMUL) {
|
||||
if (isContractableFMUL(N120)) {
|
||||
SDValue N1200 = N120.getOperand(0);
|
||||
SDValue N1201 = N120.getOperand(1);
|
||||
return DAG.getNode(PreferredFusedOpcode, SL, VT,
|
||||
@ -9153,7 +9159,7 @@ SDValue DAGCombiner::visitFSUBForFMACombine(SDNode *N) {
|
||||
SDValue N100 = N1.getOperand(0).getOperand(0);
|
||||
SDValue N101 = N1.getOperand(0).getOperand(1);
|
||||
SDValue N102 = N1.getOperand(0).getOperand(2);
|
||||
if (N102.getOpcode() == ISD::FMUL) {
|
||||
if (isContractableFMUL(N102)) {
|
||||
SDValue N1020 = N102.getOperand(0);
|
||||
SDValue N1021 = N102.getOperand(1);
|
||||
return DAG.getNode(PreferredFusedOpcode, SL, VT,
|
||||
|
@ -25,3 +25,29 @@ define <2 x float> @no_fma_2(<2 x float> %A, <2 x float> %B, <2 x float> %C) {
|
||||
%tmp2 = fadd contract <2 x float> %C, %tmp1;
|
||||
ret <2 x float> %tmp2
|
||||
}
|
||||
|
||||
define <2 x float> @fma_sub(<2 x float> %A, <2 x float> %B, <2 x float> %C) {
|
||||
; CHECK-LABEL: fma_sub:
|
||||
; CHECK: fmls {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
|
||||
%tmp1 = fmul contract <2 x float> %A, %B;
|
||||
%tmp2 = fsub contract <2 x float> %C, %tmp1;
|
||||
ret <2 x float> %tmp2
|
||||
}
|
||||
|
||||
define <2 x float> @no_fma_sub_1(<2 x float> %A, <2 x float> %B, <2 x float> %C) {
|
||||
; CHECK-LABEL: no_fma_sub_1:
|
||||
; CHECK: fmul
|
||||
; CHECK: fsub
|
||||
%tmp1 = fmul contract <2 x float> %A, %B;
|
||||
%tmp2 = fsub <2 x float> %C, %tmp1;
|
||||
ret <2 x float> %tmp2
|
||||
}
|
||||
|
||||
define <2 x float> @no_fma_sub_2(<2 x float> %A, <2 x float> %B, <2 x float> %C) {
|
||||
; CHECK-LABEL: no_fma_sub_2:
|
||||
; CHECK: fmul
|
||||
; CHECK: fsub
|
||||
%tmp1 = fmul <2 x float> %A, %B;
|
||||
%tmp2 = fsub contract <2 x float> %C, %tmp1;
|
||||
ret <2 x float> %tmp2
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user