From patchwork Thu Feb 7 16:42:43 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Georg-Johann Lay X-Patchwork-Id: 218953 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id E39CC2C0085 for ; Fri, 8 Feb 2013 03:43:41 +1100 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1360860222; h=Comment: DomainKey-Signature:Received:Received:Received:Received: Message-ID:Date:From:User-Agent:MIME-Version:To:CC:Subject: Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:Sender:Delivered-To; bh=+KVl/WM +5nKcje66nwYVW5hqlWk=; b=WkwPmxwU62bIT6sio0Ys4DJzZGLO+kRquSdQ/fc PZ40MYOJQy0tA0TisN5YXRkp38VLmS+uVbmUL6ojkhruAmhzKgZ10TG8aNl6o7+s MZ9YAOceCsnXqTNJoTgBK0jQZjza+QG0m/d5qgqKwAqyPfBWTHDUYEZFcMNDEDsM 9Pic= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:X-RZG-AUTH:X-RZG-CLASS-ID:Received:Message-ID:Date:From:User-Agent:MIME-Version:To:CC:Subject:Content-Type:X-IsSubscribed:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=jUY1RMa2MXOfUYulfrwQzOui6HbQQ/5LJXuopdhfPlbtt+2dN8bNe/BUJ7NNjU vxwjQRo/+mitY32NJ4003AdQzzhIO6BSWklKTMaY7KBGx8WJLBZp8dXRbGCiTBW1 ee7ov0N2gc+Nx3fid+lIGA63z/A/P7OeJuG49xZvCBtLc=; Received: (qmail 9302 invoked by alias); 7 Feb 2013 16:43:24 -0000 Received: (qmail 9133 invoked by uid 22791); 7 Feb 2013 16:43:21 -0000 X-SWARE-Spam-Status: No, hits=-0.9 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_NONE, TW_BQ, TW_CL, TW_DD, TW_DF, TW_DH, TW_DL, TW_DQ, TW_FX, TW_HK, TW_NV, TW_RJ, TW_RV, TW_SB, TW_SL, TW_TD, TW_UH, TW_UQ, TW_XF X-Spam-Check-By: sourceware.org Received: from mo-p00-ob.rzone.de (HELO mo-p00-ob.rzone.de) (81.169.146.162) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 07 Feb 2013 16:42:51 +0000 X-RZG-AUTH: :LXoWVUeid/7A29J/hMvvT2k715jHQaJercGObUOFkj18odoYNahU4Q== X-RZG-CLASS-ID: mo00 Received: from [192.168.0.22] (business-188-111-022-002.static.arcor-ip.net [188.111.22.2]) by smtp.strato.de (josoe mo26) (RZmta 31.14 AUTH) with ESMTPA id t01ebep17GebM6 ; Thu, 7 Feb 2013 17:42:43 +0100 (CET) Message-ID: <5113D983.2000002@gjlay.de> Date: Thu, 07 Feb 2013 17:42:43 +0100 From: Georg-Johann Lay User-Agent: Thunderbird 2.0.0.24 (X11/20100302) MIME-Version: 1.0 To: gcc-patches@gcc.gnu.org CC: Denis Chertykov , Eric Weddington Subject: [Patch,avr] Ad PR 54222: Add roundfx, countlsfx to stdfix.h X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org This patch adds more fixed-point features from embedded-C: - roundfx rounding functions - countlsfx bit counting functions - add implementations of builtins so that an implementation / symbol is available when the address of such a function is taken The stdfix.h header is cleaned up and just contains defines that map the available embedded-C functions to their builtin like #define roundr __builtin_avr_roundr Reasoning is 1) Is is possible to take the address of roundr 2) Some builtins might print diagnostics. If the functions in stdfix.h were implemented as inline functions, the diagnose will point to the implementation in stdfix.h but not to the used code that uses the builtin with odd values. I found no way to get the location of the argument; EXPR_LOCATION won't work, and emitting a warning during built-in folding will show at locations more or less randomly distributed (depending on pass) around the correct location... The type-generic functions are implemented by overloading them. A new, avr-specific C source is added to libgcc that is used to compile objects to be added to libgcc.a. The objects are compiled by iterating over the source, which is not possible with LIB2ADD. That is: With LIB2ADD, there would be a bunch of new C modules, one for each function. The new iteration scheme is similar to iterating over libgcc sources like lib1funcs.S, fp-bit.c, fixed-bit.c, etc. The new test cases pass but they need the following patch to work correctly: http://gcc.gnu.org/ml/gcc-patches/2013-02/msg00313.html This is pending review. Ok for trunk? Johann 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. Index: gcc/config/avr/avr-fixed.md =================================================================== --- gcc/config/avr/avr-fixed.md (revision 195736) +++ gcc/config/avr/avr-fixed.md (working copy) @@ -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 @@ (define_insn "*3.call" "%~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")]) Index: gcc/config/avr/builtins.def =================================================================== --- gcc/config/avr/builtins.def (revision 195736) +++ gcc/config/avr/builtins.def (working copy) @@ -61,12 +61,109 @@ DEF_BUILTIN (FLASH_SEGMENT, 1, char_ftyp /* 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) Index: gcc/config/avr/stdfix.h =================================================================== --- gcc/config/avr/stdfix.h (revision 195736) +++ gcc/config/avr/stdfix.h (working copy) @@ -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_ 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_ 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. */ + +#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 */ + +#endif /* sizeof (int) == 2 */ + + +/* 7.18a.6.3 The fixed-point round functions. */ + +/* The Embedded-C paper specifies results only for rounding points + + 0 < RP < FBIT + + As an extension, the following functions work as expected + with rounding points + + -IBIT < RP < FBIT + + For example, rounding an accum with a rounding point of -1 will + result in an even integer value. */ + +#define roundhr __builtin_avr_roundhr +#define roundr __builtin_avr_roundr +#define roundlr __builtin_avr_roundlr +#define rounduhr __builtin_avr_rounduhr +#define roundur __builtin_avr_roundur +#define roundulr __builtin_avr_roundulr -/* 7.18a.6.2 The fixed-point absolute value functions. */ +#define roundhk __builtin_avr_roundhk +#define roundk __builtin_avr_roundk -/* short fract (hr): abshr */ +#define rounduhk __builtin_avr_rounduhk +#define rounduk __builtin_avr_rounduk -static __inline__ __attribute__((__always_inline__)) -short fract abshr (const short fract __q) -{ - return __builtin_avr_abshr (__q); -} +#if __SIZEOF_INT__ == 2 + +#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 -/* fract (r): absr */ +#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 */ -static __inline__ __attribute__((__always_inline__)) -fract absr (const fract __q) -{ - return __builtin_avr_absr (__q); -} +#endif /* sizeof (int) == 2 */ -/* long fract (lr): abslr */ -static __inline__ __attribute__((__always_inline__)) -long fract abslr (const long fract __q) -{ - return __builtin_avr_abslr (__q); -} +/* 7.18a.6.5 The bitwise fixed-point to integer conversion functions. */ -/* short accum (hk): abshk */ +#define bitshr __builtin_avr_bitshr +#define bitsr __builtin_avr_bitsr +#define bitslr __builtin_avr_bitslr -static __inline__ __attribute__((__always_inline__)) -short accum abshk (const short accum __q) -{ - return __builtin_avr_abshk (__q); -} +#define bitsuhr __builtin_avr_bitsuhr +#define bitsur __builtin_avr_bitsur +#define bitsulr __builtin_avr_bitsulr -/* accum (k): absk */ +#define bitshk __builtin_avr_bitshk +#define bitsk __builtin_avr_bitsk -static __inline__ __attribute__((__always_inline__)) -accum absk (const accum __q) -{ - return __builtin_avr_absk (__q); -} +#define bitsuhk __builtin_avr_bitsuhk +#define bitsuk __builtin_avr_bitsuk #if __SIZEOF_INT__ == 2 -/* long long fract (llr): absllr */ +#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 -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 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 -/* long long fract (llr): bitsllr, bitsullr, llrbits, ullrbits */ +#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. */ -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; -} +#define absfx __builtin_avr_absfx +#define roundfx __builtin_avr_roundfx +#define countlsfx __builtin_avr_countlsfx -#endif /* __SIZEOF_INT__ == 2 */ #endif /* _AVRGCC_STDFIX_H */ Index: gcc/config/avr/avr.md =================================================================== --- gcc/config/avr/avr.md (revision 195736) +++ gcc/config/avr/avr.md (working copy) @@ -68,6 +68,7 @@ (define_c_enum "unspec" UNSPEC_COPYSIGN UNSPEC_IDENTITY UNSPEC_INSERT_BITS + UNSPEC_ROUND ]) (define_c_enum "unspecv" Index: gcc/config/avr/avr-c.c =================================================================== --- gcc/config/avr/avr-c.c (revision 195736) +++ gcc/config/avr/avr-c.c (working copy) @@ -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; } Index: gcc/config/avr/avr.c =================================================================== --- gcc/config/avr/avr.c (revision 195736) +++ gcc/config/avr/avr.c (working copy) @@ -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_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]; Index: libgcc/config/avr/lib2-object.mk =================================================================== --- libgcc/config/avr/lib2-object.mk (revision 0) +++ libgcc/config/avr/lib2-object.mk (revision 0) @@ -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 Index: libgcc/config/avr/lib1funcs-fixed.S =================================================================== --- libgcc/config/avr/lib1funcs-fixed.S (revision 195736) +++ libgcc/config/avr/lib1funcs-fixed.S (working copy) @@ -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 */ Index: libgcc/config/avr/lib1funcs.S =================================================================== --- libgcc/config/avr/lib1funcs.S (revision 195736) +++ libgcc/config/avr/lib1funcs.S (working copy) @@ -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__ Index: libgcc/config/avr/lib2funcs.c =================================================================== --- libgcc/config/avr/lib2funcs.c (revision 0) +++ libgcc/config/avr/lib2funcs.c (revision 0) @@ -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 */ Index: libgcc/config/avr/t-avr =================================================================== --- libgcc/config/avr/t-avr (revision 195736) +++ libgcc/config/avr/t-avr (working copy) @@ -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 \ Index: gcc/testsuite/gcc.target/avr/torture/builtins-4-roundfx.c =================================================================== --- gcc/testsuite/gcc.target/avr/torture/builtins-4-roundfx.c (revision 0) +++ gcc/testsuite/gcc.target/avr/torture/builtins-4-roundfx.c (revision 0) @@ -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; +} + Index: gcc/testsuite/gcc.target/avr/torture/builtins-5-countlsfx.c =================================================================== --- gcc/testsuite/gcc.target/avr/torture/builtins-5-countlsfx.c (revision 0) +++ gcc/testsuite/gcc.target/avr/torture/builtins-5-countlsfx.c (revision 0) @@ -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; +}