/* Subroutines for insn-output.c for ATMEL AVR micro controllers
- Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
Contributed by Denis Chertykov (denisc@overta.ru)
This file is part of GNU CC.
#include "real.h"
#include "insn-config.h"
#include "conditions.h"
-#include "insn-flags.h"
#include "output.h"
#include "insn-attr.h"
#include "flags.h"
#include "function.h"
#include "recog.h"
#include "tm_p.h"
+#include "target.h"
+#include "target-def.h"
+/* Maximal allowed offset for an address in the LD command */
+#define MAX_LD_OFFSET(MODE) (64 - (signed)GET_MODE_SIZE (MODE))
static int avr_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 char * ptrreg_to_str PARAMS ((int));
-static char * cond_string PARAMS ((enum rtx_code));
-
+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));
/* Allocate registers from r25 to r8 for parameters for function calls */
#define FIRST_CUM_REG 26
/* Zeroed register RTX (gen_rtx (REG,QImode,ZERO_REGNO)) */
rtx zero_reg_rtx;
+/* RTX for register which will be used for loading immediate values to
+ r0-r15 registers. */
+rtx ldi_reg_rtx;
+
/* AVR register names {"r0", "r1", ..., "r31"} */
-char * avr_regnames[] = REGISTER_NAMES;
+static const char *const avr_regnames[] = REGISTER_NAMES;
/* This holds the last insn address. */
static int last_insn_address = 0;
static int prologue_size;
static int epilogue_size;
-/* Initial stack value specified by the `-minit-stack=' option */
-const char *avr_ram_end = NULL;
+/* Size of all jump tables in the current function, in words. */
+static int jump_tables_size;
-/* Numeric representation */
-static const char *initial_stack;
+/* Initial stack value specified by the `-minit-stack=' option */
+const char *avr_init_stack = "__stack";
/* Default MCU name */
-const char *avr_mcu_name = "at90s8515";
-
-/* Default MCU */
-struct mcu_type_s *avr_mcu_type;
-
-/* MCU names, initial stack value, flag 'mega' */
-static struct mcu_type_s mcu_types[] =
-{{"at90s2313", 224-1, 0},
- {"at90s2323", 224-1, 0},
- {"at90s2333", 224-1, 0},
- {"attiny22", 224-1, 0},
- {"at90s2343", 224-1, 0},
- {"at90s4433", 224-1, 0},
- {"at90s4414", 0x15f, 0},
- {"at90s4434", 0x15f, 0},
- {"at90s8515", 0x25f, 0},
- {"at90s8535", 0x25f, 0},
- {"atmega603", 0x0fff,1},
- {"atmega103", 0x0fff,1},
- {NULL,0,0}};
-
-/* Setup MCU */
+const char *avr_mcu_name = "avr2";
+
+/* More than 8K of program memory: use "call" and "jmp". */
+int avr_mega_p = 0;
+
+/* Enhanced core: use "movw", "mul", ... */
+int avr_enhanced_p = 0;
+
+enum avr_arch {
+ AVR1 = 1,
+ AVR2,
+ AVR3,
+ AVR4,
+ AVR5
+};
+struct mcu_type_s {
+ const char *const name;
+ const enum avr_arch arch;
+};
+
+/* List of all known AVR MCU types - if updated, it has to be kept
+ in sync in several places (FIXME: is there a better way?):
+ - here
+ - avr.h (CPP_SPEC, LINK_SPEC, CRT_BINUTILS_SPECS)
+ - t-avr (MULTILIB_MATCHES)
+ - gas/config/tc-avr.c
+ - avr-libc */
+
+static const struct mcu_type_s avr_mcu_types[] = {
+ /* Classic, <= 8K. */
+ { "avr2", AVR2 },
+ { "at90s2313", AVR2 },
+ { "at90s2323", AVR2 },
+ { "attiny22", AVR2 },
+ { "at90s2333", AVR2 },
+ { "at90s2343", AVR2 },
+ { "at90s4414", AVR2 },
+ { "at90s4433", AVR2 },
+ { "at90s4434", AVR2 },
+ { "at90s8515", AVR2 },
+ { "at90c8534", AVR2 },
+ { "at90s8535", AVR2 },
+ /* Classic, > 8K. */
+ { "avr3", AVR3 },
+ { "atmega103", AVR3 },
+ { "atmega603", AVR3 },
+ /* Enhanced, <= 8K. */
+ { "avr4", AVR4 },
+ { "atmega83", AVR4 },
+ { "atmega85", AVR4 },
+ /* Enhanced, > 8K. */
+ { "avr5", AVR5 },
+ { "atmega161", AVR5 },
+ { "atmega163", AVR5 },
+ { "atmega32", AVR5 },
+ { "at94k", AVR5 },
+ /* Assembler only. */
+ { "avr1", AVR1 },
+ { "at90s1200", AVR1 },
+ { "attiny10", AVR1 },
+ { "attiny11", AVR1 },
+ { "attiny12", AVR1 },
+ { "attiny15", AVR1 },
+ { "attiny28", AVR1 },
+ { NULL, 0 }
+};
+
+int avr_case_values_threshold = 30000;
+\f
+/* Initialize the GCC target structure. */
+#undef TARGET_ASM_ALIGNED_HI_OP
+#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
+#undef TARGET_ASM_INTEGER
+#define TARGET_ASM_INTEGER avr_assemble_integer
+
+#undef TARGET_ASM_FUNCTION_PROLOGUE
+#define TARGET_ASM_FUNCTION_PROLOGUE avr_output_function_prologue
+#undef TARGET_ASM_FUNCTION_EPILOGUE
+#define TARGET_ASM_FUNCTION_EPILOGUE avr_output_function_epilogue
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE avr_attribute_table
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+\f
void
-avr_override_options (void)
+avr_override_options ()
{
- for (avr_mcu_type = mcu_types; avr_mcu_type->name; ++avr_mcu_type)
- if (strcmp (avr_mcu_type->name, avr_mcu_name) == 0)
+ const struct mcu_type_s *t;
+
+ for (t = avr_mcu_types; t->name; t++)
+ if (strcmp (t->name, avr_mcu_name) == 0)
break;
- if (!avr_mcu_type->name)
+
+ 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)
{
- int i;
- fprintf (stderr,
- "Wrong mcu `%s' specified\n"
- "Allowed mcu's:\n", avr_mcu_name);
- for (i = 0; mcu_types[i].name; ++i)
- fprintf (stderr," %s\n", mcu_types[i].name);
- fatal ("select right mcu name");
+ case AVR1:
+ default:
+ error ("MCU `%s' not supported", avr_mcu_name);
+ /* ... fall through ... */
+ case AVR2: avr_enhanced_p = 0; avr_mega_p = 0; break;
+ case AVR3: avr_enhanced_p = 0; avr_mega_p = 1; break;
+ case AVR4: avr_enhanced_p = 1; avr_mega_p = 0; break;
+ case AVR5: avr_enhanced_p = 1; avr_mega_p = 1; break;
}
+
+ if (optimize && !TARGET_NO_TABLEJUMP)
+ avr_case_values_threshold = (!AVR_MEGA || TARGET_CALL_PROLOGUES) ? 8 : 17;
}
+
/* Initialize TMP_REG_RTX and ZERO_REG_RTX */
void
-avr_init_once (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 (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;
}
/* return register class from register number */
-static int reg_class_tab[]={
+static const int reg_class_tab[]={
GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,
GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,
GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,
if (TREE_CODE (func) != FUNCTION_DECL)
abort ();
- a = lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (func));
+ a = lookup_attribute ("naked", DECL_ATTRIBUTES (func));
return a != NULL_TREE;
}
if (TREE_CODE (func) != FUNCTION_DECL)
return 0;
- a = lookup_attribute ("interrupt", DECL_MACHINE_ATTRIBUTES (func));
+ a = lookup_attribute ("interrupt", DECL_ATTRIBUTES (func));
return a != NULL_TREE;
}
-/* Return nonzero if FUNC is an signal function as specified
+/* Return nonzero if FUNC is a signal function as specified
by the "signal" attribute. */
static int
if (TREE_CODE (func) != FUNCTION_DECL)
return 0;
- a = lookup_attribute ("signal", DECL_MACHINE_ATTRIBUTES (func));
+ a = lookup_attribute ("signal", DECL_ATTRIBUTES (func));
return a != NULL_TREE;
}
/* Compute offset between arg_pointer and frame_pointer */
int
-initial_elimination_offset (from,to)
- int from ATTRIBUTE_UNUSED;
- int to ATTRIBUTE_UNUSED;
+initial_elimination_offset (from, to)
+ int from;
+ int to;
{
int reg;
- 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 (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
+ return 0;
+ else
{
- 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)))))
+ 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)
{
- ++offset;
+ 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 get_frame_size () + 2 + 1 + offset;
+ return 0;
}
/* This function checks sequence of live registers */
}
+/* Output to FILE the asm instructions to adjust the frame pointer by
+ ADJ (r29:r28 -= ADJ;) which can be positive (prologue) or negative
+ (epilogue). Returns the number of instructions generated. */
+
+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);
+
+ /* The high byte (r29) doesn't change - prefer "subi" (1 cycle)
+ over "sbiw" (2 cycles, same size). */
+
+ 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;
+}
+
+
+/* Output to FILE the asm instructions to copy r29:r28 to SPH:SPL,
+ handling various cases of interrupt enable flag state BEFORE and AFTER
+ (0=disabled, 1=enabled, -1=unknown/unchanged) and target_flags.
+ Returns the number of instructions generated. */
+
+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;
+
+ /* The logic here is so that -mno-interrupts actually means
+ "it is safe to write SPH in one instruction, then SPL in the
+ next instruction, without disabling interrupts first".
+ The after != -1 case (interrupt/signal) is not affected. */
+
+ 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++;
+ }
+
+ /* Do SPH first - maybe this will disable interrupts for one instruction
+ someday (a suggestion has been sent to avr@atmel.com for consideration
+ in future devices - that would make -mno-interrupts always safe). */
+ if (do_sph)
+ {
+ fprintf (file, AS2 (out, __SP_H__, r29) CR_TAB);
+ size++;
+ }
+
+ /* Set/restore the I flag now - interrupts will be really enabled only
+ after the next instruction. This is not clearly documented, but
+ believed to be true for all AVR devices. */
+ if (do_save)
+ {
+ fprintf (file, AS2 (out, __SREG__, __tmp_reg__) CR_TAB);
+ size++;
+ }
+ else if (do_sei)
+ {
+ fprintf (file, "sei" CR_TAB);
+ size++;
+ }
+
+ fprintf (file, AS2 (out, __SP_L__, r28) "\n");
+
+ return size;
+}
+
+
/* Output function prologue */
-void
-function_prologue (FILE *file, int size)
+static void
+avr_output_function_prologue (file, size)
+ FILE *file;
+ HOST_WIDE_INT size;
{
int reg;
int interrupt_func_p;
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 = ! strcmp ("main", current_function_name);
+ 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 (main_p)
{
fprintf (file, ("\t"
- AS2 (ldi, r28, lo8(%s - %d)) CR_TAB
- AS2 (ldi, r29, hi8(%s - %d)) CR_TAB
- AS2 (out,__SP_L__,r28) CR_TAB
- AS2 (out,__SP_H__,r29) "\n"),
- initial_stack, size, initial_stack, size);
+ 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, %d) CR_TAB
- AS2 (ldi, r27, %d) CR_TAB), size & 0xff, size / 0x100);
+ 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)
prologue_size += 4;
if (size)
{
- if (size > 63)
- {
- fprintf (file, ("\t"
- AS2 (subi,r28,%d) CR_TAB
- AS2 (sbci,r29,%d) CR_TAB)
- , size & 0xff, size / 0x100);
- prologue_size += 2;
- }
- else
- {
- fprintf (file, "\t" AS2 (sbiw,r28,%d) CR_TAB, size);
- ++prologue_size;
- }
+ fputs ("\t", file);
+ prologue_size += out_adj_frame_ptr (file, size);
+
if (interrupt_func_p)
{
- fprintf (file,
- "cli" CR_TAB
- AS2 (out,__SP_L__,r28) CR_TAB
- "sei" CR_TAB
- AS2 (out,__SP_H__,r29) "\n");
- prologue_size += 4;
+ prologue_size += out_set_stack_ptr (file, 1, 1);
}
- else if (signal_func_p || TARGET_NO_INTERRUPTS)
+ else if (signal_func_p)
{
- fprintf (file,
- AS2 (out,__SP_L__,r28) CR_TAB
- AS2 (out,__SP_H__,r29) "\n");
- prologue_size += 2;
+ prologue_size += out_set_stack_ptr (file, 0, 0);
}
else
{
- fprintf (file,
- AS2 (in,__tmp_reg__,__SREG__) CR_TAB
- "cli" CR_TAB
- AS2 (out,__SP_L__,r28) CR_TAB
- AS2 (out,__SREG__,__tmp_reg__) CR_TAB
- AS2 (out,__SP_H__,r29) "\n");
- prologue_size += 5;
+ prologue_size += out_set_stack_ptr (file, -1, -1);
}
}
}
/* Output function epilogue */
-void
-function_epilogue (FILE *file, int size)
+static void
+avr_output_function_epilogue (file, size)
+ FILE *file;
+ HOST_WIDE_INT size;
{
int reg;
int interrupt_func_p;
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 = ! strcmp ("main", current_function_name);
- function_size = (insn_addresses[INSN_UID (get_last_insn ())]
- - insn_addresses[INSN_UID (get_insns ())]);
+ 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;
if (frame_pointer_needed)
{
- if (size)
- {
- if (size > 63)
- {
- fprintf (file, AS2 (subi,r28,lo8(-%d)) CR_TAB, size);
- fprintf (file, AS2 (sbci,r29,hi8(-%d)) CR_TAB, size);
- epilogue_size += 2;
- }
- else
- {
- fprintf (file, AS2 (adiw,r28,%d) CR_TAB, size);
- ++epilogue_size;
- }
- }
+ epilogue_size += out_adj_frame_ptr (file, -size);
}
else
{
{
if (size)
{
- if (size > 63)
- {
- fprintf (file, "\t" AS2 (subi,r28,lo8(-%d)) CR_TAB, size);
- fprintf (file, AS2 (sbci,r29,hi8(-%d)) CR_TAB, size);
- epilogue_size += 2;
- }
- else
- {
- fprintf (file, "\t" AS2 (adiw,r28,%d) CR_TAB, size);
- ++epilogue_size;
- }
+ fputs ("\t", file);
+ epilogue_size += out_adj_frame_ptr (file, -size);
+
if (interrupt_func_p | signal_func_p)
{
- fprintf (file,
- "cli" CR_TAB
- AS2 (out,__SP_L__,r28) CR_TAB
- AS2 (out,__SP_H__,r29) "\n");
- epilogue_size += 3;
- }
- else if (TARGET_NO_INTERRUPTS)
- {
- fprintf (file,
- AS2 (out,__SP_L__,r28) CR_TAB
- AS2 (out,__SP_H__,r29) "\n");
- epilogue_size += 2;
+ epilogue_size += out_set_stack_ptr (file, -1, 0);
}
else
{
- fprintf (file,
- AS2 (in,__tmp_reg__,__SREG__) CR_TAB
- "cli" CR_TAB
- AS2 (out,__SP_L__,r28) CR_TAB
- AS2 (out,__SREG__,__tmp_reg__) CR_TAB
- AS2 (out,__SP_H__,r29) "\n");
- epilogue_size += 5;
+ epilogue_size += out_set_stack_ptr (file, -1, -1);
}
}
fprintf (file, "\t"
rtx x;
int strict;
{
- int r = 0;
+ enum reg_class r = NO_REGS;
+
if (TARGET_ALL_DEBUG)
{
fprintf (stderr, "mode: (%s) %s %s %s %s:",
&& REG_P (XEXP (x, 0))
&& GET_CODE (XEXP (x, 1)) == CONST_INT
&& INTVAL (XEXP (x, 1)) >= 0
- && INTVAL (XEXP (x, 1)) <= (64 - GET_MODE_SIZE (mode))
+ && INTVAL (XEXP (x, 1)) <= MAX_LD_OFFSET (mode)
&& reg_renumber
)
fprintf (stderr, "(r%d ---> r%d)", REGNO (XEXP (x, 0)),
}
if (REG_P (x) && (strict ? REG_OK_FOR_BASE_STRICT_P (x)
: REG_OK_FOR_BASE_NOSTRICT_P (x)))
- r = 'R';
+ r = POINTER_REGS;
else if (CONSTANT_ADDRESS_P (x))
- r = 'S';
+ r = ALL_REGS;
else if (GET_CODE (x) == PLUS
&& REG_P (XEXP (x, 0))
&& GET_CODE (XEXP (x, 1)) == CONST_INT
&& INTVAL (XEXP (x, 1)) >= 0)
{
- int fit = INTVAL (XEXP (x, 1)) <= (64 - GET_MODE_SIZE (mode));
+ 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 = 'Q';
+ || 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 = 'Q';
+ r = BASE_POINTER_REGS;
}
else if (frame_pointer_needed && XEXP (x,0) == frame_pointer_rtx)
- r = 'U';
+ r = POINTER_Y_REGS;
}
else if ((GET_CODE (x) == PRE_DEC || GET_CODE (x) == POST_INC)
&& REG_P (XEXP (x, 0))
&& (strict ? REG_OK_FOR_BASE_STRICT_P (XEXP (x, 0))
: REG_OK_FOR_BASE_NOSTRICT_P (XEXP (x, 0))))
{
- r = 'T';
+ r = POINTER_REGS;
}
if (TARGET_ALL_DEBUG)
{
fprintf (stderr, " ret = %c\n", r);
}
- return r;
+ return r == NO_REGS ? 0 : (int)r;
}
/* Attempts to replace X with a valid
{
int offs = INTVAL (XEXP (oldx,1));
if (frame_pointer_rtx != XEXP (oldx,0))
- if (offs > 64 - GET_MODE_SIZE (mode))
+ if (offs > MAX_LD_OFFSET (mode))
{
if (TARGET_ALL_DEBUG)
fprintf (stderr, "force_reg (big offset)\n");
/* Return a pointer register name as a string */
-static char *
+static const char *
ptrreg_to_str (regno)
int regno;
{
case REG_Y: return "Y";
case REG_Z: return "Z";
default:
- fatal ("register r%d isn't a pointer\n", regno);
+ abort ();
}
return NULL;
}
/* Return the condition name as a string.
Used in conditional jump constructing */
-static char *
+static const char *
cond_string (code)
enum rtx_code code;
{
return "pl";
else
return "ge";
- case GT:
- fatal ("Internal compiler bug: command `bgt'");
- case LE:
- fatal ("Internal compiler bug: command `ble'");
case LT:
if (cc_prev_status.flags & CC_OVERFLOW_UNUSABLE)
return "mi";
return "lt";
case GEU:
return "sh";
- case GTU:
- fatal ("Internal compiler bug: command `bgtu'");
- case LEU:
- fatal ("Internal compiler bug: command `bleu'");
case LTU:
return "lo";
default:
if (code >= 'A' && code <= 'D')
abcd = code - 'A';
- if (REG_P (x))
+ if (code == '~')
+ {
+ if (!AVR_MEGA)
+ fputc ('r', file);
+ }
+ else if (REG_P (x))
{
if (x == zero_reg_rtx)
- fprintf (file,"__zero_reg__");
+ fprintf (file, "__zero_reg__");
else
fprintf (file, reg_names[true_regnum (x) + abcd]);
}
else if (GET_CODE (x) == MEM)
{
rtx addr = XEXP (x,0);
- if (code == 'K')
- {
- if (CONSTANT_P (addr))
- putc ('s', file);
- else if (GET_CODE (addr) == PLUS)
- putc ('d', file);
- }
- else if (CONSTANT_P (addr) && abcd)
+
+ 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 bug.\nBad address:"
+ fatal_insn ("internal compiler error. Bad address:"
,addr);
fputc ('+', file);
print_operand (file, XEXP (addr,1), code);
long val;
REAL_VALUE_TYPE rv;
if (GET_MODE (x) != SFmode)
- fatal_insn ("Internal compiler bug. Unknown mode:", x);
+ fatal_insn ("internal compiler error. Unknown mode:", x);
REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
REAL_VALUE_TO_TARGET_SINGLE (rv, val);
- asm_fprintf (file, "0x%x", val);
+ asm_fprintf (file, "0x%lx", val);
}
else if (code == 'j')
asm_fprintf (file, cond_string (GET_CODE (x)));
print_operand_address (file, x);
}
-/* Recognise operand OP of mode MODE used in call instructions */
+/* Recognize operand OP of mode MODE used in call instructions */
int
call_insn_operand (op, mode)
rtx body ATTRIBUTE_UNUSED;
rtx insn;
{
+ rtx set;
+
switch (get_attr_cc (insn))
{
case CC_NONE:
break;
case CC_SET_ZN:
- {
- rtx set = single_set (insn);
- CC_STATUS_INIT;
- if (set)
- {
- cc_status.flags |= CC_NO_OVERFLOW;
- cc_status.value1 = SET_DEST (set);
- }
- }
+ 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:
/* Insn sets the Z,N,C flags of CC to recog_operand[0].
The V flag may or may not be known but that's ok because
alter_cond will change tests to use EQ/NE. */
- {
- rtx set = single_set (insn);
- CC_STATUS_INIT;
- if (set)
- {
- cc_status.value1 = SET_DEST (set);
- cc_status.flags |= CC_OVERFLOW_UNUSABLE;
- }
- }
+ 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:
- {
- rtx set = single_set (insn);
- CC_STATUS_INIT;
- if (set)
- cc_status.value1 = SET_SRC (set);
- }
+ set = single_set (insn);
+ CC_STATUS_INIT;
+ if (set)
+ cc_status.value1 = SET_SRC (set);
break;
-
+
case CC_CLOBBER:
/* Insn doesn't leave CC in a usable state. */
CC_STATUS_INIT;
+
+ /* Correct CC for the ashrqi3 with the shift count as CONST_INT != 6 */
+ 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;
}
}
3 - absolute jump (only for ATmega[16]03). */
int
-avr_jump_mode (x,insn)
+avr_jump_mode (x, insn)
rtx x; /* jump operand */
rtx insn; /* jump 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 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 2;
}
-/* return a AVR condition jump commands.
- LEN is a number returned by avr_jump_mode function. */
+/* return an AVR condition jump commands.
+ X is a comparison RTX.
+ LEN is a number returned by avr_jump_mode function.
+ if REVERSE nonzero then condition code in X must be reversed. */
-char *
-ret_cond_branch (cond,len)
- RTX_CODE cond;
+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:
AS1 (brsh,_PC_+4) CR_TAB
AS1 (jmp,%0)));
default:
- switch (len)
- {
- case 1:
- return AS1 (br%j1,%0);
- case 2:
- return (AS1 (br%k1,_PC_+2) CR_TAB
- AS1 (rjmp,%0));
- default:
- return (AS1 (br%k1,_PC_+4) CR_TAB
- AS1 (jmp,%0));
- }
+ if (reverse)
+ {
+ switch (len)
+ {
+ case 1:
+ return AS1 (br%k1,%0);
+ case 2:
+ return (AS1 (br%j1,_PC_+2) CR_TAB
+ AS1 (rjmp,%0));
+ default:
+ return (AS1 (br%j1,_PC_+4) CR_TAB
+ AS1 (jmp,%0));
+ }
+ }
+ else
+ {
+ switch (len)
+ {
+ case 1:
+ return AS1 (br%j1,%0);
+ case 2:
+ return (AS1 (br%k1,_PC_+2) CR_TAB
+ AS1 (rjmp,%0));
+ default:
+ return (AS1 (br%k1,_PC_+4) CR_TAB
+ AS1 (jmp,%0));
+ }
+ }
}
return "";
}
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));
+ 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];
+ last_insn_address = INSN_ADDRESSES (uid);
if (TARGET_RTL_DUMP)
{
}
}
-/* return 1 if undefined,
- 1 if always true or always false */
+/* Return 0 if undefined, 1 if always true or always false. */
int
avr_simplify_comparision_p (mode, operator, x)
{
unsigned int max = (mode == QImode ? 0xff :
mode == HImode ? 0xffff :
- mode == SImode ? 0xffffffffU : 0);
+ mode == SImode ? 0xffffffff : 0);
if (max && operator && GET_CODE (x) == CONST_INT)
{
if (unsigned_condition (operator) != operator)
}
}
+/* Returns the number of registers to allocate for a function argument. */
+
+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);
+
+ /* Align all function arguments to start in even-numbered registers.
+ Odd-sized arguments leave holes above them. */
+
+ return (size + 1) & ~1;
+}
+
/* Controls whether a function argument is passed
in a register, and which register. */
tree type;
int named ATTRIBUTE_UNUSED;
{
- int bytes;
-
- bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
+ 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;
}
tree type; /* type of the argument or 0 if lib support */
int named ATTRIBUTE_UNUSED; /* whether or not the argument was named */
{
- int bytes;
+ int bytes = avr_num_arg_regs (mode, type);
- bytes = (mode == BLKmode ? int_size_in_bytes (type) : GET_MODE_SIZE (mode));
cum->nregs -= bytes;
cum->regno -= bytes;
cum->nregs = 0;
cum->regno = FIRST_CUM_REG;
}
-
- return;
}
/***********************************************************************
Functions for outputting various mov's for a various modes
************************************************************************/
-char *
-out_movqi_r_mr (insn, op, l)
+const char *
+output_movqi (insn, operands, l)
rtx insn;
- rtx op[];
- int *l; /* instruction length */
+ rtx operands[];
+ int *l;
{
- /* We handle CONSTANT_ADDRESS_P case in adjust_insn_length */
- if (l) *l=1;
- if (GET_CODE (op[1]) == MEM)
+ 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))
{
- rtx x = XEXP (op[1],0);
- if (GET_CODE (x) == PLUS
- && REG_P (XEXP (x,0))
- && GET_CODE (XEXP (x,1)) == CONST_INT)
+ if (register_operand (src, QImode)) /* mov r,r */
+ {
+ 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((INTVAL (XEXP (x,1)) - GET_MODE_SIZE (GET_MODE (op[1]))) >= 63)
+ if (test_hard_reg_class (LD_REGS, dest)) /* ldi d,i */
+ return AS2 (ldi,%0,lo8(%1));
+
+ if (GET_CODE (src) == CONST_INT)
{
- int disp = INTVAL (XEXP (x,1));
- if (REGNO (XEXP (x,0)) != REG_Y)
- fatal_insn ("Incorrect insn:",insn);
- if (disp <= 63 + 64 - GET_MODE_SIZE (GET_MODE (op[1])))
+ if (src == const0_rtx) /* mov r,L */
+ return AS1 (clr,%0);
+ else if (src == const1_rtx)
{
- if (l)
- *l = 3;
- else
- {
- op[4] = GEN_INT (disp - 63);
- return (AS2 (adiw, r28, %4) CR_TAB
- AS2 (ldd, %0,Y+63) CR_TAB
- AS2 (sbiw, r28, %4));
- }
+ 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
+ else if (src == constm1_rtx)
{
- op[4] = XEXP (x,1);
- if (l)
- *l = 5;
- else
- return (AS2 (subi, r28, lo8(-%4)) CR_TAB
- AS2 (sbci, r29, hi8(-%4)) CR_TAB
- AS2 (ld, %0,Y) CR_TAB
- AS2 (subi, r28, lo8(%4)) CR_TAB
- AS2 (sbci, r29, hi8(%4)));
+ /* Immediate constants -1 to any register */
+ 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 if (REGNO (XEXP (x,0)) == REG_X)
- {
- /* This is a paranoid case LEGITIMIZE_RELOAD_ADDRESS must exclude
- it but I have this situation with extremal optimizing options
- */
- if (l)
- *l=3;
else
{
- output_asm_insn (AS2 (adiw, r26, %0),&XEXP (x,1));
- output_asm_insn (AS2 (ld ,%0,X),op);
- if (!reg_overlap_mentioned_p (op[0],XEXP (x,0)))
- output_asm_insn (AS2 (sbiw, r26, %0),&XEXP (x,1));
+ 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 "";
+ }
}
- return "";
}
+
+ /* Last resort, larger than loading from memory. */
+ *l = 4;
+ return (AS2 (mov,__tmp_reg__,r31) CR_TAB
+ AS2 (ldi,r31,lo8(%1)) CR_TAB
+ AS2 (mov,%0,r31) CR_TAB
+ AS2 (mov,r31,__tmp_reg__));
}
+ else if (GET_CODE (src) == MEM)
+ return out_movqi_r_mr (insn, operands, real_l); /* mov r,m */
+ }
+ 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 AS2 (ld%K1,%0,%1);
+ return "";
}
-char *
-out_movhi_r_mr (insn, op, l)
+
+const char *
+output_movhi (insn, operands, l)
rtx insn;
- rtx op[];
- int *l; /* instruction length */
+ rtx operands[];
+ int *l;
{
- int reg_dest = true_regnum (op[0]);
- int reg_base = true_regnum (XEXP (op[1],0));
- int len_p = 1,tmp;
- int *real_l=l;
-
+ int dummy;
+ rtx dest = operands[0];
+ rtx src = operands[1];
+ int *real_l = l;
+
if (!l)
- l = &tmp, len_p = 0;
-
- if (reg_base > 0)
- {
- if (reg_dest == reg_base) /* R = (R) */
- return *l=3, (AS2 (ld,__tmp_reg__,%1+) CR_TAB
- AS2 (ld,%B0,%1) CR_TAB
- AS2 (mov,%A0,__tmp_reg__));
- else if (reg_base == REG_X) /* (R26) */
- {
- if (reg_unused_after (insn, XEXP (op[1],0)))
- return *l=2, (AS2 (ld,%A0,X+) CR_TAB
- AS2 (ld,%B0,X));
- else
- return *l=3, (AS2 (ld,%A0,X+) CR_TAB
- AS2 (ld,%B0,X) CR_TAB
- AS2 (sbiw,r26,1));
- }
- else /* (R) */
- return *l=2, (AS2 (ld,%A0,%1) CR_TAB
- AS2 (ldd,%B0,%1+1));
- }
- else if (GET_CODE (XEXP (op[1],0)) == PLUS) /* (R + i) */
+ l = &dummy;
+
+ if (register_operand (dest, HImode))
{
- int disp = INTVAL(XEXP (XEXP (op[1],0), 1));
- int reg_base = true_regnum (XEXP (XEXP (op[1],0), 0));
-
- if (disp > 64 - GET_MODE_SIZE (GET_MODE (op[1])))
+ if (register_operand (src, HImode)) /* mov r,r */
{
- rtx x = XEXP (op[1],0);
- if (REGNO (XEXP (x,0)) != REG_Y)
- fatal_insn ("Incorrect insn:",insn);
- if (disp <= 63 + 64 - GET_MODE_SIZE (GET_MODE (op[1])))
+ 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))
{
- op[4] = GEN_INT (disp - 62);
- return *l=4, (AS2 (adiw, r28, %4) CR_TAB
- AS2 (ldd, %A0,Y+62) CR_TAB
- AS2 (ldd, %B0,Y+63) CR_TAB
- AS2 (sbiw, r28, %4));
+ *l = 2;
+ return (AS2 (mov,%B0,%B1) CR_TAB
+ AS2 (mov,%A0,%A1));
}
else
{
- op[4] = XEXP (x,1);
- return *l=6, (AS2 (subi, r28, lo8(-%4)) CR_TAB
- AS2 (sbci, r29, hi8(-%4)) CR_TAB
- AS2 (ld, %A0,Y) CR_TAB
- AS2 (ldd, %B0,Y+1) CR_TAB
- AS2 (subi, r28, lo8(%4)) CR_TAB
- AS2 (sbci, r29, hi8(%4)));
+ *l = 2;
+ return (AS2 (mov,%A0,%A1) CR_TAB
+ AS2 (mov,%B0,%B1));
}
}
- if (reg_base == REG_X)
+ else if (CONSTANT_P (src))
{
- /* This is a paranoid case. LEGITIMIZE_RELOAD_ADDRESS must exclude
- it but I have this situation with extremal optimization options
- */
- rtx ops[1];
- ops[0] = XEXP (XEXP (op[1],0), 1);
- if (real_l)
- *l = 4;
- else if (reg_base == reg_dest)
- {
- output_asm_insn (AS2 (adiw, r26, %0), ops);
- output_asm_insn (AS2 (ld , __tmp_reg__, X+), op);
- output_asm_insn (AS2 (ld , %B0, X), op);
- output_asm_insn (AS2 (mov, %A0, __tmp_reg__),op);
- }
- else
+ if (test_hard_reg_class (LD_REGS, dest)) /* ldi d,i */
{
- output_asm_insn (AS2 (adiw, r26, %0), ops);
- output_asm_insn (AS2 (ld , %A0, X+), op);
- output_asm_insn (AS2 (ld , %B0, X), op);
- if (INTVAL (ops[0]) == 63)
+ if (byte_immediate_operand (src, HImode)
+ && reg_was_0 (insn, dest))
{
- output_asm_insn (AS2 (subi, r26, %0+1), ops);
- output_asm_insn (AS2 (sbci, r26, 0), ops);
+ *l = 1;
+ return (AS2 (ldi,%A0,lo8(%1) ; reg_was_0));
}
- else
- output_asm_insn (AS2 (sbiw, r26, %0+1), ops);
+
+ *l = 2;
+ return (AS2 (ldi,%A0,lo8(%1)) CR_TAB
+ AS2 (ldi,%B0,hi8(%1)));
}
- return "";
- }
-
- if (reg_base == reg_dest)
- return *l=3, (AS2 (ldd,__tmp_reg__,%A1) CR_TAB
- AS2 (ldd,%B0,%B1) CR_TAB
- AS2 (mov,%A0,__tmp_reg__));
- else
- return *l=2, (AS2 (ldd,%A0,%A1) CR_TAB
- AS2 (ldd,%B0,%B1));
- }
- else if (GET_CODE (XEXP (op[1],0)) == PRE_DEC) /* (--R) */
- {
- if (reg_overlap_mentioned_p (op[0], XEXP (XEXP (op[1],0),0)))
- {
- debug_rtx (insn);
- fatal ("Internal error. Incorrect insn.");
- }
- return *l=2, (AS2 (ld,%B0,%1) CR_TAB
- AS2 (ld,%A0,%1));
- }
- else if (GET_CODE (XEXP (op[1],0)) == POST_INC) /* (R++) */
- {
- if (reg_overlap_mentioned_p (op[0], XEXP (XEXP (op[1],0),0)))
- {
- debug_rtx (insn);
- fatal ("Internal error. Incorrect insn.");
+
+ if (GET_CODE (src) == CONST_INT)
+ {
+ if (src == const0_rtx) /* mov r,L */
+ {
+ *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)
+ {
+ /* Immediate constants -1 to any register */
+ 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__));
+ }
+ }
+
+ /* Last resort, equal to loading from memory. */
+ *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__));
}
- return *l=2, (AS2 (ld,%A0,%1) CR_TAB
- AS2 (ld,%B0,%1));
+ else if (GET_CODE (src) == MEM)
+ return out_movhi_r_mr (insn, operands, real_l); /* mov r,m */
+ }
+ 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 "";
}
- else if (CONSTANT_ADDRESS_P (XEXP (op[1],0)))
- return *l=4, (AS2 (lds,%A0,%A1) CR_TAB
- AS2 (lds,%B0,%B1));
- fatal_insn ("Unknown move insn:",insn);
+ fatal_insn ("invalid insn:", insn);
return "";
}
-char *
-out_movsi_r_mr (insn,op,l)
+const char *
+out_movqi_r_mr (insn, op, l)
rtx insn;
rtx op[];
int *l; /* instruction length */
{
- int reg_dest=true_regnum (op[0]);
- int reg_base=true_regnum (XEXP (op[1],0));
+ 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);
+ }
+ /* memory access by reg+disp */
+ 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)
+ {
+ /* This is a paranoid case LEGITIMIZE_RELOAD_ADDRESS must exclude
+ it but I have this situation with extremal optimizing options. */
+ if (reg_overlap_mentioned_p (dest, XEXP (x,0))
+ || reg_unused_after (insn, XEXP (x,0)))
+ 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; /* instruction length */
+{
+ 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;
+ l = &tmp;
+
+ if (reg_base > 0)
+ {
+ if (reg_dest == reg_base) /* R = (R) */
+ {
+ *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) /* (R26) */
+ {
+ 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 /* (R) */
+ {
+ *l = 2;
+ return (AS2 (ld,%A0,%1) CR_TAB
+ AS2 (ldd,%B0,%1+1));
+ }
+ }
+ else if (GET_CODE (base) == PLUS) /* (R + i) */
+ {
+ 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)
+ {
+ /* This is a paranoid case. LEGITIMIZE_RELOAD_ADDRESS must exclude
+ it but I have this situation with extremal
+ optimization options. */
+
+ *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) /* (--R) */
+ {
+ 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) /* (R++) */
+ {
+ 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; /* instruction length */
+{
+ 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) /* (R26) */
{
if (reg_dest == REG_X)
- return *l=6, (AS2 (adiw,r26,3) CR_TAB
- AS2 (ld,%D0,X) CR_TAB
- AS2 (ld,%C0,-X) CR_TAB
- AS2 (ld,__tmp_reg__,-X) CR_TAB
- AS2 (ld,%A0,-X) CR_TAB
- AS2 (mov,%B0,__tmp_reg__));
+ /* "ld r26,-X" is undefined */
+ return *l=7, (AS2 (adiw,r26,3) CR_TAB
+ AS2 (ld,r29,X) CR_TAB
+ AS2 (ld,r28,-X) CR_TAB
+ AS2 (ld,__tmp_reg__,-X) CR_TAB
+ AS2 (sbiw,r26,1) CR_TAB
+ AS2 (ld,r26,X) CR_TAB
+ AS2 (mov,r27,__tmp_reg__));
else if (reg_dest == REG_X - 2)
return *l=5, (AS2 (ld,%A0,X+) CR_TAB
AS2 (ld,%B0,X+) CR_TAB
AS2 (ld,__tmp_reg__,X+) CR_TAB
AS2 (ld,%D0,X) CR_TAB
AS2 (mov,%C0,__tmp_reg__));
- else if (reg_unused_after (insn,XEXP (op[1],0)))
+ 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 (ldd,%D0,%1+3));
}
}
- else if (GET_CODE (XEXP (op[1],0)) == PLUS) /* (R + i) */
+ else if (GET_CODE (base) == PLUS) /* (R + i) */
{
- int disp = INTVAL(XEXP (XEXP (op[1],0), 1));
+ int disp = INTVAL (XEXP (base, 1));
- if (disp > 64 - GET_MODE_SIZE (GET_MODE (op[1])))
+ if (disp > MAX_LD_OFFSET (GET_MODE (src)))
{
- rtx x = XEXP (op[1],0);
- if (REGNO (XEXP (x,0)) != REG_Y)
- fatal_insn ("Incorrect insn:",insn);
- if (disp <= 63 + 64 - GET_MODE_SIZE (GET_MODE (op[1])))
- {
- op[4] = GEN_INT (disp - 60);
- return *l=6,(AS2 (adiw, r28, %4) CR_TAB
- AS2 (ldd, %A0,Y+60) CR_TAB
- AS2 (ldd, %B0,Y+61) CR_TAB
- AS2 (ldd, %C0,Y+62) CR_TAB
- AS2 (ldd, %D0,Y+63) CR_TAB
- AS2 (sbiw, r28, %4));
- }
- else
+ 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)
+ {
+ /* R = (X + d) */
+ if (reg_dest == REG_X)
{
- op[4] = XEXP (x,1);
- return *l=8,(AS2 (subi, r28, lo8(-%4)) CR_TAB
- AS2 (sbci, r29, hi8(-%4)) CR_TAB
- AS2 (ld, %A0,Y) CR_TAB
- AS2 (ldd, %B0,Y+1) CR_TAB
- AS2 (ldd, %C0,Y+2) CR_TAB
- AS2 (ldd, %D0,Y+3) CR_TAB
- AS2 (subi, r28, lo8(%4)) CR_TAB
- AS2 (sbci, r29, hi8(%4)));
+ *l = 7;
+ /* "ld r26,-X" is undefined */
+ return (AS2 (adiw,r26,%o1+3) CR_TAB
+ AS2 (ld,r29,X) CR_TAB
+ AS2 (ld,r28,-X) CR_TAB
+ AS2 (ld,__tmp_reg__,-X) CR_TAB
+ AS2 (sbiw,r26,1) CR_TAB
+ AS2 (ld,r26,X) CR_TAB
+ AS2 (mov,r27,__tmp_reg__));
}
+ *l = 6;
+ if (reg_dest == REG_X - 2)
+ return (AS2 (adiw,r26,%o1) CR_TAB
+ AS2 (ld,r24,X+) CR_TAB
+ AS2 (ld,r25,X+) CR_TAB
+ AS2 (ld,__tmp_reg__,X+) CR_TAB
+ AS2 (ld,r27,X) CR_TAB
+ AS2 (mov,r26,__tmp_reg__));
+
+ return (AS2 (adiw,r26,%o1) CR_TAB
+ AS2 (ld,%A0,X+) CR_TAB
+ AS2 (ld,%B0,X+) CR_TAB
+ AS2 (ld,%C0,X+) CR_TAB
+ AS2 (ld,%D0,X) CR_TAB
+ AS2 (sbiw,r26,%o1+3));
}
-
- reg_base = true_regnum (XEXP (XEXP (op[1],0), 0));
if (reg_dest == reg_base)
return *l=5, (AS2 (ldd,%D0,%D1) CR_TAB
AS2 (ldd,%C0,%C1) CR_TAB
AS2 (ldd,%C0,%C1) CR_TAB
AS2 (ldd,%D0,%D1));
}
- else if (GET_CODE (XEXP (op[1],0)) == PRE_DEC) /* (--R) */
+ else if (GET_CODE (base) == PRE_DEC) /* (--R) */
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 (XEXP (op[1],0)) == POST_INC) /* (R++) */
+ else if (GET_CODE (base) == POST_INC) /* (R++) */
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 (XEXP (op[1],0)))
+ 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);
+ fatal_insn ("unknown move insn:",insn);
return "";
}
-char *
-out_movsi_mr_r (insn,op,l)
+const char *
+out_movsi_mr_r (insn, op, l)
rtx insn;
rtx op[];
int *l;
{
- int reg_base = true_regnum (XEXP (op[0],0));
- int reg_dest = true_regnum (op[1]);
+ 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 (XEXP (op[0],0)))
+
+ 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
{
if (reg_base == REG_X) /* (R26) */
{
- if (reg_dest == REG_X)
+ if (reg_src == REG_X)
{
- if (reg_unused_after (insn,XEXP (op[0],0)))
- return *l=5, (AS2 (mov,__tmp_reg__,%B1) CR_TAB
- AS2 (st,%0+,%A1) CR_TAB
- AS2 (st,%0+,__tmp_reg__) CR_TAB
- AS2 (st,%0+,%C1) CR_TAB
- AS2 (st,%0,%D1));
+ /* "st X+,r26" is undefined */
+ 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=6, (AS2 (mov,__tmp_reg__,%B1) CR_TAB
- AS2 (st,%0+,%A1) CR_TAB
- AS2 (st,%0+,__tmp_reg__) CR_TAB
- AS2 (st,%0+,%C1) CR_TAB
- AS2 (st,%0,%D1) CR_TAB
- AS2 (sbiw,r26,3));
+ return *l=7, (AS2 (mov,__tmp_reg__,r27) CR_TAB
+ AS2 (st,X,r26) CR_TAB
+ AS2 (adiw,r26,1) CR_TAB
+ AS2 (st,X+,__tmp_reg__) CR_TAB
+ AS2 (st,X+,r28) CR_TAB
+ AS2 (st,X,r29) CR_TAB
+ AS2 (sbiw,r26,3));
}
- else if (reg_base == reg_dest+2)
+ else if (reg_base == reg_src + 2)
{
- if (reg_unused_after (insn,XEXP (op[0],0)))
+ 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 (std,%0+2,%C1) CR_TAB
AS2 (std,%0+3,%D1));
}
- else if (GET_CODE (XEXP (op[0],0)) == PLUS) /* (R + i) */
+ else if (GET_CODE (base) == PLUS) /* (R + i) */
{
- int disp = INTVAL(XEXP (XEXP (op[0],0), 1));
- if (disp > 64 - GET_MODE_SIZE (GET_MODE (op[0])))
+ int disp = INTVAL (XEXP (base, 1));
+ reg_base = REGNO (XEXP (base, 0));
+ if (disp > MAX_LD_OFFSET (GET_MODE (dest)))
{
- rtx x = XEXP (op[0],0);
- if (REGNO (XEXP (x,0)) != REG_Y)
- fatal_insn ("Incorrect insn:",insn);
- if (disp <= 63 + 64 - GET_MODE_SIZE (GET_MODE (op[0])))
+ if (reg_base != REG_Y)
+ fatal_insn ("incorrect insn:",insn);
+
+ if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)))
+ return *l = 6, (AS2 (adiw,r28,%o0-60) CR_TAB
+ AS2 (std,Y+60,%A1) CR_TAB
+ AS2 (std,Y+61,%B1) CR_TAB
+ AS2 (std,Y+62,%C1) CR_TAB
+ AS2 (std,Y+63,%D1) CR_TAB
+ AS2 (sbiw,r28,%o0-60));
+
+ return *l = 8, (AS2 (subi,r28,lo8(-%o0)) CR_TAB
+ AS2 (sbci,r29,hi8(-%o0)) CR_TAB
+ AS2 (st,Y,%A1) CR_TAB
+ AS2 (std,Y+1,%B1) CR_TAB
+ AS2 (std,Y+2,%C1) CR_TAB
+ AS2 (std,Y+3,%D1) CR_TAB
+ AS2 (subi,r28,lo8(%o0)) CR_TAB
+ AS2 (sbci,r29,hi8(%o0)));
+ }
+ if (reg_base == REG_X)
+ {
+ /* (X + d) = R */
+ if (reg_src == REG_X)
{
- op[4] = GEN_INT (disp - 60);
- return *l=6,(AS2 (adiw, r28, %4) CR_TAB
- AS2 (std, Y+60,%A1) CR_TAB
- AS2 (std, Y+61,%B1) CR_TAB
- AS2 (std, Y+62,%C1) CR_TAB
- AS2 (std, Y+63,%D1) CR_TAB
- AS2 (sbiw, r28, %4));
+ *l = 9;
+ return (AS2 (mov,__tmp_reg__,r26) CR_TAB
+ AS2 (mov,__zero_reg__,r27) CR_TAB
+ AS2 (adiw,r26,%o0) CR_TAB
+ AS2 (st,X+,__tmp_reg__) CR_TAB
+ AS2 (st,X+,__zero_reg__) CR_TAB
+ AS2 (st,X+,r28) CR_TAB
+ AS2 (st,X,r29) CR_TAB
+ AS1 (clr,__zero_reg__) CR_TAB
+ AS2 (sbiw,r26,%o0+3));
}
- else
+ else if (reg_src == REG_X - 2)
{
- op[4] = XEXP (x,1);
- return *l=8,(AS2 (subi, r28, lo8(-%4)) CR_TAB
- AS2 (sbci, r29, hi8(-%4)) CR_TAB
- AS2 (st, Y,%A1) CR_TAB
- AS2 (std, Y+1,%B1) CR_TAB
- AS2 (std, Y+2,%C1) CR_TAB
- AS2 (std, Y+3,%D1) CR_TAB
- AS2 (subi, r28, lo8(%4)) CR_TAB
- AS2 (sbci, r29, hi8(%4)));
+ *l = 9;
+ return (AS2 (mov,__tmp_reg__,r26) CR_TAB
+ AS2 (mov,__zero_reg__,r27) CR_TAB
+ AS2 (adiw,r26,%o0) CR_TAB
+ AS2 (st,X+,r24) CR_TAB
+ AS2 (st,X+,r25) CR_TAB
+ AS2 (st,X+,__tmp_reg__) CR_TAB
+ AS2 (st,X,__zero_reg__) CR_TAB
+ AS1 (clr,__zero_reg__) CR_TAB
+ AS2 (sbiw,r26,%o0+3));
}
+ *l = 6;
+ return (AS2 (adiw,r26,%o0) CR_TAB
+ AS2 (st,X+,%A1) CR_TAB
+ AS2 (st,X+,%B1) CR_TAB
+ AS2 (st,X+,%C1) CR_TAB
+ AS2 (st,X,%D1) CR_TAB
+ AS2 (sbiw,r26,%o0+3));
}
return *l=4, (AS2 (std,%A0,%A1) CR_TAB
AS2 (std,%B0,%B1) CR_TAB
AS2 (std,%C0,%C1) CR_TAB
AS2 (std,%D0,%D1));
}
- else if (GET_CODE (XEXP (op[0],0)) == PRE_DEC) /* (--R) */
+ else if (GET_CODE (base) == PRE_DEC) /* (--R) */
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 (XEXP (op[0],0)) == POST_INC) /* (R++) */
+ else if (GET_CODE (base) == POST_INC) /* (R++) */
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);
+ fatal_insn ("unknown move insn:",insn);
return "";
}
-char *
-output_movsisf(insn, operands, which_alternative)
+const char *
+output_movsisf(insn, operands, l)
rtx insn;
rtx operands[];
- int which_alternative;
+ int *l;
{
- rtx link;
- switch (which_alternative)
- {
- case 0: /* mov r,r */
- if (true_regnum (operands[0]) > true_regnum (operands[1]))
- return (AS2 (mov,%D0,%D1) CR_TAB
- AS2 (mov,%C0,%C1) CR_TAB
- AS2 (mov,%B0,%B1) CR_TAB
- AS2 (mov,%A0,%A1));
- else
- return (AS2 (mov,%A0,%A1) CR_TAB
- AS2 (mov,%B0,%B1) CR_TAB
- AS2 (mov,%C0,%C1) CR_TAB
- AS2 (mov,%D0,%D1));
- case 1: /* mov r,L */
- return (AS1 (clr,%A0) CR_TAB
- AS1 (clr,%B0) CR_TAB
- AS1 (clr,%C0) CR_TAB
- AS1 (clr,%D0));
- case 2: /* mov r,d */
- if (GET_MODE (operands[0]) == SImode
- && operands[1] == const1_rtx
- && (link = find_reg_note (insn, REG_WAS_0, 0))
- /* Make sure the insn that stored the 0 is still present. */
- && ! INSN_DELETED_P (XEXP (link, 0))
- && GET_CODE (XEXP (link, 0)) != NOTE
- /* Make sure cross jumping didn't happen here. */
- && no_labels_between_p (XEXP (link, 0), insn)
- /* Make sure the reg hasn't been clobbered. */
- && ! reg_set_between_p (operands[0], XEXP (link, 0), insn))
- /* Fastest way to change a 0 to a 1. */
- return AS1 (inc,%A0 ; reg_was_0);
- 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)));
- case 3: /* mov r,m*/
- case 5:
- return out_movsi_r_mr (insn, operands, NULL);
- case 4: /* mov m,r*/
- case 6:
- {
- rtx save1=NULL;
- if (operands[1] == const0_rtx)
- {
- save1 = operands[1];
- operands[1] = zero_reg_rtx;
- }
- output_asm_insn (out_movsi_mr_r (insn,operands,NULL), operands);
- if (save1)
- operands[1] = save1;
- }
+ 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)) /* mov r,r */
+ {
+ 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)) /* ldi d,i */
+ {
+ 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) /* mov r,L */
+ {
+ *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)
+ {
+ /* Immediate constants -1 to any register */
+ 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 "";
+ }
+ }
+ }
+
+ /* Last resort, better than loading from memory. */
+ *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); /* mov r,m */
}
+ 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 "";
}
-char *
+const char *
out_movqi_mr_r (insn, op, l)
rtx insn;
rtx op[];
int *l; /* instruction length */
{
- if (l) *l=1;
+ rtx dest = op[0];
+ rtx src = op[1];
+ rtx x = XEXP (dest, 0);
+ int dummy;
- if (GET_CODE (op[0]) == MEM)
+ if (!l)
+ l = &dummy;
+
+ if (CONSTANT_ADDRESS_P (x))
{
- rtx x = XEXP (op[0],0);
- if (GET_CODE (x) == PLUS
- && REG_P (XEXP (x,0))
- && GET_CODE (XEXP (x,1)) == CONST_INT)
+ if (io_address_p (x, 1))
{
- if ((INTVAL (XEXP (x,1)) - GET_MODE_SIZE (GET_MODE (op[0]))) >= 63)
+ *l = 1;
+ return AS2 (out,%0-0x20,%1);
+ }
+ *l = 2;
+ return AS2 (sts,%0,%1);
+ }
+ /* memory access by reg+disp */
+ 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)))
{
- int disp = INTVAL (XEXP (x,1));
- if (REGNO (XEXP (x,0)) != REG_Y)
- fatal_insn ("Incorrect insn:",insn);
- if (disp <= 63 + 64 - GET_MODE_SIZE (GET_MODE (op[0])))
- {
- if (l)
- *l = 3;
- else
- {
- op[4] = GEN_INT (disp - 63);
- return (AS2 (adiw, r28, %4) CR_TAB
- AS2 (std, Y+63,%1) CR_TAB
- AS2 (sbiw, r28, %4));
- }
- }
- else
- {
- op[4] = XEXP (x,1);
- if (l)
- *l = 5;
- else
- return (AS2 (subi, r28, lo8(-%4)) CR_TAB
- AS2 (sbci, r29, hi8(-%4)) CR_TAB
- AS2 (st, Y,%1) CR_TAB
- AS2 (subi, r28, lo8(%4)) CR_TAB
- AS2 (sbci, r29, hi8(%4)));
- }
+ 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 (REGNO (XEXP (x,0)) == REG_X)
+ else
{
- if (l)
- *l=4;
- else
- {
- int overlap_p = reg_overlap_mentioned_p (op[1],XEXP (x,0));
- if (!overlap_p)
- output_asm_insn (AS2 (mov, __tmp_reg__, %1),op);
- output_asm_insn (AS2 (adiw, r26,%0),&XEXP (x,1));
- if (overlap_p)
- output_asm_insn (AS2 (st ,X,__tmp_reg__),op);
- else
- output_asm_insn (AS2 (st ,X,%1),op);
- output_asm_insn (AS2 (sbiw ,r26,%0),&XEXP (x,1));
- }
- return "";
+ 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);
}
- return AS2 (st%K0, %0,%1);
+ *l = 1;
+ return AS2 (st,%0,%1);
}
-char *
-out_movhi_mr_r (insn,op,l)
+const char *
+out_movhi_mr_r (insn, op, l)
rtx insn;
rtx op[];
int *l;
{
- int reg_base = true_regnum (XEXP (op[0],0));
- int reg_dest = true_regnum (op[1]);
+ 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 (XEXP (op[0],0)))
- return *l=4,(AS2 (sts,%A0,%A1) CR_TAB
- AS2 (sts,%B0,%B1));
+ 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_dest == REG_X)
+ if (reg_src == REG_X)
{
- if (reg_unused_after (insn, op[1]))
- return *l=3, (AS2 (mov,__tmp_reg__,r27) CR_TAB
- AS2 (st ,X+,r26) CR_TAB
- AS2 (st ,X,__tmp_reg__));
+ /* "st X+,r26" is undefined */
+ 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=4, (AS2 (mov,__tmp_reg__,r27) CR_TAB
- AS2 (st ,X+,r26) CR_TAB
- AS2 (st ,X,__tmp_reg__) CR_TAB
- AS2 (sbiw,r26,1));
+ return *l=5, (AS2 (mov,__tmp_reg__,r27) CR_TAB
+ AS2 (st,X,r26) CR_TAB
+ AS2 (adiw,r26,1) CR_TAB
+ AS2 (st,X,__tmp_reg__) CR_TAB
+ AS2 (sbiw,r26,1));
}
else
{
- if (reg_unused_after (insn, XEXP (op[0],0)))
+ if (reg_unused_after (insn, base))
return *l=2, (AS2 (st,X+,%A1) CR_TAB
AS2 (st,X,%B1));
else
return *l=2, (AS2 (st ,%0,%A1) CR_TAB
AS2 (std,%0+1,%B1));
}
- else if (GET_CODE (XEXP (op[0],0)) == PLUS)
+ else if (GET_CODE (base) == PLUS)
{
- int disp = INTVAL(XEXP (XEXP (op[0],0), 1));
- if (disp > 64 - GET_MODE_SIZE (GET_MODE (op[0])))
+ int disp = INTVAL (XEXP (base, 1));
+ reg_base = REGNO (XEXP (base, 0));
+ if (disp > MAX_LD_OFFSET (GET_MODE (dest)))
{
- rtx x = XEXP (op[0],0);
- if (REGNO (XEXP (x,0)) != REG_Y)
- fatal_insn ("Incorrect insn:",insn);
- if (disp <= 63 + 64 - GET_MODE_SIZE (GET_MODE (op[0])))
- {
- op[4] = GEN_INT (disp - 62);
- return *l=4,(AS2 (adiw, r28, %4) CR_TAB
- AS2 (std, Y+62,%A1) CR_TAB
- AS2 (std, Y+63,%B1) CR_TAB
- AS2 (sbiw, r28, %4));
- }
- else
+ if (reg_base != REG_Y)
+ fatal_insn ("incorrect insn:",insn);
+
+ if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)))
+ return *l = 4, (AS2 (adiw,r28,%o0-62) CR_TAB
+ AS2 (std,Y+62,%A1) CR_TAB
+ AS2 (std,Y+63,%B1) CR_TAB
+ AS2 (sbiw,r28,%o0-62));
+
+ return *l = 6, (AS2 (subi,r28,lo8(-%o0)) CR_TAB
+ AS2 (sbci,r29,hi8(-%o0)) CR_TAB
+ AS2 (st,Y,%A1) CR_TAB
+ AS2 (std,Y+1,%B1) CR_TAB
+ AS2 (subi,r28,lo8(%o0)) CR_TAB
+ AS2 (sbci,r29,hi8(%o0)));
+ }
+ if (reg_base == REG_X)
+ {
+ /* (X + d) = R */
+ if (reg_src == REG_X)
{
- op[4] = XEXP (x,1);
- return *l=6,(AS2 (subi, r28, lo8(-%4)) CR_TAB
- AS2 (sbci, r29, hi8(-%4)) CR_TAB
- AS2 (st, Y,%A1) CR_TAB
- AS2 (std, Y+1,%B1) CR_TAB
- AS2 (subi, r28, lo8(%4)) CR_TAB
- AS2 (sbci, r29, hi8(%4)));
+ *l = 7;
+ return (AS2 (mov,__tmp_reg__,r26) CR_TAB
+ AS2 (mov,__zero_reg__,r27) CR_TAB
+ AS2 (adiw,r26,%o0) CR_TAB
+ AS2 (st,X+,__tmp_reg__) CR_TAB
+ AS2 (st,X,__zero_reg__) CR_TAB
+ AS1 (clr,__zero_reg__) CR_TAB
+ AS2 (sbiw,r26,%o0+1));
}
+ *l = 4;
+ return (AS2 (adiw,r26,%o0) CR_TAB
+ AS2 (st,X+,%A1) CR_TAB
+ AS2 (st,X,%B1) CR_TAB
+ AS2 (sbiw,r26,%o0+1));
}
return *l=2, (AS2 (std,%A0,%A1) CR_TAB
AS2 (std,%B0,%B1));
- }
- else if (GET_CODE (XEXP (op[0],0)) == PRE_DEC) /* (--R) */
+ }
+ else if (GET_CODE (base) == PRE_DEC) /* (--R) */
return *l=2, (AS2 (st,%0,%B1) CR_TAB
AS2 (st,%0,%A1));
- else if (GET_CODE (XEXP (op[0],0)) == POST_INC) /* (R++) */
+ else if (GET_CODE (base) == POST_INC) /* (R++) */
return *l=2, (AS2 (st,%0,%A1) CR_TAB
AS2 (st,%0,%B1));
- fatal_insn ("Unknown move insn:",insn);
+ fatal_insn ("unknown move insn:",insn);
return "";
}
/* Return 1 if frame pointer for current function required */
int
-frame_pointer_required_p(void)
+frame_pointer_required_p ()
{
return (current_function_calls_alloca
|| current_function_args_info.nregs == 0
|| get_frame_size () > 0);
}
-/* Return 1 if the next insn is a JUMP_INSN with condition (GT,LE,GTU,LTU) */
+/* Returns the condition of compare insn INSN, or UNKNOWN. */
-int
-compare_diff_p (insn)
+static RTX_CODE
+compare_condition (insn)
rtx insn;
{
rtx next = next_real_insn (insn);
RTX_CODE cond = UNKNOWN;
- if (GET_CODE (next) == JUMP_INSN)
+ if (next && GET_CODE (next) == JUMP_INSN)
{
rtx pat = PATTERN (next);
rtx src = SET_SRC (pat);
- rtx t = XEXP (src,0);
+ rtx t = XEXP (src, 0);
cond = GET_CODE (t);
}
- return (cond == GT || cond == GTU || cond == LE || cond == LEU) ? cond : 0;
+ return cond;
+}
+
+/* Returns nonzero if INSN is a tst insn that only tests the sign. */
+
+static int
+compare_sign_p (insn)
+ rtx insn;
+{
+ RTX_CODE cond = compare_condition (insn);
+ return (cond == GE || cond == LT);
}
-/* Returns nonzero if INSN is a compare insn with the EQ or NE condition */
+/* Returns nonzero if the next insn is a JUMP_INSN with a condition
+ that needs to be swapped (GT, GTU, LE, LEU). */
int
-compare_eq_p (insn)
+compare_diff_p (insn)
rtx insn;
{
- rtx next = next_real_insn (insn);
- RTX_CODE cond = UNKNOWN;
- if (GET_CODE (next) == JUMP_INSN)
- {
- rtx pat = PATTERN (next);
- rtx src = SET_SRC (pat);
- rtx t = XEXP (src,0);
- cond = GET_CODE (t);
- }
+ RTX_CODE cond = compare_condition (insn);
+ return (cond == GT || cond == GTU || cond == LE || cond == LEU) ? cond : 0;
+}
+
+/* Returns nonzero if INSN is a compare insn with the EQ or NE condition. */
+
+int
+compare_eq_p (insn)
+ rtx insn;
+{
+ RTX_CODE cond = compare_condition (insn);
return (cond == EQ || cond == NE);
}
/* Output test instruction for HImode */
-char *
-out_tsthi (insn,l)
+const char *
+out_tsthi (insn, l)
rtx insn;
int *l;
{
- if (!compare_eq_p (insn))
+ if (compare_sign_p (insn))
{
if (l) *l = 1;
return AS1 (tst,%B0);
}
- if (TEST_HARD_REG_CLASS (ADDW_REGS, true_regnum (SET_SRC (PATTERN (insn)))))
+ if (reg_unused_after (insn, SET_SRC (PATTERN (insn)))
+ && compare_eq_p (insn))
{
+ /* faster than sbiw if we can clobber the operand */
if (l) *l = 1;
- return AS2 (sbiw,%0,0);
+ return AS2 (or,%A0,%B0);
}
- if (compare_eq_p (insn) && reg_unused_after (insn, SET_SRC (PATTERN (insn))))
+ if (test_hard_reg_class (ADDW_REGS, SET_SRC (PATTERN (insn))))
{
if (l) *l = 1;
- return AS2 (or,%A0,%B0);
+ return AS2 (sbiw,%0,0);
}
if (l) *l = 2;
return (AS2 (cp,%A0,__zero_reg__) CR_TAB
/* Output test instruction for SImode */
-char *
-out_tstsi (insn,l)
+const char *
+out_tstsi (insn, l)
rtx insn;
int *l;
{
- if (!compare_eq_p (insn))
+ if (compare_sign_p (insn))
{
if (l) *l = 1;
return AS1 (tst,%D0);
}
- if (TEST_HARD_REG_CLASS (ADDW_REGS, true_regnum (SET_SRC (PATTERN (insn)))))
+ if (test_hard_reg_class (ADDW_REGS, SET_SRC (PATTERN (insn))))
{
if (l) *l = 3;
return (AS2 (sbiw,%A0,0) CR_TAB
}
-/* Generate asm equivalent for various shift's.
- Shift count are CONST_INT or REG. */
+/* Generate asm equivalent for various shifts.
+ Shift count is a CONST_INT, MEM or REG.
+ This only handles cases that are not already
+ carefully hand-optimized in ?sh??i3_out. */
void
-out_shift_with_cnt (template,insn,operands,len)
- char * template;
+out_shift_with_cnt (template, insn, operands, len, t_len)
+ const char *template;
rtx insn;
rtx operands[];
int *len;
+ int t_len; /* Length of template. */
{
rtx op[10];
- int l_hi=0;
- char str[300];
+ 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 (CONSTANT_P (operands[2]))
+
+ if (len)
+ *len = 1;
+
+ if (GET_CODE (operands[2]) == CONST_INT)
{
- if (len)
- ++*len;
+ int scratch = (GET_CODE (PATTERN (insn)) == PARALLEL);
+ int count = INTVAL (operands[2]);
+ int max_len = 10; /* If larger than this, always use a loop. */
+
+ 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)
+ {
+ /* Output shifts inline with no loop - faster. */
+ 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)
+ {
+ /* Hack to save one word: use __zero_reg__ as loop counter.
+ Set one bit, then shift in a loop until it is 0 again. */
+
+ op[3] = zero_reg_rtx;
+ if (len)
+ *len = 2;
+ else
+ strcat (str, ("set" CR_TAB
+ AS2 (bld,%3,%2-1)));
+ }
else
- strcat (str, "ldi %3,lo8(%2)");
+ {
+ /* No scratch register available, use one from LD_REGS (saved in
+ __tmp_reg__) that doesn't overlap with registers to shift. */
+
+ 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; /* Includes "mov %3,%4" after the loop. */
+ else
+ strcat (str, (AS2 (mov,%4,%3) CR_TAB
+ AS2 (ldi,%3,%2)));
+ }
+
+ second_label = 0;
}
else if (GET_CODE (operands[2]) == MEM)
{
- int mov_len;
rtx op_mov[10];
- l_hi = 1;
- if (len)
- *len = 2;
+
op[3] = op_mov[0] = tmp_reg_rtx;
op_mov[1] = op[2];
-
- if (!len)
- {
- output_asm_insn (out_movqi_r_mr (insn, op_mov, NULL), op_mov);
- strcat (str,(AS2 (or,%3,%3) CR_TAB
- AS1 (breq,L_hi%=)));
- }
+
+ if (len)
+ out_movqi_r_mr (insn, op_mov, len);
else
- {
- out_movqi_r_mr (insn, op_mov, &mov_len);
- *len += mov_len;
- }
+ output_asm_insn (out_movqi_r_mr (insn, op_mov, NULL), op_mov);
}
- else if (register_operand (operands[2],QImode))
+ else if (register_operand (operands[2], QImode))
{
- l_hi = 1;
- if (len)
- *len += 2;
- else
- strcat (str, (AS2 (or,%2,%2) CR_TAB
- AS1 (breq,L_hi%=)));
-
if (reg_unused_after (insn, operands[2]))
- {
- op[3] = op[2];
- }
+ op[3] = op[2];
else
{
op[3] = tmp_reg_rtx;
- if (len)
- ++*len;
- else
- strcat (str, CR_TAB "mov %3,%2");
+ if (!len)
+ strcat (str, (AS2 (mov,%3,%2) CR_TAB));
}
}
- if (!len)
+ 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; /* template + dec + brXX */
+ else
{
- strcat (str,"\n\t");
+ strcat (str, "\n1:\t");
strcat (str, template);
- if (l_hi)
- strcat (str, "\nL_hi%=:");
+ 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);
}
}
/* 8bit shift left ((char)x << i) */
-char *
-ashlqi3_out (insn,operands,len)
+const char *
+ashlqi3_out (insn, operands, len)
rtx insn;
rtx operands[];
int *len; /* insn length (may be NULL) */
if (GET_CODE (operands[2]) == CONST_INT)
{
int k;
- int *t=len;
+
if (!len)
len = &k;
+
switch (INTVAL (operands[2]))
{
- default: len = t; break;
+ default:
+ *len = 1;
+ return AS1 (clr,%0);
+
case 1:
- *len=1;
+ *len = 1;
return AS1 (lsl,%0);
+
case 2:
- *len=2;
+ *len = 2;
return (AS1 (lsl,%0) CR_TAB
AS1 (lsl,%0));
+
case 3:
- *len=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, true_regnum (operands[0])))
+ if (test_hard_reg_class (LD_REGS, operands[0]))
{
- *len=2;
+ *len = 2;
return (AS1 (swap,%0) CR_TAB
AS2 (andi,%0,0xf0));
}
- *len=4;
+ *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, true_regnum (operands[0])))
+ if (test_hard_reg_class (LD_REGS, operands[0]))
{
- *len=3;
+ *len = 3;
return (AS1 (swap,%0) CR_TAB
AS1 (lsl,%0) CR_TAB
AS2 (andi,%0,0xe0));
}
- *len=5;
+ *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, true_regnum (operands[0])))
+ if (test_hard_reg_class (LD_REGS, operands[0]))
{
- *len=4;
+ *len = 4;
return (AS1 (swap,%0) CR_TAB
AS1 (lsl,%0) CR_TAB
AS1 (lsl,%0) CR_TAB
AS2 (andi,%0,0xc0));
}
- *len=6;
+ *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;
+ *len = 3;
return (AS1 (ror,%0) CR_TAB
AS1 (clr,%0) CR_TAB
AS1 (ror,%0));
}
}
- if (len)
- *len = 3;
- out_shift_with_cnt (AS1 (lsl,%0) CR_TAB
- AS1 (dec,%3) CR_TAB
- AS1 (brne,_PC_-6),
- insn, operands, len);
+ 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 "";
}
/* 16bit shift left ((short)x << i) */
-char *
-ashlhi3_out (insn,operands,len)
+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;
+ int *t = len;
+
if (!len)
len = &k;
+
switch (INTVAL (operands[2]))
{
- default: len = t; break;
- case 1:
- *len=2;
- return (AS1 (lsl,%A0) CR_TAB
- AS1 (rol,%B0));
- case 2:
- *len=4;
- return (AS1 (lsl,%A0) CR_TAB
- AS1 (rol,%B0) CR_TAB
- AS1 (lsl,%0) CR_TAB
- AS1 (rol,%B0));
+ case 4:
+ if (optimize_size && scratch)
+ break; /* 5 */
+ 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; /* optimize_size ? 6 : 8 */
+
+ case 5:
+ if (optimize_size)
+ break; /* scratch ? 5 : 6 */
+ 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; /* 10 */
+
+ case 6:
+ if (optimize_size)
+ break; /* scratch ? 5 : 6 */
+ *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; /* 5 */
+ 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; /* 5 */
+ *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;
}
- if (len)
- *len = 4;
- out_shift_with_cnt (AS1 (lsl,%0) CR_TAB
- AS1 (rol,%B0) CR_TAB
- AS1 (dec,%3) CR_TAB
- AS1 (brne,_PC_-8),
- insn, operands, len);
+ out_shift_with_cnt ((AS1 (lsl,%A0) CR_TAB
+ AS1 (rol,%B0)),
+ insn, operands, len, 2);
return "";
}
/* 32bit shift left ((long)x << i) */
-char *
-ashlsi3_out (insn,operands,len)
+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;
+ int *t = len;
+
if (!len)
len = &k;
+
switch (INTVAL (operands[2]))
{
- default: len = t; break;
- case 1:
- *len=4;
- return (AS1 (lsl,%A0) CR_TAB
- AS1 (rol,%B0) CR_TAB
- AS1 (rol,%C0) CR_TAB
- AS1 (rol,%D0));
case 8:
{
int reg0 = true_regnum (operands[0]);
int reg1 = true_regnum (operands[1]);
- *len=4;
+ *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)
- return *len = 1, AS1 (clr,%A0);
+ {
+ *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;
+ *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)
- return *len = 2, (AS1 (clr,%B0) CR_TAB
- AS1 (clr,%A0));
+ {
+ *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;
+ *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
- return *len = 3, (AS1 (clr,%C0) CR_TAB
- AS1 (clr,%B0) CR_TAB
- AS1 (clr,%A0));
+ {
+ *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;
}
- if (len)
- *len = 6;
- out_shift_with_cnt (AS1 (lsl,%0) CR_TAB
- AS1 (rol,%B0) CR_TAB
- AS1 (rol,%C0) CR_TAB
- AS1 (rol,%D0) CR_TAB
- AS1 (dec,%3) CR_TAB
- AS1 (brne,_PC_-12),
- insn, operands, len);
+ 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 "";
}
/* 8bit arithmetic shift right ((signed char)x >> i) */
-char *
-ashrqi3_out (insn,operands,len)
+const char *
+ashrqi3_out (insn, operands, len)
rtx insn;
rtx operands[];
int *len; /* insn length */
{
if (GET_CODE (operands[2]) == CONST_INT)
{
- int *t=len;
int k;
+
if (!len)
len = &k;
+
switch (INTVAL (operands[2]))
{
- default: len = t; break;
case 1:
- *len=1;
+ *len = 1;
return AS1 (asr,%0);
+
case 2:
- *len=2;
+ *len = 2;
return (AS1 (asr,%0) CR_TAB
AS1 (asr,%0));
+
case 3:
- *len=3;
+ *len = 3;
return (AS1 (asr,%0) CR_TAB
AS1 (asr,%0) CR_TAB
AS1 (asr,%0));
+
case 4:
- *len=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));
}
}
- if (len)
- *len = 3;
- out_shift_with_cnt (AS1 (asr,%0) CR_TAB
- AS1 (dec,%3) CR_TAB
- AS1 (brne,_PC_-6),
- insn, operands, len);
+ 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 "";
}
/* 16bit arithmetic shift right ((signed short)x >> i) */
-char *
-ashrhi3_out (insn,operands,len)
+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;
+ int *t = len;
+
if (!len)
len = &k;
+
switch (INTVAL (operands[2]))
{
- default: len = t; break;
- case 1:
- *len=2;
- return (AS1 (asr,%B0) CR_TAB
- AS1 (ror,%A0));
- case 2:
- *len=4;
- return (AS1 (asr,%B0) CR_TAB
- AS1 (ror,%A0) CR_TAB
- AS1 (asr,%B0) CR_TAB
- AS1 (ror,%A0));
+ case 4:
+ case 5:
+ /* XXX try to optimize this too? */
+ break;
+
+ case 6:
+ if (optimize_size)
+ break; /* scratch ? 5 : 6 */
+ *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:
- if (true_regnum (operands[0]) != true_regnum (operands[1]) + 1)
+ {
+ 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));
- else
- return *len = 3, (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; /* 5 */
+ *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; /* 5 */
+ *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; /* scratch ? 5 : 7 */
+ *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;
}
- if (len)
- *len = 4;
- out_shift_with_cnt (AS1 (asr,%B0) CR_TAB
- AS1 (ror,%A0) CR_TAB
- AS1 (dec,%3) CR_TAB
- AS1 (brne,_PC_-8),
- insn, operands, len);
+ out_shift_with_cnt ((AS1 (asr,%B0) CR_TAB
+ AS1 (ror,%A0)),
+ insn, operands, len, 2);
return "";
}
/* 32bit arithmetic shift right ((signed long)x >> i) */
-char *
-ashrsi3_out (insn,operands,len)
+const char *
+ashrsi3_out (insn, operands, len)
rtx insn;
rtx operands[];
int *len;
{
int k;
int *t = len;
+
if (!len)
len = &k;
+
switch (INTVAL (operands[2]))
{
- default: len = t; break;
- case 1:
- *len=4;
- return (AS1 (asr,%D0) CR_TAB
- AS1 (ror,%C0) CR_TAB
- AS1 (ror,%B0) CR_TAB
- AS1 (ror,%A0));
case 8:
{
int reg0 = true_regnum (operands[0]);
AS2 (sbrc,%C0,7) CR_TAB
AS1 (dec,%D0));
else if (reg0 == reg1 + 1)
- return *len = 3, (AS1 (clr,%D0) CR_TAB
- AS2 (sbrc,%C0,7) CR_TAB
- AS1 (dec,%D0));
+ {
+ *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
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 (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 (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;
}
- if (len)
- *len = 6;
- out_shift_with_cnt (AS1 (asr,%D0) CR_TAB
- AS1 (ror,%C0) CR_TAB
- AS1 (ror,%B0) CR_TAB
- AS1 (ror,%A0) CR_TAB
- AS1 (dec,%3) CR_TAB
- AS1 (brne,_PC_-12),
- insn, operands, len);
+ 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 "";
}
/* 8bit logic shift right ((unsigned char)x >> i) */
-char *
-lshrqi3_out (insn,operands,len)
+const char *
+lshrqi3_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]))
{
- default: len = t; break;
+ default:
+ *len = 1;
+ return AS1 (clr,%0);
+
case 1:
- *len=1;
+ *len = 1;
return AS1 (lsr,%0);
+
case 2:
- *len=2;
+ *len = 2;
return (AS1 (lsr,%0) CR_TAB
AS1 (lsr,%0));
case 3:
- *len=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, true_regnum (operands[0])))
+ if (test_hard_reg_class (LD_REGS, operands[0]))
{
*len=2;
return (AS1 (swap,%0) CR_TAB
AS2 (andi,%0,0x0f));
}
- *len=4;
+ *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, true_regnum (operands[0])))
+ if (test_hard_reg_class (LD_REGS, operands[0]))
{
- *len=3;
+ *len = 3;
return (AS1 (swap,%0) CR_TAB
AS1 (lsr,%0) CR_TAB
AS2 (andi,%0,0x7));
}
- *len=5;
+ *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, true_regnum (operands[0])))
+ if (test_hard_reg_class (LD_REGS, operands[0]))
{
- *len=4;
+ *len = 4;
return (AS1 (swap,%0) CR_TAB
AS1 (lsr,%0) CR_TAB
AS1 (lsr,%0) CR_TAB
AS2 (andi,%0,0x3));
}
- *len=6;
+ *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;
+ *len = 3;
return (AS1 (rol,%0) CR_TAB
AS1 (clr,%0) CR_TAB
AS1 (rol,%0));
}
}
- if (len)
- *len = 3;
- out_shift_with_cnt (AS1 (lsr,%0) CR_TAB
- AS1 (dec,%3) CR_TAB
- AS1 (brne,_PC_-6),
- insn, operands, len);
+ 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 "";
}
/* 16bit logic shift right ((unsigned short)x >> i) */
-char *
-lshrhi3_out (insn,operands,len)
+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;
+ int *t = len;
+
if (!len)
len = &k;
+
switch (INTVAL (operands[2]))
{
- default: len = t; break;
- case 1:
- *len=2;
- return (AS1 (lsr,%B0) CR_TAB
- AS1 (ror,%A0));
- case 2:
- *len=4;
- return (AS1 (lsr,%B0) CR_TAB
- AS1 (ror,%A0) CR_TAB
- AS1 (lsr,%B0) CR_TAB
- AS1 (ror,%A0));
+ case 4:
+ if (optimize_size && scratch)
+ break; /* 5 */
+ 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; /* optimize_size ? 6 : 8 */
+
+ case 5:
+ if (optimize_size)
+ break; /* scratch ? 5 : 6 */
+ 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; /* 10 */
+
+ case 6:
+ if (optimize_size)
+ break; /* scratch ? 5 : 6 */
+ *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; /* 5 */
+ 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; /* 5 */
+ *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:
- return *len = 4, (AS1 (lsl,%B0) CR_TAB
- AS2 (sbc,%A0,%A0) CR_TAB
- AS1 (neg,%A0) CR_TAB
- AS1 (clr,%B0));
+ *len = 4;
+ return (AS1 (clr,%A0) CR_TAB
+ AS1 (lsl,%B0) CR_TAB
+ AS1 (rol,%A0) CR_TAB
+ AS1 (clr,%B0));
}
+ len = t;
}
- if (len)
- *len = 4;
- out_shift_with_cnt (AS1 (lsr,%B0) CR_TAB
- AS1 (ror,%A0) CR_TAB
- AS1 (dec,%3) CR_TAB
- AS1 (brne,_PC_-8),
- insn, operands, len);
+ out_shift_with_cnt ((AS1 (lsr,%B0) CR_TAB
+ AS1 (ror,%A0)),
+ insn, operands, len, 2);
return "";
}
/* 32bit logic shift right ((unsigned int)x >> i) */
-char *
-lshrsi3_out (insn,operands,len)
+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;
+ int *t = len;
+
if (!len)
len = &k;
+
switch (INTVAL (operands[2]))
{
- default: len = t; break;
- case 1:
- *len=4;
- return (AS1 (lsr,%D0) CR_TAB
- AS1 (ror,%C0) CR_TAB
- AS1 (ror,%B0) CR_TAB
- AS1 (ror,%A0));
case 8:
{
int reg0 = true_regnum (operands[0]);
int reg1 = true_regnum (operands[1]);
- *len=4;
+ *len = 4;
if (reg0 <= reg1)
return (AS2 (mov,%A0,%B1) CR_TAB
AS2 (mov,%B0,%C1) 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;
+ *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));
}
+
case 24:
if (true_regnum (operands[0]) != true_regnum (operands[1]) + 3)
return *len = 4, (AS2 (mov,%A0,%D1) CR_TAB
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;
}
- if (len)
- *len = 6;
- out_shift_with_cnt (AS1 (lsr,%D0) CR_TAB
- AS1 (ror,%C0) CR_TAB
- AS1 (ror,%B0) CR_TAB
- AS1 (ror,%A0) CR_TAB
- AS1 (dec,%3) CR_TAB
- AS1 (brne,_PC_-12),
- insn, operands, len);
+ 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 "";
}
LEN is the initially computed length of the insn. */
int
-adjust_insn_length (insn,len)
+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 (REG_P (op[0]) && GET_CODE (op[1]) == MEM)
- {
- if (CONSTANT_ADDRESS_P (XEXP (op[1],0)))
- switch (GET_MODE (op[0]))
- {
- case QImode: len = 2; break;
- case HImode: len = 4; break;
- case SImode:
- case SFmode: len = 8; break;
- default: break;
- }
- else
- switch (GET_MODE (op[0]))
- {
- case QImode: out_movqi_r_mr (insn,op,&len); break;
- case HImode: out_movhi_r_mr (insn,op,&len); break;
- case SImode:
- case SFmode: out_movsi_r_mr (insn,op,&len); break;
- default: break;
- }
- }
- else if ((REG_P (op[1]) || const0_rtx == op[1])
- && GET_CODE (op[0]) == MEM)
- {
- if (CONSTANT_ADDRESS_P (XEXP (op[0],0)))
- switch (GET_MODE (op[0]))
- {
- case QImode: len = 2; break;
- case HImode: len = 4; break;
- case SImode:
- case SFmode: len = 8; break;
- default: break;
- }
- else if (GET_CODE (XEXP (op[0],0)) != POST_DEC)
- switch (GET_MODE (op[0]))
- {
- case QImode: out_movqi_mr_r (insn,op,&len); break;
- case HImode: out_movhi_mr_r (insn,op,&len); break;
- case SImode:
- case SFmode: out_movsi_mr_r (insn,op,&len); break;
- default: break;
- }
- }
+ 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]))
if (GET_MODE (op[1]) == SImode)
len = (((mask & 0xff) != 0xff)
+ ((mask & 0xff00) != 0xff00)
- + ((mask & 0xff0000UL) != 0xff0000UL)
- + ((mask & 0xff000000UL) != 0xff000000UL));
+ + ((mask & 0xff0000L) != 0xff0000L)
+ + ((mask & 0xff000000L) != 0xff000000L));
else if (GET_MODE (op[1]) == HImode)
len = (((mask & 0xff) != 0xff)
+ ((mask & 0xff00) != 0xff00));
{
HOST_WIDE_INT mask = INTVAL (XEXP (op[1],1));
if (GET_MODE (op[1]) == SImode)
- len = (((mask & 0xff) == 0)
- + ((mask & 0xff00) == 0)
- + ((mask & 0xff0000UL) == 0)
- + ((mask & 0xff000000UL) ==0));
+ 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));
+ len = (((mask & 0xff) != 0)
+ + ((mask & 0xff00) != 0));
}
}
}
if (set)
{
rtx op[10];
+
op[1] = SET_SRC (set);
op[0] = SET_DEST (set);
- if (GET_CODE (op[1]) == ASHIFT
+
+ 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 insn;
rtx reg;
{
- return (0
- /* In egcs 1.1.x dead_or_set_p give buggy result after reload
-#ifdef PRESERVE_DEATH_INFO_REGNO_P
- || dead_or_set_p (insn,reg)
-#endif
- */
-
+ return (dead_or_set_p (insn, reg)
|| (REG_P(reg) && _reg_unused_after (insn, reg)));
}
return 1;
}
-/* Output rtx VALUE as .byte to file FILE */
-
-void
-asm_output_char(file,value)
- FILE *file;
- rtx value;
-{
- fprintf (file, "\t.byte ");
- output_addr_const (file, value);
- fprintf (file, "\n");
-}
-
-
-/* Output VALUE as .byte to file FILE */
-
-void
-asm_output_byte (file,value)
- FILE *file;
- char value;
-{
- fprintf (file, "\t.byte 0x%x\n",value & 0xff);
-}
-
-
-/* Output rtx VALUE as .word to file FILE */
+/* Target hook for assembling integer objects. The AVR version needs
+ special handling for references to certain labels. */
-void
-asm_output_short (file, value)
- FILE *file;
- rtx value;
+static bool
+avr_assemble_integer (x, size, aligned_p)
+ rtx x;
+ unsigned int size;
+ int aligned_p;
{
- if (SYMBOL_REF_FLAG (value) || GET_CODE (value) == LABEL_REF)
- {
- fprintf (file, "\t.word pm(");
- output_addr_const (file, (value));
- fprintf (file, ")\n");
- }
- else
+ if (size == POINTER_SIZE / BITS_PER_UNIT && aligned_p
+ && ((GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FLAG (x))
+ || GET_CODE (x) == LABEL_REF))
{
- fprintf (file, "\t.word ");
- output_addr_const (file, (value));
- fprintf (file, "\n");
+ fputs ("\t.word\tpm(", asm_out_file);
+ output_addr_const (asm_out_file, x);
+ fputs (")\n", asm_out_file);
+ return true;
}
+ return default_assemble_integer (x, size, aligned_p);
}
REAL_VALUE_TO_TARGET_SINGLE (n, val);
REAL_VALUE_TO_DECIMAL (n, "%g", dstr);
- fprintf (file, "\t.long 0x%08lx\t/* %s */\n",val, dstr);
+ fprintf (file, "\t.long 0x%08lx\t/* %s */\n", val, dstr);
}
/* Sets section name for declaration DECL */
int reloc ATTRIBUTE_UNUSED;
{
int len;
- char *name,*string;
- char *prefix;
+ const char *name, *prefix;
+ char *string;
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
/* Strip off any encoding in name. */
STRIP_NAME_ENCODING (name, name);
prefix = ".text";
}
else
- fatal ("Strange situation: unique section is not a FUNCTION_DECL");
+ abort ();
if (flag_function_sections)
{
}
-/* Output section name to file FILE */
-
-void
-asm_output_section_name(file, decl, name, reloc)
- FILE *file;
- tree decl ATTRIBUTE_UNUSED;
- const char *name;
- int reloc ATTRIBUTE_UNUSED;
-{
- fprintf (file, ".section %s\n", name);
-}
-
-
/* The routine used to output NUL terminated strings. We use a special
version of this for most svr4 targets because doing so makes the
generated assembly code more compact (and thus faster to assemble)
void
gas_output_limited_string(file, str)
- FILE * file ATTRIBUTE_UNUSED;
- char * str;
+ FILE *file;
+ const char * str;
{
- unsigned char *_limited_str = (unsigned char *) str;
+ const unsigned char *_limited_str = (unsigned char *) str;
unsigned ch;
- fprintf (file, "\t%s\t\"", STRING_ASM_OP);
+ fprintf (file, "%s\"", STRING_ASM_OP);
for (; (ch = *_limited_str); _limited_str++)
{
int escape;
void
gas_output_ascii(file, str, length)
FILE * file;
- char * str;
+ const char * str;
size_t length;
{
- unsigned char *_ascii_bytes = (unsigned char *) str;
- unsigned char *limit = _ascii_bytes + 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++)
{
- register unsigned char *p;
+ const unsigned char *p;
if (bytes_in_chunk >= 60)
{
fprintf (file, "\"\n");
fprintf (file, "\"\n");
bytes_in_chunk = 0;
}
- gas_output_limited_string (file, _ascii_bytes);
+ gas_output_limited_string (file, (char*)_ascii_bytes);
_ascii_bytes = p;
}
else
because registers of CLASS are needed for spill registers. */
enum reg_class
-class_likely_spilled_p(int c)
+class_likely_spilled_p (c)
+ int c;
{
return (c != ALL_REGS && c != ADDW_REGS);
}
-/* Only `progmem' attribute valid for type. */
-
-int
-valid_machine_type_attribute(type, attributes, identifier, args)
- tree type ATTRIBUTE_UNUSED;
- tree attributes ATTRIBUTE_UNUSED;
- tree identifier;
- tree args ATTRIBUTE_UNUSED;
-{
- return is_attribute_p ("progmem", identifier);
-}
-
-/* If IDENTIFIER with arguments ARGS is a valid machine specific
- attribute for DECL return 1.
- Valid attributes:
+/* Valid attributes:
progmem - put data to program memory;
signal - make a function to be hardware interrupt. After function
- epilogue interrupts are disabled;
+ prologue interrupts are disabled;
interrupt - make a function to be hardware interrupt. After function
- epilogue interrupts are enabled;
- naked - don't generate function prologue/epilogue and `ret' command. */
+ prologue interrupts are enabled;
+ naked - don't generate function prologue/epilogue and `ret' command.
-int
-valid_machine_decl_attribute (decl, attributes, attr, args)
- tree decl;
- tree attributes ATTRIBUTE_UNUSED;
- tree attr;
- tree args ATTRIBUTE_UNUSED;
+ Only `progmem' attribute valid for type. */
+
+const struct attribute_spec avr_attribute_table[] =
{
- if (is_attribute_p ("interrupt", attr)
- || is_attribute_p ("signal", attr)
- || is_attribute_p ("naked", attr))
- return TREE_CODE (decl) == FUNCTION_DECL;
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ { "progmem", 0, 0, false, false, false, avr_handle_progmem_attribute },
+ { "signal", 0, 0, true, false, false, avr_handle_fndecl_attribute },
+ { "interrupt", 0, 0, true, false, false, avr_handle_fndecl_attribute },
+ { "naked", 0, 0, true, false, false, avr_handle_fndecl_attribute },
+ { NULL, 0, 0, false, false, false, NULL }
+};
- if (is_attribute_p ("progmem", attr)
- && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
+/* Handle a "progmem" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+avr_handle_progmem_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (DECL_P (*node))
{
- if (DECL_INITIAL (decl) == NULL_TREE)
+ if (TREE_STATIC (*node) || DECL_EXTERNAL (*node))
+ {
+ if (DECL_INITIAL (*node) == NULL_TREE && !DECL_EXTERNAL (*node))
+ {
+ warning ("only initialized variables can be placed into "
+ "program memory area");
+ *no_add_attrs = true;
+ }
+ }
+ else
{
- warning ("Only initialized variables can be placed into "
- "program memory area.");
- return 0;
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
}
- return 1;
}
- return 0;
+
+ return NULL_TREE;
}
+/* Handle an attribute requiring a FUNCTION_DECL; arguments as in
+ struct attribute_spec.handler. */
+static tree
+avr_handle_fndecl_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning ("`%s' attribute only applies to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
/* Look for attribute `progmem' in DECL
- founded - 1 otherwise 0 */
+ if found return 1, otherwise 0. */
int
avr_progmem_p (decl)
return 0;
if (NULL_TREE
- != lookup_attribute ("progmem", DECL_MACHINE_ATTRIBUTES (decl)))
+ != lookup_attribute ("progmem", DECL_ATTRIBUTES (decl)))
return 1;
a=decl;
a = TREE_TYPE(a);
while (TREE_CODE (a) == ARRAY_TYPE);
+ if (a == error_mark_node)
+ return 0;
+
if (NULL_TREE != lookup_attribute ("progmem", TYPE_ATTRIBUTES (a)))
return 1;
{
if (TREE_CODE (decl) == FUNCTION_DECL)
SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
-
- if ((TREE_STATIC (decl) || DECL_EXTERNAL (decl))
- && TREE_CODE (decl) == VAR_DECL
- && avr_progmem_p (decl))
+ else if ((TREE_STATIC (decl) || DECL_EXTERNAL (decl))
+ && TREE_CODE (decl) == VAR_DECL
+ && avr_progmem_p (decl))
{
- char * dsec = ".progmem.data";
+ static const char *const dsec = ".progmem.data";
DECL_SECTION_NAME (decl) = build_string (strlen (dsec), dsec);
+ TREE_READONLY (decl) = 1;
}
}
FILE *file;
{
output_file_directive (file, main_input_filename);
- fprintf (file, "\t.arch %s\n", avr_mcu_type->name);
+ fprintf (file, "\t.arch %s\n", avr_mcu_name);
fputs ("__SREG__ = 0x3f\n"
"__SP_H__ = 0x3e\n"
"__SP_L__ = 0x3d\n", file);
- if (avr_ram_end)
- initial_stack = avr_ram_end;
- else
- {
- static char buf[30];
- initial_stack = buf;
- sprintf (buf, "0x%x", avr_mcu_type->stack);
- }
-
fputs ("__tmp_reg__ = 0\n"
"__zero_reg__ = 1\n"
"_PC_ = 2\n", file);
FILE *file;
{
fprintf (file,
- "/* File %s: code %4d (%4d), prologues %3d, epilogues %3d */\n",
+ "/* 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);
}
next register; and so on. */
void
-order_regs_for_local_alloc (void)
+order_regs_for_local_alloc ()
{
unsigned int i;
- int order_0[] = {
+ static const int order_0[] = {
24,25,
18,19,
20,21,
0,1,
32,33,34,35
};
- int order_1[] = {
+ static const int order_1[] = {
18,19,
20,21,
22,23,
0,1,
32,33,34,35
};
- int order_2[] = {
+ static const int order_2[] = {
25,24,
23,22,
21,20,
32,33,34,35
};
- int *order = (TARGET_ORDER_1 ? order_1 :
- TARGET_ORDER_2 ? order_2 :
- order_0);
- for (i=0; i < sizeof (order_0) / sizeof (order_0[0]); ++i)
+ 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];
}
/* Calculate the cost of a memory address */
int
-avr_address_cost (rtx x)
+avr_address_cost (x)
+ rtx x;
{
if (GET_CODE (x) == PLUS
&& GET_CODE (XEXP (x,1)) == CONST_INT
&& INTVAL (XEXP (x,1)) >= 61)
return 18;
if (CONSTANT_ADDRESS_P (x))
- return 4;
+ {
+ if (io_address_p (x, 1))
+ return 2;
+ return 4;
+ }
return 4;
}
/* EXTRA_CONSTRAINT helper */
int
-extra_constraint (x,c)
+extra_constraint (x, c)
rtx x;
- char c;
+ int c;
{
if (c == 'Q'
&& GET_CODE (x) == MEM
&& REG_P (XEXP (XEXP (x,0), 0))
&& GET_CODE (XEXP (XEXP (x,0), 1)) == CONST_INT
&& (INTVAL (XEXP (XEXP (x,0), 1))
- <= (64 - GET_MODE_SIZE (GET_MODE (x)))))
+ <= MAX_LD_OFFSET (GET_MODE (x))))
{
rtx xx = XEXP (XEXP (x,0), 0);
int regno = REGNO (xx);
case LEU:
return LTU;
default:
- fatal ("Wrong condition: %s", GET_RTX_NAME (condition));
+ abort ();
}
}
rtx first_insn;
{
rtx insn, pattern;
- CC_STATUS_INIT;
for (insn = first_insn; insn; insn = NEXT_INSN (insn))
{
- if (! (insn == 0 || GET_CODE (insn) == INSN
- || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
+ if (! (GET_CODE (insn) == INSN
+ || GET_CODE (insn) == CALL_INSN
+ || GET_CODE (insn) == JUMP_INSN)
|| !single_set (insn))
continue;
pattern = PATTERN (insn);
- cc_prev_status = cc_status;
- NOTICE_UPDATE_CC (pattern, insn);
-
if (GET_CODE (pattern) == PARALLEL)
pattern = XVECEXP (pattern, 0, 0);
if (GET_CODE (pattern) == SET
rtx src = SET_SRC (pat);
rtx t = XEXP (src,0);
- if (!(cc_prev_status.value1 != 0 && cc_status.value1 != 0
- && rtx_equal_p (cc_status.value1, cc_prev_status.value1)))
- {
- PUT_CODE (t, swap_condition (GET_CODE (t)));
- SET_SRC (pattern) = gen_rtx (NEG,
- GET_MODE (SET_SRC (pattern)),
- SET_SRC (pattern));
- INSN_CODE (next) = -1;
- INSN_CODE (insn) = -1;
- }
+ PUT_CODE (t, swap_condition (GET_CODE (t)));
+ SET_SRC (pattern) = gen_rtx (NEG,
+ GET_MODE (SET_SRC (pattern)),
+ SET_SRC (pattern));
+ INSN_CODE (next) = -1;
+ INSN_CODE (insn) = -1;
}
}
}
/* Returns register number for function return value.*/
int
-avr_ret_register (void)
+avr_ret_register ()
{
return 24;
}
function returns a value of data type VALTYPE. */
rtx
-avr_function_value (type,func)
+avr_function_value (type, func)
tree type;
tree func ATTRIBUTE_UNUSED;
{
- int offs;
+ unsigned int offs;
+
if (TYPE_MODE (type) != BLKmode)
return avr_libcall_value (TYPE_MODE (type));
return gen_rtx (REG, BLKmode, RET_REGISTER + 2 - offs);
}
-/* Returns non-zero if number MASK have only one setted bit */
+/* Returns non-zero if the number MASK has only one bit set. */
int
mask_one_bit_p (mask)
unsigned HOST_WIDE_INT n=mask;
for (i = 0; i < 32; ++i)
{
- if (n & 0x80000000UL)
+ if (n & 0x80000000L)
{
- if (n & 0x7fffffffUL)
+ if (n & 0x7fffffffL)
return 0;
else
return 32-i;
in class CLASS. */
enum reg_class
-preferred_reload_class(x,class)
- rtx x;
+preferred_reload_class (x, class)
+ rtx x ATTRIBUTE_UNUSED;
enum reg_class class;
{
- if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0)
- return class;
- if (CONSTANT_P (x) && (class == NO_LD_REGS
- || class == ALL_REGS
- || class == GENERAL_REGS))
- {
- return LD_REGS;
- }
return class;
}
int
-test_hard_reg_class(class, x)
+test_hard_reg_class (class, x)
enum reg_class class;
rtx x;
{
}
void
-debug_hard_reg_set (HARD_REG_SET set)
+debug_hard_reg_set (set)
+ HARD_REG_SET set;
{
int i;
for (i=0; i < FIRST_PSEUDO_REGISTER; ++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;
+}
+
+/* Returns 1 if a value of mode MODE can be stored starting with hard
+ register number REGNO. On the enhanced core, anything larger than
+ 1 byte must start in even numbered register for "movw" to work
+ (this way we don't have to check for odd registers everywhere). */
+
+int
+avr_hard_regno_mode_ok (regno, mode)
+ int regno;
+ enum machine_mode mode;
+{
+ if (mode == QImode)
+ return 1;
+ /* if (regno < 24 && !AVR_ENHANCED)
+ return 1;*/
+ return !(regno & 1);
+}
+
+/* Returns 1 if we know register operand OP was 0 before INSN. */
+
+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))
+ /* Make sure the insn that stored the 0 is still present. */
+ && ! INSN_DELETED_P (XEXP (link, 0))
+ && GET_CODE (XEXP (link, 0)) != NOTE
+ /* Make sure cross jumping didn't happen here. */
+ && no_labels_between_p (XEXP (link, 0), insn)
+ /* Make sure the reg hasn't been clobbered. */
+ && ! reg_set_between_p (op, XEXP (link, 0), insn));
+}
+
+/* Returns 1 if X is a valid address for an I/O register of size SIZE
+ (1 or 2). Used for lds/sts -> in/out optimization. */
+
+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);
+}
+
+/* Returns nonzero (bit number + 1) if X, or -X, is a constant power of 2. */
+
+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++;
+}
+
+/* Returns 1 if SCRATCH are safe to be allocated as a scratch
+ registers (for a define_peephole2) in the current function. */
+
+int
+avr_peep2_scratch_safe (scratch)
+ rtx scratch;
+{
+ if ((interrupt_function_p (current_function_decl)
+ || signal_function_p (current_function_decl))
+ && leaf_function_p ())
+ {
+ int first_reg = true_regnum (scratch);
+ int last_reg = first_reg + GET_MODE_SIZE (GET_MODE (scratch)) - 1;
+ int reg;
+
+ for (reg = first_reg; reg <= last_reg; reg++)
+ {
+ if (!regs_ever_live[reg])
+ return 0;
+ }
+ }
+ return 1;
+}