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]

[PATCH] generate fsincos x87 insn


Hello!

Attached to this message, please find a patch to implement x87's fsincos instruction. Patch is tested, and produces fsincos instruction when appropriate. Fsincos instruction generation is totally transparent: if a sin() instruction can be combined with matched cos(), then fsincos is generated.

Please, could someone review this patch and eventually commit it to CVS. Diff is against current mainline.

BTW: I think, that m68k's fsincos instruction can be easily implemented the way it is implemented in attached i386.md diff.

2004-04-05 Uros Bizjak <uros@kss-loka.si>

       * builtins.c: Implement support for sincos function.
       (expand_builtin_mathfn) Remove BUILT_IN_SIN{,F,L} and
       BUILT_IN_COS{,F,L}.
       (expand_builtin_mathfn_3): New function.
       (expand_builtin): Expand BUILT_IN_SIN{,F,L} and
       BUILT_IN_COS{,F,L} using expand_builtin_mathfn_3 if
       flag_unsafe_math_optimization is set.

       * optabs.h (enum optab_index): Add new OTI_sincos.
       (sincos_optab): Define corresponding macro.

       * optabs.c (init_optabs): Initialize sincos_optab.
       (expand_twoval_unop): New function.

       * genopinit.c (optabs): Implement sincos_optab using sincos?f3
       patterns.

       * reg-stack.c (subst_stack_regs_pat): Handle UNSPEC_SINCOS_COS
       and UNSPEC_SINCOS_SIN.

       * config/i386/i386.md (sincosdf3, sincossf3, *sincosextendsfdf3,
       sincosxf3): New patterns to implement sincos, sincosf and sincosl
       built-ins as inline x87 intrinsics. Define splits for
       sindf2, sinsf2, *sinextendsfdf2, sinxf2, cosdf2,
       cossf2, *cosextendsfdf2 and cosxf2 patterns from corresponding
       sincos patterns.
       (sindf2, sinsf2, sinxf2): Rename to *sindf2, *sinsf2, *sinxf2.
       (cosdf2, cossf2, cosxf2): Rename to *cosdf2, *cossf2, *cosxf2.

       (UNSPEC_SINCOS_SIN, UNPEC_SINCOS_COS): New unspecs to represent
       x87's unspec insn.

* gcc.dg/builtins-36.c: New test.


BTW2: Also attached is an ASM result of builtins-36.c testcase, compiled with -O2 -ffast-math.


Thanks,
Uros.
? config.cache
? config.log
? maybedep.tmp
? serdep.tmp
? gcc/testsuite/gcc.dg/builtins-20.s
Index: gcc/ChangeLog
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/ChangeLog,v
retrieving revision 2.3344
diff -u -r2.3344 ChangeLog
--- gcc/ChangeLog	5 Apr 2004 04:22:26 -0000	2.3344
+++ gcc/ChangeLog	5 Apr 2004 10:16:10 -0000
@@ -1,3 +1,37 @@
+2004-04-05  Uros Bizjak  <uros@kss-loka.si>
+
+	* builtins.c: Implement support for sincos function.
+	(expand_builtin_mathfn) Remove BUILT_IN_SIN{,F,L} and
+	BUILT_IN_COS{,F,L}.
+	(expand_builtin_mathfn_3): New function.
+	(expand_builtin): Expand BUILT_IN_SIN{,F,L} and
+	BUILT_IN_COS{,F,L} using expand_builtin_mathfn_3 if
+	flag_unsafe_math_optimization is set.
+
+	* optabs.h (enum optab_index): Add new OTI_sincos.
+	(sincos_optab): Define corresponding macro.
+
+	* optabs.c (init_optabs): Initialize sincos_optab.
+	(expand_twoval_unop): New function.
+
+	* genopinit.c (optabs): Implement sincos_optab using sincos?f3
+	patterns.
+
+	* reg-stack.c (subst_stack_regs_pat): Handle UNSPEC_SINCOS_COS
+	and UNSPEC_SINCOS_SIN.
+
+	* config/i386/i386.md (sincosdf3, sincossf3, *sincosextendsfdf3,
+	sincosxf3): New patterns to implement sincos, sincosf and sincosl
+	built-ins as inline x87 intrinsics. Define splits for
+	sindf2, sinsf2, *sinextendsfdf2, sinxf2, cosdf2,
+	cossf2, *cosextendsfdf2 and cosxf2 patterns from corresponding
+	sincos patterns.
+	(sindf2, sinsf2, sinxf2): Rename to *sindf2, *sinsf2, *sinxf2.
+	(cosdf2, cossf2, cosxf2): Rename to *cosdf2, *cossf2, *cosxf2.
+
+	(UNSPEC_SINCOS_SIN, UNPEC_SINCOS_COS): New unspecs to represent
+	x87's unspec insn.
+
 2004-04-05  Eric Botcazou  <ebotcazou@libertysurf.fr>
 
 	* config/sparc/sol2-bi.h (PREFERRED_DEBUGGING_TYPE): Set
