tc-frv.c revision 1.1.1.4.12.1 1 /* tc-frv.c -- Assembler for the Fujitsu FRV.
2 Copyright (C) 2002-2018 Free Software Foundation, Inc.
3
4 This file is part of GAS, the GNU Assembler.
5
6 GAS is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
10
11 GAS is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GAS; see the file COPYING. If not, write to
18 the Free Software Foundation, 51 Franklin Street - Fifth Floor,
19 Boston, MA 02110-1301, USA. */
20
21 #include "as.h"
22 #include "subsegs.h"
23 #include "symcat.h"
24 #include "opcodes/frv-desc.h"
25 #include "opcodes/frv-opc.h"
26 #include "cgen.h"
27 #include "elf/common.h"
28 #include "elf/frv.h"
29 #include "dwarf2dbg.h"
30
31 /* Structure to hold all of the different components describing
32 an individual instruction. */
33 typedef struct
34 {
35 const CGEN_INSN * insn;
36 const CGEN_INSN * orig_insn;
37 CGEN_FIELDS fields;
38 #if CGEN_INT_INSN_P
39 CGEN_INSN_INT buffer [1];
40 #define INSN_VALUE(buf) (*(buf))
41 #else
42 unsigned char buffer [CGEN_MAX_INSN_SIZE];
43 #define INSN_VALUE(buf) (buf)
44 #endif
45 char * addr;
46 fragS * frag;
47 int num_fixups;
48 fixS * fixups [GAS_CGEN_MAX_FIXUPS];
49 int indices [MAX_OPERAND_INSTANCES];
50 }
51 frv_insn;
52
53 enum vliw_insn_type
54 {
55 VLIW_GENERIC_TYPE, /* Don't care about this insn. */
56 VLIW_BRANCH_TYPE, /* A Branch. */
57 VLIW_LABEL_TYPE, /* A Label. */
58 VLIW_NOP_TYPE, /* A NOP. */
59 VLIW_BRANCH_HAS_NOPS /* A Branch that requires NOPS. */
60 };
61
62 /* We're going to use these in the fr_subtype field to mark
63 whether to keep inserted nops. */
64
65 #define NOP_KEEP 1 /* Keep these NOPS. */
66 #define NOP_DELETE 2 /* Delete these NOPS. */
67
68 #define DO_COUNT TRUE
69 #define DONT_COUNT FALSE
70
71 /* A list of insns within a VLIW insn. */
72 struct vliw_insn_list
73 {
74 /* The type of this insn. */
75 enum vliw_insn_type type;
76
77 /* The corresponding gas insn information. */
78 const CGEN_INSN *insn;
79
80 /* For branches and labels, the symbol that is referenced. */
81 symbolS *sym;
82
83 /* For branches, the frag containing the single nop that was generated. */
84 fragS *snop_frag;
85
86 /* For branches, the frag containing the double nop that was generated. */
87 fragS *dnop_frag;
88
89 /* Pointer to raw data for this insn. */
90 char *address;
91
92 /* Next insn in list. */
93 struct vliw_insn_list *next;
94 };
95
96 static struct vliw_insn_list single_nop_insn = {
97 VLIW_NOP_TYPE, NULL, NULL, NULL, NULL, NULL, NULL };
98
99 static struct vliw_insn_list double_nop_insn = {
100 VLIW_NOP_TYPE, NULL, NULL, NULL, NULL, NULL, NULL };
101
102 struct vliw_chain
103 {
104 int num;
105 int insn_count;
106 struct vliw_insn_list *insn_list;
107 struct vliw_chain *next;
108 };
109
110 static struct vliw_chain *vliw_chain_top;
111 static struct vliw_chain *current_vliw_chain;
112 static struct vliw_chain *previous_vliw_chain;
113 static struct vliw_insn_list *current_vliw_insn;
114
115 const char comment_chars[] = ";";
116 const char line_comment_chars[] = "#";
117 const char line_separator_chars[] = "!";
118 const char EXP_CHARS[] = "eE";
119 const char FLT_CHARS[] = "dD";
120
121 static FRV_VLIW vliw;
122
123 /* Default machine */
124
125 #ifdef DEFAULT_CPU_FRV
126 #define DEFAULT_MACHINE bfd_mach_frv
127 #define DEFAULT_FLAGS EF_FRV_CPU_GENERIC
128
129 #else
130 #ifdef DEFAULT_CPU_FR300
131 #define DEFAULT_MACHINE bfd_mach_fr300
132 #define DEFAULT_FLAGS EF_FRV_CPU_FR300
133
134 #else
135 #ifdef DEFAULT_CPU_SIMPLE
136 #define DEFAULT_MACHINE bfd_mach_frvsimple
137 #define DEFAULT_FLAGS EF_FRV_CPU_SIMPLE
138
139 #else
140 #ifdef DEFAULT_CPU_TOMCAT
141 #define DEFAULT_MACHINE bfd_mach_frvtomcat
142 #define DEFAULT_FLAGS EF_FRV_CPU_TOMCAT
143
144 #else
145 #ifdef DEFAULT_CPU_FR400
146 #define DEFAULT_MACHINE bfd_mach_fr400
147 #define DEFAULT_FLAGS EF_FRV_CPU_FR400
148
149 #else
150 #ifdef DEFAULT_CPU_FR550
151 #define DEFAULT_MACHINE bfd_mach_fr550
152 #define DEFAULT_FLAGS EF_FRV_CPU_FR550
153
154 #else
155 #define DEFAULT_MACHINE bfd_mach_fr500
156 #define DEFAULT_FLAGS EF_FRV_CPU_FR500
157 #endif
158 #endif
159 #endif
160 #endif
161 #endif
162 #endif
163
164 #ifdef TE_LINUX
165 # define DEFAULT_FDPIC EF_FRV_FDPIC
166 #else
167 # define DEFAULT_FDPIC 0
168 #endif
169
170 static unsigned long frv_mach = bfd_mach_frv;
171 static bfd_boolean fr400_audio;
172
173 /* Flags to set in the elf header */
174 static flagword frv_flags = DEFAULT_FLAGS | DEFAULT_FDPIC;
175
176 static int frv_user_set_flags_p = 0;
177 static int frv_pic_p = 0;
178 static const char *frv_pic_flag = DEFAULT_FDPIC ? "-mfdpic" : (const char *)0;
179
180 /* Print tomcat-specific debugging info. */
181 static int tomcat_debug = 0;
182
183 /* Tomcat-specific NOP statistics. */
184 static int tomcat_stats = 0;
185 static int tomcat_doubles = 0;
186 static int tomcat_singles = 0;
187
188 /* Forward reference to static functions */
189 static void frv_set_flags (int);
190 static void frv_pic_ptr (int);
191
192 /* The target specific pseudo-ops which we support. */
193 const pseudo_typeS md_pseudo_table[] =
194 {
195 { "eflags", frv_set_flags, 0 },
196 { "word", cons, 4 },
197 { "picptr", frv_pic_ptr, 4 },
198 { NULL, NULL, 0 }
199 };
200
201
202 #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, const 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 const 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 independent 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
483 void
485 md_begin (void)
486 {
487 /* Initialize the `cgen' interface. */
488
489 /* Set the machine number and endian. */
490 gas_cgen_cpu_desc = frv_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
491 CGEN_CPU_OPEN_ENDIAN,
492 CGEN_ENDIAN_BIG,
493 CGEN_CPU_OPEN_END);
494 frv_cgen_init_asm (gas_cgen_cpu_desc);
495
496 /* This is a callback from cgen to gas to parse operands. */
497 cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
498
499 /* Set the ELF flags if desired. */
500 if (frv_flags)
501 bfd_set_private_flags (stdoutput, frv_flags);
502
503 /* Set the machine type */
504 bfd_default_set_arch_mach (stdoutput, bfd_arch_frv, frv_mach);
505
506 /* Set up gp size so we can put local common items in .sbss */
507 bfd_set_gp_size (stdoutput, g_switch_value);
508
509 frv_vliw_reset (& vliw, frv_mach, frv_flags);
510 }
511
512 bfd_boolean
513 frv_md_fdpic_enabled (void)
514 {
515 return (frv_flags & EF_FRV_FDPIC) != 0;
516 }
517
518 int chain_num = 0;
519
520 static struct vliw_insn_list *
521 frv_insert_vliw_insn (bfd_boolean count)
522 {
523 struct vliw_insn_list *vliw_insn_list_entry;
524 struct vliw_chain *vliw_chain_entry;
525
526 if (current_vliw_chain == NULL)
527 {
528 vliw_chain_entry = XNEW (struct vliw_chain);
529 vliw_chain_entry->insn_count = 0;
530 vliw_chain_entry->insn_list = NULL;
531 vliw_chain_entry->next = NULL;
532 vliw_chain_entry->num = chain_num++;
533
534 if (!vliw_chain_top)
535 vliw_chain_top = vliw_chain_entry;
536 current_vliw_chain = vliw_chain_entry;
537 if (previous_vliw_chain)
538 previous_vliw_chain->next = vliw_chain_entry;
539 }
540
541 vliw_insn_list_entry = XNEW (struct vliw_insn_list);
542 vliw_insn_list_entry->type = VLIW_GENERIC_TYPE;
543 vliw_insn_list_entry->insn = NULL;
544 vliw_insn_list_entry->sym = NULL;
545 vliw_insn_list_entry->snop_frag = NULL;
546 vliw_insn_list_entry->dnop_frag = NULL;
547 vliw_insn_list_entry->next = NULL;
548
549 if (count)
550 current_vliw_chain->insn_count++;
551
552 if (current_vliw_insn)
553 current_vliw_insn->next = vliw_insn_list_entry;
554 current_vliw_insn = vliw_insn_list_entry;
555
556 if (!current_vliw_chain->insn_list)
557 current_vliw_chain->insn_list = current_vliw_insn;
558
559 return vliw_insn_list_entry;
560 }
561
562 /* Identify the following cases:
563
564 1) A VLIW insn that contains both a branch and the branch destination.
565 This requires the insertion of two vliw instructions before the
566 branch. The first consists of two nops. The second consists of
567 a single nop.
568
569 2) A single instruction VLIW insn which is the destination of a branch
570 that is in the next VLIW insn. This requires the insertion of a vliw
571 insn containing two nops before the branch.
572
573 3) A double instruction VLIW insn which contains the destination of a
574 branch that is in the next VLIW insn. This requires the insertion of
575 a VLIW insn containing a single nop before the branch.
576
577 4) A single instruction VLIW insn which contains branch destination (x),
578 followed by a single instruction VLIW insn which does not contain
579 the branch to (x), followed by a VLIW insn which does contain the branch
580 to (x). This requires the insertion of a VLIW insn containing a single
581 nop before the VLIW instruction containing the branch.
582
583 */
584 #define FRV_IS_NOP(insn) (insn.buffer[0] == FRV_NOP_PACK || insn.buffer[0] == FRV_NOP_NOPACK)
585 #define FRV_NOP_PACK 0x00880000 /* ori.p gr0,0,gr0 */
586 #define FRV_NOP_NOPACK 0x80880000 /* ori gr0,0,gr0 */
587
588 /* Check a vliw insn for an insn of type containing the sym passed in label_sym. */
589
590 static struct vliw_insn_list *
591 frv_find_in_vliw (enum vliw_insn_type vliw_insn_type,
592 struct vliw_chain *this_chain,
593 symbolS *label_sym)
594 {
595
596 struct vliw_insn_list *the_insn;
597
598 if (!this_chain)
599 return NULL;
600
601 for (the_insn = this_chain->insn_list; the_insn; the_insn = the_insn->next)
602 {
603 if (the_insn->type == vliw_insn_type
604 && the_insn->sym == label_sym)
605 return the_insn;
606 }
607
608 return NULL;
609 }
610
611 enum vliw_nop_type
612 {
613 /* A Vliw insn containing a single nop insn. */
614 VLIW_SINGLE_NOP,
615
616 /* A Vliw insn containing two nop insns. */
617 VLIW_DOUBLE_NOP,
618
619 /* Two vliw insns. The first containing two nop insns.
620 The second contain a single nop insn. */
621 VLIW_DOUBLE_THEN_SINGLE_NOP
622 };
623
624 static void
625 frv_debug_tomcat (struct vliw_chain *start_chain)
626 {
627 struct vliw_chain *this_chain;
628 struct vliw_insn_list *this_insn;
629 int i = 1;
630
631 for (this_chain = start_chain; this_chain; this_chain = this_chain->next, i++)
632 {
633 fprintf (stderr, "\nVliw Insn #%d, #insns: %d\n", i, this_chain->insn_count);
634
635 for (this_insn = this_chain->insn_list; this_insn; this_insn = this_insn->next)
636 {
637 if (this_insn->type == VLIW_LABEL_TYPE)
638 fprintf (stderr, "Label Value: %p\n", this_insn->sym);
639 else if (this_insn->type == VLIW_BRANCH_TYPE)
640 fprintf (stderr, "%s to %p\n", this_insn->insn->base->name, this_insn->sym);
641 else if (this_insn->type == VLIW_BRANCH_HAS_NOPS)
642 fprintf (stderr, "nop'd %s to %p\n", this_insn->insn->base->name, this_insn->sym);
643 else if (this_insn->type == VLIW_NOP_TYPE)
644 fprintf (stderr, "Nop\n");
645 else
646 fprintf (stderr, " %s\n", this_insn->insn->base->name);
647 }
648 }
649 }
650
651 static void
652 frv_adjust_vliw_count (struct vliw_chain *this_chain)
653 {
654 struct vliw_insn_list *this_insn;
655
656 this_chain->insn_count = 0;
657
658 for (this_insn = this_chain->insn_list;
659 this_insn;
660 this_insn = this_insn->next)
661 {
662 if (this_insn->type != VLIW_LABEL_TYPE)
663 this_chain->insn_count++;
664 }
665
666 }
667
668 /* Insert the desired nop combination in the vliw chain before insert_before_insn.
669 Rechain the vliw insn. */
670
671 static struct vliw_chain *
672 frv_tomcat_shuffle (enum vliw_nop_type this_nop_type,
673 struct vliw_chain *vliw_to_split,
674 struct vliw_insn_list *insert_before_insn)
675 {
676
677 bfd_boolean pack_prev = FALSE;
678 struct vliw_chain *return_me = NULL;
679 struct vliw_insn_list *prev_insn = NULL;
680 struct vliw_insn_list *curr_insn = vliw_to_split->insn_list;
681
682 struct vliw_chain *double_nop = XNEW (struct vliw_chain);
683 struct vliw_chain *single_nop = XNEW (struct vliw_chain);
684 struct vliw_chain *second_part = XNEW (struct vliw_chain);
685 struct vliw_chain *curr_vliw = vliw_chain_top;
686 struct vliw_chain *prev_vliw = NULL;
687
688 while (curr_insn && curr_insn != insert_before_insn)
689 {
690 /* We can't set the packing bit on a label. If we have the case
691 label 1:
692 label 2:
693 label 3:
694 branch that needs nops
695 Then don't set pack bit later. */
696
697 if (curr_insn->type != VLIW_LABEL_TYPE)
698 pack_prev = TRUE;
699 prev_insn = curr_insn;
700 curr_insn = curr_insn->next;
701 }
702
703 while (curr_vliw && curr_vliw != vliw_to_split)
704 {
705 prev_vliw = curr_vliw;
706 curr_vliw = curr_vliw->next;
707 }
708
709 switch (this_nop_type)
710 {
711 case VLIW_SINGLE_NOP:
712 if (!prev_insn)
713 {
714 /* Branch is first, Insert the NOP prior to this vliw insn. */
715 if (prev_vliw)
716 prev_vliw->next = single_nop;
717 else
718 vliw_chain_top = single_nop;
719 single_nop->next = vliw_to_split;
720 vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
721 return_me = vliw_to_split;
722 }
723 else
724 {
725 /* Set the packing bit on the previous insn. */
726 if (pack_prev)
727 {
728 char *buffer = prev_insn->address;
729 buffer[0] |= 0x80;
730 }
731 /* The branch is in the middle. Split this vliw insn into first
732 and second parts. Insert the NOP between. */
733
734 second_part->insn_list = insert_before_insn;
735 second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
736 second_part->next = vliw_to_split->next;
737 frv_adjust_vliw_count (second_part);
738
739 single_nop->next = second_part;
740
741 vliw_to_split->next = single_nop;
742 prev_insn->next = NULL;
743
744 return_me = second_part;
745 frv_adjust_vliw_count (vliw_to_split);
746 }
747 break;
748
749 case VLIW_DOUBLE_NOP:
750 if (!prev_insn)
751 {
752 /* Branch is first, Insert the NOP prior to this vliw insn. */
753 if (prev_vliw)
754 prev_vliw->next = double_nop;
755 else
756 vliw_chain_top = double_nop;
757
758 double_nop->next = vliw_to_split;
759 return_me = vliw_to_split;
760 vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
761 }
762 else
763 {
764 /* Set the packing bit on the previous insn. */
765 if (pack_prev)
766 {
767 char *buffer = prev_insn->address;
768 buffer[0] |= 0x80;
769 }
770
771 /* The branch is in the middle. Split this vliw insn into first
772 and second parts. Insert the NOP in between. */
773 second_part->insn_list = insert_before_insn;
774 second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
775 second_part->next = vliw_to_split->next;
776 frv_adjust_vliw_count (second_part);
777
778 double_nop->next = second_part;
779
780 vliw_to_split->next = single_nop;
781 prev_insn->next = NULL;
782 frv_adjust_vliw_count (vliw_to_split);
783
784 return_me = second_part;
785 }
786 break;
787
788 case VLIW_DOUBLE_THEN_SINGLE_NOP:
789 double_nop->next = single_nop;
790 double_nop->insn_count = 2;
791 double_nop->insn_list = &double_nop_insn;
792 single_nop->insn_count = 1;
793 single_nop->insn_list = &single_nop_insn;
794
795 if (!prev_insn)
796 {
797 /* The branch is the first insn in this vliw. Don't split the vliw. Insert
798 the nops prior to this vliw. */
799 if (prev_vliw)
800 prev_vliw->next = double_nop;
801 else
802 vliw_chain_top = double_nop;
803
804 single_nop->next = vliw_to_split;
805 return_me = vliw_to_split;
806 vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
807 }
808 else
809 {
810 /* Set the packing bit on the previous insn. */
811 if (pack_prev)
812 {
813 char *buffer = prev_insn->address;
814 buffer[0] |= 0x80;
815 }
816
817 /* The branch is in the middle of this vliw insn. Split into first and
818 second parts. Insert the nop vliws in between. */
819 second_part->insn_list = insert_before_insn;
820 second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
821 second_part->next = vliw_to_split->next;
822 frv_adjust_vliw_count (second_part);
823
824 single_nop->next = second_part;
825
826 vliw_to_split->next = double_nop;
827 prev_insn->next = NULL;
828 frv_adjust_vliw_count (vliw_to_split);
829
830 return_me = second_part;
831 }
832 break;
833 }
834
835 return return_me;
836 }
837
838 static void
839 frv_tomcat_analyze_vliw_chains (void)
840 {
841 struct vliw_chain *vliw1 = NULL;
842 struct vliw_chain *vliw2 = NULL;
843 struct vliw_chain *vliw3 = NULL;
844
845 struct vliw_insn_list *this_insn = NULL;
846 struct vliw_insn_list *temp_insn = NULL;
847
848 /* We potentially need to look at three VLIW insns to determine if the
849 workaround is required. Set them up. Ignore existing nops during analysis. */
850
851 #define FRV_SET_VLIW_WINDOW(VLIW1, VLIW2, VLIW3) \
852 if (VLIW1 && VLIW1->next) \
853 VLIW2 = VLIW1->next; \
854 else \
855 VLIW2 = NULL; \
856 if (VLIW2 && VLIW2->next) \
857 VLIW3 = VLIW2->next; \
858 else \
859 VLIW3 = NULL
860
861 vliw1 = vliw_chain_top;
862
863 workaround_top:
864
865 FRV_SET_VLIW_WINDOW (vliw1, vliw2, vliw3);
866
867 if (!vliw1)
868 return;
869
870 if (vliw1->insn_count == 1)
871 {
872 /* check vliw1 for a label. */
873 if (vliw1->insn_list->type == VLIW_LABEL_TYPE)
874 {
875 temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw2, vliw1->insn_list->sym);
876 if (temp_insn)
877 {
878 vliw1 = frv_tomcat_shuffle (VLIW_DOUBLE_NOP, vliw2, vliw1->insn_list);
879 temp_insn->dnop_frag->fr_subtype = NOP_KEEP;
880 vliw1 = vliw1->next;
881 if (tomcat_stats)
882 tomcat_doubles++;
883 goto workaround_top;
884 }
885 else if (vliw2
886 && vliw2->insn_count == 1
887 && (temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw3, vliw1->insn_list->sym)) != NULL)
888 {
889 temp_insn->snop_frag->fr_subtype = NOP_KEEP;
890 vliw1 = frv_tomcat_shuffle (VLIW_SINGLE_NOP, vliw3, vliw3->insn_list);
891 if (tomcat_stats)
892 tomcat_singles++;
893 goto workaround_top;
894 }
895 }
896 }
897
898 if (vliw1->insn_count == 2)
899 {
900 /* Check vliw1 for a label. */
901 for (this_insn = vliw1->insn_list; this_insn; this_insn = this_insn->next)
902 {
903 if (this_insn->type == VLIW_LABEL_TYPE)
904 {
905 if ((temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw2, this_insn->sym)) != NULL)
906 {
907 temp_insn->snop_frag->fr_subtype = NOP_KEEP;
908 vliw1 = frv_tomcat_shuffle (VLIW_SINGLE_NOP, vliw2, this_insn);
909 if (tomcat_stats)
910 tomcat_singles++;
911 }
912 else
913 vliw1 = vliw1->next;
914 goto workaround_top;
915 }
916 }
917 }
918 /* Examine each insn in this VLIW. Look for the workaround criteria. */
919 for (this_insn = vliw1->insn_list; this_insn; this_insn = this_insn->next)
920 {
921 /* Don't look at labels or nops. */
922 while (this_insn
923 && (this_insn->type == VLIW_LABEL_TYPE
924 || this_insn->type == VLIW_NOP_TYPE
925 || this_insn->type == VLIW_BRANCH_HAS_NOPS))
926 this_insn = this_insn->next;
927
928 if (!this_insn)
929 {
930 vliw1 = vliw2;
931 goto workaround_top;
932 }
933
934 if (frv_is_branch_insn (this_insn->insn))
935 {
936 if ((temp_insn = frv_find_in_vliw (VLIW_LABEL_TYPE, vliw1, this_insn->sym)) != NULL)
937 {
938 /* Insert [nop/nop] [nop] before branch. */
939 this_insn->snop_frag->fr_subtype = NOP_KEEP;
940 this_insn->dnop_frag->fr_subtype = NOP_KEEP;
941 vliw1 = frv_tomcat_shuffle (VLIW_DOUBLE_THEN_SINGLE_NOP, vliw1, this_insn);
942 goto workaround_top;
943 }
944 }
945
946
947 }
948 /* This vliw insn checks out okay. Take a look at the next one. */
949 vliw1 = vliw1->next;
950 goto workaround_top;
951 }
952
953 void
954 frv_tomcat_workaround (void)
955 {
956 if (frv_mach != bfd_mach_frvtomcat)
957 return;
958
959 if (tomcat_debug)
960 frv_debug_tomcat (vliw_chain_top);
961
962 frv_tomcat_analyze_vliw_chains ();
963
964 if (tomcat_stats)
965 {
966 fprintf (stderr, "Inserted %d Single Nops\n", tomcat_singles);
967 fprintf (stderr, "Inserted %d Double Nops\n", tomcat_doubles);
968 }
969 }
970
971 static int
972 fr550_check_insn_acc_range (frv_insn *insn, int low, int hi)
973 {
974 int acc;
975 switch (CGEN_INSN_NUM (insn->insn))
976 {
977 case FRV_INSN_MADDACCS:
978 case FRV_INSN_MSUBACCS:
979 case FRV_INSN_MDADDACCS:
980 case FRV_INSN_MDSUBACCS:
981 case FRV_INSN_MASACCS:
982 case FRV_INSN_MDASACCS:
983 acc = insn->fields.f_ACC40Si;
984 if (acc < low || acc > hi)
985 return 1; /* out of range */
986 acc = insn->fields.f_ACC40Sk;
987 if (acc < low || acc > hi)
988 return 1; /* out of range */
989 break;
990 case FRV_INSN_MMULHS:
991 case FRV_INSN_MMULHU:
992 case FRV_INSN_MMULXHS:
993 case FRV_INSN_MMULXHU:
994 case FRV_INSN_CMMULHS:
995 case FRV_INSN_CMMULHU:
996 case FRV_INSN_MQMULHS:
997 case FRV_INSN_MQMULHU:
998 case FRV_INSN_MQMULXHS:
999 case FRV_INSN_MQMULXHU:
1000 case FRV_INSN_CMQMULHS:
1001 case FRV_INSN_CMQMULHU:
1002 case FRV_INSN_MMACHS:
1003 case FRV_INSN_MMRDHS:
1004 case FRV_INSN_CMMACHS:
1005 case FRV_INSN_MQMACHS:
1006 case FRV_INSN_CMQMACHS:
1007 case FRV_INSN_MQXMACHS:
1008 case FRV_INSN_MQXMACXHS:
1009 case FRV_INSN_MQMACXHS:
1010 case FRV_INSN_MCPXRS:
1011 case FRV_INSN_MCPXIS:
1012 case FRV_INSN_CMCPXRS:
1013 case FRV_INSN_CMCPXIS:
1014 case FRV_INSN_MQCPXRS:
1015 case FRV_INSN_MQCPXIS:
1016 acc = insn->fields.f_ACC40Sk;
1017 if (acc < low || acc > hi)
1018 return 1; /* out of range */
1019 break;
1020 case FRV_INSN_MMACHU:
1021 case FRV_INSN_MMRDHU:
1022 case FRV_INSN_CMMACHU:
1023 case FRV_INSN_MQMACHU:
1024 case FRV_INSN_CMQMACHU:
1025 case FRV_INSN_MCPXRU:
1026 case FRV_INSN_MCPXIU:
1027 case FRV_INSN_CMCPXRU:
1028 case FRV_INSN_CMCPXIU:
1029 case FRV_INSN_MQCPXRU:
1030 case FRV_INSN_MQCPXIU:
1031 acc = insn->fields.f_ACC40Uk;
1032 if (acc < low || acc > hi)
1033 return 1; /* out of range */
1034 break;
1035 default:
1036 break;
1037 }
1038 return 0; /* all is ok */
1039 }
1040
1041 static int
1042 fr550_check_acc_range (FRV_VLIW *vlw, frv_insn *insn)
1043 {
1044 switch ((*vlw->current_vliw)[vlw->next_slot - 1])
1045 {
1046 case UNIT_FM0:
1047 case UNIT_FM2:
1048 return fr550_check_insn_acc_range (insn, 0, 3);
1049 case UNIT_FM1:
1050 case UNIT_FM3:
1051 return fr550_check_insn_acc_range (insn, 4, 7);
1052 default:
1053 break;
1054 }
1055 return 0; /* all is ok */
1056 }
1057
1058 /* Return true if the target implements instruction INSN. */
1059
1060 static bfd_boolean
1061 target_implements_insn_p (const CGEN_INSN *insn)
1062 {
1063 switch (frv_mach)
1064 {
1065 default:
1066 /* bfd_mach_frv or generic. */
1067 return TRUE;
1068
1069 case bfd_mach_fr300:
1070 case bfd_mach_frvsimple:
1071 return CGEN_INSN_MACH_HAS_P (insn, MACH_SIMPLE);
1072
1073 case bfd_mach_fr400:
1074 return ((fr400_audio || !CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_AUDIO))
1075 && CGEN_INSN_MACH_HAS_P (insn, MACH_FR400));
1076
1077 case bfd_mach_fr450:
1078 return CGEN_INSN_MACH_HAS_P (insn, MACH_FR450);
1079
1080 case bfd_mach_fr500:
1081 return CGEN_INSN_MACH_HAS_P (insn, MACH_FR500);
1082
1083 case bfd_mach_fr550:
1084 return CGEN_INSN_MACH_HAS_P (insn, MACH_FR550);
1085 }
1086 }
1087
1088 void
1089 md_assemble (char *str)
1090 {
1091 frv_insn insn;
1092 char *errmsg;
1093 int packing_constraint;
1094 finished_insnS finished_insn;
1095 fragS *double_nop_frag = NULL;
1096 fragS *single_nop_frag = NULL;
1097 struct vliw_insn_list *vliw_insn_list_entry = NULL;
1098
1099 /* Initialize GAS's cgen interface for a new instruction. */
1100 gas_cgen_init_parse ();
1101
1102 memset (&insn, 0, sizeof (insn));
1103
1104 insn.insn = frv_cgen_assemble_insn
1105 (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, &errmsg);
1106
1107 if (!insn.insn)
1108 {
1109 as_bad ("%s", errmsg);
1110 return;
1111 }
1112
1113 /* If the cpu is tomcat, then we need to insert nops to workaround
1114 hardware limitations. We need to keep track of each vliw unit
1115 and examine the length of the unit and the individual insns
1116 within the unit to determine the number and location of the
1117 required nops. */
1118 if (frv_mach == bfd_mach_frvtomcat)
1119 {
1120 /* If we've just finished a VLIW insn OR this is a branch,
1121 then start up a new frag. Fill it with nops. We will get rid
1122 of those that are not required after we've seen all of the
1123 instructions but before we start resolving fixups. */
1124 if ( !FRV_IS_NOP (insn)
1125 && (frv_is_branch_insn (insn.insn) || insn.fields.f_pack))
1126 {
1127 char *buffer;
1128
1129 frag_wane (frag_now);
1130 frag_new (0);
1131 double_nop_frag = frag_now;
1132 buffer = frag_var (rs_machine_dependent, 8, 8, NOP_DELETE, NULL, 0, 0);
1133 md_number_to_chars (buffer, FRV_NOP_PACK, 4);
1134 md_number_to_chars (buffer+4, FRV_NOP_NOPACK, 4);
1135
1136 frag_wane (frag_now);
1137 frag_new (0);
1138 single_nop_frag = frag_now;
1139 buffer = frag_var (rs_machine_dependent, 4, 4, NOP_DELETE, NULL, 0, 0);
1140 md_number_to_chars (buffer, FRV_NOP_NOPACK, 4);
1141 }
1142
1143 vliw_insn_list_entry = frv_insert_vliw_insn (DO_COUNT);
1144 vliw_insn_list_entry->insn = insn.insn;
1145 if (frv_is_branch_insn (insn.insn))
1146 vliw_insn_list_entry->type = VLIW_BRANCH_TYPE;
1147
1148 if ( !FRV_IS_NOP (insn)
1149 && (frv_is_branch_insn (insn.insn) || insn.fields.f_pack))
1150 {
1151 vliw_insn_list_entry->snop_frag = single_nop_frag;
1152 vliw_insn_list_entry->dnop_frag = double_nop_frag;
1153 }
1154 }
1155
1156 /* Make sure that this insn does not violate the VLIW packing constraints. */
1157 /* -mno-pack disallows any packing whatsoever. */
1158 if (frv_flags & EF_FRV_NOPACK)
1159 {
1160 if (! insn.fields.f_pack)
1161 {
1162 as_bad (_("VLIW packing used for -mno-pack"));
1163 return;
1164 }
1165 }
1166 /* -mcpu=FRV is an idealized FR-V implementation that supports all of the
1167 instructions, don't do vliw checking. */
1168 else if (frv_mach != bfd_mach_frv)
1169 {
1170 if (!target_implements_insn_p (insn.insn))
1171 {
1172 as_bad (_("Instruction not supported by this architecture"));
1173 return;
1174 }
1175 packing_constraint = frv_vliw_add_insn (& vliw, insn.insn);
1176 if (frv_mach == bfd_mach_fr550 && ! packing_constraint)
1177 packing_constraint = fr550_check_acc_range (& vliw, & insn);
1178 if (insn.fields.f_pack)
1179 frv_vliw_reset (& vliw, frv_mach, frv_flags);
1180 if (packing_constraint)
1181 {
1182 as_bad (_("VLIW packing constraint violation"));
1183 return;
1184 }
1185 }
1186
1187 /* Doesn't really matter what we pass for RELAX_P here. */
1188 gas_cgen_finish_insn (insn.insn, insn.buffer,
1189 CGEN_FIELDS_BITSIZE (& insn.fields), 1, &finished_insn);
1190
1191
1192 /* If the cpu is tomcat, then we need to insert nops to workaround
1193 hardware limitations. We need to keep track of each vliw unit
1194 and examine the length of the unit and the individual insns
1195 within the unit to determine the number and location of the
1196 required nops. */
1197 if (frv_mach == bfd_mach_frvtomcat)
1198 {
1199 if (vliw_insn_list_entry)
1200 vliw_insn_list_entry->address = finished_insn.addr;
1201 else
1202 abort();
1203
1204 if (insn.fields.f_pack)
1205 {
1206 /* We've completed a VLIW insn. */
1207 previous_vliw_chain = current_vliw_chain;
1208 current_vliw_chain = NULL;
1209 current_vliw_insn = NULL;
1210 }
1211 }
1212 }
1213
1214 /* The syntax in the manual says constants begin with '#'.
1215 We just ignore it. */
1216
1217 void
1218 md_operand (expressionS *expressionP)
1219 {
1220 if (* input_line_pointer == '#')
1221 {
1222 input_line_pointer ++;
1223 expression (expressionP);
1224 }
1225 }
1226
1227 valueT
1228 md_section_align (segT segment, valueT size)
1229 {
1230 int align = bfd_get_section_alignment (stdoutput, segment);
1231 return ((size + (1 << align) - 1) & -(1 << align));
1232 }
1233
1234 symbolS *
1235 md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
1236 {
1237 return 0;
1238 }
1239
1240 /* 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
1308 /* Functions concerning relocs. */
1310
1311 /* The location from which a PC relative jump should be calculated,
1312 given a PC relative reloc. */
1313
1314 long
1315 md_pcrel_from_section (fixS *fixP, segT sec)
1316 {
1317 if (TC_FORCE_RELOCATION (fixP)
1318 || (fixP->fx_addsy != (symbolS *) NULL
1319 && S_GET_SEGMENT (fixP->fx_addsy) != sec))
1320 {
1321 /* If we can't adjust this relocation, or if it references a
1322 local symbol in a different section (which
1323 TC_FORCE_RELOCATION can't check), let the linker figure it
1324 out. */
1325 return 0;
1326 }
1327
1328 return (fixP->fx_frag->fr_address + fixP->fx_where) & ~1;
1329 }
1330
1331 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
1332 Returns BFD_RELOC_NONE if no reloc type can be found.
1333 *FIXP may be modified if desired. */
1334
1335 bfd_reloc_code_real_type
1336 md_cgen_lookup_reloc (const CGEN_INSN *insn ATTRIBUTE_UNUSED,
1337 const CGEN_OPERAND *operand,
1338 fixS *fixP)
1339 {
1340 switch (operand->type)
1341 {
1342 case FRV_OPERAND_LABEL16:
1343 fixP->fx_pcrel = TRUE;
1344 return BFD_RELOC_FRV_LABEL16;
1345
1346 case FRV_OPERAND_LABEL24:
1347 fixP->fx_pcrel = TRUE;
1348
1349 if (fixP->fx_cgen.opinfo != 0)
1350 return fixP->fx_cgen.opinfo;
1351
1352 return BFD_RELOC_FRV_LABEL24;
1353
1354 case FRV_OPERAND_UHI16:
1355 case FRV_OPERAND_ULO16:
1356 case FRV_OPERAND_SLO16:
1357 case FRV_OPERAND_CALLANN:
1358 case FRV_OPERAND_LDANN:
1359 case FRV_OPERAND_LDDANN:
1360 /* The relocation type should be recorded in opinfo */
1361 if (fixP->fx_cgen.opinfo != 0)
1362 return fixP->fx_cgen.opinfo;
1363 break;
1364
1365 case FRV_OPERAND_D12:
1366 case FRV_OPERAND_S12:
1367 if (fixP->fx_cgen.opinfo != 0)
1368 return fixP->fx_cgen.opinfo;
1369
1370 return BFD_RELOC_FRV_GPREL12;
1371
1372 case FRV_OPERAND_U12:
1373 return BFD_RELOC_FRV_GPRELU12;
1374
1375 default:
1376 break;
1377 }
1378 return BFD_RELOC_NONE;
1379 }
1380
1381
1382 /* See whether we need to force a relocation into the output file.
1383 This is used to force out switch and PC relative relocations when
1384 relaxing. */
1385
1386 int
1387 frv_force_relocation (fixS *fix)
1388 {
1389 switch (fix->fx_r_type < BFD_RELOC_UNUSED
1390 ? (int) fix->fx_r_type
1391 : fix->fx_cgen.opinfo)
1392 {
1393 case BFD_RELOC_FRV_GPREL12:
1394 case BFD_RELOC_FRV_GPRELU12:
1395 case BFD_RELOC_FRV_GPREL32:
1396 case BFD_RELOC_FRV_GPRELHI:
1397 case BFD_RELOC_FRV_GPRELLO:
1398 case BFD_RELOC_FRV_GOT12:
1399 case BFD_RELOC_FRV_GOTHI:
1400 case BFD_RELOC_FRV_GOTLO:
1401 case BFD_RELOC_FRV_FUNCDESC_VALUE:
1402 case BFD_RELOC_FRV_FUNCDESC_GOTOFF12:
1403 case BFD_RELOC_FRV_FUNCDESC_GOTOFFHI:
1404 case BFD_RELOC_FRV_FUNCDESC_GOTOFFLO:
1405 case BFD_RELOC_FRV_GOTOFF12:
1406 case BFD_RELOC_FRV_GOTOFFHI:
1407 case BFD_RELOC_FRV_GOTOFFLO:
1408 case BFD_RELOC_FRV_GETTLSOFF:
1409 case BFD_RELOC_FRV_TLSDESC_VALUE:
1410 case BFD_RELOC_FRV_GOTTLSDESC12:
1411 case BFD_RELOC_FRV_GOTTLSDESCHI:
1412 case BFD_RELOC_FRV_GOTTLSDESCLO:
1413 case BFD_RELOC_FRV_TLSMOFF12:
1414 case BFD_RELOC_FRV_TLSMOFFHI:
1415 case BFD_RELOC_FRV_TLSMOFFLO:
1416 case BFD_RELOC_FRV_GOTTLSOFF12:
1417 case BFD_RELOC_FRV_GOTTLSOFFHI:
1418 case BFD_RELOC_FRV_GOTTLSOFFLO:
1419 case BFD_RELOC_FRV_TLSOFF:
1420 case BFD_RELOC_FRV_TLSDESC_RELAX:
1421 case BFD_RELOC_FRV_GETTLSOFF_RELAX:
1422 case BFD_RELOC_FRV_TLSOFF_RELAX:
1423 return 1;
1424
1425 default:
1426 break;
1427 }
1428
1429 return generic_force_reloc (fix);
1430 }
1431
1432 /* Apply a fixup that could be resolved within the assembler. */
1433
1434 void
1435 md_apply_fix (fixS *fixP, valueT *valP, segT seg)
1436 {
1437 if (fixP->fx_addsy == 0)
1438 switch (fixP->fx_cgen.opinfo)
1439 {
1440 case BFD_RELOC_FRV_HI16:
1441 *valP >>= 16;
1442 /* Fall through. */
1443 case BFD_RELOC_FRV_LO16:
1444 *valP &= 0xffff;
1445 break;
1446
1447 /* We need relocations for these, even if their symbols reduce
1448 to constants. */
1449 case BFD_RELOC_FRV_GPREL12:
1450 case BFD_RELOC_FRV_GPRELU12:
1451 case BFD_RELOC_FRV_GPREL32:
1452 case BFD_RELOC_FRV_GPRELHI:
1453 case BFD_RELOC_FRV_GPRELLO:
1454 case BFD_RELOC_FRV_GOT12:
1455 case BFD_RELOC_FRV_GOTHI:
1456 case BFD_RELOC_FRV_GOTLO:
1457 case BFD_RELOC_FRV_FUNCDESC_VALUE:
1458 case BFD_RELOC_FRV_FUNCDESC_GOTOFF12:
1459 case BFD_RELOC_FRV_FUNCDESC_GOTOFFHI:
1460 case BFD_RELOC_FRV_FUNCDESC_GOTOFFLO:
1461 case BFD_RELOC_FRV_GOTOFF12:
1462 case BFD_RELOC_FRV_GOTOFFHI:
1463 case BFD_RELOC_FRV_GOTOFFLO:
1464 case BFD_RELOC_FRV_GETTLSOFF:
1465 case BFD_RELOC_FRV_TLSDESC_VALUE:
1466 case BFD_RELOC_FRV_GOTTLSDESC12:
1467 case BFD_RELOC_FRV_GOTTLSDESCHI:
1468 case BFD_RELOC_FRV_GOTTLSDESCLO:
1469 case BFD_RELOC_FRV_TLSMOFF12:
1470 case BFD_RELOC_FRV_TLSMOFFHI:
1471 case BFD_RELOC_FRV_TLSMOFFLO:
1472 case BFD_RELOC_FRV_GOTTLSOFF12:
1473 case BFD_RELOC_FRV_GOTTLSOFFHI:
1474 case BFD_RELOC_FRV_GOTTLSOFFLO:
1475 case BFD_RELOC_FRV_TLSOFF:
1476 case BFD_RELOC_FRV_TLSDESC_RELAX:
1477 case BFD_RELOC_FRV_GETTLSOFF_RELAX:
1478 case BFD_RELOC_FRV_TLSOFF_RELAX:
1479 fixP->fx_addsy = abs_section_sym;
1480 break;
1481 }
1482 else
1483 switch (fixP->fx_cgen.opinfo)
1484 {
1485 case BFD_RELOC_FRV_GETTLSOFF:
1486 case BFD_RELOC_FRV_TLSDESC_VALUE:
1487 case BFD_RELOC_FRV_GOTTLSDESC12:
1488 case BFD_RELOC_FRV_GOTTLSDESCHI:
1489 case BFD_RELOC_FRV_GOTTLSDESCLO:
1490 case BFD_RELOC_FRV_TLSMOFF12:
1491 case BFD_RELOC_FRV_TLSMOFFHI:
1492 case BFD_RELOC_FRV_TLSMOFFLO:
1493 case BFD_RELOC_FRV_GOTTLSOFF12:
1494 case BFD_RELOC_FRV_GOTTLSOFFHI:
1495 case BFD_RELOC_FRV_GOTTLSOFFLO:
1496 case BFD_RELOC_FRV_TLSOFF:
1497 case BFD_RELOC_FRV_TLSDESC_RELAX:
1498 case BFD_RELOC_FRV_GETTLSOFF_RELAX:
1499 case BFD_RELOC_FRV_TLSOFF_RELAX:
1500 /* Mark TLS symbols as such. */
1501 if (S_GET_SEGMENT (fixP->fx_addsy) != absolute_section)
1502 S_SET_THREAD_LOCAL (fixP->fx_addsy);
1503 break;
1504 }
1505
1506 gas_cgen_md_apply_fix (fixP, valP, seg);
1507 return;
1508 }
1509
1510
1511 /* Write a value out to the object file, using the appropriate endianness. */
1513
1514 void
1515 frv_md_number_to_chars (char *buf, valueT val, int n)
1516 {
1517 number_to_chars_bigendian (buf, val, n);
1518 }
1519
1520 const char *
1521 md_atof (int type, char *litP, int *sizeP)
1522 {
1523 return ieee_md_atof (type, litP, sizeP, TRUE);
1524 }
1525
1526 bfd_boolean
1527 frv_fix_adjustable (fixS *fixP)
1528 {
1529 bfd_reloc_code_real_type reloc_type;
1530
1531 if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
1532 {
1533 const CGEN_INSN *insn = NULL;
1534 int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
1535 const CGEN_OPERAND *operand = cgen_operand_lookup_by_num(gas_cgen_cpu_desc, opindex);
1536 reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
1537 }
1538 else
1539 reloc_type = fixP->fx_r_type;
1540
1541 /* We need the symbol name for the VTABLE entries */
1542 if ( reloc_type == BFD_RELOC_VTABLE_INHERIT
1543 || reloc_type == BFD_RELOC_VTABLE_ENTRY
1544 || reloc_type == BFD_RELOC_FRV_GPREL12
1545 || reloc_type == BFD_RELOC_FRV_GPRELU12)
1546 return 0;
1547
1548 return 1;
1549 }
1550
1551 /* Allow user to set flags bits. */
1552 void
1553 frv_set_flags (int arg ATTRIBUTE_UNUSED)
1554 {
1555 flagword new_flags = get_absolute_expression ();
1556 flagword new_mask = ~ (flagword)0;
1557
1558 frv_user_set_flags_p = 1;
1559 if (*input_line_pointer == ',')
1560 {
1561 ++input_line_pointer;
1562 new_mask = get_absolute_expression ();
1563 }
1564
1565 frv_flags = (frv_flags & ~new_mask) | (new_flags & new_mask);
1566 bfd_set_private_flags (stdoutput, frv_flags);
1567 }
1568
1569 /* Frv specific function to handle 4 byte initializations for pointers that are
1570 considered 'safe' for use with pic support. Until frv_frob_file{,_section}
1571 is run, we encode it a BFD_RELOC_CTOR, and it is turned back into a normal
1572 BFD_RELOC_32 at that time. */
1573
1574 void
1575 frv_pic_ptr (int nbytes)
1576 {
1577 expressionS exp;
1578 char *p;
1579
1580 if (nbytes != 4)
1581 abort ();
1582
1583 #ifdef md_flush_pending_output
1584 md_flush_pending_output ();
1585 #endif
1586
1587 if (is_it_end_of_statement ())
1588 {
1589 demand_empty_rest_of_line ();
1590 return;
1591 }
1592
1593 #ifdef md_cons_align
1594 md_cons_align (nbytes);
1595 #endif
1596
1597 do
1598 {
1599 bfd_reloc_code_real_type reloc_type = BFD_RELOC_CTOR;
1600
1601 if (strncasecmp (input_line_pointer, "funcdesc(", 9) == 0)
1602 {
1603 input_line_pointer += 9;
1604 expression (&exp);
1605 if (*input_line_pointer == ')')
1606 input_line_pointer++;
1607 else
1608 as_bad (_("missing ')'"));
1609 reloc_type = BFD_RELOC_FRV_FUNCDESC;
1610 }
1611 else if (strncasecmp (input_line_pointer, "tlsmoff(", 8) == 0)
1612 {
1613 input_line_pointer += 8;
1614 expression (&exp);
1615 if (*input_line_pointer == ')')
1616 input_line_pointer++;
1617 else
1618 as_bad (_("missing ')'"));
1619 reloc_type = BFD_RELOC_FRV_TLSMOFF;
1620 }
1621 else
1622 expression (&exp);
1623
1624 p = frag_more (4);
1625 memset (p, 0, 4);
1626 fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &exp, 0,
1627 reloc_type);
1628 }
1629 while (*input_line_pointer++ == ',');
1630
1631 input_line_pointer--; /* Put terminator back into stream. */
1632 demand_empty_rest_of_line ();
1633 }
1634
1635
1636
1638 #ifdef DEBUG
1639 #define DPRINTF1(A) fprintf (stderr, A)
1640 #define DPRINTF2(A,B) fprintf (stderr, A, B)
1641 #define DPRINTF3(A,B,C) fprintf (stderr, A, B, C)
1642
1643 #else
1644 #define DPRINTF1(A)
1645 #define DPRINTF2(A,B)
1646 #define DPRINTF3(A,B,C)
1647 #endif
1648
1649 /* Go through a the sections looking for relocations that are problematical for
1650 pic. If not pic, just note that this object can't be linked with pic. If
1651 it is pic, see if it needs to be marked so that it will be fixed up, or if
1652 not possible, issue an error. */
1653
1654 static void
1655 frv_frob_file_section (bfd *abfd, asection *sec, void *ptr ATTRIBUTE_UNUSED)
1656 {
1657 segment_info_type *seginfo = seg_info (sec);
1658 fixS *fixp;
1659 CGEN_CPU_DESC cd = gas_cgen_cpu_desc;
1660 flagword flags = bfd_get_section_flags (abfd, sec);
1661
1662 /* Skip relocations in known sections (.ctors, .dtors, and .gcc_except_table)
1663 since we can fix those up by hand. */
1664 int known_section_p = (sec->name
1665 && sec->name[0] == '.'
1666 && ((sec->name[1] == 'c'
1667 && strcmp (sec->name, ".ctor") == 0)
1668 || (sec->name[1] == 'd'
1669 && strcmp (sec->name, ".dtor") == 0)
1670 || (sec->name[1] == 'g'
1671 && strcmp (sec->name, ".gcc_except_table") == 0)));
1672
1673 DPRINTF3 ("\nFrv section %s%s\n", sec->name, (known_section_p) ? ", known section" : "");
1674 if ((flags & SEC_ALLOC) == 0)
1675 {
1676 DPRINTF1 ("\tSkipping non-loaded section\n");
1677 return;
1678 }
1679
1680 for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next)
1681 {
1682 symbolS *s = fixp->fx_addsy;
1683 bfd_reloc_code_real_type reloc;
1684 int non_pic_p;
1685 int opindex;
1686 const CGEN_OPERAND *operand;
1687 const CGEN_INSN *insn = fixp->fx_cgen.insn;
1688
1689 if (fixp->fx_done)
1690 {
1691 DPRINTF1 ("\tSkipping reloc that has already been done\n");
1692 continue;
1693 }
1694
1695 if (fixp->fx_pcrel)
1696 {
1697 DPRINTF1 ("\tSkipping reloc that is PC relative\n");
1698 continue;
1699 }
1700
1701 if (! s)
1702 {
1703 DPRINTF1 ("\tSkipping reloc without symbol\n");
1704 continue;
1705 }
1706
1707 if (fixp->fx_r_type < BFD_RELOC_UNUSED)
1708 {
1709 opindex = -1;
1710 reloc = fixp->fx_r_type;
1711 }
1712 else
1713 {
1714 opindex = (int) fixp->fx_r_type - (int) BFD_RELOC_UNUSED;
1715 operand = cgen_operand_lookup_by_num (cd, opindex);
1716 reloc = md_cgen_lookup_reloc (insn, operand, fixp);
1717 }
1718
1719 DPRINTF3 ("\treloc %s\t%s", bfd_get_reloc_code_name (reloc), S_GET_NAME (s));
1720
1721 non_pic_p = 0;
1722 switch (reloc)
1723 {
1724 default:
1725 break;
1726
1727 case BFD_RELOC_32:
1728 /* Skip relocations in known sections (.ctors, .dtors, and
1729 .gcc_except_table) since we can fix those up by hand. Also
1730 skip forward references to constants. Also skip a difference
1731 of two symbols, which still uses the BFD_RELOC_32 at this
1732 point. */
1733 if (! known_section_p
1734 && S_GET_SEGMENT (s) != absolute_section
1735 && !fixp->fx_subsy
1736 && (flags & (SEC_READONLY | SEC_CODE)) == 0)
1737 {
1738 non_pic_p = 1;
1739 }
1740 break;
1741
1742 /* FIXME -- should determine if any of the GP relocation really uses
1743 gr16 (which is not pic safe) or not. Right now, assume if we
1744 aren't being compiled with -mpic, the usage is non pic safe, but
1745 is safe with -mpic. */
1746 case BFD_RELOC_FRV_GPREL12:
1747 case BFD_RELOC_FRV_GPRELU12:
1748 case BFD_RELOC_FRV_GPREL32:
1749 case BFD_RELOC_FRV_GPRELHI:
1750 case BFD_RELOC_FRV_GPRELLO:
1751 non_pic_p = ! frv_pic_p;
1752 break;
1753
1754 case BFD_RELOC_FRV_LO16:
1755 case BFD_RELOC_FRV_HI16:
1756 if (S_GET_SEGMENT (s) != absolute_section)
1757 non_pic_p = 1;
1758 break;
1759
1760 case BFD_RELOC_VTABLE_INHERIT:
1761 case BFD_RELOC_VTABLE_ENTRY:
1762 non_pic_p = 1;
1763 break;
1764
1765 /* If this is a blessed BFD_RELOC_32, convert it back to the normal
1766 relocation. */
1767 case BFD_RELOC_CTOR:
1768 fixp->fx_r_type = BFD_RELOC_32;
1769 break;
1770 }
1771
1772 if (non_pic_p)
1773 {
1774 DPRINTF1 (" (Non-pic relocation)\n");
1775 if (frv_pic_p)
1776 as_warn_where (fixp->fx_file, fixp->fx_line,
1777 _("Relocation %s is not safe for %s"),
1778 bfd_get_reloc_code_name (reloc), frv_pic_flag);
1779
1780 else if ((frv_flags & EF_FRV_NON_PIC_RELOCS) == 0)
1781 {
1782 frv_flags |= EF_FRV_NON_PIC_RELOCS;
1783 bfd_set_private_flags (abfd, frv_flags);
1784 }
1785 }
1786 #ifdef DEBUG
1787 else
1788 DPRINTF1 ("\n");
1789 #endif
1790 }
1791 }
1792
1793 /* After all of the symbols have been adjusted, go over the file looking
1794 for any relocations that pic won't support. */
1795
1796 void
1797 frv_frob_file (void)
1798 {
1799 bfd_map_over_sections (stdoutput, frv_frob_file_section, (void *) 0);
1800 }
1801
1802 void
1803 frv_frob_label (symbolS *this_label)
1804 {
1805 struct vliw_insn_list *vliw_insn_list_entry;
1806
1807 dwarf2_emit_label (this_label);
1808 if (frv_mach != bfd_mach_frvtomcat)
1809 return;
1810
1811 if (now_seg != text_section)
1812 return;
1813
1814 vliw_insn_list_entry = frv_insert_vliw_insn(DONT_COUNT);
1815 vliw_insn_list_entry->type = VLIW_LABEL_TYPE;
1816 vliw_insn_list_entry->sym = this_label;
1817 }
1818
1819 fixS *
1820 frv_cgen_record_fixup_exp (fragS *frag,
1821 int where,
1822 const CGEN_INSN *insn,
1823 int length,
1824 const CGEN_OPERAND *operand,
1825 int opinfo,
1826 expressionS *exp)
1827 {
1828 fixS * fixP = gas_cgen_record_fixup_exp (frag, where, insn, length,
1829 operand, opinfo, exp);
1830
1831 if (frv_mach == bfd_mach_frvtomcat
1832 && current_vliw_insn
1833 && current_vliw_insn->type == VLIW_BRANCH_TYPE
1834 && exp != NULL)
1835 current_vliw_insn->sym = exp->X_add_symbol;
1836
1837 return fixP;
1838 }
1839