From 961d6dddc1e1fc6849f05063c44ec32efb864e91 Mon Sep 17 00:00:00 2001 From: rth Date: Mon, 4 Feb 2002 17:44:26 +0000 Subject: [PATCH] * 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@49484 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 12 +++ gcc/config/alpha/alpha-protos.h | 2 + gcc/config/alpha/alpha.c | 155 ++++++++++++++++++++++++++++----------- gcc/config/alpha/alpha.h | 5 ++ gcc/cp/ChangeLog | 5 ++ gcc/cp/method.c | 157 ++++++++++++++++++++-------------------- gcc/cp/semantics.c | 6 +- 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 + + * 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 * 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 + + * 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 * 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 -- 2.7.4