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:
parent
661bc682bc
commit
85d768f349
@ -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
|
||||
|
@ -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 (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)
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
161
gcc/testsuite/gcc.target/avr/torture/builtins-4-roundfx.c
Normal file
161
gcc/testsuite/gcc.target/avr/torture/builtins-4-roundfx.c
Normal 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;
|
||||
}
|
||||
|
82
gcc/testsuite/gcc.target/avr/torture/builtins-5-countlsfx.c
Normal file
82
gcc/testsuite/gcc.target/avr/torture/builtins-5-countlsfx.c
Normal 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;
|
||||
}
|
@ -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.
|
||||
|
@ -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 */
|
||||
|
@ -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__
|
||||
|
23
libgcc/config/avr/lib2-object.mk
Normal file
23
libgcc/config/avr/lib2-object.mk
Normal 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
|
226
libgcc/config/avr/lib2funcs.c
Normal file
226
libgcc/config/avr/lib2funcs.c
Normal 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 */
|
@ -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 \
|
||||
|
Loading…
Reference in New Issue
Block a user