home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 7
/
FreshFishVol7.bin
/
bbs
/
gnu
/
gcc-2.3.3-src.lha
/
GNU
/
src
/
amiga
/
gcc-2.3.3
/
config
/
m68k.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-02-06
|
53KB
|
2,001 lines
/* Subroutines for insn-output.c for Motorola 68000 family.
Copyright (C) 1987 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Some output-actions in m68k.md need these. */
#include <stdio.h>
#include "config.h"
#include "rtl.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "real.h"
#include "insn-config.h"
#include "conditions.h"
#include "insn-flags.h"
#include "output.h"
#include "insn-attr.h"
/* Needed for use_return_insn. */
#include "flags.h"
#ifdef SUPPORT_SUN_FPA
/* Index into this array by (register number >> 3) to find the
smallest class which contains that register. */
enum reg_class regno_reg_class[]
= { DATA_REGS, ADDR_REGS, FP_REGS,
LO_FPA_REGS, LO_FPA_REGS, FPA_REGS, FPA_REGS };
#endif /* defined SUPPORT_SUN_FPA */
/* This flag is used to communicate between movhi and ASM_OUTPUT_CASE_END,
if SGS_SWITCH_TABLE. */
int switch_table_difference_label_flag;
static rtx find_addr_reg ();
rtx legitimize_pic_address ();
/* Emit a (use pic_offset_table_rtx) if we used PIC relocation in the
function at any time during the compilation process. In the future
we should try and eliminate the USE if we can easily determine that
all PIC references were deleted from the current function. That would
save an address register */
finalize_pic ()
{
if (flag_pic && (flag_pic < 3) && current_function_uses_pic_offset_table)
emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx));
}
/* This function generates the assembly code for function entry.
STREAM is a stdio stream to output the code to.
SIZE is an int: how many units of temporary storage to allocate.
Refer to the array `regs_ever_live' to determine which registers
to save; `regs_ever_live[I]' is nonzero if register number I
is ever used in the function. This function is responsible for
knowing which registers should not be saved even if used. */
/* Note that the order of the bit mask for fmovem is the opposite
of the order for movem! */
void
output_function_prologue (stream, size)
FILE *stream;
int size;
{
register int regno;
register int mask = 0;
int num_saved_regs = 0;
extern char call_used_regs[];
int fsize = (size + 3) & -4;
if (frame_pointer_needed)
{
/* Adding negative number is faster on the 68040. */
if (fsize < 0x8000 && !TARGET_68040)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tlink.w %s,%0I%d\n",
reg_names[FRAME_POINTER_REGNUM], -fsize);
#else
asm_fprintf (stream, "\tlink %s,%0I%d\n",
reg_names[FRAME_POINTER_REGNUM], -fsize);
#endif
}
else if (TARGET_68020)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tlink.l %s,%0I%d\n",
reg_names[FRAME_POINTER_REGNUM], -fsize);
#else
asm_fprintf (stream, "\tlink %s,%0I%d\n",
reg_names[FRAME_POINTER_REGNUM], -fsize);
#endif
}
else
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tlink.w %s,%0I0\n\tadd.l %0I%d,%Rsp\n",
reg_names[FRAME_POINTER_REGNUM], -fsize);
#else
asm_fprintf (stream, "\tlink %s,%0I0\n\taddl %0I%d,%Rsp\n",
reg_names[FRAME_POINTER_REGNUM], -fsize);
#endif
}
}
else if (fsize)
{
/* Adding negative number is faster on the 68040. */
if (fsize + 4 < 0x8000)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tadd.w %0I%d,%Rsp\n", - (fsize + 4));
#else
asm_fprintf (stream, "\taddw %0I%d,%Rsp\n", - (fsize + 4));
#endif
}
else
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tadd.l %0I%d,%Rsp\n", - (fsize + 4));
#else
asm_fprintf (stream, "\taddl %0I%d,%Rsp\n", - (fsize + 4));
#endif
}
}
#ifdef SUPPORT_SUN_FPA
for (regno = 24; regno < 56; regno++)
if (regs_ever_live[regno] && ! call_used_regs[regno])
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tfpmovd %s,-(%Rsp)\n",
reg_names[regno]);
#else
asm_fprintf (stream, "\tfpmoved %s,%Rsp@-\n",
reg_names[regno]);
#endif
}
#endif
for (regno = 16; regno < 24; regno++)
if (regs_ever_live[regno] && ! call_used_regs[regno])
mask |= 1 << (regno - 16);
if ((mask & 0xff) != 0)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tfmovm %0I0x%x,-(%Rsp)\n", mask & 0xff);
#else
asm_fprintf (stream, "\tfmovem %0I0x%x,%Rsp@-\n", mask & 0xff);
#endif
}
mask = 0;
for (regno = 0; regno < 16; regno++)
if (regs_ever_live[regno] && ! call_used_regs[regno])
{
mask |= 1 << (15 - regno);
num_saved_regs++;
}
if (frame_pointer_needed)
{
mask &= ~ (1 << (15 - FRAME_POINTER_REGNUM));
num_saved_regs--;
}
#ifdef PROLOGUE_EXTRA_SAVE
PROLOGUE_EXTRA_SAVE (mask);
#endif
#if NEED_PROBE
fprintf (stream, "\ttstl sp@(%d)\n", NEED_PROBE - num_saved_regs * 4);
#endif
if (num_saved_regs <= 2)
{
/* Store each separately in the same order moveml uses.
Using two movel instructions instead of a single moveml
is about 15% faster for the 68020 and 68030 at no expense
in code size */
int i;
/* Undo the work from above. */
for (i = 0; i< 16; i++)
if (mask & (1 << i))
asm_fprintf (stream,
#ifdef MOTOROLA
"\t%Omove.l %s,-(%Rsp)\n",
#else
"\tmovel %s,%Rsp@-\n",
#endif
reg_names[15 - i]);
}
else if (mask)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tmovm.l %0I0x%x,-(%Rsp)\n", mask);
#else
asm_fprintf (stream, "\tmoveml %0I0x%x,%Rsp@-\n", mask);
#endif
}
if (flag_pic && (flag_pic < 3) && current_function_uses_pic_offset_table)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\t%Omove.l %0I__GLOBAL_OFFSET_TABLE_, %s\n",
reg_names[PIC_OFFSET_TABLE_REGNUM]);
asm_fprintf (stream, "\tlea.l (%Rpc,%s.l),%s\n",
reg_names[PIC_OFFSET_TABLE_REGNUM],
reg_names[PIC_OFFSET_TABLE_REGNUM]);
#else
asm_fprintf (stream, "\tmovel %0I__GLOBAL_OFFSET_TABLE_, %s\n",
reg_names[PIC_OFFSET_TABLE_REGNUM]);
asm_fprintf (stream, "\tlea %Rpc@(0,%s:l),%s\n",
reg_names[PIC_OFFSET_TABLE_REGNUM],
reg_names[PIC_OFFSET_TABLE_REGNUM]);
#endif
}
}
/* Return true if this function's epilogue can be output as RTL. */
int
use_return_insn ()
{
int regno;
if (!reload_completed || frame_pointer_needed || get_frame_size () != 0)
return 0;
/* Copied from output_function_epilogue (). We should probably create a
separate layout routine to perform the common work. */
for (regno = 0 ; regno < FIRST_PSEUDO_REGISTER ; regno++)
if (regs_ever_live[regno] && ! call_used_regs[regno])
return 0;
return 1;
}
/* This function generates the assembly code for function exit,
on machines that need it. Args are same as for FUNCTION_PROLOGUE.
The function epilogue should not depend on the current stack pointer!
It should use the frame pointer only, if there is a frame pointer.
This is mandatory because of alloca; we also take advantage of it to
omit stack adjustments before returning. */
void
output_function_epilogue (stream, size)
FILE *stream;
int size;
{
register int regno;
register int mask, fmask;
register int nregs;
int offset, foffset, fpoffset;
extern char call_used_regs[];
int fsize = (size + 3) & -4;
int big = 0;
rtx insn = get_last_insn ();
/* If the last insn was a BARRIER, we don't have to write any code. */
if (GET_CODE (insn) == NOTE)
insn = prev_nonnote_insn (insn);
if (insn && GET_CODE (insn) == BARRIER)
{
/* Output just a no-op so that debuggers don't get confused
about which function the p