OSDN Git Service

Merge from gcc-2.8
[pf3gnuchains/gcc-fork.git] / gcc / config / m88k / m88k.c
index e2465e3..45938a1 100644 (file)
@@ -1,8 +1,7 @@
 /* Subroutines for insn-output.c for Motorola 88000.
-   Copyright (C) 1988, 1989, 1990, 1991 Free Software Foundation, Inc.
+   Copyright (C) 1988, 92, 93, 94, 95, 16, 1997 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@mcc.com)
-   Enhanced by Michael Meissner (meissner@osf.org)
-   Version 2 port by Tom Wood (Tom_Wood@NeXT.com)
+   Currently maintained by (gcc@dg-rtp.dg.com)
 
 This file is part of GNU CC.
 
@@ -18,7 +17,10 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#include "config.h"
 
 #include <stdio.h>
 #include <sys/types.h>
@@ -26,7 +28,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <ctype.h>
 
 #include "assert.h"
-#include "config.h"
 #include "rtl.h"
 #include "regs.h"
 #include "hard-reg-set.h"
@@ -47,27 +48,26 @@ extern char *ctime ();
 extern int flag_traditional;
 extern FILE *asm_out_file;
 
-static char out_sccs_id[] = "@(#)m88k.c        2.3.3.2 12/16/92 08:26:06";
-static char tm_sccs_id [] = TM_SCCS_ID;
+static char out_rcs_id[] = "$What: <@(#) m88k.c,v      1.8> $";
+static char tm_rcs_id [] = TM_RCS_ID;
 
 char *m88k_pound_sign = "";    /* Either # for SVR4 or empty for SVR3 */
 char *m88k_short_data;
 char *m88k_version;
 char m88k_volatile_code;
 
-int m88k_gp_threshold;
+unsigned m88k_gp_threshold = 0;
 int m88k_prologue_done = 0;    /* Ln directives can now be emitted */
 int m88k_function_number = 0;  /* Counter unique to each function */
 int m88k_fp_offset     = 0;    /* offset of frame pointer if used */
 int m88k_stack_size    = 0;    /* size of allocated stack (including frame) */
 int m88k_case_index;
-int m88k_version_0300;         /* Version is at least 03.00 */
 
 rtx m88k_compare_reg;          /* cmp output pseudo register */
 rtx m88k_compare_op0;          /* cmpsi operand 0 */
 rtx m88k_compare_op1;          /* cmpsi operand 1 */
 
-enum attr_cpu m88k_cpu;                /* target cpu */
+enum processor_type m88k_cpu;  /* target cpu */
 \f
 /* Determine what instructions are needed to manufacture the integer VALUE
    in the given MODE.  */
@@ -225,6 +225,10 @@ emit_move_sequence (operands, mode, scratch)
   register rtx operand0 = operands[0];
   register rtx operand1 = operands[1];
 
