OSDN Git Service

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