#include "config.h"
#include "system.h"
#include "rtl.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "real.h"
#include "insn-config.h"
#include "conditions.h"
#include "output.h"
#include "insn-attr.h"
#include "flags.h"
#include "reload.h"
#include "tree.h"
#include "expr.h"
#include "toplev.h"
#include "obstack.h"
#include "function.h"
#include "recog.h"
#include "tm_p.h"
#include "target.h"
#include "target-def.h"
#define MAX_LD_OFFSET(MODE) (64 - (signed)GET_MODE_SIZE (MODE))
static int avr_naked_function_p PARAMS ((tree));
static int interrupt_function_p PARAMS ((tree));
static int signal_function_p PARAMS ((tree));
static int sequent_regs_live PARAMS ((void));
static const char * ptrreg_to_str PARAMS ((int));
static const char * cond_string PARAMS ((enum rtx_code));
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 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));
#define FIRST_CUM_REG 26
rtx tmp_reg_rtx;
rtx zero_reg_rtx;
rtx ldi_reg_rtx;
static const char *const avr_regnames[] = REGISTER_NAMES;
static int last_insn_address = 0;
static int commands_in_file;
static int commands_in_prologues;
static int commands_in_epilogues;
static int prologue_size;
static int epilogue_size;
static int jump_tables_size;
const char *avr_init_stack = "__stack";
const char *avr_mcu_name = "avr2";
int avr_mega_p = 0;
int avr_enhanced_p = 0;
enum avr_arch {
AVR1 = 1,
AVR2,
AVR3,
AVR4,
AVR5
};
struct mcu_type_s {
const char *const name;
const enum avr_arch arch;
};
static const struct mcu_type_s avr_mcu_types[] = {
{ "avr2", AVR2 },
{ "at90s2313", AVR2 },
{ "at90s2323", AVR2 },
{ "attiny22", AVR2 },
{ "at90s2333", AVR2 },
{ "at90s2343", AVR2 },
{ "at90s4414", AVR2 },
{ "at90s4433", AVR2 },
{ "at90s4434", AVR2 },
{ "at90s8515", AVR2 },
{ "at90c8534", AVR2 },
{ "at90s8535", AVR2 },
{ "avr3", AVR3 },
{ "atmega103", AVR3 },
{ "atmega603", AVR3 },
{ "at43usb320", AVR3 },
{ "at76c711", AVR3 },
{ "avr4", AVR4 },
{ "atmega8", AVR4 },
{ "atmega83", AVR4 },
{ "atmega85", AVR4 },
{ "avr5", AVR5 },
{ "atmega16", AVR5 },
{ "atmega161", AVR5 },
{ "atmega163", AVR5 },
{ "atmega32", AVR5 },
{ "atmega323", AVR5 },
{ "atmega64", AVR5 },
{ "atmega128", AVR5 },
{ "at43usb355", AVR5 },
{ "at94k", AVR5 },
{ "avr1", AVR1 },
{ "at90s1200", AVR1 },
{ "attiny10", AVR1 },
{ "attiny11", AVR1 },
{ "attiny12", AVR1 },
{ "attiny15", AVR1 },
{ "attiny28", AVR1 },
{ NULL, 0 }
};
int avr_case_values_threshold = 30000;
#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;
void
avr_override_options ()
{
const struct mcu_type_s *t;
for (t = avr_mcu_types; t->name; t++)
if (strcmp (t->name, avr_mcu_name) == 0)
break;
if (!t->name)
{
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);
}
switch (t->arch)
{
case AVR1:
default:
error ("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;
}
if (optimize && !TARGET_NO_TABLEJUMP)
avr_case_values_threshold = (!AVR_MEGA || TARGET_CALL_PROLOGUES) ? 8 : 17;
}
void
avr_init_once ()
{
tmp_reg_rtx = xmalloc (sizeof (struct rtx_def) + 1 * sizeof (rtunion));
memset (tmp_reg_rtx, 0, sizeof (struct rtx_def) + 1 * sizeof (rtunion));
PUT_CODE (tmp_reg_rtx, REG);
PUT_MODE (tmp_reg_rtx, QImode);
XINT (tmp_reg_rtx, 0) = TMP_REGNO;
zero_reg_rtx = xmalloc (sizeof (struct rtx_def) + 1 * sizeof (rtunion));
memset (zero_reg_rtx, 0, sizeof (struct rtx_def) + 1 * sizeof (rtunion));
PUT_CODE (zero_reg_rtx, REG);
PUT_MODE (zero_reg_rtx, QImode);
XINT (zero_reg_rtx, 0) = ZERO_REGNO;
ldi_reg_rtx = xmalloc (sizeof (struct rtx_def) + 1 * sizeof (rtunion));
memset (ldi_reg_rtx, 0, sizeof (struct rtx_def) + 1 * sizeof (rtunion));
PUT_CODE (ldi_reg_rtx, REG);
PUT_MODE (ldi_reg_rtx, QImode);
XINT (ldi_reg_rtx, 0) = LDI_REG_REGNO;
}
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,
GENERAL_REGS,
LD_REGS,LD_REGS,LD_REGS,LD_REGS,LD_REGS,LD_REGS,LD_REGS,
LD_REGS,
ADDW_REGS,ADDW_REGS,
POINTER_X_REGS,POINTER_X_REGS,
POINTER_Y_REGS,POINTER_Y_REGS,
POINTER_Z_REGS,POINTER_Z_REGS,
STACK_REG,STACK_REG
};
enum reg_class
avr_regno_reg_class (r)
int r;
{
if (r <= 33)
return reg_class_tab[r];
return ALL_REGS;
}
enum reg_class
avr_reg_class_from_letter (c)
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;
}
static int
avr_naked_function_p (func)
tree func;
{
tree a;
if (TREE_CODE (func) != FUNCTION_DECL)
abort ();
a = lookup_attribute ("naked", DECL_ATTRIBUTES (func));
return a != NULL_TREE;
}
static int
interrupt_function_p (func)
tree func;
{
tree a;
if (TREE_CODE (func) != FUNCTION_DECL)
return 0;
a = lookup_attribute ("interrupt", DECL_ATTRIBUTES (func));
return a != NULL_TREE;
}
static int
signal_function_p (func)
tree func;
{
tree a;
if (TREE_CODE (func) != FUNCTION_DECL)
return 0;
a = lookup_attribute ("signal", DECL_ATTRIBUTES (func));
return a != NULL_TREE;
}
int
initial_elimination_offset (from, to)
int from;
int to;
{
int reg;
if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
return 0;
else
{
int interrupt_func_p = interrupt_function_p (current_function_decl);
int signal_func_p = signal_function_p (current_function_decl);
int leaf_func_p = leaf_function_p ();
int offset= frame_pointer_needed ? 2 : 0;
for (reg = 0; reg < 32; ++reg)
{
if ((!leaf_func_p && (call_used_regs[reg]
&& (interrupt_func_p || signal_func_p)))
|| (regs_ever_live[reg]
&& (!call_used_regs[reg] || interrupt_func_p || signal_func_p)
&& ! (frame_pointer_needed
&& (reg == REG_Y || reg == (REG_Y+1)))))
{
++offset;
}
}
return get_frame_size () + 2 + 1 + offset;
}
return 0;
}
static int
sequent_regs_live ()
{
int reg;
int live_seq=0;
int cur_seq=0;
for (reg = 0; reg < 18; ++reg)
{
if (!call_used_regs[reg])
{
if (regs_ever_live[reg])
{
++live_seq;
++cur_seq;
}
else
cur_seq = 0;
}
}
if (!frame_pointer_needed)
{
if (regs_ever_live[REG_Y])
{
++live_seq;
++cur_seq;
}
else
cur_seq = 0;
if (regs_ever_live[REG_Y+1])
{
++live_seq;
++cur_seq;
}
else
cur_seq = 0;
}
else
{
cur_seq += 2;
live_seq += 2;
}
return (cur_seq == live_seq) ? live_seq : 0;
}
static int
out_adj_frame_ptr (file, adj)
FILE *file;
int adj;
{
int size = 0;
if (adj)
{
if (TARGET_TINY_STACK)
{
if (adj < -63 || adj > 63)
warning ("large frame pointer change (%d) with -mtiny-stack", adj);
fprintf (file, (AS2 (subi, r28, %d) CR_TAB), adj);
size++;
}
else if (adj < -63 || adj > 63)
{
fprintf (file, (AS2 (subi, r28, lo8(%d)) CR_TAB
AS2 (sbci, r29, hi8(%d)) CR_TAB),
adj, adj);
size += 2;
}
else if (adj < 0)
{
fprintf (file, (AS2 (adiw, r28, %d) CR_TAB), -adj);
size++;
}
else
{
fprintf (file, (AS2 (sbiw, r28, %d) CR_TAB), adj);
size++;
}
}
return size;
}
static int
out_set_stack_ptr (file, before, after)
FILE *file;
int before;
int after;
{
int do_sph, do_cli, do_save, do_sei, lock_sph, size;
do_sph = !TARGET_TINY_STACK;
lock_sph = do_sph && !TARGET_NO_INTERRUPTS;
do_cli = (before != 0 && (after == 0 || lock_sph));
do_save = (do_cli && before == -1 && after == -1);
do_sei = ((do_cli || before != 1) && after == 1);
size = 1;
if (do_save)
{
fprintf (file, AS2 (in, __tmp_reg__, __SREG__) CR_TAB);
size++;
}
if (do_cli)
{
fprintf (file, "cli" CR_TAB);
size++;
}
if (do_sph)
{
fprintf (file, AS2 (out, __SP_H__, r29) CR_TAB);
size++;
}
if (do_save)
{
fprintf (file, AS2 (out, __SREG__, __tmp_reg__) CR_TAB);
size++;
}
else if (do_sei)
{
fprintf (file, "sei" CR_TAB);
size++;
}
fprintf (file, AS2 (out, __SP_L__, r28) "\n");
return size;
}
static void
avr_output_function_prologue (file, size)
FILE *file;
HOST_WIDE_INT size;
{
int reg;
int interrupt_func_p;
int signal_func_p;
int leaf_func_p;
int main_p;
int live_seq;
int minimize;
if (avr_naked_function_p (current_function_decl))
{
fprintf (file, "/* prologue: naked */\n");
return;
}
interrupt_func_p = interrupt_function_p (current_function_decl);
signal_func_p = signal_function_p (current_function_decl);
leaf_func_p = leaf_function_p ();
main_p = MAIN_NAME_P (DECL_NAME (current_function_decl));
live_seq = sequent_regs_live ();
minimize = (TARGET_CALL_PROLOGUES
&& !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);
if (interrupt_func_p)
{
fprintf (file,"\tsei\n");
++prologue_size;
}
if (interrupt_func_p | signal_func_p)
{
fprintf (file, "\t"
AS1 (push,__zero_reg__) CR_TAB
AS1 (push,__tmp_reg__) CR_TAB
AS2 (in,__tmp_reg__,__SREG__) CR_TAB
AS1 (push,__tmp_reg__) CR_TAB
AS1 (clr,__zero_reg__) "\n");
prologue_size += 5;
}
if (main_p)
{
fprintf (file, ("\t"
AS2 (ldi,r28,lo8(%s - %d)) CR_TAB
AS2 (ldi,r29,hi8(%s - %d)) CR_TAB
AS2 (out,__SP_H__,r29) CR_TAB
AS2 (out,__SP_L__,r28) "\n"),
avr_init_stack, size, avr_init_stack, size);
prologue_size += 4;
}
else if (minimize && (frame_pointer_needed || live_seq > 6))
{
fprintf (file, ("\t"
AS2 (ldi, r26, lo8(%d)) CR_TAB
AS2 (ldi, r27, hi8(%d)) 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)
,current_function_name, current_function_name);
prologue_size += 4;
if (AVR_MEGA)
{
fprintf (file, AS1 (jmp,__prologue_saves__+%d) "\n",
(18 - live_seq) * 2);
prologue_size += 2;
}
else
{
fprintf (file, AS1 (rjmp,__prologue_saves__+%d) "\n",
(18 - live_seq) * 2);
++prologue_size;
}
fprintf (file, ".L_%s_body:\n", current_function_name);
}
else
{
for (reg = 0; reg < 32; ++reg)
{
if ((!leaf_func_p
&& (call_used_regs[reg]
&& (interrupt_func_p || signal_func_p)
&& !(reg == TMP_REGNO || reg == ZERO_REGNO)))
|| (regs_ever_live[reg]
&& (!call_used_regs[reg]
|| interrupt_func_p || signal_func_p)
&& ! (frame_pointer_needed
&& (reg == REG_Y || reg == (REG_Y+1)))))
{
fprintf (file, "\t" AS1 (push,%s) "\n", avr_regnames[reg]);
++prologue_size;
}
}
if (frame_pointer_needed)
{
{
fprintf (file, "\t"
AS1 (push,r28) CR_TAB
AS1 (push,r29) CR_TAB
AS2 (in,r28,__SP_L__) CR_TAB
AS2 (in,r29,__SP_H__) "\n");
prologue_size += 4;
if (size)
{
fputs ("\t", file);
prologue_size += out_adj_frame_ptr (file, size);
if (interrupt_func_p)
{
prologue_size += out_set_stack_ptr (file, 1, 1);
}
else if (signal_func_p)
{
prologue_size += out_set_stack_ptr (file, 0, 0);
}
else
{
prologue_size += out_set_stack_ptr (file, -1, -1);
}
}
}
}
}
fprintf (file, "/* prologue end (size=%d) */\n", prologue_size);
}
static void
avr_output_function_epilogue (file, size)
FILE *file;
HOST_WIDE_INT size;
{
int reg;
int interrupt_func_p;
int signal_func_p;
int leaf_func_p;
int main_p;
int function_size;
int live_seq;
int minimize;
if (avr_naked_function_p (current_function_decl))
{
fprintf (file, "/* epilogue: naked */\n");
return;
}
interrupt_func_p = interrupt_function_p (current_function_decl);
signal_func_p = signal_function_p (current_function_decl);
leaf_func_p = leaf_function_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);
epilogue_size = 0;
fprintf (file, "/* epilogue: frame size=%d */\n", size);
if (main_p)
{
fprintf (file, "__stop_progIi__:\n\trjmp __stop_progIi__\n");
++epilogue_size;
}
else if (minimize && (frame_pointer_needed || live_seq > 4))
{
fprintf (file, ("\t" AS2 (ldi, r30, %d) CR_TAB), live_seq);
++epilogue_size;
if (frame_pointer_needed)
{
epilogue_size += out_adj_frame_ptr (file, -size);
}
else
{
fprintf (file, (AS2 (in , r28, __SP_L__) CR_TAB
AS2 (in , r29, __SP_H__) CR_TAB));
epilogue_size += 2;
}
if (AVR_MEGA)
{
fprintf (file, AS1 (jmp,__epilogue_restores__+%d) "\n",
(18 - live_seq) * 2);
epilogue_size += 2;
}
else
{
fprintf (file, AS1 (rjmp,__epilogue_restores__+%d) "\n",
(18 - live_seq) * 2);
++epilogue_size;
}
}
else
{
if (frame_pointer_needed)
{
if (size)
{
fputs ("\t", file);
epilogue_size += out_adj_frame_ptr (file, -size);
if (interrupt_func_p | signal_func_p)
{
epilogue_size += out_set_stack_ptr (file, -1, 0);
}
else
{
epilogue_size += out_set_stack_ptr (file, -1, -1);
}
}
fprintf (file, "\t"
AS1 (pop,r29) CR_TAB
AS1 (pop,r28) "\n");
epilogue_size += 2;
}
for (reg = 31; reg >= 0; --reg)
{
if ((!leaf_func_p
&& (call_used_regs[reg]
&& (interrupt_func_p || signal_func_p)
&& !(reg == TMP_REGNO || reg == ZERO_REGNO)))
|| (regs_ever_live[reg]
&& (!call_used_regs[reg]
|| interrupt_func_p || signal_func_p)
&& ! (frame_pointer_needed
&& (reg == REG_Y || reg == (REG_Y+1)))))
{
fprintf (file, "\t" AS1 (pop,%s) "\n", avr_regnames[reg]);
++epilogue_size;
}
}
if (interrupt_func_p | signal_func_p)
{
fprintf (file, "\t"
AS1 (pop,__tmp_reg__) CR_TAB
AS2 (out,__SREG__,__tmp_reg__) CR_TAB
AS1 (pop,__tmp_reg__) CR_TAB
AS1 (pop,__zero_reg__) "\n");
epilogue_size += 4;
fprintf (file, "\treti\n");
}
else
fprintf (file, "\tret\n");
++epilogue_size;
}
fprintf (file, "/* epilogue end (size=%d) */\n", epilogue_size);
fprintf (file, "/* function %s size %d (%d) */\n", current_function_name,
prologue_size + function_size + epilogue_size, function_size);
commands_in_file += prologue_size + function_size + epilogue_size;
commands_in_prologues += prologue_size;
commands_in_epilogues += epilogue_size;
}
int
legitimate_address_p (mode, x, strict)
enum machine_mode mode;
rtx x;
int strict;
{
enum reg_class r = NO_REGS;
if (TARGET_ALL_DEBUG)
{
fprintf (stderr, "mode: (%s) %s %s %s %s:",
GET_MODE_NAME(mode),
strict ? "(strict)": "",
reload_completed ? "(reload_completed)": "",
reload_in_progress ? "(reload_in_progress)": "",
reg_renumber ? "(reg_renumber)" : "");
if (GET_CODE (x) == PLUS
&& REG_P (XEXP (x, 0))
&& GET_CODE (XEXP (x, 1)) == CONST_INT
&& INTVAL (XEXP (x, 1)) >= 0
&& INTVAL (XEXP (x, 1)) <= MAX_LD_OFFSET (mode)
&& reg_renumber
)
fprintf (stderr, "(r%d ---> r%d)", REGNO (XEXP (x, 0)),
true_regnum (XEXP (x, 0)));
debug_rtx (x);
}
if (REG_P (x) && (strict ? REG_OK_FOR_BASE_STRICT_P (x)
: REG_OK_FOR_BASE_NOSTRICT_P (x)))
r = POINTER_REGS;
else if (CONSTANT_ADDRESS_P (x))
r = ALL_REGS;
else if (GET_CODE (x) == PLUS
&& REG_P (XEXP (x, 0))
&& GET_CODE (XEXP (x, 1)) == CONST_INT
&& INTVAL (XEXP (x, 1)) >= 0)
{
int fit = INTVAL (XEXP (x, 1)) <= MAX_LD_OFFSET (mode);
if (fit)
{
if (! strict
|| REGNO (XEXP (x,0)) == REG_Y
|| REGNO (XEXP (x,0)) == REG_Z)
r = BASE_POINTER_REGS;
if (XEXP (x,0) == frame_pointer_rtx
|| XEXP (x,0) == arg_pointer_rtx)
r = BASE_POINTER_REGS;
}
else if (frame_pointer_needed && XEXP (x,0) == frame_pointer_rtx)
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 = POINTER_REGS;
}
if (TARGET_ALL_DEBUG)
{
fprintf (stderr, " ret = %c\n", r);
}
return r == NO_REGS ? 0 : (int)r;
}
rtx
legitimize_address (x, oldx, mode)
rtx x;
rtx oldx;
enum machine_mode mode;
{
x = oldx;
if (TARGET_ALL_DEBUG)
{
fprintf (stderr, "legitimize_address mode: %s", GET_MODE_NAME(mode));
debug_rtx (oldx);
}
if (GET_CODE (oldx) == PLUS
&& REG_P (XEXP (oldx,0)))
{
if (REG_P (XEXP (oldx,1)))
x = force_reg (GET_MODE (oldx), oldx);
else if (GET_CODE (XEXP (oldx, 1)) == CONST_INT)
{
int offs = INTVAL (XEXP (oldx,1));
if (frame_pointer_rtx != XEXP (oldx,0))
if (offs > MAX_LD_OFFSET (mode))
{
if (TARGET_ALL_DEBUG)
fprintf (stderr, "force_reg (big offset)\n");
x = force_reg (GET_MODE (oldx), oldx);
}
}
}
return x;
}
static const char *
ptrreg_to_str (regno)
int regno;
{
switch (regno)
{
case REG_X: return "X";
case REG_Y: return "Y";
case REG_Z: return "Z";
default:
abort ();
}
return NULL;
}
static const char *
cond_string (code)
enum rtx_code code;
{
switch (code)
{
case NE:
return "ne";
case EQ:
return "eq";
case GE:
if (cc_prev_status.flags & CC_OVERFLOW_UNUSABLE)
return "pl";
else
return "ge";
case LT:
if (cc_prev_status.flags & CC_OVERFLOW_UNUSABLE)
return "mi";
else
return "lt";
case GEU:
return "sh";
case LTU:
return "lo";
default:
abort ();
}
}
void
print_operand_address (file, addr)
FILE *file;
rtx addr;
{
switch (GET_CODE (addr))
{
case REG:
fprintf (file, ptrreg_to_str (REGNO (addr)));
break;
case PRE_DEC:
fprintf (file, "-%s", ptrreg_to_str (REGNO (XEXP (addr, 0))));
break;
case POST_INC:
fprintf (file, "%s+", ptrreg_to_str (REGNO (XEXP (addr, 0))));
break;
default:
if (CONSTANT_ADDRESS_P (addr)
&& (SYMBOL_REF_FLAG (addr) || GET_CODE (addr) == LABEL_REF))
{
fprintf (file, "pm(");
output_addr_const (file,addr);
fprintf (file ,")");
}
else
output_addr_const (file, addr);
}
}
void
print_operand (file, x, code)
FILE *file;
rtx x;
int code;
{
int abcd = 0;
if (code >= 'A' && code <= 'D')
abcd = code - 'A';
if (code == '~')
{
if (!AVR_MEGA)
fputc ('r', file);
}
else if (REG_P (x))
{
if (x == zero_reg_rtx)
fprintf (file, "__zero_reg__");
else
fprintf (file, reg_names[true_regnum (x) + abcd]);
}
else if (GET_CODE (x) == CONST_INT)
fprintf (file, "%d", INTVAL (x) + abcd);
else if (GET_CODE (x) == MEM)
{
rtx addr = XEXP (x,0);
if (CONSTANT_P (addr) && abcd)
{
fputc ('(', file);
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));
if (REGNO (XEXP (addr, 0)) == REG_X)
fatal_insn ("internal compiler error. Bad address:"
,addr);
fputc ('+', file);
print_operand (file, XEXP (addr,1), code);
}
else
print_operand_address (file, addr);
}
else if (GET_CODE (x) == CONST_DOUBLE)
{
long val;
REAL_VALUE_TYPE rv;
if (GET_MODE (x) != SFmode)
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);
}
else if (code == 'j')
asm_fprintf (file, cond_string (GET_CODE (x)));
else if (code == 'k')
asm_fprintf (file, cond_string (reverse_condition (GET_CODE (x))));
else
print_operand_address (file, x);
}
int
call_insn_operand (op, mode)
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;
}
void
notice_update_cc (body, insn)
rtx body ATTRIBUTE_UNUSED;
rtx insn;
{
rtx set;
switch (get_attr_cc (insn))
{
case CC_NONE:
break;
case CC_SET_N:
CC_STATUS_INIT;
break;
case CC_SET_ZN:
set = single_set (insn);
CC_STATUS_INIT;
if (set)
{
cc_status.flags |= CC_NO_OVERFLOW;
cc_status.value1 = SET_DEST (set);
}
break;
case CC_SET_CZN:
set = single_set (insn);
CC_STATUS_INIT;
if (set)
{
cc_status.value1 = SET_DEST (set);
cc_status.flags |= CC_OVERFLOW_UNUSABLE;
}
break;
case CC_COMPARE:
set = single_set (insn);
CC_STATUS_INIT;
if (set)
cc_status.value1 = SET_SRC (set);
break;
case CC_CLOBBER:
CC_STATUS_INIT;
set = single_set (insn);
if (set)
{
rtx src = SET_SRC (set);
if (GET_CODE (src) == ASHIFTRT
&& GET_MODE (src) == QImode)
{
rtx x = XEXP (src, 1);
if (GET_CODE (x) == CONST_INT
&& INTVAL (x) != 6)
{
cc_status.value1 = SET_DEST (set);
cc_status.flags |= CC_OVERFLOW_UNUSABLE;
}
}
}
break;
}
}
int
class_max_nregs (class, mode)
enum reg_class class ATTRIBUTE_UNUSED;
enum machine_mode mode;
{
return ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD);
}
int
avr_jump_mode (x, insn)
rtx x;
rtx insn;
{
int dest_addr = INSN_ADDRESSES (INSN_UID (GET_MODE (x) == LABEL_REF
? XEXP (x, 0) : x));
int cur_addr = INSN_ADDRESSES (INSN_UID (insn));
int jump_distance = cur_addr - dest_addr;
if (-63 <= jump_distance && jump_distance <= 62)
return 1;
else if (-2046 <= jump_distance && jump_distance <= 2045)
return 2;
else if (AVR_MEGA)
return 3;
return 2;
}
const char *
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:
if (cc_prev_status.flags & CC_OVERFLOW_UNUSABLE)
return (len == 1 ? (AS1 (breq,_PC_+2) CR_TAB
AS1 (brpl,%0)) :
len == 2 ? (AS1 (breq,_PC_+4) CR_TAB
AS1 (brmi,_PC_+2) CR_TAB
AS1 (rjmp,%0)) :
(AS1 (breq,_PC_+6) CR_TAB
AS1 (brmi,_PC_+4) CR_TAB
AS1 (jmp,%0)));
else
return (len == 1 ? (AS1 (breq,_PC_+2) CR_TAB
AS1 (brge,%0)) :
len == 2 ? (AS1 (breq,_PC_+4) CR_TAB
AS1 (brlt,_PC_+2) CR_TAB
AS1 (rjmp,%0)) :
(AS1 (breq,_PC_+6) CR_TAB
AS1 (brlt,_PC_+4) CR_TAB
AS1 (jmp,%0)));
case GTU:
return (len == 1 ? (AS1 (breq,_PC_+2) CR_TAB
AS1 (brsh,%0)) :
len == 2 ? (AS1 (breq,_PC_+4) CR_TAB
AS1 (brlo,_PC_+2) CR_TAB
AS1 (rjmp,%0)) :
(AS1 (breq,_PC_+6) CR_TAB
AS1 (brlo,_PC_+4) CR_TAB
AS1 (jmp,%0)));
case LE:
if (cc_prev_status.flags & CC_OVERFLOW_UNUSABLE)
return (len == 1 ? (AS1 (breq,%0) CR_TAB
AS1 (brmi,%0)) :
len == 2 ? (AS1 (breq,_PC_+2) CR_TAB
AS1 (brpl,_PC_+2) CR_TAB
AS1 (rjmp,%0)) :
(AS1 (breq,_PC_+2) CR_TAB
AS1 (brpl,_PC_+4) CR_TAB
AS1 (jmp,%0)));
else
return (len == 1 ? (AS1 (breq,%0) CR_TAB
AS1 (brlt,%0)) :
len == 2 ? (AS1 (breq,_PC_+2) CR_TAB
AS1 (brge,_PC_+2) CR_TAB
AS1 (rjmp,%0)) :
(AS1 (breq,_PC_+2) CR_TAB
AS1 (brge,_PC_+4) CR_TAB
AS1 (jmp,%0)));
case LEU:
return (len == 1 ? (AS1 (breq,%0) CR_TAB
AS1 (brlo,%0)) :
len == 2 ? (AS1 (breq,_PC_+2) CR_TAB
AS1 (brsh,_PC_+2) CR_TAB
AS1 (rjmp,%0)) :
(AS1 (breq,_PC_+2) CR_TAB
AS1 (brsh,_PC_+4) CR_TAB
AS1 (jmp,%0)));
default:
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
byte_immediate_operand (op, mode)
register rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return (GET_CODE (op) == CONST_INT
&& INTVAL (op) <= 0xff && INTVAL (op) >= 0);
}
void
final_prescan_insn (insn, operand, num_operands)
rtx insn, *operand ATTRIBUTE_UNUSED;
int num_operands ATTRIBUTE_UNUSED;
{
int uid = INSN_UID (insn);
if (TARGET_INSN_SIZE_DUMP || TARGET_ALL_DEBUG)
{
fprintf (asm_out_file, "/*DEBUG: 0x%x\t\t%d\t%d */\n",
INSN_ADDRESSES (uid),
INSN_ADDRESSES (uid) - last_insn_address,
rtx_cost (PATTERN (insn), INSN));
}
last_insn_address = INSN_ADDRESSES (uid);
if (TARGET_RTL_DUMP)
{
fprintf (asm_out_file, "/*****************\n");
print_rtl_single (asm_out_file, insn);
fprintf (asm_out_file, "*****************/\n");
}
}
int
avr_simplify_comparision_p (mode, operator, x)
enum machine_mode mode;
RTX_CODE operator;
rtx x;
{
unsigned int max = (mode == QImode ? 0xff :
mode == HImode ? 0xffff :
mode == SImode ? 0xffffffff : 0);
if (max && operator && GET_CODE (x) == CONST_INT)
{
if (unsigned_condition (operator) != operator)
max >>= 1;
if (max != (INTVAL (x) & max)
&& INTVAL (x) != 0xff)
return 1;
}
return 0;
}
int
function_arg_regno_p(r)
int r;
{
return (r >= 8 && r <= 25);
}
void
init_cumulative_args (cum, fntype, libname, indirect)
CUMULATIVE_ARGS *cum;
tree fntype;
rtx libname;
int indirect ATTRIBUTE_UNUSED;
{
cum->nregs = 18;
cum->regno = FIRST_CUM_REG;
if (!libname)
{
int stdarg = (TYPE_ARG_TYPES (fntype) != 0
&& (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
!= void_type_node));
if (stdarg)
cum->nregs = 0;
}
}
static int
avr_num_arg_regs (mode, type)
enum machine_mode mode;
tree type;
{
int size;
if (mode == BLKmode)
size = int_size_in_bytes (type);
else
size = GET_MODE_SIZE (mode);
return (size + 1) & ~1;
}
rtx
function_arg (cum, mode, type, named)
CUMULATIVE_ARGS *cum;
enum machine_mode mode;
tree type;
int named ATTRIBUTE_UNUSED;
{
int bytes = avr_num_arg_regs (mode, type);
if (cum->nregs && bytes <= cum->nregs)
return gen_rtx (REG, mode, cum->regno - bytes);
return NULL_RTX;
}
void
function_arg_advance (cum, mode, type, named)
CUMULATIVE_ARGS *cum;
enum machine_mode mode;
tree type;
int named ATTRIBUTE_UNUSED;
{
int bytes = avr_num_arg_regs (mode, type);
cum->nregs -= bytes;
cum->regno -= bytes;
if (cum->nregs <= 0)
{
cum->nregs = 0;
cum->regno = FIRST_CUM_REG;
}
}
const char *
output_movqi (insn, operands, l)
rtx insn;
rtx operands[];
int *l;
{
int dummy;
rtx dest = operands[0];
rtx src = operands[1];
int *real_l = l;
if (!l)
l = &dummy;
*l = 1;
if (register_operand (dest, QImode))
{
if (register_operand (src, QImode))
{
if (test_hard_reg_class (STACK_REG, dest))
return AS2 (out,%0,%1);
else if (test_hard_reg_class (STACK_REG, src))
return AS2 (in,%0,%1);
return AS2 (mov,%0,%1);
}
else if (CONSTANT_P (src))
{
if (test_hard_reg_class (LD_REGS, dest))
return AS2 (ldi,%0,lo8(%1));
if (GET_CODE (src) == CONST_INT)
{
if (src == const0_rtx)
return AS1 (clr,%0);
else if (src == const1_rtx)
{
if (reg_was_0 (insn, dest))
return AS1 (inc,%0 ; reg_was_0);
*l = 2;
return (AS1 (clr,%0) CR_TAB
AS1 (inc,%0));
}
else if (src == constm1_rtx)
{
if (reg_was_0 (insn, dest))
return AS1 (dec,%0 ; reg_was_0);
*l = 2;
return (AS1 (clr,%0) CR_TAB
AS1 (dec,%0));
}
else
{
int bit_nr = exact_log2 (INTVAL (src));
if (bit_nr >= 0)
{
if (reg_was_0 (insn, dest))
{
*l = 2;
if (!real_l)
output_asm_insn ("set ; reg_was_0", operands);
}
else
{
*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 "";
}
}
}
*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__));
}
else if (GET_CODE (src) == MEM)
return out_movqi_r_mr (insn, operands, real_l);
}
else if (GET_CODE (dest) == MEM)
{
const char *template;
if (src == const0_rtx)
operands[1] = zero_reg_rtx;
template = out_movqi_mr_r (insn, operands, real_l);
if (!real_l)
output_asm_insn (template, operands);
operands[1] = src;
}
return "";
}
const char *
output_movhi (insn, operands, l)
rtx insn;
rtx operands[];
int *l;
{
int dummy;
rtx dest = operands[0];
rtx src = operands[1];
int *real_l = l;
if (!l)
l = &dummy;
if (register_operand (dest, HImode))
{
if (register_operand (src, HImode))
{
if (test_hard_reg_class (STACK_REG, dest))
{
if (TARGET_TINY_STACK)
{
*l = 1;
return AS2 (out,__SP_L__,%A1);
}
else if (TARGET_NO_INTERRUPTS)
{
*l = 2;
return (AS2 (out,__SP_H__,%B1) CR_TAB
AS2 (out,__SP_L__,%A1));
}
*l = 5;
return (AS2 (in,__tmp_reg__,__SREG__) CR_TAB
"cli" CR_TAB
AS2 (out,__SP_H__,%B1) CR_TAB
AS2 (out,__SREG__,__tmp_reg__) CR_TAB
AS2 (out,__SP_L__,%A1));
}
else if (test_hard_reg_class (STACK_REG, src))
{
*l = 2;
return (AS2 (in,%A0,__SP_L__) CR_TAB
AS2 (in,%B0,__SP_H__));
}
if (AVR_ENHANCED)
{
*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;
return (AS2 (mov,%A0,%A1) CR_TAB
AS2 (mov,%B0,%B1));
}
}
else if (CONSTANT_P (src))
{
if (test_hard_reg_class (LD_REGS, dest))
{
if (byte_immediate_operand (src, HImode)
&& reg_was_0 (insn, dest))
{
*l = 1;
return (AS2 (ldi,%A0,lo8(%1) ; reg_was_0));
}
*l = 2;
return (AS2 (ldi,%A0,lo8(%1)) CR_TAB
AS2 (ldi,%B0,hi8(%1)));
}
if (GET_CODE (src) == CONST_INT)
{
if (src == const0_rtx)
{
*l = 2;
return (AS1 (clr,%A0) CR_TAB
AS1 (clr,%B0));
}
else if (src == const1_rtx)
{
if (reg_was_0 (insn, dest))
{
*l = 1;
return AS1 (inc,%0 ; reg_was_0);
}
*l = 3;
return (AS1 (clr,%A0) CR_TAB
AS1 (clr,%B0) CR_TAB
AS1 (inc,%A0));
}
else if (src == constm1_rtx)
{
if (reg_was_0 (insn, dest))
{
*l = 2;
return (AS1 (dec,%A0 ; reg_was_0) CR_TAB
AS1 (dec,%B0));
}
*l = 3;
return (AS1 (clr,%0) CR_TAB
AS1 (dec,%A0) CR_TAB
AS2 (mov,%B0,%A0));
}
else
{
int bit_nr = exact_log2 (INTVAL (src));
if (bit_nr >= 0)
{
if (reg_was_0 (insn, dest))
{
*l = 2;
if (!real_l)
output_asm_insn ("set ; reg_was_0", operands);
}
else
{
*l = 4;
if (!real_l)
output_asm_insn ((AS1 (clr,%A0) CR_TAB
AS1 (clr,%B0) CR_TAB
"set"), operands);
}
if (!real_l)
avr_output_bld (operands, bit_nr);
return "";
}
}
if ((INTVAL (src) & 0xff) == 0)
{
*l = 5;
return (AS2 (mov,__tmp_reg__,r31) CR_TAB
AS1 (clr,%A0) CR_TAB
AS2 (ldi,r31,hi8(%1)) CR_TAB
AS2 (mov,%B0,r31) CR_TAB
AS2 (mov,r31,__tmp_reg__));
}
else if ((INTVAL (src) & 0xff00) == 0)
{
*l = 5;
return (AS2 (mov,__tmp_reg__,r31) CR_TAB
AS2 (ldi,r31,lo8(%1)) CR_TAB
AS2 (mov,%A0,r31) CR_TAB
AS1 (clr,%B0) CR_TAB
AS2 (mov,r31,__tmp_reg__));
}
}
*l = 6;
return (AS2 (mov,__tmp_reg__,r31) CR_TAB
AS2 (ldi,r31,lo8(%1)) CR_TAB
AS2 (mov,%A0,r31) CR_TAB
AS2 (ldi,r31,hi8(%1)) CR_TAB
AS2 (mov,%B0,r31) CR_TAB
AS2 (mov,r31,__tmp_reg__));
}
else if (GET_CODE (src) == MEM)
return out_movhi_r_mr (insn, operands, real_l);
}
else if (GET_CODE (dest) == MEM)
{
const char *template;
if (src == const0_rtx)
operands[1] = zero_reg_rtx;
template = out_movhi_mr_r (insn, operands, real_l);
if (!real_l)
output_asm_insn (template, operands);
operands[1] = src;
return "";
}
fatal_insn ("invalid insn:", insn);
return "";
}
const char *
out_movqi_r_mr (insn, op, l)
rtx insn;
rtx op[];
int *l;
{
rtx dest = op[0];
rtx src = op[1];
rtx x = XEXP (src, 0);
int dummy;
if (!l)
l = &dummy;
if (CONSTANT_ADDRESS_P (x))
{
if (io_address_p (x, 1))
{
*l = 1;
return AS2 (in,%0,%1-0x20);
}
*l = 2;
return AS2 (lds,%0,%1);
}
else if (GET_CODE (x) == PLUS
&& REG_P (XEXP (x,0))
&& GET_CODE (XEXP (x,1)) == CONST_INT)
{
if ((INTVAL (XEXP (x,1)) - GET_MODE_SIZE (GET_MODE (src))) >= 63)
{
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)))
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)
{
if (reg_overlap_mentioned_p (dest, XEXP (x,0))
|| reg_unused_after (insn, XEXP (x,0)))
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);
}
*l = 1;
return AS2 (ld,%0,%1);
}
const char *
out_movhi_r_mr (insn, op, l)
rtx insn;
rtx op[];
int *l;
{
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);
int tmp;
if (!l)
l = &tmp;
if (reg_base > 0)
{
if (reg_dest == reg_base)
{
*l = 3;
return (AS2 (ld,__tmp_reg__,%1+) CR_TAB
AS2 (ld,%B0,%1) CR_TAB
AS2 (mov,%A0,__tmp_reg__));
}
else if (reg_base == REG_X)
{
if (reg_unused_after (insn, base))
{
*l = 2;
return (AS2 (ld,%A0,X+) CR_TAB
AS2 (ld,%B0,X));
}
*l = 3;
return (AS2 (ld,%A0,X+) CR_TAB
AS2 (ld,%B0,X) CR_TAB
AS2 (sbiw,r26,1));
}
else
{
*l = 2;
return (AS2 (ld,%A0,%1) CR_TAB
AS2 (ldd,%B0,%1+1));
}
}
else if (GET_CODE (base) == PLUS)
{
int disp = INTVAL (XEXP (base, 1));
int reg_base = true_regnum (XEXP (base, 0));
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 *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)
{
*l = 4;
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)
{
*l = 3;
return (AS2 (ldd,__tmp_reg__,%A1) CR_TAB
AS2 (ldd,%B0,%B1) CR_TAB
AS2 (mov,%A0,__tmp_reg__));
}
*l = 2;
return (AS2 (ldd,%A0,%A1) CR_TAB
AS2 (ldd,%B0,%B1));
}
else if (GET_CODE (base) == PRE_DEC)
{
if (reg_overlap_mentioned_p (dest, XEXP (base, 0)))
fatal_insn ("incorrect insn:", insn);
*l = 2;
return (AS2 (ld,%B0,%1) CR_TAB
AS2 (ld,%A0,%1));
}
else if (GET_CODE (base) == POST_INC)
{
if (reg_overlap_mentioned_p (dest, XEXP (base, 0)))
fatal_insn ("incorrect insn:", insn);
*l = 2;
return (AS2 (ld,%A0,%1) CR_TAB
AS2 (ld,%B0,%1));
}
else if (CONSTANT_ADDRESS_P (base))
{
if (io_address_p (base, 2))
{
*l = 2;
return (AS2 (in,%A0,%A1-0x20) CR_TAB
AS2 (in,%B0,%B1-0x20));
}
*l = 4;
return (AS2 (lds,%A0,%A1) CR_TAB
AS2 (lds,%B0,%B1));
}
fatal_insn ("unknown move insn:",insn);
return "";
}
const char *
out_movsi_r_mr (insn, op, l)
rtx insn;
rtx op[];
int *l;
{
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);
int tmp;
if (!l)
l = &tmp;
if (reg_base > 0)
{
if (reg_base == REG_X)
{
if (reg_dest == REG_X)
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
AS2 (ld,__tmp_reg__,X+) CR_TAB
AS2 (ld,%D0,X) CR_TAB
AS2 (mov,%C0,__tmp_reg__));
else if (reg_unused_after (insn, base))
return *l=4, (AS2 (ld,%A0,X+) CR_TAB
AS2 (ld,%B0,X+) CR_TAB
AS2 (ld,%C0,X+) CR_TAB
AS2 (ld,%D0,X));
else
return *l=5, (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,3));
}
else
{
if (reg_dest == reg_base)
return *l=5, (AS2 (ldd,%D0,%1+3) CR_TAB
AS2 (ldd,%C0,%1+2) CR_TAB
AS2 (ldd,__tmp_reg__,%1+1) CR_TAB
AS2 (ld,%A0,%1) CR_TAB
AS2 (mov,%B0,__tmp_reg__));
else if (reg_base == reg_dest + 2)
return *l=5, (AS2 (ld ,%A0,%1) CR_TAB
AS2 (ldd,%B0,%1+1) CR_TAB
AS2 (ldd,__tmp_reg__,%1+2) CR_TAB
AS2 (ldd,%D0,%1+3) CR_TAB
AS2 (mov,%C0,__tmp_reg__));
else
return *l=4, (AS2 (ld ,%A0,%1) CR_TAB
AS2 (ldd,%B0,%1+1) CR_TAB
AS2 (ldd,%C0,%1+2) CR_TAB
AS2 (ldd,%D0,%1+3));
}
}
else if (GET_CODE (base) == PLUS)
{
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 *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)
{
if (reg_dest == REG_X)
{
*l = 7;
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
AS2 (ldd,__tmp_reg__,%B1) CR_TAB
AS2 (ldd,%A0,%A1) CR_TAB
AS2 (mov,%B0,__tmp_reg__));
else if (reg_dest == reg_base - 2)
return *l=5, (AS2 (ldd,%A0,%A1) CR_TAB
AS2 (ldd,%B0,%B1) CR_TAB
AS2 (ldd,__tmp_reg__,%C1) CR_TAB
AS2 (ldd,%D0,%D1) CR_TAB
AS2 (mov,%C0,__tmp_reg__));
return *l=4, (AS2 (ldd,%A0,%A1) CR_TAB
AS2 (ldd,%B0,%B1) CR_TAB
AS2 (ldd,%C0,%C1) CR_TAB
AS2 (ldd,%D0,%D1));
}
else if (GET_CODE (base) == PRE_DEC)
return *l=4, (AS2 (ld,%D0,%1) CR_TAB
AS2 (ld,%C0,%1) CR_TAB
AS2 (ld,%B0,%1) CR_TAB
AS2 (ld,%A0,%1));
else if (GET_CODE (base) == POST_INC)
return *l=4, (AS2 (ld,%A0,%1) CR_TAB
AS2 (ld,%B0,%1) CR_TAB
AS2 (ld,%C0,%1) CR_TAB
AS2 (ld,%D0,%1));
else if (CONSTANT_ADDRESS_P (base))
return *l=8, (AS2 (lds,%A0,%A1) CR_TAB
AS2 (lds,%B0,%B1) CR_TAB
AS2 (lds,%C0,%C1) CR_TAB
AS2 (lds,%D0,%D1));
fatal_insn ("unknown move insn:",insn);
return "";
}
const char *
out_movsi_mr_r (insn, op, l)
rtx insn;
rtx op[];
int *l;
{
rtx dest = op[0];
rtx src = op[1];
rtx base = XEXP (dest, 0);
int reg_base = true_regnum (base);
int reg_src = true_regnum (src);
int tmp;
if (!l)
l = &tmp;
if (CONSTANT_ADDRESS_P (base))
return *l=8,(AS2 (sts,%A0,%A1) CR_TAB
AS2 (sts,%B0,%B1) CR_TAB
AS2 (sts,%C0,%C1) CR_TAB
AS2 (sts,%D0,%D1));
if (reg_base > 0)
{
if (reg_base == REG_X)
{
if (reg_src == REG_X)
{
if (reg_unused_after (insn, base))
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=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)
{
if (reg_unused_after (insn, base))
return *l=7, (AS2 (mov,__zero_reg__,%C1) CR_TAB
AS2 (mov,__tmp_reg__,%D1) CR_TAB
AS2 (st,%0+,%A1) CR_TAB
AS2 (st,%0+,%B1) CR_TAB
AS2 (st,%0+,__zero_reg__) CR_TAB
AS2 (st,%0,__tmp_reg__) CR_TAB
AS1 (clr,__zero_reg__));
else
return *l=8, (AS2 (mov,__zero_reg__,%C1) CR_TAB
AS2 (mov,__tmp_reg__,%D1) CR_TAB
AS2 (st,%0+,%A1) CR_TAB
AS2 (st,%0+,%B1) CR_TAB
AS2 (st,%0+,__zero_reg__) CR_TAB
AS2 (st,%0,__tmp_reg__) CR_TAB
AS1 (clr,__zero_reg__) CR_TAB
AS2 (sbiw,r26,3));
}
return *l=5, (AS2 (st,%0+,%A1) CR_TAB
AS2 (st,%0+,%B1) CR_TAB
AS2 (st,%0+,%C1) CR_TAB
AS2 (st,%0,%D1) CR_TAB
AS2 (sbiw,r26,3));
}
else
return *l=4, (AS2 (st,%0,%A1) CR_TAB
AS2 (std,%0+1,%B1) CR_TAB
AS2 (std,%0+2,%C1) CR_TAB
AS2 (std,%0+3,%D1));
}
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 (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)
{
if (reg_src == REG_X)
{
*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 if (reg_src == REG_X - 2)
{
*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
AS2 (std,%C0,%C1) CR_TAB
AS2 (std,%D0,%D1));
}
else if (GET_CODE (base) == PRE_DEC)
return *l=4, (AS2 (st,%0,%D1) CR_TAB
AS2 (st,%0,%C1) CR_TAB
AS2 (st,%0,%B1) CR_TAB
AS2 (st,%0,%A1));
else if (GET_CODE (base) == POST_INC)
return *l=4, (AS2 (st,%0,%A1) CR_TAB
AS2 (st,%0,%B1) CR_TAB
AS2 (st,%0,%C1) CR_TAB
AS2 (st,%0,%D1));
fatal_insn ("unknown move insn:",insn);
return "";
}
const char *
output_movsisf(insn, operands, l)
rtx insn;
rtx operands[];
int *l;
{
int dummy;
rtx dest = operands[0];
rtx src = operands[1];
int *real_l = l;
if (!l)
l = &dummy;
if (register_operand (dest, VOIDmode))
{
if (register_operand (src, VOIDmode))
{
if (true_regnum (dest) > true_regnum (src))
{
if (AVR_ENHANCED)
{
*l = 2;
return (AS2 (movw,%C0,%C1) CR_TAB
AS2 (movw,%A0,%A1));
}
*l = 4;
return (AS2 (mov,%D0,%D1) CR_TAB
AS2 (mov,%C0,%C1) CR_TAB
AS2 (mov,%B0,%B1) CR_TAB
AS2 (mov,%A0,%A1));
}
else
{
if (AVR_ENHANCED)
{
*l = 2;
return (AS2 (movw,%A0,%A1) CR_TAB
AS2 (movw,%C0,%C1));
}
*l = 4;
return (AS2 (mov,%A0,%A1) CR_TAB
AS2 (mov,%B0,%B1) CR_TAB
AS2 (mov,%C0,%C1) CR_TAB
AS2 (mov,%D0,%D1));
}
}
else if (CONSTANT_P (src))
{
if (test_hard_reg_class (LD_REGS, dest))
{
if (byte_immediate_operand (src, SImode)
&& reg_was_0 (insn, dest))
{
*l = 1;
return (AS2 (ldi,%A0,lo8(%1) ; reg_was_0));
}
*l = 4;
return (AS2 (ldi,%A0,lo8(%1)) CR_TAB
AS2 (ldi,%B0,hi8(%1)) CR_TAB
AS2 (ldi,%C0,hlo8(%1)) CR_TAB
AS2 (ldi,%D0,hhi8(%1)));
}
if (GET_CODE (src) == CONST_INT)
{
const char *const clr_op0 =
AVR_ENHANCED ? (AS1 (clr,%A0) CR_TAB
AS1 (clr,%B0) CR_TAB
AS2 (movw,%C0,%A0))
: (AS1 (clr,%A0) CR_TAB
AS1 (clr,%B0) CR_TAB
AS1 (clr,%C0) CR_TAB
AS1 (clr,%D0));
if (src == const0_rtx)
{
*l = AVR_ENHANCED ? 3 : 4;
return clr_op0;
}
else if (src == const1_rtx)
{
if (reg_was_0 (insn, dest))
{
*l = 1;
return AS1 (inc,%A0 ; reg_was_0);
}
if (!real_l)
output_asm_insn (clr_op0, operands);
*l = AVR_ENHANCED ? 4 : 5;
return AS1 (inc,%A0);
}
else if (src == constm1_rtx)
{
if (reg_was_0 (insn, dest))
{
if (AVR_ENHANCED)
{
*l = 3;
return (AS1 (dec,%A0) CR_TAB
AS1 (dec,%B0) CR_TAB
AS2 (movw,%C0,%A0));
}
*l = 4;
return (AS1 (dec,%D0 ; reg_was_0) CR_TAB
AS1 (dec,%C0) CR_TAB
AS1 (dec,%B0) CR_TAB
AS1 (dec,%A0));
}
if (AVR_ENHANCED)
{
*l = 4;
return (AS1 (clr,%A0) CR_TAB
AS1 (dec,%A0) CR_TAB
AS2 (mov,%B0,%A0) CR_TAB
AS2 (movw,%C0,%A0));
}
*l = 5;
return (AS1 (clr,%A0) CR_TAB
AS1 (dec,%A0) CR_TAB
AS2 (mov,%B0,%A0) CR_TAB
AS2 (mov,%C0,%A0) CR_TAB
AS2 (mov,%D0,%A0));
}
else
{
int bit_nr = exact_log2 (INTVAL (src));
if (bit_nr >= 0)
{
if (reg_was_0 (insn, dest))
{
*l = 2;
if (!real_l)
output_asm_insn ("set ; reg_was_0", operands);
}
else
{
*l = AVR_ENHANCED ? 5 : 6;
if (!real_l)
{
output_asm_insn (clr_op0, operands);
output_asm_insn ("set", operands);
}
}
if (!real_l)
avr_output_bld (operands, bit_nr);
return "";
}
}
}
*l = 10;
return (AS2 (mov,__tmp_reg__,r31) CR_TAB
AS2 (ldi,r31,lo8(%1)) CR_TAB
AS2 (mov,%A0,r31) CR_TAB
AS2 (ldi,r31,hi8(%1)) CR_TAB
AS2 (mov,%B0,r31) CR_TAB
AS2 (ldi,r31,hlo8(%1)) CR_TAB
AS2 (mov,%C0,r31) CR_TAB
AS2 (ldi,r31,hhi8(%1)) CR_TAB
AS2 (mov,%D0,r31) CR_TAB
AS2 (mov,r31,__tmp_reg__));
}
else if (GET_CODE (src) == MEM)
return out_movsi_r_mr (insn, operands, real_l);
}
else if (GET_CODE (dest) == MEM)
{
const char *template;
if (src == const0_rtx)
operands[1] = zero_reg_rtx;
template = out_movsi_mr_r (insn, operands, real_l);
if (!real_l)
output_asm_insn (template, operands);
operands[1] = src;
return "";
}
fatal_insn ("invalid insn:", insn);
return "";
}
const char *
out_movqi_mr_r (insn, op, l)
rtx insn;
rtx op[];
int *l;
{
rtx dest = op[0];
rtx src = op[1];
rtx x = XEXP (dest, 0);
int dummy;
if (!l)
l = &dummy;
if (CONSTANT_ADDRESS_P (x))
{
if (io_address_p (x, 1))
{
*l = 1;
return AS2 (out,%0-0x20,%1);
}
*l = 2;
return AS2 (sts,%0,%1);
}
else if (GET_CODE (x) == PLUS
&& REG_P (XEXP (x,0))
&& GET_CODE (XEXP (x,1)) == CONST_INT)
{
if ((INTVAL (XEXP (x,1)) - GET_MODE_SIZE (GET_MODE (dest))) >= 63)
{
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)))
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)
{
if (reg_overlap_mentioned_p (src, XEXP (x, 0)))
{
if (reg_unused_after (insn, XEXP (x,0)))
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)))
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;
return AS2 (std,%0,%1);
}
*l = 1;
return AS2 (st,%0,%1);
}
const char *
out_movhi_mr_r (insn, op, l)
rtx insn;
rtx op[];
int *l;
{
rtx dest = op[0];
rtx src = op[1];
rtx base = XEXP (dest, 0);
int reg_base = true_regnum (base);
int reg_src = true_regnum (src);
int tmp;
if (!l)
l = &tmp;
if (CONSTANT_ADDRESS_P (base))
{
if (io_address_p (base, 2))
{
*l = 2;
return (AS2 (out,%B0-0x20,%B1) CR_TAB
AS2 (out,%A0-0x20,%A1));
}
return *l = 4, (AS2 (sts,%B0,%B1) CR_TAB
AS2 (sts,%A0,%A1));
}
if (reg_base > 0)
{
if (reg_base == REG_X)
{
if (reg_src == REG_X)
{
if (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));
}
else
{
if (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));
}
}
else
return *l=2, (AS2 (st ,%0,%A1) CR_TAB
AS2 (std,%0+1,%B1));
}
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 (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)
{
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 (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));
}
else if (GET_CODE (base) == PRE_DEC)
return *l=2, (AS2 (st,%0,%B1) CR_TAB
AS2 (st,%0,%A1));
else if (GET_CODE (base) == POST_INC)
return *l=2, (AS2 (st,%0,%A1) CR_TAB
AS2 (st,%0,%B1));
fatal_insn ("unknown move insn:",insn);
return "";
}
int
frame_pointer_required_p ()
{
return (current_function_calls_alloca
|| current_function_args_info.nregs == 0
|| current_function_varargs
|| get_frame_size () > 0);
}
static RTX_CODE
compare_condition (insn)
rtx insn;
{
rtx next = next_real_insn (insn);
RTX_CODE cond = UNKNOWN;
if (next && GET_CODE (next) == JUMP_INSN)
{
rtx pat = PATTERN (next);
rtx src = SET_SRC (pat);
rtx t = XEXP (src, 0);
cond = GET_CODE (t);
}
return cond;
}
static int
compare_sign_p (insn)
rtx insn;
{
RTX_CODE cond = compare_condition (insn);
return (cond == GE || cond == LT);
}
int
compare_diff_p (insn)
rtx insn;
{
RTX_CODE cond = compare_condition (insn);
return (cond == GT || cond == GTU || cond == LE || cond == LEU) ? cond : 0;
}
int
compare_eq_p (insn)
rtx insn;
{
RTX_CODE cond = compare_condition (insn);
return (cond == EQ || cond == NE);
}
const char *
out_tsthi (insn, l)
rtx insn;
int *l;
{
if (compare_sign_p (insn))
{
if (l) *l = 1;
return AS1 (tst,%B0);
}
if (reg_unused_after (insn, SET_SRC (PATTERN (insn)))
&& compare_eq_p (insn))
{
if (l) *l = 1;
return AS2 (or,%A0,%B0);
}
if (test_hard_reg_class (ADDW_REGS, SET_SRC (PATTERN (insn))))
{
if (l) *l = 1;
return AS2 (sbiw,%0,0);
}
if (l) *l = 2;
return (AS2 (cp,%A0,__zero_reg__) CR_TAB
AS2 (cpc,%B0,__zero_reg__));
}
const char *
out_tstsi (insn, l)
rtx insn;
int *l;
{
if (compare_sign_p (insn))
{
if (l) *l = 1;
return AS1 (tst,%D0);
}
if (test_hard_reg_class (ADDW_REGS, SET_SRC (PATTERN (insn))))
{
if (l) *l = 3;
return (AS2 (sbiw,%A0,0) CR_TAB
AS2 (cpc,%C0,__zero_reg__) CR_TAB
AS2 (cpc,%D0,__zero_reg__));
}
if (l) *l = 4;
return (AS2 (cp,%A0,__zero_reg__) CR_TAB
AS2 (cpc,%B0,__zero_reg__) CR_TAB
AS2 (cpc,%C0,__zero_reg__) CR_TAB
AS2 (cpc,%D0,__zero_reg__));
}
void
out_shift_with_cnt (template, insn, operands, len, t_len)
const char *template;
rtx insn;
rtx operands[];
int *len;
int t_len;
{
rtx op[10];
char str[500];
int second_label = 1;
int saved_in_tmp = 0;
int use_zero_reg = 0;
op[0] = operands[0];
op[1] = operands[1];
op[2] = operands[2];
op[3] = operands[3];
str[0] = 0;
if (len)
*len = 1;
if (GET_CODE (operands[2]) == CONST_INT)
{
int scratch = (GET_CODE (PATTERN (insn)) == PARALLEL);
int count = INTVAL (operands[2]);
int max_len = 10;
if (count < 8 && !scratch)
use_zero_reg = 1;
if (optimize_size)
max_len = t_len + (scratch ? 3 : (use_zero_reg ? 4 : 5));
if (t_len * count <= max_len)
{
if (len)
*len = t_len * count;
else
{
while (count-- > 0)
output_asm_insn (template, op);
}
return;
}
if (scratch)
{
if (!len)
strcat (str, AS2 (ldi,%3,%2));
}
else if (use_zero_reg)
{
op[3] = zero_reg_rtx;
if (len)
*len = 2;
else
strcat (str, ("set" CR_TAB
AS2 (bld,%3,%2-1)));
}
else
{
op[3] = gen_rtx (REG, QImode,
((true_regnum (operands[0]) - 1) & 15) + 16);
op[4] = tmp_reg_rtx;
saved_in_tmp = 1;
if (len)
*len = 3;
else
strcat (str, (AS2 (mov,%4,%3) CR_TAB
AS2 (ldi,%3,%2)));
}
second_label = 0;
}
else if (GET_CODE (operands[2]) == MEM)
{
rtx op_mov[10];
op[3] = op_mov[0] = tmp_reg_rtx;
op_mov[1] = op[2];
if (len)
out_movqi_r_mr (insn, op_mov, len);
else
output_asm_insn (out_movqi_r_mr (insn, op_mov, NULL), op_mov);
}
else if (register_operand (operands[2], QImode))
{
if (reg_unused_after (insn, operands[2]))
op[3] = op[2];
else
{
op[3] = tmp_reg_rtx;
if (!len)
strcat (str, (AS2 (mov,%3,%2) CR_TAB));
}
}
else
fatal_insn ("bad shift insn:", insn);
if (second_label)
{
if (len)
++*len;
else
strcat (str, AS1 (rjmp,2f));
}
if (len)
*len += t_len + 2;
else
{
strcat (str, "\n1:\t");
strcat (str, template);
strcat (str, second_label ? "\n2:\t" : "\n\t");
strcat (str, use_zero_reg ? AS1 (lsr,%3) : AS1 (dec,%3));
strcat (str, CR_TAB);
strcat (str, second_label ? AS1 (brpl,1b) : AS1 (brne,1b));
if (saved_in_tmp)
strcat (str, (CR_TAB AS2 (mov,%3,%4)));
output_asm_insn (str, op);
}
}
const char *
ashlqi3_out (insn, operands, len)
rtx insn;
rtx operands[];
int *len;
{
if (GET_CODE (operands[2]) == CONST_INT)
{
int k;
if (!len)
len = &k;
switch (INTVAL (operands[2]))
{
default:
*len = 1;
return AS1 (clr,%0);
case 1:
*len = 1;
return AS1 (lsl,%0);
case 2:
*len = 2;
return (AS1 (lsl,%0) CR_TAB
AS1 (lsl,%0));
case 3:
*len = 3;
return (AS1 (lsl,%0) CR_TAB
AS1 (lsl,%0) CR_TAB
AS1 (lsl,%0));
case 4:
if (test_hard_reg_class (LD_REGS, operands[0]))
{
*len = 2;
return (AS1 (swap,%0) CR_TAB
AS2 (andi,%0,0xf0));
}
*len = 4;
return (AS1 (lsl,%0) CR_TAB
AS1 (lsl,%0) CR_TAB
AS1 (lsl,%0) CR_TAB
AS1 (lsl,%0));
case 5:
if (test_hard_reg_class (LD_REGS, operands[0]))
{
*len = 3;
return (AS1 (swap,%0) CR_TAB
AS1 (lsl,%0) CR_TAB
AS2 (andi,%0,0xe0));
}
*len = 5;
return (AS1 (lsl,%0) CR_TAB
AS1 (lsl,%0) CR_TAB
AS1 (lsl,%0) CR_TAB
AS1 (lsl,%0) CR_TAB
AS1 (lsl,%0));
case 6:
if (test_hard_reg_class (LD_REGS, operands[0]))
{
*len = 4;
return (AS1 (swap,%0) CR_TAB
AS1 (lsl,%0) CR_TAB
AS1 (lsl,%0) CR_TAB
AS2 (andi,%0,0xc0));
}
*len = 6;
return (AS1 (lsl,%0) CR_TAB
AS1 (lsl,%0) CR_TAB
AS1 (lsl,%0) CR_TAB
AS1 (lsl,%0) CR_TAB
AS1 (lsl,%0) CR_TAB
AS1 (lsl,%0));
case 7:
*len = 3;
return (AS1 (ror,%0) CR_TAB
AS1 (clr,%0) CR_TAB
AS1 (ror,%0));
}
}
else if (CONSTANT_P (operands[2]))
fatal_insn ("internal compiler error. Incorrect shift:", insn);
out_shift_with_cnt (AS1 (lsl,%0),
insn, operands, len, 1);
return "";
}
const char *
ashlhi3_out (insn, operands, len)
rtx insn;
rtx operands[];
int *len;
{
if (GET_CODE (operands[2]) == CONST_INT)
{
int scratch = (GET_CODE (PATTERN (insn)) == PARALLEL);
int ldi_ok = test_hard_reg_class (LD_REGS, operands[0]);
int k;
int *t = len;
if (!len)
len = &k;
switch (INTVAL (operands[2]))
{
case 4:
if (optimize_size && scratch)
break;
if (ldi_ok)
{
*len = 6;
return (AS1 (swap,%A0) CR_TAB
AS1 (swap,%B0) CR_TAB
AS2 (andi,%B0,0xf0) CR_TAB
AS2 (eor,%B0,%A0) CR_TAB
AS2 (andi,%A0,0xf0) CR_TAB
AS2 (eor,%B0,%A0));
}
if (scratch)
{
*len = 7;
return (AS1 (swap,%A0) CR_TAB
AS1 (swap,%B0) CR_TAB
AS2 (ldi,%3,0xf0) CR_TAB
AS2 (and,%B0,%3) CR_TAB
AS2 (eor,%B0,%A0) CR_TAB
AS2 (and,%A0,%3) CR_TAB
AS2 (eor,%B0,%A0));
}
break;
case 5:
if (optimize_size)
break;
if (ldi_ok)
{
*len = 8;
return (AS1 (lsl,%A0) CR_TAB
AS1 (rol,%B0) CR_TAB
AS1 (swap,%A0) CR_TAB
AS1 (swap,%B0) CR_TAB
AS2 (andi,%B0,0xf0) CR_TAB
AS2 (eor,%B0,%A0) CR_TAB
AS2 (andi,%A0,0xf0) CR_TAB
AS2 (eor,%B0,%A0));
}
if (scratch)
{
*len = 9;
return (AS1 (lsl,%A0) CR_TAB
AS1 (rol,%B0) CR_TAB
AS1 (swap,%A0) CR_TAB
AS1 (swap,%B0) CR_TAB
AS2 (ldi,%3,0xf0) CR_TAB
AS2 (and,%B0,%3) CR_TAB
AS2 (eor,%B0,%A0) CR_TAB
AS2 (and,%A0,%3) CR_TAB
AS2 (eor,%B0,%A0));
}
break;
case 6:
if (optimize_size)
break;
*len = 9;
return (AS1 (clr,__tmp_reg__) CR_TAB
AS1 (lsr,%B0) CR_TAB
AS1 (ror,%A0) CR_TAB
AS1 (ror,__tmp_reg__) CR_TAB
AS1 (lsr,%B0) CR_TAB
AS1 (ror,%A0) CR_TAB
AS1 (ror,__tmp_reg__) CR_TAB
AS2 (mov,%B0,%A0) CR_TAB
AS2 (mov,%A0,__tmp_reg__));
case 7:
*len = 5;
return (AS1 (lsr,%B0) CR_TAB
AS2 (mov,%B0,%A0) CR_TAB
AS1 (clr,%A0) CR_TAB
AS1 (ror,%B0) CR_TAB
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));
case 9:
*len = 3;
return (AS2 (mov,%B0,%A0) CR_TAB
AS1 (clr,%A0) CR_TAB
AS1 (lsl,%B0));
case 10:
*len = 4;
return (AS2 (mov,%B0,%A0) CR_TAB
AS1 (clr,%A0) CR_TAB
AS1 (lsl,%B0) CR_TAB
AS1 (lsl,%B0));
case 11:
*len = 5;
return (AS2 (mov,%B0,%A0) CR_TAB
AS1 (clr,%A0) CR_TAB
AS1 (lsl,%B0) CR_TAB
AS1 (lsl,%B0) CR_TAB
AS1 (lsl,%B0));
case 12:
if (ldi_ok)
{
*len = 4;
return (AS2 (mov,%B0,%A0) CR_TAB
AS1 (clr,%A0) CR_TAB
AS1 (swap,%B0) CR_TAB
AS2 (andi,%B0,0xf0));
}
if (scratch)
{
*len = 5;
return (AS2 (mov,%B0,%A0) CR_TAB
AS1 (clr,%A0) CR_TAB
AS1 (swap,%B0) CR_TAB
AS2 (ldi,%3,0xf0) CR_TAB
AS2 (and,%B0,%3));
}
*len = 6;
return (AS2 (mov,%B0,%A0) CR_TAB
AS1 (clr,%A0) CR_TAB
AS1 (lsl,%B0) CR_TAB
AS1 (lsl,%B0) CR_TAB
AS1 (lsl,%B0) CR_TAB
AS1 (lsl,%B0));
case 13:
if (ldi_ok)
{
*len = 5;
return (AS2 (mov,%B0,%A0) CR_TAB
AS1 (clr,%A0) CR_TAB
AS1 (swap,%B0) CR_TAB
AS1 (lsl,%B0) CR_TAB
AS2 (andi,%B0,0xe0));
}
if (AVR_ENHANCED && scratch)
{
*len = 5;
return (AS2 (ldi,%3,0x20) CR_TAB
AS2 (mul,%A0,%3) CR_TAB
AS2 (mov,%B0,r0) CR_TAB
AS1 (clr,%A0) CR_TAB
AS1 (clr,__zero_reg__));
}
if (optimize_size && scratch)
break;
if (scratch)
{
*len = 6;
return (AS2 (mov,%B0,%A0) CR_TAB
AS1 (clr,%A0) CR_TAB
AS1 (swap,%B0) CR_TAB
AS1 (lsl,%B0) CR_TAB
AS2 (ldi,%3,0xe0) CR_TAB
AS2 (and,%B0,%3));
}
if (AVR_ENHANCED)
{
*len = 6;
return ("set" CR_TAB
AS2 (bld,r1,5) CR_TAB
AS2 (mul,%A0,r1) CR_TAB
AS2 (mov,%B0,r0) CR_TAB
AS1 (clr,%A0) CR_TAB
AS1 (clr,__zero_reg__));
}
*len = 7;
return (AS2 (mov,%B0,%A0) CR_TAB
AS1 (clr,%A0) CR_TAB
AS1 (lsl,%B0) CR_TAB
AS1 (lsl,%B0) CR_TAB
AS1 (lsl,%B0) CR_TAB
AS1 (lsl,%B0) CR_TAB
AS1 (lsl,%B0));
case 14:
if (AVR_ENHANCED && ldi_ok)
{
*len = 5;
return (AS2 (ldi,%B0,0x40) CR_TAB
AS2 (mul,%A0,%B0) CR_TAB
AS2 (mov,%B0,r0) CR_TAB
AS1 (clr,%A0) CR_TAB
AS1 (clr,__zero_reg__));
}
if (AVR_ENHANCED && scratch)
{
*len = 5;
return (AS2 (ldi,%3,0x40) CR_TAB
AS2 (mul,%A0,%3) CR_TAB
AS2 (mov,%B0,r0) CR_TAB
AS1 (clr,%A0) CR_TAB
AS1 (clr,__zero_reg__));
}
if (optimize_size && ldi_ok)
{
*len = 5;
return (AS2 (mov,%B0,%A0) CR_TAB
AS2 (ldi,%A0,6) "\n1:\t"
AS1 (lsl,%B0) CR_TAB
AS1 (dec,%A0) CR_TAB
AS1 (brne,1b));
}
if (optimize_size && scratch)
break;
*len = 6;
return (AS1 (clr,%B0) CR_TAB
AS1 (lsr,%A0) CR_TAB
AS1 (ror,%B0) CR_TAB
AS1 (lsr,%A0) CR_TAB
AS1 (ror,%B0) CR_TAB
AS1 (clr,%A0));
case 15:
*len = 4;
return (AS1 (clr,%B0) CR_TAB
AS1 (lsr,%A0) CR_TAB
AS1 (ror,%B0) CR_TAB
AS1 (clr,%A0));
}
len = t;
}
out_shift_with_cnt ((AS1 (lsl,%A0) CR_TAB
AS1 (rol,%B0)),
insn, operands, len, 2);
return "";
}
const char *
ashlsi3_out (insn, operands, len)
rtx insn;
rtx operands[];
int *len;
{
if (GET_CODE (operands[2]) == CONST_INT)
{
int k;
int *t = len;
if (!len)
len = &k;
switch (INTVAL (operands[2]))
{
case 8:
{
int reg0 = true_regnum (operands[0]);
int reg1 = true_regnum (operands[1]);
*len = 4;
if (reg0 >= reg1)
return (AS2 (mov,%D0,%C1) CR_TAB
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
AS2 (mov,%C0,%B1) CR_TAB
AS2 (mov,%D0,%C1));
}
case 16:
{
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));
}
else
return (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));
}
case 31:
*len = 6;
return (AS1 (clr,%D0) CR_TAB
AS1 (lsr,%A0) CR_TAB
AS1 (ror,%D0) CR_TAB
AS1 (clr,%C0) CR_TAB
AS1 (clr,%B0) CR_TAB
AS1 (clr,%A0));
}
len = t;
}
out_shift_with_cnt ((AS1 (lsl,%A0) CR_TAB
AS1 (rol,%B0) CR_TAB
AS1 (rol,%C0) CR_TAB
AS1 (rol,%D0)),
insn, operands, len, 4);
return "";
}
const char *
ashrqi3_out (insn, operands, len)
rtx insn;
rtx operands[];
int *len;
{
if (GET_CODE (operands[2]) == CONST_INT)
{
int k;
if (!len)
len = &k;
switch (INTVAL (operands[2]))
{
case 1:
*len = 1;
return AS1 (asr,%0);
case 2:
*len = 2;
return (AS1 (asr,%0) CR_TAB
AS1 (asr,%0));
case 3:
*len = 3;
return (AS1 (asr,%0) CR_TAB
AS1 (asr,%0) CR_TAB
AS1 (asr,%0));
case 4:
*len = 4;
return (AS1 (asr,%0) CR_TAB
AS1 (asr,%0) CR_TAB
AS1 (asr,%0) CR_TAB
AS1 (asr,%0));
case 5:
*len = 5;
return (AS1 (asr,%0) CR_TAB
AS1 (asr,%0) CR_TAB
AS1 (asr,%0) CR_TAB
AS1 (asr,%0) CR_TAB
AS1 (asr,%0));
case 6:
*len = 4;
return (AS2 (bst,%0,6) CR_TAB
AS1 (lsl,%0) CR_TAB
AS2 (sbc,%0,%0) CR_TAB
AS2 (bld,%0,0));
default:
case 7:
*len = 2;
return (AS1 (lsl,%0) CR_TAB
AS2 (sbc,%0,%0));
}
}
else if (CONSTANT_P (operands[2]))
fatal_insn ("internal compiler error. Incorrect shift:", insn);
out_shift_with_cnt (AS1 (asr,%0),
insn, operands, len, 1);
return "";
}
const char *
ashrhi3_out (insn, operands, len)
rtx insn;
rtx operands[];
int *len;
{
if (GET_CODE (operands[2]) == CONST_INT)
{
int scratch = (GET_CODE (PATTERN (insn)) == PARALLEL);
int ldi_ok = test_hard_reg_class (LD_REGS, operands[0]);
int k;
int *t = len;
if (!len)
len = &k;
switch (INTVAL (operands[2]))
{
case 4:
case 5:
break;
case 6:
if (optimize_size)
break;
*len = 8;
return (AS2 (mov,__tmp_reg__,%A0) CR_TAB
AS2 (mov,%A0,%B0) CR_TAB
AS1 (lsl,__tmp_reg__) CR_TAB
AS1 (rol,%A0) CR_TAB
AS2 (sbc,%B0,%B0) CR_TAB
AS1 (lsl,__tmp_reg__) CR_TAB
AS1 (rol,%A0) CR_TAB
AS1 (rol,%B0));
case 7:
*len = 4;
return (AS1 (lsl,%A0) CR_TAB
AS2 (mov,%A0,%B0) CR_TAB
AS1 (rol,%A0) CR_TAB
AS2 (sbc,%B0,%B0));
case 8:
{
int reg0 = true_regnum (operands[0]);
int reg1 = true_regnum (operands[1]);
if (reg0 == reg1)
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));
}
case 9:
*len = 4;
return (AS2 (mov,%A0,%B0) CR_TAB
AS1 (lsl,%B0) CR_TAB
AS2 (sbc,%B0,%B0) CR_TAB
AS1 (asr,%A0));
case 10:
*len = 5;
return (AS2 (mov,%A0,%B0) CR_TAB
AS1 (lsl,%B0) CR_TAB
AS2 (sbc,%B0,%B0) CR_TAB
AS1 (asr,%A0) CR_TAB
AS1 (asr,%A0));
case 11:
if (AVR_ENHANCED && ldi_ok)
{
*len = 5;
return (AS2 (ldi,%A0,0x20) CR_TAB
AS2 (muls,%B0,%A0) CR_TAB
AS2 (mov,%A0,r1) CR_TAB
AS2 (sbc,%B0,%B0) CR_TAB
AS1 (clr,__zero_reg__));
}
if (optimize_size && scratch)
break;
*len = 6;
return (AS2 (mov,%A0,%B0) CR_TAB
AS1 (lsl,%B0) CR_TAB
AS2 (sbc,%B0,%B0) CR_TAB
AS1 (asr,%A0) CR_TAB
AS1 (asr,%A0) CR_TAB
AS1 (asr,%A0));
case 12:
if (AVR_ENHANCED && ldi_ok)
{
*len = 5;
return (AS2 (ldi,%A0,0x10) CR_TAB
AS2 (muls,%B0,%A0) CR_TAB
AS2 (mov,%A0,r1) CR_TAB
AS2 (sbc,%B0,%B0) CR_TAB
AS1 (clr,__zero_reg__));
}
if (optimize_size && scratch)
break;
*len = 7;
return (AS2 (mov,%A0,%B0) CR_TAB
AS1 (lsl,%B0) CR_TAB
AS2 (sbc,%B0,%B0) CR_TAB
AS1 (asr,%A0) CR_TAB
AS1 (asr,%A0) CR_TAB
AS1 (asr,%A0) CR_TAB
AS1 (asr,%A0));
case 13:
if (AVR_ENHANCED && ldi_ok)
{
*len = 5;
return (AS2 (ldi,%A0,0x08) CR_TAB
AS2 (muls,%B0,%A0) CR_TAB
AS2 (mov,%A0,r1) CR_TAB
AS2 (sbc,%B0,%B0) CR_TAB
AS1 (clr,__zero_reg__));
}
if (optimize_size)
break;
*len = 8;
return (AS2 (mov,%A0,%B0) CR_TAB
AS1 (lsl,%B0) CR_TAB
AS2 (sbc,%B0,%B0) CR_TAB
AS1 (asr,%A0) CR_TAB
AS1 (asr,%A0) CR_TAB
AS1 (asr,%A0) CR_TAB
AS1 (asr,%A0) CR_TAB
AS1 (asr,%A0));
case 14:
*len = 5;
return (AS1 (lsl,%B0) CR_TAB
AS2 (sbc,%A0,%A0) CR_TAB
AS1 (lsl,%B0) CR_TAB
AS2 (mov,%B0,%A0) CR_TAB
AS1 (rol,%A0));
case 15:
return *len = 3, (AS1 (lsl,%B0) CR_TAB
AS2 (sbc,%A0,%A0) CR_TAB
AS2 (mov,%B0,%A0));
}
len = t;
}
out_shift_with_cnt ((AS1 (asr,%B0) CR_TAB
AS1 (ror,%A0)),
insn, operands, len, 2);
return "";
}
const char *
ashrsi3_out (insn, operands, len)
rtx insn;
rtx operands[];
int *len;
{
if (GET_CODE (operands[2]) == CONST_INT)
{
int k;
int *t = len;
if (!len)
len = &k;
switch (INTVAL (operands[2]))
{
case 8:
{
int reg0 = true_regnum (operands[0]);
int reg1 = true_regnum (operands[1]);
*len=6;
if (reg0 <= reg1)
return (AS2 (mov,%A0,%B1) CR_TAB
AS2 (mov,%B0,%C1) CR_TAB
AS2 (mov,%C0,%D1) 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
AS1 (dec,%D0) CR_TAB
AS2 (mov,%C0,%D1) CR_TAB
AS2 (mov,%B0,%C1) CR_TAB
AS2 (mov,%A0,%B1));
}
case 16:
{
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)
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));
}
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));
case 31:
if (AVR_ENHANCED)
return *len = 4, (AS1 (lsl,%D0) CR_TAB
AS2 (sbc,%A0,%A0) CR_TAB
AS2 (mov,%B0,%A0) CR_TAB
AS2 (movw,%C0,%A0));
else
return *len = 5, (AS1 (lsl,%D0) CR_TAB
AS2 (sbc,%A0,%A0) CR_TAB
AS2 (mov,%B0,%A0) CR_TAB
AS2 (mov,%C0,%A0) CR_TAB
AS2 (mov,%D0,%A0));
}
len = t;
}
out_shift_with_cnt ((AS1 (asr,%D0) CR_TAB
AS1 (ror,%C0) CR_TAB
AS1 (ror,%B0) CR_TAB
AS1 (ror,%A0)),
insn, operands, len, 4);
return "";
}
const char *
lshrqi3_out (insn, operands, len)
rtx insn;
rtx operands[];
int *len;
{
if (GET_CODE (operands[2]) == CONST_INT)
{
int k;
if (!len)
len = &k;
switch (INTVAL (operands[2]))
{
default:
*len = 1;
return AS1 (clr,%0);
case 1:
*len = 1;
return AS1 (lsr,%0);
case 2:
*len = 2;
return (AS1 (lsr,%0) CR_TAB
AS1 (lsr,%0));
case 3:
*len = 3;
return (AS1 (lsr,%0) CR_TAB
AS1 (lsr,%0) CR_TAB
AS1 (lsr,%0));
case 4:
if (test_hard_reg_class (LD_REGS, operands[0]))
{
*len=2;
return (AS1 (swap,%0) CR_TAB
AS2 (andi,%0,0x0f));
}
*len = 4;
return (AS1 (lsr,%0) CR_TAB
AS1 (lsr,%0) CR_TAB
AS1 (lsr,%0) CR_TAB
AS1 (lsr,%0));
case 5:
if (test_hard_reg_class (LD_REGS, operands[0]))
{
*len = 3;
return (AS1 (swap,%0) CR_TAB
AS1 (lsr,%0) CR_TAB
AS2 (andi,%0,0x7));
}
*len = 5;
return (AS1 (lsr,%0) CR_TAB
AS1 (lsr,%0) CR_TAB
AS1 (lsr,%0) CR_TAB
AS1 (lsr,%0) CR_TAB
AS1 (lsr,%0));
case 6:
if (test_hard_reg_class (LD_REGS, operands[0]))
{
*len = 4;
return (AS1 (swap,%0) CR_TAB
AS1 (lsr,%0) CR_TAB
AS1 (lsr,%0) CR_TAB
AS2 (andi,%0,0x3));
}
*len = 6;
return (AS1 (lsr,%0) CR_TAB
AS1 (lsr,%0) CR_TAB
AS1 (lsr,%0) CR_TAB
AS1 (lsr,%0) CR_TAB
AS1 (lsr,%0) CR_TAB
AS1 (lsr,%0));
case 7:
*len = 3;
return (AS1 (rol,%0) CR_TAB
AS1 (clr,%0) CR_TAB
AS1 (rol,%0));
}
}
else if (CONSTANT_P (operands[2]))
fatal_insn ("internal compiler error. Incorrect shift:", insn);
out_shift_with_cnt (AS1 (lsr,%0),
insn, operands, len, 1);
return "";
}
const char *
lshrhi3_out (insn, operands, len)
rtx insn;
rtx operands[];
int *len;
{
if (GET_CODE (operands[2]) == CONST_INT)
{
int scratch = (GET_CODE (PATTERN (insn)) == PARALLEL);
int ldi_ok = test_hard_reg_class (LD_REGS, operands[0]);
int k;
int *t = len;
if (!len)
len = &k;
switch (INTVAL (operands[2]))
{
case 4:
if (optimize_size && scratch)
break;
if (ldi_ok)
{
*len = 6;
return (AS1 (swap,%B0) CR_TAB
AS1 (swap,%A0) CR_TAB
AS2 (andi,%A0,0x0f) CR_TAB
AS2 (eor,%A0,%B0) CR_TAB
AS2 (andi,%B0,0x0f) CR_TAB
AS2 (eor,%A0,%B0));
}
if (scratch)
{
*len = 7;
return (AS1 (swap,%B0) CR_TAB
AS1 (swap,%A0) CR_TAB
AS2 (ldi,%3,0x0f) CR_TAB
AS2 (and,%A0,%3) CR_TAB
AS2 (eor,%A0,%B0) CR_TAB
AS2 (and,%B0,%3) CR_TAB
AS2 (eor,%A0,%B0));
}
break;
case 5:
if (optimize_size)
break;
if (ldi_ok)
{
*len = 8;
return (AS1 (lsr,%B0) CR_TAB
AS1 (ror,%A0) CR_TAB
AS1 (swap,%B0) CR_TAB
AS1 (swap,%A0) CR_TAB
AS2 (andi,%A0,0x0f) CR_TAB
AS2 (eor,%A0,%B0) CR_TAB
AS2 (andi,%B0,0x0f) CR_TAB
AS2 (eor,%A0,%B0));
}
if (scratch)
{
*len = 9;
return (AS1 (lsr,%B0) CR_TAB
AS1 (ror,%A0) CR_TAB
AS1 (swap,%B0) CR_TAB
AS1 (swap,%A0) CR_TAB
AS2 (ldi,%3,0x0f) CR_TAB
AS2 (and,%A0,%3) CR_TAB
AS2 (eor,%A0,%B0) CR_TAB
AS2 (and,%B0,%3) CR_TAB
AS2 (eor,%A0,%B0));
}
break;
case 6:
if (optimize_size)
break;
*len = 9;
return (AS1 (clr,__tmp_reg__) CR_TAB
AS1 (lsl,%A0) CR_TAB
AS1 (rol,%B0) CR_TAB
AS1 (rol,__tmp_reg__) CR_TAB
AS1 (lsl,%A0) CR_TAB
AS1 (rol,%B0) CR_TAB
AS1 (rol,__tmp_reg__) CR_TAB
AS2 (mov,%A0,%B0) CR_TAB
AS2 (mov,%B0,__tmp_reg__));
case 7:
*len = 5;
return (AS1 (lsl,%A0) CR_TAB
AS2 (mov,%A0,%B0) CR_TAB
AS1 (rol,%A0) CR_TAB
AS2 (sbc,%B0,%B0) CR_TAB
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);
case 9:
*len = 3;
return (AS2 (mov,%A0,%B0) CR_TAB
AS1 (clr,%B0) CR_TAB
AS1 (lsr,%A0));
case 10:
*len = 4;
return (AS2 (mov,%A0,%B0) CR_TAB
AS1 (clr,%B0) CR_TAB
AS1 (lsr,%A0) CR_TAB
AS1 (lsr,%A0));
case 11:
*len = 5;
return (AS2 (mov,%A0,%B0) CR_TAB
AS1 (clr,%B0) CR_TAB
AS1 (lsr,%A0) CR_TAB
AS1 (lsr,%A0) CR_TAB
AS1 (lsr,%A0));
case 12:
if (ldi_ok)
{
*len = 4;
return (AS2 (mov,%A0,%B0) CR_TAB
AS1 (clr,%B0) CR_TAB
AS1 (swap,%A0) CR_TAB
AS2 (andi,%A0,0x0f));
}
if (scratch)
{
*len = 5;
return (AS2 (mov,%A0,%B0) CR_TAB
AS1 (clr,%B0) CR_TAB
AS1 (swap,%A0) CR_TAB
AS2 (ldi,%3,0x0f) CR_TAB
AS2 (and,%A0,%3));
}
*len = 6;
return (AS2 (mov,%A0,%B0) CR_TAB
AS1 (clr,%B0) CR_TAB
AS1 (lsr,%A0) CR_TAB
AS1 (lsr,%A0) CR_TAB
AS1 (lsr,%A0) CR_TAB
AS1 (lsr,%A0));
case 13:
if (ldi_ok)
{
*len = 5;
return (AS2 (mov,%A0,%B0) CR_TAB
AS1 (clr,%B0) CR_TAB
AS1 (swap,%A0) CR_TAB
AS1 (lsr,%A0) CR_TAB
AS2 (andi,%A0,0x07));
}
if (AVR_ENHANCED && scratch)
{
*len = 5;
return (AS2 (ldi,%3,0x08) CR_TAB
AS2 (mul,%B0,%3) CR_TAB
AS2 (mov,%A0,r1) CR_TAB
AS1 (clr,%B0) CR_TAB
AS1 (clr,__zero_reg__));
}
if (optimize_size && scratch)
break;
if (scratch)
{
*len = 6;
return (AS2 (mov,%A0,%B0) CR_TAB
AS1 (clr,%B0) CR_TAB
AS1 (swap,%A0) CR_TAB
AS1 (lsr,%A0) CR_TAB
AS2 (ldi,%3,0x07) CR_TAB
AS2 (and,%A0,%3));
}
if (AVR_ENHANCED)
{
*len = 6;
return ("set" CR_TAB
AS2 (bld,r1,3) CR_TAB
AS2 (mul,%B0,r1) CR_TAB
AS2 (mov,%A0,r1) CR_TAB
AS1 (clr,%B0) CR_TAB
AS1 (clr,__zero_reg__));
}
*len = 7;
return (AS2 (mov,%A0,%B0) CR_TAB
AS1 (clr,%B0) CR_TAB
AS1 (lsr,%A0) CR_TAB
AS1 (lsr,%A0) CR_TAB
AS1 (lsr,%A0) CR_TAB
AS1 (lsr,%A0) CR_TAB
AS1 (lsr,%A0));
case 14:
if (AVR_ENHANCED && ldi_ok)
{
*len = 5;
return (AS2 (ldi,%A0,0x04) CR_TAB
AS2 (mul,%B0,%A0) CR_TAB
AS2 (mov,%A0,r1) CR_TAB
AS1 (clr,%B0) CR_TAB
AS1 (clr,__zero_reg__));
}
if (AVR_ENHANCED && scratch)
{
*len = 5;
return (AS2 (ldi,%3,0x04) CR_TAB
AS2 (mul,%B0,%3) CR_TAB
AS2 (mov,%A0,r1) CR_TAB
AS1 (clr,%B0) CR_TAB
AS1 (clr,__zero_reg__));
}
if (optimize_size && ldi_ok)
{
*len = 5;
return (AS2 (mov,%A0,%B0) CR_TAB
AS2 (ldi,%B0,6) "\n1:\t"
AS1 (lsr,%A0) CR_TAB
AS1 (dec,%B0) CR_TAB
AS1 (brne,1b));
}
if (optimize_size && scratch)
break;
*len = 6;
return (AS1 (clr,%A0) CR_TAB
AS1 (lsl,%B0) CR_TAB
AS1 (rol,%A0) CR_TAB
AS1 (lsl,%B0) CR_TAB
AS1 (rol,%A0) CR_TAB
AS1 (clr,%B0));
case 15:
*len = 4;
return (AS1 (clr,%A0) CR_TAB
AS1 (lsl,%B0) CR_TAB
AS1 (rol,%A0) CR_TAB
AS1 (clr,%B0));
}
len = t;
}
out_shift_with_cnt ((AS1 (lsr,%B0) CR_TAB
AS1 (ror,%A0)),
insn, operands, len, 2);
return "";
}
const char *
lshrsi3_out (insn, operands, len)
rtx insn;
rtx operands[];
int *len;
{
if (GET_CODE (operands[2]) == CONST_INT)
{
int k;
int *t = len;
if (!len)
len = &k;
switch (INTVAL (operands[2]))
{
case 8:
{
int reg0 = true_regnum (operands[0]);
int reg1 = true_regnum (operands[1]);
*len = 4;
if (reg0 <= reg1)
return (AS2 (mov,%A0,%B1) CR_TAB
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
AS2 (mov,%B0,%C1) CR_TAB
AS2 (mov,%A0,%B1));
}
case 16:
{
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)
return *len = 2, (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));
}
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));
case 31:
*len = 6;
return (AS1 (clr,%A0) CR_TAB
AS2 (sbrc,%D0,7) CR_TAB
AS1 (inc,%A0) CR_TAB
AS1 (clr,%B0) CR_TAB
AS1 (clr,%C0) CR_TAB
AS1 (clr,%D0));
}
len = t;
}
out_shift_with_cnt ((AS1 (lsr,%D0) CR_TAB
AS1 (ror,%C0) CR_TAB
AS1 (ror,%B0) CR_TAB
AS1 (ror,%A0)),
insn, operands, len, 4);
return "";
}
int
adjust_insn_length (insn, len)
rtx insn;
int len;
{
rtx patt = PATTERN (insn);
rtx set;
if (GET_CODE (patt) == SET)
{
rtx op[10];
op[1] = SET_SRC (patt);
op[0] = SET_DEST (patt);
if (general_operand (op[1], VOIDmode)
&& general_operand (op[0], VOIDmode))
{
switch (GET_MODE (op[0]))
{
case QImode:
output_movqi (insn, op, &len);
break;
case HImode:
output_movhi (insn, op, &len);
break;
case SImode:
case SFmode:
output_movsisf (insn, op, &len);
break;
default:
break;
}
}
else if (op[0] == cc0_rtx && REG_P (op[1]))
{
switch (GET_MODE (op[1]))
{
case HImode: out_tsthi (insn,&len); break;
case SImode: out_tstsi (insn,&len); break;
default: break;
}
}
else if (GET_CODE (op[1]) == AND)
{
if (GET_CODE (XEXP (op[1],1)) == CONST_INT)
{
HOST_WIDE_INT mask = INTVAL (XEXP (op[1],1));
if (GET_MODE (op[1]) == SImode)
len = (((mask & 0xff) != 0xff)
+ ((mask & 0xff00) != 0xff00)
+ ((mask & 0xff0000L) != 0xff0000L)
+ ((mask & 0xff000000L) != 0xff000000L));
else if (GET_MODE (op[1]) == HImode)
len = (((mask & 0xff) != 0xff)
+ ((mask & 0xff00) != 0xff00));
}
}
else if (GET_CODE (op[1]) == IOR)
{
if (GET_CODE (XEXP (op[1],1)) == CONST_INT)
{
HOST_WIDE_INT mask = INTVAL (XEXP (op[1],1));
if (GET_MODE (op[1]) == SImode)
len = (((mask & 0xff) != 0)
+ ((mask & 0xff00) != 0)
+ ((mask & 0xff0000L) != 0)
+ ((mask & 0xff000000L) != 0));
else if (GET_MODE (op[1]) == HImode)
len = (((mask & 0xff) != 0)
+ ((mask & 0xff00) != 0));
}
}
}
set = single_set (insn);
if (set)
{
rtx op[10];
op[1] = SET_SRC (set);
op[0] = SET_DEST (set);
if (GET_CODE (patt) == PARALLEL
&& general_operand (op[1], VOIDmode)
&& general_operand (op[0], VOIDmode))
{
if (XVECLEN (patt, 0) == 2)
op[2] = XVECEXP (patt, 0, 1);
switch (GET_MODE (op[0]))
{
case QImode:
len = 2;
break;
case HImode:
output_reload_inhi (insn, op, &len);
break;
case SImode:
case SFmode:
output_reload_insisf (insn, op, &len);
break;
default:
break;
}
}
else if (GET_CODE (op[1]) == ASHIFT
|| GET_CODE (op[1]) == ASHIFTRT
|| GET_CODE (op[1]) == LSHIFTRT)
{
rtx ops[10];
ops[0] = op[0];
ops[1] = XEXP (op[1],0);
ops[2] = XEXP (op[1],1);
switch (GET_CODE (op[1]))
{
case ASHIFT:
switch (GET_MODE (op[0]))
{
case QImode: ashlqi3_out (insn,ops,&len); break;
case HImode: ashlhi3_out (insn,ops,&len); break;
case SImode: ashlsi3_out (insn,ops,&len); break;
default: break;
}
break;
case ASHIFTRT:
switch (GET_MODE (op[0]))
{
case QImode: ashrqi3_out (insn,ops,&len); break;
case HImode: ashrhi3_out (insn,ops,&len); break;
case SImode: ashrsi3_out (insn,ops,&len); break;
default: break;
}
break;
case LSHIFTRT:
switch (GET_MODE (op[0]))
{
case QImode: lshrqi3_out (insn,ops,&len); break;
case HImode: lshrhi3_out (insn,ops,&len); break;
case SImode: lshrsi3_out (insn,ops,&len); break;
default: break;
}
break;
default:
break;
}
}
}
return len;
}
int
reg_unused_after (insn, reg)
rtx insn;
rtx reg;
{
return (dead_or_set_p (insn, reg)
|| (REG_P(reg) && _reg_unused_after (insn, reg)));
}
int
_reg_unused_after (insn, reg)
rtx insn;
rtx reg;
{
enum rtx_code code;
rtx set;
set = single_set (insn);
if (set && GET_CODE (SET_DEST (set)) != MEM
&& reg_overlap_mentioned_p (reg, SET_DEST (set)))
return 1;
while ((insn = NEXT_INSN (insn)))
{
code = GET_CODE (insn);
#if 0
if (code == CODE_LABEL)
return 1;
#endif
if (code == JUMP_INSN)
return 0;
else if (code == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
{
int i;
int retval = 0;
for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
{
rtx this_insn = XVECEXP (PATTERN (insn), 0, i);
rtx set = single_set (this_insn);
if (GET_CODE (this_insn) == CALL_INSN)
code = CALL_INSN;
else if (GET_CODE (this_insn) == JUMP_INSN)
{
if (INSN_ANNULLED_BRANCH_P (this_insn))
return 0;
code = JUMP_INSN;
}
if (set && reg_overlap_mentioned_p (reg, SET_SRC (set)))
return 0;
if (set && reg_overlap_mentioned_p (reg, SET_DEST (set)))
{
if (GET_CODE (SET_DEST (set)) != MEM)
retval = 1;
else
return 0;
}
if (set == 0
&& reg_overlap_mentioned_p (reg, PATTERN (this_insn)))
return 0;
}
if (retval == 1)
return 1;
else if (code == JUMP_INSN)
return 0;
}
if (code == CALL_INSN)
{
rtx tem;
for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
if (GET_CODE (XEXP (tem, 0)) == USE
&& REG_P (XEXP (XEXP (tem, 0), 0))
&& reg_overlap_mentioned_p (reg, XEXP (XEXP (tem, 0), 0)))
return 0;
if (call_used_regs[REGNO (reg)])
return 1;
}
if (GET_RTX_CLASS (code) == 'i')
{
rtx 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;
}
}
return 1;
}
static bool
avr_assemble_integer (x, size, aligned_p)
rtx x;
unsigned int size;
int aligned_p;
{
if (size == POINTER_SIZE / BITS_PER_UNIT && aligned_p
&& ((GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FLAG (x))
|| GET_CODE (x) == LABEL_REF))
{
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);
}
void
unique_section (decl, reloc)
tree decl;
int reloc ATTRIBUTE_UNUSED;
{
int len;
const char *name, *prefix;
char *string;
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
STRIP_NAME_ENCODING (name, 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);
}
}
void
gas_output_limited_string(file, str)
FILE *file;
const char * str;
{
const unsigned char *_limited_str = (unsigned char *) str;
unsigned ch;
fprintf (file, "%s\"", STRING_ASM_OP);
for (; (ch = *_limited_str); _limited_str++)
{
int escape;
switch (escape = ESCAPES[ch])
{
case 0:
putc (ch, file);
break;
case 1:
fprintf (file, "\\%03o", ch);
break;
default:
putc ('\\', file);
putc (escape, file);
break;
}
}
fprintf (file, "\"\n");
}
void
gas_output_ascii(file, str, length)
FILE * file;
const char * str;
size_t length;
{
const unsigned char *_ascii_bytes = (const unsigned char *) str;
const unsigned char *limit = _ascii_bytes + length;
unsigned bytes_in_chunk = 0;
for (; _ascii_bytes < limit; _ascii_bytes++)
{
const unsigned char *p;
if (bytes_in_chunk >= 60)
{
fprintf (file, "\"\n");
bytes_in_chunk = 0;
}
for (p = _ascii_bytes; p < limit && *p != '\0'; p++)
continue;
if (p < limit && (p - _ascii_bytes) <= (signed)STRING_LIMIT)
{
if (bytes_in_chunk > 0)
{
fprintf (file, "\"\n");
bytes_in_chunk = 0;
}
gas_output_limited_string (file, (char*)_ascii_bytes);
_ascii_bytes = p;
}
else
{
int escape;
unsigned ch;
if (bytes_in_chunk == 0)
fprintf (file, "\t.ascii\t\"");
switch (escape = ESCAPES[ch = *_ascii_bytes])
{
case 0:
putc (ch, file);
bytes_in_chunk++;
break;
case 1:
fprintf (file, "\\%03o", ch);
bytes_in_chunk += 4;
break;
default:
putc ('\\', file);
putc (escape, file);
bytes_in_chunk += 2;
break;
}
}
}
if (bytes_in_chunk > 0)
fprintf (file, "\"\n");
}
enum reg_class
class_likely_spilled_p (c)
int c;
{
return (c != ALL_REGS && c != ADDW_REGS);
}
const struct attribute_spec avr_attribute_table[] =
{
{ "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 }
};
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 (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 ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
*no_add_attrs = true;
}
}
return NULL_TREE;
}
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;
}
int
avr_progmem_p (decl)
tree decl;
{
tree a;
if (TREE_CODE (decl) != VAR_DECL)
return 0;
if (NULL_TREE
!= lookup_attribute ("progmem", DECL_ATTRIBUTES (decl)))
return 1;
a=decl;
do
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;
return 0;
}
void
encode_section_info (decl)
tree decl;
{
if (TREE_CODE (decl) == FUNCTION_DECL)
SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
else if ((TREE_STATIC (decl) || DECL_EXTERNAL (decl))
&& TREE_CODE (decl) == VAR_DECL
&& avr_progmem_p (decl))
{
static const char *const dsec = ".progmem.data";
DECL_SECTION_NAME (decl) = build_string (strlen (dsec), dsec);
TREE_READONLY (decl) = 1;
}
}
void
asm_file_start (file)
FILE *file;
{
output_file_directive (file, main_input_filename);
fprintf (file, "\t.arch %s\n", avr_mcu_name);
fputs ("__SREG__ = 0x3f\n"
"__SP_H__ = 0x3e\n"
"__SP_L__ = 0x3d\n", file);
fputs ("__tmp_reg__ = 0\n"
"__zero_reg__ = 1\n"
"_PC_ = 2\n", file);
commands_in_file = 0;
commands_in_prologues = 0;
commands_in_epilogues = 0;
}
void
asm_file_end (file)
FILE *file;
{
fprintf (file,
"/* File %s: code %4d = 0x%04x (%4d), prologues %3d, epilogues %3d */\n",
main_input_filename,
commands_in_file,
commands_in_file,
commands_in_file - commands_in_prologues - commands_in_epilogues,
commands_in_prologues, commands_in_epilogues);
}
void
order_regs_for_local_alloc ()
{
unsigned int i;
static const int order_0[] = {
24,25,
18,19,
20,21,
22,23,
30,31,
26,27,
28,29,
17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,
0,1,
32,33,34,35
};
static const int order_1[] = {
18,19,
20,21,
22,23,
24,25,
30,31,
26,27,
28,29,
17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,
0,1,
32,33,34,35
};
static const int order_2[] = {
25,24,
23,22,
21,20,
19,18,
30,31,
26,27,
28,29,
17,16,
15,14,13,12,11,10,9,8,7,6,5,4,3,2,
1,0,
32,33,34,35
};
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];
}
int
default_rtx_costs (X, code, outer_code)
rtx X;
enum rtx_code code;
enum rtx_code outer_code;
{
int cost=0;
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 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;
default:
break;
}
return cost;
}
int
avr_address_cost (x)
rtx x;
{
if (GET_CODE (x) == PLUS
&& GET_CODE (XEXP (x,1)) == CONST_INT
&& (REG_P (XEXP (x,0)) || GET_CODE (XEXP (x,0)) == SUBREG)
&& INTVAL (XEXP (x,1)) >= 61)
return 18;
if (CONSTANT_ADDRESS_P (x))
{
if (io_address_p (x, 1))
return 2;
return 4;
}
return 4;
}
int
extra_constraint (x, c)
rtx x;
int c;
{
if (c == 'Q'
&& GET_CODE (x) == MEM
&& GET_CODE (XEXP (x,0)) == PLUS)
{
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)
{
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;
else if (regno == REG_Z || regno == REG_Y)
return 1;
else if (xx == frame_pointer_rtx
|| xx == arg_pointer_rtx)
return 1;
}
}
return 0;
}
RTX_CODE
avr_normalize_condition (condition)
RTX_CODE condition;
{
switch (condition)
{
case GT:
return GE;
case GTU:
return GEU;
case LE:
return LT;
case LEU:
return LTU;
default:
abort ();
}
}
void
machine_dependent_reorg (first_insn)
rtx first_insn;
{
rtx insn, pattern;
for (insn = first_insn; insn; insn = NEXT_INSN (insn))
{
if (! (GET_CODE (insn) == INSN
|| GET_CODE (insn) == CALL_INSN
|| GET_CODE (insn) == JUMP_INSN)
|| !single_set (insn))
continue;
pattern = PATTERN (insn);
if (GET_CODE (pattern) == PARALLEL)
pattern = XVECEXP (pattern, 0, 0);
if (GET_CODE (pattern) == SET
&& SET_DEST (pattern) == cc0_rtx
&& compare_diff_p (insn))
{
if (GET_CODE (SET_SRC (pattern)) == COMPARE)
{
pattern = SET_SRC (pattern);
if (true_regnum (XEXP (pattern,0)) >= 0
&& true_regnum (XEXP (pattern,1)) >= 0 )
{
rtx x = XEXP (pattern,0);
rtx next = next_real_insn (insn);
rtx pat = PATTERN (next);
rtx src = SET_SRC (pat);
rtx t = XEXP (src,0);
PUT_CODE (t, swap_condition (GET_CODE (t)));
XEXP (pattern,0) = XEXP (pattern,1);
XEXP (pattern,1) = x;
INSN_CODE (next) = -1;
}
else if (true_regnum (XEXP (pattern,0)) >= 0
&& GET_CODE (XEXP (pattern,1)) == CONST_INT)
{
rtx x = XEXP (pattern,1);
rtx next = next_real_insn (insn);
rtx pat = PATTERN (next);
rtx src = SET_SRC (pat);
rtx t = XEXP (src,0);
if (avr_simplify_comparision_p (GET_MODE (XEXP (pattern,0)),
GET_CODE (t), x))
{
XEXP (pattern,1) = GEN_INT (INTVAL (x)+1);
PUT_CODE (t, avr_normalize_condition (GET_CODE (t)));
INSN_CODE (next) = -1;
INSN_CODE (insn) = -1;
}
}
}
else if (true_regnum (SET_SRC (pattern)) >= 0)
{
rtx next = next_real_insn (insn);
rtx pat = PATTERN (next);
rtx src = SET_SRC (pat);
rtx t = XEXP (src,0);
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;
}
}
}
}
int
avr_ret_register ()
{
return 24;
}
rtx
avr_libcall_value (mode)
enum machine_mode mode;
{
int offs = GET_MODE_SIZE (mode);
if (offs < 2)
offs = 2;
return gen_rtx (REG, mode, RET_REGISTER + 2 - offs);
}
rtx
avr_function_value (type, func)
tree type;
tree func ATTRIBUTE_UNUSED;
{
unsigned int offs;
if (TYPE_MODE (type) != BLKmode)
return avr_libcall_value (TYPE_MODE (type));
offs = int_size_in_bytes (type);
if (offs < 2)
offs = 2;
if (offs > 2 && offs < GET_MODE_SIZE (SImode))
offs = GET_MODE_SIZE (SImode);
else if (offs > GET_MODE_SIZE (SImode) && offs < GET_MODE_SIZE (DImode))
offs = GET_MODE_SIZE (DImode);
return gen_rtx (REG, BLKmode, RET_REGISTER + 2 - offs);
}
int
mask_one_bit_p (mask)
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;
}
enum reg_class
preferred_reload_class (x, class)
rtx x ATTRIBUTE_UNUSED;
enum reg_class class;
{
return class;
}
int
test_hard_reg_class (class, x)
enum reg_class class;
rtx x;
{
int regno = true_regnum (x);
if (regno < 0)
return 0;
return TEST_HARD_REG_CLASS (class, regno);
}
void
debug_hard_reg_set (set)
HARD_REG_SET set;
{
int i;
for (i=0; i < FIRST_PSEUDO_REGISTER; ++i)
{
if (TEST_HARD_REG_BIT (set, i))
{
fprintf (stderr, "r%-2d ", i);
}
}
fprintf (stderr, "\n");
}
int
jump_over_one_insn_p (insn, dest)
rtx insn;
rtx dest;
{
int uid = INSN_UID (GET_CODE (dest) == LABEL_REF
? XEXP (dest, 0)
: dest);
int jump_addr = INSN_ADDRESSES (INSN_UID (insn));
int dest_addr = INSN_ADDRESSES (uid);
return dest_addr - jump_addr == 2;
}
int
avr_hard_regno_mode_ok (regno, mode)
int regno;
enum machine_mode mode;
{
if (mode == QImode)
return 1;
return !(regno & 1);
}
static int
reg_was_0 (insn, op)
rtx insn;
rtx op;
{
rtx link;
return (optimize > 0 && insn && op && REG_P (op)
&& (link = find_reg_note (insn, REG_WAS_0, 0))
&& ! INSN_DELETED_P (XEXP (link, 0))
&& GET_CODE (XEXP (link, 0)) != NOTE
&& no_labels_between_p (XEXP (link, 0), insn)
&& ! reg_set_between_p (op, XEXP (link, 0), insn));
}
static int
io_address_p (x, size)
rtx x;
int size;
{
return (optimize > 0 && GET_CODE (x) == CONST_INT
&& INTVAL (x) >= 0x20 && INTVAL (x) <= 0x60 - size);
}
int
const_int_pow2_p (x)
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 (insn, operands, len)
rtx insn ATTRIBUTE_UNUSED;
rtx *operands;
int *len;
{
int tmp;
if (!len)
len = &tmp;
if (GET_CODE (operands[1]) == CONST_INT)
{
int val = INTVAL (operands[1]);
if ((val & 0xff) == 0)
{
*len = 3;
return (AS2 (mov,%A0,__zero_reg__) CR_TAB
AS2 (ldi,%2,hi8(%1)) CR_TAB
AS2 (mov,%B0,%2));
}
else if ((val & 0xff00) == 0)
{
*len = 3;
return (AS2 (ldi,%2,lo8(%1)) CR_TAB
AS2 (mov,%A0,%2) CR_TAB
AS2 (mov,%B0,__zero_reg__));
}
else if ((val & 0xff) == ((val & 0xff00) >> 8))
{
*len = 3;
return (AS2 (ldi,%2,lo8(%1)) CR_TAB
AS2 (mov,%A0,%2) CR_TAB
AS2 (mov,%B0,%2));
}
}
*len = 4;
return (AS2 (ldi,%2,lo8(%1)) CR_TAB
AS2 (mov,%A0,%2) CR_TAB
AS2 (ldi,%2,hi8(%1)) CR_TAB
AS2 (mov,%B0,%2));
}
const char *
output_reload_insisf (insn, operands, len)
rtx insn ATTRIBUTE_UNUSED;
rtx *operands;
int *len;
{
rtx src = operands[1];
int cnst = (GET_CODE (src) == CONST_INT);
if (len)
{
if (cnst)
*len = 4 + ((INTVAL (src) & 0xff) != 0)
+ ((INTVAL (src) & 0xff00) != 0)
+ ((INTVAL (src) & 0xff0000) != 0)
+ ((INTVAL (src) & 0xff000000) != 0);
else
*len = 8;
return "";
}
if (cnst && ((INTVAL (src) & 0xff) == 0))
output_asm_insn (AS2 (mov, %A0, __zero_reg__), operands);
else
{
output_asm_insn (AS2 (ldi, %2, lo8(%1)), operands);
output_asm_insn (AS2 (mov, %A0, %2), operands);
}
if (cnst && ((INTVAL (src) & 0xff00) == 0))
output_asm_insn (AS2 (mov, %B0, __zero_reg__), operands);
else
{
output_asm_insn (AS2 (ldi, %2, hi8(%1)), operands);
output_asm_insn (AS2 (mov, %B0, %2), operands);
}
if (cnst && ((INTVAL (src) & 0xff0000) == 0))
output_asm_insn (AS2 (mov, %C0, __zero_reg__), operands);
else
{
output_asm_insn (AS2 (ldi, %2, hlo8(%1)), operands);
output_asm_insn (AS2 (mov, %C0, %2), operands);
}
if (cnst && ((INTVAL (src) & 0xff000000) == 0))
output_asm_insn (AS2 (mov, %D0, __zero_reg__), operands);
else
{
output_asm_insn (AS2 (ldi, %2, hhi8(%1)), operands);
output_asm_insn (AS2 (mov, %D0, %2), operands);
}
return "";
}
void
avr_output_bld (operands, bit_nr)
rtx operands[];
int bit_nr;
{
static char s[] = "bld %A0,0";
s[5] = 'A' + (bit_nr >> 3);
s[8] = '0' + (bit_nr & 7);
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++;
}
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;
}