This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC] Add FMA support to sparc backend


Eric, this is a preliminary version of the FMA patch I've been
working on.  Just so you can see what I'm doing.

First, ignore the fact that there are two configure tests for the
presence of support for these instructions.  I'm busy normalizing the
-xarch options which binutils supports so that they are the same as
Sun AS and therefore just one test is necessary.

Second, like rs6000 the sparc negate fused multiply instructions
negate the full result, not the multiply result.  So we cannot use
those instructions for the fnmadf4/fnmsdf4/fnmasf4/fnmssf4 patterns.
Since rs6000 provides patterns for such negate operations (presumably
just in case the combiner creates a match) I have done so for sparc
as well.

I was really surprised that cpu designers haven't settled on a
consistent formula for negated fused multiply add/sub instructions.
Ho hum...

For now my plan is to turn these fused multiply instructions on if you
ask to compile targetting a cpu that supports them.

I'll write a suitable changelog etc. once everything is finalized, this
patch posting is just to elicit feedback.

Thanks!

diff --git a/gcc/config.in b/gcc/config.in
index d202b038..4bb6271 100644
--- a/gcc/config.in
+++ b/gcc/config.in
@@ -272,6 +272,12 @@
 #endif
 
 
+/* Define if your assembler supports FMAF instructions. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_AS_GAS_FMAF
+#endif
+
+
 /* Define if your assembler supports the --gdwarf2 option. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_AS_GDWARF2_DEBUG_FLAG
@@ -479,6 +485,12 @@
 #endif
 
 
+/* Define if your assembler supports FMAF instructions. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_AS_SUN_FMAF
+#endif
+
+
 /* Define if your assembler and linker support thread-local storage. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_AS_TLS
@@ -1047,12 +1059,6 @@
 #endif
 
 
-/* Define if _Unwind_GetIPInfo is available. */
-#ifndef USED_FOR_TARGET
-#undef HAVE_GETIPINFO
-#endif
-
-
 /* Define to 1 if you have the `getrlimit' function. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_GETRLIMIT
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
index cf9e197..ce15730 100644
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -752,9 +752,9 @@ sparc_option_override (void)
     /* UltraSPARC T2 */
     { MASK_ISA, MASK_V9},
     /* UltraSPARC T3 */
-    { MASK_ISA, MASK_V9},
+    { MASK_ISA, MASK_V9 | MASK_FMAF},
     /* UltraSPARC T4 */
-    { MASK_ISA, MASK_V9},
+    { MASK_ISA, MASK_V9 | MASK_FMAF},
   };
   const struct cpu_table *cpu;
   unsigned int i;
@@ -833,9 +833,9 @@ sparc_option_override (void)
   if (target_flags_explicit & MASK_FPU)
     target_flags = (target_flags & ~MASK_FPU) | fpu;
 
-  /* Don't allow -mvis if FPU is disabled.  */
+  /* Don't allow -mvis or -mfmaf if FPU is disabled.  */
   if (! TARGET_FPU)
-    target_flags &= ~MASK_VIS;
+    target_flags &= ~(MASK_VIS | MASK_FMAF);
 
   /* -mvis assumes UltraSPARC+, so we are sure v9 instructions
      are available.
@@ -9505,6 +9505,25 @@ sparc_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
 	*total = COSTS_N_INSNS (1);
       return false;
 
+    case FMA:
+      {
+	rtx sub;
+
+	gcc_assert (float_mode_p);
+	*total = sparc_costs->float_mul;
+
+	sub = XEXP (x, 0);
+	if (GET_CODE (sub) == NEG)
+	  sub = XEXP (sub, 0);
+	*total += rtx_cost (sub, FMA, 0, speed);
+
+	sub = XEXP (x, 2);
+	if (GET_CODE (sub) == NEG)
+	  sub = XEXP (sub, 0);
+	*total += rtx_cost (sub, FMA, 2, speed);
+	return true;
+      }
+
     case MULT:
       if (float_mode_p)
 	*total = sparc_costs->float_mul;
diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h
index afdca1e..c8174ce 100644
--- a/gcc/config/sparc/sparc.h
+++ b/gcc/config/sparc/sparc.h
@@ -1880,6 +1880,11 @@ extern int sparc_indent_opcode;
 #define TARGET_SUN_TLS TARGET_TLS
 #define TARGET_GNU_TLS 0
 
+#if !(defined(HAVE_AS_GAS_FMAF) || defined(HAVE_AS_SUN_FMAF))
+#undef TARGET_FMAF
+#define TARGET_FMAF 0
+#endif
+
 /* The number of Pmode words for the setjmp buffer.  */
 #define JMP_BUF_SIZE 12
 
diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md
index 721db93..58ac6d7 100644
--- a/gcc/config/sparc/sparc.md
+++ b/gcc/config/sparc/sparc.md
@@ -5345,6 +5345,78 @@
   "fmuls\t%1, %2, %0"
   [(set_attr "type" "fpmul")])
 
+(define_insn "fmadf4"
+  [(set (match_operand:DF 0 "register_operand" "=e")
+        (fma:DF (match_operand:DF 1 "register_operand" "e")
+		(match_operand:DF 2 "register_operand" "e")
+		(match_operand:DF 3 "register_operand" "e")))]
+  "TARGET_FMAF"
+  "fmaddd\t%1, %2, %3, %0"
+  [(set_attr "type" "fpmul")])
+
+(define_insn "fmsdf4"
+  [(set (match_operand:DF 0 "register_operand" "=e")
+        (fma:DF (match_operand:DF 1 "register_operand" "e")
+		(match_operand:DF 2 "register_operand" "e")
+		(neg:DF (match_operand:DF 3 "register_operand" "e"))))]
+  "TARGET_FMAF"
+  "fmsubd\t%1, %2, %3, %0"
+  [(set_attr "type" "fpmul")])
+
+(define_insn "*nfmadf4"
+  [(set (match_operand:DF 0 "register_operand" "=e")
+        (neg:DF (fma:DF (match_operand:DF 1 "register_operand" "e")
+			(match_operand:DF 2 "register_operand" "e")
+			(match_operand:DF 3 "register_operand" "e"))))]
+  "TARGET_FMAF"
+  "fnmaddd\t%1, %2, %3, %0"
+  [(set_attr "type" "fpmul")])
+
+(define_insn "*nfmsdf4"
+  [(set (match_operand:DF 0 "register_operand" "=e")
+        (neg:DF (fma:DF (match_operand:DF 1 "register_operand" "e")
+			(match_operand:DF 2 "register_operand" "e")
+			(neg:DF (match_operand:DF 3 "register_operand" "e")))))]
+  "TARGET_FMAF"
+  "fnmsubd\t%1, %2, %3, %0"
+  [(set_attr "type" "fpmul")])
+
+(define_insn "fmasf4"
+  [(set (match_operand:SF 0 "register_operand" "=f")
+        (fma:SF (match_operand:SF 1 "register_operand" "f")
+		(match_operand:SF 2 "register_operand" "f")
+		(match_operand:SF 3 "register_operand" "f")))]
+  "TARGET_FMAF"
+  "fmadds\t%1, %2, %3, %0"
+  [(set_attr "type" "fpmul")])
+
+(define_insn "fmssf4"
+  [(set (match_operand:SF 0 "register_operand" "=f")
+        (fma:SF (match_operand:SF 1 "register_operand" "f")
+		(match_operand:SF 2 "register_operand" "f")
+		(neg:SF (match_operand:SF 3 "register_operand" "f"))))]
+  "TARGET_FMAF"
+  "fmsubs\t%1, %2, %3, %0"
+  [(set_attr "type" "fpmul")])
+
+(define_insn "*nfmasf4"
+  [(set (match_operand:SF 0 "register_operand" "=f")
+        (neg:SF (fma:SF (match_operand:SF 1 "register_operand" "f")
+			(match_operand:SF 2 "register_operand" "f")
+			(match_operand:SF 3 "register_operand" "f"))))]
+  "TARGET_FMAF"
+  "fnmadds\t%1, %2, %3, %0"
+  [(set_attr "type" "fpmul")])
+
+(define_insn "*nfmssf4"
+  [(set (match_operand:SF 0 "register_operand" "=f")
+        (neg:SF (fma:SF (match_operand:SF 1 "register_operand" "f")
+			(match_operand:SF 2 "register_operand" "f")
+			(neg:SF (match_operand:SF 3 "register_operand" "f")))))]
+  "TARGET_FMAF"
+  "fnmsubs\t%1, %2, %3, %0"
+  [(set_attr "type" "fpmul")])
+
 (define_insn "*muldf3_extend"
   [(set (match_operand:DF 0 "register_operand" "=e")
 	(mult:DF (float_extend:DF (match_operand:SF 1 "register_operand" "f"))
diff --git a/gcc/config/sparc/sparc.opt b/gcc/config/sparc/sparc.opt
index ce6fa94..8e2c6bd 100644
--- a/gcc/config/sparc/sparc.opt
+++ b/gcc/config/sparc/sparc.opt
@@ -61,6 +61,10 @@ mvis
 Target Report Mask(VIS)
 Use UltraSPARC Visual Instruction Set extensions
 
+mfmaf
+Target Report Mask(FMAF)
+Use UltraSPARC Fused Multiply extensions
+
 mptr64
 Target Report RejectNegative Mask(PTR64)
 Pointers are 64-bit
diff --git a/gcc/configure b/gcc/configure
index b1dd57b..a046e94 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -24037,6 +24037,72 @@ if test $gcc_cv_as_sparc_offsetable_lo10 = yes; then
 $as_echo "#define HAVE_AS_OFFSETABLE_LO10 1" >>confdefs.h
 
 fi
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for FMAF instructions (GAS)" >&5
+$as_echo_n "checking assembler for FMAF instructions (GAS)... " >&6; }
+if test "${gcc_cv_as_sparc_gas_fmaf+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  gcc_cv_as_sparc_gas_fmaf=no
+  if test x$gcc_cv_as != x; then
+    $as_echo '.text
+       .align 4
+       fmaddd %f0, %f2, %f4, %f6' > conftest.s
+    if { ac_try='$gcc_cv_as $gcc_cv_as_flags -xarch=v9b -o conftest.o conftest.s >&5'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }
+    then
+	gcc_cv_as_sparc_gas_fmaf=yes
+    else
+      echo "configure: failed program was" >&5
+      cat conftest.s >&5
+    fi
+    rm -f conftest.o conftest.s
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_sparc_gas_fmaf" >&5
+$as_echo "$gcc_cv_as_sparc_gas_fmaf" >&6; }
+if test $gcc_cv_as_sparc_gas_fmaf = yes; then
+
+$as_echo "#define HAVE_AS_GAS_FMAF 1" >>confdefs.h
+
+fi
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for FMAF instructions (Sun AS)" >&5
+$as_echo_n "checking assembler for FMAF instructions (Sun AS)... " >&6; }
+if test "${gcc_cv_as_sparc_sunas_fmaf+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  gcc_cv_as_sparc_sunas_fmaf=no
+  if test x$gcc_cv_as != x; then
+    $as_echo '.text
+       .align 4
+       fmaddd %f0, %f2, %f4, %f6' > conftest.s
+    if { ac_try='$gcc_cv_as $gcc_cv_as_flags -xarch=sparcfmaf -o conftest.o conftest.s >&5'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }
+    then
+	gcc_cv_as_sparc_sunas_fmaf=yes
+    else
+      echo "configure: failed program was" >&5
+      cat conftest.s >&5
+    fi
+    rm -f conftest.o conftest.s
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_sparc_sunas_fmaf" >&5
+$as_echo "$gcc_cv_as_sparc_sunas_fmaf" >&6; }
+if test $gcc_cv_as_sparc_sunas_fmaf = yes; then
+
+$as_echo "#define HAVE_AS_SUN_FMAF 1" >>confdefs.h
+
+fi
     ;;
 
   i[34567]86-*-* | x86_64-*-*)
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 51ab3ac..e40ffc2 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -3473,6 +3473,24 @@ foo:
        fi],
        [AC_DEFINE(HAVE_AS_OFFSETABLE_LO10, 1,
 	         [Define if your assembler supports offsetable %lo().])])
+
+    gcc_GAS_CHECK_FEATURE([FMAF instructions (GAS)],
+      gcc_cv_as_sparc_gas_fmaf,,
+      [-xarch=v9b],
+      [.text
+       .align 4
+       fmaddd %f0, %f2, %f4, %f6],,
+      [AC_DEFINE(HAVE_AS_GAS_FMAF, 1,
+                [Define if your assembler supports FMAF instructions.])])
+
+    gcc_GAS_CHECK_FEATURE([FMAF instructions (Sun AS)],
+      gcc_cv_as_sparc_sunas_fmaf,,
+      [-xarch=sparcfmaf],
+      [.text
+       .align 4
+       fmaddd %f0, %f2, %f4, %f6],,
+      [AC_DEFINE(HAVE_AS_SUN_FMAF, 1,
+                [Define if your assembler supports FMAF instructions.])])
     ;;
 
 changequote(,)dnl


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]