From: Georg-Johann Lay <avr@gjlay.de>
To: gcc-patches@gcc.gnu.org
Cc: Denis Chertykov <chertykov@gmail.com>,
Eric Weddington <eric.weddington@atmel.com>,
Sean D'Epagnier <sean@depagnier.com>,
Joerg Wunsch <joerg_wunsch@uriah.heep.sax.de>
Subject: [Patch,AVR] PR54222: Add fixed point support
Date: Fri, 10 Aug 2012 15:53:00 -0000 [thread overview]
Message-ID: <50252E25.3020901@gjlay.de> (raw)
[-- Attachment #1: Type: text/plain, Size: 4838 bytes --]
This patch adds fixed point support to the avr target.
It's based on the work of Sean, see
http://lists.gnu.org/archive/html/avr-gcc-list/2012-07/msg00030.html
This patch has several changes compared to Sean's patch:
* Additions and subtractions are merged with the existing INT_MODE
operations by means of mode iterator. The output routines are
generic enough to handle fixed-point, too. The changes were minimal,
e.g. some new fixed-point constraints.
* Similar for shifts and comparisons.
* The patch neither implements NEG nor ABS. The standard requires
saturation, e.g. -0x80 must not become 0x80 again. This is work
still to be done, but just a matter of optimization.
* avr-modes.def adjusts TAmode and UTAmode to be 64-bit modes.
The GCC default with 128 bits is too extreme for AVR.
Besides that, the libgcc machinery won't generate TA/UTA functions
because it thinks the mode it too big (is does not code for
ADJUST_BYTESIZE) and the respective functions are empty.
TA/UTA have 48 fractional bits so that the user can pick
2 different resolutions of 64-bit Accum types.
* To make TA/UTA work, avr-lib.h needs some hand-made defines.
* There are no middle-end changes. The original patch changed:
rtl.h, cse.c, fold-const.c, varasm.c.
The patch works out fine. However, because of PR53923 which
shreds the AVR port, currently no reasonable testing is possible.
Work to be done is better testing after PR53923 is fixed and the
AVR port works properly again. And there are many possible tweaks,
e.g. the above mentioned NEG implementation etc, but that can be
done later.
Ok for trunk?
Johann
libgcc/
PR target/54222
* config/avr/lib1funcs-fixed.S: New file.
* config/avr/lib1funcs.S: Include it. Undefine some divmodsi
after they are used.
(neg2, neg4): New macros.
* config/avr/avr-lib.h (TA, UTA): Adjust according to gcc's
avr-modes.def.
* config/avr/t-avr (LIB1ASMFUNCS): Add: _fractqqsf, _fractuqqsf,
_fracthqsf, _fractuhqsf, _fracthasf, _fractuhasf, _fractsasf,
_fractusasf, _fractsfqq, _fractsfuqq, _fractsfhq, _fractsfuhq,
_fractsfha, _fractsfsa, _mulqq3, _muluqq3, _mulhq3, _muluhq3,
_mulha3, _muluha3, _mulsa3, _mulusa3, _divqq3, _udivuqq3, _divhq3,
_udivuhq3, _divha3, _udivuha3, _divsa3, _udivusa3.
gcc/
PR target/54222
* avr-modes.def (HA, SA, DA, TA, UTA): Adjust modes.
* avr/avr-fixed.md: New file.
* avr/avr.md: Include it.
(cc): Add: minus.
(adjust_len): Add: minus, minus64, ufract, sfract.
(ALL1, ALL2, ALL4, ORDERED234): New mode iterators.
(MOVMODE): Add: QQ, UQQ, HQ, UHQ, HA, UHA, SQ, USQ, SA, USA.
(MPUSH): Add: HQ, UHQ, HA, UHA, SQ, USQ, SA, USA.
(pushqi1, xload8_A, xload_8, movqi_insn, *reload_inqi, addqi3,
subqi3, ashlqi3, *ashlqi3, ashrqi3, lshrqi3, *lshrqi3, *cmpqi,
cbranchqi4, *cpse.eq): Generalize to handle all 8-bit modes in ALL1.
(*movhi, reload_inhi, addhi3, *addhi3, addhi3_clobber, subhi3,
ashlhi3, *ashlhi3_const, ashrhi3, *ashirhi3_const, lshrhi3,
*lshrhi3_const, *cmphi, cbranchhi4): Generalize to handle all
16-bit modes in ALL2.
(subhi3, casesi, strlenhi): Add clobber when expanding minus:HI.
(*movsi, *reload_insi, addsi3, subsi3, ashlsi3, *ashlsi3_const,
ashrsi3, *ashrhi3_const, *ashrsi3_const, lshrsi3, *lshrsi3_const,
*reversed_tstsi, *cmpsi, cbranchsi4): Generalize to handle all
32-bit modes in ALL4.
* avr-dimode.md (ALL8): New mode iterator.
(adddi3, adddi3_insn, adddi3_const_insn, subdi3, subdi3_insn,
subdi3_const_insn, cbranchdi4, compare_di2,
compare_const_di2, ashrdi3, lshrdi3, rotldi3, ashldi3_insn,
ashrdi3_insn, lshrdi3_insn, rotldi3_insn): Generalize to handle
all 64-bit modes in ALL8.
* config/avr/avr-protos.h (avr_to_int_mode): New prototype.
(avr_out_fract, avr_out_minus, avr_out_minus64): New prototypes.
* config/avr/avr.c (TARGET_FIXED_POINT_SUPPORTED_P): Return true.
(avr_scalar_mode_supported_p): Allow if ALL_FIXED_POINT_MODE_P.
(avr_builtin_setjmp_frame_value): Use gen_subhi3 and return new
pseudo instead of gen_rtx_MINUS.
(avr_print_operand, avr_operand_rtx_cost): Handle: CONST_FIXED.
(notice_update_cc): Handle: CC_MINUS.
(output_movqi): Generalize to handle respective fixed-point modes.
(output_movhi, output_movsisf, avr_2word_insn_p): Ditto.
(avr_out_compare, avr_out_plus_1): Also handle fixed-point modes.
(avr_assemble_integer): Ditto.
(output_reload_in_const, output_reload_insisf): Ditto.
(avr_out_fract, avr_out_minus, avr_out_minus64): New functions.
(avr_to_int_mode): New function.
(adjust_insn_length): Handle: ADJUST_LEN_SFRACT,
ADJUST_LEN_UFRACT, ADJUST_LEN_MINUS, ADJUST_LEN_MINUS64.
* config/avr/predicates.md (const0_operand): Allow const_fixed.
(const_operand, const_or_immediate_operand): New.
(nonmemory_or_const_operand): New.
* config/avr/constraints.md (Ynn, Y00, Y01, Y02, Ym1, Ym2, YIJ):
New constraints.
[-- Attachment #2: fixed-48.diff --]
[-- Type: text/x-patch, Size: 147887 bytes --]
Index: gcc/config/avr/predicates.md
===================================================================
--- gcc/config/avr/predicates.md (revision 190299)
+++ gcc/config/avr/predicates.md (working copy)
@@ -74,7 +74,7 @@ (define_predicate "nox_general_operand"
;; Return 1 if OP is the zero constant for MODE.
(define_predicate "const0_operand"
- (and (match_code "const_int,const_double")
+ (and (match_code "const_int,const_fixed,const_double")
(match_test "op == CONST0_RTX (mode)")))
;; Return 1 if OP is the one constant integer for MODE.
@@ -248,3 +248,21 @@ (define_predicate "s16_operand"
(define_predicate "o16_operand"
(and (match_code "const_int")
(match_test "IN_RANGE (INTVAL (op), -(1<<16), -1)")))
+
+;; Const int, fixed, or double operand
+(define_predicate "const_operand"
+ (ior (match_code "const_fixed")
+ (match_code "const_double")
+ (match_operand 0 "const_int_operand")))
+
+;; Const int, const fixed, or const double operand
+(define_predicate "nonmemory_or_const_operand"
+ (ior (match_code "const_fixed")
+ (match_code "const_double")
+ (match_operand 0 "nonmemory_operand")))
+
+;; Immediate, const fixed, or const double operand
+(define_predicate "const_or_immediate_operand"
+ (ior (match_code "const_fixed")
+ (match_code "const_double")
+ (match_operand 0 "immediate_operand")))
Index: gcc/config/avr/avr-fixed.md
===================================================================
--- gcc/config/avr/avr-fixed.md (revision 0)
+++ gcc/config/avr/avr-fixed.md (revision 0)
@@ -0,0 +1,334 @@
+;; This file contains instructions that support fixed-point operations
+;; for Atmel AVR micro controllers.
+;; Copyright (C) 2012
+;; Free Software Foundation, Inc.
+;; Contributed by Sean D'Epagnier (sean@depagnier.com)
+
+;; 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.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>.
+
+(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 "")])
+
+;;; Conversions
+
+(define_mode_iterator FIXED_A
+ [(QQ "") (UQQ "")
+ (HQ "") (UHQ "") (HA "") (UHA "")
+ (SQ "") (USQ "") (SA "") (USA "")
+ (DQ "") (UDQ "") (DA "") (UDA "")
+ (TA "") (UTA "")
+ (QI "") (HI "") (SI "") (DI "")])
+
+;; Same so that be can build cross products
+
+(define_mode_iterator FIXED_B
+ [(QQ "") (UQQ "")
+ (HQ "") (UHQ "") (HA "") (UHA "")
+ (SQ "") (USQ "") (SA "") (USA "")
+ (DQ "") (UDQ "") (DA "") (UDA "")
+ (TA "") (UTA "")
+ (QI "") (HI "") (SI "") (DI "")])
+
+(define_insn "fract<FIXED_B:mode><FIXED_A:mode>2"
+ [(set (match_operand:FIXED_A 0 "register_operand" "=r")
+ (fract_convert:FIXED_A
+ (match_operand:FIXED_B 1 "register_operand" "r")))]
+ "<FIXED_B:MODE>mode != <FIXED_A:MODE>mode"
+ {
+ return avr_out_fract (insn, operands, true, NULL);
+ }
+ [(set_attr "cc" "clobber")
+ (set_attr "adjust_len" "sfract")])
+
+(define_insn "fractuns<FIXED_B:mode><FIXED_A:mode>2"
+ [(set (match_operand:FIXED_A 0 "register_operand" "=r")
+ (unsigned_fract_convert:FIXED_A
+ (match_operand:FIXED_B 1 "register_operand" "r")))]
+ "<FIXED_B:MODE>mode != <FIXED_A:MODE>mode"
+ {
+ return avr_out_fract (insn, operands, false, NULL);
+ }
+ [(set_attr "cc" "clobber")
+ (set_attr "adjust_len" "ufract")])
+
+;******************************************************************************
+; mul
+
+(define_insn "mulqq3"
+ [(set (match_operand:QQ 0 "register_operand" "=r")
+ (mult:QQ (match_operand:QQ 1 "register_operand" "a")
+ (match_operand:QQ 2 "register_operand" "a")))]
+ "AVR_HAVE_MUL"
+ "fmuls %1,%2\;mov %0,r1\;clr __zero_reg__"
+ [(set_attr "length" "3")
+ (set_attr "cc" "clobber")])
+
+(define_insn "muluqq3"
+ [(set (match_operand:UQQ 0 "register_operand" "=r")
+ (mult:UQQ (match_operand:UQQ 1 "register_operand" "r")
+ (match_operand:UQQ 2 "register_operand" "r")))]
+ "AVR_HAVE_MUL"
+ "mul %1,%2\;mov %0,r1\;clr __zero_reg__"
+ [(set_attr "length" "3")
+ (set_attr "cc" "clobber")])
+
+;; (reg:ALL2Q 20) not clobbered on the enhanced core.
+;; Use registers from 16-23 so we can use FMULS.
+;; All call-used registers clobbered otherwise - Normal library call.
+
+;; "mulhq3" "muluhq3"
+(define_expand "mul<mode>3"
+ [(set (reg:ALL2Q 22)
+ (match_operand:ALL2Q 1 "register_operand" ""))
+ (set (reg:ALL2Q 20)
+ (match_operand:ALL2Q 2 "register_operand" ""))
+ (parallel [(set (reg:ALL2Q 18)
+ (mult:ALL2Q (reg:ALL2Q 22)
+ (reg:ALL2Q 20)))
+ (clobber (reg:ALL2Q 22))])
+ (set (match_operand:ALL2Q 0 "register_operand" "")
+ (reg:ALL2Q 18))]
+ "AVR_HAVE_MUL")
+
+;; "*mulhq3_enh_call" "*muluhq3_enh_call"
+(define_insn "*mul<mode>3_enh_call"
+ [(set (reg:ALL2Q 18)
+ (mult:ALL2Q (reg:ALL2Q 22)
+ (reg:ALL2Q 20)))
+ (clobber (reg:ALL2Q 22))]
+ "AVR_HAVE_MUL"
+ "%~call __mul<mode>3"
+ [(set_attr "type" "xcall")
+ (set_attr "cc" "clobber")])
+
+; Special calls for with and without mul.
+;; "mulha3" "muluha3"
+(define_expand "mul<mode>3"
+ [(set (reg:ALL2A 22)
+ (match_operand:ALL2A 1 "register_operand" ""))
+ (set (reg:ALL2A 20)
+ (match_operand:ALL2A 2 "register_operand" ""))
+ (parallel [(set (reg:ALL2A 18)
+ (mult:ALL2A (reg:ALL2A 22)
+ (reg:ALL2A 20)))
+ (clobber (reg:ALL2A 22))])
+ (set (match_operand:ALL2A 0 "register_operand" "")
+ (reg:ALL2A 18))]
+ ""
+ {
+ if (!AVR_HAVE_MUL)
+ {
+ emit_insn (gen_mul<mode>3_call (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+ })
+
+;; "*mulha3_enh" "*muluhq3_enh"
+(define_insn "*mul<mode>3_enh"
+ [(set (reg:ALL2A 18)
+ (mult:ALL2A (reg:ALL2A 22)
+ (reg:ALL2A 20)))
+ (clobber (reg:ALL2A 22))]
+ "AVR_HAVE_MUL"
+ "%~call __mul<mode>3"
+ [(set_attr "type" "xcall")
+ (set_attr "cc" "clobber")])
+
+;; Without MUL. Clobbers both inputs, needs a separate output register.
+
+;; "mulha3_call" "muluhq3_call"
+(define_expand "mul<mode>3_call"
+ [(set (reg:ALL2A 24)
+ (match_operand:ALL2A 1 "register_operand" ""))
+ (set (reg:ALL2A 22)
+ (match_operand:ALL2A 2 "register_operand" ""))
+ (parallel [(set (reg:ALL2A 18)
+ (mult:ALL2A (reg:ALL2A 22)
+ (reg:ALL2A 24)))
+ (clobber (reg:ALL2A 22))
+ (clobber (reg:ALL2A 24))])
+ (set (match_operand:ALL2A 0 "register_operand" "")
+ (reg:ALL2A 18))]
+ "!AVR_HAVE_MUL")
+
+;; "*mulha3_call" "*muluha3_call"
+(define_insn "*mul<mode>3_call"
+ [(set (reg:ALL2A 18)
+ (mult:ALL2A (reg:ALL2A 22)
+ (reg:ALL2A 24)))
+ (clobber (reg:ALL2A 22))
+ (clobber (reg:ALL2A 24))]
+ "!AVR_HAVE_MUL"
+ "%~call __mul<mode>3"
+ [(set_attr "type" "xcall")
+ (set_attr "cc" "clobber")])
+
+;; On the enhanced core, don't clobber either input and use a separate output.
+;; R15 is needed as a zero register since R1 aka. __zero_reg__ is used for MUL.
+
+;; "mulsa3" "mulusa3"
+(define_expand "mul<mode>3"
+ [(set (reg:ALL4A 16)
+ (match_operand:ALL4A 1 "register_operand" ""))
+ (set (reg:ALL4A 20)
+ (match_operand:ALL4A 2 "register_operand" ""))
+ (parallel [(set (reg:ALL4A 24)
+ (mult:ALL4A (reg:ALL4A 16)
+ (reg:ALL4A 20)))
+ (clobber (reg:QI 15))])
+ (set (match_operand:ALL4A 0 "register_operand" "")
+ (reg:ALL4A 24))]
+ ""
+ {
+ if (!AVR_HAVE_MUL)
+ {
+ emit_insn (gen_mul<mode>3_call (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+ })
+
+;; "*mulsa3_enh" "*mulusa3_enh"
+(define_insn "*mul<mode>3_enh"
+ [(set (reg:ALL4A 24)
+ (mult:ALL4A (reg:ALL4A 16)
+ (reg:ALL4A 20)))
+ (clobber (reg:QI 15))]
+ "AVR_HAVE_MUL"
+ "%~call __mul<mode>3"
+ [(set_attr "type" "xcall")
+ (set_attr "cc" "clobber")])
+
+;; Without MUL. Clobbers both inputs, needs a separate output,
+;; needs two more scratch registers.
+
+;; "mulsa3_call" "mulusa3_call"
+(define_expand "mul<mode>3_call"
+ [(set (reg:ALL4A 18)
+ (match_operand:ALL4A 1 "register_operand" ""))
+ (set (reg:ALL4A 24)
+ (match_operand:ALL4A 2 "register_operand" ""))
+ (parallel [(set (reg:ALL4A 14)
+ (mult:ALL4A (reg:ALL4A 18)
+ (reg:ALL4A 24)))
+ (clobber (reg:ALL4A 18))
+ (clobber (reg:ALL4A 24))
+ (clobber (reg:HI 22))])
+ (set (match_operand:ALL4A 0 "register_operand" "")
+ (reg:ALL4A 14))]
+ "!AVR_HAVE_MUL")
+
+;; "*mulsa3_call" "*mulusa3_call"
+(define_insn "*mul<mode>3_call"
+ [(set (reg:ALL4A 14)
+ (mult:ALL4A (reg:ALL4A 18)
+ (reg:ALL4A 24)))
+ (clobber (reg:ALL4A 18))
+ (clobber (reg:ALL4A 24))
+ (clobber (reg:HI 22))]
+ "!AVR_HAVE_MUL"
+ "%~call __mul<mode>3"
+ [(set_attr "type" "xcall")
+ (set_attr "cc" "clobber")])
+
+; / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
+; div
+
+;; Expand signed and unsigned in one shot
+(define_code_iterator usdiv [udiv div])
+
+;; "divqq3" "udivuqq3"
+(define_expand "<code><mode>3"
+ [(set (reg:ALL1Q 25)
+ (match_operand:ALL1Q 1 "register_operand" ""))
+ (set (reg:ALL1Q 22)
+ (match_operand:ALL1Q 2 "register_operand" ""))
+ (parallel [(set (reg:ALL1Q 24)
+ (usdiv:ALL1Q (reg:ALL1Q 25)
+ (reg:ALL1Q 22)))
+ (clobber (reg:ALL1Q 25))])
+ (set (match_operand:ALL1Q 0 "register_operand" "")
+ (reg:ALL1Q 24))])
+
+;; "*divqq3_call" "*udivuqq3_call"
+(define_insn "*<code><mode>3_call"
+ [(set (reg:ALL1Q 24)
+ (usdiv:ALL1Q (reg:ALL1Q 25)
+ (reg:ALL1Q 22)))
+ (clobber (reg:ALL1Q 25))]
+ ""
+ "%~call __<code><mode>3"
+ [(set_attr "type" "xcall")
+ (set_attr "cc" "clobber")])
+
+;; "divhq3" "udivuhq3" "divha3" "udivuha3"
+(define_expand "<code><mode>3"
+ [(set (reg:ALL2QA 26)
+ (match_operand:ALL2QA 1 "register_operand" ""))
+ (set (reg:ALL2QA 22)
+ (match_operand:ALL2QA 2 "register_operand" ""))
+ (parallel [(set (reg:ALL2QA 24)
+ (usdiv:ALL2QA (reg:ALL2QA 26)
+ (reg:ALL2QA 22)))
+ (clobber (reg:ALL2QA 26))
+ (clobber (reg:QI 21))])
+ (set (match_operand:ALL2QA 0 "register_operand" "")
+ (reg:ALL2QA 24))])
+
+;; "*divhq3_call" "*udivuhq3_call"
+;; "*divha3_call" "*udivuha3_call"
+(define_insn "*<code><mode>3_call"
+ [(set (reg:ALL2QA 24)
+ (usdiv:ALL2QA (reg:ALL2QA 26)
+ (reg:ALL2QA 22)))
+ (clobber (reg:ALL2QA 26))
+ (clobber (reg:QI 21))]
+ ""
+ "%~call __<code><mode>3"
+ [(set_attr "type" "xcall")
+ (set_attr "cc" "clobber")])
+
+;; Note the first parameter gets passed in already offset by 2 bytes
+
+;; "divsa3" "udivusa3"
+(define_expand "<code><mode>3"
+ [(set (reg:ALL4A 24)
+ (match_operand:ALL4A 1 "register_operand" ""))
+ (set (reg:ALL4A 18)
+ (match_operand:ALL4A 2 "register_operand" ""))
+ (parallel [(set (reg:ALL4A 22)
+ (usdiv:ALL4A (reg:ALL4A 24)
+ (reg:ALL4A 18)))
+ (clobber (reg:HI 26))
+ (clobber (reg:HI 30))])
+ (set (match_operand:ALL4A 0 "register_operand" "")
+ (reg:ALL4A 22))])
+
+;; "*divsa3_call" "*udivusa3_call"
+(define_insn "*<code><mode>3_call"
+ [(set (reg:ALL4A 22)
+ (usdiv:ALL4A (reg:ALL4A 24)
+ (reg:ALL4A 18)))
+ (clobber (reg:HI 26))
+ (clobber (reg:HI 30))]
+ ""
+ "%~call __<code><mode>3"
+ [(set_attr "type" "xcall")
+ (set_attr "cc" "clobber")])
Index: gcc/config/avr/avr-dimode.md
===================================================================
--- gcc/config/avr/avr-dimode.md (revision 190299)
+++ gcc/config/avr/avr-dimode.md (working copy)
@@ -47,44 +47,58 @@ (define_constants
[(ACC_A 18)
(ACC_B 10)])
+;; Supported modes that are 8 bytes wide
+(define_mode_iterator ALL8 [(DI "")
+ (DQ "") (UDQ "")
+ (DA "") (UDA "")
+ (TA "") (UTA "")])
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Addition
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(define_expand "adddi3"
- [(parallel [(match_operand:DI 0 "general_operand" "")
- (match_operand:DI 1 "general_operand" "")
- (match_operand:DI 2 "general_operand" "")])]
+;; "adddi3"
+;; "adddq3" "addudq3"
+;; "addda3" "adduda3"
+;; "addta3" "adduta3"
+(define_expand "add<mode>3"
+ [(parallel [(match_operand:ALL8 0 "general_operand" "")
+ (match_operand:ALL8 1 "general_operand" "")
+ (match_operand:ALL8 2 "general_operand" "")])]
"avr_have_dimode"
{
- rtx acc_a = gen_rtx_REG (DImode, ACC_A);
+ rtx acc_a = gen_rtx_REG (<MODE>mode, ACC_A);
emit_move_insn (acc_a, operands[1]);
- if (s8_operand (operands[2], VOIDmode))
+ if (DImode == <MODE>mode
+ && s8_operand (operands[2], VOIDmode))
{
emit_move_insn (gen_rtx_REG (QImode, REG_X), operands[2]);
emit_insn (gen_adddi3_const8_insn ());
}
- else if (CONST_INT_P (operands[2])
- || CONST_DOUBLE_P (operands[2]))
+ else if (const_operand (operands[2], GET_MODE (operands[2])))
{
- emit_insn (gen_adddi3_const_insn (operands[2]));
+ emit_insn (gen_add<mode>3_const_insn (operands[2]));
}
else
{
- emit_move_insn (gen_rtx_REG (DImode, ACC_B), operands[2]);
- emit_insn (gen_adddi3_insn ());
+ emit_move_insn (gen_rtx_REG (<MODE>mode, ACC_B), operands[2]);
+ emit_insn (gen_add<mode>3_insn ());
}
emit_move_insn (operands[0], acc_a);
DONE;
})
-(define_insn "adddi3_insn"
- [(set (reg:DI ACC_A)
- (plus:DI (reg:DI ACC_A)
- (reg:DI ACC_B)))]
+;; "adddi3_insn"
+;; "adddq3_insn" "addudq3_insn"
+;; "addda3_insn" "adduda3_insn"
+;; "addta3_insn" "adduta3_insn"
+(define_insn "add<mode>3_insn"
+ [(set (reg:ALL8 ACC_A)
+ (plus:ALL8 (reg:ALL8 ACC_A)
+ (reg:ALL8 ACC_B)))]
"avr_have_dimode"
"%~call __adddi3"
[(set_attr "adjust_len" "call")
@@ -99,10 +113,14 @@ (define_insn "adddi3_const8_insn"
[(set_attr "adjust_len" "call")
(set_attr "cc" "clobber")])
-(define_insn "adddi3_const_insn"
- [(set (reg:DI ACC_A)
- (plus:DI (reg:DI ACC_A)
- (match_operand:DI 0 "const_double_operand" "n")))]
+;; "adddi3_const_insn"
+;; "adddq3_const_insn" "addudq3_const_insn"
+;; "addda3_const_insn" "adduda3_const_insn"
+;; "addta3_const_insn" "adduta3_const_insn"
+(define_insn "add<mode>3_const_insn"
+ [(set (reg:ALL8 ACC_A)
+ (plus:ALL8 (reg:ALL8 ACC_A)
+ (match_operand:ALL8 0 "const_operand" "n Ynn")))]
"avr_have_dimode
&& !s8_operand (operands[0], VOIDmode)"
{
@@ -116,30 +134,62 @@ (define_insn "adddi3_const_insn"
;; Subtraction
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(define_expand "subdi3"
- [(parallel [(match_operand:DI 0 "general_operand" "")
- (match_operand:DI 1 "general_operand" "")
- (match_operand:DI 2 "general_operand" "")])]
+;; "subdi3"
+;; "subdq3" "subudq3"
+;; "subda3" "subuda3"
+;; "subta3" "subuta3"
+(define_expand "sub<mode>3"
+ [(parallel [(match_operand:ALL8 0 "general_operand" "")
+ (match_operand:ALL8 1 "general_operand" "")
+ (match_operand:ALL8 2 "general_operand" "")])]
"avr_have_dimode"
{
- rtx acc_a = gen_rtx_REG (DImode, ACC_A);
+ rtx acc_a = gen_rtx_REG (<MODE>mode, ACC_A);
emit_move_insn (acc_a, operands[1]);
- emit_move_insn (gen_rtx_REG (DImode, ACC_B), operands[2]);
- emit_insn (gen_subdi3_insn ());
+
+ if (const_operand (operands[2], GET_MODE (operands[2])))
+ {
+ emit_insn (gen_sub<mode>3_const_insn (operands[2]));
+ }
+ else
+ {
+ emit_move_insn (gen_rtx_REG (<MODE>mode, ACC_B), operands[2]);
+ emit_insn (gen_sub<mode>3_insn ());
+ }
+
emit_move_insn (operands[0], acc_a);
DONE;
})
-(define_insn "subdi3_insn"
- [(set (reg:DI ACC_A)
- (minus:DI (reg:DI ACC_A)
- (reg:DI ACC_B)))]
+;; "subdi3_insn"
+;; "subdq3_insn" "subudq3_insn"
+;; "subda3_insn" "subuda3_insn"
+;; "subta3_insn" "subuta3_insn"
+(define_insn "sub<mode>3_insn"
+ [(set (reg:ALL8 ACC_A)
+ (minus:ALL8 (reg:ALL8 ACC_A)
+ (reg:ALL8 ACC_B)))]
"avr_have_dimode"
"%~call __subdi3"
[(set_attr "adjust_len" "call")
(set_attr "cc" "set_czn")])
+;; "subdi3_const_insn"
+;; "subdq3_const_insn" "subudq3_const_insn"
+;; "subda3_const_insn" "subuda3_const_insn"
+;; "subta3_const_insn" "subuta3_const_insn"
+(define_insn "sub<mode>3_const_insn"
+ [(set (reg:ALL8 ACC_A)
+ (minus:ALL8 (reg:ALL8 ACC_A)
+ (match_operand:ALL8 0 "const_operand" "n Ynn")))]
+ "avr_have_dimode"
+ {
+ return avr_out_minus64 (operands[0], NULL);
+ }
+ [(set_attr "adjust_len" "minus64")
+ (set_attr "cc" "clobber")])
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Negation
@@ -180,15 +230,19 @@ (define_expand "conditional_jump"
(pc)))]
"avr_have_dimode")
-(define_expand "cbranchdi4"
- [(parallel [(match_operand:DI 1 "register_operand" "")
- (match_operand:DI 2 "nonmemory_operand" "")
+;; "cbranchdi4"
+;; "cbranchdq4" "cbranchudq4"
+;; "cbranchda4" "cbranchuda4"
+;; "cbranchta4" "cbranchuta4"
+(define_expand "cbranch<mode>4"
+ [(parallel [(match_operand:ALL8 1 "register_operand" "")
+ (match_operand:ALL8 2 "nonmemory_operand" "")
(match_operator 0 "ordered_comparison_operator" [(cc0)
(const_int 0)])
(label_ref (match_operand 3 "" ""))])]
"avr_have_dimode"
{
- rtx acc_a = gen_rtx_REG (DImode, ACC_A);
+ rtx acc_a = gen_rtx_REG (<MODE>mode, ACC_A);
emit_move_insn (acc_a, operands[1]);
@@ -197,25 +251,28 @@ (define_expand "cbranchdi4"
emit_move_insn (gen_rtx_REG (QImode, REG_X), operands[2]);
emit_insn (gen_compare_const8_di2 ());
}
- else if (CONST_INT_P (operands[2])
- || CONST_DOUBLE_P (operands[2]))
+ else if (const_operand (operands[2], GET_MODE (operands[2])))
{
- emit_insn (gen_compare_const_di2 (operands[2]));
+ emit_insn (gen_compare_const_<mode>2 (operands[2]));
}
else
{
- emit_move_insn (gen_rtx_REG (DImode, ACC_B), operands[2]);
- emit_insn (gen_compare_di2 ());
+ emit_move_insn (gen_rtx_REG (<MODE>mode, ACC_B), operands[2]);
+ emit_insn (gen_compare_<mode>2 ());
}
emit_jump_insn (gen_conditional_jump (operands[0], operands[3]));
DONE;
})
-(define_insn "compare_di2"
+;; "compare_qi2"
+;; "compare_qq2" "compare_udq2"
+;; "compare_da2" "compare_uda2"
+;; "compare_ta2" "compare_uta2"
+(define_insn "compare_<mode>2"
[(set (cc0)
- (compare (reg:DI ACC_A)
- (reg:DI ACC_B)))]
+ (compare (reg:ALL8 ACC_A)
+ (reg:ALL8 ACC_B)))]
"avr_have_dimode"
"%~call __cmpdi2"
[(set_attr "adjust_len" "call")
@@ -230,10 +287,14 @@ (define_insn "compare_const8_di2"
[(set_attr "adjust_len" "call")
(set_attr "cc" "compare")])
-(define_insn "compare_const_di2"
+;; "compare_const_qi2"
+;; "compare_const_qq2" "compare_const_udq2"
+;; "compare_const_da2" "compare_const_uda2"
+;; "compare_const_ta2" "compare_const_uta2"
+(define_insn "compare_const_<mode>2"
[(set (cc0)
- (compare (reg:DI ACC_A)
- (match_operand:DI 0 "const_double_operand" "n")))
+ (compare (reg:ALL8 ACC_A)
+ (match_operand:ALL8 0 "const_operand" "n Ynn")))
(clobber (match_scratch:QI 1 "=&d"))]
"avr_have_dimode
&& !s8_operand (operands[0], VOIDmode)"
@@ -258,25 +319,41 @@ (define_code_iterator di_shifts
;; "ashrdi3"
;; "lshrdi3"
;; "rotldi3"
-(define_expand "<code_stdname>di3"
- [(parallel [(match_operand:DI 0 "general_operand" "")
- (di_shifts:DI (match_operand:DI 1 "general_operand" "")
- (match_operand:QI 2 "general_operand" ""))])]
+;; "ashldq3" "ashrdq3" "lshrdq3" "rotldq3"
+;; "ashlda3" "ashrda3" "lshrda3" "rotlda3"
+;; "ashlta3" "ashrta3" "lshrta3" "rotlta3"
+;; "ashludq3" "ashrudq3" "lshrudq3" "rotludq3"
+;; "ashluda3" "ashruda3" "lshruda3" "rotluda3"
+;; "ashluta3" "ashruta3" "lshruta3" "rotluta3"
+(define_expand "<code_stdname><mode>3"
+ [(parallel [(match_operand:ALL8 0 "general_operand" "")
+ (di_shifts:ALL8 (match_operand:ALL8 1 "general_operand" "")
+ (match_operand:QI 2 "general_operand" ""))])]
"avr_have_dimode"
{
- rtx acc_a = gen_rtx_REG (DImode, ACC_A);
+ rtx acc_a = gen_rtx_REG (<MODE>mode, ACC_A);
emit_move_insn (acc_a, operands[1]);
emit_move_insn (gen_rtx_REG (QImode, 16), operands[2]);
- emit_insn (gen_<code_stdname>di3_insn ());
+ emit_insn (gen_<code_stdname><mode>3_insn ());
emit_move_insn (operands[0], acc_a);
DONE;
})
-(define_insn "<code_stdname>di3_insn"
- [(set (reg:DI ACC_A)
- (di_shifts:DI (reg:DI ACC_A)
- (reg:QI 16)))]
+;; "ashldi3_insn"
+;; "ashrdi3_insn"
+;; "lshrdi3_insn"
+;; "rotldi3_insn"
+;; "ashldq3_insn" "ashrdq3_insn" "lshrdq3_insn" "rotldq3_insn"
+;; "ashlda3_insn" "ashrda3_insn" "lshrda3_insn" "rotlda3_insn"
+;; "ashlta3_insn" "ashrta3_insn" "lshrta3_insn" "rotlta3_insn"
+;; "ashludq3_insn" "ashrudq3_insn" "lshrudq3_insn" "rotludq3_insn"
+;; "ashluda3_insn" "ashruda3_insn" "lshruda3_insn" "rotluda3_insn"
+;; "ashluta3_insn" "ashruta3_insn" "lshruta3_insn" "rotluta3_insn"
+(define_insn "<code_stdname><mode>3_insn"
+ [(set (reg:ALL8 ACC_A)
+ (di_shifts:ALL8 (reg:ALL8 ACC_A)
+ (reg:QI 16)))]
"avr_have_dimode"
"%~call __<code_stdname>di3"
[(set_attr "adjust_len" "call")
Index: gcc/config/avr/avr.md
===================================================================
--- gcc/config/avr/avr.md (revision 190299)
+++ gcc/config/avr/avr.md (working copy)
@@ -88,10 +88,10 @@ (define_c_enum "unspecv"
(include "predicates.md")
(include "constraints.md")
-
+
;; Condition code settings.
(define_attr "cc" "none,set_czn,set_zn,set_n,compare,clobber,
- out_plus, out_plus_noclobber,ldi"
+ out_plus, out_plus_noclobber,ldi,minus"
(const_string "none"))
(define_attr "type" "branch,branch1,arith,xcall"
@@ -139,8 +139,10 @@ (define_attr "length" ""
(define_attr "adjust_len"
"out_bitop, out_plus, out_plus_noclobber, plus64, addto_sp,
+ minus, minus64,
tsthi, tstpsi, tstsi, compare, compare64, call,
mov8, mov16, mov24, mov32, reload_in16, reload_in24, reload_in32,
+ ufract, sfract,
xload, movmem, load_lpm,
ashlqi, ashrqi, lshrqi,
ashlhi, ashrhi, lshrhi,
@@ -225,8 +227,20 @@ (define_mode_iterator QISI [(QI "") (HI
(define_mode_iterator QIDI [(QI "") (HI "") (PSI "") (SI "") (DI "")])
(define_mode_iterator HISI [(HI "") (PSI "") (SI "")])
+(define_mode_iterator ALL1 [(QI "") (QQ "") (UQQ "")])
+(define_mode_iterator ALL2 [(HI "") (HQ "") (UHQ "") (HA "") (UHA "")])
+(define_mode_iterator ALL4 [(SI "") (SQ "") (USQ "") (SA "") (USA "")])
+
;; All supported move-modes
-(define_mode_iterator MOVMODE [(QI "") (HI "") (SI "") (SF "") (PSI "")])
+(define_mode_iterator MOVMODE [(QI "") (HI "") (SI "") (SF "") (PSI "")
+ (QQ "") (UQQ "")
+ (HQ "") (UHQ "") (HA "") (UHA "")
+ (SQ "") (USQ "") (SA "") (USA "")])
+
+;; Supported ordered modes that are 2, 3, 4 bytes wide
+(define_mode_iterator ORDERED234 [(HI "") (SI "") (PSI "")
+ (HQ "") (UHQ "") (HA "") (UHA "")
+ (SQ "") (USQ "") (SA "") (USA "")])
;; Define code iterators
;; Define two incarnations so that we can build the cross product.
@@ -317,9 +331,11 @@ (define_expand "nonlocal_goto"
DONE;
})
-(define_insn "pushqi1"
- [(set (mem:QI (post_dec:HI (reg:HI REG_SP)))
- (match_operand:QI 0 "reg_or_0_operand" "r,L"))]
+;; "pushqi1"
+;; "pushqq1" "pushuqq1"
+(define_insn "push<mode>1"
+ [(set (mem:ALL1 (post_dec:HI (reg:HI REG_SP)))
+ (match_operand:ALL1 0 "reg_or_0_operand" "r,Y00"))]
""
"@
push %0
@@ -334,7 +350,9 @@ (define_mode_iterator MPUSH
(PSI "")
(SI "") (CSI "")
(DI "") (CDI "")
- (SF "") (SC "")])
+ (SF "") (SC "")
+ (HQ "") (UHQ "") (HA "") (UHA "")
+ (SQ "") (USQ "") (SA "") (USA "")])
(define_expand "push<mode>1"
[(match_operand:MPUSH 0 "" "")]
@@ -422,12 +440,14 @@ (define_insn "load_<mode>_clobber"
(set_attr "cc" "clobber")])
-(define_insn_and_split "xload8_A"
- [(set (match_operand:QI 0 "register_operand" "=r")
- (match_operand:QI 1 "memory_operand" "m"))
+;; "xload8qi_A"
+;; "xload8qq_A" "xload8uqq_A"
+(define_insn_and_split "xload8<mode>_A"
+ [(set (match_operand:ALL1 0 "register_operand" "=r")
+ (match_operand:ALL1 1 "memory_operand" "m"))
(clobber (reg:HI REG_Z))]
"can_create_pseudo_p()
- && !avr_xload_libgcc_p (QImode)
+ && !avr_xload_libgcc_p (<MODE>mode)
&& avr_mem_memx_p (operands[1])
&& REG_P (XEXP (operands[1], 0))"
{ gcc_unreachable(); }
@@ -441,16 +461,16 @@ (define_insn_and_split "xload8_A"
emit_move_insn (reg_z, simplify_gen_subreg (HImode, addr, PSImode, 0));
emit_move_insn (hi8, simplify_gen_subreg (QImode, addr, PSImode, 2));
- insn = emit_insn (gen_xload_8 (operands[0], hi8));
+ insn = emit_insn (gen_xload<mode>_8 (operands[0], hi8));
set_mem_addr_space (SET_SRC (single_set (insn)),
MEM_ADDR_SPACE (operands[1]));
DONE;
})
-;; "xloadqi_A"
-;; "xloadhi_A"
+;; "xloadqi_A" "xloadqq_A" "xloaduqq_A"
+;; "xloadhi_A" "xloadhq_A" "xloaduhq_A" "xloadha_A" "xloaduha_A"
+;; "xloadsi_A" "xloadsq_A" "xloadusq_A" "xloadsa_A" "xloadusa_A"
;; "xloadpsi_A"
-;; "xloadsi_A"
;; "xloadsf_A"
(define_insn_and_split "xload<mode>_A"
[(set (match_operand:MOVMODE 0 "register_operand" "=r")
@@ -488,11 +508,13 @@ (define_insn_and_split "xload<mode>_A"
;; Move value from address space memx to a register
;; These insns must be prior to respective generic move insn.
-(define_insn "xload_8"
- [(set (match_operand:QI 0 "register_operand" "=&r,r")
- (mem:QI (lo_sum:PSI (match_operand:QI 1 "register_operand" "r,r")
- (reg:HI REG_Z))))]
- "!avr_xload_libgcc_p (QImode)"
+;; "xloadqi_8"
+;; "xloadqq_8" "xloaduqq_8"
+(define_insn "xload<mode>_8"
+ [(set (match_operand:ALL1 0 "register_operand" "=&r,r")
+ (mem:ALL1 (lo_sum:PSI (match_operand:QI 1 "register_operand" "r,r")
+ (reg:HI REG_Z))))]
+ "!avr_xload_libgcc_p (<MODE>mode)"
{
return avr_out_xload (insn, operands, NULL);
}
@@ -504,11 +526,11 @@ (define_insn "xload_8"
;; R21:Z : 24-bit source address
;; R22 : 1-4 byte output
-;; "xload_qi_libgcc"
-;; "xload_hi_libgcc"
-;; "xload_psi_libgcc"
-;; "xload_si_libgcc"
+;; "xload_qi_libgcc" "xload_qq_libgcc" "xload_uqq_libgcc"
+;; "xload_hi_libgcc" "xload_hq_libgcc" "xload_uhq_libgcc" "xload_ha_libgcc" "xload_uha_libgcc"
+;; "xload_si_libgcc" "xload_sq_libgcc" "xload_usq_libgcc" "xload_sa_libgcc" "xload_usa_libgcc"
;; "xload_sf_libgcc"
+;; "xload_psi_libgcc"
(define_insn "xload_<mode>_libgcc"
[(set (reg:MOVMODE 22)
(mem:MOVMODE (lo_sum:PSI (reg:QI 21)
@@ -528,9 +550,9 @@ (define_insn "xload_<mode>_libgcc"
;; General move expanders
-;; "movqi"
-;; "movhi"
-;; "movsi"
+;; "movqi" "movqq" "movuqq"
+;; "movhi" "movhq" "movuhq" "movha" "movuha"
+;; "movsi" "movsq" "movusq" "movsa" "movusa"
;; "movsf"
;; "movpsi"
(define_expand "mov<mode>"
@@ -546,8 +568,7 @@ (define_expand "mov<mode>"
/* One of the operands has to be in a register. */
if (!register_operand (dest, <MODE>mode)
- && !(register_operand (src, <MODE>mode)
- || src == CONST0_RTX (<MODE>mode)))
+ && !reg_or_0_operand (src, <MODE>mode))
{
operands[1] = src = copy_to_mode_reg (<MODE>mode, src);
}
@@ -560,7 +581,9 @@ (define_expand "mov<mode>"
src = replace_equiv_address (src, copy_to_mode_reg (PSImode, addr));
if (!avr_xload_libgcc_p (<MODE>mode))
- emit_insn (gen_xload8_A (dest, src));
+ /* ; No <mode> here because gen_xload8<mode>_A only iterates over ALL1.
+ ; insn-emit does not depend on the mode, it' all about operands. */
+ emit_insn (gen_xload8qi_A (dest, src));
else
emit_insn (gen_xload<mode>_A (dest, src));
@@ -627,12 +650,13 @@ (define_expand "mov<mode>"
;; are call-saved registers, and most of LD_REGS are call-used registers,
;; so this may still be a win for registers live across function calls.
-(define_insn "movqi_insn"
- [(set (match_operand:QI 0 "nonimmediate_operand" "=r ,d,Qm,r ,q,r,*r")
- (match_operand:QI 1 "nox_general_operand" "rL,i,rL,Qm,r,q,i"))]
- "register_operand (operands[0], QImode)
- || register_operand (operands[1], QImode)
- || const0_rtx == operands[1]"
+;; "movqi_insn"
+;; "movqq_insn" "movuqq_insn"
+(define_insn "mov<mode>_insn"
+ [(set (match_operand:ALL1 0 "nonimmediate_operand" "=r ,d ,Qm ,r ,q,r,*r")
+ (match_operand:ALL1 1 "nox_general_operand" "r Y00,n Ynn,r Y00,Qm,r,q,i"))]
+ "register_operand (operands[0], <MODE>mode)
+ || reg_or_0_operand (operands[1], <MODE>mode)"
{
return output_movqi (insn, operands, NULL);
}
@@ -643,9 +667,11 @@ (define_insn "movqi_insn"
;; This is used in peephole2 to optimize loading immediate constants
;; if a scratch register from LD_REGS happens to be available.
-(define_insn "*reload_inqi"
- [(set (match_operand:QI 0 "register_operand" "=l")
- (match_operand:QI 1 "immediate_operand" "i"))
+;; "*reload_inqi"
+;; "*reload_inqq" "*reload_inuqq"
+(define_insn "*reload_in<mode>"
+ [(set (match_operand:ALL1 0 "register_operand" "=l")
+ (match_operand:ALL1 1 "const_operand" "i"))
(clobber (match_operand:QI 2 "register_operand" "=&d"))]
"reload_completed"
"ldi %2,lo8(%1)
@@ -655,14 +681,15 @@ (define_insn "*reload_inqi"
(define_peephole2
[(match_scratch:QI 2 "d")
- (set (match_operand:QI 0 "l_register_operand" "")
- (match_operand:QI 1 "immediate_operand" ""))]
- "(operands[1] != const0_rtx
- && operands[1] != const1_rtx
- && operands[1] != constm1_rtx)"
- [(parallel [(set (match_dup 0) (match_dup 1))
- (clobber (match_dup 2))])]
- "")
+ (set (match_operand:ALL1 0 "l_register_operand" "")
+ (match_operand:ALL1 1 "const_operand" ""))]
+ ; No need for a clobber reg for 0x0, 0x01 or 0xff
+ "!satisfies_constraint_Y00 (operands[1])
+ && !satisfies_constraint_Y01 (operands[1])
+ && !satisfies_constraint_Ym1 (operands[1])"
+ [(parallel [(set (match_dup 0)
+ (match_dup 1))
+ (clobber (match_dup 2))])])
;;============================================================================
;; move word (16 bit)
@@ -693,18 +720,20 @@ (define_insn "movhi_sp_r"
(define_peephole2
[(match_scratch:QI 2 "d")
- (set (match_operand:HI 0 "l_register_operand" "")
- (match_operand:HI 1 "immediate_operand" ""))]
- "(operands[1] != const0_rtx
- && operands[1] != constm1_rtx)"
- [(parallel [(set (match_dup 0) (match_dup 1))
- (clobber (match_dup 2))])]
- "")
+ (set (match_operand:ALL2 0 "l_register_operand" "")
+ (match_operand:ALL2 1 "const_or_immediate_operand" ""))]
+ "operands[1] != CONST0_RTX (<MODE>mode)"
+ [(parallel [(set (match_dup 0)
+ (match_dup 1))
+ (clobber (match_dup 2))])])
;; '*' because it is not used in rtl generation, only in above peephole
-(define_insn "*reload_inhi"
- [(set (match_operand:HI 0 "register_operand" "=r")
- (match_operand:HI 1 "immediate_operand" "i"))
+;; "*reload_inhi"
+;; "*reload_inhq" "*reload_inuhq"
+;; "*reload_inha" "*reload_inuha"
+(define_insn "*reload_in<mode>"
+ [(set (match_operand:ALL2 0 "l_register_operand" "=l")
+ (match_operand:ALL2 1 "immediate_operand" "i"))
(clobber (match_operand:QI 2 "register_operand" "=&d"))]
"reload_completed"
{
@@ -712,14 +741,16 @@ (define_insn "*reload_inhi"
}
[(set_attr "length" "4")
(set_attr "adjust_len" "reload_in16")
- (set_attr "cc" "none")])
+ (set_attr "cc" "clobber")])
-(define_insn "*movhi"
- [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,m ,d,*r,q,r")
- (match_operand:HI 1 "nox_general_operand" "r,L,m,rL,i,i ,r,q"))]
- "register_operand (operands[0], HImode)
- || register_operand (operands[1], HImode)
- || const0_rtx == operands[1]"
+;; "*movhi"
+;; "*movhq" "*movuhq"
+;; "*movha" "*movuha"
+(define_insn "*mov<mode>"
+ [(set (match_operand:ALL2 0 "nonimmediate_operand" "=r,r ,r,m ,d,*r,q,r")
+ (match_operand:ALL2 1 "nox_general_operand" "r,Y00,m,r Y00,i,i ,r,q"))]
+ "register_operand (operands[0], <MODE>mode)
+ || reg_or_0_operand (operands[1], <MODE>mode)"
{
return output_movhi (insn, operands, NULL);
}
@@ -728,28 +759,30 @@ (define_insn "*movhi"
(set_attr "cc" "none,none,clobber,clobber,none,clobber,none,none")])
(define_peephole2 ; movw
- [(set (match_operand:QI 0 "even_register_operand" "")
- (match_operand:QI 1 "even_register_operand" ""))
- (set (match_operand:QI 2 "odd_register_operand" "")
- (match_operand:QI 3 "odd_register_operand" ""))]
+ [(set (match_operand:ALL1 0 "even_register_operand" "")
+ (match_operand:ALL1 1 "even_register_operand" ""))
+ (set (match_operand:ALL1 2 "odd_register_operand" "")
+ (match_operand:ALL1 3 "odd_register_operand" ""))]
"(AVR_HAVE_MOVW
&& REGNO (operands[0]) == REGNO (operands[2]) - 1
&& REGNO (operands[1]) == REGNO (operands[3]) - 1)"
- [(set (match_dup 4) (match_dup 5))]
+ [(set (match_dup 4)
+ (match_dup 5))]
{
operands[4] = gen_rtx_REG (HImode, REGNO (operands[0]));
operands[5] = gen_rtx_REG (HImode, REGNO (operands[1]));
})
(define_peephole2 ; movw_r
- [(set (match_operand:QI 0 "odd_register_operand" "")
- (match_operand:QI 1 "odd_register_operand" ""))
- (set (match_operand:QI 2 "even_register_operand" "")
- (match_operand:QI 3 "even_register_operand" ""))]
+ [(set (match_operand:ALL1 0 "odd_register_operand" "")
+ (match_operand:ALL1 1 "odd_register_operand" ""))
+ (set (match_operand:ALL1 2 "even_register_operand" "")
+ (match_operand:ALL1 3 "even_register_operand" ""))]
"(AVR_HAVE_MOVW
&& REGNO (operands[2]) == REGNO (operands[0]) - 1
&& REGNO (operands[3]) == REGNO (operands[1]) - 1)"
- [(set (match_dup 4) (match_dup 5))]
+ [(set (match_dup 4)
+ (match_dup 5))]
{
operands[4] = gen_rtx_REG (HImode, REGNO (operands[2]));
operands[5] = gen_rtx_REG (HImode, REGNO (operands[3]));
@@ -801,19 +834,21 @@ (define_insn "*movpsi"
(define_peephole2 ; *reload_insi
[(match_scratch:QI 2 "d")
- (set (match_operand:SI 0 "l_register_operand" "")
- (match_operand:SI 1 "const_int_operand" ""))
+ (set (match_operand:ALL4 0 "l_register_operand" "")
+ (match_operand:ALL4 1 "immediate_operand" ""))
(match_dup 2)]
- "(operands[1] != const0_rtx
- && operands[1] != constm1_rtx)"
- [(parallel [(set (match_dup 0) (match_dup 1))
- (clobber (match_dup 2))])]
- "")
+ "operands[1] != CONST0_RTX (<MODE>mode)"
+ [(parallel [(set (match_dup 0)
+ (match_dup 1))
+ (clobber (match_dup 2))])])
;; '*' because it is not used in rtl generation.
+;; "*reload_insi"
+;; "*reload_insq" "*reload_inusq"
+;; "*reload_insa" "*reload_inusa"
(define_insn "*reload_insi"
- [(set (match_operand:SI 0 "register_operand" "=r")
- (match_operand:SI 1 "const_int_operand" "n"))
+ [(set (match_operand:ALL4 0 "register_operand" "=r")
+ (match_operand:ALL4 1 "immediate_operand" "n Ynn"))
(clobber (match_operand:QI 2 "register_operand" "=&d"))]
"reload_completed"
{
@@ -824,12 +859,14 @@ (define_insn "*reload_insi"
(set_attr "cc" "clobber")])
-(define_insn "*movsi"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r ,Qm,!d,r")
- (match_operand:SI 1 "nox_general_operand" "r,L,Qm,rL,i ,i"))]
- "register_operand (operands[0], SImode)
- || register_operand (operands[1], SImode)
- || const0_rtx == operands[1]"
+;; "*movsi"
+;; "*movsq" "*movusq"
+;; "*movsa" "*movusa"
+(define_insn "*mov<mode>"
+ [(set (match_operand:ALL4 0 "nonimmediate_operand" "=r,r ,r ,Qm ,!d,r")
+ (match_operand:ALL4 1 "nox_general_operand" "r,Y00,Qm,r Y00,i ,i"))]
+ "register_operand (operands[0], <MODE>mode)
+ || reg_or_0_operand (operands[1], <MODE>mode)"
{
return output_movsisf (insn, operands, NULL);
}
@@ -844,8 +881,7 @@ (define_insn "*movsf"
[(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,r ,Qm,!d,r")
(match_operand:SF 1 "nox_general_operand" "r,G,Qm,rG,F ,F"))]
"register_operand (operands[0], SFmode)
- || register_operand (operands[1], SFmode)
- || operands[1] == CONST0_RTX (SFmode)"
+ || reg_or_0_operand (operands[1], SFmode)"
{
return output_movsisf (insn, operands, NULL);
}
@@ -861,8 +897,7 @@ (define_peephole2 ; *reload_insf
"operands[1] != CONST0_RTX (SFmode)"
[(parallel [(set (match_dup 0)
(match_dup 1))
- (clobber (match_dup 2))])]
- "")
+ (clobber (match_dup 2))])])
;; '*' because it is not used in rtl generation.
(define_insn "*reload_insf"
@@ -1015,9 +1050,10 @@ (define_expand "strlenhi"
(set (match_dup 4)
(plus:HI (match_dup 4)
(const_int -1)))
- (set (match_operand:HI 0 "register_operand" "")
- (minus:HI (match_dup 4)
- (match_dup 5)))]
+ (parallel [(set (match_operand:HI 0 "register_operand" "")
+ (minus:HI (match_dup 4)
+ (match_dup 5)))
+ (clobber (scratch:QI))])]
""
{
rtx addr;
@@ -1043,10 +1079,12 @@ (define_insn "*strlenhi"
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; add bytes
-(define_insn "addqi3"
- [(set (match_operand:QI 0 "register_operand" "=r,d,r,r,r,r")
- (plus:QI (match_operand:QI 1 "register_operand" "%0,0,0,0,0,0")
- (match_operand:QI 2 "nonmemory_operand" "r,i,P,N,K,Cm2")))]
+;; "addqi3"
+;; "addqq3" "adduqq3"
+(define_insn "add<mode>3"
+ [(set (match_operand:ALL1 0 "register_operand" "=r,d ,r ,r ,r ,r")
+ (plus:ALL1 (match_operand:ALL1 1 "register_operand" "%0,0 ,0 ,0 ,0 ,0")
+ (match_operand:ALL1 2 "nonmemory_operand" "r,n Ynn,Y01,Ym1,Y02,Ym2")))]
""
"@
add %0,%2
@@ -1058,11 +1096,13 @@ (define_insn "addqi3"
[(set_attr "length" "1,1,1,1,2,2")
(set_attr "cc" "set_czn,set_czn,set_zn,set_zn,set_zn,set_zn")])
-
-(define_expand "addhi3"
- [(set (match_operand:HI 0 "register_operand" "")
- (plus:HI (match_operand:HI 1 "register_operand" "")
- (match_operand:HI 2 "nonmemory_operand" "")))]
+;; "addhi3"
+;; "addhq3" "adduhq3"
+;; "addha3" "adduha3"
+(define_expand "add<mode>3"
+ [(set (match_operand:ALL2 0 "register_operand" "")
+ (plus:ALL2 (match_operand:ALL2 1 "register_operand" "")
+ (match_operand:ALL2 2 "nonmemory_or_const_operand" "")))]
""
{
if (CONST_INT_P (operands[2]))
@@ -1079,6 +1119,12 @@ (define_expand "addhi3"
DONE;
}
}
+
+ if (CONST_FIXED == GET_CODE (operands[2]))
+ {
+ emit_insn (gen_add<mode>3_clobber (operands[0], operands[1], operands[2]));
+ DONE;
+ }
})
@@ -1124,24 +1170,22 @@ (define_insn "*addhi3_sp"
[(set_attr "length" "6")
(set_attr "adjust_len" "addto_sp")])
-(define_insn "*addhi3"
- [(set (match_operand:HI 0 "register_operand" "=r,d,!w,d")
- (plus:HI (match_operand:HI 1 "register_operand" "%0,0,0 ,0")
- (match_operand:HI 2 "nonmemory_operand" "r,s,IJ,n")))]
+;; "*addhi3"
+;; "*addhq3" "*adduhq3"
+;; "*addha3" "*adduha3"
+(define_insn "*add<mode>3"
+ [(set (match_operand:ALL2 0 "register_operand" "=r,d,!w ,d")
+ (plus:ALL2 (match_operand:ALL2 1 "register_operand" "%0,0,0 ,0")
+ (match_operand:ALL2 2 "nonmemory_or_const_operand" "r,s,IJ YIJ,n Ynn")))]
""
{
- static const char * const asm_code[] =
- {
- "add %A0,%A2\;adc %B0,%B2",
- "subi %A0,lo8(-(%2))\;sbci %B0,hi8(-(%2))",
- "",
- ""
- };
-
- if (*asm_code[which_alternative])
- return asm_code[which_alternative];
-
- return avr_out_plus_noclobber (operands, NULL, NULL);
+ if (REG_P (operands[2]))
+ return "add %A0,%A2\;adc %B0,%B2";
+ else if (CONST_INT_P (operands[2])
+ || CONST_FIXED == GET_CODE (operands[2]))
+ return avr_out_plus_noclobber (operands, NULL, NULL);
+ else
+ return "subi %A0,lo8(-(%2))\;sbci %B0,hi8(-(%2))";
}
[(set_attr "length" "2,2,2,2")
(set_attr "adjust_len" "*,*,out_plus_noclobber,out_plus_noclobber")
@@ -1152,41 +1196,44 @@ (define_insn "*addhi3"
;; itself because that insn is special to reload.
(define_peephole2 ; addhi3_clobber
- [(set (match_operand:HI 0 "d_register_operand" "")
- (match_operand:HI 1 "const_int_operand" ""))
- (set (match_operand:HI 2 "l_register_operand" "")
- (plus:HI (match_dup 2)
- (match_dup 0)))]
+ [(set (match_operand:ALL2 0 "d_register_operand" "")
+ (match_operand:ALL2 1 "const_operand" ""))
+ (set (match_operand:ALL2 2 "l_register_operand" "")
+ (plus:ALL2 (match_dup 2)
+ (match_dup 0)))]
"peep2_reg_dead_p (2, operands[0])"
[(parallel [(set (match_dup 2)
- (plus:HI (match_dup 2)
- (match_dup 1)))
+ (plus:ALL2 (match_dup 2)
+ (match_dup 1)))
(clobber (match_dup 3))])]
{
- operands[3] = simplify_gen_subreg (QImode, operands[0], HImode, 0);
+ operands[3] = simplify_gen_subreg (QImode, operands[0], <MODE>mode, 0);
})
;; Same, but with reload to NO_LD_REGS
;; Combine *reload_inhi with *addhi3
(define_peephole2 ; addhi3_clobber
- [(parallel [(set (match_operand:HI 0 "l_register_operand" "")
- (match_operand:HI 1 "const_int_operand" ""))
+ [(parallel [(set (match_operand:ALL2 0 "l_register_operand" "")
+ (match_operand:ALL2 1 "const_operand" ""))
(clobber (match_operand:QI 2 "d_register_operand" ""))])
- (set (match_operand:HI 3 "l_register_operand" "")
- (plus:HI (match_dup 3)
- (match_dup 0)))]
+ (set (match_operand:ALL2 3 "l_register_operand" "")
+ (plus:ALL2 (match_dup 3)
+ (match_dup 0)))]
"peep2_reg_dead_p (2, operands[0])"
[(parallel [(set (match_dup 3)
- (plus:HI (match_dup 3)
- (match_dup 1)))
+ (plus:ALL2 (match_dup 3)
+ (match_dup 1)))
(clobber (match_dup 2))])])
-(define_insn "addhi3_clobber"
- [(set (match_operand:HI 0 "register_operand" "=!w,d,r")
- (plus:HI (match_operand:HI 1 "register_operand" "%0,0,0")
- (match_operand:HI 2 "const_int_operand" "IJ,n,n")))
- (clobber (match_scratch:QI 3 "=X,X,&d"))]
+;; "addhi3_clobber"
+;; "addhq3_clobber" "adduhq3_clobber"
+;; "addha3_clobber" "adduha3_clobber"
+(define_insn "add<mode>3_clobber"
+ [(set (match_operand:ALL2 0 "register_operand" "=!w ,d ,r")
+ (plus:ALL2 (match_operand:ALL2 1 "register_operand" "%0 ,0 ,0")
+ (match_operand:ALL2 2 "const_operand" "IJ YIJ,n Ynn,n Ynn")))
+ (clobber (match_scratch:QI 3 "=X ,X ,&d"))]
""
{
gcc_assert (REGNO (operands[0]) == REGNO (operands[1]));
@@ -1198,29 +1245,24 @@ (define_insn "addhi3_clobber"
(set_attr "cc" "out_plus")])
-(define_insn "addsi3"
- [(set (match_operand:SI 0 "register_operand" "=r,d ,d,r")
- (plus:SI (match_operand:SI 1 "register_operand" "%0,0 ,0,0")
- (match_operand:SI 2 "nonmemory_operand" "r,s ,n,n")))
- (clobber (match_scratch:QI 3 "=X,X ,X,&d"))]
+;; "addsi3"
+;; "addsq3" "addusq3"
+;; "addsa3" "addusa3"
+(define_insn "add<mode>3"
+ [(set (match_operand:ALL4 0 "register_operand" "=r,d ,r")
+ (plus:ALL4 (match_operand:ALL4 1 "register_operand" "%0,0 ,0")
+ (match_operand:ALL4 2 "nonmemory_operand" "r,i ,n Ynn")))
+ (clobber (match_scratch:QI 3 "=X,X ,&d"))]
""
{
- static const char * const asm_code[] =
- {
- "add %A0,%A2\;adc %B0,%B2\;adc %C0,%C2\;adc %D0,%D2",
- "subi %0,lo8(-(%2))\;sbci %B0,hi8(-(%2))\;sbci %C0,hlo8(-(%2))\;sbci %D0,hhi8(-(%2))",
- "",
- ""
- };
-
- if (*asm_code[which_alternative])
- return asm_code[which_alternative];
+ if (REG_P (operands[2]))
+ return "add %A0,%A2\;adc %B0,%B2\;adc %C0,%C2\;adc %D0,%D2";
return avr_out_plus (operands, NULL, NULL);
}
- [(set_attr "length" "4,4,4,8")
- (set_attr "adjust_len" "*,*,out_plus,out_plus")
- (set_attr "cc" "set_n,set_czn,out_plus,out_plus")])
+ [(set_attr "length" "4,4,8")
+ (set_attr "adjust_len" "*,out_plus,out_plus")
+ (set_attr "cc" "set_n,out_plus,out_plus")])
(define_insn "*addpsi3_zero_extend.qi"
[(set (match_operand:PSI 0 "register_operand" "=r")
@@ -1329,27 +1371,38 @@ (define_insn "*subpsi3_sign_extend.hi"
;-----------------------------------------------------------------------------
; sub bytes
-(define_insn "subqi3"
- [(set (match_operand:QI 0 "register_operand" "=r,d")
- (minus:QI (match_operand:QI 1 "register_operand" "0,0")
- (match_operand:QI 2 "nonmemory_operand" "r,i")))]
+
+;; "subqi3"
+;; "subqq3" "subuqq3"
+(define_insn "sub<mode>3"
+ [(set (match_operand:ALL1 0 "register_operand" "=r,d ,r ,r ,r ,r")
+ (minus:ALL1 (match_operand:ALL1 1 "register_operand" "0,0 ,0 ,0 ,0 ,0")
+ (match_operand:ALL1 2 "nonmemory_or_const_operand" "r,n Ynn,Y01,Ym1,Y02,Ym2")))]
""
"@
sub %0,%2
- subi %0,lo8(%2)"
- [(set_attr "length" "1,1")
- (set_attr "cc" "set_czn,set_czn")])
+ subi %0,lo8(%2)
+ dec %0
+ inc %0
+ dec %0\;dec %0
+ inc %0\;inc %0"
+ [(set_attr "length" "1,1,1,1,2,2")
+ (set_attr "cc" "set_czn,set_czn,set_zn,set_zn,set_zn,set_zn")])
-(define_insn "subhi3"
- [(set (match_operand:HI 0 "register_operand" "=r,d")
- (minus:HI (match_operand:HI 1 "register_operand" "0,0")
- (match_operand:HI 2 "nonmemory_operand" "r,i")))]
+;; "subhi3"
+;; "subhq3" "subuhq3"
+;; "subha3" "subuha3"
+(define_insn "sub<mode>3"
+ [(set (match_operand:ALL2 0 "register_operand" "=r,d ,*r")
+ (minus:ALL2 (match_operand:ALL2 1 "register_operand" "0,0 ,0")
+ (match_operand:ALL2 2 "nonmemory_or_const_operand" "r,i Ynn,Ynn")))
+ (clobber (match_scratch:QI 3 "=X,X ,&d"))]
""
- "@
- sub %A0,%A2\;sbc %B0,%B2
- subi %A0,lo8(%2)\;sbci %B0,hi8(%2)"
- [(set_attr "length" "2,2")
- (set_attr "cc" "set_czn,set_czn")])
+ {
+ return avr_out_minus (operands, NULL, NULL);
+ }
+ [(set_attr "adjust_len" "minus")
+ (set_attr "cc" "minus")])
(define_insn "*subhi3_zero_extend1"
[(set (match_operand:HI 0 "register_operand" "=r")
@@ -1373,13 +1426,23 @@ (define_insn "*subhi3.sign_extend2"
[(set_attr "length" "5")
(set_attr "cc" "clobber")])
-(define_insn "subsi3"
- [(set (match_operand:SI 0 "register_operand" "=r")
- (minus:SI (match_operand:SI 1 "register_operand" "0")
- (match_operand:SI 2 "register_operand" "r")))]
+;; "subsi3"
+;; "subsq3" "subusq3"
+;; "subsa3" "subusa3"
+(define_insn "sub<mode>3"
+ [(set (match_operand:ALL4 0 "register_operand" "=r,d ,r")
+ (minus:ALL4 (match_operand:ALL4 1 "register_operand" "0,0 ,0")
+ (match_operand:ALL4 2 "nonmemory_or_const_operand" "r,n Ynn,Ynn")))
+ (clobber (match_scratch:QI 3 "=X,X ,&d"))]
""
- "sub %0,%2\;sbc %B0,%B2\;sbc %C0,%C2\;sbc %D0,%D2"
+ {
+ if (REG_P (operands[2]))
+ return "sub %0,%2\;sbc %B0,%B2\;sbc %C0,%C2\;sbc %D0,%D2";
+
+ return avr_out_minus (operands, NULL, NULL);
+ }
[(set_attr "length" "4")
+ (set_attr "adjust_len" "*,minus,minus")
(set_attr "cc" "set_czn")])
(define_insn "*subsi3_zero_extend"
@@ -3303,44 +3366,58 @@ (define_insn_and_split "*rotb<mode>"
;;<< << << << << << << << << << << << << << << << << << << << << << << << << <<
;; arithmetic shift left
-(define_expand "ashlqi3"
- [(set (match_operand:QI 0 "register_operand" "")
- (ashift:QI (match_operand:QI 1 "register_operand" "")
- (match_operand:QI 2 "nop_general_operand" "")))])
+;; "ashlqi3"
+;; "ashlqq3" "ashluqq3"
+(define_expand "ashl<mode>3"
+ [(set (match_operand:ALL1 0 "register_operand" "")
+ (ashift:ALL1 (match_operand:ALL1 1 "register_operand" "")
+ (match_operand:QI 2 "nop_general_operand" "")))])
(define_split ; ashlqi3_const4
- [(set (match_operand:QI 0 "d_register_operand" "")
- (ashift:QI (match_dup 0)
- (const_int 4)))]
+ [(set (match_operand:ALL1 0 "d_register_operand" "")
+ (ashift:ALL1 (match_dup 0)
+ (const_int 4)))]
""
- [(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4)))
- (set (match_dup 0) (and:QI (match_dup 0) (const_int -16)))]
- "")
+ [(set (match_dup 1)
+ (rotate:QI (match_dup 1)
+ (const_int 4)))
+ (set (match_dup 1)
+ (and:QI (match_dup 1)
+ (const_int -16)))]
+ {
+ operands[1] = avr_to_int_mode (operands[0]);
+ })
(define_split ; ashlqi3_const5
- [(set (match_operand:QI 0 "d_register_operand" "")
- (ashift:QI (match_dup 0)
- (const_int 5)))]
+ [(set (match_operand:ALL1 0 "d_register_operand" "")
+ (ashift:ALL1 (match_dup 0)
+ (const_int 5)))]
""
- [(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4)))
- (set (match_dup 0) (ashift:QI (match_dup 0) (const_int 1)))
- (set (match_dup 0) (and:QI (match_dup 0) (const_int -32)))]
- "")
+ [(set (match_dup 1) (rotate:QI (match_dup 1) (const_int 4)))
+ (set (match_dup 1) (ashift:QI (match_dup 1) (const_int 1)))
+ (set (match_dup 1) (and:QI (match_dup 1) (const_int -32)))]
+ {
+ operands[1] = avr_to_int_mode (operands[0]);
+ })
(define_split ; ashlqi3_const6
- [(set (match_operand:QI 0 "d_register_operand" "")
- (ashift:QI (match_dup 0)
- (const_int 6)))]
+ [(set (match_operand:ALL1 0 "d_register_operand" "")
+ (ashift:ALL1 (match_dup 0)
+ (const_int 6)))]
""
- [(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4)))
- (set (match_dup 0) (ashift:QI (match_dup 0) (const_int 2)))
- (set (match_dup 0) (and:QI (match_dup 0) (const_int -64)))]
- "")
+ [(set (match_dup 1) (rotate:QI (match_dup 1) (const_int 4)))
+ (set (match_dup 1) (ashift:QI (match_dup 1) (const_int 2)))
+ (set (match_dup 1) (and:QI (match_dup 1) (const_int -64)))]
+ {
+ operands[1] = avr_to_int_mode (operands[0]);
+ })
-(define_insn "*ashlqi3"
- [(set (match_operand:QI 0 "register_operand" "=r,r,r,r,!d,r,r")
- (ashift:QI (match_operand:QI 1 "register_operand" "0,0,0,0,0 ,0,0")
- (match_operand:QI 2 "nop_general_operand" "r,L,P,K,n ,n,Qm")))]
+;; "*ashlqi3"
+;; "*ashlqq3" "*ashluqq3"
+(define_insn "*ashl<mode>3"
+ [(set (match_operand:ALL1 0 "register_operand" "=r,r,r,r,!d,r,r")
+ (ashift:ALL1 (match_operand:ALL1 1 "register_operand" "0,0,0,0,0 ,0,0")
+ (match_operand:QI 2 "nop_general_operand" "r,L,P,K,n ,n,Qm")))]
""
{
return ashlqi3_out (insn, operands, NULL);
@@ -3349,10 +3426,10 @@ (define_insn "*ashlqi3"
(set_attr "adjust_len" "ashlqi")
(set_attr "cc" "clobber,none,set_czn,set_czn,set_czn,set_czn,clobber")])
-(define_insn "ashlhi3"
- [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r,r")
- (ashift:HI (match_operand:HI 1 "register_operand" "0,0,0,r,0,0,0")
- (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,n,Qm")))]
+(define_insn "ashl<mode>3"
+ [(set (match_operand:ALL2 0 "register_operand" "=r,r,r,r,r,r,r")
+ (ashift:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,0,r,0,0,0")
+ (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,n,Qm")))]
""
{
return ashlhi3_out (insn, operands, NULL);
@@ -3377,8 +3454,7 @@ (define_insn_and_split "*ashl<extend_su>
""
[(set (match_dup 0)
(ashift:QI (match_dup 1)
- (match_dup 2)))]
- "")
+ (match_dup 2)))])
;; ??? Combiner does not recognize that it could split the following insn;
;; presumably because he has no register handy?
@@ -3443,10 +3519,13 @@ (define_peephole2
})
-(define_insn "ashlsi3"
- [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r")
- (ashift:SI (match_operand:SI 1 "register_operand" "0,0,0,r,0,0,0")
- (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,n,Qm")))]
+;; "ashlsi3"
+;; "ashlsq3" "ashlusq3"
+;; "ashlsa3" "ashlusa3"
+(define_insn "ashl<mode>3"
+ [(set (match_operand:ALL4 0 "register_operand" "=r,r,r,r,r,r,r")
+ (ashift:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,0,r,0,0,0")
+ (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,n,Qm")))]
""
{
return ashlsi3_out (insn, operands, NULL);
@@ -3458,55 +3537,65 @@ (define_insn "ashlsi3"
;; Optimize if a scratch register from LD_REGS happens to be available.
(define_peephole2 ; ashlqi3_l_const4
- [(set (match_operand:QI 0 "l_register_operand" "")
- (ashift:QI (match_dup 0)
- (const_int 4)))
+ [(set (match_operand:ALL1 0 "l_register_operand" "")
+ (ashift:ALL1 (match_dup 0)
+ (const_int 4)))
(match_scratch:QI 1 "d")]
""
- [(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4)))
+ [(set (match_dup 2) (rotate:QI (match_dup 2) (const_int 4)))
(set (match_dup 1) (const_int -16))
- (set (match_dup 0) (and:QI (match_dup 0) (match_dup 1)))]
- "")
+ (set (match_dup 2) (and:QI (match_dup 2) (match_dup 1)))]
+ {
+ operands[2] = avr_to_int_mode (operands[0]);
+ })
(define_peephole2 ; ashlqi3_l_const5
- [(set (match_operand:QI 0 "l_register_operand" "")
- (ashift:QI (match_dup 0)
- (const_int 5)))
+ [(set (match_operand:ALL1 0 "l_register_operand" "")
+ (ashift:ALL1 (match_dup 0)
+ (const_int 5)))
(match_scratch:QI 1 "d")]
""
- [(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4)))
- (set (match_dup 0) (ashift:QI (match_dup 0) (const_int 1)))
+ [(set (match_dup 2) (rotate:QI (match_dup 2) (const_int 4)))
+ (set (match_dup 2) (ashift:QI (match_dup 2) (const_int 1)))
(set (match_dup 1) (const_int -32))
- (set (match_dup 0) (and:QI (match_dup 0) (match_dup 1)))]
- "")
+ (set (match_dup 2) (and:QI (match_dup 2) (match_dup 1)))]
+ {
+ operands[2] = avr_to_int_mode (operands[0]);
+ })
(define_peephole2 ; ashlqi3_l_const6
- [(set (match_operand:QI 0 "l_register_operand" "")
- (ashift:QI (match_dup 0)
- (const_int 6)))
+ [(set (match_operand:ALL1 0 "l_register_operand" "")
+ (ashift:ALL1 (match_dup 0)
+ (const_int 6)))
(match_scratch:QI 1 "d")]
""
- [(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4)))
- (set (match_dup 0) (ashift:QI (match_dup 0) (const_int 2)))
+ [(set (match_dup 2) (rotate:QI (match_dup 2) (const_int 4)))
+ (set (match_dup 2) (ashift:QI (match_dup 2) (const_int 2)))
(set (match_dup 1) (const_int -64))
- (set (match_dup 0) (and:QI (match_dup 0) (match_dup 1)))]
- "")
+ (set (match_dup 2) (and:QI (match_dup 2) (match_dup 1)))]
+ {
+ operands[2] = avr_to_int_mode (operands[0]);
+ })
(define_peephole2
[(match_scratch:QI 3 "d")
- (set (match_operand:HI 0 "register_operand" "")
- (ashift:HI (match_operand:HI 1 "register_operand" "")
- (match_operand:QI 2 "const_int_operand" "")))]
+ (set (match_operand:ALL2 0 "register_operand" "")
+ (ashift:ALL2 (match_operand:ALL2 1 "register_operand" "")
+ (match_operand:QI 2 "const_int_operand" "")))]
""
- [(parallel [(set (match_dup 0) (ashift:HI (match_dup 1) (match_dup 2)))
- (clobber (match_dup 3))])]
- "")
-
-(define_insn "*ashlhi3_const"
- [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r")
- (ashift:HI (match_operand:HI 1 "register_operand" "0,0,r,0,0")
- (match_operand:QI 2 "const_int_operand" "L,P,O,K,n")))
- (clobber (match_scratch:QI 3 "=X,X,X,X,&d"))]
+ [(parallel [(set (match_dup 0)
+ (ashift:ALL2 (match_dup 1)
+ (match_dup 2)))
+ (clobber (match_dup 3))])])
+
+;; "*ashlhi3_const"
+;; "*ashlhq3_const" "*ashluhq3_const"
+;; "*ashlha3_const" "*ashluha3_const"
+(define_insn "*ashl<mode>3_const"
+ [(set (match_operand:ALL2 0 "register_operand" "=r,r,r,r,r")
+ (ashift:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,r,0,0")
+ (match_operand:QI 2 "const_int_operand" "L,P,O,K,n")))
+ (clobber (match_scratch:QI 3 "=X,X,X,X,&d"))]
"reload_completed"
{
return ashlhi3_out (insn, operands, NULL);
@@ -3517,19 +3606,24 @@ (define_insn "*ashlhi3_const"
(define_peephole2
[(match_scratch:QI 3 "d")
- (set (match_operand:SI 0 "register_operand" "")
- (ashift:SI (match_operand:SI 1 "register_operand" "")
- (match_operand:QI 2 "const_int_operand" "")))]
+ (set (match_operand:ALL4 0 "register_operand" "")
+ (ashift:ALL4 (match_operand:ALL4 1 "register_operand" "")
+ (match_operand:QI 2 "const_int_operand" "")))]
""
- [(parallel [(set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2)))
+ [(parallel [(set (match_dup 0)
+ (ashift:ALL4 (match_dup 1)
+ (match_dup 2)))
(clobber (match_dup 3))])]
"")
-(define_insn "*ashlsi3_const"
- [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
- (ashift:SI (match_operand:SI 1 "register_operand" "0,0,r,0")
- (match_operand:QI 2 "const_int_operand" "L,P,O,n")))
- (clobber (match_scratch:QI 3 "=X,X,X,&d"))]
+;; "*ashlsi3_const"
+;; "*ashlsq3_const" "*ashlusq3_const"
+;; "*ashlsa3_const" "*ashlusa3_const"
+(define_insn "*ashl<mode>3_const"
+ [(set (match_operand:ALL4 0 "register_operand" "=r,r,r,r")
+ (ashift:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,r,0")
+ (match_operand:QI 2 "const_int_operand" "L,P,O,n")))
+ (clobber (match_scratch:QI 3 "=X,X,X,&d"))]
"reload_completed"
{
return ashlsi3_out (insn, operands, NULL);
@@ -3580,10 +3674,12 @@ (define_insn "*ashlpsi3"
;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >>
;; arithmetic shift right
-(define_insn "ashrqi3"
- [(set (match_operand:QI 0 "register_operand" "=r,r,r,r,r ,r ,r")
- (ashiftrt:QI (match_operand:QI 1 "register_operand" "0,0,0,0,0 ,0 ,0")
- (match_operand:QI 2 "nop_general_operand" "r,L,P,K,C03 C04 C05,C06 C07,Qm")))]
+;; "ashrqi3"
+;; "ashrqq3" "ashruqq3"
+(define_insn "ashr<mode>3"
+ [(set (match_operand:ALL1 0 "register_operand" "=r,r,r,r,r ,r ,r")
+ (ashiftrt:ALL1 (match_operand:ALL1 1 "register_operand" "0,0,0,0,0 ,0 ,0")
+ (match_operand:QI 2 "nop_general_operand" "r,L,P,K,C03 C04 C05,C06 C07,Qm")))]
""
{
return ashrqi3_out (insn, operands, NULL);
@@ -3592,10 +3688,13 @@ (define_insn "ashrqi3"
(set_attr "adjust_len" "ashrqi")
(set_attr "cc" "clobber,none,set_czn,set_czn,set_czn,clobber,clobber")])
-(define_insn "ashrhi3"
- [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r,r")
- (ashiftrt:HI (match_operand:HI 1 "register_operand" "0,0,0,r,0,0,0")
- (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,n,Qm")))]
+;; "ashrhi3"
+;; "ashrhq3" "ashruhq3"
+;; "ashrha3" "ashruha3"
+(define_insn "ashr<mode>3"
+ [(set (match_operand:ALL2 0 "register_operand" "=r,r,r,r,r,r,r")
+ (ashiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,0,r,0,0,0")
+ (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,n,Qm")))]
""
{
return ashrhi3_out (insn, operands, NULL);
@@ -3616,10 +3715,13 @@ (define_insn "ashrpsi3"
[(set_attr "adjust_len" "ashrpsi")
(set_attr "cc" "clobber")])
-(define_insn "ashrsi3"
- [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r")
- (ashiftrt:SI (match_operand:SI 1 "register_operand" "0,0,0,r,0,0,0")
- (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,n,Qm")))]
+;; "ashrsi3"
+;; "ashrsq3" "ashrusq3"
+;; "ashrsa3" "ashrusa3"
+(define_insn "ashr<mode>3"
+ [(set (match_operand:ALL4 0 "register_operand" "=r,r,r,r,r,r,r")
+ (ashiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,0,r,0,0,0")
+ (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,n,Qm")))]
""
{
return ashrsi3_out (insn, operands, NULL);
@@ -3632,19 +3734,23 @@ (define_insn "ashrsi3"
(define_peephole2
[(match_scratch:QI 3 "d")
- (set (match_operand:HI 0 "register_operand" "")
- (ashiftrt:HI (match_operand:HI 1 "register_operand" "")
- (match_operand:QI 2 "const_int_operand" "")))]
+ (set (match_operand:ALL2 0 "register_operand" "")
+ (ashiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "")
+ (match_operand:QI 2 "const_int_operand" "")))]
""
- [(parallel [(set (match_dup 0) (ashiftrt:HI (match_dup 1) (match_dup 2)))
- (clobber (match_dup 3))])]
- "")
-
-(define_insn "*ashrhi3_const"
- [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r")
- (ashiftrt:HI (match_operand:HI 1 "register_operand" "0,0,r,0,0")
- (match_operand:QI 2 "const_int_operand" "L,P,O,K,n")))
- (clobber (match_scratch:QI 3 "=X,X,X,X,&d"))]
+ [(parallel [(set (match_dup 0)
+ (ashiftrt:ALL2 (match_dup 1)
+ (match_dup 2)))
+ (clobber (match_dup 3))])])
+
+;; "*ashrhi3_const"
+;; "*ashrhq3_const" "*ashruhq3_const"
+;; "*ashrha3_const" "*ashruha3_const"
+(define_insn "*ashr<mode>3_const"
+ [(set (match_operand:ALL2 0 "register_operand" "=r,r,r,r,r")
+ (ashiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,r,0,0")
+ (match_operand:QI 2 "const_int_operand" "L,P,O,K,n")))
+ (clobber (match_scratch:QI 3 "=X,X,X,X,&d"))]
"reload_completed"
{
return ashrhi3_out (insn, operands, NULL);
@@ -3655,19 +3761,23 @@ (define_insn "*ashrhi3_const"
(define_peephole2
[(match_scratch:QI 3 "d")
- (set (match_operand:SI 0 "register_operand" "")
- (ashiftrt:SI (match_operand:SI 1 "register_operand" "")
- (match_operand:QI 2 "const_int_operand" "")))]
+ (set (match_operand:ALL4 0 "register_operand" "")
+ (ashiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "")
+ (match_operand:QI 2 "const_int_operand" "")))]
""
- [(parallel [(set (match_dup 0) (ashiftrt:SI (match_dup 1) (match_dup 2)))
- (clobber (match_dup 3))])]
- "")
-
-(define_insn "*ashrsi3_const"
- [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
- (ashiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r,0")
- (match_operand:QI 2 "const_int_operand" "L,P,O,n")))
- (clobber (match_scratch:QI 3 "=X,X,X,&d"))]
+ [(parallel [(set (match_dup 0)
+ (ashiftrt:ALL4 (match_dup 1)
+ (match_dup 2)))
+ (clobber (match_dup 3))])])
+
+;; "*ashrsi3_const"
+;; "*ashrsq3_const" "*ashrusq3_const"
+;; "*ashrsa3_const" "*ashrusa3_const"
+(define_insn "*ashr<mode>3_const"
+ [(set (match_operand:ALL4 0 "register_operand" "=r,r,r,r")
+ (ashiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,r,0")
+ (match_operand:QI 2 "const_int_operand" "L,P,O,n")))
+ (clobber (match_scratch:QI 3 "=X,X,X,&d"))]
"reload_completed"
{
return ashrsi3_out (insn, operands, NULL);
@@ -3679,44 +3789,59 @@ (define_insn "*ashrsi3_const"
;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >>
;; logical shift right
-(define_expand "lshrqi3"
- [(set (match_operand:QI 0 "register_operand" "")
- (lshiftrt:QI (match_operand:QI 1 "register_operand" "")
- (match_operand:QI 2 "nop_general_operand" "")))])
+;; "lshrqi3"
+;; "lshrqq3 "lshruqq3"
+(define_expand "lshr<mode>3"
+ [(set (match_operand:ALL1 0 "register_operand" "")
+ (lshiftrt:ALL1 (match_operand:ALL1 1 "register_operand" "")
+ (match_operand:QI 2 "nop_general_operand" "")))])
(define_split ; lshrqi3_const4
- [(set (match_operand:QI 0 "d_register_operand" "")
- (lshiftrt:QI (match_dup 0)
- (const_int 4)))]
+ [(set (match_operand:ALL1 0 "d_register_operand" "")
+ (lshiftrt:ALL1 (match_dup 0)
+ (const_int 4)))]
""
- [(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4)))
- (set (match_dup 0) (and:QI (match_dup 0) (const_int 15)))]
- "")
+ [(set (match_dup 1)
+ (rotate:QI (match_dup 1)
+ (const_int 4)))
+ (set (match_dup 1)
+ (and:QI (match_dup 1)
+ (const_int 15)))]
+ {
+ operands[1] = avr_to_int_mode (operands[0]);
+ })
(define_split ; lshrqi3_const5
- [(set (match_operand:QI 0 "d_register_operand" "")
- (lshiftrt:QI (match_dup 0)
- (const_int 5)))]
- ""
- [(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4)))
- (set (match_dup 0) (lshiftrt:QI (match_dup 0) (const_int 1)))
- (set (match_dup 0) (and:QI (match_dup 0) (const_int 7)))]
- "")
+ [(set (match_operand:ALL1 0 "d_register_operand" "")
+ (lshiftrt:ALL1 (match_dup 0)
+ (const_int 5)))]
+ ""
+ [(set (match_dup 1) (rotate:QI (match_dup 1) (const_int 4)))
+ (set (match_dup 1) (lshiftrt:QI (match_dup 1) (const_int 1)))
+ (set (match_dup 1) (and:QI (match_dup 1) (const_int 7)))]
+ {
+ operands[1] = avr_to_int_mode (operands[0]);
+ })
(define_split ; lshrqi3_const6
[(set (match_operand:QI 0 "d_register_operand" "")
(lshiftrt:QI (match_dup 0)
(const_int 6)))]
""
- [(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4)))
- (set (match_dup 0) (lshiftrt:QI (match_dup 0) (const_int 2)))
- (set (match_dup 0) (and:QI (match_dup 0) (const_int 3)))]
- "")
+ [(set (match_dup 1) (rotate:QI (match_dup 1) (const_int 4)))
+ (set (match_dup 1) (lshiftrt:QI (match_dup 1) (const_int 2)))
+ (set (match_dup 1) (and:QI (match_dup 1) (const_int 3)))]
+ {
+ operands[1] = avr_to_int_mode (operands[0]);
+ })
-(define_insn "*lshrqi3"
- [(set (match_operand:QI 0 "register_operand" "=r,r,r,r,!d,r,r")
- (lshiftrt:QI (match_operand:QI 1 "register_operand" "0,0,0,0,0 ,0,0")
- (match_operand:QI 2 "nop_general_operand" "r,L,P,K,n ,n,Qm")))]
+;; "*lshrqi3"
+;; "*lshrqq3"
+;; "*lshruqq3"
+(define_insn "*lshr<mode>3"
+ [(set (match_operand:ALL1 0 "register_operand" "=r,r,r,r,!d,r,r")
+ (lshiftrt:ALL1 (match_operand:ALL1 1 "register_operand" "0,0,0,0,0 ,0,0")
+ (match_operand:QI 2 "nop_general_operand" "r,L,P,K,n ,n,Qm")))]
""
{
return lshrqi3_out (insn, operands, NULL);
@@ -3725,10 +3850,13 @@ (define_insn "*lshrqi3"
(set_attr "adjust_len" "lshrqi")
(set_attr "cc" "clobber,none,set_czn,set_czn,set_czn,set_czn,clobber")])
-(define_insn "lshrhi3"
- [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r,r")
- (lshiftrt:HI (match_operand:HI 1 "register_operand" "0,0,0,r,0,0,0")
- (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,n,Qm")))]
+;; "lshrhi3"
+;; "lshrhq3" "lshruhq3"
+;; "lshrha3" "lshruha3"
+(define_insn "lshr<mode>3"
+ [(set (match_operand:ALL2 0 "register_operand" "=r,r,r,r,r,r,r")
+ (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,0,r,0,0,0")
+ (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,n,Qm")))]
""
{
return lshrhi3_out (insn, operands, NULL);
@@ -3749,10 +3877,13 @@ (define_insn "lshrpsi3"
[(set_attr "adjust_len" "lshrpsi")
(set_attr "cc" "clobber")])
-(define_insn "lshrsi3"
- [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r")
- (lshiftrt:SI (match_operand:SI 1 "register_operand" "0,0,0,r,0,0,0")
- (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,n,Qm")))]
+;; "lshrsi3"
+;; "lshrsq3" "lshrusq3"
+;; "lshrsa3" "lshrusa3"
+(define_insn "lshr<mode>3"
+ [(set (match_operand:ALL4 0 "register_operand" "=r,r,r,r,r,r,r")
+ (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,0,r,0,0,0")
+ (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,n,Qm")))]
""
{
return lshrsi3_out (insn, operands, NULL);
@@ -3764,55 +3895,65 @@ (define_insn "lshrsi3"
;; Optimize if a scratch register from LD_REGS happens to be available.
(define_peephole2 ; lshrqi3_l_const4
- [(set (match_operand:QI 0 "l_register_operand" "")
- (lshiftrt:QI (match_dup 0)
- (const_int 4)))
+ [(set (match_operand:ALL1 0 "l_register_operand" "")
+ (lshiftrt:ALL1 (match_dup 0)
+ (const_int 4)))
(match_scratch:QI 1 "d")]
""
- [(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4)))
+ [(set (match_dup 2) (rotate:QI (match_dup 2) (const_int 4)))
(set (match_dup 1) (const_int 15))
- (set (match_dup 0) (and:QI (match_dup 0) (match_dup 1)))]
- "")
+ (set (match_dup 2) (and:QI (match_dup 2) (match_dup 1)))]
+ {
+ operands[2] = avr_to_int_mode (operands[0]);
+ })
(define_peephole2 ; lshrqi3_l_const5
- [(set (match_operand:QI 0 "l_register_operand" "")
- (lshiftrt:QI (match_dup 0)
- (const_int 5)))
+ [(set (match_operand:ALL1 0 "l_register_operand" "")
+ (lshiftrt:ALL1 (match_dup 0)
+ (const_int 5)))
(match_scratch:QI 1 "d")]
""
- [(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4)))
- (set (match_dup 0) (lshiftrt:QI (match_dup 0) (const_int 1)))
+ [(set (match_dup 2) (rotate:QI (match_dup 2) (const_int 4)))
+ (set (match_dup 2) (lshiftrt:QI (match_dup 2) (const_int 1)))
(set (match_dup 1) (const_int 7))
- (set (match_dup 0) (and:QI (match_dup 0) (match_dup 1)))]
- "")
+ (set (match_dup 2) (and:QI (match_dup 2) (match_dup 1)))]
+ {
+ operands[2] = avr_to_int_mode (operands[0]);
+ })
(define_peephole2 ; lshrqi3_l_const6
- [(set (match_operand:QI 0 "l_register_operand" "")
- (lshiftrt:QI (match_dup 0)
- (const_int 6)))
+ [(set (match_operand:ALL1 0 "l_register_operand" "")
+ (lshiftrt:ALL1 (match_dup 0)
+ (const_int 6)))
(match_scratch:QI 1 "d")]
""
- [(set (match_dup 0) (rotate:QI (match_dup 0) (const_int 4)))
- (set (match_dup 0) (lshiftrt:QI (match_dup 0) (const_int 2)))
+ [(set (match_dup 2) (rotate:QI (match_dup 2) (const_int 4)))
+ (set (match_dup 2) (lshiftrt:QI (match_dup 2) (const_int 2)))
(set (match_dup 1) (const_int 3))
- (set (match_dup 0) (and:QI (match_dup 0) (match_dup 1)))]
- "")
+ (set (match_dup 2) (and:QI (match_dup 2) (match_dup 1)))]
+ {
+ operands[2] = avr_to_int_mode (operands[0]);
+ })
(define_peephole2
[(match_scratch:QI 3 "d")
- (set (match_operand:HI 0 "register_operand" "")
- (lshiftrt:HI (match_operand:HI 1 "register_operand" "")
- (match_operand:QI 2 "const_int_operand" "")))]
+ (set (match_operand:ALL2 0 "register_operand" "")
+ (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "")
+ (match_operand:QI 2 "const_int_operand" "")))]
""
- [(parallel [(set (match_dup 0) (lshiftrt:HI (match_dup 1) (match_dup 2)))
- (clobber (match_dup 3))])]
- "")
-
-(define_insn "*lshrhi3_const"
- [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r")
- (lshiftrt:HI (match_operand:HI 1 "register_operand" "0,0,r,0,0")
- (match_operand:QI 2 "const_int_operand" "L,P,O,K,n")))
- (clobber (match_scratch:QI 3 "=X,X,X,X,&d"))]
+ [(parallel [(set (match_dup 0)
+ (lshiftrt:ALL2 (match_dup 1)
+ (match_dup 2)))
+ (clobber (match_dup 3))])])
+
+;; "*lshrhi3_const"
+;; "*lshrhq3_const" "*lshruhq3_const"
+;; "*lshrha3_const" "*lshruha3_const"
+(define_insn "*lshr<mode>3_const"
+ [(set (match_operand:ALL2 0 "register_operand" "=r,r,r,r,r")
+ (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,r,0,0")
+ (match_operand:QI 2 "const_int_operand" "L,P,O,K,n")))
+ (clobber (match_scratch:QI 3 "=X,X,X,X,&d"))]
"reload_completed"
{
return lshrhi3_out (insn, operands, NULL);
@@ -3823,19 +3964,23 @@ (define_insn "*lshrhi3_const"
(define_peephole2
[(match_scratch:QI 3 "d")
- (set (match_operand:SI 0 "register_operand" "")
- (lshiftrt:SI (match_operand:SI 1 "register_operand" "")
- (match_operand:QI 2 "const_int_operand" "")))]
+ (set (match_operand:ALL4 0 "register_operand" "")
+ (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "")
+ (match_operand:QI 2 "const_int_operand" "")))]
""
- [(parallel [(set (match_dup 0) (lshiftrt:SI (match_dup 1) (match_dup 2)))
- (clobber (match_dup 3))])]
- "")
-
-(define_insn "*lshrsi3_const"
- [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
- (lshiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r,0")
- (match_operand:QI 2 "const_int_operand" "L,P,O,n")))
- (clobber (match_scratch:QI 3 "=X,X,X,&d"))]
+ [(parallel [(set (match_dup 0)
+ (lshiftrt:ALL4 (match_dup 1)
+ (match_dup 2)))
+ (clobber (match_dup 3))])])
+
+;; "*lshrsi3_const"
+;; "*lshrsq3_const" "*lshrusq3_const"
+;; "*lshrsa3_const" "*lshrusa3_const"
+(define_insn "*lshr<mode>3_const"
+ [(set (match_operand:ALL4 0 "register_operand" "=r,r,r,r")
+ (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,r,0")
+ (match_operand:QI 2 "const_int_operand" "L,P,O,n")))
+ (clobber (match_scratch:QI 3 "=X,X,X,&d"))]
"reload_completed"
{
return lshrsi3_out (insn, operands, NULL);
@@ -4278,24 +4423,29 @@ (define_insn "*negated_tstsi"
[(set_attr "cc" "compare")
(set_attr "length" "4")])
-(define_insn "*reversed_tstsi"
+;; "*reversed_tstsi"
+;; "*reversed_tstsq" "*reversed_tstusq"
+;; "*reversed_tstsa" "*reversed_tstusa"
+(define_insn "*reversed_tst<mode>"
[(set (cc0)
- (compare (const_int 0)
- (match_operand:SI 0 "register_operand" "r")))
- (clobber (match_scratch:QI 1 "=X"))]
- ""
- "cp __zero_reg__,%A0
- cpc __zero_reg__,%B0
- cpc __zero_reg__,%C0
- cpc __zero_reg__,%D0"
+ (compare (match_operand:ALL4 0 "const0_operand" "Y00")
+ (match_operand:ALL4 1 "register_operand" "r")))
+ (clobber (match_scratch:QI 2 "=X"))]
+ ""
+ "cp __zero_reg__,%A1
+ cpc __zero_reg__,%B1
+ cpc __zero_reg__,%C1
+ cpc __zero_reg__,%D1"
[(set_attr "cc" "compare")
(set_attr "length" "4")])
-(define_insn "*cmpqi"
+;; "*cmpqi"
+;; "*cmpqq" "*cmpuqq"
+(define_insn "*cmp<mode>"
[(set (cc0)
- (compare (match_operand:QI 0 "register_operand" "r,r,d")
- (match_operand:QI 1 "nonmemory_operand" "L,r,i")))]
+ (compare (match_operand:ALL1 0 "register_operand" "r ,r,d")
+ (match_operand:ALL1 1 "nonmemory_operand" "Y00,r,i")))]
""
"@
tst %0
@@ -4313,11 +4463,14 @@ (define_insn "*cmpqi_sign_extend"
[(set_attr "cc" "compare")
(set_attr "length" "1")])
-(define_insn "*cmphi"
+;; "*cmphi"
+;; "*cmphq" "*cmpuhq"
+;; "*cmpha" "*cmpuha"
+(define_insn "*cmp<mode>"
[(set (cc0)
- (compare (match_operand:HI 0 "register_operand" "!w,r,r,d ,r ,d,r")
- (match_operand:HI 1 "nonmemory_operand" "L ,L,r,s ,s ,M,n")))
- (clobber (match_scratch:QI 2 "=X ,X,X,&d,&d ,X,&d"))]
+ (compare (match_operand:ALL2 0 "register_operand" "!w ,r ,r,d ,r ,d,r")
+ (match_operand:ALL2 1 "nonmemory_operand" "Y00,Y00,r,s ,s ,M,n Ynn")))
+ (clobber (match_scratch:QI 2 "=X ,X ,X,&d,&d ,X,&d"))]
""
{
switch (which_alternative)
@@ -4330,11 +4483,15 @@ (define_insn "*cmphi"
return "cp %A0,%A1\;cpc %B0,%B1";
case 3:
+ if (<MODE>mode != HImode)
+ break;
return reg_unused_after (insn, operands[0])
? "subi %A0,lo8(%1)\;sbci %B0,hi8(%1)"
: "ldi %2,hi8(%1)\;cpi %A0,lo8(%1)\;cpc %B0,%2";
case 4:
+ if (<MODE>mode != HImode)
+ break;
return "ldi %2,lo8(%1)\;cp %A0,%2\;ldi %2,hi8(%1)\;cpc %B0,%2";
}
@@ -4374,11 +4531,14 @@ (define_insn "*cmppsi"
(set_attr "length" "3,3,5,6,3,7")
(set_attr "adjust_len" "tstpsi,*,*,*,compare,compare")])
-(define_insn "*cmpsi"
+;; "*cmpsi"
+;; "*cmpsq" "*cmpusq"
+;; "*cmpsa" "*cmpusa"
+(define_insn "*cmp<mode>"
[(set (cc0)
- (compare (match_operand:SI 0 "register_operand" "r,r ,d,r ,r")
- (match_operand:SI 1 "nonmemory_operand" "L,r ,M,M ,n")))
- (clobber (match_scratch:QI 2 "=X,X ,X,&d,&d"))]
+ (compare (match_operand:ALL4 0 "register_operand" "r ,r ,d,r ,r")
+ (match_operand:ALL4 1 "nonmemory_operand" "Y00,r ,M,M ,n Ynn")))
+ (clobber (match_scratch:QI 2 "=X ,X ,X,&d,&d"))]
""
{
if (0 == which_alternative)
@@ -4398,55 +4558,33 @@ (define_insn "*cmpsi"
;; ----------------------------------------------------------------------
;; Conditional jump instructions
-(define_expand "cbranchsi4"
- [(parallel [(set (cc0)
- (compare (match_operand:SI 1 "register_operand" "")
- (match_operand:SI 2 "nonmemory_operand" "")))
- (clobber (match_scratch:QI 4 ""))])
+;; "cbranchqi4"
+;; "cbranchqq4" "cbranchuqq4"
+(define_expand "cbranch<mode>4"
+ [(set (cc0)
+ (compare (match_operand:ALL1 1 "register_operand" "")
+ (match_operand:ALL1 2 "nonmemory_operand" "")))
(set (pc)
(if_then_else
- (match_operator 0 "ordered_comparison_operator" [(cc0)
- (const_int 0)])
- (label_ref (match_operand 3 "" ""))
- (pc)))]
- "")
-
-(define_expand "cbranchpsi4"
- [(parallel [(set (cc0)
- (compare (match_operand:PSI 1 "register_operand" "")
- (match_operand:PSI 2 "nonmemory_operand" "")))
- (clobber (match_scratch:QI 4 ""))])
- (set (pc)
- (if_then_else (match_operator 0 "ordered_comparison_operator" [(cc0)
- (const_int 0)])
- (label_ref (match_operand 3 "" ""))
- (pc)))]
- "")
+ (match_operator 0 "ordered_comparison_operator" [(cc0)
+ (const_int 0)])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))])
-(define_expand "cbranchhi4"
+;; "cbranchhi4" "cbranchhq4" "cbranchuhq4" "cbranchha4" "cbranchuha4"
+;; "cbranchsi4" "cbranchsq4" "cbranchusq4" "cbranchsa4" "cbranchusa4"
+;; "cbranchpsi4"
+(define_expand "cbranch<mode>4"
[(parallel [(set (cc0)
- (compare (match_operand:HI 1 "register_operand" "")
- (match_operand:HI 2 "nonmemory_operand" "")))
+ (compare (match_operand:ORDERED234 1 "register_operand" "")
+ (match_operand:ORDERED234 2 "nonmemory_operand" "")))
(clobber (match_scratch:QI 4 ""))])
(set (pc)
(if_then_else
- (match_operator 0 "ordered_comparison_operator" [(cc0)
- (const_int 0)])
- (label_ref (match_operand 3 "" ""))
- (pc)))]
- "")
-
-(define_expand "cbranchqi4"
- [(set (cc0)
- (compare (match_operand:QI 1 "register_operand" "")
- (match_operand:QI 2 "nonmemory_operand" "")))
- (set (pc)
- (if_then_else
- (match_operator 0 "ordered_comparison_operator" [(cc0)
- (const_int 0)])
- (label_ref (match_operand 3 "" ""))
- (pc)))]
- "")
+ (match_operator 0 "ordered_comparison_operator" [(cc0)
+ (const_int 0)])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))])
;; Test a single bit in a QI/HI/SImode register.
@@ -4477,7 +4615,7 @@ (define_insn "*sbrx_branch<mode>"
(const_int 4))))
(set_attr "cc" "clobber")])
-;; Same test based on Bitwise AND RTL. Keep this incase gcc changes patterns.
+;; Same test based on bitwise AND. Keep this in case gcc changes patterns.
;; or for old peepholes.
;; Fixme - bitwise Mask will not work for DImode
@@ -4492,12 +4630,12 @@ (define_insn "*sbrx_and_branch<mode>"
(label_ref (match_operand 3 "" ""))
(pc)))]
""
-{
+ {
HOST_WIDE_INT bitnumber;
bitnumber = exact_log2 (GET_MODE_MASK (<MODE>mode) & INTVAL (operands[2]));
operands[2] = GEN_INT (bitnumber);
return avr_out_sbxx_branch (insn, operands);
-}
+ }
[(set (attr "length")
(if_then_else (and (ge (minus (pc) (match_dup 3)) (const_int -2046))
(le (minus (pc) (match_dup 3)) (const_int 2046)))
@@ -4837,9 +4975,10 @@ (define_insn "*tablejump"
(define_expand "casesi"
- [(set (match_dup 6)
- (minus:HI (subreg:HI (match_operand:SI 0 "register_operand" "") 0)
- (match_operand:HI 1 "register_operand" "")))
+ [(parallel [(set (match_dup 6)
+ (minus:HI (subreg:HI (match_operand:SI 0 "register_operand" "") 0)
+ (match_operand:HI 1 "register_operand" "")))
+ (clobber (scratch:QI))])
(parallel [(set (cc0)
(compare (match_dup 6)
(match_operand:HI 2 "register_operand" "")))
@@ -5201,8 +5340,8 @@ (define_peephole ; "*dec-and-branchqi!=-
(define_peephole ; "*cpse.eq"
[(set (cc0)
- (compare (match_operand:QI 1 "register_operand" "r,r")
- (match_operand:QI 2 "reg_or_0_operand" "r,L")))
+ (compare (match_operand:ALL1 1 "register_operand" "r,r")
+ (match_operand:ALL1 2 "reg_or_0_operand" "r,Y00")))
(set (pc)
(if_then_else (eq (cc0)
(const_int 0))
@@ -5236,8 +5375,8 @@ (define_peephole ; "*cpse.eq"
(define_peephole ; "*cpse.ne"
[(set (cc0)
- (compare (match_operand:QI 1 "register_operand" "")
- (match_operand:QI 2 "reg_or_0_operand" "")))
+ (compare (match_operand:ALL1 1 "register_operand" "")
+ (match_operand:ALL1 2 "reg_or_0_operand" "")))
(set (pc)
(if_then_else (ne (cc0)
(const_int 0))
@@ -5246,7 +5385,7 @@ (define_peephole ; "*cpse.ne"
"!AVR_HAVE_JMP_CALL
|| !avr_current_device->errata_skip"
{
- if (operands[2] == const0_rtx)
+ if (operands[2] == CONST0_RTX (<MODE>mode))
operands[2] = zero_reg_rtx;
return 3 == avr_jump_mode (operands[0], insn)
@@ -6265,4 +6404,8 @@ (define_insn_and_split "*extzv.qihi2"
})
\f
+;; Fixed-point instructions
+(include "avr-fixed.md")
+
+;; Operations on 64-bit registers
(include "avr-dimode.md")
Index: gcc/config/avr/avr-modes.def
===================================================================
--- gcc/config/avr/avr-modes.def (revision 190299)
+++ gcc/config/avr/avr-modes.def (working copy)
@@ -1 +1,27 @@
FRACTIONAL_INT_MODE (PSI, 24, 3);
+
+/* On 8 bit machines it requires fewer instructions for fixed point
+ routines if the decimal place is on a byte boundary which is not
+ the default for signed accum types. */
+
+ADJUST_IBIT (HA, 7);
+ADJUST_FBIT (HA, 8);
+
+ADJUST_IBIT (SA, 15);
+ADJUST_FBIT (SA, 16);
+
+ADJUST_IBIT (DA, 31);
+ADJUST_FBIT (DA, 32);
+
+/* Make TA and UTA 64 bits wide.
+ 128 bit wide modes would be insane on a 8-bit machine. */
+
+ADJUST_BYTESIZE (TA, 8);
+ADJUST_ALIGNMENT (TA, 1);
+ADJUST_IBIT (TA, 15);
+ADJUST_FBIT (TA, 48);
+
+ADJUST_BYTESIZE (UTA, 8);
+ADJUST_ALIGNMENT (UTA, 1);
+ADJUST_IBIT (UTA, 16);
+ADJUST_FBIT (UTA, 48);
Index: gcc/config/avr/avr-protos.h
===================================================================
--- gcc/config/avr/avr-protos.h (revision 190299)
+++ gcc/config/avr/avr-protos.h (working copy)
@@ -79,6 +79,9 @@ extern const char* avr_load_lpm (rtx, rt
extern bool avr_rotate_bytes (rtx operands[]);
+extern const char* avr_out_fract (rtx, rtx[], bool, int*);
+extern rtx avr_to_int_mode (rtx);
+
extern void expand_prologue (void);
extern void expand_epilogue (bool);
extern bool avr_emit_movmemhi (rtx*);
@@ -92,6 +95,8 @@ extern const char* avr_out_plus (rtx*, i
extern const char* avr_out_plus_noclobber (rtx*, int*, int*);
extern const char* avr_out_plus64 (rtx, int*);
extern const char* avr_out_addto_sp (rtx*, int*);
+extern const char* avr_out_minus (rtx*, int*, int*);
+extern const char* avr_out_minus64 (rtx, int*);
extern const char* avr_out_xload (rtx, rtx*, int*);
extern const char* avr_out_movmem (rtx, rtx*, int*);
extern const char* avr_out_insert_bits (rtx*, int*);
Index: gcc/config/avr/constraints.md
===================================================================
--- gcc/config/avr/constraints.md (revision 190299)
+++ gcc/config/avr/constraints.md (working copy)
@@ -192,3 +192,47 @@ (define_constraint "C0f"
"32-bit integer constant where no nibble equals 0xf."
(and (match_code "const_int")
(match_test "!avr_has_nibble_0xf (op)")))
+
+;; CONST_FIXED is no element of 'n' so cook our own.
+;; "i" or "s" would match but because the insn uses iterators that cover
+;; INT_MODE, "i" or "s" is not always possible.
+
+(define_constraint "Ynn"
+ "Fixed-point constant known at compile time."
+ (match_code "const_fixed"))
+
+(define_constraint "Y00"
+ "Fixed-point or integer constant with bit representation 0x0"
+ (and (match_code "const_fixed,const_int")
+ (match_test "op == CONST0_RTX (GET_MODE (op))")))
+
+(define_constraint "Y01"
+ "Fixed-point or integer constant with bit representation 0x1"
+ (ior (and (match_code "const_fixed")
+ (match_test "1 == INTVAL (avr_to_int_mode (op))"))
+ (match_test "satisfies_constraint_P (op)")))
+
+(define_constraint "Ym1"
+ "Fixed-point or integer constant with bit representation -0x1"
+ (ior (and (match_code "const_fixed")
+ (match_test "-1 == INTVAL (avr_to_int_mode (op))"))
+ (match_test "satisfies_constraint_N (op)")))
+
+(define_constraint "Y02"
+ "Fixed-point or integer constant with bit representation 0x2"
+ (ior (and (match_code "const_fixed")
+ (match_test "2 == INTVAL (avr_to_int_mode (op))"))
+ (match_test "satisfies_constraint_K (op)")))
+
+(define_constraint "Ym2"
+ "Fixed-point or integer constant with bit representation -0x2"
+ (ior (and (match_code "const_fixed")
+ (match_test "-2 == INTVAL (avr_to_int_mode (op))"))
+ (match_test "satisfies_constraint_Cm2 (op)")))
+
+;; Similar to "IJ" used with ADIW/SBIW, but for CONST_FIXED.
+
+(define_constraint "YIJ"
+ "Fixed-point constant from @minus{}0x003f to 0x003f."
+ (and (match_code "const_fixed")
+ (match_test "IN_RANGE (INTVAL (avr_to_int_mode (op)), -63, 63)")))
Index: gcc/config/avr/avr.c
===================================================================
--- gcc/config/avr/avr.c (revision 190299)
+++ gcc/config/avr/avr.c (working copy)
@@ -49,6 +49,10 @@
#include "params.h"
#include "df.h"
+#ifndef CONST_FIXED_P
+#define CONST_FIXED_P(X) (CONST_FIXED == GET_CODE (X))
+#endif
+
/* Maximal allowed offset for an address in the LD command */
#define MAX_LD_OFFSET(MODE) (64 - (signed)GET_MODE_SIZE (MODE))
@@ -264,6 +268,23 @@ avr_popcount_each_byte (rtx xval, int n_
return true;
}
+
+/* Access some RTX as INT_MODE. If X is a CONST_FIXED we can get
+ the bit representation of X by "casting" it to CONST_INT. */
+
+rtx
+avr_to_int_mode (rtx x)
+{
+ enum machine_mode mode = GET_MODE (x);
+
+ return VOIDmode == mode
+ ? x
+ : simplify_gen_subreg (int_mode_for_mode (mode), x, mode, 0);
+}
+
+
+/* Implement `TARGET_OPTION_OVERRIDE'. */
+
static void
avr_option_override (void)
{
@@ -389,9 +410,14 @@ avr_regno_reg_class (int r)
}
+/* Implement `TARGET_SCALAR_MODE_SUPPORTED_P'. */
+
static bool
avr_scalar_mode_supported_p (enum machine_mode mode)
{
+ if (ALL_FIXED_POINT_MODE_P (mode))
+ return true;
+
if (PSImode == mode)
return true;
@@ -715,6 +741,8 @@ avr_initial_elimination_offset (int from
}
}
+
+/* Implement `TARGET_BUILTIN_SETJMP_FRAME_VALUE'. */
/* Actual start of frame is virtual_stack_vars_rtx this is offset from
frame pointer by +STARTING_FRAME_OFFSET.
Using saved frame = virtual_stack_vars_rtx - STARTING_FRAME_OFFSET
@@ -723,10 +751,13 @@ avr_initial_elimination_offset (int from
static rtx
avr_builtin_setjmp_frame_value (void)
{
- return gen_rtx_MINUS (Pmode, virtual_stack_vars_rtx,
- gen_int_mode (STARTING_FRAME_OFFSET, Pmode));
+ rtx xval = gen_reg_rtx (Pmode);
+ emit_insn (gen_subhi3 (xval, virtual_stack_vars_rtx,
+ gen_int_mode (STARTING_FRAME_OFFSET, Pmode)));
+ return xval;
}
+
/* Return contents of MEM at frame pointer + stack size + 1 (+2 if 3 byte PC).
This is return address of function. */
rtx
@@ -2081,6 +2112,14 @@ avr_print_operand (FILE *file, rtx x, in
/* Use normal symbol for direct address no linker trampoline needed */
output_addr_const (file, x);
}
+ else if (GET_CODE (x) == CONST_FIXED)
+ {
+ HOST_WIDE_INT ival = INTVAL (avr_to_int_mode (x));
+ if (code != 0)
+ output_operand_lossage ("Unsupported code '%c'for fixed-point:",
+ code);
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, ival);
+ }
else if (GET_CODE (x) == CONST_DOUBLE)
{
long val;
@@ -2116,6 +2155,7 @@ notice_update_cc (rtx body ATTRIBUTE_UNU
case CC_OUT_PLUS:
case CC_OUT_PLUS_NOCLOBBER:
+ case CC_MINUS:
case CC_LDI:
{
rtx *op = recog_data.operand;
@@ -2139,6 +2179,11 @@ notice_update_cc (rtx body ATTRIBUTE_UNU
cc = (enum attr_cc) icc;
break;
+ case CC_MINUS:
+ avr_out_minus (op, &len_dummy, &icc);
+ cc = (enum attr_cc) icc;
+ break;
+
case CC_LDI:
cc = (op[1] == CONST0_RTX (GET_MODE (op[0]))
@@ -2779,9 +2824,11 @@ output_movqi (rtx insn, rtx operands[],
if (real_l)
*real_l = 1;
- if (register_operand (dest, QImode))
+ gcc_assert (1 == GET_MODE_SIZE (GET_MODE (dest)));
+
+ if (REG_P (dest))
{
- if (register_operand (src, QImode)) /* mov r,r */
+ if (REG_P (src)) /* mov r,r */
{
if (test_hard_reg_class (STACK_REG, dest))
return "out %0,%1";
@@ -2803,7 +2850,7 @@ output_movqi (rtx insn, rtx operands[],
rtx xop[2];
xop[0] = dest;
- xop[1] = src == const0_rtx ? zero_reg_rtx : src;
+ xop[1] = src == CONST0_RTX (GET_MODE (dest)) ? zero_reg_rtx : src;
return out_movqi_mr_r (insn, xop, real_l);
}
@@ -2825,6 +2872,8 @@ output_movhi (rtx insn, rtx xop[], int *
return avr_out_lpm (insn, xop, plen);
}
+ gcc_assert (2 == GET_MODE_SIZE (GET_MODE (dest)));
+
if (REG_P (dest))
{
if (REG_P (src)) /* mov r,r */
@@ -2843,7 +2892,6 @@ output_movhi (rtx insn, rtx xop[], int *
return TARGET_NO_INTERRUPTS
? avr_asm_len ("out __SP_H__,%B1" CR_TAB
"out __SP_L__,%A1", xop, plen, -2)
-
: avr_asm_len ("in __tmp_reg__,__SREG__" CR_TAB
"cli" CR_TAB
"out __SP_H__,%B1" CR_TAB
@@ -2880,7 +2928,7 @@ output_movhi (rtx insn, rtx xop[], int *
rtx xop[2];
xop[0] = dest;
- xop[1] = src == const0_rtx ? zero_reg_rtx : src;
+ xop[1] = src == CONST0_RTX (GET_MODE (dest)) ? zero_reg_rtx : src;
return out_movhi_mr_r (insn, xop, plen);
}
@@ -3403,9 +3451,10 @@ output_movsisf (rtx insn, rtx operands[]
if (!l)
l = &dummy;
- if (register_operand (dest, VOIDmode))
+ gcc_assert (4 == GET_MODE_SIZE (GET_MODE (dest)));
+ if (REG_P (dest))
{
- if (register_operand (src, VOIDmode)) /* mov r,r */
+ if (REG_P (src)) /* mov r,r */
{
if (true_regnum (dest) > true_regnum (src))
{
@@ -3440,10 +3489,10 @@ output_movsisf (rtx insn, rtx operands[]
{
return output_reload_insisf (operands, NULL_RTX, real_l);
}
- else if (GET_CODE (src) == MEM)
+ else if (MEM_P (src))
return out_movsi_r_mr (insn, operands, real_l); /* mov r,m */
}
- else if (GET_CODE (dest) == MEM)
+ else if (MEM_P (dest))
{
const char *templ;
@@ -4126,14 +4175,25 @@ avr_out_compare (rtx insn, rtx *xop, int
rtx xval = xop[1];
/* MODE of the comparison. */
- enum machine_mode mode = GET_MODE (xreg);
+ enum machine_mode mode;
/* Number of bytes to operate on. */
- int i, n_bytes = GET_MODE_SIZE (mode);
+ int i, n_bytes = GET_MODE_SIZE (GET_MODE (xreg));
/* Value (0..0xff) held in clobber register xop[2] or -1 if unknown. */
int clobber_val = -1;
+ /* Map fixed mode operands to integer operands with the same binary
+ representation. They are easier to handle in the remainder. */
+
+ if (CONST_FIXED == GET_CODE (xval))
+ {
+ xreg = avr_to_int_mode (xop[0]);
+ xval = avr_to_int_mode (xop[1]);
+ }
+
+ mode = GET_MODE (xreg);
+
gcc_assert (REG_P (xreg));
gcc_assert ((CONST_INT_P (xval) && n_bytes <= 4)
|| (const_double_operand (xval, VOIDmode) && n_bytes == 8));
@@ -5884,6 +5944,9 @@ avr_out_plus_1 (rtx *xop, int *plen, enu
/* MODE of the operation. */
enum machine_mode mode = GET_MODE (xop[0]);
+ /* INT_MODE of the same size. */
+ enum machine_mode imode = int_mode_for_mode (mode);
+
/* Number of bytes to operate on. */
int i, n_bytes = GET_MODE_SIZE (mode);
@@ -5908,8 +5971,11 @@ avr_out_plus_1 (rtx *xop, int *plen, enu
*pcc = (MINUS == code) ? CC_SET_CZN : CC_CLOBBER;
+ if (CONST_FIXED_P (xval))
+ xval = avr_to_int_mode (xval);
+
if (MINUS == code)
- xval = simplify_unary_operation (NEG, mode, xval, mode);
+ xval = simplify_unary_operation (NEG, imode, xval, imode);
op[2] = xop[3];
@@ -5920,7 +5986,7 @@ avr_out_plus_1 (rtx *xop, int *plen, enu
{
/* We operate byte-wise on the destination. */
rtx reg8 = simplify_gen_subreg (QImode, xop[0], mode, i);
- rtx xval8 = simplify_gen_subreg (QImode, xval, mode, i);
+ rtx xval8 = simplify_gen_subreg (QImode, xval, imode, i);
/* 8-bit value to operate with this byte. */
unsigned int val8 = UINTVAL (xval8) & GET_MODE_MASK (QImode);
@@ -5941,7 +6007,7 @@ avr_out_plus_1 (rtx *xop, int *plen, enu
&& i + 2 <= n_bytes
&& test_hard_reg_class (ADDW_REGS, reg8))
{
- rtx xval16 = simplify_gen_subreg (HImode, xval, mode, i);
+ rtx xval16 = simplify_gen_subreg (HImode, xval, imode, i);
unsigned int val16 = UINTVAL (xval16) & GET_MODE_MASK (HImode);
/* Registers R24, X, Y, Z can use ADIW/SBIW with constants < 64
@@ -6085,6 +6151,41 @@ avr_out_plus_noclobber (rtx *xop, int *p
}
+/* Output subtraction of register XOP[0] and compile time constant XOP[2]:
+
+ XOP[0] = XOP[0] - XOP[2]
+
+ This is basically the same as `avr_out_plus' except that we subtract.
+ It's needed because (minus x const) is not mapped to (plus x -const)
+ for the fixed point modes. */
+
+const char*
+avr_out_minus (rtx *xop, int *plen, int *pcc)
+{
+ rtx op[4];
+
+ if (pcc)
+ *pcc = (int) CC_SET_CZN;
+
+ if (REG_P (xop[2]))
+ return avr_asm_len ("sub %A0,%A2" CR_TAB
+ "sbc %B0,%B2", xop, plen, -2);
+
+ if (!CONST_INT_P (xop[2])
+ && !CONST_FIXED_P (xop[2]))
+ return avr_asm_len ("subi %A0,lo8(%2)" CR_TAB
+ "sbci %B0,hi8(%2)", xop, plen, -2);
+
+ op[0] = avr_to_int_mode (xop[0]);
+ op[1] = avr_to_int_mode (xop[1]);
+ op[2] = gen_int_mode (-INTVAL (avr_to_int_mode (xop[2])),
+ GET_MODE (op[0]));
+ op[3] = xop[3];
+
+ return avr_out_plus (op, plen, pcc);
+}
+
+
/* Prepare operands of adddi3_const_insn to be used with avr_out_plus_1. */
const char*
@@ -6103,6 +6204,19 @@ avr_out_plus64 (rtx addend, int *plen)
return "";
}
+
+/* Prepare operands of subdi3_const_insn to be used with avr_out_plus64. */
+
+const char*
+avr_out_minus64 (rtx subtrahend, int *plen)
+{
+ rtx xneg = avr_to_int_mode (subtrahend);
+ xneg = simplify_unary_operation (NEG, DImode, xneg, DImode);
+
+ return avr_out_plus64 (xneg, plen);
+}
+
+
/* Output bit operation (IOR, AND, XOR) with register XOP[0] and compile
time constant XOP[2]:
@@ -6442,6 +6556,319 @@ avr_rotate_bytes (rtx operands[])
return true;
}
+
+/* Outputs instructions needed for fixed point type conversion.
+ This includes converting between any fixed point type, as well
+ as converting to any integer type. Conversion between integer
+ types is not supported.
+
+ The number of instructions generated depends on the types
+ being converted and the registers assigned to them.
+
+ The number of instructions required to complete the conversion
+ is least if the registers for source and destination are overlapping
+ and are aligned at the decimal place as actual movement of data is
+ completely avoided. In some cases, the conversion may already be
+ complete without any instructions needed.
+
+ When converting to signed types from signed types, sign extension
+ is implemented.
+
+ Converting signed fractional types requires a bit shift if converting
+ to or from any unsigned fractional type because the decimal place is
+ shifted by 1 bit. When the destination is a signed fractional, the sign
+ is stored in either the carry or T bit. */
+
+const char*
+avr_out_fract (rtx insn, rtx operands[], bool intsigned, int *plen)
+{
+ int i;
+ bool sbit[2];
+ /* ilen: Length of integral part (in bytes)
+ flen: Length of fractional part (in bytes)
+ tlen: Length of operand (in bytes)
+ blen: Length of operand (in bits) */
+ int ilen[2], flen[2], tlen[2], blen[2];
+ int rdest, rsource, offset;
+ int start, end, dir;
+ bool sign_in_T = false, sign_in_Carry = false;
+ int clrword = -1, lastclr = 0, clr = 0;
+ rtx xop[6];
+
+ const int dest = 0;
+ const int src = 1;
+
+ xop[dest] = operands[dest];
+ xop[src] = operands[src];
+
+ if (plen)
+ *plen = 0;
+
+ /* Determine format (integer and fractional parts)
+ of types needing conversion. */
+
+ for (i = 0; i < 2; i++)
+ {
+ enum machine_mode mode = GET_MODE (xop[i]);
+
+ tlen[i] = GET_MODE_SIZE (mode);
+ blen[i] = GET_MODE_BITSIZE (mode);
+
+ if (SCALAR_INT_MODE_P (mode))
+ {
+ sbit[i] = intsigned;
+ ilen[i] = GET_MODE_SIZE (mode);
+ flen[i] = 0;
+ }
+ else if (ALL_SCALAR_FIXED_POINT_MODE_P (mode))
+ {
+ sbit[i] = SIGNED_SCALAR_FIXED_POINT_MODE_P (mode);
+ ilen[i] = (GET_MODE_IBIT (mode) + 1) / 8;
+ flen[i] = (GET_MODE_FBIT (mode) + 1) / 8;
+ }
+ else
+ fatal_insn ("unsupported fixed-point conversion", insn);
+ }
+
+ rdest = REGNO (xop[dest]);
+ rsource = REGNO (xop[src]);
+ offset = flen[src] - flen[dest];
+
+ /* For bit index */
+
+ xop[2] = GEN_INT (blen[dest] - 1);
+ xop[3] = GEN_INT (blen[src] - 1);
+
+ /* Store the sign bit if the destination is a signed fract and the source
+ has a sign in the integer part. */
+
+ if (sbit[dest] && ilen[dest] == 0 && sbit[src] && ilen[src] > 0)
+ {
+ /* Position of MSB in the source operand. */
+
+ xop[4] = GEN_INT (blen[1] - 1);
+
+ /* To avoid using BST and BLD if the source and destination registers
+ overlap or the source is unused after, we can use LSL to store the
+ sign bit in carry since we don't need the integral part of the source.
+ Restoring the sign from carry saves one BLD instruction below. */
+
+ if (reg_unused_after (insn, xop[src])
+ || (rdest < rsource + tlen[src]
+ && rdest + tlen[dest] > rsource))
+ {
+ avr_asm_len ("lsl %T1%t4", xop, plen, 1);
+ sign_in_Carry = true;
+ }
+ else
+ {
+ avr_asm_len ("bst %T1%T4", xop, plen, 1);
+ sign_in_T = true;
+ }
+ }
+
+ /* Pick the correct direction to shift bytes. */
+
+ if (rdest < rsource + offset)
+ {
+ dir = 1;
+ start = 0;
+ end = tlen[dest];
+ }
+ else
+ {
+ dir = -1;
+ start = tlen[dest] - 1;
+ end = -1;
+ }
+
+ /* Perform conversion by moving registers into place, clearing
+ destination registers that do not overlap with any source. */
+
+ for (i = start; i != end; i += dir)
+ {
+ int destloc = rdest + i;
+ int sourceloc = rsource + i + offset;
+
+ /* Source register location is outside range of source register,
+ so clear this byte in the dest. */
+
+ if (sourceloc < rsource
+ || sourceloc >= rsource + tlen[src])
+ {
+ if (AVR_HAVE_MOVW
+ && i + dir != end
+ && (sourceloc + dir < rsource
+ || sourceloc + dir >= rsource + tlen[src])
+ && ((dir == 1 && !(destloc % 2) && !(sourceloc % 2))
+ || (dir == -1 && (destloc % 2) && (sourceloc % 2)))
+ && clrword != -1)
+ {
+ /* Use already cleared word to clear two bytes at a time. */
+
+ int even_i = i & ~1;
+ int even_clrword = clrword & ~1;
+
+ xop[4] = GEN_INT (8 * even_i);
+ xop[5] = GEN_INT (8 * even_clrword);
+ avr_asm_len ("movw %T0%t4,%T0%t5", xop, plen, 1);
+ i += dir;
+ }
+ else
+ {
+ /* Do not clear the register if it is going to get
+ sign extended with a MOV later. */
+
+ if (sbit[dest] && sbit[src]
+ && i != tlen[dest] - 1
+ && i >= flen[dest])
+ continue;
+
+ xop[4] = GEN_INT (8 * i);
+ avr_asm_len ("clr %T0%t4", xop, plen, 1);
+
+ /* If the last byte was cleared too, we have a cleared
+ word we can MOVW to clear two bytes at a time. */
+
+ if (lastclr)
+ clrword = i;
+
+ clr = 1;
+ }
+ }
+ else if (destloc == sourceloc)
+ {
+ /* Source byte is already in destination: Nothing needed. */
+
+ continue;
+ }
+ else
+ {
+ /* Registers do not line up and source register location
+ is within range: Perform move, shifting with MOV or MOVW. */
+
+ if (AVR_HAVE_MOVW
+ && i + dir != end
+ && sourceloc + dir >= rsource
+ && sourceloc + dir < rsource + tlen[src]
+ && ((dir == 1 && !(destloc % 2) && !(sourceloc % 2))
+ || (dir == -1 && (destloc % 2) && (sourceloc % 2))))
+ {
+ int even_i = i & ~1;
+ int even_i_plus_offset = (i + offset) & ~1;
+
+ xop[4] = GEN_INT (8 * even_i);
+ xop[5] = GEN_INT (8 * even_i_plus_offset);
+ avr_asm_len ("movw %T0%t4,%T1%t5", xop, plen, 1);
+ i += dir;
+ }
+ else
+ {
+ xop[4] = GEN_INT (8 * i);
+ xop[5] = GEN_INT (8 * (i + offset));
+ avr_asm_len ("mov %T0%t4,%T1%t5", xop, plen, 1);
+ }
+ }
+
+ lastclr = clr;
+ clr = 0;
+ }
+
+ /* Perform sign extension if source and dest are both signed,
+ and there are more integer parts in dest than in source. */
+
+ if (sbit[dest] && sbit[src] && ilen[dest] > ilen[src])
+ {
+ xop[4] = GEN_INT (blen[src] - 1 - 8 * offset);
+ avr_asm_len ("sbrc %T0%T4", xop, plen, 1);
+
+ /* Register was previously cleared, so can become 0xff and extended. */
+
+ avr_asm_len ("com %T0%t2", xop, plen, 1);
+
+ /* Sign extend additional bytes by MOV and MOVW. */
+
+ start = tlen[dest] - 2;
+ end = flen[dest] + ilen[src] - 1;
+
+ for (i = start; i != end; i--)
+ {
+ if (AVR_HAVE_MOVW && i != start && i-1 != end)
+ {
+ i--;
+ xop[4] = GEN_INT (8 * i);
+ xop[5] = GEN_INT (8 * (tlen[dest] - 2));
+ avr_asm_len ("movw %T0%t4,%T0%t5", xop, plen, 1);
+ }
+ else
+ {
+ xop[4] = GEN_INT (8 * i);
+ xop[5] = GEN_INT (8 * (tlen[dest] - 1));
+ avr_asm_len ("mov %T0%t4,%T0%t5", xop, plen, 1);
+ }
+ }
+ }
+
+ /* If destination is a signed fract, and the source was not, a shift
+ by 1 bit is needed. Also restore sign from carry or T. */
+
+ if (sbit[dest] && !ilen[dest] && (!sbit[src] || ilen[src]))
+ {
+ /* We have flen[src] non-zero fractional bytes to shift.
+ Because of the right shift, handle one byte more so that the
+ LSB won't be lost. */
+
+ int nonzero = flen[src] + 1;
+
+ /* If the LSB is in the T flag and there are no fractional
+ bits, the high byte is zero and no shift needed. */
+
+ if (flen[src] == 0 && sign_in_T)
+ nonzero = 0;
+
+ start = flen[dest] - 1;
+ end = start - nonzero;
+
+ for (i = start; i > end && i >= 0; i--)
+ {
+ xop[4] = GEN_INT (8 * i);
+ if (i == start && !sign_in_Carry)
+ avr_asm_len ("lsr %T0%t4", xop, plen, 1);
+ else
+ avr_asm_len ("ror %T0%t4", xop, plen, 1);
+ }
+
+ if (sign_in_T)
+ {
+ xop[4] = GEN_INT (blen[dest] - 1);
+ avr_asm_len ("bld %T0%T4", xop, plen, 1);
+ }
+ }
+ else if (sbit[src] && !ilen[src] && (!sbit[dest] || ilen[dest]))
+ {
+ /* If source was a signed fract and dest was not, shift 1 bit
+ other way. */
+
+ start = flen[dest] - flen[src];
+
+ if (start < 0)
+ start = 0;
+
+ for (i = start; i < flen[dest]; i++)
+ {
+ xop[4] = GEN_INT (8 * i);
+
+ if (i == start)
+ avr_asm_len ("lsl %T0%t4", xop, plen, 1);
+ else
+ avr_asm_len ("rol %T0%t4", xop, plen, 1);
+ }
+ }
+
+ return "";
+}
+
+
/* Modifies the length assigned to instruction INSN
LEN is the initially computed length of the insn. */
@@ -6489,6 +6916,8 @@ adjust_insn_length (rtx insn, int len)
case ADJUST_LEN_OUT_PLUS: avr_out_plus (op, &len, NULL); break;
case ADJUST_LEN_PLUS64: avr_out_plus64 (op[0], &len); break;
+ case ADJUST_LEN_MINUS: avr_out_minus (op, &len, NULL); break;
+ case ADJUST_LEN_MINUS64: avr_out_minus64 (op[0], &len); break;
case ADJUST_LEN_OUT_PLUS_NOCLOBBER:
avr_out_plus_noclobber (op, &len, NULL); break;
@@ -6502,6 +6931,9 @@ adjust_insn_length (rtx insn, int len)
case ADJUST_LEN_XLOAD: avr_out_xload (insn, op, &len); break;
case ADJUST_LEN_LOAD_LPM: avr_load_lpm (insn, op, &len); break;
+ case ADJUST_LEN_SFRACT: avr_out_fract (insn, op, true, &len); break;
+ case ADJUST_LEN_UFRACT: avr_out_fract (insn, op, false, &len); break;
+
case ADJUST_LEN_TSTHI: avr_out_tsthi (insn, op, &len); break;
case ADJUST_LEN_TSTPSI: avr_out_tstpsi (insn, op, &len); break;
case ADJUST_LEN_TSTSI: avr_out_tstsi (insn, op, &len); break;
@@ -6683,6 +7115,20 @@ avr_assemble_integer (rtx x, unsigned in
return true;
}
+ else if (CONST_FIXED_P (x))
+ {
+ unsigned n;
+
+ /* varasm fails to handle big fixed modes that don't fit in hwi. */
+
+ for (n = 0; n < size; n++)
+ {
+ rtx xn = simplify_gen_subreg (QImode, x, GET_MODE (x), n);
+ default_assemble_integer (xn, 1, aligned_p);
+ }
+
+ return true;
+ }
return default_assemble_integer (x, size, aligned_p);
}
@@ -7489,6 +7935,7 @@ avr_operand_rtx_cost (rtx x, enum machin
return 0;
case CONST_INT:
+ case CONST_FIXED:
case CONST_DOUBLE:
return COSTS_N_INSNS (GET_MODE_SIZE (mode));
@@ -7518,6 +7965,7 @@ avr_rtx_costs_1 (rtx x, int codearg, int
switch (code)
{
case CONST_INT:
+ case CONST_FIXED:
case CONST_DOUBLE:
case SYMBOL_REF:
case CONST:
@@ -8788,6 +9236,8 @@ avr_2word_insn_p (rtx insn)
return false;
case CODE_FOR_movqi_insn:
+ case CODE_FOR_movuqq_insn:
+ case CODE_FOR_movqq_insn:
{
rtx set = single_set (insn);
rtx src = SET_SRC (set);
@@ -8796,7 +9246,7 @@ avr_2word_insn_p (rtx insn)
/* Factor out LDS and STS from movqi_insn. */
if (MEM_P (dest)
- && (REG_P (src) || src == const0_rtx))
+ && (REG_P (src) || src == CONST0_RTX (GET_MODE (dest))))
{
return CONSTANT_ADDRESS_P (XEXP (dest, 0));
}
@@ -9021,7 +9471,7 @@ output_reload_in_const (rtx *op, rtx clo
if (NULL_RTX == clobber_reg
&& !test_hard_reg_class (LD_REGS, dest)
- && (! (CONST_INT_P (src) || CONST_DOUBLE_P (src))
+ && (! (CONST_INT_P (src) || CONST_FIXED_P (src) || CONST_DOUBLE_P (src))
|| !avr_popcount_each_byte (src, n_bytes,
(1 << 0) | (1 << 1) | (1 << 8))))
{
@@ -9048,6 +9498,7 @@ output_reload_in_const (rtx *op, rtx clo
ldreg_p = test_hard_reg_class (LD_REGS, xdest[n]);
if (!CONST_INT_P (src)
+ && !CONST_FIXED_P (src)
&& !CONST_DOUBLE_P (src))
{
static const char* const asm_code[][2] =
@@ -9239,6 +9690,7 @@ output_reload_insisf (rtx *op, rtx clobb
if (AVR_HAVE_MOVW
&& !test_hard_reg_class (LD_REGS, op[0])
&& (CONST_INT_P (op[1])
+ || CONST_FIXED_P (op[1])
|| CONST_DOUBLE_P (op[1])))
{
int len_clr, len_noclr;
@@ -10834,6 +11286,9 @@ avr_fold_builtin (tree fndecl, int n_arg
#undef TARGET_SCALAR_MODE_SUPPORTED_P
#define TARGET_SCALAR_MODE_SUPPORTED_P avr_scalar_mode_supported_p
+#undef TARGET_FIXED_POINT_SUPPORTED_P
+#define TARGET_FIXED_POINT_SUPPORTED_P hook_bool_void_true
+
#undef TARGET_ADDR_SPACE_SUBSET_P
#define TARGET_ADDR_SPACE_SUBSET_P avr_addr_space_subset_p
Index: libgcc/config/avr/avr-lib.h
===================================================================
--- libgcc/config/avr/avr-lib.h (revision 190299)
+++ libgcc/config/avr/avr-lib.h (working copy)
@@ -4,3 +4,79 @@
#define DI SI
typedef int QItype __attribute__ ((mode (QI)));
#endif
+
+/* fixed-bit.h does not define functions for TA and UTA because
+ that part is wrapped in #if MIN_UNITS_PER_WORD > 4.
+ This would lead to empty functions for TA and UTA.
+ Thus, supply appropriate defines as if HAVE_[U]TA == 1.
+ #define HAVE_[U]TA 1 won't work because avr-modes.def
+ uses ADJUST_BYTESIZE(TA,8) and fixed-bit.h is not generic enough
+ to arrange for such changes of the mode size. */
+
+typedef unsigned _Fract UTAtype __attribute__ ((mode (UTA)));
+
+#if defined (UTA_MODE)
+#define FIXED_SIZE 8 /* in bytes */
+#define INT_C_TYPE UDItype
+#define UINT_C_TYPE UDItype
+#define HINT_C_TYPE USItype
+#define HUINT_C_TYPE USItype
+#define MODE_NAME UTA
+#define MODE_NAME_S uta
+#define MODE_UNSIGNED 1
+#endif
+
+#if defined (FROM_UTA)
+#define FROM_TYPE 4 /* ID for fixed-point */
+#define FROM_MODE_NAME UTA
+#define FROM_MODE_NAME_S uta
+#define FROM_INT_C_TYPE UDItype
+#define FROM_SINT_C_TYPE DItype
+#define FROM_UINT_C_TYPE UDItype
+#define FROM_MODE_UNSIGNED 1
+#define FROM_FIXED_SIZE 8 /* in bytes */
+#elif defined (TO_UTA)
+#define TO_TYPE 4 /* ID for fixed-point */
+#define TO_MODE_NAME UTA
+#define TO_MODE_NAME_S uta
+#define TO_INT_C_TYPE UDItype
+#define TO_SINT_C_TYPE DItype
+#define TO_UINT_C_TYPE UDItype
+#define TO_MODE_UNSIGNED 1
+#define TO_FIXED_SIZE 8 /* in bytes */
+#endif
+
+/* Same for TAmode */
+
+typedef _Fract TAtype __attribute__ ((mode (TA)));
+
+#if defined (TA_MODE)
+#define FIXED_SIZE 8 /* in bytes */
+#define INT_C_TYPE DItype
+#define UINT_C_TYPE UDItype
+#define HINT_C_TYPE SItype
+#define HUINT_C_TYPE USItype
+#define MODE_NAME TA
+#define MODE_NAME_S ta
+#define MODE_UNSIGNED 0
+#endif
+
+#if defined (FROM_TA)
+#define FROM_TYPE 4 /* ID for fixed-point */
+#define FROM_MODE_NAME TA
+#define FROM_MODE_NAME_S ta
+#define FROM_INT_C_TYPE DItype
+#define FROM_SINT_C_TYPE DItype
+#define FROM_UINT_C_TYPE UDItype
+#define FROM_MODE_UNSIGNED 0
+#define FROM_FIXED_SIZE 8 /* in bytes */
+#elif defined (TO_TA)
+#define TO_TYPE 4 /* ID for fixed-point */
+#define TO_MODE_NAME TA
+#define TO_MODE_NAME_S ta
+#define TO_INT_C_TYPE DItype
+#define TO_SINT_C_TYPE DItype
+#define TO_UINT_C_TYPE UDItype
+#define TO_MODE_UNSIGNED 0
+#define TO_FIXED_SIZE 8 /* in bytes */
+#endif
Index: libgcc/config/avr/lib1funcs-fixed.S
===================================================================
--- libgcc/config/avr/lib1funcs-fixed.S (revision 0)
+++ libgcc/config/avr/lib1funcs-fixed.S (revision 0)
@@ -0,0 +1,1019 @@
+/* -*- Mode: Asm -*- */
+;; Copyright (C) 2012
+;; Free Software Foundation, Inc.
+;; Contributed by Sean D'Epagnier (sean@depagnier.com)
+
+;; This file 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.
+
+;; In addition to the permissions in the GNU General Public License, the
+;; Free Software Foundation gives you unlimited permission to link the
+;; compiled version of this file into combinations with other programs,
+;; and to distribute those combinations without any restriction coming
+;; from the use of this file. (The General Public License restrictions
+;; do apply in other respects; for example, they cover modification of
+;; the file, and distribution when not linked into a combine
+;; executable.)
+
+;; This file 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.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program; see the file COPYING. If not, write to
+;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Fixed point library routines for AVR
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+.section .text.libgcc.fixed, "ax", @progbits
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Conversions to float
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+#if defined (L_fractqqsf)
+DEFUN __fractqqsf
+ clr r25
+ sbrc r24, 7 ; if negative
+ com r25 ; sign extend
+ mov r23, r24 ; move in place
+ mov r24, r25 ; sign extend lower byte
+ lsl r23
+ clr r22
+ XJMP __fractsasf ; call larger conversion
+ENDF __fractqqsf
+#endif /* defined (L_fractqqsf) */
+
+#if defined (L_fractuqqsf)
+DEFUN __fractuqqsf
+ clr r22
+ mov r23, r24
+ clr r24
+ clr r25
+ XJMP __fractsasf ; call larger conversion
+ENDF __fractuqqsf
+#endif /* defined (L_fractuqqsf) */
+
+#if defined (L_fracthqsf)
+DEFUN __fracthqsf
+ wmov 22, 24 ; put fractional part in place
+ clr r25
+ sbrc r23, 7 ; if negative
+ com r25 ; sign extend
+ mov r24, r25 ; sign extend lower byte
+ lsl r22
+ rol r23
+ XJMP __fractsasf ; call larger conversion
+ENDF __fracthqsf
+#endif /* defined (L_fracthqsf) */
+
+#if defined (L_fractuhqsf)
+DEFUN __fractuhqsf
+ wmov 22, 24 ; put fractional part in place
+ clr r24
+ clr r25
+ XJMP __fractsasf ; call larger conversion
+ENDF __fractuhqsf
+#endif /* defined (L_fractuhqsf) */
+
+#if defined (L_fracthasf)
+DEFUN __fracthasf
+ clr r22
+ mov r23, r24 ; move into place
+ mov r24, r25
+ clr r25
+ sbrc r24, 7 ; if negative
+ com r25 ; sign extend
+ XJMP __fractsasf ; call larger conversion
+ENDF __fracthasf
+#endif /* defined (L_fracthasf) */
+
+#if defined (L_fractuhasf)
+DEFUN __fractuhasf
+ clr r22
+ mov r23, r24 ; move into place
+ XJMP __fractsasf ; call larger conversion
+ENDF __fractuhasf
+#endif /* defined (L_fractuhasf) */
+
+#if defined (L_fractsasf)
+DEFUN __fractsasf
+ XCALL __floatsisf
+ cpse r25, __zero_reg__ ; skip if zero
+ subi r25, 0x08 ; adjust exponent
+ ret
+ENDF __fractsasf
+#endif /* defined (L_fractsasf) */
+
+#if defined (L_fractusasf)
+DEFUN __fractusasf
+ XCALL __floatunsisf
+ cpse r25, __zero_reg__ ; skip if zero
+ subi r25, 0x08 ; adjust exponent
+ ret
+ENDF __fractusasf
+#endif /* defined (L_fractusasf) */
+
+#if defined (L_fractsfqq) /* Conversions from float. */
+DEFUN __fractsfqq
+ subi r25, -11 ; adjust exponent
+ subi r24, 128
+ XJMP __fixsfsi
+ENDF __fractsfqq
+#endif /* defined (L_fractqq) */
+
+#if defined (L_fractsfuqq)
+DEFUN __fractsfuqq
+ subi r25, -12 ; adjust exponent
+ XJMP __fixsfsi
+ENDF __fractsfuqq
+#endif /* defined (L_fractuqq) */
+
+#if defined (L_fractsfhq)
+DEFUN __fractsfhq
+ subi r25, -15 ; adjust exponent
+ subi r24, 128
+ XJMP __fixsfsi
+ENDF __fractsfhq
+#endif /* defined (L_fractsfhq) */
+
+#if defined (L_fractsfuhq)
+DEFUN __fractsfuhq
+ subi r25, -16 ; adjust exponent
+ XJMP __fixsfsi
+ENDF __fractsfuhq
+#endif /* defined (L_fractsfuhq) */
+
+#if defined (L_fractsfha)
+DEFUN __fractsfha
+ENDF __fractsfha
+
+DEFUN __fractsfuha
+ subi r25, -12 ; adjust exponent
+ XJMP __fixsfsi
+ENDF __fractsfuha
+#endif /* defined (L_fractsfha) */
+
+#if defined (L_fractsfsa)
+DEFUN __fractsfsa
+ENDF __fractsfsa
+
+DEFUN __fractsfusa
+ subi r25, -8 ; adjust exponent
+ XJMP __fixsfsi
+ENDF __fractsfsa
+#endif /* defined (L_fractsfsa) */
+
+/* For multiplication the functions here are called directly from
+ avr-fixed.md patterns, instead of using the standard libcall mechanisms.
+ This can make better code because GCC knows exactly which
+ of the call-used registers (not all of them) are clobbered. */
+
+#undef r_arg1L
+#undef r_arg1H
+#undef r_arg2L
+#undef r_arg2H
+#undef r_resL
+#undef r_resH
+
+/* mulqq and muluqq open coded on the enhanced core */
+#if !defined (__AVR_HAVE_MUL__)
+/*******************************************************
+ Fractional Multiplication 8 x 8
+*******************************************************/
+#define r_arg2 r22 /* multiplicand */
+#define r_arg1 r24 /* multiplier */
+#define r_res __tmp_reg__ /* result */
+
+#if defined (L_mulqq3)
+DEFUN __mulqq3
+ mov r_res, r_arg1
+ eor r_res, r_arg2
+ bst r_res, 7
+ lsl r_arg1
+ lsl r_arg2
+ brcc 0f
+ neg r_arg2
+0:
+ XCALL __muluqq3
+ lsr r_arg1
+ brtc 1f
+ neg r_arg1
+1:
+ ret
+
+ENDF __mulqq3
+#endif /* defined (L_mulqq3) */
+
+#if defined (L_muluqq3)
+DEFUN __muluqq3
+ clr r_res ; clear result
+__muluqq3_loop:
+ lsr r_arg2 ; shift multiplicand
+ sbrc r_arg1,7
+ add r_res,r_arg2
+ breq 1f ; while multiplicand != 0
+ lsl r_arg1
+ brne __muluqq3_loop ; exit if multiplier = 0
+1:
+ mov r_arg1,r_res ; result to return register
+ ret
+#undef r_arg2
+#undef r_arg1
+#undef r_res
+
+ENDF __muluqq3
+#endif /* defined (L_muluqq3) */
+#endif /* !defined (__AVR_HAVE_MUL__) */
+
+/*******************************************************
+ Fractional Multiplication 16 x 16
+*******************************************************/
+
+#if defined (__AVR_HAVE_MUL__)
+#define r_arg1L r22 /* multiplier Low */
+#define r_arg1H r23 /* multiplier High */
+#define r_arg2L r20 /* multiplicand Low */
+#define r_arg2H r21 /* multiplicand High */
+#define r_resL r18 /* result Low */
+#define r_resH r19 /* result High */
+
+#if defined (L_mulhq3)
+DEFUN __mulhq3
+ fmuls r_arg1H, r_arg2H
+ movw r_resL, r0
+ fmulsu r_arg2H, r_arg1L
+ clr r_arg1L
+ sbc r_resH, r_arg1L
+ add r_resL, r1
+ adc r_resH, r_arg1L
+ fmulsu r_arg1H, r_arg2L
+ sbc r_resH, r_arg1L
+ add r_resL, r1
+ adc r_resH, r_arg1L
+ clr __zero_reg__
+ ret
+ENDF __mulhq3
+#endif /* defined (L_mulhq3) */
+
+#if defined (L_muluhq3)
+DEFUN __muluhq3
+ mul r_arg1H, r_arg2H
+ movw r_resL, r0
+ mul r_arg1H, r_arg2L
+ add r_resL, r1
+ clr __zero_reg__
+ adc r_resH, __zero_reg__
+ mul r_arg1L, r_arg2H
+ add r_resL, r1
+ clr __zero_reg__
+ adc r_resH, __zero_reg__
+ ret
+ENDF __muluhq3
+
+#endif /* defined (L_muluhq3) */
+
+#undef r_arg1L
+#undef r_arg1H
+#undef r_arg2L
+#undef r_arg2H
+#undef r_resL
+#undef r_resH
+
+#else /* defined (__AVR_HAVE_MUL__) */
+
+#define r_arg1L 24 /* multiplier Low */
+#define r_arg1H 25 /* multiplier High */
+#define r_arg2L 22 /* multiplicand Low */
+#define r_arg2H 23 /* multiplicand High */
+#define r_resL 0 /* __tmp_reg__ result Low */
+#define r_resH 1 /* __zero_reg__ result High */
+
+#if defined (L_mulhq3)
+DEFUN __mulhq3
+ mov r_resL, r_arg1H
+ eor r_resL, r_arg2H
+ bst r_resL, 7
+ lsl r_arg1L
+ rol r_arg1H
+ lsl r_arg2L
+ rol r_arg2H
+ brcc 0f
+ neg2 r_arg2L
+0:
+ XCALL __muluhq3
+ lsr r_arg1H
+ ror r_arg1L
+ brtc mulhq3_exit
+ neg2 r_arg1L
+mulhq3_exit:
+ ret
+ENDF __mulhq3
+#endif /* defined (L_mulhq3) */
+
+#if defined (L_muluhq3)
+DEFUN __muluhq3
+ clr r_resL ; clear result
+__muluhq3_loop:
+ lsr r_arg2H ; shift multiplicand
+ ror r_arg2L
+ sbrs r_arg1H,7
+ rjmp 0f
+ add r_resL,r_arg2L ; result + multiplicand
+ adc r_resH,r_arg2H
+0:
+ lsl r_arg1L ; shift multiplier
+ rol r_arg1H
+ brne __muluhq3_loop
+ cpi r_arg1L, 0
+ brne __muluhq3_loop ; exit multiplier = 0
+ wmov r_arg1L,r_resL ; result to return register
+ clr __zero_reg__ ; zero the zero reg
+ ret
+ENDF __muluhq3
+#endif /* defined (L_muluhq3) */
+
+#undef r_arg1L
+#undef r_arg1H
+#undef r_arg2L
+#undef r_arg2H
+#undef r_resL
+#undef r_resH
+
+#endif /* defined (__AVR_HAVE_MUL__) */
+
+/*******************************************************
+ Fixed Multiplication 8.8 x 8.8
+*******************************************************/
+
+#if defined (__AVR_HAVE_MUL__)
+#define r_arg1L r22 /* multiplier Low */
+#define r_arg1H r23 /* multiplier High */
+#define r_arg2L r20 /* multiplicand Low */
+#define r_arg2H r21 /* multiplicand High */
+#define r_resL r18 /* result Low */
+#define r_resH r19 /* result High */
+
+#if defined (L_mulha3)
+DEFUN __mulha3
+ mul r_arg1L, r_arg2L
+ mov r_resL, r1
+ muls r_arg1H, r_arg2H
+ mov r_resH, r0
+ mulsu r_arg1H, r_arg2L
+ add r_resL, r0
+ adc r_resH, r1
+ mulsu r_arg2H, r_arg1L
+ add r_resL, r0
+ adc r_resH, r1
+ clr __zero_reg__
+ ret
+ENDF __mulha3
+#endif /* defined (L_mulha3) */
+
+#if defined (L_muluha3)
+DEFUN __muluha3
+ mul r_arg1L, r_arg2L
+ mov r_resL, r1
+ mul r_arg1H, r_arg2H
+ mov r_resH, r0
+ mul r_arg1H, r_arg2L
+ add r_resL, r0
+ adc r_resH, r1
+ mul r_arg1L, r_arg2H
+ add r_resL, r0
+ adc r_resH, r1
+ clr __zero_reg__
+ ret
+ENDF __muluha3
+#endif /* defined (L_muluha3) */
+
+#undef r_arg1L
+#undef r_arg1H
+#undef r_arg2L
+#undef r_arg2H
+#undef r_resL
+#undef r_resH
+
+#else /* defined (__AVR_HAVE_MUL__) */
+
+#define r_arg1L 24 /* multiplier Low */
+#define r_arg1H 25 /* multiplier High */
+#define r_arg2L 22 /* multiplicand Low */
+#define r_arg2H 23 /* multiplicand High */
+#define r_resL 18 /* result Low */
+#define r_resH 19 /* result High */
+#define r_scratchL 0 /* scratch Low */
+#define r_scratchH 1
+
+#if defined (L_mulha3)
+DEFUN __mulha3
+ mov r_resL, r_arg1H
+ eor r_resL, r_arg2H
+ bst r_resL, 7
+ sbrs r_arg1H, 7
+ rjmp 1f
+ neg2 r_arg1L
+1:
+ sbrs r_arg2H, 7
+ rjmp 2f
+ neg2 r_arg2L
+2:
+ XCALL __muluha3
+ brtc __mulha3_exit
+ neg2 r_resL
+__mulha3_exit:
+ ret
+ENDF __mulha3
+#endif /* defined (L_mulha3) */
+
+#if defined (L_muluha3)
+DEFUN __muluha3
+ clr r_resL ; clear result
+ clr r_resH
+ wmov 0, r_arg1L ; save multiplicand
+__muluha3_loop1:
+ sbrs r_arg2H,0
+ rjmp 0f
+ add r_resL,r_arg1L ; result + multiplicand
+ adc r_resH,r_arg1H
+0:
+ lsl r_arg1L ; shift multiplicand
+ rol r_arg1H
+ sbiw r_arg1L,0
+ breq __muluha3_loop1_done ; exit multiplicand = 0
+ lsr r_arg2H
+ brne __muluha3_loop1 ; exit multiplier = 0
+__muluha3_loop1_done:
+ wmov r_arg1L, r_scratchL ; restore multiplicand
+__muluha3_loop2:
+ lsr r_arg1H ; shift multiplicand
+ ror r_arg1L
+ sbiw r_arg1L,0
+ breq __muluha3_exit ; exit if multiplicand = 0
+ sbrs r_arg2L,7
+ rjmp 0f
+ add r_resL,r_arg1L ; result + multiplicand
+ adc r_resH,r_arg1H
+0:
+ lsl r_arg2L
+ brne __muluha3_loop2 ; exit if multiplier = 0
+__muluha3_exit:
+ clr __zero_reg__ ; got clobbered
+ ret
+ENDF __muluha3
+#endif /* defined (L_muluha3) */
+
+#undef r_arg1L
+#undef r_arg1H
+#undef r_arg2L
+#undef r_arg2H
+#undef r_resL
+#undef r_resH
+#undef r_scratchL
+#undef r_scratchH
+
+#endif /* defined (__AVR_HAVE_MUL__) */
+
+
+/*******************************************************
+ Fixed Multiplication 16.16 x 16.16
+*******************************************************/
+
+#if defined (__AVR_HAVE_MUL__)
+/* uses nonstandard registers because mulus only works from 16-23 */
+#define r_clr r15
+
+#define r_arg1L r16 /* multiplier Low */
+#define r_arg1H r17
+#define r_arg1HL r18
+#define r_arg1HH r19 /* multiplier High */
+
+#define r_arg2L r20 /* multiplicand Low */
+#define r_arg2H r21
+#define r_arg2HL r22
+#define r_arg2HH r23 /* multiplicand High */
+
+#define r_resL r24 /* result Low */
+#define r_resH r25
+#define r_resHL r26
+#define r_resHH r27 /* result High */
+
+#if defined (L_mulsa3)
+DEFUN __mulsa3
+ clr r_clr
+ clr r_resH
+ clr r_resHL
+ clr r_resHH
+ mul r_arg1H, r_arg2L
+ mov r_resL, r1
+ mul r_arg1L, r_arg2H
+ add r_resL, r1
+ adc r_resH, r_clr
+ mul r_arg1L, r_arg2HL
+ add r_resL, r0
+ adc r_resH, r1
+ adc r_resHL, r_clr
+ mul r_arg1H, r_arg2H
+ add r_resL, r0
+ adc r_resH, r1
+ adc r_resHL, r_clr
+ mul r_arg1HL, r_arg2L
+ add r_resL, r0
+ adc r_resH, r1
+ adc r_resHL, r_clr
+ mulsu r_arg2HH, r_arg1L
+ sbc r_resHH, r_clr
+ add r_resH, r0
+ adc r_resHL, r1
+ adc r_resHH, r_clr
+ mul r_arg1H, r_arg2HL
+ add r_resH, r0
+ adc r_resHL, r1
+ adc r_resHH, r_clr
+ mul r_arg1HL, r_arg2H
+ add r_resH, r0
+ adc r_resHL, r1
+ adc r_resHH, r_clr
+ mulsu r_arg1HH, r_arg2L
+ sbc r_resHH, r_clr
+ add r_resH, r0
+ adc r_resHL, r1
+ adc r_resHH, r_clr
+ mulsu r_arg2HH, r_arg1H
+ add r_resHL, r0
+ adc r_resHH, r1
+ mul r_arg1HL, r_arg2HL
+ add r_resHL, r0
+ adc r_resHH, r1
+ mulsu r_arg1HH, r_arg2H
+ add r_resHL, r0
+ adc r_resHH, r1
+ mulsu r_arg2HH, r_arg1HL
+ add r_resHH, r0
+ mulsu r_arg1HH, r_arg2HL
+ add r_resHH, r0
+ clr __zero_reg__
+ ret
+ENDF __mulsa3
+#endif /* L_mulsa3 */
+
+#if defined (L_mulusa3)
+DEFUN __mulusa3
+ clr r_clr
+ clr r_resH
+ clr r_resHL
+ clr r_resHH
+ mul r_arg1H, r_arg2L
+ mov r_resL, r1
+ mul r_arg1L, r_arg2H
+ add r_resL, r1
+ adc r_resH, r_clr
+ mul r_arg1L, r_arg2HL
+ add r_resL, r0
+ adc r_resH, r1
+ adc r_resHL, r_clr
+ mul r_arg1H, r_arg2H
+ add r_resL, r0
+ adc r_resH, r1
+ adc r_resHL, r_clr
+ mul r_arg1HL, r_arg2L
+ add r_resL, r0
+ adc r_resH, r1
+ adc r_resHL, r_clr
+ mul r_arg1L, r_arg2HH
+ add r_resH, r0
+ adc r_resHL, r1
+ adc r_resHH, r_clr
+ mul r_arg1H, r_arg2HL
+ add r_resH, r0
+ adc r_resHL, r1
+ adc r_resHH, r_clr
+ mul r_arg1HL, r_arg2H
+ add r_resH, r0
+ adc r_resHL, r1
+ adc r_resHH, r_clr
+ mul r_arg1HH, r_arg2L
+ add r_resH, r0
+ adc r_resHL, r1
+ adc r_resHH, r_clr
+ mul r_arg1H, r_arg2HH
+ add r_resHL, r0
+ adc r_resHH, r1
+ mul r_arg1HL, r_arg2HL
+ add r_resHL, r0
+ adc r_resHH, r1
+ mul r_arg1HH, r_arg2H
+ add r_resHL, r0
+ adc r_resHH, r1
+ mul r_arg1HL, r_arg2HH
+ add r_resHH, r0
+ mul r_arg1HH, r_arg2HL
+ add r_resHH, r0
+ clr __zero_reg__
+ ret
+ENDF __mulusa3
+#endif /* L_mulusa3 */
+
+#undef r_arg1L
+#undef r_arg1H
+#undef r_arg1HL
+#undef r_arg1HH
+
+#undef r_arg2L
+#undef r_arg2H
+#undef r_arg2HL
+#undef r_arg2HH
+
+#undef r_resL
+#undef r_resH
+#undef r_resHL
+#undef r_resHH
+#undef r_clr
+
+#else /* defined (__AVR_HAVE_MUL__) */
+
+#define r_arg1L 18 /* multiplier Low */
+#define r_arg1H 19
+#define r_arg1HL 20
+#define r_arg1HH 21 /* multiplier High */
+
+;; These registers needed for SBIW */
+#define r_arg2L 24 /* multiplicand Low */
+#define r_arg2H 25
+#define r_arg2HL 26
+#define r_arg2HH 27 /* multiplicand High */
+
+#define r_resL 14 /* result Low */
+#define r_resH 15
+#define r_resHL 16
+#define r_resHH 17 /* result High */
+
+#define r_scratchL 0 /* scratch Low */
+#define r_scratchH 1
+#define r_scratchHL 22
+#define r_scratchHH 23 /* scratch High */
+
+#if defined (L_mulsa3)
+DEFUN __mulsa3
+ mov r_resL, r_arg1HH
+ eor r_resL, r_arg2HH
+ bst r_resL, 7
+ sbrs r_arg1HH, 7
+ rjmp 1f
+ neg4 r_arg1L
+1:
+ sbrs r_arg2HH, 7
+ rjmp 2f
+ neg4 r_arg2L
+2:
+ XCALL __mulusa3
+ brtc __mulsa3_exit
+ neg4 r_resL
+__mulsa3_exit:
+ ret
+ENDF __mulsa3
+#endif /* defined (L_mulsa3) */
+
+#if defined (L_mulusa3)
+DEFUN __mulusa3
+ clr r_resL ; clear result
+ clr r_resH
+ wmov r_resHL, r_resL
+ wmov r_scratchL, r_arg1L ; save multiplicand
+ wmov r_scratchHL, r_arg1HL
+__mulusa3_loop1:
+ sbrs r_arg2HL,0
+ rjmp 0f
+ add r_resL,r_arg1L ; result + multiplicand
+ adc r_resH,r_arg1H
+ adc r_resHL,r_arg1HL
+ adc r_resHH,r_arg1HH
+0:
+ lsl r_arg1L ; shift multiplicand
+ rol r_arg1H
+ rol r_arg1HL
+ rol r_arg1HH
+ lsr r_arg2HH
+ ror r_arg2HL
+ sbiw r_arg2HL,0
+ brne __mulusa3_loop1 ; exit multiplier = 0
+ wmov r_arg1L, r_scratchL ; restore multiplicand
+ wmov r_arg1HL, r_scratchHL
+__mulusa3_loop2:
+ lsr r_arg1HH ; shift multiplicand
+ ror r_arg1HL
+ ror r_arg1H
+ ror r_arg1L
+ sbrs r_arg2H,7
+ rjmp 1f
+ add r_resL,r_arg1L ; result + multiplicand
+ adc r_resH,r_arg1H
+ adc r_resHL,r_arg1HL
+ adc r_resHH,r_arg1HH
+1:
+ lsl r_arg2L
+ rol r_arg2H
+ sbiw r_arg2L,0
+ brne __mulusa3_loop2 ; exit if multiplier = 0
+ clr __zero_reg__ ; got clobbered
+ ret
+ENDF __mulusa3
+#endif /* defined (L_mulusa3) */
+
+#undef r_scratchL
+#undef r_scratchH
+#undef r_scratchHL
+#undef r_scratchHH
+
+#undef r_arg1L
+#undef r_arg1H
+#undef r_arg1HL
+#undef r_arg1HH
+
+#undef r_arg2L
+#undef r_arg2H
+#undef r_arg2HL
+#undef r_arg2HH
+
+#undef r_resL
+#undef r_resH
+#undef r_resHL
+#undef r_resHH
+
+#endif /* defined (__AVR_HAVE_MUL__) */
+
+/*******************************************************
+ Fractional Division 8 / 8
+*******************************************************/
+
+#define r_divd r25 /* dividend */
+#define r_quo r24 /* quotient */
+#define r_div r22 /* divisor */
+
+#if defined (L_divqq3)
+DEFUN __divqq3
+ mov r0, r_divd
+ eor r0, r_div
+ sbrc r_div, 7
+ neg r_div
+ sbrc r_divd, 7
+ neg r_divd
+ cp r_divd, r_div
+ breq __divqq3_minus1 ; if equal return -1
+ XCALL __udivuqq3
+ lsr r_quo
+ sbrc r0, 7 ; negate result if needed
+ neg r_quo
+ ret
+__divqq3_minus1:
+ ldi r_quo, 0x80
+ ret
+ENDF __divqq3
+#endif /* defined (L_divqq3) */
+
+#if defined (L_udivuqq3)
+DEFUN __udivuqq3
+ clr r_quo ; clear quotient
+ inc __zero_reg__ ; init loop counter, used per shift
+__udivuqq3_loop:
+ lsl r_divd ; shift dividend
+ brcs 0f ; dividend overflow
+ cp r_divd,r_div ; compare dividend & divisor
+ brcc 0f ; dividend >= divisor
+ rol r_quo ; shift quotient (with CARRY)
+ rjmp __udivuqq3_cont
+0:
+ sub r_divd,r_div ; restore dividend
+ lsl r_quo ; shift quotient (without CARRY)
+__udivuqq3_cont:
+ lsl __zero_reg__ ; shift loop-counter bit
+ brne __udivuqq3_loop
+ com r_quo ; complement result
+ ; because C flag was complemented in loop
+ ret
+ENDF __udivuqq3
+#endif /* defined (L_udivuqq3) */
+
+#undef r_divd
+#undef r_quo
+#undef r_div
+
+
+/*******************************************************
+ Fractional Division 16 / 16
+*******************************************************/
+#define r_divdL 26 /* dividend Low */
+#define r_divdH 27 /* dividend Hig */
+#define r_quoL 24 /* quotient Low */
+#define r_quoH 25 /* quotient High */
+#define r_divL 22 /* divisor */
+#define r_divH 23 /* divisor */
+#define r_cnt 21
+
+#if defined (L_divhq3)
+DEFUN __divhq3
+ mov r0, r_divdH
+ eor r0, r_divH
+ sbrs r_divH, 7
+ rjmp 1f
+ neg2 r_divL
+1:
+ sbrs r_divdH, 7
+ rjmp 2f
+ neg2 r_divdL
+2:
+ cp r_divdL, r_divL
+ cpc r_divdH, r_divH
+ breq __divhq3_minus1 ; if equal return -1
+ XCALL __udivuhq3
+ lsr r_quoH
+ ror r_quoL
+ brpl 9f
+ ;; negate result if needed
+ neg2 r_quoL
+9:
+ ret
+__divhq3_minus1:
+ ldi r_quoH, 0x80
+ clr r_quoL
+ ret
+ENDF __divhq3
+#endif /* defined (L_divhq3) */
+
+#if defined (L_udivuhq3)
+DEFUN __udivuhq3
+ sub r_quoH,r_quoH ; clear quotient and carry
+ ;; FALLTHRU
+ENDF __udivuhq3
+
+DEFUN __udivuha3_common
+ clr r_quoL ; clear quotient
+ ldi r_cnt,16 ; init loop counter
+__udivuhq3_loop:
+ rol r_divdL ; shift dividend (with CARRY)
+ rol r_divdH
+ brcs __udivuhq3_ep ; dividend overflow
+ cp r_divdL,r_divL ; compare dividend & divisor
+ cpc r_divdH,r_divH
+ brcc __udivuhq3_ep ; dividend >= divisor
+ rol r_quoL ; shift quotient (with CARRY)
+ rjmp __udivuhq3_cont
+__udivuhq3_ep:
+ sub r_divdL,r_divL ; restore dividend
+ sbc r_divdH,r_divH
+ lsl r_quoL ; shift quotient (without CARRY)
+__udivuhq3_cont:
+ rol r_quoH ; shift quotient
+ dec r_cnt ; decrement loop counter
+ brne __udivuhq3_loop
+ com r_quoL ; complement result
+ com r_quoH ; because C flag was complemented in loop
+ ret
+ENDF __udivuha3_common
+#endif /* defined (L_udivuhq3) */
+
+/*******************************************************
+ Fixed Division 8.8 / 8.8
+*******************************************************/
+#if defined (L_divha3)
+DEFUN __divha3
+ mov r0, r_divdH
+ eor r0, r_divH
+ sbrs r_divH, 7
+ rjmp 1f
+ neg2 r_divL
+1:
+ sbrs r_divdH, 7
+ rjmp 2f
+ neg2 r_divdL
+2:
+ XCALL __udivuha3
+ sbrs r0, 7 ; negate result if needed
+ ret
+ neg2 r_quoL
+ ret
+ENDF __divha3
+#endif /* defined (L_divha3) */
+
+#if defined (L_udivuha3)
+DEFUN __udivuha3
+ mov r_quoH, r_divdL
+ mov r_divdL, r_divdH
+ clr r_divdH
+ lsl r_quoH ; shift quotient into carry
+ XJMP __udivuha3_common ; same as fractional after rearrange
+ENDF __udivuha3
+#endif /* defined (L_udivuha3) */
+
+#undef r_divdL
+#undef r_divdH
+#undef r_quoL
+#undef r_quoH
+#undef r_divL
+#undef r_divH
+#undef r_cnt
+
+/*******************************************************
+ Fixed Division 16.16 / 16.16
+*******************************************************/
+
+#define r_arg1L 24 /* arg1 gets passed already in place */
+#define r_arg1H 25
+#define r_arg1HL 26
+#define r_arg1HH 27
+#define r_divdL 26 /* dividend Low */
+#define r_divdH 27
+#define r_divdHL 30
+#define r_divdHH 31 /* dividend High */
+#define r_quoL 22 /* quotient Low */
+#define r_quoH 23
+#define r_quoHL 24
+#define r_quoHH 25 /* quotient High */
+#define r_divL 18 /* divisor Low */
+#define r_divH 19
+#define r_divHL 20
+#define r_divHH 21 /* divisor High */
+#define r_cnt __zero_reg__ /* loop count (0 after the loop!) */
+
+#if defined (L_divsa3)
+DEFUN __divsa3
+ mov r0, r_arg1HH
+ eor r0, r_divHH
+ sbrs r_divHH, 7
+ rjmp 1f
+ neg4 r_divL
+1:
+ sbrs r_arg1HH, 7
+ rjmp 2f
+ neg4 r_arg1L
+2:
+ XCALL __udivusa3
+ sbrs r0, 7 ; negate result if needed
+ ret
+ neg4 r_quoL
+ ret
+ENDF __divsa3
+#endif /* defined (L_divsa3) */
+
+#if defined (L_udivusa3)
+DEFUN __udivusa3
+ ldi r_divdHL, 32 ; init loop counter
+ mov r_cnt, r_divdHL
+ clr r_divdHL
+ clr r_divdHH
+ wmov r_quoL, r_divdHL
+ lsl r_quoHL ; shift quotient into carry
+ rol r_quoHH
+__udivusa3_loop:
+ rol r_divdL ; shift dividend (with CARRY)
+ rol r_divdH
+ rol r_divdHL
+ rol r_divdHH
+ brcs __udivusa3_ep ; dividend overflow
+ cp r_divdL,r_divL ; compare dividend & divisor
+ cpc r_divdH,r_divH
+ cpc r_divdHL,r_divHL
+ cpc r_divdHH,r_divHH
+ brcc __udivusa3_ep ; dividend >= divisor
+ rol r_quoL ; shift quotient (with CARRY)
+ rjmp __udivusa3_cont
+__udivusa3_ep:
+ sub r_divdL,r_divL ; restore dividend
+ sbc r_divdH,r_divH
+ sbc r_divdHL,r_divHL
+ sbc r_divdHH,r_divHH
+ lsl r_quoL ; shift quotient (without CARRY)
+__udivusa3_cont:
+ rol r_quoH ; shift quotient
+ rol r_quoHL
+ rol r_quoHH
+ dec r_cnt ; decrement loop counter
+ brne __udivusa3_loop
+ com r_quoL ; complement result
+ com r_quoH ; because C flag was complemented in loop
+ com r_quoHL
+ com r_quoHH
+ ret
+ENDF __udivusa3
+#endif /* defined (L_udivusa3) */
+
+#undef r_divdL
+#undef r_divdH
+#undef r_divdHL
+#undef r_divdHH
+#undef r_quoL
+#undef r_quoH
+#undef r_quoHL
+#undef r_quoHH
+#undef r_divL
+#undef r_divH
+#undef r_divHL
+#undef r_divHH
+#undef r_cnt
Index: libgcc/config/avr/lib1funcs.S
===================================================================
--- libgcc/config/avr/lib1funcs.S (revision 190299)
+++ libgcc/config/avr/lib1funcs.S (working copy)
@@ -91,6 +91,32 @@ see the files COPYING3 and COPYING.RUNTI
.endfunc
.endm
+;; Negate a 2-byte value held in consecutive registers
+.macro neg2 reg
+ com \reg+1
+ neg \reg
+ sbci \reg+1, -1
+.endm
+
+;; Negate a 4-byte value held in consecutive registers
+.macro neg4 reg
+ com \reg+3
+ com \reg+2
+ com \reg+1
+.if \reg >= 16
+ neg \reg
+ sbci \reg+1, -1
+ sbci \reg+2, -1
+ sbci \reg+3, -1
+.else
+ com \reg
+ adc \reg, __zero_reg__
+ adc \reg+1, __zero_reg__
+ adc \reg+2, __zero_reg__
+ adc \reg+3, __zero_reg__
+.endif
+.endm
+
\f
.section .text.libgcc.mul, "ax", @progbits
@@ -1247,6 +1273,22 @@ __divmodsi4_exit:
ENDF __divmodsi4
#endif /* defined (L_divmodsi4) */
+#undef r_remHH
+#undef r_remHL
+#undef r_remH
+#undef r_remL
+
+#undef r_arg1HH
+#undef r_arg1HL
+#undef r_arg1H
+#undef r_arg1L
+
+#undef r_arg2HH
+#undef r_arg2HL
+#undef r_arg2H
+#undef r_arg2L
+
+#undef r_cnt
/*******************************************************
Division 64 / 64
@@ -2794,3 +2836,5 @@ ENDF __fmul
#undef B1
#undef C0
#undef C1
+
+#include "lib1funcs-fixed.S"
Index: libgcc/config/avr/t-avr
===================================================================
--- libgcc/config/avr/t-avr (revision 190299)
+++ libgcc/config/avr/t-avr (working copy)
@@ -55,6 +55,24 @@ LIB1ASMFUNCS = \
_cmpdi2 _cmpdi2_s8 \
_fmul _fmuls _fmulsu
+# Fixed point routines in avr/lib1funcs-fixed.S
+LIB1ASMFUNCS += \
+ _fractqqsf _fractuqqsf \
+ _fracthqsf _fractuhqsf \
+ _fracthasf _fractuhasf \
+ _fractsasf _fractusasf \
+ _fractsfqq _fractsfuqq \
+ _fractsfhq _fractsfuhq \
+ _fractsfha _fractsfsa \
+ _mulqq3 _muluqq3 \
+ _mulhq3 _muluhq3 \
+ _mulha3 _muluha3 \
+ _mulsa3 _mulusa3 \
+ _divqq3 _udivuqq3 \
+ _divhq3 _udivuhq3 \
+ _divha3 _udivuha3 \
+ _divsa3 _udivusa3
+
LIB2FUNCS_EXCLUDE = \
_moddi3 _umoddi3 \
_clz
next reply other threads:[~2012-08-10 15:53 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-08-10 15:53 Georg-Johann Lay [this message]
2012-08-10 16:09 ` Weddington, Eric
2012-08-10 17:06 ` Georg-Johann Lay
2012-08-10 17:56 ` Weddington, Eric
2012-08-10 21:34 ` Georg-Johann Lay
2012-08-12 9:13 ` Denis Chertykov
2012-08-13 9:28 ` Georg-Johann Lay
2012-08-21 16:10 ` Denis Chertykov
2012-08-23 14:50 ` Georg-Johann Lay
2012-08-23 16:42 ` Weddington, Eric
2012-08-23 17:25 ` Georg-Johann Lay
2012-08-24 11:58 ` Denis Chertykov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=50252E25.3020901@gjlay.de \
--to=avr@gjlay.de \
--cc=chertykov@gmail.com \
--cc=eric.weddington@atmel.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=joerg_wunsch@uriah.heep.sax.de \
--cc=sean@depagnier.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).