OSDN Git Service

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