+  if (CONSTANT_P (operand1) && flag_pic
+      && pic_address_needs_scratch (operand1))
+    operands[1] = operand1 = legitimize_address (1, operand1, 0, 0);
+
   /* Handle most common case first: storing into a register.  */
   if (register_operand (operand0, mode))
     {
@@ -258,17 +262,17 @@ emit_move_sequence (operands, mode, scratch)
   /* Simplify the source if we need to.  */
   if (GET_CODE (operand1) != HIGH && immediate_operand (operand1, mode))
     {
-       if (GET_CODE (operand1) != CONST_INT
-           && GET_CODE (operand1) != CONST_DOUBLE)
-         {
-           rtx temp = ((reload_in_progress || reload_completed)
-                       ? operand0 : 0);
-           operands[1] = legitimize_address (flag_pic
-                                             && symbolic_address_p (operand1),
-                                             operand1, temp, scratch);
-           if (mode != SImode)
-             operands[1] = gen_rtx (SUBREG, mode, operands[1], 0);
-         }
+      if (GET_CODE (operand1) != CONST_INT
+         && GET_CODE (operand1) != CONST_DOUBLE)
+       {
+         rtx temp = ((reload_in_progress || reload_completed)
+                     ? operand0 : 0);
+         operands[1] = legitimize_address (flag_pic
+                                           && symbolic_address_p (operand1),
+                                           operand1, temp, scratch);
+         if (mode != SImode)
+           operands[1] = gen_rtx (SUBREG, mode, operands[1], 0);
+       }
     }
 
   /* Now have insn-emit do whatever it normally does.  */
@@ -314,10 +318,16 @@ legitimize_address (pic, orig, reg, scratch)
              temp = ((reload_in_progress || reload_completed)
                      ? reg : gen_reg_rtx (Pmode));
 
-             emit_insn (gen_rtx (SET, VOIDmode,
-                                 temp, gen_rtx (HIGH, SImode, addr)));
-             emit_insn (gen_rtx (SET, VOIDmode,
-                                 temp, gen_rtx (LO_SUM, SImode, temp, addr)));
+             emit_insn (gen_rtx (SET, VOIDmode, temp,
+                                 gen_rtx (HIGH, SImode,
+                                          gen_rtx (UNSPEC, SImode,
+                                                   gen_rtvec (1, addr),
+                                                   0))));
+             emit_insn (gen_rtx (SET, VOIDmode, temp,
+                                 gen_rtx (LO_SUM, SImode, temp,
+                                          gen_rtx (UNSPEC, SImode,
+                                                   gen_rtvec (1, addr),
+                                                   0))));
              addr = temp;
            }
          new = gen_rtx (MEM, Pmode,
@@ -356,7 +366,7 @@ legitimize_address (pic, orig, reg, scratch)
 
          if (GET_CODE (addr) == CONST_INT)
            {
-             if (SMALL_INT (addr))
+             if (ADD_INT (addr))
                return plus_constant_for_output (base, INTVAL (addr));
              else if (! reload_in_progress && ! reload_completed)
                addr = force_reg (Pmode, addr);
@@ -491,9 +501,9 @@ expand_block_move (dest_mem, src_mem, operands)
   int bytes = (constp ? INTVAL (operands[2]) : 0);
   int target = (int) m88k_cpu;
 
-  assert (CPU_M88100 == 0);
-  assert (CPU_M88110 == 1);
-  assert (CPU_M88000 == 2);
+  assert (PROCESSOR_M88100 == 0);
+  assert (PROCESSOR_M88110 == 1);
+  assert (PROCESSOR_M88000 == 2);
 
   if (constp && bytes <= 0)
     return;
@@ -523,13 +533,18 @@ expand_block_move (dest_mem, src_mem, operands)
                         VOIDmode, 3,
                         operands[0], Pmode,
                         operands[1], Pmode,
-                        operands[2], SImode);
+                        convert_to_mode (TYPE_MODE (sizetype), operands[2],
+                                         TREE_UNSIGNED (sizetype)),
+                        TYPE_MODE (sizetype));
 #else
       emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcopy"), 0,
                         VOIDmode, 3,
                         operands[1], Pmode,
                         operands[0], Pmode,
-                        operands[2], SImode);
+                        convert_to_mode (TYPE_MODE (integer_type_node),
+                                         operands[2],
+                                         TREE_UNSIGNED (integer_type_node)),
+                        TYPE_MODE (integer_type_node));
 #endif
     }
 }
@@ -590,7 +605,7 @@ block_move_loop (dest, dest_mem, src, src_mem, size, align)
                                offset_rtx));
   RTX_UNCHANGING_P (value_rtx) = RTX_UNCHANGING_P (src_mem);
   MEM_VOLATILE_P (value_rtx) = MEM_VOLATILE_P (src_mem);
-  MEM_IN_STRUCT_P (value_rtx) = 1;
+  MEM_IN_STRUCT_P (value_rtx) = MEM_IN_STRUCT_P (src_mem);
 
   emit_insn (gen_call_movstrsi_loop
             (gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (entry_name)),
@@ -647,7 +662,7 @@ block_move_no_loop (dest, dest_mem, src, src_mem, size, align)
                                offset_rtx));
   RTX_UNCHANGING_P (value_rtx) = RTX_UNCHANGING_P (src_mem);
   MEM_VOLATILE_P (value_rtx) = MEM_VOLATILE_P (src_mem);
-  MEM_IN_STRUCT_P (value_rtx) = 1;
+  MEM_IN_STRUCT_P (value_rtx) = MEM_IN_STRUCT_P (src_mem);
 
   value_reg = ((((most - (size - remainder)) / align) & 1) == 0
               ? (align == 8 ? 6 : 5) : 4);
