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