Patchwork [avr] : Ad PR54222: Support absolute value functions to stdfix.h

login
register
mail settings
Submitter Georg-Johann Lay
Date Jan. 24, 2013, 3:54 p.m.
Message ID <51015932.3020606@gjlay.de>
Download mbox | patch
Permalink /patch/215386/
State New
Headers show

Comments

Georg-Johann Lay - Jan. 24, 2013, 3:54 p.m.
This patch adds the absolute value functions to stdfix.h.

DEF_BUILTIN gets one more argument LIBNAME that sets the library name.  If no
folding is found, for some builtins it's more convenient to call libgcc support
directly instead of expanding to an insn.

gcc's folding is not very good, thus implement our own.


Ok for trunk?

Johann



gcc/
	PR target/54222
	* config/avr/builtins.def (DEF_BUILTIN): Add LIBNAME argument.
	Add NULL LIBNAME argument to existing definitions.
	(ABSHR, ABSR, ABSLR, ABSLLR, ABSHK, ABSK, ABSLK, ABSLLK): New.
	* config/avr/avr-c.c (DEF_BUILTIN): Add LIBNAME argument.
	* config/avr/avr.c (DEF_BUILTIN): Same.
	(avr_init_builtins): Pass down LIBNAME to add_builtin_function.
	(avr_expand_builtin): Expand to a vanilla call if a libgcc
	implementation is available (DECL_ASSEMBLER_NAME is set).
	(avr_fold_absfx): New static function.
	(avr_fold_builtin): Use it to handle: AVR_BUILTIN_ABSHR,
	AVR_BUILTIN_ABSR, AVR_BUILTIN_ABSLR, AVR_BUILTIN_ABSLLR,
	AVR_BUILTIN_ABSHK, AVR_BUILTIN_ABSK, AVR_BUILTIN_ABSLK,
	AVR_BUILTIN_ABSLLK.
	* config/avr/stdfix.h (abshr, absr, abslr, absllr)
	(abshk, absk, abslk, absllk): Provide as static inline functions.

gcc/testsuite/
	PR target/54222
	* gcc.target/avr/torture/builtins-3-absfx.c: New test.
Denis Chertykov - Jan. 25, 2013, 7:05 a.m.
2013/1/24 Georg-Johann Lay <avr@gjlay.de>:
> This patch adds the absolute value functions to stdfix.h.
>
> DEF_BUILTIN gets one more argument LIBNAME that sets the library name.  If no
> folding is found, for some builtins it's more convenient to call libgcc support
> directly instead of expanding to an insn.
>
> gcc's folding is not very good, thus implement our own.
>
>
> Ok for trunk?
>
> Johann
>
>
>
> gcc/
>         PR target/54222
>         * config/avr/builtins.def (DEF_BUILTIN): Add LIBNAME argument.
>         Add NULL LIBNAME argument to existing definitions.
>         (ABSHR, ABSR, ABSLR, ABSLLR, ABSHK, ABSK, ABSLK, ABSLLK): New.
>         * config/avr/avr-c.c (DEF_BUILTIN): Add LIBNAME argument.
>         * config/avr/avr.c (DEF_BUILTIN): Same.
>         (avr_init_builtins): Pass down LIBNAME to add_builtin_function.
>         (avr_expand_builtin): Expand to a vanilla call if a libgcc
>         implementation is available (DECL_ASSEMBLER_NAME is set).
>         (avr_fold_absfx): New static function.
>         (avr_fold_builtin): Use it to handle: AVR_BUILTIN_ABSHR,
>         AVR_BUILTIN_ABSR, AVR_BUILTIN_ABSLR, AVR_BUILTIN_ABSLLR,
>         AVR_BUILTIN_ABSHK, AVR_BUILTIN_ABSK, AVR_BUILTIN_ABSLK,
>         AVR_BUILTIN_ABSLLK.
>         * config/avr/stdfix.h (abshr, absr, abslr, absllr)
>         (abshk, absk, abslk, absllk): Provide as static inline functions.
>
> gcc/testsuite/
>         PR target/54222
>         * gcc.target/avr/torture/builtins-3-absfx.c: New test.
>
>

