diff options
author | Georg-Johann Lay <avr@gjlay.de> | 2013-02-08 10:13:37 +0000 |
---|---|---|
committer | Georg-Johann Lay <gjl@gcc.gnu.org> | 2013-02-08 10:13:37 +0000 |
commit | 85d768f349087f3766ff84054ec7b3403c52ac7a (patch) | |
tree | c41ab849c5ffa4c56a753d5d4502a23fdc14617d /gcc/config/avr/avr-fixed.md | |
parent | 661bc682bcb87f5faa709f9bcd1679874f6652f6 (diff) | |
download | gcc-85d768f349087f3766ff84054ec7b3403c52ac7a.zip gcc-85d768f349087f3766ff84054ec7b3403c52ac7a.tar.gz gcc-85d768f349087f3766ff84054ec7b3403c52ac7a.tar.bz2 |
re PR target/54222 ([avr] Implement fixed-point support)
gcc/
PR target/54222
* config/avr/avr.md (unspec) <UNSPEC_ROUND>: Add.
* config/avr/avr-fixed.md (ALL4QA, ALL124QA): New mode iterators.
(round<mode>3, round<mode>3_const): New expanders for fixed-mode.
(*round<mode>3.libgcc): New insns for fixed-modes.
* config/avr/builtins.def (ABSxx): Use a non-NULL LIBNAME.
(ROUNDxx, COUNTLSxx, BITSxx, xxBITS): New DEF_BUILTINs.
(ROUNDFX, COUNTLSFX, ABSFX): New DEF_BUILTINs.
* config/avr/stdfix.h (absFX, bitsFX, FXbits): Remove inline
implementations. Define to __builtin_avr_absFX,
__builtin_avr_bitsFX, __builtin_avr_FXbits, respectively.
(roundFX, countlsFX): Define to __builtin_avr_roundFX,
__builtin_avr_countlsFX, respectively.
* config/avr/avr-c.c (target.h): Include it.
(enum avr_builtin_id): New enum.
(avr_resolve_overloaded_builtin): New static function.
(avr_register_target_pragmas): Use it to set
targetm.resolve_overloaded_builtin.
* config/avr/avr.c (avr_init_builtins): Supply myriads of local
tree nodes used by DEF_BUILTIN.
(avr_expand_builtin) <AVR_BUILTIN_ROUNDxx>: Sanity-check them.
(avr_fold_builtin) <AVR_BUILTIN_BITSxx>: Fold to VIEW_COVERT_EXPR.
<AVR_BUILTIN_xxBITS>: Same.
libgcc/
PR target/54222
* config/avr/lib2funcs.c: New C sources for modules for libgcc.a.
* config/avr/lib2-object.mk: New iterator to build objects from it.
* config/avr/t-avr: Iterate lib2-object.mk to build objects from
lib2funcs.c.
(LIB2FUNCS_EXCLUDE): Add _clrsbdi2.
(LIB1ASMFUNCS): Add: _ssabs_1, _mask1, _ret, _roundqq3, _rounduqq3,
_round_s2, _round_u2, _round_2_const, _addmask_2, _round_s4,
_round_u4, _round_4_const, _addmask_4, _round_x8, _rounddq3
_roundudq3, _roundda3 _rounduda3, _roundta3 _rounduta3.
* config/avr/lib1funcs-fixed.S: Implement them.
gcc/testsuite/
PR target/54222
* gcc.target/avr/torture/builtins-4-roundfx.c: New test.
* gcc.target/avr/torture/builtins-5-countlsfx.c: New test.
From-SVN: r195878
Diffstat (limited to 'gcc/config/avr/avr-fixed.md')
-rw-r--r-- | gcc/config/avr/avr-fixed.md | 138 |
1 files changed, 134 insertions, 4 deletions
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 __<code><mode>3" [(set_attr "type" "xcall") (set_attr "cc" "clobber")]) + + +;****************************************************************************** +;** Rounding +;****************************************************************************** + +;; "roundqq3" "rounduqq3" +;; "roundhq3" "rounduhq3" "roundha3" "rounduha3" +;; "roundsq3" "roundusq3" "roundsa3" "roundusa3" +(define_expand "round<mode>3" + [(set (match_dup 4) + (match_operand:ALL124QA 1 "register_operand" "")) + (set (reg:QI 24) + (match_dup 5)) + (parallel [(set (match_dup 3) + (unspec:ALL124QA [(match_dup 4) + (reg:QI 24)] UNSPEC_ROUND)) + (clobber (match_dup 4))]) + (set (match_operand:ALL124QA 0 "register_operand" "") + (match_dup 3)) + (use (match_operand:HI 2 "nonmemory_operand" ""))] + "" + { + if (CONST_INT_P (operands[2]) + && !(optimize_size + && 4 == GET_MODE_SIZE (<MODE>mode))) + { + emit_insn (gen_round<mode>3_const (operands[0], operands[1], operands[2])); + DONE; + } + + // Input and output of the libgcc function + const unsigned int regno_in[] = { -1, 22, 22, -1, 18 }; + const unsigned int regno_out[] = { -1, 24, 24, -1, 22 }; + + operands[3] = gen_rtx_REG (<MODE>mode, regno_out[(size_t) GET_MODE_SIZE (<MODE>mode)]); + operands[4] = gen_rtx_REG (<MODE>mode, regno_in[(size_t) GET_MODE_SIZE (<MODE>mode)]); + operands[5] = simplify_gen_subreg (QImode, force_reg (HImode, operands[2]), HImode, 0); + // $2 is no more needed, but is referenced for expand. + operands[2] = const0_rtx; + }) + +;; Expand rounding with known rounding points inline so that the addend / mask +;; will be consumed by operation with immediate operands and there is no +;; need for a shift with variable offset. + +;; "roundqq3_const" "rounduqq3_const" +;; "roundhq3_const" "rounduhq3_const" "roundha3_const" "rounduha3_const" +;; "roundsq3_const" "roundusq3_const" "roundsa3_const" "roundusa3_const" +(define_expand "round<mode>3_const" + [(parallel [(match_operand:ALL124QA 0 "register_operand" "") + (match_operand:ALL124QA 1 "register_operand" "") + (match_operand:HI 2 "const_int_operand" "")])] + "" + { + // The rounding point RP is $2. The smallest fractional + // bit that is not cleared by the rounding is 2^(-RP). + + enum machine_mode imode = int_mode_for_mode (<MODE>mode); + int fbit = (int) GET_MODE_FBIT (<MODE>mode); + + // Add-Saturate 1/2 * 2^(-RP) + + double_int i_add = double_int_zero.set_bit (fbit-1 - INTVAL (operands[2])); + rtx x_add = const_fixed_from_double_int (i_add, <MODE>mode); + + if (SIGNED_FIXED_POINT_MODE_P (<MODE>mode)) + emit_move_insn (operands[0], + gen_rtx_SS_PLUS (<MODE>mode, operands[1], x_add)); + else + emit_move_insn (operands[0], + gen_rtx_US_PLUS (<MODE>mode, operands[1], x_add)); + + // Keep all bits from RP and higher: ... 2^(-RP) + // Clear all bits from RP+1 and lower: 2^(-RP-1) ... + // Rounding point ^^^^^^^ + // Added above ^^^^^^^^^ + + rtx xreg = simplify_gen_subreg (imode, operands[0], <MODE>mode, 0); + rtx xmask = immed_double_int_const (-i_add - i_add, imode); + + if (SImode == imode) + emit_insn (gen_andsi3 (xreg, xreg, xmask)); + else if (HImode == imode) + emit_insn (gen_andhi3 (xreg, xreg, xmask)); + else if (QImode == imode) + emit_insn (gen_andqi3 (xreg, xreg, xmask)); + else + gcc_unreachable(); + + DONE; + }) + + +;; "*roundqq3.libgcc" "*rounduqq3.libgcc" +(define_insn "*round<mode>3.libgcc" + [(set (reg:ALL1Q 24) + (unspec:ALL1Q [(reg:ALL1Q 22) + (reg:QI 24)] UNSPEC_ROUND)) + (clobber (reg:ALL1Q 22))] + "" + "%~call __round<mode>3" + [(set_attr "type" "xcall") + (set_attr "cc" "clobber")]) + +;; "*roundhq3.libgcc" "*rounduhq3.libgcc" +;; "*roundha3.libgcc" "*rounduha3.libgcc" +(define_insn "*round<mode>3.libgcc" + [(set (reg:ALL2QA 24) + (unspec:ALL2QA [(reg:ALL2QA 22) + (reg:QI 24)] UNSPEC_ROUND)) + (clobber (reg:ALL2QA 22))] + "" + "%~call __round<mode>3" + [(set_attr "type" "xcall") + (set_attr "cc" "clobber")]) + +;; "*roundsq3.libgcc" "*roundusq3.libgcc" +;; "*roundsa3.libgcc" "*roundusa3.libgcc" +(define_insn "*round<mode>3.libgcc" + [(set (reg:ALL4QA 22) + (unspec:ALL4QA [(reg:ALL4QA 18) + (reg:QI 24)] UNSPEC_ROUND)) + (clobber (reg:ALL4QA 18))] + "" + "%~call __round<mode>3" + [(set_attr "type" "xcall") + (set_attr "cc" "clobber")]) |