Merge reload-branch up to revision 101000
[official-gcc.git] / gcc / config / ns32k / ns32k.c
blobe4448efac65077af385abaa14e3ba8f12642a09c
1 /* Subroutines for assembler code output on the NS32000.
2 Copyright (C) 1988, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
3 2004, 2005
4 Free Software Foundation, Inc.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
13 GCC is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING. If not, write to
20 the Free Software Foundation, 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA. */
23 #include "config.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "tm.h"
27 #include "rtl.h"
28 #include "regs.h"
29 #include "hard-reg-set.h"
30 #include "real.h"
31 #include "insn-config.h"
32 #include "conditions.h"
33 #include "output.h"
34 #include "insn-attr.h"
35 #include "tree.h"
36 #include "function.h"
37 #include "expr.h"
38 #include "flags.h"
39 #include "recog.h"
40 #include "tm_p.h"
41 #include "target.h"
42 #include "target-def.h"
43 #include "toplev.h"
45 #ifdef OSF_OS
46 int ns32k_num_files = 0;
47 #endif
49 /* This duplicates reg_class_contents in reg_class.c, but maybe that isn't
50 initialized in time. Also this is more convenient as an array of ints.
51 We know that HARD_REG_SET fits in an unsigned int */
53 const unsigned int ns32k_reg_class_contents[N_REG_CLASSES][1] = REG_CLASS_CONTENTS;
55 const enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
57 GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
58 GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
59 FLOAT_REG0, LONG_FLOAT_REG0, FLOAT_REGS, FLOAT_REGS,
60 FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS,
61 LONG_REGS, LONG_REGS, LONG_REGS, LONG_REGS,
62 LONG_REGS, LONG_REGS, LONG_REGS, LONG_REGS,
63 FRAME_POINTER_REG, STACK_POINTER_REG
66 static const char *const ns32k_out_reg_names[] = OUTPUT_REGISTER_NAMES;
68 static bool ns32k_handle_option (size_t, const char *, int);
69 static rtx gen_indexed_expr (rtx, rtx, rtx);
70 static const char *singlemove_string (rtx *);
71 static void move_tail (rtx[], int, int);
72 static tree ns32k_handle_fntype_attribute (tree *, tree, tree, int, bool *);
73 const struct attribute_spec ns32k_attribute_table[];
74 static void ns32k_output_function_prologue (FILE *, HOST_WIDE_INT);
75 static void ns32k_output_function_epilogue (FILE *, HOST_WIDE_INT);
76 static bool ns32k_rtx_costs (rtx, int, int, int *);
77 static int ns32k_address_cost (rtx);
78 static rtx ns32k_struct_value_rtx (tree, int);
79 static int ns32k_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
80 tree, bool);
82 /* Initialize the GCC target structure. */
83 #undef TARGET_ATTRIBUTE_TABLE
84 #define TARGET_ATTRIBUTE_TABLE ns32k_attribute_table
86 #undef TARGET_ASM_ALIGNED_HI_OP
87 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
89 #ifdef ENCORE_ASM
90 #undef TARGET_ASM_ALIGNED_SI_OP
91 #define TARGET_ASM_ALIGNED_SI_OP "\t.double\t"
92 #endif
94 #undef TARGET_ASM_FUNCTION_PROLOGUE
95 #define TARGET_ASM_FUNCTION_PROLOGUE ns32k_output_function_prologue
96 #undef TARGET_ASM_FUNCTION_EPILOGUE
97 #define TARGET_ASM_FUNCTION_EPILOGUE ns32k_output_function_epilogue
99 #undef TARGET_DEFAULT_TARGET_FLAGS
100 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
101 #undef TARGET_HANDLE_OPTION
102 #define TARGET_HANDLE_OPTION ns32k_handle_option
104 #undef TARGET_RTX_COSTS
105 #define TARGET_RTX_COSTS ns32k_rtx_costs
106 #undef TARGET_ADDRESS_COST
107 #define TARGET_ADDRESS_COST ns32k_address_cost
109 #undef TARGET_STRUCT_VALUE_RTX
110 #define TARGET_STRUCT_VALUE_RTX ns32k_struct_value_rtx
112 #undef TARGET_ARG_PARTIAL_BYTES
113 #define TARGET_ARG_PARTIAL_BYTES ns32k_arg_partial_bytes
115 #undef TARGET_ASM_FILE_START_APP_OFF
116 #define TARGET_ASM_FILE_START_APP_OFF true
118 struct gcc_target targetm = TARGET_INITIALIZER;
120 /* Implement TARGET_HANDLE_OPTION. */
122 static bool
123 ns32k_handle_option (size_t code, const char *arg ATTRIBUTE_UNUSED,
124 int value ATTRIBUTE_UNUSED)
126 switch (code)
128 case OPT_m32081:
129 target_flags &= ~MASK_32381;
130 return true;
132 case OPT_msoft_float:
133 target_flags &= ~(MASK_32081 | MASK_32381);
134 return true;
136 case OPT_m32332:
137 target_flags &= ~MASK_32532;
138 return true;
140 case OPT_m32032:
141 target_flags &= ~(MASK_32332 | MASK_32532);
142 return true;
144 default:
145 return true;
149 /* Generate the assembly code for function entry. FILE is a stdio
150 stream to output the code to. SIZE is an int: how many units of
151 temporary storage to allocate.
153 Refer to the array `regs_ever_live' to determine which registers to
154 save; `regs_ever_live[I]' is nonzero if register number I is ever
155 used in the function. This function is responsible for knowing
156 which registers should not be saved even if used. */
159 * The function prologue for the ns32k is fairly simple.
160 * If a frame pointer is needed (decided in reload.c ?) then
161 * we need assembler of the form
163 * # Save the oldframe pointer, set the new frame pointer, make space
164 * # on the stack and save any general purpose registers necessary
166 * enter [<general purpose regs to save>], <local stack space>
168 * movf fn, tos # Save any floating point registers necessary
172 * If a frame pointer is not needed we need assembler of the form
174 * # Make space on the stack
176 * adjspd <local stack space + 4>
178 * # Save any general purpose registers necessary
180 * save [<general purpose regs to save>]
182 * movf fn, tos # Save any floating point registers necessary
187 #if !defined (MERLIN_TARGET) && !defined (UTEK_ASM)
189 #if defined(IMMEDIATE_PREFIX) && IMMEDIATE_PREFIX
190 #define ADJSP(FILE, N) \
191 fprintf (FILE, "\tadjspd %c" HOST_WIDE_INT_PRINT_DEC "\n", IMMEDIATE_PREFIX, (N))
192 #else
193 #define ADJSP(FILE, N) \
194 fprintf (FILE, "\tadjspd " HOST_WIDE_INT_PRINT_DEC "\n", (N))
195 #endif
197 static void
198 ns32k_output_function_prologue (FILE *file, HOST_WIDE_INT size)
200 register int regno, g_regs_used = 0;
201 int used_regs_buf[8], *bufp = used_regs_buf;
202 int used_fregs_buf[17], *fbufp = used_fregs_buf;
204 for (regno = R0_REGNUM; regno < F0_REGNUM; regno++)
205 if (regs_ever_live[regno]
206 && ! call_used_regs[regno])
208 *bufp++ = regno; g_regs_used++;
210 *bufp = -1;
212 for (; regno < FRAME_POINTER_REGNUM; regno++)
213 if (regs_ever_live[regno] && !call_used_regs[regno])
215 *fbufp++ = regno;
217 *fbufp = -1;
219 bufp = used_regs_buf;
220 if (frame_pointer_needed)
221 fprintf (file, "\tenter [");
222 else
224 if (size)
225 ADJSP (file, size + 4);
226 if (g_regs_used && g_regs_used > 4)
227 fprintf (file, "\tsave [");
228 else
230 while (*bufp >= 0)
231 fprintf (file, "\tmovd r%d,tos\n", *bufp++);
232 g_regs_used = 0;
236 while (*bufp >= 0)
238 fprintf (file, "r%d", *bufp++);
239 if (*bufp >= 0)
240 fputc (',', file);
243 if (frame_pointer_needed)
244 fprintf (file, "]," HOST_WIDE_INT_PRINT_DEC "\n", size);
245 else if (g_regs_used)
246 fprintf (file, "]\n");
248 fbufp = used_fregs_buf;
249 while (*fbufp >= 0)
251 if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1))
252 fprintf (file, "\tmovf %s,tos\n", ns32k_out_reg_names[*fbufp++]);
253 else
255 fprintf (file, "\tmovl %s,tos\n",
256 ns32k_out_reg_names[fbufp[0]]);
257 fbufp += 2;
261 if (flag_pic && current_function_uses_pic_offset_table)
263 fprintf (file, "\tsprd sb,tos\n");
264 if (TARGET_REGPARM)
266 fprintf (file, "\taddr __GLOBAL_OFFSET_TABLE_(pc),tos\n");
267 fprintf (file, "\tlprd sb,tos\n");
269 else
271 fprintf (file, "\taddr __GLOBAL_OFFSET_TABLE_(pc),r0\n");
272 fprintf (file, "\tlprd sb,r0\n");
277 #else /* MERLIN_TARGET || UTEK_ASM */
279 /* This differs from the standard one above in printing a bitmask
280 rather than a register list in the enter or save instruction. */
282 static void
283 ns32k_output_function_prologue (file, size)
284 FILE *file;
285 HOST_WIDE_INT size;
287 register int regno, g_regs_used = 0;
288 int used_regs_buf[8], *bufp = used_regs_buf;
289 int used_fregs_buf[8], *fbufp = used_fregs_buf;
291 for (regno = 0; regno < 8; regno++)
292 if (regs_ever_live[regno]
293 && ! call_used_regs[regno])
295 *bufp++ = regno; g_regs_used++;
297 *bufp = -1;
299 for (; regno < 16; regno++)
300 if (regs_ever_live[regno] && !call_used_regs[regno]) {
301 *fbufp++ = regno;
303 *fbufp = -1;
305 bufp = used_regs_buf;
306 if (frame_pointer_needed)
307 fprintf (file, "\tenter ");
308 else if (g_regs_used)
309 fprintf (file, "\tsave ");
311 if (frame_pointer_needed || g_regs_used)
313 char mask = 0;
314 while (*bufp >= 0)
315 mask |= 1 << *bufp++;
316 fprintf (file, "$0x%x", (int) mask & 0xff);
319 if (frame_pointer_needed)
320 #ifdef UTEK_ASM
321 fprintf (file, ",$%d\n", size);
322 #else
323 fprintf (file, ",%d\n", size);
324 #endif
325 else if (g_regs_used)
326 fprintf (file, "\n");
328 fbufp = used_fregs_buf;
329 while (*fbufp >= 0)
331 if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1))
332 fprintf (file, "\tmovf f%d,tos\n", *fbufp++ - 8);
333 else
335 fprintf (file, "\tmovl f%d,tos\n", fbufp[0] - 8);
336 fbufp += 2;
341 #endif /* MERLIN_TARGET || UTEK_ASM */
343 /* This function generates the assembly code for function exit,
344 on machines that need it.
346 The function epilogue should not depend on the current stack pointer,
347 if EXIT_IGNORE_STACK is nonzero. That doesn't apply here.
349 If a frame pointer is needed (decided in reload.c ?) then
350 we need assembler of the form
352 movf tos, fn # Restore any saved floating point registers
356 # Restore any saved general purpose registers, restore the stack
357 # pointer from the frame pointer, restore the old frame pointer.
358 exit [<general purpose regs to save>]
360 If a frame pointer is not needed we need assembler of the form
361 # Restore any general purpose registers saved
363 movf tos, fn # Restore any saved floating point registers
367 restore [<general purpose regs to save>]
369 # reclaim space allocated on stack
371 adjspd <-(local stack space + 4)> */
373 #if !defined (MERLIN_TARGET) && !defined (UTEK_ASM)
375 static void
376 ns32k_output_function_epilogue (FILE *file, HOST_WIDE_INT size)
378 register int regno, g_regs_used = 0, f_regs_used = 0;
379 int used_regs_buf[8], *bufp = used_regs_buf;
380 int used_fregs_buf[17], *fbufp = used_fregs_buf;
382 if (flag_pic && current_function_uses_pic_offset_table)
383 fprintf (file, "\tlprd sb,tos\n");
385 *fbufp++ = -2;
386 for (regno = F0_REGNUM; regno < FRAME_POINTER_REGNUM; regno++)
387 if (regs_ever_live[regno] && !call_used_regs[regno])
389 *fbufp++ = regno; f_regs_used++;
391 fbufp--;
393 for (regno = 0; regno < F0_REGNUM; regno++)
394 if (regs_ever_live[regno]
395 && ! call_used_regs[regno])
397 *bufp++ = regno; g_regs_used++;
400 while (fbufp > used_fregs_buf)
402 if ((*fbufp & 1) && fbufp[0] == fbufp[-1] + 1)
404 fprintf (file, "\tmovl tos,%s\n",
405 ns32k_out_reg_names[fbufp[-1]]);
406 fbufp -= 2;
408 else fprintf (file, "\tmovf tos,%s\n", ns32k_out_reg_names[*fbufp--]);
411 if (frame_pointer_needed)
412 fprintf (file, "\texit [");
413 else
415 if (g_regs_used && g_regs_used > 4)
416 fprintf (file, "\trestore [");
417 else
419 while (bufp > used_regs_buf)
420 fprintf (file, "\tmovd tos,r%d\n", *--bufp);
421 g_regs_used = 0;
425 while (bufp > used_regs_buf)
427 fprintf (file, "r%d", *--bufp);
428 if (bufp > used_regs_buf)
429 fputc (',', file);
432 if (g_regs_used || frame_pointer_needed)
433 fprintf (file, "]\n");
435 if (size && !frame_pointer_needed)
436 ADJSP (file, -(size + 4));
438 if (current_function_pops_args)
439 fprintf (file, "\tret %d\n", current_function_pops_args);
440 else
441 fprintf (file, "\tret 0\n");
444 #else /* MERLIN_TARGET || UTEK_ASM */
446 /* This differs from the standard one above in printing a bitmask
447 rather than a register list in the exit or restore instruction. */
449 static void
450 ns32k_output_function_epilogue (file, size)
451 FILE *file;
452 HOST_WIDE_INT size ATTRIBUTE_UNUSED;
454 register int regno, g_regs_used = 0, f_regs_used = 0;
455 int used_regs_buf[8], *bufp = used_regs_buf;
456 int used_fregs_buf[8], *fbufp = used_fregs_buf;
458 *fbufp++ = -2;
459 for (regno = 8; regno < 16; regno++)
460 if (regs_ever_live[regno] && !call_used_regs[regno]) {
461 *fbufp++ = regno; f_regs_used++;
463 fbufp--;
465 for (regno = 0; regno < 8; regno++)
466 if (regs_ever_live[regno]
467 && ! call_used_regs[regno])
469 *bufp++ = regno; g_regs_used++;
472 while (fbufp > used_fregs_buf)
474 if ((*fbufp & 1) && fbufp[0] == fbufp[-1] + 1)
476 fprintf (file, "\tmovl tos,f%d\n", fbufp[-1] - 8);
477 fbufp -= 2;
479 else fprintf (file, "\tmovf tos,f%d\n", *fbufp-- - 8);
482 if (frame_pointer_needed)
483 fprintf (file, "\texit ");
484 else if (g_regs_used)
485 fprintf (file, "\trestore ");
487 if (g_regs_used || frame_pointer_needed)
489 char mask = 0;
491 while (bufp > used_regs_buf)
493 /* Utek assembler takes care of reversing this */
494 mask |= 1 << *--bufp;
496 fprintf (file, "$0x%x\n", (int) mask & 0xff);
499 #ifdef UTEK_ASM
500 if (current_function_pops_args)
501 fprintf (file, "\tret $%d\n", current_function_pops_args);
502 else
503 fprintf (file, "\tret $0\n");
504 #else
505 if (current_function_pops_args)
506 fprintf (file, "\tret %d\n", current_function_pops_args);
507 else
508 fprintf (file, "\tret 0\n");
509 #endif
512 #endif /* MERLIN_TARGET || UTEK_ASM */
514 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */
516 hard_regno_mode_ok (int regno, enum machine_mode mode)
518 int size = GET_MODE_UNIT_SIZE (mode);
520 if (FLOAT_MODE_P (mode))
522 if (size == UNITS_PER_WORD && regno < L1_REGNUM)
523 return 1;
524 if (size == UNITS_PER_WORD * 2
525 && (((regno & 1) == 0 && regno < FRAME_POINTER_REGNUM)))
526 return 1;
527 return 0;
529 if (size == UNITS_PER_WORD * 2
530 && (regno & 1) == 0 && regno < F0_REGNUM)
531 return 1;
532 if (size <= UNITS_PER_WORD
533 && (regno < F0_REGNUM || regno == FRAME_POINTER_REGNUM
534 || regno == STACK_POINTER_REGNUM))
535 return 1;
536 return 0;
539 static bool
540 ns32k_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total)
542 switch (code)
544 case CONST_INT:
545 if (INTVAL (x) <= 7 && INTVAL (x) >= -8)
546 *total = 0;
547 else if (INTVAL (x) < 0x2000 && INTVAL (x) >= -0x2000)
548 *total = 1;
549 else
550 *total = 3;
551 return true;
553 case CONST:
554 case LABEL_REF:
555 case SYMBOL_REF:
556 *total = 3;
557 return true;
559 case CONST_DOUBLE:
560 *total = 5;
561 return true;
563 default:
564 return false;
569 register_move_cost (enum reg_class CLASS1, enum reg_class CLASS2)
571 if (CLASS1 == NO_REGS || CLASS2 == NO_REGS)
572 return 2;
573 if ((SUBSET_P (CLASS1, FP_REGS) && !SUBSET_P (CLASS2, FP_REGS))
574 || (!SUBSET_P (CLASS1, FP_REGS) && SUBSET_P (CLASS2, FP_REGS)))
575 return 8;
576 if (((CLASS1) == STACK_POINTER_REG && !SUBSET_P (CLASS2,GENERAL_REGS))
577 || ((CLASS2) == STACK_POINTER_REG && !SUBSET_P (CLASS1,GENERAL_REGS)))
578 return 6;
579 if (((CLASS1) == FRAME_POINTER_REG && !SUBSET_P (CLASS2,GENERAL_REGS))
580 || ((CLASS2) == FRAME_POINTER_REG && !SUBSET_P (CLASS1,GENERAL_REGS)))
581 return 6;
582 return 2;
585 #if 0
586 /* We made the insn definitions copy from floating point to general
587 registers via the stack. */
589 secondary_memory_needed (enum reg_class CLASS1,
590 enum reg_class CLASS2,
591 enum machine_mode M)
593 int ret = ((SUBSET_P (CLASS1, FP_REGS) && !SUBSET_P (CLASS2, FP_REGS))
594 || (!SUBSET_P (CLASS1, FP_REGS) && SUBSET_P (CLASS2, FP_REGS)));
595 return ret;
597 #endif
600 /* TARGET_ADDRESS_COST calls this. This function is not optimal
601 for the 32032 & 32332, but it probably is better than
602 the default. */
604 static int
605 ns32k_address_cost (rtx operand)
607 int cost = 0;
609 switch (GET_CODE (operand))
611 case REG:
612 cost += 1;
613 break;
615 case POST_DEC:
616 case PRE_DEC:
617 break;
619 case CONST_INT:
620 if (INTVAL (operand) <= 7 && INTVAL (operand) >= -8)
621 break;
622 if (INTVAL (operand) < 0x2000 && INTVAL (operand) >= -0x2000)
624 cost +=1;
625 break;
627 case CONST:
628 case LABEL_REF:
629 case SYMBOL_REF:
630 cost +=3;
631 break;
632 case CONST_DOUBLE:
633 cost += 5;
634 break;
636 case MEM:
637 cost += ns32k_address_cost (XEXP (operand, 0)) + 3;
638 break;
640 case MULT:
641 cost += 2;
642 /* FALLTHRU */
643 case PLUS:
644 cost += ns32k_address_cost (XEXP (operand, 0));
645 cost += ns32k_address_cost (XEXP (operand, 1));
646 break;
648 default:
649 break;
652 return cost;
655 /* Return the register class of a scratch register needed to copy IN into
656 or out of a register in CLASS in MODE. If it can be done directly,
657 NO_REGS is returned. */
659 enum reg_class
660 secondary_reload_class (enum reg_class class,
661 enum machine_mode mode ATTRIBUTE_UNUSED,
662 rtx in)
664 int regno = true_regnum (in);
666 if (regno >= FIRST_PSEUDO_REGISTER)
667 regno = -1;
669 if ((class == FRAME_POINTER_REG && regno == STACK_POINTER_REGNUM)
670 || ( class == STACK_POINTER_REG && regno == FRAME_POINTER_REGNUM))
671 return GENERAL_REGS;
672 else
673 return NO_REGS;
676 /* Generate the rtx that comes from an address expression in the md file */
677 /* The expression to be build is BASE[INDEX:SCALE]. To recognize this,
678 scale must be converted from an exponent (from ASHIFT) to a
679 multiplier (for MULT). */
681 static rtx
682 gen_indexed_expr (rtx base, rtx index, rtx scale)
684 rtx addr;
686 /* This generates an invalid addressing mode, if BASE is
687 fp or sp. This is handled by PRINT_OPERAND_ADDRESS. */
688 if (GET_CODE (base) != REG && GET_CODE (base) != CONST_INT)
689 base = gen_rtx_MEM (SImode, base);
690 addr = gen_rtx_MULT (SImode, index,
691 GEN_INT (1 << INTVAL (scale)));
692 addr = gen_rtx_PLUS (SImode, base, addr);
693 return addr;
697 /* Split one or more DImode RTL references into pairs of SImode
698 references. The RTL can be REG, offsettable MEM, integer constant, or
699 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
700 split and "num" is its length. lo_half and hi_half are output arrays
701 that parallel "operands". */
703 void
704 split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
706 while (num--)
708 if (GET_CODE (operands[num]) == REG)
710 lo_half[num] = gen_rtx_REG (SImode, REGNO (operands[num]));
711 hi_half[num] = gen_rtx_REG (SImode, REGNO (operands[num]) + 1);
713 else if (CONSTANT_P (operands[num]))
715 split_double (operands[num], &lo_half[num], &hi_half[num]);
717 else if (offsettable_memref_p (operands[num]))
719 lo_half[num] = operands[num];
720 hi_half[num] = adjust_address (operands[num], SImode, 4);
722 else
723 abort ();
727 /* Return the best assembler insn template
728 for moving operands[1] into operands[0] as a fullword. */
730 static const char *
731 singlemove_string (rtx *operands)
733 if (GET_CODE (operands[1]) == CONST_INT
734 && INTVAL (operands[1]) <= 7
735 && INTVAL (operands[1]) >= -8)
736 return "movqd %1,%0";
737 return "movd %1,%0";
740 const char *
741 output_move_double (rtx *operands)
743 enum anon1 { REGOP, OFFSOP, PUSHOP, CNSTOP, RNDOP } optype0, optype1;
744 rtx latehalf[2];
746 /* First classify both operands. */
748 if (REG_P (operands[0]))
749 optype0 = REGOP;
750 else if (offsettable_memref_p (operands[0]))
751 optype0 = OFFSOP;
752 else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
753 optype0 = PUSHOP;
754 else
755 optype0 = RNDOP;
757 if (REG_P (operands[1]))
758 optype1 = REGOP;
759 else if (CONSTANT_P (operands[1])
760 || GET_CODE (operands[1]) == CONST_DOUBLE)
761 optype1 = CNSTOP;
762 else if (offsettable_memref_p (operands[1]))
763 optype1 = OFFSOP;
764 else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
765 optype1 = PUSHOP;
766 else
767 optype1 = RNDOP;
769 /* Check for the cases that the operand constraints are not
770 supposed to allow to happen. Abort if we get one,
771 because generating code for these cases is painful. */
773 if (optype0 == RNDOP || optype1 == RNDOP)
774 abort ();
776 /* Ok, we can do one word at a time.
777 Normally we do the low-numbered word first,
778 but if either operand is autodecrementing then we
779 do the high-numbered word first.
781 In either case, set up in LATEHALF the operands to use
782 for the high-numbered word and in some cases alter the
783 operands in OPERANDS to be suitable for the low-numbered word. */
785 if (optype0 == REGOP)
786 latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
787 else if (optype0 == OFFSOP)
788 latehalf[0] = adjust_address (operands[0], SImode, 4);
789 else
790 latehalf[0] = operands[0];
792 if (optype1 == REGOP)
793 latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
794 else if (optype1 == OFFSOP)
795 latehalf[1] = adjust_address (operands[1], SImode, 4);
796 else if (optype1 == CNSTOP)
797 split_double (operands[1], &operands[1], &latehalf[1]);
798 else
799 latehalf[1] = operands[1];
801 /* If insn is effectively movd N(sp),tos then we will do the
802 high word first. We should use the adjusted operand 1 (which is N+4(sp))
803 for the low word as well, to compensate for the first decrement of sp.
804 Given this, it doesn't matter which half we do "first". */
805 if (optype0 == PUSHOP
806 && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
807 && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
808 operands[1] = latehalf[1];
810 /* If one or both operands autodecrementing,
811 do the two words, high-numbered first. */
812 else if (optype0 == PUSHOP || optype1 == PUSHOP)
814 output_asm_insn (singlemove_string (latehalf), latehalf);
815 return singlemove_string (operands);
818 /* If the first move would clobber the source of the second one,
819 do them in the other order. */
821 /* Overlapping registers. */
822 if (optype0 == REGOP && optype1 == REGOP
823 && REGNO (operands[0]) == REGNO (latehalf[1]))
825 /* Do that word. */
826 output_asm_insn (singlemove_string (latehalf), latehalf);
827 /* Do low-numbered word. */
828 return singlemove_string (operands);
830 /* Loading into a register which overlaps a register used in the address. */
831 else if (optype0 == REGOP && optype1 != REGOP
832 && reg_overlap_mentioned_p (operands[0], operands[1]))
834 if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
835 && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
837 /* If both halves of dest are used in the src memory address,
838 load the destination address into the low reg (operands[0]).
839 Then it works to load latehalf first. */
840 rtx xops[2];
841 xops[0] = XEXP (operands[1], 0);
842 xops[1] = operands[0];
843 output_asm_insn ("addr %a0,%1", xops);
844 operands[1] = gen_rtx_MEM (DImode, operands[0]);
845 latehalf[1] = adjust_address (operands[1], SImode, 4);
846 /* The first half has the overlap, Do the late half first. */
847 output_asm_insn (singlemove_string (latehalf), latehalf);
848 /* Then clobber. */
849 return singlemove_string (operands);
851 if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)))
853 /* The first half has the overlap, Do the late half first. */
854 output_asm_insn (singlemove_string (latehalf), latehalf);
855 /* Then clobber. */
856 return singlemove_string (operands);
860 /* Normal case. Do the two words, low-numbered first. */
862 output_asm_insn (singlemove_string (operands), operands);
864 operands[0] = latehalf[0];
865 operands[1] = latehalf[1];
866 return singlemove_string (operands);
870 #define MAX_UNALIGNED_COPY (32)
871 /* Expand string/block move operations.
873 operands[0] is the pointer to the destination.
874 operands[1] is the pointer to the source.
875 operands[2] is the number of bytes to move.
876 operands[3] is the alignment. */
878 static void
879 move_tail (rtx operands[], int bytes, int offset)
881 if (bytes & 2)
883 emit_move_insn (adjust_address (operands[0], HImode, offset),
884 adjust_address (operands[1], HImode, offset));
885 offset += 2;
887 if (bytes & 1)
888 emit_move_insn (adjust_address (operands[0], QImode, offset),
889 adjust_address (operands[1], QImode, offset));
892 void
893 expand_block_move (rtx operands[])
895 rtx bytes_rtx = operands[2];
896 rtx align_rtx = operands[3];
897 int constp = (GET_CODE (bytes_rtx) == CONST_INT);
898 int bytes = (constp ? INTVAL (bytes_rtx) : 0);
899 int align = INTVAL (align_rtx);
900 rtx src_reg = gen_rtx_REG (Pmode, 1);
901 rtx dest_reg = gen_rtx_REG (Pmode, 2);
902 rtx count_reg = gen_rtx_REG (SImode, 0);
904 if (constp && bytes <= 0)
905 return;
907 if (constp && bytes < 20)
909 int words = bytes >> 2;
911 if (words)
913 if (words < 3)
915 int offset = 0;
917 for (; words; words--, offset += 4)
918 emit_move_insn (adjust_address (operands[0], SImode, offset),
919 adjust_address (operands[1], SImode, offset));
921 else
923 /* Use movmd. It is slower than multiple movd's but more
924 compact. It is also slower than movsd for large copies
925 but causes less registers reloading so is better than movsd
926 for small copies. */
927 rtx src, dest;
928 dest = copy_addr_to_reg (XEXP (operands[0], 0));
929 src = copy_addr_to_reg (XEXP (operands[1], 0));
931 emit_insn (gen_movmemsi2(dest, src, GEN_INT (words)));
934 move_tail (operands, bytes & 3, bytes & ~3);
935 return;
938 if (align > UNITS_PER_WORD)
939 align = UNITS_PER_WORD;
941 /* Move the address into scratch registers. */
942 emit_insn (gen_rtx_CLOBBER (VOIDmode, dest_reg));
943 emit_move_insn (dest_reg, XEXP (operands[0], 0));
944 operands[0] = gen_rtx_MEM (SImode, dest_reg);
945 emit_insn (gen_rtx_CLOBBER (VOIDmode, src_reg));
946 emit_move_insn (src_reg, XEXP (operands[1], 0));
947 operands[1] = gen_rtx_MEM (SImode, src_reg);
948 emit_insn (gen_rtx_CLOBBER (VOIDmode, count_reg));
950 if (constp && (align == UNITS_PER_WORD || bytes < MAX_UNALIGNED_COPY))
952 /* constant no of bytes and aligned or small enough copy to not bother
953 * aligning. Emit insns to copy by words.
955 if (bytes >> 2)
957 emit_move_insn (count_reg, GEN_INT (bytes >> 2));
958 emit_insn (gen_movmemsi1 (GEN_INT (4)));
960 /* insns to copy rest */
961 move_tail (operands, bytes & 3, 0);
963 else if (align == UNITS_PER_WORD)
965 /* insns to copy by words */
966 emit_insn (gen_lshrsi3 (count_reg, bytes_rtx, const2_rtx));
967 emit_insn (gen_movmemsi1 (GEN_INT (4)));
968 if (constp)
970 move_tail (operands, bytes & 3, 0);
972 else
974 /* insns to copy rest */
975 emit_insn (gen_andsi3 (count_reg, bytes_rtx, GEN_INT (3)));
976 emit_insn (gen_movmemsi1 (const1_rtx));
979 else
981 /* Not aligned and we may have a lot to copy so it is worth
982 * aligning.
984 rtx aligned_label = gen_label_rtx ();
985 rtx bytes_reg;
987 bytes_reg = copy_to_mode_reg (SImode, bytes_rtx);
988 if (!constp)
990 /* Emit insns to test and skip over the alignment if it is
991 * not worth it. This doubles as a test to ensure that the alignment
992 * operation can't copy too many bytes
994 emit_insn (gen_cmpsi (bytes_reg, GEN_INT (MAX_UNALIGNED_COPY)));
995 emit_jump_insn (gen_blt (aligned_label));
998 /* Emit insns to do alignment at run time */
999 emit_insn (gen_negsi2 (count_reg, src_reg));
1000 emit_insn (gen_andsi3 (count_reg, count_reg, GEN_INT (3)));
1001 emit_insn (gen_subsi3 (bytes_reg, bytes_reg, count_reg));
1002 emit_insn (gen_movmemsi1 (const1_rtx));
1003 if (!constp)
1004 emit_label (aligned_label);
1006 /* insns to copy by words */
1007 emit_insn (gen_lshrsi3 (count_reg, bytes_reg, const2_rtx));
1008 emit_insn (gen_movmemsi1 (GEN_INT (4)));
1010 /* insns to copy rest */
1011 emit_insn (gen_andsi3 (count_reg, bytes_reg, GEN_INT (3)));
1012 emit_insn (gen_movmemsi1 (const1_rtx));
1017 /* Returns 1 if OP contains a global symbol reference */
1020 global_symbolic_reference_mentioned_p (rtx op, int f)
1022 register const char *fmt;
1023 register int i;
1025 if (GET_CODE (op) == SYMBOL_REF)
1027 if (! SYMBOL_REF_LOCAL_P (op))
1028 return 1;
1029 else
1030 return 0;
1032 else if (f && GET_CODE (op) != CONST)
1033 return 0;
1035 fmt = GET_RTX_FORMAT (GET_CODE (op));
1036 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
1038 if (fmt[i] == 'E')
1040 register int j;
1042 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
1043 if (global_symbolic_reference_mentioned_p (XVECEXP (op, i, j), 0))
1044 return 1;
1046 else if (fmt[i] == 'e'
1047 && global_symbolic_reference_mentioned_p (XEXP (op, i), 0))
1048 return 1;
1051 return 0;
1055 /* Returns 1 if OP contains a symbol reference */
1058 symbolic_reference_mentioned_p (rtx op)
1060 register const char *fmt;
1061 register int i;
1063 if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
1064 return 1;
1066 fmt = GET_RTX_FORMAT (GET_CODE (op));
1067 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
1069 if (fmt[i] == 'E')
1071 register int j;
1073 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
1074 if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
1075 return 1;
1077 else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
1078 return 1;
1081 return 0;
1084 /* Table of machine-specific attributes. */
1086 const struct attribute_spec ns32k_attribute_table[] =
1088 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
1089 /* Stdcall attribute says callee is responsible for popping arguments
1090 if they are not variable. */
1091 { "stdcall", 0, 0, false, true, true, ns32k_handle_fntype_attribute },
1092 /* Cdecl attribute says the callee is a normal C declaration */
1093 { "cdecl", 0, 0, false, true, true, ns32k_handle_fntype_attribute },
1094 { NULL, 0, 0, false, false, false, NULL }
1097 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1098 arguments as in struct attribute_spec.handler. */
1099 static tree
1100 ns32k_handle_fntype_attribute (tree *node, tree name,
1101 tree args ATTRIBUTE_UNUSED,
1102 int flags ATTRIBUTE_UNUSED,
1103 bool *no_add_attrs)
1105 if (TREE_CODE (*node) != FUNCTION_TYPE
1106 && TREE_CODE (*node) != FIELD_DECL
1107 && TREE_CODE (*node) != TYPE_DECL)
1109 warning (OPT_Wattributes, "%qs attribute only applies to functions",
1110 IDENTIFIER_POINTER (name));
1111 *no_add_attrs = true;
1114 return NULL_TREE;
1118 /* Value is the number of bytes of arguments automatically
1119 popped when returning from a subroutine call.
1120 FUNDECL is the declaration node of the function (as a tree),
1121 FUNTYPE is the data type of the function (as a tree),
1122 or for a library call it is an identifier node for the subroutine name.
1123 SIZE is the number of bytes of arguments passed on the stack.
1125 On the ns32k, the RET insn may be used to pop them if the number
1126 of args is fixed, but if the number is variable then the caller
1127 must pop them all. RET can't be used for library calls now
1128 because the library is compiled with the Unix compiler.
1129 Use of RET is a selectable option, since it is incompatible with
1130 standard Unix calling sequences. If the option is not selected,
1131 the caller must always pop the args.
1133 The attribute stdcall is equivalent to RET on a per module basis. */
1136 ns32k_return_pops_args (tree fundecl ATTRIBUTE_UNUSED, tree funtype, int size)
1138 int rtd = TARGET_RTD;
1140 if (TREE_CODE (funtype) == IDENTIFIER_NODE)
1141 return rtd ? size : 0;
1143 /* Cdecl functions override -mrtd, and never pop the stack */
1144 if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype)))
1145 return 0;
1147 /* Stdcall functions will pop the stack if not variable args */
1148 if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype)))
1149 rtd = 1;
1151 if (rtd)
1153 if (TYPE_ARG_TYPES (funtype) == NULL_TREE
1154 || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node))
1155 return size;
1158 return 0;
1161 /* PRINT_OPERAND is defined to call this function,
1162 which is easier to debug than putting all the code in
1163 a macro definition in ns32k.h. */
1165 /* XXX time 12% of cpu time is in fprintf for non optimizing */
1166 void
1167 print_operand (FILE *file, rtx x, int code)
1169 if (code == '$')
1170 PUT_IMMEDIATE_PREFIX (file);
1171 else if (code == '?')
1172 PUT_EXTERNAL_PREFIX (file);
1173 else if (GET_CODE (x) == REG)
1174 fprintf (file, "%s", ns32k_out_reg_names[REGNO (x)]);
1175 else if (GET_CODE (x) == MEM)
1177 output_address (XEXP (x, 0));
1179 else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != VOIDmode)
1181 REAL_VALUE_TYPE r;
1183 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1184 PUT_IMMEDIATE_PREFIX (file);
1185 if (GET_MODE (x) == DFmode)
1187 #ifdef SEQUENT_ASM
1188 /* Sequent likes its floating point constants as integers */
1189 long l[2];
1190 REAL_VALUE_TO_TARGET_DOUBLE (r, l);
1191 fprintf (file, "0Dx%08x%08x",
1192 l[!WORDS_BIG_ENDIAN], l[WORDS_BIG_ENDIAN]);
1193 #else
1194 char s[30];
1195 real_to_decimal (s, &r, sizeof (s), 0, 1);
1196 #ifdef ENCORE_ASM
1197 fprintf (file, "0f%s", s);
1198 #else
1199 fprintf (file, "0d%s", s);
1200 #endif
1201 #endif
1203 else
1205 #ifdef SEQUENT_ASM
1206 long l;
1207 REAL_VALUE_TO_TARGET_SINGLE (r, l);
1208 fprintf (file, "0Fx%08lx", l);
1209 #else
1210 char s[30];
1211 real_to_decimal (s, &r, sizeof (s), 0, 1);
1212 fprintf (file, "0f%s", s);
1213 #endif
1216 else
1218 if (flag_pic
1219 && GET_CODE (x) == CONST
1220 && symbolic_reference_mentioned_p (x))
1222 fprintf (stderr, "illegal constant for pic-mode: \n");
1223 print_rtl (stderr, x);
1224 fprintf (stderr, "\nGET_CODE (x) == %d, CONST == %d, symbolic_reference_mentioned_p (x) == %d\n",
1225 GET_CODE (x), CONST, symbolic_reference_mentioned_p (x));
1226 abort ();
1228 else if (flag_pic
1229 && (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF))
1231 output_addr_const (file, x);
1232 fprintf (file, "(sb)");
1234 else
1236 #ifdef NO_IMMEDIATE_PREFIX_IF_SYMBOLIC
1237 if (GET_CODE (x) == CONST_INT)
1238 #endif
1239 PUT_IMMEDIATE_PREFIX (file);
1240 output_addr_const (file, x);
1245 /* PRINT_OPERAND_ADDRESS is defined to call this function,
1246 which is easier to debug than putting all the code in
1247 a macro definition in ns32k.h . */
1249 /* Completely rewritten to get this to work with Gas for PC532 Mach.
1250 This function didn't work and I just wasn't able (nor very willing) to
1251 figure out how it worked.
1252 90-11-25 Tatu Yl|nen <ylo@cs.hut.fi> */
1254 void
1255 print_operand_address (register FILE *file, register rtx addr)
1257 static const char scales[] = { 'b', 'w', 'd', 0, 'q', };
1258 rtx offset, base, indexexp, tmp;
1259 int scale;
1260 extern int flag_pic;
1262 if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == POST_DEC)
1264 fprintf (file, "tos");
1265 return;
1268 offset = NULL;
1269 base = NULL;
1270 indexexp = NULL;
1271 while (addr != NULL)
1273 if (GET_CODE (addr) == PLUS)
1275 if (GET_CODE (XEXP (addr, 0)) == PLUS)
1277 tmp = XEXP (addr, 1);
1278 addr = XEXP (addr, 0);
1280 else
1282 tmp = XEXP (addr,0);
1283 addr = XEXP (addr,1);
1286 else
1288 tmp = addr;
1289 addr = NULL;
1291 switch (GET_CODE (tmp))
1293 case PLUS:
1294 abort ();
1295 case MEM:
1296 if (base)
1298 indexexp = base;
1299 base = tmp;
1301 else
1302 base = tmp;
1303 break;
1304 case REG:
1305 if (REGNO (tmp) < F0_REGNUM)
1306 if (base)
1308 indexexp = tmp;
1310 else
1311 base = tmp;
1312 else
1313 if (base)
1315 indexexp = base;
1316 base = tmp;
1318 else
1319 base = tmp;
1320 break;
1321 case MULT:
1322 indexexp = tmp;
1323 break;
1324 case SYMBOL_REF:
1325 if (flag_pic && ! SYMBOL_REF_LOCAL_P (tmp))
1327 if (base)
1329 if (indexexp)
1330 abort ();
1331 indexexp = base;
1333 base = tmp;
1334 break;
1336 case CONST:
1337 if (flag_pic && GET_CODE (tmp) == CONST)
1339 rtx sym, off, tmp1;
1340 tmp1 = XEXP (tmp,0);
1341 if (GET_CODE (tmp1) != PLUS)
1342 abort ();
1344 sym = XEXP (tmp1,0);
1345 if (GET_CODE (sym) != SYMBOL_REF)
1347 off = sym;
1348 sym = XEXP (tmp1,1);
1350 else
1351 off = XEXP (tmp1,1);
1352 if (GET_CODE (sym) == SYMBOL_REF)
1354 if (GET_CODE (off) != CONST_INT)
1355 abort ();
1357 if (! SYMBOL_REF_LOCAL_P (sym))
1359 if (base)
1361 if (indexexp)
1362 abort ();
1364 indexexp = base;
1367 if (offset != 0)
1368 abort ();
1370 base = sym;
1371 offset = off;
1372 break;
1376 case CONST_INT:
1377 case LABEL_REF:
1378 if (offset)
1379 offset = gen_rtx_PLUS (SImode, tmp, offset);
1380 else
1381 offset = tmp;
1382 break;
1383 default:
1384 abort ();
1387 if (! offset)
1388 offset = const0_rtx;
1390 if (base
1391 #ifndef INDEX_RATHER_THAN_BASE
1392 && (flag_pic || TARGET_HIMEM)
1393 && GET_CODE (base) != SYMBOL_REF
1394 && GET_CODE (offset) != CONST_INT
1395 #else
1396 /* This is a re-implementation of the SEQUENT_ADDRESS_BUG fix. */
1397 #endif
1398 && !indexexp && GET_CODE (base) == REG
1399 && REG_OK_FOR_INDEX_P (base))
1401 indexexp = base;
1402 base = NULL;
1405 /* now, offset, base and indexexp are set */
1406 #ifndef BASE_REG_NEEDED
1407 if (! base)
1409 #if defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC)
1410 if (GET_CODE (offset) == CONST_INT)
1411 #endif
1412 PUT_ABSOLUTE_PREFIX (file);
1414 #endif
1416 output_addr_const (file, offset);
1417 if (base) /* base can be (REG ...) or (MEM ...) */
1418 switch (GET_CODE (base))
1420 /* now we must output base. Possible alternatives are:
1421 (rN) (REG ...)
1422 (sp) (REG ...)
1423 (fp) (REG ...)
1424 (pc) (REG ...) used for SYMBOL_REF and LABEL_REF, output
1425 (disp(fp)) (MEM ...) just before possible [rX:y]
1426 (disp(sp)) (MEM ...)
1427 (disp(sb)) (MEM ...)
1429 case REG:
1430 fprintf (file, "(%s)", ns32k_out_reg_names[REGNO (base)]);
1431 break;
1432 case SYMBOL_REF:
1433 if (! flag_pic)
1434 abort ();
1436 fprintf (file, "(");
1437 output_addr_const (file, base);
1438 fprintf (file, "(sb))");
1439 break;
1440 case MEM:
1441 addr = XEXP (base,0);
1442 base = NULL;
1443 offset = NULL;
1444 while (addr != NULL)
1446 if (GET_CODE (addr) == PLUS)
1448 if (GET_CODE (XEXP (addr, 0)) == PLUS)
1450 tmp = XEXP (addr, 1);
1451 addr = XEXP (addr, 0);
1453 else
1455 tmp = XEXP (addr, 0);
1456 addr = XEXP (addr, 1);
1459 else
1461 tmp = addr;
1462 addr = NULL;
1464 switch (GET_CODE (tmp))
1466 case REG:
1467 base = tmp;
1468 break;
1469 case CONST:
1470 case CONST_INT:
1471 case SYMBOL_REF:
1472 case LABEL_REF:
1473 if (offset)
1474 offset = gen_rtx_PLUS (SImode, tmp, offset);
1475 else
1476 offset = tmp;
1477 break;
1478 default:
1479 abort ();
1482 if (! offset)
1483 offset = const0_rtx;
1484 fprintf (file, "(");
1485 output_addr_const (file, offset);
1486 if (base)
1487 fprintf (file, "(%s)", ns32k_out_reg_names[REGNO (base)]);
1488 else if (TARGET_SB)
1489 fprintf (file, "(sb)");
1490 else
1491 abort ();
1492 fprintf (file, ")");
1493 break;
1494 default:
1495 abort ();
1497 #ifdef PC_RELATIVE
1498 else if (GET_CODE (offset) != CONST_INT)
1499 fprintf (file, "(pc)");
1500 #ifdef BASE_REG_NEEDED
1501 else if (TARGET_SB)
1502 fprintf (file, "(sb)");
1503 else
1504 abort ();
1505 #endif
1506 #endif /* PC_RELATIVE */
1508 /* now print index if we have one */
1509 if (indexexp)
1511 if (GET_CODE (indexexp) == MULT)
1513 scale = INTVAL (XEXP (indexexp, 1)) >> 1;
1514 indexexp = XEXP (indexexp, 0);
1516 else
1517 scale = 0;
1518 if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= F0_REGNUM)
1519 abort ();
1521 #ifdef UTEK_ASM
1522 fprintf (file, "[%c`%s]",
1523 scales[scale],
1524 ns32k_out_reg_names[REGNO (indexexp)]);
1525 #else
1526 fprintf (file, "[%s:%c]",
1527 ns32k_out_reg_names[REGNO (indexexp)],
1528 scales[scale]);
1529 #endif
1533 /* National 32032 shifting is so bad that we can get
1534 better performance in many common cases by using other
1535 techniques. */
1536 const char *
1537 output_shift_insn (rtx *operands)
1539 if (GET_CODE (operands[2]) == CONST_INT
1540 && INTVAL (operands[2]) > 0
1541 && INTVAL (operands[2]) <= 3)
1543 if (GET_CODE (operands[0]) == REG)
1545 if (GET_CODE (operands[1]) == REG)
1547 if (REGNO (operands[0]) == REGNO (operands[1]))
1549 if (operands[2] == const1_rtx)
1550 return "addd %0,%0";
1551 else if (INTVAL (operands[2]) == 2)
1552 return "addd %0,%0\n\taddd %0,%0";
1554 if (operands[2] == const1_rtx)
1555 return "movd %1,%0\n\taddd %0,%0";
1557 operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
1558 return "addr %a1,%0";
1560 if (operands[2] == const1_rtx)
1561 return "movd %1,%0\n\taddd %0,%0";
1563 else if (GET_CODE (operands[1]) == REG)
1565 operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
1566 return "addr %a1,%0";
1568 else if (INTVAL (operands[2]) == 1
1569 && GET_CODE (operands[1]) == MEM
1570 && rtx_equal_p (operands [0], operands[1]))
1572 rtx temp = XEXP (operands[1], 0);
1574 if (GET_CODE (temp) == REG
1575 || (GET_CODE (temp) == PLUS
1576 && GET_CODE (XEXP (temp, 0)) == REG
1577 && GET_CODE (XEXP (temp, 1)) == CONST_INT))
1578 return "addd %0,%0";
1580 else return "ashd %2,%0";
1582 return "ashd %2,%0";
1585 const char *
1586 output_move_dconst (int n, const char *s)
1588 static char r[32];
1590 if (n > -9 && n < 8)
1591 strcpy (r, "movqd ");
1592 else if (n > 0 && n < 256)
1593 strcpy (r, "movzbd ");
1594 else if (n > 0 && n < 65536)
1595 strcpy (r, "movzwd ");
1596 else if (n < 0 && n > -129)
1597 strcpy (r, "movxbd ");
1598 else if (n < 0 && n > -32769)
1599 strcpy (r, "movxwd ");
1600 else
1601 strcpy (r, "movd ");
1602 strcat (r, s);
1603 return r;
1606 static rtx
1607 ns32k_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
1608 int incoming ATTRIBUTE_UNUSED)
1610 return gen_rtx_REG (Pmode, NS32K_STRUCT_VALUE_REGNUM);
1613 /* Worker function for NOTICE_UPDATE_CC. */
1615 void
1616 ns32k_notice_update_cc (rtx exp, rtx insn ATTRIBUTE_UNUSED)
1618 if (GET_CODE (exp) == SET)
1620 if (GET_CODE (SET_DEST (exp)) == CC0)
1622 cc_status.flags = 0;
1623 cc_status.value1 = SET_DEST (exp);
1624 cc_status.value2 = SET_SRC (exp);
1626 else if (GET_CODE (SET_SRC (exp)) == CALL)
1628 CC_STATUS_INIT;
1630 else if (GET_CODE (SET_DEST (exp)) == REG)
1632 if (cc_status.value1
1633 && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))
1634 cc_status.value1 = 0;
1635 if (cc_status.value2
1636 && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2))
1637 cc_status.value2 = 0;
1639 else if (GET_CODE (SET_DEST (exp)) == MEM)
1641 CC_STATUS_INIT;
1644 else if (GET_CODE (exp) == PARALLEL
1645 && GET_CODE (XVECEXP (exp, 0, 0)) == SET)
1647 if (GET_CODE (SET_DEST (XVECEXP (exp, 0, 0))) == CC0)
1649 cc_status.flags = 0;
1650 cc_status.value1 = SET_DEST (XVECEXP (exp, 0, 0));
1651 cc_status.value2 = SET_SRC (XVECEXP (exp, 0, 0));
1653 else if (GET_CODE (SET_DEST (XVECEXP (exp, 0, 0))) == REG)
1655 if (cc_status.value1
1656 && reg_overlap_mentioned_p (SET_DEST (XVECEXP (exp, 0, 0)),
1657 cc_status.value1))
1658 cc_status.value1 = 0;
1659 if (cc_status.value2
1660 && reg_overlap_mentioned_p (SET_DEST (XVECEXP (exp, 0, 0)),
1661 cc_status.value2))
1662 cc_status.value2 = 0;
1664 else if (GET_CODE (SET_DEST (XVECEXP (exp, 0, 0))) == MEM)
1666 CC_STATUS_INIT;
1669 else if (GET_CODE (exp) == CALL)
1671 /* all bets are off */
1672 CC_STATUS_INIT;
1674 else
1676 /* nothing happens? CC_STATUS_INIT; */
1678 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
1679 && cc_status.value2
1680 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
1681 abort ();
1684 /* Implement TARGET_ARG_PARTIAL_BYTES. */
1686 static int
1687 ns32k_arg_partial_bytes (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
1688 tree type, bool named ATTRIBUTE_UNUSED)
1690 int cum = *pcum;
1692 if (TARGET_REGPARM && cum < 8)
1694 HOST_WIDE_INT size;
1696 if (mode == BLKmode)
1697 size = int_size_in_bytes (type);
1698 else
1699 size = GET_MODE_SIZE (mode);
1701 if (8 < cum + size)
1702 return 8 - cum;
1705 return 0;