@@ -720,7 +735,7 @@ block_move_sequence (dest, dest_mem, src, src_mem, size, align, offset)
                                   gen_rtx (CONST_INT, SImode, offset_ld)));
          RTX_UNCHANGING_P (srcp) = RTX_UNCHANGING_P (src_mem);
          MEM_VOLATILE_P (srcp) = MEM_VOLATILE_P (src_mem);
-         MEM_IN_STRUCT_P (srcp) = 1;
+         MEM_IN_STRUCT_P (srcp) = MEM_IN_STRUCT_P (src_mem);
          emit_insn (gen_rtx (SET, VOIDmode, temp[next], srcp));
          offset_ld += amount[next];
          active[next] = TRUE;
@@ -735,7 +750,7 @@ block_move_sequence (dest, dest_mem, src, src_mem, size, align, offset)
                                   gen_rtx (CONST_INT, SImode, offset_st)));
          RTX_UNCHANGING_P (dstp) = RTX_UNCHANGING_P (dest_mem);
          MEM_VOLATILE_P (dstp) = MEM_VOLATILE_P (dest_mem);
-         MEM_IN_STRUCT_P (dstp) = 1;
+         MEM_IN_STRUCT_P (dstp) = MEM_IN_STRUCT_P (dest_mem);
          emit_insn (gen_rtx (SET, VOIDmode, dstp, temp[phase]));
          offset_st += amount[phase];
        }
@@ -868,14 +883,20 @@ output_call (operands, addr)
             If we loose, we must use the non-delay form.  This is unlikely
             to ever happen.  If it becomes a problem, claim that a call
             has two delay slots and only the second can be filled with
-            a jump.  */
+            a jump.  
+
+            The 88110 can lose when a jsr.n r1 is issued and a page fault
+            occurs accessing the delay slot.  So don't use jsr.n form when
+            jumping thru r1.
+          */
 #ifdef AS_BUG_IMMEDIATE_LABEL /* The assembler restricts immediate values.  */
          if (optimize < 2
-             || ! ADD_INTVAL (delta * 2))
+             || ! ADD_INTVAL (delta * 2)
 #else
          if (optimize < 2
-             || ! ADD_INTVAL (delta))
+             || ! ADD_INTVAL (delta)
 #endif
+             || (REG_P (addr) && REGNO (addr) == 1))
            {
              operands[1] = dest;
              return (REG_P (addr)
@@ -1260,7 +1281,7 @@ arith64_operand (op, mode)
 {
   return (register_operand (op, mode)
          || GET_CODE (op) == CONST_INT
-         || (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DImode));
+         || (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode));
 }
 
 int
@@ -1335,6 +1356,17 @@ real_or_0_operand (op, mode)
              && op == CONST0_RTX (mode)));
 }
 
+/* Return true if OP is valid to use in the context of logic arithmetic
+   on condition codes. */
+
+int
+partial_ccmode_register_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return register_operand (op, CCmode) || register_operand (op, CCEVENmode);
+}
+
 /* Return true if OP is a relational operator.  */
 
 int
@@ -1360,6 +1392,42 @@ relop (op, mode)
     }
 }
 
+int
+even_relop (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  switch (GET_CODE (op))
+    {
+    case EQ:
+    case LT:
+    case GT:
+    case LTU:
+    case GTU:
+      return 1;
+    default:
+      return 0;
+    }
+}
+
+int
+odd_relop (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  switch (GET_CODE (op))
+    {
+    case NE:
+    case LE:
+    case GE:
+    case LEU:
+    case GEU:
+      return 1;
+    default:
+      return 0;
+    }
+}
+
 /* Return true if OP is a relational operator, and is not an unsigned
    relational operator.  */
 
@@ -1412,7 +1480,7 @@ pc_or_label_ref (op, mode)
 \f
 /* Output to FILE the start of the assembler file.  */
 
