Commit 14691f8d by Richard Henderson Committed by Richard Henderson

alpha.c (current_function_is_thunk): Don't check current_function_is_thunk.

        * config/alpha/alpha.c (current_function_is_thunk): Don't check
        current_function_is_thunk.
        (alpha_sa_mask): Distinguish between current_function_is_thunk
        called from ASM_OUTPUT_MI_THUNK and not.
        (alpha_does_function_need_gp): Thunks always need gp.
        (alpha_start_function, alpha_output_function_end_prologue): Likewise.
        (alpha_output_mi_thunk_osf): New.
        * config/alpha/alpha-protos.h: Update.
        * config/alpha/alpha.h (ASM_OUTPUT_MI_THUNK): New.

cp/
        * method.c (use_thunk): Always initialize the block tree.  Reindent.
        * semantics.c (expand_body): Emit thunks after function, not before.

From-SVN: r49484
parent 8d9d2e1d
2002-02-04 Richard Henderson <rth@redhat.com>
* config/alpha/alpha.c (current_function_is_thunk): Don't check
current_function_is_thunk.
(alpha_sa_mask): Distinguish between current_function_is_thunk
called from ASM_OUTPUT_MI_THUNK and not.
(alpha_does_function_need_gp): Thunks always need gp.
(alpha_start_function, alpha_output_function_end_prologue): Likewise.
(alpha_output_mi_thunk_osf): New.
* config/alpha/alpha-protos.h: Update.
* config/alpha/alpha.h (ASM_OUTPUT_MI_THUNK): New.
2002-02-04 Richard Sandiford <rsandifo@redhat.com>
* c-typeck.c (build_c_cast): Warn when qualifiers are added to
......
......@@ -163,6 +163,8 @@ extern rtx function_arg PARAMS ((CUMULATIVE_ARGS, enum machine_mode,
#endif
extern void alpha_start_function PARAMS ((FILE *, const char *, tree));
extern void alpha_end_function PARAMS ((FILE *, const char *, tree));
extern void alpha_output_mi_thunk_osf PARAMS ((FILE *, tree,
HOST_WIDE_INT, tree));
extern void alpha_encode_section_info PARAMS ((tree));
#endif /* TREE CODE */
......
......@@ -46,6 +46,7 @@ Boston, MA 02111-1307, USA. */
#include "tm_p.h"
#include "target.h"
#include "target-def.h"
#include "debug.h"
/* External data. */
extern int rtx_equal_function_value_matters;
......@@ -4993,10 +4994,6 @@ alpha_ra_ever_killed ()
{
rtx top;
#ifdef ASM_OUTPUT_MI_THUNK
if (current_function_is_thunk)
return 0;
#endif
if (!has_hard_reg_initial_val (Pmode, REG_RA))
return regs_ever_live[REG_RA];
......@@ -5859,43 +5856,48 @@ alpha_sa_mask (imaskP, fmaskP)
unsigned long fmask = 0;
unsigned int i;
#ifdef ASM_OUTPUT_MI_THUNK
if (!current_function_is_thunk)
#endif
/* Irritatingly, there are two kinds of thunks -- those created with
ASM_OUTPUT_MI_THUNK and those with DECL_THUNK_P that go through
the regular part of the compiler. In the ASM_OUTPUT_MI_THUNK case
we don't have valid register life info, but assemble_start_function
wants to output .frame and .mask directives. */
if (current_function_is_thunk && rtx_equal_function_value_matters)
{
if (TARGET_ABI_OPEN_VMS && alpha_is_stack_procedure)
imask |= (1L << HARD_FRAME_POINTER_REGNUM);
*imaskP = 0;
*fmaskP = 0;
return;
}
/* One for every register we have to save. */
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (! fixed_regs[i] && ! call_used_regs[i]
&& regs_ever_live[i] && i != REG_RA
&& (!TARGET_ABI_UNICOSMK || i != HARD_FRAME_POINTER_REGNUM))
{
if (i < 32)
imask |= (1L << i);
else
fmask |= (1L << (i - 32));
}
if (TARGET_ABI_OPEN_VMS && alpha_is_stack_procedure)
imask |= (1L << HARD_FRAME_POINTER_REGNUM);
/* We need to restore these for the handler. */
if (current_function_calls_eh_return)
{
for (i = 0; ; ++i)
{
unsigned regno = EH_RETURN_DATA_REGNO (i);
if (regno == INVALID_REGNUM)
break;
imask |= 1L << regno;
}
}
/* One for every register we have to save. */
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (! fixed_regs[i] && ! call_used_regs[i]
&& regs_ever_live[i] && i != REG_RA
&& (!TARGET_ABI_UNICOSMK || i != HARD_FRAME_POINTER_REGNUM))
{
if (i < 32)
imask |= (1L << i);
else
fmask |= (1L << (i - 32));
}
/* We need to restore these for the handler. */
if (current_function_calls_eh_return)
for (i = 0; ; ++i)
{
unsigned regno = EH_RETURN_DATA_REGNO (i);
if (regno == INVALID_REGNUM)
break;
imask |= 1L << regno;
}
/* If any register spilled, then spill the return address also. */
/* ??? This is required by the Digital stack unwind specification
and isn't needed if we're doing Dwarf2 unwinding. */
if (imask || fmask || alpha_ra_ever_killed ())
imask |= (1L << REG_RA);
}
/* If any register spilled, then spill the return address also. */
/* ??? This is required by the Digital stack unwind specification
and isn't needed if we're doing Dwarf2 unwinding. */
if (imask || fmask || alpha_ra_ever_killed ())
imask |= (1L << REG_RA);
*imaskP = imask;
*fmaskP = fmask;
......@@ -6043,10 +6045,8 @@ alpha_does_function_need_gp ()
if (TARGET_PROFILING_NEEDS_GP && current_function_profile)
return 1;
#ifdef ASM_OUTPUT_MI_THUNK
if (current_function_is_thunk)
return 1;
#endif
/* If we need a GP (we have a LDSYM insn or a CALL_INSN), load it first.
Even if we are a static function, we still need to do this in case
......@@ -6512,7 +6512,9 @@ alpha_start_function (file, fnname, decl)
/* If the function needs GP, we'll write the "..ng" label there.
Otherwise, do it here. */
if (TARGET_ABI_OSF && ! alpha_function_needs_gp)
if (TARGET_ABI_OSF
&& ! alpha_function_needs_gp
&& ! current_function_is_thunk)
{
putc ('$', file);
assemble_name (file, fnname);
......@@ -6646,7 +6648,8 @@ alpha_output_function_end_prologue (file)
else if (TARGET_ABI_WINDOWS_NT)
fputs ("\t.prologue 0\n", file);
else if (!flag_inhibit_size_directive)
fprintf (file, "\t.prologue %d\n", alpha_function_needs_gp);
fprintf (file, "\t.prologue %d\n",
alpha_function_needs_gp || current_function_is_thunk);
}
/* Write function epilogue. */
......@@ -6946,6 +6949,76 @@ alpha_end_function (file, fnname, decl)
unicosmk_output_deferred_case_vectors (file);
}
}
/* Emit a tail call to FUNCTION after adjusting THIS by DELTA.
In order to avoid the hordes of differences between generated code
with and without TARGET_EXPLICIT_RELOCS, and to avoid duplicating
lots of code loading up large constants, generate rtl and emit it
instead of going straight to text.
Not sure why this idea hasn't been explored before... */
void
alpha_output_mi_thunk_osf (file, thunk_fndecl, delta, function)
FILE *file;
tree thunk_fndecl ATTRIBUTE_UNUSED;
HOST_WIDE_INT delta;
tree function;
{
HOST_WIDE_INT hi, lo;
rtx this, insn, funexp;
/* We always require a valid GP. */
emit_insn (gen_prologue_ldgp ());
emit_note (NULL, NOTE_INSN_PROLOGUE_END);
/* Find the "this" pointer. If the function returns a structure,
the structure return pointer is in $16. */
if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function))))
this = gen_rtx_REG (Pmode, 17);
else
this = gen_rtx_REG (Pmode, 16);
/* Add DELTA. When possible we use ldah+lda. Otherwise load the
entire constant for the add. */
lo = ((delta & 0xffff) ^ 0x8000) - 0x8000;
hi = (((delta - lo) & 0xffffffff) ^ 0x80000000) - 0x80000000;
if (hi + lo == delta)
{
if (hi)
emit_insn (gen_adddi3 (this, this, GEN_INT (hi)));
if (lo)
emit_insn (gen_adddi3 (this, this, GEN_INT (lo)));
}
else
{
rtx tmp = alpha_emit_set_long_const (gen_rtx_REG (Pmode, 0),
delta, -(delta < 0));
emit_insn (gen_adddi3 (this, this, tmp));
}
/* Generate a tail call to the target function. */
if (! TREE_USED (function))
{
assemble_external (function);
TREE_USED (function) = 1;
}
funexp = XEXP (DECL_RTL (function), 0);
funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
insn = emit_call_insn (gen_sibcall (funexp, const0_rtx));
SIBLING_CALL_P (insn) = 1;
/* Run just enough of rest_of_compilation to get the insns emitted.
There's not really enough bulk here to make other passes such as
instruction scheduling worth while. Note that use_thunk calls
assemble_start_function and assemble_end_function. */
insn = get_insns ();
shorten_branches (insn);
final_start_function (insn, file, 1);
final (insn, file, 1, 0);
final_end_function ();
}
/* Debugging support. */
......
......@@ -2236,3 +2236,8 @@ do { \
/* Generate calls to memcpy, etc., not bcopy, etc. */
#define TARGET_MEM_FUNCTIONS 1
/* Output code to add DELTA to the first argument, and then jump to FUNCTION.
Used for C++ multiple inheritance. */
#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \
alpha_output_mi_thunk_osf (FILE, THUNK_FNDECL, DELTA, FUNCTION)
2002-02-04 Richard Henderson <rth@redhat.com>
* method.c (use_thunk): Always initialize the block tree. Reindent.
* semantics.c (expand_body): Emit thunks after function, not before.
2002-02-04 Jason Merrill <jason@redhat.com>
* decl.c (start_function): Call cplus_decl_attributes immediately
......
......@@ -392,6 +392,12 @@ use_thunk (thunk_fndecl, emit_p)
push_to_top_level ();
/* The back-end expects DECL_INITIAL to contain a BLOCK, so we
create one. */
DECL_INITIAL (thunk_fndecl) = make_node (BLOCK);
BLOCK_VARS (DECL_INITIAL (thunk_fndecl))
= DECL_ARGUMENTS (thunk_fndecl);
#ifdef ASM_OUTPUT_MI_THUNK
if (!vcall_offset)
{
......@@ -411,88 +417,83 @@ use_thunk (thunk_fndecl, emit_p)
}
else
#endif /* ASM_OUTPUT_MI_THUNK */
{
/* If we don't have the necessary macro for efficient thunks, generate a
thunk function that just makes a call to the real function.
Unfortunately, this doesn't work for varargs. */
tree a, t;
if (varargs_function_p (function))
error ("generic thunk code fails for method `%#D' which uses `...'",
function);
/* Set up clone argument trees for the thunk. */
t = NULL_TREE;
for (a = DECL_ARGUMENTS (function); a; a = TREE_CHAIN (a))
{
tree x = copy_node (a);
TREE_CHAIN (x) = t;
DECL_CONTEXT (x) = thunk_fndecl;
t = x;
}
a = nreverse (t);
DECL_ARGUMENTS (thunk_fndecl) = a;
DECL_RESULT (thunk_fndecl) = NULL_TREE;
start_function (NULL_TREE, thunk_fndecl, NULL_TREE, SF_PRE_PARSED);
/* We don't bother with a body block for thunks. */
/* Adjust the this pointer by the constant. */
t = ssize_int (delta);
t = fold (build (PLUS_EXPR, TREE_TYPE (a), a, t));
/* If there's a vcall offset, look up that value in the vtable and
adjust the `this' pointer again. */
if (vcall_offset && !integer_zerop (vcall_offset))
{
tree orig_this;
t = save_expr (t);
orig_this = t;
/* The vptr is always at offset zero in the object. */
t = build1 (NOP_EXPR,
build_pointer_type (build_pointer_type
(vtable_entry_type)),
t);
/* Form the vtable address. */
t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t);
/* Find the entry with the vcall offset. */
t = build (PLUS_EXPR, TREE_TYPE (t), t, vcall_offset);
/* Calculate the offset itself. */
t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t);
/* Adjust the `this' pointer. */
t = fold (build (PLUS_EXPR,
TREE_TYPE (orig_this),
orig_this,
t));
}
/* Build up the call to the real function. */
t = tree_cons (NULL_TREE, t, NULL_TREE);
for (a = TREE_CHAIN (a); a; a = TREE_CHAIN (a))
t = tree_cons (NULL_TREE, a, t);
t = nreverse (t);
t = build_call (function, t);
if (VOID_TYPE_P (TREE_TYPE (t)))
finish_expr_stmt (t);
else
finish_return_stmt (t);
{
/* If we don't have the necessary macro for efficient thunks, generate
a thunk function that just makes a call to the real function.
Unfortunately, this doesn't work for varargs. */
/* The back-end expects DECL_INITIAL to contain a BLOCK, so we
create one. */
DECL_INITIAL (thunk_fndecl) = make_node (BLOCK);
BLOCK_VARS (DECL_INITIAL (thunk_fndecl))
= DECL_ARGUMENTS (thunk_fndecl);
tree a, t;
/* Since we want to emit the thunk, we explicitly mark its name as
referenced. */
TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (thunk_fndecl)) = 1;
if (varargs_function_p (function))
error ("generic thunk code fails for method `%#D' which uses `...'",
function);
/* But we don't want debugging information about it. */
DECL_IGNORED_P (thunk_fndecl) = 1;
/* Set up clone argument trees for the thunk. */
t = NULL_TREE;
for (a = DECL_ARGUMENTS (function); a; a = TREE_CHAIN (a))
{
tree x = copy_node (a);
TREE_CHAIN (x) = t;
DECL_CONTEXT (x) = thunk_fndecl;
t = x;
}
a = nreverse (t);
DECL_ARGUMENTS (thunk_fndecl) = a;
DECL_RESULT (thunk_fndecl) = NULL_TREE;
expand_body (finish_function (0));
}
start_function (NULL_TREE, thunk_fndecl, NULL_TREE, SF_PRE_PARSED);
/* We don't bother with a body block for thunks. */
/* Adjust the this pointer by the constant. */
t = ssize_int (delta);
t = fold (build (PLUS_EXPR, TREE_TYPE (a), a, t));
/* If there's a vcall offset, look up that value in the vtable and
adjust the `this' pointer again. */
if (vcall_offset && !integer_zerop (vcall_offset))
{
tree orig_this;
t = save_expr (t);
orig_this = t;
/* The vptr is always at offset zero in the object. */
t = build1 (NOP_EXPR,
build_pointer_type (build_pointer_type
(vtable_entry_type)),
t);
/* Form the vtable address. */
t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t);
/* Find the entry with the vcall offset. */
t = build (PLUS_EXPR, TREE_TYPE (t), t, vcall_offset);
/* Calculate the offset itself. */
t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t);
/* Adjust the `this' pointer. */
t = fold (build (PLUS_EXPR,
TREE_TYPE (orig_this),
orig_this,
t));
}
/* Build up the call to the real function. */
t = tree_cons (NULL_TREE, t, NULL_TREE);
for (a = TREE_CHAIN (a); a; a = TREE_CHAIN (a))
t = tree_cons (NULL_TREE, a, t);
t = nreverse (t);
t = build_call (function, t);
if (VOID_TYPE_P (TREE_TYPE (t)))
finish_expr_stmt (t);
else
finish_return_stmt (t);
/* Since we want to emit the thunk, we explicitly mark its name as
referenced. */
TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (thunk_fndecl)) = 1;
/* But we don't want debugging information about it. */
DECL_IGNORED_P (thunk_fndecl) = 1;
expand_body (finish_function (0));
}
pop_from_top_level ();
}
......
......@@ -2397,9 +2397,6 @@ expand_body (fn)
if (DECL_EXTERNAL (fn))
return;
/* Emit any thunks that should be emitted at the same time as FN. */
emit_associated_thunks (fn);
timevar_push (TV_INTEGRATION);
/* Optimize the body of the function before expanding it. */
......@@ -2452,6 +2449,9 @@ expand_body (fn)
extract_interface_info ();
timevar_pop (TV_EXPAND);
/* Emit any thunks that should be emitted at the same time as FN. */
emit_associated_thunks (fn);
}
/* Helper function for walk_tree, used by finish_function to override all
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment