aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/avr/avr-fixed.md
diff options
context:
space:
mode:
authorGeorg-Johann Lay <avr@gjlay.de>2013-02-08 10:13:37 +0000
committerGeorg-Johann Lay <gjl@gcc.gnu.org>2013-02-08 10:13:37 +0000
commit85d768f349087f3766ff84054ec7b3403c52ac7a (patch)
treec41ab849c5ffa4c56a753d5d4502a23fdc14617d /gcc/config/avr/avr-fixed.md
parent661bc682bcb87f5faa709f9bcd1679874f6652f6 (diff)
downloadgcc-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.md138
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")])