summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>2000-02-11 22:31:46 +0000
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>2000-02-11 22:31:46 +0000
commita28e4651dd1fd10badcd75e25cf7f727eca29a05 (patch)
treeb53a0316047aa8eaa515ccfa2834204e22979e50
parent60a9564b86354765b421d1b2be27f7f05b612371 (diff)
downloadgcc-a28e4651dd1fd10badcd75e25cf7f727eca29a05.tar.gz
Denis Chertykov <denisc@overta.ru>
* README.AVR: New file with information about the avr ports. * config/avr: New directory with avr port files. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@31935 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog23
-rw-r--r--gcc/README.AVR23
-rw-r--r--gcc/config/avr/avr-protos.h152
-rw-r--r--gcc/config/avr/avr.c3750
-rw-r--r--gcc/config/avr/avr.h3206
-rw-r--r--gcc/config/avr/avr.md1903
-rw-r--r--gcc/config/avr/libgcc.S666
-rw-r--r--gcc/config/avr/t-avr48
-rw-r--r--gcc/config/avr/xm-avr.h1
9 files changed, 9763 insertions, 9 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 01cb80fd93a..1632ef2bb20 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,8 @@
+2000-02-11 Denis Chertykov <denisc@overta.ru>
+
+ * README.AVR: New file with information about the avr ports.
+ * config/avr: New directory with avr port files.
+
2000-02-11 Andreas Jaeger <aj@suse.de>
* fixinc/Makefile.in (FIXINC_DEFS): Remove unneeded @fixinc_defs@.
@@ -335,17 +340,17 @@ Thu Feb 10 18:28:59 MET 2000 Jan Hubicka <jh@suse.cz>
2000-02-09 Scott Bambrough <scottb@netwinder.org>
- * config/arm/arm.md (movsi): In PIC mode, make sure that a
- constant source address is legitimate.
+ * config/arm/arm.md (movsi): In PIC mode, make sure that a
+ constant source address is legitimate.
2000-02-09 Philip Blundell <pb@futuretv.com>
- * config/arm/arm.c (legitimize_pic_address): Handle LABEL_REF
- correctly.
+ * config/arm/arm.c (legitimize_pic_address): Handle LABEL_REF
+ correctly.
- * config/arm/arm.h (LEGITIMATE_CONSTANT_P): Allow anything when
- generating PIC.
- (LEGITIMATE_PIC_OPERAND): Disallow references to labels.
+ * config/arm/arm.h (LEGITIMATE_CONSTANT_P): Allow anything when
+ generating PIC.
+ (LEGITIMATE_PIC_OPERAND): Disallow references to labels.
2000-02-09 Zack Weinberg <zack@wolery.cumb.org>
@@ -396,8 +401,8 @@ Tue Feb 8 15:51:50 2000 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
2000-02-08 Clinton Popetz <cpopetz@cygnus.com>
- * function.c (thread_prologue_and_epilogue_insns): Don't replace
- jumps with returns unless they are jumps to the fallthru block.
+ * function.c (thread_prologue_and_epilogue_insns): Don't replace
+ jumps with returns unless they are jumps to the fallthru block.
Tue Feb 8 07:53:55 2000 Jan Hubicka <jh@suse.cz>
diff --git a/gcc/README.AVR b/gcc/README.AVR
new file mode 100644
index 00000000000..0971cecb14e
--- /dev/null
+++ b/gcc/README.AVR
@@ -0,0 +1,23 @@
+This file describes the implementation notes of the GNU C Compiler for
+the ATMEL AVR micro controllers family.
+
+The generated assembly code requires the GNU assembler (GAS). This is
+not currently included as part of the binutils package.
+Patches against binutils-2.9.5.0.13 can be obtained from
+http://medo.fov.uni-mb.si/mapp/uTools. This site also has patches for
+the GNU debugger (GDB).
+
+
+GCC can be configured as a cross compiler for the AVR architectures
+on the same system. Use `configure --target=avr' to configure GCC.
+
+
+Further installation notes and other useful information about AVR tools
+can also be obtained from http://medo.fov.uni-mb.si/mapp/uTools.
+
+
+Mailing list, avr@fov.uni-mb.si, exists to discuss related issues and
+suggestions for further optimizations and improvements.
+
+
+Denis Chertykov <denisc@overta.ru>, 30 Jan 2000 \ No newline at end of file
diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h
new file mode 100644
index 00000000000..fc525c285dc
--- /dev/null
+++ b/gcc/config/avr/avr-protos.h
@@ -0,0 +1,152 @@
+/* Prototypes for exported functions defined in avr.c
+
+ Copyright (C) 2000 Free Software Foundation, Inc.
+ Contributed by Denis Chertykov (denisc@overta.ru)
+
+ This file is part of GNU CC.
+
+ GNU CC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU CC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU CC; see the file COPYING. If not, write to
+ the Free Software Foundation, 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+
+extern void avr_output_ascii PARAMS ((FILE *file,
+ const char *p,
+ int size));
+extern int function_arg_regno_p PARAMS ((int r));
+extern void asm_file_start PARAMS ((FILE *file));
+extern void asm_file_end PARAMS ((FILE *file));
+extern void avr_init_once PARAMS ((void));
+extern void avr_override_options PARAMS ((void));
+extern char * avr_change_section PARAMS ((char *sect_name));
+extern int avr_ret_register PARAMS((void));
+extern enum reg_class class_likely_spilled_p PARAMS ((int c));
+extern enum reg_class avr_regno_reg_class PARAMS ((int r));
+extern enum reg_class avr_reg_class_from_letter PARAMS ((int c));
+extern int frame_pointer_required_p PARAMS ((void));
+extern void asm_globalize_label PARAMS ((FILE *file,
+ const char *name));
+extern void order_regs_for_local_alloc PARAMS ((void));
+extern int initial_elimination_offset PARAMS ((int from, int to));
+extern void function_prologue PARAMS ((FILE *file, int size));
+extern void function_epilogue PARAMS ((FILE *file, int size));
+extern void progmem_section PARAMS ((void));
+extern int mask_one_bit_p PARAMS ((HOST_WIDE_INT mask));
+
+#ifdef TREE_CODE
+extern void asm_output_external PARAMS ((FILE *file, tree decl,
+ char *name));
+extern void unique_section PARAMS ((tree decl, int reloc));
+extern void encode_section_info PARAMS ((tree decl));
+extern void asm_output_section_name PARAMS ((FILE *file, tree decl,
+ const char *name,
+ int reloc));
+extern int valid_machine_type_attribute PARAMS ((tree type, tree attributes,
+ tree identifier,
+ tree args));
+extern int valid_machine_decl_attribute PARAMS ((tree decl, tree attributes,
+ tree attr, tree args));
+
+#ifdef RTX_CODE /* inside TREE_CODE */
+extern rtx avr_function_value PARAMS ((tree type, tree func));
+extern void init_cumulative_args PARAMS ((CUMULATIVE_ARGS *cum,
+ tree fntype, rtx libname,
+ int indirect));
+extern rtx function_arg PARAMS ((CUMULATIVE_ARGS *cum,
+ enum machine_mode mode,
+ tree type, int named));
+
+
+#endif /* RTX_CODE inside TREE_CODE */
+
+#ifdef HAVE_MACHINE_MODES /* inside TREE_CODE */
+extern void function_arg_advance PARAMS ((CUMULATIVE_ARGS *cum,
+ enum machine_mode mode, tree type,
+ int named));
+#endif /* HAVE_MACHINE_MODES inside TREE_CODE*/
+#endif /* TREE_CODE */
+
+#ifdef RTX_CODE
+extern void asm_output_external_libcall PARAMS ((FILE *file, rtx symref));
+extern int legitimate_address_p PARAMS ((enum machine_mode mode, rtx x,
+ int strict));
+extern void machine_dependent_reorg PARAMS ((rtx first_insn));
+extern int compare_diff_p PARAMS ((rtx insn));
+extern char * out_movqi_r_mr PARAMS ((rtx insn, rtx op[], int *l));
+extern char * out_movqi_mr_r PARAMS ((rtx insn, rtx op[], int *l));
+extern char * out_movhi_r_mr PARAMS ((rtx insn, rtx op[], int *l));
+extern char * out_movhi_mr_r PARAMS ((rtx insn, rtx op[], int *l));
+extern char * out_movsi_r_mr PARAMS ((rtx insn, rtx op[], int *l));
+extern char * out_movsi_mr_r PARAMS ((rtx insn, rtx op[], int *l));
+extern char * output_movsisf PARAMS ((rtx insn, rtx operands[],
+ int which_alternative));
+extern char * out_tstsi PARAMS ((rtx insn, int *l));
+extern char * out_tsthi PARAMS ((rtx insn, int *l));
+extern char * ret_cond_branch PARAMS ((RTX_CODE cond, int len));
+
+extern char * ashlqi3_out PARAMS ((rtx insn, rtx operands[], int *len));
+extern char * ashlhi3_out PARAMS ((rtx insn, rtx operands[], int *len));
+extern char * ashlsi3_out PARAMS ((rtx insn, rtx operands[], int *len));
+
+extern char * ashrqi3_out PARAMS ((rtx insn, rtx operands[], int *len));
+extern char * ashrhi3_out PARAMS ((rtx insn, rtx operands[], int *len));
+extern char * ashrsi3_out PARAMS ((rtx insn, rtx operands[], int *len));
+
+extern char * lshrqi3_out PARAMS ((rtx insn, rtx operands[], int *len));
+extern char * lshrhi3_out PARAMS ((rtx insn, rtx operands[], int *len));
+extern char * lshrsi3_out PARAMS ((rtx insn, rtx operands[], int *len));
+
+extern int avr_address_cost PARAMS ((rtx x));
+extern enum reg_class preferred_reload_class PARAMS ((rtx x,
+ enum reg_class class));
+extern int extra_constraint PARAMS ((rtx x, char c));
+extern rtx legitimize_address PARAMS ((rtx x, rtx oldx,
+ enum machine_mode mode));
+extern int adjust_insn_length PARAMS ((rtx insn, int len));
+extern rtx avr_libcall_value PARAMS ((enum machine_mode mode));
+extern char * output_reload_inhi PARAMS ((rtx insn, rtx *operands,
+ int which_alternative));
+extern char * output_reload_insisf PARAMS ((rtx insn, rtx *operands,
+ int which_alternative));
+extern int default_rtx_costs PARAMS ((rtx X, RTX_CODE code,
+ RTX_CODE outer_code));
+extern void asm_output_char PARAMS ((FILE *file, rtx value));
+extern void asm_output_short PARAMS ((FILE *file, rtx value));
+extern void asm_output_byte PARAMS ((FILE *file, char value));
+extern enum reg_class secondary_input_reload_class PARAMS ((enum reg_class,
+ enum machine_mode,
+ rtx));
+extern void notice_update_cc PARAMS ((rtx body, rtx insn));
+extern void print_operand PARAMS ((FILE *file, rtx x, int code));
+extern void print_operand_address PARAMS ((FILE *file, rtx addr));
+extern int reg_unused_after PARAMS ((rtx insn, rtx reg));
+extern int _reg_unused_after PARAMS ((rtx insn, rtx reg));
+extern int avr_jump_mode PARAMS ((rtx x, rtx insn));
+extern int byte_immediate_operand PARAMS ((register rtx op,
+ enum machine_mode mode));
+
+#endif /* RTX_CODE */
+
+#ifdef HAVE_MACHINE_MODES
+extern int class_max_nregs PARAMS ((enum reg_class class,
+ enum machine_mode mode));
+#endif /* HAVE_MACHINE_MODES */
+
+#ifdef REAL_VALUE_TYPE
+
+extern void asm_output_float PARAMS ((FILE *file, REAL_VALUE_TYPE n));
+
+#endif
+
+
diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c
new file mode 100644
index 00000000000..21c87dc8846
--- /dev/null
+++ b/gcc/config/avr/avr.c
@@ -0,0 +1,3750 @@
+/* Subroutines for insn-output.c for ATMEL AVR micro controllers
+ Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ Contributed by Denis Chertykov (denisc@overta.ru)
+
+ This file is part of GNU CC.
+
+ GNU CC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU CC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU CC; see the file COPYING. If not, write to
+ the Free Software Foundation, 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "config.h"
+#include <stdio.h>
+#include <string.h>
+#include "rtl.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#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 "reload.h"
+#include "tree.h"
+#include "expr.h"
+#include "toplev.h"
+#include "obstack.h"
+#include "function.h"
+#include "recog.h"
+#include "tm_p.h"
+
+
+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));
+
+
+/* Allocate registers from r25 to r8 for parameters for function calls */
+#define FIRST_CUM_REG 26
+
+/* Temporary register RTX (gen_rtx (REG,QImode,TMP_REGNO)) */
+rtx tmp_reg_rtx;
+
+/* Zeroed register RTX (gen_rtx (REG,QImode,ZERO_REGNO)) */
+rtx zero_reg_rtx;
+
+/* AVR register names {"r0", "r1", ..., "r31"} */
+char * avr_regnames[] = REGISTER_NAMES;
+
+/* This holds the last insn address. */
+static int last_insn_address = 0;
+
+/* Commands count in the compiled file */
+static int commands_in_file;
+
+/* Commands in the functions prologues in the compiled file */
+static int commands_in_prologues;
+
+/* Commands in the functions epilogues in the compiled file */
+static int commands_in_epilogues;
+
+/* Prologue/Epilogue size in words */
+static int prologue_size;
+static int epilogue_size;
+
+/* Initial stack value specified by the `-minit-stack=' option */
+const char *avr_ram_end = NULL;
+
+/* Numeric representation */
+static const char *initial_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 */
+
+void
+avr_override_options (void)
+{
+ for (avr_mcu_type = mcu_types; avr_mcu_type->name; ++avr_mcu_type)
+ if (strcmp (avr_mcu_type->name, avr_mcu_name) == 0)
+ break;
+ if (!avr_mcu_type->name)
+ {
+ 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");
+ }
+}
+
+/* Initialize TMP_REG_RTX and ZERO_REG_RTX */
+void
+avr_init_once (void)
+{
+ tmp_reg_rtx = xmalloc (sizeof (struct rtx_def) + 1 * sizeof (rtunion));
+ memset (tmp_reg_rtx, 0, sizeof (struct rtx_def) + 1 * sizeof (rtunion));
+ PUT_CODE (tmp_reg_rtx, REG);
+ PUT_MODE (tmp_reg_rtx, QImode);
+ XINT (tmp_reg_rtx, 0) = TMP_REGNO;
+
+ zero_reg_rtx = xmalloc (sizeof (struct rtx_def) + 1 * sizeof (rtunion));
+ memset (zero_reg_rtx, 0, sizeof (struct rtx_def) + 1 * sizeof (rtunion));
+ PUT_CODE (zero_reg_rtx, REG);
+ PUT_MODE (zero_reg_rtx, QImode);
+ XINT (zero_reg_rtx, 0) = ZERO_REGNO;
+}
+
+/* return register class from register number */
+
+static int reg_class_tab[]={
+ GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,
+ GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,
+ GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,
+ GENERAL_REGS, /* r0 - r15 */
+ LD_REGS,LD_REGS,LD_REGS,LD_REGS,LD_REGS,LD_REGS,LD_REGS,
+ LD_REGS, /* r16 - 23 */
+ ADDW_REGS,ADDW_REGS, /* r24,r25 */
+ POINTER_X_REGS,POINTER_X_REGS, /* r26,27 */
+ POINTER_Y_REGS,POINTER_Y_REGS, /* r28,r29 */
+ POINTER_Z_REGS,POINTER_Z_REGS, /* r30,r31 */
+ STACK_REG,STACK_REG /* SPL,SPH */
+};
+
+/* Return register class for register R */
+
+enum reg_class
+avr_regno_reg_class (r)
+ int r;
+{
+ if (r <= 33)
+ return reg_class_tab[r];
+ return ALL_REGS;
+}
+
+
+/* A C expression which defines the machine-dependent operand
+ constraint letters for register classes. If C is such a
+ letter, the value should be the register class corresponding to
+ it. Otherwise, the value should be `NO_REGS'. The register
+ letter `r', corresponding to class `GENERAL_REGS', will not be
+ passed to this macro; you do not need to handle it. */
+
+enum reg_class
+avr_reg_class_from_letter (c)
+ int c;
+{
+ switch (c)
+ {
+ case 't' : return R0_REG;
+ case 'b' : return BASE_POINTER_REGS;
+ case 'e' : return POINTER_REGS;
+ case 'w' : return ADDW_REGS;
+ case 'd' : return LD_REGS;
+ case 'l' : return NO_LD_REGS;
+ case 'a' : return SIMPLE_LD_REGS;
+ case 'x' : return POINTER_X_REGS;
+ case 'y' : return POINTER_Y_REGS;
+ case 'z' : return POINTER_Z_REGS;
+ case 'q' : return STACK_REG;
+ default: break;
+ }
+ return NO_REGS;
+}
+
+/* Return non-zero if FUNC is a naked function. */
+
+static int
+avr_naked_function_p (func)
+ tree func;
+{
+ tree a;
+
+ if (TREE_CODE (func) != FUNCTION_DECL)
+ abort ();
+
+ a = lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (func));
+ return a != NULL_TREE;
+}
+
+/* Return nonzero if FUNC is an interrupt function as specified
+ by the "interrupt" attribute. */
+
+static int
+interrupt_function_p (func)
+ tree func;
+{
+ tree a;
+
+ if (TREE_CODE (func) != FUNCTION_DECL)
+ return 0;
+
+ a = lookup_attribute ("interrupt", DECL_MACHINE_ATTRIBUTES (func));
+ return a != NULL_TREE;
+}
+
+/* Return nonzero if FUNC is an signal function as specified
+ by the "signal" attribute. */
+
+static int
+signal_function_p (func)
+ tree func;
+{
+ tree a;
+
+ if (TREE_CODE (func) != FUNCTION_DECL)
+ return 0;
+
+ a = lookup_attribute ("signal", DECL_MACHINE_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;
+{
+ 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 ((!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;
+}
+
+/* This function checks sequence of live registers */
+
+static int
+sequent_regs_live ()
+{
+ int reg;
+ int live_seq=0;
+ int cur_seq=0;
+
+ for (reg = 0; reg < 18; ++reg)
+ {
+ if (!call_used_regs[reg])
+ {
+ if (regs_ever_live[reg])
+ {
+ ++live_seq;
+ ++cur_seq;
+ }
+ else
+ cur_seq = 0;
+ }
+ }
+
+ if (!frame_pointer_needed)
+ {
+ if (regs_ever_live[REG_Y])
+ {
+ ++live_seq;
+ ++cur_seq;
+ }
+ else
+ cur_seq = 0;
+
+ if (regs_ever_live[REG_Y+1])
+ {
+ ++live_seq;
+ ++cur_seq;
+ }
+ else
+ cur_seq = 0;
+ }
+ else
+ {
+ cur_seq += 2;
+ live_seq += 2;
+ }
+ return (cur_seq == live_seq) ? live_seq : 0;
+}
+
+
+/* Output function prologue */
+
+void
+function_prologue (FILE *file, int size)
+{
+ int reg;
+ int interrupt_func_p;
+ int signal_func_p;
+ int leaf_func_p;
+ int main_p;
+ int live_seq;
+ int minimize;
+
+ if (avr_naked_function_p (current_function_decl))
+ {
+ fprintf (file, "/* prologue: naked */\n");
+ return;
+ }
+
+ interrupt_func_p = interrupt_function_p (current_function_decl);
+ signal_func_p = signal_function_p (current_function_decl);
+ leaf_func_p = leaf_function_p ();
+ main_p = ! strcmp ("main", current_function_name);
+ live_seq = sequent_regs_live ();
+ minimize = (TARGET_CALL_PROLOGUES
+ && !interrupt_func_p && !signal_func_p && live_seq);
+
+ last_insn_address = 0;
+ prologue_size = 0;
+ fprintf (file, "/* prologue: frame size=%d */\n", size);
+
+ if (interrupt_func_p)
+ {
+ fprintf (file,"\tsei\n");
+ ++prologue_size;
+ }
+ if (interrupt_func_p | signal_func_p)
+ {
+ fprintf (file, "\t"
+ AS1 (push,__zero_reg__) CR_TAB
+ AS1 (push,__tmp_reg__) CR_TAB
+ AS2 (in,__tmp_reg__,__SREG__) CR_TAB
+ AS1 (push,__tmp_reg__) CR_TAB
+ AS1 (clr,__zero_reg__) "\n");
+ prologue_size += 5;
+ }
+ if (main_p)
+ {
+ fprintf (file, ("\t"
+ AS2 (ldi, r28, lo8(%s - %d)) CR_TAB
+ AS2 (ldi, r29, hi8(%s - %d)) CR_TAB
+ AS2 (out,__SP_L__,r28) CR_TAB
+ AS2 (out,__SP_H__,r29) "\n"),
+ initial_stack, size, initial_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);
+
+ fprintf (file, (AS2 (ldi, r30, pm_lo8(.L_%s_body)) CR_TAB
+ AS2 (ldi, r31, pm_hi8(.L_%s_body)) CR_TAB)
+ ,current_function_name, current_function_name);
+
+ prologue_size += 4;
+
+ if (AVR_MEGA)
+ {
+ fprintf (file, AS1 (jmp,__prologue_saves__+%d) "\n",
+ (18 - live_seq) * 2);
+ prologue_size += 2;
+ }
+ else
+ {
+ fprintf (file, AS1 (rjmp,__prologue_saves__+%d) "\n",
+ (18 - live_seq) * 2);
+ ++prologue_size;
+ }
+ fprintf (file, ".L_%s_body:\n", current_function_name);
+ }
+ else
+ {
+ for (reg = 0; reg < 32; ++reg)
+ {
+ if ((!leaf_func_p
+ && (call_used_regs[reg]
+ && (interrupt_func_p || signal_func_p)
+ && !(reg == TMP_REGNO || reg == ZERO_REGNO)))
+ || (regs_ever_live[reg]
+ && (!call_used_regs[reg]
+ || interrupt_func_p || signal_func_p)
+ && ! (frame_pointer_needed
+ && (reg == REG_Y || reg == (REG_Y+1)))))
+ {
+ fprintf (file, "\t" AS1 (push,%s) "\n", avr_regnames[reg]);
+ ++prologue_size;
+ }
+ }
+ if (frame_pointer_needed)
+ {
+ {
+ fprintf (file, "\t"
+ AS1 (push,r28) CR_TAB
+ AS1 (push,r29) CR_TAB
+ AS2 (in,r28,__SP_L__) CR_TAB
+ AS2 (in,r29,__SP_H__) "\n");
+ prologue_size += 4;
+ if (size)
+ {
+ 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;
+ }
+ 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;
+ }
+ else if (signal_func_p || TARGET_NO_INTERRUPTS)
+ {
+ fprintf (file,
+ AS2 (out,__SP_L__,r28) CR_TAB
+ AS2 (out,__SP_H__,r29) "\n");
+ prologue_size += 2;
+ }
+ 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;
+ }
+ }
+ }
+ }
+ }
+ fprintf (file, "/* prologue end (size=%d) */\n", prologue_size);
+}
+
+/* Output function epilogue */
+
+void
+function_epilogue (FILE *file, int size)
+{
+ int reg;
+ int interrupt_func_p;
+ int signal_func_p;
+ int leaf_func_p;
+ int main_p;
+ int function_size;
+ int live_seq;
+ int minimize;
+
+ if (avr_naked_function_p (current_function_decl))
+ {
+ fprintf (file, "/* epilogue: naked */\n");
+ return;
+ }
+
+ interrupt_func_p = interrupt_function_p (current_function_decl);
+ signal_func_p = signal_function_p (current_function_decl);
+ leaf_func_p = leaf_function_p ();
+ main_p = ! strcmp ("main", current_function_name);
+ function_size = (insn_addresses[INSN_UID (get_last_insn ())]
+ - insn_addresses[INSN_UID (get_insns ())]);
+ live_seq = sequent_regs_live ();
+ minimize = (TARGET_CALL_PROLOGUES
+ && !interrupt_func_p && !signal_func_p && live_seq);
+
+ epilogue_size = 0;
+ fprintf (file, "/* epilogue: frame size=%d */\n", size);
+ if (main_p)
+ {
+ fprintf (file, "__stop_progIi__:\n\trjmp __stop_progIi__\n");
+ ++epilogue_size;
+ }
+ else if (minimize && (frame_pointer_needed || live_seq > 4))
+ {
+ fprintf (file, ("\t" AS2 (ldi, r30, %d) CR_TAB), live_seq);
+ ++epilogue_size;
+ if (frame_pointer_needed)
+ {
+ 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;
+ }
+ }
+ }
+ else
+ {
+ fprintf (file, (AS2 (in , r28, __SP_L__) CR_TAB
+ AS2 (in , r29, __SP_H__) CR_TAB));
+ epilogue_size += 2;
+ }
+
+ if (AVR_MEGA)
+ {
+ fprintf (file, AS1 (jmp,__epilogue_restores__+%d) "\n",
+ (18 - live_seq) * 2);
+ epilogue_size += 2;
+ }
+ else
+ {
+ fprintf (file, AS1 (rjmp,__epilogue_restores__+%d) "\n",
+ (18 - live_seq) * 2);
+ ++epilogue_size;
+ }
+ }
+ else
+ {
+ if (frame_pointer_needed)
+ {
+ if (size)
+ {
+ 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;
+ }
+ 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;
+ }
+ 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;
+ }
+ }
+ fprintf (file, "\t"
+ AS1 (pop,r29) CR_TAB
+ AS1 (pop,r28) "\n");
+ epilogue_size += 2;
+ }
+
+ for (reg = 31; reg >= 0; --reg)
+ {
+ if ((!leaf_func_p
+ && (call_used_regs[reg]
+ && (interrupt_func_p || signal_func_p)
+ && !(reg == TMP_REGNO || reg == ZERO_REGNO)))
+ || (regs_ever_live[reg]
+ && (!call_used_regs[reg]
+ || interrupt_func_p || signal_func_p)
+ && ! (frame_pointer_needed
+ && (reg == REG_Y || reg == (REG_Y+1)))))
+ {
+ fprintf (file, "\t" AS1 (pop,%s) "\n", avr_regnames[reg]);
+ ++epilogue_size;
+ }
+ }
+
+ if (interrupt_func_p | signal_func_p)
+ {
+ fprintf (file, "\t"
+ AS1 (pop,__tmp_reg__) CR_TAB
+ AS2 (out,__SREG__,__tmp_reg__) CR_TAB
+ AS1 (pop,__tmp_reg__) CR_TAB
+ AS1 (pop,__zero_reg__) "\n");
+ epilogue_size += 4;
+ fprintf (file, "\treti\n");
+ }
+ else
+ fprintf (file, "\tret\n");
+ ++epilogue_size;
+ }
+
+ fprintf (file, "/* epilogue end (size=%d) */\n", epilogue_size);
+ fprintf (file, "/* function %s size %d (%d) */\n", current_function_name,
+ prologue_size + function_size + epilogue_size, function_size);
+ commands_in_file += prologue_size + function_size + epilogue_size;
+ commands_in_prologues += prologue_size;
+ commands_in_epilogues += epilogue_size;
+}
+
+
+/* Return nonzero if X (an RTX) is a legitimate memory address on the target
+ machine for a memory operand of mode MODE. */
+
+int
+legitimate_address_p (mode, x, strict)
+ enum machine_mode mode;
+ rtx x;
+ int strict;
+{
+ int r = 0;
+ if (TARGET_ALL_DEBUG)
+ {
+ fprintf (stderr, "mode: (%s) %s %s %s %s:",
+ GET_MODE_NAME(mode),
+ strict ? "(strict)": "",
+ reload_completed ? "(reload_completed)": "",
+ reload_in_progress ? "(reload_in_progress)": "",
+ reg_renumber ? "(reg_renumber)" : "");
+ if (GET_CODE (x) == PLUS
+ && REG_P (XEXP (x, 0))
+ && GET_CODE (XEXP (x, 1)) == CONST_INT
+ && INTVAL (XEXP (x, 1)) >= 0
+ && INTVAL (XEXP (x, 1)) <= (64 - GET_MODE_SIZE (mode))
+ && reg_renumber
+ )
+ fprintf (stderr, "(r%d ---> r%d)", REGNO (XEXP (x, 0)),
+ true_regnum (XEXP (x, 0)));
+ debug_rtx (x);
+ }
+ if (REG_P (x) && (strict ? REG_OK_FOR_BASE_STRICT_P (x)
+ : REG_OK_FOR_BASE_NOSTRICT_P (x)))
+ r = 'R';
+ else if (CONSTANT_ADDRESS_P (x))
+ r = 'S';
+ 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));
+ if (fit)
+ {
+ if (! strict
+ || REGNO (XEXP (x,0)) == REG_Y || REGNO (XEXP (x,0)) == REG_Z)
+ r = 'Q';
+ if (XEXP (x,0) == frame_pointer_rtx
+ || XEXP (x,0) == arg_pointer_rtx)
+ r = 'Q';
+ }
+ else if (frame_pointer_needed && XEXP (x,0) == frame_pointer_rtx)
+ r = 'U';
+ }
+ 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';
+ }
+ if (TARGET_ALL_DEBUG)
+ {
+ fprintf (stderr, " ret = %c\n", r);
+ }
+ return r;
+}
+
+/* Attempts to replace X with a valid
+ memory address for an operand of mode MODE */
+
+rtx
+legitimize_address (x, oldx, mode)
+ rtx x;
+ rtx oldx;
+ enum machine_mode mode;
+{
+ x = oldx;
+ if (TARGET_ALL_DEBUG)
+ {
+ fprintf (stderr, "legitimize_address mode: %s", GET_MODE_NAME(mode));
+ debug_rtx (oldx);
+ }
+
+ if (GET_CODE (oldx) == PLUS
+ && REG_P (XEXP (oldx,0)))
+ {
+ if (REG_P (XEXP (oldx,1)))
+ x = force_reg (GET_MODE (oldx), oldx);
+ else if (GET_CODE (XEXP (oldx, 1)) == CONST_INT)
+ {
+ int offs = INTVAL (XEXP (oldx,1));
+ if (frame_pointer_rtx != XEXP (oldx,0))
+ if (offs > 64 - GET_MODE_SIZE (mode))
+ {
+ if (TARGET_ALL_DEBUG)
+ fprintf (stderr, "force_reg (big offset)\n");
+ x = force_reg (GET_MODE (oldx), oldx);
+ }
+ }
+ }
+ return x;
+}
+
+
+/* Return a pointer register name as a string */
+
+static char *
+ptrreg_to_str (regno)
+ int regno;
+{
+ switch (regno)
+ {
+ case REG_X: return "X";
+ case REG_Y: return "Y";
+ case REG_Z: return "Z";
+ default:
+ fatal ("register r%d isn't a pointer\n", regno);
+ }
+ return NULL;
+}
+
+/* Return the condition name as a string.
+ Used in conditional jump constructing */
+
+static char *
+cond_string (code)
+ enum rtx_code code;
+{
+ switch (code)
+ {
+ case NE:
+ return "ne";
+ case EQ:
+ return "eq";
+ case GE:
+ if (cc_prev_status.flags & CC_OVERFLOW_UNUSABLE)
+ return "pl";
+ else
+ return "ge";
+ case 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";
+ else
+ 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:
+ abort ();
+ }
+}
+
+/* Output ADDR to FILE as address */
+
+void
+print_operand_address (file, addr)
+ FILE *file;
+ rtx addr;
+{
+ switch (GET_CODE (addr))
+ {
+ case REG:
+ fprintf (file, ptrreg_to_str (REGNO (addr)));
+ break;
+
+ case PRE_DEC:
+ fprintf (file, "-%s", ptrreg_to_str (REGNO (XEXP (addr, 0))));
+ break;
+
+ case POST_INC:
+ fprintf (file, "%s+", ptrreg_to_str (REGNO (XEXP (addr, 0))));
+ break;
+
+ default:
+ if (CONSTANT_ADDRESS_P (addr)
+ && (SYMBOL_REF_FLAG (addr) || GET_CODE (addr) == LABEL_REF))
+ {
+ fprintf (file, "pm(");
+ output_addr_const (file,addr);
+ fprintf (file ,")");
+ }
+ else
+ output_addr_const (file, addr);
+ }
+}
+
+
+/* Output X as assembler operand to file FILE */
+
+void
+print_operand (file, x, code)
+ FILE *file;
+ rtx x;
+ int code;
+{
+ int abcd = 0;
+
+ if (code >= 'A' && code <= 'D')
+ abcd = code - 'A';
+
+ if (REG_P (x))
+ {
+ if (x == zero_reg_rtx)
+ fprintf (file,"__zero_reg__");
+ else
+ fprintf (file, reg_names[true_regnum (x) + abcd]);
+ }
+ else if (GET_CODE (x) == CONST_INT)
+ fprintf (file, "%d", INTVAL (x) + abcd);
+ else if (GET_CODE (x) == MEM)
+ {
+ rtx addr = XEXP (x,0);
+ if (code == 'K')
+ {
+ if (CONSTANT_P (addr))
+ putc ('s', file);
+ else if (GET_CODE (addr) == PLUS)
+ putc ('d', file);
+ }
+ else if (CONSTANT_P (addr) && abcd)
+ {
+ fputc ('(', file);
+ output_address (addr);
+ fprintf (file, ")+%d", abcd);
+ }
+ 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:"
+ ,addr);
+ fputc ('+', file);
+ print_operand (file, XEXP (addr,1), code);
+ }
+ else
+ print_operand_address (file, addr);
+ }
+ else if (GET_CODE (x) == CONST_DOUBLE)
+ {
+ long val;
+ REAL_VALUE_TYPE rv;
+ if (GET_MODE (x) != SFmode)
+ fatal_insn ("Internal compiler bug. Unknown mode:", x);
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
+ REAL_VALUE_TO_TARGET_SINGLE (rv, val);
+ asm_fprintf (file, "0x%x", val);
+ }
+ else if (code == 'j')
+ asm_fprintf (file, cond_string (GET_CODE (x)));
+ else if (code == 'k')
+ asm_fprintf (file, cond_string (reverse_condition (GET_CODE (x))));
+ else
+ output_addr_const (file, x);
+}
+
+/* Recognise operand OP of mode MODE used in call instructions */
+
+int
+call_insn_operand (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ if (GET_CODE (op) == MEM)
+ {
+ rtx inside = XEXP (op, 0);
+ if (register_operand (inside, Pmode))
+ return 1;
+ if (CONSTANT_ADDRESS_P (inside))
+ return 1;
+ }
+ return 0;
+}
+
+/* Update the condition code in the INSN. */
+
+void
+notice_update_cc (body, insn)
+ rtx body ATTRIBUTE_UNUSED;
+ rtx insn;
+{
+ switch (get_attr_cc (insn))
+ {
+ case CC_NONE:
+ /* Insn does not affect CC at all. */
+ break;
+
+ case CC_SET_N:
+ CC_STATUS_INIT;
+ 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);
+ }
+ }
+ 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;
+ }
+ }
+ break;
+
+ case CC_COMPARE:
+ {
+ rtx 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;
+ break;
+ }
+}
+
+/* Return maximum number of consecutive registers of
+ class CLASS needed to hold a value of mode MODE. */
+
+int
+class_max_nregs (class, mode)
+ enum reg_class class ATTRIBUTE_UNUSED;
+ enum machine_mode mode;
+{
+ return ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD);
+}
+
+/* Choose mode for jump insn:
+ 1 - relative jump in range -63 <= x <= 62 ;
+ 2 - relative jump in range -2046 <= x <= 2045 ;
+ 3 - absolute jump (only for ATmega[16]03). */
+
+int
+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 jump_distance = cur_addr - dest_addr;
+
+ if (-63 <= jump_distance && jump_distance <= 62)
+ return 1;
+ else if (-2046 <= jump_distance && jump_distance <= 2045)
+ return 2;
+ else if (AVR_MEGA)
+ return 3;
+
+ return 2;
+}
+
+/* return a AVR condition jump commands.
+ LEN is a number returned by avr_jump_mode function. */
+
+char *
+ret_cond_branch (cond,len)
+ RTX_CODE cond;
+ int len;
+{
+ switch (cond)
+ {
+ case GT:
+ if (cc_prev_status.flags & CC_OVERFLOW_UNUSABLE)
+ return (len == 1 ? (AS1 (breq,_PC_+2) CR_TAB
+ AS1 (brpl,%0)) :
+ len == 2 ? (AS1 (breq,_PC_+4) CR_TAB
+ AS1 (brmi,_PC_+2) CR_TAB
+ AS1 (rjmp,%0)) :
+ (AS1 (breq,_PC_+6) CR_TAB
+ AS1 (brmi,_PC_+4) CR_TAB
+ AS1 (jmp,%0)));
+
+ else
+ return (len == 1 ? (AS1 (breq,_PC_+2) CR_TAB
+ AS1 (brge,%0)) :
+ len == 2 ? (AS1 (breq,_PC_+4) CR_TAB
+ AS1 (brlt,_PC_+2) CR_TAB
+ AS1 (rjmp,%0)) :
+ (AS1 (breq,_PC_+6) CR_TAB
+ AS1 (brlt,_PC_+4) CR_TAB
+ AS1 (jmp,%0)));
+ case GTU:
+ return (len == 1 ? (AS1 (breq,_PC_+2) CR_TAB
+ AS1 (brsh,%0)) :
+ len == 2 ? (AS1 (breq,_PC_+4) CR_TAB
+ AS1 (brlo,_PC_+2) CR_TAB
+ AS1 (rjmp,%0)) :
+ (AS1 (breq,_PC_+6) CR_TAB
+ AS1 (brlo,_PC_+4) CR_TAB
+ AS1 (jmp,%0)));
+ case LE:
+ if (cc_prev_status.flags & CC_OVERFLOW_UNUSABLE)
+ return (len == 1 ? (AS1 (breq,%0) CR_TAB
+ AS1 (brmi,%0)) :
+ len == 2 ? (AS1 (breq,_PC_+2) CR_TAB
+ AS1 (brpl,_PC_+2) CR_TAB
+ AS1 (rjmp,%0)) :
+ (AS1 (breq,_PC_+2) CR_TAB
+ AS1 (brpl,_PC_+4) CR_TAB
+ AS1 (jmp,%0)));
+ else
+ return (len == 1 ? (AS1 (breq,%0) CR_TAB
+ AS1 (brlt,%0)) :
+ len == 2 ? (AS1 (breq,_PC_+2) CR_TAB
+ AS1 (brge,_PC_+2) CR_TAB
+ AS1 (rjmp,%0)) :
+ (AS1 (breq,_PC_+2) CR_TAB
+ AS1 (brge,_PC_+4) CR_TAB
+ AS1 (jmp,%0)));
+ case LEU:
+ return (len == 1 ? (AS1 (breq,%0) CR_TAB
+ AS1 (brlo,%0)) :
+ len == 2 ? (AS1 (breq,_PC_+2) CR_TAB
+ AS1 (brsh,_PC_+2) CR_TAB
+ AS1 (rjmp,%0)) :
+ (AS1 (breq,_PC_+2) CR_TAB
+ AS1 (brsh,_PC_+4) CR_TAB
+ AS1 (jmp,%0)));
+ default:
+ 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 "";
+}
+
+/* Predicate function for immediate operand which fits to byte (8bit) */
+
+int
+byte_immediate_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return (GET_CODE (op) == CONST_INT
+ && INTVAL (op) <= 0xff && INTVAL (op) >= 0);
+}
+
+/* Output all insn addresses and their sizes into the assembly language
+ output file. This is helpful for debugging whether the length attributes
+ in the md file are correct.
+ Output insn cost for next insn. */
+
+void
+final_prescan_insn (insn, operand, num_operands)
+ rtx insn, *operand ATTRIBUTE_UNUSED;
+ int num_operands ATTRIBUTE_UNUSED;
+{
+ int uid = INSN_UID (insn);
+
+ if (TARGET_INSN_SIZE_DUMP || TARGET_ALL_DEBUG)
+ {
+ fprintf (asm_out_file, "/*DEBUG: 0x%x\t\t%d\t%d */\n", insn_addresses[uid],
+ insn_addresses[uid] - last_insn_address,
+ rtx_cost (PATTERN (insn),INSN));
+ }
+ last_insn_address = insn_addresses[uid];
+
+ if (TARGET_RTL_DUMP)
+ {
+ fprintf (asm_out_file, "/*****************\n");
+ print_rtl_single (asm_out_file, insn);
+ fprintf (asm_out_file, "*****************/\n");
+ }
+}
+
+/* return 1 if undefined,
+ 1 if always true or always false */
+
+int
+avr_simplify_comparision_p (mode, operator, x)
+ enum machine_mode mode;
+ RTX_CODE operator;
+ rtx x;
+{
+ unsigned int max = (mode == QImode ? 0xff :
+ mode == HImode ? 0xffff :
+ mode == SImode ? 0xffffffffU : 0);
+ if (max && operator && GET_CODE (x) == CONST_INT)
+ {
+ if (unsigned_condition (operator) != operator)
+ max >>= 1;
+
+ if (max != (INTVAL (x) & max)
+ && INTVAL (x) != 0xff)
+ return 1;
+ }
+ return 0;
+}
+
+
+/* Returns nonzero if REGNO is the number of a hard
+ register in which function arguments are sometimes passed. */
+
+int
+function_arg_regno_p(r)
+ int r;
+{
+ return (r >= 8 && r <= 25);
+}
+
+/* Initializing the variable cum for the state at the beginning
+ of the argument list. */
+
+void
+init_cumulative_args (cum, fntype, libname, indirect)
+ CUMULATIVE_ARGS *cum;
+ tree fntype;
+ rtx libname;
+ int indirect ATTRIBUTE_UNUSED;
+{
+ cum->nregs = 18;
+ cum->regno = FIRST_CUM_REG;
+ if (!libname)
+ {
+ int stdarg = (TYPE_ARG_TYPES (fntype) != 0
+ && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
+ != void_type_node));
+ if (stdarg)
+ cum->nregs = 0;
+ }
+}
+
+/* Controls whether a function argument is passed
+ in a register, and which register. */
+
+rtx
+function_arg (cum, mode, type, named)
+ CUMULATIVE_ARGS *cum;
+ enum machine_mode mode;
+ tree type;
+ int named ATTRIBUTE_UNUSED;
+{
+ int bytes;
+
+ bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
+
+ if (cum->nregs && bytes <= cum->nregs)
+ return gen_rtx (REG, mode, cum->regno - bytes);
+ return NULL_RTX;
+}
+
+/* Update the summarizer variable CUM to advance past an argument
+ in the argument list. */
+
+void
+function_arg_advance (cum, mode, type, named)
+ CUMULATIVE_ARGS *cum; /* current arg information */
+ enum machine_mode mode; /* current arg mode */
+ tree type; /* type of the argument or 0 if lib support */
+ int named ATTRIBUTE_UNUSED; /* whether or not the argument was named */
+{
+ int bytes;
+
+ bytes = (mode == BLKmode ? int_size_in_bytes (type) : GET_MODE_SIZE (mode));
+ cum->nregs -= bytes;
+ cum->regno -= bytes;
+
+ if (cum->nregs <= 0)
+ {
+ 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)
+ rtx insn;
+ rtx op[];
+ int *l; /* instruction length */
+{
+ /* We handle CONSTANT_ADDRESS_P case in adjust_insn_length */
+ if (l) *l=1;
+ if (GET_CODE (op[1]) == MEM)
+ {
+ rtx x = XEXP (op[1],0);
+ 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 (op[1]))) >= 63)
+ {
+ 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 (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));
+ }
+ }
+ 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 (ld, %0,Y) CR_TAB
+ AS2 (subi, r28, lo8(%4)) CR_TAB
+ AS2 (sbci, r29, hi8(%4)));
+ }
+ }
+ 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));
+ }
+ return "";
+ }
+ }
+ }
+ return AS2 (ld%K1,%0,%1);
+}
+
+char *
+out_movhi_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));
+ int len_p = 1,tmp;
+ 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) */
+ {
+ 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])))
+ {
+ 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 - 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));
+ }
+ 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)));
+ }
+ }
+ 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
+ */
+ 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
+ {
+ 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)
+ {
+ output_asm_insn (AS2 (subi, r26, %0+1), ops);
+ output_asm_insn (AS2 (sbci, r26, 0), ops);
+ }
+ else
+ output_asm_insn (AS2 (sbiw, r26, %0+1), ops);
+ }
+ 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.");
+ }
+ return *l=2, (AS2 (ld,%A0,%1) CR_TAB
+ AS2 (ld,%B0,%1));
+ }
+ 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);
+ return "";
+}
+
+char *
+out_movsi_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));
+ 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__));
+ 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)))
+ return *l=4, (AS2 (ld,%A0,X+) CR_TAB
+ AS2 (ld,%B0,X+) CR_TAB
+ AS2 (ld,%C0,X+) CR_TAB
+ AS2 (ld,%D0,X));
+ else
+ return *l=5, (AS2 (ld,%A0,X+) CR_TAB
+ AS2 (ld,%B0,X+) CR_TAB
+ AS2 (ld,%C0,X+) CR_TAB
+ AS2 (ld,%D0,X) CR_TAB
+ AS2 (sbiw,r26,3));
+ }
+ else
+ {
+ if (reg_dest == reg_base)
+ return *l=5, (AS2 (ldd,%D0,%1+3) CR_TAB
+ AS2 (ldd,%C0,%1+2) CR_TAB
+ AS2 (ldd,__tmp_reg__,%1+1) CR_TAB
+ AS2 (ld,%A0,%1) CR_TAB
+ AS2 (mov,%B0,__tmp_reg__));
+ else if (reg_base == reg_dest + 2)
+ return *l=5, (AS2 (ld ,%A0,%1) CR_TAB
+ AS2 (ldd,%B0,%1+1) CR_TAB
+ AS2 (ldd,__tmp_reg__,%1+2) CR_TAB
+ AS2 (ldd,%D0,%1+3) CR_TAB
+ AS2 (mov,%C0,__tmp_reg__));
+ else
+ return *l=4, (AS2 (ld ,%A0,%1) CR_TAB
+ AS2 (ldd,%B0,%1+1) CR_TAB
+ AS2 (ldd,%C0,%1+2) CR_TAB
+ AS2 (ldd,%D0,%1+3));
+ }
+ }
+ else if (GET_CODE (XEXP (op[1],0)) == PLUS) /* (R + i) */
+ {
+ int disp = INTVAL(XEXP (XEXP (op[1],0), 1));
+
+ if (disp > 64 - GET_MODE_SIZE (GET_MODE (op[1])))
+ {
+ 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
+ {
+ 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)));
+ }
+ }
+
+ 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,__tmp_reg__,%B1) CR_TAB
+ AS2 (ldd,%A0,%A1) CR_TAB
+ AS2 (mov,%B0,__tmp_reg__));
+ else if (reg_dest == reg_base - 2)
+ return *l=5, (AS2 (ldd,%A0,%A1) CR_TAB
+ AS2 (ldd,%B0,%B1) CR_TAB
+ AS2 (ldd,__tmp_reg__,%C1) CR_TAB
+ AS2 (ldd,%D0,%D1) CR_TAB
+ AS2 (mov,%C0,__tmp_reg__));
+ return *l=4, (AS2 (ldd,%A0,%A1) CR_TAB
+ AS2 (ldd,%B0,%B1) CR_TAB
+ AS2 (ldd,%C0,%C1) CR_TAB
+ AS2 (ldd,%D0,%D1));
+ }
+ else if (GET_CODE (XEXP (op[1],0)) == 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++) */
+ 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)))
+ return *l=8, (AS2 (lds,%A0,%A1) CR_TAB
+ AS2 (lds,%B0,%B1) CR_TAB
+ AS2 (lds,%C0,%C1) CR_TAB
+ AS2 (lds,%D0,%D1));
+
+ fatal_insn ("Unknown move insn:",insn);
+ return "";
+}
+
+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]);
+ int tmp;
+ if (!l)
+ l = &tmp;
+ if (CONSTANT_ADDRESS_P (XEXP (op[0],0)))
+ return *l=8,(AS2 (sts,%A0,%A1) CR_TAB
+ AS2 (sts,%B0,%B1) CR_TAB
+ AS2 (sts,%C0,%C1) CR_TAB
+ AS2 (sts,%D0,%D1));
+ if (reg_base > 0) /* (r) */
+ {
+ if (reg_base == REG_X) /* (R26) */
+ {
+ if (reg_dest == 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));
+ 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));
+ }
+ else if (reg_base == reg_dest+2)
+ {
+ if (reg_unused_after (insn,XEXP (op[0],0)))
+ return *l=7, (AS2 (mov,__zero_reg__,%C1) CR_TAB
+ AS2 (mov,__tmp_reg__,%D1) CR_TAB
+ AS2 (st,%0+,%A1) CR_TAB
+ AS2 (st,%0+,%B1) CR_TAB
+ AS2 (st,%0+,__zero_reg__) CR_TAB
+ AS2 (st,%0,__tmp_reg__) CR_TAB
+ AS1 (clr,__zero_reg__));
+ else
+ return *l=8, (AS2 (mov,__zero_reg__,%C1) CR_TAB
+ AS2 (mov,__tmp_reg__,%D1) CR_TAB
+ AS2 (st,%0+,%A1) CR_TAB
+ AS2 (st,%0+,%B1) CR_TAB
+ AS2 (st,%0+,__zero_reg__) CR_TAB
+ AS2 (st,%0,__tmp_reg__) CR_TAB
+ AS1 (clr,__zero_reg__) CR_TAB
+ AS2 (sbiw,r26,3));
+ }
+ return *l=5, (AS2 (st,%0+,%A1) CR_TAB
+ AS2 (st,%0+,%B1) CR_TAB
+ AS2 (st,%0+,%C1) CR_TAB
+ AS2 (st,%0,%D1) CR_TAB
+ AS2 (sbiw,r26,3));
+ }
+ else
+ return *l=4, (AS2 (st,%0,%A1) CR_TAB
+ AS2 (std,%0+1,%B1) CR_TAB
+ AS2 (std,%0+2,%C1) CR_TAB
+ AS2 (std,%0+3,%D1));
+ }
+ else if (GET_CODE (XEXP (op[0],0)) == PLUS) /* (R + i) */
+ {
+ int disp = INTVAL(XEXP (XEXP (op[0],0), 1));
+ if (disp > 64 - GET_MODE_SIZE (GET_MODE (op[0])))
+ {
+ 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 - 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));
+ }
+ else
+ {
+ 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)));
+ }
+ }
+ 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) */
+ 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++) */
+ return *l=4, (AS2 (st,%0,%A1) CR_TAB
+ AS2 (st,%0,%B1) CR_TAB
+ AS2 (st,%0,%C1) CR_TAB
+ AS2 (st,%0,%D1));
+ fatal_insn ("Unknown move insn:",insn);
+ return "";
+}
+
+char *
+output_movsisf(insn, operands, which_alternative)
+ rtx insn;
+ rtx operands[];
+ int which_alternative;
+{
+ 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;
+ }
+ }
+ return "";
+}
+
+char *
+out_movqi_mr_r (insn, op, l)
+ rtx insn;
+ rtx op[];
+ int *l; /* instruction length */
+{
+ if (l) *l=1;
+
+ if (GET_CODE (op[0]) == MEM)
+ {
+ rtx x = XEXP (op[0],0);
+ 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 (op[0]))) >= 63)
+ {
+ 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)));
+ }
+ }
+ else if (REGNO (XEXP (x,0)) == REG_X)
+ {
+ 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 "";
+ }
+ }
+ }
+ return AS2 (st%K0, %0,%1);
+}
+
+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]);
+ 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 (reg_base > 0)
+ {
+ if (reg_base == REG_X)
+ {
+ if (reg_dest == 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__));
+ 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));
+ }
+ else
+ {
+ if (reg_unused_after (insn, XEXP (op[0],0)))
+ return *l=2, (AS2 (st,X+,%A1) CR_TAB
+ AS2 (st,X,%B1));
+ else
+ return *l=3, (AS2 (st ,X+,%A1) CR_TAB
+ AS2 (st ,X,%B1) CR_TAB
+ AS2 (sbiw,r26,1));
+ }
+ }
+ else
+ return *l=2, (AS2 (st ,%0,%A1) CR_TAB
+ AS2 (std,%0+1,%B1));
+ }
+ else if (GET_CODE (XEXP (op[0],0)) == PLUS)
+ {
+ int disp = INTVAL(XEXP (XEXP (op[0],0), 1));
+ if (disp > 64 - GET_MODE_SIZE (GET_MODE (op[0])))
+ {
+ 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
+ {
+ 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)));
+ }
+ }
+ return *l=2, (AS2 (std,%A0,%A1) CR_TAB
+ AS2 (std,%B0,%B1));
+ }
+ else if (GET_CODE (XEXP (op[0],0)) == 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++) */
+ return *l=2, (AS2 (st,%0,%A1) CR_TAB
+ AS2 (st,%0,%B1));
+ fatal_insn ("Unknown move insn:",insn);
+ return "";
+}
+
+/* Return 1 if frame pointer for current function required */
+
+int
+frame_pointer_required_p(void)
+{
+ return (current_function_calls_alloca
+ || current_function_args_info.nregs == 0
+ || current_function_varargs
+ || get_frame_size () > 0);
+}
+
+/* Return 1 if the next insn is a JUMP_INSN with condition (GT,LE,GTU,LTU) */
+
+int
+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);
+ }
+ 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 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);
+ }
+ return (cond == EQ || cond == NE);
+}
+
+
+/* Output test instruction for HImode */
+
+char *
+out_tsthi (insn,l)
+ rtx insn;
+ int *l;
+{
+ if (!compare_eq_p (insn))
+ {
+ if (l) *l = 1;
+ return AS1 (tst,%B0);
+ }
+ if (TEST_HARD_REG_CLASS (ADDW_REGS, true_regnum (SET_SRC (PATTERN (insn)))))
+ {
+ if (l) *l = 1;
+ return AS2 (sbiw,%0,0);
+ }
+ if (compare_eq_p (insn) && reg_unused_after (insn, SET_SRC (PATTERN (insn))))
+ {
+ if (l) *l = 1;
+ return AS2 (or,%A0,%B0);
+ }
+ if (l) *l = 2;
+ return (AS2 (cp,%A0,__zero_reg__) CR_TAB
+ AS2 (cpc,%B0,__zero_reg__));
+}
+
+
+/* Output test instruction for SImode */
+
+char *
+out_tstsi (insn,l)
+ rtx insn;
+ int *l;
+{
+ if (!compare_eq_p (insn))
+ {
+ if (l) *l = 1;
+ return AS1 (tst,%D0);
+ }
+ if (TEST_HARD_REG_CLASS (ADDW_REGS, true_regnum (SET_SRC (PATTERN (insn)))))
+ {
+ if (l) *l = 3;
+ return (AS2 (sbiw,%A0,0) CR_TAB
+ AS2 (cpc,%C0,__zero_reg__) CR_TAB
+ AS2 (cpc,%D0,__zero_reg__));
+ }
+ if (l) *l = 4;
+ return (AS2 (cp,%A0,__zero_reg__) CR_TAB
+ AS2 (cpc,%B0,__zero_reg__) CR_TAB
+ AS2 (cpc,%C0,__zero_reg__) CR_TAB
+ AS2 (cpc,%D0,__zero_reg__));
+}
+
+
+/* Generate asm equivalent for various shift's.
+ Shift count are CONST_INT or REG. */
+
+void
+out_shift_with_cnt (template,insn,operands,len)
+ char * template;
+ rtx insn;
+ rtx operands[];
+ int *len;
+{
+ rtx op[10];
+ int l_hi=0;
+ char str[300];
+ 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;
+ else
+ strcat (str, "ldi %3,lo8(%2)");
+ }
+ 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%=)));
+ }
+ else
+ {
+ out_movqi_r_mr (insn, op_mov, &mov_len);
+ *len += mov_len;
+ }
+ }
+ 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];
+ }
+ else
+ {
+ op[3] = tmp_reg_rtx;
+ if (len)
+ ++*len;
+ else
+ strcat (str, CR_TAB "mov %3,%2");
+ }
+ }
+ if (!len)
+ {
+ strcat (str,"\n\t");
+ strcat (str, template);
+ if (l_hi)
+ strcat (str, "\nL_hi%=:");
+ output_asm_insn (str, op);
+ }
+}
+
+
+/* 8bit shift left ((char)x << i) */
+
+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;
+ case 1:
+ *len=1;
+ return AS1 (lsl,%0);
+ case 2:
+ *len=2;
+ return (AS1 (lsl,%0) CR_TAB
+ AS1 (lsl,%0));
+ case 3:
+ *len=3;
+ return (AS1 (lsl,%0) CR_TAB
+ AS1 (lsl,%0) CR_TAB
+ AS1 (lsl,%0));
+ case 4:
+ if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0])))
+ {
+ *len=2;
+ return (AS1 (swap,%0) CR_TAB
+ AS2 (andi,%0,0xf0));
+ }
+ *len=4;
+ return (AS1 (lsl,%0) CR_TAB
+ AS1 (lsl,%0) CR_TAB
+ AS1 (lsl,%0) CR_TAB
+ AS1 (lsl,%0));
+ case 5:
+ if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0])))
+ {
+ *len=3;
+ return (AS1 (swap,%0) CR_TAB
+ AS1 (lsl,%0) CR_TAB
+ AS2 (andi,%0,0xe0));
+ }
+ *len=5;
+ return (AS1 (lsl,%0) CR_TAB
+ AS1 (lsl,%0) CR_TAB
+ AS1 (lsl,%0) CR_TAB
+ AS1 (lsl,%0) CR_TAB
+ AS1 (lsl,%0));
+ case 6:
+ if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0])))
+ {
+ *len=4;
+ return (AS1 (swap,%0) CR_TAB
+ AS1 (lsl,%0) CR_TAB
+ AS1 (lsl,%0) CR_TAB
+ AS2 (andi,%0,0xc0));
+ }
+ *len=6;
+ return (AS1 (lsl,%0) CR_TAB
+ AS1 (lsl,%0) CR_TAB
+ AS1 (lsl,%0) CR_TAB
+ AS1 (lsl,%0) CR_TAB
+ AS1 (lsl,%0) CR_TAB
+ AS1 (lsl,%0));
+ case 7:
+ *len=3;
+ return (AS1 (ror,%0) CR_TAB
+ AS1 (clr,%0) CR_TAB
+ AS1 (ror,%0));
+ }
+ }
+ 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);
+ return "";
+}
+
+
+/* 16bit shift left ((short)x << i) */
+
+char *
+ashlhi3_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;
+ 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 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));
+ }
+ }
+ 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);
+ return "";
+}
+
+
+/* 32bit shift left ((long)x << i) */
+
+char *
+ashlsi3_out (insn,operands,len)
+ rtx insn;
+ rtx operands[];
+ int *len;
+{
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ int k;
+ int *t=len;
+ if (!len)
+ len = &k;
+ switch (INTVAL (operands[2]))
+ {
+ 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;
+ 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);
+ else
+ return (AS1 (clr,%A0) CR_TAB
+ AS2 (mov,%B0,%A1) CR_TAB
+ AS2 (mov,%C0,%B1) CR_TAB
+ AS2 (mov,%D0,%C1));
+ }
+ case 16:
+ {
+ int reg0 = true_regnum (operands[0]);
+ int reg1 = true_regnum (operands[1]);
+ *len=4;
+ if (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));
+ else
+ return (AS2 (mov,%C0,%A1) CR_TAB
+ AS2 (mov,%D0,%B1) CR_TAB
+ AS1 (clr,%B0) CR_TAB
+ AS1 (clr,%A0));
+ }
+ case 24:
+ *len=4;
+ if (true_regnum (operands[0]) + 3 != true_regnum (operands[1]))
+ return (AS2 (mov,%D0,%A1) CR_TAB
+ AS1 (clr,%C0) CR_TAB
+ AS1 (clr,%B0) CR_TAB
+ AS1 (clr,%A0));
+ else
+ return *len = 3, (AS1 (clr,%C0) CR_TAB
+ AS1 (clr,%B0) CR_TAB
+ AS1 (clr,%A0));
+ }
+ }
+ 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);
+ return "";
+}
+
+/* 8bit arithmetic shift right ((signed char)x >> i) */
+
+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;
+ return AS1 (asr,%0);
+ case 2:
+ *len=2;
+ return (AS1 (asr,%0) CR_TAB
+ AS1 (asr,%0));
+ case 3:
+ *len=3;
+ return (AS1 (asr,%0) CR_TAB
+ AS1 (asr,%0) CR_TAB
+ AS1 (asr,%0));
+ case 4:
+ *len=4;
+ return (AS1 (asr,%0) CR_TAB
+ AS1 (asr,%0) CR_TAB
+ AS1 (asr,%0) CR_TAB
+ AS1 (asr,%0));
+ }
+ }
+ 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);
+ return "";
+}
+
+
+/* 16bit arithmetic shift right ((signed short)x >> i) */
+
+char *
+ashrhi3_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;
+ 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 8:
+ if (true_regnum (operands[0]) != true_regnum (operands[1]) + 1)
+ 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));
+ }
+ }
+ 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);
+ return "";
+}
+
+
+/* 32bit arithmetic shift right ((signed long)x >> i) */
+
+char *
+ashrsi3_out (insn,operands,len)
+ rtx insn;
+ rtx operands[];
+ int *len;
+{
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ int k;
+ int *t = len;
+ if (!len)
+ len = &k;
+ switch (INTVAL (operands[2]))
+ {
+ 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]);
+ int reg1 = true_regnum (operands[1]);
+ *len=6;
+ if (reg0 <= reg1)
+ return (AS2 (mov,%A0,%B1) CR_TAB
+ AS2 (mov,%B0,%C1) CR_TAB
+ AS2 (mov,%C0,%D1) CR_TAB
+ AS1 (clr,%D0) CR_TAB
+ AS2 (sbrc,%C0,7) CR_TAB
+ AS1 (dec,%D0));
+ else if (reg0 == reg1 + 1)
+ return *len = 3, (AS1 (clr,%D0) CR_TAB
+ AS2 (sbrc,%C0,7) CR_TAB
+ AS1 (dec,%D0));
+ else
+ return (AS1 (clr,%D0) CR_TAB
+ AS2 (sbrc,%C0,7) CR_TAB
+ AS1 (dec,%D0) CR_TAB
+ AS2 (mov,%C0,%D1) CR_TAB
+ AS2 (mov,%B0,%C1) CR_TAB
+ AS2 (mov,%A0,%B1));
+ }
+ case 16:
+ {
+ int reg0 = true_regnum (operands[0]);
+ int reg1 = true_regnum (operands[1]);
+ *len=6;
+ if (reg0 <= reg1 + 1)
+ return (AS2 (mov,%A0,%C1) CR_TAB
+ AS2 (mov,%B0,%D1) CR_TAB
+ AS1 (clr,%D0) CR_TAB
+ AS2 (sbrc,%B0,7) CR_TAB
+ AS1 (com,%D0) CR_TAB
+ AS2 (mov,%C0,%D0));
+ else if (reg0 == reg1 + 2)
+ return *len = 4, (AS1 (clr,%D0) CR_TAB
+ AS2 (sbrc,%B0,7) CR_TAB
+ AS1 (com,%D0) CR_TAB
+ AS2 (mov,%C0,%D0));
+ else
+ return (AS2 (mov,%B0,%D1) CR_TAB
+ AS2 (mov,%A0,%C1) CR_TAB
+ AS1 (clr,%D0) CR_TAB
+ AS2 (sbrc,%B0,7) CR_TAB
+ AS1 (com,%D0) CR_TAB
+ AS2 (mov,%C0,%D0));
+ }
+ case 24:
+ if (true_regnum (operands[0]) != true_regnum (operands[1]) + 3)
+ return *len = 6, (AS2 (mov,%A0,%D1) CR_TAB
+ AS1 (clr,%D0) CR_TAB
+ AS2 (sbrc,%A0,7) CR_TAB
+ AS1 (com,%D0) CR_TAB
+ AS2 (mov,%B0,%D0) CR_TAB
+ AS2 (mov,%C0,%D0));
+ else
+ return *len = 5, (AS1 (clr,%D0) CR_TAB
+ AS2 (sbrc,%A0,7) CR_TAB
+ AS1 (com,%D0) CR_TAB
+ AS2 (mov,%B0,%D0) CR_TAB
+ AS2 (mov,%C0,%D0));
+ }
+ }
+ 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);
+ return "";
+}
+
+/* 8bit logic shift right ((unsigned char)x >> i) */
+
+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;
+ case 1:
+ *len=1;
+ return AS1 (lsr,%0);
+ case 2:
+ *len=2;
+ return (AS1 (lsr,%0) CR_TAB
+ AS1 (lsr,%0));
+ case 3:
+ *len=3;
+ return (AS1 (lsr,%0) CR_TAB
+ AS1 (lsr,%0) CR_TAB
+ AS1 (lsr,%0));
+ case 4:
+ if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0])))
+ {
+ *len=2;
+ return (AS1 (swap,%0) CR_TAB
+ AS2 (andi,%0,0x0f));
+ }
+ *len=4;
+ return (AS1 (lsr,%0) CR_TAB
+ AS1 (lsr,%0) CR_TAB
+ AS1 (lsr,%0) CR_TAB
+ AS1 (lsr,%0));
+ case 5:
+ if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0])))
+ {
+ *len=3;
+ return (AS1 (swap,%0) CR_TAB
+ AS1 (lsr,%0) CR_TAB
+ AS2 (andi,%0,0x7));
+ }
+ *len=5;
+ return (AS1 (lsr,%0) CR_TAB
+ AS1 (lsr,%0) CR_TAB
+ AS1 (lsr,%0) CR_TAB
+ AS1 (lsr,%0) CR_TAB
+ AS1 (lsr,%0));
+ case 6:
+ if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0])))
+ {
+ *len=4;
+ return (AS1 (swap,%0) CR_TAB
+ AS1 (lsr,%0) CR_TAB
+ AS1 (lsr,%0) CR_TAB
+ AS2 (andi,%0,0x3));
+ }
+ *len=6;
+ return (AS1 (lsr,%0) CR_TAB
+ AS1 (lsr,%0) CR_TAB
+ AS1 (lsr,%0) CR_TAB
+ AS1 (lsr,%0) CR_TAB
+ AS1 (lsr,%0) CR_TAB
+ AS1 (lsr,%0));
+ case 7:
+ *len=3;
+ return (AS1 (rol,%0) CR_TAB
+ AS1 (clr,%0) CR_TAB
+ AS1 (rol,%0));
+ }
+ }
+ 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);
+ return "";
+}
+
+/* 16bit logic shift right ((unsigned short)x >> i) */
+
+char *
+lshrhi3_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;
+ 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 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);
+
+ }
+ }
+ 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);
+ return "";
+}
+
+/* 32bit logic shift right ((unsigned int)x >> i) */
+
+char *
+lshrsi3_out (insn,operands,len)
+ rtx insn;
+ rtx operands[];
+ int *len;
+{
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ int k;
+ int *t=len;
+ if (!len)
+ len = &k;
+ switch (INTVAL (operands[2]))
+ {
+ 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;
+ if (reg0 <= reg1)
+ return (AS2 (mov,%A0,%B1) CR_TAB
+ AS2 (mov,%B0,%C1) CR_TAB
+ AS2 (mov,%C0,%D1) CR_TAB
+ AS1 (clr,%D0));
+ else if (reg0 == reg1 + 1)
+ return *len = 1, AS1 (clr,%D0);
+ else
+ return (AS1 (clr,%D0) CR_TAB
+ AS2 (mov,%C0,%D1) CR_TAB
+ AS2 (mov,%B0,%C1) CR_TAB
+ AS2 (mov,%A0,%B1));
+ }
+ case 16:
+ {
+ int reg0 = true_regnum (operands[0]);
+ int reg1 = true_regnum (operands[1]);
+ *len=4;
+ if (reg0 <= reg1 + 1)
+ return (AS2 (mov,%A0,%C1) CR_TAB
+ AS2 (mov,%B0,%D1) CR_TAB
+ AS1 (clr,%C0) CR_TAB
+ AS1 (clr,%D0));
+ else if (reg0 == reg1 + 2)
+ return *len = 2, (AS1 (clr,%C0) CR_TAB
+ AS1 (clr,%D0));
+ else
+ return (AS2 (mov,%B0,%D1) CR_TAB
+ AS2 (mov,%A0,%C1) CR_TAB
+ AS1 (clr,%C0) CR_TAB
+ AS1 (clr,%D0));
+ }
+ case 24:
+ if (true_regnum (operands[0]) != true_regnum (operands[1]) + 3)
+ return *len = 4, (AS2 (mov,%A0,%D1) CR_TAB
+ AS1 (clr,%B0) CR_TAB
+ AS1 (clr,%C0) CR_TAB
+ AS1 (clr,%D0));
+ else
+ return *len = 3, (AS1 (clr,%B0) CR_TAB
+ AS1 (clr,%C0) CR_TAB
+ AS1 (clr,%D0));
+ }
+ }
+ 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);
+ return "";
+}
+
+/* Modifies the length assigned to instruction INSN
+ LEN is the initially computed length of the insn. */
+
+int
+adjust_insn_length (insn,len)
+ rtx insn;
+ int len;
+{
+ rtx patt = PATTERN (insn);
+ rtx set;
+ if (GET_CODE (patt) == SET)
+ {
+ rtx op[10];
+ op[1] = SET_SRC (patt);
+ op[0] = SET_DEST (patt);
+ if (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;
+ }
+ }
+ else if (op[0] == cc0_rtx && REG_P (op[1]))
+ {
+ switch (GET_MODE (op[1]))
+ {
+ case HImode: out_tsthi (insn,&len); break;
+ case SImode: out_tstsi (insn,&len); break;
+ default: break;
+ }
+ }
+ else if (GET_CODE (op[1]) == AND)
+ {
+ if (GET_CODE (XEXP (op[1],1)) == CONST_INT)
+ {
+ HOST_WIDE_INT mask = INTVAL (XEXP (op[1],1));
+ if (GET_MODE (op[1]) == SImode)
+ len = (((mask & 0xff) != 0xff)
+ + ((mask & 0xff00) != 0xff00)
+ + ((mask & 0xff0000UL) != 0xff0000UL)
+ + ((mask & 0xff000000UL) != 0xff000000UL));
+ else if (GET_MODE (op[1]) == HImode)
+ len = (((mask & 0xff) != 0xff)
+ + ((mask & 0xff00) != 0xff00));
+ }
+ }
+ else if (GET_CODE (op[1]) == IOR)
+ {
+ if (GET_CODE (XEXP (op[1],1)) == CONST_INT)
+ {
+ HOST_WIDE_INT mask = INTVAL (XEXP (op[1],1));
+ if (GET_MODE (op[1]) == SImode)
+ len = (((mask & 0xff) == 0)
+ + ((mask & 0xff00) == 0)
+ + ((mask & 0xff0000UL) == 0)
+ + ((mask & 0xff000000UL) ==0));
+ else if (GET_MODE (op[1]) == HImode)
+ len = (((mask & 0xff) == 0)
+ + ((mask & 0xff00) == 0));
+ }
+ }
+ }
+ set = single_set (insn);
+ if (set)
+ {
+ rtx op[10];
+ op[1] = SET_SRC (set);
+ op[0] = SET_DEST (set);
+ if (GET_CODE (op[1]) == ASHIFT
+ || GET_CODE (op[1]) == ASHIFTRT
+ || GET_CODE (op[1]) == LSHIFTRT)
+ {
+ rtx ops[10];
+ ops[0] = op[0];
+ ops[1] = XEXP (op[1],0);
+ ops[2] = XEXP (op[1],1);
+ switch (GET_CODE (op[1]))
+ {
+ case ASHIFT:
+ switch (GET_MODE (op[0]))
+ {
+ case QImode: ashlqi3_out (insn,ops,&len); break;
+ case HImode: ashlhi3_out (insn,ops,&len); break;
+ case SImode: ashlsi3_out (insn,ops,&len); break;
+ default: break;
+ }
+ break;
+ case ASHIFTRT:
+ switch (GET_MODE (op[0]))
+ {
+ case QImode: ashrqi3_out (insn,ops,&len); break;
+ case HImode: ashrhi3_out (insn,ops,&len); break;
+ case SImode: ashrsi3_out (insn,ops,&len); break;
+ default: break;
+ }
+ break;
+ case LSHIFTRT:
+ switch (GET_MODE (op[0]))
+ {
+ case QImode: lshrqi3_out (insn,ops,&len); break;
+ case HImode: lshrhi3_out (insn,ops,&len); break;
+ case SImode: lshrsi3_out (insn,ops,&len); break;
+ default: break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return len;
+}
+
+/* Return non-zero if register REG dead after INSN */
+
+int
+reg_unused_after (insn, reg)
+ 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
+ */
+
+ || (REG_P(reg) && _reg_unused_after (insn, reg)));
+}
+
+/* Return non-zero if REG is not used after INSN.
+ We assume REG is a reload reg, and therefore does
+ not live past labels. It may live past calls or jumps though. */
+
+int
+_reg_unused_after (insn, reg)
+ rtx insn;
+ rtx reg;
+{
+ enum rtx_code code;
+ rtx set;
+
+ /* If the reg is set by this instruction, then it is safe for our
+ case. Disregard the case where this is a store to memory, since
+ we are checking a register used in the store address. */
+ set = single_set (insn);
+ if (set && GET_CODE (SET_DEST (set)) != MEM
+ && reg_overlap_mentioned_p (reg, SET_DEST (set)))
+ return 1;
+
+ while ((insn = NEXT_INSN (insn)))
+ {
+ code = GET_CODE (insn);
+
+#if 0
+ /* If this is a label that existed before reload, then the register
+ if dead here. However, if this is a label added by reorg, then
+ the register may still be live here. We can't tell the difference,
+ so we just ignore labels completely. */
+ if (code == CODE_LABEL)
+ return 1;
+ /* else */
+#endif
+
+ if (code == JUMP_INSN)
+ return 0;
+
+ /* If this is a sequence, we must handle them all at once.
+ We could have for instance a call that sets the target register,
+ and a insn in a delay slot that uses the register. In this case,
+ we must return 0. */
+ else if (code == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
+ {
+ int i;
+ int retval = 0;
+
+ for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
+ {
+ rtx this_insn = XVECEXP (PATTERN (insn), 0, i);
+ rtx set = single_set (this_insn);
+
+ if (GET_CODE (this_insn) == CALL_INSN)
+ code = CALL_INSN;
+ else if (GET_CODE (this_insn) == JUMP_INSN)
+ {
+ if (INSN_ANNULLED_BRANCH_P (this_insn))
+ return 0;
+ code = JUMP_INSN;
+ }
+
+ if (set && reg_overlap_mentioned_p (reg, SET_SRC (set)))
+ return 0;
+ if (set && reg_overlap_mentioned_p (reg, SET_DEST (set)))
+ {
+ if (GET_CODE (SET_DEST (set)) != MEM)
+ retval = 1;
+ else
+ return 0;
+ }
+ if (set == 0
+ && reg_overlap_mentioned_p (reg, PATTERN (this_insn)))
+ return 0;
+ }
+ if (retval == 1)
+ return 1;
+ else if (code == JUMP_INSN)
+ return 0;
+ }
+
+ if (code == CALL_INSN)
+ {
+ rtx tem;
+ for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
+ if (GET_CODE (XEXP (tem, 0)) == USE
+ && REG_P (XEXP (XEXP (tem, 0), 0))
+ && reg_overlap_mentioned_p (reg, XEXP (XEXP (tem, 0), 0)))
+ return 0;
+ if (call_used_regs[REGNO (reg)])
+ return 1;
+ }
+
+ if (GET_RTX_CLASS (code) == 'i')
+ {
+ rtx set = single_set (insn);
+
+ if (set && reg_overlap_mentioned_p (reg, SET_SRC (set)))
+ return 0;
+ if (set && reg_overlap_mentioned_p (reg, SET_DEST (set)))
+ return GET_CODE (SET_DEST (set)) != MEM;
+ if (set == 0 && reg_overlap_mentioned_p (reg, PATTERN (insn)))
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* 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 */
+
+void
+asm_output_short (file, value)
+ FILE *file;
+ rtx value;
+{
+ if (SYMBOL_REF_FLAG (value) || GET_CODE (value) == LABEL_REF)
+ {
+ fprintf (file, "\t.word pm(");
+ output_addr_const (file, (value));
+ fprintf (file, ")\n");
+ }
+ else
+ {
+ fprintf (file, "\t.word ");
+ output_addr_const (file, (value));
+ fprintf (file, "\n");
+ }
+}
+
+
+/* Output real N to file FILE */
+
+void
+asm_output_float (file, n)
+ FILE *file;
+ REAL_VALUE_TYPE n;
+{
+ long val;
+ char dstr[100];
+
+ 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);
+}
+
+/* Sets section name for declaration DECL */
+
+void
+unique_section (decl, reloc)
+ tree decl;
+ int reloc ATTRIBUTE_UNUSED;
+{
+ int len;
+ char *name,*string;
+ char *prefix;
+ name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+ /* Strip off any encoding in name. */
+ STRIP_NAME_ENCODING (name, name);
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ if (flag_function_sections)
+ prefix = ".text.";
+ else
+ prefix = ".text";
+ }
+ else
+ fatal ("Strange situation: unique section is not a FUNCTION_DECL");
+
+ if (flag_function_sections)
+ {
+ len = strlen (name) + strlen (prefix);
+ string = alloca (len + 1);
+ sprintf (string, "%s%s", prefix, name);
+ DECL_SECTION_NAME (decl) = build_string (len, string);
+ }
+}
+
+
+/* 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)
+ as well as more readable, especially for targets like the i386
+ (where the only alternative is to output character sequences as
+ comma separated lists of numbers). */
+
+void
+gas_output_limited_string(file, str)
+ FILE * file ATTRIBUTE_UNUSED;
+ char * str;
+{
+ unsigned char *_limited_str = (unsigned char *) str;
+ unsigned ch;
+ fprintf (file, "\t%s\t\"", STRING_ASM_OP);
+ for (; (ch = *_limited_str); _limited_str++)
+ {
+ int escape;
+ switch (escape = ESCAPES[ch])
+ {
+ case 0:
+ putc (ch, file);
+ break;
+ case 1:
+ fprintf (file, "\\%03o", ch);
+ break;
+ default:
+ putc ('\\', file);
+ putc (escape, file);
+ break;
+ }
+ }
+ fprintf (file, "\"\n");
+}
+
+/* The routine used to output sequences of byte values. 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)
+ as well as more readable. Note that if we find subparts of the
+ character sequence which end with NUL (and which are shorter than
+ STRING_LIMIT) we output those using ASM_OUTPUT_LIMITED_STRING. */
+
+void
+gas_output_ascii(file, str, length)
+ FILE * file;
+ char * str;
+ size_t length;
+{
+ unsigned char *_ascii_bytes = (unsigned char *) str;
+ unsigned char *limit = _ascii_bytes + length;
+ unsigned bytes_in_chunk = 0;
+ for (; _ascii_bytes < limit; _ascii_bytes++)
+ {
+ register unsigned char *p;
+ if (bytes_in_chunk >= 60)
+ {
+ fprintf (file, "\"\n");
+ bytes_in_chunk = 0;
+ }
+ for (p = _ascii_bytes; p < limit && *p != '\0'; p++)
+ continue;
+ if (p < limit && (p - _ascii_bytes) <= (signed)STRING_LIMIT)
+ {
+ if (bytes_in_chunk > 0)
+ {
+ fprintf (file, "\"\n");
+ bytes_in_chunk = 0;
+ }
+ gas_output_limited_string (file, _ascii_bytes);
+ _ascii_bytes = p;
+ }
+ else
+ {
+ int escape;
+ unsigned ch;
+ if (bytes_in_chunk == 0)
+ fprintf (file, "\t.ascii\t\"");
+ switch (escape = ESCAPES[ch = *_ascii_bytes])
+ {
+ case 0:
+ putc (ch, file);
+ bytes_in_chunk++;
+ break;
+ case 1:
+ fprintf (file, "\\%03o", ch);
+ bytes_in_chunk += 4;
+ break;
+ default:
+ putc ('\\', file);
+ putc (escape, file);
+ bytes_in_chunk += 2;
+ break;
+ }
+ }
+ }
+ if (bytes_in_chunk > 0)
+ fprintf (file, "\"\n");
+}
+
+/* Return value is nonzero if pseudos that have been
+ assigned to registers of class CLASS would likely be spilled
+ because registers of CLASS are needed for spill registers. */
+
+enum reg_class
+class_likely_spilled_p(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:
+ progmem - put data to program memory;
+ signal - make a function to be hardware interrupt. After function
+ epilogue 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. */
+
+int
+valid_machine_decl_attribute (decl, attributes, attr, args)
+ tree decl;
+ tree attributes ATTRIBUTE_UNUSED;
+ tree attr;
+ tree args ATTRIBUTE_UNUSED;
+{
+ if (is_attribute_p ("interrupt", attr)
+ || is_attribute_p ("signal", attr)
+ || is_attribute_p ("naked", attr))
+ return TREE_CODE (decl) == FUNCTION_DECL;
+
+ if (is_attribute_p ("progmem", attr)
+ && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
+ {
+ if (DECL_INITIAL (decl) == NULL_TREE)
+ {
+ warning ("Only initialized variables can be placed into "
+ "program memory area.");
+ return 0;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+
+/* Look for attribute `progmem' in DECL
+ founded - 1 otherwise 0 */
+
+int
+avr_progmem_p (decl)
+ tree decl;
+{
+ tree a;
+
+ if (TREE_CODE (decl) != VAR_DECL)
+ return 0;
+
+ if (NULL_TREE
+ != lookup_attribute ("progmem", DECL_MACHINE_ATTRIBUTES (decl)))
+ return 1;
+
+ a=decl;
+ do
+ a = TREE_TYPE(a);
+ while (TREE_CODE (a) == ARRAY_TYPE);
+
+ if (NULL_TREE != lookup_attribute ("progmem", TYPE_ATTRIBUTES (a)))
+ return 1;
+
+ return 0;
+}
+
+/* Encode section information about tree DECL */
+
+void
+encode_section_info (decl)
+ tree decl;
+{
+ if ((TREE_STATIC (decl) || DECL_EXTERNAL (decl))
+ && TREE_CODE (decl) == VAR_DECL
+ && avr_progmem_p (decl))
+ {
+ char * dsec = ".progmem.data";
+ DECL_SECTION_NAME (decl) = build_string (strlen (dsec), dsec);
+ }
+}
+
+/* Outputs to the stdio stream FILE some
+ appropriate text to go at the start of an assembler file. */
+
+void
+asm_file_start (file)
+ FILE *file;
+{
+ output_file_directive (file, main_input_filename);
+ fprintf (file, "\t.arch %s\n", avr_mcu_type->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__ = r0\n"
+ "__zero_reg__ = r1\n"
+ "_PC_ = 2\n", file);
+
+ commands_in_file = 0;
+ commands_in_prologues = 0;
+ commands_in_epilogues = 0;
+}
+
+/* Outputs to the stdio stream FILE some
+ appropriate text to go at the end of an assembler file. */
+
+void
+asm_file_end (file)
+ FILE *file;
+{
+ fprintf (file,
+ "/* File %s: code %4d (%4d), prologues %3d, epilogues %3d */\n",
+ main_input_filename,
+ commands_in_file,
+ commands_in_file - commands_in_prologues - commands_in_epilogues,
+ commands_in_prologues, commands_in_epilogues);
+}
+
+/* Choose the order in which to allocate hard registers for
+ pseudo-registers local to a basic block.
+
+ Store the desired register order in the array `reg_alloc_order'.
+ Element 0 should be the register to allocate first; element 1, the
+ next register; and so on. */
+
+void
+order_regs_for_local_alloc (void)
+{
+ unsigned int i;
+ int order_0[] = {
+ 24,25,
+ 18,19,
+ 20,21,
+ 22,23,
+ 30,31,
+ 26,27,
+ 28,29,
+ 17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,
+ 0,1,
+ 32,33,34,35
+ };
+ int order_1[] = {
+ 18,19,
+ 20,21,
+ 22,23,
+ 24,25,
+ 30,31,
+ 26,27,
+ 28,29,
+ 17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,
+ 0,1,
+ 32,33,34,35
+ };
+ int order_2[] = {
+ 25,24,
+ 23,22,
+ 21,20,
+ 19,18,
+ 30,31,
+ 26,27,
+ 28,29,
+ 17,16,
+ 15,14,13,12,11,10,9,8,7,6,5,4,3,2,
+ 1,0,
+ 32,33,34,35
+ };
+
+ 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)
+ reg_alloc_order[i] = order[i];
+}
+
+/* Calculate the cost of X code of the expression in which it is contained,
+ found in OUTER_CODE */
+
+int
+default_rtx_costs (X, code, outer_code)
+ rtx X;
+ enum rtx_code code;
+ enum rtx_code outer_code;
+{
+ int cost=0;
+ switch (code)
+ {
+ case SYMBOL_REF:
+ case LABEL_REF:
+ cost = 2 * GET_MODE_SIZE (GET_MODE (X));
+ break;
+ case MEM:
+ if (outer_code != SET)
+ cost = 1;
+ if (GET_CODE (XEXP (X,0)) == SYMBOL_REF)
+ cost += 2 * GET_MODE_SIZE (GET_MODE (X));
+ else
+ cost += GET_MODE_SIZE (GET_MODE (X));
+ break;
+ case CONST_INT:
+ cost = 0;
+ break;
+ case SIGN_EXTEND:
+ if (outer_code == SET)
+ cost = GET_MODE_SIZE (GET_MODE (X));
+ else
+ cost = -GET_MODE_SIZE (GET_MODE (X));
+ break;
+ case ZERO_EXTEND:
+ if (outer_code == SET)
+ cost = GET_MODE_SIZE (GET_MODE (X));
+ else
+ cost = -1;
+ break;
+ case PLUS:
+ case MINUS:
+ if (outer_code == SET)
+ {
+ if (X == stack_pointer_rtx)
+ cost = -10;
+ else if (GET_CODE (XEXP (X,1)) == CONST_INT)
+ cost = (INTVAL (XEXP (X,1)) <= 63 ? 1 :
+ GET_MODE_SIZE (GET_MODE (X)));
+ else
+ cost = GET_MODE_SIZE (GET_MODE (X));
+ }
+ break;
+ case COMPARE:
+ if (GET_CODE (XEXP (X,1)) == CONST_INT)
+ cost = GET_MODE_SIZE (GET_MODE (XEXP (X,0)));
+ break;
+ default:
+ break;
+ }
+ return cost;
+}
+
+/* Calculate the cost of a memory address */
+
+int
+address_cost (rtx x)
+{
+ if (GET_CODE (x) == PLUS
+ && GET_CODE (XEXP (x,1)) == CONST_INT
+ && (REG_P (XEXP (x,0)) || GET_CODE (XEXP (x,0)) == SUBREG)
+ && INTVAL (XEXP (x,1)) >= 61)
+ return 18;
+ if (CONSTANT_ADDRESS_P (x))
+ return 4;
+ return 4;
+}
+
+/* EXTRA_CONSTRAINT helper */
+
+int
+extra_constraint (x,c)
+ rtx x;
+ char c;
+{
+ if (c == 'Q'
+ && GET_CODE (x) == MEM
+ && GET_CODE (XEXP (x,0)) == PLUS)
+ {
+ if (TARGET_ALL_DEBUG)
+ {
+ fprintf (stderr, ("extra_constraint:\n"
+ "reload_completed: %d\n"
+ "reload_in_progress: %d\n"),
+ reload_completed, reload_in_progress);
+ debug_rtx (x);
+ }
+ if (GET_CODE (x) == MEM
+ && GET_CODE (XEXP (x,0)) == PLUS
+ && REG_P (XEXP (XEXP (x,0), 0))
+ && GET_CODE (XEXP (XEXP (x,0), 1)) == CONST_INT
+ && (INTVAL (XEXP (XEXP (x,0), 1))
+ <= (64 - GET_MODE_SIZE (GET_MODE (x)))))
+ {
+ rtx xx = XEXP (XEXP (x,0), 0);
+ int regno = REGNO (xx);
+ if (TARGET_ALL_DEBUG)
+ {
+ fprintf (stderr, ("extra_constraint:\n"
+ "reload_completed: %d\n"
+ "reload_in_progress: %d\n"),
+ reload_completed, reload_in_progress);
+ debug_rtx (x);
+ }
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ return 1; /* allocate pseudos */
+ else if (regno == REG_Z || regno == REG_Y)
+ return 1; /* strictly check */
+ else if (xx == frame_pointer_rtx
+ || xx == arg_pointer_rtx)
+ return 1; /* XXX frame & arg pointer checks */
+ }
+ }
+ return 0;
+}
+
+/* Convert condition code CONDITION to the valid AVR condition code */
+
+RTX_CODE
+avr_normalize_condition (condition)
+ RTX_CODE condition;
+{
+ switch (condition)
+ {
+ case GT:
+ return GE;
+ case GTU:
+ return GEU;
+ case LE:
+ return LT;
+ case LEU:
+ return LTU;
+ default:
+ fatal ("Wrong condition: %s", GET_RTX_NAME (condition));
+ }
+}
+
+/* This fnction optimizes conditional jumps */
+
+void
+machine_dependent_reorg (first_insn)
+ 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)
+ || !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
+ && SET_DEST (pattern) == cc0_rtx
+ && compare_diff_p (insn))
+ {
+ if (GET_CODE (SET_SRC (pattern)) == COMPARE)
+ {
+ /* Now we work under compare insn */
+
+ pattern = SET_SRC (pattern);
+ if (true_regnum (XEXP (pattern,0)) >= 0
+ && true_regnum (XEXP (pattern,1)) >= 0 )
+ {
+ rtx x = XEXP (pattern,0);
+ rtx next = next_real_insn (insn);
+ rtx pat = PATTERN (next);
+ rtx src = SET_SRC (pat);
+ rtx t = XEXP (src,0);
+ PUT_CODE (t, swap_condition (GET_CODE (t)));
+ XEXP (pattern,0) = XEXP (pattern,1);
+ XEXP (pattern,1) = x;
+ INSN_CODE (next) = -1;
+ }
+ else if (true_regnum (XEXP (pattern,0)) >= 0
+ && GET_CODE (XEXP (pattern,1)) == CONST_INT)
+ {
+ rtx x = XEXP (pattern,1);
+ rtx next = next_real_insn (insn);
+ rtx pat = PATTERN (next);
+ rtx src = SET_SRC (pat);
+ rtx t = XEXP (src,0);
+
+ if (avr_simplify_comparision_p (GET_MODE (XEXP (pattern,0)),
+ GET_CODE (t), x))
+ {
+ XEXP (pattern,1) = GEN_INT (INTVAL (x)+1);
+ PUT_CODE (t, avr_normalize_condition (GET_CODE (t)));
+ INSN_CODE (next) = -1;
+ INSN_CODE (insn) = -1;
+ }
+ }
+ }
+ else if (true_regnum (SET_SRC (pattern)) >= 0)
+ {
+ /* This is a tst insn */
+ rtx next = next_real_insn (insn);
+ rtx pat = PATTERN (next);
+ 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;
+ }
+ }
+ }
+ }
+}
+
+/* Returns register number for function return value.*/
+
+int
+avr_ret_register (void)
+{
+ return 24;
+}
+
+/* Ceate an RTX representing the place where a
+ library function returns a value of mode MODE. */
+
+rtx
+avr_libcall_value (mode)
+ enum machine_mode mode;
+{
+ int offs = GET_MODE_SIZE (mode);
+ if (offs < 2)
+ offs = 2;
+ return gen_rtx (REG, mode, RET_REGISTER + 2 - offs);
+}
+
+/* Create an RTX representing the place where a
+ function returns a value of data type VALTYPE. */
+
+rtx
+avr_function_value (type,func)
+ tree type;
+ tree func ATTRIBUTE_UNUSED;
+{
+ int offs;
+ if (TYPE_MODE (type) != BLKmode)
+ return avr_libcall_value (TYPE_MODE (type));
+
+ offs = int_size_in_bytes (type);
+ if (offs < 2)
+ offs = 2;
+ if (offs > 2 && offs < GET_MODE_SIZE (SImode))
+ offs = GET_MODE_SIZE (SImode);
+ else if (offs > GET_MODE_SIZE (SImode) && offs < GET_MODE_SIZE (DImode))
+ offs = GET_MODE_SIZE (DImode);
+
+ return gen_rtx (REG, BLKmode, RET_REGISTER + 2 - offs);
+}
+
+/* Returns non-zero if number MASK have only one setted bit */
+
+int
+mask_one_bit_p (mask)
+ HOST_WIDE_INT mask;
+{
+ int i;
+ unsigned HOST_WIDE_INT n=mask;
+ for (i = 0; i < 32; ++i)
+ {
+ if (n & 0x80000000UL)
+ {
+ if (n & 0x7fffffffUL)
+ return 0;
+ else
+ return 32-i;
+ }
+ n<<=1;
+ }
+ return 0;
+}
+
+
+/* Places additional restrictions on the register class to
+ use when it is necessary to copy value X into a register
+ in class CLASS. */
+
+enum reg_class
+preferred_reload_class(x,class)
+ rtx x;
+ 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;
+}
+
+void
+debug_hard_reg_set (HARD_REG_SET set)
+{
+ int i;
+ for (i=0; i < FIRST_PSEUDO_REGISTER; ++i)
+ {
+ if (TEST_HARD_REG_BIT (set, i))
+ {
+ fprintf (stderr, "r%-2d ", i);
+ }
+ }
+ fprintf (stderr, "\n");
+}
+
diff --git a/gcc/config/avr/avr.h b/gcc/config/avr/avr.h
new file mode 100644
index 00000000000..270ae1f389e
--- /dev/null
+++ b/gcc/config/avr/avr.h
@@ -0,0 +1,3206 @@
+/* Definitions of target machine for GNU compiler,
+ for ATMEL AVR at90s8515, ATmega103/103L, ATmega603/603L microcontrollers.
+
+ Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ Contributed by Denis Chertykov (denisc@overta.ru)
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* Names to predefine in the preprocessor for this target machine. */
+
+#define CPP_PREDEFINES "-DAVR"
+/* Define this to be a string constant containing `-D' options to
+ define the predefined macros that identify this machine and system.
+ These macros will be predefined unless the `-ansi' option is
+ specified.
+
+ In addition, a parallel set of macros are predefined, whose names
+ are made by appending `__' at the beginning and at the end. These
+ `__' macros are permitted by the ANSI standard, so they are
+ predefined regardless of whether `-ansi' is specified.
+
+ For example, on the Sun, one can use the following value:
+
+ "-Dmc68000 -Dsun -Dunix"
+
+ The result is to define the macros `__mc68000__', `__sun__' and
+ `__unix__' unconditionally, and the macros `mc68000', `sun' and
+ `unix' provided `-ansi' is not specified. */
+
+
+/* This declaration should be present. */
+extern int target_flags;
+
+#define TARGET_ORDER_1 (target_flags & 0x1000)
+#define TARGET_ORDER_2 (target_flags & 0x4000)
+#define TARGET_INT8 (target_flags & 0x10000)
+#define TARGET_NO_INTERRUPTS (target_flags & 0x20000)
+#define TARGET_INSN_SIZE_DUMP (target_flags & 0x2000)
+#define TARGET_CALL_PROLOGUES (target_flags & 0x40000)
+
+/* Dump each assembler insn's rtl into the output file.
+ This is for debugging the compiler itself. */
+
+#define TARGET_RTL_DUMP (target_flags & 0x010)
+#define TARGET_ALL_DEBUG (target_flags & 0xfe0)
+
+/* `TARGET_...'
+ This series of macros is to allow compiler command arguments to
+ enable or disable the use of optional features of the target
+ machine. For example, one machine description serves both the
+ 68000 and the 68020; a command argument tells the compiler whether
+ it should use 68020-only instructions or not. This command
+ argument works by means of a macro `TARGET_68020' that tests a bit
+ in `target_flags'.
+
+ Define a macro `TARGET_FEATURENAME' for each such option. Its
+ definition should test a bit in `target_flags'; for example:
+
+ #define TARGET_68020 (target_flags & 1)
+
+ One place where these macros are used is in the
+ condition-expressions of instruction patterns. Note how
+ `TARGET_68020' appears frequently in the 68000 machine description
+ file, `m68k.md'. Another place they are used is in the
+ definitions of the other macros in the `MACHINE.h' file. */
+
+
+
+#define TARGET_SWITCHES { \
+ {"order1",0x1000, NULL}, \
+ {"order2",0x4000, NULL}, \
+ {"int8",0x10000,"Assume int to be 8 bit integer"}, \
+ {"no-interrupts",0x20000,"Don't output interrupt compatible code"}, \
+ {"call-prologues",0x40000, \
+ "Use subroutines for functions prologeu/epilogue"}, \
+ {"rtl",0x10, NULL}, \
+ {"size",0x2000,"Output instruction size's to the asm file"}, \
+ {"deb",0xfe0, NULL}, \
+ {"",0, NULL}}
+/* This macro defines names of command options to set and clear bits
+ in `target_flags'. Its definition is an initializer with a
+ subgrouping for each command option.
+
+ Each subgrouping contains a string constant, that defines the
+ option name, and a number, which contains the bits to set in
+ `target_flags'. A negative number says to clear bits instead; the
+ negative of the number is which bits to clear. The actual option
+ name is made by appending `-m' to the specified name.
+
+ One of the subgroupings should have a null string. The number in
+ this grouping is the default value for `target_flags'. Any target
+ options act starting with that value.
+
+ Here is an example which defines `-m68000' and `-m68020' with
+ opposite meanings, and picks the latter as the default:
+
+ #define TARGET_SWITCHES \
+ { { "68020", 1}, \
+ { "68000", -1}, \
+ { "", 1}} */
+
+extern const char *avr_ram_end;
+extern const char *avr_mcu_name;
+
+struct mcu_type_s {
+ char * name;
+ int stack;
+ int mega;
+ };
+
+extern struct mcu_type_s *avr_mcu_type;
+#define AVR_MEGA (avr_mcu_type->mega)
+
+#define TARGET_OPTIONS { \
+ {"init-stack=",&avr_ram_end,"Specify the initial stack address" }, \
+ {"mcu=", &avr_mcu_name, \
+ "Specify the MCU name (at90s23xx,attiny22,at90s44xx,at90s85xx,atmega603,atmega103)"}}
+/* This macro is similar to `TARGET_SWITCHES' but defines names of
+ command options that have values. Its definition is an
+ initializer with a subgrouping for each command option.
+
+ Each subgrouping contains a string constant, that defines the
+ fixed part of the option name, and the address of a variable. The
+ variable, type `char *', is set to the variable part of the given
+ option if the fixed part matches. The actual option name is made
+ by appending `-m' to the specified name.
+
+ Here is an example which defines `-mshort-data-NUMBER'. If the
+ given option is `-mshort-data-512', the variable `m88k_short_data'
+ will be set to the string `"512"'.
+
+ extern char *m88k_short_data;
+ #define TARGET_OPTIONS \
+ { { "short-data-", &m88k_short_data } } */
+
+#define TARGET_VERSION fprintf (stderr, " (GNU assembler syntax)");
+/* This macro is a C statement to print on `stderr' a string
+ describing the particular machine description choice. Every
+ machine description should define `TARGET_VERSION'. For example:
+
+ #ifdef MOTOROLA
+ #define TARGET_VERSION \
+ fprintf (stderr, " (68k, Motorola syntax)");
+ #else
+ #define TARGET_VERSION \
+ fprintf (stderr, " (68k, MIT syntax)");
+ #endif */
+
+#define OVERRIDE_OPTIONS avr_override_options()
+/* `OVERRIDE_OPTIONS'
+ Sometimes certain combinations of command options do not make
+ sense on a particular target machine. You can define a macro
+ `OVERRIDE_OPTIONS' to take account of this. This macro, if
+ defined, is executed once just after all the command options have
+ been parsed.
+
+ Don't use this macro to turn on various extra optimizations for
+ `-O'. That is what `OPTIMIZATION_OPTIONS' is for. */
+
+#define CAN_DEBUG_WITHOUT_FP
+/* Define this macro if debugging can be performed even without a
+ frame pointer. If this macro is defined, GNU CC will turn on the
+ `-fomit-frame-pointer' option whenever `-O' is specified. */
+
+/* Define this if most significant byte of a word is the lowest numbered. */
+#define BITS_BIG_ENDIAN 0
+
+/* Define this if most significant byte of a word is the lowest numbered. */
+#define BYTES_BIG_ENDIAN 0
+
+/* Define this if most significant word of a multiword number is the lowest
+ numbered. */
+#define WORDS_BIG_ENDIAN 0
+
+/* number of bits in an addressable storage unit */
+#define BITS_PER_UNIT 8
+
+/* Width in bits of a "word", which is the contents of a machine register.
+ Note that this is not necessarily the width of data type `int'; */
+#define BITS_PER_WORD 8
+
+/* Width of a word, in units (bytes). */
+#define UNITS_PER_WORD 1
+
+/* Width in bits of a pointer.
+ See also the macro `Pmode' defined below. */
+#define POINTER_SIZE 16
+
+
+/* Maximum sized of reasonable data type
+ DImode or Dfmode ... */
+#define MAX_FIXED_MODE_SIZE 32
+
+/* Allocation boundary (in *bits*) for storing arguments in argument list. */
+#define PARM_BOUNDARY 8
+
+/* Allocation boundary (in *bits*) for the code of a function. */
+#define FUNCTION_BOUNDARY 8
+
+/* Alignment of field after `int : 0' in a structure. */
+#define EMPTY_FIELD_BOUNDARY 8
+
+/* No data type wants to be aligned rounder than this. */
+#define BIGGEST_ALIGNMENT 8
+
+
+/* Define this if move instructions will actually fail to work
+ when given unaligned data. */
+#define STRICT_ALIGNMENT 0
+
+/* A C expression for the size in bits of the type `int' on the
+ target machine. If you don't define this, the default is one word. */
+#define INT_TYPE_SIZE (TARGET_INT8 ? 8 : 16)
+
+
+/* A C expression for the size in bits of the type `short' on the
+ target machine. If you don't define this, the default is half a
+ word. (If this would be less than one storage unit, it is rounded
+ up to one unit.) */
+#define SHORT_TYPE_SIZE (INT_TYPE_SIZE == 8 ? INT_TYPE_SIZE : 16)
+
+/* A C expression for the size in bits of the type `long' on the
+ target machine. If you don't define this, the default is one word. */
+#define LONG_TYPE_SIZE (INT_TYPE_SIZE == 8 ? 16 : 32)
+
+#define MAX_LONG_TYPE_SIZE 32
+/* Maximum number for the size in bits of the type `long' on the
+ target machine. If this is undefined, the default is
+ `LONG_TYPE_SIZE'. Otherwise, it is the constant value that is the
+ largest value that `LONG_TYPE_SIZE' can have at run-time. This is
+ used in `cpp'. */
+
+
+#define LONG_LONG_TYPE_SIZE 64
+/* A C expression for the size in bits of the type `long long' on the
+ target machine. If you don't define this, the default is two
+ words. If you want to support GNU Ada on your machine, the value
+ of macro must be at least 64. */
+
+
+#define CHAR_TYPE_SIZE 8
+/* A C expression for the size in bits of the type `char' on the
+ target machine. If you don't define this, the default is one
+ quarter of a word. (If this would be less than one storage unit,
+ it is rounded up to one unit.) */
+
+#define FLOAT_TYPE_SIZE 32
+/* A C expression for the size in bits of the type `float' on the
+ target machine. If you don't define this, the default is one word. */
+
+#define DOUBLE_TYPE_SIZE 32
+/* A C expression for the size in bits of the type `double' on the
+ target machine. If you don't define this, the default is two
+ words. */
+
+
+#define LONG_DOUBLE_TYPE_SIZE 32
+/* A C expression for the size in bits of the type `long double' on
+ the target machine. If you don't define this, the default is two
+ words. */
+
+#define DEFAULT_SIGNED_CHAR 1
+/* An expression whose value is 1 or 0, according to whether the type
+ `char' should be signed or unsigned by default. The user can
+ always override this default with the options `-fsigned-char' and
+ `-funsigned-char'. */
+
+/* `DEFAULT_SHORT_ENUMS'
+ A C expression to determine whether to give an `enum' type only as
+ many bytes as it takes to represent the range of possible values
+ of that type. A nonzero value means to do that; a zero value
+ means all `enum' types should be allocated like `int'.
+
+ If you don't define the macro, the default is 0. */
+
+#define SIZE_TYPE (INT_TYPE_SIZE == 8 ? "long unsigned int" : "unsigned int")
+/* A C expression for a string describing the name of the data type
+ to use for size values. The typedef name `size_t' is defined
+ using the contents of the string.
+
+ The string can contain more than one keyword. If so, separate
+ them with spaces, and write first any length keyword, then
+ `unsigned' if appropriate, and finally `int'. The string must
+ exactly match one of the data type names defined in the function
+ `init_decl_processing' in the file `c-decl.c'. You may not omit
+ `int' or change the order--that would cause the compiler to crash
+ on startup.
+
+ If you don't define this macro, the default is `"long unsigned
+ int"'. */
+
+#define PTRDIFF_TYPE (INT_TYPE_SIZE == 8 ? "long unsigned int" :"unsigned int")
+/* A C expression for a string describing the name of the data type
+ to use for the result of subtracting two pointers. The typedef
+ name `ptrdiff_t' is defined using the contents of the string. See
+ `SIZE_TYPE' above for more information.
+
+ If you don't define this macro, the default is `"long int"'. */
+
+
+#define WCHAR_TYPE_SIZE 16
+/* A C expression for the size in bits of the data type for wide
+ characters. This is used in `cpp', which cannot make use of
+ `WCHAR_TYPE'. */
+
+#define FIRST_PSEUDO_REGISTER 36
+/* Number of hardware registers known to the compiler. They receive
+ numbers 0 through `FIRST_PSEUDO_REGISTER-1'; thus, the first
+ pseudo register's number really is assigned the number
+ `FIRST_PSEUDO_REGISTER'. */
+
+#define FIXED_REGISTERS {\
+ 1,1,/* r0 r1 */\
+ 0,0,/* r2 r3 */\
+ 0,0,/* r4 r5 */\
+ 0,0,/* r6 r7 */\
+ 0,0,/* r8 r9 */\
+ 0,0,/* r10 r11 */\
+ 0,0,/* r12 r13 */\
+ 0,0,/* r14 r15 */\
+ 0,0,/* r16 r17 */\
+ 0,0,/* r18 r19 */\
+ 0,0,/* r20 r21 */\
+ 0,0,/* r22 r23 */\
+ 0,0,/* r24 r25 */\
+ 0,0,/* r26 r27 */\
+ 0,0,/* r28 r29 */\
+ 0,0,/* r30 r31 */\
+ 1,1,/* STACK */\
+ 1,1 /* arg pointer */ }
+/* An initializer that says which registers are used for fixed
+ purposes all throughout the compiled code and are therefore not
+ available for general allocation. These would include the stack
+ pointer, the frame pointer (except on machines where that can be
+ used as a general register when no frame pointer is needed), the
+ program counter on machines where that is considered one of the
+ addressable registers, and any other numbered register with a
+ standard use.
+
+ This information is expressed as a sequence of numbers, separated
+ by commas and surrounded by braces. The Nth number is 1 if
+ register N is fixed, 0 otherwise.
+
+ The table initialized from this macro, and the table initialized by
+ the following one, may be overridden at run time either
+ automatically, by the actions of the macro
+ `CONDITIONAL_REGISTER_USAGE', or by the user with the command
+ options `-ffixed-REG', `-fcall-used-REG' and `-fcall-saved-REG'. */
+
+#define CALL_USED_REGISTERS { \
+ 1,1,/* r0 r1 */ \
+ 0,0,/* r2 r3 */ \
+ 0,0,/* r4 r5 */ \
+ 0,0,/* r6 r7 */ \
+ 0,0,/* r8 r9 */ \
+ 0,0,/* r10 r11 */ \
+ 0,0,/* r12 r13 */ \
+ 0,0,/* r14 r15 */ \
+ 0,0,/* r16 r17 */ \
+ 1,1,/* r18 r19 */ \
+ 1,1,/* r20 r21 */ \
+ 1,1,/* r22 r23 */ \
+ 1,1,/* r24 r25 */ \
+ 1,1,/* r26 r27 */ \
+ 0,0,/* r28 r29 */ \
+ 1,1,/* r30 r31 */ \
+ 1,1,/* STACK */ \
+ 1,1 /* arg pointer */ }
+/* Like `FIXED_REGISTERS' but has 1 for each register that is
+ clobbered (in general) by function calls as well as for fixed
+ registers. This macro therefore identifies the registers that are
+ not available for general allocation of values that must live
+ across function calls.
+
+ If a register has 0 in `CALL_USED_REGISTERS', the compiler
+ automatically saves it on function entry and restores it on
+ function exit, if the register is used within the function. */
+
+#define NON_SAVING_SETJMP 0
+/* If this macro is defined and has a nonzero value, it means that
+ `setjmp' and related functions fail to save the registers, or that
+ `longjmp' fails to restore them. To compensate, the compiler
+ avoids putting variables in registers in functions that use
+ `setjmp'. */
+
+#define REG_ALLOC_ORDER { \
+ 24,25, \
+ 18,19, \
+ 20,21, \
+ 22,23, \
+ 30,31, \
+ 26,27, \
+ 28,29, \
+ 17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2, \
+ 0,1, \
+ 32,33,34,35 \
+ }
+/* If defined, an initializer for a vector of integers, containing the
+ numbers of hard registers in the order in which GNU CC should
+ prefer to use them (from most preferred to least).
+
+ If this macro is not defined, registers are used lowest numbered
+ first (all else being equal).
+
+ One use of this macro is on machines where the highest numbered
+ registers must always be saved and the save-multiple-registers
+ instruction supports only sequences of consetionve registers. On
+ such machines, define `REG_ALLOC_ORDER' to be an initializer that
+ lists the highest numbered allocatable register first. */
+
+#define ORDER_REGS_FOR_LOCAL_ALLOC order_regs_for_local_alloc ()
+/* ORDER_REGS_FOR_LOCAL_ALLOC'
+ A C statement (sans semicolon) to choose the order in which to
+ allocate hard registers for pseudo-registers local to a basic
+ block.
+
+ Store the desired register order in the array `reg_alloc_order'.
+ Element 0 should be the register to allocate first; element 1, the
+ next register; and so on.
+
+ The macro body should not assume anything about the contents of
+ `reg_alloc_order' before execution of the macro.
+
+ On most machines, it is not necessary to define this macro. */
+
+
+#define HARD_REGNO_NREGS(REGNO, MODE) ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+
+/* A C expression for the number of consecutive hard registers,
+ starting at register number REGNO, required to hold a value of mode
+ MODE.
+
+ On a machine where all registers are exactly one word, a suitable
+ definition of this macro is
+
+ #define HARD_REGNO_NREGS(REGNO, MODE) \
+ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \
+ / UNITS_PER_WORD)) */
+
+#define HARD_REGNO_MODE_OK(REGNO, MODE) (((REGNO) >= 24 && (MODE) != QImode) \
+ ? ! ((REGNO) & 1) \
+ : 1)
+/* A C expression that is nonzero if it is permissible to store a
+ value of mode MODE in hard register number REGNO (or in several
+ registers starting with that one). For a machine where all
+ registers are equivalent, a suitable definition is
+
+ #define HARD_REGNO_MODE_OK(REGNO, MODE) 1
+
+ It is not necessary for this macro to check for the numbers of
+ fixed registers, because the allocation mechanism considers them
+ to be always occupied.
+
+ On some machines, double-precision values must be kept in even/odd
+ register pairs. The way to implement that is to define this macro
+ to reject odd register numbers for such modes.
+
+ The minimum requirement for a mode to be OK in a register is that
+ the `movMODE' instruction pattern support moves between the
+ register and any other hard register for which the mode is OK; and
+ that moving a value into the register and back out not alter it.
+
+ Since the same instruction used to move `SImode' will work for all
+ narrower integer modes, it is not necessary on any machine for
+ `HARD_REGNO_MODE_OK' to distinguish between these modes, provided
+ you define patterns `movhi', etc., to take advantage of this. This
+ is useful because of the interaction between `HARD_REGNO_MODE_OK'
+ and `MODES_TIEABLE_P'; it is very desirable for all integer modes
+ to be tieable.
+
+ Many machines have special registers for floating point arithmetic.
+ Often people assume that floating point machine modes are allowed
+ only in floating point registers. This is not true. Any
+ registers that can hold integers can safely *hold* a floating
+ point machine mode, whether or not floating arithmetic can be done
+ on it in those registers. Integer move instructions can be used
+ to move the values.
+
+ On some machines, though, the converse is true: fixed-point machine
+ modes may not go in floating registers. This is true if the
+ floating registers normalize any value stored in them, because
+ storing a non-floating value there would garble it. In this case,
+ `HARD_REGNO_MODE_OK' should reject fixed-point machine modes in
+ floating registers. But if the floating registers do not
+ automatically normalize, if you can store any bit pattern in one
+ and retrieve it unchanged without a trap, then any machine mode
+ may go in a floating register, so you can define this macro to say
+ so.
+
+ The primary significance of special floating registers is rather
+ that they are the registers acceptable in floating point arithmetic
+ instructions. However, this is of no concern to
+ `HARD_REGNO_MODE_OK'. You handle it by writing the proper
+ constraints for those instructions.
+
+ On some machines, the floating registers are especially slow to
+ access, so that it is better to store a value in a stack frame
+ than in such a register if floating point arithmetic is not being
+ done. As long as the floating registers are not in class
+ `GENERAL_REGS', they will not be used unless some pattern's
+ constraint asks for one. */
+
+#define MODES_TIEABLE_P(MODE1, MODE2) 0
+/* A C expression that is nonzero if it is desirable to choose
+ register allocation so as to avoid move instructions between a
+ value of mode MODE1 and a value of mode MODE2.
+
+ If `HARD_REGNO_MODE_OK (R, MODE1)' and `HARD_REGNO_MODE_OK (R,
+ MODE2)' are ever different for any R, then `MODES_TIEABLE_P (MODE1,
+ MODE2)' must be zero. */
+
+enum reg_class {
+ NO_REGS,
+ R0_REG, /* r0 */
+ POINTER_X_REGS, /* r26 - r27 */
+ POINTER_Y_REGS, /* r28 - r29 */
+ POINTER_Z_REGS, /* r30 - r31 */
+ STACK_REG, /* STACK */
+ BASE_POINTER_REGS, /* r28 - r31 */
+ POINTER_REGS, /* r26 - r31 */
+ ADDW_REGS, /* r24 - r31 */
+ SIMPLE_LD_REGS, /* r16 - r23 */
+ LD_REGS, /* r16 - r31 */
+ NO_LD_REGS, /* r0 - r15 */
+ GENERAL_REGS, /* r0 - r31 */
+ ALL_REGS, LIM_REG_CLASSES
+};
+/* An enumeral type that must be defined with all the register class
+ names as enumeral values. `NO_REGS' must be first. `ALL_REGS'
+ must be the last register class, followed by one more enumeral
+ value, `LIM_REG_CLASSES', which is not a register class but rather
+ tells how many classes there are.
+
+ Each register class has a number, which is the value of casting
+ the class name to type `int'. The number serves as an index in
+ many of the tables described below. */
+
+
+#define N_REG_CLASSES (int)LIM_REG_CLASSES
+/* The number of distinct register classes, defined as follows:
+
+ #define N_REG_CLASSES (int) LIM_REG_CLASSES */
+
+#define REG_CLASS_NAMES { \
+ "NO_REGS", \
+ "R0_REG", /* r0 */ \
+ "POINTER_X_REGS", /* r26 - r27 */ \
+ "POINTER_Y_REGS", /* r28 - r29 */ \
+ "POINTER_Z_REGS", /* r30 - r31 */ \
+ "STACK_REG", /* STACK */ \
+ "BASE_POINTER_REGS", /* r28 - r31 */ \
+ "POINTER_REGS", /* r26 - r31 */ \
+ "ADDW_REGS", /* r24 - r31 */ \
+ "SIMPLE_LD_REGS", /* r16 - r23 */ \
+ "LD_REGS", /* r16 - r31 */ \
+ "NO_LD_REGS", /* r0 - r15 */ \
+ "GENERAL_REGS", /* r0 - r31 */ \
+ "ALL_REGS" }
+/* An initializer containing the names of the register classes as C
+ string constants. These names are used in writing some of the
+ debugging dumps. */
+
+#define REG_X 26
+#define REG_Y 28
+#define REG_Z 30
+#define REG_W 24
+
+#define REG_CLASS_CONTENTS { \
+ {0x00000000,0x00000000}, /* NO_REGS */ \
+ {0x00000001,0x00000000}, /* R0_REG */ \
+ {3 << REG_X,0x00000000}, /* POINTER_X_REGS, r26 - r27 */ \
+ {3 << REG_Y,0x00000000}, /* POINTER_Y_REGS, r28 - r29 */ \
+ {3 << REG_Z,0x00000000}, /* POINTER_Z_REGS, r30 - r31 */ \
+ {0x00000000,0x00000003}, /* STACK_REG, STACK */ \
+ {(3 << REG_Y) | (3 << REG_Z), \
+ 0x00000000}, /* BASE_POINTER_REGS, r28 - r31 */ \
+ {(3 << REG_X) | (3 << REG_Y) | (3 << REG_Z), \
+ 0x00000000}, /* POINTER_REGS, r26 - r31 */ \
+ {(3 << REG_X) | (3 << REG_Y) | (3 << REG_Z) | (3 << REG_W), \
+ 0x00000000}, /* ADDW_REGS, r24 - r31 */ \
+ {0x00ff0000,0x00000000}, /* SIMPLE_LD_REGS r16 - r23 */ \
+ {(3 << REG_X)|(3 << REG_Y)|(3 << REG_Z)|(3 << REG_W)|(0xff << 16), \
+ 0x00000000}, /* LD_REGS, r16 - r31 */ \
+ {0x0000ffff,0x00000000}, /* NO_LD_REGS r0 - r15 */ \
+ {0xffffffffu,0x00000000}, /* GENERAL_REGS, r0 - r31 */ \
+ {0xffffffffu,0x00000003} /* ALL_REGS */ \
+}
+/* An initializer containing the contents of the register classes, as
+ integers which are bit masks. The Nth integer specifies the
+ contents of class N. The way the integer MASK is interpreted is
+ that register R is in the class if `MASK & (1 << R)' is 1.
+
+ When the machine has more than 32 registers, an integer does not
+ suffice. Then the integers are replaced by sub-initializers,
+ braced groupings containing several integers. Each
+ sub-initializer must be suitable as an initializer for the type
+ `HARD_REG_SET' which is defined in `hard-reg-set.h'. */
+
+#define REGNO_REG_CLASS(R) avr_regno_reg_class(R)
+/* A C expression whose value is a register class containing hard
+ register REGNO. In general there is more than one such class;
+ choose a class which is "minimal", meaning that no smaller class
+ also contains the register. */
+
+#define BASE_REG_CLASS POINTER_REGS
+/* A macro whose definition is the name of the class to which a valid
+ base register must belong. A base register is one used in an
+ address which is the register value plus a displacement. */
+
+#define INDEX_REG_CLASS NO_REGS
+/* A macro whose definition is the name of the class to which a valid
+ index register must belong. An index register is one used in an
+ address where its value is either multiplied by a scale factor or
+ added to another register (as well as added to a displacement). */
+
+#define REG_CLASS_FROM_LETTER(C) avr_reg_class_from_letter(C)
+/* A C expression which defines the machine-dependent operand
+ constraint letters for register classes. If CHAR is such a
+ letter, the value should be the register class corresponding to
+ it. Otherwise, the value should be `NO_REGS'. The register
+ letter `r', corresponding to class `GENERAL_REGS', will not be
+ passed to this macro; you do not need to handle it. */
+
+#define REGNO_OK_FOR_BASE_P(r) (((r) < FIRST_PSEUDO_REGISTER \
+ && ((r) == REG_X \
+ || (r) == REG_Y \
+ || (r) == REG_Z \
+ || (r) == ARG_POINTER_REGNUM)) \
+ || (reg_renumber \
+ && (reg_renumber[r] == REG_X \
+ || reg_renumber[r] == REG_Y \
+ || reg_renumber[r] == REG_Z \
+ || (reg_renumber[r] \
+ == ARG_POINTER_REGNUM))))
+/* A C expression which is nonzero if register number NUM is suitable
+ for use as a base register in operand addresses. It may be either
+ a suitable hard register or a pseudo register that has been
+ allocated such a hard register. */
+
+/* #define REGNO_MODE_OK_FOR_BASE_P(r, m) regno_mode_ok_for_base_p(r, m)
+ A C expression that is just like `REGNO_OK_FOR_BASE_P', except that
+ that expression may examine the mode of the memory reference in
+ MODE. You should define this macro if the mode of the memory
+ reference affects whether a register may be used as a base
+ register. If you define this macro, the compiler will use it
+ instead of `REGNO_OK_FOR_BASE_P'. */
+
+#define REGNO_OK_FOR_INDEX_P(NUM) 0
+/* A C expression which is nonzero if register number NUM is suitable
+ for use as an index register in operand addresses. It may be
+ either a suitable hard register or a pseudo register that has been
+ allocated such a hard register.
+
+ The difference between an index register and a base register is
+ that the index register may be scaled. If an address involves the
+ sum of two registers, neither one of them scaled, then either one
+ may be labeled the "base" and the other the "index"; but whichever
+ labeling is used must fit the machine's constraints of which
+ registers may serve in each capacity. The compiler will try both
+ labelings, looking for one that is valid, and will reload one or
+ both registers only if neither labeling works. */
+
+#define PREFERRED_RELOAD_CLASS(X, CLASS) preferred_reload_class(X,CLASS)
+/* A C expression that places additional restrictions on the register
+ class to use when it is necessary to copy value X into a register
+ in class CLASS. The value is a register class; perhaps CLASS, or
+ perhaps another, smaller class. On many machines, the following
+ definition is safe:
+
+ #define PREFERRED_RELOAD_CLASS(X,CLASS) CLASS
+
+ Sometimes returning a more restrictive class makes better code.
+ For example, on the 68000, when X is an integer constant that is
+ in range for a `moveq' instruction, the value of this macro is
+ always `DATA_REGS' as long as CLASS includes the data registers.
+ Requiring a data register guarantees that a `moveq' will be used.
+
+ If X is a `const_double', by returning `NO_REGS' you can force X
+ into a memory constant. This is useful on certain machines where
+ immediate floating values cannot be loaded into certain kinds of
+ registers. */
+/* `PREFERRED_OUTPUT_RELOAD_CLASS (X, CLASS)'
+ Like `PREFERRED_RELOAD_CLASS', but for output reloads instead of
+ input reloads. If you don't define this macro, the default is to
+ use CLASS, unchanged. */
+
+/* `LIMIT_RELOAD_CLASS (MODE, CLASS)'
+ A C expression that places additional restrictions on the register
+ class to use when it is necessary to be able to hold a value of
+ mode MODE in a reload register for which class CLASS would
+ ordinarily be used.
+
+ Unlike `PREFERRED_RELOAD_CLASS', this macro should be used when
+ there are certain modes that simply can't go in certain reload
+ classes.
+
+ The value is a register class; perhaps CLASS, or perhaps another,
+ smaller class.
+
+ Don't define this macro unless the target machine has limitations
+ which require the macro to do something nontrivial. */
+
+/* SECONDARY_INPUT_RELOAD_CLASS(CLASS, MODE, X)
+ `SECONDARY_RELOAD_CLASS (CLASS, MODE, X)'
+ `SECONDARY_OUTPUT_RELOAD_CLASS (CLASS, MODE, X)'
+ Many machines have some registers that cannot be copied directly
+ to or from memory or even from other types of registers. An
+ example is the `MQ' register, which on most machines, can only be
+ copied to or from general registers, but not memory. Some
+ machines allow copying all registers to and from memory, but
+ require a scratch register for stores to some memory locations
+ (e.g., those with symbolic address on the RT, and those with
+ certain symbolic address on the Sparc when compiling PIC). In
+ some cases, both an intermediate and a scratch register are
+ required.
+
+ You should define these macros to indicate to the reload phase
+ that it may need to allocate at least one register for a reload in
+ addition to the register to contain the data. Specifically, if
+ copying X to a register CLASS in MODE requires an intermediate
+ register, you should define `SECONDARY_INPUT_RELOAD_CLASS' to
+ return the largest register class all of whose registers can be
+ used as intermediate registers or scratch registers.
+
+ If copying a register CLASS in MODE to X requires an intermediate
+ or scratch register, `SECONDARY_OUTPUT_RELOAD_CLASS' should be
+ defined to return the largest register class required. If the
+ requirements for input and output reloads are the same, the macro
+ `SECONDARY_RELOAD_CLASS' should be used instead of defining both
+ macros identically.
+
+ The values returned by these macros are often `GENERAL_REGS'.
+ Return `NO_REGS' if no spare register is needed; i.e., if X can be
+ directly copied to or from a register of CLASS in MODE without
+ requiring a scratch register. Do not define this macro if it
+ would always return `NO_REGS'.
+
+ If a scratch register is required (either with or without an
+ intermediate register), you should define patterns for
+ `reload_inM' or `reload_outM', as required (*note Standard
+ Names::.. These patterns, which will normally be implemented with
+ a `define_expand', should be similar to the `movM' patterns,
+ except that operand 2 is the scratch register.
+
+ Define constraints for the reload register and scratch register
+ that contain a single register class. If the original reload
+ register (whose class is CLASS) can meet the constraint given in
+ the pattern, the value returned by these macros is used for the
+ class of the scratch register. Otherwise, two additional reload
+ registers are required. Their classes are obtained from the
+ constraints in the insn pattern.
+
+ X might be a pseudo-register or a `subreg' of a pseudo-register,
+ which could either be in a hard register or in memory. Use
+ `true_regnum' to find out; it will return -1 if the pseudo is in
+ memory and the hard register number if it is in a register.
+
+ These macros should not be used in the case where a particular
+ class of registers can only be copied to memory and not to another
+ class of registers. In that case, secondary reload registers are
+ not needed and would not be helpful. Instead, a stack location
+ must be used to perform the copy and the `movM' pattern should use
+ memory as a intermediate storage. This case often occurs between
+ floating-point and general registers. */
+
+/* `SECONDARY_MEMORY_NEEDED (CLASS1, CLASS2, M)'
+ Certain machines have the property that some registers cannot be
+ copied to some other registers without using memory. Define this
+ macro on those machines to be a C expression that is non-zero if
+ objects of mode M in registers of CLASS1 can only be copied to
+ registers of class CLASS2 by storing a register of CLASS1 into
+ memory and loading that memory location into a register of CLASS2.
+
+ Do not define this macro if its value would always be zero.
+
+ `SECONDARY_MEMORY_NEEDED_RTX (MODE)'
+ Normally when `SECONDARY_MEMORY_NEEDED' is defined, the compiler
+ allocates a stack slot for a memory location needed for register
+ copies. If this macro is defined, the compiler instead uses the
+ memory location defined by this macro.
+
+ Do not define this macro if you do not define
+ `SECONDARY_MEMORY_NEEDED'. */
+
+#define SMALL_REGISTER_CLASSES 1
+/* Normally the compiler avoids choosing registers that have been
+ explicitly mentioned in the rtl as spill registers (these
+ registers are normally those used to pass parameters and return
+ values). However, some machines have so few registers of certain
+ classes that there would not be enough registers to use as spill
+ registers if this were done.
+
+ Define `SMALL_REGISTER_CLASSES' to be an expression with a non-zero
+ value on these machines. When this macro has a non-zero value, the
+ compiler allows registers explicitly used in the rtl to be used as
+ spill registers but avoids extending the lifetime of these
+ registers.
+
+ It is always safe to define this macro with a non-zero value, but
+ if you unnecessarily define it, you will reduce the amount of
+ optimizations that can be performed in some cases. If you do not
+ define this macro with a non-zero value when it is required, the
+ compiler will run out of spill registers and print a fatal error
+ message. For most machines, you should not define this macro at
+ all. */
+
+#define CLASS_LIKELY_SPILLED_P(c) class_likely_spilled_p(c)
+/* A C expression whose value is nonzero if pseudos that have been
+ assigned to registers of class CLASS would likely be spilled
+ because registers of CLASS are needed for spill registers.
+
+ The default value of this macro returns 1 if CLASS has exactly one
+ register and zero otherwise. On most machines, this default
+ should be used. Only define this macro to some other expression
+ if pseudo allocated by `local-alloc.c' end up in memory because
+ their hard registers were needed for spill registers. If this
+ macro returns nonzero for those classes, those pseudos will only
+ be allocated by `global.c', which knows how to reallocate the
+ pseudo to another register. If there would not be another
+ register available for reallocation, you should not change the
+ definition of this macro since the only effect of such a
+ definition would be to slow down register allocation. */
+
+#define CLASS_MAX_NREGS(CLASS, MODE) class_max_nregs (CLASS, MODE)
+/* A C expression for the maximum number of consecutive registers of
+ class CLASS needed to hold a value of mode MODE.
+
+ This is closely related to the macro `HARD_REGNO_NREGS'. In fact,
+ the value of the macro `CLASS_MAX_NREGS (CLASS, MODE)' should be
+ the maximum value of `HARD_REGNO_NREGS (REGNO, MODE)' for all
+ REGNO values in the class CLASS.
+
+ This macro helps control the handling of multiple-word values in
+ the reload pass. */
+
+#undef CLASS_CANNOT_CHANGE_SIZE
+/* `CLASS_CANNOT_CHANGE_SIZE'
+ If defined, a C expression for a class that contains registers
+ which the compiler must always access in a mode that is the same
+ size as the mode in which it loaded the register.
+
+ For the example, loading 32-bit integer or floating-point objects
+ into floating-point registers on the Alpha extends them to 64-bits.
+ Therefore loading a 64-bit object and then storing it as a 32-bit
+ object does not store the low-order 32-bits, as would be the case
+ for a normal register. Therefore, `alpha.h' defines this macro as
+ `FLOAT_REGS'.
+
+ Three other special macros describe which operands fit which
+ constraint letters. */
+
+#define CONST_OK_FOR_LETTER_P(VALUE, C) \
+ ((C) == 'I' ? (VALUE) >= 0 && (VALUE) <= 63 : \
+ (C) == 'J' ? (VALUE) <= 0 && (VALUE) >= -63: \
+ (C) == 'K' ? (VALUE) == 2 : \
+ (C) == 'L' ? (VALUE) == 0 : \
+ (C) == 'M' ? (VALUE) >= 0 && (VALUE) <= 0xff : \
+ (C) == 'N' ? (VALUE) == -1: \
+ (C) == 'O' ? (VALUE) == 8 || (VALUE) == 16 || (VALUE) == 24: \
+ (C) == 'P' ? (VALUE) == 1 : \
+ 0)
+
+/* A C expression that defines the machine-dependent operand
+ constraint letters (`I', `J', `K', ... `P') that specify
+ particular ranges of integer values. If C is one of those
+ letters, the expression should check that VALUE, an integer, is in
+ the appropriate range and return 1 if so, 0 otherwise. If C is
+ not one of those letters, the value should be 0 regardless of
+ VALUE. */
+
+#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \
+ ((C) == 'G' ? (VALUE) == CONST0_RTX (SFmode) \
+ : 0)
+/* `CONST_DOUBLE_OK_FOR_LETTER_P (VALUE, C)'
+ A C expression that defines the machine-dependent operand
+ constraint letters that specify particular ranges of
+ `const_double' values (`G' or `H').
+
+ If C is one of those letters, the expression should check that
+ VALUE, an RTX of code `const_double', is in the appropriate range
+ and return 1 if so, 0 otherwise. If C is not one of those
+ letters, the value should be 0 regardless of VALUE.
+
+ `const_double' is used for all floating-point constants and for
+ `DImode' fixed-point constants. A given letter can accept either
+ or both kinds of values. It can use `GET_MODE' to distinguish
+ between these kinds. */
+
+#define EXTRA_CONSTRAINT(x, c) extra_constraint(x, c)
+/* A C expression that defines the optional machine-dependent
+ constraint letters (``Q', `R', `S', `T', `U') that can'
+ be used to segregate specific types of operands, usually memory
+ references, for the target machine. Normally this macro will not
+ be defined. If it is required for a particular target machine, it
+ should return 1 if VALUE corresponds to the operand type
+ represented by the constraint letter C. If C is not defined as an
+ extra constraint, the value returned should be 0 regardless of
+ VALUE.
+
+ For example, on the ROMP, load instructions cannot have their
+ output in r0 if the memory reference contains a symbolic address.
+ Constraint letter `Q' is defined as representing a memory address
+ that does *not* contain a symbolic address. An alternative is
+ specified with a `Q' constraint on the input and `r' on the
+ output. The next alternative specifies `m' on the input and a
+ register class that does not include r0 on the output. */
+
+/* This is an undocumented variable which describes
+ how GCC will push a data */
+#define STACK_PUSH_CODE POST_DEC
+
+#define STACK_GROWS_DOWNWARD
+/* Define this macro if pushing a word onto the stack moves the stack
+ pointer to a smaller address.
+
+ When we say, "define this macro if ...," it means that the
+ compiler checks this macro only with `#ifdef' so the precise
+ definition used does not matter. */
+
+#define STARTING_FRAME_OFFSET 1
+/* Offset from the frame pointer to the first local variable slot to
+ be allocated.
+
+ If `FRAME_GROWS_DOWNWARD', find the next slot's offset by
+ subtracting the first slot's length from `STARTING_FRAME_OFFSET'.
+ Otherwise, it is found by adding the length of the first slot to
+ the value `STARTING_FRAME_OFFSET'. */
+
+#define STACK_POINTER_OFFSET 1
+/* Offset from the stack pointer register to the first location at
+ which outgoing arguments are placed. If not specified, the
+ default value of zero is used. This is the proper value for most
+ machines.
+
+ If `ARGS_GROW_DOWNWARD', this is the offset to the location above
+ the first location at which outgoing arguments are placed. */
+
+#define FIRST_PARM_OFFSET(FUNDECL) 0
+/* Offset from the argument pointer register to the first argument's
+ address. On some machines it may depend on the data type of the
+ function.
+
+ If `ARGS_GROW_DOWNWARD', this is the offset to the location above
+ the first argument's address. */
+
+/* `STACK_DYNAMIC_OFFSET (FUNDECL)'
+ Offset from the stack pointer register to an item dynamically
+ allocated on the stack, e.g., by `alloca'.
+
+ The default value for this macro is `STACK_POINTER_OFFSET' plus the
+ length of the outgoing arguments. The default is correct for most
+ machines. See `function.c' for details. */
+
+#define STACK_BOUNDARY 8
+/* Define this macro if there is a guaranteed alignment for the stack
+ pointer on this machine. The definition is a C expression for the
+ desired alignment (measured in bits). This value is used as a
+ default if PREFERRED_STACK_BOUNDARY is not defined. */
+
+#define STACK_POINTER_REGNUM 32
+/* The register number of the stack pointer register, which must also
+ be a fixed register according to `FIXED_REGISTERS'. On most
+ machines, the hardware determines which register this is. */
+
+#define FRAME_POINTER_REGNUM REG_Y
+/* The register number of the frame pointer register, which is used to
+ access automatic variables in the stack frame. On some machines,
+ the hardware determines which register this is. On other
+ machines, you can choose any register you wish for this purpose. */
+
+#define ARG_POINTER_REGNUM 34
+/* The register number of the arg pointer register, which is used to
+ access the function's argument list. On some machines, this is
+ the same as the frame pointer register. On some machines, the
+ hardware determines which register this is. On other machines,
+ you can choose any register you wish for this purpose. If this is
+ not the same register as the frame pointer register, then you must
+ mark it as a fixed register according to `FIXED_REGISTERS', or
+ arrange to be able to eliminate it (*note Elimination::.). */
+
+#define STATIC_CHAIN_REGNUM 2
+/* Register numbers used for passing a function's static chain
+ pointer. If register windows are used, the register number as
+ seen by the called function is `STATIC_CHAIN_INCOMING_REGNUM',
+ while the register number as seen by the calling function is
+ `STATIC_CHAIN_REGNUM'. If these registers are the same,
+ `STATIC_CHAIN_INCOMING_REGNUM' need not be defined.
+
+ The static chain register need not be a fixed register.
+
+ If the static chain is passed in memory, these macros should not be
+ defined; instead, the next two macros should be defined. */
+
+#define FRAME_POINTER_REQUIRED frame_pointer_required_p()
+/* A C expression which is nonzero if a function must have and use a
+ frame pointer. This expression is evaluated in the reload pass.
+ If its value is nonzero the function will have a frame pointer.
+
+ The expression can in principle examine the current function and
+ decide according to the facts, but on most machines the constant 0
+ or the constant 1 suffices. Use 0 when the machine allows code to
+ be generated with no frame pointer, and doing so saves some time
+ or space. Use 1 when there is no possible advantage to avoiding a
+ frame pointer.
+
+ In certain cases, the compiler does not know how to produce valid
+ code without a frame pointer. The compiler recognizes those cases
+ and automatically gives the function a frame pointer regardless of
+ what `FRAME_POINTER_REQUIRED' says. You don't need to worry about
+ them.
+
+ In a function that does not require a frame pointer, the frame
+ pointer register can be allocated for ordinary usage, unless you
+ mark it as a fixed register. See `FIXED_REGISTERS' for more
+ information. */
+
+#define ELIMINABLE_REGS { \
+ {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \
+ {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM} \
+ ,{FRAME_POINTER_REGNUM+1,STACK_POINTER_REGNUM+1}}
+/* If defined, this macro specifies a table of register pairs used to
+ eliminate unneeded registers that point into the stack frame. If
+ it is not defined, the only elimination attempted by the compiler
+ is to replace references to the frame pointer with references to
+ the stack pointer.
+
+ The definition of this macro is a list of structure
+ initializations, each of which specifies an original and
+ replacement register.
+
+ On some machines, the position of the argument pointer is not
+ known until the compilation is completed. In such a case, a
+ separate hard register must be used for the argument pointer.
+ This register can be eliminated by replacing it with either the
+ frame pointer or the argument pointer, depending on whether or not
+ the frame pointer has been eliminated.
+
+ In this case, you might specify:
+ #define ELIMINABLE_REGS \
+ {{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+ {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \
+ {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}}
+
+ Note that the elimination of the argument pointer with the stack
+ pointer is specified first since that is the preferred elimination. */
+
+#define CAN_ELIMINATE(FROM, TO) (((FROM) == ARG_POINTER_REGNUM \
+ && (TO) == FRAME_POINTER_REGNUM) \
+ || (((FROM) == FRAME_POINTER_REGNUM \
+ || (FROM) == FRAME_POINTER_REGNUM+1) \
+ && ! FRAME_POINTER_REQUIRED \
+ ))
+/* A C expression that returns non-zero if the compiler is allowed to
+ try to replace register number FROM-REG with register number
+ TO-REG. This macro need only be defined if `ELIMINABLE_REGS' is
+ defined, and will usually be the constant 1, since most of the
+ cases preventing register elimination are things that the compiler
+ already knows about. */
+
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
+ OFFSET = initial_elimination_offset (FROM, TO)
+/* This macro is similar to `INITIAL_FRAME_POINTER_OFFSET'. It
+ specifies the initial difference between the specified pair of
+ registers. This macro must be defined if `ELIMINABLE_REGS' is
+ defined. */
+
+#define PUSH_ROUNDING(NPUSHED) (NPUSHED)
+/* A C expression that is the number of bytes actually pushed onto the
+ stack when an instruction attempts to push NPUSHED bytes.
+
+ If the target machine does not have a push instruction, do not
+ define this macro. That directs GNU CC to use an alternate
+ strategy: to allocate the entire argument block and then store the
+ arguments into it.
+
+ On some machines, the definition
+
+ #define PUSH_ROUNDING(BYTES) (BYTES)
+
+ will suffice. But on other machines, instructions that appear to
+ push one byte actually push two bytes in an attempt to maintain
+ alignment. Then the definition should be
+
+ #define PUSH_ROUNDING(BYTES) (((BYTES) + 1) & ~1) */
+
+#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, STACK_SIZE) 0
+/* A C expression that should indicate the number of bytes of its own
+ arguments that a function pops on returning, or 0 if the function
+ pops no arguments and the caller must therefore pop them all after
+ the function returns.
+
+ FUNDECL is a C variable whose value is a tree node that describes
+ the function in question. Normally it is a node of type
+ `FUNCTION_DECL' that describes the declaration of the function.
+ From this you can obtain the DECL_MACHINE_ATTRIBUTES of the
+ function.
+
+ FUNTYPE is a C variable whose value is a tree node that describes
+ the function in question. Normally it is a node of type
+ `FUNCTION_TYPE' that describes the data type of the function.
+ From this it is possible to obtain the data types of the value and
+ arguments (if known).
+
+ When a call to a library function is being considered, FUNDECL
+ will contain an identifier node for the library function. Thus, if
+ you need to distinguish among various library functions, you can
+ do so by their names. Note that "library function" in this
+ context means a function used to perform arithmetic, whose name is
+ known specially in the compiler and was not mentioned in the C
+ code being compiled.
+
+ STACK-SIZE is the number of bytes of arguments passed on the
+ stack. If a variable number of bytes is passed, it is zero, and
+ argument popping will always be the responsibility of the calling
+ function.
+
+ On the Vax, all functions always pop their arguments, so the
+ definition of this macro is STACK-SIZE. On the 68000, using the
+ standard calling convention, no functions pop their arguments, so
+ the value of the macro is always 0 in this case. But an
+ alternative calling convention is available in which functions
+ that take a fixed number of arguments pop them but other functions
+ (such as `printf') pop nothing (the caller pops all). When this
+ convention is in use, FUNTYPE is examined to determine whether a
+ function takes a fixed number of arguments. */
+
+#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) (function_arg (&(CUM), MODE, TYPE, NAMED))
+/* A C expression that controls whether a function argument is passed
+ in a register, and which register.
+
+ The arguments are CUM, which summarizes all the previous
+ arguments; MODE, the machine mode of the argument; TYPE, the data
+ type of the argument as a tree node or 0 if that is not known
+ (which happens for C support library functions); and NAMED, which
+ is 1 for an ordinary argument and 0 for nameless arguments that
+ correspond to `...' in the called function's prototype.
+
+ The value of the expression is usually either a `reg' RTX for the
+ hard register in which to pass the argument, or zero to pass the
+ argument on the stack.
+
+ For machines like the Vax and 68000, where normally all arguments
+ are pushed, zero suffices as a definition.
+
+ The value of the expression can also be a `parallel' RTX. This is
+ used when an argument is passed in multiple locations. The mode
+ of the of the `parallel' should be the mode of the entire
+ argument. The `parallel' holds any number of `expr_list' pairs;
+ each one describes where part of the argument is passed. In each
+ `expr_list', the first operand can be either a `reg' RTX for the
+ hard register in which to pass this part of the argument, or zero
+ to pass the argument on the stack. If this operand is a `reg',
+ then the mode indicates how large this part of the argument is.
+ The second operand of the `expr_list' is a `const_int' which gives
+ the offset in bytes into the entire argument where this part
+ starts.
+
+ The usual way to make the ANSI library `stdarg.h' work on a machine
+ where some arguments are usually passed in registers, is to cause
+ nameless arguments to be passed on the stack instead. This is done
+ by making `FUNCTION_ARG' return 0 whenever NAMED is 0.
+
+ You may use the macro `MUST_PASS_IN_STACK (MODE, TYPE)' in the
+ definition of this macro to determine if this argument is of a
+ type that must be passed in the stack. If `REG_PARM_STACK_SPACE'
+ is not defined and `FUNCTION_ARG' returns non-zero for such an
+ argument, the compiler will abort. If `REG_PARM_STACK_SPACE' is
+ defined, the argument will be computed in the stack and then
+ loaded into a register. */
+
+typedef struct avr_args {
+ int nregs; /* # registers available for passing */
+ int regno; /* next available register number */
+} CUMULATIVE_ARGS;
+/* A C type for declaring a variable that is used as the first
+ argument of `FUNCTION_ARG' and other related values. For some
+ target machines, the type `int' suffices and can hold the number
+ of bytes of argument so far.
+
+ There is no need to record in `CUMULATIVE_ARGS' anything about the
+ arguments that have been passed on the stack. The compiler has
+ other variables to keep track of that. For target machines on
+ which all arguments are passed on the stack, there is no need to
+ store anything in `CUMULATIVE_ARGS'; however, the data structure
+ must exist and should not be empty, so use `int'. */
+
+#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT) init_cumulative_args (&(CUM), FNTYPE, LIBNAME, INDIRECT)
+
+/* A C statement (sans semicolon) for initializing the variable CUM
+ for the state at the beginning of the argument list. The variable
+ has type `CUMULATIVE_ARGS'. The value of FNTYPE is the tree node
+ for the data type of the function which will receive the args, or 0
+ if the args are to a compiler support library function. The value
+ of INDIRECT is nonzero when processing an indirect call, for
+ example a call through a function pointer. The value of INDIRECT
+ is zero for a call to an explicitly named function, a library
+ function call, or when `INIT_CUMULATIVE_ARGS' is used to find
+ arguments for the function being compiled.
+
+ When processing a call to a compiler support library function,
+ LIBNAME identifies which one. It is a `symbol_ref' rtx which
+ contains the name of the function, as a string. LIBNAME is 0 when
+ an ordinary C function call is being processed. Thus, each time
+ this macro is called, either LIBNAME or FNTYPE is nonzero, but
+ never both of them at once. */
+
+#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
+ (function_arg_advance (&CUM, MODE, TYPE, NAMED))
+
+/* A C statement (sans semicolon) to update the summarizer variable
+ CUM to advance past an argument in the argument list. The values
+ MODE, TYPE and NAMED describe that argument. Once this is done,
+ the variable CUM is suitable for analyzing the *following*
+ argument with `FUNCTION_ARG', etc.
+
+ This macro need not do anything if the argument in question was
+ passed on the stack. The compiler knows how to track the amount
+ of stack space used for arguments without any special help. */
+
+#define FUNCTION_ARG_REGNO_P(r) function_arg_regno_p(r)
+/* A C expression that is nonzero if REGNO is the number of a hard
+ register in which function arguments are sometimes passed. This
+ does *not* include implicit arguments such as the static chain and
+ the structure-value address. On many machines, no registers can be
+ used for this purpose since all function arguments are pushed on
+ the stack. */
+
+extern int avr_reg_order[];
+
+#define RET_REGISTER avr_ret_register ()
+
+#define FUNCTION_VALUE(VALTYPE, FUNC) avr_function_value (VALTYPE, FUNC)
+/* A C expression to create an RTX representing the place where a
+ function returns a value of data type VALTYPE. VALTYPE is a tree
+ node representing a data type. Write `TYPE_MODE (VALTYPE)' to get
+ the machine mode used to represent that type. On many machines,
+ only the mode is relevant. (Actually, on most machines, scalar
+ values are returned in the same place regardless of mode).
+
+ The value of the expression is usually a `reg' RTX for the hard
+ register where the return value is stored. The value can also be a
+ `parallel' RTX, if the return value is in multiple places. See
+ `FUNCTION_ARG' for an explanation of the `parallel' form.
+
+ If `PROMOTE_FUNCTION_RETURN' is defined, you must apply the same
+ promotion rules specified in `PROMOTE_MODE' if VALTYPE is a scalar
+ type.
+
+ If the precise function being called is known, FUNC is a tree node
+ (`FUNCTION_DECL') for it; otherwise, FUNC is a null pointer. This
+ makes it possible to use a different value-returning convention
+ for specific functions when all their calls are known.
+
+ `FUNCTION_VALUE' is not used for return vales with aggregate data
+ types, because these are returned in another way. See
+ `STRUCT_VALUE_REGNUM' and related macros, below. */
+
+#define LIBCALL_VALUE(MODE) avr_libcall_value (MODE)
+/* A C expression to create an RTX representing the place where a
+ library function returns a value of mode MODE. If the precise
+ function being called is known, FUNC is a tree node
+ (`FUNCTION_DECL') for it; otherwise, FUNC is a null pointer. This
+ makes it possible to use a different value-returning convention
+ for specific functions when all their calls are known.
+
+ Note that "library function" in this context means a compiler
+ support routine, used to perform arithmetic, whose name is known
+ specially by the compiler and was not mentioned in the C code being
+ compiled.
+
+ The definition of `LIBRARY_VALUE' need not be concerned aggregate
+ data types, because none of the library functions returns such
+ types. */
+
+#define FUNCTION_VALUE_REGNO_P(N) ((N) == RET_REGISTER)
+/* A C expression that is nonzero if REGNO is the number of a hard
+ register in which the values of called function may come back.
+
+ A register whose use for returning values is limited to serving as
+ the second of a pair (for a value of type `double', say) need not
+ be recognized by this macro. So for most machines, this definition
+ suffices:
+
+ #define FUNCTION_VALUE_REGNO_P(N) ((N) == 0)
+
+ If the machine has register windows, so that the caller and the
+ called function use different registers for the return value, this
+ macro should recognize only the caller's register numbers. */
+
+#define RETURN_IN_MEMORY(TYPE) ((TYPE_MODE (TYPE) == BLKmode) \
+ ? int_size_in_bytes (TYPE) > 8 \
+ : 0)
+/* A C expression which can inhibit the returning of certain function
+ values in registers, based on the type of value. A nonzero value
+ says to return the function value in memory, just as large
+ structures are always returned. Here TYPE will be a C expression
+ of type `tree', representing the data type of the value.
+
+ Note that values of mode `BLKmode' must be explicitly handled by
+ this macro. Also, the option `-fpcc-struct-return' takes effect
+ regardless of this macro. On most systems, it is possible to
+ leave the macro undefined; this causes a default definition to be
+ used, whose value is the constant 1 for `BLKmode' values, and 0
+ otherwise.
+
+ Do not use this macro to indicate that structures and unions
+ should always be returned in memory. You should instead use
+ `DEFAULT_PCC_STRUCT_RETURN' to indicate this. */
+
+#define DEFAULT_PCC_STRUCT_RETURN 0
+/* Define this macro to be 1 if all structure and union return values
+ must be in memory. Since this results in slower code, this should
+ be defined only if needed for compatibility with other compilers
+ or with an ABI. If you define this macro to be 0, then the
+ conventions used for structure and union return values are decided
+ by the `RETURN_IN_MEMORY' macro.
+
+ If not defined, this defaults to the value 1. */
+
+#define STRUCT_VALUE 0
+/* If the structure value address is not passed in a register, define
+ `STRUCT_VALUE' as an expression returning an RTX for the place
+ where the address is passed. If it returns 0, the address is
+ passed as an "invisible" first argument. */
+
+#define STRUCT_VALUE_INCOMING 0
+/* If the incoming location is not a register, then you should define
+ `STRUCT_VALUE_INCOMING' as an expression for an RTX for where the
+ called function should find the value. If it should find the
+ value on the stack, define this to create a `mem' which refers to
+ the frame pointer. A definition of 0 means that the address is
+ passed as an "invisible" first argument. */
+
+#define FUNCTION_PROLOGUE(FILE, SIZE) function_prologue (FILE, SIZE)
+/* A C compound statement that outputs the assembler code for entry
+ to a function. The prologue is responsible for setting up the
+ stack frame, initializing the frame pointer register, saving
+ registers that must be saved, and allocating SIZE additional bytes
+ of storage for the local variables. SIZE is an integer. FILE is
+ a stdio stream to which the assembler code should be output.
+
+ The label for the beginning of the function need not be output by
+ this macro. That has already been done when the macro is run.
+
+ To determine which registers to save, the macro can refer to the
+ array `regs_ever_live': element R is nonzero if hard register R is
+ used anywhere within the function. This implies the function
+ prologue should save register R, provided it is not one of the
+ call-used registers. (`FUNCTION_EPILOGUE' must likewise use
+ `regs_ever_live'.)
+
+ On machines that have "register windows", the function entry code
+ does not save on the stack the registers that are in the windows,
+ even if they are supposed to be preserved by function calls;
+ instead it takes appropriate steps to "push" the register stack,
+ if any non-call-used registers are used in the function.
+
+ On machines where functions may or may not have frame-pointers, the
+ function entry code must vary accordingly; it must set up the frame
+ pointer if one is wanted, and not otherwise. To determine whether
+ a frame pointer is in wanted, the macro can refer to the variable
+ `frame_pointer_needed'. The variable's value will be 1 at run
+ time in a function that needs a frame pointer. *Note
+ Elimination::.
+
+ The function entry code is responsible for allocating any stack
+ space required for the function. This stack space consists of the
+ regions listed below. In most cases, these regions are allocated
+ in the order listed, with the last listed region closest to the
+ top of the stack (the lowest address if `STACK_GROWS_DOWNWARD' is
+ defined, and the highest address if it is not defined). You can
+ use a different order for a machine if doing so is more convenient
+ or required for compatibility reasons. Except in cases where
+ required by standard or by a debugger, there is no reason why the
+ stack layout used by GCC need agree with that used by other
+ compilers for a machine.
+
+ * A region of `current_function_pretend_args_size' bytes of
+ uninitialized space just underneath the first argument
+ arriving on the stack. (This may not be at the very start of
+ the allocated stack region if the calling sequence has pushed
+ anything else since pushing the stack arguments. But
+ usually, on such machines, nothing else has been pushed yet,
+ because the function prologue itself does all the pushing.)
+ This region is used on machines where an argument may be
+ passed partly in registers and partly in memory, and, in some
+ cases to support the features in `varargs.h' and `stdargs.h'.
+
+ * An area of memory used to save certain registers used by the
+ function. The size of this area, which may also include
+ space for such things as the return address and pointers to
+ previous stack frames, is machine-specific and usually
+ depends on which registers have been used in the function.
+ Machines with register windows often do not require a save
+ area.
+
+ * A region of at least SIZE bytes, possibly rounded up to an
+ allocation boundary, to contain the local variables of the
+ function. On some machines, this region and the save area
+ may occur in the opposite order, with the save area closer to
+ the top of the stack.
+
+ * Optionally, when `ACCUMULATE_OUTGOING_ARGS' is defined, a
+ region of `current_function_outgoing_args_size' bytes to be
+ used for outgoing argument lists of the function. *Note
+ Stack Arguments::.
+
+ Normally, it is necessary for the macros `FUNCTION_PROLOGUE' and
+ `FUNCTION_EPILOGE' to treat leaf functions specially. The C
+ variable `leaf_function' is nonzero for such a function. */
+
+#define EPILOGUE_USES(REGNO) 0
+/* Define this macro as a C expression that is nonzero for registers
+ are used by the epilogue or the `return' pattern. The stack and
+ frame pointer registers are already be assumed to be used as
+ needed. */
+
+#define FUNCTION_EPILOGUE(FILE, SIZE) function_epilogue (FILE, SIZE)
+/* A C compound statement that outputs the assembler code for exit
+ from a function. The epilogue is responsible for restoring the
+ saved registers and stack pointer to their values when the
+ function was called, and returning control to the caller. This
+ macro takes the same arguments as the macro `FUNCTION_PROLOGUE',
+ and the registers to restore are determined from `regs_ever_live'
+ and `CALL_USED_REGISTERS' in the same way.
+
+ On some machines, there is a single instruction that does all the
+ work of returning from the function. On these machines, give that
+ instruction the name `return' and do not define the macro
+ `FUNCTION_EPILOGUE' at all.
+
+ Do not define a pattern named `return' if you want the
+ `FUNCTION_EPILOGUE' to be used. If you want the target switches
+ to control whether return instructions or epilogues are used,
+ define a `return' pattern with a validity condition that tests the
+ target switches appropriately. If the `return' pattern's validity
+ condition is false, epilogues will be used.
+
+ On machines where functions may or may not have frame-pointers, the
+ function exit code must vary accordingly. Sometimes the code for
+ these two cases is completely different. To determine whether a
+ frame pointer is wanted, the macro can refer to the variable
+ `frame_pointer_needed'. The variable's value will be 1 when
+ compiling a function that needs a frame pointer.
+
+ Normally, `FUNCTION_PROLOGUE' and `FUNCTION_EPILOGUE' must treat
+ leaf functions specially. The C variable `leaf_function' is
+ nonzero for such a function. *Note Leaf Functions::.
+
+ On some machines, some functions pop their arguments on exit while
+ others leave that for the caller to do. For example, the 68020
+ when given `-mrtd' pops arguments in functions that take a fixed
+ number of arguments.
+
+ Your definition of the macro `RETURN_POPS_ARGS' decides which
+ functions pop their own arguments. `FUNCTION_EPILOGUE' needs to
+ know what was decided. The variable that is called
+ `current_function_pops_args' is the number of bytes of its
+ arguments that a function should pop. *Note Scalar Return::. */
+
+#define STRICT_ARGUMENT_NAMING 1
+/* Define this macro if the location where a function argument is
+ passed depends on whether or not it is a named argument.
+
+ This macro controls how the NAMED argument to `FUNCTION_ARG' is
+ set for varargs and stdarg functions. With this macro defined,
+ the NAMED argument is always true for named arguments, and false
+ for unnamed arguments. If this is not defined, but
+ `SETUP_INCOMING_VARARGS' is defined, then all arguments are
+ treated as named. Otherwise, all named arguments except the last
+ are treated as named. */
+
+
+#define HAVE_POST_INCREMENT 1
+/* Define this macro if the machine supports post-increment
+ addressing. */
+
+#define HAVE_PRE_DECREMENT 1
+/* #define HAVE_PRE_INCREMENT
+ #define HAVE_POST_DECREMENT */
+/* Similar for other kinds of addressing. */
+
+#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X)
+/* A C expression that is 1 if the RTX X is a constant which is a
+ valid address. On most machines, this can be defined as
+ `CONSTANT_P (X)', but a few machines are more restrictive in which
+ constant addresses are supported.
+
+ `CONSTANT_P' accepts integer-values expressions whose values are
+ not explicitly known, such as `symbol_ref', `label_ref', and
+ `high' expressions and `const' arithmetic expressions, in addition
+ to `const_int' and `const_double' expressions. */
+
+#define MAX_REGS_PER_ADDRESS 1
+/* A number, the maximum number of registers that can appear in a
+ valid memory address. Note that it is up to you to specify a
+ value equal to the maximum number that `GO_IF_LEGITIMATE_ADDRESS'
+ would ever accept. */
+
+#ifdef REG_OK_STRICT
+# define GO_IF_LEGITIMATE_ADDRESS(mode, operand, ADDR) \
+{ \
+ if (legitimate_address_p (mode, operand, 1)) \
+ goto ADDR; \
+}
+# else
+# define GO_IF_LEGITIMATE_ADDRESS(mode, operand, ADDR) \
+{ \
+ if (legitimate_address_p (mode, operand, 0)) \
+ goto ADDR; \
+}
+#endif
+/* A C compound statement with a conditional `goto LABEL;' executed
+ if X (an RTX) is a legitimate memory address on the target machine
+ for a memory operand of mode MODE.
+
+ It usually pays to define several simpler macros to serve as
+ subroutines for this one. Otherwise it may be too complicated to
+ understand.
+
+ This macro must exist in two variants: a strict variant and a
+ non-strict one. The strict variant is used in the reload pass. It
+ must be defined so that any pseudo-register that has not been
+ allocated a hard register is considered a memory reference. In
+ contexts where some kind of register is required, a pseudo-register
+ with no hard register must be rejected.
+
+ The non-strict variant is used in other passes. It must be
+ defined to accept all pseudo-registers in every context where some
+ kind of register is required.
+
+ Compiler source files that want to use the strict variant of this
+ macro define the macro `REG_OK_STRICT'. You should use an `#ifdef
+ REG_OK_STRICT' conditional to define the strict variant in that
+ case and the non-strict variant otherwise.
+
+ Subroutines to check for acceptable registers for various purposes
+ (one for base registers, one for index registers, and so on) are
+ typically among the subroutines used to define
+ `GO_IF_LEGITIMATE_ADDRESS'. Then only these subroutine macros
+ need have two variants; the higher levels of macros may be the
+ same whether strict or not.
+
+ Normally, constant addresses which are the sum of a `symbol_ref'
+ and an integer are stored inside a `const' RTX to mark them as
+ constant. Therefore, there is no need to recognize such sums
+ specifically as legitimate addresses. Normally you would simply
+ recognize any `const' as legitimate.
+
+ Usually `PRINT_OPERAND_ADDRESS' is not prepared to handle constant
+ sums that are not marked with `const'. It assumes that a naked
+ `plus' indicates indexing. If so, then you *must* reject such
+ naked constant sums as illegitimate addresses, so that none of
+ them will be given to `PRINT_OPERAND_ADDRESS'.
+
+ On some machines, whether a symbolic address is legitimate depends
+ on the section that the address refers to. On these machines,
+ define the macro `ENCODE_SECTION_INFO' to store the information
+ into the `symbol_ref', and then check for it here. When you see a
+ `const', you will have to look inside it to find the `symbol_ref'
+ in order to determine the section. *Note Assembler Format::.
+
+ The best way to modify the name string is by adding text to the
+ beginning, with suitable punctuation to prevent any ambiguity.
+ Allocate the new name in `saveable_obstack'. You will have to
+ modify `ASM_OUTPUT_LABELREF' to remove and decode the added text
+ and output the name accordingly, and define `STRIP_NAME_ENCODING'
+ to access the original name string.
+
+ You can check the information stored here into the `symbol_ref' in
+ the definitions of the macros `GO_IF_LEGITIMATE_ADDRESS' and
+ `PRINT_OPERAND_ADDRESS'. */
+
+/* `REG_OK_FOR_BASE_P (X)'
+ A C expression that is nonzero if X (assumed to be a `reg' RTX) is
+ valid for use as a base register. For hard registers, it should
+ always accept those which the hardware permits and reject the
+ others. Whether the macro accepts or rejects pseudo registers
+ must be controlled by `REG_OK_STRICT' as described above. This
+ usually requires two variant definitions, of which `REG_OK_STRICT'
+ controls the one actually used. */
+
+#define REG_OK_FOR_BASE_NOSTRICT_P(X) \
+ (REGNO (X) >= FIRST_PSEUDO_REGISTER || REG_OK_FOR_BASE_STRICT_P(X))
+
+#define REG_OK_FOR_BASE_STRICT_P(X) REGNO_OK_FOR_BASE_P (REGNO (X))
+
+#ifdef REG_OK_STRICT
+# define REG_OK_FOR_BASE_P(X) REG_OK_FOR_BASE_STRICT_P (X)
+#else
+# define REG_OK_FOR_BASE_P(X) REG_OK_FOR_BASE_NOSTRICT_P (X)
+#endif
+
+/* A C expression that is just like `REG_OK_FOR_BASE_P', except that
+ that expression may examine the mode of the memory reference in
+ MODE. You should define this macro if the mode of the memory
+ reference affects whether a register may be used as a base
+ register. If you define this macro, the compiler will use it
+ instead of `REG_OK_FOR_BASE_P'. */
+#define REG_OK_FOR_INDEX_P(X) 0
+/* A C expression that is nonzero if X (assumed to be a `reg' RTX) is
+ valid for use as an index register.
+
+ The difference between an index register and a base register is
+ that the index register may be scaled. If an address involves the
+ sum of two registers, neither one of them scaled, then either one
+ may be labeled the "base" and the other the "index"; but whichever
+ labeling is used must fit the machine's constraints of which
+ registers may serve in each capacity. The compiler will try both
+ labelings, looking for one that is valid, and will reload one or
+ both registers only if neither labeling works. */
+
+#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \
+{ \
+ (X) = legitimize_address (X, OLDX, MODE); \
+ if (memory_address_p (MODE, X)) \
+ goto WIN; \
+}
+/* A C compound statement that attempts to replace X with a valid
+ memory address for an operand of mode MODE. WIN will be a C
+ statement label elsewhere in the code; the macro definition may use
+
+ GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN);
+
+ to avoid further processing if the address has become legitimate.
+
+ X will always be the result of a call to `break_out_memory_refs',
+ and OLDX will be the operand that was given to that function to
+ produce X.
+
+ The code generated by this macro should not alter the substructure
+ of X. If it transforms X into a more legitimate form, it should
+ assign X (which will always be a C variable) a new value.
+
+ It is not necessary for this macro to come up with a legitimate
+ address. The compiler has standard ways of doing so in all cases.
+ In fact, it is safe for this macro to do nothing. But often a
+ machine-dependent strategy can generate better code. */
+
+#define XEXP_(X,Y) (X)
+#define LEGITIMIZE_RELOAD_ADDRESS(X, MODE, OPNUM, TYPE, IND_LEVELS, WIN) \
+do { \
+ if (1&&(GET_CODE (X) == POST_INC || GET_CODE (X) == PRE_DEC)) \
+ { \
+ push_reload (XEXP (X,0), XEXP (X,0), &XEXP (X,0), &XEXP (X,0), \
+ POINTER_REGS, GET_MODE (X),GET_MODE (X) , 0, 0, \
+ OPNUM, RELOAD_OTHER); \
+ goto WIN; \
+ } \
+ if (GET_CODE (X) == PLUS \
+ && REG_P (XEXP (X, 0)) \
+ && GET_CODE (XEXP (X, 1)) == CONST_INT \
+ && INTVAL (XEXP (X, 1)) >= 1) \
+ { \
+ int fit = INTVAL (XEXP (X, 1)) <= (64 - GET_MODE_SIZE (MODE)); \
+ if (fit) \
+ { \
+ if (reg_equiv_address[REGNO (XEXP (X, 0))] != 0) \
+ { \
+ int regno = REGNO (XEXP (X, 0)); \
+ rtx mem = make_memloc (X, regno); \
+ push_reload (XEXP (mem,0), NULL_PTR, &XEXP (mem,0), NULL_PTR, \
+ POINTER_REGS, Pmode, VOIDmode, 0, 0, \
+ 1, ADDR_TYPE (TYPE)); \
+ push_reload (mem, NULL_RTX, &XEXP (X, 0), NULL_PTR, \
+ BASE_POINTER_REGS, GET_MODE (X), VOIDmode, 0, 0, \
+ OPNUM, TYPE); \
+ goto WIN; \
+ } \
+ push_reload (XEXP (X, 0), NULL_RTX, &XEXP (X, 0), NULL_PTR, \
+ BASE_POINTER_REGS, GET_MODE (X), VOIDmode, 0, 0, \
+ OPNUM, TYPE); \
+ goto WIN; \
+ } \
+ else if (! (frame_pointer_needed && XEXP (X,0) == frame_pointer_rtx)) \
+ { \
+ push_reload (X, NULL_RTX, &X, NULL_PTR, \
+ POINTER_REGS, GET_MODE (X), VOIDmode, 0, 0, \
+ OPNUM, TYPE); \
+ goto WIN; \
+ } \
+ } \
+} while(0)
+/* A C compound statement that attempts to replace X, which is an
+ address that needs reloading, with a valid memory address for an
+ operand of mode MODE. WIN will be a C statement label elsewhere
+ in the code. It is not necessary to define this macro, but it
+ might be useful for performance reasons.
+
+ For example, on the i386, it is sometimes possible to use a single
+ reload register instead of two by reloading a sum of two pseudo
+ registers into a register. On the other hand, for number of RISC
+ processors offsets are limited so that often an intermediate
+ address needs to be generated in order to address a stack slot.
+ By defining LEGITIMIZE_RELOAD_ADDRESS appropriately, the
+ intermediate addresses generated for adjacent some stack slots can
+ be made identical, and thus be shared.
+
+ *Note*: This macro should be used with caution. It is necessary
+ to know something of how reload works in order to effectively use
+ this, and it is quite easy to produce macros that build in too
+ much knowledge of reload internals.
+
+ *Note*: This macro must be able to reload an address created by a
+ previous invocation of this macro. If it fails to handle such
+ addresses then the compiler may generate incorrect code or abort.
+
+ The macro definition should use `push_reload' to indicate parts
+ that need reloading; OPNUM, TYPE and IND_LEVELS are usually
+ suitable to be passed unaltered to `push_reload'.
+
+ The code generated by this macro must not alter the substructure of
+ X. If it transforms X into a more legitimate form, it should
+ assign X (which will always be a C variable) a new value. This
+ also applies to parts that you change indirectly by calling
+ `push_reload'.
+
+ The macro definition may use `strict_memory_address_p' to test if
+ the address has become legitimate.
+
+ If you want to change only a part of X, one standard way of doing
+ this is to use `copy_rtx'. Note, however, that is unshares only a
+ single level of rtl. Thus, if the part to be changed is not at the
+ top level, you'll need to replace first the top leve It is not
+ necessary for this macro to come up with a legitimate address;
+ but often a machine-dependent strategy can generate better code. */
+
+#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \
+ if (GET_CODE (ADDR) == POST_INC || GET_CODE (ADDR) == PRE_DEC) \
+ goto LABEL
+/* A C statement or compound statement with a conditional `goto
+ LABEL;' executed if memory address X (an RTX) can have different
+ meanings depending on the machine mode of the memory reference it
+ is used for or if the address is valid for some modes but not
+ others.
+
+ Autoincrement and autodecrement addresses typically have
+ mode-dependent effects because the amount of the increment or
+ decrement is the size of the operand being addressed. Some
+ machines have other mode-dependent addresses. Many RISC machines
+ have no mode-dependent addresses.
+
+ You may assume that ADDR is a valid address for the machine. */
+
+#define LEGITIMATE_CONSTANT_P(X) 1
+/* A C expression that is nonzero if X is a legitimate constant for
+ an immediate operand on the target machine. You can assume that X
+ satisfies `CONSTANT_P', so you need not check this. In fact, `1'
+ is a suitable definition for this macro on machines where anything
+ `CONSTANT_P' is valid. */
+
+#define CONST_COSTS(x,CODE,OUTER_CODE) \
+ case CONST_INT: \
+ if (OUTER_CODE == PLUS \
+ || OUTER_CODE == IOR \
+ || OUTER_CODE == AND \
+ || OUTER_CODE == MINUS \
+ || OUTER_CODE == SET \
+ || INTVAL (x) == 0) \
+ return 2; \
+ if (OUTER_CODE == COMPARE \
+ && INTVAL (x) >= 0 \
+ && INTVAL (x) <= 255) \
+ return 2; \
+ case CONST: \
+ case LABEL_REF: \
+ case SYMBOL_REF: \
+ return 4; \
+ case CONST_DOUBLE: \
+ return 4;
+
+/* A part of a C `switch' statement that describes the relative costs
+ of constant RTL expressions. It must contain `case' labels for
+ expression codes `const_int', `const', `symbol_ref', `label_ref'
+ and `const_double'. Each case must ultimately reach a `return'
+ statement to return the relative cost of the use of that kind of
+ constant value in an expression. The cost may depend on the
+ precise value of the constant, which is available for examination
+ in X, and the rtx code of the expression in which it is contained,
+ found in OUTER_CODE.
+
+ CODE is the expression code--redundant, since it can be obtained
+ with `GET_CODE (X)'. */
+
+#define DEFAULT_RTX_COSTS(x, code, outer_code) \
+{ \
+ int cst = default_rtx_costs (x, code, outer_code); \
+ if (cst>0) \
+ return cst; \
+ else if (cst<0) \
+ total += -cst; \
+ break; \
+}
+
+/* Like `CONST_COSTS' but applies to nonconstant RTL expressions.
+ This can be used, for example, to indicate how costly a multiply
+ instruction is. In writing this macro, you can use the construct
+ `COSTS_N_INSNS (N)' to specify a cost equal to N fast
+ instructions. OUTER_CODE is the code of the expression in which X
+ is contained.
+
+ This macro is optional; do not define it if the default cost
+ assumptions are adequate for the target machine. */
+
+#define ADDRESS_COST(ADDRESS) address_cost (ADDRESS)
+
+/* An expression giving the cost of an addressing mode that contains
+ ADDRESS. If not defined, the cost is computed from the ADDRESS
+ expression and the `CONST_COSTS' values.
+
+ For most CISC machines, the default cost is a good approximation
+ of the true cost of the addressing mode. However, on RISC
+ machines, all instructions normally have the same length and
+ execution time. Hence all addresses will have equal costs.
+
+ In cases where more than one form of an address is known, the form
+ with the lowest cost will be used. If multiple forms have the
+ same, lowest, cost, the one that is the most complex will be used.
+
+ For example, suppose an address that is equal to the sum of a
+ register and a constant is used twice in the same basic block.
+ When this macro is not defined, the address will be computed in a
+ register and memory references will be indirect through that
+ register. On machines where the cost of the addressing mode
+ containing the sum is no higher than that of a simple indirect
+ reference, this will produce an additional instruction and
+ possibly require an additional register. Proper specification of
+ this macro eliminates this overhead for such machines.
+
+ Similar use of this macro is made in strength reduction of loops.
+
+ ADDRESS need not be valid as an address. In such a case, the cost
+ is not relevant and can be any value; invalid addresses need not be
+ assigned a different cost.
+
+ On machines where an address involving more than one register is as
+ cheap as an address computation involving only one register,
+ defining `ADDRESS_COST' to reflect this can cause two registers to
+ be live over a region of code where only one would have been if
+ `ADDRESS_COST' were not defined in that manner. This effect should
+ be considered in the definition of this macro. Equivalent costs
+ should probably only be given to addresses with different numbers
+ of registers on machines with lots of registers.
+
+ This macro will normally either not be defined or be defined as a
+ constant. */
+
+#define REGISTER_MOVE_COST(FROM, TO) ((FROM) == STACK_REG ? 6 : \
+ (TO) == STACK_REG ? 12 \
+ : 2)
+/* A C expression for the cost of moving data from a register in class
+ FROM to one in class TO. The classes are expressed using the
+ enumeration values such as `GENERAL_REGS'. A value of 2 is the
+ default; other values are interpreted relative to that.
+
+ It is not required that the cost always equal 2 when FROM is the
+ same as TO; on some machines it is expensive to move between
+ registers if they are not general registers.
+
+ If reload sees an insn consisting of a single `set' between two
+ hard registers, and if `REGISTER_MOVE_COST' applied to their
+ classes returns a value of 2, reload does not check to ensure that
+ the constraints of the insn are met. Setting a cost of other than
+ 2 will allow reload to verify that the constraints are met. You
+ should do this if the `movM' pattern's constraints do not allow
+ such copying. */
+
+#define MEMORY_MOVE_COST(MODE,CLASS,IN) ((MODE)==QImode ? 2 : \
+ (MODE)==HImode ? 4 : \
+ (MODE)==SImode ? 8 : \
+ (MODE)==SFmode ? 8 : 16)
+/* A C expression for the cost of moving data of mode M between a
+ register and memory. A value of 4 is the default; this cost is
+ relative to those in `REGISTER_MOVE_COST'.
+
+ If moving between registers and memory is more expensive than
+ between two registers, you should define this macro to express the
+ relative cost. */
+
+#define SLOW_BYTE_ACCESS 0
+/* Define this macro as a C expression which is nonzero if accessing
+ less than a word of memory (i.e. a `char' or a `short') is no
+ faster than accessing a word of memory, i.e., if such access
+ require more than one instruction or if there is no difference in
+ cost between byte and (aligned) word loads.
+
+ When this macro is not defined, the compiler will access a field by
+ finding the smallest containing object; when it is defined, a
+ fullword load will be used if alignment permits. Unless bytes
+ accesses are faster than word accesses, using word accesses is
+ preferable since it may eliminate subsequent memory access if
+ subsequent accesses occur to other fields in the same word of the
+ structure, but to different bytes.
+
+ `SLOW_ZERO_EXTEND'
+ Define this macro if zero-extension (of a `char' or `short' to an
+ `int') can be done faster if the destination is a register that is
+ known to be zero.
+
+ If you define this macro, you must have instruction patterns that
+ recognize RTL structures like this:
+
+ (set (strict_low_part (subreg:QI (reg:SI ...) 0)) ...)
+
+ and likewise for `HImode'.
+
+ `SLOW_UNALIGNED_ACCESS'
+ Define this macro to be the value 1 if unaligned accesses have a
+ cost many times greater than aligned accesses, for example if they
+ are emulated in a trap handler.
+
+ When this macro is non-zero, the compiler will act as if
+ `STRICT_ALIGNMENT' were non-zero when generating code for block
+ moves. This can cause significantly more instructions to be
+ produced. Therefore, do not set this macro non-zero if unaligned
+ accesses only add a cycle or two to the time for a memory access.
+
+ If the value of this macro is always zero, it need not be defined.
+
+ `DONT_REDUCE_ADDR'
+ Define this macro to inhibit strength reduction of memory
+ addresses. (On some machines, such strength reduction seems to do
+ harm rather than good.)
+
+ `MOVE_RATIO'
+ The number of scalar move insns which should be generated instead
+ of a string move insn or a library call. Increasing the value
+ will always make code faster, but eventually incurs high cost in
+ increased code size.
+
+ If you don't define this, a reasonable default is used. */
+
+#define NO_FUNCTION_CSE
+/* Define this macro if it is as good or better to call a constant
+ function address than to call an address kept in a register. */
+
+#define NO_RECURSIVE_FUNCTION_CSE
+/* Define this macro if it is as good or better for a function to call
+ itself with an explicit address than to call an address kept in a
+ register.
+
+ `ADJUST_COST (INSN, LINK, DEP_INSN, COST)'
+ A C statement (sans semicolon) to update the integer variable COST
+ based on the relationship between INSN that is dependent on
+ DEP_INSN through the dependence LINK. The default is to make no
+ adjustment to COST. This can be used for example to specify to
+ the scheduler that an output- or anti-dependence does not incur
+ the same cost as a data-dependence.
+
+ `ADJUST_PRIORITY (INSN)'
+ A C statement (sans semicolon) to update the integer scheduling
+ priority `INSN_PRIORITY(INSN)'. Reduce the priority to execute
+ the INSN earlier, increase the priority to execute INSN later.
+ Do not define this macro if you do not need to adjust the
+ scheduling priorities of insns. */
+
+
+#define TEXT_SECTION_ASM_OP ".text"
+/* A C expression whose value is a string containing the assembler
+ operation that should precede instructions and read-only data.
+ Normally `".text"' is right. */
+
+#define DATA_SECTION_ASM_OP ".data"
+/* A C expression whose value is a string containing the assembler
+ operation to identify the following data as writable initialized
+ data. Normally `".data"' is right. */
+
+#define EXTRA_SECTIONS in_progmem
+/* A list of names for sections other than the standard two, which are
+ `in_text' and `in_data'. You need not define this macro on a
+ system with no other sections (that GCC needs to use). */
+
+#define EXTRA_SECTION_FUNCTIONS \
+ \
+void \
+progmem_section (void) \
+{ \
+ if (in_section != in_progmem) \
+ { \
+ fprintf (asm_out_file, ".section .progmem.gcc_sw_table\n"); \
+ in_section = in_progmem; \
+ } \
+}
+/* `EXTRA_SECTION_FUNCTIONS'
+ One or more functions to be defined in `varasm.c'. These
+ functions should do jobs analogous to those of `text_section' and
+ `data_section', for your additional sections. Do not define this
+ macro if you do not define `EXTRA_SECTIONS'. */
+
+#define READONLY_DATA_SECTION data_section
+/* On most machines, read-only variables, constants, and jump tables
+ are placed in the text section. If this is not the case on your
+ machine, this macro should be defined to be the name of a function
+ (either `data_section' or a function defined in `EXTRA_SECTIONS')
+ that switches to the section to be used for read-only items.
+
+ If these items should be placed in the text section, this macro
+ should not be defined. */
+
+/* `SELECT_SECTION (EXP, RELOC)'
+ A C statement or statements to switch to the appropriate section
+ for output of EXP. You can assume that EXP is either a `VAR_DECL'
+ node or a constant of some sort. RELOC indicates whether the
+ initial value of EXP requires link-time relocations. Select the
+ section by calling `text_section' or one of the alternatives for
+ other sections.
+
+ Do not define this macro if you put all read-only variables and
+ constants in the read-only data section (usually the text section). */
+
+/* `SELECT_RTX_SECTION (MODE, RTX)'
+ A C statement or statements to switch to the appropriate section
+ for output of RTX in mode MODE. You can assume that RTX is some
+ kind of constant in RTL. The argument MODE is redundant except in
+ the case of a `const_int' rtx. Select the section by calling
+ `text_section' or one of the alternatives for other sections.
+
+ Do not define this macro if you put all constants in the read-only
+ data section. */
+
+#define JUMP_TABLES_IN_TEXT_SECTION 1
+/* Define this macro if jump tables (for `tablejump' insns) should be
+ output in the text section, along with the assembler instructions.
+ Otherwise, the readonly data section is used.
+
+ This macro is irrelevant if there is no separate readonly data
+ section. */
+
+#define ENCODE_SECTION_INFO(DECL) encode_section_info(DECL)
+/* Define this macro if references to a symbol must be treated
+ differently depending on something about the variable or function
+ named by the symbol (such as what section it is in).
+
+ The macro definition, if any, is executed immediately after the
+ rtl for DECL has been created and stored in `DECL_RTL (DECL)'.
+ The value of the rtl will be a `mem' whose address is a
+ `symbol_ref'.
+
+ The usual thing for this macro to do is to record a flag in the
+ `symbol_ref' (such as `SYMBOL_REF_FLAG') or to store a modified
+ name string in the `symbol_ref' (if one bit is not enough
+ information). */
+
+#define STRIP_NAME_ENCODING(VAR,SYMBOL_NAME) \
+ (VAR) = (SYMBOL_NAME) + ((SYMBOL_NAME)[0] == '*' || (SYMBOL_NAME)[0] == '@');
+/* `STRIP_NAME_ENCODING (VAR, SYM_NAME)'
+ Decode SYM_NAME and store the real name part in VAR, sans the
+ characters that encode section info. Define this macro if
+ `ENCODE_SECTION_INFO' alters the symbol's name string. */
+/* `UNIQUE_SECTION_P (DECL)'
+ A C expression which evaluates to true if DECL should be placed
+ into a unique section for some target-specific reason. If you do
+ not define this macro, the default is `0'. Note that the flag
+ `-ffunction-sections' will also cause functions to be placed into
+ unique sections. */
+
+#define UNIQUE_SECTION(DECL, RELOC) unique_section (DECL, RELOC)
+/* `UNIQUE_SECTION (DECL, RELOC)'
+ A C statement to build up a unique section name, expressed as a
+ STRING_CST node, and assign it to `DECL_SECTION_NAME (DECL)'.
+ RELOC indicates whether the initial value of EXP requires
+ link-time relocations. If you do not define this macro, GNU CC
+ will use the symbol name prefixed by `.' as the section name. */
+
+
+#define ASM_FILE_START(STREAM) asm_file_start (STREAM)
+/* A C expression which outputs to the stdio stream STREAM some
+ appropriate text to go at the start of an assembler file.
+
+ Normally this macro is defined to output a line containing
+ `#NO_APP', which is a comment that has no effect on most
+ assemblers but tells the GNU assembler that it can save time by not
+ checking for certain assembler constructs.
+
+ On systems that use SDB, it is necessary to output certain
+ commands; see `attasm.h'. */
+
+#define ASM_FILE_END(STREAM) asm_file_end (STREAM)
+/* A C expression which outputs to the stdio stream STREAM some
+ appropriate text to go at the end of an assembler file.
+
+ If this macro is not defined, the default is to output nothing
+ special at the end of the file. Most systems don't require any
+ definition.
+
+ On systems that use SDB, it is necessary to output certain
+ commands; see `attasm.h'. */
+
+#define ASM_COMMENT_START " ; "
+/* A C string constant describing how to begin a comment in the target
+ assembler language. The compiler assumes that the comment will
+ end at the end of the line. */
+
+#define ASM_APP_ON "/* #APP */\n"
+/* A C string constant for text to be output before each `asm'
+ statement or group of consecutive ones. Normally this is
+ `"#APP"', which is a comment that has no effect on most assemblers
+ but tells the GNU assembler that it must check the lines that
+ follow for all valid assembler constructs. */
+
+#define ASM_APP_OFF "/* #NOAPP */\n"
+/* A C string constant for text to be output after each `asm'
+ statement or group of consecutive ones. Normally this is
+ `"#NO_APP"', which tells the GNU assembler to resume making the
+ time-saving assumptions that are valid for ordinary compiler
+ output. */
+
+#define ASM_OUTPUT_SOURCE_LINE(STREAM, LINE) fprintf (STREAM,"/* line: %d */\n",LINE)
+/* A C statement to output DBX or SDB debugging information before
+ code for line number LINE of the current source file to the stdio
+ stream STREAM.
+
+ This macro need not be defined if the standard form of debugging
+ information for the debugger in use is appropriate. */
+
+#define ASM_OUTPUT_SECTION_NAME(FILE, DECL, NAME, RELOC) \
+ asm_output_section_name(FILE, DECL, NAME, RELOC)
+
+/* `ASM_OUTPUT_SECTION_NAME (STREAM, DECL, NAME, RELOC)'
+ A C statement to output something to the assembler file to switch
+ to section NAME for object DECL which is either a `FUNCTION_DECL',
+ a `VAR_DECL' or `NULL_TREE'. RELOC indicates whether the initial
+ value of EXP requires link-time relocations. Some target formats
+ do not support arbitrary sections. Do not define this macro in
+ such cases.
+
+ At present this macro is only used to support section attributes.
+ When this macro is undefined, section attributes are disabled. */
+
+#define OBJC_PROLOGUE {}
+/* A C statement to output any assembler statements which are
+ required to precede any Objective C object definitions or message
+ sending. The statement is executed only when compiling an
+ Objective C program. */
+
+
+
+#define ASM_OUTPUT_DOUBLE(STREAM, VALUE) fprintf (STREAM, "no double float %.20e\n", VALUE)
+#define ASM_OUTPUT_FLOAT(STREAM, VALUE) asm_output_float (STREAM, VALUE)
+/* `ASM_OUTPUT_LONG_DOUBLE (STREAM, VALUE)'
+ `ASM_OUTPUT_THREE_QUARTER_FLOAT (STREAM, VALUE)'
+ `ASM_OUTPUT_SHORT_FLOAT (STREAM, VALUE)'
+ `ASM_OUTPUT_BYTE_FLOAT (STREAM, VALUE)'
+ A C statement to output to the stdio stream STREAM an assembler
+ instruction to assemble a floating-point constant of `TFmode',
+ `DFmode', `SFmode', `TQFmode', `HFmode', or `QFmode',
+ respectively, whose value is VALUE. VALUE will be a C expression
+ of type `REAL_VALUE_TYPE'. Macros such as
+ `REAL_VALUE_TO_TARGET_DOUBLE' are useful for writing these
+ definitions. */
+
+
+#define ASM_OUTPUT_INT(FILE, VALUE) \
+ ( fprintf (FILE, "\t.long "), \
+ output_addr_const (FILE, (VALUE)), \
+ fputs ("\n", FILE))
+
+ /* Likewise for `short' and `char' constants. */
+
+#define ASM_OUTPUT_SHORT(FILE,VALUE) asm_output_short(FILE,VALUE)
+#define ASM_OUTPUT_CHAR(FILE,VALUE) asm_output_char(FILE,VALUE)
+
+/* `ASM_OUTPUT_QUADRUPLE_INT (STREAM, EXP)'
+ A C statement to output to the stdio stream STREAM an assembler
+ instruction to assemble an integer of 16, 8, 4, 2 or 1 bytes,
+ respectively, whose value is VALUE. The argument EXP will be an
+ RTL expression which represents a constant value. Use
+ `output_addr_const (STREAM, EXP)' to output this value as an
+ assembler expression.
+
+ For sizes larger than `UNITS_PER_WORD', if the action of a macro
+ would be identical to repeatedly calling the macro corresponding to
+ a size of `UNITS_PER_WORD', once for each word, you need not define
+ the macro. */
+
+
+#define ASM_OUTPUT_BYTE(FILE,VALUE) asm_output_byte (FILE,VALUE)
+/* A C statement to output to the stdio stream STREAM an assembler
+ instruction to assemble a single byte containing the number VALUE. */
+
+#define ASM_BYTE_OP ".byte "
+/* A C string constant giving the pseudo-op to use for a sequence of
+ single-byte constants. If this macro is not defined, the default
+ is `"byte"'. */
+
+#define ASM_OUTPUT_ASCII(FILE, P, SIZE) gas_output_ascii (FILE,P,SIZE)
+/* `ASM_OUTPUT_ASCII (STREAM, PTR, LEN)'
+ output_ascii (FILE, P, SIZE)
+ A C statement to output to the stdio stream STREAM an assembler
+ instruction to assemble a string constant containing the LEN bytes
+ at PTR. PTR will be a C expression of type `char *' and LEN a C
+ expression of type `int'.
+
+ If the assembler has a `.ascii' pseudo-op as found in the Berkeley
+ Unix assembler, do not define the macro `ASM_OUTPUT_ASCII'. */
+
+#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == '\n' \
+ || ((C) == '$'))
+/* Define this macro as a C expression which is nonzero if C is used
+ as a logical line separator by the assembler.
+
+ If you do not define this macro, the default is that only the
+ character `;' is treated as a logical line separator. */
+
+#define ASM_OPEN_PAREN "("
+#define ASM_CLOSE_PAREN ")"
+/* These macros are defined as C string constant, describing the
+ syntax in the assembler for grouping arithmetic expressions. The
+ following definitions are correct for most assemblers:
+
+ #define ASM_OPEN_PAREN "("
+ #define ASM_CLOSE_PAREN ")"
+
+ These macros are provided by `real.h' for writing the definitions of
+ `ASM_OUTPUT_DOUBLE' and the like: */
+
+#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \
+do { \
+ fputs ("\t.comm ", (STREAM)); \
+ assemble_name ((STREAM), (NAME)); \
+ fprintf ((STREAM), ",%d\n", (SIZE)); \
+} while (0)
+/* A C statement (sans semicolon) to output to the stdio stream
+ STREAM the assembler definition of a common-label named NAME whose
+ size is SIZE bytes. The variable ROUNDED is the size rounded up
+ to whatever alignment the caller wants.
+
+ Use the expression `assemble_name (STREAM, NAME)' to output the
+ name itself; before and after that, output the additional
+ assembler syntax for defining the name, and a newline.
+
+ This macro controls how the assembler definitions of uninitialized
+ common global variables are output. */
+
+#define ASM_OUTPUT_LOCAL(STREAM, NAME, SIZE, ROUNDED) \
+do { \
+ fputs ("\t.lcomm ", (STREAM)); \
+ assemble_name ((STREAM), (NAME)); \
+ fprintf ((STREAM), ",%d\n", (SIZE)); \
+} while (0)
+/* A C statement (sans semicolon) to output to the stdio stream
+ STREAM the assembler definition of a local-common-label named NAME
+ whose size is SIZE bytes. The variable ROUNDED is the size
+ rounded up to whatever alignment the caller wants.
+
+ Use the expression `assemble_name (STREAM, NAME)' to output the
+ name itself; before and after that, output the additional
+ assembler syntax for defining the name, and a newline.
+
+ This macro controls how the assembler definitions of uninitialized
+ static variables are output. */
+
+#define ASM_OUTPUT_LABEL(STREAM, NAME) \
+{ \
+ assemble_name (STREAM, NAME); \
+ fprintf (STREAM, ":\n"); \
+}
+/* A C statement (sans semicolon) to output to the stdio stream
+ STREAM the assembler definition of a label named NAME. Use the
+ expression `assemble_name (STREAM, NAME)' to output the name
+ itself; before and after that, output the additional assembler
+ syntax for defining the name, and a newline. */
+
+#undef TYPE_ASM_OP
+#undef SIZE_ASM_OP
+#undef WEAK_ASM_OP
+#define TYPE_ASM_OP ".type"
+#define SIZE_ASM_OP ".size"
+#define WEAK_ASM_OP ".weak"
+/* Define the strings used for the special svr4 .type and .size directives.
+ These strings generally do not vary from one system running svr4 to
+ another, but if a given system (e.g. m88k running svr) needs to use
+ different pseudo-op names for these, they may be overridden in the
+ file which includes this one. */
+
+
+#undef TYPE_OPERAND_FMT
+#define TYPE_OPERAND_FMT "@%s"
+/* The following macro defines the format used to output the second
+ operand of the .type assembler directive. Different svr4 assemblers
+ expect various different forms for this operand. The one given here
+ is just a default. You may need to override it in your machine-
+ specific tm.h file (depending upon the particulars of your assembler). */
+
+
+#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \
+do { \
+ fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ putc (',', FILE); \
+ fprintf (FILE, TYPE_OPERAND_FMT, "function"); \
+ putc ('\n', FILE); \
+ ASM_OUTPUT_LABEL (FILE, NAME); \
+} while (0)
+/* A C statement (sans semicolon) to output to the stdio stream
+ STREAM any text necessary for declaring the name NAME of a
+ function which is being defined. This macro is responsible for
+ outputting the label definition (perhaps using
+ `ASM_OUTPUT_LABEL'). The argument DECL is the `FUNCTION_DECL'
+ tree node representing the function.
+
+ If this macro is not defined, then the function name is defined in
+ the usual manner as a label (by means of `ASM_OUTPUT_LABEL'). */
+
+#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \
+ do { \
+ if (!flag_inhibit_size_directive) \
+ { \
+ char label[256]; \
+ static int labelno; \
+ labelno++; \
+ ASM_GENERATE_INTERNAL_LABEL (label, "Lfe", labelno); \
+ ASM_OUTPUT_INTERNAL_LABEL (FILE, "Lfe", labelno); \
+ fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \
+ assemble_name (FILE, (FNAME)); \
+ fprintf (FILE, ","); \
+ assemble_name (FILE, label); \
+ fprintf (FILE, "-"); \
+ assemble_name (FILE, (FNAME)); \
+ putc ('\n', FILE); \
+ } \
+ } while (0)
+/* A C statement (sans semicolon) to output to the stdio stream
+ STREAM any text necessary for declaring the size of a function
+ which is being defined. The argument NAME is the name of the
+ function. The argument DECL is the `FUNCTION_DECL' tree node
+ representing the function.
+
+ If this macro is not defined, then the function size is not
+ defined. */
+
+#define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) \
+do { \
+ fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ putc (',', FILE); \
+ fprintf (FILE, TYPE_OPERAND_FMT, "object"); \
+ putc ('\n', FILE); \
+ size_directive_output = 0; \
+ if (!flag_inhibit_size_directive && DECL_SIZE (DECL)) \
+ { \
+ size_directive_output = 1; \
+ fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \
+ } \
+ ASM_OUTPUT_LABEL(FILE, NAME); \
+} while (0)
+/* A C statement (sans semicolon) to output to the stdio stream
+ STREAM any text necessary for declaring the name NAME of an
+ initialized variable which is being defined. This macro must
+ output the label definition (perhaps using `ASM_OUTPUT_LABEL').
+ The argument DECL is the `VAR_DECL' tree node representing the
+ variable.
+
+ If this macro is not defined, then the variable name is defined in
+ the usual manner as a label (by means of `ASM_OUTPUT_LABEL'). */
+
+#define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END) \
+do { \
+ char *name = XSTR (XEXP (DECL_RTL (DECL), 0), 0); \
+ if (!flag_inhibit_size_directive && DECL_SIZE (DECL) \
+ && ! AT_END && TOP_LEVEL \
+ && DECL_INITIAL (DECL) == error_mark_node \
+ && !size_directive_output) \
+ { \
+ size_directive_output = 1; \
+ fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \
+ assemble_name (FILE, name); \
+ fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \
+ } \
+ } while (0)
+/* A C statement (sans semicolon) to finish up declaring a variable
+ name once the compiler has processed its initializer fully and
+ thus has had a chance to determine the size of an array when
+ controlled by an initializer. This is used on systems where it's
+ necessary to declare something about the size of the object.
+
+ If you don't define this macro, that is equivalent to defining it
+ to do nothing. */
+
+
+#define ESCAPES \
+"\1\1\1\1\1\1\1\1btn\1fr\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
+\0\0\"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\\\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\
+\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
+\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
+\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
+\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1"
+/* A table of bytes codes used by the ASM_OUTPUT_ASCII and
+ ASM_OUTPUT_LIMITED_STRING macros. Each byte in the table
+ corresponds to a particular byte value [0..255]. For any
+ given byte value, if the value in the corresponding table
+ position is zero, the given character can be output directly.
+ If the table value is 1, the byte must be output as a \ooo
+ octal escape. If the tables value is anything else, then the
+ byte value should be output as a \ followed by the value
+ in the table. Note that we can use standard UN*X escape
+ sequences for many control characters, but we don't use
+ \a to represent BEL because some svr4 assemblers (e.g. on
+ the i386) don't know about that. Also, we don't use \v
+ since some versions of gas, such as 2.2 did not accept it. */
+
+#define STRING_LIMIT ((unsigned) 64)
+#define STRING_ASM_OP ".string"
+/* Some svr4 assemblers have a limit on the number of characters which
+ can appear in the operand of a .string directive. If your assembler
+ has such a limitation, you should define STRING_LIMIT to reflect that
+ limit. Note that at least some svr4 assemblers have a limit on the
+ actual number of bytes in the double-quoted string, and that they
+ count each character in an escape sequence as one byte. Thus, an
+ escape sequence like \377 would count as four bytes.
+
+ If your target assembler doesn't support the .string directive, you
+ should define this to zero. */
+
+#define ASM_GLOBALIZE_LABEL(STREAM, NAME) \
+do { \
+ fprintf (STREAM, ".global\t"); \
+ assemble_name (STREAM, NAME); \
+ fprintf (STREAM, "\n"); \
+} \
+while (0)
+
+/* A C statement (sans semicolon) to output to the stdio stream
+ STREAM some commands that will make the label NAME global; that
+ is, available for reference from other files. Use the expression
+ `assemble_name (STREAM, NAME)' to output the name itself; before
+ and after that, output the additional assembler syntax for making
+ that name global, and a newline. */
+
+/* `ASM_WEAKEN_LABEL'
+ A C statement (sans semicolon) to output to the stdio stream
+ STREAM some commands that will make the label NAME weak; that is,
+ available for reference from other files but only used if no other
+ definition is available. Use the expression `assemble_name
+ (STREAM, NAME)' to output the name itself; before and after that,
+ output the additional assembler syntax for making that name weak,
+ and a newline.
+
+ If you don't define this macro, GNU CC will not support weak
+ symbols and you should not define the `SUPPORTS_WEAK' macro.
+
+ `SUPPORTS_WEAK'
+ A C expression which evaluates to true if the target supports weak
+ symbols.
+
+ If you don't define this macro, `defaults.h' provides a default
+ definition. If `ASM_WEAKEN_LABEL' is defined, the default
+ definition is `1'; otherwise, it is `0'. Define this macro if you
+ want to control weak symbol support with a compiler flag such as
+ `-melf'.
+
+ `MAKE_DECL_ONE_ONLY'
+ A C statement (sans semicolon) to mark DECL to be emitted as a
+ public symbol such that extra copies in multiple translation units
+ will be discarded by the linker. Define this macro if your object
+ file format provides support for this concept, such as the `COMDAT'
+ section flags in the Microsoft Windows PE/COFF format, and this
+ support requires changes to DECL, such as putting it in a separate
+ section.
+
+ `SUPPORTS_WEAK'
+ A C expression which evaluates to true if the target supports
+ one-only semantics.
+
+ If you don't define this macro, `varasm.c' provides a default
+ definition. If `MAKE_DECL_ONE_ONLY' is defined, the default
+ definition is `1'; otherwise, it is `0'. Define this macro if you
+ want to control weak symbol support with a compiler flag, or if
+ setting the `DECL_ONE_ONLY' flag is enough to mark a declaration to
+ be emitted as one-only. */
+
+#define ASM_OUTPUT_INTERNAL_LABEL(STREAM, PREFIX, NUM) \
+fprintf(STREAM, ".%s%d:\n", PREFIX, NUM)
+/* A C statement to output to the stdio stream STREAM a label whose
+ name is made from the string PREFIX and the number NUM.
+
+ It is absolutely essential that these labels be distinct from the
+ labels used for user-level functions and variables. Otherwise,
+ certain programs will have name conflicts with internal labels.
+
+ It is desirable to exclude internal labels from the symbol table
+ of the object file. Most assemblers have a naming convention for
+ labels that should be excluded; on many systems, the letter `L' at
+ the beginning of a label has this effect. You should find out what
+ convention your system uses, and follow it.
+
+ The usual definition of this macro is as follows:
+
+ fprintf (STREAM, "L%s%d:\n", PREFIX, NUM) */
+
+#define ASM_GENERATE_INTERNAL_LABEL(STRING, PREFIX, NUM) \
+sprintf (STRING, "*.%s%d", PREFIX, NUM)
+/* A C statement to store into the string STRING a label whose name
+ is made from the string PREFIX and the number NUM.
+
+ This string, when output subsequently by `assemble_name', should
+ produce the output that `ASM_OUTPUT_INTERNAL_LABEL' would produce
+ with the same PREFIX and NUM.
+
+ If the string begins with `*', then `assemble_name' will output
+ the rest of the string unchanged. It is often convenient for
+ `ASM_GENERATE_INTERNAL_LABEL' to use `*' in this way. If the
+ string doesn't start with `*', then `ASM_OUTPUT_LABELREF' gets to
+ output the string, and may change it. (Of course,
+ `ASM_OUTPUT_LABELREF' is also part of your machine description, so
+ you should know what it does on your machine.) */
+
+#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \
+( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \
+ sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO)))
+
+/* A C expression to assign to OUTVAR (which is a variable of type
+ `char *') a newly allocated string made from the string NAME and
+ the number NUMBER, with some suitable punctuation added. Use
+ `alloca' to get space for the string.
+
+ The string will be used as an argument to `ASM_OUTPUT_LABELREF' to
+ produce an assembler label for an internal static variable whose
+ name is NAME. Therefore, the string must be such as to result in
+ valid assembler code. The argument NUMBER is different each time
+ this macro is executed; it prevents conflicts between
+ similarly-named internal static variables in different scopes.
+
+ Ideally this string should not be a valid C identifier, to prevent
+ any conflict with the user's own symbols. Most assemblers allow
+ periods or percent signs in assembler symbols; putting at least
+ one of these between the name and the number will suffice. */
+
+/* `ASM_OUTPUT_WEAK_ALIAS (STREAM, NAME, VALUE)'
+ A C statement to output to the stdio stream STREAM assembler code
+ which defines (equates) the weak symbol NAME to have the value
+ VALUE.
+
+ Define this macro if the target only supports weak aliases; define
+ ASM_OUTPUT_DEF instead if possible. */
+
+#define HAS_INIT_SECTION 1
+/* If defined, `main' will not call `__main' as described above.
+ This macro should be defined for systems that control the contents
+ of the init section on a symbol-by-symbol basis, such as OSF/1,
+ and should not be defined explicitly for systems that support
+ `INIT_SECTION_ASM_OP'. */
+
+#define REGISTER_NAMES { \
+ "r0","r1","r2","r3","r4","r5","r6","r7", \
+ "r8","r9","r10","r11","r12","r13","r14","r15", \
+ "r16","r17","r18","r19","r20","r21","r22","r23", \
+ "r24","r25","r26","r27","r28","r29","r30","r31", \
+ "__SPL__","__SPH__","argL","argH"}
+/* A C initializer containing the assembler's names for the machine
+ registers, each one as a C string constant. This is what
+ translates register numbers in the compiler into assembler
+ language. */
+
+#define FINAL_PRESCAN_INSN(insn, operand, nop) final_prescan_insn (insn, operand,nop)
+/* If defined, a C statement to be executed just prior to the output
+ of assembler code for INSN, to modify the extracted operands so
+ they will be output differently.
+
+ Here the argument OPVEC is the vector containing the operands
+ extracted from INSN, and NOPERANDS is the number of elements of
+ the vector which contain meaningful data for this insn. The
+ contents of this vector are what will be used to convert the insn
+ template into assembler code, so you can change the assembler
+ output by changing the contents of the vector.
+
+ This macro is useful when various assembler syntaxes share a single
+ file of instruction patterns; by defining this macro differently,
+ you can cause a large class of instructions to be output
+ differently (such as with rearranged operands). Naturally,
+ variations in assembler syntax affecting individual insn patterns
+ ought to be handled by writing conditional output routines in
+ those patterns.
+
+ If this macro is not defined, it is equivalent to a null statement. */
+
+#define PRINT_OPERAND(STREAM, X, CODE) print_operand (STREAM, X, CODE)
+/* A C compound statement to output to stdio stream STREAM the
+ assembler syntax for an instruction operand X. X is an RTL
+ expression.
+
+ CODE is a value that can be used to specify one of several ways of
+ printing the operand. It is used when identical operands must be
+ printed differently depending on the context. CODE comes from the
+ `%' specification that was used to request printing of the
+ operand. If the specification was just `%DIGIT' then CODE is 0;
+ if the specification was `%LTR DIGIT' then CODE is the ASCII code
+ for LTR.
+
+ If X is a register, this macro should print the register's name.
+ The names can be found in an array `reg_names' whose type is `char
+ *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
+
+ When the machine description has a specification `%PUNCT' (a `%'
+ followed by a punctuation character), this macro is called with a
+ null pointer for X and the punctuation character for CODE. */
+
+#define PRINT_OPERAND_PUNCT_VALID_P(CODE) ((CODE) == '~')
+/* A C expression which evaluates to true if CODE is a valid
+ punctuation character for use in the `PRINT_OPERAND' macro. If
+ `PRINT_OPERAND_PUNCT_VALID_P' is not defined, it means that no
+ punctuation characters (except for the standard one, `%') are used
+ in this way. */
+
+#define PRINT_OPERAND_ADDRESS(STREAM, X) print_operand_address(STREAM, X)
+/* A C compound statement to output to stdio stream STREAM the
+ assembler syntax for an instruction operand that is a memory
+ reference whose address is X. X is an RTL expression.
+
+ On some machines, the syntax for a symbolic address depends on the
+ section that the address refers to. On these machines, define the
+ macro `ENCODE_SECTION_INFO' to store the information into the
+ `symbol_ref', and then check for it here. *Note Assembler
+ Format::. */
+
+#define USER_LABEL_PREFIX ""
+/* `LOCAL_LABEL_PREFIX'
+ `REGISTER_PREFIX'
+ `IMMEDIATE_PREFIX'
+ If defined, C string expressions to be used for the `%R', `%L',
+ `%U', and `%I' options of `asm_fprintf' (see `final.c'). These
+ are useful when a single `md' file must support multiple assembler
+ formats. In that case, the various `tm.h' files can define these
+ macros differently. */
+
+#define ASM_OUTPUT_REG_PUSH(STREAM, REGNO) \
+{ \
+ if (REGNO > 31) \
+ fatal("regno error in push"); \
+ fprintf (STREAM, "\tpush\tr%d", REGNO); \
+}
+/* A C expression to output to STREAM some assembler code which will
+ push hard register number REGNO onto the stack. The code need not
+ be optimal, since this macro is used only when profiling. */
+
+#define ASM_OUTPUT_REG_POP(STREAM, REGNO) \
+{ \
+ if (REGNO > 31) \
+ fatal("regno error in pop"); \
+ fprintf (STREAM, "\tpop\tr%d", REGNO); \
+}
+/* A C expression to output to STREAM some assembler code which will
+ pop hard register number REGNO off of the stack. The code need
+ not be optimal, since this macro is used only when profiling. */
+
+#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM, VALUE) \
+ fprintf (STREAM, "\t.word pm(.L%d)\n", VALUE);
+/* This macro should be provided on machines where the addresses in a
+ dispatch table are absolute.
+
+ The definition should be a C statement to output to the stdio
+ stream STREAM an assembler pseudo-instruction to generate a
+ reference to a label. VALUE is the number of an internal label
+ whose definition is output using `ASM_OUTPUT_INTERNAL_LABEL'. For
+ example,
+
+ fprintf (STREAM, "\t.word L%d\n", VALUE) */
+
+#define ASM_OUTPUT_CASE_LABEL(STREAM, PREFIX, NUM, TABLE) \
+ progmem_section (), ASM_OUTPUT_INTERNAL_LABEL (STREAM, PREFIX, NUM)
+
+/* `ASM_OUTPUT_CASE_LABEL (STREAM, PREFIX, NUM, TABLE)'
+ Define this if the label before a jump-table needs to be output
+ specially. The first three arguments are the same as for
+ `ASM_OUTPUT_INTERNAL_LABEL'; the fourth argument is the jump-table
+ which follows (a `jump_insn' containing an `addr_vec' or
+ `addr_diff_vec').
+
+ This feature is used on system V to output a `swbeg' statement for
+ the table.
+
+ If this macro is not defined, these labels are output with
+ `ASM_OUTPUT_INTERNAL_LABEL'. */
+
+/* `ASM_OUTPUT_CASE_END (STREAM, NUM, TABLE)'
+ Define this if something special must be output at the end of a
+ jump-table. The definition should be a C statement to be executed
+ after the assembler code for the table is written. It should write
+ the appropriate code to stdio stream STREAM. The argument TABLE
+ is the jump-table insn, and NUM is the label-number of the
+ preceding label.
+
+ If this macro is not defined, nothing special is output at the end
+ of the jump-table. */
+
+#define ASM_OUTPUT_SKIP(STREAM, n) \
+fprintf (STREAM, "\t.skip %d,0\n", n)
+/* A C statement to output to the stdio stream STREAM an assembler
+ instruction to advance the location counter by NBYTES bytes.
+ Those bytes should be zero when loaded. NBYTES will be a C
+ expression of type `int'. */
+
+#define ASM_OUTPUT_ALIGN(STREAM, POWER)
+/* A C statement to output to the stdio stream STREAM an assembler
+ command to advance the location counter to a multiple of 2 to the
+ POWER bytes. POWER will be a C expression of type `int'. */
+
+#define CASE_VECTOR_MODE HImode
+/* An alias for a machine mode name. This is the machine mode that
+ elements of a jump-table should have. */
+
+#define CASE_VALUES_THRESHOLD 17
+/* `CASE_VALUES_THRESHOLD'
+ Define this to be the smallest number of different values for
+ which it is best to use a jump-table instead of a tree of
+ conditional branches. The default is four for machines with a
+ `casesi' instruction and five otherwise. This is best for most
+ machines. */
+
+#undef WORD_REGISTER_OPERATIONS
+/* Define this macro if operations between registers with integral
+ mode smaller than a word are always performed on the entire
+ register. Most RISC machines have this property and most CISC
+ machines do not. */
+
+#define EASY_DIV_EXPR TRUNC_DIV_EXPR
+/* An alias for a tree code that is the easiest kind of division to
+ compile code for in the general case. It may be `TRUNC_DIV_EXPR',
+ `FLOOR_DIV_EXPR', `CEIL_DIV_EXPR' or `ROUND_DIV_EXPR'. These four
+ division operators differ in how they round the result to an
+ integer. `EASY_DIV_EXPR' is used when it is permissible to use
+ any of those kinds of division and the choice should be made on
+ the basis of efficiency. */
+
+#define MOVE_MAX 4
+/* The maximum number of bytes that a single instruction can move
+ quickly between memory and registers or between two memory
+ locations. */
+
+#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
+/* A C expression which is nonzero if on this machine it is safe to
+ "convert" an integer of INPREC bits to one of OUTPREC bits (where
+ OUTPREC is smaller than INPREC) by merely operating on it as if it
+ had only OUTPREC bits.
+
+ On many machines, this expression can be 1.
+
+ When `TRULY_NOOP_TRUNCATION' returns 1 for a pair of sizes for
+ modes for which `MODES_TIEABLE_P' is 0, suboptimal code can result.
+ If this is the case, making `TRULY_NOOP_TRUNCATION' return 0 in
+ such cases may improve things. */
+
+#define Pmode HImode
+/* An alias for the machine mode for pointers. On most machines,
+ define this to be the integer mode corresponding to the width of a
+ hardware pointer; `SImode' on 32-bit machine or `DImode' on 64-bit
+ machines. On some machines you must define this to be one of the
+ partial integer modes, such as `PSImode'.
+
+ The width of `Pmode' must be at least as large as the value of
+ `POINTER_SIZE'. If it is not equal, you must define the macro
+ `POINTERS_EXTEND_UNSIGNED' to specify how pointers are extended to
+ `Pmode'. */
+
+#define FUNCTION_MODE HImode
+/* An alias for the machine mode used for memory references to
+ functions being called, in `call' RTL expressions. On most
+ machines this should be `QImode'. */
+ /* 1 3 */
+#define INTEGRATE_THRESHOLD(DECL) (1 + (3 * list_length (DECL_ARGUMENTS (DECL)) / 2))
+
+/* A C expression for the maximum number of instructions above which
+ the function DECL should not be inlined. DECL is a
+ `FUNCTION_DECL' node.
+
+ The default definition of this macro is 64 plus 8 times the number
+ of arguments that the function accepts. Some people think a larger
+ threshold should be used on RISC machines. */
+
+#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \
+valid_machine_decl_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS)
+/* `VALID_MACHINE_DECL_ATTRIBUTE (DECL, ATTRIBUTES, IDENTIFIER, ARGS)'
+ If defined, a C expression whose value is nonzero if IDENTIFIER
+ with arguments ARGS is a valid machine specific attribute for DECL.
+ The attributes in ATTRIBUTES have previously been assigned to DECL. */
+
+#define VALID_MACHINE_TYPE_ATTRIBUTE(TYPE, ATTRIBUTES, IDENTIFIER, ARGS) \
+ valid_machine_type_attribute(TYPE, ATTRIBUTES, IDENTIFIER, ARGS)
+/* `VALID_MACHINE_TYPE_ATTRIBUTE (TYPE, ATTRIBUTES, IDENTIFIER, ARGS)'
+ If defined, a C expression whose value is nonzero if IDENTIFIER
+ with arguments ARGS is a valid machine specific attribute for TYPE.
+ The attributes in ATTRIBUTES have previously been assigned to TYPE. */
+
+#define DOLLARS_IN_IDENTIFIERS 0
+/* Define this macro to control use of the character `$' in identifier
+ names. 0 means `$' is not allowed by default; 1 means it is
+ allowed. 1 is the default; there is no need to define this macro
+ in that case. This macro controls the compiler proper; it does
+ not affect the preprocessor. */
+
+#define NO_DOLLAR_IN_LABEL 1
+/* Define this macro if the assembler does not accept the character
+ `$' in label names. By default constructors and destructors in
+ G++ have `$' in the identifiers. If this macro is defined, `.' is
+ used instead. */
+
+#define MACHINE_DEPENDENT_REORG(INSN) machine_dependent_reorg (INSN)
+/* In rare cases, correct code generation requires extra machine
+ dependent processing between the second jump optimization pass and
+ delayed branch scheduling. On those machines, define this macro
+ as a C statement to act on the code starting at INSN. */
+
+#define GIV_SORT_CRITERION(X, Y) \
+ if (GET_CODE ((X)->add_val) == CONST_INT \
+ && GET_CODE ((Y)->add_val) == CONST_INT) \
+ return INTVAL ((X)->add_val) - INTVAL ((Y)->add_val);
+
+/* `GIV_SORT_CRITERION(GIV1, GIV2)'
+ In some cases, the strength reduction optimization pass can
+ produce better code if this is defined. This macro controls the
+ order that induction variables are combined. This macro is
+ particularly useful if the target has limited addressing modes.
+ For instance, the SH target has only positive offsets in
+ addresses. Thus sorting to put the smallest address first allows
+ the most combinations to be found. */
+
+/* Define results of standard character escape sequences. */
+#define TARGET_BELL 007
+#define TARGET_BS 010
+#define TARGET_TAB 011
+#define TARGET_NEWLINE 012
+#define TARGET_VT 013
+#define TARGET_FF 014
+#define TARGET_CR 015
+
+
+
+#define TRAMPOLINE_TEMPLATE(FILE) fatal ("Trampolines not supported\n")
+
+/* Length in units of the trampoline for entering a nested function. */
+
+#define TRAMPOLINE_SIZE 4
+
+/* Emit RTL insns to initialize the variable parts of a trampoline.
+ FNADDR is an RTX for the address of the function's pure code.
+ CXT is an RTX for the static chain value for the function. */
+
+#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \
+{ \
+ emit_move_insn (gen_rtx (MEM, HImode, plus_constant ((TRAMP), 2)), CXT); \
+ emit_move_insn (gen_rtx (MEM, HImode, plus_constant ((TRAMP), 6)), FNADDR); \
+}
+/* Store in cc_status the expressions
+ that the condition codes will describe
+ after execution of an instruction whose pattern is EXP.
+ Do not alter them if the instruction would not alter the cc's. */
+
+#define NOTICE_UPDATE_CC(EXP, INSN) notice_update_cc(EXP, INSN)
+
+/* The add insns don't set overflow in a usable way. */
+#define CC_OVERFLOW_UNUSABLE 01000
+/* The mov,and,or,xor insns don't set carry. That's ok though as the
+ Z bit is all we need when doing unsigned comparisons on the result of
+ these insns (since they're always with 0). However, conditions.h has
+ CC_NO_OVERFLOW defined for this purpose. Rename it to something more
+ understandable. */
+#define CC_NO_CARRY CC_NO_OVERFLOW
+
+
+/* Output assembler code to FILE to increment profiler label # LABELNO
+ for profiling a function entry. */
+
+#define FUNCTION_PROFILER(FILE, LABELNO) \
+ fprintf (FILE, "/* profiler %d */", (LABELNO))
+
+/* `FIRST_INSN_ADDRESS'
+ When the `length' insn attribute is used, this macro specifies the
+ value to be assigned to the address of the first insn in a
+ function. If not specified, 0 is used. */
+
+#define ADJUST_INSN_LENGTH(INSN, LENGTH) (LENGTH =\
+ adjust_insn_length (INSN, LENGTH))
+/* If defined, modifies the length assigned to instruction INSN as a
+ function of the context in which it is used. LENGTH is an lvalue
+ that contains the initially computed length of the insn and should
+ be updated with the correct length of the insn. If updating is
+ required, INSN must not be a varying-length insn.
+
+ This macro will normally not be required. A case in which it is
+ required is the ROMP. On this machine, the size of an `addr_vec'
+ insn must be increased by two to compensate for the fact that
+ alignment may be required. */
+
+#define TARGET_MEM_FUNCTIONS
+/* Define this macro if GNU CC should generate calls to the System V
+ (and ANSI C) library functions `memcpy' and `memset' rather than
+ the BSD functions `bcopy' and `bzero'. */
+
+#define CPP_SPEC "\
+%{!mmcu=*:-DAVR_AT90S8515} \
+%{mmcu=at90s2313:-DAVR_AT90S2313} \
+%{mmcu=at90s2323:-DAVR_AT90S2323} \
+%{mmcu=at90s2333:-DAVR_AT90S2333} \
+%{mmcu=at90s2343:-DAVR_AT90S2343} \
+%{mmcu=attiny22:-DAVR_ATtiny22} \
+%{mmcu=at90s4433:-DAVR_AT90S4433} \
+%{mmcu=at90s4414:-DAVR_AT90S4414} \
+%{mmcu=at90s4434:-DAVR_AT90S4434} \
+%{mmcu=at90s8515:-DAVR_AT90S8515} \
+%{mmcu=at90s8535:-DAVR_AT90S8535} \
+%{mmcu=atmega603:-DAVR_ATmega603} \
+%{mmcu=atmega103:-DAVR_ATmega103} \
+%{mint8:-D__SIZE_TYPE__=long\\ unsigned\\ int -D__PTRDIFF_TYPE__=long -D__INT_MAX__=127} \
+%{!mint*:-D__SIZE_TYPE__=unsigned\\ int -D__PTRDIFF_TYPE__=int -D__INT_MAX__=32767} \
+%{posix:-D_POSIX_SOURCE}"
+/* A C string constant that tells the GNU CC driver program options to
+ pass to CPP. It can also specify how to translate options you
+ give to GNU CC into options for GNU CC to pass to the CPP.
+
+ Do not define this macro if it does not need to do anything. */
+
+#define NO_BUILTIN_SIZE_TYPE
+/* If this macro is defined, the preprocessor will not define the
+ builtin macro `__SIZE_TYPE__'. The macro `__SIZE_TYPE__' must
+ then be defined by `CPP_SPEC' instead.
+
+ This should be defined if `SIZE_TYPE' depends on target dependent
+ flags which are not accessible to the preprocessor. Otherwise, it
+ should not be defined. */
+
+#define NO_BUILTIN_PTRDIFF_TYPE
+/* If this macro is defined, the preprocessor will not define the
+ builtin macro `__PTRDIFF_TYPE__'. The macro `__PTRDIFF_TYPE__'
+ must then be defined by `CPP_SPEC' instead.
+
+ This should be defined if `PTRDIFF_TYPE' depends on target
+ dependent flags which are not accessible to the preprocessor.
+ Otherwise, it should not be defined.
+
+ `SIGNED_CHAR_SPEC'
+ A C string constant that tells the GNU CC driver program options to
+ pass to CPP. By default, this macro is defined to pass the option
+ `-D__CHAR_UNSIGNED__' to CPP if `char' will be treated as
+ `unsigned char' by `cc1'.
+
+ Do not define this macro unless you need to override the default
+ definition. */
+
+#define CC1_SPEC "%{!mmcu*:-mmcu=at90s8515} %{profile:-p}"
+/* A C string constant that tells the GNU CC driver program options to
+ pass to `cc1'. It can also specify how to translate options you
+ give to GNU CC into options for GNU CC to pass to the `cc1'.
+
+ Do not define this macro if it does not need to do anything. */
+
+#define ASM_SPEC ""
+/* A C string constant that tells the GNU CC driver program options to
+ pass to the assembler. It can also specify how to translate
+ options you give to GNU CC into options for GNU CC to pass to the
+ assembler. See the file `sun3.h' for an example of this.
+
+ Do not define this macro if it does not need to do anything. */
+
+#define ASM_FINAL_SPEC ""
+/* A C string constant that tells the GNU CC driver program how to
+ run any programs which cleanup after the normal assembler.
+ Normally, this is not needed. See the file `mips.h' for an
+ example of this.
+
+ Do not define this macro if it does not need to do anything. */
+
+#define LINK_SPEC "\
+%{!mmcu*:-m avr85xx} \
+%{mmcu=atmega603:-m avrmega603} \
+%{mmcu=atmega103:-m avrmega103} \
+%{mmcu=at90s2313:-m avr23xx} \
+%{mmcu=at90s2323:-m avr23xx} \
+%{mmcu=attiny22:-m avr23xx} \
+%{mmcu=at90s2333:-m avr23xx} \
+%{mmcu=at90s2343:-m avr23xx} \
+%{mmcu=at90s4433:-m avr4433} \
+%{mmcu=at90s4414:-m avr44x4} \
+%{mmcu=at90s4434:-m avr44x4} \
+%{mmcu=at90s8535:-m avr85xx} \
+%{mmcu=at90s8515:-m avr85xx}"
+
+/* A C string constant that tells the GNU CC driver program options to
+ pass to the linker. It can also specify how to translate options
+ you give to GNU CC into options for GNU CC to pass to the linker.
+
+ Do not define this macro if it does not need to do anything. */
+
+#define LIB_SPEC "\
+%{!mmcu*|mmcu=at90s*|mmcu=attiny22: -lc} \
+%{mmcu=atmega*: -lc-mega}"
+/* Another C string constant used much like `LINK_SPEC'. The
+ difference between the two is that `LIB_SPEC' is used at the end
+ of the command given to the linker.
+
+ If this macro is not defined, a default is provided that loads the
+ standard C library from the usual place. See `gcc.c'. */
+
+#define LIBGCC_SPEC "\
+%{mmcu=atmega*:-lgcc} \
+%{!mmcu*|mmcu=at90s*|mmcu=attiny22:-lgcc}"
+/* Another C string constant that tells the GNU CC driver program how
+ and when to place a reference to `libgcc.a' into the linker
+ command line. This constant is placed both before and after the
+ value of `LIB_SPEC'.
+
+ If this macro is not defined, the GNU CC driver provides a default
+ that passes the string `-lgcc' to the linker unless the `-shared'
+ option is specified. */
+
+#define STARTFILE_SPEC "%(crt_binutils)"
+/* Another C string constant used much like `LINK_SPEC'. The
+ difference between the two is that `STARTFILE_SPEC' is used at the
+ very beginning of the command given to the linker.
+
+ If this macro is not defined, a default is provided that loads the
+ standard C startup file from the usual place. See `gcc.c'. */
+
+#define ENDFILE_SPEC ""
+/* Another C string constant used much like `LINK_SPEC'. The
+ difference between the two is that `ENDFILE_SPEC' is used at the
+ very end of the command given to the linker.
+
+ Do not define this macro if it does not need to do anything. */
+
+#define CRT_BINUTILS_SPECS "\
+%{!mmcu*:gcrt1-8515.o%s} \
+%{mmcu=atmega603:gcrt1-mega603.o%s} \
+%{mmcu=atmega103:gcrt1-mega103.o%s} \
+%{mmcu=at90s2313:gcrt1-2313.o%s} \
+%{mmcu=at90s2323:gcrt1-2323.o%s} \
+%{mmcu=attiny22:gcrt1-tiny22.o%s} \
+%{mmcu=at90s2333:gcrt1-2333.o%s} \
+%{mmcu=at90s2343:gcrt1-2343.o%s} \
+%{mmcu=at90s4433:gcrt1-4433.o%s} \
+%{mmcu=at90s4414:gcrt1-4414.o%s} \
+%{mmcu=at90s4434:gcrt1-4434.o%s} \
+%{mmcu=at90s8535:gcrt1-8535.o%s} \
+%{mmcu=at90s8515:gcrt1-8515.o%s}"
+
+#define EXTRA_SPECS \
+{"crt_binutils", CRT_BINUTILS_SPECS},
+/* Define this macro to provide additional specifications to put in
+ the `specs' file that can be used in various specifications like
+ `CC1_SPEC'.
+
+ The definition should be an initializer for an array of structures,
+ containing a string constant, that defines the specification name,
+ and a string constant that provides the specification.
+
+ Do not define this macro if it does not need to do anything.
+
+ `EXTRA_SPECS' is useful when an architecture contains several
+ related targets, which have various `..._SPECS' which are similar
+ to each other, and the maintainer would like one central place to
+ keep these definitions.
+
+ For example, the PowerPC System V.4 targets use `EXTRA_SPECS' to
+ define either `_CALL_SYSV' when the System V calling sequence is
+ used or `_CALL_AIX' when the older AIX-based calling sequence is
+ used.
+
+ The `config/rs6000/rs6000.h' target file defines:
+
+ #define EXTRA_SPECS \
+ { "cpp_sysv_default", CPP_SYSV_DEFAULT },
+
+ #define CPP_SYS_DEFAULT ""
+
+ The `config/rs6000/sysv.h' target file defines:
+ #undef CPP_SPEC
+ #define CPP_SPEC \
+ "%{posix: -D_POSIX_SOURCE } \
+ %{mcall-sysv: -D_CALL_SYSV } %{mcall-aix: -D_CALL_AIX } \
+ %{!mcall-sysv: %{!mcall-aix: %(cpp_sysv_default) }} \
+ %{msoft-float: -D_SOFT_FLOAT} %{mcpu=403: -D_SOFT_FLOAT}"
+
+ #undef CPP_SYSV_DEFAULT
+ #define CPP_SYSV_DEFAULT "-D_CALL_SYSV"
+
+ while the `config/rs6000/eabiaix.h' target file defines
+ `CPP_SYSV_DEFAULT' as:
+
+ #undef CPP_SYSV_DEFAULT
+ #define CPP_SYSV_DEFAULT "-D_CALL_AIX" */
+
+/* This is undefined macro for collect2 disabling */
+#define LINKER_NAME "ld"
+
+#define TEST_HARD_REG_CLASS(CLASS, REGNO) \
+ TEST_HARD_REG_BIT (reg_class_contents[ (int) (CLASS)], REGNO)
+
+/* Note that the other files fail to use these
+ in some of the places where they should. */
+
+#if defined(__STDC__) || defined(ALMOST_STDC)
+#define AS2(a,b,c) #a " " #b "," #c
+#define AS2C(b,c) " " #b "," #c
+#define AS3(a,b,c,d) #a " " #b "," #c "," #d
+#define AS1(a,b) #a " " #b
+#else
+#define AS1(a,b) "a b"
+#define AS2(a,b,c) "a b,c"
+#define AS2C(b,c) " b,c"
+#define AS3(a,b,c,d) "a b,c,d"
+#endif
+#define OUT_AS1(a,b) output_asm_insn (AS1(a,b), operands)
+#define OUT_AS2(a,b,c) output_asm_insn (AS2(a,b,c), operands)
+#define CR_TAB "\n\t"
+
+/* Define this macro as a C statement that declares additional library
+ routines renames existing ones. `init_optabs' calls this macro
+ after initializing all the normal library routines. */
+
+#define INIT_TARGET_OPTABS \
+{ \
+ smul_optab->handlers[(int) QImode].libfunc \
+ = gen_rtx (SYMBOL_REF, Pmode, "_mulqi3"); \
+ \
+ sdiv_optab->handlers[(int) QImode].libfunc \
+ = gen_rtx (SYMBOL_REF, Pmode, "_divqi3"); \
+ \
+ smod_optab->handlers[(int) QImode].libfunc \
+ = gen_rtx (SYMBOL_REF, Pmode, "_modqi3"); \
+ \
+ udiv_optab->handlers[(int) QImode].libfunc \
+ = gen_rtx (SYMBOL_REF, Pmode, "_udivqi3"); \
+ \
+ umod_optab->handlers[(int) QImode].libfunc \
+ = gen_rtx (SYMBOL_REF, Pmode, "_umodqi3"); \
+ \
+ smul_optab->handlers[(int) HImode].libfunc \
+ = gen_rtx (SYMBOL_REF, Pmode, "_mulhi3"); \
+ \
+ sdiv_optab->handlers[(int) HImode].libfunc \
+ = gen_rtx (SYMBOL_REF, Pmode, "_divhi3"); \
+ \
+ smod_optab->handlers[(int) HImode].libfunc \
+ = gen_rtx (SYMBOL_REF, Pmode, "_modhi3"); \
+ \
+ udiv_optab->handlers[(int) HImode].libfunc \
+ = gen_rtx (SYMBOL_REF, Pmode, "_udivhi3"); \
+ \
+ umod_optab->handlers[(int) HImode].libfunc \
+ = gen_rtx (SYMBOL_REF, Pmode, "_umodhi3"); \
+ \
+ smul_optab->handlers[(int) SImode].libfunc \
+ = gen_rtx (SYMBOL_REF, Pmode, "_mulsi3"); \
+ \
+ sdiv_optab->handlers[(int) SImode].libfunc \
+ = gen_rtx (SYMBOL_REF, Pmode, "_divsi3"); \
+ \
+ smod_optab->handlers[(int) SImode].libfunc \
+ = gen_rtx (SYMBOL_REF, Pmode, "_modsi3"); \
+ \
+ udiv_optab->handlers[(int) SImode].libfunc \
+ = gen_rtx (SYMBOL_REF, Pmode, "_udivsi3"); \
+ \
+ umod_optab->handlers[(int) SImode].libfunc \
+ = gen_rtx (SYMBOL_REF, Pmode, "_umodsi3"); \
+ avr_init_once(); \
+}
+
+/* Temporary register r0 */
+#define TMP_REGNO 0
+
+/* zero register r1 */
+#define ZERO_REGNO 1
+
+extern struct rtx_def *tmp_reg_rtx;
+extern struct rtx_def *zero_reg_rtx;
+
+#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT
+
+/* Define to use software floating point emulator for REAL_ARITHMETIC and
+ decimal <-> binary conversion. */
+#define REAL_ARITHMETIC
+
+#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
+
+#define DBX_REGISTER_NUMBER(r) (r)
+
+/* Get the standard ELF stabs definitions. */
+#include "dbxelf.h"
+
+#undef ASM_IDENTIFY_GCC
+#define ASM_IDENTIFY_GCC(FILE) \
+do \
+ { \
+ if (write_symbols != DBX_DEBUG) \
+ fputs ("gcc2_compiled.:\n", FILE); \
+ } \
+while (0)
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
new file mode 100644
index 00000000000..f90db472727
--- /dev/null
+++ b/gcc/config/avr/avr.md
@@ -0,0 +1,1903 @@
+;; -*- Mode: Scheme -*-
+;; Machine description for GNU compiler,
+;; for ATMEL AVR micro controllers.
+;; Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+;; Contributed by Denis Chertykov (denisc@overta.ru)
+
+;; This file is part of GNU CC.
+
+;; GNU CC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU CC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU CC; see the file COPYING. If not, write to
+;; the Free Software Foundation, 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;; Condition code settings.
+(define_attr "cc" "none,set_czn,set_zn,set_n,compare,clobber"
+ (const_string "none"))
+
+(define_attr "type" "branch,branch1,arith"
+ (const_string "arith"))
+
+;; The size of instructions in bytes.
+;; XXX may depend from "cc"
+
+(define_attr "length" ""
+ (cond [(eq_attr "type" "branch")
+ (if_then_else (and (ge (minus (pc) (match_dup 0))
+ (const_int -63))
+ (le (minus (pc) (match_dup 0))
+ (const_int 62)))
+ (const_int 1)
+ (if_then_else (and (ge (minus (pc) (match_dup 0))
+ (const_int -2045))
+ (le (minus (pc) (match_dup 0))
+ (const_int 2045)))
+ (const_int 2)
+ (const_int 2)))
+ (eq_attr "type" "branch1")
+ (if_then_else (and (ge (minus (pc) (match_dup 0))
+ (const_int -62))
+ (le (minus (pc) (match_dup 0))
+ (const_int 61)))
+ (const_int 2)
+ (if_then_else (and (ge (minus (pc) (match_dup 0))
+ (const_int -2044))
+ (le (minus (pc) (match_dup 0))
+ (const_int 2043)))
+ (const_int 3)
+ (const_int 3)))]
+ (const_int 2)))
+
+(define_insn "*pop1"
+ [(set (reg:HI 32) (plus:HI (reg:HI 32) (const_int 1)))]
+ ""
+ "pop __tmp_reg__"
+ [(set_attr "length" "1")])
+
+(define_insn "*pop2"
+ [(set (reg:HI 32) (plus:HI (reg:HI 32) (const_int 2)))]
+ ""
+ "pop __tmp_reg__
+ pop __tmp_reg__"
+ [(set_attr "length" "2")])
+
+(define_insn "*pop3"
+ [(set (reg:HI 32) (plus:HI (reg:HI 32) (const_int 3)))]
+ ""
+ "pop __tmp_reg__
+ pop __tmp_reg__
+ pop __tmp_reg__"
+ [(set_attr "length" "3")])
+
+(define_insn "*pop4"
+ [(set (reg:HI 32) (plus:HI (reg:HI 32) (const_int 4)))]
+ ""
+ "pop __tmp_reg__
+ pop __tmp_reg__
+ pop __tmp_reg__
+ pop __tmp_reg__"
+ [(set_attr "length" "4")])
+
+(define_insn "*pop5"
+ [(set (reg:HI 32) (plus:HI (reg:HI 32) (const_int 5)))]
+ ""
+ "pop __tmp_reg__
+ pop __tmp_reg__
+ pop __tmp_reg__
+ pop __tmp_reg__
+ pop __tmp_reg__"
+ [(set_attr "length" "5")])
+
+(define_insn "*pushqi"
+ [(set (mem:QI (post_dec (reg:HI 32)))
+ (match_operand:QI 0 "nonmemory_operand" "r,L"))]
+ "(operands[0] == const0_rtx || register_operand (operands[0], QImode))"
+ "@
+ push %0
+ push __zero_reg__"
+ [(set_attr "length" "1,1")])
+
+
+(define_insn "*pushhi"
+ [(set (mem:HI (post_dec (reg:HI 32)))
+ (match_operand:HI 0 "nonmemory_operand" "r,L"))]
+ "(operands[0] == const0_rtx || register_operand (operands[0], HImode))"
+ "@
+ push %B0\;push %A0
+ push __zero_reg__\;push __zero_reg__"
+ [(set_attr "length" "2,2")])
+
+(define_insn "*pushsi"
+ [(set (mem:SI (post_dec (reg:HI 32)))
+ (match_operand:SI 0 "nonmemory_operand" "r,L"))]
+ "(operands[0] == const0_rtx || register_operand (operands[0], SImode))"
+ "@
+ push %D0\;push %C0\;push %B0\;push %A0
+ push __zero_reg__\;push __zero_reg__\;push __zero_reg__\;push __zero_reg__"
+ [(set_attr "length" "4,4")])
+
+(define_insn "*pushsf"
+ [(set (mem:SF (post_dec (reg:HI 32)))
+ (match_operand:SF 0 "register_operand" "r"))]
+ ""
+ "push %D0
+ push %C0
+ push %B0
+ push %A0"
+ [(set_attr "length" "4")])
+
+(define_insn "*mov_r_sp"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (reg:HI 32))]
+ ""
+ "in %A0,__SP_L__
+ in %B0,__SP_H__"
+ [(set_attr "length" "2")])
+
+(define_insn "*mov_sp_r"
+ [(set (reg:HI 32)
+ (match_operand:HI 0 "register_operand" "r"))]
+ "!TARGET_NO_INTERRUPTS"
+ "in __tmp_reg__,__SREG__
+ cli
+ out __SP_L__,%A0
+ out __SREG__,__tmp_reg__
+ out __SP_H__,%B0"
+ [(set_attr "length" "5")])
+
+(define_insn "*mov_sp_r_no_interrupts"
+ [(set (reg:HI 32)
+ (match_operand:HI 0 "register_operand" "r"))]
+ "TARGET_NO_INTERRUPTS"
+ "out __SP_L__,%A0
+ out __SP_H__,%B0"
+ [(set_attr "length" "2")])
+
+;;========================================================================
+;; move byte
+(define_expand "movqi"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "")
+ (match_operand:QI 1 "general_operand" ""))]
+ ""
+ "
+{
+ /* One of the ops has to be in a register */
+ if (!register_operand(operand0, QImode)
+ && ! (register_operand(operand1, QImode) || const0_rtx == operand1))
+ {
+ operands[1] = copy_to_mode_reg(QImode, operand1);
+ }
+ }");
+
+(define_insn "*movqi"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,d,Qm,r,q")
+ (match_operand:QI 1 "general_operand" "r,L,i,rL,Qm,r"))]
+ "(register_operand (operands[0],QImode)
+ || register_operand (operands[1], QImode) || const0_rtx == operands[1])"
+ "*{
+ switch (which_alternative)
+ {
+ case 0:
+ return AS2 (mov, %0,%1);
+ case 1:
+ return AS1 (clr, %0);
+ case 2:
+ return AS2 (ldi, %0,lo8(%1));
+ case 3:
+ {
+ rtx save1=NULL;
+ if (operands[1] == const0_rtx)
+ {
+ save1 = operands[1];
+ operands[1] = zero_reg_rtx;
+ }
+ output_asm_insn (out_movqi_mr_r (insn,operands,NULL), operands);
+ if (save1)
+ operands[1] = save1;
+ }
+ return \"\";
+ case 4:
+ return out_movqi_r_mr (insn,operands,NULL);
+ case 5:
+ return (AS2 (in,__tmp_reg__,__SREG__) CR_TAB
+ \"cli\" CR_TAB
+ AS2 (out,__SREG__,__tmp_reg__)CR_TAB
+ AS2 (out,%0,%1));
+ }
+}"
+ [(set_attr "length" "1,1,1,5,5,4")
+ (set_attr "cc" "none,clobber,none,clobber,clobber,none")])
+
+;;============================================================================
+;; move word (16 bit)
+
+(define_expand "movhi"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "")
+ (match_operand:HI 1 "general_operand" ""))]
+ ""
+ "
+{
+ /* One of the ops has to be in a register */
+ if (!register_operand(operand0, HImode)
+ && !(register_operand(operand1, HImode) || const0_rtx == operands[1]))
+ {
+ operands[1] = copy_to_mode_reg(HImode, operand1);
+ }
+}")
+
+(define_insn "*movhi"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,d,r,m")
+ (match_operand:HI 1 "general_operand" "r,L,i,m,rL"))]
+ "(register_operand (operands[0],HImode)
+ || register_operand (operands[1],HImode) || const0_rtx == operands[1])"
+ "*{
+ rtx link;
+ switch (which_alternative)
+ {
+ case 0: /* mov r,r */
+ if (true_regnum (operands[0]) > true_regnum (operands[1]))
+ return (AS2 (mov,%B0,%B1) CR_TAB
+ AS2 (mov,%A0,%A1));
+ else
+ return (AS2 (mov,%A0,%A1) CR_TAB
+ AS2 (mov,%B0,%B1));
+ case 1: /* mov r,L */
+ return (AS1 (clr,%A0) CR_TAB
+ AS1 (clr,%B0));
+ case 2: /* mov r,d */
+ if (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)));
+ case 3: /* mov r,m*/
+ return out_movhi_r_mr (insn, operands, NULL);
+ case 4: /* mov m,r*/
+ {
+ rtx save1=NULL;
+ if (operands[1] == const0_rtx)
+ {
+ save1 = operands[1];
+ operands[1] = zero_reg_rtx;
+ }
+ output_asm_insn (out_movhi_mr_r (insn,operands,NULL), operands);
+ if (save1)
+ operands[1] = save1;
+ }
+ return \"\";
+ }
+}"
+ [(set_attr "length" "2,2,2,4,4")
+ (set_attr "cc" "none,set_zn,none,clobber,clobber")])
+
+;;==========================================================================
+;; move double word (32 bit)
+
+(define_expand "movsi"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "")
+ (match_operand:SI 1 "general_operand" ""))]
+ ""
+ "
+{
+ /* One of the ops has to be in a register. */
+ if (!register_operand (operand0, SImode)
+ && !(register_operand (operand1, SImode) || const0_rtx == operand1))
+ {
+ operands[1] = copy_to_mode_reg (SImode, operand1);
+ }
+}")
+
+(define_insn "*movsi"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,d,r,Qm")
+ (match_operand:SI 1 "general_operand" "r,L,i,Qm,rL"))]
+ "(register_operand (operands[0],SImode)
+ || register_operand (operands[1],SImode) || const0_rtx == operands[1])"
+ "* return output_movsisf (insn, operands, which_alternative);"
+ [(set_attr "length" "4,4,4,8,8")
+ (set_attr "cc" "none,set_zn,none,clobber,clobber")])
+
+;; fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+;; move floating point numbers (32 bit)
+
+(define_expand "movsf"
+ [(set (match_operand:SF 0 "nonimmediate_operand" "")
+ (match_operand:SF 1 "general_operand" ""))]
+ ""
+ "
+{
+ /* One of the ops has to be in a register. */
+ if (!register_operand (operand1, SFmode)
+ && !register_operand (operand0, SFmode))
+ {
+ operands[1] = copy_to_mode_reg (SFmode, operand1);
+ }
+}")
+
+(define_insn "*movsf"
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,d,r,Qm")
+ (match_operand:SF 1 "general_operand" "r,G,F,Qm,r"))]
+ "register_operand (operands[0], SFmode)
+ || register_operand (operands[1], SFmode)"
+ "* return output_movsisf (insn, operands, which_alternative);"
+ [(set_attr "length" "4,4,4,8,8")
+ (set_attr "cc" "none,set_zn,none,clobber,clobber")])
+
+;;=========================================================================
+;; move string (like memcpy)
+
+(define_expand "movstrhi"
+ [(parallel [(set (match_operand:BLK 0 "memory_operand" "")
+ (match_operand:BLK 1 "memory_operand" ""))
+ (use (match_operand:HI 2 "const_int_operand" ""))
+ (use (match_operand:HI 3 "const_int_operand" ""))
+ (clobber (match_dup 4))
+ (clobber (match_dup 5))
+ (clobber (match_dup 6))])]
+ ""
+ "{
+ rtx addr0, addr1;
+ int cnt8;
+
+ if (GET_CODE (operands[2]) != CONST_INT)
+ FAIL;
+ cnt8 = byte_immediate_operand (operands[2], GET_MODE (operands[2]));
+ operands[2] = copy_to_mode_reg (cnt8 ? QImode : HImode, operands[2]);
+ operands[4] = operands[2];
+
+ addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
+ addr1 = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
+
+ operands[5] = addr0;
+ operands[6] = addr1;
+
+ operands[0] = gen_rtx (MEM, BLKmode, addr0);
+ operands[1] = gen_rtx (MEM, BLKmode, addr1);
+}")
+
+(define_insn "*movstrqi_insn"
+ [(set (mem:BLK (match_operand:HI 0 "register_operand" "e"))
+ (mem:BLK (match_operand:HI 1 "register_operand" "e")))
+ (use (match_operand:QI 2 "register_operand" "r"))
+ (use (match_operand:QI 3 "const_int_operand" "i"))
+ (clobber (match_dup 2))
+ (clobber (match_dup 0))
+ (clobber (match_dup 1))]
+ ""
+ "
+ ld __tmp_reg__,%a1+
+ st %a0+,__tmp_reg__
+ dec %2
+ brne _PC_-8"
+ [(set_attr "length" "4")
+ (set_attr "cc" "clobber")])
+
+(define_insn "*movstrhi"
+ [(set (mem:BLK (match_operand:HI 0 "register_operand" "e,e"))
+ (mem:BLK (match_operand:HI 1 "register_operand" "e,e")))
+ (use (match_operand:HI 2 "register_operand" "!w,d"))
+ (use (match_operand:HI 3 "const_int_operand" ""))
+ (clobber (match_dup 2))
+ (clobber (match_dup 0))
+ (clobber (match_dup 1))]
+ ""
+ "*{
+ if (which_alternative==0)
+ return (AS2 (ld,__tmp_reg__,%a1+) CR_TAB
+ AS2 (st,%a0+,__tmp_reg__) CR_TAB
+ AS2 (sbiw,%A2,1) CR_TAB
+ AS1 (brne,_PC_-8));
+ else
+ return (AS2 (ld,__tmp_reg__,%a1+) CR_TAB
+ AS2 (st,%a0+,__tmp_reg__) CR_TAB
+ AS2 (subi,%A2,1) CR_TAB
+ AS2 (sbci,%B2,0) CR_TAB
+ AS1 (brne,_PC_-10));
+}"
+ [(set_attr "length" "4,5")
+ (set_attr "cc" "clobber,clobber")])
+
+;; =0 =0 =0 =0 =0 =0 =0 =0 =0 =0 =0 =0 =0 =0 =0 =0 =0 =0 =0 =0 =0 =0 =0 =0
+;; memset (%0, 0, %1)
+
+(define_expand "clrstrhi"
+ [(parallel [(set (match_operand:BLK 0 "memory_operand" "")
+ (const_int 0))
+ (use (match_operand:HI 1 "const_int_operand" ""))
+ (use (match_operand:HI 2 "const_int_operand" "n"))
+ (clobber (match_dup 3))
+ (clobber (match_dup 4))])]
+ ""
+ "{
+ rtx addr0;
+ int cnt8;
+
+ if (GET_CODE (operands[1]) != CONST_INT)
+ FAIL;
+
+ cnt8 = byte_immediate_operand (operands[1], GET_MODE (operands[1]));
+ operands[1] = copy_to_mode_reg (cnt8 ? QImode : HImode, operands[1]);
+ operands[3] = operands[1];
+
+ addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
+ operands[4] = addr0;
+
+ operands[0] = gen_rtx (MEM, BLKmode, addr0);
+}")
+
+(define_insn "*clrstrqi"
+ [(set (mem:BLK (match_operand:HI 0 "register_operand" "e"))
+ (const_int 0))
+ (use (match_operand:QI 1 "register_operand" "r"))
+ (use (match_operand:QI 2 "const_int_operand" "n"))
+ (clobber (match_dup 1))
+ (clobber (match_dup 0))]
+ ""
+ "
+ st %a0+,__zero_reg__
+ dec %1
+ brne _PC_-6"
+ [(set_attr "length" "3")
+ (set_attr "cc" "clobber")])
+
+(define_insn "*clrstrhi"
+ [(set (mem:BLK (match_operand:HI 0 "register_operand" "e,e"))
+ (const_int 0))
+ (use (match_operand:HI 1 "register_operand" "!w,d"))
+ (use (match_operand:HI 2 "const_int_operand" "n,n"))
+ (clobber (match_dup 1))
+ (clobber (match_dup 0))]
+ ""
+ "*{
+ if (which_alternative==0)
+ return (AS2 (st,%a0+,__zero_reg__) CR_TAB
+ AS2 (sbiw,%A1,1) CR_TAB
+ AS1 (brne,_PC_-6));
+ else
+ return (AS2 (st,%a0+,__zero_reg__) CR_TAB
+ AS2 (subi,%A1,1) CR_TAB
+ AS2 (sbci,%B1,0) CR_TAB
+ AS1 (brne,_PC_-8));
+}"
+ [(set_attr "length" "3,4")
+ (set_attr "cc" "clobber,clobber")])
+
+(define_expand "strlenhi"
+ [(parallel
+ [(set (match_dup 4)
+ (unspec:HI [(match_operand:BLK 1 "memory_operand" "")
+ (match_operand:QI 2 "const_int_operand" "")
+ (match_operand:HI 3 "immediate_operand" "")] 0))
+ (clobber (match_dup 6))])
+ (set (match_dup 4) (plus:HI (match_dup 4)
+ (const_int -1)))
+ (set (match_operand:HI 0 "register_operand" "")
+ (minus:HI (match_dup 4)
+ (match_dup 5)))]
+ ""
+ "{
+ if (! (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0))
+ FAIL;
+ operands[6] = copy_to_mode_reg (Pmode, XEXP (operands[1],0));
+ operands[1] = gen_rtx (MEM, BLKmode, operands[6]);
+ operands[5] = operands[6];
+ operands[4] = gen_reg_rtx (HImode);
+}")
+
+(define_insn "*strlenhi"
+ [(set (match_operand:HI 0 "register_operand" "=e")
+ (unspec:HI [(mem:BLK (match_operand:HI 1 "register_operand" "%0"))
+ (const_int 0)
+ (match_operand:HI 2 "immediate_operand" "i")] 0))
+ (clobber (match_dup 1))]
+ ""
+ "ld __tmp_reg__,%a0+
+ tst __tmp_reg__
+ brne _PC_-6"
+ [(set_attr "length" "3")
+ (set_attr "cc" "clobber")])
+
+;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+; add bytes
+
+(define_insn "addqi3"
+ [(set (match_operand:QI 0 "register_operand" "=r,d,r,r")
+ (plus:QI (match_operand:QI 1 "register_operand" "%0,0,0,0")
+ (match_operand:QI 2 "nonmemory_operand" "r,i,P,N")))]
+ ""
+ "@
+ add %0,%2
+ subi %0,lo8(-(%2))
+ inc %0
+ dec %0"
+ [(set_attr "length" "1,1,1,1")
+ (set_attr "cc" "set_czn,set_czn,set_zn,set_zn")])
+
+
+(define_expand "addhi3"
+ [(set (match_operand:HI 0 "register_operand" "")
+ (plus:HI (match_operand:HI 1 "register_operand" "")
+ (match_operand:HI 2 "nonmemory_operand" "")))]
+ ""
+ "
+{
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ short tmp = INTVAL (operands[2]);
+ operands[2] = GEN_INT(tmp);
+ }
+ if (! (reload_completed | reload_in_progress))
+ {
+ if (REGNO (operands[0]) != REGNO (operands[1])
+ && REGNO (operands[0]) != REGNO (operands[2])&&0)
+ {
+ emit_move_insn (operands[0], operands[1]);
+ operands[1] = operands[0];
+ }
+ }
+}")
+
+
+(define_insn "*addhi3_zero_extend"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (plus:HI (zero_extend:HI
+ (match_operand:QI 1 "register_operand" "r"))
+ (match_operand:HI 2 "register_operand" "0")))]
+ ""
+ "add %A0,%1
+ adc %B0,__zero_reg__"
+ [(set_attr "length" "2")
+ (set_attr "cc" "set_n")])
+
+(define_insn "*addhi3_zero_extend1"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (plus:HI (match_operand:HI 1 "register_operand" "%0")
+ (zero_extend:HI
+ (match_operand:QI 2 "register_operand" "r"))))]
+ ""
+ "add %A0,%2
+ adc %B0,__zero_reg__"
+ [(set_attr "length" "2")
+ (set_attr "cc" "set_n")])
+
+(define_insn "*addhi3_zero_extend2"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (plus:HI
+ (zero_extend:HI (match_operand:QI 1 "register_operand" "%0"))
+ (zero_extend:HI (match_operand:QI 2 "register_operand" "r"))))]
+ ""
+ "add %0,%2
+ mov %B0,__zero_reg__
+ adc %B0,__zero_reg__"
+ [(set_attr "length" "3")
+ (set_attr "cc" "set_n")])
+
+(define_insn "*addhi3"
+ [(set (match_operand:HI 0 "register_operand" "=r,!w,!w,d,r,r")
+ (plus:HI
+ (match_operand:HI 1 "register_operand" "%0,0,0,0,0,0")
+ (match_operand:HI 2 "nonmemory_operand" "r,I,J,i,P,N")))]
+ ""
+ "@
+ add %A0,%A2\;adc %B0,%B2
+ adiw %A0,%2
+ sbiw %A0,%n2
+ subi %A0,lo8(-(%2))\;sbci %B0,hi8(-(%2))
+ sec\;adc %A0,__zero_reg__\;adc %B0,__zero_reg__
+ sec\;sbc %A0,__zero_reg__\;sbc %B0,__zero_reg__"
+ [(set_attr "length" "2,1,1,2,3,3")
+ (set_attr "cc" "set_n,set_czn,set_czn,set_czn,set_n,set_n")])
+
+(define_insn "addsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,!w,!w,d,r,r,&*!w,&*!w")
+ (plus:SI
+ (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r,r")
+ (match_operand:SI 2 "nonmemory_operand" "r,I,J,i,P,N,#I,#J")))]
+ ""
+ "@
+ add %A0,%A2\;adc %B0,%B2\;adc %C0,%C2\;adc %D0,%D2
+ adiw %0,%2\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__
+ sbiw %0,%n2\;sbc %C0,__zero_reg__\;sbc %D0,__zero_reg__
+ subi %0,lo8(-(%2))\;sbci %B0,hi8(-(%2))\;sbci %C0,hlo8(-(%2))\;sbci %D0,hhi8(-(%2))
+ sec\;adc %A0,__zero_reg__\;adc %B0,__zero_reg__\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__
+ sec\;sbc %A0,__zero_reg__\;sbc %B0,__zero_reg__\;sbc %C0,__zero_reg__\;sbc %D0,__zero_reg__
+ mov %A0,%A1\;mov %B0,%B1\;mov %C0,%C1\;mov %D0,%D1\;adiw %0,%2\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__
+ mov %A0,%A1\;mov %B0,%B1\;mov %C0,%C1\;mov %D0,%D1\;sbiw %0,%n2\;sbc %C0,__zero_reg__\;sbc %D0,__zero_reg__"
+ [(set_attr "length" "4,3,3,4,5,5,7,7")
+ (set_attr "cc" "set_n,set_n,set_czn,set_czn,set_n,set_n,set_n,set_czn")])
+
+;-----------------------------------------------------------------------------
+; sub bytes
+(define_insn "subqi3"
+ [(set (match_operand:QI 0 "register_operand" "=r,d")
+ (minus:QI (match_operand:QI 1 "register_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "r,i")))]
+ ""
+ "@
+ sub %0,%2
+ subi %0,lo8(%2)"
+ [(set_attr "length" "1,1")
+ (set_attr "cc" "set_czn,set_czn")])
+
+(define_insn "subhi3"
+ [(set (match_operand:HI 0 "register_operand" "=r,d")
+ (minus:HI (match_operand:HI 1 "register_operand" "0,0")
+ (match_operand:HI 2 "nonmemory_operand" "r,i")))]
+ ""
+ "@
+ sub %A0,%A2\;sbc %B0,%B2
+ subi %A0,lo8(%2)\;sbci %B0,hi8(%2)"
+ [(set_attr "length" "2,2")
+ (set_attr "cc" "set_czn,set_czn")])
+
+(define_insn "subsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,d")
+ (minus:SI (match_operand:SI 1 "register_operand" "0,0")
+ (match_operand:SI 2 "nonmemory_operand" "r,i")))]
+ ""
+ "@
+ sub %0,%2\;sbc %B0,%B2\;sbc %C0,%C2\;sbc %D0,%D2
+ subi %A0,lo8(%2)\;sbci %B0,hi8(%2)\;sbci %C0,hlo8(%2)\;sbci %D0,hhi8(%2)"
+ [(set_attr "length" "4,4")
+ (set_attr "cc" "set_czn,set_czn")])
+
+;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+; and
+
+(define_insn "andqi3"
+ [(set (match_operand:QI 0 "register_operand" "=r,d")
+ (and:QI (match_operand:QI 1 "register_operand" "%0,0")
+ (match_operand:QI 2 "nonmemory_operand" "r,i")))]
+ ""
+ "@
+ and %0,%2
+ andi %0,lo8(%2)"
+ [(set_attr "length" "1,1")
+ (set_attr "cc" "set_zn,set_zn")])
+
+(define_insn "andhi3"
+ [(set (match_operand:HI 0 "register_operand" "=r,d,r")
+ (and:HI (match_operand:HI 1 "register_operand" "%0,0,0")
+ (match_operand:HI 2 "nonmemory_operand" "r,i,M")))
+ (clobber (match_scratch:QI 3 "=X,X,&d"))]
+ ""
+ "*{
+ if (which_alternative==0)
+ return (AS2 (and,%A0,%A2) CR_TAB
+ AS2 (and,%B0,%B2));
+ else if (which_alternative==1)
+ {
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ int mask = INTVAL (operands[2]);
+ if ((mask & 0xff) != 0xff)
+ output_asm_insn (AS2 (andi,%A0,lo8(%2)), operands);
+ if ((mask & 0xff00) != 0xff00)
+ output_asm_insn (AS2 (andi,%B0,hi8(%2)), operands);
+ return \"\";
+ }
+ return (AS2 (andi,%A0,lo8(%2)) CR_TAB
+ AS2 (andi,%B0,hi8(%2)));
+ }
+ return (AS2 (ldi,%3,lo8(%2)) CR_TAB
+ AS2 (and,%A0,%3) CR_TAB
+ AS1 (clr,%B0));
+}"
+ [(set_attr "length" "2,2,3")
+ (set_attr "cc" "set_n,clobber,clobber")])
+
+(define_insn "andsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,d")
+ (and:SI (match_operand:SI 1 "register_operand" "%0,0")
+ (match_operand:SI 2 "nonmemory_operand" "r,i")))]
+ ""
+ "*{
+ if (which_alternative==0)
+ return (AS2 (and, %0,%2) CR_TAB
+ AS2 (and, %B0,%B2) CR_TAB
+ AS2 (and, %C0,%C2) CR_TAB
+ AS2 (and, %D0,%D2));
+ else if (which_alternative==1)
+ {
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ HOST_WIDE_INT mask = INTVAL (operands[2]);
+ if ((mask & 0xff) != 0xff)
+ output_asm_insn (AS2 (andi,%A0,lo8(%2)), operands);
+ if ((mask & 0xff00) != 0xff00)
+ output_asm_insn (AS2 (andi,%B0,hi8(%2)), operands);
+ if ((mask & 0xff0000UL) != 0xff0000UL)
+ output_asm_insn (AS2 (andi,%C0,hlo8(%2)), operands);
+ if ((mask & 0xff000000UL) != 0xff000000UL)
+ output_asm_insn (AS2 (andi,%D0,hhi8(%2)), operands);
+ return \"\";
+ }
+ return (AS2 (andi, %A0,lo8(%2)) CR_TAB
+ AS2 (andi, %B0,hi8(%2)) CR_TAB
+ AS2 (andi, %C0,hlo8(%2)) CR_TAB
+ AS2 (andi, %D0,hhi8(%2)));
+ }
+}"
+ [(set_attr "length" "4,4")
+ (set_attr "cc" "set_n,set_n")])
+
+;;|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+;; ior
+
+(define_insn "iorqi3"
+ [(set (match_operand:QI 0 "register_operand" "=r,d")
+ (ior:QI (match_operand:QI 1 "register_operand" "%0,0")
+ (match_operand:QI 2 "nonmemory_operand" "r,i")))]
+ ""
+ "@
+ or %0,%2
+ ori %0,lo8(%2)"
+ [(set_attr "length" "1,1")
+ (set_attr "cc" "set_zn,set_zn")])
+
+(define_insn "iorhi3"
+ [(set (match_operand:HI 0 "register_operand" "=r,d")
+ (ior:HI (match_operand:HI 1 "register_operand" "%0,0")
+ (match_operand:HI 2 "nonmemory_operand" "r,i")))]
+ ""
+ "*{
+ if (which_alternative==0)
+ return (AS2 (or,%A0,%A2) CR_TAB
+ AS2 (or,%B0,%B2));
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ int mask = INTVAL (operands[2]);
+ if (mask & 0xff)
+ output_asm_insn (AS2 (ori,%A0,lo8(%2)), operands);
+ if (mask & 0xff00)
+ output_asm_insn (AS2 (ori,%B0,hi8(%2)), operands);
+ return \"\";
+ }
+ return (AS2 (ori,%0,lo8(%2)) CR_TAB
+ AS2 (ori,%B0,hi8(%2)));
+}"
+ [(set_attr "length" "2,2")
+ (set_attr "cc" "set_n,clobber")])
+
+(define_insn "*iorhi3_clobber"
+ [(set (match_operand:HI 0 "register_operand" "=r,r")
+ (ior:HI (match_operand:HI 1 "register_operand" "%0,0")
+ (match_operand:HI 2 "immediate_operand" "M,i")))
+ (clobber (match_scratch:QI 3 "=&d,&d"))]
+ ""
+ "@
+ ldi %3,lo8(%2)\;or %A0,%3
+ ldi %3,lo8(%2)\;or %A0,%3\;ldi %3,lo8(%2)\;or %B0,%3"
+ [(set_attr "length" "2,4")
+ (set_attr "cc" "clobber,set_n")])
+
+(define_insn "iorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,d")
+ (ior:SI (match_operand:SI 1 "register_operand" "%0,0")
+ (match_operand:SI 2 "nonmemory_operand" "r,i")))]
+ ""
+ "*{
+ if (which_alternative==0)
+ return (AS2 (or, %0,%2) CR_TAB
+ AS2 (or, %B0,%B2) CR_TAB
+ AS2 (or, %C0,%C2) CR_TAB
+ AS2 (or, %D0,%D2));
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ HOST_WIDE_INT mask = INTVAL (operands[2]);
+ if (mask & 0xff)
+ output_asm_insn (AS2 (ori,%A0,lo8(%2)), operands);
+ if (mask & 0xff00)
+ output_asm_insn (AS2 (ori,%B0,hi8(%2)), operands);
+ if (mask & 0xff0000UL)
+ output_asm_insn (AS2 (ori,%C0,hlo8(%2)), operands);
+ if (mask & 0xff000000UL)
+ output_asm_insn (AS2 (ori,%D0,hhi8(%2)), operands);
+ return \"\";
+ }
+ return (AS2 (ori, %A0,lo8(%2)) CR_TAB
+ AS2 (ori, %B0,hi8(%2)) CR_TAB
+ AS2 (ori, %C0,hlo8(%2)) CR_TAB
+ AS2 (ori, %D0,hhi8(%2)));
+}"
+ [(set_attr "length" "4,4")
+ (set_attr "cc" "set_n,clobber")])
+
+(define_insn "*iorsi3_clobber"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (ior:SI (match_operand:SI 1 "register_operand" "%0,0")
+ (match_operand:SI 2 "immediate_operand" "M,i")))
+ (clobber (match_scratch:QI 3 "=&d,&d"))]
+ ""
+ "@
+ ldi %3,lo8(%2)\;or %A0,%3
+ ldi %3,lo8(%2)\;or %A0,%3\;ldi %3,hi8(%2)\;or %B0,%3\;ldi %3,hlo8(%2)\;or %C0,%3\;ldi %3,hhi8(%2)\;or %D0,%3"
+ [(set_attr "length" "2,8")
+ (set_attr "cc" "clobber,set_n")])
+
+;;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+;; xor
+
+(define_insn "xorqi3"
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (xor:QI (match_operand:QI 1 "register_operand" "%0")
+ (match_operand:QI 2 "register_operand" "r")))]
+ ""
+ "eor %0,%2"
+ [(set_attr "length" "1")
+ (set_attr "cc" "set_zn")])
+
+(define_insn "xorhi3"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (xor:HI (match_operand:HI 1 "register_operand" "%0")
+ (match_operand:HI 2 "register_operand" "r")))]
+ ""
+ "eor %0,%2\;eor %B0,%B2"
+ [(set_attr "length" "2")
+ (set_attr "cc" "set_n")])
+
+(define_insn "xorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (xor:SI (match_operand:SI 1 "register_operand" "%0")
+ (match_operand:SI 2 "register_operand" "r")))]
+ ""
+ "eor %0,%2
+ eor %B0,%B2
+ eor %C0,%C2
+ eor %D0,%D2"
+ [(set_attr "length" "4")
+ (set_attr "cc" "set_n")])
+
+;;<< << << << << << << << << << << << << << << << << << << << << << << << << <<
+;; arithmetic shift left
+
+(define_insn "ashlqi3"
+ [(set (match_operand:QI 0 "register_operand" "=r,!d,r,r")
+ (ashift:QI (match_operand:QI 1 "register_operand" "0,0,0,0")
+ (match_operand:QI 2 "general_operand" "r,i,i,Qm")))]
+ ""
+ "* return ashlqi3_out (insn, operands, NULL);"
+ [(set_attr "length" "6,4,6,7")
+ (set_attr "cc" "clobber,set_czn,set_czn,clobber")])
+
+(define_expand "ashlhi3"
+ [(parallel [(set (match_operand:HI 0 "register_operand" "")
+ (ashift:HI (match_operand:HI 1 "register_operand" "")
+ (match_operand:QI 2 "general_operand" "")))
+ (clobber (match_scratch:QI 3 ""))])]
+ ""
+ "")
+
+(define_insn "*ashlhi3_insn"
+ [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r")
+ (ashift:HI (match_operand:HI 1 "register_operand" "0,0,r,0,0,0")
+ (match_operand:QI 2 "general_operand" "r,P,O,K,i,Qm")))
+ (clobber (match_scratch:QI 3 "=X,X,X,X,&d,X"))]
+ ""
+ "* return ashlhi3_out (insn,operands, NULL);"
+ [(set_attr "length" "7,2,4,2,5,8")
+ (set_attr "cc" "clobber,clobber,clobber,clobber,clobber,clobber")])
+
+(define_expand "ashlsi3"
+ [(parallel [(set (match_operand:SI 0 "register_operand" "")
+ (ashift:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:QI 2 "general_operand" "")))
+ (clobber (match_scratch:QI 3 ""))])]
+ ""
+ "")
+
+(define_insn "*ashlsi3_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r")
+ (ashift:SI (match_operand:SI 1 "register_operand" "0,0,r,0,0")
+ (match_operand:QI 2 "general_operand" "r,P,O,i,Qm")))
+ (clobber (match_scratch:QI 3 "=X,X,X,&d,X"))]
+ ""
+ "* return ashlsi3_out (insn,operands, NULL);"
+ [(set_attr "length" "9,4,4,7,10")
+ (set_attr "cc" "clobber,clobber,clobber,clobber,clobber")])
+
+;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >>
+;; arithmetic shift right
+
+(define_expand "ashrqi3"
+ [(parallel [(set (match_operand:QI 0 "register_operand" "")
+ (ashiftrt:QI (match_operand:QI 1 "register_operand" "")
+ (match_operand:QI 2 "general_operand" "")))
+ (clobber (match_scratch:QI 3 ""))])]
+ ""
+ "")
+
+(define_insn "*ashrqi3"
+ [(set (match_operand:QI 0 "register_operand" "=r,r,r,r,r")
+ (ashiftrt:QI (match_operand:QI 1 "register_operand" "0,0,0,0,0")
+ (match_operand:QI 2 "general_operand" "r,P,K,i,Qm")))
+ (clobber (match_scratch:QI 3 "=X,X,X,&d,X"))]
+ ""
+ "* return ashrqi3_out (insn,operands, NULL);"
+ [(set_attr "length" "6,1,2,4,7")
+ (set_attr "cc" "clobber,clobber,clobber,clobber,clobber")])
+
+
+(define_expand "ashrhi3"
+ [(parallel [(set (match_operand:HI 0 "register_operand" "")
+ (ashiftrt:HI (match_operand:HI 1 "register_operand" "")
+ (match_operand:QI 2 "general_operand" "")))
+ (clobber (match_scratch:QI 3 ""))])]
+ ""
+ "")
+
+(define_insn "*ashrhi3_insn"
+ [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r")
+ (ashiftrt:HI (match_operand:HI 1 "register_operand" "0,0,0,r,0,0")
+ (match_operand:QI 2 "general_operand" "r,P,K,O,i,Qm")))
+ (clobber (match_scratch:QI 3 "=X,X,X,X,&d,X"))]
+ ""
+ "* return ashrhi3_out (insn,operands, NULL);"
+ [(set_attr "length" "7,2,4,2,5,8")
+ (set_attr "cc" "clobber,clobber,clobber,clobber,clobber,clobber")])
+
+(define_expand "ashrsi3"
+ [(parallel [(set (match_operand:SI 0 "register_operand" "")
+ (ashiftrt:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:QI 2 "general_operand" "")))
+ (clobber (match_scratch:QI 3 ""))])]
+ ""
+ "")
+
+(define_insn "*ashrsi3_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r")
+ (ashiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r,0,0")
+ (match_operand:QI 2 "general_operand" "r,P,O,i,Qm")))
+ (clobber (match_scratch:QI 3 "=X,X,X,&d,X"))]
+ ""
+ "* return ashrsi3_out (insn,operands, NULL);"
+ [(set_attr "length" "9,4,6,7,10")
+ (set_attr "cc" "clobber,clobber,clobber,clobber,clobber")])
+
+;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >>
+;; logical shift right
+
+(define_insn "lshrqi3"
+ [(set (match_operand:QI 0 "register_operand" "=r,d,r,r")
+ (lshiftrt:QI (match_operand:QI 1 "register_operand" "0,0,0,0")
+ (match_operand:QI 2 "general_operand" "r,i,i,Qm")))]
+ ""
+ "* return lshrqi3_out (insn,operands, NULL);"
+ [(set_attr "length" "6,4,6,7")
+ (set_attr "cc" "clobber,set_czn,set_czn,clobber")])
+
+(define_expand "lshrhi3"
+ [(parallel [(set (match_operand:HI 0 "register_operand" "")
+ (lshiftrt:HI (match_operand:HI 1 "register_operand" "")
+ (match_operand:QI 2 "general_operand" "")))
+ (clobber (match_scratch:QI 3 ""))])]
+ ""
+ "")
+
+(define_insn "*lshrhi3_insn"
+ [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r")
+ (lshiftrt:HI (match_operand:HI 1 "register_operand" "0,0,0,r,0,0")
+ (match_operand:QI 2 "general_operand" "r,P,K,O,i,Qm")))
+ (clobber (match_scratch:QI 3 "=X,X,X,X,&d,X"))]
+ ""
+ "* return lshrhi3_out (insn,operands, NULL);"
+ [(set_attr "length" "7,2,4,2,5,8")
+ (set_attr "cc" "clobber,clobber,clobber,clobber,clobber,clobber")])
+
+
+
+(define_expand "lshrsi3"
+ [(parallel [(set (match_operand:SI 0 "register_operand" "")
+ (lshiftrt:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:QI 2 "general_operand" "")))
+ (clobber (match_scratch:QI 3 ""))])]
+ ""
+ "")
+
+(define_insn "*lshrsi3_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r")
+ (lshiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r,0,0")
+ (match_operand:QI 2 "general_operand" "r,P,O,i,Qm")))
+ (clobber (match_scratch:QI 3 "=X,X,X,&d,X"))]
+ ""
+ "* return lshrsi3_out (insn,operands, NULL);"
+ [(set_attr "length" "9,4,4,7,10")
+ (set_attr "cc" "clobber,clobber,clobber,clobber,clobber")])
+
+;; abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x)
+;; abs
+
+(define_insn "absqi2"
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (abs:QI (match_operand:QI 1 "register_operand" "0")))]
+ ""
+ "sbrc %0,7\;neg %0"
+ [(set_attr "length" "2")
+ (set_attr "cc" "clobber")])
+
+
+(define_insn "abssf2"
+ [(set (match_operand:SF 0 "register_operand" "=d,r")
+ (abs:SF (match_operand:SF 1 "register_operand" "0,0")))]
+ ""
+ "@
+ andi %D0,0x7f
+ clt\;bld %D0,7"
+ [(set_attr "length" "1,2")
+ (set_attr "cc" "clobber,clobber")])
+
+;; 0 - x 0 - x 0 - x 0 - x 0 - x 0 - x 0 - x 0 - x 0 - x 0 - x 0 - x
+;; neg
+
+(define_insn "negqi2"
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (neg:QI (match_operand:QI 1 "register_operand" "0")))]
+ ""
+ "neg %0"
+ [(set_attr "length" "1")
+ (set_attr "cc" "set_zn")])
+
+(define_insn "neghi2"
+ [(set (match_operand:HI 0 "register_operand" "=!d,r")
+ (neg:HI (match_operand:HI 1 "register_operand" "0,0")))]
+ ""
+ "@
+ com %B0\;neg %A0\;sbci %B0,lo8(-1)
+ com %B0\;neg %A0\;sbc %B0,__zero_reg__\;inc %B0"
+ [(set_attr "length" "3,4")
+ (set_attr "cc" "set_czn,set_n")])
+
+(define_insn "negsi2"
+ [(set (match_operand:SI 0 "register_operand" "=!d,r")
+ (neg:SI (match_operand:SI 1 "register_operand" "0,0")))]
+ ""
+ "@
+ com %D0\;com %C0\;com %B0\;neg %A0\;sbci %B0,lo8(-1)\;sbci %C0,lo8(-1)\;sbci %D0,lo8(-1)
+ com %D0\;com %C0\;com %B0\;neg %A0\;brcs _PC_+8\;sec\;adc %B0,__zero_reg__\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__"
+ [(set_attr "length" "7,9")
+ (set_attr "cc" "set_czn,clobber")])
+
+;; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+;; not
+
+(define_insn "one_cmplqi2"
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (not:QI (match_operand:QI 1 "register_operand" "0")))]
+ ""
+ "com %0"
+ [(set_attr "length" "1")
+ (set_attr "cc" "set_czn")])
+
+(define_insn "one_cmplhi2"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (not:HI (match_operand:HI 1 "register_operand" "0")))]
+ ""
+ "com %0\;com %B0"
+ [(set_attr "length" "2")
+ (set_attr "cc" "set_n")])
+
+(define_insn "one_cmplsi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (not:SI (match_operand:SI 1 "register_operand" "0")))]
+ ""
+ "com %0\;com %B0\;com %C0\;com %D0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "set_n")])
+
+;; xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x
+;; sign extend
+
+(define_insn "extendqihi2"
+ [(set (match_operand:HI 0 "register_operand" "=r,r")
+ (sign_extend:HI (match_operand:QI 1 "register_operand" "0,*r")))]
+ ""
+ "@
+ clr %B0\;sbrc %0,7\;com %B0
+ mov %A0,%A1\;clr %B0\;sbrc %A0,7\;com %B0"
+ [(set_attr "length" "3,4")
+ (set_attr "cc" "set_n,set_n")])
+
+(define_insn "extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (sign_extend:SI (match_operand:QI 1 "register_operand" "0,*r")))]
+ ""
+ "@
+ clr %B0\;sbrc %A0,7\;com %B0\;mov %C0,%B0\;mov %D0,%B0
+ mov %A0,%A1\;clr %B0\;sbrc %A0,7\;com %B0\;mov %C0,%B0\;mov %D0,%B0"
+ [(set_attr "length" "5,6")
+ (set_attr "cc" "clobber,clobber")])
+
+(define_insn "extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "=r,&r")
+ (sign_extend:SI (match_operand:HI 1 "register_operand" "0,*r")))]
+ ""
+ "@
+ clr %C0\;sbrc %B0,7\;com %C0\;mov %D0,%C0
+ mov %A0,%A1\;mov %B0,%B1\;clr %C0\;sbrc %B0,7\;com %C0\;mov %D0,%C0"
+ [(set_attr "length" "4,6")
+ (set_attr "cc" "clobber,clobber")])
+
+;; xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x
+;; zero extend
+
+(define_insn "zero_extendqihi2"
+ [(set (match_operand:HI 0 "register_operand" "=r,r")
+ (zero_extend:HI (match_operand:QI 1 "register_operand" "0,*r")))]
+ ""
+ "@
+ clr %B0
+ mov %A0,%A1\;clr %B0"
+ [(set_attr "length" "1,2")
+ (set_attr "cc" "set_n,set_n")])
+
+(define_insn "zero_extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (zero_extend:SI (match_operand:QI 1 "register_operand" "0,*r")))]
+ ""
+ "@
+ clr %B0\;clr %C0\;clr %D0
+ mov %A0,%A1\;clr %B0\;clr %C0\;clr %D0"
+ [(set_attr "length" "3,4")
+ (set_attr "cc" "set_n,set_n")])
+
+(define_insn "zero_extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "=r,&r")
+ (zero_extend:SI (match_operand:HI 1 "register_operand" "0,*r")))]
+ ""
+ "@
+ clr %C0\;clr %D0
+ mov %A0,%A1\;mov %B0,%B1\;clr %C0\;clr %D0"
+ [(set_attr "length" "2,4")
+ (set_attr "cc" "set_n,set_n")])
+
+;;<=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=>
+;; compare
+
+(define_insn "tstqi"
+ [(set (cc0)
+ (match_operand:QI 0 "register_operand" "r"))]
+ ""
+ "tst %0"
+ [(set_attr "cc" "compare")
+ (set_attr "length" "1")])
+
+(define_insn "*negated_tstqi"
+ [(set (cc0)
+ (neg:QI (match_operand:QI 0 "register_operand" "r")))]
+ ""
+ "cp __zero_reg__,%0"
+ [(set_attr "cc" "compare")
+ (set_attr "length" "1")])
+
+(define_insn "tsthi"
+ [(set (cc0)
+ (match_operand:HI 0 "register_operand" "!w,r"))]
+ ""
+ "* return out_tsthi (insn,NULL);"
+[(set_attr "cc" "compare,compare")
+ (set_attr "length" "1,2")])
+
+(define_insn "*negated_tsthi"
+ [(set (cc0)
+ (neg:HI (match_operand:HI 0 "register_operand" "r")))]
+ ""
+ "cp __zero_reg__,%A0
+ cpc __zero_reg__,%B0"
+[(set_attr "cc" "compare")
+ (set_attr "length" "2")])
+
+(define_insn "tstsi"
+ [(set (cc0)
+ (match_operand:SI 0 "register_operand" "r"))]
+ ""
+ "* return out_tstsi (insn,NULL);"
+ [(set_attr "cc" "compare")
+ (set_attr "length" "4")])
+
+(define_insn "*negated_tstsi"
+ [(set (cc0)
+ (neg:SI (match_operand:SI 0 "register_operand" "r")))]
+ ""
+ "cp __zero_reg__,%A0
+ cpc __zero_reg__,%B0
+ cpc __zero_reg__,%C0
+ cpc __zero_reg__,%D0"
+ [(set_attr "cc" "compare")
+ (set_attr "length" "4")])
+
+
+(define_insn "cmpqi"
+ [(set (cc0)
+ (compare (match_operand:QI 0 "register_operand" "r,d")
+ (match_operand:QI 1 "nonmemory_operand" "r,i")))]
+ ""
+ "@
+ cp %0,%1
+ cpi %0,lo8(%1)"
+ [(set_attr "cc" "compare,compare")
+ (set_attr "length" "1,1")])
+
+(define_insn "*cmpqi_sign_extend"
+ [(set (cc0)
+ (compare (sign_extend:HI
+ (match_operand:QI 0 "register_operand" "d"))
+ (match_operand:HI 1 "immediate_operand" "M")))]
+ ""
+ "cpi %0,lo8(%1)"
+ [(set_attr "cc" "compare")
+ (set_attr "length" "1")])
+
+(define_insn "cmphi"
+ [(set (cc0)
+ (compare (match_operand:HI 0 "register_operand" "r,d,d,r,r")
+ (match_operand:HI 1 "nonmemory_operand" "r,M,i,M,i")))
+ (clobber (match_scratch:QI 2 "=X,X,&d,&d,&d"))]
+ ""
+ "*{
+ switch (which_alternative)
+ {
+ case 0:
+ return (AS2 (cp,%A0,%A1) CR_TAB
+ AS2 (cpc,%B0,%B1));
+ case 1:
+ if (reg_unused_after (insn, operands[0])
+ && INTVAL (operands[1]) >= 0 && INTVAL (operands[1]) <= 63
+ && TEST_HARD_REG_CLASS (ADDW_REGS, true_regnum (operands[0])))
+ return AS2 (sbiw,%0,%1);
+ else
+ return (AS2 (cpi,%0,%1) CR_TAB
+ AS2 (cpc,%B0,__zero_reg__));
+ case 2:
+ if (reg_unused_after (insn, operands[0]))
+ return (AS2 (subi,%0,lo8(%1)) CR_TAB
+ AS2 (sbci,%B0,hi8(%1)));
+ else
+ return (AS2 (ldi, %2,hi8(%1)) CR_TAB
+ AS2 (cpi, %A0,lo8(%1)) CR_TAB
+ AS2 (cpc, %B0,%2));
+ case 3:
+ return (AS2 (ldi, %2,lo8(%1)) CR_TAB
+ AS2 (cp, %A0,%2) CR_TAB
+ AS2 (cpc, %B0,__zero_reg__));
+
+ case 4:
+ return (AS2 (ldi, %2,lo8(%1)) CR_TAB
+ AS2 (cp, %A0,%2) CR_TAB
+ AS2 (ldi, %2,hi8(%1)) CR_TAB
+ AS2 (cpc, %B0,%2));
+ }
+}"
+ [(set_attr "cc" "compare,compare,compare,compare,compare")
+ (set_attr "length" "2,2,3,3,4")])
+
+
+(define_insn "cmpsi"
+ [(set (cc0)
+ (compare (match_operand:SI 0 "register_operand" "r,d,d,r,r")
+ (match_operand:SI 1 "nonmemory_operand" "r,M,i,M,i")))
+ (clobber (match_scratch:QI 2 "=X,X,&d,&d,&d"))]
+ ""
+ "*{
+ switch (which_alternative)
+ {
+ case 0:
+ return (AS2 (cp,%A0,%A1) CR_TAB
+ AS2 (cpc,%B0,%B1) CR_TAB
+ AS2 (cpc,%C0,%C1) CR_TAB
+ AS2 (cpc,%D0,%D1));
+ case 1:
+ if (reg_unused_after (insn, operands[0])
+ && INTVAL (operands[1]) >= 0 && INTVAL (operands[1]) <= 63
+ && TEST_HARD_REG_CLASS (ADDW_REGS, true_regnum (operands[0])))
+ return (AS2 (sbiw,%0,%1) CR_TAB
+ AS2 (cpc,%C0,__zero_reg__) CR_TAB
+ AS2 (cpc,%D0,__zero_reg__));
+ else
+ return (AS2 (cpi,%A0,lo8(%1)) CR_TAB
+ AS2 (cpc,%B0,__zero_reg__) CR_TAB
+ AS2 (cpc,%C0,__zero_reg__) CR_TAB
+ AS2 (cpc,%D0,__zero_reg__));
+ case 2:
+ if (reg_unused_after (insn, operands[0]))
+ return (AS2 (subi,%A0,lo8(%1)) CR_TAB
+ AS2 (sbci,%B0,hi8(%1)) CR_TAB
+ AS2 (sbci,%C0,hlo8(%1)) CR_TAB
+ AS2 (sbci,%D0,hhi8(%1)));
+ else
+ return (AS2 (cpi, %A0,lo8(%1)) CR_TAB
+ AS2 (ldi, %2,hi8(%1)) CR_TAB
+ AS2 (cpc, %B0,%2) CR_TAB
+ AS2 (ldi, %2,hlo8(%1)) CR_TAB
+ AS2 (cpc, %C0,%2) CR_TAB
+ AS2 (ldi, %2,hhi8(%1)) CR_TAB
+ AS2 (cpc, %D0,%2));
+ case 3:
+ return (AS2 (ldi,%2,lo8(%1)) CR_TAB
+ AS2 (cp,%A0,%2) CR_TAB
+ AS2 (cpc,%B0,__zero_reg__) CR_TAB
+ AS2 (cpc,%C0,__zero_reg__) CR_TAB
+ AS2 (cpc,%D0,__zero_reg__));
+ case 4:
+ return (AS2 (ldi, %2,lo8(%1)) CR_TAB
+ AS2 (cp, %A0,%2) CR_TAB
+ AS2 (ldi, %2,hi8(%1)) CR_TAB
+ AS2 (cpc, %B0,%2) CR_TAB
+ AS2 (ldi, %2,hlo8(%1)) CR_TAB
+ AS2 (cpc, %C0,%2) CR_TAB
+ AS2 (ldi, %2,hhi8(%1)) CR_TAB
+ AS2 (cpc, %D0,%2));
+ }
+}"
+ [(set_attr "cc" "compare,compare,compare,compare,compare")
+ (set_attr "length" "4,4,7,5,8")])
+
+;; ----------------------------------------------------------------------
+;; JUMP INSTRUCTIONS
+;; ----------------------------------------------------------------------
+;; Conditional jump instructions
+
+(define_expand "beq"
+ [(set (pc)
+ (if_then_else (eq (cc0) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "")
+
+(define_expand "bne"
+ [(set (pc)
+ (if_then_else (ne (cc0) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "")
+
+(define_expand "bge"
+ [(set (pc)
+ (if_then_else (ge (cc0) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "")
+
+(define_expand "bgeu"
+ [(set (pc)
+ (if_then_else (geu (cc0) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "")
+
+(define_expand "blt"
+ [(set (pc)
+ (if_then_else (lt (cc0) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "")
+
+(define_expand "bltu"
+ [(set (pc)
+ (if_then_else (ltu (cc0) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "")
+
+
+
+/****************************************************************
+ AVR not have following conditional jumps: LE,LEU,GT,GTU.
+ Convert them all to proper jumps.
+*****************************************************************/
+
+(define_expand "ble"
+ [(set (pc)
+ (if_then_else (le (cc0) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "")
+
+(define_expand "bleu"
+ [(set (pc)
+ (if_then_else (leu (cc0) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "")
+
+(define_expand "bgt"
+ [(set (pc)
+ (if_then_else (gt (cc0) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "")
+
+(define_expand "bgtu"
+ [(set (pc)
+ (if_then_else (gtu (cc0) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "")
+
+(define_insn "*sbrx_branch"
+ [(set (pc)
+ (if_then_else
+ (match_operator 0 "comparison_operator"
+ [(zero_extract
+ (match_operand:QI 1 "register_operand" "r")
+ (const_int 1)
+ (match_operand 2 "immediate_operand" "n"))
+ (const_int 0)])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))]
+ "(GET_CODE (operands[0]) == EQ || GET_CODE (operands[0]) == NE)"
+ "* {
+ int comp = ((get_attr_length (insn) == 4)
+ ? reverse_condition (GET_CODE (operands[0]))
+ : GET_CODE (operands[0]));
+ if (comp == EQ)
+ output_asm_insn (AS2 (sbrs,%1,%2), operands);
+ else
+ output_asm_insn (AS2 (sbrc,%1,%2), operands);
+ if (get_attr_length (insn) != 4)
+ return AS1 (rjmp,%3);
+ return (AS1 (rjmp,_PC_+4) CR_TAB
+ AS1 (jmp,%3));
+ }"
+ [(set (attr "length") (if_then_else (and (ge (minus (pc) (match_dup 3))
+ (const_int -2046))
+ (le (minus (pc) (match_dup 3))
+ (const_int 2046)))
+ (const_int 2)
+ (if_then_else (eq (symbol_ref "AVR_MEGA")
+ (const_int 0))
+ (const_int 2)
+ (const_int 4))))
+ (set_attr "cc" "clobber")])
+
+(define_insn "*sbrx_and_branchsi"
+ [(set (pc)
+ (if_then_else
+ (match_operator 0 "comparison_operator"
+ [(and:SI
+ (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "immediate_operand" "n"))
+ (const_int 0)])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))]
+ "(GET_CODE (operands[0]) == EQ || GET_CODE (operands[0]) == NE)
+ && mask_one_bit_p(INTVAL (operands[2]))"
+ "* {
+ int comp = ((get_attr_length (insn) == 4)
+ ? reverse_condition (GET_CODE (operands[0]))
+ : GET_CODE (operands[0]));
+ int bit = mask_one_bit_p(INTVAL (operands[2])) - 1;
+ static char buf[] = \"sbrc %A1,0\";
+ buf[3] = (comp == EQ ? 's' : 'c');
+ buf[6] = bit / 8 + 'A';
+ buf[9] = bit % 8 + '0';
+ output_asm_insn (buf, operands);
+
+ if (get_attr_length (insn) != 4)
+ return AS1 (rjmp,%3);
+ return (AS1 (rjmp,_PC_+4) CR_TAB
+ AS1 (jmp,%3));
+ }"
+ [(set (attr "length") (if_then_else (and (ge (minus (pc) (match_dup 3))
+ (const_int -2046))
+ (le (minus (pc) (match_dup 3))
+ (const_int 2046)))
+ (const_int 2)
+ (if_then_else (eq (symbol_ref "AVR_MEGA")
+ (const_int 0))
+ (const_int 2)
+ (const_int 4))))
+ (set_attr "cc" "clobber")])
+
+(define_insn "*sbrx_and_branchhi"
+ [(set (pc)
+ (if_then_else
+ (match_operator 0 "comparison_operator"
+ [(and:HI
+ (match_operand:HI 1 "register_operand" "r")
+ (match_operand:HI 2 "immediate_operand" "n"))
+ (const_int 0)])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))]
+ "(GET_CODE (operands[0]) == EQ || GET_CODE (operands[0]) == NE)
+ && mask_one_bit_p(INTVAL (operands[2]))"
+ "* {
+ int comp = ((get_attr_length (insn) == 4)
+ ? reverse_condition (GET_CODE (operands[0]))
+ : GET_CODE (operands[0]));
+ int bit = mask_one_bit_p(INTVAL (operands[2])) - 1;
+ static char buf[] = \"sbrc %A1,0\";
+ buf[3] = (comp == EQ ? 's' : 'c');
+ buf[6] = bit / 8 + 'A';
+ buf[9] = bit % 8 + '0';
+ output_asm_insn (buf, operands);
+
+ if (get_attr_length (insn) != 4)
+ return AS1 (rjmp,%3);
+ return (AS1 (rjmp,_PC_+4) CR_TAB
+ AS1 (jmp,%3));
+ }"
+ [(set (attr "length") (if_then_else (and (ge (minus (pc) (match_dup 3))
+ (const_int -2046))
+ (le (minus (pc) (match_dup 3))
+ (const_int 2046)))
+ (const_int 2)
+ (if_then_else (eq (symbol_ref "AVR_MEGA")
+ (const_int 0))
+ (const_int 2)
+ (const_int 4))))
+ (set_attr "cc" "clobber")])
+
+;; ************************************************************************
+;; Implementation of conditional jumps here.
+;; Compare with 0 (test) jumps
+;; ************************************************************************
+
+(define_insn "branch"
+ [(set (pc)
+ (if_then_else (match_operator 1 "comparison_operator"
+ [(cc0)
+ (const_int 0)])
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ "! (GET_CODE (operands[1]) == GT || GET_CODE (operands[1]) == GTU
+ || GET_CODE (operands[1]) == LE || GET_CODE (operands[1]) == LEU)"
+ "*
+ return ret_cond_branch (GET_CODE (operands[1]),
+ avr_jump_mode (operands[0],insn));"
+ [(set_attr "type" "branch")
+ (set_attr "cc" "clobber")])
+
+(define_insn "difficult_branch"
+ [(set (pc)
+ (if_then_else (match_operator 1 "comparison_operator"
+ [(cc0)
+ (const_int 0)])
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ "(GET_CODE (operands[1]) == GT || GET_CODE (operands[1]) == GTU
+ || GET_CODE (operands[1]) == LE || GET_CODE (operands[1]) == LEU)"
+ "*
+ return ret_cond_branch (GET_CODE (operands[1]),
+ avr_jump_mode (operands[0],insn));"
+ [(set_attr "type" "branch1")
+ (set_attr "cc" "clobber")])
+
+;; revers branch
+
+(define_insn "rvbranch"
+ [(set (pc)
+ (if_then_else (match_operator 1 "comparison_operator" [(cc0)
+ (const_int 0)])
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ "! (GET_CODE (operands[1]) == GT || GET_CODE (operands[1]) == GTU
+ || GET_CODE (operands[1]) == LE || GET_CODE (operands[1]) == LEU)"
+ "*
+ return ret_cond_branch (reverse_condition (GET_CODE (operands[1])),
+ avr_jump_mode (operands[0],insn));"
+ [(set_attr "type" "branch1")
+ (set_attr "cc" "clobber")])
+
+(define_insn "difficult_rvbranch"
+ [(set (pc)
+ (if_then_else (match_operator 1 "comparison_operator" [(cc0)
+ (const_int 0)])
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ "(GET_CODE (operands[1]) == GT || GET_CODE (operands[1]) == GTU
+ || GET_CODE (operands[1]) == LE || GET_CODE (operands[1]) == LEU)"
+ "*
+ return ret_cond_branch (reverse_condition (GET_CODE (operands[1])),
+ avr_jump_mode (operands[0],insn));"
+ [(set_attr "type" "branch")
+ (set_attr "cc" "clobber")])
+
+;; **************************************************************************
+;; Unconditional and other jump instructions.
+
+(define_insn "jump"
+ [(set (pc)
+ (label_ref (match_operand 0 "" "")))]
+ ""
+ "*{
+ if (AVR_MEGA && get_attr_length (insn) != 1)
+ return \"jmp %0\";
+ return \"rjmp %0\";
+}"
+ [(set (attr "length") (if_then_else (and (ge (minus (pc) (match_dup 0))
+ (const_int -2047))
+ (le (minus (pc) (match_dup 0))
+ (const_int 2047)))
+ (const_int 1)
+ (const_int 2)))
+ (set_attr "cc" "none")])
+
+;; call
+
+(define_expand "call"
+ [(call (match_operand:HI 0 "call_insn_operand" "")
+ (match_operand:HI 1 "general_operand" ""))]
+ ;; Operand 1 not used on the AVR.
+ ""
+ "")
+
+;; call value
+
+(define_expand "call_value"
+ [(set (match_operand 0 "register_operand" "")
+ (call (match_operand:HI 1 "call_insn_operand" "")
+ (match_operand:HI 2 "general_operand" "")))]
+ ;; Operand 2 not used on the AVR.
+ ""
+ "")
+
+(define_insn "call_insn"
+ [(call (mem:HI (match_operand:HI 0 "nonmemory_operand" "!z,*r,i"))
+ (match_operand:HI 1 "general_operand" "X,X,X"))]
+;; We don't need in saving Z register because r30,r31 is a call used registers
+ ;; Operand 1 not used on the AVR.
+ "(register_operand (operands[0], HImode) || CONSTANT_P (operands[0]))"
+ "*
+{
+ if (which_alternative==0)
+ return \"icall\";
+ else if (which_alternative==1)
+ return (AS2 (mov, r30,%A0) CR_TAB
+ AS2 (mov, r31,%B0) CR_TAB
+ \"icall\");
+ else if (!AVR_MEGA)
+ return AS1(rcall,%c0);
+ return AS1(call,%c0);
+}"
+ [(set_attr "cc" "clobber,clobber,clobber")
+ (set (attr "length")
+ (cond [(eq (symbol_ref "which_alternative") (const_int 0))
+ (const_int 1)
+ (eq (symbol_ref "which_alternative") (const_int 0))
+ (const_int 3)
+ (eq (symbol_ref "!AVR_MEGA")
+ (const_int 0))
+ (const_int 2)]
+ (const_int 1)))])
+
+(define_insn "call_value_insn"
+ [(set (match_operand 0 "register_operand" "=r,r,r")
+ (call (mem:HI (match_operand:HI 1 "nonmemory_operand" "!z,*r,i"))
+;; We don't need in saving Z register because r30,r31 is a call used registers
+ (match_operand:HI 2 "general_operand" "X,X,X")))]
+ ;; Operand 2 not used on the AVR.
+ "(register_operand (operands[0], VOIDmode) || CONSTANT_P (operands[0]))"
+ "*
+{
+ if (which_alternative==0)
+ return \"icall\";
+ else if (which_alternative==1)
+ return (AS2 (mov, r30,%A1) CR_TAB
+ AS2 (mov, r31,%B1) CR_TAB
+ \"icall\");
+ else if (!AVR_MEGA)
+ return AS1(rcall,%c1);
+ return AS1(call,%c1);
+}"
+ [(set_attr "cc" "clobber,clobber,clobber")
+ (set (attr "length")
+ (cond [(eq (symbol_ref "which_alternative") (const_int 0))
+ (const_int 1)
+ (eq (symbol_ref "which_alternative") (const_int 0))
+ (const_int 3)
+ (eq (symbol_ref "!AVR_MEGA")
+ (const_int 0))
+ (const_int 2)]
+ (const_int 1)))])
+
+(define_insn "nop"
+ [(const_int 0)]
+ ""
+ "nop"
+ [(set_attr "cc" "none")
+ (set_attr "length" "1")])
+
+; indirect jump
+(define_insn "indirect_jump"
+ [(set (pc) (match_operand:HI 0 "register_operand" "!z,*r"))]
+ ""
+ "@
+ ijmp
+ push %A0\;push %B0\;ret"
+ [(set_attr "length" "1,3")
+ (set_attr "cc" "none,none")])
+
+;; table jump
+(define_expand "tablejump"
+ [(parallel [(set (pc) (match_operand:HI 0 "register_operand" ""))
+ (use (label_ref (match_operand 1 "" "")))])]
+ "optimize"
+ "")
+
+(define_insn "*tablejump"
+ [(set (pc) (mem:HI
+ (plus:HI (match_operand:HI 0 "register_operand" "=&z")
+ (label_ref (match_operand 2 "" "")))))
+ (use (label_ref (match_operand 1 "" "")))]
+ ""
+ "subi r30,lo8(-(%2))
+ sbci r31,hi8(-(%2))
+ lpm
+ push r0
+ adiw r30,1
+ lpm
+ push r0
+ ret"
+ [(set_attr "length" "8")
+ (set_attr "cc" "clobber")])
+
+(define_expand "casesi"
+ [(set (match_dup 6)
+ (minus:HI (subreg:HI (match_operand:SI 0 "register_operand" "") 0)
+ (match_operand:HI 1 "register_operand" "")))
+ (parallel [(set (cc0)
+ (compare (match_dup 6)
+ (match_operand:HI 2 "register_operand" "")))
+ (clobber (match_scratch:QI 9 ""))])
+
+ (set (pc)
+ (if_then_else (gtu (cc0)
+ (const_int 0))
+ (label_ref (match_operand 4 "" ""))
+ (pc)))
+ (set (match_dup 6)
+ (plus:HI (match_dup 6)
+ (match_dup 6)))
+;; (set (match_dup 6)
+;; (plus:HI (match_dup 6) (label_ref (match_operand:HI 3 "" ""))))
+
+ (parallel [(set (pc) (mem:HI
+ (plus:HI (match_dup 6)
+ (label_ref (match_operand:HI 3 "" "")))))
+ (use (label_ref (match_dup 3)))])]
+ "!optimize"
+ "
+{
+ operands[6] = gen_reg_rtx (HImode);
+}")
+
+
+;; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+;; This instructin sets Z flag
+
+(define_insn "sez"
+ [(set (cc0) (const_int 0))]
+ ""
+ "sez"
+ [(set_attr "length" "1")
+ (set_attr "cc" "compare")])
+
+
+;; ************************* Peepholes ********************************
+
+(define_peephole
+ [(set (match_operand:SI 0 "register_operand" "")
+ (plus:SI (match_dup 0)
+ (const_int -1)))
+ (parallel
+ [(set (cc0)
+ (compare (match_dup 0)
+ (const_int -1)))
+ (clobber (match_operand:QI 1 "register_operand" ""))])
+ (set (pc)
+ (if_then_else (ne (cc0) (const_int 0))
+ (label_ref (match_operand 2 "" ""))
+ (pc)))]
+ "(true_regnum (operands[0]) >= LD_REGS
+ && true_regnum (operands[1]) >= LD_REGS)"
+ "*
+{
+ if (TEST_HARD_REG_CLASS (ADDW_REGS, true_regnum (operands[0])))
+ output_asm_insn (AS2 (sbiw,%0,1) CR_TAB
+ AS2 (sbc,%C0,__zero_reg__) CR_TAB
+ AS2 (sbc,%D0,__zero_reg__) \"\\n\", operands);
+ else
+ output_asm_insn (AS2 (subi,%A0,1) CR_TAB
+ AS2 (sbc,%B0,__zero_reg__) CR_TAB
+ AS2 (sbc,%C0,__zero_reg__) CR_TAB
+ AS2 (sbc,%D0,__zero_reg__) \"\\n\", operands);
+ switch (avr_jump_mode (operands[2],insn))
+ {
+ case 1:
+ return AS1 (brcc,%2);
+ case 2:
+ return (AS1 (brcs,_PC_+2) CR_TAB
+ AS1 (rjmp,%2));
+ }
+ return (AS1 (brcs,_PC_+4) CR_TAB
+ AS1 (jmp,%2));
+}")
+
+(define_peephole
+ [(set (match_operand:HI 0 "register_operand" "")
+ (plus:HI (match_dup 0)
+ (const_int -1)))
+ (parallel
+ [(set (cc0)
+ (compare (match_dup 0)
+ (const_int 65535)))
+ (clobber (match_operand:QI 1 "register_operand" ""))])
+ (set (pc)
+ (if_then_else (ne (cc0) (const_int 0))
+ (label_ref (match_operand 2 "" ""))
+ (pc)))]
+ "(true_regnum (operands[0]) >= LD_REGS
+ && true_regnum (operands[1]) >= LD_REGS)"
+ "*
+{
+ if (TEST_HARD_REG_CLASS (ADDW_REGS, true_regnum (operands[0])))
+ output_asm_insn (AS2 (sbiw,%0,1), operands);
+ else
+ output_asm_insn (AS2 (subi,%A0,1) CR_TAB
+ AS2 (sbc,%B0,__zero_reg__) \"\\n\", operands);
+ switch (avr_jump_mode (operands[2],insn))
+ {
+ case 1:
+ return AS1 (brcc,%2);
+ case 2:
+ return (AS1 (brcs,_PC_+2) CR_TAB
+ AS1 (rjmp,%2));
+ }
+ return (AS1 (brcs,_PC_+4) CR_TAB
+ AS1 (jmp,%2));
+}")
+
+(define_peephole
+ [(set (match_operand:QI 0 "register_operand" "")
+ (plus:QI (match_dup 0)
+ (const_int -1)))
+ (set (cc0)
+ (compare (match_dup 0)
+ (const_int -1)))
+ (set (pc)
+ (if_then_else (ne (cc0) (const_int 0))
+ (label_ref (match_operand 1 "" ""))
+ (pc)))]
+ "(true_regnum (operands[0]) >= LD_REGS)"
+ "*
+{
+ output_asm_insn (AS2 (subi,%A0,1), operands);
+ switch (avr_jump_mode (operands[1],insn))
+ {
+ case 1:
+ return AS1 (brcc,%1);
+ case 2:
+ return (AS1 (brcs,_PC_+2) CR_TAB
+ AS1 (rjmp,%1));
+ }
+ return (AS1 (brcs,_PC_+4) CR_TAB
+ AS1 (jmp,%1));
+}")
+
diff --git a/gcc/config/avr/libgcc.S b/gcc/config/avr/libgcc.S
new file mode 100644
index 00000000000..b0e91cc39fc
--- /dev/null
+++ b/gcc/config/avr/libgcc.S
@@ -0,0 +1,666 @@
+/* -*- Mode: Asm -*- */
+/* Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ Contributed by Denis Chertykov <denisc@overta.ru>
+
+This file is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file with other programs, and to distribute
+those programs without any restriction coming from the use of this
+file. (The General Public License restrictions do apply in other
+respects; for example, they cover modification of the file, and
+distribution when not linked into another program.)
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* As a special exception, if you link this library with other files,
+ some of which are compiled with GCC, to produce an executable,
+ this library does not by itself cause the resulting executable
+ to be covered by the GNU General Public License.
+ This exception does not however invalidate any other reasons why
+ the executable file might be covered by the GNU General Public License. */
+
+#define TEXT_SEG(x) .section .text.libgcc ; x
+#define GLOBAL(x) .global _##x
+#define FUNCTION(x) .func _##x
+#define LABEL(x) _##x##:
+#define ENDFUNC .endfunc
+
+#define __zero_reg__ r1
+#define __tmp_reg__ r0
+#define __SREG__ 0x3f
+#define __SP_H__ 0x3e
+#define __SP_L__ 0x3d
+
+/*******************************************************
+ Multiplication 8 x 8
+*******************************************************/
+#if defined (Lmulqi3)
+
+#define r_arg2 r25 /* multiplicand */
+#define r_arg1 r24 /* multiplier */
+#define r_res __tmp_reg__ /* result */
+
+TEXT_SEG(mulqi3)
+GLOBAL (mulqi3)
+FUNCTION (mulqi3)
+LABEL(mulqi3)
+
+GLOBAL (umulqi3)
+LABEL(umulqi3)
+ clr r_res ; clear result
+__mulqi3_loop:
+ sbrc r_arg1,0
+ add r_res,r_arg2
+ add r_arg2,r_arg2 ; shift multiplicand
+ breq __mulqi3_exit ; while multiplicand != 0
+ lsr r_arg1 ;
+ brne __mulqi3_loop ; exit if multiplier = 0
+__mulqi3_exit:
+ mov r_arg1,r_res ; result to return register
+ ret
+
+#undef r_arg2
+#undef r_arg1
+#undef r_res
+
+ENDFUNC
+#endif /* defined (Lmulqi3) */
+
+
+/*******************************************************
+ Multiplication 16 x 16
+*******************************************************/
+#if defined (Lmulhi3)
+#define r_arg1L r24 /* multiplier Low */
+#define r_arg1H r25 /* multiplier High */
+#define r_arg2L r22 /* multiplicand Low */
+#define r_arg2H r23 /* multiplicand High */
+#define r_resL r20 /* result Low */
+#define r_resH r21 /* result High */
+
+TEXT_SEG(mulhi3)
+GLOBAL (mulhi3)
+FUNCTION (mulhi3)
+LABEL(mulhi3)
+
+GLOBAL (umulhi3)
+LABEL(umulhi3)
+
+ clr r_resH ; clear result
+ clr r_resL ; clear result
+__mulhi3_loop:
+ sbrs r_arg1L,0
+ rjmp __mulhi3_skip1
+ add r_resL,r_arg2L ; result + multiplicand
+ adc r_resH,r_arg2H
+__mulhi3_skip1:
+ add r_arg2L,r_arg2L ; shift multiplicand
+ adc r_arg2H,r_arg2H
+
+ cpc r_arg2L,__zero_reg__
+ breq __mulhi3_exit ; while multiplicand != 0
+
+ lsr r_arg1H ; gets LSB of multiplier
+ ror r_arg1L
+ cpc r_arg1H,__zero_reg__
+ brne __mulhi3_loop ; exit if multiplier = 0
+__mulhi3_exit:
+ mov r_arg1H,r_resH ; result to return register
+ mov r_arg1L,r_resL
+ ret
+
+#undef r_arg1L
+#undef r_arg1H
+#undef r_arg2L
+#undef r_arg2H
+#undef r_resL
+#undef r_resH
+
+ENDFUNC
+#endif /* defined (Lmulhi3) */
+
+#if defined (Lmulsi3)
+/*******************************************************
+ Multiplication 32 x 32
+*******************************************************/
+#define r_arg1L r22 /* multiplier Low */
+#define r_arg1H r23
+#define r_arg1HL r24
+#define r_arg1HH r25 /* multiplier High */
+
+
+#define r_arg2L r18 /* multiplicand Low */
+#define r_arg2H r19
+#define r_arg2HL r20
+#define r_arg2HH r21 /* multiplicand High */
+
+#define r_resL r26 /* result Low */
+#define r_resH r27
+#define r_resHL r30
+#define r_resHH r31 /* result High */
+
+
+TEXT_SEG(mulsi3)
+GLOBAL (mulsi3)
+FUNCTION (mulsi3)
+LABEL(mulsi3)
+
+GLOBAL (umulsi3)
+LABEL(umulsi3)
+ clr r_resHH ; clear result
+ clr r_resHL ; clear result
+ clr r_resH ; clear result
+ clr r_resL ; clear result
+__mulsi3_loop:
+ sbrs r_arg1L,0
+ rjmp __mulsi3_skip1
+ add r_resL,r_arg2L ; result + multiplicand
+ adc r_resH,r_arg2H
+ adc r_resHL,r_arg2HL
+ adc r_resHH,r_arg2HH
+__mulsi3_skip1:
+ add r_arg2L,r_arg2L ; shift multiplicand
+ adc r_arg2H,r_arg2H
+ adc r_arg2HL,r_arg2HL
+ adc r_arg2HH,r_arg2HH
+
+ lsr r_arg1HH ; gets LSB of multiplier
+ ror r_arg1HL
+ ror r_arg1H
+ ror r_arg1L
+ brne __mulsi3_loop
+ sbiw r_arg1HL,0
+ cpc r_arg1H,r_arg1L
+ brne __mulsi3_loop ; exit if multiplier = 0
+__mulsi3_exit:
+ mov r_arg1HH,r_resHH ; result to return register
+ mov r_arg1HL,r_resHL
+ mov r_arg1H,r_resH
+ mov r_arg1L,r_resL
+ ret
+#undef r_arg1L
+#undef r_arg1H
+#undef r_arg1HL
+#undef r_arg1HH
+
+
+#undef r_arg2L
+#undef r_arg2H
+#undef r_arg2HL
+#undef r_arg2HH
+
+#undef r_resL
+#undef r_resH
+#undef r_resHL
+#undef r_resHH
+
+ENDFUNC
+#endif /* defined (Lmulsi3) */
+
+/*******************************************************
+ Division 8 / 8 => (result + remainder)
+*******************************************************/
+#define r_rem r26 /* remainder */
+#define r_arg1 r25 /* dividend */
+#define r_arg2 r24 /* divisor */
+#define r_cnt r27 /* loop count */
+
+#if defined (Lumodqi3)
+
+TEXT_SEG(divqi3)
+GLOBAL (umodqi3)
+FUNCTION (umodqi3)
+LABEL(umodqi3)
+ clt
+ rcall _udivqi3
+ mov r24,r_rem
+ ret
+ENDFUNC
+#endif /* defined (Lumodqi3) */
+
+#if defined (Ludivqi3)
+
+TEXT_SEG(divqi3)
+GLOBAL (udivqi3)
+FUNCTION (udivqi3)
+LABEL(udivqi3)
+ clr __tmp_reg__
+ rjmp _divqi_raw
+ENDFUNC
+#endif /* defined (Ludivqi3) */
+
+#if defined (Lmodqi3)
+
+TEXT_SEG (divqi3)
+GLOBAL (moqhi3)
+FUNCTION (moqhi3)
+LABEL (modqi3)
+ rcall _divqi3
+ mov r24,r_rem
+ ret
+ENDFUNC
+#endif /* defined (Lmodqi3) */
+
+#if defined (Ldivqi3)
+
+TEXT_SEG(divqi3)
+GLOBAL (divqi3)
+FUNCTION (divqi3)
+LABEL(divqi3)
+ bst r_arg1,7 ; store sign of divident
+ mov __tmp_reg__,r_arg1
+ eor __tmp_reg__,r_arg2; r0.7 is sign of result
+ sbrc r_arg1,7
+ neg r_arg1 ; divident negative : negate
+ sbrc r_arg2,7
+ neg r_arg2 ; divisor negative : negate
+GLOBAL (divqi_raw)
+LABEL (divqi_raw)
+ sub r_rem,r_rem ; clear remainder and carry
+ ldi r_cnt,9 ; init loop counter
+ rjmp __divqi3_ep ; jump to entry point
+__divqi3_loop:
+ rol r_rem ; shift dividend into remainder
+ cp r_rem,r_arg2 ; compare remainder & divisor
+ brcs __divqi3_ep ; remainder <= divisor
+ sub r_rem,r_arg2 ; restore remainder
+__divqi3_ep:
+ rol r_arg1 ; shift dividend (with CARRY)
+ dec r_cnt ; decrement loop counter
+ brne __divqi3_loop ; loop
+ com r_arg1 ; complement result
+ ; because C flag was complemented in loop
+ brtc __divqi3_1
+ neg r_rem ; correct remainder sign
+__divqi3_1:
+ sbrc __tmp_reg__,7
+ neg r_arg1 ; correct result sign
+__divqi3_exit:
+ mov r24,r_arg1 ; put result to return register
+ ret
+ENDFUNC
+#endif /* defined (Ldivqi3) */
+
+#undef r_rem
+#undef r_arg1
+#undef r_arg2
+#undef r_cnt
+
+
+/*******************************************************
+ Division 16 / 16 => (result + remainder)
+*******************************************************/
+#define r_remL r26 /* remainder Low */
+#define r_remH r27 /* remainder High */
+
+#define r_arg1L r24 /* dividend Low */
+#define r_arg1H r25 /* dividend High */
+
+#define r_arg2L r22 /* divisor Low */
+#define r_arg2H r23 /* divisor High */
+
+#define r_cnt r21 /* loop count */
+#if defined (Lumodhi3)
+
+TEXT_SEG (divhi3)
+GLOBAL (umodhi3)
+FUNCTION (umodhi3)
+LABEL (umodhi3)
+ clt
+ rcall _udivhi3
+GLOBAL (umodhi3_ret)
+LABEL (umodhi3_ret)
+ mov r24,r_remL
+ mov r25,r_remH
+ ret
+ENDFUNC
+#endif /* defined (Lumodhi3) */
+
+#if defined (Ludivhi3)
+
+TEXT_SEG (divhi3)
+GLOBAL (udivhi3)
+FUNCTION (udivhi3)
+LABEL (udivhi3)
+ clr __tmp_reg__
+ rjmp _divhi_raw
+ENDFUNC
+#endif /* defined (Ludivhi3) */
+
+#if defined (Lmodhi3)
+
+TEXT_SEG (divhi3)
+GLOBAL (modhi3)
+FUNCTION (modhi3)
+LABEL (modhi3)
+GLOBAL (div)
+LABEL (div)
+ rcall _divhi3
+ mov r22,r24 ; needed for div () function
+ mov r23,r25
+ rjmp _umodhi3_ret
+ENDFUNC
+#endif /* defined (Lmodhi3) */
+
+
+#if defined (Ldivhi3)
+
+TEXT_SEG (divhi3)
+GLOBAL (divhi3)
+FUNCTION (divhi3)
+LABEL (divhi3)
+ bst r_arg1H,7 ; store sign of divident
+ mov __tmp_reg__,r_arg1H
+ eor __tmp_reg__,r_arg2H ; r0.7 is sign of result
+ brtc __divhi3_skip1
+ com r_arg1H
+ neg r_arg1L ; divident negative : negate
+ sbci r_arg1H,0xff
+__divhi3_skip1:
+ tst r_arg2H
+ brpl __divhi3_skip2
+ com r_arg2H
+ neg r_arg2L ; divisor negative : negate
+ sbci r_arg2H,0xff
+__divhi3_skip2:
+GLOBAL (divhi_raw)
+LABEL (divhi_raw)
+ sub r_remL,r_remL
+ sub r_remH,r_remH ; clear remainder and carry
+ ldi r_cnt,17 ; init loop counter
+ rjmp __divhi3_ep ; jump to entry point
+__divhi3_loop:
+ rol r_remL ; shift dividend into remainder
+ rol r_remH
+ cp r_remL,r_arg2L ; compare remainder & divisor
+ cpc r_remH,r_arg2H
+ brcs __divhi3_ep ; remainder < divisor
+ sub r_remL,r_arg2L ; restore remainder
+ sbc r_remH,r_arg2H
+__divhi3_ep:
+ rol r_arg1L ; shift dividend (with CARRY)
+ rol r_arg1H
+ dec r_cnt ; decrement loop counter
+ brne __divhi3_loop ; loop
+ brtc __divhi3_1
+ com r_remH
+ neg r_remL ; correct remainder sign
+ sbci r_remH,0xff
+__divhi3_1:
+ tst __tmp_reg__
+ brpl __divhi3_exit
+ adiw r_arg1L,1 ; correct result sign
+ ret
+__divhi3_exit:
+ com r_arg1L
+ com r_arg1H
+ ret
+ENDFUNC
+#endif /* defined (Ldivhi3) */
+
+#undef r_remH
+#undef r_remL
+
+#undef r_arg1H
+#undef r_arg1L
+
+#undef r_arg2H
+#undef r_arg2L
+
+#undef r_cnt
+
+/*******************************************************
+ Division 32 / 32 => (result + remainder)
+*******************************************************/
+#define r_remHH r31 /* remainder High */
+#define r_remHL r30
+#define r_remH r27
+#define r_remL r26 /* remainder Low */
+
+#define r_arg1HH r25 /* dividend High */
+#define r_arg1HL r24
+#define r_arg1H r23
+#define r_arg1L r22 /* dividend Low */
+
+#define r_arg2HH r21 /* divisor High */
+#define r_arg2HL r20
+#define r_arg2H r19
+#define r_arg2L r18 /* divisor Low */
+
+#define r_cnt r17 /* loop count */
+
+#if defined (Lumodsi3)
+
+TEXT_SEG(divsi3)
+GLOBAL (umodsi3)
+FUNCTION (umodsi3)
+LABEL(umodsi3)
+ clt
+ rcall _udivsi3
+GLOBAL (umodsi3_ret)
+LABEL (umodsi3_ret)
+ mov r25,r_remHH
+ mov r24,r_remHL
+ mov r23,r_remH
+ mov r22,r_remL
+GLOBAL (cleanup)
+LABEL (cleanup)
+ ret
+ENDFUNC
+#endif /* defined (Lumodsi3) */
+
+#if defined (Ludivsi3)
+
+TEXT_SEG(divsi3)
+GLOBAL (udivsi3)
+FUNCTION (udivsi3)
+LABEL(udivsi3)
+ clr __tmp_reg__
+ rjmp _divsi_raw
+ENDFUNC
+#endif /* defined (Ludivsi3) */
+
+#if defined (Lmodsi3)
+
+TEXT_SEG (divsi3)
+GLOBAL (modsi3)
+FUNCTION (modsi3)
+LABEL (modsi3)
+GLOBAL (ldiv)
+LABEL (ldiv)
+ rcall _divsi3
+ mov r18,r22 /* Needed for ldiv */
+ mov r19,r23
+ mov r20,r24
+ mov r21,r25
+ rjmp _umodsi3_ret
+ENDFUNC
+#endif /* defined (Lmodsi3) */
+
+#if defined (Ldivsi3)
+
+TEXT_SEG(divsi3)
+GLOBAL (divsi3)
+FUNCTION (divsi3)
+LABEL(divsi3)
+ bst r_arg1HH,7 ; store sign of divident
+ mov __tmp_reg__,r_arg1HH
+ eor __tmp_reg__,r_arg2HH ; r0.7 is sign of result
+ brtc __divsi3_skip1
+ com r_arg1HH
+ com r_arg1HL
+ com r_arg1H
+ neg r_arg1L ; divident negative : negate
+ sbci r_arg1H, 0xff
+ sbci r_arg1HL,0xff
+ sbci r_arg1HH,0xff
+__divsi3_skip1:
+ tst r_arg2HH
+ brpl __divsi3_skip2
+ com r_arg2HH
+ com r_arg2HL
+ com r_arg2H
+ neg r_arg2L ; divisor negative : negate
+ sbci r_arg2H, 0xff
+ sbci r_arg2HL,0xff
+ sbci r_arg2HH,0xff
+__divsi3_skip2:
+GLOBAL (divsi_raw)
+LABEL (divsi_raw)
+ push r_cnt
+ sub r_remL,r_remL
+ sub r_remH,r_remH
+ sub r_remHL,r_remHL
+ sub r_remHH,r_remHH ; clear remainder and carry
+ ldi r_cnt,33 ; init loop counter
+ rjmp __divsi3_ep ; jump to entry point
+__divsi3_loop:
+ rol r_remL ; shift dividend into remainder
+ rol r_remH
+ rol r_remHL
+ rol r_remHH
+ cp r_remL,r_arg2L ; compare remainder & divisor
+ cpc r_remH,r_arg2H
+ cpc r_remHL,r_arg2HL
+ cpc r_remHH,r_arg2HH
+ brcs __divsi3_ep ; remainder <= divisor
+ sub r_remL,r_arg2L ; restore remainder
+ sbc r_remH,r_arg2H
+ sbc r_remHL,r_arg2HL
+ sbc r_remHH,r_arg2HH
+__divsi3_ep:
+ rol r_arg1L ; shift dividend (with CARRY)
+ rol r_arg1H
+ rol r_arg1HL
+ rol r_arg1HH
+ dec r_cnt ; decrement loop counter
+ brne __divsi3_loop ; loop
+ pop r_cnt
+ brtc __divsi3_1
+ com r_remHH
+ com r_remHL
+ com r_remH
+ neg r_remL ; correct remainder sign
+ sbci r_remH, 0xff
+ sbci r_remHL,0xff
+ sbci r_remHH,0xff
+__divsi3_1:
+ rol __tmp_reg__
+ brcc __divsi3_exit
+ adc r_arg1L,__zero_reg__; correct result sign
+ adc r_arg1H,__zero_reg__
+ adc r_arg1HL,__zero_reg__
+ adc r_arg1HH,__zero_reg__
+ ret
+__divsi3_exit:
+ com r_arg1L
+ com r_arg1H
+ com r_arg1HL
+ com r_arg1HH
+ ret
+ENDFUNC
+#endif /* defined (Ldivsi3) */
+
+/**********************************
+ * This is a prologue subroutine
+ **********************************/
+#if defined (Lprologue)
+
+TEXT_SEG (_prologue_saves)
+GLOBAL (_prologue_saves__)
+FUNCTION (_prologue_saves__)
+LABEL (_prologue_saves__)
+ push r2
+ push r3
+ push r4
+ push r5
+ push r6
+ push r7
+ push r8
+ push r9
+ push r10
+ push r11
+ push r12
+ push r13
+ push r14
+ push r15
+ push r16
+ push r17
+ push r28
+ push r29
+ in r28,__SP_L__
+ in r29,__SP_H__
+ sbiw r26,0
+ breq _prologue_end
+ sub r28,r26
+ sbc r29,r27
+ in __tmp_reg__,__SREG__
+ cli
+ out __SP_L__,r28
+ out __SREG__,__tmp_reg__
+ out __SP_H__,r29
+_prologue_end:
+ ijmp
+ENDFUNC
+#endif /* defined (Lprologue) */
+
+/*
+ * This is a epilogue subroutine
+ */
+#if defined (Lepilogue)
+
+TEXT_SEG (_epilogue_restores)
+GLOBAL (_epilogue_restores__)
+FUNCTION (_epilogue_restores__)
+LABEL (_epilogue_restores__)
+ ldd r2,Y+18
+ ldd r3,Y+17
+ ldd r4,Y+16
+ ldd r5,Y+15
+ ldd r6,Y+14
+ ldd r7,Y+13
+ ldd r8,Y+12
+ ldd r9,Y+11
+ ldd r10,Y+10
+ ldd r11,Y+9
+ ldd r12,Y+8
+ ldd r13,Y+7
+ ldd r14,Y+6
+ ldd r15,Y+5
+ ldd r16,Y+4
+ ldd r17,Y+3
+ ldd r26,Y+2
+ ldd r27,Y+1
+ add r28,r30
+ adc r29,__zero_reg__
+ in __tmp_reg__,__SREG__
+ cli
+ out __SP_L__,r28
+ out __SREG__,__tmp_reg__
+ out __SP_H__,r29
+ mov r28,r26
+ mov r29,r27
+ ret
+#endif /* defined (Lepilogue) */
+
+#ifdef L__exit
+TEXT_SEG(exit)
+GLOBAL (exit)
+FUNCTION (exit)
+LABEL(exit)
+ rjmp _exit
+ENDFUNC
+#endif \ No newline at end of file
diff --git a/gcc/config/avr/t-avr b/gcc/config/avr/t-avr
new file mode 100644
index 00000000000..9f549f459cd
--- /dev/null
+++ b/gcc/config/avr/t-avr
@@ -0,0 +1,48 @@
+# Specific names for AVR tools
+AR_FOR_TARGET = avr-ar
+RANLIB_FOR_TARGET = avr-ranlib
+
+CROSS_LIBGCC1 = libgcc1-asm.a
+LIB1ASMSRC = avr/libgcc.S
+LIB1ASMFUNCS = \
+ mulqi3 \
+ mulhi3 \
+ mulsi3 \
+ umodqi3 \
+ udivqi3 \
+ modqi3 \
+ divqi3 \
+ umodhi3 \
+ udivhi3 \
+ modhi3 \
+ divhi3 \
+ umodsi3 \
+ udivsi3 \
+ modsi3 \
+ divsi3 \
+ prologue \
+ epilogue \
+ __exit
+
+# libgcc...
+LIBGCC1_TEST =
+
+# We do not have DF type
+TARGET_LIBGCC2_CFLAGS = -DDF=SF -Dinhibit_libc
+#LIBGCC2 = $(LIBGCC1)
+
+fp-bit.c: $(srcdir)/config/fp-bit.c $(srcdir)/config/avr/t-avr
+ echo '#define FLOAT' > fp-bit.c
+ echo '#define FLOAT_ONLY' >> fp-bit.c
+ echo '#define CMPtype QItype' >> fp-bit.c
+ echo '#define DF SF' >> fp-bit.c
+ echo '#define DI SI' >> fp-bit.c
+ echo '#define FLOAT_BIT_ORDER_MISMATCH' >> fp-bit.c
+ echo '#define SMALL_MACHINE' >> fp-bit.c
+ echo 'typedef int QItype __attribute__ ((mode (QI)));' >> fp-bit.c
+ cat $(srcdir)/config/fp-bit.c >> fp-bit.c
+
+FPBIT = fp-bit.c
+
+
+
diff --git a/gcc/config/avr/xm-avr.h b/gcc/config/avr/xm-avr.h
new file mode 100644
index 00000000000..af51cd3e6e8
--- /dev/null
+++ b/gcc/config/avr/xm-avr.h
@@ -0,0 +1 @@
+#include "tm.h"