2003-04-11 Eric Christopher <echristo@redhat.com>
[official-gcc.git] / gcc / config / ns32k / ns32k.c
blob73b16df9058e43828ccb23c58773cd8ace3c18c9
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)
10 any later version.
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. */
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tm.h"
26 #include "rtl.h"
27 #include "regs.h"
28 #include "hard-reg-set.h"
29 #include "real.h"
30 #include "insn-config.h"
31 #include "conditions.h"
32 #include "output.h"
33 #include "insn-attr.h"
34 #include "tree.h"
35 #include "function.h"
36 #include "expr.h"
37 #include "flags.h"
38 #include "recog.h"
39 #include "tm_p.h"
40 #include "target.h"
41 #include "target-def.h"
42 #include "toplev.h"
44 #ifdef OSF_OS
45 int ns32k_num_files = 0;
46 #endif
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"
85 #ifdef ENCORE_ASM
86 #undef TARGET_ASM_ALIGNED_SI_OP
87 #define TARGET_ASM_ALIGNED_SI_OP "\t.double\t"
88 #endif
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))
147 #else
148 #define ADJSP(FILE, N) \
149 fprintf (FILE, "\tadjspd %d\n", (N))
150 #endif
152 static void
153 ns32k_output_function_prologue (file, size)
154 FILE *file;
155 HOST_WIDE_INT 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++;
167 *bufp = -1;
169 for (; regno < FRAME_POINTER_REGNUM; regno++)
170 if (regs_ever_live[regno] && !call_used_regs[regno])
172 *fbufp++ = regno;
174 *fbufp = -1;
176 bufp = used_regs_buf;
177 if (frame_pointer_needed)
178 fprintf (file, "\tenter [");
179 else
181 if (size)
182 ADJSP (file, size + 4);
183 if (g_regs_used && g_regs_used > 4)
184 fprintf (file, "\tsave [");
185 else
187 while (*bufp >= 0)
188 fprintf (file, "\tmovd r%d,tos\n", *bufp++);
189 g_regs_used = 0;
193 while (*bufp >= 0)
195 fprintf (file, "r%d", *bufp++);
196 if (*bufp >= 0)
197 fputc (',', file);
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;
206 while (*fbufp >= 0)
208 if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1))
209 fprintf (file, "\tmovf %s,tos\n", ns32k_out_reg_names[*fbufp++]);
210 else
212 fprintf (file, "\tmovl %s,tos\n",
213 ns32k_out_reg_names[fbufp[0]]);
214 fbufp += 2;
218 if (flag_pic && current_function_uses_pic_offset_table)
220 fprintf (file, "\tsprd sb,tos\n");
221 if (TARGET_REGPARM)
223 fprintf (file, "\taddr __GLOBAL_OFFSET_TABLE_(pc),tos\n");
224 fprintf (file, "\tlprd sb,tos\n");
226 else
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. */
239 static void
240 ns32k_output_function_prologue (file, size)
241 FILE *file;
242 HOST_WIDE_INT 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++;
254 *bufp = -1;
256 for (; regno < 16; regno++)
257 if (regs_ever_live[regno] && !call_used_regs[regno]) {
258 *fbufp++ = regno;
260 *fbufp = -1;
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)
270 char mask = 0;
271 while (*bufp >= 0)
272 mask |= 1 << *bufp++;
273 fprintf (file, "$0x%x", (int) mask & 0xff);
276 if (frame_pointer_needed)
277 #ifdef UTEK_ASM
278 fprintf (file, ",$%d\n", size);
279 #else
280 fprintf (file, ",%d\n", size);
281 #endif
282 else if (g_regs_used)
283 fprintf (file, "\n");
285 fbufp = used_fregs_buf;
286 while (*fbufp >= 0)
288 if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1))
289 fprintf (file, "\tmovf f%d,tos\n", *fbufp++ - 8);
290 else
292 fprintf (file, "\tmovl f%d,tos\n", fbufp[0] - 8);
293 fbufp += 2;
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)
332 static void
333 ns32k_output_function_epilogue (file, size)
334 FILE *file;
335 HOST_WIDE_INT 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");
344 *fbufp++ = -2;
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++;
350 fbufp--;
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]]);
365 fbufp -= 2;
367 else fprintf (file, "\tmovf tos,%s\n", ns32k_out_reg_names[*fbufp--]);
370 if (frame_pointer_needed)
371 fprintf (file, "\texit [");
372 else
374 if (g_regs_used && g_regs_used > 4)
375 fprintf (file, "\trestore [");
376 else
378 while (bufp > used_regs_buf)
379 fprintf (file, "\tmovd tos,r%d\n", *--bufp);
380 g_regs_used = 0;
384 while (bufp > used_regs_buf)
386 fprintf (file, "r%d", *--bufp);
387 if (bufp > used_regs_buf)
388 fputc (',', file);
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);
399 else
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. */
408 static void
409 ns32k_output_function_epilogue (file, size)
410 FILE *file;
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;
417 *fbufp++ = -2;
418 for (regno = 8; regno < 16; regno++)
419 if (regs_ever_live[regno] && !call_used_regs[regno]) {
420 *fbufp++ = regno; f_regs_used++;
422 fbufp--;
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);
436 fbufp -= 2;
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)
448 char mask = 0;
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);
458 #ifdef UTEK_ASM
459 if (current_function_pops_args)
460 fprintf (file, "\tret $%d\n", current_function_pops_args);
461 else
462 fprintf (file, "\tret $0\n");
463 #else
464 if (current_function_pops_args)
465 fprintf (file, "\tret %d\n", current_function_pops_args);
466 else
467 fprintf (file, "\tret 0\n");
468 #endif
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)
476 int regno;
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)
484 return 1;
485 if (size == UNITS_PER_WORD * 2
486 && (((regno & 1) == 0 && regno < FRAME_POINTER_REGNUM)))
487 return 1;
488 return 0;
490 if (size == UNITS_PER_WORD * 2
491 && (regno & 1) == 0 && regno < F0_REGNUM)
492 return 1;
493 if (size <= UNITS_PER_WORD
494 && (regno < F0_REGNUM || regno == FRAME_POINTER_REGNUM
495 || regno == STACK_POINTER_REGNUM))
496 return 1;
497 return 0;
500 static bool
501 ns32k_rtx_costs (x, code, outer_code, total)
502 rtx x;
503 int code, outer_code ATTRIBUTE_UNUSED;
504 int *total;
506 switch (code)
508 case CONST_INT:
509 if (INTVAL (x) <= 7 && INTVAL (x) >= -8)
510 *total = 0;
511 else if (INTVAL (x) < 0x2000 && INTVAL (x) >= -0x2000)
512 *total = 1;
513 else
514 *total = 3;
515 return true;
517 case CONST:
518 case LABEL_REF:
519 case SYMBOL_REF:
520 *total = 3;
521 return true;
523 case CONST_DOUBLE:
524 *total = 5;
525 return true;
527 default:
528 return false;
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)
537 return 2;
538 if ((SUBSET_P (CLASS1, FP_REGS) && !SUBSET_P (CLASS2, FP_REGS))
539 || (!SUBSET_P (CLASS1, FP_REGS) && SUBSET_P (CLASS2, FP_REGS)))
540 return 8;
541 if (((CLASS1) == STACK_POINTER_REG && !SUBSET_P (CLASS2,GENERAL_REGS))
542 || ((CLASS2) == STACK_POINTER_REG && !SUBSET_P (CLASS1,GENERAL_REGS)))
543 return 6;
544 if (((CLASS1) == FRAME_POINTER_REG && !SUBSET_P (CLASS2,GENERAL_REGS))
545 || ((CLASS2) == FRAME_POINTER_REG && !SUBSET_P (CLASS1,GENERAL_REGS)))
546 return 6;
547 return 2;
550 #if 0
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;
556 enum machine_mode M;
558 int ret = ((SUBSET_P (CLASS1, FP_REGS) && !SUBSET_P (CLASS2, FP_REGS))
559 || (!SUBSET_P (CLASS1, FP_REGS) && SUBSET_P (CLASS2, FP_REGS)));
560 return ret;
562 #endif
565 /* TARGET_ADDRESS_COST calls this. This function is not optimal
566 for the 32032 & 32332, but it probably is better than
567 the default. */
569 static int
570 ns32k_address_cost (operand)
571 rtx operand;
573 int cost = 0;
575 switch (GET_CODE (operand))
577 case REG:
578 cost += 1;
579 break;
581 case POST_DEC:
582 case PRE_DEC:
583 break;
585 case CONST_INT:
586 if (INTVAL (operand) <= 7 && INTVAL (operand) >= -8)
587 break;
588 if (INTVAL (operand) < 0x2000 && INTVAL (operand) >= -0x2000)
590 cost +=1;
591 break;
593 case CONST:
594 case LABEL_REF:
595 case SYMBOL_REF:
596 cost +=3;
597 break;
598 case CONST_DOUBLE:
599 cost += 5;
600 break;
602 case MEM:
603 cost += ns32k_address_cost (XEXP (operand, 0)) + 3;
604 break;
606 case MULT:
607 cost += 2;
608 /* FALLTHRU */
609 case PLUS:
610 cost += ns32k_address_cost (XEXP (operand, 0));
611 cost += ns32k_address_cost (XEXP (operand, 1));
612 break;
614 default:
615 break;
618 return cost;
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. */
625 enum reg_class
626 secondary_reload_class (class, mode, in)
627 enum reg_class class;
628 enum machine_mode mode ATTRIBUTE_UNUSED;
629 rtx in;
631 int regno = true_regnum (in);
633 if (regno >= FIRST_PSEUDO_REGISTER)
634 regno = -1;
636 if ((class == FRAME_POINTER_REG && regno == STACK_POINTER_REGNUM)
637 || ( class == STACK_POINTER_REG && regno == FRAME_POINTER_REGNUM))
638 return GENERAL_REGS;
639 else
640 return NO_REGS;
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). */
648 static rtx
649 gen_indexed_expr (base, index, scale)
650 rtx base, index, scale;
652 rtx addr;
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);
661 return 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". */
671 void
672 split_di (operands, num, lo_half, hi_half)
673 rtx operands[];
674 int num;
675 rtx lo_half[], hi_half[];
677 while (num--)
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);
693 else
694 abort ();
698 /* Return the best assembler insn template
699 for moving operands[1] into operands[0] as a fullword. */
701 static const char *
702 singlemove_string (operands)
703 rtx *operands;
705 if (GET_CODE (operands[1]) == CONST_INT
706 && INTVAL (operands[1]) <= 7
707 && INTVAL (operands[1]) >= -8)
708 return "movqd %1,%0";
709 return "movd %1,%0";
712 const char *
713 output_move_double (operands)
714 rtx *operands;
716 enum anon1 { REGOP, OFFSOP, PUSHOP, CNSTOP, RNDOP } optype0, optype1;
717 rtx latehalf[2];
719 /* First classify both operands. */
721 if (REG_P (operands[0]))
722 optype0 = REGOP;
723 else if (offsettable_memref_p (operands[0]))
724 optype0 = OFFSOP;
725 else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
726 optype0 = PUSHOP;
727 else
728 optype0 = RNDOP;
730 if (REG_P (operands[1]))
731 optype1 = REGOP;
732 else if (CONSTANT_P (operands[1])
733 || GET_CODE (operands[1]) == CONST_DOUBLE)
734 optype1 = CNSTOP;
735 else if (offsettable_memref_p (operands[1]))
736 optype1 = OFFSOP;
737 else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
738 optype1 = PUSHOP;
739 else
740 optype1 = RNDOP;
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)
747 abort ();
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);
762 else
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]);
771 else
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]))
798 /* Do that word. */
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. */
813 rtx xops[2];
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);
821 /* Then clobber. */
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);
828 /* Then clobber. */
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. */
851 static void
852 move_tail (operands, bytes, offset)
853 rtx operands[];
854 int bytes;
855 int offset;
857 if (bytes & 2)
859 emit_move_insn (adjust_address (operands[0], HImode, offset),
860 adjust_address (operands[1], HImode, offset));
861 offset += 2;
863 if (bytes & 1)
864 emit_move_insn (adjust_address (operands[0], QImode, offset),
865 adjust_address (operands[1], QImode, offset));
868 void
869 expand_block_move (operands)
870 rtx 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)
882 return;
884 if (constp && bytes < 20)
886 int words = bytes >> 2;
888 if (words)
890 if (words < 3 || flag_unroll_loops)
892 int offset = 0;
894 for (; words; words--, offset += 4)
895 emit_move_insn (adjust_address (operands[0], SImode, offset),
896 adjust_address (operands[1], SImode, offset));
898 else
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
903 for small copies. */
904 rtx src, dest;
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);
912 return;
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.
932 if (bytes >> 2)
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)));
945 if (constp)
947 move_tail (operands, bytes & 3, 0);
949 else
951 /* insns to copy rest */
952 emit_insn (gen_andsi3 (count_reg, bytes_rtx, GEN_INT (3)));
953 emit_insn (gen_movstrsi1 (const1_rtx));
956 else
958 /* Not aligned and we may have a lot to copy so it is worth
959 * aligning.
961 rtx aligned_label = gen_label_rtx ();
962 rtx bytes_reg;
964 bytes_reg = copy_to_mode_reg (SImode, bytes_rtx);
965 if (!constp)
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));
980 if (!constp)
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)
998 rtx op;
999 int f;
1001 register const char *fmt;
1002 register int i;
1004 if (GET_CODE (op) == SYMBOL_REF)
1006 if (! SYMBOL_REF_FLAG (op))
1007 return 1;
1008 else
1009 return 0;
1011 else if (f && GET_CODE (op) != CONST)
1012 return 0;
1014 fmt = GET_RTX_FORMAT (GET_CODE (op));
1015 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
1017 if (fmt[i] == 'E')
1019 register int j;
1021 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
1022 if (global_symbolic_reference_mentioned_p (XVECEXP (op, i, j), 0))
1023 return 1;
1025 else if (fmt[i] == 'e'
1026 && global_symbolic_reference_mentioned_p (XEXP (op, i), 0))
1027 return 1;
1030 return 0;
1034 /* Returns 1 if OP contains a symbol reference */
1037 symbolic_reference_mentioned_p (op)
1038 rtx op;
1040 register const char *fmt;
1041 register int i;
1043 if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
1044 return 1;
1046 fmt = GET_RTX_FORMAT (GET_CODE (op));
1047 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
1049 if (fmt[i] == 'E')
1051 register int j;
1053 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
1054 if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
1055 return 1;
1057 else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
1058 return 1;
1061 return 0;
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. */
1079 static tree
1080 ns32k_handle_fntype_attribute (node, name, args, flags, no_add_attrs)
1081 tree *node;
1082 tree name;
1083 tree args ATTRIBUTE_UNUSED;
1084 int flags ATTRIBUTE_UNUSED;
1085 bool *no_add_attrs;
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;
1096 return NULL_TREE;
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;
1120 tree funtype;
1121 int size;
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)))
1130 return 0;
1132 /* Stdcall functions will pop the stack if not variable args */
1133 if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype)))
1134 rtd = 1;
1136 if (rtd)
1138 if (TYPE_ARG_TYPES (funtype) == NULL_TREE
1139 || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node))
1140 return size;
1143 return 0;
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 */
1151 void
1152 print_operand (file, x, code)
1153 FILE *file;
1154 rtx x;
1155 int code;
1157 if (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)
1169 REAL_VALUE_TYPE r;
1171 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1172 PUT_IMMEDIATE_PREFIX (file);
1173 if (GET_MODE (x) == DFmode)
1175 #ifdef SEQUENT_ASM
1176 /* Sequent likes its floating point constants as integers */
1177 long l[2];
1178 REAL_VALUE_TO_TARGET_DOUBLE (r, l);
1179 fprintf (file, "0Dx%08x%08x",
1180 l[!WORDS_BIG_ENDIAN], l[WORDS_BIG_ENDIAN]);
1181 #else
1182 char s[30];
1183 real_to_decimal (s, &r, sizeof (s), 0, 1);
1184 #ifdef ENCORE_ASM
1185 fprintf (file, "0f%s", s);
1186 #else
1187 fprintf (file, "0d%s", s);
1188 #endif
1189 #endif
1191 else
1193 #ifdef SEQUENT_ASM
1194 long l;
1195 REAL_VALUE_TO_TARGET_SINGLE (r, l);
1196 fprintf (file, "0Fx%08lx", l);
1197 #else
1198 char s[30];
1199 real_to_decimal (s, &r, sizeof (s), 0, 1);
1200 fprintf (file, "0f%s", s);
1201 #endif
1204 else
1206 if (flag_pic
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));
1214 abort ();
1216 else if (flag_pic
1217 && (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF))
1219 output_addr_const (file, x);
1220 fprintf (file, "(sb)");
1222 else
1224 #ifdef NO_IMMEDIATE_PREFIX_IF_SYMBOLIC
1225 if (GET_CODE (x) == CONST_INT)
1226 #endif
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> */
1242 void
1243 print_operand_address (file, addr)
1244 register FILE *file;
1245 register rtx addr;
1247 static const char scales[] = { 'b', 'w', 'd', 0, 'q', };
1248 rtx offset, base, indexexp, tmp;
1249 int scale;
1250 extern int flag_pic;
1252 if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == POST_DEC)
1254 fprintf (file, "tos");
1255 return;
1258 offset = NULL;
1259 base = NULL;
1260 indexexp = NULL;
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);
1270 else
1272 tmp = XEXP (addr,0);
1273 addr = XEXP (addr,1);
1276 else
1278 tmp = addr;
1279 addr = NULL;
1281 switch (GET_CODE (tmp))
1283 case PLUS:
1284 abort ();
1285 case MEM:
1286 if (base)
1288 indexexp = base;
1289 base = tmp;
1291 else
1292 base = tmp;
1293 break;
1294 case REG:
1295 if (REGNO (tmp) < F0_REGNUM)
1296 if (base)
1298 indexexp = tmp;
1300 else
1301 base = tmp;
1302 else
1303 if (base)
1305 indexexp = base;
1306 base = tmp;
1308 else
1309 base = tmp;
1310 break;
1311 case MULT:
1312 indexexp = tmp;
1313 break;
1314 case SYMBOL_REF:
1315 if (flag_pic && ! CONSTANT_POOL_ADDRESS_P (tmp)
1316 && ! SYMBOL_REF_FLAG (tmp))
1318 if (base)
1320 if (indexexp)
1321 abort ();
1322 indexexp = base;
1324 base = tmp;
1325 break;
1327 case CONST:
1328 if (flag_pic && GET_CODE (tmp) == CONST)
1330 rtx sym, off, tmp1;
1331 tmp1 = XEXP (tmp,0);
1332 if (GET_CODE (tmp1) != PLUS)
1333 abort ();
1335 sym = XEXP (tmp1,0);
1336 if (GET_CODE (sym) != SYMBOL_REF)
1338 off = sym;
1339 sym = XEXP (tmp1,1);
1341 else
1342 off = XEXP (tmp1,1);
1343 if (GET_CODE (sym) == SYMBOL_REF)
1345 if (GET_CODE (off) != CONST_INT)
1346 abort ();
1348 if (CONSTANT_POOL_ADDRESS_P (sym)
1349 || SYMBOL_REF_FLAG (sym))
1351 SYMBOL_REF_FLAG (tmp) = 1;
1353 else
1355 if (base)
1357 if (indexexp)
1358 abort ();
1360 indexexp = base;
1363 if (offset != 0)
1364 abort ();
1366 base = sym;
1367 offset = off;
1368 break;
1372 case CONST_INT:
1373 case LABEL_REF:
1374 if (offset)
1375 offset = gen_rtx_PLUS (SImode, tmp, offset);
1376 else
1377 offset = tmp;
1378 break;
1379 default:
1380 abort ();
1383 if (! offset)
1384 offset = const0_rtx;
1386 if (base
1387 #ifndef INDEX_RATHER_THAN_BASE
1388 && (flag_pic || TARGET_HIMEM)
1389 && GET_CODE (base) != SYMBOL_REF
1390 && GET_CODE (offset) != CONST_INT
1391 #else
1392 /* This is a re-implementation of the SEQUENT_ADDRESS_BUG fix. */
1393 #endif
1394 && !indexexp && GET_CODE (base) == REG
1395 && REG_OK_FOR_INDEX_P (base))
1397 indexexp = base;
1398 base = NULL;
1401 /* now, offset, base and indexexp are set */
1402 #ifndef BASE_REG_NEEDED
1403 if (! base)
1405 #if defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC)
1406 if (GET_CODE (offset) == CONST_INT)
1407 #endif
1408 PUT_ABSOLUTE_PREFIX (file);
1410 #endif
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:
1417 (rN) (REG ...)
1418 (sp) (REG ...)
1419 (fp) (REG ...)
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 ...)
1425 case REG:
1426 fprintf (file, "(%s)", ns32k_out_reg_names[REGNO (base)]);
1427 break;
1428 case SYMBOL_REF:
1429 if (! flag_pic)
1430 abort ();
1432 fprintf (file, "(");
1433 output_addr_const (file, base);
1434 fprintf (file, "(sb))");
1435 break;
1436 case MEM:
1437 addr = XEXP (base,0);
1438 base = NULL;
1439 offset = NULL;
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);
1449 else
1451 tmp = XEXP (addr, 0);
1452 addr = XEXP (addr, 1);
1455 else
1457 tmp = addr;
1458 addr = NULL;
1460 switch (GET_CODE (tmp))
1462 case REG:
1463 base = tmp;
1464 break;
1465 case CONST:
1466 case CONST_INT:
1467 case SYMBOL_REF:
1468 case LABEL_REF:
1469 if (offset)
1470 offset = gen_rtx_PLUS (SImode, tmp, offset);
1471 else
1472 offset = tmp;
1473 break;
1474 default:
1475 abort ();
1478 if (! offset)
1479 offset = const0_rtx;
1480 fprintf (file, "(");
1481 output_addr_const (file, offset);
1482 if (base)
1483 fprintf (file, "(%s)", ns32k_out_reg_names[REGNO (base)]);
1484 else if (TARGET_SB)
1485 fprintf (file, "(sb)");
1486 else
1487 abort ();
1488 fprintf (file, ")");
1489 break;
1490 default:
1491 abort ();
1493 #ifdef PC_RELATIVE
1494 else if (GET_CODE (offset) != CONST_INT)
1495 fprintf (file, "(pc)");
1496 #ifdef BASE_REG_NEEDED
1497 else if (TARGET_SB)
1498 fprintf (file, "(sb)");
1499 else
1500 abort ();
1501 #endif
1502 #endif /* PC_RELATIVE */
1504 /* now print index if we have one */
1505 if (indexexp)
1507 if (GET_CODE (indexexp) == MULT)
1509 scale = INTVAL (XEXP (indexexp, 1)) >> 1;
1510 indexexp = XEXP (indexexp, 0);
1512 else
1513 scale = 0;
1514 if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= F0_REGNUM)
1515 abort ();
1517 #ifdef UTEK_ASM
1518 fprintf (file, "[%c`%s]",
1519 scales[scale],
1520 ns32k_out_reg_names[REGNO (indexexp)]);
1521 #else
1522 fprintf (file, "[%s:%c]",
1523 ns32k_out_reg_names[REGNO (indexexp)],
1524 scales[scale]);
1525 #endif
1529 /* National 32032 shifting is so bad that we can get
1530 better performance in many common cases by using other
1531 techniques. */
1532 const char *
1533 output_shift_insn (operands)
1534 rtx *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";
1582 const char *
1583 output_move_dconst (n, s)
1584 int n;
1585 const char *s;
1587 static char r[32];
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 ");
1599 else
1600 strcpy (r, "movd ");
1601 strcat (r, s);
1602 return r;
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. */
1608 static void
1609 ns32k_encode_section_info (decl, first)
1610 tree decl;
1611 int first ATTRIBUTE_UNUSED;
1613 if (flag_pic)
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));