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