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