* tree-ssa-phiopt.c, config/arm/arm.c, config/fr30/fr30.md,
[official-gcc.git] / gcc / config / ns32k / ns32k.c
blob8cf3fa7d1cb069ae7a5cb3bb5053f12a72814e85
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 bool ns32k_handle_option (size_t, const char *, int);
68 static rtx gen_indexed_expr (rtx, rtx, rtx);
69 static const char *singlemove_string (rtx *);
70 static void move_tail (rtx[], int, int);
71 static tree ns32k_handle_fntype_attribute (tree *, tree, tree, int, bool *);
72 const struct attribute_spec ns32k_attribute_table[];
73 static void ns32k_output_function_prologue (FILE *, HOST_WIDE_INT);
74 static void ns32k_output_function_epilogue (FILE *, HOST_WIDE_INT);
75 static bool ns32k_rtx_costs (rtx, int, int, int *);
76 static int ns32k_address_cost (rtx);
77 static rtx ns32k_struct_value_rtx (tree, int);
78 static int ns32k_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
79 tree, bool);
81 /* Initialize the GCC target structure. */
82 #undef TARGET_ATTRIBUTE_TABLE
83 #define TARGET_ATTRIBUTE_TABLE ns32k_attribute_table
85 #undef TARGET_ASM_ALIGNED_HI_OP
86 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
88 #ifdef ENCORE_ASM
89 #undef TARGET_ASM_ALIGNED_SI_OP
90 #define TARGET_ASM_ALIGNED_SI_OP "\t.double\t"
91 #endif
93 #undef TARGET_ASM_FUNCTION_PROLOGUE
94 #define TARGET_ASM_FUNCTION_PROLOGUE ns32k_output_function_prologue
95 #undef TARGET_ASM_FUNCTION_EPILOGUE
96 #define TARGET_ASM_FUNCTION_EPILOGUE ns32k_output_function_epilogue
98 #undef TARGET_DEFAULT_TARGET_FLAGS
99 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
100 #undef TARGET_HANDLE_OPTION
101 #define TARGET_HANDLE_OPTION ns32k_handle_option
103 #undef TARGET_RTX_COSTS
104 #define TARGET_RTX_COSTS ns32k_rtx_costs
105 #undef TARGET_ADDRESS_COST
106 #define TARGET_ADDRESS_COST ns32k_address_cost
108 #undef TARGET_STRUCT_VALUE_RTX
109 #define TARGET_STRUCT_VALUE_RTX ns32k_struct_value_rtx
111 #undef TARGET_ARG_PARTIAL_BYTES
112 #define TARGET_ARG_PARTIAL_BYTES ns32k_arg_partial_bytes
114 #undef TARGET_ASM_FILE_START_APP_OFF
115 #define TARGET_ASM_FILE_START_APP_OFF true
117 struct gcc_target targetm = TARGET_INITIALIZER;
119 /* Implement TARGET_HANDLE_OPTION. */
121 static bool
122 ns32k_handle_option (size_t code, const char *arg ATTRIBUTE_UNUSED,
123 int value ATTRIBUTE_UNUSED)
125 switch (code)
127 case OPT_m32081:
128 target_flags &= ~MASK_32381;
129 return true;
131 case OPT_msoft_float:
132 target_flags &= ~(MASK_32081 | MASK_32381);
133 return true;
135 case OPT_m32332:
136 target_flags &= ~MASK_32532;
137 return true;
139 case OPT_m32032:
140 target_flags &= ~(MASK_32332 | MASK_32532);
141 return true;
143 default:
144 return true;
148 /* Generate the assembly code for function entry. FILE is a stdio
149 stream to output the code to. SIZE is an int: how many units of
150 temporary storage to allocate.
152 Refer to the array `regs_ever_live' to determine which registers to
153 save; `regs_ever_live[I]' is nonzero if register number I is ever
154 used in the function. This function is responsible for knowing
155 which registers should not be saved even if used. */
158 * The function prologue for the ns32k is fairly simple.
159 * If a frame pointer is needed (decided in reload.c ?) then
160 * we need assembler of the form
162 * # Save the oldframe pointer, set the new frame pointer, make space
163 * # on the stack and save any general purpose registers necessary
165 * enter [<general purpose regs to save>], <local stack space>
167 * movf fn, tos # Save any floating point registers necessary
171 * If a frame pointer is not needed we need assembler of the form
173 * # Make space on the stack
175 * adjspd <local stack space + 4>
177 * # Save any general purpose registers necessary
179 * save [<general purpose regs to save>]
181 * movf fn, tos # Save any floating point registers necessary
186 #if !defined (MERLIN_TARGET) && !defined (UTEK_ASM)
188 #if defined(IMMEDIATE_PREFIX) && IMMEDIATE_PREFIX
189 #define ADJSP(FILE, N) \
190 fprintf (FILE, "\tadjspd %c" HOST_WIDE_INT_PRINT_DEC "\n", IMMEDIATE_PREFIX, (N))
191 #else
192 #define ADJSP(FILE, N) \
193 fprintf (FILE, "\tadjspd " HOST_WIDE_INT_PRINT_DEC "\n", (N))
194 #endif
196 static void
197 ns32k_output_function_prologue (FILE *file, HOST_WIDE_INT size)
199 register int regno, g_regs_used = 0;
200 int used_regs_buf[8], *bufp = used_regs_buf;
201 int used_fregs_buf[17], *fbufp = used_fregs_buf;
203 for (regno = R0_REGNUM; regno < F0_REGNUM; regno++)
204 if (regs_ever_live[regno]
205 && ! call_used_regs[regno])
207 *bufp++ = regno; g_regs_used++;
209 *bufp = -1;
211 for (; regno < FRAME_POINTER_REGNUM; regno++)
212 if (regs_ever_live[regno] && !call_used_regs[regno])
214 *fbufp++ = regno;
216 *fbufp = -1;
218 bufp = used_regs_buf;
219 if (frame_pointer_needed)
220 fprintf (file, "\tenter [");
221 else
223 if (size)
224 ADJSP (file, size + 4);
225 if (g_regs_used && g_regs_used > 4)
226 fprintf (file, "\tsave [");
227 else
229 while (*bufp >= 0)
230 fprintf (file, "\tmovd r%d,tos\n", *bufp++);
231 g_regs_used = 0;
235 while (*bufp >= 0)
237 fprintf (file, "r%d", *bufp++);
238 if (*bufp >= 0)
239 fputc (',', file);
242 if (frame_pointer_needed)
243 fprintf (file, "]," HOST_WIDE_INT_PRINT_DEC "\n", size);
244 else if (g_regs_used)
245 fprintf (file, "]\n");
247 fbufp = used_fregs_buf;
248 while (*fbufp >= 0)
250 if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1))
251 fprintf (file, "\tmovf %s,tos\n", ns32k_out_reg_names[*fbufp++]);
252 else
254 fprintf (file, "\tmovl %s,tos\n",
255 ns32k_out_reg_names[fbufp[0]]);
256 fbufp += 2;
260 if (flag_pic && current_function_uses_pic_offset_table)
262 fprintf (file, "\tsprd sb,tos\n");
263 if (TARGET_REGPARM)
265 fprintf (file, "\taddr __GLOBAL_OFFSET_TABLE_(pc),tos\n");
266 fprintf (file, "\tlprd sb,tos\n");
268 else
270 fprintf (file, "\taddr __GLOBAL_OFFSET_TABLE_(pc),r0\n");
271 fprintf (file, "\tlprd sb,r0\n");
276 #else /* MERLIN_TARGET || UTEK_ASM */
278 /* This differs from the standard one above in printing a bitmask
279 rather than a register list in the enter or save instruction. */
281 static void
282 ns32k_output_function_prologue (file, size)
283 FILE *file;
284 HOST_WIDE_INT size;
286 register int regno, g_regs_used = 0;
287 int used_regs_buf[8], *bufp = used_regs_buf;
288 int used_fregs_buf[8], *fbufp = used_fregs_buf;
290 for (regno = 0; regno < 8; regno++)
291 if (regs_ever_live[regno]
292 && ! call_used_regs[regno])
294 *bufp++ = regno; g_regs_used++;
296 *bufp = -1;
298 for (; regno < 16; regno++)
299 if (regs_ever_live[regno] && !call_used_regs[regno]) {
300 *fbufp++ = regno;
302 *fbufp = -1;
304 bufp = used_regs_buf;
305 if (frame_pointer_needed)
306 fprintf (file, "\tenter ");
307 else if (g_regs_used)
308 fprintf (file, "\tsave ");
310 if (frame_pointer_needed || g_regs_used)
312 char mask = 0;
313 while (*bufp >= 0)
314 mask |= 1 << *bufp++;
315 fprintf (file, "$0x%x", (int) mask & 0xff);
318 if (frame_pointer_needed)
319 #ifdef UTEK_ASM
320 fprintf (file, ",$%d\n", size);
321 #else
322 fprintf (file, ",%d\n", size);
323 #endif
324 else if (g_regs_used)
325 fprintf (file, "\n");
327 fbufp = used_fregs_buf;
328 while (*fbufp >= 0)
330 if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1))
331 fprintf (file, "\tmovf f%d,tos\n", *fbufp++ - 8);
332 else
334 fprintf (file, "\tmovl f%d,tos\n", fbufp[0] - 8);
335 fbufp += 2;
340 #endif /* MERLIN_TARGET || UTEK_ASM */
342 /* This function generates the assembly code for function exit,
343 on machines that need it.
345 The function epilogue should not depend on the current stack pointer,
346 if EXIT_IGNORE_STACK is nonzero. That doesn't apply here.
348 If a frame pointer is needed (decided in reload.c ?) then
349 we need assembler of the form
351 movf tos, fn # Restore any saved floating point registers
355 # Restore any saved general purpose registers, restore the stack
356 # pointer from the frame pointer, restore the old frame pointer.
357 exit [<general purpose regs to save>]
359 If a frame pointer is not needed we need assembler of the form
360 # Restore any general purpose registers saved
362 movf tos, fn # Restore any saved floating point registers
366 restore [<general purpose regs to save>]
368 # reclaim space allocated on stack
370 adjspd <-(local stack space + 4)> */
372 #if !defined (MERLIN_TARGET) && !defined (UTEK_ASM)
374 static void
375 ns32k_output_function_epilogue (FILE *file, HOST_WIDE_INT size)
377 register int regno, g_regs_used = 0, f_regs_used = 0;
378 int used_regs_buf[8], *bufp = used_regs_buf;
379 int used_fregs_buf[17], *fbufp = used_fregs_buf;
381 if (flag_pic && current_function_uses_pic_offset_table)
382 fprintf (file, "\tlprd sb,tos\n");
384 *fbufp++ = -2;
385 for (regno = F0_REGNUM; regno < FRAME_POINTER_REGNUM; regno++)
386 if (regs_ever_live[regno] && !call_used_regs[regno])
388 *fbufp++ = regno; f_regs_used++;
390 fbufp--;
392 for (regno = 0; regno < F0_REGNUM; regno++)
393 if (regs_ever_live[regno]
394 && ! call_used_regs[regno])
396 *bufp++ = regno; g_regs_used++;
399 while (fbufp > used_fregs_buf)
401 if ((*fbufp & 1) && fbufp[0] == fbufp[-1] + 1)
403 fprintf (file, "\tmovl tos,%s\n",
404 ns32k_out_reg_names[fbufp[-1]]);
405 fbufp -= 2;
407 else fprintf (file, "\tmovf tos,%s\n", ns32k_out_reg_names[*fbufp--]);
410 if (frame_pointer_needed)
411 fprintf (file, "\texit [");
412 else
414 if (g_regs_used && g_regs_used > 4)
415 fprintf (file, "\trestore [");
416 else
418 while (bufp > used_regs_buf)
419 fprintf (file, "\tmovd tos,r%d\n", *--bufp);
420 g_regs_used = 0;
424 while (bufp > used_regs_buf)
426 fprintf (file, "r%d", *--bufp);
427 if (bufp > used_regs_buf)
428 fputc (',', file);
431 if (g_regs_used || frame_pointer_needed)
432 fprintf (file, "]\n");
434 if (size && !frame_pointer_needed)
435 ADJSP (file, -(size + 4));
437 if (current_function_pops_args)
438 fprintf (file, "\tret %d\n", current_function_pops_args);
439 else
440 fprintf (file, "\tret 0\n");
443 #else /* MERLIN_TARGET || UTEK_ASM */
445 /* This differs from the standard one above in printing a bitmask
446 rather than a register list in the exit or restore instruction. */
448 static void
449 ns32k_output_function_epilogue (file, size)
450 FILE *file;
451 HOST_WIDE_INT size ATTRIBUTE_UNUSED;
453 register int regno, g_regs_used = 0, f_regs_used = 0;
454 int used_regs_buf[8], *bufp = used_regs_buf;
455 int used_fregs_buf[8], *fbufp = used_fregs_buf;
457 *fbufp++ = -2;
458 for (regno = 8; regno < 16; regno++)
459 if (regs_ever_live[regno] && !call_used_regs[regno]) {
460 *fbufp++ = regno; f_regs_used++;
462 fbufp--;
464 for (regno = 0; regno < 8; regno++)
465 if (regs_ever_live[regno]
466 && ! call_used_regs[regno])
468 *bufp++ = regno; g_regs_used++;
471 while (fbufp > used_fregs_buf)
473 if ((*fbufp & 1) && fbufp[0] == fbufp[-1] + 1)
475 fprintf (file, "\tmovl tos,f%d\n", fbufp[-1] - 8);
476 fbufp -= 2;
478 else fprintf (file, "\tmovf tos,f%d\n", *fbufp-- - 8);
481 if (frame_pointer_needed)
482 fprintf (file, "\texit ");
483 else if (g_regs_used)
484 fprintf (file, "\trestore ");
486 if (g_regs_used || frame_pointer_needed)
488 char mask = 0;
490 while (bufp > used_regs_buf)
492 /* Utek assembler takes care of reversing this */
493 mask |= 1 << *--bufp;
495 fprintf (file, "$0x%x\n", (int) mask & 0xff);
498 #ifdef UTEK_ASM
499 if (current_function_pops_args)
500 fprintf (file, "\tret $%d\n", current_function_pops_args);
501 else
502 fprintf (file, "\tret $0\n");
503 #else
504 if (current_function_pops_args)
505 fprintf (file, "\tret %d\n", current_function_pops_args);
506 else
507 fprintf (file, "\tret 0\n");
508 #endif
511 #endif /* MERLIN_TARGET || UTEK_ASM */
513 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */
515 hard_regno_mode_ok (int regno, enum machine_mode mode)
517 int size = GET_MODE_UNIT_SIZE (mode);
519 if (FLOAT_MODE_P (mode))
521 if (size == UNITS_PER_WORD && regno < L1_REGNUM)
522 return 1;
523 if (size == UNITS_PER_WORD * 2
524 && (((regno & 1) == 0 && regno < FRAME_POINTER_REGNUM)))
525 return 1;
526 return 0;
528 if (size == UNITS_PER_WORD * 2
529 && (regno & 1) == 0 && regno < F0_REGNUM)
530 return 1;
531 if (size <= UNITS_PER_WORD
532 && (regno < F0_REGNUM || regno == FRAME_POINTER_REGNUM
533 || regno == STACK_POINTER_REGNUM))
534 return 1;
535 return 0;
538 static bool
539 ns32k_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total)
541 switch (code)
543 case CONST_INT:
544 if (INTVAL (x) <= 7 && INTVAL (x) >= -8)
545 *total = 0;
546 else if (INTVAL (x) < 0x2000 && INTVAL (x) >= -0x2000)
547 *total = 1;
548 else
549 *total = 3;
550 return true;
552 case CONST:
553 case LABEL_REF:
554 case SYMBOL_REF:
555 *total = 3;
556 return true;
558 case CONST_DOUBLE:
559 *total = 5;
560 return true;
562 default:
563 return false;
568 register_move_cost (enum reg_class CLASS1, enum reg_class CLASS2)
570 if (CLASS1 == NO_REGS || CLASS2 == NO_REGS)
571 return 2;
572 if ((SUBSET_P (CLASS1, FP_REGS) && !SUBSET_P (CLASS2, FP_REGS))
573 || (!SUBSET_P (CLASS1, FP_REGS) && SUBSET_P (CLASS2, FP_REGS)))
574 return 8;
575 if (((CLASS1) == STACK_POINTER_REG && !SUBSET_P (CLASS2,GENERAL_REGS))
576 || ((CLASS2) == STACK_POINTER_REG && !SUBSET_P (CLASS1,GENERAL_REGS)))
577 return 6;
578 if (((CLASS1) == FRAME_POINTER_REG && !SUBSET_P (CLASS2,GENERAL_REGS))
579 || ((CLASS2) == FRAME_POINTER_REG && !SUBSET_P (CLASS1,GENERAL_REGS)))
580 return 6;
581 return 2;
584 #if 0
585 /* We made the insn definitions copy from floating point to general
586 registers via the stack. */
588 secondary_memory_needed (enum reg_class CLASS1,
589 enum reg_class CLASS2,
590 enum machine_mode M)
592 int ret = ((SUBSET_P (CLASS1, FP_REGS) && !SUBSET_P (CLASS2, FP_REGS))
593 || (!SUBSET_P (CLASS1, FP_REGS) && SUBSET_P (CLASS2, FP_REGS)));
594 return ret;
596 #endif
599 /* TARGET_ADDRESS_COST calls this. This function is not optimal
600 for the 32032 & 32332, but it probably is better than
601 the default. */
603 static int
604 ns32k_address_cost (rtx operand)
606 int cost = 0;
608 switch (GET_CODE (operand))
610 case REG:
611 cost += 1;
612 break;
614 case POST_DEC:
615 case PRE_DEC:
616 break;
618 case CONST_INT:
619 if (INTVAL (operand) <= 7 && INTVAL (operand) >= -8)
620 break;
621 if (INTVAL (operand) < 0x2000 && INTVAL (operand) >= -0x2000)
623 cost +=1;
624 break;
626 case CONST:
627 case LABEL_REF:
628 case SYMBOL_REF:
629 cost +=3;
630 break;
631 case CONST_DOUBLE:
632 cost += 5;
633 break;
635 case MEM:
636 cost += ns32k_address_cost (XEXP (operand, 0)) + 3;
637 break;
639 case MULT:
640 cost += 2;
641 /* FALLTHRU */
642 case PLUS:
643 cost += ns32k_address_cost (XEXP (operand, 0));
644 cost += ns32k_address_cost (XEXP (operand, 1));
645 break;
647 default:
648 break;
651 return cost;
654 /* Return the register class of a scratch register needed to copy IN into
655 or out of a register in CLASS in MODE. If it can be done directly,
656 NO_REGS is returned. */
658 enum reg_class
659 secondary_reload_class (enum reg_class class,
660 enum machine_mode mode ATTRIBUTE_UNUSED,
661 rtx in)
663 int regno = true_regnum (in);
665 if (regno >= FIRST_PSEUDO_REGISTER)
666 regno = -1;
668 if ((class == FRAME_POINTER_REG && regno == STACK_POINTER_REGNUM)
669 || ( class == STACK_POINTER_REG && regno == FRAME_POINTER_REGNUM))
670 return GENERAL_REGS;
671 else
672 return NO_REGS;
675 /* Generate the rtx that comes from an address expression in the md file */
676 /* The expression to be build is BASE[INDEX:SCALE]. To recognize this,
677 scale must be converted from an exponent (from ASHIFT) to a
678 multiplier (for MULT). */
680 static rtx
681 gen_indexed_expr (rtx base, rtx index, rtx scale)
683 rtx addr;
685 /* This generates an invalid addressing mode, if BASE is
686 fp or sp. This is handled by PRINT_OPERAND_ADDRESS. */
687 if (GET_CODE (base) != REG && GET_CODE (base) != CONST_INT)
688 base = gen_rtx_MEM (SImode, base);
689 addr = gen_rtx_MULT (SImode, index,
690 GEN_INT (1 << INTVAL (scale)));
691 addr = gen_rtx_PLUS (SImode, base, addr);
692 return addr;
696 /* Split one or more DImode RTL references into pairs of SImode
697 references. The RTL can be REG, offsettable MEM, integer constant, or
698 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
699 split and "num" is its length. lo_half and hi_half are output arrays
700 that parallel "operands". */
702 void
703 split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
705 while (num--)
707 if (GET_CODE (operands[num]) == REG)
709 lo_half[num] = gen_rtx_REG (SImode, REGNO (operands[num]));
710 hi_half[num] = gen_rtx_REG (SImode, REGNO (operands[num]) + 1);
712 else if (CONSTANT_P (operands[num]))
714 split_double (operands[num], &lo_half[num], &hi_half[num]);
716 else if (offsettable_memref_p (operands[num]))
718 lo_half[num] = operands[num];
719 hi_half[num] = adjust_address (operands[num], SImode, 4);
721 else
722 abort ();
726 /* Return the best assembler insn template
727 for moving operands[1] into operands[0] as a fullword. */
729 static const char *
730 singlemove_string (rtx *operands)
732 if (GET_CODE (operands[1]) == CONST_INT
733 && INTVAL (operands[1]) <= 7
734 && INTVAL (operands[1]) >= -8)
735 return "movqd %1,%0";
736 return "movd %1,%0";
739 const char *
740 output_move_double (rtx *operands)
742 enum anon1 { REGOP, OFFSOP, PUSHOP, CNSTOP, RNDOP } optype0, optype1;
743 rtx latehalf[2];
745 /* First classify both operands. */
747 if (REG_P (operands[0]))
748 optype0 = REGOP;
749 else if (offsettable_memref_p (operands[0]))
750 optype0 = OFFSOP;
751 else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
752 optype0 = PUSHOP;
753 else
754 optype0 = RNDOP;
756 if (REG_P (operands[1]))
757 optype1 = REGOP;
758 else if (CONSTANT_P (operands[1])
759 || GET_CODE (operands[1]) == CONST_DOUBLE)
760 optype1 = CNSTOP;
761 else if (offsettable_memref_p (operands[1]))
762 optype1 = OFFSOP;
763 else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
764 optype1 = PUSHOP;
765 else
766 optype1 = RNDOP;
768 /* Check for the cases that the operand constraints are not
769 supposed to allow to happen. Abort if we get one,
770 because generating code for these cases is painful. */
772 if (optype0 == RNDOP || optype1 == RNDOP)
773 abort ();
775 /* Ok, we can do one word at a time.
776 Normally we do the low-numbered word first,
777 but if either operand is autodecrementing then we
778 do the high-numbered word first.
780 In either case, set up in LATEHALF the operands to use
781 for the high-numbered word and in some cases alter the
782 operands in OPERANDS to be suitable for the low-numbered word. */
784 if (optype0 == REGOP)
785 latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
786 else if (optype0 == OFFSOP)
787 latehalf[0] = adjust_address (operands[0], SImode, 4);
788 else
789 latehalf[0] = operands[0];
791 if (optype1 == REGOP)
792 latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
793 else if (optype1 == OFFSOP)
794 latehalf[1] = adjust_address (operands[1], SImode, 4);
795 else if (optype1 == CNSTOP)
796 split_double (operands[1], &operands[1], &latehalf[1]);
797 else
798 latehalf[1] = operands[1];
800 /* If insn is effectively movd N(sp),tos then we will do the
801 high word first. We should use the adjusted operand 1 (which is N+4(sp))
802 for the low word as well, to compensate for the first decrement of sp.
803 Given this, it doesn't matter which half we do "first". */
804 if (optype0 == PUSHOP
805 && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
806 && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
807 operands[1] = latehalf[1];
809 /* If one or both operands autodecrementing,
810 do the two words, high-numbered first. */
811 else if (optype0 == PUSHOP || optype1 == PUSHOP)
813 output_asm_insn (singlemove_string (latehalf), latehalf);
814 return singlemove_string (operands);
817 /* If the first move would clobber the source of the second one,
818 do them in the other order. */
820 /* Overlapping registers. */
821 if (optype0 == REGOP && optype1 == REGOP
822 && REGNO (operands[0]) == REGNO (latehalf[1]))
824 /* Do that word. */
825 output_asm_insn (singlemove_string (latehalf), latehalf);
826 /* Do low-numbered word. */
827 return singlemove_string (operands);
829 /* Loading into a register which overlaps a register used in the address. */
830 else if (optype0 == REGOP && optype1 != REGOP
831 && reg_overlap_mentioned_p (operands[0], operands[1]))
833 if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
834 && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
836 /* If both halves of dest are used in the src memory address,
837 load the destination address into the low reg (operands[0]).
838 Then it works to load latehalf first. */
839 rtx xops[2];
840 xops[0] = XEXP (operands[1], 0);
841 xops[1] = operands[0];
842 output_asm_insn ("addr %a0,%1", xops);
843 operands[1] = gen_rtx_MEM (DImode, operands[0]);
844 latehalf[1] = adjust_address (operands[1], SImode, 4);
845 /* The first half has the overlap, Do the late half first. */
846 output_asm_insn (singlemove_string (latehalf), latehalf);
847 /* Then clobber. */
848 return singlemove_string (operands);
850 if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)))
852 /* The first half has the overlap, Do the late half first. */
853 output_asm_insn (singlemove_string (latehalf), latehalf);
854 /* Then clobber. */
855 return singlemove_string (operands);
859 /* Normal case. Do the two words, low-numbered first. */
861 output_asm_insn (singlemove_string (operands), operands);
863 operands[0] = latehalf[0];
864 operands[1] = latehalf[1];
865 return singlemove_string (operands);
869 #define MAX_UNALIGNED_COPY (32)
870 /* Expand string/block move operations.
872 operands[0] is the pointer to the destination.
873 operands[1] is the pointer to the source.
874 operands[2] is the number of bytes to move.
875 operands[3] is the alignment. */
877 static void
878 move_tail (rtx operands[], int bytes, int offset)
880 if (bytes & 2)
882 emit_move_insn (adjust_address (operands[0], HImode, offset),
883 adjust_address (operands[1], HImode, offset));
884 offset += 2;
886 if (bytes & 1)
887 emit_move_insn (adjust_address (operands[0], QImode, offset),
888 adjust_address (operands[1], QImode, offset));
891 void
892 expand_block_move (rtx operands[])
894 rtx bytes_rtx = operands[2];
895 rtx align_rtx = operands[3];
896 int constp = (GET_CODE (bytes_rtx) == CONST_INT);
897 int bytes = (constp ? INTVAL (bytes_rtx) : 0);
898 int align = INTVAL (align_rtx);
899 rtx src_reg = gen_rtx_REG (Pmode, 1);
900 rtx dest_reg = gen_rtx_REG (Pmode, 2);
901 rtx count_reg = gen_rtx_REG (SImode, 0);
903 if (constp && bytes <= 0)
904 return;
906 if (constp && bytes < 20)
908 int words = bytes >> 2;
910 if (words)
912 if (words < 3)
914 int offset = 0;
916 for (; words; words--, offset += 4)
917 emit_move_insn (adjust_address (operands[0], SImode, offset),
918 adjust_address (operands[1], SImode, offset));
920 else
922 /* Use movmd. It is slower than multiple movd's but more
923 compact. It is also slower than movsd for large copies
924 but causes less registers reloading so is better than movsd
925 for small copies. */
926 rtx src, dest;
927 dest = copy_addr_to_reg (XEXP (operands[0], 0));
928 src = copy_addr_to_reg (XEXP (operands[1], 0));
930 emit_insn (gen_movmemsi2(dest, src, GEN_INT (words)));
933 move_tail (operands, bytes & 3, bytes & ~3);
934 return;
937 if (align > UNITS_PER_WORD)
938 align = UNITS_PER_WORD;
940 /* Move the address into scratch registers. */
941 emit_insn (gen_rtx_CLOBBER (VOIDmode, dest_reg));
942 emit_move_insn (dest_reg, XEXP (operands[0], 0));
943 operands[0] = gen_rtx_MEM (SImode, dest_reg);
944 emit_insn (gen_rtx_CLOBBER (VOIDmode, src_reg));
945 emit_move_insn (src_reg, XEXP (operands[1], 0));
946 operands[1] = gen_rtx_MEM (SImode, src_reg);
947 emit_insn (gen_rtx_CLOBBER (VOIDmode, count_reg));
949 if (constp && (align == UNITS_PER_WORD || bytes < MAX_UNALIGNED_COPY))
951 /* constant no of bytes and aligned or small enough copy to not bother
952 * aligning. Emit insns to copy by words.
954 if (bytes >> 2)
956 emit_move_insn (count_reg, GEN_INT (bytes >> 2));
957 emit_insn (gen_movmemsi1 (GEN_INT (4)));
959 /* insns to copy rest */
960 move_tail (operands, bytes & 3, 0);
962 else if (align == UNITS_PER_WORD)
964 /* insns to copy by words */
965 emit_insn (gen_lshrsi3 (count_reg, bytes_rtx, const2_rtx));
966 emit_insn (gen_movmemsi1 (GEN_INT (4)));
967 if (constp)
969 move_tail (operands, bytes & 3, 0);
971 else
973 /* insns to copy rest */
974 emit_insn (gen_andsi3 (count_reg, bytes_rtx, GEN_INT (3)));
975 emit_insn (gen_movmemsi1 (const1_rtx));
978 else
980 /* Not aligned and we may have a lot to copy so it is worth
981 * aligning.
983 rtx aligned_label = gen_label_rtx ();
984 rtx bytes_reg;
986 bytes_reg = copy_to_mode_reg (SImode, bytes_rtx);
987 if (!constp)
989 /* Emit insns to test and skip over the alignment if it is
990 * not worth it. This doubles as a test to ensure that the alignment
991 * operation can't copy too many bytes
993 emit_insn (gen_cmpsi (bytes_reg, GEN_INT (MAX_UNALIGNED_COPY)));
994 emit_jump_insn (gen_blt (aligned_label));
997 /* Emit insns to do alignment at run time */
998 emit_insn (gen_negsi2 (count_reg, src_reg));
999 emit_insn (gen_andsi3 (count_reg, count_reg, GEN_INT (3)));
1000 emit_insn (gen_subsi3 (bytes_reg, bytes_reg, count_reg));
1001 emit_insn (gen_movmemsi1 (const1_rtx));
1002 if (!constp)
1003 emit_label (aligned_label);
1005 /* insns to copy by words */
1006 emit_insn (gen_lshrsi3 (count_reg, bytes_reg, const2_rtx));
1007 emit_insn (gen_movmemsi1 (GEN_INT (4)));
1009 /* insns to copy rest */
1010 emit_insn (gen_andsi3 (count_reg, bytes_reg, GEN_INT (3)));
1011 emit_insn (gen_movmemsi1 (const1_rtx));
1016 /* Returns 1 if OP contains a global symbol reference */
1019 global_symbolic_reference_mentioned_p (rtx op, int f)
1021 register const char *fmt;
1022 register int i;
1024 if (GET_CODE (op) == SYMBOL_REF)
1026 if (! SYMBOL_REF_LOCAL_P (op))
1027 return 1;
1028 else
1029 return 0;
1031 else if (f && GET_CODE (op) != CONST)
1032 return 0;
1034 fmt = GET_RTX_FORMAT (GET_CODE (op));
1035 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
1037 if (fmt[i] == 'E')
1039 register int j;
1041 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
1042 if (global_symbolic_reference_mentioned_p (XVECEXP (op, i, j), 0))
1043 return 1;
1045 else if (fmt[i] == 'e'
1046 && global_symbolic_reference_mentioned_p (XEXP (op, i), 0))
1047 return 1;
1050 return 0;
1054 /* Returns 1 if OP contains a symbol reference */
1057 symbolic_reference_mentioned_p (rtx op)
1059 register const char *fmt;
1060 register int i;
1062 if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
1063 return 1;
1065 fmt = GET_RTX_FORMAT (GET_CODE (op));
1066 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
1068 if (fmt[i] == 'E')
1070 register int j;
1072 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
1073 if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
1074 return 1;
1076 else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
1077 return 1;
1080 return 0;
1083 /* Table of machine-specific attributes. */
1085 const struct attribute_spec ns32k_attribute_table[] =
1087 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
1088 /* Stdcall attribute says callee is responsible for popping arguments
1089 if they are not variable. */
1090 { "stdcall", 0, 0, false, true, true, ns32k_handle_fntype_attribute },
1091 /* Cdecl attribute says the callee is a normal C declaration */
1092 { "cdecl", 0, 0, false, true, true, ns32k_handle_fntype_attribute },
1093 { NULL, 0, 0, false, false, false, NULL }
1096 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1097 arguments as in struct attribute_spec.handler. */
1098 static tree
1099 ns32k_handle_fntype_attribute (tree *node, tree name,
1100 tree args ATTRIBUTE_UNUSED,
1101 int flags ATTRIBUTE_UNUSED,
1102 bool *no_add_attrs)
1104 if (TREE_CODE (*node) != FUNCTION_TYPE
1105 && TREE_CODE (*node) != FIELD_DECL
1106 && TREE_CODE (*node) != TYPE_DECL)
1108 warning ("%qs attribute only applies to functions",
1109 IDENTIFIER_POINTER (name));
1110 *no_add_attrs = true;
1113 return NULL_TREE;
1117 /* Value is the number of bytes of arguments automatically
1118 popped when returning from a subroutine call.
1119 FUNDECL is the declaration node of the function (as a tree),
1120 FUNTYPE is the data type of the function (as a tree),
1121 or for a library call it is an identifier node for the subroutine name.
1122 SIZE is the number of bytes of arguments passed on the stack.
1124 On the ns32k, the RET insn may be used to pop them if the number
1125 of args is fixed, but if the number is variable then the caller
1126 must pop them all. RET can't be used for library calls now
1127 because the library is compiled with the Unix compiler.
1128 Use of RET is a selectable option, since it is incompatible with
1129 standard Unix calling sequences. If the option is not selected,
1130 the caller must always pop the args.
1132 The attribute stdcall is equivalent to RET on a per module basis. */
1135 ns32k_return_pops_args (tree fundecl ATTRIBUTE_UNUSED, tree funtype, int size)
1137 int rtd = TARGET_RTD;
1139 if (TREE_CODE (funtype) == IDENTIFIER_NODE)
1140 return rtd ? size : 0;
1142 /* Cdecl functions override -mrtd, and never pop the stack */
1143 if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype)))
1144 return 0;
1146 /* Stdcall functions will pop the stack if not variable args */
1147 if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype)))
1148 rtd = 1;
1150 if (rtd)
1152 if (TYPE_ARG_TYPES (funtype) == NULL_TREE
1153 || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node))
1154 return size;
1157 return 0;
1160 /* PRINT_OPERAND is defined to call this function,
1161 which is easier to debug than putting all the code in
1162 a macro definition in ns32k.h. */
1164 /* XXX time 12% of cpu time is in fprintf for non optimizing */
1165 void
1166 print_operand (FILE *file, rtx x, int code)
1168 if (code == '$')
1169 PUT_IMMEDIATE_PREFIX (file);
1170 else if (code == '?')
1171 PUT_EXTERNAL_PREFIX (file);
1172 else if (GET_CODE (x) == REG)
1173 fprintf (file, "%s", ns32k_out_reg_names[REGNO (x)]);
1174 else if (GET_CODE (x) == MEM)
1176 output_address (XEXP (x, 0));
1178 else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != VOIDmode)
1180 REAL_VALUE_TYPE r;
1182 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1183 PUT_IMMEDIATE_PREFIX (file);
1184 if (GET_MODE (x) == DFmode)
1186 #ifdef SEQUENT_ASM
1187 /* Sequent likes its floating point constants as integers */
1188 long l[2];
1189 REAL_VALUE_TO_TARGET_DOUBLE (r, l);
1190 fprintf (file, "0Dx%08x%08x",
1191 l[!WORDS_BIG_ENDIAN], l[WORDS_BIG_ENDIAN]);
1192 #else
1193 char s[30];
1194 real_to_decimal (s, &r, sizeof (s), 0, 1);
1195 #ifdef ENCORE_ASM
1196 fprintf (file, "0f%s", s);
1197 #else
1198 fprintf (file, "0d%s", s);
1199 #endif
1200 #endif
1202 else
1204 #ifdef SEQUENT_ASM
1205 long l;
1206 REAL_VALUE_TO_TARGET_SINGLE (r, l);
1207 fprintf (file, "0Fx%08lx", l);
1208 #else
1209 char s[30];
1210 real_to_decimal (s, &r, sizeof (s), 0, 1);
1211 fprintf (file, "0f%s", s);
1212 #endif
1215 else
1217 if (flag_pic
1218 && GET_CODE (x) == CONST
1219 && symbolic_reference_mentioned_p (x))
1221 fprintf (stderr, "illegal constant for pic-mode: \n");
1222 print_rtl (stderr, x);
1223 fprintf (stderr, "\nGET_CODE (x) == %d, CONST == %d, symbolic_reference_mentioned_p (x) == %d\n",
1224 GET_CODE (x), CONST, symbolic_reference_mentioned_p (x));
1225 abort ();
1227 else if (flag_pic
1228 && (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF))
1230 output_addr_const (file, x);
1231 fprintf (file, "(sb)");
1233 else
1235 #ifdef NO_IMMEDIATE_PREFIX_IF_SYMBOLIC
1236 if (GET_CODE (x) == CONST_INT)
1237 #endif
1238 PUT_IMMEDIATE_PREFIX (file);
1239 output_addr_const (file, x);
1244 /* PRINT_OPERAND_ADDRESS is defined to call this function,
1245 which is easier to debug than putting all the code in
1246 a macro definition in ns32k.h . */
1248 /* Completely rewritten to get this to work with Gas for PC532 Mach.
1249 This function didn't work and I just wasn't able (nor very willing) to
1250 figure out how it worked.
1251 90-11-25 Tatu Yl|nen <ylo@cs.hut.fi> */
1253 void
1254 print_operand_address (register FILE *file, register rtx addr)
1256 static const char scales[] = { 'b', 'w', 'd', 0, 'q', };
1257 rtx offset, base, indexexp, tmp;
1258 int scale;
1259 extern int flag_pic;
1261 if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == POST_DEC)
1263 fprintf (file, "tos");
1264 return;
1267 offset = NULL;
1268 base = NULL;
1269 indexexp = NULL;
1270 while (addr != NULL)
1272 if (GET_CODE (addr) == PLUS)
1274 if (GET_CODE (XEXP (addr, 0)) == PLUS)
1276 tmp = XEXP (addr, 1);
1277 addr = XEXP (addr, 0);
1279 else
1281 tmp = XEXP (addr,0);
1282 addr = XEXP (addr,1);
1285 else
1287 tmp = addr;
1288 addr = NULL;
1290 switch (GET_CODE (tmp))
1292 case PLUS:
1293 abort ();
1294 case MEM:
1295 if (base)
1297 indexexp = base;
1298 base = tmp;
1300 else
1301 base = tmp;
1302 break;
1303 case REG:
1304 if (REGNO (tmp) < F0_REGNUM)
1305 if (base)
1307 indexexp = tmp;
1309 else
1310 base = tmp;
1311 else
1312 if (base)
1314 indexexp = base;
1315 base = tmp;
1317 else
1318 base = tmp;
1319 break;
1320 case MULT:
1321 indexexp = tmp;
1322 break;
1323 case SYMBOL_REF:
1324 if (flag_pic && ! SYMBOL_REF_LOCAL_P (tmp))
1326 if (base)
1328 if (indexexp)
1329 abort ();
1330 indexexp = base;
1332 base = tmp;
1333 break;
1335 case CONST:
1336 if (flag_pic && GET_CODE (tmp) == CONST)
1338 rtx sym, off, tmp1;
1339 tmp1 = XEXP (tmp,0);
1340 if (GET_CODE (tmp1) != PLUS)
1341 abort ();
1343 sym = XEXP (tmp1,0);
1344 if (GET_CODE (sym) != SYMBOL_REF)
1346 off = sym;
1347 sym = XEXP (tmp1,1);
1349 else
1350 off = XEXP (tmp1,1);
1351 if (GET_CODE (sym) == SYMBOL_REF)
1353 if (GET_CODE (off) != CONST_INT)
1354 abort ();
1356 if (! SYMBOL_REF_LOCAL_P (sym))
1358 if (base)
1360 if (indexexp)
1361 abort ();
1363 indexexp = base;
1366 if (offset != 0)
1367 abort ();
1369 base = sym;
1370 offset = off;
1371 break;
1375 case CONST_INT:
1376 case LABEL_REF:
1377 if (offset)
1378 offset = gen_rtx_PLUS (SImode, tmp, offset);
1379 else
1380 offset = tmp;
1381 break;
1382 default:
1383 abort ();
1386 if (! offset)
1387 offset = const0_rtx;
1389 if (base
1390 #ifndef INDEX_RATHER_THAN_BASE
1391 && (flag_pic || TARGET_HIMEM)
1392 && GET_CODE (base) != SYMBOL_REF
1393 && GET_CODE (offset) != CONST_INT
1394 #else
1395 /* This is a re-implementation of the SEQUENT_ADDRESS_BUG fix. */
1396 #endif
1397 && !indexexp && GET_CODE (base) == REG
1398 && REG_OK_FOR_INDEX_P (base))
1400 indexexp = base;
1401 base = NULL;
1404 /* now, offset, base and indexexp are set */
1405 #ifndef BASE_REG_NEEDED
1406 if (! base)
1408 #if defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC)
1409 if (GET_CODE (offset) == CONST_INT)
1410 #endif
1411 PUT_ABSOLUTE_PREFIX (file);
1413 #endif
1415 output_addr_const (file, offset);
1416 if (base) /* base can be (REG ...) or (MEM ...) */
1417 switch (GET_CODE (base))
1419 /* now we must output base. Possible alternatives are:
1420 (rN) (REG ...)
1421 (sp) (REG ...)
1422 (fp) (REG ...)
1423 (pc) (REG ...) used for SYMBOL_REF and LABEL_REF, output
1424 (disp(fp)) (MEM ...) just before possible [rX:y]
1425 (disp(sp)) (MEM ...)
1426 (disp(sb)) (MEM ...)
1428 case REG:
1429 fprintf (file, "(%s)", ns32k_out_reg_names[REGNO (base)]);
1430 break;
1431 case SYMBOL_REF:
1432 if (! flag_pic)
1433 abort ();
1435 fprintf (file, "(");
1436 output_addr_const (file, base);
1437 fprintf (file, "(sb))");
1438 break;
1439 case MEM:
1440 addr = XEXP (base,0);
1441 base = NULL;
1442 offset = NULL;
1443 while (addr != NULL)
1445 if (GET_CODE (addr) == PLUS)
1447 if (GET_CODE (XEXP (addr, 0)) == PLUS)
1449 tmp = XEXP (addr, 1);
1450 addr = XEXP (addr, 0);
1452 else
1454 tmp = XEXP (addr, 0);
1455 addr = XEXP (addr, 1);
1458 else
1460 tmp = addr;
1461 addr = NULL;
1463 switch (GET_CODE (tmp))
1465 case REG:
1466 base = tmp;
1467 break;
1468 case CONST:
1469 case CONST_INT:
1470 case SYMBOL_REF:
1471 case LABEL_REF:
1472 if (offset)
1473 offset = gen_rtx_PLUS (SImode, tmp, offset);
1474 else
1475 offset = tmp;
1476 break;
1477 default:
1478 abort ();
1481 if (! offset)
1482 offset = const0_rtx;
1483 fprintf (file, "(");
1484 output_addr_const (file, offset);
1485 if (base)
1486 fprintf (file, "(%s)", ns32k_out_reg_names[REGNO (base)]);
1487 else if (TARGET_SB)
1488 fprintf (file, "(sb)");
1489 else
1490 abort ();
1491 fprintf (file, ")");
1492 break;
1493 default:
1494 abort ();
1496 #ifdef PC_RELATIVE
1497 else if (GET_CODE (offset) != CONST_INT)
1498 fprintf (file, "(pc)");
1499 #ifdef BASE_REG_NEEDED
1500 else if (TARGET_SB)
1501 fprintf (file, "(sb)");
1502 else
1503 abort ();
1504 #endif
1505 #endif /* PC_RELATIVE */
1507 /* now print index if we have one */
1508 if (indexexp)
1510 if (GET_CODE (indexexp) == MULT)
1512 scale = INTVAL (XEXP (indexexp, 1)) >> 1;
1513 indexexp = XEXP (indexexp, 0);
1515 else
1516 scale = 0;
1517 if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= F0_REGNUM)
1518 abort ();
1520 #ifdef UTEK_ASM
1521 fprintf (file, "[%c`%s]",
1522 scales[scale],
1523 ns32k_out_reg_names[REGNO (indexexp)]);
1524 #else
1525 fprintf (file, "[%s:%c]",
1526 ns32k_out_reg_names[REGNO (indexexp)],
1527 scales[scale]);
1528 #endif
1532 /* National 32032 shifting is so bad that we can get
1533 better performance in many common cases by using other
1534 techniques. */
1535 const char *
1536 output_shift_insn (rtx *operands)
1538 if (GET_CODE (operands[2]) == CONST_INT
1539 && INTVAL (operands[2]) > 0
1540 && INTVAL (operands[2]) <= 3)
1542 if (GET_CODE (operands[0]) == REG)
1544 if (GET_CODE (operands[1]) == REG)
1546 if (REGNO (operands[0]) == REGNO (operands[1]))
1548 if (operands[2] == const1_rtx)
1549 return "addd %0,%0";
1550 else if (INTVAL (operands[2]) == 2)
1551 return "addd %0,%0\n\taddd %0,%0";
1553 if (operands[2] == const1_rtx)
1554 return "movd %1,%0\n\taddd %0,%0";
1556 operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
1557 return "addr %a1,%0";
1559 if (operands[2] == const1_rtx)
1560 return "movd %1,%0\n\taddd %0,%0";
1562 else if (GET_CODE (operands[1]) == REG)
1564 operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
1565 return "addr %a1,%0";
1567 else if (INTVAL (operands[2]) == 1
1568 && GET_CODE (operands[1]) == MEM
1569 && rtx_equal_p (operands [0], operands[1]))
1571 rtx temp = XEXP (operands[1], 0);
1573 if (GET_CODE (temp) == REG
1574 || (GET_CODE (temp) == PLUS
1575 && GET_CODE (XEXP (temp, 0)) == REG
1576 && GET_CODE (XEXP (temp, 1)) == CONST_INT))
1577 return "addd %0,%0";
1579 else return "ashd %2,%0";
1581 return "ashd %2,%0";
1584 const char *
1585 output_move_dconst (int n, 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 static rtx
1606 ns32k_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
1607 int incoming ATTRIBUTE_UNUSED)
1609 return gen_rtx_REG (Pmode, NS32K_STRUCT_VALUE_REGNUM);
1612 /* Worker function for NOTICE_UPDATE_CC. */
1614 void
1615 ns32k_notice_update_cc (rtx exp, rtx insn ATTRIBUTE_UNUSED)
1617 if (GET_CODE (exp) == SET)
1619 if (GET_CODE (SET_DEST (exp)) == CC0)
1621 cc_status.flags = 0;
1622 cc_status.value1 = SET_DEST (exp);
1623 cc_status.value2 = SET_SRC (exp);
1625 else if (GET_CODE (SET_SRC (exp)) == CALL)
1627 CC_STATUS_INIT;
1629 else if (GET_CODE (SET_DEST (exp)) == REG)
1631 if (cc_status.value1
1632 && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))
1633 cc_status.value1 = 0;
1634 if (cc_status.value2
1635 && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2))
1636 cc_status.value2 = 0;
1638 else if (GET_CODE (SET_DEST (exp)) == MEM)
1640 CC_STATUS_INIT;
1643 else if (GET_CODE (exp) == PARALLEL
1644 && GET_CODE (XVECEXP (exp, 0, 0)) == SET)
1646 if (GET_CODE (SET_DEST (XVECEXP (exp, 0, 0))) == CC0)
1648 cc_status.flags = 0;
1649 cc_status.value1 = SET_DEST (XVECEXP (exp, 0, 0));
1650 cc_status.value2 = SET_SRC (XVECEXP (exp, 0, 0));
1652 else if (GET_CODE (SET_DEST (XVECEXP (exp, 0, 0))) == REG)
1654 if (cc_status.value1
1655 && reg_overlap_mentioned_p (SET_DEST (XVECEXP (exp, 0, 0)),
1656 cc_status.value1))
1657 cc_status.value1 = 0;
1658 if (cc_status.value2
1659 && reg_overlap_mentioned_p (SET_DEST (XVECEXP (exp, 0, 0)),
1660 cc_status.value2))
1661 cc_status.value2 = 0;
1663 else if (GET_CODE (SET_DEST (XVECEXP (exp, 0, 0))) == MEM)
1665 CC_STATUS_INIT;
1668 else if (GET_CODE (exp) == CALL)
1670 /* all bets are off */
1671 CC_STATUS_INIT;
1673 else
1675 /* nothing happens? CC_STATUS_INIT; */
1677 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
1678 && cc_status.value2
1679 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
1680 abort ();
1683 /* Implement TARGET_ARG_PARTIAL_BYTES. */
1685 static int
1686 ns32k_arg_partial_bytes (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
1687 tree type, bool named ATTRIBUTE_UNUSED)
1689 int cum = *pcum;
1691 if (TARGET_REGPARM && cum < 8)
1693 HOST_WIDE_INT size;
1695 if (mode == BLKmode)
1696 size = int_size_in_bytes (type);
1697 else
1698 size = GET_MODE_SIZE (mode);
1700 if (8 < cum + size)
1701 return 8 - cum;
1704 return 0;