1 /* Subroutines for insn-output.c for Motorola 88000.
2 Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
3 Free Software Foundation, Inc.
4 Contributed by Michael Tiemann (tiemann@mcc.com)
5 Currently maintained by (gcc@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, 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
28 #include "hard-reg-set.h"
30 #include "insn-config.h"
31 #include "conditions.h"
33 #include "insn-attr.h"
43 #include "target-def.h"
45 extern int flag_traditional;
46 extern FILE *asm_out_file;
48 const char *m88k_pound_sign = ""; /* Either # for SVR4 or empty for SVR3 */
49 const char *m88k_short_data;
50 const char *m88k_version;
51 char m88k_volatile_code;
53 unsigned m88k_gp_threshold = 0;
54 int m88k_prologue_done = 0; /* Ln directives can now be emitted */
55 int m88k_function_number = 0; /* Counter unique to each function */
56 int m88k_fp_offset = 0; /* offset of frame pointer if used */
57 int m88k_stack_size = 0; /* size of allocated stack (including frame) */
60 rtx m88k_compare_reg; /* cmp output pseudo register */
61 rtx m88k_compare_op0; /* cmpsi operand 0 */
62 rtx m88k_compare_op1; /* cmpsi operand 1 */
64 enum processor_type m88k_cpu; /* target cpu */
66 /* Initialize the GCC target structure. */
68 struct gcc_target target = TARGET_INITIALIZER;
70 /* Determine what instructions are needed to manufacture the integer VALUE
74 classify_integer (mode, value)
75 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))
96 /* Return the bit number in a compare word corresponding to CONDITION. */
99 condition_value (condition)
102 switch (GET_CODE (condition))
119 integer_ok_for_set (value)
120 register unsigned value;
122 /* All the "one" bits must be contiguous. If so, MASK + 1 will be
123 a power of two or zero. */
124 register unsigned mask = (value | (value - 1));
125 return (value && POWER_OF_2_or_0 (mask + 1));
129 output_load_const_int (mode, operands)
130 enum machine_mode mode;
133 static const char *const patterns[] =
141 "or.u %0,%#r0,%X1\n\tor %0,%0,%x1",
144 if (! REG_P (operands[0])
145 || GET_CODE (operands[1]) != CONST_INT)
147 return patterns[classify_integer (mode, INTVAL (operands[1]))];
150 /* These next two routines assume that floating point numbers are represented
151 in a manner which is consistent between host and target machines. */
154 output_load_const_float (operands)
157 /* These can return 0 under some circumstances when cross-compiling. */
158 operands[0] = operand_subword (operands[0], 0, 0, SFmode);
159 operands[1] = operand_subword (operands[1], 0, 0, SFmode);
161 return output_load_const_int (SImode, operands);
165 output_load_const_double (operands)
170 /* These can return zero on some cross-compilers, but there's nothing
171 we can do about it. */
172 latehalf[0] = operand_subword (operands[0], 1, 0, DFmode);
173 latehalf[1] = operand_subword (operands[1], 1, 0, DFmode);
175 operands[0] = operand_subword (operands[0], 0, 0, DFmode);
176 operands[1] = operand_subword (operands[1], 0, 0, DFmode);
178 output_asm_insn (output_load_const_int (SImode, operands), operands);
180 operands[0] = latehalf[0];
181 operands[1] = latehalf[1];
183 return output_load_const_int (SImode, operands);
187 output_load_const_dimode (operands)
192 latehalf[0] = operand_subword (operands[0], 1, 0, DImode);
193 latehalf[1] = operand_subword (operands[1], 1, 0, DImode);
195 operands[0] = operand_subword (operands[0], 0, 0, DImode);
196 operands[1] = operand_subword (operands[1], 0, 0, DImode);
198 output_asm_insn (output_load_const_int (SImode, operands), operands);
200 operands[0] = latehalf[0];
201 operands[1] = latehalf[1];
203 return output_load_const_int (SImode, operands);
206 /* Emit insns to move operands[1] into operands[0].
208 Return 1 if we have written out everything that needs to be done to
209 do the move. Otherwise, return 0 and the caller will emit the move
212 SCRATCH if non zero can be used as a scratch register for the move
213 operation. It is provided by a SECONDARY_RELOAD_* macro if needed. */
216 emit_move_sequence (operands, mode, scratch)
218 enum machine_mode mode;
221 register rtx operand0 = operands[0];
222 register rtx operand1 = operands[1];
224 if (CONSTANT_P (operand1) && flag_pic
225 && pic_address_needs_scratch (operand1))
226 operands[1] = operand1 = legitimize_address (1, operand1, 0, 0);
228 /* Handle most common case first: storing into a register. */
229 if (register_operand (operand0, mode))
231 if (register_operand (operand1, mode)
232 || (GET_CODE (operand1) == CONST_INT && SMALL_INT (operand1))
233 || GET_CODE (operand1) == HIGH
234 /* Only `general_operands' can come here, so MEM is ok. */
235 || GET_CODE (operand1) == MEM)
237 /* Run this case quickly. */
238 emit_insn (gen_rtx_SET (VOIDmode, operand0, operand1));
242 else if (GET_CODE (operand0) == MEM)
244 if (register_operand (operand1, mode)
245 || (operand1 == const0_rtx && GET_MODE_SIZE (mode) <= UNITS_PER_WORD))
247 /* Run this case quickly. */
248 emit_insn (gen_rtx_SET (VOIDmode, operand0, operand1));
251 if (! reload_in_progress && ! reload_completed)
253 operands[0] = validize_mem (operand0);
254 operands[1] = operand1 = force_reg (mode, operand1);
258 /* Simplify the source if we need to. */
259 if (GET_CODE (operand1) != HIGH && immediate_operand (operand1, mode))
261 if (GET_CODE (operand1) != CONST_INT
262 && GET_CODE (operand1) != CONST_DOUBLE)
264 rtx temp = ((reload_in_progress || reload_completed)
266 operands[1] = legitimize_address (flag_pic
267 && symbolic_address_p (operand1),
268 operand1, temp, scratch);
270 operands[1] = gen_rtx_SUBREG (mode, operands[1], 0);
274 /* Now have insn-emit do whatever it normally does. */
278 /* Return a legitimate reference for ORIG (either an address or a MEM)
279 using the register REG. If PIC and the address is already
280 position-independent, use ORIG. Newly generated position-independent
281 addresses go into a reg. This is REG if non zero, otherwise we
282 allocate register(s) as necessary. If this is called during reload,
283 and we need a second temp register, then we use SCRATCH, which is
284 provided via the SECONDARY_INPUT_RELOAD_CLASS mechanism. */
287 legitimize_address (pic, orig, reg, scratch)
293 rtx addr = (GET_CODE (orig) == MEM ? XEXP (orig, 0) : orig);
299 if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
303 if (reload_in_progress || reload_completed)
306 reg = gen_reg_rtx (Pmode);
311 /* If not during reload, allocate another temp reg here for
312 loading in the address, so that these instructions can be
313 optimized properly. */
314 temp = ((reload_in_progress || reload_completed)
315 ? reg : gen_reg_rtx (Pmode));
317 emit_insn (gen_rtx_SET
319 gen_rtx_HIGH (SImode,
320 gen_rtx_UNSPEC (SImode,
324 emit_insn (gen_rtx_SET
326 gen_rtx_LO_SUM (SImode, temp,
327 gen_rtx_UNSPEC (SImode,
333 new = gen_rtx_MEM (Pmode,
334 gen_rtx_PLUS (SImode,
335 pic_offset_table_rtx, addr));
337 current_function_uses_pic_offset_table = 1;
338 RTX_UNCHANGING_P (new) = 1;
339 insn = emit_move_insn (reg, new);
340 /* Put a REG_EQUAL note on this insn, so that it can be optimized
342 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig,
346 else if (GET_CODE (addr) == CONST)
350 if (GET_CODE (XEXP (addr, 0)) == PLUS
351 && XEXP (XEXP (addr, 0), 0) == pic_offset_table_rtx)
356 if (reload_in_progress || reload_completed)
359 reg = gen_reg_rtx (Pmode);
362 if (GET_CODE (XEXP (addr, 0)) != PLUS) abort ();
364 base = legitimize_address (1, XEXP (XEXP (addr, 0), 0), reg, 0);
365 addr = legitimize_address (1, XEXP (XEXP (addr, 0), 1),
366 base == reg ? 0 : reg, 0);
368 if (GET_CODE (addr) == CONST_INT)
371 return plus_constant_for_output (base, INTVAL (addr));
372 else if (! reload_in_progress && ! reload_completed)
373 addr = force_reg (Pmode, addr);
374 /* We can't create any new registers during reload, so use the
375 SCRATCH reg provided by the reload_insi pattern. */
378 emit_move_insn (scratch, addr);
382 /* If we reach here, then the SECONDARY_INPUT_RELOAD_CLASS
383 macro needs to be adjusted so that a scratch reg is provided
387 new = gen_rtx_PLUS (SImode, base, addr);
388 /* Should we set special REG_NOTEs here? */
391 else if (! SHORT_ADDRESS_P (addr, temp))
395 if (reload_in_progress || reload_completed)
398 reg = gen_reg_rtx (Pmode);
401 emit_insn (gen_rtx_SET (VOIDmode,
402 reg, gen_rtx_HIGH (SImode, addr)));
403 new = gen_rtx_LO_SUM (SImode, reg, addr);
407 && GET_CODE (orig) == MEM)
409 new = gen_rtx_MEM (GET_MODE (orig), new);
410 MEM_COPY_ATTRIBUTES (new, orig);
415 /* Support functions for code to emit a block move. There are four methods
416 used to perform the block move:
418 + call the looping library function, e.g. __movstrSI64n8
419 + call a non-looping library function, e.g. __movstrHI15x11
420 + produce an inline sequence of ld/st instructions
422 The parameters below describe the library functions produced by
425 #define MOVSTR_LOOP 64 /* __movstrSI64n68 .. __movstrSI64n8 */
426 #define MOVSTR_QI 16 /* __movstrQI16x16 .. __movstrQI16x2 */
427 #define MOVSTR_HI 48 /* __movstrHI48x48 .. __movstrHI48x4 */
428 #define MOVSTR_SI 96 /* __movstrSI96x96 .. __movstrSI96x8 */
429 #define MOVSTR_DI 96 /* __movstrDI96x96 .. __movstrDI96x16 */
430 #define MOVSTR_ODD_HI 16 /* __movstrHI15x15 .. __movstrHI15x5 */
431 #define MOVSTR_ODD_SI 48 /* __movstrSI47x47 .. __movstrSI47x11,
432 __movstrSI46x46 .. __movstrSI46x10,
433 __movstrSI45x45 .. __movstrSI45x9 */
434 #define MOVSTR_ODD_DI 48 /* __movstrDI47x47 .. __movstrDI47x23,
435 __movstrDI46x46 .. __movstrDI46x22,
436 __movstrDI45x45 .. __movstrDI45x21,
437 __movstrDI44x44 .. __movstrDI44x20,
438 __movstrDI43x43 .. __movstrDI43x19,
439 __movstrDI42x42 .. __movstrDI42x18,
440 __movstrDI41x41 .. __movstrDI41x17 */
442 /* Limits for using the non-looping movstr functions. For the m88100
443 processor, we assume the source and destination are word aligned.
444 The QImode and HImode limits are the break even points where memcpy
445 does just as well and beyond which memcpy does better. For the
446 m88110, we tend to assume double word alignment, but also analyze
447 the word aligned cases. The analysis is complicated because memcpy
448 may use the cache control instructions for better performance. */
450 #define MOVSTR_QI_LIMIT_88100 13
451 #define MOVSTR_HI_LIMIT_88100 38
452 #define MOVSTR_SI_LIMIT_88100 MOVSTR_SI
453 #define MOVSTR_DI_LIMIT_88100 MOVSTR_SI
455 #define MOVSTR_QI_LIMIT_88000 16
456 #define MOVSTR_HI_LIMIT_88000 38
457 #define MOVSTR_SI_LIMIT_88000 72
458 #define MOVSTR_DI_LIMIT_88000 72
460 #define MOVSTR_QI_LIMIT_88110 16
461 #define MOVSTR_HI_LIMIT_88110 38
462 #define MOVSTR_SI_LIMIT_88110 72
463 #define MOVSTR_DI_LIMIT_88110 72
465 static enum machine_mode mode_from_align[] =
466 {VOIDmode, QImode, HImode, VOIDmode, SImode,
467 VOIDmode, VOIDmode, VOIDmode, DImode};
468 static int max_from_align[] = {0, MOVSTR_QI, MOVSTR_HI, 0, MOVSTR_SI,
470 static int all_from_align[] = {0, MOVSTR_QI, MOVSTR_ODD_HI, 0, MOVSTR_ODD_SI,
471 0, 0, 0, MOVSTR_ODD_DI};
473 static int best_from_align[3][9] = {
474 {0, MOVSTR_QI_LIMIT_88100, MOVSTR_HI_LIMIT_88100, 0, MOVSTR_SI_LIMIT_88100,
475 0, 0, 0, MOVSTR_DI_LIMIT_88100},
476 {0, MOVSTR_QI_LIMIT_88110, MOVSTR_HI_LIMIT_88110, 0, MOVSTR_SI_LIMIT_88110,
477 0, 0, 0, MOVSTR_DI_LIMIT_88110},
478 {0, MOVSTR_QI_LIMIT_88000, MOVSTR_HI_LIMIT_88000, 0, MOVSTR_SI_LIMIT_88000,
479 0, 0, 0, MOVSTR_DI_LIMIT_88000}
482 static void block_move_loop PARAMS ((rtx, rtx, rtx, rtx, int, int));
483 static void block_move_no_loop PARAMS ((rtx, rtx, rtx, rtx, int, int));
484 static void block_move_sequence PARAMS ((rtx, rtx, rtx, rtx, int, int, int));
485 static void output_short_branch_defs PARAMS ((FILE *));
486 static int output_option PARAMS ((FILE *, const char *, const char *,
487 const char *, const char *, int, int));
489 /* Emit code to perform a block move. Choose the best method.
491 OPERANDS[0] is the destination.
492 OPERANDS[1] is the source.
493 OPERANDS[2] is the size.
494 OPERANDS[3] is the alignment safe to use. */
497 expand_block_move (dest_mem, src_mem, operands)
502 int align = INTVAL (operands[3]);
503 int constp = (GET_CODE (operands[2]) == CONST_INT);
504 int bytes = (constp ? INTVAL (operands[2]) : 0);
505 int target = (int) m88k_cpu;
507 if (! (PROCESSOR_M88100 == 0
508 && PROCESSOR_M88110 == 1
509 && PROCESSOR_M88000 == 2))
512 if (constp && bytes <= 0)
515 /* Determine machine mode to do move with. */
516 if (align > 4 && !TARGET_88110)
518 else if (align <= 0 || align == 3)
519 abort (); /* block move invalid alignment. */
521 if (constp && bytes <= 3 * align)
522 block_move_sequence (operands[0], dest_mem, operands[1], src_mem,
525 else if (constp && bytes <= best_from_align[target][align])
526 block_move_no_loop (operands[0], dest_mem, operands[1], src_mem,
529 else if (constp && align == 4 && TARGET_88100)
530 block_move_loop (operands[0], dest_mem, operands[1], src_mem,
535 #ifdef TARGET_MEM_FUNCTIONS
536 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "memcpy"), 0,
540 convert_to_mode (TYPE_MODE (sizetype), operands[2],
541 TREE_UNSIGNED (sizetype)),
542 TYPE_MODE (sizetype));
544 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "bcopy"), 0,
548 convert_to_mode (TYPE_MODE (integer_type_node),
550 TREE_UNSIGNED (integer_type_node)),
551 TYPE_MODE (integer_type_node));
556 /* Emit code to perform a block move by calling a looping movstr library
557 function. SIZE and ALIGN are known constants. DEST and SRC are
561 block_move_loop (dest, dest_mem, src, src_mem, size, align)
567 enum machine_mode mode;
576 /* Determine machine mode to do move with. */
580 /* Determine the structure of the loop. */
581 count = size / MOVSTR_LOOP;
582 units = (size - count * MOVSTR_LOOP) / align;
587 units += MOVSTR_LOOP / align;
592 block_move_no_loop (dest, dest_mem, src, src_mem, size, align);
596 remainder = size - count * MOVSTR_LOOP - units * align;
598 mode = mode_from_align[align];
599 sprintf (entry, "__movstr%s%dn%d",
600 GET_MODE_NAME (mode), MOVSTR_LOOP, units * align);
601 entry_name = get_identifier (entry);
603 offset_rtx = GEN_INT (MOVSTR_LOOP + (1 - units) * align);
605 value_rtx = gen_rtx_MEM (MEM_IN_STRUCT_P (src_mem) ? mode : BLKmode,
607 gen_rtx_REG (Pmode, 3),
609 MEM_COPY_ATTRIBUTES (value_rtx, src_mem);
611 emit_insn (gen_call_movstrsi_loop
612 (gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (entry_name)),
613 dest, src, offset_rtx, value_rtx,
614 gen_rtx_REG (mode, ((units & 1) ? 4 : 5)),
618 block_move_sequence (gen_rtx_REG (Pmode, 2), dest_mem,
619 gen_rtx_REG (Pmode, 3), src_mem,
620 remainder, align, MOVSTR_LOOP + align);
623 /* Emit code to perform a block move by calling a non-looping library
624 function. SIZE and ALIGN are known constants. DEST and SRC are
625 registers. OFFSET is the known starting point for the output pattern. */
628 block_move_no_loop (dest, dest_mem, src, src_mem, size, align)
634 enum machine_mode mode = mode_from_align[align];
635 int units = size / align;
636 int remainder = size - units * align;
644 if (remainder && size <= all_from_align[align])
646 most = all_from_align[align] - (align - remainder);
651 most = max_from_align[align];
654 sprintf (entry, "__movstr%s%dx%d",
655 GET_MODE_NAME (mode), most, size - remainder);
656 entry_name = get_identifier (entry);
658 offset_rtx = GEN_INT (most - (size - remainder));
660 value_rtx = gen_rtx_MEM (MEM_IN_STRUCT_P (src_mem) ? mode : BLKmode,
662 gen_rtx_REG (Pmode, 3),
665 MEM_COPY_ATTRIBUTES (value_rtx, src_mem);
667 value_reg = ((((most - (size - remainder)) / align) & 1) == 0
668 ? (align == 8 ? 6 : 5) : 4);
670 emit_insn (gen_call_block_move
671 (gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (entry_name)),
672 dest, src, offset_rtx, value_rtx,
673 gen_rtx_REG (mode, value_reg)));
676 block_move_sequence (gen_rtx_REG (Pmode, 2), dest_mem,
677 gen_rtx_REG (Pmode, 3), src_mem,
678 remainder, align, most);
681 /* Emit code to perform a block move with an offset sequence of ld/st
682 instructions (..., ld 0, st 1, ld 1, st 0, ...). SIZE and ALIGN are
683 known constants. DEST and SRC are registers. OFFSET is the known
684 starting point for the output pattern. */
687 block_move_sequence (dest, dest_mem, src, src_mem, size, align, offset)
695 enum machine_mode mode[2];
700 int offset_ld = offset;
701 int offset_st = offset;
703 active[0] = active[1] = FALSE;
705 /* Establish parameters for the first load and for the second load if
706 it is known to be the same mode as the first. */
707 amount[0] = amount[1] = align;
708 mode[0] = mode_from_align[align];
709 temp[0] = gen_reg_rtx (mode[0]);
710 if (size >= 2 * align)
713 temp[1] = gen_reg_rtx (mode[1]);
724 /* Change modes as the sequence tails off. */
725 if (size < amount[next])
727 amount[next] = (size >= 4 ? 4 : (size >= 2 ? 2 : 1));
728 mode[next] = mode_from_align[amount[next]];
729 temp[next] = gen_reg_rtx (mode[next]);
731 size -= amount[next];
732 srcp = gen_rtx_MEM (MEM_IN_STRUCT_P (src_mem) ? mode[next] : BLKmode,
733 plus_constant (src, offset_ld));
735 MEM_COPY_ATTRIBUTES (srcp, src_mem);
736 emit_insn (gen_rtx_SET (VOIDmode, temp[next], srcp));
737 offset_ld += amount[next];
743 active[phase] = FALSE;
745 = gen_rtx_MEM (MEM_IN_STRUCT_P (dest_mem) ? mode[phase] : BLKmode,
746 plus_constant (dest, offset_st));
748 MEM_COPY_ATTRIBUTES (dstp, dest_mem);
749 emit_insn (gen_rtx_SET (VOIDmode, dstp, temp[phase]));
750 offset_st += amount[phase];
753 while (active[next]);
756 /* Emit the code to do an AND operation. */
759 output_and (operands)
764 if (REG_P (operands[2]))
765 return "and %0,%1,%2";
767 value = INTVAL (operands[2]);
768 if (SMALL_INTVAL (value))
769 return "mask %0,%1,%2";
770 else if ((value & 0xffff0000) == 0xffff0000)
771 return "and %0,%1,%x2";
772 else if ((value & 0xffff) == 0xffff)
773 return "and.u %0,%1,%X2";
774 else if ((value & 0xffff) == 0)
775 return "mask.u %0,%1,%X2";
776 else if (integer_ok_for_set (~value))
777 return "clr %0,%1,%S2";
779 return "and.u %0,%1,%X2\n\tand %0,%0,%x2";
782 /* Emit the code to do an inclusive OR operation. */
785 output_ior (operands)
790 if (REG_P (operands[2]))
791 return "or %0,%1,%2";
793 value = INTVAL (operands[2]);
794 if (SMALL_INTVAL (value))
795 return "or %0,%1,%2";
796 else if ((value & 0xffff) == 0)
797 return "or.u %0,%1,%X2";
798 else if (integer_ok_for_set (value))
799 return "set %0,%1,%s2";
801 return "or.u %0,%1,%X2\n\tor %0,%0,%x2";
804 /* Emit the instructions for doing an XOR. */
807 output_xor (operands)
812 if (REG_P (operands[2]))
813 return "xor %0,%1,%2";
815 value = INTVAL (operands[2]);
816 if (SMALL_INTVAL (value))
817 return "xor %0,%1,%2";
818 else if ((value & 0xffff) == 0)
819 return "xor.u %0,%1,%X2";
821 return "xor.u %0,%1,%X2\n\txor %0,%0,%x2";
824 /* Output a call. Normally this is just bsr or jsr, but this also deals with
825 accomplishing a branch after the call by incrementing r1. This requires
826 that various assembler bugs be accommodated. The 4.30 DG/UX assembler
827 requires that forward references not occur when computing the difference of
828 two labels. The [version?] Motorola assembler computes a word difference.
829 No doubt there's more to come!
831 It would seem the same idea could be used to tail call, but in this case,
832 the epilogue will be non-null. */
834 static rtx sb_name = 0;
835 static rtx sb_high = 0;
836 static rtx sb_low = 0;
839 output_call (operands, addr)
849 /* This can be generalized, but there is currently no need. */
850 if (XVECLEN (final_sequence, 0) != 2)
853 /* The address of interior insns is not computed, so use the sequence. */
854 seq_insn = NEXT_INSN (PREV_INSN (XVECEXP (final_sequence, 0, 0)));
855 jump = XVECEXP (final_sequence, 0, 1);
856 if (GET_CODE (jump) == JUMP_INSN)
860 rtx dest = XEXP (SET_SRC (PATTERN (jump)), 0);
861 int delta = 4 * (INSN_ADDRESSES (INSN_UID (dest))
862 - INSN_ADDRESSES (INSN_UID (seq_insn))
864 #if (MONITOR_GCC & 0x2) /* How often do long branches happen? */
865 if ((unsigned) (delta + 0x8000) >= 0x10000)
866 warning ("Internal gcc monitor: short-branch(%x)", delta);
869 /* Delete the jump. */
870 PUT_CODE (jump, NOTE);
871 NOTE_LINE_NUMBER (jump) = NOTE_INSN_DELETED;
872 NOTE_SOURCE_FILE (jump) = 0;
874 /* We only do this optimization if -O2, modifying the value of
875 r1 in the delay slot confuses debuggers and profilers on some
878 If we loose, we must use the non-delay form. This is unlikely
879 to ever happen. If it becomes a problem, claim that a call
880 has two delay slots and only the second can be filled with
883 The 88110 can lose when a jsr.n r1 is issued and a page fault
884 occurs accessing the delay slot. So don't use jsr.n form when
887 #ifdef AS_BUG_IMMEDIATE_LABEL /* The assembler restricts immediate values. */
889 || ! ADD_INTVAL (delta * 2)
892 || ! ADD_INTVAL (delta)
894 || (REG_P (addr) && REGNO (addr) == 1))
900 ? "bsr %0#plt\n\tbr %l1"
901 : "bsr %0\n\tbr %l1"));
904 /* Output the short branch form. */
905 output_asm_insn ((REG_P (addr)
907 : (flag_pic ? "bsr.n %0#plt" : "bsr.n %0")),
912 ? "subu %#r1,%#r1,.-%l0+4"
913 : "addu %#r1,%#r1,%l0-.-4");
916 operands[0] = gen_label_rtx ();
917 operands[1] = gen_label_rtx ();
922 last = "subu %#r1,%#r1,%l0\n%l1:";
928 last = "addu %#r1,%#r1,%l0\n%l1:";
931 /* Record the values to be computed later as "def name,high-low". */
932 sb_name = gen_rtx_EXPR_LIST (VOIDmode, operands[0], sb_name);
933 sb_high = gen_rtx_EXPR_LIST (VOIDmode, high, sb_high);
934 sb_low = gen_rtx_EXPR_LIST (VOIDmode, low, sb_low);
935 #endif /* Don't USE_GAS */
942 : (flag_pic ? "bsr%. %0#plt" : "bsr%. %0"));
946 output_short_branch_defs (stream)
949 char name[256], high[256], low[256];
951 for (; sb_name && sb_high && sb_low;
952 sb_name = XEXP (sb_name, 1),
953 sb_high = XEXP (sb_high, 1),
954 sb_low = XEXP (sb_low, 1))
956 ASM_GENERATE_INTERNAL_LABEL
957 (name, "L", CODE_LABEL_NUMBER (XEXP (sb_name, 0)));
958 ASM_GENERATE_INTERNAL_LABEL
959 (high, "L", CODE_LABEL_NUMBER (XEXP (sb_high, 0)));
960 ASM_GENERATE_INTERNAL_LABEL
961 (low, "L", CODE_LABEL_NUMBER (XEXP (sb_low, 0)));
962 /* This will change as the assembler requirements become known. */
963 fprintf (stream, "%s%s,%s-%s\n",
964 SET_ASM_OP, &name[1], &high[1], &low[1]);
966 if (sb_name || sb_high || sb_low)
970 /* Return truth value of the statement that this conditional branch is likely
971 to fall through. CONDITION, is the condition that JUMP_INSN is testing. */
974 mostly_false_jump (jump_insn, condition)
975 rtx jump_insn, condition;
977 rtx target_label = JUMP_LABEL (jump_insn);
980 /* Much of this isn't computed unless we're optimizing. */
984 /* Determine if one path or the other leads to a return. */
985 for (insnt = NEXT_INSN (target_label);
987 insnt = NEXT_INSN (insnt))
989 if (GET_CODE (insnt) == JUMP_INSN)
991 else if (GET_CODE (insnt) == INSN
992 && GET_CODE (PATTERN (insnt)) == SEQUENCE
993 && GET_CODE (XVECEXP (PATTERN (insnt), 0, 0)) == JUMP_INSN)
995 insnt = XVECEXP (PATTERN (insnt), 0, 0);
1000 && (GET_CODE (PATTERN (insnt)) == RETURN
1001 || (GET_CODE (PATTERN (insnt)) == SET
1002 && GET_CODE (SET_SRC (PATTERN (insnt))) == REG
1003 && REGNO (SET_SRC (PATTERN (insnt))) == 1)))
1006 for (insnj = NEXT_INSN (jump_insn);
1008 insnj = NEXT_INSN (insnj))
1010 if (GET_CODE (insnj) == JUMP_INSN)
1012 else if (GET_CODE (insnj) == INSN
1013 && GET_CODE (PATTERN (insnj)) == SEQUENCE
1014 && GET_CODE (XVECEXP (PATTERN (insnj), 0, 0)) == JUMP_INSN)
1016 insnj = XVECEXP (PATTERN (insnj), 0, 0);
1021 && (GET_CODE (PATTERN (insnj)) == RETURN
1022 || (GET_CODE (PATTERN (insnj)) == SET
1023 && GET_CODE (SET_SRC (PATTERN (insnj))) == REG
1024 && REGNO (SET_SRC (PATTERN (insnj))) == 1)))
1027 /* Predict to not return. */
1028 if ((insnt == 0) != (insnj == 0))
1029 return (insnt == 0);
1031 /* Predict loops to loop. */
1032 for (insnt = PREV_INSN (target_label);
1033 insnt && GET_CODE (insnt) == NOTE;
1034 insnt = PREV_INSN (insnt))
1035 if (NOTE_LINE_NUMBER (insnt) == NOTE_INSN_LOOP_END)
1037 else if (NOTE_LINE_NUMBER (insnt) == NOTE_INSN_LOOP_BEG)
1039 else if (NOTE_LINE_NUMBER (insnt) == NOTE_INSN_LOOP_CONT)
1042 /* Predict backward branches usually take. */
1044 insnj = NEXT_INSN (PREV_INSN (XVECEXP (final_sequence, 0, 0)));
1047 if (INSN_ADDRESSES (INSN_UID (insnj))
1048 > INSN_ADDRESSES (INSN_UID (target_label)))
1051 /* EQ tests are usually false and NE tests are usually true. Also,
1052 most quantities are positive, so we can make the appropriate guesses
1053 about signed comparisons against zero. Consider unsigned comparisons
1054 to be a range check and assume quantities to be in range. */
1055 switch (GET_CODE (condition))
1058 /* Unconditional branch. */
1067 case GTU: /* Must get casesi right at least. */
1068 if (XEXP (condition, 1) == const0_rtx)
1075 if (XEXP (condition, 1) == const0_rtx)
1085 /* Return true if the operand is a power of two and is a floating
1086 point type (to optimize division by power of two into multiplication). */
1089 real_power_of_2_operand (op, mode)
1091 enum machine_mode mode ATTRIBUTE_UNUSED;
1095 int i[sizeof (REAL_VALUE_TYPE) / sizeof (int)];
1096 struct { /* IEEE double precision format */
1098 unsigned exponent : 11;
1099 unsigned mantissa1 : 20;
1102 struct { /* IEEE double format to quick check */
1103 unsigned sign : 1; /* if it fits in a float */
1104 unsigned exponent1 : 4;
1105 unsigned exponent2 : 7;
1106 unsigned mantissa1 : 20;
1111 if (GET_MODE (op) != DFmode && GET_MODE (op) != SFmode)
1114 if (GET_CODE (op) != CONST_DOUBLE)
1117 u.i[0] = CONST_DOUBLE_LOW (op);
1118 u.i[1] = CONST_DOUBLE_HIGH (op);
1120 if (u.s.mantissa1 != 0 || u.s.mantissa2 != 0 /* not a power of two */
1121 || u.s.exponent == 0 /* constant 0.0 */
1122 || u.s.exponent == 0x7ff /* NAN */
1123 || (u.s2.exponent1 != 0x8 && u.s2.exponent1 != 0x7))
1124 return 0; /* const won't fit in float */
1129 /* Make OP legitimate for mode MODE. Currently this only deals with DFmode
1130 operands, putting them in registers and making CONST_DOUBLE values
1131 SFmode where possible. */
1134 legitimize_operand (op, mode)
1136 enum machine_mode mode;
1140 union real_extract r;
1141 struct { /* IEEE double precision format */
1143 unsigned exponent : 11;
1144 unsigned mantissa1 : 20;
1147 struct { /* IEEE double format to quick check */
1148 unsigned sign : 1; /* if it fits in a float */
1149 unsigned exponent1 : 4;
1150 unsigned exponent2 : 7;
1151 unsigned mantissa1 : 20;
1156 if (GET_CODE (op) == REG || mode != DFmode)
1159 if (GET_CODE (op) == CONST_DOUBLE)
1161 memcpy (&u.r, &CONST_DOUBLE_LOW (op), sizeof u);
1162 if (u.d.exponent != 0x7ff /* NaN */
1163 && u.d.mantissa2 == 0 /* Mantissa fits */
1164 && (u.s.exponent1 == 0x8 || u.s.exponent1 == 0x7) /* Exponent fits */
1165 && (temp = simplify_unary_operation (FLOAT_TRUNCATE, SFmode,
1167 return gen_rtx_FLOAT_EXTEND (mode, force_reg (SFmode, temp));
1169 else if (register_operand (op, mode))
1172 return force_reg (mode, op);
1175 /* Return true if OP is a suitable input for a move insn. */
1178 move_operand (op, mode)
1180 enum machine_mode mode;
1182 if (register_operand (op, mode))
1184 if (GET_CODE (op) == CONST_INT)
1185 return (classify_integer (mode, INTVAL (op)) < m88k_oru_hi16);
1186 if (GET_MODE (op) != mode)
1188 if (GET_CODE (op) == SUBREG)
1189 op = SUBREG_REG (op);
1190 if (GET_CODE (op) != MEM)
1194 if (GET_CODE (op) == LO_SUM)
1195 return (REG_P (XEXP (op, 0))
1196 && symbolic_address_p (XEXP (op, 1)));
1197 return memory_address_p (mode, op);
1200 /* Return true if OP is suitable for a call insn. */
1203 call_address_operand (op, mode)
1205 enum machine_mode mode ATTRIBUTE_UNUSED;
1207 return (REG_P (op) || symbolic_address_p (op));
1210 /* Returns true if OP is either a symbol reference or a sum of a symbol
1211 reference and a constant. */
1214 symbolic_address_p (op)
1217 switch (GET_CODE (op))
1225 return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1226 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1227 && GET_CODE (XEXP (op, 1)) == CONST_INT);
1234 /* Return true if OP is a register or const0_rtx. */
1237 reg_or_0_operand (op, mode)
1239 enum machine_mode mode;
1241 return (op == const0_rtx || register_operand (op, mode));
1244 /* Nonzero if OP is a valid second operand for an arithmetic insn. */
1247 arith_operand (op, mode)
1249 enum machine_mode mode;
1251 return (register_operand (op, mode)
1252 || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));
1255 /* Return true if OP is a register or 5 bit integer. */
1258 arith5_operand (op, mode)
1260 enum machine_mode mode;
1262 return (register_operand (op, mode)
1263 || (GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 32));
1267 arith32_operand (op, mode)
1269 enum machine_mode mode;
1271 return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
1275 arith64_operand (op, mode)
1277 enum machine_mode mode;
1279 return (register_operand (op, mode)
1280 || GET_CODE (op) == CONST_INT
1281 || (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode));
1285 int5_operand (op, mode)
1287 enum machine_mode mode ATTRIBUTE_UNUSED;
1289 return (GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 32);
1293 int32_operand (op, mode)
1295 enum machine_mode mode ATTRIBUTE_UNUSED;
1297 return (GET_CODE (op) == CONST_INT);
1300 /* Return true if OP is a register or a valid immediate operand for
1304 add_operand (op, mode)
1306 enum machine_mode mode;
1308 return (register_operand (op, mode)
1309 || (GET_CODE (op) == CONST_INT && ADD_INT (op)));
1312 /* Nonzero if this is a bitmask filling the bottom bits, for optimizing and +
1313 shift left combinations into a single mak instruction. */
1319 return (value && POWER_OF_2_or_0 (value + 1));
1323 reg_or_bbx_mask_operand (op, mode)
1325 enum machine_mode mode;
1328 if (register_operand (op, mode))
1330 if (GET_CODE (op) != CONST_INT)
1333 value = INTVAL (op);
1334 if (POWER_OF_2 (value))
1340 /* Return true if OP is valid to use in the context of a floating
1341 point operation. Special case 0.0, since we can use r0. */
1344 real_or_0_operand (op, mode)
1346 enum machine_mode mode;
1348 if (mode != SFmode && mode != DFmode)
1351 return (register_operand (op, mode)
1352 || (GET_CODE (op) == CONST_DOUBLE
1353 && op == CONST0_RTX (mode)));
1356 /* Return true if OP is valid to use in the context of logic arithmetic
1357 on condition codes. */
1360 partial_ccmode_register_operand (op, mode)
1362 enum machine_mode mode ATTRIBUTE_UNUSED;
1364 return register_operand (op, CCmode) || register_operand (op, CCEVENmode);
1367 /* Return true if OP is a relational operator. */
1372 enum machine_mode mode ATTRIBUTE_UNUSED;
1374 switch (GET_CODE (op))
1393 even_relop (op, mode)
1395 enum machine_mode mode ATTRIBUTE_UNUSED;
1397 switch (GET_CODE (op))
1411 odd_relop (op, mode)
1413 enum machine_mode mode ATTRIBUTE_UNUSED;
1415 switch (GET_CODE (op))
1428 /* Return true if OP is a relational operator, and is not an unsigned
1429 relational operator. */
1432 relop_no_unsigned (op, mode)
1434 enum machine_mode mode ATTRIBUTE_UNUSED;
1436 switch (GET_CODE (op))
1444 /* @@ What is this test doing? Why not use `mode'? */
1445 if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT
1446 || GET_MODE (op) == DImode
1447 || GET_MODE_CLASS (GET_MODE (XEXP (op, 0))) == MODE_FLOAT
1448 || GET_MODE (XEXP (op, 0)) == DImode
1449 || GET_MODE_CLASS (GET_MODE (XEXP (op, 1))) == MODE_FLOAT
1450 || GET_MODE (XEXP (op, 1)) == DImode)
1458 /* Return true if the code of this rtx pattern is EQ or NE. */
1461 equality_op (op, mode)
1463 enum machine_mode mode ATTRIBUTE_UNUSED;
1465 return (GET_CODE (op) == EQ || GET_CODE (op) == NE);
1468 /* Return true if the code of this rtx pattern is pc or label_ref. */
1471 pc_or_label_ref (op, mode)
1473 enum machine_mode mode ATTRIBUTE_UNUSED;
1475 return (GET_CODE (op) == PC || GET_CODE (op) == LABEL_REF);
1478 /* Output to FILE the start of the assembler file. */
1480 /* This definition must match lang_independent_options from toplev.c. */
1481 struct m88k_lang_independent_options
1486 const char *description;
1489 static void output_options PARAMS ((FILE *,
1490 struct m88k_lang_independent_options *,
1492 struct m88k_lang_independent_options *,
1493 int, int, int, const char *, const char *,
1497 output_option (file, sep, type, name, indent, pos, max)
1506 if ((long)(strlen (sep) + strlen (type) + strlen (name) + pos) > max)
1508 fprintf (file, indent);
1509 return fprintf (file, "%s%s", type, name);
1511 return pos + fprintf (file, "%s%s%s", sep, type, name);
1514 static struct { const char *name; int value; } m_options[] = TARGET_SWITCHES;
1517 output_options (file, f_options, f_len, W_options, W_len,
1518 pos, max, sep, indent, term)
1520 struct m88k_lang_independent_options *f_options;
1521 struct m88k_lang_independent_options *W_options;
1532 pos = output_option (file, sep, "-O", "", indent, pos, max);
1533 if (write_symbols != NO_DEBUG)
1534 pos = output_option (file, sep, "-g", "", indent, pos, max);
1535 if (flag_traditional)
1536 pos = output_option (file, sep, "-traditional", "", indent, pos, max);
1538 pos = output_option (file, sep, "-p", "", indent, pos, max);
1539 if (profile_block_flag)
1540 pos = output_option (file, sep, "-a", "", indent, pos, max);
1542 for (j = 0; j < f_len; j++)
1543 if (*f_options[j].variable == f_options[j].on_value)
1544 pos = output_option (file, sep, "-f", f_options[j].string,
1547 for (j = 0; j < W_len; j++)
1548 if (*W_options[j].variable == W_options[j].on_value)
1549 pos = output_option (file, sep, "-W", W_options[j].string,
1552 for (j = 0; j < (long) ARRAY_SIZE (m_options); j++)
1553 if (m_options[j].name[0] != '\0'
1554 && m_options[j].value > 0
1555 && ((m_options[j].value & target_flags)
1556 == m_options[j].value))
1557 pos = output_option (file, sep, "-m", m_options[j].name,
1560 if (m88k_short_data)
1561 pos = output_option (file, sep, "-mshort-data-", m88k_short_data,
1564 fprintf (file, term);
1568 output_file_start (file, f_options, f_len, W_options, W_len)
1570 struct m88k_lang_independent_options *f_options;
1571 struct m88k_lang_independent_options *W_options;
1576 ASM_FIRST_LINE (file);
1579 fprintf (file, "%s\n", REQUIRES_88110_ASM_OP);
1580 output_file_directive (file, main_input_filename);
1581 /* Switch to the data section so that the coffsem symbol
1582 isn't in the text section. */
1585 if (TARGET_IDENTIFY_REVISION)
1589 time_t now = time ((time_t *)0);
1590 sprintf (indent, "]\"\n%s\"@(#)%s [", IDENT_ASM_OP, main_input_filename);
1591 fprintf (file, indent+3);
1592 pos = fprintf (file, "gcc %s, %.24s,", version_string, ctime (&now));
1594 /* ??? It would be nice to call print_switch_values here (and thereby
1595 let us delete output_options) but this is kept in until it is known
1596 whether the change in content format matters. */
1597 output_options (file, f_options, f_len, W_options, W_len,
1598 pos, 150 - strlen (indent), " ", indent, "]\"\n\n");
1600 fprintf (file, "]\"\n");
1601 print_switch_values (file, 0, 150 - strlen (indent),
1602 indent + 3, " ", "]\"\n");
1607 /* Output an ascii string. */
1610 output_ascii (file, opcode, max, p, size)
1614 const unsigned char *p;
1620 register int num = 0;
1622 fprintf (file, "%s\"", opcode);
1623 for (i = 0; i < size; i++)
1625 register int c = p[i];
1629 fprintf (file, "\"\n%s\"", opcode);
1633 if (c == '\"' || c == '\\')
1641 else if (in_escape && c >= '0' && c <= '9')
1643 /* If a digit follows an octal-escape, the Vax assembler fails
1644 to stop reading the escape after three digits. Continue to
1645 output the values as an octal-escape until a non-digit is
1647 fprintf (file, "\\%03o", c);
1650 else if ((c >= ' ' && c < 0177) || (c == '\t'))
1660 /* Some assemblers can't handle \a, \v, or \?. */
1661 case '\f': c = 'f'; goto escape;
1662 case '\b': c = 'b'; goto escape;
1663 case '\r': c = 'r'; goto escape;
1664 case '\n': c = 'n'; goto escape;
1667 fprintf (file, "\\%03o", c);
1672 fprintf (file, "\"\n");
1675 /* Output a label (allows insn-output.c to be compiled without including
1676 m88k.c or needing to include stdio.h). */
1679 output_label (label_number)
1682 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", label_number);
1685 /* Generate the assembly code for function entry.
1687 The prologue is responsible for setting up the stack frame,
1688 initializing the frame pointer register, saving registers that must be
1689 saved, and allocating SIZE additional bytes of storage for the
1690 local variables. SIZE is an integer. FILE is a stdio
1691 stream to which the assembler code should be output.
1693 The label for the beginning of the function need not be output by this
1694 macro. That has already been done when the macro is run.
1696 To determine which registers to save, the macro can refer to the array
1697 `regs_ever_live': element R is nonzero if hard register
1698 R is used anywhere within the function. This implies the
1699 function prologue should save register R, but not if it is one
1700 of the call-used registers.
1702 On machines where functions may or may not have frame-pointers, the
1703 function entry code must vary accordingly; it must set up the frame
1704 pointer if one is wanted, and not otherwise. To determine whether a
1705 frame pointer is in wanted, the macro can refer to the variable
1706 `frame_pointer_needed'. The variable's value will be 1 at run
1707 time in a function that needs a frame pointer.
1709 On machines where an argument may be passed partly in registers and
1710 partly in memory, this macro must examine the variable
1711 `current_function_pretend_args_size', and allocate that many bytes
1712 of uninitialized space on the stack just underneath the first argument
1713 arriving on the stack. (This may not be at the very end of the stack,
1714 if the calling sequence has pushed anything else since pushing the stack
1715 arguments. But usually, on such machines, nothing else has been pushed
1716 yet, because the function prologue itself does all the pushing.)
1718 If `ACCUMULATE_OUTGOING_ARGS' is defined, the variable
1719 `current_function_outgoing_args_size' contains the size in bytes
1720 required for the outgoing arguments. This macro must add that
1721 amount of uninitialized space to very bottom of the stack.
1723 The stack frame we use looks like this:
1726 |==============================================|
1728 |==============================================|
1729 | [caller's outgoing memory arguments] |
1730 |==============================================|
1731 | caller's outgoing argument area (32 bytes) |
1732 sp -> |==============================================| <- ap
1733 | [local variable space] |
1734 |----------------------------------------------|
1735 | [return address (r1)] |
1736 |----------------------------------------------|
1737 | [previous frame pointer (r30)] |
1738 |==============================================| <- fp
1739 | [preserved registers (r25..r14)] |
1740 |----------------------------------------------|
1741 | [preserved registers (x29..x22)] |
1742 |==============================================|
1743 | [dynamically allocated space (alloca)] |
1744 |==============================================|
1745 | [callee's outgoing memory arguments] |
1746 |==============================================|
1747 | [callee's outgoing argument area (32 bytes)] |
1748 |==============================================| <- sp
1752 r1 and r30 must be saved if debugging.
1754 fp (if present) is located two words down from the local
1758 static void emit_add PARAMS ((rtx, rtx, int));
1759 static void preserve_registers PARAMS ((int, int));
1760 static void emit_ldst PARAMS ((int, int, enum machine_mode, int));
1761 static void output_tdesc PARAMS ((FILE *, int));
1762 static int uses_arg_area_p PARAMS ((void));
1766 static char save_regs[FIRST_PSEUDO_REGISTER];
1767 static int frame_laid_out;
1768 static int frame_size;
1769 static int variable_args_p;
1770 static int epilogue_marked;
1771 static int prologue_marked;
1773 #define FIRST_OCS_PRESERVE_REGISTER 14
1774 #define LAST_OCS_PRESERVE_REGISTER 30
1776 #define FIRST_OCS_EXTENDED_PRESERVE_REGISTER (32 + 22)
1777 #define LAST_OCS_EXTENDED_PRESERVE_REGISTER (32 + 31)
1779 #define STACK_UNIT_BOUNDARY (STACK_BOUNDARY / BITS_PER_UNIT)
1780 #define ROUND_CALL_BLOCK_SIZE(BYTES) \
1781 (((BYTES) + (STACK_UNIT_BOUNDARY - 1)) & ~(STACK_UNIT_BOUNDARY - 1))
1783 /* Establish the position of the FP relative to the SP. This is done
1784 either during FUNCTION_PROLOGUE or by INITIAL_ELIMINATION_OFFSET. */
1787 m88k_layout_frame ()
1793 memset ((char *) &save_regs[0], 0, sizeof (save_regs));
1794 sp_size = nregs = nxregs = 0;
1795 frame_size = get_frame_size ();
1797 /* Since profiling requires a call, make sure r1 is saved. */
1798 if (profile_flag || profile_block_flag)
1801 /* If we are producing debug information, store r1 and r30 where the
1802 debugger wants to find them (r30 at r30+0, r1 at r30+4). Space has
1803 already been reserved for r1/r30 in STARTING_FRAME_OFFSET. */
1804 if (write_symbols != NO_DEBUG && !TARGET_OCS_FRAME_POSITION)
1807 /* If there is a call, alloca is used, __builtin_alloca is used, or
1808 a dynamic-sized object is defined, add the 8 additional words
1809 for the callee's argument area. The common denominator is that the
1810 FP is required. may_call_alloca only gets calls to alloca;
1811 current_function_calls_alloca gets alloca and __builtin_alloca. */
1812 if (regs_ever_live[1] || frame_pointer_needed)
1815 sp_size += REG_PARM_STACK_SPACE (0);
1818 /* If we are producing PIC, save the addressing base register and r1. */
1819 if (flag_pic && current_function_uses_pic_offset_table)
1821 save_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
1825 /* If a frame is requested, save the previous FP, and the return
1826 address (r1), so that a traceback can be done without using tdesc
1827 information. Otherwise, simply save the FP if it is used as
1828 a preserve register. */
1829 if (frame_pointer_needed)
1830 save_regs[FRAME_POINTER_REGNUM] = save_regs[1] = 1;
1831 else if (regs_ever_live[FRAME_POINTER_REGNUM])
1832 save_regs[FRAME_POINTER_REGNUM] = 1;
1834 /* Figure out which extended register(s) needs to be saved. */
1835 for (regno = FIRST_EXTENDED_REGISTER + 1; regno < FIRST_PSEUDO_REGISTER;
1837 if (regs_ever_live[regno] && ! call_used_regs[regno])
1839 save_regs[regno] = 1;
1843 /* Figure out which normal register(s) needs to be saved. */
1844 for (regno = 2; regno < FRAME_POINTER_REGNUM; regno++)
1845 if (regs_ever_live[regno] && ! call_used_regs[regno])
1847 save_regs[regno] = 1;
1851 /* Achieve greatest use of double memory ops. Either we end up saving
1852 r30 or we use that slot to align the registers we do save. */
1853 if (nregs >= 2 && save_regs[1] && !save_regs[FRAME_POINTER_REGNUM])
1856 nregs += save_regs[1] + save_regs[FRAME_POINTER_REGNUM];
1857 /* if we need to align extended registers, add a word */
1858 if (nxregs > 0 && (nregs & 1) != 0)
1860 sp_size += 4 * nregs;
1861 sp_size += 8 * nxregs;
1862 sp_size += current_function_outgoing_args_size;
1864 /* The first two saved registers are placed above the new frame pointer
1865 if any. In the only case this matters, they are r1 and r30. */
1866 if (frame_pointer_needed || sp_size)
1867 m88k_fp_offset = ROUND_CALL_BLOCK_SIZE (sp_size - STARTING_FRAME_OFFSET);
1869 m88k_fp_offset = -STARTING_FRAME_OFFSET;
1870 m88k_stack_size = m88k_fp_offset + STARTING_FRAME_OFFSET;
1872 /* First, combine m88k_stack_size and size. If m88k_stack_size is
1873 non-zero, align the frame size to 8 mod 16; otherwise align the
1874 frame size to 0 mod 16. (If stacks are 8 byte aligned, this ends
1878 = ((m88k_stack_size ? STACK_UNIT_BOUNDARY - STARTING_FRAME_OFFSET : 0)
1879 - (frame_size % STACK_UNIT_BOUNDARY));
1883 need += STACK_UNIT_BOUNDARY;
1884 (void) assign_stack_local (BLKmode, need, BITS_PER_UNIT);
1885 frame_size = get_frame_size ();
1888 = ROUND_CALL_BLOCK_SIZE (m88k_stack_size + frame_size
1889 + current_function_pretend_args_size);
1893 /* Return true if this function is known to have a null prologue. */
1898 if (! reload_completed)
1900 if (! frame_laid_out)
1901 m88k_layout_frame ();
1902 return (! frame_pointer_needed
1905 && m88k_stack_size == 0);
1908 /* Determine if the current function has any references to the arg pointer.
1909 This is done indirectly by examining the DECL_ARGUMENTS' DECL_RTL.
1910 It is OK to return TRUE if there are no references, but FALSE must be
1918 if (current_function_decl == 0
1919 || current_function_varargs
1923 for (parm = DECL_ARGUMENTS (current_function_decl);
1925 parm = TREE_CHAIN (parm))
1927 if (DECL_RTL (parm) == 0
1928 || GET_CODE (DECL_RTL (parm)) == MEM)
1931 if (DECL_INCOMING_RTL (parm) == 0
1932 || GET_CODE (DECL_INCOMING_RTL (parm)) == MEM)
1939 m88k_begin_prologue (stream, size)
1940 FILE *stream ATTRIBUTE_UNUSED;
1941 int size ATTRIBUTE_UNUSED;
1943 if (TARGET_OMIT_LEAF_FRAME_POINTER && ! quiet_flag && leaf_function_p ())
1944 fprintf (stderr, "$");
1946 m88k_prologue_done = 1; /* it's ok now to put out ln directives */
1950 m88k_end_prologue (stream)
1953 if (TARGET_OCS_DEBUG_INFO && !prologue_marked)
1955 PUT_OCS_FUNCTION_START (stream);
1956 prologue_marked = 1;
1958 /* If we've already passed the start of the epilogue, say that
1959 it starts here. This marks the function as having a null body,
1960 but at a point where the return address is in a known location.
1962 Originally, I thought this couldn't happen, but the pic prologue
1963 for leaf functions ends with the instruction that restores the
1964 return address from the temporary register. If the temporary
1965 register is never used, that instruction can float all the way
1966 to the end of the function. */
1967 if (epilogue_marked)
1968 PUT_OCS_FUNCTION_END (stream);
1973 m88k_expand_prologue ()
1975 m88k_layout_frame ();
1977 if (TARGET_OPTIMIZE_ARG_AREA
1979 && ! uses_arg_area_p ())
1981 /* The incoming argument area is used for stack space if it is not
1982 used (or if -mno-optimize-arg-area is given). */
1983 if ((m88k_stack_size -= REG_PARM_STACK_SPACE (0)) < 0)
1984 m88k_stack_size = 0;
1987 if (m88k_stack_size)
1988 emit_add (stack_pointer_rtx, stack_pointer_rtx, -m88k_stack_size);
1990 if (nregs || nxregs)
1991 preserve_registers (m88k_fp_offset + 4, 1);
1993 if (frame_pointer_needed)
1994 emit_add (frame_pointer_rtx, stack_pointer_rtx, m88k_fp_offset);
1996 if (flag_pic && save_regs[PIC_OFFSET_TABLE_REGNUM])
1998 rtx return_reg = gen_rtx_REG (SImode, 1);
1999 rtx label = gen_label_rtx ();
2004 temp_reg = gen_rtx_REG (SImode, TEMP_REGNUM);
2005 emit_move_insn (temp_reg, return_reg);
2007 emit_insn (gen_locate1 (pic_offset_table_rtx, label));
2008 emit_insn (gen_locate2 (pic_offset_table_rtx, label));
2009 emit_insn (gen_addsi3 (pic_offset_table_rtx,
2010 pic_offset_table_rtx, return_reg));
2012 emit_move_insn (return_reg, temp_reg);
2014 if (profile_flag || profile_block_flag)
2015 emit_insn (gen_blockage ());
2018 /* This function generates the assembly code for function exit,
2019 on machines that need it. Args are same as for FUNCTION_PROLOGUE.
2021 The function epilogue should not depend on the current stack pointer!
2022 It should use the frame pointer only, if there is a frame pointer.
2023 This is mandatory because of alloca; we also take advantage of it to
2024 omit stack adjustments before returning. */
2027 m88k_begin_epilogue (stream)
2030 if (TARGET_OCS_DEBUG_INFO && !epilogue_marked && prologue_marked)
2032 PUT_OCS_FUNCTION_END (stream);
2034 epilogue_marked = 1;
2038 m88k_end_epilogue (stream, size)
2040 int size ATTRIBUTE_UNUSED;
2042 rtx insn = get_last_insn ();
2044 if (TARGET_OCS_DEBUG_INFO && !epilogue_marked)
2045 PUT_OCS_FUNCTION_END (stream);
2047 /* If the last insn isn't a BARRIER, we must write a return insn. This
2048 should only happen if the function has no prologue and no body. */
2049 if (GET_CODE (insn) == NOTE)
2050 insn = prev_nonnote_insn (insn);
2051 if (insn == 0 || GET_CODE (insn) != BARRIER)
2052 fprintf (stream, "\tjmp\t %s\n", reg_names[1]);
2054 /* If the last insn is a barrier, and the insn before that is a call,
2055 then add a nop instruction so that tdesc can walk the stack correctly
2056 even though there is no epilogue. (Otherwise, the label for the
2057 end of the tdesc region ends up at the start of the next function. */
2058 if (insn && GET_CODE (insn) == BARRIER)
2060 insn = prev_nonnote_insn (insn);
2061 if (insn && GET_CODE (insn) == CALL_INSN)
2062 fprintf (stream, "\tor\t %s,%s,%s\n",reg_names[0],reg_names[0],reg_names[0]);
2065 output_short_branch_defs (stream);
2067 fprintf (stream, "\n");
2069 if (TARGET_OCS_DEBUG_INFO)
2070 output_tdesc (stream, m88k_fp_offset + 4);
2072 m88k_function_number++;
2073 m88k_prologue_done = 0; /* don't put out ln directives */
2074 variable_args_p = 0; /* has variable args */
2076 epilogue_marked = 0;
2077 prologue_marked = 0;
2081 m88k_expand_epilogue ()
2083 #if (MONITOR_GCC & 0x4) /* What are interesting prologue/epilogue values? */
2084 fprintf (stream, "; size = %d, m88k_fp_offset = %d, m88k_stack_size = %d\n",
2085 size, m88k_fp_offset, m88k_stack_size);
2088 if (frame_pointer_needed)
2089 emit_add (stack_pointer_rtx, frame_pointer_rtx, -m88k_fp_offset);
2091 if (nregs || nxregs)
2092 preserve_registers (m88k_fp_offset + 4, 0);
2094 if (m88k_stack_size)
2095 emit_add (stack_pointer_rtx, stack_pointer_rtx, m88k_stack_size);
2098 /* Emit insns to set DSTREG to SRCREG + AMOUNT during the prologue or
2102 emit_add (dstreg, srcreg, amount)
2107 rtx incr = GEN_INT (abs (amount));
2109 if (! ADD_INTVAL (amount))
2111 rtx temp = gen_rtx_REG (SImode, TEMP_REGNUM);
2112 emit_move_insn (temp, incr);
2115 emit_insn ((amount < 0 ? gen_subsi3 : gen_addsi3) (dstreg, srcreg, incr));
2118 /* Save/restore the preserve registers. base is the highest offset from
2119 r31 at which a register is stored. store_p is true if stores are to
2120 be done; otherwise loads. */
2123 preserve_registers (base, store_p)
2132 } mem_op[FIRST_PSEUDO_REGISTER];
2133 struct mem_op *mo_ptr = mem_op;
2135 /* The 88open OCS mandates that preserved registers be stored in
2136 increasing order. For compatibility with current practice,
2137 the order is r1, r30, then the preserve registers. */
2142 /* An extra word is given in this case to make best use of double
2144 if (nregs > 2 && !save_regs[FRAME_POINTER_REGNUM])
2146 emit_ldst (store_p, 1, SImode, offset);
2151 /* Walk the registers to save recording all single memory operations. */
2152 for (regno = FRAME_POINTER_REGNUM; regno > 1; regno--)
2153 if (save_regs[regno])
2155 if ((offset & 7) != 4 || (regno & 1) != 1 || !save_regs[regno-1])
2158 mo_ptr->regno = regno;
2159 mo_ptr->offset = offset;
2170 /* Walk the registers to save recording all double memory operations.
2171 This avoids a delay in the epilogue (ld.d/ld). */
2173 for (regno = FRAME_POINTER_REGNUM; regno > 1; regno--)
2174 if (save_regs[regno])
2176 if ((offset & 7) != 4 || (regno & 1) != 1 || !save_regs[regno-1])
2183 mo_ptr->regno = regno-1;
2184 mo_ptr->offset = offset-4;
2191 /* Walk the extended registers to record all memory operations. */
2192 /* Be sure the offset is double word aligned. */
2193 offset = (offset - 1) & ~7;
2194 for (regno = FIRST_PSEUDO_REGISTER - 1; regno > FIRST_EXTENDED_REGISTER;
2196 if (save_regs[regno])
2199 mo_ptr->regno = regno;
2200 mo_ptr->offset = offset;
2207 /* Output the memory operations. */
2208 for (mo_ptr = mem_op; mo_ptr->regno; mo_ptr++)
2211 emit_ldst (store_p, mo_ptr->regno,
2212 (mo_ptr->nregs > 1 ? DImode : SImode),
2218 emit_ldst (store_p, regno, mode, offset)
2221 enum machine_mode mode;
2224 rtx reg = gen_rtx_REG (mode, regno);
2227 if (SMALL_INTVAL (offset))
2229 mem = gen_rtx_MEM (mode, plus_constant (stack_pointer_rtx, offset));
2233 /* offset is too large for immediate index must use register */
2235 rtx disp = GEN_INT (offset);
2236 rtx temp = gen_rtx_REG (SImode, TEMP_REGNUM);
2237 rtx regi = gen_rtx_PLUS (SImode, stack_pointer_rtx, temp);
2239 emit_move_insn (temp, disp);
2240 mem = gen_rtx_MEM (mode, regi);
2244 emit_move_insn (mem, reg);
2246 emit_move_insn (reg, mem);
2249 /* Convert the address expression REG to a CFA offset. */
2252 m88k_debugger_offset (reg, offset)
2254 register int offset;
2256 if (GET_CODE (reg) == PLUS)
2258 offset = INTVAL (XEXP (reg, 1));
2259 reg = XEXP (reg, 0);
2262 /* Put the offset in terms of the CFA (arg pointer). */
2263 if (reg == frame_pointer_rtx)
2264 offset += m88k_fp_offset - m88k_stack_size;
2265 else if (reg == stack_pointer_rtx)
2266 offset -= m88k_stack_size;
2267 else if (reg != arg_pointer_rtx)
2269 #if (MONITOR_GCC & 0x10) /* Watch for suspicious symbolic locations. */
2270 if (! (GET_CODE (reg) == REG
2271 && REGNO (reg) >= FIRST_PSEUDO_REGISTER))
2272 warning ("Internal gcc error: Can't express symbolic location");
2280 /* Output the 88open OCS proscribed text description information.
2283 0 22: info-byte-length (16 or 20 bytes)
2284 0 2: info-alignment (word 2)
2285 1 32: info-protocol (version 1 or 2(pic))
2286 2 32: starting-address (inclusive, not counting prologue)
2287 3 32: ending-address (exclusive, not counting epilog)
2288 4 8: info-variant (version 1 or 3(extended registers))
2289 4 17: register-save-mask (from register 14 to 30)
2291 4 1: return-address-info-discriminant
2292 4 5: frame-address-register
2293 5 32: frame-address-offset
2294 6 32: return-address-info
2295 7 32: register-save-offset
2296 8 16: extended-register-save-mask (x16 - x31)
2297 8 16: extended-register-save-offset (WORDS from register-save-offset) */
2300 output_tdesc (file, offset)
2305 long mask, return_address_info, register_save_offset;
2306 long xmask, xregister_save_offset;
2309 for (mask = 0, i = 0, regno = FIRST_OCS_PRESERVE_REGISTER;
2310 regno <= LAST_OCS_PRESERVE_REGISTER;
2314 if (save_regs[regno])
2321 for (xmask = 0, j = 0, regno = FIRST_OCS_EXTENDED_PRESERVE_REGISTER;
2322 regno <= LAST_OCS_EXTENDED_PRESERVE_REGISTER;
2326 if (save_regs[regno])
2335 if ((nxregs > 0 || nregs > 2) && !save_regs[FRAME_POINTER_REGNUM])
2337 return_address_info = - m88k_stack_size + offset;
2338 register_save_offset = return_address_info - i*4;
2342 return_address_info = 1;
2343 register_save_offset = - m88k_stack_size + offset + 4 - i*4;
2346 xregister_save_offset = - (j * 2 + ((register_save_offset >> 2) & 1));
2350 fprintf (file, "%s%d,%d", INT_ASM_OP, /* 8:0,22:(20 or 16),2:2 */
2351 (((xmask != 0) ? 20 : 16) << 2) | 2,
2354 ASM_GENERATE_INTERNAL_LABEL (buf, OCS_START_PREFIX, m88k_function_number);
2355 fprintf (file, ",%s%s", buf+1, flag_pic ? "#rel" : "");
2356 ASM_GENERATE_INTERNAL_LABEL (buf, OCS_END_PREFIX, m88k_function_number);
2357 fprintf (file, ",%s%s", buf+1, flag_pic ? "#rel" : "");
2359 fprintf (file, ",0x%x,0x%x,0x%lx,0x%lx",
2360 /* 8:1,17:0x%.3x,1:0,1:%d,5:%d */
2361 (int)(((xmask ? 3 : 1) << (17+1+1+5))
2363 | ((!!save_regs[1]) << 5)
2364 | (frame_pointer_needed
2365 ? FRAME_POINTER_REGNUM
2366 : STACK_POINTER_REGNUM)),
2367 (m88k_stack_size - (frame_pointer_needed ? m88k_fp_offset : 0)),
2368 return_address_info,
2369 register_save_offset);
2371 fprintf (file, ",0x%lx%04lx", xmask, (0xffff & xregister_save_offset));
2377 /* Output assembler code to FILE to increment profiler label # LABELNO
2378 for profiling a function entry. NAME is the mcount function name
2379 (varies), SAVEP indicates whether the parameter registers need to
2380 be saved and restored. */
2383 output_function_profiler (file, labelno, name, savep)
2391 const char *temp = (savep ? reg_names[2] : reg_names[10]);
2393 /* Remember to update FUNCTION_PROFILER_LENGTH. */
2397 fprintf (file, "\tsubu\t %s,%s,64\n", reg_names[31], reg_names[31]);
2398 fprintf (file, "\tst.d\t %s,%s,32\n", reg_names[2], reg_names[31]);
2399 fprintf (file, "\tst.d\t %s,%s,40\n", reg_names[4], reg_names[31]);
2400 fprintf (file, "\tst.d\t %s,%s,48\n", reg_names[6], reg_names[31]);
2401 fprintf (file, "\tst.d\t %s,%s,56\n", reg_names[8], reg_names[31]);
2404 ASM_GENERATE_INTERNAL_LABEL (label, "LP", labelno);
2407 fprintf (file, "\tor.u\t %s,%s,%shi16(%s#got_rel)\n",
2408 temp, reg_names[0], m88k_pound_sign, &label[1]);
2409 fprintf (file, "\tor\t %s,%s,%slo16(%s#got_rel)\n",
2410 temp, temp, m88k_pound_sign, &label[1]);
2411 sprintf (dbi, "\tld\t %s,%s,%s\n", temp,
2412 reg_names[PIC_OFFSET_TABLE_REGNUM], temp);
2416 sprintf (dbi, "\tld\t %s,%s,%s#got_rel\n", temp,
2417 reg_names[PIC_OFFSET_TABLE_REGNUM], &label[1]);
2421 fprintf (file, "\tor.u\t %s,%s,%shi16(%s)\n",
2422 temp, reg_names[0], m88k_pound_sign, &label[1]);
2423 sprintf (dbi, "\tor\t %s,%s,%slo16(%s)\n",
2424 temp, temp, m88k_pound_sign, &label[1]);
2428 fprintf (file, "\tbsr.n\t %s#plt\n", name);
2430 fprintf (file, "\tbsr.n\t %s\n", name);
2435 fprintf (file, "\tld.d\t %s,%s,32\n", reg_names[2], reg_names[31]);
2436 fprintf (file, "\tld.d\t %s,%s,40\n", reg_names[4], reg_names[31]);
2437 fprintf (file, "\tld.d\t %s,%s,48\n", reg_names[6], reg_names[31]);
2438 fprintf (file, "\tld.d\t %s,%s,56\n", reg_names[8], reg_names[31]);
2439 fprintf (file, "\taddu\t %s,%s,64\n", reg_names[31], reg_names[31]);
2443 /* Output assembler code to FILE to initialize basic-block profiling for
2444 the current module. LABELNO is unique to each instance. */
2447 output_function_block_profiler (file, labelno)
2454 /* Remember to update FUNCTION_BLOCK_PROFILER_LENGTH. */
2456 ASM_GENERATE_INTERNAL_LABEL (block, "LPBX", 0);
2457 ASM_GENERATE_INTERNAL_LABEL (label, "LPY", labelno);
2459 /* @@ Need to deal with PIC. I'm not sure what the requirements are on
2460 register usage, so I used r26/r27 to be safe. */
2461 fprintf (file, "\tor.u\t %s,%s,%shi16(%s)\n", reg_names[27], reg_names[0],
2462 m88k_pound_sign, &block[1]);
2463 fprintf (file, "\tld\t %s,%s,%slo16(%s)\n", reg_names[26], reg_names[27],
2464 m88k_pound_sign, &block[1]);
2465 fprintf (file, "\tbcnd\t %sne0,%s,%s\n",
2466 m88k_pound_sign, reg_names[26], &label[1]);
2467 fprintf (file, "\tsubu\t %s,%s,64\n", reg_names[31], reg_names[31]);
2468 fprintf (file, "\tst.d\t %s,%s,32\n", reg_names[2], reg_names[31]);
2469 fprintf (file, "\tst.d\t %s,%s,40\n", reg_names[4], reg_names[31]);
2470 fprintf (file, "\tst.d\t %s,%s,48\n", reg_names[6], reg_names[31]);
2471 fprintf (file, "\tst.d\t %s,%s,56\n", reg_names[8], reg_names[31]);
2472 fputs ("\tbsr.n\t ", file);
2473 ASM_OUTPUT_LABELREF (file, "__bb_init_func");
2475 fprintf (file, "\tor\t %s,%s,%slo16(%s)\n", reg_names[2], reg_names[27],
2476 m88k_pound_sign, &block[1]);
2477 fprintf (file, "\tld.d\t %s,%s,32\n", reg_names[2], reg_names[31]);
2478 fprintf (file, "\tld.d\t %s,%s,40\n", reg_names[4], reg_names[31]);
2479 fprintf (file, "\tld.d\t %s,%s,48\n", reg_names[6], reg_names[31]);
2480 fprintf (file, "\tld.d\t %s,%s,56\n", reg_names[8], reg_names[31]);
2481 fprintf (file, "\taddu\t %s,%s,64\n", reg_names[31], reg_names[31]);
2482 ASM_OUTPUT_INTERNAL_LABEL (file, "LPY", labelno);
2485 /* Output assembler code to FILE to increment the count associated with
2486 the basic block number BLOCKNO. */
2489 output_block_profiler (file, blockno)
2495 /* Remember to update BLOCK_PROFILER_LENGTH. */
2497 ASM_GENERATE_INTERNAL_LABEL (block, "LPBX", 2);
2499 /* @@ Need to deal with PIC. I'm not sure what the requirements are on
2500 register usage, so I used r26/r27 to be safe. */
2501 fprintf (file, "\tor.u\t %s,%s,%shi16(%s+%d)\n", reg_names[27], reg_names[0],
2502 m88k_pound_sign, &block[1], 4 * blockno);
2503 fprintf (file, "\tld\t %s,%s,%slo16(%s+%d)\n", reg_names[26], reg_names[27],
2504 m88k_pound_sign, &block[1], 4 * blockno);
2505 fprintf (file, "\taddu\t %s,%s,1\n", reg_names[26], reg_names[26]);
2506 fprintf (file, "\tst\t %s,%s,%slo16(%s+%d)\n", reg_names[26], reg_names[27],
2507 m88k_pound_sign, &block[1], 4 * blockno);
2510 /* Determine whether a function argument is passed in a register, and
2513 The arguments are CUM, which summarizes all the previous
2514 arguments; MODE, the machine mode of the argument; TYPE,
2515 the data type of the argument as a tree node or 0 if that is not known
2516 (which happens for C support library functions); and NAMED,
2517 which is 1 for an ordinary argument and 0 for nameless arguments that
2518 correspond to `...' in the called function's prototype.
2520 The value of the expression should either be a `reg' RTX for the
2521 hard register in which to pass the argument, or zero to pass the
2522 argument on the stack.
2524 On the m88000 the first eight words of args are normally in registers
2525 and the rest are pushed. Double precision floating point must be
2526 double word aligned (and if in a register, starting on an even
2527 register). Structures and unions which are not 4 byte, and word
2528 aligned are passed in memory rather than registers, even if they
2529 would fit completely in the registers under OCS rules.
2531 Note that FUNCTION_ARG and FUNCTION_INCOMING_ARG were different.
2532 For structures that are passed in memory, but could have been
2533 passed in registers, we first load the structure into the
2534 register, and then when the last argument is passed, we store
2535 the registers into the stack locations. This fixes some bugs
2536 where GCC did not expect to have register arguments, followed
2537 by stack arguments, followed by register arguments. */
2540 m88k_function_arg (args_so_far, mode, type, named)
2541 CUMULATIVE_ARGS args_so_far;
2542 enum machine_mode mode;
2544 int named ATTRIBUTE_UNUSED;
2548 if (type != 0 /* undo putting struct in register */
2549 && (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE))
2552 if (mode == BLKmode && TARGET_WARN_PASS_STRUCT)
2553 warning ("argument #%d is a structure", args_so_far + 1);
2555 if ((args_so_far & 1) != 0
2556 && (mode == DImode || mode == DFmode
2557 || (type != 0 && TYPE_ALIGN (type) > 32)))
2562 return (rtx) 0; /* don't put args in registers */
2565 if (type == 0 && mode == BLKmode)
2566 abort (); /* m88k_function_arg argument `type' is NULL for BLKmode. */
2568 bytes = (mode != BLKmode) ? GET_MODE_SIZE (mode) : int_size_in_bytes (type);
2569 words = (bytes + 3) / 4;
2571 if (args_so_far + words > 8)
2572 return (rtx) 0; /* args have exhausted registers */
2574 else if (mode == BLKmode
2575 && (TYPE_ALIGN (type) != BITS_PER_WORD
2576 || bytes != UNITS_PER_WORD))
2579 return gen_rtx_REG (((mode == BLKmode) ? TYPE_MODE (type) : mode),
2583 /* Do what is necessary for `va_start'. We look at the current function
2584 to determine if stdargs or varargs is used and spill as necessary.
2585 We return a pointer to the spill area. */
2588 m88k_builtin_saveregs ()
2591 tree fntype = TREE_TYPE (current_function_decl);
2592 int argadj = ((!(TYPE_ARG_TYPES (fntype) != 0
2593 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
2594 != void_type_node)))
2595 ? -UNITS_PER_WORD : 0) + UNITS_PER_WORD - 1;
2598 variable_args_p = 1;
2601 if (CONSTANT_P (current_function_arg_offset_rtx))
2603 fixed = (XINT (current_function_arg_offset_rtx, 0)
2604 + argadj) / UNITS_PER_WORD;
2607 /* Allocate the register space, and store it as the __va_reg member. */
2608 addr = assign_stack_local (BLKmode, 8 * UNITS_PER_WORD, -1);
2609 MEM_ALIAS_SET (addr) = get_varargs_alias_set ();
2610 RTX_UNCHANGING_P (addr) = 1;
2611 RTX_UNCHANGING_P (XEXP (addr, 0)) = 1;
2613 /* Now store the incoming registers. */
2616 dest = change_address (addr, Pmode,
2617 plus_constant (XEXP (addr, 0),
2618 fixed * UNITS_PER_WORD));
2619 move_block_from_reg (2 + fixed, dest, 8 - fixed,
2620 UNITS_PER_WORD * (8 - fixed));
2622 if (current_function_check_memory_usage)
2624 emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
2626 GEN_INT (UNITS_PER_WORD * (8 - fixed)),
2627 TYPE_MODE (sizetype),
2628 GEN_INT (MEMORY_USE_RW),
2629 TYPE_MODE (integer_type_node));
2633 /* Return the address of the save area, but don't put it in a
2634 register. This fails when not optimizing and produces worse code
2636 return XEXP (addr, 0);
2639 /* Define the `__builtin_va_list' type for the ABI. */
2642 m88k_build_va_list ()
2644 tree field_reg, field_stk, field_arg, int_ptr_type_node, record;
2646 int_ptr_type_node = build_pointer_type (integer_type_node);
2648 record = make_node (RECORD_TYPE);
2650 field_arg = build_decl (FIELD_DECL, get_identifier ("__va_arg"),
2652 field_stk = build_decl (FIELD_DECL, get_identifier ("__va_stk"),
2654 field_reg = build_decl (FIELD_DECL, get_identifier ("__va_reg"),
2657 DECL_FIELD_CONTEXT (field_arg) = record;
2658 DECL_FIELD_CONTEXT (field_stk) = record;
2659 DECL_FIELD_CONTEXT (field_reg) = record;
2661 TYPE_FIELDS (record) = field_arg;
2662 TREE_CHAIN (field_arg) = field_stk;
2663 TREE_CHAIN (field_stk) = field_reg;
2665 layout_type (record);
2669 /* Implement `va_start' for varargs and stdarg. */
2672 m88k_va_start (stdarg_p, valist, nextarg)
2673 int stdarg_p ATTRIBUTE_UNUSED;
2675 rtx nextarg ATTRIBUTE_UNUSED;
2677 tree field_reg, field_stk, field_arg;
2678 tree reg, stk, arg, t;
2680 field_arg = TYPE_FIELDS (va_list_type_node);
2681 field_stk = TREE_CHAIN (field_arg);
2682 field_reg = TREE_CHAIN (field_stk);
2684 arg = build (COMPONENT_REF, TREE_TYPE (field_arg), valist, field_arg);
2685 stk = build (COMPONENT_REF, TREE_TYPE (field_stk), valist, field_stk);
2686 reg = build (COMPONENT_REF, TREE_TYPE (field_reg), valist, field_reg);
2688 /* Fill in the ARG member. */
2690 tree fntype = TREE_TYPE (current_function_decl);
2691 int argadj = ((!(TYPE_ARG_TYPES (fntype) != 0
2692 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
2693 != void_type_node)))
2694 ? -UNITS_PER_WORD : 0) + UNITS_PER_WORD - 1;
2697 if (CONSTANT_P (current_function_arg_offset_rtx))
2699 int fixed = (INTVAL (current_function_arg_offset_rtx)
2700 + argadj) / UNITS_PER_WORD;
2702 argsize = build_int_2 (fixed, 0);
2706 argsize = make_tree (integer_type_node,
2707 current_function_arg_offset_rtx);
2708 argsize = fold (build (PLUS_EXPR, integer_type_node, argsize,
2709 build_int_2 (argadj, 0)));
2710 argsize = fold (build (RSHIFT_EXPR, integer_type_node, argsize,
2711 build_int_2 (2, 0)));
2714 t = build (MODIFY_EXPR, TREE_TYPE (arg), arg, argsize);
2715 TREE_SIDE_EFFECTS (t) = 1;
2716 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
2719 /* Store the arg pointer in the __va_stk member. */
2720 t = make_tree (TREE_TYPE (stk), virtual_incoming_args_rtx);
2721 t = build (MODIFY_EXPR, TREE_TYPE (stk), stk, t);
2722 TREE_SIDE_EFFECTS (t) = 1;
2723 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
2725 /* Tuck the return value from __builtin_saveregs into __va_reg. */
2726 t = make_tree (TREE_TYPE (reg), expand_builtin_saveregs ());
2727 t = build (MODIFY_EXPR, TREE_TYPE (reg), reg, t);
2728 TREE_SIDE_EFFECTS (t) = 1;
2729 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
2732 /* Implement `va_arg'. */
2735 m88k_va_arg (valist, type)
2738 tree field_reg, field_stk, field_arg;
2739 tree reg, stk, arg, arg_align, base, t;
2740 int size, wsize, align, reg_p;
2743 field_arg = TYPE_FIELDS (va_list_type_node);
2744 field_stk = TREE_CHAIN (field_arg);
2745 field_reg = TREE_CHAIN (field_stk);
2747 arg = build (COMPONENT_REF, TREE_TYPE (field_arg), valist, field_arg);
2748 stk = build (COMPONENT_REF, TREE_TYPE (field_stk), valist, field_stk);
2749 reg = build (COMPONENT_REF, TREE_TYPE (field_reg), valist, field_reg);
2751 size = int_size_in_bytes (type);
2752 wsize = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
2753 align = 1 << ((TYPE_ALIGN (type) / BITS_PER_UNIT) >> 3);
2754 reg_p = (AGGREGATE_TYPE_P (type)
2755 ? size == UNITS_PER_WORD && TYPE_ALIGN (type) == BITS_PER_WORD
2756 : size <= 2*UNITS_PER_WORD);
2758 /* Align __va_arg to the (doubleword?) boundary above. */
2759 t = build (PLUS_EXPR, TREE_TYPE (arg), arg, build_int_2 (align - 1, 0));
2760 arg_align = build (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-align, -1));
2761 arg_align = save_expr (arg_align);
2763 /* Decide if we should read from stack or regs. */
2764 t = build (LT_EXPR, integer_type_node, arg_align, build_int_2 (8, 0));
2765 base = build (COND_EXPR, TREE_TYPE (reg), t, reg, stk);
2767 /* Find the final address. */
2768 t = build (PLUS_EXPR, TREE_TYPE (base), base, arg_align);
2769 addr_rtx = expand_expr (t, NULL_RTX, Pmode, EXPAND_NORMAL);
2770 addr_rtx = copy_to_reg (addr_rtx);
2772 /* Increment __va_arg. */
2773 t = build (PLUS_EXPR, TREE_TYPE (arg), arg_align, build_int_2 (wsize, 0));
2774 t = build (MODIFY_EXPR, TREE_TYPE (arg), arg, t);
2775 TREE_SIDE_EFFECTS (t) = 1;
2776 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
2781 /* If cmpsi has not been generated, emit code to do the test. Return the
2782 expression describing the test of operator OP. */
2785 emit_test (op, mode)
2787 enum machine_mode mode;
2789 if (m88k_compare_reg == 0)
2790 emit_insn (gen_test (m88k_compare_op0, m88k_compare_op1));
2791 return (gen_rtx (op, mode, m88k_compare_reg, const0_rtx));
2794 /* Determine how to best perform cmpsi/bxx, where cmpsi has a constant
2795 operand. All tests with zero (albeit swapped) and all equality tests
2796 with a constant are done with bcnd. The remaining cases are swapped
2800 emit_bcnd (op, label)
2804 if (m88k_compare_op1 == const0_rtx)
2805 emit_jump_insn (gen_bcnd
2806 (gen_rtx (op, VOIDmode,m88k_compare_op0, const0_rtx),
2808 else if (m88k_compare_op0 == const0_rtx)
2809 emit_jump_insn (gen_bcnd
2810 (gen_rtx (swap_condition (op),
2811 VOIDmode, m88k_compare_op1, const0_rtx),
2813 else if (op != EQ && op != NE)
2814 emit_jump_insn (gen_bxx (emit_test (op, VOIDmode), label));
2817 rtx zero = gen_reg_rtx (SImode);
2821 if (GET_CODE (m88k_compare_op1) == CONST_INT)
2823 reg = force_reg (SImode, m88k_compare_op0);
2824 constant = m88k_compare_op1;
2828 reg = force_reg (SImode, m88k_compare_op1);
2829 constant = m88k_compare_op0;
2831 value = INTVAL (constant);
2833 /* Perform an arithmetic computation to make the compared-to value
2834 zero, but avoid loosing if the bcnd is later changed into sxx. */
2835 if (SMALL_INTVAL (value))
2836 emit_jump_insn (gen_bxx (emit_test (op, VOIDmode), label));
2839 if (SMALL_INTVAL (-value))
2840 emit_insn (gen_addsi3 (zero, reg,
2843 emit_insn (gen_xorsi3 (zero, reg, constant));
2845 emit_jump_insn (gen_bcnd (gen_rtx (op, VOIDmode,
2852 /* Print an operand. Recognize special options, documented below. */
2855 print_operand (file, x, code)
2860 enum rtx_code xc = (x ? GET_CODE (x) : UNKNOWN);
2861 register int value = (xc == CONST_INT ? INTVAL (x) : 0);
2862 static int sequencep;
2863 static int reversep;
2867 if (code < 'B' || code > 'E')
2868 output_operand_lossage ("%R not followed by %B/C/D/E");
2870 xc = reverse_condition (xc);
2876 case '*': /* addressing base register for PIC */
2877 fputs (reg_names[PIC_OFFSET_TABLE_REGNUM], file); return;
2879 case '#': /* SVR4 pound-sign syntax character (empty if SVR3) */
2880 fputs (m88k_pound_sign, file); return;
2882 case 'V': /* Output a serializing instruction as needed if the operand
2883 (assumed to be a MEM) is a volatile load. */
2884 case 'v': /* ditto for a volatile store. */
2885 if (MEM_VOLATILE_P (x) && TARGET_SERIALIZE_VOLATILE)
2887 /* The m88110 implements two FIFO queues, one for loads and
2888 one for stores. These queues mean that loads complete in
2889 their issue order as do stores. An interaction between the
2890 history buffer and the store reservation station ensures
2891 that a store will not bypass load. Finally, a load will not
2892 bypass store, but only when they reference the same address.
2894 To avoid this reordering (a load bypassing a store) for
2895 volatile references, a serializing instruction is output.
2896 We choose the fldcr instruction as it does not serialize on
2897 the m88100 so that -m88000 code will not be degraded.
2899 The mechanism below is completed by having CC_STATUS_INIT set
2900 the code to the unknown value. */
2904 A problem with 88110 4.1 & 4.2 makes the use of fldcr for
2905 this purpose undesirable. Instead we will use tb1, this will
2906 cause serialization on the 88100 but such is life.
2909 static rtx last_addr = 0;
2910 if (code == 'V' /* Only need to serialize before a load. */
2911 && m88k_volatile_code != 'V' /* Loads complete in FIFO order. */
2912 && !(m88k_volatile_code == 'v'
2913 && GET_CODE (XEXP (x, 0)) == LO_SUM
2914 && rtx_equal_p (XEXP (XEXP (x, 0), 1), last_addr)))
2918 "fldcr\t %s,%scr63\n\t",
2920 "fldcr\t %s,%sfcr63\n\t",
2922 reg_names[0], m88k_pound_sign);
2924 "tb1\t 1,%s,0xff\n\t", reg_names[0]);
2926 m88k_volatile_code = code;
2927 last_addr = (GET_CODE (XEXP (x, 0)) == LO_SUM
2928 ? XEXP (XEXP (x, 0), 1) : 0);
2932 case 'X': /* print the upper 16 bits... */
2934 case 'x': /* print the lower 16 bits of the integer constant in hex */
2935 if (xc != CONST_INT)
2936 output_operand_lossage ("invalid %x/X value");
2937 fprintf (file, "0x%x", value & 0xffff); return;
2939 case 'H': /* print the low 16 bits of the negated integer constant */
2940 if (xc != CONST_INT)
2941 output_operand_lossage ("invalid %H value");
2943 case 'h': /* print the register or low 16 bits of the integer constant */
2946 if (xc != CONST_INT)
2947 output_operand_lossage ("invalid %h value");
2948 fprintf (file, "%d", value & 0xffff);
2951 case 'Q': /* print the low 8 bits of the negated integer constant */
2952 if (xc != CONST_INT)
2953 output_operand_lossage ("invalid %Q value");
2955 case 'q': /* print the register or low 8 bits of the integer constant */
2958 if (xc != CONST_INT)
2959 output_operand_lossage ("invalid %q value");
2960 fprintf (file, "%d", value & 0xff);
2963 case 'w': /* print the integer constant (X == 32 ? 0 : 32 - X) */
2964 if (xc != CONST_INT)
2965 output_operand_lossage ("invalid %o value");
2966 fprintf (file, "%d", value == 32 ? 0 : 32 - value);
2969 case 'p': /* print the logarithm of the integer constant */
2971 || (value = exact_log2 (value)) < 0)
2972 output_operand_lossage ("invalid %p value");
2973 fprintf (file, "%d", value);
2976 case 'S': /* compliment the value and then... */
2978 case 's': /* print the width and offset values forming the integer
2979 constant with a SET instruction. See integer_ok_for_set. */
2981 register unsigned mask, uval = value;
2982 register int top, bottom;
2984 if (xc != CONST_INT)
2985 output_operand_lossage ("invalid %s/S value");
2986 /* All the "one" bits must be contiguous. If so, MASK will be
2987 a power of two or zero. */
2988 mask = (uval | (uval - 1)) + 1;
2989 if (!(uval && POWER_OF_2_or_0 (mask)))
2990 output_operand_lossage ("invalid %s/S value");
2991 top = mask ? exact_log2 (mask) : 32;
2992 bottom = exact_log2 (uval & ~(uval - 1));
2993 fprintf (file,"%d<%d>", top - bottom, bottom);
2997 case 'P': /* print nothing if pc_rtx; output label_ref */
2998 if (xc == LABEL_REF)
2999 output_addr_const (file, x);
3001 output_operand_lossage ("invalid %P operand");
3004 case 'L': /* print 0 or 1 if operand is label_ref and then... */
3005 fputc (xc == LABEL_REF ? '1' : '0', file);
3006 case '.': /* print .n if delay slot is used */
3007 fputs ((final_sequence
3008 && ! INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0)))
3009 ? ".n\t" : "\t", file);
3012 case '!': /* Reverse the following condition. */
3016 case 'R': /* reverse the condition of the next print_operand
3017 if operand is a label_ref. */
3019 reversep = (xc == LABEL_REF);
3022 case 'B': /* bcnd branch values */
3023 fputs (m88k_pound_sign, file);
3026 case EQ: fputs ("eq0", file); return;
3027 case NE: fputs ("ne0", file); return;
3028 case GT: fputs ("gt0", file); return;
3029 case LE: fputs ("le0", file); return;
3030 case LT: fputs ("lt0", file); return;
3031 case GE: fputs ("ge0", file); return;
3032 default: output_operand_lossage ("invalid %B value");
3035 case 'C': /* bb0/bb1 branch values for comparisons */
3036 fputs (m88k_pound_sign, file);
3039 case EQ: fputs ("eq", file); return;
3040 case NE: fputs ("ne", file); return;
3041 case GT: fputs ("gt", file); return;
3042 case LE: fputs ("le", file); return;
3043 case LT: fputs ("lt", file); return;
3044 case GE: fputs ("ge", file); return;
3045 case GTU: fputs ("hi", file); return;
3046 case LEU: fputs ("ls", file); return;
3047 case LTU: fputs ("lo", file); return;
3048 case GEU: fputs ("hs", file); return;
3049 default: output_operand_lossage ("invalid %C value");
3052 case 'D': /* bcnd branch values for float comparisons */
3055 case EQ: fputs ("0xa", file); return;
3056 case NE: fputs ("0x5", file); return;
3057 case GT: fputs (m88k_pound_sign, file);
3058 fputs ("gt0", file); return;
3059 case LE: fputs ("0xe", file); return;
3060 case LT: fputs ("0x4", file); return;
3061 case GE: fputs ("0xb", file); return;
3062 default: output_operand_lossage ("invalid %D value");
3065 case 'E': /* bcnd branch values for special integers */
3068 case EQ: fputs ("0x8", file); return;
3069 case NE: fputs ("0x7", file); return;
3070 default: output_operand_lossage ("invalid %E value");
3073 case 'd': /* second register of a two register pair */
3075 output_operand_lossage ("`%d' operand isn't a register");
3076 fputs (reg_names[REGNO (x) + 1], file);
3079 case 'r': /* an immediate 0 should be represented as `r0' */
3080 if (x == const0_rtx)
3082 fputs (reg_names[0], file);
3086 output_operand_lossage ("invalid %r value");
3092 if (REGNO (x) == ARG_POINTER_REGNUM)
3093 output_operand_lossage ("operand is r0");
3095 fputs (reg_names[REGNO (x)], file);
3097 else if (xc == PLUS)
3100 output_address (XEXP (x, 0));
3101 else if (flag_pic && xc == UNSPEC)
3103 output_addr_const (file, XVECEXP (x, 0, 0));
3104 fputs ("#got_rel", file);
3106 else if (xc == CONST_DOUBLE)
3107 output_operand_lossage ("operand is const_double");
3109 output_addr_const (file, x);
3112 case 'g': /* append #got_rel as needed */
3113 if (flag_pic && (xc == SYMBOL_REF || xc == LABEL_REF))
3115 output_addr_const (file, x);
3116 fputs ("#got_rel", file);
3121 case 'a': /* (standard), assume operand is an address */
3122 case 'c': /* (standard), assume operand is an immediate value */
3123 case 'l': /* (standard), assume operand is a label_ref */
3124 case 'n': /* (standard), like %c, except negate first */
3126 output_operand_lossage ("invalid code");
3131 print_operand_address (file, addr)
3135 register rtx reg0, reg1, temp;
3137 switch (GET_CODE (addr))
3140 if (REGNO (addr) == ARG_POINTER_REGNUM)
3143 fprintf (file, "%s,%s", reg_names[0], reg_names [REGNO (addr)]);
3147 fprintf (file, "%s,%slo16(",
3148 reg_names[REGNO (XEXP (addr, 0))], m88k_pound_sign);
3149 output_addr_const (file, XEXP (addr, 1));
3154 reg0 = XEXP (addr, 0);
3155 reg1 = XEXP (addr, 1);
3156 if (GET_CODE (reg0) == MULT || GET_CODE (reg0) == CONST_INT)
3163 if ((REG_P (reg0) && REGNO (reg0) == ARG_POINTER_REGNUM)
3164 || (REG_P (reg1) && REGNO (reg1) == ARG_POINTER_REGNUM))
3167 else if (REG_P (reg0))
3170 fprintf (file, "%s,%s",
3171 reg_names [REGNO (reg0)], reg_names [REGNO (reg1)]);
3173 else if (GET_CODE (reg1) == CONST_INT)
3174 fprintf (file, "%s,%d",
3175 reg_names [REGNO (reg0)], INTVAL (reg1));
3177 else if (GET_CODE (reg1) == MULT)
3179 rtx mreg = XEXP (reg1, 0);
3180 if (REGNO (mreg) == ARG_POINTER_REGNUM)
3183 fprintf (file, "%s[%s]", reg_names[REGNO (reg0)],
3184 reg_names[REGNO (mreg)]);
3187 else if (GET_CODE (reg1) == ZERO_EXTRACT)
3189 fprintf (file, "%s,%slo16(",
3190 reg_names[REGNO (reg0)], m88k_pound_sign);
3191 output_addr_const (file, XEXP (reg1, 0));
3197 fprintf (file, "%s,", reg_names[REGNO (reg0)]);
3198 output_addr_const (file, reg1);
3199 fputs ("#got_rel", file);
3209 if (REGNO (XEXP (addr, 0)) == ARG_POINTER_REGNUM)
3212 fprintf (file, "%s[%s]",
3213 reg_names[0], reg_names[REGNO (XEXP (addr, 0))]);
3217 fprintf (file, "%s,%d", reg_names[0], INTVAL (addr));
3221 fprintf (file, "%s,", reg_names[0]);
3222 if (SHORT_ADDRESS_P (addr, temp))
3224 fprintf (file, "%siw16(", m88k_pound_sign);
3225 output_addr_const (file, addr);
3229 output_addr_const (file, addr);
3233 /* Return true if X is an address which needs a temporary register when
3234 reloaded while generating PIC code. */
3237 pic_address_needs_scratch (x)
3240 /* An address which is a symbolic plus a non SMALL_INT needs a temp reg. */
3241 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
3242 && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
3243 && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
3244 && ! ADD_INT (XEXP (XEXP (x, 0), 1)))
3250 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
3251 reference and a constant. */
3254 symbolic_operand (op, mode)
3256 enum machine_mode mode;
3258 switch (GET_CODE (op))
3266 return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
3267 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
3268 && GET_CODE (XEXP (op, 1)) == CONST_INT);
3270 /* ??? This clause seems to be irrelevant. */
3272 return GET_MODE (op) == mode;