===================================================================
@@ -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
===================================================================
@@ -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 */
===================================================================
@@ -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
===================================================================
@@ -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];
===================================================================
@@ -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;
+}
+