OSDN Git Service

*** empty log message ***
[pf3gnuchains/gcc-fork.git] / gcc / config / m88k / m88k.c
1 /* Subroutines for insn-output.c for Motorola 88000.
2    Copyright (C) 1988, 1989, 1990, 1991 Free Software Foundation, Inc.
3    Contributed by Michael Tiemann (tiemann@mcc.com)
4    Enhanced by Michael Meissner (meissner@osf.org)
5    Currently supported by Tom Wood (wood@dg-rtp.dg.com)
6
7 This file is part of GNU CC.
8
9 GNU CC is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
13
14 GNU CC is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with GNU CC; see the file COPYING.  If not, write to
21 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
22
23 #include <stdio.h>
24 #include <sys/types.h>
25 #include <time.h>
26 #include <ctype.h>
27
28 #include "config.h"
29 #include "rtl.h"
30 #include "regs.h"
31 #include "hard-reg-set.h"
32 #include "real.h"
33 #include "insn-config.h"
34 #include "conditions.h"
35 #include "insn-flags.h"
36 #include "output.h"
37 #include "insn-attr.h"
38 #include "tree.h"
39 #include "c-tree.h"
40 #include "expr.h"
41 #include "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.1.3.1 07 Apr 1992 17:23:59";
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
722       /* This can be generalized, but there is currently no need.  */
723       if (XVECLEN (final_sequence, 0) != 2)
724         abort ();
725
726       jump = XVECEXP (final_sequence, 0, 1);
727       if (GET_CODE (jump) == JUMP_INSN)
728         {
729           rtx low, high;
730           char *last;
731           rtx dest = XEXP (SET_SRC (PATTERN (jump)), 0);
732           int delta = 4 * (insn_addresses[INSN_UID (dest)]
733                            - insn_addresses[INSN_UID (jump)]);
734 #if (MONITOR_GCC & 0x2) /* How often do long branches happen?  */
735           if ((unsigned) (delta + 0x8000) >= 0x10000)
736             warning ("Internal gcc monitor: short-branch(%x)", delta);
737 #endif
738
739           /* Delete the jump.  */
740           PUT_CODE (jump, NOTE);
741           NOTE_LINE_NUMBER (jump) = NOTE_INSN_DELETED;
742           NOTE_SOURCE_FILE (jump) = 0;
743
744           /* If we loose, we must use the non-delay form.  This is unlikely
745              to ever happen.  If it becomes a problem, claim that a call
746              has two delay slots and only the second can be filled with
747              a jump.  */
748 #ifdef AS_BUG_IMMEDIATE_LABEL /* The assembler restricts immediate values.  */
749           if (! ADD_INTVAL (delta * 2))
750 #else
751           if (! ADD_INTVAL (delta))
752 #endif
753             {
754               operands[1] = dest;
755               return (REG_P (addr)
756                       ? "jsr %0\n\tbr %l1"
757                       : (flag_pic
758                          ? "bsr %0#plt\n\tbr %l1"
759                          : "bsr %0\n\tbr %l1"));
760             }
761
762           /* Output the short branch form.  */
763           output_asm_insn ((REG_P (addr)
764                             ? "jsr.n %0"
765                             : (flag_pic ? "bsr.n %0#plt" : "bsr.n %0")),
766                            operands);
767
768           operands[0] = gen_label_rtx ();
769           operands[1] = gen_label_rtx ();
770           if (delta < 0)
771             {
772               low = dest;
773               high = operands[1];
774               last = "subu %#r1,%#r1,%l0\n%l1:";
775             }
776           else
777             {
778               low = operands[1];
779               high = dest;
780               last = "addu %#r1,%#r1,%l0\n%l1:";
781             }
782
783           /* Record the values to be computed later as "def name,high-low".  */
784           sb_name = gen_rtx (EXPR_LIST, VOIDmode, operands[0], sb_name);
785           sb_high = gen_rtx (EXPR_LIST, VOIDmode, high, sb_high);
786           sb_low = gen_rtx (EXPR_LIST, VOIDmode, low, sb_low);
787
788           return last;
789         }
790     }
791   return (REG_P (addr)
792           ? "jsr%. %0"
793           : (flag_pic ? "bsr%. %0#plt" : "bsr%. %0"));
794 }
795
796 static void
797 output_short_branch_defs (stream)
798      FILE *stream;
799 {
800   char name[256], high[256], low[256];
801
802   for (; sb_name && sb_high && sb_low;
803        sb_name = XEXP (sb_name, 1),
804        sb_high = XEXP (sb_high, 1),
805        sb_low = XEXP (sb_low, 1))
806     {
807       ASM_GENERATE_INTERNAL_LABEL
808         (name, "L", CODE_LABEL_NUMBER (XEXP (sb_name, 0)));
809       ASM_GENERATE_INTERNAL_LABEL
810         (high, "L", CODE_LABEL_NUMBER (XEXP (sb_high, 0)));
811       ASM_GENERATE_INTERNAL_LABEL
812         (low, "L", CODE_LABEL_NUMBER (XEXP (sb_low, 0)));
813       /* This will change as the assembler requirements become known.  */
814       fprintf (stream, "\t%s\t %s,%s-%s\n",
815                DEF_ASM_OP, &name[1], &high[1], &low[1]);
816     }
817   if (sb_name || sb_high || sb_low)
818     abort ();
819 }
820 \f
821 /* Report errors on floating point, if we are given NaN's, or such.  Leave
822    the number as is, though, since we output the number in hex, and the
823    assembler won't choke on it.  */
824
825 void
826 check_float_value (mode, value)
827      enum machine_mode mode;
828      REAL_VALUE_TYPE value;
829 {
830   union {
831     REAL_VALUE_TYPE d;
832     struct {
833       unsigned sign         :  1;
834       unsigned exponent  : 11;
835       unsigned mantissa1 : 20;
836       unsigned mantissa2;
837     } s;
838   } u;
839
840   if (mode == DFmode)
841     {
842       u.d = value;
843       if (u.s.mantissa1 != 0 || u.s.mantissa2 != 0)
844         {
845           if (u.s.exponent == 0x7ff)    /* Not a Number */
846             warning ("floating point number is not valid for IEEE double precision");
847           else if (u.s.exponent == 0)
848             warning ("denormalized double precision floating point number");
849         }
850     }
851   else if (mode == SFmode)
852     {
853       u.d = REAL_VALUE_TRUNCATE (mode, value);
854       if (u.s.mantissa1 != 0 || u.s.mantissa2 != 0)
855         {
856           if (u.s.exponent == 0x7ff)    /* Not a Number */
857             warning ("floating point number is not valid for IEEE double precision");
858           else if (u.s.exponent == 0)
859             warning ("denormalized single precision floating point number");
860         }
861       else if (u.s.exponent == 0x7ff)   /* Infinity */
862         warning ("floating point number exceeds range of `float'");
863     }
864 }
865 \f
866 /* Return true if the operand is a power of two and is a floating
867    point type (to optimize division by power of two into multiplication).  */
868
869 int
870 real_power_of_2_operand (op, mode)
871      rtx op;
872      enum machine_mode mode;
873 {
874   union {
875     REAL_VALUE_TYPE d;
876     int i[sizeof (REAL_VALUE_TYPE) / sizeof (int)];
877     struct {                            /* IEEE double precision format */
878       unsigned sign      :  1;
879       unsigned exponent  : 11;
880       unsigned mantissa1 : 20;
881       unsigned mantissa2;
882     } s;
883     struct {                            /* IEEE double format to quick check */
884       unsigned sign      :  1;          /* if it fits in a float */
885       unsigned exponent1 :  4;
886       unsigned exponent2 :  7;
887       unsigned mantissa1 : 20;
888       unsigned mantissa2;
889     } s2;
890   } u;
891
892   if (GET_MODE (op) != DFmode && GET_MODE (op) != SFmode)
893     return 0;
894
895   if (GET_CODE (op) != CONST_DOUBLE)
896     return 0;
897
898   u.i[0] = CONST_DOUBLE_LOW  (op);
899   u.i[1] = CONST_DOUBLE_HIGH (op);
900
901   if (u.s.mantissa1 != 0 || u.s.mantissa2 != 0  /* not a power of two */
902       || u.s.exponent == 0                      /* constant 0.0 */
903       || u.s.exponent == 0x7ff                  /* NAN */
904       || (u.s2.exponent1 != 0x8 && u.s2.exponent1 != 0x7))
905     return 0;                                   /* const won't fit in float */
906
907   return 1;
908 }
909 \f
910 /* Make OP legitimate for mode MODE.  Currently this only deals with DFmode
911    operands, putting them in registers and making CONST_DOUBLE values
912    SFmode where possible.  */
913
914 struct rtx_def *
915 legitimize_operand (op, mode)
916      rtx op;
917      enum machine_mode mode;
918 {
919   rtx temp;
920   union {
921     union real_extract r;
922     struct {                            /* IEEE double precision format */
923       unsigned sign      :  1;
924       unsigned exponent  : 11;
925       unsigned mantissa1 : 20;
926       unsigned mantissa2;
927     } d;
928     struct {                            /* IEEE double format to quick check */
929       unsigned sign      :  1;          /* if it fits in a float */
930       unsigned exponent1 :  4;
931       unsigned exponent2 :  7;
932       unsigned mantissa1 : 20;
933       unsigned mantissa2;
934     } s;
935   } u;
936
937   if (GET_CODE (op) == REG || mode != DFmode)
938     return op;
939
940   if (GET_CODE (op) == CONST_DOUBLE)
941     {
942       bcopy (&CONST_DOUBLE_LOW (op), &u.r, sizeof u);
943       if (u.d.exponent != 0x7ff /* NaN */
944           && u.d.mantissa2 == 0 /* Mantissa fits */
945           && (u.s.exponent1 == 0x8 || u.s.exponent1 == 0x7) /* Exponent fits */
946           && (temp = simplify_unary_operation (FLOAT_TRUNCATE, SFmode,
947                                                op, mode)) != 0)
948         return gen_rtx (FLOAT_EXTEND, mode, force_reg (SFmode, temp));
949     }
950   else if (register_operand (op, mode))
951     return op;
952
953   return force_reg (mode, op);
954 }
955 \f
956 /* Return true if OP is a suitable input for a move insn.  */
957
958 int
959 move_operand (op, mode)
960      rtx op;
961      enum machine_mode mode;
962 {
963   if (register_operand (op, mode))
964     return 1;
965   if (GET_CODE (op) == CONST_INT)
966     return (classify_integer (mode, INTVAL (op)) < m88k_oru_hi16);
967   if (GET_MODE (op) != mode)
968     return 0;
969   if (GET_CODE (op) == SUBREG)
970     op = SUBREG_REG (op);
971   if (GET_CODE (op) != MEM)
972     return 0;
973
974   op = XEXP (op, 0);
975   if (GET_CODE (op) == LO_SUM)
976     return (REG_P (XEXP (op, 0))
977             && symbolic_address_p (XEXP (op, 1)));
978   return memory_address_p (mode, op);
979 }
980
981 /* Return true if OP is suitable for a call insn.  */
982
983 int
984 call_address_operand (op, mode)
985      rtx op;
986      enum machine_mode mode;
987 {
988   return (REG_P (op) || symbolic_address_p (op));
989 }
990
991 /* Returns true if OP is either a symbol reference or a sum of a symbol
992    reference and a constant.  */
993
994 int
995 symbolic_address_p (op)
996      register rtx op;
997 {
998   switch (GET_CODE (op))
999     {
1000     case SYMBOL_REF:
1001     case LABEL_REF:
1002       return 1;
1003
1004     case CONST:
1005       op = XEXP (op, 0);
1006       return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1007                || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1008               && GET_CODE (XEXP (op, 1)) == CONST_INT);
1009
1010     default:
1011       return 0;
1012     }
1013 }
1014
1015 /* Return true if OP is a register or const0_rtx.  */
1016
1017 int
1018 reg_or_0_operand (op, mode)
1019      rtx op;
1020      enum machine_mode mode;
1021 {
1022   return (op == const0_rtx || register_operand (op, mode));
1023 }
1024
1025 /* Nonzero if OP is a valid second operand for an arithmetic insn.  */
1026
1027 int
1028 arith_operand (op, mode)
1029      rtx op;
1030      enum machine_mode mode;
1031 {
1032   return (register_operand (op, mode)
1033           || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));
1034 }
1035
1036 /* Return true if OP is a  register or 5 bit integer.  */
1037
1038 int
1039 arith5_operand (op, mode)
1040      rtx op;
1041      enum machine_mode mode;
1042 {
1043   return (register_operand (op, mode)
1044           || (GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 32));
1045 }
1046
1047 int
1048 arith32_operand (op, mode)
1049      rtx op;
1050      enum machine_mode mode;
1051 {
1052   return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
1053 }
1054
1055 int
1056 arith64_operand (op, mode)
1057      rtx op;
1058      enum machine_mode mode;
1059 {
1060   return (register_operand (op, mode)
1061           || GET_CODE (op) == CONST_INT
1062           || (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DImode));
1063 }
1064
1065 int
1066 int5_operand (op, mode)
1067      rtx op;
1068      enum machine_mode mode;
1069 {
1070   return (GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 32);
1071 }
1072
1073 int
1074 int32_operand (op, mode)
1075      rtx op;
1076      enum machine_mode mode;
1077 {
1078   return (GET_CODE (op) == CONST_INT);
1079 }
1080
1081 /* Return true if OP is a register or a valid immediate operand for
1082    addu or subu.  */
1083
1084 int
1085 add_operand (op, mode)
1086      rtx op;
1087      enum machine_mode mode;
1088 {
1089   return (register_operand (op, mode)
1090           || (GET_CODE (op) == CONST_INT && ADD_INT (op)));
1091 }
1092
1093 /* Nonzero if this is a bitmask filling the bottom bits, for optimizing and +
1094    shift left combinations into a single mak instruction.  */
1095
1096 int
1097 mak_mask_p (value)
1098      int value;
1099 {
1100   return (value && POWER_OF_2_or_0 (value + 1));
1101 }
1102
1103 int
1104 reg_or_bbx_mask_operand (op, mode)
1105      rtx op;
1106      enum machine_mode mode;
1107 {
1108   int value;
1109   if (register_operand (op, mode))
1110     return 1;
1111   if (GET_CODE (op) != CONST_INT)
1112     return 0;
1113
1114   value = INTVAL (op);
1115   if (POWER_OF_2 (value))
1116     return 1;
1117
1118   return 0;
1119 }
1120
1121 /* Return true if OP is valid to use in the context of a floating
1122    point operation.  Special case 0.0, since we can use r0.  */
1123
1124 int
1125 real_or_0_operand (op, mode)
1126      rtx op;
1127      enum machine_mode mode;
1128 {
1129   if (mode != SFmode && mode != DFmode)
1130     return 0;
1131
1132   return (register_operand (op, mode)
1133           || (GET_CODE (op) == CONST_DOUBLE
1134               && op == CONST0_RTX (mode)));
1135 }
1136
1137 /* Return true if OP is a relational operator.  */
1138
1139 int
1140 relop (op, mode)
1141      rtx op;
1142      enum machine_mode mode;
1143 {
1144   switch (GET_CODE (op))
1145     {
1146     case EQ:
1147     case NE:
1148     case LT:
1149     case LE:
1150     case GE:
1151     case GT:
1152     case LTU:
1153     case LEU:
1154     case GEU:
1155     case GTU:
1156       return 1;
1157     default:
1158       return 0;
1159     }
1160 }
1161
1162 /* Return true if OP is a relational operator, and is not an unsigned
1163    relational operator.  */
1164
1165 int
1166 relop_no_unsigned (op, mode)
1167      rtx op;
1168      enum machine_mode mode;
1169 {
1170   switch (GET_CODE (op))
1171     {
1172     case EQ:
1173     case NE:
1174     case LT:
1175     case LE:
1176     case GE:
1177     case GT:
1178       /* @@ What is this test doing?  Why not use `mode'?  */
1179       if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT
1180           || GET_MODE (op) == DImode
1181           || GET_MODE_CLASS (GET_MODE (XEXP (op, 0))) == MODE_FLOAT
1182           || GET_MODE (XEXP (op, 0)) == DImode
1183           || GET_MODE_CLASS (GET_MODE (XEXP (op, 1))) == MODE_FLOAT
1184           || GET_MODE (XEXP (op, 1)) == DImode)
1185         return 0;
1186       return 1;
1187     default:
1188       return 0;
1189     }
1190 }
1191
1192 /* Return true if the code of this rtx pattern is EQ or NE.  */
1193
1194 int
1195 equality_op (op, mode)
1196      rtx op;
1197      enum machine_mode mode;
1198 {
1199   return (GET_CODE (op) == EQ || GET_CODE (op) == NE);
1200 }
1201
1202 /* Return true if the code of this rtx pattern is pc or label_ref.  */
1203
1204 int
1205 pc_or_label_ref (op, mode)
1206      rtx op;
1207      enum machine_mode mode;
1208 {
1209   return (GET_CODE (op) == PC || GET_CODE (op) == LABEL_REF);
1210 }
1211 \f
1212 /* Output to FILE the start of the assembler file.  */
1213
1214 struct option
1215 {
1216   char *string;
1217   int *variable;
1218   int on_value;
1219 };
1220
1221 static int
1222 output_option (file, sep, type, name, indent, pos, max)
1223      FILE *file;
1224      char *sep;
1225      char *type;
1226      char *name;
1227      char *indent;
1228      int pos;
1229      int max;
1230 {
1231   if (strlen (sep) + strlen (type) + strlen (name) + pos > max)
1232     {
1233       fprintf (file, indent);
1234       return fprintf (file, "%s%s", type, name);
1235     }
1236   return pos + fprintf (file, "%s%s%s", sep, type, name);
1237 }
1238
1239 static struct { char *name; int value; } m_options[] = TARGET_SWITCHES;
1240
1241 static void
1242 output_options (file, f_options, f_len, W_options, W_len,
1243                 pos, max, sep, indent, term)
1244      FILE *file;
1245      struct option *f_options;
1246      struct option *W_options;
1247      int f_len, W_len;
1248      int pos;
1249      int max;
1250      char *indent;
1251      char *term;
1252 {
1253   register int j;
1254
1255   if (optimize)
1256     pos = output_option (file, sep, "-O", "", indent, pos, max);
1257   if (write_symbols != NO_DEBUG)
1258     pos = output_option (file, sep, "-g", "", indent, pos, max);
1259   if (flag_traditional)
1260     pos = output_option (file, sep, "-traditional", "", indent, pos, max);
1261   if (profile_flag)
1262     pos = output_option (file, sep, "-p", "", indent, pos, max);
1263
1264   for (j = 0; j < f_len; j++)
1265     if (*f_options[j].variable == f_options[j].on_value)
1266       pos = output_option (file, sep, "-f", f_options[j].string,
1267                            indent, pos, max);
1268
1269   for (j = 0; j < W_len; j++)
1270     if (*W_options[j].variable == W_options[j].on_value)
1271       pos = output_option (file, sep, "-W", W_options[j].string,
1272                            indent, pos, max);
1273
1274   for (j = 0; j < sizeof m_options / sizeof m_options[0]; j++)
1275     if (m_options[j].name[0] != '\0'
1276         && m_options[j].value > 0
1277         && ((m_options[j].value & target_flags)
1278             == m_options[j].value))
1279       pos = output_option (file, sep, "-m", m_options[j].name,
1280                            indent, pos, max);
1281
1282   if (m88k_short_data)
1283     pos = output_option (file, sep, "-mshort-data-", m88k_short_data,
1284                          indent, pos, max);
1285
1286   fprintf (file, term);
1287 }
1288
1289 void
1290 output_file_start (file, f_options, f_len, W_options, W_len)
1291      FILE *file;
1292      struct option *f_options;
1293      struct option *W_options;
1294      int f_len, W_len;
1295 {
1296   register int pos;
1297
1298   ASM_FIRST_LINE (file);
1299   output_file_directive (file, main_input_filename);
1300   /* Switch to the data section so that the coffsem symbol and the
1301      gcc2_compiled. symbol aren't in the text section.  */
1302   data_section ();
1303   ASM_COFFSEM (file);
1304
1305   pos = fprintf (file, "\n; cc1 (%s) arguments:", VERSION_STRING);
1306   output_options (file, f_options, f_len, W_options, W_len,
1307                   pos, 75, " ", "\n; ", "\n\n");
1308
1309   if (TARGET_IDENTIFY_REVISION)
1310     {
1311       char indent[256];
1312
1313       time_t now = time ((time_t *)0);
1314       sprintf (indent, "]\"\n\t%s\t \"@(#)%s [", IDENT_ASM_OP, main_input_filename);
1315       fprintf (file, indent+3);
1316       pos = fprintf (file, "gcc %s, %.24s,", VERSION_STRING, ctime (&now));
1317       output_options (file, f_options, f_len, W_options, W_len,
1318                       pos, 150 - strlen (indent), " ", indent, "]\"\n\n");
1319     }
1320 }
1321 \f
1322 /* Output an ascii string.  */
1323
1324 void
1325 output_ascii (file, opcode, max, p, size)
1326      FILE *file;
1327      char *opcode;
1328      int max;
1329      unsigned char *p;
1330      int size;
1331 {
1332   int i;
1333
1334   register int num = 0;
1335
1336   fprintf (file, "\t%s\t \"", opcode);
1337   for (i = 0; i < size; i++)
1338     {
1339       register int c = p[i];
1340
1341       if (num > max)
1342         {
1343           fprintf (file, "\"\n\t%s\t \"", opcode);
1344           num = 0;
1345         }
1346
1347       if (c == '\"' || c == '\\')
1348         {
1349           putc ('\\', file);
1350           num++;
1351         }
1352
1353       if (c >= ' ' && c < 0177)
1354         {
1355           putc (c, file);
1356           num++;
1357         }
1358       else
1359         {
1360           fprintf (file, "\\%03o", c);
1361           num += 4;
1362           /* After an octal-escape, if a digit follows,
1363              terminate one string constant and start another.
1364              The Vax assembler fails to stop reading the escape
1365              after three digits, so this is the only way we
1366              can get it to parse the data properly.  */
1367           if (i < size - 1 && p[i + 1] >= '0' && p[i + 1] <= '9')
1368             num = max + 1;      /* next pass will start a new string */
1369         }
1370     }
1371   fprintf (file, "\"\n");
1372 }
1373 \f
1374 /* Output a label (allows insn-output.c to be compiled without including
1375    m88k.c or needing to include stdio.h).  */
1376
1377 void
1378 output_label (label_number)
1379      int label_number;
1380 {
1381   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", label_number);
1382 }
1383
1384 /* Handle a pragma directive.  HANDLE_PRAGMA conspires to parse the input
1385    following #pragma into tokens based on yylex.  */
1386
1387 void
1388 m88k_handle_pragma_token (string, token)
1389      char *string;
1390      tree token;
1391 {
1392   static enum pragma_state
1393     {
1394       ps_start,
1395       ps_done,
1396       ps_bad,
1397       ps_weak,
1398       ps_name,
1399       ps_equals,
1400       ps_value
1401     } state;
1402   static char *name;
1403   static char *value;
1404
1405   if (HANDLE_PRAGMA_WEAK)
1406     {
1407       if (string == 0)
1408         {
1409           if (state == ps_name || state == ps_value)
1410             {
1411               fprintf (asm_out_file, "\t%s\t ", WEAK_ASM_OP);
1412               ASM_OUTPUT_LABELREF (asm_out_file, name);
1413               fputc ('\n', asm_out_file);
1414               if (state == ps_value)
1415                 {
1416                   fprintf (asm_out_file, "\t%s\t ", DEF_ASM_OP);
1417                   ASM_OUTPUT_LABELREF (asm_out_file, name);
1418                   fputc (',', asm_out_file);
1419                   ASM_OUTPUT_LABELREF (asm_out_file, value);
1420                   fputc ('\n', asm_out_file);
1421                 }
1422             }
1423           else if (! (state == ps_done || state == ps_start))
1424             warning ("ignoring malformed #pragma weak symbol [=value]");
1425           state = ps_start;
1426         }
1427       else
1428         switch (state)
1429           {
1430           case ps_start:
1431             if (token
1432                 && TREE_CODE (token) == IDENTIFIER_NODE
1433                 && !strcmp (IDENTIFIER_POINTER (token), "weak"))
1434               state = ps_weak;
1435             else
1436               state = ps_done;
1437             break;
1438
1439           case ps_weak:
1440             if (token
1441                 && TREE_CODE (token) == IDENTIFIER_NODE)
1442               {
1443                 name = IDENTIFIER_POINTER (token);
1444                 state = ps_name;
1445               }
1446             else
1447               state = ps_bad;
1448             break;
1449
1450           case ps_name:
1451             state = (strcmp (string, "=") ? ps_bad : ps_equals);
1452             break;
1453
1454           case ps_equals:
1455             if (token
1456                 && TREE_CODE (token) == IDENTIFIER_NODE)
1457               {
1458                 value = IDENTIFIER_POINTER (token);
1459                 state = ps_value;
1460               }
1461             else
1462               state = ps_bad;
1463             break;
1464
1465           case ps_value:
1466             state = ps_bad;
1467           case ps_bad:
1468           case ps_done:
1469             break;
1470
1471           default:
1472             abort ();
1473           }
1474     }
1475 }
1476 \f
1477 /* Generate the assembly code for function entry.
1478
1479    The prologue is responsible for setting up the stack frame,
1480    initializing the frame pointer register, saving registers that must be
1481    saved, and allocating SIZE additional bytes of storage for the
1482    local variables.  SIZE is an integer.  FILE is a stdio
1483    stream to which the assembler code should be output.
1484
1485    The label for the beginning of the function need not be output by this
1486    macro.  That has already been done when the macro is run.
1487
1488    To determine which registers to save, the macro can refer to the array
1489    `regs_ever_live': element R is nonzero if hard register
1490    R is used anywhere within the function.  This implies the
1491    function prologue should save register R, but not if it is one
1492    of the call-used registers.
1493
1494    On machines where functions may or may not have frame-pointers, the
1495    function entry code must vary accordingly; it must set up the frame
1496    pointer if one is wanted, and not otherwise.  To determine whether a
1497    frame pointer is in wanted, the macro can refer to the variable
1498    `frame_pointer_needed'.  The variable's value will be 1 at run
1499    time in a function that needs a frame pointer.
1500
1501    On machines where an argument may be passed partly in registers and
1502    partly in memory, this macro must examine the variable
1503    `current_function_pretend_args_size', and allocate that many bytes
1504    of uninitialized space on the stack just underneath the first argument
1505    arriving on the stack.  (This may not be at the very end of the stack,
1506    if the calling sequence has pushed anything else since pushing the stack
1507    arguments.  But usually, on such machines, nothing else has been pushed
1508    yet, because the function prologue itself does all the pushing.)
1509
1510    If `ACCUMULATE_OUTGOING_ARGS' is defined, the variable
1511    `current_function_outgoing_args_size' contains the size in bytes
1512    required for the outgoing arguments.  This macro must add that
1513    amount of uninitialized space to very bottom of the stack.
1514
1515    The stack frame we use looks like this:
1516
1517  caller                                                  callee
1518         |==============================================|
1519         |                caller's frame                |
1520         |==============================================|
1521         |     [caller's outgoing memory arguments]     |
1522         |==============================================|
1523         |  caller's outgoing argument area (32 bytes)  |
1524   sp -> |==============================================| <- ap
1525         |            [local variable space]            |
1526         |----------------------------------------------|
1527         |            [return address (r1)]             |
1528         |----------------------------------------------|
1529         |        [previous frame pointer (r30)]        |
1530         |==============================================| <- fp
1531         |       [preserved registers (r25..r14)]       |
1532         |----------------------------------------------|
1533         |       [preserved registers (x29..x22)]       |
1534         |==============================================|
1535         |    [dynamically allocated space (alloca)]    |
1536         |==============================================|
1537         |     [callee's outgoing memory arguments]     |
1538         |==============================================|
1539         | [callee's outgoing argument area (32 bytes)] |
1540         |==============================================| <- sp
1541
1542   Notes:
1543
1544   r1 and r30 must be saved if debugging.
1545
1546   fp (if present) is located two words down from the local
1547   variable space.
1548   */
1549
1550 static void output_reg_adjust ();
1551 static void preserve_registers ();
1552 static void output_tdesc ();
1553
1554 static int  nregs;
1555 static int  nxregs;
1556 static char save_regs[FIRST_PSEUDO_REGISTER];
1557 static int  frame_laid_out;
1558 static int  frame_size;
1559 static int  variable_args_p;
1560
1561 extern char call_used_regs[];
1562 extern int  current_function_pretend_args_size;
1563 extern int  current_function_outgoing_args_size;
1564 extern int  frame_pointer_needed;
1565
1566 #define FIRST_OCS_PRESERVE_REGISTER     14
1567 #define LAST_OCS_PRESERVE_REGISTER      30
1568
1569 #define FIRST_OCS_EXTENDED_PRESERVE_REGISTER    (32 + 22)
1570 #define LAST_OCS_EXTENDED_PRESERVE_REGISTER     (32 + 31)
1571
1572 #define STACK_UNIT_BOUNDARY (STACK_BOUNDARY / BITS_PER_UNIT)
1573 #define ROUND_CALL_BLOCK_SIZE(BYTES) \
1574   (((BYTES) + (STACK_UNIT_BOUNDARY - 1)) & ~(STACK_UNIT_BOUNDARY - 1))
1575 \f
1576 /* Establish the position of the FP relative to the SP.  This is done
1577    either during FUNCTION_PROLOGUE or by INITIAL_ELIMINATION_OFFSET.  */
1578
1579 void
1580 m88k_layout_frame ()
1581 {
1582   int regno, sp_size;
1583
1584   frame_laid_out++;
1585
1586   bzero ((char *) &save_regs[0], sizeof (save_regs));
1587   sp_size = nregs = nxregs = 0;
1588   frame_size = get_frame_size ();
1589
1590   /* Since profiling requires a call, make sure r1 is saved.  */
1591   if (profile_flag)
1592     save_regs[1] = 1;
1593
1594   /* If we are producing debug information, store r1 and r30 where the
1595      debugger wants to find them (r30 at r30+0, r1 at r30+4).  Space has
1596      already been reserved for r1/r30 in STARTING_FRAME_OFFSET.  */
1597   if (write_symbols != NO_DEBUG && !TARGET_OCS_FRAME_POSITION)
1598     save_regs[1] = 1;
1599
1600   /* If there is a call, alloca is used, __builtin_alloca is used, or
1601      a dynamic-sized object is defined, add the 8 additional words
1602      for the callee's argument area.  The common denominator is that the
1603      FP is required.  may_call_alloca only gets calls to alloca;
1604      current_function_calls_alloca gets alloca and __builtin_alloca.  */
1605   if (regs_ever_live[1] || frame_pointer_needed)
1606     {
1607       save_regs[1] = 1;
1608       sp_size += REG_PARM_STACK_SPACE (0);
1609     }
1610
1611   /* If we are producing PIC, save the addressing base register and r1.  */
1612   if (flag_pic && current_function_uses_pic_offset_table)
1613     {
1614       save_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
1615       nregs++;
1616     }
1617
1618   /* If a frame is requested, save the previous FP, and the return
1619      address (r1), so that a traceback can be done without using tdesc
1620      information.  */
1621   if (frame_pointer_needed)
1622     save_regs[FRAME_POINTER_REGNUM] = save_regs[1] = 1;
1623
1624   /* Figure out which extended register(s) needs to be saved.  */
1625   for (regno = FIRST_EXTENDED_REGISTER + 1; regno < FIRST_PSEUDO_REGISTER;
1626        regno++)
1627     if (regs_ever_live[regno] && ! call_used_regs[regno])
1628       {
1629         save_regs[regno] = 1;
1630         nxregs++;
1631       }
1632
1633   /* Figure out which normal register(s) needs to be saved.  */
1634   for (regno = 2; regno < FRAME_POINTER_REGNUM; regno++)
1635     if (regs_ever_live[regno] && ! call_used_regs[regno])
1636       {
1637         save_regs[regno] = 1;
1638         nregs++;
1639       }
1640
1641   /* Achieve greatest use of double memory ops.  Either we end up saving
1642      r30 or we use that slot to align the regsters we do save.  */
1643   if (nregs >= 2 && save_regs[1] && !save_regs[FRAME_POINTER_REGNUM])
1644     sp_size += 4;
1645
1646   nregs += save_regs[1] + save_regs[FRAME_POINTER_REGNUM];
1647   /* if we need to align extended registers, add a word */
1648   if (nxregs > 0 && (nregs & 1) != 0)
1649     sp_size +=4;
1650   sp_size += 4 * nregs;
1651   sp_size += 8 * nxregs;
1652   sp_size += current_function_outgoing_args_size;
1653
1654   /* The first two saved registers are placed above the new frame pointer
1655      if any.  In the only case this matters, they are r1 and r30. */
1656   if (frame_pointer_needed || sp_size)
1657     {
1658       m88k_fp_offset = ROUND_CALL_BLOCK_SIZE (sp_size - STARTING_FRAME_OFFSET);
1659       m88k_stack_size = m88k_fp_offset + STARTING_FRAME_OFFSET;
1660     }
1661   else
1662     {
1663       m88k_stack_size = m88k_fp_offset = 0;
1664     }
1665
1666   /* First, combine m88k_stack_size and size.  If m88k_stack_size is
1667      non-zero, align the frame size to 8 mod 16; otherwise align the
1668      frame size to 0 mod 16.  (If stacks are 8 byte aligned, this ends
1669      up as a NOP.  */
1670   {
1671     int need
1672       = ((m88k_stack_size ? STACK_UNIT_BOUNDARY - STARTING_FRAME_OFFSET : 0)
1673          - (frame_size % STACK_UNIT_BOUNDARY));
1674     if (need)
1675       {
1676         if (need < 0)
1677           need += STACK_UNIT_BOUNDARY;
1678         (void) assign_stack_local (BLKmode, need, BITS_PER_UNIT);
1679         frame_size = get_frame_size ();
1680       }
1681     m88k_stack_size
1682       = ROUND_CALL_BLOCK_SIZE (m88k_stack_size + frame_size
1683                                + current_function_pretend_args_size);
1684   }
1685 }
1686
1687 /* Return true if this function is known to have a null epilogue.  */
1688
1689 int
1690 null_epilogue ()
1691 {
1692   if (! reload_completed)
1693     return 0;
1694   if (! frame_laid_out)
1695     m88k_layout_frame ();
1696   return (! frame_pointer_needed
1697           && nregs == 0
1698           && nxregs == 0
1699           && m88k_stack_size == 0);
1700 }
1701
1702 /* Determine the number of instructions needed for the function epilogue.  */
1703
1704 #define MAX_EPILOGUE_DELAY_INSNS 4
1705
1706 static char epilogue_dead_regs[FIRST_PSEUDO_REGISTER];
1707
1708 delay_slots_for_epilogue ()
1709 {
1710   register int insns = save_regs[1] + save_regs[FRAME_POINTER_REGNUM];
1711   register int regs = nregs - insns;
1712
1713   if (regs > 3)
1714     insns += 1 + (regs & 1);
1715   else if (nregs == 4)
1716     /* This is a special cases of ld/ld/ld.d which has no start-up delay.  */
1717     return 0;
1718
1719   if (insns)
1720     {
1721       bzero ((char *) &epilogue_dead_regs[0], sizeof (epilogue_dead_regs));
1722       epilogue_dead_regs[1] = save_regs[1];
1723       epilogue_dead_regs[STACK_POINTER_REGNUM] = frame_pointer_needed;
1724       epilogue_dead_regs[TEMP_REGNUM] = ! ADD_INTVAL (m88k_fp_offset);
1725     }
1726
1727   return insns;
1728 }
1729
1730 /* Return 1 if X is safe to use as an epilogue insn.  */
1731
1732 int
1733 ok_for_epilogue_p (x)
1734      rtx x;
1735 {
1736   register char *fmt;
1737   register int i, j;
1738
1739   switch (GET_CODE (x))
1740     {
1741     case REG:
1742       for (i = REGNO (x), j = i + HARD_REGNO_NREGS (i, GET_MODE (x));
1743            i < j;
1744            i++)
1745         if (epilogue_dead_regs[i])
1746           return 0;
1747
1748     case CONST_INT:
1749     case CONST_DOUBLE:
1750     case CONST:
1751     case PC:
1752     case CC0:
1753     case LABEL_REF:
1754     case SYMBOL_REF:
1755     case CODE_LABEL:
1756       return 1;
1757     }
1758
1759   fmt = GET_RTX_FORMAT (GET_CODE (x));
1760   for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
1761     {
1762       if (fmt[i] == 'e')
1763         {
1764           if (!ok_for_epilogue_p (XEXP (x, i)))
1765             return 0;
1766         }
1767       else if (fmt[i] == 'E')
1768         {
1769           for (j = XVECLEN (x, i) - 1; j >= 0; j--)
1770             if (!ok_for_epilogue_p (XVECEXP (x, i, j)))
1771               return 0;
1772         }
1773     }
1774   return 1;
1775 }
1776
1777 int
1778 eligible_for_epilogue_delay (insn)
1779      rtx insn;
1780 {
1781   switch (get_attr_type (insn))
1782     {
1783     case TYPE_STORE:
1784     case TYPE_LOADA:
1785     case TYPE_ARITH:
1786     case TYPE_MARITH:
1787     case TYPE_MSTORE:
1788       return ok_for_epilogue_p (PATTERN (insn));
1789     default:
1790       return 0;
1791     }
1792 }
1793
1794 /* Determine if the current function has any references to the arg pointer.
1795    This is done indirectly by examining the DECL_ARGUMENTS' DECL_RTL.
1796    It is OK to return TRUE if there are no references, but FALSE must be
1797    correct.  */
1798
1799 static int
1800 uses_arg_area_p ()
1801 {
1802   register tree parm;
1803
1804   if (current_function_decl == 0
1805       || current_function_varargs
1806       || variable_args_p)
1807     return 1;
1808
1809   for (parm = DECL_ARGUMENTS (current_function_decl);
1810        parm;
1811        parm = TREE_CHAIN (parm))
1812     {
1813       if (DECL_RTL (parm) == 0
1814           || GET_CODE (DECL_RTL (parm)) == MEM)
1815         return 1;
1816
1817       if (DECL_INCOMING_RTL (parm) == 0
1818           || GET_CODE (DECL_INCOMING_RTL (parm)) == MEM)
1819         return 1;
1820     }
1821   return 0;
1822 }
1823 \f
1824 void
1825 m88k_output_prologue (stream, size)
1826      FILE *stream;
1827      int size;
1828 {
1829   int old_fp_offset = m88k_fp_offset;
1830   int old_stack_size = m88k_stack_size;
1831
1832   m88k_layout_frame ();
1833 #if (MONITOR_GCC & 0x8) /* Watch for suspicious register elimination changes.  */
1834   if (frame_laid_out > 1)
1835     {
1836       if (old_fp_offset != m88k_fp_offset)
1837         warning ("Internal gcc error: FP offset has changed by %d bytes",
1838                  m88k_fp_offset - old_fp_offset);
1839       if (old_stack_size != m88k_stack_size)
1840         warning ("Internal gcc error: stack size has changed by %d bytes",
1841                  m88k_stack_size - old_stack_size);
1842     }
1843 #endif
1844   frame_laid_out = 0;
1845
1846   if (TARGET_OPTIMIZE_ARG_AREA
1847       && m88k_stack_size
1848       && ! uses_arg_area_p ())
1849     {
1850       /* The incoming argument area is used for stack space if it is not
1851          used (or if -mno-use-arg-area is given).  */
1852       if ((m88k_stack_size -= REG_PARM_STACK_SPACE (0)) < 0)
1853         m88k_stack_size = 0;
1854     }
1855
1856   if (m88k_stack_size)
1857     output_reg_adjust (stream, 31, 31, -m88k_stack_size, 0);
1858
1859   if (nregs || nxregs)
1860     preserve_registers (stream, m88k_fp_offset + 4, 1);
1861
1862   if (frame_pointer_needed)
1863     output_reg_adjust (stream, 30, 31, m88k_fp_offset, 0);
1864
1865   if (TARGET_OCS_DEBUG_INFO)
1866     PUT_OCS_FUNCTION_START (stream);
1867
1868   if (flag_pic && save_regs[PIC_OFFSET_TABLE_REGNUM])
1869     {
1870       char label[256];
1871
1872       if (! save_regs[1])
1873         fprintf (stream, "\tor\t %s,%s,0\n",
1874                  reg_names[TEMP_REGNUM], reg_names[1]);
1875       ASM_GENERATE_INTERNAL_LABEL (label, "Lab", m88k_function_number);
1876       fprintf (stream, "\tbsr.n\t %s\n", &label[1]);
1877       fprintf (stream, "\tor.u\t %s,%s,%shi16(%s#abdiff)\n",
1878                reg_names[PIC_OFFSET_TABLE_REGNUM], reg_names[0],
1879                m88k_pound_sign, &label[1]);
1880       ASM_OUTPUT_INTERNAL_LABEL (stream, "Lab", m88k_function_number);
1881       fprintf (stream, "\tor\t %s,%s,%slo16(%s#abdiff)\n",
1882                reg_names[PIC_OFFSET_TABLE_REGNUM],
1883                reg_names[PIC_OFFSET_TABLE_REGNUM],
1884                m88k_pound_sign, &label[1]);
1885       fprintf (stream, "\taddu\t %s,%s,%s\n",
1886                reg_names[PIC_OFFSET_TABLE_REGNUM],
1887                reg_names[PIC_OFFSET_TABLE_REGNUM], reg_names[1]);
1888       if (! save_regs[1])
1889         fprintf (stream, "\tor\t %s,%s,0\n",
1890                  reg_names[1], reg_names[TEMP_REGNUM]);
1891     }
1892
1893   m88k_prologue_done = 1;       /* it's ok now to put out ln directives */
1894 }
1895 \f
1896 /* This function generates the assembly code for function exit,
1897    on machines that need it.  Args are same as for FUNCTION_PROLOGUE.
1898
1899    The function epilogue should not depend on the current stack pointer!
1900    It should use the frame pointer only, if there is a frame pointer.
1901    This is mandatory because of alloca; we also take advantage of it to
1902    omit stack adjustments before returning.  */
1903
1904 void
1905 m88k_output_epilogue (stream, size)
1906      FILE *stream;
1907      int size;
1908 {
1909   rtx insn = get_last_insn ();
1910 #if (MONITOR_GCC & 0x4) /* What are interesting prologue/epilogue values?  */
1911   fprintf (stream, "; size = %d, m88k_fp_offset = %d, m88k_stack_size = %d\n",
1912            size, m88k_fp_offset, m88k_stack_size);
1913 #endif
1914
1915   output_short_branch_defs (stream);
1916
1917   if (TARGET_OCS_DEBUG_INFO)
1918     PUT_OCS_FUNCTION_END (stream);
1919
1920   /* If the last insn was a BARRIER, we don't have to write any code.  */
1921   if (GET_CODE (insn) == NOTE)
1922     insn = prev_nonnote_insn (insn);
1923   if (insn && GET_CODE (insn) == BARRIER)
1924     {
1925       if (current_function_epilogue_delay_list)
1926         abort ();
1927     }
1928   else
1929     {
1930       if (frame_pointer_needed)
1931         output_reg_adjust (stream, 31, 30, -m88k_fp_offset, 0);
1932
1933       if (nregs || nxregs)
1934         preserve_registers (stream, m88k_fp_offset + 4, 0);
1935
1936       output_reg_adjust (stream, 31, 31, m88k_stack_size, 1);
1937     }
1938
1939   fprintf (stream, "\n");
1940
1941   if (TARGET_OCS_DEBUG_INFO)
1942     output_tdesc (stream, m88k_fp_offset + 4);
1943
1944   m88k_function_number++;
1945   m88k_prologue_done    = 0;            /* don't put out ln directives */
1946   variable_args_p       = 0;            /* has variable args */
1947 }
1948 \f
1949 /* Output code to STREAM to set DSTREG to SRCREG + AMOUNT.  Issue
1950    a return instruction and use it's delay slot based on RETURN_P.  */
1951
1952 static void
1953 output_reg_adjust (stream, dstreg, srcreg, amount, return_p)
1954      FILE *stream;
1955      int dstreg, srcreg, amount, return_p;
1956 {
1957   char *opname;
1958   char incr[256];
1959
1960   if (amount < 0)
1961     {
1962       opname = "subu";
1963       amount = -amount;
1964     }
1965   else
1966     opname = "addu";
1967
1968   if (amount == 0 && dstreg == srcreg)
1969     {
1970       if (return_p)
1971         fprintf (stream, "\tjmp\t %s\n", reg_names[1]);
1972       return;
1973     }
1974   else if (SMALL_INTVAL (amount))
1975     sprintf (incr, "\t%s\t %s,%s,%d", opname,
1976              reg_names[dstreg], reg_names[srcreg], amount);
1977   else
1978     {
1979       rtx operands[2];
1980
1981       operands[0] = gen_rtx (REG, SImode, TEMP_REGNUM);
1982       operands[1] = gen_rtx (CONST_INT, VOIDmode, amount);
1983       output_asm_insn (output_load_const_int (SImode, operands),
1984                        operands);
1985       sprintf (incr, "\t%s\t %s,%s,%s", opname,
1986                reg_names[dstreg], reg_names[srcreg], reg_names[TEMP_REGNUM]);
1987     }
1988
1989   if (!return_p)
1990     fprintf (stream, "%s\n", incr);
1991   else if (flag_delayed_branch)
1992     fprintf (stream, "\tjmp.n\t %s\n%s\n", reg_names[1], incr);
1993   else
1994     fprintf (stream, "%s\n\tjmp\t %s\n", incr, reg_names[1]);
1995 }
1996
1997 /* Save/restore the preserve registers.  base is the highest offset from
1998    r31 at which a register is stored.  store_p is true if stores are to
1999    be done; otherwise loads.  When loading, output the epilogue delay
2000    insns.  */
2001
2002 static void
2003 preserve_registers (stream, base, store_p)
2004      FILE *stream;
2005      int base;
2006      int store_p;
2007 {
2008   int regno, offset;
2009   char *fmt = (store_p ? "\tst%s\t %s,%s,%d\n" : "\tld%s\t %s,%s,%d\n");
2010   struct mem_op {
2011     int regno;
2012     int nregs;
2013     int offset;
2014   } mem_op[FIRST_PSEUDO_REGISTER];
2015   struct mem_op *mo_ptr = mem_op;
2016
2017   /* The 88open OCS mandates that preserved registers be stored in
2018      increasing order.  For compatibility with current practice,
2019      the order is r1, r30, then the preserve registers.  */
2020
2021   offset = base;
2022   if (save_regs[1])
2023     {
2024       /* An extra word is given in this case to make best use of double
2025          memory ops.  */
2026       if (nregs > 2 && !save_regs[FRAME_POINTER_REGNUM])
2027         offset -= 4;
2028       fprintf (stream, fmt, "", reg_names[1], reg_names[31], offset);
2029       offset -= 4;
2030       base = offset;
2031     }
2032
2033   /* Walk the registers to save recording all single memory operations.  */
2034   for (regno = FRAME_POINTER_REGNUM; regno > 1; regno--)
2035     if (save_regs[regno])
2036       {
2037         if ((offset & 7) != 4 || (regno & 1) != 1 || !save_regs[regno-1])
2038           {
2039             mo_ptr->nregs = 1;
2040             mo_ptr->regno = regno;
2041             mo_ptr->offset = offset;
2042             mo_ptr++;
2043             offset -= 4;
2044           }
2045         else
2046           {
2047             regno--;
2048             offset -= 2*4;
2049           }
2050       }
2051
2052   /* Walk the registers to save recording all double memory operations.
2053      This avoids a delay in the epilogue (ld.d/ld).  */
2054   offset = base;
2055   for (regno = FRAME_POINTER_REGNUM; regno > 1; regno--)
2056     if (save_regs[regno])
2057       {
2058         if ((offset & 7) != 4 || (regno & 1) != 1 || !save_regs[regno-1])
2059           {
2060             offset -= 4;
2061           }
2062         else
2063           {
2064             mo_ptr->nregs = 2;
2065             mo_ptr->regno = regno-1;
2066             mo_ptr->offset = offset-4;
2067             mo_ptr++;
2068             regno--;
2069             offset -= 2*4;
2070           }
2071       }
2072
2073   /* Walk the extended registers to record all memory operations.  */
2074   /*  Be sure the offset is double word aligned.  */
2075   offset = (offset - 1) & ~7;
2076   for (regno = FIRST_PSEUDO_REGISTER - 1; regno > FIRST_EXTENDED_REGISTER;
2077        regno--)
2078     if (save_regs[regno])
2079       {
2080         mo_ptr->nregs = 2;
2081         mo_ptr->regno = regno;
2082         mo_ptr->offset = offset;
2083         mo_ptr++;
2084         offset -= 2*4;
2085       }
2086
2087   mo_ptr->regno = 0;
2088
2089   /* Output the delay insns interleaved with the memory operations.  */
2090   if (! store_p && current_function_epilogue_delay_list)
2091     {
2092       rtx delay_insns = current_function_epilogue_delay_list;
2093       rtx insn;
2094
2095       /* The first delay insn goes after the restore of r1.  */
2096       if (save_regs[1])
2097         {
2098           final_scan_insn (XEXP (delay_insns, 0), stream, 1, 0, 1);
2099           delay_insns = XEXP (delay_insns, 1);
2100         }
2101
2102       while (delay_insns)
2103         {
2104           /* Find a memory operation that doesn't conflict with this insn.  */
2105           for (mo_ptr = mem_op; mo_ptr->regno != 0; mo_ptr++)
2106             {
2107               if (mo_ptr->nregs)
2108                 {
2109                   int nregs = (mo_ptr->regno < FIRST_EXTENDED_REGISTER
2110                                ? mo_ptr->nregs : 1);
2111                   rtx ok_insns = delay_insns;
2112                   int i;
2113
2114                   for (i = 0; i < nregs; i++)
2115                     epilogue_dead_regs[mo_ptr->regno + i] = 1;
2116
2117                   while (ok_insns)
2118                     {
2119                       insn = XEXP (ok_insns, 0);
2120                       ok_insns = XEXP (ok_insns, 1);
2121
2122                       if (! ok_for_epilogue_p (PATTERN (insn)))
2123                         {
2124                           for (i = 0; i < nregs; i++)
2125                             epilogue_dead_regs[mo_ptr->regno + i] = 0;
2126                           insn = 0;
2127                           break; /* foreach delay insn */
2128                         }
2129                     }
2130                   if (insn)
2131                     {
2132                       fprintf (stream, fmt, mo_ptr->nregs > 1 ? ".d" : "",
2133                                reg_names[mo_ptr->regno], reg_names[31],
2134                                mo_ptr->offset);
2135                       mo_ptr->nregs = 0;
2136                       break; /* foreach memory operation */
2137                     }
2138                 }
2139             }
2140           final_scan_insn (XEXP (delay_insns, 0), stream, 1, 0, 1);
2141           delay_insns = XEXP (delay_insns, 1);
2142         }
2143     }
2144
2145   /* Output the memory operations.  */
2146   for (mo_ptr = mem_op; mo_ptr->regno; mo_ptr++)
2147     {
2148       if (mo_ptr->nregs)
2149         fprintf (stream, fmt, mo_ptr->nregs > 1 ? ".d" : "",
2150                  reg_names[mo_ptr->regno], reg_names[31], mo_ptr->offset);
2151     }
2152 }
2153
2154 /* Convert the address expression REG to a CFA offset.  */
2155
2156 int
2157 m88k_debugger_offset (reg, offset)
2158      register rtx reg;
2159      register int offset;
2160 {
2161   if (GET_CODE (reg) == PLUS)
2162     {
2163       offset = INTVAL (XEXP (reg, 1));
2164       reg = XEXP (reg, 0);
2165     }
2166
2167   /* Put the offset in terms of the CFA (arg pointer).  */
2168   if (reg == frame_pointer_rtx)
2169     offset += m88k_fp_offset - m88k_stack_size;
2170   else if (reg == stack_pointer_rtx)
2171     offset -= m88k_stack_size;
2172   else if (reg != arg_pointer_rtx)
2173     {
2174 #if (MONITOR_GCC & 0x10) /* Watch for suspicious symbolic locations.  */
2175       if (! (GET_CODE (reg) == REG
2176              && REGNO (reg) >= FIRST_PSEUDO_REGISTER))
2177         warning ("Internal gcc error: Can't express symbolic location");
2178 #endif
2179       return 0;
2180     }
2181
2182   return offset;
2183 }
2184
2185 /* Output the 88open OCS proscribed text description information.
2186    The information is:
2187         0  8: zero
2188         0 22: info-byte-length (16 or 20 bytes)
2189         0  2: info-alignment (word 2)
2190         1 32: info-protocol (version 1 or 2(pic))
2191         2 32: starting-address (inclusive, not counting prologue)
2192         3 32: ending-address (exclusive, not counting epilog)
2193         4  8: info-variant (version 1 or 3(extended registers))
2194         4 17: register-save-mask (from register 14 to 30)
2195         4  1: zero
2196         4  1: return-address-info-discriminant
2197         4  5: frame-address-register
2198         5 32: frame-address-offset
2199         6 32: return-address-info
2200         7 32: register-save-offset
2201         8 16: extended-register-save-mask (x16 - x31)
2202         8 16: extended-register-save-offset (WORDS from register-save-offset)  */
2203
2204 static void
2205 output_tdesc (file, offset)
2206      FILE *file;
2207      int offset;
2208 {
2209   int regno, i, j;
2210   long mask, return_address_info, register_save_offset;
2211   long xmask, xregister_save_offset;
2212   char buf[256];
2213
2214   for (mask = 0, i = 0, regno = FIRST_OCS_PRESERVE_REGISTER;
2215        regno <= LAST_OCS_PRESERVE_REGISTER;
2216        regno++)
2217     {
2218       mask <<= 1;
2219       if (save_regs[regno])
2220         {
2221           mask |= 1;
2222           i++;
2223         }
2224     }
2225
2226   for (xmask = 0, j = 0, regno = FIRST_OCS_EXTENDED_PRESERVE_REGISTER;
2227        regno <= LAST_OCS_EXTENDED_PRESERVE_REGISTER;
2228        regno++)
2229     {
2230       xmask <<= 1;
2231       if (save_regs[regno])
2232         {
2233           xmask |= 1;
2234           j++;
2235         }
2236     }
2237
2238   if (save_regs[1])
2239     {
2240       if ((nxregs > 0 || nregs > 2) && !save_regs[FRAME_POINTER_REGNUM])
2241         offset -= 4;
2242       return_address_info = - m88k_stack_size + offset;
2243       register_save_offset = return_address_info - i*4;
2244     }
2245   else
2246     {
2247       return_address_info = 1;
2248       register_save_offset = - m88k_stack_size + offset + 4 - i*4;
2249     }
2250
2251   xregister_save_offset = - (j * 2 + ((register_save_offset >> 2) & 1));
2252
2253   tdesc_section ();
2254
2255   fprintf (file, "\t%s\t %d,%d", INT_ASM_OP, /* 8:0,22:(20 or 16),2:2 */
2256            (((xmask != 0) ? 20 : 16) << 2) | 2,
2257            flag_pic ? 2 : 1);
2258
2259   ASM_GENERATE_INTERNAL_LABEL (buf, OCS_START_PREFIX, m88k_function_number);
2260   fprintf (file, ",%s%s", buf+1, flag_pic ? "#rel" : "");
2261   ASM_GENERATE_INTERNAL_LABEL (buf, OCS_END_PREFIX, m88k_function_number);
2262   fprintf (file, ",%s%s", buf+1, flag_pic ? "#rel" : "");
2263
2264   fprintf (file, ",0x%x,0x%x,0x%x,0x%x",
2265            /* 8:1,17:0x%.3x,1:0,1:%d,5:%d */
2266            (((xmask ? 3 : 1) << (17+1+1+5))
2267             | (mask << (1+1+5))
2268             | ((!!save_regs[1]) << 5)
2269             | (frame_pointer_needed
2270                ? FRAME_POINTER_REGNUM
2271                : STACK_POINTER_REGNUM)),
2272            (m88k_stack_size - (frame_pointer_needed ? m88k_fp_offset : 0)),
2273            return_address_info,
2274            register_save_offset);
2275   if (xmask)
2276     fprintf (file, ",0x%x%04x", xmask, (0xffff & xregister_save_offset));
2277   fputc ('\n', file);
2278
2279   text_section ();
2280 }
2281
2282 /* Output assembler code to FILE to increment profiler label # LABELNO
2283    for profiling a function entry.  NAME is the mcount function name
2284    (varies), SAVEP indicates whether the parameter registers need to
2285    be saved and restored.  */
2286
2287 void
2288 output_function_profiler (file, labelno, name, savep)
2289      FILE *file;
2290      int labelno;
2291      char *name;
2292      int savep;
2293 {
2294   char label[256];
2295   char dbi[256];
2296   char *temp = (savep ? reg_names[2] : reg_names[10]);
2297
2298   if (savep)
2299     {
2300       fprintf (file, "\tsubu\t %s,%s,64\n", reg_names[31], reg_names[31]);
2301       fprintf (file, "\tst.d\t %s,%s,32\n", reg_names[2], reg_names[31]);
2302       fprintf (file, "\tst.d\t %s,%s,40\n", reg_names[4], reg_names[31]);
2303       fprintf (file, "\tst.d\t %s,%s,48\n", reg_names[6], reg_names[31]);
2304       fprintf (file, "\tst.d\t %s,%s,56\n", reg_names[8], reg_names[31]);
2305     }
2306
2307   ASM_GENERATE_INTERNAL_LABEL (label, "LP", labelno);
2308   if (flag_pic == 2)
2309     {
2310       fprintf (file, "\tor.u\t %s,%s,%shi16(%s#got_rel)\n",
2311                temp, reg_names[0], m88k_pound_sign, &label[1]);
2312       fprintf (file, "\tor\t %s,%s,%slo16(%s#got_rel)\n",
2313                temp, temp, m88k_pound_sign, &label[1]);
2314       sprintf (dbi, "\tld\t %s,%s,%s\n", temp,
2315                reg_names[PIC_OFFSET_TABLE_REGNUM], temp);
2316     }
2317   else if (flag_pic)
2318     {
2319       sprintf (dbi, "\tld\t %s,%s,%s#got_rel\n", temp,
2320                reg_names[PIC_OFFSET_TABLE_REGNUM], &label[1]);
2321     }
2322   else
2323     {
2324       fprintf (file, "\tor.u\t %s,%s,%shi16(%s)\n",
2325                temp, reg_names[0], m88k_pound_sign, &label[1]);
2326       sprintf (dbi, "\tor\t %s,%s,%slo16(%s)\n",
2327                temp, temp, m88k_pound_sign, &label[1]);
2328     }
2329
2330   if (flag_pic)
2331     fprintf (file, "\tbsr.n\t %s#plt\n", name);
2332   else
2333     fprintf (file, "\tbsr.n\t %s\n", name);
2334   fputs (dbi, file);
2335
2336   if (savep)
2337     {
2338       fprintf (file, "\tld.d\t %s,%s,32\n", reg_names[2], reg_names[31]);
2339       fprintf (file, "\tld.d\t %s,%s,40\n", reg_names[4], reg_names[31]);
2340       fprintf (file, "\tld.d\t %s,%s,48\n", reg_names[6], reg_names[31]);
2341       fprintf (file, "\tld.d\t %s,%s,56\n", reg_names[8], reg_names[31]);
2342       fprintf (file, "\taddu\t %s,%s,64\n", reg_names[31], reg_names[31]);
2343     }
2344 }
2345
2346 /* Output assembler code to FILE to initialize basic-block profiling for
2347    the current module.  LABELNO is unique to each instance.  */
2348
2349 void
2350 output_function_block_profiler (file, labelno)
2351      FILE *file;
2352      int labelno;
2353 {
2354   char block[256];
2355   char label[256];
2356
2357   ASM_GENERATE_INTERNAL_LABEL (block, "LPBX", 0);
2358   ASM_GENERATE_INTERNAL_LABEL (label, "LPY", labelno);
2359
2360   /* @@ Need to deal with PIC.  I'm not sure what the requirements are on
2361      register usage, so I used r26/r27 to be safe.  */
2362   fprintf (file, "\tor.u\t %s,%s,%shi16(%s)\n", reg_names[27], reg_names[0],
2363                  m88k_pound_sign, &block[1]);
2364   fprintf (file, "\tld\t %s,%s,%slo16(%s)\n", reg_names[26], reg_names[27],
2365                  m88k_pound_sign, &block[1]);
2366   fprintf (file, "\tbcnd\t %sne0,%s,%s\n",
2367                  m88k_pound_sign, reg_names[26], &label[1]);
2368   fputs ("\tbsr.n\t ", file);
2369   ASM_OUTPUT_LABELREF (file, "__bb_init_func");
2370   putc ('\n', file);
2371   fprintf (file, "\tor\t %s,%s,%slo16(%s)\n", reg_names[2], reg_names[27],
2372                  m88k_pound_sign, &block[1]);
2373   ASM_OUTPUT_INTERNAL_LABEL (file, "LPY", labelno);
2374 }
2375
2376 /* Output assembler code to FILE to increment the count associated with
2377    the basic block number BLOCKNO.  */
2378
2379 void
2380 output_block_profiler (file, blockno)
2381      FILE *file;
2382      int blockno;
2383 {
2384   char block[256];
2385
2386   ASM_GENERATE_INTERNAL_LABEL (block, "LPBX", 0);
2387
2388   /* @@ Need to deal with PIC.  I'm not sure what the requirements are on
2389      register usage, so I used r26/r27 to be safe.  */
2390   fprintf (file, "\tor.u\t %s,%s,%shi16(%s+%d)\n", reg_names[27], reg_names[0],
2391                  m88k_pound_sign, &block[1], 4 * blockno);
2392   fprintf (file, "\tld\t %s,%s,%slo16(%s+%d)\n", reg_names[26], reg_names[27],
2393                  m88k_pound_sign, &block[1], 4 * blockno);
2394   fprintf (file, "\taddu\t %s,%s,1\n", reg_names[26], reg_names[26]);
2395   fprintf (file, "\tst\t %s,%s,%slo16(%s+%d)\n", reg_names[26], reg_names[27],
2396                  m88k_pound_sign, &block[1], 4 * blockno);
2397 }
2398 \f
2399 /* Determine whether a function argument is passed in a register, and
2400    which register.
2401
2402    The arguments are CUM, which summarizes all the previous
2403    arguments; MODE, the machine mode of the argument; TYPE,
2404    the data type of the argument as a tree node or 0 if that is not known
2405    (which happens for C support library functions); and NAMED,
2406    which is 1 for an ordinary argument and 0 for nameless arguments that
2407    correspond to `...' in the called function's prototype.
2408
2409    The value of the expression should either be a `reg' RTX for the
2410    hard register in which to pass the argument, or zero to pass the
2411    argument on the stack.
2412
2413    On the m88000 the first eight words of args are normally in registers
2414    and the rest are pushed.  Double precision floating point must be
2415    double word aligned (and if in a register, starting on an even
2416    register). Structures and unions which are not 4 byte, and word
2417    aligned are passed in memory rather than registers, even if they
2418    would fit completely in the registers under OCS rules.
2419
2420    Note that FUNCTION_ARG and FUNCTION_INCOMING_ARG were different.
2421    For structures that are passed in memory, but could have been
2422    passed in registers, we first load the structure into the
2423    register, and then when the last argument is passed, we store
2424    the registers into the stack locations.  This fixes some bugs
2425    where GCC did not expect to have register arguments, followed
2426    by stack arguments, followed by register arguments.  */
2427
2428 struct rtx_def *
2429 m88k_function_arg (args_so_far, mode, type, named)
2430      CUMULATIVE_ARGS args_so_far;
2431      enum machine_mode mode;
2432      tree type;
2433      int named;
2434 {
2435   int bytes, words;
2436
2437   if (type != 0                 /* undo putting struct in register */
2438       && (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE))
2439     mode = BLKmode;
2440
2441   if (mode == BLKmode && TARGET_WARN_PASS_STRUCT)
2442     warning ("argument #%d is a structure", args_so_far + 1);
2443
2444   if ((args_so_far & 1) != 0
2445       && (mode == DImode || mode == DFmode
2446           || (type != 0 && TYPE_ALIGN (type) > 32)))
2447     args_so_far++;
2448
2449 #ifdef ESKIT
2450   if (no_reg_params)
2451     return (rtx) 0;             /* don't put args in registers */
2452 #endif
2453
2454   if (type == 0 && mode == BLKmode)
2455     abort ();   /* m88k_function_arg argument `type' is NULL for BLKmode. */
2456
2457   bytes = (mode != BLKmode) ? GET_MODE_SIZE (mode) : int_size_in_bytes (type);
2458   words = (bytes + 3) / 4;
2459
2460   if (args_so_far + words > 8)
2461     return (rtx) 0;             /* args have exhausted registers */
2462
2463   else if (mode == BLKmode
2464            && (TYPE_ALIGN (type) != BITS_PER_WORD
2465                || bytes != UNITS_PER_WORD))
2466     return (rtx) 0;
2467
2468   return gen_rtx (REG,
2469                   ((mode == BLKmode) ? TYPE_MODE (type) : mode),
2470                   2 + args_so_far);
2471 }
2472 \f
2473 /* Do what is necessary for `va_start'.  The argument is ignored;
2474    We look at the current function to determine if stdargs or varargs
2475    is used and fill in an initial va_list.  A pointer to this constructor
2476    is returned.  */
2477
2478 struct rtx_def *
2479 m88k_builtin_saveregs (arglist)
2480      tree arglist;
2481 {
2482   rtx block, addr, argsize;
2483   tree fntype = TREE_TYPE (current_function_decl);
2484   int argadj = ((!(TYPE_ARG_TYPES (fntype) != 0
2485                    && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
2486                        != void_type_node)))
2487                 ? -UNITS_PER_WORD : 0) + UNITS_PER_WORD - 1;
2488   int fixed;
2489   variable_args_p = 1;
2490
2491   if (CONSTANT_P (current_function_arg_offset_rtx))
2492     {
2493       fixed = (XINT (current_function_arg_offset_rtx, 0)
2494                + argadj) / UNITS_PER_WORD;
2495       argsize = gen_rtx (CONST_INT, VOIDmode, fixed);
2496     }
2497   else
2498     {
2499       fixed = 0;
2500       argsize = plus_constant (current_function_arg_offset_rtx, argadj);
2501       argsize = expand_shift (RSHIFT_EXPR, Pmode, argsize,
2502                               build_int_2 (2, 0), argsize, 0);
2503     }
2504
2505   /* Allocate the va_list constructor */
2506   block = assign_stack_local (BLKmode, 3 * UNITS_PER_WORD, BITS_PER_WORD);
2507   RTX_UNCHANGING_P (block) = 1;
2508   RTX_UNCHANGING_P (XEXP (block, 0)) = 1;
2509
2510   /* Store the argsize as the __va_arg member.  */
2511   emit_move_insn (change_address (block, SImode, XEXP (block, 0)),
2512                   argsize);
2513
2514   /* Store the arg pointer in the __va_stk member.  */
2515   emit_move_insn (change_address (block, Pmode,
2516                                   plus_constant (XEXP (block, 0),
2517                                                  UNITS_PER_WORD)),
2518                   copy_to_reg (virtual_incoming_args_rtx));
2519
2520   /* Allocate the register space, and store it as the __va_reg member.  */
2521   addr = assign_stack_local (BLKmode, 8 * UNITS_PER_WORD, -1);
2522   MEM_IN_STRUCT_P (addr) = 1;
2523   RTX_UNCHANGING_P (addr) = 1;
2524   RTX_UNCHANGING_P (XEXP (addr, 0)) = 1;
2525   emit_move_insn (change_address (block, Pmode,
2526                                   plus_constant (XEXP (block, 0),
2527                                                  2 * UNITS_PER_WORD)),
2528                   copy_to_reg (XEXP (addr, 0)));
2529
2530   /* Now store the incoming registers and return the address of the
2531      va_list constructor.  */
2532   if (fixed < 8)
2533       move_block_from_reg
2534         (2 + fixed,
2535          change_address (addr, Pmode,
2536                          plus_constant (XEXP (addr, 0),
2537                                         fixed * UNITS_PER_WORD)),
2538          8 - fixed);
2539
2540   return copy_to_reg (XEXP (block, 0));
2541 }
2542 \f
2543 /* If cmpsi has not been generated, emit code to do the test.  Return the
2544    expression describing the test of operator OP.  */
2545
2546 rtx
2547 emit_test (op, mode)
2548      enum rtx_code op;
2549      enum machine_mode mode;
2550 {
2551   if (m88k_compare_reg == 0)
2552     emit_insn (gen_test (m88k_compare_op0, m88k_compare_op1));
2553   return (gen_rtx (op, mode, m88k_compare_reg, const0_rtx));
2554 }
2555
2556 /* Determine how to best perform cmpsi/bxx, where cmpsi has a constant
2557    operand.  All tests with zero (albeit swapped) and all equality tests
2558    with a constant are done with bcnd.  The remaining cases are swapped
2559    as needed.  */
2560
2561 void
2562 emit_bcnd (op, label)
2563      enum rtx_code op;
2564      rtx label;
2565 {
2566   if (m88k_compare_op1 == const0_rtx)
2567     emit_jump_insn (optimize
2568                     ? gen_bxx (emit_test (op, VOIDmode), label)
2569                     : gen_bcnd (gen_rtx (op, VOIDmode,
2570                                          m88k_compare_op0, const0_rtx),
2571                                 label));
2572   else if (m88k_compare_op0 == const0_rtx)
2573     emit_jump_insn (optimize
2574                     ? gen_bxx (emit_test (op, VOIDmode), label)
2575                     : gen_bcnd (gen_rtx (swap_condition (op), VOIDmode,
2576                                          m88k_compare_op1, const0_rtx),
2577                                 label));
2578   else if (op != EQ && op != NE)
2579     emit_jump_insn (gen_bxx (emit_test (op, VOIDmode), label));
2580   else
2581     {
2582       rtx zero = gen_reg_rtx (SImode);
2583       rtx reg, constant;
2584       int value;
2585
2586       if (GET_CODE (m88k_compare_op1) == CONST_INT)
2587         {
2588           reg = force_reg (SImode, m88k_compare_op0);
2589           constant = m88k_compare_op1;
2590         }
2591       else
2592         {
2593           reg = force_reg (SImode, m88k_compare_op1);
2594           constant = m88k_compare_op0;
2595         }
2596       value = INTVAL (constant);
2597
2598       /* Perform an arithmetic computation to make the compared-to value
2599          zero, but avoid loosing if the bcnd is later changed into sxx.  */
2600       if (SMALL_INTVAL (value))
2601         emit_jump_insn (gen_bxx (emit_test (op, VOIDmode), label));
2602       else
2603         {
2604           if (SMALL_INTVAL (-value))
2605             emit_insn (gen_addsi3 (zero, reg,
2606                                    gen_rtx (CONST_INT, VOIDmode, -value)));
2607           else
2608             emit_insn (gen_xorsi3 (zero, reg, constant));
2609
2610           emit_jump_insn (gen_bcnd (gen_rtx (op, VOIDmode,
2611                                              zero, const0_rtx),
2612                                     label));
2613         }
2614     }
2615 }
2616 \f
2617 /* Print an operand.  Recognize special options, documented below.  */
2618
2619 void
2620 print_operand (file, x, code)
2621     FILE *file;
2622     rtx x;
2623     char code;
2624 {
2625   enum rtx_code xc = (x ? GET_CODE (x) : UNKNOWN);
2626   register int value = (xc == CONST_INT ? INTVAL (x) : 0);
2627   static int sequencep;
2628   static int reversep;
2629
2630   if (sequencep)
2631     {
2632       if (code < 'B' || code > 'E')
2633         output_operand_lossage ("%R not followed by %B/C/D/E");
2634       if (reversep)
2635         xc = reverse_condition (xc);
2636       sequencep = 0;
2637     }
2638
2639   switch (code)
2640     {
2641     case '*': /* addressing base register for PIC */
2642       fputs (reg_names[PIC_OFFSET_TABLE_REGNUM], file); return;
2643
2644     case '#': /* SVR4 pound-sign syntax character (empty if SVR3) */
2645       fputs (m88k_pound_sign, file); return;
2646
2647     case 'X': /* print the upper 16 bits... */
2648       value >>= 16;
2649     case 'x': /* print the lower 16 bits of the integer constant in hex */
2650       if (xc != CONST_INT)
2651         output_operand_lossage ("invalid %x/X value");
2652       fprintf (file, "0x%x", value & 0xffff); return;
2653
2654     case 'H': /* print the low 16 bits of the negated integer constant */
2655       if (xc != CONST_INT)
2656         output_operand_lossage ("invalid %H value");
2657       value = -value;
2658     case 'h': /* print the register or low 16 bits of the integer constant */
2659       if (xc == REG)
2660         goto reg;
2661       if (xc != CONST_INT)
2662         output_operand_lossage ("invalid %h value");
2663       fprintf (file, "%d", value & 0xffff);
2664       return;
2665
2666     case 'Q': /* print the low 8 bits of the negated integer constant */
2667       if (xc != CONST_INT)
2668         output_operand_lossage ("invalid %Q value");
2669       value = -value;
2670     case 'q': /* print the register or low 8 bits of the integer constant */
2671       if (xc == REG)
2672         goto reg;
2673       if (xc != CONST_INT)
2674         output_operand_lossage ("invalid %q value");
2675       fprintf (file, "%d", value & 0xff);
2676       return;
2677
2678     case 'w': /* print the integer constant (X == 32 ? 0 : 32 - X) */
2679       if (xc != CONST_INT)
2680         output_operand_lossage ("invalid %o value");
2681       fprintf (file, "%d", value == 32 ? 0 : 32 - value);
2682       return;
2683
2684     case 'p': /* print the logarithm of the integer constant */
2685       if (xc != CONST_INT
2686           || (value = exact_log2 (value)) < 0)
2687         output_operand_lossage ("invalid %p value");
2688       fprintf (file, "%d", value);
2689       return;
2690
2691     case 'S': /* compliment the value and then... */
2692       value = ~value;
2693     case 's': /* print the width and offset values forming the integer
2694                  constant with a SET instruction.  See integer_ok_for_set. */
2695       {
2696         register unsigned mask, uval = value;
2697         register int top, bottom;
2698
2699         if (xc != CONST_INT)
2700           output_operand_lossage ("invalid %s/S value");
2701         /* All the "one" bits must be contiguous.  If so, MASK will be
2702            a power of two or zero.  */
2703         mask = (uval | (uval - 1)) + 1;
2704         if (!(uval && POWER_OF_2_or_0 (mask)))
2705           output_operand_lossage ("invalid %s/S value");
2706         top = mask ? exact_log2 (mask) : 32;
2707         bottom = exact_log2 (uval & ~(uval - 1));
2708         fprintf (file,"%d<%d>", top - bottom, bottom);
2709         return;
2710       }
2711
2712     case 'P': /* print nothing if pc_rtx; output label_ref */
2713       if (xc == LABEL_REF)
2714         output_addr_const (file, x);
2715       else if (xc != PC)
2716         output_operand_lossage ("invalid %P operand");
2717       return;
2718
2719     case 'L': /* print 0 or 1 if operand is label_ref and then...  */
2720       fputc (xc == LABEL_REF ? '1' : '0', file);
2721     case '.': /* print .n if delay slot is used */
2722       fputs ((final_sequence
2723               && ! INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0)))
2724              ? ".n\t" : "\t", file);
2725       return;
2726
2727     case 'R': /* reverse the condition of the next print_operand
2728                  if operand is a label_ref.  */
2729       sequencep++;
2730       reversep = (xc == LABEL_REF);
2731       return;
2732
2733     case 'B': /* bcnd branch values */
2734       fputs (m88k_pound_sign, file);
2735       switch (xc)
2736         {
2737         case EQ: fputs ("eq0", file); return;
2738         case NE: fputs ("ne0", file); return;
2739         case GT: fputs ("gt0", file); return;
2740         case LE: fputs ("le0", file); return;
2741         case LT: fputs ("lt0", file); return;
2742         case GE: fputs ("ge0", file); return;
2743         default: output_operand_lossage ("invalid %B value");
2744         }
2745
2746     case 'C': /* bb0/bb1 branch values for comparisons */
2747       fputs (m88k_pound_sign, file);
2748       switch (xc)
2749         {
2750         case EQ:  fputs ("eq", file); return;
2751         case NE:  fputs ("ne", file); return;
2752         case GT:  fputs ("gt", file); return;
2753         case LE:  fputs ("le", file); return;
2754         case LT:  fputs ("lt", file); return;
2755         case GE:  fputs ("ge", file); return;
2756         case GTU: fputs ("hi", file); return;
2757         case LEU: fputs ("ls", file); return;
2758         case LTU: fputs ("lo", file); return;
2759         case GEU: fputs ("hs", file); return;
2760         default:  output_operand_lossage ("invalid %C value");
2761         }
2762
2763     case 'D': /* bcnd branch values for float comparisons */
2764       switch (xc)
2765         {
2766         case EQ: fputs ("0xa", file); return;
2767         case NE: fputs ("0x5", file); return;
2768         case GT: fputs (m88k_pound_sign, file);
2769           fputs ("gt0", file); return;
2770         case LE: fputs ("0xe", file); return;
2771         case LT: fputs ("0x4", file); return;
2772         case GE: fputs ("0xb", file); return;
2773         default: output_operand_lossage ("invalid %D value");
2774         }
2775
2776     case 'E': /* bcnd branch values for special integers */
2777       switch (xc)
2778         {
2779         case EQ: fputs ("0x8", file); return;
2780         case NE: fputs ("0x7", file); return;
2781         default: output_operand_lossage ("invalid %E value");
2782         }
2783
2784     case 'd': /* second register of a two register pair */
2785       if (xc != REG)
2786         output_operand_lossage ("`%d' operand isn't a register");
2787       fputs (reg_names[REGNO (x) + 1], file);
2788       return;
2789
2790     case 'r': /* an immediate 0 should be represented as `r0' */
2791       if (x == const0_rtx)
2792         {
2793           fputs (reg_names[0], file);
2794           return;
2795         }
2796       else if (xc != REG)
2797         output_operand_lossage ("invalid %r value");
2798     case 0:
2799     name:
2800       if (xc == REG)
2801         {
2802         reg:
2803           if (REGNO (x) == ARG_POINTER_REGNUM)
2804             output_operand_lossage ("operand is r0");
2805           else
2806             fputs (reg_names[REGNO (x)], file);
2807         }
2808       else if (xc == PLUS)
2809         output_address (x);
2810       else if (xc == MEM)
2811         output_address (XEXP (x, 0));
2812       else if (xc == CONST_DOUBLE)
2813         output_operand_lossage ("operand is const_double");
2814       else
2815         output_addr_const (file, x);
2816       return;
2817
2818     case 'g': /* append #got_rel as needed */
2819       if (flag_pic && (xc == SYMBOL_REF || xc == LABEL_REF))
2820         {
2821           output_addr_const (file, x);
2822           fputs ("#got_rel", file);
2823           return;
2824         }
2825       goto name;
2826
2827     case 'a': /* (standard), assume operand is an address */
2828     case 'c': /* (standard), assume operand is an immediate value */
2829     case 'l': /* (standard), assume operand is a label_ref */
2830     case 'n': /* (standard), like %c, except negate first */
2831     default:
2832       output_operand_lossage ("invalid code");
2833     }
2834 }
2835
2836 void
2837 print_operand_address (file, addr)
2838     FILE *file;
2839     rtx addr;
2840 {
2841   register rtx reg0, reg1, temp;
2842
2843   switch (GET_CODE (addr))
2844     {
2845     case REG:
2846       if (REGNO (addr) == ARG_POINTER_REGNUM)
2847         abort ();
2848       else
2849         fprintf (file, "%s,%s", reg_names[0], reg_names [REGNO (addr)]);
2850       break;
2851
2852     case LO_SUM:
2853       fprintf (file, "%s,%slo16(",
2854                reg_names[REGNO (XEXP (addr, 0))], m88k_pound_sign);
2855       output_addr_const (file, XEXP (addr, 1));
2856       fputc (')', file);
2857       break;
2858
2859     case PLUS:
2860       reg0 = XEXP (addr, 0);
2861       reg1 = XEXP (addr, 1);
2862       if (GET_CODE (reg0) == MULT || GET_CODE (reg0) == CONST_INT)
2863         {
2864           rtx tmp = reg0;
2865           reg0 = reg1;
2866           reg1 = tmp;
2867         }
2868
2869       if ((REG_P (reg0) && REGNO (reg0) == ARG_POINTER_REGNUM)
2870           || (REG_P (reg1) && REGNO (reg1) == ARG_POINTER_REGNUM))
2871         abort ();
2872
2873       else if (REG_P (reg0))
2874         {
2875           if (REG_P (reg1))
2876             fprintf (file, "%s,%s",
2877                      reg_names [REGNO (reg0)], reg_names [REGNO (reg1)]);
2878
2879           else if (GET_CODE (reg1) == CONST_INT)
2880             fprintf (file, "%s,%d",
2881                      reg_names [REGNO (reg0)], INTVAL (reg1));
2882
2883           else if (GET_CODE (reg1) == MULT)
2884             {
2885               rtx mreg = XEXP (reg1, 0);
2886               if (REGNO (mreg) == ARG_POINTER_REGNUM)
2887                 abort ();
2888
2889               fprintf (file, "%s[%s]", reg_names[REGNO (reg0)],
2890                        reg_names[REGNO (mreg)]);
2891             }
2892
2893           else if (GET_CODE (reg1) == ZERO_EXTRACT)
2894             {
2895               fprintf (file, "%s,%slo16(",
2896                        reg_names[REGNO (reg0)], m88k_pound_sign);
2897               output_addr_const (file, XEXP (reg1, 0));
2898               fputc (')', file);
2899             }
2900
2901           else if (flag_pic)
2902             {
2903               fprintf (file, "%s,", reg_names[REGNO (reg0)]);
2904               output_addr_const (file, reg1);
2905               fputs ("#got_rel", file);
2906             }
2907           else abort ();
2908         }
2909
2910       else
2911         abort ();
2912       break;
2913
2914     case MULT:
2915       if (REGNO (XEXP (addr, 0)) == ARG_POINTER_REGNUM)
2916         abort ();
2917
2918       fprintf (file, "%s[%s]",
2919                reg_names[0], reg_names[REGNO (XEXP (addr, 0))]);
2920       break;
2921
2922     case LSHIFT:
2923       fprintf (file, "%s,%shi16(", reg_names[0], m88k_pound_sign);
2924       output_addr_const (file, XEXP (addr, 0));
2925       fputc (')', file);
2926       break;
2927
2928     case CONST_INT:
2929       fprintf (file, "%s,%d", reg_names[0], INTVAL (addr));
2930       break;
2931
2932     default:
2933       fprintf (file, "%s,", reg_names[0]);
2934       if (SHORT_ADDRESS_P (addr, temp))
2935         {
2936           fprintf (file, "%siw16(", m88k_pound_sign);
2937           output_addr_const (file, addr);
2938           fputc (')', file);
2939         }
2940       else
2941           output_addr_const (file, addr);
2942     }
2943 }