Commit 556f9906 by Georg-Johann Lay Committed by Georg-Johann Lay

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
parent 1f546bbb
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
......
......@@ -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
......
......@@ -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];
......
......@@ -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 */
......
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
......
/* { 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment