1 /* Subroutines for assembler code output on the NS32000.
2 Copyright (C) 1988, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
3 Free Software Foundation, Inc.
5 This file is part of GNU CC.
7 GNU CC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GNU CC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU CC; see the file COPYING. If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
26 #include "hard-reg-set.h"
28 #include "insn-config.h"
29 #include "conditions.h"
31 #include "insn-attr.h"
39 #include "target-def.h"
43 int ns32k_num_files = 0;
46 /* This duplicates reg_class_contents in reg_class.c, but maybe that isn't
47 initialized in time. Also this is more convenient as an array of ints.
48 We know that HARD_REG_SET fits in an unsigned int */
50 unsigned int ns32k_reg_class_contents[N_REG_CLASSES][1] = REG_CLASS_CONTENTS;
52 enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
54 GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
55 GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
56 FLOAT_REG0, LONG_FLOAT_REG0, FLOAT_REGS, FLOAT_REGS,
57 FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS,
58 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
59 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
60 FRAME_POINTER_REG, STACK_POINTER_REG
63 static const char *const ns32k_out_reg_names[] = OUTPUT_REGISTER_NAMES;
65 static rtx gen_indexed_expr PARAMS ((rtx, rtx, rtx));
66 static const char *singlemove_string PARAMS ((rtx *));
67 static void move_tail PARAMS ((rtx[], int, int));
68 static tree ns32k_handle_fntype_attribute PARAMS ((tree *, tree, tree, int, bool *));
69 const struct attribute_spec ns32k_attribute_table[];
70 static void ns32k_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
71 static void ns32k_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
73 /* Initialize the GCC target structure. */
74 #undef TARGET_ATTRIBUTE_TABLE
75 #define TARGET_ATTRIBUTE_TABLE ns32k_attribute_table
77 #undef TARGET_ASM_ALIGNED_HI_OP
78 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
81 #undef TARGET_ASM_ALIGNED_SI_OP
82 #define TARGET_ASM_ALIGNED_SI_OP "\t.double\t"
85 #undef TARGET_ASM_FUNCTION_PROLOGUE
86 #define TARGET_ASM_FUNCTION_PROLOGUE ns32k_output_function_prologue
87 #undef TARGET_ASM_FUNCTION_EPILOGUE
88 #define TARGET_ASM_FUNCTION_EPILOGUE ns32k_output_function_epilogue
90 struct gcc_target targetm = TARGET_INITIALIZER;
92 /* Generate the assembly code for function entry. FILE is a stdio
93 stream to output the code to. SIZE is an int: how many units of
94 temporary storage to allocate.
96 Refer to the array `regs_ever_live' to determine which registers to
97 save; `regs_ever_live[I]' is nonzero if register number I is ever
98 used in the function. This function is responsible for knowing
99 which registers should not be saved even if used. */
102 * The function prologue for the ns32k is fairly simple.
103 * If a frame pointer is needed (decided in reload.c ?) then
104 * we need assembler of the form
106 * # Save the oldframe pointer, set the new frame pointer, make space
107 * # on the stack and save any general purpose registers necessary
109 * enter [<general purpose regs to save>], <local stack space>
111 * movf fn, tos # Save any floating point registers necessary
115 * If a frame pointer is not needed we need assembler of the form
117 * # Make space on the stack
119 * adjspd <local stack space + 4>
121 * # Save any general purpose registers necessary
123 * save [<general purpose regs to save>]
125 * movf fn, tos # Save any floating point registers necessary
130 #if !defined (MERLIN_TARGET) && !defined (UTEK_ASM)
132 #if defined(IMMEDIATE_PREFIX) && IMMEDIATE_PREFIX
133 #define ADJSP(FILE, N) \
134 fprintf (FILE, "\tadjspd %c%d\n", IMMEDIATE_PREFIX, (N))
136 #define ADJSP(FILE, N) \
137 fprintf (FILE, "\tadjspd %d\n", (N))
141 ns32k_output_function_prologue (file, size)
145 register int regno, g_regs_used = 0;
146 int used_regs_buf[8], *bufp = used_regs_buf;
147 int used_fregs_buf[17], *fbufp = used_fregs_buf;
149 for (regno = R0_REGNUM; regno < F0_REGNUM; regno++)
150 if (regs_ever_live[regno]
151 && ! call_used_regs[regno])
153 *bufp++ = regno; g_regs_used++;
157 for (; regno < FRAME_POINTER_REGNUM; regno++)
158 if (regs_ever_live[regno] && !call_used_regs[regno])
164 bufp = used_regs_buf;
165 if (frame_pointer_needed)
166 fprintf (file, "\tenter [");
170 ADJSP (file, size + 4);
171 if (g_regs_used && g_regs_used > 4)
172 fprintf (file, "\tsave [");
176 fprintf (file, "\tmovd r%d,tos\n", *bufp++);
183 fprintf (file, "r%d", *bufp++);
188 if (frame_pointer_needed)
189 fprintf (file, "],%d\n", size);
190 else if (g_regs_used)
191 fprintf (file, "]\n");
193 fbufp = used_fregs_buf;
196 if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1))
197 fprintf (file, "\tmovf %s,tos\n", ns32k_out_reg_names[*fbufp++]);
200 fprintf (file, "\tmovl %s,tos\n",
201 ns32k_out_reg_names[fbufp[0]]);
206 if (flag_pic && current_function_uses_pic_offset_table)
208 fprintf (file, "\tsprd sb,tos\n");
211 fprintf (file, "\taddr __GLOBAL_OFFSET_TABLE_(pc),tos\n");
212 fprintf (file, "\tlprd sb,tos\n");
216 fprintf (file, "\taddr __GLOBAL_OFFSET_TABLE_(pc),r0\n");
217 fprintf (file, "\tlprd sb,r0\n");
222 #else /* MERLIN_TARGET || UTEK_ASM */
224 /* This differs from the standard one above in printing a bitmask
225 rather than a register list in the enter or save instruction. */
228 ns32k_output_function_prologue (file, size)
232 register int regno, g_regs_used = 0;
233 int used_regs_buf[8], *bufp = used_regs_buf;
234 int used_fregs_buf[8], *fbufp = used_fregs_buf;
236 for (regno = 0; regno < 8; regno++)
237 if (regs_ever_live[regno]
238 && ! call_used_regs[regno])
240 *bufp++ = regno; g_regs_used++;
244 for (; regno < 16; regno++)
245 if (regs_ever_live[regno] && !call_used_regs[regno]) {
250 bufp = used_regs_buf;
251 if (frame_pointer_needed)
252 fprintf (file, "\tenter ");
253 else if (g_regs_used)
254 fprintf (file, "\tsave ");
256 if (frame_pointer_needed || g_regs_used)
260 mask |= 1 << *bufp++;
261 fprintf (file, "$0x%x", (int) mask & 0xff);
264 if (frame_pointer_needed)
266 fprintf (file, ",$%d\n", size);
268 fprintf (file, ",%d\n", size);
270 else if (g_regs_used)
271 fprintf (file, "\n");
273 fbufp = used_fregs_buf;
276 if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1))
277 fprintf (file, "\tmovf f%d,tos\n", *fbufp++ - 8);
280 fprintf (file, "\tmovl f%d,tos\n", fbufp[0] - 8);
286 #endif /* MERLIN_TARGET || UTEK_ASM */
288 /* This function generates the assembly code for function exit,
289 on machines that need it.
291 The function epilogue should not depend on the current stack pointer,
292 if EXIT_IGNORE_STACK is nonzero. That doesn't apply here.
294 If a frame pointer is needed (decided in reload.c ?) then
295 we need assembler of the form
297 movf tos, fn # Restore any saved floating point registers
301 # Restore any saved general purpose registers, restore the stack
302 # pointer from the frame pointer, restore the old frame pointer.
303 exit [<general purpose regs to save>]
305 If a frame pointer is not needed we need assembler of the form
306 # Restore any general purpose registers saved
308 movf tos, fn # Restore any saved floating point registers
312 restore [<general purpose regs to save>]
314 # reclaim space allocated on stack
316 adjspd <-(local stack space + 4)> */
318 #if !defined (MERLIN_TARGET) && !defined (UTEK_ASM)
321 ns32k_output_function_epilogue (file, size)
325 register int regno, g_regs_used = 0, f_regs_used = 0;
326 int used_regs_buf[8], *bufp = used_regs_buf;
327 int used_fregs_buf[17], *fbufp = used_fregs_buf;
329 if (flag_pic && current_function_uses_pic_offset_table)
330 fprintf (file, "\tlprd sb,tos\n");
333 for (regno = F0_REGNUM; regno < FRAME_POINTER_REGNUM; regno++)
334 if (regs_ever_live[regno] && !call_used_regs[regno])
336 *fbufp++ = regno; f_regs_used++;
340 for (regno = 0; regno < F0_REGNUM; regno++)
341 if (regs_ever_live[regno]
342 && ! call_used_regs[regno])
344 *bufp++ = regno; g_regs_used++;
347 while (fbufp > used_fregs_buf)
349 if ((*fbufp & 1) && fbufp[0] == fbufp[-1] + 1)
351 fprintf (file, "\tmovl tos,%s\n",
352 ns32k_out_reg_names[fbufp[-1]]);
355 else fprintf (file, "\tmovf tos,%s\n", ns32k_out_reg_names[*fbufp--]);
358 if (frame_pointer_needed)
359 fprintf (file, "\texit [");
362 if (g_regs_used && g_regs_used > 4)
363 fprintf (file, "\trestore [");
366 while (bufp > used_regs_buf)
367 fprintf (file, "\tmovd tos,r%d\n", *--bufp);
372 while (bufp > used_regs_buf)
374 fprintf (file, "r%d", *--bufp);
375 if (bufp > used_regs_buf)
379 if (g_regs_used || frame_pointer_needed)
380 fprintf (file, "]\n");
382 if (size && !frame_pointer_needed)
383 ADJSP (file, -(size + 4));
385 if (current_function_pops_args)
386 fprintf (file, "\tret %d\n", current_function_pops_args);
388 fprintf (file, "\tret 0\n");
391 #else /* MERLIN_TARGET || UTEK_ASM */
393 /* This differs from the standard one above in printing a bitmask
394 rather than a register list in the exit or restore instruction. */
397 ns32k_output_function_epilogue (file, size)
399 HOST_WIDE_INT size ATTRIBUTE_UNUSED;
401 register int regno, g_regs_used = 0, f_regs_used = 0;
402 int used_regs_buf[8], *bufp = used_regs_buf;
403 int used_fregs_buf[8], *fbufp = used_fregs_buf;
406 for (regno = 8; regno < 16; regno++)
407 if (regs_ever_live[regno] && !call_used_regs[regno]) {
408 *fbufp++ = regno; f_regs_used++;
412 for (regno = 0; regno < 8; regno++)
413 if (regs_ever_live[regno]
414 && ! call_used_regs[regno])
416 *bufp++ = regno; g_regs_used++;
419 while (fbufp > used_fregs_buf)
421 if ((*fbufp & 1) && fbufp[0] == fbufp[-1] + 1)
423 fprintf (file, "\tmovl tos,f%d\n", fbufp[-1] - 8);
426 else fprintf (file, "\tmovf tos,f%d\n", *fbufp-- - 8);
429 if (frame_pointer_needed)
430 fprintf (file, "\texit ");
431 else if (g_regs_used)
432 fprintf (file, "\trestore ");
434 if (g_regs_used || frame_pointer_needed)
438 while (bufp > used_regs_buf)
440 /* Utek assembler takes care of reversing this */
441 mask |= 1 << *--bufp;
443 fprintf (file, "$0x%x\n", (int) mask & 0xff);
447 if (current_function_pops_args)
448 fprintf (file, "\tret $%d\n", current_function_pops_args);
450 fprintf (file, "\tret $0\n");
452 if (current_function_pops_args)
453 fprintf (file, "\tret %d\n", current_function_pops_args);
455 fprintf (file, "\tret 0\n");
459 #endif /* MERLIN_TARGET || UTEK_ASM */
461 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */
463 hard_regno_mode_ok (regno, mode)
465 enum machine_mode mode;
467 int size = GET_MODE_UNIT_SIZE (mode);
469 if (FLOAT_MODE_P (mode))
471 if (size == UNITS_PER_WORD && regno < L1_REGNUM)
473 if (size == UNITS_PER_WORD * 2
474 && (((regno & 1) == 0 && regno < FRAME_POINTER_REGNUM)))
478 if (size == UNITS_PER_WORD * 2
479 && (regno & 1) == 0 && regno < F0_REGNUM)
481 if (size <= UNITS_PER_WORD
482 && (regno < F0_REGNUM || regno == FRAME_POINTER_REGNUM
483 || regno == STACK_POINTER_REGNUM))
488 int register_move_cost (CLASS1, CLASS2)
489 enum reg_class CLASS1;
490 enum reg_class CLASS2;
492 if (CLASS1 == NO_REGS || CLASS2 == NO_REGS)
494 if ((SUBSET_P (CLASS1, FP_REGS) && !SUBSET_P (CLASS2, FP_REGS))
495 || (!SUBSET_P (CLASS1, FP_REGS) && SUBSET_P (CLASS2, FP_REGS)))
497 if (((CLASS1) == STACK_POINTER_REG && !SUBSET_P (CLASS2,GENERAL_REGS))
498 || ((CLASS2) == STACK_POINTER_REG && !SUBSET_P (CLASS1,GENERAL_REGS)))
500 if (((CLASS1) == FRAME_POINTER_REG && !SUBSET_P (CLASS2,GENERAL_REGS))
501 || ((CLASS2) == FRAME_POINTER_REG && !SUBSET_P (CLASS1,GENERAL_REGS)))
507 /* We made the insn definitions copy from floating point to general
508 registers via the stack. */
509 int secondary_memory_needed (CLASS1, CLASS2, M)
510 enum reg_class CLASS1;
511 enum reg_class CLASS2;
514 int ret = ((SUBSET_P (CLASS1, FP_REGS) && !SUBSET_P (CLASS2, FP_REGS))
515 || (!SUBSET_P (CLASS1, FP_REGS) && SUBSET_P (CLASS2, FP_REGS)));
521 /* ADDRESS_COST calls this. This function is not optimal
522 for the 32032 & 32332, but it probably is better than
526 calc_address_cost (operand)
531 if (GET_CODE (operand) == MEM)
533 if (GET_CODE (operand) == MULT)
535 switch (GET_CODE (operand))
544 if (INTVAL (operand) <= 7 && INTVAL (operand) >= -8)
546 if (INTVAL (operand) < 0x2000 && INTVAL (operand) >= -0x2000)
560 cost += calc_address_cost (XEXP (operand, 0));
564 for (i = 0; i < GET_RTX_LENGTH (GET_CODE (operand)); i++)
566 cost += calc_address_cost (XEXP (operand, i));
574 /* Return the register class of a scratch register needed to copy IN into
575 or out of a register in CLASS in MODE. If it can be done directly,
576 NO_REGS is returned. */
579 secondary_reload_class (class, mode, in)
580 enum reg_class class;
581 enum machine_mode mode ATTRIBUTE_UNUSED;
584 int regno = true_regnum (in);
586 if (regno >= FIRST_PSEUDO_REGISTER)
589 if ((class == FRAME_POINTER_REG && regno == STACK_POINTER_REGNUM)
590 || ( class == STACK_POINTER_REG && regno == FRAME_POINTER_REGNUM))
596 /* Generate the rtx that comes from an address expression in the md file */
597 /* The expression to be build is BASE[INDEX:SCALE]. To recognize this,
598 scale must be converted from an exponent (from ASHIFT) to a
599 multiplier (for MULT). */
602 gen_indexed_expr (base, index, scale)
603 rtx base, index, scale;
607 /* This generates an invalid addressing mode, if BASE is
608 fp or sp. This is handled by PRINT_OPERAND_ADDRESS. */
609 if (GET_CODE (base) != REG && GET_CODE (base) != CONST_INT)
610 base = gen_rtx_MEM (SImode, base);
611 addr = gen_rtx_MULT (SImode, index,
612 GEN_INT (1 << INTVAL (scale)));
613 addr = gen_rtx_PLUS (SImode, base, addr);
618 /* Split one or more DImode RTL references into pairs of SImode
619 references. The RTL can be REG, offsettable MEM, integer constant, or
620 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
621 split and "num" is its length. lo_half and hi_half are output arrays
622 that parallel "operands". */
625 split_di (operands, num, lo_half, hi_half)
628 rtx lo_half[], hi_half[];
632 if (GET_CODE (operands[num]) == REG)
634 lo_half[num] = gen_rtx_REG (SImode, REGNO (operands[num]));
635 hi_half[num] = gen_rtx_REG (SImode, REGNO (operands[num]) + 1);
637 else if (CONSTANT_P (operands[num]))
639 split_double (operands[num], &lo_half[num], &hi_half[num]);
641 else if (offsettable_memref_p (operands[num]))
643 lo_half[num] = operands[num];
644 hi_half[num] = adjust_address (operands[num], SImode, 4);
651 /* Return the best assembler insn template
652 for moving operands[1] into operands[0] as a fullword. */
655 singlemove_string (operands)
658 if (GET_CODE (operands[1]) == CONST_INT
659 && INTVAL (operands[1]) <= 7
660 && INTVAL (operands[1]) >= -8)
661 return "movqd %1,%0";
666 output_move_double (operands)
669 enum anon1 { REGOP, OFFSOP, PUSHOP, CNSTOP, RNDOP } optype0, optype1;
672 /* First classify both operands. */
674 if (REG_P (operands[0]))
676 else if (offsettable_memref_p (operands[0]))
678 else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
683 if (REG_P (operands[1]))
685 else if (CONSTANT_P (operands[1])
686 || GET_CODE (operands[1]) == CONST_DOUBLE)
688 else if (offsettable_memref_p (operands[1]))
690 else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
695 /* Check for the cases that the operand constraints are not
696 supposed to allow to happen. Abort if we get one,
697 because generating code for these cases is painful. */
699 if (optype0 == RNDOP || optype1 == RNDOP)
702 /* Ok, we can do one word at a time.
703 Normally we do the low-numbered word first,
704 but if either operand is autodecrementing then we
705 do the high-numbered word first.
707 In either case, set up in LATEHALF the operands to use
708 for the high-numbered word and in some cases alter the
709 operands in OPERANDS to be suitable for the low-numbered word. */
711 if (optype0 == REGOP)
712 latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
713 else if (optype0 == OFFSOP)
714 latehalf[0] = adjust_address (operands[0], SImode, 4);
716 latehalf[0] = operands[0];
718 if (optype1 == REGOP)
719 latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
720 else if (optype1 == OFFSOP)
721 latehalf[1] = adjust_address (operands[1], SImode, 4);
722 else if (optype1 == CNSTOP)
723 split_double (operands[1], &operands[1], &latehalf[1]);
725 latehalf[1] = operands[1];
727 /* If insn is effectively movd N(sp),tos then we will do the
728 high word first. We should use the adjusted operand 1 (which is N+4(sp))
729 for the low word as well, to compensate for the first decrement of sp.
730 Given this, it doesn't matter which half we do "first". */
731 if (optype0 == PUSHOP
732 && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
733 && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
734 operands[1] = latehalf[1];
736 /* If one or both operands autodecrementing,
737 do the two words, high-numbered first. */
738 else if (optype0 == PUSHOP || optype1 == PUSHOP)
740 output_asm_insn (singlemove_string (latehalf), latehalf);
741 return singlemove_string (operands);
744 /* If the first move would clobber the source of the second one,
745 do them in the other order. */
747 /* Overlapping registers. */
748 if (optype0 == REGOP && optype1 == REGOP
749 && REGNO (operands[0]) == REGNO (latehalf[1]))
752 output_asm_insn (singlemove_string (latehalf), latehalf);
753 /* Do low-numbered word. */
754 return singlemove_string (operands);
756 /* Loading into a register which overlaps a register used in the address. */
757 else if (optype0 == REGOP && optype1 != REGOP
758 && reg_overlap_mentioned_p (operands[0], operands[1]))
760 if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
761 && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
763 /* If both halves of dest are used in the src memory address,
764 load the destination address into the low reg (operands[0]).
765 Then it works to load latehalf first. */
767 xops[0] = XEXP (operands[1], 0);
768 xops[1] = operands[0];
769 output_asm_insn ("addr %a0,%1", xops);
770 operands[1] = gen_rtx_MEM (DImode, operands[0]);
771 latehalf[1] = adjust_address (operands[1], SImode, 4);
772 /* The first half has the overlap, Do the late half first. */
773 output_asm_insn (singlemove_string (latehalf), latehalf);
775 return singlemove_string (operands);
777 if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)))
779 /* The first half has the overlap, Do the late half first. */
780 output_asm_insn (singlemove_string (latehalf), latehalf);
782 return singlemove_string (operands);
786 /* Normal case. Do the two words, low-numbered first. */
788 output_asm_insn (singlemove_string (operands), operands);
790 operands[0] = latehalf[0];
791 operands[1] = latehalf[1];
792 return singlemove_string (operands);
796 #define MAX_UNALIGNED_COPY (32)
797 /* Expand string/block move operations.
799 operands[0] is the pointer to the destination.
800 operands[1] is the pointer to the source.
801 operands[2] is the number of bytes to move.
802 operands[3] is the alignment. */
805 move_tail (operands, bytes, offset)
812 emit_move_insn (adjust_address (operands[0], HImode, offset),
813 adjust_address (operands[1], HImode, offset));
817 emit_move_insn (adjust_address (operands[0], QImode, offset),
818 adjust_address (operands[1], QImode, offset));
822 expand_block_move (operands)
825 rtx bytes_rtx = operands[2];
826 rtx align_rtx = operands[3];
827 int constp = (GET_CODE (bytes_rtx) == CONST_INT);
828 int bytes = (constp ? INTVAL (bytes_rtx) : 0);
829 int align = INTVAL (align_rtx);
830 rtx src_reg = gen_rtx_REG (Pmode, 1);
831 rtx dest_reg = gen_rtx_REG (Pmode, 2);
832 rtx count_reg = gen_rtx_REG (SImode, 0);
834 if (constp && bytes <= 0)
837 if (constp && bytes < 20)
839 int words = bytes >> 2;
843 if (words < 3 || flag_unroll_loops)
847 for (; words; words--, offset += 4)
848 emit_move_insn (adjust_address (operands[0], SImode, offset),
849 adjust_address (operands[1], SImode, offset));
853 /* Use movmd. It is slower than multiple movd's but more
854 compact. It is also slower than movsd for large copies
855 but causes less registers reloading so is better than movsd
858 dest = copy_addr_to_reg (XEXP (operands[0], 0));
859 src = copy_addr_to_reg (XEXP (operands[1], 0));
861 emit_insn (gen_movstrsi2(dest, src, GEN_INT (words)));
864 move_tail (operands, bytes & 3, bytes & ~3);
868 if (align > UNITS_PER_WORD)
869 align = UNITS_PER_WORD;
871 /* Move the address into scratch registers. */
872 emit_insn (gen_rtx_CLOBBER (VOIDmode, dest_reg));
873 emit_move_insn (dest_reg, XEXP (operands[0], 0));
874 operands[0] = gen_rtx_MEM (SImode, dest_reg);
875 emit_insn (gen_rtx_CLOBBER (VOIDmode, src_reg));
876 emit_move_insn (src_reg, XEXP (operands[1], 0));
877 operands[1] = gen_rtx_MEM (SImode, src_reg);
878 emit_insn (gen_rtx_CLOBBER (VOIDmode, count_reg));
880 if (constp && (align == UNITS_PER_WORD || bytes < MAX_UNALIGNED_COPY))
882 /* constant no of bytes and aligned or small enough copy to not bother
883 * aligning. Emit insns to copy by words.
887 emit_move_insn (count_reg, GEN_INT (bytes >> 2));
888 emit_insn (gen_movstrsi1 (GEN_INT (4)));
890 /* insns to copy rest */
891 move_tail (operands, bytes & 3, 0);
893 else if (align == UNITS_PER_WORD)
895 /* insns to copy by words */
896 emit_insn (gen_lshrsi3 (count_reg, bytes_rtx, GEN_INT (2)));
897 emit_insn (gen_movstrsi1 (GEN_INT (4)));
900 move_tail (operands, bytes & 3, 0);
904 /* insns to copy rest */
905 emit_insn (gen_andsi3 (count_reg, bytes_rtx, GEN_INT (3)));
906 emit_insn (gen_movstrsi1 (const1_rtx));
911 /* Not aligned and we may have a lot to copy so it is worth
914 rtx aligned_label = gen_label_rtx ();
917 bytes_reg = copy_to_mode_reg (SImode, bytes_rtx);
920 /* Emit insns to test and skip over the alignment if it is
921 * not worth it. This doubles as a test to ensure that the alignment
922 * operation can't copy too many bytes
924 emit_insn (gen_cmpsi (bytes_reg, GEN_INT (MAX_UNALIGNED_COPY)));
925 emit_jump_insn (gen_blt (aligned_label));
928 /* Emit insns to do alignment at run time */
929 emit_insn (gen_negsi2 (count_reg, src_reg));
930 emit_insn (gen_andsi3 (count_reg, count_reg, GEN_INT (3)));
931 emit_insn (gen_subsi3 (bytes_reg, bytes_reg, count_reg));
932 emit_insn (gen_movstrsi1 (const1_rtx));
934 emit_label (aligned_label);
936 /* insns to copy by words */
937 emit_insn (gen_lshrsi3 (count_reg, bytes_reg, GEN_INT (2)));
938 emit_insn (gen_movstrsi1 (GEN_INT (4)));
940 /* insns to copy rest */
941 emit_insn (gen_andsi3 (count_reg, bytes_reg, GEN_INT (3)));
942 emit_insn (gen_movstrsi1 (const1_rtx));
947 /* Returns 1 if OP contains a global symbol reference */
950 global_symbolic_reference_mentioned_p (op, f)
954 register const char *fmt;
957 if (GET_CODE (op) == SYMBOL_REF)
959 if (! SYMBOL_REF_FLAG (op))
964 else if (f && GET_CODE (op) != CONST)
967 fmt = GET_RTX_FORMAT (GET_CODE (op));
968 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
974 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
975 if (global_symbolic_reference_mentioned_p (XVECEXP (op, i, j), 0))
978 else if (fmt[i] == 'e'
979 && global_symbolic_reference_mentioned_p (XEXP (op, i), 0))
987 /* Returns 1 if OP contains a symbol reference */
990 symbolic_reference_mentioned_p (op)
993 register const char *fmt;
996 if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
999 fmt = GET_RTX_FORMAT (GET_CODE (op));
1000 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
1006 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
1007 if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
1010 else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
1017 /* Table of machine-specific attributes. */
1019 const struct attribute_spec ns32k_attribute_table[] =
1021 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
1022 /* Stdcall attribute says callee is responsible for popping arguments
1023 if they are not variable. */
1024 { "stdcall", 0, 0, false, true, true, ns32k_handle_fntype_attribute },
1025 /* Cdecl attribute says the callee is a normal C declaration */
1026 { "cdecl", 0, 0, false, true, true, ns32k_handle_fntype_attribute },
1027 { NULL, 0, 0, false, false, false, NULL }
1030 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1031 arguments as in struct attribute_spec.handler. */
1033 ns32k_handle_fntype_attribute (node, name, args, flags, no_add_attrs)
1036 tree args ATTRIBUTE_UNUSED;
1037 int flags ATTRIBUTE_UNUSED;
1040 if (TREE_CODE (*node) != FUNCTION_TYPE
1041 && TREE_CODE (*node) != FIELD_DECL
1042 && TREE_CODE (*node) != TYPE_DECL)
1044 warning ("`%s' attribute only applies to functions",
1045 IDENTIFIER_POINTER (name));
1046 *no_add_attrs = true;
1053 /* Value is the number of bytes of arguments automatically
1054 popped when returning from a subroutine call.
1055 FUNDECL is the declaration node of the function (as a tree),
1056 FUNTYPE is the data type of the function (as a tree),
1057 or for a library call it is an identifier node for the subroutine name.
1058 SIZE is the number of bytes of arguments passed on the stack.
1060 On the ns32k, the RET insn may be used to pop them if the number
1061 of args is fixed, but if the number is variable then the caller
1062 must pop them all. RET can't be used for library calls now
1063 because the library is compiled with the Unix compiler.
1064 Use of RET is a selectable option, since it is incompatible with
1065 standard Unix calling sequences. If the option is not selected,
1066 the caller must always pop the args.
1068 The attribute stdcall is equivalent to RET on a per module basis. */
1071 ns32k_return_pops_args (fundecl, funtype, size)
1072 tree fundecl ATTRIBUTE_UNUSED;
1076 int rtd = TARGET_RTD;
1078 if (TREE_CODE (funtype) == IDENTIFIER_NODE)
1079 return rtd ? size : 0;
1081 /* Cdecl functions override -mrtd, and never pop the stack */
1082 if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype)))
1085 /* Stdcall functions will pop the stack if not variable args */
1086 if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype)))
1091 if (TYPE_ARG_TYPES (funtype) == NULL_TREE
1092 || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node))
1099 /* PRINT_OPERAND is defined to call this function,
1100 which is easier to debug than putting all the code in
1101 a macro definition in ns32k.h. */
1103 /* XXX time 12% of cpu time is in fprintf for non optimizing */
1105 print_operand (file, x, code)
1111 PUT_IMMEDIATE_PREFIX (file);
1112 else if (code == '?')
1113 PUT_EXTERNAL_PREFIX (file);
1114 else if (GET_CODE (x) == REG)
1115 fprintf (file, "%s", ns32k_out_reg_names[REGNO (x)]);
1116 else if (GET_CODE (x) == MEM)
1118 output_address (XEXP (x, 0));
1120 else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != VOIDmode)
1122 if (GET_MODE (x) == DFmode)
1124 union { double d; int i[2]; } u;
1125 u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
1126 PUT_IMMEDIATE_PREFIX (file);
1128 /* Sequent likes its floating point constants as integers */
1129 fprintf (file, "0Dx%08x%08x", u.i[1], u.i[0]);
1132 fprintf (file, "0f%.20e", u.d);
1134 fprintf (file, "0d%.20e", u.d);
1140 union { double d; int i[2]; } u;
1141 u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
1142 PUT_IMMEDIATE_PREFIX (file);
1144 /* We have no way of winning if we can't get the bits
1145 for a sequent floating point number. */
1146 #if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
1150 union { float f; long l; } uu;
1152 fprintf (file, "0Fx%08lx", uu.l);
1155 fprintf (file, "0f%.20e", u.d);
1162 && GET_CODE (x) == CONST
1163 && symbolic_reference_mentioned_p (x))
1165 fprintf (stderr, "illegal constant for pic-mode: \n");
1166 print_rtl (stderr, x);
1167 fprintf (stderr, "\nGET_CODE (x) == %d, CONST == %d, symbolic_reference_mentioned_p (x) == %d\n",
1168 GET_CODE (x), CONST, symbolic_reference_mentioned_p (x));
1172 && (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF))
1174 output_addr_const (file, x);
1175 fprintf (file, "(sb)");
1179 #ifdef NO_IMMEDIATE_PREFIX_IF_SYMBOLIC
1180 if (GET_CODE (x) == CONST_INT)
1182 PUT_IMMEDIATE_PREFIX (file);
1183 output_addr_const (file, x);
1188 /* PRINT_OPERAND_ADDRESS is defined to call this function,
1189 which is easier to debug than putting all the code in
1190 a macro definition in ns32k.h . */
1192 /* Completely rewritten to get this to work with Gas for PC532 Mach.
1193 This function didn't work and I just wasn't able (nor very willing) to
1194 figure out how it worked.
1195 90-11-25 Tatu Yl|nen <ylo@cs.hut.fi> */
1198 print_operand_address (file, addr)
1199 register FILE *file;
1202 static const char scales[] = { 'b', 'w', 'd', 0, 'q', };
1203 rtx offset, base, indexexp, tmp;
1205 extern int flag_pic;
1207 if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == POST_DEC)
1209 fprintf (file, "tos");
1216 while (addr != NULL)
1218 if (GET_CODE (addr) == PLUS)
1220 if (GET_CODE (XEXP (addr, 0)) == PLUS)
1222 tmp = XEXP (addr, 1);
1223 addr = XEXP (addr, 0);
1227 tmp = XEXP (addr,0);
1228 addr = XEXP (addr,1);
1236 switch (GET_CODE (tmp))
1250 if (REGNO (tmp) < F0_REGNUM)
1270 if (flag_pic && ! CONSTANT_POOL_ADDRESS_P (tmp)
1271 && ! SYMBOL_REF_FLAG (tmp))
1283 if (flag_pic && GET_CODE (tmp) == CONST)
1286 tmp1 = XEXP (tmp,0);
1287 if (GET_CODE (tmp1) != PLUS)
1290 sym = XEXP (tmp1,0);
1291 if (GET_CODE (sym) != SYMBOL_REF)
1294 sym = XEXP (tmp1,1);
1297 off = XEXP (tmp1,1);
1298 if (GET_CODE (sym) == SYMBOL_REF)
1300 if (GET_CODE (off) != CONST_INT)
1303 if (CONSTANT_POOL_ADDRESS_P (sym)
1304 || SYMBOL_REF_FLAG (sym))
1306 SYMBOL_REF_FLAG (tmp) = 1;
1330 offset = gen_rtx_PLUS (SImode, tmp, offset);
1339 offset = const0_rtx;
1342 #ifndef INDEX_RATHER_THAN_BASE
1343 && (flag_pic || TARGET_HIMEM)
1344 && GET_CODE (base) != SYMBOL_REF
1345 && GET_CODE (offset) != CONST_INT
1347 /* This is a re-implementation of the SEQUENT_ADDRESS_BUG fix. */
1349 && !indexexp && GET_CODE (base) == REG
1350 && REG_OK_FOR_INDEX_P (base))
1356 /* now, offset, base and indexexp are set */
1357 #ifndef BASE_REG_NEEDED
1360 #if defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC)
1361 if (GET_CODE (offset) == CONST_INT)
1363 PUT_ABSOLUTE_PREFIX (file);
1367 output_addr_const (file, offset);
1368 if (base) /* base can be (REG ...) or (MEM ...) */
1369 switch (GET_CODE (base))
1371 /* now we must output base. Possible alternatives are:
1375 (pc) (REG ...) used for SYMBOL_REF and LABEL_REF, output
1376 (disp(fp)) (MEM ...) just before possible [rX:y]
1377 (disp(sp)) (MEM ...)
1378 (disp(sb)) (MEM ...)
1381 fprintf (file, "(%s)", ns32k_out_reg_names[REGNO (base)]);
1387 fprintf (file, "(");
1388 output_addr_const (file, base);
1389 fprintf (file, "(sb))");
1392 addr = XEXP (base,0);
1395 while (addr != NULL)
1397 if (GET_CODE (addr) == PLUS)
1399 if (GET_CODE (XEXP (addr, 0)) == PLUS)
1401 tmp = XEXP (addr, 1);
1402 addr = XEXP (addr, 0);
1406 tmp = XEXP (addr, 0);
1407 addr = XEXP (addr, 1);
1415 switch (GET_CODE (tmp))
1425 offset = gen_rtx_PLUS (SImode, tmp, offset);
1434 offset = const0_rtx;
1435 fprintf (file, "(");
1436 output_addr_const (file, offset);
1438 fprintf (file, "(%s)", ns32k_out_reg_names[REGNO (base)]);
1440 fprintf (file, "(sb)");
1443 fprintf (file, ")");
1449 else if (GET_CODE (offset) != CONST_INT)
1450 fprintf (file, "(pc)");
1451 #ifdef BASE_REG_NEEDED
1453 fprintf (file, "(sb)");
1457 #endif /* PC_RELATIVE */
1459 /* now print index if we have one */
1462 if (GET_CODE (indexexp) == MULT)
1464 scale = INTVAL (XEXP (indexexp, 1)) >> 1;
1465 indexexp = XEXP (indexexp, 0);
1469 if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= F0_REGNUM)
1473 fprintf (file, "[%c`%s]",
1475 ns32k_out_reg_names[REGNO (indexexp)]);
1477 fprintf (file, "[%s:%c]",
1478 ns32k_out_reg_names[REGNO (indexexp)],
1484 /* National 32032 shifting is so bad that we can get
1485 better performance in many common cases by using other
1488 output_shift_insn (operands)
1491 if (GET_CODE (operands[2]) == CONST_INT
1492 && INTVAL (operands[2]) > 0
1493 && INTVAL (operands[2]) <= 3)
1495 if (GET_CODE (operands[0]) == REG)
1497 if (GET_CODE (operands[1]) == REG)
1499 if (REGNO (operands[0]) == REGNO (operands[1]))
1501 if (operands[2] == const1_rtx)
1502 return "addd %0,%0";
1503 else if (INTVAL (operands[2]) == 2)
1504 return "addd %0,%0\n\taddd %0,%0";
1506 if (operands[2] == const1_rtx)
1507 return "movd %1,%0\n\taddd %0,%0";
1509 operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
1510 return "addr %a1,%0";
1512 if (operands[2] == const1_rtx)
1513 return "movd %1,%0\n\taddd %0,%0";
1515 else if (GET_CODE (operands[1]) == REG)
1517 operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
1518 return "addr %a1,%0";
1520 else if (INTVAL (operands[2]) == 1
1521 && GET_CODE (operands[1]) == MEM
1522 && rtx_equal_p (operands [0], operands[1]))
1524 rtx temp = XEXP (operands[1], 0);
1526 if (GET_CODE (temp) == REG
1527 || (GET_CODE (temp) == PLUS
1528 && GET_CODE (XEXP (temp, 0)) == REG
1529 && GET_CODE (XEXP (temp, 1)) == CONST_INT))
1530 return "addd %0,%0";
1532 else return "ashd %2,%0";
1534 return "ashd %2,%0";
1538 output_move_dconst (n, s)
1544 if (n > -9 && n < 8)
1545 strcpy (r, "movqd ");
1546 else if (n > 0 && n < 256)
1547 strcpy (r, "movzbd ");
1548 else if (n > 0 && n < 65536)
1549 strcpy (r, "movzwd ");
1550 else if (n < 0 && n > -129)
1551 strcpy (r, "movxbd ");
1552 else if (n < 0 && n > -32769)
1553 strcpy (r, "movxwd ");
1555 strcpy (r, "movd ");