[AArch64] Check fmul node single use in fused multiply patterns
authorAna Pazos <apazos@codeaurora.org>
Tue, 24 Dec 2013 00:47:29 +0000 (00:47 +0000)
committerAna Pazos <apazos@codeaurora.org>
Tue, 24 Dec 2013 00:47:29 +0000 (00:47 +0000)
Check for single use of fmul node in fused multiply patterns
to allow generation of fused multiply add/sub instructions.
Otherwise fmul operation ends up being repeated more than
once which does not help peformance on targets with
only one MAC unit, as for example cortex-a53.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@197929 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/AArch64/AArch64InstrInfo.td
lib/Target/AArch64/AArch64InstrNEON.td
test/CodeGen/AArch64/fp-dp3.ll
test/CodeGen/AArch64/neon-fma.ll

index add11de67f40e751633a551db403cc975a3241a0..c961fb2c5d2b881279dec3f33468ae4a4c020fb5 100644 (file)
@@ -26,6 +26,15 @@ def UseFusedMAC      : Predicate<"(TM.Options.AllowFPOpFusion =="
                                  " FPOpFusion::Fast)">;
 include "AArch64InstrFormats.td"
 
                                  " FPOpFusion::Fast)">;
 include "AArch64InstrFormats.td"
 
+//===----------------------------------------------------------------------===//
+//  AArch64 specific pattern fragments.
+//
+// An 'fmul' node with a single use.
+def fmul_su : PatFrag<(ops node:$lhs, node:$rhs), (fmul node:$lhs, node:$rhs),[{
+  return N->hasOneUse();
+}]>;
+
+
 //===----------------------------------------------------------------------===//
 // Target-specific ISD nodes and profiles
 //===----------------------------------------------------------------------===//
 //===----------------------------------------------------------------------===//
 // Target-specific ISD nodes and profiles
 //===----------------------------------------------------------------------===//
@@ -2198,22 +2207,22 @@ def FNMSUBdddd : A64I_fpdp3Impl<"fnmsub", FPR64, f64, 0b01, 0b1, 0b1, fnmsub>;
 // Extra patterns for when we're allowed to optimise separate multiplication and
 // addition.
 let Predicates = [HasFPARMv8, UseFusedMAC] in {
 // Extra patterns for when we're allowed to optimise separate multiplication and
 // addition.
 let Predicates = [HasFPARMv8, UseFusedMAC] in {
-def : Pat<(f32 (fadd FPR32:$Ra, (f32 (fmul FPR32:$Rn, FPR32:$Rm)))),
+def : Pat<(f32 (fadd FPR32:$Ra, (f32 (fmul_su FPR32:$Rn, FPR32:$Rm)))),
           (FMADDssss FPR32:$Rn, FPR32:$Rm, FPR32:$Ra)>;
           (FMADDssss FPR32:$Rn, FPR32:$Rm, FPR32:$Ra)>;
-def : Pat<(f32 (fsub FPR32:$Ra, (f32 (fmul FPR32:$Rn, FPR32:$Rm)))),
+def : Pat<(f32 (fsub FPR32:$Ra, (f32 (fmul_su FPR32:$Rn, FPR32:$Rm)))),
           (FMSUBssss FPR32:$Rn, FPR32:$Rm, FPR32:$Ra)>;
           (FMSUBssss FPR32:$Rn, FPR32:$Rm, FPR32:$Ra)>;
-def : Pat<(f32 (fsub (f32 (fneg FPR32:$Ra)), (f32 (fmul FPR32:$Rn, FPR32:$Rm)))),
+def : Pat<(f32 (fsub (f32 (fneg FPR32:$Ra)), (f32 (fmul_su FPR32:$Rn, FPR32:$Rm)))),
           (FNMADDssss FPR32:$Rn, FPR32:$Rm, FPR32:$Ra)>;
           (FNMADDssss FPR32:$Rn, FPR32:$Rm, FPR32:$Ra)>;
-def : Pat<(f32 (fsub (f32 (fmul FPR32:$Rn, FPR32:$Rm)), FPR32:$Ra)),
+def : Pat<(f32 (fsub (f32 (fmul_su FPR32:$Rn, FPR32:$Rm)), FPR32:$Ra)),
           (FNMSUBssss FPR32:$Rn, FPR32:$Rm, FPR32:$Ra)>;
 
           (FNMSUBssss FPR32:$Rn, FPR32:$Rm, FPR32:$Ra)>;
 
-def : Pat<(f64 (fadd FPR64:$Ra, (f64 (fmul FPR64:$Rn, FPR64:$Rm)))),
+def : Pat<(f64 (fadd FPR64:$Ra, (f64 (fmul_su FPR64:$Rn, FPR64:$Rm)))),
           (FMADDdddd FPR64:$Rn, FPR64:$Rm, FPR64:$Ra)>;
           (FMADDdddd FPR64:$Rn, FPR64:$Rm, FPR64:$Ra)>;
-def : Pat<(f64 (fsub FPR64:$Ra, (f64 (fmul FPR64:$Rn, FPR64:$Rm)))),
+def : Pat<(f64 (fsub FPR64:$Ra, (f64 (fmul_su FPR64:$Rn, FPR64:$Rm)))),
           (FMSUBdddd FPR64:$Rn, FPR64:$Rm, FPR64:$Ra)>;
           (FMSUBdddd FPR64:$Rn, FPR64:$Rm, FPR64:$Ra)>;
-def : Pat<(f64 (fsub (f64 (fneg FPR64:$Ra)), (f64 (fmul FPR64:$Rn, FPR64:$Rm)))),
+def : Pat<(f64 (fsub (f64 (fneg FPR64:$Ra)), (f64 (fmul_su FPR64:$Rn, FPR64:$Rm)))),
           (FNMADDdddd FPR64:$Rn, FPR64:$Rm, FPR64:$Ra)>;
           (FNMADDdddd FPR64:$Rn, FPR64:$Rm, FPR64:$Ra)>;
-def : Pat<(f64 (fsub (f64 (fmul FPR64:$Rn, FPR64:$Rm)), FPR64:$Ra)),
+def : Pat<(f64 (fsub (f64 (fmul_su FPR64:$Rn, FPR64:$Rm)), FPR64:$Ra)),
           (FNMSUBdddd FPR64:$Rn, FPR64:$Rm, FPR64:$Ra)>;
 }
 
           (FNMSUBdddd FPR64:$Rn, FPR64:$Rm, FPR64:$Ra)>;
 }
 
