Commit 957ec0f9 by Hans-Peter Nilsson Committed by Hans-Peter Nilsson

Emit MMIX function prologue and epilogue as rtl.

	* config/mmix/mmix.md ("call"): Use mmix_get_hard_reg_initial_val,
	not unprototyped get_hard_reg_initial_val.
	("call_value", "nonlocal_goto_receiver"): Ditto.
	("return"): Make define_expand.  Move real insn to...
	("*expanded_return"): New pattern.
	("prologue", "epilogue"): New define_expands.
	* config/mmix/mmix.h (MMIX_rO_REGNUM): New macro.
	(struct machine_function): New member in_prologue.
	(FIRST_PSEUDO_REGISTER): Adjust for including rO as register.
	(FIXED_REGISTERS, CALL_USED_REGISTERS): Ditto.
	(MMIX_MMIXWARE_ABI_REG_ALLOC_ORDER): Ditto.
	(MMIX_GNU_ABI_REG_ALLOC_ORDER, REG_CLASS_CONTENTS): Ditto.
	(REGISTER_NAMES, ADDITIONAL_REGISTER_NAMES): Ditto.
	(LOCAL_REGNO): Define.  Adjust comment.
	* config/mmix/mmix.c (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS):
	Consider regs_ever_live[MMIX_rJ_REGNUM], not just
	leaf_function_p.
	(MMIX_OUTPUT_REGNO): Don't translate registers while outputting
	the prologue.
	(mmix_target_asm_function_prologue): Make static.  Just mark that
	the prologue is being emitted.  Move guts to...
	(mmix_expand_prologue): New function.  Adjust for emitting
	prologue as rtl.  For sizes, use HOST_WIDE_INT only.
	(mmix_target_asm_function_epilogue): Make static.  Simply emit a
	\n.  Move guts to...
	(mmix_expand_epilogue): New function.  Adjust for emitting
	epilogue as rtl.  For sizes, use HOST_WIDE_INT only.
	(mmix_target_asm_function_end_prologue): Mark that the prologue
	has ended.
	(TARGET_ASM_FUNCTION_END_PROLOGUE): Define.
	(mmix_conditional_register_usage): Improve comments.
	(mmix_local_regno): New function.
	(mmix_emit_sp_add, mmix_get_hard_reg_initial_val): Ditto.
	* config/mmix/mmix-protos.h (mmix_local_regno): Prototype.
	(mmix_expand_prologue, mmix_expand_epilogue): Ditto.
	(mmix_get_hard_reg_initial_val): Ditto.

