From 65450d64b7ea2c26eb03dd0557703440c24a112a Mon Sep 17 00:00:00 2001
From: Jakub Jelinek <jakub@redhat.com>
Date: Thu, 3 Feb 2011 11:53:19 +0100
Subject: [PATCH] re PR target/47312 (ICE: in expand_ternary_op, at
 optabs.c:656 with -flto -mno-sse -mxop and __builtin_fmaf())

	PR target/47312
	* expr.c (expand_expr_real_2) <case FMA_EXPR>: If target doesn't expand
	fma, expand FMA_EXPR as fma{,f,l} call.

	* gcc.target/i386/pr47312.c: New test.

From-SVN: r169786
---
 gcc/ChangeLog                           |  4 ++++
 gcc/expr.c                              | 12 ++++++++++++
 gcc/testsuite/ChangeLog                 |  3 +++
 gcc/testsuite/gcc.target/i386/pr47312.c | 23 +++++++++++++++++++++++
 4 files changed, 42 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr47312.c

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index cffaf02baf20..1588c6f00d72 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,9 @@
 2011-02-03  Jakub Jelinek  <jakub@redhat.com>
 
+	PR target/47312
+	* expr.c (expand_expr_real_2) <case FMA_EXPR>: If target doesn't expand
+	fma, expand FMA_EXPR as fma{,f,l} call.
+
 	PR lto/47274
 	* lto-streamer-out.c (write_symbol): When writing kind and visibility,
 	copy them into a unsigned char variable and pass address of it to
diff --git a/gcc/expr.c b/gcc/expr.c
index e6b42795b3a1..df15c928bee8 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -7695,6 +7695,18 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
 	optab opt = fma_optab;
 	gimple def0, def2;
 
+	/* If there is no insn for FMA, emit it as __builtin_fma{,f,l}
+	   call.  */
+	if (optab_handler (fma_optab, mode) == CODE_FOR_nothing)
+	  {
+	    tree fn = mathfn_built_in (TREE_TYPE (treeop0), BUILT_IN_FMA);
+	    tree call_expr;
+
+	    gcc_assert (fn != NULL_TREE);
+	    call_expr = build_call_expr (fn, 3, treeop0, treeop1, treeop2);
+	    return expand_builtin (call_expr, target, subtarget, mode, false);
+	  }
+
 	def0 = get_def_for_expr (treeop0, NEGATE_EXPR);
 	def2 = get_def_for_expr (treeop2, NEGATE_EXPR);
 
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 001d60425bb6..3ea0a1b585f5 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,8 @@
 2011-02-03  Jakub Jelinek  <jakub@redhat.com>
 
+	PR target/47312
+	* gcc.target/i386/pr47312.c: New test.
+
 	PR target/47564
 	* gcc.target/i386/pr47564.c: New test.
 
diff --git a/gcc/testsuite/gcc.target/i386/pr47312.c b/gcc/testsuite/gcc.target/i386/pr47312.c
new file mode 100644
index 000000000000..a63089d422a2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr47312.c
@@ -0,0 +1,23 @@
+/* PR target/47312 */
+/* { dg-do link } */
+/* { dg-require-effective-target lto } */
+/* { dg-require-effective-target xop } */
+/* { dg-options "-O -flto -mno-sse3 -mxop" } */
+
+extern double fma (double, double, double);
+extern float fmaf (float, float, float);
+extern long double fmal (long double, long double, long double);
+
+volatile float f;
+volatile double d;
+volatile long double ld;
+
+int
+main ()
+{
+  f = fmaf (f, f, f);
+  d = fma (d, d, d);
+  ld = fmal (ld, ld, ld);
+  asm volatile ("" : : "r" (&f), "r" (&d), "r" (&ld) : "memory");
+  return 0;
+}
-- 
GitLab