OSDN Git Service

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