OSDN Git Service

8cf3fa7d1cb069ae7a5cb3bb5053f12a72814e85
[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, 2004
3    Free Software Foundation, Inc.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING.  If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.  */
21
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tm.h"
26 #include "rtl.h"
27 #include "regs.h"
28 #include "hard-reg-set.h"
29 #include "real.h"
30 #include "insn-config.h"
31 #include "conditions.h"
32 #include "output.h"
33 #include "insn-attr.h"
34 #include "tree.h"
35 #include "function.h"
36 #include "expr.h"
37 #include "flags.h"
38 #include "recog.h"
39 #include "tm_p.h"
40 #include "target.h"
41 #include "target-def.h"
42 #include "toplev.h"
43
44 #ifdef OSF_OS
45 int ns32k_num_files = 0;
46 #endif
47
48 /* This duplicates reg_class_contents in reg_class.c, but maybe that isn't
49    initialized in time. Also this is more convenient as an array of ints.
50    We know that HARD_REG_SET fits in an unsigned int */
51
52 const unsigned int ns32k_reg_class_contents[N_REG_CLASSES][1] = REG_CLASS_CONTENTS;
53
54 const enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
55 {
56   GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
57   GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
58   FLOAT_REG0, LONG_FLOAT_REG0, FLOAT_REGS, FLOAT_REGS,
59   FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS,
60   LONG_REGS, LONG_REGS, LONG_REGS, LONG_REGS,
61   LONG_REGS, LONG_REGS, LONG_REGS, LONG_REGS,
62   FRAME_POINTER_REG, STACK_POINTER_REG
63 };
64
65 static const char *const ns32k_out_reg_names[] = OUTPUT_REGISTER_NAMES;
66
67 static bool ns32k_handle_option (size_t, const char *, int);
68 static rtx gen_indexed_expr (rtx, rtx, rtx);
69 static const char *singlemove_string (rtx *);
70 static void move_tail (rtx[], int, int);
71 static tree ns32k_handle_fntype_attribute (tree *, tree, tree, int, bool *);
72 const struct attribute_spec ns32k_attribute_table[];
73 static void ns32k_output_function_prologue (FILE *, HOST_WIDE_INT);
74 static void ns32k_output_function_epilogue (FILE *, HOST_WIDE_INT);
75 static bool ns32k_rtx_costs (rtx, int, int, int *);
76 static int ns32k_address_cost (rtx);
77 static rtx ns32k_struct_value_rtx (tree, int);
78 static int ns32k_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
79                                     tree, bool);
80 \f
81 /* Initialize the GCC target structure.  */
82 #undef TARGET_ATTRIBUTE_TABLE
83 #define TARGET_ATTRIBUTE_TABLE ns32k_attribute_table
84
85 #undef TARGET_ASM_ALIGNED_HI_OP
86 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
87
88 #ifdef ENCORE_ASM
89 #undef TARGET_ASM_ALIGNED_SI_OP
90 #define TARGET_ASM_ALIGNED_SI_OP "\t.double\t"
91 #endif
92
93 #undef TARGET_ASM_FUNCTION_PROLOGUE
94 #define TARGET_ASM_FUNCTION_PROLOGUE ns32k_output_function_prologue
95 #undef TARGET_ASM_FUNCTION_EPILOGUE
96 #define TARGET_ASM_FUNCTION_EPILOGUE ns32k_output_function_epilogue
97
98 #undef TARGET_DEFAULT_TARGET_FLAGS
99 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
100 #undef TARGET_HANDLE_OPTION
101 #define TARGET_HANDLE_OPTION ns32k_handle_option
102
103 #undef TARGET_RTX_COSTS
104 #define TARGET_RTX_COSTS ns32k_rtx_costs
105 #undef TARGET_ADDRESS_COST
106 #define TARGET_ADDRESS_COST ns32k_address_cost
107
108 #undef TARGET_STRUCT_VALUE_RTX
109 #define TARGET_STRUCT_VALUE_RTX ns32k_struct_value_rtx
110
111 #undef TARGET_ARG_PARTIAL_BYTES
112 #define TARGET_ARG_PARTIAL_BYTES ns32k_arg_partial_bytes
113
114 #undef TARGET_ASM_FILE_START_APP_OFF
115 #define TARGET_ASM_FILE_START_APP_OFF true
116
117 struct gcc_target targetm = TARGET_INITIALIZER;
118 \f
119 /* Implement TARGET_HANDLE_OPTION.  */
120
121 static bool
122 ns32k_handle_option (size_t code, const char *arg ATTRIBUTE_UNUSED,
123                      int value ATTRIBUTE_UNUSED)
124 {
125   switch (code)
126     {
127     case OPT_m32081:
128       target_flags &= ~MASK_32381;
129       return true;
130
131     case OPT_msoft_float:
132       target_flags &= ~(MASK_32081 | MASK_32381);
133       return true;
134
135     case OPT_m32332:
136       target_flags &= ~MASK_32532;
137       return true;
138
139     case OPT_m32032:
140       target_flags &= ~(MASK_32332 | MASK_32532);
141       return true;
142
143     default:
144       return true;
145     }
146 }
147 \f
148 /* Generate the assembly code for function entry.  FILE is a stdio
149    stream to output the code to.  SIZE is an int: how many units of
150    temporary storage to allocate.
151
152    Refer to the array `regs_ever_live' to determine which registers to
153    save; `regs_ever_live[I]' is nonzero if register number I is ever
154    used in the function.  This function is responsible for knowing
155    which registers should not be saved even if used.  */
156
157 /*
158  * The function prologue for the ns32k is fairly simple.
159  * If a frame pointer is needed (decided in reload.c ?) then
160  * we need assembler of the form
161  *
162  *  # Save the oldframe pointer, set the new frame pointer, make space
163  *  # on the stack and save any general purpose registers necessary
164  *
165  *  enter [<general purpose regs to save>], <local stack space>
166  *
167  *  movf  fn, tos    # Save any floating point registers necessary
168  *  .
169  *  .
170  *
171  * If a frame pointer is not needed we need assembler of the form
172  *
173  *  # Make space on the stack
174  *
175  *  adjspd <local stack space + 4>
176  *
177  *  # Save any general purpose registers necessary
178  *
179  *  save [<general purpose regs to save>]
180  *
181  *  movf  fn, tos    # Save any floating point registers necessary
182  *  .
183  *  .
184  */
185
186 #if !defined (MERLIN_TARGET) && !defined (UTEK_ASM)
187
188 #if defined(IMMEDIATE_PREFIX) && IMMEDIATE_PREFIX
189 #define ADJSP(FILE, N) \
190         fprintf (FILE, "\tadjspd %c" HOST_WIDE_INT_PRINT_DEC "\n", IMMEDIATE_PREFIX, (N))
191 #else
192 #define ADJSP(FILE, N) \
193         fprintf (FILE, "\tadjspd " HOST_WIDE_INT_PRINT_DEC "\n", (N))
194 #endif
195
196 static void
197 ns32k_output_function_prologue (FILE *file, HOST_WIDE_INT size)
198 {
199   register int regno, g_regs_used = 0;
200   int used_regs_buf[8], *bufp = used_regs_buf;
201   int used_fregs_buf[17], *fbufp = used_fregs_buf;
202
203   for (regno = R0_REGNUM; regno < F0_REGNUM; regno++)
204     if (regs_ever_live[regno]
205         && ! call_used_regs[regno])
206       {
207         *bufp++ = regno; g_regs_used++;
208       }
209   *bufp = -1;
210
211   for (; regno < FRAME_POINTER_REGNUM; regno++)
212     if (regs_ever_live[regno] && !call_used_regs[regno])
213       {
214         *fbufp++ = regno;
215       }
216   *fbufp = -1;
217
218   bufp = used_regs_buf;
219   if (frame_pointer_needed)
220     fprintf (file, "\tenter [");
221   else
222     {
223       if (size)
224         ADJSP (file, size + 4);
225       if (g_regs_used && g_regs_used > 4)
226         fprintf (file, "\tsave [");
227       else
228         {
229           while (*bufp >= 0)
230             fprintf (file, "\tmovd r%d,tos\n", *bufp++);
231           g_regs_used = 0;
232         }
233     }
234
235   while (*bufp >= 0)
236     {
237       fprintf (file, "r%d", *bufp++);
238       if (*bufp >= 0)
239         fputc (',', file);
240     }
241
242   if (frame_pointer_needed)
243     fprintf (file, "]," HOST_WIDE_INT_PRINT_DEC "\n", size);
244   else if (g_regs_used)
245     fprintf (file, "]\n");
246
247   fbufp = used_fregs_buf;
248   while (*fbufp >= 0)
249     {
250       if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1))
251         fprintf (file, "\tmovf %s,tos\n", ns32k_out_reg_names[*fbufp++]);
252       else
253         {
254           fprintf (file, "\tmovl %s,tos\n",
255                    ns32k_out_reg_names[fbufp[0]]);
256           fbufp += 2;
257         }
258     }
259
260   if (flag_pic && current_function_uses_pic_offset_table)
261     {
262       fprintf (file, "\tsprd sb,tos\n");
263       if (TARGET_REGPARM)
264         {
265           fprintf (file, "\taddr __GLOBAL_OFFSET_TABLE_(pc),tos\n");
266           fprintf (file, "\tlprd sb,tos\n");
267         }
268       else
269         {
270           fprintf (file, "\taddr __GLOBAL_OFFSET_TABLE_(pc),r0\n");
271           fprintf (file, "\tlprd sb,r0\n");
272         }
273     }
274 }
275
276 #else /* MERLIN_TARGET || UTEK_ASM  */
277
278 /* This differs from the standard one above in printing a bitmask
279    rather than a register list in the enter or save instruction.  */
280
281 static void
282 ns32k_output_function_prologue (file, size)
283      FILE *file;
284      HOST_WIDE_INT size;
285 {
286   register int regno, g_regs_used = 0;
287   int used_regs_buf[8], *bufp = used_regs_buf;
288   int used_fregs_buf[8], *fbufp = used_fregs_buf;
289
290   for (regno = 0; regno < 8; regno++)
291     if (regs_ever_live[regno]
292         && ! call_used_regs[regno])
293       {
294         *bufp++ = regno; g_regs_used++;
295       }
296   *bufp = -1;
297
298   for (; regno < 16; regno++)
299     if (regs_ever_live[regno] && !call_used_regs[regno]) {
300       *fbufp++ = regno;
301     }
302   *fbufp = -1;
303
304   bufp = used_regs_buf;
305   if (frame_pointer_needed)
306     fprintf (file, "\tenter ");
307   else if (g_regs_used)
308     fprintf (file, "\tsave ");
309
310   if (frame_pointer_needed || g_regs_used)
311     {
312       char mask = 0;
313       while (*bufp >= 0)
314         mask |= 1 << *bufp++;
315       fprintf (file, "$0x%x", (int) mask & 0xff);
316     }
317
318   if (frame_pointer_needed)
319 #ifdef UTEK_ASM
320     fprintf (file, ",$%d\n", size);
321 #else
322     fprintf (file, ",%d\n", size);
323 #endif
324   else if (g_regs_used)
325     fprintf (file, "\n");
326
327   fbufp = used_fregs_buf;
328   while (*fbufp >= 0)
329     {
330       if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1))
331         fprintf (file, "\tmovf f%d,tos\n", *fbufp++ - 8);
332       else
333         {
334           fprintf (file, "\tmovl f%d,tos\n", fbufp[0] - 8);
335           fbufp += 2;
336         }
337     }
338 }
339
340 #endif /* MERLIN_TARGET || UTEK_ASM  */
341
342 /* This function generates the assembly code for function exit,
343    on machines that need it.
344
345    The function epilogue should not depend on the current stack pointer,
346    if EXIT_IGNORE_STACK is nonzero.  That doesn't apply here.
347
348    If a frame pointer is needed (decided in reload.c ?) then
349    we need assembler of the form
350
351     movf  tos, fn       # Restore any saved floating point registers
352     .
353     .
354
355     # Restore any saved general purpose registers, restore the stack
356     # pointer from the frame pointer, restore the old frame pointer.
357     exit [<general purpose regs to save>]
358
359    If a frame pointer is not needed we need assembler of the form
360     # Restore any general purpose registers saved
361
362     movf  tos, fn       # Restore any saved floating point registers
363     .
364     .
365     .
366     restore [<general purpose regs to save>]
367
368     # reclaim space allocated on stack
369
370     adjspd <-(local stack space + 4)> */
371
372 #if !defined (MERLIN_TARGET) && !defined (UTEK_ASM)
373
374 static void
375 ns32k_output_function_epilogue (FILE *file, HOST_WIDE_INT size)
376 {
377   register int regno, g_regs_used = 0, f_regs_used = 0;
378   int used_regs_buf[8], *bufp = used_regs_buf;
379   int used_fregs_buf[17], *fbufp = used_fregs_buf;
380
381   if (flag_pic && current_function_uses_pic_offset_table)
382     fprintf (file, "\tlprd sb,tos\n");
383
384   *fbufp++ = -2;
385   for (regno = F0_REGNUM; regno < FRAME_POINTER_REGNUM; regno++)
386     if (regs_ever_live[regno] && !call_used_regs[regno])
387       {
388         *fbufp++ = regno; f_regs_used++;
389       }
390   fbufp--;
391
392   for (regno = 0; regno < F0_REGNUM; regno++)
393     if (regs_ever_live[regno]
394         && ! call_used_regs[regno])
395       {
396         *bufp++ = regno; g_regs_used++;
397       }
398
399   while (fbufp > used_fregs_buf)
400     {
401       if ((*fbufp & 1) && fbufp[0] == fbufp[-1] + 1)
402         {
403           fprintf (file, "\tmovl tos,%s\n",
404                    ns32k_out_reg_names[fbufp[-1]]);
405           fbufp -= 2;
406         }
407       else fprintf (file, "\tmovf tos,%s\n", ns32k_out_reg_names[*fbufp--]);
408     }
409
410   if (frame_pointer_needed)
411     fprintf (file, "\texit [");
412   else
413     {
414       if (g_regs_used && g_regs_used > 4)
415         fprintf (file, "\trestore [");
416       else
417         {
418           while (bufp > used_regs_buf)
419             fprintf (file, "\tmovd tos,r%d\n", *--bufp);
420           g_regs_used = 0;
421         }
422     }
423
424   while (bufp > used_regs_buf)
425     {
426       fprintf (file, "r%d", *--bufp);
427       if (bufp > used_regs_buf)
428         fputc (',', file);
429     }
430
431   if (g_regs_used || frame_pointer_needed)
432     fprintf (file, "]\n");
433
434   if (size && !frame_pointer_needed)
435     ADJSP (file, -(size + 4));
436
437   if (current_function_pops_args)
438     fprintf (file, "\tret %d\n", current_function_pops_args);
439   else
440     fprintf (file, "\tret 0\n");
441 }
442
443 #else /* MERLIN_TARGET || UTEK_ASM  */
444
445 /* This differs from the standard one above in printing a bitmask
446    rather than a register list in the exit or restore instruction.  */
447
448 static void
449 ns32k_output_function_epilogue (file, size)
450      FILE *file;
451      HOST_WIDE_INT size ATTRIBUTE_UNUSED;
452 {
453   register int regno, g_regs_used = 0, f_regs_used = 0;
454   int used_regs_buf[8], *bufp = used_regs_buf;
455   int used_fregs_buf[8], *fbufp = used_fregs_buf;
456
457   *fbufp++ = -2;
458   for (regno = 8; regno < 16; regno++)
459     if (regs_ever_live[regno] && !call_used_regs[regno]) {
460       *fbufp++ = regno; f_regs_used++;
461     }
462   fbufp--;
463
464   for (regno = 0; regno < 8; regno++)
465     if (regs_ever_live[regno]
466         && ! call_used_regs[regno])
467       {
468         *bufp++ = regno; g_regs_used++;
469       }
470
471   while (fbufp > used_fregs_buf)
472     {
473       if ((*fbufp & 1) && fbufp[0] == fbufp[-1] + 1)
474         {
475           fprintf (file, "\tmovl tos,f%d\n", fbufp[-1] - 8);
476           fbufp -= 2;
477         }
478       else fprintf (file, "\tmovf tos,f%d\n", *fbufp-- - 8);
479     }
480
481   if (frame_pointer_needed)
482     fprintf (file, "\texit ");
483   else if (g_regs_used)
484     fprintf (file, "\trestore ");
485
486   if (g_regs_used || frame_pointer_needed)
487     {
488       char mask = 0;
489
490       while (bufp > used_regs_buf)
491         {
492           /* Utek assembler takes care of reversing this */
493           mask |= 1 << *--bufp;
494         }
495       fprintf (file, "$0x%x\n", (int) mask & 0xff);
496     }
497
498 #ifdef UTEK_ASM
499   if (current_function_pops_args)
500     fprintf (file, "\tret $%d\n", current_function_pops_args);
501   else
502     fprintf (file, "\tret $0\n");
503 #else
504   if (current_function_pops_args)
505     fprintf (file, "\tret %d\n", current_function_pops_args);
506   else
507     fprintf (file, "\tret 0\n");
508 #endif
509 }
510
511 #endif /* MERLIN_TARGET || UTEK_ASM  */
512
513 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */ 
514 int
515 hard_regno_mode_ok (int regno, enum machine_mode mode)
516 {
517   int size = GET_MODE_UNIT_SIZE (mode);
518
519   if (FLOAT_MODE_P (mode))
520     {
521       if (size == UNITS_PER_WORD && regno < L1_REGNUM)
522         return 1;
523       if (size == UNITS_PER_WORD * 2
524           && (((regno & 1) == 0 && regno < FRAME_POINTER_REGNUM)))
525         return 1;
526       return 0;
527     }
528   if (size == UNITS_PER_WORD * 2
529       && (regno & 1) == 0 && regno < F0_REGNUM)
530     return 1;
531   if (size <= UNITS_PER_WORD
532       && (regno < F0_REGNUM || regno == FRAME_POINTER_REGNUM
533           || regno == STACK_POINTER_REGNUM))
534     return 1;
535   return 0;
536 }
537
538 static bool
539 ns32k_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total)
540 {
541   switch (code)
542     {
543     case CONST_INT:
544       if (INTVAL (x) <= 7 && INTVAL (x) >= -8)
545         *total = 0;
546       else if (INTVAL (x) < 0x2000 && INTVAL (x) >= -0x2000)
547         *total = 1;
548       else
549         *total = 3;
550       return true;
551
552     case CONST:
553     case LABEL_REF:
554     case SYMBOL_REF:
555       *total = 3;
556       return true;
557
558     case CONST_DOUBLE:
559       *total = 5;
560       return true;
561
562     default:
563       return false;
564     }
565 }
566
567 int
568 register_move_cost (enum reg_class CLASS1, enum reg_class CLASS2)
569 {
570   if (CLASS1 == NO_REGS || CLASS2 == NO_REGS)
571     return 2;
572   if ((SUBSET_P (CLASS1, FP_REGS) && !SUBSET_P (CLASS2, FP_REGS))
573    || (!SUBSET_P (CLASS1, FP_REGS) && SUBSET_P (CLASS2, FP_REGS)))
574     return 8;
575   if (((CLASS1) == STACK_POINTER_REG && !SUBSET_P (CLASS2,GENERAL_REGS))
576       || ((CLASS2) == STACK_POINTER_REG && !SUBSET_P (CLASS1,GENERAL_REGS)))
577     return 6;
578   if (((CLASS1) == FRAME_POINTER_REG && !SUBSET_P (CLASS2,GENERAL_REGS))
579       || ((CLASS2) == FRAME_POINTER_REG && !SUBSET_P (CLASS1,GENERAL_REGS)))
580     return 6;
581   return 2;
582 }
583
584 #if 0
585 /* We made the insn definitions copy from floating point to general
586   registers via the stack.  */
587 int
588 secondary_memory_needed (enum reg_class CLASS1,
589                          enum reg_class CLASS2,
590                          enum machine_mode M)
591 {
592   int ret = ((SUBSET_P (CLASS1, FP_REGS) && !SUBSET_P (CLASS2, FP_REGS))
593    || (!SUBSET_P (CLASS1, FP_REGS) && SUBSET_P (CLASS2, FP_REGS)));
594   return ret;
595 }
596 #endif
597     
598
599 /* TARGET_ADDRESS_COST calls this.  This function is not optimal
600    for the 32032 & 32332, but it probably is better than
601    the default.  */
602
603 static int
604 ns32k_address_cost (rtx operand)
605 {
606   int cost = 0;
607
608   switch (GET_CODE (operand))
609     {
610     case REG:
611       cost += 1;
612       break;
613
614     case POST_DEC:
615     case PRE_DEC:
616       break;
617
618     case CONST_INT:
619       if (INTVAL (operand) <= 7 && INTVAL (operand) >= -8)
620         break;
621       if (INTVAL (operand) < 0x2000 && INTVAL (operand) >= -0x2000)
622         {
623           cost +=1;
624           break;
625         }
626     case CONST:
627     case LABEL_REF:
628     case SYMBOL_REF:
629       cost +=3;
630       break;
631     case CONST_DOUBLE:
632       cost += 5;
633       break;
634
635     case MEM:
636       cost += ns32k_address_cost (XEXP (operand, 0)) + 3;
637       break;
638
639     case MULT:
640       cost += 2;
641       /* FALLTHRU */
642     case PLUS:
643       cost += ns32k_address_cost (XEXP (operand, 0));
644       cost += ns32k_address_cost (XEXP (operand, 1));
645       break;
646
647     default:
648       break;
649     }
650
651   return cost;
652 }
653
654 /* Return the register class of a scratch register needed to copy IN into
655    or out of a register in CLASS in MODE.  If it can be done directly,
656    NO_REGS is returned.  */
657
658 enum reg_class
659 secondary_reload_class (enum reg_class class,
660                         enum machine_mode mode ATTRIBUTE_UNUSED,
661                         rtx in)
662 {
663   int regno = true_regnum (in);
664
665   if (regno >= FIRST_PSEUDO_REGISTER)
666     regno = -1;
667
668   if ((class == FRAME_POINTER_REG && regno == STACK_POINTER_REGNUM)
669       || ( class == STACK_POINTER_REG && regno == FRAME_POINTER_REGNUM))
670     return GENERAL_REGS;
671   else
672     return NO_REGS;
673 }
674
675 /* Generate the rtx that comes from an address expression in the md file */
676 /* The expression to be build is BASE[INDEX:SCALE].  To recognize this,
677    scale must be converted from an exponent (from ASHIFT) to a
678    multiplier (for MULT). */
679
680 static rtx
681 gen_indexed_expr (rtx base, rtx index, rtx scale)
682 {
683   rtx addr;
684
685   /* This generates an invalid addressing mode, if BASE is
686      fp or sp.  This is handled by PRINT_OPERAND_ADDRESS.  */
687   if (GET_CODE (base) != REG && GET_CODE (base) != CONST_INT)
688     base = gen_rtx_MEM (SImode, base);
689   addr = gen_rtx_MULT (SImode, index,
690                        GEN_INT (1 << INTVAL (scale)));
691   addr = gen_rtx_PLUS (SImode, base, addr);
692   return addr;
693 }
694
695 \f
696 /* Split one or more DImode RTL references into pairs of SImode
697    references.  The RTL can be REG, offsettable MEM, integer constant, or
698    CONST_DOUBLE.  "operands" is a pointer to an array of DImode RTL to
699    split and "num" is its length.  lo_half and hi_half are output arrays
700    that parallel "operands". */
701
702 void
703 split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
704 {
705   while (num--)
706     {
707       if (GET_CODE (operands[num]) == REG)
708         {
709           lo_half[num] = gen_rtx_REG (SImode, REGNO (operands[num]));
710           hi_half[num] = gen_rtx_REG (SImode, REGNO (operands[num]) + 1);
711         }
712       else if (CONSTANT_P (operands[num]))
713         {
714           split_double (operands[num], &lo_half[num], &hi_half[num]);
715         }
716       else if (offsettable_memref_p (operands[num]))
717         {
718           lo_half[num] = operands[num];
719           hi_half[num] = adjust_address (operands[num], SImode, 4);
720         }
721       else
722         abort ();
723     }
724 }
725 \f
726 /* Return the best assembler insn template
727    for moving operands[1] into operands[0] as a fullword.  */
728
729 static const char *
730 singlemove_string (rtx *operands)
731 {
732   if (GET_CODE (operands[1]) == CONST_INT
733       && INTVAL (operands[1]) <= 7
734       && INTVAL (operands[1]) >= -8)
735     return "movqd %1,%0";
736   return "movd %1,%0";
737 }
738
739 const char *
740 output_move_double (rtx *operands)
741 {
742   enum anon1 { REGOP, OFFSOP, PUSHOP, CNSTOP, RNDOP } optype0, optype1;
743   rtx latehalf[2];
744
745   /* First classify both operands.  */
746
747   if (REG_P (operands[0]))
748     optype0 = REGOP;
749   else if (offsettable_memref_p (operands[0]))
750     optype0 = OFFSOP;
751   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
752     optype0 = PUSHOP;
753   else
754     optype0 = RNDOP;
755
756   if (REG_P (operands[1]))
757     optype1 = REGOP;
758   else if (CONSTANT_P (operands[1])
759            || GET_CODE (operands[1]) == CONST_DOUBLE)
760     optype1 = CNSTOP;
761   else if (offsettable_memref_p (operands[1]))
762     optype1 = OFFSOP;
763   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
764     optype1 = PUSHOP;
765   else
766     optype1 = RNDOP;
767
768   /* Check for the cases that the operand constraints are not
769      supposed to allow to happen.  Abort if we get one,
770      because generating code for these cases is painful.  */
771
772   if (optype0 == RNDOP || optype1 == RNDOP)
773     abort ();
774
775   /* Ok, we can do one word at a time.
776      Normally we do the low-numbered word first,
777      but if either operand is autodecrementing then we
778      do the high-numbered word first.
779
780      In either case, set up in LATEHALF the operands to use
781      for the high-numbered word and in some cases alter the
782      operands in OPERANDS to be suitable for the low-numbered word.  */
783
784   if (optype0 == REGOP)
785     latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
786   else if (optype0 == OFFSOP)
787     latehalf[0] = adjust_address (operands[0], SImode, 4);
788   else
789     latehalf[0] = operands[0];
790
791   if (optype1 == REGOP)
792     latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
793   else if (optype1 == OFFSOP)
794     latehalf[1] = adjust_address (operands[1], SImode, 4);
795   else if (optype1 == CNSTOP)
796     split_double (operands[1], &operands[1], &latehalf[1]);
797   else
798     latehalf[1] = operands[1];
799
800   /* If insn is effectively movd N(sp),tos then we will do the
801      high word first.  We should use the adjusted operand 1 (which is N+4(sp))
802      for the low word as well, to compensate for the first decrement of sp.
803      Given this, it doesn't matter which half we do "first".  */
804   if (optype0 == PUSHOP
805       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
806       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
807     operands[1] = latehalf[1];
808
809   /* If one or both operands autodecrementing,
810      do the two words, high-numbered first.  */
811   else if (optype0 == PUSHOP || optype1 == PUSHOP)
812     {
813       output_asm_insn (singlemove_string (latehalf), latehalf);
814       return singlemove_string (operands);
815     }
816
817   /* If the first move would clobber the source of the second one,
818      do them in the other order.  */
819
820   /* Overlapping registers.  */
821   if (optype0 == REGOP && optype1 == REGOP
822       && REGNO (operands[0]) == REGNO (latehalf[1]))
823     {
824       /* Do that word.  */
825       output_asm_insn (singlemove_string (latehalf), latehalf);
826       /* Do low-numbered word.  */
827       return singlemove_string (operands);
828     }
829   /* Loading into a register which overlaps a register used in the address.  */
830   else if (optype0 == REGOP && optype1 != REGOP
831            && reg_overlap_mentioned_p (operands[0], operands[1]))
832     {
833       if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
834           && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
835         {
836           /* If both halves of dest are used in the src memory address,
837              load the destination address into the low reg (operands[0]).
838              Then it works to load latehalf first.  */
839           rtx xops[2];
840           xops[0] = XEXP (operands[1], 0);
841           xops[1] = operands[0];
842           output_asm_insn ("addr %a0,%1", xops);
843           operands[1] = gen_rtx_MEM (DImode, operands[0]);
844           latehalf[1] = adjust_address (operands[1], SImode, 4);
845           /* The first half has the overlap, Do the late half first.  */
846           output_asm_insn (singlemove_string (latehalf), latehalf);
847           /* Then clobber.  */
848           return singlemove_string (operands);
849         }
850       if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)))
851         {
852           /* The first half has the overlap, Do the late half first.  */
853           output_asm_insn (singlemove_string (latehalf), latehalf);
854           /* Then clobber.  */
855           return singlemove_string (operands);
856         }
857     }
858
859   /* Normal case.  Do the two words, low-numbered first.  */
860
861   output_asm_insn (singlemove_string (operands), operands);
862
863   operands[0] = latehalf[0];
864   operands[1] = latehalf[1];
865   return singlemove_string (operands);
866 }
867
868 \f
869 #define MAX_UNALIGNED_COPY (32)
870 /* Expand string/block move operations.
871
872    operands[0] is the pointer to the destination.
873    operands[1] is the pointer to the source.
874    operands[2] is the number of bytes to move.
875    operands[3] is the alignment.  */
876
877 static void
878 move_tail (rtx operands[], int bytes, int offset)
879 {
880   if (bytes & 2)
881     {
882       emit_move_insn (adjust_address (operands[0], HImode, offset),
883                       adjust_address (operands[1], HImode, offset));
884       offset += 2;
885     }
886   if (bytes & 1)
887     emit_move_insn (adjust_address (operands[0], QImode, offset),
888                     adjust_address (operands[1], QImode, offset));
889 }
890
891 void
892 expand_block_move (rtx operands[])
893 {
894   rtx bytes_rtx = operands[2];
895   rtx align_rtx = operands[3];
896   int constp    = (GET_CODE (bytes_rtx) == CONST_INT);
897   int bytes     = (constp ? INTVAL (bytes_rtx) : 0);
898   int align     = INTVAL (align_rtx);
899   rtx src_reg = gen_rtx_REG (Pmode, 1);
900   rtx dest_reg = gen_rtx_REG (Pmode, 2);
901   rtx count_reg = gen_rtx_REG (SImode, 0);
902
903   if (constp && bytes <= 0)
904     return;
905
906   if (constp && bytes < 20)
907     {
908       int words = bytes >> 2;
909
910       if (words)
911         {
912           if (words < 3)
913             {
914               int offset = 0;
915
916               for (; words; words--, offset += 4)
917                 emit_move_insn (adjust_address (operands[0], SImode, offset),
918                                 adjust_address (operands[1], SImode, offset));
919             }
920           else
921             {
922               /* Use movmd. It is slower than multiple movd's but more
923                  compact. It is also slower than movsd for large copies
924                  but causes less registers reloading so is better than movsd
925                  for small copies.  */
926               rtx src, dest;
927               dest = copy_addr_to_reg (XEXP (operands[0], 0));
928               src = copy_addr_to_reg (XEXP (operands[1], 0));
929             
930               emit_insn (gen_movmemsi2(dest, src, GEN_INT (words)));
931             }
932         }
933       move_tail (operands, bytes & 3, bytes & ~3);
934       return;
935     }
936
937   if (align > UNITS_PER_WORD)
938     align = UNITS_PER_WORD;
939
940   /* Move the address into scratch registers.  */
941   emit_insn (gen_rtx_CLOBBER (VOIDmode, dest_reg));
942   emit_move_insn (dest_reg, XEXP (operands[0], 0));
943   operands[0] = gen_rtx_MEM (SImode, dest_reg);
944   emit_insn (gen_rtx_CLOBBER (VOIDmode, src_reg));
945   emit_move_insn (src_reg, XEXP (operands[1], 0));
946   operands[1] = gen_rtx_MEM (SImode, src_reg);
947   emit_insn (gen_rtx_CLOBBER (VOIDmode, count_reg));
948
949   if (constp && (align == UNITS_PER_WORD || bytes < MAX_UNALIGNED_COPY))
950     {
951       /* constant no of bytes and aligned or small enough copy to not bother
952        * aligning. Emit insns to copy by words.
953        */
954       if (bytes >> 2)
955         {
956           emit_move_insn (count_reg, GEN_INT (bytes >> 2));
957           emit_insn (gen_movmemsi1 (GEN_INT (4)));
958         }
959       /* insns to copy rest */
960       move_tail (operands, bytes & 3, 0);
961     }
962   else if (align == UNITS_PER_WORD)
963     {
964       /* insns to copy by words */
965       emit_insn (gen_lshrsi3 (count_reg, bytes_rtx, const2_rtx));
966       emit_insn (gen_movmemsi1 (GEN_INT (4)));
967       if (constp)
968         {
969           move_tail (operands, bytes & 3, 0);
970         }
971       else
972         {
973           /* insns to copy rest */
974           emit_insn (gen_andsi3 (count_reg, bytes_rtx, GEN_INT (3)));
975           emit_insn (gen_movmemsi1 (const1_rtx));
976         }
977     }
978   else
979     {
980       /* Not aligned and we may have a lot to copy so it is worth
981        * aligning.
982        */
983       rtx aligned_label = gen_label_rtx ();
984       rtx bytes_reg;
985
986       bytes_reg = copy_to_mode_reg (SImode, bytes_rtx);
987       if (!constp)
988         {
989           /* Emit insns to test and skip over the alignment if it is
990            * not worth it. This doubles as a test to ensure that the alignment
991            * operation can't copy too many bytes
992            */
993           emit_insn (gen_cmpsi (bytes_reg, GEN_INT (MAX_UNALIGNED_COPY)));
994           emit_jump_insn (gen_blt (aligned_label));
995         }
996
997       /* Emit insns to do alignment at run time */
998       emit_insn (gen_negsi2 (count_reg, src_reg));
999       emit_insn (gen_andsi3 (count_reg, count_reg, GEN_INT (3)));
1000       emit_insn (gen_subsi3 (bytes_reg, bytes_reg, count_reg));
1001       emit_insn (gen_movmemsi1 (const1_rtx));
1002       if (!constp)
1003         emit_label (aligned_label);
1004
1005       /* insns to copy by words */
1006       emit_insn (gen_lshrsi3 (count_reg, bytes_reg, const2_rtx));
1007       emit_insn (gen_movmemsi1 (GEN_INT (4)));
1008
1009       /* insns to copy rest */
1010       emit_insn (gen_andsi3 (count_reg, bytes_reg, GEN_INT (3)));
1011       emit_insn (gen_movmemsi1 (const1_rtx));
1012     }
1013 }
1014 \f
1015
1016 /* Returns 1 if OP contains a global symbol reference */
1017
1018 int
1019 global_symbolic_reference_mentioned_p (rtx op, int f)
1020 {
1021   register const char *fmt;
1022   register int i;
1023
1024   if (GET_CODE (op) == SYMBOL_REF)
1025     {
1026       if (! SYMBOL_REF_LOCAL_P (op))
1027         return 1;
1028       else
1029         return 0;
1030     }
1031   else if (f && GET_CODE (op) != CONST)
1032     return 0;
1033
1034   fmt = GET_RTX_FORMAT (GET_CODE (op));
1035   for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
1036     {
1037       if (fmt[i] == 'E')
1038         {
1039           register int j;
1040
1041           for (j = XVECLEN (op, i) - 1; j >= 0; j--)
1042             if (global_symbolic_reference_mentioned_p (XVECEXP (op, i, j), 0))
1043               return 1;
1044         }
1045       else if (fmt[i] == 'e' 
1046                && global_symbolic_reference_mentioned_p (XEXP (op, i), 0))
1047         return 1;
1048     }
1049
1050   return 0;
1051 }
1052
1053 \f
1054 /* Returns 1 if OP contains a symbol reference */
1055
1056 int
1057 symbolic_reference_mentioned_p (rtx op)
1058 {
1059   register const char *fmt;
1060   register int i;
1061
1062   if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
1063     return 1;
1064
1065   fmt = GET_RTX_FORMAT (GET_CODE (op));
1066   for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
1067     {
1068       if (fmt[i] == 'E')
1069         {
1070           register int j;
1071
1072           for (j = XVECLEN (op, i) - 1; j >= 0; j--)
1073             if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
1074               return 1;
1075         }
1076       else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
1077         return 1;
1078     }
1079
1080   return 0;
1081 }
1082 \f
1083 /* Table of machine-specific attributes.  */
1084
1085 const struct attribute_spec ns32k_attribute_table[] =
1086 {
1087   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
1088   /* Stdcall attribute says callee is responsible for popping arguments
1089      if they are not variable.  */
1090   { "stdcall", 0, 0, false, true,  true,  ns32k_handle_fntype_attribute },
1091   /* Cdecl attribute says the callee is a normal C declaration */
1092   { "cdecl",   0, 0, false, true,  true,  ns32k_handle_fntype_attribute },
1093   { NULL,      0, 0, false, false, false, NULL }
1094 };
1095
1096 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1097    arguments as in struct attribute_spec.handler.  */
1098 static tree
1099 ns32k_handle_fntype_attribute (tree *node, tree name,
1100                                tree args ATTRIBUTE_UNUSED,
1101                                int flags ATTRIBUTE_UNUSED,
1102                                bool *no_add_attrs)
1103 {
1104   if (TREE_CODE (*node) != FUNCTION_TYPE
1105       && TREE_CODE (*node) != FIELD_DECL
1106       && TREE_CODE (*node) != TYPE_DECL)
1107     {
1108       warning ("%qs attribute only applies to functions",
1109                IDENTIFIER_POINTER (name));
1110       *no_add_attrs = true;
1111     }
1112
1113   return NULL_TREE;
1114 }
1115
1116 \f
1117 /* Value is the number of bytes of arguments automatically
1118    popped when returning from a subroutine call.
1119    FUNDECL is the declaration node of the function (as a tree),
1120    FUNTYPE is the data type of the function (as a tree),
1121    or for a library call it is an identifier node for the subroutine name.
1122    SIZE is the number of bytes of arguments passed on the stack.
1123
1124    On the ns32k, the RET insn may be used to pop them if the number
1125      of args is fixed, but if the number is variable then the caller
1126      must pop them all.  RET can't be used for library calls now
1127      because the library is compiled with the Unix compiler.
1128    Use of RET is a selectable option, since it is incompatible with
1129    standard Unix calling sequences.  If the option is not selected,
1130    the caller must always pop the args.
1131
1132    The attribute stdcall is equivalent to RET on a per module basis.  */
1133
1134 int
1135 ns32k_return_pops_args (tree fundecl ATTRIBUTE_UNUSED, tree funtype, int size)
1136 {
1137   int rtd = TARGET_RTD;
1138
1139   if (TREE_CODE (funtype) == IDENTIFIER_NODE)
1140     return rtd ? size : 0;
1141
1142   /* Cdecl functions override -mrtd, and never pop the stack */
1143   if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype)))
1144     return 0;
1145
1146   /* Stdcall functions will pop the stack if not variable args */
1147   if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype)))
1148     rtd = 1;
1149
1150   if (rtd)
1151     {
1152       if (TYPE_ARG_TYPES (funtype) == NULL_TREE
1153           || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node))
1154         return size;
1155     }
1156
1157   return 0;
1158 }
1159 \f
1160 /* PRINT_OPERAND is defined to call this function,
1161    which is easier to debug than putting all the code in
1162    a macro definition in ns32k.h.  */
1163
1164 /* XXX time 12% of cpu time is in fprintf for non optimizing */
1165 void
1166 print_operand (FILE *file, rtx x, int code)
1167 {
1168   if (code == '$')
1169     PUT_IMMEDIATE_PREFIX (file);
1170   else if (code == '?')
1171     PUT_EXTERNAL_PREFIX (file);
1172   else if (GET_CODE (x) == REG)
1173     fprintf (file, "%s", ns32k_out_reg_names[REGNO (x)]);
1174   else if (GET_CODE (x) == MEM)
1175     {
1176       output_address (XEXP (x, 0));
1177     }
1178   else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != VOIDmode)
1179     {
1180       REAL_VALUE_TYPE r;
1181
1182       REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1183       PUT_IMMEDIATE_PREFIX (file);
1184       if (GET_MODE (x) == DFmode)
1185         { 
1186 #ifdef SEQUENT_ASM
1187           /* Sequent likes its floating point constants as integers */
1188           long l[2];
1189           REAL_VALUE_TO_TARGET_DOUBLE (r, l);
1190           fprintf (file, "0Dx%08x%08x",
1191                    l[!WORDS_BIG_ENDIAN], l[WORDS_BIG_ENDIAN]);
1192 #else
1193           char s[30];
1194           real_to_decimal (s, &r, sizeof (s), 0, 1);
1195 #ifdef ENCORE_ASM
1196           fprintf (file, "0f%s", s);
1197 #else
1198           fprintf (file, "0d%s", s);
1199 #endif
1200 #endif
1201         }
1202       else
1203         {
1204 #ifdef SEQUENT_ASM
1205           long l;
1206           REAL_VALUE_TO_TARGET_SINGLE (r, l);
1207           fprintf (file, "0Fx%08lx", l);
1208 #else
1209           char s[30];
1210           real_to_decimal (s, &r, sizeof (s), 0, 1);
1211           fprintf (file, "0f%s", s);
1212 #endif
1213         }
1214     }
1215   else
1216     {
1217       if (flag_pic
1218           && GET_CODE (x) == CONST
1219           && symbolic_reference_mentioned_p (x))
1220         {
1221           fprintf (stderr, "illegal constant for pic-mode: \n");
1222           print_rtl (stderr, x);
1223           fprintf (stderr, "\nGET_CODE (x) == %d, CONST == %d, symbolic_reference_mentioned_p (x) == %d\n",
1224                   GET_CODE (x), CONST, symbolic_reference_mentioned_p (x));
1225           abort ();
1226         }
1227       else if (flag_pic
1228                && (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF))
1229         {
1230           output_addr_const (file, x);
1231           fprintf (file, "(sb)");
1232         }
1233       else
1234         {
1235 #ifdef NO_IMMEDIATE_PREFIX_IF_SYMBOLIC
1236           if (GET_CODE (x) == CONST_INT)
1237 #endif
1238             PUT_IMMEDIATE_PREFIX (file);
1239           output_addr_const (file, x);
1240         }
1241     }
1242 }
1243 \f
1244 /* PRINT_OPERAND_ADDRESS is defined to call this function,
1245    which is easier to debug than putting all the code in
1246    a macro definition in ns32k.h .  */
1247
1248 /* Completely rewritten to get this to work with Gas for PC532 Mach.
1249    This function didn't work and I just wasn't able (nor very willing) to
1250    figure out how it worked.
1251    90-11-25 Tatu Yl|nen <ylo@cs.hut.fi> */
1252
1253 void
1254 print_operand_address (register FILE *file, register rtx addr)
1255 {
1256   static const char scales[] = { 'b', 'w', 'd', 0, 'q', };
1257   rtx offset, base, indexexp, tmp;
1258   int scale;
1259   extern int flag_pic;
1260
1261   if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == POST_DEC)
1262     {
1263       fprintf (file, "tos");
1264       return;
1265     }
1266
1267   offset = NULL;
1268   base = NULL;
1269   indexexp = NULL;
1270   while (addr != NULL)
1271     {
1272       if (GET_CODE (addr) == PLUS)
1273         {
1274           if (GET_CODE (XEXP (addr, 0)) == PLUS)
1275             {
1276               tmp = XEXP (addr, 1);
1277               addr = XEXP (addr, 0);
1278             }
1279           else
1280             {
1281               tmp = XEXP (addr,0);
1282               addr = XEXP (addr,1);
1283             }
1284         }
1285       else
1286         {
1287           tmp = addr;
1288           addr = NULL;
1289         }
1290       switch (GET_CODE (tmp))
1291         {
1292         case PLUS:
1293           abort ();
1294         case MEM:
1295           if (base)
1296             {
1297               indexexp = base;
1298               base = tmp;
1299             }
1300           else
1301             base = tmp;
1302           break;
1303         case REG:
1304           if (REGNO (tmp) < F0_REGNUM)
1305             if (base)
1306               {
1307                 indexexp = tmp;
1308               }
1309             else
1310               base = tmp;
1311           else
1312             if (base)
1313               {
1314                 indexexp = base;
1315                 base = tmp;
1316               }
1317             else
1318               base = tmp;
1319           break;
1320         case MULT:
1321           indexexp = tmp;
1322           break;
1323         case SYMBOL_REF:
1324           if (flag_pic && ! SYMBOL_REF_LOCAL_P (tmp))
1325             {
1326               if (base)
1327                 {
1328                   if (indexexp)
1329                     abort ();
1330                   indexexp = base;
1331                 }
1332               base = tmp;
1333               break;
1334             }
1335         case CONST:
1336           if (flag_pic && GET_CODE (tmp) == CONST)
1337             {
1338               rtx sym, off, tmp1;
1339               tmp1 = XEXP (tmp,0);
1340               if (GET_CODE (tmp1)  != PLUS)
1341                 abort ();
1342
1343               sym = XEXP (tmp1,0);
1344               if (GET_CODE (sym) != SYMBOL_REF)
1345                 {
1346                   off = sym;
1347                   sym = XEXP (tmp1,1);
1348                 }
1349               else
1350                 off = XEXP (tmp1,1);
1351               if (GET_CODE (sym) == SYMBOL_REF)
1352                 {
1353                   if (GET_CODE (off) != CONST_INT)
1354                     abort ();
1355
1356                   if (! SYMBOL_REF_LOCAL_P (sym))
1357                     {
1358                       if (base)
1359                         {
1360                           if (indexexp)
1361                             abort ();
1362
1363                           indexexp = base;
1364                         }
1365
1366                       if (offset != 0)
1367                         abort ();
1368
1369                       base = sym;
1370                       offset = off;
1371                       break;
1372                     }
1373                 }
1374             }
1375         case CONST_INT:
1376         case LABEL_REF:
1377           if (offset)
1378             offset = gen_rtx_PLUS (SImode, tmp, offset);
1379           else
1380             offset = tmp;
1381           break;
1382         default:
1383           abort ();
1384         }
1385     }
1386   if (! offset)
1387     offset = const0_rtx;
1388
1389   if (base
1390 #ifndef INDEX_RATHER_THAN_BASE
1391       && (flag_pic || TARGET_HIMEM)
1392       && GET_CODE (base) != SYMBOL_REF 
1393       && GET_CODE (offset) != CONST_INT
1394 #else
1395   /* This is a re-implementation of the SEQUENT_ADDRESS_BUG fix.  */
1396 #endif
1397       && !indexexp && GET_CODE (base) == REG
1398       && REG_OK_FOR_INDEX_P (base))
1399     {
1400       indexexp = base;
1401       base = NULL;
1402     }
1403
1404   /* now, offset, base and indexexp are set */
1405 #ifndef BASE_REG_NEEDED
1406   if (! base)
1407     {
1408 #if defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC)
1409       if (GET_CODE (offset) == CONST_INT)
1410 #endif
1411         PUT_ABSOLUTE_PREFIX (file);
1412     }
1413 #endif
1414
1415   output_addr_const (file, offset);
1416   if (base) /* base can be (REG ...) or (MEM ...) */
1417     switch (GET_CODE (base))
1418       {
1419         /* now we must output base.  Possible alternatives are:
1420            (rN)       (REG ...)
1421            (sp)       (REG ...)
1422            (fp)       (REG ...)
1423            (pc)       (REG ...)  used for SYMBOL_REF and LABEL_REF, output
1424            (disp(fp)) (MEM ...)       just before possible [rX:y]
1425            (disp(sp)) (MEM ...)
1426            (disp(sb)) (MEM ...)
1427            */
1428       case REG:
1429         fprintf (file, "(%s)", ns32k_out_reg_names[REGNO (base)]);
1430         break;
1431       case SYMBOL_REF:
1432         if (! flag_pic)
1433           abort ();
1434
1435         fprintf (file, "(");
1436         output_addr_const (file, base);
1437         fprintf (file, "(sb))");
1438         break;
1439       case MEM:
1440         addr = XEXP (base,0);
1441         base = NULL;
1442         offset = NULL;
1443         while (addr != NULL)
1444           {
1445             if (GET_CODE (addr) == PLUS)
1446               {
1447                 if (GET_CODE (XEXP (addr, 0)) == PLUS)
1448                   {
1449                     tmp = XEXP (addr, 1);
1450                     addr = XEXP (addr, 0);
1451                   }
1452                 else
1453                   {
1454                     tmp = XEXP (addr, 0);
1455                     addr = XEXP (addr, 1);
1456                   }
1457               }
1458             else
1459               {
1460                 tmp = addr;
1461                 addr = NULL;
1462               }
1463             switch (GET_CODE (tmp))
1464               {
1465               case REG:
1466                 base = tmp;
1467                 break;
1468               case CONST:
1469               case CONST_INT:
1470               case SYMBOL_REF:
1471               case LABEL_REF:
1472                 if (offset)
1473                   offset = gen_rtx_PLUS (SImode, tmp, offset);
1474                 else
1475                   offset = tmp;
1476                 break;
1477               default:
1478                 abort ();
1479               }
1480           }
1481         if (! offset)
1482           offset = const0_rtx;
1483         fprintf (file, "(");
1484         output_addr_const (file, offset);
1485         if (base)
1486           fprintf (file, "(%s)", ns32k_out_reg_names[REGNO (base)]);
1487         else if (TARGET_SB)
1488           fprintf (file, "(sb)");
1489         else
1490           abort ();
1491         fprintf (file, ")");
1492         break;
1493       default:
1494         abort ();
1495       }
1496 #ifdef PC_RELATIVE
1497   else if (GET_CODE (offset) != CONST_INT)
1498     fprintf (file, "(pc)");
1499 #ifdef BASE_REG_NEEDED
1500   else if (TARGET_SB)
1501     fprintf (file, "(sb)");
1502   else
1503     abort ();
1504 #endif
1505 #endif /* PC_RELATIVE */
1506
1507   /* now print index if we have one */
1508   if (indexexp)
1509     {
1510       if (GET_CODE (indexexp) == MULT)
1511         {
1512           scale = INTVAL (XEXP (indexexp, 1)) >> 1;
1513           indexexp = XEXP (indexexp, 0);
1514         }
1515       else
1516         scale = 0;
1517       if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= F0_REGNUM)
1518         abort ();
1519
1520 #ifdef UTEK_ASM
1521       fprintf (file, "[%c`%s]",
1522                scales[scale],
1523                ns32k_out_reg_names[REGNO (indexexp)]);
1524 #else
1525       fprintf (file, "[%s:%c]",
1526                ns32k_out_reg_names[REGNO (indexexp)],
1527                scales[scale]);
1528 #endif
1529     }
1530 }
1531 \f
1532 /* National 32032 shifting is so bad that we can get
1533    better performance in many common cases by using other
1534    techniques.  */
1535 const char *
1536 output_shift_insn (rtx *operands)
1537 {
1538   if (GET_CODE (operands[2]) == CONST_INT
1539       && INTVAL (operands[2]) > 0
1540       && INTVAL (operands[2]) <= 3)
1541     {
1542       if (GET_CODE (operands[0]) == REG)
1543         {
1544           if (GET_CODE (operands[1]) == REG)
1545             {
1546               if (REGNO (operands[0]) == REGNO (operands[1]))
1547                 {
1548                   if (operands[2] == const1_rtx)
1549                     return "addd %0,%0";
1550                   else if (INTVAL (operands[2]) == 2)
1551                     return "addd %0,%0\n\taddd %0,%0";
1552                 }
1553               if (operands[2] == const1_rtx)
1554                 return "movd %1,%0\n\taddd %0,%0";
1555             
1556               operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
1557               return "addr %a1,%0";
1558             }
1559           if (operands[2] == const1_rtx)
1560             return "movd %1,%0\n\taddd %0,%0";
1561         }
1562       else if (GET_CODE (operands[1]) == REG)
1563         {
1564           operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
1565           return "addr %a1,%0";
1566         }
1567       else if (INTVAL (operands[2]) == 1
1568                && GET_CODE (operands[1]) == MEM
1569                && rtx_equal_p (operands [0], operands[1]))
1570         {
1571           rtx temp = XEXP (operands[1], 0);
1572         
1573           if (GET_CODE (temp) == REG
1574               || (GET_CODE (temp) == PLUS
1575                   && GET_CODE (XEXP (temp, 0)) == REG
1576                   && GET_CODE (XEXP (temp, 1)) == CONST_INT))
1577             return "addd %0,%0";
1578         }
1579       else return "ashd %2,%0";
1580     }
1581   return "ashd %2,%0";
1582 }
1583
1584 const char *
1585 output_move_dconst (int n, const char *s)
1586 {
1587   static char r[32];
1588
1589   if (n > -9 && n < 8)
1590     strcpy (r, "movqd ");
1591   else if (n > 0 && n < 256)
1592     strcpy (r, "movzbd ");
1593   else if (n > 0 && n < 65536)
1594     strcpy (r, "movzwd ");
1595   else if (n < 0 && n > -129)
1596     strcpy (r, "movxbd ");
1597   else if (n < 0 && n > -32769)
1598     strcpy (r, "movxwd ");
1599   else
1600     strcpy (r, "movd ");
1601   strcat (r, s);
1602   return r;
1603 }
1604
1605 static rtx
1606 ns32k_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
1607                         int incoming ATTRIBUTE_UNUSED)
1608 {
1609   return gen_rtx_REG (Pmode, NS32K_STRUCT_VALUE_REGNUM);
1610 }
1611
1612 /* Worker function for NOTICE_UPDATE_CC.  */
1613
1614 void
1615 ns32k_notice_update_cc (rtx exp, rtx insn ATTRIBUTE_UNUSED)
1616 {
1617   if (GET_CODE (exp) == SET)
1618     {
1619       if (GET_CODE (SET_DEST (exp)) == CC0)
1620         {
1621           cc_status.flags = 0;
1622           cc_status.value1 = SET_DEST (exp);
1623           cc_status.value2 = SET_SRC (exp);
1624         }
1625       else if (GET_CODE (SET_SRC (exp)) == CALL)
1626         {
1627           CC_STATUS_INIT;
1628         }
1629       else if (GET_CODE (SET_DEST (exp)) == REG)
1630         {
1631           if (cc_status.value1
1632               && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))
1633             cc_status.value1 = 0;
1634           if (cc_status.value2
1635               && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2))
1636             cc_status.value2 = 0;
1637         }
1638       else if (GET_CODE (SET_DEST (exp)) == MEM)
1639         {
1640           CC_STATUS_INIT;
1641         }
1642     }
1643   else if (GET_CODE (exp) == PARALLEL
1644            && GET_CODE (XVECEXP (exp, 0, 0)) == SET)
1645     {
1646       if (GET_CODE (SET_DEST (XVECEXP (exp, 0, 0))) == CC0)
1647         {
1648           cc_status.flags = 0;
1649           cc_status.value1 = SET_DEST (XVECEXP (exp, 0, 0));
1650           cc_status.value2 = SET_SRC (XVECEXP (exp, 0, 0));
1651         }
1652       else if (GET_CODE (SET_DEST (XVECEXP (exp, 0, 0))) == REG)
1653         {
1654           if (cc_status.value1
1655               && reg_overlap_mentioned_p (SET_DEST (XVECEXP (exp, 0, 0)),
1656                                           cc_status.value1))
1657             cc_status.value1 = 0;
1658           if (cc_status.value2
1659               && reg_overlap_mentioned_p (SET_DEST (XVECEXP (exp, 0, 0)),
1660                                           cc_status.value2))
1661             cc_status.value2 = 0;
1662         }
1663       else if (GET_CODE (SET_DEST (XVECEXP (exp, 0, 0))) == MEM)
1664         {
1665           CC_STATUS_INIT;
1666         }
1667     }
1668   else if (GET_CODE (exp) == CALL)
1669     {
1670       /* all bets are off */
1671       CC_STATUS_INIT;
1672     }
1673   else
1674     {
1675       /* nothing happens? CC_STATUS_INIT; */
1676     }
1677   if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
1678       && cc_status.value2
1679       && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
1680     abort ();
1681 }
1682
1683 /* Implement TARGET_ARG_PARTIAL_BYTES.  */
1684
1685 static int
1686 ns32k_arg_partial_bytes (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
1687                          tree type, bool named ATTRIBUTE_UNUSED)
1688 {
1689   int cum = *pcum;
1690
1691   if (TARGET_REGPARM && cum < 8)
1692     {
1693       HOST_WIDE_INT size;
1694
1695       if (mode == BLKmode)
1696         size = int_size_in_bytes (type);
1697       else
1698         size = GET_MODE_SIZE (mode);
1699
1700       if (8 < cum + size)
1701         return 8 - cum;
1702     }
1703
1704   return 0;
1705 }