re PR target/54222 ([avr] Implement fixed-point support)

gcc/
	PR target/54222
	* config/avr/avr.md (unspec) <UNSPEC_ROUND>: Add.
	* config/avr/avr-fixed.md (ALL4QA, ALL124QA): New mode iterators.
	(round<mode>3, round<mode>3_const): New expanders for fixed-mode.
	(*round<mode>3.libgcc): New insns for fixed-modes.
	* config/avr/builtins.def (ABSxx): Use a non-NULL LIBNAME.
	(ROUNDxx, COUNTLSxx, BITSxx, xxBITS): New DEF_BUILTINs.
	(ROUNDFX, COUNTLSFX, ABSFX): New DEF_BUILTINs.
	* config/avr/stdfix.h (absFX, bitsFX, FXbits): Remove inline
	implementations.  Define to __builtin_avr_absFX,
	__builtin_avr_bitsFX, __builtin_avr_FXbits, respectively.
	(roundFX, countlsFX): Define to __builtin_avr_roundFX,
	__builtin_avr_countlsFX, respectively.
	* config/avr/avr-c.c (target.h): Include it.
	(enum avr_builtin_id): New enum.
	(avr_resolve_overloaded_builtin): New static function.
	(avr_register_target_pragmas): Use it to set
	targetm.resolve_overloaded_builtin.
	* config/avr/avr.c (avr_init_builtins): Supply myriads of local
	tree nodes used by DEF_BUILTIN.
	(avr_expand_builtin) <AVR_BUILTIN_ROUNDxx>: Sanity-check them.
	(avr_fold_builtin) <AVR_BUILTIN_BITSxx>: Fold to VIEW_COVERT_EXPR.
	<AVR_BUILTIN_xxBITS>: Same.
	
libgcc/
	PR target/54222
	* config/avr/lib2funcs.c: New C sources for modules for libgcc.a.
	* config/avr/lib2-object.mk: New iterator to build objects from it.
	* config/avr/t-avr: Iterate lib2-object.mk to build objects from
	lib2funcs.c.
	(LIB2FUNCS_EXCLUDE): Add _clrsbdi2.
	(LIB1ASMFUNCS): Add: _ssabs_1, _mask1, _ret, _roundqq3, _rounduqq3,
	_round_s2, _round_u2, _round_2_const, _addmask_2, _round_s4,
	_round_u4, _round_4_const, _addmask_4, _round_x8, _rounddq3
	_roundudq3, _roundda3 _rounduda3, _roundta3 _rounduta3.
	* config/avr/lib1funcs-fixed.S: Implement them.

gcc/testsuite/
	PR target/54222
	* gcc.target/avr/torture/builtins-4-roundfx.c: New test.
	* gcc.target/avr/torture/builtins-5-countlsfx.c: New test.

From-SVN: r195878
This commit is contained in:
Georg-Johann Lay 2013-02-08 10:13:37 +00:00 committed by Georg-Johann Lay
parent 661bc682bc
commit 85d768f349
16 changed files with 1911 additions and 366 deletions

View File

@ -1,3 +1,29 @@
2013-02-08 Georg-Johann Lay <avr@gjlay.de>
PR target/54222
* config/avr/avr.md (unspec) <UNSPEC_ROUND>: Add.
* config/avr/avr-fixed.md (ALL4QA, ALL124QA): New mode iterators.
(round<mode>3, round<mode>3_const): New expanders for fixed-mode.
(*round<mode>3.libgcc): New insns for fixed-modes.
* config/avr/builtins.def (ABSxx): Use a non-NULL LIBNAME.
(ROUNDxx, COUNTLSxx, BITSxx, xxBITS): New DEF_BUILTINs.
(ROUNDFX, COUNTLSFX, ABSFX): New DEF_BUILTINs.
* config/avr/stdfix.h (absFX, bitsFX, FXbits): Remove inline
implementations. Define to __builtin_avr_absFX,
__builtin_avr_bitsFX, __builtin_avr_FXbits, respectively.
(roundFX, countlsFX): Define to __builtin_avr_roundFX,
__builtin_avr_countlsFX, respectively.
* config/avr/avr-c.c (target.h): Include it.
(enum avr_builtin_id): New enum.
(avr_resolve_overloaded_builtin): New static function.
(avr_register_target_pragmas): Use it to set
targetm.resolve_overloaded_builtin.
* config/avr/avr.c (avr_init_builtins): Supply myriads of local
tree nodes used by DEF_BUILTIN.
(avr_expand_builtin) <AVR_BUILTIN_ROUNDxx>: Sanity-check them.
(avr_fold_builtin) <AVR_BUILTIN_BITSxx>: Fold to VIEW_COVERT_EXPR.
<AVR_BUILTIN_xxBITS>: Same.
2013-02-08 Richard Biener <rguenther@suse.de>
* cfgloop.c (verify_loop_structure): Properly handle

View File

@ -26,10 +26,226 @@
#include "tm_p.h"
#include "cpplib.h"
#include "tree.h"
#include "target.h"
#include "c-family/c-common.h"
#include "langhooks.h"
/* IDs for all the AVR builtins. */
enum avr_builtin_id
{
#define DEF_BUILTIN(NAME, N_ARGS, TYPE, CODE, LIBNAME) \
AVR_BUILTIN_ ## NAME,
#include "builtins.def"
#undef DEF_BUILTIN
AVR_BUILTIN_COUNT
};
/* Implement `TARGET_RESOLVE_OVERLOADED_PLUGIN'. */
static tree
avr_resolve_overloaded_builtin (unsigned int iloc, tree fndecl, void *vargs)
{
tree type0, type1, fold = NULL_TREE;
enum avr_builtin_id id = AVR_BUILTIN_COUNT;
location_t loc = (location_t) iloc;
vec<tree, va_gc> &args = * (vec<tree, va_gc>*) vargs;
switch (DECL_FUNCTION_CODE (fndecl))
{
default:
break;
case AVR_BUILTIN_ABSFX:
if (args.length() != 1)
{
error_at (loc, "%qs expects 1 argument but %d given",
"absfx", (int) args.length());
fold = error_mark_node;
break;
}
type0 = TREE_TYPE (args[0]);
if (!FIXED_POINT_TYPE_P (type0))
{
error_at (loc, "%qs expects a fixed-point value as argument",
"absfx");
fold = error_mark_node;
}
switch (TYPE_MODE (type0))
{
case QQmode: id = AVR_BUILTIN_ABSHR; break;
case HQmode: id = AVR_BUILTIN_ABSR; break;
case SQmode: id = AVR_BUILTIN_ABSLR; break;
case DQmode: id = AVR_BUILTIN_ABSLLR; break;
case HAmode: id = AVR_BUILTIN_ABSHK; break;
case SAmode: id = AVR_BUILTIN_ABSK; break;
case DAmode: id = AVR_BUILTIN_ABSLK; break;
case TAmode: id = AVR_BUILTIN_ABSLLK; break;
case UQQmode:
case UHQmode:
case USQmode:
case UDQmode:
case UHAmode:
case USAmode:
case UDAmode:
case UTAmode:
warning_at (loc, 0, "using %qs with unsigned type has no effect",
"absfx");
return args[0];
default:
error_at (loc, "no matching fixed-point overload found for %qs",
"absfx");
fold = error_mark_node;
break;
}
fold = targetm.builtin_decl (id, true);
if (fold != error_mark_node)
fold = build_function_call_vec (loc, fold, &args, NULL);
break; // absfx
case AVR_BUILTIN_ROUNDFX:
if (args.length() != 2)
{
error_at (loc, "%qs expects 2 arguments but %d given",
"roundfx", (int) args.length());
fold = error_mark_node;
break;
}
type0 = TREE_TYPE (args[0]);
type1 = TREE_TYPE (args[1]);
if (!FIXED_POINT_TYPE_P (type0))
{
error_at (loc, "%qs expects a fixed-point value as first argument",
"roundfx");
fold = error_mark_node;
}
if (!INTEGRAL_TYPE_P (type1))
{
error_at (loc, "%qs expects an integer value as second argument",
"roundfx");
fold = error_mark_node;
}
switch (TYPE_MODE (type0))
{
case QQmode: id = AVR_BUILTIN_ROUNDHR; break;
case HQmode: id = AVR_BUILTIN_ROUNDR; break;
case SQmode: id = AVR_BUILTIN_ROUNDLR; break;
case DQmode: id = AVR_BUILTIN_ROUNDLLR; break;
case UQQmode: id = AVR_BUILTIN_ROUNDUHR; break;
case UHQmode: id = AVR_BUILTIN_ROUNDUR; break;
case USQmode: id = AVR_BUILTIN_ROUNDULR; break;
case UDQmode: id = AVR_BUILTIN_ROUNDULLR; break;
case HAmode: id = AVR_BUILTIN_ROUNDHK; break;
case SAmode: id = AVR_BUILTIN_ROUNDK; break;
case DAmode: id = AVR_BUILTIN_ROUNDLK; break;
case TAmode: id = AVR_BUILTIN_ROUNDLLK; break;
case UHAmode: id = AVR_BUILTIN_ROUNDUHK; break;
case USAmode: id = AVR_BUILTIN_ROUNDUK; break;
case UDAmode: id = AVR_BUILTIN_ROUNDULK; break;
case UTAmode: id = AVR_BUILTIN_ROUNDULLK; break;
default:
error_at (loc, "no matching fixed-point overload found for %qs",
"roundfx");
fold = error_mark_node;
break;
}
fold = targetm.builtin_decl (id, true);
if (fold != error_mark_node)
fold = build_function_call_vec (loc, fold, &args, NULL);
break; // roundfx
case AVR_BUILTIN_COUNTLSFX:
if (args.length() != 1)
{
error_at (loc, "%qs expects 1 argument but %d given",
"countlsfx", (int) args.length());
fold = error_mark_node;
break;
}
type0 = TREE_TYPE (args[0]);
if (!FIXED_POINT_TYPE_P (type0))
{
error_at (loc, "%qs expects a fixed-point value as first argument",
"countlsfx");
fold = error_mark_node;
}
switch (TYPE_MODE (type0))
{
case QQmode: id = AVR_BUILTIN_COUNTLSHR; break;
case HQmode: id = AVR_BUILTIN_COUNTLSR; break;
case SQmode: id = AVR_BUILTIN_COUNTLSLR; break;
case DQmode: id = AVR_BUILTIN_COUNTLSLLR; break;
case UQQmode: id = AVR_BUILTIN_COUNTLSUHR; break;
case UHQmode: id = AVR_BUILTIN_COUNTLSUR; break;
case USQmode: id = AVR_BUILTIN_COUNTLSULR; break;
case UDQmode: id = AVR_BUILTIN_COUNTLSULLR; break;
case HAmode: id = AVR_BUILTIN_COUNTLSHK; break;
case SAmode: id = AVR_BUILTIN_COUNTLSK; break;
case DAmode: id = AVR_BUILTIN_COUNTLSLK; break;
case TAmode: id = AVR_BUILTIN_COUNTLSLLK; break;
case UHAmode: id = AVR_BUILTIN_COUNTLSUHK; break;
case USAmode: id = AVR_BUILTIN_COUNTLSUK; break;
case UDAmode: id = AVR_BUILTIN_COUNTLSULK; break;
case UTAmode: id = AVR_BUILTIN_COUNTLSULLK; break;
default:
error_at (loc, "no matching fixed-point overload found for %qs",
"countlsfx");
fold = error_mark_node;
break;
}
fold = targetm.builtin_decl (id, true);
if (fold != error_mark_node)
fold = build_function_call_vec (loc, fold, &args, NULL);
break; // countlsfx
}
return fold;
}
/* Implement `REGISTER_TARGET_PRAGMAS'. */
void
@ -49,6 +265,8 @@ avr_register_target_pragmas (void)
if (!ADDR_SPACE_GENERIC_P (i))
c_register_addr_space (avr_addrspace[i].name, avr_addrspace[i].id);
}
targetm.resolve_overloaded_builtin = avr_resolve_overloaded_builtin;
}

