OSDN Git Service

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