[PATCH] Implement "atan" builtin as x87 intrinsic

Roger Sayle roger@eyesopen.com
Sun Jun 15 20:45:00 GMT 2003


This patch implements GCC's atan, atanf and atanl mathematical
built-in functions as inline instrinsics on x86.

Firstly, this patch adds "tan" and "atan" optabs to GCC, so that
implementations of these functions can be provided by back-ends.
Secondly, it tweaks the way that we specify whether built-in
mathematical functions may set errno or not in builtins.c.  We now
default to false, and each function that may set errno is responsible
for flagging this explicitly.  Finally, i386.md provides patterns
for atansf2, atandf2, atanxf2 and atantf2 reusing the existing
patterns for the x87's "fpatan" instruction that implements atan2.
This uses the usual idiom that atan(x) = atan2(x,1.0).


The following patch has been tested with a complete bootstrap on
i686-pc-linux-gnu, all languages except treelang, and regression
tested with a top-level "make -k check" with no new failures.
The new i386-387-5.c and i386-387-6.c are clones of i386-387-1.c
and i386-387-2.c, as the latter already contain tests for atan2,
so new files are required to not get false positives from the
scan-assembler tests.  Finally, I've also confirmed by hand that
atan produces the same results with -ffast-math (i.e. when using
this intrinsic) as it does without (i.e. when using libm's atan).

Ok for mainline?


2003-06-15  Roger Sayle  <roger@eyesopen.com>

	* optabs.h (enum optab_index): Add new OTI_tan and OTI_atan.
	(tan_optab, atan_optab): Define corresponding macros.
	* optabs.c (init_optabs): Initialize tan_optab and atan_optab.
	* genopinit.c (optabs): Implement tan_optab and atan_optab
	using tan?f2 and atan?f2 patterns.
	* builtins.c (expand_builtin_mathfn): Handle BUILT_IN_TAN{,F,L}
	using tan_optab, and BUILT_IN_ATAN{,F,L} using atan_optab.
	Change the default value of errno_set to false.
	(expand_builtin): Expand BUILT_IN_TAN{,F,L} and BUILT_IN_ATAN{,F,L}
	using expand_builtin_mathfn.

	* config/i386/i386.md (atansf2, atandf2, atanxf2, atantf2): New
	expander patterns implemented using existing atan2?f3 patterns.

	* gcc.dg/i386-387-5.c: New test case.
	* gcc.dg/i386-387-6.c: New test case.
	* gcc.dg/builtins-23.c: New test case.


Index: optabs.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/optabs.h,v
retrieving revision 1.13
diff -c -3 -p -r1.13 optabs.h
*** optabs.h	3 Jun 2003 21:29:48 -0000	1.13
--- optabs.h	15 Jun 2003 17:01:57 -0000
*************** enum optab_index
*** 149,154 ****
--- 149,158 ----
    OTI_trunc,
    OTI_round,
    OTI_nearbyint,
+   /* Tangent */
+   OTI_tan,
+   /* Inverse tangent */
+   OTI_atan,

    /* Compare insn; two operands.  */
    OTI_cmp,
*************** extern GTY(()) optab optab_table[OTI_MAX
*** 232,237 ****
--- 236,243 ----
  #define trunc_optab (optab_table[OTI_trunc])
  #define round_optab (optab_table[OTI_round])
  #define nearbyint_optab (optab_table[OTI_nearbyint])
+ #define tan_optab (optab_table[OTI_tan])
+ #define atan_optab (optab_table[OTI_atan])

  #define cmp_optab (optab_table[OTI_cmp])
  #define ucmp_optab (optab_table[OTI_ucmp])
Index: optabs.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/optabs.c,v
retrieving revision 1.178
diff -c -3 -p -r1.178 optabs.c
*** optabs.c	11 Jun 2003 06:43:43 -0000	1.178
--- optabs.c	15 Jun 2003 17:01:58 -0000
*************** init_optabs ()
*** 5552,5557 ****
--- 5552,5559 ----
    cos_optab = init_optab (UNKNOWN);
    exp_optab = init_optab (UNKNOWN);
    log_optab = init_optab (UNKNOWN);
+   tan_optab = init_optab (UNKNOWN);
+   atan_optab = init_optab (UNKNOWN);
    strlen_optab = init_optab (UNKNOWN);
    cbranch_optab = init_optab (UNKNOWN);
    cmov_optab = init_optab (UNKNOWN);
Index: genopinit.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/genopinit.c,v
retrieving revision 1.58
diff -c -3 -p -r1.58 genopinit.c
*** genopinit.c	1 Jun 2003 15:59:09 -0000	1.58
--- genopinit.c	15 Jun 2003 17:01:58 -0000
*************** static const char * const optabs[] =
*** 125,130 ****
--- 125,132 ----
    "cos_optab->handlers[$A].insn_code = CODE_FOR_$(cos$a2$)",
    "exp_optab->handlers[$A].insn_code = CODE_FOR_$(exp$a2$)",
    "log_optab->handlers[$A].insn_code = CODE_FOR_$(log$a2$)",
+   "tan_optab->handlers[$A].insn_code = CODE_FOR_$(tan$a2$)",
+   "atan_optab->handlers[$A].insn_code = CODE_FOR_$(atan$a2$)",
    "strlen_optab->handlers[$A].insn_code = CODE_FOR_$(strlen$a$)",
    "one_cmpl_optab->handlers[$A].insn_code = CODE_FOR_$(one_cmpl$a2$)",
    "ffs_optab->handlers[$A].insn_code = CODE_FOR_$(ffs$a2$)",
Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.212
diff -c -3 -p -r1.212 builtins.c
*** builtins.c	15 Jun 2003 06:55:55 -0000	1.212
--- builtins.c	15 Jun 2003 17:01:59 -0000
*************** expand_builtin_mathfn (exp, target, subt
*** 1759,1765 ****
    tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
    tree arglist = TREE_OPERAND (exp, 1);
    enum machine_mode argmode;
!   bool errno_set = true;

    if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
      return 0;
--- 1759,1765 ----
    tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
    tree arglist = TREE_OPERAND (exp, 1);
    enum machine_mode argmode;
!   bool errno_set = false;

    if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
      return 0;
*************** expand_builtin_mathfn (exp, target, subt
*** 1801,1835 ****
      case BUILT_IN_SQRT:
      case BUILT_IN_SQRTF:
      case BUILT_IN_SQRTL:
!       builtin_optab = sqrt_optab; break;
      case BUILT_IN_EXP:
      case BUILT_IN_EXPF:
      case BUILT_IN_EXPL:
!       builtin_optab = exp_optab; break;
      case BUILT_IN_LOG:
      case BUILT_IN_LOGF:
      case BUILT_IN_LOGL:
!       builtin_optab = log_optab; break;
      case BUILT_IN_FLOOR:
      case BUILT_IN_FLOORF:
      case BUILT_IN_FLOORL:
!       errno_set = false ; builtin_optab = floor_optab; break;
      case BUILT_IN_CEIL:
      case BUILT_IN_CEILF:
      case BUILT_IN_CEILL:
!       errno_set = false ; builtin_optab = ceil_optab; break;
      case BUILT_IN_TRUNC:
      case BUILT_IN_TRUNCF:
      case BUILT_IN_TRUNCL:
!       errno_set = false ; builtin_optab = trunc_optab; break;
      case BUILT_IN_ROUND:
      case BUILT_IN_ROUNDF:
      case BUILT_IN_ROUNDL:
!       errno_set = false ; builtin_optab = round_optab; break;
      case BUILT_IN_NEARBYINT:
      case BUILT_IN_NEARBYINTF:
      case BUILT_IN_NEARBYINTL:
!       errno_set = false ; builtin_optab = nearbyint_optab; break;
      default:
        abort ();
      }
--- 1801,1843 ----
      case BUILT_IN_SQRT:
      case BUILT_IN_SQRTF:
      case BUILT_IN_SQRTL:
!       errno_set = true; builtin_optab = sqrt_optab; break;
      case BUILT_IN_EXP:
      case BUILT_IN_EXPF:
      case BUILT_IN_EXPL:
!       errno_set = true; builtin_optab = exp_optab; break;
      case BUILT_IN_LOG:
      case BUILT_IN_LOGF:
      case BUILT_IN_LOGL:
!       errno_set = true; builtin_optab = log_optab; break;
!     case BUILT_IN_TAN:
!     case BUILT_IN_TANF:
!     case BUILT_IN_TANL:
!       builtin_optab = tan_optab; break;
!     case BUILT_IN_ATAN:
!     case BUILT_IN_ATANF:
!     case BUILT_IN_ATANL:
!       builtin_optab = atan_optab; break;
      case BUILT_IN_FLOOR:
      case BUILT_IN_FLOORF:
      case BUILT_IN_FLOORL:
!       builtin_optab = floor_optab; break;
      case BUILT_IN_CEIL:
      case BUILT_IN_CEILF:
      case BUILT_IN_CEILL:
!       builtin_optab = ceil_optab; break;
      case BUILT_IN_TRUNC:
      case BUILT_IN_TRUNCF:
      case BUILT_IN_TRUNCL:
!       builtin_optab = trunc_optab; break;
      case BUILT_IN_ROUND:
      case BUILT_IN_ROUNDF:
      case BUILT_IN_ROUNDL:
!       builtin_optab = round_optab; break;
      case BUILT_IN_NEARBYINT:
      case BUILT_IN_NEARBYINTF:
      case BUILT_IN_NEARBYINTL:
!       builtin_optab = nearbyint_optab; break;
      default:
        abort ();
      }
*************** expand_builtin (exp, target, subtarget,
*** 4574,4579 ****
--- 4582,4593 ----
      case BUILT_IN_LOG:
      case BUILT_IN_LOGF:
      case BUILT_IN_LOGL:
+     case BUILT_IN_TAN:
+     case BUILT_IN_TANF:
+     case BUILT_IN_TANL:
+     case BUILT_IN_ATAN:
+     case BUILT_IN_ATANF:
+     case BUILT_IN_ATANL:
        /* Treat these like sqrt only if unsafe math optimizations are allowed,
  	 because of possible accuracy problems.  */
        if (! flag_unsafe_math_optimizations)
Index: config/i386/i386.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.md,v
retrieving revision 1.470
diff -c -3 -p -r1.470 i386.md
*** config/i386/i386.md	15 Jun 2003 13:32:29 -0000	1.470
--- config/i386/i386.md	15 Jun 2003 17:02:04 -0000
***************
*** 15855,15860 ****
--- 15855,15912 ----
    emit_move_insn (operands[2], temp);
    emit_move_insn (operands[7], CONST1_RTX (XFmode));  /* fld1 */
  })
+
+ (define_expand "atansf2"
+   [(parallel [(set (match_operand:SF 0 "register_operand" "")
+ 		   (unspec:SF [(match_dup 2)
+ 			       (match_operand:SF 1 "register_operand" "")]
+ 		    UNSPEC_FPATAN))
+ 	      (clobber (match_dup 1))])]
+   "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+    && flag_unsafe_math_optimizations"
+ {
+   operands[2] = gen_reg_rtx (SFmode);
+   emit_move_insn (operands[2], CONST1_RTX (SFmode));  /* fld1 */
+ })
+
+ (define_expand "atandf2"
+   [(parallel [(set (match_operand:DF 0 "register_operand" "")
+ 		   (unspec:DF [(match_dup 2)
+ 			       (match_operand:DF 1 "register_operand" "")]
+ 		    UNSPEC_FPATAN))
+ 	      (clobber (match_dup 1))])]
+   "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+    && flag_unsafe_math_optimizations"
+ {
+   operands[2] = gen_reg_rtx (DFmode);
+   emit_move_insn (operands[2], CONST1_RTX (DFmode));  /* fld1 */
+ })
+
+ (define_expand "atanxf2"
+   [(parallel [(set (match_operand:XF 0 "register_operand" "")
+ 		   (unspec:XF [(match_dup 2)
+ 			       (match_operand:XF 1 "register_operand" "")]
+ 		    UNSPEC_FPATAN))
+ 	      (clobber (match_dup 1))])]
+   "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+    && flag_unsafe_math_optimizations"
+ {
+   operands[2] = gen_reg_rtx (XFmode);
+   emit_move_insn (operands[2], CONST1_RTX (XFmode));  /* fld1 */
+ })
+
+ (define_expand "atantf2"
+   [(parallel [(set (match_operand:TF 0 "register_operand" "")
+ 		   (unspec:TF [(match_dup 2)
+ 			       (match_operand:TF 1 "register_operand" "")]
+ 		    UNSPEC_FPATAN))
+ 	      (clobber (match_dup 1))])]
+   "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+    && flag_unsafe_math_optimizations"
+ {
+   operands[2] = gen_reg_rtx (TFmode);
+   emit_move_insn (operands[2], CONST1_RTX (TFmode));  /* fld1 */
+ })

  ;; Block operation instructions


/* Verify that -mno-fancy-math-387 works.  */
/* { dg-do compile { target "i?86-*-*" } } */
/* { dg-options "-O -ffast-math -mfpmath=387 -mno-fancy-math-387" } */
/* { dg-final { scan-assembler "call\t_?atan" } } */

double f1(double x) { return __builtin_atan(x); }


/* Verify that -march overrides -mno-fancy-math-387.  */
/* { dg-do compile { target "i?86-*-*" } } */
/* { dg-options "-O -ffast-math -mfpmath=387 -march=i686 -mno-fancy-math-387" } */
/* { dg-final { scan-assembler "fpatan" } } */

double f1(double x) { return __builtin_atan(x); }


/* Related to PR optimization/10764  */

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

double atan(double x);

double foo(double x)
{
  return atan(atan(x));
}


Roger
--
Roger Sayle,                         E-mail: roger@eyesopen.com
OpenEye Scientific Software,         WWW: http://www.eyesopen.com/
Suite 1107, 3600 Cerrillos Road,     Tel: (+1) 505-473-7385
Santa Fe, New Mexico, 87507.         Fax: (+1) 505-473-0833



More information about the Gcc-patches mailing list