OSDN Git Service

Merge in gcc2-ss-010999
[pf3gnuchains/gcc-fork.git] / gcc / config / ns32k / ns32k.c
1 /* Subroutines for assembler code output on the NS32000.
2    Copyright (C) 1988, 94, 95, 96, 97, 98, 1999 Free Software Foundation, Inc.
3
4 This file is part of GNU CC.
5
6 GNU CC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU CC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU CC; see the file COPYING.  If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.  */
20
21 #include "config.h"
22 #include "system.h"
23 #include "rtl.h"
24 #include "regs.h"
25 #include "hard-reg-set.h"
26 #include "real.h"
27 #include "insn-config.h"
28 #include "conditions.h"
29 #include "insn-flags.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
37 #ifdef OSF_OS
38 int ns32k_num_files = 0;
39 #endif
40
41 /* This duplicates reg_class_contens in reg_class.c, but maybe that isn't
42    initialized in time. Also this is more convenient as an array of ints.
43    We know that HARD_REG_SET fits in an unsigned int */
44
45 unsigned int ns32k_reg_class_contents[N_REG_CLASSES] = REG_CLASS_CONTENTS;
46
47 enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
48 {
49   GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
50   GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
51   FLOAT_REG0, LONG_FLOAT_REG0, FLOAT_REGS, FLOAT_REGS,
52   FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS,
53   FP_REGS, FP_REGS, FP_REGS, FP_REGS,
54   FP_REGS, FP_REGS, FP_REGS, FP_REGS,
55   FRAME_POINTER_REG, STACK_POINTER_REG
56 };
57
58 char *ns32k_out_reg_names[] = OUTPUT_REGISTER_NAMES;
59
60 void
61 trace (s, s1, s2)
62      char *s, *s1, *s2;
63 {
64   fprintf (stderr, s, s1, s2);
65 }
66
67
68 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */ 
69 int
70 hard_regno_mode_ok (regno, mode)
71      int regno;
72      enum machine_mode mode;
73 {
74   int size = GET_MODE_UNIT_SIZE(mode);
75
76   if (FLOAT_MODE_P(mode))
77     {
78       if (size == UNITS_PER_WORD && regno < L1_REGNUM)
79         return 1;
80       if (size == UNITS_PER_WORD * 2
81           && (((regno & 1) == 0 && regno < FRAME_POINTER_REGNUM)))
82         return 1;
83       return 0;
84     }
85   if (size == UNITS_PER_WORD * 2
86       && (regno & 1) == 0 && regno < F0_REGNUM)
87     return 1;
88   if (size <= UNITS_PER_WORD
89       && (regno < F0_REGNUM || regno == FRAME_POINTER_REGNUM
90           || regno == STACK_POINTER_REGNUM))
91     return 1;
92   return 0;
93 }
94
95 int register_move_cost(CLASS1, CLASS2)
96      enum reg_class CLASS1;
97      enum reg_class CLASS2;
98 {
99   if (CLASS1 == NO_REGS || CLASS2 == NO_REGS)
100     return 2;
101   if((SUBSET_P(CLASS1, FP_REGS) && !SUBSET_P(CLASS2, FP_REGS))
102    || (!SUBSET_P(CLASS1, FP_REGS) && SUBSET_P(CLASS2, FP_REGS)))
103     return 8;
104   if (((CLASS1) == STACK_POINTER_REG && !SUBSET_P(CLASS2,GENERAL_REGS))
105       || ((CLASS2) == STACK_POINTER_REG && !SUBSET_P(CLASS1,GENERAL_REGS)))
106     return 6;
107   if (((CLASS1) == FRAME_POINTER_REG && !SUBSET_P(CLASS2,GENERAL_REGS))
108       || ((CLASS2) == FRAME_POINTER_REG && !SUBSET_P(CLASS1,GENERAL_REGS)))
109     return 6;
110   return 2;
111 }
112
113 #if 0
114 /* We made the insn definitions copy from floating point to general
115   registers via the stack. */
116 int secondary_memory_needed(CLASS1, CLASS2, M)
117      enum reg_class CLASS1;
118      enum reg_class CLASS2;
119      enum machine_mode M;
120 {
121   int ret = ((SUBSET_P(CLASS1, FP_REGS) && !SUBSET_P(CLASS2, FP_REGS))
122    || (!SUBSET_P(CLASS1, FP_REGS) && SUBSET_P(CLASS2, FP_REGS)));
123   return ret;
124 }
125 #endif
126     
127
128 /* ADDRESS_COST calls this.  This function is not optimal
129    for the 32032 & 32332, but it probably is better than
130    the default. */
131
132 int
133 calc_address_cost (operand)
134      rtx operand;
135 {
136   int i;
137   int cost = 0;
138   
139   if (GET_CODE (operand) == MEM)
140     cost += 3;
141   if (GET_CODE (operand) == MULT)
142     cost += 2;
143 #if 0
144   if (GET_CODE (operand) == REG)
145     cost += 1;                  /* not really, but the documentation
146                                    says different amount of registers
147                                    shouldn't return the same costs */
148 #endif
149   switch (GET_CODE (operand))
150     {
151     case REG:
152     case CONST:
153     case CONST_INT:
154     case CONST_DOUBLE:
155     case SYMBOL_REF:
156     case LABEL_REF:
157     case POST_DEC:
158     case PRE_DEC:
159       break;
160     case MEM:
161       cost += calc_address_cost (XEXP (operand, 0));
162       break;
163     case MULT:
164     case PLUS:
165       for (i = 0; i < GET_RTX_LENGTH (GET_CODE (operand)); i++)
166         {
167           cost += calc_address_cost (XEXP (operand, i));
168         }
169     default:
170       break;
171     }
172   return cost;
173 }
174
175 /* Return the register class of a scratch register needed to copy IN into
176    or out of a register in CLASS in MODE.  If it can be done directly,
177    NO_REGS is returned.  */
178
179 enum reg_class
180 secondary_reload_class (class, mode, in)
181      enum reg_class class;
182      enum machine_mode mode;
183      rtx in;
184 {
185   int regno = true_regnum (in);
186
187   if (regno >= FIRST_PSEUDO_REGISTER)
188     regno = -1;
189
190   if ((class == FRAME_POINTER_REG && regno == STACK_POINTER_REGNUM)
191       || ( class == STACK_POINTER_REG && regno == FRAME_POINTER_REGNUM))
192     return GENERAL_REGS;
193   else
194     return NO_REGS;
195 }
196
197 /* Generate the rtx that comes from an address expression in the md file */
198 /* The expression to be build is BASE[INDEX:SCALE].  To recognize this,
199    scale must be converted from an exponent (from ASHIFT) to a
200    multiplier (for MULT). */
201 static rtx
202 gen_indexed_expr (base, index, scale)
203      rtx base, index, scale;
204 {
205   rtx addr;
206
207   /* This generates an invalid addressing mode, if BASE is
208      fp or sp.  This is handled by PRINT_OPERAND_ADDRESS.  */
209   if (GET_CODE (base) != REG && GET_CODE (base) != CONST_INT)
210     base = gen_rtx_MEM (SImode, base);
211   addr = gen_rtx_MULT (SImode, index,
212                        GEN_INT (1 << INTVAL (scale)));
213   addr = gen_rtx_PLUS (SImode, base, addr);
214   return addr;
215 }
216
217 /* Return 1 if OP is a valid operand of mode MODE.  This
218    predicate rejects operands which do not have a mode
219    (such as CONST_INT which are VOIDmode).  */
220 int
221 reg_or_mem_operand (op, mode)
222      register rtx op;
223      enum machine_mode mode;
224 {
225   return (GET_MODE (op) == mode
226           && (GET_CODE (op) == REG
227               || GET_CODE (op) == SUBREG
228               || GET_CODE (op) == MEM));
229 }
230
231 \f
232 /* Split one or more DImode RTL references into pairs of SImode
233    references.  The RTL can be REG, offsettable MEM, integer constant, or
234    CONST_DOUBLE.  "operands" is a pointer to an array of DImode RTL to
235    split and "num" is its length.  lo_half and hi_half are output arrays
236    that parallel "operands". */
237
238 void
239 split_di (operands, num, lo_half, hi_half)
240      rtx operands[];
241      int num;
242      rtx lo_half[], hi_half[];
243 {
244   while (num--)
245     {
246       if (GET_CODE (operands[num]) == REG)
247         {
248           lo_half[num] = gen_rtx_REG (SImode, REGNO (operands[num]));
249           hi_half[num] = gen_rtx_REG (SImode, REGNO (operands[num]) + 1);
250         }
251       else if (CONSTANT_P (operands[num]))
252         {
253           split_double (operands[num], &lo_half[num], &hi_half[num]);
254         }
255       else if (offsettable_memref_p (operands[num]))
256         {
257           lo_half[num] = operands[num];
258           hi_half[num] = adj_offsettable_operand (operands[num], 4);
259         }
260       else
261         abort();
262     }
263 }
264 \f
265 /* Return the best assembler insn template
266    for moving operands[1] into operands[0] as a fullword.  */
267
268 static char *
269 singlemove_string (operands)
270      rtx *operands;
271 {
272   if (GET_CODE (operands[1]) == CONST_INT
273       && INTVAL (operands[1]) <= 7
274       && INTVAL (operands[1]) >= -8)
275     return "movqd %1,%0";
276   return "movd %1,%0";
277 }
278
279 char *
280 output_move_double (operands)
281      rtx *operands;
282 {
283   enum anon1 { REGOP, OFFSOP, PUSHOP, CNSTOP, RNDOP } optype0, optype1;
284   rtx latehalf[2];
285
286   /* First classify both operands.  */
287
288   if (REG_P (operands[0]))
289     optype0 = REGOP;
290   else if (offsettable_memref_p (operands[0]))
291     optype0 = OFFSOP;
292   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
293     optype0 = PUSHOP;
294   else
295     optype0 = RNDOP;
296
297   if (REG_P (operands[1]))
298     optype1 = REGOP;
299   else if (CONSTANT_P (operands[1])
300            || GET_CODE (operands[1]) == CONST_DOUBLE)
301     optype1 = CNSTOP;
302   else if (offsettable_memref_p (operands[1]))
303     optype1 = OFFSOP;
304   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
305     optype1 = PUSHOP;
306   else
307     optype1 = RNDOP;
308
309   /* Check for the cases that the operand constraints are not
310      supposed to allow to happen.  Abort if we get one,
311      because generating code for these cases is painful.  */
312
313   if (optype0 == RNDOP || optype1 == RNDOP)
314     abort ();
315
316   /* Ok, we can do one word at a time.
317      Normally we do the low-numbered word first,
318      but if either operand is autodecrementing then we
319      do the high-numbered word first.
320
321      In either case, set up in LATEHALF the operands to use
322      for the high-numbered word and in some cases alter the
323      operands in OPERANDS to be suitable for the low-numbered word.  */
324
325   if (optype0 == REGOP)
326     latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
327   else if (optype0 == OFFSOP)
328     latehalf[0] = adj_offsettable_operand (operands[0], 4);
329   else
330     latehalf[0] = operands[0];
331
332   if (optype1 == REGOP)
333     latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
334   else if (optype1 == OFFSOP)
335     latehalf[1] = adj_offsettable_operand (operands[1], 4);
336   else if (optype1 == CNSTOP)
337     split_double (operands[1], &operands[1], &latehalf[1]);
338   else
339     latehalf[1] = operands[1];
340
341   /* If insn is effectively movd N(sp),tos then we will do the
342      high word first.  We should use the adjusted operand 1 (which is N+4(sp))
343      for the low word as well, to compensate for the first decrement of sp.
344      Given this, it doesn't matter which half we do "first".  */
345   if (optype0 == PUSHOP
346       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
347       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
348     operands[1] = latehalf[1];
349
350   /* If one or both operands autodecrementing,
351      do the two words, high-numbered first.  */
352   else if (optype0 == PUSHOP || optype1 == PUSHOP)
353     {
354       output_asm_insn (singlemove_string (latehalf), latehalf);
355       return singlemove_string (operands);
356     }
357
358   /* If the first move would clobber the source of the second one,
359      do them in the other order.  */
360
361   /* Overlapping registers.  */
362   if (optype0 == REGOP && optype1 == REGOP
363       && REGNO (operands[0]) == REGNO (latehalf[1]))
364     {
365       /* Do that word.  */
366       output_asm_insn (singlemove_string (latehalf), latehalf);
367       /* Do low-numbered word.  */
368       return singlemove_string (operands);
369     }
370   /* Loading into a register which overlaps a register used in the address.  */
371   else if (optype0 == REGOP && optype1 != REGOP
372            && reg_overlap_mentioned_p (operands[0], operands[1]))
373     {
374       if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
375           && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
376         {
377           /* If both halves of dest are used in the src memory address,
378              load the destination address into the low reg (operands[0]).
379              Then it works to load latehalf first.  */
380           rtx xops[2];
381           xops[0] = XEXP (operands[1], 0);
382           xops[1] = operands[0];
383           output_asm_insn ("addr %a0,%1", xops);
384           operands[1] = gen_rtx_MEM (DImode, operands[0]);
385           latehalf[1] = adj_offsettable_operand (operands[1], 4);
386           /* The first half has the overlap, Do the late half first.  */
387           output_asm_insn (singlemove_string (latehalf), latehalf);
388           /* Then clobber.  */
389           return singlemove_string (operands);
390         }
391       if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)))
392         {
393           /* The first half has the overlap, Do the late half first.  */
394           output_asm_insn (singlemove_string (latehalf), latehalf);
395           /* Then clobber.  */
396           return singlemove_string (operands);
397         }
398     }
399
400   /* Normal case.  Do the two words, low-numbered first.  */
401
402   output_asm_insn (singlemove_string (operands), operands);
403
404   operands[0] = latehalf[0];
405   operands[1] = latehalf[1];
406   return singlemove_string (operands);
407 }
408
409 \f
410 #define MAX_UNALIGNED_COPY (32)
411 /* Expand string/block move operations.
412
413    operands[0] is the pointer to the destination.
414    operands[1] is the pointer to the source.
415    operands[2] is the number of bytes to move.
416    operands[3] is the alignment.  */
417
418 static void
419 move_tail(operands, bytes, offset)
420      rtx operands[];
421      int bytes;
422      int offset;
423 {
424   if (bytes & 2)
425     {
426       rtx src, dest;
427       dest = change_address(operands[0], HImode,
428                             plus_constant(XEXP(operands[0], 0), offset));
429       src = change_address(operands[1], HImode,
430                            plus_constant(XEXP(operands[1], 0), offset));
431       emit_move_insn(dest, src);
432       offset += 2;
433     }
434   if (bytes & 1)
435     {
436       rtx src, dest;
437       dest = change_address(operands[0], QImode,
438                             plus_constant(XEXP(operands[0], 0), offset));
439       src = change_address(operands[1], QImode,
440                            plus_constant(XEXP(operands[1], 0), offset));
441       emit_move_insn(dest, src);
442     }
443 }
444
445 void
446 expand_block_move (operands)
447      rtx operands[];
448 {
449   rtx bytes_rtx = operands[2];
450   rtx align_rtx = operands[3];
451   int constp    = (GET_CODE (bytes_rtx) == CONST_INT);
452   int bytes     = (constp ? INTVAL (bytes_rtx) : 0);
453   int align     = INTVAL (align_rtx);
454   rtx src_reg = gen_rtx(REG, Pmode, 1);
455   rtx dest_reg = gen_rtx(REG, Pmode, 2);
456   rtx count_reg = gen_rtx(REG, SImode, 0);
457   rtx insn;
458
459   if (constp && bytes <= 0)
460     return;
461
462   if (constp && bytes < 20)
463     {
464       int words = bytes >> 2;
465       if (words)
466         if (words < 3 || flag_unroll_loops)
467           {
468             int offset = 0;
469             for (; words; words--, offset += 4)
470               {
471                 rtx src, dest;
472                 dest = change_address(operands[0], SImode,
473                                       plus_constant(XEXP(operands[0], 0), offset));
474                 src = change_address(operands[1], SImode,
475                                      plus_constant(XEXP(operands[1], 0), offset));
476                 emit_move_insn(dest, src);
477               }
478           }
479         else
480           {
481             /* Use movmd. It is slower than multiple movd's but more
482                compact. It is also slower than movsd for large copies
483                but causes less registers reloading so is better than movsd
484                for small copies. */
485             rtx src, dest;
486             dest = copy_addr_to_reg (XEXP(operands[0], 0));
487             src = copy_addr_to_reg (XEXP(operands[1], 0));
488             
489             emit_insn(gen_movstrsi2(dest, src, GEN_INT(words)));
490           }
491       move_tail(operands, bytes & 3, bytes & ~3);
492       return;
493     }
494
495   if (align > UNITS_PER_WORD)
496     align = UNITS_PER_WORD;
497
498   /* Move the address into scratch registers.  */
499   emit_insn(gen_rtx(CLOBBER, VOIDmode, dest_reg));
500   emit_move_insn(dest_reg, XEXP (operands[0], 0));
501   emit_insn(gen_rtx(CLOBBER, VOIDmode, src_reg));
502   emit_move_insn(src_reg, XEXP (operands[1], 0));
503   emit_insn(gen_rtx(CLOBBER, VOIDmode, count_reg));
504
505   if (constp && (align == UNITS_PER_WORD || bytes < MAX_UNALIGNED_COPY))
506     {
507       rtx  bytes_reg;
508
509       /* constant no of bytes and aligned or small enough copy to not bother
510        * aligning. Emit insns to copy by words.
511        */
512       if (bytes >> 2)
513         {
514           emit_move_insn(count_reg, GEN_INT(bytes >> 2));
515           emit_insn(gen_movstrsi1 (GEN_INT(4)));
516         }
517       /* insns to copy rest */
518       move_tail(operands, bytes & 3, bytes & ~3);
519     }
520   else if (align == UNITS_PER_WORD)
521     {
522       /* insns to copy by words */
523       emit_insn(gen_lshrsi3 (count_reg, bytes_rtx, GEN_INT(2)));
524       emit_insn(gen_movstrsi1 (GEN_INT(4)));
525       /* insns to copy rest */
526       emit_insn(gen_andsi3 (count_reg, bytes_rtx, GEN_INT(3)));
527       emit_insn(gen_movstrsi1 (const1_rtx));
528     }
529   else
530     {
531       /* Not aligned and we may have a lot to copy so it is worth
532        * aligning.
533        */
534       rtx aligned_label = gen_label_rtx ();
535       rtx bytes_reg;
536
537       bytes_reg = copy_to_mode_reg(SImode, bytes_rtx);
538       if (!constp)
539         {
540           /* Emit insns to test and skip over the alignment if it is
541            * not worth it. This doubles as a test to ensure that the alignment
542            * operation can't copy too many bytes
543            */
544           emit_insn(gen_cmpsi (bytes_reg, GEN_INT(MAX_UNALIGNED_COPY)));
545           emit_jump_insn (gen_blt (aligned_label));
546         }
547
548       /* Emit insns to do alignment at run time */
549       emit_insn(gen_negsi2 (count_reg, src_reg));
550       emit_insn(gen_andsi3 (count_reg, count_reg, GEN_INT(3)));
551       emit_insn(gen_subsi3 (bytes_reg, bytes_reg, count_reg));
552       emit_insn(gen_movstrsi1 (const1_rtx));
553       if (!constp)
554         emit_label (aligned_label);
555
556       /* insns to copy by words */
557       emit_insn (gen_lshrsi3 (count_reg, bytes_reg, GEN_INT(2)));
558       emit_insn(gen_movstrsi1 (GEN_INT(4)));
559
560       /* insns to copy rest */
561       emit_insn (gen_andsi3 (count_reg, bytes_reg, GEN_INT(3)));
562       emit_insn(gen_movstrsi1 (const1_rtx));    
563     }
564 }
565 \f
566
567 /* Returns 1 if OP contains a global symbol reference */
568
569 int
570 global_symbolic_reference_mentioned_p (op, f)
571      rtx op;
572      int f;
573 {
574   register const char *fmt;
575   register int i;
576
577   if (GET_CODE (op) == SYMBOL_REF)
578     {
579       if (! SYMBOL_REF_FLAG (op))
580         return 1;
581       else
582         return 0;
583     }
584   else if (f && GET_CODE (op) != CONST)
585     return 0;
586
587   fmt = GET_RTX_FORMAT (GET_CODE (op));
588   for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
589     {
590       if (fmt[i] == 'E')
591         {
592           register int j;
593
594           for (j = XVECLEN (op, i) - 1; j >= 0; j--)
595             if (global_symbolic_reference_mentioned_p (XVECEXP (op, i, j), 0))
596               return 1;
597         }
598       else if (fmt[i] == 'e' 
599                && global_symbolic_reference_mentioned_p (XEXP (op, i), 0))
600         return 1;
601     }
602
603   return 0;
604 }
605
606 \f
607 /* Returns 1 if OP contains a symbol reference */
608
609 int
610 symbolic_reference_mentioned_p (op)
611      rtx op;
612 {
613   register const char *fmt;
614   register int i;
615
616   if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
617     return 1;
618
619   fmt = GET_RTX_FORMAT (GET_CODE (op));
620   for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
621     {
622       if (fmt[i] == 'E')
623         {
624           register int j;
625
626           for (j = XVECLEN (op, i) - 1; j >= 0; j--)
627             if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
628               return 1;
629         }
630       else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
631         return 1;
632     }
633
634   return 0;
635 }
636 \f
637 /* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific
638    attribute for DECL.  The attributes in ATTRIBUTES have previously been
639    assigned to DECL.  */
640
641 int
642 ns32k_valid_decl_attribute_p (decl, attributes, identifier, args)
643      tree decl;
644      tree attributes;
645      tree identifier;
646      tree args;
647 {
648   return 0;
649 }
650
651 /* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific
652    attribute for TYPE.  The attributes in ATTRIBUTES have previously been
653    assigned to TYPE.  */
654
655 int
656 ns32k_valid_type_attribute_p (type, attributes, identifier, args)
657      tree type;
658      tree attributes;
659      tree identifier;
660      tree args;
661 {
662   if (TREE_CODE (type) != FUNCTION_TYPE
663       && TREE_CODE (type) != FIELD_DECL
664       && TREE_CODE (type) != TYPE_DECL)
665     return 0;
666
667   /* Stdcall attribute says callee is responsible for popping arguments
668      if they are not variable.  */
669   if (is_attribute_p ("stdcall", identifier))
670     return (args == NULL_TREE);
671
672   /* Cdecl attribute says the callee is a normal C declaration */
673   if (is_attribute_p ("cdecl", identifier))
674     return (args == NULL_TREE);
675
676   return 0;
677 }
678
679 /* Return 0 if the attributes for two types are incompatible, 1 if they
680    are compatible, and 2 if they are nearly compatible (which causes a
681    warning to be generated).  */
682
683 int
684 ns32k_comp_type_attributes (type1, type2)
685      tree type1;
686      tree type2;
687 {
688   return 1;
689 }
690
691 \f
692 /* Value is the number of bytes of arguments automatically
693    popped when returning from a subroutine call.
694    FUNDECL is the declaration node of the function (as a tree),
695    FUNTYPE is the data type of the function (as a tree),
696    or for a library call it is an identifier node for the subroutine name.
697    SIZE is the number of bytes of arguments passed on the stack.
698
699    On the ns32k, the RET insn may be used to pop them if the number
700      of args is fixed, but if the number is variable then the caller
701      must pop them all.  RET can't be used for library calls now
702      because the library is compiled with the Unix compiler.
703    Use of RET is a selectable option, since it is incompatible with
704    standard Unix calling sequences.  If the option is not selected,
705    the caller must always pop the args.
706
707    The attribute stdcall is equivalent to RET on a per module basis.  */
708
709 int
710 ns32k_return_pops_args (fundecl, funtype, size)
711      tree fundecl;
712      tree funtype;
713      int size;
714 {
715   int rtd = TARGET_RTD;
716
717   if (TREE_CODE (funtype) == IDENTIFIER_NODE)
718     return rtd ? size : 0;
719
720   /* Cdecl functions override -mrtd, and never pop the stack */
721   if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype)))
722     return 0;
723
724   /* Stdcall functions will pop the stack if not variable args */
725   if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype)))
726     rtd = 1;
727
728   if (rtd)
729     {
730       if (TYPE_ARG_TYPES (funtype) == NULL_TREE
731           || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node))
732         return size;
733     }
734
735   return 0;
736 }
737 \f
738 /* PRINT_OPERAND is defined to call this function,
739    which is easier to debug than putting all the code in
740    a macro definition in ns32k.h.  */
741
742 /* XXX time 12% of cpu time is in fprintf for non optimizing */
743 void
744 print_operand (file, x, code)
745      FILE *file;
746      rtx x;
747      char code;
748 {
749   if (code == '$')
750     PUT_IMMEDIATE_PREFIX (file);
751   else if (code == '?')
752     PUT_EXTERNAL_PREFIX (file);
753   else if (GET_CODE (x) == REG)
754     fprintf (file, "%s", ns32k_out_reg_names[REGNO (x)]);
755   else if (GET_CODE (x) == MEM)
756     {
757       rtx tmp = XEXP (x, 0);
758       output_address (XEXP (x, 0));
759     }
760   else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != VOIDmode)
761     {
762       if (GET_MODE (x) == DFmode)
763         { 
764           union { double d; int i[2]; } u;
765           u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
766           PUT_IMMEDIATE_PREFIX(file);
767 #ifdef SEQUENT_ASM
768           /* Sequent likes its floating point constants as integers */
769           fprintf (file, "0Dx%08x%08x", u.i[1], u.i[0]);
770 #else
771 #ifdef ENCORE_ASM
772           fprintf (file, "0f%.20e", u.d); 
773 #else
774           fprintf (file, "0d%.20e", u.d); 
775 #endif
776 #endif
777         }
778       else
779         { 
780           union { double d; int i[2]; } u;
781           u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
782           PUT_IMMEDIATE_PREFIX (file);
783 #ifdef SEQUENT_ASM
784           /* We have no way of winning if we can't get the bits
785              for a sequent floating point number.  */
786 #if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
787           abort ();
788 #endif
789           {
790             union { float f; long l; } uu;
791             uu.f = u.d;
792             fprintf (file, "0Fx%08x", uu.l);
793           }
794 #else
795           fprintf (file, "0f%.20e", u.d); 
796 #endif
797         }
798     }
799   else
800     {
801       if (flag_pic
802           && GET_CODE (x) == CONST
803           && symbolic_reference_mentioned_p (x))
804         {
805           fprintf(stderr, "illegal constant for pic-mode: \n");
806           print_rtl(stderr, x);
807           fprintf(stderr, "\nGET_CODE (x) == %d, CONST == %d, symbolic_reference_mentioned_p (x) == %d\n",
808                   GET_CODE (x), CONST, symbolic_reference_mentioned_p(x));
809           abort ();
810         }
811       else if (flag_pic
812                && (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF))
813         {
814           output_addr_const (file, x);
815           fprintf (file, "(sb)");
816         }
817       else
818         {
819 #ifdef NO_IMMEDIATE_PREFIX_IF_SYMBOLIC
820           if (GET_CODE (x) == CONST_INT)
821 #endif
822             PUT_IMMEDIATE_PREFIX (file);
823           output_addr_const (file, x);
824         }
825     }
826 }
827 \f
828 /* PRINT_OPERAND_ADDRESS is defined to call this function,
829    which is easier to debug than putting all the code in
830    a macro definition in ns32k.h .  */
831
832 /* Completely rewritten to get this to work with Gas for PC532 Mach.
833    This function didn't work and I just wasn't able (nor very willing) to
834    figure out how it worked.
835    90-11-25 Tatu Yl|nen <ylo@cs.hut.fi> */
836
837 void
838 print_operand_address (file, addr)
839      register FILE *file;
840      register rtx addr;
841 {
842   static char scales[] = { 'b', 'w', 'd', 0, 'q', };
843   rtx offset, base, indexexp, tmp;
844   int scale;
845   extern int flag_pic;
846
847   if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == POST_DEC)
848     {
849       fprintf (file, "tos");
850       return;
851     }
852
853   offset = NULL;
854   base = NULL;
855   indexexp = NULL;
856   while (addr != NULL)
857     {
858       if (GET_CODE (addr) == PLUS)
859         {
860           if (GET_CODE (XEXP (addr, 0)) == PLUS)
861             {
862               tmp = XEXP (addr, 1);
863               addr = XEXP (addr, 0);
864             }
865           else
866             {
867               tmp = XEXP (addr,0);
868               addr = XEXP (addr,1);
869             }
870         }
871       else
872         {
873           tmp = addr;
874           addr = NULL;
875         }
876       switch (GET_CODE (tmp))
877         {
878         case PLUS:
879           abort ();
880         case MEM:
881           if (base)
882             {
883               indexexp = base;
884               base = tmp;
885             }
886           else
887             base = tmp;
888           break;
889         case REG:
890           if (REGNO (tmp) < F0_REGNUM)
891             if (base)
892               {
893                 indexexp = tmp;
894               }
895             else
896               base = tmp;
897           else
898             if (base)
899               {
900                 indexexp = base;
901                 base = tmp;
902               }
903             else
904               base = tmp;
905           break;
906         case MULT:
907           indexexp = tmp;
908           break;
909         case SYMBOL_REF:
910           if (flag_pic && ! CONSTANT_POOL_ADDRESS_P (tmp)
911               && ! SYMBOL_REF_FLAG (tmp))
912             {
913               if (base)
914                 {
915                   if (indexexp)
916                     abort ();
917                   indexexp = base;
918                 }
919               base = tmp;
920               break;
921             }
922         case CONST:
923           if (flag_pic && GET_CODE (tmp) == CONST)
924             {
925               rtx sym, off, tmp1;
926               tmp1 = XEXP (tmp,0);
927               if (GET_CODE (tmp1)  != PLUS)
928                 abort ();
929
930               sym = XEXP (tmp1,0);
931               if (GET_CODE (sym) != SYMBOL_REF)
932                 {
933                   off = sym;
934                   sym = XEXP (tmp1,1);
935                 }
936               else
937                 off = XEXP (tmp1,1);
938               if (GET_CODE (sym) == SYMBOL_REF)
939                 {
940                   if (GET_CODE (off) != CONST_INT)
941                     abort ();
942
943                   if (CONSTANT_POOL_ADDRESS_P (sym)
944                       || SYMBOL_REF_FLAG (sym))
945                     {
946                       SYMBOL_REF_FLAG (tmp) = 1;
947                     }
948                   else
949                     {
950                       if (base)
951                         {
952                           if (indexexp)
953                             abort ();
954
955                           indexexp = base;
956                         }
957
958                       if (offset != 0)
959                         abort ();
960
961                       base = sym;
962                       offset = off;
963                       break;
964                     }
965                 }
966             }
967         case CONST_INT:
968         case LABEL_REF:
969           if (offset)
970             offset = gen_rtx_PLUS (SImode, tmp, offset);
971           else
972             offset = tmp;
973           break;
974         default:
975           abort ();
976         }
977     }
978   if (! offset)
979     offset = const0_rtx;
980
981   if (base
982 #ifndef INDEX_RATHER_THAN_BASE
983       && (flag_pic || TARGET_HIMEM)
984       && GET_CODE (base) != SYMBOL_REF 
985       && GET_CODE (offset) != CONST_INT
986 #else
987   /* This is a re-implementation of the SEQUENT_ADDRESS_BUG fix.  */
988 #endif
989       && !indexexp && GET_CODE (base) == REG
990       && REG_OK_FOR_INDEX_P (base))
991     {
992       indexexp = base;
993       base = NULL;
994     }
995
996   /* now, offset, base and indexexp are set */
997 #ifndef BASE_REG_NEEDED
998   if (! base)
999     {
1000 #if defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC)
1001       if (GET_CODE (offset) == CONST_INT)
1002 #endif
1003         PUT_ABSOLUTE_PREFIX (file);
1004     }
1005 #endif
1006
1007   output_addr_const (file, offset);
1008   if (base) /* base can be (REG ...) or (MEM ...) */
1009     switch (GET_CODE (base))
1010       {
1011         /* now we must output base.  Possible alternatives are:
1012            (rN)       (REG ...)
1013            (sp)       (REG ...)
1014            (fp)       (REG ...)
1015            (pc)       (REG ...)  used for SYMBOL_REF and LABEL_REF, output
1016            (disp(fp)) (MEM ...)       just before possible [rX:y]
1017            (disp(sp)) (MEM ...)
1018            (disp(sb)) (MEM ...)
1019            */
1020       case REG:
1021         fprintf (file, "(%s)", ns32k_out_reg_names[REGNO (base)]);
1022         break;
1023       case SYMBOL_REF:
1024         if (! flag_pic)
1025           abort ();
1026
1027         fprintf (file, "(");
1028         output_addr_const (file, base);
1029         fprintf (file, "(sb))");
1030         break;
1031       case MEM:
1032         addr = XEXP(base,0);
1033         base = NULL;
1034         offset = NULL;
1035         while (addr != NULL)
1036           {
1037             if (GET_CODE (addr) == PLUS)
1038               {
1039                 if (GET_CODE (XEXP (addr, 0)) == PLUS)
1040                   {
1041                     tmp = XEXP (addr, 1);
1042                     addr = XEXP (addr, 0);
1043                   }
1044                 else
1045                   {
1046                     tmp = XEXP (addr, 0);
1047                     addr = XEXP (addr, 1);
1048                   }
1049               }
1050             else
1051               {
1052                 tmp = addr;
1053                 addr = NULL;
1054               }
1055             switch (GET_CODE (tmp))
1056               {
1057               case REG:
1058                 base = tmp;
1059                 break;
1060               case CONST:
1061               case CONST_INT:
1062               case SYMBOL_REF:
1063               case LABEL_REF:
1064                 if (offset)
1065                   offset = gen_rtx_PLUS (SImode, tmp, offset);
1066                 else
1067                   offset = tmp;
1068                 break;
1069               default:
1070                 abort ();
1071               }
1072           }
1073         if (! offset)
1074           offset = const0_rtx;
1075         fprintf (file, "(");
1076         output_addr_const (file, offset);
1077         if (base)
1078           fprintf (file, "(%s)", ns32k_out_reg_names[REGNO (base)]);
1079         else if (TARGET_SB)
1080           fprintf (file, "(sb)");
1081         else
1082           abort ();
1083         fprintf (file, ")");
1084         break;
1085       default:
1086         abort ();
1087       }
1088 #ifdef PC_RELATIVE
1089   else if (GET_CODE (offset) != CONST_INT)
1090     fprintf (file, "(pc)");
1091 #ifdef BASE_REG_NEEDED
1092   else if (TARGET_SB)
1093     fprintf (file, "(sb)");
1094   else
1095     abort ();
1096 #endif
1097 #endif /* PC_RELATIVE */
1098
1099   /* now print index if we have one */
1100   if (indexexp)
1101     {
1102       if (GET_CODE (indexexp) == MULT)
1103         {
1104           scale = INTVAL (XEXP (indexexp, 1)) >> 1;
1105           indexexp = XEXP (indexexp, 0);
1106         }
1107       else
1108         scale = 0;
1109       if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= F0_REGNUM)
1110         abort ();
1111
1112 #ifdef UTEK_ASM
1113       fprintf (file, "[%c`%s]",
1114                scales[scale],
1115                ns32k_out_reg_names[REGNO (indexexp)]);
1116 #else
1117       fprintf (file, "[%s:%c]",
1118                ns32k_out_reg_names[REGNO (indexexp)],
1119                scales[scale]);
1120 #endif
1121     }
1122 }
1123 \f
1124 /* National 32032 shifting is so bad that we can get
1125    better performance in many common cases by using other
1126    techniques.  */
1127 char *
1128 output_shift_insn (operands)
1129      rtx *operands;
1130 {
1131   if (GET_CODE (operands[2]) == CONST_INT
1132       && INTVAL (operands[2]) > 0
1133       && INTVAL (operands[2]) <= 3)
1134     if (GET_CODE (operands[0]) == REG)
1135       {
1136         if (GET_CODE (operands[1]) == REG)
1137           {
1138             if (REGNO (operands[0]) == REGNO (operands[1]))
1139               {
1140                 if (operands[2] == const1_rtx)
1141                   return "addd %0,%0";
1142                 else if (INTVAL (operands[2]) == 2)
1143                   return "addd %0,%0\n\taddd %0,%0";
1144               }
1145             if (operands[2] == const1_rtx)
1146               return "movd %1,%0\n\taddd %0,%0";
1147             
1148             operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
1149             return "addr %a1,%0";
1150           }
1151         if (operands[2] == const1_rtx)
1152           return "movd %1,%0\n\taddd %0,%0";
1153       }
1154     else if (GET_CODE (operands[1]) == REG)
1155       {
1156         operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
1157         return "addr %a1,%0";
1158       }
1159     else if (INTVAL (operands[2]) == 1
1160              && GET_CODE (operands[1]) == MEM
1161              && rtx_equal_p (operands [0], operands[1]))
1162       {
1163         rtx temp = XEXP (operands[1], 0);
1164         
1165         if (GET_CODE (temp) == REG
1166             || (GET_CODE (temp) == PLUS
1167                 && GET_CODE (XEXP (temp, 0)) == REG
1168                 && GET_CODE (XEXP (temp, 1)) == CONST_INT))
1169           return "addd %0,%0";
1170       }
1171     else return "ashd %2,%0";
1172   return "ashd %2,%0";
1173 }
1174
1175 char *
1176 output_move_dconst (n, s)
1177         int n;
1178         char *s;
1179 {
1180   static char r[32];
1181
1182   if (n > -9 && n < 8)
1183     strcpy (r, "movqd ");
1184   else if (n > 0 && n < 256)
1185     strcpy (r, "movzbd ");
1186   else if (n > 0 && n < 65536)
1187     strcpy (r, "movzwd ");
1188   else if (n < 0 && n > -129)
1189     strcpy (r, "movxbd ");
1190   else if (n < 0 && n > -32769)
1191     strcpy (r, "movxwd ");
1192   else
1193     strcpy (r, "movd ");
1194   strcat (r, s);
1195   return r;
1196 }