1 /* Subroutines for assembler code output on the NS32000.
2 Copyright (C) 1988, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
4 Free Software Foundation, Inc.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
13 GCC is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING. If not, write to
20 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA. */
25 #include "coretypes.h"
29 #include "hard-reg-set.h"
31 #include "insn-config.h"
32 #include "conditions.h"
34 #include "insn-attr.h"
42 #include "target-def.h"
46 int ns32k_num_files = 0;
49 /* This duplicates reg_class_contents in reg_class.c, but maybe that isn't
50 initialized in time. Also this is more convenient as an array of ints.
51 We know that HARD_REG_SET fits in an unsigned int */
53 const unsigned int ns32k_reg_class_contents[N_REG_CLASSES][1] = REG_CLASS_CONTENTS;
55 const enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
57 GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
58 GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
59 FLOAT_REG0, LONG_FLOAT_REG0, FLOAT_REGS, FLOAT_REGS,
60 FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS,
61 LONG_REGS, LONG_REGS, LONG_REGS, LONG_REGS,
62 LONG_REGS, LONG_REGS, LONG_REGS, LONG_REGS,
63 FRAME_POINTER_REG, STACK_POINTER_REG
66 static const char *const ns32k_out_reg_names[] = OUTPUT_REGISTER_NAMES;
68 static bool ns32k_handle_option (size_t, const char *, int);
69 static rtx gen_indexed_expr (rtx, rtx, rtx);
70 static const char *singlemove_string (rtx *);
71 static void move_tail (rtx[], int, int);
72 static tree ns32k_handle_fntype_attribute (tree *, tree, tree, int, bool *);
73 const struct attribute_spec ns32k_attribute_table[];
74 static void ns32k_output_function_prologue (FILE *, HOST_WIDE_INT);
75 static void ns32k_output_function_epilogue (FILE *, HOST_WIDE_INT);
76 static bool ns32k_rtx_costs (rtx, int, int, int *);
77 static int ns32k_address_cost (rtx);
78 static rtx ns32k_struct_value_rtx (tree, int);
79 static int ns32k_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
82 /* Initialize the GCC target structure. */
83 #undef TARGET_ATTRIBUTE_TABLE
84 #define TARGET_ATTRIBUTE_TABLE ns32k_attribute_table
86 #undef TARGET_ASM_ALIGNED_HI_OP
87 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
90 #undef TARGET_ASM_ALIGNED_SI_OP
91 #define TARGET_ASM_ALIGNED_SI_OP "\t.double\t"
94 #undef TARGET_ASM_FUNCTION_PROLOGUE
95 #define TARGET_ASM_FUNCTION_PROLOGUE ns32k_output_function_prologue
96 #undef TARGET_ASM_FUNCTION_EPILOGUE
97 #define TARGET_ASM_FUNCTION_EPILOGUE ns32k_output_function_epilogue
99 #undef TARGET_DEFAULT_TARGET_FLAGS
100 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
101 #undef TARGET_HANDLE_OPTION
102 #define TARGET_HANDLE_OPTION ns32k_handle_option
104 #undef TARGET_RTX_COSTS
105 #define TARGET_RTX_COSTS ns32k_rtx_costs
106 #undef TARGET_ADDRESS_COST
107 #define TARGET_ADDRESS_COST ns32k_address_cost
109 #undef TARGET_STRUCT_VALUE_RTX
110 #define TARGET_STRUCT_VALUE_RTX ns32k_struct_value_rtx
112 #undef TARGET_ARG_PARTIAL_BYTES
113 #define TARGET_ARG_PARTIAL_BYTES ns32k_arg_partial_bytes
115 #undef TARGET_ASM_FILE_START_APP_OFF
116 #define TARGET_ASM_FILE_START_APP_OFF true
118 struct gcc_target targetm = TARGET_INITIALIZER;
120 /* Implement TARGET_HANDLE_OPTION. */
123 ns32k_handle_option (size_t code, const char *arg ATTRIBUTE_UNUSED,
124 int value ATTRIBUTE_UNUSED)
129 target_flags &= ~MASK_32381;
132 case OPT_msoft_float:
133 target_flags &= ~(MASK_32081 | MASK_32381);
137 target_flags &= ~MASK_32532;
141 target_flags &= ~(MASK_32332 | MASK_32532);
149 /* Generate the assembly code for function entry. FILE is a stdio
150 stream to output the code to. SIZE is an int: how many units of
151 temporary storage to allocate.
153 Refer to the array `regs_ever_live' to determine which registers to
154 save; `regs_ever_live[I]' is nonzero if register number I is ever
155 used in the function. This function is responsible for knowing
156 which registers should not be saved even if used. */
159 * The function prologue for the ns32k is fairly simple.
160 * If a frame pointer is needed (decided in reload.c ?) then
161 * we need assembler of the form
163 * # Save the oldframe pointer, set the new frame pointer, make space
164 * # on the stack and save any general purpose registers necessary
166 * enter [<general purpose regs to save>], <local stack space>
168 * movf fn, tos # Save any floating point registers necessary
172 * If a frame pointer is not needed we need assembler of the form
174 * # Make space on the stack
176 * adjspd <local stack space + 4>
178 * # Save any general purpose registers necessary
180 * save [<general purpose regs to save>]
182 * movf fn, tos # Save any floating point registers necessary
187 #if !defined (MERLIN_TARGET) && !defined (UTEK_ASM)
189 #if defined(IMMEDIATE_PREFIX) && IMMEDIATE_PREFIX
190 #define ADJSP(FILE, N) \
191 fprintf (FILE, "\tadjspd %c" HOST_WIDE_INT_PRINT_DEC "\n", IMMEDIATE_PREFIX, (N))
193 #define ADJSP(FILE, N) \
194 fprintf (FILE, "\tadjspd " HOST_WIDE_INT_PRINT_DEC "\n", (N))
198 ns32k_output_function_prologue (FILE *file, HOST_WIDE_INT size)
200 register int regno, g_regs_used = 0;
201 int used_regs_buf[8], *bufp = used_regs_buf;
202 int used_fregs_buf[17], *fbufp = used_fregs_buf;
204 for (regno = R0_REGNUM; regno < F0_REGNUM; regno++)
205 if (regs_ever_live[regno]
206 && ! call_used_regs[regno])
208 *bufp++ = regno; g_regs_used++;
212 for (; regno < FRAME_POINTER_REGNUM; regno++)
213 if (regs_ever_live[regno] && !call_used_regs[regno])
219 bufp = used_regs_buf;
220 if (frame_pointer_needed)
221 fprintf (file, "\tenter [");
225 ADJSP (file, size + 4);
226 if (g_regs_used && g_regs_used > 4)
227 fprintf (file, "\tsave [");
231 fprintf (file, "\tmovd r%d,tos\n", *bufp++);
238 fprintf (file, "r%d", *bufp++);
243 if (frame_pointer_needed)
244 fprintf (file, "]," HOST_WIDE_INT_PRINT_DEC "\n", size);
245 else if (g_regs_used)
246 fprintf (file, "]\n");
248 fbufp = used_fregs_buf;
251 if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1))
252 fprintf (file, "\tmovf %s,tos\n", ns32k_out_reg_names[*fbufp++]);
255 fprintf (file, "\tmovl %s,tos\n",
256 ns32k_out_reg_names[fbufp[0]]);
261 if (flag_pic && current_function_uses_pic_offset_table)
263 fprintf (file, "\tsprd sb,tos\n");
266 fprintf (file, "\taddr __GLOBAL_OFFSET_TABLE_(pc),tos\n");
267 fprintf (file, "\tlprd sb,tos\n");
271 fprintf (file, "\taddr __GLOBAL_OFFSET_TABLE_(pc),r0\n");
272 fprintf (file, "\tlprd sb,r0\n");
277 #else /* MERLIN_TARGET || UTEK_ASM */
279 /* This differs from the standard one above in printing a bitmask
280 rather than a register list in the enter or save instruction. */
283 ns32k_output_function_prologue (file, size)
287 register int regno, g_regs_used = 0;
288 int used_regs_buf[8], *bufp = used_regs_buf;
289 int used_fregs_buf[8], *fbufp = used_fregs_buf;
291 for (regno = 0; regno < 8; regno++)
292 if (regs_ever_live[regno]
293 && ! call_used_regs[regno])
295 *bufp++ = regno; g_regs_used++;
299 for (; regno < 16; regno++)
300 if (regs_ever_live[regno] && !call_used_regs[regno]) {
305 bufp = used_regs_buf;
306 if (frame_pointer_needed)
307 fprintf (file, "\tenter ");
308 else if (g_regs_used)
309 fprintf (file, "\tsave ");
311 if (frame_pointer_needed || g_regs_used)
315 mask |= 1 << *bufp++;
316 fprintf (file, "$0x%x", (int) mask & 0xff);
319 if (frame_pointer_needed)
321 fprintf (file, ",$%d\n", size);
323 fprintf (file, ",%d\n", size);
325 else if (g_regs_used)
326 fprintf (file, "\n");
328 fbufp = used_fregs_buf;
331 if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1))
332 fprintf (file, "\tmovf f%d,tos\n", *fbufp++ - 8);
335 fprintf (file, "\tmovl f%d,tos\n", fbufp[0] - 8);
341 #endif /* MERLIN_TARGET || UTEK_ASM */
343 /* This function generates the assembly code for function exit,
344 on machines that need it.
346 The function epilogue should not depend on the current stack pointer,
347 if EXIT_IGNORE_STACK is nonzero. That doesn't apply here.
349 If a frame pointer is needed (decided in reload.c ?) then
350 we need assembler of the form
352 movf tos, fn # Restore any saved floating point registers
356 # Restore any saved general purpose registers, restore the stack
357 # pointer from the frame pointer, restore the old frame pointer.
358 exit [<general purpose regs to save>]
360 If a frame pointer is not needed we need assembler of the form
361 # Restore any general purpose registers saved
363 movf tos, fn # Restore any saved floating point registers
367 restore [<general purpose regs to save>]
369 # reclaim space allocated on stack
371 adjspd <-(local stack space + 4)> */
373 #if !defined (MERLIN_TARGET) && !defined (UTEK_ASM)
376 ns32k_output_function_epilogue (FILE *file, HOST_WIDE_INT size)
378 register int regno, g_regs_used = 0, f_regs_used = 0;
379 int used_regs_buf[8], *bufp = used_regs_buf;
380 int used_fregs_buf[17], *fbufp = used_fregs_buf;
382 if (flag_pic && current_function_uses_pic_offset_table)
383 fprintf (file, "\tlprd sb,tos\n");
386 for (regno = F0_REGNUM; regno < FRAME_POINTER_REGNUM; regno++)
387 if (regs_ever_live[regno] && !call_used_regs[regno])
389 *fbufp++ = regno; f_regs_used++;
393 for (regno = 0; regno < F0_REGNUM; regno++)
394 if (regs_ever_live[regno]
395 && ! call_used_regs[regno])
397 *bufp++ = regno; g_regs_used++;
400 while (fbufp > used_fregs_buf)
402 if ((*fbufp & 1) && fbufp[0] == fbufp[-1] + 1)
404 fprintf (file, "\tmovl tos,%s\n",
405 ns32k_out_reg_names[fbufp[-1]]);
408 else fprintf (file, "\tmovf tos,%s\n", ns32k_out_reg_names[*fbufp--]);
411 if (frame_pointer_needed)
412 fprintf (file, "\texit [");
415 if (g_regs_used && g_regs_used > 4)
416 fprintf (file, "\trestore [");
419 while (bufp > used_regs_buf)
420 fprintf (file, "\tmovd tos,r%d\n", *--bufp);
425 while (bufp > used_regs_buf)
427 fprintf (file, "r%d", *--bufp);
428 if (bufp > used_regs_buf)
432 if (g_regs_used || frame_pointer_needed)
433 fprintf (file, "]\n");
435 if (size && !frame_pointer_needed)
436 ADJSP (file, -(size + 4));
438 if (current_function_pops_args)
439 fprintf (file, "\tret %d\n", current_function_pops_args);
441 fprintf (file, "\tret 0\n");
444 #else /* MERLIN_TARGET || UTEK_ASM */
446 /* This differs from the standard one above in printing a bitmask
447 rather than a register list in the exit or restore instruction. */
450 ns32k_output_function_epilogue (file, size)
452 HOST_WIDE_INT size ATTRIBUTE_UNUSED;
454 register int regno, g_regs_used = 0, f_regs_used = 0;
455 int used_regs_buf[8], *bufp = used_regs_buf;
456 int used_fregs_buf[8], *fbufp = used_fregs_buf;
459 for (regno = 8; regno < 16; regno++)
460 if (regs_ever_live[regno] && !call_used_regs[regno]) {
461 *fbufp++ = regno; f_regs_used++;
465 for (regno = 0; regno < 8; regno++)
466 if (regs_ever_live[regno]
467 && ! call_used_regs[regno])
469 *bufp++ = regno; g_regs_used++;
472 while (fbufp > used_fregs_buf)
474 if ((*fbufp & 1) && fbufp[0] == fbufp[-1] + 1)
476 fprintf (file, "\tmovl tos,f%d\n", fbufp[-1] - 8);
479 else fprintf (file, "\tmovf tos,f%d\n", *fbufp-- - 8);
482 if (frame_pointer_needed)
483 fprintf (file, "\texit ");
484 else if (g_regs_used)
485 fprintf (file, "\trestore ");
487 if (g_regs_used || frame_pointer_needed)
491 while (bufp > used_regs_buf)
493 /* Utek assembler takes care of reversing this */
494 mask |= 1 << *--bufp;
496 fprintf (file, "$0x%x\n", (int) mask & 0xff);
500 if (current_function_pops_args)
501 fprintf (file, "\tret $%d\n", current_function_pops_args);
503 fprintf (file, "\tret $0\n");
505 if (current_function_pops_args)
506 fprintf (file, "\tret %d\n", current_function_pops_args);
508 fprintf (file, "\tret 0\n");
512 #endif /* MERLIN_TARGET || UTEK_ASM */
514 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */
516 hard_regno_mode_ok (int regno, enum machine_mode mode)
518 int size = GET_MODE_UNIT_SIZE (mode);
520 if (FLOAT_MODE_P (mode))
522 if (size == UNITS_PER_WORD && regno < L1_REGNUM)
524 if (size == UNITS_PER_WORD * 2
525 && (((regno & 1) == 0 && regno < FRAME_POINTER_REGNUM)))
529 if (size == UNITS_PER_WORD * 2
530 && (regno & 1) == 0 && regno < F0_REGNUM)
532 if (size <= UNITS_PER_WORD
533 && (regno < F0_REGNUM || regno == FRAME_POINTER_REGNUM
534 || regno == STACK_POINTER_REGNUM))
540 ns32k_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total)
545 if (INTVAL (x) <= 7 && INTVAL (x) >= -8)
547 else if (INTVAL (x) < 0x2000 && INTVAL (x) >= -0x2000)
569 register_move_cost (enum reg_class CLASS1, enum reg_class CLASS2)
571 if (CLASS1 == NO_REGS || CLASS2 == NO_REGS)
573 if ((SUBSET_P (CLASS1, FP_REGS) && !SUBSET_P (CLASS2, FP_REGS))
574 || (!SUBSET_P (CLASS1, FP_REGS) && SUBSET_P (CLASS2, FP_REGS)))
576 if (((CLASS1) == STACK_POINTER_REG && !SUBSET_P (CLASS2,GENERAL_REGS))
577 || ((CLASS2) == STACK_POINTER_REG && !SUBSET_P (CLASS1,GENERAL_REGS)))
579 if (((CLASS1) == FRAME_POINTER_REG && !SUBSET_P (CLASS2,GENERAL_REGS))
580 || ((CLASS2) == FRAME_POINTER_REG && !SUBSET_P (CLASS1,GENERAL_REGS)))
586 /* We made the insn definitions copy from floating point to general
587 registers via the stack. */
589 secondary_memory_needed (enum reg_class CLASS1,
590 enum reg_class CLASS2,
593 int ret = ((SUBSET_P (CLASS1, FP_REGS) && !SUBSET_P (CLASS2, FP_REGS))
594 || (!SUBSET_P (CLASS1, FP_REGS) && SUBSET_P (CLASS2, FP_REGS)));
600 /* TARGET_ADDRESS_COST calls this. This function is not optimal
601 for the 32032 & 32332, but it probably is better than
605 ns32k_address_cost (rtx operand)
609 switch (GET_CODE (operand))
620 if (INTVAL (operand) <= 7 && INTVAL (operand) >= -8)
622 if (INTVAL (operand) < 0x2000 && INTVAL (operand) >= -0x2000)
637 cost += ns32k_address_cost (XEXP (operand, 0)) + 3;
644 cost += ns32k_address_cost (XEXP (operand, 0));
645 cost += ns32k_address_cost (XEXP (operand, 1));
655 /* Return the register class of a scratch register needed to copy IN into
656 or out of a register in CLASS in MODE. If it can be done directly,
657 NO_REGS is returned. */
660 secondary_reload_class (enum reg_class class,
661 enum machine_mode mode ATTRIBUTE_UNUSED,
664 int regno = true_regnum (in);
666 if (regno >= FIRST_PSEUDO_REGISTER)
669 if ((class == FRAME_POINTER_REG && regno == STACK_POINTER_REGNUM)
670 || ( class == STACK_POINTER_REG && regno == FRAME_POINTER_REGNUM))
676 /* Generate the rtx that comes from an address expression in the md file */
677 /* The expression to be build is BASE[INDEX:SCALE]. To recognize this,
678 scale must be converted from an exponent (from ASHIFT) to a
679 multiplier (for MULT). */
682 gen_indexed_expr (rtx base, rtx index, rtx scale)
686 /* This generates an invalid addressing mode, if BASE is
687 fp or sp. This is handled by PRINT_OPERAND_ADDRESS. */
688 if (GET_CODE (base) != REG && GET_CODE (base) != CONST_INT)
689 base = gen_rtx_MEM (SImode, base);
690 addr = gen_rtx_MULT (SImode, index,
691 GEN_INT (1 << INTVAL (scale)));
692 addr = gen_rtx_PLUS (SImode, base, addr);
697 /* Split one or more DImode RTL references into pairs of SImode
698 references. The RTL can be REG, offsettable MEM, integer constant, or
699 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
700 split and "num" is its length. lo_half and hi_half are output arrays
701 that parallel "operands". */
704 split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
708 if (GET_CODE (operands[num]) == REG)
710 lo_half[num] = gen_rtx_REG (SImode, REGNO (operands[num]));
711 hi_half[num] = gen_rtx_REG (SImode, REGNO (operands[num]) + 1);
713 else if (CONSTANT_P (operands[num]))
715 split_double (operands[num], &lo_half[num], &hi_half[num]);
717 else if (offsettable_memref_p (operands[num]))
719 lo_half[num] = operands[num];
720 hi_half[num] = adjust_address (operands[num], SImode, 4);
727 /* Return the best assembler insn template
728 for moving operands[1] into operands[0] as a fullword. */
731 singlemove_string (rtx *operands)
733 if (GET_CODE (operands[1]) == CONST_INT
734 && INTVAL (operands[1]) <= 7
735 && INTVAL (operands[1]) >= -8)
736 return "movqd %1,%0";
741 output_move_double (rtx *operands)
743 enum anon1 { REGOP, OFFSOP, PUSHOP, CNSTOP, RNDOP } optype0, optype1;
746 /* First classify both operands. */
748 if (REG_P (operands[0]))
750 else if (offsettable_memref_p (operands[0]))
752 else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
757 if (REG_P (operands[1]))
759 else if (CONSTANT_P (operands[1])
760 || GET_CODE (operands[1]) == CONST_DOUBLE)
762 else if (offsettable_memref_p (operands[1]))
764 else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
769 /* Check for the cases that the operand constraints are not
770 supposed to allow to happen. Abort if we get one,
771 because generating code for these cases is painful. */
773 if (optype0 == RNDOP || optype1 == RNDOP)
776 /* Ok, we can do one word at a time.
777 Normally we do the low-numbered word first,
778 but if either operand is autodecrementing then we
779 do the high-numbered word first.
781 In either case, set up in LATEHALF the operands to use
782 for the high-numbered word and in some cases alter the
783 operands in OPERANDS to be suitable for the low-numbered word. */
785 if (optype0 == REGOP)
786 latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
787 else if (optype0 == OFFSOP)
788 latehalf[0] = adjust_address (operands[0], SImode, 4);
790 latehalf[0] = operands[0];
792 if (optype1 == REGOP)
793 latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
794 else if (optype1 == OFFSOP)
795 latehalf[1] = adjust_address (operands[1], SImode, 4);
796 else if (optype1 == CNSTOP)
797 split_double (operands[1], &operands[1], &latehalf[1]);
799 latehalf[1] = operands[1];
801 /* If insn is effectively movd N(sp),tos then we will do the
802 high word first. We should use the adjusted operand 1 (which is N+4(sp))
803 for the low word as well, to compensate for the first decrement of sp.
804 Given this, it doesn't matter which half we do "first". */
805 if (optype0 == PUSHOP
806 && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
807 && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
808 operands[1] = latehalf[1];
810 /* If one or both operands autodecrementing,
811 do the two words, high-numbered first. */
812 else if (optype0 == PUSHOP || optype1 == PUSHOP)
814 output_asm_insn (singlemove_string (latehalf), latehalf);
815 return singlemove_string (operands);
818 /* If the first move would clobber the source of the second one,
819 do them in the other order. */
821 /* Overlapping registers. */
822 if (optype0 == REGOP && optype1 == REGOP
823 && REGNO (operands[0]) == REGNO (latehalf[1]))
826 output_asm_insn (singlemove_string (latehalf), latehalf);
827 /* Do low-numbered word. */
828 return singlemove_string (operands);
830 /* Loading into a register which overlaps a register used in the address. */
831 else if (optype0 == REGOP && optype1 != REGOP
832 && reg_overlap_mentioned_p (operands[0], operands[1]))
834 if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
835 && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
837 /* If both halves of dest are used in the src memory address,
838 load the destination address into the low reg (operands[0]).
839 Then it works to load latehalf first. */
841 xops[0] = XEXP (operands[1], 0);
842 xops[1] = operands[0];
843 output_asm_insn ("addr %a0,%1", xops);
844 operands[1] = gen_rtx_MEM (DImode, operands[0]);
845 latehalf[1] = adjust_address (operands[1], SImode, 4);
846 /* The first half has the overlap, Do the late half first. */
847 output_asm_insn (singlemove_string (latehalf), latehalf);
849 return singlemove_string (operands);
851 if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)))
853 /* The first half has the overlap, Do the late half first. */
854 output_asm_insn (singlemove_string (latehalf), latehalf);
856 return singlemove_string (operands);
860 /* Normal case. Do the two words, low-numbered first. */
862 output_asm_insn (singlemove_string (operands), operands);
864 operands[0] = latehalf[0];
865 operands[1] = latehalf[1];
866 return singlemove_string (operands);
870 #define MAX_UNALIGNED_COPY (32)
871 /* Expand string/block move operations.
873 operands[0] is the pointer to the destination.
874 operands[1] is the pointer to the source.
875 operands[2] is the number of bytes to move.
876 operands[3] is the alignment. */
879 move_tail (rtx operands[], int bytes, int offset)
883 emit_move_insn (adjust_address (operands[0], HImode, offset),
884 adjust_address (operands[1], HImode, offset));
888 emit_move_insn (adjust_address (operands[0], QImode, offset),
889 adjust_address (operands[1], QImode, offset));
893 expand_block_move (rtx operands[])
895 rtx bytes_rtx = operands[2];
896 rtx align_rtx = operands[3];
897 int constp = (GET_CODE (bytes_rtx) == CONST_INT);
898 int bytes = (constp ? INTVAL (bytes_rtx) : 0);
899 int align = INTVAL (align_rtx);
900 rtx src_reg = gen_rtx_REG (Pmode, 1);
901 rtx dest_reg = gen_rtx_REG (Pmode, 2);
902 rtx count_reg = gen_rtx_REG (SImode, 0);
904 if (constp && bytes <= 0)
907 if (constp && bytes < 20)
909 int words = bytes >> 2;
917 for (; words; words--, offset += 4)
918 emit_move_insn (adjust_address (operands[0], SImode, offset),
919 adjust_address (operands[1], SImode, offset));
923 /* Use movmd. It is slower than multiple movd's but more
924 compact. It is also slower than movsd for large copies
925 but causes less registers reloading so is better than movsd
928 dest = copy_addr_to_reg (XEXP (operands[0], 0));
929 src = copy_addr_to_reg (XEXP (operands[1], 0));
931 emit_insn (gen_movmemsi2(dest, src, GEN_INT (words)));
934 move_tail (operands, bytes & 3, bytes & ~3);
938 if (align > UNITS_PER_WORD)
939 align = UNITS_PER_WORD;
941 /* Move the address into scratch registers. */
942 emit_insn (gen_rtx_CLOBBER (VOIDmode, dest_reg));
943 emit_move_insn (dest_reg, XEXP (operands[0], 0));
944 operands[0] = gen_rtx_MEM (SImode, dest_reg);
945 emit_insn (gen_rtx_CLOBBER (VOIDmode, src_reg));
946 emit_move_insn (src_reg, XEXP (operands[1], 0));
947 operands[1] = gen_rtx_MEM (SImode, src_reg);
948 emit_insn (gen_rtx_CLOBBER (VOIDmode, count_reg));
950 if (constp && (align == UNITS_PER_WORD || bytes < MAX_UNALIGNED_COPY))
952 /* constant no of bytes and aligned or small enough copy to not bother
953 * aligning. Emit insns to copy by words.
957 emit_move_insn (count_reg, GEN_INT (bytes >> 2));
958 emit_insn (gen_movmemsi1 (GEN_INT (4)));
960 /* insns to copy rest */
961 move_tail (operands, bytes & 3, 0);
963 else if (align == UNITS_PER_WORD)
965 /* insns to copy by words */
966 emit_insn (gen_lshrsi3 (count_reg, bytes_rtx, const2_rtx));
967 emit_insn (gen_movmemsi1 (GEN_INT (4)));
970 move_tail (operands, bytes & 3, 0);
974 /* insns to copy rest */
975 emit_insn (gen_andsi3 (count_reg, bytes_rtx, GEN_INT (3)));
976 emit_insn (gen_movmemsi1 (const1_rtx));
981 /* Not aligned and we may have a lot to copy so it is worth
984 rtx aligned_label = gen_label_rtx ();
987 bytes_reg = copy_to_mode_reg (SImode, bytes_rtx);
990 /* Emit insns to test and skip over the alignment if it is
991 * not worth it. This doubles as a test to ensure that the alignment
992 * operation can't copy too many bytes
994 emit_insn (gen_cmpsi (bytes_reg, GEN_INT (MAX_UNALIGNED_COPY)));
995 emit_jump_insn (gen_blt (aligned_label));
998 /* Emit insns to do alignment at run time */
999 emit_insn (gen_negsi2 (count_reg, src_reg));
1000 emit_insn (gen_andsi3 (count_reg, count_reg, GEN_INT (3)));
1001 emit_insn (gen_subsi3 (bytes_reg, bytes_reg, count_reg));
1002 emit_insn (gen_movmemsi1 (const1_rtx));
1004 emit_label (aligned_label);
1006 /* insns to copy by words */
1007 emit_insn (gen_lshrsi3 (count_reg, bytes_reg, const2_rtx));
1008 emit_insn (gen_movmemsi1 (GEN_INT (4)));
1010 /* insns to copy rest */
1011 emit_insn (gen_andsi3 (count_reg, bytes_reg, GEN_INT (3)));
1012 emit_insn (gen_movmemsi1 (const1_rtx));
1017 /* Returns 1 if OP contains a global symbol reference */
1020 global_symbolic_reference_mentioned_p (rtx op, int f)
1022 register const char *fmt;
1025 if (GET_CODE (op) == SYMBOL_REF)
1027 if (! SYMBOL_REF_LOCAL_P (op))
1032 else if (f && GET_CODE (op) != CONST)
1035 fmt = GET_RTX_FORMAT (GET_CODE (op));
1036 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
1042 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
1043 if (global_symbolic_reference_mentioned_p (XVECEXP (op, i, j), 0))
1046 else if (fmt[i] == 'e'
1047 && global_symbolic_reference_mentioned_p (XEXP (op, i), 0))
1055 /* Returns 1 if OP contains a symbol reference */
1058 symbolic_reference_mentioned_p (rtx op)
1060 register const char *fmt;
1063 if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
1066 fmt = GET_RTX_FORMAT (GET_CODE (op));
1067 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
1073 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
1074 if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
1077 else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
1084 /* Table of machine-specific attributes. */
1086 const struct attribute_spec ns32k_attribute_table[] =
1088 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
1089 /* Stdcall attribute says callee is responsible for popping arguments
1090 if they are not variable. */
1091 { "stdcall", 0, 0, false, true, true, ns32k_handle_fntype_attribute },
1092 /* Cdecl attribute says the callee is a normal C declaration */
1093 { "cdecl", 0, 0, false, true, true, ns32k_handle_fntype_attribute },
1094 { NULL, 0, 0, false, false, false, NULL }
1097 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1098 arguments as in struct attribute_spec.handler. */
1100 ns32k_handle_fntype_attribute (tree *node, tree name,
1101 tree args ATTRIBUTE_UNUSED,
1102 int flags ATTRIBUTE_UNUSED,
1105 if (TREE_CODE (*node) != FUNCTION_TYPE
1106 && TREE_CODE (*node) != FIELD_DECL
1107 && TREE_CODE (*node) != TYPE_DECL)
1109 warning (OPT_Wattributes, "%qs attribute only applies to functions",
1110 IDENTIFIER_POINTER (name));
1111 *no_add_attrs = true;
1118 /* Value is the number of bytes of arguments automatically
1119 popped when returning from a subroutine call.
1120 FUNDECL is the declaration node of the function (as a tree),
1121 FUNTYPE is the data type of the function (as a tree),
1122 or for a library call it is an identifier node for the subroutine name.
1123 SIZE is the number of bytes of arguments passed on the stack.
1125 On the ns32k, the RET insn may be used to pop them if the number
1126 of args is fixed, but if the number is variable then the caller
1127 must pop them all. RET can't be used for library calls now
1128 because the library is compiled with the Unix compiler.
1129 Use of RET is a selectable option, since it is incompatible with
1130 standard Unix calling sequences. If the option is not selected,
1131 the caller must always pop the args.
1133 The attribute stdcall is equivalent to RET on a per module basis. */
1136 ns32k_return_pops_args (tree fundecl ATTRIBUTE_UNUSED, tree funtype, int size)
1138 int rtd = TARGET_RTD;
1140 if (TREE_CODE (funtype) == IDENTIFIER_NODE)
1141 return rtd ? size : 0;
1143 /* Cdecl functions override -mrtd, and never pop the stack */
1144 if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype)))
1147 /* Stdcall functions will pop the stack if not variable args */
1148 if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype)))
1153 if (TYPE_ARG_TYPES (funtype) == NULL_TREE
1154 || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node))
1161 /* PRINT_OPERAND is defined to call this function,
1162 which is easier to debug than putting all the code in
1163 a macro definition in ns32k.h. */
1165 /* XXX time 12% of cpu time is in fprintf for non optimizing */
1167 print_operand (FILE *file, rtx x, int code)
1170 PUT_IMMEDIATE_PREFIX (file);
1171 else if (code == '?')
1172 PUT_EXTERNAL_PREFIX (file);
1173 else if (GET_CODE (x) == REG)
1174 fprintf (file, "%s", ns32k_out_reg_names[REGNO (x)]);
1175 else if (GET_CODE (x) == MEM)
1177 output_address (XEXP (x, 0));
1179 else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != VOIDmode)
1183 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1184 PUT_IMMEDIATE_PREFIX (file);
1185 if (GET_MODE (x) == DFmode)
1188 /* Sequent likes its floating point constants as integers */
1190 REAL_VALUE_TO_TARGET_DOUBLE (r, l);
1191 fprintf (file, "0Dx%08x%08x",
1192 l[!WORDS_BIG_ENDIAN], l[WORDS_BIG_ENDIAN]);
1195 real_to_decimal (s, &r, sizeof (s), 0, 1);
1197 fprintf (file, "0f%s", s);
1199 fprintf (file, "0d%s", s);
1207 REAL_VALUE_TO_TARGET_SINGLE (r, l);
1208 fprintf (file, "0Fx%08lx", l);
1211 real_to_decimal (s, &r, sizeof (s), 0, 1);
1212 fprintf (file, "0f%s", s);
1219 && GET_CODE (x) == CONST
1220 && symbolic_reference_mentioned_p (x))
1222 fprintf (stderr, "illegal constant for pic-mode: \n");
1223 print_rtl (stderr, x);
1224 fprintf (stderr, "\nGET_CODE (x) == %d, CONST == %d, symbolic_reference_mentioned_p (x) == %d\n",
1225 GET_CODE (x), CONST, symbolic_reference_mentioned_p (x));
1229 && (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF))
1231 output_addr_const (file, x);
1232 fprintf (file, "(sb)");
1236 #ifdef NO_IMMEDIATE_PREFIX_IF_SYMBOLIC
1237 if (GET_CODE (x) == CONST_INT)
1239 PUT_IMMEDIATE_PREFIX (file);
1240 output_addr_const (file, x);
1245 /* PRINT_OPERAND_ADDRESS is defined to call this function,
1246 which is easier to debug than putting all the code in
1247 a macro definition in ns32k.h . */
1249 /* Completely rewritten to get this to work with Gas for PC532 Mach.
1250 This function didn't work and I just wasn't able (nor very willing) to
1251 figure out how it worked.
1252 90-11-25 Tatu Yl|nen <ylo@cs.hut.fi> */
1255 print_operand_address (register FILE *file, register rtx addr)
1257 static const char scales[] = { 'b', 'w', 'd', 0, 'q', };
1258 rtx offset, base, indexexp, tmp;
1260 extern int flag_pic;
1262 if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == POST_DEC)
1264 fprintf (file, "tos");
1271 while (addr != NULL)
1273 if (GET_CODE (addr) == PLUS)
1275 if (GET_CODE (XEXP (addr, 0)) == PLUS)
1277 tmp = XEXP (addr, 1);
1278 addr = XEXP (addr, 0);
1282 tmp = XEXP (addr,0);
1283 addr = XEXP (addr,1);
1291 switch (GET_CODE (tmp))
1305 if (REGNO (tmp) < F0_REGNUM)
1325 if (flag_pic && ! SYMBOL_REF_LOCAL_P (tmp))
1337 if (flag_pic && GET_CODE (tmp) == CONST)
1340 tmp1 = XEXP (tmp,0);
1341 if (GET_CODE (tmp1) != PLUS)
1344 sym = XEXP (tmp1,0);
1345 if (GET_CODE (sym) != SYMBOL_REF)
1348 sym = XEXP (tmp1,1);
1351 off = XEXP (tmp1,1);
1352 if (GET_CODE (sym) == SYMBOL_REF)
1354 if (GET_CODE (off) != CONST_INT)
1357 if (! SYMBOL_REF_LOCAL_P (sym))
1379 offset = gen_rtx_PLUS (SImode, tmp, offset);
1388 offset = const0_rtx;
1391 #ifndef INDEX_RATHER_THAN_BASE
1392 && (flag_pic || TARGET_HIMEM)
1393 && GET_CODE (base) != SYMBOL_REF
1394 && GET_CODE (offset) != CONST_INT
1396 /* This is a re-implementation of the SEQUENT_ADDRESS_BUG fix. */
1398 && !indexexp && GET_CODE (base) == REG
1399 && REG_OK_FOR_INDEX_P (base))
1405 /* now, offset, base and indexexp are set */
1406 #ifndef BASE_REG_NEEDED
1409 #if defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC)
1410 if (GET_CODE (offset) == CONST_INT)
1412 PUT_ABSOLUTE_PREFIX (file);
1416 output_addr_const (file, offset);
1417 if (base) /* base can be (REG ...) or (MEM ...) */
1418 switch (GET_CODE (base))
1420 /* now we must output base. Possible alternatives are:
1424 (pc) (REG ...) used for SYMBOL_REF and LABEL_REF, output
1425 (disp(fp)) (MEM ...) just before possible [rX:y]
1426 (disp(sp)) (MEM ...)
1427 (disp(sb)) (MEM ...)
1430 fprintf (file, "(%s)", ns32k_out_reg_names[REGNO (base)]);
1436 fprintf (file, "(");
1437 output_addr_const (file, base);
1438 fprintf (file, "(sb))");
1441 addr = XEXP (base,0);
1444 while (addr != NULL)
1446 if (GET_CODE (addr) == PLUS)
1448 if (GET_CODE (XEXP (addr, 0)) == PLUS)
1450 tmp = XEXP (addr, 1);
1451 addr = XEXP (addr, 0);
1455 tmp = XEXP (addr, 0);
1456 addr = XEXP (addr, 1);
1464 switch (GET_CODE (tmp))
1474 offset = gen_rtx_PLUS (SImode, tmp, offset);
1483 offset = const0_rtx;
1484 fprintf (file, "(");
1485 output_addr_const (file, offset);
1487 fprintf (file, "(%s)", ns32k_out_reg_names[REGNO (base)]);
1489 fprintf (file, "(sb)");
1492 fprintf (file, ")");
1498 else if (GET_CODE (offset) != CONST_INT)
1499 fprintf (file, "(pc)");
1500 #ifdef BASE_REG_NEEDED
1502 fprintf (file, "(sb)");
1506 #endif /* PC_RELATIVE */
1508 /* now print index if we have one */
1511 if (GET_CODE (indexexp) == MULT)
1513 scale = INTVAL (XEXP (indexexp, 1)) >> 1;
1514 indexexp = XEXP (indexexp, 0);
1518 if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= F0_REGNUM)
1522 fprintf (file, "[%c`%s]",
1524 ns32k_out_reg_names[REGNO (indexexp)]);
1526 fprintf (file, "[%s:%c]",
1527 ns32k_out_reg_names[REGNO (indexexp)],
1533 /* National 32032 shifting is so bad that we can get
1534 better performance in many common cases by using other
1537 output_shift_insn (rtx *operands)
1539 if (GET_CODE (operands[2]) == CONST_INT
1540 && INTVAL (operands[2]) > 0
1541 && INTVAL (operands[2]) <= 3)
1543 if (GET_CODE (operands[0]) == REG)
1545 if (GET_CODE (operands[1]) == REG)
1547 if (REGNO (operands[0]) == REGNO (operands[1]))
1549 if (operands[2] == const1_rtx)
1550 return "addd %0,%0";
1551 else if (INTVAL (operands[2]) == 2)
1552 return "addd %0,%0\n\taddd %0,%0";
1554 if (operands[2] == const1_rtx)
1555 return "movd %1,%0\n\taddd %0,%0";
1557 operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
1558 return "addr %a1,%0";
1560 if (operands[2] == const1_rtx)
1561 return "movd %1,%0\n\taddd %0,%0";
1563 else if (GET_CODE (operands[1]) == REG)
1565 operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
1566 return "addr %a1,%0";
1568 else if (INTVAL (operands[2]) == 1
1569 && GET_CODE (operands[1]) == MEM
1570 && rtx_equal_p (operands [0], operands[1]))
1572 rtx temp = XEXP (operands[1], 0);
1574 if (GET_CODE (temp) == REG
1575 || (GET_CODE (temp) == PLUS
1576 && GET_CODE (XEXP (temp, 0)) == REG
1577 && GET_CODE (XEXP (temp, 1)) == CONST_INT))
1578 return "addd %0,%0";
1580 else return "ashd %2,%0";
1582 return "ashd %2,%0";
1586 output_move_dconst (int n, const char *s)
1590 if (n > -9 && n < 8)
1591 strcpy (r, "movqd ");
1592 else if (n > 0 && n < 256)
1593 strcpy (r, "movzbd ");
1594 else if (n > 0 && n < 65536)
1595 strcpy (r, "movzwd ");
1596 else if (n < 0 && n > -129)
1597 strcpy (r, "movxbd ");
1598 else if (n < 0 && n > -32769)
1599 strcpy (r, "movxwd ");
1601 strcpy (r, "movd ");
1607 ns32k_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
1608 int incoming ATTRIBUTE_UNUSED)
1610 return gen_rtx_REG (Pmode, NS32K_STRUCT_VALUE_REGNUM);
1613 /* Worker function for NOTICE_UPDATE_CC. */
1616 ns32k_notice_update_cc (rtx exp, rtx insn ATTRIBUTE_UNUSED)
1618 if (GET_CODE (exp) == SET)
1620 if (GET_CODE (SET_DEST (exp)) == CC0)
1622 cc_status.flags = 0;
1623 cc_status.value1 = SET_DEST (exp);
1624 cc_status.value2 = SET_SRC (exp);
1626 else if (GET_CODE (SET_SRC (exp)) == CALL)
1630 else if (GET_CODE (SET_DEST (exp)) == REG)
1632 if (cc_status.value1
1633 && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))
1634 cc_status.value1 = 0;
1635 if (cc_status.value2
1636 && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2))
1637 cc_status.value2 = 0;
1639 else if (GET_CODE (SET_DEST (exp)) == MEM)
1644 else if (GET_CODE (exp) == PARALLEL
1645 && GET_CODE (XVECEXP (exp, 0, 0)) == SET)
1647 if (GET_CODE (SET_DEST (XVECEXP (exp, 0, 0))) == CC0)
1649 cc_status.flags = 0;
1650 cc_status.value1 = SET_DEST (XVECEXP (exp, 0, 0));
1651 cc_status.value2 = SET_SRC (XVECEXP (exp, 0, 0));
1653 else if (GET_CODE (SET_DEST (XVECEXP (exp, 0, 0))) == REG)
1655 if (cc_status.value1
1656 && reg_overlap_mentioned_p (SET_DEST (XVECEXP (exp, 0, 0)),
1658 cc_status.value1 = 0;
1659 if (cc_status.value2
1660 && reg_overlap_mentioned_p (SET_DEST (XVECEXP (exp, 0, 0)),
1662 cc_status.value2 = 0;
1664 else if (GET_CODE (SET_DEST (XVECEXP (exp, 0, 0))) == MEM)
1669 else if (GET_CODE (exp) == CALL)
1671 /* all bets are off */
1676 /* nothing happens? CC_STATUS_INIT; */
1678 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
1680 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
1684 /* Implement TARGET_ARG_PARTIAL_BYTES. */
1687 ns32k_arg_partial_bytes (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
1688 tree type, bool named ATTRIBUTE_UNUSED)
1692 if (TARGET_REGPARM && cum < 8)
1696 if (mode == BLKmode)
1697 size = int_size_in_bytes (type);
1699 size = GET_MODE_SIZE (mode);