View File

@ -24,14 +24,16 @@
(define_mode_iterator ALL1Q [QQ UQQ])
(define_mode_iterator ALL2Q [HQ UHQ])
(define_mode_iterator ALL2A [HA UHA])
(define_mode_iterator ALL2QA [HQ UHQ
HA UHA])
(define_mode_iterator ALL4A [SA USA])
(define_mode_iterator ALL2QA [HQ UHQ HA UHA])
(define_mode_iterator ALL4QA [SQ USQ SA USA])
(define_mode_iterator ALL124QA [ QQ HQ HA SA SQ
UQQ UHQ UHA USA USQ])
(define_mode_iterator ALL2S [HQ HA])
(define_mode_iterator ALL4S [SA SQ])
(define_mode_iterator ALL24S [ HQ HA SA SQ])
(define_mode_iterator ALL124S [ QQ HQ HA SA SQ])
(define_mode_iterator ALL24S [ HQ HA SA SQ])
(define_mode_iterator ALL124S [ QQ HQ HA SA SQ])
(define_mode_iterator ALL124U [UQQ UHQ UHA USA USQ])
;;; Conversions
@ -396,3 +398,131 @@
"%~call __<code><mode>3"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
;******************************************************************************
;** Rounding
;******************************************************************************
;; "roundqq3" "rounduqq3"
;; "roundhq3" "rounduhq3" "roundha3" "rounduha3"
;; "roundsq3" "roundusq3" "roundsa3" "roundusa3"
(define_expand "round<mode>3"
[(set (match_dup 4)
(match_operand:ALL124QA 1 "register_operand" ""))
(set (reg:QI 24)
(match_dup 5))
(parallel [(set (match_dup 3)
(unspec:ALL124QA [(match_dup 4)
(reg:QI 24)] UNSPEC_ROUND))
(clobber (match_dup 4))])
(set (match_operand:ALL124QA 0 "register_operand" "")
(match_dup 3))
(use (match_operand:HI 2 "nonmemory_operand" ""))]
""
{
if (CONST_INT_P (operands[2])
&& !(optimize_size
&& 4 == GET_MODE_SIZE (<MODE>mode)))
{
emit_insn (gen_round<mode>3_const (operands[0], operands[1], operands[2]));
DONE;
}
// Input and output of the libgcc function
const unsigned int regno_in[] = { -1, 22, 22, -1, 18 };
const unsigned int regno_out[] = { -1, 24, 24, -1, 22 };
operands[3] = gen_rtx_REG (<MODE>mode, regno_out[(size_t) GET_MODE_SIZE (<MODE>mode)]);
operands[4] = gen_rtx_REG (<MODE>mode, regno_in[(size_t) GET_MODE_SIZE (<MODE>mode)]);
operands[5] = simplify_gen_subreg (QImode, force_reg (HImode, operands[2]), HImode, 0);
// $2 is no more needed, but is referenced for expand.
operands[2] = const0_rtx;
})
;; Expand rounding with known rounding points inline so that the addend / mask
;; will be consumed by operation with immediate operands and there is no
;; need for a shift with variable offset.
;; "roundqq3_const" "rounduqq3_const"
;; "roundhq3_const" "rounduhq3_const" "roundha3_const" "rounduha3_const"
;; "roundsq3_const" "roundusq3_const" "roundsa3_const" "roundusa3_const"
(define_expand "round<mode>3_const"
[(parallel [(match_operand:ALL124QA 0 "register_operand" "")
(match_operand:ALL124QA 1 "register_operand" "")
(match_operand:HI 2 "const_int_operand" "")])]
""
{
// The rounding point RP is $2. The smallest fractional
// bit that is not cleared by the rounding is 2^(-RP).
enum machine_mode imode = int_mode_for_mode (<MODE>mode);
int fbit = (int) GET_MODE_FBIT (<MODE>mode);
// Add-Saturate 1/2 * 2^(-RP)
double_int i_add = double_int_zero.set_bit (fbit-1 - INTVAL (operands[2]));
rtx x_add = const_fixed_from_double_int (i_add, <MODE>mode);
if (SIGNED_FIXED_POINT_MODE_P (<MODE>mode))
emit_move_insn (operands[0],
gen_rtx_SS_PLUS (<MODE>mode, operands[1], x_add));
else
emit_move_insn (operands[0],
gen_rtx_US_PLUS (<MODE>mode, operands[1], x_add));
// Keep all bits from RP and higher: ... 2^(-RP)
// Clear all bits from RP+1 and lower: 2^(-RP-1) ...
// Rounding point ^^^^^^^
// Added above ^^^^^^^^^
rtx xreg = simplify_gen_subreg (imode, operands[0], <MODE>mode, 0);
rtx xmask = immed_double_int_const (-i_add - i_add, imode);
if (SImode == imode)
emit_insn (gen_andsi3 (xreg, xreg, xmask));
else if (HImode == imode)
emit_insn (gen_andhi3 (xreg, xreg, xmask));
else if (QImode == imode)
emit_insn (gen_andqi3 (xreg, xreg, xmask));
else
gcc_unreachable();
DONE;
})
;; "*roundqq3.libgcc" "*rounduqq3.libgcc"
(define_insn "*round<mode>3.libgcc"
[(set (reg:ALL1Q 24)
(unspec:ALL1Q [(reg:ALL1Q 22)
(reg:QI 24)] UNSPEC_ROUND))
(clobber (reg:ALL1Q 22))]
""
"%~call __round<mode>3"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
;; "*roundhq3.libgcc" "*rounduhq3.libgcc"
;; "*roundha3.libgcc" "*rounduha3.libgcc"
(define_insn "*round<mode>3.libgcc"
[(set (reg:ALL2QA 24)
(unspec:ALL2QA [(reg:ALL2QA 22)
(reg:QI 24)] UNSPEC_ROUND))
(clobber (reg:ALL2QA 22))]
""
"%~call __round<mode>3"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])
;; "*roundsq3.libgcc" "*roundusq3.libgcc"
;; "*roundsa3.libgcc" "*roundusa3.libgcc"
(define_insn "*round<mode>3.libgcc"
[(set (reg:ALL4QA 22)
(unspec:ALL4QA [(reg:ALL4QA 18)
(reg:QI 24)] UNSPEC_ROUND))
(clobber (reg:ALL4QA 18))]
""
"%~call __round<mode>3"
[(set_attr "type" "xcall")
(set_attr "cc" "clobber")])

View File

