OSDN Git Service

dummy import to prevent merge lossage
[pf3gnuchains/gcc-fork.git] / gcc / config / convex / convex.c
1 /* Subroutines for insn-output.c for Convex.
2    Copyright (C) 1988, 1993, 1994, 1997 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 1, 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 <stdio.h>
23 #include "tree.h"
24 #include "rtl.h"
25 #include "regs.h"
26 #include "hard-reg-set.h"
27 #include "real.h"
28 #include "insn-config.h"
29 #include "conditions.h"
30 #include "insn-flags.h"
31 #include "insn-attr.h"
32 #include "output.h"
33 #include "expr.h"
34
35 /* Tables used in convex.h */
36
37 char regno_ok_for_index_p_base[1 + LAST_VIRTUAL_REGISTER + 1];
38 enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER];
39 enum reg_class reg_class_from_letter[256];
40
41 /* Target cpu index. */
42
43 int target_cpu;
44
45 /* Boolean to keep track of whether the current section is .text or not.
46    Used by .align handler in convex.h. */
47
48 int current_section_is_text;
49
50 /* Communication between output_compare and output_condjump. */
51
52 static rtx cmp_operand0, cmp_operand1;
53 static char cmp_modech;
54
55 /* Forwards */
56
57 static rtx frame_argblock;
58 static int frame_argblock_size;
59 static rtx convert_arg_pushes ();
60 static void expand_movstr_call ();
61
62 /* Here from OVERRIDE_OPTIONS at startup.  Initialize constant tables. */
63
64 init_convex ()
65 {
66   int regno;
67
68   /* Set A and S reg classes. */
69   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
70     if (A_REGNO_P (regno))
71       {
72         regno_ok_for_index_p[regno] = 1;
73         regno_reg_class[regno] = INDEX_REGS;
74       }
75     else
76       {
77         regno_ok_for_index_p[regno] = 0;
78         regno_reg_class[regno] = S_REGS;
79       }
80
81   /* Can't index off the stack pointer, register 0. */
82   regno_ok_for_index_p[STACK_POINTER_REGNUM] = 0;
83   regno_reg_class[STACK_POINTER_REGNUM] = SP_REGS;
84
85   /* Can't index off aliases of the stack pointer.  */
86   regno_ok_for_index_p[VIRTUAL_INCOMING_ARGS_REGNUM] = 1;
87   regno_ok_for_index_p[VIRTUAL_STACK_VARS_REGNUM] = 1;
88   regno_ok_for_index_p[VIRTUAL_STACK_DYNAMIC_REGNUM] = 0;
89   regno_ok_for_index_p[VIRTUAL_OUTGOING_ARGS_REGNUM] = 0;
90
91   /* Can't index off hard reg -1 == pseudos not assigned */
92   regno_ok_for_index_p[-1] = 0;
93
94   /* Set reg class letters */
95   reg_class_from_letter['a'] = A_REGS;
96   reg_class_from_letter['A'] = INDEX_REGS;
97   reg_class_from_letter['d'] = S_REGS;
98
99   /* Turn off floating point exception enables in the psw. */
100   psw_disable_float ();
101 }
102
103 psw_disable_float ()
104 {
105 #if __convex__ && __GNUC__
106   register int *p;
107   asm ("mov fp,%0" : "=a" (p));
108   while (p)
109     {
110       p[1] &= ~0x1000c400;
111       p = (int *) p[2];
112     }
113 #endif  
114 }
115 \f
116 /* Here to output code for a compare insn.  Output nothing, just
117    record the operands and their mode. */
118
119 char *
120 output_cmp (operand0, operand1, modech)
121      rtx operand0, operand1;
122      char modech;
123 {
124   cmp_operand0 = operand0;
125   cmp_operand1 = operand1;
126   cmp_modech = modech;
127   return "";
128 }
129
130 /* Output code for a conditional jump.  The preceding instruction
131    is necessarily a compare.  Output two instructions, for example
132        eq.w a1,a2
133        jbra.t L5
134    for
135        (cmpsi a1 a2)
136        (beq L5)
137  */
138
139 char *
140 output_condjump (label, cond, jbr_sense)
141      rtx label;
142      char *cond;
143      char jbr_sense;
144 {
145   rtx operands[3];
146   char cmp_op[4];
147   char buf[80];
148   char jbr_regch;
149
150   strcpy (cmp_op, cond);
151
152   /* [BL] mean the value is being compared against immediate 0.
153      Use neg.x, which produces the same carry that eq.x #0 would if it
154      existed.  In this case operands[1] is a scratch register, not a
155      compare operand. */
156
157   if (cmp_modech == 'B' || cmp_modech == 'L')
158     {
159       cmp_modech = cmp_modech - 'A' + 'a';
160       strcpy (cmp_op, "neg");
161     }
162
163   /* [WH] mean the value being compared resulted from "add.[wh] #-1,rk"
164      when rk was nonnegative -- we can omit equality compares against -1
165      or inequality compares against 0. */
166
167   else if (cmp_modech == 'W' || cmp_modech == 'H')
168     {
169       if (! strcmp (cmp_op, "eq") && cmp_operand1 == constm1_rtx)
170         jbr_sense ^= 't' ^ 'f';
171       else if (! strcmp (cmp_op, "lt") && cmp_operand1 == const0_rtx)
172         ;
173       else
174         cmp_modech = cmp_modech - 'A' + 'a';
175     }
176
177   /* Constant must be first; swap operands if necessary.
178      If lt, le, ltu, leu are swapped, change to le, lt, leu, ltu
179      and reverse the sense of the jump. */
180
181   if (! REG_P (cmp_operand1))
182     {
183       operands[0] = cmp_operand1;
184       operands[1] = cmp_operand0;
185       if (cmp_op[0] == 'l')
186         {
187           cmp_op[1] ^= 'e' ^ 't';
188           jbr_sense ^= 't' ^ 'f';
189         }
190     }
191   else
192     {
193       operands[0] = cmp_operand0;
194       operands[1] = cmp_operand1;
195     }
196
197   operands[2] = label;
198
199   if (S_REG_P (operands[1]))
200     jbr_regch = 's';
201   else if (A_REG_P (operands[1]))
202     jbr_regch = 'a';
203   else
204     abort ();
205
206   if (cmp_modech == 'W' || cmp_modech == 'H')
207     sprintf (buf, "jbr%c.%c %%l2", jbr_regch, jbr_sense);
208   else
209     sprintf (buf, "%s.%c %%0,%%1\n\tjbr%c.%c %%l2",
210              cmp_op, cmp_modech, jbr_regch, jbr_sense);
211   output_asm_insn (buf, operands);
212   return "";
213 }
214
215 /* Return 1 if OP is valid for cmpsf.
216    In IEEE mode, +/- zero compares are not handled by 
217      the immediate versions of eq.s and on some machines, lt.s, and le.s.  
218    So disallow 0.0 as the immediate operand of xx.s compares in IEEE mode. */
219
220 int
221 nonmemory_cmpsf_operand (op, mode)
222      rtx op;
223      enum machine_mode mode;
224 {
225 #if _IEEE_FLOAT_
226   if (op == CONST0_RTX (SFmode))
227     return 0;
228 #endif
229
230   return nonmemory_operand (op, mode);
231 }
232 \f
233 /* Convex /bin/as does not like unary minus in some contexts.
234    Simplify CONST addresses to remove it. */
235
236 rtx
237 simplify_for_convex (x)
238      rtx x;
239 {
240   switch (GET_CODE (x))
241     {
242     case MINUS:
243       if (GET_CODE (XEXP (x, 1)) == CONST_INT
244           && INTVAL (XEXP (x, 1)) < 0)
245         {
246           PUT_CODE (x, PLUS);
247           XEXP (x, 1) = GEN_INT (- INTVAL (XEXP (x, 1)));
248         }
249       break;
250
251     case CONST:
252       return simplify_for_convex (XEXP (x, 0));
253     }
254
255   return x;
256 }
257 \f
258 /* Routines to separate CONST_DOUBLEs into component parts. */
259
260 int
261 const_double_high_int (x)
262      rtx x;
263 {
264   if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
265     return CONST_DOUBLE_LOW (x);
266   else
267     return CONST_DOUBLE_HIGH (x);
268 }
269
270 int
271 const_double_low_int (x)
272      rtx x;
273 {
274   if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
275     return CONST_DOUBLE_HIGH (x);
276   else
277     return CONST_DOUBLE_LOW (x);
278 }
279 \f
280 /* Inline block copy. */
281
282 void
283 expand_movstr (operands)
284      rtx *operands;
285 {
286   rtx dest = operands[0];
287   rtx src = operands[1];
288   int align = INTVAL (operands[3]);
289   int nregs, maxsize;
290   unsigned len;
291   enum machine_mode mode;
292   rtx reg, load, store, prev_store, prev_store_2;
293   int size;
294
295   /* Decide how many regs to use, depending on load latency, and what
296      size pieces to move, depending on whether machine does unaligned
297      loads and stores efficiently. */
298
299   if (TARGET_C1)
300     {
301       /* ld.l latency is 4, no alignment problems. */
302       nregs = 3, maxsize = 8;
303     }
304   else if (TARGET_C2)
305     {
306       /* loads are latency 2 if we avoid ld.l not at least word aligned. */
307       if (align >= 4)
308         nregs = 2, maxsize = 8;
309       else
310         nregs = 2, maxsize = 4;
311     }
312   else if (TARGET_C34)
313     {
314       /* latency is 4 if aligned, horrible if not. */
315       nregs = 3, maxsize = align;
316     }
317   else if (TARGET_C38)
318     {
319       /* latency is 2 if at least word aligned, 3 or 4 if unaligned. */
320       if (align >= 4)
321         nregs = 2, maxsize = 8;
322       else
323         nregs = 3, maxsize = 8;
324     }
325   else
326     abort ();
327
328   /* Caller is not necessarily prepared for us to fail in this
329      expansion.  So fall back by generating memcpy call here. */
330
331   if (GET_CODE (operands[2]) != CONST_INT
332       || (len = INTVAL (operands[2])) > (unsigned) 32 * maxsize)
333     {
334       expand_movstr_call (operands);
335       return;
336     }
337
338   reg = 0;
339   prev_store = prev_store_2 = 0;
340
341   while (len > 0)
342     {
343       if (len >= 8 && maxsize >= 8)
344         mode = DImode;
345       else if (len >= 4 && maxsize >= 4)
346         mode = SImode;
347       else if (len >= 2 && maxsize >= 2)
348         mode = HImode;
349       else
350         mode = QImode;
351
352       /* If no temp pseudo to reuse, or not the right mode, make one */
353       if (! reg || GET_MODE (reg) != mode)
354         reg = gen_reg_rtx (mode);
355
356       /* Get src and dest in the right mode */
357       if (GET_MODE (src) != mode)
358         src = change_address (src, mode, 0),
359         dest = change_address (dest, mode, 0);
360
361       /* Make load and store patterns for this piece */
362       load = gen_rtx (SET, VOIDmode, reg, src);
363       store = gen_rtx (SET, VOIDmode, dest, reg);
364
365       /* Emit the load and the store from last time. 
366          When we emit a store, we can reuse its temp reg. */
367       emit_insn (load);
368       if (prev_store)
369         {
370           reg = SET_SRC (prev_store);
371           emit_insn (prev_store);
372         }
373       else
374         reg = 0;
375
376       /* Queue up the store, for next time or the time after that. */
377       if (nregs == 2)
378         prev_store = store;
379       else
380         prev_store = prev_store_2, prev_store_2 = store;
381
382       /* Advance to next piece. */
383       size = GET_MODE_SIZE (mode);
384       src = adj_offsettable_operand (src, size);
385       dest = adj_offsettable_operand (dest, size);
386       len -= size;
387     }
388
389   /* Finally, emit the last stores. */
390   if (prev_store)
391     emit_insn (prev_store);
392   if (prev_store_2)
393     emit_insn (prev_store_2);
394 }
395
396 static void
397 expand_movstr_call (operands)
398      rtx *operands;
399 {
400   emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), 0,
401                      VOIDmode, 3,
402                      XEXP (operands[0], 0), Pmode,
403                      XEXP (operands[1], 0), Pmode,
404                      convert_to_mode (TYPE_MODE (sizetype), operands[2],
405                                       TREE_UNSIGNED (sizetype)),
406                      TYPE_MODE (sizetype));
407 }
408 \f
409 #if _IEEE_FLOAT_
410 #define MAX_FLOAT 3.4028234663852886e+38
411 #define MIN_FLOAT 1.1754943508222875e-38
412 #else
413 #define MAX_FLOAT 1.7014117331926443e+38
414 #define MIN_FLOAT 2.9387358770557188e-39
415 #endif
416
417 int
418 check_float_value (mode, dp, overflow)
419      enum machine_mode mode;
420      REAL_VALUE_TYPE *dp;
421      int overflow;
422 {
423   REAL_VALUE_TYPE d = *dp;
424
425   if (overflow)
426     {
427       *dp = MAX_FLOAT;
428       return 1;
429     }
430
431   if (mode == SFmode)
432     {
433       if (d > MAX_FLOAT)
434         {
435           *dp = MAX_FLOAT;
436           return 1;
437         }
438       else if (d < -MAX_FLOAT)
439         {
440           *dp = -MAX_FLOAT;
441           return 1;
442         }       
443       else if ((d > 0 && d < MIN_FLOAT) || (d < 0 && d > -MIN_FLOAT))
444         {
445           *dp = 0.0;
446           return 1;
447         }
448     }
449
450   return 0;
451 }
452 \f
453 /* Output the label at the start of a function.
454    Precede it with the number of formal args so debuggers will have
455    some idea of how many args to print. */
456
457 void
458 asm_declare_function_name (file, name, decl)
459     FILE *file;
460     char *name;
461     tree decl;
462 {
463   tree parms;
464   int nargs = list_length (DECL_ARGUMENTS (decl));
465
466   char *p, c;
467   extern char *version_string;
468   static char vers[4];
469   int i;
470   
471   p = version_string;
472   for (i = 0; i < 3; ) {
473     c = *p;
474     if (c - '0' < (unsigned) 10)
475       vers[i++] = c;
476     if (c == 0 || c == ' ')
477       vers[i++] = '0';
478     else
479       p++;
480   }
481   fprintf (file, "\tds.b \"g%s\"\n", vers);
482
483   if (nargs < 100)
484     fprintf (file, "\tds.b \"+%02d\\0\"\n", nargs);
485   else
486     fprintf (file, "\tds.b \"+00\\0\"\n");
487
488   ASM_OUTPUT_LABEL (file, name);
489 }
490 \f
491 /* Print an instruction operand X on file FILE.
492    CODE is the code from the %-spec that requested printing this operand;
493    if `%z3' was used to print operand 3, then CODE is 'z'. */
494 /* Convex codes:
495     %u prints a CONST_DOUBLE's high word
496     %v prints a CONST_DOUBLE's low word
497     %z prints a CONST_INT shift count as a multiply operand -- viz. 1 << n.
498  */
499
500 print_operand (file, x, code)
501      FILE *file;
502      rtx x;
503      char code;
504 {
505   long u[2];
506   REAL_VALUE_TYPE d;
507
508   switch (GET_CODE (x))
509     {
510     case REG:
511       fprintf (file, "%s", reg_names[REGNO (x)]);
512       break;
513
514     case MEM:
515       output_address (XEXP (x, 0));
516       break;
517
518     case CONST_DOUBLE:
519       REAL_VALUE_FROM_CONST_DOUBLE (d, x);
520       switch (GET_MODE (x)) {
521       case DFmode:
522 #if 0 /* doesn't work, produces dfloats */
523         REAL_VALUE_TO_TARGET_DOUBLE (d, u); 
524 #else
525         {
526           union { double d; int i[2]; } t;
527           t.d = d;
528           u[0] = t.i[0];
529           u[1] = t.i[1];
530         }
531 #endif
532         if (code == 'u')
533           fprintf (file, "#%#x", u[0]);
534         else if (code == 'v')
535           fprintf (file, "#%#x", u[1]);
536         else
537           outfloat (file, d, "%.17e", "#", "");
538         break;
539       case SFmode:
540         outfloat (file, d, "%.9e", "#", "");
541         break;
542       default:
543         if (code == 'u')
544           fprintf (file, "#%d", CONST_DOUBLE_HIGH (x));
545         else
546           fprintf (file, "#%d", CONST_DOUBLE_LOW (x));
547       }
548       break;
549
550     default:
551       if (code == 'z')
552         {
553           if (GET_CODE (x) != CONST_INT)
554             abort ();
555           fprintf (file, "#%d", 1 << INTVAL (x));
556         }
557       else
558         {
559           putc ('#', file);
560           output_addr_const (file, x);
561         }
562     }
563 }
564
565 /* Print a memory operand whose address is X, on file FILE. */
566
567 print_operand_address (file, addr)
568      FILE *file;
569      rtx addr;
570 {
571   rtx index = 0;
572   rtx offset = 0;
573
574   if (GET_CODE (addr) == MEM)
575     {
576       fprintf (file, "@");
577       addr = XEXP (addr, 0);
578     }
579
580   switch (GET_CODE (addr))
581     {
582     case REG:
583       index = addr;
584       break;
585
586     case PLUS:
587       index = XEXP (addr, 0);
588       if (REG_P (index))
589         offset = XEXP (addr, 1);
590       else
591         {
592           offset = XEXP (addr, 0);
593           index = XEXP (addr, 1);
594           if (! REG_P (index))
595             abort ();
596         }
597       break;
598
599     default:
600       offset = addr;
601       break;
602     }
603
604   if (offset)
605     output_addr_const (file, offset);
606
607   if (index)
608     fprintf (file, "(%s)", reg_names[REGNO (index)]);
609 }
610
611 /* Output a float to FILE, value VALUE, format FMT, preceded by PFX
612    and followed by SFX. */
613
614 outfloat (file, value, fmt, pfx, sfx)
615      FILE *file;
616      REAL_VALUE_TYPE value;
617      char *fmt, *pfx, *sfx;
618 {
619   char buf[64];
620   fputs (pfx, file);
621   REAL_VALUE_TO_DECIMAL (value, fmt, buf);
622   fputs (buf, file);
623   fputs (sfx, file);
624 }
625 \f
626 /* Here during RTL generation of return.  If we are at the final return
627    in a function, go through the function and replace pushes with stores
628    into a frame arg block.  This is similar to what ACCUMULATE_OUTGOING_ARGS
629    does, but we must index off the frame pointer, not the stack pointer,
630    and the calling sequence does not require the arg block to be at the
631    top of the stack.  */
632
633 replace_arg_pushes ()
634 {
635   /* Doesn't work yet. */
636 }
637
638 /* Output the insns needed to do a call.  operands[] are
639      0 - MEM, the place to call
640      1 - CONST_INT, the number of bytes in the arg list
641      2 - CONST_INT, the number of arguments
642      3 - CONST_INT, the number of bytes to pop
643      4 - address of the arg list.  
644  */
645
646 char *
647 output_call (insn, operands)
648      rtx insn, *operands;
649 {
650   if (operands[4] == stack_pointer_rtx)
651     output_asm_insn ("mov sp,ap", operands);
652   else
653     abort ();
654
655   if (TARGET_ARGCOUNT)
656     output_asm_insn ("pshea %a2", operands);
657
658   output_asm_insn ("calls %0", operands);
659
660   output_asm_insn ("ld.w 12(fp),ap", operands);
661
662   if (operands[4] == stack_pointer_rtx && operands[3] != const0_rtx)
663     output_asm_insn ("add.w %3,sp", operands);
664
665   return "";
666 }
667
668
669 /* Here after reloading, before the second scheduling pass. */
670
671 emit_ap_optimizations ()
672 {
673   /* Removed for now. */
674 }
675