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