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] Fix PR17687, sincos causing extra addressable vars


This fixes PR17687 by introducing a better internal representation
for sincos.  The representation of choice is the cexp function in
a variant that takes just the imaginary part of the complex argument.
I have created a new builtin for this, called CEXPI (cexp-imaginary).
The extra builtin (rather than using { 0, x } as argument to cexp) allows
one temporary less during the conversion and does not require us to rely
on TER to see the special argument form at expansion time.

The conversion of sincos to cexpi is done at gimplification time and
the transformation back to sincos is done at expansion time where we
also can expand via optab directly and avoid addressable vars completely
(otherwise we're re-introducing them at expansion time).

Bootstrapped and tested on x86_64-unknown-linux-gnu,

ok for mainline?

Thanks,
Richard.

:ADDPATCH middle-end:

2006-12-06  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/17687
	* builtins.def (BUILT_IN_CEXPI, BUILT_IN_CEXPIF, BUILT_IN_CEXPIL):
	New builtins for imaginary argument cexp.
	* builtin-types.def (BT_FN_COMPLEX_FLOAT_FLOAT,
	BT_FN_COMPLEX_DOUBLE_DOUBLE, BT_FN_COMPLEX_LONGDOUBLE_LONGDOUBLE):
	New required builtin types.
	* builtins.c (expand_builtin_cexpi): Declare.
	(mathfn_built_in): Handle BUILT_IN_CEXPI.
	(expand_builtin_cexpi): New static helper.
	(expand_builtin): Call it.
	(fold_builtin_1): Handle folding of CEXPI.
	(do_mpfr_sincos): Adjust for CEXPI evaluation.
	* gimplify.c (gimplify_call_expr): Gimplify calls to sincos to
	calls to cexpi.

Index: builtins.def
===================================================================
*** builtins.def	(revision 119579)
--- builtins.def	(working copy)
*************** DEF_C99_BUILTIN        (BUILT_IN_CCOSL, 
*** 452,457 ****
--- 452,460 ----
  DEF_C99_BUILTIN        (BUILT_IN_CEXP, "cexp", BT_FN_COMPLEX_DOUBLE_COMPLEX_DOUBLE, ATTR_MATHFN_FPROUNDING)
  DEF_C99_BUILTIN        (BUILT_IN_CEXPF, "cexpf", BT_FN_COMPLEX_FLOAT_COMPLEX_FLOAT, ATTR_MATHFN_FPROUNDING)
  DEF_C99_BUILTIN        (BUILT_IN_CEXPL, "cexpl", BT_FN_COMPLEX_LONGDOUBLE_COMPLEX_LONGDOUBLE, ATTR_MATHFN_FPROUNDING)
+ DEF_GCC_BUILTIN        (BUILT_IN_CEXPI, "cexpi", BT_FN_COMPLEX_DOUBLE_DOUBLE, ATTR_MATHFN_FPROUNDING)
+ DEF_GCC_BUILTIN        (BUILT_IN_CEXPIF, "cexpif", BT_FN_COMPLEX_FLOAT_FLOAT, ATTR_MATHFN_FPROUNDING)
+ DEF_GCC_BUILTIN        (BUILT_IN_CEXPIL, "cexpil", BT_FN_COMPLEX_LONGDOUBLE_LONGDOUBLE, ATTR_MATHFN_FPROUNDING)
  DEF_C99_BUILTIN        (BUILT_IN_CIMAG, "cimag", BT_FN_DOUBLE_COMPLEX_DOUBLE, ATTR_CONST_NOTHROW_LIST)
  DEF_C99_BUILTIN        (BUILT_IN_CIMAGF, "cimagf", BT_FN_FLOAT_COMPLEX_FLOAT, ATTR_CONST_NOTHROW_LIST)
  DEF_C99_BUILTIN        (BUILT_IN_CIMAGL, "cimagl", BT_FN_LONGDOUBLE_COMPLEX_LONGDOUBLE, ATTR_CONST_NOTHROW_LIST)
Index: builtin-types.def
===================================================================
*** builtin-types.def	(revision 119579)
--- builtin-types.def	(working copy)
*************** DEF_FUNCTION_TYPE_1 (BT_FN_DOUBLE_COMPLE
*** 159,164 ****
--- 159,170 ----
  		     BT_DOUBLE, BT_COMPLEX_DOUBLE)
  DEF_FUNCTION_TYPE_1 (BT_FN_LONGDOUBLE_COMPLEX_LONGDOUBLE,
  		     BT_LONGDOUBLE, BT_COMPLEX_LONGDOUBLE)
+ DEF_FUNCTION_TYPE_1 (BT_FN_COMPLEX_FLOAT_FLOAT,
+ 		     BT_COMPLEX_FLOAT, BT_FLOAT)
+ DEF_FUNCTION_TYPE_1 (BT_FN_COMPLEX_DOUBLE_DOUBLE,
+ 		     BT_COMPLEX_DOUBLE, BT_DOUBLE)
+ DEF_FUNCTION_TYPE_1 (BT_FN_COMPLEX_LONGDOUBLE_LONGDOUBLE,
+ 		     BT_COMPLEX_LONGDOUBLE, BT_LONGDOUBLE)
  DEF_FUNCTION_TYPE_1 (BT_FN_PTR_UINT, BT_PTR, BT_UINT)
  DEF_FUNCTION_TYPE_1 (BT_FN_PTR_SIZE, BT_PTR, BT_SIZE)
  DEF_FUNCTION_TYPE_1 (BT_FN_INT_INT, BT_INT, BT_INT)
Index: builtins.c
===================================================================
*** builtins.c	(revision 119609)
--- builtins.c	(working copy)
*************** static rtx expand_builtin_mathfn (tree, 
*** 95,100 ****
--- 95,101 ----
  static rtx expand_builtin_mathfn_2 (tree, rtx, rtx);
  static rtx expand_builtin_mathfn_3 (tree, rtx, rtx);
  static rtx expand_builtin_sincos (tree);
+ static rtx expand_builtin_cexpi (tree, rtx, rtx);
  static rtx expand_builtin_int_roundingfn (tree, rtx, rtx);
  static rtx expand_builtin_int_roundingfn_2 (tree, rtx, rtx);
  static rtx expand_builtin_args_info (tree);
*************** mathfn_built_in (tree type, enum built_i
*** 1651,1656 ****
--- 1652,1658 ----
        CASE_MATHFN (BUILT_IN_ATANH)
        CASE_MATHFN (BUILT_IN_CBRT)
        CASE_MATHFN (BUILT_IN_CEIL)
+       CASE_MATHFN (BUILT_IN_CEXPI)
        CASE_MATHFN (BUILT_IN_COPYSIGN)
        CASE_MATHFN (BUILT_IN_COS)
        CASE_MATHFN (BUILT_IN_COSH)
*************** expand_builtin_sincos (tree exp)
*** 2218,2223 ****
--- 2220,2294 ----
    return const0_rtx;
  }
  
+ /* Expand a call to the internal cexpi builtin to the sincos math function.
+    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_cexpi (tree exp, rtx target, rtx subtarget)
+ {
+   tree fndecl = get_callee_fndecl (exp);
+   tree arglist = TREE_OPERAND (exp, 1);
+   enum machine_mode mode;
+   tree arg, type;
+   rtx op0, op1, op2;
+ 
+   if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+     return 0;
+ 
+   arg = TREE_VALUE (arglist);
+   type = TREE_TYPE (arg);
+   mode = TYPE_MODE (TREE_TYPE (arg));
+ 
+   /* Try expanding via a sincos optab, fall back to emitting a libcall
+      to sincos.  We are sure we have sincos either way because cexpi
+      is only generated from sincos.  */
+   if (sincos_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+     {
+       op1 = gen_reg_rtx (mode);
+       op2 = gen_reg_rtx (mode);
+ 
+       op0 = expand_expr (arg, subtarget, VOIDmode, 0);
+ 
+       /* Compute into op1 and op2.  */
+       expand_twoval_unop (sincos_optab, op0, op2, op1, 0);
+     }
+   else
+     {
+       tree narglist, fn = NULL_TREE;
+       tree top1, top2;
+       rtx op1a, op2a;
+ 
+       if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPIF)
+ 	fn = built_in_decls[BUILT_IN_SINCOSF];
+       else if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPI)
+ 	fn = built_in_decls[BUILT_IN_SINCOS];
+       else if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPIL)
+ 	fn = built_in_decls[BUILT_IN_SINCOSL];
+       gcc_assert (fn);
+  
+       op1 = assign_temp (TREE_TYPE (arg), 0, 1, 1);
+       op2 = assign_temp (TREE_TYPE (arg), 0, 1, 1);
+       op1a = copy_to_mode_reg (Pmode, XEXP (op1, 0));
+       op2a = copy_to_mode_reg (Pmode, XEXP (op2, 0));
+       top1 = make_tree (build_pointer_type (TREE_TYPE (arg)), op1a);
+       top2 = make_tree (build_pointer_type (TREE_TYPE (arg)), op2a);
+ 
+       narglist = build_tree_list (NULL_TREE, arg);
+       narglist = tree_cons (NULL_TREE, top1, narglist);
+       narglist = tree_cons (NULL_TREE, top2, narglist);
+ 
+       expand_normal (build_function_call_expr (fn, narglist));
+     }
+ 
+   /* Now build the proper return type.  */
+   return expand_expr (build2 (COMPLEX_EXPR, build_complex_type (type),
+ 			      make_tree (TREE_TYPE (arg), op2),
+ 			      make_tree (TREE_TYPE (arg), op1)),
+ 		      target, VOIDmode, 0);
+ }
+ 
  /* Expand a call to one of the builtin rounding functions gcc defines
     as an extension (lfloor and lceil).  As these are gcc extensions we
     do not need to worry about setting errno to EDOM.
*************** expand_builtin (tree exp, rtx target, rt
*** 5770,5775 ****
--- 5841,5851 ----
  	return target;
        break;
  
+     CASE_FLT_FN (BUILT_IN_CEXPI):
+       target = expand_builtin_cexpi (exp, target, subtarget);
+       gcc_assert (target);
+       return target;
+ 
      CASE_FLT_FN (BUILT_IN_SIN):
      CASE_FLT_FN (BUILT_IN_COS):
        if (! flag_unsafe_math_optimizations)
*************** fold_builtin_1 (tree fndecl, tree arglis
*** 9193,9199 ****
        if (validate_arglist (arglist, REAL_TYPE, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
  	return do_mpfr_sincos (TREE_VALUE (arglist), TREE_VALUE (TREE_CHAIN (arglist)),
  			       TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))));
!     break;
  
      CASE_FLT_FN (BUILT_IN_SINH):
        if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
--- 9269,9279 ----
        if (validate_arglist (arglist, REAL_TYPE, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
  	return do_mpfr_sincos (TREE_VALUE (arglist), TREE_VALUE (TREE_CHAIN (arglist)),
  			       TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))));
!       break;
! 
!     CASE_FLT_FN (BUILT_IN_CEXPI):
!       if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
! 	return do_mpfr_sincos (TREE_VALUE (arglist), NULL_TREE, NULL_TREE);
  
      CASE_FLT_FN (BUILT_IN_SINH):
        if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
*************** do_mpfr_arg3 (tree arg1, tree arg2, tree
*** 11665,11670 ****
--- 11745,11752 ----
  
  /* If argument ARG is a REAL_CST, call mpfr_sin_cos() on it and set
     the pointers *(ARG_SINP) and *(ARG_COSP) to the resulting values.
+    If ARG_SINP and ARG_COSP are NULL then the result is returned
+    as a complex value.
     The type is taken from the type of ARG and is used for setting the
     precision of the calculation and results.  */
  