-struct option
+struct options
 {
   char *string;
   int *variable;
@@ -1443,8 +1511,8 @@ static void
 output_options (file, f_options, f_len, W_options, W_len,
                pos, max, sep, indent, term)
      FILE *file;
-     struct option *f_options;
-     struct option *W_options;
+     struct options *f_options;
+     struct options *W_options;
      int f_len, W_len;
      int pos;
      int max;
@@ -1492,15 +1560,15 @@ output_options (file, f_options, f_len, W_options, W_len,
 void
 output_file_start (file, f_options, f_len, W_options, W_len)
      FILE *file;
-     struct option *f_options;
-     struct option *W_options;
+     struct options *f_options;
+     struct options *W_options;
      int f_len, W_len;
 {
   register int pos;
 
   ASM_FIRST_LINE (file);
   if (TARGET_88110
-      && m88k_version != 0 && strcmp (m88k_version, "04.00") >= 0)
+      && TARGET_SVR4)
     fprintf (file, "\t%s\n", REQUIRES_88110_ASM_OP);
   output_file_directive (file, main_input_filename);
   /* Switch to the data section so that the coffsem symbol and the
@@ -1508,10 +1576,6 @@ output_file_start (file, f_options, f_len, W_options, W_len)
   data_section ();
   ASM_COFFSEM (file);
 
-  pos = fprintf (file, "\n; cc1 (%s) arguments:", VERSION_STRING);
-  output_options (file, f_options, f_len, W_options, W_len,
-                 pos, 75, " ", "\n; ", "\n\n");
-
   if (TARGET_IDENTIFY_REVISION)
     {
       char indent[256];
@@ -1520,8 +1584,17 @@ output_file_start (file, f_options, f_len, W_options, W_len)
       sprintf (indent, "]\"\n\t%s\t \"@(#)%s [", IDENT_ASM_OP, main_input_filename);
       fprintf (file, indent+3);
       pos = fprintf (file, "gcc %s, %.24s,", VERSION_STRING, ctime (&now));
+#if 1
+      /* ??? It would be nice to call print_switch_values here (and thereby
+        let us delete output_options) but this is kept in until it is known
+        whether the change in content format matters.  */
       output_options (file, f_options, f_len, W_options, W_len,
                      pos, 150 - strlen (indent), " ", indent, "]\"\n\n");
+#else
+      fprintf (file, "]\"\n");
+      print_switch_values (file, 0, 150 - strlen (indent),
+                          indent + 3, " ", "]\"\n");
+#endif
     }
 }
 \f
@@ -1568,7 +1641,7 @@ output_ascii (file, opcode, max, p, size)
          fprintf (file, "\\%03o", c);
          num += 4;
        }
-      else if (c >= ' ' && c < 0177)
+      else if ((c >= ' ' && c < 0177) || (c == '\t'))
        {
          putc (c, file);
          num++;
@@ -1579,7 +1652,6 @@ output_ascii (file, opcode, max, p, size)
          switch (c)
            {
              /* Some assemblers can't handle \a, \v, or \?.  */
-           case '\t': c = 't'; goto escape;
            case '\f': c = 'f'; goto escape;
            case '\b': c = 'b'; goto escape;
            case '\r': c = 'r'; goto escape;
@@ -1866,6 +1938,9 @@ m88k_begin_prologue (stream, size)
      FILE *stream;
      int size;
 {
+  if (TARGET_OMIT_LEAF_FRAME_POINTER && ! quiet_flag && leaf_function_p ())
+    fprintf (stderr, "$");
+
   m88k_prologue_done = 1;      /* it's ok now to put out ln directives */
 }
 
@@ -1968,12 +2043,23 @@ m88k_end_epilogue (stream, size)
     PUT_OCS_FUNCTION_END (stream);
 
   /* If the last insn isn't a BARRIER, we must write a return insn.  This
-     should only happen if the function has no prologe and no body.  */
+     should only happen if the function has no prologue and no body.  */
   if (GET_CODE (insn) == NOTE)
     insn = prev_nonnote_insn (insn);
   if (insn == 0 || GET_CODE (insn) != BARRIER)
     fprintf (stream, "\tjmp\t %s\n", reg_names[1]);
 
+  /* If the last insn is a barrier, and the insn before that is a call,
+     then add a nop instruction so that tdesc can walk the stack correctly
+     even though there is no epilogue. (Otherwise, the label for the
+     end of the tdesc region ends up at the start of the next function. */
+  if (insn && GET_CODE (insn) == BARRIER)
+    {
+      insn = prev_nonnote_insn (insn);
+      if (insn && GET_CODE (insn) == CALL_INSN)
+        fprintf (stream, "\tor\t %s,%s,%s\n",reg_names[0],reg_names[0],reg_names[0]);
+    }
+
   output_short_branch_defs (stream);
 
   fprintf (stream, "\n");
@@ -2409,12 +2495,12 @@ output_block_profiler (file, blockno)
   /* @@ Need to deal with PIC.  I'm not sure what the requirements are on
      register usage, so I used r26/r27 to be safe.  */
   fprintf (file, "\tor.u\t %s,%s,%shi16(%s+%d)\n", reg_names[27], reg_names[0],
-                m88k_pound_sign, &block[1], 4 * blockno);
+          m88k_pound_sign, &block[1], 4 * blockno);
   fprintf (file, "\tld\t %s,%s,%slo16(%s+%d)\n", reg_names[26], reg_names[27],
-                m88k_pound_sign, &block[1], 4 * blockno);
+          m88k_pound_sign, &block[1], 4 * blockno);
   fprintf (file, "\taddu\t %s,%s,1\n", reg_names[26], reg_names[26]);
   fprintf (file, "\tst\t %s,%s,%slo16(%s+%d)\n", reg_names[26], reg_names[27],
-                m88k_pound_sign, &block[1], 4 * blockno);
+          m88k_pound_sign, &block[1], 4 * blockno);
 }
 \f
 /* Determine whether a function argument is passed in a register, and
@@ -2500,7 +2586,7 @@ struct rtx_def *
 m88k_builtin_saveregs (arglist)
      tree arglist;
 {
-  rtx block, addr, argsize;
+  rtx block, addr, argsize, dest;
   tree fntype = TREE_TYPE (current_function_decl);
   int argadj = ((!(TYPE_ARG_TYPES (fntype) != 0
                   && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
@@ -2525,6 +2611,7 @@ m88k_builtin_saveregs (arglist)
 
   /* Allocate the va_list constructor */
   block = assign_stack_local (BLKmode, 3 * UNITS_PER_WORD, BITS_PER_WORD);
