#include "real.h"
#include "insn-config.h"
#include "conditions.h"
-#include "insn-flags.h"
#include "output.h"
#include "insn-attr.h"
#include "flags.h"
#include "function.h"
#include "recog.h"
#include "tm_p.h"
+#include "target.h"
+#include "target-def.h"
/* Maximal allowed offset for an address in the LD command */
#define MAX_LD_OFFSET(MODE) (64 - (signed)GET_MODE_SIZE (MODE))
static int reg_was_0 PARAMS ((rtx insn, rtx op));
static int io_address_p PARAMS ((rtx x, int size));
void debug_hard_reg_set PARAMS ((HARD_REG_SET set));
+static tree avr_handle_progmem_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree avr_handle_fndecl_attribute PARAMS ((tree *, tree, tree, int, bool *));
+const struct attribute_spec avr_attribute_table[];
+static bool avr_assemble_integer PARAMS ((rtx, unsigned int, int));
+static void avr_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
+static void avr_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
/* Allocate registers from r25 to r8 for parameters for function calls */
#define FIRST_CUM_REG 26
rtx ldi_reg_rtx;
/* AVR register names {"r0", "r1", ..., "r31"} */
-const char * avr_regnames[] = REGISTER_NAMES;
+static const char *const avr_regnames[] = REGISTER_NAMES;
/* This holds the last insn address. */
static int last_insn_address = 0;
};
struct mcu_type_s {
- const char *name;
- enum avr_arch arch;
+ const char *const name;
+ const enum avr_arch arch;
};
/* List of all known AVR MCU types - if updated, it has to be kept
};
int avr_case_values_threshold = 30000;
-
+\f
+/* Initialize the GCC target structure. */
+#undef TARGET_ASM_ALIGNED_HI_OP
+#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
+#undef TARGET_ASM_INTEGER
+#define TARGET_ASM_INTEGER avr_assemble_integer
+
+#undef TARGET_ASM_FUNCTION_PROLOGUE
+#define TARGET_ASM_FUNCTION_PROLOGUE avr_output_function_prologue
+#undef TARGET_ASM_FUNCTION_EPILOGUE
+#define TARGET_ASM_FUNCTION_EPILOGUE avr_output_function_epilogue
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE avr_attribute_table
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+\f
void
avr_override_options ()
{
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);
/* return register class from register number */
-static int reg_class_tab[]={
+static const int reg_class_tab[]={
GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,
GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,
GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,
if (TREE_CODE (func) != FUNCTION_DECL)
abort ();
- a = lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (func));
+ a = lookup_attribute ("naked", DECL_ATTRIBUTES (func));
return a != NULL_TREE;
}
if (TREE_CODE (func) != FUNCTION_DECL)
return 0;
- a = lookup_attribute ("interrupt", DECL_MACHINE_ATTRIBUTES (func));
+ a = lookup_attribute ("interrupt", DECL_ATTRIBUTES (func));
return a != NULL_TREE;
}
if (TREE_CODE (func) != FUNCTION_DECL)
return 0;
- a = lookup_attribute ("signal", DECL_MACHINE_ATTRIBUTES (func));
+ a = lookup_attribute ("signal", DECL_ATTRIBUTES (func));
return a != NULL_TREE;
}
/* Output function prologue */
-void
-function_prologue (file, size)
+static void
+avr_output_function_prologue (file, size)
FILE *file;
- int size;
+ HOST_WIDE_INT size;
{
int reg;
int interrupt_func_p;
/* Output function epilogue */
-void
-function_epilogue (file, size)
+static void
+avr_output_function_epilogue (file, size)
FILE *file;
- int size;
+ HOST_WIDE_INT size;
{
int reg;
int interrupt_func_p;
rtx x;
int strict;
{
- int r = 0;
+ enum reg_class r = NO_REGS;
+
if (TARGET_ALL_DEBUG)
{
fprintf (stderr, "mode: (%s) %s %s %s %s:",
}
if (REG_P (x) && (strict ? REG_OK_FOR_BASE_STRICT_P (x)
: REG_OK_FOR_BASE_NOSTRICT_P (x)))
- r = 'R';
+ r = POINTER_REGS;
else if (CONSTANT_ADDRESS_P (x))
- r = 'S';
+ r = ALL_REGS;
else if (GET_CODE (x) == PLUS
&& REG_P (XEXP (x, 0))
&& GET_CODE (XEXP (x, 1)) == CONST_INT
if (! strict
|| REGNO (XEXP (x,0)) == REG_Y
|| REGNO (XEXP (x,0)) == REG_Z)
- r = 'Q';
+ r = BASE_POINTER_REGS;
if (XEXP (x,0) == frame_pointer_rtx
|| XEXP (x,0) == arg_pointer_rtx)
- r = 'Q';
+ r = BASE_POINTER_REGS;
}
else if (frame_pointer_needed && XEXP (x,0) == frame_pointer_rtx)
- r = 'U';
+ r = POINTER_Y_REGS;
}
else if ((GET_CODE (x) == PRE_DEC || GET_CODE (x) == POST_INC)
&& REG_P (XEXP (x, 0))
&& (strict ? REG_OK_FOR_BASE_STRICT_P (XEXP (x, 0))
: REG_OK_FOR_BASE_NOSTRICT_P (XEXP (x, 0))))
{
- r = 'T';
+ r = POINTER_REGS;
}
if (TARGET_ALL_DEBUG)
{
fprintf (stderr, " ret = %c\n", r);
}
- return r;
+ return r == NO_REGS ? 0 : (int)r;
}
/* Attempts to replace X with a valid
else if (code == 'o')
{
if (GET_CODE (addr) != PLUS)
- fatal_insn ("Bad address, not (reg+disp):", addr);
+ fatal_insn ("bad address, not (reg+disp):", addr);
print_operand (file, XEXP (addr, 1), 0);
}
{
print_operand_address (file, XEXP (addr,0));
if (REGNO (XEXP (addr, 0)) == REG_X)
- fatal_insn ("Internal compiler bug.\nBad address:"
+ fatal_insn ("internal compiler error. Bad address:"
,addr);
fputc ('+', file);
print_operand (file, XEXP (addr,1), code);
long val;
REAL_VALUE_TYPE rv;
if (GET_MODE (x) != SFmode)
- fatal_insn ("Internal compiler bug. Unknown mode:", x);
+ fatal_insn ("internal compiler error. Unknown mode:", x);
REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
REAL_VALUE_TO_TARGET_SINGLE (rv, val);
asm_fprintf (file, "0x%lx", val);
{
unsigned int max = (mode == QImode ? 0xff :
mode == HImode ? 0xffff :
- mode == SImode ? 0xffffffffU : 0);
+ mode == SImode ? 0xffffffff : 0);
if (max && operator && GET_CODE (x) == CONST_INT)
{
if (unsigned_condition (operator) != operator)
operands[1] = src;
return "";
}
- fatal_insn ("Invalid insn:", insn);
+ fatal_insn ("invalid insn:", insn);
return "";
}
{
int disp = INTVAL (XEXP (x,1));
if (REGNO (XEXP (x,0)) != REG_Y)
- fatal_insn ("Incorrect insn:",insn);
+ fatal_insn ("incorrect insn:",insn);
if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src)))
return *l = 3, (AS2 (adiw,r28,%o1-63) CR_TAB
if (disp > MAX_LD_OFFSET (GET_MODE (src)))
{
if (REGNO (XEXP (base, 0)) != REG_Y)
- fatal_insn ("Incorrect insn:",insn);
+ fatal_insn ("incorrect insn:",insn);
if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src)))
return *l = 4, (AS2 (adiw,r28,%o1-62) CR_TAB
else if (GET_CODE (base) == PRE_DEC) /* (--R) */
{
if (reg_overlap_mentioned_p (dest, XEXP (base, 0)))
- fatal_insn ("Incorrect insn:", insn);
+ fatal_insn ("incorrect insn:", insn);
*l = 2;
return (AS2 (ld,%B0,%1) CR_TAB
else if (GET_CODE (base) == POST_INC) /* (R++) */
{
if (reg_overlap_mentioned_p (dest, XEXP (base, 0)))
- fatal_insn ("Incorrect insn:", insn);
+ fatal_insn ("incorrect insn:", insn);
*l = 2;
return (AS2 (ld,%A0,%1) CR_TAB
AS2 (lds,%B0,%B1));
}
- fatal_insn ("Unknown move insn:",insn);
+ fatal_insn ("unknown move insn:",insn);
return "";
}
if (disp > MAX_LD_OFFSET (GET_MODE (src)))
{
if (REGNO (XEXP (base, 0)) != REG_Y)
- fatal_insn ("Incorrect insn:",insn);
+ fatal_insn ("incorrect insn:",insn);
if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src)))
return *l = 6, (AS2 (adiw,r28,%o1-60) CR_TAB
AS2 (lds,%C0,%C1) CR_TAB
AS2 (lds,%D0,%D1));
- fatal_insn ("Unknown move insn:",insn);
+ fatal_insn ("unknown move insn:",insn);
return "";
}
if (disp > MAX_LD_OFFSET (GET_MODE (dest)))
{
if (reg_base != REG_Y)
- fatal_insn ("Incorrect insn:",insn);
+ fatal_insn ("incorrect insn:",insn);
if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)))
return *l = 6, (AS2 (adiw,r28,%o0-60) CR_TAB
AS2 (st,%0,%B1) CR_TAB
AS2 (st,%0,%C1) CR_TAB
AS2 (st,%0,%D1));
- fatal_insn ("Unknown move insn:",insn);
+ fatal_insn ("unknown move insn:",insn);
return "";
}
if (GET_CODE (src) == CONST_INT)
{
- const char *clr_op0 =
+ const char *const clr_op0 =
AVR_ENHANCED ? (AS1 (clr,%A0) CR_TAB
AS1 (clr,%B0) CR_TAB
AS2 (movw,%C0,%A0))
operands[1] = src;
return "";
}
- fatal_insn ("Invalid insn:", insn);
+ fatal_insn ("invalid insn:", insn);
return "";
}
{
int disp = INTVAL (XEXP (x,1));
if (REGNO (XEXP (x,0)) != REG_Y)
- fatal_insn ("Incorrect insn:",insn);
+ fatal_insn ("incorrect insn:",insn);
if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)))
return *l = 3, (AS2 (adiw,r28,%o0-63) CR_TAB
if (disp > MAX_LD_OFFSET (GET_MODE (dest)))
{
if (reg_base != REG_Y)
- fatal_insn ("Incorrect insn:",insn);
+ fatal_insn ("incorrect insn:",insn);
if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)))
return *l = 4, (AS2 (adiw,r28,%o0-62) CR_TAB
else if (GET_CODE (base) == POST_INC) /* (R++) */
return *l=2, (AS2 (st,%0,%A1) CR_TAB
AS2 (st,%0,%B1));
- fatal_insn ("Unknown move insn:",insn);
+ fatal_insn ("unknown move insn:",insn);
return "";
}
}
}
else
- fatal_insn ("Bad shift insn:", insn);
+ fatal_insn ("bad shift insn:", insn);
if (second_label)
{
}
}
else if (CONSTANT_P (operands[2]))
- fatal_insn ("Internal compiler bug.\nIncorrect shift:", insn);
+ fatal_insn ("internal compiler error. Incorrect shift:", insn);
out_shift_with_cnt (AS1 (lsl,%0),
insn, operands, len, 1);
}
}
else if (CONSTANT_P (operands[2]))
- fatal_insn ("Internal compiler bug.\nIncorrect shift:", insn);
+ fatal_insn ("internal compiler error. Incorrect shift:", insn);
out_shift_with_cnt (AS1 (asr,%0),
insn, operands, len, 1);
}
}
else if (CONSTANT_P (operands[2]))
- fatal_insn ("Internal compiler bug.\nIncorrect shift:", insn);
+ fatal_insn ("internal compiler error. Incorrect shift:", insn);
out_shift_with_cnt (AS1 (lsr,%0),
insn, operands, len, 1);
if (GET_MODE (op[1]) == SImode)
len = (((mask & 0xff) != 0xff)
+ ((mask & 0xff00) != 0xff00)
- + ((mask & 0xff0000UL) != 0xff0000UL)
- + ((mask & 0xff000000UL) != 0xff000000UL));
+ + ((mask & 0xff0000L) != 0xff0000L)
+ + ((mask & 0xff000000L) != 0xff000000L));
else if (GET_MODE (op[1]) == HImode)
len = (((mask & 0xff) != 0xff)
+ ((mask & 0xff00) != 0xff00));
if (GET_MODE (op[1]) == SImode)
len = (((mask & 0xff) != 0)
+ ((mask & 0xff00) != 0)
- + ((mask & 0xff0000UL) != 0)
- + ((mask & 0xff000000UL) != 0));
+ + ((mask & 0xff0000L) != 0)
+ + ((mask & 0xff000000L) != 0));
else if (GET_MODE (op[1]) == HImode)
len = (((mask & 0xff) != 0)
+ ((mask & 0xff00) != 0));
return 1;
}
-/* Output rtx VALUE as .byte to file FILE */
-
-void
-asm_output_char (file, value)
- FILE *file;
- rtx value;
-{
- fprintf (file, "\t.byte ");
- output_addr_const (file, value);
- fprintf (file, "\n");
-}
-
+/* Target hook for assembling integer objects. The AVR version needs
+ special handling for references to certain labels. */
-/* Output VALUE as .byte to file FILE */
-
-void
-asm_output_byte (file, value)
- FILE *file;
- int value;
-{
- fprintf (file, "\t.byte 0x%x\n", value & 0xff);
-}
-
-
-/* Output rtx VALUE as .word to file FILE */
-
-void
-asm_output_short (file, value)
- FILE *file;
- rtx value;
+static bool
+avr_assemble_integer (x, size, aligned_p)
+ rtx x;
+ unsigned int size;
+ int aligned_p;
{
- if (SYMBOL_REF_FLAG (value) || GET_CODE (value) == LABEL_REF)
+ if (size == POINTER_SIZE / BITS_PER_UNIT && aligned_p
+ && ((GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FLAG (x))
+ || GET_CODE (x) == LABEL_REF))
{
- fprintf (file, "\t.word pm(");
- output_addr_const (file, (value));
- fprintf (file, ")\n");
- }
- else
- {
- fprintf (file, "\t.word ");
- output_addr_const (file, (value));
- fprintf (file, "\n");
+ fputs ("\t.word\tpm(", asm_out_file);
+ output_addr_const (asm_out_file, x);
+ fputs (")\n", asm_out_file);
+ return true;
}
+ return default_assemble_integer (x, size, aligned_p);
}
}
-/* Output section name to file FILE
- We make the section read-only and executable for a function decl,
- read-only for a const data decl, and writable for a non-const data decl. */
-
-void
-asm_output_section_name(file, decl, name, reloc)
- FILE *file;
- tree decl;
- const char *name;
- int reloc ATTRIBUTE_UNUSED;
-{
- fprintf (file, ".section %s, \"%s\", @progbits\n", name,
- decl && TREE_CODE (decl) == FUNCTION_DECL ? "ax" :
- decl && TREE_READONLY (decl) ? "a" : "aw");
-}
-
-
/* 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)
return (c != ALL_REGS && c != ADDW_REGS);
}
-/* Only `progmem' attribute valid for type. */
-
-int
-valid_machine_type_attribute(type, attributes, identifier, args)
- tree type ATTRIBUTE_UNUSED;
- tree attributes ATTRIBUTE_UNUSED;
- tree identifier;
- tree args ATTRIBUTE_UNUSED;
-{
- return is_attribute_p ("progmem", identifier);
-}
-
-/* If IDENTIFIER with arguments ARGS is a valid machine specific
- attribute for DECL return 1.
- Valid attributes:
+/* Valid attributes:
progmem - put data to program memory;
signal - make a function to be hardware interrupt. After function
prologue interrupts are disabled;
interrupt - make a function to be hardware interrupt. After function
prologue interrupts are enabled;
- naked - don't generate function prologue/epilogue and `ret' command. */
+ naked - don't generate function prologue/epilogue and `ret' command.
-int
-valid_machine_decl_attribute (decl, attributes, attr, args)
- tree decl;
- tree attributes ATTRIBUTE_UNUSED;
- tree attr;
- tree args ATTRIBUTE_UNUSED;
+ Only `progmem' attribute valid for type. */
+
+const struct attribute_spec avr_attribute_table[] =
{
- if (is_attribute_p ("interrupt", attr)
- || is_attribute_p ("signal", attr)
- || is_attribute_p ("naked", attr))
- return TREE_CODE (decl) == FUNCTION_DECL;
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ { "progmem", 0, 0, false, false, false, avr_handle_progmem_attribute },
+ { "signal", 0, 0, true, false, false, avr_handle_fndecl_attribute },
+ { "interrupt", 0, 0, true, false, false, avr_handle_fndecl_attribute },
+ { "naked", 0, 0, true, false, false, avr_handle_fndecl_attribute },
+ { NULL, 0, 0, false, false, false, NULL }
+};
- if (is_attribute_p ("progmem", attr)
- && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
+/* Handle a "progmem" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+avr_handle_progmem_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (DECL_P (*node))
{
- if (DECL_INITIAL (decl) == NULL_TREE && !DECL_EXTERNAL (decl))
+ if (TREE_STATIC (*node) || DECL_EXTERNAL (*node))
+ {
+ if (DECL_INITIAL (*node) == NULL_TREE && !DECL_EXTERNAL (*node))
+ {
+ warning ("only initialized variables can be placed into "
+ "program memory area");
+ *no_add_attrs = true;
+ }
+ }
+ else
{
- warning ("Only initialized variables can be placed into "
- "program memory area.");
- return 0;
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
}
- return 1;
}
- return 0;
+
+ return NULL_TREE;
}
+/* Handle an attribute requiring a FUNCTION_DECL; arguments as in
+ struct attribute_spec.handler. */
+static tree
+avr_handle_fndecl_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning ("`%s' attribute only applies to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
/* Look for attribute `progmem' in DECL
if found return 1, otherwise 0. */
return 0;
if (NULL_TREE
- != lookup_attribute ("progmem", DECL_MACHINE_ATTRIBUTES (decl)))
+ != lookup_attribute ("progmem", DECL_ATTRIBUTES (decl)))
return 1;
a=decl;
&& TREE_CODE (decl) == VAR_DECL
&& avr_progmem_p (decl))
{
- const char *dsec = ".progmem.data";
+ static const char *const dsec = ".progmem.data";
DECL_SECTION_NAME (decl) = build_string (strlen (dsec), dsec);
TREE_READONLY (decl) = 1;
}
order_regs_for_local_alloc ()
{
unsigned int i;
- int order_0[] = {
+ static const int order_0[] = {
24,25,
18,19,
20,21,
0,1,
32,33,34,35
};
- int order_1[] = {
+ static const int order_1[] = {
18,19,
20,21,
22,23,
0,1,
32,33,34,35
};
- int order_2[] = {
+ static const int order_2[] = {
25,24,
23,22,
21,20,
32,33,34,35
};
- int *order = (TARGET_ORDER_1 ? order_1 :
- TARGET_ORDER_2 ? order_2 :
- order_0);
+ const int *order = (TARGET_ORDER_1 ? order_1 :
+ TARGET_ORDER_2 ? order_2 :
+ order_0);
for (i=0; i < ARRAY_SIZE (order_0); ++i)
reg_alloc_order[i] = order[i];
}
unsigned HOST_WIDE_INT n=mask;
for (i = 0; i < 32; ++i)
{
- if (n & 0x80000000UL)
+ if (n & 0x80000000L)
{
- if (n & 0x7fffffffUL)
+ if (n & 0x7fffffffL)
return 0;
else
return 32-i;
*len = 4 + ((INTVAL (src) & 0xff) != 0)
+ ((INTVAL (src) & 0xff00) != 0)
+ ((INTVAL (src) & 0xff0000) != 0)
- + ((INTVAL (src) & 0xff000000U) != 0);
+ + ((INTVAL (src) & 0xff000000) != 0);
else
*len = 8;
output_asm_insn (AS2 (ldi, %2, hlo8(%1)), operands);
output_asm_insn (AS2 (mov, %C0, %2), operands);
}
- if (cnst && ((INTVAL (src) & 0xff000000U) == 0))
+ if (cnst && ((INTVAL (src) & 0xff000000) == 0))
output_asm_insn (AS2 (mov, %D0, __zero_reg__), operands);
else
{