This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [Patch, AVR]: Fix PR46779
Denis Chertykov schrieb:
> 2011/6/13 Georg-Johann Lay <avr@gjlay.de>:
>> So you think is is pointless/discouraged to give a more realistic
>> description of AVR addressing be means of MODE_CODE_BASE_REG_CLASS (instead
>> of BASE_REG_CLASS) resp. REGNO_MODE_CODE_OK_FOR_BASE_P?
>>
>>> Look carefully at `out_movqi_r_mr'.
>>> There are even two fake addressing modes:
>>> 1. [Y + infinite-dslacement];
>>> 2. [X + (0...63)].
>> Yes, I know. The first is introduced by avr_legitimate_address_p and the
>> second appears to be artifact of LEGITIMIZE_RELOAD_ADDRESS.
>>
>> The changes are basically MODE_CODE_BASE_REG_CLASS (introduced in 4.2) and a
>> rewrite of avr_legitimate_address_p. The changes aim at a better addressing
>> for X and to minimize fake addresses.
>>
>>> I have spent a many hours (days, months) to debug GCC (especially avr port
>>> and reload) for right addressing modes.
>>> I have stopped on this code.
>>> AVR have a limited memory addressing and GCC can't handle it in native
>>> form.
>>> Because of that I have supported a fake adddressing modes.
>> I assume the code is from prior to 4.2 when REGNO_MODE_CODE_OK_FOR_BASE_P
>> and MODE_CODE_BASE_REG_CLASS had not been available so that supporting X
>> required some hacking.
>> All that would still be fine; however the new register allocator leads to
>> code that noone would accept. Accessing a structure through a pointer is not
>> uncommon, not even on AVR. So if Z is used for, say accessing flash, X
>> appears to be the best register.
>>
>> The shortcoming in GCC is that there is no way to give costs of addressing
>> (TARGET_ADDRESS_COST does different things).
>>
>> So take a look what avr-gcc compiles here:
>> http://gcc.gnu.org/bugzilla/attachment.cgi?id=22242
>> I saw similar complains in forums on the web.
>>
>>> (Richard Henderson have a different opinion: GCC can, AVR port can't)
>> What does he mean with that?
>>
>>> IMHO that three limited pointer registers is not enough for C compiler.
>>> Even more with frame pointer it's only two and X is a very limited.
>> The current implementation has several oddities like
>>
>> * allowing SUBREGs in avr-legitimate_address_p
>> * changing BASE_REG_CLASS on the fly (by means of reload_completed)
>>
>> isn't that supposed to cause trouble?
>
> You can try to remove all oddities and check results.
> Definitely something changed in GCC core since I wrote addressing code.
>
>
> Denis.
For your interest, here is a patch that shows the changes in
addressing mode.
Note that the
* LEGITIMIZE_RELOAD_ADDRESS is disabled. This is because I am
unsure about how it should look like. The special cases for X
are no more needed, and for Y and Z it might be good to have
intermediate addresses with, say offset =0 mod 60, so that
big offsets can be reached with addr + const, 0<= const < 60.
* patch already includes patch for pr46779 from
http://gcc.gnu.org/ml/gcc-patches/2011-06/msg00810.html
* As I said above, I removed orphan DI insns.
So if you have a look into reload, it might also be interesting what
it does with this changes.
Johann
--
* config/avr/avr.h (BASE_REG_CLASS): Remove.
(REG_OK_FOR_BASE_NOSTRICT_P): Remove.
(REG_OK_FOR_BASE_STRICT_P): Remove.
(LEGITIMIZE_RELOAD_ADDRESS): Remove.
(MODE_CODE_BASE_REG_CLASS): New Define.
(REGNO_MODE_CODE_OK_FOR_BASE_P): New Define.
* config/avr/avr.c: (avr_legitimate_address_p): Rewrite to allow
addresses that can actually be handled by hardware.
(avr_regno_mode_code_ok_for_base_p): New global Function.
(avr_mode_code_base_reg_class): New global Function.
(avr_hard_regno_mode_ok): Allow QI in all GPRs.
(avr_reg_ok_for_addr): New static function.
(avr_regno_reg_class): Change return type from enum reg_class to
reg_class_t.
(reg_class_tab): Set base type to reg_class_t. Return smallest
register class for each register.
* config/avr/avr.md: ("*sbrx_branch<mode>"): Disallow DI in mode.
("rotl<mode>3"): Ditto.
("*movqi"): Remove constraint 'Q'.
("*movsi"): Ditto.
("*movsf"): Ditto.
("*ashlqi3", "ashrqi3", "*lshrqi3"): Ditto.
("ashlhi3", "ashrhi3", "lshrhi3"): Ditto.
("ashlsi3", "ashrsi3", "lshrsi3"): Ditto.
("*movhi_sp"): Remove insn.
("zero_extendqidi2"): Remove insn_and_split.
("zero_extendhidi2"): Remove insn_and_split.
("zero_extendsidi2"): Remove insn_and_split.
* config/avr/avr-protos.h
(secondary_input_reload_class): Remove prototype.
(avr_mode_code_base_reg_class): New prototype.
(avr_regno_mode_code_ok_for_base_p): New prototype.
(avr_legitimize_reload_address): New prototype.
Index: config/avr/avr-protos.h
===================================================================
--- config/avr/avr-protos.h (Revision 175011)
+++ config/avr/avr-protos.h (Arbeitskopie)
@@ -24,7 +24,7 @@
extern int function_arg_regno_p (int r);
extern void avr_cpu_cpp_builtins (struct cpp_reader * pfile);
-extern enum reg_class avr_regno_reg_class (int r);
+extern reg_class_t avr_regno_reg_class (unsigned int r);
extern void asm_globalize_label (FILE *file, const char *name);
extern void avr_asm_declare_function_name (FILE *, const char *, tree);
extern void order_regs_for_local_alloc (void);
@@ -88,9 +88,6 @@ extern int extra_constraint_Q (rtx x);
extern int adjust_insn_length (rtx insn, int len);
extern const char *output_reload_inhi (rtx insn, rtx *operands, int *len);
extern const char *output_reload_insisf (rtx insn, rtx *operands, int *len);
-extern enum reg_class secondary_input_reload_class (enum reg_class,
- enum machine_mode,
- rtx);
extern void notice_update_cc (rtx body, rtx insn);
extern void print_operand (FILE *file, rtx x, int code);
extern void print_operand_address (FILE *file, rtx addr);
@@ -109,6 +106,8 @@ extern RTX_CODE avr_normalize_condition
extern int compare_eq_p (rtx insn);
extern void out_shift_with_cnt (const char *templ, rtx insn,
rtx operands[], int *len, int t_len);
+extern reg_class_t avr_mode_code_base_reg_class (enum machine_mode, RTX_CODE, RTX_CODE);
+extern bool avr_regno_mode_code_ok_for_base_p (int, enum machine_mode, RTX_CODE, RTX_CODE);
extern rtx avr_incoming_return_addr_rtx (void);
#endif /* RTX_CODE */
Index: config/avr/avr.md
===================================================================
--- config/avr/avr.md (Revision 175011)
+++ config/avr/avr.md (Arbeitskopie)
@@ -246,8 +246,8 @@ (define_expand "movqi"
")
(define_insn "*movqi"
- [(set (match_operand:QI 0 "nonimmediate_operand" "=r,d,Qm,r,q,r,*r")
- (match_operand:QI 1 "general_operand" "rL,i,rL,Qm,r,q,i"))]
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=r,d,m,r,q,r,*r")
+ (match_operand:QI 1 "general_operand" "rL,i,rL,m,r,q,i"))]
"(register_operand (operands[0],QImode)
|| register_operand (operands[1], QImode) || const0_rtx == operands[1])"
"* return output_movqi (insn, operands, NULL);"
@@ -295,15 +295,6 @@ (define_expand "movhi"
}
}")
-(define_insn "*movhi_sp"
- [(set (match_operand:HI 0 "register_operand" "=q,r")
- (match_operand:HI 1 "register_operand" "r,q"))]
- "((stack_register_operand(operands[0], HImode) && register_operand (operands[1], HImode))
- || (register_operand (operands[0], HImode) && stack_register_operand(operands[1], HImode)))"
- "* return output_movhi (insn, operands, NULL);"
- [(set_attr "length" "5,2")
- (set_attr "cc" "none,none")])
-
(define_insn "movhi_sp_r_irq_off"
[(set (match_operand:HI 0 "stack_register_operand" "=q")
(unspec_volatile:HI [(match_operand:HI 1 "register_operand" "r")]
@@ -425,8 +416,8 @@ (define_insn "*reload_insi"
(define_insn "*movsi"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,Qm,!d,r")
- (match_operand:SI 1 "general_operand" "r,L,Qm,rL,i,i"))]
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,m,!d,r")
+ (match_operand:SI 1 "general_operand" "r,L,m,rL,i,i"))]
"(register_operand (operands[0],SImode)
|| register_operand (operands[1],SImode) || const0_rtx == operands[1])"
"* return output_movsisf (insn, operands, NULL);"
@@ -451,8 +442,8 @@ (define_expand "movsf"
}")
(define_insn "*movsf"
- [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,r,Qm,!d,r")
- (match_operand:SF 1 "general_operand" "r,G,Qm,r,F,F"))]
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,r,m,!d,r")
+ (match_operand:SF 1 "general_operand" "r,G,m,r,F,F"))]
"register_operand (operands[0], SFmode)
|| register_operand (operands[1], SFmode)"
"* return output_movsisf (insn, operands, NULL);"
@@ -1518,8 +1509,8 @@ (define_mode_attr rotx [(DI "&r,&r,X") (
(define_mode_attr rotsmode [(DI "QI") (SI "HI") (HI "QI")])
(define_expand "rotl<mode>3"
- [(parallel [(set (match_operand:HIDI 0 "register_operand" "")
- (rotate:HIDI (match_operand:HIDI 1 "register_operand" "")
+ [(parallel [(set (match_operand:HISI 0 "register_operand" "")
+ (rotate:HISI (match_operand:HISI 1 "register_operand" "")
(match_operand:VOID 2 "const_int_operand" "")))
(clobber (match_dup 3))])]
""
@@ -1618,7 +1609,7 @@ (define_split ; ashlqi3_const6
(define_insn "*ashlqi3"
[(set (match_operand:QI 0 "register_operand" "=r,r,r,r,!d,r,r")
(ashift:QI (match_operand:QI 1 "register_operand" "0,0,0,0,0,0,0")
- (match_operand:QI 2 "general_operand" "r,L,P,K,n,n,Qm")))]
+ (match_operand:QI 2 "general_operand" "r,L,P,K,n,n,m")))]
""
"* return ashlqi3_out (insn, operands, NULL);"
[(set_attr "length" "5,0,1,2,4,6,9")
@@ -1627,7 +1618,7 @@ (define_insn "*ashlqi3"
(define_insn "ashlhi3"
[(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r,r")
(ashift:HI (match_operand:HI 1 "register_operand" "0,0,0,r,0,0,0")
- (match_operand:QI 2 "general_operand" "r,L,P,O,K,n,Qm")))]
+ (match_operand:QI 2 "general_operand" "r,L,P,O,K,n,m")))]
""
"* return ashlhi3_out (insn, operands, NULL);"
[(set_attr "length" "6,0,2,2,4,10,10")
@@ -1636,7 +1627,7 @@ (define_insn "ashlhi3"
(define_insn "ashlsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r")
(ashift:SI (match_operand:SI 1 "register_operand" "0,0,0,r,0,0,0")
- (match_operand:QI 2 "general_operand" "r,L,P,O,K,n,Qm")))]
+ (match_operand:QI 2 "general_operand" "r,L,P,O,K,n,m")))]
""
"* return ashlsi3_out (insn, operands, NULL);"
[(set_attr "length" "8,0,4,4,8,10,12")
@@ -1725,7 +1716,7 @@ (define_insn "*ashlsi3_const"
(define_insn "ashrqi3"
[(set (match_operand:QI 0 "register_operand" "=r,r,r,r,r,r")
(ashiftrt:QI (match_operand:QI 1 "register_operand" "0,0,0,0,0,0")
- (match_operand:QI 2 "general_operand" "r,L,P,K,n,Qm")))]
+ (match_operand:QI 2 "general_operand" "r,L,P,K,n,m")))]
""
"* return ashrqi3_out (insn, operands, NULL);"
[(set_attr "length" "5,0,1,2,5,9")
@@ -1734,7 +1725,7 @@ (define_insn "ashrqi3"
(define_insn "ashrhi3"
[(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r,r")
(ashiftrt:HI (match_operand:HI 1 "register_operand" "0,0,0,r,0,0,0")
- (match_operand:QI 2 "general_operand" "r,L,P,O,K,n,Qm")))]
+ (match_operand:QI 2 "general_operand" "r,L,P,O,K,n,m")))]
""
"* return ashrhi3_out (insn, operands, NULL);"
[(set_attr "length" "6,0,2,4,4,10,10")
@@ -1743,7 +1734,7 @@ (define_insn "ashrhi3"
(define_insn "ashrsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r")
(ashiftrt:SI (match_operand:SI 1 "register_operand" "0,0,0,r,0,0,0")
- (match_operand:QI 2 "general_operand" "r,L,P,O,K,n,Qm")))]
+ (match_operand:QI 2 "general_operand" "r,L,P,O,K,n,m")))]
""
"* return ashrsi3_out (insn, operands, NULL);"
[(set_attr "length" "8,0,4,6,8,10,12")
@@ -1833,7 +1824,7 @@ (define_split ; lshrqi3_const6
(define_insn "*lshrqi3"
[(set (match_operand:QI 0 "register_operand" "=r,r,r,r,!d,r,r")
(lshiftrt:QI (match_operand:QI 1 "register_operand" "0,0,0,0,0,0,0")
- (match_operand:QI 2 "general_operand" "r,L,P,K,n,n,Qm")))]
+ (match_operand:QI 2 "general_operand" "r,L,P,K,n,n,m")))]
""
"* return lshrqi3_out (insn, operands, NULL);"
[(set_attr "length" "5,0,1,2,4,6,9")
@@ -1842,7 +1833,7 @@ (define_insn "*lshrqi3"
(define_insn "lshrhi3"
[(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r,r,r")
(lshiftrt:HI (match_operand:HI 1 "register_operand" "0,0,0,r,0,0,0")
- (match_operand:QI 2 "general_operand" "r,L,P,O,K,n,Qm")))]
+ (match_operand:QI 2 "general_operand" "r,L,P,O,K,n,m")))]
""
"* return lshrhi3_out (insn, operands, NULL);"
[(set_attr "length" "6,0,2,2,4,10,10")
@@ -1851,7 +1842,7 @@ (define_insn "lshrhi3"
(define_insn "lshrsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r")
(lshiftrt:SI (match_operand:SI 1 "register_operand" "0,0,0,r,0,0,0")
- (match_operand:QI 2 "general_operand" "r,L,P,O,K,n,Qm")))]
+ (match_operand:QI 2 "general_operand" "r,L,P,O,K,n,m")))]
""
"* return lshrsi3_out (insn, operands, NULL);"
[(set_attr "length" "8,0,4,4,8,10,12")
@@ -2124,54 +2115,6 @@ (define_insn_and_split "zero_extendhisi2
operands[3] = simplify_gen_subreg (HImode, operands[0], SImode, high_off);
})
-(define_insn_and_split "zero_extendqidi2"
- [(set (match_operand:DI 0 "register_operand" "=r")
- (zero_extend:DI (match_operand:QI 1 "register_operand" "r")))]
- ""
- "#"
- "reload_completed"
- [(set (match_dup 2) (zero_extend:SI (match_dup 1)))
- (set (match_dup 3) (const_int 0))]
-{
- unsigned int low_off = subreg_lowpart_offset (SImode, DImode);
- unsigned int high_off = subreg_highpart_offset (SImode, DImode);
-
- operands[2] = simplify_gen_subreg (SImode, operands[0], DImode, low_off);
- operands[3] = simplify_gen_subreg (SImode, operands[0], DImode, high_off);
-})
-
-(define_insn_and_split "zero_extendhidi2"
- [(set (match_operand:DI 0 "register_operand" "=r")
- (zero_extend:DI (match_operand:HI 1 "register_operand" "r")))]
- ""
- "#"
- "reload_completed"
- [(set (match_dup 2) (zero_extend:SI (match_dup 1)))
- (set (match_dup 3) (const_int 0))]
-{
- unsigned int low_off = subreg_lowpart_offset (SImode, DImode);
- unsigned int high_off = subreg_highpart_offset (SImode, DImode);
-
- operands[2] = simplify_gen_subreg (SImode, operands[0], DImode, low_off);
- operands[3] = simplify_gen_subreg (SImode, operands[0], DImode, high_off);
-})
-
-(define_insn_and_split "zero_extendsidi2"
- [(set (match_operand:DI 0 "register_operand" "=r")
- (zero_extend:DI (match_operand:SI 1 "register_operand" "r")))]
- ""
- "#"
- "reload_completed"
- [(set (match_dup 2) (match_dup 1))
- (set (match_dup 3) (const_int 0))]
-{
- unsigned int low_off = subreg_lowpart_offset (SImode, DImode);
- unsigned int high_off = subreg_highpart_offset (SImode, DImode);
-
- operands[2] = simplify_gen_subreg (SImode, operands[0], DImode, low_off);
- operands[3] = simplify_gen_subreg (SImode, operands[0], DImode, high_off);
-})
-
;;<=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=>
;; compare
@@ -2430,7 +2373,7 @@ (define_insn "*sbrx_branch<mode>"
[(set (pc)
(if_then_else
(match_operator 0 "eqne_operator"
- [(zero_extract:QIDI
+ [(zero_extract:QISI
(match_operand:VOID 1 "register_operand" "r")
(const_int 1)
(match_operand 2 "const_int_operand" "n"))
Index: config/avr/avr.c
===================================================================
--- config/avr/avr.c (Revision 175011)
+++ config/avr/avr.c (Arbeitskopie)
@@ -343,18 +343,27 @@ avr_help (void)
/* return register class from register number. */
-static const enum reg_class 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 */
+static const reg_class_t reg_class_tab[] =
+ {
+ /* r0 */
+ R0_REG,
+ /* r1 - r15 */
+ NO_LD_REGS, NO_LD_REGS, NO_LD_REGS, NO_LD_REGS, NO_LD_REGS,
+ NO_LD_REGS, NO_LD_REGS, NO_LD_REGS, NO_LD_REGS, NO_LD_REGS,
+ NO_LD_REGS, NO_LD_REGS, NO_LD_REGS, NO_LD_REGS, NO_LD_REGS,
+ /* r16 - r23 */
+ SIMPLE_LD_REGS, SIMPLE_LD_REGS, SIMPLE_LD_REGS, SIMPLE_LD_REGS,
+ SIMPLE_LD_REGS, SIMPLE_LD_REGS, SIMPLE_LD_REGS, SIMPLE_LD_REGS,
+ /* r24, r25 */
+ ADDW_REGS, ADDW_REGS,
+ /* r26, r27 */
+ POINTER_X_REGS, POINTER_X_REGS,
+ /* r28, r29 */
+ POINTER_Y_REGS, POINTER_Y_REGS,
+ /* r30, r31 */
+ POINTER_Z_REGS, POINTER_Z_REGS,
+ /* SPL, SPH */
+ STACK_REG, STACK_REG
};
/* Function to set up the backend function structure. */
@@ -367,8 +376,8 @@ avr_init_machine_status (void)
/* Return register class for register R. */
-enum reg_class
-avr_regno_reg_class (int r)
+reg_class_t
+avr_regno_reg_class (unsigned int r)
{
if (r <= 33)
return reg_class_tab[r];
@@ -1146,74 +1155,75 @@ avr_cannot_modify_jumps_p (void)
}
-/* Return nonzero if X (an RTX) is a legitimate memory address on the target
- machine for a memory operand of mode MODE. */
+/* Helper function for `avr_legitimate_address_p'. */
+
+static inline int
+avr_reg_ok_for_addr (rtx reg, int strict)
+{
+ return (REG_P (reg)
+ && (avr_regno_mode_code_ok_for_base_p (REGNO (reg), QImode, MEM, SCRATCH)
+ || (!strict && REGNO (reg) >= FIRST_PSEUDO_REGISTER)));
+}
+
+
+/* Implement `TARGET_LEGITIMATE_ADDRESS_P'. */
bool
avr_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
{
- enum reg_class r = NO_REGS;
-
- if (TARGET_ALL_DEBUG)
- {
- fprintf (stderr, "mode: (%s) %s %s %s %s:",
- GET_MODE_NAME(mode),
- strict ? "(strict)": "",
- reload_completed ? "(reload_completed)": "",
- reload_in_progress ? "(reload_in_progress)": "",
- reg_renumber ? "(reg_renumber)" : "");
- if (GET_CODE (x) == PLUS
- && REG_P (XEXP (x, 0))
- && GET_CODE (XEXP (x, 1)) == CONST_INT
- && INTVAL (XEXP (x, 1)) >= 0
- && INTVAL (XEXP (x, 1)) <= MAX_LD_OFFSET (mode)
- && reg_renumber
- )
- fprintf (stderr, "(r%d ---> r%d)", REGNO (XEXP (x, 0)),
- true_regnum (XEXP (x, 0)));
- debug_rtx (x);
- }
- if (!strict && GET_CODE (x) == SUBREG)
- x = SUBREG_REG (x);
- if (REG_P (x) && (strict ? REG_OK_FOR_BASE_STRICT_P (x)
- : REG_OK_FOR_BASE_NOSTRICT_P (x)))
- r = POINTER_REGS;
- else if (CONSTANT_ADDRESS_P (x))
- r = ALL_REGS;
- else if (GET_CODE (x) == PLUS
- && REG_P (XEXP (x, 0))
- && GET_CODE (XEXP (x, 1)) == CONST_INT
- && INTVAL (XEXP (x, 1)) >= 0)
- {
- int fit = INTVAL (XEXP (x, 1)) <= MAX_LD_OFFSET (mode);
- if (fit)
- {
- if (! strict
- || REGNO (XEXP (x,0)) == REG_X
- || REGNO (XEXP (x,0)) == REG_Y
- || REGNO (XEXP (x,0)) == REG_Z)
- r = BASE_POINTER_REGS;
- if (XEXP (x,0) == frame_pointer_rtx
- || XEXP (x,0) == arg_pointer_rtx)
- r = BASE_POINTER_REGS;
- }
- else if (frame_pointer_needed && XEXP (x,0) == frame_pointer_rtx)
- r = POINTER_Y_REGS;
- }
- else if ((GET_CODE (x) == PRE_DEC || GET_CODE (x) == POST_INC)
- && REG_P (XEXP (x, 0))
- && (strict ? REG_OK_FOR_BASE_STRICT_P (XEXP (x, 0))
- : REG_OK_FOR_BASE_NOSTRICT_P (XEXP (x, 0))))
- {
- r = POINTER_REGS;
- }
- if (TARGET_ALL_DEBUG)
+ bool ok = false;
+
+ switch (GET_CODE (x))
{
- fprintf (stderr, " ret = %c\n", r + '0');
+ case REG:
+ ok = avr_reg_ok_for_addr (x, strict);
+ if (strict
+ && DImode == mode
+ && REG_X == REGNO (x))
+ {
+ ok = false;
+ }
+ break;
+
+ case POST_INC:
+ case PRE_DEC:
+ ok = avr_reg_ok_for_addr (XEXP (x, 0), strict);
+ break;
+
+ case SYMBOL_REF:
+ case CONST_INT:
+ case CONST:
+ ok = true;
+ break;
+
+ case PLUS:
+ {
+ rtx op0 = XEXP (x, 0);
+ rtx op1 = XEXP (x, 1);
+
+ if (REG_P (op0)
+ && CONST_INT_P (op1))
+ {
+ ok = (avr_reg_ok_for_addr (op0, strict)
+ && INTVAL (op1) >= 0
+ && INTVAL (op1) <= MAX_LD_OFFSET (mode));
+
+ if (strict
+ && REG_X == REGNO (op0))
+ {
+ ok = false;
+ }
+ }
+ break;
+ }
+
+ default:
+ break;
}
- return r == NO_REGS ? 0 : (int)r;
-}
+ return ok;
+}
+
/* Attempts to replace X with a valid
memory address for an operand of mode MODE */
@@ -6278,27 +6288,74 @@ jump_over_one_insn_p (rtx insn, rtx dest
int
avr_hard_regno_mode_ok (int regno, enum machine_mode mode)
{
- /* Disallow QImode in stack pointer regs. */
- if ((regno == REG_SP || regno == (REG_SP + 1)) && mode == QImode)
- return 0;
+ /* Any GENERAL_REGS register can hold 8-bit values. */
+ /* FIXME: 8-bit values must not be disallowed for R28 or R29.
+ Disallowing QI et al. in these registers might lead to code like
+ (set (subreg:QI (reg:HI 28) n) ...)
+ which will result in wrong code because reload does not handle
+ SUBREGs of hard regsisters like this. This could be fixed in reload.
+ However, it appears that fixing reload is not wanted by reload people. */
+
+ if (GET_MODE_SIZE (mode) == 1)
+ return 1;
+
+ /* All modes larger than 8 bits should start in an even register. */
+
+ return regno % 2 == 0;
+}
- /* The only thing that can go into registers r28:r29 is a Pmode. */
- if (regno == REG_Y && mode == Pmode)
- return 1;
- /* Otherwise disallow all regno/mode combinations that span r28:r29. */
- if (regno <= (REG_Y + 1) && (regno + GET_MODE_SIZE (mode)) >= (REG_Y + 1))
- return 0;
+/* Worker function for `MODE_CODE_BASE_REG_CLASS'. */
- if (mode == QImode)
- return 1;
+reg_class_t
+avr_mode_code_base_reg_class (enum machine_mode mode ATTRIBUTE_UNUSED,
+ RTX_CODE outer_code, RTX_CODE index_code ATTRIBUTE_UNUSED)
+{
+ reg_class_t rclass = BASE_POINTER_REGS;
+
+ switch (outer_code)
+ {
+ case MEM:
+ case POST_INC:
+ case PRE_DEC:
+ rclass = POINTER_REGS;
+ break;
+
+ default:
+ break;
+ }
+
+ return rclass;
+}
- /* Modes larger than QImode occupy consecutive registers. */
- if (regno + GET_MODE_SIZE (mode) > FIRST_PSEUDO_REGISTER)
- return 0;
- /* All modes larger than QImode should start in an even register. */
- return !(regno & 1);
+/* Worker function for `REGNO_MODE_CODE_OK_FOR_BASE_P'. */
+
+bool
+avr_regno_mode_code_ok_for_base_p (int regno, enum machine_mode mode ATTRIBUTE_UNUSED,
+ RTX_CODE outer_code, RTX_CODE index_code ATTRIBUTE_UNUSED)
+{
+ bool ok;
+
+ switch (outer_code)
+ {
+ case PLUS:
+ ok = regno == REG_Z || regno == REG_Y;
+ break;
+
+ case MEM: /* plain reg */
+ case POST_INC:
+ case PRE_DEC:
+ ok = regno == REG_Z || regno == REG_Y || regno == REG_X;
+ break;
+
+ default:
+ ok = false;
+ break;
+
+ }
+
+ return ok;
}
const char *
@@ -6424,13 +6481,23 @@ avr_hard_regno_scratch_ok (unsigned int
&& !df_regs_ever_live_p (regno))
return false;
+ /* Don't allow hard registers that might be part of the frame pointer.
+ Some places in the compiler just test for [HARD_]FRAME_POINTER_REGNUM
+ and don't care for a frame pointer that spans more than one register. */
+
+ if ((!reload_completed || frame_pointer_needed)
+ && (regno == REG_Y || regno == REG_Y + 1))
+ {
+ return false;
+ }
+
return true;
}
/* Return nonzero if register OLD_REG can be renamed to register NEW_REG. */
int
-avr_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED,
+avr_hard_regno_rename_ok (unsigned int old_reg,
unsigned int new_reg)
{
/* Interrupt functions can only use registers that have already been
@@ -6441,6 +6508,17 @@ avr_hard_regno_rename_ok (unsigned int o
&& !df_regs_ever_live_p (new_reg))
return 0;
+ /* Don't allow hard registers that might be part of the frame pointer.
+ Some places in the compiler just test for [HARD_]FRAME_POINTER_REGNUM
+ and don't care for a frame pointer that spans more than one register. */
+
+ if ((!reload_completed || frame_pointer_needed)
+ && (old_reg == REG_Y || old_reg == REG_Y + 1
+ || new_reg == REG_Y || new_reg == REG_Y + 1))
+ {
+ return 0;
+ }
+
return 1;
}
Index: config/avr/avr.h
===================================================================
--- config/avr/avr.h (Revision 175011)
+++ config/avr/avr.h (Arbeitskopie)
@@ -294,21 +294,13 @@ enum reg_class {
#define REGNO_REG_CLASS(R) avr_regno_reg_class(R)
-#define BASE_REG_CLASS (reload_completed ? BASE_POINTER_REGS : POINTER_REGS)
+#define MODE_CODE_BASE_REG_CLASS(mode, outer_code, index_code) \
+ avr_mode_code_base_reg_class (mode, outer_code, index_code)
#define INDEX_REG_CLASS NO_REGS
-#define REGNO_OK_FOR_BASE_P(r) (((r) < FIRST_PSEUDO_REGISTER \
- && ((r) == REG_X \
- || (r) == REG_Y \
- || (r) == REG_Z \
- || (r) == ARG_POINTER_REGNUM)) \
- || (reg_renumber \
- && (reg_renumber[r] == REG_X \
- || reg_renumber[r] == REG_Y \
- || reg_renumber[r] == REG_Z \
- || (reg_renumber[r] \
- == ARG_POINTER_REGNUM))))
+#define REGNO_MODE_CODE_OK_FOR_BASE_P(num, mode, outer_code, index_code) \
+ avr_regno_mode_code_ok_for_base_p (num, mode, outer_code, index_code)
#define REGNO_OK_FOR_INDEX_P(NUM) 0
@@ -371,16 +363,11 @@ extern int avr_reg_order[];
#define MAX_REGS_PER_ADDRESS 1
-#define REG_OK_FOR_BASE_NOSTRICT_P(X) \
- (REGNO (X) >= FIRST_PSEUDO_REGISTER || REG_OK_FOR_BASE_STRICT_P(X))
-
-#define REG_OK_FOR_BASE_STRICT_P(X) REGNO_OK_FOR_BASE_P (REGNO (X))
-
/* LEGITIMIZE_RELOAD_ADDRESS will allow register R26/27 to be used, where it
is no worse than normal base pointers R28/29 and R30/31. For example:
If base offset is greater than 63 bytes or for R++ or --R addressing. */
-#define LEGITIMIZE_RELOAD_ADDRESS(X, MODE, OPNUM, TYPE, IND_LEVELS, WIN) \
+#define _LEGITIMIZE_RELOAD_ADDRESS(X, MODE, OPNUM, TYPE, IND_LEVELS, WIN) \
do { \
if (1&&(GET_CODE (X) == POST_INC || GET_CODE (X) == PRE_DEC)) \
{ \