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