summaryrefslogtreecommitdiff
path: root/gcc/config/avr/avr.c
diff options
context:
space:
mode:
authoraldyh <aldyh@138bc75d-0d04-0410-961f-82ee72b054a4>2011-11-08 03:20:30 +0000
committeraldyh <aldyh@138bc75d-0d04-0410-961f-82ee72b054a4>2011-11-08 03:20:30 +0000
commit643df0593c630691fa6877cddeefdd4c3023d444 (patch)
tree1eb48ad31d05a9ce117bedc17115de96dffa2f0b /gcc/config/avr/avr.c
parent54f3f029d816c6d1626310649adfda740e203f7b (diff)
parentd5d8f1ccc6d3972dc5cfc0949e85e0b1c9e24ee0 (diff)
downloadgcc-transactional-memory.tar.gz
* Merge from mainline rev 181122.transactional-memory
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/transactional-memory@181148 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/avr/avr.c')
-rw-r--r--gcc/config/avr/avr.c859
1 files changed, 731 insertions, 128 deletions
diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c
index 6435c4854f5..630b7ef19ee 100644
--- a/gcc/config/avr/avr.c
+++ b/gcc/config/avr/avr.c
@@ -71,7 +71,8 @@ static const char *ptrreg_to_str (int);
static const char *cond_string (enum rtx_code);
static int avr_num_arg_regs (enum machine_mode, const_tree);
static int avr_operand_rtx_cost (rtx, enum machine_mode, enum rtx_code,
- int, bool);
+ int, bool);
+static void output_reload_in_const (rtx*, rtx, int*, bool);
static struct machine_function * avr_init_machine_status (void);
@@ -217,6 +218,9 @@ bool avr_need_copy_data_p = false;
#undef TARGET_ASM_FUNCTION_RODATA_SECTION
#define TARGET_ASM_FUNCTION_RODATA_SECTION avr_asm_function_rodata_section
+#undef TARGET_SCALAR_MODE_SUPPORTED_P
+#define TARGET_SCALAR_MODE_SUPPORTED_P avr_scalar_mode_supported_p
+
/* Custom function to replace string prefix.
@@ -369,6 +373,17 @@ avr_regno_reg_class (int r)
return ALL_REGS;
}
+
+static bool
+avr_scalar_mode_supported_p (enum machine_mode mode)
+{
+ if (PSImode == mode)
+ return true;
+
+ return default_scalar_mode_supported_p (mode);
+}
+
+
/* A helper for the subsequent function attribute used to dig for
attribute 'name' in a FUNCTION_DECL or FUNCTION_TYPE */
@@ -1487,7 +1502,7 @@ avr_legitimize_reload_address (rtx *px, enum machine_mode mode,
/* Helper function to print assembler resp. track instruction
- sequence lengths.
+ sequence lengths. Always return "".
If PLEN == NULL:
Output assembler code from template TPL with operands supplied
@@ -1499,7 +1514,7 @@ avr_legitimize_reload_address (rtx *px, enum machine_mode mode,
Don't output anything.
*/
-static void
+static const char*
avr_asm_len (const char* tpl, rtx* operands, int* plen, int n_words)
{
if (NULL == plen)
@@ -1513,6 +1528,8 @@ avr_asm_len (const char* tpl, rtx* operands, int* plen, int n_words)
else
*plen += n_words;
}
+
+ return "";
}
@@ -1562,6 +1579,8 @@ cond_string (enum rtx_code code)
default:
gcc_unreachable ();
}
+
+ return "";
}
/* Output ADDR to FILE as address. */
@@ -1968,6 +1987,7 @@ avr_simplify_comparison_p (enum machine_mode mode, RTX_CODE op, rtx x)
{
unsigned int max = (mode == QImode ? 0xff :
mode == HImode ? 0xffff :
+ mode == PSImode ? 0xffffff :
mode == SImode ? 0xffffffff : 0);
if (max && op && GET_CODE (x) == CONST_INT)
{
@@ -2182,52 +2202,10 @@ output_movqi (rtx insn, rtx operands[], int *l)
return AS2 (mov,%0,%1);
}
else if (CONSTANT_P (src))
- {
- if (test_hard_reg_class (LD_REGS, dest)) /* ldi d,i */
- return AS2 (ldi,%0,lo8(%1));
-
- if (GET_CODE (src) == CONST_INT)
- {
- if (src == const0_rtx) /* mov r,L */
- return AS1 (clr,%0);
- else if (src == const1_rtx)
- {
- *l = 2;
- return (AS1 (clr,%0) CR_TAB
- AS1 (inc,%0));
- }
- else if (src == constm1_rtx)
- {
- /* Immediate constants -1 to any register */
- *l = 2;
- return (AS1 (clr,%0) CR_TAB
- AS1 (dec,%0));
- }
- else
- {
- int bit_nr = exact_log2 (INTVAL (src));
-
- if (bit_nr >= 0)
- {
- *l = 3;
- if (!real_l)
- output_asm_insn ((AS1 (clr,%0) CR_TAB
- "set"), operands);
- if (!real_l)
- avr_output_bld (operands, bit_nr);
-
- return "";
- }
- }
- }
-
- /* Last resort, larger than loading from memory. */
- *l = 4;
- return (AS2 (mov,__tmp_reg__,r31) CR_TAB
- AS2 (ldi,r31,lo8(%1)) CR_TAB
- AS2 (mov,%0,r31) CR_TAB
- AS2 (mov,r31,__tmp_reg__));
- }
+ {
+ output_reload_in_const (operands, NULL_RTX, real_l, false);
+ return "";
+ }
else if (GET_CODE (src) == MEM)
return out_movqi_r_mr (insn, operands, real_l); /* mov r,m */
}
@@ -2956,6 +2934,306 @@ output_movsisf (rtx insn, rtx operands[], int *l)
return "";
}
+
+/* Handle loads of 24-bit types from memory to register. */
+
+static const char*
+avr_out_load_psi (rtx insn, rtx *op, int *plen)
+{
+ rtx dest = op[0];
+ rtx src = op[1];
+ rtx base = XEXP (src, 0);
+ int reg_dest = true_regnum (dest);
+ int reg_base = true_regnum (base);
+
+ if (reg_base > 0)
+ {
+ if (reg_base == REG_X) /* (R26) */
+ {
+ if (reg_dest == REG_X)
+ /* "ld r26,-X" is undefined */
+ return avr_asm_len ("adiw r26,2" CR_TAB
+ "ld r28,X" CR_TAB
+ "ld __tmp_reg__,-X" CR_TAB
+ "sbiw r26,1" CR_TAB
+ "ld r26,X" CR_TAB
+ "mov r27,__tmp_reg__", op, plen, -6);
+ else
+ {
+ avr_asm_len ("ld %A0,X+" CR_TAB
+ "ld %B0,X+" CR_TAB
+ "ld %C0,X", op, plen, -3);
+
+ if (reg_dest != REG_X - 2
+ && !reg_unused_after (insn, base))
+ {
+ avr_asm_len ("sbiw r26,2", op, plen, 1);
+ }
+
+ return "";
+ }
+ }
+ else /* reg_base != REG_X */
+ {
+ if (reg_dest == reg_base)
+ return avr_asm_len ("ldd %C0,%1+2" CR_TAB
+ "ldd __tmp_reg__,%1+1" CR_TAB
+ "ld %A0,%1" CR_TAB
+ "mov %B0,__tmp_reg__", op, plen, -4);
+ else
+ return avr_asm_len ("ld %A0,%1" CR_TAB
+ "ldd %B0,%1+1" CR_TAB
+ "ldd %C0,%1+2", op, plen, -3);
+ }
+ }
+ else if (GET_CODE (base) == PLUS) /* (R + i) */
+ {
+ int disp = INTVAL (XEXP (base, 1));
+
+ if (disp > MAX_LD_OFFSET (GET_MODE (src)))
+ {
+ if (REGNO (XEXP (base, 0)) != REG_Y)
+ fatal_insn ("incorrect insn:",insn);
+
+ if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src)))
+ return avr_asm_len ("adiw r28,%o1-61" CR_TAB
+ "ldd %A0,Y+61" CR_TAB
+ "ldd %B0,Y+62" CR_TAB
+ "ldd %C0,Y+63" CR_TAB
+ "sbiw r28,%o1-61", op, plen, -5);
+
+ return avr_asm_len ("subi r28,lo8(-%o1)" CR_TAB
+ "sbci r29,hi8(-%o1)" CR_TAB
+ "ld %A0,Y" CR_TAB
+ "ldd %B0,Y+1" CR_TAB
+ "ldd %C0,Y+2" CR_TAB
+ "subi r28,lo8(%o1)" CR_TAB
+ "sbci r29,hi8(%o1)", op, plen, -7);
+ }
+
+ reg_base = true_regnum (XEXP (base, 0));
+ if (reg_base == REG_X)
+ {
+ /* R = (X + d) */
+ if (reg_dest == REG_X)
+ {
+ /* "ld r26,-X" is undefined */
+ return avr_asm_len ("adiw r26,%o1+2" CR_TAB
+ "ld r28,X" CR_TAB
+ "ld __tmp_reg__,-X" CR_TAB
+ "sbiw r26,1" CR_TAB
+ "ld r26,X" CR_TAB
+ "mov r27,__tmp_reg__", op, plen, -6);
+ }
+
+ avr_asm_len ("adiw r26,%o1" CR_TAB
+ "ld r24,X+" CR_TAB
+ "ld r25,X+" CR_TAB
+ "ld r26,X", op, plen, -4);
+
+ if (reg_dest != REG_X - 2)
+ avr_asm_len ("sbiw r26,%o1+2", op, plen, 1);
+
+ return "";
+ }
+
+ if (reg_dest == reg_base)
+ return avr_asm_len ("ldd %C0,%C1" CR_TAB
+ "ldd __tmp_reg__,%B1" CR_TAB
+ "ldd %A0,%A1" CR_TAB
+ "mov %B0,__tmp_reg__", op, plen, -4);
+
+ return avr_asm_len ("ldd %A0,%A1" CR_TAB
+ "ldd %B0,%B1" CR_TAB
+ "ldd %C0,%C1", op, plen, -3);
+ }
+ else if (GET_CODE (base) == PRE_DEC) /* (--R) */
+ return avr_asm_len ("ld %C0,%1" CR_TAB
+ "ld %B0,%1" CR_TAB
+ "ld %A0,%1", op, plen, -3);
+ else if (GET_CODE (base) == POST_INC) /* (R++) */
+ return avr_asm_len ("ld %A0,%1" CR_TAB
+ "ld %B0,%1" CR_TAB
+ "ld %C0,%1", op, plen, -3);
+
+ else if (CONSTANT_ADDRESS_P (base))
+ return avr_asm_len ("lds %A0,%m1" CR_TAB
+ "lds %B0,%m1+1" CR_TAB
+ "lds %C0,%m1+2", op, plen , -6);
+
+ fatal_insn ("unknown move insn:",insn);
+ return "";
+}
+
+/* Handle store of 24-bit type from register or zero to memory. */
+
+static const char*
+avr_out_store_psi (rtx insn, rtx *op, int *plen)
+{
+ rtx dest = op[0];
+ rtx src = op[1];
+ rtx base = XEXP (dest, 0);
+ int reg_base = true_regnum (base);
+
+ if (CONSTANT_ADDRESS_P (base))
+ return avr_asm_len ("sts %m0,%A1" CR_TAB
+ "sts %m0+1,%B1" CR_TAB
+ "sts %m0+2,%C1", op, plen, -6);
+
+ if (reg_base > 0) /* (r) */
+ {
+ if (reg_base == REG_X) /* (R26) */
+ {
+ gcc_assert (!reg_overlap_mentioned_p (base, src));
+
+ avr_asm_len ("st %0+,%A1" CR_TAB
+ "st %0+,%B1" CR_TAB
+ "st %0,%C1", op, plen, -3);
+
+ if (!reg_unused_after (insn, base))
+ avr_asm_len ("sbiw r26,2", op, plen, 1);
+
+ return "";
+ }
+ else
+ return avr_asm_len ("st %0,%A1" CR_TAB
+ "std %0+1,%B1" CR_TAB
+ "std %0+2,%C1", op, plen, -3);
+ }
+ else if (GET_CODE (base) == PLUS) /* (R + i) */
+ {
+ int disp = INTVAL (XEXP (base, 1));
+ reg_base = REGNO (XEXP (base, 0));
+
+ if (disp > MAX_LD_OFFSET (GET_MODE (dest)))
+ {
+ if (reg_base != REG_Y)
+ fatal_insn ("incorrect insn:",insn);
+
+ if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)))
+ return avr_asm_len ("adiw r28,%o0-61" CR_TAB
+ "std Y+61,%A1" CR_TAB
+ "std Y+62,%B1" CR_TAB
+ "std Y+63,%C1" CR_TAB
+ "sbiw r28,%o0-60", op, plen, -5);
+
+ return avr_asm_len ("subi r28,lo8(-%o0)" CR_TAB
+ "sbci r29,hi8(-%o0)" CR_TAB
+ "st Y,%A1" CR_TAB
+ "std Y+1,%B1" CR_TAB
+ "std Y+2,%C1" CR_TAB
+ "subi r28,lo8(%o0)" CR_TAB
+ "sbci r29,hi8(%o0)", op, plen, -7);
+ }
+ if (reg_base == REG_X)
+ {
+ /* (X + d) = R */
+ gcc_assert (!reg_overlap_mentioned_p (XEXP (base, 0), src));
+
+ avr_asm_len ("adiw r26,%o0" CR_TAB
+ "st X+,%A1" CR_TAB
+ "st X+,%B1" CR_TAB
+ "st X,%C1", op, plen, -4);
+
+ if (!reg_unused_after (insn, XEXP (base, 0)))
+ avr_asm_len ("sbiw r26,%o0+2", op, plen, 1);
+
+ return "";
+ }
+
+ return avr_asm_len ("std %A0,%A1" CR_TAB
+ "std %B0,%B1" CR_TAB
+ "std %C0,%C1", op, plen, -3);
+ }
+ else if (GET_CODE (base) == PRE_DEC) /* (--R) */
+ return avr_asm_len ("st %0,%C1" CR_TAB
+ "st %0,%B1" CR_TAB
+ "st %0,%A1", op, plen, -3);
+ else if (GET_CODE (base) == POST_INC) /* (R++) */
+ return avr_asm_len ("st %0,%A1" CR_TAB
+ "st %0,%B1" CR_TAB
+ "st %0,%C1", op, plen, -3);
+
+ fatal_insn ("unknown move insn:",insn);
+ return "";
+}
+
+
+/* Move around 24-bit stuff. */
+
+const char *
+avr_out_movpsi (rtx insn, rtx *op, int *plen)
+{
+ rtx dest = op[0];
+ rtx src = op[1];
+
+ if (register_operand (dest, VOIDmode))
+ {
+ if (register_operand (src, VOIDmode)) /* mov r,r */
+ {
+ if (true_regnum (dest) > true_regnum (src))
+ {
+ avr_asm_len ("mov %C0,%C1", op, plen, -1);
+
+ if (AVR_HAVE_MOVW)
+ return avr_asm_len ("movw %A0,%A1", op, plen, 1);
+ else
+ return avr_asm_len ("mov %B0,%B1" CR_TAB
+ "mov %A0,%A1", op, plen, 2);
+ }
+ else
+ {
+ if (AVR_HAVE_MOVW)
+ avr_asm_len ("movw %A0,%A1", op, plen, -1);
+ else
+ avr_asm_len ("mov %A0,%A1" CR_TAB
+ "mov %B0,%B1", op, plen, -2);
+
+ return avr_asm_len ("mov %C0,%C1", op, plen, 1);
+ }
+ }
+ else if (CONST_INT_P (src))
+ {
+ return avr_out_reload_inpsi (op, NULL_RTX, plen);
+ }
+ else if (CONSTANT_P (src))
+ {
+ if (test_hard_reg_class (LD_REGS, dest)) /* ldi d,i */
+ {
+ return avr_asm_len ("ldi %A0,lo8(%1)" CR_TAB
+ "ldi %B0,hi8(%1)" CR_TAB
+ "ldi %C0,hh8(%1)", op, plen, -3);
+ }
+
+ /* Last resort, better than loading from memory. */
+ return avr_asm_len ("mov __tmp_reg__,r31" CR_TAB
+ "ldi r31,lo8(%1)" CR_TAB
+ "mov %A0,r31" CR_TAB
+ "ldi r31,hi8(%1)" CR_TAB
+ "mov %B0,r31" CR_TAB
+ "ldi r31,hh8(%1)" CR_TAB
+ "mov %C0,r31" CR_TAB
+ "mov r31,__tmp_reg__", op, plen, -8);
+ }
+ else if (MEM_P (src))
+ return avr_out_load_psi (insn, op, plen); /* mov r,m */
+ }
+ else if (MEM_P (dest))
+ {
+ if (src == CONST0_RTX (GET_MODE (dest)))
+ op[1] = zero_reg_rtx;
+
+ avr_out_store_psi (insn, op, plen);
+
+ op[1] = src;
+ return "";
+ }
+
+ fatal_insn ("invalid insn:", insn);
+ return "";
+}
+
+
const char *
out_movqi_mr_r (rtx insn, rtx op[], int *l)
{
@@ -3280,22 +3558,24 @@ avr_out_compare (rtx insn, rtx *xop, int *plen)
avr_asm_len ("dec %A0" CR_TAB
"or %A0,%B0", xop, plen, 2);
- if (n_bytes == 4)
- avr_asm_len ("or %A0,%C0" CR_TAB
- "or %A0,%D0", xop, plen, 2);
+ if (n_bytes >= 3)
+ avr_asm_len ("or %A0,%C0", xop, plen, 1);
+
+ if (n_bytes >= 4)
+ avr_asm_len ("or %A0,%D0", xop, plen, 1);
return "";
}
else if (xval == constm1_rtx)
{
- if (n_bytes == 4)
- avr_asm_len ("and %A0,%D0" CR_TAB
- "and %A0,%C0", xop, plen, 2);
+ if (n_bytes >= 4)
+ avr_asm_len ("and %A0,%D0", xop, plen, 1);
- avr_asm_len ("and %A0,%B0" CR_TAB
- "com %A0", xop, plen, 2);
+ if (n_bytes >= 3)
+ avr_asm_len ("and %A0,%C0", xop, plen, 1);
- return "";
+ return avr_asm_len ("and %A0,%B0" CR_TAB
+ "com %A0", xop, plen, 2);
}
}
@@ -3335,8 +3615,7 @@ avr_out_compare (rtx insn, rtx *xop, int *plen)
&& compare_eq_p (insn)
&& reg_unused_after (insn, xreg))
{
- avr_asm_len ("adiw %0,%n1", xop, plen, 1);
- break;
+ return avr_asm_len ("adiw %0,%n1", xop, plen, 1);
}
}
@@ -3410,6 +3689,31 @@ avr_out_tsthi (rtx insn, rtx *op, int *plen)
}
+/* Output test instruction for PSImode. */
+
+const char*
+avr_out_tstpsi (rtx insn, rtx *op, int *plen)
+{
+ if (compare_sign_p (insn))
+ {
+ avr_asm_len ("tst %C0", op, plen, -1);
+ }
+ else if (reg_unused_after (insn, op[0])
+ && compare_eq_p (insn))
+ {
+ /* Faster than sbiw if we can clobber the operand. */
+ avr_asm_len ("or %A0,%B0" CR_TAB
+ "or %A0,%C0", op, plen, -2);
+ }
+ else
+ {
+ avr_out_compare (insn, op, plen);
+ }
+
+ return "";
+}
+
+
/* Output test instruction for SImode. */
const char*
@@ -3938,6 +4242,69 @@ ashlhi3_out (rtx insn, rtx operands[], int *len)
}
+/* 24-bit shift left */
+
+const char*
+avr_out_ashlpsi3 (rtx insn, rtx *op, int *plen)
+{
+ if (plen)
+ *plen = 0;
+
+ if (CONST_INT_P (op[2]))
+ {
+ switch (INTVAL (op[2]))
+ {
+ default:
+ if (INTVAL (op[2]) < 24)
+ break;
+
+ return avr_asm_len ("clr %A0" CR_TAB
+ "clr %B0" CR_TAB
+ "clr %C0", op, plen, 3);
+
+ case 8:
+ {
+ int reg0 = REGNO (op[0]);
+ int reg1 = REGNO (op[1]);
+
+ if (reg0 >= reg1)
+ return avr_asm_len ("mov %C0,%B1" CR_TAB
+ "mov %B0,%A1" CR_TAB
+ "clr %A0", op, plen, 3);
+ else
+ return avr_asm_len ("clr %A0" CR_TAB
+ "mov %B0,%A1" CR_TAB
+ "mov %C0,%B1", op, plen, 3);
+ }
+
+ case 16:
+ {
+ int reg0 = REGNO (op[0]);
+ int reg1 = REGNO (op[1]);
+
+ if (reg0 + 2 != reg1)
+ avr_asm_len ("mov %C0,%A0", op, plen, 1);
+
+ return avr_asm_len ("clr %B0" CR_TAB
+ "clr %A0", op, plen, 2);
+ }
+
+ case 23:
+ return avr_asm_len ("clr %C0" CR_TAB
+ "lsr %A0" CR_TAB
+ "ror %C0" CR_TAB
+ "clr %B0" CR_TAB
+ "clr %A0", op, plen, 5);
+ }
+ }
+
+ out_shift_with_cnt ("lsl %A0" CR_TAB
+ "rol %B0" CR_TAB
+ "rol %C0", insn, op, plen, 3);
+ return "";
+}
+
+
/* 32bit shift left ((long)x << i) */
const char *
@@ -4264,6 +4631,65 @@ ashrhi3_out (rtx insn, rtx operands[], int *len)
}
+/* 24-bit arithmetic shift right */
+
+const char*
+avr_out_ashrpsi3 (rtx insn, rtx *op, int *plen)
+{
+ int dest = REGNO (op[0]);
+ int src = REGNO (op[1]);
+
+ if (CONST_INT_P (op[2]))
+ {
+ if (plen)
+ *plen = 0;
+
+ switch (INTVAL (op[2]))
+ {
+ case 8:
+ if (dest <= src)
+ return avr_asm_len ("mov %A0,%B1" CR_TAB
+ "mov %B0,%C1" CR_TAB
+ "clr %C0" CR_TAB
+ "sbrc %B0,7" CR_TAB
+ "dec %C0", op, plen, 5);
+ else
+ return avr_asm_len ("clr %C0" CR_TAB
+ "sbrc %C1,7" CR_TAB
+ "dec %C0" CR_TAB
+ "mov %B0,%C1" CR_TAB
+ "mov %A0,%B1", op, plen, 5);
+
+ case 16:
+ if (dest != src + 2)
+ avr_asm_len ("mov %A0,%C1", op, plen, 1);
+
+ return avr_asm_len ("clr %B0" CR_TAB
+ "sbrc %A0,7" CR_TAB
+ "com %B0" CR_TAB
+ "mov %C0,%B0", op, plen, 4);
+
+ default:
+ if (INTVAL (op[2]) < 24)
+ break;
+
+ /* fall through */
+
+ case 31:
+ return avr_asm_len ("lsl %C0" CR_TAB
+ "sbc %A0,%A0" CR_TAB
+ "mov %B0,%A0" CR_TAB
+ "mov %C0,%A0", op, plen, 4);
+ } /* switch */
+ }
+
+ out_shift_with_cnt ("asr %C0" CR_TAB
+ "ror %B0" CR_TAB
+ "ror %A0", insn, op, plen, 3);
+ return "";
+}
+
+
/* 32bit arithmetic shift right ((signed long)x >> i) */
const char *
@@ -4714,6 +5140,61 @@ lshrhi3_out (rtx insn, rtx operands[], int *len)
return "";
}
+
+/* 24-bit logic shift right */
+
+const char*
+avr_out_lshrpsi3 (rtx insn, rtx *op, int *plen)
+{
+ int dest = REGNO (op[0]);
+ int src = REGNO (op[1]);
+
+ if (CONST_INT_P (op[2]))
+ {
+ if (plen)
+ *plen = 0;
+
+ switch (INTVAL (op[2]))
+ {
+ case 8:
+ if (dest <= src)
+ return avr_asm_len ("mov %A0,%B1" CR_TAB
+ "mov %B0,%C1" CR_TAB
+ "clr %C0", op, plen, 3);
+ else
+ return avr_asm_len ("clr %C0" CR_TAB
+ "mov %B0,%C1" CR_TAB
+ "mov %A0,%B1", op, plen, 3);
+
+ case 16:
+ if (dest != src + 2)
+ avr_asm_len ("mov %A0,%C1", op, plen, 1);
+
+ return avr_asm_len ("clr %B0" CR_TAB
+ "clr %C0", op, plen, 2);
+
+ default:
+ if (INTVAL (op[2]) < 24)
+ break;
+
+ /* fall through */
+
+ case 23:
+ return avr_asm_len ("clr %A0" CR_TAB
+ "sbrc %C0,7" CR_TAB
+ "inc %A0" CR_TAB
+ "clr %B0" CR_TAB
+ "clr %C0", op, plen, 5);
+ } /* switch */
+ }
+
+ out_shift_with_cnt ("lsr %C0" CR_TAB
+ "ror %B0" CR_TAB
+ "ror %A0", insn, op, plen, 3);
+ return "";
+}
+
+
/* 32bit logic shift right ((unsigned int)x >> i) */
const char *
@@ -4874,7 +5355,9 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc)
if (i && !started)
*pcc = CC_CLOBBER;
- if (!started && i % 2 == 0
+ if (!started
+ && i % 2 == 0
+ && i + 2 <= n_bytes
&& test_hard_reg_class (ADDW_REGS, reg8))
{
rtx xval16 = simplify_gen_subreg (HImode, xval, mode, i);
@@ -4911,11 +5394,11 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc)
else if ((val8 == 1 || val8 == 0xff)
&& !started
&& i == n_bytes - 1)
- {
+ {
avr_asm_len ((code == PLUS) ^ (val8 == 1) ? "dec %0" : "inc %0",
op, plen, 1);
break;
- }
+ }
switch (code)
{
@@ -5399,6 +5882,7 @@ adjust_insn_length (rtx insn, int len)
switch (adjust_len)
{
case ADJUST_LEN_RELOAD_IN16: output_reload_inhi (op, op[2], &len); break;
+ case ADJUST_LEN_RELOAD_IN24: avr_out_reload_inpsi (op, op[2], &len); break;
case ADJUST_LEN_RELOAD_IN32: output_reload_insisf (op, op[2], &len); break;
case ADJUST_LEN_OUT_BITOP: avr_out_bitop (insn, op, &len); break;
@@ -5411,9 +5895,11 @@ adjust_insn_length (rtx insn, int len)
case ADJUST_LEN_MOV8: output_movqi (insn, op, &len); break;
case ADJUST_LEN_MOV16: output_movhi (insn, op, &len); break;
+ case ADJUST_LEN_MOV24: avr_out_movpsi (insn, op, &len); break;
case ADJUST_LEN_MOV32: output_movsisf (insn, op, &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;
case ADJUST_LEN_COMPARE: avr_out_compare (insn, op, &len); break;
@@ -5429,6 +5915,10 @@ adjust_insn_length (rtx insn, int len)
case ADJUST_LEN_ASHLHI: ashlhi3_out (insn, op, &len); break;
case ADJUST_LEN_ASHLSI: ashlsi3_out (insn, op, &len); break;
+ case ADJUST_LEN_ASHLPSI: avr_out_ashlpsi3 (insn, op, &len); break;
+ case ADJUST_LEN_ASHRPSI: avr_out_ashrpsi3 (insn, op, &len); break;
+ case ADJUST_LEN_LSHRPSI: avr_out_lshrpsi3 (insn, op, &len); break;
+
case ADJUST_LEN_CALL: len = AVR_HAVE_JMP_CALL ? 2 : 1; break;
default:
@@ -6228,13 +6718,11 @@ avr_rtx_costs_1 (rtx x, int codearg, int outer_code ATTRIBUTE_UNUSED,
*total = COSTS_N_INSNS (1);
break;
- case HImode:
- *total = COSTS_N_INSNS (3);
- break;
-
- case SImode:
- *total = COSTS_N_INSNS (7);
- break;
+ case HImode:
+ case PSImode:
+ case SImode:
+ *total = COSTS_N_INSNS (2 * GET_MODE_SIZE (mode) - 1);
+ break;
default:
return false;
@@ -6320,6 +6808,19 @@ avr_rtx_costs_1 (rtx x, int codearg, int outer_code ATTRIBUTE_UNUSED,
*total = COSTS_N_INSNS (2);
break;
+ case PSImode:
+ if (!CONST_INT_P (XEXP (x, 1)))
+ {
+ *total = COSTS_N_INSNS (3);
+ *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, 1,
+ speed);
+ }
+ else if (INTVAL (XEXP (x, 1)) >= -63 && INTVAL (XEXP (x, 1)) <= 63)
+ *total = COSTS_N_INSNS (2);
+ else
+ *total = COSTS_N_INSNS (3);
+ break;
+
case SImode:
if (GET_CODE (XEXP (x, 1)) != CONST_INT)
{
@@ -6367,6 +6868,7 @@ avr_rtx_costs_1 (rtx x, int codearg, int outer_code ATTRIBUTE_UNUSED,
*total = COSTS_N_INSNS (1) + *total;
return true;
}
+ /* FALLTHRU */
case AND:
case IOR:
*total = COSTS_N_INSNS (GET_MODE_SIZE (mode));
@@ -6437,6 +6939,13 @@ avr_rtx_costs_1 (rtx x, int codearg, int outer_code ATTRIBUTE_UNUSED,
return false;
break;
+ case PSImode:
+ if (!speed)
+ *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 2 : 1);
+ else
+ *total = 10;
+ break;
+
case SImode:
if (AVR_HAVE_MUL)
{
@@ -6611,6 +7120,31 @@ avr_rtx_costs_1 (rtx x, int codearg, int outer_code ATTRIBUTE_UNUSED,
}
break;
+ case PSImode:
+ if (!CONST_INT_P (XEXP (x, 1)))
+ {
+ *total = COSTS_N_INSNS (!speed ? 6 : 73);
+ }
+ else
+ switch (INTVAL (XEXP (x, 1)))
+ {
+ case 0:
+ *total = 0;
+ break;
+ case 1:
+ case 8:
+ case 16:
+ *total = COSTS_N_INSNS (3);
+ break;
+ case 23:
+ *total = COSTS_N_INSNS (5);
+ break;
+ default:
+ *total = COSTS_N_INSNS (!speed ? 5 : 3 * INTVAL (XEXP (x, 1)));
+ break;
+ }
+ break;
+
case SImode:
if (GET_CODE (XEXP (x, 1)) != CONST_INT)
{
@@ -6721,6 +7255,33 @@ avr_rtx_costs_1 (rtx x, int codearg, int outer_code ATTRIBUTE_UNUSED,
}
break;
+ case PSImode:
+ if (!CONST_INT_P (XEXP (x, 1)))
+ {
+ *total = COSTS_N_INSNS (!speed ? 6 : 73);
+ }
+ else
+ switch (INTVAL (XEXP (x, 1)))
+ {
+ case 0:
+ *total = 0;
+ break;
+ case 1:
+ *total = COSTS_N_INSNS (3);
+ break;
+ case 16:
+ case 8:
+ *total = COSTS_N_INSNS (5);
+ break;
+ case 23:
+ *total = COSTS_N_INSNS (4);
+ break;
+ default:
+ *total = COSTS_N_INSNS (!speed ? 5 : 3 * INTVAL (XEXP (x, 1)));
+ break;
+ }
+ break;
+
case SImode:
if (GET_CODE (XEXP (x, 1)) != CONST_INT)
{
@@ -6832,6 +7393,31 @@ avr_rtx_costs_1 (rtx x, int codearg, int outer_code ATTRIBUTE_UNUSED,
}
break;
+ case PSImode:
+ if (!CONST_INT_P (XEXP (x, 1)))
+ {
+ *total = COSTS_N_INSNS (!speed ? 6 : 73);
+ }
+ else
+ switch (INTVAL (XEXP (x, 1)))
+ {
+ case 0:
+ *total = 0;
+ break;
+ case 1:
+ case 8:
+ case 16:
+ *total = COSTS_N_INSNS (3);
+ break;
+ case 23:
+ *total = COSTS_N_INSNS (5);
+ break;
+ default:
+ *total = COSTS_N_INSNS (!speed ? 5 : 3 * INTVAL (XEXP (x, 1)));
+ break;
+ }
+ break;
+
case SImode:
if (GET_CODE (XEXP (x, 1)) != CONST_INT)
{
@@ -6889,6 +7475,12 @@ avr_rtx_costs_1 (rtx x, int codearg, int outer_code ATTRIBUTE_UNUSED,
*total += COSTS_N_INSNS (1);
break;
+ case PSImode:
+ *total = COSTS_N_INSNS (3);
+ if (CONST_INT_P (XEXP (x, 1)) && INTVAL (XEXP (x, 1)) != 0)
+ *total += COSTS_N_INSNS (2);
+ break;
+
case SImode:
*total = COSTS_N_INSNS (4);
if (GET_CODE (XEXP (x, 1)) != CONST_INT)
@@ -7310,8 +7902,10 @@ avr_libcall_value (enum machine_mode mode,
const_rtx func ATTRIBUTE_UNUSED)
{
int offs = GET_MODE_SIZE (mode);
- if (offs < 2)
- offs = 2;
+
+ if (offs <= 4)
+ offs = (offs + 1) & ~1;
+
return gen_rtx_REG (mode, avr_ret_register () + 2 - offs);
}
@@ -7528,8 +8122,10 @@ output_reload_in_const (rtx *op, rtx clobber_reg, int *len, bool clear_p)
bool set_p = false;
unsigned int n;
enum machine_mode mode = GET_MODE (dest);
+ int n_bytes = GET_MODE_SIZE (mode);
- gcc_assert (REG_P (dest));
+ gcc_assert (REG_P (dest)
+ && CONSTANT_P (src));
if (len)
*len = 0;
@@ -7537,20 +8133,21 @@ output_reload_in_const (rtx *op, rtx clobber_reg, int *len, bool clear_p)
/* (REG:SI 14) is special: It's neither in LD_REGS nor in NO_LD_REGS
but has some subregs that are in LD_REGS. Use the MSB (REG:QI 17). */
- if (14 == REGNO (dest)
- && 4 == GET_MODE_SIZE (mode))
+ if (REGNO (dest) < 16
+ && REGNO (dest) + GET_MODE_SIZE (mode) > 16)
{
- clobber_reg = gen_rtx_REG (QImode, 17);
+ clobber_reg = gen_rtx_REG (QImode, REGNO (dest) + n_bytes - 1);
}
- /* We might need a clobber reg but don't have one. Look at the value
- to be loaded more closely. A clobber is only needed if it contains
- a byte that is neither 0, -1 or a power of 2. */
+ /* We might need a clobber reg but don't have one. Look at the value to
+ be loaded more closely. A clobber is only needed if it is a symbol
+ or contains a byte that is neither 0, -1 or a power of 2. */
if (NULL_RTX == clobber_reg
&& !test_hard_reg_class (LD_REGS, dest)
- && !avr_popcount_each_byte (src, GET_MODE_SIZE (mode),
- (1 << 0) | (1 << 1) | (1 << 8)))
+ && (! (CONST_INT_P (src) || CONST_DOUBLE_P (src))
+ || !avr_popcount_each_byte (src, n_bytes,
+ (1 << 0) | (1 << 1) | (1 << 8))))
{
/* We have no clobber register but need one. Cook one up.
That's cheaper than loading from constant pool. */
@@ -7562,21 +8159,49 @@ output_reload_in_const (rtx *op, rtx clobber_reg, int *len, bool clear_p)
/* Now start filling DEST from LSB to MSB. */
- for (n = 0; n < GET_MODE_SIZE (mode); n++)
+ for (n = 0; n < n_bytes; n++)
{
+ int ldreg_p;
bool done_byte = false;
unsigned int j;
rtx xop[3];
- /* Crop the n-th sub-byte. */
-
- xval = simplify_gen_subreg (QImode, src, mode, n);
+ /* Crop the n-th destination byte. */
+
xdest[n] = simplify_gen_subreg (QImode, dest, mode, n);
+ ldreg_p = test_hard_reg_class (LD_REGS, xdest[n]);
+
+ if (!CONST_INT_P (src)
+ && !CONST_DOUBLE_P (src))
+ {
+ static const char* const asm_code[][2] =
+ {
+ { "ldi %2,lo8(%1)" CR_TAB "mov %0,%2", "ldi %0,lo8(%1)" },
+ { "ldi %2,hi8(%1)" CR_TAB "mov %0,%2", "ldi %0,hi8(%1)" },
+ { "ldi %2,hlo8(%1)" CR_TAB "mov %0,%2", "ldi %0,hlo8(%1)" },
+ { "ldi %2,hhi8(%1)" CR_TAB "mov %0,%2", "ldi %0,hhi8(%1)" }
+ };
+
+ xop[0] = xdest[n];
+ xop[1] = src;
+ xop[2] = clobber_reg;
+
+ if (n >= 2)
+ avr_asm_len ("clr %0", xop, len, 1);
+ else
+ avr_asm_len (asm_code[n][ldreg_p], xop, len, ldreg_p ? 1 : 2);
+ continue;
+ }
+
+ /* Crop the n-th source byte. */
+
+ xval = simplify_gen_subreg (QImode, src, mode, n);
ival[n] = INTVAL (xval);
/* Look if we can reuse the low word by means of MOVW. */
if (n == 2
+ && n_bytes >= 4
&& AVR_HAVE_MOVW)
{
rtx lo16 = simplify_gen_subreg (HImode, src, mode, 0);
@@ -7613,7 +8238,7 @@ output_reload_in_const (rtx *op, rtx clobber_reg, int *len, bool clear_p)
/* LD_REGS can use LDI to move a constant value */
- if (test_hard_reg_class (LD_REGS, xdest[n]))
+ if (ldreg_p)
{
xop[0] = xdest[n];
xop[1] = xval;
@@ -7716,45 +8341,7 @@ output_reload_in_const (rtx *op, rtx clobber_reg, int *len, bool clear_p)
const char*
output_reload_inhi (rtx *op, rtx clobber_reg, int *plen)
{
- if (CONST_INT_P (op[1]))
- {
- output_reload_in_const (op, clobber_reg, plen, false);
- }
- else if (test_hard_reg_class (LD_REGS, op[0]))
- {
- avr_asm_len ("ldi %A0,lo8(%1)" CR_TAB
- "ldi %B0,hi8(%1)", op, plen, -2);
- }
- else
- {
- rtx xop[3];
-
- xop[0] = op[0];
- xop[1] = op[1];
- xop[2] = clobber_reg;
-
- if (plen)
- *plen = 0;
-
- if (clobber_reg == NULL_RTX)
- {
- /* No scratch register provided: cook une up. */
-
- xop[2] = gen_rtx_REG (QImode, REG_Z + 1);
- avr_asm_len ("mov __tmp_reg__,%2", xop, plen, 1);
- }
-
- avr_asm_len ("ldi %2,lo8(%1)" CR_TAB
- "mov %A0,%2" CR_TAB
- "ldi %2,hi8(%1)" CR_TAB
- "mov %B0,%2", xop, plen, 4);
-
- if (clobber_reg == NULL_RTX)
- {
- avr_asm_len ("mov %2,__tmp_reg__", xop, plen, 1);
- }
- }
-
+ output_reload_in_const (op, clobber_reg, plen, false);
return "";
}
@@ -7774,9 +8361,6 @@ output_reload_inhi (rtx *op, rtx clobber_reg, int *plen)
const char *
output_reload_insisf (rtx *op, rtx clobber_reg, int *len)
{
- gcc_assert (REG_P (op[0])
- && CONSTANT_P (op[1]));
-
if (AVR_HAVE_MOVW
&& !test_hard_reg_class (LD_REGS, op[0]))
{
@@ -7820,6 +8404,13 @@ output_reload_insisf (rtx *op, rtx clobber_reg, int *len)
return "";
}
+const char *
+avr_out_reload_inpsi (rtx *op, rtx clobber_reg, int *len)
+{
+ output_reload_in_const (op, clobber_reg, len, false);
+ return "";
+}
+
void
avr_output_bld (rtx operands[], int bit_nr)
{
@@ -8078,6 +8669,16 @@ enum avr_builtin_id
AVR_BUILTIN_DELAY_CYCLES
};
+static void
+avr_init_builtin_int24 (void)
+{
+ tree int24_type = make_signed_type (GET_MODE_BITSIZE (PSImode));
+ tree uint24_type = make_unsigned_type (GET_MODE_BITSIZE (PSImode));
+
+ (*lang_hooks.types.register_builtin_type) (int24_type, "__int24");
+ (*lang_hooks.types.register_builtin_type) (uint24_type, "__uint24");
+}
+
#define DEF_BUILTIN(NAME, TYPE, CODE) \
do \
{ \
@@ -8133,6 +8734,8 @@ avr_init_builtins (void)
AVR_BUILTIN_FMULS);
DEF_BUILTIN ("__builtin_avr_fmulsu", int_ftype_char_uchar,
AVR_BUILTIN_FMULSU);
+
+ avr_init_builtin_int24 ();
}
#undef DEF_BUILTIN