1 /* Subroutines for insn-output.c for Motorola 88000.
2 Copyright (C) 1988, 1989, 1990, 1991 Free Software Foundation, Inc.
3 Contributed by Michael Tiemann (tiemann@mcc.com)
4 Enhanced by Michael Meissner (meissner@osf.org)
5 Currently supported by Tom Wood (wood@dg-rtp.dg.com)
7 This file is part of GNU CC.
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)
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.
19 You should have received a copy of the GNU General Public License
20 along with GNU CC; see the file COPYING. If not, write to
21 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
24 #include <sys/types.h>
31 #include "hard-reg-set.h"
33 #include "insn-config.h"
34 #include "conditions.h"
35 #include "insn-flags.h"
37 #include "insn-attr.h"
43 extern char *version_string;
44 extern time_t time ();
45 extern char *ctime ();
46 extern int flag_traditional;
47 extern FILE *asm_out_file;
49 static char out_sccs_id[] = "@(#)m88k.c 2.1.3.1 07 Apr 1992 17:23:59";
50 static char tm_sccs_id [] = TM_SCCS_ID;
52 char *m88k_pound_sign = ""; /* Either # for SVR4 or empty for SVR3 */
53 char *m88k_short_data;
55 int m88k_gp_threshold;
56 int m88k_prologue_done = 0; /* Ln directives can now be emitted */
57 int m88k_function_number = 0; /* Counter unique to each function */
58 int m88k_fp_offset = 0; /* offset of frame pointer if used */
59 int m88k_stack_size = 0; /* size of allocated stack (including frame) */
62 rtx m88k_compare_reg; /* cmp output pseudo register */
63 rtx m88k_compare_op0; /* cmpsi operand 0 */
64 rtx m88k_compare_op1; /* cmpsi operand 1 */
66 enum attr_cpu m88k_cpu; /* target cpu */
68 /* Determine what instructions are needed to manufacture the integer VALUE
72 classify_integer (mode, value)
73 enum machine_mode mode;
80 else if (SMALL_INTVAL (value))
82 else if (SMALL_INTVAL (-value))
84 else if (mode == HImode)
86 else if (mode == QImode)
88 else if ((value & 0xffff) == 0)
90 else if (integer_ok_for_set (value))
97 integer_ok_for_set (value)
98 register unsigned value;
100 /* All the "one" bits must be contiguous. If so, MASK + 1 will be
101 a power of two or zero. */
102 register unsigned mask = (value | (value - 1));
103 return (value && POWER_OF_2_or_0 (mask + 1));
107 output_load_const_int (mode, operands)
108 enum machine_mode mode;
111 static char *patterns[] =
119 "or.u %0,%#r0,%X1\n\tor %0,%0,%x1",
122 if (! REG_P (operands[0])
123 || GET_CODE (operands[1]) != CONST_INT)
125 return patterns[classify_integer (mode, INTVAL (operands[1]))];
128 /* These next two routines assume that floating point numbers are represented
129 in a manner which is consistent between host and target machines. */
132 output_load_const_float (operands)
135 /* These can return 0 under some circumstances when cross-compiling. */
136 operands[0] = operand_subword (operands[0], 0, 0, SFmode);
137 operands[1] = operand_subword (operands[1], 0, 0, SFmode);
139 return output_load_const_int (SImode, operands);
143 output_load_const_double (operands)
148 /* These can return zero on some cross-compilers, but there's nothing
149 we can do about it. */
150 latehalf[0] = operand_subword (operands[0], 1, 0, DFmode);
151 latehalf[1] = operand_subword (operands[1], 1, 0, DFmode);
153 operands[0] = operand_subword (operands[0], 0, 0, DFmode);
154 operands[1] = operand_subword (operands[1], 0, 0, DFmode);
156 output_asm_insn (output_load_const_int (SImode, operands), operands);
158 operands[0] = latehalf[0];
159 operands[1] = latehalf[1];
161 return output_load_const_int (SImode, operands);
165 output_load_const_dimode (operands)
170 latehalf[0] = operand_subword (operands[0], 1, 0, DImode);
171 latehalf[1] = operand_subword (operands[1], 1, 0, DImode);
173 operands[0] = operand_subword (operands[0], 0, 0, DImode);
174 operands[1] = operand_subword (operands[1], 0, 0, DImode);
176 output_asm_insn (output_load_const_int (SImode, operands), operands);
178 operands[0] = latehalf[0];
179 operands[1] = latehalf[1];
181 return output_load_const_int (SImode, operands);
184 /* Emit insns to move operands[1] into operands[0].
186 Return 1 if we have written out everything that needs to be done to
187 do the move. Otherwise, return 0 and the caller will emit the move
191 emit_move_sequence (operands, mode)
193 enum machine_mode mode;
195 register rtx operand0 = operands[0];
196 register rtx operand1 = operands[1];
198 /* Handle most common case first: storing into a register. */
199 if (register_operand (operand0, mode))
201 if (register_operand (operand1, mode)
202 || (GET_CODE (operand1) == CONST_INT && SMALL_INT (operand1))
203 || GET_CODE (operand1) == HIGH
204 /* Only `general_operands' can come here, so MEM is ok. */
205 || GET_CODE (operand1) == MEM)
207 /* Run this case quickly. */
208 emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1));
212 else if (GET_CODE (operand0) == MEM)
214 if (register_operand (operand1, mode)
215 || (operand1 == const0_rtx && GET_MODE_SIZE (mode) <= UNITS_PER_WORD))
217 /* Run this case quickly. */
218 emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1));
221 if (! reload_in_progress && ! reload_completed)
223 operands[0] = validize_mem (operand0);
224 operands[1] = operand1 = force_reg (mode, operand1);
228 /* Simplify the source if we need to. */
229 if (GET_CODE (operand1) != HIGH && immediate_operand (operand1, mode))
231 if (GET_CODE (operand1) != CONST_INT
232 && GET_CODE (operand1) != CONST_DOUBLE)
234 rtx temp = ((reload_in_progress || reload_completed)
235 ? operand0 : gen_reg_rtx (Pmode));
236 operands[1] = legitimize_address (flag_pic
237 && symbolic_address_p (operand1),
240 operands[1] = gen_rtx (SUBREG, mode, operands[1], 0);
244 /* Now have insn-emit do whatever it normally does. */
248 /* Return a legitimate reference for ORIG (either an address or a MEM) using
249 the register REG. If PIC and the address is already position-independent,
253 legitimize_address (pic, orig, reg)
258 rtx addr = (GET_CODE (orig) == MEM ? XEXP (orig, 0) : orig);
264 if (GET_CODE (addr) == SYMBOL_REF
265 || GET_CODE (addr) == LABEL_REF)
267 if (reg == 0) abort ();
271 emit_insn (gen_rtx (SET, VOIDmode,
272 reg, gen_rtx (HIGH, SImode, addr)));
273 emit_insn (gen_rtx (SET, VOIDmode,
274 reg, gen_rtx (LO_SUM, SImode, reg, addr)));
277 new = gen_rtx (MEM, Pmode,
278 gen_rtx (PLUS, SImode,
279 pic_offset_table_rtx, addr));
280 current_function_uses_pic_offset_table = 1;
281 RTX_UNCHANGING_P (new) = 1;
283 rtx insn = emit_move_insn (reg, new);
284 /* Put a REG_EQUAL note on this insn, so that it can be optimized
286 REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUAL, orig,
291 else if (GET_CODE (addr) == CONST)
295 if (GET_CODE (XEXP (addr, 0)) == PLUS
296 && XEXP (XEXP (addr, 0), 0) == pic_offset_table_rtx)
302 if (GET_CODE (XEXP (addr, 0)) != PLUS) abort ();
304 base = legitimize_address (1, XEXP (XEXP (addr, 0), 0), reg);
305 addr = legitimize_address (1, XEXP (XEXP (addr, 0), 1),
306 base == reg ? 0 : reg);
308 if (GET_CODE (addr) == CONST_INT)
309 new = plus_constant_for_output (base, INTVAL (addr));
311 new = gen_rtx (PLUS, SImode, base, addr);
312 /* Should we set special REG_NOTEs here? */
315 else if (! SHORT_ADDRESS_P (addr, temp))
317 emit_insn (gen_rtx (SET, VOIDmode,
318 reg, gen_rtx (HIGH, SImode, addr)));
319 new = gen_rtx (LO_SUM, SImode, reg, addr);
323 && GET_CODE (orig) == MEM)
325 new = gen_rtx (MEM, GET_MODE (orig), new);
326 RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (orig);
327 MEM_VOLATILE_P (new) = MEM_VOLATILE_P (orig);
328 MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (orig);
333 /* Support functions for code to emit a block move. There are four methods
334 used to perform the block move:
336 + call the looping library function, e.g. __movstrSI64n8
337 + call a non-looping library function, e.g. __movstrHI15x11
338 + produce an inline sequence of ld/st instructions
340 The parameters below describe the library functions produced by
343 #define MOVSTR_LOOP 64 /* __movstrSI64n68 .. __movstrSI64n8 */
344 #define MOVSTR_QI 16 /* __movstrQI16x16 .. __movstrQI16x2 */
345 #define MOVSTR_HI 48 /* __movstrHI48x48 .. __movstrHI48x4 */
346 #define MOVSTR_SI 96 /* __movstrSI96x96 .. __movstrSI96x8 */
347 #define MOVSTR_ODD_SI 48 /* __movstrSI47x47 .. __movstrSI47x11,
348 __movstrSI46x46 .. __movstrSI46x10,
349 __movstrSI45x45 .. __movstrSI45x9 */
350 #define MOVSTR_ODD_HI 16 /* __movstrHI15x15 .. __movstrHI15x5 */
352 /* Break even points where memcpy will do just as well. */
353 #define MOVSTR_QI_LIMIT 13
354 #define MOVSTR_HI_LIMIT 38
355 #define MOVSTR_SI_LIMIT MOVSTR_SI
357 static enum machine_mode mode_from_bytes[] =
358 {VOIDmode, QImode, HImode, VOIDmode, SImode};
359 static int max_from_bytes[] = {0, MOVSTR_QI, MOVSTR_HI, 0, MOVSTR_SI};
360 static int all_from_bytes[] = {0, MOVSTR_QI, MOVSTR_ODD_HI, 0, MOVSTR_ODD_SI};
361 static int best_from_bytes[] =
362 {0, MOVSTR_QI_LIMIT, MOVSTR_HI_LIMIT, 0, MOVSTR_SI_LIMIT};
364 static void block_move_loop ();
365 static void block_move_no_loop ();
366 static void block_move_sequence ();
368 /* Emit code to perform a block move. Choose the best method.
370 OPERANDS[0] is the destination.
371 OPERANDS[1] is the source.
372 OPERANDS[2] is the size.
373 OPERANDS[3] is the alignment safe to use. */
376 expand_block_move (dest_mem, src_mem, operands)
381 int align = INTVAL (operands[3]);
382 int constp = (GET_CODE (operands[2]) == CONST_INT);
383 int bytes = (constp ? INTVAL (operands[2]) : 0);
385 if (constp && bytes <= 0)
388 /* Determine machine mode to do move with. */
391 else if (align <= 0 || align == 3)
392 abort (); /* block move invalid alignment. */
394 if (constp && bytes <= 3 * align)
395 block_move_sequence (operands[0], dest_mem, operands[1], src_mem,
398 else if (constp && bytes <= best_from_bytes[align])
399 block_move_no_loop (operands[0], dest_mem, operands[1], src_mem,
402 else if (constp && align == 4)
403 block_move_loop (operands[0], dest_mem, operands[1], src_mem,
408 #ifdef TARGET_MEM_FUNCTIONS
409 emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), 0,
413 operands[2], SImode);
415 emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcopy"), 0,
419 operands[2], SImode);
424 /* Emit code to perform a block move by calling a looping movstr library
425 function. SIZE and ALIGN are known constants. DEST and SRC are
429 block_move_loop (dest, dest_mem, src, src_mem, size, align)
435 enum machine_mode mode;
444 /* Determine machine mode to do move with. */
448 /* Determine the structure of the loop. */
449 count = size / MOVSTR_LOOP;
450 units = (size - count * MOVSTR_LOOP) / align;
455 units += MOVSTR_LOOP / align;
460 block_move_no_loop (dest, dest_mem, src, src_mem, size, align);
464 remainder = size - count * MOVSTR_LOOP - units * align;
466 mode = mode_from_bytes[align];
467 sprintf (entry, "__movstr%s%dn%d",
468 GET_MODE_NAME (mode), MOVSTR_LOOP, units * align);
469 entry_name = get_identifier (entry);
471 offset_rtx = gen_rtx (CONST_INT, VOIDmode,
472 MOVSTR_LOOP + (1 - units) * align);
474 value_rtx = gen_rtx (MEM, mode,
475 gen_rtx (PLUS, Pmode,
476 gen_rtx (REG, Pmode, 3),
478 RTX_UNCHANGING_P (value_rtx) = RTX_UNCHANGING_P (src_mem);
479 MEM_VOLATILE_P (value_rtx) = MEM_VOLATILE_P (src_mem);
480 MEM_IN_STRUCT_P (value_rtx) = MEM_IN_STRUCT_P (src_mem);
482 emit_insn (gen_call_block_move_loop
483 (gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (entry_name)),
484 dest, src, offset_rtx, value_rtx,
485 gen_rtx (REG, GET_MODE (value_rtx), ((units & 1) ? 4 : 5)),
486 gen_rtx (CONST_INT, VOIDmode, count)));
489 block_move_sequence (gen_rtx (REG, Pmode, 2), dest_mem,
490 gen_rtx (REG, Pmode, 3), src_mem,
491 remainder, align, MOVSTR_LOOP + align);
494 /* Emit code to perform a block move by calling a non-looping library
495 function. SIZE and ALIGN are known constants. DEST and SRC are
496 registers. OFFSET is the known starting point for the output pattern. */
499 block_move_no_loop (dest, dest_mem, src, src_mem, size, align)
505 enum machine_mode mode = mode_from_bytes[align];
506 int units = size / align;
507 int remainder = size - units * align;
515 if (remainder && size <= all_from_bytes[align])
517 most = all_from_bytes[align] - (align - remainder);
522 most = max_from_bytes[align];
525 sprintf (entry, "__movstr%s%dx%d",
526 GET_MODE_NAME (mode), most, size - remainder);
527 entry_name = get_identifier (entry);
529 offset_rtx = gen_rtx (CONST_INT, VOIDmode, most - (size - remainder));
531 value_rtx = gen_rtx (MEM, mode,
532 gen_rtx (PLUS, Pmode,
533 gen_rtx (REG, Pmode, 3),
535 RTX_UNCHANGING_P (value_rtx) = RTX_UNCHANGING_P (src_mem);
536 MEM_VOLATILE_P (value_rtx) = MEM_VOLATILE_P (src_mem);
537 MEM_IN_STRUCT_P (value_rtx) = MEM_IN_STRUCT_P (src_mem);
539 evenp = ((most - (size - remainder)) / align) & 1;
541 emit_insn (gen_call_block_move
542 (gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (entry_name)),
543 dest, src, offset_rtx, value_rtx,
544 gen_rtx (REG, GET_MODE (value_rtx), (evenp ? 4 : 5))));
547 block_move_sequence (gen_rtx (REG, Pmode, 2), dest_mem,
548 gen_rtx (REG, Pmode, 3), src_mem,
549 remainder, align, most);
552 /* Emit code to perform a block move with an offset sequence of ld/st
553 instructions (..., ld 0, st 1, ld 1, st 0, ...). SIZE and ALIGN are
554 known constants. DEST and SRC are registers. OFFSET is the known
555 starting point for the output pattern. */
558 block_move_sequence (dest, dest_mem, src, src_mem, size, align, offset)
566 enum machine_mode mode[2];
571 int offset_ld = offset;
572 int offset_st = offset;
574 active[0] = active[1] = FALSE;
576 /* Establish parameters for the first load and for the second load if
577 it is known to be the same mode as the first. */
578 amount[0] = amount[1] = align;
579 mode[0] = mode_from_bytes[align];
580 temp[0] = gen_reg_rtx (mode[0]);
581 if (size >= 2 * align)
584 temp[1] = gen_reg_rtx (mode[1]);
595 /* Change modes as the sequence tails off. */
596 if (size < amount[next])
598 amount[next] = (size >= 2 ? 2 : 1);
599 mode[next] = mode_from_bytes[amount[next]];
600 temp[next] = gen_reg_rtx (mode[next]);
602 size -= amount[next];
603 srcp = gen_rtx (MEM, mode[next],
604 gen_rtx (PLUS, Pmode, src,
605 gen_rtx (CONST_INT, SImode, offset_ld)));
606 RTX_UNCHANGING_P (srcp) = RTX_UNCHANGING_P (src_mem);
607 MEM_VOLATILE_P (srcp) = MEM_VOLATILE_P (src_mem);
608 MEM_IN_STRUCT_P (srcp) = MEM_IN_STRUCT_P (src_mem);
609 emit_move_insn (temp[next], srcp);
610 offset_ld += amount[next];
616 active[phase] = FALSE;
617 dstp = gen_rtx (MEM, mode[phase],
618 gen_rtx (PLUS, Pmode, dest,
619 gen_rtx (CONST_INT, SImode, offset_st)));
620 RTX_UNCHANGING_P (dstp) = RTX_UNCHANGING_P (dest_mem);
621 MEM_VOLATILE_P (dstp) = MEM_VOLATILE_P (dest_mem);
622 MEM_IN_STRUCT_P (dstp) = MEM_IN_STRUCT_P (dest_mem);
623 emit_move_insn (dstp, temp[phase]);
624 offset_st += amount[phase];
627 while (active[next]);
630 /* Emit the code to do an AND operation. */
633 output_and (operands)
638 if (REG_P (operands[2]))
639 return "and %0,%1,%2";
641 value = INTVAL (operands[2]);
642 if (SMALL_INTVAL (value))
643 return "mask %0,%1,%2";
644 else if ((value & 0xffff0000) == 0xffff0000)
645 return "and %0,%1,%x2";
646 else if ((value & 0xffff) == 0xffff)
647 return "and.u %0,%1,%X2";
648 else if ((value & 0xffff) == 0)
649 return "mask.u %0,%1,%X2";
650 else if (integer_ok_for_set (~value))
651 return "clr %0,%1,%S2";
653 return "and.u %0,%1,%X2\n\tand %0,%0,%x2";
656 /* Emit the code to do an inclusive OR operation. */
659 output_ior (operands)
664 if (REG_P (operands[2]))
665 return "or %0,%1,%2";
667 value = INTVAL (operands[2]);
668 if (SMALL_INTVAL (value))
669 return "or %0,%1,%2";
670 else if ((value & 0xffff) == 0)
671 return "or.u %0,%1,%X2";
672 else if (integer_ok_for_set (value))
673 return "set %0,%1,%s2";
675 return "or.u %0,%1,%X2\n\tor %0,%0,%x2";
678 /* Emit the instructions for doing an XOR. */
681 output_xor (operands)
686 if (REG_P (operands[2]))
687 return "xor %0,%1,%2";
689 value = INTVAL (operands[2]);
690 if (SMALL_INTVAL (value))
691 return "xor %0,%1,%2";
692 else if ((value & 0xffff) == 0)
693 return "xor.u %0,%1,%X2";
695 return "xor.u %0,%1,%X2\n\txor %0,%0,%x2";
698 /* Output a call. Normally this is just bsr or jsr, but this also deals with
699 accomplishing a branch after the call by incrementing r1. This requires
700 that various assembler bugs be accommodated. The 4.30 DG/UX assembler
701 requires that forward references not occur when computing the difference of
702 two labels. The [version?] Motorola assembler computes a word difference.
703 No doubt there's more to come!
705 It would seem the same idea could be used to tail call, but in this case,
706 the epilogue will be non-null. */
708 static rtx sb_name = 0;
709 static rtx sb_high = 0;
710 static rtx sb_low = 0;
713 output_call (operands, addr)
722 /* This can be generalized, but there is currently no need. */
723 if (XVECLEN (final_sequence, 0) != 2)
726 jump = XVECEXP (final_sequence, 0, 1);
727 if (GET_CODE (jump) == JUMP_INSN)
731 rtx dest = XEXP (SET_SRC (PATTERN (jump)), 0);
732 int delta = 4 * (insn_addresses[INSN_UID (dest)]
733 - insn_addresses[INSN_UID (jump)]);
734 #if (MONITOR_GCC & 0x2) /* How often do long branches happen? */
735 if ((unsigned) (delta + 0x8000) >= 0x10000)
736 warning ("Internal gcc monitor: short-branch(%x)", delta);
739 /* Delete the jump. */
740 PUT_CODE (jump, NOTE);
741 NOTE_LINE_NUMBER (jump) = NOTE_INSN_DELETED;
742 NOTE_SOURCE_FILE (jump) = 0;
744 /* If we loose, we must use the non-delay form. This is unlikely
745 to ever happen. If it becomes a problem, claim that a call
746 has two delay slots and only the second can be filled with
748 #ifdef AS_BUG_IMMEDIATE_LABEL /* The assembler restricts immediate values. */
749 if (! ADD_INTVAL (delta * 2))
751 if (! ADD_INTVAL (delta))
758 ? "bsr %0#plt\n\tbr %l1"
759 : "bsr %0\n\tbr %l1"));
762 /* Output the short branch form. */
763 output_asm_insn ((REG_P (addr)
765 : (flag_pic ? "bsr.n %0#plt" : "bsr.n %0")),
768 operands[0] = gen_label_rtx ();
769 operands[1] = gen_label_rtx ();
774 last = "subu %#r1,%#r1,%l0\n%l1:";
780 last = "addu %#r1,%#r1,%l0\n%l1:";
783 /* Record the values to be computed later as "def name,high-low". */
784 sb_name = gen_rtx (EXPR_LIST, VOIDmode, operands[0], sb_name);
785 sb_high = gen_rtx (EXPR_LIST, VOIDmode, high, sb_high);
786 sb_low = gen_rtx (EXPR_LIST, VOIDmode, low, sb_low);
793 : (flag_pic ? "bsr%. %0#plt" : "bsr%. %0"));
797 output_short_branch_defs (stream)
800 char name[256], high[256], low[256];
802 for (; sb_name && sb_high && sb_low;
803 sb_name = XEXP (sb_name, 1),
804 sb_high = XEXP (sb_high, 1),
805 sb_low = XEXP (sb_low, 1))
807 ASM_GENERATE_INTERNAL_LABEL
808 (name, "L", CODE_LABEL_NUMBER (XEXP (sb_name, 0)));
809 ASM_GENERATE_INTERNAL_LABEL
810 (high, "L", CODE_LABEL_NUMBER (XEXP (sb_high, 0)));
811 ASM_GENERATE_INTERNAL_LABEL
812 (low, "L", CODE_LABEL_NUMBER (XEXP (sb_low, 0)));
813 /* This will change as the assembler requirements become known. */
814 fprintf (stream, "\t%s\t %s,%s-%s\n",
815 DEF_ASM_OP, &name[1], &high[1], &low[1]);
817 if (sb_name || sb_high || sb_low)
821 /* Report errors on floating point, if we are given NaN's, or such. Leave
822 the number as is, though, since we output the number in hex, and the
823 assembler won't choke on it. */
826 check_float_value (mode, value)
827 enum machine_mode mode;
828 REAL_VALUE_TYPE value;
834 unsigned exponent : 11;
835 unsigned mantissa1 : 20;
843 if (u.s.mantissa1 != 0 || u.s.mantissa2 != 0)
845 if (u.s.exponent == 0x7ff) /* Not a Number */
846 warning ("floating point number is not valid for IEEE double precision");
847 else if (u.s.exponent == 0)
848 warning ("denormalized double precision floating point number");
851 else if (mode == SFmode)
853 u.d = REAL_VALUE_TRUNCATE (mode, value);
854 if (u.s.mantissa1 != 0 || u.s.mantissa2 != 0)
856 if (u.s.exponent == 0x7ff) /* Not a Number */
857 warning ("floating point number is not valid for IEEE double precision");
858 else if (u.s.exponent == 0)
859 warning ("denormalized single precision floating point number");
861 else if (u.s.exponent == 0x7ff) /* Infinity */
862 warning ("floating point number exceeds range of `float'");
866 /* Return true if the operand is a power of two and is a floating
867 point type (to optimize division by power of two into multiplication). */
870 real_power_of_2_operand (op, mode)
872 enum machine_mode mode;
876 int i[sizeof (REAL_VALUE_TYPE) / sizeof (int)];
877 struct { /* IEEE double precision format */
879 unsigned exponent : 11;
880 unsigned mantissa1 : 20;
883 struct { /* IEEE double format to quick check */
884 unsigned sign : 1; /* if it fits in a float */
885 unsigned exponent1 : 4;
886 unsigned exponent2 : 7;
887 unsigned mantissa1 : 20;
892 if (GET_MODE (op) != DFmode && GET_MODE (op) != SFmode)
895 if (GET_CODE (op) != CONST_DOUBLE)
898 u.i[0] = CONST_DOUBLE_LOW (op);
899 u.i[1] = CONST_DOUBLE_HIGH (op);
901 if (u.s.mantissa1 != 0 || u.s.mantissa2 != 0 /* not a power of two */
902 || u.s.exponent == 0 /* constant 0.0 */
903 || u.s.exponent == 0x7ff /* NAN */
904 || (u.s2.exponent1 != 0x8 && u.s2.exponent1 != 0x7))
905 return 0; /* const won't fit in float */
910 /* Make OP legitimate for mode MODE. Currently this only deals with DFmode
911 operands, putting them in registers and making CONST_DOUBLE values
912 SFmode where possible. */
915 legitimize_operand (op, mode)
917 enum machine_mode mode;
921 union real_extract r;
922 struct { /* IEEE double precision format */
924 unsigned exponent : 11;
925 unsigned mantissa1 : 20;
928 struct { /* IEEE double format to quick check */
929 unsigned sign : 1; /* if it fits in a float */
930 unsigned exponent1 : 4;
931 unsigned exponent2 : 7;
932 unsigned mantissa1 : 20;
937 if (GET_CODE (op) == REG || mode != DFmode)
940 if (GET_CODE (op) == CONST_DOUBLE)
942 bcopy (&CONST_DOUBLE_LOW (op), &u.r, sizeof u);
943 if (u.d.exponent != 0x7ff /* NaN */
944 && u.d.mantissa2 == 0 /* Mantissa fits */
945 && (u.s.exponent1 == 0x8 || u.s.exponent1 == 0x7) /* Exponent fits */
946 && (temp = simplify_unary_operation (FLOAT_TRUNCATE, SFmode,
948 return gen_rtx (FLOAT_EXTEND, mode, force_reg (SFmode, temp));
950 else if (register_operand (op, mode))
953 return force_reg (mode, op);
956 /* Return true if OP is a suitable input for a move insn. */
959 move_operand (op, mode)
961 enum machine_mode mode;
963 if (register_operand (op, mode))
965 if (GET_CODE (op) == CONST_INT)
966 return (classify_integer (mode, INTVAL (op)) < m88k_oru_hi16);
967 if (GET_MODE (op) != mode)
969 if (GET_CODE (op) == SUBREG)
970 op = SUBREG_REG (op);
971 if (GET_CODE (op) != MEM)
975 if (GET_CODE (op) == LO_SUM)
976 return (REG_P (XEXP (op, 0))
977 && symbolic_address_p (XEXP (op, 1)));
978 return memory_address_p (mode, op);
981 /* Return true if OP is suitable for a call insn. */
984 call_address_operand (op, mode)
986 enum machine_mode mode;
988 return (REG_P (op) || symbolic_address_p (op));
991 /* Returns true if OP is either a symbol reference or a sum of a symbol
992 reference and a constant. */
995 symbolic_address_p (op)
998 switch (GET_CODE (op))
1006 return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1007 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1008 && GET_CODE (XEXP (op, 1)) == CONST_INT);
1015 /* Return true if OP is a register or const0_rtx. */
1018 reg_or_0_operand (op, mode)
1020 enum machine_mode mode;
1022 return (op == const0_rtx || register_operand (op, mode));
1025 /* Nonzero if OP is a valid second operand for an arithmetic insn. */
1028 arith_operand (op, mode)
1030 enum machine_mode mode;
1032 return (register_operand (op, mode)
1033 || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));
1036 /* Return true if OP is a register or 5 bit integer. */
1039 arith5_operand (op, mode)
1041 enum machine_mode mode;
1043 return (register_operand (op, mode)
1044 || (GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 32));
1048 arith32_operand (op, mode)
1050 enum machine_mode mode;
1052 return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
1056 arith64_operand (op, mode)
1058 enum machine_mode mode;
1060 return (register_operand (op, mode)
1061 || GET_CODE (op) == CONST_INT
1062 || (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DImode));
1066 int5_operand (op, mode)
1068 enum machine_mode mode;
1070 return (GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 32);
1074 int32_operand (op, mode)
1076 enum machine_mode mode;
1078 return (GET_CODE (op) == CONST_INT);
1081 /* Return true if OP is a register or a valid immediate operand for
1085 add_operand (op, mode)
1087 enum machine_mode mode;
1089 return (register_operand (op, mode)
1090 || (GET_CODE (op) == CONST_INT && ADD_INT (op)));
1093 /* Nonzero if this is a bitmask filling the bottom bits, for optimizing and +
1094 shift left combinations into a single mak instruction. */
1100 return (value && POWER_OF_2_or_0 (value + 1));
1104 reg_or_bbx_mask_operand (op, mode)
1106 enum machine_mode mode;
1109 if (register_operand (op, mode))
1111 if (GET_CODE (op) != CONST_INT)
1114 value = INTVAL (op);
1115 if (POWER_OF_2 (value))
1121 /* Return true if OP is valid to use in the context of a floating
1122 point operation. Special case 0.0, since we can use r0. */
1125 real_or_0_operand (op, mode)
1127 enum machine_mode mode;
1129 if (mode != SFmode && mode != DFmode)
1132 return (register_operand (op, mode)
1133 || (GET_CODE (op) == CONST_DOUBLE
1134 && op == CONST0_RTX (mode)));
1137 /* Return true if OP is a relational operator. */
1142 enum machine_mode mode;
1144 switch (GET_CODE (op))
1162 /* Return true if OP is a relational operator, and is not an unsigned
1163 relational operator. */
1166 relop_no_unsigned (op, mode)
1168 enum machine_mode mode;
1170 switch (GET_CODE (op))
1178 /* @@ What is this test doing? Why not use `mode'? */
1179 if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT
1180 || GET_MODE (op) == DImode
1181 || GET_MODE_CLASS (GET_MODE (XEXP (op, 0))) == MODE_FLOAT
1182 || GET_MODE (XEXP (op, 0)) == DImode
1183 || GET_MODE_CLASS (GET_MODE (XEXP (op, 1))) == MODE_FLOAT
1184 || GET_MODE (XEXP (op, 1)) == DImode)
1192 /* Return true if the code of this rtx pattern is EQ or NE. */
1195 equality_op (op, mode)
1197 enum machine_mode mode;
1199 return (GET_CODE (op) == EQ || GET_CODE (op) == NE);
1202 /* Return true if the code of this rtx pattern is pc or label_ref. */
1205 pc_or_label_ref (op, mode)
1207 enum machine_mode mode;
1209 return (GET_CODE (op) == PC || GET_CODE (op) == LABEL_REF);
1212 /* Output to FILE the start of the assembler file. */
1222 output_option (file, sep, type, name, indent, pos, max)
1231 if (strlen (sep) + strlen (type) + strlen (name) + pos > max)
1233 fprintf (file, indent);
1234 return fprintf (file, "%s%s", type, name);
1236 return pos + fprintf (file, "%s%s%s", sep, type, name);
1239 static struct { char *name; int value; } m_options[] = TARGET_SWITCHES;
1242 output_options (file, f_options, f_len, W_options, W_len,
1243 pos, max, sep, indent, term)
1245 struct option *f_options;
1246 struct option *W_options;
1256 pos = output_option (file, sep, "-O", "", indent, pos, max);
1257 if (write_symbols != NO_DEBUG)
1258 pos = output_option (file, sep, "-g", "", indent, pos, max);
1259 if (flag_traditional)
1260 pos = output_option (file, sep, "-traditional", "", indent, pos, max);
1262 pos = output_option (file, sep, "-p", "", indent, pos, max);
1264 for (j = 0; j < f_len; j++)
1265 if (*f_options[j].variable == f_options[j].on_value)
1266 pos = output_option (file, sep, "-f", f_options[j].string,
1269 for (j = 0; j < W_len; j++)
1270 if (*W_options[j].variable == W_options[j].on_value)
1271 pos = output_option (file, sep, "-W", W_options[j].string,
1274 for (j = 0; j < sizeof m_options / sizeof m_options[0]; j++)
1275 if (m_options[j].name[0] != '\0'
1276 && m_options[j].value > 0
1277 && ((m_options[j].value & target_flags)
1278 == m_options[j].value))
1279 pos = output_option (file, sep, "-m", m_options[j].name,
1282 if (m88k_short_data)
1283 pos = output_option (file, sep, "-mshort-data-", m88k_short_data,
1286 fprintf (file, term);
1290 output_file_start (file, f_options, f_len, W_options, W_len)
1292 struct option *f_options;
1293 struct option *W_options;
1298 ASM_FIRST_LINE (file);
1299 output_file_directive (file, main_input_filename);
1300 /* Switch to the data section so that the coffsem symbol and the
1301 gcc2_compiled. symbol aren't in the text section. */
1305 pos = fprintf (file, "\n; cc1 (%s) arguments:", VERSION_STRING);
1306 output_options (file, f_options, f_len, W_options, W_len,
1307 pos, 75, " ", "\n; ", "\n\n");
1309 if (TARGET_IDENTIFY_REVISION)
1313 time_t now = time ((time_t *)0);
1314 sprintf (indent, "]\"\n\t%s\t \"@(#)%s [", IDENT_ASM_OP, main_input_filename);
1315 fprintf (file, indent+3);
1316 pos = fprintf (file, "gcc %s, %.24s,", VERSION_STRING, ctime (&now));
1317 output_options (file, f_options, f_len, W_options, W_len,
1318 pos, 150 - strlen (indent), " ", indent, "]\"\n\n");
1322 /* Output an ascii string. */
1325 output_ascii (file, opcode, max, p, size)
1334 register int num = 0;
1336 fprintf (file, "\t%s\t \"", opcode);
1337 for (i = 0; i < size; i++)
1339 register int c = p[i];
1343 fprintf (file, "\"\n\t%s\t \"", opcode);
1347 if (c == '\"' || c == '\\')
1353 if (c >= ' ' && c < 0177)
1360 fprintf (file, "\\%03o", c);
1362 /* After an octal-escape, if a digit follows,
1363 terminate one string constant and start another.
1364 The Vax assembler fails to stop reading the escape
1365 after three digits, so this is the only way we
1366 can get it to parse the data properly. */
1367 if (i < size - 1 && p[i + 1] >= '0' && p[i + 1] <= '9')
1368 num = max + 1; /* next pass will start a new string */
1371 fprintf (file, "\"\n");
1374 /* Output a label (allows insn-output.c to be compiled without including
1375 m88k.c or needing to include stdio.h). */
1378 output_label (label_number)
1381 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", label_number);
1384 /* Handle a pragma directive. HANDLE_PRAGMA conspires to parse the input
1385 following #pragma into tokens based on yylex. */
1388 m88k_handle_pragma_token (string, token)
1392 static enum pragma_state
1405 if (HANDLE_PRAGMA_WEAK)
1409 if (state == ps_name || state == ps_value)
1411 fprintf (asm_out_file, "\t%s\t ", WEAK_ASM_OP);
1412 ASM_OUTPUT_LABELREF (asm_out_file, name);
1413 fputc ('\n', asm_out_file);
1414 if (state == ps_value)
1416 fprintf (asm_out_file, "\t%s\t ", DEF_ASM_OP);
1417 ASM_OUTPUT_LABELREF (asm_out_file, name);
1418 fputc (',', asm_out_file);
1419 ASM_OUTPUT_LABELREF (asm_out_file, value);
1420 fputc ('\n', asm_out_file);
1423 else if (! (state == ps_done || state == ps_start))
1424 warning ("ignoring malformed #pragma weak symbol [=value]");
1432 && TREE_CODE (token) == IDENTIFIER_NODE
1433 && !strcmp (IDENTIFIER_POINTER (token), "weak"))
1441 && TREE_CODE (token) == IDENTIFIER_NODE)
1443 name = IDENTIFIER_POINTER (token);
1451 state = (strcmp (string, "=") ? ps_bad : ps_equals);
1456 && TREE_CODE (token) == IDENTIFIER_NODE)
1458 value = IDENTIFIER_POINTER (token);
1477 /* Generate the assembly code for function entry.
1479 The prologue is responsible for setting up the stack frame,
1480 initializing the frame pointer register, saving registers that must be
1481 saved, and allocating SIZE additional bytes of storage for the
1482 local variables. SIZE is an integer. FILE is a stdio
1483 stream to which the assembler code should be output.
1485 The label for the beginning of the function need not be output by this
1486 macro. That has already been done when the macro is run.
1488 To determine which registers to save, the macro can refer to the array
1489 `regs_ever_live': element R is nonzero if hard register
1490 R is used anywhere within the function. This implies the
1491 function prologue should save register R, but not if it is one
1492 of the call-used registers.
1494 On machines where functions may or may not have frame-pointers, the
1495 function entry code must vary accordingly; it must set up the frame
1496 pointer if one is wanted, and not otherwise. To determine whether a
1497 frame pointer is in wanted, the macro can refer to the variable
1498 `frame_pointer_needed'. The variable's value will be 1 at run
1499 time in a function that needs a frame pointer.
1501 On machines where an argument may be passed partly in registers and
1502 partly in memory, this macro must examine the variable
1503 `current_function_pretend_args_size', and allocate that many bytes
1504 of uninitialized space on the stack just underneath the first argument
1505 arriving on the stack. (This may not be at the very end of the stack,
1506 if the calling sequence has pushed anything else since pushing the stack
1507 arguments. But usually, on such machines, nothing else has been pushed
1508 yet, because the function prologue itself does all the pushing.)
1510 If `ACCUMULATE_OUTGOING_ARGS' is defined, the variable
1511 `current_function_outgoing_args_size' contains the size in bytes
1512 required for the outgoing arguments. This macro must add that
1513 amount of uninitialized space to very bottom of the stack.
1515 The stack frame we use looks like this:
1518 |==============================================|
1520 |==============================================|
1521 | [caller's outgoing memory arguments] |
1522 |==============================================|
1523 | caller's outgoing argument area (32 bytes) |
1524 sp -> |==============================================| <- ap
1525 | [local variable space] |
1526 |----------------------------------------------|
1527 | [return address (r1)] |
1528 |----------------------------------------------|
1529 | [previous frame pointer (r30)] |
1530 |==============================================| <- fp
1531 | [preserved registers (r25..r14)] |
1532 |----------------------------------------------|
1533 | [preserved registers (x29..x22)] |
1534 |==============================================|
1535 | [dynamically allocated space (alloca)] |
1536 |==============================================|
1537 | [callee's outgoing memory arguments] |
1538 |==============================================|
1539 | [callee's outgoing argument area (32 bytes)] |
1540 |==============================================| <- sp
1544 r1 and r30 must be saved if debugging.
1546 fp (if present) is located two words down from the local
1550 static void output_reg_adjust ();
1551 static void preserve_registers ();
1552 static void output_tdesc ();
1556 static char save_regs[FIRST_PSEUDO_REGISTER];
1557 static int frame_laid_out;
1558 static int frame_size;
1559 static int variable_args_p;
1561 extern char call_used_regs[];
1562 extern int current_function_pretend_args_size;
1563 extern int current_function_outgoing_args_size;
1564 extern int frame_pointer_needed;
1566 #define FIRST_OCS_PRESERVE_REGISTER 14
1567 #define LAST_OCS_PRESERVE_REGISTER 30
1569 #define FIRST_OCS_EXTENDED_PRESERVE_REGISTER (32 + 22)
1570 #define LAST_OCS_EXTENDED_PRESERVE_REGISTER (32 + 31)
1572 #define STACK_UNIT_BOUNDARY (STACK_BOUNDARY / BITS_PER_UNIT)
1573 #define ROUND_CALL_BLOCK_SIZE(BYTES) \
1574 (((BYTES) + (STACK_UNIT_BOUNDARY - 1)) & ~(STACK_UNIT_BOUNDARY - 1))
1576 /* Establish the position of the FP relative to the SP. This is done
1577 either during FUNCTION_PROLOGUE or by INITIAL_ELIMINATION_OFFSET. */
1580 m88k_layout_frame ()
1586 bzero ((char *) &save_regs[0], sizeof (save_regs));
1587 sp_size = nregs = nxregs = 0;
1588 frame_size = get_frame_size ();
1590 /* Since profiling requires a call, make sure r1 is saved. */
1594 /* If we are producing debug information, store r1 and r30 where the
1595 debugger wants to find them (r30 at r30+0, r1 at r30+4). Space has
1596 already been reserved for r1/r30 in STARTING_FRAME_OFFSET. */
1597 if (write_symbols != NO_DEBUG && !TARGET_OCS_FRAME_POSITION)
1600 /* If there is a call, alloca is used, __builtin_alloca is used, or
1601 a dynamic-sized object is defined, add the 8 additional words
1602 for the callee's argument area. The common denominator is that the
1603 FP is required. may_call_alloca only gets calls to alloca;
1604 current_function_calls_alloca gets alloca and __builtin_alloca. */
1605 if (regs_ever_live[1] || frame_pointer_needed)
1608 sp_size += REG_PARM_STACK_SPACE (0);
1611 /* If we are producing PIC, save the addressing base register and r1. */
1612 if (flag_pic && current_function_uses_pic_offset_table)
1614 save_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
1618 /* If a frame is requested, save the previous FP, and the return
1619 address (r1), so that a traceback can be done without using tdesc
1621 if (frame_pointer_needed)
1622 save_regs[FRAME_POINTER_REGNUM] = save_regs[1] = 1;
1624 /* Figure out which extended register(s) needs to be saved. */
1625 for (regno = FIRST_EXTENDED_REGISTER + 1; regno < FIRST_PSEUDO_REGISTER;
1627 if (regs_ever_live[regno] && ! call_used_regs[regno])
1629 save_regs[regno] = 1;
1633 /* Figure out which normal register(s) needs to be saved. */
1634 for (regno = 2; regno < FRAME_POINTER_REGNUM; regno++)
1635 if (regs_ever_live[regno] && ! call_used_regs[regno])
1637 save_regs[regno] = 1;
1641 /* Achieve greatest use of double memory ops. Either we end up saving
1642 r30 or we use that slot to align the regsters we do save. */
1643 if (nregs >= 2 && save_regs[1] && !save_regs[FRAME_POINTER_REGNUM])
1646 nregs += save_regs[1] + save_regs[FRAME_POINTER_REGNUM];
1647 /* if we need to align extended registers, add a word */
1648 if (nxregs > 0 && (nregs & 1) != 0)
1650 sp_size += 4 * nregs;
1651 sp_size += 8 * nxregs;
1652 sp_size += current_function_outgoing_args_size;
1654 /* The first two saved registers are placed above the new frame pointer
1655 if any. In the only case this matters, they are r1 and r30. */
1656 if (frame_pointer_needed || sp_size)
1658 m88k_fp_offset = ROUND_CALL_BLOCK_SIZE (sp_size - STARTING_FRAME_OFFSET);
1659 m88k_stack_size = m88k_fp_offset + STARTING_FRAME_OFFSET;
1663 m88k_stack_size = m88k_fp_offset = 0;
1666 /* First, combine m88k_stack_size and size. If m88k_stack_size is
1667 non-zero, align the frame size to 8 mod 16; otherwise align the
1668 frame size to 0 mod 16. (If stacks are 8 byte aligned, this ends
1672 = ((m88k_stack_size ? STACK_UNIT_BOUNDARY - STARTING_FRAME_OFFSET : 0)
1673 - (frame_size % STACK_UNIT_BOUNDARY));
1677 need += STACK_UNIT_BOUNDARY;
1678 (void) assign_stack_local (BLKmode, need, BITS_PER_UNIT);
1679 frame_size = get_frame_size ();
1682 = ROUND_CALL_BLOCK_SIZE (m88k_stack_size + frame_size
1683 + current_function_pretend_args_size);
1687 /* Return true if this function is known to have a null epilogue. */
1692 if (! reload_completed)
1694 if (! frame_laid_out)
1695 m88k_layout_frame ();
1696 return (! frame_pointer_needed
1699 && m88k_stack_size == 0);
1702 /* Determine the number of instructions needed for the function epilogue. */
1704 #define MAX_EPILOGUE_DELAY_INSNS 4
1706 static char epilogue_dead_regs[FIRST_PSEUDO_REGISTER];
1708 delay_slots_for_epilogue ()
1710 register int insns = save_regs[1] + save_regs[FRAME_POINTER_REGNUM];
1711 register int regs = nregs - insns;
1714 insns += 1 + (regs & 1);
1715 else if (nregs == 4)
1716 /* This is a special cases of ld/ld/ld.d which has no start-up delay. */
1721 bzero ((char *) &epilogue_dead_regs[0], sizeof (epilogue_dead_regs));
1722 epilogue_dead_regs[1] = save_regs[1];
1723 epilogue_dead_regs[STACK_POINTER_REGNUM] = frame_pointer_needed;
1724 epilogue_dead_regs[TEMP_REGNUM] = ! ADD_INTVAL (m88k_fp_offset);
1730 /* Return 1 if X is safe to use as an epilogue insn. */
1733 ok_for_epilogue_p (x)
1739 switch (GET_CODE (x))
1742 for (i = REGNO (x), j = i + HARD_REGNO_NREGS (i, GET_MODE (x));
1745 if (epilogue_dead_regs[i])
1759 fmt = GET_RTX_FORMAT (GET_CODE (x));
1760 for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
1764 if (!ok_for_epilogue_p (XEXP (x, i)))
1767 else if (fmt[i] == 'E')
1769 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
1770 if (!ok_for_epilogue_p (XVECEXP (x, i, j)))
1778 eligible_for_epilogue_delay (insn)
1781 switch (get_attr_type (insn))
1788 return ok_for_epilogue_p (PATTERN (insn));
1794 /* Determine if the current function has any references to the arg pointer.
1795 This is done indirectly by examining the DECL_ARGUMENTS' DECL_RTL.
1796 It is OK to return TRUE if there are no references, but FALSE must be
1804 if (current_function_decl == 0
1805 || current_function_varargs
1809 for (parm = DECL_ARGUMENTS (current_function_decl);
1811 parm = TREE_CHAIN (parm))
1813 if (DECL_RTL (parm) == 0
1814 || GET_CODE (DECL_RTL (parm)) == MEM)
1817 if (DECL_INCOMING_RTL (parm) == 0
1818 || GET_CODE (DECL_INCOMING_RTL (parm)) == MEM)
1825 m88k_output_prologue (stream, size)
1829 int old_fp_offset = m88k_fp_offset;
1830 int old_stack_size = m88k_stack_size;
1832 m88k_layout_frame ();
1833 #if (MONITOR_GCC & 0x8) /* Watch for suspicious register elimination changes. */
1834 if (frame_laid_out > 1)
1836 if (old_fp_offset != m88k_fp_offset)
1837 warning ("Internal gcc error: FP offset has changed by %d bytes",
1838 m88k_fp_offset - old_fp_offset);
1839 if (old_stack_size != m88k_stack_size)
1840 warning ("Internal gcc error: stack size has changed by %d bytes",
1841 m88k_stack_size - old_stack_size);
1846 if (TARGET_OPTIMIZE_ARG_AREA
1848 && ! uses_arg_area_p ())
1850 /* The incoming argument area is used for stack space if it is not
1851 used (or if -mno-use-arg-area is given). */
1852 if ((m88k_stack_size -= REG_PARM_STACK_SPACE (0)) < 0)
1853 m88k_stack_size = 0;
1856 if (m88k_stack_size)
1857 output_reg_adjust (stream, 31, 31, -m88k_stack_size, 0);
1859 if (nregs || nxregs)
1860 preserve_registers (stream, m88k_fp_offset + 4, 1);
1862 if (frame_pointer_needed)
1863 output_reg_adjust (stream, 30, 31, m88k_fp_offset, 0);
1865 if (TARGET_OCS_DEBUG_INFO)
1866 PUT_OCS_FUNCTION_START (stream);
1868 if (flag_pic && save_regs[PIC_OFFSET_TABLE_REGNUM])
1873 fprintf (stream, "\tor\t %s,%s,0\n",
1874 reg_names[TEMP_REGNUM], reg_names[1]);
1875 ASM_GENERATE_INTERNAL_LABEL (label, "Lab", m88k_function_number);
1876 fprintf (stream, "\tbsr.n\t %s\n", &label[1]);
1877 fprintf (stream, "\tor.u\t %s,%s,%shi16(%s#abdiff)\n",
1878 reg_names[PIC_OFFSET_TABLE_REGNUM], reg_names[0],
1879 m88k_pound_sign, &label[1]);
1880 ASM_OUTPUT_INTERNAL_LABEL (stream, "Lab", m88k_function_number);
1881 fprintf (stream, "\tor\t %s,%s,%slo16(%s#abdiff)\n",
1882 reg_names[PIC_OFFSET_TABLE_REGNUM],
1883 reg_names[PIC_OFFSET_TABLE_REGNUM],
1884 m88k_pound_sign, &label[1]);
1885 fprintf (stream, "\taddu\t %s,%s,%s\n",
1886 reg_names[PIC_OFFSET_TABLE_REGNUM],
1887 reg_names[PIC_OFFSET_TABLE_REGNUM], reg_names[1]);
1889 fprintf (stream, "\tor\t %s,%s,0\n",
1890 reg_names[1], reg_names[TEMP_REGNUM]);
1893 m88k_prologue_done = 1; /* it's ok now to put out ln directives */
1896 /* This function generates the assembly code for function exit,
1897 on machines that need it. Args are same as for FUNCTION_PROLOGUE.
1899 The function epilogue should not depend on the current stack pointer!
1900 It should use the frame pointer only, if there is a frame pointer.
1901 This is mandatory because of alloca; we also take advantage of it to
1902 omit stack adjustments before returning. */
1905 m88k_output_epilogue (stream, size)
1909 rtx insn = get_last_insn ();
1910 #if (MONITOR_GCC & 0x4) /* What are interesting prologue/epilogue values? */
1911 fprintf (stream, "; size = %d, m88k_fp_offset = %d, m88k_stack_size = %d\n",
1912 size, m88k_fp_offset, m88k_stack_size);
1915 output_short_branch_defs (stream);
1917 if (TARGET_OCS_DEBUG_INFO)
1918 PUT_OCS_FUNCTION_END (stream);
1920 /* If the last insn was a BARRIER, we don't have to write any code. */
1921 if (GET_CODE (insn) == NOTE)
1922 insn = prev_nonnote_insn (insn);
1923 if (insn && GET_CODE (insn) == BARRIER)
1925 if (current_function_epilogue_delay_list)
1930 if (frame_pointer_needed)
1931 output_reg_adjust (stream, 31, 30, -m88k_fp_offset, 0);
1933 if (nregs || nxregs)
1934 preserve_registers (stream, m88k_fp_offset + 4, 0);
1936 output_reg_adjust (stream, 31, 31, m88k_stack_size, 1);
1939 fprintf (stream, "\n");
1941 if (TARGET_OCS_DEBUG_INFO)
1942 output_tdesc (stream, m88k_fp_offset + 4);
1944 m88k_function_number++;
1945 m88k_prologue_done = 0; /* don't put out ln directives */
1946 variable_args_p = 0; /* has variable args */
1949 /* Output code to STREAM to set DSTREG to SRCREG + AMOUNT. Issue
1950 a return instruction and use it's delay slot based on RETURN_P. */
1953 output_reg_adjust (stream, dstreg, srcreg, amount, return_p)
1955 int dstreg, srcreg, amount, return_p;
1968 if (amount == 0 && dstreg == srcreg)
1971 fprintf (stream, "\tjmp\t %s\n", reg_names[1]);
1974 else if (SMALL_INTVAL (amount))
1975 sprintf (incr, "\t%s\t %s,%s,%d", opname,
1976 reg_names[dstreg], reg_names[srcreg], amount);
1981 operands[0] = gen_rtx (REG, SImode, TEMP_REGNUM);
1982 operands[1] = gen_rtx (CONST_INT, VOIDmode, amount);
1983 output_asm_insn (output_load_const_int (SImode, operands),
1985 sprintf (incr, "\t%s\t %s,%s,%s", opname,
1986 reg_names[dstreg], reg_names[srcreg], reg_names[TEMP_REGNUM]);
1990 fprintf (stream, "%s\n", incr);
1991 else if (flag_delayed_branch)
1992 fprintf (stream, "\tjmp.n\t %s\n%s\n", reg_names[1], incr);
1994 fprintf (stream, "%s\n\tjmp\t %s\n", incr, reg_names[1]);
1997 /* Save/restore the preserve registers. base is the highest offset from
1998 r31 at which a register is stored. store_p is true if stores are to
1999 be done; otherwise loads. When loading, output the epilogue delay
2003 preserve_registers (stream, base, store_p)
2009 char *fmt = (store_p ? "\tst%s\t %s,%s,%d\n" : "\tld%s\t %s,%s,%d\n");
2014 } mem_op[FIRST_PSEUDO_REGISTER];
2015 struct mem_op *mo_ptr = mem_op;
2017 /* The 88open OCS mandates that preserved registers be stored in
2018 increasing order. For compatibility with current practice,
2019 the order is r1, r30, then the preserve registers. */
2024 /* An extra word is given in this case to make best use of double
2026 if (nregs > 2 && !save_regs[FRAME_POINTER_REGNUM])
2028 fprintf (stream, fmt, "", reg_names[1], reg_names[31], offset);
2033 /* Walk the registers to save recording all single memory operations. */
2034 for (regno = FRAME_POINTER_REGNUM; regno > 1; regno--)
2035 if (save_regs[regno])
2037 if ((offset & 7) != 4 || (regno & 1) != 1 || !save_regs[regno-1])
2040 mo_ptr->regno = regno;
2041 mo_ptr->offset = offset;
2052 /* Walk the registers to save recording all double memory operations.
2053 This avoids a delay in the epilogue (ld.d/ld). */
2055 for (regno = FRAME_POINTER_REGNUM; regno > 1; regno--)
2056 if (save_regs[regno])
2058 if ((offset & 7) != 4 || (regno & 1) != 1 || !save_regs[regno-1])
2065 mo_ptr->regno = regno-1;
2066 mo_ptr->offset = offset-4;
2073 /* Walk the extended registers to record all memory operations. */
2074 /* Be sure the offset is double word aligned. */
2075 offset = (offset - 1) & ~7;
2076 for (regno = FIRST_PSEUDO_REGISTER - 1; regno > FIRST_EXTENDED_REGISTER;
2078 if (save_regs[regno])
2081 mo_ptr->regno = regno;
2082 mo_ptr->offset = offset;
2089 /* Output the delay insns interleaved with the memory operations. */
2090 if (! store_p && current_function_epilogue_delay_list)
2092 rtx delay_insns = current_function_epilogue_delay_list;
2095 /* The first delay insn goes after the restore of r1. */
2098 final_scan_insn (XEXP (delay_insns, 0), stream, 1, 0, 1);
2099 delay_insns = XEXP (delay_insns, 1);
2104 /* Find a memory operation that doesn't conflict with this insn. */
2105 for (mo_ptr = mem_op; mo_ptr->regno != 0; mo_ptr++)
2109 int nregs = (mo_ptr->regno < FIRST_EXTENDED_REGISTER
2110 ? mo_ptr->nregs : 1);
2111 rtx ok_insns = delay_insns;
2114 for (i = 0; i < nregs; i++)
2115 epilogue_dead_regs[mo_ptr->regno + i] = 1;
2119 insn = XEXP (ok_insns, 0);
2120 ok_insns = XEXP (ok_insns, 1);
2122 if (! ok_for_epilogue_p (PATTERN (insn)))
2124 for (i = 0; i < nregs; i++)
2125 epilogue_dead_regs[mo_ptr->regno + i] = 0;
2127 break; /* foreach delay insn */
2132 fprintf (stream, fmt, mo_ptr->nregs > 1 ? ".d" : "",
2133 reg_names[mo_ptr->regno], reg_names[31],
2136 break; /* foreach memory operation */
2140 final_scan_insn (XEXP (delay_insns, 0), stream, 1, 0, 1);
2141 delay_insns = XEXP (delay_insns, 1);
2145 /* Output the memory operations. */
2146 for (mo_ptr = mem_op; mo_ptr->regno; mo_ptr++)
2149 fprintf (stream, fmt, mo_ptr->nregs > 1 ? ".d" : "",
2150 reg_names[mo_ptr->regno], reg_names[31], mo_ptr->offset);
2154 /* Convert the address expression REG to a CFA offset. */
2157 m88k_debugger_offset (reg, offset)
2159 register int offset;
2161 if (GET_CODE (reg) == PLUS)
2163 offset = INTVAL (XEXP (reg, 1));
2164 reg = XEXP (reg, 0);
2167 /* Put the offset in terms of the CFA (arg pointer). */
2168 if (reg == frame_pointer_rtx)
2169 offset += m88k_fp_offset - m88k_stack_size;
2170 else if (reg == stack_pointer_rtx)
2171 offset -= m88k_stack_size;
2172 else if (reg != arg_pointer_rtx)
2174 #if (MONITOR_GCC & 0x10) /* Watch for suspicious symbolic locations. */
2175 if (! (GET_CODE (reg) == REG
2176 && REGNO (reg) >= FIRST_PSEUDO_REGISTER))
2177 warning ("Internal gcc error: Can't express symbolic location");
2185 /* Output the 88open OCS proscribed text description information.
2188 0 22: info-byte-length (16 or 20 bytes)
2189 0 2: info-alignment (word 2)
2190 1 32: info-protocol (version 1 or 2(pic))
2191 2 32: starting-address (inclusive, not counting prologue)
2192 3 32: ending-address (exclusive, not counting epilog)
2193 4 8: info-variant (version 1 or 3(extended registers))
2194 4 17: register-save-mask (from register 14 to 30)
2196 4 1: return-address-info-discriminant
2197 4 5: frame-address-register
2198 5 32: frame-address-offset
2199 6 32: return-address-info
2200 7 32: register-save-offset
2201 8 16: extended-register-save-mask (x16 - x31)
2202 8 16: extended-register-save-offset (WORDS from register-save-offset) */
2205 output_tdesc (file, offset)
2210 long mask, return_address_info, register_save_offset;
2211 long xmask, xregister_save_offset;
2214 for (mask = 0, i = 0, regno = FIRST_OCS_PRESERVE_REGISTER;
2215 regno <= LAST_OCS_PRESERVE_REGISTER;
2219 if (save_regs[regno])
2226 for (xmask = 0, j = 0, regno = FIRST_OCS_EXTENDED_PRESERVE_REGISTER;
2227 regno <= LAST_OCS_EXTENDED_PRESERVE_REGISTER;
2231 if (save_regs[regno])
2240 if ((nxregs > 0 || nregs > 2) && !save_regs[FRAME_POINTER_REGNUM])
2242 return_address_info = - m88k_stack_size + offset;
2243 register_save_offset = return_address_info - i*4;
2247 return_address_info = 1;
2248 register_save_offset = - m88k_stack_size + offset + 4 - i*4;
2251 xregister_save_offset = - (j * 2 + ((register_save_offset >> 2) & 1));
2255 fprintf (file, "\t%s\t %d,%d", INT_ASM_OP, /* 8:0,22:(20 or 16),2:2 */
2256 (((xmask != 0) ? 20 : 16) << 2) | 2,
2259 ASM_GENERATE_INTERNAL_LABEL (buf, OCS_START_PREFIX, m88k_function_number);
2260 fprintf (file, ",%s%s", buf+1, flag_pic ? "#rel" : "");
2261 ASM_GENERATE_INTERNAL_LABEL (buf, OCS_END_PREFIX, m88k_function_number);
2262 fprintf (file, ",%s%s", buf+1, flag_pic ? "#rel" : "");
2264 fprintf (file, ",0x%x,0x%x,0x%x,0x%x",
2265 /* 8:1,17:0x%.3x,1:0,1:%d,5:%d */
2266 (((xmask ? 3 : 1) << (17+1+1+5))
2268 | ((!!save_regs[1]) << 5)
2269 | (frame_pointer_needed
2270 ? FRAME_POINTER_REGNUM
2271 : STACK_POINTER_REGNUM)),
2272 (m88k_stack_size - (frame_pointer_needed ? m88k_fp_offset : 0)),
2273 return_address_info,
2274 register_save_offset);
2276 fprintf (file, ",0x%x%04x", xmask, (0xffff & xregister_save_offset));
2282 /* Output assembler code to FILE to increment profiler label # LABELNO
2283 for profiling a function entry. NAME is the mcount function name
2284 (varies), SAVEP indicates whether the parameter registers need to
2285 be saved and restored. */
2288 output_function_profiler (file, labelno, name, savep)
2296 char *temp = (savep ? reg_names[2] : reg_names[10]);
2300 fprintf (file, "\tsubu\t %s,%s,64\n", reg_names[31], reg_names[31]);
2301 fprintf (file, "\tst.d\t %s,%s,32\n", reg_names[2], reg_names[31]);
2302 fprintf (file, "\tst.d\t %s,%s,40\n", reg_names[4], reg_names[31]);
2303 fprintf (file, "\tst.d\t %s,%s,48\n", reg_names[6], reg_names[31]);
2304 fprintf (file, "\tst.d\t %s,%s,56\n", reg_names[8], reg_names[31]);
2307 ASM_GENERATE_INTERNAL_LABEL (label, "LP", labelno);
2310 fprintf (file, "\tor.u\t %s,%s,%shi16(%s#got_rel)\n",
2311 temp, reg_names[0], m88k_pound_sign, &label[1]);
2312 fprintf (file, "\tor\t %s,%s,%slo16(%s#got_rel)\n",
2313 temp, temp, m88k_pound_sign, &label[1]);
2314 sprintf (dbi, "\tld\t %s,%s,%s\n", temp,
2315 reg_names[PIC_OFFSET_TABLE_REGNUM], temp);
2319 sprintf (dbi, "\tld\t %s,%s,%s#got_rel\n", temp,
2320 reg_names[PIC_OFFSET_TABLE_REGNUM], &label[1]);
2324 fprintf (file, "\tor.u\t %s,%s,%shi16(%s)\n",
2325 temp, reg_names[0], m88k_pound_sign, &label[1]);
2326 sprintf (dbi, "\tor\t %s,%s,%slo16(%s)\n",
2327 temp, temp, m88k_pound_sign, &label[1]);
2331 fprintf (file, "\tbsr.n\t %s#plt\n", name);
2333 fprintf (file, "\tbsr.n\t %s\n", name);
2338 fprintf (file, "\tld.d\t %s,%s,32\n", reg_names[2], reg_names[31]);
2339 fprintf (file, "\tld.d\t %s,%s,40\n", reg_names[4], reg_names[31]);
2340 fprintf (file, "\tld.d\t %s,%s,48\n", reg_names[6], reg_names[31]);
2341 fprintf (file, "\tld.d\t %s,%s,56\n", reg_names[8], reg_names[31]);
2342 fprintf (file, "\taddu\t %s,%s,64\n", reg_names[31], reg_names[31]);
2346 /* Output assembler code to FILE to initialize basic-block profiling for
2347 the current module. LABELNO is unique to each instance. */
2350 output_function_block_profiler (file, labelno)
2357 ASM_GENERATE_INTERNAL_LABEL (block, "LPBX", 0);
2358 ASM_GENERATE_INTERNAL_LABEL (label, "LPY", labelno);
2360 /* @@ Need to deal with PIC. I'm not sure what the requirements are on
2361 register usage, so I used r26/r27 to be safe. */
2362 fprintf (file, "\tor.u\t %s,%s,%shi16(%s)\n", reg_names[27], reg_names[0],
2363 m88k_pound_sign, &block[1]);
2364 fprintf (file, "\tld\t %s,%s,%slo16(%s)\n", reg_names[26], reg_names[27],
2365 m88k_pound_sign, &block[1]);
2366 fprintf (file, "\tbcnd\t %sne0,%s,%s\n",
2367 m88k_pound_sign, reg_names[26], &label[1]);
2368 fputs ("\tbsr.n\t ", file);
2369 ASM_OUTPUT_LABELREF (file, "__bb_init_func");
2371 fprintf (file, "\tor\t %s,%s,%slo16(%s)\n", reg_names[2], reg_names[27],
2372 m88k_pound_sign, &block[1]);
2373 ASM_OUTPUT_INTERNAL_LABEL (file, "LPY", labelno);
2376 /* Output assembler code to FILE to increment the count associated with
2377 the basic block number BLOCKNO. */
2380 output_block_profiler (file, blockno)
2386 ASM_GENERATE_INTERNAL_LABEL (block, "LPBX", 0);
2388 /* @@ Need to deal with PIC. I'm not sure what the requirements are on
2389 register usage, so I used r26/r27 to be safe. */
2390 fprintf (file, "\tor.u\t %s,%s,%shi16(%s+%d)\n", reg_names[27], reg_names[0],
2391 m88k_pound_sign, &block[1], 4 * blockno);
2392 fprintf (file, "\tld\t %s,%s,%slo16(%s+%d)\n", reg_names[26], reg_names[27],
2393 m88k_pound_sign, &block[1], 4 * blockno);
2394 fprintf (file, "\taddu\t %s,%s,1\n", reg_names[26], reg_names[26]);
2395 fprintf (file, "\tst\t %s,%s,%slo16(%s+%d)\n", reg_names[26], reg_names[27],
2396 m88k_pound_sign, &block[1], 4 * blockno);
2399 /* Determine whether a function argument is passed in a register, and
2402 The arguments are CUM, which summarizes all the previous
2403 arguments; MODE, the machine mode of the argument; TYPE,
2404 the data type of the argument as a tree node or 0 if that is not known
2405 (which happens for C support library functions); and NAMED,
2406 which is 1 for an ordinary argument and 0 for nameless arguments that
2407 correspond to `...' in the called function's prototype.
2409 The value of the expression should either be a `reg' RTX for the
2410 hard register in which to pass the argument, or zero to pass the
2411 argument on the stack.
2413 On the m88000 the first eight words of args are normally in registers
2414 and the rest are pushed. Double precision floating point must be
2415 double word aligned (and if in a register, starting on an even
2416 register). Structures and unions which are not 4 byte, and word
2417 aligned are passed in memory rather than registers, even if they
2418 would fit completely in the registers under OCS rules.
2420 Note that FUNCTION_ARG and FUNCTION_INCOMING_ARG were different.
2421 For structures that are passed in memory, but could have been
2422 passed in registers, we first load the structure into the
2423 register, and then when the last argument is passed, we store
2424 the registers into the stack locations. This fixes some bugs
2425 where GCC did not expect to have register arguments, followed
2426 by stack arguments, followed by register arguments. */
2429 m88k_function_arg (args_so_far, mode, type, named)
2430 CUMULATIVE_ARGS args_so_far;
2431 enum machine_mode mode;
2437 if (type != 0 /* undo putting struct in register */
2438 && (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE))
2441 if (mode == BLKmode && TARGET_WARN_PASS_STRUCT)
2442 warning ("argument #%d is a structure", args_so_far + 1);
2444 if ((args_so_far & 1) != 0
2445 && (mode == DImode || mode == DFmode
2446 || (type != 0 && TYPE_ALIGN (type) > 32)))
2451 return (rtx) 0; /* don't put args in registers */
2454 if (type == 0 && mode == BLKmode)
2455 abort (); /* m88k_function_arg argument `type' is NULL for BLKmode. */
2457 bytes = (mode != BLKmode) ? GET_MODE_SIZE (mode) : int_size_in_bytes (type);
2458 words = (bytes + 3) / 4;
2460 if (args_so_far + words > 8)
2461 return (rtx) 0; /* args have exhausted registers */
2463 else if (mode == BLKmode
2464 && (TYPE_ALIGN (type) != BITS_PER_WORD
2465 || bytes != UNITS_PER_WORD))
2468 return gen_rtx (REG,
2469 ((mode == BLKmode) ? TYPE_MODE (type) : mode),
2473 /* Do what is necessary for `va_start'. The argument is ignored;
2474 We look at the current function to determine if stdargs or varargs
2475 is used and fill in an initial va_list. A pointer to this constructor
2479 m88k_builtin_saveregs (arglist)
2482 rtx block, addr, argsize;
2483 tree fntype = TREE_TYPE (current_function_decl);
2484 int argadj = ((!(TYPE_ARG_TYPES (fntype) != 0
2485 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
2486 != void_type_node)))
2487 ? -UNITS_PER_WORD : 0) + UNITS_PER_WORD - 1;
2489 variable_args_p = 1;
2491 if (CONSTANT_P (current_function_arg_offset_rtx))
2493 fixed = (XINT (current_function_arg_offset_rtx, 0)
2494 + argadj) / UNITS_PER_WORD;
2495 argsize = gen_rtx (CONST_INT, VOIDmode, fixed);
2500 argsize = plus_constant (current_function_arg_offset_rtx, argadj);
2501 argsize = expand_shift (RSHIFT_EXPR, Pmode, argsize,
2502 build_int_2 (2, 0), argsize, 0);
2505 /* Allocate the va_list constructor */
2506 block = assign_stack_local (BLKmode, 3 * UNITS_PER_WORD, BITS_PER_WORD);
2507 RTX_UNCHANGING_P (block) = 1;
2508 RTX_UNCHANGING_P (XEXP (block, 0)) = 1;
2510 /* Store the argsize as the __va_arg member. */
2511 emit_move_insn (change_address (block, SImode, XEXP (block, 0)),
2514 /* Store the arg pointer in the __va_stk member. */
2515 emit_move_insn (change_address (block, Pmode,
2516 plus_constant (XEXP (block, 0),
2518 copy_to_reg (virtual_incoming_args_rtx));
2520 /* Allocate the register space, and store it as the __va_reg member. */
2521 addr = assign_stack_local (BLKmode, 8 * UNITS_PER_WORD, -1);
2522 MEM_IN_STRUCT_P (addr) = 1;
2523 RTX_UNCHANGING_P (addr) = 1;
2524 RTX_UNCHANGING_P (XEXP (addr, 0)) = 1;
2525 emit_move_insn (change_address (block, Pmode,
2526 plus_constant (XEXP (block, 0),
2527 2 * UNITS_PER_WORD)),
2528 copy_to_reg (XEXP (addr, 0)));
2530 /* Now store the incoming registers and return the address of the
2531 va_list constructor. */
2535 change_address (addr, Pmode,
2536 plus_constant (XEXP (addr, 0),
2537 fixed * UNITS_PER_WORD)),
2540 return copy_to_reg (XEXP (block, 0));
2543 /* If cmpsi has not been generated, emit code to do the test. Return the
2544 expression describing the test of operator OP. */
2547 emit_test (op, mode)
2549 enum machine_mode mode;
2551 if (m88k_compare_reg == 0)
2552 emit_insn (gen_test (m88k_compare_op0, m88k_compare_op1));
2553 return (gen_rtx (op, mode, m88k_compare_reg, const0_rtx));
2556 /* Determine how to best perform cmpsi/bxx, where cmpsi has a constant
2557 operand. All tests with zero (albeit swapped) and all equality tests
2558 with a constant are done with bcnd. The remaining cases are swapped
2562 emit_bcnd (op, label)
2566 if (m88k_compare_op1 == const0_rtx)
2567 emit_jump_insn (optimize
2568 ? gen_bxx (emit_test (op, VOIDmode), label)
2569 : gen_bcnd (gen_rtx (op, VOIDmode,
2570 m88k_compare_op0, const0_rtx),
2572 else if (m88k_compare_op0 == const0_rtx)
2573 emit_jump_insn (optimize
2574 ? gen_bxx (emit_test (op, VOIDmode), label)
2575 : gen_bcnd (gen_rtx (swap_condition (op), VOIDmode,
2576 m88k_compare_op1, const0_rtx),
2578 else if (op != EQ && op != NE)
2579 emit_jump_insn (gen_bxx (emit_test (op, VOIDmode), label));
2582 rtx zero = gen_reg_rtx (SImode);
2586 if (GET_CODE (m88k_compare_op1) == CONST_INT)
2588 reg = force_reg (SImode, m88k_compare_op0);
2589 constant = m88k_compare_op1;
2593 reg = force_reg (SImode, m88k_compare_op1);
2594 constant = m88k_compare_op0;
2596 value = INTVAL (constant);
2598 /* Perform an arithmetic computation to make the compared-to value
2599 zero, but avoid loosing if the bcnd is later changed into sxx. */
2600 if (SMALL_INTVAL (value))
2601 emit_jump_insn (gen_bxx (emit_test (op, VOIDmode), label));
2604 if (SMALL_INTVAL (-value))
2605 emit_insn (gen_addsi3 (zero, reg,
2606 gen_rtx (CONST_INT, VOIDmode, -value)));
2608 emit_insn (gen_xorsi3 (zero, reg, constant));
2610 emit_jump_insn (gen_bcnd (gen_rtx (op, VOIDmode,
2617 /* Print an operand. Recognize special options, documented below. */
2620 print_operand (file, x, code)
2625 enum rtx_code xc = (x ? GET_CODE (x) : UNKNOWN);
2626 register int value = (xc == CONST_INT ? INTVAL (x) : 0);
2627 static int sequencep;
2628 static int reversep;
2632 if (code < 'B' || code > 'E')
2633 output_operand_lossage ("%R not followed by %B/C/D/E");
2635 xc = reverse_condition (xc);
2641 case '*': /* addressing base register for PIC */
2642 fputs (reg_names[PIC_OFFSET_TABLE_REGNUM], file); return;
2644 case '#': /* SVR4 pound-sign syntax character (empty if SVR3) */
2645 fputs (m88k_pound_sign, file); return;
2647 case 'X': /* print the upper 16 bits... */
2649 case 'x': /* print the lower 16 bits of the integer constant in hex */
2650 if (xc != CONST_INT)
2651 output_operand_lossage ("invalid %x/X value");
2652 fprintf (file, "0x%x", value & 0xffff); return;
2654 case 'H': /* print the low 16 bits of the negated integer constant */
2655 if (xc != CONST_INT)
2656 output_operand_lossage ("invalid %H value");
2658 case 'h': /* print the register or low 16 bits of the integer constant */
2661 if (xc != CONST_INT)
2662 output_operand_lossage ("invalid %h value");
2663 fprintf (file, "%d", value & 0xffff);
2666 case 'Q': /* print the low 8 bits of the negated integer constant */
2667 if (xc != CONST_INT)
2668 output_operand_lossage ("invalid %Q value");
2670 case 'q': /* print the register or low 8 bits of the integer constant */
2673 if (xc != CONST_INT)
2674 output_operand_lossage ("invalid %q value");
2675 fprintf (file, "%d", value & 0xff);
2678 case 'w': /* print the integer constant (X == 32 ? 0 : 32 - X) */
2679 if (xc != CONST_INT)
2680 output_operand_lossage ("invalid %o value");
2681 fprintf (file, "%d", value == 32 ? 0 : 32 - value);
2684 case 'p': /* print the logarithm of the integer constant */
2686 || (value = exact_log2 (value)) < 0)
2687 output_operand_lossage ("invalid %p value");
2688 fprintf (file, "%d", value);
2691 case 'S': /* compliment the value and then... */
2693 case 's': /* print the width and offset values forming the integer
2694 constant with a SET instruction. See integer_ok_for_set. */
2696 register unsigned mask, uval = value;
2697 register int top, bottom;
2699 if (xc != CONST_INT)
2700 output_operand_lossage ("invalid %s/S value");
2701 /* All the "one" bits must be contiguous. If so, MASK will be
2702 a power of two or zero. */
2703 mask = (uval | (uval - 1)) + 1;
2704 if (!(uval && POWER_OF_2_or_0 (mask)))
2705 output_operand_lossage ("invalid %s/S value");
2706 top = mask ? exact_log2 (mask) : 32;
2707 bottom = exact_log2 (uval & ~(uval - 1));
2708 fprintf (file,"%d<%d>", top - bottom, bottom);
2712 case 'P': /* print nothing if pc_rtx; output label_ref */
2713 if (xc == LABEL_REF)
2714 output_addr_const (file, x);
2716 output_operand_lossage ("invalid %P operand");
2719 case 'L': /* print 0 or 1 if operand is label_ref and then... */
2720 fputc (xc == LABEL_REF ? '1' : '0', file);
2721 case '.': /* print .n if delay slot is used */
2722 fputs ((final_sequence
2723 && ! INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0)))
2724 ? ".n\t" : "\t", file);
2727 case 'R': /* reverse the condition of the next print_operand
2728 if operand is a label_ref. */
2730 reversep = (xc == LABEL_REF);
2733 case 'B': /* bcnd branch values */
2734 fputs (m88k_pound_sign, file);
2737 case EQ: fputs ("eq0", file); return;
2738 case NE: fputs ("ne0", file); return;
2739 case GT: fputs ("gt0", file); return;
2740 case LE: fputs ("le0", file); return;
2741 case LT: fputs ("lt0", file); return;
2742 case GE: fputs ("ge0", file); return;
2743 default: output_operand_lossage ("invalid %B value");
2746 case 'C': /* bb0/bb1 branch values for comparisons */
2747 fputs (m88k_pound_sign, file);
2750 case EQ: fputs ("eq", file); return;
2751 case NE: fputs ("ne", file); return;
2752 case GT: fputs ("gt", file); return;
2753 case LE: fputs ("le", file); return;
2754 case LT: fputs ("lt", file); return;
2755 case GE: fputs ("ge", file); return;
2756 case GTU: fputs ("hi", file); return;
2757 case LEU: fputs ("ls", file); return;
2758 case LTU: fputs ("lo", file); return;
2759 case GEU: fputs ("hs", file); return;
2760 default: output_operand_lossage ("invalid %C value");
2763 case 'D': /* bcnd branch values for float comparisons */
2766 case EQ: fputs ("0xa", file); return;
2767 case NE: fputs ("0x5", file); return;
2768 case GT: fputs (m88k_pound_sign, file);
2769 fputs ("gt0", file); return;
2770 case LE: fputs ("0xe", file); return;
2771 case LT: fputs ("0x4", file); return;
2772 case GE: fputs ("0xb", file); return;
2773 default: output_operand_lossage ("invalid %D value");
2776 case 'E': /* bcnd branch values for special integers */
2779 case EQ: fputs ("0x8", file); return;
2780 case NE: fputs ("0x7", file); return;
2781 default: output_operand_lossage ("invalid %E value");
2784 case 'd': /* second register of a two register pair */
2786 output_operand_lossage ("`%d' operand isn't a register");
2787 fputs (reg_names[REGNO (x) + 1], file);
2790 case 'r': /* an immediate 0 should be represented as `r0' */
2791 if (x == const0_rtx)
2793 fputs (reg_names[0], file);
2797 output_operand_lossage ("invalid %r value");
2803 if (REGNO (x) == ARG_POINTER_REGNUM)
2804 output_operand_lossage ("operand is r0");
2806 fputs (reg_names[REGNO (x)], file);
2808 else if (xc == PLUS)
2811 output_address (XEXP (x, 0));
2812 else if (xc == CONST_DOUBLE)
2813 output_operand_lossage ("operand is const_double");
2815 output_addr_const (file, x);
2818 case 'g': /* append #got_rel as needed */
2819 if (flag_pic && (xc == SYMBOL_REF || xc == LABEL_REF))
2821 output_addr_const (file, x);
2822 fputs ("#got_rel", file);
2827 case 'a': /* (standard), assume operand is an address */
2828 case 'c': /* (standard), assume operand is an immediate value */
2829 case 'l': /* (standard), assume operand is a label_ref */
2830 case 'n': /* (standard), like %c, except negate first */
2832 output_operand_lossage ("invalid code");
2837 print_operand_address (file, addr)
2841 register rtx reg0, reg1, temp;
2843 switch (GET_CODE (addr))
2846 if (REGNO (addr) == ARG_POINTER_REGNUM)
2849 fprintf (file, "%s,%s", reg_names[0], reg_names [REGNO (addr)]);
2853 fprintf (file, "%s,%slo16(",
2854 reg_names[REGNO (XEXP (addr, 0))], m88k_pound_sign);
2855 output_addr_const (file, XEXP (addr, 1));
2860 reg0 = XEXP (addr, 0);
2861 reg1 = XEXP (addr, 1);
2862 if (GET_CODE (reg0) == MULT || GET_CODE (reg0) == CONST_INT)
2869 if ((REG_P (reg0) && REGNO (reg0) == ARG_POINTER_REGNUM)
2870 || (REG_P (reg1) && REGNO (reg1) == ARG_POINTER_REGNUM))
2873 else if (REG_P (reg0))
2876 fprintf (file, "%s,%s",
2877 reg_names [REGNO (reg0)], reg_names [REGNO (reg1)]);
2879 else if (GET_CODE (reg1) == CONST_INT)
2880 fprintf (file, "%s,%d",
2881 reg_names [REGNO (reg0)], INTVAL (reg1));
2883 else if (GET_CODE (reg1) == MULT)
2885 rtx mreg = XEXP (reg1, 0);
2886 if (REGNO (mreg) == ARG_POINTER_REGNUM)
2889 fprintf (file, "%s[%s]", reg_names[REGNO (reg0)],
2890 reg_names[REGNO (mreg)]);
2893 else if (GET_CODE (reg1) == ZERO_EXTRACT)
2895 fprintf (file, "%s,%slo16(",
2896 reg_names[REGNO (reg0)], m88k_pound_sign);
2897 output_addr_const (file, XEXP (reg1, 0));
2903 fprintf (file, "%s,", reg_names[REGNO (reg0)]);
2904 output_addr_const (file, reg1);
2905 fputs ("#got_rel", file);
2915 if (REGNO (XEXP (addr, 0)) == ARG_POINTER_REGNUM)
2918 fprintf (file, "%s[%s]",
2919 reg_names[0], reg_names[REGNO (XEXP (addr, 0))]);
2923 fprintf (file, "%s,%shi16(", reg_names[0], m88k_pound_sign);
2924 output_addr_const (file, XEXP (addr, 0));
2929 fprintf (file, "%s,%d", reg_names[0], INTVAL (addr));
2933 fprintf (file, "%s,", reg_names[0]);
2934 if (SHORT_ADDRESS_P (addr, temp))
2936 fprintf (file, "%siw16(", m88k_pound_sign);
2937 output_addr_const (file, addr);
2941 output_addr_const (file, addr);