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