re PR target/54222 ([avr] Implement fixed-point support)
authorGeorg-Johann Lay <avr@gjlay.de>
Fri, 25 Jan 2013 09:28:09 +0000 (09:28 +0000)
committerGeorg-Johann Lay <gjl@gcc.gnu.org>
Fri, 25 Jan 2013 09:28:09 +0000 (09:28 +0000)
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.

From-SVN: r195464

gcc/ChangeLog
gcc/config/avr/avr-c.c
gcc/config/avr/avr.c
gcc/config/avr/builtins.def
gcc/config/avr/stdfix.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/avr/torture/builtins-3-absfx.c [new file with mode: 0644]

index 327d2859816da8a168ba287233f12f99886646a8..cb97d62ce7c8b377dea9a774fa3505c3edec700e 100644 (file)
@@ -1,3 +1,22 @@
+2013-01-25  Georg-Johann Lay  <avr@gjlay.de>
+
+       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.
+
 2013-01-25  Marek Polacek  <polacek@redhat.com>
 
        PR tree-optimization/56035
index 075d9ef791b6ec91cd1892a106600ba777d5ec1c..ddcab546076749b2c2c0020c901ab4f237633458 100644 (file)
@@ -168,7 +168,7 @@ avr_cpu_cpp_builtins (struct cpp_reader *pfile)
   /* 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 f0906fad43e4f58b557757aa9cade47e20545860..c833bfbaa79bac5b5c5cc6e64874830094e3dd11 100644 (file)
@@ -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_args ATTRIBUTE_UNUSED, tree *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 c8314acc7670c8b963f1b0eb8f0f6b5b406f74ea..ecce186870d88f3bf08108e2599d27a11f40fe40 100644 (file)
    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 95535a881802153d4b6f3d06658c779725b70b7e..b86195a3f16ab64b2927cdecba7d2242978a5fc5 100644 (file)
 
 #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 6fc08a1474548bf0723c70b26c8fe205942e9977..d00476ef161690761919560e06b167293ac805a1 100644 (file)
@@ -1,3 +1,8 @@
+2013-01-25  Georg-Johann Lay  <avr@gjlay.de>
+
+       PR target/54222
+       * gcc.target/avr/torture/builtins-3-absfx.c: New test.
+
 2013-01-22  Marek Polacek  <polacek@redhat.com>
 
        PR tree-optimization/56035
diff --git a/gcc/testsuite/gcc.target/avr/torture/builtins-3-absfx.c b/gcc/testsuite/gcc.target/avr/torture/builtins-3-absfx.c
new file mode 100644 (file)
index 0000000..a8bde29
--- /dev/null
@@ -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;
+}
+