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