index 3ddeed4d93a0336cd5a31fd0332bf6fd2d18fbea..43c2bf48c7deeb842d82dd6f8c4c8c57539b6d28 100644 (file)
@@ -320,10 +320,10 @@ def MLSvvv_4S:  NeonI_3VSame_Constraint_impl<"mls", ".4s",  VPR128, v4i32,
 // Vector Multiply-accumulate and Multiply-subtract (Floating Point)
 
 def Neon_fmla : PatFrag<(ops node:$Ra, node:$Rn, node:$Rm),
 // Vector Multiply-accumulate and Multiply-subtract (Floating Point)
 
 def Neon_fmla : PatFrag<(ops node:$Ra, node:$Rn, node:$Rm),
-                        (fadd node:$Ra, (fmul node:$Rn, node:$Rm))>;
+                        (fadd node:$Ra, (fmul_su node:$Rn, node:$Rm))>;
 
 def Neon_fmls : PatFrag<(ops node:$Ra, node:$Rn, node:$Rm),
 
 def Neon_fmls : PatFrag<(ops node:$Ra, node:$Rn, node:$Rm),
-                        (fsub node:$Ra, (fmul node:$Rn, node:$Rm))>;
+                        (fsub node:$Ra, (fmul_su node:$Rn, node:$Rm))>;
 
 let Predicates = [HasNEON, UseFusedMAC] in {
 def FMLAvvv_2S: NeonI_3VSame_Constraint_impl<"fmla", ".2s",  VPR64,  v2f32,
 
 let Predicates = [HasNEON, UseFusedMAC] in {
 def FMLAvvv_2S: NeonI_3VSame_Constraint_impl<"fmla", ".2s",  VPR64,  v2f32,
index 6b9acc8865f89b6d87d82585ff6e89f13a916654..2a6790e99c6cdc24fc01e25f6a1625ec25006e94 100644 (file)
@@ -135,3 +135,29 @@ define float @test_fnmsub_unfused(float %a, float %b, float %c) {
   ret float %sum
 }
 
   ret float %sum
 }
 
+; Another set of tests that check for multiply single use
+
+define float @test_fmadd_unfused_su(float %a, float %b, float %c) {
+; CHECK-LABEL: test_fmadd_unfused_su:
+  %prod = fmul float %b, %c
+  %sum = fadd float %a, %prod
+  %res = fadd float %sum, %prod
+; CHECK-NOT: fmadd {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+; CHECK: fmul {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+; CHECK: fadd {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+; CHECK: fadd {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+  ret float %res
+}
+
+define float @test_fmsub_unfused_su(float %a, float %b, float %c) {
+; CHECK-LABEL: test_fmsub_unfused_su:
+  %prod = fmul float %b, %c
+  %diff = fsub float %a, %prod
+  %res = fsub float %diff, %prod
+; CHECK-NOT: fmsub {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+; CHECK: fmul {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+; CHECK: fsub {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+; CHECK: fsub {{s[0-9]+}}, {{s[0-9]+}}, {{s[0-9]+}}
+  ret float %res
+}
+
index 7b8f2121ca684547f98dccc25e4650e34746de45..af70302ca939c4c3c60e6225c901a0474ad584be 100644 (file)
@@ -111,3 +111,22 @@ define <2 x double> @fmuladd2xdouble_fused(<2 x double> %A, <2 x double> %B, <2
        ret <2 x double> %val
 }
 
        ret <2 x double> %val
 }
 
+
+; Another set of tests that check for multiply single use
+
+define <2 x float> @fmla2xfloati_su(<2 x float> %A, <2 x float> %B, <2 x float> %C) {
+;CHECK-NOT: fmla {{v[0-9]+}}.2s, {{v[0-9]+}}.2s, {{v[0-9]+}}.2s
+  %tmp1 = fmul <2 x float> %A, %B;
+  %tmp2 = fadd <2 x float> %C, %tmp1;
+  %tmp3 = fadd <2 x float> %tmp2, %tmp1;
+  ret <2 x float> %tmp3
+}
+
+define <2 x double> @fmls2xdouble_su(<2 x double> %A, <2 x double> %B, <2 x double> %C) {
+;CHECK-NOT: fmls {{v[0-9]+}}.2d, {{v[0-9]+}}.2d, {{v[0-9]+}}.2d
+        %tmp1 = fmul <2 x double> %A, %B;
+        %tmp2 = fsub <2 x double> %C, %tmp1;
+        %tmp3 = fsub <2 x double> %tmp2, %tmp1;
+        ret <2 x double> %tmp3
+}
+