OSDN Git Service

Fix typos in comments.
[pf3gnuchains/gcc-fork.git] / gcc / config / pdp11 / pdp11.c
1 /* Subroutines for gcc2 for pdp11.
2    Copyright (C) 1994 Free Software Foundation, Inc.
3    Contributed by Michael K. Gschwind (mike@vlsivie.tuwien.ac.at).
4
5 This file is part of GNU CC.
6
7 GNU CC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 1, or (at your option)
10 any later version.
11
12 GNU CC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU CC; see the file COPYING.  If not, write to
19 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
20
21 #ifndef FILE
22 #include <stdio.h>
23 #endif
24 #include "config.h"
25 #include "rtl.h"
26 #include "regs.h"
27 #include "hard-reg-set.h"
28 #include "real.h"
29 #include "insn-config.h"
30 #include "conditions.h"
31 #include "insn-flags.h"
32 #include "output.h"
33 #include "insn-attr.h"
34
35 /*
36 #define FPU_REG_P(X)    ((X)>=8 && (X)<14)
37 #define CPU_REG_P(X)    ((X)>=0 && (X)<8)
38 */
39
40 /* this is the current value returned by the macro FIRST_PARM_OFFSET 
41    defined in tm.h */
42 int current_first_parm_offset;
43
44 /* This is where the condition code register lives.  */
45 /* rtx cc0_reg_rtx; - no longer needed? */
46
47 static rtx find_addr_reg (); 
48
49 /* Nonzero if OP is a valid second operand for an arithmetic insn.  */
50
51 int
52 arith_operand (op, mode)
53      rtx op;
54      enum machine_mode mode;
55 {
56   return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
57 }
58
59 int
60 const_immediate_operand (op, mode)
61      rtx op;
62      enum machine_mode mode;
63 {
64   return (GET_CODE (op) == CONST_INT);
65 }
66
67 int 
68 immediate15_operand (op, mode)
69      rtx op;
70      enum machine_mode mode;
71 {
72     return (GET_CODE (op) == CONST_INT && ((INTVAL (op) & 0x8000) == 0x0000));
73 }
74
75 int
76 expand_shift_operand (op, mode)
77   rtx op;
78   enum machine_mode mode;
79 {
80     return (GET_CODE (op) == CONST_INT 
81             && abs (INTVAL(op)) > 1 
82             && abs (INTVAL(op)) <= 4);
83 }
84
85 /*
86    stream is a stdio stream to output the code to.
87    size is an int: how many units of temporary storage to allocate.
88    Refer to the array `regs_ever_live' to determine which registers
89    to save; `regs_ever_live[I]' is nonzero if register number I
90    is ever used in the function.  This macro is responsible for
91    knowing which registers should not be saved even if used.  
92 */
93
94 void 
95 output_function_prologue(stream, size)
96   FILE *stream;
97   int size;
98 {                                                              
99     extern char call_used_regs[];                                       
100     extern int frame_pointer_needed;                            
101
102     int fsize = ((size) + 1) & ~1;                                      
103     int regno, nregs, i;                                                
104     int offset = 0;
105
106     int via_ac = -1;
107     
108     fprintf (stream, "\n\t;     /* function prologue %s*/\n", current_function_name);           
109
110     /* if we are outputting code for main, 
111        the switch FPU to right mode if TARGET_FPU */
112     if ( (strcmp ("main", current_function_name) == 0)
113          && TARGET_FPU)
114     {
115         fprintf(stream, "\t;/* switch cpu to double float, single integer */\n");
116         fprintf(stream, "\tsetd\n");
117         fprintf(stream, "\tseti\n\n");
118     }
119     
120     if (frame_pointer_needed)                                   
121     {                                                           
122         fprintf(stream, "\tmov fp, -(sp)\n");                   
123         fprintf(stream, "\tmov sp, fp\n");                              
124     }                                                           
125     else                                                                
126     {                                                           
127         /* DON'T SAVE FP */
128     }                                                           
129
130     /* make frame */
131     if (fsize)                                                  
132         fprintf (stream, "\tsub $%d, sp\n", fsize);                     
133
134     /* save CPU registers  */
135     for (regno = 0; regno < 8; regno++)                         
136         if (regs_ever_live[regno] && ! call_used_regs[regno])   
137             if (! ((regno == FRAME_POINTER_REGNUM)                      
138                    && frame_pointer_needed))                            
139                 fprintf (stream, "\tmov %s, -(sp)\n", reg_names[regno]);        
140     /* fpu regs saving */
141     
142     /* via_ac specifies the ac to use for saving ac4, ac5 */
143     via_ac = -1;
144     
145     for (regno = 8; regno < FIRST_PSEUDO_REGISTER ; regno++) 
146     {
147         /* ac0 - ac3 */                                         
148         if (LOAD_FPU_REG_P(regno)
149             && regs_ever_live[regno] 
150             && ! call_used_regs[regno])
151         {
152             fprintf (stream, "\tfstd %s, -(sp)\n", reg_names[regno]);
153             via_ac = regno;
154         }
155         
156         /* maybe make ac4, ac5 call used regs?? */
157         /* ac4 - ac5 */
158         if (NO_LOAD_FPU_REG_P(regno)
159             && regs_ever_live[regno]
160             && ! call_used_regs[regno])
161         {
162             if (via_ac == -1)
163                 abort();
164             
165             fprintf (stream, "\tfldd %s, %s\n", reg_names[regno], reg_names[via_ac]);
166             fprintf (stream, "\tfstd %s, -(sp)\n", reg_names[via_ac]);
167         }
168     }
169
170     fprintf (stream, "\t;/* end of prologue */\n\n");           
171 }
172
173 /*
174    The function epilogue should not depend on the current stack pointer!
175    It should use the frame pointer only.  This is mandatory because
176    of alloca; we also take advantage of it to omit stack adjustments
177    before returning.  */
178
179 /* maybe we can make leaf functions faster by switching to the
180    second register file - this way we don't have to save regs!
181    leaf functions are ~ 50% of all functions (dynamically!) 
182
183    set/clear bit 11 (dec. 2048) of status word for switching register files - 
184    but how can we do this? the pdp11/45 manual says bit may only 
185    be set (p.24), but not cleared!
186
187    switching to kernel is probably more expensive, so we'll leave it 
188    like this and not use the second set of registers... 
189
190    maybe as option if you want to generate code for kernel mode? */
191
192
193 void 
194 output_function_epilogue(stream, size)
195   FILE *stream;
196   int size;
197 {                                                               
198     extern char call_used_regs[];                                       
199     extern int may_call_alloca;
200
201     int fsize = ((size) + 1) & ~1;                                      
202     int nregs, regno, i, j, k, adjust_fp;                               
203
204     int via_ac;
205     
206     fprintf (stream, "\n\t;     /*function epilogue */\n");             
207
208     if (frame_pointer_needed)                                   
209     {                                                           
210         /* hope this is safe - m68k does it also .... */                
211         regs_ever_live[FRAME_POINTER_REGNUM] = 0;                       
212                                                                 
213         for (i =7, j = 0 ; i >= 0 ; i--)                                
214             if (regs_ever_live[i] && ! call_used_regs[i])               
215                 j++;
216         
217         /* remember # of pushed bytes for CPU regs */
218         k = 2*j;
219         
220         for (i =7 ; i >= 0 ; i--)                                       
221             if (regs_ever_live[i] && ! call_used_regs[i])               
222                 fprintf(stream, "\tmov %d(fp), %s\n",-fsize-2*j--, reg_names[i]);
223
224         /* get ACs */                                           
225         via_ac = FIRST_PSEUDO_REGISTER -1;
226         
227         for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
228             if (regs_ever_live[i] && ! call_used_regs[i])
229             {
230                 via_ac = i;
231                 k += 8;
232             }
233         
234         for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
235         {
236             if (LOAD_FPU_REG_P(i)
237                 && regs_ever_live[i]
238                 && ! call_used_regs[i])
239             {
240                 fprintf(stream, "\tfldd %d(fp), %s\n", -fsize-k, reg_names[i]);
241                 k -= 8;
242             }
243             
244             if (NO_LOAD_FPU_REG_P(i)
245                 && regs_ever_live[i]
246                 && ! call_used_regs[i])
247             {
248                 if (! LOAD_FPU_REG_P(via_ac))
249                     abort();
250                     
251                 fprintf(stream, "\tfldd %d(fp), %s\n", -fsize-k, reg_names[via_ac]);
252                 fprintf(stream, "\tfstd %s, %s\n", reg_names[via_ac], reg_names[i]);
253                 k -= 8;
254             }
255         }
256         
257         fprintf(stream, "\tmov fp, sp\n");                              
258         fprintf (stream, "\tmov (sp)+, fp\n");                          
259     }                                                           
260     else                                                                
261     {              
262         via_ac = FIRST_PSEUDO_REGISTER -1;
263         
264         /* get ACs */
265         for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
266             if (regs_ever_live[i] && call_used_regs[i])
267                 via_ac = i;
268         
269         for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
270         {
271             if (LOAD_FPU_REG_P(i)
272                 && regs_ever_live[i]
273                 && ! call_used_regs[i])
274               fprintf(stream, "\tfldd (sp)+, %s\n", reg_names[i]);
275             
276             if (NO_LOAD_FPU_REG_P(i)
277                 && regs_ever_live[i]
278                 && ! call_used_regs[i])
279             {
280                 if (! LOAD_FPU_REG_P(via_ac))
281                     abort();
282                     
283                 fprintf(stream, "\tfldd (sp)+, %s\n", reg_names[via_ac]);
284                 fprintf(stream, "\tfstd %s, %s\n", reg_names[via_ac], reg_names[i]);
285             }
286         }
287
288         for (i=7; i >= 0; i--)                                  
289             if (regs_ever_live[i] && !call_used_regs[i])                
290                 fprintf(stream, "\tmov (sp)+, %s\n", reg_names[i]);     
291                                                                 
292         if (fsize)                                              
293             fprintf((stream), "\tadd $%d, sp\n", fsize);                
294     }                   
295                                         
296     fprintf (stream, "\trts pc\n");                                     
297     fprintf (stream, "\t;/* end of epilogue*/\n\n\n");          
298 }
299         
300 /* Return the best assembler insn template
301    for moving operands[1] into operands[0] as a fullword.  */
302 static char *
303 singlemove_string (operands)
304      rtx *operands;
305 {
306   if (operands[1] != const0_rtx)
307     return "mov %1,%0";
308
309   return "clr %0";
310 }
311
312 \f
313 /* Output assembler code to perform a doubleword move insn
314    with operands OPERANDS.  */
315
316 char *
317 output_move_double (operands)
318      rtx *operands;
319 {
320   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
321   rtx latehalf[2];
322   rtx addreg0 = 0, addreg1 = 0;
323
324   /* First classify both operands.  */
325
326   if (REG_P (operands[0]))
327     optype0 = REGOP;
328   else if (offsettable_memref_p (operands[0]))
329     optype0 = OFFSOP;
330   else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
331     optype0 = POPOP;
332   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
333     optype0 = PUSHOP;
334   else if (GET_CODE (operands[0]) == MEM)
335     optype0 = MEMOP;
336   else
337     optype0 = RNDOP;
338
339   if (REG_P (operands[1]))
340     optype1 = REGOP;
341   else if (CONSTANT_P (operands[1]))
342 #if 0
343            || GET_CODE (operands[1]) == CONST_DOUBLE)
344 #endif
345     optype1 = CNSTOP;
346   else if (offsettable_memref_p (operands[1]))
347     optype1 = OFFSOP;
348   else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
349     optype1 = POPOP;
350   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
351     optype1 = PUSHOP;
352   else if (GET_CODE (operands[1]) == MEM)
353     optype1 = MEMOP;
354   else
355     optype1 = RNDOP;
356
357   /* Check for the cases that the operand constraints are not
358      supposed to allow to happen.  Abort if we get one,
359      because generating code for these cases is painful.  */
360
361   if (optype0 == RNDOP || optype1 == RNDOP)
362     abort ();
363
364   /* If one operand is decrementing and one is incrementing
365      decrement the former register explicitly
366      and change that operand into ordinary indexing.  */
367
368   if (optype0 == PUSHOP && optype1 == POPOP)
369     {
370       operands[0] = XEXP (XEXP (operands[0], 0), 0);
371       output_asm_insn ("sub $4,%0", operands);
372       operands[0] = gen_rtx (MEM, SImode, operands[0]);
373       optype0 = OFFSOP;
374     }
375   if (optype0 == POPOP && optype1 == PUSHOP)
376     {
377       operands[1] = XEXP (XEXP (operands[1], 0), 0);
378       output_asm_insn ("sub $4,%1", operands);
379       operands[1] = gen_rtx (MEM, SImode, operands[1]);
380       optype1 = OFFSOP;
381     }
382
383   /* If an operand is an unoffsettable memory ref, find a register
384      we can increment temporarily to make it refer to the second word.  */
385
386   if (optype0 == MEMOP)
387     addreg0 = find_addr_reg (XEXP (operands[0], 0));
388
389   if (optype1 == MEMOP)
390     addreg1 = find_addr_reg (XEXP (operands[1], 0));
391
392   /* Ok, we can do one word at a time.
393      Normally we do the low-numbered word first,
394      but if either operand is autodecrementing then we
395      do the high-numbered word first.
396
397      In either case, set up in LATEHALF the operands to use
398      for the high-numbered word and in some cases alter the
399      operands in OPERANDS to be suitable for the low-numbered word.  */
400
401   if (optype0 == REGOP)
402     latehalf[0] = gen_rtx (REG, HImode, REGNO (operands[0]) + 1);
403   else if (optype0 == OFFSOP)
404     latehalf[0] = adj_offsettable_operand (operands[0], 2);
405   else
406     latehalf[0] = operands[0];
407
408   if (optype1 == REGOP)
409     latehalf[1] = gen_rtx (REG, HImode, REGNO (operands[1]) + 1);
410   else if (optype1 == OFFSOP)
411     latehalf[1] = adj_offsettable_operand (operands[1], 2);
412   else if (optype1 == CNSTOP)
413     {
414         if (CONSTANT_P (operands[1]))
415         {
416             /* now the mess begins, high word is in lower word??? 
417
418                that's what ashc makes me think, but I don't remember :-( */
419             latehalf[1] = gen_rtx(CONST_INT, VOIDmode, 
420                                   INTVAL(operands[1])>>16);
421             operands[1] = gen_rtx(CONST_INT, VOIDmode,
422                                   INTVAL(operands[1])&0xff);
423         }
424       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
425         {
426             /* immediate 32 bit values not allowed */
427             abort();
428         }
429     }
430   else
431     latehalf[1] = operands[1];
432
433   /* If insn is effectively movd N(sp),-(sp) then we will do the
434      high word first.  We should use the adjusted operand 1 (which is N+4(sp))
435      for the low word as well, to compensate for the first decrement of sp.  */
436   if (optype0 == PUSHOP
437       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
438       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
439     operands[1] = latehalf[1];
440
441   /* If one or both operands autodecrementing,
442      do the two words, high-numbered first.  */
443
444   /* Likewise,  the first move would clobber the source of the second one,
445      do them in the other order.  This happens only for registers;
446      such overlap can't happen in memory unless the user explicitly
447      sets it up, and that is an undefined circumstance.  */
448
449   if (optype0 == PUSHOP || optype1 == PUSHOP
450       || (optype0 == REGOP && optype1 == REGOP
451           && REGNO (operands[0]) == REGNO (latehalf[1])))
452     {
453       /* Make any unoffsettable addresses point at high-numbered word.  */
454       if (addreg0)
455         output_asm_insn ("add $2,%0", &addreg0);
456       if (addreg1)
457         output_asm_insn ("add $2,%0", &addreg1);
458
459       /* Do that word.  */
460       output_asm_insn (singlemove_string (latehalf), latehalf);
461
462       /* Undo the adds we just did.  */
463       if (addreg0)
464         output_asm_insn ("sub $2,%0", &addreg0);
465       if (addreg1)
466         output_asm_insn ("sub $2,%0", &addreg1);
467
468       /* Do low-numbered word.  */
469       return singlemove_string (operands);
470     }
471
472   /* Normal case: do the two words, low-numbered first.  */
473
474   output_asm_insn (singlemove_string (operands), operands);
475
476   /* Make any unoffsettable addresses point at high-numbered word.  */
477   if (addreg0)
478     output_asm_insn ("add $2,%0", &addreg0);
479   if (addreg1)
480     output_asm_insn ("add $2,%0", &addreg1);
481
482   /* Do that word.  */
483   output_asm_insn (singlemove_string (latehalf), latehalf);
484
485   /* Undo the adds we just did.  */
486   if (addreg0)
487     output_asm_insn ("sub $2,%0", &addreg0);
488   if (addreg1)
489     output_asm_insn ("sub $2,%0", &addreg1);
490
491   return "";
492 }
493 /* Output assembler code to perform a quadword move insn
494    with operands OPERANDS.  */
495
496 char *
497 output_move_quad (operands)
498      rtx *operands;
499 {
500   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
501   rtx latehalf[2];
502   rtx addreg0 = 0, addreg1 = 0;
503
504   output_asm_insn(";; movdi/df: %1 -> %0", operands);
505   
506   if (REG_P (operands[0]))
507     optype0 = REGOP;
508   else if (offsettable_memref_p (operands[0]))
509     optype0 = OFFSOP;
510   else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
511     optype0 = POPOP;
512   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
513     optype0 = PUSHOP;
514   else if (GET_CODE (operands[0]) == MEM)
515     optype0 = MEMOP;
516   else
517     optype0 = RNDOP;
518
519   if (REG_P (operands[1]))
520     optype1 = REGOP;
521   else if (CONSTANT_P (operands[1])
522            || GET_CODE (operands[1]) == CONST_DOUBLE)
523     optype1 = CNSTOP;
524   else if (offsettable_memref_p (operands[1]))
525     optype1 = OFFSOP;
526   else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
527     optype1 = POPOP;
528   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
529     optype1 = PUSHOP;
530   else if (GET_CODE (operands[1]) == MEM)
531     optype1 = MEMOP;
532   else
533     optype1 = RNDOP;
534
535   /* Check for the cases that the operand constraints are not
536      supposed to allow to happen.  Abort if we get one,
537      because generating code for these cases is painful.  */
538
539   if (optype0 == RNDOP || optype1 == RNDOP)
540     abort ();
541   
542   /* check if we move a CPU reg to an FPU reg, or vice versa! */
543   if (optype0 == REGOP && optype1 == REGOP)
544       /* bogus - 64 bit cannot reside in CPU! */
545       if (CPU_REG_P(REGNO(operands[0]))
546           || CPU_REG_P (REGNO(operands[1])))
547           abort();
548   
549   if (optype0 == REGOP || optype1 == REGOP)
550   {
551       /* check for use of clrd???? 
552          if you ever allow ac4 and ac5 (now we require secondary load) 
553          you must check whether 
554          you want to load into them or store from them - 
555          then dump ac0 into $help$ movce ac4/5 to ac0, do the 
556          store from ac0, and restore ac0 - if you can find 
557          an unused ac[0-3], use that and you save a store and a load!*/
558
559       if (FPU_REG_P(REGNO(operands[0])))
560       {
561           if (GET_CODE(operands[1]) == CONST_DOUBLE)
562           {
563               union { double d; int i[2]; } u;
564               u.i[0] = CONST_DOUBLE_LOW (operands[1]); 
565               u.i[1] = CONST_DOUBLE_HIGH (operands[1]); 
566               
567               if (u.d == 0.0)
568                   return "clrd %0";
569           }
570               
571           return "ldd %1, %0";
572       }
573       
574       if (FPU_REG_P(REGNO(operands[1])))
575           return "std %1, %0";
576   }
577       
578   /* If one operand is decrementing and one is incrementing
579      decrement the former register explicitly
580      and change that operand into ordinary indexing.  */
581
582   if (optype0 == PUSHOP && optype1 == POPOP)
583     {
584       operands[0] = XEXP (XEXP (operands[0], 0), 0);
585       output_asm_insn ("sub $8,%0", operands);
586       operands[0] = gen_rtx (MEM, DImode, operands[0]);
587       optype0 = OFFSOP;
588     }
589   if (optype0 == POPOP && optype1 == PUSHOP)
590     {
591       operands[1] = XEXP (XEXP (operands[1], 0), 0);
592       output_asm_insn ("sub $8,%1", operands);
593       operands[1] = gen_rtx (MEM, SImode, operands[1]);
594       optype1 = OFFSOP;
595     }
596
597   /* If an operand is an unoffsettable memory ref, find a register
598      we can increment temporarily to make it refer to the second word.  */
599
600   if (optype0 == MEMOP)
601     addreg0 = find_addr_reg (XEXP (operands[0], 0));
602
603   if (optype1 == MEMOP)
604     addreg1 = find_addr_reg (XEXP (operands[1], 0));
605
606   /* Ok, we can do one word at a time.
607      Normally we do the low-numbered word first,
608      but if either operand is autodecrementing then we
609      do the high-numbered word first.
610
611      In either case, set up in LATEHALF the operands to use
612      for the high-numbered word and in some cases alter the
613      operands in OPERANDS to be suitable for the low-numbered word.  */
614
615   if (optype0 == REGOP)
616     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 2);
617   else if (optype0 == OFFSOP)
618     latehalf[0] = adj_offsettable_operand (operands[0], 4);
619   else
620     latehalf[0] = operands[0];
621
622   if (optype1 == REGOP)
623     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 2);
624   else if (optype1 == OFFSOP)
625     latehalf[1] = adj_offsettable_operand (operands[1], 4);
626   else if (optype1 == CNSTOP)
627     {
628       if (GET_CODE (operands[1]) == CONST_DOUBLE)
629         {
630             /* floats only. not yet supported!
631
632              -- compute it into PDP float format, - internally,
633              just use IEEE and ignore possible problems ;-)
634
635              we might get away with it !!!! */
636
637             abort();
638             
639 #ifndef HOST_WORDS_BIG_ENDIAN
640           latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
641                                  CONST_DOUBLE_LOW (operands[1]));
642           operands[1] = gen_rtx (CONST_INT, VOIDmode,
643                                  CONST_DOUBLE_HIGH (operands[1]));
644 #else /* HOST_WORDS_BIG_ENDIAN */
645           latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
646                                  CONST_DOUBLE_HIGH (operands[1]));
647           operands[1] = gen_rtx (CONST_INT, VOIDmode,
648                                  CONST_DOUBLE_LOW (operands[1]));
649 #endif /* HOST_WORDS_BIG_ENDIAN */
650         }
651     }
652   else
653     latehalf[1] = operands[1];
654
655   /* If insn is effectively movd N(sp),-(sp) then we will do the
656      high word first.  We should use the adjusted operand 1 (which is N+4(sp))
657      for the low word as well, to compensate for the first decrement of sp.  */
658   if (optype0 == PUSHOP
659       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
660       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
661     operands[1] = latehalf[1];
662
663   /* If one or both operands autodecrementing,
664      do the two words, high-numbered first.  */
665
666   /* Likewise,  the first move would clobber the source of the second one,
667      do them in the other order.  This happens only for registers;
668      such overlap can't happen in memory unless the user explicitly
669      sets it up, and that is an undefined circumstance.  */
670
671   if (optype0 == PUSHOP || optype1 == PUSHOP
672       || (optype0 == REGOP && optype1 == REGOP
673           && REGNO (operands[0]) == REGNO (latehalf[1])))
674     {
675       /* Make any unoffsettable addresses point at high-numbered word.  */
676       if (addreg0)
677         output_asm_insn ("add $4,%0", &addreg0);
678       if (addreg1)
679         output_asm_insn ("add $4,%0", &addreg1);
680
681       /* Do that word.  */
682       output_asm_insn(output_move_double(latehalf), latehalf);
683
684       /* Undo the adds we just did.  */
685       if (addreg0)
686         output_asm_insn ("sub $4,%0", &addreg0);
687       if (addreg1)
688         output_asm_insn ("sub $4,%0", &addreg1);
689
690       /* Do low-numbered word.  */
691       return output_move_double (operands);
692     }
693
694   /* Normal case: do the two words, low-numbered first.  */
695
696   output_asm_insn (output_move_double (operands), operands);
697
698   /* Make any unoffsettable addresses point at high-numbered word.  */
699   if (addreg0)
700     output_asm_insn ("add $4,%0", &addreg0);
701   if (addreg1)
702     output_asm_insn ("add $4,%0", &addreg1);
703
704   /* Do that word.  */
705   output_asm_insn (output_move_double (latehalf), latehalf);
706
707   /* Undo the adds we just did.  */
708   if (addreg0)
709     output_asm_insn ("sub $4,%0", &addreg0);
710   if (addreg1)
711     output_asm_insn ("sub $4,%0", &addreg1);
712
713   return "";
714 }
715
716 \f
717 /* Return a REG that occurs in ADDR with coefficient 1.
718    ADDR can be effectively incremented by incrementing REG.  */
719
720 static rtx
721 find_addr_reg (addr)
722      rtx addr;
723 {
724   while (GET_CODE (addr) == PLUS)
725     {
726       if (GET_CODE (XEXP (addr, 0)) == REG)
727         addr = XEXP (addr, 0);
728       if (GET_CODE (XEXP (addr, 1)) == REG)
729         addr = XEXP (addr, 1);
730       if (CONSTANT_P (XEXP (addr, 0)))
731         addr = XEXP (addr, 1);
732       if (CONSTANT_P (XEXP (addr, 1)))
733         addr = XEXP (addr, 0);
734     }
735   if (GET_CODE (addr) == REG)
736     return addr;
737   return 0;
738 }
739 \f
740 /* Output an ascii string.  */
741 output_ascii (file, p, size)
742      FILE *file;
743      char *p;
744      int size;
745 {
746   int i;
747
748   fprintf (file, "\t.byte \"");
749
750   for (i = 0; i < size; i++)
751     {
752       register int c = p[i];
753       if (c == '\"' || c == '\\')
754         putc ('\\', file);
755       if (c >= ' ' && c < 0177)
756         putc (c, file);
757       else
758         {
759           fprintf (file, "\\%03o", c);
760           /* After an octal-escape, if a digit follows,
761              terminate one string constant and start another.
762              The Vax assembler fails to stop reading the escape
763              after three digits, so this is the only way we
764              can get it to parse the data properly.  */
765           if (i < size - 1 && p[i + 1] >= '0' && p[i + 1] <= '9')
766             fprintf (file, "\"\n\tstring \"");
767         }
768     }
769   fprintf (file, "\"\n");
770 }
771
772
773 /* --- stole from out-vax, needs changes */
774
775 print_operand_address (file, addr)
776      FILE *file;
777      register rtx addr;
778 {
779   register rtx reg1, reg2, breg, ireg;
780   rtx offset;
781
782  retry:
783
784   switch (GET_CODE (addr))
785     {
786     case MEM:
787       fprintf (file, "@");
788       addr = XEXP (addr, 0);
789       goto retry;
790
791     case REG:
792       fprintf (file, "(%s)", reg_names[REGNO (addr)]);
793       break;
794
795     case PRE_DEC:
796       fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]);
797       break;
798
799     case POST_INC:
800       fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]);
801       break;
802
803     case PLUS:
804       reg1 = 0; reg2 = 0;
805       ireg = 0; breg = 0;
806       offset = 0;
807       if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
808           || GET_CODE (XEXP (addr, 0)) == MEM)
809         {
810           offset = XEXP (addr, 0);
811           addr = XEXP (addr, 1);
812         }
813       else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
814                || GET_CODE (XEXP (addr, 1)) == MEM)
815         {
816           offset = XEXP (addr, 1);
817           addr = XEXP (addr, 0);
818         }
819       if (GET_CODE (addr) != PLUS)
820         ;
821       else if (GET_CODE (XEXP (addr, 0)) == MULT)
822         {
823           reg1 = XEXP (addr, 0);
824           addr = XEXP (addr, 1);
825         }
826       else if (GET_CODE (XEXP (addr, 1)) == MULT)
827         {
828           reg1 = XEXP (addr, 1);
829           addr = XEXP (addr, 0);
830         }
831       else if (GET_CODE (XEXP (addr, 0)) == REG)
832         {
833           reg1 = XEXP (addr, 0);
834           addr = XEXP (addr, 1);
835         }
836       else if (GET_CODE (XEXP (addr, 1)) == REG)
837         {
838           reg1 = XEXP (addr, 1);
839           addr = XEXP (addr, 0);
840         }
841       if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
842         {
843           if (reg1 == 0)
844             reg1 = addr;
845           else
846             reg2 = addr;
847           addr = 0;
848         }
849       if (offset != 0)
850         {
851           if (addr != 0) abort ();
852           addr = offset;
853         }
854       if (reg1 != 0 && GET_CODE (reg1) == MULT)
855         {
856           breg = reg2;
857           ireg = reg1;
858         }
859       else if (reg2 != 0 && GET_CODE (reg2) == MULT)
860         {
861           breg = reg1;
862           ireg = reg2;
863         }
864       else if (reg2 != 0 || GET_CODE (addr) == MEM)
865         {
866           breg = reg2;
867           ireg = reg1;
868         }
869       else
870         {
871           breg = reg1;
872           ireg = reg2;
873         }
874       if (addr != 0)
875         output_address (addr);
876       if (breg != 0)
877         {
878           if (GET_CODE (breg) != REG)
879             abort ();
880           fprintf (file, "(%s)", reg_names[REGNO (breg)]);
881         }
882       if (ireg != 0)
883         {
884           if (GET_CODE (ireg) == MULT)
885             ireg = XEXP (ireg, 0);
886           if (GET_CODE (ireg) != REG)
887             abort ();
888           abort();
889           fprintf (file, "[%s]", reg_names[REGNO (ireg)]);
890         }
891       break;
892
893     default:
894       output_addr_const (file, addr);
895     }
896 }
897
898 /* register move costs, indexed by regs */
899
900 static int move_costs[N_REG_CLASSES][N_REG_CLASSES] = 
901 {
902              /* NO  MUL  GEN  LFPU  NLFPU FPU ALL */
903
904 /* NO */     {  0,   0,   0,    0,    0,    0,   0},
905 /* MUL */    {  0,   2,   2,   10,   22,   22,  22},
906 /* GEN */    {  0,   2,   2,   10,   22,   22,  22},
907 /* LFPU */   {  0,  10,  10,    2,    2,    2,  10},
908 /* NLFPU */  {  0,  22,  22,    2,    2,    2,  22},
909 /* FPU */    {  0,  22,  22,    2,    2,    2,  22},
910 /* ALL */    {  0,  22,  22,   10,   22,   22,  22}
911 }  ;
912
913
914 /* -- note that some moves are tremendously expensive, 
915    because they require lots of tricks! do we have to 
916    charge the costs incurred by secondary reload class 
917    -- as we do here with 22 -- or not ? */
918
919 int 
920 register_move_cost(c1, c2)
921   enum reg_class c1, c2;
922 {
923     return move_costs[(int)c1][(int)c2];
924 }
925
926 char *
927 output_jump(pos, neg, length)
928   int length;
929   char *pos, *neg;
930 {
931     static int x = 0;
932     
933     static char buf[1000];
934
935 #if 0
936 /* currently we don't need this, because the tstdf and cmpdf 
937    copy the condition code immediately, and other float operations are not 
938    yet recognized as changing the FCC - if so, then the length-cost of all
939    jump insns increases by one, because we have to potentially copy the 
940    FCC! */
941     if (cc_status.flags & CC_IN_FPU)
942         output_asm_insn("cfcc", NULL);
943 #endif
944         
945     switch (length)
946     {
947       case 1:
948         
949         strcpy(buf, pos);
950         strcat(buf, " %l0");
951         
952         return buf;
953         
954       case 3:
955         
956         sprintf(buf, "%s JMP_%d\n\tjmp %%l0\nJMP_%d:", neg, x, x);
957         
958         x++;
959         
960         return buf;
961         
962       default:
963         
964         abort();
965     }
966     
967 }
968
969 void
970 notice_update_cc_on_set(exp, insn)
971   rtx exp;
972   rtx insn;
973 {
974     if (GET_CODE (SET_DEST (exp)) == CC0)
975     { 
976         cc_status.flags = 0;                                    
977         cc_status.value1 = SET_DEST (exp);                      
978         cc_status.value2 = SET_SRC (exp);                       
979
980 /*
981         if (GET_MODE(SET_SRC(exp)) == DFmode)
982             cc_status.flags |= CC_IN_FPU;
983 */      
984     }                                                   
985     else if ((GET_CODE (SET_DEST (exp)) == REG          
986               || GET_CODE (SET_DEST (exp)) == MEM)              
987              && GET_CODE (SET_SRC (exp)) != PC          
988              && (GET_MODE (SET_DEST(exp)) == HImode             
989                  || GET_MODE (SET_DEST(exp)) == QImode) 
990                 && (GET_CODE (SET_SRC(exp)) == PLUS             
991                     || GET_CODE (SET_SRC(exp)) == MINUS 
992                     || GET_CODE (SET_SRC(exp)) == AND   
993                     || GET_CODE (SET_SRC(exp)) == IOR   
994                     || GET_CODE (SET_SRC(exp)) == XOR   
995                     || GET_CODE (SET_SRC(exp)) == NOT   
996                     || GET_CODE (SET_SRC(exp)) == NEG   
997                         || GET_CODE (SET_SRC(exp)) == REG       
998                     || GET_CODE (SET_SRC(exp)) == MEM)) 
999     { 
1000         cc_status.flags = 0;                                    
1001         cc_status.value1 = SET_SRC (exp);                       
1002         cc_status.value2 = SET_DEST (exp);                      
1003         
1004         if (cc_status.value1 && GET_CODE (cc_status.value1) == REG      
1005             && cc_status.value2                                 
1006             && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
1007             cc_status.value2 = 0;                                       
1008         if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM      
1009             && cc_status.value2                                 
1010             && GET_CODE (cc_status.value2) == MEM)                      
1011             cc_status.value2 = 0;                                       
1012     }                                                   
1013     else if (GET_CODE (SET_SRC (exp)) == CALL)          
1014     { 
1015         CC_STATUS_INIT; 
1016     }
1017     else if (GET_CODE (SET_DEST (exp)) == REG)                  
1018         /* what's this ? */                                     
1019     { 
1020         if ((cc_status.value1                                   
1021              && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1)))
1022             cc_status.value1 = 0;                               
1023         if ((cc_status.value2                                   
1024              && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2)))
1025             cc_status.value2 = 0;                               
1026     }                                                   
1027     else if (SET_DEST(exp) == pc_rtx)
1028     { 
1029         /* jump */
1030     }
1031     else /* if (GET_CODE (SET_DEST (exp)) == MEM)       */      
1032     {  
1033         /* the last else is a bit paranoiac, but since nearly all instructions 
1034            play with condition codes, it's reasonable! */
1035
1036         CC_STATUS_INIT; /* paranoia*/ 
1037     }                   
1038 }
1039
1040
1041 int simple_memory_operand(op, mode)
1042   rtx op;
1043   enum machine_mode mode;
1044 {
1045     rtx addr, plus0, plus1;
1046     int offset = 0;
1047
1048     /* Eliminate non-memory operations */
1049     if (GET_CODE (op) != MEM)
1050         return FALSE;
1051
1052 #if 0
1053     /* dword operations really put out 2 instructions, so eliminate them.  */
1054     if (GET_MODE_SIZE (GET_MODE (op)) > (HAVE_64BIT_P () ? 8 : 4))
1055         return FALSE;
1056 #endif
1057
1058     /* Decode the address now.  */
1059
1060   indirection:
1061     
1062     addr = XEXP (op, 0);
1063
1064     switch (GET_CODE (addr))
1065     {
1066       case REG:
1067         /* (R0) - no extra cost */
1068         return 1;
1069         
1070       case PRE_DEC:
1071       case POST_INC:
1072         /* -(R0), (R0)+ - cheap! */
1073         return 0;
1074         
1075       case MEM:
1076         /* cheap - is encoded in addressing mode info! 
1077
1078            -- except for @(R0), which has to be @0(R0) !!! */
1079
1080         if (GET_CODE (XEXP (addr, 0)) == REG)
1081             return 0;
1082         
1083         op=addr;
1084         goto indirection;
1085         
1086       case CONST_INT:
1087       case LABEL_REF:          
1088       case CONST:
1089       case SYMBOL_REF:
1090         /* @#address - extra cost */
1091         return 0;
1092
1093       case PLUS:
1094         /* X(R0) - extra cost */
1095         return 0;
1096     }
1097     
1098     return FALSE;
1099 }
1100
1101
1102 /*
1103  * output a block move:
1104  *
1105  * operands[0]  ... to
1106  * operands[1]  ... from
1107  * operands[2]  ... length
1108  * operands[3]  ... alignment
1109  * operands[4]  ... scratch register
1110  */
1111
1112  
1113 char *
1114 output_block_move(operands)
1115   rtx *operands;
1116 {
1117     static int count = 0;
1118     char buf[200];
1119     
1120     if (GET_CODE(operands[2]) == CONST_INT
1121         && TARGET_TIME)
1122     {
1123         if (INTVAL(operands[2]) < 16
1124             && INTVAL(operands[3]) == 1)
1125         {
1126             register int i;
1127             
1128             for (i = 1; i <= INTVAL(operands[2]); i++)
1129                 output_asm_insn("movb (%1)+, (%0)+", operands);
1130
1131             return "";
1132         }
1133         else if (INTVAL(operands[2]) < 32)
1134         {
1135             register int i;
1136             
1137             for (i = 1; i <= INTVAL(operands[2])/2; i++)
1138                 output_asm_insn("mov (%1)+, (%0)+", operands);
1139             
1140             /* may I assume that moved quantity is 
1141                multiple of alignment ???
1142
1143                I HOPE SO !
1144             */
1145
1146             return "";
1147         }
1148         
1149
1150         /* can do other clever things, maybe... */
1151     }
1152
1153     if (CONSTANT_P(operands[2]) )
1154     {
1155         /* just move count to scratch */
1156         output_asm_insn("mov %2, %4", operands);
1157     }
1158     else
1159     {
1160         /* just clobber the register */
1161         operands[4] = operands[2];
1162     }
1163     
1164
1165     /* switch over alignment */
1166     switch (INTVAL(operands[3]))
1167     {
1168       case 1:
1169         
1170         /* 
1171           x:
1172           movb (%1)+, (%0)+
1173           
1174           if (TARGET_45)
1175              sob %4,x
1176           else
1177              dec %4
1178              bgt x
1179
1180         */
1181
1182         sprintf(buf, "\nmovestrhi%d:", count);
1183         output_asm_insn(buf, NULL);
1184         
1185         output_asm_insn("movb (%1)+, (%0)+", operands);
1186         
1187         if (TARGET_45)
1188         {
1189             sprintf(buf, "sob %%4, movestrhi%d", count);
1190             output_asm_insn(buf, operands);
1191         }
1192         else
1193         {
1194             output_asm_insn("dec %4", operands);
1195             
1196             sprintf(buf, "bgt movestrhi%d", count);
1197             output_asm_insn(buf, NULL);
1198         }
1199         
1200         count ++;
1201         break;
1202         
1203       case 2:
1204         
1205         /* 
1206            asr %4
1207
1208            x:
1209
1210            mov (%1)+, (%0)+
1211
1212            if (TARGET_45)
1213              sob %4, x
1214            else
1215              dec %4
1216              bgt x
1217         */
1218
1219       generate_compact_code:
1220
1221         output_asm_insn("asr %4", operands);
1222
1223         sprintf(buf, "\nmovestrhi%d:", count);
1224         output_asm_insn(buf, NULL);
1225         
1226         output_asm_insn("mov (%1)+, (%0)+", operands);
1227         
1228         if (TARGET_45)
1229         {
1230             sprintf(buf, "sob %%4, movestrhi%d", count);
1231             output_asm_insn(buf, operands);
1232         }
1233         else
1234         {
1235             output_asm_insn("dec %4", operands);
1236             
1237             sprintf(buf, "bgt movestrhi%d", count);
1238             output_asm_insn(buf, NULL);
1239         }
1240         
1241         count ++;
1242         break;
1243
1244       case 4:
1245         
1246         /*
1247
1248            asr %4
1249            asr %4
1250
1251            x:
1252
1253            mov (%1)+, (%0)+
1254            mov (%1)+, (%0)+
1255
1256            if (TARGET_45)
1257              sob %4, x
1258            else
1259              dec %4
1260              bgt x
1261         */
1262
1263         if (TARGET_SPACE)
1264             goto generate_compact_code;
1265         
1266         output_asm_insn("asr %4", operands);
1267         output_asm_insn("asr %4", operands);
1268
1269         sprintf(buf, "\nmovestrhi%d:", count);
1270         output_asm_insn(buf, NULL);
1271         
1272         output_asm_insn("mov (%1)+, (%0)+", operands);
1273         output_asm_insn("mov (%1)+, (%0)+", operands);
1274         
1275         if (TARGET_45)
1276         {
1277             sprintf(buf, "sob %%4, movestrhi%d", count);
1278             output_asm_insn(buf, operands);
1279         }
1280         else
1281         {
1282             output_asm_insn("dec %4", operands);
1283             
1284             sprintf(buf, "bgt movestrhi%d", count);
1285             output_asm_insn(buf, NULL);
1286         }
1287         
1288         count ++;
1289         break;
1290        
1291       default:
1292         
1293         /*
1294            
1295            asr %4
1296            asr %4
1297            asr %4
1298
1299            x:
1300
1301            mov (%1)+, (%0)+
1302            mov (%1)+, (%0)+
1303            mov (%1)+, (%0)+
1304            mov (%1)+, (%0)+
1305            
1306            if (TARGET_45)
1307              sob %4, x
1308            else
1309              dec %4
1310              bgt x
1311         */
1312
1313
1314         if (TARGET_SPACE)
1315             goto generate_compact_code;
1316         
1317         output_asm_insn("asr %4", operands);
1318         output_asm_insn("asr %4", operands);
1319         output_asm_insn("asr %4", operands);
1320
1321         sprintf(buf, "\nmovestrhi%d:", count);
1322         output_asm_insn(buf, NULL);
1323         
1324         output_asm_insn("mov (%1)+, (%0)+", operands);
1325         output_asm_insn("mov (%1)+, (%0)+", operands);
1326         output_asm_insn("mov (%1)+, (%0)+", operands);
1327         output_asm_insn("mov (%1)+, (%0)+", operands);
1328         
1329         if (TARGET_45)
1330         {
1331             sprintf(buf, "sob %%4, movestrhi%d", count);
1332             output_asm_insn(buf, operands);
1333         }
1334         else
1335         {
1336             output_asm_insn("dec %4", operands);
1337             
1338             sprintf(buf, "bgt movestrhi%d", count);
1339             output_asm_insn(buf, NULL);
1340         }
1341         
1342         count ++;
1343         break;
1344         
1345         ;
1346         
1347     }
1348     
1349     return "";
1350 }
1351
1352 /* for future use */
1353 int
1354 comparison_operator_index(op)
1355   rtx op;
1356 {
1357     switch (GET_CODE(op))
1358     {
1359       case NE:
1360         return 0;
1361         
1362       case EQ:
1363         return 1;
1364         
1365       case GE:
1366         return 2;
1367         
1368       case GT:
1369         return 3;
1370         
1371       case LE:
1372         return 4;
1373         
1374       case LT:
1375         return 5;
1376         
1377       case GEU:
1378         return 6;
1379         
1380       case GTU:
1381         return 7;
1382
1383       case LEU:
1384         return 8;
1385         
1386       case LTU:
1387         return 9;
1388         
1389       default:
1390         return -1;
1391     }
1392 }    
1393         
1394 /* tests whether the rtx is a comparison operator */
1395 int
1396 comp_operator (op, mode)
1397   rtx op;
1398   enum machine_mode mode;
1399 {
1400     return comparison_operator_index(op) >= 0;
1401 }
1402
1403     
1404 int
1405 legitimate_address_p (mode, address)
1406   enum machine_mode mode;
1407   rtx address;
1408 {
1409 /* #define REG_OK_STRICT */
1410     GO_IF_LEGITIMATE_ADDRESS(mode, address, win);
1411     
1412     return 0;
1413     
1414   win:
1415     return 1;
1416
1417 /* #undef REG_OK_STRICT */
1418 }