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