diff options
author | Mike Frysinger <vapier@gentoo.org> | 2005-05-21 06:16:34 +0000 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2005-05-21 06:16:34 +0000 |
commit | 91b1262b9570591b291c2a8fc20b4b6fc049f229 (patch) | |
tree | e4c24020a96a945daf86666244559e521cac26f9 /2.95.3 | |
parent | roll tarballs automagically (diff) | |
download | gcc-patches-91b1262b9570591b291c2a8fc20b4b6fc049f229.tar.gz gcc-patches-91b1262b9570591b291c2a8fc20b4b6fc049f229.tar.bz2 gcc-patches-91b1262b9570591b291c2a8fc20b4b6fc049f229.zip |
import patches from crosstool/debian
Diffstat (limited to '2.95.3')
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] |