Back to index

cell-binutils  2.17cvs20070401
tc-frv.c
Go to the documentation of this file.
00001 /* tc-frv.c -- Assembler for the Fujitsu FRV.
00002    Copyright 2002, 2003, 2004, 2005, 2006 Free Software Foundation.
00003 
00004    This file is part of GAS, the GNU Assembler.
00005 
00006    GAS is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2, or (at your option)
00009    any later version.
00010 
00011    GAS is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014    GNU General Public License for more details.
00015 
00016    You should have received a copy of the GNU General Public License
00017    along with GAS; see the file COPYING.  If not, write to
00018    the Free Software Foundation, 51 Franklin Street - Fifth Floor,
00019    Boston, MA 02110-1301, USA.  */
00020 
00021 #include "as.h"
00022 #include "subsegs.h"     
00023 #include "symcat.h"
00024 #include "opcodes/frv-desc.h"
00025 #include "opcodes/frv-opc.h"
00026 #include "cgen.h"
00027 #include "libbfd.h"
00028 #include "elf/common.h"
00029 #include "elf/frv.h"
00030 
00031 /* Structure to hold all of the different components describing
00032    an individual instruction.  */
00033 typedef struct
00034 {
00035   const CGEN_INSN *  insn;
00036   const CGEN_INSN *  orig_insn;
00037   CGEN_FIELDS        fields;
00038 #if CGEN_INT_INSN_P
00039   CGEN_INSN_INT         buffer [1];
00040 #define INSN_VALUE(buf) (*(buf))
00041 #else
00042   unsigned char         buffer [CGEN_MAX_INSN_SIZE];
00043 #define INSN_VALUE(buf) (buf)
00044 #endif
00045   char *             addr;
00046   fragS *            frag;
00047   int                   num_fixups;
00048   fixS *                fixups [GAS_CGEN_MAX_FIXUPS];
00049   int                   indices [MAX_OPERAND_INSTANCES];
00050 }
00051 frv_insn;
00052 
00053 enum vliw_insn_type
00054 {
00055   VLIW_GENERIC_TYPE,        /* Don't care about this insn.  */
00056   VLIW_BRANCH_TYPE,         /* A Branch.  */
00057   VLIW_LABEL_TYPE,          /* A Label.  */
00058   VLIW_NOP_TYPE,            /* A NOP.  */
00059   VLIW_BRANCH_HAS_NOPS             /* A Branch that requires NOPS.  */
00060 };
00061 
00062 /* We're going to use these in the fr_subtype field to mark 
00063    whether to keep inserted nops.  */
00064 
00065 #define NOP_KEEP 1          /* Keep these NOPS.  */
00066 #define NOP_DELETE 2        /* Delete these NOPS.  */
00067 
00068 #define DO_COUNT    TRUE
00069 #define DONT_COUNT  FALSE
00070 
00071 /* A list of insns within a VLIW insn.  */
00072 struct vliw_insn_list
00073 {
00074   /*  The type of this insn.  */
00075   enum vliw_insn_type       type;
00076 
00077   /*  The corresponding gas insn information.  */
00078   const CGEN_INSN    *insn;
00079 
00080   /*  For branches and labels, the symbol that is referenced.  */
00081   symbolS            *sym;
00082 
00083   /*  For branches, the frag containing the single nop that was generated.  */
00084   fragS                     *snop_frag;
00085 
00086   /*  For branches, the frag containing the double nop that was generated.  */
00087   fragS                     *dnop_frag;
00088 
00089   /*  Pointer to raw data for this insn.  */
00090   char               *address;
00091 
00092   /* Next insn in list.  */
00093   struct vliw_insn_list *next;
00094 };
00095 
00096 static struct vliw_insn_list single_nop_insn = {
00097    VLIW_NOP_TYPE, NULL, NULL, NULL, NULL, NULL, NULL };
00098 
00099 static struct vliw_insn_list double_nop_insn = {
00100    VLIW_NOP_TYPE, NULL, NULL, NULL, NULL, NULL, NULL };
00101 
00102 struct vliw_chain
00103 {
00104   int                num;
00105   int                insn_count;
00106   struct vliw_insn_list *insn_list;
00107   struct vliw_chain     *next;
00108 };
00109 
00110 static struct vliw_chain    *vliw_chain_top;
00111 static struct vliw_chain    *current_vliw_chain;
00112 static struct vliw_chain    *previous_vliw_chain;
00113 static struct vliw_insn_list       *current_vliw_insn;
00114 
00115 const char comment_chars[]        = ";";
00116 const char line_comment_chars[]   = "#";
00117 const char line_separator_chars[] = "!"; 
00118 const char EXP_CHARS[]            = "eE";
00119 const char FLT_CHARS[]            = "dD";
00120 
00121 static FRV_VLIW vliw;
00122 
00123 /* Default machine */
00124 
00125 #ifdef  DEFAULT_CPU_FRV
00126 #define DEFAULT_MACHINE bfd_mach_frv
00127 #define DEFAULT_FLAGS       EF_FRV_CPU_GENERIC
00128 
00129 #else
00130 #ifdef  DEFAULT_CPU_FR300
00131 #define DEFAULT_MACHINE     bfd_mach_fr300
00132 #define DEFAULT_FLAGS       EF_FRV_CPU_FR300
00133 
00134 #else
00135 #ifdef DEFAULT_CPU_SIMPLE
00136 #define       DEFAULT_MACHINE bfd_mach_frvsimple
00137 #define DEFAULT_FLAGS       EF_FRV_CPU_SIMPLE
00138 
00139 #else
00140 #ifdef DEFAULT_CPU_TOMCAT
00141 #define       DEFAULT_MACHINE bfd_mach_frvtomcat
00142 #define DEFAULT_FLAGS       EF_FRV_CPU_TOMCAT
00143 
00144 #else
00145 #ifdef  DEFAULT_CPU_FR400
00146 #define DEFAULT_MACHINE     bfd_mach_fr400
00147 #define DEFAULT_FLAGS       EF_FRV_CPU_FR400
00148 
00149 #else
00150 #ifdef  DEFAULT_CPU_FR550
00151 #define DEFAULT_MACHINE     bfd_mach_fr550
00152 #define DEFAULT_FLAGS       EF_FRV_CPU_FR550
00153 
00154 #else
00155 #define DEFAULT_MACHINE     bfd_mach_fr500
00156 #define DEFAULT_FLAGS       EF_FRV_CPU_FR500
00157 #endif
00158 #endif
00159 #endif
00160 #endif
00161 #endif
00162 #endif
00163 
00164 #ifdef TE_LINUX
00165 # define DEFAULT_FDPIC      EF_FRV_FDPIC
00166 #else
00167 # define DEFAULT_FDPIC      0
00168 #endif
00169 
00170 static unsigned long frv_mach = bfd_mach_frv;
00171 static bfd_boolean fr400_audio;
00172 
00173 /* Flags to set in the elf header */
00174 static flagword frv_flags = DEFAULT_FLAGS | DEFAULT_FDPIC;
00175 
00176 static int frv_user_set_flags_p = 0;
00177 static int frv_pic_p = 0;
00178 static const char *frv_pic_flag = DEFAULT_FDPIC ? "-mfdpic" : (const char *)0;
00179 
00180 /* Print tomcat-specific debugging info.  */
00181 static int tomcat_debug = 0;
00182 
00183 /* Tomcat-specific NOP statistics.  */
00184 static int tomcat_stats = 0;
00185 static int tomcat_doubles = 0;
00186 static int tomcat_singles = 0;
00187 
00188 /* Forward reference to static functions */
00189 static void frv_set_flags          PARAMS ((int));
00190 static void frv_pic_ptr                   PARAMS ((int));
00191 static void frv_frob_file_section  PARAMS ((bfd *, asection *, PTR));
00192 
00193 /* The target specific pseudo-ops which we support.  */
00194 const pseudo_typeS md_pseudo_table[] =
00195 {
00196   { "eflags", frv_set_flags,              0 },
00197   { "word",   cons,                4 },
00198   { "picptr", frv_pic_ptr,         4 },
00199   { NULL,     NULL,                0 }
00200 };
00201 
00202 
00203 #define FRV_SHORTOPTS "G:"
00204 const char * md_shortopts = FRV_SHORTOPTS;
00205 
00206 #define OPTION_GPR_32              (OPTION_MD_BASE)
00207 #define OPTION_GPR_64              (OPTION_MD_BASE + 1)
00208 #define OPTION_FPR_32              (OPTION_MD_BASE + 2)
00209 #define OPTION_FPR_64              (OPTION_MD_BASE + 3)
00210 #define OPTION_SOFT_FLOAT   (OPTION_MD_BASE + 4)
00211 #define OPTION_DWORD_YES    (OPTION_MD_BASE + 5)
00212 #define OPTION_DWORD_NO            (OPTION_MD_BASE + 6)
00213 #define OPTION_DOUBLE              (OPTION_MD_BASE + 7)
00214 #define OPTION_NO_DOUBLE    (OPTION_MD_BASE + 8)
00215 #define OPTION_MEDIA        (OPTION_MD_BASE + 9)
00216 #define OPTION_NO_MEDIA            (OPTION_MD_BASE + 10)
00217 #define OPTION_CPU          (OPTION_MD_BASE + 11)
00218 #define OPTION_PIC          (OPTION_MD_BASE + 12)
00219 #define OPTION_BIGPIC              (OPTION_MD_BASE + 13)
00220 #define OPTION_LIBPIC              (OPTION_MD_BASE + 14)
00221 #define OPTION_MULADD              (OPTION_MD_BASE + 15)
00222 #define OPTION_NO_MULADD    (OPTION_MD_BASE + 16)
00223 #define OPTION_TOMCAT_DEBUG (OPTION_MD_BASE + 17)
00224 #define OPTION_TOMCAT_STATS (OPTION_MD_BASE + 18)
00225 #define OPTION_PACK          (OPTION_MD_BASE + 19)
00226 #define OPTION_NO_PACK              (OPTION_MD_BASE + 20)
00227 #define OPTION_FDPIC        (OPTION_MD_BASE + 21)
00228 #define OPTION_NOPIC        (OPTION_MD_BASE + 22)
00229 
00230 struct option md_longopts[] =
00231 {
00232   { "mgpr-32",              no_argument,         NULL, OPTION_GPR_32        },
00233   { "mgpr-64",              no_argument,         NULL, OPTION_GPR_64        },
00234   { "mfpr-32",              no_argument,         NULL, OPTION_FPR_32        },
00235   { "mfpr-64",              no_argument,         NULL, OPTION_FPR_64        },
00236   { "mhard-float",   no_argument,         NULL, OPTION_FPR_64        },
00237   { "msoft-float",   no_argument,         NULL, OPTION_SOFT_FLOAT    },
00238   { "mdword",        no_argument,         NULL, OPTION_DWORD_YES     },
00239   { "mno-dword",     no_argument,         NULL, OPTION_DWORD_NO      },
00240   { "mdouble",              no_argument,         NULL, OPTION_DOUBLE        },
00241   { "mno-double",    no_argument,         NULL, OPTION_NO_DOUBLE     },
00242   { "mmedia",        no_argument,         NULL, OPTION_MEDIA         },
00243   { "mno-media",     no_argument,         NULL, OPTION_NO_MEDIA      },
00244   { "mcpu",          required_argument,   NULL, OPTION_CPU           },
00245   { "mpic",          no_argument,         NULL, OPTION_PIC           },
00246   { "mPIC",          no_argument,         NULL, OPTION_BIGPIC        },
00247   { "mlibrary-pic",  no_argument,         NULL, OPTION_LIBPIC        },
00248   { "mmuladd",              no_argument,         NULL, OPTION_MULADD        },
00249   { "mno-muladd",    no_argument,         NULL, OPTION_NO_MULADD     },
00250   { "mtomcat-debug",    no_argument,            NULL, OPTION_TOMCAT_DEBUG  },
00251   { "mtomcat-stats", no_argument,         NULL, OPTION_TOMCAT_STATS  },
00252   { "mpack",         no_argument,         NULL, OPTION_PACK          },
00253   { "mno-pack",             no_argument,         NULL, OPTION_NO_PACK       },
00254   { "mfdpic",        no_argument,         NULL, OPTION_FDPIC      },
00255   { "mnopic",        no_argument,         NULL, OPTION_NOPIC      },
00256   { NULL,            no_argument,         NULL, 0                 },
00257 };
00258 
00259 size_t md_longopts_size = sizeof (md_longopts);
00260 
00261 /* What value to give to bfd_set_gp_size.  */
00262 static int g_switch_value = 8;
00263 
00264 int
00265 md_parse_option (c, arg)
00266      int    c;
00267      char * arg;
00268 {
00269   switch (c)
00270     {
00271     default:
00272       return 0;
00273 
00274     case 'G':
00275       g_switch_value = atoi (arg);
00276       if (! g_switch_value)
00277        frv_flags |= EF_FRV_G0;
00278       break;
00279 
00280     case OPTION_GPR_32:
00281       frv_flags = (frv_flags & ~EF_FRV_GPR_MASK) | EF_FRV_GPR_32;
00282       break;
00283 
00284     case OPTION_GPR_64:
00285       frv_flags = (frv_flags & ~EF_FRV_GPR_MASK) | EF_FRV_GPR_64;
00286       break;
00287 
00288     case OPTION_FPR_32:
00289       frv_flags = (frv_flags & ~EF_FRV_FPR_MASK) | EF_FRV_FPR_32;
00290       break;
00291 
00292     case OPTION_FPR_64:
00293       frv_flags = (frv_flags & ~EF_FRV_FPR_MASK) | EF_FRV_FPR_64;
00294       break;
00295 
00296     case OPTION_SOFT_FLOAT:
00297       frv_flags = (frv_flags & ~EF_FRV_FPR_MASK) | EF_FRV_FPR_NONE;
00298       break;
00299 
00300     case OPTION_DWORD_YES:
00301       frv_flags = (frv_flags & ~EF_FRV_DWORD_MASK) | EF_FRV_DWORD_YES;
00302       break;
00303 
00304     case OPTION_DWORD_NO:
00305       frv_flags = (frv_flags & ~EF_FRV_DWORD_MASK) | EF_FRV_DWORD_NO;
00306       break;
00307 
00308     case OPTION_DOUBLE:
00309       frv_flags |= EF_FRV_DOUBLE;
00310       break;
00311 
00312     case OPTION_NO_DOUBLE:
00313       frv_flags &= ~EF_FRV_DOUBLE;
00314       break;
00315 
00316     case OPTION_MEDIA:
00317       frv_flags |= EF_FRV_MEDIA;
00318       break;
00319 
00320     case OPTION_NO_MEDIA:
00321       frv_flags &= ~EF_FRV_MEDIA;
00322       break;
00323 
00324     case OPTION_MULADD:
00325       frv_flags |= EF_FRV_MULADD;
00326       break;
00327 
00328     case OPTION_NO_MULADD:
00329       frv_flags &= ~EF_FRV_MULADD;
00330       break;
00331 
00332     case OPTION_PACK:
00333       frv_flags &= ~EF_FRV_NOPACK;
00334       break;
00335 
00336     case OPTION_NO_PACK:
00337       frv_flags |= EF_FRV_NOPACK;
00338       break;
00339 
00340     case OPTION_CPU:
00341       {
00342        char *p;
00343        int cpu_flags = EF_FRV_CPU_GENERIC;
00344 
00345        /* Identify the processor type */
00346        p = arg;
00347        if (strcmp (p, "frv") == 0)
00348          {
00349            cpu_flags = EF_FRV_CPU_GENERIC;
00350            frv_mach = bfd_mach_frv;
00351          }
00352 
00353        else if (strcmp (p, "fr500") == 0)
00354          {
00355            cpu_flags = EF_FRV_CPU_FR500;
00356            frv_mach = bfd_mach_fr500;
00357          }
00358 
00359        else if (strcmp (p, "fr550") == 0)
00360          {
00361            cpu_flags = EF_FRV_CPU_FR550;
00362            frv_mach = bfd_mach_fr550;
00363          }
00364 
00365        else if (strcmp (p, "fr450") == 0)
00366          {
00367            cpu_flags = EF_FRV_CPU_FR450;
00368            frv_mach = bfd_mach_fr450;
00369          }
00370 
00371        else if (strcmp (p, "fr405") == 0)
00372          {
00373            cpu_flags = EF_FRV_CPU_FR405;
00374            frv_mach = bfd_mach_fr400;
00375            fr400_audio = TRUE;
00376          }
00377 
00378        else if (strcmp (p, "fr400") == 0)
00379          {
00380            cpu_flags = EF_FRV_CPU_FR400;
00381            frv_mach = bfd_mach_fr400;
00382            fr400_audio = FALSE;
00383          }
00384 
00385        else if (strcmp (p, "fr300") == 0)
00386          {
00387            cpu_flags = EF_FRV_CPU_FR300;
00388            frv_mach = bfd_mach_fr300;
00389          }
00390 
00391        else if (strcmp (p, "simple") == 0)
00392          {
00393            cpu_flags = EF_FRV_CPU_SIMPLE;
00394            frv_mach = bfd_mach_frvsimple;
00395            frv_flags |= EF_FRV_NOPACK;
00396          }
00397 
00398         else if (strcmp (p, "tomcat") == 0)
00399           {
00400             cpu_flags = EF_FRV_CPU_TOMCAT;
00401             frv_mach = bfd_mach_frvtomcat;
00402           }
00403 
00404        else
00405          {
00406            as_fatal ("Unknown cpu -mcpu=%s", arg);
00407            return 0;
00408          }
00409 
00410        frv_flags = (frv_flags & ~EF_FRV_CPU_MASK) | cpu_flags;
00411       }
00412       break;
00413 
00414     case OPTION_PIC:
00415       frv_flags |= EF_FRV_PIC;
00416       frv_pic_p = 1;
00417       frv_pic_flag = "-fpic";
00418       break;
00419 
00420     case OPTION_BIGPIC:
00421       frv_flags |= EF_FRV_BIGPIC;
00422       frv_pic_p = 1;
00423       frv_pic_flag = "-fPIC";
00424       break;
00425 
00426     case OPTION_LIBPIC:
00427       frv_flags |= (EF_FRV_LIBPIC | EF_FRV_G0);
00428       frv_pic_p = 1;
00429       frv_pic_flag = "-mlibrary-pic";
00430       g_switch_value = 0;
00431       break;
00432 
00433     case OPTION_FDPIC:
00434       frv_flags |= EF_FRV_FDPIC;
00435       frv_pic_flag = "-mfdpic";
00436       break;
00437 
00438     case OPTION_NOPIC:
00439       frv_flags &= ~(EF_FRV_FDPIC | EF_FRV_PIC
00440                    | EF_FRV_BIGPIC | EF_FRV_LIBPIC);
00441       frv_pic_flag = 0;
00442       break;
00443 
00444     case OPTION_TOMCAT_DEBUG:
00445       tomcat_debug = 1;
00446       break;
00447 
00448     case OPTION_TOMCAT_STATS:
00449       tomcat_stats = 1;
00450       break;
00451     }
00452 
00453   return 1;
00454 }
00455 
00456 void
00457 md_show_usage (stream)
00458   FILE * stream;
00459 {
00460   fprintf (stream, _("FRV specific command line options:\n"));
00461   fprintf (stream, _("-G n         Data >= n bytes is in small data area\n"));
00462   fprintf (stream, _("-mgpr-32     Note 32 gprs are used\n"));
00463   fprintf (stream, _("-mgpr-64     Note 64 gprs are used\n"));
00464   fprintf (stream, _("-mfpr-32     Note 32 fprs are used\n"));
00465   fprintf (stream, _("-mfpr-64     Note 64 fprs are used\n"));
00466   fprintf (stream, _("-msoft-float Note software fp is used\n"));
00467   fprintf (stream, _("-mdword      Note stack is aligned to a 8 byte boundary\n"));
00468   fprintf (stream, _("-mno-dword   Note stack is aligned to a 4 byte boundary\n"));
00469   fprintf (stream, _("-mdouble     Note fp double insns are used\n"));
00470   fprintf (stream, _("-mmedia      Note media insns are used\n"));
00471   fprintf (stream, _("-mmuladd     Note multiply add/subtract insns are used\n"));
00472   fprintf (stream, _("-mpack       Note instructions are packed\n"));
00473   fprintf (stream, _("-mno-pack    Do not allow instructions to be packed\n"));
00474   fprintf (stream, _("-mpic        Note small position independent code\n"));
00475   fprintf (stream, _("-mPIC        Note large position independent code\n"));
00476   fprintf (stream, _("-mlibrary-pic Compile library for large position indepedent code\n"));
00477   fprintf (stream, _("-mfdpic      Assemble for the FDPIC ABI\n"));
00478   fprintf (stream, _("-mnopic      Disable -mpic, -mPIC, -mlibrary-pic and -mfdpic\n"));
00479   fprintf (stream, _("-mcpu={fr500|fr550|fr400|fr405|fr450|fr300|frv|simple|tomcat}\n"));
00480   fprintf (stream, _("             Record the cpu type\n"));
00481   fprintf (stream, _("-mtomcat-stats Print out stats for tomcat workarounds\n"));
00482   fprintf (stream, _("-mtomcat-debug Debug tomcat workarounds\n"));
00483 } 
00484 
00485 
00486 void
00487 md_begin ()
00488 {
00489   /* Initialize the `cgen' interface.  */
00490   
00491   /* Set the machine number and endian.  */
00492   gas_cgen_cpu_desc = frv_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
00493                                     CGEN_CPU_OPEN_ENDIAN,
00494                                     CGEN_ENDIAN_BIG,
00495                                     CGEN_CPU_OPEN_END);
00496   frv_cgen_init_asm (gas_cgen_cpu_desc);
00497 
00498   /* This is a callback from cgen to gas to parse operands.  */
00499   cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
00500 
00501   /* Set the ELF flags if desired. */
00502   if (frv_flags)
00503     bfd_set_private_flags (stdoutput, frv_flags);
00504 
00505   /* Set the machine type */
00506   bfd_default_set_arch_mach (stdoutput, bfd_arch_frv, frv_mach);
00507 
00508   /* Set up gp size so we can put local common items in .sbss */
00509   bfd_set_gp_size (stdoutput, g_switch_value);
00510 
00511   frv_vliw_reset (& vliw, frv_mach, frv_flags);
00512 }
00513 
00514 bfd_boolean
00515 frv_md_fdpic_enabled (void)
00516 {
00517   return (frv_flags & EF_FRV_FDPIC) != 0;
00518 }
00519 
00520 int chain_num = 0;
00521 
00522 struct vliw_insn_list *frv_insert_vliw_insn PARAMS ((bfd_boolean));
00523 
00524 struct vliw_insn_list *
00525 frv_insert_vliw_insn (count)
00526       bfd_boolean count;
00527 {
00528   struct vliw_insn_list *vliw_insn_list_entry;
00529   struct vliw_chain     *vliw_chain_entry;
00530 
00531   if (current_vliw_chain == NULL)
00532     {
00533       vliw_chain_entry = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
00534       vliw_chain_entry->insn_count = 0;
00535       vliw_chain_entry->insn_list  = NULL;
00536       vliw_chain_entry->next       = NULL;
00537       vliw_chain_entry->num        = chain_num++;
00538 
00539       if (!vliw_chain_top)
00540        vliw_chain_top = vliw_chain_entry;
00541       current_vliw_chain = vliw_chain_entry;
00542       if (previous_vliw_chain)
00543        previous_vliw_chain->next = vliw_chain_entry;
00544     }
00545 
00546   vliw_insn_list_entry = (struct vliw_insn_list *) xmalloc (sizeof (struct vliw_insn_list));
00547   vliw_insn_list_entry->type      = VLIW_GENERIC_TYPE;
00548   vliw_insn_list_entry->insn      = NULL;
00549   vliw_insn_list_entry->sym       = NULL;
00550   vliw_insn_list_entry->snop_frag = NULL;
00551   vliw_insn_list_entry->dnop_frag = NULL;
00552   vliw_insn_list_entry->next      = NULL;
00553 
00554   if (count)
00555     current_vliw_chain->insn_count++;
00556 
00557   if (current_vliw_insn)
00558     current_vliw_insn->next = vliw_insn_list_entry;
00559   current_vliw_insn = vliw_insn_list_entry;
00560 
00561   if (!current_vliw_chain->insn_list)
00562     current_vliw_chain->insn_list = current_vliw_insn;
00563 
00564   return vliw_insn_list_entry;
00565 }
00566 
00567   /* Identify the following cases:
00568  
00569      1) A VLIW insn that contains both a branch and the branch destination.
00570         This requires the insertion of two vliw instructions before the
00571         branch.  The first consists of two nops.  The second consists of
00572         a single nop.
00573  
00574      2) A single instruction VLIW insn which is the destination of a branch
00575         that is in the next VLIW insn.  This requires the insertion of a vliw
00576         insn containing two nops before the branch.
00577  
00578      3) A double instruction VLIW insn which contains the destination of a
00579         branch that is in the next VLIW insn.  This requires the insertion of
00580         a VLIW insn containing a single nop before the branch.
00581  
00582      4) A single instruction VLIW insn which contains branch destination (x),
00583         followed by a single instruction VLIW insn which does not contain
00584         the branch to (x), followed by a VLIW insn which does contain the branch
00585         to (x).  This requires the insertion of a VLIW insn containing a single
00586         nop before the VLIW instruction containing the branch.
00587  
00588   */
00589 #define FRV_IS_NOP(insn) (insn.buffer[0] == FRV_NOP_PACK || insn.buffer[0] == FRV_NOP_NOPACK)
00590 #define FRV_NOP_PACK   0x00880000  /* ori.p  gr0,0,gr0 */
00591 #define FRV_NOP_NOPACK 0x80880000  /* ori    gr0,0,gr0 */
00592 
00593 /* Check a vliw insn for an insn of type containing the sym passed in label_sym.  */
00594 
00595 static struct vliw_insn_list *frv_find_in_vliw
00596   PARAMS ((enum vliw_insn_type, struct vliw_chain *, symbolS *));
00597 
00598 static struct vliw_insn_list *
00599 frv_find_in_vliw (vliw_insn_type, this_chain, label_sym)
00600     enum vliw_insn_type vliw_insn_type;
00601     struct vliw_chain *this_chain;
00602     symbolS *label_sym;
00603 {
00604 
00605   struct vliw_insn_list *the_insn;
00606 
00607   if (!this_chain)
00608     return NULL;
00609 
00610   for (the_insn = this_chain->insn_list; the_insn; the_insn = the_insn->next)
00611     {
00612       if (the_insn->type == vliw_insn_type
00613          && the_insn->sym == label_sym)
00614        return the_insn;
00615     }
00616 
00617   return NULL;
00618 }
00619 
00620 enum vliw_nop_type
00621 {
00622   /* A Vliw insn containing a single nop insn.  */
00623   VLIW_SINGLE_NOP,
00624   
00625   /* A Vliw insn containing two nop insns.  */
00626   VLIW_DOUBLE_NOP,
00627 
00628   /* Two vliw insns.  The first containing two nop insns.  
00629      The second contain a single nop insn.  */
00630   VLIW_DOUBLE_THEN_SINGLE_NOP
00631 };
00632 
00633 static void frv_debug_tomcat PARAMS ((struct vliw_chain *));
00634 
00635 static void
00636 frv_debug_tomcat (start_chain)
00637    struct vliw_chain *start_chain;
00638 {
00639    struct vliw_chain *this_chain;
00640    struct vliw_insn_list *this_insn;
00641    int i = 1;
00642 
00643   for (this_chain = start_chain; this_chain; this_chain = this_chain->next, i++)
00644     {
00645       fprintf (stderr, "\nVliw Insn #%d, #insns: %d\n", i, this_chain->insn_count);
00646 
00647       for (this_insn = this_chain->insn_list; this_insn; this_insn = this_insn->next)
00648        {
00649          if (this_insn->type == VLIW_LABEL_TYPE)
00650            fprintf (stderr, "Label Value: %p\n", this_insn->sym);
00651          else if (this_insn->type == VLIW_BRANCH_TYPE)
00652            fprintf (stderr, "%s to %p\n", this_insn->insn->base->name, this_insn->sym);
00653          else if (this_insn->type == VLIW_BRANCH_HAS_NOPS)
00654            fprintf (stderr, "nop'd %s to %p\n", this_insn->insn->base->name, this_insn->sym);
00655          else if (this_insn->type == VLIW_NOP_TYPE)
00656            fprintf (stderr, "Nop\n");
00657          else
00658            fprintf (stderr, "      %s\n", this_insn->insn->base->name);
00659        }
00660    }
00661 }
00662 
00663 static void frv_adjust_vliw_count PARAMS ((struct vliw_chain *));
00664 
00665 static void
00666 frv_adjust_vliw_count (this_chain)
00667     struct vliw_chain *this_chain;
00668 {
00669   struct vliw_insn_list *this_insn;
00670 
00671   this_chain->insn_count = 0;
00672 
00673   for (this_insn = this_chain->insn_list;
00674        this_insn;
00675        this_insn = this_insn->next)
00676     {
00677       if (this_insn->type != VLIW_LABEL_TYPE)
00678        this_chain->insn_count++;
00679     }
00680 
00681 }
00682 
00683 /* Insert the desired nop combination in the vliw chain before insert_before_insn.
00684    Rechain the vliw insn.  */
00685 
00686 static struct vliw_chain *frv_tomcat_shuffle
00687   PARAMS ((enum vliw_nop_type, struct vliw_chain *, struct vliw_insn_list *));
00688 
00689 static struct vliw_chain *
00690 frv_tomcat_shuffle (this_nop_type, vliw_to_split, insert_before_insn)
00691    enum vliw_nop_type    this_nop_type;
00692    struct vliw_chain     *vliw_to_split;
00693    struct vliw_insn_list *insert_before_insn;
00694 {
00695 
00696   bfd_boolean pack_prev = FALSE;
00697   struct vliw_chain *return_me = NULL;
00698   struct vliw_insn_list *prev_insn = NULL;
00699   struct vliw_insn_list *curr_insn = vliw_to_split->insn_list;
00700 
00701   struct vliw_chain *double_nop = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
00702   struct vliw_chain *single_nop = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
00703   struct vliw_chain *second_part = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
00704   struct vliw_chain *curr_vliw = vliw_chain_top;
00705   struct vliw_chain *prev_vliw = NULL;
00706 
00707   while (curr_insn && curr_insn != insert_before_insn)
00708     {
00709       /* We can't set the packing bit on a label.  If we have the case
00710         label 1:
00711         label 2:
00712         label 3:
00713           branch that needs nops
00714        Then don't set pack bit later.  */
00715 
00716       if (curr_insn->type != VLIW_LABEL_TYPE)
00717        pack_prev = TRUE;
00718       prev_insn = curr_insn;
00719       curr_insn = curr_insn->next;
00720     } 
00721 
00722   while (curr_vliw && curr_vliw != vliw_to_split)
00723     {
00724       prev_vliw = curr_vliw;
00725       curr_vliw = curr_vliw->next;
00726     }
00727 
00728   switch (this_nop_type)
00729     {
00730     case VLIW_SINGLE_NOP:
00731       if (!prev_insn)
00732        {
00733        /* Branch is first,  Insert the NOP prior to this vliw insn.  */
00734        if (prev_vliw)
00735          prev_vliw->next = single_nop;
00736        else
00737          vliw_chain_top = single_nop;
00738        single_nop->next = vliw_to_split;
00739        vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
00740        return_me = vliw_to_split;
00741        }
00742       else
00743        {
00744          /* Set the packing bit on the previous insn.  */
00745          if (pack_prev)
00746            {
00747              char *buffer = prev_insn->address;
00748              buffer[0] |= 0x80;
00749            }
00750          /* The branch is in the middle.  Split this vliw insn into first
00751             and second parts.  Insert the NOP inbetween.  */
00752 
00753           second_part->insn_list = insert_before_insn;
00754          second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
00755           second_part->next      = vliw_to_split->next;
00756          frv_adjust_vliw_count (second_part);
00757 
00758           single_nop->next       = second_part;
00759  
00760           vliw_to_split->next    = single_nop;
00761           prev_insn->next        = NULL;
00762  
00763           return_me = second_part;
00764          frv_adjust_vliw_count (vliw_to_split);
00765        }
00766       break;
00767 
00768     case VLIW_DOUBLE_NOP:
00769       if (!prev_insn)
00770        {
00771        /* Branch is first,  Insert the NOP prior to this vliw insn.  */
00772         if (prev_vliw)
00773           prev_vliw->next = double_nop;
00774         else
00775           vliw_chain_top = double_nop;
00776 
00777        double_nop->next = vliw_to_split;
00778        return_me = vliw_to_split;
00779        vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
00780        }
00781       else
00782        {
00783          /* Set the packing bit on the previous insn.  */
00784          if (pack_prev)
00785            {
00786              char *buffer = prev_insn->address;
00787              buffer[0] |= 0x80;
00788            }
00789 
00790        /* The branch is in the middle.  Split this vliw insn into first
00791           and second parts.  Insert the NOP inbetween.  */
00792           second_part->insn_list = insert_before_insn;
00793          second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
00794           second_part->next      = vliw_to_split->next;
00795          frv_adjust_vliw_count (second_part);
00796  
00797           double_nop->next       = second_part;
00798  
00799           vliw_to_split->next    = single_nop;
00800           prev_insn->next        = NULL;
00801          frv_adjust_vliw_count (vliw_to_split);
00802  
00803           return_me = second_part;
00804        }
00805       break;
00806 
00807     case VLIW_DOUBLE_THEN_SINGLE_NOP:
00808       double_nop->next = single_nop;
00809       double_nop->insn_count = 2;
00810       double_nop->insn_list = &double_nop_insn;
00811       single_nop->insn_count = 1;
00812       single_nop->insn_list = &single_nop_insn;
00813 
00814       if (!prev_insn)
00815        {
00816          /* The branch is the first insn in this vliw.  Don't split the vliw.  Insert
00817             the nops prior to this vliw.  */
00818           if (prev_vliw)
00819             prev_vliw->next = double_nop;
00820           else
00821             vliw_chain_top = double_nop;
00822  
00823          single_nop->next = vliw_to_split;
00824          return_me = vliw_to_split;
00825          vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
00826        }
00827       else
00828        {
00829          /* Set the packing bit on the previous insn.  */
00830          if (pack_prev)
00831            {
00832              char *buffer = prev_insn->address;
00833              buffer[0] |= 0x80;
00834            }
00835 
00836          /* The branch is in the middle of this vliw insn.  Split into first and
00837             second parts.  Insert the nop vliws in between.  */  
00838          second_part->insn_list = insert_before_insn;
00839          second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
00840          second_part->next      = vliw_to_split->next;
00841          frv_adjust_vliw_count (second_part);
00842 
00843          single_nop->next       = second_part;
00844 
00845          vliw_to_split->next        = double_nop;
00846          prev_insn->next     = NULL;
00847          frv_adjust_vliw_count (vliw_to_split);
00848 
00849          return_me = second_part;
00850        }
00851       break;
00852     }
00853 
00854   return return_me;
00855 }
00856 
00857 static void frv_tomcat_analyze_vliw_chains PARAMS ((void));
00858 
00859 static void
00860 frv_tomcat_analyze_vliw_chains ()
00861 {
00862   struct vliw_chain *vliw1 = NULL;
00863   struct vliw_chain *vliw2 = NULL;
00864   struct vliw_chain *vliw3 = NULL;
00865 
00866   struct vliw_insn_list *this_insn = NULL;
00867   struct vliw_insn_list *temp_insn = NULL;
00868 
00869   /* We potentially need to look at three VLIW insns to determine if the
00870      workaround is required.  Set them up.  Ignore existing nops during analysis. */
00871 
00872 #define FRV_SET_VLIW_WINDOW(VLIW1, VLIW2, VLIW3) \
00873   if (VLIW1 && VLIW1->next)                \
00874     VLIW2 = VLIW1->next;                   \
00875   else                                     \
00876     VLIW2 = NULL;                          \
00877   if (VLIW2 && VLIW2->next)                \
00878     VLIW3 = VLIW2->next;                   \
00879   else                                     \
00880     VLIW3 = NULL
00881 
00882   vliw1 = vliw_chain_top;
00883 
00884 workaround_top:
00885 
00886   FRV_SET_VLIW_WINDOW (vliw1, vliw2, vliw3);
00887 
00888   if (!vliw1)
00889     return;
00890 
00891   if (vliw1->insn_count == 1)
00892     {
00893       /* check vliw1 for a label. */
00894       if (vliw1->insn_list->type == VLIW_LABEL_TYPE)
00895        {
00896          temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw2, vliw1->insn_list->sym);
00897          if (temp_insn)
00898            {
00899              vliw1 = frv_tomcat_shuffle (VLIW_DOUBLE_NOP, vliw2, vliw1->insn_list);
00900              temp_insn->dnop_frag->fr_subtype = NOP_KEEP;
00901              vliw1 = vliw1->next;
00902              if (tomcat_stats)
00903               tomcat_doubles++;
00904              goto workaround_top;
00905            }
00906          else if (vliw2 
00907                  && vliw2->insn_count == 1
00908                  && (temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw3, vliw1->insn_list->sym)) != NULL)
00909            {
00910              temp_insn->snop_frag->fr_subtype = NOP_KEEP;
00911              vliw1 = frv_tomcat_shuffle (VLIW_SINGLE_NOP, vliw3, vliw3->insn_list);
00912              if (tomcat_stats)
00913               tomcat_singles++;
00914              goto workaround_top;
00915            }
00916        }
00917     }
00918 
00919   if (vliw1->insn_count == 2)
00920     {
00921       struct vliw_insn_list *this_insn;
00922  
00923       /* check vliw1 for a label. */
00924       for (this_insn = vliw1->insn_list; this_insn; this_insn = this_insn->next)
00925        {
00926          if (this_insn->type == VLIW_LABEL_TYPE)
00927            {
00928              if ((temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw2, this_insn->sym)) != NULL)
00929               {
00930                 temp_insn->snop_frag->fr_subtype = NOP_KEEP;
00931                 vliw1 = frv_tomcat_shuffle (VLIW_SINGLE_NOP, vliw2, this_insn);
00932                 if (tomcat_stats)
00933                   tomcat_singles++;
00934               }
00935              else
00936               vliw1 = vliw1->next;
00937               goto workaround_top;
00938             }
00939        }
00940     }
00941   /* Examine each insn in this VLIW.  Look for the workaround criteria.  */
00942   for (this_insn = vliw1->insn_list; this_insn; this_insn = this_insn->next)
00943     {
00944       /* Don't look at labels or nops.  */
00945       while (this_insn
00946             && (this_insn->type == VLIW_LABEL_TYPE
00947                  || this_insn->type == VLIW_NOP_TYPE
00948                || this_insn->type == VLIW_BRANCH_HAS_NOPS))
00949        this_insn = this_insn->next;
00950 
00951       if (!this_insn)
00952         {
00953          vliw1 = vliw2;
00954          goto workaround_top;
00955        }
00956 
00957       if (frv_is_branch_insn (this_insn->insn))
00958        {
00959          if ((temp_insn = frv_find_in_vliw (VLIW_LABEL_TYPE, vliw1, this_insn->sym)) != NULL)
00960            {
00961              /* Insert [nop/nop] [nop] before branch.  */
00962              this_insn->snop_frag->fr_subtype = NOP_KEEP;
00963              this_insn->dnop_frag->fr_subtype = NOP_KEEP;
00964              vliw1 = frv_tomcat_shuffle (VLIW_DOUBLE_THEN_SINGLE_NOP, vliw1, this_insn);
00965              goto workaround_top;
00966            }
00967        }
00968 
00969 
00970     }
00971   /* This vliw insn checks out okay.  Take a look at the next one.  */
00972   vliw1 = vliw1->next;
00973   goto workaround_top;
00974 }
00975 
00976 void
00977 frv_tomcat_workaround ()
00978 {
00979   if (frv_mach != bfd_mach_frvtomcat)
00980     return;
00981 
00982   if (tomcat_debug)
00983     frv_debug_tomcat (vliw_chain_top);
00984 
00985   frv_tomcat_analyze_vliw_chains ();
00986 
00987   if (tomcat_stats)
00988     {
00989       fprintf (stderr, "Inserted %d Single Nops\n", tomcat_singles);
00990       fprintf (stderr, "Inserted %d Double Nops\n", tomcat_doubles);
00991     }
00992 }
00993 
00994 static int
00995 fr550_check_insn_acc_range (frv_insn *insn, int low, int hi)
00996 {
00997   int acc;
00998   switch (CGEN_INSN_NUM (insn->insn))
00999     {
01000     case FRV_INSN_MADDACCS:
01001     case FRV_INSN_MSUBACCS:
01002     case FRV_INSN_MDADDACCS:
01003     case FRV_INSN_MDSUBACCS:
01004     case FRV_INSN_MASACCS:
01005     case FRV_INSN_MDASACCS:
01006       acc = insn->fields.f_ACC40Si;
01007       if (acc < low || acc > hi)
01008        return 1; /* out of range */
01009       acc = insn->fields.f_ACC40Sk;
01010       if (acc < low || acc > hi)
01011        return 1; /* out of range */
01012       break;
01013     case FRV_INSN_MMULHS:
01014     case FRV_INSN_MMULHU:
01015     case FRV_INSN_MMULXHS:
01016     case FRV_INSN_MMULXHU:
01017     case FRV_INSN_CMMULHS:
01018     case FRV_INSN_CMMULHU:
01019     case FRV_INSN_MQMULHS:
01020     case FRV_INSN_MQMULHU:
01021     case FRV_INSN_MQMULXHS:
01022     case FRV_INSN_MQMULXHU:
01023     case FRV_INSN_CMQMULHS:
01024     case FRV_INSN_CMQMULHU:
01025     case FRV_INSN_MMACHS:
01026     case FRV_INSN_MMRDHS:
01027     case FRV_INSN_CMMACHS: 
01028     case FRV_INSN_MQMACHS:
01029     case FRV_INSN_CMQMACHS:
01030     case FRV_INSN_MQXMACHS:
01031     case FRV_INSN_MQXMACXHS:
01032     case FRV_INSN_MQMACXHS:
01033     case FRV_INSN_MCPXRS:
01034     case FRV_INSN_MCPXIS:
01035     case FRV_INSN_CMCPXRS:
01036     case FRV_INSN_CMCPXIS:
01037     case FRV_INSN_MQCPXRS:
01038     case FRV_INSN_MQCPXIS:
01039      acc = insn->fields.f_ACC40Sk;
01040       if (acc < low || acc > hi)
01041        return 1; /* out of range */
01042       break;
01043     case FRV_INSN_MMACHU:
01044     case FRV_INSN_MMRDHU:
01045     case FRV_INSN_CMMACHU:
01046     case FRV_INSN_MQMACHU:
01047     case FRV_INSN_CMQMACHU:
01048     case FRV_INSN_MCPXRU:
01049     case FRV_INSN_MCPXIU:
01050     case FRV_INSN_CMCPXRU:
01051     case FRV_INSN_CMCPXIU:
01052     case FRV_INSN_MQCPXRU:
01053     case FRV_INSN_MQCPXIU:
01054       acc = insn->fields.f_ACC40Uk;
01055       if (acc < low || acc > hi)
01056        return 1; /* out of range */
01057       break;
01058     default:
01059       break;
01060     }
01061   return 0; /* all is ok */
01062 }
01063 
01064 static int
01065 fr550_check_acc_range (FRV_VLIW *vliw, frv_insn *insn)
01066 {
01067   switch ((*vliw->current_vliw)[vliw->next_slot - 1])
01068     {
01069     case UNIT_FM0:
01070     case UNIT_FM2:
01071       return fr550_check_insn_acc_range (insn, 0, 3);
01072     case UNIT_FM1:
01073     case UNIT_FM3:
01074       return fr550_check_insn_acc_range (insn, 4, 7);
01075     default:
01076       break;
01077     }
01078   return 0; /* all is ok */
01079 }
01080 
01081 /* Return true if the target implements instruction INSN.  */
01082 
01083 static bfd_boolean
01084 target_implements_insn_p (const CGEN_INSN *insn)
01085 {
01086   switch (frv_mach)
01087     {
01088     default:
01089       /* bfd_mach_frv or generic.  */
01090       return TRUE;
01091 
01092     case bfd_mach_fr300:
01093     case bfd_mach_frvsimple:
01094       return CGEN_INSN_MACH_HAS_P (insn, MACH_SIMPLE);
01095 
01096     case bfd_mach_fr400:
01097       return ((fr400_audio || !CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_AUDIO))
01098              && CGEN_INSN_MACH_HAS_P (insn, MACH_FR400));
01099 
01100     case bfd_mach_fr450:
01101       return CGEN_INSN_MACH_HAS_P (insn, MACH_FR450);
01102 
01103     case bfd_mach_fr500:
01104       return CGEN_INSN_MACH_HAS_P (insn, MACH_FR500);
01105 
01106     case bfd_mach_fr550:
01107       return CGEN_INSN_MACH_HAS_P (insn, MACH_FR550);
01108     }
01109 }
01110 
01111 void
01112 md_assemble (str)
01113      char * str;
01114 {
01115   frv_insn insn;
01116   char *errmsg;
01117   int packing_constraint;
01118   finished_insnS  finished_insn;
01119   fragS *double_nop_frag = NULL;
01120   fragS *single_nop_frag = NULL;
01121   struct vliw_insn_list *vliw_insn_list_entry = NULL;
01122 
01123   /* Initialize GAS's cgen interface for a new instruction.  */
01124   gas_cgen_init_parse ();
01125 
01126   memset (&insn, 0, sizeof (insn));
01127 
01128   insn.insn = frv_cgen_assemble_insn
01129     (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, &errmsg);
01130   
01131   if (!insn.insn)
01132     {
01133       as_bad (errmsg);
01134       return;
01135     }
01136   
01137   /* If the cpu is tomcat, then we need to insert nops to workaround
01138      hardware limitations.  We need to keep track of each vliw unit
01139      and examine the length of the unit and the individual insns
01140      within the unit to determine the number and location of the
01141      required nops.  */
01142   if (frv_mach == bfd_mach_frvtomcat)
01143     {
01144       /* If we've just finished a VLIW insn OR this is a branch,
01145         then start up a new frag.  Fill it with nops.  We will get rid
01146         of those that are not required after we've seen all of the 
01147         instructions but before we start resolving fixups.  */
01148       if ( !FRV_IS_NOP (insn)
01149          && (frv_is_branch_insn (insn.insn) || insn.fields.f_pack))
01150        {
01151          char *buffer;
01152 
01153          frag_wane (frag_now);
01154          frag_new (0);
01155          double_nop_frag = frag_now;
01156          buffer = frag_var (rs_machine_dependent, 8, 8, NOP_DELETE, NULL, 0, 0);
01157          md_number_to_chars (buffer, FRV_NOP_PACK, 4);
01158          md_number_to_chars (buffer+4, FRV_NOP_NOPACK, 4);
01159 
01160          frag_wane (frag_now);
01161          frag_new (0);
01162          single_nop_frag = frag_now;
01163          buffer = frag_var (rs_machine_dependent, 4, 4, NOP_DELETE, NULL, 0, 0);
01164          md_number_to_chars (buffer, FRV_NOP_NOPACK, 4);
01165        }
01166 
01167       vliw_insn_list_entry = frv_insert_vliw_insn (DO_COUNT);
01168       vliw_insn_list_entry->insn   = insn.insn;
01169       if (frv_is_branch_insn (insn.insn))
01170        vliw_insn_list_entry->type = VLIW_BRANCH_TYPE;
01171 
01172       if ( !FRV_IS_NOP (insn)
01173          && (frv_is_branch_insn (insn.insn) || insn.fields.f_pack))
01174        {
01175          vliw_insn_list_entry->snop_frag = single_nop_frag;
01176          vliw_insn_list_entry->dnop_frag = double_nop_frag;
01177        }
01178     }
01179 
01180   /* Make sure that this insn does not violate the VLIW packing constraints.  */
01181   /* -mno-pack disallows any packing whatsoever.  */
01182   if (frv_flags & EF_FRV_NOPACK)
01183     {
01184       if (! insn.fields.f_pack)
01185        {
01186          as_bad (_("VLIW packing used for -mno-pack"));
01187          return;
01188        }
01189     }
01190   /* -mcpu=FRV is an idealized FR-V implementation that supports all of the
01191      instructions, don't do vliw checking.  */
01192   else if (frv_mach != bfd_mach_frv)
01193     {
01194       if (!target_implements_insn_p (insn.insn))
01195        {
01196          as_bad (_("Instruction not supported by this architecture"));
01197          return;
01198        }
01199       packing_constraint = frv_vliw_add_insn (& vliw, insn.insn);
01200       if (frv_mach == bfd_mach_fr550 && ! packing_constraint)
01201        packing_constraint = fr550_check_acc_range (& vliw, & insn);
01202       if (insn.fields.f_pack)
01203        frv_vliw_reset (& vliw, frv_mach, frv_flags);
01204       if (packing_constraint)
01205        {
01206          as_bad (_("VLIW packing constraint violation"));
01207          return;
01208        }
01209     }
01210 
01211   /* Doesn't really matter what we pass for RELAX_P here.  */
01212   gas_cgen_finish_insn (insn.insn, insn.buffer,
01213                      CGEN_FIELDS_BITSIZE (& insn.fields), 1, &finished_insn);
01214 
01215 
01216   /* If the cpu is tomcat, then we need to insert nops to workaround
01217      hardware limitations.  We need to keep track of each vliw unit
01218      and examine the length of the unit and the individual insns
01219      within the unit to determine the number and location of the
01220      required nops.  */
01221   if (frv_mach == bfd_mach_frvtomcat)
01222     {
01223       if (vliw_insn_list_entry)
01224         vliw_insn_list_entry->address = finished_insn.addr;
01225       else
01226        abort();
01227 
01228       if (insn.fields.f_pack)
01229        {
01230          /* We've completed a VLIW insn.  */
01231          previous_vliw_chain = current_vliw_chain;
01232          current_vliw_chain = NULL;
01233          current_vliw_insn  = NULL;
01234         } 
01235     }
01236 }
01237 
01238 /* The syntax in the manual says constants begin with '#'.
01239    We just ignore it.  */
01240 
01241 void 
01242 md_operand (expressionP)
01243      expressionS * expressionP;
01244 {
01245   if (* input_line_pointer == '#')
01246     {
01247       input_line_pointer ++;
01248       expression (expressionP);
01249     }
01250 }
01251 
01252 valueT
01253 md_section_align (segment, size)
01254      segT   segment;
01255      valueT size;
01256 {
01257   int align = bfd_get_section_alignment (stdoutput, segment);
01258   return ((size + (1 << align) - 1) & (-1 << align));
01259 }
01260 
01261 symbolS *
01262 md_undefined_symbol (name)
01263   char * name ATTRIBUTE_UNUSED;
01264 {
01265   return 0;
01266 }
01267 
01268 /* Interface to relax_segment.  */
01269 
01270 /* FIXME: Build table by hand, get it working, then machine generate.  */
01271 const relax_typeS md_relax_table[] =
01272 {
01273   {1, 1, 0, 0},
01274   {511 - 2 - 2, -512 - 2 + 2, 0, 2 },
01275   {0x2000000 - 1 - 2, -0x2000000 - 2, 2, 0 },
01276   {0x2000000 - 1 - 2, -0x2000000 - 2, 4, 0 }
01277 };
01278 
01279 long
01280 frv_relax_frag (fragP, stretch)
01281      fragS   *fragP ATTRIBUTE_UNUSED;
01282      long    stretch ATTRIBUTE_UNUSED;
01283 {
01284   return 0;
01285 }
01286 
01287 /* Return an initial guess of the length by which a fragment must grow to
01288    hold a branch to reach its destination.
01289    Also updates fr_type/fr_subtype as necessary.
01290 
01291    Called just before doing relaxation.
01292    Any symbol that is now undefined will not become defined.
01293    The guess for fr_var is ACTUALLY the growth beyond fr_fix.
01294    Whatever we do to grow fr_fix or fr_var contributes to our returned value.
01295    Although it may not be explicit in the frag, pretend fr_var starts with a
01296    0 value.  */
01297 
01298 int
01299 md_estimate_size_before_relax (fragP, segment)
01300      fragS * fragP;
01301      segT    segment ATTRIBUTE_UNUSED;
01302 {
01303   switch (fragP->fr_subtype)
01304     {
01305     case NOP_KEEP:
01306       return fragP->fr_var;
01307 
01308     default:
01309     case NOP_DELETE:
01310       return 0;
01311     }     
01312 } 
01313 
01314 /* *fragP has been relaxed to its final size, and now needs to have
01315    the bytes inside it modified to conform to the new size.
01316 
01317    Called after relaxation is finished.
01318    fragP->fr_type == rs_machine_dependent.
01319    fragP->fr_subtype is the subtype of what the address relaxed to.  */
01320 
01321 void
01322 md_convert_frag (abfd, sec, fragP)
01323   bfd *   abfd ATTRIBUTE_UNUSED;
01324   segT    sec ATTRIBUTE_UNUSED;
01325   fragS * fragP;
01326 {
01327   switch (fragP->fr_subtype)
01328     {
01329     default:
01330     case NOP_DELETE:
01331       return;
01332 
01333     case NOP_KEEP:
01334       fragP->fr_fix = fragP->fr_var;
01335       fragP->fr_var = 0;
01336       return;   
01337     }
01338 }
01339 
01340 /* Functions concerning relocs.  */
01341 
01342 /* The location from which a PC relative jump should be calculated,
01343    given a PC relative reloc.  */
01344 
01345 long
01346 md_pcrel_from_section (fixP, sec)
01347      fixS * fixP;
01348      segT   sec;
01349 {
01350   if (TC_FORCE_RELOCATION (fixP)
01351       || (fixP->fx_addsy != (symbolS *) NULL
01352          && S_GET_SEGMENT (fixP->fx_addsy) != sec))
01353     {
01354       /* If we can't adjust this relocation, or if it references a
01355         local symbol in a different section (which
01356         TC_FORCE_RELOCATION can't check), let the linker figure it
01357         out.  */
01358       return 0;
01359     }
01360 
01361   return (fixP->fx_frag->fr_address + fixP->fx_where) & ~1;
01362 }
01363 
01364 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
01365    Returns BFD_RELOC_NONE if no reloc type can be found.
01366    *FIXP may be modified if desired.  */
01367 
01368 bfd_reloc_code_real_type
01369 md_cgen_lookup_reloc (insn, operand, fixP)
01370      const CGEN_INSN *    insn ATTRIBUTE_UNUSED;
01371      const CGEN_OPERAND * operand;
01372      fixS *               fixP;
01373 {
01374   switch (operand->type)
01375     {
01376     case FRV_OPERAND_LABEL16:
01377       fixP->fx_pcrel = TRUE;
01378       return BFD_RELOC_FRV_LABEL16;
01379 
01380     case FRV_OPERAND_LABEL24:
01381       fixP->fx_pcrel = TRUE;
01382 
01383       if (fixP->fx_cgen.opinfo != 0)
01384        return fixP->fx_cgen.opinfo;
01385 
01386       return BFD_RELOC_FRV_LABEL24;
01387 
01388     case FRV_OPERAND_UHI16:
01389     case FRV_OPERAND_ULO16:
01390     case FRV_OPERAND_SLO16:
01391     case FRV_OPERAND_CALLANN:
01392     case FRV_OPERAND_LDANN:
01393     case FRV_OPERAND_LDDANN:
01394       /* The relocation type should be recorded in opinfo */
01395       if (fixP->fx_cgen.opinfo != 0)
01396         return fixP->fx_cgen.opinfo;
01397       break;
01398 
01399     case FRV_OPERAND_D12:
01400     case FRV_OPERAND_S12:
01401       if (fixP->fx_cgen.opinfo != 0)
01402        return fixP->fx_cgen.opinfo;
01403 
01404       return BFD_RELOC_FRV_GPREL12;
01405 
01406     case FRV_OPERAND_U12:
01407       return BFD_RELOC_FRV_GPRELU12;
01408 
01409     default: 
01410       break;
01411     }
01412   return BFD_RELOC_NONE;
01413 }
01414 
01415 
01416 /* See whether we need to force a relocation into the output file.
01417    This is used to force out switch and PC relative relocations when
01418    relaxing.  */
01419 
01420 int
01421 frv_force_relocation (fix)
01422      fixS * fix;
01423 {
01424   switch (fix->fx_r_type < BFD_RELOC_UNUSED
01425          ? (int) fix->fx_r_type
01426          : fix->fx_cgen.opinfo)
01427     {
01428     case BFD_RELOC_FRV_GPREL12:
01429     case BFD_RELOC_FRV_GPRELU12:
01430     case BFD_RELOC_FRV_GPREL32:
01431     case BFD_RELOC_FRV_GPRELHI:
01432     case BFD_RELOC_FRV_GPRELLO:
01433     case BFD_RELOC_FRV_GOT12:
01434     case BFD_RELOC_FRV_GOTHI:
01435     case BFD_RELOC_FRV_GOTLO:
01436     case BFD_RELOC_FRV_FUNCDESC_VALUE:
01437     case BFD_RELOC_FRV_FUNCDESC_GOTOFF12:
01438     case BFD_RELOC_FRV_FUNCDESC_GOTOFFHI:
01439     case BFD_RELOC_FRV_FUNCDESC_GOTOFFLO:
01440     case BFD_RELOC_FRV_GOTOFF12:
01441     case BFD_RELOC_FRV_GOTOFFHI:
01442     case BFD_RELOC_FRV_GOTOFFLO:
01443     case BFD_RELOC_FRV_GETTLSOFF:
01444     case BFD_RELOC_FRV_TLSDESC_VALUE:
01445     case BFD_RELOC_FRV_GOTTLSDESC12:
01446     case BFD_RELOC_FRV_GOTTLSDESCHI:
01447     case BFD_RELOC_FRV_GOTTLSDESCLO:
01448     case BFD_RELOC_FRV_TLSMOFF12:
01449     case BFD_RELOC_FRV_TLSMOFFHI:
01450     case BFD_RELOC_FRV_TLSMOFFLO:
01451     case BFD_RELOC_FRV_GOTTLSOFF12:
01452     case BFD_RELOC_FRV_GOTTLSOFFHI:
01453     case BFD_RELOC_FRV_GOTTLSOFFLO:
01454     case BFD_RELOC_FRV_TLSOFF:
01455     case BFD_RELOC_FRV_TLSDESC_RELAX:
01456     case BFD_RELOC_FRV_GETTLSOFF_RELAX:
01457     case BFD_RELOC_FRV_TLSOFF_RELAX:
01458       return 1;
01459 
01460     default:
01461       break;
01462     }
01463 
01464   return generic_force_reloc (fix);
01465 }
01466 
01467 /* Apply a fixup that could be resolved within the assembler.  */
01468 
01469 void
01470 md_apply_fix (fixP, valP, seg)
01471      fixS *   fixP;
01472      valueT * valP;
01473      segT     seg;
01474 {
01475   if (fixP->fx_addsy == 0)
01476     switch (fixP->fx_cgen.opinfo)
01477       {
01478       case BFD_RELOC_FRV_HI16:
01479        *valP >>= 16;
01480        /* Fall through.  */
01481       case BFD_RELOC_FRV_LO16:
01482        *valP &= 0xffff;
01483        break;
01484 
01485        /* We need relocations for these, even if their symbols reduce
01486           to constants.  */
01487       case BFD_RELOC_FRV_GPREL12:
01488       case BFD_RELOC_FRV_GPRELU12:
01489       case BFD_RELOC_FRV_GPREL32:
01490       case BFD_RELOC_FRV_GPRELHI:
01491       case BFD_RELOC_FRV_GPRELLO:
01492       case BFD_RELOC_FRV_GOT12:
01493       case BFD_RELOC_FRV_GOTHI:
01494       case BFD_RELOC_FRV_GOTLO:
01495       case BFD_RELOC_FRV_FUNCDESC_VALUE:
01496       case BFD_RELOC_FRV_FUNCDESC_GOTOFF12:
01497       case BFD_RELOC_FRV_FUNCDESC_GOTOFFHI:
01498       case BFD_RELOC_FRV_FUNCDESC_GOTOFFLO:
01499       case BFD_RELOC_FRV_GOTOFF12:
01500       case BFD_RELOC_FRV_GOTOFFHI:
01501       case BFD_RELOC_FRV_GOTOFFLO:
01502       case BFD_RELOC_FRV_GETTLSOFF:
01503       case BFD_RELOC_FRV_TLSDESC_VALUE:
01504       case BFD_RELOC_FRV_GOTTLSDESC12:
01505       case BFD_RELOC_FRV_GOTTLSDESCHI:
01506       case BFD_RELOC_FRV_GOTTLSDESCLO:
01507       case BFD_RELOC_FRV_TLSMOFF12:
01508       case BFD_RELOC_FRV_TLSMOFFHI:
01509       case BFD_RELOC_FRV_TLSMOFFLO:
01510       case BFD_RELOC_FRV_GOTTLSOFF12:
01511       case BFD_RELOC_FRV_GOTTLSOFFHI:
01512       case BFD_RELOC_FRV_GOTTLSOFFLO:
01513       case BFD_RELOC_FRV_TLSOFF:
01514       case BFD_RELOC_FRV_TLSDESC_RELAX:
01515       case BFD_RELOC_FRV_GETTLSOFF_RELAX:
01516       case BFD_RELOC_FRV_TLSOFF_RELAX:
01517        fixP->fx_addsy = expr_build_uconstant (0);
01518        break;
01519       }
01520   else
01521     switch (fixP->fx_cgen.opinfo)
01522       {
01523       case BFD_RELOC_FRV_GETTLSOFF:
01524       case BFD_RELOC_FRV_TLSDESC_VALUE:
01525       case BFD_RELOC_FRV_GOTTLSDESC12:
01526       case BFD_RELOC_FRV_GOTTLSDESCHI:
01527       case BFD_RELOC_FRV_GOTTLSDESCLO:
01528       case BFD_RELOC_FRV_TLSMOFF12:
01529       case BFD_RELOC_FRV_TLSMOFFHI:
01530       case BFD_RELOC_FRV_TLSMOFFLO:
01531       case BFD_RELOC_FRV_GOTTLSOFF12:
01532       case BFD_RELOC_FRV_GOTTLSOFFHI:
01533       case BFD_RELOC_FRV_GOTTLSOFFLO:
01534       case BFD_RELOC_FRV_TLSOFF:
01535       case BFD_RELOC_FRV_TLSDESC_RELAX:
01536       case BFD_RELOC_FRV_GETTLSOFF_RELAX:
01537       case BFD_RELOC_FRV_TLSOFF_RELAX:
01538        /* Mark TLS symbols as such.  */
01539        if (S_GET_SEGMENT (fixP->fx_addsy) != absolute_section)
01540          S_SET_THREAD_LOCAL (fixP->fx_addsy);
01541        break;
01542       }
01543 
01544   gas_cgen_md_apply_fix (fixP, valP, seg);
01545   return;
01546 }
01547 
01548 
01549 /* Write a value out to the object file, using the appropriate endianness.  */
01550 
01551 void
01552 frv_md_number_to_chars (buf, val, n)
01553      char * buf;
01554      valueT val;
01555      int    n;
01556 {
01557   number_to_chars_bigendian (buf, val, n);
01558 }
01559 
01560 /* Turn a string in input_line_pointer into a floating point constant of type
01561    type, and store the appropriate bytes in *litP.  The number of LITTLENUMS
01562    emitted is stored in *sizeP .  An error message is returned, or NULL on OK.
01563 */
01564 
01565 /* Equal to MAX_PRECISION in atof-ieee.c */
01566 #define MAX_LITTLENUMS 6
01567 
01568 char *
01569 md_atof (type, litP, sizeP)
01570      char   type;
01571      char * litP;
01572      int *  sizeP;
01573 {
01574   int              i;
01575   int              prec;
01576   LITTLENUM_TYPE   words [MAX_LITTLENUMS];
01577   char *           t;
01578 
01579   switch (type)
01580     {
01581     case 'f':
01582     case 'F':
01583     case 's':
01584     case 'S':
01585       prec = 2;
01586       break;
01587 
01588     case 'd':
01589     case 'D':
01590     case 'r':
01591     case 'R':
01592       prec = 4;
01593       break;
01594 
01595    /* FIXME: Some targets allow other format chars for bigger sizes here.  */
01596 
01597     default:
01598       * sizeP = 0;
01599       return _("Bad call to md_atof()");
01600     }
01601 
01602   t = atof_ieee (input_line_pointer, type, words);
01603   if (t)
01604     input_line_pointer = t;
01605   * sizeP = prec * sizeof (LITTLENUM_TYPE);
01606 
01607   for (i = 0; i < prec; i++)
01608     {
01609       md_number_to_chars (litP, (valueT) words[i],
01610                        sizeof (LITTLENUM_TYPE));
01611       litP += sizeof (LITTLENUM_TYPE);
01612     }
01613      
01614   return 0;
01615 }
01616 
01617 bfd_boolean
01618 frv_fix_adjustable (fixP)
01619    fixS * fixP;
01620 {
01621   bfd_reloc_code_real_type reloc_type;
01622 
01623   if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
01624     {
01625       const CGEN_INSN *insn = NULL;
01626       int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
01627       const CGEN_OPERAND *operand = cgen_operand_lookup_by_num(gas_cgen_cpu_desc, opindex);
01628       reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
01629     }
01630   else
01631     reloc_type = fixP->fx_r_type;
01632 
01633   /* We need the symbol name for the VTABLE entries */
01634   if (   reloc_type == BFD_RELOC_VTABLE_INHERIT
01635       || reloc_type == BFD_RELOC_VTABLE_ENTRY
01636       || reloc_type == BFD_RELOC_FRV_GPREL12
01637       || reloc_type == BFD_RELOC_FRV_GPRELU12)
01638     return 0;
01639 
01640   return 1;
01641 }
01642 
01643 /* Allow user to set flags bits.  */
01644 void
01645 frv_set_flags (arg)
01646      int arg ATTRIBUTE_UNUSED;
01647 {
01648   flagword new_flags = get_absolute_expression ();
01649   flagword new_mask = ~ (flagword)0;
01650 
01651   frv_user_set_flags_p = 1;
01652   if (*input_line_pointer == ',')
01653     {
01654       ++input_line_pointer;
01655       new_mask = get_absolute_expression ();
01656     }
01657 
01658   frv_flags = (frv_flags & ~new_mask) | (new_flags & new_mask);
01659   bfd_set_private_flags (stdoutput, frv_flags);
01660 }
01661 
01662 /* Frv specific function to handle 4 byte initializations for pointers that are
01663    considered 'safe' for use with pic support.  Until frv_frob_file{,_section}
01664    is run, we encode it a BFD_RELOC_CTOR, and it is turned back into a normal
01665    BFD_RELOC_32 at that time.  */
01666 
01667 void
01668 frv_pic_ptr (nbytes)
01669      int nbytes;
01670 {
01671   expressionS exp;
01672   char *p;
01673 
01674   if (nbytes != 4)
01675     abort ();
01676 
01677 #ifdef md_flush_pending_output
01678   md_flush_pending_output ();
01679 #endif
01680 
01681   if (is_it_end_of_statement ())
01682     {
01683       demand_empty_rest_of_line ();
01684       return;
01685     }
01686 
01687 #ifdef md_cons_align
01688   md_cons_align (nbytes);
01689 #endif
01690 
01691   do
01692     {
01693       bfd_reloc_code_real_type reloc_type = BFD_RELOC_CTOR;
01694       
01695       if (strncasecmp (input_line_pointer, "funcdesc(", 9) == 0)
01696        {
01697          input_line_pointer += 9;
01698          expression (&exp);
01699          if (*input_line_pointer == ')')
01700            input_line_pointer++;
01701          else
01702            as_bad ("missing ')'");
01703          reloc_type = BFD_RELOC_FRV_FUNCDESC;
01704        }
01705       else if (strncasecmp (input_line_pointer, "tlsmoff(", 8) == 0)
01706        {
01707          input_line_pointer += 8;
01708          expression (&exp);
01709          if (*input_line_pointer == ')')
01710            input_line_pointer++;
01711          else
01712            as_bad ("missing ')'");
01713          reloc_type = BFD_RELOC_FRV_TLSMOFF;
01714        }
01715       else
01716        expression (&exp);
01717 
01718       p = frag_more (4);
01719       memset (p, 0, 4);
01720       fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &exp, 0,
01721                  reloc_type);
01722     }
01723   while (*input_line_pointer++ == ',');
01724 
01725   input_line_pointer--;                   /* Put terminator back into stream. */
01726   demand_empty_rest_of_line ();
01727 }
01728 
01729 
01730 
01731 #ifdef DEBUG
01732 #define DPRINTF1(A)  fprintf (stderr, A)
01733 #define DPRINTF2(A,B)       fprintf (stderr, A, B)
01734 #define DPRINTF3(A,B,C)     fprintf (stderr, A, B, C)
01735 
01736 #else
01737 #define DPRINTF1(A)
01738 #define DPRINTF2(A,B)
01739 #define DPRINTF3(A,B,C)
01740 #endif
01741 
01742 /* Go through a the sections looking for relocations that are problematical for
01743    pic.  If not pic, just note that this object can't be linked with pic.  If
01744    it is pic, see if it needs to be marked so that it will be fixed up, or if
01745    not possible, issue an error.  */
01746 
01747 static void
01748 frv_frob_file_section (abfd, sec, ptr)
01749      bfd *abfd;
01750      asection *sec;
01751      PTR ptr ATTRIBUTE_UNUSED;
01752 {
01753   segment_info_type *seginfo = seg_info (sec);
01754   fixS *fixp;
01755   CGEN_CPU_DESC cd = gas_cgen_cpu_desc;
01756   flagword flags = bfd_get_section_flags (abfd, sec);
01757 
01758   /* Skip relocations in known sections (.ctors, .dtors, and .gcc_except_table)
01759      since we can fix those up by hand.  */
01760   int known_section_p = (sec->name
01761                       && sec->name[0] == '.'
01762                       && ((sec->name[1] == 'c'
01763                            && strcmp (sec->name, ".ctor") == 0)
01764                           || (sec->name[1] == 'd'
01765                              && strcmp (sec->name, ".dtor") == 0)
01766                           || (sec->name[1] == 'g'
01767                              && strcmp (sec->name, ".gcc_except_table") == 0)));
01768 
01769   DPRINTF3 ("\nFrv section %s%s\n", sec->name, (known_section_p) ? ", known section" : "");
01770   if ((flags & SEC_ALLOC) == 0)
01771     {
01772       DPRINTF1 ("\tSkipping non-loaded section\n");
01773       return;
01774     }
01775 
01776   for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next)
01777     {
01778       symbolS *s = fixp->fx_addsy;
01779       bfd_reloc_code_real_type reloc;
01780       int non_pic_p;
01781       int opindex;
01782       const CGEN_OPERAND *operand;
01783       const CGEN_INSN *insn = fixp->fx_cgen.insn;
01784 
01785       if (fixp->fx_done)
01786        {
01787          DPRINTF1 ("\tSkipping reloc that has already been done\n");
01788          continue;
01789        }
01790 
01791       if (fixp->fx_pcrel)
01792        {
01793          DPRINTF1 ("\tSkipping reloc that is PC relative\n");
01794          continue;
01795        }
01796 
01797       if (! s)
01798        {
01799          DPRINTF1 ("\tSkipping reloc without symbol\n");
01800          continue;
01801        }
01802 
01803       if (fixp->fx_r_type < BFD_RELOC_UNUSED)
01804        {
01805          opindex = -1;
01806          reloc = fixp->fx_r_type;
01807        }
01808       else
01809        {
01810          opindex = (int) fixp->fx_r_type - (int) BFD_RELOC_UNUSED;
01811          operand = cgen_operand_lookup_by_num (cd, opindex);
01812          reloc = md_cgen_lookup_reloc (insn, operand, fixp);
01813        }
01814 
01815       DPRINTF3 ("\treloc %s\t%s", bfd_get_reloc_code_name (reloc), S_GET_NAME (s));
01816 
01817       non_pic_p = 0;
01818       switch (reloc)
01819        {
01820        default:
01821          break;
01822 
01823        case BFD_RELOC_32:
01824          /* Skip relocations in known sections (.ctors, .dtors, and
01825             .gcc_except_table) since we can fix those up by hand.  Also
01826             skip forward references to constants.  Also skip a difference
01827             of two symbols, which still uses the BFD_RELOC_32 at this
01828             point.  */
01829          if (! known_section_p
01830              && S_GET_SEGMENT (s) != absolute_section
01831              && !fixp->fx_subsy
01832              && (flags & (SEC_READONLY | SEC_CODE)) == 0)
01833            {
01834              non_pic_p = 1;
01835            }
01836          break;
01837 
01838          /* FIXME -- should determine if any of the GP relocation really uses
01839             gr16 (which is not pic safe) or not.  Right now, assume if we
01840             aren't being compiled with -mpic, the usage is non pic safe, but
01841             is safe with -mpic.  */
01842        case BFD_RELOC_FRV_GPREL12:
01843        case BFD_RELOC_FRV_GPRELU12:
01844        case BFD_RELOC_FRV_GPREL32:
01845        case BFD_RELOC_FRV_GPRELHI:
01846        case BFD_RELOC_FRV_GPRELLO:
01847          non_pic_p = ! frv_pic_p;
01848          break;
01849 
01850        case BFD_RELOC_FRV_LO16:
01851        case BFD_RELOC_FRV_HI16:
01852          if (S_GET_SEGMENT (s) != absolute_section)
01853            non_pic_p = 1;
01854          break;
01855 
01856        case BFD_RELOC_VTABLE_INHERIT:
01857        case BFD_RELOC_VTABLE_ENTRY:
01858          non_pic_p = 1;
01859          break;
01860 
01861          /* If this is a blessed BFD_RELOC_32, convert it back to the normal
01862              relocation.  */
01863        case BFD_RELOC_CTOR:
01864          fixp->fx_r_type = BFD_RELOC_32;
01865          break;
01866        }
01867 
01868       if (non_pic_p)
01869        {
01870          DPRINTF1 (" (Non-pic relocation)\n");
01871          if (frv_pic_p)
01872            as_warn_where (fixp->fx_file, fixp->fx_line,
01873                         _("Relocation %s is not safe for %s"),
01874                         bfd_get_reloc_code_name (reloc), frv_pic_flag);
01875 
01876          else if ((frv_flags & EF_FRV_NON_PIC_RELOCS) == 0)
01877            {
01878              frv_flags |= EF_FRV_NON_PIC_RELOCS;
01879              bfd_set_private_flags (abfd, frv_flags);
01880            }
01881        }
01882 #ifdef DEBUG
01883       else
01884        DPRINTF1 ("\n");
01885 #endif
01886     }
01887 }
01888 
01889 /* After all of the symbols have been adjusted, go over the file looking
01890    for any relocations that pic won't support.  */
01891 
01892 void
01893 frv_frob_file ()
01894 {
01895   bfd_map_over_sections (stdoutput, frv_frob_file_section, (PTR)0);
01896 }
01897 
01898 void
01899 frv_frob_label (this_label)
01900     symbolS *this_label;
01901 {
01902   struct vliw_insn_list *vliw_insn_list_entry;
01903 
01904   if (frv_mach != bfd_mach_frvtomcat)
01905     return;
01906 
01907   if (now_seg != text_section)
01908     return;
01909 
01910   vliw_insn_list_entry = frv_insert_vliw_insn(DONT_COUNT);
01911   vliw_insn_list_entry->type = VLIW_LABEL_TYPE;
01912   vliw_insn_list_entry->sym  = this_label; 
01913 }
01914 
01915 fixS *
01916 frv_cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp)
01917      fragS *              frag;
01918      int                  where;
01919      const CGEN_INSN *    insn;
01920      int                  length;
01921      const CGEN_OPERAND * operand;
01922      int                  opinfo;
01923      expressionS *        exp;
01924 {
01925   fixS * fixP = gas_cgen_record_fixup_exp (frag, where, insn, length,
01926                                            operand, opinfo, exp);
01927 
01928   if (frv_mach == bfd_mach_frvtomcat
01929       && current_vliw_insn
01930       && current_vliw_insn->type == VLIW_BRANCH_TYPE
01931       && exp != NULL)
01932     current_vliw_insn->sym = exp->X_add_symbol;
01933     
01934   return fixP;
01935 }