We use the stock (3.1) file.
This commit is contained in:
parent
d89ca98b1b
commit
1c7d68f037
@ -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);
|
||||
/* Don't re-split. */
|
||||
if (GET_CODE (x) == LO_SUM)
|
||||
return -1;
|
||||
|
||||
/* If this is an ldq_u type address, discard the outer AND. */
|
||||
if (GET_CODE (x) == AND)
|
||||
x = XEXP (x, 0);
|
||||
|
||||
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);
|
||||
|
||||
if (extra != 0)
|
||||
temp = expand_binop (mode, add_optab, temp, GEN_INT (extra << 16),
|
||||
subtarget, 0, OPTAB_WIDEN);
|
||||
/* 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. */
|
||||
|
||||
return expand_binop (mode, add_optab, temp, GEN_INT (low),
|
||||
target, 0, OPTAB_WIDEN);
|
||||
if (extra != 0)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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,44 +5931,49 @@ 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);
|
||||
|
||||
/* 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);
|
||||
*imaskP = 0;
|
||||
*fmaskP = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_STACK)
|
||||
imask |= (1L << HARD_FRAME_POINTER_REGNUM);
|
||||
|
||||
/* 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);
|
||||
|
||||
*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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user