OSDN Git Service

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