OSDN Git Service

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