? .avr.h.swp ? atmega2560.patch ? avr-protos.h.safe ? avr.c.p ? avr.c.safe ? avr.c.safe2 ? avr.d ? avr.md.s ? avr.md.safe ? desc ? monster Index: avr-protos.h =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/config/avr/avr-protos.h,v retrieving revision 1.33 diff -U12 -r1.33 avr-protos.h --- avr-protos.h 15 Mar 2004 18:20:47 -0000 1.33 +++ avr-protos.h 18 Sep 2005 14:59:23 -0000 @@ -124,12 +124,15 @@ extern int avr_io_address_p (rtx x, int size); extern int const_int_pow2_p (rtx x); extern int avr_peep2_scratch_safe (rtx reg_rtx); #endif /* RTX_CODE */ #ifdef HAVE_MACHINE_MODES extern int class_max_nregs (enum reg_class class, enum machine_mode mode); #endif /* HAVE_MACHINE_MODES */ #ifdef REAL_VALUE_TYPE extern void asm_output_float (FILE *file, REAL_VALUE_TYPE n); #endif + +int avr_sched_adjust_priority (rtx insn, int priority); +extern int avr_pc_size; Index: avr.c =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/config/avr/avr.c,v retrieving revision 1.138 diff -U12 -r1.138 avr.c --- avr.c 25 Jun 2005 01:20:56 -0000 1.138 +++ avr.c 18 Sep 2005 14:59:34 -0000 @@ -47,26 +47,26 @@ /* Maximal allowed offset for an address in the LD command */ #define MAX_LD_OFFSET(MODE) (64 - (signed)GET_MODE_SIZE (MODE)) static int avr_naked_function_p (tree); static int interrupt_function_p (tree); static int signal_function_p (tree); static int avr_regs_to_save (HARD_REG_SET *); static int sequent_regs_live (void); static const char *ptrreg_to_str (int); static const char *cond_string (enum rtx_code); static int avr_num_arg_regs (enum machine_mode, tree); -static int out_adj_frame_ptr (FILE *, int); -static int out_set_stack_ptr (FILE *, int, int); +static int old_out_adj_frame_ptr (FILE *, int); +static int old_out_set_stack_ptr (FILE *, int, int); static RTX_CODE compare_condition (rtx insn); static int compare_sign_p (rtx insn); static tree avr_handle_progmem_attribute (tree *, tree, tree, int, bool *); static tree avr_handle_fndecl_attribute (tree *, tree, tree, int, bool *); const struct attribute_spec avr_attribute_table[]; static bool avr_assemble_integer (rtx, unsigned int, int); static void avr_file_start (void); static void avr_file_end (void); static void avr_output_function_prologue (FILE *, HOST_WIDE_INT); static void avr_output_function_epilogue (FILE *, HOST_WIDE_INT); static void avr_insert_attributes (tree, tree *); static unsigned int avr_section_type_flags (tree, const char *, int); @@ -85,24 +85,27 @@ /* Temporary register RTX (gen_rtx_REG (QImode, TMP_REGNO)) */ static GTY(()) rtx tmp_reg_rtx; /* Zeroed register RTX (gen_rtx_REG (QImode, ZERO_REGNO)) */ static GTY(()) rtx zero_reg_rtx; /* AVR register names {"r0", "r1", ..., "r31"} */ static const char *const avr_regnames[] = REGISTER_NAMES; /* This holds the last insn address. */ static int last_insn_address = 0; +/* This holds the size of the PC. Usually 2. For the very large devices 3. */ +int avr_pc_size = 2; + /* Commands count in the compiled file */ static int commands_in_file; /* Commands in the functions prologues in the compiled file */ static int commands_in_prologues; /* Commands in the functions epilogues in the compiled file */ static int commands_in_epilogues; /* Prologue/Epilogue size in words */ static int prologue_size; static int epilogue_size; @@ -111,41 +114,46 @@ static int jump_tables_size; /* Preprocessor macros to define depending on MCU type. */ const char *avr_base_arch_macro; const char *avr_extra_arch_macro; /* More than 8K of program memory: use "call" and "jmp". */ int avr_mega_p = 0; /* Enhanced core: use "movw", "mul", ... */ int avr_enhanced_p = 0; +/* Enhanced core: use "movw", "mul", ... */ +int avr_large_flash_p = 0; + /* Assembler only. */ int avr_asm_only_p = 0; struct base_arch_s { int asm_only; int enhanced; int mega; + int large_flash; const char *const macro; }; static const struct base_arch_s avr_arch_types[] = { - { 1, 0, 0, NULL }, /* unknown device specified */ - { 1, 0, 0, "__AVR_ARCH__=1" }, - { 0, 0, 0, "__AVR_ARCH__=2" }, - { 0, 0, 1, "__AVR_ARCH__=3" }, - { 0, 1, 0, "__AVR_ARCH__=4" }, - { 0, 1, 1, "__AVR_ARCH__=5" } + { 1, 0, 0, 0, NULL }, /* unknown device specified */ + { 1, 0, 0, 0, "__AVR_ARCH__=1" }, + { 0, 0, 0, 0, "__AVR_ARCH__=2" }, + { 0, 0, 1, 0, "__AVR_ARCH__=3" }, + { 0, 1, 0, 0, "__AVR_ARCH__=4" }, + { 0, 1, 1, 0, "__AVR_ARCH__=5" }, + { 0, 1, 1, 1, "__AVR_ARCH__=6" } }; struct mcu_type_s { const char *const name; int arch; /* index in avr_arch_types[] */ /* Must lie outside user's namespace. NULL == no macro. */ const char *const macro; }; /* List of all known AVR MCU types - if updated, it has to be kept in sync in several places (FIXME: is there a better way?): - here @@ -197,24 +205,28 @@ { "atmega168", 5, "__AVR_ATmega168__" }, { "atmega169", 5, "__AVR_ATmega169__" }, { "atmega32", 5, "__AVR_ATmega32__" }, { "atmega323", 5, "__AVR_ATmega323__" }, { "atmega325", 5, "__AVR_ATmega325__" }, { "atmega3250", 5, "__AVR_ATmega3250__" }, { "atmega64", 5, "__AVR_ATmega64__" }, { "atmega645", 5, "__AVR_ATmega645__" }, { "atmega6450", 5, "__AVR_ATmega6450__" }, { "atmega128", 5, "__AVR_ATmega128__" }, { "at90can128", 5, "__AVR_AT90CAN128__" }, { "at94k", 5, "__AVR_AT94K__" }, + /* Enhanced, > 128K. */ + { "avr6", 6, NULL }, + { "atmega2560", 6, "__AVR_ATMEGA2560__" }, + { "atmega2561", 6, "__AVR_ATMEGA2561__" }, /* Assembler only. */ { "avr1", 1, NULL }, { "at90s1200", 1, "__AVR_AT90S1200__" }, { "attiny11", 1, "__AVR_ATtiny11__" }, { "attiny12", 1, "__AVR_ATtiny12__" }, { "attiny15", 1, "__AVR_ATtiny15__" }, { "attiny28", 1, "__AVR_ATtiny28__" }, { NULL, 0, NULL } }; int avr_case_values_threshold = 30000; @@ -269,57 +281,64 @@ if (!t->name) { fprintf (stderr, "unknown MCU `%s' specified\nKnown MCU names:\n", avr_mcu_name); for (t = avr_mcu_types; t->name; t++) fprintf (stderr," %s\n", t->name); } base = &avr_arch_types[t->arch]; avr_asm_only_p = base->asm_only; avr_enhanced_p = base->enhanced; + avr_large_flash_p = base->large_flash; + if (avr_large_flash_p) + avr_pc_size = 3; + else + avr_pc_size = 2; + avr_mega_p = base->mega; avr_base_arch_macro = base->macro; avr_extra_arch_macro = t->macro; if (optimize && !TARGET_NO_TABLEJUMP) avr_case_values_threshold = (!AVR_MEGA || TARGET_CALL_PROLOGUES) ? 8 : 17; 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 const int reg_class_tab[]={ GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS, GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS, GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS, 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 */ + STACK_REG,STACK_REG, /* SPL,SPH */ + CC_REG /* SREG */ }; /* Return register class for register R. */ enum reg_class avr_regno_reg_class (int r) { - if (r <= 33) + if (r <= 34) return reg_class_tab[r]; return ALL_REGS; } /* A C expression which defines the machine-dependent operand constraint letters for register classes. If C is such a letter, the value should be the register class corresponding to it. Otherwise, the value should be `NO_REGS'. The register letter `r', corresponding to class `GENERAL_REGS', will not be passed to this macro; you do not need to handle it. */ @@ -330,24 +349,25 @@ { 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; + case 'c' : return CC_REG; default: break; } return NO_REGS; } /* Return nonzero if FUNC is a naked function. */ static int avr_naked_function_p (tree func) { tree a; @@ -430,25 +450,25 @@ /* Compute offset between arg_pointer and frame_pointer. */ int initial_elimination_offset (int from, int to) { if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM) return 0; else { int offset = frame_pointer_needed ? 2 : 0; offset += avr_regs_to_save (NULL); - return get_frame_size () + 2 + 1 + offset; + return get_frame_size () + avr_pc_size + 1 + offset; } } /* Return 1 if the function epilogue is just a single "ret". */ int avr_simple_epilogue (void) { return (! frame_pointer_needed && get_frame_size () == 0 && avr_regs_to_save (NULL) == 0 && ! interrupt_function_p (current_function_decl) @@ -504,125 +524,390 @@ cur_seq += 2; live_seq += 2; } return (cur_seq == live_seq) ? live_seq : 0; } /* Output to FILE the asm instructions to adjust the frame pointer by ADJ (r29:r28 -= ADJ;) which can be positive (prologue) or negative (epilogue). Returns the number of instructions generated. */ static int -out_adj_frame_ptr (FILE *file, int adj) +old_out_adj_frame_ptr (FILE *file, int adj) { int size = 0; if (adj) { if (TARGET_TINY_STACK) { if (adj < -63 || adj > 63) warning (0, "large frame pointer change (%d) with -mtiny-stack", adj); /* The high byte (r29) doesn't change - prefer "subi" (1 cycle) over "sbiw" (2 cycles, same size). */ - fprintf (file, (AS2 (subi, r28, %d) CR_TAB), adj); + fprintf (file, (AS2 (;subi, r28, %d) CR_TAB), adj); size++; } else if (adj < -63 || adj > 63) { - fprintf (file, (AS2 (subi, r28, lo8(%d)) CR_TAB - AS2 (sbci, r29, hi8(%d)) CR_TAB), + fprintf (file, (AS2 (;subi, r28, lo8(%d)) CR_TAB + AS2 (;sbci, r29, hi8(%d)) CR_TAB), adj, adj); size += 2; } else if (adj < 0) { - fprintf (file, (AS2 (adiw, r28, %d) CR_TAB), -adj); + fprintf (file, (AS2 (;adiw, r28, %d) CR_TAB), -adj); size++; } else { - fprintf (file, (AS2 (sbiw, r28, %d) CR_TAB), adj); + fprintf (file, (AS2 (;sbiw, r28, %d) CR_TAB), adj); size++; } } return size; } /* Output to FILE the asm instructions to copy r29:r28 to SPH:SPL, handling various cases of interrupt enable flag state BEFORE and AFTER (0=disabled, 1=enabled, -1=unknown/unchanged) and target_flags. Returns the number of instructions generated. */ static int -out_set_stack_ptr (FILE *file, int before, int after) +old_out_set_stack_ptr (FILE *file, int before, int after) { int do_sph, do_cli, do_save, do_sei, lock_sph, size; /* The logic here is so that -mno-interrupts actually means "it is safe to write SPH in one instruction, then SPL in the next instruction, without disabling interrupts first". The after != -1 case (interrupt/signal) is not affected. */ do_sph = !TARGET_TINY_STACK; lock_sph = do_sph && !TARGET_NO_INTERRUPTS; do_cli = (before != 0 && (after == 0 || lock_sph)); do_save = (do_cli && before == -1 && after == -1); do_sei = ((do_cli || before != 1) && after == 1); size = 1; if (do_save) { - fprintf (file, AS2 (in, __tmp_reg__, __SREG__) CR_TAB); + fprintf (file, AS2 (;in, __tmp_reg__, __SREG__) CR_TAB); size++; } if (do_cli) { - fprintf (file, "cli" CR_TAB); + fprintf (file, ";cli" CR_TAB); size++; } /* Do SPH first - maybe this will disable interrupts for one instruction someday (a suggestion has been sent to address@hidden for consideration in future devices - that would make -mno-interrupts always safe). */ if (do_sph) { - fprintf (file, AS2 (out, __SP_H__, r29) CR_TAB); + fprintf (file, AS2 (;out, __SP_H__, r29) CR_TAB); size++; } /* Set/restore the I flag now - interrupts will be really enabled only after the next instruction. This is not clearly documented, but believed to be true for all AVR devices. */ if (do_save) { - fprintf (file, AS2 (out, __SREG__, __tmp_reg__) CR_TAB); + fprintf (file, AS2 (;out, __SREG__, __tmp_reg__) CR_TAB); size++; } else if (do_sei) { - fprintf (file, "sei" CR_TAB); + fprintf (file, ";sei" CR_TAB); size++; } - fprintf (file, AS2 (out, __SP_L__, r28) "\n"); + fprintf (file, AS2 (;out, __SP_L__, r28) "\n"); + + return size; +} + + +#define AVR_MAX_EPILOGUE_SIZE 30 +rtx epilogue_rtl[AVR_MAX_EPILOGUE_SIZE]; +int epilogue_rtl_count; +static void +start_new_epilogue (void) +{ + epilogue_rtl_count = 0; +} + +static void +add_epilogue_insn (rtx insn) +{ + gcc_assert (epilogue_rtl_count < AVR_MAX_EPILOGUE_SIZE); + + epilogue_rtl [epilogue_rtl_count] = insn; + epilogue_rtl_count += 1; +} + +static int +size_of_insn (rtx insn) +{ + int size; + size = get_attr_length (insn); + size = adjust_insn_length (insn,size); return size; } +int avr_epilogue_size; +int avr_prologue_size; + +void +avr_expand_epilogue (void) +{ + int i = epilogue_rtl_count; + rtx insn; + + while (i > 0) + { + i -= 1; + insn = emit_insn (epilogue_rtl [i]); + avr_epilogue_size += size_of_insn (insn); + } +} + +/* Generate both, function prologue and function epilogue. + * Store the epilogue insns temporarily in an array accessed by the + * helper functions "start_new_epilogue" and "add_epilogue_insn". + * Calculate the length of the prologue and store it in + * avr_prologue_size. */ + +void +avr_expand_prologue (void) +{ + HOST_WIDE_INT frame_size = get_frame_size (); + int reg; + int interrupt_func_p; + int signal_func_p; + int live_seq; + int use_call_prologues; + rtx insn; + + start_new_epilogue (); + avr_prologue_size = 0; + + if (avr_naked_function_p (current_function_decl)) + { + return; + } + + interrupt_func_p = interrupt_function_p (current_function_decl); + signal_func_p = signal_function_p (current_function_decl); + + live_seq = sequent_regs_live (); + use_call_prologues = (TARGET_CALL_PROLOGUES + && !interrupt_func_p && !signal_func_p && live_seq + && (frame_pointer_needed || live_seq > 6) + && (avr_pc_size == 2)); + + if (interrupt_func_p) + { + insn = emit_insn (gen_enable_interrupts () ); + avr_prologue_size += size_of_insn (insn); + } + if (interrupt_func_p || signal_func_p) + { + add_epilogue_insn (gen_avr_return_i ()); + + insn = emit_insn (gen_pushqi (zero_reg_rtx)); + avr_prologue_size += size_of_insn (insn); + add_epilogue_insn (gen_popqi (zero_reg_rtx)); + + insn = emit_insn (gen_pushqi (tmp_reg_rtx)); + avr_prologue_size += size_of_insn (insn); + add_epilogue_insn (gen_popqi (tmp_reg_rtx)); + + insn = emit_insn (gen_movqi_sreg ( + tmp_reg_rtx,gen_rtx_REG (QImode,SREG_REGNO))); + avr_prologue_size += size_of_insn (insn); + add_epilogue_insn (gen_movqi_sreg (gen_rtx_REG (QImode,SREG_REGNO), + tmp_reg_rtx)); + + insn = emit_insn (gen_pushqi (tmp_reg_rtx)); + avr_prologue_size += size_of_insn (insn); + add_epilogue_insn (gen_popqi (tmp_reg_rtx)); + + insn = emit_insn (gen_clear_zeroreg () ); + avr_prologue_size += size_of_insn (insn); + } + else + { + if (! use_call_prologues) + add_epilogue_insn (gen_avr_return ()); + } + + if (use_call_prologues) + { + insn = emit_insn (gen_call_prologue_saves ( + gen_int_mode (frame_size, HImode), + gen_int_mode ((18 - live_seq) * 2, HImode))); + avr_prologue_size += size_of_insn (insn); + rtx label = gen_label_rtx (); + emit_label (label); + + /* Now generate the epilogue. */ + + add_epilogue_insn (gen_epilogue_restores ( + gen_int_mode (live_seq, HImode))); + add_epilogue_insn (gen_adjust_frame_ptr (GEN_INT (+frame_size))); + } + else + { + HARD_REG_SET set; + + avr_regs_to_save (&set); + for (reg = 0; reg < 32; ++reg) + { + if (TEST_HARD_REG_BIT (set, reg)) + { + insn = emit_insn (gen_pushqi (gen_rtx_REG (QImode,reg))); + avr_prologue_size += size_of_insn (insn); + add_epilogue_insn (gen_popqi (gen_rtx_REG (QImode,reg))); + } + } + if (frame_pointer_needed) + { + insn = emit_insn (gen_pushqi (gen_rtx_REG (QImode,28))); + avr_prologue_size += size_of_insn (insn); + add_epilogue_insn (gen_popqi (gen_rtx_REG (QImode,28))); + + insn = emit_insn (gen_pushqi (gen_rtx_REG (QImode,29))); + avr_prologue_size += size_of_insn (insn); + add_epilogue_insn (gen_popqi (gen_rtx_REG (QImode,29))); + + if (frame_size == 0) + { + insn = emit_insn (gen_movhi_sp_to_reg (frame_pointer_rtx)); + avr_prologue_size += size_of_insn (insn); + } + else + { + /* We need to adjust frame pointer and stack pointer + * Method one: (1) SP -= frame_size + * (2) FP = SP + * Method two: (1) FP = SP + * (2) FP -= frame_size + * (3) SP = F + * Let's do it like Andy Hutchinson suggested: + * Calculate first the length of both and choose afterwards. */ + int length_m1 = 0; + int length_m2 = 0; + + /* Method 1: Lets decompose SP -= frame_size into several + * times "rcall ." and possibly one or two + * additional "push __tmp_reg__". */ + { + length_m1 += (frame_size / avr_pc_size) + * size_of_insn (gen_dec_sp ()); + length_m1 += (frame_size % avr_pc_size) + * size_of_insn ( + gen_pushqi (gen_rtx_REG (QImode,28))); + length_m1 += size_of_insn ( + gen_movhi_sp_to_reg (frame_pointer_rtx)); + } + + length_m2 += size_of_insn + (gen_movhi_sp_to_reg (frame_pointer_rtx)); + length_m2 += size_of_insn + (gen_adjust_frame_ptr (GEN_INT (-frame_size))); + if (signal_func_p) + { + /* OK, we now that IRQs are disabled here. */ + length_m2 += size_of_insn ( + gen_movhi_reg_to_sp_without_irq (frame_pointer_rtx)); + } + else + { + length_m2 += size_of_insn + (gen_movhi_reg_to_sp (frame_pointer_rtx)); + } + + if (length_m1 < length_m2) + { + int i; + for (i = 0; i < (frame_size / avr_pc_size); i ++) + { + insn = emit_insn (gen_dec_sp ()); + avr_prologue_size += size_of_insn (insn); + } + for (i = 0; i < (frame_size % avr_pc_size); i ++) + { + insn = emit_insn (gen_pushqi (tmp_reg_rtx)); + avr_prologue_size += size_of_insn (insn); + } + insn = emit_insn (gen_movhi_sp_to_reg (frame_pointer_rtx)); + avr_prologue_size += size_of_insn (insn); + } + else + { + insn = emit_insn (gen_movhi_sp_to_reg (frame_pointer_rtx)); + avr_prologue_size += size_of_insn (insn); + insn = emit_insn (gen_adjust_frame_ptr ( + GEN_INT (-frame_size))); + avr_prologue_size += size_of_insn (insn); + if (signal_func_p) + { + /* OK, we now that IRQs are presently disabled. */ + insn = emit_insn( + gen_movhi_reg_to_sp_without_irq (frame_pointer_rtx)); + avr_prologue_size += size_of_insn (insn); + } + else + { + insn = emit_insn (gen_movhi_reg_to_sp (frame_pointer_rtx)); + avr_prologue_size += size_of_insn (insn); + } + } + { + /* Now the same thing for the epilogue. + * We could either use a sequence of pops or + * decrement the frame pointer and write it to the sp. */ + int sequence_of_pops_length = frame_size; + + int frame_pointer_calc_length = + size_of_insn (gen_adjust_frame_ptr (GEN_INT (+ frame_size))) + + size_of_insn (gen_movhi_reg_to_sp (frame_pointer_rtx)); + + if (sequence_of_pops_length <= frame_pointer_calc_length) + { + int i; + for (i = 0; i < frame_size; i ++) + add_epilogue_insn (gen_popqi (tmp_reg_rtx)); + } + else + { + add_epilogue_insn (gen_movhi_reg_to_sp (frame_pointer_rtx)); + add_epilogue_insn + (gen_adjust_frame_ptr (GEN_INT (+ frame_size))); + } + } + } + } + } +} /* Output function prologue. */ static void avr_output_function_prologue (FILE *file, HOST_WIDE_INT size) { int reg; int interrupt_func_p; int signal_func_p; int main_p; int live_seq; int minimize; @@ -639,118 +924,122 @@ goto out; } interrupt_func_p = interrupt_function_p (current_function_decl); signal_func_p = signal_function_p (current_function_decl); main_p = MAIN_NAME_P (DECL_NAME (current_function_decl)); live_seq = sequent_regs_live (); minimize = (TARGET_CALL_PROLOGUES && !interrupt_func_p && !signal_func_p && live_seq); if (interrupt_func_p) { - fprintf (file,"\tsei\n"); + fprintf (file,"\t;sei\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"); + AS1 (;push,__zero_reg__) CR_TAB + AS1 (;push,__tmp_reg__) CR_TAB + AS2 (;in,__tmp_reg__,__SREG__) CR_TAB + AS1 (;push,__tmp_reg__) CR_TAB + AS1 (;clr,__zero_reg__) "\n"); prologue_size += 5; } if (main_p) { fprintf (file, ("\t" - AS1 (ldi,r28) ",lo8(%s - " HOST_WIDE_INT_PRINT_DEC ")" CR_TAB - AS1 (ldi,r29) ",hi8(%s - " HOST_WIDE_INT_PRINT_DEC ")" CR_TAB - AS2 (out,__SP_H__,r29) CR_TAB - AS2 (out,__SP_L__,r28) "\n"), + AS1 (;ldi,r28) ",lo8(%s - " HOST_WIDE_INT_PRINT_DEC ")" CR_TAB + AS1 (;ldi,r29) ",hi8(%s - " HOST_WIDE_INT_PRINT_DEC ")" CR_TAB + AS2 (;out,__SP_H__,r29) CR_TAB + AS2 (;out,__SP_L__,r28) "\n"), avr_init_stack, size, avr_init_stack, size); prologue_size += 4; } else if (minimize && (frame_pointer_needed || live_seq > 6)) { fprintf (file, ("\t" - AS1 (ldi, r26) ",lo8(" HOST_WIDE_INT_PRINT_DEC ")" CR_TAB - AS1 (ldi, r27) ",hi8(" HOST_WIDE_INT_PRINT_DEC ")" CR_TAB), size, size); + AS1 (;ldi, r26) ",lo8(" HOST_WIDE_INT_PRINT_DEC ")" CR_TAB + AS1 (;ldi, r27) ",hi8(" HOST_WIDE_INT_PRINT_DEC ")" CR_TAB), size, size); - fputs ((AS2 (ldi,r30,pm_lo8(1f)) CR_TAB - AS2 (ldi,r31,pm_hi8(1f)) CR_TAB), file); + fputs ((AS2 (;ldi,r30,pm_lo8(1f)) CR_TAB + AS2 (;ldi,r31,pm_hi8(1f)) CR_TAB), file); prologue_size += 4; if (AVR_MEGA) { - fprintf (file, AS1 (jmp,__prologue_saves__+%d) "\n", + fprintf (file, AS1 (;jmp,__prologue_saves__+%d) "\n", (18 - live_seq) * 2); prologue_size += 2; } else { - fprintf (file, AS1 (rjmp,__prologue_saves__+%d) "\n", + fprintf (file, AS1 (;rjmp,__prologue_saves__+%d) "\n", (18 - live_seq) * 2); ++prologue_size; } - fputs ("1:\n", file); + fputs (";1:\n", file); } else { HARD_REG_SET set; prologue_size += avr_regs_to_save (&set); for (reg = 0; reg < 32; ++reg) { if (TEST_HARD_REG_BIT (set, reg)) { - fprintf (file, "\t" AS1 (push,%s) "\n", avr_regnames[reg]); + fprintf (file, "\t" AS1 (;push,%s) "\n", avr_regnames[reg]); } } 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"); + 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) { fputs ("\t", file); - prologue_size += out_adj_frame_ptr (file, size); + prologue_size += old_out_adj_frame_ptr (file, size); if (interrupt_func_p) { - prologue_size += out_set_stack_ptr (file, 1, 1); + prologue_size += old_out_set_stack_ptr (file, 1, 1); } else if (signal_func_p) { - prologue_size += out_set_stack_ptr (file, 0, 0); + prologue_size += old_out_set_stack_ptr (file, 0, 0); } else { - prologue_size += out_set_stack_ptr (file, -1, -1); + prologue_size += old_out_set_stack_ptr (file, -1, -1); } } } } out: fprintf (file, "/* prologue end (size=%d) */\n", prologue_size); + fprintf (file, "/* prologue end (size=%d) */\n", avr_prologue_size); } + + + /* Output function epilogue. */ static void avr_output_function_epilogue (FILE *file, HOST_WIDE_INT size) { int reg; int interrupt_func_p; int signal_func_p; int main_p; int function_size; int live_seq; int minimize; @@ -784,113 +1073,114 @@ signal_func_p = signal_function_p (current_function_decl); main_p = MAIN_NAME_P (DECL_NAME (current_function_decl)); live_seq = sequent_regs_live (); minimize = (TARGET_CALL_PROLOGUES && !interrupt_func_p && !signal_func_p && live_seq); if (main_p) { /* Return value from main() is already in the correct registers (r25:r24) as the exit() argument. */ if (AVR_MEGA) { - fputs ("\t" AS1 (jmp,exit) "\n", file); + fputs ("\t" AS1 (;jmp,exit) "\n", file); epilogue_size += 2; } else { - fputs ("\t" AS1 (rjmp,exit) "\n", file); + fputs ("\t" AS1 (;rjmp,exit) "\n", file); ++epilogue_size; } } else if (minimize && (frame_pointer_needed || live_seq > 4)) { - fprintf (file, ("\t" AS2 (ldi, r30, %d) CR_TAB), live_seq); + fprintf (file, ("\t" AS2 (;ldi, r30, %d) CR_TAB), live_seq); ++epilogue_size; if (frame_pointer_needed) { - epilogue_size += out_adj_frame_ptr (file, -size); + epilogue_size += old_out_adj_frame_ptr (file, -size); } else { - fprintf (file, (AS2 (in , r28, __SP_L__) CR_TAB - AS2 (in , r29, __SP_H__) CR_TAB)); + 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", + fprintf (file, AS1 (;jmp,__epilogue_restores__+%d) "\n", (18 - live_seq) * 2); epilogue_size += 2; } else { - fprintf (file, AS1 (rjmp,__epilogue_restores__+%d) "\n", + fprintf (file, AS1 (;rjmp,__epilogue_restores__+%d) "\n", (18 - live_seq) * 2); ++epilogue_size; } } else { HARD_REG_SET set; if (frame_pointer_needed) { if (size) { fputs ("\t", file); - epilogue_size += out_adj_frame_ptr (file, -size); + epilogue_size += old_out_adj_frame_ptr (file, -size); if (interrupt_func_p || signal_func_p) { - epilogue_size += out_set_stack_ptr (file, -1, 0); + epilogue_size += old_out_set_stack_ptr (file, -1, 0); } else { - epilogue_size += out_set_stack_ptr (file, -1, -1); + epilogue_size += old_out_set_stack_ptr (file, -1, -1); } } fprintf (file, "\t" - AS1 (pop,r29) CR_TAB - AS1 (pop,r28) "\n"); + AS1 (;pop,r29) CR_TAB + AS1 (;pop,r28) "\n"); epilogue_size += 2; } epilogue_size += avr_regs_to_save (&set); for (reg = 31; reg >= 0; --reg) { if (TEST_HARD_REG_BIT (set, reg)) { - fprintf (file, "\t" AS1 (pop,%s) "\n", avr_regnames[reg]); + fprintf (file, "\t" AS1 (;pop,%s) "\n", avr_regnames[reg]); } } 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"); + 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"); + fprintf (file, "\t;reti\n"); } else - fprintf (file, "\tret\n"); + fprintf (file, "\t;ret\n"); ++epilogue_size; } out: fprintf (file, "/* epilogue end (size=%d) */\n", epilogue_size); + fprintf (file, "/* epilogue end (size=%d) */\n", avr_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 @@ -4207,24 +4497,27 @@ insn, operands, len, 4); return ""; } /* Modifies the length assigned to instruction INSN LEN is the initially computed length of the insn. */ int adjust_insn_length (rtx insn, int len) { rtx patt = PATTERN (insn); rtx set; + + if (! patt) + return len; if (GET_CODE (patt) == SET) { rtx op[10]; op[1] = SET_SRC (patt); op[0] = SET_DEST (patt); if (general_operand (op[1], VOIDmode) && general_operand (op[0], VOIDmode)) { switch (GET_MODE (op[0])) { case QImode: @@ -4826,50 +5119,50 @@ { unsigned int i; static const int order_0[] = { 24,25, 18,19, 20,21, 22,23, 30,31, 26,27, 28,29, 17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2, 0,1, - 32,33,34,35 + 32,33,34,35,36 }; static const 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 + 32,33,34,35,36 }; static const 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 + 32,33,34,35,36 }; const int *order = (TARGET_ORDER_1 ? order_1 : TARGET_ORDER_2 ? order_2 : order_0); for (i=0; i < ARRAY_SIZE (order_0); ++i) reg_alloc_order[i] = order[i]; } /* Mutually recursive subroutine of avr_rtx_cost for calculating the cost of an RTX operand given its context. X is the rtx of the Index: avr.h =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/config/avr/avr.h,v retrieving revision 1.114 diff -U12 -r1.114 avr.h --- avr.h 27 Apr 2005 17:02:34 -0000 1.114 +++ avr.h 18 Sep 2005 14:59:34 -0000 @@ -28,37 +28,42 @@ { \ builtin_define_std ("AVR"); \ if (avr_base_arch_macro) \ builtin_define (avr_base_arch_macro); \ if (avr_extra_arch_macro) \ builtin_define (avr_extra_arch_macro); \ if (avr_asm_only_p) \ builtin_define ("__AVR_ASM_ONLY__"); \ if (avr_enhanced_p) \ builtin_define ("__AVR_ENHANCED__"); \ if (avr_mega_p) \ builtin_define ("__AVR_MEGA__"); \ + if (avr_large_flash_p) \ + builtin_define ("__AVR_LARGE_FLASH__"); \ if (TARGET_NO_INTERRUPTS) \ builtin_define ("__NO_INTERRUPTS__"); \ } \ while (0) extern const char *avr_base_arch_macro; extern const char *avr_extra_arch_macro; extern int avr_mega_p; extern int avr_enhanced_p; +extern int avr_large_flash_p; extern int avr_asm_only_p; +extern int avr_pc_size; #define AVR_MEGA (avr_mega_p && !TARGET_SHORT_CALLS) #define AVR_ENHANCED (avr_enhanced_p) +#define AVR_LARGE_FLASH (avr_large_flash_p) #define TARGET_VERSION fprintf (stderr, " (GNU assembler syntax)"); #define OVERRIDE_OPTIONS avr_override_options () #define CAN_DEBUG_WITHOUT_FP #define BITS_BIG_ENDIAN 0 #define BYTES_BIG_ENDIAN 0 #define WORDS_BIG_ENDIAN 0 #ifdef IN_LIBGCC2 @@ -94,132 +99,138 @@ #define LONG_LONG_TYPE_SIZE (INT_TYPE_SIZE == 8 ? 32 : 64) #define FLOAT_TYPE_SIZE 32 #define DOUBLE_TYPE_SIZE 32 #define LONG_DOUBLE_TYPE_SIZE 32 #define DEFAULT_SIGNED_CHAR 1 #define SIZE_TYPE (INT_TYPE_SIZE == 8 ? "long unsigned int" : "unsigned int") #define PTRDIFF_TYPE (INT_TYPE_SIZE == 8 ? "long int" :"int") #define WCHAR_TYPE_SIZE 16 -#define FIRST_PSEUDO_REGISTER 36 +#define FIRST_PSEUDO_REGISTER 37 + +#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, /* SREG */ \ + 1,1 /* arg pointer */ } -#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 */ } #define CALL_USED_REGISTERS { \ - 1,1,/* r0 r1 */ \ + 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 */ } + 1, /* SREG */ \ + 1,1 /* arg pointer */} #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 \ + 32,33,34,35,36 \ } #define ORDER_REGS_FOR_LOCAL_ALLOC order_regs_for_local_alloc () #define HARD_REGNO_NREGS(REGNO, MODE) ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) #define HARD_REGNO_MODE_OK(REGNO, MODE) avr_hard_regno_mode_ok(REGNO, MODE) #define MODES_TIEABLE_P(MODE1, MODE2) 1 enum reg_class { NO_REGS, R0_REG, /* r0 */ + CC_REG, /* SREG */ 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 }; #define N_REG_CLASSES (int)LIM_REG_CLASSES #define REG_CLASS_NAMES { \ "NO_REGS", \ "R0_REG", /* r0 */ \ + "CC_REG", /* SREG */ \ "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" } #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 */ \ + {0x00000000,0x00000004}, /* CC_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), \ @@ -283,25 +294,25 @@ #define STARTING_FRAME_OFFSET 1 #define STACK_POINTER_OFFSET 1 #define FIRST_PARM_OFFSET(FUNDECL) 0 #define STACK_BOUNDARY 8 #define STACK_POINTER_REGNUM 32 #define FRAME_POINTER_REGNUM REG_Y -#define ARG_POINTER_REGNUM 34 +#define ARG_POINTER_REGNUM 35 #define STATIC_CHAIN_REGNUM 2 #define FRAME_POINTER_REQUIRED frame_pointer_required_p() #define ELIMINABLE_REGS { \ {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \ {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM} \ ,{FRAME_POINTER_REGNUM+1,STACK_POINTER_REGNUM+1}} #define CAN_ELIMINATE(FROM, TO) (((FROM) == ARG_POINTER_REGNUM \ && (TO) == FRAME_POINTER_REGNUM) \ @@ -447,25 +458,25 @@ #define MEMORY_MOVE_COST(MODE,CLASS,IN) ((MODE)==QImode ? 2 : \ (MODE)==HImode ? 4 : \ (MODE)==SImode ? 8 : \ (MODE)==SFmode ? 8 : 16) #define BRANCH_COST 0 #define SLOW_BYTE_ACCESS 0 #define NO_FUNCTION_CSE -#define TEXT_SECTION_ASM_OP "\t.text" +#define TEXT_SECTION_ASM_OP "\t.text 2" #define DATA_SECTION_ASM_OP "\t.data" #define BSS_SECTION_ASM_OP "\t.section .bss" /* Define the pseudo-ops used to switch to the .ctors and .dtors sections. There are no shared libraries on this target, and these sections are placed in the read-only program memory, so they are not writable. */ #undef CTORS_SECTION_ASM_OP #define CTORS_SECTION_ASM_OP "\t.section .ctors,\"a\",@progbits" @@ -544,25 +555,37 @@ #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 { \ ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "function"); \ - ASM_OUTPUT_LABEL (FILE, NAME); \ + if (avr_pc_size != 3) \ + { \ + ASM_OUTPUT_LABEL (FILE, NAME); \ + } \ + else \ + { \ + fputs ("\t.text 1 \n",(FILE)); \ + ASM_OUTPUT_LABEL (FILE, NAME); \ + fprintf ((FILE),"\tjmp _text2_%s ; jump stub\n",NAME); \ + fputs ("\t.text 2 \n",(FILE)); \ + fprintf ((FILE),".global _text2_%s \n",(NAME)); \ + fprintf ((FILE),"_text2_%s: \n",(NAME)); \ + } \ } while (0) #define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \ do { \ if (!flag_inhibit_size_directive) \ ASM_OUTPUT_MEASURED_SIZE (FILE, FNAME); \ } while (0) #define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) \ do { \ ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object"); \ size_directive_output = 0; \ @@ -643,25 +666,25 @@ #define SUPPORTS_WEAK 1 #define ASM_GENERATE_INTERNAL_LABEL(STRING, PREFIX, NUM) \ sprintf (STRING, "*.%s%lu", PREFIX, (unsigned long)(NUM)) #define HAS_INIT_SECTION 1 #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"} + "__SPL__","__SPH__","__SR__","argL","argH"} #define FINAL_PRESCAN_INSN(insn, operand, nop) final_prescan_insn (insn, operand,nop) #define PRINT_OPERAND(STREAM, X, CODE) print_operand (STREAM, X, CODE) #define PRINT_OPERAND_PUNCT_VALID_P(CODE) ((CODE) == '~') #define PRINT_OPERAND_ADDRESS(STREAM, X) print_operand_address(STREAM, X) #define USER_LABEL_PREFIX "" #define ASSEMBLER_DIALECT AVR_ENHANCED @@ -738,41 +761,42 @@ /* 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 ADJUST_INSN_LENGTH(INSN, LENGTH) (LENGTH =\ adjust_insn_length (INSN, LENGTH)) #define CPP_SPEC "%{posix:-D_POSIX_SOURCE}" -#define CC1_SPEC "%{profile:-p}" +#define CC1_SPEC "%{profile:-p:-fno-delete-null-pointer-checks}" #define CC1PLUS_SPEC "%{!frtti:-fno-rtti} \ %{!fenforce-eh-specs:-fno-enforce-eh-specs} \ - %{!fexceptions:-fno-exceptions}" + %{!fexceptions:-fno-exceptions:-fno-delete-null-pointer-checks}" /* A C string constant that tells the GCC drvier program options to pass to `cc1plus'. */ #define ASM_SPEC "%{mmcu=*:-mmcu=%*}" #define LINK_SPEC " %{!mmcu*:-m avr2}\ %{mmcu=at90s1200|mmcu=attiny11|mmcu=attiny12|mmcu=attiny15|mmcu=attiny28:-m avr1} \ %{mmcu=attiny22|mmcu=attiny26|mmcu=at90s2*|mmcu=at90s4*|mmcu=at90s8*|mmcu=at90c8*|mmcu=at86rf401|mmcu=attiny13|mmcu=attiny2313:-m avr2}\ %{mmcu=atmega103|mmcu=atmega603|mmcu=at43*|mmcu=at76*:-m avr3}\ %{mmcu=atmega8*|mmcu=atmega48:-m avr4}\ %{mmcu=atmega16*|mmcu=atmega32*|mmcu=atmega64*|mmcu=atmega128|mmcu=at90can128|mmcu=at94k:-m avr5}\ -%{mmcu=atmega325|mmcu=atmega3250|mmcu=atmega48|mmcu=atmega88|mmcu=atmega64|mmcu=atmega645|mmcu=atmega6450|mmcu=atmega128|mmcu=at90can128|mmcu=at90can128|mmcu=atmega162|mmcu=atmega165|mmcu=atmega168|mmcu=atmega169: -Tdata 0x800100} " +%{mmcu=atmega256*:-m avr6}\ +%{mmcu=atmega325|mmcu=atmega3250|mmcu=atmega48|mmcu=atmega88|mmcu=atmega64|mmcu=atmega645|mmcu=atmega6450|mmcu=atmega128|mmcu=at90can128|mmcu=at90can128|mmcu=atmega162|mmcu=atmega165|mmcu=atmega168|mmcu=atmega169|mmcu=atmega2560|mmcu=atmega2561: -Tdata 0x800100} " #define LIB_SPEC \ "%{!mmcu=at90s1*:%{!mmcu=attiny11:%{!mmcu=attiny12:%{!mmcu=attiny15:%{!mmcu=attiny28: -lc }}}}}" #define LIBSTDCXX "-lgcc" /* No libstdc++ for now. Empty string doesn't work. */ #define LIBGCC_SPEC \ "%{!mmcu=at90s1*:%{!mmcu=attiny11:%{!mmcu=attiny12:%{!mmcu=attiny15:%{!mmcu=attiny28: -lgcc }}}}}" #define STARTFILE_SPEC "%(crt_binutils)" @@ -815,24 +839,26 @@ %{mmcu=atmega163:crtm163.o%s} \ %{mmcu=atmega165:crtm165.o%s} \ %{mmcu=atmega168:crtm168.o%s} \ %{mmcu=atmega169:crtm169.o%s} \ %{mmcu=atmega32:crtm32.o%s} \ %{mmcu=atmega323:crtm323.o%s} \ %{mmcu=atmega325:crtm325.o%s} \ %{mmcu=atmega3250:crtm3250.o%s} \ %{mmcu=atmega64:crtm64.o%s} \ %{mmcu=atmega645:crtm6450.o%s} \ %{mmcu=atmega6450:crtm6450.o%s} \ %{mmcu=atmega128:crtm128.o%s} \ +%{mmcu=atmega2560:crtm2560.o%s} \ +%{mmcu=atmega2561:crtm2561.o%s} \ %{mmcu=at90can128:crtcan128.o%s} \ %{mmcu=at94k:crtat94k.o%s}" #define EXTRA_SPECS {"crt_binutils", CRT_BINUTILS_SPECS}, /* This is the default without any -mmcu=* option (AT90S*). */ #define MULTILIB_DEFAULTS { "mmcu=avr2" } /* This is undefined macro for collect2 disabling */ #define LINKER_NAME "ld" #define TEST_HARD_REG_CLASS(CLASS, REGNO) \ @@ -852,14 +878,17 @@ #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" /* Temporary register r0 */ #define TMP_REGNO 0 /* zero register r1 */ #define ZERO_REGNO 1 + +/* Status register regno */ +#define SREG_REGNO 34 #define PREFERRED_DEBUGGING_TYPE DBX_DEBUG Index: avr.md =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/config/avr/avr.md,v retrieving revision 1.51 diff -U12 -r1.51 avr.md --- avr.md 13 Mar 2005 10:09:53 -0000 1.51 +++ avr.md 18 Sep 2005 14:59:40 -0000 @@ -26,26 +26,40 @@ ;; A No effect (add 0). ;; B Add 1 to REG number, MEM address or CONST_INT. ;; C Add 2. ;; D Add 3. ;; j Branch condition. ;; k Reverse branch condition. ;; o Displacement for (mem (plus (reg) (const_int))) operands. ;; p POST_INC or PRE_DEC address as a pointer (X, Y, Z) ;; r POST_INC or PRE_DEC address as a register (r26, r28, r30) ;; ~ Output 'r' if not AVR_MEGA. ;; UNSPEC usage: -;; 0 Length of a string, see "strlenhi". -;; 1 Read from a word address in program memory, see "casesi". + +(define_constants + [(UNSP_STRLEN 0) ; Length of a string, see "strlenhi". + (UNSP_READPM 1) ; Read from a word address in program memory, see "casesi". + (UNSP_NEVER_DEL 2) ; Never optimize away an insn with this unspec. + (UNSP_SET_OUTSIDE 3) ; Use in prologue: reg set outside of current functn. + (UNSP_USED_OUTSIDE 4) ; Use in epilogue: reg used outside of current functn. + (UNSPV_RETI 5) + (UNSPV_RET 6) + ]) + +(define_constants + [(TMP_REGNO 0) + (ZERO_REGNO 1) + (SP_REGNO 32) + (SREG 34)]) ;; Condition code settings. (define_attr "cc" "none,set_czn,set_zn,set_n,compare,clobber" (const_string "none")) (define_attr "type" "branch,branch1,arith,xcall" (const_string "arith")) (define_attr "mcu_enhanced" "yes,no" (const (if_then_else (symbol_ref "AVR_ENHANCED") (const_string "yes") (const_string "no")))) @@ -82,93 +96,99 @@ (const_int -2044)) (le (minus (pc) (match_dup 0)) (const_int 2043))) (const_int 3) (const_int 4))) (eq_attr "type" "xcall") (if_then_else (eq_attr "mcu_mega" "no") (const_int 1) (const_int 2))] (const_int 2))) (define_insn "*pop1" - [(set (reg:HI 32) (plus:HI (reg:HI 32) (const_int 1)))] + [(set (reg:HI SP_REGNO) (plus:HI (reg:HI SP_REGNO) (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)))] + [(set (reg:HI SP_REGNO) (plus:HI (reg:HI SP_REGNO) (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)))] + [(set (reg:HI SP_REGNO) (plus:HI (reg:HI SP_REGNO) (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)))] + [(set (reg:HI SP_REGNO) (plus:HI (reg:HI SP_REGNO) (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)))] + [(set (reg:HI SP_REGNO) (plus:HI (reg:HI SP_REGNO) (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))) +(define_insn "pushqi" + [(set (mem:QI (post_dec (reg:HI SP_REGNO))) (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 "popqi" + [(set (match_operand:QI 0 "register_operand" "=r") + (mem:QI (pre_inc (reg:HI SP_REGNO))))] + "" + "pop %0" + [(set_attr "length" "1")]) (define_insn "*pushhi" - [(set (mem:HI (post_dec (reg:HI 32))) + [(set (mem:HI (post_dec (reg:HI SP_REGNO))) (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))) + [(set (mem:SI (post_dec (reg:HI SP_REGNO))) (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))) + [(set (mem:SF (post_dec (reg:HI SP_REGNO))) (match_operand:SF 0 "register_operand" "r"))] "" "push %D0 push %C0 push %B0 push %A0" [(set_attr "length" "4")]) ;;======================================================================== ;; move byte ;; The last alternative (any immediate constant to any register) is ;; very expensive. It should be optimized by peephole2 if a scratch @@ -469,46 +489,48 @@ return (AS2 (st,%a0+,__zero_reg__) CR_TAB AS2 (subi,%A1,1) CR_TAB AS2 (sbci,%B1,0) CR_TAB AS1 (brne,.-8)); }" [(set_attr "length" "3,4") (set_attr "cc" "clobber,clobber")]) (define_expand "strlenhi" [(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)) + (match_operand:HI 3 "immediate_operand" "")] + UNSP_STRLEN)) (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)))] "" "{ rtx addr; if (! (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0)) FAIL; addr = copy_to_mode_reg (Pmode, XEXP (operands[1],0)); operands[1] = gen_rtx_MEM (BLKmode, addr); operands[5] = addr; 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))] + (match_operand:HI 2 "immediate_operand" "i")] + UNSP_STRLEN))] "" "ld __tmp_reg__,%a0+ tst __tmp_reg__ brne .-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") @@ -821,135 +843,249 @@ ;; - we get both the quotient and the remainder at no extra cost (define_expand "divmodqi4" [(set (reg:QI 24) (match_operand:QI 1 "register_operand" "")) (set (reg:QI 22) (match_operand:QI 2 "register_operand" "")) (parallel [(set (reg:QI 24) (div:QI (reg:QI 24) (reg:QI 22))) (set (reg:QI 25) (mod:QI (reg:QI 24) (reg:QI 22))) (clobber (reg:QI 22)) (clobber (reg:QI 23))]) (set (match_operand:QI 0 "register_operand" "") (reg:QI 24)) (set (match_operand:QI 3 "register_operand" "") (reg:QI 25))] "" - "") + "/* Generate RTL identical to above template with the only difference + * that we add register notes to the last two set insn describing the + * contents of the registers. This way CSE is able to use both results. */ + rtx insn; + emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (QImode,24), operands[1])); + emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (QImode,22), operands[2])); + emit_insn (gen_divmodqi4_call () ); + insn = emit_insn (gen_rtx_SET (VOIDmode, + operands[0], gen_rtx_REG (QImode,24))); + set_unique_reg_note (insn, REG_EQUAL, + gen_rtx_fmt_ee (DIV, QImode, + copy_rtx (operands[1]), + copy_rtx (operands[2]))); + insn = emit_insn (gen_rtx_SET (VOIDmode, + operands[3], gen_rtx_REG (QImode,25))); + set_unique_reg_note (insn, REG_EQUAL, + gen_rtx_fmt_ee (MOD, QImode, + copy_rtx (operands[1]), + copy_rtx (operands[2]))); + DONE;") -(define_insn "*divmodqi4_call" +(define_insn "divmodqi4_call" [(set (reg:QI 24) (div:QI (reg:QI 24) (reg:QI 22))) (set (reg:QI 25) (mod:QI (reg:QI 24) (reg:QI 22))) (clobber (reg:QI 22)) (clobber (reg:QI 23))] "" "%~call __divmodqi4" [(set_attr "type" "xcall") (set_attr "cc" "clobber")]) (define_expand "udivmodqi4" [(set (reg:QI 24) (match_operand:QI 1 "register_operand" "")) (set (reg:QI 22) (match_operand:QI 2 "register_operand" "")) (parallel [(set (reg:QI 24) (udiv:QI (reg:QI 24) (reg:QI 22))) (set (reg:QI 25) (umod:QI (reg:QI 24) (reg:QI 22))) (clobber (reg:QI 23))]) (set (match_operand:QI 0 "register_operand" "") (reg:QI 24)) (set (match_operand:QI 3 "register_operand" "") (reg:QI 25))] "" - "") + "/* Generate RTL identical to above template with the only difference + * that we add register notes to the last two set insn describing the + * contents of the registers. This way CSE is able to use both results. */ + rtx insn; + emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (QImode,24), operands[1])); + emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (QImode,22), operands[2])); + emit_insn (gen_udivmodqi4_call () ); + insn = emit_insn (gen_rtx_SET (VOIDmode, + operands[0], gen_rtx_REG (QImode,24))); + set_unique_reg_note (insn, REG_EQUAL, + gen_rtx_fmt_ee (UDIV, QImode, + copy_rtx (operands[1]), + copy_rtx (operands[2]))); + insn = emit_insn (gen_rtx_SET (VOIDmode, + operands[3], gen_rtx_REG (QImode,25))); + set_unique_reg_note (insn, REG_EQUAL, + gen_rtx_fmt_ee (UMOD, QImode, + copy_rtx (operands[1]), + copy_rtx (operands[2]))); + DONE;") -(define_insn "*udivmodqi4_call" +(define_insn "udivmodqi4_call" [(set (reg:QI 24) (udiv:QI (reg:QI 24) (reg:QI 22))) (set (reg:QI 25) (umod:QI (reg:QI 24) (reg:QI 22))) (clobber (reg:QI 23))] "" "%~call __udivmodqi4" [(set_attr "type" "xcall") (set_attr "cc" "clobber")]) (define_expand "divmodhi4" [(set (reg:HI 24) (match_operand:HI 1 "register_operand" "")) (set (reg:HI 22) (match_operand:HI 2 "register_operand" "")) (parallel [(set (reg:HI 22) (div:HI (reg:HI 24) (reg:HI 22))) (set (reg:HI 24) (mod:HI (reg:HI 24) (reg:HI 22))) (clobber (reg:HI 26)) (clobber (reg:QI 21))]) (set (match_operand:HI 0 "register_operand" "") (reg:HI 22)) (set (match_operand:HI 3 "register_operand" "") (reg:HI 24))] "" - "") + "/* Generate RTL identical to above template with the only difference + * that we add register notes to the last two set insn describing the + * contents of the registers. This way CSE is able to use both results. */ + rtx insn; + emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (HImode,24), operands[1])); + emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (HImode,22), operands[2])); + emit_insn (gen_divmodhi4_call () ); + insn = emit_insn (gen_rtx_SET (VOIDmode, + operands[0], gen_rtx_REG (HImode,22))); + set_unique_reg_note (insn, REG_EQUAL, + gen_rtx_fmt_ee (DIV, HImode, + copy_rtx (operands[1]), + copy_rtx (operands[2]))); + insn = emit_insn (gen_rtx_SET (VOIDmode, + operands[3], gen_rtx_REG (HImode,24))); + set_unique_reg_note (insn, REG_EQUAL, + gen_rtx_fmt_ee (MOD, HImode, + copy_rtx (operands[1]), + copy_rtx (operands[2]))); + DONE;") -(define_insn "*divmodhi4_call" +(define_insn "divmodhi4_call" [(set (reg:HI 22) (div:HI (reg:HI 24) (reg:HI 22))) (set (reg:HI 24) (mod:HI (reg:HI 24) (reg:HI 22))) (clobber (reg:HI 26)) (clobber (reg:QI 21))] "" "%~call __divmodhi4" [(set_attr "type" "xcall") (set_attr "cc" "clobber")]) (define_expand "udivmodhi4" [(set (reg:HI 24) (match_operand:HI 1 "register_operand" "")) (set (reg:HI 22) (match_operand:HI 2 "register_operand" "")) (parallel [(set (reg:HI 22) (udiv:HI (reg:HI 24) (reg:HI 22))) (set (reg:HI 24) (umod:HI (reg:HI 24) (reg:HI 22))) (clobber (reg:HI 26)) (clobber (reg:QI 21))]) (set (match_operand:HI 0 "register_operand" "") (reg:HI 22)) (set (match_operand:HI 3 "register_operand" "") (reg:HI 24))] "" - "") + "/* Generate RTL identical to above template with the only difference + * that we add register notes to the last two set insn describing the + * contents of the registers. This way CSE is able to use both results. */ + rtx insn; + emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (HImode,24), operands[1])); + emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (HImode,22), operands[2])); + emit_insn (gen_udivmodhi4_call () ); + insn = emit_insn (gen_rtx_SET (VOIDmode, + operands[0], gen_rtx_REG (HImode,22))); + set_unique_reg_note (insn, REG_EQUAL, + gen_rtx_fmt_ee (UDIV, HImode, + copy_rtx (operands[1]), + copy_rtx (operands[2]))); + insn = emit_insn (gen_rtx_SET (VOIDmode, + operands[3], gen_rtx_REG (HImode,24))); + set_unique_reg_note (insn, REG_EQUAL, + gen_rtx_fmt_ee (UMOD, HImode, + copy_rtx (operands[1]), + copy_rtx (operands[2]))); + DONE;") -(define_insn "*udivmodhi4_call" +(define_insn "udivmodhi4_call" [(set (reg:HI 22) (udiv:HI (reg:HI 24) (reg:HI 22))) (set (reg:HI 24) (umod:HI (reg:HI 24) (reg:HI 22))) (clobber (reg:HI 26)) (clobber (reg:QI 21))] "" "%~call __udivmodhi4" [(set_attr "type" "xcall") (set_attr "cc" "clobber")]) (define_expand "divmodsi4" [(set (reg:SI 22) (match_operand:SI 1 "register_operand" "")) (set (reg:SI 18) (match_operand:SI 2 "register_operand" "")) (parallel [(set (reg:SI 18) (div:SI (reg:SI 22) (reg:SI 18))) (set (reg:SI 22) (mod:SI (reg:SI 22) (reg:SI 18))) (clobber (reg:HI 26)) (clobber (reg:HI 30))]) (set (match_operand:SI 0 "register_operand" "") (reg:SI 18)) (set (match_operand:SI 3 "register_operand" "") (reg:SI 22))] "" - "") + "/* Generate RTL identical to above template with the only difference + * that we add register notes to the last two set insn describing the + * contents of the registers. This way CSE is able to use both results. */ + rtx insn; + emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode,22), operands[1])); + emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode,18), operands[2])); + emit_insn (gen_divmodsi4_call () ); + insn = emit_insn (gen_rtx_SET (VOIDmode, + operands[0], gen_rtx_REG (SImode,18))); + set_unique_reg_note (insn, REG_EQUAL, + gen_rtx_fmt_ee (DIV, SImode, + copy_rtx (operands[1]), + copy_rtx (operands[2]))); + insn = emit_insn (gen_rtx_SET (VOIDmode, + operands[3], gen_rtx_REG (SImode,22))); + set_unique_reg_note (insn, REG_EQUAL, + gen_rtx_fmt_ee (MOD, SImode, + copy_rtx (operands[1]), + copy_rtx (operands[2]))); + DONE;") -(define_insn "*divmodsi4_call" +(define_insn "divmodsi4_call" [(set (reg:SI 18) (div:SI (reg:SI 22) (reg:SI 18))) (set (reg:SI 22) (mod:SI (reg:SI 22) (reg:SI 18))) (clobber (reg:HI 26)) (clobber (reg:HI 30))] "" "%~call __divmodsi4" [(set_attr "type" "xcall") (set_attr "cc" "clobber")]) (define_expand "udivmodsi4" [(set (reg:SI 22) (match_operand:SI 1 "register_operand" "")) (set (reg:SI 18) (match_operand:SI 2 "register_operand" "")) (parallel [(set (reg:SI 18) (udiv:SI (reg:SI 22) (reg:SI 18))) (set (reg:SI 22) (umod:SI (reg:SI 22) (reg:SI 18))) (clobber (reg:HI 26)) (clobber (reg:HI 30))]) (set (match_operand:SI 0 "register_operand" "") (reg:SI 18)) (set (match_operand:SI 3 "register_operand" "") (reg:SI 22))] "" - "") + "/* Generate RTL identical to above template with the only difference + * that we add register notes to the last two set insn describing the + * contents of the registers. This way CSE is able to use both results. */ + rtx insn; + emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode,22), operands[1])); + emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode,18), operands[2])); + emit_insn (gen_udivmodsi4_call () ); + insn = emit_insn (gen_rtx_SET (VOIDmode, + operands[0], gen_rtx_REG (SImode,18))); + set_unique_reg_note (insn, REG_EQUAL, + gen_rtx_fmt_ee (UDIV, SImode, + copy_rtx (operands[1]), + copy_rtx (operands[2]))); + insn = emit_insn (gen_rtx_SET (VOIDmode, + operands[3], gen_rtx_REG (SImode,22))); + set_unique_reg_note (insn, REG_EQUAL, + gen_rtx_fmt_ee (UMOD, SImode, + copy_rtx (operands[1]), + copy_rtx (operands[2]))); + DONE;") -(define_insn "*udivmodsi4_call" +(define_insn "udivmodsi4_call" [(set (reg:SI 18) (udiv:SI (reg:SI 22) (reg:SI 18))) (set (reg:SI 22) (umod:SI (reg:SI 22) (reg:SI 18))) (clobber (reg:HI 26)) (clobber (reg:HI 30))] "" "%~call __udivmodsi4" [(set_attr "type" "xcall") (set_attr "cc" "clobber")]) ;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ; and @@ -2086,25 +2222,30 @@ return \"icall\"; else if (which_alternative==1) { if (AVR_ENHANCED) return (AS2 (movw, r30, %0) CR_TAB \"icall\"); else return (AS2 (mov, r30, %A0) CR_TAB AS2 (mov, r31, %B0) CR_TAB \"icall\"); } else if (which_alternative==2) - return AS1(%~call,%c0); + { + if (avr_pc_size == 3) + return AS1(%~call,_text2_%c0); + else + return AS1(%~call,%c0); + } return (AS2 (ldi,r30,lo8(%0)) CR_TAB AS2 (ldi,r31,hi8(%0)) CR_TAB \"icall\"); }" [(set_attr "cc" "clobber,clobber,clobber,clobber") (set_attr_alternative "length" [(const_int 1) (if_then_else (eq_attr "mcu_enhanced" "yes") (const_int 2) (const_int 3)) (if_then_else (eq_attr "mcu_mega" "yes") (const_int 2) @@ -2167,60 +2308,64 @@ [(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 ;; Table made from "rjmp" instructions for <=8K devices. (define_insn "*tablejump_rjmp" - [(set (pc) (unspec:HI [(match_operand:HI 0 "register_operand" "!z,*r")] 1)) + [(set (pc) (unspec:HI [(match_operand:HI 0 "register_operand" "!z,*r")] + UNSP_READPM)) (use (label_ref (match_operand 1 "" ""))) (clobber (match_dup 0))] "!AVR_MEGA" "@ ijmp push %A0\;push %B0\;ret" [(set_attr "length" "1,3") (set_attr "cc" "none,none")]) ;; Not a prologue, but similar idea - move the common piece of code to libgcc. (define_insn "*tablejump_lib" - [(set (pc) (unspec:HI [(match_operand:HI 0 "register_operand" "z")] 1)) + [(set (pc) (unspec:HI [(match_operand:HI 0 "register_operand" "z")] + UNSP_READPM)) (use (label_ref (match_operand 1 "" ""))) (clobber (match_dup 0))] "AVR_MEGA && TARGET_CALL_PROLOGUES" "jmp __tablejump2__" [(set_attr "length" "2") (set_attr "cc" "clobber")]) (define_insn "*tablejump_enh" - [(set (pc) (unspec:HI [(match_operand:HI 0 "register_operand" "z")] 1)) + [(set (pc) (unspec:HI [(match_operand:HI 0 "register_operand" "z")] + UNSP_READPM)) (use (label_ref (match_operand 1 "" ""))) (clobber (match_dup 0))] "AVR_MEGA && AVR_ENHANCED" "lsl r30 rol r31 lpm __tmp_reg__,Z+ lpm r31,Z mov r30,__tmp_reg__ ijmp" [(set_attr "length" "6") (set_attr "cc" "clobber")]) (define_insn "*tablejump" - [(set (pc) (unspec:HI [(match_operand:HI 0 "register_operand" "z")] 1)) + [(set (pc) (unspec:HI [(match_operand:HI 0 "register_operand" "z")] + UNSP_READPM)) (use (label_ref (match_operand 1 "" ""))) (clobber (match_dup 0))] "AVR_MEGA" "lsl r30 rol r31 lpm inc r30 push r0 lpm push r0 ret" [(set_attr "length" "8") @@ -2235,25 +2380,25 @@ (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) (label_ref (match_operand:HI 3 "" "")))) - (parallel [(set (pc) (unspec:HI [(match_dup 6)] 1)) + (parallel [(set (pc) (unspec:HI [(match_dup 6)] UNSP_READPM)) (use (label_ref (match_dup 3))) (clobber (match_dup 6))])] "" " { operands[6] = gen_reg_rtx (HImode); }") ;; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ;; This instruction sets Z flag @@ -2505,12 +2650,342 @@ "cpse %0,__zero_reg__") (define_peephole [(set (cc0) (compare (match_operand:QI 0 "register_operand" "") (match_operand:QI 1 "register_operand" ""))) (set (pc) (if_then_else (eq (cc0) (const_int 0)) (label_ref (match_operand 2 "" "")) (pc)))] "jump_over_one_insn_p (insn, operands[2])" "cpse %0,%1") + + +;; Insns used during prologue/epilogue generation + +(define_insn "enable_interrupts" + [(set (reg:QI SREG) + (ior:QI (reg:QI SREG) (const_int -128)))] + "" + "sei" + [(set_attr "length" "1" ) + (set_attr "cc" "none")]) + +(define_insn "disable_interrupts" + [(set (reg:QI SREG) + (and:QI (reg:QI SREG) (const_int 127)))] + "" + "cli" + [(set_attr "length" "1" ) + (set_attr "cc" "none")]) + +(define_insn "clear_zeroreg" + [(unspec:QI [(const_int 0)] UNSP_NEVER_DEL) + (set (reg:QI ZERO_REGNO) + (const_int 0) )] + "" + "clr %0" + [(set_attr "length" "1") + (set_attr "cc" "clobber")]) + +(define_insn "set_all_call_used_regs" + [(set (reg:QI 0) (unspec:QI [(const_int 0)] UNSP_NEVER_DEL)) + (set (reg:QI 1) (unspec:QI [(const_int 0)] UNSP_NEVER_DEL)) + (set (reg:QI 18) (unspec:QI [(const_int 0)] UNSP_NEVER_DEL)) + (set (reg:QI 19) (unspec:QI [(const_int 0)] UNSP_NEVER_DEL)) + (set (reg:QI 20) (unspec:QI [(const_int 0)] UNSP_NEVER_DEL)) + (set (reg:QI 21) (unspec:QI [(const_int 0)] UNSP_NEVER_DEL)) + (set (reg:QI 22) (unspec:QI [(const_int 0)] UNSP_NEVER_DEL)) + (set (reg:QI 23) (unspec:QI [(const_int 0)] UNSP_NEVER_DEL)) + (set (reg:QI 24) (unspec:QI [(const_int 0)] UNSP_NEVER_DEL)) + (set (reg:QI 25) (unspec:QI [(const_int 0)] UNSP_NEVER_DEL)) + (set (reg:QI 26) (unspec:QI [(const_int 0)] UNSP_NEVER_DEL)) + (set (reg:QI 27) (unspec:QI [(const_int 0)] UNSP_NEVER_DEL)) + (set (reg:QI 30) (unspec:QI [(const_int 0)] UNSP_NEVER_DEL)) + (set (reg:QI 31) (unspec:QI [(const_int 0)] UNSP_NEVER_DEL)) + (set (reg:QI 32) (unspec:QI [(const_int 0)] UNSP_NEVER_DEL)) + (set (reg:QI SREG)(unspec:QI [(const_int 0)] UNSP_NEVER_DEL))] + "" + "" + [(set_attr "length" "0")]); + +(define_insn "*reg_has_useful_value" + [(set (match_operand:QI 0 "general_operand" "=rc") + (unspec:QI [(const_int 0)] UNSP_NEVER_DEL))] + "" + "" + [(set_attr "length" "0")]); + +(define_insn "outside_world_before_std_function" + [(unspec:QI [(const_int 1)] UNSP_NEVER_DEL) + (set (reg:QI ZERO_REGNO) + (const_int 0) )] + "" + ";" + [(set_attr "length" "0")]) + +(define_insn "outside_world_after_std_function" + [(unspec:QI [(const_int 0)] UNSP_NEVER_DEL) + (use (reg:QI ZERO_REGNO))] + "" + ";" + [(set_attr "length" "0")]) + +(define_insn "need_all_call_used" + [(unspec:QI [(const_int 0)] UNSP_NEVER_DEL) + (use (reg:QI 0)) + (use (reg:QI 1)) + (use (reg:QI 18)) + (use (reg:QI 19)) + (use (reg:QI 20)) + (use (reg:QI 21)) + (use (reg:QI 22)) + (use (reg:QI 23)) + (use (reg:QI 24)) + (use (reg:QI 25)) + (use (reg:QI 26)) + (use (reg:QI 27)) + (use (reg:QI 30)) + (use (reg:QI 31)) + (use (reg:QI SREG))] + "" + ";" + [(set_attr "length" "0")]) + +(define_insn "movqi_sreg" + [(set (match_operand:QI 0 "register_operand" "=r,c") + (match_operand:QI 1 "register_operand" "c,r"))] + "" + "@ + in %0,__SREG__ + out __SREG__,%1" + [(set_attr "length" "1,1") + (set_attr "cc" "none,none")]) + +;; Moves from and to the stack pointer. +;; Different insn handling the cases of tiny stack/no irq/default +;; Expanders choosing which alternative to emit. + + +(define_insn "movhi_reg_to_sp_tinys" + [(set (subreg:QI (reg:HI SP_REGNO) 0) + (subreg:QI (match_operand:HI 0 "register_operand" "r") 0))] + "(TARGET_TINY_STACK)" + "out __SP_L__,%0" + [(set_attr "length" "1")]) + +(define_insn "movhi_reg_to_sp_without_irq" + [(set (reg:HI SP_REGNO) + (match_operand:HI 0 "register_operand" "r"))] + "" + "out __SP_H__,%B0\;out __SP_L__,%A0" + [(set_attr "length" "2")]) + +(define_insn "movhi_reg_to_sp_with_irq" + [(set (reg:HI SP_REGNO) + (match_operand:HI 0 "register_operand" "r")) + (set (reg:QI TMP_REGNO) (reg:QI SREG))] + "" + " + in __tmp_reg__,__SREG__ + cli + out __SP_H__,%B0 + out __SREG__,__tmp_reg__ + out __SP_L__,%A0" + [(set_attr "length" "5") + (set_attr "cc" "none")]) + +(define_expand "movhi_reg_to_sp" + [(set (reg:HI SP_REGNO) + (match_operand:HI 0 "register_operand" "r")) + (set (reg:QI TMP_REGNO) (reg:QI SREG))] + "" + "if (TARGET_TINY_STACK) + { + emit_insn (gen_movhi_reg_to_sp_tinys (operands[0])); + DONE; + } + else if (TARGET_NO_INTERRUPTS) + { + emit_insn (gen_movhi_reg_to_sp_without_irq (operands[0])); + DONE; + } + else + { + emit_insn (gen_movhi_reg_to_sp_with_irq (operands[0])); + DONE; + } + ") + + +(define_insn "*movhi_sp_to_reg" + [(set (match_operand:HI 0 "register_operand" "=r") + (reg:HI SP_REGNO))] + "" + "in %B0,__SP_H__\;in %A0,__SP_L__" + [(set_attr "length" "2")]) + +(define_insn "movhi_sp_to_reg_tinys" + [(set (subreg:QI (match_operand:HI 0 "register_operand" "=r") 0) + (subreg:QI (reg:HI SP_REGNO) 0))] + "(TARGET_TINY_STACK)" + "in %A0,__SP_L__" + [(set_attr "length" "1")]) + +(define_expand "movhi_sp_to_reg" + [(set (match_operand:HI 0 "register_operand" "=r") + (reg:HI SP_REGNO))] + "" + "if (TARGET_TINY_STACK) + { + gen_movhi_sp_to_reg_tinys (operands [0]); + DONE; + }") + +;; Adjust the frame pointer. +;; Expand to RTL that is handeled by the usual patterns. +;; Consider the distinction between TINY_STACK and other targets. + +(define_expand "adjust_frame_ptr_tiny_stack" + [(set (subreg:QI (reg:HI 28) 0) + (plus:QI (subreg:QI (reg:HI 28) 0) + (match_operand:QI 0 "immediate_operand" "i")))] + "" + "") + +(define_expand "adjust_frame_ptr" + [(set (reg:HI 28) + (plus:HI (reg:HI 28) + (match_operand:QI 0 "immediate_operand" "i")))] + "" + " + if (TARGET_TINY_STACK) + { + emit_insn (gen_adjust_frame_ptr_tiny_stack (operands[0])); + DONE; + } + ") + +(define_insn "dec_sp_by_two" + [(set (reg:HI SP_REGNO) (minus:HI (reg:HI SP_REGNO) (const_int 2)))] + "(avr_pc_size == 2)" + "rcall . ; SP -= 2" + [(set_attr "length" "1")]) + +(define_insn "dec_sp_by_three" + [(set (reg:HI SP_REGNO) (minus:HI (reg:HI SP_REGNO) (const_int 3)))] + "(avr_pc_size == 3)" + "rcall . ; SP -= 3" + [(set_attr "length" "1")]) + +(define_expand "dec_sp" + [(set (reg:HI SP_REGNO) (minus:HI (reg:HI SP_REGNO) (const_int 2)))] + "" + "if (avr_pc_size == 3) + { + emit_insn (gen_dec_sp_by_three () ); + DONE; + } + ") + +; Library prolog saves +(define_insn "call_prologue_saves" + [(set (reg:HI SP_REGNO ) (minus:HI + (reg:HI SP_REGNO) + (match_operand:HI 0 "immediate_operand" ""))) + (set (reg:HI SP_REGNO) (minus:HI + (reg:HI SP_REGNO) + (match_operand:HI 1 "immediate_operand" "i"))) + (set (reg:HI 26) (match_dup 0)) + (clobber (reg:HI 30))] + "" + "* + { + output_asm_insn (AS2 (ldi,r26,lo8(%0)),operands); + output_asm_insn (AS2 (ldi,r27,hi8(%0)),operands); + output_asm_insn (AS2 (ldi,r30,pm_lo8(1f)),operands); + output_asm_insn (AS2 (ldi,r31,pm_hi8(1f)),operands); + + if (AVR_MEGA ) + output_asm_insn (AS1 (jmp,__prologue_saves__+(%1)),operands); + else + output_asm_insn (AS1 (rjmp,__prologue_saves__+(%1)),operands); + output_asm_insn(\"1:\",operands); + return \"\"; + }" + [(set_attr_alternative "length" + [(if_then_else (eq_attr "mcu_mega" "yes") + (const_int 6) + (const_int 5))]) + (set_attr "cc" "clobber") + ]) + + +(define_insn "epilogue_restores" + [ + (set (reg:HI 28 ) (plus:HI + (reg:HI 28) + (match_operand:HI 0 "immediate_operand" ""))) + (set (reg:HI SP_REGNO) (plus:HI (reg:HI 28) (match_dup 0))) + (clobber (reg:QI 30))] + "" + "* + { + rtx ops[4]; + ops[0]=operands[0]; + ops[1]=gen_int_mode((18 - INTVAL(operands[0])) * 2,HImode); + output_asm_insn (AS2 (ldi,r30,lo8(%0)),ops); + + if (AVR_MEGA ) + output_asm_insn (AS1 (jmp,__epilogue_restores__+(%1)),ops); + else + output_asm_insn (AS1 (rjmp,__epilogue_restores__+(%1)),ops); + return \"\"; + }" + [(set_attr_alternative "length" + [(if_then_else (eq_attr "mcu_mega" "yes") + (const_int 3) + (const_int 2))]) + (set_attr "cc" "clobber") + ]) + +(define_insn "avr_return" + [(parallel [ (return) + (unspec_volatile:QI [(const_int 0)] UNSPV_RET) ])] + "" + "ret" + [(set_attr "length" "1" ) + (set_attr "cc" "none")]) + +(define_insn "avr_return_i" + [(parallel [ (return) + (unspec_volatile:QI [(const_int 0)] UNSPV_RETI) ])] + "" + "reti" + [(set_attr "length" "1" ) + (set_attr "cc" "none")]) + +(define_expand "prologue" + [(const_int 0)] + "" + "{ + avr_expand_prologue (); + DONE; + }") + +(define_expand "epilogue" + [(const_int 0)] + "" + "{ + avr_expand_epilogue (); + DONE; + }") + +; Add a pipeline description for avr that states that every instruction +; needs the avr core in order to execute. +; Only effect is that gcc now runs the scheduler pass that delays +; loads from memory for us and writes back results to memory as early as +; possible. (This reduces register pressure). +; +;(define_cpu_unit "avr_core") +;(define_insn_reservation "all_insn" 1 (const_int 1) "avr_core") Index: t-avr =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/config/avr/t-avr,v retrieving revision 1.15 diff -U12 -r1.15 t-avr --- t-avr 6 Apr 2005 05:34:30 -0000 1.15 +++ t-avr 18 Sep 2005 14:59:41 -0000 @@ -13,52 +13,53 @@ _epilogue \ _exit \ _cleanup \ _tablejump \ _copy_data \ _clear_bss \ _ctors \ _dtors # We do not have the DF type. # Most of the C functions in libgcc2 use almost all registers, # so use -mcall-prologues for smaller code size. -TARGET_LIBGCC2_CFLAGS = -DDF=SF -Dinhibit_libc -mcall-prologues +TARGET_LIBGCC2_CFLAGS = -DDF=SF -Dinhibit_libc -mcall-prologues -Os fp-bit.c: $(srcdir)/config/fp-bit.c $(srcdir)/config/avr/t-avr echo '#define FLOAT' > fp-bit.c echo '#define FLOAT_ONLY' >> fp-bit.c echo '#define CMPtype QItype' >> fp-bit.c echo '#define DF SF' >> fp-bit.c echo '#define DI SI' >> fp-bit.c echo '#define FLOAT_BIT_ORDER_MISMATCH' >> fp-bit.c echo '#define SMALL_MACHINE' >> fp-bit.c echo 'typedef int QItype __attribute__ ((mode (QI)));' >> fp-bit.c cat $(srcdir)/config/fp-bit.c >> fp-bit.c FPBIT = fp-bit.c -MULTILIB_OPTIONS = mmcu=avr2/mmcu=avr3/mmcu=avr4/mmcu=avr5 -MULTILIB_DIRNAMES = avr2 avr3 avr4 avr5 +MULTILIB_OPTIONS = mmcu=avr2/mmcu=avr3/mmcu=avr4/mmcu=avr5/mmcu=avr6 +MULTILIB_DIRNAMES = avr2 avr3 avr4 avr5 avr6 # The many avr2 matches are not listed here - this is the default. MULTILIB_MATCHES = \ mmcu?avr3=mmcu?atmega103 mmcu?avr3=mmcu?atmega603 \ mmcu?avr3=mmcu?at43usb320 mmcu?avr3=mmcu?at43usb355 \ mmcu?avr3=mmcu?at76c711 \ mmcu?avr4=mmcu?atmega8515 mmcu?avr4=mmcu?atmega8535 \ mmcu?avr4=mmcu?atmega8 mmcu?avr4=mmcu?atmega48 \ mmcu?avr4=mmcu?atmega88 \ mmcu?avr5=mmcu?atmega161 mmcu?avr5=mmcu?atmega162 \ mmcu?avr5=mmcu?atmega163 mmcu?avr5=mmcu?atmega169 \ mmcu?avr5=mmcu?atmega16 mmcu?avr5=mmcu?atmega168 \ mmcu?avr5=mmcu?atmega165 \ mmcu?avr5=mmcu?atmega323 mmcu?avr5=mmcu?atmega32 \ mmcu?avr5=mmcu?atmega325 mmcu?avr5=mmcu?atmega3250 \ mmcu?avr5=mmcu?atmega64 mmcu?avr5=mmcu?atmega128 \ mmcu?avr5=mmcu?atmega645 mmcu?avr5=mmcu?atmega6450 \ - mmcu?avr5=mmcu?at94k mmcu?avr5=mmcu?at90can128 + mmcu?avr5=mmcu?at94k mmcu?avr5=mmcu?at90can128 \ + mmcu?avr6=mmcu?atmega2560 mmcu?avr6=mmcu?atmega2561 MULTILIB_EXCEPTIONS = LIBGCC = stmp-multilib INSTALL_LIBGCC = install-multilib