Index: gcc/builtins.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.301
diff -u -r1.301 builtins.c
--- gcc/builtins.c	1 Apr 2004 03:50:26 -0000	1.301
+++ gcc/builtins.c	5 Apr 2004 10:16:11 -0000
@@ -94,6 +94,7 @@
 static void expand_errno_check (tree, rtx);
 static rtx expand_builtin_mathfn (tree, rtx, rtx);
 static rtx expand_builtin_mathfn_2 (tree, rtx, rtx);
+static rtx expand_builtin_mathfn_3 (tree, rtx, rtx);
 static rtx expand_builtin_constant_p (tree, enum machine_mode);
 static rtx expand_builtin_args_info (tree);
 static rtx expand_builtin_next_arg (tree);
@@ -1520,7 +1521,7 @@
 }
 
 
-/* Expand a call to one of the builtin math functions (sin, cos, or sqrt).
+/* Expand a call to one of the builtin math functions (sqrt, exp, or log).
    Return 0 if a normal call should be emitted rather than expanding the
    function in-line.  EXP is the expression that is a call to the builtin
    function; if convenient, the result should be placed in TARGET.
@@ -1544,14 +1545,6 @@
 
   switch (DECL_FUNCTION_CODE (fndecl))
     {
-    case BUILT_IN_SIN:
-    case BUILT_IN_SINF:
-    case BUILT_IN_SINL:
-      builtin_optab = sin_optab; break;
-    case BUILT_IN_COS:
-    case BUILT_IN_COSF:
-    case BUILT_IN_COSL:
-      builtin_optab = cos_optab; break;
     case BUILT_IN_SQRT:
     case BUILT_IN_SQRTF:
     case BUILT_IN_SQRTL:
@@ -1815,6 +1808,138 @@
   return target;
 }
 
+/* Expand a call to the builtin sin and cos math functions.
+   Return 0 if a normal call should be emitted rather than expanding the
+   function in-line.  EXP is the expression that is a call to the builtin
+   function; if convenient, the result should be placed in TARGET.
+   SUBTARGET may be used as the target for computing one of EXP's
+   operands.  */
+
+static rtx
+expand_builtin_mathfn_3 (tree exp, rtx target, rtx subtarget)
+{
+  optab builtin_optab;
+  rtx op0, insns, before_call;
+  tree fndecl = get_callee_fndecl (exp);
+  tree arglist = TREE_OPERAND (exp, 1);
+  enum machine_mode mode;
+  bool errno_set = false;
+  tree arg, narg;
+
+  if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+    return 0;
+
+  arg = TREE_VALUE (arglist);
+
+  switch (DECL_FUNCTION_CODE (fndecl))
+    {
+    case BUILT_IN_SIN:
+    case BUILT_IN_SINF:
+    case BUILT_IN_SINL:
+    case BUILT_IN_COS:
+    case BUILT_IN_COSF:
+    case BUILT_IN_COSL:
+      builtin_optab = sincos_optab; break;
+    default:
+      abort ();
+    }
+
+  /* Make a suitable register to place result in.  */
+  mode = TYPE_MODE (TREE_TYPE (exp));
+
+  if (! flag_errno_math || ! HONOR_NANS (mode))
+    errno_set = false;
+
+  /* Check if sincos insn is available, otherwise fallback
+     to sin or cos insn. */
+  if (builtin_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing) {
+    switch (DECL_FUNCTION_CODE (fndecl))
+      {
+      case BUILT_IN_SIN:
+      case BUILT_IN_SINF:
+      case BUILT_IN_SINL:
+	builtin_optab = sin_optab; break;
+      case BUILT_IN_COS:
+      case BUILT_IN_COSF:
+      case BUILT_IN_COSL:
+	builtin_optab = cos_optab; break;
+      default:
+	abort();
+      }
+  }
+
+  /* Before working hard, check whether the instruction is available.  */
+  if (builtin_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+    {
+      target = gen_reg_rtx (mode);
+
+      /* Wrap the computation of the argument in a SAVE_EXPR, as we may
+	 need to expand the argument again.  This way, we will not perform
+	 side-effects more the once.  */
+      narg = save_expr (arg);
+      if (narg != arg)
+	{
+	  arglist = build_tree_list (NULL_TREE, arg);
+	  exp = build_function_call_expr (fndecl, arglist);
+	}
+
+      op0 = expand_expr (arg, subtarget, VOIDmode, 0);
+
+      emit_queue ();
+      start_sequence ();
+
+      /* Compute into TARGET.
+	 Set TARGET to wherever the result comes back.  */
+      if (builtin_optab == sincos_optab)
+	{
+	  switch (DECL_FUNCTION_CODE (fndecl))
+	    {
+	    case BUILT_IN_SIN:
+	    case BUILT_IN_SINF:
+	    case BUILT_IN_SINL:
+	      if (! expand_twoval_unop(builtin_optab, 0, target, op0, 0))    
+		abort();
+	      break;
+	    case BUILT_IN_COS:
+	    case BUILT_IN_COSF:
+	    case BUILT_IN_COSL:
+	      if (! expand_twoval_unop(builtin_optab, target, 0, op0, 0))
+		abort();
+	      break;
+	    default:
+	      abort();
+	    }
+	}
+      else
+	{
+	  target = expand_unop (mode, builtin_optab, op0, target, 0);
+	}
+
+      if (target != 0)
+	{
+	  if (errno_set)
+	    expand_errno_check (exp, target);
+
+	  /* Output the entire sequence.  */
+	  insns = get_insns ();
+	  end_sequence ();
+	  emit_insn (insns);
+	  return target;
+	}
+
+      /* If we were unable to expand via the builtin, stop the sequence
+	 (without outputting the insns) and call to the library function
+	 with the stabilized argument list.  */
+      end_sequence ();
+    }
+
+  before_call = get_last_insn ();
+
+  target = expand_call (exp, target, target == const0_rtx);
+
+  return target;
+}
+
 /* To evaluate powi(x,n), the floating point value x raised to the
    constant integer exponent n, we use a hybrid algorithm that
    combines the "window method" with look-up tables.  For an
@@ -5042,12 +5167,6 @@
 	 and IMAGPART_EXPR.  */
       abort ();
 
-    case BUILT_IN_SIN:
-    case BUILT_IN_SINF:
-    case BUILT_IN_SINL:
-    case BUILT_IN_COS:
-    case BUILT_IN_COSF:
-    case BUILT_IN_COSL:
     case BUILT_IN_EXP:
     case BUILT_IN_EXPF:
     case BUILT_IN_EXPL:
@@ -5116,6 +5235,19 @@
       if (! flag_unsafe_math_optimizations)
 	break;
       target = expand_builtin_mathfn_2 (exp, target, subtarget);
+      if (target)
+	return target;
+      break;
+
+    case BUILT_IN_SIN:
+    case BUILT_IN_SINF:
+    case BUILT_IN_SINL:
+    case BUILT_IN_COS:
+    case BUILT_IN_COSF:
+    case BUILT_IN_COSL:
+      if (! flag_unsafe_math_optimizations)
+	break;
+      target = expand_builtin_mathfn_3 (exp, target, subtarget);
       if (target)
 	return target;
       break;
Index: gcc/genopinit.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/genopinit.c,v
retrieving revision 1.69
diff -u -r1.69 genopinit.c
--- gcc/genopinit.c	10 Mar 2004 22:36:12 -0000	1.69
+++ gcc/genopinit.c	5 Apr 2004 10:16:12 -0000
@@ -122,6 +122,7 @@
   "round_optab->handlers[$A].insn_code = CODE_FOR_$(round$a2$)",
   "trunc_optab->handlers[$A].insn_code = CODE_FOR_$(trunc$a2$)",
   "nearbyint_optab->handlers[$A].insn_code = CODE_FOR_$(nearbyint$a2$)",
+  "sincos_optab->handlers[$A].insn_code = CODE_FOR_$(sincos$a3$)",
   "sin_optab->handlers[$A].insn_code = CODE_FOR_$(sin$a2$)",
   "cos_optab->handlers[$A].insn_code = CODE_FOR_$(cos$a2$)",
   "exp_optab->handlers[$A].insn_code = CODE_FOR_$(exp$a2$)",
Index: gcc/optabs.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/optabs.c,v
retrieving revision 1.213
diff -u -r1.213 optabs.c
--- gcc/optabs.c	1 Apr 2004 03:50:29 -0000	1.213
+++ gcc/optabs.c	5 Apr 2004 10:16:12 -0000
@@ -2147,6 +2147,109 @@
   return 0;
 }
 
