OSDN Git Service

9c2def4c3a1a225b9fd9fadc8fa2e4b7f782c6ff
[pf3gnuchains/gcc-fork.git] / gcc / config / pdp11 / pdp11.c
1 /* Subroutines for gcc2 for pdp11.
2    Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2001, 2004
3    Free Software Foundation, Inc.
4    Contributed by Michael K. Gschwind (mike@vlsivie.tuwien.ac.at).
5
6 This file is part of GCC.
7
8 GCC is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12
13 GCC is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING.  If not, write to
20 the Free Software Foundation, 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.  */
22
23 #include "config.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "tm.h"
27 #include "rtl.h"
28 #include "regs.h"
29 #include "hard-reg-set.h"
30 #include "real.h"
31 #include "insn-config.h"
32 #include "conditions.h"
33 #include "function.h"
34 #include "output.h"
35 #include "insn-attr.h"
36 #include "flags.h"
37 #include "recog.h"
38 #include "tree.h"
39 #include "expr.h"
40 #include "toplev.h"
41 #include "tm_p.h"
42 #include "target.h"
43 #include "target-def.h"
44
45 /*
46 #define FPU_REG_P(X)    ((X)>=8 && (X)<14)
47 #define CPU_REG_P(X)    ((X)>=0 && (X)<8)
48 */
49
50 /* this is the current value returned by the macro FIRST_PARM_OFFSET 
51    defined in tm.h */
52 int current_first_parm_offset;
53
54 /* Routines to encode/decode pdp11 floats */
55 static void encode_pdp11_f (const struct real_format *fmt,
56                             long *, const REAL_VALUE_TYPE *);
57 static void decode_pdp11_f (const struct real_format *,
58                             REAL_VALUE_TYPE *, const long *);
59 static void encode_pdp11_d (const struct real_format *fmt,
60                             long *, const REAL_VALUE_TYPE *);
61 static void decode_pdp11_d (const struct real_format *,
62                             REAL_VALUE_TYPE *, const long *);
63
64 /* These two are taken from the corresponding vax descriptors
65    in real.c, changing only the encode/decode routine pointers.  */
66 const struct real_format pdp11_f_format =
67   {
68     encode_pdp11_f,
69     decode_pdp11_f,
70     2,
71     1,
72     24,
73     24,
74     -127,
75     127,
76     15,
77     false,
78     false,
79     false,
80     false,
81     false
82   };
83
84 const struct real_format pdp11_d_format =
85   {
86     encode_pdp11_d,
87     decode_pdp11_d,
88     2,
89     1,
90     56,
91     56,
92     -127,
93     127,
94     15,
95     false,
96     false,
97     false,
98     false,
99     false
100   };
101
102 static void
103 encode_pdp11_f (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf,
104                 const REAL_VALUE_TYPE *r)
105 {
106   (*vax_f_format.encode) (fmt, buf, r);
107   buf[0] = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16);
108 }
109
110 static void
111 decode_pdp11_f (const struct real_format *fmt ATTRIBUTE_UNUSED,
112                 REAL_VALUE_TYPE *r, const long *buf)
113 {
114   long tbuf;
115   tbuf = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16);
116   (*vax_f_format.decode) (fmt, r, &tbuf);
117 }
118
119 static void
120 encode_pdp11_d (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf,
121                 const REAL_VALUE_TYPE *r)
122 {
123   (*vax_d_format.encode) (fmt, buf, r);
124   buf[0] = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16);
125   buf[1] = ((buf[1] >> 16) & 0xffff) | ((buf[1] & 0xffff) << 16);
126 }
127
128 static void
129 decode_pdp11_d (const struct real_format *fmt ATTRIBUTE_UNUSED,
130                 REAL_VALUE_TYPE *r, const long *buf)
131 {
132   long tbuf[2];
133   tbuf[0] = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16);
134   tbuf[1] = ((buf[1] >> 16) & 0xffff) | ((buf[1] & 0xffff) << 16);
135   (*vax_d_format.decode) (fmt, r, tbuf);
136 }
137
138 /* This is where the condition code register lives.  */
139 /* rtx cc0_reg_rtx; - no longer needed? */
140
141 static rtx find_addr_reg (rtx); 
142 static const char *singlemove_string (rtx *);
143 static bool pdp11_assemble_integer (rtx, unsigned int, int);
144 static void pdp11_output_function_prologue (FILE *, HOST_WIDE_INT);
145 static void pdp11_output_function_epilogue (FILE *, HOST_WIDE_INT);
146 static bool pdp11_rtx_costs (rtx, int, int, int *);
147 static bool pdp11_return_in_memory (tree, tree);
148 \f
149 /* Initialize the GCC target structure.  */
150 #undef TARGET_ASM_BYTE_OP
151 #define TARGET_ASM_BYTE_OP NULL
152 #undef TARGET_ASM_ALIGNED_HI_OP
153 #define TARGET_ASM_ALIGNED_HI_OP NULL
154 #undef TARGET_ASM_ALIGNED_SI_OP
155 #define TARGET_ASM_ALIGNED_SI_OP NULL
156 #undef TARGET_ASM_INTEGER
157 #define TARGET_ASM_INTEGER pdp11_assemble_integer
158
159 #undef TARGET_ASM_FUNCTION_PROLOGUE
160 #define TARGET_ASM_FUNCTION_PROLOGUE pdp11_output_function_prologue
161 #undef TARGET_ASM_FUNCTION_EPILOGUE
162 #define TARGET_ASM_FUNCTION_EPILOGUE pdp11_output_function_epilogue
163
164 #undef TARGET_ASM_OPEN_PAREN
165 #define TARGET_ASM_OPEN_PAREN "["
166 #undef TARGET_ASM_CLOSE_PAREN
167 #define TARGET_ASM_CLOSE_PAREN "]"
168
169 #undef TARGET_RTX_COSTS
170 #define TARGET_RTX_COSTS pdp11_rtx_costs
171
172 #undef TARGET_RETURN_IN_MEMORY
173 #define TARGET_RETURN_IN_MEMORY pdp11_return_in_memory
174
175 struct gcc_target targetm = TARGET_INITIALIZER;
176 \f
177 /* Nonzero if OP is a valid second operand for an arithmetic insn.  */
178
179 int
180 arith_operand (rtx op, enum machine_mode mode)
181 {
182   return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
183 }
184
185 int
186 const_immediate_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
187 {
188   return (GET_CODE (op) == CONST_INT);
189 }
190
191 int 
192 immediate15_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
193 {
194     return (GET_CODE (op) == CONST_INT && ((INTVAL (op) & 0x8000) == 0x0000));
195 }
196
197 int
198 expand_shift_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
199 {
200     return (GET_CODE (op) == CONST_INT 
201             && abs (INTVAL(op)) > 1 
202             && abs (INTVAL(op)) <= 4);
203 }
204
205 /*
206    stream is a stdio stream to output the code to.
207    size is an int: how many units of temporary storage to allocate.
208    Refer to the array `regs_ever_live' to determine which registers
209    to save; `regs_ever_live[I]' is nonzero if register number I
210    is ever used in the function.  This macro is responsible for
211    knowing which registers should not be saved even if used.  
212 */
213
214 #ifdef TWO_BSD
215
216 static void
217 pdp11_output_function_prologue (FILE *stream, HOST_WIDE_INT size)
218 {                                                              
219   fprintf (stream, "\tjsr       r5, csv\n");
220   if (size)
221     {
222       fprintf (stream, "\t/*abuse empty parameter slot for locals!*/\n");
223       if (size > 2)
224         fprintf(stream, "\tsub $%#o, sp\n", size - 2);
225
226     }
227 }
228
229 #else  /* !TWO_BSD */
230
231 static void
232 pdp11_output_function_prologue (FILE *stream, HOST_WIDE_INT size)
233 {                                                              
234     HOST_WIDE_INT fsize = ((size) + 1) & ~1;
235     int regno;
236     int via_ac = -1;
237
238     fprintf (stream,
239              "\n\t;     /* function prologue %s*/\n",
240              current_function_name ());
241
242     /* if we are outputting code for main, 
243        the switch FPU to right mode if TARGET_FPU */
244     if (MAIN_NAME_P (DECL_NAME (current_function_decl)) && TARGET_FPU)
245     {
246         fprintf(stream,
247                 "\t;/* switch cpu to double float, single integer */\n");
248         fprintf(stream, "\tsetd\n");
249         fprintf(stream, "\tseti\n\n");
250     }
251     
252     if (frame_pointer_needed)                                   
253     {                                                           
254         fprintf(stream, "\tmov r5, -(sp)\n");                   
255         fprintf(stream, "\tmov sp, r5\n");                              
256     }                                                           
257     else                                                                
258     {                                                           
259         /* DON'T SAVE FP */
260     }                                                           
261
262     /* make frame */
263     if (fsize)                                                  
264         fprintf (stream, "\tsub $%#o, sp\n", fsize);                    
265
266     /* save CPU registers  */
267     for (regno = 0; regno < 8; regno++)                         
268         if (regs_ever_live[regno] && ! call_used_regs[regno])   
269             if (! ((regno == FRAME_POINTER_REGNUM)                      
270                    && frame_pointer_needed))                            
271                 fprintf (stream, "\tmov %s, -(sp)\n", reg_names[regno]);        
272     /* fpu regs saving */
273     
274     /* via_ac specifies the ac to use for saving ac4, ac5 */
275     via_ac = -1;
276     
277     for (regno = 8; regno < FIRST_PSEUDO_REGISTER ; regno++) 
278     {
279         /* ac0 - ac3 */                                         
280         if (LOAD_FPU_REG_P(regno)
281             && regs_ever_live[regno] 
282             && ! call_used_regs[regno])
283         {
284             fprintf (stream, "\tstd %s, -(sp)\n", reg_names[regno]);
285             via_ac = regno;
286         }
287         
288         /* maybe make ac4, ac5 call used regs?? */
289         /* ac4 - ac5 */
290         if (NO_LOAD_FPU_REG_P(regno)
291             && regs_ever_live[regno]
292             && ! call_used_regs[regno])
293         {
294             if (via_ac == -1)
295                 abort();
296             
297             fprintf (stream, "\tldd %s, %s\n", reg_names[regno], reg_names[via_ac]);
298             fprintf (stream, "\tstd %s, -(sp)\n", reg_names[via_ac]);
299         }
300     }
301
302     fprintf (stream, "\t;/* end of prologue */\n\n");           
303 }
304
305 #endif /* !TWO_BSD */
306
307 /*
308    The function epilogue should not depend on the current stack pointer!
309    It should use the frame pointer only.  This is mandatory because
310    of alloca; we also take advantage of it to omit stack adjustments
311    before returning.  */
312
313 /* maybe we can make leaf functions faster by switching to the
314    second register file - this way we don't have to save regs!
315    leaf functions are ~ 50% of all functions (dynamically!) 
316
317    set/clear bit 11 (dec. 2048) of status word for switching register files - 
318    but how can we do this? the pdp11/45 manual says bit may only 
319    be set (p.24), but not cleared!
320
321    switching to kernel is probably more expensive, so we'll leave it 
322    like this and not use the second set of registers... 
323
324    maybe as option if you want to generate code for kernel mode? */
325
326 #ifdef TWO_BSD
327
328 static void
329 pdp11_output_function_epilogue (FILE *stream,
330                                 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
331 {                                                               
332   fprintf (stream, "\t/* SP ignored by cret? */\n");
333   fprintf (stream, "\tjmp cret\n");
334 }
335
336 #else  /* !TWO_BSD */
337
338 static void
339 pdp11_output_function_epilogue (FILE *stream, HOST_WIDE_INT size)
340 {                                                               
341     HOST_WIDE_INT fsize = ((size) + 1) & ~1;
342     int i, j, k;
343
344     int via_ac;
345     
346     fprintf (stream, "\n\t;     /*function epilogue */\n");             
347
348     if (frame_pointer_needed)                                   
349     {                                                           
350         /* hope this is safe - m68k does it also .... */                
351         regs_ever_live[FRAME_POINTER_REGNUM] = 0;                       
352                                                                 
353         for (i =7, j = 0 ; i >= 0 ; i--)                                
354             if (regs_ever_live[i] && ! call_used_regs[i])               
355                 j++;
356         
357         /* remember # of pushed bytes for CPU regs */
358         k = 2*j;
359         
360         /* change fp -> r5 due to the compile error on libgcc2.c */
361         for (i =7 ; i >= 0 ; i--)                                       
362             if (regs_ever_live[i] && ! call_used_regs[i])               
363                 fprintf(stream, "\tmov %#o(r5), %s\n",(-fsize-2*j--)&0xffff, reg_names[i]);
364
365         /* get ACs */                                           
366         via_ac = FIRST_PSEUDO_REGISTER -1;
367         
368         for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
369             if (regs_ever_live[i] && ! call_used_regs[i])
370             {
371                 via_ac = i;
372                 k += 8;
373             }
374         
375         for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
376         {
377             if (LOAD_FPU_REG_P(i)
378                 && regs_ever_live[i]
379                 && ! call_used_regs[i])
380             {
381                 fprintf(stream, "\tldd %#o(r5), %s\n", (-fsize-k)&0xffff, reg_names[i]);
382                 k -= 8;
383             }
384             
385             if (NO_LOAD_FPU_REG_P(i)
386                 && regs_ever_live[i]
387                 && ! call_used_regs[i])
388             {
389                 if (! LOAD_FPU_REG_P(via_ac))
390                     abort();
391                     
392                 fprintf(stream, "\tldd %#o(r5), %s\n", (-fsize-k)&0xffff, reg_names[via_ac]);
393                 fprintf(stream, "\tstd %s, %s\n", reg_names[via_ac], reg_names[i]);
394                 k -= 8;
395             }
396         }
397         
398         fprintf(stream, "\tmov r5, sp\n");                              
399         fprintf (stream, "\tmov (sp)+, r5\n");                          
400     }                                                           
401     else                                                                
402     {              
403         via_ac = FIRST_PSEUDO_REGISTER -1;
404         
405         /* get ACs */
406         for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
407             if (regs_ever_live[i] && call_used_regs[i])
408                 via_ac = i;
409         
410         for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
411         {
412             if (LOAD_FPU_REG_P(i)
413                 && regs_ever_live[i]
414                 && ! call_used_regs[i])
415               fprintf(stream, "\tldd (sp)+, %s\n", reg_names[i]);
416             
417             if (NO_LOAD_FPU_REG_P(i)
418                 && regs_ever_live[i]
419                 && ! call_used_regs[i])
420             {
421                 if (! LOAD_FPU_REG_P(via_ac))
422                     abort();
423                     
424                 fprintf(stream, "\tldd (sp)+, %s\n", reg_names[via_ac]);
425                 fprintf(stream, "\tstd %s, %s\n", reg_names[via_ac], reg_names[i]);
426             }
427         }
428
429         for (i=7; i >= 0; i--)                                  
430             if (regs_ever_live[i] && !call_used_regs[i])                
431                 fprintf(stream, "\tmov (sp)+, %s\n", reg_names[i]);     
432                                                                 
433         if (fsize)                                              
434             fprintf((stream), "\tadd $%#o, sp\n", (fsize)&0xffff);                      
435     }                   
436                                         
437     fprintf (stream, "\trts pc\n");                                     
438     fprintf (stream, "\t;/* end of epilogue*/\n\n\n");          
439 }
440
441 #endif /* !TWO_BSD */
442         
443 /* Return the best assembler insn template
444    for moving operands[1] into operands[0] as a fullword.  */
445 static const char *
446 singlemove_string (rtx *operands)
447 {
448   if (operands[1] != const0_rtx)
449     return "mov %1,%0";
450
451   return "clr %0";
452 }
453
454 \f
455 /* Output assembler code to perform a doubleword move insn
456    with operands OPERANDS.  */
457
458 const char *
459 output_move_double (rtx *operands)
460 {
461   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
462   rtx latehalf[2];
463   rtx addreg0 = 0, addreg1 = 0;
464
465   /* First classify both operands.  */
466
467   if (REG_P (operands[0]))
468     optype0 = REGOP;
469   else if (offsettable_memref_p (operands[0]))
470     optype0 = OFFSOP;
471   else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
472     optype0 = POPOP;
473   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
474     optype0 = PUSHOP;
475   else if (GET_CODE (operands[0]) == MEM)
476     optype0 = MEMOP;
477   else
478     optype0 = RNDOP;
479
480   if (REG_P (operands[1]))
481     optype1 = REGOP;
482   else if (CONSTANT_P (operands[1])
483 #if 0
484            || GET_CODE (operands[1]) == CONST_DOUBLE
485 #endif
486            )
487     optype1 = CNSTOP;
488   else if (offsettable_memref_p (operands[1]))
489     optype1 = OFFSOP;
490   else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
491     optype1 = POPOP;
492   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
493     optype1 = PUSHOP;
494   else if (GET_CODE (operands[1]) == MEM)
495     optype1 = MEMOP;
496   else
497     optype1 = RNDOP;
498
499   /* Check for the cases that the operand constraints are not
500      supposed to allow to happen.  Abort if we get one,
501      because generating code for these cases is painful.  */
502
503   if (optype0 == RNDOP || optype1 == RNDOP)
504     abort ();
505
506   /* If one operand is decrementing and one is incrementing
507      decrement the former register explicitly
508      and change that operand into ordinary indexing.  */
509
510   if (optype0 == PUSHOP && optype1 == POPOP)
511     {
512       operands[0] = XEXP (XEXP (operands[0], 0), 0);
513       output_asm_insn ("sub $4,%0", operands);
514       operands[0] = gen_rtx_MEM (SImode, operands[0]);
515       optype0 = OFFSOP;
516     }
517   if (optype0 == POPOP && optype1 == PUSHOP)
518     {
519       operands[1] = XEXP (XEXP (operands[1], 0), 0);
520       output_asm_insn ("sub $4,%1", operands);
521       operands[1] = gen_rtx_MEM (SImode, operands[1]);
522       optype1 = OFFSOP;
523     }
524
525   /* If an operand is an unoffsettable memory ref, find a register
526      we can increment temporarily to make it refer to the second word.  */
527
528   if (optype0 == MEMOP)
529     addreg0 = find_addr_reg (XEXP (operands[0], 0));
530
531   if (optype1 == MEMOP)
532     addreg1 = find_addr_reg (XEXP (operands[1], 0));
533
534   /* Ok, we can do one word at a time.
535      Normally we do the low-numbered word first,
536      but if either operand is autodecrementing then we
537      do the high-numbered word first.
538
539      In either case, set up in LATEHALF the operands to use
540      for the high-numbered word and in some cases alter the
541      operands in OPERANDS to be suitable for the low-numbered word.  */
542
543   if (optype0 == REGOP)
544     latehalf[0] = gen_rtx_REG (HImode, REGNO (operands[0]) + 1);
545   else if (optype0 == OFFSOP)
546     latehalf[0] = adjust_address (operands[0], HImode, 2);
547   else
548     latehalf[0] = operands[0];
549
550   if (optype1 == REGOP)
551     latehalf[1] = gen_rtx_REG (HImode, REGNO (operands[1]) + 1);
552   else if (optype1 == OFFSOP)
553     latehalf[1] = adjust_address (operands[1], HImode, 2);
554   else if (optype1 == CNSTOP)
555     {
556         if (CONSTANT_P (operands[1]))
557         {
558             /* now the mess begins, high word is in lower word??? 
559
560                that's what ashc makes me think, but I don't remember :-( */
561             latehalf[1] = GEN_INT (INTVAL(operands[1]) >> 16);
562             operands[1] = GEN_INT (INTVAL(operands[1]) & 0xff);
563         }
564       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
565         {
566             /* immediate 32 bit values not allowed */
567             abort();
568         }
569     }
570   else
571     latehalf[1] = operands[1];
572
573   /* If insn is effectively movd N(sp),-(sp) then we will do the
574      high word first.  We should use the adjusted operand 1 (which is N+4(sp))
575      for the low word as well, to compensate for the first decrement of sp.  */
576   if (optype0 == PUSHOP
577       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
578       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
579     operands[1] = latehalf[1];
580
581   /* If one or both operands autodecrementing,
582      do the two words, high-numbered first.  */
583
584   /* Likewise,  the first move would clobber the source of the second one,
585      do them in the other order.  This happens only for registers;
586      such overlap can't happen in memory unless the user explicitly
587      sets it up, and that is an undefined circumstance.  */
588
589   if (optype0 == PUSHOP || optype1 == PUSHOP
590       || (optype0 == REGOP && optype1 == REGOP
591           && REGNO (operands[0]) == REGNO (latehalf[1])))
592     {
593       /* Make any unoffsettable addresses point at high-numbered word.  */
594       if (addreg0)
595         output_asm_insn ("add $2,%0", &addreg0);
596       if (addreg1)
597         output_asm_insn ("add $2,%0", &addreg1);
598
599       /* Do that word.  */
600       output_asm_insn (singlemove_string (latehalf), latehalf);
601
602       /* Undo the adds we just did.  */
603       if (addreg0)
604         output_asm_insn ("sub $2,%0", &addreg0);
605       if (addreg1)
606         output_asm_insn ("sub $2,%0", &addreg1);
607
608       /* Do low-numbered word.  */
609       return singlemove_string (operands);
610     }
611
612   /* Normal case: do the two words, low-numbered first.  */
613
614   output_asm_insn (singlemove_string (operands), operands);
615
616   /* Make any unoffsettable addresses point at high-numbered word.  */
617   if (addreg0)
618     output_asm_insn ("add $2,%0", &addreg0);
619   if (addreg1)
620     output_asm_insn ("add $2,%0", &addreg1);
621
622   /* Do that word.  */
623   output_asm_insn (singlemove_string (latehalf), latehalf);
624
625   /* Undo the adds we just did.  */
626   if (addreg0)
627     output_asm_insn ("sub $2,%0", &addreg0);
628   if (addreg1)
629     output_asm_insn ("sub $2,%0", &addreg1);
630
631   return "";
632 }
633 /* Output assembler code to perform a quadword move insn
634    with operands OPERANDS.  */
635
636 const char *
637 output_move_quad (rtx *operands)
638 {
639   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
640   rtx latehalf[2];
641   rtx addreg0 = 0, addreg1 = 0;
642
643   output_asm_insn(";/* movdi/df: %1 -> %0 */", operands);
644   
645   if (REG_P (operands[0]))
646     optype0 = REGOP;
647   else if (offsettable_memref_p (operands[0]))
648     optype0 = OFFSOP;
649   else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
650     optype0 = POPOP;
651   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
652     optype0 = PUSHOP;
653   else if (GET_CODE (operands[0]) == MEM)
654     optype0 = MEMOP;
655   else
656     optype0 = RNDOP;
657
658   if (REG_P (operands[1]))
659     optype1 = REGOP;
660   else if (CONSTANT_P (operands[1])
661            || GET_CODE (operands[1]) == CONST_DOUBLE)
662     optype1 = CNSTOP;
663   else if (offsettable_memref_p (operands[1]))
664     optype1 = OFFSOP;
665   else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
666     optype1 = POPOP;
667   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
668     optype1 = PUSHOP;
669   else if (GET_CODE (operands[1]) == MEM)
670     optype1 = MEMOP;
671   else
672     optype1 = RNDOP;
673
674   /* Check for the cases that the operand constraints are not
675      supposed to allow to happen.  Abort if we get one,
676      because generating code for these cases is painful.  */
677
678   if (optype0 == RNDOP || optype1 == RNDOP)
679     abort ();
680   
681   /* check if we move a CPU reg to an FPU reg, or vice versa! */
682   if (optype0 == REGOP && optype1 == REGOP)
683       /* bogus - 64 bit cannot reside in CPU! */
684       if (CPU_REG_P(REGNO(operands[0]))
685           || CPU_REG_P (REGNO(operands[1])))
686           abort();
687   
688   if (optype0 == REGOP || optype1 == REGOP)
689   {
690       /* check for use of clrd???? 
691          if you ever allow ac4 and ac5 (now we require secondary load) 
692          you must check whether 
693          you want to load into them or store from them - 
694          then dump ac0 into $help$ movce ac4/5 to ac0, do the 
695          store from ac0, and restore ac0 - if you can find 
696          an unused ac[0-3], use that and you save a store and a load!*/
697
698       if (FPU_REG_P(REGNO(operands[0])))
699       {
700           if (GET_CODE(operands[1]) == CONST_DOUBLE)
701           {
702               REAL_VALUE_TYPE r;
703               REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
704
705               if (REAL_VALUES_EQUAL (r, dconst0))
706                   return "{clrd|clrf} %0";
707           }
708               
709           return "{ldd|movf} %1, %0";
710       }
711       
712       if (FPU_REG_P(REGNO(operands[1])))
713           return "{std|movf} %1, %0";
714   }
715       
716   /* If one operand is decrementing and one is incrementing
717      decrement the former register explicitly
718      and change that operand into ordinary indexing.  */
719
720   if (optype0 == PUSHOP && optype1 == POPOP)
721     {
722       operands[0] = XEXP (XEXP (operands[0], 0), 0);
723       output_asm_insn ("sub $8,%0", operands);
724       operands[0] = gen_rtx_MEM (DImode, operands[0]);
725       optype0 = OFFSOP;
726     }
727   if (optype0 == POPOP && optype1 == PUSHOP)
728     {
729       operands[1] = XEXP (XEXP (operands[1], 0), 0);
730       output_asm_insn ("sub $8,%1", operands);
731       operands[1] = gen_rtx_MEM (SImode, operands[1]);
732       optype1 = OFFSOP;
733     }
734
735   /* If an operand is an unoffsettable memory ref, find a register
736      we can increment temporarily to make it refer to the second word.  */
737
738   if (optype0 == MEMOP)
739     addreg0 = find_addr_reg (XEXP (operands[0], 0));
740
741   if (optype1 == MEMOP)
742     addreg1 = find_addr_reg (XEXP (operands[1], 0));
743
744   /* Ok, we can do one word at a time.
745      Normally we do the low-numbered word first,
746      but if either operand is autodecrementing then we
747      do the high-numbered word first.
748
749      In either case, set up in LATEHALF the operands to use
750      for the high-numbered word and in some cases alter the
751      operands in OPERANDS to be suitable for the low-numbered word.  */
752
753   if (optype0 == REGOP)
754     latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 2);
755   else if (optype0 == OFFSOP)
756     latehalf[0] = adjust_address (operands[0], SImode, 4);
757   else
758     latehalf[0] = operands[0];
759
760   if (optype1 == REGOP)
761     latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2);
762   else if (optype1 == OFFSOP)
763     latehalf[1] = adjust_address (operands[1], SImode, 4);
764   else if (optype1 == CNSTOP)
765     {
766       if (GET_CODE (operands[1]) == CONST_DOUBLE)
767         {
768           REAL_VALUE_TYPE r;
769           long dval[2];
770           REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
771           REAL_VALUE_TO_TARGET_DOUBLE (r, dval);
772           latehalf[1] = GEN_INT (dval[1]);
773           operands[1] = GEN_INT (dval[0]);
774         }
775       else if (GET_CODE(operands[1]) == CONST_INT)
776         {
777           latehalf[1] = const0_rtx;
778         }
779       else
780         abort();
781     }
782   else
783     latehalf[1] = operands[1];
784
785   /* If insn is effectively movd N(sp),-(sp) then we will do the
786      high word first.  We should use the adjusted operand 1 (which is N+4(sp))
787      for the low word as well, to compensate for the first decrement of sp.  */
788   if (optype0 == PUSHOP
789       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
790       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
791     operands[1] = latehalf[1];
792
793   /* If one or both operands autodecrementing,
794      do the two words, high-numbered first.  */
795
796   /* Likewise,  the first move would clobber the source of the second one,
797      do them in the other order.  This happens only for registers;
798      such overlap can't happen in memory unless the user explicitly
799      sets it up, and that is an undefined circumstance.  */
800
801   if (optype0 == PUSHOP || optype1 == PUSHOP
802       || (optype0 == REGOP && optype1 == REGOP
803           && REGNO (operands[0]) == REGNO (latehalf[1])))
804     {
805       /* Make any unoffsettable addresses point at high-numbered word.  */
806       if (addreg0)
807         output_asm_insn ("add $4,%0", &addreg0);
808       if (addreg1)
809         output_asm_insn ("add $4,%0", &addreg1);
810
811       /* Do that word.  */
812       output_asm_insn(output_move_double(latehalf), latehalf);
813
814       /* Undo the adds we just did.  */
815       if (addreg0)
816         output_asm_insn ("sub $4,%0", &addreg0);
817       if (addreg1)
818         output_asm_insn ("sub $4,%0", &addreg1);
819
820       /* Do low-numbered word.  */
821       return output_move_double (operands);
822     }
823
824   /* Normal case: do the two words, low-numbered first.  */
825
826   output_asm_insn (output_move_double (operands), operands);
827
828   /* Make any unoffsettable addresses point at high-numbered word.  */
829   if (addreg0)
830     output_asm_insn ("add $4,%0", &addreg0);
831   if (addreg1)
832     output_asm_insn ("add $4,%0", &addreg1);
833
834   /* Do that word.  */
835   output_asm_insn (output_move_double (latehalf), latehalf);
836
837   /* Undo the adds we just did.  */
838   if (addreg0)
839     output_asm_insn ("sub $4,%0", &addreg0);
840   if (addreg1)
841     output_asm_insn ("sub $4,%0", &addreg1);
842
843   return "";
844 }
845
846 \f
847 /* Return a REG that occurs in ADDR with coefficient 1.
848    ADDR can be effectively incremented by incrementing REG.  */
849
850 static rtx
851 find_addr_reg (rtx addr)
852 {
853   while (GET_CODE (addr) == PLUS)
854     {
855       if (GET_CODE (XEXP (addr, 0)) == REG)
856         addr = XEXP (addr, 0);
857       if (GET_CODE (XEXP (addr, 1)) == REG)
858         addr = XEXP (addr, 1);
859       if (CONSTANT_P (XEXP (addr, 0)))
860         addr = XEXP (addr, 1);
861       if (CONSTANT_P (XEXP (addr, 1)))
862         addr = XEXP (addr, 0);
863     }
864   if (GET_CODE (addr) == REG)
865     return addr;
866   return 0;
867 }
868 \f
869 /* Output an ascii string.  */
870 void
871 output_ascii (FILE *file, const char *p, int size)
872 {
873   int i;
874
875   /* This used to output .byte "string", which doesn't work with the UNIX
876      assembler and I think not with DEC ones either.  */
877   fprintf (file, "\t.byte ");
878
879   for (i = 0; i < size; i++)
880     {
881       register int c = p[i];
882       if (c < 0)
883         c += 256;
884       fprintf (file, "%#o", c);
885       if (i < size - 1)
886         putc (',', file);
887     }
888   putc ('\n', file);
889 }
890
891
892 /* --- stole from out-vax, needs changes */
893
894 void
895 print_operand_address (FILE *file, register rtx addr)
896 {
897   register rtx reg1, reg2, breg, ireg;
898   rtx offset;
899
900  retry:
901
902   switch (GET_CODE (addr))
903     {
904     case MEM:
905       if (TARGET_UNIX_ASM)
906         fprintf (file, "*");
907       else
908         fprintf (file, "@");
909       addr = XEXP (addr, 0);
910       goto retry;
911
912     case REG:
913       fprintf (file, "(%s)", reg_names[REGNO (addr)]);
914       break;
915
916     case PRE_MODIFY:
917     case PRE_DEC:
918       fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]);
919       break;
920
921     case POST_MODIFY:
922     case POST_INC:
923       fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]);
924       break;
925
926     case PLUS:
927       reg1 = 0; reg2 = 0;
928       ireg = 0; breg = 0;
929       offset = 0;
930       if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
931           || GET_CODE (XEXP (addr, 0)) == MEM)
932         {
933           offset = XEXP (addr, 0);
934           addr = XEXP (addr, 1);
935         }
936       else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
937                || GET_CODE (XEXP (addr, 1)) == MEM)
938         {
939           offset = XEXP (addr, 1);
940           addr = XEXP (addr, 0);
941         }
942       if (GET_CODE (addr) != PLUS)
943         ;
944       else if (GET_CODE (XEXP (addr, 0)) == MULT)
945         {
946           reg1 = XEXP (addr, 0);
947           addr = XEXP (addr, 1);
948         }
949       else if (GET_CODE (XEXP (addr, 1)) == MULT)
950         {
951           reg1 = XEXP (addr, 1);
952           addr = XEXP (addr, 0);
953         }
954       else if (GET_CODE (XEXP (addr, 0)) == REG)
955         {
956           reg1 = XEXP (addr, 0);
957           addr = XEXP (addr, 1);
958         }
959       else if (GET_CODE (XEXP (addr, 1)) == REG)
960         {
961           reg1 = XEXP (addr, 1);
962           addr = XEXP (addr, 0);
963         }
964       if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
965         {
966           if (reg1 == 0)
967             reg1 = addr;
968           else
969             reg2 = addr;
970           addr = 0;
971         }
972       if (offset != 0)
973         {
974           if (addr != 0) abort ();
975           addr = offset;
976         }
977       if (reg1 != 0 && GET_CODE (reg1) == MULT)
978         {
979           breg = reg2;
980           ireg = reg1;
981         }
982       else if (reg2 != 0 && GET_CODE (reg2) == MULT)
983         {
984           breg = reg1;
985           ireg = reg2;
986         }
987       else if (reg2 != 0 || GET_CODE (addr) == MEM)
988         {
989           breg = reg2;
990           ireg = reg1;
991         }
992       else
993         {
994           breg = reg1;
995           ireg = reg2;
996         }
997       if (addr != 0)
998         output_address (addr);
999       if (breg != 0)
1000         {
1001           if (GET_CODE (breg) != REG)
1002             abort ();
1003           fprintf (file, "(%s)", reg_names[REGNO (breg)]);
1004         }
1005       if (ireg != 0)
1006         {
1007           if (GET_CODE (ireg) == MULT)
1008             ireg = XEXP (ireg, 0);
1009           if (GET_CODE (ireg) != REG)
1010             abort ();
1011           abort();
1012           fprintf (file, "[%s]", reg_names[REGNO (ireg)]);
1013         }
1014       break;
1015
1016     default:
1017       output_addr_const_pdp11 (file, addr);
1018     }
1019 }
1020
1021 /* Target hook to assemble integer objects.  We need to use the
1022    pdp-specific version of output_addr_const.  */
1023
1024 static bool
1025 pdp11_assemble_integer (rtx x, unsigned int size, int aligned_p)
1026 {
1027   if (aligned_p)
1028     switch (size)
1029       {
1030       case 1:
1031         fprintf (asm_out_file, "\t.byte\t");
1032         output_addr_const_pdp11 (asm_out_file, x);
1033         fprintf (asm_out_file, " /* char */\n");
1034         return true;
1035
1036       case 2:
1037         fprintf (asm_out_file, TARGET_UNIX_ASM ? "\t" : "\t.word\t");
1038         output_addr_const_pdp11 (asm_out_file, x);
1039         fprintf (asm_out_file, " /* short */\n");
1040         return true;
1041       }
1042   return default_assemble_integer (x, size, aligned_p);
1043 }
1044
1045
1046 /* register move costs, indexed by regs */
1047
1048 static const int move_costs[N_REG_CLASSES][N_REG_CLASSES] = 
1049 {
1050              /* NO  MUL  GEN  LFPU  NLFPU FPU ALL */
1051
1052 /* NO */     {  0,   0,   0,    0,    0,    0,   0},
1053 /* MUL */    {  0,   2,   2,   10,   22,   22,  22},
1054 /* GEN */    {  0,   2,   2,   10,   22,   22,  22},
1055 /* LFPU */   {  0,  10,  10,    2,    2,    2,  10},
1056 /* NLFPU */  {  0,  22,  22,    2,    2,    2,  22},
1057 /* FPU */    {  0,  22,  22,    2,    2,    2,  22},
1058 /* ALL */    {  0,  22,  22,   10,   22,   22,  22}
1059 }  ;
1060
1061
1062 /* -- note that some moves are tremendously expensive, 
1063    because they require lots of tricks! do we have to 
1064    charge the costs incurred by secondary reload class 
1065    -- as we do here with 22 -- or not ? */
1066
1067 int 
1068 register_move_cost(c1, c2)
1069   enum reg_class c1, c2;
1070 {
1071     return move_costs[(int)c1][(int)c2];
1072 }
1073
1074 static bool
1075 pdp11_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total)
1076 {
1077   switch (code)
1078     {
1079     case CONST_INT:
1080       if (INTVAL (x) == 0 || INTVAL (x) == -1 || INTVAL (x) == 1)
1081         {
1082           *total = 0;
1083           return true;
1084         }
1085       /* FALLTHRU */
1086
1087     case CONST:
1088     case LABEL_REF:
1089     case SYMBOL_REF:
1090       /* Twice as expensive as REG.  */
1091       *total = 2;
1092       return true;
1093
1094     case CONST_DOUBLE:
1095       /* Twice (or 4 times) as expensive as 16 bit.  */
1096       *total = 4;
1097       return true;
1098
1099     case MULT:
1100       /* ??? There is something wrong in MULT because MULT is not 
1101          as cheap as total = 2 even if we can shift!  */
1102       /* If optimizing for size make mult etc cheap, but not 1, so when 
1103          in doubt the faster insn is chosen.  */
1104       if (optimize_size)
1105         *total = COSTS_N_INSNS (2);
1106       else
1107         *total = COSTS_N_INSNS (11);
1108       return false;
1109
1110     case DIV:
1111       if (optimize_size)
1112         *total = COSTS_N_INSNS (2);
1113       else
1114         *total = COSTS_N_INSNS (25);
1115       return false;
1116
1117     case MOD:
1118       if (optimize_size)
1119         *total = COSTS_N_INSNS (2);
1120       else
1121         *total = COSTS_N_INSNS (26);
1122       return false;
1123
1124     case ABS:
1125       /* Equivalent to length, so same for optimize_size.  */
1126       *total = COSTS_N_INSNS (3);
1127       return false;
1128
1129     case ZERO_EXTEND:
1130       /* Only used for qi->hi.  */
1131       *total = COSTS_N_INSNS (1);
1132       return false;
1133
1134     case SIGN_EXTEND:
1135       if (GET_MODE (x) == HImode)
1136         *total = COSTS_N_INSNS (1);
1137       else if (GET_MODE (x) == SImode)
1138         *total = COSTS_N_INSNS (6);
1139       else
1140         *total = COSTS_N_INSNS (2);
1141       return false;
1142
1143     case ASHIFT:
1144     case LSHIFTRT:
1145     case ASHIFTRT:
1146       if (optimize_size)
1147         *total = COSTS_N_INSNS (1);
1148       else if (GET_MODE (x) ==  QImode)
1149         {
1150           if (GET_CODE (XEXP (x, 1)) != CONST_INT)
1151             *total = COSTS_N_INSNS (8); /* worst case */
1152           else
1153             *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1)));
1154         }
1155       else if (GET_MODE (x) == HImode)
1156         {
1157           if (GET_CODE (XEXP (x, 1)) == CONST_INT)
1158             {
1159               if (abs (INTVAL (XEXP (x, 1))) == 1)
1160                 *total = COSTS_N_INSNS (1);
1161               else
1162                 *total = COSTS_N_INSNS (2.5 + 0.5 * INTVAL (XEXP (x, 1)));
1163             }
1164           else
1165             *total = COSTS_N_INSNS (10); /* worst case */
1166         }
1167       else if (GET_MODE (x) == SImode)
1168         {
1169           if (GET_CODE (XEXP (x, 1)) == CONST_INT)
1170             *total = COSTS_N_INSNS (2.5 + 0.5 * INTVAL (XEXP (x, 1)));
1171           else /* worst case */
1172             *total = COSTS_N_INSNS (18);
1173         }
1174       return false;
1175
1176     default:
1177       return false;
1178     }
1179 }
1180
1181 const char *
1182 output_jump(const char *pos, const char *neg, int length)
1183 {
1184     static int x = 0;
1185     
1186     static char buf[1000];
1187
1188 #if 0
1189 /* currently we don't need this, because the tstdf and cmpdf 
1190    copy the condition code immediately, and other float operations are not 
1191    yet recognized as changing the FCC - if so, then the length-cost of all
1192    jump insns increases by one, because we have to potentially copy the 
1193    FCC! */
1194     if (cc_status.flags & CC_IN_FPU)
1195         output_asm_insn("cfcc", NULL);
1196 #endif
1197         
1198     switch (length)
1199     {
1200       case 1:
1201         
1202         strcpy(buf, pos);
1203         strcat(buf, " %l0");
1204         
1205         return buf;
1206         
1207       case 3:
1208         
1209         sprintf(buf, "%s JMP_%d\n\tjmp %%l0\nJMP_%d:", neg, x, x);
1210         
1211         x++;
1212         
1213         return buf;
1214         
1215       default:
1216         
1217         abort();
1218     }
1219     
1220 }
1221
1222 void
1223 notice_update_cc_on_set(rtx exp, rtx insn ATTRIBUTE_UNUSED)
1224 {
1225     if (GET_CODE (SET_DEST (exp)) == CC0)
1226     { 
1227         cc_status.flags = 0;                                    
1228         cc_status.value1 = SET_DEST (exp);                      
1229         cc_status.value2 = SET_SRC (exp);                       
1230
1231 /*
1232         if (GET_MODE(SET_SRC(exp)) == DFmode)
1233             cc_status.flags |= CC_IN_FPU;
1234 */      
1235     }                                                   
1236     else if ((GET_CODE (SET_DEST (exp)) == REG          
1237               || GET_CODE (SET_DEST (exp)) == MEM)              
1238              && GET_CODE (SET_SRC (exp)) != PC          
1239              && (GET_MODE (SET_DEST(exp)) == HImode             
1240                  || GET_MODE (SET_DEST(exp)) == QImode) 
1241                 && (GET_CODE (SET_SRC(exp)) == PLUS             
1242                     || GET_CODE (SET_SRC(exp)) == MINUS 
1243                     || GET_CODE (SET_SRC(exp)) == AND   
1244                     || GET_CODE (SET_SRC(exp)) == IOR   
1245                     || GET_CODE (SET_SRC(exp)) == XOR   
1246                     || GET_CODE (SET_SRC(exp)) == NOT   
1247                     || GET_CODE (SET_SRC(exp)) == NEG   
1248                         || GET_CODE (SET_SRC(exp)) == REG       
1249                     || GET_CODE (SET_SRC(exp)) == MEM)) 
1250     { 
1251         cc_status.flags = 0;                                    
1252         cc_status.value1 = SET_SRC (exp);                       
1253         cc_status.value2 = SET_DEST (exp);                      
1254         
1255         if (cc_status.value1 && GET_CODE (cc_status.value1) == REG      
1256             && cc_status.value2                                 
1257             && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
1258             cc_status.value2 = 0;                                       
1259         if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM      
1260             && cc_status.value2                                 
1261             && GET_CODE (cc_status.value2) == MEM)                      
1262             cc_status.value2 = 0;                                       
1263     }                                                   
1264     else if (GET_CODE (SET_SRC (exp)) == CALL)          
1265     { 
1266         CC_STATUS_INIT; 
1267     }
1268     else if (GET_CODE (SET_DEST (exp)) == REG)                  
1269         /* what's this ? */                                     
1270     { 
1271         if ((cc_status.value1                                   
1272              && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1)))
1273             cc_status.value1 = 0;                               
1274         if ((cc_status.value2                                   
1275              && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2)))
1276             cc_status.value2 = 0;                               
1277     }                                                   
1278     else if (SET_DEST(exp) == pc_rtx)
1279     { 
1280         /* jump */
1281     }
1282     else /* if (GET_CODE (SET_DEST (exp)) == MEM)       */      
1283     {  
1284         /* the last else is a bit paranoiac, but since nearly all instructions 
1285            play with condition codes, it's reasonable! */
1286
1287         CC_STATUS_INIT; /* paranoia*/ 
1288     }                   
1289 }
1290
1291
1292 int
1293 simple_memory_operand(rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1294 {
1295     rtx addr;
1296
1297     /* Eliminate non-memory operations */
1298     if (GET_CODE (op) != MEM)
1299         return FALSE;
1300
1301 #if 0
1302     /* dword operations really put out 2 instructions, so eliminate them.  */
1303     if (GET_MODE_SIZE (GET_MODE (op)) > (HAVE_64BIT_P () ? 8 : 4))
1304         return FALSE;
1305 #endif
1306
1307     /* Decode the address now.  */
1308
1309   indirection:
1310     
1311     addr = XEXP (op, 0);
1312
1313     switch (GET_CODE (addr))
1314     {
1315       case REG:
1316         /* (R0) - no extra cost */
1317         return 1;
1318         
1319       case PRE_DEC:
1320       case POST_INC:
1321         /* -(R0), (R0)+ - cheap! */
1322         return 0;
1323         
1324       case MEM:
1325         /* cheap - is encoded in addressing mode info! 
1326
1327            -- except for @(R0), which has to be @0(R0) !!! */
1328
1329         if (GET_CODE (XEXP (addr, 0)) == REG)
1330             return 0;
1331         
1332         op=addr;
1333         goto indirection;
1334         
1335       case CONST_INT:
1336       case LABEL_REF:          
1337       case CONST:
1338       case SYMBOL_REF:
1339         /* @#address - extra cost */
1340         return 0;
1341
1342       case PLUS:
1343         /* X(R0) - extra cost */
1344         return 0;
1345
1346       default:
1347         break;
1348     }
1349     
1350     return FALSE;
1351 }
1352
1353
1354 /*
1355  * output a block move:
1356  *
1357  * operands[0]  ... to
1358  * operands[1]  ... from
1359  * operands[2]  ... length
1360  * operands[3]  ... alignment
1361  * operands[4]  ... scratch register
1362  */
1363
1364  
1365 const char *
1366 output_block_move(rtx *operands)
1367 {
1368     static int count = 0;
1369     char buf[200];
1370     
1371     if (GET_CODE(operands[2]) == CONST_INT
1372         && ! optimize_size)
1373     {
1374         if (INTVAL(operands[2]) < 16
1375             && INTVAL(operands[3]) == 1)
1376         {
1377             register int i;
1378             
1379             for (i = 1; i <= INTVAL(operands[2]); i++)
1380                 output_asm_insn("movb (%1)+, (%0)+", operands);
1381
1382             return "";
1383         }
1384         else if (INTVAL(operands[2]) < 32)
1385         {
1386             register int i;
1387             
1388             for (i = 1; i <= INTVAL(operands[2])/2; i++)
1389                 output_asm_insn("mov (%1)+, (%0)+", operands);
1390             
1391             /* may I assume that moved quantity is 
1392                multiple of alignment ???
1393
1394                I HOPE SO !
1395             */
1396
1397             return "";
1398         }
1399         
1400
1401         /* can do other clever things, maybe... */
1402     }
1403
1404     if (CONSTANT_P(operands[2]) )
1405     {
1406         /* just move count to scratch */
1407         output_asm_insn("mov %2, %4", operands);
1408     }
1409     else
1410     {
1411         /* just clobber the register */
1412         operands[4] = operands[2];
1413     }
1414     
1415
1416     /* switch over alignment */
1417     switch (INTVAL(operands[3]))
1418     {
1419       case 1:
1420         
1421         /* 
1422           x:
1423           movb (%1)+, (%0)+
1424           
1425           if (TARGET_45)
1426              sob %4,x
1427           else
1428              dec %4
1429              bgt x
1430
1431         */
1432
1433         sprintf(buf, "\nmovestrhi%d:", count);
1434         output_asm_insn(buf, NULL);
1435         
1436         output_asm_insn("movb (%1)+, (%0)+", operands);
1437         
1438         if (TARGET_45)
1439         {
1440             sprintf(buf, "sob %%4, movestrhi%d", count);
1441             output_asm_insn(buf, operands);
1442         }
1443         else
1444         {
1445             output_asm_insn("dec %4", operands);
1446             
1447             sprintf(buf, "bgt movestrhi%d", count);
1448             output_asm_insn(buf, NULL);
1449         }
1450         
1451         count ++;
1452         break;
1453         
1454       case 2:
1455         
1456         /* 
1457            asr %4
1458
1459            x:
1460
1461            mov (%1)+, (%0)+
1462
1463            if (TARGET_45)
1464              sob %4, x
1465            else
1466              dec %4
1467              bgt x
1468         */
1469
1470       generate_compact_code:
1471
1472         output_asm_insn("asr %4", operands);
1473
1474         sprintf(buf, "\nmovestrhi%d:", count);
1475         output_asm_insn(buf, NULL);
1476         
1477         output_asm_insn("mov (%1)+, (%0)+", operands);
1478         
1479         if (TARGET_45)
1480         {
1481             sprintf(buf, "sob %%4, movestrhi%d", count);
1482             output_asm_insn(buf, operands);
1483         }
1484         else
1485         {
1486             output_asm_insn("dec %4", operands);
1487             
1488             sprintf(buf, "bgt movestrhi%d", count);
1489             output_asm_insn(buf, NULL);
1490         }
1491         
1492         count ++;
1493         break;
1494
1495       case 4:
1496         
1497         /*
1498
1499            asr %4
1500            asr %4
1501
1502            x:
1503
1504            mov (%1)+, (%0)+
1505            mov (%1)+, (%0)+
1506
1507            if (TARGET_45)
1508              sob %4, x
1509            else
1510              dec %4
1511              bgt x
1512         */
1513
1514         if (optimize_size)
1515             goto generate_compact_code;
1516         
1517         output_asm_insn("asr %4", operands);
1518         output_asm_insn("asr %4", operands);
1519
1520         sprintf(buf, "\nmovestrhi%d:", count);
1521         output_asm_insn(buf, NULL);
1522         
1523         output_asm_insn("mov (%1)+, (%0)+", operands);
1524         output_asm_insn("mov (%1)+, (%0)+", operands);
1525         
1526         if (TARGET_45)
1527         {
1528             sprintf(buf, "sob %%4, movestrhi%d", count);
1529             output_asm_insn(buf, operands);
1530         }
1531         else
1532         {
1533             output_asm_insn("dec %4", operands);
1534             
1535             sprintf(buf, "bgt movestrhi%d", count);
1536             output_asm_insn(buf, NULL);
1537         }
1538         
1539         count ++;
1540         break;
1541        
1542       default:
1543         
1544         /*
1545            
1546            asr %4
1547            asr %4
1548            asr %4
1549
1550            x:
1551
1552            mov (%1)+, (%0)+
1553            mov (%1)+, (%0)+
1554            mov (%1)+, (%0)+
1555            mov (%1)+, (%0)+
1556            
1557            if (TARGET_45)
1558              sob %4, x
1559            else
1560              dec %4
1561              bgt x
1562         */
1563
1564
1565         if (optimize_size)
1566             goto generate_compact_code;
1567         
1568         output_asm_insn("asr %4", operands);
1569         output_asm_insn("asr %4", operands);
1570         output_asm_insn("asr %4", operands);
1571
1572         sprintf(buf, "\nmovestrhi%d:", count);
1573         output_asm_insn(buf, NULL);
1574         
1575         output_asm_insn("mov (%1)+, (%0)+", operands);
1576         output_asm_insn("mov (%1)+, (%0)+", operands);
1577         output_asm_insn("mov (%1)+, (%0)+", operands);
1578         output_asm_insn("mov (%1)+, (%0)+", operands);
1579         
1580         if (TARGET_45)
1581         {
1582             sprintf(buf, "sob %%4, movestrhi%d", count);
1583             output_asm_insn(buf, operands);
1584         }
1585         else
1586         {
1587             output_asm_insn("dec %4", operands);
1588             
1589             sprintf(buf, "bgt movestrhi%d", count);
1590             output_asm_insn(buf, NULL);
1591         }
1592         
1593         count ++;
1594         break;
1595         
1596         ;
1597         
1598     }
1599     
1600     return "";
1601 }
1602
1603 int
1604 legitimate_address_p (enum machine_mode mode, rtx address)
1605 {
1606 /* #define REG_OK_STRICT */
1607     GO_IF_LEGITIMATE_ADDRESS(mode, address, win);
1608     
1609     return 0;
1610     
1611   win:
1612     return 1;
1613
1614 /* #undef REG_OK_STRICT */
1615 }
1616
1617 /* This function checks whether a real value can be encoded as
1618    a literal, i.e., addressing mode 27.  In that mode, real values
1619    are one word values, so the remaining 48 bits have to be zero.  */
1620 int
1621 legitimate_const_double_p (rtx address)
1622 {
1623   REAL_VALUE_TYPE r;
1624   long sval[2];
1625   REAL_VALUE_FROM_CONST_DOUBLE (r, address);
1626   REAL_VALUE_TO_TARGET_DOUBLE (r, sval);
1627   if ((sval[0] & 0xffff) == 0 && sval[1] == 0)
1628     return 1;
1629   return 0;
1630 }
1631
1632 /* A copy of output_addr_const modified for pdp11 expression syntax.
1633    output_addr_const also gets called for %cDIGIT and %nDIGIT, which we don't
1634    use, and for debugging output, which we don't support with this port either.
1635    So this copy should get called whenever needed.
1636 */
1637 void
1638 output_addr_const_pdp11 (FILE *file, rtx x)
1639 {
1640   char buf[256];
1641
1642  restart:
1643   switch (GET_CODE (x))
1644     {
1645     case PC:
1646       if (flag_pic)
1647         putc ('.', file);
1648       else
1649         abort ();
1650       break;
1651
1652     case SYMBOL_REF:
1653       assemble_name (file, XSTR (x, 0));
1654       break;
1655
1656     case LABEL_REF:
1657       ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
1658       assemble_name (file, buf);
1659       break;
1660
1661     case CODE_LABEL:
1662       ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
1663       assemble_name (file, buf);
1664       break;
1665
1666     case CONST_INT:
1667       /* Should we check for constants which are too big?  Maybe cutting
1668          them off to 16 bits is OK?  */
1669       fprintf (file, "%#ho", (unsigned short) INTVAL (x));
1670       break;
1671
1672     case CONST:
1673       /* This used to output parentheses around the expression,
1674          but that does not work on the 386 (either ATT or BSD assembler).  */
1675       output_addr_const_pdp11 (file, XEXP (x, 0));
1676       break;
1677
1678     case CONST_DOUBLE:
1679       if (GET_MODE (x) == VOIDmode)
1680         {
1681           /* We can use %o if the number is one word and positive.  */
1682           if (CONST_DOUBLE_HIGH (x))
1683             abort (); /* Should we just silently drop the high part?  */
1684           else
1685             fprintf (file, "%#ho", (unsigned short) CONST_DOUBLE_LOW (x));
1686         }
1687       else
1688         /* We can't handle floating point constants;
1689            PRINT_OPERAND must handle them.  */
1690         output_operand_lossage ("floating constant misused");
1691       break;
1692
1693     case PLUS:
1694       /* Some assemblers need integer constants to appear last (eg masm).  */
1695       if (GET_CODE (XEXP (x, 0)) == CONST_INT)
1696         {
1697           output_addr_const_pdp11 (file, XEXP (x, 1));
1698           if (INTVAL (XEXP (x, 0)) >= 0)
1699             fprintf (file, "+");
1700           output_addr_const_pdp11 (file, XEXP (x, 0));
1701         }
1702       else
1703         {
1704           output_addr_const_pdp11 (file, XEXP (x, 0));
1705           if (INTVAL (XEXP (x, 1)) >= 0)
1706             fprintf (file, "+");
1707           output_addr_const_pdp11 (file, XEXP (x, 1));
1708         }
1709       break;
1710
1711     case MINUS:
1712       /* Avoid outputting things like x-x or x+5-x,
1713          since some assemblers can't handle that.  */
1714       x = simplify_subtraction (x);
1715       if (GET_CODE (x) != MINUS)
1716         goto restart;
1717
1718       output_addr_const_pdp11 (file, XEXP (x, 0));
1719       fprintf (file, "-");
1720       if (GET_CODE (XEXP (x, 1)) == CONST_INT
1721           && INTVAL (XEXP (x, 1)) < 0)
1722         {
1723           fprintf (file, targetm.asm_out.open_paren);
1724           output_addr_const_pdp11 (file, XEXP (x, 1));
1725           fprintf (file, targetm.asm_out.close_paren);
1726         }
1727       else
1728         output_addr_const_pdp11 (file, XEXP (x, 1));
1729       break;
1730
1731     case ZERO_EXTEND:
1732     case SIGN_EXTEND:
1733       output_addr_const_pdp11 (file, XEXP (x, 0));
1734       break;
1735
1736     default:
1737       output_operand_lossage ("invalid expression as operand");
1738     }
1739 }
1740
1741 /* Worker function for TARGET_RETURN_IN_MEMORY.  */
1742
1743 static bool
1744 pdp11_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
1745 {
1746   /* Should probably return DImode and DFmode in memory, lest
1747      we fill up all regs!
1748
1749      have to, else we crash - exception: maybe return result in 
1750      ac0 if DFmode and FPU present - compatibility problem with
1751      libraries for non-floating point....  */
1752   return (TYPE_MODE (type) == DImode
1753           || (TYPE_MODE (type) == DFmode && ! TARGET_AC0));
1754 }