From 85d768f349087f3766ff84054ec7b3403c52ac7a Mon Sep 17 00:00:00 2001 From: Georg-Johann Lay Date: Fri, 8 Feb 2013 10:13:37 +0000 Subject: [PATCH] re PR target/54222 ([avr] Implement fixed-point support) gcc/ PR target/54222 * config/avr/avr.md (unspec) : Add. * config/avr/avr-fixed.md (ALL4QA, ALL124QA): New mode iterators. (round3, round3_const): New expanders for fixed-mode. (*round3.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) : Sanity-check them. (avr_fold_builtin) : Fold to VIEW_COVERT_EXPR. : 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 --- gcc/ChangeLog | 26 + gcc/config/avr/avr-c.c | 218 +++++++++ gcc/config/avr/avr-fixed.md | 138 +++++- gcc/config/avr/avr.c | 204 +++++++- gcc/config/avr/avr.md | 1 + gcc/config/avr/builtins.def | 115 ++++- gcc/config/avr/stdfix.h | 477 ++++++------------- gcc/testsuite/ChangeLog | 6 + .../gcc.target/avr/torture/builtins-4-roundfx.c | 161 +++++++ .../gcc.target/avr/torture/builtins-5-countlsfx.c | 82 ++++ libgcc/ChangeLog | 14 + libgcc/config/avr/lib1funcs-fixed.S | 528 +++++++++++++++++++++ libgcc/config/avr/lib1funcs.S | 4 +- libgcc/config/avr/lib2-object.mk | 23 + libgcc/config/avr/lib2funcs.c | 226 +++++++++ libgcc/config/avr/t-avr | 94 +++- 16 files changed, 1931 insertions(+), 386 deletions(-) create mode 100644 gcc/testsuite/gcc.target/avr/torture/builtins-4-roundfx.c create mode 100644 gcc/testsuite/gcc.target/avr/torture/builtins-5-countlsfx.c create mode 100644 libgcc/config/avr/lib2-object.mk create mode 100644 libgcc/config/avr/lib2funcs.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 787efb7..38173e9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,29 @@ +2013-02-08 Georg-Johann Lay + + PR target/54222 + * config/avr/avr.md (unspec) : Add. + * config/avr/avr-fixed.md (ALL4QA, ALL124QA): New mode iterators. + (round3, round3_const): New expanders for fixed-mode. + (*round3.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) : Sanity-check them. + (avr_fold_builtin) : Fold to VIEW_COVERT_EXPR. + : Same. + 2013-02-08 Richard Biener * cfgloop.c (verify_loop_structure): Properly handle diff --git a/gcc/config/avr/avr-c.c b/gcc/config/avr/avr-c.c index ddcab54..4e64405 100644 --- a/gcc/config/avr/avr-c.c +++ b/gcc/config/avr/avr-c.c @@ -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 &args = * (vec*) 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; } diff --git a/gcc/config/avr/avr-fixed.md b/gcc/config/avr/avr-fixed.md index ce7f54d..7d9b525 100644 --- a/gcc/config/avr/avr-fixed.md +++ b/gcc/config/avr/avr-fixed.md @@ -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 __3" [(set_attr "type" "xcall") (set_attr "cc" "clobber")]) + + +;****************************************************************************** +;** Rounding +;****************************************************************************** + +;; "roundqq3" "rounduqq3" +;; "roundhq3" "rounduhq3" "roundha3" "rounduha3" +;; "roundsq3" "roundusq3" "roundsa3" "roundusa3" +(define_expand "round3" + [(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))) + { + emit_insn (gen_round3_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, regno_out[(size_t) GET_MODE_SIZE (mode)]); + operands[4] = gen_rtx_REG (mode, regno_in[(size_t) GET_MODE_SIZE (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 "round3_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); + int fbit = (int) GET_MODE_FBIT (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); + + if (SIGNED_FIXED_POINT_MODE_P (mode)) + emit_move_insn (operands[0], + gen_rtx_SS_PLUS (mode, operands[1], x_add)); + else + emit_move_insn (operands[0], + gen_rtx_US_PLUS (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, 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 "*round3.libgcc" + [(set (reg:ALL1Q 24) + (unspec:ALL1Q [(reg:ALL1Q 22) + (reg:QI 24)] UNSPEC_ROUND)) + (clobber (reg:ALL1Q 22))] + "" + "%~call __round3" + [(set_attr "type" "xcall") + (set_attr "cc" "clobber")]) + +;; "*roundhq3.libgcc" "*rounduhq3.libgcc" +;; "*roundha3.libgcc" "*rounduha3.libgcc" +(define_insn "*round3.libgcc" + [(set (reg:ALL2QA 24) + (unspec:ALL2QA [(reg:ALL2QA 22) + (reg:QI 24)] UNSPEC_ROUND)) + (clobber (reg:ALL2QA 22))] + "" + "%~call __round3" + [(set_attr "type" "xcall") + (set_attr "cc" "clobber")]) + +;; "*roundsq3.libgcc" "*roundusq3.libgcc" +;; "*roundsa3.libgcc" "*roundusa3.libgcc" +(define_insn "*round3.libgcc" + [(set (reg:ALL4QA 22) + (unspec:ALL4QA [(reg:ALL4QA 18) + (reg:QI 24)] UNSPEC_ROUND)) + (clobber (reg:ALL4QA 18))] + "" + "%~call __round3" + [(set_attr "type" "xcall") + (set_attr "cc" "clobber")]) diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index c833bfb..0f1d2c1 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -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]; diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index 6432d63..e9f5d03 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -68,6 +68,7 @@ UNSPEC_COPYSIGN UNSPEC_IDENTITY UNSPEC_INSERT_BITS + UNSPEC_ROUND ]) (define_c_enum "unspecv" diff --git a/gcc/config/avr/builtins.def b/gcc/config/avr/builtins.def index ecce186..ce444ab 100644 --- a/gcc/config/avr/builtins.def +++ b/gcc/config/avr/builtins.def @@ -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) diff --git a/gcc/config/avr/stdfix.h b/gcc/config/avr/stdfix.h index b86195a..afcacdf 100644 --- a/gcc/config/avr/stdfix.h +++ b/gcc/config/avr/stdfix.h @@ -35,10 +35,6 @@ #include -#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 The fixed-point intrinsic functions. */ -/* 7.18a.6.2 The fixed-point absolute value functions. */ +/* 7.18a.6.2 The fixed-point absolute value functions. */ + +#define abshr __builtin_avr_abshr +#define absr __builtin_avr_absr +#define abslr __builtin_avr_abslr + +#define abshk __builtin_avr_abshk +#define absk __builtin_avr_absk + +#if __SIZEOF_INT__ == 2 + +#define abslk __builtin_avr_abslk +#define absllr __builtin_avr_absllr /* GCC Extension */ +#define absllk __builtin_avr_absllk /* GCC Extension */ -/* short fract (hr): abshr */ +#endif /* sizeof (int) == 2 */ -static __inline__ __attribute__((__always_inline__)) -short fract abshr (const short fract __q) -{ - return __builtin_avr_abshr (__q); -} -/* fract (r): absr */ +/* 7.18a.6.3 The fixed-point round functions. */ -static __inline__ __attribute__((__always_inline__)) -fract absr (const fract __q) -{ - return __builtin_avr_absr (__q); -} +/* The Embedded-C paper specifies results only for rounding points -/* long fract (lr): abslr */ + 0 < RP < FBIT + + As an extension, the following functions work as expected + with rounding points -static __inline__ __attribute__((__always_inline__)) -long fract abslr (const long fract __q) -{ - return __builtin_avr_abslr (__q); -} + -IBIT < RP < FBIT + + For example, rounding an accum with a rounding point of -1 will + result in an even integer value. */ -/* short accum (hk): abshk */ +#define roundhr __builtin_avr_roundhr +#define roundr __builtin_avr_roundr +#define roundlr __builtin_avr_roundlr -static __inline__ __attribute__((__always_inline__)) -short accum abshk (const short accum __q) -{ - return __builtin_avr_abshk (__q); -} +#define rounduhr __builtin_avr_rounduhr +#define roundur __builtin_avr_roundur +#define roundulr __builtin_avr_roundulr -/* accum (k): absk */ +#define roundhk __builtin_avr_roundhk +#define roundk __builtin_avr_roundk -static __inline__ __attribute__((__always_inline__)) -accum absk (const accum __q) -{ - return __builtin_avr_absk (__q); -} +#define rounduhk __builtin_avr_rounduhk +#define rounduk __builtin_avr_rounduk #if __SIZEOF_INT__ == 2 -/* long long fract (llr): absllr */ - -static __inline__ __attribute__((__always_inline__)) -long long fract absllr (const long long fract __q) /* GCC extension */ -{ - return __builtin_avr_absllr (__q); -} - -/* long accum (lk): abslk */ - -static __inline__ __attribute__((__always_inline__)) -long accum abslk (const long accum __q) -{ - return __builtin_avr_abslk (__q); -} - -/* long long accum (llk): absllk */ - -static __inline__ __attribute__((__always_inline__)) -long long accum absllk (const long long accum __q) /* GCC extension */ -{ - return __builtin_avr_absllk (__q); -} - -#endif /* __SIZEOF_INT__ == 2 */ - - -/* 7.18a.6.5 The bitwise fixed-point to integer conversion functions. */ -/* 7.18a.6.6 The bitwise integer to fixed-point conversion functions. */ - -/* short fract (hr): bitshr, bitsuhr, hrbits, uhrbits */ - -static __inline__ __attribute__((__always_inline__)) -int_hr_t bitshr (const short fract __q) -{ - int_hr_t __result; - _GCC_TYPEPUN (__result, __q); - return __result; -} - -static __inline__ __attribute__((__always_inline__)) -uint_uhr_t bitsuhr (const unsigned short fract __q) -{ - uint_uhr_t __result; - _GCC_TYPEPUN (__result, __q); - return __result; -} - -static __inline__ __attribute__((__always_inline__)) -short fract hrbits (const int_hr_t __i) -{ - short fract __result; - _GCC_TYPEPUN (__result, __i); - return __result; -} - -static __inline__ __attribute__((__always_inline__)) -unsigned short fract uhrbits (const uint_uhr_t __i) -{ - unsigned short fract __result; - _GCC_TYPEPUN (__result, __i); - return __result; -} - -/* fract (r): bitsr, bitsur, rbits, urbits */ - -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 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 */ + +#endif /* sizeof (int) == 2 */ + + +/* 7.18a.6.4 The fixed-point bit countls functions. */ + +#define countlshr __builtin_avr_countlshr +#define countlsr __builtin_avr_countlsr +#define countlslr __builtin_avr_countlslr + +#define countlsuhr __builtin_avr_countlsuhr +#define countlsur __builtin_avr_countlsur +#define countlsulr __builtin_avr_countlsulr + +#define countlshk __builtin_avr_countlshk +#define countlsk __builtin_avr_countlsk + +#define countlsuhk __builtin_avr_countlsuhk +#define countlsuk __builtin_avr_countlsuk #if __SIZEOF_INT__ == 2 -/* long long fract (llr): bitsllr, bitsullr, llrbits, ullrbits */ - -static __inline__ __attribute__((__always_inline__)) -int_llr_t bitsllr (const long long fract __q) -{ - int_llr_t __result; - _GCC_TYPEPUN (__result, __q); - return __result; -} - -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; -} - -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; -} - -/* long accum (lk): bitslk, bitsulk, lkbits, ulkbits */ - -static __inline__ __attribute__((__always_inline__)) -int_lk_t bitslk (const long accum __q) -{ - int_lk_t __result; - _GCC_TYPEPUN (__result, __q); - return __result; -} - -static __inline__ __attribute__((__always_inline__)) -uint_ulk_t bitsulk (const unsigned long accum __q) -{ - uint_ulk_t __result; - _GCC_TYPEPUN (__result, __q); - return __result; -} - -static __inline__ __attribute__((__always_inline__)) -long accum lkbits (const int_lk_t __i) -{ - long accum __result; - _GCC_TYPEPUN (__result, __i); - return __result; -} - -static __inline__ __attribute__((__always_inline__)) -unsigned long accum ulkbits (const uint_ulk_t __i) -{ - unsigned long accum __result; - _GCC_TYPEPUN (__result, __i); - return __result; -} - -/* long long accum (llk): bitsllk, bitsullk, llkbits, ullkbits */ - -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; -} - -static __inline__ __attribute__((__always_inline__)) -long long accum llkbits (const int_llk_t __i) -{ - long long accum __result; - _GCC_TYPEPUN (__result, __i); - return __result; -} - -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; -} - -#endif /* __SIZEOF_INT__ == 2 */ +#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 */ + +#endif /* sizeof (int) == 2 */ + + +/* 7.18a.6.5 The bitwise fixed-point to integer conversion functions. */ + +#define bitshr __builtin_avr_bitshr +#define bitsr __builtin_avr_bitsr +#define bitslr __builtin_avr_bitslr + +#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 /* _AVRGCC_STDFIX_H */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c8ce975..c12303d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2013-02-08 Georg-Johann Lay + + 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 PR c++/56241 diff --git a/gcc/testsuite/gcc.target/avr/torture/builtins-4-roundfx.c b/gcc/testsuite/gcc.target/avr/torture/builtins-4-roundfx.c new file mode 100644 index 0000000..6ad0775 --- /dev/null +++ b/gcc/testsuite/gcc.target/avr/torture/builtins-4-roundfx.c @@ -0,0 +1,161 @@ +/* { dg-options "-std=gnu99" } */ +/* { dg-do run } */ + +#include + +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; +} + diff --git a/gcc/testsuite/gcc.target/avr/torture/builtins-5-countlsfx.c b/gcc/testsuite/gcc.target/avr/torture/builtins-5-countlsfx.c new file mode 100644 index 0000000..b0ff5e3 --- /dev/null +++ b/gcc/testsuite/gcc.target/avr/torture/builtins-5-countlsfx.c @@ -0,0 +1,82 @@ +/* { dg-options "-std=gnu99" } */ +/* { dg-do run } */ + +#include + +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; +} diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index ed8c0a1..13fc01d 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,17 @@ +2013-02-08 Georg-Johann Lay + + 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 Update copyright years. diff --git a/libgcc/config/avr/lib1funcs-fixed.S b/libgcc/config/avr/lib1funcs-fixed.S index 731da44..92d8eaf 100644 --- a/libgcc/config/avr/lib1funcs-fixed.S +++ b/libgcc/config/avr/lib1funcs-fixed.S @@ -959,6 +959,28 @@ ENDF __udivusa3 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; 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 */ diff --git a/libgcc/config/avr/lib1funcs.S b/libgcc/config/avr/lib1funcs.S index 9ca83a8..0a406d5 100644 --- a/libgcc/config/avr/lib1funcs.S +++ b/libgcc/config/avr/lib1funcs.S @@ -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__ diff --git a/libgcc/config/avr/lib2-object.mk b/libgcc/config/avr/lib2-object.mk new file mode 100644 index 0000000..6a9e04d --- /dev/null +++ b/libgcc/config/avr/lib2-object.mk @@ -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 diff --git a/libgcc/config/avr/lib2funcs.c b/libgcc/config/avr/lib2funcs.c new file mode 100644 index 0000000..83f2e23 --- /dev/null +++ b/libgcc/config/avr/lib2funcs.c @@ -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 + . */ + + +/* 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 */ diff --git a/libgcc/config/avr/t-avr b/libgcc/config/avr/t-avr index 3bc0718..a4b8113e 100644 --- a/libgcc/config/avr/t-avr +++ b/libgcc/config/avr/t-avr @@ -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 \ -- 2.7.4