gcc/ChangeLog:
[official-gcc.git] / gcc / config / ns32k / ns32k.c
blob696e86b818847a23e7a37a9b3cfdb355fca98ea9
1 /* Subroutines for assembler code output on the NS32000.
2 Copyright (C) 1988, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2004
3 Free Software Foundation, Inc.
5 This file is part of GCC.
7 GCC 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 GCC 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 GCC; 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 (rtx, rtx, rtx);
68 static const char *singlemove_string (rtx *);
69 static void move_tail (rtx[], int, int);
70 static tree ns32k_handle_fntype_attribute (tree *, tree, tree, int, bool *);
71 const struct attribute_spec ns32k_attribute_table[];
72 static void ns32k_output_function_prologue (FILE *, HOST_WIDE_INT);
73 static void ns32k_output_function_epilogue (FILE *, HOST_WIDE_INT);
74 static bool ns32k_rtx_costs (rtx, int, int, int *);
75 static int ns32k_address_cost (rtx);
76 static rtx ns32k_struct_value_rtx (tree, int);
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
95 #undef TARGET_RTX_COSTS
96 #define TARGET_RTX_COSTS ns32k_rtx_costs
97 #undef TARGET_ADDRESS_COST
98 #define TARGET_ADDRESS_COST ns32k_address_cost
100 #undef TARGET_STRUCT_VALUE_RTX
101 #define TARGET_STRUCT_VALUE_RTX ns32k_struct_value_rtx
103 #undef TARGET_ASM_FILE_START_APP_OFF
104 #define TARGET_ASM_FILE_START_APP_OFF true
106 struct gcc_target targetm = TARGET_INITIALIZER;
108 /* Generate the assembly code for function entry. FILE is a stdio
109 stream to output the code to. SIZE is an int: how many units of
110 temporary storage to allocate.
112 Refer to the array `regs_ever_live' to determine which registers to
113 save; `regs_ever_live[I]' is nonzero if register number I is ever
114 used in the function. This function is responsible for knowing
115 which registers should not be saved even if used. */
118 * The function prologue for the ns32k is fairly simple.
119 * If a frame pointer is needed (decided in reload.c ?) then
120 * we need assembler of the form
122 * # Save the oldframe pointer, set the new frame pointer, make space
123 * # on the stack and save any general purpose registers necessary
125 * enter [<general purpose regs to save>], <local stack space>
127 * movf fn, tos # Save any floating point registers necessary
131 * If a frame pointer is not needed we need assembler of the form
133 * # Make space on the stack
135 * adjspd <local stack space + 4>
137 * # Save any general purpose registers necessary
139 * save [<general purpose regs to save>]
141 * movf fn, tos # Save any floating point registers necessary
146 #if !defined (MERLIN_TARGET) && !defined (UTEK_ASM)
148 #if defined(IMMEDIATE_PREFIX) && IMMEDIATE_PREFIX
149 #define ADJSP(FILE, N) \
150 fprintf (FILE, "\tadjspd %c" HOST_WIDE_INT_PRINT_DEC "\n", IMMEDIATE_PREFIX, (N))
151 #else
152 #define ADJSP(FILE, N) \
153 fprintf (FILE, "\tadjspd " HOST_WIDE_INT_PRINT_DEC "\n", (N))
154 #endif
156 static void
157 ns32k_output_function_prologue (FILE *file, HOST_WIDE_INT size)
159 register int regno, g_regs_used = 0;
160 int used_regs_buf[8], *bufp = used_regs_buf;
161 int used_fregs_buf[17], *fbufp = used_fregs_buf;
163 for (regno = R0_REGNUM; regno < F0_REGNUM; regno++)
164 if (regs_ever_live[regno]
165 && ! call_used_regs[regno])
167 *bufp++ = regno; g_regs_used++;
169 *bufp = -1;
171 for (; regno < FRAME_POINTER_REGNUM; regno++)
172 if (regs_ever_live[regno] && !call_used_regs[regno])
174 *fbufp++ = regno;
176 *fbufp = -1;
178 bufp = used_regs_buf;
179 if (frame_pointer_needed)
180 fprintf (file, "\tenter [");
181 else
183 if (size)
184 ADJSP (file, size + 4);
185 if (g_regs_used && g_regs_used > 4)
186 fprintf (file, "\tsave [");
187 else
189 while (*bufp >= 0)
190 fprintf (file, "\tmovd r%d,tos\n", *bufp++);
191 g_regs_used = 0;
195 while (*bufp >= 0)
197 fprintf (file, "r%d", *bufp++);
198 if (*bufp >= 0)
199 fputc (',', file);
202 if (frame_pointer_needed)
203 fprintf (file, "]," HOST_WIDE_INT_PRINT_DEC "\n", size);
204 else if (g_regs_used)
205 fprintf (file, "]\n");
207 fbufp = used_fregs_buf;
208 while (*fbufp >= 0)
210 if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1))
211 fprintf (file, "\tmovf %s,tos\n", ns32k_out_reg_names[*fbufp++]);
212 else
214 fprintf (file, "\tmovl %s,tos\n",
215 ns32k_out_reg_names[fbufp[0]]);
216 fbufp += 2;
220 if (flag_pic && current_function_uses_pic_offset_table)
222 fprintf (file, "\tsprd sb,tos\n");
223 if (TARGET_REGPARM)
225 fprintf (file, "\taddr __GLOBAL_OFFSET_TABLE_(pc),tos\n");
226 fprintf (file, "\tlprd sb,tos\n");
228 else
230 fprintf (file, "\taddr __GLOBAL_OFFSET_TABLE_(pc),r0\n");
231 fprintf (file, "\tlprd sb,r0\n");
236 #else /* MERLIN_TARGET || UTEK_ASM */
238 /* This differs from the standard one above in printing a bitmask
239 rather than a register list in the enter or save instruction. */
241 static void
242 ns32k_output_function_prologue (file, size)
243 FILE *file;
244 HOST_WIDE_INT size;
246 register int regno, g_regs_used = 0;
247 int used_regs_buf[8], *bufp = used_regs_buf;
248 int used_fregs_buf[8], *fbufp = used_fregs_buf;
250 for (regno = 0; regno < 8; regno++)
251 if (regs_ever_live[regno]
252 && ! call_used_regs[regno])
254 *bufp++ = regno; g_regs_used++;
256 *bufp = -1;
258 for (; regno < 16; regno++)
259 if (regs_ever_live[regno] && !call_used_regs[regno]) {
260 *fbufp++ = regno;
262 *fbufp = -1;
264 bufp = used_regs_buf;
265 if (frame_pointer_needed)
266 fprintf (file, "\tenter ");
267 else if (g_regs_used)
268 fprintf (file, "\tsave ");
270 if (frame_pointer_needed || g_regs_used)
272 char mask = 0;
273 while (*bufp >= 0)
274 mask |= 1 << *bufp++;
275 fprintf (file, "$0x%x", (int) mask & 0xff);
278 if (frame_pointer_needed)
279 #ifdef UTEK_ASM
280 fprintf (file, ",$%d\n", size);
281 #else
282 fprintf (file, ",%d\n", size);
283 #endif
284 else if (g_regs_used)
285 fprintf (file, "\n");
287 fbufp = used_fregs_buf;
288 while (*fbufp >= 0)
290 if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1))
291 fprintf (file, "\tmovf f%d,tos\n", *fbufp++ - 8);
292 else
294 fprintf (file, "\tmovl f%d,tos\n", fbufp[0] - 8);
295 fbufp += 2;
300 #endif /* MERLIN_TARGET || UTEK_ASM */
302 /* This function generates the assembly code for function exit,
303 on machines that need it.
305 The function epilogue should not depend on the current stack pointer,
306 if EXIT_IGNORE_STACK is nonzero. That doesn't apply here.
308 If a frame pointer is needed (decided in reload.c ?) then
309 we need assembler of the form
311 movf tos, fn # Restore any saved floating point registers
315 # Restore any saved general purpose registers, restore the stack
316 # pointer from the frame pointer, restore the old frame pointer.
317 exit [<general purpose regs to save>]
319 If a frame pointer is not needed we need assembler of the form
320 # Restore any general purpose registers saved
322 movf tos, fn # Restore any saved floating point registers
326 restore [<general purpose regs to save>]
328 # reclaim space allocated on stack
330 adjspd <-(local stack space + 4)> */
332 #if !defined (MERLIN_TARGET) && !defined (UTEK_ASM)
334 static void
335 ns32k_output_function_epilogue (FILE *file, 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 (int regno, enum machine_mode mode)
477 int size = GET_MODE_UNIT_SIZE (mode);
479 if (FLOAT_MODE_P (mode))
481 if (size == UNITS_PER_WORD && regno < L1_REGNUM)
482 return 1;
483 if (size == UNITS_PER_WORD * 2
484 && (((regno & 1) == 0 && regno < FRAME_POINTER_REGNUM)))
485 return 1;
486 return 0;
488 if (size == UNITS_PER_WORD * 2
489 && (regno & 1) == 0 && regno < F0_REGNUM)
490 return 1;
491 if (size <= UNITS_PER_WORD
492 && (regno < F0_REGNUM || regno == FRAME_POINTER_REGNUM
493 || regno == STACK_POINTER_REGNUM))
494 return 1;
495 return 0;
498 static bool
499 ns32k_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total)
501 switch (code)
503 case CONST_INT:
504 if (INTVAL (x) <= 7 && INTVAL (x) >= -8)
505 *total = 0;
506 else if (INTVAL (x) < 0x2000 && INTVAL (x) >= -0x2000)
507 *total = 1;
508 else
509 *total = 3;
510 return true;
512 case CONST:
513 case LABEL_REF:
514 case SYMBOL_REF:
515 *total = 3;
516 return true;
518 case CONST_DOUBLE:
519 *total = 5;
520 return true;
522 default:
523 return false;
528 register_move_cost (enum reg_class CLASS1, enum reg_class CLASS2)
530 if (CLASS1 == NO_REGS || CLASS2 == NO_REGS)
531 return 2;
532 if ((SUBSET_P (CLASS1, FP_REGS) && !SUBSET_P (CLASS2, FP_REGS))
533 || (!SUBSET_P (CLASS1, FP_REGS) && SUBSET_P (CLASS2, FP_REGS)))
534 return 8;
535 if (((CLASS1) == STACK_POINTER_REG && !SUBSET_P (CLASS2,GENERAL_REGS))
536 || ((CLASS2) == STACK_POINTER_REG && !SUBSET_P (CLASS1,GENERAL_REGS)))
537 return 6;
538 if (((CLASS1) == FRAME_POINTER_REG && !SUBSET_P (CLASS2,GENERAL_REGS))
539 || ((CLASS2) == FRAME_POINTER_REG && !SUBSET_P (CLASS1,GENERAL_REGS)))
540 return 6;
541 return 2;
544 #if 0
545 /* We made the insn definitions copy from floating point to general
546 registers via the stack. */
548 secondary_memory_needed (enum reg_class CLASS1,
549 enum reg_class CLASS2,
550 enum machine_mode M)
552 int ret = ((SUBSET_P (CLASS1, FP_REGS) && !SUBSET_P (CLASS2, FP_REGS))
553 || (!SUBSET_P (CLASS1, FP_REGS) && SUBSET_P (CLASS2, FP_REGS)));
554 return ret;
556 #endif
559 /* TARGET_ADDRESS_COST calls this. This function is not optimal
560 for the 32032 & 32332, but it probably is better than
561 the default. */
563 static int
564 ns32k_address_cost (rtx operand)
566 int cost = 0;
568 switch (GET_CODE (operand))
570 case REG:
571 cost += 1;
572 break;
574 case POST_DEC:
575 case PRE_DEC:
576 break;
578 case CONST_INT:
579 if (INTVAL (operand) <= 7 && INTVAL (operand) >= -8)
580 break;
581 if (INTVAL (operand) < 0x2000 && INTVAL (operand) >= -0x2000)
583 cost +=1;
584 break;
586 case CONST:
587 case LABEL_REF:
588 case SYMBOL_REF:
589 cost +=3;
590 break;
591 case CONST_DOUBLE:
592 cost += 5;
593 break;
595 case MEM:
596 cost += ns32k_address_cost (XEXP (operand, 0)) + 3;
597 break;
599 case MULT:
600 cost += 2;
601 /* FALLTHRU */
602 case PLUS:
603 cost += ns32k_address_cost (XEXP (operand, 0));
604 cost += ns32k_address_cost (XEXP (operand, 1));
605 break;
607 default:
608 break;
611 return cost;
614 /* Return the register class of a scratch register needed to copy IN into
615 or out of a register in CLASS in MODE. If it can be done directly,
616 NO_REGS is returned. */
618 enum reg_class
619 secondary_reload_class (enum reg_class class,
620 enum machine_mode mode ATTRIBUTE_UNUSED,
621 rtx in)
623 int regno = true_regnum (in);
625 if (regno >= FIRST_PSEUDO_REGISTER)
626 regno = -1;
628 if ((class == FRAME_POINTER_REG && regno == STACK_POINTER_REGNUM)
629 || ( class == STACK_POINTER_REG && regno == FRAME_POINTER_REGNUM))
630 return GENERAL_REGS;
631 else
632 return NO_REGS;
635 /* Generate the rtx that comes from an address expression in the md file */
636 /* The expression to be build is BASE[INDEX:SCALE]. To recognize this,
637 scale must be converted from an exponent (from ASHIFT) to a
638 multiplier (for MULT). */
640 static rtx
641 gen_indexed_expr (rtx base, rtx index, rtx scale)
643 rtx addr;
645 /* This generates an invalid addressing mode, if BASE is
646 fp or sp. This is handled by PRINT_OPERAND_ADDRESS. */
647 if (GET_CODE (base) != REG && GET_CODE (base) != CONST_INT)
648 base = gen_rtx_MEM (SImode, base);
649 addr = gen_rtx_MULT (SImode, index,
650 GEN_INT (1 << INTVAL (scale)));
651 addr = gen_rtx_PLUS (SImode, base, addr);
652 return addr;
656 /* Split one or more DImode RTL references into pairs of SImode
657 references. The RTL can be REG, offsettable MEM, integer constant, or
658 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
659 split and "num" is its length. lo_half and hi_half are output arrays
660 that parallel "operands". */
662 void
663 split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
665 while (num--)
667 if (GET_CODE (operands[num]) == REG)
669 lo_half[num] = gen_rtx_REG (SImode, REGNO (operands[num]));
670 hi_half[num] = gen_rtx_REG (SImode, REGNO (operands[num]) + 1);
672 else if (CONSTANT_P (operands[num]))
674 split_double (operands[num], &lo_half[num], &hi_half[num]);
676 else if (offsettable_memref_p (operands[num]))
678 lo_half[num] = operands[num];
679 hi_half[num] = adjust_address (operands[num], SImode, 4);
681 else
682 abort ();
686 /* Return the best assembler insn template
687 for moving operands[1] into operands[0] as a fullword. */
689 static const char *
690 singlemove_string (rtx *operands)
692 if (GET_CODE (operands[1]) == CONST_INT
693 && INTVAL (operands[1]) <= 7
694 && INTVAL (operands[1]) >= -8)
695 return "movqd %1,%0";
696 return "movd %1,%0";
699 const char *
700 output_move_double (rtx *operands)
702 enum anon1 { REGOP, OFFSOP, PUSHOP, CNSTOP, RNDOP } optype0, optype1;
703 rtx latehalf[2];
705 /* First classify both operands. */
707 if (REG_P (operands[0]))
708 optype0 = REGOP;
709 else if (offsettable_memref_p (operands[0]))
710 optype0 = OFFSOP;
711 else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
712 optype0 = PUSHOP;
713 else
714 optype0 = RNDOP;
716 if (REG_P (operands[1]))
717 optype1 = REGOP;
718 else if (CONSTANT_P (operands[1])
719 || GET_CODE (operands[1]) == CONST_DOUBLE)
720 optype1 = CNSTOP;
721 else if (offsettable_memref_p (operands[1]))
722 optype1 = OFFSOP;
723 else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
724 optype1 = PUSHOP;
725 else
726 optype1 = RNDOP;
728 /* Check for the cases that the operand constraints are not
729 supposed to allow to happen. Abort if we get one,
730 because generating code for these cases is painful. */
732 if (optype0 == RNDOP || optype1 == RNDOP)
733 abort ();
735 /* Ok, we can do one word at a time.
736 Normally we do the low-numbered word first,
737 but if either operand is autodecrementing then we
738 do the high-numbered word first.
740 In either case, set up in LATEHALF the operands to use
741 for the high-numbered word and in some cases alter the
742 operands in OPERANDS to be suitable for the low-numbered word. */
744 if (optype0 == REGOP)
745 latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
746 else if (optype0 == OFFSOP)
747 latehalf[0] = adjust_address (operands[0], SImode, 4);
748 else
749 latehalf[0] = operands[0];
751 if (optype1 == REGOP)
752 latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
753 else if (optype1 == OFFSOP)
754 latehalf[1] = adjust_address (operands[1], SImode, 4);
755 else if (optype1 == CNSTOP)
756 split_double (operands[1], &operands[1], &latehalf[1]);
757 else
758 latehalf[1] = operands[1];
760 /* If insn is effectively movd N(sp),tos then we will do the
761 high word first. We should use the adjusted operand 1 (which is N+4(sp))
762 for the low word as well, to compensate for the first decrement of sp.
763 Given this, it doesn't matter which half we do "first". */
764 if (optype0 == PUSHOP
765 && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
766 && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
767 operands[1] = latehalf[1];
769 /* If one or both operands autodecrementing,
770 do the two words, high-numbered first. */
771 else if (optype0 == PUSHOP || optype1 == PUSHOP)
773 output_asm_insn (singlemove_string (latehalf), latehalf);
774 return singlemove_string (operands);
777 /* If the first move would clobber the source of the second one,
778 do them in the other order. */
780 /* Overlapping registers. */
781 if (optype0 == REGOP && optype1 == REGOP
782 && REGNO (operands[0]) == REGNO (latehalf[1]))
784 /* Do that word. */
785 output_asm_insn (singlemove_string (latehalf), latehalf);
786 /* Do low-numbered word. */
787 return singlemove_string (operands);
789 /* Loading into a register which overlaps a register used in the address. */
790 else if (optype0 == REGOP && optype1 != REGOP
791 && reg_overlap_mentioned_p (operands[0], operands[1]))
793 if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
794 && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
796 /* If both halves of dest are used in the src memory address,
797 load the destination address into the low reg (operands[0]).
798 Then it works to load latehalf first. */
799 rtx xops[2];
800 xops[0] = XEXP (operands[1], 0);
801 xops[1] = operands[0];
802 output_asm_insn ("addr %a0,%1", xops);
803 operands[1] = gen_rtx_MEM (DImode, operands[0]);
804 latehalf[1] = adjust_address (operands[1], SImode, 4);
805 /* The first half has the overlap, Do the late half first. */
806 output_asm_insn (singlemove_string (latehalf), latehalf);
807 /* Then clobber. */
808 return singlemove_string (operands);
810 if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)))
812 /* The first half has the overlap, Do the late half first. */
813 output_asm_insn (singlemove_string (latehalf), latehalf);
814 /* Then clobber. */
815 return singlemove_string (operands);
819 /* Normal case. Do the two words, low-numbered first. */
821 output_asm_insn (singlemove_string (operands), operands);
823 operands[0] = latehalf[0];
824 operands[1] = latehalf[1];
825 return singlemove_string (operands);
829 #define MAX_UNALIGNED_COPY (32)
830 /* Expand string/block move operations.
832 operands[0] is the pointer to the destination.
833 operands[1] is the pointer to the source.
834 operands[2] is the number of bytes to move.
835 operands[3] is the alignment. */
837 static void
838 move_tail (rtx operands[], int bytes, int offset)
840 if (bytes & 2)
842 emit_move_insn (adjust_address (operands[0], HImode, offset),
843 adjust_address (operands[1], HImode, offset));
844 offset += 2;
846 if (bytes & 1)
847 emit_move_insn (adjust_address (operands[0], QImode, offset),
848 adjust_address (operands[1], QImode, offset));
851 void
852 expand_block_move (rtx operands[])
854 rtx bytes_rtx = operands[2];
855 rtx align_rtx = operands[3];
856 int constp = (GET_CODE (bytes_rtx) == CONST_INT);
857 int bytes = (constp ? INTVAL (bytes_rtx) : 0);
858 int align = INTVAL (align_rtx);
859 rtx src_reg = gen_rtx_REG (Pmode, 1);
860 rtx dest_reg = gen_rtx_REG (Pmode, 2);
861 rtx count_reg = gen_rtx_REG (SImode, 0);
863 if (constp && bytes <= 0)
864 return;
866 if (constp && bytes < 20)
868 int words = bytes >> 2;
870 if (words)
872 if (words < 3)
874 int offset = 0;
876 for (; words; words--, offset += 4)
877 emit_move_insn (adjust_address (operands[0], SImode, offset),
878 adjust_address (operands[1], SImode, offset));
880 else
882 /* Use movmd. It is slower than multiple movd's but more
883 compact. It is also slower than movsd for large copies
884 but causes less registers reloading so is better than movsd
885 for small copies. */
886 rtx src, dest;
887 dest = copy_addr_to_reg (XEXP (operands[0], 0));
888 src = copy_addr_to_reg (XEXP (operands[1], 0));
890 emit_insn (gen_movmemsi2(dest, src, GEN_INT (words)));
893 move_tail (operands, bytes & 3, bytes & ~3);
894 return;
897 if (align > UNITS_PER_WORD)
898 align = UNITS_PER_WORD;
900 /* Move the address into scratch registers. */
901 emit_insn (gen_rtx_CLOBBER (VOIDmode, dest_reg));
902 emit_move_insn (dest_reg, XEXP (operands[0], 0));
903 operands[0] = gen_rtx_MEM (SImode, dest_reg);
904 emit_insn (gen_rtx_CLOBBER (VOIDmode, src_reg));
905 emit_move_insn (src_reg, XEXP (operands[1], 0));
906 operands[1] = gen_rtx_MEM (SImode, src_reg);
907 emit_insn (gen_rtx_CLOBBER (VOIDmode, count_reg));
909 if (constp && (align == UNITS_PER_WORD || bytes < MAX_UNALIGNED_COPY))
911 /* constant no of bytes and aligned or small enough copy to not bother
912 * aligning. Emit insns to copy by words.
914 if (bytes >> 2)
916 emit_move_insn (count_reg, GEN_INT (bytes >> 2));
917 emit_insn (gen_movmemsi1 (GEN_INT (4)));
919 /* insns to copy rest */
920 move_tail (operands, bytes & 3, 0);
922 else if (align == UNITS_PER_WORD)
924 /* insns to copy by words */
925 emit_insn (gen_lshrsi3 (count_reg, bytes_rtx, const2_rtx));
926 emit_insn (gen_movmemsi1 (GEN_INT (4)));
927 if (constp)
929 move_tail (operands, bytes & 3, 0);
931 else
933 /* insns to copy rest */
934 emit_insn (gen_andsi3 (count_reg, bytes_rtx, GEN_INT (3)));
935 emit_insn (gen_movmemsi1 (const1_rtx));
938 else
940 /* Not aligned and we may have a lot to copy so it is worth
941 * aligning.
943 rtx aligned_label = gen_label_rtx ();
944 rtx bytes_reg;
946 bytes_reg = copy_to_mode_reg (SImode, bytes_rtx);
947 if (!constp)
949 /* Emit insns to test and skip over the alignment if it is
950 * not worth it. This doubles as a test to ensure that the alignment
951 * operation can't copy too many bytes
953 emit_insn (gen_cmpsi (bytes_reg, GEN_INT (MAX_UNALIGNED_COPY)));
954 emit_jump_insn (gen_blt (aligned_label));
957 /* Emit insns to do alignment at run time */
958 emit_insn (gen_negsi2 (count_reg, src_reg));
959 emit_insn (gen_andsi3 (count_reg, count_reg, GEN_INT (3)));
960 emit_insn (gen_subsi3 (bytes_reg, bytes_reg, count_reg));
961 emit_insn (gen_movmemsi1 (const1_rtx));
962 if (!constp)
963 emit_label (aligned_label);
965 /* insns to copy by words */
966 emit_insn (gen_lshrsi3 (count_reg, bytes_reg, const2_rtx));
967 emit_insn (gen_movmemsi1 (GEN_INT (4)));
969 /* insns to copy rest */
970 emit_insn (gen_andsi3 (count_reg, bytes_reg, GEN_INT (3)));
971 emit_insn (gen_movmemsi1 (const1_rtx));
976 /* Returns 1 if OP contains a global symbol reference */
979 global_symbolic_reference_mentioned_p (rtx op, int f)
981 register const char *fmt;
982 register int i;
984 if (GET_CODE (op) == SYMBOL_REF)
986 if (! SYMBOL_REF_LOCAL_P (op))
987 return 1;
988 else
989 return 0;
991 else if (f && GET_CODE (op) != CONST)
992 return 0;
994 fmt = GET_RTX_FORMAT (GET_CODE (op));
995 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
997 if (fmt[i] == 'E')
999 register int j;
1001 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
1002 if (global_symbolic_reference_mentioned_p (XVECEXP (op, i, j), 0))
1003 return 1;
1005 else if (fmt[i] == 'e'
1006 && global_symbolic_reference_mentioned_p (XEXP (op, i), 0))
1007 return 1;
1010 return 0;
1014 /* Returns 1 if OP contains a symbol reference */
1017 symbolic_reference_mentioned_p (rtx op)
1019 register const char *fmt;
1020 register int i;
1022 if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
1023 return 1;
1025 fmt = GET_RTX_FORMAT (GET_CODE (op));
1026 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
1028 if (fmt[i] == 'E')
1030 register int j;
1032 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
1033 if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
1034 return 1;
1036 else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
1037 return 1;
1040 return 0;
1043 /* Table of machine-specific attributes. */
1045 const struct attribute_spec ns32k_attribute_table[] =
1047 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
1048 /* Stdcall attribute says callee is responsible for popping arguments
1049 if they are not variable. */
1050 { "stdcall", 0, 0, false, true, true, ns32k_handle_fntype_attribute },
1051 /* Cdecl attribute says the callee is a normal C declaration */
1052 { "cdecl", 0, 0, false, true, true, ns32k_handle_fntype_attribute },
1053 { NULL, 0, 0, false, false, false, NULL }
1056 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1057 arguments as in struct attribute_spec.handler. */
1058 static tree
1059 ns32k_handle_fntype_attribute (tree *node, tree name,
1060 tree args ATTRIBUTE_UNUSED,
1061 int flags ATTRIBUTE_UNUSED,
1062 bool *no_add_attrs)
1064 if (TREE_CODE (*node) != FUNCTION_TYPE
1065 && TREE_CODE (*node) != FIELD_DECL
1066 && TREE_CODE (*node) != TYPE_DECL)
1068 warning ("`%s' attribute only applies to functions",
1069 IDENTIFIER_POINTER (name));
1070 *no_add_attrs = true;
1073 return NULL_TREE;
1077 /* Value is the number of bytes of arguments automatically
1078 popped when returning from a subroutine call.
1079 FUNDECL is the declaration node of the function (as a tree),
1080 FUNTYPE is the data type of the function (as a tree),
1081 or for a library call it is an identifier node for the subroutine name.
1082 SIZE is the number of bytes of arguments passed on the stack.
1084 On the ns32k, the RET insn may be used to pop them if the number
1085 of args is fixed, but if the number is variable then the caller
1086 must pop them all. RET can't be used for library calls now
1087 because the library is compiled with the Unix compiler.
1088 Use of RET is a selectable option, since it is incompatible with
1089 standard Unix calling sequences. If the option is not selected,
1090 the caller must always pop the args.
1092 The attribute stdcall is equivalent to RET on a per module basis. */
1095 ns32k_return_pops_args (tree fundecl ATTRIBUTE_UNUSED, tree funtype, int size)
1097 int rtd = TARGET_RTD;
1099 if (TREE_CODE (funtype) == IDENTIFIER_NODE)
1100 return rtd ? size : 0;
1102 /* Cdecl functions override -mrtd, and never pop the stack */
1103 if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype)))
1104 return 0;
1106 /* Stdcall functions will pop the stack if not variable args */
1107 if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype)))
1108 rtd = 1;
1110 if (rtd)
1112 if (TYPE_ARG_TYPES (funtype) == NULL_TREE
1113 || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node))
1114 return size;
1117 return 0;
1120 /* PRINT_OPERAND is defined to call this function,
1121 which is easier to debug than putting all the code in
1122 a macro definition in ns32k.h. */
1124 /* XXX time 12% of cpu time is in fprintf for non optimizing */
1125 void
1126 print_operand (FILE *file, rtx x, int code)
1128 if (code == '$')
1129 PUT_IMMEDIATE_PREFIX (file);
1130 else if (code == '?')
1131 PUT_EXTERNAL_PREFIX (file);
1132 else if (GET_CODE (x) == REG)
1133 fprintf (file, "%s", ns32k_out_reg_names[REGNO (x)]);
1134 else if (GET_CODE (x) == MEM)
1136 output_address (XEXP (x, 0));
1138 else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != VOIDmode)
1140 REAL_VALUE_TYPE r;
1142 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1143 PUT_IMMEDIATE_PREFIX (file);
1144 if (GET_MODE (x) == DFmode)
1146 #ifdef SEQUENT_ASM
1147 /* Sequent likes its floating point constants as integers */
1148 long l[2];
1149 REAL_VALUE_TO_TARGET_DOUBLE (r, l);
1150 fprintf (file, "0Dx%08x%08x",
1151 l[!WORDS_BIG_ENDIAN], l[WORDS_BIG_ENDIAN]);
1152 #else
1153 char s[30];
1154 real_to_decimal (s, &r, sizeof (s), 0, 1);
1155 #ifdef ENCORE_ASM
1156 fprintf (file, "0f%s", s);
1157 #else
1158 fprintf (file, "0d%s", s);
1159 #endif
1160 #endif
1162 else
1164 #ifdef SEQUENT_ASM
1165 long l;
1166 REAL_VALUE_TO_TARGET_SINGLE (r, l);
1167 fprintf (file, "0Fx%08lx", l);
1168 #else
1169 char s[30];
1170 real_to_decimal (s, &r, sizeof (s), 0, 1);
1171 fprintf (file, "0f%s", s);
1172 #endif
1175 else
1177 if (flag_pic
1178 && GET_CODE (x) == CONST
1179 && symbolic_reference_mentioned_p (x))
1181 fprintf (stderr, "illegal constant for pic-mode: \n");
1182 print_rtl (stderr, x);
1183 fprintf (stderr, "\nGET_CODE (x) == %d, CONST == %d, symbolic_reference_mentioned_p (x) == %d\n",
1184 GET_CODE (x), CONST, symbolic_reference_mentioned_p (x));
1185 abort ();
1187 else if (flag_pic
1188 && (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF))
1190 output_addr_const (file, x);
1191 fprintf (file, "(sb)");
1193 else
1195 #ifdef NO_IMMEDIATE_PREFIX_IF_SYMBOLIC
1196 if (GET_CODE (x) == CONST_INT)
1197 #endif
1198 PUT_IMMEDIATE_PREFIX (file);
1199 output_addr_const (file, x);
1204 /* PRINT_OPERAND_ADDRESS is defined to call this function,
1205 which is easier to debug than putting all the code in
1206 a macro definition in ns32k.h . */
1208 /* Completely rewritten to get this to work with Gas for PC532 Mach.
1209 This function didn't work and I just wasn't able (nor very willing) to
1210 figure out how it worked.
1211 90-11-25 Tatu Yl|nen <ylo@cs.hut.fi> */
1213 void
1214 print_operand_address (register FILE *file, register rtx addr)
1216 static const char scales[] = { 'b', 'w', 'd', 0, 'q', };
1217 rtx offset, base, indexexp, tmp;
1218 int scale;
1219 extern int flag_pic;
1221 if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == POST_DEC)
1223 fprintf (file, "tos");
1224 return;
1227 offset = NULL;
1228 base = NULL;
1229 indexexp = NULL;
1230 while (addr != NULL)
1232 if (GET_CODE (addr) == PLUS)
1234 if (GET_CODE (XEXP (addr, 0)) == PLUS)
1236 tmp = XEXP (addr, 1);
1237 addr = XEXP (addr, 0);
1239 else
1241 tmp = XEXP (addr,0);
1242 addr = XEXP (addr,1);
1245 else
1247 tmp = addr;
1248 addr = NULL;
1250 switch (GET_CODE (tmp))
1252 case PLUS:
1253 abort ();
1254 case MEM:
1255 if (base)
1257 indexexp = base;
1258 base = tmp;
1260 else
1261 base = tmp;
1262 break;
1263 case REG:
1264 if (REGNO (tmp) < F0_REGNUM)
1265 if (base)
1267 indexexp = tmp;
1269 else
1270 base = tmp;
1271 else
1272 if (base)
1274 indexexp = base;
1275 base = tmp;
1277 else
1278 base = tmp;
1279 break;
1280 case MULT:
1281 indexexp = tmp;
1282 break;
1283 case SYMBOL_REF:
1284 if (flag_pic && ! SYMBOL_REF_LOCAL_P (tmp))
1286 if (base)
1288 if (indexexp)
1289 abort ();
1290 indexexp = base;
1292 base = tmp;
1293 break;
1295 case CONST:
1296 if (flag_pic && GET_CODE (tmp) == CONST)
1298 rtx sym, off, tmp1;
1299 tmp1 = XEXP (tmp,0);
1300 if (GET_CODE (tmp1) != PLUS)
1301 abort ();
1303 sym = XEXP (tmp1,0);
1304 if (GET_CODE (sym) != SYMBOL_REF)
1306 off = sym;
1307 sym = XEXP (tmp1,1);
1309 else
1310 off = XEXP (tmp1,1);
1311 if (GET_CODE (sym) == SYMBOL_REF)
1313 if (GET_CODE (off) != CONST_INT)
1314 abort ();
1316 if (! SYMBOL_REF_LOCAL_P (sym))
1318 if (base)
1320 if (indexexp)
1321 abort ();
1323 indexexp = base;
1326 if (offset != 0)
1327 abort ();
1329 base = sym;
1330 offset = off;
1331 break;
1335 case CONST_INT:
1336 case LABEL_REF:
1337 if (offset)
1338 offset = gen_rtx_PLUS (SImode, tmp, offset);
1339 else
1340 offset = tmp;
1341 break;
1342 default:
1343 abort ();
1346 if (! offset)
1347 offset = const0_rtx;
1349 if (base
1350 #ifndef INDEX_RATHER_THAN_BASE
1351 && (flag_pic || TARGET_HIMEM)
1352 && GET_CODE (base) != SYMBOL_REF
1353 && GET_CODE (offset) != CONST_INT
1354 #else
1355 /* This is a re-implementation of the SEQUENT_ADDRESS_BUG fix. */
1356 #endif
1357 && !indexexp && GET_CODE (base) == REG
1358 && REG_OK_FOR_INDEX_P (base))
1360 indexexp = base;
1361 base = NULL;
1364 /* now, offset, base and indexexp are set */
1365 #ifndef BASE_REG_NEEDED
1366 if (! base)
1368 #if defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC)
1369 if (GET_CODE (offset) == CONST_INT)
1370 #endif
1371 PUT_ABSOLUTE_PREFIX (file);
1373 #endif
1375 output_addr_const (file, offset);
1376 if (base) /* base can be (REG ...) or (MEM ...) */
1377 switch (GET_CODE (base))
1379 /* now we must output base. Possible alternatives are:
1380 (rN) (REG ...)
1381 (sp) (REG ...)
1382 (fp) (REG ...)
1383 (pc) (REG ...) used for SYMBOL_REF and LABEL_REF, output
1384 (disp(fp)) (MEM ...) just before possible [rX:y]
1385 (disp(sp)) (MEM ...)
1386 (disp(sb)) (MEM ...)
1388 case REG:
1389 fprintf (file, "(%s)", ns32k_out_reg_names[REGNO (base)]);
1390 break;
1391 case SYMBOL_REF:
1392 if (! flag_pic)
1393 abort ();
1395 fprintf (file, "(");
1396 output_addr_const (file, base);
1397 fprintf (file, "(sb))");
1398 break;
1399 case MEM:
1400 addr = XEXP (base,0);
1401 base = NULL;
1402 offset = NULL;
1403 while (addr != NULL)
1405 if (GET_CODE (addr) == PLUS)
1407 if (GET_CODE (XEXP (addr, 0)) == PLUS)
1409 tmp = XEXP (addr, 1);
1410 addr = XEXP (addr, 0);
1412 else
1414 tmp = XEXP (addr, 0);
1415 addr = XEXP (addr, 1);
1418 else
1420 tmp = addr;
1421 addr = NULL;
1423 switch (GET_CODE (tmp))
1425 case REG:
1426 base = tmp;
1427 break;
1428 case CONST:
1429 case CONST_INT:
1430 case SYMBOL_REF:
1431 case LABEL_REF:
1432 if (offset)
1433 offset = gen_rtx_PLUS (SImode, tmp, offset);
1434 else
1435 offset = tmp;
1436 break;
1437 default:
1438 abort ();
1441 if (! offset)
1442 offset = const0_rtx;
1443 fprintf (file, "(");
1444 output_addr_const (file, offset);
1445 if (base)
1446 fprintf (file, "(%s)", ns32k_out_reg_names[REGNO (base)]);
1447 else if (TARGET_SB)
1448 fprintf (file, "(sb)");
1449 else
1450 abort ();
1451 fprintf (file, ")");
1452 break;
1453 default:
1454 abort ();
1456 #ifdef PC_RELATIVE
1457 else if (GET_CODE (offset) != CONST_INT)
1458 fprintf (file, "(pc)");
1459 #ifdef BASE_REG_NEEDED
1460 else if (TARGET_SB)
1461 fprintf (file, "(sb)");
1462 else
1463 abort ();
1464 #endif
1465 #endif /* PC_RELATIVE */
1467 /* now print index if we have one */
1468 if (indexexp)
1470 if (GET_CODE (indexexp) == MULT)
1472 scale = INTVAL (XEXP (indexexp, 1)) >> 1;
1473 indexexp = XEXP (indexexp, 0);
1475 else
1476 scale = 0;
1477 if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= F0_REGNUM)
1478 abort ();
1480 #ifdef UTEK_ASM
1481 fprintf (file, "[%c`%s]",
1482 scales[scale],
1483 ns32k_out_reg_names[REGNO (indexexp)]);
1484 #else
1485 fprintf (file, "[%s:%c]",
1486 ns32k_out_reg_names[REGNO (indexexp)],
1487 scales[scale]);
1488 #endif
1492 /* National 32032 shifting is so bad that we can get
1493 better performance in many common cases by using other
1494 techniques. */
1495 const char *
1496 output_shift_insn (rtx *operands)
1498 if (GET_CODE (operands[2]) == CONST_INT
1499 && INTVAL (operands[2]) > 0
1500 && INTVAL (operands[2]) <= 3)
1502 if (GET_CODE (operands[0]) == REG)
1504 if (GET_CODE (operands[1]) == REG)
1506 if (REGNO (operands[0]) == REGNO (operands[1]))
1508 if (operands[2] == const1_rtx)
1509 return "addd %0,%0";
1510 else if (INTVAL (operands[2]) == 2)
1511 return "addd %0,%0\n\taddd %0,%0";
1513 if (operands[2] == const1_rtx)
1514 return "movd %1,%0\n\taddd %0,%0";
1516 operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
1517 return "addr %a1,%0";
1519 if (operands[2] == const1_rtx)
1520 return "movd %1,%0\n\taddd %0,%0";
1522 else if (GET_CODE (operands[1]) == REG)
1524 operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
1525 return "addr %a1,%0";
1527 else if (INTVAL (operands[2]) == 1
1528 && GET_CODE (operands[1]) == MEM
1529 && rtx_equal_p (operands [0], operands[1]))
1531 rtx temp = XEXP (operands[1], 0);
1533 if (GET_CODE (temp) == REG
1534 || (GET_CODE (temp) == PLUS
1535 && GET_CODE (XEXP (temp, 0)) == REG
1536 && GET_CODE (XEXP (temp, 1)) == CONST_INT))
1537 return "addd %0,%0";
1539 else return "ashd %2,%0";
1541 return "ashd %2,%0";
1544 const char *
1545 output_move_dconst (int n, const char *s)
1547 static char r[32];
1549 if (n > -9 && n < 8)
1550 strcpy (r, "movqd ");
1551 else if (n > 0 && n < 256)
1552 strcpy (r, "movzbd ");
1553 else if (n > 0 && n < 65536)
1554 strcpy (r, "movzwd ");
1555 else if (n < 0 && n > -129)
1556 strcpy (r, "movxbd ");
1557 else if (n < 0 && n > -32769)
1558 strcpy (r, "movxwd ");
1559 else
1560 strcpy (r, "movd ");
1561 strcat (r, s);
1562 return r;
1565 static rtx
1566 ns32k_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
1567 int incoming ATTRIBUTE_UNUSED)
1569 return gen_rtx_REG (Pmode, NS32K_STRUCT_VALUE_REGNUM);
1572 /* Worker function for NOTICE_UPDATE_CC. */
1574 void
1575 ns32k_notice_update_cc (rtx exp, rtx insn ATTRIBUTE_UNUSED)
1577 if (GET_CODE (exp) == SET)
1579 if (GET_CODE (SET_DEST (exp)) == CC0)
1581 cc_status.flags = 0;
1582 cc_status.value1 = SET_DEST (exp);
1583 cc_status.value2 = SET_SRC (exp);
1585 else if (GET_CODE (SET_SRC (exp)) == CALL)
1587 CC_STATUS_INIT;
1589 else if (GET_CODE (SET_DEST (exp)) == REG)
1591 if (cc_status.value1
1592 && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))
1593 cc_status.value1 = 0;
1594 if (cc_status.value2
1595 && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2))
1596 cc_status.value2 = 0;
1598 else if (GET_CODE (SET_DEST (exp)) == MEM)
1600 CC_STATUS_INIT;
1603 else if (GET_CODE (exp) == PARALLEL
1604 && GET_CODE (XVECEXP (exp, 0, 0)) == SET)
1606 if (GET_CODE (SET_DEST (XVECEXP (exp, 0, 0))) == CC0)
1608 cc_status.flags = 0;
1609 cc_status.value1 = SET_DEST (XVECEXP (exp, 0, 0));
1610 cc_status.value2 = SET_SRC (XVECEXP (exp, 0, 0));
1612 else if (GET_CODE (SET_DEST (XVECEXP (exp, 0, 0))) == REG)
1614 if (cc_status.value1
1615 && reg_overlap_mentioned_p (SET_DEST (XVECEXP (exp, 0, 0)),
1616 cc_status.value1))
1617 cc_status.value1 = 0;
1618 if (cc_status.value2
1619 && reg_overlap_mentioned_p (SET_DEST (XVECEXP (exp, 0, 0)),
1620 cc_status.value2))
1621 cc_status.value2 = 0;
1623 else if (GET_CODE (SET_DEST (XVECEXP (exp, 0, 0))) == MEM)
1625 CC_STATUS_INIT;
1628 else if (GET_CODE (exp) == CALL)
1630 /* all bets are off */
1631 CC_STATUS_INIT;
1633 else
1635 /* nothing happens? CC_STATUS_INIT; */
1637 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
1638 && cc_status.value2
1639 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
1640 abort ();