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