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 >
C/C++ Source or Header  |  1994-02-06  |  53KB  |  2,001 lines

  1. /* Subroutines for insn-output.c for Motorola 68000 family.
  2.    Copyright (C) 1987 Free Software Foundation, Inc.
  3.  
  4. This file is part of GNU CC.
  5.  
  6. GNU CC is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. GNU CC is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GNU CC; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20.  
  21. /* Some output-actions in m68k.md need these.  */
  22. #include <stdio.h>
  23. #include "config.h"
  24. #include "rtl.h"
  25. #include "regs.h"
  26. #include "hard-reg-set.h"
  27. #include "real.h"
  28. #include "insn-config.h"
  29. #include "conditions.h"
  30. #include "insn-flags.h"
  31. #include "output.h"
  32. #include "insn-attr.h"
  33.  
  34. /* Needed for use_return_insn.  */
  35. #include "flags.h"
  36.  
  37. #ifdef SUPPORT_SUN_FPA
  38.  
  39. /* Index into this array by (register number >> 3) to find the
  40.    smallest class which contains that register.  */
  41. enum reg_class regno_reg_class[]
  42.   = { DATA_REGS, ADDR_REGS, FP_REGS,
  43.       LO_FPA_REGS, LO_FPA_REGS, FPA_REGS, FPA_REGS };
  44.  
  45. #endif /* defined SUPPORT_SUN_FPA */
  46.  
  47. /* This flag is used to communicate between movhi and ASM_OUTPUT_CASE_END,
  48.    if SGS_SWITCH_TABLE.  */
  49. int switch_table_difference_label_flag;
  50.  
  51. static rtx find_addr_reg ();
  52. rtx legitimize_pic_address ();
  53.  
  54.  
  55. /* Emit a (use pic_offset_table_rtx) if we used PIC relocation in the 
  56.    function at any time during the compilation process.  In the future 
  57.    we should try and eliminate the USE if we can easily determine that 
  58.    all PIC references were deleted from the current function.  That would 
  59.    save an address register */
  60.    
  61. finalize_pic ()
  62. {
  63.   if (flag_pic && (flag_pic < 3) && current_function_uses_pic_offset_table)
  64.     emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx));
  65. }
  66.  
  67.  
  68. /* This function generates the assembly code for function entry.
  69.    STREAM is a stdio stream to output the code to.
  70.    SIZE is an int: how many units of temporary storage to allocate.
  71.    Refer to the array `regs_ever_live' to determine which registers
  72.    to save; `regs_ever_live[I]' is nonzero if register number I
  73.    is ever used in the function.  This function is responsible for
  74.    knowing which registers should not be saved even if used.  */
  75.  
  76.  
  77. /* Note that the order of the bit mask for fmovem is the opposite
  78.    of the order for movem!  */
  79.  
  80.  
  81. void
  82. output_function_prologue (stream, size)
  83.      FILE *stream;
  84.      int size;
  85. {
  86.   register int regno;
  87.   register int mask = 0;
  88.   int num_saved_regs = 0;
  89.   extern char call_used_regs[];
  90.   int fsize = (size + 3) & -4;
  91.   
  92.  
  93.   if (frame_pointer_needed)
  94.     {
  95.       /* Adding negative number is faster on the 68040.  */
  96.       if (fsize < 0x8000 && !TARGET_68040)
  97.     {
  98. #ifdef MOTOROLA
  99.       asm_fprintf (stream, "\tlink.w %s,%0I%d\n",
  100.                reg_names[FRAME_POINTER_REGNUM], -fsize);
  101. #else
  102.       asm_fprintf (stream, "\tlink %s,%0I%d\n",
  103.                reg_names[FRAME_POINTER_REGNUM], -fsize);
  104. #endif
  105.     }
  106.       else if (TARGET_68020)
  107.     {
  108. #ifdef MOTOROLA
  109.       asm_fprintf (stream, "\tlink.l %s,%0I%d\n",
  110.                reg_names[FRAME_POINTER_REGNUM], -fsize);
  111. #else
  112.       asm_fprintf (stream, "\tlink %s,%0I%d\n",
  113.                reg_names[FRAME_POINTER_REGNUM], -fsize);
  114. #endif
  115.     }
  116.       else
  117.     {
  118. #ifdef MOTOROLA
  119.       asm_fprintf (stream, "\tlink.w %s,%0I0\n\tadd.l %0I%d,%Rsp\n",
  120.                reg_names[FRAME_POINTER_REGNUM], -fsize);
  121. #else
  122.       asm_fprintf (stream, "\tlink %s,%0I0\n\taddl %0I%d,%Rsp\n",
  123.                reg_names[FRAME_POINTER_REGNUM], -fsize);
  124. #endif
  125.     }
  126.     }
  127.   else if (fsize)
  128.     {
  129.       /* Adding negative number is faster on the 68040.  */
  130.       if (fsize + 4 < 0x8000)
  131.     {
  132. #ifdef MOTOROLA
  133.       asm_fprintf (stream, "\tadd.w %0I%d,%Rsp\n", - (fsize + 4));
  134. #else
  135.       asm_fprintf (stream, "\taddw %0I%d,%Rsp\n", - (fsize + 4));
  136. #endif
  137.     }
  138.       else
  139.     {
  140. #ifdef MOTOROLA
  141.       asm_fprintf (stream, "\tadd.l %0I%d,%Rsp\n", - (fsize + 4));
  142. #else
  143.       asm_fprintf (stream, "\taddl %0I%d,%Rsp\n", - (fsize + 4));
  144. #endif
  145.     }
  146.     }
  147. #ifdef SUPPORT_SUN_FPA
  148.   for (regno = 24; regno < 56; regno++)
  149.     if (regs_ever_live[regno] && ! call_used_regs[regno])
  150.       {
  151. #ifdef MOTOROLA
  152.     asm_fprintf (stream, "\tfpmovd %s,-(%Rsp)\n",
  153.              reg_names[regno]);
  154. #else
  155.     asm_fprintf (stream, "\tfpmoved %s,%Rsp@-\n",
  156.              reg_names[regno]);
  157. #endif
  158.       }
  159. #endif
  160.   for (regno = 16; regno < 24; regno++)
  161.     if (regs_ever_live[regno] && ! call_used_regs[regno])
  162.        mask |= 1 << (regno - 16);
  163.   if ((mask & 0xff) != 0)
  164.     {
  165. #ifdef MOTOROLA
  166.       asm_fprintf (stream, "\tfmovm %0I0x%x,-(%Rsp)\n", mask & 0xff);
  167. #else
  168.       asm_fprintf (stream, "\tfmovem %0I0x%x,%Rsp@-\n", mask & 0xff);
  169. #endif
  170.     }
  171.   mask = 0;
  172.   for (regno = 0; regno < 16; regno++)
  173.     if (regs_ever_live[regno] && ! call_used_regs[regno])
  174.       {
  175.         mask |= 1 << (15 - regno);
  176.         num_saved_regs++;
  177.       }
  178.   if (frame_pointer_needed)
  179.     {
  180.       mask &= ~ (1 << (15 - FRAME_POINTER_REGNUM));
  181.       num_saved_regs--;
  182.     }
  183. #ifdef PROLOGUE_EXTRA_SAVE
  184.   PROLOGUE_EXTRA_SAVE (mask);
  185. #endif
  186.  
  187. #if NEED_PROBE
  188.   fprintf (stream, "\ttstl sp@(%d)\n", NEED_PROBE - num_saved_regs * 4);
  189. #endif
  190.  
  191.   if (num_saved_regs <= 2)
  192.     {
  193.       /* Store each separately in the same order moveml uses.
  194.          Using two movel instructions instead of a single moveml
  195.          is about 15% faster for the 68020 and 68030 at no expense
  196.          in code size */
  197.  
  198.       int i;
  199.  
  200.       /* Undo the work from above. */
  201.       for (i = 0; i< 16; i++)
  202.         if (mask & (1 << i))
  203.           asm_fprintf (stream,
  204. #ifdef MOTOROLA
  205.                "\t%Omove.l %s,-(%Rsp)\n",
  206. #else
  207.                "\tmovel %s,%Rsp@-\n",
  208. #endif
  209.                reg_names[15 - i]);
  210.     }
  211.   else if (mask)
  212.     {
  213. #ifdef MOTOROLA
  214.       asm_fprintf (stream, "\tmovm.l %0I0x%x,-(%Rsp)\n", mask);
  215. #else
  216.       asm_fprintf (stream, "\tmoveml %0I0x%x,%Rsp@-\n", mask);
  217. #endif
  218.     }
  219.   if (flag_pic && (flag_pic < 3) && current_function_uses_pic_offset_table)
  220.     {
  221. #ifdef MOTOROLA
  222.       asm_fprintf (stream, "\t%Omove.l %0I__GLOBAL_OFFSET_TABLE_, %s\n",
  223.            reg_names[PIC_OFFSET_TABLE_REGNUM]);
  224.       asm_fprintf (stream, "\tlea.l (%Rpc,%s.l),%s\n",
  225.            reg_names[PIC_OFFSET_TABLE_REGNUM],
  226.            reg_names[PIC_OFFSET_TABLE_REGNUM]);
  227. #else
  228.       asm_fprintf (stream, "\tmovel %0I__GLOBAL_OFFSET_TABLE_, %s\n",
  229.            reg_names[PIC_OFFSET_TABLE_REGNUM]);
  230.       asm_fprintf (stream, "\tlea %Rpc@(0,%s:l),%s\n",
  231.            reg_names[PIC_OFFSET_TABLE_REGNUM],
  232.            reg_names[PIC_OFFSET_TABLE_REGNUM]);
  233. #endif
  234.     }
  235. }
  236.  
  237. /* Return true if this function's epilogue can be output as RTL.  */
  238.  
  239. int
  240. use_return_insn ()
  241. {
  242.   int regno;
  243.  
  244.   if (!reload_completed || frame_pointer_needed || get_frame_size () != 0)
  245.     return 0;
  246.   
  247.   /* Copied from output_function_epilogue ().  We should probably create a
  248.      separate layout routine to perform the common work.  */
  249.   
  250.   for (regno = 0 ; regno < FIRST_PSEUDO_REGISTER ; regno++)
  251.     if (regs_ever_live[regno] && ! call_used_regs[regno])
  252.       return 0;
  253.   
  254.   return 1;
  255. }
  256.  
  257. /* This function generates the assembly code for function exit,
  258.    on machines that need it.  Args are same as for FUNCTION_PROLOGUE.
  259.  
  260.    The function epilogue should not depend on the current stack pointer!
  261.    It should use the frame pointer only, if there is a frame pointer.
  262.    This is mandatory because of alloca; we also take advantage of it to
  263.    omit stack adjustments before returning.  */
  264.  
  265. void
  266. output_function_epilogue (stream, size)
  267.      FILE *stream;
  268.      int size;
  269. {
  270.   register int regno;
  271.   register int mask, fmask;
  272.   register int nregs;
  273.   int offset, foffset, fpoffset;
  274.   extern char call_used_regs[];
  275.   int fsize = (size + 3) & -4;
  276.   int big = 0;
  277.   rtx insn = get_last_insn ();
  278.   
  279.   /* If the last insn was a BARRIER, we don't have to write any code.  */
  280.   if (GET_CODE (insn) == NOTE)
  281.     insn = prev_nonnote_insn (insn);
  282.   if (insn && GET_CODE (insn) == BARRIER)
  283.     {
  284.       /* Output just a no-op so that debuggers don't get confused
  285.      about which function the p