diff options
author | Georg-Johann Lay <avr@gjlay.de> | 2013-01-25 09:28:09 +0000 |
---|---|---|
committer | Georg-Johann Lay <gjl@gcc.gnu.org> | 2013-01-25 09:28:09 +0000 |
commit | 556f9906c548af7332f7f274f9e05cacfaeb64a6 (patch) | |
tree | 918c673cf4287a1ff60b0fbe521ff2d09b487c88 | |
parent | 1f546bbbc4dcc9cf044310cf0eafb091415df614 (diff) | |
download | gcc-556f9906c548af7332f7f274f9e05cacfaeb64a6.zip gcc-556f9906c548af7332f7f274f9e05cacfaeb64a6.tar.gz gcc-556f9906c548af7332f7f274f9e05cacfaeb64a6.tar.bz2 |
re PR target/54222 ([avr] Implement fixed-point support)
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
-rw-r--r-- | gcc/ChangeLog | 19 | ||||
-rw-r--r-- | gcc/config/avr/avr-c.c | 2 | ||||
-rw-r--r-- | gcc/config/avr/avr.c | 84 | ||||
-rw-r--r-- | gcc/config/avr/builtins.def | 60 | ||||
-rw-r--r-- | gcc/config/avr/stdfix.h | 78 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/avr/torture/builtins-3-absfx.c | 171 |
7 files changed, 389 insertions, 30 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 327d285..cb97d62 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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 diff --git a/gcc/config/avr/avr-c.c b/gcc/config/avr/avr-c.c index 075d9ef..ddcab54 100644 --- a/gcc/config/avr/avr-c.c +++ b/gcc/config/avr/avr-c.c @@ -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 diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index f0906fa..c833bfb 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -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]; diff --git a/gcc/config/avr/builtins.def b/gcc/config/avr/builtins.def index c8314ac..ecce186 100644 --- a/gcc/config/avr/builtins.def +++ b/gcc/config/avr/builtins.def @@ -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 diff --git a/gcc/config/avr/stdfix.h b/gcc/config/avr/stdfix.h index 95535a8..b86195a 100644 --- a/gcc/config/avr/stdfix.h +++ b/gcc/config/avr/stdfix.h @@ -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 */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 6fc08a1..d00476e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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 index 0000000..a8bde29 --- /dev/null +++ b/gcc/testsuite/gcc.target/avr/torture/builtins-3-absfx.c @@ -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; +} + |