+/* Generate code to perform an operation specified by UNOPPTAB
+   on operand OP0, with two results to TARG0 and TARG1.
+   We assume that the order of the operands for the instruction
+   is TARG0, TARG1, OP0.
+
+   Either TARG0 or TARG1 may be zero, but what that means is that
+   the result is not actually wanted.  We will generate it into
+   a dummy pseudo-reg and discard it.  They may not both be zero.
+
+   Returns 1 if this operation can be performed; 0 if not.  */
+
+int
+expand_twoval_unop (optab unoptab, rtx targ0, rtx targ1, rtx op0,
+		    int unsignedp)
+{
+  enum machine_mode mode = GET_MODE (targ0 ? targ0 : targ1);
+  enum mode_class class;
+  enum machine_mode wider_mode;
+  rtx entry_last = get_last_insn ();
+  rtx last;
+
+  class = GET_MODE_CLASS (mode);
+
+  op0 = protect_from_queue (op0, 0);
+
+  if (flag_force_mem)
+    {
+      op0 = force_not_mem (op0);
+    }
+
+  if (targ0)
+    targ0 = protect_from_queue (targ0, 1);
+  else
+    targ0 = gen_reg_rtx (mode);
+  if (targ1)
+    targ1 = protect_from_queue (targ1, 1);
+  else
+    targ1 = gen_reg_rtx (mode);
+
+  /* Record where to go back to if we fail.  */
+  last = get_last_insn ();
+
+  if (unoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+    {
+      int icode = (int) unoptab->handlers[(int) mode].insn_code;
+      enum machine_mode mode0 = insn_data[icode].operand[2].mode;
+      rtx pat;
+      rtx xop0 = op0;
+
+      if (GET_MODE (xop0) != VOIDmode
+	  && GET_MODE (xop0) != mode0)
+	xop0 = convert_to_mode (mode0, xop0, unsignedp);
+
+      /* Now, if insn doesn't accept these operands, put them into pseudos.  */
+      if (! (*insn_data[icode].operand[2].predicate) (xop0, mode0))
+	xop0 = copy_to_mode_reg (mode0, xop0);
+
+      /* We could handle this, but we should always be called with a pseudo
+	 for our targets and all insns should take them as outputs.  */
+      if (! (*insn_data[icode].operand[0].predicate) (targ0, mode)
+	  || ! (*insn_data[icode].operand[1].predicate) (targ1, mode))
+	abort ();
+
+      pat = GEN_FCN (icode) (targ0, targ1, xop0);
+      if (pat)
+	{
+	  emit_insn (pat);
+	  return 1;
+	}
+      else
+	delete_insns_since (last);
+    }
+
+  /* It can't be done in this mode.  Can we do it in a wider mode?  */
+
+  if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
+    {
+      for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
+	   wider_mode = GET_MODE_WIDER_MODE (wider_mode))
+	{
+	  if (unoptab->handlers[(int) wider_mode].insn_code
+	      != CODE_FOR_nothing)
+	    {
+	      rtx t0 = gen_reg_rtx (wider_mode);
+	      rtx t1 = gen_reg_rtx (wider_mode);
+	      rtx cop0 = convert_modes (wider_mode, mode, op0, unsignedp);
+
+	      if (expand_twoval_unop (unoptab, t0, t1, cop0, unsignedp))
+		{
+		  convert_move (targ0, t0, unsignedp);
+		  convert_move (targ1, t1, unsignedp);
+		  return 1;
+		}
+	      else
+		delete_insns_since (last);
+	    }
+	}
+    }
+
+  delete_insns_since (entry_last);
+  return 0;
+}
+
 /* Generate code to perform an operation specified by BINOPTAB
    on operands OP0 and OP1, with two results to TARG1 and TARG2.
    We assume that the order of the operands for the instruction
@@ -5275,6 +5378,7 @@
   round_optab = init_optab (UNKNOWN);
   btrunc_optab = init_optab (UNKNOWN);
   nearbyint_optab = init_optab (UNKNOWN);
+  sincos_optab = init_optab (UNKNOWN);
   sin_optab = init_optab (UNKNOWN);
   cos_optab = init_optab (UNKNOWN);
   exp_optab = init_optab (UNKNOWN);
Index: gcc/optabs.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/optabs.h,v
retrieving revision 1.23
diff -u -r1.23 optabs.h
--- gcc/optabs.h	10 Mar 2004 22:36:12 -0000	1.23
+++ gcc/optabs.h	5 Apr 2004 10:16:12 -0000
@@ -148,6 +148,8 @@
   OTI_parity,
   /* Square root */
   OTI_sqrt,
