/* Subroutines for insn-output.c for ATMEL AVR micro controllers
- Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
Contributed by Denis Chertykov (denisc@overta.ru)
This file is part of GNU CC.
#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 avr_num_arg_regs PARAMS ((enum machine_mode, tree));
static int out_adj_frame_ptr PARAMS ((FILE *, int));
static int out_set_stack_ptr PARAMS ((FILE *, int, int));
+static RTX_CODE compare_condition PARAMS ((rtx insn));
+static int compare_sign_p PARAMS ((rtx insn));
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 int avr_valid_type_attribute PARAMS ((tree, tree, tree, tree));
+static int avr_valid_decl_attribute PARAMS ((tree, tree, tree, tree));
+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
static int prologue_size;
static int epilogue_size;
+/* 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";
};
int avr_case_values_threshold = 30000;
-
+\f
+/* Initialize the GCC target structure. */
+#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_VALID_DECL_ATTRIBUTE
+#define TARGET_VALID_DECL_ATTRIBUTE avr_valid_decl_attribute
+
+#undef TARGET_VALID_TYPE_ATTRIBUTE
+#define TARGET_VALID_TYPE_ATTRIBUTE avr_valid_type_attribute
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+\f
void
avr_override_options ()
{
avr_mcu_name);
for (t = avr_mcu_types; t->name; t++)
fprintf (stderr," %s\n", t->name);
- fatal ("select right MCU name");
}
switch (t->arch)
{
- case AVR1:
- default:
- fatal ("MCU `%s' not supported", avr_mcu_name);
- case AVR2: avr_enhanced_p = 0; avr_mega_p = 0; break;
- case AVR3: avr_enhanced_p = 0; avr_mega_p = 1; break;
- case AVR4: avr_enhanced_p = 1; avr_mega_p = 0; break;
- case AVR5: avr_enhanced_p = 1; avr_mega_p = 1; break;
+ case AVR1:
+ default:
+ error ("MCU `%s' not supported", avr_mcu_name);
+ /* ... fall through ... */
+ case AVR2: avr_enhanced_p = 0; avr_mega_p = 0; break;
+ case AVR3: avr_enhanced_p = 0; avr_mega_p = 1; break;
+ case AVR4: avr_enhanced_p = 1; avr_mega_p = 0; break;
+ case AVR5: avr_enhanced_p = 1; avr_mega_p = 1; break;
}
if (optimize && !TARGET_NO_TABLEJUMP)
}
/* Set/restore the I flag now - interrupts will be really enabled only
- after the next instruction starts. This was not clearly documented.
- XXX - verify this on the new devices with enhanced AVR core. */
+ after the next instruction. This is not clearly documented, but
+ believed to be true for all AVR devices. */
if (do_save)
{
fprintf (file, AS2 (out, __SREG__, __tmp_reg__) CR_TAB);
/* 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;
&& !interrupt_func_p && !signal_func_p && live_seq);
last_insn_address = 0;
+ jump_tables_size = 0;
prologue_size = 0;
fprintf (file, "/* prologue: frame size=%d */\n", size);
/* 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;
main_p = MAIN_NAME_P (DECL_NAME (current_function_decl));
function_size = (INSN_ADDRESSES (INSN_UID (get_last_insn ()))
- INSN_ADDRESSES (INSN_UID (get_insns ())));
+ function_size += jump_tables_size;
live_seq = sequent_regs_live ();
minimize = (TARGET_CALL_PROLOGUES
&& !interrupt_func_p && !signal_func_p && live_seq);
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
case REG_Y: return "Y";
case REG_Z: return "Z";
default:
- fatal ("register r%d isn't a pointer\n", regno);
+ abort ();
}
return NULL;
}
return "pl";
else
return "ge";
- case GT:
- fatal ("Internal compiler bug: command `bgt'");
- case LE:
- fatal ("Internal compiler bug: command `ble'");
case LT:
if (cc_prev_status.flags & CC_OVERFLOW_UNUSABLE)
return "mi";
return "lt";
case GEU:
return "sh";
- case GTU:
- fatal ("Internal compiler bug: command `bgtu'");
- case LEU:
- fatal ("Internal compiler bug: command `bleu'");
case LTU:
return "lo";
default:
if (code >= 'A' && code <= 'D')
abcd = code - 'A';
- if (REG_P (x))
+ if (code == '~')
+ {
+ if (!AVR_MEGA)
+ fputc ('r', file);
+ }
+ else if (REG_P (x))
{
if (x == zero_reg_rtx)
- fprintf (file,"__zero_reg__");
+ fprintf (file, "__zero_reg__");
else
fprintf (file, reg_names[true_regnum (x) + abcd]);
}
output_address (addr);
fprintf (file, ")+%d", abcd);
}
+ else if (code == 'o')
+ {
+ if (GET_CODE (addr) != PLUS)
+ fatal_insn ("Bad address, not (reg+disp):", addr);
+
+ print_operand (file, XEXP (addr, 1), 0);
+ }
else if (GET_CODE (addr) == PLUS)
{
print_operand_address (file, XEXP (addr,0));
return 2;
}
-/* return a AVR condition jump commands.
- LEN is a number returned by avr_jump_mode function. */
+/* return an AVR condition jump commands.
+ X is a comparison RTX.
+ LEN is a number returned by avr_jump_mode function.
+ if REVERSE nonzero then condition code in X must be reversed. */
const char *
-ret_cond_branch (cond, len)
- RTX_CODE cond;
+ret_cond_branch (x, len, reverse)
+ rtx x;
int len;
+ int reverse;
{
+ RTX_CODE cond = reverse ? reverse_condition (GET_CODE (x)) : GET_CODE (x);
+
switch (cond)
{
case GT:
AS1 (brsh,_PC_+4) CR_TAB
AS1 (jmp,%0)));
default:
- switch (len)
- {
- case 1:
- return AS1 (br%j1,%0);
- case 2:
- return (AS1 (br%k1,_PC_+2) CR_TAB
- AS1 (rjmp,%0));
- default:
- return (AS1 (br%k1,_PC_+4) CR_TAB
- AS1 (jmp,%0));
- }
+ if (reverse)
+ {
+ switch (len)
+ {
+ case 1:
+ return AS1 (br%k1,%0);
+ case 2:
+ return (AS1 (br%j1,_PC_+2) CR_TAB
+ AS1 (rjmp,%0));
+ default:
+ return (AS1 (br%j1,_PC_+4) CR_TAB
+ AS1 (jmp,%0));
+ }
+ }
+ else
+ {
+ switch (len)
+ {
+ case 1:
+ return AS1 (br%j1,%0);
+ case 2:
+ return (AS1 (br%k1,_PC_+2) CR_TAB
+ AS1 (rjmp,%0));
+ default:
+ return (AS1 (br%k1,_PC_+4) CR_TAB
+ AS1 (jmp,%0));
+ }
+ }
}
return "";
}
int disp = INTVAL (XEXP (x,1));
if (REGNO (XEXP (x,0)) != REG_Y)
fatal_insn ("Incorrect insn:",insn);
+
if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src)))
- {
- *l = 3;
- op[4] = XEXP (x, 1);
- return (AS2 (adiw, r28, %4-63) CR_TAB
- AS2 (ldd, %0,Y+63) CR_TAB
- AS2 (sbiw, r28, %4-63));
- }
- else
- {
- *l = 5;
- op[4] = XEXP (x,1);
- return (AS2 (subi, r28, lo8(-%4)) CR_TAB
- AS2 (sbci, r29, hi8(-%4)) CR_TAB
- AS2 (ld, %0,Y) CR_TAB
- AS2 (subi, r28, lo8(%4)) CR_TAB
- AS2 (sbci, r29, hi8(%4)));
- }
+ return *l = 3, (AS2 (adiw,r28,%o1-63) CR_TAB
+ AS2 (ldd,%0,Y+63) CR_TAB
+ AS2 (sbiw,r28,%o1-63));
+
+ return *l = 5, (AS2 (subi,r28,lo8(-%o1)) CR_TAB
+ AS2 (sbci,r29,hi8(-%o1)) CR_TAB
+ AS2 (ld,%0,Y) CR_TAB
+ AS2 (subi,r28,lo8(%o1)) CR_TAB
+ AS2 (sbci,r29,hi8(%o1)));
}
else if (REGNO (XEXP (x,0)) == REG_X)
{
- op[4] = XEXP (x, 1);
/* This is a paranoid case LEGITIMIZE_RELOAD_ADDRESS must exclude
it but I have this situation with extremal optimizing options. */
if (reg_overlap_mentioned_p (dest, XEXP (x,0))
|| reg_unused_after (insn, XEXP (x,0)))
- {
- *l = 2;
- return (AS2 (adiw,r26,%4) CR_TAB
- AS2 (ld,%0,X));
- }
- *l = 3;
- return (AS2 (adiw,r26,%4) CR_TAB
- AS2 (ld,%0,X) CR_TAB
- AS2 (sbiw,r26,%4));
+ return *l = 2, (AS2 (adiw,r26,%o1) CR_TAB
+ AS2 (ld,%0,X));
+
+ return *l = 3, (AS2 (adiw,r26,%o1) CR_TAB
+ AS2 (ld,%0,X) CR_TAB
+ AS2 (sbiw,r26,%o1));
}
*l = 1;
return AS2 (ldd,%0,%1);
if (disp > MAX_LD_OFFSET (GET_MODE (src)))
{
- op[4] = XEXP (base, 1);
-
if (REGNO (XEXP (base, 0)) != REG_Y)
fatal_insn ("Incorrect insn:",insn);
if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src)))
- {
- *l = 4;
- return (AS2 (adiw,r28,%4-62) CR_TAB
- AS2 (ldd,%A0,Y+62) CR_TAB
- AS2 (ldd,%B0,Y+63) CR_TAB
- AS2 (sbiw,r28,%4-62));
- }
- else
- {
- *l = 6;
- return (AS2 (subi,r28,lo8(-%4)) CR_TAB
- AS2 (sbci,r29,hi8(-%4)) CR_TAB
- AS2 (ld,%A0,Y) CR_TAB
- AS2 (ldd,%B0,Y+1) CR_TAB
- AS2 (subi,r28,lo8(%4)) CR_TAB
- AS2 (sbci,r29,hi8(%4)));
- }
+ return *l = 4, (AS2 (adiw,r28,%o1-62) CR_TAB
+ AS2 (ldd,%A0,Y+62) CR_TAB
+ AS2 (ldd,%B0,Y+63) CR_TAB
+ AS2 (sbiw,r28,%o1-62));
+
+ return *l = 6, (AS2 (subi,r28,lo8(-%o1)) CR_TAB
+ AS2 (sbci,r29,hi8(-%o1)) CR_TAB
+ AS2 (ld,%A0,Y) CR_TAB
+ AS2 (ldd,%B0,Y+1) CR_TAB
+ AS2 (subi,r28,lo8(%o1)) CR_TAB
+ AS2 (sbci,r29,hi8(%o1)));
}
if (reg_base == REG_X)
{
it but I have this situation with extremal
optimization options. */
- op[4] = XEXP (base, 1);
-
- if (reg_base == reg_dest)
- {
- *l = 4;
- return (AS2 (adiw,r26,%4) CR_TAB
- AS2 (ld,__tmp_reg__,X+) CR_TAB
- AS2 (ld,%B0,X) CR_TAB
- AS2 (mov,%A0,__tmp_reg__));
- }
-
- if (INTVAL (op[4]) == 63)
- {
- *l = 5;
- return (AS2 (adiw,r26,%4) CR_TAB
- AS2 (ld,%A0,X+) CR_TAB
- AS2 (ld,%B0,X) CR_TAB
- AS2 (subi,r26,%4+1) CR_TAB
- AS2 (sbci,r27,0));
- }
*l = 4;
- return (AS2 (adiw,r26,%4) CR_TAB
- AS2 (ld,%A0,X+) CR_TAB
- AS2 (ld,%B0,X) CR_TAB
- AS2 (sbiw,r26,%4+1));
+ if (reg_base == reg_dest)
+ return (AS2 (adiw,r26,%o1) CR_TAB
+ AS2 (ld,__tmp_reg__,X+) CR_TAB
+ AS2 (ld,%B0,X) CR_TAB
+ AS2 (mov,%A0,__tmp_reg__));
+
+ return (AS2 (adiw,r26,%o1) CR_TAB
+ AS2 (ld,%A0,X+) CR_TAB
+ AS2 (ld,%B0,X) CR_TAB
+ AS2 (sbiw,r26,%o1+1));
}
if (reg_base == reg_dest)
if (reg_base == REG_X) /* (R26) */
{
if (reg_dest == REG_X)
- return *l=6, (AS2 (adiw,r26,3) CR_TAB
- AS2 (ld,%D0,X) CR_TAB
- AS2 (ld,%C0,-X) CR_TAB
- AS2 (ld,__tmp_reg__,-X) CR_TAB
- AS2 (ld,%A0,-X) CR_TAB
- AS2 (mov,%B0,__tmp_reg__));
+ /* "ld r26,-X" is undefined */
+ return *l=7, (AS2 (adiw,r26,3) CR_TAB
+ AS2 (ld,r29,X) CR_TAB
+ AS2 (ld,r28,-X) CR_TAB
+ AS2 (ld,__tmp_reg__,-X) CR_TAB
+ AS2 (sbiw,r26,1) CR_TAB
+ AS2 (ld,r26,X) CR_TAB
+ AS2 (mov,r27,__tmp_reg__));
else if (reg_dest == REG_X - 2)
return *l=5, (AS2 (ld,%A0,X+) CR_TAB
AS2 (ld,%B0,X+) CR_TAB
{
if (REGNO (XEXP (base, 0)) != REG_Y)
fatal_insn ("Incorrect insn:",insn);
+
if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src)))
- {
- op[4] = GEN_INT (disp - 60);
- return *l=6,(AS2 (adiw, r28, %4) CR_TAB
- AS2 (ldd, %A0,Y+60) CR_TAB
- AS2 (ldd, %B0,Y+61) CR_TAB
- AS2 (ldd, %C0,Y+62) CR_TAB
- AS2 (ldd, %D0,Y+63) CR_TAB
- AS2 (sbiw, r28, %4));
- }
- else
- {
- op[4] = XEXP (base, 1);
- return *l=8,(AS2 (subi, r28, lo8(-%4)) CR_TAB
- AS2 (sbci, r29, hi8(-%4)) CR_TAB
- AS2 (ld, %A0,Y) CR_TAB
- AS2 (ldd, %B0,Y+1) CR_TAB
- AS2 (ldd, %C0,Y+2) CR_TAB
- AS2 (ldd, %D0,Y+3) CR_TAB
- AS2 (subi, r28, lo8(%4)) CR_TAB
- AS2 (sbci, r29, hi8(%4)));
- }
+ return *l = 6, (AS2 (adiw,r28,%o1-60) CR_TAB
+ AS2 (ldd,%A0,Y+60) CR_TAB
+ AS2 (ldd,%B0,Y+61) CR_TAB
+ AS2 (ldd,%C0,Y+62) CR_TAB
+ AS2 (ldd,%D0,Y+63) CR_TAB
+ AS2 (sbiw,r28,%o1-60));
+
+ return *l = 8, (AS2 (subi,r28,lo8(-%o1)) CR_TAB
+ AS2 (sbci,r29,hi8(-%o1)) CR_TAB
+ AS2 (ld,%A0,Y) CR_TAB
+ AS2 (ldd,%B0,Y+1) CR_TAB
+ AS2 (ldd,%C0,Y+2) CR_TAB
+ AS2 (ldd,%D0,Y+3) CR_TAB
+ AS2 (subi,r28,lo8(%o1)) CR_TAB
+ AS2 (sbci,r29,hi8(%o1)));
}
reg_base = true_regnum (XEXP (base, 0));
+ if (reg_base == REG_X)
+ {
+ /* R = (X + d) */
+ if (reg_dest == REG_X)
+ {
+ *l = 7;
+ /* "ld r26,-X" is undefined */
+ return (AS2 (adiw,r26,%o1+3) CR_TAB
+ AS2 (ld,r29,X) CR_TAB
+ AS2 (ld,r28,-X) CR_TAB
+ AS2 (ld,__tmp_reg__,-X) CR_TAB
+ AS2 (sbiw,r26,1) CR_TAB
+ AS2 (ld,r26,X) CR_TAB
+ AS2 (mov,r27,__tmp_reg__));
+ }
+ *l = 6;
+ if (reg_dest == REG_X - 2)
+ return (AS2 (adiw,r26,%o1) CR_TAB
+ AS2 (ld,r24,X+) CR_TAB
+ AS2 (ld,r25,X+) CR_TAB
+ AS2 (ld,__tmp_reg__,X+) CR_TAB
+ AS2 (ld,r27,X) CR_TAB
+ AS2 (mov,r26,__tmp_reg__));
+
+ return (AS2 (adiw,r26,%o1) CR_TAB
+ AS2 (ld,%A0,X+) CR_TAB
+ AS2 (ld,%B0,X+) CR_TAB
+ AS2 (ld,%C0,X+) CR_TAB
+ AS2 (ld,%D0,X) CR_TAB
+ AS2 (sbiw,r26,%o1+3));
+ }
if (reg_dest == reg_base)
return *l=5, (AS2 (ldd,%D0,%D1) CR_TAB
AS2 (ldd,%C0,%C1) CR_TAB
{
if (reg_src == REG_X)
{
+ /* "st X+,r26" is undefined */
if (reg_unused_after (insn, base))
- return *l=5, (AS2 (mov,__tmp_reg__,%B1) CR_TAB
- AS2 (st,%0+,%A1) CR_TAB
- AS2 (st,%0+,__tmp_reg__) CR_TAB
- AS2 (st,%0+,%C1) CR_TAB
- AS2 (st,%0,%D1));
+ return *l=6, (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 (st,X+,r28) CR_TAB
+ AS2 (st,X,r29));
else
- return *l=6, (AS2 (mov,__tmp_reg__,%B1) CR_TAB
- AS2 (st,%0+,%A1) CR_TAB
- AS2 (st,%0+,__tmp_reg__) CR_TAB
- AS2 (st,%0+,%C1) CR_TAB
- AS2 (st,%0,%D1) CR_TAB
- AS2 (sbiw,r26,3));
+ return *l=7, (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 (st,X+,r28) CR_TAB
+ AS2 (st,X,r29) CR_TAB
+ AS2 (sbiw,r26,3));
}
else if (reg_base == reg_src + 2)
{
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 (REGNO (XEXP (base, 0)) != REG_Y)
+ if (reg_base != REG_Y)
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 (std,Y+60,%A1) CR_TAB
+ AS2 (std,Y+61,%B1) CR_TAB
+ AS2 (std,Y+62,%C1) CR_TAB
+ AS2 (std,Y+63,%D1) CR_TAB
+ AS2 (sbiw,r28,%o0-60));
+
+ return *l = 8, (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 (std,Y+2,%C1) CR_TAB
+ AS2 (std,Y+3,%D1) CR_TAB
+ AS2 (subi,r28,lo8(%o0)) CR_TAB
+ AS2 (sbci,r29,hi8(%o0)));
+ }
+ if (reg_base == REG_X)
+ {
+ /* (X + d) = R */
+ if (reg_src == REG_X)
{
- op[4] = GEN_INT (disp - 60);
- return *l=6,(AS2 (adiw, r28, %4) CR_TAB
- AS2 (std, Y+60,%A1) CR_TAB
- AS2 (std, Y+61,%B1) CR_TAB
- AS2 (std, Y+62,%C1) CR_TAB
- AS2 (std, Y+63,%D1) CR_TAB
- AS2 (sbiw, r28, %4));
+ *l = 9;
+ 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 (st,X+,__zero_reg__) CR_TAB
+ AS2 (st,X+,r28) CR_TAB
+ AS2 (st,X,r29) CR_TAB
+ AS1 (clr,__zero_reg__) CR_TAB
+ AS2 (sbiw,r26,%o0+3));
}
- else
+ else if (reg_src == REG_X - 2)
{
- op[4] = XEXP (base, 1);
- return *l=8,(AS2 (subi, r28, lo8(-%4)) CR_TAB
- AS2 (sbci, r29, hi8(-%4)) CR_TAB
- AS2 (st, Y,%A1) CR_TAB
- AS2 (std, Y+1,%B1) CR_TAB
- AS2 (std, Y+2,%C1) CR_TAB
- AS2 (std, Y+3,%D1) CR_TAB
- AS2 (subi, r28, lo8(%4)) CR_TAB
- AS2 (sbci, r29, hi8(%4)));
+ *l = 9;
+ return (AS2 (mov,__tmp_reg__,r26) CR_TAB
+ AS2 (mov,__zero_reg__,r27) CR_TAB
+ AS2 (adiw,r26,%o0) CR_TAB
+ AS2 (st,X+,r24) CR_TAB
+ AS2 (st,X+,r25) CR_TAB
+ AS2 (st,X+,__tmp_reg__) CR_TAB
+ AS2 (st,X,__zero_reg__) CR_TAB
+ AS1 (clr,__zero_reg__) CR_TAB
+ AS2 (sbiw,r26,%o0+3));
}
+ *l = 6;
+ return (AS2 (adiw,r26,%o0) CR_TAB
+ AS2 (st,X+,%A1) CR_TAB
+ AS2 (st,X+,%B1) CR_TAB
+ AS2 (st,X+,%C1) CR_TAB
+ AS2 (st,X,%D1) CR_TAB
+ AS2 (sbiw,r26,%o0+3));
}
return *l=4, (AS2 (std,%A0,%A1) CR_TAB
AS2 (std,%B0,%B1) CR_TAB
int disp = INTVAL (XEXP (x,1));
if (REGNO (XEXP (x,0)) != REG_Y)
fatal_insn ("Incorrect insn:",insn);
+
if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)))
- {
- *l = 3;
- op[4] = XEXP (x, 1);
- return (AS2 (adiw, r28, %4-63) CR_TAB
- AS2 (std, Y+63,%1) CR_TAB
- AS2 (sbiw, r28, %4-63));
- }
- else
- {
- *l = 5;
- op[4] = XEXP (x,1);
- return (AS2 (subi, r28, lo8(-%4)) CR_TAB
- AS2 (sbci, r29, hi8(-%4)) CR_TAB
- AS2 (st, Y,%1) CR_TAB
- AS2 (subi, r28, lo8(%4)) CR_TAB
- AS2 (sbci, r29, hi8(%4)));
- }
+ return *l = 3, (AS2 (adiw,r28,%o0-63) CR_TAB
+ AS2 (std,Y+63,%1) CR_TAB
+ AS2 (sbiw,r28,%o0-63));
+
+ return *l = 5, (AS2 (subi,r28,lo8(-%o0)) CR_TAB
+ AS2 (sbci,r29,hi8(-%o0)) CR_TAB
+ AS2 (st,Y,%1) CR_TAB
+ AS2 (subi,r28,lo8(%o0)) CR_TAB
+ AS2 (sbci,r29,hi8(%o0)));
}
else if (REGNO (XEXP (x,0)) == REG_X)
{
- op[4] = XEXP (x,1);
if (reg_overlap_mentioned_p (src, XEXP (x, 0)))
{
if (reg_unused_after (insn, XEXP (x,0)))
- {
- *l = 3;
- return (AS2 (mov,__tmp_reg__,%1) CR_TAB
- AS2 (adiw,r26,%4) CR_TAB
- AS2 (st,X,__tmp_reg__));
- }
- *l = 4;
- return (AS2 (mov,__tmp_reg__,%1) CR_TAB
- AS2 (adiw,r26,%4) CR_TAB
- AS2 (st,X,__tmp_reg__) CR_TAB
- AS2 (sbiw,r26,%4));
+ return *l = 3, (AS2 (mov,__tmp_reg__,%1) CR_TAB
+ AS2 (adiw,r26,%o0) CR_TAB
+ AS2 (st,X,__tmp_reg__));
+
+ return *l = 4, (AS2 (mov,__tmp_reg__,%1) CR_TAB
+ AS2 (adiw,r26,%o0) CR_TAB
+ AS2 (st,X,__tmp_reg__) CR_TAB
+ AS2 (sbiw,r26,%o0));
}
else
{
if (reg_unused_after (insn, XEXP (x,0)))
- {
- *l = 2;
- return (AS2 (adiw,r26,%4) CR_TAB
- AS2 (st,X,%1));
- }
- *l = 3;
- return (AS2 (adiw,r26,%4) CR_TAB
- AS2 (st,X,%1) CR_TAB
- AS2 (sbiw,r26,%4));
+ return *l = 2, (AS2 (adiw,r26,%o0) CR_TAB
+ AS2 (st,X,%1));
+
+ return *l = 3, (AS2 (adiw,r26,%o0) CR_TAB
+ AS2 (st,X,%1) CR_TAB
+ AS2 (sbiw,r26,%o0));
}
}
*l = 1;
{
if (reg_src == REG_X)
{
+ /* "st X+,r26" is undefined */
if (reg_unused_after (insn, src))
- return *l=3, (AS2 (mov,__tmp_reg__,r27) CR_TAB
- AS2 (st ,X+,r26) CR_TAB
- AS2 (st ,X,__tmp_reg__));
+ 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=4, (AS2 (mov,__tmp_reg__,r27) CR_TAB
- AS2 (st ,X+,r26) CR_TAB
- AS2 (st ,X,__tmp_reg__) CR_TAB
- AS2 (sbiw,r26,1));
+ 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));
}
else
{
else if (GET_CODE (base) == PLUS)
{
int disp = INTVAL (XEXP (base, 1));
+ reg_base = REGNO (XEXP (base, 0));
if (disp > MAX_LD_OFFSET (GET_MODE (dest)))
{
- if (REGNO (XEXP (base, 0)) != REG_Y)
+ if (reg_base != REG_Y)
fatal_insn ("Incorrect insn:",insn);
+
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 (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 (subi,r28,lo8(%o0)) CR_TAB
+ AS2 (sbci,r29,hi8(%o0)));
+ }
+ if (reg_base == REG_X)
+ {
+ /* (X + d) = R */
+ if (reg_src == REG_X)
{
- op[4] = GEN_INT (disp - 62);
- return *l=4,(AS2 (adiw, r28, %4) CR_TAB
- AS2 (std, Y+62,%A1) CR_TAB
- AS2 (std, Y+63,%B1) CR_TAB
- AS2 (sbiw, r28, %4));
- }
- else
- {
- op[4] = XEXP (base, 1);
- return *l=6,(AS2 (subi, r28, lo8(-%4)) CR_TAB
- AS2 (sbci, r29, hi8(-%4)) CR_TAB
- AS2 (st, Y,%A1) CR_TAB
- AS2 (std, Y+1,%B1) CR_TAB
- AS2 (subi, r28, lo8(%4)) CR_TAB
- AS2 (sbci, r29, hi8(%4)));
+ *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 (st,X,__zero_reg__) CR_TAB
+ AS1 (clr,__zero_reg__) CR_TAB
+ AS2 (sbiw,r26,%o0+1));
}
+ *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 *l=2, (AS2 (std,%A0,%A1) CR_TAB
AS2 (std,%B0,%B1));
|| get_frame_size () > 0);
}
-/* Return 1 if the next insn is a JUMP_INSN with condition (GT,LE,GTU,LTU) */
+/* Returns the condition of compare insn INSN, or UNKNOWN. */
-int
-compare_diff_p (insn)
+static RTX_CODE
+compare_condition (insn)
rtx insn;
{
rtx next = next_real_insn (insn);
RTX_CODE cond = UNKNOWN;
- if (GET_CODE (next) == JUMP_INSN)
+ if (next && GET_CODE (next) == JUMP_INSN)
{
rtx pat = PATTERN (next);
rtx src = SET_SRC (pat);
- rtx t = XEXP (src,0);
+ rtx t = XEXP (src, 0);
cond = GET_CODE (t);
}
+ return cond;
+}
+
+/* Returns nonzero if INSN is a tst insn that only tests the sign. */
+
+static int
+compare_sign_p (insn)
+ rtx insn;
+{
+ RTX_CODE cond = compare_condition (insn);
+ return (cond == GE || cond == LT);
+}
+
+/* Returns nonzero if the next insn is a JUMP_INSN with a condition
+ that needs to be swapped (GT, GTU, LE, LEU). */
+
+int
+compare_diff_p (insn)
+ rtx insn;
+{
+ RTX_CODE cond = compare_condition (insn);
return (cond == GT || cond == GTU || cond == LE || cond == LEU) ? cond : 0;
}
-/* Returns nonzero if INSN is a compare insn with the EQ or NE condition */
+/* Returns nonzero if INSN is a compare insn with the EQ or NE condition. */
int
compare_eq_p (insn)
rtx insn;
{
- rtx next = next_real_insn (insn);
- RTX_CODE cond = UNKNOWN;
- if (GET_CODE (next) == JUMP_INSN)
- {
- rtx pat = PATTERN (next);
- rtx src = SET_SRC (pat);
- rtx t = XEXP (src,0);
- cond = GET_CODE (t);
- }
+ RTX_CODE cond = compare_condition (insn);
return (cond == EQ || cond == NE);
}
rtx insn;
int *l;
{
- if (!compare_eq_p (insn))
+ if (compare_sign_p (insn))
{
if (l) *l = 1;
return AS1 (tst,%B0);
}
- if (reg_unused_after (insn, SET_SRC (PATTERN (insn))))
+ if (reg_unused_after (insn, SET_SRC (PATTERN (insn)))
+ && compare_eq_p (insn))
{
/* faster than sbiw if we can clobber the operand */
if (l) *l = 1;
rtx insn;
int *l;
{
- if (!compare_eq_p (insn))
+ if (compare_sign_p (insn))
{
if (l) *l = 1;
return AS1 (tst,%D0);
prefix = ".text";
}
else
- fatal ("Strange situation: unique section is not a FUNCTION_DECL");
+ abort ();
if (flag_function_sections)
{
}
-/* 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)
/* Only `progmem' attribute valid for type. */
-int
-valid_machine_type_attribute(type, attributes, identifier, args)
+static int
+avr_valid_type_attribute (type, attributes, identifier, args)
tree type ATTRIBUTE_UNUSED;
tree attributes ATTRIBUTE_UNUSED;
tree identifier;
prologue interrupts are enabled;
naked - don't generate function prologue/epilogue and `ret' command. */
-int
-valid_machine_decl_attribute (decl, attributes, attr, args)
+static int
+avr_valid_decl_attribute (decl, attributes, attr, args)
tree decl;
tree attributes ATTRIBUTE_UNUSED;
tree attr;
a = TREE_TYPE(a);
while (TREE_CODE (a) == ARRAY_TYPE);
+ if (a == error_mark_node)
+ return 0;
+
if (NULL_TREE != lookup_attribute ("progmem", TYPE_ATTRIBUTES (a)))
return 1;
{
if (TREE_CODE (decl) == FUNCTION_DECL)
SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
-
- if ((TREE_STATIC (decl) || DECL_EXTERNAL (decl))
- && TREE_CODE (decl) == VAR_DECL
- && avr_progmem_p (decl))
+ else if ((TREE_STATIC (decl) || DECL_EXTERNAL (decl))
+ && TREE_CODE (decl) == VAR_DECL
+ && avr_progmem_p (decl))
{
const char *dsec = ".progmem.data";
DECL_SECTION_NAME (decl) = build_string (strlen (dsec), dsec);
case LEU:
return LTU;
default:
- fatal ("Wrong condition: %s", GET_RTX_NAME (condition));
+ abort ();
}
}
rtx first_insn;
{
rtx insn, pattern;
- CC_STATUS_INIT;
for (insn = first_insn; insn; insn = NEXT_INSN (insn))
{
- if (! (insn == 0 || GET_CODE (insn) == INSN
- || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
+ if (! (GET_CODE (insn) == INSN
+ || GET_CODE (insn) == CALL_INSN
+ || GET_CODE (insn) == JUMP_INSN)
|| !single_set (insn))
continue;
pattern = PATTERN (insn);
- cc_prev_status = cc_status;
- NOTICE_UPDATE_CC (pattern, insn);
-
if (GET_CODE (pattern) == PARALLEL)
pattern = XVECEXP (pattern, 0, 0);
if (GET_CODE (pattern) == SET
rtx src = SET_SRC (pat);
rtx t = XEXP (src,0);
- if (!(cc_prev_status.value1 != 0 && cc_status.value1 != 0
- && rtx_equal_p (cc_status.value1, cc_prev_status.value1)))
- {
- PUT_CODE (t, swap_condition (GET_CODE (t)));
- SET_SRC (pattern) = gen_rtx (NEG,
- GET_MODE (SET_SRC (pattern)),
- SET_SRC (pattern));
- INSN_CODE (next) = -1;
- INSN_CODE (insn) = -1;
- }
+ PUT_CODE (t, swap_condition (GET_CODE (t)));
+ SET_SRC (pattern) = gen_rtx (NEG,
+ GET_MODE (SET_SRC (pattern)),
+ SET_SRC (pattern));
+ INSN_CODE (next) = -1;
+ INSN_CODE (insn) = -1;
}
}
}
tree func ATTRIBUTE_UNUSED;
{
unsigned int offs;
+
if (TYPE_MODE (type) != BLKmode)
return avr_libcall_value (TYPE_MODE (type));
output_asm_insn (s, operands);
}
+void
+avr_output_addr_vec_elt (stream, value)
+ FILE *stream;
+ int value;
+{
+ if (AVR_MEGA)
+ fprintf (stream, "\t.word pm(.L%d)\n", value);
+ else
+ fprintf (stream, "\trjmp .L%d\n", value);
+
+ jump_tables_size++;
+}
+
+/* Returns 1 if SCRATCH are safe to be allocated as a scratch
+ registers (for a define_peephole2) in the current function. */
+
+int
+avr_peep2_scratch_safe (scratch)
+ rtx scratch;
+{
+ if ((interrupt_function_p (current_function_decl)
+ || signal_function_p (current_function_decl))
+ && leaf_function_p ())
+ {
+ int first_reg = true_regnum (scratch);
+ int last_reg = first_reg + GET_MODE_SIZE (GET_MODE (scratch)) - 1;
+ int reg;
+
+ for (reg = first_reg; reg <= last_reg; reg++)
+ {
+ if (!regs_ever_live[reg])
+ return 0;
+ }
+ }
+ return 1;
+}