aboutsummaryrefslogtreecommitdiff
path: root/2.95.3
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2005-05-21 06:16:34 +0000
committerMike Frysinger <vapier@gentoo.org>2005-05-21 06:16:34 +0000
commit91b1262b9570591b291c2a8fc20b4b6fc049f229 (patch)
treee4c24020a96a945daf86666244559e521cac26f9 /2.95.3
parentroll tarballs automagically (diff)
downloadgcc-patches-91b1262b9570591b291c2a8fc20b4b6fc049f229.tar.gz
gcc-patches-91b1262b9570591b291c2a8fc20b4b6fc049f229.tar.bz2
gcc-patches-91b1262b9570591b291c2a8fc20b4b6fc049f229.zip
import patches from crosstool/debian
Diffstat (limited to '2.95.3')
-rw-r--r--2.95.3/gentoo/10_all_new-atexit.patch (renamed from 2.95.3/gcc-2.95.3-new-atexit.diff)0
-rw-r--r--2.95.3/gentoo/10_alpha_new-atexit.patch (renamed from 2.95.3/gcc-2.95.3-alpha.diff)0
-rw-r--r--2.95.3/gentoo/11_all_gcc34compile.patch11
-rw-r--r--2.95.3/gentoo/12_all_dont-make-libdirs.patch18
-rw-r--r--2.95.3/gentoo/20_all_crosstool-arm-linux.patch647
-rw-r--r--2.95.3/gentoo/21_all_crosstool-backport-config.gcc-1.4.patch48
-rw-r--r--2.95.3/gentoo/21_all_crosstool-backport-config.gcc-1.92.patch71
-rw-r--r--2.95.3/gentoo/22_all_crosstool-gcc-2.95.3-trap-posix.patch44
-rw-r--r--2.95.3/gentoo/23_all_crosstool-gcc-pr3106.patch28
-rw-r--r--2.95.3/gentoo/40_all_debian-arm-const-double.patch41
-rw-r--r--2.95.3/gentoo/40_all_debian-arm-libgcc-umodsi3.patch84
-rw-r--r--2.95.3/gentoo/40_all_debian-arm-output-int.patch125
-rw-r--r--2.95.3/gentoo/40_all_debian-arm-profile.patch36
-rw-r--r--2.95.3/gentoo/41_all_debian-gcc-core-2.95.2-avr-1.1.patch13221
-rw-r--r--2.95.3/gentoo/42_all_debian-gcc-m68k-pic.patch62
-rw-r--r--2.95.3/gentoo/42_all_debian-m68k-md.patch56
-rw-r--r--2.95.3/gentoo/42_all_debian-m68k-reload.patch327
-rw-r--r--2.95.3/gentoo/43_all_debian-strength-red.patch278
18 files changed, 15097 insertions, 0 deletions
diff --git a/2.95.3/gcc-2.95.3-new-atexit.diff b/2.95.3/gentoo/10_all_new-atexit.patch
index 02f1756..02f1756 100644
--- a/2.95.3/gcc-2.95.3-new-atexit.diff
+++ b/2.95.3/gentoo/10_all_new-atexit.patch
diff --git a/2.95.3/gcc-2.95.3-alpha.diff b/2.95.3/gentoo/10_alpha_new-atexit.patch
index 1ea9e8d..1ea9e8d 100644
--- a/2.95.3/gcc-2.95.3-alpha.diff
+++ b/2.95.3/gentoo/10_alpha_new-atexit.patch
diff --git a/2.95.3/gentoo/11_all_gcc34compile.patch b/2.95.3/gentoo/11_all_gcc34compile.patch
new file mode 100644
index 0000000..2a23bb7
--- /dev/null
+++ b/2.95.3/gentoo/11_all_gcc34compile.patch
@@ -0,0 +1,11 @@
+--- gcc-2.95.3/gcc/f/com.h.orig 2005-03-14 02:03:50.000000000 -0800
++++ gcc-2.95.3/gcc/f/com.h 2005-03-14 02:04:01.000000000 -0800
+@@ -310,7 +310,7 @@ void ffecom_finish_decl (tree decl, tree
+ void ffecom_finish_progunit (void);
+ tree ffecom_get_invented_identifier (const char *pattern, const char *text,
+ int number);
+-ffeinfoKindtype ffecom_gfrt_basictype (ffecomGfrt ix);
++ffeinfoBasictype ffecom_gfrt_basictype (ffecomGfrt ix);
+ ffeinfoKindtype ffecom_gfrt_kindtype (ffecomGfrt ix);
+ void ffecom_init_0 (void);
+ void ffecom_init_2 (void);
diff --git a/2.95.3/gentoo/12_all_dont-make-libdirs.patch b/2.95.3/gentoo/12_all_dont-make-libdirs.patch
new file mode 100644
index 0000000..6f3a9c7
--- /dev/null
+++ b/2.95.3/gentoo/12_all_dont-make-libdirs.patch
@@ -0,0 +1,18 @@
+This will fail bad with sandbox.
+
+--- gcc/Makefile.in
++++ gcc/Makefile.in
+@@ -2179,13 +2179,6 @@
+ # exists.
+ # We deliberately use tooldir instead of gcc_tooldir here. gcc_tooldir
+ # won't work because libsubdir doesn't exist yet.
+- if [ "$(SYSTEM_HEADER_DIR)" = "$(tooldir)/sys-include" ] \
+- && [ -d $(tooldir)/sys-include ]; then \
+- if [ -d $(libdir) ] ; then true ; else mkdir $(libdir) ; fi; \
+- if [ -d $(libdir)/gcc-lib ] ; then true ; else mkdir $(libdir)/gcc-lib; fi; \
+- if [ -d $(libdir)/gcc-lib/$(target_alias) ] ; then true ; else mkdir $(libdir)/gcc-lib/$(target_alias) ; fi; \
+- if [ -d $(libdir)/gcc-lib/$(target_alias)/$(version) ] ; then true ; else mkdir $(libdir)/gcc-lib/$(target_alias)/$(version) ; fi; \
+- else true; fi
+
+ touch stmp-fixinc
+
diff --git a/2.95.3/gentoo/20_all_crosstool-arm-linux.patch b/2.95.3/gentoo/20_all_crosstool-arm-linux.patch
new file mode 100644
index 0000000..00974f6
--- /dev/null
+++ b/2.95.3/gentoo/20_all_crosstool-arm-linux.patch
@@ -0,0 +1,647 @@
+--------- snip -------
+Downloaded from ftp://ftp.linux.org.uk/pub/armlinux/toolchain/src-2.95.3/gcc-2.95.3.diff.bz2
+Not sure what it fixes, but this appears to be The Patch used with gcc-2.95.3 on arm.
+--------- snip -------
+
+diff -urN gcc-2.95.3-orig/gcc/config/arm/arm.c gcc-2.95.3/gcc/config/arm/arm.c
+--- gcc-2.95.3-orig/gcc/config/arm/arm.c Thu Jan 25 15:03:24 2001
++++ gcc-2.95.3/gcc/config/arm/arm.c Fri Jul 20 19:39:11 2001
+@@ -1529,27 +1529,34 @@
+ return gen_rtx_PLUS (Pmode, base, offset);
+ }
+ else if (GET_CODE (orig) == LABEL_REF)
+- current_function_uses_pic_offset_table = 1;
+-
+- return orig;
+-}
++ {
++ current_function_uses_pic_offset_table = 1;
+
+-static rtx pic_rtx;
++ if (NEED_PLT_GOT)
++ {
++ rtx pic_ref, address = gen_reg_rtx (Pmode);
++
++ emit_insn (gen_pic_load_addr (address, orig));
++ pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
++ address);
++ emit_move_insn (address, pic_ref);
++ return address;
++ }
++ }
+
+-int
+-is_pic(x)
+- rtx x;
+-{
+- if (x == pic_rtx)
+- return 1;
+- return 0;
++ return orig;
+ }
+
++/* Generate code to load the PIC register. PROLOGUE is true if
++ called from arm_expand_prologue (in which case we want the
++ generated insns at the start of the function); false if called
++ by an exception receiver that needs the PIC register reloaded
++ (in which case the insns are just dumped at the current location). */
+ void
+-arm_finalize_pic ()
++arm_finalize_pic (int prologue)
+ {
+ #ifndef AOF_ASSEMBLER
+- rtx l1, pic_tmp, pic_tmp2, seq;
++ rtx l1, pic_tmp, pic_tmp2, seq, pic_rtx;
+ rtx global_offset_table;
+
+ if (current_function_uses_pic_offset_table == 0)
+@@ -1578,7 +1585,10 @@
+
+ seq = gen_sequence ();
+ end_sequence ();
+- emit_insn_after (seq, get_insns ());
++ if (prologue)
++ emit_insn_after (seq, get_insns ());
++ else
++ emit_insn (seq);
+
+ /* Need to emit this whether or not we obey regdecls,
+ since setjmp/longjmp can cause life info to screw up. */
+@@ -5327,7 +5337,13 @@
+ if (frame_pointer_needed)
+ live_regs += 4;
+
+- if (live_regs)
++ if (live_regs == 1 && regs_ever_live[LR_REGNUM]
++ && ! lr_save_eliminated && ! really_return)
++ {
++ output_asm_insn (reverse ? "ldr%?%D0\t%|lr, [%|sp}, #4"
++ : "ldr%?%d0\t%|lr, [%|sp], #4", &operand);
++ }
++ else if (live_regs)
+ {
+ if (lr_save_eliminated || ! regs_ever_live[14])
+ live_regs++;
+@@ -5446,7 +5462,7 @@
+ rtx x;
+
+ length = strlen (name);
+- alignlength = (length + 1) + 3 & ~3;
++ alignlength = ((length + 1) + 3) & ~3;
+
+ ASM_OUTPUT_ASCII (stream, name, length + 1);
+ ASM_OUTPUT_ALIGN (stream, 2);
+@@ -5838,6 +5854,9 @@
+ int store_arg_regs = 0;
+ int volatile_func = (optimize > 0
+ && TREE_THIS_VOLATILE (current_function_decl));
++ rtx ip_rtx;
++ int fp_offset = 0;
++ rtx insn;
+
+ /* Naked functions don't have prologues. */
+ if (arm_naked_function_p (current_function_decl))
+@@ -5859,11 +5878,59 @@
+ live_regs_mask |= 0x4000;
+ }
+
++ ip_rtx = gen_rtx_REG (SImode, IP_REGNUM);
++
+ if (frame_pointer_needed)
+ {
++ if (current_function_needs_context)
++ {
++ /* The Static chain register is the same as the IP register
++ used as a scratch register during stack frame creation.
++ To get around this need to find somewhere to store IP
++ whilst the frame is being created. We try the following
++ places in order:
++
++ 1. An unused argument register.
++ 2. A slot on the stack above the frame. (This only
++ works if the function is not a varargs function).
++
++ If neither of these places is available, we abort (for now). */
++ if (regs_ever_live[3] == 0)
++ {
++ insn = gen_rtx_REG (SImode, 3);
++ insn = gen_rtx_SET (SImode, insn, ip_rtx);
++ insn = emit_insn (insn);
++ RTX_FRAME_RELATED_P (insn) = 1;
++ }
++ else if (current_function_pretend_args_size == 0)
++ {
++ insn = gen_rtx_PRE_DEC (SImode, stack_pointer_rtx);
++ insn = gen_rtx_MEM (SImode, insn);
++ insn = gen_rtx_SET (VOIDmode, insn, ip_rtx);
++ insn = emit_insn (insn);
++ RTX_FRAME_RELATED_P (insn) = 1;
++ fp_offset = 4;
++ }
++ else
++ /* FIXME - the way to handle this situation is to allow
++ the pretend args to be dumped onto the stack, then
++ reuse r3 to save IP. This would involve moving the
++ copying os SP into IP until after the pretend args
++ have been dumped, but this is not too hard. */
++ error ("Unable to find a temporary location for static chanin register");
++ }
++
+ live_regs_mask |= 0xD800;
+- emit_insn (gen_movsi (gen_rtx_REG (SImode, 12),
+- stack_pointer_rtx));
++ if (fp_offset)
++ {
++ insn = gen_rtx_PLUS (SImode, stack_pointer_rtx, GEN_INT (fp_offset));
++ insn = gen_rtx_SET (SImode, ip_rtx, insn);
++ }
++ else
++ insn = gen_movsi (ip_rtx, stack_pointer_rtx);
++
++ insn = emit_insn (insn);
++ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+
+ if (current_function_pretend_args_size)
+@@ -5927,9 +5994,31 @@
+ }
+
+ if (frame_pointer_needed)
+- emit_insn (gen_addsi3 (hard_frame_pointer_rtx, gen_rtx_REG (SImode, 12),
+- (GEN_INT
+- (-(4 + current_function_pretend_args_size)))));
++ {
++ insn = GEN_INT (-(4 + current_function_pretend_args_size + fp_offset));
++ insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx, ip_rtx, insn));
++ RTX_FRAME_RELATED_P (insn) = 1;
++
++ if (current_function_needs_context)
++ {
++ /* Recover the static chain register. */
++ if (regs_ever_live [3] == 0)
++ {
++ insn = gen_rtx_REG (SImode, 3);
++ insn = gen_rtx_SET (SImode, ip_rtx, insn);
++ insn = emit_insn (insn);
++ RTX_FRAME_RELATED_P (insn) = 1;
++ }
++ else /* if (current_function_pretend_args_size == 0) */
++ {
++ insn = gen_rtx_PLUS (SImode, hard_frame_pointer_rtx, GEN_INT (4));
++ insn = gen_rtx_MEM (SImode, insn);
++ insn = gen_rtx_SET (SImode, ip_rtx, insn);
++ insn = emit_insn (insn);
++ RTX_FRAME_RELATED_P (insn) = 1;
++ }
++ }
++ }
+
+ if (amount != const0_rtx)
+ {
+diff -urN gcc-2.95.3-orig/gcc/config/arm/arm.h gcc-2.95.3/gcc/config/arm/arm.h
+--- gcc-2.95.3-orig/gcc/config/arm/arm.h Thu Jan 25 15:03:26 2001
++++ gcc-2.95.3/gcc/config/arm/arm.h Fri Jul 20 19:39:11 2001
+@@ -601,14 +601,20 @@
+ (TREE_CODE (EXP) == STRING_CST \
+ && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
+
++#ifndef STRUCTURE_SIZE_BOUNDARY
+ /* Every structures size must be a multiple of 32 bits. */
+ /* This is for compatibility with ARMCC. ARM SDT Reference Manual
+ (ARM DUI 0020D) page 2-20 says "Structures are aligned on word
+ boundaries". */
+-#ifndef STRUCTURE_SIZE_BOUNDARY
+-#define STRUCTURE_SIZE_BOUNDARY 32
++/* Setting this to 32 produces more efficient code, but the value set in previous
++ versions of this toolchain was 8, which produces more compact structures. The
++ command line option -mstructure_size_boundary=<n> can be used to change this
++ value. */
++#define STRUCTURE_SIZE_BOUNDARY arm_structure_size_boundary
+ #endif
+
++extern int arm_structure_size_boundary;
++
+ /* Used when parsing command line option -mstructure_size_boundary. */
+ extern const char * structure_size_string;
+
+@@ -768,6 +774,9 @@
+ /* Specify the registers used for certain standard purposes.
+ The values of these macros are register numbers. */
+
++/* Register which holds return address from a subroutine call. */
++#define LR_REGNUM 14
++
+ /* Define this if the program counter is overloaded on a register. */
+ #define PC_REGNUM 15
+
+@@ -777,6 +786,9 @@
+ /* Base register for access to local variables of the function. */
+ #define FRAME_POINTER_REGNUM 25
+
++/* Scratch register - used in all kinds of places, eg trampolines. */
++#define IP_REGNUM 12
++
+ /* Define this to be where the real frame pointer is if it is not possible to
+ work out the offset between the frame pointer and the automatic variables
+ until after register allocation has taken place. FRAME_POINTER_REGNUM
+@@ -798,7 +810,7 @@
+ /* The native (Norcroft) Pascal compiler for the ARM passes the static chain
+ as an invisible last argument (possible since varargs don't exist in
+ Pascal), so the following is not true. */
+-#define STATIC_CHAIN_REGNUM 8
++#define STATIC_CHAIN_REGNUM 12
+
+ /* Register in which address to store a structure value
+ is passed to a function. */
+@@ -1248,7 +1260,12 @@
+ { \
+ int volatile_func = arm_volatile_func (); \
+ if ((FROM) == ARG_POINTER_REGNUM && (TO) == HARD_FRAME_POINTER_REGNUM)\
+- (OFFSET) = 0; \
++ { \
++ if (! current_function_needs_context || ! frame_pointer_needed) \
++ (OFFSET) = 0; \
++ else \
++ (OFFSET) = 4; \
++ } \
+ else if ((FROM) == FRAME_POINTER_REGNUM \
+ && (TO) == STACK_POINTER_REGNUM) \
+ (OFFSET) = (current_function_outgoing_args_size \
+@@ -1379,8 +1396,10 @@
+
+ On the ARM, allow any integer (invalid ones are removed later by insn
+ patterns), nice doubles and symbol_refs which refer to the function's
+- constant pool XXX. */
+-#define LEGITIMATE_CONSTANT_P(X) (! label_mentioned_p (X))
++ constant pool XXX.
++
++ When generating PIC code, allow anything. */
++#define LEGITIMATE_CONSTANT_P(X) (flag_pic || ! label_mentioned_p (X))
+
+ /* Symbols in the text segment can be accessed without indirecting via the
+ constant pool; it may take an extra binary operation, but this is still
+@@ -1496,9 +1515,8 @@
+ && INTVAL (op) <= 31) \
+ goto LABEL; \
+ } \
+- /* NASTY: Since this limits the addressing of unsigned byte loads */ \
+ range = ((MODE) == HImode || (MODE) == QImode) \
+- ? (arm_arch4 ? 256 : 4095) : 4096; \
++ ? (((MODE) == HImode && arm_arch4) ? 256 : 4095) : 4096; \
+ if (code == CONST_INT && INTVAL (INDEX) < range \
+ && INTVAL (INDEX) > -range) \
+ goto LABEL; \
+@@ -1812,14 +1830,15 @@
+ data addresses in memory. */
+ #define PIC_OFFSET_TABLE_REGNUM arm_pic_register
+
+-#define FINALIZE_PIC arm_finalize_pic ()
++#define FINALIZE_PIC arm_finalize_pic (1)
+
+-/* We can't directly access anything that contains a symbol,
++/* We can't directly access anything that contains a symbol or label,
+ nor can we indirect via the constant pool. */
+ #define LEGITIMATE_PIC_OPERAND_P(X) \
+- (! symbol_mentioned_p (X) \
++ (! symbol_mentioned_p (X) && ! label_mentioned_p (X) \
+ && (! CONSTANT_POOL_ADDRESS_P (X) \
+- || ! symbol_mentioned_p (get_pool_constant (X))))
++ || (! symbol_mentioned_p (get_pool_constant (X))) \
++ && (! label_mentioned_p (get_pool_constant (X)))))
+
+ /* We need to know when we are making a constant pool; this determines
+ whether data needs to be in the GOT or can be referenced via a GOT
+@@ -2046,17 +2065,9 @@
+ else output_addr_const(STREAM, X); \
+ }
+
+-/* Handles PIC addr specially */
+ #define OUTPUT_INT_ADDR_CONST(STREAM,X) \
+ { \
+- if (flag_pic && GET_CODE(X) == CONST && is_pic(X)) \
+- { \
+- output_addr_const(STREAM, XEXP (XEXP (XEXP (X, 0), 0), 0)); \
+- fputs(" - (", STREAM); \
+- output_addr_const(STREAM, XEXP (XEXP (XEXP (X, 0), 1), 0)); \
+- fputs(")", STREAM); \
+- } \
+- else output_addr_const(STREAM, X); \
++ output_addr_const(STREAM, X); \
+ \
+ /* Mark symbols as position independent. We only do this in the \
+ .text segment, not in the .data segment. */ \
+@@ -2170,8 +2181,7 @@
+ int arm_return_in_memory PROTO ((Tree));
+ int legitimate_pic_operand_p PROTO ((Rtx));
+ Rtx legitimize_pic_address PROTO ((Rtx, Mmode, Rtx));
+-int is_pic PROTO ((Rtx));
+-void arm_finalize_pic PROTO ((void));
++void arm_finalize_pic PROTO ((int));
+ int arm_rtx_costs RTX_CODE_PROTO ((Rtx, Rcode));
+ int arm_adjust_cost PROTO ((Rtx, Rtx, Rtx, int));
+ int const_double_rtx_ok_for_fpu PROTO ((Rtx));
+diff -urN gcc-2.95.3-orig/gcc/config/arm/arm.md gcc-2.95.3/gcc/config/arm/arm.md
+--- gcc-2.95.3-orig/gcc/config/arm/arm.md Thu Jan 25 15:03:27 2001
++++ gcc-2.95.3/gcc/config/arm/arm.md Fri Jul 20 19:39:11 2001
+@@ -2629,7 +2629,8 @@
+ : preserve_subexpressions_p ()));
+ DONE;
+ }
+- if (CONSTANT_P (operands[1]) && flag_pic)
++ if ((CONSTANT_P (operands[1]) || symbol_mentioned_p (operands[1])
++ || label_mentioned_p (operands[1])) && flag_pic)
+ operands[1] = legitimize_pic_address (operands[1], SImode,
+ ((reload_in_progress
+ || reload_completed)
+@@ -2721,6 +2722,15 @@
+ return \"add%?\\t%0, %|pc, %0\";
+ ")
+
++(define_expand "builtin_setjmp_receiver"
++ [(label_ref (match_operand 0 "" ""))]
++ "flag_pic"
++ "
++{
++ arm_finalize_pic (0);
++ DONE;
++}")
++
+ ;; If copying one reg to another we can set the condition codes according to
+ ;; its value. Such a move is common after a return from subroutine and the
+ ;; result is being tested against zero.
+@@ -6184,15 +6194,20 @@
+ abort ();
+ return \"\";
+ }
+- strcpy (pattern, \"stmfd\\t%m0!, {%1\");
+- for (i = 1; i < XVECLEN (operands[2], 0); i++)
++ if (XVECLEN (operands[2], 0) > 1)
+ {
+- strcat (pattern, \", %|\");
+- strcat (pattern, reg_names[REGNO (XEXP (XVECEXP (operands[2], 0, i),
++ strcpy (pattern, \"stmfd\\t%m0!, {%1\");
++ for (i = 1; i < XVECLEN (operands[2], 0); i++)
++ {
++ strcat (pattern, \", %|\");
++ strcat (pattern, reg_names[REGNO (XEXP (XVECEXP (operands[2], 0, i),
+ 0))]);
++ }
++ strcat (pattern, \"}\");
++ output_asm_insn (pattern, operands);
+ }
+- strcat (pattern, \"}\");
+- output_asm_insn (pattern, operands);
++ else
++ output_asm_insn (\"str\\t%1, [%m0, #-4]!\", operands);
+ return \"\";
+ }"
+ [(set_attr "type" "store4")])
+diff -urN gcc-2.95.3-orig/gcc/config/arm/elf.h gcc-2.95.3/gcc/config/arm/elf.h
+--- gcc-2.95.3-orig/gcc/config/arm/elf.h Mon May 31 10:21:53 1999
++++ gcc-2.95.3/gcc/config/arm/elf.h Fri Jul 20 19:39:11 2001
+@@ -167,15 +167,6 @@
+ #define MULTILIB_DEFAULTS { "mlittle-endian", "msoft-float", "mapcs-32", "mno-thumb-interwork" }
+ #endif
+
+-/* Setting this to 32 produces more efficient code, but the value set in previous
+- versions of this toolchain was 8, which produces more compact structures. The
+- command line option -mstructure_size_boundary=<n> can be used to change this
+- value. */
+-#undef STRUCTURE_SIZE_BOUNDARY
+-#define STRUCTURE_SIZE_BOUNDARY arm_structure_size_boundary
+-
+-extern int arm_structure_size_boundary;
+-
+ /* 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. */
+diff -urN gcc-2.95.3-orig/gcc/config/arm/linux-gas.h gcc-2.95.3/gcc/config/arm/linux-gas.h
+--- gcc-2.95.3-orig/gcc/config/arm/linux-gas.h Mon Feb 22 17:47:57 1999
++++ gcc-2.95.3/gcc/config/arm/linux-gas.h Fri Jul 20 19:39:11 2001
+@@ -1,6 +1,6 @@
+ /* Definitions of target machine for GNU compiler.
+ ARM Linux-based GNU systems version.
+- Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
++ Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+ Contributed by Russell King <rmk92@ecs.soton.ac.uk>.
+
+ This file is part of GNU CC.
+@@ -79,5 +79,7 @@
+ register unsigned long _beg __asm ("a1") = (unsigned long) (BEG); \
+ register unsigned long _end __asm ("a2") = (unsigned long) (END); \
+ register unsigned long _flg __asm ("a3") = 0; \
+- __asm __volatile ("swi 0x9f0002"); \
++ __asm __volatile ("swi 0x9f0002 @ sys_cacheflush" \
++ : "=r" (_beg) \
++ : "0" (_beg), "r" (_end), "r" (_flg)); \
+ }
+diff -urN gcc-2.95.3-orig/gcc/config/arm/t-linux gcc-2.95.3/gcc/config/arm/t-linux
+--- gcc-2.95.3-orig/gcc/config/arm/t-linux Fri Mar 26 16:30:20 1999
++++ gcc-2.95.3/gcc/config/arm/t-linux Fri Jul 20 20:46:19 2001
+@@ -1,6 +1,6 @@
+ # Just for these, we omit the frame pointer since it makes such a big
+ # difference. It is then pointless adding debugging.
+-TARGET_LIBGCC2_CFLAGS = -fomit-frame-pointer -fPIC
++TARGET_LIBGCC2_CFLAGS = -fomit-frame-pointer -fPIC
+ LIBGCC2_DEBUG_CFLAGS = -g0
+
+ # Don't build enquire
+diff -urN gcc-2.95.3-orig/gcc/final.c gcc-2.95.3/gcc/final.c
+--- gcc-2.95.3-orig/gcc/final.c Mon Mar 12 13:07:59 2001
++++ gcc-2.95.3/gcc/final.c Fri Jul 20 19:39:11 2001
+@@ -3652,8 +3652,9 @@
+
+ output_addr_const (file, XEXP (x, 0));
+ fprintf (file, "-");
+- if (GET_CODE (XEXP (x, 1)) == CONST_INT
+- && INTVAL (XEXP (x, 1)) < 0)
++ if ((GET_CODE (XEXP (x, 1)) == CONST_INT
++ && INTVAL (XEXP (x, 1)) < 0)
++ || GET_CODE (XEXP (x, 1)) != CONST_INT)
+ {
+ fprintf (file, ASM_OPEN_PAREN);
+ output_addr_const (file, XEXP (x, 1));
+diff -urN gcc-2.95.3-orig/gcc/function.c gcc-2.95.3/gcc/function.c
+--- gcc-2.95.3-orig/gcc/function.c Thu Jan 25 15:03:15 2001
++++ gcc-2.95.3/gcc/function.c Fri Jul 20 19:39:10 2001
+@@ -3053,6 +3053,105 @@
+ extracted by usage MEM with narrower mode. */
+ static rtx purge_addressof_replacements;
+
++/* Return 1 if X and Y are identical-looking rtx's.
++ This is the Lisp function EQUAL for rtx arguments. */
++
++int
++rtx_equal_for_addressof_p (x, y)
++ rtx x, y;
++{
++ register int i;
++ register int j;
++ register enum rtx_code code;
++ register char *fmt;
++
++ if (x == y)
++ return 1;
++ if (x == 0 || y == 0)
++ return 0;
++
++ code = GET_CODE (x);
++ /* Rtx's of different codes cannot be equal. */
++ if (code != GET_CODE (y))
++ return 0;
++
++ /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent.
++ (REG:SI x) and (REG:HI x) are NOT equivalent.
++ But (MEM:SI x) and (MEM:HI x) are equivalent for our purposes. */
++
++ if (code != MEM && (GET_MODE (x) != GET_MODE (y)))
++ return 0;
++
++ /* REG, LABEL_REF, and SYMBOL_REF can be compared nonrecursively. */
++
++ if (code == REG)
++ return REGNO (x) == REGNO (y);
++ else if (code == LABEL_REF)
++ return XEXP (x, 0) == XEXP (y, 0);
++ else if (code == SYMBOL_REF)
++ return XSTR (x, 0) == XSTR (y, 0);
++ else if (code == SCRATCH || code == CONST_DOUBLE)
++ return 0;
++
++ /* Compare the elements. If any pair of corresponding elements
++ fail to match, return 0 for the whole things. */
++
++ fmt = GET_RTX_FORMAT (code);
++ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
++ {
++ switch (fmt[i])
++ {
++ case 'w':
++ if (XWINT (x, i) != XWINT (y, i))
++ return 0;
++ break;
++
++ case 'n':
++ case 'i':
++ if (XINT (x, i) != XINT (y, i))
++ return 0;
++ break;
++
++ case 'V':
++ case 'E':
++ /* Two vectors must have the same length. */
++ if (XVECLEN (x, i) != XVECLEN (y, i))
++ return 0;
++
++ /* And the corresponding elements must match. */
++ for (j = 0; j < XVECLEN (x, i); j++)
++ if (rtx_equal_p (XVECEXP (x, i, j), XVECEXP (y, i, j)) == 0)
++ return 0;
++ break;
++
++ case 'e':
++ if (rtx_equal_p (XEXP (x, i), XEXP (y, i)) == 0)
++ return 0;
++ break;
++
++ case 'S':
++ case 's':
++ if (strcmp (XSTR (x, i), XSTR (y, i)))
++ return 0;
++ break;
++
++ case 'u':
++ /* These are just backpointers, so they don't matter. */
++ break;
++
++ case '0':
++ break;
++
++ /* It is believed that rtx's at this level will never
++ contain anything but integers and other rtx's,
++ except for within LABEL_REFs and SYMBOL_REFs. */
++ default:
++ abort ();
++ }
++ }
++ return 1;
++}
++
+ /* Helper function for purge_addressof. See if the rtx expression at *LOC
+ in INSN needs to be changed. If FORCE, always put any ADDRESSOFs into
+ the stack. */
+@@ -3133,7 +3232,7 @@
+ for (tem = purge_bitfield_addressof_replacements;
+ tem != NULL_RTX;
+ tem = XEXP (XEXP (tem, 1), 1))
+- if (rtx_equal_p (x, XEXP (tem, 0)))
++ if (rtx_equal_for_addressof_p (x, XEXP (tem, 0)))
+ {
+ *loc = XEXP (XEXP (tem, 1), 0);
+ return;
+@@ -3143,7 +3242,7 @@
+ for (tem = purge_addressof_replacements;
+ tem != NULL_RTX;
+ tem = XEXP (XEXP (tem, 1), 1))
+- if (rtx_equal_p (XEXP (x, 0), XEXP (tem, 0)))
++ if (rtx_equal_for_addressof_p (XEXP (x, 0), XEXP (tem, 0)))
+ {
+ rtx z = XEXP (XEXP (tem, 1), 0);
+
+diff -urN gcc-2.95.3-orig/gcc/jump.c gcc-2.95.3/gcc/jump.c
+--- gcc-2.95.3-orig/gcc/jump.c Thu Oct 21 08:24:03 1999
++++ gcc-2.95.3/gcc/jump.c Fri Jul 20 19:39:10 2001
+@@ -115,7 +115,7 @@
+ static rtx delete_unreferenced_labels PROTO((rtx));
+ static void delete_noop_moves PROTO((rtx));
+ static int calculate_can_reach_end PROTO((rtx, int, int));
+-static int duplicate_loop_exit_test PROTO((rtx));
++static int duplicate_loop_exit_test PROTO((rtx, int));
+ static void find_cross_jump PROTO((rtx, rtx, int, rtx *, rtx *));
+ static void do_cross_jump PROTO((rtx, rtx, rtx));
+ static int jump_back_p PROTO((rtx, rtx));
+@@ -338,7 +338,7 @@
+ && simplejump_p (temp1))
+ {
+ temp = PREV_INSN (insn);
+- if (duplicate_loop_exit_test (insn))
++ if (duplicate_loop_exit_test (insn, after_regscan))
+ {
+ changed = 1;
+ next = NEXT_INSN (temp);
+@@ -2548,8 +2548,9 @@
+ values of regno_first_uid and regno_last_uid. */
+
+ static int
+-duplicate_loop_exit_test (loop_start)
++duplicate_loop_exit_test (loop_start, after_regscan)
+ rtx loop_start;
++ int after_regscan;
+ {
+ rtx insn, set, reg, p, link;
+ rtx copy = 0, first_copy = 0;
+@@ -2662,6 +2663,9 @@
+ reg_map[REGNO (reg)] = gen_reg_rtx (GET_MODE (reg));
+ }
+ }
++
++ if (after_regscan)
++ reg_scan_update (exitcode, lastexit, max_reg);
+
+ /* Now copy each insn. */
+ for (insn = exitcode; insn != lastexit; insn = NEXT_INSN (insn))
+diff -urN gcc-2.95.3-orig/gcc/varasm.c gcc-2.95.3/gcc/varasm.c
+--- gcc-2.95.3-orig/gcc/varasm.c Mon Feb 19 15:02:02 2001
++++ gcc-2.95.3/gcc/varasm.c Fri Jul 20 19:39:11 2001
+@@ -3286,7 +3286,10 @@
+ value->un.addr.offset = - INTVAL (XEXP (x, 1));
+ }
+ else
+- abort ();
++ {
++ value->un.addr.base = x;
++ value->un.addr.offset = 0;
++ }
+ break;
+
+ default:
diff --git a/2.95.3/gentoo/21_all_crosstool-backport-config.gcc-1.4.patch b/2.95.3/gentoo/21_all_crosstool-backport-config.gcc-1.4.patch
new file mode 100644
index 0000000..b153f78
--- /dev/null
+++ b/2.95.3/gentoo/21_all_crosstool-backport-config.gcc-1.4.patch
@@ -0,0 +1,48 @@
+# Taken from http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/config.gcc.diff?r1=1.3&r2=1.4
+# Should fix error
+# Configuration powerpc-host_apple-darwin7.3.0 not supported
+# when configuring gcc-2.95 on Mac OS X for i686 target
+# Also create xm-darwin.h, seems to be required, else we get the error
+# In file included from .../gcc-2.95.3/gcc/gencheck.c:21:
+# hconfig.h:11:30: rs6000/xm-darwin.h: No such file or directory
+# make[1]: *** [gencheck.o] Error 1
+
+
+--- gcc-2.95.3/gcc/configure
++++ gcc-2.95.3/gcc/configure
+@@ -5079,6 +5079,10 @@
+ tmake_file=rs6000/t-beos
+ xmake_file=rs6000/x-beos
+ ;;
++ powerpc-*-darwin*)
++ xm_file="rs6000/xm-rs6000.h rs6000/xm-darwin.h"
++ xmake_file=rs6000/x-darwin
++ ;;
+ powerpc-*-sysv* | powerpc-*-elf*)
+ tm_file=rs6000/sysv4.h
+ xm_file="xm-siglist.h rs6000/xm-sysv4.h"
+--- /dev/null 2003-01-30 02:24:37.000000000 -0800
++++ gcc-3.0.4/gcc/config/rs6000/xm-darwin.h 2000-11-20 19:02:09.000000000 -0800
+@@ -0,0 +1,9 @@
++/* Undo the USG definition in xm-rs6000.h, Darwin is a BSD flavor. */
++
++#undef USG
++
++/* Override the usual setting, since Apple's GCC has lame bugs and
++ can't handle the initializers. Someday the bugs will be fixed and
++ we can get rid of this silliness. */
++
++#define HAVE_DESIGNATED_INITIALIZERS 0
+--- gcc-2.95.3/gcc/configure.in
++++ gcc-2.95.3/gcc/configure.in
+@@ -5079,6 +5079,10 @@
+ tmake_file=rs6000/t-beos
+ xmake_file=rs6000/x-beos
+ ;;
++ powerpc-*-darwin*)
++ xm_file="rs6000/xm-rs6000.h rs6000/xm-darwin.h"
++ xmake_file=rs6000/x-darwin
++ ;;
+ powerpc-*-sysv* | powerpc-*-elf*)
+ tm_file=rs6000/sysv4.h
+ xm_file="xm-siglist.h rs6000/xm-sysv4.h"
diff --git a/2.95.3/gentoo/21_all_crosstool-backport-config.gcc-1.92.patch b/2.95.3/gentoo/21_all_crosstool-backport-config.gcc-1.92.patch
new file mode 100644
index 0000000..42733cc
--- /dev/null
+++ b/2.95.3/gentoo/21_all_crosstool-backport-config.gcc-1.92.patch
@@ -0,0 +1,71 @@
+# Taken from http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/config.gcc.diff?r1=1.91&r2=1.92
+# Should fix error
+# Configuration x86_64-host_unknown-linux-gnu not supported
+# when configuring gcc-2.95 on x86_64 build for i686 target
+# It's a bit silly, since tm_file refers to files that don't exist,
+# but as long as x86_64 is just the build machine, that doesn't matter.
+
+--- gcc-2.95.3/gcc/configure
++++ gcc-2.95.3/gcc/configure
+@@ -2929,6 +2929,9 @@
+ i[34567]86-*-*)
+ cpu_type=i386
+ ;;
++ x86_64-*-*)
++ cpu_type=i386
++ ;;
+ hppa*-*-*)
+ cpu_type=pa
+ ;;
+@@ -3643,6 +3646,19 @@
+ thread_file='posix'
+ fi
+ ;;
++ x86_64-*-linux*)
++ xmake_file=x-linux
++ tm_file="i386/biarch64.h i386/i386.h i386/att.h linux.h i386/x86-64.h \
++ i386/linux64.h"
++ tmake_file="t-slibgcc-elf-ver t-linux i386/t-crtstuff"
++ extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
++ gnu_ld=yes
++ float_format=i386
++ if test x$enable_threads = xyes; then
++ thread_file='posix'
++ fi
++ ;;
++
+ i[34567]86-*-gnu*)
+ float_format=i386
+ ;;
+--- gcc-2.95.3/gcc/configure.in
++++ gcc-2.95.3/gcc/configure.in
+@@ -529,6 +529,9 @@
+ changequote([,])dnl
+ cpu_type=i386
+ ;;
++ x86_64-*-*)
++ cpu_type=i386
++ ;;
+ hppa*-*-*)
+ cpu_type=pa
+ ;;
+@@ -1643,6 +1646,19 @@
+ thread_file='posix'
+ fi
+ ;;
++ x86_64-*-linux*)
++ xmake_file=x-linux
++ tm_file="i386/biarch64.h i386/i386.h i386/att.h linux.h i386/x86-64.h \
++ i386/linux64.h"
++ tmake_file="t-slibgcc-elf-ver t-linux i386/t-crtstuff"
++ extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
++ gnu_ld=yes
++ float_format=i386
++ if test x$enable_threads = xyes; then
++ thread_file='posix'
++ fi
++ ;;
++
+ changequote(,)dnl
+ i[34567]86-*-gnu*)
+ float_format=i386
diff --git a/2.95.3/gentoo/22_all_crosstool-gcc-2.95.3-trap-posix.patch b/2.95.3/gentoo/22_all_crosstool-gcc-2.95.3-trap-posix.patch
new file mode 100644
index 0000000..1d18055
--- /dev/null
+++ b/2.95.3/gentoo/22_all_crosstool-gcc-2.95.3-trap-posix.patch
@@ -0,0 +1,44 @@
+#
+# Submitted-By: Marc Kleine-Budde <mkl@pengutronix.de>, 2005-04-20
+#
+# Error:
+#
+# creating libintl.h
+# Configuring etc...
+# loading cache ../config.cache
+# checking for a BSD compatible install... (cached) /usr/bin/install -c
+# creating ./config.status
+# creating Makefile
+# trap: usage: trap [-lp] [[arg] signal_spec ...]
+#
+# Description:
+#
+# non-posix conform usage of trap causes bash >= 3.0 to fail
+# e.g.: http://sourceware.org/ml/crossgcc/2004-12/msg00132.html
+#
+# Status:
+#
+# fixed in gcc >= 3.3.5
+# backport of gcc-3.3.5 fix
+#
+diff -ruN gcc-2.95.3-orig/configure gcc-2.95.3/configure
+--- gcc-2.95.3-orig/configure 1999-04-02 16:17:40.000000000 +0200
++++ gcc-2.95.3/configure 2005-04-20 18:25:45.030488235 +0200
+@@ -687,7 +687,7 @@
+ if test -f skip-this-dir; then
+ # Perform the same cleanup as the trap handler, minus the "exit 1" of course,
+ # and reset the trap handler.
+- trap 0
++ trap '' 0
+ rm -f Makefile* ${tmpfile}.com ${tmpfile}.tgt ${tmpfile}.hst ${tmpfile}.pos
+ # Execute the final clean-up actions
+ ${config_shell} skip-this-dir
+@@ -1599,7 +1599,7 @@
+ # Perform the same cleanup as the trap handler, minus the "exit 1" of course,
+ # and reset the trap handler.
+ rm -f ${tmpfile}.com ${tmpfile}.tgt ${tmpfile}.hst ${tmpfile}.pos
+-trap 0
++trap '' 0
+
+ exit 0
+
diff --git a/2.95.3/gentoo/23_all_crosstool-gcc-pr3106.patch b/2.95.3/gentoo/23_all_crosstool-gcc-pr3106.patch
new file mode 100644
index 0000000..0e077ea
--- /dev/null
+++ b/2.95.3/gentoo/23_all_crosstool-gcc-pr3106.patch
@@ -0,0 +1,28 @@
+See http://gcc.gnu.org/PR3106
+Backported from gcc-3.0.x
+
+Fixes error
+ .../binutils-2.11.2/libiberty/strerror.c:468: error: conflicting types for `sys_nerr'
+ /usr/include/stdio.h:258: error: previous declaration of `sys_nerr'
+ make[1]: *** [strerror.o] Error 1
+ make: *** [all-libiberty] Error 2
+on Mac OS X.
+
+--- gcc-2.95.3/libiberty/strerror.c.old 2004-03-24 16:23:19.000000000 -0800
++++ gcc-2.95.3/libiberty/strerror.c 2004-03-24 16:23:48.000000000 -0800
+@@ -13,6 +13,7 @@
+ incompatible with our later declaration, perhaps by using const
+ attributes. So we hide the declaration in errno.h (if any) using a
+ macro. */
++#define sys_nerr sys_nerr__
+ #define sys_errlist sys_errlist__
+ #endif
+
+@@ -20,6 +21,7 @@
+ #include <errno.h>
+
+ #ifdef HAVE_SYS_ERRLIST
++#undef sys_nerr
+ #undef sys_errlist
+ #endif
+
diff --git a/2.95.3/gentoo/40_all_debian-arm-const-double.patch b/2.95.3/gentoo/40_all_debian-arm-const-double.patch
new file mode 100644
index 0000000..57c2487
--- /dev/null
+++ b/2.95.3/gentoo/40_all_debian-arm-const-double.patch
@@ -0,0 +1,41 @@
+#! /bin/sh -e
+
+# DP: ARM patch for const_double, courtesy Richard Earnshaw
+
+src=gcc
+if [ $# -eq 3 -a "$2" = '-d' ]; then
+ pdir="-d $3"
+ src=$3/gcc
+elif [ $# -ne 1 ]; then
+ echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
+ exit 1
+fi
+case "$1" in
+ -patch)
+ patch $pdir -f --no-backup-if-mismatch -p1 --fuzz 10 < $0
+ cd $src && autoconf
+ ;;
+ -unpatch)
+ patch $pdir -f --no-backup-if-mismatch -R -p1 --fuzz 10 < $0
+ cd $src && autoconf
+ ;;
+ *)
+ echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
+ exit 1
+esac
+exit 0
+
+--- src/gcc/config/arm/arm.c.old Sun Jun 17 18:36:06 2001
++++ src/gcc/config/arm/arm.c Sun Jun 17 18:36:40 2001
+@@ -2416,6 +2416,11 @@
+ if (GET_CODE (x) == SYMBOL_REF)
+ return 1;
+
++ /* CONST_DOUBLE can contain a symbol ref for its in-memory
++ representation. We are not interested about that case here. */
++ if (GET_CODE (x) == CONST_DOUBLE)
++ return 0;
++
+ fmt = GET_RTX_FORMAT (GET_CODE (x));
+ for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+ {
diff --git a/2.95.3/gentoo/40_all_debian-arm-libgcc-umodsi3.patch b/2.95.3/gentoo/40_all_debian-arm-libgcc-umodsi3.patch
new file mode 100644
index 0000000..05b6ef9
--- /dev/null
+++ b/2.95.3/gentoo/40_all_debian-arm-libgcc-umodsi3.patch
@@ -0,0 +1,84 @@
+#! /bin/sh -e
+
+# DP: <your description>
+
+if [ $# -eq 3 -a "$2" = '-d' ]; then
+ pdir="-d $3"
+elif [ $# -ne 1 ]; then
+ echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
+ exit 1
+fi
+case "$1" in
+ -patch) patch $pdir -f --no-backup-if-mismatch -p0 < $0;;
+ -unpatch) patch $pdir -f --no-backup-if-mismatch -R -p0 < $0;;
+ *)
+ echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
+ exit 1
+esac
+exit 0
+
+From: Phil Blundell <pb@nexus.co.uk>
+To: 130394@bugs.debian.org, control@bugs.debian.org
+Cc: 130394-submitter@bugs.debian.org
+Subject: Bug#130394: [ARM] gcc misunhandle % with unsigned long operands
+Date: 15 Feb 2002 14:25:42 +0000
+
+reassign 130394 gcc-2.95
+severity 130394 important
+forwarded 130394 gcc-gnats@gcc.gnu.org
+tags 130394 + patch
+tags 130394 + upstream
+tags 130394 + fixed
+retitle 130394 [PR 5700] [ARM; fixed in 3.0] bug in __umodsi3
+thanks
+
+The reason this one didn't show up with a cross-compiler is that the bug
+is in the division support routine itself, rather than the compiler
+proper.
+
+I haven't tested it yet, but I suspect this patch may fix the problem.
+
+# DP: 2000-08-22 Nick Clifton <nickc@redhat.com>
+# DP:
+# DP: * config/arm/lib1funcs.asm (__umodsi3): Before performing any
+# DP: restorative additions, test for bottom bits of IP being set,
+# DP: rather than relying upon the RORs not matching.
+# DP: (__modsi3): Ditto.
+
+Index: lib1funcs.asm
+===================================================================
+RCS file: /cvs/gcc/gcc/gcc/config/arm/lib1funcs.asm,v
+retrieving revision 1.7
+diff -u -r1.7 lib1funcs.asm
+--- gcc/config/arm/lib1funcs.asm 1999/04/07 13:53:02 1.7
++++ gcc/config/arm/lib1funcs.asm 2002/02/15 14:17:36
+@@ -215,6 +215,13 @@
+ @ then none of the below will match, since the bit in ip will not be
+ @ in the bottom nibble.
+ ands overdone, overdone, #0xe0000000
++ @ If we terminated early, because dividend became zero, then the
++ @ bit in ip will not be in the bottom nibble, and we should not
++ @ perform the additions below. We must test for this though
++ @ (rather relying upon the TSTs to prevent the additions) since
++ @ the bit in ip could be in the top two bits which might then match
++ @ with one of the smaller RORs.
++ tstne ip, #0x7
+ RETc(eq) pc, lr @ No fixups needed
+ tst overdone, ip, ror #3
+ addne dividend, dividend, divisor, lsr #3
+@@ -397,6 +404,13 @@
+ @ then none of the below will match, since the bit in ip will not be
+ @ in the bottom nibble.
+ ands overdone, overdone, #0xe0000000
++ @ If we terminated early, because dividend became zero, then the
++ @ bit in ip will not be in the bottom nibble, and we should not
++ @ perform the additions below. We must test for this though
++ @ (rather relying upon the TSTs to prevent the additions) since
++ @ the bit in ip could be in the top two bits which might then match
++ @ with one of the smaller RORs.
++ tstne ip, #0x7
+ beq Lgot_result
+ tst overdone, ip, ror #3
+ addne dividend, dividend, divisor, lsr #3
+
+
diff --git a/2.95.3/gentoo/40_all_debian-arm-output-int.patch b/2.95.3/gentoo/40_all_debian-arm-output-int.patch
new file mode 100644
index 0000000..fba697d
--- /dev/null
+++ b/2.95.3/gentoo/40_all_debian-arm-output-int.patch
@@ -0,0 +1,125 @@
+#! /bin/sh -e
+
+# DP: ARM patch for large constant generation
+
+src=gcc
+if [ $# -eq 3 -a "$2" = '-d' ]; then
+ pdir="-d $3"
+ src=$3/gcc
+elif [ $# -ne 1 ]; then
+ echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
+ exit 1
+fi
+case "$1" in
+ -patch)
+ patch $pdir -f --no-backup-if-mismatch -p1 --fuzz 10 < $0
+ cd $src && autoconf
+ ;;
+ -unpatch)
+ patch $pdir -f --no-backup-if-mismatch -R -p1 --fuzz 10 < $0
+ cd $src && autoconf
+ ;;
+ *)
+ echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
+ exit 1
+esac
+exit 0
+
+--- src/gcc/config/arm/arm.c 2001/01/25 14:03:24 1.43.4.8
++++ src/gcc/config/arm/arm.c 2001/06/23 12:07:08
+@@ -722,6 +722,33 @@ arm_split_constant (code, mode, val, tar
+ return arm_gen_constant (code, mode, val, target, source, subtargets, 1);
+ }
+
++static int
++count_insns_for_constant (HOST_WIDE_INT remainder, int i)
++{
++ HOST_WIDE_INT temp1;
++ int num_insns = 0;
++ do
++ {
++ int end;
++
++ if (i <= 0)
++ i += 32;
++ if (remainder & (3 << (i - 2)))
++ {
++ end = i - 8;
++ if (end < 0)
++ end += 32;
++ temp1 = remainder & ((0x0ff << end)
++ | ((i < end) ? (0xff >> (32 - end)) : 0));
++ remainder &= ~temp1;
++ num_insns++;
++ i -= 6;
++ }
++ i -= 2;
++ } while (remainder);
++ return num_insns;
++}
++
+ /* As above, but extra parameter GENERATE which, if clear, suppresses
+ RTL generation. */
+ int
+@@ -1178,7 +1205,7 @@ arm_gen_constant (code, mode, val, targe
+ We start by looking for the largest block of zeros that are aligned on
+ a 2-bit boundary, we then fill up the temps, wrapping around to the
+ top of the word when we drop off the bottom.
+- In the worst case this code should produce no more than four insns. */
++ In the worst case this code should produce no more than four insns. */
+ {
+ int best_start = 0;
+ int best_consecutive_zeros = 0;
+@@ -1187,9 +1214,9 @@ arm_gen_constant (code, mode, val, targe
+ {
+ int consecutive_zeros = 0;
+
+- if (! (remainder & (3 << i)))
++ if (!(remainder & (3 << i)))
+ {
+- while ((i < 32) && ! (remainder & (3 << i)))
++ while ((i < 32) && !(remainder & (3 << i)))
+ {
+ consecutive_zeros += 2;
+ i += 2;
+@@ -1202,10 +1229,37 @@ arm_gen_constant (code, mode, val, targe
+ i -= 2;
+ }
+ }
++
++ /* So long as it won't require any more insns to do so, it's
++ desirable to emit a small constant (in bits 0...9) in the last
++ insn. This way there is more chance that it can be combined with
++ a later addressing insn to form a pre-indexed load or store
++ operation. Consider:
++
++ *((volatile int *)0xe0000100) = 1;
++ *((volatile int *)0xe0000110) = 2;
++
++ We want this to wind up as:
++
++ mov rA, #0xe0000000
++ mov rB, #1
++ str rB, [rA, #0x100]
++ mov rB, #2
++ str rB, [rA, #0x110]
++
++ rather than having to synthesize both large constants from scratch.
++
++ Therefore, we calculate how many insns would be required to emit
++ the constant starting from `best_start', and also starting from
++ zero (ie with bit 31 first to be output). If `best_start' doesn't
++ yield a shorter sequence, we may as well use zero. */
++ if (best_start != 0
++ && ((((unsigned HOST_WIDE_INT) 1) << best_start) < remainder)
++ && (count_insns_for_constant (remainder, 0) <=
++ count_insns_for_constant (remainder, best_start)))
++ best_start = 0;
+
+- /* Now start emitting the insns, starting with the one with the highest
+- bit set: we do this so that the smallest number will be emitted last;
+- this is more likely to be combinable with addressing insns. */
++ /* Now start emitting the insns. */
+ i = best_start;
+ do
+ {
diff --git a/2.95.3/gentoo/40_all_debian-arm-profile.patch b/2.95.3/gentoo/40_all_debian-arm-profile.patch
new file mode 100644
index 0000000..8994cd9
--- /dev/null
+++ b/2.95.3/gentoo/40_all_debian-arm-profile.patch
@@ -0,0 +1,36 @@
+#! /bin/sh -e
+
+# DP: ARM profiling fix
+
+if [ $# -eq 3 -a "$2" = '-d' ]; then
+ pdir="-d $3"
+elif [ $# -ne 1 ]; then
+ echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
+ exit 1
+fi
+case "$1" in
+ -patch) patch $pdir -f --no-backup-if-mismatch -p0 --fuzz 10 < $0;;
+ -unpatch) patch $pdir -f --no-backup-if-mismatch -R -p0 --fuzz 10 < $0;;
+ *)
+ echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
+ exit 1
+esac
+exit 0
+
+--- gcc/config/arm/linux-elf.h.old Tue Jul 30 23:19:59 2002
++++ gcc/config/arm/linux-elf.h Tue Jul 30 23:20:47 2002
+@@ -304,3 +304,14 @@
+ #undef FP_DEFAULT
+ #define FP_DEFAULT FP_SOFT3
+ #endif
++
++/* Call the function profiler with a given profile label. */
++#undef FUNCTION_PROFILER
++#define FUNCTION_PROFILER(STREAM, LABELNO) \
++{ \
++ fprintf (STREAM, "\tbl\tmcount%s\n", NEED_PLT_GOT ? "(PLT)" : ""); \
++}
++
++#undef CC1_SPEC
++#define CC1_SPEC "%{profile:-p}"
++
diff --git a/2.95.3/gentoo/41_all_debian-gcc-core-2.95.2-avr-1.1.patch b/2.95.3/gentoo/41_all_debian-gcc-core-2.95.2-avr-1.1.patch
new file mode 100644
index 0000000..5742b2a
--- /dev/null
+++ b/2.95.3/gentoo/41_all_debian-gcc-core-2.95.2-avr-1.1.patch
@@ -0,0 +1,13221 @@
+#! /bin/sh -e
+
+# DP: Some fixes for ARM from Philip Blundell
+# DP: put together by Hakan Ardo <hakan@debian.org>
+
+src=gcc
+if [ $# -eq 3 -a "$2" = '-d' ]; then
+ pdir="-d $3"
+ src=$3/gcc
+elif [ $# -ne 1 ]; then
+ echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
+ exit 1
+fi
+case "$1" in
+ -patch)
+ patch $pdir -f --no-backup-if-mismatch -p1 --fuzz 10 < $0
+ cd $src && autoconf
+ ;;
+ -unpatch)
+ patch $pdir -f --no-backup-if-mismatch -R -p1 --fuzz 10 < $0
+ cd $src && autoconf
+ ;;
+ *)
+ echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
+ exit 1
+esac
+exit 0
+
+diff -Nrc3p gcc-2.95.2.orig/gcc/config/avr/avr.c gcc-2.95.2/gcc/config/avr/avr.c
+*** gcc-2.95.2.orig/gcc/config/avr/avr.c Sat Dec 18 17:50:16 1999
+--- gcc-2.95.2/gcc/config/avr/avr.c Tue Dec 21 13:37:39 1999
+***************
+*** 0 ****
+--- 1,4147 ----
++ /* Subroutines for insn-output.c for ATMEL AVR micro controllers
++ Copyright (C) 1998, 1999 by Denis Chertykov (denisc@overta.ru)
++
++ 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.
++ */
++
++ #ifndef FILE
++ # include <stdio.h>
++ #endif
++ #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"
++
++
++ static int avr_naked_function_p PROTO ((tree));
++
++ /* Used for generate various comparison insn's */
++ struct rtx_def *avr_compare_op0, *avr_compare_op1;
++ struct rtx_def * (*avr_compare_gen)();
++
++ /* 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;
++
++ /* Flag: needed for the Uros Platise `ava' assembler syntax */
++ int make_it_public;
++
++ /* This holds the last insn address. */
++ static int last_insn_address = 0;
++
++ /* Commands in 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;
++
++ /* Ininial stack value specified by the `-minit-stack=' option */
++ const char *avr_ram_end = NULL;
++ static const char *initial_stack; /* numeric representation */
++
++ const char *avr_mcu_name = "at90s8515";
++
++ struct mcu_type_s *avr_mcu_type;
++
++ static struct mcu_type_s mcu_types[] =
++ {{"at90s2313","AT90S2313", 224-1, 0},
++ {"at90s2323","AT90S2323", 224-1, 0},
++ {"at90s2333","AT90S2333", 224-1, 0},
++ {"attiny22", "ATtiny22", 224-1, 0},
++ {"at90s2343","AT90S2343", 224-1, 0},
++ {"at90s4433","AT90S4433", 224-1, 0},
++ {"at90s4414","AT90S4414", 0x15f, 0},
++ {"at90s4434","AT90S4434", 0x15f, 0},
++ {"at90s8515","AT90S8515", 0x25f, 0},
++ {"at90s8535","AT90S8535", 0x25f, 0},
++ {"atmega603","ATmega603", 0x0fff,1}, /* XXX */
++ {"atmega103","ATmega103", 0x0fff,1}, /* XXX */
++ {NULL,0,0}};
++
++ void
++ avr_override_options ()
++ {
++ for (avr_mcu_type = mcu_types; avr_mcu_type->name; ++avr_mcu_type)
++ if (strcmp (avr_mcu_type->name, avr_mcu_name) == 0)
++ 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 ("");
++ }
++ /* flag_function_sections=1; */ /* always add `removable' to segment decl */
++ }
++
++ /* Initialize all variables */
++ void
++ avr_init_once ()
++ {
++ tmp_reg_rtx = gen_rtx (REG,QImode,TMP_REGNO);
++ zero_reg_rtx = gen_rtx (REG,QImode,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 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.
++ */
++ 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 from arg_pointer and frame_pointer */
++ int
++ initial_elimination_offset (from,to)
++ int from,to;
++ {
++ int reg;
++ int interrupt_func_p = interrupt_function_p (current_function_decl);
++ int signal_func_p = signal_function_p (current_function_decl);
++ int leaf_func_p = leaf_function_p ();
++ int main_p = ! strcmp ("main", current_function_name);
++ 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)
++ {
++ char stack_str[300];
++ sprintf (stack_str,
++ "%s - %d",
++ TARGET_INCLUDE ? "__INIT_STACK" : initial_stack,
++ size);
++
++ fprintf (file, ("\t"
++ AS2 (ldi, r28, lo8(%s)) CR_TAB
++ AS2 (ldi, r29, hi8(%s)) CR_TAB
++ AS2 (out,__SP_L__,r28) CR_TAB
++ AS2 (out,__SP_H__,r29) "\n"), stack_str, stack_str);
++ prologue_size += 4;
++ }
++ else if (minimize && (frame_pointer_needed || live_seq > 6))
++ {
++ char t[300];
++ sprintf (t, AS_STR ("CcC_%s_body",
++ ".L_%s_body"), current_function_name);
++ 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(%s)) CR_TAB
++ AS2 (ldi, r31, pm_hi8(%s))CR_TAB)
++ ,t,t);
++ 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, "%s:\n", t);
++ }
++ 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
++ )
++ {
++ #if 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';
++ }
++ else if ((reload_in_progress | reload_completed)
++ && frame_pointer_needed
++ && XEXP (x,0) == frame_pointer_rtx)
++ r = 'U';
++ #else
++ 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 (1/* (reload_in_progress | reload_completed) */
++ && frame_pointer_needed
++ && XEXP (x,0) == frame_pointer_rtx)
++ r = 'U';
++ #endif
++ }
++ 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 inline char *
++ ptrreg_to_str (int regno)
++ {
++ switch (regno)
++ {
++ case REG_X: return "X";
++ case REG_Y: return "Y";
++ case REG_Z: return "Z";
++ default:
++ fatal ("Internal compiler bug: register r%d can't be pointer\n", regno);
++ }
++ return NULL;
++ }
++
++ /*
++ Return the condition name as 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 ();
++ }
++ }
++
++
++ void
++ print_operand_address (file, addr)
++ FILE *file;
++ register 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))
++ {
++ if (TARGET_AVA)
++ {
++ fprintf (file, "(");
++ output_addr_const (file,addr);
++ fprintf (file ,")/2");
++ }
++ else
++ {
++ fprintf (file, "pm(");
++ output_addr_const (file,addr);
++ fprintf (file ,")");
++ }
++ }
++ else
++ output_addr_const (file, addr);
++ }
++ }
++
++ void
++ print_operand (file, x, code)
++ FILE *file;
++ rtx x;
++ int code;
++ {
++ int abcd = 0;
++
++ if (code >= 'A' && code <= 'D')
++ abcd = code - 'A';
++
++ if (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
++ output_address (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_address (x);
++ }
++
++ /* Recognise operand OP of mode MODE used in call instructions */
++ int
++ call_insn_operand (op, mode)
++ rtx op;
++ enum machine_mode mode;
++ {
++ 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 from the insn. */
++
++ void
++ notice_update_cc (body, insn)
++ rtx body;
++ 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;
++ }
++ }
++
++ int
++ class_max_nregs (class, mode)
++ enum reg_class class;
++ 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 AVR condition jump commands */
++ 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;
++ {
++ 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;
++ int num_operands;
++ {
++ rtx x;
++ 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 0 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 ? 0xffffffff : 0);
++ if (max && operator && GET_CODE (x) == CONST_INT)
++ {
++ if (unsigned_condition (operator) != operator)
++ max >>= 1;
++
++ if (max != (INTVAL (x) & max)
++ && INTVAL (x) != 0xff)
++ return 1;
++ }
++ return 0;
++ }
++
++ #define FROM_25_TO_8
++
++ #ifdef FROM_25_TO_8
++ # define FIRST_CUM_REG 26
++ #else
++ # define FIRST_CUM_REG 2
++ #endif
++
++ int
++ function_arg_regno_p(r)
++ int r;
++ {
++ #ifdef FROM_25_TO_8
++ return (r >= 8 && r <= 25);
++ #else
++ return (r >= 2 && r <= 19);
++ #endif
++ }
++
++ void
++ init_cumulative_args (cum, fntype, libname, indirect)
++ CUMULATIVE_ARGS *cum;
++ tree fntype;
++ char *libname;
++ int indirect;
++ {
++ #ifdef FROM_25_TO_8
++ cum->nregs = 18;
++ #else
++ cum->nregs = 18;
++ #endif
++ 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;
++ }
++ }
++
++ rtx
++ function_arg (cum, mode, type, named)
++ CUMULATIVE_ARGS *cum;
++ enum machine_mode mode;
++ tree type;
++ int named;
++ {
++ rtx ret = NULL_RTX;
++ int bytes = (mode == BLKmode ? int_size_in_bytes (type)
++ : GET_MODE_SIZE (mode));
++
++ if (cum->nregs && bytes <= cum->nregs)
++ ret = gen_rtx (REG, mode,
++ #ifdef FROM_25_TO_8
++ cum->regno - bytes
++ #else
++ cum->regno
++ #endif
++ );
++ return ret;
++ }
++
++ 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; /* whether or not the argument was named */
++ {
++ int bytes = (mode == BLKmode) ? int_size_in_bytes (type)
++ : GET_MODE_SIZE (mode);
++
++ cum->nregs -= bytes;
++ #ifdef FROM_25_TO_8
++ cum->regno -= bytes;
++ #else
++ cum->regno += bytes;
++ #endif
++
++ if (cum->nregs <= 0)
++ {
++ cum->nregs = 0;
++ cum->regno = FIRST_CUM_REG;
++ }
++
++ return;
++ }
++
++ /***********************************************************************
++ Functions for output various mov's for the 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()
++ {
++ return (current_function_calls_alloca
++ || current_function_args_info.nregs == 0
++ || current_function_varargs
++ || get_frame_size () > 0);
++ }
++
++ /*
++ Return 1 if 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;
++ }
++
++ 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);
++ }
++
++ 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__));
++ }
++
++
++
++ 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);
++ }
++ }
++
++
++ /* SHIFT LEFT (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 "";
++ }
++
++ 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 "";
++ }
++
++ 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 "";
++ }
++
++ /* Arithmetic SHIFT RIGHT ((signed)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 "";
++ }
++
++ 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 "";
++ }
++
++ 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 "";
++ }
++
++ /* LOGIC SHIFT RIGHT ((unsigned)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 "";
++ }
++
++ 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 "";
++ }
++
++ 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 "";
++ }
++
++ 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;
++ }
++
++
++ int
++ reg_unused_after (insn, reg)
++ rtx insn;
++ rtx reg;
++ {
++ return (0
++ /* In egcs 1.1.x dead_or_set_p do not properly after reload
++ #ifdef PRESERVE_DEATH_INFO_REGNO_P&&0
++ || 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;
++ }
++
++ static int bytes_count;
++ static int must_be_aligned=0;
++
++ void
++ asm_output_char(file,value)
++ FILE *file;
++ rtx value;
++ {
++ fprintf (file, AS_STR ("\tdc.b ",
++ "\t.byte "));
++ output_addr_const (file, value);
++ fprintf (file, "\n");
++ ++bytes_count;
++ }
++
++ void
++ asm_output_byte (file,value)
++ FILE *file;
++ char value;
++ {
++ fprintf (file, AS_STR ("\tdc.b 0x%x\n",
++ "\t.byte 0x%x\n"),value & 0xff);
++ ++bytes_count;
++ }
++
++ void
++ asm_output_short(file,value)
++ FILE *file;
++ rtx value;
++ {
++ if (SYMBOL_REF_FLAG (value) || GET_CODE (value) == LABEL_REF)
++ {
++ fprintf (file, AS_STR ("\tdc.w (",
++ "\t.word pm("));
++ output_addr_const (file, (value));
++ fprintf (file, AS_STR (") / 2\n",
++ ")\n"));
++ }
++ else
++ {
++ fprintf (file, AS_STR ("\tdc.w (",
++ "\t.word "));
++ output_addr_const (file, (value));
++ fprintf (file, AS_STR (") & 0xffff\n","\n"));
++ }
++ }
++
++ 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, AS_STR ("\tdc.l 0x%08lx\t//* %s */\n",
++ "\t.long 0x%08lx\t/* %s */\n"),val, dstr);
++ }
++
++
++ void
++ unique_section (decl, reloc)
++ tree decl;
++ int reloc;
++ {
++ 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 = AS_STR ("removable flash.code.f_",
++ ".text.");
++ else
++ prefix = AS_STR ("flash.code.f_",
++ ".text");
++ }
++ else
++ fatal ("Strange situation: unique section is not a FUNCTION_DECL");
++
++ if (!TARGET_AVA && !flag_function_sections)
++ name = "";
++
++ len = strlen (name) + strlen (prefix);
++ string = alloca (len + 1);
++ sprintf (string, "%s%s", prefix, name);
++ DECL_SECTION_NAME (decl) = build_string (len, string);
++ }
++
++ static void
++ output_align ()
++ {
++ if (TARGET_AVA)
++ {
++ fprintf (asm_out_file, "/* aligning segment */\n");
++ if (bytes_count & 1)
++ ASM_OUTPUT_BYTE (asm_out_file,0);
++ must_be_aligned=0;
++ }
++ }
++
++ char *
++ avr_change_section (sect_name)
++ char *sect_name;
++ {
++ if (must_be_aligned)
++ output_align();
++ return sect_name;
++ }
++
++ void
++ asm_output_section_name(file, decl, name, reloc)
++ FILE *file;
++ tree decl;
++ char *name;
++ int reloc;
++ {
++ if (must_be_aligned)
++ output_align();
++ fprintf (file, AS_STR ("\tseg %s\n",
++ ".section %s\n"), name);
++ if (TARGET_AVA && !strncmp (name,"flash",strlen ("flash")))
++ {
++ bytes_count = 0;
++ must_be_aligned=1;
++ }
++ }
++
++
++
++
++
++ /* 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). */
++
++ gas_output_limited_string(file, str)
++ FILE * file;
++ 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. */
++
++ 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) <= 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");
++ }
++
++ void
++ avr_output_ascii (file,p,size)
++ FILE *file;
++ char *p;
++ int size;
++ {
++ if (TARGET_AVA)
++ {
++ while (size--)
++ ASM_OUTPUT_BYTE (file, *p++);
++ }
++ else
++ gas_output_ascii (file, p, size);
++ }
++
++ int
++ 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");
++ }
++
++
++ enum reg_class
++ class_likely_spilled_p(int c)
++ {
++ return
++ #if 0
++ (c == BASE_POINTER_REGS
++ || c == POINTER_REGS
++ );
++ #else
++ (c != ALL_REGS
++ && c != ADDW_REGS
++ );
++ #endif
++ }
++
++ /*
++ Predicate function for memory address operand with displacement
++ */
++ int
++ displacement_operand (x,mode)
++ rtx x;
++ enum machine_mode mode;
++ {
++ return (GET_CODE (x) == CONST_INT
++ && INTVAL (x) >= 0
++ && INTVAL (x) <= 64 - GET_MODE_SIZE (mode));
++ }
++
++ /*
++ Only `progmem' attribute valid for type.
++ */
++ int
++ valid_machine_type_attribute(type, attributes, identifier, args)
++ tree type;
++ tree attributes;
++ tree identifier;
++ tree args;
++ {
++ 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;
++ tree attr;
++ tree args;
++ {
++ 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 */
++
++ 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;
++ }
++
++ void
++ encode_section_info (decl)
++ tree decl;
++ {
++ if (TREE_CODE (decl) == FUNCTION_DECL)
++ {
++ char *name, *string;
++ char *prefix = AS_STR ("flash.code.f_",
++ ".text");
++ int len;
++ SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
++ name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
++ /* Strip off any encoding in fnname. */
++ STRIP_NAME_ENCODING (name, name);
++
++ if (! flag_function_sections)
++ {
++ if (! TARGET_AVA)
++ name = "";
++ len = strlen (name) + strlen (prefix);
++ string = alloca (len + 1);
++ sprintf (string, "%s%s", prefix, name);
++
++ DECL_SECTION_NAME (decl) = build_string (len, string);
++ }
++ }
++ else if ((TREE_STATIC (decl) || DECL_EXTERNAL (decl))
++ && TREE_CODE (decl) == VAR_DECL
++ && avr_progmem_p (decl))
++ {
++ char * dsec = AS_STR ("flash.data",
++ ".progmem.data");
++ DECL_SECTION_NAME (decl) = build_string (strlen (dsec), dsec);
++ }
++ }
++
++
++ char *avr_bss_section_name;
++ char *avr_data_section_name;
++
++ char *
++ normalize_file_name (name)
++ char *name;
++ {
++ static char c[1000];
++ int i;
++ char *n = name + strlen(name);
++ c[999]=0;
++ i = 999;
++ while(n != name)
++ {
++ char tmp = *(--n);
++ if ((tmp >= 'a' && tmp <= 'z')
++ || (tmp >= 'A' && tmp <= 'Z')
++ || tmp == '_'
++ || (tmp >= '0' && tmp <= '9'))
++ {
++ c[--i]=tmp;
++ if (i==0)
++ break;
++ }
++ }
++ return &c[i];
++ }
++
++ extern char * main_input_filename;
++
++ static void
++ init_section_names ()
++ {
++ char *bss;
++ char *data;
++ char *file = normalize_file_name (main_input_filename);
++ if (TARGET_AVA)
++ {
++ /* AVA assembler version */
++ if (flag_function_sections)
++ {
++ bss = "\tseg removable eram.gcc_bss_section.AA";
++ data = "\tseg removable eram.gcc_data_section.AA";
++ }
++ else
++ {
++ bss = "\tseg eram.gcc_bss_section";
++ data = "\tseg eram.gcc_data_section";
++ }
++ }
++ else
++ {
++ /* GAS assembler version */
++ bss = ".section .bss";
++ data = ".section .data";
++ }
++
++
++
++ if (avr_bss_section_name)
++ free (avr_bss_section_name);
++ if (avr_data_section_name)
++ free (avr_data_section_name);
++
++ avr_bss_section_name = malloc (strlen (bss) + strlen (file) + 1);
++ avr_data_section_name = malloc (strlen (data) + strlen (file) + 1);
++
++ strcpy (avr_bss_section_name,bss);
++ strcpy (avr_data_section_name,data);
++
++ if (TARGET_AVA && flag_function_sections)
++ {
++ strcat (avr_bss_section_name,file);
++ strcat (avr_data_section_name,file);
++ }
++ }
++
++ void
++ asm_file_start (file)
++ FILE *file;
++ {
++ init_section_names ();
++ if (TARGET_AVA)
++ {
++ if (TARGET_INCLUDE)
++ fprintf (file,
++ "#include \"target.inc\"\n"
++ "#ifndef __AVR_ARCH_VER\n"
++ "#arch %s\n"
++ "#endif\n", avr_mcu_type->ava_name);
++ else
++ fprintf (file, "#arch %s\n", avr_mcu_type->ava_name);
++ fputs ("#define __SREG__ 0x3f\n"
++ "#define __SP_H__ 0x3e\n"
++ "#define __SP_L__ 0x3d\n", file);
++ }
++ else
++ {
++ /* GAS version */
++ 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);
++ }
++
++
++ if (TARGET_INCLUDE && TARGET_AVA)
++ fprintf (file,
++ "#ifndef __INIT_STACK\n"
++ "#define __INIT_STACK %s\n"
++ "#endif\n", initial_stack);
++
++ if (TARGET_AVA)
++ {
++ fputs ("#define lo8(x) ((x)&0xff)\n"
++ "#define hi8(x) (((x)>>8)&0xff)\n"
++ "#define hlo8(x) (((x)>>16)&0xff)\n"
++ "#define hhi8(x) (((x)>>24)&0xff)\n"
++ "#define pm(x) ((x)/2)\n"
++ "#define pm_lo8(x) lo8(pm(x))\n"
++ "#define pm_hi8(x) hi8(pm(x))\n"
++ "#define pm_hlo8(x) hlo8(pm(x))\n"
++ "#define pm_hhi8(x) hhi8(pm(x))\n"
++ "#define __tmp_reg__ r0\n"
++ "#define __zero_reg__ r1\n"
++ "#define _PC_ 0\n"
++ "\n"
++ "extern __prologue_saves__\n"
++ "extern __epilogue_restores__\n", file);
++ }
++ else
++ {
++ 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;
++ }
++
++ 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);
++ }
++
++ void
++ asm_output_external (file, decl, name)
++ FILE *file;
++ tree decl;
++ char *name;
++ {
++ if (TARGET_AVA && ! (decl && DECL_INLINE (decl)))
++ {
++ fputs ("extern ", file);
++ assemble_name (file, name);
++ fputs ("\n", file);
++ }
++ }
++
++ void
++ asm_output_external_libcall(file, symref)
++ FILE *file;
++ rtx symref;
++ {
++ if (TARGET_AVA)
++ fprintf (file, "extern _%s\n", XSTR (symref,0));
++ }
++
++ void
++ order_regs_for_local_alloc ()
++ {
++ unsigned int i;
++ int order_0[] = {
++ #ifdef FROM_25_TO_8
++ 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
++ #else
++ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
++ 24,25,
++ 16,17,18,19,20,21,22,23,
++ 28,29,30,31,26,27,
++ 32,33,34,35
++ #endif
++ };
++ 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 cost of memory address */
++ int
++ avr_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 2;
++ }
++
++
++ /*
++ My expirience with EXTRA_CONSTRAINT as recommended by Jeffrey A Law
++ Bad result!
++ */
++ 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;
++ }
++
++ /*
++ This function is my expirience with modifying of
++ function record_address_regs
++ */
++ enum reg_class
++ correct_address_class (x, class, scale)
++ rtx x;
++ enum reg_class class;
++ int scale;
++ {
++ if (class == BASE_REG_CLASS)
++ {
++ if (GET_CODE (x) == PLUS
++ && GET_CODE (XEXP (x,0)) == REG
++ && GET_CODE (XEXP (x,1)) == CONST_INT)
++ class = BASE_POINTER_REGS;
++ }
++ return class;
++ }
++
++ 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 ("Internal compiler bug. Wrong condition: %s",
++ GET_RTX_NAME (condition));
++ }
++ }
++
++ 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;
++ }
++ }
++ }
++ }
++ }
++
++ int
++ avr_ret_register ()
++ {
++ return 24;
++ }
++
++ rtx
++ avr_libcall_value (mode)
++ enum machine_mode mode;
++ {
++ int offs = GET_MODE_SIZE (mode);
++ if (offs < 2)
++ offs = 2;
++ return gen_rtx (REG, mode, RET_REGISTER + 2 - offs);
++ }
++
++ rtx
++ avr_function_value (type,func)
++ tree type;
++ tree func;
++ {
++ int offs;
++ if (TYPE_MODE (type) != BLKmode)
++ return avr_libcall_value (TYPE_MODE (type));
++
++ offs = int_size_in_bytes (type);
++ if (offs < 2)
++ offs = 2;
++ if (offs > 2 && offs < GET_MODE_SIZE (SImode))
++ offs = GET_MODE_SIZE (SImode);
++ else if (offs > GET_MODE_SIZE (SImode) && offs < GET_MODE_SIZE (DImode))
++ offs = GET_MODE_SIZE (DImode);
++
++ return gen_rtx (REG, BLKmode, RET_REGISTER + 2 - offs);
++ }
++
++ int
++ mask_one_bit_p (mask)
++ HOST_WIDE_INT mask;
++ {
++ int i;
++ unsigned HOST_WIDE_INT n=mask;
++ for (i = 0; i < 32; ++i)
++ {
++ if (n & 0x80000000UL)
++ {
++ if (n & 0x7fffffffUL)
++ return 0;
++ else
++ return 32-i;
++ }
++ n<<=1;
++ }
++ return 0;
++ }
++
++
++
++ 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;
++ }
++
++
++ enum reg_class
++ secondary_input_reload_class (class, mode, x)
++ enum reg_class class;
++ enum machine_mode mode;
++ rtx x;
++ {
++ if ((class == NO_LD_REGS || class == GENERAL_REGS)
++ && CONSTANT_P (x)
++ && ! (GET_CODE (x) == CONST_INT && INTVAL (x) == 0))
++ {
++ return SIMPLE_LD_REGS;
++ }
++ return NO_REGS;
++ }
++
++ char *
++ output_reload_insisf (insn, operands, which_alternative)
++ rtx insn;
++ rtx *operands;
++ int which_alternative;
++ {
++ int cnst = (GET_CODE (operands[1]) == CONST_INT);
++ if (cnst && ((INTVAL (operands[1]) & 0xff) == 0))
++ output_asm_insn (AS2 (mov, %A0, __zero_reg__), operands);
++ else
++ {
++ output_asm_insn (AS2 (ldi, %2, lo8(%1)), operands);
++ output_asm_insn (AS2 (mov, %A0, %2), operands);
++ }
++ if (cnst && ((INTVAL (operands[1]) & 0xff00) == 0))
++ output_asm_insn (AS2 (mov, %B0, __zero_reg__), operands);
++ else
++ {
++ output_asm_insn (AS2 (ldi, %2, hi8(%1)), operands);
++ output_asm_insn (AS2 (mov, %B0, %2), operands);
++ }
++ if (cnst && ((INTVAL (operands[1]) & 0xff0000) == 0))
++ output_asm_insn (AS2 (mov, %C0, __zero_reg__), operands);
++ else
++ {
++ output_asm_insn (AS2 (ldi, %2, hlo8(%1)), operands);
++ output_asm_insn (AS2 (mov, %C0, %2), operands);
++ }
++ if (cnst && ((INTVAL (operands[1]) & 0xff000000) == 0))
++ output_asm_insn (AS2 (mov, %D0, __zero_reg__), operands);
++ else
++ {
++ output_asm_insn (AS2 (ldi, %2, hhi8(%1)), operands);
++ output_asm_insn (AS2 (mov, %D0, %2), operands);
++ }
++ return "";
++ }
++
++ char *
++ output_reload_inhi (insn, operands, which_alternative)
++ rtx insn;
++ rtx *operands;
++ int which_alternative;
++ {
++ output_asm_insn (AS2 (ldi, %2, lo8(%1)), operands);
++ output_asm_insn (AS2 (mov, %A0, %2), operands);
++ if (! (GET_CODE (operands[1]) == CONST_INT
++ && ((INTVAL (operands[1]) & 0xff)
++ == ((INTVAL (operands[1]) & 0xffff) >> 8))))
++ output_asm_insn (AS2 (ldi, %2, hi8(%1)), operands);
++ output_asm_insn (AS2 (mov, %B0, %2), operands);
++ return "";
++ }
++
++ void
++ asm_globalize_label (file,name)
++ FILE *file;
++ char *name;
++ {
++ if (TARGET_AVA)
++ make_it_public=1;
++ else
++ {
++ fprintf (file, ".global\t");
++ assemble_name (file, name);
++ fprintf (file, "\n");
++ }
++ }
++
++
++ #if 0
++
++ rtx
++ try_auto_inc_1 (reg, mem_addr, set)
++ rtx reg;
++ rtx mem_addr;
++ rtx set;
++ {
++ if (GET_CODE (set) == SET)
++ {
++ rtx addr = XEXP (mem_addr,0);
++ HOST_WIDE_INT offset = 0;
++
++ if (GET_CODE (addr) == PLUS
++ && GET_CODE (XEXP (addr, 1)) == CONST_INT)
++ offset = INTVAL (XEXP (addr, 1)), addr = XEXP (addr, 0);
++
++ if (GET_CODE (addr) == REG
++ && ! reg_overlap_mentioned_p (addr, reg))
++ {
++ register rtx y;
++ register int size = GET_MODE_SIZE (GET_MODE (mem_addr));
++
++ /* Is the next use an increment that might make auto-increment? */
++ if ((y = SET_SRC (set), GET_CODE (y) == PLUS) )
++ if (XEXP (y, 0) == addr && addr == SET_DEST (y))
++ if (GET_CODE (XEXP (y, 1)) == CONST_INT)
++ if ((HAVE_POST_INCREMENT
++ && (INTVAL (XEXP (y, 1)) == size && offset == 0))
++ || (HAVE_POST_DECREMENT
++ && (INTVAL (XEXP (y, 1)) == - size && offset == 0))
++ || (HAVE_PRE_INCREMENT
++ && (INTVAL (XEXP (y, 1)) == size && offset == size))
++ || (HAVE_PRE_DECREMENT
++ && (INTVAL (XEXP (y, 1)) == - size
++ && offset == - size)))
++ {
++ enum rtx_code inc_code = (INTVAL (XEXP (y, 1)) == size
++ ? (offset ? PRE_INC : POST_INC)
++ : (offset ? PRE_DEC : POST_DEC));
++
++ /* This is the simple case. Try to make the auto-inc. */
++ return gen_rtx_MEM (GET_MODE (mem_addr),
++ gen_rtx_fmt_e (inc_code, Pmode, addr));
++ }
++ }
++ }
++ return NULL_RTX;
++ }
++
++ rtx
++ try_auto_inc (pnewpat, insn, pnotes)
++ rtx *pnewpat;
++ rtx insn;
++ rtx *pnotes;
++ {
++ rtx pat = *pnewpat;
++ rtx new_rtx;
++ rtx *new_mem;
++ if (GET_CODE (pat) == PARALLEL
++ && XVECLEN (pat, 0) == 2)
++ {
++ rtx incr = XVECEXP (pat, 0, 1);
++ rtx x = XVECEXP (pat, 0, 0);
++ rtx addr;
++ rtx reg;
++ if (GET_CODE (SET_SRC (x)) == MEM && REG_P (SET_DEST (x)))
++ {
++ addr = SET_SRC (x);
++ reg = SET_DEST (x);
++ new_rtx = gen_rtx_SET (VOIDmode, reg, addr);
++ new_mem = &XEXP (new_rtx,1);
++ }
++ else if (GET_CODE (SET_DEST (x)) == MEM && REG_P (SET_SRC (x)))
++ {
++ addr = SET_DEST (x);
++ reg = SET_SRC (x);
++ new_rtx = gen_rtx_SET (VOIDmode, addr, reg);
++ new_mem = &XEXP (new_rtx,0);
++ }
++ else
++ return *pnewpat;
++ if (pat = try_auto_inc_1 (reg, addr, incr))
++ {
++ *new_mem = pat;
++ *pnewpat = new_rtx;
++ /* insn has an implicit side effect. */
++ /* REG_NOTES (insn) */
++ /* = gen_rtx_EXPR_LIST (REG_INC, XEXP (addr,0), REG_NOTES (insn)); */
++ *pnotes = gen_rtx_EXPR_LIST (REG_INC, XEXP (addr,0), 0);
++ }
++ }
++ return *pnewpat;
++ }
++ #endif
++
++ void my_deb ()
++ {
++ }
++
++ void deb_deb (int i)
++ {
++ if (i == 125)
++ my_deb ();
++ }
++
+diff -Nrc3p gcc-2.95.2.orig/gcc/config/avr/avr.md gcc-2.95.2/gcc/config/avr/avr.md
+*** gcc-2.95.2.orig/gcc/config/avr/avr.md Sat Dec 18 17:50:17 1999
+--- gcc-2.95.2/gcc/config/avr/avr.md Thu Dec 23 23:18:45 1999
+***************
+*** 0 ****
+--- 1,2316 ----
++ ;; -*- Mode: Scheme -*-
++ ;; Machine description for GNU compiler,
++ ;; for ATMEL AVR micro controller.
++ ;; Copyright (C) 1998, 1999 by Denis Chertykov (denisc@overta.ru)
++ ;;
++ ;; 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.
++
++ ;; 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 "general_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")])
++
++ (define_expand "reload_inqi"
++ [(parallel [(set (match_operand:QI 0 "register_operand" "=l")
++ (match_operand:QI 1 "immediate_operand" "i"))
++ (clobber (match_operand:QI 2 "register_operand" "=&a"))])]
++ ""
++ "")
++
++ (define_insn "*reload_inqi"
++ [(set (match_operand:QI 0 "register_operand" "=l")
++ (match_operand:QI 1 "immediate_operand" "i"))
++ (clobber (match_operand:QI 2 "register_operand" "=&a"))]
++ ""
++ "ldd %2,lo8(%1)
++ mov %0,%2"
++ [(set_attr "length" "2")
++ (set_attr "cc" "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")])
++
++ (define_expand "reload_inhi"
++ [(parallel [(set (match_operand:HI 0 "register_operand" "=l")
++ (match_operand:HI 1 "immediate_operand" "i"))
++ (clobber (match_operand:QI 2 "register_operand" "=&a"))])]
++ ""
++ "")
++
++ (define_insn "*reload_inhi"
++ [(set (match_operand:HI 0 "register_operand" "=l")
++ (match_operand:HI 1 "immediate_operand" "i"))
++ (clobber (match_operand:QI 2 "register_operand" "=&a"))]
++ ""
++ "* return output_reload_inhi (insn, operands, which_alternative);"
++ [(set_attr "length" "4")
++ (set_attr "cc" "none")])
++
++ ;--------------------------------------------
++ (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 "general_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")])
++
++ (define_expand "reload_insi"
++ [(parallel [(set (match_operand:SI 0 "register_operand" "=l")
++ (match_operand:SI 1 "immediate_operand" "i"))
++ (clobber (match_operand:QI 2 "register_operand" "=&a"))])]
++ ""
++ "")
++
++ (define_insn "*reload_insi"
++ [(set (match_operand:SI 0 "register_operand" "=l")
++ (match_operand:SI 1 "immediate_operand" "i"))
++ (clobber (match_operand:QI 2 "register_operand" "=&a"))]
++ ""
++ "* return output_reload_insisf (insn, operands, which_alternative);"
++ [(set_attr "length" "8")
++ (set_attr "cc" "none")])
++ ;; fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
++
++ (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 "general_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")])
++
++ (define_expand "reload_insf"
++ [(parallel [(set (match_operand:SF 0 "register_operand" "=l")
++ (match_operand:SF 1 "immediate_operand" "iF"))
++ (clobber (match_operand:QI 2 "register_operand" "=&a"))])]
++ ""
++ "")
++
++ (define_insn "*reload_insf"
++ [(set (match_operand:SF 0 "register_operand" "=l")
++ (match_operand:SF 1 "immediate_operand" "iF"))
++ (clobber (match_operand:QI 2 "register_operand" "=&a"))]
++ ""
++ "* return output_reload_insisf (insn, operands, which_alternative);"
++ [(set_attr "length" "8")
++ (set_attr "cc" "none")])
++
++ ;; =========================================================================
++
++ (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
++
++ (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 "cmpstrsi"
++ [(parallel [(set (match_operand:QI 0 "register_operand" "")
++ (compare:QI (match_operand:BLK 1 "general_operand" "")
++ (match_operand:BLK 2 "general_operand" "")))
++ (use (match_operand:HI 3 "general_operand" ""))
++ (use (match_operand:QI 4 "immediate_operand" ""))
++ (clobber (match_dup 5))
++ (clobber (match_dup 6))
++ (clobber (match_dup 3))])]
++ "0 /* Disabled until better times */"
++ "{
++ rtx addr1, addr2;
++ int cnt8;
++
++ addr1 = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
++ addr2 = copy_to_mode_reg (Pmode, XEXP (operands[2], 0));
++
++ cnt8 = byte_immediate_operand (operands[3], GET_MODE (operands[3]));
++ operands[3] = copy_to_mode_reg (cnt8 ? QImode : HImode, operands[3]);
++
++ operands[5] = addr1;
++ operands[6] = addr2;
++
++ operands[1] = gen_rtx_MEM (BLKmode, addr1);
++ operands[2] = gen_rtx_MEM (BLKmode, addr2);
++ }")
++
++ (define_insn "*cmpstrqi_r"
++ [(set (match_operand:QI 4 "register_operand" "=d")
++ (compare:QI (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 "immediate_operand" "i"))
++ (clobber (match_dup 0))
++ (clobber (match_dup 1))
++ (clobber (match_dup 2))]
++ ""
++ "
++ cmp_l%=:
++ ld %4,%a0+
++ ld __tmp_reg__,%a1+
++ sub %4,__tmp_reg__
++ brne cmp_o%=
++ dec %2
++ brne cmp_l%=
++ cmp_o%=:
++ brcc _PC_+2
++ ldi %4,lo8(-1)"
++ [(set_attr "length" "8")
++ (set_attr "cc" "clobber")])
++
++ (define_insn "*cmpstrqi"
++ [(set (cc0)
++ (compare:QI (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 "immediate_operand" "i"))
++ (clobber (match_dup 0))
++ (clobber (match_dup 1))
++ (clobber (match_dup 2))
++ (clobber (match_scratch:QI 4 "=r"))]
++ ""
++ "*{
++ cc_status.flags |= CC_NOT_SIGNED;
++ return (\"\\ncmp_l%=:\" CR_TAB
++ AS2 (ld, %4,%a0+) CR_TAB
++ AS2 (ld, __tmp_reg__,%a1+) CR_TAB
++ AS2 (sub, %4,__tmp_reg__) CR_TAB
++ AS1 (brne, cmp_o%=) CR_TAB
++ AS1 (dec, %2) CR_TAB
++ AS1 (brne, cmp_l%=\\n)
++ \"cmp_o%=:\");
++ }"
++ [(set_attr "length" "6")
++ (set_attr "cc" "compare")])
++
++ (define_insn "*cmpstrhi_r"
++ [(set (match_operand:QI 4 "register_operand" "=d,d")
++ (compare:QI (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:QI 3 "immediate_operand" "i,i"))
++ (clobber (match_dup 0))
++ (clobber (match_dup 1))
++ (clobber (match_dup 2))]
++ ""
++ "*{
++ if (which_alternative==0)
++ return (\"\\ncmp_l%=:\" CR_TAB
++ AS2 (ld, %4,%a0+) CR_TAB
++ AS2 (ld, __tmp_reg__,%a1+) CR_TAB
++ AS2 (sub, %4,__tmp_reg__) CR_TAB
++ AS1 (brne, cmp_o%=) CR_TAB
++ AS2 (sbiw, %2,1) CR_TAB
++ AS1 (brne, cmp_l%=) \"\\n\"
++ \"cmp_o%=:\" CR_TAB
++ AS1 (brcc, cmp_e%=) CR_TAB
++ AS2 (ldi, %4,lo8(-1)) \"\\n\"
++ \"cmp_e%=:\");
++ else
++ return (\"\\ncmp_l%=:\" CR_TAB
++ AS2 (ld, %4,%a0+) CR_TAB
++ AS2 (ld, __tmp_reg__,%a1+) CR_TAB
++ AS2 (sub, %4,__tmp_reg__) CR_TAB
++ AS1 (brne, cmp_o%=) CR_TAB
++ AS2 (subi, %2,lo8(-1)) CR_TAB
++ AS2 (sbci, %2,hi8(-1)) CR_TAB
++ AS1 (brne, cmp_l%=) \"\\n\"
++ \"cmp_o%=:\" CR_TAB
++ AS1 (brcc, cmp_e%=) CR_TAB
++ AS2 (ldi, %4,lo8(-1)) \"\\n\"
++ \"cmp_e%=:\");
++ }"
++ [(set_attr "length" "8,9")
++ (set_attr "cc" "clobber,clobber")])
++
++ (define_insn "*cmpstrhi"
++ [(set (cc0)
++ (compare:QI (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:QI 3 "immediate_operand" "i,i"))
++ (clobber (match_dup 0))
++ (clobber (match_dup 1))
++ (clobber (match_dup 2))
++ (clobber (match_scratch:QI 4 "=&r,&r"))]
++ ""
++ "*{
++ cc_status.flags |= CC_NOT_SIGNED;
++ if (which_alternative==0)
++ return (\"\\ncmp_l%=:\" CR_TAB
++ AS2 (ld, %4,%a0+) CR_TAB
++ AS2 (ld, __tmp_reg__,%a1+) CR_TAB
++ AS2 (sub, %4,__tmp_reg__) CR_TAB
++ AS1 (brne, cmp_e%=) CR_TAB
++ AS2 (sbiw, %2,1) CR_TAB
++ AS1 (brne, cmp_l%=\\n)
++ \"cmp_e%=:\");
++ else
++ return (\"\\ncmp_l%=:\" CR_TAB
++ AS2 (ld, %4,%a0+) CR_TAB
++ AS2 (ld, __tmp_reg__,%a1+) CR_TAB
++ AS2 (sub, %4,__tmp_reg__) CR_TAB
++ AS1 (brne, cmp_e%=) CR_TAB
++ AS2 (subi, %2,lo8(-1)) CR_TAB
++ AS2 (sbci, %2,hi8(-1)) CR_TAB
++ AS1 (brne, cmp_l%=\\n)
++ \"cmp_e%=:\");
++ }"
++ [(set_attr "length" "6,7")
++ (set_attr "cc" "compare,compare")])
++
++
++ (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_sign_extend"
++ [(set (match_operand:HI 0 "register_operand" "=r")
++ (plus:HI (sign_extend:HI
++ (match_operand:QI 1 "register_operand" "r"))
++ (match_operand:HI 2 "register_operand" "0")))]
++ "0"
++ "add %A0,%1
++ sbrs %1,7
++ adc %B0,__zero_reg__
++ sbrc %1,7
++ sbc %B0,__zero_reg__"
++ [(set_attr "length" "5")
++ (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 "*addhi3_clobber"
++ [(set (match_operand:HI 0 "register_operand" "=r,r")
++ (plus:HI (match_operand:HI 1 "register_operand" "%0,0")
++ (match_operand:HI 2 "immediate_operand" "M,i")))
++ (clobber (match_scratch:QI 3 "=&d,&d"))]
++ "0"
++ "@
++ ldi %3,lo8(%2)\;add %A0,%3\;adc %B0,__zero_reg__
++ ldi %3,lo8(%2)\;add %A0,%3\;ldi %3,hi8(%2)\;adc %B0,%3"
++ [(set_attr "length" "3,4")
++ (set_attr "cc" "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")])
++
++ (define_insn "*addsi3_clobber"
++ [(set (match_operand:SI 0 "register_operand" "=r,r")
++ (plus:SI (match_operand:SI 1 "register_operand" "%0,0")
++ (match_operand:SI 2 "immediate_operand" "M,i")))
++ (clobber (match_scratch:QI 3 "=&d,&d"))]
++ "0"
++ "@
++ ldi %3,lo8(%2)\;add %A0,%3\;adc %B0,__zero_reg__\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__
++ ldi %3,lo8(%2)\;add %A0,%3\;ldi %3,hi8(%2)\;adc %B0,%3\;ldi %3,hlo8(%2)\;adc %C0,%3\;ldi %3,hhi8(%2)\;adc %D0,%3"
++ [(set_attr "length" "5,8")
++ (set_attr "cc" "set_n,set_n")])
++
++ ;-----------------------------------------------------------------------------
++ ; 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
++ ;; XXX optimize
++ (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 ""))])]
++ ""
++ "/* Bad result. Two SI registers allocated and combiner don't work
++ on sebregs
++ {
++ if (GET_CODE (operands[2]) == CONST_INT)
++ {
++ switch (INTVAL (operands[2]))
++ {
++ case 16:
++ {
++ emit_insn (gen_movhi (gen_rtx_SUBREG (HImode, operands[0], 0),
++ gen_rtx_SUBREG (HImode, operands[1], 2)));
++ emit_insn (gen_movhi (gen_rtx_SUBREG (HImode, operands[0], 2),
++ const0_rtx));
++ DONE;
++ }
++ }
++ }
++ }
++ */")
++
++ (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 "*tst_bit"
++ [(set (cc0)
++ (and:SI (match_operand:SI 0 "register_operand" "r")
++ (const_int 1)))]
++ ""
++ " sbrc %0,%1 -----------"
++ [(set_attr "length" "3")
++ (set_attr "cc" "clobber")])
++
++ (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);
++ }")
++
++
++ ;; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++
++ (define_insn "sez"
++ [(set (cc0) (const_int 0))]
++ ""
++ "sez"
++ [(set_attr "length" "1")
++ (set_attr "cc" "compare")])
++
++ ; ;; Some patterns for decrement and branch optimizing
++
++ ; (define_insn "*decqi_and_branch_until_0"
++ ; [(set (pc)
++ ; (if_then_else (ne (match_operand:QI 0 "nonimmediate_operand" "+r,+o")
++ ; (const_int 0))
++ ; (label_ref (match_operand 1 "" ""))
++ ; (pc)))
++ ; (set (match_dup 0)
++ ; (plus:QI (match_dup 0)
++ ; (const_int -1)))]
++ ; "(reload_in_progress | reload_completed)
++ ; && "
++ ; "#")
++
++ ; (define_insn "*dechi_and_branch_until_0"
++ ; [(set (pc)
++ ; (if_then_else (ne (match_operand:HI 0 "register_operand" "+r")
++ ; (const_int 0))
++ ; (label_ref (match_operand 1 "" ""))
++ ; (pc)))
++ ; (set (match_dup 0)
++ ; (plus:HI (match_dup 0)
++ ; (const_int -1)))]
++ ; ""
++ ; "#")
++
++ ; (define_insn "*decsi_and_branch_until_0"
++ ; [(set (pc)
++ ; (if_then_else (ne (match_operand:SI 0 "register_operand" "+r")
++ ; (const_int 0))
++ ; (label_ref (match_operand 1 "" ""))
++ ; (pc)))
++ ; (set (match_dup 0)
++ ; (plus:SI (match_dup 0)
++ ; (const_int -1)))]
++ ; ""
++ ; "#")
++
++ ; (define_split
++ ; [(set (pc)
++ ; (if_then_else (ne (match_operand 0 "register_operand" "+r")
++ ; (const_int 0))
++ ; (label_ref (match_operand 1 "" ""))
++ ; (pc)))
++ ; (set (match_dup 0)
++ ; (plus (match_dup 0)
++ ; (const_int -1)))]
++ ; ""
++ ; [(set (match_dup 0) (match_dup 2))
++ ; (set (pc)
++ ; (if_then_else (geu (cc0)
++ ; (const_int 0))
++ ; (label_ref (match_operand 1 "" ""))
++ ; (pc)))]
++ ; "
++ ; {
++ ; operands[2] = gen_rtx (PLUS, GET_MODE (operands[0]),
++ ; operands[0], constm1_rtx);
++ ; if (true_regnum (operands[0]) < 16)
++ ; emit_insn (gen_sez ());
++ ; }")
++
++ ; (define_insn "*decqi_and_branch_until_1"
++ ; [(set (pc)
++ ; (if_then_else (ne (match_operand:QI 0 "register_operand" "+r")
++ ; (const_int 1))
++ ; (label_ref (match_operand 1 "" ""))
++ ; (pc)))
++ ; (set (match_dup 0)
++ ; (plus:QI (match_dup 0)
++ ; (const_int -1)))]
++ ; ""
++ ; "#")
++
++ ; (define_insn "*dechi_and_branch_until_1"
++ ; [(set (pc)
++ ; (if_then_else (ne (match_operand:HI 0 "register_operand" "+r")
++ ; (const_int 1))
++ ; (label_ref (match_operand 1 "" ""))
++ ; (pc)))
++ ; (set (match_dup 0)
++ ; (plus:HI (match_dup 0)
++ ; (const_int -1)))]
++ ; ""
++ ; "#")
++
++ ; (define_insn "*decsi_and_branch_until_1"
++ ; [(set (pc)
++ ; (if_then_else (ne (match_operand:SI 0 "register_operand" "+r")
++ ; (const_int 1))
++ ; (label_ref (match_operand 1 "" ""))
++ ; (pc)))
++ ; (set (match_dup 0)
++ ; (plus:SI (match_dup 0)
++ ; (const_int -1)))]
++ ; ""
++ ; "#")
++
++ ; (define_split
++ ; [(set (pc)
++ ; (if_then_else (ne (match_operand 0 "register_operand" "+r")
++ ; (const_int 1))
++ ; (label_ref (match_operand 1 "" ""))
++ ; (pc)))
++ ; (set (match_dup 0)
++ ; (plus (match_dup 0)
++ ; (const_int -1)))]
++ ; ""
++ ; [(set (match_dup 0) (match_dup 2))
++ ; (set (pc)
++ ; (if_then_else (ne (cc0)
++ ; (const_int 0))
++ ; (label_ref (match_operand 1 "" ""))
++ ; (pc)))]
++ ; "
++ ; {
++ ; operands[2] = gen_rtx (PLUS, GET_MODE (operands[0]),
++ ; operands[0], constm1_rtx);
++ ; if (true_regnum (operands[0]) < 16)
++ ; emit_insn (gen_sez ());
++ ; }")
++
++ ;;(define_insn ""
++ ;; [(set (pc)
++ ;; (if_then_else (eq (match_operand 0 "register_operand" "+d")
++ ;; (const_int 0))
++ ;; (label_ref (match_operand 1 "" ""))
++ ;; (pc)))
++ ;; (set (match_dup 0)
++ ;; (plus (match_dup 0)
++ ;; (const_int -1)))]
++ ;; ""
++ ;; "#")
++ ;;
++ ;;(define_split
++ ;; [(set (pc)
++ ;; (if_then_else (eq (match_operand 0 "register_operand" "+d")
++ ;; (const_int 0))
++ ;; (label_ref (match_operand 1 "" ""))
++ ;; (pc)))
++ ;; (set (match_dup 0)
++ ;; (plus (match_dup 0)
++ ;; (const_int -1)))]
++ ;; ""
++ ;; [(set (match_dup 0) (match_dup 2))
++ ;; (set (pc)
++ ;; (if_then_else (ltu (cc0)
++ ;; (const_int 0))
++ ;; (label_ref (match_operand 1 "" ""))
++ ;; (pc)))]
++ ;; "
++ ;;{
++ ;; operands[2] = gen_rtx (PLUS, GET_MODE (operands[0]),
++ ;; operands[0], constm1_rtx);
++ ;;}")
++ ;; ************************* 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 -Nrc3p gcc-2.95.2.orig/gcc/config/avr/avr.h gcc-2.95.2/gcc/config/avr/avr.h
+*** gcc-2.95.2.orig/gcc/config/avr/avr.h Sat Dec 18 17:50:17 1999
+--- gcc-2.95.2/gcc/config/avr/avr.h Sun Dec 19 22:57:52 1999
+***************
+*** 0 ****
+--- 1,5524 ----
++ /* Definitions of target machine for GNU compiler,
++ for ATMEL AVR at90s8515, ATmega103/103L, ATmega603/603L microcontroller.
++ Copyright (C) 1998, 1999 by Denis Chertykov (denisc@overta.ru)
++
++ 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.
++ */
++
++ /* 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.
++ */
++ extern int target_flags;
++ /*
++ This declaration should be present.
++ */
++
++ /* Select string according to the target assembler */
++ #define AS_STR(ava,gas) (TARGET_AVA ? ava : gas)
++
++ /* Dump each assembler insn's rtl into the output file.
++ This is for debugging the compiler only. */
++
++ #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_INCLUDE (target_flags & 0x8000)
++ #define TARGET_CALL_PROLOGUES (target_flags & 0x40000)
++ #define TARGET_AVA (target_flags & 0x80000)
++
++ #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}, \
++ {"order2",0x4000}, \
++ {"include-target",0x8000, \
++ "Add line `#include \"target.inc\"' to front of outputed .s file"}, \
++ {"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"}, \
++ {"ava", 0x80000, "Use AVA as assembler and linker"}, \
++ {"rtl",0x10}, \
++ {"size",0x2000,"Output instruction size's to the asm file"}, \
++ {"deb",0xfe0}, \
++ {"",0}}
++ /*
++ 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;
++ char * ava_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, "AVA/GNU BINUTILS version");
++ /*
++ 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.
++ */
++ /*
++ `OPTIMIZATION_OPTIONS (LEVEL)'
++ Some machines may desire to change what optimizations are
++ performed for various optimization levels. This macro, if
++ defined, is executed once just after the optimization level is
++ determined and before the remainder of the command options have
++ been parsed. Values set in this macro are used as the default
++ values for the other command line options.
++
++ LEVEL is the optimization level specified; 2 if `-O2' is
++ specified, 1 if `-O' is specified, and 0 if neither is specified.
++
++ You should not use this macro to change options that are not
++ machine-specific. These should uniformly selected by the same
++ optimization level on all supported machines. Use this macro to
++ enable machine-specific optimizations.
++
++ *Do not examine `write_symbols' in this macro!* The debugging
++ options are not supposed to alter the generated code.
++ */
++
++
++ #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 STRICT_ALIGNMENT 0
++ /*
++ Define this if move instructions will actually fail to work
++ when given unaligned data.
++ */
++
++
++ #define INT_TYPE_SIZE (TARGET_INT8 ? 8 : 16)
++ /*
++ 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 SHORT_TYPE_SIZE (INT_TYPE_SIZE == 8 ? INT_TYPE_SIZE : 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 LONG_TYPE_SIZE (INT_TYPE_SIZE == 8 ? 16 : 32)
++ /*
++ 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 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"'.
++ */
++
++ /*
++ 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 PTRDIFF_TYPE (INT_TYPE_SIZE == 8 ? "long unsigned int" : "unsigned 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 CONDITIONAL_REGISTER_USAGE ;*/
++ /*
++ Zero or more C statements that may conditionally modify two
++ variables `fixed_regs' and `call_used_regs' (both of type `char
++ []') after they have been initialized from the two preceding
++ macros.
++
++ This is necessary in case the fixed or call-clobbered registers
++ depend on target flags.
++
++ You need not define this macro if it has no work to do.
++
++ If the usage of an entire class of registers depends on the target
++ flags, you may indicate this to GCC by using this macro to modify
++ `fixed_regs' and `call_used_regs' to 1 for each of the registers
++ in the classes which should not be used by GCC. Also define the
++ macro `REG_CLASS_FROM_LETTER' to return `NO_REGS' if it is called
++ with a letter for a class that shouldn't be used.
++
++ (However, if this class is not included in `GENERAL_REGS' and all
++ of the insn patterns whose constraints permit this class are
++ controlled by target switches, then GCC will automatically avoid
++ using these registers when the target switches are opposed to
++ them.)
++ */
++
++ #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'.
++ */
++
++ /*
++ `INCOMING_REGNO (OUT)'
++ Define this macro if the target machine has register windows.
++ This C expression returns the register number as seen by the
++ called function corresponding to the register number OUT as seen
++ by the calling function. Return OUT if register number OUT is not
++ an outbound register.
++
++ `OUTGOING_REGNO (IN)'
++ Define this macro if the target machine has register windows.
++ This C expression returns the register number as seen by the
++ calling function corresponding to the register number IN as seen
++ by the called function. Return IN if register number IN is not an
++ inbound register.
++
++ */
++ #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 \
++ }
++ /* XXX optimize optimize
++
++ 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)
++ /* XXX may be need
++ 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 */ \
++ {0xffffffff,0x00000000}, /* GENERAL_REGS, r0 - r31 */ \
++ {0xffffffff,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.
++ */
++
++ #define SECONDARY_INPUT_RELOAD_CLASS(CLASS, MODE, X) \
++ secondary_input_reload_class (CLASS, MODE, X)
++
++ /*
++ #define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS, MODE, X) secondary_output_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'.
++ */
++
++ /*
++ `SECONDARY_MEMORY_NEEDED_MODE (MODE)'
++ When the compiler needs a secondary memory location to copy
++ between two registers of mode MODE, it normally allocates
++ sufficient memory to hold a quantity of `BITS_PER_WORD' bits and
++ performs the store and load operations in a mode that many bits
++ wide and whose class is the same as that of MODE.
++
++ This is right thing to do on most machines because it ensures that
++ all bits of the register are copied and prevents accesses to the
++ registers in a narrower mode, which some machines prohibit for
++ floating-point registers.
++
++ However, this default behavior is not correct on some machines,
++ such as the DEC Alpha, that store short integers in floating-point
++ registers differently than in integer registers. On those
++ machines, the default widening will not work correctly and you
++ must define this macro to suppress that widening in some cases.
++ See the file `alpha.h' for details.
++
++ Do not define this macro if you do not define
++ `SECONDARY_MEMORY_NEEDED' or if widening MODE to a mode that is
++ `BITS_PER_WORD' bits wide is correct for your machine.
++ */
++
++ #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.
++ */
++
++ /*
++ `FRAME_GROWS_DOWNWARD'
++ Define this macro if the addresses of local variable slots are at
++ negative offsets from the frame pointer.
++ */
++
++ /*
++ `ARGS_GROW_DOWNWARD'
++ Define this macro if successive arguments to a function occupy
++ decreasing addresses on the stack.
++ */
++
++ #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.
++ */
++
++ /*
++ `DYNAMIC_CHAIN_ADDRESS (FRAMEADDR)'
++ A C expression whose value is RTL representing the address in a
++ stack frame where the pointer to the caller's frame is stored.
++ Assume that FRAMEADDR is an RTL expression for the address of the
++ stack frame itself.
++
++ If you don't define this macro, the default is to return the value
++ of FRAMEADDR--that is, the stack frame address is also the address
++ of the stack word that points to the previous frame.
++ */
++
++ /*
++ `SETUP_FRAME_ADDRESSES ()'
++ If defined, a C expression that produces the machine-specific code
++ to setup the stack so that arbitrary frames can be accessed. For
++ example, on the Sparc, we must flush all of the register windows
++ to the stack before we can access arbitrary stack frames. This
++ macro will seldom need to be defined.
++ */
++
++ /*XXX
++
++ After the prologue, RA is at -4(AP) in the current frame.
++ #define RETURN_ADDR_RTX(COUNT, FRAME) \
++ ((COUNT) == 0 \
++ ? gen_rtx (MEM, Pmode, gen_rtx (PLUS, Pmode, arg_pointer_rtx, GEN_INT(-4)))\
++ : gen_rtx (MEM, Pmode, gen_rtx (PLUS, Pmode, (FRAME), GEN_INT(4))))
++
++ #define RETURN_ADDR_RTX(COUNT, FRAMEADDR)
++ A C expression whose value is RTL representing the value of the
++ return address for the frame COUNT steps up from the current
++ frame, after the prologue. FRAMEADDR is the frame pointer of the
++ COUNT frame, or the frame pointer of the COUNT - 1 frame if
++ `RETURN_ADDR_IN_PREVIOUS_FRAME' is defined.
++ */
++
++ /*
++ `RETURN_ADDR_IN_PREVIOUS_FRAME'
++ Define this if the return address of a particular stack frame is
++ accessed from the frame pointer of the previous stack frame.
++ */
++
++ /*XXX
++ Before the prologue, RA is at 0(%esp).
++ #define INCOMING_RETURN_ADDR_RTX \
++ gen_rtx (MEM, VOIDmode, gen_rtx (REG, VOIDmode, STACK_POINTER_REGNUM))
++
++ `INCOMING_RETURN_ADDR_RTX'
++ A C expression whose value is RTL representing the location of the
++ incoming return address at the beginning of any function, before
++ the prologue. This RTL is either a `REG', indicating that the
++ return value is saved in `REG', or a `MEM' representing a location
++ in the stack.
++
++ You only need to define this macro if you want to support call
++ frame debugging information like that provided by DWARF 2.
++ */
++
++ /*
++ `INCOMING_FRAME_SP_OFFSET'
++ A C expression whose value is an integer giving the offset, in
++ bytes, from the value of the stack pointer register to the top of
++ the stack frame at the beginning of any function, before the
++ prologue. The top of the frame is defined to be the value of the
++ stack pointer in the previous frame, just before the call
++ instruction.
++
++ You only need to define this macro if you want to support call
++ frame debugging information like that provided by DWARF 2.
++ */
++
++
++ #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.
++ */
++
++ /*
++ `HARD_FRAME_POINTER_REGNUM'
++ On some machines the offset between the frame pointer and starting
++ offset of the automatic variables is not known until after register
++ allocation has been done (for example, because the saved registers
++ are between these two locations). On those machines, define
++ `FRAME_POINTER_REGNUM' the number of a special, fixed register to
++ be used internally until the offset is known, and define
++ `HARD_FRAME_POINTER_REGNUM' to be actual the hard register number
++ used for the frame pointer.
++
++ You should define this macro only in the very rare circumstances
++ when it is not possible to calculate the offset between the frame
++ pointer and the automatic variables until after register
++ allocation has been completed. When this macro is defined, you
++ must also indicate in your definition of `ELIMINABLE_REGS' how to
++ eliminate `FRAME_POINTER_REGNUM' into either
++ `HARD_FRAME_POINTER_REGNUM' or `STACK_POINTER_REGNUM'.
++
++ Do not define this macro if it would be the same as
++ `FRAME_POINTER_REGNUM'.
++ */
++
++ #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::.).
++ */
++
++ /*
++ `RETURN_ADDRESS_POINTER_REGNUM'
++ The register number of the return address pointer register, which
++ is used to access the current function's return address from the
++ stack. On some machines, the return address is not at a fixed
++ offset from the frame pointer or stack pointer or argument
++ pointer. This register can be defined to point to the return
++ address on the stack, and then be converted by `ELIMINABLE_REGS'
++ into either the frame pointer or stack pointer.
++
++ Do not define this macro unless there is no other way to get the
++ return address from the stack.
++ */
++
++ #define STATIC_CHAIN_REGNUM 2
++ /*
++ `STATIC_CHAIN_INCOMING_REGNUM'
++ 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.
++ */
++ /*
++ `STATIC_CHAIN'
++ `STATIC_CHAIN_INCOMING'
++ If the static chain is passed in memory, these macros provide rtx
++ giving `mem' expressions that denote where they are stored.
++ `STATIC_CHAIN' and `STATIC_CHAIN_INCOMING' give the locations as
++ seen by the calling and called functions, respectively. Often the
++ former will be at an offset from the stack pointer and the latter
++ at an offset from the frame pointer.
++
++ The variables `stack_pointer_rtx', `frame_pointer_rtx', and
++ `arg_pointer_rtx' will have been initialized prior to the use of
++ these macros and should be used to refer to those items.
++
++ If the static chain is passed in a register, the two previous
++ macros should be defined instead.
++ */
++
++
++ #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 INITIAL_FRAME_POINTER_OFFSET(DV) ((DV)=0)
++ A C statement to store in the variable DEPTH-VAR the difference
++ between the frame pointer and the stack pointer values immediately
++ after the function prologue. The value would be computed from
++ information such as the result of `get_frame_size ()' and the
++ tables of registers `regs_ever_live' and `call_used_regs'.
++
++ If `ELIMINABLE_REGS' is defined, this macro will be not be used and
++ need not be defined. Otherwise, it must be defined even if
++ `FRAME_POINTER_REQUIRED' is defined to always be true; in that
++ case, you may set DEPTH-VAR to anything.
++ */
++
++ #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.
++ */
++
++ /*
++ `LONGJMP_RESTORE_FROM_STACK'
++ Define this macro if the `longjmp' function restores registers from
++ the stack frames, rather than from those saved specifically by
++ `setjmp'. Certain quantities must not be kept in registers across
++ a call to `setjmp' on such machines.
++ */
++
++ /*
++ #define PROMOTE_PROTOTYPES
++ Define this macro if an argument declared in a prototype as an
++ integral type smaller than `int' should actually be passed as an
++ `int'. In addition to avoiding errors in certain cases of
++ mismatch, it also makes for better code on certain machines.
++ */
++
++ #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)
++ */
++
++ /*
++ `ACCUMULATE_OUTGOING_ARGS'
++ If defined, the maximum amount of space required for outgoing
++ arguments will be computed and placed into the variable
++ `current_function_outgoing_args_size'. No space will be pushed
++ onto the stack for each call; instead, the function prologue should
++ increase the stack frame size by this amount.
++
++ Defining both `PUSH_ROUNDING' and `ACCUMULATE_OUTGOING_ARGS' is
++ not proper.
++ */
++
++ /*
++ `REG_PARM_STACK_SPACE (FNDECL)'
++ Define this macro if functions should assume that stack space has
++ been allocated for arguments even when their values are passed in
++ registers.
++
++ The value of this macro is the size, in bytes, of the area
++ reserved for arguments passed in registers for the function
++ represented by FNDECL.
++
++ This space can be allocated by the caller, or be a part of the
++ machine-dependent stack frame: `OUTGOING_REG_PARM_STACK_SPACE' says
++ which.
++ */
++
++ /*
++ `MAYBE_REG_PARM_STACK_SPACE'
++ `FINAL_REG_PARM_STACK_SPACE (CONST_SIZE, VAR_SIZE)'
++ Define these macros in addition to the one above if functions might
++ allocate stack space for arguments even when their values are
++ passed in registers. These should be used when the stack space
++ allocated for arguments in registers is not a simple constant
++ independent of the function declaration.
++
++ The value of the first macro is the size, in bytes, of the area
++ that we should initially assume would be reserved for arguments
++ passed in registers.
++
++ The value of the second macro is the actual size, in bytes, of the
++ area that will be reserved for arguments passed in registers.
++ This takes two arguments: an integer representing the number of
++ bytes of fixed sized arguments on the stack, and a tree
++ representing the number of bytes of variable sized arguments on
++ the stack.
++
++ When these macros are defined, `REG_PARM_STACK_SPACE' will only be
++ called for libcall functions, the current function, or for a
++ function being called when it is known that such stack space must
++ be allocated. In each case this value can be easily computed.
++
++ When deciding whether a called function needs such stack space,
++ and how much space to reserve, GNU CC uses these two macros
++ instead of `REG_PARM_STACK_SPACE'.
++ */
++
++ /*
++ `OUTGOING_REG_PARM_STACK_SPACE'
++ Define this if it is the responsibility of the caller to allocate
++ the area reserved for arguments passed in registers.
++
++ If `ACCUMULATE_OUTGOING_ARGS' is defined, this macro controls
++ whether the space for these arguments counts in the value of
++ `current_function_outgoing_args_size'.
++ */
++
++ /*
++ `STACK_PARMS_IN_REG_PARM_AREA'
++ Define this macro if `REG_PARM_STACK_SPACE' is defined, but the
++ stack parameters don't skip the area specified by it.
++
++ Normally, when a parameter is not passed in registers, it is
++ placed on the stack beyond the `REG_PARM_STACK_SPACE' area.
++ Defining this macro suppresses this behavior and causes the
++ parameter to be passed on the stack in its natural location.
++ */
++
++ #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))
++ /*XXX optimize
++ #define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) 0
++ 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.
++ */
++
++ /*
++ `FUNCTION_INCOMING_ARG (CUM, MODE, TYPE, NAMED)'
++ Define this macro if the target machine has "register windows", so
++ that the register in which a function sees an arguments is not
++ necessarily the same as the one in which the caller passed the
++ argument.
++
++ For such machines, `FUNCTION_ARG' computes the register in which
++ the caller passes the value, and `FUNCTION_INCOMING_ARG' should be
++ defined in a similar fashion to tell the function being called
++ where the arguments will arrive.
++
++ If `FUNCTION_INCOMING_ARG' is not defined, `FUNCTION_ARG' serves
++ both purposes.
++ */
++
++
++ /* #define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) function_arg_partial_nregs (CUM, MODE, TYPE, NAMED) */
++ #define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) 0
++ /*XXX optimize
++ A C expression for the number of words, at the beginning of an
++ argument, must be put in registers. The value must be zero for
++ arguments that are passed entirely in registers or that are
++ entirely pushed on the stack.
++
++ On some machines, certain arguments must be passed partially in
++ registers and partially in memory. On these machines, typically
++ the first N words of arguments are passed in registers, and the
++ rest on the stack. If a multi-word argument (a `double' or a
++ structure) crosses that boundary, its first few words must be
++ passed in registers and the rest must be pushed. This macro tells
++ the compiler when this occurs, and how many of the words should go
++ in registers.
++
++ `FUNCTION_ARG' for these arguments should return the first
++ register to be used by the caller for this argument; likewise
++ `FUNCTION_INCOMING_ARG', for the called function.
++ */
++
++ /*
++ `FUNCTION_ARG_PASS_BY_REFERENCE (CUM, MODE, TYPE, NAMED)'
++ A C expression that indicates when an argument must be passed by
++ reference. If nonzero for an argument, a copy of that argument is
++ made in memory and a pointer to the argument is passed instead of
++ the argument itself. The pointer is passed in whatever way is
++ appropriate for passing a pointer to that type.
++
++ On machines where `REG_PARM_STACK_SPACE' is not defined, a suitable
++ definition of this macro might be
++ #define FUNCTION_ARG_PASS_BY_REFERENCE\
++ (CUM, MODE, TYPE, NAMED) \
++ MUST_PASS_IN_STACK (MODE, TYPE)
++ */
++
++ /*
++ `FUNCTION_ARG_CALLEE_COPIES (CUM, MODE, TYPE, NAMED)'
++ If defined, a C expression that indicates when it is the called
++ function's responsibility to make a copy of arguments passed by
++ invisible reference. Normally, the caller makes a copy and passes
++ the address of the copy to the routine being called. When
++ FUNCTION_ARG_CALLEE_COPIES is defined and is nonzero, the caller
++ does not make a copy. Instead, it passes a pointer to the "live"
++ value. The called function must not modify this value. If it can
++ be determined that the value won't be modified, it need not make a
++ copy; otherwise a copy must be made.
++ */
++
++ 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)
++
++ /*XXX optimize
++ 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.
++ */
++
++ /*
++ `INIT_CUMULATIVE_INCOMING_ARGS (CUM, FNTYPE, LIBNAME)'
++ Like `INIT_CUMULATIVE_ARGS' but overrides it for the purposes of
++ finding the arguments for the function being compiled. If this
++ macro is undefined, `INIT_CUMULATIVE_ARGS' is used instead.
++
++ The value passed for LIBNAME is always 0, since library routines
++ with special calling conventions are never compiled with GNU CC.
++ The argument LIBNAME exists for symmetry with
++ `INIT_CUMULATIVE_ARGS'.
++ */
++
++ #define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
++ (function_arg_advance (&CUM, MODE, TYPE, NAMED))
++
++ /*XXX optimize
++ 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.
++ */
++
++ /*
++ `FUNCTION_ARG_PADDING (MODE, TYPE)'
++ If defined, a C expression which determines whether, and in which
++ direction, to pad out an argument with extra space. The value
++ should be of type `enum direction': either `upward' to pad above
++ the argument, `downward' to pad below, or `none' to inhibit
++ padding.
++
++ The *amount* of padding is always just enough to reach the next
++ multiple of `FUNCTION_ARG_BOUNDARY'; this macro does not control
++ it.
++
++ This macro has a default definition which is right for most
++ systems. For little-endian machines, the default is to pad
++ upward. For big-endian machines, the default is to pad downward
++ for an argument of constant size shorter than an `int', and upward
++ otherwise.
++ */
++ /*
++ `FUNCTION_ARG_BOUNDARY (MODE, TYPE)'
++ If defined, a C expression that gives the alignment boundary, in
++ bits, of an argument with the specified mode and type. If it is
++ not defined, `PARM_BOUNDARY' is used for all arguments.
++ */
++
++ #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.
++ */
++
++ /*
++ `TRADITIONAL_RETURN_FLOAT'
++ Define this macro if `-traditional' should not cause functions
++ declared to return `float' to convert the value to `double'.
++ */
++
++ 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.
++ */
++
++ /*
++ `FUNCTION_OUTGOING_VALUE (VALTYPE, FUNC)'
++ Define this macro if the target machine has "register windows" so
++ that the register in which a function returns its value is not the
++ same as the one in which the caller sees the value.
++
++ For such machines, `FUNCTION_VALUE' computes the register in which
++ the caller will see the value. `FUNCTION_OUTGOING_VALUE' should be
++ defined in a similar fashion to tell the function where to put the
++ value.
++
++ If `FUNCTION_OUTGOING_VALUE' is not defined, `FUNCTION_VALUE'
++ serves both purposes.
++
++ `FUNCTION_OUTGOING_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.
++ */
++
++ /*
++ `APPLY_RESULT_SIZE'
++ Define this macro if `untyped_call' and `untyped_return' need more
++ space than is implied by `FUNCTION_VALUE_REGNO_P' for saving and
++ restoring an arbitrary return value.
++ */
++
++
++ #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_REGNUM RET_REGISTER
++ If the structure value address is passed in a register, then
++ `STRUCT_VALUE_REGNUM' should be the number of that register.
++ */
++
++ #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.
++ */
++
++ /*
++ STRUCT_VALUE_INCOMING_REGNUM
++ On some architectures the place where the structure value address
++ is found by the called function is not the same place that the
++ caller put it. This can be due to register windows, or it could
++ be because the function prologue moves it to a different place.
++
++ If the incoming location of the structure value address is in a
++ register, define this macro as the register number.
++ */
++ #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.
++ */
++
++ /*
++ `PCC_STATIC_STRUCT_RETURN'
++ Define this macro if the usual system convention on the target
++ machine for returning structures and unions is for the called
++ function to return the address of a static variable containing the
++ value.
++
++ Do not define this if the usual system convention is for the
++ caller to pass an address to the subroutine.
++
++ This macro has effect in `-fpcc-struct-return' mode, but it does
++ nothing when you use `-freg-struct-return' mode.
++ */
++
++ /*
++ `DEFAULT_CALLER_SAVES'
++ Define this macro if function calls on the target machine do not
++ preserve any registers; in other words, if `CALL_USED_REGISTERS'
++ has 1 for all registers. This macro enables `-fcaller-saves' by
++ default. Eventually that option will be enabled by default on all
++ machines and both the option and this macro will be eliminated.
++ */
++
++ /*
++ `CALLER_SAVE_PROFITABLE (REFS, CALLS)'
++ A C expression to determine whether it is worthwhile to consider
++ placing a pseudo-register in a call-clobbered hard register and
++ saving and restoring it around each function call. The expression
++ should be 1 when this is worth doing, and 0 otherwise.
++
++ If you don't define this macro, a default is used which is good on
++ most machines: `4 * CALLS < REFS'.
++ */
++
++ #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.
++ */
++
++ /* XXX optimize later
++ #define EXIT_IGNORE_STACK 1
++ Define this macro as a C expression that is nonzero if the return
++ instruction or the function epilogue ignores the value of the stack
++ pointer; in other words, if it is safe to delete an instruction to
++ adjust the stack pointer before a return from the function.
++
++ Note that this macro's value is relevant only for functions for
++ which frame pointers are maintained. It is never safe to delete a
++ final stack adjustment in a function that has no frame pointer,
++ and the compiler knows this regardless of `EXIT_IGNORE_STACK'.
++ */
++
++ #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::.
++ */
++
++ /*
++ `DELAY_SLOTS_FOR_EPILOGUE'
++ Define this macro if the function epilogue contains delay slots to
++ which instructions from the rest of the function can be "moved".
++ The definition should be a C expression whose value is an integer
++ representing the number of delay slots there.
++
++ `ELIGIBLE_FOR_EPILOGUE_DELAY (INSN, N)'
++ A C expression that returns 1 if INSN can be placed in delay slot
++ number N of the epilogue.
++
++ The argument N is an integer which identifies the delay slot now
++ being considered (since different slots may have different rules of
++ eligibility). It is never negative and is always less than the
++ number of epilogue delay slots (what `DELAY_SLOTS_FOR_EPILOGUE'
++ returns). If you reject a particular insn for a given delay slot,
++ in principle, it may be reconsidered for a subsequent delay slot.
++ Also, other insns may (at least in principle) be considered for
++ the so far unfilled delay slot.
++
++ The insns accepted to fill the epilogue delay slots are put in an
++ RTL list made with `insn_list' objects, stored in the variable
++ `current_function_epilogue_delay_list'. The insn for the first
++ delay slot comes first in the list. Your definition of the macro
++ `FUNCTION_EPILOGUE' should fill the delay slots by outputting the
++ insns in this list, usually by calling `final_scan_insn'.
++
++ You need not define this macro if you did not define
++ `DELAY_SLOTS_FOR_EPILOGUE'.
++ */
++
++ /*
++ `ASM_OUTPUT_MI_THUNK (FILE, THUNK_FNDECL, DELTA, FUNCTION)'
++ A C compound statement that outputs the assembler code for a thunk
++ function, used to implement C++ virtual function calls with
++ multiple inheritance. The thunk acts as a wrapper around a
++ virtual function, adjusting the implicit object parameter before
++ handing control off to the real function.
++
++ First, emit code to add the integer DELTA to the location that
++ contains the incoming first argument. Assume that this argument
++ contains a pointer, and is the one used to pass the `this' pointer
++ in C++. This is the incoming argument *before* the function
++ prologue, e.g. `%o0' on a sparc. The addition must preserve the
++ values of all other incoming arguments.
++
++ After the addition, emit code to jump to FUNCTION, which is a
++ `FUNCTION_DECL'. This is a direct pure jump, not a call, and does
++ not touch the return address. Hence returning from FUNCTION will
++ return to whoever called the current `thunk'.
++
++ The effect must be as if FUNCTION had been called directly with
++ the adjusted first argument. This macro is responsible for
++ emitting all of the code for a thunk function; `FUNCTION_PROLOGUE'
++ and `FUNCTION_EPILOGUE' are not invoked.
++
++ The THUNK_FNDECL is redundant. (DELTA and FUNCTION have already
++ been extracted from it.) It might possibly be useful on some
++ targets, but probably not.
++
++ If you do not define this macro, the target-independent code in
++ the C++ frontend will generate a less efficient heavyweight thunk
++ that calls FUNCTION instead of jumping to it. The generic
++ approach does not support varargs.
++ */
++
++ /*
++ `__builtin_saveregs ()'
++ Use this built-in function to save the argument registers in
++ memory so that the varargs mechanism can access them. Both ANSI
++ and traditional versions of `va_start' must use
++ `__builtin_saveregs', unless you use `SETUP_INCOMING_VARARGS' (see
++ below) instead.
++
++ On some machines, `__builtin_saveregs' is open-coded under the
++ control of the macro `EXPAND_BUILTIN_SAVEREGS'. On other machines,
++ it calls a routine written in assembler language, found in
++ `libgcc2.c'.
++
++ Code generated for the call to `__builtin_saveregs' appears at the
++ beginning of the function, as opposed to where the call to
++ `__builtin_saveregs' is written, regardless of what the code is.
++ This is because the registers must be saved before the function
++ starts to use them for its own purposes.
++
++ `__builtin_args_info (CATEGORY)'
++ Use this built-in function to find the first anonymous arguments in
++ registers.
++
++ In general, a machine may have several categories of registers
++ used for arguments, each for a particular category of data types.
++ (For example, on some machines, floating-point registers are used
++ for floating-point arguments while other arguments are passed in
++ the general registers.) To make non-varargs functions use the
++ proper calling convention, you have defined the `CUMULATIVE_ARGS'
++ data type to record how many registers in each category have been
++ used so far
++
++ `__builtin_args_info' accesses the same data structure of type
++ `CUMULATIVE_ARGS' after the ordinary argument layout is finished
++ with it, with CATEGORY specifying which word to access. Thus, the
++ value indicates the first unused register in a given category.
++
++ Normally, you would use `__builtin_args_info' in the implementation
++ of `va_start', accessing each category just once and storing the
++ value in the `va_list' object. This is because `va_list' will
++ have to update the values, and there is no way to alter the values
++ accessed by `__builtin_args_info'.
++
++ `__builtin_next_arg (LASTARG)'
++ This is the equivalent of `__builtin_args_info', for stack
++ arguments. It returns the address of the first anonymous stack
++ argument, as type `void *'. If `ARGS_GROW_DOWNWARD', it returns
++ the address of the location above the first anonymous stack
++ argument. Use it in `va_start' to initialize the pointer for
++ fetching arguments from the stack. Also use it in `va_start' to
++ verify that the second parameter LASTARG is the last named argument
++ of the current function.
++
++ `__builtin_classify_type (OBJECT)'
++ Since each machine has its own conventions for which data types are
++ passed in which kind of register, your implementation of `va_arg'
++ has to embody these conventions. The easiest way to categorize the
++ specified data type is to use `__builtin_classify_type' together
++ with `sizeof' and `__alignof__'.
++
++ `__builtin_classify_type' ignores the value of OBJECT, considering
++ only its data type. It returns an integer describing what kind of
++ type that is--integer, floating, pointer, structure, and so on.
++
++ The file `typeclass.h' defines an enumeration that you can use to
++ interpret the values of `__builtin_classify_type'.
++
++ These machine description macros help implement varargs:
++
++ `EXPAND_BUILTIN_SAVEREGS (ARGS)'
++ If defined, is a C expression that produces the machine-specific
++ code for a call to `__builtin_saveregs'. This code will be moved
++ to the very beginning of the function, before any parameter access
++ are made. The return value of this function should be an RTX that
++ contains the value to use as the return of `__builtin_saveregs'.
++
++ The argument ARGS is a `tree_list' containing the arguments that
++ were passed to `__builtin_saveregs'.
++
++ If this macro is not defined, the compiler will output an ordinary
++ call to the library function `__builtin_saveregs'.
++
++ `SETUP_INCOMING_VARARGS (ARGS_SO_FAR, MODE, TYPE,'
++ PRETEND_ARGS_SIZE, SECOND_TIME) This macro offers an alternative
++ to using `__builtin_saveregs' and defining the macro
++ `EXPAND_BUILTIN_SAVEREGS'. Use it to store the anonymous register
++ arguments into the stack so that all the arguments appear to have
++ been passed consecutively on the stack. Once this is done, you
++ can use the standard implementation of varargs that works for
++ machines that pass all their arguments on the stack.
++
++ The argument ARGS_SO_FAR is the `CUMULATIVE_ARGS' data structure,
++ containing the values that obtain after processing of the named
++ arguments. The arguments MODE and TYPE describe the last named
++ argument--its machine mode and its data type as a tree node.
++
++ The macro implementation should do two things: first, push onto the
++ stack all the argument registers *not* used for the named
++ arguments, and second, store the size of the data thus pushed into
++ the `int'-valued variable whose name is supplied as the argument
++ PRETEND_ARGS_SIZE. The value that you store here will serve as
++ additional offset for setting up the stack frame.
++
++ Because you must generate code to push the anonymous arguments at
++ compile time without knowing their data types,
++ `SETUP_INCOMING_VARARGS' is only useful on machines that have just
++ a single category of argument register and use it uniformly for
++ all data types.
++
++ If the argument SECOND_TIME is nonzero, it means that the
++ arguments of the function are being analyzed for the second time.
++ This happens for an inline function, which is not actually
++ compiled until the end of the source file. The macro
++ `SETUP_INCOMING_VARARGS' should not generate any instructions in
++ this case.
++ */
++
++ #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 2
++ /*
++ 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
++ /*XXX
++ 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) \
++ { \
++ rtx orig_x = (X); \
++ (X) = legitimize_address (X, OLDX, MODE); \
++ if (memory_address_p (MODE, X)) \
++ goto WIN; \
++ }
++ /*
++ #define LEGITIMIZE_ADDRESS(X, OLDX, MODE, 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 ((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.
++ */
++
++ /*
++ `DONT_RECORD_EQUIVALENCE (NOTE)'
++ A C expression that is nonzero if the `REG_EQUAL' note X should not
++ be promoted to a `REG_EQUIV' note.
++
++ Define this macro if NOTE refers to a constant that must be
++ accepted by `LEGITIMATE_CONSTANT_P', but must not appear as an
++ immediate operand.
++
++ Most machine descriptions do not need to define this macro.
++ */
++
++
++
++ #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; \
++ }
++
++ /*XXX ?-?-?
++ 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) avr_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 BRANCH_COST 2
++ A C expression for the cost of a branch instruction. A value of 1
++ is the default; other values are interpreted relative to that.
++
++ Here are additional macros which do not specify precise relative
++ costs, but only that certain actions are more expensive than GNU CC
++ would ordinarily expect.
++ */
++
++ #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 \
++ avr_change_section (AS_STR ("\tseg flash.code", ".section .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.
++ */
++
++ extern char * avr_data_section_name;
++ #define DATA_SECTION_ASM_OP \
++ avr_change_section (avr_data_section_name)
++ /*
++ 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.
++ */
++
++ /*
++ `SHARED_SECTION_ASM_OP'
++ If defined, a C expression whose value is a string containing the
++ assembler operation to identify the following data as shared data.
++ If not defined, `DATA_SECTION_ASM_OP' will be used.
++ */
++
++ extern char * avr_bss_section_name;
++ #define BSS_SECTION_ASM_OP \
++ avr_change_section (avr_bss_section_name)
++ /*
++ If defined, a C expression whose value is a string containing the
++ assembler operation to identify the following data as
++ uninitialized global data. If not defined, and neither
++ `ASM_OUTPUT_BSS' nor `ASM_OUTPUT_ALIGNED_BSS' are defined,
++ uninitialized global data will be output in the data section if
++ `-fno-common' is passed, otherwise `ASM_OUTPUT_COMMON' will be
++ used.
++ */
++
++ /*
++ `SHARED_BSS_SECTION_ASM_OP'
++ If defined, a C expression whose value is a string containing the
++ assembler operation to identify the following data as
++ uninitialized global shared data. If not defined, and
++ `BSS_SECTION_ASM_OP' is, the latter will be used.
++ */
++ /*
++ `INIT_SECTION_ASM_OP'
++ If defined, a C expression whose value is a string containing the
++ assembler operation to identify the following data as
++ initialization code. If not defined, GNU CC will assume such a
++ section does not exist.
++ */
++ #define EXTRA_SECTIONS in_progmem
++ /*
++ `EXTRA_SECTIONS'
++ 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() \
++ { \
++ if (in_section != in_progmem) \
++ { \
++ fprintf (asm_out_file, AS_STR ("seg flash.progmem\n", \
++ ".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
++ /*XXX
++ 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'.
++ */
++
++ /* Defined in dbxelf.h
++ #define ASM_IDENTIFY_GCC(FILE) {}
++ A C statement to output assembler commands which will identify the
++ object file as having been compiled with GNU CC (or another GNU
++ compiler).
++
++ If you don't define this macro, the string `gcc_compiled.:' is
++ output. This string is calculated to define a symbol which, on
++ BSD systems, will never be defined for any other reason. GDB
++ checks for the presence of this symbol when reading the symbol
++ table of an executable.
++
++ On non-BSD systems, you must arrange communication with GDB in
++ some other fashion. If GDB is not used on your system, you can
++ define this macro with an empty body.
++ */
++
++ #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.
++ */
++
++ #if 0
++ #define ASM_OUTPUT_SOURCE_FILENAME(STREAM, NAME) \
++ fprintf (STREAM, "/* file: %s */\n", NAME)
++ #endif
++ /*
++ A C statement to output COFF information or DWARF debugging
++ information which indicates that filename NAME is the current
++ source file to the stdio stream STREAM.
++
++ This macro need not be defined if the standard form of output for
++ the file format in use is appropriate.
++ */
++
++ #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.
++ */
++ /*
++ `ASM_OUTPUT_IDENT (STREAM, STRING)'
++ A C statement to output something to the assembler file to handle a
++ `#ident' directive containing the text STRING. If this macro is
++ not defined, nothing is output for a `#ident' directive.
++ */
++
++ #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, AS_STR ("\tdc.l ", "\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 AS_STR("dc.b ",".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) avr_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'.
++ */
++ /*
++ `CONSTANT_POOL_BEFORE_FUNCTION'
++ You may define this macro as a C expression. You should define the
++ expression to have a non-zero value if GNU CC should output the
++ constant pool for a function before the code for the function, or
++ a zero value if GNU CC should output the constant pool after the
++ function. If you do not define this macro, the usual case, GNU CC
++ will output the constant pool before the function.
++ */
++ /*
++ `ASM_OUTPUT_POOL_PROLOGUE (FILE FUNNAME FUNDECL SIZE)'
++ A C statement to output assembler commands to define the start of
++ the constant pool for a function. FUNNAME is a string giving the
++ name of the function. Should the return type of the function be
++ required, it can be obtained via FUNDECL. SIZE is the size, in
++ bytes, of the constant pool that will be written immediately after
++ this call.
++
++ If no constant-pool prefix is required, the usual case, this macro
++ need not be defined.
++ */
++ /*
++ `ASM_OUTPUT_SPECIAL_POOL_ENTRY (FILE, X, MODE, ALIGN, LABELNO, JUMPTO)'
++ A C statement (with or without semicolon) to output a constant in
++ the constant pool, if it needs special treatment. (This macro
++ need not do anything for RTL expressions that can be output
++ normally.)
++
++ The argument FILE is the standard I/O stream to output the
++ assembler code on. X is the RTL expression for the constant to
++ output, and MODE is the machine mode (in case X is a `const_int').
++ ALIGN is the required alignment for the value X; you should
++ output an assembler directive to force this much alignment.
++
++ The argument LABELNO is a number to use in an internal label for
++ the address of this pool entry. The definition of this macro is
++ responsible for outputting the label definition at the proper
++ place. Here is how to do this:
++
++ ASM_OUTPUT_INTERNAL_LABEL (FILE, "LC", LABELNO);
++
++ When you output a pool entry specially, you should end with a
++ `goto' to the label JUMPTO. This will prevent the same pool entry
++ from being output a second time in the usual manner.
++
++ You need not define this macro if it would do nothing.
++ */
++ /*
++ `CONSTANT_AFTER_FUNCTION_P (EXP)'
++ Define this macro as a C expression which is nonzero if the
++ constant EXP, of type `tree', should be output after the code for a
++ function. The compiler will normally output all constants before
++ the function; you need not define this macro if this is OK.
++ */
++ /*
++ `ASM_OUTPUT_POOL_EPILOGUE (FILE FUNNAME FUNDECL SIZE)'
++ A C statement to output assembler commands to at the end of the
++ constant pool for a function. FUNNAME is a string giving the name
++ of the function. Should the return type of the function be
++ required, you can obtain it via FUNDECL. SIZE is the size, in
++ bytes, of the constant pool that GNU CC wrote immediately before
++ this call.
++
++ If no constant-pool epilogue is required, the usual case, you need
++ not define this macro.
++ */
++
++
++ #define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == '\n' \
++ || (!TARGET_AVA && (C) == '$'))
++ /*
++ #define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((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:
++ */
++ /*
++ `REAL_VALUE_TO_TARGET_SINGLE (X, L)'
++ `REAL_VALUE_TO_TARGET_DOUBLE (X, L)'
++ `REAL_VALUE_TO_TARGET_LONG_DOUBLE (X, L)'
++ These translate X, of type `REAL_VALUE_TYPE', to the target's
++ floating point representation, and store its bit pattern in the
++ array of `long int' whose address is L. The number of elements in
++ the output array is determined by the size of the desired target
++ floating point data type: 32 bits of it go in each `long int' array
++ element. Each array element holds 32 bits of the result, even if
++ `long int' is wider than 32 bits on the host machine.
++
++ The array element values are designed so that you can print them
++ out using `fprintf' in the order they should appear in the target
++ machine's memory.
++
++ `REAL_VALUE_TO_DECIMAL (X, FORMAT, STRING)'
++ This macro converts X, of type `REAL_VALUE_TYPE', to a decimal
++ number and stores it as a string into STRING. You must pass, as
++ STRING, the address of a long enough block of space to hold the
++ result.
++
++ The argument FORMAT is a `printf'-specification that serves as a
++ suggestion for how to format the output string.
++ */
++
++
++ #define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \
++ do { \
++ if (TARGET_AVA) \
++ { \
++ bss_section (); \
++ fprintf (STREAM,"public "); \
++ assemble_name (STREAM, NAME); \
++ fprintf (STREAM, \
++ ":\n\tds.b %d\t/* common label size: %d, rounded: %d */\n", \
++ ROUNDED, SIZE, ROUNDED); \
++ } \
++ else \
++ { \
++ 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.
++ */
++ /*
++ `ASM_OUTPUT_ALIGNED_COMMON (STREAM, NAME, SIZE, ALIGNMENT)'
++ Like `ASM_OUTPUT_COMMON' except takes the required alignment as a
++ separate, explicit argument. If you define this macro, it is used
++ in place of `ASM_OUTPUT_COMMON', and gives you more flexibility in
++ handling the required alignment of the variable. The alignment is
++ specified as the number of bits.
++ */
++ /*
++ `ASM_OUTPUT_SHARED_COMMON (STREAM, NAME, SIZE, ROUNDED)'
++ If defined, it is similar to `ASM_OUTPUT_COMMON', except that it
++ is used when NAME is shared. If not defined, `ASM_OUTPUT_COMMON'
++ will be used.
++ */
++
++ /*
++ #define ASM_OUTPUT_BSS(STREAM, DECL, NAME, SIZE, ROUNDED) asm_output_bss(STREAM, DECL, NAME, SIZE, ROUNDED)
++ A C statement (sans semicolon) to output to the stdio stream
++ STREAM the assembler definition of uninitialized global DECL named
++ NAME whose size is SIZE bytes. The variable ROUNDED is the size
++ rounded up to whatever alignment the caller wants.
++
++ Try to use function `asm_output_bss' defined in `varasm.c' when
++ defining this macro. If unable, 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
++ global variables are output. This macro exists to properly
++ support languages like `c++' which do not have `common' data.
++ However, this macro currently is not defined for all targets. If
++ this macro and `ASM_OUTPUT_ALIGNED_BSS' are not defined then
++ `ASM_OUTPUT_COMMON' or `ASM_OUTPUT_ALIGNED_COMMON' is used.
++
++ `ASM_OUTPUT_ALIGNED_BSS (STREAM, DECL, NAME, SIZE, ALIGNMENT)'
++ Like `ASM_OUTPUT_BSS' except takes the required alignment as a
++ separate, explicit argument. If you define this macro, it is used
++ in place of `ASM_OUTPUT_BSS', and gives you more flexibility in
++ handling the required alignment of the variable. The alignment is
++ specified as the number of bits.
++
++ Try to use function `asm_output_aligned_bss' defined in file
++ `varasm.c' when defining this macro.
++
++ `ASM_OUTPUT_SHARED_BSS (STREAM, DECL, NAME, SIZE, ROUNDED)'
++ If defined, it is similar to `ASM_OUTPUT_BSS', except that it is
++ used when NAME is shared. If not defined, `ASM_OUTPUT_BSS' will
++ be used.
++ */
++
++ #define ASM_OUTPUT_LOCAL(STREAM, NAME, SIZE, ROUNDED) \
++ do { \
++ if (TARGET_AVA) \
++ { \
++ bss_section (); \
++ assemble_name (STREAM, NAME); \
++ fprintf (STREAM, ":\tds.b %d\n", (SIZE)); \
++ } \
++ else \
++ { \
++ 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.
++ */
++ /*
++ `ASM_OUTPUT_ALIGNED_LOCAL (STREAM, NAME, SIZE, ALIGNMENT)'
++ Like `ASM_OUTPUT_LOCAL' except takes the required alignment as a
++ separate, explicit argument. If you define this macro, it is used
++ in place of `ASM_OUTPUT_LOCAL', and gives you more flexibility in
++ handling the required alignment of the variable. The alignment is
++ specified as the number of bits.
++ */
++ /*
++ `ASM_OUTPUT_SHARED_LOCAL (STREAM, NAME, SIZE, ROUNDED)'
++ If defined, it is similar to `ASM_OUTPUT_LOCAL', except that it is
++ used when NAME is shared. If not defined, `ASM_OUTPUT_LOCAL' will
++ be used.
++ */
++
++
++ #define ASM_OUTPUT_LABEL(STREAM, NAME) \
++ { \
++ if (TARGET_AVA && make_it_public) \
++ { \
++ make_it_public = 0; \
++ fprintf (STREAM, "public "); \
++ } \
++ 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 { \
++ if (!TARGET_AVA) \
++ { \
++ 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)
++ /*
++ `ASM_DECLARE_FUNCTION_NAME (STREAM, NAME, DECL)'
++ 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 && !TARGET_AVA) \
++ { \
++ 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)
++ /*
++ `ASM_DECLARE_FUNCTION_SIZE (STREAM, NAME, DECL)'
++ 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 { \
++ if (!TARGET_AVA) \
++ { \
++ 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)
++ /*
++ `ASM_DECLARE_OBJECT_NAME (STREAM, NAME, DECL)'
++ 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 \
++ && !TARGET_AVA) \
++ { \
++ 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)
++ /*
++ `ASM_FINISH_DECLARE_OBJECT (STREAM, DECL, TOPLEVEL, ATEND)'
++ 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.
++ */
++
++ extern int make_it_public;
++ #define ASM_GLOBALIZE_LABEL(STREAM, NAME) asm_globalize_label (STREAM, NAME)
++ /*
++ fprintf (STREAM, "\tpublic\t"); \
++ assemble_name (STREAM, NAME); \
++ fprintf (STREAM, "\n"); \
++ 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_EXTERNAL(STREAM, DECL, NAME) asm_output_external(STREAM, DECL, NAME)
++ /*
++ A C statement (sans semicolon) to output to the stdio stream
++ STREAM any text necessary for declaring the name of an external
++ symbol named NAME which is referenced in this compilation but not
++ defined. The value of DECL is the tree node for the declaration.
++
++ This macro need not be defined if it does not need to output
++ anything. The GNU assembler and most Unix assemblers don't
++ require anything.
++ */
++
++ #define ASM_OUTPUT_EXTERNAL_LIBCALL(STREAM, SYMREF) asm_output_external_libcall(STREAM, SYMREF)
++ /*
++ A C statement (sans semicolon) to output on STREAM an assembler
++ pseudo-op to declare a library function name external. The name
++ of the library function is given by SYMREF, which has type `rtx'
++ and is a `symbol_ref'.
++
++ This macro need not be defined if it does not need to output
++ anything. The GNU assembler and most Unix assemblers don't
++ require anything.
++ */
++
++ /*
++ #define ASM_OUTPUT_LABELREF(STREAM, NAME)
++ A C statement (sans semicolon) to output to the stdio stream
++ STREAM a reference in assembler syntax to a label named NAME.
++ This should add `_' to the front of the name, if that is customary
++ on your operating system, as it is in most Berkeley Unix systems.
++ This macro is used in `assemble_name'.
++ */
++
++ #define ASM_OUTPUT_INTERNAL_LABEL(STREAM, PREFIX, NUM) \
++ fprintf(STREAM, AS_STR("%s%d:\n", \
++ ".%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, AS_STR ("*%s%d", \
++ "*.%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), AS_STR ("%s_I_%d","%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.
++ */
++ /*XXX
++ #define ASM_OUTPUT_DEF(STREAM, NAME, VALUE) fprintf (STREAM, "equ\t%s = %d\n", NAME, VALUE)
++ A C statement to output to the stdio stream STREAM assembler code
++ which defines (equates) the symbol NAME to have the value VALUE.
++
++ If SET_ASM_OP is defined, a default definition is provided which is
++ correct for most systems.
++ */
++
++ /*
++ `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.
++ */
++ /*
++ `OBJC_GEN_METHOD_LABEL (BUF, IS_INST, CLASS_NAME, CAT_NAME, SEL_NAME)'
++ Define this macro to override the default assembler names used for
++ Objective C methods.
++
++ The default name is a unique method number followed by the name of
++ the class (e.g. `_1_Foo'). For methods in categories, the name of
++ the category is also included in the assembler name (e.g.
++ `_1_Foo_Bar').
++
++ These names are safe on most systems, but make debugging difficult
++ since the method's selector is not present in the name.
++ Therefore, particular systems define other ways of computing names.
++
++ BUF is an expression of type `char *' which gives you a buffer in
++ which to store the name; its length is as long as CLASS_NAME,
++ CAT_NAME and SEL_NAME put together, plus 50 characters extra.
++
++ The argument IS_INST specifies whether the method is an instance
++ method or a class method; CLASS_NAME is the name of the class;
++ CAT_NAME is the name of the category (or NULL if the method is not
++ in a category); and SEL_NAME is the name of the selector.
++
++ On systems where the assembler can handle quoted names, you can
++ use this macro to provide more human-readable names.
++ */
++ #define HAS_INIT_SECTION 1
++ /*
++ `HAS_INIT_SECTION'
++ 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.
++ */
++ /*
++ `ADDITIONAL_REGISTER_NAMES'
++ If defined, a C initializer for an array of structures containing
++ a name and a register number. This macro defines additional names
++ for hard registers, thus allowing the `asm' option in declarations
++ to refer to registers using alternate names.
++ */
++ /*
++ `ASM_OUTPUT_OPCODE (STREAM, PTR)'
++ Define this macro if you are using an unusual assembler that
++ requires different names for the machine instructions.
++
++ The definition is a C statement or statements which output an
++ assembler instruction opcode to the stdio stream STREAM. The
++ macro-operand PTR is a variable of type `char *' which points to
++ the opcode name in its "internal" form--the form that is written
++ in the machine description. The definition should output the
++ opcode name to STREAM, performing any translation you desire, and
++ increment the variable PTR to point at the end of the opcode so
++ that it will not be output twice.
++
++ In fact, your macro definition may process less than the entire
++ opcode name, or more than the opcode name; but if you want to
++ process text that includes `%'-sequences to substitute operands,
++ you must take care of the substitution yourself. Just be sure to
++ increment PTR over whatever text should not be output normally.
++
++ If you need to look at the operand values, they can be found as the
++ elements of `recog_operand'.
++
++ If the macro definition does nothing, the instruction is output in
++ the usual way.
++ */
++
++ #define FINAL_PRESCAN_INSN(insn, operand, nop) final_prescan_insn (insn, operand,nop)
++ /*
++ `FINAL_PRESCAN_INSN (INSN, OPVEC, NOPERANDS)'
++ 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.
++ */
++ /*
++ `FINAL_PRESCAN_LABEL'
++ If defined, `FINAL_PRESCAN_INSN' will be called on each
++ `CODE_LABEL'. In that case, OPVEC will be a null pointer and
++ NOPERANDS will be zero.
++ */
++ #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) == '~')
++ /*
++ `PRINT_OPERAND_PUNCT_VALID_P (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)
++ /* XXX
++ 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::.
++ */
++ /*
++ `DBR_OUTPUT_SEQEND(FILE)'
++ A C statement, to be executed after all slot-filler instructions
++ have been output. If necessary, call `dbr_sequence_length' to
++ determine the number of slots filled in a sequence (zero if not
++ currently outputting a sequence), to decide how many no-ops to
++ output, or whatever.
++
++ Don't define this macro if it has nothing to do, but it is helpful
++ in reading assembly output if the extent of the delay sequence is
++ made explicit (e.g. with white space).
++
++ Note that output routines for instructions with delay slots must be
++ prepared to deal with not being output as part of a sequence (i.e.
++ when the scheduling pass is not run, or when no slot fillers could
++ be found.) The variable `final_sequence' is null when not
++ processing a sequence, otherwise it contains the `sequence' rtx
++ being output.
++ */
++
++ #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.
++ */
++ /*
++ `ASSEMBLER_DIALECT'
++ If your target supports multiple dialects of assembler language
++ (such as different opcodes), define this macro as a C expression
++ that gives the numeric index of the assembler language dialect to
++ use, with zero as the first variant.
++
++ If this macro is defined, you may use constructs of the form
++ `{option0|option1|option2...}' in the output templates of patterns
++ (*note Output Template::.) or in the first argument of
++ `asm_fprintf'. This construct outputs `option0', `option1' or
++ `option2', etc., if the value of `ASSEMBLER_DIALECT' is zero, one
++ or two, etc. Any special characters within these strings retain
++ their usual meaning.
++
++ If you do not define this macro, the characters `{', `|' and `}'
++ do not have any special meaning when used in templates or operands
++ to `asm_fprintf'.
++
++ Define the macros `REGISTER_PREFIX', `LOCAL_LABEL_PREFIX',
++ `USER_LABEL_PREFIX' and `IMMEDIATE_PREFIX' if you can express the
++ variations in assemble language syntax with that mechanism. Define
++ `ASSEMBLER_DIALECT' and use the `{option0|option1}' syntax if the
++ syntax variant are larger and involve such things as different
++ opcodes or operand order.
++ */
++
++ #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_DIFF_ELT(STREAM, VALUE, REL) ASM_OUTPUT_ADDR_VEC_ELT(STREAM, VALUE)
++ A C statement to output to the stdio stream STREAM an assembler
++ pseudo-instruction to generate a difference between two labels.
++ VALUE and REL are the numbers of two internal labels. The
++ definitions of these labels are output using
++ `ASM_OUTPUT_INTERNAL_LABEL', and they must be printed in the same
++ way here. For example,
++
++ fprintf (STREAM, "\t.word L%d-L%d\n",
++ VALUE, REL)
++
++ You must provide this macro on machines where the addresses in a
++ dispatch table are relative to the table's own address. If
++ defined, GNU CC will also use this macro on all machines when
++ producing PIC.
++ */
++
++ #define ASM_OUTPUT_ADDR_VEC_ELT(STREAM, VALUE) \
++ fprintf (STREAM, AS_STR ("\tdc.w (L%d)/2\n", "\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.
++ */
++
++ /*
++ `ASM_OUTPUT_ALIGN_CODE (FILE)'
++ A C expression to output text to align the location counter in the
++ way that is desirable at a point in the code that is reached only
++ by jumping.
++
++ This macro need not be defined if you don't want any special
++ alignment to be done at such a time. Most machine descriptions do
++ not currently define the macro.
++ */
++ /*
++ `ASM_OUTPUT_LOOP_ALIGN (FILE)'
++ A C expression to output text to align the location counter in the
++ way that is desirable at the beginning of a loop.
++
++ This macro need not be defined if you don't want any special
++ alignment to be done at such a time. Most machine descriptions do
++ not currently define the macro.
++ */
++
++ #define ASM_OUTPUT_SKIP(STREAM, n) \
++ fprintf (STREAM, AS_STR ("\tds.b %d\n", \
++ "\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_NO_SKIP_IN_TEXT
++ Define this macro if `ASM_OUTPUT_SKIP' should not be used in the
++ text section because it fails put zeros in the bytes that are
++ skipped. This is true on many Unix systems, where the pseudo-op
++ to skip bytes produces no-op instructions rather than zeros when
++ used in the text section.
++ */
++
++ #define ASM_OUTPUT_ALIGN(STREAM, POWER)
++ /*XXX
++ 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'.
++ */
++
++ /*
++ `PREDICATE_CODES'
++ Define this if you have defined special-purpose predicates in the
++ file `MACHINE.c'. This macro is called within an initializer of an
++ array of structures. The first field in the structure is the name
++ of a predicate and the second field is an array of rtl codes. For
++ each predicate, list all rtl codes that can be in expressions
++ matched by the predicate. The list should have a trailing comma.
++ Here is an example of two entries in the list for a typical RISC
++ machine:
++
++ #define PREDICATE_CODES \
++ {"gen_reg_rtx_operand", {SUBREG, REG}}, \
++ {"reg_or_short_cint_operand", {SUBREG, REG, CONST_INT}},
++
++ Defining this macro does not affect the generated code (however,
++ incorrect definitions that omit an rtl code that may be matched by
++ the predicate can cause the compiler to malfunction). Instead, it
++ allows the table built by `genrecog' to be more compact and
++ efficient, thus speeding up the compiler. The most important
++ predicates to include in the list specified by this macro are
++ thoses used in the most insn patterns.
++ */
++ #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_VECTOR_PC_RELATIVE
++ Define this macro if jump-tables should contain relative addresses.
++ */
++ /*
++ `CASE_DROPS_THROUGH'
++ Define this if control falls through a `case' insn when the index
++ value is out of range. This means the specified default-label is
++ actually ignored by the `case' insn proper.
++ */
++
++ #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.
++ */
++ /*
++ `LOAD_EXTEND_OP (MODE)'
++ Define this macro to be a C expression indicating when insns that
++ read memory in MODE, an integral mode narrower than a word, set the
++ bits outside of MODE to be either the sign-extension or the
++ zero-extension of the data read. Return `SIGN_EXTEND' for values
++ of MODE for which the insn sign-extends, `ZERO_EXTEND' for which
++ it zero-extends, and `NIL' for other modes.
++
++ This macro is not called with MODE non-integral or with a width
++ greater than or equal to `BITS_PER_WORD', so you may return any
++ value in this case. Do not define this macro if it would always
++ return `NIL'. On machines where this macro is defined, you will
++ normally define it as the constant `SIGN_EXTEND' or `ZERO_EXTEND'.
++ */
++ /*
++ `SHORT_IMMEDIATES_SIGN_EXTEND'
++ Define this macro if loading short immediate values into registers
++ sign extends.
++ */
++ /*
++ `IMPLICIT_FIX_EXPR'
++ An alias for a tree code that should be used by default for
++ conversion of floating point values to fixed point. Normally,
++ `FIX_ROUND_EXPR' is used.
++ */
++ /*
++ `FIXUNS_TRUNC_LIKE_FIX_TRUNC'
++ Define this macro if the same instructions that convert a floating
++ point number to a signed fixed point number also convert validly
++ to an unsigned one.
++ */
++
++ #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.
++ */
++ /*
++ `MAX_MOVE_MAX'
++ The maximum number of bytes that a single instruction can move
++ quickly between memory and registers or between two memory
++ locations. If this is undefined, the default is `MOVE_MAX'.
++ Otherwise, it is the constant value that is the largest value that
++ `MOVE_MAX' can have at run-time.
++ */
++ /*
++ `SHIFT_COUNT_TRUNCATED'
++ A C expression that is nonzero if on this machine the number of
++ bits actually used for the count of a shift operation is equal to
++ the number of bits needed to represent the size of the object
++ being shifted. When this macro is non-zero, the compiler will
++ assume that it is safe to omit a sign-extend, zero-extend, and
++ certain bitwise `and' instructions that truncates the count of a
++ shift operation. On machines that have instructions that act on
++ bitfields at variable positions, which may include `bit test'
++ instructions, a nonzero `SHIFT_COUNT_TRUNCATED' also enables
++ deletion of truncations of the values that serve as arguments to
++ bitfield instructions.
++
++ If both types of instructions truncate the count (for shifts) and
++ position (for bitfield operations), or if no variable-position
++ bitfield instructions exist, you should define this macro.
++
++ However, on some machines, such as the 80386 and the 680x0,
++ truncation only applies to shift operations and not the (real or
++ pretended) bitfield operations. Define `SHIFT_COUNT_TRUNCATED' to
++ be zero on such machines. Instead, add patterns to the `md' file
++ that include the implied truncation of the shift instructions.
++
++ You need not define this macro if it would always have the value
++ of zero.
++ */
++
++ #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 STORE_FLAG_VALUE 1
++ A C expression describing the value returned by a comparison
++ operator with an integral mode and stored by a store-flag
++ instruction (`sCOND') when the condition is true. This
++ description must apply to *all* the `sCOND' patterns and all the
++ comparison operators whose results have a `MODE_INT' mode.
++
++ A value of 1 or -1 means that the instruction implementing the
++ comparison operator returns exactly 1 or -1 when the comparison is
++ true and 0 when the comparison is false. Otherwise, the value
++ indicates which bits of the result are guaranteed to be 1 when the
++ comparison is true. This value is interpreted in the mode of the
++ comparison operation, which is given by the mode of the first
++ operand in the `sCOND' pattern. Either the low bit or the sign
++ bit of `STORE_FLAG_VALUE' be on. Presently, only those bits are
++ used by the compiler.
++
++ If `STORE_FLAG_VALUE' is neither 1 or -1, the compiler will
++ generate code that depends only on the specified bits. It can also
++ replace comparison operators with equivalent operations if they
++ cause the required bits to be set, even if the remaining bits are
++ undefined. For example, on a machine whose comparison operators
++ return an `SImode' value and where `STORE_FLAG_VALUE' is defined as
++ `0x80000000', saying that just the sign bit is relevant, the
++ expression
++
++ (ne:SI (and:SI X (const_int POWER-OF-2)) (const_int 0))
++
++ can be converted to
++
++ (ashift:SI X (const_int N))
++
++ where N is the appropriate shift count to move the bit being
++ tested into the sign bit.
++
++ There is no way to describe a machine that always sets the
++ low-order bit for a true value, but does not guarantee the value
++ of any other bits, but we do not know of any machine that has such
++ an instruction. If you are trying to port GNU CC to such a
++ machine, include an instruction to perform a logical-and of the
++ result with 1 in the pattern for the comparison operators and let
++ us know (*note How to Report Bugs: Bug Reporting.).
++
++ Often, a machine will have multiple instructions that obtain a
++ value from a comparison (or the condition codes). Here are rules
++ to guide the choice of value for `STORE_FLAG_VALUE', and hence the
++ instructions to be used:
++
++ * Use the shortest sequence that yields a valid definition for
++ `STORE_FLAG_VALUE'. It is more efficient for the compiler to
++ "normalize" the value (convert it to, e.g., 1 or 0) than for
++ the comparison operators to do so because there may be
++ opportunities to combine the normalization with other
++ operations.
++
++ * For equal-length sequences, use a value of 1 or -1, with -1
++ being slightly preferred on machines with expensive jumps and
++ 1 preferred on other machines.
++
++ * As a second choice, choose a value of `0x80000001' if
++ instructions exist that set both the sign and low-order bits
++ but do not define the others.
++
++ * Otherwise, use a value of `0x80000000'.
++
++ Many machines can produce both the value chosen for
++ `STORE_FLAG_VALUE' and its negation in the same number of
++ instructions. On those machines, you should also define a pattern
++ for those cases, e.g., one matching
++
++ (set A (neg:M (ne:M B C)))
++
++ Some machines can also perform `and' or `plus' operations on
++ condition code values with less instructions than the corresponding
++ `sCOND' insn followed by `and' or `plus'. On those machines,
++ define the appropriate patterns. Use the names `incscc' and
++ `decscc', respectively, for the patterns which perform `plus' or
++ `minus' operations on condition code values. See `rs6000.md' for
++ some examples. The GNU Superoptizer can be used to find such
++ instruction sequences on other machines.
++
++ You need not define `STORE_FLAG_VALUE' if the machine has no
++ store-flag instructions.
++ */
++ /*
++ `FLOAT_STORE_FLAG_VALUE'
++ A C expression that gives a non-zero floating point value that is
++ returned when comparison operators with floating-point results are
++ true. Define this macro on machine that have comparison
++ operations that return floating-point values. If there are no
++ such operations, do not define this macro.
++ */
++ #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))
++
++ /*
++ `INTEGRATE_THRESHOLD (DECL)'
++ 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.
++ */
++ /*
++ `SCCS_DIRECTIVE'
++ Define this if the preprocessor should ignore `#sccs' directives
++ and print no error message.
++ */
++ /*
++ `NO_IMPLICIT_EXTERN_C'
++ Define this macro if the system header files support C++ as well
++ as C. This macro inhibits the usual method of using system header
++ files in C++, which is to pretend that the file's contents are
++ enclosed in `extern "C" {...}'.
++ */
++ /*
++ `HANDLE_PRAGMA (STREAM, NODE)'
++ Define this macro if you want to implement any pragmas. If
++ defined, it is a C expression whose value is 1 if the pragma was
++ handled by the function. The argument STREAM is the stdio input
++ stream from which the source text can be read. NODE is the tree
++ node for the identifier after the `#pragma'.
++
++ It is generally a bad idea to implement new uses of `#pragma'. The
++ only reason to define this macro is for compatibility with other
++ compilers that do support `#pragma' for the sake of any user
++ programs which already use it.
++ */
++
++ #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.
++ */
++ /*
++ `COMP_TYPE_ATTRIBUTES (TYPE1, TYPE2)'
++ If defined, a C expression whose value is zero if the attributes on
++ TYPE1 and TYPE2 are incompatible, one if they are compatible, and
++ two if they are nearly compatible (which causes a warning to be
++ generated).
++
++ `SET_DEFAULT_TYPE_ATTRIBUTES (TYPE)'
++ If defined, a C statement that assigns default attributes to newly
++ defined 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 NO_DOT_IN_LABEL !!TARGET_AVA
++ /*
++ Define this macro if the assembler does not accept the character
++ `.' in label names. By default constructors and destructors in G++
++ have names that use `.'. If this macro is defined, these names
++ are rewritten to avoid `.'.
++ */
++ /*
++ `DEFAULT_MAIN_RETURN'
++ Define this macro if the target system expects every program's
++ `main' function to return a standard "success" value by default
++ (if no other value is explicitly returned).
++
++ The definition should be a C statement (sans semicolon) to
++ generate the appropriate rtl instructions. It is used only when
++ compiling the end of `main'.
++ */
++ /*
++ `HAVE_ATEXIT'
++ Define this if the target system supports the function `atexit'
++ from the ANSI C standard. If this is not defined, and
++ `INIT_SECTION_ASM_OP' is not defined, a default `exit' function
++ will be provided to support C++.
++ */
++ /*
++ `EXIT_BODY'
++ Define this if your `exit' function needs to do something besides
++ calling an external function `_cleanup' before terminating with
++ `_exit'. The `EXIT_BODY' macro is only needed if netiher
++ `HAVE_ATEXIT' nor `INIT_SECTION_ASM_OP' are defined.
++ */
++ /*
++ `INSN_SETS_ARE_DELAYED (INSN)'
++ Define this macro as a C expression that is nonzero if it is safe
++ for the delay slot scheduler to place instructions in the delay
++ slot of INSN, even if they appear to use a resource set or
++ clobbered in INSN. INSN is always a `jump_insn' or an `insn'; GNU
++ CC knows that every `call_insn' has this behavior. On machines
++ where some `insn' or `jump_insn' is really a function call and
++ hence has this behavior, you should define this macro.
++
++ You need not define this macro if it would always return zero.
++
++ `INSN_REFERENCES_ARE_DELAYED (INSN)'
++ Define this macro as a C expression that is nonzero if it is safe
++ for the delay slot scheduler to place instructions in the delay
++ slot of INSN, even if they appear to set or clobber a resource
++ referenced in INSN. INSN is always a `jump_insn' or an `insn'.
++ On machines where some `insn' or `jump_insn' is really a function
++ call and its operands are registers whose use is actually in the
++ subroutine it calls, you should define this macro. Doing so
++ allows the delay slot scheduler to move instructions which copy
++ arguments into the argument registers into the delay slot of INSN.
++
++ You need not define this macro if it would always return zero.
++ */
++
++ #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.
++ */
++ /*
++ `MULTIPLE_SYMBOL_SPACES'
++ Define this macro if in some cases global symbols from one
++ translation unit may not be bound to undefined symbols in another
++ translation unit without user intervention. For instance, under
++ Microsoft Windows symbols must be explicitly imported from shared
++ libraries (DLLs).
++ */
++
++ #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.
++ */
++ /*
++ `ISSUE_RATE'
++ A C expression that returns how many instructions can be issued at
++ the same time if the machine is a superscalar machine. This is
++ only used by the `Haifa' scheduler, and not the traditional
++ scheduler.
++ */
++
++
++
++ /* 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
++
++
++
++ /* Output assembler code for a block containing the constant parts
++ of a trampoline, leaving space for the variable parts.
++
++ H8/300
++ vvvv context
++ 1 0000 7900xxxx mov.w #0x1234,r3
++ 2 0004 5A00xxxx jmp @0x1234
++ ^^^^ function
++
++ H8/300H
++ vvvvvvvv context
++ 2 0000 7A00xxxxxxxx mov.l #0x12345678,er3
++ 3 0006 5Axxxxxx jmp @0x123456
++ ^^^^^^ function
++ */
++
++ #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))
++
++
++ /* Define the information needed to generate branch and scc insns. This is
++ stored from the compare operation. Note that we can't use "rtx" here
++ since it hasn't been defined! */
++ extern struct rtx_def *avr_compare_op0, *avr_compare_op1;
++ extern struct rtx_def * (*avr_compare_gen)();
++ extern int avr_compare_fp_p;
++
++
++ /*
++ #define EXTRA_CC_MODES PMmode
++ A list of names to be used for additional modes for condition code
++ values in registers (*note Jump Patterns::.). These names are
++ added to `enum machine_mode' and all have class `MODE_CC'. By
++ convention, they should start with `CC' and end with `mode'.
++
++ You should only define this macro if your machine does not use
++ `cc0' and only if additional modes are required.
++ */
++ /*
++ #define EXTRA_CC_NAMES "PMmode"
++ A list of C strings giving the names for the modes listed in
++ `EXTRA_CC_MODES'. For example, the Sparc defines this macro and
++ `EXTRA_CC_MODES' as
++
++ #define EXTRA_CC_MODES CC_NOOVmode, CCFPmode, CCFPEmode
++ #define EXTRA_CC_NAMES "CC_NOOV", "CCFP", "CCFPE"
++
++ This macro is not required if `EXTRA_CC_MODES' is not defined.
++ */
++
++ /*
++ #define SELECT_CC_MODE(OP, X, Y) CCmode
++ Returns a mode from class `MODE_CC' to be used when comparison
++ operation code OP is applied to rtx X and Y. For example, on the
++ Sparc, `SELECT_CC_MODE' is defined as (see *note Jump Patterns::.
++ for a description of the reason for this definition)
++
++ #define SELECT_CC_MODE(OP,X,Y) \
++ (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT \
++ ? ((OP == EQ || OP == NE) ? CCFPmode : CCFPEmode) \
++ : ((GET_CODE (X) == PLUS || GET_CODE (X) == MINUS \
++ || GET_CODE (X) == NEG) \
++ ? CC_NOOVmode : CCmode))
++
++ You need not define this macro if `EXTRA_CC_MODES' is not defined.
++ */
++
++ /*
++ #define CANONICALIZE_COMPARISON(CODE, OP0, OP1) (CODE) = canonicalize_comparison(CODE,&(OP0), &(OP1))
++ One some machines not all possible comparisons are defined, but
++ you can convert an invalid comparison into a valid one. For
++ example, the Alpha does not have a `GT' comparison, but you can
++ use an `LT' comparison instead and swap the order of the operands.
++
++ On such machines, define this macro to be a C statement to do any
++ required conversions. CODE is the initial comparison code and OP0
++ and OP1 are the left and right operands of the comparison,
++ respectively. You should modify CODE, OP0, and OP1 as required.
++
++ GNU CC will not assume that the comparison resulting from this
++ macro is valid but will see if the resulting insn matches a
++ pattern in the `md' file.
++
++ You need not define this macro if it would never change the
++ comparison code or operands.
++ */
++
++ /*
++ `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
++ /*
++ `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'.
++ */
++
++ /*
++ `SWITCH_TAKES_ARG (CHAR)'
++ A C expression which determines whether the option `-CHAR' takes
++ arguments. The value should be the number of arguments that
++ option takes-zero, for many options.
++
++ By default, this macro is defined as `DEFAULT_SWITCH_TAKES_ARG',
++ which handles the standard options properly. You need not define
++ `SWITCH_TAKES_ARG' unless you wish to add additional options which
++ take arguments. Any redefinition should call
++ `DEFAULT_SWITCH_TAKES_ARG' and then check for additional options.
++
++ `WORD_SWITCH_TAKES_ARG (NAME)'
++ A C expression which determines whether the option `-NAME' takes
++ arguments. The value should be the number of arguments that
++ option takes-zero, for many options. This macro rather than
++ `SWITCH_TAKES_ARG' is used for multi-character option names.
++
++ By default, this macro is defined as
++ `DEFAULT_WORD_SWITCH_TAKES_ARG', which handles the standard options
++ properly. You need not define `WORD_SWITCH_TAKES_ARG' unless you
++ wish to add additional options which take arguments. Any
++ redefinition should call `DEFAULT_WORD_SWITCH_TAKES_ARG' and then
++ check for additional options.
++
++ `SWITCH_CURTAILS_COMPILATION (CHAR)'
++ A C expression which determines whether the option `-CHAR' stops
++ compilation before the generation of an executable. The value is
++ boolean, non-zero if the option does stop an executable from being
++ generated, zero otherwise.
++
++ By default, this macro is defined as
++ `DEFAULT_SWITCH_CURTAILS_COMPILATION', which handles the standard
++ options properly. You need not define
++ `SWITCH_CURTAILS_COMPILATION' unless you wish to add additional
++ options which affect the generation of an executable. Any
++ redefinition should call `DEFAULT_SWITCH_CURTAILS_COMPILATION' and
++ then check for additional options.
++
++ `SWITCHES_NEED_SPACES'
++ A string-valued C expression which enumerates the options for which
++ the linker needs a space between the option and its argument.
++
++ If this macro is not defined, the default value is `""'.
++ */
++
++ #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.
++ */
++
++ /*
++ `CC1PLUS_SPEC'
++ A C string constant that tells the GNU CC driver program options to
++ pass to `cc1plus'. It can also specify how to translate options
++ you give to GNU CC into options for GNU CC to pass to the
++ `cc1plus'.
++
++ Do not define this macro if it does not need to do anything.
++ */
++
++ #define ASM_SPEC "%{mava:-favr_noendianbug}"
++ /*
++ 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 "\
++ %{mava:--motorola -favr_noendianbug} \
++ %{!mava: \
++ %{!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 avr44xx} \
++ %{mmcu=at90s4434:-m avr44xx} \
++ %{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 "\
++ %{mava: \
++ %{!mmcu*:libgcc.o%s libc/%s} \
++ %{mmcu=atmega*:libgcc-mega.o%s libc-mega/%s} \
++ %{mmcu=at90s*|mmcu=attiny22:libgcc.o%s libc/%s}} \
++ %{!mava: \
++ %{!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 "\
++ %{!mava: \
++ %{mmcu=atmega*:-lgcc-mega} \
++ %{!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 "%{mava:%(crt_ava)} %{!mava:%(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 "\
++ %{mava: \
++ %{!mmcu*:crtn.o%s} \
++ %{mmcu=atmega*:crtn-mega.o%s} \
++ %{mmcu=at90s*:crtn.o%s} \
++ }"
++ /*
++ 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_AVA_SPECS "\
++ %{!mmcu*:crt1-8515.o%s} \
++ %{mmcu=atmega603:crt1-mega603.o%s} \
++ %{mmcu=atmega103:crt1-mega103.o%s} \
++ %{mmcu=at90s2313:crt1-2313.o%s} \
++ %{mmcu=at90s2323:crt1-2323.o%s} \
++ %{mmcu=attiny22:crt1-tiny22.o%s} \
++ %{mmcu=at90s2333:crt1-2333.o%s} \
++ %{mmcu=at90s2343:crt1-2343.o%s} \
++ %{mmcu=at90s4433:crt1-4433.o%s} \
++ %{mmcu=at90s4414:crt1-4414.o%s} \
++ %{mmcu=at90s4434:crt1-4434.o%s} \
++ %{mmcu=at90s8535:crt1-8535.o%s} \
++ %{mmcu=at90s8515:crt1-8515.o%s}"
++
++ #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_ava", CRT_AVA_SPECS}, \
++ {"crt_binutils", CRT_BINUTILS_SPECS},
++ /*
++ `EXTRA_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 "%{mava:ava} %{!mava:ld}"
++
++ #define LINK_LIBGCC_SPECIAL
++
++ /*
++ `LINK_LIBGCC_SPECIAL'
++ Define this macro if the driver program should find the library
++ `libgcc.a' itself and should not pass `-L' options to the linker.
++ If you do not define this macro, the driver program will pass the
++ argument `-lgcc' to tell the linker to do the search and will pass
++ `-L' options to it.
++
++ `LINK_LIBGCC_SPECIAL_1'
++ Define this macro if the driver program should find the library
++ `libgcc.a'. If you do not define this macro, the driver program
++ will pass the argument `-lgcc' to tell the linker to do the search.
++ This macro is similar to `LINK_LIBGCC_SPECIAL', except that it does
++ not affect `-L' options.
++ */
++
++ #define LINK_COMMAND_SPEC "\
++ %{!fsyntax-only: \
++ %{!c:%{!M:%{!MM:%{!E:%{!S:%(linker) %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n}\
++ %{r} %{s} %{t} %{u*} %{x} %{z} %{Z}\
++ %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
++ %{static:} %{!mava: %{L*} %D} %o\
++ %{!nostdlib:%{!nodefaultlibs:%G %L %G}}\
++ %{!A:%{!nostdlib:%{!nostartfiles:%E}}}\
++ %{T*}\
++ \n }}}}}}";
++
++ /*
++ A C string constant giving the complete command line need to
++ execute the linker. When you do this, you will need to update
++ your port each time a change is made to the link command line
++ within `gcc.c'. Therefore, define this macro only if you need to
++ completely redefine the command line for invoking the linker and
++ there is no other way to accomplish the effect you need.
++
++ `MULTILIB_DEFAULTS'
++ Define this macro as a C expression for the initializer of an
++ array of string to tell the driver program which options are
++ defaults for this target and thus do not need to be handled
++ specially when using `MULTILIB_OPTIONS'.
++
++ Do not define this macro if `MULTILIB_OPTIONS' is not defined in
++ the target makefile fragment or if none of the options listed in
++ `MULTILIB_OPTIONS' are set by default. *Note Target Fragment::.
++
++ `RELATIVE_PREFIX_NOT_LINKDIR'
++ Define this macro to tell `gcc' that it should only translate a
++ `-B' prefix into a `-L' linker option if the prefix indicates an
++ absolute file name.
++
++ `STANDARD_EXEC_PREFIX'
++ Define this macro as a C string constant if you wish to override
++ the standard choice of `/usr/local/lib/gcc-lib/' as the default
++ prefix to try when searching for the executable files of the
++ compiler.
++
++ `MD_EXEC_PREFIX'
++ If defined, this macro is an additional prefix to try after
++ `STANDARD_EXEC_PREFIX'. `MD_EXEC_PREFIX' is not searched when the
++ `-b' option is used, or the compiler is built as a cross compiler.
++
++ `STANDARD_STARTFILE_PREFIX'
++ Define this macro as a C string constant if you wish to override
++ the standard choice of `/usr/local/lib/' as the default prefix to
++ try when searching for startup files such as `crt0.o'.
++
++ `MD_STARTFILE_PREFIX'
++ If defined, this macro supplies an additional prefix to try after
++ the standard prefixes. `MD_EXEC_PREFIX' is not searched when the
++ `-b' option is used, or when the compiler is built as a cross
++ compiler.
++
++ `MD_STARTFILE_PREFIX_1'
++ If defined, this macro supplies yet another prefix to try after the
++ standard prefixes. It is not searched when the `-b' option is
++ used, or when the compiler is built as a cross compiler.
++
++ `INIT_ENVIRONMENT'
++ Define this macro as a C string constant if you wish to set
++ environment variables for programs called by the driver, such as
++ the assembler and loader. The driver passes the value of this
++ macro to `putenv' to initialize the necessary environment
++ variables.
++
++ `LOCAL_INCLUDE_DIR'
++ Define this macro as a C string constant if you wish to override
++ the standard choice of `/usr/local/include' as the default prefix
++ to try when searching for local header files. `LOCAL_INCLUDE_DIR'
++ comes before `SYSTEM_INCLUDE_DIR' in the search order.
++
++ Cross compilers do not use this macro and do not search either
++ `/usr/local/include' or its replacement.
++
++ `SYSTEM_INCLUDE_DIR'
++ Define this macro as a C string constant if you wish to specify a
++ system-specific directory to search for header files before the
++ standard directory. `SYSTEM_INCLUDE_DIR' comes before
++ `STANDARD_INCLUDE_DIR' in the search order.
++
++ Cross compilers do not use this macro and do not search the
++ directory specified.
++
++ `STANDARD_INCLUDE_DIR'
++ Define this macro as a C string constant if you wish to override
++ the standard choice of `/usr/include' as the default prefix to try
++ when searching for header files.
++
++ Cross compilers do not use this macro and do not search either
++ `/usr/include' or its replacement.
++
++ `STANDARD_INCLUDE_COMPONENT'
++ The "component" corresponding to `STANDARD_INCLUDE_DIR'. See
++ `INCLUDE_DEFAULTS', below, for the description of components. If
++ you do not define this macro, no component is used.
++
++ `INCLUDE_DEFAULTS'
++ Define this macro if you wish to override the entire default
++ search path for include files. For a native compiler, the default
++ search path usually consists of `GCC_INCLUDE_DIR',
++ `LOCAL_INCLUDE_DIR', `SYSTEM_INCLUDE_DIR',
++ `GPLUSPLUS_INCLUDE_DIR', and `STANDARD_INCLUDE_DIR'. In addition,
++ `GPLUSPLUS_INCLUDE_DIR' and `GCC_INCLUDE_DIR' are defined
++ automatically by `Makefile', and specify private search areas for
++ GCC. The directory `GPLUSPLUS_INCLUDE_DIR' is used only for C++
++ programs.
++
++ The definition should be an initializer for an array of structures.
++ Each array element should have four elements: the directory name (a
++ string constant), the component name, and flag for C++-only
++ directories, and a flag showing that the includes in the directory
++ don't need to be wrapped in `extern `C'' when compiling C++. Mark
++ the end of the array with a null element.
++
++ The component name denotes what GNU package the include file is
++ part of, if any, in all upper-case letters. For example, it might
++ be `GCC' or `BINUTILS'. If the package is part of the a
++ vendor-supplied operating system, code the component name as `0'.
++
++ For example, here is the definition used for VAX/VMS:
++
++ #define INCLUDE_DEFAULTS \
++ { \
++ { "GNU_GXX_INCLUDE:", "G++", 1, 1}, \
++ { "GNU_CC_INCLUDE:", "GCC", 0, 0}, \
++ { "SYS$SYSROOT:[SYSLIB.]", 0, 0, 0}, \
++ { ".", 0, 0, 0}, \
++ { 0, 0, 0, 0} \
++ }
++
++ Here is the order of prefixes tried for exec files:
++
++ 1. Any prefixes specified by the user with `-B'.
++
++ 2. The environment variable `GCC_EXEC_PREFIX', if any.
++
++ 3. The directories specified by the environment variable
++ `COMPILER_PATH'.
++
++ 4. The macro `STANDARD_EXEC_PREFIX'.
++
++ 5. `/usr/lib/gcc/'.
++
++ 6. The macro `MD_EXEC_PREFIX', if any.
++
++ Here is the order of prefixes tried for startfiles:
++
++ 1. Any prefixes specified by the user with `-B'.
++
++ 2. The environment variable `GCC_EXEC_PREFIX', if any.
++
++ 3. The directories specified by the environment variable
++ `LIBRARY_PATH' (native only, cross compilers do not use this).
++
++ 4. The macro `STANDARD_EXEC_PREFIX'.
++
++ 5. `/usr/lib/gcc/'.
++
++ 6. The macro `MD_EXEC_PREFIX', if any.
++
++ 7. The macro `MD_STARTFILE_PREFIX', if any.
++
++ 8. The macro `STANDARD_STARTFILE_PREFIX'.
++
++ 9. `/lib/'.
++
++ 10. `/usr/lib/'.
++
++ */
++
++ #define TEST_HARD_REG_CLASS(CLASS, REGNO) \
++ TEST_HARD_REG_BIT (reg_class_contents[ (int) (CLASS)], REGNO)
++
++ /* #define PRESERVE_DEATH_INFO_REGNO_P(r) 1 */
++
++ /* 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"
++
++ extern void asm_output_external_libcall ();
++ extern void asm_output_external ();
++ extern void avr_output_ascii ();
++ extern void unique_section ();
++ extern void encode_section_info ();
++ extern void asm_output_section_name ();
++ extern int legitimate_address_p ();
++ extern int function_arg_regno_p ();
++ extern int valid_machine_type_attribute ();
++ extern int valid_machine_decl_attribute ();
++ extern void machine_dependent_reorg ();
++ extern void asm_file_start ();
++ extern void asm_file_end ();
++
++ extern void avr_init_once ();
++ extern void avr_override_options ();
++ extern void init_cumulative_args ();
++ extern void function_arg_advance ();
++ extern struct rtx_def *function_arg ();
++ extern struct rtx_def *gen_cmphi_1s ();
++ extern struct rtx_def *gen_cmpsi_1s ();
++ extern int compare_diff_p (struct rtx_def *);
++ extern char * output_cmpHI ();
++ extern char * output_cmpSI ();
++ extern char * out_movqi_r_mr ();
++ extern char * out_movqi_mr_r ();
++ extern char * out_movhi_r_mr ();
++ extern char * out_movsi_r_mr ();
++ extern char * out_movhi_mr_r ();
++ extern char * out_movsi_mr_r ();
++ extern char * output_movsisf();
++ extern char * out_tstsi ();
++ extern char * out_tsthi ();
++ extern char * ret_cond_branch ();
++ extern char * ashlqi3_out ();
++ extern char * ashlhi3_out ();
++ extern char * ashlsi3_out ();
++
++ extern char * ashrqi3_out ();
++ extern char * ashrhi3_out ();
++ extern char * ashrsi3_out ();
++
++ extern char * lshrqi3_out ();
++ extern char * lshrhi3_out ();
++ extern char * lshrsi3_out ();
++ extern char * avr_change_section ();
++ extern struct rtx_def * avr_function_value ();
++ extern int avr_address_cost (struct rtx_def *);
++ extern int avr_ret_register ();
++ extern enum reg_class class_likely_spilled_p ();
++ extern enum reg_class preferred_reload_class ();
++ extern enum reg_class avr_regno_reg_class (int);
++ extern int extra_constraint ();
++ extern enum reg_class avr_reg_class_from_letter ();
++ extern int class_max_nregs ();
++ extern struct rtx_def * legitimize_address ();
++ extern int adjust_insn_length (struct rtx_def *, int);
++ extern struct rtx_def * avr_libcall_value ();
++ extern char *output_reload_inhi (struct rtx_def *, struct rtx_def **, int);
++ extern char *output_reload_insisf (struct rtx_def *, struct rtx_def **, int);
++
++ /*
++ 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
++
++ /* Make DWARF2 an option, but keep DBX as the default for now.
++ Use -gdwarf-2 to turn on DWARF2. */
++ /*#define DWARF2_DEBUGGING_INFO*/
++
++ #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 (AS_STR ("","gcc2_compiled.:\n"), FILE); \
++ } \
++ while (0)
++
+diff -Nrc3p gcc-2.95.2.orig/gcc/config/avr/libgcc.S gcc-2.95.2/gcc/config/avr/libgcc.S
+*** gcc-2.95.2.orig/gcc/config/avr/libgcc.S Sat Dec 18 17:50:17 1999
+--- gcc-2.95.2/gcc/config/avr/libgcc.S Thu Dec 23 22:36:37 1999
+***************
+*** 0 ****
+--- 1,664 ----
++ /* -*- Mode: Asm -*- */
++
++ #ifdef ASSEMBLER_AVA
++ # define TEXT_SEG(x) seg removable flash.code.##x
++ # define GLOBAL(x)
++ # define FUNCTION(x)
++ # define ENDFUNC
++ # define LABEL(x) public _##x##:
++ #else
++ # 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
++ #endif /* ASSEMBLER_AVA */
++
++
++ #ifdef ASSEMBLER_AVA
++ # define Lmulqi3
++ # define Lmulhi3
++ # define Lmulsi3
++ # define Lumodqi3
++ # define Ludivqi3
++ # define Lmodqi3
++ # define Ldivqi3
++ # define Lumodhi3
++ # define Ludivhi
++ # define Lmodhi3
++ # define Ldivhi3
++ # define Lumodsi3
++ # define Ludivsi3
++ # define Lmodsi3
++ # define Ldivsi3
++ # define Lprologue
++ # define Lepilogue
++ # define L__exit
++ #endif
++
++ #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 -Nrc3p gcc-2.95.2.orig/gcc/config/avr/t-avr gcc-2.95.2/gcc/config/avr/t-avr
+*** gcc-2.95.2.orig/gcc/config/avr/t-avr Sat Dec 18 17:50:17 1999
+--- gcc-2.95.2/gcc/config/avr/t-avr Thu Nov 25 22:44:42 1999
+***************
+*** 0 ****
+--- 1,67 ----
++ 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...
++ ifeq ($(TARGET_ASSEMBLER), ava)
++ LIBGCC = libgcc.o libgcc-mega.o
++ INSTALL_LIBGCC = install-libgcc-ava
++ endif
++
++ LIBGCC1_TEST =
++
++ # We do not have DF or DI types, so fake out the libgcc2 compilation.
++ TARGET_LIBGCC2_CFLAGS = -DDF=SF -Dinhibit_libc
++ #LIBGCC2 = $(LIBGCC1)
++
++ LIBGCC_AVA = libgcc.o libgcc-mega.o
++
++ 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
++
++ install-libgcc-ava: $(LIBGCC_AVA)
++ $(INSTALL_DATA) libgcc.o $(libsubdir)/libgcc.o
++ $(INSTALL_DATA) libgcc-mega.o $(libsubdir)/libgcc-mega.o
++
++ AR_FOR_TARGET = avr-ar
++ RANLIB_FOR_TARGET = avr-ranlib
++
++ FPBIT = fp-bit.c
++ #fp-bit.c
++
++ # Internal AVR port variable
++ AVA_LIB_FILE = $(srcdir)/config/avr/libgcc.S
++
++ libgcc.o: $(AVA_LIB_FILE)
++ $(GCC_FOR_TARGET) -DASSEMBLER_AVA -E -P -o $(objdir)/libgcc.s $(srcdir)/config/avr/libgcc.S
++ ava -favr_noendianbug -AAT90S8515 -o $(objdir)/libgcc.o $(objdir)/libgcc.s
++
++ libgcc-mega.o: $(AVA_LIB_FILE)
++ $(GCC_FOR_TARGET) -DASSEMBLER_AVA -P -E -mmcu=atmega603 -o $(objdir)/libgcc-mega.s $(srcdir)/config/avr/libgcc.S
++ ava -favr_noendianbug -AATmega603 -o $(objdir)/libgcc-mega.o $(objdir)/libgcc-mega.s
+diff -Nrc3p gcc-2.95.2.orig/gcc/config/avr/xm-avr.h gcc-2.95.2/gcc/config/avr/xm-avr.h
+*** gcc-2.95.2.orig/gcc/config/avr/xm-avr.h Sat Dec 18 17:50:17 1999
+--- gcc-2.95.2/gcc/config/avr/xm-avr.h Sun Oct 31 00:01:25 1999
+***************
+*** 0 ****
+--- 1 ----
++ #include "tm.h"
+diff -Nrc3p gcc-2.95.2.orig/gcc/ginclude/va-avr.h gcc-2.95.2/gcc/ginclude/va-avr.h
+*** gcc-2.95.2.orig/gcc/ginclude/va-avr.h Sat Dec 18 17:50:17 1999
+--- gcc-2.95.2/gcc/ginclude/va-avr.h Thu Nov 25 23:29:08 1999
+***************
+*** 0 ****
+--- 1,49 ----
++ /* stdarg/vararg support for the ATMEL AVR microcontroller */
++
++ /* Define __gnuc_va_list. */
++
++ #ifndef __GNUC_VA_LIST
++ #define __GNUC_VA_LIST
++ typedef void *__gnuc_va_list;
++ #endif
++
++ /* If this is for internal libc use, don't define anything but
++ __gnuc_va_list. */
++ #if defined (_STDARG_H) || defined (_VARARGS_H)
++
++ /* In GCC version 2, we want an ellipsis at the end of the declaration
++ of the argument list. GCC version 1 can't parse it. */
++
++ #if __GNUC__ > 1
++ #define __va_ellipsis ...
++ #else
++ #define __va_ellipsis
++ #endif
++
++ #define __va_rounded_size(TYPE) sizeof (TYPE)
++
++ #ifdef _STDARG_H
++
++ #define va_start(AP,LASTARG) \
++ (AP = ((__gnuc_va_list) __builtin_next_arg (LASTARG)))
++
++ #else /* _VARARGS_H */
++
++ #define va_alist __builtin_va_alist
++ /* The ... causes current_function_varargs to be set in cc1. */
++ #define va_dcl int __builtin_va_alist; __va_ellipsis
++ #define va_start(AP) AP = (void *) &__builtin_va_alist
++
++ #endif /* _VARARGS_H */
++
++ /* This is for little-endian machines; small args are padded upward. */
++ #define va_arg(AP, TYPE) \
++ (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)), \
++ *((TYPE *) (void *) ((char *) (AP) - __va_rounded_size (TYPE))))
++
++ #define va_end(AP) ((void) 0)
++
++ /* Copy __gnuc_va_list into another variable of this type. */
++ #define __va_copy(dest, src) (dest) = (src)
++
++ #endif /* defined (_STDARG_H) || defined (_VARARGS_H) */
+diff -Nrc3p gcc-2.95.2.orig/gcc/ginclude/stdarg.h gcc-2.95.2/gcc/ginclude/stdarg.h
+*** gcc-2.95.2.orig/gcc/ginclude/stdarg.h Sun Aug 1 23:09:54 1999
+--- gcc-2.95.2/gcc/ginclude/stdarg.h Thu Nov 25 23:29:05 1999
+***************
+*** 62,67 ****
+--- 62,70 ----
+ #if defined (_TMS320C4x) || defined (_TMS320C3x)
+ #include <va-c4x.h>
+ #else
++ #ifdef __AVR__
++ #include "va-avr.h"
++ #else
+
+ /* Define __gnuc_va_list. */
+
+*************** void va_end (__gnuc_va_list); /* Define
+*** 121,126 ****
+--- 124,130 ----
+
+ #endif /* _STDARG_H */
+
++ #endif /* not AVR */
+ #endif /* not TMS320C3x or TMS320C4x */
+ #endif /* not v850 */
+ #endif /* not mn10200 */
+diff -Nrc3p gcc-2.95.2.orig/gcc/ginclude/varargs.h gcc-2.95.2/gcc/ginclude/varargs.h
+*** gcc-2.95.2.orig/gcc/ginclude/varargs.h Sun Aug 1 23:09:55 1999
+--- gcc-2.95.2/gcc/ginclude/varargs.h Thu Nov 25 23:29:10 1999
+***************
+*** 60,65 ****
+--- 60,68 ----
+ #if defined (_TMS320C4x) || defined (_TMS320C3x)
+ #include <va-c4x.h>
+ #else
++ #ifdef __AVR__
++ #include "va-avr.h"
++ #else
+
+ #ifdef __NeXT__
+
+*************** typedef void *__gnuc_va_list;
+*** 140,145 ****
+--- 143,149 ----
+ /* Copy __gnuc_va_list into another variable of this type. */
+ #define __va_copy(dest, src) (dest) = (src)
+
++ #endif /* not AVR */
+ #endif /* not TMS320C3x or TMS320C4x */
+ #endif /* not v850 */
+ #endif /* not mn10200 */
+diff -Nrc3p gcc-2.95.2.orig/gcc/invoke.texi gcc-2.95.2/gcc/invoke.texi
+*** gcc-2.95.2.orig/gcc/invoke.texi Sat Oct 30 20:13:09 1999
+--- gcc-2.95.2/gcc/invoke.texi Thu Nov 25 23:28:57 1999
+*************** in the following sections.
+*** 409,414 ****
+--- 409,418 ----
+ -m32032 -m32332 -m32532 -m32081 -m32381 -mmult-add -mnomult-add
+ -msoft-float -mrtd -mnortd -mregparam -mnoregparam -msb -mnosb
+ -mbitfield -mnobitfield -mhimem -mnohimem
++
++ @emph{AVR Options}
++ -mmcu=@var{mcu} -msize -minit-stack=@var{n} -mtarget-include
++ -mno-interrupts -mcall-prologues -mava
+ @end smallexample
+
+ @item Code Generation Options
+*************** that macro, which enables you to change
+*** 3125,3130 ****
+--- 3129,3135 ----
+ * V850 Options::
+ * ARC Options::
+ * NS32K Options::
++ * AVR Options::
+ @end menu
+
+ @node M680x0 Options
+*************** Put functions, data, and readonly data i
+*** 5975,5980 ****
+--- 5980,6017 ----
+ by default. This can be overridden with the @code{section} attribute.
+ @xref{Variable Attributes}.
+
++ @end table
++
++ @node AVR Options
++ @subsection AVR Options
++ @cindex AVR Options
++
++ These options are defined for AVR implementations:
++
++ @table @code
++ @item -mmcu=@var{mcu}
++ Specify ATMEL AVR mcu (at90s23xx,attiny22,at90s44xx,at90s85xx,atmega603,
++ atmega103).
++
++ @item -msize
++ Output instruction size's to the asm file
++
++ @item -minit-stack=@var{N}
++ Specify the initial stack address
++
++ @item -mtarget-include
++ Add line @samp{#include "target.inc"} to front of asm file
++
++ @item -mno-interrupts
++ Generated code is not compatible with hardware interrupts.
++ Code size will be smaller.
++
++ @item -mcall-prologues
++ Functions prologues/epilogues expanded as call to appropriate
++ subroutines. Code size will be smaller.
++
++ @item -mava
++ Use AVA as assembler and linker.
+ @end table
+
+ @node NS32K Options
+diff -Nrc3p gcc-2.95.2.orig/gcc/install.texi gcc-2.95.2/gcc/install.texi
+*** gcc-2.95.2.orig/gcc/install.texi Sun Aug 1 23:09:55 1999
+--- gcc-2.95.2/gcc/install.texi Thu Nov 25 23:28:55 1999
+*************** Here are the possible CPU types:
+*** 726,732 ****
+
+ @quotation
+ @c gmicro, alliant, spur and tahoe omitted since they don't work.
+! 1750a, a29k, alpha, arm, c@var{n}, clipper, dsp16xx, elxsi, h8300,
+ hppa1.0, hppa1.1, i370, i386, i486, i586, i860, i960, m32r, m68000, m68k,
+ m88k, mips, mipsel, mips64, mips64el, ns32k, powerpc, powerpcle,
+ pyramid, romp, rs6000, sh, sparc, sparclite, sparc64, vax, we32k.
+--- 726,732 ----
+
+ @quotation
+ @c gmicro, alliant, spur and tahoe omitted since they don't work.
+! 1750a, a29k, alpha, arm, avr, c@var{n}, clipper, dsp16xx, elxsi, h8300,
+ hppa1.0, hppa1.1, i370, i386, i486, i586, i860, i960, m32r, m68000, m68k,
+ m88k, mips, mipsel, mips64, mips64el, ns32k, powerpc, powerpcle,
+ pyramid, romp, rs6000, sh, sparc, sparclite, sparc64, vax, we32k.
+*************** particular configuration.
+*** 945,950 ****
+--- 945,958 ----
+
+ @item a29k-*-bsd
+ AMD Am29050 used in a system running a variant of BSD Unix.
++
++ @item avr
++ ATMEL AVR-family micro controllers. These are used in embedded
++ applications. There are no standard Unix configurations.
++ Supports following MCU's:
++ - AT90S8515
++ - ATmega603/603L
++ - ATmega103/103L
+
+ @item decstation-*
+ MIPS-based DECstations can support three different personalities:
+diff -Nrc3p gcc-2.95.2.orig/gcc/extend.texi gcc-2.95.2/gcc/extend.texi
+*** gcc-2.95.2.orig/gcc/extend.texi Sun Aug 1 23:09:48 1999
+--- gcc-2.95.2/gcc/extend.texi Mon Dec 13 22:30:51 1999
+*************** function is an interrupt handler. The c
+*** 1657,1662 ****
+--- 1657,1681 ----
+ entry and exit sequences suitable for use in an interrupt handler when this
+ attribute is present.
+
++ Interrupt handler functions on the AVR processors
++ Use this option on the AVR to indicate that the specified
++ function is an interrupt handler. The compiler will generate function
++ entry and exit sequences suitable for use in an interrupt handler when this
++ attribute is present. Interrupts will be enabled inside function.
++
++ @item signal
++ @cindex signal handler functions on the AVR processors
++ Use this option on the AVR to indicate that the specified
++ function is an signal handler. The compiler will generate function
++ entry and exit sequences suitable for use in an signal handler when this
++ attribute is present. Interrupts will be disabled inside function.
++
++ @item naked
++ @cindex function without a prologue/epilogue code on the AVR processors
++ Use this option on the AVR to indicate that the specified
++ function don't have a prologue/epilogue. The compiler don't generate
++ function entry and exit sequences.
++
+ @item model (@var{model-name})
+ @cindex function addressability on the M32R/D
+ Use this attribute on the M32R/D to set the addressability of an object,
+diff -Nrc3p gcc-2.95.2.orig/gcc/md.texi gcc-2.95.2/gcc/md.texi
+*** gcc-2.95.2.orig/gcc/md.texi Sun Aug 1 23:10:00 1999
+--- gcc-2.95.2/gcc/md.texi Thu Nov 25 23:29:00 1999
+*************** A floating point constant (in @code{asm}
+*** 1351,1356 ****
+--- 1351,1416 ----
+ independent @samp{E} or @samp{F} instead)
+ @end table
+
++ @item AVR family---@file{avr.h}
++ @table @code
++ @item l
++ Registers from r0 to r15
++
++ @item a
++ Registers from r16 to r23
++
++ @item d
++ Registers from r16 to r31
++
++ @item w
++ Register from r24 to r31. This registers can be used in @samp{addw} command
++
++ @item e
++ Pointer register (r26 - r31)
++
++ @item b
++ Base pointer register (r28 - r31)
++
++ @item t
++ Temporary register r0
++
++ @item x
++ Register pair X (r27:r26)
++
++ @item y
++ Register pair Y (r29:r28)
++
++ @item z
++ Register pair Z (r31:r30)
++
++ @item I
++ Constant greater than -1, less than 64
++
++ @item J
++ Constant greater than -64, less than 1
++
++ @item K
++ Constant integer 2
++
++ @item L
++ Constant integer 0
++
++ @item M
++ Constant that fits in 8 bits
++
++ @item N
++ Constant integer -1
++
++ @item O
++ Constant integer 8
++
++ @item P
++ Constant integer 1
++
++ @item G
++ A floating point constant 0.0
++ @end table
++
+ @item IBM RS6000---@file{rs6000.h}
+ @table @code
+ @item b
+diff -Nrc3p gcc-2.95.2.orig/gcc/configure.in gcc-2.95.2/gcc/configure.in
+*** gcc-2.95.2.orig/gcc/configure.in Sat Oct 30 20:13:07 1999
+--- gcc-2.95.2/gcc/configure.in Sat Oct 30 22:26:10 1999
+*************** changequote([,])dnl
+*** 2721,2726 ****
+--- 2721,2728 ----
+ pdp11-*-bsd)
+ tm_file="${tm_file} pdp11/2bsd.h"
+ ;;
++ avr-*-*)
++ ;;
+ pdp11-*-*)
+ ;;
+ ns32k-*-openbsd*)
+diff -Nrc3p gcc-2.95.2.orig/gcc/Makefile.in gcc-2.95.2/gcc/Makefile.in
+*** gcc-2.95.2.orig/gcc/Makefile.in Sat Aug 21 17:11:52 1999
+--- gcc-2.95.2/gcc/Makefile.in Thu Nov 25 23:28:47 1999
+*************** USER_H = $(srcdir)/ginclude/stdarg.h $(s
+*** 157,162 ****
+--- 157,163 ----
+ $(srcdir)/ginclude/va-m32r.h $(srcdir)/ginclude/va-sh.h \
+ $(srcdir)/ginclude/va-v850.h $(srcdir)/ginclude/va-arc.h \
+ $(srcdir)/ginclude/iso646.h $(srcdir)/ginclude/va-ppc.h \
++ $(srcdir)/ginclude/va-avr.h \
+ $(srcdir)/ginclude/va-c4x.h $(EXTRA_HEADERS) $(LANG_EXTRA_HEADERS) \
+ $(srcdir)/ginclude/proto.h $(srcdir)/ginclude/stdbool.h
+
+diff -Nrc3p gcc-2.95.2.orig/config.sub gcc-2.95.2/config.sub
+*** gcc-2.95.2.orig/config.sub Sat Aug 21 17:11:51 1999
+--- gcc-2.95.2/config.sub Thu Nov 25 23:29:50 1999
+*************** case $basic_machine in
+*** 168,174 ****
+ | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \
+ | alpha | alphaev5 | alphaev56 | alphapca56 | alphaev6 \
+ | we32k | ns16k | clipper | i370 | sh | powerpc | powerpcle \
+! | 1750a | dsp16xx | pdp11 \
+ | mips64 | mipsel | mips64el | mips64orion | mips64orionel \
+ | mipstx39 | mipstx39el \
+ | sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x)
+--- 168,174 ----
+ | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \
+ | alpha | alphaev5 | alphaev56 | alphapca56 | alphaev6 \
+ | we32k | ns16k | clipper | i370 | sh | powerpc | powerpcle \
+! | 1750a | dsp16xx | pdp11 | avr \
+ | mips64 | mipsel | mips64el | mips64orion | mips64orionel \
+ | mipstx39 | mipstx39el \
+ | sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x)
+diff -Nrc3p gcc-2.95.2.orig/gcc/expr.c gcc-2.95.2/gcc/expr.c
+*** gcc-2.95.2.orig/gcc/expr.c Sun Aug 1 23:09:47 1999
+--- gcc-2.95.2/gcc/expr.c Wed Dec 15 23:03:14 1999
+*************** emit_move_insn_1 (x, y)
+*** 2710,2720 ****
+ X with a reference to the stack pointer. */
+ if (push_operand (x, GET_MODE (x)))
+ {
+ anti_adjust_stack (GEN_INT (GET_MODE_SIZE (GET_MODE (x))));
+! x = change_address (x, VOIDmode, stack_pointer_rtx);
+! }
+ #endif
+!
+ start_sequence ();
+
+ need_clobber = 0;
+--- 2710,2732 ----
+ X with a reference to the stack pointer. */
+ if (push_operand (x, GET_MODE (x)))
+ {
++ rtx ptr_rtx = stack_pointer_rtx;
+ anti_adjust_stack (GEN_INT (GET_MODE_SIZE (GET_MODE (x))));
+! #if defined (STACK_POINTER_OFFSET) || defined (STACK_DYNAMIC_OFFSET)
+! {
+! rtx addend;
+! #ifdef STACK_DYNAMIC_OFFSET
+! addend = GEN_INT (STACK_DYNAMIC_OFFSET (current_function_decl));
+! #else
+! addend = GEN_INT (STACK_POINTER_OFFSET);
+! #endif
+! ptr_rtx = gen_rtx (PLUS, Pmode, stack_pointer_rtx, addend);
+! }
+ #endif
+! x = change_address (x, VOIDmode, ptr_rtx);
+! }
+! #endif
+!
+ start_sequence ();
+
+ need_clobber = 0;
+diff -Nrc3p gcc-2.95.2.orig/gcc/final.c gcc-2.95.2/gcc/final.c
+*** gcc-2.95.2.orig/gcc/final.c Sun Aug 1 23:09:48 1999
+--- gcc-2.95.2/gcc/final.c Sat Dec 11 20:21:59 1999
+*************** shorten_branches (first)
+*** 1271,1277 ****
+ * GET_MODE_SIZE (GET_MODE (body)));
+ /* Alignment is handled by ADDR_VEC_ALIGN. */
+ }
+! else if (asm_noperands (body) >= 0)
+ insn_lengths[uid] = asm_insn_count (body) * insn_default_length (insn);
+ else if (GET_CODE (body) == SEQUENCE)
+ {
+--- 1271,1277 ----
+ * GET_MODE_SIZE (GET_MODE (body)));
+ /* Alignment is handled by ADDR_VEC_ALIGN. */
+ }
+! else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
+ insn_lengths[uid] = asm_insn_count (body) * insn_default_length (insn);
+ else if (GET_CODE (body) == SEQUENCE)
+ {
+*************** shorten_branches (first)
+*** 1291,1297 ****
+ int inner_uid = INSN_UID (inner_insn);
+ int inner_length;
+
+! if (asm_noperands (PATTERN (XVECEXP (body, 0, i))) >= 0)
+ inner_length = (asm_insn_count (PATTERN (inner_insn))
+ * insn_default_length (inner_insn));
+ else
+--- 1291,1298 ----
+ int inner_uid = INSN_UID (inner_insn);
+ int inner_length;
+
+! if (GET_CODE (PATTERN (XVECEXP (body, 0, i))) == ASM_INPUT
+! || asm_noperands (PATTERN (XVECEXP (body, 0, i))) >= 0)
+ inner_length = (asm_insn_count (PATTERN (inner_insn))
+ * insn_default_length (inner_insn));
+ else
diff --git a/2.95.3/gentoo/42_all_debian-gcc-m68k-pic.patch b/2.95.3/gentoo/42_all_debian-gcc-m68k-pic.patch
new file mode 100644
index 0000000..36c5c7e
--- /dev/null
+++ b/2.95.3/gentoo/42_all_debian-gcc-m68k-pic.patch
@@ -0,0 +1,62 @@
+#! /bin/sh -e
+
+# DP: Two patches by Andreas Schwab to fix -fpic and loop optimization.
+# DP: Another patch by Andreas Schwab to fix %a5 restauration in some cases.
+
+if [ $# -eq 3 -a "$2" = '-d' ]; then
+ pdir="-d $3"
+elif [ $# -ne 1 ]; then
+ echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
+ exit 1
+fi
+case "$1" in
+ -patch) patch $pdir -f --no-backup-if-mismatch -p0 < $0;;
+ -unpatch) patch $pdir -f --no-backup-if-mismatch -R -p0 < $0;;
+ *)
+ echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
+ exit 1
+esac
+exit 0
+
+------------------------------------------------------------------------------
+--- gcc/config/m68k/m68k.c~ Mon Aug 2 06:51:08 1999
++++ gcc/config/m68k/m68k.c Fri Oct 22 11:47:09 1999
+@@ -356,7 +356,7 @@
+ mask &= ~ (1 << (15 - FRAME_POINTER_REGNUM));
+ num_saved_regs--;
+ }
+- if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
++ if (flag_pic && current_function_uses_pic_offset_table)
+ {
+ mask |= 1 << (15 - PIC_OFFSET_TABLE_REGNUM);
+ num_saved_regs++;
+@@ -493,7 +493,10 @@
+ for (regno = 0 ; regno < FIRST_PSEUDO_REGISTER ; regno++)
+ if (regs_ever_live[regno] && ! call_used_regs[regno])
+ return 0;
+-
++
++ if (flag_pic && current_function_uses_pic_offset_table)
++ return 0;
++
+ return 1;
+ }
+
+@@ -568,7 +571,7 @@
+ nregs++;
+ mask |= 1 << regno;
+ }
+- if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
++ if (flag_pic && current_function_uses_pic_offset_table)
+ {
+ nregs++;
+ mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
+@@ -1334,8 +1337,6 @@
+ gen_rtx_PLUS (Pmode,
+ pic_offset_table_rtx, orig));
+ current_function_uses_pic_offset_table = 1;
+- if (reload_in_progress)
+- regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
+ RTX_UNCHANGING_P (pic_ref) = 1;
+ emit_move_insn (reg, pic_ref);
+ return reg;
diff --git a/2.95.3/gentoo/42_all_debian-m68k-md.patch b/2.95.3/gentoo/42_all_debian-m68k-md.patch
new file mode 100644
index 0000000..7383bb4
--- /dev/null
+++ b/2.95.3/gentoo/42_all_debian-m68k-md.patch
@@ -0,0 +1,56 @@
+#! /bin/sh -e
+
+dir=
+if [ $# -eq 3 -a "$2" = '-d' ]; then
+ pdir="-d $3"
+ dir="$3/"
+elif [ $# -ne 1 ]; then
+ echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
+ exit 1
+fi
+case "$1" in
+ -patch)
+ patch $pdir -f --no-backup-if-mismatch -p0 < $0
+ #cd ${dir}gcc && autoconf
+ ;;
+ -unpatch)
+ patch $pdir -f --no-backup-if-mismatch -R -p0 < $0
+ #rm ${dir}gcc/configure
+ ;;
+ *)
+ echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
+ exit 1
+esac
+exit 0
+
+# DP: From: Roman Zippel <zippel@linux-m68k.org>
+# DP: m68k md fix (#105622).
+
+From: Roman Zippel <zippel@linux-m68k.org>
+Sender: roman@cs.tu-berlin.de
+To: Matt Zimmerman <mdz@debian.org>, 105622@bugs.debian.org,
+ Matthias Klose <doko@cs.tu-berlin.de>
+Subject: Bug#105622: Test case
+Date: Sat, 21 Jul 2001 01:33:39 +0200
+
+--- gcc/config/m68k/m68k.md.org Sat Jul 21 01:17:42 2001
++++ gcc/config/m68k/m68k.md Sat Jul 21 01:18:53 2001
+@@ -2116,7 +2116,7 @@
+ ;; (plus:DI (match_operand:DI 2 "general_operand" "%0")
+ ;; (lshiftrt:DI (match_operand:DI 1 "general_operand" "ro")
+ ;; (const_int 32))))]
+- (plus:DI (lshiftrt:DI (match_operand:DI 1 "general_operand" "ro,r")
++ (plus:DI (lshiftrt:DI (match_operand:DI 1 "general_operand" "ro,d")
+ (const_int 32))
+ (match_operand:DI 2 "general_operand" "0,0")))]
+ ""
+@@ -2135,7 +2135,7 @@
+ ;; (plus:DI (match_operand:DI 2 "general_operand" "%0")
+ ;; (ashift:DI (match_operand:DI 1 "general_operand" "ro")
+ ;; (const_int 32))))]
+- (plus:DI (ashift:DI (match_operand:DI 1 "general_operand" "ro,r")
++ (plus:DI (ashift:DI (match_operand:DI 1 "general_operand" "ro,d")
+ (const_int 32))
+ (match_operand:DI 2 "general_operand" "0,0")))]
+ ""
+
diff --git a/2.95.3/gentoo/42_all_debian-m68k-reload.patch b/2.95.3/gentoo/42_all_debian-m68k-reload.patch
new file mode 100644
index 0000000..71240d7
--- /dev/null
+++ b/2.95.3/gentoo/42_all_debian-m68k-reload.patch
@@ -0,0 +1,327 @@
+#! /bin/sh -e
+
+# DP: <your description>
+
+if [ $# -eq 3 -a "$2" = '-d' ]; then
+ pdir="-d $3"
+elif [ $# -ne 1 ]; then
+ echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
+ exit 1
+fi
+case "$1" in
+ -patch) patch $pdir -f --no-backup-if-mismatch -p0 < $0;;
+ -unpatch) patch $pdir -f --no-backup-if-mismatch -R -p0 < $0;;
+ *)
+ echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
+ exit 1
+esac
+exit 0
+
+--- gcc/reload.c.org Sun Aug 26 19:41:02 2001
++++ gcc/reload.c Sun Aug 26 20:59:59 2001
+@@ -2451,6 +2451,7 @@
+ char this_alternative_earlyclobber[MAX_RECOG_OPERANDS];
+ int this_alternative_matches[MAX_RECOG_OPERANDS];
+ int swapped;
++ int n_swapped;
+ int goal_alternative[MAX_RECOG_OPERANDS];
+ int this_alternative_number;
+ int goal_alternative_number;
+@@ -2462,7 +2463,8 @@
+ char goal_alternative_earlyclobber[MAX_RECOG_OPERANDS];
+ int goal_alternative_swapped;
+ int best;
+- int commutative;
++ int commutative[MAX_RECOG_OPERANDS];
++ int commutative_op[MAX_RECOG_OPERANDS/2];
+ int changed;
+ char operands_match[MAX_RECOG_OPERANDS][MAX_RECOG_OPERANDS];
+ rtx substed_operand[MAX_RECOG_OPERANDS];
+@@ -2479,6 +2481,7 @@
+ n_reloads = 0;
+ n_replacements = 0;
+ n_earlyclobbers = 0;
++ n_swapped = 0;
+ replace_reloads = replace;
+ hard_regs_live_known = live_known;
+ static_reload_reg_p = reload_reg_p;
+@@ -2532,14 +2535,12 @@
+ bcopy ((char *) recog_constraints, (char *) constraints,
+ noperands * sizeof (char *));
+
+- commutative = -1;
+-
+ /* If we will need to know, later, whether some pair of operands
+ are the same, we must compare them now and save the result.
+ Reloading the base and index registers will clobber them
+ and afterward they will fail to match. */
+
+- for (i = 0; i < noperands; i++)
++ for (i = 0, j = 0; i < noperands; i++)
+ {
+ register char *p;
+ register int c;
+@@ -2547,6 +2548,7 @@
+ substed_operand[i] = recog_operand[i];
+ p = constraints[i];
+
++ commutative[i] = i;
+ modified[i] = RELOAD_READ;
+
+ /* Scan this operand's constraint to see if it is an output operand,
+@@ -2560,11 +2562,14 @@
+ modified[i] = RELOAD_READ_WRITE;
+ else if (c == '%')
+ {
+- /* The last operand should not be marked commutative. */
+- if (i == noperands - 1)
++ /* The last and the next operand should not be marked commutative. */
++ if (i == noperands - 1 || commutative[i] != i)
+ abort ();
+
+- commutative = i;
++ n_swapped = n_swapped ? n_swapped * 2 : 2;
++ commutative_op[j++] = i;
++ commutative[i] = i + 1;
++ commutative[i + 1] = i;
+ }
+ else if (c >= '0' && c <= '9')
+ {
+@@ -2576,26 +2581,21 @@
+ if (c == i)
+ abort ();
+
++ if (commutative[i] != i)
++ operands_match[c][commutative[i]]
++ = operands_match_p (recog_operand[c],
++ recog_operand[commutative[i]]);
++
+ /* If C can be commuted with C+1, and C might need to match I,
+ then C+1 might also need to match I. */
+- if (commutative >= 0)
+- {
+- if (c == commutative || c == commutative + 1)
+- {
+- int other = c + (c == commutative ? 1 : -1);
+- operands_match[other][i]
+- = operands_match_p (recog_operand[other], recog_operand[i]);
+- }
+- if (i == commutative || i == commutative + 1)
+- {
+- int other = i + (i == commutative ? 1 : -1);
+- operands_match[c][other]
+- = operands_match_p (recog_operand[c], recog_operand[other]);
+- }
+- /* Note that C is supposed to be less than I.
+- No need to consider altering both C and I because in
+- that case we would alter one into the other. */
+- }
++ if (commutative[c] != c)
++ operands_match[commutative[c]][i]
++ = operands_match_p (recog_operand[commutative[c]],
++ recog_operand[i]);
++ if (commutative[i] != i && commutative[c] != c)
++ operands_match[commutative[c]][commutative[i]]
++ = operands_match_p (recog_operand[commutative[c]],
++ recog_operand[commutative[i]]);
+ }
+ }
+ }
+@@ -2756,6 +2756,8 @@
+
+ swapped = 0;
+ goal_alternative_swapped = 0;
++ for (i = 0; i < noperands; i++)
++ commutative[i] = i;
+ try_swapped:
+
+ /* The constraints are made of several alternatives.
+@@ -2910,12 +2912,7 @@
+ case '=':
+ case '+':
+ case '*':
+- break;
+-
+ case '%':
+- /* The last operand should not be marked commutative. */
+- if (i != noperands - 1)
+- commutative = i;
+ break;
+
+ case '?':
+@@ -2946,19 +2943,10 @@
+ only a single reload insn will be needed to make
+ the two operands win. As a result, this alternative
+ may be rejected when it is actually desirable.) */
+- if ((swapped && (c != commutative || i != commutative + 1))
+- /* If we are matching as if two operands were swapped,
+- also pretend that operands_match had been computed
+- with swapped.
+- But if I is the second of those and C is the first,
+- don't exchange them, because operands_match is valid
+- only on one side of its diagonal. */
+- ? (operands_match
+- [(c == commutative || c == commutative + 1)
+- ? 2*commutative + 1 - c : c]
+- [(i == commutative || i == commutative + 1)
+- ? 2*commutative + 1 - i : i])
+- : operands_match[c][i])
++ /* If we are matching as if two operands were swapped,
++ also pretend that operands_match had been computed
++ with swapped. */
++ if (operands_match[commutative[c]][commutative[i]])
+ {
+ /* If we are matching a non-offsettable address where an
+ offsettable address was expected, then we must reject
+@@ -3438,11 +3426,22 @@
+ if (losers == 0)
+ {
+ /* Unswap these so that they are never swapped at `finish'. */
+- if (commutative >= 0)
++ if (swapped)
+ {
+- recog_operand[commutative] = substed_operand[commutative];
+- recog_operand[commutative + 1]
+- = substed_operand[commutative + 1];
++ int s = swapped;
++ s ^= s >> 1;
++
++ for (i = 0; s; i++, s >>= 1)
++ {
++ register int c;
++
++ if (!(s & 1))
++ continue;
++ c = commutative_op[i];
++
++ recog_operand[c] = substed_operand[c];
++ recog_operand[c + 1] = substed_operand[c + 1];
++ }
+ }
+ for (i = 0; i < noperands; i++)
+ {
+@@ -3492,37 +3491,48 @@
+ as if we had exchanged them.
+ To do this, really exchange them in operands.
+
+- If we have just tried the alternatives the second time,
++ We try all the possible alternatives and after we tried the last one,
+ return operands to normal and drop through. */
+
+- if (commutative >= 0)
++ if (++swapped <= n_swapped)
+ {
+- swapped = !swapped;
+- if (swapped)
++ int s, t;
++ rtx x;
++
++ s = swapped - 1;
++ if (swapped < n_swapped)
++ s ^= swapped;
++ s ^= s >> 1;
++
++ for (i = 0; s; i++, s >>= 1)
++ if (s & 1)
++ break;
++ i = commutative_op[i];
++
++ t = commutative[i];
++ commutative[i] = commutative[i + 1];
++ commutative[i + 1] = t;
++
++ x = recog_operand[i];
++ recog_operand[i] = recog_operand[i + 1];
++ recog_operand[i + 1] = x;
++
++ if (swapped < n_swapped)
+ {
+ register enum reg_class tclass;
+- register int t;
+-
+- recog_operand[commutative] = substed_operand[commutative + 1];
+- recog_operand[commutative + 1] = substed_operand[commutative];
+
+- tclass = preferred_class[commutative];
+- preferred_class[commutative] = preferred_class[commutative + 1];
+- preferred_class[commutative + 1] = tclass;
+-
+- t = pref_or_nothing[commutative];
+- pref_or_nothing[commutative] = pref_or_nothing[commutative + 1];
+- pref_or_nothing[commutative + 1] = t;
++ tclass = preferred_class[i];
++ preferred_class[i] = preferred_class[i + 1];
++ preferred_class[i + 1] = tclass;
++
++ t = pref_or_nothing[i];
++ pref_or_nothing[i] = pref_or_nothing[i + 1];
++ pref_or_nothing[i + 1] = t;
+
+ bcopy ((char *) recog_constraints, (char *) constraints,
+ noperands * sizeof (char *));
+ goto try_swapped;
+ }
+- else
+- {
+- recog_operand[commutative] = substed_operand[commutative];
+- recog_operand[commutative + 1] = substed_operand[commutative + 1];
+- }
+ }
+
+ /* The operands don't meet the constraints.
+@@ -3566,25 +3576,38 @@
+
+ if (goal_alternative_swapped)
+ {
+- register rtx tem;
++ int s = goal_alternative_swapped;
++ s ^= s >> 1;
+
+- tem = substed_operand[commutative];
+- substed_operand[commutative] = substed_operand[commutative + 1];
+- substed_operand[commutative + 1] = tem;
+- tem = recog_operand[commutative];
+- recog_operand[commutative] = recog_operand[commutative + 1];
+- recog_operand[commutative + 1] = tem;
+- tem = *recog_operand_loc[commutative];
+- *recog_operand_loc[commutative] = *recog_operand_loc[commutative+1];
+- *recog_operand_loc[commutative+1] = tem;
++ for (i = 0; s; i++, s >>= 1)
++ {
++ register int c;
++ register rtx tem;
++
++ if (!(s & 1))
++ continue;
++ c = commutative_op[i];
++
++ tem = substed_operand[c];
++ substed_operand[c] = substed_operand[c + 1];
++ substed_operand[c + 1] = tem;
++
++ tem = recog_operand[c];
++ recog_operand[c] = recog_operand[c + 1];
++ recog_operand[c + 1] = tem;
++
++ tem = *recog_operand_loc[c];
++ *recog_operand_loc[c] = *recog_operand_loc[c + 1];
++ *recog_operand_loc[c + 1] = tem;
+
+- for (i = 0; i < n_reloads; i++)
+- {
+- if (reload_opnum[i] == commutative)
+- reload_opnum[i] = commutative + 1;
+- else if (reload_opnum[i] == commutative + 1)
+- reload_opnum[i] = commutative;
+- }
++ for (j = 0; j < n_reloads; j++)
++ {
++ if (reload_opnum[j] == c)
++ reload_opnum[j] = c + 1;
++ else if (reload_opnum[j] == c + 1)
++ reload_opnum[j] = c;
++ }
++ }
+ }
+
+ for (i = 0; i < noperands; i++)
diff --git a/2.95.3/gentoo/43_all_debian-strength-red.patch b/2.95.3/gentoo/43_all_debian-strength-red.patch
new file mode 100644
index 0000000..102313b
--- /dev/null
+++ b/2.95.3/gentoo/43_all_debian-strength-red.patch
@@ -0,0 +1,278 @@
+#! /bin/sh -e
+
+if [ $# -eq 3 -a "$2" = '-d' ]; then
+ pdir="-d $3"
+elif [ $# -ne 1 ]; then
+ echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
+ exit 1
+fi
+case "$1" in
+ -patch) patch $pdir -f --no-backup-if-mismatch -p0 < $0;;
+ -unpatch) patch $pdir -f --no-backup-if-mismatch -R -p0 < $0;;
+ *)
+ echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
+ exit 1
+esac
+exit 0
+
+# DP: From: Alan Modra <amodra@bigpond.net.au>
+Sender: gcc-patches-owner@gcc.gnu.org
+# DP: To: gcc-patches@gcc.gnu.org
+Cc: Paul Mackerras <paulus@au1.ibm.com>, Olaf Hering <olh@suse.de>
+# DP: Subject: gcc-2.95 strength reduction fix
+# DP: Date: Mon, 3 Dec 2001 14:51:31 +1030
+
+This test case, extracted from lomount.c, fails for powerpc-linux with
+current 2.95 CVS at -O2.
+
+---
+#define SIZE(a) (sizeof(a)/sizeof(a[0]))
+
+static char *loop_formats[] = { "/dev/loop%d", "/dev/loop/%d" };
+static char statbuf[20];
+
+extern void exit (int);
+extern void abort (void);
+int sprintf (char *, const char *, ...);
+int printf (const char *, ...);
+int stat (char *, char *);
+int open (char *);
+
+char *
+find_unused_loop_device (void)
+{
+ char dev[20];
+ int i, j, fd;
+
+ for (j = 0; j < SIZE (loop_formats); j++)
+ {
+ for (i = 0; i < 256; i++)
+ {
+ sprintf (dev, loop_formats[j], i);
+ printf ("dev=%s i=%d j=%d\n", dev, i, j);
+ if (stat (dev, statbuf) != 0 || statbuf[0] != 0)
+ break;
+ fd = foo2 ("blah");
+ if (fd >= 0)
+ return "blah";
+ }
+ }
+ return 0;
+}
+
+int sprintf (char *buf, const char *fmt, ...)
+{
+ if (fmt != loop_formats[0] && fmt != loop_formats[1])
+ abort ();
+ return 0;
+}
+
+int printf (const char *fmt, ...)
+{
+ return 0;
+}
+
+int stat (char *x, char *y)
+{
+ y[0] = 0;
+ return 0;
+}
+
+int open (char *x)
+{
+ return -1;
+}
+
+int main (void)
+{
+ find_unused_loop_device ();
+ exit (0);
+}
+---
+
+# DP: This particular problem was fixed on the mainline by
+# DP: http://gcc.gnu.org/ml/gcc-patches/2000-04/msg00576.html, which is a
+# DP: much nicer fix than the following but a minimal change may be preferred
+# DP: for the 2.95 branch.
+# DP:
+# DP: * loop.c (strength_reduce <giv loop>): Set up maybe_multiple for givs.
+# DP: (record_giv): Pass in maybe_multiple.
+# DP: (find_mem_givs): Likewise.
+
+Index: loop.c
+===================================================================
+RCS file: /cvs/gcc/gcc/gcc/loop.c,v
+retrieving revision 1.156.4.21
+diff -u -p -r1.156.4.21 loop.c
+--- gcc/loop.c 2001/04/03 12:09:42 1.156.4.21
++++ gcc/loop.c 2001/12/03 02:44:40
+@@ -320,11 +320,12 @@ static int count_nonfixed_reads PROTO((r
+ static void strength_reduce PROTO((rtx, rtx, rtx, int, rtx, rtx, rtx, int, int));
+ static void find_single_use_in_loop PROTO((rtx, rtx, varray_type));
+ static int valid_initial_value_p PROTO((rtx, rtx, int, rtx));
+-static void find_mem_givs PROTO((rtx, rtx, int, rtx, rtx));
++static void find_mem_givs PROTO((rtx, rtx, int, int, rtx, rtx));
+ static void record_biv PROTO((struct induction *, rtx, rtx, rtx, rtx, rtx *, int, int));
+ static void check_final_value PROTO((struct induction *, rtx, rtx,
+ unsigned HOST_WIDE_INT));
+-static void record_giv PROTO((struct induction *, rtx, rtx, rtx, rtx, rtx, int, enum g_types, int, rtx *, rtx, rtx));
++static void record_giv PROTO((struct induction *, rtx, rtx, rtx, rtx, rtx,
++ int, enum g_types, int, int, rtx *, rtx, rtx));
+ static void update_giv_derive PROTO((rtx));
+ static int basic_induction_var PROTO((rtx, enum machine_mode, rtx, rtx, rtx *, rtx *, rtx **));
+ static rtx simplify_giv_expr PROTO((rtx, int *));
+@@ -4426,6 +4427,7 @@ strength_reduce (scan_start, end, loop_t
+ biv and a constant (or invariant), and it is not a biv. */
+
+ not_every_iteration = 0;
++ maybe_multiple = 0;
+ loop_depth = 0;
+ p = scan_start;
+ while (1)
+@@ -4445,6 +4446,40 @@ strength_reduce (scan_start, end, loop_t
+ break;
+ }
+
++ if (GET_CODE (p) == CODE_LABEL)
++ {
++ rtx insn = p;
++
++ maybe_multiple = 0;
++
++ while (1)
++ {
++ insn = NEXT_INSN (insn);
++ if (insn == scan_start)
++ break;
++ if (insn == end)
++ {
++ if (loop_top != 0)
++ insn = loop_top;
++ else
++ break;
++ if (insn == scan_start)
++ break;
++ }
++
++ if (GET_CODE (insn) == JUMP_INSN
++ && GET_CODE (PATTERN (insn)) != RETURN
++ && (! condjump_p (insn)
++ || (JUMP_LABEL (insn) != 0
++ && JUMP_LABEL (insn) != scan_start
++ && ! loop_insn_first_p (p, JUMP_LABEL (insn)))))
++ {
++ maybe_multiple = 1;
++ break;
++ }
++ }
++ }
++
+ /* Look for a general induction variable in a register. */
+ if (GET_CODE (p) == INSN
+ && (set = single_set (p))
+@@ -4495,8 +4530,8 @@ strength_reduce (scan_start, end, loop_t
+ p = last_consec_insn;
+
+ record_giv (v, p, src_reg, dest_reg, mult_val, add_val, benefit,
+- DEST_REG, not_every_iteration, NULL_PTR, loop_start,
+- loop_end);
++ DEST_REG, not_every_iteration, maybe_multiple,
++ NULL_PTR, loop_start, loop_end);
+
+ }
+ }
+@@ -4506,8 +4541,8 @@ strength_reduce (scan_start, end, loop_t
+ /* This resulted in worse code on a VAX 8600. I wonder if it
+ still does. */
+ if (GET_CODE (p) == INSN)
+- find_mem_givs (PATTERN (p), p, not_every_iteration, loop_start,
+- loop_end);
++ find_mem_givs (PATTERN (p), p, not_every_iteration, maybe_multiple,
++ loop_start, loop_end);
+ #endif
+
+ /* Update the status of whether giv can derive other givs. This can
+@@ -5246,10 +5285,12 @@ valid_initial_value_p (x, insn, call_see
+ every loop iteration. */
+
+ static void
+-find_mem_givs (x, insn, not_every_iteration, loop_start, loop_end)
++find_mem_givs (x, insn, not_every_iteration, maybe_multiple,
++ loop_start, loop_end)
+ rtx x;
+ rtx insn;
+ int not_every_iteration;
++ int maybe_multiple;
+ rtx loop_start, loop_end;
+ {
+ register int i, j;
+@@ -5297,7 +5338,7 @@ find_mem_givs (x, insn, not_every_iterat
+
+ record_giv (v, insn, src_reg, addr_placeholder, mult_val,
+ add_val, benefit, DEST_ADDR, not_every_iteration,
+- &XEXP (x, 0), loop_start, loop_end);
++ maybe_multiple, &XEXP (x, 0), loop_start, loop_end);
+
+ v->mem_mode = GET_MODE (x);
+ }
+@@ -5313,12 +5354,12 @@ find_mem_givs (x, insn, not_every_iterat
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ if (fmt[i] == 'e')
+- find_mem_givs (XEXP (x, i), insn, not_every_iteration, loop_start,
+- loop_end);
++ find_mem_givs (XEXP (x, i), insn, not_every_iteration, maybe_multiple,
++ loop_start, loop_end);
+ else if (fmt[i] == 'E')
+ for (j = 0; j < XVECLEN (x, i); j++)
+ find_mem_givs (XVECEXP (x, i, j), insn, not_every_iteration,
+- loop_start, loop_end);
++ maybe_multiple, loop_start, loop_end);
+ }
+
+ /* Fill in the data about one biv update.
+@@ -5440,7 +5481,8 @@ record_biv (v, insn, dest_reg, inc_val,
+
+ static void
+ record_giv (v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
+- type, not_every_iteration, location, loop_start, loop_end)
++ type, not_every_iteration, maybe_multiple,
++ location, loop_start, loop_end)
+ struct induction *v;
+ rtx insn;
+ rtx src_reg;
+@@ -5449,6 +5491,7 @@ record_giv (v, insn, src_reg, dest_reg,
+ int benefit;
+ enum g_types type;
+ int not_every_iteration;
++ int maybe_multiple;
+ rtx *location;
+ rtx loop_start, loop_end;
+ {
+@@ -5466,7 +5509,7 @@ record_giv (v, insn, src_reg, dest_reg,
+ v->location = location;
+ v->cant_derive = 0;
+ v->combined_with = 0;
+- v->maybe_multiple = 0;
++ v->maybe_multiple = maybe_multiple;
+ v->maybe_dead = 0;
+ v->derive_adjustment = 0;
+ v->same = 0;
+
+In-Reply-To: <20011203145131.C1047@bubble.sa.bigpond.net.au>; from amodra@bigpond.net.au on Mon, Dec 03, 2001 at 02:51:31PM +1030
+From: Alan Modra <amodra@bigpond.net.au>
+Sender: gcc-patches-owner@gcc.gnu.org
+To: gcc-patches@gcc.gnu.org, Paul Mackerras <paulus@au1.ibm.com>,
+ Olaf Hering <olh@suse.de>
+Subject: Re: gcc-2.95 strength reduction fix
+Date: Mon, 3 Dec 2001 17:17:11 +1030
+
+On Mon, Dec 03, 2001 at 02:51:31PM +1030, Alan Modra wrote:
+>
+> * loop.c (strength_reduce <giv loop>): Set up maybe_multiple for givs.
+> (record_giv): Pass in maybe_multiple.
+> (find_mem_givs): Likewise.
+
+Sorry, needs this hunk too.
+
+[inserted above]