@ -11489,32 +11489,118 @@ avr_init_builtins (void)
const_memx_ptr_type_node,
NULL);
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 ITYP(T) \
lang_hooks.types.type_for_size (TYPE_PRECISION (T), TYPE_UNSIGNED (T))
#define FX_FTYPE_FX(fx) \
tree fx##r_ftype_##fx##r \
= build_function_type_list (node_##fx##r, node_##fx##r, NULL); \
tree fx##k_ftype_##fx##k \
= build_function_type_list (node_##fx##k, node_##fx##k, NULL)
#define FX_FTYPE_FX_INT(fx) \
tree fx##r_ftype_##fx##r_int \
= build_function_type_list (node_##fx##r, node_##fx##r, \
integer_type_node, NULL); \
tree fx##k_ftype_##fx##k_int \
= build_function_type_list (node_##fx##k, node_##fx##k, \
integer_type_node, NULL)
#define INT_FTYPE_FX(fx) \
tree int_ftype_##fx##r \
= build_function_type_list (integer_type_node, node_##fx##r, NULL); \
tree int_ftype_##fx##k \
= build_function_type_list (integer_type_node, node_##fx##k, NULL)
#define INTX_FTYPE_FX(fx) \
tree int##fx##r_ftype_##fx##r \
= build_function_type_list (ITYP (node_##fx##r), node_##fx##r, NULL); \
tree int##fx##k_ftype_##fx##k \
= build_function_type_list (ITYP (node_##fx##k), node_##fx##k, NULL)
#define FX_FTYPE_INTX(fx) \
tree fx##r_ftype_int##fx##r \
= build_function_type_list (node_##fx##r, ITYP (node_##fx##r), NULL); \
tree fx##k_ftype_int##fx##k \
= build_function_type_list (node_##fx##k, ITYP (node_##fx##k), NULL)
tree node_hr = short_fract_type_node;
tree node_r = fract_type_node;
tree node_lr = long_fract_type_node;
tree node_llr = long_long_fract_type_node;
tree node_uhr = unsigned_short_fract_type_node;
tree node_ur = unsigned_fract_type_node;
tree node_ulr = unsigned_long_fract_type_node;
tree node_ullr = unsigned_long_long_fract_type_node;
tree node_hk = short_accum_type_node;
tree node_k = accum_type_node;
tree node_lk = long_accum_type_node;
tree node_llk = long_long_accum_type_node;
tree node_uhk = unsigned_short_accum_type_node;
tree node_uk = unsigned_accum_type_node;
tree node_ulk = unsigned_long_accum_type_node;
tree node_ullk = unsigned_long_long_accum_type_node;
/* For absfx builtins. */
FX_FTYPE_FX (h);
FX_FTYPE_FX ();
FX_FTYPE_FX (l);
FX_FTYPE_FX (ll);
/* For roundfx builtins. */
FX_FTYPE_FX_INT (h);
FX_FTYPE_FX_INT ();
FX_FTYPE_FX_INT (l);
FX_FTYPE_FX_INT (ll);
FX_FTYPE_FX_INT (uh);
FX_FTYPE_FX_INT (u);
FX_FTYPE_FX_INT (ul);
FX_FTYPE_FX_INT (ull);
/* For countlsfx builtins. */
INT_FTYPE_FX (h);
INT_FTYPE_FX ();
INT_FTYPE_FX (l);
INT_FTYPE_FX (ll);
INT_FTYPE_FX (uh);
INT_FTYPE_FX (u);
INT_FTYPE_FX (ul);
INT_FTYPE_FX (ull);
/* For bitsfx builtins. */
INTX_FTYPE_FX (h);
INTX_FTYPE_FX ();
INTX_FTYPE_FX (l);
INTX_FTYPE_FX (ll);
INTX_FTYPE_FX (uh);
INTX_FTYPE_FX (u);
INTX_FTYPE_FX (ul);
INTX_FTYPE_FX (ull);
/* For fxbits builtins. */
FX_FTYPE_INTX (h);
FX_FTYPE_INTX ();
FX_FTYPE_INTX (l);
FX_FTYPE_INTX (ll);
FX_FTYPE_INTX (uh);
FX_FTYPE_INTX (u);
FX_FTYPE_INTX (ul);
FX_FTYPE_INTX (ull);
#define DEF_BUILTIN(NAME, N_ARGS, TYPE, CODE, LIBNAME) \
{ \
int id = AVR_BUILTIN_ ## NAME; \
@ -11647,7 +11733,50 @@ avr_expand_builtin (tree exp, rtx target,
" as first argument", bname);
return target;
}
break;
}
case AVR_BUILTIN_ROUNDHR: case AVR_BUILTIN_ROUNDUHR:
case AVR_BUILTIN_ROUNDR: case AVR_BUILTIN_ROUNDUR:
case AVR_BUILTIN_ROUNDLR: case AVR_BUILTIN_ROUNDULR:
case AVR_BUILTIN_ROUNDLLR: case AVR_BUILTIN_ROUNDULLR:
case AVR_BUILTIN_ROUNDHK: case AVR_BUILTIN_ROUNDUHK:
case AVR_BUILTIN_ROUNDK: case AVR_BUILTIN_ROUNDUK:
case AVR_BUILTIN_ROUNDLK: case AVR_BUILTIN_ROUNDULK:
case AVR_BUILTIN_ROUNDLLK: case AVR_BUILTIN_ROUNDULLK:
/* Warn about odd rounding. Rounding points >= FBIT will have
no effect. */
if (TREE_CODE (CALL_EXPR_ARG (exp, 1)) != INTEGER_CST)
break;
int rbit = (int) TREE_INT_CST_LOW (CALL_EXPR_ARG (exp, 1));
if (rbit >= (int) GET_MODE_FBIT (mode))
{
warning (OPT_Wextra, "rounding to %d bits has no effect for "
"fixed-point value with %d fractional bits",
rbit, GET_MODE_FBIT (mode));
return expand_expr (CALL_EXPR_ARG (exp, 0), NULL_RTX, mode,
EXPAND_NORMAL);
}
else if (rbit <= - (int) GET_MODE_IBIT (mode))
{
warning (0, "rounding result will always be 0");
return CONST0_RTX (mode);
}
/* The rounding points RP satisfies now: -IBIT < RP < FBIT.
TR 18037 only specifies results for RP > 0. However, the
remaining cases of -IBIT < RP <= 0 can easily be supported
without any additional overhead. */
break; /* round */
}
/* No fold found and no insn: Call support function from libgcc. */
@ -11736,6 +11865,31 @@ avr_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *arg,
return avr_fold_absfx (arg[0]);
case AVR_BUILTIN_BITSHR: case AVR_BUILTIN_HRBITS:
case AVR_BUILTIN_BITSHK: case AVR_BUILTIN_HKBITS:
case AVR_BUILTIN_BITSUHR: case AVR_BUILTIN_UHRBITS:
case AVR_BUILTIN_BITSUHK: case AVR_BUILTIN_UHKBITS:
case AVR_BUILTIN_BITSR: case AVR_BUILTIN_RBITS:
case AVR_BUILTIN_BITSK: case AVR_BUILTIN_KBITS:
case AVR_BUILTIN_BITSUR: case AVR_BUILTIN_URBITS:
case AVR_BUILTIN_BITSUK: case AVR_BUILTIN_UKBITS:
case AVR_BUILTIN_BITSLR: case AVR_BUILTIN_LRBITS:
case AVR_BUILTIN_BITSLK: case AVR_BUILTIN_LKBITS:
case AVR_BUILTIN_BITSULR: case AVR_BUILTIN_ULRBITS:
case AVR_BUILTIN_BITSULK: case AVR_BUILTIN_ULKBITS:
case AVR_BUILTIN_BITSLLR: case AVR_BUILTIN_LLRBITS:
case AVR_BUILTIN_BITSLLK: case AVR_BUILTIN_LLKBITS:
case AVR_BUILTIN_BITSULLR: case AVR_BUILTIN_ULLRBITS:
case AVR_BUILTIN_BITSULLK: case AVR_BUILTIN_ULLKBITS:
gcc_assert (TYPE_PRECISION (val_type)
== TYPE_PRECISION (TREE_TYPE (arg[0])));
return build1 (VIEW_CONVERT_EXPR, val_type, arg[0]);
case AVR_BUILTIN_INSERT_BITS:
{
tree tbits = arg[1];

View File

@ -68,6 +68,7 @@
UNSPEC_COPYSIGN
UNSPEC_IDENTITY
UNSPEC_INSERT_BITS
UNSPEC_ROUND
])
(define_c_enum "unspecv"

View File

@ -61,12 +61,109 @@ DEF_BUILTIN (FLASH_SEGMENT, 1, char_ftype_const_memx_ptr, flash_segment, NULL)
/* 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 (ABSHR, 1, hr_ftype_hr, ssabsqq2, "__ssabs_1")
DEF_BUILTIN (ABSR, 1, r_ftype_r, ssabshq2, "__ssabs_2")
DEF_BUILTIN (ABSLR, 1, lr_ftype_lr, ssabssq2, "__ssabs_4")
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
DEF_BUILTIN (ABSHK, 1, hk_ftype_hk, ssabsha2, "__ssabs_2")
DEF_BUILTIN (ABSK, 1, k_ftype_k, ssabssa2, "__ssabs_4")
DEF_BUILTIN (ABSLK, -1, lk_ftype_lk, nothing, "__ssabsda2")
DEF_BUILTIN (ABSLLK, -1, llk_ftype_llk, nothing, "__ssabsta2") // GCC extension
/* 7.18a.6.3 The fixed-point round functions. */
DEF_BUILTIN (ROUNDHR, 2, hr_ftype_hr_int, roundqq3, "__roundhr")
DEF_BUILTIN (ROUNDR, 2, r_ftype_r_int, roundhq3, "__roundr")
DEF_BUILTIN (ROUNDLR, 2, lr_ftype_lr_int, roundsq3, "__roundlr")
DEF_BUILTIN (ROUNDLLR, -1, llr_ftype_llr_int, nothing, "__rounddq3") // GCC extension
DEF_BUILTIN (ROUNDUHR, 2, uhr_ftype_uhr_int, rounduqq3, "__rounduhr")
DEF_BUILTIN (ROUNDUR, 2, ur_ftype_ur_int, rounduhq3, "__roundur")
DEF_BUILTIN (ROUNDULR, 2, ulr_ftype_ulr_int, roundusq3, "__roundulr")
DEF_BUILTIN (ROUNDULLR, -1, ullr_ftype_ullr_int, nothing, "__roundudq3") // GCC extension
DEF_BUILTIN (ROUNDHK, 2, hk_ftype_hk_int, roundha3, "__roundhk")
DEF_BUILTIN (ROUNDK, 2, k_ftype_k_int, roundsa3, "__roundk")
DEF_BUILTIN (ROUNDLK, -1, lk_ftype_lk_int, nothing, "__roundda3")
DEF_BUILTIN (ROUNDLLK, -1, llk_ftype_llk_int, nothing, "__roundta3") // GCC extension
DEF_BUILTIN (ROUNDUHK, 2, uhk_ftype_uhk_int, rounduha3, "__rounduhk")
DEF_BUILTIN (ROUNDUK, 2, uk_ftype_uk_int, roundusa3, "__rounduk")
DEF_BUILTIN (ROUNDULK, -1, ulk_ftype_ulk_int, nothing, "__rounduda3")
DEF_BUILTIN (ROUNDULLK, -1, ullk_ftype_ullk_int, nothing, "__rounduta3") // GCC extension
/* 7.18a.6.4 The fixed-point bit countls functions. */
DEF_BUILTIN (COUNTLSHR, -1, int_ftype_hr, nothing, "__countlsqi2")
DEF_BUILTIN (COUNTLSR, -1, int_ftype_r, nothing, "__countlshi2")
DEF_BUILTIN (COUNTLSLR, -1, int_ftype_lr, nothing, "__countlssi2")
DEF_BUILTIN (COUNTLSLLR, -1, int_ftype_llr, nothing, "__countlsdi2") // GCC extension
DEF_BUILTIN (COUNTLSUHR, -1, int_ftype_uhr, nothing, "__countlsuqi2")
DEF_BUILTIN (COUNTLSUR, -1, int_ftype_ur, nothing, "__countlsuhi2")
DEF_BUILTIN (COUNTLSULR, -1, int_ftype_ulr, nothing, "__countlsusi2")
DEF_BUILTIN (COUNTLSULLR, -1, int_ftype_ullr, nothing, "__countlsudi2") // GCC extension
DEF_BUILTIN (COUNTLSHK, -1, int_ftype_hk, nothing, "__countlshi2")
DEF_BUILTIN (COUNTLSK, -1, int_ftype_k, nothing, "__countlssi2")
DEF_BUILTIN (COUNTLSLK, -1, int_ftype_lk, nothing, "__countlsdi2")
DEF_BUILTIN (COUNTLSLLK, -1, int_ftype_llk, nothing, "__countlsdi2") // GCC extension
DEF_BUILTIN (COUNTLSUHK, -1, int_ftype_uhk, nothing, "__countlsuhi2")
DEF_BUILTIN (COUNTLSUK, -1, int_ftype_uk, nothing, "__countlsusi2")
DEF_BUILTIN (COUNTLSULK, -1, int_ftype_ulk, nothing, "__countlsudi2")
DEF_BUILTIN (COUNTLSULLK, -1, int_ftype_ullk, nothing, "__countlsudi2") // GCC extension
/* 7.18a.6.5 The bitwise fixed-point to integer conversion functions. */
DEF_BUILTIN (BITSHR, -1, inthr_ftype_hr, nothing, "__ret")
DEF_BUILTIN (BITSR, -1, intr_ftype_r, nothing, "__ret")
DEF_BUILTIN (BITSLR, -1, intlr_ftype_lr, nothing, "__ret")
DEF_BUILTIN (BITSLLR, -1, intllr_ftype_llr, nothing, "__ret") // GCC extension
DEF_BUILTIN (BITSUHR, -1, intuhr_ftype_uhr, nothing, "__ret")
DEF_BUILTIN (BITSUR, -1, intur_ftype_ur, nothing, "__ret")
DEF_BUILTIN (BITSULR, -1, intulr_ftype_ulr, nothing, "__ret")
DEF_BUILTIN (BITSULLR, -1, intullr_ftype_ullr, nothing, "__ret") // GCC extension
DEF_BUILTIN (BITSHK, -1, inthk_ftype_hk, nothing, "__ret")
DEF_BUILTIN (BITSK, -1, intk_ftype_k, nothing, "__ret")
DEF_BUILTIN (BITSLK, -1, intlk_ftype_lk, nothing, "__ret")
DEF_BUILTIN (BITSLLK, -1, intllk_ftype_llk, nothing, "__ret") // GCC extension
DEF_BUILTIN (BITSUHK, -1, intuhk_ftype_uhk, nothing, "__ret")
DEF_BUILTIN (BITSUK, -1, intuk_ftype_uk, nothing, "__ret")
DEF_BUILTIN (BITSULK, -1, intulk_ftype_ulk, nothing, "__ret")
DEF_BUILTIN (BITSULLK, -1, intullk_ftype_ullk, nothing, "__ret") // GCC extension
/* 7.18a.6.6 The bitwise integer to fixed-point conversion functions. */
DEF_BUILTIN ( HRBITS, -1, hr_ftype_inthr, nothing, "__ret")
DEF_BUILTIN ( RBITS, -1, r_ftype_intr, nothing, "__ret")
DEF_BUILTIN ( LRBITS, -1, lr_ftype_intlr, nothing, "__ret")
DEF_BUILTIN ( LLRBITS, -1, llr_ftype_intllr, nothing, "__ret") // GCC extension
DEF_BUILTIN ( UHRBITS, -1, uhr_ftype_intuhr, nothing, "__ret")
DEF_BUILTIN ( URBITS, -1, ur_ftype_intur, nothing, "__ret")
DEF_BUILTIN ( ULRBITS, -1, ulr_ftype_intulr, nothing, "__ret")
DEF_BUILTIN (ULLRBITS, -1, ullr_ftype_intullr, nothing, "__ret") // GCC extension
DEF_BUILTIN ( HKBITS, -1, hk_ftype_inthk, nothing, "__ret")
DEF_BUILTIN ( KBITS, -1, k_ftype_intk, nothing, "__ret")
DEF_BUILTIN ( LKBITS, -1, lk_ftype_intlk, nothing, "__ret")
DEF_BUILTIN ( LLKBITS, -1, llk_ftype_intllk, nothing, "__ret") // GCC extension
DEF_BUILTIN ( UHKBITS, -1, uhk_ftype_intuhk, nothing, "__ret")
DEF_BUILTIN ( UKBITS, -1, uk_ftype_intuk, nothing, "__ret")
DEF_BUILTIN ( ULKBITS, -1, ulk_ftype_intulk, nothing, "__ret")
DEF_BUILTIN (ULLKBITS, -1, ullk_ftype_intullk, nothing, "__ret") // GCC extension
/* Overloaded */
/* 7.18a.6.7 Type-generic fixed-point functions. */
DEF_BUILTIN (ABSFX, -1, void_ftype_void /* dummy */, nothing, NULL)
DEF_BUILTIN (ROUNDFX, -1, void_ftype_void /* dummy */, nothing, NULL)
DEF_BUILTIN (COUNTLSFX, -1, void_ftype_void /* dummy */, nothing, NULL)

View File

@ -35,10 +35,6 @@
#include <stdfix-gcc.h>
#define _GCC_TYPEPUN(A, B) \
__builtin_memcpy (&A, &B, sizeof (A))
/* 7.18a.6 The fixed-point intrinsic functions. */
#if __SIZEOF_INT__ == 2
@ -66,8 +62,7 @@ typedef long long unsigned int uint_ulk_t;
typedef long long int int_llk_t;
typedef long long unsigned int uint_ullk_t;
#else /* __SIZEOF_INT__ = 1 (for -mint8) */
#elif __SIZEOF_INT__ == 1 /* -mint8 */
typedef signed char int_hr_t;
typedef unsigned char uint_uhr_t;
@ -84,356 +79,158 @@ typedef long long unsigned int uint_ulr_t;
typedef long long int int_k_t;
typedef long long unsigned int uint_uk_t;
#endif /* __SIZEOF_INT__ == 2 */
#endif /* __SIZEOF_INT__ == 1, 2 */
/* 7.18a.6.2 The fixed-point absolute value functions. */
/* 7.18a.6 The fixed-point intrinsic functions. */
/* short fract (hr): abshr */
static __inline__ __attribute__((__always_inline__))
short fract abshr (const short fract __q)
{
return __builtin_avr_abshr (__q);
}
/* 7.18a.6.2 The fixed-point absolute value functions. */
/* fract (r): absr */
#define abshr __builtin_avr_abshr
#define absr __builtin_avr_absr
#define abslr __builtin_avr_abslr
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);
}
#define abshk __builtin_avr_abshk
#define absk __builtin_avr_absk
#if __SIZEOF_INT__ == 2
/* long long fract (llr): absllr */
#define abslk __builtin_avr_abslk
#define absllr __builtin_avr_absllr /* GCC Extension */
#define absllk __builtin_avr_absllk /* GCC Extension */
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 */
#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. */
/* 7.18a.6.3 The fixed-point round functions. */
/* short fract (hr): bitshr, bitsuhr, hrbits, uhrbits */
/* The Embedded-C paper specifies results only for rounding points
static __inline__ __attribute__((__always_inline__))
int_hr_t bitshr (const short fract __q)
{
int_hr_t __result;
_GCC_TYPEPUN (__result, __q);
return __result;
}
0 < RP < FBIT
As an extension, the following functions work as expected
with rounding points
static __inline__ __attribute__((__always_inline__))
uint_uhr_t bitsuhr (const unsigned short fract __q)
{
uint_uhr_t __result;
_GCC_TYPEPUN (__result, __q);
return __result;
}
-IBIT < RP < FBIT
For example, rounding an accum with a rounding point of -1 will
result in an even integer value. */
static __inline__ __attribute__((__always_inline__))
short fract hrbits (const int_hr_t __i)
{
short fract __result;
_GCC_TYPEPUN (__result, __i);
return __result;
}
#define roundhr __builtin_avr_roundhr
#define roundr __builtin_avr_roundr
#define roundlr __builtin_avr_roundlr
static __inline__ __attribute__((__always_inline__))
unsigned short fract uhrbits (const uint_uhr_t __i)
{
unsigned short fract __result;
_GCC_TYPEPUN (__result, __i);
return __result;
}
#define rounduhr __builtin_avr_rounduhr
#define roundur __builtin_avr_roundur
#define roundulr __builtin_avr_roundulr
/* fract (r): bitsr, bitsur, rbits, urbits */
#define roundhk __builtin_avr_roundhk
#define roundk __builtin_avr_roundk
static __inline__ __attribute__((__always_inline__))
int_r_t bitsr (const fract __q)
{
int_r_t __result;
_GCC_TYPEPUN (__result, __q);
return __result;
}
static __inline__ __attribute__((__always_inline__))
uint_ur_t bitsur (const unsigned fract __q)
{
uint_ur_t __result;
_GCC_TYPEPUN (__result, __q);
return __result;
}
static __inline__ __attribute__((__always_inline__))
fract rbits (const int_r_t __i)
{
fract __result;
_GCC_TYPEPUN (__result, __i);
return __result;
}
static __inline__ __attribute__((__always_inline__))
unsigned fract urbits (const uint_ur_t __i)
{
unsigned fract __result;
_GCC_TYPEPUN (__result, __i);
return __result;
}
/* long fract (lr): bitslr, bitsulr, lrbits, ulrbits */
static __inline__ __attribute__((__always_inline__))
int_lr_t bitslr (const long fract __q)
{
int_lr_t __result;
_GCC_TYPEPUN (__result, __q);
return __result;
}
static __inline__ __attribute__((__always_inline__))
uint_ulr_t bitsulr (const unsigned long fract __q)
{
uint_ulr_t __result;
_GCC_TYPEPUN (__result, __q);
return __result;
}
static __inline__ __attribute__((__always_inline__))
long fract lrbits (const int_lr_t __i)
{
long fract __result;
_GCC_TYPEPUN (__result, __i);
return __result;
}
static __inline__ __attribute__((__always_inline__))
unsigned long fract ulrbits (const uint_ulr_t __i)
{
unsigned long fract __result;
_GCC_TYPEPUN (__result, __i);
return __result;
}
/* short accum (hk): bitshk, bitsuhk, hkbits, uhkbits */
static __inline__ __attribute__((__always_inline__))
int_hk_t bitshk (const short accum __q)
{
int_hk_t __result;
_GCC_TYPEPUN (__result, __q);
return __result;
}
static __inline__ __attribute__((__always_inline__))
uint_uhk_t bitsuhk (const unsigned short accum __q)
{
uint_uhk_t __result;
_GCC_TYPEPUN (__result, __q);
return __result;
}
static __inline__ __attribute__((__always_inline__))
short accum hkbits (const int_hk_t __i)
{
short accum __result;
_GCC_TYPEPUN (__result, __i);
return __result;
}
static __inline__ __attribute__((__always_inline__))
unsigned short accum uhkbits (const uint_uhk_t __i)
{
unsigned short accum __result;
_GCC_TYPEPUN (__result, __i);
return __result;
}
/* accum (k): bitsk, bitsuk, kbits, ukbits */
static __inline__ __attribute__((__always_inline__))
int_k_t bitsk (const accum __q)
{
int_k_t __result;
_GCC_TYPEPUN (__result, __q);
return __result;
}
static __inline__ __attribute__((__always_inline__))
uint_uk_t bitsuk (const unsigned accum __q)
{
uint_uk_t __result;
_GCC_TYPEPUN (__result, __q);
return __result;
}
static __inline__ __attribute__((__always_inline__))
accum kbits (const int_k_t __i)
{
accum __result;
_GCC_TYPEPUN (__result, __i);
return __result;
}
static __inline__ __attribute__((__always_inline__))
unsigned accum ukbits (const uint_uk_t __i)
{
unsigned accum __result;
_GCC_TYPEPUN (__result, __i);
return __result;
}
#define rounduhk __builtin_avr_rounduhk
#define rounduk __builtin_avr_rounduk
#if __SIZEOF_INT__ == 2
/* long long fract (llr): bitsllr, bitsullr, llrbits, ullrbits */
#define roundlk __builtin_avr_roundlk
#define roundulk __builtin_avr_roundulk
#define roundllr __builtin_avr_roundllr /* GCC Extension */
#define roundullr __builtin_avr_roundullr /* GCC Extension */
#define roundllk __builtin_avr_roundllk /* GCC Extension */
#define roundullk __builtin_avr_roundullk /* GCC Extension */
static __inline__ __attribute__((__always_inline__))
int_llr_t bitsllr (const long long fract __q)
{
int_llr_t __result;
_GCC_TYPEPUN (__result, __q);
return __result;
}
#endif /* sizeof (int) == 2 */
static __inline__ __attribute__((__always_inline__))
uint_ullr_t bitsullr (const unsigned long long fract __q)
{
uint_ullr_t __result;
_GCC_TYPEPUN (__result, __q);
return __result;
}
static __inline__ __attribute__((__always_inline__))
long long fract llrbits (const int_llr_t __i)
{
long long fract __result;
_GCC_TYPEPUN (__result, __i);
return __result;
}
/* 7.18a.6.4 The fixed-point bit countls functions. */
static __inline__ __attribute__((__always_inline__))
unsigned long long fract ullrbits (const uint_ullr_t __i)
{
unsigned long long fract __result;
_GCC_TYPEPUN (__result, __i);
return __result;
}
#define countlshr __builtin_avr_countlshr
#define countlsr __builtin_avr_countlsr
#define countlslr __builtin_avr_countlslr
/* long accum (lk): bitslk, bitsulk, lkbits, ulkbits */
#define countlsuhr __builtin_avr_countlsuhr
#define countlsur __builtin_avr_countlsur
#define countlsulr __builtin_avr_countlsulr
static __inline__ __attribute__((__always_inline__))
int_lk_t bitslk (const long accum __q)
{
int_lk_t __result;
_GCC_TYPEPUN (__result, __q);
return __result;
}
#define countlshk __builtin_avr_countlshk
#define countlsk __builtin_avr_countlsk
static __inline__ __attribute__((__always_inline__))
uint_ulk_t bitsulk (const unsigned long accum __q)
{
uint_ulk_t __result;
_GCC_TYPEPUN (__result, __q);
return __result;
}
#define countlsuhk __builtin_avr_countlsuhk
#define countlsuk __builtin_avr_countlsuk
static __inline__ __attribute__((__always_inline__))
long accum lkbits (const int_lk_t __i)
{
long accum __result;
_GCC_TYPEPUN (__result, __i);
return __result;
}
#if __SIZEOF_INT__ == 2
static __inline__ __attribute__((__always_inline__))
unsigned long accum ulkbits (const uint_ulk_t __i)
{
unsigned long accum __result;
_GCC_TYPEPUN (__result, __i);
return __result;
}
#define countlslk __builtin_avr_countlslk
#define countlsulk __builtin_avr_countlsulk
#define countlsllr __builtin_avr_countlsllr /* GCC Extension */
#define countlsullr __builtin_avr_countlsullr /* GCC Extension */
#define countlsllk __builtin_avr_countlsllk /* GCC Extension */
#define countlsullk __builtin_avr_countlsullk /* GCC Extension */
/* long long accum (llk): bitsllk, bitsullk, llkbits, ullkbits */
#endif /* sizeof (int) == 2 */
static __inline__ __attribute__((__always_inline__))
int_llk_t bitsllk (const long long accum __q)
{
int_llk_t __result;
_GCC_TYPEPUN (__result, __q);
return __result;
}
static __inline__ __attribute__((__always_inline__))
uint_ullk_t bitsullk (const unsigned long long accum __q)
{
uint_ullk_t __result;
_GCC_TYPEPUN (__result, __q);
return __result;
}
/* 7.18a.6.5 The bitwise fixed-point to integer conversion functions. */
static __inline__ __attribute__((__always_inline__))
long long accum llkbits (const int_llk_t __i)
{
long long accum __result;
_GCC_TYPEPUN (__result, __i);
return __result;
}
#define bitshr __builtin_avr_bitshr
#define bitsr __builtin_avr_bitsr
#define bitslr __builtin_avr_bitslr
static __inline__ __attribute__((__always_inline__))
unsigned long long accum ullkbits (const uint_ullk_t __i)
{
unsigned long long accum __result;
_GCC_TYPEPUN (__result, __i);
return __result;
}
#define bitsuhr __builtin_avr_bitsuhr
#define bitsur __builtin_avr_bitsur
#define bitsulr __builtin_avr_bitsulr
#define bitshk __builtin_avr_bitshk
#define bitsk __builtin_avr_bitsk
#define bitsuhk __builtin_avr_bitsuhk
#define bitsuk __builtin_avr_bitsuk
#if __SIZEOF_INT__ == 2
#define bitslk __builtin_avr_bitslk
#define bitsulk __builtin_avr_bitsulk
#define bitsllr __builtin_avr_bitsllr /* GCC Extension */
#define bitsullr __builtin_avr_bitsullr /* GCC Extension */
#define bitsllk __builtin_avr_bitsllk /* GCC Extension */
#define bitsullk __builtin_avr_bitsullk /* GCC Extension */
#endif /* sizeof (int) == 2 */
/* 7.18a.6.6 The bitwise integer to fixed-point conversion functions. */
#define hrbits __builtin_avr_hrbits
#define rbits __builtin_avr_rbits
#define lrbits __builtin_avr_lrbits
#define uhrbits __builtin_avr_uhrbits
#define urbits __builtin_avr_urbits
#define ulrbits __builtin_avr_ulrbits
#define hkbits __builtin_avr_hkbits
#define kbits __builtin_avr_kbits
#define uhkbits __builtin_avr_uhkbits
#define ukbits __builtin_avr_ukbits
#if __SIZEOF_INT__ == 2
#define lkbits __builtin_avr_lkbits
#define ulkbits __builtin_avr_ulkbits
#define llrbits __builtin_avr_llrbits /* GCC Extension */
#define ullrbits __builtin_avr_ullrbits /* GCC Extension */
#define llkbits __builtin_avr_llkbits /* GCC Extension */
#define ullkbits __builtin_avr_ullkbits /* GCC Extension */
#endif /* sizeof (int) == 2 */
/* 7.18a.6.7 Type-generic fixed-point functions. */
#define absfx __builtin_avr_absfx
#define roundfx __builtin_avr_roundfx
#define countlsfx __builtin_avr_countlsfx
#endif /* __SIZEOF_INT__ == 2 */
#endif /* _AVRGCC_STDFIX_H */

View File

@ -1,3 +1,9 @@
2013-02-08 Georg-Johann Lay <avr@gjlay.de>
PR target/54222
* gcc.target/avr/torture/builtins-4-roundfx.c: New test.
* gcc.target/avr/torture/builtins-5-countlsfx.c: New test.
2013-02-07 Jakub Jelinek <jakub@redhat.com>
PR c++/56241

View File

@ -0,0 +1,161 @@
/* { dg-options "-std=gnu99" } */
/* { dg-do run } */
#include <stdfix.h>
extern void abort (void);
typedef short _Fract fx_hr_t;
typedef _Fract fx_r_t;
typedef long _Fract fx_lr_t;
typedef long long _Fract fx_llr_t;
typedef unsigned short _Fract fx_uhr_t;
typedef unsigned _Fract fx_ur_t;
typedef unsigned long _Fract fx_ulr_t;
typedef unsigned long long _Fract fx_ullr_t;
typedef short _Accum fx_hk_t;
typedef _Accum fx_k_t;
typedef long _Accum fx_lk_t;
typedef long long _Accum fx_llk_t;
typedef unsigned short _Accum fx_uhk_t;
typedef unsigned _Accum fx_uk_t;
typedef unsigned long _Accum fx_ulk_t;
typedef unsigned long long _Accum fx_ullk_t;
typedef unsigned char int_uhr_t;
typedef unsigned int int_ur_t;
typedef unsigned long int_ulr_t;
typedef unsigned long long int_ullr_t;
typedef unsigned int int_uhk_t;
typedef unsigned long int_uk_t;
typedef unsigned long long int_ulk_t;
typedef unsigned long long int_ullk_t;
#define DEFTEST1(T,FX) \
T test1_##FX (T x, int rp) \
{ \
return round##FX (x, rp); \
} \
\
unsigned T test1_u##FX (unsigned T x, int rp) \
{ \
return roundu##FX (x, rp); \
}
DEFTEST1 (short fract, hr)
DEFTEST1 (fract, r)
DEFTEST1 (long fract, lr)
DEFTEST1 (long long fract, llr)
DEFTEST1 (short accum, hk)
DEFTEST1 (accum, k)
DEFTEST1 (long accum, lk)
DEFTEST1 (long long accum, llk)
#define TEST2(FX, RP, VAL, ROUND) \
{ \
if (round##FX (FX##bits (VAL), RP) != FX##bits (ROUND)) \
abort(); \
fx_##FX##_t (*f)(fx_##FX##_t,int) = round##FX; \
asm ("" : "+r" (f)); \
if (f (FX##bits (VAL), RP) != FX##bits (ROUND)) \
abort(); \
}
static void test2hr (void)
{
TEST2 (hr, 1, 0x7f, 0x40);
TEST2 (hr, 2, 0x7f, 0b1100000);
TEST2 (hr, 3, 0x7f, 0b1110000);
TEST2 (hr, 4, 0x7f, 0b1111000);
TEST2 (uhr, 1, 0x7f, 0x80);
TEST2 (uhr, 2, 0x7f, 0x80);
TEST2 (uhr, 3, 0x7f, 0x80);
TEST2 (uhr, 4, 0x7f, 0x80);
}
void test2k (void)
{
TEST2 (k, 1, 0x7fffffff, 0x7fff8000 | 0b100000000000000);
TEST2 (k, 2, 0x7fffffff, 0x7fff8000 | 0b110000000000000);
TEST2 (k, 3, 0x7fffffff, 0x7fff8000 | 0b111000000000000);
TEST2 (k, 4, 0x7fffffff, 0x7fff8000 | 0b111100000000000);
TEST2 (uk, 1, 0x7fffffff, 1ul << 31);
TEST2 (uk, 2, 0x7fffffff, 1ul << 31);
TEST2 (uk, 3, 0x7fffffff, 1ul << 31);
TEST2 (uk, 4, 0x7fffffff, 1ul << 31);
}
#define DEFTEST3(FX, FBIT) \
void test3##FX (void) \
{ \
TEST2 (FX, FBIT-1, 0b01100, 0b01100); \
TEST2 (FX, FBIT-2, 0b01100, 0b01100); \
TEST2 (FX, FBIT-3, 0b01100, 0b10000); \
TEST2 (FX, FBIT-4, 0b01100, 0b10000); \
TEST2 (FX, FBIT-5, 0b01100, 0); \
\
if (FX##bits ((int_##FX##_t) -1) > 0) \
return; \
\
TEST2 (FX, FBIT-1, -0b01100, -0b01100); \
TEST2 (FX, FBIT-2, -0b01100, -0b01100); \
TEST2 (FX, FBIT-3, -0b01100, -0b01000); \
TEST2 (FX, FBIT-4, -0b01100, -0b10000); \
TEST2 (FX, FBIT-5, -0b01100, -0b00000); \
}
DEFTEST3 (hr, SFRACT_FBIT)
DEFTEST3 (r, FRACT_FBIT)
DEFTEST3 (lr, LFRACT_FBIT)
DEFTEST3 (uhr, USFRACT_FBIT)
DEFTEST3 (ur, UFRACT_FBIT)
DEFTEST3 (ulr, ULFRACT_FBIT)
DEFTEST3 (hk, SACCUM_FBIT)
DEFTEST3 (k, ACCUM_FBIT)
DEFTEST3 (lk, LACCUM_FBIT)
DEFTEST3 (llk, LLACCUM_FBIT)
DEFTEST3 (uhk, USACCUM_FBIT)
DEFTEST3 (uk, UACCUM_FBIT)
DEFTEST3 (ulk, ULACCUM_FBIT)
DEFTEST3 (ullk, ULLACCUM_FBIT)
int main (void)
{
test2hr();
test2k();
test3hr();
test3r();
test3lr();
test3uhr();
test3ur();
test3ulr();
test3hk();
test3k();
test3lk();
test3llk();
test3uhk();
test3uk();
test3ulk();
test3ullk();
return 0;
}

View File

@ -0,0 +1,82 @@
/* { dg-options "-std=gnu99" } */
/* { dg-do run } */
#include <stdfix.h>
extern void abort (void);
#define DEFTEST1(T,FX) \
int test1_##FX (T x) \
{ \
return countls##FX (x); \
} \
\
int test1_u##FX (unsigned T x) \
{ \
return countlsu##FX (x); \
}
DEFTEST1 (short fract, hr)
DEFTEST1 (fract, r)
DEFTEST1 (long fract, lr)
DEFTEST1 (long long fract, llr)
DEFTEST1 (short accum, hk)
DEFTEST1 (accum, k)
DEFTEST1 (long accum, lk)
DEFTEST1 (long long accum, llk)
#define TEST2P(FX, VAL, DD) \
{ \
if (countls##FX (FX##bits (VAL)) != 8 * sizeof (0##FX) - DD) \
abort(); \
\
if (countlsu##FX (u##FX##bits (VAL)) != 8 * sizeof (0u##FX) + 1 - DD) \
abort(); \
}
#define TEST2M(FX, VAL, DD) \
{ \
if (countls##FX (FX##bits (VAL)) != 8 * sizeof (0##FX) - (DD)) \
abort(); \
\
if (countlsu##FX (u##FX##bits (VAL)) != 0) \
abort(); \
}
#define TEST2PX(VAL, DD) \
TEST2P (hr, VAL, DD); \
TEST2P (r, VAL, DD); \
TEST2P (lr, VAL, DD); \
\
TEST2P (hk, VAL, DD); \
TEST2P (k, VAL, DD); \
TEST2P (lk, VAL, DD); \
TEST2P (llk, VAL, DD)
#define TEST2MX(VAL, DD) \
TEST2M (hr, VAL, DD); \
TEST2M (r, VAL, DD); \
TEST2M (lr, VAL, DD); \
\
TEST2M (hk, VAL, DD); \
TEST2M (k, VAL, DD); \
TEST2M (lk, VAL, DD); \
TEST2M (llk, VAL, DD)
int main (void)
{
TEST2PX (1, 2);
TEST2PX (2, 3);
TEST2PX (3, 3);
TEST2MX (-1, 1);
TEST2MX (-2, 2);
TEST2MX (-3, 3);
return 0;
}

View File

@ -1,3 +1,17 @@
2013-02-08 Georg-Johann Lay <avr@gjlay.de>
PR target/54222
* config/avr/lib2funcs.c: New C sources for modules for libgcc.a.
* config/avr/lib2-object.mk: New iterator to build objects from it.
* config/avr/t-avr: Iterate lib2-object.mk to build objects from
lib2funcs.c.
(LIB2FUNCS_EXCLUDE): Add _clrsbdi2.
(LIB1ASMFUNCS): Add: _ssabs_1, _mask1, _ret, _roundqq3, _rounduqq3,
_round_s2, _round_u2, _round_2_const, _addmask_2, _round_s4,
_round_u4, _round_4_const, _addmask_4, _round_x8, _rounddq3
_roundudq3, _roundda3 _rounduda3, _roundta3 _rounduta3.
* config/avr/lib1funcs-fixed.S: Implement them.
2013-02-04 Richard Sandiford <rdsandiford@googlemail.com>
Update copyright years.

View File

@ -957,6 +957,28 @@ ENDF __udivusa3
#undef r_divHH
#undef r_cnt
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Saturation, 1 Byte
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; First Argument and Return Register
#define A0 24
#if defined (L_ssabs_1)
DEFUN __ssabs_1
sbrs A0, 7
ret
neg A0
sbrc A0,7
dec A0
ret
ENDF __ssabs_1
#endif /* L_ssabs_1 */
#undef A0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Saturation, 2 Bytes
@ -1176,3 +1198,509 @@ ENDF __sssub_8
#undef B5
#undef B6
#undef B7
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Rounding Helpers
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#ifdef L_mask1
#define AA 24
#define CC 25
;; R25 = 1 << (R24 & 7)
;; CC = 1 << (AA & 7)
;; Clobbers: None
DEFUN __mask1
;; CC = 2 ^ AA.1
ldi CC, 1 << 2
sbrs AA, 1
ldi CC, 1 << 0
;; CC *= 2 ^ AA.0
sbrc AA, 0
lsl CC
;; CC *= 2 ^ AA.2
sbrc AA, 2
swap CC
ret
ENDF __mask1
#undef AA
#undef CC
#endif /* L_mask1 */
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; The rounding point. Any bits smaller than
;; 2^{-RP} will be cleared.
#define RP R24
#define A0 22
#define A1 A0 + 1
#define C0 24
#define C1 C0 + 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Rounding, 1 Byte
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#ifdef L_roundqq3
;; R24 = round (R22, R24)
;; Clobbers: R22, __tmp_reg__
DEFUN __roundqq3
mov __tmp_reg__, C1
subi RP, __QQ_FBIT__ - 1
neg RP
;; R25 = 1 << RP (Total offset is FBIT-1 - RP)
XCALL __mask1
mov C0, C1
;; Add-Saturate 2^{-RP-1}
add A0, C0
brvc 0f
ldi A0, 0x7f
0: ;; Mask out bits beyond RP
lsl C0
neg C0
and C0, A0
mov C1, __tmp_reg__
ret
ENDF __roundqq3
#endif /* L_roundqq3 */
#ifdef L_rounduqq3
;; R24 = round (R22, R24)
;; Clobbers: R22, __tmp_reg__
DEFUN __rounduqq3
mov __tmp_reg__, C1
subi RP, __UQQ_FBIT__ - 1
neg RP
;; R25 = 1 << RP (Total offset is FBIT-1 - RP)
XCALL __mask1
mov C0, C1
;; Add-Saturate 2^{-RP-1}
add A0, C0
brcc 0f
ldi A0, 0xff
0: ;; Mask out bits beyond RP
lsl C0
neg C0
and C0, A0
mov C1, __tmp_reg__
ret
ENDF __rounduqq3
#endif /* L_rounduqq3 */
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Rounding, 2 Bytes
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#ifdef L_addmask_2
;; [ R25:R24 = 1 << (R24 & 15)
;; R23:R22 += 1 << (R24 & 15) ]
;; SREG is set according to the addition
DEFUN __addmask_2
;; R25 = 1 << (R24 & 7)
XCALL __mask1
cpi RP, 1 << 3
sbc C0, C0
;; Swap C0 and C1 if RP.3 was set
and C0, C1
eor C1, C0
;; Finally, add the power-of-two: A[] += C[]
add A0, C0
adc A1, C1
ret
ENDF __addmask_2
#endif /* L_addmask_2 */
#ifdef L_round_s2
;; R25:R24 = round (R23:R22, R24)
;; Clobbers: R23, R22
DEFUN __roundhq3
subi RP, __HQ_FBIT__ - __HA_FBIT__
ENDF __roundhq3
DEFUN __roundha3
subi RP, __HA_FBIT__ - 1
neg RP
;; [ R25:R24 = 1 << (FBIT-1 - RP)
;; R23:R22 += 1 << (FBIT-1 - RP) ]
XCALL __addmask_2
XJMP __round_s2_const
ENDF __roundha3
#endif /* L_round_s2 */
#ifdef L_round_u2
;; R25:R24 = round (R23:R22, R24)
;; Clobbers: R23, R22
DEFUN __rounduhq3
subi RP, __UHQ_FBIT__ - __UHA_FBIT__
ENDF __rounduhq3
DEFUN __rounduha3
subi RP, __UHA_FBIT__ - 1
neg RP
;; [ R25:R24 = 1 << (FBIT-1 - RP)
;; R23:R22 += 1 << (FBIT-1 - RP) ]
XCALL __addmask_2
XJMP __round_u2_const
ENDF __rounduha3
#endif /* L_round_u2 */
#ifdef L_round_2_const
;; Helpers for 2 byte wide rounding
DEFUN __round_s2_const
brvc 2f
ldi A1, 0x7f
rjmp 1f
;; FALLTHRU (Barrier)
ENDF __round_s2_const
DEFUN __round_u2_const
brcc 2f
ldi A1, 0xff
1:
ldi A0, 0xff
2:
;; Saturation is performed now.
;; Currently, we have C[] = 2^{-RP-1}
;; C[] = 2^{-RP}
lsl C0
rol C1
;;
NEG2 C0
;; Clear the bits beyond the rounding point.
and C0, A0
and C1, A1
ret
ENDF __round_u2_const
#endif /* L_round_2_const */
#undef A0
#undef A1
#undef C0
#undef C1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Rounding, 4 Bytes
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#define A0 18
#define A1 A0 + 1
#define A2 A0 + 2
#define A3 A0 + 3
#define C0 22
#define C1 C0 + 1
#define C2 C0 + 2
#define C3 C0 + 3
#ifdef L_addmask_4
;; [ R25:R22 = 1 << (R24 & 31)
;; R21:R18 += 1 << (R24 & 31) ]
;; SREG is set according to the addition
DEFUN __addmask_4
;; R25 = 1 << (R24 & 7)
XCALL __mask1
cpi RP, 1 << 4
sbc C0, C0
sbc C1, C1
;; Swap C2 with C3 if RP.3 is not set
cpi RP, 1 << 3
sbc C2, C2
and C2, C3
eor C3, C2
;; Swap C3:C2 with C1:C0 if RP.4 is not set
and C0, C2 $ eor C2, C0
and C1, C3 $ eor C3, C1
;; Finally, add the power-of-two: A[] += C[]
add A0, C0
adc A1, C1
adc A2, C2
adc A3, C3
ret
ENDF __addmask_4
#endif /* L_addmask_4 */
#ifdef L_round_s4
;; R25:R22 = round (R21:R18, R24)
;; Clobbers: R18...R21
DEFUN __roundsq3
subi RP, __SQ_FBIT__ - __SA_FBIT__
ENDF __roundsq3
DEFUN __roundsa3
subi RP, __SA_FBIT__ - 1
neg RP
;; [ R25:R22 = 1 << (FBIT-1 - RP)
;; R21:R18 += 1 << (FBIT-1 - RP) ]
XCALL __addmask_4
XJMP __round_s4_const
ENDF __roundsa3
#endif /* L_round_s4 */
#ifdef L_round_u4
;; R25:R22 = round (R21:R18, R24)
;; Clobbers: R18...R21
DEFUN __roundusq3
subi RP, __USQ_FBIT__ - __USA_FBIT__
ENDF __roundusq3
DEFUN __roundusa3
subi RP, __USA_FBIT__ - 1
neg RP
;; [ R25:R22 = 1 << (FBIT-1 - RP)
;; R21:R18 += 1 << (FBIT-1 - RP) ]
XCALL __addmask_4
XJMP __round_u4_const
ENDF __roundusa3
#endif /* L_round_u4 */
#ifdef L_round_4_const
;; Helpers for 4 byte wide rounding
DEFUN __round_s4_const
brvc 2f
ldi A3, 0x7f
rjmp 1f
;; FALLTHRU (Barrier)
ENDF __round_s4_const
DEFUN __round_u4_const
brcc 2f
ldi A3, 0xff
1:
ldi A2, 0xff
ldi A1, 0xff
ldi A0, 0xff
2:
;; Saturation is performed now.
;; Currently, we have C[] = 2^{-RP-1}
;; C[] = 2^{-RP}
lsl C0
rol C1
rol C2
rol C3
XCALL __negsi2
;; Clear the bits beyond the rounding point.
and C0, A0
and C1, A1
and C2, A2
and C3, A3
ret
ENDF __round_u4_const
#endif /* L_round_4_const */
#undef A0
#undef A1
#undef A2
#undef A3
#undef C0
#undef C1
#undef C2
#undef C3
#undef RP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Rounding, 8 Bytes
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#define RP 16
#define FBITm1 31
#define C0 18
#define C1 C0 + 1
#define C2 C0 + 2
#define C3 C0 + 3
#define C4 C0 + 4
#define C5 C0 + 5
#define C6 C0 + 6
#define C7 C0 + 7
#define A0 16
#define A1 17
#define A2 26
#define A3 27
#define A4 28
#define A5 29
#define A6 30
#define A7 31
#ifdef L_rounddq3
;; R25:R18 = round (R25:R18, R16)
;; Clobbers: ABI
DEFUN __rounddq3
ldi FBITm1, __DQ_FBIT__ - 1
clt
XJMP __round_x8
ENDF __rounddq3
#endif /* L_rounddq3 */
#ifdef L_roundudq3
;; R25:R18 = round (R25:R18, R16)
;; Clobbers: ABI
DEFUN __roundudq3
ldi FBITm1, __UDQ_FBIT__ - 1
set
XJMP __round_x8
ENDF __roundudq3
#endif /* L_roundudq3 */
#ifdef L_roundda3
;; R25:R18 = round (R25:R18, R16)
;; Clobbers: ABI
DEFUN __roundda3
ldi FBITm1, __DA_FBIT__ - 1
clt
XJMP __round_x8
ENDF __roundda3
#endif /* L_roundda3 */
#ifdef L_rounduda3
;; R25:R18 = round (R25:R18, R16)
;; Clobbers: ABI
DEFUN __rounduda3
ldi FBITm1, __UDA_FBIT__ - 1
set
XJMP __round_x8
ENDF __rounduda3
#endif /* L_rounduda3 */
#ifdef L_roundta3
;; R25:R18 = round (R25:R18, R16)
;; Clobbers: ABI
DEFUN __roundta3
ldi FBITm1, __TA_FBIT__ - 1
clt
XJMP __round_x8
ENDF __roundta3
#endif /* L_roundta3 */
#ifdef L_rounduta3
;; R25:R18 = round (R25:R18, R16)
;; Clobbers: ABI
DEFUN __rounduta3
ldi FBITm1, __UTA_FBIT__ - 1
set
XJMP __round_x8
ENDF __rounduta3
#endif /* L_rounduta3 */
#ifdef L_round_x8
DEFUN __round_x8
push r16
push r17
push r28
push r29
;; Compute log2 of addend from rounding point
sub RP, FBITm1
neg RP
;; Move input to work register A[]
push C0
mov A1, C1
wmov A2, C2
wmov A4, C4
wmov A6, C6
;; C[] = 1 << (FBIT-1 - RP)
XCALL __clr_8
inc C0
XCALL __ashldi3
pop A0
;; A[] += C[]
add A0, C0
adc A1, C1
adc A2, C2
adc A3, C3
adc A4, C4
adc A5, C5
adc A6, C6
adc A7, C7
brts 1f
;; Signed
brvc 3f
;; Signed overflow: A[] = 0x7f...
brvs 2f
1: ;; Unsigned
brcc 3f
;; Unsigned overflow: A[] = 0xff...
2: ldi A7, 0xff
ldi A6, 0xff
wmov A0, A6
wmov A2, A6
wmov A4, A6
bld A7, 7
3:
;; C[] = -C[] - C[]
push A0
ldi r16, 1
XCALL __ashldi3
pop A0
XCALL __negdi2
;; Clear the bits beyond the rounding point.
and C0, A0
and C1, A1
and C2, A2
and C3, A3
and C4, A4
and C5, A5
and C6, A6
and C7, A7
;; Epilogue
pop r29
pop r28
pop r17
pop r16
ret
ENDF __round_x8
#endif /* L_round_x8 */
#undef A0
#undef A1
#undef A2
#undef A3
#undef A4
#undef A5
#undef A6
#undef A7
#undef C0
#undef C1
#undef C2
#undef C3
#undef C4
#undef C5
#undef C6
#undef C7
#undef RP
#undef FBITm1
;; Supply implementations / symbols for the bit-banging functions
;; __builtin_avr_bitsfx and __builtin_avr_fxbits
#ifdef L_ret
DEFUN __ret
ret
ENDF __ret
#endif /* L_ret */

View File

@ -1684,12 +1684,12 @@ DEFUN __divdi3_moddi3
ENDF __divdi3_moddi3
#endif /* L_divdi3 */
#undef R_cnt
#undef SS
#undef NN
#endif /* L_divdi3 */
.section .text.libgcc, "ax", @progbits
#define TT __tmp_reg__

View File

@ -0,0 +1,23 @@
# This file is included several times in a row, once for each element of
# $(iter-items). On each inclusion, we advance $o to the next element.
# $(iter-labels) and $(iter-flags) are also advanced.
# This works similar to $(srcdir)/siditi-object.mk.
o := $(firstword $(iter-items))
iter-items := $(filter-out $o,$(iter-items))
$o-label := $(firstword $(iter-labels))
iter-labels := $(wordlist 2,$(words $(iter-labels)),$(iter-labels))
$o-flag := $(firstword $(iter-flags))
iter-flags := $(wordlist 2,$(words $(iter-flags)),$(iter-flags))
$o$(objext): %$(objext): $(srcdir)/config/avr/lib2funcs.c
$(gcc_compile) -DL_$($*-label) -DL_LABEL=$($*-label) $($*-flag) \
-c $< $(vis_hide)
ifeq ($(enable_shared),yes)
$(o)_s$(objext): %_s$(objext): $(srcdir)/config/avr/lib2funcs.c
$(gcc_s_compile) -DL_$($*-label) -DL_LABEL=$($*-label) $($*-flag) \
-c $<
endif

View File

@ -0,0 +1,226 @@
/* Copyright (C) 2013 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.
You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
/* This file supplies implementations for some AVR-specific builtin
functions so that code like the following works as expected:
int (*f (void))(_Fract)
{
return __builtin_avr_countlsr;
}
In this specific case, the generated code is:
f:
ldi r24,lo8(gs(__countlsHI))
ldi r25,hi8(gs(__countlsHI))
ret
*/
/* Map fixed-point suffix to the corresponding fixed-point type. */
typedef short _Fract fx_hr_t;
typedef _Fract fx_r_t;
typedef long _Fract fx_lr_t;
typedef long long _Fract fx_llr_t;
typedef unsigned short _Fract fx_uhr_t;
typedef unsigned _Fract fx_ur_t;
typedef unsigned long _Fract fx_ulr_t;
typedef unsigned long long _Fract fx_ullr_t;
typedef short _Accum fx_hk_t;
typedef _Accum fx_k_t;
typedef long _Accum fx_lk_t;
typedef long long _Accum fx_llk_t;
typedef unsigned short _Accum fx_uhk_t;
typedef unsigned _Accum fx_uk_t;
typedef unsigned long _Accum fx_ulk_t;
typedef unsigned long long _Accum fx_ullk_t;
/* Map fixed-point suffix to the corresponding natural integer type. */
typedef char int_hr_t;
typedef int int_r_t;
typedef long int_lr_t;
typedef long long int_llr_t;
typedef unsigned char int_uhr_t;
typedef unsigned int int_ur_t;
typedef unsigned long int_ulr_t;
typedef unsigned long long int_ullr_t;
typedef int int_hk_t;
typedef long int_k_t;
typedef long long int_lk_t;
typedef long long int_llk_t;
typedef unsigned int int_uhk_t;
typedef unsigned long int_uk_t;
typedef unsigned long long int_ulk_t;
typedef unsigned long long int_ullk_t;
/* Map mode to the corresponding integer type. */
typedef char int_qi_t;
typedef int int_hi_t;
typedef long int_si_t;
typedef long long int_di_t;
typedef unsigned char uint_qi_t;
typedef unsigned int uint_hi_t;
typedef unsigned long uint_si_t;
typedef unsigned long long uint_di_t;
/************************************************************************/
/* Supply implementations / symbols for __builtin_roundFX ASM_NAME. */
#ifdef L_round
#define ROUND1(FX) \
ROUND2 (FX)
#define ROUND2(FX) \
extern fx_## FX ##_t __round## FX (fx_## FX ##_t x, int rpoint); \
\
fx_## FX ##_t \
__round## FX (fx_## FX ##_t x, int rpoint) \
{ \
return __builtin_avr_round ##FX (x, rpoint); \
}
ROUND1(L_LABEL)
#endif /* L_round */
/*********************************************************************/
/* Implement some count-leading-redundant-sign-bits to be used with
coundlsFX implementation. */
#ifdef L__clrsbqi
extern int __clrsbqi2 (char x);
int
__clrsbqi2 (char x)
{
int ret;
if (x < 0)
x = ~x;
if (x == 0)
return 8 * sizeof (x) -1;
ret = __builtin_clz (x << 8);
return ret - 1;
}
#endif /* L__clrsbqi */
#ifdef L__clrsbdi
extern int __clrsbdi2 (long long x);
int
__clrsbdi2 (long long x)
{
int ret;
if (x < 0LL)
x = ~x;
if (x == 0LL)
return 8 * sizeof (x) -1;
ret = __builtin_clzll ((unsigned long long) x);
return ret - 1;
}
#endif /* L__clrsbdi */
/*********************************************************************/
/* Supply implementations / symbols for __builtin_avr_countlsFX. */
/* Signed */
#ifdef L_countls
#define COUNTLS1(MM) \
COUNTLS2 (MM)
#define COUNTLS2(MM) \
extern int __countls## MM ##2 (int_## MM ##_t); \
extern int __clrsb## MM ##2 (int_## MM ##_t); \
\
int \
__countls## MM ##2 (int_## MM ##_t x) \
{ \
if (x == 0) \
return __INT8_MAX__; \
\
return __clrsb## MM ##2 (x); \
}
COUNTLS1(L_LABEL)
#endif /* L_countls */
/* Unsigned */
#ifdef L_countlsu
#define clz_qi2 __builtin_clz /* unused, avoid warning */
#define clz_hi2 __builtin_clz
#define clz_si2 __builtin_clzl
#define clz_di2 __builtin_clzll
#define COUNTLS1(MM) \
COUNTLS2 (MM)
#define COUNTLS2(MM) \
extern int __countlsu## MM ##2 (uint_## MM ##_t); \
\
int \
__countlsu## MM ##2 (uint_## MM ##_t x) \
{ \
if (x == 0) \
return __INT8_MAX__; \
\
if (sizeof (x) == 1) \
return clz_hi2 (x << 8); \
else \
return clz_## MM ##2 (x); \
}
COUNTLS1(L_LABEL)
#endif /* L_countlsu */

View File

@ -75,13 +75,24 @@ LIB1ASMFUNCS += \
_divsa3 _udivusa3 \
_clr_8 \
_ssneg_2 _ssneg_4 _ssneg_8 \
_ssabs_2 _ssabs_4 _ssabs_8 \
_ssabs_1 _ssabs_2 _ssabs_4 _ssabs_8 \
_ssadd_8 _sssub_8 \
_usadd_8 _ussub_8
_usadd_8 _ussub_8 \
_mask1 _ret \
_roundqq3 _rounduqq3 \
_round_s2 _round_u2 _round_2_const _addmask_2 \
_round_s4 _round_u4 _round_4_const _addmask_4 \
_round_x8 \
_rounddq3 _roundudq3 \
_roundda3 _rounduda3 \
_roundta3 _rounduta3 \
LIB2FUNCS_EXCLUDE = \
_moddi3 _umoddi3 \
_clz
_clz \
_clrsbdi2 \
# We do not have the DF type.
# Most of the C functions in libgcc2 use almost all registers,
@ -106,13 +117,84 @@ ifeq ($(enable_shared),yes)
libgcc-s-objects += $(patsubst %,%_s$(objext),$(hiintfuncs16))
endif
# Filter out supported conversions from fixed-bit.c
# Also filter out TQ and UTQ.
###
conv_XY=$(conv)$(mode1)$(mode2)
func_X=$(func)$(mode)
# Compile C functions from lib2funcs.c and add them to libgcc.a.
#
# Some functions which are not performance.critical are more convenient
# to implement in C than in assembler. Most of them serve as implementation
# for AVR-specific builtins in the case where the address of a builtin
# function is taken or if there is no insn that implements the builtin.
#
# We don't use LIB2ADD because we want to iterate over the source for
# different modes, fixed-point suffixes, etc. See iter-labels and L_LABEL.
# iter-label will get one more underscore in order to avoid too short
# labels like -DLk and we use -DL_k instead.
# Build roundFX functions from lib2funcs.c
round_suffix := hr r lr uhr ur ulr \
hk k uhk uk
round_funcs := $(foreach func,_round,\
$(foreach mode,$(round_suffix),$(func_X)))
iter-items := $(round_funcs)
iter-labels := $(round_suffix)
iter-flags := $(patsubst %,-DL_round,$(iter-items))
include $(srcdir)/empty.mk $(patsubst %,$(srcdir)/config/avr/lib2-object.mk,$(iter-items))
libgcc-objects += $(patsubst %,%$(objext),$(round_funcs))
# Build clrsbXX functions from lib2funcs.c
clrsb_modes := qi di
clrsb_funcs := $(foreach func,_clrsb,\
$(foreach mode,$(clrsb_modes),$(func_X)))
iter-items := $(clrsb_funcs)
iter-labels := $(clrsb_funcs)
iter-flags := $(patsubst %,-DL_clrsb,$(iter-items))
include $(srcdir)/empty.mk $(patsubst %,$(srcdir)/config/avr/lib2-object.mk,$(iter-items))
libgcc-objects += $(patsubst %,%$(objext),$(clrsb_funcs))
# Build signed countlsFX functions from lib2funcs.c
countls_modes := qi hi si di
countls_funcs := $(foreach func,_countls,\
$(foreach mode,$(countls_modes),$(func_X)))
iter-items := $(countls_funcs)
iter-labels := $(countls_modes)
iter-flags := $(patsubst %,-DL_countls,$(iter-items))
include $(srcdir)/empty.mk $(patsubst %,$(srcdir)/config/avr/lib2-object.mk,$(iter-items))
libgcc-objects += $(patsubst %,%$(objext),$(countls_funcs))
# Build unsigned countlsFX functions from lib2funcs.c
countlsu_modes := qi hi si di
countlsu_funcs := $(foreach func,_countlsu,\
$(foreach mode,$(countlsu_modes),$(func_X)))
iter-items := $(countlsu_funcs)
iter-labels := $(countlsu_modes)
iter-flags := $(patsubst %,-DL_countlsu,$(iter-items))
include $(srcdir)/empty.mk $(patsubst %,$(srcdir)/config/avr/lib2-object.mk,$(iter-items))
libgcc-objects += $(patsubst %,%$(objext),$(countlsu_funcs))
# Filter out supported conversions from fixed-bit.c
# Also filter out TQ and UTQ.
# Conversions supported by the compiler
convf_modes = QI UQI QQ UQQ \