diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 15 | ||||
-rw-r--r-- | gcc/config/avr/avr.c | 146 | ||||
-rw-r--r-- | gcc/config/avr/avr.opt | 4 | ||||
-rw-r--r-- | gcc/doc/invoke.texi | 19 |
4 files changed, 127 insertions, 57 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index aaca1df..add57f0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +2011-10-14 Georg-Johann Lay <avr@gjlay.de> + + PR target/46278 + * doc/invoke.texi (AVR Options): Document -mstrict-X. + + * config/avr/avr.opt (-mstrict-X): New option. + (avr_strict_X): New variable reflecting -mstrict-X. + * config/avr/avr.c (avr_reg_ok_for_addr_p): Add parameter + outer_code and pass it down to avr_regno_mode_code_ok_for_base_p. + (avr_legitimate_address_p): Pass outer_code to + avr_reg_ok_for_addr_p and use that function in case PLUS. + (avr_mode_code_base_reg_class): Depend on avr_strict_X. + (avr_regno_mode_code_ok_for_base_p): Ditto, and depend on outer_code. + (avr_option_override): Disable -fcaller-saves if -mstrict-X is on. + 2011-10-14 Jakub Jelinek <jakub@redhat.com> * config/i386/sse.md (neg<mode>2): Use VI_AVX2 iterator instead diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index 4a93c0a..d34ac6a 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -351,6 +351,17 @@ avr_option_override (void) { flag_delete_null_pointer_checks = 0; + /* caller-save.c looks for call-clobbered hard registers that are assigned + to pseudos that cross calls and tries so save-restore them around calls + in order to reduce the number of stack slots needed. + + This might leads to situations where reload is no more able to cope + with the challenge of AVR's very few address registers and fails to + perform the requested spills. */ + + if (avr_strict_X) + flag_caller_saves = 0; + /* Unwind tables currently require a frame pointer for correctness, see toplev.c:process_options(). */ @@ -1205,11 +1216,12 @@ avr_cannot_modify_jumps_p (void) /* Helper function for `avr_legitimate_address_p'. */ static inline bool -avr_reg_ok_for_addr_p (rtx reg, addr_space_t as ATTRIBUTE_UNUSED, int strict) +avr_reg_ok_for_addr_p (rtx reg, addr_space_t as ATTRIBUTE_UNUSED, + RTX_CODE outer_code, bool strict) { return (REG_P (reg) && (avr_regno_mode_code_ok_for_base_p (REGNO (reg), - QImode, MEM, UNKNOWN) + QImode, outer_code, UNKNOWN) || (!strict && REGNO (reg) >= FIRST_PSEUDO_REGISTER))); } @@ -1221,58 +1233,69 @@ avr_reg_ok_for_addr_p (rtx reg, addr_space_t as ATTRIBUTE_UNUSED, int strict) static bool avr_legitimate_address_p (enum machine_mode mode, rtx x, bool strict) { - reg_class_t r = NO_REGS; + bool ok = CONSTANT_ADDRESS_P (x); - if (REG_P (x) - && avr_reg_ok_for_addr_p (x, ADDR_SPACE_GENERIC, strict)) - { - r = POINTER_REGS; - } - else if (CONSTANT_ADDRESS_P (x)) - { - r = ALL_REGS; - } - else if (GET_CODE (x) == PLUS - && REG_P (XEXP (x, 0)) - && CONST_INT_P (XEXP (x, 1)) - && INTVAL (XEXP (x, 1)) >= 0) + switch (GET_CODE (x)) { - rtx reg = XEXP (x, 0); - bool fit = INTVAL (XEXP (x, 1)) <= MAX_LD_OFFSET (mode); - - if (fit) - { - if (! strict - || REGNO (reg) == REG_X - || REGNO (reg) == REG_Y - || REGNO (reg) == REG_Z) - { - r = BASE_POINTER_REGS; - } - - if (reg == frame_pointer_rtx - || reg == arg_pointer_rtx) - { - r = BASE_POINTER_REGS; - } - } - else if (frame_pointer_needed && reg == frame_pointer_rtx) + case REG: + ok = avr_reg_ok_for_addr_p (x, ADDR_SPACE_GENERIC, + MEM, strict); + + if (strict + && DImode == mode + && REG_X == REGNO (x)) { - r = POINTER_Y_REGS; + ok = false; } - } - else if ((GET_CODE (x) == PRE_DEC || GET_CODE (x) == POST_INC) - && REG_P (XEXP (x, 0)) - && avr_reg_ok_for_addr_p (XEXP (x, 0), ADDR_SPACE_GENERIC, strict)) - { - r = POINTER_REGS; - } + break; + + case POST_INC: + case PRE_DEC: + ok = avr_reg_ok_for_addr_p (XEXP (x, 0), ADDR_SPACE_GENERIC, + GET_CODE (x), strict); + break; + case PLUS: + { + rtx reg = XEXP (x, 0); + rtx op1 = XEXP (x, 1); + + if (REG_P (reg) + && CONST_INT_P (op1) + && INTVAL (op1) >= 0) + { + bool fit = IN_RANGE (INTVAL (op1), 0, MAX_LD_OFFSET (mode)); + + if (fit) + { + ok = (! strict + || avr_reg_ok_for_addr_p (reg, ADDR_SPACE_GENERIC, + PLUS, strict)); + + if (reg == frame_pointer_rtx + || reg == arg_pointer_rtx) + { + ok = true; + } + } + else if (frame_pointer_needed + && reg == frame_pointer_rtx) + { + ok = true; + } + } + } + break; + + default: + break; + } + if (avr_log.legitimate_address_p) { - avr_edump ("\n%?: ret=%d=%R, mode=%m strict=%d " + avr_edump ("\n%?: ret=%d, mode=%m strict=%d " "reload_completed=%d reload_in_progress=%d %s:", - !!r, r, mode, strict, reload_completed, reload_in_progress, + ok, mode, strict, reload_completed, reload_in_progress, reg_renumber ? "(reg_renumber)" : ""); if (GET_CODE (x) == PLUS @@ -1288,7 +1311,7 @@ avr_legitimate_address_p (enum machine_mode mode, rtx x, bool strict) avr_edump ("\n%r\n", x); } - return r == NO_REGS ? 0 : (int)r; + return ok; } /* Attempts to replace X with a valid @@ -7304,10 +7327,13 @@ avr_hard_regno_mode_ok (int regno, enum machine_mode mode) reg_class_t avr_mode_code_base_reg_class (enum machine_mode mode ATTRIBUTE_UNUSED, - RTX_CODE outer_code ATTRIBUTE_UNUSED, + RTX_CODE outer_code, RTX_CODE index_code ATTRIBUTE_UNUSED) { - return reload_completed ? BASE_POINTER_REGS : POINTER_REGS; + if (!avr_strict_X) + return reload_completed ? BASE_POINTER_REGS : POINTER_REGS; + + return PLUS == outer_code ? BASE_POINTER_REGS : POINTER_REGS; } @@ -7316,19 +7342,20 @@ avr_mode_code_base_reg_class (enum machine_mode mode ATTRIBUTE_UNUSED, bool avr_regno_mode_code_ok_for_base_p (int regno, enum machine_mode mode ATTRIBUTE_UNUSED, - RTX_CODE outer_code ATTRIBUTE_UNUSED, + RTX_CODE outer_code, RTX_CODE index_code ATTRIBUTE_UNUSED) { + bool ok = false; + if (regno < FIRST_PSEUDO_REGISTER && (regno == REG_X || regno == REG_Y || regno == REG_Z || regno == ARG_POINTER_REGNUM)) { - return true; + ok = true; } - - if (reg_renumber) + else if (reg_renumber) { regno = reg_renumber[regno]; @@ -7337,11 +7364,18 @@ avr_regno_mode_code_ok_for_base_p (int regno, || regno == REG_Z || regno == ARG_POINTER_REGNUM) { - return true; + ok = true; } } - - return false; + + if (avr_strict_X + && PLUS == outer_code + && regno == REG_X) + { + ok = false; + } + + return ok; } diff --git a/gcc/config/avr/avr.opt b/gcc/config/avr/avr.opt index 1128dd3..277b600 100644 --- a/gcc/config/avr/avr.opt +++ b/gcc/config/avr/avr.opt @@ -61,3 +61,7 @@ Relax branches mpmem-wrap-around Target Report Make the linker relaxation machine assume that a program counter wrap-around occurs. + +mstrict-X +Target Report Var(avr_strict_X) Init(0) +When accessing RAM, use X as imposed by the hardware, i.e. just use pre-decrement, post-increment and indirect addressing with the X register. Without this option, the compiler may assume that there is an addressing mode X+const similar to Y+const and Z+const and emit instructions to emulate such an addressing mode for X. diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index d374db4..2501a8e 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -487,7 +487,7 @@ Objective-C and Objective-C++ Dialects}. @emph{AVR Options} @gccoptlist{-mmcu=@var{mcu} -mno-interrupts @gol --mcall-prologues -mtiny-stack -mint8} +-mcall-prologues -mtiny-stack -mint8 -mstrict-X} @emph{Blackfin Options} @gccoptlist{-mcpu=@var{cpu}@r{[}-@var{sirevision}@r{]} @gol @@ -10689,6 +10689,23 @@ char will be 1 byte, an int will be 1 byte, a long will be 2 bytes and long long will be 4 bytes. Please note that this option does not comply to the C standards, but it will provide you with smaller code size. + +@item -mstrict-X +@opindex mstrict-X +Use register @code{X} in a way proposed by the hardware. This means +that @code{X} will only be used in indirect, post-increment or +pre-decrement addressing. + +Without this option, the @code{X} register may be used in the same way +as @code{Y} or @code{Z} which then is emulated by additional +instructions. +For example, loading a value with @code{X+const} addressing with a +small @code{const @leq{} 63} to a register @var{Rn} will be printed as +@example +adiw r26, const +ld @var{Rn}, X +sbiw r26, const +@end example @end table @node Blackfin Options |