Approved.

Denis.

Patch

Index: config/avr/builtins.def
===================================================================
--- config/avr/builtins.def	(revision 195406)
+++ config/avr/builtins.def	(working copy)
@@ -20,35 +20,53 @@ 
    builtins defined in the AVR part of the GNU compiler.
    Befor including this file, define a macro
 
-   DEF_BUILTIN(NAME, N_ARGS, TYPE, ICODE)
+   DEF_BUILTIN(NAME, N_ARGS, TYPE, ICODE, LIBNAME)
 
-   NAME:   `__builtin_avr_name' will be the user-level name of the builtin.
-           `AVR_BUILTIN_NAME' will be the internal builtin's id.
-   N_ARGS: Number of input arguments.  If special treatment is needed,
-           set to -1 and handle it by hand, see avr.c:avr_expand_builtin().
-   TYPE:   A tree node describing the prototype of the built-in.
-   ICODE:  Name of attached insn or expander.  If special treatment in avr.c
-           is needed to expand the built-in, use `nothing'.
-*/
+   NAME:    `__builtin_avr_name' will be the user-level name of the builtin.
+            `AVR_BUILTIN_NAME' will be the internal builtin's id.
+   N_ARGS:  Number of input arguments.  If special treatment is needed,
+            set to -1 and handle it by hand, see avr.c:avr_expand_builtin().
+   TYPE:    A tree node describing the prototype of the built-in.
+   ICODE:   Name of attached insn or expander.  If special treatment in avr.c
+            is needed to expand the built-in, use `nothing'.
+   LIBNAME: Name of the attached implementation in libgcc which is used if
+            the builtin cannot be folded away and there is no insn.  */
 
 /* Mapped to respective instruction.  */
 
-DEF_BUILTIN (NOP,  -1, void_ftype_void, nothing)
-DEF_BUILTIN (SEI,   0, void_ftype_void, enable_interrupt)
-DEF_BUILTIN (CLI,   0, void_ftype_void, disable_interrupt)
-DEF_BUILTIN (WDR,   0, void_ftype_void, wdr)
-DEF_BUILTIN (SLEEP, 0, void_ftype_void, sleep)
+DEF_BUILTIN (NOP,  -1, void_ftype_void, nothing, NULL)
+DEF_BUILTIN (SEI,   0, void_ftype_void, enable_interrupt, NULL)
+DEF_BUILTIN (CLI,   0, void_ftype_void, disable_interrupt, NULL)
+DEF_BUILTIN (WDR,   0, void_ftype_void, wdr, NULL)
+DEF_BUILTIN (SLEEP, 0, void_ftype_void, sleep, NULL)
 
 /* Mapped to respective instruction but might also be folded away
    or emit as libgcc call if ISA does not provide the instruction.  */
 
-DEF_BUILTIN (SWAP,   1, uchar_ftype_uchar,      rotlqi3_4)
-DEF_BUILTIN (FMUL,   2, uint_ftype_uchar_uchar, fmul)
-DEF_BUILTIN (FMULS,  2, int_ftype_char_char,    fmuls)
-DEF_BUILTIN (FMULSU, 2, int_ftype_char_uchar,   fmulsu)
+DEF_BUILTIN (SWAP,   1, uchar_ftype_uchar,      rotlqi3_4, NULL)
+DEF_BUILTIN (FMUL,   2, uint_ftype_uchar_uchar, fmul, NULL)
+DEF_BUILTIN (FMULS,  2, int_ftype_char_char,    fmuls, NULL)
+DEF_BUILTIN (FMULSU, 2, int_ftype_char_uchar,   fmulsu, NULL)
 
 /* More complex stuff that cannot be mapped 1:1 to an instruction.  */
 
-DEF_BUILTIN (DELAY_CYCLES, -1, void_ftype_ulong, nothing)
-DEF_BUILTIN (INSERT_BITS, 3, uchar_ftype_ulong_uchar_uchar, insert_bits)
-DEF_BUILTIN (FLASH_SEGMENT, 1, char_ftype_const_memx_ptr, flash_segment)
+DEF_BUILTIN (DELAY_CYCLES, -1, void_ftype_ulong, nothing, NULL)
+DEF_BUILTIN (INSERT_BITS, 3, uchar_ftype_ulong_uchar_uchar, insert_bits, NULL)
+DEF_BUILTIN (FLASH_SEGMENT, 1, char_ftype_const_memx_ptr, flash_segment, NULL)
+
+/* ISO/IEC TR 18037 "Embedded C"
+   The following builtins are undocumented and used by stdfix.h.  */
+
+/* 7.18a.6 The fixed-point intrinsic functions. */
+
+/* 7.18a.6.2 The fixed-point absolute value functions. */
+
+DEF_BUILTIN (ABSHR,   1, hr_ftype_hr,   ssabsqq2, NULL)
+DEF_BUILTIN (ABSR,    1, r_ftype_r,     ssabshq2, NULL)
+DEF_BUILTIN (ABSLR,   1, lr_ftype_lr,   ssabssq2, NULL)
+DEF_BUILTIN (ABSLLR,  1, llr_ftype_llr, nothing, "__ssabsdq2") // GCC extension
+
+DEF_BUILTIN (ABSHK,   1, hk_ftype_hk,   ssabsha2, NULL)
+DEF_BUILTIN (ABSK,    1, k_ftype_k,     ssabssa2, NULL)
+DEF_BUILTIN (ABSLK,  -1, lk_ftype_lk,   nothing, "__ssabsda2")
+DEF_BUILTIN (ABSLLK, -1, llk_ftype_llk, nothing, "__ssabsta2") // GCC extension
Index: config/avr/stdfix.h
===================================================================
--- config/avr/stdfix.h	(revision 195407)
+++ config/avr/stdfix.h	(working copy)
@@ -35,12 +35,11 @@ 
 
 #include <stdfix-gcc.h>
 
-/* 2.1.7.4 The bitwise fixed-point to integer conversion functions.  */
-/* 2.1.7.5 The bitwise integer to fixed-point conversion functions.  */
-
 #define _GCC_TYPEPUN(A, B)                      \
   __builtin_memcpy (&A, &B, sizeof (A))
 
+/* 7.18a.6  The fixed-point intrinsic functions.  */
+
 #if __SIZEOF_INT__ == 2
 
 typedef signed char int_hr_t;
@@ -88,6 +87,79 @@  typedef long long unsigned int uint_uk_t
 #endif /* __SIZEOF_INT__ == 2 */
 
 
+/* 7.18a.6.2 The fixed-point absolute value functions. */
+
+/* short fract (hr): abshr */
+
+static __inline__ __attribute__((__always_inline__))
+short fract abshr (const short fract __q)
+{
+  return __builtin_avr_abshr (__q);
+}
+
+/* fract (r): absr */
+
+static __inline__ __attribute__((__always_inline__))
+fract absr (const fract __q)
+{
+  return __builtin_avr_absr (__q);
+}
+
+/* long fract (lr): abslr */
+
+static __inline__ __attribute__((__always_inline__))
+long fract abslr (const long fract __q)
+{
+  return __builtin_avr_abslr (__q);
+}
+
+/* short accum (hk): abshk */
+
+static __inline__ __attribute__((__always_inline__))
+short accum abshk (const short accum __q)
+{
+  return __builtin_avr_abshk (__q);
+}
+
+/* accum (k): absk */
+
+static __inline__ __attribute__((__always_inline__))
+accum absk (const accum __q)
+{
+  return __builtin_avr_absk (__q);
+}
+
+#if __SIZEOF_INT__ == 2
+
+/* long long fract (llr): absllr */
+
+static __inline__ __attribute__((__always_inline__))
+long long fract absllr (const long long fract __q) /* GCC extension */
+{
+  return __builtin_avr_absllr (__q);
+}
+
+/* long accum (lk): abslk */
+
+static __inline__ __attribute__((__always_inline__))
+long accum abslk (const long accum __q)
+{
+  return __builtin_avr_abslk (__q);
+}
+
+/* long long accum (llk): absllk */
+
+static __inline__ __attribute__((__always_inline__))
+long long accum absllk (const long long accum __q) /* GCC extension */
+{
+  return __builtin_avr_absllk (__q);
+}
+
+#endif /* __SIZEOF_INT__ == 2 */
+
+
+/* 7.18a.6.5 The bitwise fixed-point to integer conversion functions. */
+/* 7.18a.6.6 The bitwise integer to fixed-point conversion functions. */
 
 /* short fract (hr): bitshr, bitsuhr, hrbits, uhrbits */
 
