Only hard regs with pseudos considered for save/restore across calls?
Fred Fish
fnf@fred.ninemoons.com
Thu Jun 5 19:47:00 GMT 2003
I have run across what I think may be a serious restriction related to
saving and restoring hard registers across function calls.
It appears to me that only pseudos that are allocated to hard registers that
are clobbered across calls are saved and restored across calls, and hard
registers that are never associated with a pseudo are not saved and restored
even when the compiler knows they are clobbered across a call.
I've traced my way through the call tree
restore
setup_save_areas
assign_stack_local
save_caller_clobbered_regs
insert_save
insert_one_insn
insert_restore
and it appears that this restriction (only pseudos considered for
save/restore) is pretty hardcoded into the compiler.
If I'm wrong or simply missing something obvious, I'd sure appreciate a
nudge in the right direction.
In our port we have some hard registers that are essentially allocated when
the initial RTL is generated and thus never have pseudo registers associated
with them. As an example, consider:
mat0 = __ADD_M_M (mat0, mat1);
__CMPGT_M_M (cc0, mat0, mat1);
mat1 = foo (mat0, mat1);
mat0 = __SELECTH_M_M (cc0, mat0, mat1);
This source code uses three compiler builtins that each correspond to one
machine instruction, __ADD_M_M, __CMPGT_M_M, and __SELECTH_M_M. After the
CMP is a call to a normal C function, foo(). The mat0 and mat1 variables
are matrix_t types (V16SI) that ARE allocated to pseudos and then the
compiler later chooses one of the available 16 hard matrix registers
$m00-$m15. The cc0 variable is actually an integer value in the range of
0-3 that selects one of the hardware condition code registers $mcc0-$mcc3
respectively. Since all of $m00-$m15 and $mcc0-$mcc3 are call clobbered
registers (caller save), the hardware registers associated with mat0 and cc0
must be preserved across the call to foo(). The RTL from the cse2 pass is:
(insn 12 5 14 0 0x4029aa00 (parallel [
(set (reg/v:V16SI 206 [ mat0 ])
(unspec:V16SI [
(reg/v:V16SI 206 [ mat0 ])
(reg/v:V16SI 207 [ mat1 ])
] 63))
(set (reg:V16PSI 196 $mcc2)
(unspec:V16PSI [
(const_int 0 [0x0])
] 502))
(set (reg:V16PSI 197 $mcc3)
(unspec:V16PSI [
(const_int 0 [0x0])
] 502))
]) 375 {fm_addm} (nil)
(nil))
(insn 14 12 23 0 0x4029aa00 (set (reg:V16PSI 194 $mcc0)
(unspec:V16PSI [
(reg/v:V16SI 206 [ mat0 ])
(reg/v:V16SI 207 [ mat1 ])
] 159)) 450 {fm_cmpgtm_internal} (nil)
(nil))
(insn 23 14 25 0 0x4029aa00 (set (reg:V16SI 176 $m0 [ mat0 ])
(reg/v:V16SI 206 [ mat0 ])) 355 {movv16si_internal} (nil)
(nil))
(call_insn 25 23 26 0 0x4029aa00 (parallel [
(set (reg:V16SI 176 $m0)
(call (mem:SI (symbol_ref:SI ("foo") <function_decl 0x4029b15c foo>) [0 S4 A32])
(const_int 0 [0x0])))
(clobber (reg:SI 31 ra))
]) 324 {call_value_internal} (nil)
(nil)
(expr_list (use (reg:V16SI 177 $m1 [ mat1 ]))
(expr_list (use (reg:V16SI 176 $m0 [ mat0 ]))
(nil))))
(insn 26 25 29 0 0x4029aa00 (set (reg/v:V16SI 207 [ mat1 ])
(reg:V16SI 176 $m0)) 355 {movv16si_internal} (nil)
(nil))
(insn 29 26 37 0 0x4029aa00 (set (reg/v:V16SI 206 [ mat0 ])
(unspec:V16SI [
(reg:V16PSI 194 $mcc0)
(reg/v:V16SI 206 [ mat0 ])
(reg/v:V16SI 207 [ mat1 ])
] 231)) 504 {fm_selecthm_internal} (nil)
(nil))
Since mat0 is first allocated to a pseudo, and then later allocated to hard
register $m00, it is properly saved and restored across the call to foo().
However since cc0 gets directly allocated to $mcc0 at RTL generation time,
it never gets saved and restored. Even worse, since the compiler knows it
is clobbered across the call to foo(), it treats the setting of cc0 by the
__CMPGT_M_M builtin as a dead store and eliminates the instruction entirely
in the life analysis pass.
Thanks in advance for any advice.
-Fred
More information about the Gcc
mailing list