+  MEM_IN_STRUCT_P (block) = 1;
   RTX_UNCHANGING_P (block) = 1;
   RTX_UNCHANGING_P (XEXP (block, 0)) = 1;
 
@@ -2550,12 +2637,29 @@ m88k_builtin_saveregs (arglist)
 
   /* Now store the incoming registers.  */
   if (fixed < 8)
-      move_block_from_reg
-       (2 + fixed,
-        change_address (addr, Pmode,
-                        plus_constant (XEXP (addr, 0),
-                                       fixed * UNITS_PER_WORD)),
-        8 - fixed);
+    {
+      dest = change_address (addr, Pmode,
+                            plus_constant (XEXP (addr, 0),
+                                           fixed * UNITS_PER_WORD));
+      move_block_from_reg (2 + fixed, dest, 8 - fixed,
+                          UNITS_PER_WORD * (8 - fixed));
+    }
+
+  if (flag_check_memory_usage)
+    {
+      emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
+                        block, ptr_mode,
+                        GEN_INT (3 * UNITS_PER_WORD), TYPE_MODE (sizetype),
+                        GEN_INT (MEMORY_USE_RW),
+                        TYPE_MODE (integer_type_node));
+      if (fixed < 8)
+       emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
+                          dest, ptr_mode,
+                          GEN_INT (UNITS_PER_WORD * (8 - fixed)),
+                          TYPE_MODE (sizetype),
+                          GEN_INT (MEMORY_USE_RW),
+                          TYPE_MODE (integer_type_node));
+    }
 
   /* Return the address of the va_list constructor, but don't put it in a
      register.  This fails when not optimizing and produces worse code when
@@ -2587,17 +2691,15 @@ emit_bcnd (op, label)
      rtx label;
 {
   if (m88k_compare_op1 == const0_rtx)
-    emit_jump_insn (optimize
-                   ? gen_bxx (emit_test (op, VOIDmode), label)
-                   : gen_bcnd (gen_rtx (op, VOIDmode,
-                                        m88k_compare_op0, const0_rtx),
-                               label));
+    emit_jump_insn( gen_bcnd (
+                       gen_rtx (op, VOIDmode,m88k_compare_op0, const0_rtx),
+                       label));
   else if (m88k_compare_op0 == const0_rtx)
-    emit_jump_insn (optimize
-                   ? gen_bxx (emit_test (op, VOIDmode), label)
-                   : gen_bcnd (gen_rtx (swap_condition (op), VOIDmode,
-                                        m88k_compare_op1, const0_rtx),
-                               label));
+    emit_jump_insn( gen_bcnd(
+                     gen_rtx(
+                       swap_condition (op),
+                       VOIDmode, m88k_compare_op1, const0_rtx),
+                     label));
   else if (op != EQ && op != NE)
     emit_jump_insn (gen_bxx (emit_test (op, VOIDmode), label));
   else
@@ -2687,6 +2789,13 @@ print_operand (file, x, code)
             The mechanism below is completed by having CC_STATUS_INIT set
             the code to the unknown value.  */
 
