re PR target/41246 (should "sorry" when regparm=3 and nested functions are encountered)
PR target/41246 * target.h (struct gcc_target): Add asm_out.trampoline_template, calls.static_chain, calls.trampoline_init, calls.trampoline_adjust_address. * target-def.h (TARGET_ASM_TRAMPOLINE_TEMPLATE): New. (TARGET_STATIC_CHAIN, TARGET_TRAMPOLINE_INIT): New. (TARGET_TRAMPOLINE_ADJUST_ADDRESS): New. * builtins.c (expand_builtin_setjmp_receiver): Use targetm.calls.static_chain; only clobber registers. (expand_builtin_init_trampoline): Use targetm.calls.trampoline_init; set up memory attributes properly for the trampoline block. (expand_builtin_adjust_trampoline): Use targetm.calls.trampoline_adjust_address. * calls.c (prepare_call_address): Add fndecl argument. Use targetm.calls.static_chain. * df-scan.c (df_need_static_chain_reg): Remove. (df_get_entry_block_def_set): Use targetm.calls.static_chain; consolodate static chain handling. * doc/tm.texi: Document new hooks. * emit-rtl.c (static_chain_rtx, static_chain_incoming_rtx): Remove. (init_emit_regs): Don't initialize them. * expr.h (prepare_call_address): Update decl. * final.c (profile_function): Use targetm.calls.static_chain. * function.c (expand_function_start): Likewise. * rtl.h (static_chain_rtx, static_chain_incoming_rtx): Remove. * stmt.c (expand_nl_goto_receiver): Use targetm.calls.static_chain; only clobber registers. * targhooks.c (default_static_chain): New. (default_asm_trampoline_template, default_trampoline_init): New. (default_trampoline_adjust_address): New. * targhooks.h: Declare them. * varasm.c (assemble_trampoline_template): Use targetm.asm_out.trampoline_template. Make the memory block const and set its size. From-SVN: r151983
This commit is contained in:
parent
2df373c2eb
commit
531ca746f9
|
@ -1,3 +1,40 @@
|
|||
2009-09-22 Richard Henderson <rth@redhat.com>
|
||||
|
||||
PR target/41246
|
||||
* target.h (struct gcc_target): Add asm_out.trampoline_template,
|
||||
calls.static_chain, calls.trampoline_init,
|
||||
calls.trampoline_adjust_address.
|
||||
* target-def.h (TARGET_ASM_TRAMPOLINE_TEMPLATE): New.
|
||||
(TARGET_STATIC_CHAIN, TARGET_TRAMPOLINE_INIT): New.
|
||||
(TARGET_TRAMPOLINE_ADJUST_ADDRESS): New.
|
||||
* builtins.c (expand_builtin_setjmp_receiver): Use
|
||||
targetm.calls.static_chain; only clobber registers.
|
||||
(expand_builtin_init_trampoline): Use targetm.calls.trampoline_init;
|
||||
set up memory attributes properly for the trampoline block.
|
||||
(expand_builtin_adjust_trampoline): Use
|
||||
targetm.calls.trampoline_adjust_address.
|
||||
* calls.c (prepare_call_address): Add fndecl argument. Use
|
||||
targetm.calls.static_chain.
|
||||
* df-scan.c (df_need_static_chain_reg): Remove.
|
||||
(df_get_entry_block_def_set): Use targetm.calls.static_chain;
|
||||
consolodate static chain handling.
|
||||
* doc/tm.texi: Document new hooks.
|
||||
* emit-rtl.c (static_chain_rtx, static_chain_incoming_rtx): Remove.
|
||||
(init_emit_regs): Don't initialize them.
|
||||
* expr.h (prepare_call_address): Update decl.
|
||||
* final.c (profile_function): Use targetm.calls.static_chain.
|
||||
* function.c (expand_function_start): Likewise.
|
||||
* rtl.h (static_chain_rtx, static_chain_incoming_rtx): Remove.
|
||||
* stmt.c (expand_nl_goto_receiver): Use targetm.calls.static_chain;
|
||||
only clobber registers.
|
||||
* targhooks.c (default_static_chain): New.
|
||||
(default_asm_trampoline_template, default_trampoline_init): New.
|
||||
(default_trampoline_adjust_address): New.
|
||||
* targhooks.h: Declare them.
|
||||
* varasm.c (assemble_trampoline_template): Use
|
||||
targetm.asm_out.trampoline_template. Make the memory block const
|
||||
and set its size.
|
||||
|
||||
2009-09-22 Richard Guenther <rguenther@suse.de>
|
||||
|
||||
PR middle-end/41395
|
||||
|
|
|
@ -755,13 +755,17 @@ expand_builtin_setjmp_setup (rtx buf_addr, rtx receiver_label)
|
|||
void
|
||||
expand_builtin_setjmp_receiver (rtx receiver_label ATTRIBUTE_UNUSED)
|
||||
{
|
||||
rtx chain;
|
||||
|
||||
/* Clobber the FP when we get here, so we have to make sure it's
|
||||
marked as used by this function. */
|
||||
emit_use (hard_frame_pointer_rtx);
|
||||
|
||||
/* Mark the static chain as clobbered here so life information
|
||||
doesn't get messed up for it. */
|
||||
emit_clobber (static_chain_rtx);
|
||||
chain = targetm.calls.static_chain (current_function_decl, true);
|
||||
if (chain && REG_P (chain))
|
||||
emit_clobber (chain);
|
||||
|
||||
/* Now put in the code to restore the frame pointer, and argument
|
||||
pointer, if needed. */
|
||||
|
@ -839,11 +843,8 @@ expand_builtin_longjmp (rtx buf_addr, rtx value)
|
|||
|
||||
buf_addr = force_reg (Pmode, buf_addr);
|
||||
|
||||
/* We used to store value in static_chain_rtx, but that fails if pointers
|
||||
are smaller than integers. We instead require that the user must pass
|
||||
a second argument of 1, because that is what builtin_setjmp will
|
||||
return. This also makes EH slightly more efficient, since we are no
|
||||
longer copying around a value that we don't care about. */
|
||||
/* We require that the user must pass a second argument of 1, because
|
||||
that is what builtin_setjmp will return. */
|
||||
gcc_assert (value == const1_rtx);
|
||||
|
||||
last = get_last_insn ();
|
||||
|
@ -1590,7 +1591,7 @@ expand_builtin_apply (rtx function, rtx arguments, rtx argsize)
|
|||
}
|
||||
|
||||
/* All arguments and registers used for the call are set up by now! */
|
||||
function = prepare_call_address (function, NULL, &call_fusage, 0, 0);
|
||||
function = prepare_call_address (NULL, function, NULL, &call_fusage, 0, 0);
|
||||
|
||||
/* Ensure address is valid. SYMBOL_REF is already valid, so no need,
|
||||
and we don't want to load it into a register as an optimization,
|
||||
|
@ -5815,10 +5816,7 @@ static rtx
|
|||
expand_builtin_init_trampoline (tree exp)
|
||||
{
|
||||
tree t_tramp, t_func, t_chain;
|
||||
rtx r_tramp, r_func, r_chain;
|
||||
#ifdef TRAMPOLINE_TEMPLATE
|
||||
rtx blktramp;
|
||||
#endif
|
||||
rtx m_tramp, r_tramp, r_chain, tmp;
|
||||
|
||||
if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE,
|
||||
POINTER_TYPE, VOID_TYPE))
|
||||
|
@ -5829,20 +5827,36 @@ expand_builtin_init_trampoline (tree exp)
|
|||
t_chain = CALL_EXPR_ARG (exp, 2);
|
||||
|
||||
r_tramp = expand_normal (t_tramp);
|
||||
r_func = expand_normal (t_func);
|
||||
m_tramp = gen_rtx_MEM (BLKmode, r_tramp);
|
||||
MEM_NOTRAP_P (m_tramp) = 1;
|
||||
|
||||
/* The TRAMP argument should be the address of a field within the
|
||||
local function's FRAME decl. Let's see if we can fill in the
|
||||
to fill in the MEM_ATTRs for this memory. */
|
||||
if (TREE_CODE (t_tramp) == ADDR_EXPR)
|
||||
set_mem_attributes_minus_bitpos (m_tramp, TREE_OPERAND (t_tramp, 0),
|
||||
true, 0);
|
||||
|
||||
tmp = round_trampoline_addr (r_tramp);
|
||||
if (tmp != r_tramp)
|
||||
{
|
||||
m_tramp = change_address (m_tramp, BLKmode, tmp);
|
||||
set_mem_align (m_tramp, TRAMPOLINE_ALIGNMENT);
|
||||
set_mem_size (m_tramp, GEN_INT (TRAMPOLINE_SIZE));
|
||||
}
|
||||
|
||||
/* The FUNC argument should be the address of the nested function.
|
||||
Extract the actual function decl to pass to the hook. */
|
||||
gcc_assert (TREE_CODE (t_func) == ADDR_EXPR);
|
||||
t_func = TREE_OPERAND (t_func, 0);
|
||||
gcc_assert (TREE_CODE (t_func) == FUNCTION_DECL);
|
||||
|
||||
r_chain = expand_normal (t_chain);
|
||||
|
||||
/* Generate insns to initialize the trampoline. */
|
||||
r_tramp = round_trampoline_addr (r_tramp);
|
||||
#ifdef TRAMPOLINE_TEMPLATE
|
||||
blktramp = gen_rtx_MEM (BLKmode, r_tramp);
|
||||
set_mem_align (blktramp, TRAMPOLINE_ALIGNMENT);
|
||||
emit_block_move (blktramp, assemble_trampoline_template (),
|
||||
GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
|
||||
#endif
|
||||
trampolines_created = 1;
|
||||
INITIALIZE_TRAMPOLINE (r_tramp, r_func, r_chain);
|
||||
targetm.calls.trampoline_init (m_tramp, t_func, r_chain);
|
||||
|
||||
trampolines_created = 1;
|
||||
return const0_rtx;
|
||||
}
|
||||
|
||||
|
@ -5856,9 +5870,8 @@ expand_builtin_adjust_trampoline (tree exp)
|
|||
|
||||
tramp = expand_normal (CALL_EXPR_ARG (exp, 0));
|
||||
tramp = round_trampoline_addr (tramp);
|
||||
#ifdef TRAMPOLINE_ADJUST_ADDRESS
|
||||
TRAMPOLINE_ADJUST_ADDRESS (tramp);
|
||||
#endif
|
||||
if (targetm.calls.trampoline_adjust_address)
|
||||
tramp = targetm.calls.trampoline_adjust_address (tramp);
|
||||
|
||||
return tramp;
|
||||
}
|
||||
|
|
18
gcc/calls.c
18
gcc/calls.c
|
@ -166,7 +166,7 @@ static void restore_fixed_argument_area (rtx, rtx, int, int);
|
|||
CALL_INSN_FUNCTION_USAGE information. */
|
||||
|
||||
rtx
|
||||
prepare_call_address (rtx funexp, rtx static_chain_value,
|
||||
prepare_call_address (tree fndecl, rtx funexp, rtx static_chain_value,
|
||||
rtx *call_fusage, int reg_parm_seen, int sibcallp)
|
||||
{
|
||||
/* Make a valid memory address and copy constants through pseudo-regs,
|
||||
|
@ -187,11 +187,15 @@ prepare_call_address (rtx funexp, rtx static_chain_value,
|
|||
|
||||
if (static_chain_value != 0)
|
||||
{
|
||||
static_chain_value = convert_memory_address (Pmode, static_chain_value);
|
||||
emit_move_insn (static_chain_rtx, static_chain_value);
|
||||
rtx chain;
|
||||
|
||||
if (REG_P (static_chain_rtx))
|
||||
use_reg (call_fusage, static_chain_rtx);
|
||||
gcc_assert (fndecl);
|
||||
chain = targetm.calls.static_chain (fndecl, false);
|
||||
static_chain_value = convert_memory_address (Pmode, static_chain_value);
|
||||
|
||||
emit_move_insn (chain, static_chain_value);
|
||||
if (REG_P (chain))
|
||||
use_reg (call_fusage, chain);
|
||||
}
|
||||
|
||||
return funexp;
|
||||
|
@ -2807,7 +2811,7 @@ expand_call (tree exp, rtx target, int ignore)
|
|||
}
|
||||
|
||||
after_args = get_last_insn ();
|
||||
funexp = prepare_call_address (funexp, static_chain_value,
|
||||
funexp = prepare_call_address (fndecl, funexp, static_chain_value,
|
||||
&call_fusage, reg_parm_seen, pass == 0);
|
||||
|
||||
load_register_parameters (args, num_actuals, &call_fusage, flags,
|
||||
|
@ -3735,7 +3739,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
|
|||
else
|
||||
argnum = 0;
|
||||
|
||||
fun = prepare_call_address (fun, NULL, &call_fusage, 0, 0);
|
||||
fun = prepare_call_address (NULL, fun, NULL, &call_fusage, 0, 0);
|
||||
|
||||
/* Now load any reg parms into their regs. */
|
||||
|
||||
|
|
|
@ -982,7 +982,7 @@ void add_framework_path (char *);
|
|||
#endif
|
||||
|
||||
/* Attempt to turn on execute permission for the stack. This may be
|
||||
used by INITIALIZE_TRAMPOLINE of the target needs it (that is,
|
||||
used by TARGET_TRAMPOLINE_INIT if the target needs it (that is,
|
||||
if the target machine can change execute permissions on a page).
|
||||
|
||||
There is no way to query the execute permission of the stack, so
|
||||
|
|
|
@ -180,7 +180,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
|
||||
/* Attempt to turn on execute permission for the stack. This may be
|
||||
used by INITIALIZE_TRAMPOLINE of the target needs it (that is,
|
||||
used by TARGET_TRAMPOLINE_INIT if the target needs it (that is,
|
||||
if the target machine can change execute permissions on a page).
|
||||
|
||||
There is no way to query the execute permission of the stack, so
|
||||
|
|
|
@ -3601,18 +3601,6 @@ df_recompute_luids (basic_block bb)
|
|||
}
|
||||
|
||||
|
||||
/* Returns true if the function entry needs to
|
||||
define the static chain register. */
|
||||
|
||||
static bool
|
||||
df_need_static_chain_reg (struct function *fun)
|
||||
{
|
||||
tree fun_context = decl_function_context (fun->decl);
|
||||
return fun_context
|
||||
&& DECL_NO_STATIC_CHAIN (fun_context) == false;
|
||||
}
|
||||
|
||||
|
||||
/* Collect all artificial refs at the block level for BB and add them
|
||||
to COLLECTION_REC. */
|
||||
|
||||
|
@ -3891,24 +3879,17 @@ df_get_entry_block_def_set (bitmap entry_block_defs)
|
|||
if ((call_used_regs[i] == 0) && (df_regs_ever_live_p (i)))
|
||||
bitmap_set_bit (entry_block_defs, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If STATIC_CHAIN_INCOMING_REGNUM == STATIC_CHAIN_REGNUM
|
||||
only STATIC_CHAIN_REGNUM is defined. If they are different,
|
||||
we only care about the STATIC_CHAIN_INCOMING_REGNUM. */
|
||||
#ifdef STATIC_CHAIN_INCOMING_REGNUM
|
||||
bitmap_set_bit (entry_block_defs, STATIC_CHAIN_INCOMING_REGNUM);
|
||||
#else
|
||||
#ifdef STATIC_CHAIN_REGNUM
|
||||
bitmap_set_bit (entry_block_defs, STATIC_CHAIN_REGNUM);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
r = targetm.calls.struct_value_rtx (current_function_decl, true);
|
||||
if (r && REG_P (r))
|
||||
bitmap_set_bit (entry_block_defs, REGNO (r));
|
||||
|
||||
/* If the function has an incoming STATIC_CHAIN, it has to show up
|
||||
in the entry def set. */
|
||||
r = targetm.calls.static_chain (current_function_decl, true);
|
||||
if (r && REG_P (r))
|
||||
bitmap_set_bit (entry_block_defs, REGNO (r));
|
||||
|
||||
if ((!reload_completed) || frame_pointer_needed)
|
||||
{
|
||||
/* Any reference to any pseudo before reload is a potential
|
||||
|
@ -3946,19 +3927,6 @@ df_get_entry_block_def_set (bitmap entry_block_defs)
|
|||
#endif
|
||||
|
||||
targetm.live_on_entry (entry_block_defs);
|
||||
|
||||
/* If the function has an incoming STATIC_CHAIN,
|
||||
it has to show up in the entry def set. */
|
||||
if (df_need_static_chain_reg (cfun))
|
||||
{
|
||||
#ifdef STATIC_CHAIN_INCOMING_REGNUM
|
||||
bitmap_set_bit (entry_block_defs, STATIC_CHAIN_INCOMING_REGNUM);
|
||||
#else
|
||||
#ifdef STATIC_CHAIN_REGNUM
|
||||
bitmap_set_bit (entry_block_defs, STATIC_CHAIN_REGNUM);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -3684,6 +3684,16 @@ If the static chain is passed in a register, the two previous macros should
|
|||
be defined instead.
|
||||
@end defmac
|
||||
|
||||
@deftypefn {Target Hook} rtx TARGET_STATIC_CHAIN (const_tree @var{fndecl}, bool @var{incoming_p})
|
||||
This hook replaces the use of @code{STATIC_CHAIN_REGNUM} et al for
|
||||
targets that may use different static chain locations for different
|
||||
nested functions. This may be required if the target has function
|
||||
attributes that affect the calling conventions of the function and
|
||||
those calling conventions use different static chain locations.
|
||||
|
||||
The default version of this hook uses @code{STATIC_CHAIN_REGNUM} et al.
|
||||
@end deftypefn
|
||||
|
||||
@defmac DWARF_FRAME_REGISTERS
|
||||
This macro specifies the maximum number of hard registers that can be
|
||||
saved in a call frame. This is used to size data structures used in
|
||||
|
@ -5099,17 +5109,17 @@ proper offset from the start of the trampoline. On a RISC machine, it
|
|||
may be necessary to take out pieces of the address and store them
|
||||
separately.
|
||||
|
||||
@defmac TRAMPOLINE_TEMPLATE (@var{file})
|
||||
A C statement to output, on the stream @var{file}, assembler code for a
|
||||
block of data that contains the constant parts of a trampoline. This
|
||||
code should not include a label---the label is taken care of
|
||||
automatically.
|
||||
@deftypefn {Target Hook} void TARGET_ASM_TRAMPOLINE_TEMPLATE (FILE *@var{f})
|
||||
This hook is called by @code{assemble_trampoline_template} to output,
|
||||
on the stream @var{f}, assembler code for a block of data that contains
|
||||
the constant parts of a trampoline. This code should not include a
|
||||
label---the label is taken care of automatically.
|
||||
|
||||
If you do not define this macro, it means no template is needed
|
||||
for the target. Do not define this macro on systems where the block move
|
||||
If you do not define this hook, it means no template is needed
|
||||
for the target. Do not define this hook on systems where the block move
|
||||
code to copy the trampoline into place would be larger than the code
|
||||
to generate it on the spot.
|
||||
@end defmac
|
||||
@end deftypefn
|
||||
|
||||
@defmac TRAMPOLINE_SECTION
|
||||
Return the section into which the trampoline template is to be placed
|
||||
|
@ -5123,43 +5133,38 @@ A C expression for the size in bytes of the trampoline, as an integer.
|
|||
@defmac TRAMPOLINE_ALIGNMENT
|
||||
Alignment required for trampolines, in bits.
|
||||
|
||||
If you don't define this macro, the value of @code{BIGGEST_ALIGNMENT}
|
||||
If you don't define this macro, the value of @code{FUNCTION_ALIGNMENT}
|
||||
is used for aligning trampolines.
|
||||
@end defmac
|
||||
|
||||
@defmac INITIALIZE_TRAMPOLINE (@var{addr}, @var{fnaddr}, @var{static_chain})
|
||||
A C statement to initialize the variable parts of a trampoline.
|
||||
@var{addr} is an RTX for the address of the trampoline; @var{fnaddr} is
|
||||
an RTX for the address of the nested function; @var{static_chain} is an
|
||||
@deftypefn {Target Hook} void TARGET_TRAMPOLINE_INIT (rtx @var{m_tramp}, tree @var{fndecl}, rtx @var{static_chain})
|
||||
This hook is called to initialize a trampoline.
|
||||
@var{m_tramp} is an RTX for the memory block for the trampoline; @var{fndecl}
|
||||
is the @code{FUNCTION_DECL} for the nested function; @var{static_chain} is an
|
||||
RTX for the static chain value that should be passed to the function
|
||||
when it is called.
|
||||
@end defmac
|
||||
|
||||
@defmac TRAMPOLINE_ADJUST_ADDRESS (@var{addr})
|
||||
A C statement that should perform any machine-specific adjustment in
|
||||
the address of the trampoline. Its argument contains the address that
|
||||
was passed to @code{INITIALIZE_TRAMPOLINE}. In case the address to be
|
||||
used for a function call should be different from the address in which
|
||||
the template was stored, the different address should be assigned to
|
||||
@var{addr}. If this macro is not defined, @var{addr} will be used for
|
||||
function calls.
|
||||
If the target defines @code{TARGET_ASM_TRAMPOLINE_TEMPLATE}, then the
|
||||
first thing this hook should do is emit a block move into @var{m_tramp}
|
||||
from the memory block returned by @code{assemble_trampoline_template}.
|
||||
Note that the block move need only cover the constant parts of the
|
||||
trampoline. If the target isolates the variable parts of the trampoline
|
||||
to the end, not all @code{TRAMPOLINE_SIZE} bytes need be copied.
|
||||
|
||||
@cindex @code{TARGET_ASM_FUNCTION_EPILOGUE} and trampolines
|
||||
@cindex @code{TARGET_ASM_FUNCTION_PROLOGUE} and trampolines
|
||||
If this macro is not defined, by default the trampoline is allocated as
|
||||
a stack slot. This default is right for most machines. The exceptions
|
||||
are machines where it is impossible to execute instructions in the stack
|
||||
area. On such machines, you may have to implement a separate stack,
|
||||
using this macro in conjunction with @code{TARGET_ASM_FUNCTION_PROLOGUE}
|
||||
and @code{TARGET_ASM_FUNCTION_EPILOGUE}.
|
||||
If the target requires any other actions, such as flushing caches or
|
||||
enabling stack execution, these actions should be performed after
|
||||
initializing the trampoline proper.
|
||||
@end deftypefn
|
||||
|
||||
@var{fp} points to a data structure, a @code{struct function}, which
|
||||
describes the compilation status of the immediate containing function of
|
||||
the function which the trampoline is for. The stack slot for the
|
||||
trampoline is in the stack frame of this containing function. Other
|
||||
allocation strategies probably must do something analogous with this
|
||||
information.
|
||||
@end defmac
|
||||
@deftypefn {Target Hook} rtx TARGET_TRAMPOLINE_ADJUST_ADDRESS (rtx @var{addr})
|
||||
This hook should perform any machine-specific adjustment in
|
||||
the address of the trampoline. Its argument contains the address of the
|
||||
memory block that was passed to @code{TARGET_TRAMPOLINE_INIT}. In case
|
||||
the address to be used for a function call should be different from the
|
||||
address at which the template was stored, the different address should
|
||||
be returned; otherwise @var{addr} should be returned unchanged.
|
||||
If this hook is not defined, @var{addr} will be used for function calls.
|
||||
@end deftypefn
|
||||
|
||||
Implementing trampolines is difficult on many machines because they have
|
||||
separate instruction and data caches. Writing into a stack location
|
||||
|
@ -5192,7 +5197,7 @@ code located on the stack. The macro should expand to a series of C
|
|||
file-scope constructs (e.g.@: functions) and provide a unique entry point
|
||||
named @code{__enable_execute_stack}. The target is responsible for
|
||||
emitting calls to the entry point in the code, for example from the
|
||||
@code{INITIALIZE_TRAMPOLINE} macro.
|
||||
@code{TARGET_TRAMPOLINE_INIT} hook.
|
||||
@end defmac
|
||||
|
||||
To use a standard subroutine, define the following macro. In addition,
|
||||
|
|
|
@ -136,8 +136,6 @@ FIXED_VALUE_TYPE fconst1[MAX_FCONST1];
|
|||
|
||||
In an inline procedure, the stack and frame pointer rtxs may not be
|
||||
used for anything else. */
|
||||
rtx static_chain_rtx; /* (REG:Pmode STATIC_CHAIN_REGNUM) */
|
||||
rtx static_chain_incoming_rtx; /* (REG:Pmode STATIC_CHAIN_INCOMING_REGNUM) */
|
||||
rtx pic_offset_table_rtx; /* (REG:Pmode PIC_OFFSET_TABLE_REGNUM) */
|
||||
|
||||
/* This is used to implement __builtin_return_address for some machines.
|
||||
|
@ -5671,28 +5669,6 @@ init_emit_regs (void)
|
|||
= gen_raw_REG (Pmode, RETURN_ADDRESS_POINTER_REGNUM);
|
||||
#endif
|
||||
|
||||
#ifdef STATIC_CHAIN_REGNUM
|
||||
static_chain_rtx = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
|
||||
|
||||
#ifdef STATIC_CHAIN_INCOMING_REGNUM
|
||||
if (STATIC_CHAIN_INCOMING_REGNUM != STATIC_CHAIN_REGNUM)
|
||||
static_chain_incoming_rtx
|
||||
= gen_rtx_REG (Pmode, STATIC_CHAIN_INCOMING_REGNUM);
|
||||
else
|
||||
#endif
|
||||
static_chain_incoming_rtx = static_chain_rtx;
|
||||
#endif
|
||||
|
||||
#ifdef STATIC_CHAIN
|
||||
static_chain_rtx = STATIC_CHAIN;
|
||||
|
||||
#ifdef STATIC_CHAIN_INCOMING
|
||||
static_chain_incoming_rtx = STATIC_CHAIN_INCOMING;
|
||||
#else
|
||||
static_chain_incoming_rtx = static_chain_rtx;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if ((unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
|
||||
pic_offset_table_rtx = gen_raw_REG (Pmode, PIC_OFFSET_TABLE_REGNUM);
|
||||
else
|
||||
|
|
|
@ -618,7 +618,7 @@ extern HOST_WIDE_INT int_expr_size (tree);
|
|||
in its original home. This becomes invalid if any more code is emitted. */
|
||||
extern rtx hard_function_value (const_tree, const_tree, const_tree, int);
|
||||
|
||||
extern rtx prepare_call_address (rtx, rtx, rtx *, int, int);
|
||||
extern rtx prepare_call_address (tree, rtx, rtx, rtx *, int, int);
|
||||
|
||||
extern bool shift_return_value (enum machine_mode, bool, rtx);
|
||||
|
||||
|
|
58
gcc/final.c
58
gcc/final.c
|
@ -1594,12 +1594,14 @@ profile_function (FILE *file ATTRIBUTE_UNUSED)
|
|||
#ifndef NO_PROFILE_COUNTERS
|
||||
# define NO_PROFILE_COUNTERS 0
|
||||
#endif
|
||||
#if defined(ASM_OUTPUT_REG_PUSH)
|
||||
int sval = cfun->returns_struct;
|
||||
rtx svrtx = targetm.calls.struct_value_rtx (TREE_TYPE (current_function_decl), 1);
|
||||
#if defined(STATIC_CHAIN_INCOMING_REGNUM) || defined(STATIC_CHAIN_REGNUM)
|
||||
int cxt = cfun->static_chain_decl != NULL;
|
||||
#endif
|
||||
#ifdef ASM_OUTPUT_REG_PUSH
|
||||
rtx sval = NULL, chain = NULL;
|
||||
|
||||
if (cfun->returns_struct)
|
||||
sval = targetm.calls.struct_value_rtx (TREE_TYPE (current_function_decl),
|
||||
true);
|
||||
if (cfun->static_chain_decl)
|
||||
chain = targetm.calls.static_chain (current_function_decl, true);
|
||||
#endif /* ASM_OUTPUT_REG_PUSH */
|
||||
|
||||
if (! NO_PROFILE_COUNTERS)
|
||||
|
@ -1613,44 +1615,20 @@ profile_function (FILE *file ATTRIBUTE_UNUSED)
|
|||
|
||||
switch_to_section (current_function_section ());
|
||||
|
||||
#if defined(ASM_OUTPUT_REG_PUSH)
|
||||
if (sval && svrtx != NULL_RTX && REG_P (svrtx))
|
||||
{
|
||||
ASM_OUTPUT_REG_PUSH (file, REGNO (svrtx));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
|
||||
if (cxt)
|
||||
ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_INCOMING_REGNUM);
|
||||
#else
|
||||
#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
|
||||
if (cxt)
|
||||
{
|
||||
ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_REGNUM);
|
||||
}
|
||||
#endif
|
||||
#ifdef ASM_OUTPUT_REG_PUSH
|
||||
if (sval && REG_P (sval))
|
||||
ASM_OUTPUT_REG_PUSH (file, REGNO (sval));
|
||||
if (chain && REG_P (chain))
|
||||
ASM_OUTPUT_REG_PUSH (file, REGNO (chain));
|
||||
#endif
|
||||
|
||||
FUNCTION_PROFILER (file, current_function_funcdef_no);
|
||||
|
||||
#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
|
||||
if (cxt)
|
||||
ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_INCOMING_REGNUM);
|
||||
#else
|
||||
#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
|
||||
if (cxt)
|
||||
{
|
||||
ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_REGNUM);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(ASM_OUTPUT_REG_PUSH)
|
||||
if (sval && svrtx != NULL_RTX && REG_P (svrtx))
|
||||
{
|
||||
ASM_OUTPUT_REG_POP (file, REGNO (svrtx));
|
||||
}
|
||||
#ifdef ASM_OUTPUT_REG_PUSH
|
||||
if (chain && REG_P (chain))
|
||||
ASM_OUTPUT_REG_POP (file, REGNO (chain));
|
||||
if (sval && REG_P (sval))
|
||||
ASM_OUTPUT_REG_POP (file, REGNO (sval));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -4453,13 +4453,21 @@ expand_function_start (tree subr)
|
|||
if (cfun->static_chain_decl)
|
||||
{
|
||||
tree parm = cfun->static_chain_decl;
|
||||
rtx local = gen_reg_rtx (Pmode);
|
||||
rtx local, chain, insn;
|
||||
|
||||
set_decl_incoming_rtl (parm, static_chain_incoming_rtx, false);
|
||||
local = gen_reg_rtx (Pmode);
|
||||
chain = targetm.calls.static_chain (current_function_decl, true);
|
||||
|
||||
set_decl_incoming_rtl (parm, chain, false);
|
||||
SET_DECL_RTL (parm, local);
|
||||
mark_reg_pointer (local, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (parm))));
|
||||
|
||||
emit_move_insn (local, static_chain_incoming_rtx);
|
||||
insn = emit_move_insn (local, chain);
|
||||
|
||||
/* Mark the register as eliminable, similar to parameters. */
|
||||
if (MEM_P (chain)
|
||||
&& reg_mentioned_p (arg_pointer_rtx, XEXP (chain, 0)))
|
||||
set_unique_reg_note (insn, REG_EQUIV, chain);
|
||||
}
|
||||
|
||||
/* If the function receives a non-local goto, then store the
|
||||
|
|
|
@ -2024,8 +2024,6 @@ extern GTY(()) rtx global_rtl[GR_MAX];
|
|||
#define arg_pointer_rtx (global_rtl[GR_ARG_POINTER])
|
||||
|
||||
extern GTY(()) rtx pic_offset_table_rtx;
|
||||
extern GTY(()) rtx static_chain_rtx;
|
||||
extern GTY(()) rtx static_chain_incoming_rtx;
|
||||
extern GTY(()) rtx return_address_pointer_rtx;
|
||||
|
||||
/* Include the RTL generation functions. */
|
||||
|
|
|
@ -1799,13 +1799,17 @@ expand_return (tree retval)
|
|||
static void
|
||||
expand_nl_goto_receiver (void)
|
||||
{
|
||||
rtx chain;
|
||||
|
||||
/* Clobber the FP when we get here, so we have to make sure it's
|
||||
marked as used by this function. */
|
||||
emit_use (hard_frame_pointer_rtx);
|
||||
|
||||
/* Mark the static chain as clobbered here so life information
|
||||
doesn't get messed up for it. */
|
||||
emit_clobber (static_chain_rtx);
|
||||
chain = targetm.calls.static_chain (current_function_decl, true);
|
||||
if (chain && REG_P (chain))
|
||||
emit_clobber (chain);
|
||||
|
||||
#ifdef HAVE_nonlocal_goto
|
||||
if (! HAVE_nonlocal_goto)
|
||||
|
|
|
@ -247,6 +247,12 @@
|
|||
#define TARGET_ASM_RECORD_GCC_SWITCHES_SECTION ".GCC.command.line"
|
||||
#endif
|
||||
|
||||
#ifdef TRAMPOLINE_TEMPLATE
|
||||
# define TARGET_ASM_TRAMPOLINE_TEMPLATE default_asm_trampoline_template
|
||||
#else
|
||||
# define TARGET_ASM_TRAMPOLINE_TEMPLATE NULL
|
||||
#endif
|
||||
|
||||
#define TARGET_ASM_ALIGNED_INT_OP \
|
||||
{TARGET_ASM_ALIGNED_HI_OP, \
|
||||
TARGET_ASM_ALIGNED_SI_OP, \
|
||||
|
@ -296,7 +302,8 @@
|
|||
TARGET_ASM_RECORD_GCC_SWITCHES_SECTION, \
|
||||
TARGET_ASM_OUTPUT_ANCHOR, \
|
||||
TARGET_ASM_OUTPUT_DWARF_DTPREL, \
|
||||
TARGET_ASM_FINAL_POSTSCAN_INSN}
|
||||
TARGET_ASM_FINAL_POSTSCAN_INSN, \
|
||||
TARGET_ASM_TRAMPOLINE_TEMPLATE }
|
||||
|
||||
/* Scheduler hooks. All of these default to null pointers, which
|
||||
haifa-sched.c looks for and handles. */
|
||||
|
@ -607,6 +614,14 @@
|
|||
#define TARGET_UPDATE_STACK_BOUNDARY NULL
|
||||
#define TARGET_GET_DRAP_RTX NULL
|
||||
#define TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS hook_bool_void_true
|
||||
#define TARGET_STATIC_CHAIN default_static_chain
|
||||
#define TARGET_TRAMPOLINE_INIT default_trampoline_init
|
||||
|
||||
#ifdef TRAMPOLINE_ADJUST_ADDRESS
|
||||
# define TARGET_TRAMPOLINE_ADJUST_ADDRESS default_trampoline_adjust_address
|
||||
#else
|
||||
# define TARGET_TRAMPOLINE_ADJUST_ADDRESS NULL
|
||||
#endif
|
||||
|
||||
#define TARGET_CALLS { \
|
||||
TARGET_PROMOTE_FUNCTION_MODE, \
|
||||
|
@ -629,7 +644,10 @@
|
|||
TARGET_INTERNAL_ARG_POINTER, \
|
||||
TARGET_UPDATE_STACK_BOUNDARY, \
|
||||
TARGET_GET_DRAP_RTX, \
|
||||
TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS \
|
||||
TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS, \
|
||||
TARGET_STATIC_CHAIN, \
|
||||
TARGET_TRAMPOLINE_INIT, \
|
||||
TARGET_TRAMPOLINE_ADJUST_ADDRESS \
|
||||
}
|
||||
|
||||
#ifndef TARGET_UNWIND_TABLES_DEFAULT
|
||||
|
|
15
gcc/target.h
15
gcc/target.h
|
@ -253,6 +253,9 @@ struct gcc_target
|
|||
|
||||
/* Some target machines need to postscan each insn after it is output. */
|
||||
void (*final_postscan_insn) (FILE *, rtx, rtx *, int);
|
||||
|
||||
/* Emit the trampoline template. This hook may be NULL. */
|
||||
void (*trampoline_template) (FILE *);
|
||||
} asm_out;
|
||||
|
||||
/* Functions relating to instruction scheduling. */
|
||||
|
@ -915,7 +918,17 @@ struct gcc_target
|
|||
/* Return true if all function parameters should be spilled to the
|
||||
stack. */
|
||||
bool (*allocate_stack_slots_for_args) (void);
|
||||
|
||||
|
||||
/* Return an rtx for the static chain for FNDECL. If INCOMING_P is true,
|
||||
then it should be for the callee; otherwise for the caller. */
|
||||
rtx (*static_chain) (const_tree fndecl, bool incoming_p);
|
||||
|
||||
/* Fill in the trampoline at MEM with a call to FNDECL and a
|
||||
static chain value of CHAIN. */
|
||||
void (*trampoline_init) (rtx mem, tree fndecl, rtx chain);
|
||||
|
||||
/* Adjust the address of the trampoline in a target-specific way. */
|
||||
rtx (*trampoline_adjust_address) (rtx addr);
|
||||
} calls;
|
||||
|
||||
/* Return the diagnostic message string if conversion from FROMTYPE
|
||||
|
|
|
@ -628,6 +628,69 @@ default_internal_arg_pointer (void)
|
|||
return virtual_incoming_args_rtx;
|
||||
}
|
||||
|
||||
rtx
|
||||
default_static_chain (const_tree fndecl, bool incoming_p)
|
||||
{
|
||||
if (DECL_NO_STATIC_CHAIN (fndecl))
|
||||
return NULL;
|
||||
|
||||
if (incoming_p)
|
||||
{
|
||||
#ifdef STATIC_CHAIN_INCOMING
|
||||
return STATIC_CHAIN_INCOMING;
|
||||
#endif
|
||||
#ifdef STATIC_CHAIN_INCOMING_REGNUM
|
||||
return gen_rtx_REG (Pmode, STATIC_CHAIN_INCOMING_REGNUM);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef STATIC_CHAIN
|
||||
return STATIC_CHAIN;
|
||||
#endif
|
||||
#ifdef STATIC_CHAIN_REGNUM
|
||||
return gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
|
||||
#endif
|
||||
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
#ifdef TRAMPOLINE_TEMPLATE
|
||||
void
|
||||
default_asm_trampoline_template (FILE *f)
|
||||
{
|
||||
TRAMPOLINE_TEMPLATE (f);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
default_trampoline_init (rtx ARG_UNUSED (m_tramp), tree ARG_UNUSED (t_func),
|
||||
rtx ARG_UNUSED (r_chain))
|
||||
{
|
||||
#ifdef INITIALIZE_TRAMPOLINE
|
||||
rtx r_tramp, r_func;
|
||||
|
||||
if (targetm.asm_out.trampoline_template)
|
||||
emit_block_move (m_tramp, assemble_trampoline_template (),
|
||||
GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
|
||||
|
||||
r_func = XEXP (DECL_RTL (t_func), 0);
|
||||
r_tramp = XEXP (m_tramp, 0);
|
||||
|
||||
INITIALIZE_TRAMPOLINE (r_tramp, r_func, r_chain);
|
||||
#else
|
||||
sorry ("nested function trampolines not supported on this target");
|
||||
#endif
|
||||
}
|
||||
|
||||
rtx
|
||||
default_trampoline_adjust_address (rtx addr)
|
||||
{
|
||||
#ifdef TRAMPOLINE_ADJUST_ADDRESS
|
||||
TRAMPOLINE_ADJUST_ADDRESS (addr);
|
||||
#endif
|
||||
return addr;
|
||||
}
|
||||
|
||||
enum reg_class
|
||||
default_branch_target_register_class (void)
|
||||
{
|
||||
|
|
|
@ -100,6 +100,10 @@ extern bool hook_bool_const_rtx_commutative_p (const_rtx, int);
|
|||
extern rtx default_function_value (const_tree, const_tree, bool);
|
||||
extern rtx default_libcall_value (enum machine_mode, rtx);
|
||||
extern rtx default_internal_arg_pointer (void);
|
||||
extern rtx default_static_chain (const_tree, bool);
|
||||
extern void default_asm_trampoline_template (FILE *);
|
||||
extern void default_trampoline_init (rtx, tree, rtx);
|
||||
extern rtx default_trampoline_adjust_address (rtx);
|
||||
extern enum reg_class default_branch_target_register_class (void);
|
||||
#ifdef IRA_COVER_CLASSES
|
||||
extern const enum reg_class *default_ira_cover_classes (void);
|
||||
|
|
13
gcc/varasm.c
13
gcc/varasm.c
|
@ -2507,7 +2507,6 @@ assemble_static_space (unsigned HOST_WIDE_INT size)
|
|||
|
||||
static GTY(()) rtx initial_trampoline;
|
||||
|
||||
#ifdef TRAMPOLINE_TEMPLATE
|
||||
rtx
|
||||
assemble_trampoline_template (void)
|
||||
{
|
||||
|
@ -2516,6 +2515,8 @@ assemble_trampoline_template (void)
|
|||
int align;
|
||||
rtx symbol;
|
||||
|
||||
gcc_assert (targetm.asm_out.trampoline_template != NULL);
|
||||
|
||||
if (initial_trampoline)
|
||||
return initial_trampoline;
|
||||
|
||||
|
@ -2530,12 +2531,10 @@ assemble_trampoline_template (void)
|
|||
/* Write the assembler code to define one. */
|
||||
align = floor_log2 (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT);
|
||||
if (align > 0)
|
||||
{
|
||||
ASM_OUTPUT_ALIGN (asm_out_file, align);
|
||||
}
|
||||
ASM_OUTPUT_ALIGN (asm_out_file, align);
|
||||
|
||||
targetm.asm_out.internal_label (asm_out_file, "LTRAMP", 0);
|
||||
TRAMPOLINE_TEMPLATE (asm_out_file);
|
||||
targetm.asm_out.trampoline_template (asm_out_file);
|
||||
|
||||
/* Record the rtl to refer to it. */
|
||||
ASM_GENERATE_INTERNAL_LABEL (label, "LTRAMP", 0);
|
||||
|
@ -2543,12 +2542,12 @@ assemble_trampoline_template (void)
|
|||
symbol = gen_rtx_SYMBOL_REF (Pmode, name);
|
||||
SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_LOCAL;
|
||||
|
||||
initial_trampoline = gen_rtx_MEM (BLKmode, symbol);
|
||||
initial_trampoline = gen_const_mem (BLKmode, symbol);
|
||||
set_mem_align (initial_trampoline, TRAMPOLINE_ALIGNMENT);
|
||||
set_mem_size (initial_trampoline, GEN_INT (TRAMPOLINE_SIZE));
|
||||
|
||||
return initial_trampoline;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* A and B are either alignments or offsets. Return the minimum alignment
|
||||
that may be assumed after adding the two together. */
|
||||
|
|
Loading…
Reference in New Issue