OSDN Git Service

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