summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--contrib/gcc/config/alpha/alpha.c469
1 files changed, 316 insertions, 153 deletions
diff --git a/contrib/gcc/config/alpha/alpha.c b/contrib/gcc/config/alpha/alpha.c
index 2320f1c..eb478e0 100644
--- a/contrib/gcc/config/alpha/alpha.c
+++ b/contrib/gcc/config/alpha/alpha.c
@@ -48,9 +48,7 @@ Boston, MA 02111-1307, USA. */
#include "tm_p.h"
#include "target.h"
#include "target-def.h"
-
-/* External data. */
-extern int rtx_equal_function_value_matters;
+#include "debug.h"
/* Specify which cpu to schedule for. */
@@ -118,9 +116,9 @@ int alpha_this_gpdisp_sequence_number;
/* Declarations of static functions. */
static bool decl_in_text_section
PARAMS ((tree));
-static int some_small_symbolic_mem_operand_1
+static int some_small_symbolic_operand_1
PARAMS ((rtx *, void *));
-static int split_small_symbolic_mem_operand_1
+static int split_small_symbolic_operand_1
PARAMS ((rtx *, void *));
static bool local_symbol_p
PARAMS ((rtx));
@@ -1876,61 +1874,55 @@ alpha_legitimize_address (x, scratch, mode)
so that sched2 has the proper dependency information. */
int
-some_small_symbolic_mem_operand (x, mode)
+some_small_symbolic_operand (x, mode)
rtx x;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
- return for_each_rtx (&x, some_small_symbolic_mem_operand_1, NULL);
+ return for_each_rtx (&x, some_small_symbolic_operand_1, NULL);
}
static int
-some_small_symbolic_mem_operand_1 (px, data)
+some_small_symbolic_operand_1 (px, data)
rtx *px;
void *data ATTRIBUTE_UNUSED;
{
rtx x = *px;
- if (GET_CODE (x) != MEM)
- return 0;
- x = XEXP (x, 0);
-
- /* If this is an ldq_u type address, discard the outer AND. */
- if (GET_CODE (x) == AND)
- x = XEXP (x, 0);
+ /* Don't re-split. */
+ if (GET_CODE (x) == LO_SUM)
+ return -1;
- return small_symbolic_operand (x, Pmode) ? 1 : -1;
+ return small_symbolic_operand (x, Pmode) != 0;
}
rtx
-split_small_symbolic_mem_operand (x)
+split_small_symbolic_operand (x)
rtx x;
{
x = copy_insn (x);
- for_each_rtx (&x, split_small_symbolic_mem_operand_1, NULL);
+ for_each_rtx (&x, split_small_symbolic_operand_1, NULL);
return x;
}
static int
-split_small_symbolic_mem_operand_1 (px, data)
+split_small_symbolic_operand_1 (px, data)
rtx *px;
void *data ATTRIBUTE_UNUSED;
{
rtx x = *px;
- if (GET_CODE (x) != MEM)
- return 0;
-
- px = &XEXP (x, 0), x = *px;
- if (GET_CODE (x) == AND)
- px = &XEXP (x, 0), x = *px;
+ /* Don't re-split. */
+ if (GET_CODE (x) == LO_SUM)
+ return -1;
if (small_symbolic_operand (x, Pmode))
{
x = gen_rtx_LO_SUM (Pmode, pic_offset_table_rtx, x);
*px = x;
+ return -1;
}
- return -1;
+ return 0;
}
/* Try a machine-dependent way of reloading an illegitimate address
@@ -2238,15 +2230,39 @@ alpha_emit_set_const (target, mode, c, n)
HOST_WIDE_INT c;
int n;
{
- rtx pat;
+ rtx result = 0;
+ rtx orig_target = target;
int i;
+ /* If we can't make any pseudos, TARGET is an SImode hard register, we
+ can't load this constant in one insn, do this in DImode. */
+ if (no_new_pseudos && mode == SImode
+ && GET_CODE (target) == REG && REGNO (target) < FIRST_PSEUDO_REGISTER
+ && (result = alpha_emit_set_const_1 (target, mode, c, 1)) == 0)
+ {
+ target = gen_lowpart (DImode, target);
+ mode = DImode;
+ }
+
/* Try 1 insn, then 2, then up to N. */
for (i = 1; i <= n; i++)
- if ((pat = alpha_emit_set_const_1 (target, mode, c, i)) != 0)
- return pat;
+ {
+ result = alpha_emit_set_const_1 (target, mode, c, i);
+ if (result)
+ {
+ rtx insn = get_last_insn ();
+ rtx set = single_set (insn);
+ if (! CONSTANT_P (SET_SRC (set)))
+ set_unique_reg_note (get_last_insn (), REG_EQUAL, GEN_INT (c));
+ break;
+ }
+ }
- return 0;
+ /* Allow for the case where we changed the mode of TARGET. */
+ if (result == target)
+ result = orig_target;
+
+ return result;
}
/* Internal routine for the above to check for N or below insns. */
@@ -2262,18 +2278,8 @@ alpha_emit_set_const_1 (target, mode, c, n)
int i, bits;
/* Use a pseudo if highly optimizing and still generating RTL. */
rtx subtarget
- = (flag_expensive_optimizations && rtx_equal_function_value_matters
- ? 0 : target);
- rtx temp;
-
-#if HOST_BITS_PER_WIDE_INT == 64
- /* We are only called for SImode and DImode. If this is SImode, ensure that
- we are sign extended to a full word. This does not make any sense when
- cross-compiling on a narrow machine. */
-
- if (mode == SImode)
- c = ((c & 0xffffffff) ^ 0x80000000) - 0x80000000;
-#endif
+ = (flag_expensive_optimizations && !no_new_pseudos ? 0 : target);
+ rtx temp, insn;
/* If this is a sign-extended 32-bit constant, we can do this in at most
three insns, so do it if we have enough insns left. We always have
@@ -2314,12 +2320,28 @@ alpha_emit_set_const_1 (target, mode, c, n)
{
temp = copy_to_suggested_reg (GEN_INT (high << 16), subtarget, mode);
+ /* As of 2002-02-23, addsi3 is only available when not optimizing.
+ This means that if we go through expand_binop, we'll try to
+ generate extensions, etc, which will require new pseudos, which
+ will fail during some split phases. The SImode add patterns
+ still exist, but are not named. So build the insns by hand. */
+
if (extra != 0)
- temp = expand_binop (mode, add_optab, temp, GEN_INT (extra << 16),
- subtarget, 0, OPTAB_WIDEN);
+ {
+ if (! subtarget)
+ subtarget = gen_reg_rtx (mode);
+ insn = gen_rtx_PLUS (mode, temp, GEN_INT (extra << 16));
+ insn = gen_rtx_SET (VOIDmode, subtarget, insn);
+ emit_insn (insn);
+ temp = subtarget;
+ }
- return expand_binop (mode, add_optab, temp, GEN_INT (low),
- target, 0, OPTAB_WIDEN);
+ if (target == NULL)
+ target = gen_reg_rtx (mode);
+ insn = gen_rtx_PLUS (mode, temp, GEN_INT (low));
+ insn = gen_rtx_SET (VOIDmode, target, insn);
+ emit_insn (insn);
+ return target;
}
}
@@ -2328,8 +2350,7 @@ alpha_emit_set_const_1 (target, mode, c, n)
we can't make pseudos, we can't do anything since the expand_binop
and expand_unop calls will widen and try to make pseudos. */
- if (n == 1
- || (mode == SImode && ! rtx_equal_function_value_matters))
+ if (n == 1 || (mode == SImode && no_new_pseudos))
return 0;
/* Next, see if we can load a related constant and then shift and possibly
@@ -2510,7 +2531,26 @@ alpha_expand_mov (mode, operands)
/* Allow legitimize_address to perform some simplifications. */
if (mode == Pmode && symbolic_operand (operands[1], mode))
{
- rtx tmp = alpha_legitimize_address (operands[1], operands[0], mode);
+ rtx tmp;
+
+ /* With RTL inlining, at -O3, rtl is generated, stored, then actually
+ compiled at the end of compilation. In the meantime, someone can
+ re-encode-section-info on some symbol changing it e.g. from global
+ to local-not-small. If this happens, we'd have emitted a plain
+ load rather than a high+losum load and not recognize the insn.
+
+ So if rtl inlining is in effect, we delay the global/not-global
+ decision until rest_of_compilation by wrapping it in an
+ UNSPEC_SYMBOL. */
+ if (TARGET_EXPLICIT_RELOCS && flag_inline_functions
+ && rtx_equal_function_value_matters
+ && global_symbolic_operand (operands[1], mode))
+ {
+ emit_insn (gen_movdi_er_maybe_g (operands[0], operands[1]));
+ return true;
+ }
+
+ tmp = alpha_legitimize_address (operands[1], operands[0], mode);
if (tmp)
{
operands[1] = tmp;
@@ -2786,21 +2826,29 @@ alpha_emit_conditional_branch (code)
1 true
Convert the compare against the raw return value. */
- if (code == UNORDERED || code == ORDERED)
- cmp_code = EQ;
- else
- cmp_code = code;
+ switch (code)
+ {
+ case UNORDERED:
+ cmp_code = EQ;
+ code = LT;
+ break;
+ case ORDERED:
+ cmp_code = EQ;
+ code = GE;
+ break;
+ case NE:
+ cmp_code = NE;
+ code = NE;
+ break;
+ default:
+ cmp_code = code;
+ code = GT;
+ break;
+ }
op0 = alpha_emit_xfloating_compare (cmp_code, op0, op1);
op1 = const0_rtx;
alpha_compare.fp_p = 0;
-
- if (code == UNORDERED)
- code = LT;
- else if (code == ORDERED)
- code = GE;
- else
- code = GT;
}
/* The general case: fold the comparison code to the types of compares
@@ -4987,7 +5035,10 @@ alpha_return_addr (count, frame)
rtx
alpha_gp_save_rtx ()
{
- return get_hard_reg_initial_val (DImode, 29);
+ rtx r = get_hard_reg_initial_val (DImode, 29);
+ if (GET_CODE (r) != MEM)
+ r = gen_mem_addressof (r, NULL_TREE);
+ return r;
}
static int
@@ -4995,10 +5046,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];
@@ -5514,12 +5561,13 @@ alpha_initialize_trampoline (tramp, fnaddr, cxt, fnofs, cxtofs, jmpofs)
OPTAB_WIDEN);
temp = expand_shift (RSHIFT_EXPR, Pmode, temp,
build_int_2 (2, 0), NULL_RTX, 1);
- temp = expand_and (gen_lowpart (SImode, temp), GEN_INT (0x3fff), 0);
+ temp = expand_and (SImode, gen_lowpart (SImode, temp),
+ GEN_INT (0x3fff), 0);
/* Merge in the hint. */
addr = memory_address (SImode, plus_constant (tramp, jmpofs));
temp1 = force_reg (SImode, gen_rtx_MEM (SImode, addr));
- temp1 = expand_and (temp1, GEN_INT (0xffffc000), NULL_RTX);
+ temp1 = expand_and (SImode, temp1, GEN_INT (0xffffc000), NULL_RTX);
temp1 = expand_binop (SImode, ior_optab, temp1, temp, temp1, 1,
OPTAB_WIDEN);
emit_move_insn (gen_rtx_MEM (SImode, addr), temp1);
@@ -5761,9 +5809,8 @@ rtx
alpha_va_arg (valist, type)
tree valist, type;
{
- HOST_WIDE_INT tsize;
rtx addr;
- tree t;
+ tree t, type_size, rounded_size;
tree offset_field, base_field, addr_tree, addend;
tree wide_type, wide_ofs;
int indirect = 0;
@@ -5771,7 +5818,18 @@ alpha_va_arg (valist, type)
if (TARGET_ABI_OPEN_VMS || TARGET_ABI_UNICOSMK)
return std_expand_builtin_va_arg (valist, type);
- tsize = ((TREE_INT_CST_LOW (TYPE_SIZE (type)) / BITS_PER_UNIT + 7) / 8) * 8;
+ if (type == error_mark_node
+ || (type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type))) == NULL
+ || TREE_OVERFLOW (type_size))
+ rounded_size = size_zero_node;
+ else
+ rounded_size = fold (build (MULT_EXPR, sizetype,
+ fold (build (TRUNC_DIV_EXPR, sizetype,
+ fold (build (PLUS_EXPR, sizetype,
+ type_size,
+ size_int (7))),
+ size_int (8))),
+ size_int (8)));
base_field = TYPE_FIELDS (TREE_TYPE (valist));
offset_field = TREE_CHAIN (base_field);
@@ -5781,6 +5839,17 @@ alpha_va_arg (valist, type)
offset_field = build (COMPONENT_REF, TREE_TYPE (offset_field),
valist, offset_field);
+ /* If the type could not be passed in registers, skip the block
+ reserved for the registers. */
+ if (MUST_PASS_IN_STACK (TYPE_MODE (type), type))
+ {
+ t = build (MODIFY_EXPR, TREE_TYPE (offset_field), offset_field,
+ build (MAX_EXPR, TREE_TYPE (offset_field),
+ offset_field, build_int_2 (6*8, 0)));
+ TREE_SIDE_EFFECTS (t) = 1;
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ }
+
wide_type = make_signed_type (64);
wide_ofs = save_expr (build1 (CONVERT_EXPR, wide_type, offset_field));
@@ -5789,7 +5858,7 @@ alpha_va_arg (valist, type)
if (TYPE_MODE (type) == TFmode || TYPE_MODE (type) == TCmode)
{
indirect = 1;
- tsize = UNITS_PER_WORD;
+ rounded_size = size_int (UNITS_PER_WORD);
}
else if (FLOAT_TYPE_P (type))
{
@@ -5813,7 +5882,7 @@ alpha_va_arg (valist, type)
t = build (MODIFY_EXPR, TREE_TYPE (offset_field), offset_field,
build (PLUS_EXPR, TREE_TYPE (offset_field),
- offset_field, build_int_2 (tsize, 0)));
+ offset_field, rounded_size));
TREE_SIDE_EFFECTS (t) = 1;
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -5837,7 +5906,8 @@ alpha_va_arg (valist, type)
descriptior to generate. */
/* Nonzero if we need a stack procedure. */
-static int alpha_is_stack_procedure;
+enum alpha_procedure_types {PT_NULL = 0, PT_REGISTER = 1, PT_STACK = 2};
+static enum alpha_procedure_types alpha_procedure_type;
/* Register number (either FP or SP) that is used to unwind the frame. */
static int vms_unwind_regno;
@@ -5861,43 +5931,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 && !no_new_pseudos)
{
- 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_procedure_type == PT_STACK)
+ 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;
@@ -5933,17 +6008,16 @@ alpha_sa_size ()
use alloca and have not determined that we need a frame for other
reasons. */
- alpha_is_stack_procedure = (sa_size
- || get_frame_size() != 0
- || current_function_outgoing_args_size
- || current_function_varargs
- || current_function_stdarg
- || current_function_calls_alloca
- || frame_pointer_needed);
+ alpha_procedure_type
+ = (sa_size || get_frame_size() != 0
+ || current_function_outgoing_args_size || current_function_varargs
+ || current_function_stdarg || current_function_calls_alloca
+ || frame_pointer_needed)
+ ? PT_STACK : PT_REGISTER;
/* Always reserve space for saving callee-saved registers if we
need a frame as required by the calling convention. */
- if (alpha_is_stack_procedure)
+ if (alpha_procedure_type == PT_STACK)
sa_size = 14;
}
else if (TARGET_ABI_OPEN_VMS)
@@ -5951,22 +6025,29 @@ alpha_sa_size ()
/* Start by assuming we can use a register procedure if we don't
make any calls (REG_RA not used) or need to save any
registers and a stack procedure if we do. */
- alpha_is_stack_procedure = ((mask[0] >> REG_RA) & 1);
+ if ((mask[0] >> REG_RA) & 1)
+ alpha_procedure_type = PT_STACK;
+ else if (get_frame_size() != 0)
+ alpha_procedure_type = PT_REGISTER;
+ else
+ alpha_procedure_type = PT_NULL;
- /* Don't reserve space for saving RA yet. Do that later after we've
+ /* Don't reserve space for saving FP & RA yet. Do that later after we've
made the final decision on stack procedure vs register procedure. */
- if (alpha_is_stack_procedure)
- sa_size--;
+ if (alpha_procedure_type == PT_STACK)
+ sa_size -= 2;
/* Decide whether to refer to objects off our PV via FP or PV.
If we need FP for something else or if we receive a nonlocal
goto (which expects PV to contain the value), we must use PV.
Otherwise, start by assuming we can use FP. */
- vms_base_regno = (frame_pointer_needed
- || current_function_has_nonlocal_label
- || alpha_is_stack_procedure
- || current_function_outgoing_args_size
- ? REG_PV : HARD_FRAME_POINTER_REGNUM);
+
+ vms_base_regno
+ = (frame_pointer_needed
+ || current_function_has_nonlocal_label
+ || alpha_procedure_type == PT_STACK
+ || current_function_outgoing_args_size)
+ ? REG_PV : HARD_FRAME_POINTER_REGNUM;
/* If we want to copy PV into FP, we need to find some register
in which to save FP. */
@@ -5977,15 +6058,17 @@ alpha_sa_size ()
if (! fixed_regs[i] && call_used_regs[i] && ! regs_ever_live[i])
vms_save_fp_regno = i;
- if (vms_save_fp_regno == -1)
- vms_base_regno = REG_PV, alpha_is_stack_procedure = 1;
+ if (vms_save_fp_regno == -1 && alpha_procedure_type == PT_REGISTER)
+ vms_base_regno = REG_PV, alpha_procedure_type = PT_STACK;
+ else if (alpha_procedure_type == PT_NULL)
+ vms_base_regno = REG_PV;
/* Stack unwinding should be done via FP unless we use it for PV. */
vms_unwind_regno = (vms_base_regno == REG_PV
? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
/* If this is a stack procedure, allow space for saving FP and RA. */
- if (alpha_is_stack_procedure)
+ if (alpha_procedure_type == PT_STACK)
sa_size += 2;
}
else
@@ -6002,7 +6085,7 @@ int
alpha_pv_save_size ()
{
alpha_sa_size ();
- return alpha_is_stack_procedure ? 8 : 0;
+ return alpha_procedure_type == PT_STACK ? 8 : 0;
}
int
@@ -6045,10 +6128,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
@@ -6153,13 +6234,13 @@ alpha_expand_prologue ()
frame_size = get_frame_size ();
if (TARGET_ABI_OPEN_VMS)
frame_size = ALPHA_ROUND (sa_size
- + (alpha_is_stack_procedure ? 8 : 0)
+ + (alpha_procedure_type == PT_STACK ? 8 : 0)
+ frame_size
+ current_function_pretend_args_size);
else if (TARGET_ABI_UNICOSMK)
/* We have to allocate space for the DSIB if we generate a frame. */
frame_size = ALPHA_ROUND (sa_size
- + (alpha_is_stack_procedure ? 48 : 0))
+ + (alpha_procedure_type == PT_STACK ? 48 : 0))
+ ALPHA_ROUND (frame_size
+ current_function_outgoing_args_size);
else
@@ -6314,7 +6395,7 @@ alpha_expand_prologue ()
}
/* Save regs in stack order. Beginning with VMS PV. */
- if (TARGET_ABI_OPEN_VMS && alpha_is_stack_procedure)
+ if (TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_STACK)
{
mem = gen_rtx_MEM (DImode, stack_pointer_rtx);
set_mem_alias_set (mem, alpha_sr_alias_set);
@@ -6350,7 +6431,7 @@ alpha_expand_prologue ()
reg_offset += 8;
}
}
- else if (TARGET_ABI_UNICOSMK && alpha_is_stack_procedure)
+ else if (TARGET_ABI_UNICOSMK && alpha_procedure_type == PT_STACK)
{
/* The standard frame on the T3E includes space for saving registers.
We just have to use it. We don't have to save the return address and
@@ -6379,17 +6460,18 @@ alpha_expand_prologue ()
if (TARGET_ABI_OPEN_VMS)
{
- if (!alpha_is_stack_procedure)
- /* Register frame procedures save the fp. */
- /* ??? Ought to have a dwarf2 save for this. */
+ if (alpha_procedure_type == PT_REGISTER)
+ /* Register frame procedures save the fp.
+ ?? Ought to have a dwarf2 save for this. */
emit_move_insn (gen_rtx_REG (DImode, vms_save_fp_regno),
hard_frame_pointer_rtx);
- if (vms_base_regno != REG_PV)
+ if (alpha_procedure_type != PT_NULL && vms_base_regno != REG_PV)
emit_insn (gen_force_movdi (gen_rtx_REG (DImode, vms_base_regno),
gen_rtx_REG (DImode, REG_PV)));
- if (vms_unwind_regno == HARD_FRAME_POINTER_REGNUM)
+ if (alpha_procedure_type != PT_NULL
+ && vms_unwind_regno == HARD_FRAME_POINTER_REGNUM)
FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
/* If we have to allocate space for outgoing args, do it now. */
@@ -6462,12 +6544,12 @@ alpha_start_function (file, fnname, decl)
frame_size = get_frame_size ();
if (TARGET_ABI_OPEN_VMS)
frame_size = ALPHA_ROUND (sa_size
- + (alpha_is_stack_procedure ? 8 : 0)
+ + (alpha_procedure_type == PT_STACK ? 8 : 0)
+ frame_size
+ current_function_pretend_args_size);
else if (TARGET_ABI_UNICOSMK)
frame_size = ALPHA_ROUND (sa_size
- + (alpha_is_stack_procedure ? 48 : 0))
+ + (alpha_procedure_type == PT_STACK ? 48 : 0))
+ ALPHA_ROUND (frame_size
+ current_function_outgoing_args_size);
else
@@ -6514,7 +6596,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);
@@ -6585,7 +6669,7 @@ alpha_start_function (file, fnname, decl)
fprintf (file, "\t.mask 0x%lx,0\n", imask & ~(1L << REG_RA));
if (fmask)
fprintf (file, "\t.fmask 0x%lx,0\n", fmask);
- if (!alpha_is_stack_procedure)
+ if (alpha_procedure_type == PT_REGISTER)
fprintf (file, "\t.fp_save $%d\n", vms_save_fp_regno);
}
else if (!flag_inhibit_size_directive)
@@ -6629,7 +6713,9 @@ alpha_start_function (file, fnname, decl)
ASM_OUTPUT_LABEL (file, fnname);
fprintf (file, "\t.pdesc ");
assemble_name (file, fnname);
- fprintf (file, "..en,%s\n", alpha_is_stack_procedure ? "stack" : "reg");
+ fprintf (file, "..en,%s\n",
+ alpha_procedure_type == PT_STACK ? "stack"
+ : alpha_procedure_type == PT_REGISTER ? "reg" : "null");
alpha_need_linkage (fnname, 1);
text_section ();
#endif
@@ -6648,7 +6734,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. */
@@ -6682,12 +6769,12 @@ alpha_expand_epilogue ()
frame_size = get_frame_size ();
if (TARGET_ABI_OPEN_VMS)
frame_size = ALPHA_ROUND (sa_size
- + (alpha_is_stack_procedure ? 8 : 0)
+ + (alpha_procedure_type == PT_STACK ? 8 : 0)
+ frame_size
+ current_function_pretend_args_size);
else if (TARGET_ABI_UNICOSMK)
frame_size = ALPHA_ROUND (sa_size
- + (alpha_is_stack_procedure ? 48 : 0))
+ + (alpha_procedure_type == PT_STACK ? 48 : 0))
+ ALPHA_ROUND (frame_size
+ current_function_outgoing_args_size);
else
@@ -6697,14 +6784,20 @@ alpha_expand_epilogue ()
+ current_function_pretend_args_size));
if (TARGET_ABI_OPEN_VMS)
- reg_offset = 8;
+ {
+ if (alpha_procedure_type == PT_STACK)
+ reg_offset = 8;
+ else
+ reg_offset = 0;
+ }
else
reg_offset = ALPHA_ROUND (current_function_outgoing_args_size);
alpha_sa_mask (&imask, &fmask);
- fp_is_frame_pointer = ((TARGET_ABI_OPEN_VMS && alpha_is_stack_procedure)
- || (!TARGET_ABI_OPEN_VMS && frame_pointer_needed));
+ fp_is_frame_pointer
+ = ((TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_STACK)
+ || (!TARGET_ABI_OPEN_VMS && frame_pointer_needed));
fp_offset = 0;
sa_reg = stack_pointer_rtx;
@@ -6771,7 +6864,7 @@ alpha_expand_epilogue ()
reg_offset += 8;
}
}
- else if (TARGET_ABI_UNICOSMK && alpha_is_stack_procedure)
+ else if (TARGET_ABI_UNICOSMK && alpha_procedure_type == PT_STACK)
{
/* Restore callee-saved general-purpose registers. */
@@ -6891,13 +6984,13 @@ alpha_expand_epilogue ()
}
else
{
- if (TARGET_ABI_OPEN_VMS && !alpha_is_stack_procedure)
+ if (TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_REGISTER)
{
emit_insn (gen_blockage ());
FRP (emit_move_insn (hard_frame_pointer_rtx,
gen_rtx_REG (DImode, vms_save_fp_regno)));
}
- else if (TARGET_ABI_UNICOSMK && !alpha_is_stack_procedure)
+ else if (TARGET_ABI_UNICOSMK && alpha_procedure_type != PT_STACK)
{
/* Decrement the frame pointer if the function does not have a
frame. */
@@ -6948,6 +7041,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. */
@@ -8630,7 +8793,7 @@ static void
unicosmk_gen_dsib (imaskP)
unsigned long * imaskP;
{
- if (alpha_is_stack_procedure)
+ if (alpha_procedure_type == PT_STACK)
{
const char *ssib_name;
rtx mem;
OpenPOWER on IntegriCloud