OSDN Git Service

2001-05-03 David O'Brien <obrien@FreeBSD.org>
[pf3gnuchains/gcc-fork.git] / gcc / config / m68k / crds.h
1 /* Definitions of target machine for GNU compiler;
2    Charles River Data Systems UNiverse/32.
3    Copyright (C) 1987, 1993, 1994, 1996, 1997, 1998, 1999, 2000
4    Free Software Foundation, Inc.
5    Contributed by Gary E. Miller (Gary_Edmunds_Miller@cup.portal.com)
6
7 This file is part of GNU CC.
8
9 GNU CC is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
13
14 GNU CC is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with GNU CC; see the file COPYING.  If not, write to
21 the Free Software Foundation, 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.  */
23
24 #define MOTOROLA                /* Use Motorola syntax rather than "MIT" */
25 #define SGS                     /* Uses SGS assembler */
26 #define SGS_SWITCH_TABLES       /* Different switch table handling */
27 #define SGS_NO_LI               /* Suppress jump table label usage */
28 #define CRDS                    /* Charles River Data Systems assembler */
29
30 #include "m68k/m68k.h"
31
32 /* Without STRUCTURE_SIZE_BOUNDARY, we can't ensure that structures are
33    aligned such that we can correctly extract bitfields from them.
34    Someone should check whether the usual compiler on the crds machine
35    provides the equivalent behavior of STRUCTURE_SIZE_BOUNDARY.  */
36 /* Set to 16 because all other m68k targets have it so */
37 #define STRUCTURE_SIZE_BOUNDARY 16
38
39 /* See m68k.h.  0 means 680[01]0 with no 68881.  */
40
41 #undef TARGET_DEFAULT
42 #define TARGET_DEFAULT 0
43
44 /* Don't try using XFmode.  */
45 #undef LONG_DOUBLE_TYPE_SIZE
46 #define LONG_DOUBLE_TYPE_SIZE 64
47
48 /* special flags to the unos assembler.  */
49
50 #undef ASM_SPEC
51 #define ASM_SPEC "-g"
52
53 #undef LIB_SPEC
54 #define LIB_SPEC "%{!p:%{!pg:-lunos}}%{p:-lc_p}%{pg:-lc_p}"
55
56 #undef STARTFILE_SPEC
57 #define STARTFILE_SPEC  \
58   "%{pg:gcrt0.o%s}%{!pg:%{p:mc68rt0.o%s}%{!p:c68rt0.o%s}}"
59
60 /* CC1 spec */
61 #if 0
62 /* c.sac only used in _s_call_r() in libunos.a and malloc() in libmalloc.a */
63 /* so we do not need to bother ! */
64 #define CC1_SPEC "-fpcc-struct-return"
65 #endif
66
67 /* -O2 for MAX optimization */
68 #undef CC1_SPEC
69 #define CC1_SPEC "%{O2:-fstrength-reduce}"
70
71 /* cpp has to support a #sccs directive for the /usr/include files */
72
73 #define SCCS_DIRECTIVE
74
75 /* Make output for SDB.  */
76
77 /* #define SDB_DEBUGGING_INFO UNOS casm has no debugging :-( */
78
79 /* UNOS need stack probe :-( */
80
81 #if 0
82 #define HAVE_probe 1
83 #define gen_probe()  gen_rtx_ASM_INPUT (VOIDmode, "tstb -2048(sp)\t;probe\n")
84 #else
85 #undef NEED_PROBE
86 #define NEED_PROBE (-2048)
87 #endif
88
89 /* use memcpy, memset instead of bcopy, etc. */
90
91 #define TARGET_MEM_FUNCTIONS
92
93 /* Define __HAVE_68881__ in preprocessor if -m68881 is specified.
94    This will control the use of inline 68881 insns in certain macros.  */
95
96 #undef CPP_SPEC
97 #define CPP_SPEC "%{m68881:-D__HAVE_68881__}"
98
99 /* Names to predefine in the preprocessor for this target machine.  */
100
101 #undef CPP_PREDEFINES
102 #define CPP_PREDEFINES "-Dmc68k -DM68000 -Dmc68000 -Dunos -Dunix -D__motorola__ -Asystem=unix  -Acpu=m68k -Amachine=m68k"
103
104 /* Register in which address to store a structure value
105    is passed to a function.  */
106 /* unos uses ".comm c.sac" returns &c.sac in d0 */
107 /* make pointer to c.sac ?
108 #undef STRUCT_VALUE_REGNUM
109 #define STRUCT_VALUE gen_rtx_MEM (Pmode, gen_rtx( , , ) )
110 */
111
112 #define BSS_SECTION_ASM_OP "\t.bss"
113
114 /* Specify how to pad function arguments.
115    Value should be `upward', `downward' or `none'.
116    Same as the default, except no padding for large or variable-size args.  */
117
118 #define FUNCTION_ARG_PADDING(MODE, TYPE)                                \
119   (((MODE) == BLKmode                                                   \
120     ? ((TYPE) && TREE_CODE (TYPE_SIZE (TYPE))   == INTEGER_CST          \
121        && int_size_in_bytes (TYPE) < PARM_BOUNDARY / BITS_PER_UNIT)     \
122     : GET_MODE_BITSIZE (MODE) < PARM_BOUNDARY)                          \
123    ? downward : none)
124
125 /* Override parts of m68k.h to fit the CRuDS assembler.  */
126
127 #undef TARGET_VERSION 
128 #define TARGET_VERSION fprintf (stderr, " (68k, CRDS/UNOS)");
129
130 /* Specify extra dir to search for include files.  */
131 #define SYSTEM_INCLUDE_DIR "/include"
132
133 /* Control the assembler format that we output.  */
134
135 /* Output at beginning of assembler file.  */
136
137 #undef ASM_FILE_START
138 #define ASM_FILE_START(FILE)    \
139   fprintf (FILE, ";#NO_APP\n");
140
141 /* Output to assembler file text saying following lines
142    may contain character constants, extra white space, comments, etc.  */
143
144 #undef ASM_APP_ON
145 #define ASM_APP_ON ";#APP\n"
146
147 /* Output to assembler file text saying following lines
148    no longer contain unusual constructs.  */
149
150 #undef ASM_APP_OFF 
151 #define ASM_APP_OFF ";#NO_APP\n"
152
153 /* The prefix for immediate operands.  */
154
155 #undef IMMEDIATE_PREFIX
156 #define IMMEDIATE_PREFIX "$"
157
158 /* This is how to output an assembler line defining a `double' constant.  */
159
160 #undef ASM_OUTPUT_DOUBLE
161 #define ASM_OUTPUT_DOUBLE(FILE,VALUE)  \
162 do { long l[2];                                         \
163      REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l);            \
164      fprintf (FILE, "\t.long 0x%x, 0x%x\n", l[0], l[1]);        \
165    } while (0)
166
167 /*unos has no .skip :-( */
168 #undef ASM_OUTPUT_SKIP
169 #define ASM_OUTPUT_SKIP(FILE,SIZE)              \
170     fprintf (FILE, "\t. = . + %u\n", (SIZE));   
171
172 /* This says how to output an assembler line
173    to define a local common symbol.  */
174 /* should use bss_section instead of data_section but this makes casm die ? */
175
176 #undef ASM_OUTPUT_LOCAL
177 #define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED)  \
178 { data_section ();                              \
179   if ((SIZE) > 1) fprintf (FILE, "\t.even\n");  \
180   assemble_name ((FILE), (NAME));               \
181   fprintf ((FILE), ":\t. = . + %u\n", (ROUNDED));}
182
183 /* This is how to output an insn to push a register on the stack.
184    It need not be very fast code.  */
185
186 #undef ASM_OUTPUT_REG_PUSH
187 #define ASM_OUTPUT_REG_PUSH(FILE,REGNO)  \
188   fprintf (FILE, "\tmovel %s,-(sp)\n", reg_names[REGNO])
189
190 /* This is how to output an insn to pop a register from the stack.
191    It need not be very fast code.  */
192
193 #undef ASM_OUTPUT_REG_POP
194 #define ASM_OUTPUT_REG_POP(FILE,REGNO)  \
195   fprintf (FILE, "\tmovel (sp)+,%s\n", reg_names[REGNO])
196
197 #undef  ASM_OUTPUT_ASCII
198 #define  ASM_OUTPUT_ASCII(FILE, P , SIZE)                               \
199 do {  int i;                                                            \
200           fprintf ((FILE), "\t.ascii \"");                              \
201           for (i = 0; i < (SIZE); i++)                                  \
202             {                                                           \
203               register int c = (P)[i];                                  \
204               if (i != 0 && (i / 200) * 200 == i)                       \
205                 fprintf ((FILE), "\"\n\t.ascii \"");                    \
206               if (c >= ' ' && c < 0177) {                               \
207                 if (c != '\"' && c != '\\') {                           \
208                   putc (c, (FILE));                                     \
209                   continue;                                             \
210                 }                                                       \
211                }                                                        \
212                /* brain dead asm doesn't understand char escapes */     \
213                fprintf ((FILE), "\"\n\t.byte\t%d\n\t.ascii \"", c);     \
214             }                                                           \
215           fprintf ((FILE), "\"\n");                                     \
216  } while (0)
217
218
219 /* Change all JBxx to Bxx.  Also change all DBRA to DBF.
220    Also change divs.l, etc., to divs, etc.  But don't change divsl.l.  */
221
222 #define ASM_OUTPUT_OPCODE(FILE, PTR)                    \
223 { if ((PTR)[0] == 'j' && (PTR)[1] == 'b')               \
224     { ++(PTR); }                                        \
225   else if ((PTR)[0] == 'd')                             \
226     {                                                   \
227       if (!strncmp ((PTR), "dbra", 4))                  \
228         { fprintf ((FILE), "dbf"); (PTR) += 4; }        \
229       else if (!strncmp ((PTR), "div", 3) && (PTR)[5] == ' ')  \
230         { fprintf ((FILE), "div%c", (PTR)[3]); (PTR) += 6; }   \
231     }                                                   \
232 }
233
234
235 #if 0
236 /* Print operand X (an rtx) in assembler syntax to file FILE.
237    CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
238    For `%' followed by punctuation, CODE is the punctuation and X is null.
239
240    On the 68000, we use several CODE characters:
241    '.' for dot needed in Motorola-style opcode names.
242    '-' for an operand pushing on the stack:
243        sp@-, -(sp) or -(%sp) depending on the style of syntax.
244    '+' for an operand pushing on the stack:
245        sp@+, (sp)+ or (%sp)+ depending on the style of syntax.
246    '@' for a reference to the top word on the stack:
247        sp@, (sp) or (%sp) depending on the style of syntax.
248    '#' for an immediate operand prefix (# in MIT and Motorola syntax
249        but & in SGS syntax, $ in unos syntax).
250    '!' for the fpcr register (used in some float-to-fixed conversions).
251
252    'b' for byte insn (no effect, on the Sun; this is for the ISI).
253    'd' to force memory addressing to be absolute, not relative.
254    'f' for float insn (print a CONST_DOUBLE as a float rather than in hex)
255    'w' for FPA insn (print a CONST_DOUBLE as a SunFPA constant rather
256        than directly).  Second part of 'y' below.
257    'x' for float insn (print a CONST_DOUBLE as a float rather than in hex),
258        or print pair of registers as rx:ry.
259    'y' for a FPA insn (print pair of registers as rx:ry).  This also outputs
260        CONST_DOUBLE's as SunFPA constant RAM registers if
261        possible, so it should not be used except for the SunFPA. */
262
263 #undef PRINT_OPERAND_PUNCT_VALID_P
264 #define PRINT_OPERAND_PUNCT_VALID_P(CODE)                               \
265   ((CODE) == '.' || (CODE) == '#' || (CODE) == '-'                      \
266    || (CODE) == '+' || (CODE) == '@' || (CODE) == '!')
267
268 #undef PRINT_OPERAND
269 #define PRINT_OPERAND(FILE, X, CODE)  \
270 { int i;                                                                \
271   if (CODE == '.') ;                                                    \
272   else if (CODE == '#') fprintf (FILE, "$");                            \
273   else if (CODE == '-') fprintf (FILE, "-(sp)");                        \
274   else if (CODE == '+') fprintf (FILE, "(sp)+");                        \
275   else if (CODE == '@') fprintf (FILE, "(sp)");                         \
276   else if (CODE == '!') fprintf (FILE, "fpcr");                         \
277   else if (CODE == '/')                                                 \
278     ;                                                                   \
279   else if (GET_CODE (X) == REG)                                         \
280     { if (REGNO (X) < 16 && (CODE == 'y' || CODE == 'x') && GET_MODE (X) == DFmode)     \
281         fprintf (FILE, "%s:%s", reg_names[REGNO (X)], reg_names[REGNO (X)+1]); \
282       else                                                              \
283         fprintf (FILE, "%s", reg_names[REGNO (X)]);                     \
284     }                                                                   \
285   else if (GET_CODE (X) == MEM)                                         \
286     {                                                                   \
287       output_address (XEXP (X, 0));                                     \
288       if (CODE == 'd' && ! TARGET_68020                                 \
289           && CONSTANT_ADDRESS_P (XEXP (X, 0)))                          \
290         /* fprintf (FILE, ".l") */;                                     \
291     }                                                                   \
292   else if ((CODE == 'y' || CODE == 'w')                                 \
293            && GET_CODE(X) == CONST_DOUBLE                               \
294            && (i = standard_sun_fpa_constant_p (X)))                    \
295     fprintf (FILE, "%%%d", i & 0x1ff);                                  \
296   else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == SFmode)      \
297     { REAL_VALUE_TYPE r; long l;                                        \
298       REAL_VALUE_FROM_CONST_DOUBLE (r, X);                              \
299       if (CODE == 'f')                                                  \
300         ASM_OUTPUT_FLOAT_OPERAND (CODE, FILE, r);                       \
301       else                                                              \
302         { REAL_VALUE_TO_TARGET_SINGLE (r, l);                           \
303           fprintf (FILE, "$0x%x", l); } }                               \
304   else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == DFmode)      \
305     { REAL_VALUE_TYPE r;                                                \
306       REAL_VALUE_FROM_CONST_DOUBLE (r, X);                              \
307       ASM_OUTPUT_DOUBLE_OPERAND (FILE, r); }                            \
308   else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == XFmode)      \
309     { REAL_VALUE_TYPE r;                                                \
310       REAL_VALUE_FROM_CONST_DOUBLE (r, X);                              \
311       ASM_OUTPUT_LONG_DOUBLE_OPERAND (FILE, r); }                       \
312   else { putc ('$', FILE); output_addr_const (FILE, X); }}
313 #endif
314 \f
315 /* Note that this contains a kludge that knows that the only reason
316    we have an address (plus (label_ref...) (reg...))
317    is in the insn before a tablejump, and we know that m68k.md
318    generates a label LInnn: on such an insn.  */
319 #undef PRINT_OPERAND_ADDRESS
320 #define PRINT_OPERAND_ADDRESS(FILE, ADDR)  \
321 { register rtx reg1, reg2, breg, ireg;                                  \
322   register rtx addr = ADDR;                                             \
323   rtx offset;                                                           \
324   switch (GET_CODE (addr))                                              \
325     {                                                                   \
326     case REG:                                                           \
327       fprintf (FILE, "(%s)", reg_names[REGNO (addr)]);                  \
328       break;                                                            \
329     case PRE_DEC:                                                       \
330       fprintf (FILE, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]);       \
331       break;                                                            \
332     case POST_INC:                                                      \
333       fprintf (FILE, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]);       \
334       break;                                                            \
335     case PLUS:                                                          \
336       reg1 = 0; reg2 = 0;                                               \
337       ireg = 0; breg = 0;                                               \
338       offset = 0;                                                       \
339       if (CONSTANT_ADDRESS_P (XEXP (addr, 0)))                          \
340         {                                                               \
341           offset = XEXP (addr, 0);                                      \
342           addr = XEXP (addr, 1);                                        \
343         }                                                               \
344       else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)))                     \
345         {                                                               \
346           offset = XEXP (addr, 1);                                      \
347           addr = XEXP (addr, 0);                                        \
348         }                                                               \
349       if (GET_CODE (addr) != PLUS) ;                                    \
350       else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND)                \
351         {                                                               \
352           reg1 = XEXP (addr, 0);                                        \
353           addr = XEXP (addr, 1);                                        \
354         }                                                               \
355       else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND)                \
356         {                                                               \
357           reg1 = XEXP (addr, 1);                                        \
358           addr = XEXP (addr, 0);                                        \
359         }                                                               \
360       else if (GET_CODE (XEXP (addr, 0)) == MULT)                       \
361         {                                                               \
362           reg1 = XEXP (addr, 0);                                        \
363           addr = XEXP (addr, 1);                                        \
364         }                                                               \
365       else if (GET_CODE (XEXP (addr, 1)) == MULT)                       \
366         {                                                               \
367           reg1 = XEXP (addr, 1);                                        \
368           addr = XEXP (addr, 0);                                        \
369         }                                                               \
370       else if (GET_CODE (XEXP (addr, 0)) == REG)                        \
371         {                                                               \
372           reg1 = XEXP (addr, 0);                                        \
373           addr = XEXP (addr, 1);                                        \
374         }                                                               \
375       else if (GET_CODE (XEXP (addr, 1)) == REG)                        \
376         {                                                               \
377           reg1 = XEXP (addr, 1);                                        \
378           addr = XEXP (addr, 0);                                        \
379         }                                                               \
380       if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT             \
381           || GET_CODE (addr) == SIGN_EXTEND)                            \
382         { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; }     \
383       if (offset != 0) { if (addr != 0) abort (); addr = offset; }      \
384       if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND                      \
385                     || GET_CODE (reg1) == MULT))                        \
386           || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2))))         \
387         { breg = reg2; ireg = reg1; }                                   \
388       else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1)))         \
389         { breg = reg1; ireg = reg2; }                                   \
390       if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF)       \
391         { int scale = 1;                                                \
392           if (GET_CODE (ireg) == MULT)                                  \
393             { scale = INTVAL (XEXP (ireg, 1));                          \
394               ireg = XEXP (ireg, 0); }                                  \
395           if (GET_CODE (ireg) == SIGN_EXTEND)                           \
396             fprintf (FILE, "L%d-LI%d-2(pc,%s.w",                        \
397                      CODE_LABEL_NUMBER (XEXP (addr, 0)),                \
398                      CODE_LABEL_NUMBER (XEXP (addr, 0)),                \
399                      reg_names[REGNO (XEXP (ireg, 0))]);                \
400           else                                                          \
401             fprintf (FILE, "L%d-LI%d-2(pc,%s.l",                        \
402                      CODE_LABEL_NUMBER (XEXP (addr, 0)),                \
403                      CODE_LABEL_NUMBER (XEXP (addr, 0)),                \
404                      reg_names[REGNO (ireg)]);                          \
405           if (scale != 1) fprintf (FILE, ":%d", scale);                 \
406           putc (')', FILE);                                             \
407           break; }                                                      \
408       if (breg != 0 && ireg == 0 && GET_CODE (addr) == LABEL_REF)       \
409         { fprintf (FILE, "L%d-LI%d-2(pc,%s.l",                          \
410                    CODE_LABEL_NUMBER (XEXP (addr, 0)),                  \
411                    CODE_LABEL_NUMBER (XEXP (addr, 0)),                  \
412                    reg_names[REGNO (breg)]);                            \
413           putc (')', FILE);                                             \
414           break; }                                                      \
415       if (ireg != 0 || breg != 0)                                       \
416         { int scale = 1;                                                \
417           if (breg == 0)                                                \
418             abort ();                                                   \
419           if (addr && GET_CODE (addr) == LABEL_REF) abort ();           \
420           if (addr != 0)                                                \
421             output_addr_const (FILE, addr);                             \
422           fprintf (FILE, "(%s", reg_names[REGNO (breg)]);               \
423           if (breg != 0 && ireg != 0)                                   \
424             putc (',', FILE);                                           \
425           if (ireg != 0 && GET_CODE (ireg) == MULT)                     \
426             { scale = INTVAL (XEXP (ireg, 1));                          \
427               ireg = XEXP (ireg, 0); }                                  \
428           if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND)              \
429             fprintf (FILE, "%s.w", reg_names[REGNO (XEXP (ireg, 0))]);  \
430           else if (ireg != 0)                                           \
431             fprintf (FILE, "%s.l", reg_names[REGNO (ireg)]);            \
432           if (scale != 1) fprintf (FILE, ":%d", scale);                 \
433           putc (')', FILE);                                             \
434           break;                                                        \
435         }                                                               \
436       else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF)               \
437         { fprintf (FILE, "L%d-LI%d-2(pc,%s.l)",                         \
438                    CODE_LABEL_NUMBER (XEXP (addr, 0)),                  \
439                    CODE_LABEL_NUMBER (XEXP (addr, 0)),                  \
440                    reg_names[REGNO (reg1)]);                            \
441           break; }                                                      \
442     default:                                                            \
443       if (GET_CODE (addr) == CONST_INT                                  \
444           && INTVAL (addr) < 0x8000                                     \
445           && INTVAL (addr) >= -0x8000)                                  \
446         fprintf (FILE, "%d", INTVAL (addr));                            \
447       else                                                              \
448         output_addr_const (FILE, addr);                                 \
449     }}
450 \f
451 #define ASM_OUTPUT_SOURCE_FILENAME(FILE, FILENAME) \
452   do {  fprintf (FILE, "\t; file\t");                   \
453         output_quoted_string (FILE, FILENAME);          \
454         fprintf (FILE, "\n");                           \
455   } while (0)
456
457 #define ASM_OUTPUT_SOURCE_LINE(FILE, LINENO)    \
458   fprintf (FILE, "\t; ln\t%d\n",                        \
459            (sdb_begin_function_line             \
460             ? last_linenum - sdb_begin_function_line : 1))
461
462 /* This macro generates the assembly code for function entry.
463    FILE is a stdio stream to output the code to.
464    SIZE is an int: how many units of temporary storage to allocate.
465    Refer to the array `regs_ever_live' to determine which registers
466    to save; `regs_ever_live[I]' is nonzero if register number I
467    is ever used in the function.  This macro is responsible for
468    knowing which registers should not be saved even if used.  */
469
470 /* Note that the order of the bit mask for fmovem is the opposite
471    of the order for movem!  */
472
473 #undef FUNCTION_PROLOGUE
474 #define FUNCTION_PROLOGUE(FILE, SIZE)     \
475 { register int regno;                                           \
476   register int mask = 0;                                        \
477   extern char call_used_regs[];                                 \
478   int fsize = ((SIZE) + 3) & -4;                                \
479   /* unos stack probe */                                        \
480   if ( fsize > 30000 ) {                                        \
481     fprintf (FILE, "\tmovel sp,a0\n");                          \
482     fprintf (FILE, "\taddl $-%d,a0\n", 2048 + fsize);           \
483     fprintf (FILE, "\ttstb (a0)\n");                            \
484   } else {                                                      \
485     fprintf (FILE, "\ttstb -%d(sp)\n", 2048 + fsize);           \
486   }                                                             \
487   if (frame_pointer_needed)                                     \
488     { if (TARGET_68020 || fsize < 0x8000)                       \
489         fprintf (FILE, "\tlink a6,$%d\n", -fsize);              \
490       else                                                      \
491         fprintf (FILE, "\tlink a6,$0\n\tsubl $%d,sp\n", fsize); }  \
492   else if (fsize)                                                     \
493     {                                                                 \
494       /* Adding negative number is faster on the 68040.  */           \
495       if (fsize + 4 < 0x8000)                                         \
496         {                                                             \
497           fprintf (FILE, "\tadd.w #%d,sp\n", - (fsize + 4));          \
498         }                                                             \
499       else                                                            \
500         {                                                             \
501           fprintf (FILE, "\tadd.l #%d,sp\n", - (fsize + 4));          \
502         }                                                             \
503     }                                                                 \
504   for (regno = 16; regno < 24; regno++)                         \
505     if (regs_ever_live[regno] && ! call_used_regs[regno])       \
506        mask |= 1 << (regno - 16);                               \
507   if ((mask & 0xff) != 0)                                       \
508     fprintf (FILE, "\tfmovem $0x%x,-(sp)\n", mask & 0xff);       \
509   mask = 0;                                                     \
510   for (regno = 0; regno < 16; regno++)                          \
511     if (regs_ever_live[regno] && ! call_used_regs[regno])       \
512        mask |= 1 << (15 - regno);                               \
513   if (frame_pointer_needed)                                     \
514     mask &= ~ (1 << (15-FRAME_POINTER_REGNUM));                 \
515   if (exact_log2 (mask) >= 0)                                   \
516     fprintf (FILE, "\tmovel %s,-(sp)\n", reg_names[15 - exact_log2 (mask)]);  \
517   else if (mask) fprintf (FILE, "\tmovem $0x%x,-(sp)\n", mask); }
518
519 /* Must put address in  %a0 , not  %d0 . -- LGM, 7/15/88 */
520 /* UNOS ?? */
521 #undef FUNCTION_PROFILER
522 #define FUNCTION_PROFILER(FILE, LABEL_NO)       \
523     fprintf (FILE, "\tmovl &LP%%%d,%%a0\n\tjsr mcount\n", (LABEL_NO))
524
525 /* This macro generates the assembly code for function exit,
526    on machines that need it.  If FUNCTION_EPILOGUE is not defined
527    then individual return instructions are generated for each
528    return statement.  Args are same as for FUNCTION_PROLOGUE.
529
530    The function epilogue should not depend on the current stack pointer!
531    It should use the frame pointer only.  This is mandatory because
532    of alloca; we also take advantage of it to omit stack adjustments
533    before returning.  */
534
535 #undef FUNCTION_EPILOGUE
536 #define FUNCTION_EPILOGUE(FILE, SIZE) \
537 { register int regno;                                           \
538   register int mask, fmask;                                     \
539   register int nregs;                                           \
540   int offset, foffset, fpoffset;                                \
541   extern char call_used_regs[];                                 \
542   int fsize = ((SIZE) + 3) & -4;                                \
543   int big = 0;                                                  \
544   nregs = 0;  fmask = 0; fpoffset = 0;                          \
545   for (regno = 16; regno < 24; regno++)                         \
546     if (regs_ever_live[regno] && ! call_used_regs[regno])       \
547       { nregs++; fmask |= 1 << (23 - regno); }                  \
548   foffset = fpoffset + nregs * 12;                              \
549   nregs = 0;  mask = 0;                                         \
550   if (frame_pointer_needed) regs_ever_live[FRAME_POINTER_REGNUM] = 0; \
551   for (regno = 0; regno < 16; regno++)                          \
552     if (regs_ever_live[regno] && ! call_used_regs[regno])       \
553       { nregs++; mask |= 1 << regno; }                          \
554   offset = foffset + nregs * 4;                                 \
555   if (offset + fsize >= 0x8000                                  \
556       && frame_pointer_needed                                   \
557       && (mask || fmask || fpoffset))                           \
558     { fprintf (FILE, "\tmovel $%d,a0\n", -fsize);               \
559       fsize = 0, big = 1; }                                     \
560   if (exact_log2 (mask) >= 0) {                                 \
561     if (big)                                                    \
562       fprintf (FILE, "\tmovel -%d(a6,a0.l),%s\n",               \
563                offset + fsize, reg_names[exact_log2 (mask)]);   \
564     else if (! frame_pointer_needed)                            \
565       fprintf (FILE, "\tmovel (sp)+,%s\n",                      \
566                reg_names[exact_log2 (mask)]);                   \
567     else                                                        \
568       fprintf (FILE, "\tmovel -%d(a6),%s\n",                    \
569                offset + fsize, reg_names[exact_log2 (mask)]); } \
570   else if (mask) {                                              \
571     if (big)                                                    \
572       fprintf (FILE, "\tmovem -%d(a6,a0.l),$0x%x\n",            \
573                offset + fsize, mask);                           \
574     else if (! frame_pointer_needed)                            \
575       fprintf (FILE, "\tmovem (sp)+,$0x%x\n", mask);            \
576     else                                                        \
577       fprintf (FILE, "\tmovem -%d(a6),$0x%x\n",         \
578                offset + fsize, mask); }                         \
579   if (fmask) {                                                  \
580     if (big)                                                    \
581       fprintf (FILE, "\tfmovem -%d(a6,a0.l),$0x%x\n",           \
582                foffset + fsize, fmask);                         \
583     else if (! frame_pointer_needed)                            \
584       fprintf (FILE, "\tfmovem (sp)+,$0x%x\n", fmask);          \
585     else                                                        \
586       fprintf (FILE, "\tfmovem -%d(a6),$0x%x\n",                \
587                foffset + fsize, fmask); }                       \
588   if (fpoffset != 0)                                            \
589     for (regno = 55; regno >= 24; regno--)                      \
590       if (regs_ever_live[regno] && ! call_used_regs[regno]) {   \
591         if (big)                                                \
592           fprintf(FILE, "\tfpmoved -%d(a6,a0.l), %s\n", \
593                   fpoffset + fsize, reg_names[regno]);          \
594         else if (! frame_pointer_needed)                        \
595           fprintf(FILE, "\tfpmoved (sp)+, %s\n",                        \
596                   reg_names[regno]);                            \
597         else                                                    \
598           fprintf(FILE, "\tfpmoved -%d(a6), %s\n",              \
599                   fpoffset + fsize, reg_names[regno]);          \
600         fpoffset -= 8;                                          \
601       }                                                         \
602   if (frame_pointer_needed)                                     \
603     fprintf (FILE, "\tunlk a6\n");                              \
604   else if (fsize)                                                     \
605     {                                                                 \
606       if (fsize + 4 < 0x8000)                                         \
607         {                                                             \
608           fprintf (FILE, "\tadd.w #%d,sp\n", fsize + 4);              \
609         }                                                             \
610       else                                                            \
611         {                                                             \
612           fprintf (FILE, "\tadd.l #%d,sp\n", fsize + 4);              \
613         }                                                             \
614     }                                                                 \
615   if (current_function_pops_args)                               \
616     fprintf (FILE, "\trtd $%d\n", current_function_pops_args);  \
617   else fprintf (FILE, "\trts\n"); }
618