OSDN Git Service

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