diff options
author | rth <rth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2002-02-04 17:44:26 +0000 |
---|---|---|
committer | rth <rth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2002-02-04 17:44:26 +0000 |
commit | 961d6dddc1e1fc6849f05063c44ec32efb864e91 (patch) | |
tree | 00e69406554780de155cc3cfc05ce57cf2a19f1f /gcc/config/alpha | |
parent | 555168031f0b1f01983ae80245c5ee24d61865d9 (diff) | |
download | gcc-961d6dddc1e1fc6849f05063c44ec32efb864e91.tar.gz |
* 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
Diffstat (limited to 'gcc/config/alpha')
-rw-r--r-- | gcc/config/alpha/alpha-protos.h | 2 | ||||
-rw-r--r-- | gcc/config/alpha/alpha.c | 155 | ||||
-rw-r--r-- | gcc/config/alpha/alpha.h | 5 |
3 files changed, 121 insertions, 41 deletions
diff --git a/gcc/config/alpha/alpha-protos.h b/gcc/config/alpha/alpha-protos.h index 2ff035092f2..957e5d9c773 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 0a1be015c3a..9897077664f 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 4e676f2da59..99ef24ea976 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) |