OSDN Git Service

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