OSDN Git Service

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