Hi,
After turning on FP -> SP elimination after Vlad fixed
an elimination issue in
https://gcc.gnu.org/git?p=gcc.git;a=commit;h=2971ff7b1d564ac04b537d907c70e6093af70832,
I'm now running into reload failure if arithmetic is done on SP.
For a call to a vararg functions, the avr target pushes args into the stack,
calls the function, and then adjusts the SP back to where it was before the
arg pushing occurred.
So for code like
extern int foo(int, ...);
int bar(void) {
long double l = 1.2345E6;
foo(0, l);
return 0;
}
and
$ avr-gcc -mmcu=avr51 -Os ../20031208-1.c
Reload sees
<snip>
(insn 5 2 6 2 (set (reg:QI 44)
(const_int 65 [0x41])) "../20031208-1.c":4:3 86 {movqi_insn_split}
(expr_list:REG_EQUIV (const_int 65 [0x41])
(nil)))
(insn 6 5 7 2 (set (mem:QI (post_dec:HI (reg/f:HI 32 __SP_L__)) [0 S1 A8])
(reg:QI 44)) "../20031208-1.c":4:3 1 {pushqi1}
(expr_list:REG_DEAD (reg:QI 44)
(expr_list:REG_ARGS_SIZE (const_int 1 [0x1])
(nil))))
...
<more arg pushes>
...
(call_insn 19 18 21 2 (parallel [
(set (reg:HI 24 r24)
(call (mem:HI (symbol_ref:HI ("foo") [flags 0x41]
<function_decl 0x7f430ca59700 foo>) [0 foo S2 A8])
(const_int 10 [0xa])))
(use (const_int 0 [0]))
]) "../20031208-1.c":4:3 776 {call_value_insn}
(expr_list:REG_UNUSED (reg:HI 24 r24)
(expr_list:REG_CALL_DECL (symbol_ref:HI ("foo") [flags 0x41]
<function_decl 0x7f430ca59700 foo>)
(nil)))
(nil))
(insn 21 19 25 2 (set (reg/f:HI 32 __SP_L__)
(plus:HI (reg/f:HI 32 __SP_L__)
(const_int 10 [0xa]))) "../20031208-1.c":5:10 discrim 1 165
{*addhi3_split}
(expr_list:REG_UNUSED (reg:QI 33 __SP_H__)
(expr_list:REG_ARGS_SIZE (const_int 0 [0])
(nil))))
LRA doesn't pick any of the 4 alternatives for insn 21
Considering alt=0 of insn 21: (0) =??r (1) %0 (2) r
Staticly defined alt reject+=12
Considering alt=1 of insn 21: (0) d (1) 0 (2) s
Considering alt=2 of insn 21: (0) !w (1) 0 (2) IJYIJ
Staticly defined alt reject+=600
Considering alt=3 of insn 21: (0) d (1) 0 (2) nYnn
Considering alt=0 of insn 21: (0) =??r (1) %0 (2) r
Staticly defined alt reject+=12
Considering alt=1 of insn 21: (0) d (1) 0 (2) s
Considering alt=2 of insn 21: (0) !w (1) 0 (2) IJYIJ
Staticly defined alt reject+=600
Considering alt=3 of insn 21: (0) d (1) 0 (2) nYnn
whereas classic reload does.
Reloads for insn # 21
Reload 0: reload_in (HI) = (reg/f:HI 32 __SP_L__)
reload_out (HI) = (reg/f:HI 32 __SP_L__)
LD_REGS, RELOAD_OTHER (opnum = 0)
reload_in_reg: (reg/f:HI 32 __SP_L__)
reload_out_reg: (reg/f:HI 32 __SP_L__)
reload_reg_rtx: (reg:HI 24 r24)
Digging through the code, I found lra-constraints.c:2687, which forbids
output reload of SP, with a comment that says
/* Never do output reload of stack pointer. It makes
impossible to do elimination when SP is changed in
RTL. */
Just to check if that is indeed the problem, I commented out the check
and goto fail; that follows that comment, and reload/code-gen worked fine.
Considering alt=0 of insn 21: (0) =??r (1) %0 (2) r
Staticly defined alt reject+=12
0 Non-pseudo reload: reject+=2
0 Small class reload: reject+=3
0 Non input pseudo reload: reject++
overall=24,losers=1 -- refuse
Considering alt=1 of insn 21: (0) d (1) 0 (2) s
0 Non-pseudo reload: reject+=2
0 Small class reload: reject+=3
0 Non input pseudo reload: reject++
1 Matching alt: reject+=2
1 Non-pseudo reload: reject+=2
1 Small class reload: reject+=3
1 Non input pseudo reload: reject++
overall=26,losers=2 -- refuse
Considering alt=2 of insn 21: (0) !w (1) 0 (2) IJYIJ
Staticly defined alt reject+=600
0 Non-pseudo reload: reject+=2
0 Non input pseudo reload: reject++
overall=609,losers=1 -- refuse
Considering alt=3 of insn 21: (0) d (1) 0 (2) nYnn
0 Non-pseudo reload: reject+=2
0 Small class reload: reject+=3
0 Non input pseudo reload: reject++
1 Matching alt: reject+=2
1 Non-pseudo reload: reject+=2
1 Small class reload: reject+=3
1 Non input pseudo reload: reject++
overall=26,losers=2 -- refuse
Choosing alt 3 in insn 21: (0) d (1) 0 (2) nYnn {*addhi3_split}
(sp_off=-10)
Creating newreg=50 from oldreg=32, assigning class LD_REGS to r50
21: r50:HI=r50:HI+0xa
REG_UNUSED __SP_H__:QI
REG_ARGS_SIZE 0
Inserting insn reload before:
29: r50:HI=__SP_L__:HI
Inserting insn reload after:
30: __SP_L__:HI=r50:HI
eventually generating
(insn 29 19 21 2 (set (reg/f:HI 24 r24 [50])
(reg/f:HI 32 __SP_L__)) "../20031208-1.c":5:10 discrim 1 101
{*movhi_split}
(nil))
(insn 21 29 30 2 (set (reg/f:HI 24 r24 [50])
(plus:HI (reg/f:HI 24 r24 [50])
(const_int 10 [0xa]))) "../20031208-1.c":5:10 discrim 1 165
{*addhi3_split}
(expr_list:REG_ARGS_SIZE (const_int 0 [0])
(nil)))
(insn 30 21 25 2 (set (reg/f:HI 32 __SP_L__)
(reg/f:HI 24 r24 [50])) "../20031208-1.c":5:10 discrim 1 101
{*movhi_split}
(nil))
just like classic reload did.
I guess the condition exists to ensure sp_off is always correct? Considering
LRA already
handles post_dec of SP just fine, perhaps it can allow RTX like
(set (reg/f:HI 32 __SP_L__)
(plus:HI (reg/f:HI 32 __SP_L__)
(const_int 10 [0xa]))) "../20031208-1.c":5:10 discrim 1 165
{*addhi3_split}
as long as the PLUS/MINUS is by a constant, and update sp_off accordingly?
Or is there something the avr target has to do differently?
Regards
Senthil