#! /bin/sh -e # DP: Some fixes for ARM from Philip Blundell # DP: put together by Hakan Ardo 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 + #endif + #include "config.h" + #include + #include + #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<= 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 #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 #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