Index: config/avr/avr-c.c
===================================================================
--- config/avr/avr-c.c	(revision 195406)
+++ config/avr/avr-c.c	(working copy)
@@ -168,7 +168,7 @@  avr_cpu_cpp_builtins (struct cpp_reader
   /* Define builtin macros so that the user can easily query whether or
      not a specific builtin is available. */
 
-#define DEF_BUILTIN(NAME, N_ARGS, TYPE, CODE)   \
+#define DEF_BUILTIN(NAME, N_ARGS, TYPE, CODE, LIBNAME)  \
   cpp_define (pfile, "__BUILTIN_AVR_" #NAME);
 #include "builtins.def"
 #undef DEF_BUILTIN
Index: config/avr/avr.c
===================================================================
--- config/avr/avr.c	(revision 195424)
+++ config/avr/avr.c	(working copy)
@@ -11384,7 +11384,7 @@  avr_out_insert_bits (rtx *op, int *plen)
 
 enum avr_builtin_id
   {
-#define DEF_BUILTIN(NAME, N_ARGS, TYPE, CODE)   \
+#define DEF_BUILTIN(NAME, N_ARGS, TYPE, CODE, LIBNAME)  \
     AVR_BUILTIN_ ## NAME,
 #include "builtins.def"
 #undef DEF_BUILTIN
@@ -11407,7 +11407,7 @@  struct GTY(()) avr_builtin_description
 static GTY(()) struct avr_builtin_description
 avr_bdesc[AVR_BUILTIN_COUNT] =
   {
-#define DEF_BUILTIN(NAME, N_ARGS, TYPE, ICODE)                  \
+#define DEF_BUILTIN(NAME, N_ARGS, TYPE, ICODE, LIBNAME)         \
     { (enum insn_code) CODE_FOR_ ## ICODE, N_ARGS, NULL_TREE },
 #include "builtins.def"
 #undef DEF_BUILTIN
@@ -11489,7 +11489,33 @@  avr_init_builtins (void)
                                 const_memx_ptr_type_node,
                                 NULL);
 
-#define DEF_BUILTIN(NAME, N_ARGS, TYPE, CODE)                           \
+  tree hr_ftype_hr
+    = build_function_type_list (short_fract_type_node,
+                                short_fract_type_node, NULL);
+  tree r_ftype_r
+    = build_function_type_list (fract_type_node,
+                                fract_type_node, NULL);
+  tree lr_ftype_lr
+    = build_function_type_list (long_fract_type_node,
+                                long_fract_type_node, NULL);
+  tree llr_ftype_llr
+    = build_function_type_list (long_long_fract_type_node,
+                                long_long_fract_type_node, NULL);
+
+  tree hk_ftype_hk
+    = build_function_type_list (short_accum_type_node,
+                                short_accum_type_node, NULL);
+  tree k_ftype_k
+    = build_function_type_list (accum_type_node,
+                                accum_type_node, NULL);
+  tree lk_ftype_lk
+    = build_function_type_list (long_accum_type_node,
+                                long_accum_type_node, NULL);
+  tree llk_ftype_llk
+    = build_function_type_list (long_long_accum_type_node,
+                                long_long_accum_type_node, NULL);
+  
+#define DEF_BUILTIN(NAME, N_ARGS, TYPE, CODE, LIBNAME)                  \
   {                                                                     \
     int id = AVR_BUILTIN_ ## NAME;                                      \
     const char *Name = "__builtin_avr_" #NAME;                          \
@@ -11498,7 +11524,7 @@  avr_init_builtins (void)
     gcc_assert (id < AVR_BUILTIN_COUNT);                                \
     avr_bdesc[id].fndecl                                                \
       = add_builtin_function (avr_tolower (name, Name), TYPE, id,       \
-                              BUILT_IN_MD, NULL, NULL_TREE);            \
+                              BUILT_IN_MD, LIBNAME, NULL_TREE);         \
   }
 #include "builtins.def"
 #undef DEF_BUILTIN
@@ -11580,7 +11606,7 @@  static rtx
 avr_expand_builtin (tree exp, rtx target,
                     rtx subtarget ATTRIBUTE_UNUSED,
                     enum machine_mode mode ATTRIBUTE_UNUSED,
-                    int ignore ATTRIBUTE_UNUSED)
+                    int ignore)
 {
   tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
   const char *bname = IDENTIFIER_POINTER (DECL_NAME (fndecl));
@@ -11624,6 +11650,14 @@  avr_expand_builtin (tree exp, rtx target
       }
     }
 
+  /* No fold found and no insn:  Call support function from libgcc.  */
+
+  if (d->icode == CODE_FOR_nothing
+      && DECL_ASSEMBLER_NAME (get_callee_fndecl (exp)) != NULL_TREE)
+    {
+      return expand_call (exp, target, ignore);
+    }
+
   /* No special treatment needed: vanilla expand.  */
 
   gcc_assert (d->icode != CODE_FOR_nothing);
@@ -11639,6 +11673,33 @@  avr_expand_builtin (tree exp, rtx target
 }
 
 
+/* Helper for `avr_fold_builtin' that folds  absfx (FIXED_CST).  */
+
+static tree
+avr_fold_absfx (tree tval)
+{
+  if (FIXED_CST != TREE_CODE (tval))
+    return NULL_TREE;
+
+  /* Our fixed-points have no padding:  Use double_int payload directly.  */
+
+  FIXED_VALUE_TYPE fval = TREE_FIXED_CST (tval);
+  unsigned int bits = GET_MODE_BITSIZE (fval.mode);
+  double_int ival = fval.data.sext (bits);
+
+  if (!ival.is_negative())
+    return tval;
+
+  /* ISO/IEC TR 18037, 7.18a.6.2:  The absfx functions are saturating.  */
+
+  fval.data = (ival == double_int::min_value (bits, false).sext (bits))
+    ? double_int::max_value (bits, false)
+    : -ival;
+
+  return build_fixed (TREE_TYPE (tval), fval);
+}
+
+
 /* Implement `TARGET_FOLD_BUILTIN'.  */
 
 static tree
@@ -11662,6 +11723,19 @@  avr_fold_builtin (tree fndecl, int n_arg
                             build_int_cst (val_type, 4));
       }
 
+    case AVR_BUILTIN_ABSHR:
+    case AVR_BUILTIN_ABSR:
+    case AVR_BUILTIN_ABSLR:
+    case AVR_BUILTIN_ABSLLR:
+
+    case AVR_BUILTIN_ABSHK:
+    case AVR_BUILTIN_ABSK:
+    case AVR_BUILTIN_ABSLK:
+    case AVR_BUILTIN_ABSLLK:
+      /* GCC is not good with folding ABS for fixed-point.  Do it by hand.  */
+
+      return avr_fold_absfx (arg[0]);
+
     case AVR_BUILTIN_INSERT_BITS:
       {
         tree tbits = arg[1];
Index: testsuite/gcc.target/avr/torture/builtins-3-absfx.c
===================================================================
--- testsuite/gcc.target/avr/torture/builtins-3-absfx.c	(revision 0)
+++ testsuite/gcc.target/avr/torture/builtins-3-absfx.c	(revision 0)
@@ -0,0 +1,171 @@ 
+/* { dg-options "-std=gnu99" } */
+/* { dg-do run } */
+
+#include <stdfix.h>
+
+extern void abort (void);
+
+short fract test1_hr (short fract x)
+{
+  return abshr (x);
+}
+
+fract test1_r (fract x)
+{
+  return absr (x);
+}
+
+long fract test1_lr (long fract x)
+{
+  return abslr (x);
+}
+
+long long fract test1_llr (long long fract x)
+{
+  return absllr (x);
+}
+
+short accum test1_hk (short accum x)
+{
+  return abshk (x);
+}
+
+accum test1_k (accum x)
+{
+  return absk (x);
+}
+
+long accum test1_lk (long accum x)
+{
+  return abslk (x);
+}
+
+long long accum test1_llk (long long accum x)
+{
+  return absllk (x);
+}
+
+
+short fract test2_hr (void)
+{
+  return abshr (-0.12hr);
+}
+
+fract test2_r (void)
+{
+  return absr (-0.12r);
+}
+
+long fract test2_lr (void)
+{
+  return abslr (-0.12lr);
+}
+
+long long fract test2_llr (void)
+{
+  return absllr (-0.123456llr);
+}
+
+short accum test2_hk (void)
+{
+  return abshk (-221.12hk);
+}
+
+accum test2_k (void)
+{
+  return absk (-4321.12k);
+}
+
+long accum test2_lk (void)
+{
+  return abslk (-4321.12lk);
+}
+
+long long accum test2_llk (void)
+{
+  return absllk (-4321.12llk);
+}
+
+#define TEST1(VAL,FX)                                          \
+  if (abs ## FX (-VAL ## FX -v) != VAL ## FX + v)              \
+    abort();                                                   \
+  if (abs ## FX (-VAL ## FX -v) != abs ## FX (VAL ## FX + v))  \
+    abort();
+
+#define TEST2(VAL,FX)                                   \
+  if (abs ## FX (-VAL ## FX) != VAL ## FX)              \
+    abort();                                            \
+  if (abs ## FX (-VAL ## FX) != abs ## FX (VAL ## FX))  \
+    abort();
+
+const __flash short fract volatile v = 0.33hr;
+const __flash short fract volatile z = 0hr;
+
+void test1 (void)
+{
+  TEST1 (0.123, hr);
+  TEST1 (0.123, r);
+  TEST1 (0.1234567, lr);
+  TEST1 (0.1234567, llr);
+  
+  TEST1 (223.123, hk);
+  TEST1 (12345.123, k);
+  TEST1 (12342345.123, lk);
+  TEST1 (12345.123, llk);
+}
+
+
+void test2 (void)
+{
+  TEST2 (0.123, hr);
+  TEST2 (0.123, r);
+  TEST2 (0.1234567, lr);
+  TEST2 (0.1234567, llr);
+  
+  TEST2 (223.123, hk);
+  TEST2 (12345.123, k);
+  TEST2 (12342345.123, lk);
+  TEST2 (12345.123, llk);
+}
+
+#define MINMAX(T,FX)                                                    \
+  {                                                                     \
+    int_ ## FX ## _t imin                                               \
+      = (int_ ## FX ## _t) 1 << (8 * sizeof (int_ ## FX ## _t) -1);     \
+    int_ ## FX ## _t imax = ~imin;                                      \
+    T fmin =  FX ## bits (imin);                                        \
+    T fmax =  FX ## bits (imax);                                        \
+                                                                        \
+    if (abs ## FX (fmin) != fmax)                                       \
+      abort();                                                          \
+    if (abs ## FX (fmin) != abs ## FX (fmax))                           \
+      abort();                                                          \
+    if (abs ## FX (fmin + z) != fmax + z)                               \
+      abort();                                                          \
+    if (abs ## FX (fmin - z) != abs ## FX (fmax + z))                   \
+      abort();                                                          \
+  }
+
+void test3 (void)
+{
+  MINMAX (short fract, hr);
+  MINMAX (fract, r);
+  MINMAX (long fract, lr);
+  MINMAX (long long fract, llr);
+
+  MINMAX (short accum, hk);
+  MINMAX (accum, k);
+  MINMAX (long accum, lk);
+  MINMAX (long long accum, llk);
+}
+
+
+int main (void)
+{
+  test1();
+  test2();
+  test3();
+
+  return 0;
+}
+