OSDN Git Service

39a0ebb0ba796a242f7e7140c2df6070591869d7
[pf3gnuchains/gcc-fork.git] / gcc / config / 1750a / 1750a.c
1 /* Subroutines for insn-output.c for MIL-STD-1750.
2    Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999,
3    2000 Free Software Foundation, Inc.
4    Contributed by O.M.Kellogg, DASA (kellogg@space.otn.dasa.de)
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 #define __datalbl
24 #include "config.h"
25 #include "system.h"
26 #include "rtl.h"
27 #include "tree.h"
28 #include "function.h"
29 #include "expr.h"
30 #define HAVE_cc0
31 #include "conditions.h"
32 #include "real.h"
33 #include "regs.h"
34 #include "output.h"
35 #include "flags.h"
36 #include "tm_p.h"
37 #include "target.h"
38 #include "target-def.h"
39
40 struct datalabel_array datalbl[DATALBL_ARRSIZ];
41 int datalbl_ndx = -1;
42 struct jumplabel_array jmplbl[JMPLBL_ARRSIZ];
43 int jmplbl_ndx = -1;
44 int label_pending = 0, program_counter = 0;
45 enum section current_section = Normal;
46 const char *const sectname[4] =
47 {"Init", "Normal", "Konst", "Static"};
48
49 static int which_bit PARAMS ((int));
50 static void output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
51 static void output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
52 \f
53 /* Initialize the GCC target structure.  */
54 #undef TARGET_ASM_FUNCTION_PROLOGUE
55 #define TARGET_ASM_FUNCTION_PROLOGUE output_function_prologue
56 #undef TARGET_ASM_FUNCTION_EPILOGUE
57 #define TARGET_ASM_FUNCTION_EPILOGUE output_function_epilogue
58
59 struct gcc_target target = TARGET_INITIALIZER;
60 \f
61 /* Generate the assembly code for function entry.  FILE is a stdio
62    stream to output the code to.  SIZE is an int: how many units of
63    temporary storage to allocate.
64
65    Refer to the array `regs_ever_live' to determine which registers to
66    save; `regs_ever_live[I]' is nonzero if register number I is ever
67    used in the function.  This function is responsible for knowing
68    which registers should not be saved even if used.  */
69
70 static void
71 output_function_prologue (file, size)
72      FILE *file;
73      HOST_WIDE_INT size;
74 {
75   if (flag_verbose_asm)
76     {
77       int regno, regs_used = 0;
78
79       fprintf (file, "\t; registers used: ");
80       for (regno = 0; regno < 14; regno++)
81         if (regs_ever_live[regno])
82           {
83             fprintf (file, " %s", reg_names[regno]);
84             regs_used++;
85           }
86
87       if (regs_used == 0)
88         fprintf (file, "(none)");
89     }
90
91   if (size > 0)
92     {
93       fprintf (file, "\n\t%s\tr15,%d",
94                (size <= 16 ? "sisp" : "sim"), size);
95       if (flag_verbose_asm)
96         fprintf (file, "  ; reserve local-variable space");
97     }
98
99   if (frame_pointer_needed)
100     {
101       fprintf(file, "\n\tpshm\tr14,r14");
102       if (flag_verbose_asm)
103         fprintf (file, "  ; push old frame");
104       fprintf (file, "\n\tlr\tr14,r15");
105       if (flag_verbose_asm)
106         fprintf (file, "  ; set new frame");
107     }
108
109   fprintf (file, "\n");
110   program_counter = 0;
111   jmplbl_ndx = -1;
112 }
113
114 /* This function generates the assembly code for function exit.
115    Args are as for output_function_prologue ().
116
117    The function epilogue should not depend on the current stack
118    pointer!  It should use the frame pointer only.  This is mandatory
119    because of alloca; we also take advantage of it to omit stack
120    adjustments before returning. */
121
122 static void
123 output_function_epilogue (file, size)
124      FILE *file;
125      HOST_WIDE_INT size;
126 {
127   if (frame_pointer_needed)
128     {
129       fprintf (file, "\tlr\tr15,r14");
130       if (flag_verbose_asm)
131         fprintf (file, "  ; set stack ptr to frame ptr");
132       fprintf (file, "\n\tpopm\tr14,r14");
133       if (flag_verbose_asm)
134         fprintf (file, "  ; restore previous frame ptr");
135       fprintf (file, "\n");
136     }
137
138   if (size > 0)
139     {
140       fprintf (file, "\t%s\tr15,%d",
141                (size <= 16 ? "aisp" : "aim"), size);
142       if (flag_verbose_asm)
143         fprintf (file, "  ; free up local-var space");
144       fprintf (file, "\n");
145     }
146
147   fprintf (file, "\turs\tr15\n\n");
148 }
149
150 void
151 notice_update_cc (exp)
152      rtx exp;
153 {
154   if (GET_CODE (exp) == SET)
155     {
156       enum rtx_code src_code = GET_CODE (SET_SRC (exp));
157       /* Jumps do not alter the cc's.  */
158       if (SET_DEST (exp) == pc_rtx)
159         return;
160       /* Moving a register or constant into memory doesn't alter the cc's. */
161       if (GET_CODE (SET_DEST (exp)) == MEM
162           && (src_code == REG || src_code == CONST_INT))
163         return;
164       /* Function calls clobber the cc's.  */
165       if (src_code == CALL)
166         {
167           CC_STATUS_INIT;
168           return;
169         }
170       /* Emulated longword bit-ops leave cc's incorrect */
171       if (GET_MODE (SET_DEST (exp)) == HImode ?
172                src_code == AND || src_code == IOR ||
173                src_code == XOR || src_code == NOT : 0)
174         {
175           CC_STATUS_INIT;
176           return;
177         }
178       /* Tests and compares set the cc's in predictable ways.  */
179       if (SET_DEST (exp) == cc0_rtx)
180         {
181           CC_STATUS_INIT;
182           cc_status.value1 = SET_SRC (exp);
183           return;
184         }
185       /* Anything else will set cc_status. */
186       cc_status.flags = CC_NO_OVERFLOW;
187       cc_status.value1 = SET_SRC (exp);
188       cc_status.value2 = SET_DEST (exp);
189       return;
190     }
191   else if (GET_CODE (exp) == PARALLEL
192            && GET_CODE (XVECEXP (exp, 0, 0)) == SET)
193     {
194       if (SET_DEST (XVECEXP (exp, 0, 0)) == pc_rtx)
195         return;
196       if (SET_DEST (XVECEXP (exp, 0, 0)) == cc0_rtx)
197         {
198           CC_STATUS_INIT;
199           cc_status.value1 = SET_SRC (XVECEXP (exp, 0, 0));
200           return;
201         }
202       CC_STATUS_INIT;
203     }
204   else
205     {
206       CC_STATUS_INIT;
207     }
208 }
209
210
211 rtx
212 function_arg (cum, mode, type, named)
213      int cum;
214      enum machine_mode mode;
215      tree type;
216      int named ATTRIBUTE_UNUSED;
217 {
218   int size;
219
220   if (MUST_PASS_IN_STACK (mode, type))
221     return (rtx) 0;
222   if (mode == BLKmode)
223     size = int_size_in_bytes (type);
224   else
225     size = GET_MODE_SIZE (mode);
226   if (cum + size < 12)
227     return gen_rtx_REG (mode, cum);
228   else
229     return (rtx) 0;
230 }
231
232
233 double
234 get_double (x)
235      rtx x;
236 {
237   union
238     {
239       double d;
240       long i[2];
241     }
242   du;
243
244   du.i[0] = CONST_DOUBLE_LOW (x);
245   du.i[1] = CONST_DOUBLE_HIGH (x);
246   return du.d;
247 }
248
249 char *
250 float_label (code, value)
251      int code;
252      double value;
253 {
254   static char label[32];
255   char *p;
256
257   label[0] = code;
258   p = label + 1;
259   sprintf (p, "%f", value);
260   while (*p)
261     {
262       *p = (*p == '+') ? 'p' :
263         (*p == '-') ? 'm' : *p;
264       p++;
265     }
266   return xstrdup (label);
267 }
268
269
270 const char *
271 movcnt_regno_adjust (op)
272      rtx *op;
273 {
274   static char outstr[80];
275   int op0r = REGNO (op[0]), op1r = REGNO (op[1]), op2r = REGNO (op[2]);
276 #define dstreg op0r
277 #define srcreg op1r
278 #define cntreg op2r
279 #define cntreg_1750 (op0r + 1)
280
281   if (cntreg == cntreg_1750)
282     sprintf (outstr, "mov r%d,r%d", op0r, op1r);
283   else if (dstreg + 1 == srcreg && cntreg > srcreg)
284     sprintf (outstr, "xwr r%d,r%d\n\tmov r%d,r%d", op2r, op1r, op0r, op2r);
285   else if (dstreg == cntreg + 1)
286     sprintf (outstr, "xwr r%d,r%d\n\tmov r%d,r%d", op0r, op2r, op2r, op1r);
287   else if (dstreg == srcreg + 1)
288     sprintf (outstr, "xwr r%d,r%d\n\txwr r%d,r%d\n\tmov r%d,r%d",
289              op0r, op1r, op0r, op2r, op1r, op2r);
290   else if (cntreg + 1 == srcreg)
291     sprintf (outstr, "xwr r%d,r%d\n\txwr r%d,r%d\n\tmov r%d,r%d",
292              op2r, op1r, op0r, op2r, op2r, op0r);
293   else if (cntreg == srcreg + 1)
294     sprintf (outstr, "xwr r%d,r%d\n\tmov r%d,r%d", op0r, op1r, op1r, op0r);
295   else
296     sprintf (outstr, "xwr r%d,r%d\n\tmov r%d,r%d\n\txwr r%d,r%d",
297              op2r, cntreg_1750, op0r, op1r, op2r, cntreg_1750);
298   return outstr;
299 }
300
301 const char *
302 mod_regno_adjust (instr, op)
303      const char *instr;
304      rtx *op;
305 {
306   static char outstr[40];
307   const char *r = (!strncmp (instr, "dvr", 3) ? "r" : "");
308   int modregno_gcc = REGNO (op[3]), modregno_1750 = REGNO (op[0]) + 1;
309
310   if (modregno_gcc == modregno_1750
311       || (reg_renumber != NULL
312           && reg_renumber[modregno_gcc] >= 0
313           && reg_renumber[modregno_gcc] == reg_renumber[modregno_1750]))
314     sprintf (outstr, "%s r%%0,%s%%2", instr, r);
315   else
316     sprintf (outstr, "lr r%d,r%d\n\t%s r%%0,%s%%2\n\txwr r%d,r%d",
317              modregno_gcc, modregno_1750, instr, r, modregno_1750,
318              modregno_gcc);
319   return outstr;
320 }
321
322
323 /* Check if op is a valid memory operand for 1750A Load/Store instructions
324    (memory indirection permitted.)  */
325
326 int
327 memop_valid (op)
328      rtx op;
329 {
330   static int recurred = 0;
331   int valid_operand;
332
333   if (GET_MODE (op) != Pmode && GET_MODE (op) != VOIDmode
334       && GET_MODE (op) != QImode)
335     return 0;
336   switch (GET_CODE (op))
337     {
338     case MEM:
339       if (!recurred && GET_CODE (XEXP (op, 0)) == REG)
340         return 1;
341     case MINUS:
342     case MULT:
343     case DIV:
344       return 0;
345     case PLUS:
346       recurred = 1;
347       valid_operand = memop_valid (XEXP (op, 0));
348       if (valid_operand)
349         valid_operand = memop_valid (XEXP (op, 1));
350        recurred = 0;
351        return valid_operand;
352     case REG:
353       if (REGNO (op) > 0)
354         return 1;
355       return 0;
356     case CONST:
357     case CONST_INT:
358     case SYMBOL_REF:
359     case SUBREG:
360       return 1;
361     default:
362       printf ("memop_valid: code=%d\n", (int) GET_CODE (op));
363       return 1;
364     }
365 }
366
367
368 /* predicate for the MOV instruction: */
369 int
370 mov_memory_operand (op, mode)
371      rtx op;
372      enum machine_mode mode ATTRIBUTE_UNUSED;
373 {
374   return (GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == REG);
375 }
376
377 /* predicate for the STC instruction: */
378 int
379 small_nonneg_const (op, mode)
380      rtx op;
381      enum machine_mode mode ATTRIBUTE_UNUSED;
382 {
383   if (GET_CODE (op) == CONST_INT && INTVAL (op) >= 0 && INTVAL (op) <= 15)
384     return 1;
385   return 0;
386 }
387
388 /* predicate for constant zero: */
389 int
390 zero_operand (op, mode)
391      rtx op;
392      enum machine_mode mode;
393 {
394   return op == CONST0_RTX (mode);
395 }
396
397
398 /* predicate for 1750 `B' addressing mode (Base Register with Offset)
399    memory operand */
400 int
401 b_mode_operand (op)
402      rtx op;
403 {
404   if (GET_CODE (op) == MEM)
405     {
406       rtx inner = XEXP (op, 0);
407       if (GET_CODE (inner) == REG && REG_OK_FOR_INDEX_P (inner))
408         return 1;
409       if (GET_CODE (inner) == PLUS)
410         {
411           rtx plus_op0 = XEXP (inner, 0);
412           if (GET_CODE (plus_op0) == REG && REG_OK_FOR_INDEX_P (plus_op0))
413             {
414               rtx plus_op1 = XEXP (inner, 1);
415               if (GET_CODE (plus_op1) == CONST_INT
416                   && INTVAL (plus_op1) >= 0
417                   && INTVAL (plus_op1) <= 255)
418                 return 1;
419             }
420         }
421     }
422   return 0;
423 }
424
425
426 /* Decide whether to output a conditional jump as a "Jump Conditional"
427    or as a "Branch Conditional": */
428
429 int
430 find_jmplbl (labelnum)
431      int labelnum;
432 {
433   int i, found = 0;
434
435   for (i = 0; i <= jmplbl_ndx; i++)
436     if (labelnum == jmplbl[i].num)
437       {
438         found = 1;
439         break;
440       }
441   if (found)
442     return i;
443   return -1;
444 }
445
446 const char *
447 branch_or_jump (condition, targetlabel_number)
448      const char *condition;
449      int targetlabel_number;
450 {
451   static char buf[30];
452   int index;
453
454   if ((index = find_jmplbl (targetlabel_number)) >= 0)
455     if (program_counter - jmplbl[index].pc < 128)
456       {
457         sprintf (buf, "b%s %%l0", condition);
458         return buf;
459       }
460   sprintf (buf, "jc %s,%%l0", condition);
461   return buf;
462 }
463
464
465 int
466 unsigned_comparison_operator (insn)
467      rtx insn;
468 {
469   switch (GET_CODE (insn))
470     {
471     case GEU:
472     case GTU:
473     case LEU:
474     case LTU:
475       return 1;
476     default:
477       return 0;
478     }
479 }
480
481 int
482 next_cc_user_is_unsigned (insn)
483      rtx insn;
484 {
485   if ( !(insn = next_cc0_user (insn)))
486     abort ();
487   else if (GET_CODE (insn) == JUMP_INSN
488            && GET_CODE (PATTERN (insn)) == SET
489            && GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE)
490     return unsigned_comparison_operator (XEXP (SET_SRC (PATTERN (insn)), 0));
491   else if (GET_CODE (insn) == INSN
492            && GET_CODE (PATTERN (insn)) == SET)
493     return unsigned_comparison_operator (SET_SRC (PATTERN (insn)));
494   else
495     abort ();
496 }
497
498
499 static int addr_inc;
500
501 /* A C compound statement to output to stdio stream STREAM the
502    assembler syntax for an instruction operand X.  X is an RTL
503    expression.
504
505    CODE is a value that can be used to specify one of several ways
506    of printing the operand.  It is used when identical operands
507    must be printed differently depending on the context.  CODE
508    comes from the `%' specification that was used to request
509    printing of the operand.  If the specification was just `%DIGIT'
510    then CODE is 0; if the specification was `%LTR DIGIT' then CODE
511    is the ASCII code for LTR.
512
513    If X is a register, this macro should print the register's name.
514    The names can be found in an array `reg_names' whose type is
515    `char *[]'.  `reg_names' is initialized from `REGISTER_NAMES'.
516
517    When the machine description has a specification `%PUNCT' (a `%'
518    followed by a punctuation character), this macro is called with
519    a null pointer for X and the punctuation character for CODE.
520
521    The 1750 specific codes are:
522    'J' for the negative of a constant
523    'Q' for printing addresses in B mode syntax
524    'd' for the second register in a pair
525    't' for the third register in a triple 
526    'b' for the bit number (using 1750 test bit convention)
527    'B' for the bit number of the 1's complement (for bit clear)
528    'w' for int - 16
529 */
530
531 void
532 print_operand (file, x, letter)
533      FILE *file;
534      rtx x;
535      int letter;
536 {
537   switch (GET_CODE (x))
538     {
539     case REG:
540       if (letter == 'd')
541         fprintf (file, "%d", REGNO (x) + 1);
542       else if (letter == 't')
543         fprintf (file, "%d", REGNO (x) + 2);
544       else
545         fprintf (file, "%d", REGNO (x));
546       break;
547
548     case SYMBOL_REF:
549       fprintf (file, "%s", XSTR (x, 0));
550       if (letter == 'A')
551         fprintf (file, "+1");
552       break;
553
554     case LABEL_REF:
555     case CONST:
556     case MEM:
557       if (letter == 'Q')
558         {
559           rtx inner = XEXP (x, 0);
560           switch (GET_CODE (inner))
561             {
562             case REG:
563               fprintf (file, "r%d,0", REGNO (inner));
564               break;
565             case PLUS:
566               fprintf (file, "r%d,%d", REGNO (XEXP (inner, 0)),
567                        INTVAL (XEXP (inner, 1)));
568               break;
569             default:
570               fprintf (file, "[ill Q code=%d]", GET_CODE (inner));
571             }
572         }
573       else
574         {
575           addr_inc = (letter == 'A' ? 1 : 0);
576           output_address (XEXP (x, 0));
577         }
578       break;
579
580     case CONST_DOUBLE:
581 /*    {
582         double value = get_double (x);
583         char fltstr[32];
584         sprintf (fltstr, "%f", value);
585
586         if (letter == 'D' || letter == 'E')
587           {
588             int i, found = 0;
589             for (i = 0; i <= datalbl_ndx; i++)
590               if (strcmp (fltstr, datalbl[i].value) == 0)
591                 {
592                   found = 1;
593                   break;
594                 }
595             if (!found)
596               {
597                 strcpy (datalbl[i = ++datalbl_ndx].value, fltstr);
598                 datalbl[i].name = float_label (letter, value);
599                 datalbl[i].size = (letter == 'E') ? 3 : 2;
600                 check_section (Konst);
601                 fprintf (file, "K%s \tdata%s %s ;p_o\n", datalbl[i].name,
602                         (letter == 'E' ? "ef" : "f"), fltstr);
603                 check_section (Normal);
604               }
605           }
606         else if (letter == 'F' || letter == 'G')
607           {
608             int i, found = 0;
609             for (i = 0; i <= datalbl_ndx; i++)
610               if (strcmp (fltstr, datalbl[i].value) == 0)
611                 {
612                   found = 1;
613                   break;
614                 }
615             if (!found)
616               {
617                 fprintf (stderr,
618                    "float value %f not found upon label reference\n", value);
619                 strcpy (datalbl[i = ++datalbl_ndx].value, fltstr);
620                 datalbl[i].name = float_label (letter, value);
621                 datalbl[i].size = (letter == 'G') ? 3 : 2;
622                 check_section (Konst);
623                 fprintf (file, "K%s \tdata%s %s ;p_o\n", datalbl[i].name,
624                         (letter == 'G' ? "ef" : "f"), fltstr);
625                 check_section (Normal);
626               }
627             fprintf (file, "%s ;P_O 'F'", datalbl[i].name);
628           }
629         else
630           fprintf (file, " %s  ;P_O cst_dbl ", fltstr);
631       }
632  */
633       fprintf (file, "%f", get_double (x));
634       break;
635
636     case CONST_INT:
637       if (letter == 'J')
638         fprintf (file, HOST_WIDE_INT_PRINT_DEC, -INTVAL (x));
639       else if (letter == 'b')
640         fprintf (file, "%d", which_bit (INTVAL (x)));
641       else if (letter == 'B')
642         fprintf (file, "%d", which_bit (~INTVAL (x)));
643       else if (letter == 'w')
644         fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) - 16);
645       else
646         fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
647       break;
648
649     case CODE_LABEL:
650       fprintf (file, "L%d", XINT (x, 3));
651       break;
652
653     case CALL:
654       fprintf (file, "CALL nargs=");
655       fprintf (file, HOST_PTR_PRINTF, XEXP (x, 1));
656       fprintf (file, ", func is either '%s' or '%s'",
657                XSTR (XEXP (XEXP (x, 0), 1), 0), XSTR (XEXP (x, 0), 1));
658       break;
659
660     case PLUS:
661       {
662         rtx op0 = XEXP (x, 0), op1 = XEXP (x, 1);
663         int op0code = GET_CODE (op0), op1code = GET_CODE (op1);
664         if (op1code == CONST_INT)
665           switch (op0code)
666             {
667             case REG:
668               fprintf (file, "%d,r%d  ; p_o_PLUS for REG and CONST_INT",
669                        INTVAL (op1), REGNO (op0));
670               break;
671             case SYMBOL_REF:
672               fprintf (file, "%d+%s", INTVAL (op1), XSTR (op0, 0));
673               break;
674             case MEM:
675               fprintf (file, "%d,[mem:", INTVAL (op1));
676               output_address (XEXP (op0, 0));
677               fprintf (file, "] ;P_O plus");
678               break;
679             default:
680               fprintf (file, "p_o_PLUS UFO, code=%d, with CONST=%d",
681                        (int) op0code, INTVAL (op1));
682             }
683         else if (op1code == SYMBOL_REF && op0code == REG)
684           fprintf (file, "%s,r%d  ; P_O: (plus reg sym)",
685                    XSTR (op1, 0), REGNO (op0));
686         else
687           fprintf (file, "p_o_+: op0code=%d, op1code=%d", op0code, op1code);
688       }
689       break;
690
691     default:
692       fprintf (file, "p_o_UFO code=%d", GET_CODE (x));
693     }
694
695   addr_inc = 0;
696 }
697
698 void
699 print_operand_address (file, addr)
700      FILE *file;
701      rtx addr;
702 {
703   switch (GET_CODE (addr))
704     {
705     case REG:
706       fprintf (file, "%d,r%d ; P_O_A", addr_inc, REGNO (addr));
707       break;
708     case PLUS:
709       {
710         register rtx x = XEXP (addr, 0), y = XEXP (addr, 1);
711         switch (GET_CODE (x))
712           {
713           case REG:
714             switch (GET_CODE (y))
715               {
716               case CONST:
717                 output_address (XEXP (y, 0));
718                 fprintf (file, ",r%d ;P_O_A reg + const expr", REGNO (x));
719                 break;
720               case CONST_INT:
721                 fprintf (file, "%d,r%d", INTVAL (y) + addr_inc, REGNO (x));
722                 break;
723               case SYMBOL_REF:
724                 fprintf (file, "%s", XSTR (y, 0));
725                 if (addr_inc)
726                   fprintf (file, "+%d", addr_inc);
727                 fprintf (file, ",r%d  ; P_O_A reg + sym", REGNO (x));
728                 break;
729               case LABEL_REF:
730                 output_address (XEXP (y, 0));
731                 fprintf (file, ",r%d  ; P_O_A reg + label", REGNO (x));
732                 break;
733               default:
734                 fprintf (file, "[P_O_A reg%d+UFO code=%d]",
735                          REGNO (x), GET_CODE (y));
736               }
737             break;
738           case LABEL_REF:
739             output_address (XEXP (x, 0));
740             break;
741           case SYMBOL_REF:
742             switch (GET_CODE (y))
743               {
744               case CONST_INT:
745                 fprintf (file, "%d+%s", INTVAL (y) + addr_inc, XSTR (x, 0));
746                 break;
747               case REG:
748                 fprintf (file, "%s,r%d ;P_O_A sym + reg",
749                          XSTR (x, 0), REGNO (y));
750                 break;
751               default:
752                 fprintf (file, "P_O_A sym/lab+UFO[sym=%s,code(y)=%d]",
753                          XSTR (x, 0), GET_CODE (y));
754               }
755             break;
756           case CONST:
757             output_address (XEXP (x, 0));
758             if (GET_CODE (y) == REG)
759               fprintf (file, ",r%d ;P_O_A const + reg", REGNO (x));
760             else
761               fprintf (file, "P_O_A const+UFO code(y)=%d]", GET_CODE (y));
762             break;
763           case MEM:
764             output_address (y);
765             fprintf (file, ",[mem:");
766             output_address (XEXP (x, 0));
767             fprintf (file, "] ;P_O_A plus");
768             break;
769           default:
770             fprintf (file, "P_O_A plus op1_UFO[code1=%d,code2=%d]",
771                      GET_CODE (x), GET_CODE (y));
772           }
773       }
774       break;
775     case CONST_INT:
776       if (INTVAL (addr) < 0x10000 && INTVAL (addr) >= -0x10000)
777         fprintf (file, "%d ; p_o_a const addr?!", INTVAL (addr));
778       else
779         {
780           fprintf (file, "[p_o_a=ILLEGAL_CONST]");
781           output_addr_const (file, addr);
782         }
783       break;
784     case LABEL_REF:
785     case SYMBOL_REF:
786       fprintf (file, "%s", XSTR (addr, 0));
787       if (addr_inc)
788         fprintf (file, "+%d", addr_inc);
789       break;
790     case MEM:
791       fprintf (file, "[memUFO:");
792       output_address (XEXP (addr, 0));
793       fprintf (file, "]");
794       break;
795     case CONST:
796       output_address (XEXP (addr, 0));
797       fprintf (file, " ;P_O_A const");
798       break;
799     case CODE_LABEL:
800       fprintf (file, "L%d", XINT (addr, 3));
801       break;
802     default:
803       fprintf (file, " p_o_a UFO, code=%d val=0x%x",
804                (int) GET_CODE (addr), INTVAL (addr));
805       break;
806     }
807   addr_inc = 0;
808 }
809
810
811 /*
812  *  Return non zero if the LS 16 bits of the given value has just one bit set,
813  *  otherwise return zero. Note this function may be used to detect one
814  *  bit clear by inverting the param.
815  */
816 int
817 one_bit_set_p (x)
818      int x;
819 {
820   x &= 0xffff; 
821   return x && (x & (x - 1)) == 0;
822 }
823
824
825 /*
826  * Return the number of the least significant bit set, using the  same
827  * convention for bit numbering as in the MIL-STD-1750 sb instruction.
828  */
829 static int
830 which_bit (x)
831      int x;
832 {
833   int b = 15;
834
835   while (b > 0 && (x & 1) == 0)
836     {
837       b--;
838       x >>= 1;
839     }
840
841   return b;
842 }
843
844