*************** do_mpfr_sincos (tree arg, tree arg_sinp,
*** 11696,11701 ****
--- 11778,11788 ----
  	  mpfr_clears (m, ms, mc, NULL);
  	  if (result_s && result_c)
  	    {
+ 	      /* If we are to return in a complex value do so.  */
+ 	      if (!arg_sinp && !arg_cosp)
+ 		return build_complex (build_complex_type (type),
+ 				      result_c, result_s);
+ 
  	      /* Dereference the sin/cos pointer arguments.  */
  	      arg_sinp = build_fold_indirect_ref (arg_sinp);
  	      arg_cosp = build_fold_indirect_ref (arg_cosp);
Index: gimplify.c
===================================================================
*** gimplify.c	(revision 119609)
--- gimplify.c	(working copy)
*************** gimplify_call_expr (tree *expr_p, tree *
*** 2051,2056 ****
--- 2051,2095 ----
      {
        tree arglist = TREE_OPERAND (*expr_p, 1);
        tree new = fold_builtin (decl, arglist, !want_value);
+       tree fn;
+ 
+       /* We treat sincos specially here because we want to avoid
+ 	 making the second and third argument addressable.  We do so
+ 	 by creating a new compound expression with a temporary
+ 	 complex value to store the result of a cexpi call
+ 	 and to initialize the sincos result arguments.  */
+       if ((DECL_FUNCTION_CODE (decl) == BUILT_IN_SINCOSF
+            || DECL_FUNCTION_CODE (decl) == BUILT_IN_SINCOS
+            || DECL_FUNCTION_CODE (decl) == BUILT_IN_SINCOSL)
+ 	  && (fn = mathfn_built_in (TREE_TYPE (TREE_VALUE (arglist)),
+ 				    BUILT_IN_CEXPI)))
+ 	{
+ 	  tree arg = TREE_VALUE (arglist);
+ 	  tree type = TREE_TYPE (arg);
+ 	  tree ctype = TREE_TYPE (TREE_TYPE (fn));
+ 	  tree tmp = create_tmp_var (ctype, "sincostmp");
+ 	  tree sinpart, cospart, args;
+ 
+ 	  sinpart = TREE_VALUE (TREE_CHAIN (arglist));
+ 	  sinpart = build_fold_indirect_ref (sinpart);
+ 	  cospart = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+ 	  cospart = build_fold_indirect_ref (cospart);
+ 	  args = build_tree_list (NULL_TREE, arg);
+ 	  DECL_COMPLEX_GIMPLE_REG_P (tmp) = 1;
+ 
+ 	  /* ( ( tmp = cexpi (arg), cospart = __real tmp ),
+ 	         sinpart = __imag tmp )  */
+ 	  new = build2 (COMPOUND_EXPR, type,
+ 	  		build2 (COMPOUND_EXPR, type,
+ 				build2 (MODIFY_EXPR, void_type_node, tmp,
+ 					build_function_call_expr (fn, args)),
+ 				build2 (MODIFY_EXPR, void_type_node,
+ 					cospart,
+ 					build1 (REALPART_EXPR, type, tmp))),
+ 			build2 (MODIFY_EXPR, void_type_node,
+ 				sinpart, build1 (IMAGPART_EXPR, type, tmp)));
+ 	  /* Fall through to re-gimplification.  */
+ 	}
  
        if (new && new != *expr_p)
  	{


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