aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorGeorg-Johann Lay <avr@gjlay.de>2012-01-02 12:30:56 +0000
committerGeorg-Johann Lay <gjl@gcc.gnu.org>2012-01-02 12:30:56 +0000
commit8c57e5473e707a0def3df29d89336b96abca9388 (patch)
tree3c24b38e4a5abc3d1734ad1478057a319e4036c7 /gcc
parent5f595f167555e127f24d3defedf431b06209bdfc (diff)
downloadgcc-8c57e5473e707a0def3df29d89336b96abca9388.zip
gcc-8c57e5473e707a0def3df29d89336b96abca9388.tar.gz
gcc-8c57e5473e707a0def3df29d89336b96abca9388.tar.bz2
Implement light-weight DImode support.
gcc/ Implement light-weight DImode support. * config/avr/avr-dimode.md: New file. * config/avr/avr.md: Include it. (adjust_len): Add plus64, compare64. (HIDI): Remove code iterator. (code_stdname): New code attribute. (rotx, rotsmode): Remove DI. (rotl<mode>3, *rotw<mode>, *rotb<mode>): Use HISI instead of HIDI as code iterator. * config/avr/avr-protos.h (avr_have_dimode): New. (avr_out_plus64, avr_out_compare64): New. * config/avr/avr.c (avr_out_compare): Handle DImode. (avr_have_dimode): New variable definition and initialization. (avr_out_compare64, avr_out_plus64): New functions. (avr_out_plus_1): Use simplify_unary_operation to negate xval. (adjust_insn_length): Handle ADJUST_LEN_COMPARE64, ADJUST_LEN_PLUS64. (avr_compare_pattern): Skip DImode comparisons. libgcc/ Implement light-weight DImode support. * config/avr/t-avr (LIB1ASMFUNCS): Add _adddi3, _adddi3_s8, _subdi3, _cmpdi2, _cmpdi2_s8, _rotldi3. * config/avr/lib1funcs.S (__adddi3, __adddi3_s8, __subdi3, __cmpdi2, __cmpdi2_s8, __rotldi3): New functions. From-SVN: r182794
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog20
-rw-r--r--gcc/config/avr/avr-dimode.md283
-rw-r--r--gcc/config/avr/avr-protos.h4
-rw-r--r--gcc/config/avr/avr.c53
-rw-r--r--gcc/config/avr/avr.md50
5 files changed, 381 insertions, 29 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 7284b31..9081d54 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,23 @@
+2012-01-02 Georg-Johann Lay <avr@gjlay.de>
+
+ Implement light-weight DImode support.
+ * config/avr/avr-dimode.md: New file.
+ * config/avr/avr.md: Include it.
+ (adjust_len): Add plus64, compare64.
+ (HIDI): Remove code iterator.
+ (code_stdname): New code attribute.
+ (rotx, rotsmode): Remove DI.
+ (rotl<mode>3, *rotw<mode>, *rotb<mode>): Use HISI instead of HIDI
+ as code iterator.
+ * config/avr/avr-protos.h (avr_have_dimode): New.
+ (avr_out_plus64, avr_out_compare64): New.
+ * config/avr/avr.c (avr_out_compare): Handle DImode.
+ (avr_have_dimode): New variable definition and initialization.
+ (avr_out_compare64, avr_out_plus64): New functions.
+ (avr_out_plus_1): Use simplify_unary_operation to negate xval.
+ (adjust_insn_length): Handle ADJUST_LEN_COMPARE64, ADJUST_LEN_PLUS64.
+ (avr_compare_pattern): Skip DImode comparisons.
+
2012-01-02 Revital Eres <revital.eres@linaro.org>
* ddg.c (def_has_ccmode_p): New function.
diff --git a/gcc/config/avr/avr-dimode.md b/gcc/config/avr/avr-dimode.md
new file mode 100644
index 0000000..3db069b
--- /dev/null
+++ b/gcc/config/avr/avr-dimode.md
@@ -0,0 +1,283 @@
+;; Machine description for GNU compiler,
+;; for Atmel AVR micro controllers.
+;; Copyright (C) 1998 - 2011
+;; Free Software Foundation, Inc.
+;; Contributed by Georg Lay (avr@gjlay.de)
+;;
+;; 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/>.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; The purpose of this file is to provide a light-weight DImode
+;; implementation for AVR. The trouble with DImode is that tree -> RTL
+;; lowering leads to really unpleasant code for operations that don't
+;; work byte-wise like NEG, PLUS, MINUS, etc. Defining optabs entries for
+;; them won't help because the optab machinery assumes these operations
+;; are cheap and does not check if a libgcc implementation is available.
+;;
+;; The DImode insns are all straight forward -- except movdi. The approach
+;; of this implementation is to provide DImode insns without the burden of
+;; introducing movdi.
+;;
+;; The caveat is that if there are insns for some mode, there must also be a
+;; respective move insn that describes reloads. Therefore, this
+;; implementation uses an accumulator-based model with two hard-coded,
+;; accumulator-like registers
+;;
+;; A[] = reg:DI 18
+;; B[] = reg:DI 10
+;;
+;; so that no DImode insn contains pseudos or needs reloading.
+
+(define_constants
+ [(ACC_A 18)
+ (ACC_B 10)])
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Addition
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define_expand "adddi3"
+ [(parallel [(match_operand:DI 0 "general_operand" "")
+ (match_operand:DI 1 "general_operand" "")
+ (match_operand:DI 2 "general_operand" "")])]
+ "avr_have_dimode"
+ {
+ rtx acc_a = gen_rtx_REG (DImode, ACC_A);
+
+ emit_move_insn (acc_a, operands[1]);
+
+ if (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]))
+ {
+ emit_insn (gen_adddi3_const_insn (operands[2]));
+ }
+ else
+ {
+ emit_move_insn (gen_rtx_REG (DImode, ACC_B), operands[2]);
+ emit_insn (gen_adddi3_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)))]
+ "avr_have_dimode"
+ "%~call __adddi3"
+ [(set_attr "adjust_len" "call")
+ (set_attr "cc" "clobber")])
+
+(define_insn "adddi3_const8_insn"
+ [(set (reg:DI ACC_A)
+ (plus:DI (reg:DI ACC_A)
+ (sign_extend:DI (reg:QI REG_X))))]
+ "avr_have_dimode"
+ "%~call __adddi3_s8"
+ [(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")))]
+ "avr_have_dimode
+ && !s8_operand (operands[0], VOIDmode)"
+ {
+ return avr_out_plus64 (operands[0], NULL);
+ }
+ [(set_attr "adjust_len" "plus64")
+ (set_attr "cc" "clobber")])
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Subtraction
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define_expand "subdi3"
+ [(parallel [(match_operand:DI 0 "general_operand" "")
+ (match_operand:DI 1 "general_operand" "")
+ (match_operand:DI 2 "general_operand" "")])]
+ "avr_have_dimode"
+ {
+ rtx acc_a = gen_rtx_REG (DImode, 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 ());
+ 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)))]
+ "avr_have_dimode"
+ "%~call __subdi3"
+ [(set_attr "adjust_len" "call")
+ (set_attr "cc" "set_czn")])
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Negation
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define_expand "negdi2"
+ [(parallel [(match_operand:DI 0 "general_operand" "")
+ (match_operand:DI 1 "general_operand" "")])]
+ "avr_have_dimode"
+ {
+ rtx acc_a = gen_rtx_REG (DImode, ACC_A);
+
+ emit_move_insn (acc_a, operands[1]);
+ emit_insn (gen_negdi2_insn ());
+ emit_move_insn (operands[0], acc_a);
+ DONE;
+ })
+
+(define_insn "negdi2_insn"
+ [(set (reg:DI ACC_A)
+ (neg:DI (reg:DI ACC_A)))]
+ "avr_have_dimode"
+ "%~call __negdi2"
+ [(set_attr "adjust_len" "call")
+ (set_attr "cc" "clobber")])
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Comparison
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define_expand "conditional_jump"
+ [(set (pc)
+ (if_then_else
+ (match_operator 0 "ordered_comparison_operator" [(cc0)
+ (const_int 0)])
+ (label_ref (match_operand 1 "" ""))
+ (pc)))]
+ "avr_have_dimode")
+
+(define_expand "cbranchdi4"
+ [(parallel [(match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 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);
+
+ emit_move_insn (acc_a, operands[1]);
+
+ if (s8_operand (operands[2], VOIDmode))
+ {
+ 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]))
+ {
+ emit_insn (gen_compare_const_di2 (operands[2]));
+ }
+ else
+ {
+ emit_move_insn (gen_rtx_REG (DImode, ACC_B), operands[2]);
+ emit_insn (gen_compare_di2 ());
+ }
+
+ emit_jump_insn (gen_conditional_jump (operands[0], operands[3]));
+ DONE;
+ })
+
+(define_insn "compare_di2"
+ [(set (cc0)
+ (compare (reg:DI ACC_A)
+ (reg:DI ACC_B)))]
+ "avr_have_dimode"
+ "%~call __cmpdi2"
+ [(set_attr "adjust_len" "call")
+ (set_attr "cc" "compare")])
+
+(define_insn "compare_const8_di2"
+ [(set (cc0)
+ (compare (reg:DI ACC_A)
+ (sign_extend:DI (reg:QI REG_X))))]
+ "avr_have_dimode"
+ "%~call __cmpdi2_s8"
+ [(set_attr "adjust_len" "call")
+ (set_attr "cc" "compare")])
+
+(define_insn "compare_const_di2"
+ [(set (cc0)
+ (compare (reg:DI ACC_A)
+ (match_operand:DI 0 "const_double_operand" "n")))
+ (clobber (match_scratch:QI 1 "=&d"))]
+ "avr_have_dimode
+ && !s8_operand (operands[0], VOIDmode)"
+ {
+ return avr_out_compare64 (insn, operands, NULL);
+ }
+ [(set_attr "adjust_len" "compare64")
+ (set_attr "cc" "compare")])
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Shifts and Rotate
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define_code_iterator di_shifts
+ [ashift ashiftrt lshiftrt rotate])
+
+;; Shift functions from libgcc are called without defining these insns,
+;; but with them we can describe their reduced register footprint.
+
+;; "ashldi3"
+;; "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" ""))])]
+ "avr_have_dimode"
+ {
+ rtx acc_a = gen_rtx_REG (DImode, 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_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)))]
+ "avr_have_dimode"
+ "%~call __<code_stdname>di3"
+ [(set_attr "adjust_len" "call")
+ (set_attr "cc" "clobber")])
diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h
index 1230451..09f8271 100644
--- a/gcc/config/avr/avr-protos.h
+++ b/gcc/config/avr/avr-protos.h
@@ -56,6 +56,7 @@ extern const char *avr_out_tstsi (rtx, rtx*, int*);
extern const char *avr_out_tsthi (rtx, rtx*, int*);
extern const char *avr_out_tstpsi (rtx, rtx*, int*);
extern const char *avr_out_compare (rtx, rtx*, int*);
+extern const char *avr_out_compare64 (rtx, rtx*, int*);
extern const char *ret_cond_branch (rtx x, int len, int reverse);
extern const char *avr_out_movpsi (rtx, rtx*, int*);
@@ -89,6 +90,7 @@ extern const char *avr_out_sbxx_branch (rtx insn, rtx operands[]);
extern const char* avr_out_bitop (rtx, rtx*, int*);
extern const char* avr_out_plus (rtx*, int*, int*);
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_xload (rtx, rtx*, int*);
extern const char* avr_out_movmem (rtx, rtx*, int*);
@@ -128,6 +130,8 @@ extern bool avr_xload_libgcc_p (enum machine_mode);
extern void asm_output_float (FILE *file, REAL_VALUE_TYPE n);
#endif
+extern bool avr_have_dimode;
+
/* From avr-log.c */
#define avr_edump (avr_log_set_caller_e (__FUNCTION__))
diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c
index 2493638..652e41c 100644
--- a/gcc/config/avr/avr.c
+++ b/gcc/config/avr/avr.c
@@ -164,6 +164,9 @@ static GTY(()) section *progmem_swtable_section;
or to address space __pgm*. */
static GTY(()) section *progmem_section[6];
+/* Condition for insns/expanders from avr-dimode.md. */
+bool avr_have_dimode = true;
+
/* To track if code will use .bss and/or .data. */
bool avr_need_clear_bss_p = false;
bool avr_need_copy_data_p = false;
@@ -4091,14 +4094,17 @@ avr_out_compare (rtx insn, rtx *xop, int *plen)
/* Value (0..0xff) held in clobber register xop[2] or -1 if unknown. */
int clobber_val = -1;
- gcc_assert (REG_P (xreg)
- && CONST_INT_P (xval));
+ gcc_assert (REG_P (xreg));
+ gcc_assert ((CONST_INT_P (xval) && n_bytes <= 4)
+ || (const_double_operand (xval, VOIDmode) && n_bytes == 8));
if (plen)
*plen = 0;
/* Comparisons == +/-1 and != +/-1 can be done similar to camparing
- against 0 by ORing the bytes. This is one instruction shorter. */
+ against 0 by ORing the bytes. This is one instruction shorter.
+ Notice that DImode comparisons are always against reg:DI 18
+ and therefore don't use this. */
if (!test_hard_reg_class (LD_REGS, xreg)
&& compare_eq_p (insn)
@@ -4216,6 +4222,20 @@ avr_out_compare (rtx insn, rtx *xop, int *plen)
}
+/* Prepare operands of compare_const_di2 to be used with avr_out_compare. */
+
+const char*
+avr_out_compare64 (rtx insn, rtx *op, int *plen)
+{
+ rtx xop[3];
+
+ xop[0] = gen_rtx_REG (DImode, 18);
+ xop[1] = op[0];
+ xop[2] = op[1];
+
+ return avr_out_compare (insn, xop, plen);
+}
+
/* Output test instruction for HImode. */
const char*
@@ -5855,7 +5875,7 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc)
*pcc = (MINUS == code) ? CC_SET_CZN : CC_CLOBBER;
if (MINUS == code)
- xval = gen_int_mode (-UINTVAL (xval), mode);
+ xval = simplify_unary_operation (NEG, mode, xval, mode);
op[2] = xop[3];
@@ -6030,6 +6050,25 @@ avr_out_plus_noclobber (rtx *xop, int *plen, int *pcc)
return avr_out_plus (op, plen, pcc);
}
+
+/* Prepare operands of adddi3_const_insn to be used with avr_out_plus_1. */
+
+const char*
+avr_out_plus64 (rtx addend, int *plen)
+{
+ int cc_dummy;
+ rtx op[4];
+
+ op[0] = gen_rtx_REG (DImode, 18);
+ op[1] = op[0];
+ op[2] = addend;
+ op[3] = NULL_RTX;
+
+ avr_out_plus_1 (op, plen, MINUS, &cc_dummy);
+
+ return "";
+}
+
/* Output bit operation (IOR, AND, XOR) with register XOP[0] and compile
time constant XOP[2]:
@@ -6415,6 +6454,7 @@ adjust_insn_length (rtx insn, int len)
case ADJUST_LEN_OUT_BITOP: avr_out_bitop (insn, op, &len); break;
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_OUT_PLUS_NOCLOBBER:
avr_out_plus_noclobber (op, &len, NULL); break;
@@ -6431,6 +6471,7 @@ adjust_insn_length (rtx insn, int len)
case ADJUST_LEN_TSTPSI: avr_out_tstpsi (insn, op, &len); break;
case ADJUST_LEN_TSTSI: avr_out_tstsi (insn, op, &len); break;
case ADJUST_LEN_COMPARE: avr_out_compare (insn, op, &len); break;
+ case ADJUST_LEN_COMPARE64: avr_out_compare64 (insn, op, &len); break;
case ADJUST_LEN_LSHRQI: lshrqi3_out (insn, op, &len); break;
case ADJUST_LEN_LSHRHI: lshrhi3_out (insn, op, &len); break;
@@ -8389,7 +8430,9 @@ avr_compare_pattern (rtx insn)
if (pattern
&& NONJUMP_INSN_P (insn)
&& SET_DEST (pattern) == cc0_rtx
- && GET_CODE (SET_SRC (pattern)) == COMPARE)
+ && GET_CODE (SET_SRC (pattern)) == COMPARE
+ && DImode != GET_MODE (XEXP (SET_SRC (pattern), 0))
+ && DImode != GET_MODE (XEXP (SET_SRC (pattern), 1)))
{
return pattern;
}
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index 21e329b..9222f0b 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -142,8 +142,8 @@
;; Otherwise do special processing depending on the attribute.
(define_attr "adjust_len"
- "out_bitop, out_plus, out_plus_noclobber, addto_sp,
- tsthi, tstpsi, tstsi, compare, call,
+ "out_bitop, out_plus, out_plus_noclobber, plus64, addto_sp,
+ tsthi, tstpsi, tstsi, compare, compare64, call,
mov8, mov16, mov24, mov32, reload_in16, reload_in24, reload_in32,
xload, movmem,
ashlqi, ashrqi, lshrqi,
@@ -218,7 +218,6 @@
(define_mode_iterator QIHI2 [(QI "") (HI "")])
(define_mode_iterator QISI [(QI "") (HI "") (PSI "") (SI "")])
(define_mode_iterator QIDI [(QI "") (HI "") (PSI "") (SI "") (DI "")])
-(define_mode_iterator HIDI [(HI "") (PSI "") (SI "") (DI "")])
(define_mode_iterator HISI [(HI "") (PSI "") (SI "")])
;; All supported move-modes
@@ -247,6 +246,12 @@
[(zero_extend "r")
(sign_extend "d")])
+;; Map RTX code to its standard insn name
+(define_code_attr code_stdname
+ [(ashift "ashl")
+ (ashiftrt "ashr")
+ (lshiftrt "lshr")
+ (rotate "rotl")])
;;========================================================================
;; The following is used by nonlocal_goto and setjmp.
@@ -3094,23 +3099,21 @@
[(set_attr "length" "2,4,4,1,3,5,3,0")
(set_attr "cc" "set_n,set_n,clobber,none,set_n,set_n,clobber,none")])
-;; Split all rotates of HI,SI and DImode registers where rotation is by
+;; Split all rotates of HI,SI and PSImode registers where rotation is by
;; a whole number of bytes. The split creates the appropriate moves and
-;; considers all overlap situations. DImode is split before reload.
+;; considers all overlap situations.
;; HImode does not need scratch. Use attribute for this constraint.
-;; Use QI scratch for DI mode as this is often split into byte sized operands.
-(define_mode_attr rotx [(DI "&r,&r,X") (SI "&r,&r,X") (PSI "&r,&r,X") (HI "X,X,X")])
-(define_mode_attr rotsmode [(DI "QI") (SI "HI") (PSI "QI") (HI "QI")])
+(define_mode_attr rotx [(SI "&r,&r,X") (PSI "&r,&r,X") (HI "X,X,X")])
+(define_mode_attr rotsmode [(SI "HI") (PSI "QI") (HI "QI")])
;; "rotlhi3"
;; "rotlpsi3"
;; "rotlsi3"
-;; "rotldi3"
(define_expand "rotl<mode>3"
- [(parallel [(set (match_operand:HIDI 0 "register_operand" "")
- (rotate:HIDI (match_operand:HIDI 1 "register_operand" "")
+ [(parallel [(set (match_operand:HISI 0 "register_operand" "")
+ (rotate:HISI (match_operand:HISI 1 "register_operand" "")
(match_operand:VOID 2 "const_int_operand" "")))
(clobber (match_dup 3))])]
""
@@ -3129,9 +3132,8 @@
else
operands[3] = gen_rtx_SCRATCH (QImode);
}
- else if (<MODE>mode != DImode
- && (offset == 1
- || offset == GET_MODE_BITSIZE (<MODE>mode) -1))
+ else if (offset == 1
+ || offset == GET_MODE_BITSIZE (<MODE>mode) -1)
{
/*; Support rotate left/right by 1 */
@@ -3207,18 +3209,17 @@
;; "*rotwhi"
;; "*rotwsi"
-;; "*rotwdi"
(define_insn_and_split "*rotw<mode>"
- [(set (match_operand:HIDI 0 "register_operand" "=r,r,#&r")
- (rotate:HIDI (match_operand:HIDI 1 "register_operand" "0,r,r")
- (match_operand 2 "const_int_operand" "n,n,n")))
+ [(set (match_operand:HISI 0 "register_operand" "=r,r,#&r")
+ (rotate:HISI (match_operand:HISI 1 "register_operand" "0,r,r")
+ (match_operand 2 "const_int_operand" "n,n,n")))
(clobber (match_scratch:<rotsmode> 3 "=<rotx>"))]
"AVR_HAVE_MOVW
&& CONST_INT_P (operands[2])
&& GET_MODE_SIZE (<MODE>mode) % 2 == 0
&& 0 == INTVAL (operands[2]) % 16"
"#"
- "&& (reload_completed || <MODE>mode == DImode)"
+ "&& reload_completed"
[(const_int 0)]
{
avr_rotate_bytes (operands);
@@ -3231,11 +3232,10 @@
;; "*rotbhi"
;; "*rotbpsi"
;; "*rotbsi"
-;; "*rotbdi"
(define_insn_and_split "*rotb<mode>"
- [(set (match_operand:HIDI 0 "register_operand" "=r,r,#&r")
- (rotate:HIDI (match_operand:HIDI 1 "register_operand" "0,r,r")
- (match_operand 2 "const_int_operand" "n,n,n")))
+ [(set (match_operand:HISI 0 "register_operand" "=r,r,#&r")
+ (rotate:HISI (match_operand:HISI 1 "register_operand" "0,r,r")
+ (match_operand 2 "const_int_operand" "n,n,n")))
(clobber (match_scratch:QI 3 "=<rotx>"))]
"CONST_INT_P (operands[2])
&& (8 == INTVAL (operands[2]) % 16
@@ -3243,7 +3243,7 @@
|| GET_MODE_SIZE (<MODE>mode) % 2 != 0)
&& 0 == INTVAL (operands[2]) % 16))"
"#"
- "&& (reload_completed || <MODE>mode == DImode)"
+ "&& reload_completed"
[(const_int 0)]
{
avr_rotate_bytes (operands);
@@ -5949,6 +5949,8 @@
operands[4] = simplify_gen_subreg (QImode, operands[0], HImode, 1);
})
+(include "avr-dimode.md")
+
(define_insn_and_split "*extzv.qihi2"
[(set (match_operand:HI 0 "register_operand" "=r")
(zero_extend:HI