summaryrefslogtreecommitdiff
path: root/gcc/config/alpha/alpha.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/alpha/alpha.c')
-rw-r--r--gcc/config/alpha/alpha.c155
1 files changed, 114 insertions, 41 deletions
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. */