OSDN Git Service

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