OSDN Git Service

* system.h (BLOCK_PROFILER, BLOCK_PROFILER_CODE,
[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 non zero 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 non zero, 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      non-zero, 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       || current_function_varargs
1951       || variable_args_p)
1952     return 1;
1953
1954   for (parm = DECL_ARGUMENTS (current_function_decl);
1955        parm;
1956        parm = TREE_CHAIN (parm))
1957     {
1958       if (DECL_RTL (parm) == 0
1959           || GET_CODE (DECL_RTL (parm)) == MEM)
1960         return 1;
1961
1962       if (DECL_INCOMING_RTL (parm) == 0
1963           || GET_CODE (DECL_INCOMING_RTL (parm)) == MEM)
1964         return 1;
1965     }
1966   return 0;
1967 }
1968 \f
1969 static void
1970 m88k_output_function_prologue (stream, size)
1971      FILE *stream ATTRIBUTE_UNUSED;
1972      HOST_WIDE_INT size ATTRIBUTE_UNUSED;
1973 {
1974   if (TARGET_OMIT_LEAF_FRAME_POINTER && ! quiet_flag && leaf_function_p ())
1975     fprintf (stderr, "$");
1976
1977   m88k_prologue_done = 1;       /* it's ok now to put out ln directives */
1978 }
1979
1980 static void
1981 m88k_output_function_end_prologue (stream)
1982      FILE *stream;
1983 {
1984   if (TARGET_OCS_DEBUG_INFO && !prologue_marked)
1985     {
1986       PUT_OCS_FUNCTION_START (stream);
1987       prologue_marked = 1;
1988
1989       /* If we've already passed the start of the epilogue, say that
1990          it starts here.  This marks the function as having a null body,
1991          but at a point where the return address is in a known location.
1992
1993          Originally, I thought this couldn't happen, but the pic prologue
1994          for leaf functions ends with the instruction that restores the
1995          return address from the temporary register.  If the temporary
1996          register is never used, that instruction can float all the way
1997          to the end of the function.  */
1998       if (epilogue_marked)
1999         PUT_OCS_FUNCTION_END (stream);
2000     }
2001 }
2002
2003 void
2004 m88k_expand_prologue ()
2005 {
2006   m88k_layout_frame ();
2007
2008   if (TARGET_OPTIMIZE_ARG_AREA
2009       && m88k_stack_size
2010       && ! uses_arg_area_p ())
2011     {
2012       /* The incoming argument area is used for stack space if it is not
2013          used (or if -mno-optimize-arg-area is given).  */
2014       if ((m88k_stack_size -= REG_PARM_STACK_SPACE (0)) < 0)
2015         m88k_stack_size = 0;
2016     }
2017
2018   if (m88k_stack_size)
2019     emit_add (stack_pointer_rtx, stack_pointer_rtx, -m88k_stack_size);
2020
2021   if (nregs || nxregs)
2022     preserve_registers (m88k_fp_offset + 4, 1);
2023
2024   if (frame_pointer_needed)
2025     emit_add (frame_pointer_rtx, stack_pointer_rtx, m88k_fp_offset);
2026
2027   if (flag_pic && save_regs[PIC_OFFSET_TABLE_REGNUM])
2028     {
2029       rtx return_reg = gen_rtx_REG (SImode, 1);
2030       rtx label = gen_label_rtx ();
2031       rtx temp_reg = NULL_RTX;
2032
2033       if (! save_regs[1])
2034         {
2035           temp_reg = gen_rtx_REG (SImode, TEMP_REGNUM);
2036           emit_move_insn (temp_reg, return_reg);
2037         }
2038       emit_insn (gen_locate1 (pic_offset_table_rtx, label));
2039       emit_insn (gen_locate2 (pic_offset_table_rtx, label));
2040       emit_insn (gen_addsi3 (pic_offset_table_rtx,
2041                              pic_offset_table_rtx, return_reg));
2042       if (! save_regs[1])
2043         emit_move_insn (return_reg, temp_reg);
2044     }
2045   if (current_function_profile)
2046     emit_insn (gen_blockage ());
2047 }
2048 \f
2049 /* This function generates the assembly code for function exit,
2050    on machines that need it.
2051
2052    The function epilogue should not depend on the current stack pointer!
2053    It should use the frame pointer only, if there is a frame pointer.
2054    This is mandatory because of alloca; we also take advantage of it to
2055    omit stack adjustments before returning.  */
2056
2057 static void
2058 m88k_output_function_begin_epilogue (stream)
2059      FILE *stream;
2060 {
2061   if (TARGET_OCS_DEBUG_INFO && !epilogue_marked && prologue_marked)
2062     {
2063       PUT_OCS_FUNCTION_END (stream);
2064     }
2065   epilogue_marked = 1;
2066 }
2067
2068 static void
2069 m88k_output_function_epilogue (stream, size)
2070      FILE *stream;
2071      HOST_WIDE_INT size ATTRIBUTE_UNUSED;
2072 {
2073   rtx insn = get_last_insn ();
2074
2075   if (TARGET_OCS_DEBUG_INFO && !epilogue_marked)
2076     PUT_OCS_FUNCTION_END (stream);
2077
2078   /* If the last insn isn't a BARRIER, we must write a return insn.  This
2079      should only happen if the function has no prologue and no body.  */
2080   if (GET_CODE (insn) == NOTE)
2081     insn = prev_nonnote_insn (insn);
2082   if (insn == 0 || GET_CODE (insn) != BARRIER)
2083     fprintf (stream, "\tjmp\t %s\n", reg_names[1]);
2084
2085   /* If the last insn is a barrier, and the insn before that is a call,
2086      then add a nop instruction so that tdesc can walk the stack correctly
2087      even though there is no epilogue. (Otherwise, the label for the
2088      end of the tdesc region ends up at the start of the next function. */
2089   if (insn && GET_CODE (insn) == BARRIER)
2090     {
2091       insn = prev_nonnote_insn (insn);
2092       if (insn && GET_CODE (insn) == CALL_INSN)
2093         fprintf (stream, "\tor\t %s,%s,%s\n",reg_names[0],reg_names[0],reg_names[0]);
2094     }
2095
2096   output_short_branch_defs (stream);
2097
2098   fprintf (stream, "\n");
2099
2100   if (TARGET_OCS_DEBUG_INFO)
2101     output_tdesc (stream, m88k_fp_offset + 4);
2102
2103   m88k_function_number++;
2104   m88k_prologue_done    = 0;            /* don't put out ln directives */
2105   variable_args_p       = 0;            /* has variable args */
2106   frame_laid_out        = 0;
2107   epilogue_marked       = 0;
2108   prologue_marked       = 0;
2109 }
2110
2111 void
2112 m88k_expand_epilogue ()
2113 {
2114 #if (MONITOR_GCC & 0x4) /* What are interesting prologue/epilogue values?  */
2115   fprintf (stream, "; size = %d, m88k_fp_offset = %d, m88k_stack_size = %d\n",
2116            size, m88k_fp_offset, m88k_stack_size);
2117 #endif
2118
2119   if (frame_pointer_needed)
2120     emit_add (stack_pointer_rtx, frame_pointer_rtx, -m88k_fp_offset);
2121
2122   if (nregs || nxregs)
2123     preserve_registers (m88k_fp_offset + 4, 0);
2124
2125   if (m88k_stack_size)
2126     emit_add (stack_pointer_rtx, stack_pointer_rtx, m88k_stack_size);
2127 }
2128 \f
2129 /* Emit insns to set DSTREG to SRCREG + AMOUNT during the prologue or
2130    epilogue.  */
2131
2132 static void
2133 emit_add (dstreg, srcreg, amount)
2134      rtx dstreg;
2135      rtx srcreg;
2136      int amount;
2137 {
2138   rtx incr = GEN_INT (abs (amount));
2139
2140   if (! ADD_INTVAL (amount))
2141     {
2142       rtx temp = gen_rtx_REG (SImode, TEMP_REGNUM);
2143       emit_move_insn (temp, incr);
2144       incr = temp;
2145     }
2146   emit_insn ((amount < 0 ? gen_subsi3 : gen_addsi3) (dstreg, srcreg, incr));
2147 }
2148
2149 /* Save/restore the preserve registers.  base is the highest offset from
2150    r31 at which a register is stored.  store_p is true if stores are to
2151    be done; otherwise loads.  */
2152
2153 static void
2154 preserve_registers (base, store_p)
2155      int base;
2156      int store_p;
2157 {
2158   int regno, offset;
2159   struct mem_op {
2160     int regno;
2161     int nregs;
2162     int offset;
2163   } mem_op[FIRST_PSEUDO_REGISTER];
2164   struct mem_op *mo_ptr = mem_op;
2165
2166   /* The 88open OCS mandates that preserved registers be stored in
2167      increasing order.  For compatibility with current practice,
2168      the order is r1, r30, then the preserve registers.  */
2169
2170   offset = base;
2171   if (save_regs[1])
2172     {
2173       /* An extra word is given in this case to make best use of double
2174          memory ops.  */
2175       if (nregs > 2 && !save_regs[FRAME_POINTER_REGNUM])
2176         offset -= 4;
2177       emit_ldst (store_p, 1, SImode, offset);
2178       offset -= 4;
2179       base = offset;
2180     }
2181
2182   /* Walk the registers to save recording all single memory operations.  */
2183   for (regno = FRAME_POINTER_REGNUM; regno > 1; regno--)
2184     if (save_regs[regno])
2185       {
2186         if ((offset & 7) != 4 || (regno & 1) != 1 || !save_regs[regno-1])
2187           {
2188             mo_ptr->nregs = 1;
2189             mo_ptr->regno = regno;
2190             mo_ptr->offset = offset;
2191             mo_ptr++;
2192             offset -= 4;
2193           }
2194         else
2195           {
2196             regno--;
2197             offset -= 2*4;
2198           }
2199       }
2200
2201   /* Walk the registers to save recording all double memory operations.
2202      This avoids a delay in the epilogue (ld.d/ld).  */
2203   offset = base;
2204   for (regno = FRAME_POINTER_REGNUM; regno > 1; regno--)
2205     if (save_regs[regno])
2206       {
2207         if ((offset & 7) != 4 || (regno & 1) != 1 || !save_regs[regno-1])
2208           {
2209             offset -= 4;
2210           }
2211         else
2212           {
2213             mo_ptr->nregs = 2;
2214             mo_ptr->regno = regno-1;
2215             mo_ptr->offset = offset-4;
2216             mo_ptr++;
2217             regno--;
2218             offset -= 2*4;
2219           }
2220       }
2221
2222   /* Walk the extended registers to record all memory operations.  */
2223   /*  Be sure the offset is double word aligned.  */
2224   offset = (offset - 1) & ~7;
2225   for (regno = FIRST_PSEUDO_REGISTER - 1; regno > FIRST_EXTENDED_REGISTER;
2226        regno--)
2227     if (save_regs[regno])
2228       {
2229         mo_ptr->nregs = 2;
2230         mo_ptr->regno = regno;
2231         mo_ptr->offset = offset;
2232         mo_ptr++;
2233         offset -= 2*4;
2234       }
2235
2236   mo_ptr->regno = 0;
2237
2238   /* Output the memory operations.  */
2239   for (mo_ptr = mem_op; mo_ptr->regno; mo_ptr++)
2240     {
2241       if (mo_ptr->nregs)
2242         emit_ldst (store_p, mo_ptr->regno,
2243                    (mo_ptr->nregs > 1 ? DImode : SImode),
2244                    mo_ptr->offset);
2245     }
2246 }
2247
2248 static void
2249 emit_ldst (store_p, regno, mode, offset)
2250      int store_p;
2251      int regno;
2252      enum machine_mode mode;
2253      int offset;
2254 {
2255   rtx reg = gen_rtx_REG (mode, regno);
2256   rtx mem;
2257
2258   if (SMALL_INTVAL (offset))
2259     {
2260       mem = gen_rtx_MEM (mode, plus_constant (stack_pointer_rtx, offset));
2261     }
2262   else
2263     {
2264       /* offset is too large for immediate index must use register */
2265
2266       rtx disp = GEN_INT (offset);
2267       rtx temp = gen_rtx_REG (SImode, TEMP_REGNUM);
2268       rtx regi = gen_rtx_PLUS (SImode, stack_pointer_rtx, temp);
2269
2270       emit_move_insn (temp, disp);
2271       mem = gen_rtx_MEM (mode, regi);
2272     }
2273
2274   if (store_p)
2275     emit_move_insn (mem, reg);
2276   else
2277     emit_move_insn (reg, mem);
2278 }
2279
2280 /* Convert the address expression REG to a CFA offset.  */
2281
2282 int
2283 m88k_debugger_offset (reg, offset)
2284      register rtx reg;
2285      register int offset;
2286 {
2287   if (GET_CODE (reg) == PLUS)
2288     {
2289       offset = INTVAL (XEXP (reg, 1));
2290       reg = XEXP (reg, 0);
2291     }
2292
2293   /* Put the offset in terms of the CFA (arg pointer).  */
2294   if (reg == frame_pointer_rtx)
2295     offset += m88k_fp_offset - m88k_stack_size;
2296   else if (reg == stack_pointer_rtx)
2297     offset -= m88k_stack_size;
2298   else if (reg != arg_pointer_rtx)
2299     {
2300 #if (MONITOR_GCC & 0x10) /* Watch for suspicious symbolic locations.  */
2301       if (! (GET_CODE (reg) == REG
2302              && REGNO (reg) >= FIRST_PSEUDO_REGISTER))
2303         warning ("internal gcc error: Can't express symbolic location");
2304 #endif
2305       return 0;
2306     }
2307
2308   return offset;
2309 }
2310
2311 /* Output the 88open OCS proscribed text description information.
2312    The information is:
2313         0  8: zero
2314         0 22: info-byte-length (16 or 20 bytes)
2315         0  2: info-alignment (word 2)
2316         1 32: info-protocol (version 1 or 2(pic))
2317         2 32: starting-address (inclusive, not counting prologue)
2318         3 32: ending-address (exclusive, not counting epilog)
2319         4  8: info-variant (version 1 or 3(extended registers))
2320         4 17: register-save-mask (from register 14 to 30)
2321         4  1: zero
2322         4  1: return-address-info-discriminant
2323         4  5: frame-address-register
2324         5 32: frame-address-offset
2325         6 32: return-address-info
2326         7 32: register-save-offset
2327         8 16: extended-register-save-mask (x16 - x31)
2328         8 16: extended-register-save-offset (WORDS from register-save-offset)  */
2329
2330 static void
2331 output_tdesc (file, offset)
2332      FILE *file;
2333      int offset;
2334 {
2335   int regno, i, j;
2336   long mask, return_address_info, register_save_offset;
2337   long xmask, xregister_save_offset;
2338   char buf[256];
2339
2340   for (mask = 0, i = 0, regno = FIRST_OCS_PRESERVE_REGISTER;
2341        regno <= LAST_OCS_PRESERVE_REGISTER;
2342        regno++)
2343     {
2344       mask <<= 1;
2345       if (save_regs[regno])
2346         {
2347           mask |= 1;
2348           i++;
2349         }
2350     }
2351
2352   for (xmask = 0, j = 0, regno = FIRST_OCS_EXTENDED_PRESERVE_REGISTER;
2353        regno <= LAST_OCS_EXTENDED_PRESERVE_REGISTER;
2354        regno++)
2355     {
2356       xmask <<= 1;
2357       if (save_regs[regno])
2358         {
2359           xmask |= 1;
2360           j++;
2361         }
2362     }
2363
2364   if (save_regs[1])
2365     {
2366       if ((nxregs > 0 || nregs > 2) && !save_regs[FRAME_POINTER_REGNUM])
2367         offset -= 4;
2368       return_address_info = - m88k_stack_size + offset;
2369       register_save_offset = return_address_info - i*4;
2370     }
2371   else
2372     {
2373       return_address_info = 1;
2374       register_save_offset = - m88k_stack_size + offset + 4 - i*4;
2375     }
2376
2377   xregister_save_offset = - (j * 2 + ((register_save_offset >> 2) & 1));
2378
2379   tdesc_section ();
2380
2381   /* 8:0,22:(20 or 16),2:2 */
2382   fprintf (file, "%s%d,%d", integer_asm_op (4, TRUE),
2383            (((xmask != 0) ? 20 : 16) << 2) | 2,
2384            flag_pic ? 2 : 1);
2385
2386   ASM_GENERATE_INTERNAL_LABEL (buf, OCS_START_PREFIX, m88k_function_number);
2387   fprintf (file, ",%s%s", buf+1, flag_pic ? "#rel" : "");
2388   ASM_GENERATE_INTERNAL_LABEL (buf, OCS_END_PREFIX, m88k_function_number);
2389   fprintf (file, ",%s%s", buf+1, flag_pic ? "#rel" : "");
2390
2391   fprintf (file, ",0x%x,0x%x,0x%lx,0x%lx",
2392            /* 8:1,17:0x%.3x,1:0,1:%d,5:%d */
2393            (int)(((xmask ? 3 : 1) << (17+1+1+5))
2394             | (mask << (1+1+5))
2395             | ((!!save_regs[1]) << 5)
2396             | (frame_pointer_needed
2397                ? FRAME_POINTER_REGNUM
2398                : STACK_POINTER_REGNUM)),
2399            (m88k_stack_size - (frame_pointer_needed ? m88k_fp_offset : 0)),
2400            return_address_info,
2401            register_save_offset);
2402   if (xmask)
2403     fprintf (file, ",0x%lx%04lx", xmask, (0xffff & xregister_save_offset));
2404   fputc ('\n', file);
2405
2406   text_section ();
2407 }
2408 \f
2409 /* Output assembler code to FILE to increment profiler label # LABELNO
2410    for profiling a function entry.  NAME is the mcount function name
2411    (varies), SAVEP indicates whether the parameter registers need to
2412    be saved and restored.  */
2413
2414 void
2415 output_function_profiler (file, labelno, name, savep)
2416      FILE *file;
2417      int labelno;
2418      const char *name;
2419      int savep;
2420 {
2421   char label[256];
2422   char dbi[256];
2423   const char *const temp = (savep ? reg_names[2] : reg_names[10]);
2424
2425   /* Remember to update FUNCTION_PROFILER_LENGTH.  */
2426
2427   if (savep)
2428     {
2429       fprintf (file, "\tsubu\t %s,%s,64\n", reg_names[31], reg_names[31]);
2430       fprintf (file, "\tst.d\t %s,%s,32\n", reg_names[2], reg_names[31]);
2431       fprintf (file, "\tst.d\t %s,%s,40\n", reg_names[4], reg_names[31]);
2432       fprintf (file, "\tst.d\t %s,%s,48\n", reg_names[6], reg_names[31]);
2433       fprintf (file, "\tst.d\t %s,%s,56\n", reg_names[8], reg_names[31]);
2434     }
2435
2436   ASM_GENERATE_INTERNAL_LABEL (label, "LP", labelno);
2437   if (flag_pic == 2)
2438     {
2439       fprintf (file, "\tor.u\t %s,%s,%shi16(%s#got_rel)\n",
2440                temp, reg_names[0], m88k_pound_sign, &label[1]);
2441       fprintf (file, "\tor\t %s,%s,%slo16(%s#got_rel)\n",
2442                temp, temp, m88k_pound_sign, &label[1]);
2443       sprintf (dbi, "\tld\t %s,%s,%s\n", temp,
2444                reg_names[PIC_OFFSET_TABLE_REGNUM], temp);
2445     }
2446   else if (flag_pic)
2447     {
2448       sprintf (dbi, "\tld\t %s,%s,%s#got_rel\n", temp,
2449                reg_names[PIC_OFFSET_TABLE_REGNUM], &label[1]);
2450     }
2451   else
2452     {
2453       fprintf (file, "\tor.u\t %s,%s,%shi16(%s)\n",
2454                temp, reg_names[0], m88k_pound_sign, &label[1]);
2455       sprintf (dbi, "\tor\t %s,%s,%slo16(%s)\n",
2456                temp, temp, m88k_pound_sign, &label[1]);
2457     }
2458
2459   if (flag_pic)
2460     fprintf (file, "\tbsr.n\t %s#plt\n", name);
2461   else
2462     fprintf (file, "\tbsr.n\t %s\n", name);
2463   fputs (dbi, file);
2464
2465   if (savep)
2466     {
2467       fprintf (file, "\tld.d\t %s,%s,32\n", reg_names[2], reg_names[31]);
2468       fprintf (file, "\tld.d\t %s,%s,40\n", reg_names[4], reg_names[31]);
2469       fprintf (file, "\tld.d\t %s,%s,48\n", reg_names[6], reg_names[31]);
2470       fprintf (file, "\tld.d\t %s,%s,56\n", reg_names[8], reg_names[31]);
2471       fprintf (file, "\taddu\t %s,%s,64\n", reg_names[31], reg_names[31]);
2472     }
2473 }
2474 \f
2475 /* Determine whether a function argument is passed in a register, and
2476    which register.
2477
2478    The arguments are CUM, which summarizes all the previous
2479    arguments; MODE, the machine mode of the argument; TYPE,
2480    the data type of the argument as a tree node or 0 if that is not known
2481    (which happens for C support library functions); and NAMED,
2482    which is 1 for an ordinary argument and 0 for nameless arguments that
2483    correspond to `...' in the called function's prototype.
2484
2485    The value of the expression should either be a `reg' RTX for the
2486    hard register in which to pass the argument, or zero to pass the
2487    argument on the stack.
2488
2489    On the m88000 the first eight words of args are normally in registers
2490    and the rest are pushed.  Double precision floating point must be
2491    double word aligned (and if in a register, starting on an even
2492    register). Structures and unions which are not 4 byte, and word
2493    aligned are passed in memory rather than registers, even if they
2494    would fit completely in the registers under OCS rules.
2495
2496    Note that FUNCTION_ARG and FUNCTION_INCOMING_ARG were different.
2497    For structures that are passed in memory, but could have been
2498    passed in registers, we first load the structure into the
2499    register, and then when the last argument is passed, we store
2500    the registers into the stack locations.  This fixes some bugs
2501    where GCC did not expect to have register arguments, followed
2502    by stack arguments, followed by register arguments.  */
2503
2504 struct rtx_def *
2505 m88k_function_arg (args_so_far, mode, type, named)
2506      CUMULATIVE_ARGS args_so_far;
2507      enum machine_mode mode;
2508      tree type;
2509      int named ATTRIBUTE_UNUSED;
2510 {
2511   int bytes, words;
2512
2513   if (type != 0                 /* undo putting struct in register */
2514       && (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE))
2515     mode = BLKmode;
2516
2517   if (mode == BLKmode && TARGET_WARN_PASS_STRUCT)
2518     warning ("argument #%d is a structure", args_so_far + 1);
2519
2520   if ((args_so_far & 1) != 0
2521       && (mode == DImode || mode == DFmode
2522           || (type != 0 && TYPE_ALIGN (type) > 32)))
2523     args_so_far++;
2524
2525 #ifdef ESKIT
2526   if (no_reg_params)
2527     return (rtx) 0;             /* don't put args in registers */
2528 #endif
2529
2530   if (type == 0 && mode == BLKmode)
2531     abort ();   /* m88k_function_arg argument `type' is NULL for BLKmode. */
2532
2533   bytes = (mode != BLKmode) ? GET_MODE_SIZE (mode) : int_size_in_bytes (type);
2534   words = (bytes + 3) / 4;
2535
2536   if (args_so_far + words > 8)
2537     return (rtx) 0;             /* args have exhausted registers */
2538
2539   else if (mode == BLKmode
2540            && (TYPE_ALIGN (type) != BITS_PER_WORD
2541                || bytes != UNITS_PER_WORD))
2542     return (rtx) 0;
2543
2544   return gen_rtx_REG (((mode == BLKmode) ? TYPE_MODE (type) : mode),
2545                       2 + args_so_far);
2546 }
2547 \f
2548 /* Do what is necessary for `va_start'.  We look at the current function
2549    to determine if stdargs or varargs is used and spill as necessary. 
2550    We return a pointer to the spill area.  */
2551
2552 struct rtx_def *
2553 m88k_builtin_saveregs ()
2554 {
2555   rtx addr;
2556   tree fntype = TREE_TYPE (current_function_decl);
2557   int argadj = ((!(TYPE_ARG_TYPES (fntype) != 0
2558                    && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
2559                        != void_type_node)))
2560                 ? -UNITS_PER_WORD : 0) + UNITS_PER_WORD - 1;
2561   int fixed;
2562
2563   variable_args_p = 1;
2564
2565   fixed = 0;
2566   if (GET_CODE (current_function_arg_offset_rtx) == CONST_INT)
2567     fixed = ((INTVAL (current_function_arg_offset_rtx) + argadj)
2568              / UNITS_PER_WORD);
2569
2570   /* Allocate the register space, and store it as the __va_reg member.  */
2571   addr = assign_stack_local (BLKmode, 8 * UNITS_PER_WORD, -1);
2572   set_mem_alias_set (addr, get_varargs_alias_set ());
2573   RTX_UNCHANGING_P (addr) = 1;
2574   RTX_UNCHANGING_P (XEXP (addr, 0)) = 1;
2575
2576   /* Now store the incoming registers.  */
2577   if (fixed < 8)
2578     move_block_from_reg (2 + fixed,
2579                          adjust_address (addr, Pmode, fixed * UNITS_PER_WORD),
2580                          8 - fixed,
2581                          UNITS_PER_WORD * (8 - fixed));
2582
2583   /* Return the address of the save area, but don't put it in a
2584      register.  This fails when not optimizing and produces worse code
2585      when optimizing.  */
2586   return XEXP (addr, 0);
2587 }
2588
2589 /* Define the `__builtin_va_list' type for the ABI.  */
2590
2591 tree
2592 m88k_build_va_list ()
2593 {
2594   tree field_reg, field_stk, field_arg, int_ptr_type_node, record;
2595
2596   int_ptr_type_node = build_pointer_type (integer_type_node);
2597
2598   record = make_node (RECORD_TYPE);
2599
2600   field_arg = build_decl (FIELD_DECL, get_identifier ("__va_arg"),
2601                           integer_type_node);
2602   field_stk = build_decl (FIELD_DECL, get_identifier ("__va_stk"),
2603                           int_ptr_type_node);
2604   field_reg = build_decl (FIELD_DECL, get_identifier ("__va_reg"),
2605                           int_ptr_type_node);
2606
2607   DECL_FIELD_CONTEXT (field_arg) = record;
2608   DECL_FIELD_CONTEXT (field_stk) = record;
2609   DECL_FIELD_CONTEXT (field_reg) = record;
2610
2611   TYPE_FIELDS (record) = field_arg;
2612   TREE_CHAIN (field_arg) = field_stk;
2613   TREE_CHAIN (field_stk) = field_reg;
2614
2615   layout_type (record);
2616   return record;
2617 }
2618
2619 /* Implement `va_start' for varargs and stdarg.  */
2620
2621 void
2622 m88k_va_start (stdarg_p, valist, nextarg)
2623      int stdarg_p ATTRIBUTE_UNUSED;
2624      tree valist;
2625      rtx nextarg ATTRIBUTE_UNUSED;
2626 {
2627   tree field_reg, field_stk, field_arg;
2628   tree reg, stk, arg, t;
2629
2630   field_arg = TYPE_FIELDS (va_list_type_node);
2631   field_stk = TREE_CHAIN (field_arg);
2632   field_reg = TREE_CHAIN (field_stk);
2633
2634   arg = build (COMPONENT_REF, TREE_TYPE (field_arg), valist, field_arg);
2635   stk = build (COMPONENT_REF, TREE_TYPE (field_stk), valist, field_stk);
2636   reg = build (COMPONENT_REF, TREE_TYPE (field_reg), valist, field_reg);
2637
2638   /* Fill in the ARG member.  */
2639   {
2640     tree fntype = TREE_TYPE (current_function_decl);
2641     int argadj = ((!(TYPE_ARG_TYPES (fntype) != 0
2642                      && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
2643                          != void_type_node)))
2644                   ? -UNITS_PER_WORD : 0) + UNITS_PER_WORD - 1;
2645     tree argsize;
2646
2647     if (CONSTANT_P (current_function_arg_offset_rtx))
2648       {
2649         int fixed = (INTVAL (current_function_arg_offset_rtx)
2650                      + argadj) / UNITS_PER_WORD;
2651
2652         argsize = build_int_2 (fixed, 0);
2653       }
2654     else
2655       {
2656         argsize = make_tree (integer_type_node,
2657                              current_function_arg_offset_rtx);
2658         argsize = fold (build (PLUS_EXPR, integer_type_node, argsize,
2659                                build_int_2 (argadj, 0)));
2660         argsize = fold (build (RSHIFT_EXPR, integer_type_node, argsize,
2661                                build_int_2 (2, 0)));
2662       }
2663
2664     t = build (MODIFY_EXPR, TREE_TYPE (arg), arg, argsize);
2665     TREE_SIDE_EFFECTS (t) = 1;
2666     expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
2667   }
2668
2669   /* Store the arg pointer in the __va_stk member.  */
2670   t = make_tree (TREE_TYPE (stk), virtual_incoming_args_rtx);
2671   t = build (MODIFY_EXPR, TREE_TYPE (stk), stk, t);
2672   TREE_SIDE_EFFECTS (t) = 1;
2673   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
2674
2675   /* Tuck the return value from __builtin_saveregs into __va_reg.  */
2676   t = make_tree (TREE_TYPE (reg), expand_builtin_saveregs ());
2677   t = build (MODIFY_EXPR, TREE_TYPE (reg), reg, t);
2678   TREE_SIDE_EFFECTS (t) = 1;
2679   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
2680 }
2681
2682 /* Implement `va_arg'.  */
2683
2684 rtx
2685 m88k_va_arg (valist, type)
2686      tree valist, type;
2687 {
2688   tree field_reg, field_stk, field_arg;
2689   tree reg, stk, arg, arg_align, base, t;
2690   int size, wsize, align, reg_p;
2691   rtx addr_rtx;
2692
2693   field_arg = TYPE_FIELDS (va_list_type_node);
2694   field_stk = TREE_CHAIN (field_arg);
2695   field_reg = TREE_CHAIN (field_stk);
2696
2697   arg = build (COMPONENT_REF, TREE_TYPE (field_arg), valist, field_arg);
2698   stk = build (COMPONENT_REF, TREE_TYPE (field_stk), valist, field_stk);
2699   reg = build (COMPONENT_REF, TREE_TYPE (field_reg), valist, field_reg);
2700
2701   size = int_size_in_bytes (type);
2702   wsize = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
2703   align = 1 << ((TYPE_ALIGN (type) / BITS_PER_UNIT) >> 3);
2704   reg_p = (AGGREGATE_TYPE_P (type)
2705            ? size == UNITS_PER_WORD && TYPE_ALIGN (type) == BITS_PER_WORD
2706            : size <= 2*UNITS_PER_WORD);
2707
2708   /* Align __va_arg to the (doubleword?) boundary above.  */
2709   t = build (PLUS_EXPR, TREE_TYPE (arg), arg, build_int_2 (align - 1, 0));
2710   arg_align = build (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-align, -1));
2711   arg_align = save_expr (arg_align);
2712
2713   /* Decide if we should read from stack or regs.  */
2714   t = build (LT_EXPR, integer_type_node, arg_align, build_int_2 (8, 0));
2715   base = build (COND_EXPR, TREE_TYPE (reg), t, reg, stk);
2716
2717   /* Find the final address.  */
2718   t = build (PLUS_EXPR, TREE_TYPE (base), base, arg_align);
2719   addr_rtx = expand_expr (t, NULL_RTX, Pmode, EXPAND_NORMAL);
2720   addr_rtx = copy_to_reg (addr_rtx);
2721
2722   /* Increment __va_arg.  */
2723   t = build (PLUS_EXPR, TREE_TYPE (arg), arg_align, build_int_2 (wsize, 0));
2724   t = build (MODIFY_EXPR, TREE_TYPE (arg), arg, t);
2725   TREE_SIDE_EFFECTS (t) = 1;
2726   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
2727
2728   return addr_rtx;
2729 }
2730 \f
2731 /* If cmpsi has not been generated, emit code to do the test.  Return the
2732    expression describing the test of operator OP.  */
2733
2734 rtx
2735 emit_test (op, mode)
2736      enum rtx_code op;
2737      enum machine_mode mode;
2738 {
2739   if (m88k_compare_reg == 0)
2740     emit_insn (gen_test (m88k_compare_op0, m88k_compare_op1));
2741   return (gen_rtx (op, mode, m88k_compare_reg, const0_rtx));
2742 }
2743
2744 /* Determine how to best perform cmpsi/bxx, where cmpsi has a constant
2745    operand.  All tests with zero (albeit swapped) and all equality tests
2746    with a constant are done with bcnd.  The remaining cases are swapped
2747    as needed.  */
2748
2749 void
2750 emit_bcnd (op, label)
2751      enum rtx_code op;
2752      rtx label;
2753 {
2754   if (m88k_compare_op1 == const0_rtx)
2755     emit_jump_insn (gen_bcnd
2756                     (gen_rtx (op, VOIDmode,m88k_compare_op0, const0_rtx),
2757                      label));
2758   else if (m88k_compare_op0 == const0_rtx)
2759     emit_jump_insn (gen_bcnd
2760                     (gen_rtx (swap_condition (op),
2761                               VOIDmode, m88k_compare_op1, const0_rtx),
2762                      label));
2763   else if (op != EQ && op != NE)
2764     emit_jump_insn (gen_bxx (emit_test (op, VOIDmode), label));
2765   else
2766     {
2767       rtx zero = gen_reg_rtx (SImode);
2768       rtx reg, constant;
2769       int value;
2770
2771       if (GET_CODE (m88k_compare_op1) == CONST_INT)
2772         {
2773           reg = force_reg (SImode, m88k_compare_op0);
2774           constant = m88k_compare_op1;
2775         }
2776       else
2777         {
2778           reg = force_reg (SImode, m88k_compare_op1);
2779           constant = m88k_compare_op0;
2780         }
2781       value = INTVAL (constant);
2782
2783       /* Perform an arithmetic computation to make the compared-to value
2784          zero, but avoid loosing if the bcnd is later changed into sxx.  */
2785       if (SMALL_INTVAL (value))
2786         emit_jump_insn (gen_bxx (emit_test (op, VOIDmode), label));
2787       else
2788         {
2789           if (SMALL_INTVAL (-value))
2790             emit_insn (gen_addsi3 (zero, reg,
2791                                    GEN_INT (-value)));
2792           else
2793             emit_insn (gen_xorsi3 (zero, reg, constant));
2794
2795           emit_jump_insn (gen_bcnd (gen_rtx (op, VOIDmode,
2796                                              zero, const0_rtx),
2797                                     label));
2798         }
2799     }
2800 }
2801 \f
2802 /* Print an operand.  Recognize special options, documented below.  */
2803
2804 void
2805 print_operand (file, x, code)
2806     FILE *file;
2807     rtx x;
2808     int code;
2809 {
2810   enum rtx_code xc = (x ? GET_CODE (x) : UNKNOWN);
2811   register int value = (xc == CONST_INT ? INTVAL (x) : 0);
2812   static int sequencep;
2813   static int reversep;
2814
2815   if (sequencep)
2816     {
2817       if (code < 'B' || code > 'E')
2818         output_operand_lossage ("%%R not followed by %%B/C/D/E");
2819       if (reversep)
2820         xc = reverse_condition (xc);
2821       sequencep = 0;
2822     }
2823
2824   switch (code)
2825     {
2826     case '*': /* addressing base register for PIC */
2827       fputs (reg_names[PIC_OFFSET_TABLE_REGNUM], file); return;
2828
2829     case '#': /* SVR4 pound-sign syntax character (empty if SVR3) */
2830       fputs (m88k_pound_sign, file); return;
2831
2832     case 'V': /* Output a serializing instruction as needed if the operand
2833                  (assumed to be a MEM) is a volatile load.  */
2834     case 'v': /* ditto for a volatile store.  */
2835       if (MEM_VOLATILE_P (x) && TARGET_SERIALIZE_VOLATILE)
2836         {
2837           /* The m88110 implements two FIFO queues, one for loads and
2838              one for stores.  These queues mean that loads complete in
2839              their issue order as do stores.  An interaction between the
2840              history buffer and the store reservation station ensures
2841              that a store will not bypass load.  Finally, a load will not
2842              bypass store, but only when they reference the same address.
2843
2844              To avoid this reordering (a load bypassing a store) for
2845              volatile references, a serializing instruction is output.
2846              We choose the fldcr instruction as it does not serialize on
2847              the m88100 so that -m88000 code will not be degraded.
2848
2849              The mechanism below is completed by having CC_STATUS_INIT set
2850              the code to the unknown value.  */
2851
2852           /*
2853              hassey 6/30/93
2854              A problem with 88110 4.1 & 4.2 makes the use of fldcr for
2855              this purpose undesirable.  Instead we will use tb1, this will
2856              cause serialization on the 88100 but such is life.
2857           */
2858
2859           static rtx last_addr = 0;
2860           if (code == 'V' /* Only need to serialize before a load.  */
2861               && m88k_volatile_code != 'V' /* Loads complete in FIFO order.  */
2862               && !(m88k_volatile_code == 'v'
2863                    && GET_CODE (XEXP (x, 0)) == LO_SUM
2864                    && rtx_equal_p (XEXP (XEXP (x, 0), 1), last_addr)))
2865             fprintf (file,
2866 #if 0
2867 #ifdef AS_BUG_FLDCR
2868                      "fldcr\t %s,%scr63\n\t",
2869 #else
2870                      "fldcr\t %s,%sfcr63\n\t",
2871 #endif
2872                      reg_names[0], m88k_pound_sign);
2873 #else /* 0 */
2874                      "tb1\t 1,%s,0xff\n\t", reg_names[0]);
2875 #endif /* 0 */
2876           m88k_volatile_code = code;
2877           last_addr = (GET_CODE (XEXP (x, 0)) == LO_SUM
2878                        ? XEXP (XEXP (x, 0), 1) : 0);
2879         }
2880       return;
2881
2882     case 'X': /* print the upper 16 bits... */
2883       value >>= 16;
2884     case 'x': /* print the lower 16 bits of the integer constant in hex */
2885       if (xc != CONST_INT)
2886         output_operand_lossage ("invalid %%x/X value");
2887       fprintf (file, "0x%x", value & 0xffff); return;
2888
2889     case 'H': /* print the low 16 bits of the negated integer constant */
2890       if (xc != CONST_INT)
2891         output_operand_lossage ("invalid %%H value");
2892       value = -value;
2893     case 'h': /* print the register or low 16 bits of the integer constant */
2894       if (xc == REG)
2895         goto reg;
2896       if (xc != CONST_INT)
2897         output_operand_lossage ("invalid %%h value");
2898       fprintf (file, "%d", value & 0xffff);
2899       return;
2900
2901     case 'Q': /* print the low 8 bits of the negated integer constant */
2902       if (xc != CONST_INT)
2903         output_operand_lossage ("invalid %%Q value");
2904       value = -value;
2905     case 'q': /* print the register or low 8 bits of the integer constant */
2906       if (xc == REG)
2907         goto reg;
2908       if (xc != CONST_INT)
2909         output_operand_lossage ("invalid %%q value");
2910       fprintf (file, "%d", value & 0xff);
2911       return;
2912
2913     case 'w': /* print the integer constant (X == 32 ? 0 : 32 - X) */
2914       if (xc != CONST_INT)
2915         output_operand_lossage ("invalid %%o value");
2916       fprintf (file, "%d", value == 32 ? 0 : 32 - value);
2917       return;
2918
2919     case 'p': /* print the logarithm of the integer constant */
2920       if (xc != CONST_INT
2921           || (value = exact_log2 (value)) < 0)
2922         output_operand_lossage ("invalid %%p value");
2923       fprintf (file, "%d", value);
2924       return;
2925
2926     case 'S': /* compliment the value and then... */
2927       value = ~value;
2928     case 's': /* print the width and offset values forming the integer
2929                  constant with a SET instruction.  See integer_ok_for_set. */
2930       {
2931         register unsigned mask, uval = value;
2932         register int top, bottom;
2933
2934         if (xc != CONST_INT)
2935           output_operand_lossage ("invalid %%s/S value");
2936         /* All the "one" bits must be contiguous.  If so, MASK will be
2937            a power of two or zero.  */
2938         mask = (uval | (uval - 1)) + 1;
2939         if (!(uval && POWER_OF_2_or_0 (mask)))
2940           output_operand_lossage ("invalid %%s/S value");
2941         top = mask ? exact_log2 (mask) : 32;
2942         bottom = exact_log2 (uval & ~(uval - 1));
2943         fprintf (file,"%d<%d>", top - bottom, bottom);
2944         return;
2945       }
2946
2947     case 'P': /* print nothing if pc_rtx; output label_ref */
2948       if (xc == LABEL_REF)
2949         output_addr_const (file, x);
2950       else if (xc != PC)
2951         output_operand_lossage ("invalid %%P operand");
2952       return;
2953
2954     case 'L': /* print 0 or 1 if operand is label_ref and then...  */
2955       fputc (xc == LABEL_REF ? '1' : '0', file);
2956     case '.': /* print .n if delay slot is used */
2957       fputs ((final_sequence
2958               && ! INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0)))
2959              ? ".n\t" : "\t", file);
2960       return;
2961
2962     case '!': /* Reverse the following condition. */
2963       sequencep++;
2964       reversep = 1;
2965       return; 
2966     case 'R': /* reverse the condition of the next print_operand
2967                  if operand is a label_ref.  */
2968       sequencep++;
2969       reversep = (xc == LABEL_REF);
2970       return;
2971
2972     case 'B': /* bcnd branch values */
2973       fputs (m88k_pound_sign, file);
2974       switch (xc)
2975         {
2976         case EQ: fputs ("eq0", file); return;
2977         case NE: fputs ("ne0", file); return;
2978         case GT: fputs ("gt0", file); return;
2979         case LE: fputs ("le0", file); return;
2980         case LT: fputs ("lt0", file); return;
2981         case GE: fputs ("ge0", file); return;
2982         default: output_operand_lossage ("invalid %%B value");
2983         }
2984
2985     case 'C': /* bb0/bb1 branch values for comparisons */
2986       fputs (m88k_pound_sign, file);
2987       switch (xc)
2988         {
2989         case EQ:  fputs ("eq", file); return;
2990         case NE:  fputs ("ne", file); return;
2991         case GT:  fputs ("gt", file); return;
2992         case LE:  fputs ("le", file); return;
2993         case LT:  fputs ("lt", file); return;
2994         case GE:  fputs ("ge", file); return;
2995         case GTU: fputs ("hi", file); return;
2996         case LEU: fputs ("ls", file); return;
2997         case LTU: fputs ("lo", file); return;
2998         case GEU: fputs ("hs", file); return;
2999         default:  output_operand_lossage ("invalid %%C value");
3000         }
3001
3002     case 'D': /* bcnd branch values for float comparisons */
3003       switch (xc)
3004         {
3005         case EQ: fputs ("0xa", file); return;
3006         case NE: fputs ("0x5", file); return;
3007         case GT: fputs (m88k_pound_sign, file);
3008           fputs ("gt0", file); return;
3009         case LE: fputs ("0xe", file); return;
3010         case LT: fputs ("0x4", file); return;
3011         case GE: fputs ("0xb", file); return;
3012         default: output_operand_lossage ("invalid %%D value");
3013         }
3014
3015     case 'E': /* bcnd branch values for special integers */
3016       switch (xc)
3017         {
3018         case EQ: fputs ("0x8", file); return;
3019         case NE: fputs ("0x7", file); return;
3020         default: output_operand_lossage ("invalid %%E value");
3021         }
3022
3023     case 'd': /* second register of a two register pair */
3024       if (xc != REG)
3025         output_operand_lossage ("`%%d' operand isn't a register");
3026       fputs (reg_names[REGNO (x) + 1], file);
3027       return;
3028
3029     case 'r': /* an immediate 0 should be represented as `r0' */
3030       if (x == const0_rtx)
3031         {
3032           fputs (reg_names[0], file);
3033           return;
3034         }
3035       else if (xc != REG)
3036         output_operand_lossage ("invalid %%r value");
3037     case 0:
3038     name:
3039       if (xc == REG)
3040         {
3041         reg:
3042           if (REGNO (x) == ARG_POINTER_REGNUM)
3043             output_operand_lossage ("operand is r0");
3044           else
3045             fputs (reg_names[REGNO (x)], file);
3046         }
3047       else if (xc == PLUS)
3048         output_address (x);
3049       else if (xc == MEM)
3050         output_address (XEXP (x, 0));
3051       else if (flag_pic && xc == UNSPEC)
3052         {
3053           output_addr_const (file, XVECEXP (x, 0, 0));
3054           fputs ("#got_rel", file);
3055         }
3056       else if (xc == CONST_DOUBLE)
3057         output_operand_lossage ("operand is const_double");
3058       else
3059         output_addr_const (file, x);
3060       return;
3061
3062     case 'g': /* append #got_rel as needed */
3063       if (flag_pic && (xc == SYMBOL_REF || xc == LABEL_REF))
3064         {
3065           output_addr_const (file, x);
3066           fputs ("#got_rel", file);
3067           return;
3068         }
3069       goto name;
3070
3071     case 'a': /* (standard), assume operand is an address */
3072     case 'c': /* (standard), assume operand is an immediate value */
3073     case 'l': /* (standard), assume operand is a label_ref */
3074     case 'n': /* (standard), like %c, except negate first */
3075     default:
3076       output_operand_lossage ("invalid code");
3077     }
3078 }
3079
3080 void
3081 print_operand_address (file, addr)
3082     FILE *file;
3083     rtx addr;
3084 {
3085   register rtx reg0, reg1, temp;
3086
3087   switch (GET_CODE (addr))
3088     {
3089     case REG:
3090       if (REGNO (addr) == ARG_POINTER_REGNUM)
3091         abort ();
3092       else
3093         fprintf (file, "%s,%s", reg_names[0], reg_names [REGNO (addr)]);
3094       break;
3095
3096     case LO_SUM:
3097       fprintf (file, "%s,%slo16(",
3098                reg_names[REGNO (XEXP (addr, 0))], m88k_pound_sign);
3099       output_addr_const (file, XEXP (addr, 1));
3100       fputc (')', file);
3101       break;
3102
3103     case PLUS:
3104       reg0 = XEXP (addr, 0);
3105       reg1 = XEXP (addr, 1);
3106       if (GET_CODE (reg0) == MULT || GET_CODE (reg0) == CONST_INT)
3107         {
3108           rtx tmp = reg0;
3109           reg0 = reg1;
3110           reg1 = tmp;
3111         }
3112
3113       if ((REG_P (reg0) && REGNO (reg0) == ARG_POINTER_REGNUM)
3114           || (REG_P (reg1) && REGNO (reg1) == ARG_POINTER_REGNUM))
3115         abort ();
3116
3117       else if (REG_P (reg0))
3118         {
3119           if (REG_P (reg1))
3120             fprintf (file, "%s,%s",
3121                      reg_names [REGNO (reg0)], reg_names [REGNO (reg1)]);
3122
3123           else if (GET_CODE (reg1) == CONST_INT)
3124             fprintf (file, "%s,%d",
3125                      reg_names [REGNO (reg0)], INTVAL (reg1));
3126
3127           else if (GET_CODE (reg1) == MULT)
3128             {
3129               rtx mreg = XEXP (reg1, 0);
3130               if (REGNO (mreg) == ARG_POINTER_REGNUM)
3131                 abort ();
3132
3133               fprintf (file, "%s[%s]", reg_names[REGNO (reg0)],
3134                        reg_names[REGNO (mreg)]);
3135             }
3136
3137           else if (GET_CODE (reg1) == ZERO_EXTRACT)
3138             {
3139               fprintf (file, "%s,%slo16(",
3140                        reg_names[REGNO (reg0)], m88k_pound_sign);
3141               output_addr_const (file, XEXP (reg1, 0));
3142               fputc (')', file);
3143             }
3144
3145           else if (flag_pic)
3146             {
3147               fprintf (file, "%s,", reg_names[REGNO (reg0)]);
3148               output_addr_const (file, reg1);
3149               fputs ("#got_rel", file);
3150             }
3151           else abort ();
3152         }
3153
3154       else
3155         abort ();
3156       break;
3157
3158     case MULT:
3159       if (REGNO (XEXP (addr, 0)) == ARG_POINTER_REGNUM)
3160         abort ();
3161
3162       fprintf (file, "%s[%s]",
3163                reg_names[0], reg_names[REGNO (XEXP (addr, 0))]);
3164       break;
3165
3166     case CONST_INT:
3167       fprintf (file, "%s,%d", reg_names[0], INTVAL (addr));
3168       break;
3169
3170     default:
3171       fprintf (file, "%s,", reg_names[0]);
3172       if (SHORT_ADDRESS_P (addr, temp))
3173         {
3174           fprintf (file, "%siw16(", m88k_pound_sign);
3175           output_addr_const (file, addr);
3176           fputc (')', file);
3177         }
3178       else
3179           output_addr_const (file, addr);
3180     }
3181 }
3182
3183 /* Return true if X is an address which needs a temporary register when 
3184    reloaded while generating PIC code.  */
3185
3186 int
3187 pic_address_needs_scratch (x)
3188      rtx x;
3189 {
3190   /* An address which is a symbolic plus a non SMALL_INT needs a temp reg.  */
3191   if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
3192       && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
3193       && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
3194       && ! ADD_INT (XEXP (XEXP (x, 0), 1)))
3195     return 1;
3196
3197   return 0;
3198 }
3199
3200 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
3201    reference and a constant.  */
3202
3203 int
3204 symbolic_operand (op, mode)
3205      register rtx op;
3206      enum machine_mode mode;
3207 {
3208   switch (GET_CODE (op))
3209     {
3210     case SYMBOL_REF:
3211     case LABEL_REF:
3212       return 1;
3213
3214     case CONST:
3215       op = XEXP (op, 0);
3216       return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
3217                || GET_CODE (XEXP (op, 0)) == LABEL_REF)
3218               && GET_CODE (XEXP (op, 1)) == CONST_INT);
3219
3220       /* ??? This clause seems to be irrelevant.  */
3221     case CONST_DOUBLE:
3222       return GET_MODE (op) == mode;
3223
3224     default:
3225       return 0;
3226     }
3227 }
3228
3229 #if defined (CTOR_LIST_BEGIN) && !defined (OBJECT_FORMAT_ELF)
3230 static void
3231 m88k_svr3_asm_out_constructor (symbol, priority)
3232      rtx symbol;
3233      int priority ATTRIBUTE_UNUSED;
3234 {
3235   const char *name = XSTR (symbol, 0);
3236
3237   init_section ();
3238   fprintf (asm_out_file, "\tor.u\t r13,r0,hi16(");
3239   assemble_name (asm_out_file, name);
3240   fprintf (asm_out_file, ")\n\tor\t r13,r13,lo16(");
3241   assemble_name (asm_out_file, name);
3242   fprintf (asm_out_file, ")\n\tsubu\t r31,r31,%d\n\tst\t r13,r31,%d\n",
3243            STACK_BOUNDARY / BITS_PER_UNIT, REG_PARM_STACK_SPACE (0));
3244 }
3245
3246 static void
3247 m88k_svr3_asm_out_destructor (symbol, priority)
3248      rtx symbol;
3249      int priority ATTRIBUTE_UNUSED;
3250 {
3251   int i;
3252
3253   fini_section ();
3254   assemble_integer (symbol, UNITS_PER_WORD, BITS_PER_WORD, 1);
3255   for (i = 1; i < 4; i++)
3256     assemble_integer (constm1_rtx, UNITS_PER_WORD, BITS_PER_WORD, 1);
3257 }
3258 #endif /* INIT_SECTION_ASM_OP && ! OBJECT_FORMAT_ELF */
3259
3260 static void
3261 m88k_select_section (decl, reloc, align)
3262      tree decl;
3263      int reloc;
3264      unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED;
3265 {
3266   if (TREE_CODE (decl) == STRING_CST)
3267     {
3268       if (! flag_writable_strings)
3269         readonly_data_section ();
3270       else if (TREE_STRING_LENGTH (decl) <= m88k_gp_threshold)
3271         sdata_section ();
3272       else
3273         data_section ();
3274     }
3275   else if (TREE_CODE (decl) == VAR_DECL)
3276     {
3277       if (SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)))
3278         sdata_section ();
3279       else if ((flag_pic && reloc)
3280                || !TREE_READONLY (decl) || TREE_SIDE_EFFECTS (decl)
3281                || !DECL_INITIAL (decl)
3282                || (DECL_INITIAL (decl) != error_mark_node
3283                    && !TREE_CONSTANT (DECL_INITIAL (decl))))
3284         data_section ();
3285       else
3286         readonly_data_section ();
3287     }
3288   else
3289     readonly_data_section ();
3290 }
3291
3292 /* Adjust the cost of INSN based on the relationship between INSN that
3293    is dependent on DEP_INSN through the dependence LINK.  The default
3294    is to make no adjustment to COST.
3295
3296    On the m88k, ignore the cost of anti- and output-dependencies.  On
3297    the m88100, a store can issue two cycles before the value (not the
3298    address) has finished computing.  */
3299
3300 static int
3301 m88k_adjust_cost (insn, link, dep, cost)
3302      rtx insn;
3303      rtx link;
3304      rtx dep;
3305      int cost;
3306 {
3307   if (REG_NOTE_KIND (link) != 0)
3308     return 0;  /* Anti or output dependence.  */
3309
3310   if (! TARGET_88100
3311       && recog_memoized (insn) >= 0
3312       && get_attr_type (insn) == TYPE_STORE
3313       && SET_SRC (PATTERN (insn)) == SET_DEST (PATTERN (dep)))
3314     return cost - 4;  /* 88110 store reservation station.  */
3315
3316   return cost;
3317 }
3318
3319 /* For the m88k, determine if the item should go in the global pool.  */
3320
3321 static void
3322 m88k_encode_section_info (decl, first)
3323      tree decl;
3324      int first ATTRIBUTE_UNUSED;
3325 {
3326   if (m88k_gp_threshold > 0)
3327     {
3328       if (TREE_CODE (decl) == VAR_DECL)
3329         {
3330           if (!TREE_READONLY (decl) || TREE_SIDE_EFFECTS (decl))
3331             {
3332               int size = int_size_in_bytes (TREE_TYPE (decl));
3333
3334               if (size > 0 && size <= m88k_gp_threshold)
3335                 SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
3336             }
3337         }
3338       else if (TREE_CODE (decl) == STRING_CST
3339                && flag_writable_strings
3340                && TREE_STRING_LENGTH (decl) <= m88k_gp_threshold)
3341         SYMBOL_REF_FLAG (XEXP (TREE_CST_RTL (decl), 0)) = 1;
3342     }
3343 }