aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog15
-rw-r--r--gcc/config/avr/avr.c146
-rw-r--r--gcc/config/avr/avr.opt4
-rw-r--r--gcc/doc/invoke.texi19
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