+  /* Sine-Cosine */
+  OTI_sincos,
   /* Sine */
   OTI_sin,
   /* Cosine */
@@ -264,6 +266,7 @@
 #define popcount_optab (optab_table[OTI_popcount])
 #define parity_optab (optab_table[OTI_parity])
 #define sqrt_optab (optab_table[OTI_sqrt])
+#define sincos_optab (optab_table[OTI_sincos])
 #define sin_optab (optab_table[OTI_sin])
 #define cos_optab (optab_table[OTI_cos])
 #define exp_optab (optab_table[OTI_exp])
@@ -385,6 +388,9 @@
 /* Expand a binary operation with both signed and unsigned forms.  */
 extern rtx sign_expand_binop (enum machine_mode, optab, optab, rtx, rtx,
 			      rtx, int, enum optab_methods);
+
+/* Generate code to perform an operation on one operand with two results.  */
+extern int expand_twoval_unop (optab, rtx, rtx, rtx, int);
 
 /* Generate code to perform an operation on two operands with two results.  */
 extern int expand_twoval_binop (optab, rtx, rtx, rtx, rtx, int);
Index: gcc/reg-stack.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/reg-stack.c,v
retrieving revision 1.145
diff -u -r1.145 reg-stack.c
--- gcc/reg-stack.c	24 Mar 2004 02:28:40 -0000	1.145
+++ gcc/reg-stack.c	5 Apr 2004 10:16:13 -0000
@@ -1768,6 +1768,60 @@
 		replace_reg (dest, FIRST_STACK_REG);
 		break;
 