+         /*
+            hassey 6/30/93
+            A problem with 88110 4.1 & 4.2 makes the use of fldcr for
+            this purpose undesirable.  Instead we will use tb1, this will
+            cause serialization on the 88100 but such is life.
+         */
+
          static rtx last_addr = 0;
          if (code == 'V' /* Only need to serialize before a load.  */
              && m88k_volatile_code != 'V' /* Loads complete in FIFO order.  */
@@ -2694,12 +2803,16 @@ print_operand (file, x, code)
                   && GET_CODE (XEXP (x, 0)) == LO_SUM
                   && rtx_equal_p (XEXP (XEXP (x, 0), 1), last_addr)))
            fprintf (file,
+#if 0
 #ifdef AS_BUG_FLDCR
                     "fldcr\t %s,%scr63\n\t",
 #else
                     "fldcr\t %s,%sfcr63\n\t",
 #endif
                     reg_names[0], m88k_pound_sign);
+#else /* 0 */
+                    "tb1\t 1,%s,0xff\n\t", reg_names[0]);
+#endif /* 0 */
          m88k_volatile_code = code;
          last_addr = (GET_CODE (XEXP (x, 0)) == LO_SUM
                       ? XEXP (XEXP (x, 0), 1) : 0);
@@ -2786,6 +2899,10 @@ print_operand (file, x, code)
             ? ".n\t" : "\t", file);
       return;
 
+    case '!': /* Reverse the following condition. */
+      sequencep++;
+      reversep = 1;
+      return; 
     case 'R': /* reverse the condition of the next print_operand
                 if operand is a label_ref.  */
       sequencep++;
@@ -2871,6 +2988,11 @@ print_operand (file, x, code)
        output_address (x);
       else if (xc == MEM)
        output_address (XEXP (x, 0));
+      else if (flag_pic && xc == UNSPEC)
+       {
+         output_addr_const (file, XVECEXP (x, 0, 0));
+         fputs ("#got_rel", file);
+       }
       else if (xc == CONST_DOUBLE)
        output_operand_lossage ("operand is const_double");
       else
@@ -2981,12 +3103,6 @@ print_operand_address (file, addr)
               reg_names[0], reg_names[REGNO (XEXP (addr, 0))]);
       break;
 
-    case LSHIFT:
-      fprintf (file, "%s,%shi16(", reg_names[0], m88k_pound_sign);
-      output_addr_const (file, XEXP (addr, 0));
-      fputc (')', file);
-      break;
-
     case CONST_INT:
       fprintf (file, "%s,%d", reg_names[0], INTVAL (addr));
       break;
@@ -3003,3 +3119,49 @@ print_operand_address (file, addr)
          output_addr_const (file, addr);
     }
 }
+
+/* Return true if X is an address which needs a temporary register when 
+   reloaded while generating PIC code.  */
+
+int
+pic_address_needs_scratch (x)
+     rtx x;
+{
+  /* An address which is a symbolic plus a non SMALL_INT needs a temp reg.  */
+  if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
+      && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
+      && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
+      && ! ADD_INT (XEXP (XEXP (x, 0), 1)))
+    return 1;
+
+  return 0;
+}
+
+/* Returns 1 if OP is either a symbol reference or a sum of a symbol
+   reference and a constant.  */
+
+int
+symbolic_operand (op, mode)
+     register rtx op;
+     enum machine_mode mode;
+{
+  switch (GET_CODE (op))
+    {
+    case SYMBOL_REF:
+    case LABEL_REF:
+      return 1;
+
+    case CONST:
+      op = XEXP (op, 0);
+      return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
+               || GET_CODE (XEXP (op, 0)) == LABEL_REF)
+              && GET_CODE (XEXP (op, 1)) == CONST_INT);
+
+      /* ??? This clause seems to be irrelevant.  */
+    case CONST_DOUBLE:
+      return GET_MODE (op) == mode;
+
+    default:
+      return 0;
+    }
+}