OSDN Git Service

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