OSDN Git Service

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