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