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