OSDN Git Service

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