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