OSDN Git Service

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