OSDN Git Service

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