+	      case UNSPEC_SINCOS_COS:
+		/* These insns operate on the top two stack slots,
+		   first part of one input, double output insn.  */
+
+		src1 = get_true_reg (&XVECEXP (pat_src, 0, 0));
+
+		emit_swap_insn (insn, regstack, *src1);
+
+		src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
+
+		/* Push the result back onto stack. Empty stack slot
+		   will be filled in second part of insn. */
+		if (STACK_REG_P (*dest)) {
+		  regstack->reg[regstack->top + 1] = REGNO (*dest);
+		  SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
+		  replace_reg (dest, FIRST_STACK_REG);
+		}
+
+		if (src1_note)
+		  {
+		    replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG);
+		    regstack->top--;
+		    CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (*src1));
+		  }
+		replace_reg (src1, FIRST_STACK_REG);
+		break;
+
+	      case UNSPEC_SINCOS_SIN:
+		src1 = get_true_reg (&XVECEXP (pat_src, 0, 0));
+
+		emit_swap_insn (insn, regstack, *src1);
+
+		src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
+
+		/* Push the result back onto stack. Fill empty slot from
+		   first part of insn and fix top of stack pointer.  */
+		if (STACK_REG_P (*dest)) {
+		  regstack->reg[regstack->top] = REGNO (*dest);
+		  SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
+		  replace_reg (dest, FIRST_STACK_REG + 1);
+
+		  regstack->top++;
+		}
+
+		if (src1_note)
+		  {
+		    replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG);
+		    regstack->top--;
+		    CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (*src1));
+		  }
+
+		replace_reg (src1, FIRST_STACK_REG);
+		break;
+
 	      case UNSPEC_SAHF:
 		/* (unspec [(unspec [(compare)] UNSPEC_FNSTSW)] UNSPEC_SAHF)
 		   The combination matches the PPRO fcomi instruction.  */
Index: gcc/config/i386/i386.md
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/i386/i386.md,v
retrieving revision 1.523
diff -u -r1.523 i386.md
--- gcc/config/i386/i386.md	2 Apr 2004 15:05:55 -0000	1.523
+++ gcc/config/i386/i386.md	5 Apr 2004 10:16:16 -0000
@@ -121,6 +121,9 @@
    (UNSPEC_FRNDINT		68)
    (UNSPEC_F2XM1		69)
 
+   (UNSPEC_SINCOS_COS		80)
+   (UNSPEC_SINCOS_SIN		81)
+
    ; REP instruction
    (UNSPEC_REP			75)
   ])
@@ -14916,7 +14919,7 @@
    (set_attr "mode" "XF")
    (set_attr "athlon_decode" "direct")])
 
