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