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