1 /* tc-frv.c -- Assembler for the Fujitsu FRV.
2    Copyright 2002, 2003, 2004, 2005, 2006 Free Software Foundation.
3 
4    This file is part of GAS, the GNU Assembler.
5 
6    GAS is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2, or (at your option)
9    any later version.
10 
11    GAS is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with GAS; see the file COPYING.  If not, write to
18    the Free Software Foundation, 51 Franklin Street - Fifth Floor,
19    Boston, MA 02110-1301, USA.  */
20 
21 #include <stdio.h>
22 #include "as.h"
23 #include "subsegs.h"
24 #include "symcat.h"
25 #include "opcodes/frv-desc.h"
26 #include "opcodes/frv-opc.h"
27 #include "cgen.h"
28 #include "libbfd.h"
29 #include "elf/common.h"
30 #include "elf/frv.h"
31 
32 /* Structure to hold all of the different components describing
33    an individual instruction.  */
34 typedef struct
35 {
36   const CGEN_INSN *	insn;
37   const CGEN_INSN *	orig_insn;
38   CGEN_FIELDS		fields;
39 #if CGEN_INT_INSN_P
40   CGEN_INSN_INT         buffer [1];
41 #define INSN_VALUE(buf) (*(buf))
42 #else
43   unsigned char         buffer [CGEN_MAX_INSN_SIZE];
44 #define INSN_VALUE(buf) (buf)
45 #endif
46   char *		addr;
47   fragS *		frag;
48   int                   num_fixups;
49   fixS *                fixups [GAS_CGEN_MAX_FIXUPS];
50   int                   indices [MAX_OPERAND_INSTANCES];
51 }
52 frv_insn;
53 
54 enum vliw_insn_type
55 {
56   VLIW_GENERIC_TYPE,		/* Don't care about this insn.  */
57   VLIW_BRANCH_TYPE,		/* A Branch.  */
58   VLIW_LABEL_TYPE,		/* A Label.  */
59   VLIW_NOP_TYPE,		/* A NOP.  */
60   VLIW_BRANCH_HAS_NOPS		/* A Branch that requires NOPS.  */
61 };
62 
63 /* We're going to use these in the fr_subtype field to mark
64    whether to keep inserted nops.  */
65 
66 #define NOP_KEEP 1		/* Keep these NOPS.  */
67 #define NOP_DELETE 2		/* Delete these NOPS.  */
68 
69 #define DO_COUNT    TRUE
70 #define DONT_COUNT  FALSE
71 
72 /* A list of insns within a VLIW insn.  */
73 struct vliw_insn_list
74 {
75   /*  The type of this insn.  */
76   enum vliw_insn_type	type;
77 
78   /*  The corresponding gas insn information.  */
79   const CGEN_INSN	*insn;
80 
81   /*  For branches and labels, the symbol that is referenced.  */
82   symbolS		*sym;
83 
84   /*  For branches, the frag containing the single nop that was generated.  */
85   fragS			*snop_frag;
86 
87   /*  For branches, the frag containing the double nop that was generated.  */
88   fragS			*dnop_frag;
89 
90   /*  Pointer to raw data for this insn.  */
91   char			*address;
92 
93   /* Next insn in list.  */
94   struct vliw_insn_list *next;
95 };
96 
97 static struct vliw_insn_list single_nop_insn = {
98    VLIW_NOP_TYPE, NULL, NULL, NULL, NULL, NULL, NULL };
99 
100 static struct vliw_insn_list double_nop_insn = {
101    VLIW_NOP_TYPE, NULL, NULL, NULL, NULL, NULL, NULL };
102 
103 struct vliw_chain
104 {
105   int			num;
106   int			insn_count;
107   struct vliw_insn_list *insn_list;
108   struct vliw_chain     *next;
109 };
110 
111 static struct vliw_chain	*vliw_chain_top;
112 static struct vliw_chain	*current_vliw_chain;
113 static struct vliw_chain	*previous_vliw_chain;
114 static struct vliw_insn_list	*current_vliw_insn;
115 
116 const char comment_chars[]        = ";";
117 const char line_comment_chars[]   = "#";
118 const char line_separator_chars[] = "!";
119 const char EXP_CHARS[]            = "eE";
120 const char FLT_CHARS[]            = "dD";
121 
122 static FRV_VLIW vliw;
123 
124 /* Default machine */
125 
126 #ifdef  DEFAULT_CPU_FRV
127 #define DEFAULT_MACHINE bfd_mach_frv
128 #define DEFAULT_FLAGS	EF_FRV_CPU_GENERIC
129 
130 #else
131 #ifdef  DEFAULT_CPU_FR300
132 #define DEFAULT_MACHINE	bfd_mach_fr300
133 #define DEFAULT_FLAGS	EF_FRV_CPU_FR300
134 
135 #else
136 #ifdef	DEFAULT_CPU_SIMPLE
137 #define	DEFAULT_MACHINE bfd_mach_frvsimple
138 #define DEFAULT_FLAGS	EF_FRV_CPU_SIMPLE
139 
140 #else
141 #ifdef	DEFAULT_CPU_TOMCAT
142 #define	DEFAULT_MACHINE bfd_mach_frvtomcat
143 #define DEFAULT_FLAGS	EF_FRV_CPU_TOMCAT
144 
145 #else
146 #ifdef  DEFAULT_CPU_FR400
147 #define DEFAULT_MACHINE	bfd_mach_fr400
148 #define DEFAULT_FLAGS	EF_FRV_CPU_FR400
149 
150 #else
151 #ifdef  DEFAULT_CPU_FR550
152 #define DEFAULT_MACHINE	bfd_mach_fr550
153 #define DEFAULT_FLAGS	EF_FRV_CPU_FR550
154 
155 #else
156 #define DEFAULT_MACHINE	bfd_mach_fr500
157 #define DEFAULT_FLAGS	EF_FRV_CPU_FR500
158 #endif
159 #endif
160 #endif
161 #endif
162 #endif
163 #endif
164 
165 #ifdef TE_LINUX
166 # define DEFAULT_FDPIC	EF_FRV_FDPIC
167 #else
168 # define DEFAULT_FDPIC	0
169 #endif
170 
171 static unsigned long frv_mach = bfd_mach_frv;
172 static bfd_boolean fr400_audio;
173 
174 /* Flags to set in the elf header */
175 static flagword frv_flags = DEFAULT_FLAGS | DEFAULT_FDPIC;
176 
177 static int frv_user_set_flags_p = 0;
178 static int frv_pic_p = 0;
179 static const char *frv_pic_flag = DEFAULT_FDPIC ? "-mfdpic" : (const char *)0;
180 
181 /* Print tomcat-specific debugging info.  */
182 static int tomcat_debug = 0;
183 
184 /* Tomcat-specific NOP statistics.  */
185 static int tomcat_stats = 0;
186 static int tomcat_doubles = 0;
187 static int tomcat_singles = 0;
188 
189 /* Forward reference to static functions */
190 static void frv_set_flags		PARAMS ((int));
191 static void frv_pic_ptr			PARAMS ((int));
192 static void frv_frob_file_section	PARAMS ((bfd *, asection *, PTR));
193 
194 /* The target specific pseudo-ops which we support.  */
195 const pseudo_typeS md_pseudo_table[] =
196 {
197   { "eflags",	frv_set_flags,		0 },
198   { "word",	cons,			4 },
199   { "picptr",	frv_pic_ptr,		4 },
200   { NULL, 	NULL,			0 }
201 };
202 
203 
204 #define FRV_SHORTOPTS "G:"
205 const char * md_shortopts = FRV_SHORTOPTS;
206 
207 #define OPTION_GPR_32		(OPTION_MD_BASE)
208 #define OPTION_GPR_64		(OPTION_MD_BASE + 1)
209 #define OPTION_FPR_32		(OPTION_MD_BASE + 2)
210 #define OPTION_FPR_64		(OPTION_MD_BASE + 3)
211 #define OPTION_SOFT_FLOAT	(OPTION_MD_BASE + 4)
212 #define OPTION_DWORD_YES	(OPTION_MD_BASE + 5)
213 #define OPTION_DWORD_NO		(OPTION_MD_BASE + 6)
214 #define OPTION_DOUBLE		(OPTION_MD_BASE + 7)
215 #define OPTION_NO_DOUBLE	(OPTION_MD_BASE + 8)
216 #define OPTION_MEDIA		(OPTION_MD_BASE + 9)
217 #define OPTION_NO_MEDIA		(OPTION_MD_BASE + 10)
218 #define OPTION_CPU		(OPTION_MD_BASE + 11)
219 #define OPTION_PIC		(OPTION_MD_BASE + 12)
220 #define OPTION_BIGPIC		(OPTION_MD_BASE + 13)
221 #define OPTION_LIBPIC		(OPTION_MD_BASE + 14)
222 #define OPTION_MULADD		(OPTION_MD_BASE + 15)
223 #define OPTION_NO_MULADD	(OPTION_MD_BASE + 16)
224 #define OPTION_TOMCAT_DEBUG	(OPTION_MD_BASE + 17)
225 #define OPTION_TOMCAT_STATS	(OPTION_MD_BASE + 18)
226 #define OPTION_PACK	        (OPTION_MD_BASE + 19)
227 #define OPTION_NO_PACK	        (OPTION_MD_BASE + 20)
228 #define OPTION_FDPIC		(OPTION_MD_BASE + 21)
229 #define OPTION_NOPIC		(OPTION_MD_BASE + 22)
230 
231 struct option md_longopts[] =
232 {
233   { "mgpr-32",		no_argument,		NULL, OPTION_GPR_32        },
234   { "mgpr-64",		no_argument,		NULL, OPTION_GPR_64        },
235   { "mfpr-32",		no_argument,		NULL, OPTION_FPR_32        },
236   { "mfpr-64",		no_argument,		NULL, OPTION_FPR_64        },
237   { "mhard-float",	no_argument,		NULL, OPTION_FPR_64        },
238   { "msoft-float",	no_argument,		NULL, OPTION_SOFT_FLOAT    },
239   { "mdword",		no_argument,		NULL, OPTION_DWORD_YES     },
240   { "mno-dword",	no_argument,		NULL, OPTION_DWORD_NO      },
241   { "mdouble",		no_argument,		NULL, OPTION_DOUBLE        },
242   { "mno-double",	no_argument,		NULL, OPTION_NO_DOUBLE     },
243   { "mmedia",		no_argument,		NULL, OPTION_MEDIA         },
244   { "mno-media",	no_argument,		NULL, OPTION_NO_MEDIA      },
245   { "mcpu",		required_argument,	NULL, OPTION_CPU           },
246   { "mpic",		no_argument,		NULL, OPTION_PIC           },
247   { "mPIC",		no_argument,		NULL, OPTION_BIGPIC        },
248   { "mlibrary-pic",	no_argument,		NULL, OPTION_LIBPIC        },
249   { "mmuladd",		no_argument,		NULL, OPTION_MULADD        },
250   { "mno-muladd",	no_argument,		NULL, OPTION_NO_MULADD     },
251   { "mtomcat-debug",    no_argument,            NULL, OPTION_TOMCAT_DEBUG  },
252   { "mtomcat-stats",	no_argument,		NULL, OPTION_TOMCAT_STATS  },
253   { "mpack",        	no_argument,		NULL, OPTION_PACK          },
254   { "mno-pack",        	no_argument,		NULL, OPTION_NO_PACK       },
255   { "mfdpic",		no_argument,		NULL, OPTION_FDPIC	   },
256   { "mnopic",		no_argument,		NULL, OPTION_NOPIC	   },
257   { NULL,		no_argument,		NULL, 0                 },
258 };
259 
260 size_t md_longopts_size = sizeof (md_longopts);
261 
262 /* What value to give to bfd_set_gp_size.  */
263 static int g_switch_value = 8;
264 
265 int
266 md_parse_option (c, arg)
267      int    c;
268      char * arg;
269 {
270   switch (c)
271     {
272     default:
273       return 0;
274 
275     case 'G':
276       g_switch_value = atoi (arg);
277       if (! g_switch_value)
278 	frv_flags |= EF_FRV_G0;
279       break;
280 
281     case OPTION_GPR_32:
282       frv_flags = (frv_flags & ~EF_FRV_GPR_MASK) | EF_FRV_GPR_32;
283       break;
284 
285     case OPTION_GPR_64:
286       frv_flags = (frv_flags & ~EF_FRV_GPR_MASK) | EF_FRV_GPR_64;
287       break;
288 
289     case OPTION_FPR_32:
290       frv_flags = (frv_flags & ~EF_FRV_FPR_MASK) | EF_FRV_FPR_32;
291       break;
292 
293     case OPTION_FPR_64:
294       frv_flags = (frv_flags & ~EF_FRV_FPR_MASK) | EF_FRV_FPR_64;
295       break;
296 
297     case OPTION_SOFT_FLOAT:
298       frv_flags = (frv_flags & ~EF_FRV_FPR_MASK) | EF_FRV_FPR_NONE;
299       break;
300 
301     case OPTION_DWORD_YES:
302       frv_flags = (frv_flags & ~EF_FRV_DWORD_MASK) | EF_FRV_DWORD_YES;
303       break;
304 
305     case OPTION_DWORD_NO:
306       frv_flags = (frv_flags & ~EF_FRV_DWORD_MASK) | EF_FRV_DWORD_NO;
307       break;
308 
309     case OPTION_DOUBLE:
310       frv_flags |= EF_FRV_DOUBLE;
311       break;
312 
313     case OPTION_NO_DOUBLE:
314       frv_flags &= ~EF_FRV_DOUBLE;
315       break;
316 
317     case OPTION_MEDIA:
318       frv_flags |= EF_FRV_MEDIA;
319       break;
320 
321     case OPTION_NO_MEDIA:
322       frv_flags &= ~EF_FRV_MEDIA;
323       break;
324 
325     case OPTION_MULADD:
326       frv_flags |= EF_FRV_MULADD;
327       break;
328 
329     case OPTION_NO_MULADD:
330       frv_flags &= ~EF_FRV_MULADD;
331       break;
332 
333     case OPTION_PACK:
334       frv_flags &= ~EF_FRV_NOPACK;
335       break;
336 
337     case OPTION_NO_PACK:
338       frv_flags |= EF_FRV_NOPACK;
339       break;
340 
341     case OPTION_CPU:
342       {
343 	char *p;
344 	int cpu_flags = EF_FRV_CPU_GENERIC;
345 
346 	/* Identify the processor type */
347 	p = arg;
348 	if (strcmp (p, "frv") == 0)
349 	  {
350 	    cpu_flags = EF_FRV_CPU_GENERIC;
351 	    frv_mach = bfd_mach_frv;
352 	  }
353 
354 	else if (strcmp (p, "fr500") == 0)
355 	  {
356 	    cpu_flags = EF_FRV_CPU_FR500;
357 	    frv_mach = bfd_mach_fr500;
358 	  }
359 
360 	else if (strcmp (p, "fr550") == 0)
361 	  {
362 	    cpu_flags = EF_FRV_CPU_FR550;
363 	    frv_mach = bfd_mach_fr550;
364 	  }
365 
366 	else if (strcmp (p, "fr450") == 0)
367 	  {
368 	    cpu_flags = EF_FRV_CPU_FR450;
369 	    frv_mach = bfd_mach_fr450;
370 	  }
371 
372 	else if (strcmp (p, "fr405") == 0)
373 	  {
374 	    cpu_flags = EF_FRV_CPU_FR405;
375 	    frv_mach = bfd_mach_fr400;
376 	    fr400_audio = TRUE;
377 	  }
378 
379 	else if (strcmp (p, "fr400") == 0)
380 	  {
381 	    cpu_flags = EF_FRV_CPU_FR400;
382 	    frv_mach = bfd_mach_fr400;
383 	    fr400_audio = FALSE;
384 	  }
385 
386 	else if (strcmp (p, "fr300") == 0)
387 	  {
388 	    cpu_flags = EF_FRV_CPU_FR300;
389 	    frv_mach = bfd_mach_fr300;
390 	  }
391 
392 	else if (strcmp (p, "simple") == 0)
393 	  {
394 	    cpu_flags = EF_FRV_CPU_SIMPLE;
395 	    frv_mach = bfd_mach_frvsimple;
396 	    frv_flags |= EF_FRV_NOPACK;
397 	  }
398 
399         else if (strcmp (p, "tomcat") == 0)
400           {
401             cpu_flags = EF_FRV_CPU_TOMCAT;
402             frv_mach = bfd_mach_frvtomcat;
403           }
404 
405 	else
406 	  {
407 	    as_fatal ("Unknown cpu -mcpu=%s", arg);
408 	    return 0;
409 	  }
410 
411 	frv_flags = (frv_flags & ~EF_FRV_CPU_MASK) | cpu_flags;
412       }
413       break;
414 
415     case OPTION_PIC:
416       frv_flags |= EF_FRV_PIC;
417       frv_pic_p = 1;
418       frv_pic_flag = "-fpic";
419       break;
420 
421     case OPTION_BIGPIC:
422       frv_flags |= EF_FRV_BIGPIC;
423       frv_pic_p = 1;
424       frv_pic_flag = "-fPIC";
425       break;
426 
427     case OPTION_LIBPIC:
428       frv_flags |= (EF_FRV_LIBPIC | EF_FRV_G0);
429       frv_pic_p = 1;
430       frv_pic_flag = "-mlibrary-pic";
431       g_switch_value = 0;
432       break;
433 
434     case OPTION_FDPIC:
435       frv_flags |= EF_FRV_FDPIC;
436       frv_pic_flag = "-mfdpic";
437       break;
438 
439     case OPTION_NOPIC:
440       frv_flags &= ~(EF_FRV_FDPIC | EF_FRV_PIC
441 		     | EF_FRV_BIGPIC | EF_FRV_LIBPIC);
442       frv_pic_flag = 0;
443       break;
444 
445     case OPTION_TOMCAT_DEBUG:
446       tomcat_debug = 1;
447       break;
448 
449     case OPTION_TOMCAT_STATS:
450       tomcat_stats = 1;
451       break;
452     }
453 
454   return 1;
455 }
456 
457 void
458 md_show_usage (stream)
459   FILE * stream;
460 {
461   fprintf (stream, _("FRV specific command line options:\n"));
462   fprintf (stream, _("-G n         Data >= n bytes is in small data area\n"));
463   fprintf (stream, _("-mgpr-32     Note 32 gprs are used\n"));
464   fprintf (stream, _("-mgpr-64     Note 64 gprs are used\n"));
465   fprintf (stream, _("-mfpr-32     Note 32 fprs are used\n"));
466   fprintf (stream, _("-mfpr-64     Note 64 fprs are used\n"));
467   fprintf (stream, _("-msoft-float Note software fp is used\n"));
468   fprintf (stream, _("-mdword      Note stack is aligned to a 8 byte boundary\n"));
469   fprintf (stream, _("-mno-dword   Note stack is aligned to a 4 byte boundary\n"));
470   fprintf (stream, _("-mdouble     Note fp double insns are used\n"));
471   fprintf (stream, _("-mmedia      Note media insns are used\n"));
472   fprintf (stream, _("-mmuladd     Note multiply add/subtract insns are used\n"));
473   fprintf (stream, _("-mpack       Note instructions are packed\n"));
474   fprintf (stream, _("-mno-pack    Do not allow instructions to be packed\n"));
475   fprintf (stream, _("-mpic        Note small position independent code\n"));
476   fprintf (stream, _("-mPIC        Note large position independent code\n"));
477   fprintf (stream, _("-mlibrary-pic Compile library for large position indepedent code\n"));
478   fprintf (stream, _("-mfdpic      Assemble for the FDPIC ABI\n"));
479   fprintf (stream, _("-mnopic      Disable -mpic, -mPIC, -mlibrary-pic and -mfdpic\n"));
480   fprintf (stream, _("-mcpu={fr500|fr550|fr400|fr405|fr450|fr300|frv|simple|tomcat}\n"));
481   fprintf (stream, _("             Record the cpu type\n"));
482   fprintf (stream, _("-mtomcat-stats Print out stats for tomcat workarounds\n"));
483   fprintf (stream, _("-mtomcat-debug Debug tomcat workarounds\n"));
484 }
485 
486 
487 void
488 md_begin ()
489 {
490   /* Initialize the `cgen' interface.  */
491 
492   /* Set the machine number and endian.  */
493   gas_cgen_cpu_desc = frv_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
494 					 CGEN_CPU_OPEN_ENDIAN,
495 					 CGEN_ENDIAN_BIG,
496 					 CGEN_CPU_OPEN_END);
497   frv_cgen_init_asm (gas_cgen_cpu_desc);
498 
499   /* This is a callback from cgen to gas to parse operands.  */
500   cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
501 
502   /* Set the ELF flags if desired. */
503   if (frv_flags)
504     bfd_set_private_flags (stdoutput, frv_flags);
505 
506   /* Set the machine type */
507   bfd_default_set_arch_mach (stdoutput, bfd_arch_frv, frv_mach);
508 
509   /* Set up gp size so we can put local common items in .sbss */
510   bfd_set_gp_size (stdoutput, g_switch_value);
511 
512   frv_vliw_reset (& vliw, frv_mach, frv_flags);
513 }
514 
515 bfd_boolean
516 frv_md_fdpic_enabled (void)
517 {
518   return (frv_flags & EF_FRV_FDPIC) != 0;
519 }
520 
521 int chain_num = 0;
522 
523 struct vliw_insn_list *frv_insert_vliw_insn PARAMS ((bfd_boolean));
524 
525 struct vliw_insn_list *
526 frv_insert_vliw_insn (count)
527       bfd_boolean count;
528 {
529   struct vliw_insn_list *vliw_insn_list_entry;
530   struct vliw_chain     *vliw_chain_entry;
531 
532   if (current_vliw_chain == NULL)
533     {
534       vliw_chain_entry = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
535       vliw_chain_entry->insn_count = 0;
536       vliw_chain_entry->insn_list  = NULL;
537       vliw_chain_entry->next       = NULL;
538       vliw_chain_entry->num        = chain_num++;
539 
540       if (!vliw_chain_top)
541 	vliw_chain_top = vliw_chain_entry;
542       current_vliw_chain = vliw_chain_entry;
543       if (previous_vliw_chain)
544 	previous_vliw_chain->next = vliw_chain_entry;
545     }
546 
547   vliw_insn_list_entry = (struct vliw_insn_list *) xmalloc (sizeof (struct vliw_insn_list));
548   vliw_insn_list_entry->type      = VLIW_GENERIC_TYPE;
549   vliw_insn_list_entry->insn      = NULL;
550   vliw_insn_list_entry->sym       = NULL;
551   vliw_insn_list_entry->snop_frag = NULL;
552   vliw_insn_list_entry->dnop_frag = NULL;
553   vliw_insn_list_entry->next      = NULL;
554 
555   if (count)
556     current_vliw_chain->insn_count++;
557 
558   if (current_vliw_insn)
559     current_vliw_insn->next = vliw_insn_list_entry;
560   current_vliw_insn = vliw_insn_list_entry;
561 
562   if (!current_vliw_chain->insn_list)
563     current_vliw_chain->insn_list = current_vliw_insn;
564 
565   return vliw_insn_list_entry;
566 }
567 
568   /* Identify the following cases:
569 
570      1) A VLIW insn that contains both a branch and the branch destination.
571         This requires the insertion of two vliw instructions before the
572         branch.  The first consists of two nops.  The second consists of
573         a single nop.
574 
575      2) A single instruction VLIW insn which is the destination of a branch
576         that is in the next VLIW insn.  This requires the insertion of a vliw
577         insn containing two nops before the branch.
578 
579      3) A double instruction VLIW insn which contains the destination of a
580         branch that is in the next VLIW insn.  This requires the insertion of
581         a VLIW insn containing a single nop before the branch.
582 
583      4) A single instruction VLIW insn which contains branch destination (x),
584         followed by a single instruction VLIW insn which does not contain
585         the branch to (x), followed by a VLIW insn which does contain the branch
586         to (x).  This requires the insertion of a VLIW insn containing a single
587         nop before the VLIW instruction containing the branch.
588 
589   */
590 #define FRV_IS_NOP(insn) (insn.buffer[0] == FRV_NOP_PACK || insn.buffer[0] == FRV_NOP_NOPACK)
591 #define FRV_NOP_PACK   0x00880000  /* ori.p  gr0,0,gr0 */
592 #define FRV_NOP_NOPACK 0x80880000  /* ori    gr0,0,gr0 */
593 
594 /* Check a vliw insn for an insn of type containing the sym passed in label_sym.  */
595 
596 static struct vliw_insn_list *frv_find_in_vliw
597   PARAMS ((enum vliw_insn_type, struct vliw_chain *, symbolS *));
598 
599 static struct vliw_insn_list *
600 frv_find_in_vliw (vliw_insn_type, this_chain, label_sym)
601     enum vliw_insn_type vliw_insn_type;
602     struct vliw_chain *this_chain;
603     symbolS *label_sym;
604 {
605 
606   struct vliw_insn_list *the_insn;
607 
608   if (!this_chain)
609     return NULL;
610 
611   for (the_insn = this_chain->insn_list; the_insn; the_insn = the_insn->next)
612     {
613       if (the_insn->type == vliw_insn_type
614 	  && the_insn->sym == label_sym)
615 	return the_insn;
616     }
617 
618   return NULL;
619 }
620 
621 enum vliw_nop_type
622 {
623   /* A Vliw insn containing a single nop insn.  */
624   VLIW_SINGLE_NOP,
625 
626   /* A Vliw insn containing two nop insns.  */
627   VLIW_DOUBLE_NOP,
628 
629   /* Two vliw insns.  The first containing two nop insns.
630      The second contain a single nop insn.  */
631   VLIW_DOUBLE_THEN_SINGLE_NOP
632 };
633 
634 static void frv_debug_tomcat PARAMS ((struct vliw_chain *));
635 
636 static void
637 frv_debug_tomcat (start_chain)
638    struct vliw_chain *start_chain;
639 {
640    struct vliw_chain *this_chain;
641    struct vliw_insn_list *this_insn;
642    int i = 1;
643 
644   for (this_chain = start_chain; this_chain; this_chain = this_chain->next, i++)
645     {
646       fprintf (stderr, "\nVliw Insn #%d, #insns: %d\n", i, this_chain->insn_count);
647 
648       for (this_insn = this_chain->insn_list; this_insn; this_insn = this_insn->next)
649 	{
650 	  if (this_insn->type == VLIW_LABEL_TYPE)
651 	    fprintf (stderr, "Label Value: %p\n", this_insn->sym);
652 	  else if (this_insn->type == VLIW_BRANCH_TYPE)
653 	    fprintf (stderr, "%s to %p\n", this_insn->insn->base->name, this_insn->sym);
654 	  else if (this_insn->type == VLIW_BRANCH_HAS_NOPS)
655 	    fprintf (stderr, "nop'd %s to %p\n", this_insn->insn->base->name, this_insn->sym);
656 	  else if (this_insn->type == VLIW_NOP_TYPE)
657 	    fprintf (stderr, "Nop\n");
658 	  else
659 	    fprintf (stderr, "	%s\n", this_insn->insn->base->name);
660 	}
661    }
662 }
663 
664 static void frv_adjust_vliw_count PARAMS ((struct vliw_chain *));
665 
666 static void
667 frv_adjust_vliw_count (this_chain)
668     struct vliw_chain *this_chain;
669 {
670   struct vliw_insn_list *this_insn;
671 
672   this_chain->insn_count = 0;
673 
674   for (this_insn = this_chain->insn_list;
675        this_insn;
676        this_insn = this_insn->next)
677     {
678       if (this_insn->type != VLIW_LABEL_TYPE)
679   	this_chain->insn_count++;
680     }
681 
682 }
683 
684 /* Insert the desired nop combination in the vliw chain before insert_before_insn.
685    Rechain the vliw insn.  */
686 
687 static struct vliw_chain *frv_tomcat_shuffle
688   PARAMS ((enum vliw_nop_type, struct vliw_chain *, struct vliw_insn_list *));
689 
690 static struct vliw_chain *
691 frv_tomcat_shuffle (this_nop_type, vliw_to_split, insert_before_insn)
692    enum vliw_nop_type    this_nop_type;
693    struct vliw_chain     *vliw_to_split;
694    struct vliw_insn_list *insert_before_insn;
695 {
696 
697   bfd_boolean pack_prev = FALSE;
698   struct vliw_chain *return_me = NULL;
699   struct vliw_insn_list *prev_insn = NULL;
700   struct vliw_insn_list *curr_insn = vliw_to_split->insn_list;
701 
702   struct vliw_chain *double_nop = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
703   struct vliw_chain *single_nop = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
704   struct vliw_chain *second_part = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
705   struct vliw_chain *curr_vliw = vliw_chain_top;
706   struct vliw_chain *prev_vliw = NULL;
707 
708   while (curr_insn && curr_insn != insert_before_insn)
709     {
710       /* We can't set the packing bit on a label.  If we have the case
711 	 label 1:
712 	 label 2:
713 	 label 3:
714 	   branch that needs nops
715 	Then don't set pack bit later.  */
716 
717       if (curr_insn->type != VLIW_LABEL_TYPE)
718 	pack_prev = TRUE;
719       prev_insn = curr_insn;
720       curr_insn = curr_insn->next;
721     }
722 
723   while (curr_vliw && curr_vliw != vliw_to_split)
724     {
725       prev_vliw = curr_vliw;
726       curr_vliw = curr_vliw->next;
727     }
728 
729   switch (this_nop_type)
730     {
731     case VLIW_SINGLE_NOP:
732       if (!prev_insn)
733 	{
734 	/* Branch is first,  Insert the NOP prior to this vliw insn.  */
735 	if (prev_vliw)
736 	  prev_vliw->next = single_nop;
737 	else
738 	  vliw_chain_top = single_nop;
739 	single_nop->next = vliw_to_split;
740 	vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
741 	return_me = vliw_to_split;
742 	}
743       else
744 	{
745 	  /* Set the packing bit on the previous insn.  */
746 	  if (pack_prev)
747 	    {
748 	      char *buffer = prev_insn->address;
749 	      buffer[0] |= 0x80;
750 	    }
751 	  /* The branch is in the middle.  Split this vliw insn into first
752 	     and second parts.  Insert the NOP inbetween.  */
753 
754           second_part->insn_list = insert_before_insn;
755 	  second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
756           second_part->next      = vliw_to_split->next;
757  	  frv_adjust_vliw_count (second_part);
758 
759           single_nop->next       = second_part;
760 
761           vliw_to_split->next    = single_nop;
762           prev_insn->next        = NULL;
763 
764           return_me = second_part;
765 	  frv_adjust_vliw_count (vliw_to_split);
766 	}
767       break;
768 
769     case VLIW_DOUBLE_NOP:
770       if (!prev_insn)
771 	{
772 	/* Branch is first,  Insert the NOP prior to this vliw insn.  */
773         if (prev_vliw)
774           prev_vliw->next = double_nop;
775         else
776           vliw_chain_top = double_nop;
777 
778 	double_nop->next = vliw_to_split;
779 	return_me = vliw_to_split;
780 	vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
781 	}
782       else
783 	{
784 	  /* Set the packing bit on the previous insn.  */
785 	  if (pack_prev)
786 	    {
787 	      char *buffer = prev_insn->address;
788 	      buffer[0] |= 0x80;
789 	    }
790 
791 	/* The branch is in the middle.  Split this vliw insn into first
792 	   and second parts.  Insert the NOP inbetween.  */
793           second_part->insn_list = insert_before_insn;
794 	  second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
795           second_part->next      = vliw_to_split->next;
796  	  frv_adjust_vliw_count (second_part);
797 
798           double_nop->next       = second_part;
799 
800           vliw_to_split->next    = single_nop;
801           prev_insn->next        = NULL;
802  	  frv_adjust_vliw_count (vliw_to_split);
803 
804           return_me = second_part;
805 	}
806       break;
807 
808     case VLIW_DOUBLE_THEN_SINGLE_NOP:
809       double_nop->next = single_nop;
810       double_nop->insn_count = 2;
811       double_nop->insn_list = &double_nop_insn;
812       single_nop->insn_count = 1;
813       single_nop->insn_list = &single_nop_insn;
814 
815       if (!prev_insn)
816 	{
817 	  /* The branch is the first insn in this vliw.  Don't split the vliw.  Insert
818 	     the nops prior to this vliw.  */
819           if (prev_vliw)
820             prev_vliw->next = double_nop;
821           else
822             vliw_chain_top = double_nop;
823 
824 	  single_nop->next = vliw_to_split;
825 	  return_me = vliw_to_split;
826 	  vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
827 	}
828       else
829 	{
830 	  /* Set the packing bit on the previous insn.  */
831 	  if (pack_prev)
832 	    {
833 	      char *buffer = prev_insn->address;
834 	      buffer[0] |= 0x80;
835 	    }
836 
837 	  /* The branch is in the middle of this vliw insn.  Split into first and
838 	     second parts.  Insert the nop vliws in between.  */
839 	  second_part->insn_list = insert_before_insn;
840 	  second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
841 	  second_part->next      = vliw_to_split->next;
842  	  frv_adjust_vliw_count (second_part);
843 
844 	  single_nop->next       = second_part;
845 
846 	  vliw_to_split->next	 = double_nop;
847 	  prev_insn->next	 = NULL;
848  	  frv_adjust_vliw_count (vliw_to_split);
849 
850 	  return_me = second_part;
851 	}
852       break;
853     }
854 
855   return return_me;
856 }
857 
858 static void frv_tomcat_analyze_vliw_chains PARAMS ((void));
859 
860 static void
861 frv_tomcat_analyze_vliw_chains ()
862 {
863   struct vliw_chain *vliw1 = NULL;
864   struct vliw_chain *vliw2 = NULL;
865   struct vliw_chain *vliw3 = NULL;
866 
867   struct vliw_insn_list *this_insn = NULL;
868   struct vliw_insn_list *temp_insn = NULL;
869 
870   /* We potentially need to look at three VLIW insns to determine if the
871      workaround is required.  Set them up.  Ignore existing nops during analysis. */
872 
873 #define FRV_SET_VLIW_WINDOW(VLIW1, VLIW2, VLIW3) \
874   if (VLIW1 && VLIW1->next)			 \
875     VLIW2 = VLIW1->next;			 \
876   else						 \
877     VLIW2 = NULL;				 \
878   if (VLIW2 && VLIW2->next)			 \
879     VLIW3 = VLIW2->next;			 \
880   else						 \
881     VLIW3 = NULL
882 
883   vliw1 = vliw_chain_top;
884 
885 workaround_top:
886 
887   FRV_SET_VLIW_WINDOW (vliw1, vliw2, vliw3);
888 
889   if (!vliw1)
890     return;
891 
892   if (vliw1->insn_count == 1)
893     {
894       /* check vliw1 for a label. */
895       if (vliw1->insn_list->type == VLIW_LABEL_TYPE)
896 	{
897 	  temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw2, vliw1->insn_list->sym);
898 	  if (temp_insn)
899 	    {
900 	      vliw1 = frv_tomcat_shuffle (VLIW_DOUBLE_NOP, vliw2, vliw1->insn_list);
901 	      temp_insn->dnop_frag->fr_subtype = NOP_KEEP;
902 	      vliw1 = vliw1->next;
903 	      if (tomcat_stats)
904 		tomcat_doubles++;
905 	      goto workaround_top;
906 	    }
907 	  else if (vliw2
908 		   && vliw2->insn_count == 1
909 		   && (temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw3, vliw1->insn_list->sym)) != NULL)
910 	    {
911 	      temp_insn->snop_frag->fr_subtype = NOP_KEEP;
912 	      vliw1 = frv_tomcat_shuffle (VLIW_SINGLE_NOP, vliw3, vliw3->insn_list);
913 	      if (tomcat_stats)
914 		tomcat_singles++;
915 	      goto workaround_top;
916 	    }
917 	}
918     }
919 
920   if (vliw1->insn_count == 2)
921     {
922       struct vliw_insn_list *this_insn;
923 
924       /* check vliw1 for a label. */
925       for (this_insn = vliw1->insn_list; this_insn; this_insn = this_insn->next)
926 	{
927 	  if (this_insn->type == VLIW_LABEL_TYPE)
928 	    {
929 	      if ((temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw2, this_insn->sym)) != NULL)
930 		{
931 		  temp_insn->snop_frag->fr_subtype = NOP_KEEP;
932 		  vliw1 = frv_tomcat_shuffle (VLIW_SINGLE_NOP, vliw2, this_insn);
933 		  if (tomcat_stats)
934 		    tomcat_singles++;
935 		}
936 	      else
937 		vliw1 = vliw1->next;
938               goto workaround_top;
939             }
940 	}
941     }
942   /* Examine each insn in this VLIW.  Look for the workaround criteria.  */
943   for (this_insn = vliw1->insn_list; this_insn; this_insn = this_insn->next)
944     {
945       /* Don't look at labels or nops.  */
946       while (this_insn
947 	     && (this_insn->type == VLIW_LABEL_TYPE
948                  || this_insn->type == VLIW_NOP_TYPE
949 		 || this_insn->type == VLIW_BRANCH_HAS_NOPS))
950 	this_insn = this_insn->next;
951 
952       if (!this_insn)
953         {
954 	  vliw1 = vliw2;
955 	  goto workaround_top;
956 	}
957 
958       if (frv_is_branch_insn (this_insn->insn))
959 	{
960 	  if ((temp_insn = frv_find_in_vliw (VLIW_LABEL_TYPE, vliw1, this_insn->sym)) != NULL)
961 	    {
962 	      /* Insert [nop/nop] [nop] before branch.  */
963 	      this_insn->snop_frag->fr_subtype = NOP_KEEP;
964 	      this_insn->dnop_frag->fr_subtype = NOP_KEEP;
965 	      vliw1 = frv_tomcat_shuffle (VLIW_DOUBLE_THEN_SINGLE_NOP, vliw1, this_insn);
966 	      goto workaround_top;
967 	    }
968 	}
969 
970 
971     }
972   /* This vliw insn checks out okay.  Take a look at the next one.  */
973   vliw1 = vliw1->next;
974   goto workaround_top;
975 }
976 
977 void
978 frv_tomcat_workaround ()
979 {
980   if (frv_mach != bfd_mach_frvtomcat)
981     return;
982 
983   if (tomcat_debug)
984     frv_debug_tomcat (vliw_chain_top);
985 
986   frv_tomcat_analyze_vliw_chains ();
987 
988   if (tomcat_stats)
989     {
990       fprintf (stderr, "Inserted %d Single Nops\n", tomcat_singles);
991       fprintf (stderr, "Inserted %d Double Nops\n", tomcat_doubles);
992     }
993 }
994 
995 static int
996 fr550_check_insn_acc_range (frv_insn *insn, int low, int hi)
997 {
998   int acc;
999   switch (CGEN_INSN_NUM (insn->insn))
1000     {
1001     case FRV_INSN_MADDACCS:
1002     case FRV_INSN_MSUBACCS:
1003     case FRV_INSN_MDADDACCS:
1004     case FRV_INSN_MDSUBACCS:
1005     case FRV_INSN_MASACCS:
1006     case FRV_INSN_MDASACCS:
1007       acc = insn->fields.f_ACC40Si;
1008       if (acc < low || acc > hi)
1009 	return 1; /* out of range */
1010       acc = insn->fields.f_ACC40Sk;
1011       if (acc < low || acc > hi)
1012 	return 1; /* out of range */
1013       break;
1014     case FRV_INSN_MMULHS:
1015     case FRV_INSN_MMULHU:
1016     case FRV_INSN_MMULXHS:
1017     case FRV_INSN_MMULXHU:
1018     case FRV_INSN_CMMULHS:
1019     case FRV_INSN_CMMULHU:
1020     case FRV_INSN_MQMULHS:
1021     case FRV_INSN_MQMULHU:
1022     case FRV_INSN_MQMULXHS:
1023     case FRV_INSN_MQMULXHU:
1024     case FRV_INSN_CMQMULHS:
1025     case FRV_INSN_CMQMULHU:
1026     case FRV_INSN_MMACHS:
1027     case FRV_INSN_MMRDHS:
1028     case FRV_INSN_CMMACHS:
1029     case FRV_INSN_MQMACHS:
1030     case FRV_INSN_CMQMACHS:
1031     case FRV_INSN_MQXMACHS:
1032     case FRV_INSN_MQXMACXHS:
1033     case FRV_INSN_MQMACXHS:
1034     case FRV_INSN_MCPXRS:
1035     case FRV_INSN_MCPXIS:
1036     case FRV_INSN_CMCPXRS:
1037     case FRV_INSN_CMCPXIS:
1038     case FRV_INSN_MQCPXRS:
1039     case FRV_INSN_MQCPXIS:
1040      acc = insn->fields.f_ACC40Sk;
1041       if (acc < low || acc > hi)
1042 	return 1; /* out of range */
1043       break;
1044     case FRV_INSN_MMACHU:
1045     case FRV_INSN_MMRDHU:
1046     case FRV_INSN_CMMACHU:
1047     case FRV_INSN_MQMACHU:
1048     case FRV_INSN_CMQMACHU:
1049     case FRV_INSN_MCPXRU:
1050     case FRV_INSN_MCPXIU:
1051     case FRV_INSN_CMCPXRU:
1052     case FRV_INSN_CMCPXIU:
1053     case FRV_INSN_MQCPXRU:
1054     case FRV_INSN_MQCPXIU:
1055       acc = insn->fields.f_ACC40Uk;
1056       if (acc < low || acc > hi)
1057 	return 1; /* out of range */
1058       break;
1059     default:
1060       break;
1061     }
1062   return 0; /* all is ok */
1063 }
1064 
1065 static int
1066 fr550_check_acc_range (FRV_VLIW *vliw, frv_insn *insn)
1067 {
1068   switch ((*vliw->current_vliw)[vliw->next_slot - 1])
1069     {
1070     case UNIT_FM0:
1071     case UNIT_FM2:
1072       return fr550_check_insn_acc_range (insn, 0, 3);
1073     case UNIT_FM1:
1074     case UNIT_FM3:
1075       return fr550_check_insn_acc_range (insn, 4, 7);
1076     default:
1077       break;
1078     }
1079   return 0; /* all is ok */
1080 }
1081 
1082 /* Return true if the target implements instruction INSN.  */
1083 
1084 static bfd_boolean
1085 target_implements_insn_p (const CGEN_INSN *insn)
1086 {
1087   switch (frv_mach)
1088     {
1089     default:
1090       /* bfd_mach_frv or generic.  */
1091       return TRUE;
1092 
1093     case bfd_mach_fr300:
1094     case bfd_mach_frvsimple:
1095       return CGEN_INSN_MACH_HAS_P (insn, MACH_SIMPLE);
1096 
1097     case bfd_mach_fr400:
1098       return ((fr400_audio || !CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_AUDIO))
1099 	      && CGEN_INSN_MACH_HAS_P (insn, MACH_FR400));
1100 
1101     case bfd_mach_fr450:
1102       return CGEN_INSN_MACH_HAS_P (insn, MACH_FR450);
1103 
1104     case bfd_mach_fr500:
1105       return CGEN_INSN_MACH_HAS_P (insn, MACH_FR500);
1106 
1107     case bfd_mach_fr550:
1108       return CGEN_INSN_MACH_HAS_P (insn, MACH_FR550);
1109     }
1110 }
1111 
1112 void
1113 md_assemble (str)
1114      char * str;
1115 {
1116   frv_insn insn;
1117   char *errmsg;
1118   int packing_constraint;
1119   finished_insnS  finished_insn;
1120   fragS *double_nop_frag = NULL;
1121   fragS *single_nop_frag = NULL;
1122   struct vliw_insn_list *vliw_insn_list_entry = NULL;
1123 
1124   /* Initialize GAS's cgen interface for a new instruction.  */
1125   gas_cgen_init_parse ();
1126 
1127   memset (&insn, 0, sizeof (insn));
1128 
1129   insn.insn = frv_cgen_assemble_insn
1130     (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, &errmsg);
1131 
1132   if (!insn.insn)
1133     {
1134       as_bad (errmsg);
1135       return;
1136     }
1137 
1138   /* If the cpu is tomcat, then we need to insert nops to workaround
1139      hardware limitations.  We need to keep track of each vliw unit
1140      and examine the length of the unit and the individual insns
1141      within the unit to determine the number and location of the
1142      required nops.  */
1143   if (frv_mach == bfd_mach_frvtomcat)
1144     {
1145       /* If we've just finished a VLIW insn OR this is a branch,
1146 	 then start up a new frag.  Fill it with nops.  We will get rid
1147 	 of those that are not required after we've seen all of the
1148 	 instructions but before we start resolving fixups.  */
1149       if ( !FRV_IS_NOP (insn)
1150 	  && (frv_is_branch_insn (insn.insn) || insn.fields.f_pack))
1151 	{
1152 	  char *buffer;
1153 
1154 	  frag_wane (frag_now);
1155 	  frag_new (0);
1156 	  double_nop_frag = frag_now;
1157 	  buffer = frag_var (rs_machine_dependent, 8, 8, NOP_DELETE, NULL, 0, 0);
1158 	  md_number_to_chars (buffer, FRV_NOP_PACK, 4);
1159 	  md_number_to_chars (buffer+4, FRV_NOP_NOPACK, 4);
1160 
1161 	  frag_wane (frag_now);
1162 	  frag_new (0);
1163 	  single_nop_frag = frag_now;
1164 	  buffer = frag_var (rs_machine_dependent, 4, 4, NOP_DELETE, NULL, 0, 0);
1165 	  md_number_to_chars (buffer, FRV_NOP_NOPACK, 4);
1166 	}
1167 
1168       vliw_insn_list_entry = frv_insert_vliw_insn (DO_COUNT);
1169       vliw_insn_list_entry->insn   = insn.insn;
1170       if (frv_is_branch_insn (insn.insn))
1171 	vliw_insn_list_entry->type = VLIW_BRANCH_TYPE;
1172 
1173       if ( !FRV_IS_NOP (insn)
1174 	  && (frv_is_branch_insn (insn.insn) || insn.fields.f_pack))
1175 	{
1176 	  vliw_insn_list_entry->snop_frag = single_nop_frag;
1177 	  vliw_insn_list_entry->dnop_frag = double_nop_frag;
1178 	}
1179     }
1180 
1181   /* Make sure that this insn does not violate the VLIW packing constraints.  */
1182   /* -mno-pack disallows any packing whatsoever.  */
1183   if (frv_flags & EF_FRV_NOPACK)
1184     {
1185       if (! insn.fields.f_pack)
1186 	{
1187 	  as_bad (_("VLIW packing used for -mno-pack"));
1188 	  return;
1189 	}
1190     }
1191   /* -mcpu=FRV is an idealized FR-V implementation that supports all of the
1192      instructions, don't do vliw checking.  */
1193   else if (frv_mach != bfd_mach_frv)
1194     {
1195       if (!target_implements_insn_p (insn.insn))
1196 	{
1197 	  as_bad (_("Instruction not supported by this architecture"));
1198 	  return;
1199 	}
1200       packing_constraint = frv_vliw_add_insn (& vliw, insn.insn);
1201       if (frv_mach == bfd_mach_fr550 && ! packing_constraint)
1202 	packing_constraint = fr550_check_acc_range (& vliw, & insn);
1203       if (insn.fields.f_pack)
1204 	frv_vliw_reset (& vliw, frv_mach, frv_flags);
1205       if (packing_constraint)
1206 	{
1207 	  as_bad (_("VLIW packing constraint violation"));
1208 	  return;
1209 	}
1210     }
1211 
1212   /* Doesn't really matter what we pass for RELAX_P here.  */
1213   gas_cgen_finish_insn (insn.insn, insn.buffer,
1214 			CGEN_FIELDS_BITSIZE (& insn.fields), 1, &finished_insn);
1215 
1216 
1217   /* If the cpu is tomcat, then we need to insert nops to workaround
1218      hardware limitations.  We need to keep track of each vliw unit
1219      and examine the length of the unit and the individual insns
1220      within the unit to determine the number and location of the
1221      required nops.  */
1222   if (frv_mach == bfd_mach_frvtomcat)
1223     {
1224       if (vliw_insn_list_entry)
1225         vliw_insn_list_entry->address = finished_insn.addr;
1226       else
1227 	abort();
1228 
1229       if (insn.fields.f_pack)
1230 	{
1231 	  /* We've completed a VLIW insn.  */
1232 	  previous_vliw_chain = current_vliw_chain;
1233 	  current_vliw_chain = NULL;
1234 	  current_vliw_insn  = NULL;
1235         }
1236     }
1237 }
1238 
1239 /* The syntax in the manual says constants begin with '#'.
1240    We just ignore it.  */
1241 
1242 void
1243 md_operand (expressionP)
1244      expressionS * expressionP;
1245 {
1246   if (* input_line_pointer == '#')
1247     {
1248       input_line_pointer ++;
1249       expression (expressionP);
1250     }
1251 }
1252 
1253 valueT
1254 md_section_align (segment, size)
1255      segT   segment;
1256      valueT size;
1257 {
1258   int align = bfd_get_section_alignment (stdoutput, segment);
1259   return ((size + (1 << align) - 1) & (-1 << align));
1260 }
1261 
1262 symbolS *
1263 md_undefined_symbol (name)
1264   char * name ATTRIBUTE_UNUSED;
1265 {
1266   return 0;
1267 }
1268 
1269 /* Interface to relax_segment.  */
1270 
1271 /* FIXME: Build table by hand, get it working, then machine generate.  */
1272 const relax_typeS md_relax_table[] =
1273 {
1274   {1, 1, 0, 0},
1275   {511 - 2 - 2, -512 - 2 + 2, 0, 2 },
1276   {0x2000000 - 1 - 2, -0x2000000 - 2, 2, 0 },
1277   {0x2000000 - 1 - 2, -0x2000000 - 2, 4, 0 }
1278 };
1279 
1280 long
1281 frv_relax_frag (fragP, stretch)
1282      fragS   *fragP ATTRIBUTE_UNUSED;
1283      long    stretch ATTRIBUTE_UNUSED;
1284 {
1285   return 0;
1286 }
1287 
1288 /* Return an initial guess of the length by which a fragment must grow to
1289    hold a branch to reach its destination.
1290    Also updates fr_type/fr_subtype as necessary.
1291 
1292    Called just before doing relaxation.
1293    Any symbol that is now undefined will not become defined.
1294    The guess for fr_var is ACTUALLY the growth beyond fr_fix.
1295    Whatever we do to grow fr_fix or fr_var contributes to our returned value.
1296    Although it may not be explicit in the frag, pretend fr_var starts with a
1297    0 value.  */
1298 
1299 int
1300 md_estimate_size_before_relax (fragP, segment)
1301      fragS * fragP;
1302      segT    segment ATTRIBUTE_UNUSED;
1303 {
1304   switch (fragP->fr_subtype)
1305     {
1306     case NOP_KEEP:
1307       return fragP->fr_var;
1308 
1309     default:
1310     case NOP_DELETE:
1311       return 0;
1312     }
1313 }
1314 
1315 /* *fragP has been relaxed to its final size, and now needs to have
1316    the bytes inside it modified to conform to the new size.
1317 
1318    Called after relaxation is finished.
1319    fragP->fr_type == rs_machine_dependent.
1320    fragP->fr_subtype is the subtype of what the address relaxed to.  */
1321 
1322 void
1323 md_convert_frag (abfd, sec, fragP)
1324   bfd *   abfd ATTRIBUTE_UNUSED;
1325   segT    sec ATTRIBUTE_UNUSED;
1326   fragS * fragP;
1327 {
1328   switch (fragP->fr_subtype)
1329     {
1330     default:
1331     case NOP_DELETE:
1332       return;
1333 
1334     case NOP_KEEP:
1335       fragP->fr_fix = fragP->fr_var;
1336       fragP->fr_var = 0;
1337       return;
1338     }
1339 }
1340 
1341 /* Functions concerning relocs.  */
1342 
1343 /* The location from which a PC relative jump should be calculated,
1344    given a PC relative reloc.  */
1345 
1346 long
1347 md_pcrel_from_section (fixP, sec)
1348      fixS * fixP;
1349      segT   sec;
1350 {
1351   if (TC_FORCE_RELOCATION (fixP)
1352       || (fixP->fx_addsy != (symbolS *) NULL
1353 	  && S_GET_SEGMENT (fixP->fx_addsy) != sec))
1354     {
1355       /* If we can't adjust this relocation, or if it references a
1356 	 local symbol in a different section (which
1357 	 TC_FORCE_RELOCATION can't check), let the linker figure it
1358 	 out.  */
1359       return 0;
1360     }
1361 
1362   return (fixP->fx_frag->fr_address + fixP->fx_where) & ~1;
1363 }
1364 
1365 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
1366    Returns BFD_RELOC_NONE if no reloc type can be found.
1367    *FIXP may be modified if desired.  */
1368 
1369 bfd_reloc_code_real_type
1370 md_cgen_lookup_reloc (insn, operand, fixP)
1371      const CGEN_INSN *    insn ATTRIBUTE_UNUSED;
1372      const CGEN_OPERAND * operand;
1373      fixS *               fixP;
1374 {
1375   switch (operand->type)
1376     {
1377     case FRV_OPERAND_LABEL16:
1378       fixP->fx_pcrel = TRUE;
1379       return BFD_RELOC_FRV_LABEL16;
1380 
1381     case FRV_OPERAND_LABEL24:
1382       fixP->fx_pcrel = TRUE;
1383 
1384       if (fixP->fx_cgen.opinfo != 0)
1385 	return fixP->fx_cgen.opinfo;
1386 
1387       return BFD_RELOC_FRV_LABEL24;
1388 
1389     case FRV_OPERAND_UHI16:
1390     case FRV_OPERAND_ULO16:
1391     case FRV_OPERAND_SLO16:
1392     case FRV_OPERAND_CALLANN:
1393     case FRV_OPERAND_LDANN:
1394     case FRV_OPERAND_LDDANN:
1395       /* The relocation type should be recorded in opinfo */
1396       if (fixP->fx_cgen.opinfo != 0)
1397         return fixP->fx_cgen.opinfo;
1398       break;
1399 
1400     case FRV_OPERAND_D12:
1401     case FRV_OPERAND_S12:
1402       if (fixP->fx_cgen.opinfo != 0)
1403 	return fixP->fx_cgen.opinfo;
1404 
1405       return BFD_RELOC_FRV_GPREL12;
1406 
1407     case FRV_OPERAND_U12:
1408       return BFD_RELOC_FRV_GPRELU12;
1409 
1410     default:
1411       break;
1412     }
1413   return BFD_RELOC_NONE;
1414 }
1415 
1416 
1417 /* See whether we need to force a relocation into the output file.
1418    This is used to force out switch and PC relative relocations when
1419    relaxing.  */
1420 
1421 int
1422 frv_force_relocation (fix)
1423      fixS * fix;
1424 {
1425   switch (fix->fx_r_type < BFD_RELOC_UNUSED
1426 	  ? (int) fix->fx_r_type
1427 	  : fix->fx_cgen.opinfo)
1428     {
1429     case BFD_RELOC_FRV_GPREL12:
1430     case BFD_RELOC_FRV_GPRELU12:
1431     case BFD_RELOC_FRV_GPREL32:
1432     case BFD_RELOC_FRV_GPRELHI:
1433     case BFD_RELOC_FRV_GPRELLO:
1434     case BFD_RELOC_FRV_GOT12:
1435     case BFD_RELOC_FRV_GOTHI:
1436     case BFD_RELOC_FRV_GOTLO:
1437     case BFD_RELOC_FRV_FUNCDESC_VALUE:
1438     case BFD_RELOC_FRV_FUNCDESC_GOTOFF12:
1439     case BFD_RELOC_FRV_FUNCDESC_GOTOFFHI:
1440     case BFD_RELOC_FRV_FUNCDESC_GOTOFFLO:
1441     case BFD_RELOC_FRV_GOTOFF12:
1442     case BFD_RELOC_FRV_GOTOFFHI:
1443     case BFD_RELOC_FRV_GOTOFFLO:
1444     case BFD_RELOC_FRV_GETTLSOFF:
1445     case BFD_RELOC_FRV_TLSDESC_VALUE:
1446     case BFD_RELOC_FRV_GOTTLSDESC12:
1447     case BFD_RELOC_FRV_GOTTLSDESCHI:
1448     case BFD_RELOC_FRV_GOTTLSDESCLO:
1449     case BFD_RELOC_FRV_TLSMOFF12:
1450     case BFD_RELOC_FRV_TLSMOFFHI:
1451     case BFD_RELOC_FRV_TLSMOFFLO:
1452     case BFD_RELOC_FRV_GOTTLSOFF12:
1453     case BFD_RELOC_FRV_GOTTLSOFFHI:
1454     case BFD_RELOC_FRV_GOTTLSOFFLO:
1455     case BFD_RELOC_FRV_TLSOFF:
1456     case BFD_RELOC_FRV_TLSDESC_RELAX:
1457     case BFD_RELOC_FRV_GETTLSOFF_RELAX:
1458     case BFD_RELOC_FRV_TLSOFF_RELAX:
1459       return 1;
1460 
1461     default:
1462       break;
1463     }
1464 
1465   return generic_force_reloc (fix);
1466 }
1467 
1468 /* Apply a fixup that could be resolved within the assembler.  */
1469 
1470 void
1471 md_apply_fix (fixP, valP, seg)
1472      fixS *   fixP;
1473      valueT * valP;
1474      segT     seg;
1475 {
1476   if (fixP->fx_addsy == 0)
1477     switch (fixP->fx_cgen.opinfo)
1478       {
1479       case BFD_RELOC_FRV_HI16:
1480 	*valP >>= 16;
1481 	/* Fall through.  */
1482       case BFD_RELOC_FRV_LO16:
1483 	*valP &= 0xffff;
1484 	break;
1485 
1486 	/* We need relocations for these, even if their symbols reduce
1487 	   to constants.  */
1488       case BFD_RELOC_FRV_GPREL12:
1489       case BFD_RELOC_FRV_GPRELU12:
1490       case BFD_RELOC_FRV_GPREL32:
1491       case BFD_RELOC_FRV_GPRELHI:
1492       case BFD_RELOC_FRV_GPRELLO:
1493       case BFD_RELOC_FRV_GOT12:
1494       case BFD_RELOC_FRV_GOTHI:
1495       case BFD_RELOC_FRV_GOTLO:
1496       case BFD_RELOC_FRV_FUNCDESC_VALUE:
1497       case BFD_RELOC_FRV_FUNCDESC_GOTOFF12:
1498       case BFD_RELOC_FRV_FUNCDESC_GOTOFFHI:
1499       case BFD_RELOC_FRV_FUNCDESC_GOTOFFLO:
1500       case BFD_RELOC_FRV_GOTOFF12:
1501       case BFD_RELOC_FRV_GOTOFFHI:
1502       case BFD_RELOC_FRV_GOTOFFLO:
1503       case BFD_RELOC_FRV_GETTLSOFF:
1504       case BFD_RELOC_FRV_TLSDESC_VALUE:
1505       case BFD_RELOC_FRV_GOTTLSDESC12:
1506       case BFD_RELOC_FRV_GOTTLSDESCHI:
1507       case BFD_RELOC_FRV_GOTTLSDESCLO:
1508       case BFD_RELOC_FRV_TLSMOFF12:
1509       case BFD_RELOC_FRV_TLSMOFFHI:
1510       case BFD_RELOC_FRV_TLSMOFFLO:
1511       case BFD_RELOC_FRV_GOTTLSOFF12:
1512       case BFD_RELOC_FRV_GOTTLSOFFHI:
1513       case BFD_RELOC_FRV_GOTTLSOFFLO:
1514       case BFD_RELOC_FRV_TLSOFF:
1515       case BFD_RELOC_FRV_TLSDESC_RELAX:
1516       case BFD_RELOC_FRV_GETTLSOFF_RELAX:
1517       case BFD_RELOC_FRV_TLSOFF_RELAX:
1518 	fixP->fx_addsy = expr_build_uconstant (0);
1519 	break;
1520       }
1521   else
1522     switch (fixP->fx_cgen.opinfo)
1523       {
1524       case BFD_RELOC_FRV_GETTLSOFF:
1525       case BFD_RELOC_FRV_TLSDESC_VALUE:
1526       case BFD_RELOC_FRV_GOTTLSDESC12:
1527       case BFD_RELOC_FRV_GOTTLSDESCHI:
1528       case BFD_RELOC_FRV_GOTTLSDESCLO:
1529       case BFD_RELOC_FRV_TLSMOFF12:
1530       case BFD_RELOC_FRV_TLSMOFFHI:
1531       case BFD_RELOC_FRV_TLSMOFFLO:
1532       case BFD_RELOC_FRV_GOTTLSOFF12:
1533       case BFD_RELOC_FRV_GOTTLSOFFHI:
1534       case BFD_RELOC_FRV_GOTTLSOFFLO:
1535       case BFD_RELOC_FRV_TLSOFF:
1536       case BFD_RELOC_FRV_TLSDESC_RELAX:
1537       case BFD_RELOC_FRV_GETTLSOFF_RELAX:
1538       case BFD_RELOC_FRV_TLSOFF_RELAX:
1539 	/* Mark TLS symbols as such.  */
1540 	if (S_GET_SEGMENT (fixP->fx_addsy) != absolute_section)
1541 	  S_SET_THREAD_LOCAL (fixP->fx_addsy);
1542 	break;
1543       }
1544 
1545   gas_cgen_md_apply_fix (fixP, valP, seg);
1546   return;
1547 }
1548 
1549 
1550 /* Write a value out to the object file, using the appropriate endianness.  */
1551 
1552 void
1553 frv_md_number_to_chars (buf, val, n)
1554      char * buf;
1555      valueT val;
1556      int    n;
1557 {
1558   number_to_chars_bigendian (buf, val, n);
1559 }
1560 
1561 /* Turn a string in input_line_pointer into a floating point constant of type
1562    type, and store the appropriate bytes in *litP.  The number of LITTLENUMS
1563    emitted is stored in *sizeP .  An error message is returned, or NULL on OK.
1564 */
1565 
1566 /* Equal to MAX_PRECISION in atof-ieee.c */
1567 #define MAX_LITTLENUMS 6
1568 
1569 char *
1570 md_atof (type, litP, sizeP)
1571      char   type;
1572      char * litP;
1573      int *  sizeP;
1574 {
1575   int              i;
1576   int              prec;
1577   LITTLENUM_TYPE   words [MAX_LITTLENUMS];
1578   char *           t;
1579 
1580   switch (type)
1581     {
1582     case 'f':
1583     case 'F':
1584     case 's':
1585     case 'S':
1586       prec = 2;
1587       break;
1588 
1589     case 'd':
1590     case 'D':
1591     case 'r':
1592     case 'R':
1593       prec = 4;
1594       break;
1595 
1596    /* FIXME: Some targets allow other format chars for bigger sizes here.  */
1597 
1598     default:
1599       * sizeP = 0;
1600       return _("Bad call to md_atof()");
1601     }
1602 
1603   t = atof_ieee (input_line_pointer, type, words);
1604   if (t)
1605     input_line_pointer = t;
1606   * sizeP = prec * sizeof (LITTLENUM_TYPE);
1607 
1608   for (i = 0; i < prec; i++)
1609     {
1610       md_number_to_chars (litP, (valueT) words[i],
1611 			  sizeof (LITTLENUM_TYPE));
1612       litP += sizeof (LITTLENUM_TYPE);
1613     }
1614 
1615   return 0;
1616 }
1617 
1618 bfd_boolean
1619 frv_fix_adjustable (fixP)
1620    fixS * fixP;
1621 {
1622   bfd_reloc_code_real_type reloc_type;
1623 
1624   if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
1625     {
1626       const CGEN_INSN *insn = NULL;
1627       int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
1628       const CGEN_OPERAND *operand = cgen_operand_lookup_by_num(gas_cgen_cpu_desc, opindex);
1629       reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
1630     }
1631   else
1632     reloc_type = fixP->fx_r_type;
1633 
1634   /* We need the symbol name for the VTABLE entries */
1635   if (   reloc_type == BFD_RELOC_VTABLE_INHERIT
1636       || reloc_type == BFD_RELOC_VTABLE_ENTRY
1637       || reloc_type == BFD_RELOC_FRV_GPREL12
1638       || reloc_type == BFD_RELOC_FRV_GPRELU12)
1639     return 0;
1640 
1641   return 1;
1642 }
1643 
1644 /* Allow user to set flags bits.  */
1645 void
1646 frv_set_flags (arg)
1647      int arg ATTRIBUTE_UNUSED;
1648 {
1649   flagword new_flags = get_absolute_expression ();
1650   flagword new_mask = ~ (flagword)0;
1651 
1652   frv_user_set_flags_p = 1;
1653   if (*input_line_pointer == ',')
1654     {
1655       ++input_line_pointer;
1656       new_mask = get_absolute_expression ();
1657     }
1658 
1659   frv_flags = (frv_flags & ~new_mask) | (new_flags & new_mask);
1660   bfd_set_private_flags (stdoutput, frv_flags);
1661 }
1662 
1663 /* Frv specific function to handle 4 byte initializations for pointers that are
1664    considered 'safe' for use with pic support.  Until frv_frob_file{,_section}
1665    is run, we encode it a BFD_RELOC_CTOR, and it is turned back into a normal
1666    BFD_RELOC_32 at that time.  */
1667 
1668 void
1669 frv_pic_ptr (nbytes)
1670      int nbytes;
1671 {
1672   expressionS exp;
1673   char *p;
1674 
1675   if (nbytes != 4)
1676     abort ();
1677 
1678 #ifdef md_flush_pending_output
1679   md_flush_pending_output ();
1680 #endif
1681 
1682   if (is_it_end_of_statement ())
1683     {
1684       demand_empty_rest_of_line ();
1685       return;
1686     }
1687 
1688 #ifdef md_cons_align
1689   md_cons_align (nbytes);
1690 #endif
1691 
1692   do
1693     {
1694       bfd_reloc_code_real_type reloc_type = BFD_RELOC_CTOR;
1695 
1696       if (strncasecmp (input_line_pointer, "funcdesc(", 9) == 0)
1697 	{
1698 	  input_line_pointer += 9;
1699 	  expression (&exp);
1700 	  if (*input_line_pointer == ')')
1701 	    input_line_pointer++;
1702 	  else
1703 	    as_bad ("missing ')'");
1704 	  reloc_type = BFD_RELOC_FRV_FUNCDESC;
1705 	}
1706       else if (strncasecmp (input_line_pointer, "tlsmoff(", 8) == 0)
1707 	{
1708 	  input_line_pointer += 8;
1709 	  expression (&exp);
1710 	  if (*input_line_pointer == ')')
1711 	    input_line_pointer++;
1712 	  else
1713 	    as_bad ("missing ')'");
1714 	  reloc_type = BFD_RELOC_FRV_TLSMOFF;
1715 	}
1716       else
1717 	expression (&exp);
1718 
1719       p = frag_more (4);
1720       memset (p, 0, 4);
1721       fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &exp, 0,
1722 		   reloc_type);
1723     }
1724   while (*input_line_pointer++ == ',');
1725 
1726   input_line_pointer--;			/* Put terminator back into stream. */
1727   demand_empty_rest_of_line ();
1728 }
1729 
1730 
1731 
1732 #ifdef DEBUG
1733 #define DPRINTF1(A)	fprintf (stderr, A)
1734 #define DPRINTF2(A,B)	fprintf (stderr, A, B)
1735 #define DPRINTF3(A,B,C)	fprintf (stderr, A, B, C)
1736 
1737 #else
1738 #define DPRINTF1(A)
1739 #define DPRINTF2(A,B)
1740 #define DPRINTF3(A,B,C)
1741 #endif
1742 
1743 /* Go through a the sections looking for relocations that are problematical for
1744    pic.  If not pic, just note that this object can't be linked with pic.  If
1745    it is pic, see if it needs to be marked so that it will be fixed up, or if
1746    not possible, issue an error.  */
1747 
1748 static void
1749 frv_frob_file_section (abfd, sec, ptr)
1750      bfd *abfd;
1751      asection *sec;
1752      PTR ptr ATTRIBUTE_UNUSED;
1753 {
1754   segment_info_type *seginfo = seg_info (sec);
1755   fixS *fixp;
1756   CGEN_CPU_DESC cd = gas_cgen_cpu_desc;
1757   flagword flags = bfd_get_section_flags (abfd, sec);
1758 
1759   /* Skip relocations in known sections (.ctors, .dtors, and .gcc_except_table)
1760      since we can fix those up by hand.  */
1761   int known_section_p = (sec->name
1762 			 && sec->name[0] == '.'
1763 			 && ((sec->name[1] == 'c'
1764 			      && strcmp (sec->name, ".ctor") == 0)
1765 			     || (sec->name[1] == 'd'
1766 				 && strcmp (sec->name, ".dtor") == 0)
1767 			     || (sec->name[1] == 'g'
1768 				 && strcmp (sec->name, ".gcc_except_table") == 0)));
1769 
1770   DPRINTF3 ("\nFrv section %s%s\n", sec->name, (known_section_p) ? ", known section" : "");
1771   if ((flags & SEC_ALLOC) == 0)
1772     {
1773       DPRINTF1 ("\tSkipping non-loaded section\n");
1774       return;
1775     }
1776 
1777   for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next)
1778     {
1779       symbolS *s = fixp->fx_addsy;
1780       bfd_reloc_code_real_type reloc;
1781       int non_pic_p;
1782       int opindex;
1783       const CGEN_OPERAND *operand;
1784       const CGEN_INSN *insn = fixp->fx_cgen.insn;
1785 
1786       if (fixp->fx_done)
1787 	{
1788 	  DPRINTF1 ("\tSkipping reloc that has already been done\n");
1789 	  continue;
1790 	}
1791 
1792       if (fixp->fx_pcrel)
1793 	{
1794 	  DPRINTF1 ("\tSkipping reloc that is PC relative\n");
1795 	  continue;
1796 	}
1797 
1798       if (! s)
1799 	{
1800 	  DPRINTF1 ("\tSkipping reloc without symbol\n");
1801 	  continue;
1802 	}
1803 
1804       if (fixp->fx_r_type < BFD_RELOC_UNUSED)
1805 	{
1806 	  opindex = -1;
1807 	  reloc = fixp->fx_r_type;
1808 	}
1809       else
1810 	{
1811 	  opindex = (int) fixp->fx_r_type - (int) BFD_RELOC_UNUSED;
1812 	  operand = cgen_operand_lookup_by_num (cd, opindex);
1813 	  reloc = md_cgen_lookup_reloc (insn, operand, fixp);
1814 	}
1815 
1816       DPRINTF3 ("\treloc %s\t%s", bfd_get_reloc_code_name (reloc), S_GET_NAME (s));
1817 
1818       non_pic_p = 0;
1819       switch (reloc)
1820 	{
1821 	default:
1822 	  break;
1823 
1824 	case BFD_RELOC_32:
1825 	  /* Skip relocations in known sections (.ctors, .dtors, and
1826 	     .gcc_except_table) since we can fix those up by hand.  Also
1827 	     skip forward references to constants.  Also skip a difference
1828 	     of two symbols, which still uses the BFD_RELOC_32 at this
1829 	     point.  */
1830 	  if (! known_section_p
1831 	      && S_GET_SEGMENT (s) != absolute_section
1832 	      && !fixp->fx_subsy
1833 	      && (flags & (SEC_READONLY | SEC_CODE)) == 0)
1834 	    {
1835 	      non_pic_p = 1;
1836 	    }
1837 	  break;
1838 
1839 	  /* FIXME -- should determine if any of the GP relocation really uses
1840 	     gr16 (which is not pic safe) or not.  Right now, assume if we
1841 	     aren't being compiled with -mpic, the usage is non pic safe, but
1842 	     is safe with -mpic.  */
1843 	case BFD_RELOC_FRV_GPREL12:
1844 	case BFD_RELOC_FRV_GPRELU12:
1845 	case BFD_RELOC_FRV_GPREL32:
1846 	case BFD_RELOC_FRV_GPRELHI:
1847 	case BFD_RELOC_FRV_GPRELLO:
1848 	  non_pic_p = ! frv_pic_p;
1849 	  break;
1850 
1851 	case BFD_RELOC_FRV_LO16:
1852 	case BFD_RELOC_FRV_HI16:
1853 	  if (S_GET_SEGMENT (s) != absolute_section)
1854 	    non_pic_p = 1;
1855 	  break;
1856 
1857 	case BFD_RELOC_VTABLE_INHERIT:
1858 	case BFD_RELOC_VTABLE_ENTRY:
1859 	  non_pic_p = 1;
1860 	  break;
1861 
1862 	  /* If this is a blessed BFD_RELOC_32, convert it back to the normal
1863              relocation.  */
1864 	case BFD_RELOC_CTOR:
1865 	  fixp->fx_r_type = BFD_RELOC_32;
1866 	  break;
1867 	}
1868 
1869       if (non_pic_p)
1870 	{
1871 	  DPRINTF1 (" (Non-pic relocation)\n");
1872 	  if (frv_pic_p)
1873 	    as_warn_where (fixp->fx_file, fixp->fx_line,
1874 			   _("Relocation %s is not safe for %s"),
1875 			   bfd_get_reloc_code_name (reloc), frv_pic_flag);
1876 
1877 	  else if ((frv_flags & EF_FRV_NON_PIC_RELOCS) == 0)
1878 	    {
1879 	      frv_flags |= EF_FRV_NON_PIC_RELOCS;
1880 	      bfd_set_private_flags (abfd, frv_flags);
1881 	    }
1882 	}
1883 #ifdef DEBUG
1884       else
1885 	DPRINTF1 ("\n");
1886 #endif
1887     }
1888 }
1889 
1890 /* After all of the symbols have been adjusted, go over the file looking
1891    for any relocations that pic won't support.  */
1892 
1893 void
1894 frv_frob_file ()
1895 {
1896   bfd_map_over_sections (stdoutput, frv_frob_file_section, (PTR)0);
1897 }
1898 
1899 void
1900 frv_frob_label (this_label)
1901     symbolS *this_label;
1902 {
1903   struct vliw_insn_list *vliw_insn_list_entry;
1904 
1905   if (frv_mach != bfd_mach_frvtomcat)
1906     return;
1907 
1908   if (now_seg != text_section)
1909     return;
1910 
1911   vliw_insn_list_entry = frv_insert_vliw_insn(DONT_COUNT);
1912   vliw_insn_list_entry->type = VLIW_LABEL_TYPE;
1913   vliw_insn_list_entry->sym  = this_label;
1914 }
1915 
1916 fixS *
1917 frv_cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp)
1918      fragS *              frag;
1919      int                  where;
1920      const CGEN_INSN *    insn;
1921      int                  length;
1922      const CGEN_OPERAND * operand;
1923      int                  opinfo;
1924      expressionS *        exp;
1925 {
1926   fixS * fixP = gas_cgen_record_fixup_exp (frag, where, insn, length,
1927                                            operand, opinfo, exp);
1928 
1929   if (frv_mach == bfd_mach_frvtomcat
1930       && current_vliw_insn
1931       && current_vliw_insn->type == VLIW_BRANCH_TYPE
1932       && exp != NULL)
1933     current_vliw_insn->sym = exp->X_add_symbol;
1934 
1935   return fixP;
1936 }
1937