OSDN Git Service

Update FSF address.
[pf3gnuchains/gcc-fork.git] / gcc / config / ns32k / ns32k.c
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.
5
6 This file is part of GCC.
7
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.
12
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.
17
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, 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA.  */
22
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"
44
45 #ifdef OSF_OS
46 int ns32k_num_files = 0;
47 #endif
48
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 */
52
53 const unsigned int ns32k_reg_class_contents[N_REG_CLASSES][1] = REG_CLASS_CONTENTS;
54
55 const enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
56 {
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
64 };
65
66 static const char *const ns32k_out_reg_names[] = OUTPUT_REGISTER_NAMES;
67
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);
81 \f
82 /* Initialize the GCC target structure.  */
83 #undef TARGET_ATTRIBUTE_TABLE
84 #define TARGET_ATTRIBUTE_TABLE ns32k_attribute_table
85
86 #undef TARGET_ASM_ALIGNED_HI_OP
87 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
88
89 #ifdef ENCORE_ASM
90 #undef TARGET_ASM_ALIGNED_SI_OP
91 #define TARGET_ASM_ALIGNED_SI_OP "\t.double\t"
92 #endif
93
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
98
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
103
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
108
109 #undef TARGET_STRUCT_VALUE_RTX
110 #define TARGET_STRUCT_VALUE_RTX ns32k_struct_value_rtx
111
112 #undef TARGET_ARG_PARTIAL_BYTES
113 #define TARGET_ARG_PARTIAL_BYTES ns32k_arg_partial_bytes
114
115 #undef TARGET_ASM_FILE_START_APP_OFF
116 #define TARGET_ASM_FILE_START_APP_OFF true
117
118 struct gcc_target targetm = TARGET_INITIALIZER;
119 \f
120 /* Implement TARGET_HANDLE_OPTION.  */
121
122 static bool
123 ns32k_handle_option (size_t code, const char *arg ATTRIBUTE_UNUSED,
124                      int value ATTRIBUTE_UNUSED)
125 {
126   switch (code)
127     {
128     case OPT_m32081:
129       target_flags &= ~MASK_32381;
130       return true;
131
132     case OPT_msoft_float:
133       target_flags &= ~(MASK_32081 | MASK_32381);
134       return true;
135
136     case OPT_m32332:
137       target_flags &= ~MASK_32532;
138       return true;
139
140     case OPT_m32032:
141       target_flags &= ~(MASK_32332 | MASK_32532);
142       return true;
143
144     default:
145       return true;
146     }
147 }
148 \f
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.
152
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.  */
157
158 /*
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
162  *
163  *  # Save the oldframe pointer, set the new frame pointer, make space
164  *  # on the stack and save any general purpose registers necessary
165  *
166  *  enter [<general purpose regs to save>], <local stack space>
167  *
168  *  movf  fn, tos    # Save any floating point registers necessary
169  *  .
170  *  .
171  *
172  * If a frame pointer is not needed we need assembler of the form
173  *
174  *  # Make space on the stack
175  *
176  *  adjspd <local stack space + 4>
177  *
178  *  # Save any general purpose registers necessary
179  *
180  *  save [<general purpose regs to save>]
181  *
182  *  movf  fn, tos    # Save any floating point registers necessary
183  *  .
184  *  .
185  */
186
187 #if !defined (MERLIN_TARGET) && !defined (UTEK_ASM)
188
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
196
197 static void
198 ns32k_output_function_prologue (FILE *file, HOST_WIDE_INT size)
199 {
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;
203
204   for (regno = R0_REGNUM; regno < F0_REGNUM; regno++)
205     if (regs_ever_live[regno]
206         && ! call_used_regs[regno])
207       {
208         *bufp++ = regno; g_regs_used++;
209       }
210   *bufp = -1;
211
212   for (; regno < FRAME_POINTER_REGNUM; regno++)
213     if (regs_ever_live[regno] && !call_used_regs[regno])
214       {
215         *fbufp++ = regno;
216       }
217   *fbufp = -1;
218
219   bufp = used_regs_buf;
220   if (frame_pointer_needed)
221     fprintf (file, "\tenter [");
222   else
223     {
224       if (size)
225         ADJSP (file, size + 4);
226       if (g_regs_used && g_regs_used > 4)
227         fprintf (file, "\tsave [");
228       else
229         {
230           while (*bufp >= 0)
231             fprintf (file, "\tmovd r%d,tos\n", *bufp++);
232           g_regs_used = 0;
233         }
234     }
235
236   while (*bufp >= 0)
237     {
238       fprintf (file, "r%d", *bufp++);
239       if (*bufp >= 0)
240         fputc (',', file);
241     }
242
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");
247
248   fbufp = used_fregs_buf;
249   while (*fbufp >= 0)
250     {
251       if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1))
252         fprintf (file, "\tmovf %s,tos\n", ns32k_out_reg_names[*fbufp++]);
253       else
254         {
255           fprintf (file, "\tmovl %s,tos\n",
256                    ns32k_out_reg_names[fbufp[0]]);
257           fbufp += 2;
258         }
259     }
260
261   if (flag_pic && current_function_uses_pic_offset_table)
262     {
263       fprintf (file, "\tsprd sb,tos\n");
264       if (TARGET_REGPARM)
265         {
266           fprintf (file, "\taddr __GLOBAL_OFFSET_TABLE_(pc),tos\n");
267           fprintf (file, "\tlprd sb,tos\n");
268         }
269       else
270         {
271           fprintf (file, "\taddr __GLOBAL_OFFSET_TABLE_(pc),r0\n");
272           fprintf (file, "\tlprd sb,r0\n");
273         }
274     }
275 }
276
277 #else /* MERLIN_TARGET || UTEK_ASM  */
278
279 /* This differs from the standard one above in printing a bitmask
280    rather than a register list in the enter or save instruction.  */
281
282 static void
283 ns32k_output_function_prologue (file, size)
284      FILE *file;
285      HOST_WIDE_INT size;
286 {
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;
290
291   for (regno = 0; regno < 8; regno++)
292     if (regs_ever_live[regno]
293         && ! call_used_regs[regno])
294       {
295         *bufp++ = regno; g_regs_used++;
296       }
297   *bufp = -1;
298
299   for (; regno < 16; regno++)
300     if (regs_ever_live[regno] && !call_used_regs[regno]) {
301       *fbufp++ = regno;
302     }
303   *fbufp = -1;
304
305   bufp = used_regs_buf;
306   if (frame_pointer_needed)
307     fprintf (file, "\tenter ");
308   else if (g_regs_used)
309     fprintf (file, "\tsave ");
310
311   if (frame_pointer_needed || g_regs_used)
312     {
313       char mask = 0;
314       while (*bufp >= 0)
315         mask |= 1 << *bufp++;
316       fprintf (file, "$0x%x", (int) mask & 0xff);
317     }
318
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");
327
328   fbufp = used_fregs_buf;
329   while (*fbufp >= 0)
330     {
331       if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1))
332         fprintf (file, "\tmovf f%d,tos\n", *fbufp++ - 8);
333       else
334         {
335           fprintf (file, "\tmovl f%d,tos\n", fbufp[0] - 8);
336           fbufp += 2;
337         }
338     }
339 }
340
341 #endif /* MERLIN_TARGET || UTEK_ASM  */
342
343 /* This function generates the assembly code for function exit,
344    on machines that need it.
345
346    The function epilogue should not depend on the current stack pointer,
347    if EXIT_IGNORE_STACK is nonzero.  That doesn't apply here.
348
349    If a frame pointer is needed (decided in reload.c ?) then
350    we need assembler of the form
351
352     movf  tos, fn       # Restore any saved floating point registers
353     .
354     .
355
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>]
359
360    If a frame pointer is not needed we need assembler of the form
361     # Restore any general purpose registers saved
362
363     movf  tos, fn       # Restore any saved floating point registers
364     .
365     .
366     .
367     restore [<general purpose regs to save>]
368
369     # reclaim space allocated on stack
370
371     adjspd <-(local stack space + 4)> */
372
373 #if !defined (MERLIN_TARGET) && !defined (UTEK_ASM)
374
375 static void
376 ns32k_output_function_epilogue (FILE *file, HOST_WIDE_INT size)
377 {
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;
381
382   if (flag_pic && current_function_uses_pic_offset_table)
383     fprintf (file, "\tlprd sb,tos\n");
384
385   *fbufp++ = -2;
386   for (regno = F0_REGNUM; regno < FRAME_POINTER_REGNUM; regno++)
387     if (regs_ever_live[regno] && !call_used_regs[regno])
388       {
389         *fbufp++ = regno; f_regs_used++;
390       }
391   fbufp--;
392
393   for (regno = 0; regno < F0_REGNUM; regno++)
394     if (regs_ever_live[regno]
395         && ! call_used_regs[regno])
396       {
397         *bufp++ = regno; g_regs_used++;
398       }
399
400   while (fbufp > used_fregs_buf)
401     {
402       if ((*fbufp & 1) && fbufp[0] == fbufp[-1] + 1)
403         {
404           fprintf (file, "\tmovl tos,%s\n",
405                    ns32k_out_reg_names[fbufp[-1]]);
406           fbufp -= 2;
407         }
408       else fprintf (file, "\tmovf tos,%s\n", ns32k_out_reg_names[*fbufp--]);
409     }
410
411   if (frame_pointer_needed)
412     fprintf (file, "\texit [");
413   else
414     {
415       if (g_regs_used && g_regs_used > 4)
416         fprintf (file, "\trestore [");
417       else
418         {
419           while (bufp > used_regs_buf)
420             fprintf (file, "\tmovd tos,r%d\n", *--bufp);
421           g_regs_used = 0;
422         }
423     }
424
425   while (bufp > used_regs_buf)
426     {
427       fprintf (file, "r%d", *--bufp);
428       if (bufp > used_regs_buf)
429         fputc (',', file);
430     }
431
432   if (g_regs_used || frame_pointer_needed)
433     fprintf (file, "]\n");
434
435   if (size && !frame_pointer_needed)
436     ADJSP (file, -(size + 4));
437
438   if (current_function_pops_args)
439     fprintf (file, "\tret %d\n", current_function_pops_args);
440   else
441     fprintf (file, "\tret 0\n");
442 }
443
444 #else /* MERLIN_TARGET || UTEK_ASM  */
445
446 /* This differs from the standard one above in printing a bitmask
447    rather than a register list in the exit or restore instruction.  */
448
449 static void
450 ns32k_output_function_epilogue (file, size)
451      FILE *file;
452      HOST_WIDE_INT size ATTRIBUTE_UNUSED;
453 {
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;
457
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++;
462     }
463   fbufp--;
464
465   for (regno = 0; regno < 8; regno++)
466     if (regs_ever_live[regno]
467         && ! call_used_regs[regno])
468       {
469         *bufp++ = regno; g_regs_used++;
470       }
471
472   while (fbufp > used_fregs_buf)
473     {
474       if ((*fbufp & 1) && fbufp[0] == fbufp[-1] + 1)
475         {
476           fprintf (file, "\tmovl tos,f%d\n", fbufp[-1] - 8);
477           fbufp -= 2;
478         }
479       else fprintf (file, "\tmovf tos,f%d\n", *fbufp-- - 8);
480     }
481
482   if (frame_pointer_needed)
483     fprintf (file, "\texit ");
484   else if (g_regs_used)
485     fprintf (file, "\trestore ");
486
487   if (g_regs_used || frame_pointer_needed)
488     {
489       char mask = 0;
490
491       while (bufp > used_regs_buf)
492         {
493           /* Utek assembler takes care of reversing this */
494           mask |= 1 << *--bufp;
495         }
496       fprintf (file, "$0x%x\n", (int) mask & 0xff);
497     }
498
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
510 }
511
512 #endif /* MERLIN_TARGET || UTEK_ASM  */
513
514 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */ 
515 int
516 hard_regno_mode_ok (int regno, enum machine_mode mode)
517 {
518   int size = GET_MODE_UNIT_SIZE (mode);
519
520   if (FLOAT_MODE_P (mode))
521     {
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;
528     }
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;
537 }
538
539 static bool
540 ns32k_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total)
541 {
542   switch (code)
543     {
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;
552
553     case CONST:
554     case LABEL_REF:
555     case SYMBOL_REF:
556       *total = 3;
557       return true;
558
559     case CONST_DOUBLE:
560       *total = 5;
561       return true;
562
563     default:
564       return false;
565     }
566 }
567
568 int
569 register_move_cost (enum reg_class CLASS1, enum reg_class CLASS2)
570 {
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;
583 }
584
585 #if 0
586 /* We made the insn definitions copy from floating point to general
587   registers via the stack.  */
588 int
589 secondary_memory_needed (enum reg_class CLASS1,
590                          enum reg_class CLASS2,
591                          enum machine_mode M)
592 {
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;
596 }
597 #endif
598     
599
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.  */
603
604 static int
605 ns32k_address_cost (rtx operand)
606 {
607   int cost = 0;
608
609   switch (GET_CODE (operand))
610     {
611     case REG:
612       cost += 1;
613       break;
614
615     case POST_DEC:
616     case PRE_DEC:
617       break;
618
619     case CONST_INT:
620       if (INTVAL (operand) <= 7 && INTVAL (operand) >= -8)
621         break;
622       if (INTVAL (operand) < 0x2000 && INTVAL (operand) >= -0x2000)
623         {
624           cost +=1;
625           break;
626         }
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;
635
636     case MEM:
637       cost += ns32k_address_cost (XEXP (operand, 0)) + 3;
638       break;
639
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;
647
648     default:
649       break;
650     }
651
652   return cost;
653 }
654
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.  */
658
659 enum reg_class
660 secondary_reload_class (enum reg_class class,
661                         enum machine_mode mode ATTRIBUTE_UNUSED,
662                         rtx in)
663 {
664   int regno = true_regnum (in);
665
666   if (regno >= FIRST_PSEUDO_REGISTER)
667     regno = -1;
668
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;
674 }
675
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). */
680
681 static rtx
682 gen_indexed_expr (rtx base, rtx index, rtx scale)
683 {
684   rtx addr;
685
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;
694 }
695
696 \f
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". */
702
703 void
704 split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
705 {
706   while (num--)
707     {
708       if (GET_CODE (operands[num]) == REG)
709         {
710           lo_half[num] = gen_rtx_REG (SImode, REGNO (operands[num]));
711           hi_half[num] = gen_rtx_REG (SImode, REGNO (operands[num]) + 1);
712         }
713       else if (CONSTANT_P (operands[num]))
714         {
715           split_double (operands[num], &lo_half[num], &hi_half[num]);
716         }
717       else if (offsettable_memref_p (operands[num]))
718         {
719           lo_half[num] = operands[num];
720           hi_half[num] = adjust_address (operands[num], SImode, 4);
721         }
722       else
723         abort ();
724     }
725 }
726 \f
727 /* Return the best assembler insn template
728    for moving operands[1] into operands[0] as a fullword.  */
729
730 static const char *
731 singlemove_string (rtx *operands)
732 {
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";
738 }
739
740 const char *
741 output_move_double (rtx *operands)
742 {
743   enum anon1 { REGOP, OFFSOP, PUSHOP, CNSTOP, RNDOP } optype0, optype1;
744   rtx latehalf[2];
745
746   /* First classify both operands.  */
747
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;
756
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;
768
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.  */
772
773   if (optype0 == RNDOP || optype1 == RNDOP)
774     abort ();
775
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.
780
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.  */
784
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];
791
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];
800
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];
809
810   /* If one or both operands autodecrementing,
811      do the two words, high-numbered first.  */
812   else if (optype0 == PUSHOP || optype1 == PUSHOP)
813     {
814       output_asm_insn (singlemove_string (latehalf), latehalf);
815       return singlemove_string (operands);
816     }
817
818   /* If the first move would clobber the source of the second one,
819      do them in the other order.  */
820
821   /* Overlapping registers.  */
822   if (optype0 == REGOP && optype1 == REGOP
823       && REGNO (operands[0]) == REGNO (latehalf[1]))
824     {
825       /* Do that word.  */
826       output_asm_insn (singlemove_string (latehalf), latehalf);
827       /* Do low-numbered word.  */
828       return singlemove_string (operands);
829     }
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]))
833     {
834       if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
835           && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
836         {
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);
850         }
851       if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)))
852         {
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);
857         }
858     }
859
860   /* Normal case.  Do the two words, low-numbered first.  */
861
862   output_asm_insn (singlemove_string (operands), operands);
863
864   operands[0] = latehalf[0];
865   operands[1] = latehalf[1];
866   return singlemove_string (operands);
867 }
868
869 \f
870 #define MAX_UNALIGNED_COPY (32)
871 /* Expand string/block move operations.
872
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.  */
877
878 static void
879 move_tail (rtx operands[], int bytes, int offset)
880 {
881   if (bytes & 2)
882     {
883       emit_move_insn (adjust_address (operands[0], HImode, offset),
884                       adjust_address (operands[1], HImode, offset));
885       offset += 2;
886     }
887   if (bytes & 1)
888     emit_move_insn (adjust_address (operands[0], QImode, offset),
889                     adjust_address (operands[1], QImode, offset));
890 }
891
892 void
893 expand_block_move (rtx operands[])
894 {
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);
903
904   if (constp && bytes <= 0)
905     return;
906
907   if (constp && bytes < 20)
908     {
909       int words = bytes >> 2;
910
911       if (words)
912         {
913           if (words < 3)
914             {
915               int offset = 0;
916
917               for (; words; words--, offset += 4)
918                 emit_move_insn (adjust_address (operands[0], SImode, offset),
919                                 adjust_address (operands[1], SImode, offset));
920             }
921           else
922             {
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));
930             
931               emit_insn (gen_movmemsi2(dest, src, GEN_INT (words)));
932             }
933         }
934       move_tail (operands, bytes & 3, bytes & ~3);
935       return;
936     }
937
938   if (align > UNITS_PER_WORD)
939     align = UNITS_PER_WORD;
940
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));
949
950   if (constp && (align == UNITS_PER_WORD || bytes < MAX_UNALIGNED_COPY))
951     {
952       /* constant no of bytes and aligned or small enough copy to not bother
953        * aligning. Emit insns to copy by words.
954        */
955       if (bytes >> 2)
956         {
957           emit_move_insn (count_reg, GEN_INT (bytes >> 2));
958           emit_insn (gen_movmemsi1 (GEN_INT (4)));
959         }
960       /* insns to copy rest */
961       move_tail (operands, bytes & 3, 0);
962     }
963   else if (align == UNITS_PER_WORD)
964     {
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)
969         {
970           move_tail (operands, bytes & 3, 0);
971         }
972       else
973         {
974           /* insns to copy rest */
975           emit_insn (gen_andsi3 (count_reg, bytes_rtx, GEN_INT (3)));
976           emit_insn (gen_movmemsi1 (const1_rtx));
977         }
978     }
979   else
980     {
981       /* Not aligned and we may have a lot to copy so it is worth
982        * aligning.
983        */
984       rtx aligned_label = gen_label_rtx ();
985       rtx bytes_reg;
986
987       bytes_reg = copy_to_mode_reg (SImode, bytes_rtx);
988       if (!constp)
989         {
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
993            */
994           emit_insn (gen_cmpsi (bytes_reg, GEN_INT (MAX_UNALIGNED_COPY)));
995           emit_jump_insn (gen_blt (aligned_label));
996         }
997
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);
1005
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)));
1009
1010       /* insns to copy rest */
1011       emit_insn (gen_andsi3 (count_reg, bytes_reg, GEN_INT (3)));
1012       emit_insn (gen_movmemsi1 (const1_rtx));
1013     }
1014 }
1015 \f
1016
1017 /* Returns 1 if OP contains a global symbol reference */
1018
1019 int
1020 global_symbolic_reference_mentioned_p (rtx op, int f)
1021 {
1022   register const char *fmt;
1023   register int i;
1024
1025   if (GET_CODE (op) == SYMBOL_REF)
1026     {
1027       if (! SYMBOL_REF_LOCAL_P (op))
1028         return 1;
1029       else
1030         return 0;
1031     }
1032   else if (f && GET_CODE (op) != CONST)
1033     return 0;
1034
1035   fmt = GET_RTX_FORMAT (GET_CODE (op));
1036   for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
1037     {
1038       if (fmt[i] == 'E')
1039         {
1040           register int j;
1041
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;
1045         }
1046       else if (fmt[i] == 'e' 
1047                && global_symbolic_reference_mentioned_p (XEXP (op, i), 0))
1048         return 1;
1049     }
1050
1051   return 0;
1052 }
1053
1054 \f
1055 /* Returns 1 if OP contains a symbol reference */
1056
1057 int
1058 symbolic_reference_mentioned_p (rtx op)
1059 {
1060   register const char *fmt;
1061   register int i;
1062
1063   if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
1064     return 1;
1065
1066   fmt = GET_RTX_FORMAT (GET_CODE (op));
1067   for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
1068     {
1069       if (fmt[i] == 'E')
1070         {
1071           register int j;
1072
1073           for (j = XVECLEN (op, i) - 1; j >= 0; j--)
1074             if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
1075               return 1;
1076         }
1077       else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
1078         return 1;
1079     }
1080
1081   return 0;
1082 }
1083 \f
1084 /* Table of machine-specific attributes.  */
1085
1086 const struct attribute_spec ns32k_attribute_table[] =
1087 {
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 }
1095 };
1096
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)
1104 {
1105   if (TREE_CODE (*node) != FUNCTION_TYPE
1106       && TREE_CODE (*node) != FIELD_DECL
1107       && TREE_CODE (*node) != TYPE_DECL)
1108     {
1109       warning (OPT_Wattributes, "%qs attribute only applies to functions",
1110                IDENTIFIER_POINTER (name));
1111       *no_add_attrs = true;
1112     }
1113
1114   return NULL_TREE;
1115 }
1116
1117 \f
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.
1124
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.
1132
1133    The attribute stdcall is equivalent to RET on a per module basis.  */
1134
1135 int
1136 ns32k_return_pops_args (tree fundecl ATTRIBUTE_UNUSED, tree funtype, int size)
1137 {
1138   int rtd = TARGET_RTD;
1139
1140   if (TREE_CODE (funtype) == IDENTIFIER_NODE)
1141     return rtd ? size : 0;
1142
1143   /* Cdecl functions override -mrtd, and never pop the stack */
1144   if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype)))
1145     return 0;
1146
1147   /* Stdcall functions will pop the stack if not variable args */
1148   if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype)))
1149     rtd = 1;
1150
1151   if (rtd)
1152     {
1153       if (TYPE_ARG_TYPES (funtype) == NULL_TREE
1154           || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node))
1155         return size;
1156     }
1157
1158   return 0;
1159 }
1160 \f
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.  */
1164
1165 /* XXX time 12% of cpu time is in fprintf for non optimizing */
1166 void
1167 print_operand (FILE *file, rtx x, int code)
1168 {
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)
1176     {
1177       output_address (XEXP (x, 0));
1178     }
1179   else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != VOIDmode)
1180     {
1181       REAL_VALUE_TYPE r;
1182
1183       REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1184       PUT_IMMEDIATE_PREFIX (file);
1185       if (GET_MODE (x) == DFmode)
1186         { 
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
1202         }
1203       else
1204         {
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
1214         }
1215     }
1216   else
1217     {
1218       if (flag_pic
1219           && GET_CODE (x) == CONST
1220           && symbolic_reference_mentioned_p (x))
1221         {
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 ();
1227         }
1228       else if (flag_pic
1229                && (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF))
1230         {
1231           output_addr_const (file, x);
1232           fprintf (file, "(sb)");
1233         }
1234       else
1235         {
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);
1241         }
1242     }
1243 }
1244 \f
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 .  */
1248
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> */
1253
1254 void
1255 print_operand_address (register FILE *file, register rtx addr)
1256 {
1257   static const char scales[] = { 'b', 'w', 'd', 0, 'q', };
1258   rtx offset, base, indexexp, tmp;
1259   int scale;
1260   extern int flag_pic;
1261
1262   if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == POST_DEC)
1263     {
1264       fprintf (file, "tos");
1265       return;
1266     }
1267
1268   offset = NULL;
1269   base = NULL;
1270   indexexp = NULL;
1271   while (addr != NULL)
1272     {
1273       if (GET_CODE (addr) == PLUS)
1274         {
1275           if (GET_CODE (XEXP (addr, 0)) == PLUS)
1276             {
1277               tmp = XEXP (addr, 1);
1278               addr = XEXP (addr, 0);
1279             }
1280           else
1281             {
1282               tmp = XEXP (addr,0);
1283               addr = XEXP (addr,1);
1284             }
1285         }
1286       else
1287         {
1288           tmp = addr;
1289           addr = NULL;
1290         }
1291       switch (GET_CODE (tmp))
1292         {
1293         case PLUS:
1294           abort ();
1295         case MEM:
1296           if (base)
1297             {
1298               indexexp = base;
1299               base = tmp;
1300             }
1301           else
1302             base = tmp;
1303           break;
1304         case REG:
1305           if (REGNO (tmp) < F0_REGNUM)
1306             if (base)
1307               {
1308                 indexexp = tmp;
1309               }
1310             else
1311               base = tmp;
1312           else
1313             if (base)
1314               {
1315                 indexexp = base;
1316                 base = tmp;
1317               }
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))
1326             {
1327               if (base)
1328                 {
1329                   if (indexexp)
1330                     abort ();
1331                   indexexp = base;
1332                 }
1333               base = tmp;
1334               break;
1335             }
1336         case CONST:
1337           if (flag_pic && GET_CODE (tmp) == CONST)
1338             {
1339               rtx sym, off, tmp1;
1340               tmp1 = XEXP (tmp,0);
1341               if (GET_CODE (tmp1)  != PLUS)
1342                 abort ();
1343
1344               sym = XEXP (tmp1,0);
1345               if (GET_CODE (sym) != SYMBOL_REF)
1346                 {
1347                   off = sym;
1348                   sym = XEXP (tmp1,1);
1349                 }
1350               else
1351                 off = XEXP (tmp1,1);
1352               if (GET_CODE (sym) == SYMBOL_REF)
1353                 {
1354                   if (GET_CODE (off) != CONST_INT)
1355                     abort ();
1356
1357                   if (! SYMBOL_REF_LOCAL_P (sym))
1358                     {
1359                       if (base)
1360                         {
1361                           if (indexexp)
1362                             abort ();
1363
1364                           indexexp = base;
1365                         }
1366
1367                       if (offset != 0)
1368                         abort ();
1369
1370                       base = sym;
1371                       offset = off;
1372                       break;
1373                     }
1374                 }
1375             }
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 ();
1385         }
1386     }
1387   if (! offset)
1388     offset = const0_rtx;
1389
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))
1400     {
1401       indexexp = base;
1402       base = NULL;
1403     }
1404
1405   /* now, offset, base and indexexp are set */
1406 #ifndef BASE_REG_NEEDED
1407   if (! base)
1408     {
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);
1413     }
1414 #endif
1415
1416   output_addr_const (file, offset);
1417   if (base) /* base can be (REG ...) or (MEM ...) */
1418     switch (GET_CODE (base))
1419       {
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 ...)
1428            */
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 ();
1435
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)
1445           {
1446             if (GET_CODE (addr) == PLUS)
1447               {
1448                 if (GET_CODE (XEXP (addr, 0)) == PLUS)
1449                   {
1450                     tmp = XEXP (addr, 1);
1451                     addr = XEXP (addr, 0);
1452                   }
1453                 else
1454                   {
1455                     tmp = XEXP (addr, 0);
1456                     addr = XEXP (addr, 1);
1457                   }
1458               }
1459             else
1460               {
1461                 tmp = addr;
1462                 addr = NULL;
1463               }
1464             switch (GET_CODE (tmp))
1465               {
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 ();
1480               }
1481           }
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 ();
1496       }
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 */
1507
1508   /* now print index if we have one */
1509   if (indexexp)
1510     {
1511       if (GET_CODE (indexexp) == MULT)
1512         {
1513           scale = INTVAL (XEXP (indexexp, 1)) >> 1;
1514           indexexp = XEXP (indexexp, 0);
1515         }
1516       else
1517         scale = 0;
1518       if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= F0_REGNUM)
1519         abort ();
1520
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
1530     }
1531 }
1532 \f
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)
1538 {
1539   if (GET_CODE (operands[2]) == CONST_INT
1540       && INTVAL (operands[2]) > 0
1541       && INTVAL (operands[2]) <= 3)
1542     {
1543       if (GET_CODE (operands[0]) == REG)
1544         {
1545           if (GET_CODE (operands[1]) == REG)
1546             {
1547               if (REGNO (operands[0]) == REGNO (operands[1]))
1548                 {
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";
1553                 }
1554               if (operands[2] == const1_rtx)
1555                 return "movd %1,%0\n\taddd %0,%0";
1556             
1557               operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
1558               return "addr %a1,%0";
1559             }
1560           if (operands[2] == const1_rtx)
1561             return "movd %1,%0\n\taddd %0,%0";
1562         }
1563       else if (GET_CODE (operands[1]) == REG)
1564         {
1565           operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
1566           return "addr %a1,%0";
1567         }
1568       else if (INTVAL (operands[2]) == 1
1569                && GET_CODE (operands[1]) == MEM
1570                && rtx_equal_p (operands [0], operands[1]))
1571         {
1572           rtx temp = XEXP (operands[1], 0);
1573         
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";
1579         }
1580       else return "ashd %2,%0";
1581     }
1582   return "ashd %2,%0";
1583 }
1584
1585 const char *
1586 output_move_dconst (int n, const char *s)
1587 {
1588   static char r[32];
1589
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;
1604 }
1605
1606 static rtx
1607 ns32k_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
1608                         int incoming ATTRIBUTE_UNUSED)
1609 {
1610   return gen_rtx_REG (Pmode, NS32K_STRUCT_VALUE_REGNUM);
1611 }
1612
1613 /* Worker function for NOTICE_UPDATE_CC.  */
1614
1615 void
1616 ns32k_notice_update_cc (rtx exp, rtx insn ATTRIBUTE_UNUSED)
1617 {
1618   if (GET_CODE (exp) == SET)
1619     {
1620       if (GET_CODE (SET_DEST (exp)) == CC0)
1621         {
1622           cc_status.flags = 0;
1623           cc_status.value1 = SET_DEST (exp);
1624           cc_status.value2 = SET_SRC (exp);
1625         }
1626       else if (GET_CODE (SET_SRC (exp)) == CALL)
1627         {
1628           CC_STATUS_INIT;
1629         }
1630       else if (GET_CODE (SET_DEST (exp)) == REG)
1631         {
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;
1638         }
1639       else if (GET_CODE (SET_DEST (exp)) == MEM)
1640         {
1641           CC_STATUS_INIT;
1642         }
1643     }
1644   else if (GET_CODE (exp) == PARALLEL
1645            && GET_CODE (XVECEXP (exp, 0, 0)) == SET)
1646     {
1647       if (GET_CODE (SET_DEST (XVECEXP (exp, 0, 0))) == CC0)
1648         {
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));
1652         }
1653       else if (GET_CODE (SET_DEST (XVECEXP (exp, 0, 0))) == REG)
1654         {
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;
1663         }
1664       else if (GET_CODE (SET_DEST (XVECEXP (exp, 0, 0))) == MEM)
1665         {
1666           CC_STATUS_INIT;
1667         }
1668     }
1669   else if (GET_CODE (exp) == CALL)
1670     {
1671       /* all bets are off */
1672       CC_STATUS_INIT;
1673     }
1674   else
1675     {
1676       /* nothing happens? CC_STATUS_INIT; */
1677     }
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 ();
1682 }
1683
1684 /* Implement TARGET_ARG_PARTIAL_BYTES.  */
1685
1686 static int
1687 ns32k_arg_partial_bytes (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
1688                          tree type, bool named ATTRIBUTE_UNUSED)
1689 {
1690   int cum = *pcum;
1691
1692   if (TARGET_REGPARM && cum < 8)
1693     {
1694       HOST_WIDE_INT size;
1695
1696       if (mode == BLKmode)
1697         size = int_size_in_bytes (type);
1698       else
1699         size = GET_MODE_SIZE (mode);
1700
1701       if (8 < cum + size)
1702         return 8 - cum;
1703     }
1704
1705   return 0;
1706 }