OSDN Git Service

* c-common.c, c-common.h, c-decl.c, c-lex.c, c-parse.in,
[pf3gnuchains/gcc-fork.git] / gcc / config / m88k / m88k.c
1 /* Subroutines for insn-output.c for Motorola 88000.
2    Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
3    2001 Free Software Foundation, Inc. 
4    Contributed by Michael Tiemann (tiemann@mcc.com)
5    Currently maintained by (gcc@dg-rtp.dg.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 #include "config.h"
25 #include "system.h"
26 #include "rtl.h"
27 #include "regs.h"
28 #include "hard-reg-set.h"
29 #include "real.h"
30 #include "insn-config.h"
31 #include "conditions.h"
32 #include "output.h"
33 #include "insn-attr.h"
34 #include "tree.h"
35 #include "function.h"
36 #include "expr.h"
37 #include "libfuncs.h"
38 #include "c-tree.h"
39 #include "flags.h"
40 #include "recog.h"
41 #include "toplev.h"
42 #include "tm_p.h"
43 #include "target.h"
44 #include "target-def.h"
45
46 extern FILE *asm_out_file;
47
48 const char *m88k_pound_sign = ""; /* Either # for SVR4 or empty for SVR3 */
49 const char *m88k_short_data;
50 const char *m88k_version;
51 char m88k_volatile_code;
52
53 unsigned m88k_gp_threshold = 0;
54 int m88k_prologue_done  = 0;    /* Ln directives can now be emitted */
55 int m88k_function_number = 0;   /* Counter unique to each function */
56 int m88k_fp_offset      = 0;    /* offset of frame pointer if used */
57 int m88k_stack_size     = 0;    /* size of allocated stack (including frame) */
58 int m88k_case_index;
59
60 rtx m88k_compare_reg;           /* cmp output pseudo register */
61 rtx m88k_compare_op0;           /* cmpsi operand 0 */
62 rtx m88k_compare_op1;           /* cmpsi operand 1 */
63
64 enum processor_type m88k_cpu;   /* target cpu */
65
66 static void m88k_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
67 static void m88k_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
68 static void m88k_output_function_end_prologue PARAMS ((FILE *));
69 static void m88k_output_function_begin_epilogue PARAMS ((FILE *));
70 #if defined (CTOR_LIST_BEGIN) && !defined (OBJECT_FORMAT_ELF)
71 static void m88k_svr3_asm_out_constructor PARAMS ((rtx, int));
72 static void m88k_svr3_asm_out_destructor PARAMS ((rtx, int));
73 #endif
74
75 static int m88k_adjust_cost PARAMS ((rtx, rtx, rtx, int));
76 \f
77 /* Initialize the GCC target structure.  */
78 #undef TARGET_ASM_BYTE_OP
79 #define TARGET_ASM_BYTE_OP "\tbyte\t"
80 #undef TARGET_ASM_ALIGNED_HI_OP
81 #define TARGET_ASM_ALIGNED_HI_OP "\thalf\t"
82 #undef TARGET_ASM_ALIGNED_SI_OP
83 #define TARGET_ASM_ALIGNED_SI_OP "\tword\t"
84 #undef TARGET_ASM_UNALIGNED_HI_OP
85 #define TARGET_ASM_UNALIGNED_HI_OP "\tuahalf\t"
86 #undef TARGET_ASM_UNALIGNED_SI_OP
87 #define TARGET_ASM_UNALIGNED_SI_OP "\tuaword\t"
88
89 #undef TARGET_ASM_FUNCTION_PROLOGUE
90 #define TARGET_ASM_FUNCTION_PROLOGUE m88k_output_function_prologue
91 #undef TARGET_ASM_FUNCTION_END_PROLOGUE
92 #define TARGET_ASM_FUNCTION_END_PROLOGUE m88k_output_function_end_prologue
93 #undef TARGET_ASM_FUNCTION_BEGIN_EPILOGUE
94 #define TARGET_ASM_FUNCTION_BEGIN_EPILOGUE m88k_output_function_begin_epilogue
95 #undef TARGET_ASM_FUNCTION_EPILOGUE
96 #define TARGET_ASM_FUNCTION_EPILOGUE m88k_output_function_epilogue
97
98 #undef TARGET_SCHED_ADJUST_COST
99 #define TARGET_SCHED_ADJUST_COST m88k_adjust_cost
100
101 struct gcc_target targetm = TARGET_INITIALIZER;
102 \f
103 /* Determine what instructions are needed to manufacture the integer VALUE
104    in the given MODE.  */
105
106 enum m88k_instruction
107 classify_integer (mode, value)
108      enum machine_mode mode;
109      register int value;
110 {
111   if (value == 0)
112     return m88k_zero;
113   else if (SMALL_INTVAL (value))
114     return m88k_or;
115   else if (SMALL_INTVAL (-value))
116     return m88k_subu;
117   else if (mode == HImode)
118     return m88k_or_lo16;
119   else if (mode == QImode)
120     return m88k_or_lo8;
121   else if ((value & 0xffff) == 0)
122     return m88k_oru_hi16;
123   else if (integer_ok_for_set (value))
124     return m88k_set;
125   else
126     return m88k_oru_or;
127 }
128
129 /* Return the bit number in a compare word corresponding to CONDITION.  */
130
131 int
132 condition_value (condition)
133      rtx condition;
134 {
135   switch (GET_CODE (condition))
136     {
137     case EQ: return 2;
138     case NE: return 3;
139     case GT: return 4;
140     case LE: return 5;
141     case LT: return 6;
142     case GE: return 7;
143     case GTU: return 8;
144     case LEU: return 9;
145     case LTU: return 10;
146     case GEU: return 11;
147     default: abort ();
148     }
149 }
150
151 int
152 integer_ok_for_set (value)
153      register unsigned value;
154 {
155   /* All the "one" bits must be contiguous.  If so, MASK + 1 will be
156      a power of two or zero.  */
157   register unsigned mask = (value | (value - 1));
158   return (value && POWER_OF_2_or_0 (mask + 1));
159 }
160
161 const char *
162 output_load_const_int (mode, operands)
163      enum machine_mode mode;
164      rtx *operands;
165 {
166   static const char *const patterns[] =
167     { "or %0,%#r0,0",
168       "or %0,%#r0,%1",
169       "subu %0,%#r0,%n1",
170       "or %0,%#r0,%h1",
171       "or %0,%#r0,%q1",
172       "set %0,%#r0,%s1",
173       "or.u %0,%#r0,%X1",
174       "or.u %0,%#r0,%X1\n\tor %0,%0,%x1",
175     };
176
177   if (! REG_P (operands[0])
178       || GET_CODE (operands[1]) != CONST_INT)
179     abort ();
180   return patterns[classify_integer (mode, INTVAL (operands[1]))];
181 }
182
183 /* These next two routines assume that floating point numbers are represented
184    in a manner which is consistent between host and target machines.  */
185
186 const char *
187 output_load_const_float (operands)
188      rtx *operands;
189 {
190   /* These can return 0 under some circumstances when cross-compiling.  */
191   operands[0] = operand_subword (operands[0], 0, 0, SFmode);
192   operands[1] = operand_subword (operands[1], 0, 0, SFmode);
193
194   return output_load_const_int (SImode, operands);
195 }
196
197 const char *
198 output_load_const_double (operands)
199      rtx *operands;
200 {
201   rtx latehalf[2];
202
203   /* These can return zero on some cross-compilers, but there's nothing
204      we can do about it.  */
205   latehalf[0] = operand_subword (operands[0], 1, 0, DFmode);
206   latehalf[1] = operand_subword (operands[1], 1, 0, DFmode);
207
208   operands[0] = operand_subword (operands[0], 0, 0, DFmode);
209   operands[1] = operand_subword (operands[1], 0, 0, DFmode);
210
211   output_asm_insn (output_load_const_int (SImode, operands), operands);
212
213   operands[0] = latehalf[0];
214   operands[1] = latehalf[1];
215
216   return output_load_const_int (SImode, operands);
217 }
218
219 const char *
220 output_load_const_dimode (operands)
221      rtx *operands;
222 {
223   rtx latehalf[2];
224
225   latehalf[0] = operand_subword (operands[0], 1, 0, DImode);
226   latehalf[1] = operand_subword (operands[1], 1, 0, DImode);
227
228   operands[0] = operand_subword (operands[0], 0, 0, DImode);
229   operands[1] = operand_subword (operands[1], 0, 0, DImode);
230
231   output_asm_insn (output_load_const_int (SImode, operands), operands);
232
233   operands[0] = latehalf[0];
234   operands[1] = latehalf[1];
235
236   return output_load_const_int (SImode, operands);
237 }
238 \f
239 /* Emit insns to move operands[1] into operands[0].
240
241    Return 1 if we have written out everything that needs to be done to
242    do the move.  Otherwise, return 0 and the caller will emit the move
243    normally.
244
245    SCRATCH if non zero can be used as a scratch register for the move
246    operation.  It is provided by a SECONDARY_RELOAD_* macro if needed.  */
247
248 int
249 emit_move_sequence (operands, mode, scratch)
250      rtx *operands;
251      enum machine_mode mode;
252      rtx scratch;
253 {
254   register rtx operand0 = operands[0];
255   register rtx operand1 = operands[1];
256
257   if (CONSTANT_P (operand1) && flag_pic
258       && pic_address_needs_scratch (operand1))
259     operands[1] = operand1 = legitimize_address (1, operand1, 0, 0);
260
261   /* Handle most common case first: storing into a register.  */
262   if (register_operand (operand0, mode))
263     {
264       if (register_operand (operand1, mode)
265           || (GET_CODE (operand1) == CONST_INT && SMALL_INT (operand1))
266           || GET_CODE (operand1) == HIGH
267           /* Only `general_operands' can come here, so MEM is ok.  */
268           || GET_CODE (operand1) == MEM)
269         {
270           /* Run this case quickly.  */
271           emit_insn (gen_rtx_SET (VOIDmode, operand0, operand1));
272           return 1;
273         }
274     }
275   else if (GET_CODE (operand0) == MEM)
276     {
277       if (register_operand (operand1, mode)
278           || (operand1 == const0_rtx && GET_MODE_SIZE (mode) <= UNITS_PER_WORD))
279         {
280           /* Run this case quickly.  */
281           emit_insn (gen_rtx_SET (VOIDmode, operand0, operand1));
282           return 1;
283         }
284       if (! reload_in_progress && ! reload_completed)
285         {
286           operands[0] = validize_mem (operand0);
287           operands[1] = operand1 = force_reg (mode, operand1);
288         }
289     }
290
291   /* Simplify the source if we need to.  */
292   if (GET_CODE (operand1) != HIGH && immediate_operand (operand1, mode))
293     {
294       if (GET_CODE (operand1) != CONST_INT
295           && GET_CODE (operand1) != CONST_DOUBLE)
296         {
297           rtx temp = ((reload_in_progress || reload_completed)
298                       ? operand0 : 0);
299           operands[1] = legitimize_address (flag_pic
300                                             && symbolic_address_p (operand1),
301                                             operand1, temp, scratch);
302           if (mode != SImode)
303             operands[1] = gen_rtx_SUBREG (mode, operands[1], 0);
304         }
305     }
306
307   /* Now have insn-emit do whatever it normally does.  */
308   return 0;
309 }
310
311 /* Return a legitimate reference for ORIG (either an address or a MEM)
312    using the register REG.  If PIC and the address is already
313    position-independent, use ORIG.  Newly generated position-independent
314    addresses go into a reg.  This is REG if non zero, otherwise we
315    allocate register(s) as necessary.  If this is called during reload,
316    and we need a second temp register, then we use SCRATCH, which is
317    provided via the SECONDARY_INPUT_RELOAD_CLASS mechanism.  */
318
319 struct rtx_def *
320 legitimize_address (pic, orig, reg, scratch)
321      int pic;
322      rtx orig;
323      rtx reg;
324      rtx scratch;
325 {
326   rtx addr = (GET_CODE (orig) == MEM ? XEXP (orig, 0) : orig);
327   rtx new = orig;
328   rtx temp, insn;
329
330   if (pic)
331     {
332       if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
333         {
334           if (reg == 0)
335             {
336               if (reload_in_progress || reload_completed)
337                 abort ();
338               else
339                 reg = gen_reg_rtx (Pmode);
340             }
341
342           if (flag_pic == 2)
343             {
344               /* If not during reload, allocate another temp reg here for
345                  loading in the address, so that these instructions can be
346                  optimized properly.  */
347               temp = ((reload_in_progress || reload_completed)
348                       ? reg : gen_reg_rtx (Pmode));
349
350               emit_insn (gen_rtx_SET
351                          (VOIDmode, temp,
352                           gen_rtx_HIGH (SImode,
353                                         gen_rtx_UNSPEC (SImode,
354                                                         gen_rtvec (1, addr),
355                                                         0))));
356
357               emit_insn (gen_rtx_SET
358                          (VOIDmode, temp,
359                           gen_rtx_LO_SUM (SImode, temp,
360                                           gen_rtx_UNSPEC (SImode,
361                                                           gen_rtvec (1, addr),
362                                                           0))));
363               addr = temp;
364             }
365
366           new = gen_rtx_MEM (Pmode,
367                              gen_rtx_PLUS (SImode,
368                                            pic_offset_table_rtx, addr));
369
370           current_function_uses_pic_offset_table = 1;
371           RTX_UNCHANGING_P (new) = 1;
372           insn = emit_move_insn (reg, new);
373           /* Put a REG_EQUAL note on this insn, so that it can be optimized
374              by loop.  */
375           REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig,
376                                                 REG_NOTES (insn));
377           new = reg;
378         }
379       else if (GET_CODE (addr) == CONST)
380         {
381           rtx base;
382
383           if (GET_CODE (XEXP (addr, 0)) == PLUS
384               && XEXP (XEXP (addr, 0), 0) == pic_offset_table_rtx)
385             return orig;
386
387           if (reg == 0)
388             {
389               if (reload_in_progress || reload_completed)
390                 abort ();
391               else
392                 reg = gen_reg_rtx (Pmode);
393             }
394
395           if (GET_CODE (XEXP (addr, 0)) != PLUS) abort ();
396
397           base = legitimize_address (1, XEXP (XEXP (addr, 0), 0), reg, 0);
398           addr = legitimize_address (1, XEXP (XEXP (addr, 0), 1),
399                                      base == reg ? 0 : reg, 0);
400
401           if (GET_CODE (addr) == CONST_INT)
402             {
403               if (ADD_INT (addr))
404                 return plus_constant (base, INTVAL (addr));
405               else if (! reload_in_progress && ! reload_completed)
406                 addr = force_reg (Pmode, addr);
407               /* We can't create any new registers during reload, so use the
408                  SCRATCH reg provided by the reload_insi pattern.  */
409               else if (scratch)
410                 {
411                   emit_move_insn (scratch, addr);
412                   addr = scratch;
413                 }
414               else
415                 /* If we reach here, then the SECONDARY_INPUT_RELOAD_CLASS
416                    macro needs to be adjusted so that a scratch reg is provided
417                    for this address.  */
418                 abort ();
419             }
420           new = gen_rtx_PLUS (SImode, base, addr);
421           /* Should we set special REG_NOTEs here?  */
422         }
423     }
424   else if (! SHORT_ADDRESS_P (addr, temp))
425     {
426       if (reg == 0)
427         {
428           if (reload_in_progress || reload_completed)
429             abort ();
430           else
431             reg = gen_reg_rtx (Pmode);
432         }
433
434       emit_insn (gen_rtx_SET (VOIDmode,
435                               reg, gen_rtx_HIGH (SImode, addr)));
436       new = gen_rtx_LO_SUM (SImode, reg, addr);
437     }
438
439   if (new != orig
440       && GET_CODE (orig) == MEM)
441     {
442       new = gen_rtx_MEM (GET_MODE (orig), new);
443       MEM_COPY_ATTRIBUTES (new, orig);
444     }
445   return new;
446 }
447 \f
448 /* Support functions for code to emit a block move.  There are four methods
449    used to perform the block move:
450    + call memcpy
451    + call the looping library function, e.g. __movstrSI64n8
452    + call a non-looping library function, e.g. __movstrHI15x11
453    + produce an inline sequence of ld/st instructions
454
455    The parameters below describe the library functions produced by
456    movstr-m88k.sh.  */
457
458 #define MOVSTR_LOOP     64 /* __movstrSI64n68 .. __movstrSI64n8 */
459 #define MOVSTR_QI       16 /* __movstrQI16x16 .. __movstrQI16x2 */
460 #define MOVSTR_HI       48 /* __movstrHI48x48 .. __movstrHI48x4 */
461 #define MOVSTR_SI       96 /* __movstrSI96x96 .. __movstrSI96x8 */
462 #define MOVSTR_DI       96 /* __movstrDI96x96 .. __movstrDI96x16 */
463 #define MOVSTR_ODD_HI   16 /* __movstrHI15x15 .. __movstrHI15x5 */
464 #define MOVSTR_ODD_SI   48 /* __movstrSI47x47 .. __movstrSI47x11,
465                               __movstrSI46x46 .. __movstrSI46x10,
466                               __movstrSI45x45 .. __movstrSI45x9 */
467 #define MOVSTR_ODD_DI   48 /* __movstrDI47x47 .. __movstrDI47x23,
468                               __movstrDI46x46 .. __movstrDI46x22,
469                               __movstrDI45x45 .. __movstrDI45x21,
470                               __movstrDI44x44 .. __movstrDI44x20,
471                               __movstrDI43x43 .. __movstrDI43x19,
472                               __movstrDI42x42 .. __movstrDI42x18,
473                               __movstrDI41x41 .. __movstrDI41x17 */
474
475 /* Limits for using the non-looping movstr functions.  For the m88100
476    processor, we assume the source and destination are word aligned.
477    The QImode and HImode limits are the break even points where memcpy
478    does just as well and beyond which memcpy does better.  For the
479    m88110, we tend to assume double word alignment, but also analyze
480    the word aligned cases.  The analysis is complicated because memcpy
481    may use the cache control instructions for better performance.  */
482
483 #define MOVSTR_QI_LIMIT_88100   13
484 #define MOVSTR_HI_LIMIT_88100   38
485 #define MOVSTR_SI_LIMIT_88100   MOVSTR_SI
486 #define MOVSTR_DI_LIMIT_88100   MOVSTR_SI
487   
488 #define MOVSTR_QI_LIMIT_88000   16
489 #define MOVSTR_HI_LIMIT_88000   38
490 #define MOVSTR_SI_LIMIT_88000   72
491 #define MOVSTR_DI_LIMIT_88000   72
492
493 #define MOVSTR_QI_LIMIT_88110   16
494 #define MOVSTR_HI_LIMIT_88110   38
495 #define MOVSTR_SI_LIMIT_88110   72
496 #define MOVSTR_DI_LIMIT_88110   72
497
498 static const enum machine_mode mode_from_align[] =
499                               {VOIDmode, QImode, HImode, VOIDmode, SImode,
500                                VOIDmode, VOIDmode, VOIDmode, DImode};
501 static const int max_from_align[] = {0, MOVSTR_QI, MOVSTR_HI, 0, MOVSTR_SI,
502                                      0, 0, 0, MOVSTR_DI};
503 static const int all_from_align[] = {0, MOVSTR_QI, MOVSTR_ODD_HI, 0,
504                                      MOVSTR_ODD_SI, 0, 0, 0, MOVSTR_ODD_DI};
505
506 static const int best_from_align[3][9] = {
507   {0, MOVSTR_QI_LIMIT_88100, MOVSTR_HI_LIMIT_88100, 0, MOVSTR_SI_LIMIT_88100,
508    0, 0, 0, MOVSTR_DI_LIMIT_88100},
509   {0, MOVSTR_QI_LIMIT_88110, MOVSTR_HI_LIMIT_88110, 0, MOVSTR_SI_LIMIT_88110,
510    0, 0, 0, MOVSTR_DI_LIMIT_88110},
511   {0, MOVSTR_QI_LIMIT_88000, MOVSTR_HI_LIMIT_88000, 0, MOVSTR_SI_LIMIT_88000,
512    0, 0, 0, MOVSTR_DI_LIMIT_88000}
513 };
514
515 static void block_move_loop PARAMS ((rtx, rtx, rtx, rtx, int, int));
516 static void block_move_no_loop PARAMS ((rtx, rtx, rtx, rtx, int, int));
517 static void block_move_sequence PARAMS ((rtx, rtx, rtx, rtx, int, int, int));
518 static void output_short_branch_defs PARAMS ((FILE *));
519 static int output_option PARAMS ((FILE *, const char *, const char *,
520                                   const char *, const char *, int, int));
521
522 /* Emit code to perform a block move.  Choose the best method.
523
524    OPERANDS[0] is the destination.
525    OPERANDS[1] is the source.
526    OPERANDS[2] is the size.
527    OPERANDS[3] is the alignment safe to use.  */
528
529 void
530 expand_block_move (dest_mem, src_mem, operands)
531      rtx dest_mem;
532      rtx src_mem;
533      rtx *operands;
534 {
535   int align = INTVAL (operands[3]);
536   int constp = (GET_CODE (operands[2]) == CONST_INT);
537   int bytes = (constp ? INTVAL (operands[2]) : 0);
538   int target = (int) m88k_cpu;
539
540   if (! (PROCESSOR_M88100 == 0
541          && PROCESSOR_M88110 == 1
542          && PROCESSOR_M88000 == 2))
543     abort ();
544
545   if (constp && bytes <= 0)
546     return;
547
548   /* Determine machine mode to do move with.  */
549   if (align > 4 && !TARGET_88110)
550     align = 4;
551   else if (align <= 0 || align == 3)
552     abort ();   /* block move invalid alignment.  */
553
554   if (constp && bytes <= 3 * align)
555     block_move_sequence (operands[0], dest_mem, operands[1], src_mem,
556                          bytes, align, 0);
557
558   else if (constp && bytes <= best_from_align[target][align])
559     block_move_no_loop (operands[0], dest_mem, operands[1], src_mem,
560                         bytes, align);
561
562   else if (constp && align == 4 && TARGET_88100)
563     block_move_loop (operands[0], dest_mem, operands[1], src_mem,
564                      bytes, align);
565
566   else
567     {
568 #ifdef TARGET_MEM_FUNCTIONS
569       emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "memcpy"), 0,
570                          VOIDmode, 3,
571                          operands[0], Pmode,
572                          operands[1], Pmode,
573                          convert_to_mode (TYPE_MODE (sizetype), operands[2],
574                                           TREE_UNSIGNED (sizetype)),
575                          TYPE_MODE (sizetype));
576 #else
577       emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "bcopy"), 0,
578                          VOIDmode, 3,
579                          operands[1], Pmode,
580                          operands[0], Pmode,
581                          convert_to_mode (TYPE_MODE (integer_type_node),
582                                           operands[2],
583                                           TREE_UNSIGNED (integer_type_node)),
584                          TYPE_MODE (integer_type_node));
585 #endif
586     }
587 }
588
589 /* Emit code to perform a block move by calling a looping movstr library
590    function.  SIZE and ALIGN are known constants.  DEST and SRC are
591    registers.  */
592
593 static void
594 block_move_loop (dest, dest_mem, src, src_mem, size, align)
595      rtx dest, dest_mem;
596      rtx src, src_mem;
597      int size;
598      int align;
599 {
600   enum machine_mode mode;
601   int count;
602   int units;
603   int remainder;
604   rtx offset_rtx;
605   rtx value_rtx;
606   char entry[30];
607   tree entry_name;
608
609   /* Determine machine mode to do move with.  */
610   if (align != 4)
611     abort ();
612
613   /* Determine the structure of the loop.  */
614   count = size / MOVSTR_LOOP;
615   units = (size - count * MOVSTR_LOOP) / align;
616
617   if (units < 2)
618     {
619       count--;
620       units += MOVSTR_LOOP / align;
621     }
622
623   if (count <= 0)
624     {
625       block_move_no_loop (dest, dest_mem, src, src_mem, size, align);
626       return;
627     }
628
629   remainder = size - count * MOVSTR_LOOP - units * align;
630
631   mode = mode_from_align[align];
632   sprintf (entry, "__movstr%s%dn%d",
633            GET_MODE_NAME (mode), MOVSTR_LOOP, units * align);
634   entry_name = get_identifier (entry);
635
636   offset_rtx = GEN_INT (MOVSTR_LOOP + (1 - units) * align);
637
638   value_rtx = gen_rtx_MEM (MEM_IN_STRUCT_P (src_mem) ? mode : BLKmode,
639                            gen_rtx_PLUS (Pmode,
640                                          gen_rtx_REG (Pmode, 3),
641                                          offset_rtx));
642   MEM_COPY_ATTRIBUTES (value_rtx, src_mem);
643
644   emit_insn (gen_call_movstrsi_loop
645              (gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (entry_name)),
646               dest, src, offset_rtx, value_rtx,
647               gen_rtx_REG (mode, ((units & 1) ? 4 : 5)),
648               GEN_INT (count)));
649
650   if (remainder)
651     block_move_sequence (gen_rtx_REG (Pmode, 2), dest_mem,
652                          gen_rtx_REG (Pmode, 3), src_mem,
653                          remainder, align, MOVSTR_LOOP + align);
654 }
655
656 /* Emit code to perform a block move by calling a non-looping library
657    function.  SIZE and ALIGN are known constants.  DEST and SRC are
658    registers.  OFFSET is the known starting point for the output pattern.  */
659
660 static void
661 block_move_no_loop (dest, dest_mem, src, src_mem, size, align)
662      rtx dest, dest_mem;
663      rtx src, src_mem;
664      int size;
665      int align;
666 {
667   enum machine_mode mode = mode_from_align[align];
668   int units = size / align;
669   int remainder = size - units * align;
670   int most;
671   int value_reg;
672   rtx offset_rtx;
673   rtx value_rtx;
674   char entry[30];
675   tree entry_name;
676
677   if (remainder && size <= all_from_align[align])
678     {
679       most = all_from_align[align] - (align - remainder);
680       remainder = 0;
681     }
682   else
683     {
684       most = max_from_align[align];
685     }
686
687   sprintf (entry, "__movstr%s%dx%d",
688            GET_MODE_NAME (mode), most, size - remainder);
689   entry_name = get_identifier (entry);
690
691   offset_rtx = GEN_INT (most - (size - remainder));
692
693   value_rtx = gen_rtx_MEM (MEM_IN_STRUCT_P (src_mem) ? mode : BLKmode,
694                            gen_rtx_PLUS (Pmode,
695                                          gen_rtx_REG (Pmode, 3),
696                                          offset_rtx));
697
698   MEM_COPY_ATTRIBUTES (value_rtx, src_mem);
699
700   value_reg = ((((most - (size - remainder)) / align) & 1) == 0
701                ? (align == 8 ? 6 : 5) : 4);
702
703   emit_insn (gen_call_block_move
704              (gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (entry_name)),
705               dest, src, offset_rtx, value_rtx,
706               gen_rtx_REG (mode, value_reg)));
707
708   if (remainder)
709     block_move_sequence (gen_rtx_REG (Pmode, 2), dest_mem,
710                          gen_rtx_REG (Pmode, 3), src_mem,
711                          remainder, align, most);
712 }
713
714 /* Emit code to perform a block move with an offset sequence of ld/st
715    instructions (..., ld 0, st 1, ld 1, st 0, ...).  SIZE and ALIGN are
716    known constants.  DEST and SRC are registers.  OFFSET is the known
717    starting point for the output pattern.  */
718
719 static void
720 block_move_sequence (dest, dest_mem, src, src_mem, size, align, offset)
721      rtx dest, dest_mem;
722      rtx src, src_mem;
723      int size;
724      int align;
725      int offset;
726 {
727   rtx temp[2];
728   enum machine_mode mode[2];
729   int amount[2];
730   int active[2];
731   int phase = 0;
732   int next;
733   int offset_ld = offset;
734   int offset_st = offset;
735
736   active[0] = active[1] = FALSE;
737
738   /* Establish parameters for the first load and for the second load if
739      it is known to be the same mode as the first.  */
740   amount[0] = amount[1] = align;
741   mode[0] = mode_from_align[align];
742   temp[0] = gen_reg_rtx (mode[0]);
743   if (size >= 2 * align)
744     {
745       mode[1] = mode[0];
746       temp[1] = gen_reg_rtx (mode[1]);
747     }
748
749   do
750     {
751       rtx srcp, dstp;
752       next = phase;
753       phase = !phase;
754
755       if (size > 0)
756         {
757           /* Change modes as the sequence tails off.  */
758           if (size < amount[next])
759             {
760               amount[next] = (size >= 4 ? 4 : (size >= 2 ? 2 : 1));
761               mode[next] = mode_from_align[amount[next]];
762               temp[next] = gen_reg_rtx (mode[next]);
763             }
764           size -= amount[next];
765           srcp = gen_rtx_MEM (MEM_IN_STRUCT_P (src_mem) ? mode[next] : BLKmode,
766                               plus_constant (src, offset_ld));
767
768           MEM_COPY_ATTRIBUTES (srcp, src_mem);
769           emit_insn (gen_rtx_SET (VOIDmode, temp[next], srcp));
770           offset_ld += amount[next];
771           active[next] = TRUE;
772         }
773
774       if (active[phase])
775         {
776           active[phase] = FALSE;
777           dstp
778             = gen_rtx_MEM (MEM_IN_STRUCT_P (dest_mem) ? mode[phase] : BLKmode,
779                            plus_constant (dest, offset_st));
780
781           MEM_COPY_ATTRIBUTES (dstp, dest_mem);
782           emit_insn (gen_rtx_SET (VOIDmode, dstp, temp[phase]));
783           offset_st += amount[phase];
784         }
785     }
786   while (active[next]);
787 }
788 \f
789 /* Emit the code to do an AND operation.  */
790
791 const char *
792 output_and (operands)
793      rtx operands[];
794 {
795   unsigned int value;
796
797   if (REG_P (operands[2]))
798     return "and %0,%1,%2";
799
800   value = INTVAL (operands[2]);
801   if (SMALL_INTVAL (value))
802     return "mask %0,%1,%2";
803   else if ((value & 0xffff0000) == 0xffff0000)
804     return "and %0,%1,%x2";
805   else if ((value & 0xffff) == 0xffff)
806     return "and.u %0,%1,%X2";
807   else if ((value & 0xffff) == 0)
808     return "mask.u %0,%1,%X2";
809   else if (integer_ok_for_set (~value))
810     return "clr %0,%1,%S2";
811   else
812     return "and.u %0,%1,%X2\n\tand %0,%0,%x2";
813 }
814
815 /* Emit the code to do an inclusive OR operation.  */
816
817 const char *
818 output_ior (operands)
819      rtx operands[];
820 {
821   unsigned int value;
822
823   if (REG_P (operands[2]))
824     return "or %0,%1,%2";
825
826   value = INTVAL (operands[2]);
827   if (SMALL_INTVAL (value))
828     return "or %0,%1,%2";
829   else if ((value & 0xffff) == 0)
830     return "or.u %0,%1,%X2";
831   else if (integer_ok_for_set (value))
832     return "set %0,%1,%s2";
833   else
834     return "or.u %0,%1,%X2\n\tor %0,%0,%x2";
835 }
836
837 /* Emit the instructions for doing an XOR.  */
838
839 const char *
840 output_xor (operands)
841      rtx operands[];
842 {
843   unsigned int value;
844
845   if (REG_P (operands[2]))
846     return "xor %0,%1,%2";
847
848   value = INTVAL (operands[2]);
849   if (SMALL_INTVAL (value))
850     return "xor %0,%1,%2";
851   else if ((value & 0xffff) == 0)
852     return "xor.u %0,%1,%X2";
853   else
854     return "xor.u %0,%1,%X2\n\txor %0,%0,%x2";
855 }
856 \f
857 /* Output a call.  Normally this is just bsr or jsr, but this also deals with
858    accomplishing a branch after the call by incrementing r1.  This requires
859    that various assembler bugs be accommodated.  The 4.30 DG/UX assembler
860    requires that forward references not occur when computing the difference of
861    two labels.  The [version?] Motorola assembler computes a word difference.
862    No doubt there's more to come!
863
864    It would seem the same idea could be used to tail call, but in this case,
865    the epilogue will be non-null.  */
866
867 static rtx sb_name = 0;
868 static rtx sb_high = 0;
869 static rtx sb_low = 0;
870
871 const char *
872 output_call (operands, addr)
873      rtx operands[];
874      rtx addr;
875 {
876   operands[0] = addr;
877   if (final_sequence)
878     {
879       rtx jump;
880       rtx seq_insn;
881
882       /* This can be generalized, but there is currently no need.  */
883       if (XVECLEN (final_sequence, 0) != 2)
884         abort ();
885
886       /* The address of interior insns is not computed, so use the sequence.  */
887       seq_insn = NEXT_INSN (PREV_INSN (XVECEXP (final_sequence, 0, 0)));
888       jump = XVECEXP (final_sequence, 0, 1);
889       if (GET_CODE (jump) == JUMP_INSN)
890         {
891           rtx low, high;
892           const char *last;
893           rtx dest = XEXP (SET_SRC (PATTERN (jump)), 0);
894           int delta = 4 * (INSN_ADDRESSES (INSN_UID (dest))
895                            - INSN_ADDRESSES (INSN_UID (seq_insn))
896                            - 2);
897 #if (MONITOR_GCC & 0x2) /* How often do long branches happen?  */
898           if ((unsigned) (delta + 0x8000) >= 0x10000)
899             warning ("internal gcc monitor: short-branch(%x)", delta);
900 #endif
901
902           /* Delete the jump.  */
903           PUT_CODE (jump, NOTE);
904           NOTE_LINE_NUMBER (jump) = NOTE_INSN_DELETED;
905           NOTE_SOURCE_FILE (jump) = 0;
906
907           /* We only do this optimization if -O2, modifying the value of
908              r1 in the delay slot confuses debuggers and profilers on some
909              systems.
910
911              If we loose, we must use the non-delay form.  This is unlikely
912              to ever happen.  If it becomes a problem, claim that a call
913              has two delay slots and only the second can be filled with
914              a jump.  
915
916              The 88110 can lose when a jsr.n r1 is issued and a page fault
917              occurs accessing the delay slot.  So don't use jsr.n form when
918              jumping thru r1.
919            */
920 #ifdef AS_BUG_IMMEDIATE_LABEL /* The assembler restricts immediate values.  */
921           if (optimize < 2
922               || ! ADD_INTVAL (delta * 2)
923 #else
924           if (optimize < 2
925               || ! ADD_INTVAL (delta)
926 #endif
927               || (REG_P (addr) && REGNO (addr) == 1))
928             {
929               operands[1] = dest;
930               return (REG_P (addr)
931                       ? "jsr %0\n\tbr %l1"
932                       : (flag_pic
933                          ? "bsr %0#plt\n\tbr %l1"
934                          : "bsr %0\n\tbr %l1"));
935             }
936
937           /* Output the short branch form.  */
938           output_asm_insn ((REG_P (addr)
939                             ? "jsr.n %0"
940                             : (flag_pic ? "bsr.n %0#plt" : "bsr.n %0")),
941                            operands);
942
943 #ifdef USE_GAS
944           last = (delta < 0
945                   ? "subu %#r1,%#r1,.-%l0+4"
946                   : "addu %#r1,%#r1,%l0-.-4");
947           operands[0] = dest;
948 #else
949           operands[0] = gen_label_rtx ();
950           operands[1] = gen_label_rtx ();
951           if (delta < 0)
952             {
953               low = dest;
954               high = operands[1];
955               last = "subu %#r1,%#r1,%l0\n%l1:";
956             }
957           else
958             {
959               low = operands[1];
960               high = dest;
961               last = "addu %#r1,%#r1,%l0\n%l1:";
962             }
963
964           /* Record the values to be computed later as "def name,high-low".  */
965           sb_name = gen_rtx_EXPR_LIST (VOIDmode, operands[0], sb_name);
966           sb_high = gen_rtx_EXPR_LIST (VOIDmode, high, sb_high);
967           sb_low = gen_rtx_EXPR_LIST (VOIDmode, low, sb_low);
968 #endif /* Don't USE_GAS */
969
970           return last;
971         }
972     }
973   return (REG_P (addr)
974           ? "jsr%. %0"
975           : (flag_pic ? "bsr%. %0#plt" : "bsr%. %0"));
976 }
977
978 static void
979 output_short_branch_defs (stream)
980      FILE *stream;
981 {
982   char name[256], high[256], low[256];
983
984   for (; sb_name && sb_high && sb_low;
985        sb_name = XEXP (sb_name, 1),
986        sb_high = XEXP (sb_high, 1),
987        sb_low = XEXP (sb_low, 1))
988     {
989       ASM_GENERATE_INTERNAL_LABEL
990         (name, "L", CODE_LABEL_NUMBER (XEXP (sb_name, 0)));
991       ASM_GENERATE_INTERNAL_LABEL
992         (high, "L", CODE_LABEL_NUMBER (XEXP (sb_high, 0)));
993       ASM_GENERATE_INTERNAL_LABEL
994         (low, "L", CODE_LABEL_NUMBER (XEXP (sb_low, 0)));
995       /* This will change as the assembler requirements become known.  */
996       fprintf (stream, "%s%s,%s-%s\n",
997                SET_ASM_OP, &name[1], &high[1], &low[1]);
998     }
999   if (sb_name || sb_high || sb_low)
1000     abort ();
1001 }
1002 \f
1003 /* Return truth value of the statement that this conditional branch is likely
1004    to fall through.  CONDITION, is the condition that JUMP_INSN is testing.  */
1005
1006 int
1007 mostly_false_jump (jump_insn, condition)
1008      rtx jump_insn, condition;
1009 {
1010   rtx target_label = JUMP_LABEL (jump_insn);
1011   rtx insnt, insnj;
1012
1013   /* Much of this isn't computed unless we're optimizing.  */
1014   if (optimize == 0)
1015     return 0;
1016
1017   /* Determine if one path or the other leads to a return.  */
1018   for (insnt = NEXT_INSN (target_label);
1019        insnt;
1020        insnt = NEXT_INSN (insnt))
1021     {
1022       if (GET_CODE (insnt) == JUMP_INSN)
1023         break;
1024       else if (GET_CODE (insnt) == INSN
1025                && GET_CODE (PATTERN (insnt)) == SEQUENCE
1026                && GET_CODE (XVECEXP (PATTERN (insnt), 0, 0)) == JUMP_INSN)
1027         {
1028           insnt = XVECEXP (PATTERN (insnt), 0, 0);
1029           break;
1030         }
1031     }
1032   if (insnt
1033       && (GET_CODE (PATTERN (insnt)) == RETURN
1034           || (GET_CODE (PATTERN (insnt)) == SET
1035               && GET_CODE (SET_SRC (PATTERN (insnt))) == REG
1036               && REGNO (SET_SRC (PATTERN (insnt))) == 1)))
1037     insnt = 0;
1038
1039   for (insnj = NEXT_INSN (jump_insn);
1040        insnj;
1041        insnj = NEXT_INSN (insnj))
1042     {
1043       if (GET_CODE (insnj) == JUMP_INSN)
1044         break;
1045       else if (GET_CODE (insnj) == INSN
1046                && GET_CODE (PATTERN (insnj)) == SEQUENCE
1047                && GET_CODE (XVECEXP (PATTERN (insnj), 0, 0)) == JUMP_INSN)
1048         {
1049           insnj = XVECEXP (PATTERN (insnj), 0, 0);
1050           break;
1051         }
1052     }
1053   if (insnj
1054       && (GET_CODE (PATTERN (insnj)) == RETURN
1055           || (GET_CODE (PATTERN (insnj)) == SET
1056               && GET_CODE (SET_SRC (PATTERN (insnj))) == REG
1057               && REGNO (SET_SRC (PATTERN (insnj))) == 1)))
1058     insnj = 0;
1059
1060   /* Predict to not return.  */
1061   if ((insnt == 0) != (insnj == 0))
1062     return (insnt == 0);
1063
1064   /* Predict loops to loop.  */
1065   for (insnt = PREV_INSN (target_label);
1066        insnt && GET_CODE (insnt) == NOTE;
1067        insnt = PREV_INSN (insnt))
1068     if (NOTE_LINE_NUMBER (insnt) == NOTE_INSN_LOOP_END)
1069       return 1;
1070     else if (NOTE_LINE_NUMBER (insnt) == NOTE_INSN_LOOP_BEG)
1071       return 0;
1072     else if (NOTE_LINE_NUMBER (insnt) == NOTE_INSN_LOOP_CONT)
1073       return 0;
1074
1075   /* Predict backward branches usually take.  */
1076   if (final_sequence)
1077     insnj = NEXT_INSN (PREV_INSN (XVECEXP (final_sequence, 0, 0)));
1078   else
1079     insnj = jump_insn;
1080   if (INSN_ADDRESSES (INSN_UID (insnj))
1081       > INSN_ADDRESSES (INSN_UID (target_label)))
1082     return 0;
1083
1084   /* EQ tests are usually false and NE tests are usually true.  Also,
1085      most quantities are positive, so we can make the appropriate guesses
1086      about signed comparisons against zero.  Consider unsigned comparisons
1087      to be a range check and assume quantities to be in range.  */
1088   switch (GET_CODE (condition))
1089     {
1090     case CONST_INT:
1091       /* Unconditional branch.  */
1092       return 0;
1093     case EQ:
1094       return 1;
1095     case NE:
1096       return 0;
1097     case LE:
1098     case LT:
1099     case GEU:
1100     case GTU: /* Must get casesi right at least.  */
1101       if (XEXP (condition, 1) == const0_rtx)
1102         return 1;
1103       break;
1104     case GE:
1105     case GT:
1106     case LEU:
1107     case LTU:
1108       if (XEXP (condition, 1) == const0_rtx)
1109         return 0;
1110       break;
1111     default:
1112       break;
1113     }
1114
1115   return 0;
1116 }
1117 \f
1118 /* Return true if the operand is a power of two and is a floating
1119    point type (to optimize division by power of two into multiplication).  */
1120
1121 int
1122 real_power_of_2_operand (op, mode)
1123      rtx op;
1124      enum machine_mode mode ATTRIBUTE_UNUSED;
1125 {
1126   union {
1127     REAL_VALUE_TYPE d;
1128     int i[sizeof (REAL_VALUE_TYPE) / sizeof (int)];
1129     struct {                            /* IEEE double precision format */
1130       unsigned sign      :  1;
1131       unsigned exponent  : 11;
1132       unsigned mantissa1 : 20;
1133       unsigned mantissa2;
1134     } s;
1135     struct {                            /* IEEE double format to quick check */
1136       unsigned sign      :  1;          /* if it fits in a float */
1137       unsigned exponent1 :  4;
1138       unsigned exponent2 :  7;
1139       unsigned mantissa1 : 20;
1140       unsigned mantissa2;
1141     } s2;
1142   } u;
1143
1144   if (GET_MODE (op) != DFmode && GET_MODE (op) != SFmode)
1145     return 0;
1146
1147   if (GET_CODE (op) != CONST_DOUBLE)
1148     return 0;
1149
1150   u.i[0] = CONST_DOUBLE_LOW  (op);
1151   u.i[1] = CONST_DOUBLE_HIGH (op);
1152
1153   if (u.s.mantissa1 != 0 || u.s.mantissa2 != 0  /* not a power of two */
1154       || u.s.exponent == 0                      /* constant 0.0 */
1155       || u.s.exponent == 0x7ff                  /* NAN */
1156       || (u.s2.exponent1 != 0x8 && u.s2.exponent1 != 0x7))
1157     return 0;                                   /* const won't fit in float */
1158
1159   return 1;
1160 }
1161 \f
1162 /* Make OP legitimate for mode MODE.  Currently this only deals with DFmode
1163    operands, putting them in registers and making CONST_DOUBLE values
1164    SFmode where possible.  */
1165
1166 struct rtx_def *
1167 legitimize_operand (op, mode)
1168      rtx op;
1169      enum machine_mode mode;
1170 {
1171   rtx temp;
1172   union {
1173     union real_extract r;
1174     struct {                            /* IEEE double precision format */
1175       unsigned sign      :  1;
1176       unsigned exponent  : 11;
1177       unsigned mantissa1 : 20;
1178       unsigned mantissa2;
1179     } d;
1180     struct {                            /* IEEE double format to quick check */
1181       unsigned sign      :  1;          /* if it fits in a float */
1182       unsigned exponent1 :  4;
1183       unsigned exponent2 :  7;
1184       unsigned mantissa1 : 20;
1185       unsigned mantissa2;
1186     } s;
1187   } u;
1188
1189   if (GET_CODE (op) == REG || mode != DFmode)
1190     return op;
1191
1192   if (GET_CODE (op) == CONST_DOUBLE)
1193     {
1194       memcpy (&u.r, &CONST_DOUBLE_LOW (op), sizeof u);
1195       if (u.d.exponent != 0x7ff /* NaN */
1196           && u.d.mantissa2 == 0 /* Mantissa fits */
1197           && (u.s.exponent1 == 0x8 || u.s.exponent1 == 0x7) /* Exponent fits */
1198           && (temp = simplify_unary_operation (FLOAT_TRUNCATE, SFmode,
1199                                                op, mode)) != 0)
1200         return gen_rtx_FLOAT_EXTEND (mode, force_reg (SFmode, temp));
1201     }
1202   else if (register_operand (op, mode))
1203     return op;
1204
1205   return force_reg (mode, op);
1206 }
1207 \f
1208 /* Return true if OP is a suitable input for a move insn.  */
1209
1210 int
1211 move_operand (op, mode)
1212      rtx op;
1213      enum machine_mode mode;
1214 {
1215   if (register_operand (op, mode))
1216     return 1;
1217   if (GET_CODE (op) == CONST_INT)
1218     return (classify_integer (mode, INTVAL (op)) < m88k_oru_hi16);
1219   if (GET_MODE (op) != mode)
1220     return 0;
1221   if (GET_CODE (op) == SUBREG)
1222     op = SUBREG_REG (op);
1223   if (GET_CODE (op) != MEM)
1224     return 0;
1225
1226   op = XEXP (op, 0);
1227   if (GET_CODE (op) == LO_SUM)
1228     return (REG_P (XEXP (op, 0))
1229             && symbolic_address_p (XEXP (op, 1)));
1230   return memory_address_p (mode, op);
1231 }
1232
1233 /* Return true if OP is suitable for a call insn.  */
1234
1235 int
1236 call_address_operand (op, mode)
1237      rtx op;
1238      enum machine_mode mode ATTRIBUTE_UNUSED;
1239 {
1240   return (REG_P (op) || symbolic_address_p (op));
1241 }
1242
1243 /* Returns true if OP is either a symbol reference or a sum of a symbol
1244    reference and a constant.  */
1245
1246 int
1247 symbolic_address_p (op)
1248      register rtx op;
1249 {
1250   switch (GET_CODE (op))
1251     {
1252     case SYMBOL_REF:
1253     case LABEL_REF:
1254       return 1;
1255
1256     case CONST:
1257       op = XEXP (op, 0);
1258       return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1259                || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1260               && GET_CODE (XEXP (op, 1)) == CONST_INT);
1261
1262     default:
1263       return 0;
1264     }
1265 }
1266
1267 /* Return true if OP is a register or const0_rtx.  */
1268
1269 int
1270 reg_or_0_operand (op, mode)
1271      rtx op;
1272      enum machine_mode mode;
1273 {
1274   return (op == const0_rtx || register_operand (op, mode));
1275 }
1276
1277 /* Nonzero if OP is a valid second operand for an arithmetic insn.  */
1278
1279 int
1280 arith_operand (op, mode)
1281      rtx op;
1282      enum machine_mode mode;
1283 {
1284   return (register_operand (op, mode)
1285           || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));
1286 }
1287
1288 /* Return true if OP is a  register or 5 bit integer.  */
1289
1290 int
1291 arith5_operand (op, mode)
1292      rtx op;
1293      enum machine_mode mode;
1294 {
1295   return (register_operand (op, mode)
1296           || (GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 32));
1297 }
1298
1299 int
1300 arith32_operand (op, mode)
1301      rtx op;
1302      enum machine_mode mode;
1303 {
1304   return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
1305 }
1306
1307 int
1308 arith64_operand (op, mode)
1309      rtx op;
1310      enum machine_mode mode;
1311 {
1312   return (register_operand (op, mode)
1313           || GET_CODE (op) == CONST_INT
1314           || (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode));
1315 }
1316
1317 int
1318 int5_operand (op, mode)
1319      rtx op;
1320      enum machine_mode mode ATTRIBUTE_UNUSED;
1321 {
1322   return (GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 32);
1323 }
1324
1325 int
1326 int32_operand (op, mode)
1327      rtx op;
1328      enum machine_mode mode ATTRIBUTE_UNUSED;
1329 {
1330   return (GET_CODE (op) == CONST_INT);
1331 }
1332
1333 /* Return true if OP is a register or a valid immediate operand for
1334    addu or subu.  */
1335
1336 int
1337 add_operand (op, mode)
1338      rtx op;
1339      enum machine_mode mode;
1340 {
1341   return (register_operand (op, mode)
1342           || (GET_CODE (op) == CONST_INT && ADD_INT (op)));
1343 }
1344
1345 /* Nonzero if this is a bitmask filling the bottom bits, for optimizing and +
1346    shift left combinations into a single mak instruction.  */
1347
1348 int
1349 mak_mask_p (value)
1350      int value;
1351 {
1352   return (value && POWER_OF_2_or_0 (value + 1));
1353 }
1354
1355 int
1356 reg_or_bbx_mask_operand (op, mode)
1357      rtx op;
1358      enum machine_mode mode;
1359 {
1360   int value;
1361   if (register_operand (op, mode))
1362     return 1;
1363   if (GET_CODE (op) != CONST_INT)
1364     return 0;
1365
1366   value = INTVAL (op);
1367   if (POWER_OF_2 (value))
1368     return 1;
1369
1370   return 0;
1371 }
1372
1373 /* Return true if OP is valid to use in the context of a floating
1374    point operation.  Special case 0.0, since we can use r0.  */
1375
1376 int
1377 real_or_0_operand (op, mode)
1378      rtx op;
1379      enum machine_mode mode;
1380 {
1381   if (mode != SFmode && mode != DFmode)
1382     return 0;
1383
1384   return (register_operand (op, mode)
1385           || (GET_CODE (op) == CONST_DOUBLE
1386               && op == CONST0_RTX (mode)));
1387 }
1388
1389 /* Return true if OP is valid to use in the context of logic arithmetic
1390    on condition codes. */
1391
1392 int
1393 partial_ccmode_register_operand (op, mode)
1394      rtx op;
1395      enum machine_mode mode ATTRIBUTE_UNUSED;
1396 {
1397   return register_operand (op, CCmode) || register_operand (op, CCEVENmode);
1398 }
1399
1400 /* Return true if OP is a relational operator.  */
1401
1402 int
1403 relop (op, mode)
1404      rtx op;
1405      enum machine_mode mode ATTRIBUTE_UNUSED;
1406 {
1407   switch (GET_CODE (op))
1408     {
1409     case EQ:
1410     case NE:
1411     case LT:
1412     case LE:
1413     case GE:
1414     case GT:
1415     case LTU:
1416     case LEU:
1417     case GEU:
1418     case GTU:
1419       return 1;
1420     default:
1421       return 0;
1422     }
1423 }
1424
1425 int
1426 even_relop (op, mode)
1427      rtx op;
1428      enum machine_mode mode ATTRIBUTE_UNUSED;
1429 {
1430   switch (GET_CODE (op))
1431     {
1432     case EQ:
1433     case LT:
1434     case GT:
1435     case LTU:
1436     case GTU:
1437       return 1;
1438     default:
1439       return 0;
1440     }
1441 }
1442
1443 int
1444 odd_relop (op, mode)
1445      rtx op;
1446      enum machine_mode mode ATTRIBUTE_UNUSED;
1447 {
1448   switch (GET_CODE (op))
1449     {
1450     case NE:
1451     case LE:
1452     case GE:
1453     case LEU:
1454     case GEU:
1455       return 1;
1456     default:
1457       return 0;
1458     }
1459 }
1460
1461 /* Return true if OP is a relational operator, and is not an unsigned
1462    relational operator.  */
1463
1464 int
1465 relop_no_unsigned (op, mode)
1466      rtx op;
1467      enum machine_mode mode ATTRIBUTE_UNUSED;
1468 {
1469   switch (GET_CODE (op))
1470     {
1471     case EQ:
1472     case NE:
1473     case LT:
1474     case LE:
1475     case GE:
1476     case GT:
1477       /* @@ What is this test doing?  Why not use `mode'?  */
1478       if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT
1479           || GET_MODE (op) == DImode
1480           || GET_MODE_CLASS (GET_MODE (XEXP (op, 0))) == MODE_FLOAT
1481           || GET_MODE (XEXP (op, 0)) == DImode
1482           || GET_MODE_CLASS (GET_MODE (XEXP (op, 1))) == MODE_FLOAT
1483           || GET_MODE (XEXP (op, 1)) == DImode)
1484         return 0;
1485       return 1;
1486     default:
1487       return 0;
1488     }
1489 }
1490
1491 /* Return true if the code of this rtx pattern is EQ or NE.  */
1492
1493 int
1494 equality_op (op, mode)
1495      rtx op;
1496      enum machine_mode mode ATTRIBUTE_UNUSED;
1497 {
1498   return (GET_CODE (op) == EQ || GET_CODE (op) == NE);
1499 }
1500
1501 /* Return true if the code of this rtx pattern is pc or label_ref.  */
1502
1503 int
1504 pc_or_label_ref (op, mode)
1505      rtx op;
1506      enum machine_mode mode ATTRIBUTE_UNUSED;
1507 {
1508   return (GET_CODE (op) == PC || GET_CODE (op) == LABEL_REF);
1509 }
1510 \f
1511 /* Output to FILE the start of the assembler file.  */
1512
1513 /* This definition must match lang_independent_options from toplev.c.  */
1514 struct m88k_lang_independent_options
1515 {
1516   const char *const string;
1517   int *const variable;
1518   const int on_value;
1519   const char *const description;
1520 };
1521
1522 static void output_options PARAMS ((FILE *,
1523                                     const struct m88k_lang_independent_options *,
1524                                     int,
1525                                     const struct m88k_lang_independent_options *,
1526                                     int, int, int, const char *, const char *,
1527                                     const char *));
1528
1529 static int
1530 output_option (file, sep, type, name, indent, pos, max)
1531      FILE *file;
1532      const char *sep;
1533      const char *type;
1534      const char *name;
1535      const char *indent;
1536      int pos;
1537      int max;
1538 {
1539   if ((long)(strlen (sep) + strlen (type) + strlen (name) + pos) > max)
1540     {
1541       fprintf (file, indent);
1542       return fprintf (file, "%s%s", type, name);
1543     }
1544   return pos + fprintf (file, "%s%s%s", sep, type, name);
1545 }
1546
1547 static const struct { const char *const name; const int value; } m_options[] =
1548 TARGET_SWITCHES;
1549
1550 static void
1551 output_options (file, f_options, f_len, W_options, W_len,
1552                 pos, max, sep, indent, term)
1553      FILE *file;
1554      const struct m88k_lang_independent_options *f_options;
1555      const struct m88k_lang_independent_options *W_options;
1556      int f_len, W_len;
1557      int pos;
1558      int max;
1559      const char *sep;
1560      const char *indent;
1561      const char *term;
1562 {
1563   register int j;
1564
1565   if (optimize)
1566     pos = output_option (file, sep, "-O", "", indent, pos, max);
1567   if (write_symbols != NO_DEBUG)
1568     pos = output_option (file, sep, "-g", "", indent, pos, max);
1569   if (profile_flag)
1570     pos = output_option (file, sep, "-p", "", indent, pos, max);
1571   for (j = 0; j < f_len; j++)
1572     if (*f_options[j].variable == f_options[j].on_value)
1573       pos = output_option (file, sep, "-f", f_options[j].string,
1574                            indent, pos, max);
1575
1576   for (j = 0; j < W_len; j++)
1577     if (*W_options[j].variable == W_options[j].on_value)
1578       pos = output_option (file, sep, "-W", W_options[j].string,
1579                            indent, pos, max);
1580
1581   for (j = 0; j < (long) ARRAY_SIZE (m_options); j++)
1582     if (m_options[j].name[0] != '\0'
1583         && m_options[j].value > 0
1584         && ((m_options[j].value & target_flags)
1585             == m_options[j].value))
1586       pos = output_option (file, sep, "-m", m_options[j].name,
1587                            indent, pos, max);
1588
1589   if (m88k_short_data)
1590     pos = output_option (file, sep, "-mshort-data-", m88k_short_data,
1591                          indent, pos, max);
1592
1593   fprintf (file, term);
1594 }
1595
1596 void
1597 output_file_start (file, f_options, f_len, W_options, W_len)
1598      FILE *file;
1599      const struct m88k_lang_independent_options *f_options;
1600      const struct m88k_lang_independent_options *W_options;
1601      int f_len, W_len;
1602 {
1603   register int pos;
1604
1605   ASM_FIRST_LINE (file);
1606   if (TARGET_88110
1607       && TARGET_SVR4)
1608     fprintf (file, "%s\n", REQUIRES_88110_ASM_OP);
1609   output_file_directive (file, main_input_filename);
1610   /* Switch to the data section so that the coffsem symbol
1611      isn't in the text section.  */
1612   ASM_COFFSEM (file);
1613
1614   if (TARGET_IDENTIFY_REVISION)
1615     {
1616       char indent[256];
1617
1618       time_t now = time ((time_t *)0);
1619       sprintf (indent, "]\"\n%s\"@(#)%s [", IDENT_ASM_OP, main_input_filename);
1620       fprintf (file, indent+3);
1621       pos = fprintf (file, "gcc %s, %.24s,", version_string, ctime (&now));
1622 #if 1
1623       /* ??? It would be nice to call print_switch_values here (and thereby
1624          let us delete output_options) but this is kept in until it is known
1625          whether the change in content format matters.  */
1626       output_options (file, f_options, f_len, W_options, W_len,
1627                       pos, 150 - strlen (indent), " ", indent, "]\"\n\n");
1628 #else
1629       fprintf (file, "]\"\n");
1630       print_switch_values (file, 0, 150 - strlen (indent),
1631                            indent + 3, " ", "]\"\n");
1632 #endif
1633     }
1634 }
1635 \f
1636 /* Output an ascii string.  */
1637
1638 void
1639 output_ascii (file, opcode, max, p, size)
1640      FILE *file;
1641      const char *opcode;
1642      int max;
1643      const char *p;
1644      int size;
1645 {
1646   int i;
1647   int in_escape = 0;
1648
1649   register int num = 0;
1650
1651   fprintf (file, "%s\"", opcode);
1652   for (i = 0; i < size; i++)
1653     {
1654       register int c = (unsigned char) p[i];
1655
1656       if (num > max)
1657         {
1658           fprintf (file, "\"\n%s\"", opcode);
1659           num = 0;
1660         }
1661           
1662       if (c == '\"' || c == '\\')
1663         {
1664         escape:
1665           putc ('\\', file);
1666           putc (c, file);
1667           num += 2;
1668           in_escape = 0;
1669         }
1670       else if (in_escape && ISDIGIT (c))
1671         {
1672           /* If a digit follows an octal-escape, the VAX assembler fails
1673              to stop reading the escape after three digits.  Continue to
1674              output the values as an octal-escape until a non-digit is
1675              found.  */
1676           fprintf (file, "\\%03o", c);
1677           num += 4;
1678         }
1679       else if ((c >= ' ' && c < 0177) || (c == '\t'))
1680         {
1681           putc (c, file);
1682           num++;
1683           in_escape = 0;
1684         }
1685       else
1686         {
1687           switch (c)
1688             {
1689               /* Some assemblers can't handle \a, \v, or \?.  */
1690             case '\f': c = 'f'; goto escape;
1691             case '\b': c = 'b'; goto escape;
1692             case '\r': c = 'r'; goto escape;
1693             case '\n': c = 'n'; goto escape;
1694             }
1695
1696           fprintf (file, "\\%03o", c);
1697           num += 4;
1698           in_escape = 1;
1699         }
1700     }
1701   fprintf (file, "\"\n");
1702 }
1703 \f
1704 /* Output a label (allows insn-output.c to be compiled without including
1705    m88k.c or needing to include stdio.h).  */
1706
1707 void
1708 output_label (label_number)
1709      int label_number;
1710 {
1711   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", label_number);
1712 }
1713 \f
1714 /* Generate the assembly code for function entry.
1715
1716    The prologue is responsible for setting up the stack frame,
1717    initializing the frame pointer register, saving registers that must be
1718    saved, and allocating SIZE additional bytes of storage for the
1719    local variables.  SIZE is an integer.  FILE is a stdio
1720    stream to which the assembler code should be output.
1721
1722    The label for the beginning of the function need not be output by this
1723    macro.  That has already been done when the macro is run.
1724
1725    To determine which registers to save, the macro can refer to the array
1726    `regs_ever_live': element R is nonzero if hard register
1727    R is used anywhere within the function.  This implies the
1728    function prologue should save register R, but not if it is one
1729    of the call-used registers.
1730
1731    On machines where functions may or may not have frame-pointers, the
1732    function entry code must vary accordingly; it must set up the frame
1733    pointer if one is wanted, and not otherwise.  To determine whether a
1734    frame pointer is in wanted, the macro can refer to the variable
1735    `frame_pointer_needed'.  The variable's value will be 1 at run
1736    time in a function that needs a frame pointer.
1737
1738    On machines where an argument may be passed partly in registers and
1739    partly in memory, this macro must examine the variable
1740    `current_function_pretend_args_size', and allocate that many bytes
1741    of uninitialized space on the stack just underneath the first argument
1742    arriving on the stack.  (This may not be at the very end of the stack,
1743    if the calling sequence has pushed anything else since pushing the stack
1744    arguments.  But usually, on such machines, nothing else has been pushed
1745    yet, because the function prologue itself does all the pushing.)
1746
1747    If `ACCUMULATE_OUTGOING_ARGS' is defined, the variable
1748    `current_function_outgoing_args_size' contains the size in bytes
1749    required for the outgoing arguments.  This macro must add that
1750    amount of uninitialized space to very bottom of the stack.
1751
1752    The stack frame we use looks like this:
1753
1754  caller                                                  callee
1755         |==============================================|
1756         |                caller's frame                |
1757         |==============================================|
1758         |     [caller's outgoing memory arguments]     |
1759         |==============================================|
1760         |  caller's outgoing argument area (32 bytes)  |
1761   sp -> |==============================================| <- ap
1762         |            [local variable space]            |
1763         |----------------------------------------------|
1764         |            [return address (r1)]             |
1765         |----------------------------------------------|
1766         |        [previous frame pointer (r30)]        |
1767         |==============================================| <- fp
1768         |       [preserved registers (r25..r14)]       |
1769         |----------------------------------------------|
1770         |       [preserved registers (x29..x22)]       |
1771         |==============================================|
1772         |    [dynamically allocated space (alloca)]    |
1773         |==============================================|
1774         |     [callee's outgoing memory arguments]     |
1775         |==============================================|
1776         | [callee's outgoing argument area (32 bytes)] |
1777         |==============================================| <- sp
1778
1779   Notes:
1780
1781   r1 and r30 must be saved if debugging.
1782
1783   fp (if present) is located two words down from the local
1784   variable space.
1785   */
1786
1787 static void emit_add PARAMS ((rtx, rtx, int));
1788 static void preserve_registers PARAMS ((int, int));
1789 static void emit_ldst PARAMS ((int, int, enum machine_mode, int));
1790 static void output_tdesc PARAMS ((FILE *, int));
1791 static int uses_arg_area_p PARAMS ((void));
1792
1793 static int  nregs;
1794 static int  nxregs;
1795 static char save_regs[FIRST_PSEUDO_REGISTER];
1796 static int  frame_laid_out;
1797 static int  frame_size;
1798 static int  variable_args_p;
1799 static int  epilogue_marked;
1800 static int  prologue_marked;
1801
1802 #define FIRST_OCS_PRESERVE_REGISTER     14
1803 #define LAST_OCS_PRESERVE_REGISTER      30
1804
1805 #define FIRST_OCS_EXTENDED_PRESERVE_REGISTER    (32 + 22)
1806 #define LAST_OCS_EXTENDED_PRESERVE_REGISTER     (32 + 31)
1807
1808 #define STACK_UNIT_BOUNDARY (STACK_BOUNDARY / BITS_PER_UNIT)
1809 #define ROUND_CALL_BLOCK_SIZE(BYTES) \
1810   (((BYTES) + (STACK_UNIT_BOUNDARY - 1)) & ~(STACK_UNIT_BOUNDARY - 1))
1811 \f
1812 /* Establish the position of the FP relative to the SP.  This is done
1813    either during output_function_prologue() or by
1814    INITIAL_ELIMINATION_OFFSET.  */
1815
1816 void
1817 m88k_layout_frame ()
1818 {
1819   int regno, sp_size;
1820
1821   frame_laid_out++;
1822
1823   memset ((char *) &save_regs[0], 0, sizeof (save_regs));
1824   sp_size = nregs = nxregs = 0;
1825   frame_size = get_frame_size ();
1826
1827   /* Since profiling requires a call, make sure r1 is saved.  */
1828   if (current_function_profile)
1829     save_regs[1] = 1;
1830
1831   /* If we are producing debug information, store r1 and r30 where the
1832      debugger wants to find them (r30 at r30+0, r1 at r30+4).  Space has
1833      already been reserved for r1/r30 in STARTING_FRAME_OFFSET.  */
1834   if (write_symbols != NO_DEBUG && !TARGET_OCS_FRAME_POSITION)
1835     save_regs[1] = 1;
1836
1837   /* If there is a call, alloca is used, __builtin_alloca is used, or
1838      a dynamic-sized object is defined, add the 8 additional words
1839      for the callee's argument area.  The common denominator is that the
1840      FP is required.  may_call_alloca only gets calls to alloca;
1841      current_function_calls_alloca gets alloca and __builtin_alloca.  */
1842   if (regs_ever_live[1] || frame_pointer_needed)
1843     {
1844       save_regs[1] = 1;
1845       sp_size += REG_PARM_STACK_SPACE (0);
1846     }
1847
1848   /* If we are producing PIC, save the addressing base register and r1.  */
1849   if (flag_pic && current_function_uses_pic_offset_table)
1850     {
1851       save_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
1852       nregs++;
1853     }
1854
1855   /* If a frame is requested, save the previous FP, and the return
1856      address (r1), so that a traceback can be done without using tdesc
1857      information.  Otherwise, simply save the FP if it is used as
1858      a preserve register.  */
1859   if (frame_pointer_needed)
1860     save_regs[FRAME_POINTER_REGNUM] = save_regs[1] = 1;
1861   else if (regs_ever_live[FRAME_POINTER_REGNUM])
1862     save_regs[FRAME_POINTER_REGNUM] = 1;
1863
1864   /* Figure out which extended register(s) needs to be saved.  */
1865   for (regno = FIRST_EXTENDED_REGISTER + 1; regno < FIRST_PSEUDO_REGISTER;
1866        regno++)
1867     if (regs_ever_live[regno] && ! call_used_regs[regno])
1868       {
1869         save_regs[regno] = 1;
1870         nxregs++;
1871       }
1872
1873   /* Figure out which normal register(s) needs to be saved.  */
1874   for (regno = 2; regno < FRAME_POINTER_REGNUM; regno++)
1875     if (regs_ever_live[regno] && ! call_used_regs[regno])
1876       {
1877         save_regs[regno] = 1;
1878         nregs++;
1879       }
1880
1881   /* Achieve greatest use of double memory ops.  Either we end up saving
1882      r30 or we use that slot to align the registers we do save.  */
1883   if (nregs >= 2 && save_regs[1] && !save_regs[FRAME_POINTER_REGNUM])
1884     sp_size += 4;
1885
1886   nregs += save_regs[1] + save_regs[FRAME_POINTER_REGNUM];
1887   /* if we need to align extended registers, add a word */
1888   if (nxregs > 0 && (nregs & 1) != 0)
1889     sp_size +=4;
1890   sp_size += 4 * nregs;
1891   sp_size += 8 * nxregs;
1892   sp_size += current_function_outgoing_args_size;
1893
1894   /* The first two saved registers are placed above the new frame pointer
1895      if any.  In the only case this matters, they are r1 and r30. */
1896   if (frame_pointer_needed || sp_size)
1897     m88k_fp_offset = ROUND_CALL_BLOCK_SIZE (sp_size - STARTING_FRAME_OFFSET);
1898   else
1899     m88k_fp_offset = -STARTING_FRAME_OFFSET;
1900   m88k_stack_size = m88k_fp_offset + STARTING_FRAME_OFFSET;
1901
1902   /* First, combine m88k_stack_size and size.  If m88k_stack_size is
1903      non-zero, align the frame size to 8 mod 16; otherwise align the
1904      frame size to 0 mod 16.  (If stacks are 8 byte aligned, this ends
1905      up as a NOP.  */
1906   {
1907     int need
1908       = ((m88k_stack_size ? STACK_UNIT_BOUNDARY - STARTING_FRAME_OFFSET : 0)
1909          - (frame_size % STACK_UNIT_BOUNDARY));
1910     if (need < 0)
1911       need += STACK_UNIT_BOUNDARY;
1912     m88k_stack_size
1913       = ROUND_CALL_BLOCK_SIZE (m88k_stack_size + frame_size + need
1914                                + current_function_pretend_args_size);
1915   }
1916 }
1917
1918 /* Return true if this function is known to have a null prologue.  */
1919
1920 int
1921 null_prologue ()
1922 {
1923   if (! reload_completed)
1924     return 0;
1925   if (! frame_laid_out)
1926     m88k_layout_frame ();
1927   return (! frame_pointer_needed
1928           && nregs == 0
1929           && nxregs == 0
1930           && m88k_stack_size == 0);
1931 }
1932
1933 /* Determine if the current function has any references to the arg pointer.
1934    This is done indirectly by examining the DECL_ARGUMENTS' DECL_RTL.
1935    It is OK to return TRUE if there are no references, but FALSE must be
1936    correct.  */
1937
1938 static int
1939 uses_arg_area_p ()
1940 {
1941   register tree parm;
1942
1943   if (current_function_decl == 0
1944       || current_function_varargs
1945       || variable_args_p)
1946     return 1;
1947
1948   for (parm = DECL_ARGUMENTS (current_function_decl);
1949        parm;
1950        parm = TREE_CHAIN (parm))
1951     {
1952       if (DECL_RTL (parm) == 0
1953           || GET_CODE (DECL_RTL (parm)) == MEM)
1954         return 1;
1955
1956       if (DECL_INCOMING_RTL (parm) == 0
1957           || GET_CODE (DECL_INCOMING_RTL (parm)) == MEM)
1958         return 1;
1959     }
1960   return 0;
1961 }
1962 \f
1963 static void
1964 m88k_output_function_prologue (stream, size)
1965      FILE *stream ATTRIBUTE_UNUSED;
1966      HOST_WIDE_INT size ATTRIBUTE_UNUSED;
1967 {
1968   if (TARGET_OMIT_LEAF_FRAME_POINTER && ! quiet_flag && leaf_function_p ())
1969     fprintf (stderr, "$");
1970
1971   m88k_prologue_done = 1;       /* it's ok now to put out ln directives */
1972 }
1973
1974 static void
1975 m88k_output_function_end_prologue (stream)
1976      FILE *stream;
1977 {
1978   if (TARGET_OCS_DEBUG_INFO && !prologue_marked)
1979     {
1980       PUT_OCS_FUNCTION_START (stream);
1981       prologue_marked = 1;
1982
1983       /* If we've already passed the start of the epilogue, say that
1984          it starts here.  This marks the function as having a null body,
1985          but at a point where the return address is in a known location.
1986
1987          Originally, I thought this couldn't happen, but the pic prologue
1988          for leaf functions ends with the instruction that restores the
1989          return address from the temporary register.  If the temporary
1990          register is never used, that instruction can float all the way
1991          to the end of the function.  */
1992       if (epilogue_marked)
1993         PUT_OCS_FUNCTION_END (stream);
1994     }
1995 }
1996
1997 void
1998 m88k_expand_prologue ()
1999 {
2000   m88k_layout_frame ();
2001
2002   if (TARGET_OPTIMIZE_ARG_AREA
2003       && m88k_stack_size
2004       && ! uses_arg_area_p ())
2005     {
2006       /* The incoming argument area is used for stack space if it is not
2007          used (or if -mno-optimize-arg-area is given).  */
2008       if ((m88k_stack_size -= REG_PARM_STACK_SPACE (0)) < 0)
2009         m88k_stack_size = 0;
2010     }
2011
2012   if (m88k_stack_size)
2013     emit_add (stack_pointer_rtx, stack_pointer_rtx, -m88k_stack_size);
2014
2015   if (nregs || nxregs)
2016     preserve_registers (m88k_fp_offset + 4, 1);
2017
2018   if (frame_pointer_needed)
2019     emit_add (frame_pointer_rtx, stack_pointer_rtx, m88k_fp_offset);
2020
2021   if (flag_pic && save_regs[PIC_OFFSET_TABLE_REGNUM])
2022     {
2023       rtx return_reg = gen_rtx_REG (SImode, 1);
2024       rtx label = gen_label_rtx ();
2025       rtx temp_reg = NULL_RTX;
2026
2027       if (! save_regs[1])
2028         {
2029           temp_reg = gen_rtx_REG (SImode, TEMP_REGNUM);
2030           emit_move_insn (temp_reg, return_reg);
2031         }
2032       emit_insn (gen_locate1 (pic_offset_table_rtx, label));
2033       emit_insn (gen_locate2 (pic_offset_table_rtx, label));
2034       emit_insn (gen_addsi3 (pic_offset_table_rtx,
2035                              pic_offset_table_rtx, return_reg));
2036       if (! save_regs[1])
2037         emit_move_insn (return_reg, temp_reg);
2038     }
2039   if (current_function_profile)
2040     emit_insn (gen_blockage ());
2041 }
2042 \f
2043 /* This function generates the assembly code for function exit,
2044    on machines that need it.
2045
2046    The function epilogue should not depend on the current stack pointer!
2047    It should use the frame pointer only, if there is a frame pointer.
2048    This is mandatory because of alloca; we also take advantage of it to
2049    omit stack adjustments before returning.  */
2050
2051 static void
2052 m88k_output_function_begin_epilogue (stream)
2053      FILE *stream;
2054 {
2055   if (TARGET_OCS_DEBUG_INFO && !epilogue_marked && prologue_marked)
2056     {
2057       PUT_OCS_FUNCTION_END (stream);
2058     }
2059   epilogue_marked = 1;
2060 }
2061
2062 static void
2063 m88k_output_function_epilogue (stream, size)
2064      FILE *stream;
2065      HOST_WIDE_INT size ATTRIBUTE_UNUSED;
2066 {
2067   rtx insn = get_last_insn ();
2068
2069   if (TARGET_OCS_DEBUG_INFO && !epilogue_marked)
2070     PUT_OCS_FUNCTION_END (stream);
2071
2072   /* If the last insn isn't a BARRIER, we must write a return insn.  This
2073      should only happen if the function has no prologue and no body.  */
2074   if (GET_CODE (insn) == NOTE)
2075     insn = prev_nonnote_insn (insn);
2076   if (insn == 0 || GET_CODE (insn) != BARRIER)
2077     fprintf (stream, "\tjmp\t %s\n", reg_names[1]);
2078
2079   /* If the last insn is a barrier, and the insn before that is a call,
2080      then add a nop instruction so that tdesc can walk the stack correctly
2081      even though there is no epilogue. (Otherwise, the label for the
2082      end of the tdesc region ends up at the start of the next function. */
2083   if (insn && GET_CODE (insn) == BARRIER)
2084     {
2085       insn = prev_nonnote_insn (insn);
2086       if (insn && GET_CODE (insn) == CALL_INSN)
2087         fprintf (stream, "\tor\t %s,%s,%s\n",reg_names[0],reg_names[0],reg_names[0]);
2088     }
2089
2090   output_short_branch_defs (stream);
2091
2092   fprintf (stream, "\n");
2093
2094   if (TARGET_OCS_DEBUG_INFO)
2095     output_tdesc (stream, m88k_fp_offset + 4);
2096
2097   m88k_function_number++;
2098   m88k_prologue_done    = 0;            /* don't put out ln directives */
2099   variable_args_p       = 0;            /* has variable args */
2100   frame_laid_out        = 0;
2101   epilogue_marked       = 0;
2102   prologue_marked       = 0;
2103 }
2104
2105 void
2106 m88k_expand_epilogue ()
2107 {
2108 #if (MONITOR_GCC & 0x4) /* What are interesting prologue/epilogue values?  */
2109   fprintf (stream, "; size = %d, m88k_fp_offset = %d, m88k_stack_size = %d\n",
2110            size, m88k_fp_offset, m88k_stack_size);
2111 #endif
2112
2113   if (frame_pointer_needed)
2114     emit_add (stack_pointer_rtx, frame_pointer_rtx, -m88k_fp_offset);
2115
2116   if (nregs || nxregs)
2117     preserve_registers (m88k_fp_offset + 4, 0);
2118
2119   if (m88k_stack_size)
2120     emit_add (stack_pointer_rtx, stack_pointer_rtx, m88k_stack_size);
2121 }
2122 \f
2123 /* Emit insns to set DSTREG to SRCREG + AMOUNT during the prologue or
2124    epilogue.  */
2125
2126 static void
2127 emit_add (dstreg, srcreg, amount)
2128      rtx dstreg;
2129      rtx srcreg;
2130      int amount;
2131 {
2132   rtx incr = GEN_INT (abs (amount));
2133
2134   if (! ADD_INTVAL (amount))
2135     {
2136       rtx temp = gen_rtx_REG (SImode, TEMP_REGNUM);
2137       emit_move_insn (temp, incr);
2138       incr = temp;
2139     }
2140   emit_insn ((amount < 0 ? gen_subsi3 : gen_addsi3) (dstreg, srcreg, incr));
2141 }
2142
2143 /* Save/restore the preserve registers.  base is the highest offset from
2144    r31 at which a register is stored.  store_p is true if stores are to
2145    be done; otherwise loads.  */
2146
2147 static void
2148 preserve_registers (base, store_p)
2149      int base;
2150      int store_p;
2151 {
2152   int regno, offset;
2153   struct mem_op {
2154     int regno;
2155     int nregs;
2156     int offset;
2157   } mem_op[FIRST_PSEUDO_REGISTER];
2158   struct mem_op *mo_ptr = mem_op;
2159
2160   /* The 88open OCS mandates that preserved registers be stored in
2161      increasing order.  For compatibility with current practice,
2162      the order is r1, r30, then the preserve registers.  */
2163
2164   offset = base;
2165   if (save_regs[1])
2166     {
2167       /* An extra word is given in this case to make best use of double
2168          memory ops.  */
2169       if (nregs > 2 && !save_regs[FRAME_POINTER_REGNUM])
2170         offset -= 4;
2171       emit_ldst (store_p, 1, SImode, offset);
2172       offset -= 4;
2173       base = offset;
2174     }
2175
2176   /* Walk the registers to save recording all single memory operations.  */
2177   for (regno = FRAME_POINTER_REGNUM; regno > 1; regno--)
2178     if (save_regs[regno])
2179       {
2180         if ((offset & 7) != 4 || (regno & 1) != 1 || !save_regs[regno-1])
2181           {
2182             mo_ptr->nregs = 1;
2183             mo_ptr->regno = regno;
2184             mo_ptr->offset = offset;
2185             mo_ptr++;
2186             offset -= 4;
2187           }
2188         else
2189           {
2190             regno--;
2191             offset -= 2*4;
2192           }
2193       }
2194
2195   /* Walk the registers to save recording all double memory operations.
2196      This avoids a delay in the epilogue (ld.d/ld).  */
2197   offset = base;
2198   for (regno = FRAME_POINTER_REGNUM; regno > 1; regno--)
2199     if (save_regs[regno])
2200       {
2201         if ((offset & 7) != 4 || (regno & 1) != 1 || !save_regs[regno-1])
2202           {
2203             offset -= 4;
2204           }
2205         else
2206           {
2207             mo_ptr->nregs = 2;
2208             mo_ptr->regno = regno-1;
2209             mo_ptr->offset = offset-4;
2210             mo_ptr++;
2211             regno--;
2212             offset -= 2*4;
2213           }
2214       }
2215
2216   /* Walk the extended registers to record all memory operations.  */
2217   /*  Be sure the offset is double word aligned.  */
2218   offset = (offset - 1) & ~7;
2219   for (regno = FIRST_PSEUDO_REGISTER - 1; regno > FIRST_EXTENDED_REGISTER;
2220        regno--)
2221     if (save_regs[regno])
2222       {
2223         mo_ptr->nregs = 2;
2224         mo_ptr->regno = regno;
2225         mo_ptr->offset = offset;
2226         mo_ptr++;
2227         offset -= 2*4;
2228       }
2229
2230   mo_ptr->regno = 0;
2231
2232   /* Output the memory operations.  */
2233   for (mo_ptr = mem_op; mo_ptr->regno; mo_ptr++)
2234     {
2235       if (mo_ptr->nregs)
2236         emit_ldst (store_p, mo_ptr->regno,
2237                    (mo_ptr->nregs > 1 ? DImode : SImode),
2238                    mo_ptr->offset);
2239     }
2240 }
2241
2242 static void
2243 emit_ldst (store_p, regno, mode, offset)
2244      int store_p;
2245      int regno;
2246      enum machine_mode mode;
2247      int offset;
2248 {
2249   rtx reg = gen_rtx_REG (mode, regno);
2250   rtx mem;
2251
2252   if (SMALL_INTVAL (offset))
2253     {
2254       mem = gen_rtx_MEM (mode, plus_constant (stack_pointer_rtx, offset));
2255     }
2256   else
2257     {
2258       /* offset is too large for immediate index must use register */
2259
2260       rtx disp = GEN_INT (offset);
2261       rtx temp = gen_rtx_REG (SImode, TEMP_REGNUM);
2262       rtx regi = gen_rtx_PLUS (SImode, stack_pointer_rtx, temp);
2263
2264       emit_move_insn (temp, disp);
2265       mem = gen_rtx_MEM (mode, regi);
2266     }
2267
2268   if (store_p)
2269     emit_move_insn (mem, reg);
2270   else
2271     emit_move_insn (reg, mem);
2272 }
2273
2274 /* Convert the address expression REG to a CFA offset.  */
2275
2276 int
2277 m88k_debugger_offset (reg, offset)
2278      register rtx reg;
2279      register int offset;
2280 {
2281   if (GET_CODE (reg) == PLUS)
2282     {
2283       offset = INTVAL (XEXP (reg, 1));
2284       reg = XEXP (reg, 0);
2285     }
2286
2287   /* Put the offset in terms of the CFA (arg pointer).  */
2288   if (reg == frame_pointer_rtx)
2289     offset += m88k_fp_offset - m88k_stack_size;
2290   else if (reg == stack_pointer_rtx)
2291     offset -= m88k_stack_size;
2292   else if (reg != arg_pointer_rtx)
2293     {
2294 #if (MONITOR_GCC & 0x10) /* Watch for suspicious symbolic locations.  */
2295       if (! (GET_CODE (reg) == REG
2296              && REGNO (reg) >= FIRST_PSEUDO_REGISTER))
2297         warning ("internal gcc error: Can't express symbolic location");
2298 #endif
2299       return 0;
2300     }
2301
2302   return offset;
2303 }
2304
2305 /* Output the 88open OCS proscribed text description information.
2306    The information is:
2307         0  8: zero
2308         0 22: info-byte-length (16 or 20 bytes)
2309         0  2: info-alignment (word 2)
2310         1 32: info-protocol (version 1 or 2(pic))
2311         2 32: starting-address (inclusive, not counting prologue)
2312         3 32: ending-address (exclusive, not counting epilog)
2313         4  8: info-variant (version 1 or 3(extended registers))
2314         4 17: register-save-mask (from register 14 to 30)
2315         4  1: zero
2316         4  1: return-address-info-discriminant
2317         4  5: frame-address-register
2318         5 32: frame-address-offset
2319         6 32: return-address-info
2320         7 32: register-save-offset
2321         8 16: extended-register-save-mask (x16 - x31)
2322         8 16: extended-register-save-offset (WORDS from register-save-offset)  */
2323
2324 static void
2325 output_tdesc (file, offset)
2326      FILE *file;
2327      int offset;
2328 {
2329   int regno, i, j;
2330   long mask, return_address_info, register_save_offset;
2331   long xmask, xregister_save_offset;
2332   char buf[256];
2333
2334   for (mask = 0, i = 0, regno = FIRST_OCS_PRESERVE_REGISTER;
2335        regno <= LAST_OCS_PRESERVE_REGISTER;
2336        regno++)
2337     {
2338       mask <<= 1;
2339       if (save_regs[regno])
2340         {
2341           mask |= 1;
2342           i++;
2343         }
2344     }
2345
2346   for (xmask = 0, j = 0, regno = FIRST_OCS_EXTENDED_PRESERVE_REGISTER;
2347        regno <= LAST_OCS_EXTENDED_PRESERVE_REGISTER;
2348        regno++)
2349     {
2350       xmask <<= 1;
2351       if (save_regs[regno])
2352         {
2353           xmask |= 1;
2354           j++;
2355         }
2356     }
2357
2358   if (save_regs[1])
2359     {
2360       if ((nxregs > 0 || nregs > 2) && !save_regs[FRAME_POINTER_REGNUM])
2361         offset -= 4;
2362       return_address_info = - m88k_stack_size + offset;
2363       register_save_offset = return_address_info - i*4;
2364     }
2365   else
2366     {
2367       return_address_info = 1;
2368       register_save_offset = - m88k_stack_size + offset + 4 - i*4;
2369     }
2370
2371   xregister_save_offset = - (j * 2 + ((register_save_offset >> 2) & 1));
2372
2373   tdesc_section ();
2374
2375   /* 8:0,22:(20 or 16),2:2 */
2376   fprintf (file, "%s%d,%d", integer_asm_op (4, TRUE),
2377            (((xmask != 0) ? 20 : 16) << 2) | 2,
2378            flag_pic ? 2 : 1);
2379
2380   ASM_GENERATE_INTERNAL_LABEL (buf, OCS_START_PREFIX, m88k_function_number);
2381   fprintf (file, ",%s%s", buf+1, flag_pic ? "#rel" : "");
2382   ASM_GENERATE_INTERNAL_LABEL (buf, OCS_END_PREFIX, m88k_function_number);
2383   fprintf (file, ",%s%s", buf+1, flag_pic ? "#rel" : "");
2384
2385   fprintf (file, ",0x%x,0x%x,0x%lx,0x%lx",
2386            /* 8:1,17:0x%.3x,1:0,1:%d,5:%d */
2387            (int)(((xmask ? 3 : 1) << (17+1+1+5))
2388             | (mask << (1+1+5))
2389             | ((!!save_regs[1]) << 5)
2390             | (frame_pointer_needed
2391                ? FRAME_POINTER_REGNUM
2392                : STACK_POINTER_REGNUM)),
2393            (m88k_stack_size - (frame_pointer_needed ? m88k_fp_offset : 0)),
2394            return_address_info,
2395            register_save_offset);
2396   if (xmask)
2397     fprintf (file, ",0x%lx%04lx", xmask, (0xffff & xregister_save_offset));
2398   fputc ('\n', file);
2399
2400   text_section ();
2401 }
2402 \f
2403 /* Output assembler code to FILE to increment profiler label # LABELNO
2404    for profiling a function entry.  NAME is the mcount function name
2405    (varies), SAVEP indicates whether the parameter registers need to
2406    be saved and restored.  */
2407
2408 void
2409 output_function_profiler (file, labelno, name, savep)
2410      FILE *file;
2411      int labelno;
2412      const char *name;
2413      int savep;
2414 {
2415   char label[256];
2416   char dbi[256];
2417   const char *const temp = (savep ? reg_names[2] : reg_names[10]);
2418
2419   /* Remember to update FUNCTION_PROFILER_LENGTH.  */
2420
2421   if (savep)
2422     {
2423       fprintf (file, "\tsubu\t %s,%s,64\n", reg_names[31], reg_names[31]);
2424       fprintf (file, "\tst.d\t %s,%s,32\n", reg_names[2], reg_names[31]);
2425       fprintf (file, "\tst.d\t %s,%s,40\n", reg_names[4], reg_names[31]);
2426       fprintf (file, "\tst.d\t %s,%s,48\n", reg_names[6], reg_names[31]);
2427       fprintf (file, "\tst.d\t %s,%s,56\n", reg_names[8], reg_names[31]);
2428     }
2429
2430   ASM_GENERATE_INTERNAL_LABEL (label, "LP", labelno);
2431   if (flag_pic == 2)
2432     {
2433       fprintf (file, "\tor.u\t %s,%s,%shi16(%s#got_rel)\n",
2434                temp, reg_names[0], m88k_pound_sign, &label[1]);
2435       fprintf (file, "\tor\t %s,%s,%slo16(%s#got_rel)\n",
2436                temp, temp, m88k_pound_sign, &label[1]);
2437       sprintf (dbi, "\tld\t %s,%s,%s\n", temp,
2438                reg_names[PIC_OFFSET_TABLE_REGNUM], temp);
2439     }
2440   else if (flag_pic)
2441     {
2442       sprintf (dbi, "\tld\t %s,%s,%s#got_rel\n", temp,
2443                reg_names[PIC_OFFSET_TABLE_REGNUM], &label[1]);
2444     }
2445   else
2446     {
2447       fprintf (file, "\tor.u\t %s,%s,%shi16(%s)\n",
2448                temp, reg_names[0], m88k_pound_sign, &label[1]);
2449       sprintf (dbi, "\tor\t %s,%s,%slo16(%s)\n",
2450                temp, temp, m88k_pound_sign, &label[1]);
2451     }
2452
2453   if (flag_pic)
2454     fprintf (file, "\tbsr.n\t %s#plt\n", name);
2455   else
2456     fprintf (file, "\tbsr.n\t %s\n", name);
2457   fputs (dbi, file);
2458
2459   if (savep)
2460     {
2461       fprintf (file, "\tld.d\t %s,%s,32\n", reg_names[2], reg_names[31]);
2462       fprintf (file, "\tld.d\t %s,%s,40\n", reg_names[4], reg_names[31]);
2463       fprintf (file, "\tld.d\t %s,%s,48\n", reg_names[6], reg_names[31]);
2464       fprintf (file, "\tld.d\t %s,%s,56\n", reg_names[8], reg_names[31]);
2465       fprintf (file, "\taddu\t %s,%s,64\n", reg_names[31], reg_names[31]);
2466     }
2467 }
2468
2469 /* Output assembler code to FILE to initialize basic-block profiling for
2470    the current module.  LABELNO is unique to each instance.  */
2471
2472 void
2473 output_function_block_profiler (file, labelno)
2474      FILE *file;
2475      int labelno;
2476 {
2477   char block[256];
2478   char label[256];
2479
2480   /* Remember to update FUNCTION_BLOCK_PROFILER_LENGTH.  */
2481
2482   ASM_GENERATE_INTERNAL_LABEL (block, "LPBX", 0);
2483   ASM_GENERATE_INTERNAL_LABEL (label, "LPY", labelno);
2484
2485   /* @@ Need to deal with PIC.  I'm not sure what the requirements are on
2486      register usage, so I used r26/r27 to be safe.  */
2487   fprintf (file, "\tor.u\t %s,%s,%shi16(%s)\n", reg_names[27], reg_names[0],
2488                  m88k_pound_sign, &block[1]);
2489   fprintf (file, "\tld\t %s,%s,%slo16(%s)\n", reg_names[26], reg_names[27],
2490                  m88k_pound_sign, &block[1]);
2491   fprintf (file, "\tbcnd\t %sne0,%s,%s\n",
2492                  m88k_pound_sign, reg_names[26], &label[1]);
2493   fprintf (file, "\tsubu\t %s,%s,64\n", reg_names[31], reg_names[31]);
2494   fprintf (file, "\tst.d\t %s,%s,32\n", reg_names[2], reg_names[31]);
2495   fprintf (file, "\tst.d\t %s,%s,40\n", reg_names[4], reg_names[31]);
2496   fprintf (file, "\tst.d\t %s,%s,48\n", reg_names[6], reg_names[31]);
2497   fprintf (file, "\tst.d\t %s,%s,56\n", reg_names[8], reg_names[31]);
2498   fputs ("\tbsr.n\t ", file);
2499   ASM_OUTPUT_LABELREF (file, "__bb_init_func");
2500   putc ('\n', file);
2501   fprintf (file, "\tor\t %s,%s,%slo16(%s)\n", reg_names[2], reg_names[27],
2502                  m88k_pound_sign, &block[1]);
2503   fprintf (file, "\tld.d\t %s,%s,32\n", reg_names[2], reg_names[31]);
2504   fprintf (file, "\tld.d\t %s,%s,40\n", reg_names[4], reg_names[31]);
2505   fprintf (file, "\tld.d\t %s,%s,48\n", reg_names[6], reg_names[31]);
2506   fprintf (file, "\tld.d\t %s,%s,56\n", reg_names[8], reg_names[31]);
2507   fprintf (file, "\taddu\t %s,%s,64\n", reg_names[31], reg_names[31]);
2508   ASM_OUTPUT_INTERNAL_LABEL (file, "LPY", labelno);
2509 }
2510
2511 /* Output assembler code to FILE to increment the count associated with
2512    the basic block number BLOCKNO.  */
2513
2514 void
2515 output_block_profiler (file, blockno)
2516      FILE *file;
2517      int blockno;
2518 {
2519   char block[256];
2520
2521   /* Remember to update BLOCK_PROFILER_LENGTH.  */
2522
2523   ASM_GENERATE_INTERNAL_LABEL (block, "LPBX", 2);
2524
2525   /* @@ Need to deal with PIC.  I'm not sure what the requirements are on
2526      register usage, so I used r26/r27 to be safe.  */
2527   fprintf (file, "\tor.u\t %s,%s,%shi16(%s+%d)\n", reg_names[27], reg_names[0],
2528            m88k_pound_sign, &block[1], 4 * blockno);
2529   fprintf (file, "\tld\t %s,%s,%slo16(%s+%d)\n", reg_names[26], reg_names[27],
2530            m88k_pound_sign, &block[1], 4 * blockno);
2531   fprintf (file, "\taddu\t %s,%s,1\n", reg_names[26], reg_names[26]);
2532   fprintf (file, "\tst\t %s,%s,%slo16(%s+%d)\n", reg_names[26], reg_names[27],
2533            m88k_pound_sign, &block[1], 4 * blockno);
2534 }
2535 \f
2536 /* Determine whether a function argument is passed in a register, and
2537    which register.
2538
2539    The arguments are CUM, which summarizes all the previous
2540    arguments; MODE, the machine mode of the argument; TYPE,
2541    the data type of the argument as a tree node or 0 if that is not known
2542    (which happens for C support library functions); and NAMED,
2543    which is 1 for an ordinary argument and 0 for nameless arguments that
2544    correspond to `...' in the called function's prototype.
2545
2546    The value of the expression should either be a `reg' RTX for the
2547    hard register in which to pass the argument, or zero to pass the
2548    argument on the stack.
2549
2550    On the m88000 the first eight words of args are normally in registers
2551    and the rest are pushed.  Double precision floating point must be
2552    double word aligned (and if in a register, starting on an even
2553    register). Structures and unions which are not 4 byte, and word
2554    aligned are passed in memory rather than registers, even if they
2555    would fit completely in the registers under OCS rules.
2556
2557    Note that FUNCTION_ARG and FUNCTION_INCOMING_ARG were different.
2558    For structures that are passed in memory, but could have been
2559    passed in registers, we first load the structure into the
2560    register, and then when the last argument is passed, we store
2561    the registers into the stack locations.  This fixes some bugs
2562    where GCC did not expect to have register arguments, followed
2563    by stack arguments, followed by register arguments.  */
2564
2565 struct rtx_def *
2566 m88k_function_arg (args_so_far, mode, type, named)
2567      CUMULATIVE_ARGS args_so_far;
2568      enum machine_mode mode;
2569      tree type;
2570      int named ATTRIBUTE_UNUSED;
2571 {
2572   int bytes, words;
2573
2574   if (type != 0                 /* undo putting struct in register */
2575       && (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE))
2576     mode = BLKmode;
2577
2578   if (mode == BLKmode && TARGET_WARN_PASS_STRUCT)
2579     warning ("argument #%d is a structure", args_so_far + 1);
2580
2581   if ((args_so_far & 1) != 0
2582       && (mode == DImode || mode == DFmode
2583           || (type != 0 && TYPE_ALIGN (type) > 32)))
2584     args_so_far++;
2585
2586 #ifdef ESKIT
2587   if (no_reg_params)
2588     return (rtx) 0;             /* don't put args in registers */
2589 #endif
2590
2591   if (type == 0 && mode == BLKmode)
2592     abort ();   /* m88k_function_arg argument `type' is NULL for BLKmode. */
2593
2594   bytes = (mode != BLKmode) ? GET_MODE_SIZE (mode) : int_size_in_bytes (type);
2595   words = (bytes + 3) / 4;
2596
2597   if (args_so_far + words > 8)
2598     return (rtx) 0;             /* args have exhausted registers */
2599
2600   else if (mode == BLKmode
2601            && (TYPE_ALIGN (type) != BITS_PER_WORD
2602                || bytes != UNITS_PER_WORD))
2603     return (rtx) 0;
2604
2605   return gen_rtx_REG (((mode == BLKmode) ? TYPE_MODE (type) : mode),
2606                       2 + args_so_far);
2607 }
2608 \f
2609 /* Do what is necessary for `va_start'.  We look at the current function
2610    to determine if stdargs or varargs is used and spill as necessary. 
2611    We return a pointer to the spill area.  */
2612
2613 struct rtx_def *
2614 m88k_builtin_saveregs ()
2615 {
2616   rtx addr;
2617   tree fntype = TREE_TYPE (current_function_decl);
2618   int argadj = ((!(TYPE_ARG_TYPES (fntype) != 0
2619                    && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
2620                        != void_type_node)))
2621                 ? -UNITS_PER_WORD : 0) + UNITS_PER_WORD - 1;
2622   int fixed;
2623
2624   variable_args_p = 1;
2625
2626   fixed = 0;
2627   if (GET_CODE (current_function_arg_offset_rtx) == CONST_INT)
2628     fixed = ((INTVAL (current_function_arg_offset_rtx) + argadj)
2629              / UNITS_PER_WORD);
2630
2631   /* Allocate the register space, and store it as the __va_reg member.  */
2632   addr = assign_stack_local (BLKmode, 8 * UNITS_PER_WORD, -1);
2633   set_mem_alias_set (addr, get_varargs_alias_set ());
2634   RTX_UNCHANGING_P (addr) = 1;
2635   RTX_UNCHANGING_P (XEXP (addr, 0)) = 1;
2636
2637   /* Now store the incoming registers.  */
2638   if (fixed < 8)
2639     move_block_from_reg (2 + fixed,
2640                          adjust_address (addr, Pmode, fixed * UNITS_PER_WORD),
2641                          8 - fixed,
2642                          UNITS_PER_WORD * (8 - fixed));
2643
2644   /* Return the address of the save area, but don't put it in a
2645      register.  This fails when not optimizing and produces worse code
2646      when optimizing.  */
2647   return XEXP (addr, 0);
2648 }
2649
2650 /* Define the `__builtin_va_list' type for the ABI.  */
2651
2652 tree
2653 m88k_build_va_list ()
2654 {
2655   tree field_reg, field_stk, field_arg, int_ptr_type_node, record;
2656
2657   int_ptr_type_node = build_pointer_type (integer_type_node);
2658
2659   record = make_node (RECORD_TYPE);
2660
2661   field_arg = build_decl (FIELD_DECL, get_identifier ("__va_arg"),
2662                           integer_type_node);
2663   field_stk = build_decl (FIELD_DECL, get_identifier ("__va_stk"),
2664                           int_ptr_type_node);
2665   field_reg = build_decl (FIELD_DECL, get_identifier ("__va_reg"),
2666                           int_ptr_type_node);
2667
2668   DECL_FIELD_CONTEXT (field_arg) = record;
2669   DECL_FIELD_CONTEXT (field_stk) = record;
2670   DECL_FIELD_CONTEXT (field_reg) = record;
2671
2672   TYPE_FIELDS (record) = field_arg;
2673   TREE_CHAIN (field_arg) = field_stk;
2674   TREE_CHAIN (field_stk) = field_reg;
2675
2676   layout_type (record);
2677   return record;
2678 }
2679
2680 /* Implement `va_start' for varargs and stdarg.  */
2681
2682 void
2683 m88k_va_start (stdarg_p, valist, nextarg)
2684      int stdarg_p ATTRIBUTE_UNUSED;
2685      tree valist;
2686      rtx nextarg ATTRIBUTE_UNUSED;
2687 {
2688   tree field_reg, field_stk, field_arg;
2689   tree reg, stk, arg, t;
2690
2691   field_arg = TYPE_FIELDS (va_list_type_node);
2692   field_stk = TREE_CHAIN (field_arg);
2693   field_reg = TREE_CHAIN (field_stk);
2694
2695   arg = build (COMPONENT_REF, TREE_TYPE (field_arg), valist, field_arg);
2696   stk = build (COMPONENT_REF, TREE_TYPE (field_stk), valist, field_stk);
2697   reg = build (COMPONENT_REF, TREE_TYPE (field_reg), valist, field_reg);
2698
2699   /* Fill in the ARG member.  */
2700   {
2701     tree fntype = TREE_TYPE (current_function_decl);
2702     int argadj = ((!(TYPE_ARG_TYPES (fntype) != 0
2703                      && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
2704                          != void_type_node)))
2705                   ? -UNITS_PER_WORD : 0) + UNITS_PER_WORD - 1;
2706     tree argsize;
2707
2708     if (CONSTANT_P (current_function_arg_offset_rtx))
2709       {
2710         int fixed = (INTVAL (current_function_arg_offset_rtx)
2711                      + argadj) / UNITS_PER_WORD;
2712
2713         argsize = build_int_2 (fixed, 0);
2714       }
2715     else
2716       {
2717         argsize = make_tree (integer_type_node,
2718                              current_function_arg_offset_rtx);
2719         argsize = fold (build (PLUS_EXPR, integer_type_node, argsize,
2720                                build_int_2 (argadj, 0)));
2721         argsize = fold (build (RSHIFT_EXPR, integer_type_node, argsize,
2722                                build_int_2 (2, 0)));
2723       }
2724
2725     t = build (MODIFY_EXPR, TREE_TYPE (arg), arg, argsize);
2726     TREE_SIDE_EFFECTS (t) = 1;
2727     expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
2728   }
2729
2730   /* Store the arg pointer in the __va_stk member.  */
2731   t = make_tree (TREE_TYPE (stk), virtual_incoming_args_rtx);
2732   t = build (MODIFY_EXPR, TREE_TYPE (stk), stk, t);
2733   TREE_SIDE_EFFECTS (t) = 1;
2734   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
2735
2736   /* Tuck the return value from __builtin_saveregs into __va_reg.  */
2737   t = make_tree (TREE_TYPE (reg), expand_builtin_saveregs ());
2738   t = build (MODIFY_EXPR, TREE_TYPE (reg), reg, t);
2739   TREE_SIDE_EFFECTS (t) = 1;
2740   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
2741 }
2742
2743 /* Implement `va_arg'.  */
2744
2745 rtx
2746 m88k_va_arg (valist, type)
2747      tree valist, type;
2748 {
2749   tree field_reg, field_stk, field_arg;
2750   tree reg, stk, arg, arg_align, base, t;
2751   int size, wsize, align, reg_p;
2752   rtx addr_rtx;
2753
2754   field_arg = TYPE_FIELDS (va_list_type_node);
2755   field_stk = TREE_CHAIN (field_arg);
2756   field_reg = TREE_CHAIN (field_stk);
2757
2758   arg = build (COMPONENT_REF, TREE_TYPE (field_arg), valist, field_arg);
2759   stk = build (COMPONENT_REF, TREE_TYPE (field_stk), valist, field_stk);
2760   reg = build (COMPONENT_REF, TREE_TYPE (field_reg), valist, field_reg);
2761
2762   size = int_size_in_bytes (type);
2763   wsize = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
2764   align = 1 << ((TYPE_ALIGN (type) / BITS_PER_UNIT) >> 3);
2765   reg_p = (AGGREGATE_TYPE_P (type)
2766            ? size == UNITS_PER_WORD && TYPE_ALIGN (type) == BITS_PER_WORD
2767            : size <= 2*UNITS_PER_WORD);
2768
2769   /* Align __va_arg to the (doubleword?) boundary above.  */
2770   t = build (PLUS_EXPR, TREE_TYPE (arg), arg, build_int_2 (align - 1, 0));
2771   arg_align = build (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-align, -1));
2772   arg_align = save_expr (arg_align);
2773
2774   /* Decide if we should read from stack or regs.  */
2775   t = build (LT_EXPR, integer_type_node, arg_align, build_int_2 (8, 0));
2776   base = build (COND_EXPR, TREE_TYPE (reg), t, reg, stk);
2777
2778   /* Find the final address.  */
2779   t = build (PLUS_EXPR, TREE_TYPE (base), base, arg_align);
2780   addr_rtx = expand_expr (t, NULL_RTX, Pmode, EXPAND_NORMAL);
2781   addr_rtx = copy_to_reg (addr_rtx);
2782
2783   /* Increment __va_arg.  */
2784   t = build (PLUS_EXPR, TREE_TYPE (arg), arg_align, build_int_2 (wsize, 0));
2785   t = build (MODIFY_EXPR, TREE_TYPE (arg), arg, t);
2786   TREE_SIDE_EFFECTS (t) = 1;
2787   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
2788
2789   return addr_rtx;
2790 }
2791 \f
2792 /* If cmpsi has not been generated, emit code to do the test.  Return the
2793    expression describing the test of operator OP.  */
2794
2795 rtx
2796 emit_test (op, mode)
2797      enum rtx_code op;
2798      enum machine_mode mode;
2799 {
2800   if (m88k_compare_reg == 0)
2801     emit_insn (gen_test (m88k_compare_op0, m88k_compare_op1));
2802   return (gen_rtx (op, mode, m88k_compare_reg, const0_rtx));
2803 }
2804
2805 /* Determine how to best perform cmpsi/bxx, where cmpsi has a constant
2806    operand.  All tests with zero (albeit swapped) and all equality tests
2807    with a constant are done with bcnd.  The remaining cases are swapped
2808    as needed.  */
2809
2810 void
2811 emit_bcnd (op, label)
2812      enum rtx_code op;
2813      rtx label;
2814 {
2815   if (m88k_compare_op1 == const0_rtx)
2816     emit_jump_insn (gen_bcnd
2817                     (gen_rtx (op, VOIDmode,m88k_compare_op0, const0_rtx),
2818                      label));
2819   else if (m88k_compare_op0 == const0_rtx)
2820     emit_jump_insn (gen_bcnd
2821                     (gen_rtx (swap_condition (op),
2822                               VOIDmode, m88k_compare_op1, const0_rtx),
2823                      label));
2824   else if (op != EQ && op != NE)
2825     emit_jump_insn (gen_bxx (emit_test (op, VOIDmode), label));
2826   else
2827     {
2828       rtx zero = gen_reg_rtx (SImode);
2829       rtx reg, constant;
2830       int value;
2831
2832       if (GET_CODE (m88k_compare_op1) == CONST_INT)
2833         {
2834           reg = force_reg (SImode, m88k_compare_op0);
2835           constant = m88k_compare_op1;
2836         }
2837       else
2838         {
2839           reg = force_reg (SImode, m88k_compare_op1);
2840           constant = m88k_compare_op0;
2841         }
2842       value = INTVAL (constant);
2843
2844       /* Perform an arithmetic computation to make the compared-to value
2845          zero, but avoid loosing if the bcnd is later changed into sxx.  */
2846       if (SMALL_INTVAL (value))
2847         emit_jump_insn (gen_bxx (emit_test (op, VOIDmode), label));
2848       else
2849         {
2850           if (SMALL_INTVAL (-value))
2851             emit_insn (gen_addsi3 (zero, reg,
2852                                    GEN_INT (-value)));
2853           else
2854             emit_insn (gen_xorsi3 (zero, reg, constant));
2855
2856           emit_jump_insn (gen_bcnd (gen_rtx (op, VOIDmode,
2857                                              zero, const0_rtx),
2858                                     label));
2859         }
2860     }
2861 }
2862 \f
2863 /* Print an operand.  Recognize special options, documented below.  */
2864
2865 void
2866 print_operand (file, x, code)
2867     FILE *file;
2868     rtx x;
2869     int code;
2870 {
2871   enum rtx_code xc = (x ? GET_CODE (x) : UNKNOWN);
2872   register int value = (xc == CONST_INT ? INTVAL (x) : 0);
2873   static int sequencep;
2874   static int reversep;
2875
2876   if (sequencep)
2877     {
2878       if (code < 'B' || code > 'E')
2879         output_operand_lossage ("%%R not followed by %%B/C/D/E");
2880       if (reversep)
2881         xc = reverse_condition (xc);
2882       sequencep = 0;
2883     }
2884
2885   switch (code)
2886     {
2887     case '*': /* addressing base register for PIC */
2888       fputs (reg_names[PIC_OFFSET_TABLE_REGNUM], file); return;
2889
2890     case '#': /* SVR4 pound-sign syntax character (empty if SVR3) */
2891       fputs (m88k_pound_sign, file); return;
2892
2893     case 'V': /* Output a serializing instruction as needed if the operand
2894                  (assumed to be a MEM) is a volatile load.  */
2895     case 'v': /* ditto for a volatile store.  */
2896       if (MEM_VOLATILE_P (x) && TARGET_SERIALIZE_VOLATILE)
2897         {
2898           /* The m88110 implements two FIFO queues, one for loads and
2899              one for stores.  These queues mean that loads complete in
2900              their issue order as do stores.  An interaction between the
2901              history buffer and the store reservation station ensures
2902              that a store will not bypass load.  Finally, a load will not
2903              bypass store, but only when they reference the same address.
2904
2905              To avoid this reordering (a load bypassing a store) for
2906              volatile references, a serializing instruction is output.
2907              We choose the fldcr instruction as it does not serialize on
2908              the m88100 so that -m88000 code will not be degraded.
2909
2910              The mechanism below is completed by having CC_STATUS_INIT set
2911              the code to the unknown value.  */
2912
2913           /*
2914              hassey 6/30/93
2915              A problem with 88110 4.1 & 4.2 makes the use of fldcr for
2916              this purpose undesirable.  Instead we will use tb1, this will
2917              cause serialization on the 88100 but such is life.
2918           */
2919
2920           static rtx last_addr = 0;
2921           if (code == 'V' /* Only need to serialize before a load.  */
2922               && m88k_volatile_code != 'V' /* Loads complete in FIFO order.  */
2923               && !(m88k_volatile_code == 'v'
2924                    && GET_CODE (XEXP (x, 0)) == LO_SUM
2925                    && rtx_equal_p (XEXP (XEXP (x, 0), 1), last_addr)))
2926             fprintf (file,
2927 #if 0
2928 #ifdef AS_BUG_FLDCR
2929                      "fldcr\t %s,%scr63\n\t",
2930 #else
2931                      "fldcr\t %s,%sfcr63\n\t",
2932 #endif
2933                      reg_names[0], m88k_pound_sign);
2934 #else /* 0 */
2935                      "tb1\t 1,%s,0xff\n\t", reg_names[0]);
2936 #endif /* 0 */
2937           m88k_volatile_code = code;
2938           last_addr = (GET_CODE (XEXP (x, 0)) == LO_SUM
2939                        ? XEXP (XEXP (x, 0), 1) : 0);
2940         }
2941       return;
2942
2943     case 'X': /* print the upper 16 bits... */
2944       value >>= 16;
2945     case 'x': /* print the lower 16 bits of the integer constant in hex */
2946       if (xc != CONST_INT)
2947         output_operand_lossage ("invalid %%x/X value");
2948       fprintf (file, "0x%x", value & 0xffff); return;
2949
2950     case 'H': /* print the low 16 bits of the negated integer constant */
2951       if (xc != CONST_INT)
2952         output_operand_lossage ("invalid %%H value");
2953       value = -value;
2954     case 'h': /* print the register or low 16 bits of the integer constant */
2955       if (xc == REG)
2956         goto reg;
2957       if (xc != CONST_INT)
2958         output_operand_lossage ("invalid %%h value");
2959       fprintf (file, "%d", value & 0xffff);
2960       return;
2961
2962     case 'Q': /* print the low 8 bits of the negated integer constant */
2963       if (xc != CONST_INT)
2964         output_operand_lossage ("invalid %%Q value");
2965       value = -value;
2966     case 'q': /* print the register or low 8 bits of the integer constant */
2967       if (xc == REG)
2968         goto reg;
2969       if (xc != CONST_INT)
2970         output_operand_lossage ("invalid %%q value");
2971       fprintf (file, "%d", value & 0xff);
2972       return;
2973
2974     case 'w': /* print the integer constant (X == 32 ? 0 : 32 - X) */
2975       if (xc != CONST_INT)
2976         output_operand_lossage ("invalid %%o value");
2977       fprintf (file, "%d", value == 32 ? 0 : 32 - value);
2978       return;
2979
2980     case 'p': /* print the logarithm of the integer constant */
2981       if (xc != CONST_INT
2982           || (value = exact_log2 (value)) < 0)
2983         output_operand_lossage ("invalid %%p value");
2984       fprintf (file, "%d", value);
2985       return;
2986
2987     case 'S': /* compliment the value and then... */
2988       value = ~value;
2989     case 's': /* print the width and offset values forming the integer
2990                  constant with a SET instruction.  See integer_ok_for_set. */
2991       {
2992         register unsigned mask, uval = value;
2993         register int top, bottom;
2994
2995         if (xc != CONST_INT)
2996           output_operand_lossage ("invalid %%s/S value");
2997         /* All the "one" bits must be contiguous.  If so, MASK will be
2998            a power of two or zero.  */
2999         mask = (uval | (uval - 1)) + 1;
3000         if (!(uval && POWER_OF_2_or_0 (mask)))
3001           output_operand_lossage ("invalid %%s/S value");
3002         top = mask ? exact_log2 (mask) : 32;
3003         bottom = exact_log2 (uval & ~(uval - 1));
3004         fprintf (file,"%d<%d>", top - bottom, bottom);
3005         return;
3006       }
3007
3008     case 'P': /* print nothing if pc_rtx; output label_ref */
3009       if (xc == LABEL_REF)
3010         output_addr_const (file, x);
3011       else if (xc != PC)
3012         output_operand_lossage ("invalid %%P operand");
3013       return;
3014
3015     case 'L': /* print 0 or 1 if operand is label_ref and then...  */
3016       fputc (xc == LABEL_REF ? '1' : '0', file);
3017     case '.': /* print .n if delay slot is used */
3018       fputs ((final_sequence
3019               && ! INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0)))
3020              ? ".n\t" : "\t", file);
3021       return;
3022
3023     case '!': /* Reverse the following condition. */
3024       sequencep++;
3025       reversep = 1;
3026       return; 
3027     case 'R': /* reverse the condition of the next print_operand
3028                  if operand is a label_ref.  */
3029       sequencep++;
3030       reversep = (xc == LABEL_REF);
3031       return;
3032
3033     case 'B': /* bcnd branch values */
3034       fputs (m88k_pound_sign, file);
3035       switch (xc)
3036         {
3037         case EQ: fputs ("eq0", file); return;
3038         case NE: fputs ("ne0", file); return;
3039         case GT: fputs ("gt0", file); return;
3040         case LE: fputs ("le0", file); return;
3041         case LT: fputs ("lt0", file); return;
3042         case GE: fputs ("ge0", file); return;
3043         default: output_operand_lossage ("invalid %%B value");
3044         }
3045
3046     case 'C': /* bb0/bb1 branch values for comparisons */
3047       fputs (m88k_pound_sign, file);
3048       switch (xc)
3049         {
3050         case EQ:  fputs ("eq", file); return;
3051         case NE:  fputs ("ne", file); return;
3052         case GT:  fputs ("gt", file); return;
3053         case LE:  fputs ("le", file); return;
3054         case LT:  fputs ("lt", file); return;
3055         case GE:  fputs ("ge", file); return;
3056         case GTU: fputs ("hi", file); return;
3057         case LEU: fputs ("ls", file); return;
3058         case LTU: fputs ("lo", file); return;
3059         case GEU: fputs ("hs", file); return;
3060         default:  output_operand_lossage ("invalid %%C value");
3061         }
3062
3063     case 'D': /* bcnd branch values for float comparisons */
3064       switch (xc)
3065         {
3066         case EQ: fputs ("0xa", file); return;
3067         case NE: fputs ("0x5", file); return;
3068         case GT: fputs (m88k_pound_sign, file);
3069           fputs ("gt0", file); return;
3070         case LE: fputs ("0xe", file); return;
3071         case LT: fputs ("0x4", file); return;
3072         case GE: fputs ("0xb", file); return;
3073         default: output_operand_lossage ("invalid %%D value");
3074         }
3075
3076     case 'E': /* bcnd branch values for special integers */
3077       switch (xc)
3078         {
3079         case EQ: fputs ("0x8", file); return;
3080         case NE: fputs ("0x7", file); return;
3081         default: output_operand_lossage ("invalid %%E value");
3082         }
3083
3084     case 'd': /* second register of a two register pair */
3085       if (xc != REG)
3086         output_operand_lossage ("`%%d' operand isn't a register");
3087       fputs (reg_names[REGNO (x) + 1], file);
3088       return;
3089
3090     case 'r': /* an immediate 0 should be represented as `r0' */
3091       if (x == const0_rtx)
3092         {
3093           fputs (reg_names[0], file);
3094           return;
3095         }
3096       else if (xc != REG)
3097         output_operand_lossage ("invalid %%r value");
3098     case 0:
3099     name:
3100       if (xc == REG)
3101         {
3102         reg:
3103           if (REGNO (x) == ARG_POINTER_REGNUM)
3104             output_operand_lossage ("operand is r0");
3105           else
3106             fputs (reg_names[REGNO (x)], file);
3107         }
3108       else if (xc == PLUS)
3109         output_address (x);
3110       else if (xc == MEM)
3111         output_address (XEXP (x, 0));
3112       else if (flag_pic && xc == UNSPEC)
3113         {
3114           output_addr_const (file, XVECEXP (x, 0, 0));
3115           fputs ("#got_rel", file);
3116         }
3117       else if (xc == CONST_DOUBLE)
3118         output_operand_lossage ("operand is const_double");
3119       else
3120         output_addr_const (file, x);
3121       return;
3122
3123     case 'g': /* append #got_rel as needed */
3124       if (flag_pic && (xc == SYMBOL_REF || xc == LABEL_REF))
3125         {
3126           output_addr_const (file, x);
3127           fputs ("#got_rel", file);
3128           return;
3129         }
3130       goto name;
3131
3132     case 'a': /* (standard), assume operand is an address */
3133     case 'c': /* (standard), assume operand is an immediate value */
3134     case 'l': /* (standard), assume operand is a label_ref */
3135     case 'n': /* (standard), like %c, except negate first */
3136     default:
3137       output_operand_lossage ("invalid code");
3138     }
3139 }
3140
3141 void
3142 print_operand_address (file, addr)
3143     FILE *file;
3144     rtx addr;
3145 {
3146   register rtx reg0, reg1, temp;
3147
3148   switch (GET_CODE (addr))
3149     {
3150     case REG:
3151       if (REGNO (addr) == ARG_POINTER_REGNUM)
3152         abort ();
3153       else
3154         fprintf (file, "%s,%s", reg_names[0], reg_names [REGNO (addr)]);
3155       break;
3156
3157     case LO_SUM:
3158       fprintf (file, "%s,%slo16(",
3159                reg_names[REGNO (XEXP (addr, 0))], m88k_pound_sign);
3160       output_addr_const (file, XEXP (addr, 1));
3161       fputc (')', file);
3162       break;
3163
3164     case PLUS:
3165       reg0 = XEXP (addr, 0);
3166       reg1 = XEXP (addr, 1);
3167       if (GET_CODE (reg0) == MULT || GET_CODE (reg0) == CONST_INT)
3168         {
3169           rtx tmp = reg0;
3170           reg0 = reg1;
3171           reg1 = tmp;
3172         }
3173
3174       if ((REG_P (reg0) && REGNO (reg0) == ARG_POINTER_REGNUM)
3175           || (REG_P (reg1) && REGNO (reg1) == ARG_POINTER_REGNUM))
3176         abort ();
3177
3178       else if (REG_P (reg0))
3179         {
3180           if (REG_P (reg1))
3181             fprintf (file, "%s,%s",
3182                      reg_names [REGNO (reg0)], reg_names [REGNO (reg1)]);
3183
3184           else if (GET_CODE (reg1) == CONST_INT)
3185             fprintf (file, "%s,%d",
3186                      reg_names [REGNO (reg0)], INTVAL (reg1));
3187
3188           else if (GET_CODE (reg1) == MULT)
3189             {
3190               rtx mreg = XEXP (reg1, 0);
3191               if (REGNO (mreg) == ARG_POINTER_REGNUM)
3192                 abort ();
3193
3194               fprintf (file, "%s[%s]", reg_names[REGNO (reg0)],
3195                        reg_names[REGNO (mreg)]);
3196             }
3197
3198           else if (GET_CODE (reg1) == ZERO_EXTRACT)
3199             {
3200               fprintf (file, "%s,%slo16(",
3201                        reg_names[REGNO (reg0)], m88k_pound_sign);
3202               output_addr_const (file, XEXP (reg1, 0));
3203               fputc (')', file);
3204             }
3205
3206           else if (flag_pic)
3207             {
3208               fprintf (file, "%s,", reg_names[REGNO (reg0)]);
3209               output_addr_const (file, reg1);
3210               fputs ("#got_rel", file);
3211             }
3212           else abort ();
3213         }
3214
3215       else
3216         abort ();
3217       break;
3218
3219     case MULT:
3220       if (REGNO (XEXP (addr, 0)) == ARG_POINTER_REGNUM)
3221         abort ();
3222
3223       fprintf (file, "%s[%s]",
3224                reg_names[0], reg_names[REGNO (XEXP (addr, 0))]);
3225       break;
3226
3227     case CONST_INT:
3228       fprintf (file, "%s,%d", reg_names[0], INTVAL (addr));
3229       break;
3230
3231     default:
3232       fprintf (file, "%s,", reg_names[0]);
3233       if (SHORT_ADDRESS_P (addr, temp))
3234         {
3235           fprintf (file, "%siw16(", m88k_pound_sign);
3236           output_addr_const (file, addr);
3237           fputc (')', file);
3238         }
3239       else
3240           output_addr_const (file, addr);
3241     }
3242 }
3243
3244 /* Return true if X is an address which needs a temporary register when 
3245    reloaded while generating PIC code.  */
3246
3247 int
3248 pic_address_needs_scratch (x)
3249      rtx x;
3250 {
3251   /* An address which is a symbolic plus a non SMALL_INT needs a temp reg.  */
3252   if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
3253       && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
3254       && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
3255       && ! ADD_INT (XEXP (XEXP (x, 0), 1)))
3256     return 1;
3257
3258   return 0;
3259 }
3260
3261 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
3262    reference and a constant.  */
3263
3264 int
3265 symbolic_operand (op, mode)
3266      register rtx op;
3267      enum machine_mode mode;
3268 {
3269   switch (GET_CODE (op))
3270     {
3271     case SYMBOL_REF:
3272     case LABEL_REF:
3273       return 1;
3274
3275     case CONST:
3276       op = XEXP (op, 0);
3277       return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
3278                || GET_CODE (XEXP (op, 0)) == LABEL_REF)
3279               && GET_CODE (XEXP (op, 1)) == CONST_INT);
3280
3281       /* ??? This clause seems to be irrelevant.  */
3282     case CONST_DOUBLE:
3283       return GET_MODE (op) == mode;
3284
3285     default:
3286       return 0;
3287     }
3288 }
3289
3290 #if defined (CTOR_LIST_BEGIN) && !defined (OBJECT_FORMAT_ELF)
3291 static void
3292 m88k_svr3_asm_out_constructor (symbol, priority)
3293      rtx symbol;
3294      int priority ATTRIBUTE_UNUSED;
3295 {
3296   const char *name = XSTR (symbol, 0);
3297
3298   init_section ();
3299   fprintf (asm_out_file, "\tor.u\t r13,r0,hi16(");
3300   assemble_name (asm_out_file, name);
3301   fprintf (asm_out_file, ")\n\tor\t r13,r13,lo16(");
3302   assemble_name (asm_out_file, name);
3303   fprintf (asm_out_file, ")\n\tsubu\t r31,r31,%d\n\tst\t r13,r31,%d\n",
3304            STACK_BOUNDARY / BITS_PER_UNIT, REG_PARM_STACK_SPACE (0));
3305 }
3306
3307 static void
3308 m88k_svr3_asm_out_destructor (symbol, priority)
3309      rtx symbol;
3310      int priority ATTRIBUTE_UNUSED;
3311 {
3312   int i;
3313
3314   fini_section ();
3315   assemble_integer (symbol, UNITS_PER_WORD, BITS_PER_WORD, 1);
3316   for (i = 1; i < 4; i++)
3317     assemble_integer (constm1_rtx, UNITS_PER_WORD, BITS_PER_WORD, 1);
3318 }
3319 #endif /* INIT_SECTION_ASM_OP && ! OBJECT_FORMAT_ELF */
3320
3321 /* Adjust the cost of INSN based on the relationship between INSN that
3322    is dependent on DEP_INSN through the dependence LINK.  The default
3323    is to make no adjustment to COST.
3324
3325    On the m88k, ignore the cost of anti- and output-dependencies.  On
3326    the m88100, a store can issue two cycles before the value (not the
3327    address) has finished computing.  */
3328
3329 static int
3330 m88k_adjust_cost (insn, link, dep, cost)
3331      rtx insn;
3332      rtx link;
3333      rtx dep;
3334      int cost;
3335 {
3336   if (REG_NOTE_KIND (link) != 0)
3337     return 0;  /* Anti or output dependence.  */
3338
3339   if (! TARGET_88100
3340       && recog_memoized (insn) >= 0
3341       && get_attr_type (insn) == TYPE_STORE
3342       && SET_SRC (PATTERN (insn)) == SET_DEST (PATTERN (dep)))
3343     return cost - 4;  /* 88110 store reservation station.  */
3344
3345   return cost;
3346 }