OSDN Git Service

* hooks.c (hook_tree_bool_false): New.
[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, 2002 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 static void m88k_select_section PARAMS ((tree, int, unsigned HOST_WIDE_INT));
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   REAL_VALUE_TYPE d;
1127   union {
1128     long l[2];
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   REAL_VALUE_FROM_CONST_DOUBLE (d, op);
1151   REAL_VALUE_TO_TARGET_DOUBLE (d, u.l);
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   REAL_VALUE_TYPE r;
1173   union {
1174     long l[2];
1175     struct {                            /* IEEE double precision format */
1176       unsigned sign      :  1;
1177       unsigned exponent  : 11;
1178       unsigned mantissa1 : 20;
1179       unsigned mantissa2;
1180     } d;
1181     struct {                            /* IEEE double format to quick check */
1182       unsigned sign      :  1;          /* if it fits in a float */
1183       unsigned exponent1 :  4;
1184       unsigned exponent2 :  7;
1185       unsigned mantissa1 : 20;
1186       unsigned mantissa2;
1187     } s;
1188   } u;
1189
1190   if (GET_CODE (op) == REG || mode != DFmode)
1191     return op;
1192
1193   if (GET_CODE (op) == CONST_DOUBLE)
1194     {
1195       REAL_VALUE_FROM_CONST_DOUBLE (r, op);
1196       REAL_VALUE_TO_TARGET_DOUBLE (r, u.l);
1197       if (u.d.exponent != 0x7ff /* NaN */
1198           && u.d.mantissa2 == 0 /* Mantissa fits */
1199           && (u.s.exponent1 == 0x8 || u.s.exponent1 == 0x7) /* Exponent fits */
1200           && (temp = simplify_unary_operation (FLOAT_TRUNCATE, SFmode,
1201                                                op, mode)) != 0)
1202         return gen_rtx_FLOAT_EXTEND (mode, force_reg (SFmode, temp));
1203     }
1204   else if (register_operand (op, mode))
1205     return op;
1206
1207   return force_reg (mode, op);
1208 }
1209 \f
1210 /* Return true if OP is a suitable input for a move insn.  */
1211
1212 int
1213 move_operand (op, mode)
1214      rtx op;
1215      enum machine_mode mode;
1216 {
1217   if (register_operand (op, mode))
1218     return 1;
1219   if (GET_CODE (op) == CONST_INT)
1220     return (classify_integer (mode, INTVAL (op)) < m88k_oru_hi16);
1221   if (GET_MODE (op) != mode)
1222     return 0;
1223   if (GET_CODE (op) == SUBREG)
1224     op = SUBREG_REG (op);
1225   if (GET_CODE (op) != MEM)
1226     return 0;
1227
1228   op = XEXP (op, 0);
1229   if (GET_CODE (op) == LO_SUM)
1230     return (REG_P (XEXP (op, 0))
1231             && symbolic_address_p (XEXP (op, 1)));
1232   return memory_address_p (mode, op);
1233 }
1234
1235 /* Return true if OP is suitable for a call insn.  */
1236
1237 int
1238 call_address_operand (op, mode)
1239      rtx op;
1240      enum machine_mode mode ATTRIBUTE_UNUSED;
1241 {
1242   return (REG_P (op) || symbolic_address_p (op));
1243 }
1244
1245 /* Returns true if OP is either a symbol reference or a sum of a symbol
1246    reference and a constant.  */
1247
1248 int
1249 symbolic_address_p (op)
1250      register rtx op;
1251 {
1252   switch (GET_CODE (op))
1253     {
1254     case SYMBOL_REF:
1255     case LABEL_REF:
1256       return 1;
1257
1258     case CONST:
1259       op = XEXP (op, 0);
1260       return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1261                || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1262               && GET_CODE (XEXP (op, 1)) == CONST_INT);
1263
1264     default:
1265       return 0;
1266     }
1267 }
1268
1269 /* Return true if OP is a register or const0_rtx.  */
1270
1271 int
1272 reg_or_0_operand (op, mode)
1273      rtx op;
1274      enum machine_mode mode;
1275 {
1276   return (op == const0_rtx || register_operand (op, mode));
1277 }
1278
1279 /* Nonzero if OP is a valid second operand for an arithmetic insn.  */
1280
1281 int
1282 arith_operand (op, mode)
1283      rtx op;
1284      enum machine_mode mode;
1285 {
1286   return (register_operand (op, mode)
1287           || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));
1288 }
1289
1290 /* Return true if OP is a  register or 5 bit integer.  */
1291
1292 int
1293 arith5_operand (op, mode)
1294      rtx op;
1295      enum machine_mode mode;
1296 {
1297   return (register_operand (op, mode)
1298           || (GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 32));
1299 }
1300
1301 int
1302 arith32_operand (op, mode)
1303      rtx op;
1304      enum machine_mode mode;
1305 {
1306   return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
1307 }
1308
1309 int
1310 arith64_operand (op, mode)
1311      rtx op;
1312      enum machine_mode mode;
1313 {
1314   return (register_operand (op, mode)
1315           || GET_CODE (op) == CONST_INT
1316           || (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode));
1317 }
1318
1319 int
1320 int5_operand (op, mode)
1321      rtx op;
1322      enum machine_mode mode ATTRIBUTE_UNUSED;
1323 {
1324   return (GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 32);
1325 }
1326
1327 int
1328 int32_operand (op, mode)
1329      rtx op;
1330      enum machine_mode mode ATTRIBUTE_UNUSED;
1331 {
1332   return (GET_CODE (op) == CONST_INT);
1333 }
1334
1335 /* Return true if OP is a register or a valid immediate operand for
1336    addu or subu.  */
1337
1338 int
1339 add_operand (op, mode)
1340      rtx op;
1341      enum machine_mode mode;
1342 {
1343   return (register_operand (op, mode)
1344           || (GET_CODE (op) == CONST_INT && ADD_INT (op)));
1345 }
1346
1347 /* Nonzero if this is a bitmask filling the bottom bits, for optimizing and +
1348    shift left combinations into a single mak instruction.  */
1349
1350 int
1351 mak_mask_p (value)
1352      int value;
1353 {
1354   return (value && POWER_OF_2_or_0 (value + 1));
1355 }
1356
1357 int
1358 reg_or_bbx_mask_operand (op, mode)
1359      rtx op;
1360      enum machine_mode mode;
1361 {
1362   int value;
1363   if (register_operand (op, mode))
1364     return 1;
1365   if (GET_CODE (op) != CONST_INT)
1366     return 0;
1367
1368   value = INTVAL (op);
1369   if (POWER_OF_2 (value))
1370     return 1;
1371
1372   return 0;
1373 }
1374
1375 /* Return true if OP is valid to use in the context of a floating
1376    point operation.  Special case 0.0, since we can use r0.  */
1377
1378 int
1379 real_or_0_operand (op, mode)
1380      rtx op;
1381      enum machine_mode mode;
1382 {
1383   if (mode != SFmode && mode != DFmode)
1384     return 0;
1385
1386   return (register_operand (op, mode)
1387           || (GET_CODE (op) == CONST_DOUBLE
1388               && op == CONST0_RTX (mode)));
1389 }
1390
1391 /* Return true if OP is valid to use in the context of logic arithmetic
1392    on condition codes. */
1393
1394 int
1395 partial_ccmode_register_operand (op, mode)
1396      rtx op;
1397      enum machine_mode mode ATTRIBUTE_UNUSED;
1398 {
1399   return register_operand (op, CCmode) || register_operand (op, CCEVENmode);
1400 }
1401
1402 /* Return true if OP is a relational operator.  */
1403
1404 int
1405 relop (op, mode)
1406      rtx op;
1407      enum machine_mode mode ATTRIBUTE_UNUSED;
1408 {
1409   switch (GET_CODE (op))
1410     {
1411     case EQ:
1412     case NE:
1413     case LT:
1414     case LE:
1415     case GE:
1416     case GT:
1417     case LTU:
1418     case LEU:
1419     case GEU:
1420     case GTU:
1421       return 1;
1422     default:
1423       return 0;
1424     }
1425 }
1426
1427 int
1428 even_relop (op, mode)
1429      rtx op;
1430      enum machine_mode mode ATTRIBUTE_UNUSED;
1431 {
1432   switch (GET_CODE (op))
1433     {
1434     case EQ:
1435     case LT:
1436     case GT:
1437     case LTU:
1438     case GTU:
1439       return 1;
1440     default:
1441       return 0;
1442     }
1443 }
1444
1445 int
1446 odd_relop (op, mode)
1447      rtx op;
1448      enum machine_mode mode ATTRIBUTE_UNUSED;
1449 {
1450   switch (GET_CODE (op))
1451     {
1452     case NE:
1453     case LE:
1454     case GE:
1455     case LEU:
1456     case GEU:
1457       return 1;
1458     default:
1459       return 0;
1460     }
1461 }
1462
1463 /* Return true if OP is a relational operator, and is not an unsigned
1464    relational operator.  */
1465
1466 int
1467 relop_no_unsigned (op, mode)
1468      rtx op;
1469      enum machine_mode mode ATTRIBUTE_UNUSED;
1470 {
1471   switch (GET_CODE (op))
1472     {
1473     case EQ:
1474     case NE:
1475     case LT:
1476     case LE:
1477     case GE:
1478     case GT:
1479       /* @@ What is this test doing?  Why not use `mode'?  */
1480       if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT
1481           || GET_MODE (op) == DImode
1482           || GET_MODE_CLASS (GET_MODE (XEXP (op, 0))) == MODE_FLOAT
1483           || GET_MODE (XEXP (op, 0)) == DImode
1484           || GET_MODE_CLASS (GET_MODE (XEXP (op, 1))) == MODE_FLOAT
1485           || GET_MODE (XEXP (op, 1)) == DImode)
1486         return 0;
1487       return 1;
1488     default:
1489       return 0;
1490     }
1491 }
1492
1493 /* Return true if the code of this rtx pattern is EQ or NE.  */
1494
1495 int
1496 equality_op (op, mode)
1497      rtx op;
1498      enum machine_mode mode ATTRIBUTE_UNUSED;
1499 {
1500   return (GET_CODE (op) == EQ || GET_CODE (op) == NE);
1501 }
1502
1503 /* Return true if the code of this rtx pattern is pc or label_ref.  */
1504
1505 int
1506 pc_or_label_ref (op, mode)
1507      rtx op;
1508      enum machine_mode mode ATTRIBUTE_UNUSED;
1509 {
1510   return (GET_CODE (op) == PC || GET_CODE (op) == LABEL_REF);
1511 }
1512 \f
1513 /* Output to FILE the start of the assembler file.  */
1514
1515 /* This definition must match lang_independent_options from toplev.c.  */
1516 struct m88k_lang_independent_options
1517 {
1518   const char *const string;
1519   int *const variable;
1520   const int on_value;
1521   const char *const description;
1522 };
1523
1524 static void output_options PARAMS ((FILE *,
1525                                     const struct m88k_lang_independent_options *,
1526                                     int,
1527                                     const struct m88k_lang_independent_options *,
1528                                     int, int, int, const char *, const char *,
1529                                     const char *));
1530
1531 static int
1532 output_option (file, sep, type, name, indent, pos, max)
1533      FILE *file;
1534      const char *sep;
1535      const char *type;
1536      const char *name;
1537      const char *indent;
1538      int pos;
1539      int max;
1540 {
1541   if ((long)(strlen (sep) + strlen (type) + strlen (name) + pos) > max)
1542     {
1543       fprintf (file, indent);
1544       return fprintf (file, "%s%s", type, name);
1545     }
1546   return pos + fprintf (file, "%s%s%s", sep, type, name);
1547 }
1548
1549 static const struct { const char *const name; const int value; } m_options[] =
1550 TARGET_SWITCHES;
1551
1552 static void
1553 output_options (file, f_options, f_len, W_options, W_len,
1554                 pos, max, sep, indent, term)
1555      FILE *file;
1556      const struct m88k_lang_independent_options *f_options;
1557      const struct m88k_lang_independent_options *W_options;
1558      int f_len, W_len;
1559      int pos;
1560      int max;
1561      const char *sep;
1562      const char *indent;
1563      const char *term;
1564 {
1565   register int j;
1566
1567   if (optimize)
1568     pos = output_option (file, sep, "-O", "", indent, pos, max);
1569   if (write_symbols != NO_DEBUG)
1570     pos = output_option (file, sep, "-g", "", indent, pos, max);
1571   if (profile_flag)
1572     pos = output_option (file, sep, "-p", "", indent, pos, max);
1573   for (j = 0; j < f_len; j++)
1574     if (*f_options[j].variable == f_options[j].on_value)
1575       pos = output_option (file, sep, "-f", f_options[j].string,
1576                            indent, pos, max);
1577
1578   for (j = 0; j < W_len; j++)
1579     if (*W_options[j].variable == W_options[j].on_value)
1580       pos = output_option (file, sep, "-W", W_options[j].string,
1581                            indent, pos, max);
1582
1583   for (j = 0; j < (long) ARRAY_SIZE (m_options); j++)
1584     if (m_options[j].name[0] != '\0'
1585         && m_options[j].value > 0
1586         && ((m_options[j].value & target_flags)
1587             == m_options[j].value))
1588       pos = output_option (file, sep, "-m", m_options[j].name,
1589                            indent, pos, max);
1590
1591   if (m88k_short_data)
1592     pos = output_option (file, sep, "-mshort-data-", m88k_short_data,
1593                          indent, pos, max);
1594
1595   fprintf (file, term);
1596 }
1597
1598 void
1599 output_file_start (file, f_options, f_len, W_options, W_len)
1600      FILE *file;
1601      const struct m88k_lang_independent_options *f_options;
1602      const struct m88k_lang_independent_options *W_options;
1603      int f_len, W_len;
1604 {
1605   register int pos;
1606
1607   ASM_FIRST_LINE (file);
1608   if (TARGET_88110
1609       && TARGET_SVR4)
1610     fprintf (file, "%s\n", REQUIRES_88110_ASM_OP);
1611   output_file_directive (file, main_input_filename);
1612   /* Switch to the data section so that the coffsem symbol
1613      isn't in the text section.  */
1614   ASM_COFFSEM (file);
1615
1616   if (TARGET_IDENTIFY_REVISION)
1617     {
1618       char indent[256];
1619
1620       time_t now = time ((time_t *)0);
1621       sprintf (indent, "]\"\n%s\"@(#)%s [", IDENT_ASM_OP, main_input_filename);
1622       fprintf (file, indent+3);
1623       pos = fprintf (file, "gcc %s, %.24s,", version_string, ctime (&now));
1624 #if 1
1625       /* ??? It would be nice to call print_switch_values here (and thereby
1626          let us delete output_options) but this is kept in until it is known
1627          whether the change in content format matters.  */
1628       output_options (file, f_options, f_len, W_options, W_len,
1629                       pos, 150 - strlen (indent), " ", indent, "]\"\n\n");
1630 #else
1631       fprintf (file, "]\"\n");
1632       print_switch_values (file, 0, 150 - strlen (indent),
1633                            indent + 3, " ", "]\"\n");
1634 #endif
1635     }
1636 }
1637 \f
1638 /* Output an ascii string.  */
1639
1640 void
1641 output_ascii (file, opcode, max, p, size)
1642      FILE *file;
1643      const char *opcode;
1644      int max;
1645      const char *p;
1646      int size;
1647 {
1648   int i;
1649   int in_escape = 0;
1650
1651   register int num = 0;
1652
1653   fprintf (file, "%s\"", opcode);
1654   for (i = 0; i < size; i++)
1655     {
1656       register int c = (unsigned char) p[i];
1657
1658       if (num > max)
1659         {
1660           fprintf (file, "\"\n%s\"", opcode);
1661           num = 0;
1662         }
1663           
1664       if (c == '\"' || c == '\\')
1665         {
1666         escape:
1667           putc ('\\', file);
1668           putc (c, file);
1669           num += 2;
1670           in_escape = 0;
1671         }
1672       else if (in_escape && ISDIGIT (c))
1673         {
1674           /* If a digit follows an octal-escape, the VAX assembler fails
1675              to stop reading the escape after three digits.  Continue to
1676              output the values as an octal-escape until a non-digit is
1677              found.  */
1678           fprintf (file, "\\%03o", c);
1679           num += 4;
1680         }
1681       else if ((c >= ' ' && c < 0177) || (c == '\t'))
1682         {
1683           putc (c, file);
1684           num++;
1685           in_escape = 0;
1686         }
1687       else
1688         {
1689           switch (c)
1690             {
1691               /* Some assemblers can't handle \a, \v, or \?.  */
1692             case '\f': c = 'f'; goto escape;
1693             case '\b': c = 'b'; goto escape;
1694             case '\r': c = 'r'; goto escape;
1695             case '\n': c = 'n'; goto escape;
1696             }
1697
1698           fprintf (file, "\\%03o", c);
1699           num += 4;
1700           in_escape = 1;
1701         }
1702     }
1703   fprintf (file, "\"\n");
1704 }
1705 \f
1706 /* Output a label (allows insn-output.c to be compiled without including
1707    m88k.c or needing to include stdio.h).  */
1708
1709 void
1710 output_label (label_number)
1711      int label_number;
1712 {
1713   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", label_number);
1714 }
1715 \f
1716 /* Generate the assembly code for function entry.
1717
1718    The prologue is responsible for setting up the stack frame,
1719    initializing the frame pointer register, saving registers that must be
1720    saved, and allocating SIZE additional bytes of storage for the
1721    local variables.  SIZE is an integer.  FILE is a stdio
1722    stream to which the assembler code should be output.
1723
1724    The label for the beginning of the function need not be output by this
1725    macro.  That has already been done when the macro is run.
1726
1727    To determine which registers to save, the macro can refer to the array
1728    `regs_ever_live': element R is nonzero if hard register
1729    R is used anywhere within the function.  This implies the
1730    function prologue should save register R, but not if it is one
1731    of the call-used registers.
1732
1733    On machines where functions may or may not have frame-pointers, the
1734    function entry code must vary accordingly; it must set up the frame
1735    pointer if one is wanted, and not otherwise.  To determine whether a
1736    frame pointer is in wanted, the macro can refer to the variable
1737    `frame_pointer_needed'.  The variable's value will be 1 at run
1738    time in a function that needs a frame pointer.
1739
1740    On machines where an argument may be passed partly in registers and
1741    partly in memory, this macro must examine the variable
1742    `current_function_pretend_args_size', and allocate that many bytes
1743    of uninitialized space on the stack just underneath the first argument
1744    arriving on the stack.  (This may not be at the very end of the stack,
1745    if the calling sequence has pushed anything else since pushing the stack
1746    arguments.  But usually, on such machines, nothing else has been pushed
1747    yet, because the function prologue itself does all the pushing.)
1748
1749    If `ACCUMULATE_OUTGOING_ARGS' is defined, the variable
1750    `current_function_outgoing_args_size' contains the size in bytes
1751    required for the outgoing arguments.  This macro must add that
1752    amount of uninitialized space to very bottom of the stack.
1753
1754    The stack frame we use looks like this:
1755
1756  caller                                                  callee
1757         |==============================================|
1758         |                caller's frame                |
1759         |==============================================|
1760         |     [caller's outgoing memory arguments]     |
1761         |==============================================|
1762         |  caller's outgoing argument area (32 bytes)  |
1763   sp -> |==============================================| <- ap
1764         |            [local variable space]            |
1765         |----------------------------------------------|
1766         |            [return address (r1)]             |
1767         |----------------------------------------------|
1768         |        [previous frame pointer (r30)]        |
1769         |==============================================| <- fp
1770         |       [preserved registers (r25..r14)]       |
1771         |----------------------------------------------|
1772         |       [preserved registers (x29..x22)]       |
1773         |==============================================|
1774         |    [dynamically allocated space (alloca)]    |
1775         |==============================================|
1776         |     [callee's outgoing memory arguments]     |
1777         |==============================================|
1778         | [callee's outgoing argument area (32 bytes)] |
1779         |==============================================| <- sp
1780
1781   Notes:
1782
1783   r1 and r30 must be saved if debugging.
1784
1785   fp (if present) is located two words down from the local
1786   variable space.
1787   */
1788
1789 static void emit_add PARAMS ((rtx, rtx, int));
1790 static void preserve_registers PARAMS ((int, int));
1791 static void emit_ldst PARAMS ((int, int, enum machine_mode, int));
1792 static void output_tdesc PARAMS ((FILE *, int));
1793 static int uses_arg_area_p PARAMS ((void));
1794
1795 static int  nregs;
1796 static int  nxregs;
1797 static char save_regs[FIRST_PSEUDO_REGISTER];
1798 static int  frame_laid_out;
1799 static int  frame_size;
1800 static int  variable_args_p;
1801 static int  epilogue_marked;
1802 static int  prologue_marked;
1803
1804 #define FIRST_OCS_PRESERVE_REGISTER     14
1805 #define LAST_OCS_PRESERVE_REGISTER      30
1806
1807 #define FIRST_OCS_EXTENDED_PRESERVE_REGISTER    (32 + 22)
1808 #define LAST_OCS_EXTENDED_PRESERVE_REGISTER     (32 + 31)
1809
1810 #define STACK_UNIT_BOUNDARY (STACK_BOUNDARY / BITS_PER_UNIT)
1811 #define ROUND_CALL_BLOCK_SIZE(BYTES) \
1812   (((BYTES) + (STACK_UNIT_BOUNDARY - 1)) & ~(STACK_UNIT_BOUNDARY - 1))
1813 \f
1814 /* Establish the position of the FP relative to the SP.  This is done
1815    either during output_function_prologue() or by
1816    INITIAL_ELIMINATION_OFFSET.  */
1817
1818 void
1819 m88k_layout_frame ()
1820 {
1821   int regno, sp_size;
1822
1823   frame_laid_out++;
1824
1825   memset ((char *) &save_regs[0], 0, sizeof (save_regs));
1826   sp_size = nregs = nxregs = 0;
1827   frame_size = get_frame_size ();
1828
1829   /* Since profiling requires a call, make sure r1 is saved.  */
1830   if (current_function_profile)
1831     save_regs[1] = 1;
1832
1833   /* If we are producing debug information, store r1 and r30 where the
1834      debugger wants to find them (r30 at r30+0, r1 at r30+4).  Space has
1835      already been reserved for r1/r30 in STARTING_FRAME_OFFSET.  */
1836   if (write_symbols != NO_DEBUG && !TARGET_OCS_FRAME_POSITION)
1837     save_regs[1] = 1;
1838
1839   /* If there is a call, alloca is used, __builtin_alloca is used, or
1840      a dynamic-sized object is defined, add the 8 additional words
1841      for the callee's argument area.  The common denominator is that the
1842      FP is required.  may_call_alloca only gets calls to alloca;
1843      current_function_calls_alloca gets alloca and __builtin_alloca.  */
1844   if (regs_ever_live[1] || frame_pointer_needed)
1845     {
1846       save_regs[1] = 1;
1847       sp_size += REG_PARM_STACK_SPACE (0);
1848     }
1849
1850   /* If we are producing PIC, save the addressing base register and r1.  */
1851   if (flag_pic && current_function_uses_pic_offset_table)
1852     {
1853       save_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
1854       nregs++;
1855     }
1856
1857   /* If a frame is requested, save the previous FP, and the return
1858      address (r1), so that a traceback can be done without using tdesc
1859      information.  Otherwise, simply save the FP if it is used as
1860      a preserve register.  */
1861   if (frame_pointer_needed)
1862     save_regs[FRAME_POINTER_REGNUM] = save_regs[1] = 1;
1863   else if (regs_ever_live[FRAME_POINTER_REGNUM])
1864     save_regs[FRAME_POINTER_REGNUM] = 1;
1865
1866   /* Figure out which extended register(s) needs to be saved.  */
1867   for (regno = FIRST_EXTENDED_REGISTER + 1; regno < FIRST_PSEUDO_REGISTER;
1868        regno++)
1869     if (regs_ever_live[regno] && ! call_used_regs[regno])
1870       {
1871         save_regs[regno] = 1;
1872         nxregs++;
1873       }
1874
1875   /* Figure out which normal register(s) needs to be saved.  */
1876   for (regno = 2; regno < FRAME_POINTER_REGNUM; regno++)
1877     if (regs_ever_live[regno] && ! call_used_regs[regno])
1878       {
1879         save_regs[regno] = 1;
1880         nregs++;
1881       }
1882
1883   /* Achieve greatest use of double memory ops.  Either we end up saving
1884      r30 or we use that slot to align the registers we do save.  */
1885   if (nregs >= 2 && save_regs[1] && !save_regs[FRAME_POINTER_REGNUM])
1886     sp_size += 4;
1887
1888   nregs += save_regs[1] + save_regs[FRAME_POINTER_REGNUM];
1889   /* if we need to align extended registers, add a word */
1890   if (nxregs > 0 && (nregs & 1) != 0)
1891     sp_size +=4;
1892   sp_size += 4 * nregs;
1893   sp_size += 8 * nxregs;
1894   sp_size += current_function_outgoing_args_size;
1895
1896   /* The first two saved registers are placed above the new frame pointer
1897      if any.  In the only case this matters, they are r1 and r30. */
1898   if (frame_pointer_needed || sp_size)
1899     m88k_fp_offset = ROUND_CALL_BLOCK_SIZE (sp_size - STARTING_FRAME_OFFSET);
1900   else
1901     m88k_fp_offset = -STARTING_FRAME_OFFSET;
1902   m88k_stack_size = m88k_fp_offset + STARTING_FRAME_OFFSET;
1903
1904   /* First, combine m88k_stack_size and size.  If m88k_stack_size is
1905      non-zero, align the frame size to 8 mod 16; otherwise align the
1906      frame size to 0 mod 16.  (If stacks are 8 byte aligned, this ends
1907      up as a NOP.  */
1908   {
1909     int need
1910       = ((m88k_stack_size ? STACK_UNIT_BOUNDARY - STARTING_FRAME_OFFSET : 0)
1911          - (frame_size % STACK_UNIT_BOUNDARY));
1912     if (need < 0)
1913       need += STACK_UNIT_BOUNDARY;
1914     m88k_stack_size
1915       = ROUND_CALL_BLOCK_SIZE (m88k_stack_size + frame_size + need
1916                                + current_function_pretend_args_size);
1917   }
1918 }
1919
1920 /* Return true if this function is known to have a null prologue.  */
1921
1922 int
1923 null_prologue ()
1924 {
1925   if (! reload_completed)
1926     return 0;
1927   if (! frame_laid_out)
1928     m88k_layout_frame ();
1929   return (! frame_pointer_needed
1930           && nregs == 0
1931           && nxregs == 0
1932           && m88k_stack_size == 0);
1933 }
1934
1935 /* Determine if the current function has any references to the arg pointer.
1936    This is done indirectly by examining the DECL_ARGUMENTS' DECL_RTL.
1937    It is OK to return TRUE if there are no references, but FALSE must be
1938    correct.  */
1939
1940 static int
1941 uses_arg_area_p ()
1942 {
1943   register tree parm;
1944
1945   if (current_function_decl == 0
1946       || current_function_varargs
1947       || variable_args_p)
1948     return 1;
1949
1950   for (parm = DECL_ARGUMENTS (current_function_decl);
1951        parm;
1952        parm = TREE_CHAIN (parm))
1953     {
1954       if (DECL_RTL (parm) == 0
1955           || GET_CODE (DECL_RTL (parm)) == MEM)
1956         return 1;
1957
1958       if (DECL_INCOMING_RTL (parm) == 0
1959           || GET_CODE (DECL_INCOMING_RTL (parm)) == MEM)
1960         return 1;
1961     }
1962   return 0;
1963 }
1964 \f
1965 static void
1966 m88k_output_function_prologue (stream, size)
1967      FILE *stream ATTRIBUTE_UNUSED;
1968      HOST_WIDE_INT size ATTRIBUTE_UNUSED;
1969 {
1970   if (TARGET_OMIT_LEAF_FRAME_POINTER && ! quiet_flag && leaf_function_p ())
1971     fprintf (stderr, "$");
1972
1973   m88k_prologue_done = 1;       /* it's ok now to put out ln directives */
1974 }
1975
1976 static void
1977 m88k_output_function_end_prologue (stream)
1978      FILE *stream;
1979 {
1980   if (TARGET_OCS_DEBUG_INFO && !prologue_marked)
1981     {
1982       PUT_OCS_FUNCTION_START (stream);
1983       prologue_marked = 1;
1984
1985       /* If we've already passed the start of the epilogue, say that
1986          it starts here.  This marks the function as having a null body,
1987          but at a point where the return address is in a known location.
1988
1989          Originally, I thought this couldn't happen, but the pic prologue
1990          for leaf functions ends with the instruction that restores the
1991          return address from the temporary register.  If the temporary
1992          register is never used, that instruction can float all the way
1993          to the end of the function.  */
1994       if (epilogue_marked)
1995         PUT_OCS_FUNCTION_END (stream);
1996     }
1997 }
1998
1999 void
2000 m88k_expand_prologue ()
2001 {
2002   m88k_layout_frame ();
2003
2004   if (TARGET_OPTIMIZE_ARG_AREA
2005       && m88k_stack_size
2006       && ! uses_arg_area_p ())
2007     {
2008       /* The incoming argument area is used for stack space if it is not
2009          used (or if -mno-optimize-arg-area is given).  */
2010       if ((m88k_stack_size -= REG_PARM_STACK_SPACE (0)) < 0)
2011         m88k_stack_size = 0;
2012     }
2013
2014   if (m88k_stack_size)
2015     emit_add (stack_pointer_rtx, stack_pointer_rtx, -m88k_stack_size);
2016
2017   if (nregs || nxregs)
2018     preserve_registers (m88k_fp_offset + 4, 1);
2019
2020   if (frame_pointer_needed)
2021     emit_add (frame_pointer_rtx, stack_pointer_rtx, m88k_fp_offset);
2022
2023   if (flag_pic && save_regs[PIC_OFFSET_TABLE_REGNUM])
2024     {
2025       rtx return_reg = gen_rtx_REG (SImode, 1);
2026       rtx label = gen_label_rtx ();
2027       rtx temp_reg = NULL_RTX;
2028
2029       if (! save_regs[1])
2030         {
2031           temp_reg = gen_rtx_REG (SImode, TEMP_REGNUM);
2032           emit_move_insn (temp_reg, return_reg);
2033         }
2034       emit_insn (gen_locate1 (pic_offset_table_rtx, label));
2035       emit_insn (gen_locate2 (pic_offset_table_rtx, label));
2036       emit_insn (gen_addsi3 (pic_offset_table_rtx,
2037                              pic_offset_table_rtx, return_reg));
2038       if (! save_regs[1])
2039         emit_move_insn (return_reg, temp_reg);
2040     }
2041   if (current_function_profile)
2042     emit_insn (gen_blockage ());
2043 }
2044 \f
2045 /* This function generates the assembly code for function exit,
2046    on machines that need it.
2047
2048    The function epilogue should not depend on the current stack pointer!
2049    It should use the frame pointer only, if there is a frame pointer.
2050    This is mandatory because of alloca; we also take advantage of it to
2051    omit stack adjustments before returning.  */
2052
2053 static void
2054 m88k_output_function_begin_epilogue (stream)
2055      FILE *stream;
2056 {
2057   if (TARGET_OCS_DEBUG_INFO && !epilogue_marked && prologue_marked)
2058     {
2059       PUT_OCS_FUNCTION_END (stream);
2060     }
2061   epilogue_marked = 1;
2062 }
2063
2064 static void
2065 m88k_output_function_epilogue (stream, size)
2066      FILE *stream;
2067      HOST_WIDE_INT size ATTRIBUTE_UNUSED;
2068 {
2069   rtx insn = get_last_insn ();
2070
2071   if (TARGET_OCS_DEBUG_INFO && !epilogue_marked)
2072     PUT_OCS_FUNCTION_END (stream);
2073
2074   /* If the last insn isn't a BARRIER, we must write a return insn.  This
2075      should only happen if the function has no prologue and no body.  */
2076   if (GET_CODE (insn) == NOTE)
2077     insn = prev_nonnote_insn (insn);
2078   if (insn == 0 || GET_CODE (insn) != BARRIER)
2079     fprintf (stream, "\tjmp\t %s\n", reg_names[1]);
2080
2081   /* If the last insn is a barrier, and the insn before that is a call,
2082      then add a nop instruction so that tdesc can walk the stack correctly
2083      even though there is no epilogue. (Otherwise, the label for the
2084      end of the tdesc region ends up at the start of the next function. */
2085   if (insn && GET_CODE (insn) == BARRIER)
2086     {
2087       insn = prev_nonnote_insn (insn);
2088       if (insn && GET_CODE (insn) == CALL_INSN)
2089         fprintf (stream, "\tor\t %s,%s,%s\n",reg_names[0],reg_names[0],reg_names[0]);
2090     }
2091
2092   output_short_branch_defs (stream);
2093
2094   fprintf (stream, "\n");
2095
2096   if (TARGET_OCS_DEBUG_INFO)
2097     output_tdesc (stream, m88k_fp_offset + 4);
2098
2099   m88k_function_number++;
2100   m88k_prologue_done    = 0;            /* don't put out ln directives */
2101   variable_args_p       = 0;            /* has variable args */
2102   frame_laid_out        = 0;
2103   epilogue_marked       = 0;
2104   prologue_marked       = 0;
2105 }
2106
2107 void
2108 m88k_expand_epilogue ()
2109 {
2110 #if (MONITOR_GCC & 0x4) /* What are interesting prologue/epilogue values?  */
2111   fprintf (stream, "; size = %d, m88k_fp_offset = %d, m88k_stack_size = %d\n",
2112            size, m88k_fp_offset, m88k_stack_size);
2113 #endif
2114
2115   if (frame_pointer_needed)
2116     emit_add (stack_pointer_rtx, frame_pointer_rtx, -m88k_fp_offset);
2117
2118   if (nregs || nxregs)
2119     preserve_registers (m88k_fp_offset + 4, 0);
2120
2121   if (m88k_stack_size)
2122     emit_add (stack_pointer_rtx, stack_pointer_rtx, m88k_stack_size);
2123 }
2124 \f
2125 /* Emit insns to set DSTREG to SRCREG + AMOUNT during the prologue or
2126    epilogue.  */
2127
2128 static void
2129 emit_add (dstreg, srcreg, amount)
2130      rtx dstreg;
2131      rtx srcreg;
2132      int amount;
2133 {
2134   rtx incr = GEN_INT (abs (amount));
2135
2136   if (! ADD_INTVAL (amount))
2137     {
2138       rtx temp = gen_rtx_REG (SImode, TEMP_REGNUM);
2139       emit_move_insn (temp, incr);
2140       incr = temp;
2141     }
2142   emit_insn ((amount < 0 ? gen_subsi3 : gen_addsi3) (dstreg, srcreg, incr));
2143 }
2144
2145 /* Save/restore the preserve registers.  base is the highest offset from
2146    r31 at which a register is stored.  store_p is true if stores are to
2147    be done; otherwise loads.  */
2148
2149 static void
2150 preserve_registers (base, store_p)
2151      int base;
2152      int store_p;
2153 {
2154   int regno, offset;
2155   struct mem_op {
2156     int regno;
2157     int nregs;
2158     int offset;
2159   } mem_op[FIRST_PSEUDO_REGISTER];
2160   struct mem_op *mo_ptr = mem_op;
2161
2162   /* The 88open OCS mandates that preserved registers be stored in
2163      increasing order.  For compatibility with current practice,
2164      the order is r1, r30, then the preserve registers.  */
2165
2166   offset = base;
2167   if (save_regs[1])
2168     {
2169       /* An extra word is given in this case to make best use of double
2170          memory ops.  */
2171       if (nregs > 2 && !save_regs[FRAME_POINTER_REGNUM])
2172         offset -= 4;
2173       emit_ldst (store_p, 1, SImode, offset);
2174       offset -= 4;
2175       base = offset;
2176     }
2177
2178   /* Walk the registers to save recording all single memory operations.  */
2179   for (regno = FRAME_POINTER_REGNUM; regno > 1; regno--)
2180     if (save_regs[regno])
2181       {
2182         if ((offset & 7) != 4 || (regno & 1) != 1 || !save_regs[regno-1])
2183           {
2184             mo_ptr->nregs = 1;
2185             mo_ptr->regno = regno;
2186             mo_ptr->offset = offset;
2187             mo_ptr++;
2188             offset -= 4;
2189           }
2190         else
2191           {
2192             regno--;
2193             offset -= 2*4;
2194           }
2195       }
2196
2197   /* Walk the registers to save recording all double memory operations.
2198      This avoids a delay in the epilogue (ld.d/ld).  */
2199   offset = base;
2200   for (regno = FRAME_POINTER_REGNUM; regno > 1; regno--)
2201     if (save_regs[regno])
2202       {
2203         if ((offset & 7) != 4 || (regno & 1) != 1 || !save_regs[regno-1])
2204           {
2205             offset -= 4;
2206           }
2207         else
2208           {
2209             mo_ptr->nregs = 2;
2210             mo_ptr->regno = regno-1;
2211             mo_ptr->offset = offset-4;
2212             mo_ptr++;
2213             regno--;
2214             offset -= 2*4;
2215           }
2216       }
2217
2218   /* Walk the extended registers to record all memory operations.  */
2219   /*  Be sure the offset is double word aligned.  */
2220   offset = (offset - 1) & ~7;
2221   for (regno = FIRST_PSEUDO_REGISTER - 1; regno > FIRST_EXTENDED_REGISTER;
2222        regno--)
2223     if (save_regs[regno])
2224       {
2225         mo_ptr->nregs = 2;
2226         mo_ptr->regno = regno;
2227         mo_ptr->offset = offset;
2228         mo_ptr++;
2229         offset -= 2*4;
2230       }
2231
2232   mo_ptr->regno = 0;
2233
2234   /* Output the memory operations.  */
2235   for (mo_ptr = mem_op; mo_ptr->regno; mo_ptr++)
2236     {
2237       if (mo_ptr->nregs)
2238         emit_ldst (store_p, mo_ptr->regno,
2239                    (mo_ptr->nregs > 1 ? DImode : SImode),
2240                    mo_ptr->offset);
2241     }
2242 }
2243
2244 static void
2245 emit_ldst (store_p, regno, mode, offset)
2246      int store_p;
2247      int regno;
2248      enum machine_mode mode;
2249      int offset;
2250 {
2251   rtx reg = gen_rtx_REG (mode, regno);
2252   rtx mem;
2253
2254   if (SMALL_INTVAL (offset))
2255     {
2256       mem = gen_rtx_MEM (mode, plus_constant (stack_pointer_rtx, offset));
2257     }
2258   else
2259     {
2260       /* offset is too large for immediate index must use register */
2261
2262       rtx disp = GEN_INT (offset);
2263       rtx temp = gen_rtx_REG (SImode, TEMP_REGNUM);
2264       rtx regi = gen_rtx_PLUS (SImode, stack_pointer_rtx, temp);
2265
2266       emit_move_insn (temp, disp);
2267       mem = gen_rtx_MEM (mode, regi);
2268     }
2269
2270   if (store_p)
2271     emit_move_insn (mem, reg);
2272   else
2273     emit_move_insn (reg, mem);
2274 }
2275
2276 /* Convert the address expression REG to a CFA offset.  */
2277
2278 int
2279 m88k_debugger_offset (reg, offset)
2280      register rtx reg;
2281      register int offset;
2282 {
2283   if (GET_CODE (reg) == PLUS)
2284     {
2285       offset = INTVAL (XEXP (reg, 1));
2286       reg = XEXP (reg, 0);
2287     }
2288
2289   /* Put the offset in terms of the CFA (arg pointer).  */
2290   if (reg == frame_pointer_rtx)
2291     offset += m88k_fp_offset - m88k_stack_size;
2292   else if (reg == stack_pointer_rtx)
2293     offset -= m88k_stack_size;
2294   else if (reg != arg_pointer_rtx)
2295     {
2296 #if (MONITOR_GCC & 0x10) /* Watch for suspicious symbolic locations.  */
2297       if (! (GET_CODE (reg) == REG
2298              && REGNO (reg) >= FIRST_PSEUDO_REGISTER))
2299         warning ("internal gcc error: Can't express symbolic location");
2300 #endif
2301       return 0;
2302     }
2303
2304   return offset;
2305 }
2306
2307 /* Output the 88open OCS proscribed text description information.
2308    The information is:
2309         0  8: zero
2310         0 22: info-byte-length (16 or 20 bytes)
2311         0  2: info-alignment (word 2)
2312         1 32: info-protocol (version 1 or 2(pic))
2313         2 32: starting-address (inclusive, not counting prologue)
2314         3 32: ending-address (exclusive, not counting epilog)
2315         4  8: info-variant (version 1 or 3(extended registers))
2316         4 17: register-save-mask (from register 14 to 30)
2317         4  1: zero
2318         4  1: return-address-info-discriminant
2319         4  5: frame-address-register
2320         5 32: frame-address-offset
2321         6 32: return-address-info
2322         7 32: register-save-offset
2323         8 16: extended-register-save-mask (x16 - x31)
2324         8 16: extended-register-save-offset (WORDS from register-save-offset)  */
2325
2326 static void
2327 output_tdesc (file, offset)
2328      FILE *file;
2329      int offset;
2330 {
2331   int regno, i, j;
2332   long mask, return_address_info, register_save_offset;
2333   long xmask, xregister_save_offset;
2334   char buf[256];
2335
2336   for (mask = 0, i = 0, regno = FIRST_OCS_PRESERVE_REGISTER;
2337        regno <= LAST_OCS_PRESERVE_REGISTER;
2338        regno++)
2339     {
2340       mask <<= 1;
2341       if (save_regs[regno])
2342         {
2343           mask |= 1;
2344           i++;
2345         }
2346     }
2347
2348   for (xmask = 0, j = 0, regno = FIRST_OCS_EXTENDED_PRESERVE_REGISTER;
2349        regno <= LAST_OCS_EXTENDED_PRESERVE_REGISTER;
2350        regno++)
2351     {
2352       xmask <<= 1;
2353       if (save_regs[regno])
2354         {
2355           xmask |= 1;
2356           j++;
2357         }
2358     }
2359
2360   if (save_regs[1])
2361     {
2362       if ((nxregs > 0 || nregs > 2) && !save_regs[FRAME_POINTER_REGNUM])
2363         offset -= 4;
2364       return_address_info = - m88k_stack_size + offset;
2365       register_save_offset = return_address_info - i*4;
2366     }
2367   else
2368     {
2369       return_address_info = 1;
2370       register_save_offset = - m88k_stack_size + offset + 4 - i*4;
2371     }
2372
2373   xregister_save_offset = - (j * 2 + ((register_save_offset >> 2) & 1));
2374
2375   tdesc_section ();
2376
2377   /* 8:0,22:(20 or 16),2:2 */
2378   fprintf (file, "%s%d,%d", integer_asm_op (4, TRUE),
2379            (((xmask != 0) ? 20 : 16) << 2) | 2,
2380            flag_pic ? 2 : 1);
2381
2382   ASM_GENERATE_INTERNAL_LABEL (buf, OCS_START_PREFIX, m88k_function_number);
2383   fprintf (file, ",%s%s", buf+1, flag_pic ? "#rel" : "");
2384   ASM_GENERATE_INTERNAL_LABEL (buf, OCS_END_PREFIX, m88k_function_number);
2385   fprintf (file, ",%s%s", buf+1, flag_pic ? "#rel" : "");
2386
2387   fprintf (file, ",0x%x,0x%x,0x%lx,0x%lx",
2388            /* 8:1,17:0x%.3x,1:0,1:%d,5:%d */
2389            (int)(((xmask ? 3 : 1) << (17+1+1+5))
2390             | (mask << (1+1+5))
2391             | ((!!save_regs[1]) << 5)
2392             | (frame_pointer_needed
2393                ? FRAME_POINTER_REGNUM
2394                : STACK_POINTER_REGNUM)),
2395            (m88k_stack_size - (frame_pointer_needed ? m88k_fp_offset : 0)),
2396            return_address_info,
2397            register_save_offset);
2398   if (xmask)
2399     fprintf (file, ",0x%lx%04lx", xmask, (0xffff & xregister_save_offset));
2400   fputc ('\n', file);
2401
2402   text_section ();
2403 }
2404 \f
2405 /* Output assembler code to FILE to increment profiler label # LABELNO
2406    for profiling a function entry.  NAME is the mcount function name
2407    (varies), SAVEP indicates whether the parameter registers need to
2408    be saved and restored.  */
2409
2410 void
2411 output_function_profiler (file, labelno, name, savep)
2412      FILE *file;
2413      int labelno;
2414      const char *name;
2415      int savep;
2416 {
2417   char label[256];
2418   char dbi[256];
2419   const char *const temp = (savep ? reg_names[2] : reg_names[10]);
2420
2421   /* Remember to update FUNCTION_PROFILER_LENGTH.  */
2422
2423   if (savep)
2424     {
2425       fprintf (file, "\tsubu\t %s,%s,64\n", reg_names[31], reg_names[31]);
2426       fprintf (file, "\tst.d\t %s,%s,32\n", reg_names[2], reg_names[31]);
2427       fprintf (file, "\tst.d\t %s,%s,40\n", reg_names[4], reg_names[31]);
2428       fprintf (file, "\tst.d\t %s,%s,48\n", reg_names[6], reg_names[31]);
2429       fprintf (file, "\tst.d\t %s,%s,56\n", reg_names[8], reg_names[31]);
2430     }
2431
2432   ASM_GENERATE_INTERNAL_LABEL (label, "LP", labelno);
2433   if (flag_pic == 2)
2434     {
2435       fprintf (file, "\tor.u\t %s,%s,%shi16(%s#got_rel)\n",
2436                temp, reg_names[0], m88k_pound_sign, &label[1]);
2437       fprintf (file, "\tor\t %s,%s,%slo16(%s#got_rel)\n",
2438                temp, temp, m88k_pound_sign, &label[1]);
2439       sprintf (dbi, "\tld\t %s,%s,%s\n", temp,
2440                reg_names[PIC_OFFSET_TABLE_REGNUM], temp);
2441     }
2442   else if (flag_pic)
2443     {
2444       sprintf (dbi, "\tld\t %s,%s,%s#got_rel\n", temp,
2445                reg_names[PIC_OFFSET_TABLE_REGNUM], &label[1]);
2446     }
2447   else
2448     {
2449       fprintf (file, "\tor.u\t %s,%s,%shi16(%s)\n",
2450                temp, reg_names[0], m88k_pound_sign, &label[1]);
2451       sprintf (dbi, "\tor\t %s,%s,%slo16(%s)\n",
2452                temp, temp, m88k_pound_sign, &label[1]);
2453     }
2454
2455   if (flag_pic)
2456     fprintf (file, "\tbsr.n\t %s#plt\n", name);
2457   else
2458     fprintf (file, "\tbsr.n\t %s\n", name);
2459   fputs (dbi, file);
2460
2461   if (savep)
2462     {
2463       fprintf (file, "\tld.d\t %s,%s,32\n", reg_names[2], reg_names[31]);
2464       fprintf (file, "\tld.d\t %s,%s,40\n", reg_names[4], reg_names[31]);
2465       fprintf (file, "\tld.d\t %s,%s,48\n", reg_names[6], reg_names[31]);
2466       fprintf (file, "\tld.d\t %s,%s,56\n", reg_names[8], reg_names[31]);
2467       fprintf (file, "\taddu\t %s,%s,64\n", reg_names[31], reg_names[31]);
2468     }
2469 }
2470
2471 /* Output assembler code to FILE to initialize basic-block profiling for
2472    the current module.  LABELNO is unique to each instance.  */
2473
2474 void
2475 output_function_block_profiler (file, labelno)
2476      FILE *file;
2477      int labelno;
2478 {
2479   char block[256];
2480   char label[256];
2481
2482   /* Remember to update FUNCTION_BLOCK_PROFILER_LENGTH.  */
2483
2484   ASM_GENERATE_INTERNAL_LABEL (block, "LPBX", 0);
2485   ASM_GENERATE_INTERNAL_LABEL (label, "LPY", labelno);
2486
2487   /* @@ Need to deal with PIC.  I'm not sure what the requirements are on
2488      register usage, so I used r26/r27 to be safe.  */
2489   fprintf (file, "\tor.u\t %s,%s,%shi16(%s)\n", reg_names[27], reg_names[0],
2490                  m88k_pound_sign, &block[1]);
2491   fprintf (file, "\tld\t %s,%s,%slo16(%s)\n", reg_names[26], reg_names[27],
2492                  m88k_pound_sign, &block[1]);
2493   fprintf (file, "\tbcnd\t %sne0,%s,%s\n",
2494                  m88k_pound_sign, reg_names[26], &label[1]);
2495   fprintf (file, "\tsubu\t %s,%s,64\n", reg_names[31], reg_names[31]);
2496   fprintf (file, "\tst.d\t %s,%s,32\n", reg_names[2], reg_names[31]);
2497   fprintf (file, "\tst.d\t %s,%s,40\n", reg_names[4], reg_names[31]);
2498   fprintf (file, "\tst.d\t %s,%s,48\n", reg_names[6], reg_names[31]);
2499   fprintf (file, "\tst.d\t %s,%s,56\n", reg_names[8], reg_names[31]);
2500   fputs ("\tbsr.n\t ", file);
2501   ASM_OUTPUT_LABELREF (file, "__bb_init_func");
2502   putc ('\n', file);
2503   fprintf (file, "\tor\t %s,%s,%slo16(%s)\n", reg_names[2], reg_names[27],
2504                  m88k_pound_sign, &block[1]);
2505   fprintf (file, "\tld.d\t %s,%s,32\n", reg_names[2], reg_names[31]);
2506   fprintf (file, "\tld.d\t %s,%s,40\n", reg_names[4], reg_names[31]);
2507   fprintf (file, "\tld.d\t %s,%s,48\n", reg_names[6], reg_names[31]);
2508   fprintf (file, "\tld.d\t %s,%s,56\n", reg_names[8], reg_names[31]);
2509   fprintf (file, "\taddu\t %s,%s,64\n", reg_names[31], reg_names[31]);
2510   ASM_OUTPUT_INTERNAL_LABEL (file, "LPY", labelno);
2511 }
2512
2513 /* Output assembler code to FILE to increment the count associated with
2514    the basic block number BLOCKNO.  */
2515
2516 void
2517 output_block_profiler (file, blockno)
2518      FILE *file;
2519      int blockno;
2520 {
2521   char block[256];
2522
2523   /* Remember to update BLOCK_PROFILER_LENGTH.  */
2524
2525   ASM_GENERATE_INTERNAL_LABEL (block, "LPBX", 2);
2526
2527   /* @@ Need to deal with PIC.  I'm not sure what the requirements are on
2528      register usage, so I used r26/r27 to be safe.  */
2529   fprintf (file, "\tor.u\t %s,%s,%shi16(%s+%d)\n", reg_names[27], reg_names[0],
2530            m88k_pound_sign, &block[1], 4 * blockno);
2531   fprintf (file, "\tld\t %s,%s,%slo16(%s+%d)\n", reg_names[26], reg_names[27],
2532            m88k_pound_sign, &block[1], 4 * blockno);
2533   fprintf (file, "\taddu\t %s,%s,1\n", reg_names[26], reg_names[26]);
2534   fprintf (file, "\tst\t %s,%s,%slo16(%s+%d)\n", reg_names[26], reg_names[27],
2535            m88k_pound_sign, &block[1], 4 * blockno);
2536 }
2537 \f
2538 /* Determine whether a function argument is passed in a register, and
2539    which register.
2540
2541    The arguments are CUM, which summarizes all the previous
2542    arguments; MODE, the machine mode of the argument; TYPE,
2543    the data type of the argument as a tree node or 0 if that is not known
2544    (which happens for C support library functions); and NAMED,
2545    which is 1 for an ordinary argument and 0 for nameless arguments that
2546    correspond to `...' in the called function's prototype.
2547
2548    The value of the expression should either be a `reg' RTX for the
2549    hard register in which to pass the argument, or zero to pass the
2550    argument on the stack.
2551
2552    On the m88000 the first eight words of args are normally in registers
2553    and the rest are pushed.  Double precision floating point must be
2554    double word aligned (and if in a register, starting on an even
2555    register). Structures and unions which are not 4 byte, and word
2556    aligned are passed in memory rather than registers, even if they
2557    would fit completely in the registers under OCS rules.
2558
2559    Note that FUNCTION_ARG and FUNCTION_INCOMING_ARG were different.
2560    For structures that are passed in memory, but could have been
2561    passed in registers, we first load the structure into the
2562    register, and then when the last argument is passed, we store
2563    the registers into the stack locations.  This fixes some bugs
2564    where GCC did not expect to have register arguments, followed
2565    by stack arguments, followed by register arguments.  */
2566
2567 struct rtx_def *
2568 m88k_function_arg (args_so_far, mode, type, named)
2569      CUMULATIVE_ARGS args_so_far;
2570      enum machine_mode mode;
2571      tree type;
2572      int named ATTRIBUTE_UNUSED;
2573 {
2574   int bytes, words;
2575
2576   if (type != 0                 /* undo putting struct in register */
2577       && (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE))
2578     mode = BLKmode;
2579
2580   if (mode == BLKmode && TARGET_WARN_PASS_STRUCT)
2581     warning ("argument #%d is a structure", args_so_far + 1);
2582
2583   if ((args_so_far & 1) != 0
2584       && (mode == DImode || mode == DFmode
2585           || (type != 0 && TYPE_ALIGN (type) > 32)))
2586     args_so_far++;
2587
2588 #ifdef ESKIT
2589   if (no_reg_params)
2590     return (rtx) 0;             /* don't put args in registers */
2591 #endif
2592
2593   if (type == 0 && mode == BLKmode)
2594     abort ();   /* m88k_function_arg argument `type' is NULL for BLKmode. */
2595
2596   bytes = (mode != BLKmode) ? GET_MODE_SIZE (mode) : int_size_in_bytes (type);
2597   words = (bytes + 3) / 4;
2598
2599   if (args_so_far + words > 8)
2600     return (rtx) 0;             /* args have exhausted registers */
2601
2602   else if (mode == BLKmode
2603            && (TYPE_ALIGN (type) != BITS_PER_WORD
2604                || bytes != UNITS_PER_WORD))
2605     return (rtx) 0;
2606
2607   return gen_rtx_REG (((mode == BLKmode) ? TYPE_MODE (type) : mode),
2608                       2 + args_so_far);
2609 }
2610 \f
2611 /* Do what is necessary for `va_start'.  We look at the current function
2612    to determine if stdargs or varargs is used and spill as necessary. 
2613    We return a pointer to the spill area.  */
2614
2615 struct rtx_def *
2616 m88k_builtin_saveregs ()
2617 {
2618   rtx addr;
2619   tree fntype = TREE_TYPE (current_function_decl);
2620   int argadj = ((!(TYPE_ARG_TYPES (fntype) != 0
2621                    && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
2622                        != void_type_node)))
2623                 ? -UNITS_PER_WORD : 0) + UNITS_PER_WORD - 1;
2624   int fixed;
2625
2626   variable_args_p = 1;
2627
2628   fixed = 0;
2629   if (GET_CODE (current_function_arg_offset_rtx) == CONST_INT)
2630     fixed = ((INTVAL (current_function_arg_offset_rtx) + argadj)
2631              / UNITS_PER_WORD);
2632
2633   /* Allocate the register space, and store it as the __va_reg member.  */
2634   addr = assign_stack_local (BLKmode, 8 * UNITS_PER_WORD, -1);
2635   set_mem_alias_set (addr, get_varargs_alias_set ());
2636   RTX_UNCHANGING_P (addr) = 1;
2637   RTX_UNCHANGING_P (XEXP (addr, 0)) = 1;
2638
2639   /* Now store the incoming registers.  */
2640   if (fixed < 8)
2641     move_block_from_reg (2 + fixed,
2642                          adjust_address (addr, Pmode, fixed * UNITS_PER_WORD),
2643                          8 - fixed,
2644                          UNITS_PER_WORD * (8 - fixed));
2645
2646   /* Return the address of the save area, but don't put it in a
2647      register.  This fails when not optimizing and produces worse code
2648      when optimizing.  */
2649   return XEXP (addr, 0);
2650 }
2651
2652 /* Define the `__builtin_va_list' type for the ABI.  */
2653
2654 tree
2655 m88k_build_va_list ()
2656 {
2657   tree field_reg, field_stk, field_arg, int_ptr_type_node, record;
2658
2659   int_ptr_type_node = build_pointer_type (integer_type_node);
2660
2661   record = make_node (RECORD_TYPE);
2662
2663   field_arg = build_decl (FIELD_DECL, get_identifier ("__va_arg"),
2664                           integer_type_node);
2665   field_stk = build_decl (FIELD_DECL, get_identifier ("__va_stk"),
2666                           int_ptr_type_node);
2667   field_reg = build_decl (FIELD_DECL, get_identifier ("__va_reg"),
2668                           int_ptr_type_node);
2669
2670   DECL_FIELD_CONTEXT (field_arg) = record;
2671   DECL_FIELD_CONTEXT (field_stk) = record;
2672   DECL_FIELD_CONTEXT (field_reg) = record;
2673
2674   TYPE_FIELDS (record) = field_arg;
2675   TREE_CHAIN (field_arg) = field_stk;
2676   TREE_CHAIN (field_stk) = field_reg;
2677
2678   layout_type (record);
2679   return record;
2680 }
2681
2682 /* Implement `va_start' for varargs and stdarg.  */
2683
2684 void
2685 m88k_va_start (stdarg_p, valist, nextarg)
2686      int stdarg_p ATTRIBUTE_UNUSED;
2687      tree valist;
2688      rtx nextarg ATTRIBUTE_UNUSED;
2689 {
2690   tree field_reg, field_stk, field_arg;
2691   tree reg, stk, arg, t;
2692
2693   field_arg = TYPE_FIELDS (va_list_type_node);
2694   field_stk = TREE_CHAIN (field_arg);
2695   field_reg = TREE_CHAIN (field_stk);
2696
2697   arg = build (COMPONENT_REF, TREE_TYPE (field_arg), valist, field_arg);
2698   stk = build (COMPONENT_REF, TREE_TYPE (field_stk), valist, field_stk);
2699   reg = build (COMPONENT_REF, TREE_TYPE (field_reg), valist, field_reg);
2700
2701   /* Fill in the ARG member.  */
2702   {
2703     tree fntype = TREE_TYPE (current_function_decl);
2704     int argadj = ((!(TYPE_ARG_TYPES (fntype) != 0
2705                      && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
2706                          != void_type_node)))
2707                   ? -UNITS_PER_WORD : 0) + UNITS_PER_WORD - 1;
2708     tree argsize;
2709
2710     if (CONSTANT_P (current_function_arg_offset_rtx))
2711       {
2712         int fixed = (INTVAL (current_function_arg_offset_rtx)
2713                      + argadj) / UNITS_PER_WORD;
2714
2715         argsize = build_int_2 (fixed, 0);
2716       }
2717     else
2718       {
2719         argsize = make_tree (integer_type_node,
2720                              current_function_arg_offset_rtx);
2721         argsize = fold (build (PLUS_EXPR, integer_type_node, argsize,
2722                                build_int_2 (argadj, 0)));
2723         argsize = fold (build (RSHIFT_EXPR, integer_type_node, argsize,
2724                                build_int_2 (2, 0)));
2725       }
2726
2727     t = build (MODIFY_EXPR, TREE_TYPE (arg), arg, argsize);
2728     TREE_SIDE_EFFECTS (t) = 1;
2729     expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
2730   }
2731
2732   /* Store the arg pointer in the __va_stk member.  */
2733   t = make_tree (TREE_TYPE (stk), virtual_incoming_args_rtx);
2734   t = build (MODIFY_EXPR, TREE_TYPE (stk), stk, t);
2735   TREE_SIDE_EFFECTS (t) = 1;
2736   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
2737
2738   /* Tuck the return value from __builtin_saveregs into __va_reg.  */
2739   t = make_tree (TREE_TYPE (reg), expand_builtin_saveregs ());
2740   t = build (MODIFY_EXPR, TREE_TYPE (reg), reg, t);
2741   TREE_SIDE_EFFECTS (t) = 1;
2742   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
2743 }
2744
2745 /* Implement `va_arg'.  */
2746
2747 rtx
2748 m88k_va_arg (valist, type)
2749      tree valist, type;
2750 {
2751   tree field_reg, field_stk, field_arg;
2752   tree reg, stk, arg, arg_align, base, t;
2753   int size, wsize, align, reg_p;
2754   rtx addr_rtx;
2755
2756   field_arg = TYPE_FIELDS (va_list_type_node);
2757   field_stk = TREE_CHAIN (field_arg);
2758   field_reg = TREE_CHAIN (field_stk);
2759
2760   arg = build (COMPONENT_REF, TREE_TYPE (field_arg), valist, field_arg);
2761   stk = build (COMPONENT_REF, TREE_TYPE (field_stk), valist, field_stk);
2762   reg = build (COMPONENT_REF, TREE_TYPE (field_reg), valist, field_reg);
2763
2764   size = int_size_in_bytes (type);
2765   wsize = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
2766   align = 1 << ((TYPE_ALIGN (type) / BITS_PER_UNIT) >> 3);
2767   reg_p = (AGGREGATE_TYPE_P (type)
2768            ? size == UNITS_PER_WORD && TYPE_ALIGN (type) == BITS_PER_WORD
2769            : size <= 2*UNITS_PER_WORD);
2770
2771   /* Align __va_arg to the (doubleword?) boundary above.  */
2772   t = build (PLUS_EXPR, TREE_TYPE (arg), arg, build_int_2 (align - 1, 0));
2773   arg_align = build (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-align, -1));
2774   arg_align = save_expr (arg_align);
2775
2776   /* Decide if we should read from stack or regs.  */
2777   t = build (LT_EXPR, integer_type_node, arg_align, build_int_2 (8, 0));
2778   base = build (COND_EXPR, TREE_TYPE (reg), t, reg, stk);
2779
2780   /* Find the final address.  */
2781   t = build (PLUS_EXPR, TREE_TYPE (base), base, arg_align);
2782   addr_rtx = expand_expr (t, NULL_RTX, Pmode, EXPAND_NORMAL);
2783   addr_rtx = copy_to_reg (addr_rtx);
2784
2785   /* Increment __va_arg.  */
2786   t = build (PLUS_EXPR, TREE_TYPE (arg), arg_align, build_int_2 (wsize, 0));
2787   t = build (MODIFY_EXPR, TREE_TYPE (arg), arg, t);
2788   TREE_SIDE_EFFECTS (t) = 1;
2789   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
2790
2791   return addr_rtx;
2792 }
2793 \f
2794 /* If cmpsi has not been generated, emit code to do the test.  Return the
2795    expression describing the test of operator OP.  */
2796
2797 rtx
2798 emit_test (op, mode)
2799      enum rtx_code op;
2800      enum machine_mode mode;
2801 {
2802   if (m88k_compare_reg == 0)
2803     emit_insn (gen_test (m88k_compare_op0, m88k_compare_op1));
2804   return (gen_rtx (op, mode, m88k_compare_reg, const0_rtx));
2805 }
2806
2807 /* Determine how to best perform cmpsi/bxx, where cmpsi has a constant
2808    operand.  All tests with zero (albeit swapped) and all equality tests
2809    with a constant are done with bcnd.  The remaining cases are swapped
2810    as needed.  */
2811
2812 void
2813 emit_bcnd (op, label)
2814      enum rtx_code op;
2815      rtx label;
2816 {
2817   if (m88k_compare_op1 == const0_rtx)
2818     emit_jump_insn (gen_bcnd
2819                     (gen_rtx (op, VOIDmode,m88k_compare_op0, const0_rtx),
2820                      label));
2821   else if (m88k_compare_op0 == const0_rtx)
2822     emit_jump_insn (gen_bcnd
2823                     (gen_rtx (swap_condition (op),
2824                               VOIDmode, m88k_compare_op1, const0_rtx),
2825                      label));
2826   else if (op != EQ && op != NE)
2827     emit_jump_insn (gen_bxx (emit_test (op, VOIDmode), label));
2828   else
2829     {
2830       rtx zero = gen_reg_rtx (SImode);
2831       rtx reg, constant;
2832       int value;
2833
2834       if (GET_CODE (m88k_compare_op1) == CONST_INT)
2835         {
2836           reg = force_reg (SImode, m88k_compare_op0);
2837           constant = m88k_compare_op1;
2838         }
2839       else
2840         {
2841           reg = force_reg (SImode, m88k_compare_op1);
2842           constant = m88k_compare_op0;
2843         }
2844       value = INTVAL (constant);
2845
2846       /* Perform an arithmetic computation to make the compared-to value
2847          zero, but avoid loosing if the bcnd is later changed into sxx.  */
2848       if (SMALL_INTVAL (value))
2849         emit_jump_insn (gen_bxx (emit_test (op, VOIDmode), label));
2850       else
2851         {
2852           if (SMALL_INTVAL (-value))
2853             emit_insn (gen_addsi3 (zero, reg,
2854                                    GEN_INT (-value)));
2855           else
2856             emit_insn (gen_xorsi3 (zero, reg, constant));
2857
2858           emit_jump_insn (gen_bcnd (gen_rtx (op, VOIDmode,
2859                                              zero, const0_rtx),
2860                                     label));
2861         }
2862     }
2863 }
2864 \f
2865 /* Print an operand.  Recognize special options, documented below.  */
2866
2867 void
2868 print_operand (file, x, code)
2869     FILE *file;
2870     rtx x;
2871     int code;
2872 {
2873   enum rtx_code xc = (x ? GET_CODE (x) : UNKNOWN);
2874   register int value = (xc == CONST_INT ? INTVAL (x) : 0);
2875   static int sequencep;
2876   static int reversep;
2877
2878   if (sequencep)
2879     {
2880       if (code < 'B' || code > 'E')
2881         output_operand_lossage ("%%R not followed by %%B/C/D/E");
2882       if (reversep)
2883         xc = reverse_condition (xc);
2884       sequencep = 0;
2885     }
2886
2887   switch (code)
2888     {
2889     case '*': /* addressing base register for PIC */
2890       fputs (reg_names[PIC_OFFSET_TABLE_REGNUM], file); return;
2891
2892     case '#': /* SVR4 pound-sign syntax character (empty if SVR3) */
2893       fputs (m88k_pound_sign, file); return;
2894
2895     case 'V': /* Output a serializing instruction as needed if the operand
2896                  (assumed to be a MEM) is a volatile load.  */
2897     case 'v': /* ditto for a volatile store.  */
2898       if (MEM_VOLATILE_P (x) && TARGET_SERIALIZE_VOLATILE)
2899         {
2900           /* The m88110 implements two FIFO queues, one for loads and
2901              one for stores.  These queues mean that loads complete in
2902              their issue order as do stores.  An interaction between the
2903              history buffer and the store reservation station ensures
2904              that a store will not bypass load.  Finally, a load will not
2905              bypass store, but only when they reference the same address.
2906
2907              To avoid this reordering (a load bypassing a store) for
2908              volatile references, a serializing instruction is output.
2909              We choose the fldcr instruction as it does not serialize on
2910              the m88100 so that -m88000 code will not be degraded.
2911
2912              The mechanism below is completed by having CC_STATUS_INIT set
2913              the code to the unknown value.  */
2914
2915           /*
2916              hassey 6/30/93
2917              A problem with 88110 4.1 & 4.2 makes the use of fldcr for
2918              this purpose undesirable.  Instead we will use tb1, this will
2919              cause serialization on the 88100 but such is life.
2920           */
2921
2922           static rtx last_addr = 0;
2923           if (code == 'V' /* Only need to serialize before a load.  */
2924               && m88k_volatile_code != 'V' /* Loads complete in FIFO order.  */
2925               && !(m88k_volatile_code == 'v'
2926                    && GET_CODE (XEXP (x, 0)) == LO_SUM
2927                    && rtx_equal_p (XEXP (XEXP (x, 0), 1), last_addr)))
2928             fprintf (file,
2929 #if 0
2930 #ifdef AS_BUG_FLDCR
2931                      "fldcr\t %s,%scr63\n\t",
2932 #else
2933                      "fldcr\t %s,%sfcr63\n\t",
2934 #endif
2935                      reg_names[0], m88k_pound_sign);
2936 #else /* 0 */
2937                      "tb1\t 1,%s,0xff\n\t", reg_names[0]);
2938 #endif /* 0 */
2939           m88k_volatile_code = code;
2940           last_addr = (GET_CODE (XEXP (x, 0)) == LO_SUM
2941                        ? XEXP (XEXP (x, 0), 1) : 0);
2942         }
2943       return;
2944
2945     case 'X': /* print the upper 16 bits... */
2946       value >>= 16;
2947     case 'x': /* print the lower 16 bits of the integer constant in hex */
2948       if (xc != CONST_INT)
2949         output_operand_lossage ("invalid %%x/X value");
2950       fprintf (file, "0x%x", value & 0xffff); return;
2951
2952     case 'H': /* print the low 16 bits of the negated integer constant */
2953       if (xc != CONST_INT)
2954         output_operand_lossage ("invalid %%H value");
2955       value = -value;
2956     case 'h': /* print the register or low 16 bits of the integer constant */
2957       if (xc == REG)
2958         goto reg;
2959       if (xc != CONST_INT)
2960         output_operand_lossage ("invalid %%h value");
2961       fprintf (file, "%d", value & 0xffff);
2962       return;
2963
2964     case 'Q': /* print the low 8 bits of the negated integer constant */
2965       if (xc != CONST_INT)
2966         output_operand_lossage ("invalid %%Q value");
2967       value = -value;
2968     case 'q': /* print the register or low 8 bits of the integer constant */
2969       if (xc == REG)
2970         goto reg;
2971       if (xc != CONST_INT)
2972         output_operand_lossage ("invalid %%q value");
2973       fprintf (file, "%d", value & 0xff);
2974       return;
2975
2976     case 'w': /* print the integer constant (X == 32 ? 0 : 32 - X) */
2977       if (xc != CONST_INT)
2978         output_operand_lossage ("invalid %%o value");
2979       fprintf (file, "%d", value == 32 ? 0 : 32 - value);
2980       return;
2981
2982     case 'p': /* print the logarithm of the integer constant */
2983       if (xc != CONST_INT
2984           || (value = exact_log2 (value)) < 0)
2985         output_operand_lossage ("invalid %%p value");
2986       fprintf (file, "%d", value);
2987       return;
2988
2989     case 'S': /* compliment the value and then... */
2990       value = ~value;
2991     case 's': /* print the width and offset values forming the integer
2992                  constant with a SET instruction.  See integer_ok_for_set. */
2993       {
2994         register unsigned mask, uval = value;
2995         register int top, bottom;
2996
2997         if (xc != CONST_INT)
2998           output_operand_lossage ("invalid %%s/S value");
2999         /* All the "one" bits must be contiguous.  If so, MASK will be
3000            a power of two or zero.  */
3001         mask = (uval | (uval - 1)) + 1;
3002         if (!(uval && POWER_OF_2_or_0 (mask)))
3003           output_operand_lossage ("invalid %%s/S value");
3004         top = mask ? exact_log2 (mask) : 32;
3005         bottom = exact_log2 (uval & ~(uval - 1));
3006         fprintf (file,"%d<%d>", top - bottom, bottom);
3007         return;
3008       }
3009
3010     case 'P': /* print nothing if pc_rtx; output label_ref */
3011       if (xc == LABEL_REF)
3012         output_addr_const (file, x);
3013       else if (xc != PC)
3014         output_operand_lossage ("invalid %%P operand");
3015       return;
3016
3017     case 'L': /* print 0 or 1 if operand is label_ref and then...  */
3018       fputc (xc == LABEL_REF ? '1' : '0', file);
3019     case '.': /* print .n if delay slot is used */
3020       fputs ((final_sequence
3021               && ! INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0)))
3022              ? ".n\t" : "\t", file);
3023       return;
3024
3025     case '!': /* Reverse the following condition. */
3026       sequencep++;
3027       reversep = 1;
3028       return; 
3029     case 'R': /* reverse the condition of the next print_operand
3030                  if operand is a label_ref.  */
3031       sequencep++;
3032       reversep = (xc == LABEL_REF);
3033       return;
3034
3035     case 'B': /* bcnd branch values */
3036       fputs (m88k_pound_sign, file);
3037       switch (xc)
3038         {
3039         case EQ: fputs ("eq0", file); return;
3040         case NE: fputs ("ne0", file); return;
3041         case GT: fputs ("gt0", file); return;
3042         case LE: fputs ("le0", file); return;
3043         case LT: fputs ("lt0", file); return;
3044         case GE: fputs ("ge0", file); return;
3045         default: output_operand_lossage ("invalid %%B value");
3046         }
3047
3048     case 'C': /* bb0/bb1 branch values for comparisons */
3049       fputs (m88k_pound_sign, file);
3050       switch (xc)
3051         {
3052         case EQ:  fputs ("eq", file); return;
3053         case NE:  fputs ("ne", file); return;
3054         case GT:  fputs ("gt", file); return;
3055         case LE:  fputs ("le", file); return;
3056         case LT:  fputs ("lt", file); return;
3057         case GE:  fputs ("ge", file); return;
3058         case GTU: fputs ("hi", file); return;
3059         case LEU: fputs ("ls", file); return;
3060         case LTU: fputs ("lo", file); return;
3061         case GEU: fputs ("hs", file); return;
3062         default:  output_operand_lossage ("invalid %%C value");
3063         }
3064
3065     case 'D': /* bcnd branch values for float comparisons */
3066       switch (xc)
3067         {
3068         case EQ: fputs ("0xa", file); return;
3069         case NE: fputs ("0x5", file); return;
3070         case GT: fputs (m88k_pound_sign, file);
3071           fputs ("gt0", file); return;
3072         case LE: fputs ("0xe", file); return;
3073         case LT: fputs ("0x4", file); return;
3074         case GE: fputs ("0xb", file); return;
3075         default: output_operand_lossage ("invalid %%D value");
3076         }
3077
3078     case 'E': /* bcnd branch values for special integers */
3079       switch (xc)
3080         {
3081         case EQ: fputs ("0x8", file); return;
3082         case NE: fputs ("0x7", file); return;
3083         default: output_operand_lossage ("invalid %%E value");
3084         }
3085
3086     case 'd': /* second register of a two register pair */
3087       if (xc != REG)
3088         output_operand_lossage ("`%%d' operand isn't a register");
3089       fputs (reg_names[REGNO (x) + 1], file);
3090       return;
3091
3092     case 'r': /* an immediate 0 should be represented as `r0' */
3093       if (x == const0_rtx)
3094         {
3095           fputs (reg_names[0], file);
3096           return;
3097         }
3098       else if (xc != REG)
3099         output_operand_lossage ("invalid %%r value");
3100     case 0:
3101     name:
3102       if (xc == REG)
3103         {
3104         reg:
3105           if (REGNO (x) == ARG_POINTER_REGNUM)
3106             output_operand_lossage ("operand is r0");
3107           else
3108             fputs (reg_names[REGNO (x)], file);
3109         }
3110       else if (xc == PLUS)
3111         output_address (x);
3112       else if (xc == MEM)
3113         output_address (XEXP (x, 0));
3114       else if (flag_pic && xc == UNSPEC)
3115         {
3116           output_addr_const (file, XVECEXP (x, 0, 0));
3117           fputs ("#got_rel", file);
3118         }
3119       else if (xc == CONST_DOUBLE)
3120         output_operand_lossage ("operand is const_double");
3121       else
3122         output_addr_const (file, x);
3123       return;
3124
3125     case 'g': /* append #got_rel as needed */
3126       if (flag_pic && (xc == SYMBOL_REF || xc == LABEL_REF))
3127         {
3128           output_addr_const (file, x);
3129           fputs ("#got_rel", file);
3130           return;
3131         }
3132       goto name;
3133
3134     case 'a': /* (standard), assume operand is an address */
3135     case 'c': /* (standard), assume operand is an immediate value */
3136     case 'l': /* (standard), assume operand is a label_ref */
3137     case 'n': /* (standard), like %c, except negate first */
3138     default:
3139       output_operand_lossage ("invalid code");
3140     }
3141 }
3142
3143 void
3144 print_operand_address (file, addr)
3145     FILE *file;
3146     rtx addr;
3147 {
3148   register rtx reg0, reg1, temp;
3149
3150   switch (GET_CODE (addr))
3151     {
3152     case REG:
3153       if (REGNO (addr) == ARG_POINTER_REGNUM)
3154         abort ();
3155       else
3156         fprintf (file, "%s,%s", reg_names[0], reg_names [REGNO (addr)]);
3157       break;
3158
3159     case LO_SUM:
3160       fprintf (file, "%s,%slo16(",
3161                reg_names[REGNO (XEXP (addr, 0))], m88k_pound_sign);
3162       output_addr_const (file, XEXP (addr, 1));
3163       fputc (')', file);
3164       break;
3165
3166     case PLUS:
3167       reg0 = XEXP (addr, 0);
3168       reg1 = XEXP (addr, 1);
3169       if (GET_CODE (reg0) == MULT || GET_CODE (reg0) == CONST_INT)
3170         {
3171           rtx tmp = reg0;
3172           reg0 = reg1;
3173           reg1 = tmp;
3174         }
3175
3176       if ((REG_P (reg0) && REGNO (reg0) == ARG_POINTER_REGNUM)
3177           || (REG_P (reg1) && REGNO (reg1) == ARG_POINTER_REGNUM))
3178         abort ();
3179
3180       else if (REG_P (reg0))
3181         {
3182           if (REG_P (reg1))
3183             fprintf (file, "%s,%s",
3184                      reg_names [REGNO (reg0)], reg_names [REGNO (reg1)]);
3185
3186           else if (GET_CODE (reg1) == CONST_INT)
3187             fprintf (file, "%s,%d",
3188                      reg_names [REGNO (reg0)], INTVAL (reg1));
3189
3190           else if (GET_CODE (reg1) == MULT)
3191             {
3192               rtx mreg = XEXP (reg1, 0);
3193               if (REGNO (mreg) == ARG_POINTER_REGNUM)
3194                 abort ();
3195
3196               fprintf (file, "%s[%s]", reg_names[REGNO (reg0)],
3197                        reg_names[REGNO (mreg)]);
3198             }
3199
3200           else if (GET_CODE (reg1) == ZERO_EXTRACT)
3201             {
3202               fprintf (file, "%s,%slo16(",
3203                        reg_names[REGNO (reg0)], m88k_pound_sign);
3204               output_addr_const (file, XEXP (reg1, 0));
3205               fputc (')', file);
3206             }
3207
3208           else if (flag_pic)
3209             {
3210               fprintf (file, "%s,", reg_names[REGNO (reg0)]);
3211               output_addr_const (file, reg1);
3212               fputs ("#got_rel", file);
3213             }
3214           else abort ();
3215         }
3216
3217       else
3218         abort ();
3219       break;
3220
3221     case MULT:
3222       if (REGNO (XEXP (addr, 0)) == ARG_POINTER_REGNUM)
3223         abort ();
3224
3225       fprintf (file, "%s[%s]",
3226                reg_names[0], reg_names[REGNO (XEXP (addr, 0))]);
3227       break;
3228
3229     case CONST_INT:
3230       fprintf (file, "%s,%d", reg_names[0], INTVAL (addr));
3231       break;
3232
3233     default:
3234       fprintf (file, "%s,", reg_names[0]);
3235       if (SHORT_ADDRESS_P (addr, temp))
3236         {
3237           fprintf (file, "%siw16(", m88k_pound_sign);
3238           output_addr_const (file, addr);
3239           fputc (')', file);
3240         }
3241       else
3242           output_addr_const (file, addr);
3243     }
3244 }
3245
3246 /* Return true if X is an address which needs a temporary register when 
3247    reloaded while generating PIC code.  */
3248
3249 int
3250 pic_address_needs_scratch (x)
3251      rtx x;
3252 {
3253   /* An address which is a symbolic plus a non SMALL_INT needs a temp reg.  */
3254   if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
3255       && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
3256       && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
3257       && ! ADD_INT (XEXP (XEXP (x, 0), 1)))
3258     return 1;
3259
3260   return 0;
3261 }
3262
3263 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
3264    reference and a constant.  */
3265
3266 int
3267 symbolic_operand (op, mode)
3268      register rtx op;
3269      enum machine_mode mode;
3270 {
3271   switch (GET_CODE (op))
3272     {
3273     case SYMBOL_REF:
3274     case LABEL_REF:
3275       return 1;
3276
3277     case CONST:
3278       op = XEXP (op, 0);
3279       return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
3280                || GET_CODE (XEXP (op, 0)) == LABEL_REF)
3281               && GET_CODE (XEXP (op, 1)) == CONST_INT);
3282
3283       /* ??? This clause seems to be irrelevant.  */
3284     case CONST_DOUBLE:
3285       return GET_MODE (op) == mode;
3286
3287     default:
3288       return 0;
3289     }
3290 }
3291
3292 #if defined (CTOR_LIST_BEGIN) && !defined (OBJECT_FORMAT_ELF)
3293 static void
3294 m88k_svr3_asm_out_constructor (symbol, priority)
3295      rtx symbol;
3296      int priority ATTRIBUTE_UNUSED;
3297 {
3298   const char *name = XSTR (symbol, 0);
3299
3300   init_section ();
3301   fprintf (asm_out_file, "\tor.u\t r13,r0,hi16(");
3302   assemble_name (asm_out_file, name);
3303   fprintf (asm_out_file, ")\n\tor\t r13,r13,lo16(");
3304   assemble_name (asm_out_file, name);
3305   fprintf (asm_out_file, ")\n\tsubu\t r31,r31,%d\n\tst\t r13,r31,%d\n",
3306            STACK_BOUNDARY / BITS_PER_UNIT, REG_PARM_STACK_SPACE (0));
3307 }
3308
3309 static void
3310 m88k_svr3_asm_out_destructor (symbol, priority)
3311      rtx symbol;
3312      int priority ATTRIBUTE_UNUSED;
3313 {
3314   int i;
3315
3316   fini_section ();
3317   assemble_integer (symbol, UNITS_PER_WORD, BITS_PER_WORD, 1);
3318   for (i = 1; i < 4; i++)
3319     assemble_integer (constm1_rtx, UNITS_PER_WORD, BITS_PER_WORD, 1);
3320 }
3321 #endif /* INIT_SECTION_ASM_OP && ! OBJECT_FORMAT_ELF */
3322
3323 static void
3324 m88k_select_section (decl, reloc, align)
3325      tree decl;
3326      int reloc;
3327      unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED;
3328 {
3329   if (TREE_CODE (decl) == STRING_CST)
3330     {
3331       if (! flag_writable_strings)
3332         const_section ();
3333       else if (TREE_STRING_LENGTH (decl) <= m88k_gp_threshold)
3334         sdata_section ();
3335       else
3336         data_section ();
3337     }
3338   else if (TREE_CODE (decl) == VAR_DECL)
3339     {
3340       if (SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)))
3341         sdata_section ();
3342       else if ((flag_pic && reloc)
3343                || !TREE_READONLY (decl) || TREE_SIDE_EFFECTS (decl)
3344                || !DECL_INITIAL (decl)
3345                || (DECL_INITIAL (decl) != error_mark_node
3346                    && !TREE_CONSTANT (DECL_INITIAL (decl))))
3347         data_section ();
3348       else
3349         const_section ();
3350     }
3351   else
3352     const_section ();
3353 }
3354
3355 /* Adjust the cost of INSN based on the relationship between INSN that
3356    is dependent on DEP_INSN through the dependence LINK.  The default
3357    is to make no adjustment to COST.
3358
3359    On the m88k, ignore the cost of anti- and output-dependencies.  On
3360    the m88100, a store can issue two cycles before the value (not the
3361    address) has finished computing.  */
3362
3363 static int
3364 m88k_adjust_cost (insn, link, dep, cost)
3365      rtx insn;
3366      rtx link;
3367      rtx dep;
3368      int cost;
3369 {
3370   if (REG_NOTE_KIND (link) != 0)
3371     return 0;  /* Anti or output dependence.  */
3372
3373   if (! TARGET_88100
3374       && recog_memoized (insn) >= 0
3375       && get_attr_type (insn) == TYPE_STORE
3376       && SET_SRC (PATTERN (insn)) == SET_DEST (PATTERN (dep)))
3377     return cost - 4;  /* 88110 store reservation station.  */
3378
3379   return cost;
3380 }