From-SVN: r55302
parent 276e31ec
2002-07-07 Hans-Peter Nilsson <hp@bitrange.com>
Emit MMIX function prologue and epilogue as rtl.
* config/mmix/mmix.md ("call"): Use mmix_get_hard_reg_initial_val,
not unprototyped get_hard_reg_initial_val.
("call_value", "nonlocal_goto_receiver"): Ditto.
("return"): Make define_expand. Move real insn to...
("*expanded_return"): New pattern.
("prologue", "epilogue"): New define_expands.
* config/mmix/mmix.h (MMIX_rO_REGNUM): New macro.
(struct machine_function): New member in_prologue.
(FIRST_PSEUDO_REGISTER): Adjust for including rO as register.
(FIXED_REGISTERS, CALL_USED_REGISTERS): Ditto.
(MMIX_MMIXWARE_ABI_REG_ALLOC_ORDER): Ditto.
(MMIX_GNU_ABI_REG_ALLOC_ORDER, REG_CLASS_CONTENTS): Ditto.
(REGISTER_NAMES, ADDITIONAL_REGISTER_NAMES): Ditto.
(LOCAL_REGNO): Define. Adjust comment.
* config/mmix/mmix.c (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS):
Consider regs_ever_live[MMIX_rJ_REGNUM], not just
leaf_function_p.
(MMIX_OUTPUT_REGNO): Don't translate registers while outputting
the prologue.
(mmix_target_asm_function_prologue): Make static. Just mark that
the prologue is being emitted. Move guts to...
(mmix_expand_prologue): New function. Adjust for emitting
prologue as rtl. For sizes, use HOST_WIDE_INT only.
(mmix_target_asm_function_epilogue): Make static. Simply emit a
\n. Move guts to...
(mmix_expand_epilogue): New function. Adjust for emitting
epilogue as rtl. For sizes, use HOST_WIDE_INT only.
(mmix_target_asm_function_end_prologue): Mark that the prologue
has ended.
(TARGET_ASM_FUNCTION_END_PROLOGUE): Define.
(mmix_conditional_register_usage): Improve comments.
(mmix_local_regno): New function.
(mmix_emit_sp_add, mmix_get_hard_reg_initial_val): Ditto.
* config/mmix/mmix-protos.h (mmix_local_regno): Prototype.
(mmix_expand_prologue, mmix_expand_epilogue): Ditto.
(mmix_get_hard_reg_initial_val): Ditto.
2002-07-06 Andreas Jaeger <aj@suse.de>
* toplev.c (set_fast_math_flags): Don't use ISO C style function
......
......@@ -57,6 +57,7 @@ extern int mmix_shiftable_wyde_value PARAMS ((unsigned HOST_WIDEST_INT));
extern void mmix_output_register_setting
PARAMS ((FILE *, int, HOST_WIDEST_INT, int));
extern void mmix_conditional_register_usage PARAMS ((void));
extern int mmix_local_regno PARAMS ((int));
extern int mmix_dbx_register_number PARAMS ((int));
/* Things that need rtl.h, tree.h or real.h included, or in combination. */
......@@ -123,6 +124,9 @@ extern void mmix_print_operand_address PARAMS ((FILE *, rtx));
extern int mmix_valid_comparison PARAMS ((RTX_CODE, enum machine_mode, rtx));
extern rtx mmix_gen_compare_reg PARAMS ((enum rtx_code, rtx, rtx));
extern void mmix_machine_dependent_reorg PARAMS ((rtx));
extern void mmix_expand_prologue PARAMS ((void));
extern void mmix_expand_epilogue PARAMS ((void));
extern rtx mmix_get_hard_reg_initial_val PARAMS ((enum machine_mode, int));
#endif /* RTX_CODE */
extern int mmix_asm_preferred_eh_data_format PARAMS ((int, int));
......
......@@ -52,9 +52,19 @@ Boston, MA 02111-1307, USA. */
/* We have no means to tell DWARF 2 about the register stack, so we need
to store the return address on the stack if an exception can get into
this function. FIXME: Narrow condition. */
#define MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS \
(flag_exceptions && ! leaf_function_p ())
this function. FIXME: Narrow condition. Before any whole-function
analysis, regs_ever_live[] isn't initialized. We know it's up-to-date
after reload_completed; it may contain incorrect information some time
before that. Within a RTL sequence (after a call to start_sequence,
such as in RTL expanders), leaf_function_p doesn't see all insns
(perhaps any insn). But regs_ever_live is up-to-date when
leaf_function_p () isn't, so we "or" them together to get accurate
information. FIXME: Some tweak to leaf_function_p might be
preferrable. */
#define MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS \
(flag_exceptions \
&& ((reload_completed && regs_ever_live[MMIX_rJ_REGNUM]) \
|| !leaf_function_p ()))
#define IS_MMIX_EH_RETURN_DATA_REG(REGNO) \
(current_function_calls_eh_return \
......@@ -68,11 +78,15 @@ Boston, MA 02111-1307, USA. */
registers. In effect this makes unused call-saved registers to be used
as call-clobbered registers. The benefit comes from keeping the number
of local registers (value of rL) low, since there's a cost of
increasing rL and clearing unused (unset) registers with lower numbers. */
increasing rL and clearing unused (unset) registers with lower numbers.
Don't translate while outputting the prologue. */
#define MMIX_OUTPUT_REGNO(N) \
(TARGET_ABI_GNU \
|| (int) (N) < MMIX_RETURN_VALUE_REGNUM \
|| (int) (N) > MMIX_LAST_STACK_REGISTER_REGNUM \
|| cfun == NULL \
|| cfun->machine == NULL \
|| cfun->machine->in_prologue \
? (N) : ((N) - MMIX_RETURN_VALUE_REGNUM \
+ cfun->machine->highest_saved_stack_register + 1))
......@@ -110,10 +124,11 @@ static bool mmix_assemble_integer PARAMS ((rtx, unsigned int, int));
static struct machine_function * mmix_init_machine_status PARAMS ((void));
static void mmix_encode_section_info PARAMS ((tree, int));
static const char *mmix_strip_name_encoding PARAMS ((const char *));
extern void mmix_target_asm_function_prologue
static void mmix_emit_sp_add PARAMS ((HOST_WIDE_INT offset));
static void mmix_target_asm_function_prologue
PARAMS ((FILE *, HOST_WIDE_INT));
extern void mmix_target_asm_function_epilogue
static void mmix_target_asm_function_end_prologue PARAMS ((FILE *));
static void mmix_target_asm_function_epilogue
PARAMS ((FILE *, HOST_WIDE_INT));
......@@ -136,6 +151,9 @@ extern void mmix_target_asm_function_epilogue
#undef TARGET_ASM_FUNCTION_PROLOGUE
#define TARGET_ASM_FUNCTION_PROLOGUE mmix_target_asm_function_prologue
#undef TARGET_ASM_FUNCTION_END_PROLOGUE
#define TARGET_ASM_FUNCTION_END_PROLOGUE mmix_target_asm_function_end_prologue
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE mmix_target_asm_function_epilogue
......@@ -241,11 +259,11 @@ mmix_conditional_register_usage ()
/* Change the default from the mmixware ABI. For the GNU ABI,
$15..$30 are call-saved just as $0..$14. There must be one
call-clobbered local register for the "hole" describing number of
saved local registers saved by PUSHJ/PUSHGO during the function
call, receiving the return value at return. So best is to use
the highest, $31. It's already marked call-clobbered for the
mmixware ABI. */
call-clobbered local register for the "hole" that holds the
number of saved local registers saved by PUSHJ/PUSHGO during the
function call, receiving the return value at return. So best is
to use the highest, $31. It's already marked call-clobbered for
the mmixware ABI. */
for (i = 15; i <= 30; i++)
call_used_regs[i] = 0;
......@@ -263,6 +281,17 @@ mmix_conditional_register_usage ()
reg_names[i]++;
}
/* LOCAL_REGNO.
All registers that are part of the register stack and that will be
saved are local. */
int
mmix_local_regno (regno)
int regno;
{
return regno <= MMIX_LAST_STACK_REGISTER_REGNUM && !call_used_regs[regno];
}
/* PREFERRED_RELOAD_CLASS.
We need to extend the reload class of REMAINDER_REG and HIMULT_REG. */
......@@ -672,335 +701,25 @@ mmix_asm_preferred_eh_data_format (code, global)
return DW_EH_PE_absptr;
}
/* Emit the function prologue. For simplicity while the port is still
in a flux, we do it as text rather than the now preferred RTL way,
as (define_insn "function_prologue").
/* Make a note that we've seen the beginning of of the prologue. This
matters to whether we'll translate register numbers as calculated by
mmix_machine_dependent_reorg. */
FIXME: Translate to RTL and/or optimize some of the DWARF 2 stuff. */
void
mmix_target_asm_function_prologue (stream, locals_size)
FILE *stream;
HOST_WIDE_INT locals_size;
static void
mmix_target_asm_function_prologue (stream, framesize)
FILE *stream ATTRIBUTE_UNUSED;
HOST_WIDE_INT framesize ATTRIBUTE_UNUSED;
{
int regno;
int stack_space_to_allocate
= (current_function_outgoing_args_size
+ current_function_pretend_args_size
+ (int) locals_size + 7) & ~7;
int offset = -8;
int doing_dwarf = dwarf2out_do_frame ();
long cfa_offset = 0;
/* Guard our assumptions. Very low priority FIXME. */
if (locals_size != (int) locals_size)
error ("stack frame too big");
/* Add room needed to save global non-register-stack registers. */
for (regno = 255;
regno >= MMIX_FIRST_GLOBAL_REGNUM;
regno--)
/* Note that we assume that the frame-pointer-register is one of these
registers, in which case we don't count it here. */
if ((((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
&& regs_ever_live[regno] && !call_used_regs[regno]))
|| IS_MMIX_EH_RETURN_DATA_REG (regno))
stack_space_to_allocate += 8;
/* If we do have a frame-pointer, add room for it. */
if (frame_pointer_needed)
stack_space_to_allocate += 8;
/* If we have a non-local label, we need to be able to unwind to it, so
store the current register stack pointer. Also store the return
address if we do that. */
if (MMIX_CFUN_HAS_LANDING_PAD)
stack_space_to_allocate += 16;
else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
/* If we do have a saved return-address slot, add room for it. */
stack_space_to_allocate += 8;
/* Make sure we don't get an unaligned stack. */
if ((stack_space_to_allocate % 8) != 0)
internal_error ("stack frame not a multiple of 8 bytes: %d",
stack_space_to_allocate);
if (current_function_pretend_args_size)
{
int mmix_first_vararg_reg
= (MMIX_FIRST_INCOMING_ARG_REGNUM
+ (MMIX_MAX_ARGS_IN_REGS
- current_function_pretend_args_size / 8));
for (regno
= MMIX_FIRST_INCOMING_ARG_REGNUM + MMIX_MAX_ARGS_IN_REGS - 1;
regno >= mmix_first_vararg_reg;
regno--)
{
if (offset < 0)
{
int stack_chunk
= stack_space_to_allocate > (256 - 8)
? (256 - 8) : stack_space_to_allocate;
fprintf (stream, "\tSUBU %s,%s,%d\n",
reg_names[MMIX_STACK_POINTER_REGNUM],
reg_names[MMIX_STACK_POINTER_REGNUM],
stack_chunk);
if (doing_dwarf)
{
/* Each call to dwarf2out_def_cfa overrides the previous
setting; they don't accumulate. We must keep track
of the offset ourselves. */
cfa_offset += stack_chunk;
if (!frame_pointer_needed)
dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
cfa_offset);
}
offset += stack_chunk;
stack_space_to_allocate -= stack_chunk;
}
fprintf (stream, "\tSTOU %s,%s,%d\n", reg_names[regno],
reg_names[MMIX_STACK_POINTER_REGNUM],
offset);
/* These registers aren't actually saved (as in "will be
restored"), so don't tell DWARF2 they're saved. */
offset -= 8;
}
}
/* Store the frame-pointer. */
if (frame_pointer_needed)
{
if (offset < 0)
{
/* Get 8 less than otherwise, since we need to reach offset + 8. */
int stack_chunk
= stack_space_to_allocate > (256 - 8 - 8)
? (256 - 8 - 8) : stack_space_to_allocate;
fprintf (stream, "\tSUBU %s,%s,%d\n",
reg_names[MMIX_STACK_POINTER_REGNUM],
reg_names[MMIX_STACK_POINTER_REGNUM],
stack_chunk);
if (doing_dwarf)
cfa_offset += stack_chunk;
offset += stack_chunk;
stack_space_to_allocate -= stack_chunk;
}
fprintf (stream, "\tSTOU %s,%s,%d\n\tADDU %s,%s,%d\n",
reg_names[MMIX_FRAME_POINTER_REGNUM],
reg_names[MMIX_STACK_POINTER_REGNUM],
offset,
reg_names[MMIX_FRAME_POINTER_REGNUM],
reg_names[MMIX_STACK_POINTER_REGNUM],
offset + 8);
if (doing_dwarf)
{
/* If we're using the frame-pointer, then we just need this CFA
definition basing on that value (often equal to the CFA).
Further changes to the stack-pointer do not affect the
frame-pointer, so we conditionalize them below on
!frame_pointer_needed. */
dwarf2out_def_cfa ("", MMIX_FRAME_POINTER_REGNUM,
-cfa_offset + offset + 8);
dwarf2out_reg_save ("", MMIX_FRAME_POINTER_REGNUM,
-cfa_offset + offset);
}
offset -= 8;
}
if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
{
/* Store the return-address, if one is needed on the stack. We
usually store it in a register when needed, but that doesn't work
with -fexceptions. */
if (offset < 0)
{
/* Get 8 less than otherwise, since we need to reach offset + 8. */
int stack_chunk
= stack_space_to_allocate > (256 - 8 - 8)
? (256 - 8 - 8) : stack_space_to_allocate;
fprintf (stream, "\tSUBU %s,%s,%d\n",
reg_names[MMIX_STACK_POINTER_REGNUM],
reg_names[MMIX_STACK_POINTER_REGNUM],
stack_chunk);
if (doing_dwarf)
{
cfa_offset += stack_chunk;
if (!frame_pointer_needed)
dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
cfa_offset);
}
offset += stack_chunk;
stack_space_to_allocate -= stack_chunk;
}
fprintf (stream, "\tGET $255,rJ\n\tSTOU $255,%s,%d\n",
reg_names[MMIX_STACK_POINTER_REGNUM],
offset);
if (doing_dwarf)
dwarf2out_return_save ("", -cfa_offset + offset);
offset -= 8;
}
else if (MMIX_CFUN_HAS_LANDING_PAD)
offset -= 8;
if (MMIX_CFUN_HAS_LANDING_PAD)
{
/* Store the register defining the numbering of local registers, so
we know how long to unwind the register stack. */
if (offset < 0)
{
/* Get 8 less than otherwise, since we need to reach offset + 8. */
int stack_chunk
= stack_space_to_allocate > (256 - 8 - 8)
? (256 - 8 - 8) : stack_space_to_allocate;
fprintf (stream, "\tSUBU %s,%s,%d\n",
reg_names[MMIX_STACK_POINTER_REGNUM],
reg_names[MMIX_STACK_POINTER_REGNUM],
stack_chunk);
offset += stack_chunk;
stack_space_to_allocate -= stack_chunk;
if (doing_dwarf)
{
cfa_offset += stack_chunk;
if (!frame_pointer_needed)
dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
cfa_offset);
}
}
/* We don't tell dwarf2 about this one; we just have it to unwind
the register stack at landing pads. FIXME: It's a kludge because
we can't describe the effect of the PUSHJ and PUSHGO insns on the
register stack at the moment. Best thing would be to handle it
like stack-pointer offsets. Better: some hook into dwarf2out.c
to produce DW_CFA_expression:s that specify the increment of rO,
and unwind it at eh_return (preferred) or at the landing pad.
Then saves to $0..$G-1 could be specified through that register. */
fprintf (stream, "\tGET $255,rO\n\tSTOU $255,%s,%d\n",
reg_names[MMIX_STACK_POINTER_REGNUM], offset);
offset -= 8;
}
/* After the return-address and the frame-pointer, we have the local
variables. They're the ones that may have an "unaligned" size. */
offset -= (locals_size + 7) & ~7;
/* Now store all registers that are global, i.e. not saved by the
register file machinery.
It is assumed that the frame-pointer is one of these registers, so it
is explicitly excluded in the count. */
for (regno = 255;
regno >= MMIX_FIRST_GLOBAL_REGNUM;
regno--)
if (((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
&& regs_ever_live[regno] && ! call_used_regs[regno])
|| IS_MMIX_EH_RETURN_DATA_REG (regno))
{
if (offset < 0)
{
int stack_chunk;
/* Since the local variables go above, we may get a large
offset here. */
if (offset < -248)
{
/* We're not going to access the locals area in the
prologue, so we'll just silently subtract the slab we
will not access. */
stack_chunk =
stack_space_to_allocate > (256 - offset - 8)
? (256 - offset - 8) : stack_space_to_allocate;
mmix_output_register_setting (stream, 255, stack_chunk, 1);
fprintf (stream, "\tSUBU %s,%s,$255\n",
reg_names[MMIX_STACK_POINTER_REGNUM],
reg_names[MMIX_STACK_POINTER_REGNUM]);
if (doing_dwarf)
{
cfa_offset += stack_chunk;
if (!frame_pointer_needed)
dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
cfa_offset);
}
}
else
{
stack_chunk = stack_space_to_allocate > (256 - 8)
? (256 - 8) : stack_space_to_allocate;
fprintf (stream, "\tSUBU %s,%s,%d\n",
reg_names[MMIX_STACK_POINTER_REGNUM],
reg_names[MMIX_STACK_POINTER_REGNUM], stack_chunk);
if (doing_dwarf)
{
cfa_offset += stack_chunk;
if (!frame_pointer_needed)
dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
cfa_offset);
}
}
offset += stack_chunk;
stack_space_to_allocate -= stack_chunk;
}
fprintf (stream, "\tSTOU %s,%s,%d\n", reg_names[regno],
reg_names[MMIX_STACK_POINTER_REGNUM], offset);
if (doing_dwarf)
dwarf2out_reg_save ("", regno, -cfa_offset + offset);
offset -= 8;
}
cfun->machine->in_prologue = 1;
}
/* Finally, allocate room for outgoing args and local vars if room
wasn't allocated above. This might be any number of bytes (well, we
assume it fits in a host-int). */
if (stack_space_to_allocate)
{
if (stack_space_to_allocate < 256)
{
fprintf (stream, "\tSUBU %s,%s,%d\n",
reg_names[MMIX_STACK_POINTER_REGNUM],
reg_names[MMIX_STACK_POINTER_REGNUM],
stack_space_to_allocate);
}
else
{
mmix_output_register_setting (stream, 255,
stack_space_to_allocate, 1);
fprintf (stream, "\tSUBU %s,%s,$255\n",
reg_names[MMIX_STACK_POINTER_REGNUM],
reg_names[MMIX_STACK_POINTER_REGNUM]);
}
/* Make a note that we've seen the end of the prologue. */
if (doing_dwarf)
{
cfa_offset += stack_space_to_allocate;
if (!frame_pointer_needed)
dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
cfa_offset);
}
}
static void
mmix_target_asm_function_end_prologue (stream)
FILE *stream ATTRIBUTE_UNUSED;
{
cfun->machine->in_prologue = 0;
}
/* MACHINE_DEPENDENT_REORG.
......@@ -1055,210 +774,40 @@ mmix_target_asm_function_epilogue (stream, locals_size)
HOST_WIDE_INT locals_size;
{
int regno;
int stack_space_to_deallocate
= (current_function_outgoing_args_size
+ current_function_pretend_args_size
+ (int) locals_size + 7) & ~7;
/* Emit an \n for readability of the generated assembly. */
fputc ('\n', stream);
}
/* The assumption that locals_size fits in an int is asserted in
mmix_target_asm_function_prologue. */
/* ASM_OUTPUT_MI_THUNK. */
/* The first address to access is beyond the outgoing_args area. */
int offset = current_function_outgoing_args_size;
void
mmix_asm_output_mi_thunk (stream, fndecl, delta, func)
FILE * stream;
tree fndecl ATTRIBUTE_UNUSED;
int delta;
tree func;
{
/* If you define STRUCT_VALUE to 0, rather than use STRUCT_VALUE_REGNUM,
(i.e. pass location of structure to return as invisible first
argument) you need to tweak this code too. */
const char *regname = reg_names[MMIX_FIRST_INCOMING_ARG_REGNUM];
rtx insn = get_last_insn ();
/* If the last insn was a BARRIER, we don't have to write any code,
then all returns were covered by "return" insns. */
if (GET_CODE (insn) == NOTE)
insn = prev_nonnote_insn (insn);
if (insn
&& (GET_CODE (insn) == BARRIER
/* We must make sure that the insn really is a "return" and
not a conditional branch. Try to match the return exactly,
and if it doesn't match, assume it is a conditional branch
(and output an epilogue). */
|| (GET_CODE (insn) == JUMP_INSN
&& GET_CODE (PATTERN (insn)) == RETURN)))
if (delta >= 0 && delta < 65536)
asm_fprintf (stream, "\tINCL %s,%d\n", delta, regname);
else if (delta < 0 && delta >= -255)
asm_fprintf (stream, "\tSUBU %s,%s,%d\n", regname, regname, -delta);
else
{
/* Emit an extra \n as is done with the normal epilogue. */
fputc ('\n', stream);
return;
mmix_output_register_setting (stream, 255, delta, 1);
asm_fprintf (stream, "\tADDU %s,%s,$255\n", regname, regname);
}
/* Add the space for global non-register-stack registers.
It is assumed that the frame-pointer register can be one of these
registers, in which case it is excluded from the count when needed. */
for (regno = 255;
regno >= MMIX_FIRST_GLOBAL_REGNUM;
regno--)
if (((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
&& regs_ever_live[regno] && !call_used_regs[regno])
|| IS_MMIX_EH_RETURN_DATA_REG (regno))
stack_space_to_deallocate += 8;
/* Add in the space for register stack-pointer. If so, always add room
for the saved PC. */
if (MMIX_CFUN_HAS_LANDING_PAD)
stack_space_to_deallocate += 16;
else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
/* If we have a saved return-address slot, add it in. */
stack_space_to_deallocate += 8;
fprintf (stream, "\tJMP ");
assemble_name (stream, XSTR (XEXP (DECL_RTL (func), 0), 0));
fprintf (stream, "\n");
}
/* Add in the frame-pointer. */
if (frame_pointer_needed)
stack_space_to_deallocate += 8;
/* Make sure we don't get an unaligned stack. */
if ((stack_space_to_deallocate % 8) != 0)
internal_error ("stack frame not a multiple of octabyte: %d",
stack_space_to_deallocate);
/* We will add back small offsets to the stack pointer as we go.
First, we restore all registers that are global, i.e. not saved by
the register file machinery. */
for (regno = MMIX_FIRST_GLOBAL_REGNUM;
regno <= 255;
regno++)
if (((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
&& regs_ever_live[regno] && !call_used_regs[regno])
|| IS_MMIX_EH_RETURN_DATA_REG (regno))
{
if (offset > 255)
{
if (offset > 65535)
{
/* There's better support for incrementing than
decrementing, so we might be able to optimize this as
we see a need. */
mmix_output_register_setting (stream, 255, offset, 1);
fprintf (stream, "\tADDU %s,%s,$255\n",
reg_names[MMIX_STACK_POINTER_REGNUM],
reg_names[MMIX_STACK_POINTER_REGNUM]);
}
else
fprintf (stream, "\tINCL %s,%d\n",
reg_names[MMIX_STACK_POINTER_REGNUM], offset);
stack_space_to_deallocate -= offset;
offset = 0;
}
fprintf (stream, "\tLDOU %s,%s,%d\n",
reg_names[regno],
reg_names[MMIX_STACK_POINTER_REGNUM],
offset);
offset += 8;
}
/* Here is where the local variables were. As in the prologue, they
might be of an unaligned size. */
offset += (locals_size + 7) & ~7;
/* The saved register stack pointer is just below the frame-pointer
register. We don't need to restore it "manually"; the POP
instruction does that. */
if (MMIX_CFUN_HAS_LANDING_PAD)
offset += 16;
else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
/* The return-address slot is just below the frame-pointer register.
We don't need to restore it because we don't really use it. */
offset += 8;
/* Get back the old frame-pointer-value. */
if (frame_pointer_needed)
{
if (offset > 255)
{
if (offset > 65535)
{
/* There's better support for incrementing than
decrementing, so we might be able to optimize this as
we see a need. */
mmix_output_register_setting (stream, 255, offset, 1);
fprintf (stream, "\tADDU %s,%s,$255\n",
reg_names[MMIX_STACK_POINTER_REGNUM],
reg_names[MMIX_STACK_POINTER_REGNUM]);
}
else
fprintf (stream, "\tINCL %s,%d\n",
reg_names[MMIX_STACK_POINTER_REGNUM], offset);
stack_space_to_deallocate -= offset;
offset = 0;
}
fprintf (stream, "\tLDOU %s,%s,%d\n",
reg_names[MMIX_FRAME_POINTER_REGNUM],
reg_names[MMIX_STACK_POINTER_REGNUM],
offset);
offset += 8;
}
/* We do not need to restore pretended incoming args, just add back
offset to sp. */
if (stack_space_to_deallocate > 65535)
{
/* There's better support for incrementing than decrementing, so
we might be able to optimize this as we see a need. */
mmix_output_register_setting (stream, 255,
stack_space_to_deallocate, 1);
fprintf (stream, "\tADDU %s,%s,$255\n",
reg_names[MMIX_STACK_POINTER_REGNUM],
reg_names[MMIX_STACK_POINTER_REGNUM]);
}
else if (stack_space_to_deallocate != 0)
fprintf (stream, "\tINCL %s,%d\n",
reg_names[MMIX_STACK_POINTER_REGNUM],
stack_space_to_deallocate);
if (current_function_calls_eh_return)
/* Adjustment the (normal) stack-pointer to that of the receiver.
FIXME: It would be nice if we could also adjust the register stack
here, but we need to express it through DWARF 2 too. */
fprintf (stream, "\tADDU %s,%s,%s\n",
reg_names [MMIX_STACK_POINTER_REGNUM],
reg_names [MMIX_STACK_POINTER_REGNUM],
reg_names [MMIX_EH_RETURN_STACKADJ_REGNUM]);
/* The extra \n is so we have a blank line between the assembly code of
separate functions. */
fprintf (stream, "\tPOP %d,0\n\n", MMIX_POP_ARGUMENT ());
}
/* ASM_OUTPUT_MI_THUNK. */
void
mmix_asm_output_mi_thunk (stream, fndecl, delta, func)
FILE * stream;
tree fndecl ATTRIBUTE_UNUSED;
int delta;
tree func;
{
/* If you define STRUCT_VALUE to 0, rather than use STRUCT_VALUE_REGNUM,
(i.e. pass location of structure to return as invisible first
argument) you need to tweak this code too. */
const char *regname = reg_names[MMIX_FIRST_INCOMING_ARG_REGNUM];
if (delta >= 0 && delta < 65536)
asm_fprintf (stream, "\tINCL %s,%d\n", delta, regname);
else if (delta < 0 && delta >= -255)
asm_fprintf (stream, "\tSUBU %s,%s,%d\n", regname, regname, -delta);
else
{
mmix_output_register_setting (stream, 255, delta, 1);
asm_fprintf (stream, "\tADDU %s,%s,$255\n", regname, regname);
}
fprintf (stream, "\tJMP ");
assemble_name (stream, XSTR (XEXP (DECL_RTL (func), 0), 0));
fprintf (stream, "\n");
}
/* FUNCTION_PROFILER. */
/* FUNCTION_PROFILER. */
void
mmix_function_profiler (stream, labelno)
......@@ -2483,8 +2032,19 @@ mmix_dbx_register_number (regno)
Now MMIX's own functions. First the exported ones. */
/* Wrapper for get_hard_reg_initial_val since integrate.h isn't included
from insn-emit.c. */
rtx
mmix_get_hard_reg_initial_val (mode, regno)
enum machine_mode mode;
int regno;
{
return get_hard_reg_initial_val (mode, regno);
}
/* Non-zero when the function epilogue is simple enough that a single
"POP %d,0" should be used. */
"POP %d,0" should be used even within the function. */
int
mmix_use_simple_return ()
......@@ -2520,6 +2080,360 @@ mmix_use_simple_return ()
return stack_space_to_allocate == 0;
}
/* Expands the function prologue into RTX. */
void
mmix_expand_prologue ()
{
HOST_WIDE_INT locals_size = get_frame_size ();
int regno;
HOST_WIDE_INT stack_space_to_allocate
= (current_function_outgoing_args_size
+ current_function_pretend_args_size
+ locals_size + 7) & ~7;
HOST_WIDE_INT offset = -8;
/* Add room needed to save global non-register-stack registers. */
for (regno = 255;
regno >= MMIX_FIRST_GLOBAL_REGNUM;
regno--)
/* Note that we assume that the frame-pointer-register is one of these
registers, in which case we don't count it here. */
if ((((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
&& regs_ever_live[regno] && !call_used_regs[regno]))
|| IS_MMIX_EH_RETURN_DATA_REG (regno))
stack_space_to_allocate += 8;
/* If we do have a frame-pointer, add room for it. */
if (frame_pointer_needed)
stack_space_to_allocate += 8;
/* If we have a non-local label, we need to be able to unwind to it, so
store the current register stack pointer. Also store the return
address if we do that. */
if (MMIX_CFUN_HAS_LANDING_PAD)
stack_space_to_allocate += 16;
else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
/* If we do have a saved return-address slot, add room for it. */
stack_space_to_allocate += 8;
/* Make sure we don't get an unaligned stack. */
if ((stack_space_to_allocate % 8) != 0)
internal_error ("stack frame not a multiple of 8 bytes: %d",
stack_space_to_allocate);
if (current_function_pretend_args_size)
{
int mmix_first_vararg_reg
= (MMIX_FIRST_INCOMING_ARG_REGNUM
+ (MMIX_MAX_ARGS_IN_REGS
- current_function_pretend_args_size / 8));
for (regno
= MMIX_FIRST_INCOMING_ARG_REGNUM + MMIX_MAX_ARGS_IN_REGS - 1;
regno >= mmix_first_vararg_reg;
regno--)
{
if (offset < 0)
{
HOST_WIDE_INT stack_chunk
= stack_space_to_allocate > (256 - 8)
? (256 - 8) : stack_space_to_allocate;
mmix_emit_sp_add (-stack_chunk);
offset += stack_chunk;
stack_space_to_allocate -= stack_chunk;
}
/* These registers aren't actually saved (as in "will be
restored"), so don't tell DWARF2 they're saved. */
emit_move_insn (gen_rtx_MEM (DImode,
plus_constant (stack_pointer_rtx,
offset)),
gen_rtx_REG (DImode, regno));
offset -= 8;
}
}
/* Store the frame-pointer. */
if (frame_pointer_needed)
{
rtx insn;
if (offset < 0)
{
/* Get 8 less than otherwise, since we need to reach offset + 8. */
HOST_WIDE_INT stack_chunk
= stack_space_to_allocate > (256 - 8 - 8)
? (256 - 8 - 8) : stack_space_to_allocate;
mmix_emit_sp_add (-stack_chunk);
offset += stack_chunk;
stack_space_to_allocate -= stack_chunk;
}
insn = emit_move_insn (gen_rtx_MEM (DImode,
plus_constant (stack_pointer_rtx,
offset)),
hard_frame_pointer_rtx);
RTX_FRAME_RELATED_P (insn) = 1;
insn = emit_insn (gen_adddi3 (hard_frame_pointer_rtx,
stack_pointer_rtx,
GEN_INT (offset + 8)));
RTX_FRAME_RELATED_P (insn) = 1;
offset -= 8;
}
if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
{
rtx tmpreg, retreg;
rtx insn;
/* Store the return-address, if one is needed on the stack. We
usually store it in a register when needed, but that doesn't work
with -fexceptions. */
if (offset < 0)
{
/* Get 8 less than otherwise, since we need to reach offset + 8. */
HOST_WIDE_INT stack_chunk
= stack_space_to_allocate > (256 - 8 - 8)
? (256 - 8 - 8) : stack_space_to_allocate;
mmix_emit_sp_add (-stack_chunk);
offset += stack_chunk;
stack_space_to_allocate -= stack_chunk;
}
tmpreg = gen_rtx_REG (DImode, 255);
retreg = gen_rtx_REG (DImode, MMIX_rJ_REGNUM);
/* Dwarf2 code is confused by the use of a temporary register for
storing the return address, so we have to express it as a note,
which we attach to the actual store insn. */
emit_move_insn (tmpreg, retreg);
insn = emit_move_insn (gen_rtx_MEM (DImode,
plus_constant (stack_pointer_rtx,
offset)),
tmpreg);
RTX_FRAME_RELATED_P (insn) = 1;
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
gen_rtx_SET (VOIDmode,
gen_rtx_MEM (DImode,
plus_constant (stack_pointer_rtx,
offset)),
retreg),
REG_NOTES (insn));
offset -= 8;
}
else if (MMIX_CFUN_HAS_LANDING_PAD)
offset -= 8;
if (MMIX_CFUN_HAS_LANDING_PAD)
{
/* Store the register defining the numbering of local registers, so
we know how long to unwind the register stack. */
if (offset < 0)
{
/* Get 8 less than otherwise, since we need to reach offset + 8. */
HOST_WIDE_INT stack_chunk
= stack_space_to_allocate > (256 - 8 - 8)
? (256 - 8 - 8) : stack_space_to_allocate;
mmix_emit_sp_add (-stack_chunk);
offset += stack_chunk;
stack_space_to_allocate -= stack_chunk;
}
/* We don't tell dwarf2 about this one; we just have it to unwind
the register stack at landing pads. FIXME: It's a kludge because
we can't describe the effect of the PUSHJ and PUSHGO insns on the
register stack at the moment. Best thing would be to handle it
like stack-pointer offsets. Better: some hook into dwarf2out.c
to produce DW_CFA_expression:s that specify the increment of rO,
and unwind it at eh_return (preferred) or at the landing pad.
Then saves to $0..$G-1 could be specified through that register. */
emit_move_insn (gen_rtx_REG (DImode, 255),
gen_rtx_REG (DImode,
MMIX_rO_REGNUM));
emit_move_insn (gen_rtx_MEM (DImode,
plus_constant (stack_pointer_rtx, offset)),
gen_rtx_REG (DImode, 255));
offset -= 8;
}
/* After the return-address and the frame-pointer, we have the local
variables. They're the ones that may have an "unaligned" size. */
offset -= (locals_size + 7) & ~7;
/* Now store all registers that are global, i.e. not saved by the
register file machinery.
It is assumed that the frame-pointer is one of these registers, so it
is explicitly excluded in the count. */
for (regno = 255;
regno >= MMIX_FIRST_GLOBAL_REGNUM;
regno--)
if (((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
&& regs_ever_live[regno] && ! call_used_regs[regno])
|| IS_MMIX_EH_RETURN_DATA_REG (regno))
{
rtx insn;
if (offset < 0)
{
HOST_WIDE_INT stack_chunk
= (stack_space_to_allocate > (256 - offset - 8)
? (256 - offset - 8) : stack_space_to_allocate);
mmix_emit_sp_add (-stack_chunk);
offset += stack_chunk;
stack_space_to_allocate -= stack_chunk;
}
insn = emit_move_insn (gen_rtx_MEM (DImode,
plus_constant (stack_pointer_rtx,
offset)),
gen_rtx_REG (DImode, regno));
RTX_FRAME_RELATED_P (insn) = 1;
offset -= 8;
}
/* Finally, allocate room for outgoing args and local vars if room
wasn't allocated above. */
if (stack_space_to_allocate)
mmix_emit_sp_add (-stack_space_to_allocate);
}
/* Expands the function epilogue into RTX. */
void
mmix_expand_epilogue ()
{
HOST_WIDE_INT locals_size = get_frame_size ();
int regno;
HOST_WIDE_INT stack_space_to_deallocate
= (current_function_outgoing_args_size
+ current_function_pretend_args_size
+ locals_size + 7) & ~7;
/* The assumption that locals_size fits in an int is asserted in
mmix_expand_prologue. */
/* The first address to access is beyond the outgoing_args area. */
int offset = current_function_outgoing_args_size;
/* Add the space for global non-register-stack registers.
It is assumed that the frame-pointer register can be one of these
registers, in which case it is excluded from the count when needed. */
for (regno = 255;
regno >= MMIX_FIRST_GLOBAL_REGNUM;
regno--)
if (((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
&& regs_ever_live[regno] && !call_used_regs[regno])
|| IS_MMIX_EH_RETURN_DATA_REG (regno))
stack_space_to_deallocate += 8;
/* Add in the space for register stack-pointer. If so, always add room
for the saved PC. */
if (MMIX_CFUN_HAS_LANDING_PAD)
stack_space_to_deallocate += 16;
else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
/* If we have a saved return-address slot, add it in. */
stack_space_to_deallocate += 8;
/* Add in the frame-pointer. */
if (frame_pointer_needed)
stack_space_to_deallocate += 8;
/* Make sure we don't get an unaligned stack. */
if ((stack_space_to_deallocate % 8) != 0)
internal_error ("stack frame not a multiple of octabyte: %d",
stack_space_to_deallocate);
/* We will add back small offsets to the stack pointer as we go.
First, we restore all registers that are global, i.e. not saved by
the register file machinery. */
for (regno = MMIX_FIRST_GLOBAL_REGNUM;
regno <= 255;
regno++)
if (((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
&& regs_ever_live[regno] && !call_used_regs[regno])
|| IS_MMIX_EH_RETURN_DATA_REG (regno))
{
if (offset > 255)
{
mmix_emit_sp_add (offset);
stack_space_to_deallocate -= offset;
offset = 0;
}
emit_move_insn (gen_rtx_REG (DImode, regno),
gen_rtx_MEM (DImode,
plus_constant (stack_pointer_rtx,
offset)));
offset += 8;
}
/* Here is where the local variables were. As in the prologue, they
might be of an unaligned size. */
offset += (locals_size + 7) & ~7;
/* The saved register stack pointer is just below the frame-pointer
register. We don't need to restore it "manually"; the POP
instruction does that. */
if (MMIX_CFUN_HAS_LANDING_PAD)
offset += 16;
else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
/* The return-address slot is just below the frame-pointer register.
We don't need to restore it because we don't really use it. */
offset += 8;
/* Get back the old frame-pointer-value. */
if (frame_pointer_needed)
{
if (offset > 255)
{
mmix_emit_sp_add (offset);
stack_space_to_deallocate -= offset;
offset = 0;
}
emit_move_insn (hard_frame_pointer_rtx,
gen_rtx_MEM (DImode,
plus_constant (stack_pointer_rtx,
offset)));
offset += 8;
}
/* We do not need to restore pretended incoming args, just add back
offset to sp. */
if (stack_space_to_deallocate != 0)
mmix_emit_sp_add (stack_space_to_deallocate);
if (current_function_calls_eh_return)
/* Adjust the (normal) stack-pointer to that of the receiver.
FIXME: It would be nice if we could also adjust the register stack
here, but we need to express it through DWARF 2 too. */
emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx,
gen_rtx_REG (DImode,
MMIX_EH_RETURN_STACKADJ_REGNUM)));
}
/* Output an optimal sequence for setting a register to a specific
constant. Used in an alternative for const_ints in movdi, and when
using large stack-frame offsets.
......@@ -2884,6 +2798,48 @@ mmix_gen_compare_reg (code, x, y)
/* Local (static) helper functions. */
static void
mmix_emit_sp_add (offset)
HOST_WIDE_INT offset;
{
rtx insn;
if (offset < 0)
{
/* Negative stack-pointer adjustments are allocations and appear in
the prologue only. We mark them as frame-related so unwind and
debug info is properly emitted for them. */
if (offset > -255)
insn = emit_insn (gen_adddi3 (stack_pointer_rtx,
stack_pointer_rtx,
GEN_INT (offset)));
else
{
rtx tmpr = gen_rtx_REG (DImode, 255);
RTX_FRAME_RELATED_P (emit_move_insn (tmpr, GEN_INT (offset))) = 1;
insn = emit_insn (gen_adddi3 (stack_pointer_rtx,
stack_pointer_rtx, tmpr));
}
RTX_FRAME_RELATED_P (insn) = 1;
}
else
{
/* Positive adjustments are in the epilogue only. Don't mark them
as "frame-related" for unwind info. */
if (CONST_OK_FOR_LETTER_P (offset, 'L'))
emit_insn (gen_adddi3 (stack_pointer_rtx,
stack_pointer_rtx,
GEN_INT (offset)));
else
{
rtx tmpr = gen_rtx_REG (DImode, 255);
emit_move_insn (tmpr, GEN_INT (offset));
insn = emit_insn (gen_adddi3 (stack_pointer_rtx,
stack_pointer_rtx, tmpr));
}
}
}
/* Print operator suitable for doing something with a shiftable
wyde. The type of operator is passed as an asm output modifier. */
......
......@@ -49,6 +49,7 @@ Boston, MA 02111-1307, USA. */
#define MMIX_HIMULT_REGNUM 258
#define MMIX_REMAINDER_REGNUM 260
#define MMIX_ARG_POINTER_REGNUM 261
#define MMIX_rO_REGNUM 262
#define MMIX_LAST_STACK_REGISTER_REGNUM 31
/* Four registers; "ideally, these registers should be call-clobbered", so
......@@ -92,6 +93,7 @@ struct machine_function GTY(())
{
int has_landing_pad;
int highest_saved_stack_register;
int in_prologue;
};
/* For these target macros, there is no generic documentation here. You
......@@ -360,13 +362,13 @@ extern int target_flags;
/* Node: Register Basics */
/* We tell GCC about all 256 general registers, and we also include
rD, rE, rH, rJ and rR (in that order) so we can describe what insns
rD, rE, rH, rJ, rR and rO (in that order) so we can describe what insns
clobber them. We use a faked register for the argument pointer. It is
always eliminated towards the frame-pointer or the stack-pointer, never
output in assembly. Any fixed register would do for this, like $255,
but future debugging is easier when using a separate register. It
counts as a global register for pseudorandom reasons. */
#define FIRST_PSEUDO_REGISTER 262
#define FIRST_PSEUDO_REGISTER 263
/* We treat general registers with no assigned purpose as fixed. The
stack pointer, $254, is also fixed. Register $255 is referred to as a
......@@ -390,7 +392,7 @@ extern int target_flags;
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, \
1, 1, 0, 0, 0, 1 \
1, 1, 0, 0, 0, 1, 1 \
}
/* General registers are fixed and therefore "historically" marked
......@@ -414,19 +416,23 @@ extern int target_flags;
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, \
1, 1, 1, 1, 1, 1 \
1, 1, 1, 1, 1, 1, 1 \
}
#define CONDITIONAL_REGISTER_USAGE mmix_conditional_register_usage ()
/* No LOCAL_REGNO, INCOMING_REGNO or OUTGOING_REGNO, since those macros
are not usable for MMIX: it doesn't have a fixed register window size.
FIXME: Perhaps we should say something about $0..$15 may sometimes be
the incoming $16..$31. Those macros need better documentation; it
looks like they're just bogus and that FUNCTION_INCOMING_ARG_REGNO_P
and FUNCTION_OUTGOING_VALUE should be used where they're used. For the
/* No INCOMING_REGNO or OUTGOING_REGNO, since those macros are not usable
for MMIX: it doesn't have a fixed register window size. FIXME: Perhaps
we should say something about $0..$15 may sometimes be the incoming
$16..$31. Those macros need better documentation; it looks like
they're just bogus and that FUNCTION_INCOMING_ARG_REGNO_P and
FUNCTION_OUTGOING_VALUE should be used where they're used. For the
moment, do nothing; things seem to work anyway. */
/* Defining LOCAL_REGNO is necessary in presence of prologue/epilogue,
else GCC will be confused that those registers aren't saved and
restored. */
#define LOCAL_REGNO(REGNO) mmix_local_regno (REGNO)
/* Node: Allocation Order */
......@@ -474,7 +480,7 @@ extern int target_flags;
232, 233, 234, 235, 236, 237, 238, 239, \
240, 241, 242, 243, 244, 245, 246, \
\
254, 255, 256, 257, 261 \
254, 255, 256, 257, 261, 262 \
}
/* As a convenience, we put this nearby, for ease of comparison.
......@@ -529,7 +535,7 @@ extern int target_flags;
216, 217, 218, 219, 220, 221, 222, 223, \
224, 225, 226, 227, 228, 229, 230, \
\
254, 255, 256, 257, 261 \
254, 255, 256, 257, 261, 262 \
}
/* The default one. */
......@@ -573,8 +579,8 @@ enum reg_class
{~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, 0x20}, \
{0, 0, 0, 0, 0, 0, 0, 0, 0x10}, \
{0, 0, 0, 0, 0, 0, 0, 0, 4}, \
{0, 0, 0, 0, 0, 0, 0, 0, 0x3f}, \
{~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, 0x3f}}
{0, 0, 0, 0, 0, 0, 0, 0, 0x7f}, \
{~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, 0x7f}}
#define REGNO_REG_CLASS(REGNO) \
((REGNO) <= MMIX_LAST_GENERAL_REGISTER \
......@@ -1058,11 +1064,11 @@ typedef struct { int regs; int lib; int now_varargs; } CUMULATIVE_ARGS;
"$232", "$233", "$234", "$235", "$236", "$237", "$238", "$239", \
"$240", "$241", "$242", "$243", "$244", "$245", "$246", "$247", \
"$248", "$249", "$250", "$251", "$252", "$253", "$254", "$255", \
":rD", ":rE", ":rH", ":rJ", ":rR", "ap_!BAD!"}
":rD", ":rE", ":rH", ":rJ", ":rR", "ap_!BAD!", ":rO"}
#define ADDITIONAL_REGISTER_NAMES \
{{"sp", 254}, {":sp", 254}, {"rD", 256}, {"rE", 257}, \
{"rH", 258}, {"rJ", MMIX_rJ_REGNUM}}
{"rH", 258}, {"rJ", MMIX_rJ_REGNUM}, {"rO", MMIX_rO_REGNUM}}
#define PRINT_OPERAND(STREAM, X, CODE) \
mmix_print_operand (STREAM, X, CODE)
......
......@@ -988,7 +988,8 @@ DIVU %1,%1,%2\;GET %0,:rR\;NEGU %2,0,%0\;CSNN %0,$255,%2")
in the call, and we set it back after every call (all but one setting
will be optimized away), integrity is maintained. */
operands[3]
= get_hard_reg_initial_val (Pmode, MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
= mmix_get_hard_reg_initial_val (Pmode,
MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
/* FIXME: There's a bug in gcc which causes NULL to be passed as
operand[2] when we get out of registers, which later confuses gcc.
......@@ -1014,7 +1015,8 @@ DIVU %1,%1,%2\;GET %0,:rR\;NEGU %2,0,%0\;CSNN %0,$255,%2")
in the call, and we set it back after every call (all but one setting
will be optimized away), integrity is maintained. */
operands[4]
= get_hard_reg_initial_val (Pmode, MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
= mmix_get_hard_reg_initial_val (Pmode,
MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
/* FIXME: See 'call'. */
if (operands[3] == NULL_RTX)
......@@ -1067,11 +1069,30 @@ DIVU %1,%1,%2\;GET %0,:rR\;NEGU %2,0,%0\;CSNN %0,$255,%2")
;; I hope untyped_call and untyped_return are not needed for MMIX.
;; Users of Objective C will notice.
(define_insn "return"
; Generated by GCC.
(define_expand "return"
[(return)]
"mmix_use_simple_return ()"
"")
; Generated by the epilogue expander.
(define_insn "*expanded_return"
[(return)]
""
"POP %.,0")
(define_expand "prologue"
[(const_int 0)]
""
"mmix_expand_prologue (); DONE;")
; Note that the (return) from the expander itself is always the last insn
; in the epilogue.
(define_expand "epilogue"
[(return)]
""
"mmix_expand_epilogue ();")
(define_insn "nop"
[(const_int 0)]
""
......@@ -1111,7 +1132,8 @@ DIVU %1,%1,%2\;GET %0,:rR\;NEGU %2,0,%0\;CSNN %0,$255,%2")
"
{
operands[0]
= get_hard_reg_initial_val (Pmode, MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
= mmix_get_hard_reg_initial_val (Pmode,
MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
/* Mark this function as containing a landing-pad. */
cfun->machine->has_landing_pad = 1;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment