OSDN Git Service

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