OSDN Git Service

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