From 78cf8279acfb5c38229579af7d72ce3b9bfc511c Mon Sep 17 00:00:00 2001 From: Marek Michalkiewicz Date: Sat, 24 Jun 2000 20:01:26 +0200 Subject: [PATCH] avr-protos.h (avr_hard_regno_mode_ok): New prototype. * config/avr/avr-protos.h (avr_hard_regno_mode_ok): New prototype. * config/avr/avr.c (out_adj_frame_ptr, out_set_stack_ptr): New functions, common code moved from function_{prologue,epilogue} and extended to support the -mtiny-stack option. (function_prologue, function_epilogue): Use them. Use lo8/hi8 consistently for asm output readability. (avr_hard_regno_mode_ok): New function. * config/avr/avr.h (TARGET_SWITCHES): Fix typo. Add -mtiny-stack. (UNITS_PER_WORD): Define as 4 (not 1) when compiling libgcc2.c. (HARD_REGNO_MODE_OK): Call the avr_hard_regno_mode_ok function. * config/avr/avr.md (*mov_sp_r): Add support for -mtiny-stack. Write SPH before SPL. (*movqi): No need to disable interrupts for just one "out" in alternative 5. Change length attribute from 4 to 1. * config/avr/libgcc.S (__prologue_saves__, __epilogue_restores__): Write SPH before SPL. From-SVN: r34678 --- gcc/ChangeLog | 19 ++++ gcc/config/avr/avr-protos.h | 2 + gcc/config/avr/avr.c | 229 +++++++++++++++++++++++++++++--------------- gcc/config/avr/avr.h | 13 ++- gcc/config/avr/avr.md | 26 ++--- gcc/config/avr/libgcc.S | 8 +- 6 files changed, 201 insertions(+), 96 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4d78128..7e39f84 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,22 @@ +2000-06-24 Marek Michalkiewicz + + * config/avr/avr-protos.h (avr_hard_regno_mode_ok): New prototype. + * config/avr/avr.c (out_adj_frame_ptr, out_set_stack_ptr): + New functions, common code moved from function_{prologue,epilogue} + and extended to support the -mtiny-stack option. + (function_prologue, function_epilogue): Use them. + Use lo8/hi8 consistently for asm output readability. + (avr_hard_regno_mode_ok): New function. + * config/avr/avr.h (TARGET_SWITCHES): Fix typo. Add -mtiny-stack. + (UNITS_PER_WORD): Define as 4 (not 1) when compiling libgcc2.c. + (HARD_REGNO_MODE_OK): Call the avr_hard_regno_mode_ok function. + * config/avr/avr.md (*mov_sp_r): Add support for -mtiny-stack. + Write SPH before SPL. + (*movqi): No need to disable interrupts for just one "out" + in alternative 5. Change length attribute from 4 to 1. + * config/avr/libgcc.S (__prologue_saves__, __epilogue_restores__): + Write SPH before SPL. + 2000-06-24 Bernd Schmidt * rtl.texi (Vector Operations): New node. diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h index 7532754..4399dba 100644 --- a/gcc/config/avr/avr-protos.h +++ b/gcc/config/avr/avr-protos.h @@ -138,6 +138,8 @@ extern int byte_immediate_operand PARAMS ((register rtx op, extern int test_hard_reg_class PARAMS ((enum reg_class class, rtx x)); extern int jump_over_one_insn_p PARAMS ((rtx insn, rtx dest)); +extern int avr_hard_regno_mode_ok PARAMS ((int regno, + enum machine_mode mode)); #endif /* RTX_CODE */ #ifdef HAVE_MACHINE_MODES diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index 5ac63f19..4e58c72 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -49,6 +49,8 @@ static int signal_function_p PARAMS ((tree)); static int sequent_regs_live PARAMS ((void)); static char * ptrreg_to_str PARAMS ((int)); static char * cond_string PARAMS ((enum rtx_code)); +static int out_adj_frame_ptr PARAMS ((FILE *, int)); +static int out_set_stack_ptr PARAMS ((FILE *, int, int)); /* Allocate registers from r25 to r8 for parameters for function calls */ @@ -332,6 +334,124 @@ sequent_regs_live () } +/* 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, adj) + FILE *file; + int adj; +{ + int size = 0; + + if (adj) + { + /* For -mtiny-stack, the high byte (r29) does not change - + prefer "subi" (1 cycle) over "sbiw" (2 cycles). */ + + if (adj < -63 || adj > 63 || TARGET_TINY_STACK) + { + fprintf (file, (AS2 (subi, r28, lo8(%d)) CR_TAB), adj); + size++; + + if (TARGET_TINY_STACK) + { + /* In addition to any local data, each level of function calls + needs at least 4 more bytes of stack space for the saved + frame pointer and return address. So, (255 - 16) leaves + room for 4 levels of function calls. */ + + if (adj < -(255 - 16) || adj > (255 - 16)) + fatal ("Frame pointer change (%d) too big for -mtiny-stack", + adj); + } + else + { + fprintf (file, (AS2 (sbci, r29, hi8(%d)) CR_TAB), adj); + size++; + } + } + else if (adj < 0) + { + fprintf (file, (AS2 (adiw, r28, %d) CR_TAB), -adj); + size++; + } + else + { + 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, before, after) + FILE *file; + int before; + int after; +{ + int do_sph, do_cli, do_save, size; + + if (TARGET_NO_INTERRUPTS) + { + before = 0; + after = 0; + } + + do_sph = !TARGET_TINY_STACK; + do_cli = (before != 0 && (after == 0 || do_sph)); + do_save = (before == -1 && after == -1 && do_cli); + size = 1; + + if (do_save) + { + fprintf (file, AS2 (in, __tmp_reg__, __SREG__) CR_TAB); + size++; + } + + if (do_cli) + { + fprintf (file, "cli" CR_TAB); + size++; + } + + /* Do SPH first - maybe this will disable interrupts for one instruction + someday, much like x86 does when changing SS (a suggestion has been + sent to avr@atmel.com for consideration in future devices). */ + if (do_sph) + { + 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 starts. This was not clearly documented. + XXX - verify this on the new devices with enhanced AVR core. */ + if (do_save) + { + fprintf (file, AS2 (out, __SREG__, __tmp_reg__) CR_TAB); + size++; + } + else if (after == 1 && (before != 1 || do_cli)) + { + fprintf (file, "sei" CR_TAB); + size++; + } + + fprintf (file, AS2 (out, __SP_L__, r28) "\n"); + + return size; +} + + /* Output function prologue */ void @@ -392,8 +512,8 @@ function_prologue (FILE *file, int size) else if (minimize && (frame_pointer_needed || live_seq > 6)) { fprintf (file, ("\t" - AS2 (ldi, r26, %d) CR_TAB - AS2 (ldi, r27, %d) CR_TAB), size & 0xff, size / 0x100); + AS2 (ldi, r26, lo8(%d)) CR_TAB + AS2 (ldi, r27, hi8(%d)) CR_TAB), size, size); fprintf (file, (AS2 (ldi, r30, pm_lo8(.L_%s_body)) CR_TAB AS2 (ldi, r31, pm_hi8(.L_%s_body)) CR_TAB) @@ -444,44 +564,20 @@ function_prologue (FILE *file, int size) 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; - } + fputs ("\t", file); + prologue_size += out_adj_frame_ptr (file, 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; + prologue_size += out_set_stack_ptr (file, -1, 1); } - else if (signal_func_p || TARGET_NO_INTERRUPTS) + else if (signal_func_p) { - fprintf (file, - AS2 (out,__SP_L__,r28) CR_TAB - AS2 (out,__SP_H__,r29) "\n"); - prologue_size += 2; + prologue_size += out_set_stack_ptr (file, 0, 0); } 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; + prologue_size += out_set_stack_ptr (file, -1, -1); } } } @@ -533,20 +629,7 @@ function_epilogue (FILE *file, int size) ++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; - } - } + epilogue_size += out_adj_frame_ptr (file, -size); } else { @@ -574,41 +657,16 @@ function_epilogue (FILE *file, int size) { 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; - } + fputs ("\t", file); + epilogue_size += out_adj_frame_ptr (file, -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; + epilogue_size += out_set_stack_ptr (file, -1, 0); } 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; + epilogue_size += out_set_stack_ptr (file, -1, -1); } } fprintf (file, "\t" @@ -3886,3 +3944,20 @@ jump_over_one_insn_p (insn, dest) int dest_addr = insn_addresses[uid]; return dest_addr - jump_addr == 2; } + +/* Returns 1 if a value of mode MODE can be stored starting with hard + register number REGNO. On the enhanced core, it should be a win to + align modes larger than QI on even register numbers (even if < 24). + so that the "movw" instruction can be used on them. */ + +int +avr_hard_regno_mode_ok (regno, mode) + int regno; + enum machine_mode mode; +{ + if (mode == QImode) + return 1; + if (regno < 24 /* && !TARGET_ENHANCED */ ) + return 1; + return !(regno & 1); +} diff --git a/gcc/config/avr/avr.h b/gcc/config/avr/avr.h index b357af5..0096629 100644 --- a/gcc/config/avr/avr.h +++ b/gcc/config/avr/avr.h @@ -52,6 +52,7 @@ extern int target_flags; #define TARGET_NO_INTERRUPTS (target_flags & 0x20000) #define TARGET_INSN_SIZE_DUMP (target_flags & 0x2000) #define TARGET_CALL_PROLOGUES (target_flags & 0x40000) +#define TARGET_TINY_STACK (target_flags & 0x80000) /* Dump each assembler insn's rtl into the output file. This is for debugging the compiler itself. */ @@ -87,7 +88,8 @@ extern int target_flags; {"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"}, \ + "Use subroutines for functions prologue/epilogue"}, \ + {"tiny-stack", 0x80000, "Change only low 8 bits of stack pointer"}, \ {"rtl",0x10, NULL}, \ {"size",0x2000,"Output instruction size's to the asm file"}, \ {"deb",0xfe0, NULL}, \ @@ -194,8 +196,13 @@ extern struct mcu_type_s *avr_mcu_type; Note that this is not necessarily the width of data type `int'; */ #define BITS_PER_WORD 8 +#ifdef IN_LIBGCC2 +/* This is to get correct SI and DI modes in libgcc2.c (32 and 64 bits). */ +#define UNITS_PER_WORD 4 +#else /* Width of a word, in units (bytes). */ #define UNITS_PER_WORD 1 +#endif /* Width in bits of a pointer. See also the macro `Pmode' defined below. */ @@ -452,9 +459,7 @@ extern struct mcu_type_s *avr_mcu_type; ((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) +#define HARD_REGNO_MODE_OK(REGNO, MODE) avr_hard_regno_mode_ok(REGNO, MODE) /* 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 diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index f3ac93b..4d2451e 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -147,22 +147,29 @@ (define_insn "*mov_sp_r" [(set (reg:HI 32) (match_operand:HI 0 "register_operand" "r"))] - "!TARGET_NO_INTERRUPTS" + "(!TARGET_TINY_STACK && !TARGET_NO_INTERRUPTS)" "in __tmp_reg__,__SREG__ cli - out __SP_L__,%A0 + out __SP_H__,%B0 out __SREG__,__tmp_reg__ - out __SP_H__,%B0" + out __SP_L__,%A0" [(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" + "(!TARGET_TINY_STACK && TARGET_NO_INTERRUPTS)" + "out __SP_H__,%B0 + out __SP_L__,%A0" [(set_attr "length" "2")]) +(define_insn "*mov_sp_r_tiny" + [(set (reg:HI 32) + (match_operand:HI 0 "register_operand" "r"))] + "TARGET_TINY_STACK" + "out __SP_L__,%A0" + [(set_attr "length" "1")]) + ;;======================================================================== ;; move byte (define_expand "movqi" @@ -209,13 +216,10 @@ 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)); + return (AS2 (out,%0,%1)); } }" - [(set_attr "length" "1,1,1,5,5,4") + [(set_attr "length" "1,1,1,5,5,1") (set_attr "cc" "none,clobber,none,clobber,clobber,none")]) ;;============================================================================ diff --git a/gcc/config/avr/libgcc.S b/gcc/config/avr/libgcc.S index 10fa12e..00aa50b 100644 --- a/gcc/config/avr/libgcc.S +++ b/gcc/config/avr/libgcc.S @@ -583,9 +583,9 @@ __prologue_saves__: sbc r29,r27 in __tmp_reg__,__SREG__ cli - out __SP_L__,r28 - out __SREG__,__tmp_reg__ out __SP_H__,r29 + out __SREG__,__tmp_reg__ + out __SP_L__,r28 _prologue_end: ijmp .endfunc @@ -621,9 +621,9 @@ __epilogue_restores__: adc r29,__zero_reg__ in __tmp_reg__,__SREG__ cli - out __SP_L__,r28 - out __SREG__,__tmp_reg__ out __SP_H__,r29 + out __SREG__,__tmp_reg__ + out __SP_L__,r28 mov r28,r26 mov r29,r27 ret -- 2.7.4