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. */
24 #include "coretypes.h"
28 #include "hard-reg-set.h"
30 #include "insn-config.h"
31 #include "conditions.h"
33 #include "insn-attr.h"
41 #include "target-def.h"
45 int ns32k_num_files
= 0;
48 /* This duplicates reg_class_contents in reg_class.c, but maybe that isn't
49 initialized in time. Also this is more convenient as an array of ints.
50 We know that HARD_REG_SET fits in an unsigned int */
52 const unsigned int ns32k_reg_class_contents
[N_REG_CLASSES
][1] = REG_CLASS_CONTENTS
;
54 const enum reg_class regclass_map
[FIRST_PSEUDO_REGISTER
] =
56 GENERAL_REGS
, GENERAL_REGS
, GENERAL_REGS
, GENERAL_REGS
,
57 GENERAL_REGS
, GENERAL_REGS
, GENERAL_REGS
, GENERAL_REGS
,
58 FLOAT_REG0
, LONG_FLOAT_REG0
, FLOAT_REGS
, FLOAT_REGS
,
59 FLOAT_REGS
, FLOAT_REGS
, FLOAT_REGS
, FLOAT_REGS
,
60 LONG_REGS
, LONG_REGS
, LONG_REGS
, LONG_REGS
,
61 LONG_REGS
, LONG_REGS
, LONG_REGS
, LONG_REGS
,
62 FRAME_POINTER_REG
, STACK_POINTER_REG
65 static const char *const ns32k_out_reg_names
[] = OUTPUT_REGISTER_NAMES
;
67 static rtx gen_indexed_expr
PARAMS ((rtx
, rtx
, rtx
));
68 static const char *singlemove_string
PARAMS ((rtx
*));
69 static void move_tail
PARAMS ((rtx
[], int, int));
70 static tree ns32k_handle_fntype_attribute
PARAMS ((tree
*, tree
, tree
, int, bool *));
71 const struct attribute_spec ns32k_attribute_table
[];
72 static void ns32k_output_function_prologue
PARAMS ((FILE *, HOST_WIDE_INT
));
73 static void ns32k_output_function_epilogue
PARAMS ((FILE *, HOST_WIDE_INT
));
74 static void ns32k_encode_section_info
PARAMS ((tree
, int));
75 static bool ns32k_rtx_costs
PARAMS ((rtx
, int, int, int *));
76 static int ns32k_address_cost
PARAMS ((rtx
));
78 /* Initialize the GCC target structure. */
79 #undef TARGET_ATTRIBUTE_TABLE
80 #define TARGET_ATTRIBUTE_TABLE ns32k_attribute_table
82 #undef TARGET_ASM_ALIGNED_HI_OP
83 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
86 #undef TARGET_ASM_ALIGNED_SI_OP
87 #define TARGET_ASM_ALIGNED_SI_OP "\t.double\t"
90 #undef TARGET_ASM_FUNCTION_PROLOGUE
91 #define TARGET_ASM_FUNCTION_PROLOGUE ns32k_output_function_prologue
92 #undef TARGET_ASM_FUNCTION_EPILOGUE
93 #define TARGET_ASM_FUNCTION_EPILOGUE ns32k_output_function_epilogue
94 #undef TARGET_ENCODE_SECTION_INFO
95 #define TARGET_ENCODE_SECTION_INFO ns32k_encode_section_info
97 #undef TARGET_RTX_COSTS
98 #define TARGET_RTX_COSTS ns32k_rtx_costs
99 #undef TARGET_ADDRESS_COST
100 #define TARGET_ADDRESS_COST ns32k_address_cost
102 struct gcc_target targetm
= TARGET_INITIALIZER
;
104 /* Generate the assembly code for function entry. FILE is a stdio
105 stream to output the code to. SIZE is an int: how many units of
106 temporary storage to allocate.
108 Refer to the array `regs_ever_live' to determine which registers to
109 save; `regs_ever_live[I]' is nonzero if register number I is ever
110 used in the function. This function is responsible for knowing
111 which registers should not be saved even if used. */
114 * The function prologue for the ns32k is fairly simple.
115 * If a frame pointer is needed (decided in reload.c ?) then
116 * we need assembler of the form
118 * # Save the oldframe pointer, set the new frame pointer, make space
119 * # on the stack and save any general purpose registers necessary
121 * enter [<general purpose regs to save>], <local stack space>
123 * movf fn, tos # Save any floating point registers necessary
127 * If a frame pointer is not needed we need assembler of the form
129 * # Make space on the stack
131 * adjspd <local stack space + 4>
133 * # Save any general purpose registers necessary
135 * save [<general purpose regs to save>]
137 * movf fn, tos # Save any floating point registers necessary
142 #if !defined (MERLIN_TARGET) && !defined (UTEK_ASM)
144 #if defined(IMMEDIATE_PREFIX) && IMMEDIATE_PREFIX
145 #define ADJSP(FILE, N) \
146 fprintf (FILE, "\tadjspd %c%d\n", IMMEDIATE_PREFIX, (N))
148 #define ADJSP(FILE, N) \
149 fprintf (FILE, "\tadjspd %d\n", (N))
153 ns32k_output_function_prologue (file
, size
)
157 register int regno
, g_regs_used
= 0;
158 int used_regs_buf
[8], *bufp
= used_regs_buf
;
159 int used_fregs_buf
[17], *fbufp
= used_fregs_buf
;
161 for (regno
= R0_REGNUM
; regno
< F0_REGNUM
; regno
++)
162 if (regs_ever_live
[regno
]
163 && ! call_used_regs
[regno
])
165 *bufp
++ = regno
; g_regs_used
++;
169 for (; regno
< FRAME_POINTER_REGNUM
; regno
++)
170 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
176 bufp
= used_regs_buf
;
177 if (frame_pointer_needed
)
178 fprintf (file
, "\tenter [");
182 ADJSP (file
, size
+ 4);
183 if (g_regs_used
&& g_regs_used
> 4)
184 fprintf (file
, "\tsave [");
188 fprintf (file
, "\tmovd r%d,tos\n", *bufp
++);
195 fprintf (file
, "r%d", *bufp
++);
200 if (frame_pointer_needed
)
201 fprintf (file
, "],%d\n", size
);
202 else if (g_regs_used
)
203 fprintf (file
, "]\n");
205 fbufp
= used_fregs_buf
;
208 if ((*fbufp
& 1) || (fbufp
[0] != fbufp
[1] - 1))
209 fprintf (file
, "\tmovf %s,tos\n", ns32k_out_reg_names
[*fbufp
++]);
212 fprintf (file
, "\tmovl %s,tos\n",
213 ns32k_out_reg_names
[fbufp
[0]]);
218 if (flag_pic
&& current_function_uses_pic_offset_table
)
220 fprintf (file
, "\tsprd sb,tos\n");
223 fprintf (file
, "\taddr __GLOBAL_OFFSET_TABLE_(pc),tos\n");
224 fprintf (file
, "\tlprd sb,tos\n");
228 fprintf (file
, "\taddr __GLOBAL_OFFSET_TABLE_(pc),r0\n");
229 fprintf (file
, "\tlprd sb,r0\n");
234 #else /* MERLIN_TARGET || UTEK_ASM */
236 /* This differs from the standard one above in printing a bitmask
237 rather than a register list in the enter or save instruction. */
240 ns32k_output_function_prologue (file
, size
)
244 register int regno
, g_regs_used
= 0;
245 int used_regs_buf
[8], *bufp
= used_regs_buf
;
246 int used_fregs_buf
[8], *fbufp
= used_fregs_buf
;
248 for (regno
= 0; regno
< 8; regno
++)
249 if (regs_ever_live
[regno
]
250 && ! call_used_regs
[regno
])
252 *bufp
++ = regno
; g_regs_used
++;
256 for (; regno
< 16; regno
++)
257 if (regs_ever_live
[regno
] && !call_used_regs
[regno
]) {
262 bufp
= used_regs_buf
;
263 if (frame_pointer_needed
)
264 fprintf (file
, "\tenter ");
265 else if (g_regs_used
)
266 fprintf (file
, "\tsave ");
268 if (frame_pointer_needed
|| g_regs_used
)
272 mask
|= 1 << *bufp
++;
273 fprintf (file
, "$0x%x", (int) mask
& 0xff);
276 if (frame_pointer_needed
)
278 fprintf (file
, ",$%d\n", size
);
280 fprintf (file
, ",%d\n", size
);
282 else if (g_regs_used
)
283 fprintf (file
, "\n");
285 fbufp
= used_fregs_buf
;
288 if ((*fbufp
& 1) || (fbufp
[0] != fbufp
[1] - 1))
289 fprintf (file
, "\tmovf f%d,tos\n", *fbufp
++ - 8);
292 fprintf (file
, "\tmovl f%d,tos\n", fbufp
[0] - 8);
298 #endif /* MERLIN_TARGET || UTEK_ASM */
300 /* This function generates the assembly code for function exit,
301 on machines that need it.
303 The function epilogue should not depend on the current stack pointer,
304 if EXIT_IGNORE_STACK is nonzero. That doesn't apply here.
306 If a frame pointer is needed (decided in reload.c ?) then
307 we need assembler of the form
309 movf tos, fn # Restore any saved floating point registers
313 # Restore any saved general purpose registers, restore the stack
314 # pointer from the frame pointer, restore the old frame pointer.
315 exit [<general purpose regs to save>]
317 If a frame pointer is not needed we need assembler of the form
318 # Restore any general purpose registers saved
320 movf tos, fn # Restore any saved floating point registers
324 restore [<general purpose regs to save>]
326 # reclaim space allocated on stack
328 adjspd <-(local stack space + 4)> */
330 #if !defined (MERLIN_TARGET) && !defined (UTEK_ASM)
333 ns32k_output_function_epilogue (file
, size
)
337 register int regno
, g_regs_used
= 0, f_regs_used
= 0;
338 int used_regs_buf
[8], *bufp
= used_regs_buf
;
339 int used_fregs_buf
[17], *fbufp
= used_fregs_buf
;
341 if (flag_pic
&& current_function_uses_pic_offset_table
)
342 fprintf (file
, "\tlprd sb,tos\n");
345 for (regno
= F0_REGNUM
; regno
< FRAME_POINTER_REGNUM
; regno
++)
346 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
348 *fbufp
++ = regno
; f_regs_used
++;
352 for (regno
= 0; regno
< F0_REGNUM
; regno
++)
353 if (regs_ever_live
[regno
]
354 && ! call_used_regs
[regno
])
356 *bufp
++ = regno
; g_regs_used
++;
359 while (fbufp
> used_fregs_buf
)
361 if ((*fbufp
& 1) && fbufp
[0] == fbufp
[-1] + 1)
363 fprintf (file
, "\tmovl tos,%s\n",
364 ns32k_out_reg_names
[fbufp
[-1]]);
367 else fprintf (file
, "\tmovf tos,%s\n", ns32k_out_reg_names
[*fbufp
--]);
370 if (frame_pointer_needed
)
371 fprintf (file
, "\texit [");
374 if (g_regs_used
&& g_regs_used
> 4)
375 fprintf (file
, "\trestore [");
378 while (bufp
> used_regs_buf
)
379 fprintf (file
, "\tmovd tos,r%d\n", *--bufp
);
384 while (bufp
> used_regs_buf
)
386 fprintf (file
, "r%d", *--bufp
);
387 if (bufp
> used_regs_buf
)
391 if (g_regs_used
|| frame_pointer_needed
)
392 fprintf (file
, "]\n");
394 if (size
&& !frame_pointer_needed
)
395 ADJSP (file
, -(size
+ 4));
397 if (current_function_pops_args
)
398 fprintf (file
, "\tret %d\n", current_function_pops_args
);
400 fprintf (file
, "\tret 0\n");
403 #else /* MERLIN_TARGET || UTEK_ASM */
405 /* This differs from the standard one above in printing a bitmask
406 rather than a register list in the exit or restore instruction. */
409 ns32k_output_function_epilogue (file
, size
)
411 HOST_WIDE_INT size ATTRIBUTE_UNUSED
;
413 register int regno
, g_regs_used
= 0, f_regs_used
= 0;
414 int used_regs_buf
[8], *bufp
= used_regs_buf
;
415 int used_fregs_buf
[8], *fbufp
= used_fregs_buf
;
418 for (regno
= 8; regno
< 16; regno
++)
419 if (regs_ever_live
[regno
] && !call_used_regs
[regno
]) {
420 *fbufp
++ = regno
; f_regs_used
++;
424 for (regno
= 0; regno
< 8; regno
++)
425 if (regs_ever_live
[regno
]
426 && ! call_used_regs
[regno
])
428 *bufp
++ = regno
; g_regs_used
++;
431 while (fbufp
> used_fregs_buf
)
433 if ((*fbufp
& 1) && fbufp
[0] == fbufp
[-1] + 1)
435 fprintf (file
, "\tmovl tos,f%d\n", fbufp
[-1] - 8);
438 else fprintf (file
, "\tmovf tos,f%d\n", *fbufp
-- - 8);
441 if (frame_pointer_needed
)
442 fprintf (file
, "\texit ");
443 else if (g_regs_used
)
444 fprintf (file
, "\trestore ");
446 if (g_regs_used
|| frame_pointer_needed
)
450 while (bufp
> used_regs_buf
)
452 /* Utek assembler takes care of reversing this */
453 mask
|= 1 << *--bufp
;
455 fprintf (file
, "$0x%x\n", (int) mask
& 0xff);
459 if (current_function_pops_args
)
460 fprintf (file
, "\tret $%d\n", current_function_pops_args
);
462 fprintf (file
, "\tret $0\n");
464 if (current_function_pops_args
)
465 fprintf (file
, "\tret %d\n", current_function_pops_args
);
467 fprintf (file
, "\tret 0\n");
471 #endif /* MERLIN_TARGET || UTEK_ASM */
473 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */
475 hard_regno_mode_ok (regno
, mode
)
477 enum machine_mode mode
;
479 int size
= GET_MODE_UNIT_SIZE (mode
);
481 if (FLOAT_MODE_P (mode
))
483 if (size
== UNITS_PER_WORD
&& regno
< L1_REGNUM
)
485 if (size
== UNITS_PER_WORD
* 2
486 && (((regno
& 1) == 0 && regno
< FRAME_POINTER_REGNUM
)))
490 if (size
== UNITS_PER_WORD
* 2
491 && (regno
& 1) == 0 && regno
< F0_REGNUM
)
493 if (size
<= UNITS_PER_WORD
494 && (regno
< F0_REGNUM
|| regno
== FRAME_POINTER_REGNUM
495 || regno
== STACK_POINTER_REGNUM
))
501 ns32k_rtx_costs (x
, code
, outer_code
, total
)
503 int code
, outer_code ATTRIBUTE_UNUSED
;
509 if (INTVAL (x
) <= 7 && INTVAL (x
) >= -8)
511 else if (INTVAL (x
) < 0x2000 && INTVAL (x
) >= -0x2000)
532 int register_move_cost (CLASS1
, CLASS2
)
533 enum reg_class CLASS1
;
534 enum reg_class CLASS2
;
536 if (CLASS1
== NO_REGS
|| CLASS2
== NO_REGS
)
538 if ((SUBSET_P (CLASS1
, FP_REGS
) && !SUBSET_P (CLASS2
, FP_REGS
))
539 || (!SUBSET_P (CLASS1
, FP_REGS
) && SUBSET_P (CLASS2
, FP_REGS
)))
541 if (((CLASS1
) == STACK_POINTER_REG
&& !SUBSET_P (CLASS2
,GENERAL_REGS
))
542 || ((CLASS2
) == STACK_POINTER_REG
&& !SUBSET_P (CLASS1
,GENERAL_REGS
)))
544 if (((CLASS1
) == FRAME_POINTER_REG
&& !SUBSET_P (CLASS2
,GENERAL_REGS
))
545 || ((CLASS2
) == FRAME_POINTER_REG
&& !SUBSET_P (CLASS1
,GENERAL_REGS
)))
551 /* We made the insn definitions copy from floating point to general
552 registers via the stack. */
553 int secondary_memory_needed (CLASS1
, CLASS2
, M
)
554 enum reg_class CLASS1
;
555 enum reg_class CLASS2
;
558 int ret
= ((SUBSET_P (CLASS1
, FP_REGS
) && !SUBSET_P (CLASS2
, FP_REGS
))
559 || (!SUBSET_P (CLASS1
, FP_REGS
) && SUBSET_P (CLASS2
, FP_REGS
)));
565 /* TARGET_ADDRESS_COST calls this. This function is not optimal
566 for the 32032 & 32332, but it probably is better than
570 ns32k_address_cost (operand
)
575 switch (GET_CODE (operand
))
586 if (INTVAL (operand
) <= 7 && INTVAL (operand
) >= -8)
588 if (INTVAL (operand
) < 0x2000 && INTVAL (operand
) >= -0x2000)
603 cost
+= ns32k_address_cost (XEXP (operand
, 0)) + 3;
610 cost
+= ns32k_address_cost (XEXP (operand
, 0));
611 cost
+= ns32k_address_cost (XEXP (operand
, 1));
621 /* Return the register class of a scratch register needed to copy IN into
622 or out of a register in CLASS in MODE. If it can be done directly,
623 NO_REGS is returned. */
626 secondary_reload_class (class, mode
, in
)
627 enum reg_class
class;
628 enum machine_mode mode ATTRIBUTE_UNUSED
;
631 int regno
= true_regnum (in
);
633 if (regno
>= FIRST_PSEUDO_REGISTER
)
636 if ((class == FRAME_POINTER_REG
&& regno
== STACK_POINTER_REGNUM
)
637 || ( class == STACK_POINTER_REG
&& regno
== FRAME_POINTER_REGNUM
))
643 /* Generate the rtx that comes from an address expression in the md file */
644 /* The expression to be build is BASE[INDEX:SCALE]. To recognize this,
645 scale must be converted from an exponent (from ASHIFT) to a
646 multiplier (for MULT). */
649 gen_indexed_expr (base
, index
, scale
)
650 rtx base
, index
, scale
;
654 /* This generates an invalid addressing mode, if BASE is
655 fp or sp. This is handled by PRINT_OPERAND_ADDRESS. */
656 if (GET_CODE (base
) != REG
&& GET_CODE (base
) != CONST_INT
)
657 base
= gen_rtx_MEM (SImode
, base
);
658 addr
= gen_rtx_MULT (SImode
, index
,
659 GEN_INT (1 << INTVAL (scale
)));
660 addr
= gen_rtx_PLUS (SImode
, base
, addr
);
665 /* Split one or more DImode RTL references into pairs of SImode
666 references. The RTL can be REG, offsettable MEM, integer constant, or
667 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
668 split and "num" is its length. lo_half and hi_half are output arrays
669 that parallel "operands". */
672 split_di (operands
, num
, lo_half
, hi_half
)
675 rtx lo_half
[], hi_half
[];
679 if (GET_CODE (operands
[num
]) == REG
)
681 lo_half
[num
] = gen_rtx_REG (SImode
, REGNO (operands
[num
]));
682 hi_half
[num
] = gen_rtx_REG (SImode
, REGNO (operands
[num
]) + 1);
684 else if (CONSTANT_P (operands
[num
]))
686 split_double (operands
[num
], &lo_half
[num
], &hi_half
[num
]);
688 else if (offsettable_memref_p (operands
[num
]))
690 lo_half
[num
] = operands
[num
];
691 hi_half
[num
] = adjust_address (operands
[num
], SImode
, 4);
698 /* Return the best assembler insn template
699 for moving operands[1] into operands[0] as a fullword. */
702 singlemove_string (operands
)
705 if (GET_CODE (operands
[1]) == CONST_INT
706 && INTVAL (operands
[1]) <= 7
707 && INTVAL (operands
[1]) >= -8)
708 return "movqd %1,%0";
713 output_move_double (operands
)
716 enum anon1
{ REGOP
, OFFSOP
, PUSHOP
, CNSTOP
, RNDOP
} optype0
, optype1
;
719 /* First classify both operands. */
721 if (REG_P (operands
[0]))
723 else if (offsettable_memref_p (operands
[0]))
725 else if (GET_CODE (XEXP (operands
[0], 0)) == PRE_DEC
)
730 if (REG_P (operands
[1]))
732 else if (CONSTANT_P (operands
[1])
733 || GET_CODE (operands
[1]) == CONST_DOUBLE
)
735 else if (offsettable_memref_p (operands
[1]))
737 else if (GET_CODE (XEXP (operands
[1], 0)) == PRE_DEC
)
742 /* Check for the cases that the operand constraints are not
743 supposed to allow to happen. Abort if we get one,
744 because generating code for these cases is painful. */
746 if (optype0
== RNDOP
|| optype1
== RNDOP
)
749 /* Ok, we can do one word at a time.
750 Normally we do the low-numbered word first,
751 but if either operand is autodecrementing then we
752 do the high-numbered word first.
754 In either case, set up in LATEHALF the operands to use
755 for the high-numbered word and in some cases alter the
756 operands in OPERANDS to be suitable for the low-numbered word. */
758 if (optype0
== REGOP
)
759 latehalf
[0] = gen_rtx_REG (SImode
, REGNO (operands
[0]) + 1);
760 else if (optype0
== OFFSOP
)
761 latehalf
[0] = adjust_address (operands
[0], SImode
, 4);
763 latehalf
[0] = operands
[0];
765 if (optype1
== REGOP
)
766 latehalf
[1] = gen_rtx_REG (SImode
, REGNO (operands
[1]) + 1);
767 else if (optype1
== OFFSOP
)
768 latehalf
[1] = adjust_address (operands
[1], SImode
, 4);
769 else if (optype1
== CNSTOP
)
770 split_double (operands
[1], &operands
[1], &latehalf
[1]);
772 latehalf
[1] = operands
[1];
774 /* If insn is effectively movd N(sp),tos then we will do the
775 high word first. We should use the adjusted operand 1 (which is N+4(sp))
776 for the low word as well, to compensate for the first decrement of sp.
777 Given this, it doesn't matter which half we do "first". */
778 if (optype0
== PUSHOP
779 && REGNO (XEXP (XEXP (operands
[0], 0), 0)) == STACK_POINTER_REGNUM
780 && reg_overlap_mentioned_p (stack_pointer_rtx
, operands
[1]))
781 operands
[1] = latehalf
[1];
783 /* If one or both operands autodecrementing,
784 do the two words, high-numbered first. */
785 else if (optype0
== PUSHOP
|| optype1
== PUSHOP
)
787 output_asm_insn (singlemove_string (latehalf
), latehalf
);
788 return singlemove_string (operands
);
791 /* If the first move would clobber the source of the second one,
792 do them in the other order. */
794 /* Overlapping registers. */
795 if (optype0
== REGOP
&& optype1
== REGOP
796 && REGNO (operands
[0]) == REGNO (latehalf
[1]))
799 output_asm_insn (singlemove_string (latehalf
), latehalf
);
800 /* Do low-numbered word. */
801 return singlemove_string (operands
);
803 /* Loading into a register which overlaps a register used in the address. */
804 else if (optype0
== REGOP
&& optype1
!= REGOP
805 && reg_overlap_mentioned_p (operands
[0], operands
[1]))
807 if (reg_mentioned_p (operands
[0], XEXP (operands
[1], 0))
808 && reg_mentioned_p (latehalf
[0], XEXP (operands
[1], 0)))
810 /* If both halves of dest are used in the src memory address,
811 load the destination address into the low reg (operands[0]).
812 Then it works to load latehalf first. */
814 xops
[0] = XEXP (operands
[1], 0);
815 xops
[1] = operands
[0];
816 output_asm_insn ("addr %a0,%1", xops
);
817 operands
[1] = gen_rtx_MEM (DImode
, operands
[0]);
818 latehalf
[1] = adjust_address (operands
[1], SImode
, 4);
819 /* The first half has the overlap, Do the late half first. */
820 output_asm_insn (singlemove_string (latehalf
), latehalf
);
822 return singlemove_string (operands
);
824 if (reg_mentioned_p (operands
[0], XEXP (operands
[1], 0)))
826 /* The first half has the overlap, Do the late half first. */
827 output_asm_insn (singlemove_string (latehalf
), latehalf
);
829 return singlemove_string (operands
);
833 /* Normal case. Do the two words, low-numbered first. */
835 output_asm_insn (singlemove_string (operands
), operands
);
837 operands
[0] = latehalf
[0];
838 operands
[1] = latehalf
[1];
839 return singlemove_string (operands
);
843 #define MAX_UNALIGNED_COPY (32)
844 /* Expand string/block move operations.
846 operands[0] is the pointer to the destination.
847 operands[1] is the pointer to the source.
848 operands[2] is the number of bytes to move.
849 operands[3] is the alignment. */
852 move_tail (operands
, bytes
, offset
)
859 emit_move_insn (adjust_address (operands
[0], HImode
, offset
),
860 adjust_address (operands
[1], HImode
, offset
));
864 emit_move_insn (adjust_address (operands
[0], QImode
, offset
),
865 adjust_address (operands
[1], QImode
, offset
));
869 expand_block_move (operands
)
872 rtx bytes_rtx
= operands
[2];
873 rtx align_rtx
= operands
[3];
874 int constp
= (GET_CODE (bytes_rtx
) == CONST_INT
);
875 int bytes
= (constp
? INTVAL (bytes_rtx
) : 0);
876 int align
= INTVAL (align_rtx
);
877 rtx src_reg
= gen_rtx_REG (Pmode
, 1);
878 rtx dest_reg
= gen_rtx_REG (Pmode
, 2);
879 rtx count_reg
= gen_rtx_REG (SImode
, 0);
881 if (constp
&& bytes
<= 0)
884 if (constp
&& bytes
< 20)
886 int words
= bytes
>> 2;
890 if (words
< 3 || flag_unroll_loops
)
894 for (; words
; words
--, offset
+= 4)
895 emit_move_insn (adjust_address (operands
[0], SImode
, offset
),
896 adjust_address (operands
[1], SImode
, offset
));
900 /* Use movmd. It is slower than multiple movd's but more
901 compact. It is also slower than movsd for large copies
902 but causes less registers reloading so is better than movsd
905 dest
= copy_addr_to_reg (XEXP (operands
[0], 0));
906 src
= copy_addr_to_reg (XEXP (operands
[1], 0));
908 emit_insn (gen_movstrsi2(dest
, src
, GEN_INT (words
)));
911 move_tail (operands
, bytes
& 3, bytes
& ~3);
915 if (align
> UNITS_PER_WORD
)
916 align
= UNITS_PER_WORD
;
918 /* Move the address into scratch registers. */
919 emit_insn (gen_rtx_CLOBBER (VOIDmode
, dest_reg
));
920 emit_move_insn (dest_reg
, XEXP (operands
[0], 0));
921 operands
[0] = gen_rtx_MEM (SImode
, dest_reg
);
922 emit_insn (gen_rtx_CLOBBER (VOIDmode
, src_reg
));
923 emit_move_insn (src_reg
, XEXP (operands
[1], 0));
924 operands
[1] = gen_rtx_MEM (SImode
, src_reg
);
925 emit_insn (gen_rtx_CLOBBER (VOIDmode
, count_reg
));
927 if (constp
&& (align
== UNITS_PER_WORD
|| bytes
< MAX_UNALIGNED_COPY
))
929 /* constant no of bytes and aligned or small enough copy to not bother
930 * aligning. Emit insns to copy by words.
934 emit_move_insn (count_reg
, GEN_INT (bytes
>> 2));
935 emit_insn (gen_movstrsi1 (GEN_INT (4)));
937 /* insns to copy rest */
938 move_tail (operands
, bytes
& 3, 0);
940 else if (align
== UNITS_PER_WORD
)
942 /* insns to copy by words */
943 emit_insn (gen_lshrsi3 (count_reg
, bytes_rtx
, GEN_INT (2)));
944 emit_insn (gen_movstrsi1 (GEN_INT (4)));
947 move_tail (operands
, bytes
& 3, 0);
951 /* insns to copy rest */
952 emit_insn (gen_andsi3 (count_reg
, bytes_rtx
, GEN_INT (3)));
953 emit_insn (gen_movstrsi1 (const1_rtx
));
958 /* Not aligned and we may have a lot to copy so it is worth
961 rtx aligned_label
= gen_label_rtx ();
964 bytes_reg
= copy_to_mode_reg (SImode
, bytes_rtx
);
967 /* Emit insns to test and skip over the alignment if it is
968 * not worth it. This doubles as a test to ensure that the alignment
969 * operation can't copy too many bytes
971 emit_insn (gen_cmpsi (bytes_reg
, GEN_INT (MAX_UNALIGNED_COPY
)));
972 emit_jump_insn (gen_blt (aligned_label
));
975 /* Emit insns to do alignment at run time */
976 emit_insn (gen_negsi2 (count_reg
, src_reg
));
977 emit_insn (gen_andsi3 (count_reg
, count_reg
, GEN_INT (3)));
978 emit_insn (gen_subsi3 (bytes_reg
, bytes_reg
, count_reg
));
979 emit_insn (gen_movstrsi1 (const1_rtx
));
981 emit_label (aligned_label
);
983 /* insns to copy by words */
984 emit_insn (gen_lshrsi3 (count_reg
, bytes_reg
, GEN_INT (2)));
985 emit_insn (gen_movstrsi1 (GEN_INT (4)));
987 /* insns to copy rest */
988 emit_insn (gen_andsi3 (count_reg
, bytes_reg
, GEN_INT (3)));
989 emit_insn (gen_movstrsi1 (const1_rtx
));
994 /* Returns 1 if OP contains a global symbol reference */
997 global_symbolic_reference_mentioned_p (op
, f
)
1001 register const char *fmt
;
1004 if (GET_CODE (op
) == SYMBOL_REF
)
1006 if (! SYMBOL_REF_FLAG (op
))
1011 else if (f
&& GET_CODE (op
) != CONST
)
1014 fmt
= GET_RTX_FORMAT (GET_CODE (op
));
1015 for (i
= GET_RTX_LENGTH (GET_CODE (op
)) - 1; i
>= 0; i
--)
1021 for (j
= XVECLEN (op
, i
) - 1; j
>= 0; j
--)
1022 if (global_symbolic_reference_mentioned_p (XVECEXP (op
, i
, j
), 0))
1025 else if (fmt
[i
] == 'e'
1026 && global_symbolic_reference_mentioned_p (XEXP (op
, i
), 0))
1034 /* Returns 1 if OP contains a symbol reference */
1037 symbolic_reference_mentioned_p (op
)
1040 register const char *fmt
;
1043 if (GET_CODE (op
) == SYMBOL_REF
|| GET_CODE (op
) == LABEL_REF
)
1046 fmt
= GET_RTX_FORMAT (GET_CODE (op
));
1047 for (i
= GET_RTX_LENGTH (GET_CODE (op
)) - 1; i
>= 0; i
--)
1053 for (j
= XVECLEN (op
, i
) - 1; j
>= 0; j
--)
1054 if (symbolic_reference_mentioned_p (XVECEXP (op
, i
, j
)))
1057 else if (fmt
[i
] == 'e' && symbolic_reference_mentioned_p (XEXP (op
, i
)))
1064 /* Table of machine-specific attributes. */
1066 const struct attribute_spec ns32k_attribute_table
[] =
1068 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
1069 /* Stdcall attribute says callee is responsible for popping arguments
1070 if they are not variable. */
1071 { "stdcall", 0, 0, false, true, true, ns32k_handle_fntype_attribute
},
1072 /* Cdecl attribute says the callee is a normal C declaration */
1073 { "cdecl", 0, 0, false, true, true, ns32k_handle_fntype_attribute
},
1074 { NULL
, 0, 0, false, false, false, NULL
}
1077 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1078 arguments as in struct attribute_spec.handler. */
1080 ns32k_handle_fntype_attribute (node
, name
, args
, flags
, no_add_attrs
)
1083 tree args ATTRIBUTE_UNUSED
;
1084 int flags ATTRIBUTE_UNUSED
;
1087 if (TREE_CODE (*node
) != FUNCTION_TYPE
1088 && TREE_CODE (*node
) != FIELD_DECL
1089 && TREE_CODE (*node
) != TYPE_DECL
)
1091 warning ("`%s' attribute only applies to functions",
1092 IDENTIFIER_POINTER (name
));
1093 *no_add_attrs
= true;
1100 /* Value is the number of bytes of arguments automatically
1101 popped when returning from a subroutine call.
1102 FUNDECL is the declaration node of the function (as a tree),
1103 FUNTYPE is the data type of the function (as a tree),
1104 or for a library call it is an identifier node for the subroutine name.
1105 SIZE is the number of bytes of arguments passed on the stack.
1107 On the ns32k, the RET insn may be used to pop them if the number
1108 of args is fixed, but if the number is variable then the caller
1109 must pop them all. RET can't be used for library calls now
1110 because the library is compiled with the Unix compiler.
1111 Use of RET is a selectable option, since it is incompatible with
1112 standard Unix calling sequences. If the option is not selected,
1113 the caller must always pop the args.
1115 The attribute stdcall is equivalent to RET on a per module basis. */
1118 ns32k_return_pops_args (fundecl
, funtype
, size
)
1119 tree fundecl ATTRIBUTE_UNUSED
;
1123 int rtd
= TARGET_RTD
;
1125 if (TREE_CODE (funtype
) == IDENTIFIER_NODE
)
1126 return rtd
? size
: 0;
1128 /* Cdecl functions override -mrtd, and never pop the stack */
1129 if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype
)))
1132 /* Stdcall functions will pop the stack if not variable args */
1133 if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype
)))
1138 if (TYPE_ARG_TYPES (funtype
) == NULL_TREE
1139 || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype
))) == void_type_node
))
1146 /* PRINT_OPERAND is defined to call this function,
1147 which is easier to debug than putting all the code in
1148 a macro definition in ns32k.h. */
1150 /* XXX time 12% of cpu time is in fprintf for non optimizing */
1152 print_operand (file
, x
, code
)
1158 PUT_IMMEDIATE_PREFIX (file
);
1159 else if (code
== '?')
1160 PUT_EXTERNAL_PREFIX (file
);
1161 else if (GET_CODE (x
) == REG
)
1162 fprintf (file
, "%s", ns32k_out_reg_names
[REGNO (x
)]);
1163 else if (GET_CODE (x
) == MEM
)
1165 output_address (XEXP (x
, 0));
1167 else if (GET_CODE (x
) == CONST_DOUBLE
&& GET_MODE (x
) != VOIDmode
)
1171 REAL_VALUE_FROM_CONST_DOUBLE (r
, x
);
1172 PUT_IMMEDIATE_PREFIX (file
);
1173 if (GET_MODE (x
) == DFmode
)
1176 /* Sequent likes its floating point constants as integers */
1178 REAL_VALUE_TO_TARGET_DOUBLE (r
, l
);
1179 fprintf (file
, "0Dx%08x%08x",
1180 l
[!WORDS_BIG_ENDIAN
], l
[WORDS_BIG_ENDIAN
]);
1183 real_to_decimal (s
, &r
, sizeof (s
), 0, 1);
1185 fprintf (file
, "0f%s", s
);
1187 fprintf (file
, "0d%s", s
);
1195 REAL_VALUE_TO_TARGET_SINGLE (r
, l
);
1196 fprintf (file
, "0Fx%08lx", l
);
1199 real_to_decimal (s
, &r
, sizeof (s
), 0, 1);
1200 fprintf (file
, "0f%s", s
);
1207 && GET_CODE (x
) == CONST
1208 && symbolic_reference_mentioned_p (x
))
1210 fprintf (stderr
, "illegal constant for pic-mode: \n");
1211 print_rtl (stderr
, x
);
1212 fprintf (stderr
, "\nGET_CODE (x) == %d, CONST == %d, symbolic_reference_mentioned_p (x) == %d\n",
1213 GET_CODE (x
), CONST
, symbolic_reference_mentioned_p (x
));
1217 && (GET_CODE (x
) == SYMBOL_REF
|| GET_CODE (x
) == LABEL_REF
))
1219 output_addr_const (file
, x
);
1220 fprintf (file
, "(sb)");
1224 #ifdef NO_IMMEDIATE_PREFIX_IF_SYMBOLIC
1225 if (GET_CODE (x
) == CONST_INT
)
1227 PUT_IMMEDIATE_PREFIX (file
);
1228 output_addr_const (file
, x
);
1233 /* PRINT_OPERAND_ADDRESS is defined to call this function,
1234 which is easier to debug than putting all the code in
1235 a macro definition in ns32k.h . */
1237 /* Completely rewritten to get this to work with Gas for PC532 Mach.
1238 This function didn't work and I just wasn't able (nor very willing) to
1239 figure out how it worked.
1240 90-11-25 Tatu Yl|nen <ylo@cs.hut.fi> */
1243 print_operand_address (file
, addr
)
1244 register FILE *file
;
1247 static const char scales
[] = { 'b', 'w', 'd', 0, 'q', };
1248 rtx offset
, base
, indexexp
, tmp
;
1250 extern int flag_pic
;
1252 if (GET_CODE (addr
) == PRE_DEC
|| GET_CODE (addr
) == POST_DEC
)
1254 fprintf (file
, "tos");
1261 while (addr
!= NULL
)
1263 if (GET_CODE (addr
) == PLUS
)
1265 if (GET_CODE (XEXP (addr
, 0)) == PLUS
)
1267 tmp
= XEXP (addr
, 1);
1268 addr
= XEXP (addr
, 0);
1272 tmp
= XEXP (addr
,0);
1273 addr
= XEXP (addr
,1);
1281 switch (GET_CODE (tmp
))
1295 if (REGNO (tmp
) < F0_REGNUM
)
1315 if (flag_pic
&& ! CONSTANT_POOL_ADDRESS_P (tmp
)
1316 && ! SYMBOL_REF_FLAG (tmp
))
1328 if (flag_pic
&& GET_CODE (tmp
) == CONST
)
1331 tmp1
= XEXP (tmp
,0);
1332 if (GET_CODE (tmp1
) != PLUS
)
1335 sym
= XEXP (tmp1
,0);
1336 if (GET_CODE (sym
) != SYMBOL_REF
)
1339 sym
= XEXP (tmp1
,1);
1342 off
= XEXP (tmp1
,1);
1343 if (GET_CODE (sym
) == SYMBOL_REF
)
1345 if (GET_CODE (off
) != CONST_INT
)
1348 if (CONSTANT_POOL_ADDRESS_P (sym
)
1349 || SYMBOL_REF_FLAG (sym
))
1351 SYMBOL_REF_FLAG (tmp
) = 1;
1375 offset
= gen_rtx_PLUS (SImode
, tmp
, offset
);
1384 offset
= const0_rtx
;
1387 #ifndef INDEX_RATHER_THAN_BASE
1388 && (flag_pic
|| TARGET_HIMEM
)
1389 && GET_CODE (base
) != SYMBOL_REF
1390 && GET_CODE (offset
) != CONST_INT
1392 /* This is a re-implementation of the SEQUENT_ADDRESS_BUG fix. */
1394 && !indexexp
&& GET_CODE (base
) == REG
1395 && REG_OK_FOR_INDEX_P (base
))
1401 /* now, offset, base and indexexp are set */
1402 #ifndef BASE_REG_NEEDED
1405 #if defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC)
1406 if (GET_CODE (offset
) == CONST_INT
)
1408 PUT_ABSOLUTE_PREFIX (file
);
1412 output_addr_const (file
, offset
);
1413 if (base
) /* base can be (REG ...) or (MEM ...) */
1414 switch (GET_CODE (base
))
1416 /* now we must output base. Possible alternatives are:
1420 (pc) (REG ...) used for SYMBOL_REF and LABEL_REF, output
1421 (disp(fp)) (MEM ...) just before possible [rX:y]
1422 (disp(sp)) (MEM ...)
1423 (disp(sb)) (MEM ...)
1426 fprintf (file
, "(%s)", ns32k_out_reg_names
[REGNO (base
)]);
1432 fprintf (file
, "(");
1433 output_addr_const (file
, base
);
1434 fprintf (file
, "(sb))");
1437 addr
= XEXP (base
,0);
1440 while (addr
!= NULL
)
1442 if (GET_CODE (addr
) == PLUS
)
1444 if (GET_CODE (XEXP (addr
, 0)) == PLUS
)
1446 tmp
= XEXP (addr
, 1);
1447 addr
= XEXP (addr
, 0);
1451 tmp
= XEXP (addr
, 0);
1452 addr
= XEXP (addr
, 1);
1460 switch (GET_CODE (tmp
))
1470 offset
= gen_rtx_PLUS (SImode
, tmp
, offset
);
1479 offset
= const0_rtx
;
1480 fprintf (file
, "(");
1481 output_addr_const (file
, offset
);
1483 fprintf (file
, "(%s)", ns32k_out_reg_names
[REGNO (base
)]);
1485 fprintf (file
, "(sb)");
1488 fprintf (file
, ")");
1494 else if (GET_CODE (offset
) != CONST_INT
)
1495 fprintf (file
, "(pc)");
1496 #ifdef BASE_REG_NEEDED
1498 fprintf (file
, "(sb)");
1502 #endif /* PC_RELATIVE */
1504 /* now print index if we have one */
1507 if (GET_CODE (indexexp
) == MULT
)
1509 scale
= INTVAL (XEXP (indexexp
, 1)) >> 1;
1510 indexexp
= XEXP (indexexp
, 0);
1514 if (GET_CODE (indexexp
) != REG
|| REGNO (indexexp
) >= F0_REGNUM
)
1518 fprintf (file
, "[%c`%s]",
1520 ns32k_out_reg_names
[REGNO (indexexp
)]);
1522 fprintf (file
, "[%s:%c]",
1523 ns32k_out_reg_names
[REGNO (indexexp
)],
1529 /* National 32032 shifting is so bad that we can get
1530 better performance in many common cases by using other
1533 output_shift_insn (operands
)
1536 if (GET_CODE (operands
[2]) == CONST_INT
1537 && INTVAL (operands
[2]) > 0
1538 && INTVAL (operands
[2]) <= 3)
1540 if (GET_CODE (operands
[0]) == REG
)
1542 if (GET_CODE (operands
[1]) == REG
)
1544 if (REGNO (operands
[0]) == REGNO (operands
[1]))
1546 if (operands
[2] == const1_rtx
)
1547 return "addd %0,%0";
1548 else if (INTVAL (operands
[2]) == 2)
1549 return "addd %0,%0\n\taddd %0,%0";
1551 if (operands
[2] == const1_rtx
)
1552 return "movd %1,%0\n\taddd %0,%0";
1554 operands
[1] = gen_indexed_expr (const0_rtx
, operands
[1], operands
[2]);
1555 return "addr %a1,%0";
1557 if (operands
[2] == const1_rtx
)
1558 return "movd %1,%0\n\taddd %0,%0";
1560 else if (GET_CODE (operands
[1]) == REG
)
1562 operands
[1] = gen_indexed_expr (const0_rtx
, operands
[1], operands
[2]);
1563 return "addr %a1,%0";
1565 else if (INTVAL (operands
[2]) == 1
1566 && GET_CODE (operands
[1]) == MEM
1567 && rtx_equal_p (operands
[0], operands
[1]))
1569 rtx temp
= XEXP (operands
[1], 0);
1571 if (GET_CODE (temp
) == REG
1572 || (GET_CODE (temp
) == PLUS
1573 && GET_CODE (XEXP (temp
, 0)) == REG
1574 && GET_CODE (XEXP (temp
, 1)) == CONST_INT
))
1575 return "addd %0,%0";
1577 else return "ashd %2,%0";
1579 return "ashd %2,%0";
1583 output_move_dconst (n
, s
)
1589 if (n
> -9 && n
< 8)
1590 strcpy (r
, "movqd ");
1591 else if (n
> 0 && n
< 256)
1592 strcpy (r
, "movzbd ");
1593 else if (n
> 0 && n
< 65536)
1594 strcpy (r
, "movzwd ");
1595 else if (n
< 0 && n
> -129)
1596 strcpy (r
, "movxbd ");
1597 else if (n
< 0 && n
> -32769)
1598 strcpy (r
, "movxwd ");
1600 strcpy (r
, "movd ");
1605 /* If using PIC, mark a SYMBOL_REF for a non-global symbol or a code
1606 symbol. These symbols are referenced via pc and not via sb. */
1609 ns32k_encode_section_info (decl
, first
)
1611 int first ATTRIBUTE_UNUSED
;
1615 rtx rtl
= (TREE_CODE_CLASS (TREE_CODE (decl
)) != 'd'
1616 ? TREE_CST_RTL (decl
) : DECL_RTL (decl
));
1617 SYMBOL_REF_FLAG (XEXP (rtl
, 0))
1618 = (TREE_CODE_CLASS (TREE_CODE (decl
)) != 'd'
1619 || ! TREE_PUBLIC (decl
));