ld/testsuite/
[binutils.git] / gas / config / tc-frv.c
blob77787719bcdbaeaf51ef1145c3e12b86f479635c
1 /* tc-frv.c -- Assembler for the Fujitsu FRV.
2 Copyright 2002, 2003, 2004, 2005, 2006 Free Software Foundation.
4 This file is part of GAS, the GNU Assembler.
6 GAS is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
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.
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. */
21 #include "as.h"
22 #include "subsegs.h"
23 #include "symcat.h"
24 #include "opcodes/frv-desc.h"
25 #include "opcodes/frv-opc.h"
26 #include "cgen.h"
27 #include "libbfd.h"
28 #include "elf/common.h"
29 #include "elf/frv.h"
31 /* Structure to hold all of the different components describing
32 an individual instruction. */
33 typedef struct
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];
51 frv_insn;
53 enum vliw_insn_type
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. */
62 /* We're going to use these in the fr_subtype field to mark
63 whether to keep inserted nops. */
65 #define NOP_KEEP 1 /* Keep these NOPS. */
66 #define NOP_DELETE 2 /* Delete these NOPS. */
68 #define DO_COUNT TRUE
69 #define DONT_COUNT FALSE
71 /* A list of insns within a VLIW insn. */
72 struct vliw_insn_list
74 /* The type of this insn. */
75 enum vliw_insn_type type;
77 /* The corresponding gas insn information. */
78 const CGEN_INSN *insn;
80 /* For branches and labels, the symbol that is referenced. */
81 symbolS *sym;
83 /* For branches, the frag containing the single nop that was generated. */
84 fragS *snop_frag;
86 /* For branches, the frag containing the double nop that was generated. */
87 fragS *dnop_frag;
89 /* Pointer to raw data for this insn. */
90 char *address;
92 /* Next insn in list. */
93 struct vliw_insn_list *next;
96 static struct vliw_insn_list single_nop_insn = {
97 VLIW_NOP_TYPE, NULL, NULL, NULL, NULL, NULL, NULL };
99 static struct vliw_insn_list double_nop_insn = {
100 VLIW_NOP_TYPE, NULL, NULL, NULL, NULL, NULL, NULL };
102 struct vliw_chain
104 int num;
105 int insn_count;
106 struct vliw_insn_list *insn_list;
107 struct vliw_chain *next;
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;
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";
121 static FRV_VLIW vliw;
123 /* Default machine */
125 #ifdef DEFAULT_CPU_FRV
126 #define DEFAULT_MACHINE bfd_mach_frv
127 #define DEFAULT_FLAGS EF_FRV_CPU_GENERIC
129 #else
130 #ifdef DEFAULT_CPU_FR300
131 #define DEFAULT_MACHINE bfd_mach_fr300
132 #define DEFAULT_FLAGS EF_FRV_CPU_FR300
134 #else
135 #ifdef DEFAULT_CPU_SIMPLE
136 #define DEFAULT_MACHINE bfd_mach_frvsimple
137 #define DEFAULT_FLAGS EF_FRV_CPU_SIMPLE
139 #else
140 #ifdef DEFAULT_CPU_TOMCAT
141 #define DEFAULT_MACHINE bfd_mach_frvtomcat
142 #define DEFAULT_FLAGS EF_FRV_CPU_TOMCAT
144 #else
145 #ifdef DEFAULT_CPU_FR400
146 #define DEFAULT_MACHINE bfd_mach_fr400
147 #define DEFAULT_FLAGS EF_FRV_CPU_FR400
149 #else
150 #ifdef DEFAULT_CPU_FR550
151 #define DEFAULT_MACHINE bfd_mach_fr550
152 #define DEFAULT_FLAGS EF_FRV_CPU_FR550
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
164 #ifdef TE_LINUX
165 # define DEFAULT_FDPIC EF_FRV_FDPIC
166 #else
167 # define DEFAULT_FDPIC 0
168 #endif
170 static unsigned long frv_mach = bfd_mach_frv;
171 static bfd_boolean fr400_audio;
173 /* Flags to set in the elf header */
174 static flagword frv_flags = DEFAULT_FLAGS | DEFAULT_FDPIC;
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;
180 /* Print tomcat-specific debugging info. */
181 static int tomcat_debug = 0;
183 /* Tomcat-specific NOP statistics. */
184 static int tomcat_stats = 0;
185 static int tomcat_doubles = 0;
186 static int tomcat_singles = 0;
188 /* Forward reference to static functions */
189 static void frv_set_flags PARAMS ((int));
190 static void frv_pic_ptr PARAMS ((int));
191 static void frv_frob_file_section PARAMS ((bfd *, asection *, PTR));
193 /* The target specific pseudo-ops which we support. */
194 const pseudo_typeS md_pseudo_table[] =
196 { "eflags", frv_set_flags, 0 },
197 { "word", cons, 4 },
198 { "picptr", frv_pic_ptr, 4 },
199 { NULL, NULL, 0 }
203 #define FRV_SHORTOPTS "G:"
204 const char * md_shortopts = FRV_SHORTOPTS;
206 #define OPTION_GPR_32 (OPTION_MD_BASE)
207 #define OPTION_GPR_64 (OPTION_MD_BASE + 1)
208 #define OPTION_FPR_32 (OPTION_MD_BASE + 2)
209 #define OPTION_FPR_64 (OPTION_MD_BASE + 3)
210 #define OPTION_SOFT_FLOAT (OPTION_MD_BASE + 4)
211 #define OPTION_DWORD_YES (OPTION_MD_BASE + 5)
212 #define OPTION_DWORD_NO (OPTION_MD_BASE + 6)
213 #define OPTION_DOUBLE (OPTION_MD_BASE + 7)
214 #define OPTION_NO_DOUBLE (OPTION_MD_BASE + 8)
215 #define OPTION_MEDIA (OPTION_MD_BASE + 9)
216 #define OPTION_NO_MEDIA (OPTION_MD_BASE + 10)
217 #define OPTION_CPU (OPTION_MD_BASE + 11)
218 #define OPTION_PIC (OPTION_MD_BASE + 12)
219 #define OPTION_BIGPIC (OPTION_MD_BASE + 13)
220 #define OPTION_LIBPIC (OPTION_MD_BASE + 14)
221 #define OPTION_MULADD (OPTION_MD_BASE + 15)
222 #define OPTION_NO_MULADD (OPTION_MD_BASE + 16)
223 #define OPTION_TOMCAT_DEBUG (OPTION_MD_BASE + 17)
224 #define OPTION_TOMCAT_STATS (OPTION_MD_BASE + 18)
225 #define OPTION_PACK (OPTION_MD_BASE + 19)
226 #define OPTION_NO_PACK (OPTION_MD_BASE + 20)
227 #define OPTION_FDPIC (OPTION_MD_BASE + 21)
228 #define OPTION_NOPIC (OPTION_MD_BASE + 22)
230 struct option md_longopts[] =
232 { "mgpr-32", no_argument, NULL, OPTION_GPR_32 },
233 { "mgpr-64", no_argument, NULL, OPTION_GPR_64 },
234 { "mfpr-32", no_argument, NULL, OPTION_FPR_32 },
235 { "mfpr-64", no_argument, NULL, OPTION_FPR_64 },
236 { "mhard-float", no_argument, NULL, OPTION_FPR_64 },
237 { "msoft-float", no_argument, NULL, OPTION_SOFT_FLOAT },
238 { "mdword", no_argument, NULL, OPTION_DWORD_YES },
239 { "mno-dword", no_argument, NULL, OPTION_DWORD_NO },
240 { "mdouble", no_argument, NULL, OPTION_DOUBLE },
241 { "mno-double", no_argument, NULL, OPTION_NO_DOUBLE },
242 { "mmedia", no_argument, NULL, OPTION_MEDIA },
243 { "mno-media", no_argument, NULL, OPTION_NO_MEDIA },
244 { "mcpu", required_argument, NULL, OPTION_CPU },
245 { "mpic", no_argument, NULL, OPTION_PIC },
246 { "mPIC", no_argument, NULL, OPTION_BIGPIC },
247 { "mlibrary-pic", no_argument, NULL, OPTION_LIBPIC },
248 { "mmuladd", no_argument, NULL, OPTION_MULADD },
249 { "mno-muladd", no_argument, NULL, OPTION_NO_MULADD },
250 { "mtomcat-debug", no_argument, NULL, OPTION_TOMCAT_DEBUG },
251 { "mtomcat-stats", no_argument, NULL, OPTION_TOMCAT_STATS },
252 { "mpack", no_argument, NULL, OPTION_PACK },
253 { "mno-pack", no_argument, NULL, OPTION_NO_PACK },
254 { "mfdpic", no_argument, NULL, OPTION_FDPIC },
255 { "mnopic", no_argument, NULL, OPTION_NOPIC },
256 { NULL, no_argument, NULL, 0 },
259 size_t md_longopts_size = sizeof (md_longopts);
261 /* What value to give to bfd_set_gp_size. */
262 static int g_switch_value = 8;
265 md_parse_option (c, arg)
266 int c;
267 char * arg;
269 switch (c)
271 default:
272 return 0;
274 case 'G':
275 g_switch_value = atoi (arg);
276 if (! g_switch_value)
277 frv_flags |= EF_FRV_G0;
278 break;
280 case OPTION_GPR_32:
281 frv_flags = (frv_flags & ~EF_FRV_GPR_MASK) | EF_FRV_GPR_32;
282 break;
284 case OPTION_GPR_64:
285 frv_flags = (frv_flags & ~EF_FRV_GPR_MASK) | EF_FRV_GPR_64;
286 break;
288 case OPTION_FPR_32:
289 frv_flags = (frv_flags & ~EF_FRV_FPR_MASK) | EF_FRV_FPR_32;
290 break;
292 case OPTION_FPR_64:
293 frv_flags = (frv_flags & ~EF_FRV_FPR_MASK) | EF_FRV_FPR_64;
294 break;
296 case OPTION_SOFT_FLOAT:
297 frv_flags = (frv_flags & ~EF_FRV_FPR_MASK) | EF_FRV_FPR_NONE;
298 break;
300 case OPTION_DWORD_YES:
301 frv_flags = (frv_flags & ~EF_FRV_DWORD_MASK) | EF_FRV_DWORD_YES;
302 break;
304 case OPTION_DWORD_NO:
305 frv_flags = (frv_flags & ~EF_FRV_DWORD_MASK) | EF_FRV_DWORD_NO;
306 break;
308 case OPTION_DOUBLE:
309 frv_flags |= EF_FRV_DOUBLE;
310 break;
312 case OPTION_NO_DOUBLE:
313 frv_flags &= ~EF_FRV_DOUBLE;
314 break;
316 case OPTION_MEDIA:
317 frv_flags |= EF_FRV_MEDIA;
318 break;
320 case OPTION_NO_MEDIA:
321 frv_flags &= ~EF_FRV_MEDIA;
322 break;
324 case OPTION_MULADD:
325 frv_flags |= EF_FRV_MULADD;
326 break;
328 case OPTION_NO_MULADD:
329 frv_flags &= ~EF_FRV_MULADD;
330 break;
332 case OPTION_PACK:
333 frv_flags &= ~EF_FRV_NOPACK;
334 break;
336 case OPTION_NO_PACK:
337 frv_flags |= EF_FRV_NOPACK;
338 break;
340 case OPTION_CPU:
342 char *p;
343 int cpu_flags = EF_FRV_CPU_GENERIC;
345 /* Identify the processor type */
346 p = arg;
347 if (strcmp (p, "frv") == 0)
349 cpu_flags = EF_FRV_CPU_GENERIC;
350 frv_mach = bfd_mach_frv;
353 else if (strcmp (p, "fr500") == 0)
355 cpu_flags = EF_FRV_CPU_FR500;
356 frv_mach = bfd_mach_fr500;
359 else if (strcmp (p, "fr550") == 0)
361 cpu_flags = EF_FRV_CPU_FR550;
362 frv_mach = bfd_mach_fr550;
365 else if (strcmp (p, "fr450") == 0)
367 cpu_flags = EF_FRV_CPU_FR450;
368 frv_mach = bfd_mach_fr450;
371 else if (strcmp (p, "fr405") == 0)
373 cpu_flags = EF_FRV_CPU_FR405;
374 frv_mach = bfd_mach_fr400;
375 fr400_audio = TRUE;
378 else if (strcmp (p, "fr400") == 0)
380 cpu_flags = EF_FRV_CPU_FR400;
381 frv_mach = bfd_mach_fr400;
382 fr400_audio = FALSE;
385 else if (strcmp (p, "fr300") == 0)
387 cpu_flags = EF_FRV_CPU_FR300;
388 frv_mach = bfd_mach_fr300;
391 else if (strcmp (p, "simple") == 0)
393 cpu_flags = EF_FRV_CPU_SIMPLE;
394 frv_mach = bfd_mach_frvsimple;
395 frv_flags |= EF_FRV_NOPACK;
398 else if (strcmp (p, "tomcat") == 0)
400 cpu_flags = EF_FRV_CPU_TOMCAT;
401 frv_mach = bfd_mach_frvtomcat;
404 else
406 as_fatal ("Unknown cpu -mcpu=%s", arg);
407 return 0;
410 frv_flags = (frv_flags & ~EF_FRV_CPU_MASK) | cpu_flags;
412 break;
414 case OPTION_PIC:
415 frv_flags |= EF_FRV_PIC;
416 frv_pic_p = 1;
417 frv_pic_flag = "-fpic";
418 break;
420 case OPTION_BIGPIC:
421 frv_flags |= EF_FRV_BIGPIC;
422 frv_pic_p = 1;
423 frv_pic_flag = "-fPIC";
424 break;
426 case OPTION_LIBPIC:
427 frv_flags |= (EF_FRV_LIBPIC | EF_FRV_G0);
428 frv_pic_p = 1;
429 frv_pic_flag = "-mlibrary-pic";
430 g_switch_value = 0;
431 break;
433 case OPTION_FDPIC:
434 frv_flags |= EF_FRV_FDPIC;
435 frv_pic_flag = "-mfdpic";
436 break;
438 case OPTION_NOPIC:
439 frv_flags &= ~(EF_FRV_FDPIC | EF_FRV_PIC
440 | EF_FRV_BIGPIC | EF_FRV_LIBPIC);
441 frv_pic_flag = 0;
442 break;
444 case OPTION_TOMCAT_DEBUG:
445 tomcat_debug = 1;
446 break;
448 case OPTION_TOMCAT_STATS:
449 tomcat_stats = 1;
450 break;
453 return 1;
456 void
457 md_show_usage (stream)
458 FILE * stream;
460 fprintf (stream, _("FRV specific command line options:\n"));
461 fprintf (stream, _("-G n Data >= n bytes is in small data area\n"));
462 fprintf (stream, _("-mgpr-32 Note 32 gprs are used\n"));
463 fprintf (stream, _("-mgpr-64 Note 64 gprs are used\n"));
464 fprintf (stream, _("-mfpr-32 Note 32 fprs are used\n"));
465 fprintf (stream, _("-mfpr-64 Note 64 fprs are used\n"));
466 fprintf (stream, _("-msoft-float Note software fp is used\n"));
467 fprintf (stream, _("-mdword Note stack is aligned to a 8 byte boundary\n"));
468 fprintf (stream, _("-mno-dword Note stack is aligned to a 4 byte boundary\n"));
469 fprintf (stream, _("-mdouble Note fp double insns are used\n"));
470 fprintf (stream, _("-mmedia Note media insns are used\n"));
471 fprintf (stream, _("-mmuladd Note multiply add/subtract insns are used\n"));
472 fprintf (stream, _("-mpack Note instructions are packed\n"));
473 fprintf (stream, _("-mno-pack Do not allow instructions to be packed\n"));
474 fprintf (stream, _("-mpic Note small position independent code\n"));
475 fprintf (stream, _("-mPIC Note large position independent code\n"));
476 fprintf (stream, _("-mlibrary-pic Compile library for large position indepedent code\n"));
477 fprintf (stream, _("-mfdpic Assemble for the FDPIC ABI\n"));
478 fprintf (stream, _("-mnopic Disable -mpic, -mPIC, -mlibrary-pic and -mfdpic\n"));
479 fprintf (stream, _("-mcpu={fr500|fr550|fr400|fr405|fr450|fr300|frv|simple|tomcat}\n"));
480 fprintf (stream, _(" Record the cpu type\n"));
481 fprintf (stream, _("-mtomcat-stats Print out stats for tomcat workarounds\n"));
482 fprintf (stream, _("-mtomcat-debug Debug tomcat workarounds\n"));
486 void
487 md_begin ()
489 /* Initialize the `cgen' interface. */
491 /* Set the machine number and endian. */
492 gas_cgen_cpu_desc = frv_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
493 CGEN_CPU_OPEN_ENDIAN,
494 CGEN_ENDIAN_BIG,
495 CGEN_CPU_OPEN_END);
496 frv_cgen_init_asm (gas_cgen_cpu_desc);
498 /* This is a callback from cgen to gas to parse operands. */
499 cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
501 /* Set the ELF flags if desired. */
502 if (frv_flags)
503 bfd_set_private_flags (stdoutput, frv_flags);
505 /* Set the machine type */
506 bfd_default_set_arch_mach (stdoutput, bfd_arch_frv, frv_mach);
508 /* Set up gp size so we can put local common items in .sbss */
509 bfd_set_gp_size (stdoutput, g_switch_value);
511 frv_vliw_reset (& vliw, frv_mach, frv_flags);
514 bfd_boolean
515 frv_md_fdpic_enabled (void)
517 return (frv_flags & EF_FRV_FDPIC) != 0;
520 int chain_num = 0;
522 struct vliw_insn_list *frv_insert_vliw_insn PARAMS ((bfd_boolean));
524 struct vliw_insn_list *
525 frv_insert_vliw_insn (count)
526 bfd_boolean count;
528 struct vliw_insn_list *vliw_insn_list_entry;
529 struct vliw_chain *vliw_chain_entry;
531 if (current_vliw_chain == NULL)
533 vliw_chain_entry = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
534 vliw_chain_entry->insn_count = 0;
535 vliw_chain_entry->insn_list = NULL;
536 vliw_chain_entry->next = NULL;
537 vliw_chain_entry->num = chain_num++;
539 if (!vliw_chain_top)
540 vliw_chain_top = vliw_chain_entry;
541 current_vliw_chain = vliw_chain_entry;
542 if (previous_vliw_chain)
543 previous_vliw_chain->next = vliw_chain_entry;
546 vliw_insn_list_entry = (struct vliw_insn_list *) xmalloc (sizeof (struct vliw_insn_list));
547 vliw_insn_list_entry->type = VLIW_GENERIC_TYPE;
548 vliw_insn_list_entry->insn = NULL;
549 vliw_insn_list_entry->sym = NULL;
550 vliw_insn_list_entry->snop_frag = NULL;
551 vliw_insn_list_entry->dnop_frag = NULL;
552 vliw_insn_list_entry->next = NULL;
554 if (count)
555 current_vliw_chain->insn_count++;
557 if (current_vliw_insn)
558 current_vliw_insn->next = vliw_insn_list_entry;
559 current_vliw_insn = vliw_insn_list_entry;
561 if (!current_vliw_chain->insn_list)
562 current_vliw_chain->insn_list = current_vliw_insn;
564 return vliw_insn_list_entry;
567 /* Identify the following cases:
569 1) A VLIW insn that contains both a branch and the branch destination.
570 This requires the insertion of two vliw instructions before the
571 branch. The first consists of two nops. The second consists of
572 a single nop.
574 2) A single instruction VLIW insn which is the destination of a branch
575 that is in the next VLIW insn. This requires the insertion of a vliw
576 insn containing two nops before the branch.
578 3) A double instruction VLIW insn which contains the destination of a
579 branch that is in the next VLIW insn. This requires the insertion of
580 a VLIW insn containing a single nop before the branch.
582 4) A single instruction VLIW insn which contains branch destination (x),
583 followed by a single instruction VLIW insn which does not contain
584 the branch to (x), followed by a VLIW insn which does contain the branch
585 to (x). This requires the insertion of a VLIW insn containing a single
586 nop before the VLIW instruction containing the branch.
589 #define FRV_IS_NOP(insn) (insn.buffer[0] == FRV_NOP_PACK || insn.buffer[0] == FRV_NOP_NOPACK)
590 #define FRV_NOP_PACK 0x00880000 /* ori.p gr0,0,gr0 */
591 #define FRV_NOP_NOPACK 0x80880000 /* ori gr0,0,gr0 */
593 /* Check a vliw insn for an insn of type containing the sym passed in label_sym. */
595 static struct vliw_insn_list *frv_find_in_vliw
596 PARAMS ((enum vliw_insn_type, struct vliw_chain *, symbolS *));
598 static struct vliw_insn_list *
599 frv_find_in_vliw (vliw_insn_type, this_chain, label_sym)
600 enum vliw_insn_type vliw_insn_type;
601 struct vliw_chain *this_chain;
602 symbolS *label_sym;
605 struct vliw_insn_list *the_insn;
607 if (!this_chain)
608 return NULL;
610 for (the_insn = this_chain->insn_list; the_insn; the_insn = the_insn->next)
612 if (the_insn->type == vliw_insn_type
613 && the_insn->sym == label_sym)
614 return the_insn;
617 return NULL;
620 enum vliw_nop_type
622 /* A Vliw insn containing a single nop insn. */
623 VLIW_SINGLE_NOP,
625 /* A Vliw insn containing two nop insns. */
626 VLIW_DOUBLE_NOP,
628 /* Two vliw insns. The first containing two nop insns.
629 The second contain a single nop insn. */
630 VLIW_DOUBLE_THEN_SINGLE_NOP
633 static void frv_debug_tomcat PARAMS ((struct vliw_chain *));
635 static void
636 frv_debug_tomcat (start_chain)
637 struct vliw_chain *start_chain;
639 struct vliw_chain *this_chain;
640 struct vliw_insn_list *this_insn;
641 int i = 1;
643 for (this_chain = start_chain; this_chain; this_chain = this_chain->next, i++)
645 fprintf (stderr, "\nVliw Insn #%d, #insns: %d\n", i, this_chain->insn_count);
647 for (this_insn = this_chain->insn_list; this_insn; this_insn = this_insn->next)
649 if (this_insn->type == VLIW_LABEL_TYPE)
650 fprintf (stderr, "Label Value: %p\n", this_insn->sym);
651 else if (this_insn->type == VLIW_BRANCH_TYPE)
652 fprintf (stderr, "%s to %p\n", this_insn->insn->base->name, this_insn->sym);
653 else if (this_insn->type == VLIW_BRANCH_HAS_NOPS)
654 fprintf (stderr, "nop'd %s to %p\n", this_insn->insn->base->name, this_insn->sym);
655 else if (this_insn->type == VLIW_NOP_TYPE)
656 fprintf (stderr, "Nop\n");
657 else
658 fprintf (stderr, " %s\n", this_insn->insn->base->name);
663 static void frv_adjust_vliw_count PARAMS ((struct vliw_chain *));
665 static void
666 frv_adjust_vliw_count (this_chain)
667 struct vliw_chain *this_chain;
669 struct vliw_insn_list *this_insn;
671 this_chain->insn_count = 0;
673 for (this_insn = this_chain->insn_list;
674 this_insn;
675 this_insn = this_insn->next)
677 if (this_insn->type != VLIW_LABEL_TYPE)
678 this_chain->insn_count++;
683 /* Insert the desired nop combination in the vliw chain before insert_before_insn.
684 Rechain the vliw insn. */
686 static struct vliw_chain *frv_tomcat_shuffle
687 PARAMS ((enum vliw_nop_type, struct vliw_chain *, struct vliw_insn_list *));
689 static struct vliw_chain *
690 frv_tomcat_shuffle (this_nop_type, vliw_to_split, insert_before_insn)
691 enum vliw_nop_type this_nop_type;
692 struct vliw_chain *vliw_to_split;
693 struct vliw_insn_list *insert_before_insn;
696 bfd_boolean pack_prev = FALSE;
697 struct vliw_chain *return_me = NULL;
698 struct vliw_insn_list *prev_insn = NULL;
699 struct vliw_insn_list *curr_insn = vliw_to_split->insn_list;
701 struct vliw_chain *double_nop = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
702 struct vliw_chain *single_nop = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
703 struct vliw_chain *second_part = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
704 struct vliw_chain *curr_vliw = vliw_chain_top;
705 struct vliw_chain *prev_vliw = NULL;
707 while (curr_insn && curr_insn != insert_before_insn)
709 /* We can't set the packing bit on a label. If we have the case
710 label 1:
711 label 2:
712 label 3:
713 branch that needs nops
714 Then don't set pack bit later. */
716 if (curr_insn->type != VLIW_LABEL_TYPE)
717 pack_prev = TRUE;
718 prev_insn = curr_insn;
719 curr_insn = curr_insn->next;
722 while (curr_vliw && curr_vliw != vliw_to_split)
724 prev_vliw = curr_vliw;
725 curr_vliw = curr_vliw->next;
728 switch (this_nop_type)
730 case VLIW_SINGLE_NOP:
731 if (!prev_insn)
733 /* Branch is first, Insert the NOP prior to this vliw insn. */
734 if (prev_vliw)
735 prev_vliw->next = single_nop;
736 else
737 vliw_chain_top = single_nop;
738 single_nop->next = vliw_to_split;
739 vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
740 return_me = vliw_to_split;
742 else
744 /* Set the packing bit on the previous insn. */
745 if (pack_prev)
747 char *buffer = prev_insn->address;
748 buffer[0] |= 0x80;
750 /* The branch is in the middle. Split this vliw insn into first
751 and second parts. Insert the NOP inbetween. */
753 second_part->insn_list = insert_before_insn;
754 second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
755 second_part->next = vliw_to_split->next;
756 frv_adjust_vliw_count (second_part);
758 single_nop->next = second_part;
760 vliw_to_split->next = single_nop;
761 prev_insn->next = NULL;
763 return_me = second_part;
764 frv_adjust_vliw_count (vliw_to_split);
766 break;
768 case VLIW_DOUBLE_NOP:
769 if (!prev_insn)
771 /* Branch is first, Insert the NOP prior to this vliw insn. */
772 if (prev_vliw)
773 prev_vliw->next = double_nop;
774 else
775 vliw_chain_top = double_nop;
777 double_nop->next = vliw_to_split;
778 return_me = vliw_to_split;
779 vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
781 else
783 /* Set the packing bit on the previous insn. */
784 if (pack_prev)
786 char *buffer = prev_insn->address;
787 buffer[0] |= 0x80;
790 /* The branch is in the middle. Split this vliw insn into first
791 and second parts. Insert the NOP inbetween. */
792 second_part->insn_list = insert_before_insn;
793 second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
794 second_part->next = vliw_to_split->next;
795 frv_adjust_vliw_count (second_part);
797 double_nop->next = second_part;
799 vliw_to_split->next = single_nop;
800 prev_insn->next = NULL;
801 frv_adjust_vliw_count (vliw_to_split);
803 return_me = second_part;
805 break;
807 case VLIW_DOUBLE_THEN_SINGLE_NOP:
808 double_nop->next = single_nop;
809 double_nop->insn_count = 2;
810 double_nop->insn_list = &double_nop_insn;
811 single_nop->insn_count = 1;
812 single_nop->insn_list = &single_nop_insn;
814 if (!prev_insn)
816 /* The branch is the first insn in this vliw. Don't split the vliw. Insert
817 the nops prior to this vliw. */
818 if (prev_vliw)
819 prev_vliw->next = double_nop;
820 else
821 vliw_chain_top = double_nop;
823 single_nop->next = vliw_to_split;
824 return_me = vliw_to_split;
825 vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
827 else
829 /* Set the packing bit on the previous insn. */
830 if (pack_prev)
832 char *buffer = prev_insn->address;
833 buffer[0] |= 0x80;
836 /* The branch is in the middle of this vliw insn. Split into first and
837 second parts. Insert the nop vliws in between. */
838 second_part->insn_list = insert_before_insn;
839 second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
840 second_part->next = vliw_to_split->next;
841 frv_adjust_vliw_count (second_part);
843 single_nop->next = second_part;
845 vliw_to_split->next = double_nop;
846 prev_insn->next = NULL;
847 frv_adjust_vliw_count (vliw_to_split);
849 return_me = second_part;
851 break;
854 return return_me;
857 static void frv_tomcat_analyze_vliw_chains PARAMS ((void));
859 static void
860 frv_tomcat_analyze_vliw_chains ()
862 struct vliw_chain *vliw1 = NULL;
863 struct vliw_chain *vliw2 = NULL;
864 struct vliw_chain *vliw3 = NULL;
866 struct vliw_insn_list *this_insn = NULL;
867 struct vliw_insn_list *temp_insn = NULL;
869 /* We potentially need to look at three VLIW insns to determine if the
870 workaround is required. Set them up. Ignore existing nops during analysis. */
872 #define FRV_SET_VLIW_WINDOW(VLIW1, VLIW2, VLIW3) \
873 if (VLIW1 && VLIW1->next) \
874 VLIW2 = VLIW1->next; \
875 else \
876 VLIW2 = NULL; \
877 if (VLIW2 && VLIW2->next) \
878 VLIW3 = VLIW2->next; \
879 else \
880 VLIW3 = NULL
882 vliw1 = vliw_chain_top;
884 workaround_top:
886 FRV_SET_VLIW_WINDOW (vliw1, vliw2, vliw3);
888 if (!vliw1)
889 return;
891 if (vliw1->insn_count == 1)
893 /* check vliw1 for a label. */
894 if (vliw1->insn_list->type == VLIW_LABEL_TYPE)
896 temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw2, vliw1->insn_list->sym);
897 if (temp_insn)
899 vliw1 = frv_tomcat_shuffle (VLIW_DOUBLE_NOP, vliw2, vliw1->insn_list);
900 temp_insn->dnop_frag->fr_subtype = NOP_KEEP;
901 vliw1 = vliw1->next;
902 if (tomcat_stats)
903 tomcat_doubles++;
904 goto workaround_top;
906 else if (vliw2
907 && vliw2->insn_count == 1
908 && (temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw3, vliw1->insn_list->sym)) != NULL)
910 temp_insn->snop_frag->fr_subtype = NOP_KEEP;
911 vliw1 = frv_tomcat_shuffle (VLIW_SINGLE_NOP, vliw3, vliw3->insn_list);
912 if (tomcat_stats)
913 tomcat_singles++;
914 goto workaround_top;
919 if (vliw1->insn_count == 2)
921 struct vliw_insn_list *this_insn;
923 /* check vliw1 for a label. */
924 for (this_insn = vliw1->insn_list; this_insn; this_insn = this_insn->next)
926 if (this_insn->type == VLIW_LABEL_TYPE)
928 if ((temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw2, this_insn->sym)) != NULL)
930 temp_insn->snop_frag->fr_subtype = NOP_KEEP;
931 vliw1 = frv_tomcat_shuffle (VLIW_SINGLE_NOP, vliw2, this_insn);
932 if (tomcat_stats)
933 tomcat_singles++;
935 else
936 vliw1 = vliw1->next;
937 goto workaround_top;
941 /* Examine each insn in this VLIW. Look for the workaround criteria. */
942 for (this_insn = vliw1->insn_list; this_insn; this_insn = this_insn->next)
944 /* Don't look at labels or nops. */
945 while (this_insn
946 && (this_insn->type == VLIW_LABEL_TYPE
947 || this_insn->type == VLIW_NOP_TYPE
948 || this_insn->type == VLIW_BRANCH_HAS_NOPS))
949 this_insn = this_insn->next;
951 if (!this_insn)
953 vliw1 = vliw2;
954 goto workaround_top;
957 if (frv_is_branch_insn (this_insn->insn))
959 if ((temp_insn = frv_find_in_vliw (VLIW_LABEL_TYPE, vliw1, this_insn->sym)) != NULL)
961 /* Insert [nop/nop] [nop] before branch. */
962 this_insn->snop_frag->fr_subtype = NOP_KEEP;
963 this_insn->dnop_frag->fr_subtype = NOP_KEEP;
964 vliw1 = frv_tomcat_shuffle (VLIW_DOUBLE_THEN_SINGLE_NOP, vliw1, this_insn);
965 goto workaround_top;
971 /* This vliw insn checks out okay. Take a look at the next one. */
972 vliw1 = vliw1->next;
973 goto workaround_top;
976 void
977 frv_tomcat_workaround ()
979 if (frv_mach != bfd_mach_frvtomcat)
980 return;
982 if (tomcat_debug)
983 frv_debug_tomcat (vliw_chain_top);
985 frv_tomcat_analyze_vliw_chains ();
987 if (tomcat_stats)
989 fprintf (stderr, "Inserted %d Single Nops\n", tomcat_singles);
990 fprintf (stderr, "Inserted %d Double Nops\n", tomcat_doubles);
994 static int
995 fr550_check_insn_acc_range (frv_insn *insn, int low, int hi)
997 int acc;
998 switch (CGEN_INSN_NUM (insn->insn))
1000 case FRV_INSN_MADDACCS:
1001 case FRV_INSN_MSUBACCS:
1002 case FRV_INSN_MDADDACCS:
1003 case FRV_INSN_MDSUBACCS:
1004 case FRV_INSN_MASACCS:
1005 case FRV_INSN_MDASACCS:
1006 acc = insn->fields.f_ACC40Si;
1007 if (acc < low || acc > hi)
1008 return 1; /* out of range */
1009 acc = insn->fields.f_ACC40Sk;
1010 if (acc < low || acc > hi)
1011 return 1; /* out of range */
1012 break;
1013 case FRV_INSN_MMULHS:
1014 case FRV_INSN_MMULHU:
1015 case FRV_INSN_MMULXHS:
1016 case FRV_INSN_MMULXHU:
1017 case FRV_INSN_CMMULHS:
1018 case FRV_INSN_CMMULHU:
1019 case FRV_INSN_MQMULHS:
1020 case FRV_INSN_MQMULHU:
1021 case FRV_INSN_MQMULXHS:
1022 case FRV_INSN_MQMULXHU:
1023 case FRV_INSN_CMQMULHS:
1024 case FRV_INSN_CMQMULHU:
1025 case FRV_INSN_MMACHS:
1026 case FRV_INSN_MMRDHS:
1027 case FRV_INSN_CMMACHS:
1028 case FRV_INSN_MQMACHS:
1029 case FRV_INSN_CMQMACHS:
1030 case FRV_INSN_MQXMACHS:
1031 case FRV_INSN_MQXMACXHS:
1032 case FRV_INSN_MQMACXHS:
1033 case FRV_INSN_MCPXRS:
1034 case FRV_INSN_MCPXIS:
1035 case FRV_INSN_CMCPXRS:
1036 case FRV_INSN_CMCPXIS:
1037 case FRV_INSN_MQCPXRS:
1038 case FRV_INSN_MQCPXIS:
1039 acc = insn->fields.f_ACC40Sk;
1040 if (acc < low || acc > hi)
1041 return 1; /* out of range */
1042 break;
1043 case FRV_INSN_MMACHU:
1044 case FRV_INSN_MMRDHU:
1045 case FRV_INSN_CMMACHU:
1046 case FRV_INSN_MQMACHU:
1047 case FRV_INSN_CMQMACHU:
1048 case FRV_INSN_MCPXRU:
1049 case FRV_INSN_MCPXIU:
1050 case FRV_INSN_CMCPXRU:
1051 case FRV_INSN_CMCPXIU:
1052 case FRV_INSN_MQCPXRU:
1053 case FRV_INSN_MQCPXIU:
1054 acc = insn->fields.f_ACC40Uk;
1055 if (acc < low || acc > hi)
1056 return 1; /* out of range */
1057 break;
1058 default:
1059 break;
1061 return 0; /* all is ok */
1064 static int
1065 fr550_check_acc_range (FRV_VLIW *vliw, frv_insn *insn)
1067 switch ((*vliw->current_vliw)[vliw->next_slot - 1])
1069 case UNIT_FM0:
1070 case UNIT_FM2:
1071 return fr550_check_insn_acc_range (insn, 0, 3);
1072 case UNIT_FM1:
1073 case UNIT_FM3:
1074 return fr550_check_insn_acc_range (insn, 4, 7);
1075 default:
1076 break;
1078 return 0; /* all is ok */
1081 /* Return true if the target implements instruction INSN. */
1083 static bfd_boolean
1084 target_implements_insn_p (const CGEN_INSN *insn)
1086 switch (frv_mach)
1088 default:
1089 /* bfd_mach_frv or generic. */
1090 return TRUE;
1092 case bfd_mach_fr300:
1093 case bfd_mach_frvsimple:
1094 return CGEN_INSN_MACH_HAS_P (insn, MACH_SIMPLE);
1096 case bfd_mach_fr400:
1097 return ((fr400_audio || !CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_AUDIO))
1098 && CGEN_INSN_MACH_HAS_P (insn, MACH_FR400));
1100 case bfd_mach_fr450:
1101 return CGEN_INSN_MACH_HAS_P (insn, MACH_FR450);
1103 case bfd_mach_fr500:
1104 return CGEN_INSN_MACH_HAS_P (insn, MACH_FR500);
1106 case bfd_mach_fr550:
1107 return CGEN_INSN_MACH_HAS_P (insn, MACH_FR550);
1111 void
1112 md_assemble (str)
1113 char * str;
1115 frv_insn insn;
1116 char *errmsg;
1117 int packing_constraint;
1118 finished_insnS finished_insn;
1119 fragS *double_nop_frag = NULL;
1120 fragS *single_nop_frag = NULL;
1121 struct vliw_insn_list *vliw_insn_list_entry = NULL;
1123 /* Initialize GAS's cgen interface for a new instruction. */
1124 gas_cgen_init_parse ();
1126 memset (&insn, 0, sizeof (insn));
1128 insn.insn = frv_cgen_assemble_insn
1129 (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, &errmsg);
1131 if (!insn.insn)
1133 as_bad (errmsg);
1134 return;
1137 /* If the cpu is tomcat, then we need to insert nops to workaround
1138 hardware limitations. We need to keep track of each vliw unit
1139 and examine the length of the unit and the individual insns
1140 within the unit to determine the number and location of the
1141 required nops. */
1142 if (frv_mach == bfd_mach_frvtomcat)
1144 /* If we've just finished a VLIW insn OR this is a branch,
1145 then start up a new frag. Fill it with nops. We will get rid
1146 of those that are not required after we've seen all of the
1147 instructions but before we start resolving fixups. */
1148 if ( !FRV_IS_NOP (insn)
1149 && (frv_is_branch_insn (insn.insn) || insn.fields.f_pack))
1151 char *buffer;
1153 frag_wane (frag_now);
1154 frag_new (0);
1155 double_nop_frag = frag_now;
1156 buffer = frag_var (rs_machine_dependent, 8, 8, NOP_DELETE, NULL, 0, 0);
1157 md_number_to_chars (buffer, FRV_NOP_PACK, 4);
1158 md_number_to_chars (buffer+4, FRV_NOP_NOPACK, 4);
1160 frag_wane (frag_now);
1161 frag_new (0);
1162 single_nop_frag = frag_now;
1163 buffer = frag_var (rs_machine_dependent, 4, 4, NOP_DELETE, NULL, 0, 0);
1164 md_number_to_chars (buffer, FRV_NOP_NOPACK, 4);
1167 vliw_insn_list_entry = frv_insert_vliw_insn (DO_COUNT);
1168 vliw_insn_list_entry->insn = insn.insn;
1169 if (frv_is_branch_insn (insn.insn))
1170 vliw_insn_list_entry->type = VLIW_BRANCH_TYPE;
1172 if ( !FRV_IS_NOP (insn)
1173 && (frv_is_branch_insn (insn.insn) || insn.fields.f_pack))
1175 vliw_insn_list_entry->snop_frag = single_nop_frag;
1176 vliw_insn_list_entry->dnop_frag = double_nop_frag;
1180 /* Make sure that this insn does not violate the VLIW packing constraints. */
1181 /* -mno-pack disallows any packing whatsoever. */
1182 if (frv_flags & EF_FRV_NOPACK)
1184 if (! insn.fields.f_pack)
1186 as_bad (_("VLIW packing used for -mno-pack"));
1187 return;
1190 /* -mcpu=FRV is an idealized FR-V implementation that supports all of the
1191 instructions, don't do vliw checking. */
1192 else if (frv_mach != bfd_mach_frv)
1194 if (!target_implements_insn_p (insn.insn))
1196 as_bad (_("Instruction not supported by this architecture"));
1197 return;
1199 packing_constraint = frv_vliw_add_insn (& vliw, insn.insn);
1200 if (frv_mach == bfd_mach_fr550 && ! packing_constraint)
1201 packing_constraint = fr550_check_acc_range (& vliw, & insn);
1202 if (insn.fields.f_pack)
1203 frv_vliw_reset (& vliw, frv_mach, frv_flags);
1204 if (packing_constraint)
1206 as_bad (_("VLIW packing constraint violation"));
1207 return;
1211 /* Doesn't really matter what we pass for RELAX_P here. */
1212 gas_cgen_finish_insn (insn.insn, insn.buffer,
1213 CGEN_FIELDS_BITSIZE (& insn.fields), 1, &finished_insn);
1216 /* If the cpu is tomcat, then we need to insert nops to workaround
1217 hardware limitations. We need to keep track of each vliw unit
1218 and examine the length of the unit and the individual insns
1219 within the unit to determine the number and location of the
1220 required nops. */
1221 if (frv_mach == bfd_mach_frvtomcat)
1223 if (vliw_insn_list_entry)
1224 vliw_insn_list_entry->address = finished_insn.addr;
1225 else
1226 abort();
1228 if (insn.fields.f_pack)
1230 /* We've completed a VLIW insn. */
1231 previous_vliw_chain = current_vliw_chain;
1232 current_vliw_chain = NULL;
1233 current_vliw_insn = NULL;
1238 /* The syntax in the manual says constants begin with '#'.
1239 We just ignore it. */
1241 void
1242 md_operand (expressionP)
1243 expressionS * expressionP;
1245 if (* input_line_pointer == '#')
1247 input_line_pointer ++;
1248 expression (expressionP);
1252 valueT
1253 md_section_align (segment, size)
1254 segT segment;
1255 valueT size;
1257 int align = bfd_get_section_alignment (stdoutput, segment);
1258 return ((size + (1 << align) - 1) & (-1 << align));
1261 symbolS *
1262 md_undefined_symbol (name)
1263 char * name ATTRIBUTE_UNUSED;
1265 return 0;
1268 /* Interface to relax_segment. */
1270 /* FIXME: Build table by hand, get it working, then machine generate. */
1271 const relax_typeS md_relax_table[] =
1273 {1, 1, 0, 0},
1274 {511 - 2 - 2, -512 - 2 + 2, 0, 2 },
1275 {0x2000000 - 1 - 2, -0x2000000 - 2, 2, 0 },
1276 {0x2000000 - 1 - 2, -0x2000000 - 2, 4, 0 }
1279 long
1280 frv_relax_frag (fragP, stretch)
1281 fragS *fragP ATTRIBUTE_UNUSED;
1282 long stretch ATTRIBUTE_UNUSED;
1284 return 0;
1287 /* Return an initial guess of the length by which a fragment must grow to
1288 hold a branch to reach its destination.
1289 Also updates fr_type/fr_subtype as necessary.
1291 Called just before doing relaxation.
1292 Any symbol that is now undefined will not become defined.
1293 The guess for fr_var is ACTUALLY the growth beyond fr_fix.
1294 Whatever we do to grow fr_fix or fr_var contributes to our returned value.
1295 Although it may not be explicit in the frag, pretend fr_var starts with a
1296 0 value. */
1299 md_estimate_size_before_relax (fragP, segment)
1300 fragS * fragP;
1301 segT segment ATTRIBUTE_UNUSED;
1303 switch (fragP->fr_subtype)
1305 case NOP_KEEP:
1306 return fragP->fr_var;
1308 default:
1309 case NOP_DELETE:
1310 return 0;
1314 /* *fragP has been relaxed to its final size, and now needs to have
1315 the bytes inside it modified to conform to the new size.
1317 Called after relaxation is finished.
1318 fragP->fr_type == rs_machine_dependent.
1319 fragP->fr_subtype is the subtype of what the address relaxed to. */
1321 void
1322 md_convert_frag (abfd, sec, fragP)
1323 bfd * abfd ATTRIBUTE_UNUSED;
1324 segT sec ATTRIBUTE_UNUSED;
1325 fragS * fragP;
1327 switch (fragP->fr_subtype)
1329 default:
1330 case NOP_DELETE:
1331 return;
1333 case NOP_KEEP:
1334 fragP->fr_fix = fragP->fr_var;
1335 fragP->fr_var = 0;
1336 return;
1340 /* Functions concerning relocs. */
1342 /* The location from which a PC relative jump should be calculated,
1343 given a PC relative reloc. */
1345 long
1346 md_pcrel_from_section (fixP, sec)
1347 fixS * fixP;
1348 segT sec;
1350 if (TC_FORCE_RELOCATION (fixP)
1351 || (fixP->fx_addsy != (symbolS *) NULL
1352 && S_GET_SEGMENT (fixP->fx_addsy) != sec))
1354 /* If we can't adjust this relocation, or if it references a
1355 local symbol in a different section (which
1356 TC_FORCE_RELOCATION can't check), let the linker figure it
1357 out. */
1358 return 0;
1361 return (fixP->fx_frag->fr_address + fixP->fx_where) & ~1;
1364 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
1365 Returns BFD_RELOC_NONE if no reloc type can be found.
1366 *FIXP may be modified if desired. */
1368 bfd_reloc_code_real_type
1369 md_cgen_lookup_reloc (insn, operand, fixP)
1370 const CGEN_INSN * insn ATTRIBUTE_UNUSED;
1371 const CGEN_OPERAND * operand;
1372 fixS * fixP;
1374 switch (operand->type)
1376 case FRV_OPERAND_LABEL16:
1377 fixP->fx_pcrel = TRUE;
1378 return BFD_RELOC_FRV_LABEL16;
1380 case FRV_OPERAND_LABEL24:
1381 fixP->fx_pcrel = TRUE;
1383 if (fixP->fx_cgen.opinfo != 0)
1384 return fixP->fx_cgen.opinfo;
1386 return BFD_RELOC_FRV_LABEL24;
1388 case FRV_OPERAND_UHI16:
1389 case FRV_OPERAND_ULO16:
1390 case FRV_OPERAND_SLO16:
1391 case FRV_OPERAND_CALLANN:
1392 case FRV_OPERAND_LDANN:
1393 case FRV_OPERAND_LDDANN:
1394 /* The relocation type should be recorded in opinfo */
1395 if (fixP->fx_cgen.opinfo != 0)
1396 return fixP->fx_cgen.opinfo;
1397 break;
1399 case FRV_OPERAND_D12:
1400 case FRV_OPERAND_S12:
1401 if (fixP->fx_cgen.opinfo != 0)
1402 return fixP->fx_cgen.opinfo;
1404 return BFD_RELOC_FRV_GPREL12;
1406 case FRV_OPERAND_U12:
1407 return BFD_RELOC_FRV_GPRELU12;
1409 default:
1410 break;
1412 return BFD_RELOC_NONE;
1416 /* See whether we need to force a relocation into the output file.
1417 This is used to force out switch and PC relative relocations when
1418 relaxing. */
1421 frv_force_relocation (fix)
1422 fixS * fix;
1424 switch (fix->fx_r_type < BFD_RELOC_UNUSED
1425 ? (int) fix->fx_r_type
1426 : fix->fx_cgen.opinfo)
1428 case BFD_RELOC_FRV_GPREL12:
1429 case BFD_RELOC_FRV_GPRELU12:
1430 case BFD_RELOC_FRV_GPREL32:
1431 case BFD_RELOC_FRV_GPRELHI:
1432 case BFD_RELOC_FRV_GPRELLO:
1433 case BFD_RELOC_FRV_GOT12:
1434 case BFD_RELOC_FRV_GOTHI:
1435 case BFD_RELOC_FRV_GOTLO:
1436 case BFD_RELOC_FRV_FUNCDESC_VALUE:
1437 case BFD_RELOC_FRV_FUNCDESC_GOTOFF12:
1438 case BFD_RELOC_FRV_FUNCDESC_GOTOFFHI:
1439 case BFD_RELOC_FRV_FUNCDESC_GOTOFFLO:
1440 case BFD_RELOC_FRV_GOTOFF12:
1441 case BFD_RELOC_FRV_GOTOFFHI:
1442 case BFD_RELOC_FRV_GOTOFFLO:
1443 case BFD_RELOC_FRV_GETTLSOFF:
1444 case BFD_RELOC_FRV_TLSDESC_VALUE:
1445 case BFD_RELOC_FRV_GOTTLSDESC12:
1446 case BFD_RELOC_FRV_GOTTLSDESCHI:
1447 case BFD_RELOC_FRV_GOTTLSDESCLO:
1448 case BFD_RELOC_FRV_TLSMOFF12:
1449 case BFD_RELOC_FRV_TLSMOFFHI:
1450 case BFD_RELOC_FRV_TLSMOFFLO:
1451 case BFD_RELOC_FRV_GOTTLSOFF12:
1452 case BFD_RELOC_FRV_GOTTLSOFFHI:
1453 case BFD_RELOC_FRV_GOTTLSOFFLO:
1454 case BFD_RELOC_FRV_TLSOFF:
1455 case BFD_RELOC_FRV_TLSDESC_RELAX:
1456 case BFD_RELOC_FRV_GETTLSOFF_RELAX:
1457 case BFD_RELOC_FRV_TLSOFF_RELAX:
1458 return 1;
1460 default:
1461 break;
1464 return generic_force_reloc (fix);
1467 /* Apply a fixup that could be resolved within the assembler. */
1469 void
1470 md_apply_fix (fixP, valP, seg)
1471 fixS * fixP;
1472 valueT * valP;
1473 segT seg;
1475 if (fixP->fx_addsy == 0)
1476 switch (fixP->fx_cgen.opinfo)
1478 case BFD_RELOC_FRV_HI16:
1479 *valP >>= 16;
1480 /* Fall through. */
1481 case BFD_RELOC_FRV_LO16:
1482 *valP &= 0xffff;
1483 break;
1485 /* We need relocations for these, even if their symbols reduce
1486 to constants. */
1487 case BFD_RELOC_FRV_GPREL12:
1488 case BFD_RELOC_FRV_GPRELU12:
1489 case BFD_RELOC_FRV_GPREL32:
1490 case BFD_RELOC_FRV_GPRELHI:
1491 case BFD_RELOC_FRV_GPRELLO:
1492 case BFD_RELOC_FRV_GOT12:
1493 case BFD_RELOC_FRV_GOTHI:
1494 case BFD_RELOC_FRV_GOTLO:
1495 case BFD_RELOC_FRV_FUNCDESC_VALUE:
1496 case BFD_RELOC_FRV_FUNCDESC_GOTOFF12:
1497 case BFD_RELOC_FRV_FUNCDESC_GOTOFFHI:
1498 case BFD_RELOC_FRV_FUNCDESC_GOTOFFLO:
1499 case BFD_RELOC_FRV_GOTOFF12:
1500 case BFD_RELOC_FRV_GOTOFFHI:
1501 case BFD_RELOC_FRV_GOTOFFLO:
1502 case BFD_RELOC_FRV_GETTLSOFF:
1503 case BFD_RELOC_FRV_TLSDESC_VALUE:
1504 case BFD_RELOC_FRV_GOTTLSDESC12:
1505 case BFD_RELOC_FRV_GOTTLSDESCHI:
1506 case BFD_RELOC_FRV_GOTTLSDESCLO:
1507 case BFD_RELOC_FRV_TLSMOFF12:
1508 case BFD_RELOC_FRV_TLSMOFFHI:
1509 case BFD_RELOC_FRV_TLSMOFFLO:
1510 case BFD_RELOC_FRV_GOTTLSOFF12:
1511 case BFD_RELOC_FRV_GOTTLSOFFHI:
1512 case BFD_RELOC_FRV_GOTTLSOFFLO:
1513 case BFD_RELOC_FRV_TLSOFF:
1514 case BFD_RELOC_FRV_TLSDESC_RELAX:
1515 case BFD_RELOC_FRV_GETTLSOFF_RELAX:
1516 case BFD_RELOC_FRV_TLSOFF_RELAX:
1517 fixP->fx_addsy = expr_build_uconstant (0);
1518 break;
1520 else
1521 switch (fixP->fx_cgen.opinfo)
1523 case BFD_RELOC_FRV_GETTLSOFF:
1524 case BFD_RELOC_FRV_TLSDESC_VALUE:
1525 case BFD_RELOC_FRV_GOTTLSDESC12:
1526 case BFD_RELOC_FRV_GOTTLSDESCHI:
1527 case BFD_RELOC_FRV_GOTTLSDESCLO:
1528 case BFD_RELOC_FRV_TLSMOFF12:
1529 case BFD_RELOC_FRV_TLSMOFFHI:
1530 case BFD_RELOC_FRV_TLSMOFFLO:
1531 case BFD_RELOC_FRV_GOTTLSOFF12:
1532 case BFD_RELOC_FRV_GOTTLSOFFHI:
1533 case BFD_RELOC_FRV_GOTTLSOFFLO:
1534 case BFD_RELOC_FRV_TLSOFF:
1535 case BFD_RELOC_FRV_TLSDESC_RELAX:
1536 case BFD_RELOC_FRV_GETTLSOFF_RELAX:
1537 case BFD_RELOC_FRV_TLSOFF_RELAX:
1538 /* Mark TLS symbols as such. */
1539 if (S_GET_SEGMENT (fixP->fx_addsy) != absolute_section)
1540 S_SET_THREAD_LOCAL (fixP->fx_addsy);
1541 break;
1544 gas_cgen_md_apply_fix (fixP, valP, seg);
1545 return;
1549 /* Write a value out to the object file, using the appropriate endianness. */
1551 void
1552 frv_md_number_to_chars (buf, val, n)
1553 char * buf;
1554 valueT val;
1555 int n;
1557 number_to_chars_bigendian (buf, val, n);
1560 /* Turn a string in input_line_pointer into a floating point constant of type
1561 type, and store the appropriate bytes in *litP. The number of LITTLENUMS
1562 emitted is stored in *sizeP . An error message is returned, or NULL on OK.
1565 /* Equal to MAX_PRECISION in atof-ieee.c */
1566 #define MAX_LITTLENUMS 6
1568 char *
1569 md_atof (type, litP, sizeP)
1570 char type;
1571 char * litP;
1572 int * sizeP;
1574 int i;
1575 int prec;
1576 LITTLENUM_TYPE words [MAX_LITTLENUMS];
1577 char * t;
1579 switch (type)
1581 case 'f':
1582 case 'F':
1583 case 's':
1584 case 'S':
1585 prec = 2;
1586 break;
1588 case 'd':
1589 case 'D':
1590 case 'r':
1591 case 'R':
1592 prec = 4;
1593 break;
1595 /* FIXME: Some targets allow other format chars for bigger sizes here. */
1597 default:
1598 * sizeP = 0;
1599 return _("Bad call to md_atof()");
1602 t = atof_ieee (input_line_pointer, type, words);
1603 if (t)
1604 input_line_pointer = t;
1605 * sizeP = prec * sizeof (LITTLENUM_TYPE);
1607 for (i = 0; i < prec; i++)
1609 md_number_to_chars (litP, (valueT) words[i],
1610 sizeof (LITTLENUM_TYPE));
1611 litP += sizeof (LITTLENUM_TYPE);
1614 return 0;
1617 bfd_boolean
1618 frv_fix_adjustable (fixP)
1619 fixS * fixP;
1621 bfd_reloc_code_real_type reloc_type;
1623 if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
1625 const CGEN_INSN *insn = NULL;
1626 int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
1627 const CGEN_OPERAND *operand = cgen_operand_lookup_by_num(gas_cgen_cpu_desc, opindex);
1628 reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
1630 else
1631 reloc_type = fixP->fx_r_type;
1633 /* We need the symbol name for the VTABLE entries */
1634 if ( reloc_type == BFD_RELOC_VTABLE_INHERIT
1635 || reloc_type == BFD_RELOC_VTABLE_ENTRY
1636 || reloc_type == BFD_RELOC_FRV_GPREL12
1637 || reloc_type == BFD_RELOC_FRV_GPRELU12)
1638 return 0;
1640 return 1;
1643 /* Allow user to set flags bits. */
1644 void
1645 frv_set_flags (arg)
1646 int arg ATTRIBUTE_UNUSED;
1648 flagword new_flags = get_absolute_expression ();
1649 flagword new_mask = ~ (flagword)0;
1651 frv_user_set_flags_p = 1;
1652 if (*input_line_pointer == ',')
1654 ++input_line_pointer;
1655 new_mask = get_absolute_expression ();
1658 frv_flags = (frv_flags & ~new_mask) | (new_flags & new_mask);
1659 bfd_set_private_flags (stdoutput, frv_flags);
1662 /* Frv specific function to handle 4 byte initializations for pointers that are
1663 considered 'safe' for use with pic support. Until frv_frob_file{,_section}
1664 is run, we encode it a BFD_RELOC_CTOR, and it is turned back into a normal
1665 BFD_RELOC_32 at that time. */
1667 void
1668 frv_pic_ptr (nbytes)
1669 int nbytes;
1671 expressionS exp;
1672 char *p;
1674 if (nbytes != 4)
1675 abort ();
1677 #ifdef md_flush_pending_output
1678 md_flush_pending_output ();
1679 #endif
1681 if (is_it_end_of_statement ())
1683 demand_empty_rest_of_line ();
1684 return;
1687 #ifdef md_cons_align
1688 md_cons_align (nbytes);
1689 #endif
1693 bfd_reloc_code_real_type reloc_type = BFD_RELOC_CTOR;
1695 if (strncasecmp (input_line_pointer, "funcdesc(", 9) == 0)
1697 input_line_pointer += 9;
1698 expression (&exp);
1699 if (*input_line_pointer == ')')
1700 input_line_pointer++;
1701 else
1702 as_bad ("missing ')'");
1703 reloc_type = BFD_RELOC_FRV_FUNCDESC;
1705 else if (strncasecmp (input_line_pointer, "tlsmoff(", 8) == 0)
1707 input_line_pointer += 8;
1708 expression (&exp);
1709 if (*input_line_pointer == ')')
1710 input_line_pointer++;
1711 else
1712 as_bad ("missing ')'");
1713 reloc_type = BFD_RELOC_FRV_TLSMOFF;
1715 else
1716 expression (&exp);
1718 p = frag_more (4);
1719 memset (p, 0, 4);
1720 fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &exp, 0,
1721 reloc_type);
1723 while (*input_line_pointer++ == ',');
1725 input_line_pointer--; /* Put terminator back into stream. */
1726 demand_empty_rest_of_line ();
1731 #ifdef DEBUG
1732 #define DPRINTF1(A) fprintf (stderr, A)
1733 #define DPRINTF2(A,B) fprintf (stderr, A, B)
1734 #define DPRINTF3(A,B,C) fprintf (stderr, A, B, C)
1736 #else
1737 #define DPRINTF1(A)
1738 #define DPRINTF2(A,B)
1739 #define DPRINTF3(A,B,C)
1740 #endif
1742 /* Go through a the sections looking for relocations that are problematical for
1743 pic. If not pic, just note that this object can't be linked with pic. If
1744 it is pic, see if it needs to be marked so that it will be fixed up, or if
1745 not possible, issue an error. */
1747 static void
1748 frv_frob_file_section (abfd, sec, ptr)
1749 bfd *abfd;
1750 asection *sec;
1751 PTR ptr ATTRIBUTE_UNUSED;
1753 segment_info_type *seginfo = seg_info (sec);
1754 fixS *fixp;
1755 CGEN_CPU_DESC cd = gas_cgen_cpu_desc;
1756 flagword flags = bfd_get_section_flags (abfd, sec);
1758 /* Skip relocations in known sections (.ctors, .dtors, and .gcc_except_table)
1759 since we can fix those up by hand. */
1760 int known_section_p = (sec->name
1761 && sec->name[0] == '.'
1762 && ((sec->name[1] == 'c'
1763 && strcmp (sec->name, ".ctor") == 0)
1764 || (sec->name[1] == 'd'
1765 && strcmp (sec->name, ".dtor") == 0)
1766 || (sec->name[1] == 'g'
1767 && strcmp (sec->name, ".gcc_except_table") == 0)));
1769 DPRINTF3 ("\nFrv section %s%s\n", sec->name, (known_section_p) ? ", known section" : "");
1770 if ((flags & SEC_ALLOC) == 0)
1772 DPRINTF1 ("\tSkipping non-loaded section\n");
1773 return;
1776 for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next)
1778 symbolS *s = fixp->fx_addsy;
1779 bfd_reloc_code_real_type reloc;
1780 int non_pic_p;
1781 int opindex;
1782 const CGEN_OPERAND *operand;
1783 const CGEN_INSN *insn = fixp->fx_cgen.insn;
1785 if (fixp->fx_done)
1787 DPRINTF1 ("\tSkipping reloc that has already been done\n");
1788 continue;
1791 if (fixp->fx_pcrel)
1793 DPRINTF1 ("\tSkipping reloc that is PC relative\n");
1794 continue;
1797 if (! s)
1799 DPRINTF1 ("\tSkipping reloc without symbol\n");
1800 continue;
1803 if (fixp->fx_r_type < BFD_RELOC_UNUSED)
1805 opindex = -1;
1806 reloc = fixp->fx_r_type;
1808 else
1810 opindex = (int) fixp->fx_r_type - (int) BFD_RELOC_UNUSED;
1811 operand = cgen_operand_lookup_by_num (cd, opindex);
1812 reloc = md_cgen_lookup_reloc (insn, operand, fixp);
1815 DPRINTF3 ("\treloc %s\t%s", bfd_get_reloc_code_name (reloc), S_GET_NAME (s));
1817 non_pic_p = 0;
1818 switch (reloc)
1820 default:
1821 break;
1823 case BFD_RELOC_32:
1824 /* Skip relocations in known sections (.ctors, .dtors, and
1825 .gcc_except_table) since we can fix those up by hand. Also
1826 skip forward references to constants. Also skip a difference
1827 of two symbols, which still uses the BFD_RELOC_32 at this
1828 point. */
1829 if (! known_section_p
1830 && S_GET_SEGMENT (s) != absolute_section
1831 && !fixp->fx_subsy
1832 && (flags & (SEC_READONLY | SEC_CODE)) == 0)
1834 non_pic_p = 1;
1836 break;
1838 /* FIXME -- should determine if any of the GP relocation really uses
1839 gr16 (which is not pic safe) or not. Right now, assume if we
1840 aren't being compiled with -mpic, the usage is non pic safe, but
1841 is safe with -mpic. */
1842 case BFD_RELOC_FRV_GPREL12:
1843 case BFD_RELOC_FRV_GPRELU12:
1844 case BFD_RELOC_FRV_GPREL32:
1845 case BFD_RELOC_FRV_GPRELHI:
1846 case BFD_RELOC_FRV_GPRELLO:
1847 non_pic_p = ! frv_pic_p;
1848 break;
1850 case BFD_RELOC_FRV_LO16:
1851 case BFD_RELOC_FRV_HI16:
1852 if (S_GET_SEGMENT (s) != absolute_section)
1853 non_pic_p = 1;
1854 break;
1856 case BFD_RELOC_VTABLE_INHERIT:
1857 case BFD_RELOC_VTABLE_ENTRY:
1858 non_pic_p = 1;
1859 break;
1861 /* If this is a blessed BFD_RELOC_32, convert it back to the normal
1862 relocation. */
1863 case BFD_RELOC_CTOR:
1864 fixp->fx_r_type = BFD_RELOC_32;
1865 break;
1868 if (non_pic_p)
1870 DPRINTF1 (" (Non-pic relocation)\n");
1871 if (frv_pic_p)
1872 as_warn_where (fixp->fx_file, fixp->fx_line,
1873 _("Relocation %s is not safe for %s"),
1874 bfd_get_reloc_code_name (reloc), frv_pic_flag);
1876 else if ((frv_flags & EF_FRV_NON_PIC_RELOCS) == 0)
1878 frv_flags |= EF_FRV_NON_PIC_RELOCS;
1879 bfd_set_private_flags (abfd, frv_flags);
1882 #ifdef DEBUG
1883 else
1884 DPRINTF1 ("\n");
1885 #endif
1889 /* After all of the symbols have been adjusted, go over the file looking
1890 for any relocations that pic won't support. */
1892 void
1893 frv_frob_file ()
1895 bfd_map_over_sections (stdoutput, frv_frob_file_section, (PTR)0);
1898 void
1899 frv_frob_label (this_label)
1900 symbolS *this_label;
1902 struct vliw_insn_list *vliw_insn_list_entry;
1904 if (frv_mach != bfd_mach_frvtomcat)
1905 return;
1907 if (now_seg != text_section)
1908 return;
1910 vliw_insn_list_entry = frv_insert_vliw_insn(DONT_COUNT);
1911 vliw_insn_list_entry->type = VLIW_LABEL_TYPE;
1912 vliw_insn_list_entry->sym = this_label;
1915 fixS *
1916 frv_cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp)
1917 fragS * frag;
1918 int where;
1919 const CGEN_INSN * insn;
1920 int length;
1921 const CGEN_OPERAND * operand;
1922 int opinfo;
1923 expressionS * exp;
1925 fixS * fixP = gas_cgen_record_fixup_exp (frag, where, insn, length,
1926 operand, opinfo, exp);
1928 if (frv_mach == bfd_mach_frvtomcat
1929 && current_vliw_insn
1930 && current_vliw_insn->type == VLIW_BRANCH_TYPE
1931 && exp != NULL)
1932 current_vliw_insn->sym = exp->X_add_symbol;
1934 return fixP;