fixes for host gcc 4.6.1
[zpugcc/jano.git] / toolchain / binutils / gas / config / tc-frv.c
blob7c802b9fe3a13ac4c4e45d7c0545139000faecf0
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 #ifdef TE_LINUX
166 # define DEFAULT_FDPIC EF_FRV_FDPIC
167 #else
168 # define DEFAULT_FDPIC 0
169 #endif
171 static unsigned long frv_mach = bfd_mach_frv;
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, "fr400") == 0)
367 cpu_flags = EF_FRV_CPU_FR400;
368 frv_mach = bfd_mach_fr400;
371 else if (strcmp (p, "fr300") == 0)
373 cpu_flags = EF_FRV_CPU_FR300;
374 frv_mach = bfd_mach_fr300;
377 else if (strcmp (p, "simple") == 0)
379 cpu_flags = EF_FRV_CPU_SIMPLE;
380 frv_mach = bfd_mach_frvsimple;
381 frv_flags |= EF_FRV_NOPACK;
384 else if (strcmp (p, "tomcat") == 0)
386 cpu_flags = EF_FRV_CPU_TOMCAT;
387 frv_mach = bfd_mach_frvtomcat;
390 else
392 as_fatal ("Unknown cpu -mcpu=%s", arg);
393 return 0;
396 frv_flags = (frv_flags & ~EF_FRV_CPU_MASK) | cpu_flags;
398 break;
400 case OPTION_PIC:
401 frv_flags |= EF_FRV_PIC;
402 frv_pic_p = 1;
403 frv_pic_flag = "-fpic";
404 break;
406 case OPTION_BIGPIC:
407 frv_flags |= EF_FRV_BIGPIC;
408 frv_pic_p = 1;
409 frv_pic_flag = "-fPIC";
410 break;
412 case OPTION_LIBPIC:
413 frv_flags |= (EF_FRV_LIBPIC | EF_FRV_G0);
414 frv_pic_p = 1;
415 frv_pic_flag = "-mlibrary-pic";
416 g_switch_value = 0;
417 break;
419 case OPTION_FDPIC:
420 frv_flags |= EF_FRV_FDPIC;
421 frv_pic_flag = "-mfdpic";
422 break;
424 case OPTION_NOPIC:
425 frv_flags &= ~(EF_FRV_FDPIC | EF_FRV_PIC
426 | EF_FRV_BIGPIC | EF_FRV_LIBPIC);
427 frv_pic_flag = 0;
428 break;
430 case OPTION_TOMCAT_DEBUG:
431 tomcat_debug = 1;
432 break;
434 case OPTION_TOMCAT_STATS:
435 tomcat_stats = 1;
436 break;
439 return 1;
442 void
443 md_show_usage (stream)
444 FILE * stream;
446 fprintf (stream, _("FRV specific command line options:\n"));
447 fprintf (stream, _("-G n Data >= n bytes is in small data area\n"));
448 fprintf (stream, _("-mgpr-32 Note 32 gprs are used\n"));
449 fprintf (stream, _("-mgpr-64 Note 64 gprs are used\n"));
450 fprintf (stream, _("-mfpr-32 Note 32 fprs are used\n"));
451 fprintf (stream, _("-mfpr-64 Note 64 fprs are used\n"));
452 fprintf (stream, _("-msoft-float Note software fp is used\n"));
453 fprintf (stream, _("-mdword Note stack is aligned to a 8 byte boundary\n"));
454 fprintf (stream, _("-mno-dword Note stack is aligned to a 4 byte boundary\n"));
455 fprintf (stream, _("-mdouble Note fp double insns are used\n"));
456 fprintf (stream, _("-mmedia Note media insns are used\n"));
457 fprintf (stream, _("-mmuladd Note multiply add/subtract insns are used\n"));
458 fprintf (stream, _("-mpack Note instructions are packed\n"));
459 fprintf (stream, _("-mno-pack Do not allow instructions to be packed\n"));
460 fprintf (stream, _("-mpic Note small position independent code\n"));
461 fprintf (stream, _("-mPIC Note large position independent code\n"));
462 fprintf (stream, _("-mlibrary-pic Compile library for large position indepedent code\n"));
463 fprintf (stream, _("-mfdpic Assemble for the FDPIC ABI\n"));
464 fprintf (stream, _("-mnopic Disable -mpic, -mPIC, -mlibrary-pic and -mfdpic\n"));
465 fprintf (stream, _("-mcpu={fr500|fr550|fr400|fr300|frv|simple|tomcat}\n"));
466 fprintf (stream, _(" Record the cpu type\n"));
467 fprintf (stream, _("-mtomcat-stats Print out stats for tomcat workarounds\n"));
468 fprintf (stream, _("-mtomcat-debug Debug tomcat workarounds\n"));
472 void
473 md_begin ()
475 /* Initialize the `cgen' interface. */
477 /* Set the machine number and endian. */
478 gas_cgen_cpu_desc = frv_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
479 CGEN_CPU_OPEN_ENDIAN,
480 CGEN_ENDIAN_BIG,
481 CGEN_CPU_OPEN_END);
482 frv_cgen_init_asm (gas_cgen_cpu_desc);
484 /* This is a callback from cgen to gas to parse operands. */
485 cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
487 /* Set the ELF flags if desired. */
488 if (frv_flags)
489 bfd_set_private_flags (stdoutput, frv_flags);
491 /* Set the machine type */
492 bfd_default_set_arch_mach (stdoutput, bfd_arch_frv, frv_mach);
494 /* Set up gp size so we can put local common items in .sbss */
495 bfd_set_gp_size (stdoutput, g_switch_value);
497 frv_vliw_reset (& vliw, frv_mach, frv_flags);
500 bfd_boolean
501 frv_md_fdpic_enabled (void)
503 return (frv_flags & EF_FRV_FDPIC) != 0;
506 int chain_num = 0;
508 struct vliw_insn_list *frv_insert_vliw_insn PARAMS ((bfd_boolean));
510 struct vliw_insn_list *
511 frv_insert_vliw_insn (count)
512 bfd_boolean count;
514 struct vliw_insn_list *vliw_insn_list_entry;
515 struct vliw_chain *vliw_chain_entry;
517 if (current_vliw_chain == NULL)
519 vliw_chain_entry = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
520 vliw_chain_entry->insn_count = 0;
521 vliw_chain_entry->insn_list = NULL;
522 vliw_chain_entry->next = NULL;
523 vliw_chain_entry->num = chain_num++;
525 if (!vliw_chain_top)
526 vliw_chain_top = vliw_chain_entry;
527 current_vliw_chain = vliw_chain_entry;
528 if (previous_vliw_chain)
529 previous_vliw_chain->next = vliw_chain_entry;
532 vliw_insn_list_entry = (struct vliw_insn_list *) xmalloc (sizeof (struct vliw_insn_list));
533 vliw_insn_list_entry->type = VLIW_GENERIC_TYPE;
534 vliw_insn_list_entry->insn = NULL;
535 vliw_insn_list_entry->sym = NULL;
536 vliw_insn_list_entry->snop_frag = NULL;
537 vliw_insn_list_entry->dnop_frag = NULL;
538 vliw_insn_list_entry->next = NULL;
540 if (count)
541 current_vliw_chain->insn_count++;
543 if (current_vliw_insn)
544 current_vliw_insn->next = vliw_insn_list_entry;
545 current_vliw_insn = vliw_insn_list_entry;
547 if (!current_vliw_chain->insn_list)
548 current_vliw_chain->insn_list = current_vliw_insn;
550 return vliw_insn_list_entry;
553 /* Identify the following cases:
555 1) A VLIW insn that contains both a branch and the branch destination.
556 This requires the insertion of two vliw instructions before the
557 branch. The first consists of two nops. The second consists of
558 a single nop.
560 2) A single instruction VLIW insn which is the destination of a branch
561 that is in the next VLIW insn. This requires the insertion of a vliw
562 insn containing two nops before the branch.
564 3) A double instruction VLIW insn which contains the destination of a
565 branch that is in the next VLIW insn. This requires the insertion of
566 a VLIW insn containing a single nop before the branch.
568 4) A single instruction VLIW insn which contains branch destination (x),
569 followed by a single instruction VLIW insn which does not contain
570 the branch to (x), followed by a VLIW insn which does contain the branch
571 to (x). This requires the insertion of a VLIW insn containing a single
572 nop before the VLIW instruction containing the branch.
575 #define FRV_IS_NOP(insn) (insn.buffer[0] == FRV_NOP_PACK || insn.buffer[0] == FRV_NOP_NOPACK)
576 #define FRV_NOP_PACK 0x00880000 /* ori.p gr0,0,gr0 */
577 #define FRV_NOP_NOPACK 0x80880000 /* ori gr0,0,gr0 */
579 /* Check a vliw insn for an insn of type containing the sym passed in label_sym. */
581 static struct vliw_insn_list *frv_find_in_vliw
582 PARAMS ((enum vliw_insn_type, struct vliw_chain *, symbolS *));
584 static struct vliw_insn_list *
585 frv_find_in_vliw (vliw_insn_type, this_chain, label_sym)
586 enum vliw_insn_type vliw_insn_type;
587 struct vliw_chain *this_chain;
588 symbolS *label_sym;
591 struct vliw_insn_list *the_insn;
593 if (!this_chain)
594 return NULL;
596 for (the_insn = this_chain->insn_list; the_insn; the_insn = the_insn->next)
598 if (the_insn->type == vliw_insn_type
599 && the_insn->sym == label_sym)
600 return the_insn;
603 return NULL;
606 enum vliw_nop_type
608 /* A Vliw insn containing a single nop insn. */
609 VLIW_SINGLE_NOP,
611 /* A Vliw insn containing two nop insns. */
612 VLIW_DOUBLE_NOP,
614 /* Two vliw insns. The first containing two nop insns.
615 The second contain a single nop insn. */
616 VLIW_DOUBLE_THEN_SINGLE_NOP
619 static void frv_debug_tomcat PARAMS ((struct vliw_chain *));
621 static void
622 frv_debug_tomcat (start_chain)
623 struct vliw_chain *start_chain;
625 struct vliw_chain *this_chain;
626 struct vliw_insn_list *this_insn;
627 int i = 1;
629 for (this_chain = start_chain; this_chain; this_chain = this_chain->next, i++)
631 fprintf (stderr, "\nVliw Insn #%d, #insns: %d\n", i, this_chain->insn_count);
633 for (this_insn = this_chain->insn_list; this_insn; this_insn = this_insn->next)
635 if (this_insn->type == VLIW_LABEL_TYPE)
636 fprintf (stderr, "Label Value: %d\n", (int) this_insn->sym);
637 else if (this_insn->type == VLIW_BRANCH_TYPE)
638 fprintf (stderr, "%s to %d\n", this_insn->insn->base->name, (int) this_insn->sym);
639 else if (this_insn->type == VLIW_BRANCH_HAS_NOPS)
640 fprintf (stderr, "nop'd %s to %d\n", this_insn->insn->base->name, (int) this_insn->sym);
641 else if (this_insn->type == VLIW_NOP_TYPE)
642 fprintf (stderr, "Nop\n");
643 else
644 fprintf (stderr, " %s\n", this_insn->insn->base->name);
649 static void frv_adjust_vliw_count PARAMS ((struct vliw_chain *));
651 static void
652 frv_adjust_vliw_count (this_chain)
653 struct vliw_chain *this_chain;
655 struct vliw_insn_list *this_insn;
657 this_chain->insn_count = 0;
659 for (this_insn = this_chain->insn_list;
660 this_insn;
661 this_insn = this_insn->next)
663 if (this_insn->type != VLIW_LABEL_TYPE)
664 this_chain->insn_count++;
669 /* Insert the desired nop combination in the vliw chain before insert_before_insn.
670 Rechain the vliw insn. */
672 static struct vliw_chain *frv_tomcat_shuffle
673 PARAMS ((enum vliw_nop_type, struct vliw_chain *, struct vliw_insn_list *));
675 static struct vliw_chain *
676 frv_tomcat_shuffle (this_nop_type, vliw_to_split, insert_before_insn)
677 enum vliw_nop_type this_nop_type;
678 struct vliw_chain *vliw_to_split;
679 struct vliw_insn_list *insert_before_insn;
682 bfd_boolean pack_prev = FALSE;
683 struct vliw_chain *return_me = NULL;
684 struct vliw_insn_list *prev_insn = NULL;
685 struct vliw_insn_list *curr_insn = vliw_to_split->insn_list;
687 struct vliw_chain *double_nop = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
688 struct vliw_chain *single_nop = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
689 struct vliw_chain *second_part = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
690 struct vliw_chain *curr_vliw = vliw_chain_top;
691 struct vliw_chain *prev_vliw = NULL;
693 while (curr_insn && curr_insn != insert_before_insn)
695 /* We can't set the packing bit on a label. If we have the case
696 label 1:
697 label 2:
698 label 3:
699 branch that needs nops
700 Then don't set pack bit later. */
702 if (curr_insn->type != VLIW_LABEL_TYPE)
703 pack_prev = TRUE;
704 prev_insn = curr_insn;
705 curr_insn = curr_insn->next;
708 while (curr_vliw && curr_vliw != vliw_to_split)
710 prev_vliw = curr_vliw;
711 curr_vliw = curr_vliw->next;
714 switch (this_nop_type)
716 case VLIW_SINGLE_NOP:
717 if (!prev_insn)
719 /* Branch is first, Insert the NOP prior to this vliw insn. */
720 if (prev_vliw)
721 prev_vliw->next = single_nop;
722 else
723 vliw_chain_top = single_nop;
724 single_nop->next = vliw_to_split;
725 vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
726 return_me = vliw_to_split;
728 else
730 /* Set the packing bit on the previous insn. */
731 if (pack_prev)
733 unsigned char *buffer = prev_insn->address;
734 buffer[0] |= 0x80;
736 /* The branch is in the middle. Split this vliw insn into first
737 and second parts. Insert the NOP inbetween. */
739 second_part->insn_list = insert_before_insn;
740 second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
741 second_part->next = vliw_to_split->next;
742 frv_adjust_vliw_count (second_part);
744 single_nop->next = second_part;
746 vliw_to_split->next = single_nop;
747 prev_insn->next = NULL;
749 return_me = second_part;
750 frv_adjust_vliw_count (vliw_to_split);
752 break;
754 case VLIW_DOUBLE_NOP:
755 if (!prev_insn)
757 /* Branch is first, Insert the NOP prior to this vliw insn. */
758 if (prev_vliw)
759 prev_vliw->next = double_nop;
760 else
761 vliw_chain_top = double_nop;
763 double_nop->next = vliw_to_split;
764 return_me = vliw_to_split;
765 vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
767 else
769 /* Set the packing bit on the previous insn. */
770 if (pack_prev)
772 unsigned char *buffer = prev_insn->address;
773 buffer[0] |= 0x80;
776 /* The branch is in the middle. Split this vliw insn into first
777 and second parts. Insert the NOP inbetween. */
778 second_part->insn_list = insert_before_insn;
779 second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
780 second_part->next = vliw_to_split->next;
781 frv_adjust_vliw_count (second_part);
783 double_nop->next = second_part;
785 vliw_to_split->next = single_nop;
786 prev_insn->next = NULL;
787 frv_adjust_vliw_count (vliw_to_split);
789 return_me = second_part;
791 break;
793 case VLIW_DOUBLE_THEN_SINGLE_NOP:
794 double_nop->next = single_nop;
795 double_nop->insn_count = 2;
796 double_nop->insn_list = &double_nop_insn;
797 single_nop->insn_count = 1;
798 single_nop->insn_list = &single_nop_insn;
800 if (!prev_insn)
802 /* The branch is the first insn in this vliw. Don't split the vliw. Insert
803 the nops prior to this vliw. */
804 if (prev_vliw)
805 prev_vliw->next = double_nop;
806 else
807 vliw_chain_top = double_nop;
809 single_nop->next = vliw_to_split;
810 return_me = vliw_to_split;
811 vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
813 else
815 /* Set the packing bit on the previous insn. */
816 if (pack_prev)
818 unsigned char *buffer = prev_insn->address;
819 buffer[0] |= 0x80;
822 /* The branch is in the middle of this vliw insn. Split into first and
823 second parts. Insert the nop vliws in between. */
824 second_part->insn_list = insert_before_insn;
825 second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
826 second_part->next = vliw_to_split->next;
827 frv_adjust_vliw_count (second_part);
829 single_nop->next = second_part;
831 vliw_to_split->next = double_nop;
832 prev_insn->next = NULL;
833 frv_adjust_vliw_count (vliw_to_split);
835 return_me = second_part;
837 break;
840 return return_me;
843 static void frv_tomcat_analyze_vliw_chains PARAMS ((void));
845 static void
846 frv_tomcat_analyze_vliw_chains ()
848 struct vliw_chain *vliw1 = NULL;
849 struct vliw_chain *vliw2 = NULL;
850 struct vliw_chain *vliw3 = NULL;
852 struct vliw_insn_list *this_insn = NULL;
853 struct vliw_insn_list *temp_insn = NULL;
855 /* We potentially need to look at three VLIW insns to determine if the
856 workaround is required. Set them up. Ignore existing nops during analysis. */
858 #define FRV_SET_VLIW_WINDOW(VLIW1, VLIW2, VLIW3) \
859 if (VLIW1 && VLIW1->next) \
860 VLIW2 = VLIW1->next; \
861 else \
862 VLIW2 = NULL; \
863 if (VLIW2 && VLIW2->next) \
864 VLIW3 = VLIW2->next; \
865 else \
866 VLIW3 = NULL
868 vliw1 = vliw_chain_top;
870 workaround_top:
872 FRV_SET_VLIW_WINDOW (vliw1, vliw2, vliw3);
874 if (!vliw1)
875 return;
877 if (vliw1->insn_count == 1)
879 /* check vliw1 for a label. */
880 if (vliw1->insn_list->type == VLIW_LABEL_TYPE)
882 temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw2, vliw1->insn_list->sym);
883 if (temp_insn)
885 vliw1 = frv_tomcat_shuffle (VLIW_DOUBLE_NOP, vliw2, vliw1->insn_list);
886 temp_insn->dnop_frag->fr_subtype = NOP_KEEP;
887 vliw1 = vliw1->next;
888 if (tomcat_stats)
889 tomcat_doubles++;
890 goto workaround_top;
892 else if (vliw2
893 && vliw2->insn_count == 1
894 && (temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw3, vliw1->insn_list->sym)) != NULL)
896 temp_insn->snop_frag->fr_subtype = NOP_KEEP;
897 vliw1 = frv_tomcat_shuffle (VLIW_SINGLE_NOP, vliw3, vliw3->insn_list);
898 if (tomcat_stats)
899 tomcat_singles++;
900 goto workaround_top;
905 if (vliw1->insn_count == 2)
907 struct vliw_insn_list *this_insn;
909 /* check vliw1 for a label. */
910 for (this_insn = vliw1->insn_list; this_insn; this_insn = this_insn->next)
912 if (this_insn->type == VLIW_LABEL_TYPE)
914 if ((temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw2, this_insn->sym)) != NULL)
916 temp_insn->snop_frag->fr_subtype = NOP_KEEP;
917 vliw1 = frv_tomcat_shuffle (VLIW_SINGLE_NOP, vliw2, this_insn);
918 if (tomcat_stats)
919 tomcat_singles++;
921 else
922 vliw1 = vliw1->next;
923 goto workaround_top;
927 /* Examine each insn in this VLIW. Look for the workaround criteria. */
928 for (this_insn = vliw1->insn_list; this_insn; this_insn = this_insn->next)
930 /* Don't look at labels or nops. */
931 while (this_insn
932 && (this_insn->type == VLIW_LABEL_TYPE
933 || this_insn->type == VLIW_NOP_TYPE
934 || this_insn->type == VLIW_BRANCH_HAS_NOPS))
935 this_insn = this_insn->next;
937 if (!this_insn)
939 vliw1 = vliw2;
940 goto workaround_top;
943 if (frv_is_branch_insn (this_insn->insn))
945 if ((temp_insn = frv_find_in_vliw (VLIW_LABEL_TYPE, vliw1, this_insn->sym)) != NULL)
947 /* Insert [nop/nop] [nop] before branch. */
948 this_insn->snop_frag->fr_subtype = NOP_KEEP;
949 this_insn->dnop_frag->fr_subtype = NOP_KEEP;
950 vliw1 = frv_tomcat_shuffle (VLIW_DOUBLE_THEN_SINGLE_NOP, vliw1, this_insn);
951 goto workaround_top;
957 /* This vliw insn checks out okay. Take a look at the next one. */
958 vliw1 = vliw1->next;
959 goto workaround_top;
962 void
963 frv_tomcat_workaround ()
965 if (frv_mach != bfd_mach_frvtomcat)
966 return;
968 if (tomcat_debug)
969 frv_debug_tomcat (vliw_chain_top);
971 frv_tomcat_analyze_vliw_chains ();
973 if (tomcat_stats)
975 fprintf (stderr, "Inserted %d Single Nops\n", tomcat_singles);
976 fprintf (stderr, "Inserted %d Double Nops\n", tomcat_doubles);
980 static int
981 fr550_check_insn_acc_range (frv_insn *insn, int low, int hi)
983 int acc;
984 switch (CGEN_INSN_NUM (insn->insn))
986 case FRV_INSN_MADDACCS:
987 case FRV_INSN_MSUBACCS:
988 case FRV_INSN_MDADDACCS:
989 case FRV_INSN_MDSUBACCS:
990 case FRV_INSN_MASACCS:
991 case FRV_INSN_MDASACCS:
992 acc = insn->fields.f_ACC40Si;
993 if (acc < low || acc > hi)
994 return 1; /* out of range */
995 acc = insn->fields.f_ACC40Sk;
996 if (acc < low || acc > hi)
997 return 1; /* out of range */
998 break;
999 case FRV_INSN_MMULHS:
1000 case FRV_INSN_MMULHU:
1001 case FRV_INSN_MMULXHS:
1002 case FRV_INSN_MMULXHU:
1003 case FRV_INSN_CMMULHS:
1004 case FRV_INSN_CMMULHU:
1005 case FRV_INSN_MQMULHS:
1006 case FRV_INSN_MQMULHU:
1007 case FRV_INSN_MQMULXHS:
1008 case FRV_INSN_MQMULXHU:
1009 case FRV_INSN_CMQMULHS:
1010 case FRV_INSN_CMQMULHU:
1011 case FRV_INSN_MMACHS:
1012 case FRV_INSN_MMRDHS:
1013 case FRV_INSN_CMMACHS:
1014 case FRV_INSN_MQMACHS:
1015 case FRV_INSN_CMQMACHS:
1016 case FRV_INSN_MQXMACHS:
1017 case FRV_INSN_MQXMACXHS:
1018 case FRV_INSN_MQMACXHS:
1019 case FRV_INSN_MCPXRS:
1020 case FRV_INSN_MCPXIS:
1021 case FRV_INSN_CMCPXRS:
1022 case FRV_INSN_CMCPXIS:
1023 case FRV_INSN_MQCPXRS:
1024 case FRV_INSN_MQCPXIS:
1025 acc = insn->fields.f_ACC40Sk;
1026 if (acc < low || acc > hi)
1027 return 1; /* out of range */
1028 break;
1029 case FRV_INSN_MMACHU:
1030 case FRV_INSN_MMRDHU:
1031 case FRV_INSN_CMMACHU:
1032 case FRV_INSN_MQMACHU:
1033 case FRV_INSN_CMQMACHU:
1034 case FRV_INSN_MCPXRU:
1035 case FRV_INSN_MCPXIU:
1036 case FRV_INSN_CMCPXRU:
1037 case FRV_INSN_CMCPXIU:
1038 case FRV_INSN_MQCPXRU:
1039 case FRV_INSN_MQCPXIU:
1040 acc = insn->fields.f_ACC40Uk;
1041 if (acc < low || acc > hi)
1042 return 1; /* out of range */
1043 break;
1044 default:
1045 break;
1047 return 0; /* all is ok */
1050 static int
1051 fr550_check_acc_range (FRV_VLIW *vliw, frv_insn *insn)
1053 switch ((*vliw->current_vliw)[vliw->next_slot - 1])
1055 case UNIT_FM0:
1056 case UNIT_FM2:
1057 return fr550_check_insn_acc_range (insn, 0, 3);
1058 case UNIT_FM1:
1059 case UNIT_FM3:
1060 return fr550_check_insn_acc_range (insn, 4, 7);
1061 default:
1062 break;
1064 return 0; /* all is ok */
1067 void
1068 md_assemble (str)
1069 char * str;
1071 frv_insn insn;
1072 char *errmsg;
1073 int packing_constraint;
1074 finished_insnS finished_insn;
1075 fragS *double_nop_frag = NULL;
1076 fragS *single_nop_frag = NULL;
1077 struct vliw_insn_list *vliw_insn_list_entry = NULL;
1079 /* Initialize GAS's cgen interface for a new instruction. */
1080 gas_cgen_init_parse ();
1082 memset (&insn, 0, sizeof (insn));
1084 insn.insn = frv_cgen_assemble_insn
1085 (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, &errmsg);
1087 if (!insn.insn)
1089 as_bad (errmsg);
1090 return;
1093 /* If the cpu is tomcat, then we need to insert nops to workaround
1094 hardware limitations. We need to keep track of each vliw unit
1095 and examine the length of the unit and the individual insns
1096 within the unit to determine the number and location of the
1097 required nops. */
1098 if (frv_mach == bfd_mach_frvtomcat)
1100 /* If we've just finished a VLIW insn OR this is a branch,
1101 then start up a new frag. Fill it with nops. We will get rid
1102 of those that are not required after we've seen all of the
1103 instructions but before we start resolving fixups. */
1104 if ( !FRV_IS_NOP (insn)
1105 && (frv_is_branch_insn (insn.insn) || insn.fields.f_pack))
1107 char *buffer;
1109 frag_wane (frag_now);
1110 frag_new (0);
1111 double_nop_frag = frag_now;
1112 buffer = frag_var (rs_machine_dependent, 8, 8, NOP_DELETE, NULL, 0, 0);
1113 md_number_to_chars (buffer, FRV_NOP_PACK, 4);
1114 md_number_to_chars (buffer+4, FRV_NOP_NOPACK, 4);
1116 frag_wane (frag_now);
1117 frag_new (0);
1118 single_nop_frag = frag_now;
1119 buffer = frag_var (rs_machine_dependent, 4, 4, NOP_DELETE, NULL, 0, 0);
1120 md_number_to_chars (buffer, FRV_NOP_NOPACK, 4);
1123 vliw_insn_list_entry = frv_insert_vliw_insn (DO_COUNT);
1124 vliw_insn_list_entry->insn = insn.insn;
1125 if (frv_is_branch_insn (insn.insn))
1126 vliw_insn_list_entry->type = VLIW_BRANCH_TYPE;
1128 if ( !FRV_IS_NOP (insn)
1129 && (frv_is_branch_insn (insn.insn) || insn.fields.f_pack))
1131 vliw_insn_list_entry->snop_frag = single_nop_frag;
1132 vliw_insn_list_entry->dnop_frag = double_nop_frag;
1136 /* Make sure that this insn does not violate the VLIW packing constraints. */
1137 /* -mno-pack disallows any packing whatsoever. */
1138 if (frv_flags & EF_FRV_NOPACK)
1140 if (! insn.fields.f_pack)
1142 as_bad (_("VLIW packing used for -mno-pack"));
1143 return;
1146 /* -mcpu=FRV is an idealized FR-V implementation that supports all of the
1147 instructions, don't do vliw checking. */
1148 else if (frv_mach != bfd_mach_frv)
1150 packing_constraint = frv_vliw_add_insn (& vliw, insn.insn);
1151 if (frv_mach == bfd_mach_fr550 && ! packing_constraint)
1152 packing_constraint = fr550_check_acc_range (& vliw, & insn);
1153 if (insn.fields.f_pack)
1154 frv_vliw_reset (& vliw, frv_mach, frv_flags);
1155 if (packing_constraint)
1157 as_bad (_("VLIW packing constraint violation"));
1158 return;
1162 /* Doesn't really matter what we pass for RELAX_P here. */
1163 gas_cgen_finish_insn (insn.insn, insn.buffer,
1164 CGEN_FIELDS_BITSIZE (& insn.fields), 1, &finished_insn);
1167 /* If the cpu is tomcat, then we need to insert nops to workaround
1168 hardware limitations. We need to keep track of each vliw unit
1169 and examine the length of the unit and the individual insns
1170 within the unit to determine the number and location of the
1171 required nops. */
1172 if (frv_mach == bfd_mach_frvtomcat)
1174 if (vliw_insn_list_entry)
1175 vliw_insn_list_entry->address = finished_insn.addr;
1176 else
1177 abort();
1179 if (insn.fields.f_pack)
1181 /* We've completed a VLIW insn. */
1182 previous_vliw_chain = current_vliw_chain;
1183 current_vliw_chain = NULL;
1184 current_vliw_insn = NULL;
1189 /* The syntax in the manual says constants begin with '#'.
1190 We just ignore it. */
1192 void
1193 md_operand (expressionP)
1194 expressionS * expressionP;
1196 if (* input_line_pointer == '#')
1198 input_line_pointer ++;
1199 expression (expressionP);
1203 valueT
1204 md_section_align (segment, size)
1205 segT segment;
1206 valueT size;
1208 int align = bfd_get_section_alignment (stdoutput, segment);
1209 return ((size + (1 << align) - 1) & (-1 << align));
1212 symbolS *
1213 md_undefined_symbol (name)
1214 char * name ATTRIBUTE_UNUSED;
1216 return 0;
1219 /* Interface to relax_segment. */
1221 /* FIXME: Build table by hand, get it working, then machine generate. */
1222 const relax_typeS md_relax_table[] =
1224 {1, 1, 0, 0},
1225 {511 - 2 - 2, -512 - 2 + 2, 0, 2 },
1226 {0x2000000 - 1 - 2, -0x2000000 - 2, 2, 0 },
1227 {0x2000000 - 1 - 2, -0x2000000 - 2, 4, 0 }
1230 long
1231 frv_relax_frag (fragP, stretch)
1232 fragS *fragP ATTRIBUTE_UNUSED;
1233 long stretch ATTRIBUTE_UNUSED;
1235 return 0;
1238 /* Return an initial guess of the length by which a fragment must grow to
1239 hold a branch to reach its destination.
1240 Also updates fr_type/fr_subtype as necessary.
1242 Called just before doing relaxation.
1243 Any symbol that is now undefined will not become defined.
1244 The guess for fr_var is ACTUALLY the growth beyond fr_fix.
1245 Whatever we do to grow fr_fix or fr_var contributes to our returned value.
1246 Although it may not be explicit in the frag, pretend fr_var starts with a
1247 0 value. */
1250 md_estimate_size_before_relax (fragP, segment)
1251 fragS * fragP;
1252 segT segment ATTRIBUTE_UNUSED;
1254 switch (fragP->fr_subtype)
1256 case NOP_KEEP:
1257 return fragP->fr_var;
1259 default:
1260 case NOP_DELETE:
1261 return 0;
1265 /* *fragP has been relaxed to its final size, and now needs to have
1266 the bytes inside it modified to conform to the new size.
1268 Called after relaxation is finished.
1269 fragP->fr_type == rs_machine_dependent.
1270 fragP->fr_subtype is the subtype of what the address relaxed to. */
1272 void
1273 md_convert_frag (abfd, sec, fragP)
1274 bfd * abfd ATTRIBUTE_UNUSED;
1275 segT sec ATTRIBUTE_UNUSED;
1276 fragS * fragP;
1278 switch (fragP->fr_subtype)
1280 default:
1281 case NOP_DELETE:
1282 return;
1284 case NOP_KEEP:
1285 fragP->fr_fix = fragP->fr_var;
1286 fragP->fr_var = 0;
1287 return;
1291 /* Functions concerning relocs. */
1293 /* The location from which a PC relative jump should be calculated,
1294 given a PC relative reloc. */
1296 long
1297 md_pcrel_from_section (fixP, sec)
1298 fixS * fixP;
1299 segT sec;
1301 if (TC_FORCE_RELOCATION (fixP)
1302 || (fixP->fx_addsy != (symbolS *) NULL
1303 && S_GET_SEGMENT (fixP->fx_addsy) != sec))
1305 /* If we can't adjust this relocation, or if it references a
1306 local symbol in a different section (which
1307 TC_FORCE_RELOCATION can't check), let the linker figure it
1308 out. */
1309 return 0;
1312 return (fixP->fx_frag->fr_address + fixP->fx_where) & ~1;
1315 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
1316 Returns BFD_RELOC_NONE if no reloc type can be found.
1317 *FIXP may be modified if desired. */
1319 bfd_reloc_code_real_type
1320 md_cgen_lookup_reloc (insn, operand, fixP)
1321 const CGEN_INSN * insn ATTRIBUTE_UNUSED;
1322 const CGEN_OPERAND * operand;
1323 fixS * fixP;
1325 switch (operand->type)
1327 case FRV_OPERAND_LABEL16:
1328 fixP->fx_pcrel = TRUE;
1329 return BFD_RELOC_FRV_LABEL16;
1331 case FRV_OPERAND_LABEL24:
1332 fixP->fx_pcrel = TRUE;
1333 return BFD_RELOC_FRV_LABEL24;
1335 case FRV_OPERAND_UHI16:
1336 case FRV_OPERAND_ULO16:
1337 case FRV_OPERAND_SLO16:
1339 /* The relocation type should be recorded in opinfo */
1340 if (fixP->fx_cgen.opinfo != 0)
1341 return fixP->fx_cgen.opinfo;
1342 break;
1344 case FRV_OPERAND_D12:
1345 case FRV_OPERAND_S12:
1346 if (fixP->fx_cgen.opinfo != 0)
1347 return fixP->fx_cgen.opinfo;
1349 return BFD_RELOC_FRV_GPREL12;
1351 case FRV_OPERAND_U12:
1352 return BFD_RELOC_FRV_GPRELU12;
1354 default:
1355 break;
1357 return BFD_RELOC_NONE;
1361 /* See whether we need to force a relocation into the output file.
1362 This is used to force out switch and PC relative relocations when
1363 relaxing. */
1366 frv_force_relocation (fix)
1367 fixS * fix;
1369 if (fix->fx_r_type == BFD_RELOC_FRV_GPREL12
1370 || fix->fx_r_type == BFD_RELOC_FRV_GPRELU12)
1371 return 1;
1373 return generic_force_reloc (fix);
1376 /* Apply a fixup that could be resolved within the assembler. */
1378 void
1379 md_apply_fix3 (fixP, valP, seg)
1380 fixS * fixP;
1381 valueT * valP;
1382 segT seg;
1384 if (fixP->fx_addsy == 0)
1385 switch (fixP->fx_cgen.opinfo)
1387 case BFD_RELOC_FRV_HI16:
1388 *valP >>= 16;
1389 /* Fall through. */
1390 case BFD_RELOC_FRV_LO16:
1391 *valP &= 0xffff;
1392 break;
1395 gas_cgen_md_apply_fix3 (fixP, valP, seg);
1396 return;
1400 /* Write a value out to the object file, using the appropriate endianness. */
1402 void
1403 frv_md_number_to_chars (buf, val, n)
1404 char * buf;
1405 valueT val;
1406 int n;
1408 number_to_chars_bigendian (buf, val, n);
1411 /* Turn a string in input_line_pointer into a floating point constant of type
1412 type, and store the appropriate bytes in *litP. The number of LITTLENUMS
1413 emitted is stored in *sizeP . An error message is returned, or NULL on OK.
1416 /* Equal to MAX_PRECISION in atof-ieee.c */
1417 #define MAX_LITTLENUMS 6
1419 char *
1420 md_atof (type, litP, sizeP)
1421 char type;
1422 char * litP;
1423 int * sizeP;
1425 int i;
1426 int prec;
1427 LITTLENUM_TYPE words [MAX_LITTLENUMS];
1428 char * t;
1430 switch (type)
1432 case 'f':
1433 case 'F':
1434 case 's':
1435 case 'S':
1436 prec = 2;
1437 break;
1439 case 'd':
1440 case 'D':
1441 case 'r':
1442 case 'R':
1443 prec = 4;
1444 break;
1446 /* FIXME: Some targets allow other format chars for bigger sizes here. */
1448 default:
1449 * sizeP = 0;
1450 return _("Bad call to md_atof()");
1453 t = atof_ieee (input_line_pointer, type, words);
1454 if (t)
1455 input_line_pointer = t;
1456 * sizeP = prec * sizeof (LITTLENUM_TYPE);
1458 for (i = 0; i < prec; i++)
1460 md_number_to_chars (litP, (valueT) words[i],
1461 sizeof (LITTLENUM_TYPE));
1462 litP += sizeof (LITTLENUM_TYPE);
1465 return 0;
1468 bfd_boolean
1469 frv_fix_adjustable (fixP)
1470 fixS * fixP;
1472 bfd_reloc_code_real_type reloc_type;
1474 if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
1476 const CGEN_INSN *insn = NULL;
1477 int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
1478 const CGEN_OPERAND *operand = cgen_operand_lookup_by_num(gas_cgen_cpu_desc, opindex);
1479 reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
1481 else
1482 reloc_type = fixP->fx_r_type;
1484 /* We need the symbol name for the VTABLE entries */
1485 if ( reloc_type == BFD_RELOC_VTABLE_INHERIT
1486 || reloc_type == BFD_RELOC_VTABLE_ENTRY
1487 || reloc_type == BFD_RELOC_FRV_GPREL12
1488 || reloc_type == BFD_RELOC_FRV_GPRELU12)
1489 return 0;
1491 return 1;
1494 /* Allow user to set flags bits. */
1495 void
1496 frv_set_flags (arg)
1497 int arg ATTRIBUTE_UNUSED;
1499 flagword new_flags = get_absolute_expression ();
1500 flagword new_mask = ~ (flagword)0;
1502 frv_user_set_flags_p = 1;
1503 if (*input_line_pointer == ',')
1505 ++input_line_pointer;
1506 new_mask = get_absolute_expression ();
1509 frv_flags = (frv_flags & ~new_mask) | (new_flags & new_mask);
1510 bfd_set_private_flags (stdoutput, frv_flags);
1513 /* Frv specific function to handle 4 byte initializations for pointers that are
1514 considered 'safe' for use with pic support. Until frv_frob_file{,_section}
1515 is run, we encode it a BFD_RELOC_CTOR, and it is turned back into a normal
1516 BFD_RELOC_32 at that time. */
1518 void
1519 frv_pic_ptr (nbytes)
1520 int nbytes;
1522 expressionS exp;
1523 char *p;
1525 if (nbytes != 4)
1526 abort ();
1528 #ifdef md_flush_pending_output
1529 md_flush_pending_output ();
1530 #endif
1532 if (is_it_end_of_statement ())
1534 demand_empty_rest_of_line ();
1535 return;
1538 #ifdef md_cons_align
1539 md_cons_align (nbytes);
1540 #endif
1544 bfd_reloc_code_real_type reloc_type = BFD_RELOC_CTOR;
1546 if (strncasecmp (input_line_pointer, "funcdesc(", 9) == 0)
1548 input_line_pointer += 9;
1549 expression (&exp);
1550 if (*input_line_pointer == ')')
1551 input_line_pointer++;
1552 else
1553 as_bad ("missing ')'");
1554 reloc_type = BFD_RELOC_FRV_FUNCDESC;
1556 else
1557 expression (&exp);
1559 p = frag_more (4);
1560 memset (p, 0, 4);
1561 fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &exp, 0,
1562 reloc_type);
1564 while (*input_line_pointer++ == ',');
1566 input_line_pointer--; /* Put terminator back into stream. */
1567 demand_empty_rest_of_line ();
1572 #ifdef DEBUG
1573 #define DPRINTF1(A) fprintf (stderr, A)
1574 #define DPRINTF2(A,B) fprintf (stderr, A, B)
1575 #define DPRINTF3(A,B,C) fprintf (stderr, A, B, C)
1577 #else
1578 #define DPRINTF1(A)
1579 #define DPRINTF2(A,B)
1580 #define DPRINTF3(A,B,C)
1581 #endif
1583 /* Go through a the sections looking for relocations that are problematical for
1584 pic. If not pic, just note that this object can't be linked with pic. If
1585 it is pic, see if it needs to be marked so that it will be fixed up, or if
1586 not possible, issue an error. */
1588 static void
1589 frv_frob_file_section (abfd, sec, ptr)
1590 bfd *abfd;
1591 asection *sec;
1592 PTR ptr ATTRIBUTE_UNUSED;
1594 segment_info_type *seginfo = seg_info (sec);
1595 fixS *fixp;
1596 CGEN_CPU_DESC cd = gas_cgen_cpu_desc;
1597 flagword flags = bfd_get_section_flags (abfd, sec);
1599 /* Skip relocations in known sections (.ctors, .dtors, and .gcc_except_table)
1600 since we can fix those up by hand. */
1601 int known_section_p = (sec->name
1602 && sec->name[0] == '.'
1603 && ((sec->name[1] == 'c'
1604 && strcmp (sec->name, ".ctor") == 0)
1605 || (sec->name[1] == 'd'
1606 && strcmp (sec->name, ".dtor") == 0)
1607 || (sec->name[1] == 'g'
1608 && strcmp (sec->name, ".gcc_except_table") == 0)));
1610 DPRINTF3 ("\nFrv section %s%s\n", sec->name, (known_section_p) ? ", known section" : "");
1611 if ((flags & SEC_ALLOC) == 0)
1613 DPRINTF1 ("\tSkipping non-loaded section\n");
1614 return;
1617 for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next)
1619 symbolS *s = fixp->fx_addsy;
1620 bfd_reloc_code_real_type reloc;
1621 int non_pic_p;
1622 int opindex;
1623 const CGEN_OPERAND *operand;
1624 const CGEN_INSN *insn = fixp->fx_cgen.insn;
1626 if (fixp->fx_done)
1628 DPRINTF1 ("\tSkipping reloc that has already been done\n");
1629 continue;
1632 if (fixp->fx_pcrel)
1634 DPRINTF1 ("\tSkipping reloc that is PC relative\n");
1635 continue;
1638 if (! s)
1640 DPRINTF1 ("\tSkipping reloc without symbol\n");
1641 continue;
1644 if (fixp->fx_r_type < BFD_RELOC_UNUSED)
1646 opindex = -1;
1647 reloc = fixp->fx_r_type;
1649 else
1651 opindex = (int) fixp->fx_r_type - (int) BFD_RELOC_UNUSED;
1652 operand = cgen_operand_lookup_by_num (cd, opindex);
1653 reloc = md_cgen_lookup_reloc (insn, operand, fixp);
1656 DPRINTF3 ("\treloc %s\t%s", bfd_get_reloc_code_name (reloc), S_GET_NAME (s));
1658 non_pic_p = 0;
1659 switch (reloc)
1661 default:
1662 break;
1664 case BFD_RELOC_32:
1665 /* Skip relocations in known sections (.ctors, .dtors, and
1666 .gcc_except_table) since we can fix those up by hand. Also
1667 skip forward references to constants. Also skip a difference
1668 of two symbols, which still uses the BFD_RELOC_32 at this
1669 point. */
1670 if (! known_section_p
1671 && S_GET_SEGMENT (s) != absolute_section
1672 && !fixp->fx_subsy
1673 && (flags & (SEC_READONLY | SEC_CODE)) == 0)
1675 non_pic_p = 1;
1677 break;
1679 /* FIXME -- should determine if any of the GP relocation really uses
1680 gr16 (which is not pic safe) or not. Right now, assume if we
1681 aren't being compiled with -mpic, the usage is non pic safe, but
1682 is safe with -mpic. */
1683 case BFD_RELOC_FRV_GPREL12:
1684 case BFD_RELOC_FRV_GPRELU12:
1685 case BFD_RELOC_FRV_GPREL32:
1686 case BFD_RELOC_FRV_GPRELHI:
1687 case BFD_RELOC_FRV_GPRELLO:
1688 non_pic_p = ! frv_pic_p;
1689 break;
1691 case BFD_RELOC_FRV_LO16:
1692 case BFD_RELOC_FRV_HI16:
1693 if (S_GET_SEGMENT (s) != absolute_section)
1694 non_pic_p = 1;
1695 break;
1697 case BFD_RELOC_VTABLE_INHERIT:
1698 case BFD_RELOC_VTABLE_ENTRY:
1699 non_pic_p = 1;
1700 break;
1702 /* If this is a blessed BFD_RELOC_32, convert it back to the normal
1703 relocation. */
1704 case BFD_RELOC_CTOR:
1705 fixp->fx_r_type = BFD_RELOC_32;
1706 break;
1709 if (non_pic_p)
1711 DPRINTF1 (" (Non-pic relocation)\n");
1712 if (frv_pic_p)
1713 as_warn_where (fixp->fx_file, fixp->fx_line,
1714 _("Relocation %s is not safe for %s"),
1715 bfd_get_reloc_code_name (reloc), frv_pic_flag);
1717 else if ((frv_flags & EF_FRV_NON_PIC_RELOCS) == 0)
1719 frv_flags |= EF_FRV_NON_PIC_RELOCS;
1720 bfd_set_private_flags (abfd, frv_flags);
1723 #ifdef DEBUG
1724 else
1725 DPRINTF1 ("\n");
1726 #endif
1730 /* After all of the symbols have been adjusted, go over the file looking
1731 for any relocations that pic won't support. */
1733 void
1734 frv_frob_file ()
1736 bfd_map_over_sections (stdoutput, frv_frob_file_section, (PTR)0);
1739 void
1740 frv_frob_label (this_label)
1741 symbolS *this_label;
1743 struct vliw_insn_list *vliw_insn_list_entry;
1745 if (frv_mach != bfd_mach_frvtomcat)
1746 return;
1748 if (now_seg != text_section)
1749 return;
1751 vliw_insn_list_entry = frv_insert_vliw_insn(DONT_COUNT);
1752 vliw_insn_list_entry->type = VLIW_LABEL_TYPE;
1753 vliw_insn_list_entry->sym = this_label;
1756 fixS *
1757 frv_cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp)
1758 fragS * frag;
1759 int where;
1760 const CGEN_INSN * insn;
1761 int length;
1762 const CGEN_OPERAND * operand;
1763 int opinfo;
1764 expressionS * exp;
1766 fixS * fixP = gas_cgen_record_fixup_exp (frag, where, insn, length,
1767 operand, opinfo, exp);
1769 if (frv_mach == bfd_mach_frvtomcat
1770 && current_vliw_insn
1771 && current_vliw_insn->type == VLIW_BRANCH_TYPE
1772 && exp != NULL)
1773 current_vliw_insn->sym = exp->X_add_symbol;
1775 return fixP;