daily update
[binutils.git] / gas / config / tc-frv.c
blob85503cd9008e86b5dbdc0fb28d72538542ce0bc1
1 /* tc-frv.c -- Assembler for the Fujitsu FRV.
2 Copyright 2002, 2003 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, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 #include <stdio.h>
22 #include "as.h"
23 #include "subsegs.h"
24 #include "symcat.h"
25 #include "opcodes/frv-desc.h"
26 #include "opcodes/frv-opc.h"
27 #include "cgen.h"
28 #include "libbfd.h"
29 #include "elf/common.h"
30 #include "elf/frv.h"
32 /* Structure to hold all of the different components describing
33 an individual instruction. */
34 typedef struct
36 const CGEN_INSN * insn;
37 const CGEN_INSN * orig_insn;
38 CGEN_FIELDS fields;
39 #if CGEN_INT_INSN_P
40 CGEN_INSN_INT buffer [1];
41 #define INSN_VALUE(buf) (*(buf))
42 #else
43 unsigned char buffer [CGEN_MAX_INSN_SIZE];
44 #define INSN_VALUE(buf) (buf)
45 #endif
46 char * addr;
47 fragS * frag;
48 int num_fixups;
49 fixS * fixups [GAS_CGEN_MAX_FIXUPS];
50 int indices [MAX_OPERAND_INSTANCES];
52 frv_insn;
54 enum vliw_insn_type
56 VLIW_GENERIC_TYPE, /* Don't care about this insn. */
57 VLIW_BRANCH_TYPE, /* A Branch. */
58 VLIW_LABEL_TYPE, /* A Label. */
59 VLIW_NOP_TYPE, /* A NOP. */
60 VLIW_BRANCH_HAS_NOPS /* A Branch that requires NOPS. */
63 /* We're going to use these in the fr_subtype field to mark
64 whether to keep inserted nops. */
66 #define NOP_KEEP 1 /* Keep these NOPS. */
67 #define NOP_DELETE 2 /* Delete these NOPS. */
69 #define DO_COUNT TRUE
70 #define DONT_COUNT FALSE
72 /* A list of insns within a VLIW insn. */
73 struct vliw_insn_list
75 /* The type of this insn. */
76 enum vliw_insn_type type;
78 /* The corresponding gas insn information. */
79 const CGEN_INSN *insn;
81 /* For branches and labels, the symbol that is referenced. */
82 symbolS *sym;
84 /* For branches, the frag containing the single nop that was generated. */
85 fragS *snop_frag;
87 /* For branches, the frag containing the double nop that was generated. */
88 fragS *dnop_frag;
90 /* Pointer to raw data for this insn. */
91 char *address;
93 /* Next insn in list. */
94 struct vliw_insn_list *next;
97 static struct vliw_insn_list single_nop_insn = {
98 VLIW_NOP_TYPE, NULL, NULL, NULL, NULL, NULL, NULL };
100 static struct vliw_insn_list double_nop_insn = {
101 VLIW_NOP_TYPE, NULL, NULL, NULL, NULL, NULL, NULL };
103 struct vliw_chain
105 int num;
106 int insn_count;
107 struct vliw_insn_list *insn_list;
108 struct vliw_chain *next;
111 static struct vliw_chain *vliw_chain_top;
112 static struct vliw_chain *current_vliw_chain;
113 static struct vliw_chain *previous_vliw_chain;
114 static struct vliw_insn_list *current_vliw_insn;
116 const char comment_chars[] = ";";
117 const char line_comment_chars[] = "#";
118 const char line_separator_chars[] = "";
119 const char EXP_CHARS[] = "eE";
120 const char FLT_CHARS[] = "dD";
122 static FRV_VLIW vliw;
124 /* Default machine */
126 #ifdef DEFAULT_CPU_FRV
127 #define DEFAULT_MACHINE bfd_mach_frv
128 #define DEFAULT_FLAGS EF_FRV_CPU_GENERIC
130 #else
131 #ifdef DEFAULT_CPU_FR300
132 #define DEFAULT_MACHINE bfd_mach_fr300
133 #define DEFAULT_FLAGS EF_FRV_CPU_FR300
135 #else
136 #ifdef DEFAULT_CPU_SIMPLE
137 #define DEFAULT_MACHINE bfd_mach_frvsimple
138 #define DEFAULT_FLAGS EF_FRV_CPU_SIMPLE
140 #else
141 #ifdef DEFAULT_CPU_TOMCAT
142 #define DEFAULT_MACHINE bfd_mach_frvtomcat
143 #define DEFAULT_FLAGS EF_FRV_CPU_TOMCAT
145 #else
146 #ifdef DEFAULT_CPU_FR400
147 #define DEFAULT_MACHINE bfd_mach_fr400
148 #define DEFAULT_FLAGS EF_FRV_CPU_FR400
150 #else
151 #ifdef DEFAULT_CPU_FR550
152 #define DEFAULT_MACHINE bfd_mach_fr550
153 #define DEFAULT_FLAGS EF_FRV_CPU_FR550
155 #else
156 #define DEFAULT_MACHINE bfd_mach_fr500
157 #define DEFAULT_FLAGS EF_FRV_CPU_FR500
158 #endif
159 #endif
160 #endif
161 #endif
162 #endif
163 #endif
165 static unsigned long frv_mach = bfd_mach_frv;
167 /* Flags to set in the elf header */
168 static flagword frv_flags = DEFAULT_FLAGS;
170 static int frv_user_set_flags_p = 0;
171 static int frv_pic_p = 0;
172 static const char *frv_pic_flag = (const char *)0;
174 /* Print tomcat-specific debugging info. */
175 static int tomcat_debug = 0;
177 /* Tomcat-specific NOP statistics. */
178 static int tomcat_stats = 0;
179 static int tomcat_doubles = 0;
180 static int tomcat_singles = 0;
182 /* Forward reference to static functions */
183 static void frv_set_flags PARAMS ((int));
184 static void frv_pic_ptr PARAMS ((int));
185 static void frv_frob_file_section PARAMS ((bfd *, asection *, PTR));
187 /* The target specific pseudo-ops which we support. */
188 const pseudo_typeS md_pseudo_table[] =
190 { "eflags", frv_set_flags, 0 },
191 { "word", cons, 4 },
192 { "picptr", frv_pic_ptr, 4 },
193 { NULL, NULL, 0 }
197 #define FRV_SHORTOPTS "G:"
198 const char * md_shortopts = FRV_SHORTOPTS;
200 #define OPTION_GPR_32 (OPTION_MD_BASE)
201 #define OPTION_GPR_64 (OPTION_MD_BASE + 1)
202 #define OPTION_FPR_32 (OPTION_MD_BASE + 2)
203 #define OPTION_FPR_64 (OPTION_MD_BASE + 3)
204 #define OPTION_SOFT_FLOAT (OPTION_MD_BASE + 4)
205 #define OPTION_DWORD_YES (OPTION_MD_BASE + 5)
206 #define OPTION_DWORD_NO (OPTION_MD_BASE + 6)
207 #define OPTION_DOUBLE (OPTION_MD_BASE + 7)
208 #define OPTION_NO_DOUBLE (OPTION_MD_BASE + 8)
209 #define OPTION_MEDIA (OPTION_MD_BASE + 9)
210 #define OPTION_NO_MEDIA (OPTION_MD_BASE + 10)
211 #define OPTION_CPU (OPTION_MD_BASE + 11)
212 #define OPTION_PIC (OPTION_MD_BASE + 12)
213 #define OPTION_BIGPIC (OPTION_MD_BASE + 13)
214 #define OPTION_LIBPIC (OPTION_MD_BASE + 14)
215 #define OPTION_MULADD (OPTION_MD_BASE + 15)
216 #define OPTION_NO_MULADD (OPTION_MD_BASE + 16)
217 #define OPTION_TOMCAT_DEBUG (OPTION_MD_BASE + 17)
218 #define OPTION_TOMCAT_STATS (OPTION_MD_BASE + 18)
219 #define OPTION_PACK (OPTION_MD_BASE + 19)
220 #define OPTION_NO_PACK (OPTION_MD_BASE + 20)
222 struct option md_longopts[] =
224 { "mgpr-32", no_argument, NULL, OPTION_GPR_32 },
225 { "mgpr-64", no_argument, NULL, OPTION_GPR_64 },
226 { "mfpr-32", no_argument, NULL, OPTION_FPR_32 },
227 { "mfpr-64", no_argument, NULL, OPTION_FPR_64 },
228 { "mhard-float", no_argument, NULL, OPTION_FPR_64 },
229 { "msoft-float", no_argument, NULL, OPTION_SOFT_FLOAT },
230 { "mdword", no_argument, NULL, OPTION_DWORD_YES },
231 { "mno-dword", no_argument, NULL, OPTION_DWORD_NO },
232 { "mdouble", no_argument, NULL, OPTION_DOUBLE },
233 { "mno-double", no_argument, NULL, OPTION_NO_DOUBLE },
234 { "mmedia", no_argument, NULL, OPTION_MEDIA },
235 { "mno-media", no_argument, NULL, OPTION_NO_MEDIA },
236 { "mcpu", required_argument, NULL, OPTION_CPU },
237 { "mpic", no_argument, NULL, OPTION_PIC },
238 { "mPIC", no_argument, NULL, OPTION_BIGPIC },
239 { "mlibrary-pic", no_argument, NULL, OPTION_LIBPIC },
240 { "mmuladd", no_argument, NULL, OPTION_MULADD },
241 { "mno-muladd", no_argument, NULL, OPTION_NO_MULADD },
242 { "mtomcat-debug", no_argument, NULL, OPTION_TOMCAT_DEBUG },
243 { "mtomcat-stats", no_argument, NULL, OPTION_TOMCAT_STATS },
244 { "mpack", no_argument, NULL, OPTION_PACK },
245 { "mno-pack", no_argument, NULL, OPTION_NO_PACK },
246 { NULL, no_argument, NULL, 0 },
249 size_t md_longopts_size = sizeof (md_longopts);
251 /* What value to give to bfd_set_gp_size. */
252 static int g_switch_value = 8;
255 md_parse_option (c, arg)
256 int c;
257 char * arg;
259 switch (c)
261 default:
262 return 0;
264 case 'G':
265 g_switch_value = atoi (arg);
266 if (! g_switch_value)
267 frv_flags |= EF_FRV_G0;
268 break;
270 case OPTION_GPR_32:
271 frv_flags = (frv_flags & ~EF_FRV_GPR_MASK) | EF_FRV_GPR_32;
272 break;
274 case OPTION_GPR_64:
275 frv_flags = (frv_flags & ~EF_FRV_GPR_MASK) | EF_FRV_GPR_64;
276 break;
278 case OPTION_FPR_32:
279 frv_flags = (frv_flags & ~EF_FRV_FPR_MASK) | EF_FRV_FPR_32;
280 break;
282 case OPTION_FPR_64:
283 frv_flags = (frv_flags & ~EF_FRV_FPR_MASK) | EF_FRV_FPR_64;
284 break;
286 case OPTION_SOFT_FLOAT:
287 frv_flags = (frv_flags & ~EF_FRV_FPR_MASK) | EF_FRV_FPR_NONE;
288 break;
290 case OPTION_DWORD_YES:
291 frv_flags = (frv_flags & ~EF_FRV_DWORD_MASK) | EF_FRV_DWORD_YES;
292 break;
294 case OPTION_DWORD_NO:
295 frv_flags = (frv_flags & ~EF_FRV_DWORD_MASK) | EF_FRV_DWORD_NO;
296 break;
298 case OPTION_DOUBLE:
299 frv_flags |= EF_FRV_DOUBLE;
300 break;
302 case OPTION_NO_DOUBLE:
303 frv_flags &= ~EF_FRV_DOUBLE;
304 break;
306 case OPTION_MEDIA:
307 frv_flags |= EF_FRV_MEDIA;
308 break;
310 case OPTION_NO_MEDIA:
311 frv_flags &= ~EF_FRV_MEDIA;
312 break;
314 case OPTION_MULADD:
315 frv_flags |= EF_FRV_MULADD;
316 break;
318 case OPTION_NO_MULADD:
319 frv_flags &= ~EF_FRV_MULADD;
320 break;
322 case OPTION_PACK:
323 frv_flags &= ~EF_FRV_NOPACK;
324 break;
326 case OPTION_NO_PACK:
327 frv_flags |= EF_FRV_NOPACK;
328 break;
330 case OPTION_CPU:
332 char *p;
333 int cpu_flags = EF_FRV_CPU_GENERIC;
335 /* Identify the processor type */
336 p = arg;
337 if (strcmp (p, "frv") == 0)
339 cpu_flags = EF_FRV_CPU_GENERIC;
340 frv_mach = bfd_mach_frv;
343 else if (strcmp (p, "fr500") == 0)
345 cpu_flags = EF_FRV_CPU_FR500;
346 frv_mach = bfd_mach_fr500;
349 else if (strcmp (p, "fr550") == 0)
351 cpu_flags = EF_FRV_CPU_FR550;
352 frv_mach = bfd_mach_fr550;
355 else if (strcmp (p, "fr400") == 0)
357 cpu_flags = EF_FRV_CPU_FR400;
358 frv_mach = bfd_mach_fr400;
361 else if (strcmp (p, "fr300") == 0)
363 cpu_flags = EF_FRV_CPU_FR300;
364 frv_mach = bfd_mach_fr300;
367 else if (strcmp (p, "simple") == 0)
369 cpu_flags = EF_FRV_CPU_SIMPLE;
370 frv_mach = bfd_mach_frvsimple;
371 frv_flags |= EF_FRV_NOPACK;
374 else if (strcmp (p, "tomcat") == 0)
376 cpu_flags = EF_FRV_CPU_TOMCAT;
377 frv_mach = bfd_mach_frvtomcat;
380 else
382 as_fatal ("Unknown cpu -mcpu=%s", arg);
383 return 0;
386 frv_flags = (frv_flags & ~EF_FRV_CPU_MASK) | cpu_flags;
388 break;
390 case OPTION_PIC:
391 frv_flags |= EF_FRV_PIC;
392 frv_pic_p = 1;
393 frv_pic_flag = "-fpic";
394 break;
396 case OPTION_BIGPIC:
397 frv_flags |= EF_FRV_BIGPIC;
398 frv_pic_p = 1;
399 frv_pic_flag = "-fPIC";
400 break;
402 case OPTION_LIBPIC:
403 frv_flags |= (EF_FRV_LIBPIC | EF_FRV_G0);
404 frv_pic_p = 1;
405 frv_pic_flag = "-mlibrary-pic";
406 g_switch_value = 0;
407 break;
409 case OPTION_TOMCAT_DEBUG:
410 tomcat_debug = 1;
411 break;
413 case OPTION_TOMCAT_STATS:
414 tomcat_stats = 1;
415 break;
418 return 1;
421 void
422 md_show_usage (stream)
423 FILE * stream;
425 fprintf (stream, _("FRV specific command line options:\n"));
426 fprintf (stream, _("-G n Data >= n bytes is in small data area\n"));
427 fprintf (stream, _("-mgpr-32 Note 32 gprs are used\n"));
428 fprintf (stream, _("-mgpr-64 Note 64 gprs are used\n"));
429 fprintf (stream, _("-mfpr-32 Note 32 fprs are used\n"));
430 fprintf (stream, _("-mfpr-64 Note 64 fprs are used\n"));
431 fprintf (stream, _("-msoft-float Note software fp is used\n"));
432 fprintf (stream, _("-mdword Note stack is aligned to a 8 byte boundary\n"));
433 fprintf (stream, _("-mno-dword Note stack is aligned to a 4 byte boundary\n"));
434 fprintf (stream, _("-mdouble Note fp double insns are used\n"));
435 fprintf (stream, _("-mmedia Note media insns are used\n"));
436 fprintf (stream, _("-mmuladd Note multiply add/subtract insns are used\n"));
437 fprintf (stream, _("-mpack Note instructions are packed\n"));
438 fprintf (stream, _("-mno-pack Do not allow instructions to be packed\n"));
439 fprintf (stream, _("-mpic Note small position independent code\n"));
440 fprintf (stream, _("-mPIC Note large position independent code\n"));
441 fprintf (stream, _("-mlibrary-pic Compile library for large position indepedent code\n"));
442 fprintf (stream, _("-mcpu={fr500|fr550|fr400|fr300|frv|simple|tomcat}\n"));
443 fprintf (stream, _(" Record the cpu type\n"));
444 fprintf (stream, _("-mtomcat-stats Print out stats for tomcat workarounds\n"));
445 fprintf (stream, _("-mtomcat-debug Debug tomcat workarounds\n"));
449 void
450 md_begin ()
452 /* Initialize the `cgen' interface. */
454 /* Set the machine number and endian. */
455 gas_cgen_cpu_desc = frv_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
456 CGEN_CPU_OPEN_ENDIAN,
457 CGEN_ENDIAN_BIG,
458 CGEN_CPU_OPEN_END);
459 frv_cgen_init_asm (gas_cgen_cpu_desc);
461 /* This is a callback from cgen to gas to parse operands. */
462 cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
464 /* Set the ELF flags if desired. */
465 if (frv_flags)
466 bfd_set_private_flags (stdoutput, frv_flags);
468 /* Set the machine type */
469 bfd_default_set_arch_mach (stdoutput, bfd_arch_frv, frv_mach);
471 /* Set up gp size so we can put local common items in .sbss */
472 bfd_set_gp_size (stdoutput, g_switch_value);
474 frv_vliw_reset (& vliw, frv_mach, frv_flags);
477 int chain_num = 0;
479 struct vliw_insn_list *frv_insert_vliw_insn PARAMS ((bfd_boolean));
481 struct vliw_insn_list *
482 frv_insert_vliw_insn (count)
483 bfd_boolean count;
485 struct vliw_insn_list *vliw_insn_list_entry;
486 struct vliw_chain *vliw_chain_entry;
488 if (current_vliw_chain == NULL)
490 vliw_chain_entry = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
491 vliw_chain_entry->insn_count = 0;
492 vliw_chain_entry->insn_list = NULL;
493 vliw_chain_entry->next = NULL;
494 vliw_chain_entry->num = chain_num++;
496 if (!vliw_chain_top)
497 vliw_chain_top = vliw_chain_entry;
498 current_vliw_chain = vliw_chain_entry;
499 if (previous_vliw_chain)
500 previous_vliw_chain->next = vliw_chain_entry;
503 vliw_insn_list_entry = (struct vliw_insn_list *) xmalloc (sizeof (struct vliw_insn_list));
504 vliw_insn_list_entry->type = VLIW_GENERIC_TYPE;
505 vliw_insn_list_entry->insn = NULL;
506 vliw_insn_list_entry->sym = NULL;
507 vliw_insn_list_entry->snop_frag = NULL;
508 vliw_insn_list_entry->dnop_frag = NULL;
509 vliw_insn_list_entry->next = NULL;
511 if (count)
512 current_vliw_chain->insn_count++;
514 if (current_vliw_insn)
515 current_vliw_insn->next = vliw_insn_list_entry;
516 current_vliw_insn = vliw_insn_list_entry;
518 if (!current_vliw_chain->insn_list)
519 current_vliw_chain->insn_list = current_vliw_insn;
521 return vliw_insn_list_entry;
524 /* Identify the following cases:
526 1) A VLIW insn that contains both a branch and the branch destination.
527 This requires the insertion of two vliw instructions before the
528 branch. The first consists of two nops. The second consists of
529 a single nop.
531 2) A single instruction VLIW insn which is the destination of a branch
532 that is in the next VLIW insn. This requires the insertion of a vliw
533 insn containing two nops before the branch.
535 3) A double instruction VLIW insn which contains the destination of a
536 branch that is in the next VLIW insn. This requires the insertion of
537 a VLIW insn containing a single nop before the branch.
539 4) A single instruction VLIW insn which contains branch destination (x),
540 followed by a single instruction VLIW insn which does not contain
541 the branch to (x), followed by a VLIW insn which does contain the branch
542 to (x). This requires the insertion of a VLIW insn containing a single
543 nop before the VLIW instruction containing the branch.
546 #define FRV_IS_NOP(insn) (insn.buffer[0] == FRV_NOP_PACK || insn.buffer[0] == FRV_NOP_NOPACK)
547 #define FRV_NOP_PACK 0x00880000 /* ori.p gr0,0,gr0 */
548 #define FRV_NOP_NOPACK 0x80880000 /* ori gr0,0,gr0 */
550 /* Check a vliw insn for an insn of type containing the sym passed in label_sym. */
552 static struct vliw_insn_list *frv_find_in_vliw
553 PARAMS ((enum vliw_insn_type, struct vliw_chain *, symbolS *));
555 static struct vliw_insn_list *
556 frv_find_in_vliw (vliw_insn_type, this_chain, label_sym)
557 enum vliw_insn_type vliw_insn_type;
558 struct vliw_chain *this_chain;
559 symbolS *label_sym;
562 struct vliw_insn_list *the_insn;
564 if (!this_chain)
565 return NULL;
567 for (the_insn = this_chain->insn_list; the_insn; the_insn = the_insn->next)
569 if (the_insn->type == vliw_insn_type
570 && the_insn->sym == label_sym)
571 return the_insn;
574 return NULL;
577 enum vliw_nop_type
579 /* A Vliw insn containing a single nop insn. */
580 VLIW_SINGLE_NOP,
582 /* A Vliw insn containing two nop insns. */
583 VLIW_DOUBLE_NOP,
585 /* Two vliw insns. The first containing two nop insns.
586 The second contain a single nop insn. */
587 VLIW_DOUBLE_THEN_SINGLE_NOP
590 static void frv_debug_tomcat PARAMS ((struct vliw_chain *));
592 static void
593 frv_debug_tomcat (start_chain)
594 struct vliw_chain *start_chain;
596 struct vliw_chain *this_chain;
597 struct vliw_insn_list *this_insn;
598 int i = 1;
600 for (this_chain = start_chain; this_chain; this_chain = this_chain->next, i++)
602 fprintf (stderr, "\nVliw Insn #%d, #insns: %d\n", i, this_chain->insn_count);
604 for (this_insn = this_chain->insn_list; this_insn; this_insn = this_insn->next)
606 if (this_insn->type == VLIW_LABEL_TYPE)
607 fprintf (stderr, "Label Value: %d\n", (int) this_insn->sym);
608 else if (this_insn->type == VLIW_BRANCH_TYPE)
609 fprintf (stderr, "%s to %d\n", this_insn->insn->base->name, (int) this_insn->sym);
610 else if (this_insn->type == VLIW_BRANCH_HAS_NOPS)
611 fprintf (stderr, "nop'd %s to %d\n", this_insn->insn->base->name, (int) this_insn->sym);
612 else if (this_insn->type == VLIW_NOP_TYPE)
613 fprintf (stderr, "Nop\n");
614 else
615 fprintf (stderr, " %s\n", this_insn->insn->base->name);
620 static void frv_adjust_vliw_count PARAMS ((struct vliw_chain *));
622 static void
623 frv_adjust_vliw_count (this_chain)
624 struct vliw_chain *this_chain;
626 struct vliw_insn_list *this_insn;
628 this_chain->insn_count = 0;
630 for (this_insn = this_chain->insn_list;
631 this_insn;
632 this_insn = this_insn->next)
634 if (this_insn->type != VLIW_LABEL_TYPE)
635 this_chain->insn_count++;
640 /* Insert the desired nop combination in the vliw chain before insert_before_insn.
641 Rechain the vliw insn. */
643 static struct vliw_chain *frv_tomcat_shuffle
644 PARAMS ((enum vliw_nop_type, struct vliw_chain *, struct vliw_insn_list *));
646 static struct vliw_chain *
647 frv_tomcat_shuffle (this_nop_type, vliw_to_split, insert_before_insn)
648 enum vliw_nop_type this_nop_type;
649 struct vliw_chain *vliw_to_split;
650 struct vliw_insn_list *insert_before_insn;
653 bfd_boolean pack_prev = FALSE;
654 struct vliw_chain *return_me = NULL;
655 struct vliw_insn_list *prev_insn = NULL;
656 struct vliw_insn_list *curr_insn = vliw_to_split->insn_list;
658 struct vliw_chain *double_nop = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
659 struct vliw_chain *single_nop = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
660 struct vliw_chain *second_part = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
661 struct vliw_chain *curr_vliw = vliw_chain_top;
662 struct vliw_chain *prev_vliw = NULL;
664 while (curr_insn && curr_insn != insert_before_insn)
666 /* We can't set the packing bit on a label. If we have the case
667 label 1:
668 label 2:
669 label 3:
670 branch that needs nops
671 Then don't set pack bit later. */
673 if (curr_insn->type != VLIW_LABEL_TYPE)
674 pack_prev = TRUE;
675 prev_insn = curr_insn;
676 curr_insn = curr_insn->next;
679 while (curr_vliw && curr_vliw != vliw_to_split)
681 prev_vliw = curr_vliw;
682 curr_vliw = curr_vliw->next;
685 switch (this_nop_type)
687 case VLIW_SINGLE_NOP:
688 if (!prev_insn)
690 /* Branch is first, Insert the NOP prior to this vliw insn. */
691 if (prev_vliw)
692 prev_vliw->next = single_nop;
693 else
694 vliw_chain_top = single_nop;
695 single_nop->next = vliw_to_split;
696 vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
697 return_me = vliw_to_split;
699 else
701 /* Set the packing bit on the previous insn. */
702 if (pack_prev)
704 unsigned char *buffer = prev_insn->address;
705 buffer[0] |= 0x80;
707 /* The branch is in the middle. Split this vliw insn into first
708 and second parts. Insert the NOP inbetween. */
710 second_part->insn_list = insert_before_insn;
711 second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
712 second_part->next = vliw_to_split->next;
713 frv_adjust_vliw_count (second_part);
715 single_nop->next = second_part;
717 vliw_to_split->next = single_nop;
718 prev_insn->next = NULL;
720 return_me = second_part;
721 frv_adjust_vliw_count (vliw_to_split);
723 break;
725 case VLIW_DOUBLE_NOP:
726 if (!prev_insn)
728 /* Branch is first, Insert the NOP prior to this vliw insn. */
729 if (prev_vliw)
730 prev_vliw->next = double_nop;
731 else
732 vliw_chain_top = double_nop;
734 double_nop->next = vliw_to_split;
735 return_me = vliw_to_split;
736 vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
738 else
740 /* Set the packing bit on the previous insn. */
741 if (pack_prev)
743 unsigned char *buffer = prev_insn->address;
744 buffer[0] |= 0x80;
747 /* The branch is in the middle. Split this vliw insn into first
748 and second parts. Insert the NOP inbetween. */
749 second_part->insn_list = insert_before_insn;
750 second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
751 second_part->next = vliw_to_split->next;
752 frv_adjust_vliw_count (second_part);
754 double_nop->next = second_part;
756 vliw_to_split->next = single_nop;
757 prev_insn->next = NULL;
758 frv_adjust_vliw_count (vliw_to_split);
760 return_me = second_part;
762 break;
764 case VLIW_DOUBLE_THEN_SINGLE_NOP:
765 double_nop->next = single_nop;
766 double_nop->insn_count = 2;
767 double_nop->insn_list = &double_nop_insn;
768 single_nop->insn_count = 1;
769 single_nop->insn_list = &single_nop_insn;
771 if (!prev_insn)
773 /* The branch is the first insn in this vliw. Don't split the vliw. Insert
774 the nops prior to this vliw. */
775 if (prev_vliw)
776 prev_vliw->next = double_nop;
777 else
778 vliw_chain_top = double_nop;
780 single_nop->next = vliw_to_split;
781 return_me = vliw_to_split;
782 vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
784 else
786 /* Set the packing bit on the previous insn. */
787 if (pack_prev)
789 unsigned char *buffer = prev_insn->address;
790 buffer[0] |= 0x80;
793 /* The branch is in the middle of this vliw insn. Split into first and
794 second parts. Insert the nop vliws in between. */
795 second_part->insn_list = insert_before_insn;
796 second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
797 second_part->next = vliw_to_split->next;
798 frv_adjust_vliw_count (second_part);
800 single_nop->next = second_part;
802 vliw_to_split->next = double_nop;
803 prev_insn->next = NULL;
804 frv_adjust_vliw_count (vliw_to_split);
806 return_me = second_part;
808 break;
811 return return_me;
814 static void frv_tomcat_analyze_vliw_chains PARAMS ((void));
816 static void
817 frv_tomcat_analyze_vliw_chains ()
819 struct vliw_chain *vliw1 = NULL;
820 struct vliw_chain *vliw2 = NULL;
821 struct vliw_chain *vliw3 = NULL;
823 struct vliw_insn_list *this_insn = NULL;
824 struct vliw_insn_list *temp_insn = NULL;
826 /* We potentially need to look at three VLIW insns to determine if the
827 workaround is required. Set them up. Ignore existing nops during analysis. */
829 #define FRV_SET_VLIW_WINDOW(VLIW1, VLIW2, VLIW3) \
830 if (VLIW1 && VLIW1->next) \
831 VLIW2 = VLIW1->next; \
832 else \
833 VLIW2 = NULL; \
834 if (VLIW2 && VLIW2->next) \
835 VLIW3 = VLIW2->next; \
836 else \
837 VLIW3 = NULL
839 vliw1 = vliw_chain_top;
841 workaround_top:
843 FRV_SET_VLIW_WINDOW (vliw1, vliw2, vliw3);
845 if (!vliw1)
846 return;
848 if (vliw1->insn_count == 1)
850 /* check vliw1 for a label. */
851 if (vliw1->insn_list->type == VLIW_LABEL_TYPE)
853 temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw2, vliw1->insn_list->sym);
854 if (temp_insn)
856 vliw1 = frv_tomcat_shuffle (VLIW_DOUBLE_NOP, vliw2, vliw1->insn_list);
857 temp_insn->dnop_frag->fr_subtype = NOP_KEEP;
858 vliw1 = vliw1->next;
859 if (tomcat_stats)
860 tomcat_doubles++;
861 goto workaround_top;
863 else if (vliw2
864 && vliw2->insn_count == 1
865 && (temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw3, vliw1->insn_list->sym)) != NULL)
867 temp_insn->snop_frag->fr_subtype = NOP_KEEP;
868 vliw1 = frv_tomcat_shuffle (VLIW_SINGLE_NOP, vliw3, vliw3->insn_list);
869 if (tomcat_stats)
870 tomcat_singles++;
871 goto workaround_top;
876 if (vliw1->insn_count == 2)
878 struct vliw_insn_list *this_insn;
880 /* check vliw1 for a label. */
881 for (this_insn = vliw1->insn_list; this_insn; this_insn = this_insn->next)
883 if (this_insn->type == VLIW_LABEL_TYPE)
885 if ((temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw2, this_insn->sym)) != NULL)
887 temp_insn->snop_frag->fr_subtype = NOP_KEEP;
888 vliw1 = frv_tomcat_shuffle (VLIW_SINGLE_NOP, vliw2, this_insn);
889 if (tomcat_stats)
890 tomcat_singles++;
892 else
893 vliw1 = vliw1->next;
894 goto workaround_top;
898 /* Examine each insn in this VLIW. Look for the workaround criteria. */
899 for (this_insn = vliw1->insn_list; this_insn; this_insn = this_insn->next)
901 /* Don't look at labels or nops. */
902 while (this_insn
903 && (this_insn->type == VLIW_LABEL_TYPE
904 || this_insn->type == VLIW_NOP_TYPE
905 || this_insn->type == VLIW_BRANCH_HAS_NOPS))
906 this_insn = this_insn->next;
908 if (!this_insn)
910 vliw1 = vliw2;
911 goto workaround_top;
914 if (frv_is_branch_insn (this_insn->insn))
916 if ((temp_insn = frv_find_in_vliw (VLIW_LABEL_TYPE, vliw1, this_insn->sym)) != NULL)
918 /* Insert [nop/nop] [nop] before branch. */
919 this_insn->snop_frag->fr_subtype = NOP_KEEP;
920 this_insn->dnop_frag->fr_subtype = NOP_KEEP;
921 vliw1 = frv_tomcat_shuffle (VLIW_DOUBLE_THEN_SINGLE_NOP, vliw1, this_insn);
922 goto workaround_top;
928 /* This vliw insn checks out okay. Take a look at the next one. */
929 vliw1 = vliw1->next;
930 goto workaround_top;
933 void
934 frv_tomcat_workaround ()
936 if (frv_mach != bfd_mach_frvtomcat)
937 return;
939 if (tomcat_debug)
940 frv_debug_tomcat (vliw_chain_top);
942 frv_tomcat_analyze_vliw_chains ();
944 if (tomcat_stats)
946 fprintf (stderr, "Inserted %d Single Nops\n", tomcat_singles);
947 fprintf (stderr, "Inserted %d Double Nops\n", tomcat_doubles);
951 static int
952 fr550_check_insn_acc_range (frv_insn *insn, int low, int hi)
954 int acc;
955 switch (CGEN_INSN_NUM (insn->insn))
957 case FRV_INSN_MADDACCS:
958 case FRV_INSN_MSUBACCS:
959 case FRV_INSN_MDADDACCS:
960 case FRV_INSN_MDSUBACCS:
961 case FRV_INSN_MASACCS:
962 case FRV_INSN_MDASACCS:
963 acc = insn->fields.f_ACC40Si;
964 if (acc < low || acc > hi)
965 return 1; /* out of range */
966 acc = insn->fields.f_ACC40Sk;
967 if (acc < low || acc > hi)
968 return 1; /* out of range */
969 break;
970 case FRV_INSN_MMULHS:
971 case FRV_INSN_MMULHU:
972 case FRV_INSN_MMULXHS:
973 case FRV_INSN_MMULXHU:
974 case FRV_INSN_CMMULHS:
975 case FRV_INSN_CMMULHU:
976 case FRV_INSN_MQMULHS:
977 case FRV_INSN_MQMULHU:
978 case FRV_INSN_MQMULXHS:
979 case FRV_INSN_MQMULXHU:
980 case FRV_INSN_CMQMULHS:
981 case FRV_INSN_CMQMULHU:
982 case FRV_INSN_MMACHS:
983 case FRV_INSN_MMRDHS:
984 case FRV_INSN_CMMACHS:
985 case FRV_INSN_MQMACHS:
986 case FRV_INSN_CMQMACHS:
987 case FRV_INSN_MQXMACHS:
988 case FRV_INSN_MQXMACXHS:
989 case FRV_INSN_MQMACXHS:
990 case FRV_INSN_MCPXRS:
991 case FRV_INSN_MCPXIS:
992 case FRV_INSN_CMCPXRS:
993 case FRV_INSN_CMCPXIS:
994 case FRV_INSN_MQCPXRS:
995 case FRV_INSN_MQCPXIS:
996 acc = insn->fields.f_ACC40Sk;
997 if (acc < low || acc > hi)
998 return 1; /* out of range */
999 break;
1000 case FRV_INSN_MMACHU:
1001 case FRV_INSN_MMRDHU:
1002 case FRV_INSN_CMMACHU:
1003 case FRV_INSN_MQMACHU:
1004 case FRV_INSN_CMQMACHU:
1005 case FRV_INSN_MCPXRU:
1006 case FRV_INSN_MCPXIU:
1007 case FRV_INSN_CMCPXRU:
1008 case FRV_INSN_CMCPXIU:
1009 case FRV_INSN_MQCPXRU:
1010 case FRV_INSN_MQCPXIU:
1011 acc = insn->fields.f_ACC40Uk;
1012 if (acc < low || acc > hi)
1013 return 1; /* out of range */
1014 break;
1015 default:
1016 break;
1018 return 0; /* all is ok */
1021 static int
1022 fr550_check_acc_range (FRV_VLIW *vliw, frv_insn *insn)
1024 switch ((*vliw->current_vliw)[vliw->next_slot - 1])
1026 case UNIT_FM0:
1027 case UNIT_FM2:
1028 return fr550_check_insn_acc_range (insn, 0, 3);
1029 case UNIT_FM1:
1030 case UNIT_FM3:
1031 return fr550_check_insn_acc_range (insn, 4, 7);
1032 default:
1033 break;
1035 return 0; /* all is ok */
1038 void
1039 md_assemble (str)
1040 char * str;
1042 frv_insn insn;
1043 char *errmsg;
1044 int packing_constraint;
1045 finished_insnS finished_insn;
1046 fragS *double_nop_frag = NULL;
1047 fragS *single_nop_frag = NULL;
1048 struct vliw_insn_list *vliw_insn_list_entry = NULL;
1050 /* Initialize GAS's cgen interface for a new instruction. */
1051 gas_cgen_init_parse ();
1053 insn.insn = frv_cgen_assemble_insn
1054 (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, &errmsg);
1056 if (!insn.insn)
1058 as_bad (errmsg);
1059 return;
1062 /* If the cpu is tomcat, then we need to insert nops to workaround
1063 hardware limitations. We need to keep track of each vliw unit
1064 and examine the length of the unit and the individual insns
1065 within the unit to determine the number and location of the
1066 required nops. */
1067 if (frv_mach == bfd_mach_frvtomcat)
1069 /* If we've just finished a VLIW insn OR this is a branch,
1070 then start up a new frag. Fill it with nops. We will get rid
1071 of those that are not required after we've seen all of the
1072 instructions but before we start resolving fixups. */
1073 if ( !FRV_IS_NOP (insn)
1074 && (frv_is_branch_insn (insn.insn) || insn.fields.f_pack))
1076 char *buffer;
1078 frag_wane (frag_now);
1079 frag_new (0);
1080 double_nop_frag = frag_now;
1081 buffer = frag_var (rs_machine_dependent, 8, 8, NOP_DELETE, NULL, 0, 0);
1082 md_number_to_chars (buffer, FRV_NOP_PACK, 4);
1083 md_number_to_chars (buffer+4, FRV_NOP_NOPACK, 4);
1085 frag_wane (frag_now);
1086 frag_new (0);
1087 single_nop_frag = frag_now;
1088 buffer = frag_var (rs_machine_dependent, 4, 4, NOP_DELETE, NULL, 0, 0);
1089 md_number_to_chars (buffer, FRV_NOP_NOPACK, 4);
1092 vliw_insn_list_entry = frv_insert_vliw_insn (DO_COUNT);
1093 vliw_insn_list_entry->insn = insn.insn;
1094 if (frv_is_branch_insn (insn.insn))
1095 vliw_insn_list_entry->type = VLIW_BRANCH_TYPE;
1097 if ( !FRV_IS_NOP (insn)
1098 && (frv_is_branch_insn (insn.insn) || insn.fields.f_pack))
1100 vliw_insn_list_entry->snop_frag = single_nop_frag;
1101 vliw_insn_list_entry->dnop_frag = double_nop_frag;
1105 /* Make sure that this insn does not violate the VLIW packing constraints. */
1106 /* -mno-pack disallows any packing whatsoever. */
1107 if (frv_flags & EF_FRV_NOPACK)
1109 if (! insn.fields.f_pack)
1111 as_bad (_("VLIW packing used for -mno-pack"));
1112 return;
1115 /* -mcpu=FRV is an idealized FR-V implementation that supports all of the
1116 instructions, don't do vliw checking. */
1117 else if (frv_mach != bfd_mach_frv)
1119 packing_constraint = frv_vliw_add_insn (& vliw, insn.insn);
1120 if (frv_mach == bfd_mach_fr550 && ! packing_constraint)
1121 packing_constraint = fr550_check_acc_range (& vliw, & insn);
1122 if (insn.fields.f_pack)
1123 frv_vliw_reset (& vliw, frv_mach, frv_flags);
1124 if (packing_constraint)
1126 as_bad (_("VLIW packing constraint violation"));
1127 return;
1131 /* Doesn't really matter what we pass for RELAX_P here. */
1132 gas_cgen_finish_insn (insn.insn, insn.buffer,
1133 CGEN_FIELDS_BITSIZE (& insn.fields), 1, &finished_insn);
1136 /* If the cpu is tomcat, then we need to insert nops to workaround
1137 hardware limitations. We need to keep track of each vliw unit
1138 and examine the length of the unit and the individual insns
1139 within the unit to determine the number and location of the
1140 required nops. */
1141 if (frv_mach == bfd_mach_frvtomcat)
1143 if (vliw_insn_list_entry)
1144 vliw_insn_list_entry->address = finished_insn.addr;
1145 else
1146 abort();
1148 if (insn.fields.f_pack)
1150 /* We've completed a VLIW insn. */
1151 previous_vliw_chain = current_vliw_chain;
1152 current_vliw_chain = NULL;
1153 current_vliw_insn = NULL;
1158 /* The syntax in the manual says constants begin with '#'.
1159 We just ignore it. */
1161 void
1162 md_operand (expressionP)
1163 expressionS * expressionP;
1165 if (* input_line_pointer == '#')
1167 input_line_pointer ++;
1168 expression (expressionP);
1172 valueT
1173 md_section_align (segment, size)
1174 segT segment;
1175 valueT size;
1177 int align = bfd_get_section_alignment (stdoutput, segment);
1178 return ((size + (1 << align) - 1) & (-1 << align));
1181 symbolS *
1182 md_undefined_symbol (name)
1183 char * name ATTRIBUTE_UNUSED;
1185 return 0;
1188 /* Interface to relax_segment. */
1190 /* FIXME: Build table by hand, get it working, then machine generate. */
1191 const relax_typeS md_relax_table[] =
1193 {1, 1, 0, 0},
1194 {511 - 2 - 2, -512 - 2 + 2, 0, 2 },
1195 {0x2000000 - 1 - 2, -0x2000000 - 2, 2, 0 },
1196 {0x2000000 - 1 - 2, -0x2000000 - 2, 4, 0 }
1199 long
1200 frv_relax_frag (fragP, stretch)
1201 fragS *fragP ATTRIBUTE_UNUSED;
1202 long stretch ATTRIBUTE_UNUSED;
1204 return 0;
1207 /* Return an initial guess of the length by which a fragment must grow to
1208 hold a branch to reach its destination.
1209 Also updates fr_type/fr_subtype as necessary.
1211 Called just before doing relaxation.
1212 Any symbol that is now undefined will not become defined.
1213 The guess for fr_var is ACTUALLY the growth beyond fr_fix.
1214 Whatever we do to grow fr_fix or fr_var contributes to our returned value.
1215 Although it may not be explicit in the frag, pretend fr_var starts with a
1216 0 value. */
1219 md_estimate_size_before_relax (fragP, segment)
1220 fragS * fragP;
1221 segT segment ATTRIBUTE_UNUSED;
1223 switch (fragP->fr_subtype)
1225 case NOP_KEEP:
1226 return fragP->fr_var;
1228 default:
1229 case NOP_DELETE:
1230 return 0;
1234 /* *fragP has been relaxed to its final size, and now needs to have
1235 the bytes inside it modified to conform to the new size.
1237 Called after relaxation is finished.
1238 fragP->fr_type == rs_machine_dependent.
1239 fragP->fr_subtype is the subtype of what the address relaxed to. */
1241 void
1242 md_convert_frag (abfd, sec, fragP)
1243 bfd * abfd ATTRIBUTE_UNUSED;
1244 segT sec ATTRIBUTE_UNUSED;
1245 fragS * fragP;
1247 switch (fragP->fr_subtype)
1249 default:
1250 case NOP_DELETE:
1251 return;
1253 case NOP_KEEP:
1254 fragP->fr_fix = fragP->fr_var;
1255 fragP->fr_var = 0;
1256 return;
1260 /* Functions concerning relocs. */
1262 /* The location from which a PC relative jump should be calculated,
1263 given a PC relative reloc. */
1265 long
1266 md_pcrel_from_section (fixP, sec)
1267 fixS * fixP;
1268 segT sec;
1270 if (TC_FORCE_RELOCATION (fixP)
1271 || (fixP->fx_addsy != (symbolS *) NULL
1272 && S_GET_SEGMENT (fixP->fx_addsy) != sec))
1274 /* If we can't adjust this relocation, or if it references a
1275 local symbol in a different section (which
1276 TC_FORCE_RELOCATION can't check), let the linker figure it
1277 out. */
1278 return 0;
1281 return (fixP->fx_frag->fr_address + fixP->fx_where) & ~1;
1284 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
1285 Returns BFD_RELOC_NONE if no reloc type can be found.
1286 *FIXP may be modified if desired. */
1288 bfd_reloc_code_real_type
1289 md_cgen_lookup_reloc (insn, operand, fixP)
1290 const CGEN_INSN * insn ATTRIBUTE_UNUSED;
1291 const CGEN_OPERAND * operand;
1292 fixS * fixP;
1294 switch (operand->type)
1296 case FRV_OPERAND_LABEL16:
1297 fixP->fx_pcrel = TRUE;
1298 return BFD_RELOC_FRV_LABEL16;
1300 case FRV_OPERAND_LABEL24:
1301 fixP->fx_pcrel = TRUE;
1302 return BFD_RELOC_FRV_LABEL24;
1304 case FRV_OPERAND_UHI16:
1305 case FRV_OPERAND_ULO16:
1306 case FRV_OPERAND_SLO16:
1308 /* The relocation type should be recorded in opinfo */
1309 if (fixP->fx_cgen.opinfo != 0)
1310 return fixP->fx_cgen.opinfo;
1311 break;
1313 case FRV_OPERAND_D12:
1314 case FRV_OPERAND_S12:
1315 return BFD_RELOC_FRV_GPREL12;
1317 case FRV_OPERAND_U12:
1318 return BFD_RELOC_FRV_GPRELU12;
1320 default:
1321 break;
1323 return BFD_RELOC_NONE;
1327 /* See whether we need to force a relocation into the output file.
1328 This is used to force out switch and PC relative relocations when
1329 relaxing. */
1332 frv_force_relocation (fix)
1333 fixS * fix;
1335 if (fix->fx_r_type == BFD_RELOC_FRV_GPREL12
1336 || fix->fx_r_type == BFD_RELOC_FRV_GPRELU12)
1337 return 1;
1339 return generic_force_reloc (fix);
1342 /* Write a value out to the object file, using the appropriate endianness. */
1344 void
1345 frv_md_number_to_chars (buf, val, n)
1346 char * buf;
1347 valueT val;
1348 int n;
1350 number_to_chars_bigendian (buf, val, n);
1353 /* Turn a string in input_line_pointer into a floating point constant of type
1354 type, and store the appropriate bytes in *litP. The number of LITTLENUMS
1355 emitted is stored in *sizeP . An error message is returned, or NULL on OK.
1358 /* Equal to MAX_PRECISION in atof-ieee.c */
1359 #define MAX_LITTLENUMS 6
1361 char *
1362 md_atof (type, litP, sizeP)
1363 char type;
1364 char * litP;
1365 int * sizeP;
1367 int i;
1368 int prec;
1369 LITTLENUM_TYPE words [MAX_LITTLENUMS];
1370 char * t;
1372 switch (type)
1374 case 'f':
1375 case 'F':
1376 case 's':
1377 case 'S':
1378 prec = 2;
1379 break;
1381 case 'd':
1382 case 'D':
1383 case 'r':
1384 case 'R':
1385 prec = 4;
1386 break;
1388 /* FIXME: Some targets allow other format chars for bigger sizes here. */
1390 default:
1391 * sizeP = 0;
1392 return _("Bad call to md_atof()");
1395 t = atof_ieee (input_line_pointer, type, words);
1396 if (t)
1397 input_line_pointer = t;
1398 * sizeP = prec * sizeof (LITTLENUM_TYPE);
1400 for (i = 0; i < prec; i++)
1402 md_number_to_chars (litP, (valueT) words[i],
1403 sizeof (LITTLENUM_TYPE));
1404 litP += sizeof (LITTLENUM_TYPE);
1407 return 0;
1410 bfd_boolean
1411 frv_fix_adjustable (fixP)
1412 fixS * fixP;
1414 bfd_reloc_code_real_type reloc_type;
1416 if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
1418 const CGEN_INSN *insn = NULL;
1419 int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
1420 const CGEN_OPERAND *operand = cgen_operand_lookup_by_num(gas_cgen_cpu_desc, opindex);
1421 reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
1423 else
1424 reloc_type = fixP->fx_r_type;
1426 /* We need the symbol name for the VTABLE entries */
1427 if ( reloc_type == BFD_RELOC_VTABLE_INHERIT
1428 || reloc_type == BFD_RELOC_VTABLE_ENTRY
1429 || reloc_type == BFD_RELOC_FRV_GPREL12
1430 || reloc_type == BFD_RELOC_FRV_GPRELU12)
1431 return 0;
1433 return 1;
1436 /* Allow user to set flags bits. */
1437 void
1438 frv_set_flags (arg)
1439 int arg ATTRIBUTE_UNUSED;
1441 flagword new_flags = get_absolute_expression ();
1442 flagword new_mask = ~ (flagword)0;
1444 frv_user_set_flags_p = 1;
1445 if (*input_line_pointer == ',')
1447 ++input_line_pointer;
1448 new_mask = get_absolute_expression ();
1451 frv_flags = (frv_flags & ~new_mask) | (new_flags & new_mask);
1452 bfd_set_private_flags (stdoutput, frv_flags);
1455 /* Frv specific function to handle 4 byte initializations for pointers that are
1456 considered 'safe' for use with pic support. Until frv_frob_file{,_section}
1457 is run, we encode it a BFD_RELOC_CTOR, and it is turned back into a normal
1458 BFD_RELOC_32 at that time. */
1460 void
1461 frv_pic_ptr (nbytes)
1462 int nbytes;
1464 expressionS exp;
1465 char *p;
1467 if (nbytes != 4)
1468 abort ();
1470 #ifdef md_flush_pending_output
1471 md_flush_pending_output ();
1472 #endif
1474 if (is_it_end_of_statement ())
1476 demand_empty_rest_of_line ();
1477 return;
1480 #ifdef md_cons_align
1481 md_cons_align (nbytes);
1482 #endif
1486 expression (&exp);
1488 p = frag_more (4);
1489 memset (p, 0, 4);
1490 fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &exp, 0,
1491 BFD_RELOC_CTOR);
1493 while (*input_line_pointer++ == ',');
1495 input_line_pointer--; /* Put terminator back into stream. */
1496 demand_empty_rest_of_line ();
1501 #ifdef DEBUG
1502 #define DPRINTF1(A) fprintf (stderr, A)
1503 #define DPRINTF2(A,B) fprintf (stderr, A, B)
1504 #define DPRINTF3(A,B,C) fprintf (stderr, A, B, C)
1506 #else
1507 #define DPRINTF1(A)
1508 #define DPRINTF2(A,B)
1509 #define DPRINTF3(A,B,C)
1510 #endif
1512 /* Go through a the sections looking for relocations that are problematical for
1513 pic. If not pic, just note that this object can't be linked with pic. If
1514 it is pic, see if it needs to be marked so that it will be fixed up, or if
1515 not possible, issue an error. */
1517 static void
1518 frv_frob_file_section (abfd, sec, ptr)
1519 bfd *abfd;
1520 asection *sec;
1521 PTR ptr ATTRIBUTE_UNUSED;
1523 segment_info_type *seginfo = seg_info (sec);
1524 fixS *fixp;
1525 CGEN_CPU_DESC cd = gas_cgen_cpu_desc;
1526 flagword flags = bfd_get_section_flags (abfd, sec);
1528 /* Skip relocations in known sections (.ctors, .dtors, and .gcc_except_table)
1529 since we can fix those up by hand. */
1530 int known_section_p = (sec->name
1531 && sec->name[0] == '.'
1532 && ((sec->name[1] == 'c'
1533 && strcmp (sec->name, ".ctor") == 0)
1534 || (sec->name[1] == 'd'
1535 && strcmp (sec->name, ".dtor") == 0)
1536 || (sec->name[1] == 'g'
1537 && strcmp (sec->name, ".gcc_except_table") == 0)));
1539 DPRINTF3 ("\nFrv section %s%s\n", sec->name, (known_section_p) ? ", known section" : "");
1540 if ((flags & SEC_ALLOC) == 0)
1542 DPRINTF1 ("\tSkipping non-loaded section\n");
1543 return;
1546 for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next)
1548 symbolS *s = fixp->fx_addsy;
1549 bfd_reloc_code_real_type reloc;
1550 int non_pic_p;
1551 int opindex;
1552 const CGEN_OPERAND *operand;
1553 const CGEN_INSN *insn = fixp->fx_cgen.insn;
1555 if (fixp->fx_done)
1557 DPRINTF1 ("\tSkipping reloc that has already been done\n");
1558 continue;
1561 if (fixp->fx_pcrel)
1563 DPRINTF1 ("\tSkipping reloc that is PC relative\n");
1564 continue;
1567 if (! s)
1569 DPRINTF1 ("\tSkipping reloc without symbol\n");
1570 continue;
1573 if (fixp->fx_r_type < BFD_RELOC_UNUSED)
1575 opindex = -1;
1576 reloc = fixp->fx_r_type;
1578 else
1580 opindex = (int) fixp->fx_r_type - (int) BFD_RELOC_UNUSED;
1581 operand = cgen_operand_lookup_by_num (cd, opindex);
1582 reloc = md_cgen_lookup_reloc (insn, operand, fixp);
1585 DPRINTF3 ("\treloc %s\t%s", bfd_get_reloc_code_name (reloc), S_GET_NAME (s));
1587 non_pic_p = 0;
1588 switch (reloc)
1590 default:
1591 break;
1593 case BFD_RELOC_32:
1594 /* Skip relocations in known sections (.ctors, .dtors, and
1595 .gcc_except_table) since we can fix those up by hand. Also
1596 skip forward references to constants. Also skip a difference
1597 of two symbols, which still uses the BFD_RELOC_32 at this
1598 point. */
1599 if (! known_section_p
1600 && S_GET_SEGMENT (s) != absolute_section
1601 && !fixp->fx_subsy
1602 && (flags & (SEC_READONLY | SEC_CODE)) == 0)
1604 non_pic_p = 1;
1606 break;
1608 /* FIXME -- should determine if any of the GP relocation really uses
1609 gr16 (which is not pic safe) or not. Right now, assume if we
1610 aren't being compiled with -mpic, the usage is non pic safe, but
1611 is safe with -mpic. */
1612 case BFD_RELOC_FRV_GPREL12:
1613 case BFD_RELOC_FRV_GPRELU12:
1614 case BFD_RELOC_FRV_GPREL32:
1615 case BFD_RELOC_FRV_GPRELHI:
1616 case BFD_RELOC_FRV_GPRELLO:
1617 non_pic_p = ! frv_pic_p;
1618 break;
1620 case BFD_RELOC_FRV_LO16:
1621 case BFD_RELOC_FRV_HI16:
1622 if (S_GET_SEGMENT (s) != absolute_section)
1623 non_pic_p = 1;
1624 break;
1626 case BFD_RELOC_VTABLE_INHERIT:
1627 case BFD_RELOC_VTABLE_ENTRY:
1628 non_pic_p = 1;
1629 break;
1631 /* If this is a blessed BFD_RELOC_32, convert it back to the normal
1632 relocation. */
1633 case BFD_RELOC_CTOR:
1634 fixp->fx_r_type = BFD_RELOC_32;
1635 break;
1638 if (non_pic_p)
1640 DPRINTF1 (" (Non-pic relocation)\n");
1641 if (frv_pic_p)
1642 as_warn_where (fixp->fx_file, fixp->fx_line,
1643 _("Relocation %s is not safe for %s"),
1644 bfd_get_reloc_code_name (reloc), frv_pic_flag);
1646 else if ((frv_flags & EF_FRV_NON_PIC_RELOCS) == 0)
1648 frv_flags |= EF_FRV_NON_PIC_RELOCS;
1649 bfd_set_private_flags (abfd, frv_flags);
1652 #ifdef DEBUG
1653 else
1654 DPRINTF1 ("\n");
1655 #endif
1659 /* After all of the symbols have been adjusted, go over the file looking
1660 for any relocations that pic won't support. */
1662 void
1663 frv_frob_file ()
1665 bfd_map_over_sections (stdoutput, frv_frob_file_section, (PTR)0);
1668 void
1669 frv_frob_label (this_label)
1670 symbolS *this_label;
1672 struct vliw_insn_list *vliw_insn_list_entry;
1674 if (frv_mach != bfd_mach_frvtomcat)
1675 return;
1677 if (now_seg != text_section)
1678 return;
1680 vliw_insn_list_entry = frv_insert_vliw_insn(DONT_COUNT);
1681 vliw_insn_list_entry->type = VLIW_LABEL_TYPE;
1682 vliw_insn_list_entry->sym = this_label;
1685 fixS *
1686 frv_cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp)
1687 fragS * frag;
1688 int where;
1689 const CGEN_INSN * insn;
1690 int length;
1691 const CGEN_OPERAND * operand;
1692 int opinfo;
1693 expressionS * exp;
1695 fixS * fixP = gas_cgen_record_fixup_exp (frag, where, insn, length,
1696 operand, opinfo, exp);
1698 if (frv_mach == bfd_mach_frvtomcat
1699 && current_vliw_insn
1700 && current_vliw_insn->type == VLIW_BRANCH_TYPE
1701 && exp != NULL)
1702 current_vliw_insn->sym = exp->X_add_symbol;
1704 return fixP;