OSDN Git Service

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