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