-(define_insn "sindf2"
+(define_insn "*sindf2"
   [(set (match_operand:DF 0 "register_operand" "=f")
 	(unspec:DF [(match_operand:DF 1 "register_operand" "0")] UNSPEC_SIN))]
   "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
@@ -14925,7 +14928,7 @@
   [(set_attr "type" "fpspc")
    (set_attr "mode" "DF")])
 
-(define_insn "sinsf2"
+(define_insn "*sinsf2"
   [(set (match_operand:SF 0 "register_operand" "=f")
 	(unspec:SF [(match_operand:SF 1 "register_operand" "0")] UNSPEC_SIN))]
   "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
@@ -14945,7 +14948,7 @@
   [(set_attr "type" "fpspc")
    (set_attr "mode" "DF")])
 
-(define_insn "sinxf2"
+(define_insn "*sinxf2"
   [(set (match_operand:XF 0 "register_operand" "=f")
 	(unspec:XF [(match_operand:XF 1 "register_operand" "0")] UNSPEC_SIN))]
   "TARGET_80387 && !TARGET_NO_FANCY_MATH_387
@@ -14954,7 +14957,7 @@
   [(set_attr "type" "fpspc")
    (set_attr "mode" "XF")])
 
-(define_insn "cosdf2"
+(define_insn "*cosdf2"
   [(set (match_operand:DF 0 "register_operand" "=f")
 	(unspec:DF [(match_operand:DF 1 "register_operand" "0")] UNSPEC_COS))]
   "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
@@ -14963,7 +14966,7 @@
   [(set_attr "type" "fpspc")
    (set_attr "mode" "DF")])
 
-(define_insn "cossf2"
+(define_insn "*cossf2"
   [(set (match_operand:SF 0 "register_operand" "=f")
 	(unspec:SF [(match_operand:SF 1 "register_operand" "0")] UNSPEC_COS))]
   "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
@@ -14983,7 +14986,7 @@
   [(set_attr "type" "fpspc")
    (set_attr "mode" "DF")])
 
-(define_insn "cosxf2"
+(define_insn "*cosxf2"
   [(set (match_operand:XF 0 "register_operand" "=f")
 	(unspec:XF [(match_operand:XF 1 "register_operand" "0")] UNSPEC_COS))]
   "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
@@ -14991,6 +14994,156 @@
   "fcos"
   [(set_attr "type" "fpspc")
    (set_attr "mode" "XF")])
+
+;; With sincos pattern defined, sin and cos builtin function will be
+;; expanded to sincos pattern with one of its outputs left unused. 
+;; Cse pass  will detected, if two sincos patterns can be combined,
+;; otherwise sincos pattern will be splitted back to sin or cos pattern,
+;; depending on the unused output.
+
+(define_insn "sincosdf3"
+  [(set (match_operand:DF 0 "register_operand" "=f")
+	(unspec:DF [(match_operand:DF 2 "register_operand" "0")]
+		   UNSPEC_SINCOS_COS))
+   (set (match_operand:DF 1 "register_operand" "=u")
+        (unspec:DF [(match_dup 2)] UNSPEC_SINCOS_SIN))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
+   && flag_unsafe_math_optimizations"
+  "fsincos"
+  [(set_attr "type" "fpspc")
+   (set_attr "mode" "DF")])
+
+(define_split
+  [(set (match_operand:DF 0 "register_operand" "")
+	(unspec:DF [(match_operand:DF 2 "register_operand" "")]
+		   UNSPEC_SINCOS_COS))
+   (set (match_operand:DF 1 "register_operand" "")
+	(unspec:DF [(match_dup 2)] UNSPEC_SINCOS_SIN))]
+  "find_regno_note (insn, REG_UNUSED, REGNO (operands[0]))
+   && !reload_completed && !reload_in_progress"
+  [(set (match_dup 1) (unspec:DF [(match_dup 2)] UNSPEC_SIN))]
+  "")
+
+(define_split
+  [(set (match_operand:DF 0 "register_operand" "")
+	(unspec:DF [(match_operand:DF 2 "register_operand" "")]
+		   UNSPEC_SINCOS_COS))
+   (set (match_operand:DF 1 "register_operand" "")
+	(unspec:DF [(match_dup 2)] UNSPEC_SINCOS_SIN))]
+  "find_regno_note (insn, REG_UNUSED, REGNO (operands[1]))
+   && !reload_completed && !reload_in_progress"
+  [(set (match_dup 0) (unspec:DF [(match_dup 2)] UNSPEC_COS))]
+  "")
+
+(define_insn "sincossf3"
+  [(set (match_operand:SF 0 "register_operand" "=f")
+	(unspec:SF [(match_operand:SF 2 "register_operand" "0")]
+		   UNSPEC_SINCOS_COS))
+   (set (match_operand:SF 1 "register_operand" "=u")
+        (unspec:SF [(match_dup 2)] UNSPEC_SINCOS_SIN))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
+   && flag_unsafe_math_optimizations"
+  "fsincos"
+  [(set_attr "type" "fpspc")
+   (set_attr "mode" "SF")])
+
+(define_split
+  [(set (match_operand:SF 0 "register_operand" "")
+	(unspec:SF [(match_operand:SF 2 "register_operand" "")]
+		   UNSPEC_SINCOS_COS))
+   (set (match_operand:SF 1 "register_operand" "")
+	(unspec:SF [(match_dup 2)] UNSPEC_SINCOS_SIN))]
+  "find_regno_note (insn, REG_UNUSED, REGNO (operands[0]))
+   && !reload_completed && !reload_in_progress"
+  [(set (match_dup 1) (unspec:SF [(match_dup 2)] UNSPEC_SIN))]
+  "")
+
+(define_split
+  [(set (match_operand:SF 0 "register_operand" "")
+	(unspec:SF [(match_operand:SF 2 "register_operand" "")]
+		   UNSPEC_SINCOS_COS))
+   (set (match_operand:SF 1 "register_operand" "")
+	(unspec:SF [(match_dup 2)] UNSPEC_SINCOS_SIN))]
+  "find_regno_note (insn, REG_UNUSED, REGNO (operands[1]))
+   && !reload_completed && !reload_in_progress"
+  [(set (match_dup 0) (unspec:SF [(match_dup 2)] UNSPEC_COS))]
+  "")
+
+(define_insn "*sincosextendsfdf3"
+  [(set (match_operand:DF 0 "register_operand" "=f")
+	(unspec:DF [(float_extend:DF
+		     (match_operand:SF 2 "register_operand" "0"))]
+		   UNSPEC_SINCOS_COS))
+   (set (match_operand:DF 1 "register_operand" "=u")
+        (unspec:DF [(float_extend:DF
+		     (match_dup 2))] UNSPEC_SINCOS_SIN))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
+   && flag_unsafe_math_optimizations"
+  "fsincos"
+  [(set_attr "type" "fpspc")
+   (set_attr "mode" "DF")])
+
+(define_split
+  [(set (match_operand:DF 0 "register_operand" "")
+	(unspec:DF [(float_extend:DF
+		     (match_operand:SF 2 "register_operand" ""))]
+		   UNSPEC_SINCOS_COS))
+   (set (match_operand:DF 1 "register_operand" "")
+        (unspec:DF [(float_extend:DF
+		     (match_dup 2))] UNSPEC_SINCOS_SIN))]
+  "find_regno_note (insn, REG_UNUSED, REGNO (operands[0]))
+   && !reload_completed && !reload_in_progress"
+  [(set (match_dup 1) (unspec:DF [(float_extend:DF
+				   (match_dup 2))] UNSPEC_SIN))]
+  "")
+
+(define_split
+  [(set (match_operand:DF 0 "register_operand" "")
+	(unspec:DF [(float_extend:DF
+		     (match_operand:SF 2 "register_operand" ""))]
+		   UNSPEC_SINCOS_COS))
+   (set (match_operand:DF 1 "register_operand" "")
+        (unspec:DF [(float_extend:DF
+		     (match_dup 2))] UNSPEC_SINCOS_SIN))]
+  "find_regno_note (insn, REG_UNUSED, REGNO (operands[1]))
+   && !reload_completed && !reload_in_progress"
+  [(set (match_dup 0) (unspec:DF [(float_extend:DF
+				   (match_dup 2))] UNSPEC_COS))]
+  "")
+
+(define_insn "sincosxf3"
+  [(set (match_operand:XF 0 "register_operand" "=f")
+	(unspec:XF [(match_operand:XF 2 "register_operand" "0")]
+		   UNSPEC_SINCOS_COS))
+   (set (match_operand:XF 1 "register_operand" "=u")
+        (unspec:XF [(match_dup 2)] UNSPEC_SINCOS_SIN))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
+   && flag_unsafe_math_optimizations"
+  "fsincos"
+  [(set_attr "type" "fpspc")
+   (set_attr "mode" "XF")])
+
+(define_split
+  [(set (match_operand:XF 0 "register_operand" "")
+	(unspec:XF [(match_operand:XF 2 "register_operand" "")]
+		   UNSPEC_SINCOS_COS))
+   (set (match_operand:XF 1 "register_operand" "")
+	(unspec:XF [(match_dup 2)] UNSPEC_SINCOS_SIN))]
+  "find_regno_note (insn, REG_UNUSED, REGNO (operands[0]))
+   && !reload_completed && !reload_in_progress"
+  [(set (match_dup 1) (unspec:XF [(match_dup 2)] UNSPEC_SIN))]
+  "")
+
+(define_split
+  [(set (match_operand:XF 0 "register_operand" "")
+	(unspec:XF [(match_operand:XF 2 "register_operand" "")]
+		   UNSPEC_SINCOS_COS))
+   (set (match_operand:XF 1 "register_operand" "")
+	(unspec:XF [(match_dup 2)] UNSPEC_SINCOS_SIN))]
+  "find_regno_note (insn, REG_UNUSED, REGNO (operands[1]))
+   && !reload_completed && !reload_in_progress"
+  [(set (match_dup 0) (unspec:XF [(match_dup 2)] UNSPEC_COS))]
+  "")
 
 (define_insn "atan2df3_1"
   [(set (match_operand:DF 0 "register_operand" "=f")
Index: gcc/testsuite/ChangeLog
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/testsuite/ChangeLog,v
retrieving revision 1.3652
diff -u -r1.3652 ChangeLog
--- gcc/testsuite/ChangeLog	2 Apr 2004 23:50:42 -0000	1.3652
+++ gcc/testsuite/ChangeLog	5 Apr 2004 10:16:19 -0000
@@ -1,3 +1,7 @@
+2004-04-05  Uros Bizjak <uros@kss-loka.si>
+
+	* gcc.dg/builtins-36.c: New test.
+
 2004-04-02  Nathanael Nerode  <neroden@gcc.gnu.org>
 
 	* g++.dg/README: Bring up to date with new subdirectories; remove
/* Copyright (C) 2004 Free Software Foundation.

   Check sin, sinf, sinl, cos, cosf and cosl built-in functions
   eventually compile to sincos, sincosf and sincosl.

   Written by Uros Bizjak, 5th April 2004.  */

/* { dg-do compile } */
/* { dg-options "-O2 -ffast-math" } */

extern double sin(double);
extern float sinf(float);
extern long double sinl(long double);

extern double cos(double);
extern float cosf(float);
extern long double cosl(long double);


double test1(double x)
{
	double y1, y2;

	y1 = sin(x);
	y2 = cos(x);

	return y1 - y2;
}

float test1f(float x)
{
	float y1, y2;

	y1 = sinf(x);
	y2 = cosf(x);

	return y1 - y2;
}

long double test1l(long double x)
{
	long double y1, y2;

	y1 = sinl(x);
	y2 = cosl(x);

	return y1 - y2;
}

double test2(double x)
{
	return sin(x);
}

float test2f(float x)
{
	return sinf(x);
}

long double test2l(long double x)
{
	return sinl(x);
}

double test3(double x)
{
	return cos(x);
}

float test3f(float x)
{
	return cosf(x);
}

long double test3l(long double x)
{
	return cosl(x);
}
	.file	"builtins-36.c"
	.text
	.p2align 4,,15
.globl test1
	.type	test1, @function
test1:
	pushl	%ebp
	movl	%esp, %ebp
	fldl	8(%ebp)
	fsincos
	popl	%ebp
	fsubrp	%st, %st(1)
	ret
	.size	test1, .-test1
	.p2align 4,,15
.globl test1f
	.type	test1f, @function
test1f:
	pushl	%ebp
	movl	%esp, %ebp
	flds	8(%ebp)
	fsincos
	popl	%ebp
	fsubrp	%st, %st(1)
	ret
	.size	test1f, .-test1f
	.p2align 4,,15
.globl test1l
	.type	test1l, @function
test1l:
	pushl	%ebp
	movl	%esp, %ebp
	fldt	8(%ebp)
	popl	%ebp
	fsincos
	fsubrp	%st, %st(1)
	ret
	.size	test1l, .-test1l
	.p2align 4,,15
.globl test2
	.type	test2, @function
test2:
	pushl	%ebp
	movl	%esp, %ebp
	fldl	8(%ebp)
	fsin
	popl	%ebp
	ret
	.size	test2, .-test2
	.p2align 4,,15
.globl test2f
	.type	test2f, @function
test2f:
	pushl	%ebp
	movl	%esp, %ebp
	flds	8(%ebp)
	fsin
	popl	%ebp
	ret
	.size	test2f, .-test2f
	.p2align 4,,15
.globl test2l
	.type	test2l, @function
test2l:
	pushl	%ebp
	movl	%esp, %ebp
	fldt	8(%ebp)
	popl	%ebp
	fsin
	ret
	.size	test2l, .-test2l
	.p2align 4,,15
.globl test3
	.type	test3, @function
test3:
	pushl	%ebp
	movl	%esp, %ebp
	fldl	8(%ebp)
	fcos
	popl	%ebp
	ret
	.size	test3, .-test3
	.p2align 4,,15
.globl test3f
	.type	test3f, @function
test3f:
	pushl	%ebp
	movl	%esp, %ebp
	flds	8(%ebp)
	fcos
	popl	%ebp
	ret
	.size	test3f, .-test3f
	.p2align 4,,15
.globl test3l
	.type	test3l, @function
test3l:
	pushl	%ebp
	movl	%esp, %ebp
	fldt	8(%ebp)
	popl	%ebp
	fcos
	ret
	.size	test3l, .-test3l
	.section	.note.GNU-stack,"",@progbits
	.ident	"GCC: (GNU) 3.5.0 20040405 (experimental)"

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