re PR target/46278 (avr-gcc 4.5.1 doing suboptimal reloads using X)

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.

From-SVN: r179993
This commit is contained in:
Georg-Johann Lay 2011-10-14 15:42:33 +00:00 committed by Georg-Johann Lay
parent 7d7a021160
commit e8ac5ac96a
4 changed files with 129 additions and 59 deletions

View File

@ -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

View File

@ -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))
switch (GET_CODE (x))
{
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)
{
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)
{
r = POINTER_Y_REGS;
}
}
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;
}
case REG:
ok = avr_reg_ok_for_addr_p (x, ADDR_SPACE_GENERIC,
MEM, strict);
if (strict
&& DImode == mode
&& REG_X == REGNO (x))
{
ok = false;
}
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;
}

View File

@ -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.

View File

@ -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