OSDN Git Service

Initial revision
[pf3gnuchains/gcc-fork.git] / gcc / config / ns32k / ns32k.c
1 /* Subroutines for assembler code output on the NS32000.
2    Copyright (C) 1988 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
20 /* Some output-actions in ns32k.md need these.  */
21 #include <stdio.h>
22 #include "config.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
33 #ifdef OSF_OS
34 int ns32k_num_files = 0;
35 #endif
36
37 void
38 trace (s, s1, s2)
39      char *s, *s1, *s2;
40 {
41     fprintf (stderr, s, s1, s2);
42 }
43
44 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */ 
45
46 int
47 hard_regno_mode_ok( regno, mode )
48 int regno;
49 int mode;
50 {
51         switch( mode ) {
52                 case QImode:
53                 case HImode:
54                 case PSImode:
55                 case SImode:
56                 case PDImode:
57                 case VOIDmode:
58                 case BLKmode:
59                         if( (regno < 8) || (regno == 16) || (regno == 17) ) {
60                                 return( 1 );
61                         }
62                         else {
63                                 return( 0 );
64                         }
65
66                 case DImode:
67                         if( (regno < 8) && ((regno & 1) == 0) ) {
68                                 return( 1 );
69                         }
70                         else {
71                                 return( 0 );
72                         }
73
74
75                 case SFmode:
76                 case SCmode:
77                         if( TARGET_32081 ) {
78                                 if( regno < 16 ) {
79                                         return( 1 );
80                                 }
81                                 else {
82                                         return( 0 );
83                                 }
84                         }
85                         else {
86                                 if( regno < 8 ) {
87                                         return( 1 );
88                                 }
89                                 else {
90                                         return( 0 );
91                                 }
92                         }
93
94                 case DFmode:
95                 case DCmode:
96                         if( (regno & 1) == 0 ) {
97                                 if( TARGET_32081 ) {
98                                         if( regno < 16 ) {
99                                                 return( 1 );
100                                         }
101                                         else {
102                                                 return( 0 );
103                                         }
104                                 }
105                                 else {
106                                         if( regno < 8 ) {
107                                                 return( 1 );
108                                         }
109                                         else {
110                                                 return( 0 );
111                                         }
112                                 }
113                         }
114                         else {
115                                 return( 0 );
116                         }
117  
118                 case XFmode:
119                         abort( 0 );
120                 case CCmode:
121                         abort( 0 );
122                 case TImode:
123                         abort( 0 );
124                 case XCmode:    
125                         abort( 0 );
126                 case TFmode:
127                         abort( 0 );
128                 case TCmode:
129                         abort( 0 );
130
131
132                 default:
133                         fprintf( stderr, "cant match mode %d\n", mode );
134                         abort( 0 );
135         }
136         abort(0);
137 }
138
139 /* ADDRESS_COST calls this.  This function is not optimal
140    for the 32032 & 32332, but it probably is better than
141    the default. */
142
143 int
144 calc_address_cost (operand)
145      rtx operand;
146 {
147   int i;
148   int cost = 0;
149   
150   if (GET_CODE (operand) == MEM)
151     cost += 3;
152   if (GET_CODE (operand) == MULT)
153     cost += 2;
154 #if 0
155   if (GET_CODE (operand) == REG)
156     cost += 1;                  /* not really, but the documentation
157                                    says different amount of registers
158                                    shouldn't return the same costs */
159 #endif
160   switch (GET_CODE (operand))
161     {
162     case REG:
163     case CONST:
164     case CONST_INT:
165     case CONST_DOUBLE:
166     case SYMBOL_REF:
167     case LABEL_REF:
168     case POST_DEC:
169     case PRE_DEC:
170       break;
171     case MULT:
172     case MEM:
173     case PLUS:
174       for (i = 0; i < GET_RTX_LENGTH (GET_CODE (operand)); i++)
175         {
176           cost += calc_address_cost (XEXP (operand, i));
177         }
178     default:
179       break;
180     }
181   return cost;
182 }
183
184 /* Return the register class of a scratch register needed to copy IN into
185    or out of a register in CLASS in MODE.  If it can be done directly,
186    NO_REGS is returned.  */
187
188 enum reg_class
189 secondary_reload_class (class, mode, in)
190      enum reg_class class;
191      enum machine_mode mode;
192      rtx in;
193 {
194   int regno = true_regnum (in);
195
196   if (regno >= FIRST_PSEUDO_REGISTER)
197     regno = -1;
198
199   /* We can place anything into GENERAL_REGS and can put GENERAL_REGS
200      into anything.  */
201   if (class == GENERAL_REGS || (regno >= 0 && regno < 8))
202     return NO_REGS;
203
204   /* Constants, memory, and FP registers can go into FP registers */
205   if ((regno == -1 || (regno >= 8 && regno < 16)) && (class == FLOAT_REGS))
206     return NO_REGS;
207
208   /* Otherwise, we need GENERAL_REGS. */
209   return GENERAL_REGS;
210 }
211 /* Generate the rtx that comes from an address expression in the md file */
212 /* The expression to be build is BASE[INDEX:SCALE].  To recognize this,
213    scale must be converted from an exponent (from ASHIFT) to a
214    muliplier (for MULT). */
215 rtx
216 gen_indexed_expr (base, index, scale)
217      rtx base, index, scale;
218 {
219   rtx addr;
220
221   /* This generates an illegal addressing mode, if BASE is
222      fp or sp.  This is handled by PRINT_OPERAND_ADDRESS.  */
223   if (GET_CODE (base) != REG && GET_CODE (base) != CONST_INT)
224     base = gen_rtx (MEM, SImode, base);
225   addr = gen_rtx (MULT, SImode, index,
226                   gen_rtx (CONST_INT, VOIDmode, 1 << INTVAL (scale)));
227   addr = gen_rtx (PLUS, SImode, base, addr);
228   return addr;
229 }
230
231 /* Return 1 if OP is a valid operand of mode MODE.  This
232    predicate rejects operands which do not have a mode
233    (such as CONST_INT which are VOIDmode).  */
234 int
235 reg_or_mem_operand (op, mode)
236      register rtx op;
237      enum machine_mode mode;
238 {
239   return (GET_MODE (op) == mode
240           && (GET_CODE (op) == REG
241               || GET_CODE (op) == SUBREG
242               || GET_CODE (op) == MEM));
243 }
244 \f
245 /* Return the best assembler insn template
246    for moving operands[1] into operands[0] as a fullword.  */
247
248 static char *
249 singlemove_string (operands)
250      rtx *operands;
251 {
252   if (GET_CODE (operands[1]) == CONST_INT
253       && INTVAL (operands[1]) <= 7
254       && INTVAL (operands[1]) >= -8)
255     return "movqd %1,%0";
256   return "movd %1,%0";
257 }
258
259 char *
260 output_move_double (operands)
261      rtx *operands;
262 {
263   enum anon1 { REGOP, OFFSOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
264   rtx latehalf[2];
265
266   /* First classify both operands.  */
267
268   if (REG_P (operands[0]))
269     optype0 = REGOP;
270   else if (offsettable_memref_p (operands[0]))
271     optype0 = OFFSOP;
272   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
273     optype0 = POPOP;
274   else
275     optype0 = RNDOP;
276
277   if (REG_P (operands[1]))
278     optype1 = REGOP;
279   else if (CONSTANT_ADDRESS_P (operands[1])
280            || GET_CODE (operands[1]) == CONST_DOUBLE)
281     optype1 = CNSTOP;
282   else if (offsettable_memref_p (operands[1]))
283     optype1 = OFFSOP;
284   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
285     optype1 = POPOP;
286   else
287     optype1 = RNDOP;
288
289   /* Check for the cases that the operand constraints are not
290      supposed to allow to happen.  Abort if we get one,
291      because generating code for these cases is painful.  */
292
293   if (optype0 == RNDOP || optype1 == RNDOP)
294     abort ();
295
296   /* Ok, we can do one word at a time.
297      Normally we do the low-numbered word first,
298      but if either operand is autodecrementing then we
299      do the high-numbered word first.
300
301      In either case, set up in LATEHALF the operands to use
302      for the high-numbered word and in some cases alter the
303      operands in OPERANDS to be suitable for the low-numbered word.  */
304
305   if (optype0 == REGOP)
306     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
307   else if (optype0 == OFFSOP)
308     latehalf[0] = adj_offsettable_operand (operands[0], 4);
309   else
310     latehalf[0] = operands[0];
311
312   if (optype1 == REGOP)
313     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
314   else if (optype1 == OFFSOP)
315     latehalf[1] = adj_offsettable_operand (operands[1], 4);
316   else if (optype1 == CNSTOP)
317     {
318       if (CONSTANT_ADDRESS_P (operands[1]))
319         latehalf[1] = const0_rtx;
320       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
321         split_double (operands[1], &operands[1], &latehalf[1]);
322     }
323   else
324     latehalf[1] = operands[1];
325
326   /* If one or both operands autodecrementing,
327      do the two words, high-numbered first.  */
328
329   if (optype0 == POPOP || optype1 == POPOP)
330     {
331       output_asm_insn (singlemove_string (latehalf), latehalf);
332       return singlemove_string (operands);
333     }
334
335   /* Not autodecrementing.  Do the two words, low-numbered first.  */
336
337   output_asm_insn (singlemove_string (operands), operands);
338
339   operands[0] = latehalf[0];
340   operands[1] = latehalf[1];
341   return singlemove_string (operands);
342 }
343
344 int
345 check_reg (oper, reg)
346      rtx oper;
347      int reg;
348 {
349   register int i;
350
351   if (oper == 0)
352     return 0;
353   switch (GET_CODE(oper))
354     {
355     case REG:
356       return (REGNO(oper) == reg) ? 1 : 0;
357     case MEM:
358       return check_reg(XEXP(oper, 0), reg);
359     case PLUS:
360     case MULT:
361       return check_reg(XEXP(oper, 0), reg) || check_reg(XEXP(oper, 1), reg);
362     }
363   return 0;
364 }
365 \f
366 /* PRINT_OPERAND is defined to call this function,
367    which is easier to debug than putting all the code in
368    a macro definition in ns32k.h.  */
369
370 void
371 print_operand (file, x, code)
372      FILE *file;
373      rtx x;
374      char code;
375 {
376   if (code == '$')
377     PUT_IMMEDIATE_PREFIX(file);
378   else if (code == '?')
379     PUT_EXTERNAL_PREFIX(file);
380   else if (GET_CODE (x) == REG)
381     fprintf (file, "%s", reg_names[REGNO (x)]);
382   else if (GET_CODE (x) == MEM)
383     output_address (XEXP (x, 0));
384   else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != DImode)
385     if (GET_MODE (x) == DFmode)
386       { 
387         union { double d; int i[2]; } u;
388         u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
389         PUT_IMMEDIATE_PREFIX(file);
390         fprintf (file, "0d%.20e", u.d); 
391       }
392     else
393       { 
394         union { double d; int i[2]; } u;
395         u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
396         PUT_IMMEDIATE_PREFIX(file);
397         fprintf (file, "0f%.20e", u.d); 
398       }
399   else
400     {
401       PUT_IMMEDIATE_PREFIX(file);
402       output_addr_const (file, x);
403     }
404 }
405 \f
406 /* PRINT_OPERAND_ADDRESS is defined to call this function,
407    which is easier to debug than putting all the code in
408    a macro definition in ns32k.h .  */
409
410 /* Completely rewritten to get this to work with Gas for PC532 Mach.
411    This function didn't work and I just wasn't able (nor very willing) to
412    figure out how it worked.
413    90-11-25 Tatu Yl|nen <ylo@cs.hut.fi> */
414
415 print_operand_address (file, addr)
416      register FILE *file;
417      register rtx addr;
418 {
419   static char scales[] = { 'b', 'w', 'd', 0, 'q', };
420   rtx offset, base, indexexp, tmp;
421   int scale;
422
423   if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == POST_DEC)
424     {
425       fprintf (file, "tos");
426       return;
427     }
428
429   offset = NULL;
430   base = NULL;
431   indexexp = NULL;
432   while (addr != NULL)
433     {
434       if (GET_CODE (addr) == PLUS)
435         {
436           if (GET_CODE (XEXP (addr, 0)) == PLUS)
437             {
438               tmp = XEXP (addr, 1);
439               addr = XEXP (addr, 0);
440             }
441           else
442             {
443               tmp = XEXP (addr,0);
444               addr = XEXP (addr,1);
445             }
446         }
447       else
448         {
449           tmp = addr;
450           addr = NULL;
451         }
452       switch (GET_CODE (tmp))
453         {
454         case PLUS:
455           abort ();
456         case MEM:
457           if (base)
458             {
459               indexexp = base;
460               base = tmp;
461             }
462           else
463             base = tmp;
464           break;
465         case REG:
466           if (REGNO (tmp) < 8)
467             if (base)
468               {
469                 indexexp = tmp;
470               }
471             else
472               base = tmp;
473           else
474             if (base)
475               {
476                 indexexp = base;
477                 base = tmp;
478               }
479             else
480               base = tmp;
481           break;
482         case MULT:
483           indexexp = tmp;
484           break;
485         case CONST:
486         case CONST_INT:
487         case SYMBOL_REF:
488         case LABEL_REF:
489           if (offset)
490             offset = gen_rtx (PLUS, SImode, tmp, offset);
491           else
492             offset = tmp;
493           break;
494         default:
495           abort ();
496         }
497     }
498   if (! offset)
499     offset = const0_rtx;
500   /* now, offset, base and indexexp are set */
501   if (! base)
502 #ifdef PC_RELATIVE
503     {
504       if (GET_CODE (offset) == LABEL_REF || GET_CODE (offset) == SYMBOL_REF)
505         ;
506       else
507 #endif
508         PUT_ABSOLUTE_PREFIX (file);
509 #ifdef PC_RELATIVE
510     }
511 #endif
512
513   output_addr_const (file,offset);
514   if (base) /* base can be (REG ...) or (MEM ...) */
515     switch (GET_CODE (base))
516       {
517         /* now we must output base.  Possible alternatives are:
518            (rN)       (REG ...)
519            (sp) (REG ...)
520            (fp)       (REG ...)
521            (pc)       (REG ...)  used for SYMBOL_REF and LABEL_REF, output
522            (disp(fp)) (MEM ...)       just before possible [rX:y]
523            (disp(sp)) (MEM ...)
524            (disp(sb)) (MEM ...)
525            */
526       case REG:
527         fprintf (file, "(%s)", reg_names[REGNO (base)]);
528         break;
529       case MEM:
530         addr = XEXP(base,0);
531         base = NULL;
532         offset = NULL;
533         while (addr != NULL)
534           {
535             if (GET_CODE (addr) == PLUS)
536               {
537                 if (GET_CODE (XEXP (addr, 0)) == PLUS)
538                   {
539                     tmp = XEXP (addr, 1);
540                     addr = XEXP (addr, 0);
541                   }
542                 else
543                   {
544                     tmp = XEXP (addr, 0);
545                     addr = XEXP (addr, 1);
546                   }
547               }
548             else
549               {
550                 tmp = addr;
551                 addr = NULL;
552               }
553             switch (GET_CODE (tmp))
554               {
555               case REG:
556                 base = tmp;
557                 break;
558               case CONST:
559               case CONST_INT:
560               case SYMBOL_REF:
561               case LABEL_REF:
562                 if (offset)
563                   offset = gen_rtx (PLUS, SImode, tmp, offset);
564                 else
565                   offset = tmp;
566                 break;
567               default:
568                 abort ();
569               }
570           }
571         if (! offset)
572           offset = const0_rtx;
573         fprintf (file, "(");
574         output_addr_const (file, offset);
575         if (base)
576           fprintf (file, "(%s)", reg_names[REGNO (base)]);
577         else if (TARGET_SB)
578           fprintf (file, "(sb)");
579         else
580           abort ();
581         fprintf (file, ")");
582         break;
583
584       default:
585         abort ();
586       }
587 #ifdef PC_RELATIVE
588   else                          /* no base */
589     if (GET_CODE (offset) == LABEL_REF || GET_CODE (offset) == SYMBOL_REF)
590       fprintf (file, "(pc)");
591 #endif
592 #ifdef BASE_REG_NEEDED          /* this is defined if the assembler always
593                                    needs a base register */
594     else if (TARGET_SB)
595       fprintf (file, "(sb)");
596     else
597       abort ();
598 #endif
599   /* now print index if we have one */
600   if (indexexp)
601     {
602       if (GET_CODE (indexexp) == MULT)
603         {
604           scale = INTVAL (XEXP (indexexp, 1)) >> 1;
605           indexexp = XEXP (indexexp, 0);
606         }
607       else
608         scale = 0;
609       if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= 8)
610         abort ();
611
612       fprintf (file, "[%s:%c]",
613                reg_names[REGNO (indexexp)],
614                scales[scale]);
615     }
616 }
617 \f
618 /* National 32032 shifting is so bad that we can get
619    better performance in many common cases by using other
620    techniques.  */
621 char *
622 output_shift_insn (operands)
623      rtx *operands;
624 {
625   if (GET_CODE (operands[2]) == CONST_INT
626       && INTVAL (operands[2]) > 0
627       && INTVAL (operands[2]) <= 3)
628     if (GET_CODE (operands[0]) == REG)
629       {
630         if (GET_CODE (operands[1]) == REG)
631           {
632             if (REGNO (operands[0]) == REGNO (operands[1]))
633               {
634                 if (operands[2] == const1_rtx)
635                   return "addd %0,%0";
636                 else if (INTVAL (operands[2]) == 2)
637                   return "addd %0,%0\n\taddd %0,%0";
638               }
639             if (operands[2] == const1_rtx)
640               return "movd %1,%0\n\taddd %0,%0";
641             
642             operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
643             return "addr %a1,%0";
644           }
645         if (operands[2] == const1_rtx)
646           return "movd %1,%0\n\taddd %0,%0";
647       }
648     else if (GET_CODE (operands[1]) == REG)
649       {
650         operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
651         return "addr %a1,%0";
652       }
653     else if (INTVAL (operands[2]) == 1
654              && GET_CODE (operands[1]) == MEM
655              && rtx_equal_p (operands [0], operands[1]))
656       {
657         rtx temp = XEXP (operands[1], 0);
658         
659         if (GET_CODE (temp) == REG
660             || (GET_CODE (temp) == PLUS
661                 && GET_CODE (XEXP (temp, 0)) == REG
662                 && GET_CODE (XEXP (temp, 1)) == CONST_INT))
663           return "addd %0,%0";
664       }
665     else return "ashd %2,%0";
666   return "ashd %2,%0";
667 }