/* Subroutines for insn-output.c for ATMEL AVR micro controllers
- Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004
+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007
Free Software Foundation, Inc.
Contributed by Denis Chertykov (denisc@overta.ru)
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to
- the Free Software Foundation, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
#include "config.h"
#include "system.h"
static void avr_file_end (void);
static void avr_output_function_prologue (FILE *, HOST_WIDE_INT);
static void avr_output_function_epilogue (FILE *, HOST_WIDE_INT);
-static void avr_unique_section (tree, int);
static void avr_insert_attributes (tree, tree *);
+static void avr_asm_init_sections (void);
static unsigned int avr_section_type_flags (tree, const char *, int);
static void avr_reorg (void);
static void avr_asm_out_ctor (rtx, int);
static void avr_asm_out_dtor (rtx, int);
-static int default_rtx_costs (rtx, enum rtx_code, enum rtx_code);
+static int avr_operand_rtx_cost (rtx, enum machine_mode, enum rtx_code);
static bool avr_rtx_costs (rtx, int, int, int *);
static int avr_address_cost (rtx);
static bool avr_return_in_memory (tree, tree);
/* Size of all jump tables in the current function, in words. */
static int jump_tables_size;
-/* Initial stack value specified by the `-minit-stack=' option */
-const char *avr_init_stack = "__stack";
-
-/* Default MCU name */
-const char *avr_mcu_name = "avr2";
-
/* Preprocessor macros to define depending on MCU type. */
const char *avr_base_arch_macro;
const char *avr_extra_arch_macro;
+section *progmem_section;
+
/* More than 8K of program memory: use "call" and "jmp". */
int avr_mega_p = 0;
-/* Enhanced core: use "movw", "mul", ... */
-int avr_enhanced_p = 0;
+/* Core have 'MUL*' instructions. */
+int avr_have_mul_p = 0;
/* Assembler only. */
int avr_asm_only_p = 0;
+/* Core have 'MOVW' and 'LPM Rx,Z' instructions. */
+int avr_have_movw_lpmx_p = 0;
+
struct base_arch_s {
int asm_only;
- int enhanced;
+ int have_mul;
int mega;
+ int have_movw_lpmx;
const char *const macro;
};
static const struct base_arch_s avr_arch_types[] = {
- { 1, 0, 0, NULL }, /* unknown device specified */
- { 1, 0, 0, "__AVR_ARCH__=1" },
- { 0, 0, 0, "__AVR_ARCH__=2" },
- { 0, 0, 1, "__AVR_ARCH__=3" },
- { 0, 1, 0, "__AVR_ARCH__=4" },
- { 0, 1, 1, "__AVR_ARCH__=5" }
+ { 1, 0, 0, 0, NULL }, /* unknown device specified */
+ { 1, 0, 0, 0, "__AVR_ARCH__=1" },
+ { 0, 0, 0, 0, "__AVR_ARCH__=2" },
+ { 0, 0, 1, 0, "__AVR_ARCH__=3" },
+ { 0, 1, 0, 1, "__AVR_ARCH__=4" },
+ { 0, 1, 1, 1, "__AVR_ARCH__=5" },
+ { 0, 0, 0, 1, "__AVR_ARCH__=25"}
};
struct mcu_type_s {
{ "at90s8515", 2, "__AVR_AT90S8515__" },
{ "at90c8534", 2, "__AVR_AT90C8534__" },
{ "at90s8535", 2, "__AVR_AT90S8535__" },
- { "at86rf401", 2, "__AVR_AT86RF401__" },
+ /* Classic + MOVW, <= 8K. */
+ { "avr25", 6, NULL },
+ { "attiny13", 6, "__AVR_ATtiny13__" },
+ { "attiny2313", 6, "__AVR_ATtiny2313__" },
+ { "attiny24", 6, "__AVR_ATtiny24__" },
+ { "attiny44", 6, "__AVR_ATtiny44__" },
+ { "attiny84", 6, "__AVR_ATtiny84__" },
+ { "attiny25", 6, "__AVR_ATtiny25__" },
+ { "attiny45", 6, "__AVR_ATtiny45__" },
+ { "attiny85", 6, "__AVR_ATtiny85__" },
+ { "attiny261", 6, "__AVR_ATtiny261__" },
+ { "attiny461", 6, "__AVR_ATtiny461__" },
+ { "attiny861", 6, "__AVR_ATtiny861__" },
+ { "at86rf401", 6, "__AVR_AT86RF401__" },
/* Classic, > 8K. */
{ "avr3", 3, NULL },
{ "atmega103", 3, "__AVR_ATmega103__" },
/* Enhanced, <= 8K. */
{ "avr4", 4, NULL },
{ "atmega8", 4, "__AVR_ATmega8__" },
+ { "atmega48", 4, "__AVR_ATmega48__" },
+ { "atmega88", 4, "__AVR_ATmega88__" },
{ "atmega8515", 4, "__AVR_ATmega8515__" },
{ "atmega8535", 4, "__AVR_ATmega8535__" },
+ { "at90pwm1", 4, "__AVR_AT90PWM1__" },
+ { "at90pwm2", 4, "__AVR_AT90PWM2__" },
+ { "at90pwm3", 4, "__AVR_AT90PWM3__" },
+ { "at90usb82", 5, "__AVR_AT90USB82__" },
/* Enhanced, > 8K. */
{ "avr5", 5, NULL },
{ "atmega16", 5, "__AVR_ATmega16__" },
{ "atmega161", 5, "__AVR_ATmega161__" },
{ "atmega162", 5, "__AVR_ATmega162__" },
{ "atmega163", 5, "__AVR_ATmega163__" },
+ { "atmega164p",5, "__AVR_ATmega164P__" },
+ { "atmega165", 5, "__AVR_ATmega165__" },
+ { "atmega165p",5, "__AVR_ATmega165P__" },
+ { "atmega168", 5, "__AVR_ATmega168__" },
{ "atmega169", 5, "__AVR_ATmega169__" },
+ { "atmega169p",5, "__AVR_ATmega169P__" },
{ "atmega32", 5, "__AVR_ATmega32__" },
{ "atmega323", 5, "__AVR_ATmega323__" },
+ { "atmega324p",5, "__AVR_ATmega324P__" },
+ { "atmega325", 5, "__AVR_ATmega325__" },
+ { "atmega325p", 5, "__AVR_ATmega325P__" },
+ { "atmega3250", 5, "__AVR_ATmega3250__" },
+ { "atmega3250p", 5, "__AVR_ATmega3250P__" },
+ { "atmega329", 5, "__AVR_ATmega329__" },
+ { "atmega329p", 5, "__AVR_ATmega329P__" },
+ { "atmega3290", 5, "__AVR_ATmega3290__" },
+ { "atmega3290p", 5, "__AVR_ATmega3290P__" },
+ { "atmega406", 5, "__AVR_ATmega406__" },
{ "atmega64", 5, "__AVR_ATmega64__" },
+ { "atmega640", 5, "__AVR_ATmega640__" },
+ { "atmega644", 5, "__AVR_ATmega644__" },
+ { "atmega644p",5, "__AVR_ATmega644P__" },
+ { "atmega645", 5, "__AVR_ATmega645__" },
+ { "atmega6450", 5, "__AVR_ATmega6450__" },
+ { "atmega649", 5, "__AVR_ATmega649__" },
+ { "atmega6490", 5, "__AVR_ATmega6490__" },
{ "atmega128", 5, "__AVR_ATmega128__" },
+ { "atmega1280",5, "__AVR_ATmega1280__" },
+ { "atmega1281",5, "__AVR_ATmega1281__" },
+ { "at90can32", 5, "__AVR_AT90CAN32__" },
+ { "at90can64", 5, "__AVR_AT90CAN64__" },
+ { "at90can128", 5, "__AVR_AT90CAN128__" },
+ { "at90usb162", 5, "__AVR_AT90USB162__" },
+ { "at90usb646", 5, "__AVR_AT90USB646__" },
+ { "at90usb647", 5, "__AVR_AT90USB647__" },
+ { "at90usb1286", 5, "__AVR_AT90USB1286__" },
+ { "at90usb1287", 5, "__AVR_AT90USB1287__" },
{ "at94k", 5, "__AVR_AT94K__" },
/* Assembler only. */
{ "avr1", 1, NULL },
/* Initialize the GCC target structure. */
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
+#undef TARGET_ASM_ALIGNED_SI_OP
+#define TARGET_ASM_ALIGNED_SI_OP "\t.long\t"
+#undef TARGET_ASM_UNALIGNED_HI_OP
+#define TARGET_ASM_UNALIGNED_HI_OP "\t.word\t"
+#undef TARGET_ASM_UNALIGNED_SI_OP
+#define TARGET_ASM_UNALIGNED_SI_OP "\t.long\t"
#undef TARGET_ASM_INTEGER
#define TARGET_ASM_INTEGER avr_assemble_integer
#undef TARGET_ASM_FILE_START
#define TARGET_ASM_FUNCTION_EPILOGUE avr_output_function_epilogue
#undef TARGET_ATTRIBUTE_TABLE
#define TARGET_ATTRIBUTE_TABLE avr_attribute_table
-#undef TARGET_ASM_UNIQUE_SECTION
-#define TARGET_ASM_UNIQUE_SECTION avr_unique_section
+#undef TARGET_ASM_FUNCTION_RODATA_SECTION
+#define TARGET_ASM_FUNCTION_RODATA_SECTION default_no_function_rodata_section
#undef TARGET_INSERT_ATTRIBUTES
#define TARGET_INSERT_ATTRIBUTES avr_insert_attributes
#undef TARGET_SECTION_TYPE_FLAGS
#undef TARGET_MACHINE_DEPENDENT_REORG
#define TARGET_MACHINE_DEPENDENT_REORG avr_reorg
-#undef TARGET_STRUCT_VALUE_RTX
-#define TARGET_STRUCT_VALUE_RTX hook_rtx_tree_int_null
#undef TARGET_RETURN_IN_MEMORY
#define TARGET_RETURN_IN_MEMORY avr_return_in_memory
if (!t->name)
{
- fprintf (stderr, "unknown MCU `%s' specified\nKnown MCU names:\n",
+ fprintf (stderr, "unknown MCU '%s' specified\nKnown MCU names:\n",
avr_mcu_name);
for (t = avr_mcu_types; t->name; t++)
fprintf (stderr," %s\n", t->name);
base = &avr_arch_types[t->arch];
avr_asm_only_p = base->asm_only;
- avr_enhanced_p = base->enhanced;
+ avr_have_mul_p = base->have_mul;
avr_mega_p = base->mega;
+ avr_have_movw_lpmx_p = base->have_movw_lpmx;
avr_base_arch_macro = base->macro;
avr_extra_arch_macro = t->macro;
return ALL_REGS;
}
-
-/* A C expression which defines the machine-dependent operand
- constraint letters for register classes. If C is such a
- letter, the value should be the register class corresponding to
- it. Otherwise, the value should be `NO_REGS'. The register
- letter `r', corresponding to class `GENERAL_REGS', will not be
- passed to this macro; you do not need to handle it. */
-
-enum reg_class
-avr_reg_class_from_letter (int c)
-{
- switch (c)
- {
- case 't' : return R0_REG;
- case 'b' : return BASE_POINTER_REGS;
- case 'e' : return POINTER_REGS;
- case 'w' : return ADDW_REGS;
- case 'd' : return LD_REGS;
- case 'l' : return NO_LD_REGS;
- case 'a' : return SIMPLE_LD_REGS;
- case 'x' : return POINTER_X_REGS;
- case 'y' : return POINTER_Y_REGS;
- case 'z' : return POINTER_Z_REGS;
- case 'q' : return STACK_REG;
- default: break;
- }
- return NO_REGS;
-}
-
/* Return nonzero if FUNC is a naked function. */
static int
{
tree a;
- if (TREE_CODE (func) != FUNCTION_DECL)
- abort ();
+ gcc_assert (TREE_CODE (func) == FUNCTION_DECL);
a = lookup_attribute ("naked", DECL_ATTRIBUTES (func));
return a != NULL_TREE;
if (TARGET_TINY_STACK)
{
if (adj < -63 || adj > 63)
- warning ("large frame pointer change (%d) with -mtiny-stack", adj);
+ warning (0, "large frame pointer change (%d) with -mtiny-stack", adj);
/* The high byte (r29) doesn't change - prefer "subi" (1 cycle)
over "sbiw" (2 cycles, same size). */
}
else if (minimize && (frame_pointer_needed || live_seq > 6))
{
- const char *cfun_name = current_function_name ();
fprintf (file, ("\t"
AS1 (ldi, r26) ",lo8(" HOST_WIDE_INT_PRINT_DEC ")" CR_TAB
AS1 (ldi, r27) ",hi8(" HOST_WIDE_INT_PRINT_DEC ")" CR_TAB), size, size);
- fprintf (file, (AS2 (ldi, r30, pm_lo8(.L_%s_body)) CR_TAB
- AS2 (ldi, r31, pm_hi8(.L_%s_body)) CR_TAB),
- cfun_name, cfun_name);
+ fputs ((AS2 (ldi,r30,pm_lo8(1f)) CR_TAB
+ AS2 (ldi,r31,pm_hi8(1f)) CR_TAB), file);
prologue_size += 4;
(18 - live_seq) * 2);
++prologue_size;
}
- fprintf (file, ".L_%s_body:\n", cfun_name);
+ fputs ("1:\n", file);
}
else
{
}
if (TARGET_ALL_DEBUG)
{
- fprintf (stderr, " ret = %c\n", r);
+ fprintf (stderr, " ret = %c\n", r + '0');
}
return r == NO_REGS ? 0 : (int)r;
}
case REG_Y: return "Y";
case REG_Z: return "Z";
default:
- abort ();
+ gcc_unreachable ();
}
return NULL;
}
case LTU:
return "lo";
default:
- abort ();
+ gcc_unreachable ();
}
}
print_operand (file, XEXP (addr, 1), 0);
}
+ else if (code == 'p' || code == 'r')
+ {
+ if (GET_CODE (addr) != POST_INC && GET_CODE (addr) != PRE_DEC)
+ fatal_insn ("bad address, not post_inc or pre_dec:", addr);
+
+ if (code == 'p')
+ print_operand_address (file, XEXP (addr, 0)); /* X, Y, Z */
+ else
+ print_operand (file, XEXP (addr, 0), 0); /* r26, r28, r30 */
+ }
else if (GET_CODE (addr) == PLUS)
{
print_operand_address (file, XEXP (addr,0));
print_operand_address (file, x);
}
-/* Recognize operand OP of mode MODE used in call instructions. */
-
-int
-call_insn_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- if (GET_CODE (op) == MEM)
- {
- rtx inside = XEXP (op, 0);
- if (register_operand (inside, Pmode))
- return 1;
- if (CONSTANT_ADDRESS_P (inside))
- return 1;
- }
- return 0;
-}
-
/* Update the condition code in the INSN. */
void
rtx x = XEXP (src, 1);
if (GET_CODE (x) == CONST_INT
+ && INTVAL (x) > 0
&& INTVAL (x) != 6)
{
cc_status.value1 = SET_DEST (set);
AS2 (in,%B0,__SP_H__));
}
- if (AVR_ENHANCED)
+ if (AVR_HAVE_MOVW)
{
*l = 1;
return (AS2 (movw,%0,%1));
}
-
- if (true_regnum (dest) > true_regnum (src))
- {
- *l = 2;
- return (AS2 (mov,%B0,%B1) CR_TAB
- AS2 (mov,%A0,%A1));
- }
else
{
*l = 2;
rtx base = XEXP (src, 0);
int reg_dest = true_regnum (dest);
int reg_base = true_regnum (base);
+ /* "volatile" forces reading low byte first, even if less efficient,
+ for correct operation with 16-bit I/O registers. */
+ int mem_volatile_p = MEM_VOLATILE_P (src);
int tmp;
if (!l)
if (reg_overlap_mentioned_p (dest, XEXP (base, 0)))
fatal_insn ("incorrect insn:", insn);
+ if (mem_volatile_p)
+ {
+ if (REGNO (XEXP (base, 0)) == REG_X)
+ {
+ *l = 4;
+ return (AS2 (sbiw,r26,2) CR_TAB
+ AS2 (ld,%A0,X+) CR_TAB
+ AS2 (ld,%B0,X) CR_TAB
+ AS2 (sbiw,r26,1));
+ }
+ else
+ {
+ *l = 3;
+ return (AS2 (sbiw,%r1,2) CR_TAB
+ AS2 (ld,%A0,%p1) CR_TAB
+ AS2 (ldd,%B0,%p1+1));
+ }
+ }
+
*l = 2;
return (AS2 (ld,%B0,%1) CR_TAB
AS2 (ld,%A0,%1));
{
if (true_regnum (dest) > true_regnum (src))
{
- if (AVR_ENHANCED)
+ if (AVR_HAVE_MOVW)
{
*l = 2;
return (AS2 (movw,%C0,%C1) CR_TAB
}
else
{
- if (AVR_ENHANCED)
+ if (AVR_HAVE_MOVW)
{
*l = 2;
return (AS2 (movw,%A0,%A1) CR_TAB
if (GET_CODE (src) == CONST_INT)
{
const char *const clr_op0 =
- AVR_ENHANCED ? (AS1 (clr,%A0) CR_TAB
+ AVR_HAVE_MOVW ? (AS1 (clr,%A0) CR_TAB
AS1 (clr,%B0) CR_TAB
AS2 (movw,%C0,%A0))
: (AS1 (clr,%A0) CR_TAB
if (src == const0_rtx) /* mov r,L */
{
- *l = AVR_ENHANCED ? 3 : 4;
+ *l = AVR_HAVE_MOVW ? 3 : 4;
return clr_op0;
}
else if (src == const1_rtx)
{
if (!real_l)
output_asm_insn (clr_op0, operands);
- *l = AVR_ENHANCED ? 4 : 5;
+ *l = AVR_HAVE_MOVW ? 4 : 5;
return AS1 (inc,%A0);
}
else if (src == constm1_rtx)
{
/* Immediate constants -1 to any register */
- if (AVR_ENHANCED)
+ if (AVR_HAVE_MOVW)
{
*l = 4;
return (AS1 (clr,%A0) CR_TAB
if (bit_nr >= 0)
{
- *l = AVR_ENHANCED ? 5 : 6;
+ *l = AVR_HAVE_MOVW ? 5 : 6;
if (!real_l)
{
output_asm_insn (clr_op0, operands);
rtx base = XEXP (dest, 0);
int reg_base = true_regnum (base);
int reg_src = true_regnum (src);
+ /* "volatile" forces writing high byte first, even if less efficient,
+ for correct operation with 16-bit I/O registers. */
+ int mem_volatile_p = MEM_VOLATILE_P (dest);
int tmp;
+
if (!l)
l = &tmp;
if (CONSTANT_ADDRESS_P (base))
{
if (reg_src == REG_X)
{
- /* "st X+,r26" is undefined */
- if (reg_unused_after (insn, src))
+ /* "st X+,r26" and "st -X,r26" are undefined. */
+ if (!mem_volatile_p && reg_unused_after (insn, src))
return *l=4, (AS2 (mov,__tmp_reg__,r27) CR_TAB
AS2 (st,X,r26) CR_TAB
AS2 (adiw,r26,1) CR_TAB
AS2 (st,X,__tmp_reg__));
else
return *l=5, (AS2 (mov,__tmp_reg__,r27) CR_TAB
- AS2 (st,X,r26) CR_TAB
AS2 (adiw,r26,1) CR_TAB
AS2 (st,X,__tmp_reg__) CR_TAB
- AS2 (sbiw,r26,1));
+ AS2 (sbiw,r26,1) CR_TAB
+ AS2 (st,X,r26));
}
else
{
- if (reg_unused_after (insn, base))
+ if (!mem_volatile_p && reg_unused_after (insn, base))
return *l=2, (AS2 (st,X+,%A1) CR_TAB
AS2 (st,X,%B1));
else
- return *l=3, (AS2 (st ,X+,%A1) CR_TAB
- AS2 (st ,X,%B1) CR_TAB
- AS2 (sbiw,r26,1));
+ return *l=3, (AS2 (adiw,r26,1) CR_TAB
+ AS2 (st,X,%B1) CR_TAB
+ AS2 (st,-X,%A1));
}
}
else
- return *l=2, (AS2 (st ,%0,%A1) CR_TAB
- AS2 (std,%0+1,%B1));
+ return *l=2, (AS2 (std,%0+1,%B1) CR_TAB
+ AS2 (st,%0,%A1));
}
else if (GET_CODE (base) == PLUS)
{
if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)))
return *l = 4, (AS2 (adiw,r28,%o0-62) CR_TAB
- AS2 (std,Y+62,%A1) CR_TAB
AS2 (std,Y+63,%B1) CR_TAB
+ AS2 (std,Y+62,%A1) CR_TAB
AS2 (sbiw,r28,%o0-62));
return *l = 6, (AS2 (subi,r28,lo8(-%o0)) CR_TAB
AS2 (sbci,r29,hi8(-%o0)) CR_TAB
- AS2 (st,Y,%A1) CR_TAB
AS2 (std,Y+1,%B1) CR_TAB
+ AS2 (st,Y,%A1) CR_TAB
AS2 (subi,r28,lo8(%o0)) CR_TAB
AS2 (sbci,r29,hi8(%o0)));
}
{
/* (X + d) = R */
if (reg_src == REG_X)
- {
+ {
*l = 7;
return (AS2 (mov,__tmp_reg__,r26) CR_TAB
AS2 (mov,__zero_reg__,r27) CR_TAB
- AS2 (adiw,r26,%o0) CR_TAB
- AS2 (st,X+,__tmp_reg__) CR_TAB
+ AS2 (adiw,r26,%o0+1) CR_TAB
AS2 (st,X,__zero_reg__) CR_TAB
+ AS2 (st,-X,__tmp_reg__) CR_TAB
AS1 (clr,__zero_reg__) CR_TAB
- AS2 (sbiw,r26,%o0+1));
+ AS2 (sbiw,r26,%o0));
}
*l = 4;
- return (AS2 (adiw,r26,%o0) CR_TAB
- AS2 (st,X+,%A1) CR_TAB
- AS2 (st,X,%B1) CR_TAB
- AS2 (sbiw,r26,%o0+1));
+ return (AS2 (adiw,r26,%o0+1) CR_TAB
+ AS2 (st,X,%B1) CR_TAB
+ AS2 (st,-X,%A1) CR_TAB
+ AS2 (sbiw,r26,%o0));
}
- return *l=2, (AS2 (std,%A0,%A1) CR_TAB
- AS2 (std,%B0,%B1));
+ return *l=2, (AS2 (std,%B0,%B1) CR_TAB
+ AS2 (std,%A0,%A1));
}
else if (GET_CODE (base) == PRE_DEC) /* (--R) */
return *l=2, (AS2 (st,%0,%B1) CR_TAB
AS2 (st,%0,%A1));
else if (GET_CODE (base) == POST_INC) /* (R++) */
- return *l=2, (AS2 (st,%0,%A1) CR_TAB
- AS2 (st,%0,%B1));
+ {
+ if (mem_volatile_p)
+ {
+ if (REGNO (XEXP (base, 0)) == REG_X)
+ {
+ *l = 4;
+ return (AS2 (adiw,r26,1) CR_TAB
+ AS2 (st,X,%B1) CR_TAB
+ AS2 (st,-X,%A1) CR_TAB
+ AS2 (adiw,r26,2));
+ }
+ else
+ {
+ *l = 3;
+ return (AS2 (std,%p0+1,%B1) CR_TAB
+ AS2 (st,%p0,%A1) CR_TAB
+ AS2 (adiw,%r0,2));
+ }
+ }
+
+ *l = 2;
+ return (AS2 (st,%0,%A1) CR_TAB
+ AS2 (st,%0,%B1));
+ }
fatal_insn ("unknown move insn:",insn);
return "";
}
int count = INTVAL (operands[2]);
int max_len = 10; /* If larger than this, always use a loop. */
+ if (count <= 0)
+ {
+ if (len)
+ *len = 0;
+ return;
+ }
+
if (count < 8 && !scratch)
use_zero_reg = 1;
switch (INTVAL (operands[2]))
{
default:
+ if (INTVAL (operands[2]) < 8)
+ break;
+
*len = 1;
return AS1 (clr,%0);
switch (INTVAL (operands[2]))
{
+ default:
+ if (INTVAL (operands[2]) < 16)
+ break;
+
+ *len = 2;
+ return (AS1 (clr,%B0) CR_TAB
+ AS1 (clr,%A0));
+
case 4:
if (optimize_size && scratch)
break; /* 5 */
AS1 (ror,%A0));
case 8:
- if (true_regnum (operands[0]) + 1 == true_regnum (operands[1]))
- return *len = 1, AS1 (clr,%A0);
- else
- return *len = 2, (AS2 (mov,%B0,%A1) CR_TAB
- AS1 (clr,%A0));
+ return *len = 2, (AS2 (mov,%B0,%A1) CR_TAB
+ AS1 (clr,%A0));
case 9:
*len = 3;
AS1 (lsl,%B0) CR_TAB
AS2 (andi,%B0,0xe0));
}
- if (AVR_ENHANCED && scratch)
+ if (AVR_HAVE_MUL && scratch)
{
*len = 5;
return (AS2 (ldi,%3,0x20) CR_TAB
AS2 (ldi,%3,0xe0) CR_TAB
AS2 (and,%B0,%3));
}
- if (AVR_ENHANCED)
+ if (AVR_HAVE_MUL)
{
*len = 6;
return ("set" CR_TAB
AS1 (lsl,%B0));
case 14:
- if (AVR_ENHANCED && ldi_ok)
+ if (AVR_HAVE_MUL && ldi_ok)
{
*len = 5;
return (AS2 (ldi,%B0,0x40) CR_TAB
AS1 (clr,%A0) CR_TAB
AS1 (clr,__zero_reg__));
}
- if (AVR_ENHANCED && scratch)
+ if (AVR_HAVE_MUL && scratch)
{
*len = 5;
return (AS2 (ldi,%3,0x40) CR_TAB
switch (INTVAL (operands[2]))
{
+ default:
+ if (INTVAL (operands[2]) < 32)
+ break;
+
+ if (AVR_HAVE_MOVW)
+ return *len = 3, (AS1 (clr,%D0) CR_TAB
+ AS1 (clr,%C0) CR_TAB
+ AS2 (movw,%A0,%C0));
+ *len = 4;
+ return (AS1 (clr,%D0) CR_TAB
+ AS1 (clr,%C0) CR_TAB
+ AS1 (clr,%B0) CR_TAB
+ AS1 (clr,%A0));
+
case 8:
{
int reg0 = true_regnum (operands[0]);
AS2 (mov,%C0,%B1) CR_TAB
AS2 (mov,%B0,%A1) CR_TAB
AS1 (clr,%A0));
- else if (reg0 + 1 == reg1)
- {
- *len = 1;
- return AS1 (clr,%A0);
- }
else
return (AS1 (clr,%A0) CR_TAB
AS2 (mov,%B0,%A1) CR_TAB
{
int reg0 = true_regnum (operands[0]);
int reg1 = true_regnum (operands[1]);
- *len = 4;
- if (AVR_ENHANCED && (reg0 + 2 != reg1))
- {
- *len = 3;
- return (AS2 (movw,%C0,%A1) CR_TAB
- AS1 (clr,%B0) CR_TAB
- AS1 (clr,%A0));
- }
- if (reg0 + 1 >= reg1)
- return (AS2 (mov,%D0,%B1) CR_TAB
- AS2 (mov,%C0,%A1) CR_TAB
- AS1 (clr,%B0) CR_TAB
- AS1 (clr,%A0));
if (reg0 + 2 == reg1)
- {
- *len = 2;
- return (AS1 (clr,%B0) CR_TAB
- AS1 (clr,%A0));
- }
+ return *len = 2, (AS1 (clr,%B0) CR_TAB
+ AS1 (clr,%A0));
+ if (AVR_HAVE_MOVW)
+ return *len = 3, (AS2 (movw,%C0,%A1) CR_TAB
+ AS1 (clr,%B0) CR_TAB
+ AS1 (clr,%A0));
else
- return (AS2 (mov,%C0,%A1) CR_TAB
- AS2 (mov,%D0,%B1) CR_TAB
- AS1 (clr,%B0) CR_TAB
- AS1 (clr,%A0));
+ return *len = 4, (AS2 (mov,%C0,%A1) CR_TAB
+ AS2 (mov,%D0,%B1) CR_TAB
+ AS1 (clr,%B0) CR_TAB
+ AS1 (clr,%A0));
}
case 24:
*len = 4;
- if (true_regnum (operands[0]) + 3 != true_regnum (operands[1]))
- return (AS2 (mov,%D0,%A1) CR_TAB
- AS1 (clr,%C0) CR_TAB
- AS1 (clr,%B0) CR_TAB
- AS1 (clr,%A0));
- else
- {
- *len = 3;
- return (AS1 (clr,%C0) CR_TAB
- AS1 (clr,%B0) CR_TAB
- AS1 (clr,%A0));
- }
+ return (AS2 (mov,%D0,%A1) CR_TAB
+ AS1 (clr,%C0) CR_TAB
+ AS1 (clr,%B0) CR_TAB
+ AS1 (clr,%A0));
case 31:
*len = 6;
AS2 (bld,%0,0));
default:
+ if (INTVAL (operands[2]) < 8)
+ break;
+
+ /* fall through */
+
case 7:
*len = 2;
return (AS1 (lsl,%0) CR_TAB
return *len = 3, (AS2 (mov,%A0,%B0) CR_TAB
AS1 (lsl,%B0) CR_TAB
AS2 (sbc,%B0,%B0));
- else if (reg0 == reg1 + 1)
- return *len = 3, (AS1 (clr,%B0) CR_TAB
- AS2 (sbrc,%A0,7) CR_TAB
- AS1 (dec,%B0));
-
- return *len = 4, (AS2 (mov,%A0,%B1) CR_TAB
- AS1 (clr,%B0) CR_TAB
- AS2 (sbrc,%A0,7) CR_TAB
- AS1 (dec,%B0));
+ else
+ return *len = 4, (AS2 (mov,%A0,%B1) CR_TAB
+ AS1 (clr,%B0) CR_TAB
+ AS2 (sbrc,%A0,7) CR_TAB
+ AS1 (dec,%B0));
}
case 9:
AS1 (asr,%A0));
case 11:
- if (AVR_ENHANCED && ldi_ok)
+ if (AVR_HAVE_MUL && ldi_ok)
{
*len = 5;
return (AS2 (ldi,%A0,0x20) CR_TAB
AS1 (asr,%A0));
case 12:
- if (AVR_ENHANCED && ldi_ok)
+ if (AVR_HAVE_MUL && ldi_ok)
{
*len = 5;
return (AS2 (ldi,%A0,0x10) CR_TAB
AS1 (asr,%A0));
case 13:
- if (AVR_ENHANCED && ldi_ok)
+ if (AVR_HAVE_MUL && ldi_ok)
{
*len = 5;
return (AS2 (ldi,%A0,0x08) CR_TAB
AS2 (mov,%B0,%A0) CR_TAB
AS1 (rol,%A0));
+ default:
+ if (INTVAL (operands[2]) < 16)
+ break;
+
+ /* fall through */
+
case 15:
return *len = 3, (AS1 (lsl,%B0) CR_TAB
AS2 (sbc,%A0,%A0) CR_TAB
AS1 (clr,%D0) CR_TAB
AS2 (sbrc,%C0,7) CR_TAB
AS1 (dec,%D0));
- else if (reg0 == reg1 + 1)
- {
- *len = 3;
- return (AS1 (clr,%D0) CR_TAB
- AS2 (sbrc,%C0,7) CR_TAB
- AS1 (dec,%D0));
- }
else
return (AS1 (clr,%D0) CR_TAB
AS2 (sbrc,%D1,7) CR_TAB
{
int reg0 = true_regnum (operands[0]);
int reg1 = true_regnum (operands[1]);
- *len=6;
- if (AVR_ENHANCED && (reg0 != reg1 + 2))
- {
- *len = 5;
- return (AS2 (movw,%A0,%C1) CR_TAB
- AS1 (clr,%D0) CR_TAB
- AS2 (sbrc,%B0,7) CR_TAB
- AS1 (com,%D0) CR_TAB
- AS2 (mov,%C0,%D0));
- }
- if (reg0 <= reg1 + 1)
- return (AS2 (mov,%A0,%C1) CR_TAB
- AS2 (mov,%B0,%D1) CR_TAB
- AS1 (clr,%D0) CR_TAB
- AS2 (sbrc,%B0,7) CR_TAB
- AS1 (com,%D0) CR_TAB
- AS2 (mov,%C0,%D0));
- else if (reg0 == reg1 + 2)
+
+ if (reg0 == reg1 + 2)
return *len = 4, (AS1 (clr,%D0) CR_TAB
AS2 (sbrc,%B0,7) CR_TAB
AS1 (com,%D0) CR_TAB
AS2 (mov,%C0,%D0));
- else
- return (AS2 (mov,%B0,%D1) CR_TAB
- AS2 (mov,%A0,%C1) CR_TAB
- AS1 (clr,%D0) CR_TAB
- AS2 (sbrc,%B0,7) CR_TAB
- AS1 (com,%D0) CR_TAB
- AS2 (mov,%C0,%D0));
+ if (AVR_HAVE_MOVW)
+ return *len = 5, (AS2 (movw,%A0,%C1) CR_TAB
+ AS1 (clr,%D0) CR_TAB
+ AS2 (sbrc,%B0,7) CR_TAB
+ AS1 (com,%D0) CR_TAB
+ AS2 (mov,%C0,%D0));
+ else
+ return *len = 6, (AS2 (mov,%B0,%D1) CR_TAB
+ AS2 (mov,%A0,%C1) CR_TAB
+ AS1 (clr,%D0) CR_TAB
+ AS2 (sbrc,%B0,7) CR_TAB
+ AS1 (com,%D0) CR_TAB
+ AS2 (mov,%C0,%D0));
}
case 24:
- if (true_regnum (operands[0]) != true_regnum (operands[1]) + 3)
- return *len = 6, (AS2 (mov,%A0,%D1) CR_TAB
- AS1 (clr,%D0) CR_TAB
- AS2 (sbrc,%A0,7) CR_TAB
- AS1 (com,%D0) CR_TAB
- AS2 (mov,%B0,%D0) CR_TAB
- AS2 (mov,%C0,%D0));
- else
- return *len = 5, (AS1 (clr,%D0) CR_TAB
- AS2 (sbrc,%A0,7) CR_TAB
- AS1 (com,%D0) CR_TAB
- AS2 (mov,%B0,%D0) CR_TAB
- AS2 (mov,%C0,%D0));
+ return *len = 6, (AS2 (mov,%A0,%D1) CR_TAB
+ AS1 (clr,%D0) CR_TAB
+ AS2 (sbrc,%A0,7) CR_TAB
+ AS1 (com,%D0) CR_TAB
+ AS2 (mov,%B0,%D0) CR_TAB
+ AS2 (mov,%C0,%D0));
+
+ default:
+ if (INTVAL (operands[2]) < 32)
+ break;
+
+ /* fall through */
case 31:
- if (AVR_ENHANCED)
+ if (AVR_HAVE_MOVW)
return *len = 4, (AS1 (lsl,%D0) CR_TAB
AS2 (sbc,%A0,%A0) CR_TAB
AS2 (mov,%B0,%A0) CR_TAB
switch (INTVAL (operands[2]))
{
default:
+ if (INTVAL (operands[2]) < 8)
+ break;
+
*len = 1;
return AS1 (clr,%0);
switch (INTVAL (operands[2]))
{
+ default:
+ if (INTVAL (operands[2]) < 16)
+ break;
+
+ *len = 2;
+ return (AS1 (clr,%B0) CR_TAB
+ AS1 (clr,%A0));
+
case 4:
if (optimize_size && scratch)
break; /* 5 */
AS1 (neg,%B0));
case 8:
- if (true_regnum (operands[0]) != true_regnum (operands[1]) + 1)
- return *len = 2, (AS2 (mov,%A0,%B1) CR_TAB
- AS1 (clr,%B0));
- else
- return *len = 1, AS1 (clr,%B0);
+ return *len = 2, (AS2 (mov,%A0,%B1) CR_TAB
+ AS1 (clr,%B0));
case 9:
*len = 3;
AS1 (lsr,%A0) CR_TAB
AS2 (andi,%A0,0x07));
}
- if (AVR_ENHANCED && scratch)
+ if (AVR_HAVE_MUL && scratch)
{
*len = 5;
return (AS2 (ldi,%3,0x08) CR_TAB
AS2 (ldi,%3,0x07) CR_TAB
AS2 (and,%A0,%3));
}
- if (AVR_ENHANCED)
+ if (AVR_HAVE_MUL)
{
*len = 6;
return ("set" CR_TAB
AS1 (lsr,%A0));
case 14:
- if (AVR_ENHANCED && ldi_ok)
+ if (AVR_HAVE_MUL && ldi_ok)
{
*len = 5;
return (AS2 (ldi,%A0,0x04) CR_TAB
AS1 (clr,%B0) CR_TAB
AS1 (clr,__zero_reg__));
}
- if (AVR_ENHANCED && scratch)
+ if (AVR_HAVE_MUL && scratch)
{
*len = 5;
return (AS2 (ldi,%3,0x04) CR_TAB
switch (INTVAL (operands[2]))
{
+ default:
+ if (INTVAL (operands[2]) < 32)
+ break;
+
+ if (AVR_HAVE_MOVW)
+ return *len = 3, (AS1 (clr,%D0) CR_TAB
+ AS1 (clr,%C0) CR_TAB
+ AS2 (movw,%A0,%C0));
+ *len = 4;
+ return (AS1 (clr,%D0) CR_TAB
+ AS1 (clr,%C0) CR_TAB
+ AS1 (clr,%B0) CR_TAB
+ AS1 (clr,%A0));
+
case 8:
{
int reg0 = true_regnum (operands[0]);
AS2 (mov,%B0,%C1) CR_TAB
AS2 (mov,%C0,%D1) CR_TAB
AS1 (clr,%D0));
- else if (reg0 == reg1 + 1)
- return *len = 1, AS1 (clr,%D0);
else
return (AS1 (clr,%D0) CR_TAB
AS2 (mov,%C0,%D1) CR_TAB
{
int reg0 = true_regnum (operands[0]);
int reg1 = true_regnum (operands[1]);
- *len = 4;
- if (AVR_ENHANCED && (reg0 != reg1 + 2))
- {
- *len = 3;
- return (AS2 (movw,%A0,%C1) CR_TAB
- AS1 (clr,%C0) CR_TAB
- AS1 (clr,%D0));
- }
- if (reg0 <= reg1 + 1)
- return (AS2 (mov,%A0,%C1) CR_TAB
- AS2 (mov,%B0,%D1) CR_TAB
- AS1 (clr,%C0) CR_TAB
- AS1 (clr,%D0));
- else if (reg0 == reg1 + 2)
+
+ if (reg0 == reg1 + 2)
return *len = 2, (AS1 (clr,%C0) CR_TAB
AS1 (clr,%D0));
+ if (AVR_HAVE_MOVW)
+ return *len = 3, (AS2 (movw,%A0,%C1) CR_TAB
+ AS1 (clr,%C0) CR_TAB
+ AS1 (clr,%D0));
else
- return (AS2 (mov,%B0,%D1) CR_TAB
- AS2 (mov,%A0,%C1) CR_TAB
- AS1 (clr,%C0) CR_TAB
- AS1 (clr,%D0));
+ return *len = 4, (AS2 (mov,%B0,%D1) CR_TAB
+ AS2 (mov,%A0,%C1) CR_TAB
+ AS1 (clr,%C0) CR_TAB
+ AS1 (clr,%D0));
}
case 24:
- if (true_regnum (operands[0]) != true_regnum (operands[1]) + 3)
- return *len = 4, (AS2 (mov,%A0,%D1) CR_TAB
- AS1 (clr,%B0) CR_TAB
- AS1 (clr,%C0) CR_TAB
- AS1 (clr,%D0));
- else
- return *len = 3, (AS1 (clr,%B0) CR_TAB
- AS1 (clr,%C0) CR_TAB
- AS1 (clr,%D0));
+ return *len = 4, (AS2 (mov,%A0,%D1) CR_TAB
+ AS1 (clr,%B0) CR_TAB
+ AS1 (clr,%C0) CR_TAB
+ AS1 (clr,%D0));
case 31:
*len = 6;
while ((insn = NEXT_INSN (insn)))
{
+ rtx set;
code = GET_CODE (insn);
#if 0
/* else */
#endif
+ if (!INSN_P (insn))
+ continue;
+
if (code == JUMP_INSN)
return 0;
return 1;
}
- if (GET_RTX_CLASS (code) == 'i')
- {
- rtx set = single_set (insn);
+ set = single_set (insn);
- if (set && reg_overlap_mentioned_p (reg, SET_SRC (set)))
- return 0;
- if (set && reg_overlap_mentioned_p (reg, SET_DEST (set)))
- return GET_CODE (SET_DEST (set)) != MEM;
- if (set == 0 && reg_overlap_mentioned_p (reg, PATTERN (insn)))
- return 0;
- }
+ if (set && reg_overlap_mentioned_p (reg, SET_SRC (set)))
+ return 0;
+ if (set && reg_overlap_mentioned_p (reg, SET_DEST (set)))
+ return GET_CODE (SET_DEST (set)) != MEM;
+ if (set == 0 && reg_overlap_mentioned_p (reg, PATTERN (insn)))
+ return 0;
}
return 1;
}
return default_assemble_integer (x, size, aligned_p);
}
-/* Sets section name for declaration DECL. */
-
-static void
-avr_unique_section (tree decl, int reloc ATTRIBUTE_UNUSED)
-{
- int len;
- const char *name, *prefix;
- char *string;
-
- name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
- name = (* targetm.strip_name_encoding) (name);
-
- if (TREE_CODE (decl) == FUNCTION_DECL)
- {
- if (flag_function_sections)
- prefix = ".text.";
- else
- prefix = ".text";
- }
- else
- abort ();
-
- if (flag_function_sections)
- {
- len = strlen (name) + strlen (prefix);
- string = alloca (len + 1);
- sprintf (string, "%s%s", prefix, name);
- DECL_SECTION_NAME (decl) = build_string (len, string);
- }
-}
-
-
/* The routine used to output NUL terminated strings. We use a special
version of this for most svr4 targets because doing so makes the
generated assembly code more compact (and thus faster to assemble)
{
if (DECL_INITIAL (*node) == NULL_TREE && !DECL_EXTERNAL (*node))
{
- warning ("only initialized variables can be placed into "
+ warning (0, "only initialized variables can be placed into "
"program memory area");
*no_add_attrs = true;
}
}
else
{
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qs attribute ignored",
+ IDENTIFIER_POINTER (name));
*no_add_attrs = true;
}
}
{
if (TREE_CODE (*node) != FUNCTION_DECL)
{
- warning ("`%s' attribute only applies to functions",
+ warning (OPT_Wattributes, "%qs attribute only applies to functions",
IDENTIFIER_POINTER (name));
*no_add_attrs = true;
}
+ else
+ {
+ const char *func_name = IDENTIFIER_POINTER (DECL_NAME (*node));
+ const char *attr = IDENTIFIER_POINTER (name);
+
+ /* If the function has the 'signal' or 'interrupt' attribute, test to
+ make sure that the name of the function is "__vector_NN" so as to
+ catch when the user misspells the interrupt vector name. */
+
+ if (strncmp (attr, "interrupt", strlen ("interrupt")) == 0)
+ {
+ if (strncmp (func_name, "__vector", strlen ("__vector")) != 0)
+ {
+ warning (0, "%qs appears to be a misspelled interrupt handler",
+ func_name);
+ }
+ }
+ else if (strncmp (attr, "signal", strlen ("signal")) == 0)
+ {
+ if (strncmp (func_name, "__vector", strlen ("__vector")) != 0)
+ {
+ warning (0, "%qs appears to be a misspelled signal handler",
+ func_name);
+ }
+ }
+ }
return NULL_TREE;
}
if found return 1, otherwise 0. */
int
-avr_progmem_p (tree decl)
+avr_progmem_p (tree decl, tree attributes)
{
tree a;
return 0;
if (NULL_TREE
- != lookup_attribute ("progmem", DECL_ATTRIBUTES (decl)))
+ != lookup_attribute ("progmem", attributes))
return 1;
a=decl;
{
if (TREE_CODE (node) == VAR_DECL
&& (TREE_STATIC (node) || DECL_EXTERNAL (node))
- && avr_progmem_p (node))
+ && avr_progmem_p (node, *attributes))
{
static const char dsec[] = ".progmem.data";
*attributes = tree_cons (get_identifier ("section"),
}
}
+/* A get_unnamed_section callback for switching to progmem_section. */
+
+static void
+avr_output_progmem_section_asm_op (const void *arg ATTRIBUTE_UNUSED)
+{
+ fprintf (asm_out_file,
+ "\t.section .progmem.gcc_sw_table, \"%s\", @progbits\n",
+ AVR_MEGA ? "a" : "ax");
+ /* Should already be aligned, this is just to be safe if it isn't. */
+ fprintf (asm_out_file, "\t.p2align 1\n");
+}
+
+/* Implement TARGET_ASM_INIT_SECTIONS. */
+
+static void
+avr_asm_init_sections (void)
+{
+ progmem_section = get_unnamed_section (AVR_MEGA ? 0 : SECTION_CODE,
+ avr_output_progmem_section_asm_op,
+ NULL);
+ readonly_data_section = data_section;
+}
+
static unsigned int
avr_section_type_flags (tree decl, const char *name, int reloc)
{
&& DECL_INITIAL (decl) == NULL_TREE)
flags |= SECTION_BSS; /* @nobits */
else
- warning ("only uninitialized variables can be placed in the "
+ warning (0, "only uninitialized variables can be placed in the "
".noinit section");
}
avr_file_start (void)
{
if (avr_asm_only_p)
- error ("MCU `%s' supported for assembler only", avr_mcu_name);
+ error ("MCU %qs supported for assembler only", avr_mcu_name);
default_file_start ();
- fprintf (asm_out_file, "\t.arch %s\n", avr_mcu_name);
+/* fprintf (asm_out_file, "\t.arch %s\n", avr_mcu_name);*/
fputs ("__SREG__ = 0x3f\n"
"__SP_H__ = 0x3e\n"
"__SP_L__ = 0x3d\n", asm_out_file);
reg_alloc_order[i] = order[i];
}
-/* Calculate the cost of X code of the expression in which it is contained,
- found in OUTER_CODE */
+
+/* Mutually recursive subroutine of avr_rtx_cost for calculating the
+ cost of an RTX operand given its context. X is the rtx of the
+ operand, MODE is its mode, and OUTER is the rtx_code of this
+ operand's parent operator. */
static int
-default_rtx_costs (rtx X, enum rtx_code code, enum rtx_code outer_code)
+avr_operand_rtx_cost (rtx x, enum machine_mode mode, enum rtx_code outer)
{
- int cost=0;
+ enum rtx_code code = GET_CODE (x);
+ int total;
+
switch (code)
{
- case SYMBOL_REF:
- case LABEL_REF:
- cost = 2 * GET_MODE_SIZE (GET_MODE (X));
- break;
- case MEM:
- if (outer_code != SET)
- cost = 1;
- if (GET_CODE (XEXP (X,0)) == SYMBOL_REF)
- cost += 2 * GET_MODE_SIZE (GET_MODE (X));
- else
- cost += GET_MODE_SIZE (GET_MODE (X));
- break;
+ case REG:
+ case SUBREG:
+ return 0;
+
case CONST_INT:
- cost = 0;
- break;
- case SIGN_EXTEND:
- if (outer_code == SET)
- cost = GET_MODE_SIZE (GET_MODE (X));
- else
- cost = -GET_MODE_SIZE (GET_MODE (X));
- break;
- case ZERO_EXTEND:
- if (outer_code == SET)
- cost = GET_MODE_SIZE (GET_MODE (X));
- else
- cost = -1;
- break;
- case PLUS:
- case MINUS:
- if (outer_code == SET)
- {
- if (X == stack_pointer_rtx)
- cost = -10;
- else if (GET_CODE (XEXP (X,1)) == CONST_INT)
- cost = (INTVAL (XEXP (X,1)) <= 63 ? 1 :
- GET_MODE_SIZE (GET_MODE (X)));
- else
- cost = GET_MODE_SIZE (GET_MODE (X));
- }
- break;
- case COMPARE:
- if (GET_CODE (XEXP (X,1)) == CONST_INT)
- cost = GET_MODE_SIZE (GET_MODE (XEXP (X,0)));
- break;
+ case CONST_DOUBLE:
+ return COSTS_N_INSNS (GET_MODE_SIZE (mode));
+
default:
break;
}
- return cost;
+
+ total = 0;
+ avr_rtx_costs (x, code, outer, &total);
+ return total;
}
+/* The AVR backend's rtx_cost function. X is rtx expression whose cost
+ is to be calculated. Return true if the complete cost has been
+ computed, and false if subexpressions should be scanned. In either
+ case, *TOTAL contains the cost result. */
+
static bool
-avr_rtx_costs (rtx x, int code, int outer_code, int *total)
+avr_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total)
{
- int cst;
+ enum machine_mode mode = GET_MODE (x);
+ HOST_WIDE_INT val;
switch (code)
{
case CONST_INT:
- if (outer_code == PLUS
- || outer_code == IOR
- || outer_code == AND
- || outer_code == MINUS
- || outer_code == SET
- || INTVAL (x) == 0)
+ case CONST_DOUBLE:
+ /* Immediate constants are as cheap as registers. */
+ *total = 0;
+ return true;
+
+ case MEM:
+ case CONST:
+ case LABEL_REF:
+ case SYMBOL_REF:
+ *total = COSTS_N_INSNS (GET_MODE_SIZE (mode));
+ return true;
+
+ case NEG:
+ switch (mode)
{
- *total = 2;
- return true;
+ case QImode:
+ case SFmode:
+ *total = COSTS_N_INSNS (1);
+ break;
+
+ case HImode:
+ *total = COSTS_N_INSNS (3);
+ break;
+
+ case SImode:
+ *total = COSTS_N_INSNS (7);
+ break;
+
+ default:
+ return false;
}
- if (outer_code == COMPARE
- && INTVAL (x) >= 0
- && INTVAL (x) <= 255)
+ *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
+ return true;
+
+ case ABS:
+ switch (mode)
{
- *total = 2;
- return true;
+ case QImode:
+ case SFmode:
+ *total = COSTS_N_INSNS (1);
+ break;
+
+ default:
+ return false;
}
- /* FALLTHRU */
+ *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
+ return true;
- case CONST:
- case LABEL_REF:
- case SYMBOL_REF:
- case CONST_DOUBLE:
- *total = 4;
+ case NOT:
+ *total = COSTS_N_INSNS (GET_MODE_SIZE (mode));
+ *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
return true;
- default:
- cst = default_rtx_costs (x, code, outer_code);
- if (cst > 0)
+ case ZERO_EXTEND:
+ *total = COSTS_N_INSNS (GET_MODE_SIZE (mode)
+ - GET_MODE_SIZE (GET_MODE (XEXP (x, 0))));
+ *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
+ return true;
+
+ case SIGN_EXTEND:
+ *total = COSTS_N_INSNS (GET_MODE_SIZE (mode) + 2
+ - GET_MODE_SIZE (GET_MODE (XEXP (x, 0))));
+ *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
+ return true;
+
+ case PLUS:
+ switch (mode)
+ {
+ case QImode:
+ *total = COSTS_N_INSNS (1);
+ if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+ *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+ break;
+
+ case HImode:
+ if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+ {
+ *total = COSTS_N_INSNS (2);
+ *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+ }
+ else if (INTVAL (XEXP (x, 1)) >= -63 && INTVAL (XEXP (x, 1)) <= 63)
+ *total = COSTS_N_INSNS (1);
+ else
+ *total = COSTS_N_INSNS (2);
+ break;
+
+ case SImode:
+ if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+ {
+ *total = COSTS_N_INSNS (4);
+ *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+ }
+ else if (INTVAL (XEXP (x, 1)) >= -63 && INTVAL (XEXP (x, 1)) <= 63)
+ *total = COSTS_N_INSNS (1);
+ else
+ *total = COSTS_N_INSNS (4);
+ break;
+
+ default:
+ return false;
+ }
+ *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
+ return true;
+
+ case MINUS:
+ case AND:
+ case IOR:
+ *total = COSTS_N_INSNS (GET_MODE_SIZE (mode));
+ *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
+ if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+ *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+ return true;
+
+ case XOR:
+ *total = COSTS_N_INSNS (GET_MODE_SIZE (mode));
+ *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
+ *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+ return true;
+
+ case MULT:
+ switch (mode)
{
- *total = cst;
- return true;
+ case QImode:
+ if (AVR_HAVE_MUL)
+ *total = COSTS_N_INSNS (optimize_size ? 3 : 4);
+ else if (optimize_size)
+ *total = COSTS_N_INSNS (AVR_MEGA ? 2 : 1);
+ else
+ return false;
+
+ case HImode:
+ if (AVR_HAVE_MUL)
+ *total = COSTS_N_INSNS (optimize_size ? 7 : 10);
+ else if (optimize_size)
+ *total = COSTS_N_INSNS (AVR_MEGA ? 2 : 1);
+ else
+ return false;
+
+ default:
+ return false;
+ }
+ *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
+ *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+ return true;
+
+ case DIV:
+ case MOD:
+ case UDIV:
+ case UMOD:
+ if (optimize_size)
+ *total = COSTS_N_INSNS (AVR_MEGA ? 2 : 1);
+ else
+ return false;
+ *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
+ *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+ return true;
+
+ case ASHIFT:
+ switch (mode)
+ {
+ case QImode:
+ if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+ {
+ *total = COSTS_N_INSNS (optimize_size ? 4 : 17);
+ *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+ }
+ else
+ {
+ val = INTVAL (XEXP (x, 1));
+ if (val == 7)
+ *total = COSTS_N_INSNS (3);
+ else if (val >= 0 && val <= 7)
+ *total = COSTS_N_INSNS (val);
+ else
+ *total = COSTS_N_INSNS (1);
+ }
+ break;
+
+ case HImode:
+ if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+ {
+ *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
+ *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+ }
+ else
+ switch (INTVAL (XEXP (x, 1)))
+ {
+ case 0:
+ *total = 0;
+ break;
+ case 1:
+ case 8:
+ *total = COSTS_N_INSNS (2);
+ break;
+ case 9:
+ *total = COSTS_N_INSNS (3);
+ break;
+ case 2:
+ case 3:
+ case 10:
+ case 15:
+ *total = COSTS_N_INSNS (4);
+ break;
+ case 7:
+ case 11:
+ case 12:
+ *total = COSTS_N_INSNS (5);
+ break;
+ case 4:
+ *total = COSTS_N_INSNS (optimize_size ? 5 : 8);
+ break;
+ case 6:
+ *total = COSTS_N_INSNS (optimize_size ? 5 : 9);
+ break;
+ case 5:
+ *total = COSTS_N_INSNS (optimize_size ? 5 : 10);
+ break;
+ default:
+ *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
+ *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+ }
+ break;
+
+ case SImode:
+ if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+ {
+ *total = COSTS_N_INSNS (optimize_size ? 7 : 113);
+ *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+ }
+ else
+ switch (INTVAL (XEXP (x, 1)))
+ {
+ case 0:
+ *total = 0;
+ break;
+ case 24:
+ *total = COSTS_N_INSNS (3);
+ break;
+ case 1:
+ case 8:
+ case 16:
+ *total = COSTS_N_INSNS (4);
+ break;
+ case 31:
+ *total = COSTS_N_INSNS (6);
+ break;
+ case 2:
+ *total = COSTS_N_INSNS (optimize_size ? 7 : 8);
+ break;
+ default:
+ *total = COSTS_N_INSNS (optimize_size ? 7 : 113);
+ *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+ }
+ break;
+
+ default:
+ return false;
}
- else if (cst < 0)
- *total += -cst;
- return false;
+ *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
+ return true;
+
+ case ASHIFTRT:
+ switch (mode)
+ {
+ case QImode:
+ if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+ {
+ *total = COSTS_N_INSNS (optimize_size ? 4 : 17);
+ *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+ }
+ else
+ {
+ val = INTVAL (XEXP (x, 1));
+ if (val == 6)
+ *total = COSTS_N_INSNS (4);
+ else if (val == 7)
+ *total = COSTS_N_INSNS (2);
+ else if (val >= 0 && val <= 7)
+ *total = COSTS_N_INSNS (val);
+ else
+ *total = COSTS_N_INSNS (1);
+ }
+ break;
+
+ case HImode:
+ if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+ {
+ *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
+ *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+ }
+ else
+ switch (INTVAL (XEXP (x, 1)))
+ {
+ case 0:
+ *total = 0;
+ break;
+ case 1:
+ *total = COSTS_N_INSNS (2);
+ break;
+ case 15:
+ *total = COSTS_N_INSNS (3);
+ break;
+ case 2:
+ case 7:
+ case 8:
+ case 9:
+ *total = COSTS_N_INSNS (4);
+ break;
+ case 10:
+ case 14:
+ *total = COSTS_N_INSNS (5);
+ break;
+ case 11:
+ *total = COSTS_N_INSNS (optimize_size ? 5 : 6);
+ break;
+ case 12:
+ *total = COSTS_N_INSNS (optimize_size ? 5 : 7);
+ break;
+ case 6:
+ case 13:
+ *total = COSTS_N_INSNS (optimize_size ? 5 : 8);
+ break;
+ default:
+ *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
+ *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+ }
+ break;
+
+ case SImode:
+ if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+ {
+ *total = COSTS_N_INSNS (optimize_size ? 7 : 113);
+ *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+ }
+ else
+ switch (INTVAL (XEXP (x, 1)))
+ {
+ case 0:
+ *total = 0;
+ break;
+ case 1:
+ *total = COSTS_N_INSNS (4);
+ break;
+ case 8:
+ case 16:
+ case 24:
+ *total = COSTS_N_INSNS (6);
+ break;
+ case 2:
+ *total = COSTS_N_INSNS (optimize_size ? 7 : 8);
+ break;
+ case 31:
+ *total = COSTS_N_INSNS (AVR_HAVE_MOVW ? 4 : 5);
+ break;
+ default:
+ *total = COSTS_N_INSNS (optimize_size ? 7 : 113);
+ *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+ }
+ break;
+
+ default:
+ return false;
+ }
+ *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
+ return true;
+
+ case LSHIFTRT:
+ switch (mode)
+ {
+ case QImode:
+ if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+ {
+ *total = COSTS_N_INSNS (optimize_size ? 4 : 17);
+ *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+ }
+ else
+ {
+ val = INTVAL (XEXP (x, 1));
+ if (val == 7)
+ *total = COSTS_N_INSNS (3);
+ else if (val >= 0 && val <= 7)
+ *total = COSTS_N_INSNS (val);
+ else
+ *total = COSTS_N_INSNS (1);
+ }
+ break;
+
+ case HImode:
+ if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+ {
+ *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
+ *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+ }
+ else
+ switch (INTVAL (XEXP (x, 1)))
+ {
+ case 0:
+ *total = 0;
+ break;
+ case 1:
+ case 8:
+ *total = COSTS_N_INSNS (2);
+ break;
+ case 9:
+ *total = COSTS_N_INSNS (3);
+ break;
+ case 2:
+ case 10:
+ case 15:
+ *total = COSTS_N_INSNS (4);
+ break;
+ case 7:
+ case 11:
+ *total = COSTS_N_INSNS (5);
+ break;
+ case 3:
+ case 12:
+ case 13:
+ case 14:
+ *total = COSTS_N_INSNS (optimize_size ? 5 : 6);
+ break;
+ case 4:
+ *total = COSTS_N_INSNS (optimize_size ? 5 : 7);
+ break;
+ case 5:
+ case 6:
+ *total = COSTS_N_INSNS (optimize_size ? 5 : 9);
+ break;
+ default:
+ *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
+ *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+ }
+ break;
+
+ case SImode:
+ if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+ {
+ *total = COSTS_N_INSNS (optimize_size ? 7 : 113);
+ *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+ }
+ else
+ switch (INTVAL (XEXP (x, 1)))
+ {
+ case 0:
+ *total = 0;
+ break;
+ case 1:
+ *total = COSTS_N_INSNS (4);
+ break;
+ case 2:
+ *total = COSTS_N_INSNS (optimize_size ? 7 : 8);
+ break;
+ case 8:
+ case 16:
+ case 24:
+ *total = COSTS_N_INSNS (4);
+ break;
+ case 31:
+ *total = COSTS_N_INSNS (6);
+ break;
+ default:
+ *total = COSTS_N_INSNS (optimize_size ? 7 : 113);
+ *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+ }
+ break;
+
+ default:
+ return false;
+ }
+ *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
+ return true;
+
+ case COMPARE:
+ switch (GET_MODE (XEXP (x, 0)))
+ {
+ case QImode:
+ *total = COSTS_N_INSNS (1);
+ if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+ *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+ break;
+
+ case HImode:
+ *total = COSTS_N_INSNS (2);
+ if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+ *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+ else if (INTVAL (XEXP (x, 1)) != 0)
+ *total += COSTS_N_INSNS (1);
+ break;
+
+ case SImode:
+ *total = COSTS_N_INSNS (4);
+ if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+ *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
+ else if (INTVAL (XEXP (x, 1)) != 0)
+ *total += COSTS_N_INSNS (3);
+ break;
+
+ default:
+ return false;
+ }
+ *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
+ return true;
+
+ default:
+ break;
}
+ return false;
}
/* Calculate the cost of a memory address. */
return 4;
}
-/* EXTRA_CONSTRAINT helper */
+/* Test for extra memory constraint 'Q'.
+ It's a memory address based on Y or Z pointer with valid displacement. */
int
-extra_constraint (rtx x, int c)
+extra_constraint_Q (rtx x)
{
- if (c == 'Q'
- && GET_CODE (x) == MEM
- && GET_CODE (XEXP (x,0)) == PLUS)
+ if (GET_CODE (XEXP (x,0)) == PLUS
+ && REG_P (XEXP (XEXP (x,0), 0))
+ && GET_CODE (XEXP (XEXP (x,0), 1)) == CONST_INT
+ && (INTVAL (XEXP (XEXP (x,0), 1))
+ <= MAX_LD_OFFSET (GET_MODE (x))))
{
- if (TARGET_ALL_DEBUG)
- {
- fprintf (stderr, ("extra_constraint:\n"
- "reload_completed: %d\n"
- "reload_in_progress: %d\n"),
- reload_completed, reload_in_progress);
- debug_rtx (x);
- }
- if (GET_CODE (x) == MEM
- && GET_CODE (XEXP (x,0)) == PLUS
- && REG_P (XEXP (XEXP (x,0), 0))
- && GET_CODE (XEXP (XEXP (x,0), 1)) == CONST_INT
- && (INTVAL (XEXP (XEXP (x,0), 1))
- <= MAX_LD_OFFSET (GET_MODE (x))))
+ rtx xx = XEXP (XEXP (x,0), 0);
+ int regno = REGNO (xx);
+ if (TARGET_ALL_DEBUG)
{
- rtx xx = XEXP (XEXP (x,0), 0);
- int regno = REGNO (xx);
- if (TARGET_ALL_DEBUG)
- {
- fprintf (stderr, ("extra_constraint:\n"
- "reload_completed: %d\n"
- "reload_in_progress: %d\n"),
- reload_completed, reload_in_progress);
- debug_rtx (x);
- }
- if (regno >= FIRST_PSEUDO_REGISTER)
- return 1; /* allocate pseudos */
- else if (regno == REG_Z || regno == REG_Y)
- return 1; /* strictly check */
- else if (xx == frame_pointer_rtx
- || xx == arg_pointer_rtx)
- return 1; /* XXX frame & arg pointer checks */
+ fprintf (stderr, ("extra_constraint:\n"
+ "reload_completed: %d\n"
+ "reload_in_progress: %d\n"),
+ reload_completed, reload_in_progress);
+ debug_rtx (x);
}
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ return 1; /* allocate pseudos */
+ else if (regno == REG_Z || regno == REG_Y)
+ return 1; /* strictly check */
+ else if (xx == frame_pointer_rtx
+ || xx == arg_pointer_rtx)
+ return 1; /* XXX frame & arg pointer checks */
}
return 0;
}
case LEU:
return LTU;
default:
- abort ();
+ gcc_unreachable ();
}
}
return 24;
}
-/* Ceate an RTX representing the place where a
+/* Create an RTX representing the place where a
library function returns a value of mode MODE. */
rtx
return gen_rtx_REG (BLKmode, RET_REGISTER + 2 - offs);
}
-/* Returns nonzero if the number MASK has only one bit set. */
-
-int
-mask_one_bit_p (HOST_WIDE_INT mask)
-{
- int i;
- unsigned HOST_WIDE_INT n=mask;
- for (i = 0; i < 32; ++i)
- {
- if (n & 0x80000000L)
- {
- if (n & 0x7fffffffL)
- return 0;
- else
- return 32-i;
- }
- n<<=1;
- }
- return 0;
-}
-
-
/* Places additional restrictions on the register class to
use when it is necessary to copy value X into a register
in class CLASS. */
int
avr_hard_regno_mode_ok (int regno, enum machine_mode mode)
{
- /* Bug workaround: recog.c (peep2_find_free_register) and probably
- a few other places assume that the frame pointer is a single hard
- register, so r29 may be allocated and overwrite the high byte of
- the frame pointer. Do not allow any value to start in r29. */
- if (regno == REG_Y + 1)
+ /* The only thing that can go into registers r28:r29 is a Pmode. */
+ if (regno == REG_Y && mode == Pmode)
+ return 1;
+
+ /* Otherwise disallow all regno/mode combinations that span r28:r29. */
+ if (regno <= (REG_Y + 1) && (regno + GET_MODE_SIZE (mode)) >= (REG_Y + 1))
return 0;
if (mode == QImode)
return 1;
- /* if (regno < 24 && !AVR_ENHANCED)
- return 1;*/
+
+ /* Modes larger than QImode occupy consecutive registers. */
+ if (regno + GET_MODE_SIZE (mode) > FIRST_PSEUDO_REGISTER)
+ return 0;
+
+ /* All modes larger than QImode should start in an even register. */
return !(regno & 1);
}
&& INTVAL (x) >= 0x20 && INTVAL (x) <= 0x60 - size);
}
-/* Returns nonzero (bit number + 1) if X, or -X, is a constant power of 2. */
-
-int
-const_int_pow2_p (rtx x)
-{
- if (GET_CODE (x) == CONST_INT)
- {
- HOST_WIDE_INT d = INTVAL (x);
- HOST_WIDE_INT abs_d = (d >= 0) ? d : -d;
- return exact_log2 (abs_d) + 1;
- }
- return 0;
-}
-
const char *
output_reload_inhi (rtx insn ATTRIBUTE_UNUSED, rtx *operands, int *len)
{
void
avr_output_addr_vec_elt (FILE *stream, int value)
{
+ switch_to_section (progmem_section);
if (AVR_MEGA)
fprintf (stream, "\t.word pm(.L%d)\n", value);
else