aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Henderson <rth@redhat.com>2002-02-04 09:44:26 -0800
committerRichard Henderson <rth@gcc.gnu.org>2002-02-04 09:44:26 -0800
commit14691f8d24c7971bd09d3263a96758574946a6e5 (patch)
tree00e69406554780de155cc3cfc05ce57cf2a19f1f /gcc
parent8d9d2e1df75bbf81c68ea846d27dbfb53a309488 (diff)
downloadgcc-14691f8d24c7971bd09d3263a96758574946a6e5.zip
gcc-14691f8d24c7971bd09d3263a96758574946a6e5.tar.gz
gcc-14691f8d24c7971bd09d3263a96758574946a6e5.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog12
-rw-r--r--gcc/config/alpha/alpha-protos.h2
-rw-r--r--gcc/config/alpha/alpha.c155
-rw-r--r--gcc/config/alpha/alpha.h5
-rw-r--r--gcc/cp/ChangeLog5
-rw-r--r--gcc/cp/method.c157
-rw-r--r--gcc/cp/semantics.c6
7 files changed, 220 insertions, 122 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 102e0ab..919a408 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,15 @@
+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
diff --git a/gcc/config/alpha/alpha-protos.h b/gcc/config/alpha/alpha-protos.h
index 2ff0350..957e5d9 100644
--- a/gcc/config/alpha/alpha-protos.h
+++ b/gcc/config/alpha/alpha-protos.h
@@ -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 */
diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c
index 0a1be01..9897077 100644
--- a/gcc/config/alpha/alpha.c
+++ b/gcc/config/alpha/alpha.c
@@ -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. */
diff --git a/gcc/config/alpha/alpha.h b/gcc/config/alpha/alpha.h
index 4e676f2..99ef24e 100644
--- a/gcc/config/alpha/alpha.h
+++ b/gcc/config/alpha/alpha.h
@@ -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)
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 6179739..dfb3d4b 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,8 @@
+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
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index b0cc63a..52a6a8c 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -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 ();
}
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 7ac47a1..cdc1178 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -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