OSDN Git Service

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