Commit 85d768f3 by Georg-Johann Lay Committed by Georg-Johann Lay

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
parent 661bc682
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
......
......@@ -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;
}
......
......@@ -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")])
......@@ -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];
......
......@@ -68,6 +68,7 @@
UNSPEC_COPYSIGN
UNSPEC_IDENTITY
UNSPEC_INSERT_BITS
UNSPEC_ROUND
])
(define_c_enum "unspecv"
......
......@@ -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 (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 (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, "__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)
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
......
/* { 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;
}
/* { 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;
}
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.
......
......@@ -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__
......
# 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
/* 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 */
......@@ -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 \
......
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