Remove redundant returns in void functions.
[deliverable/binutils-gdb.git] / gas / config / tc-frv.c
CommitLineData
0ebb9a87 1/* tc-frv.c -- Assembler for the Fujitsu FRV.
ae6063d4 2 Copyright 2002, 2003 Free Software Foundation.
0ebb9a87
DB
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"
0ebb9a87
DB
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. */
34typedef 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}
52frv_insn;
53
54enum 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
b34976b6
AM
69#define DO_COUNT TRUE
70#define DONT_COUNT FALSE
0ebb9a87
DB
71
72/* A list of insns within a VLIW insn. */
73struct 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
97static struct vliw_insn_list single_nop_insn = {
98 VLIW_NOP_TYPE, NULL, NULL, NULL, NULL, NULL, NULL };
99
100static struct vliw_insn_list double_nop_insn = {
101 VLIW_NOP_TYPE, NULL, NULL, NULL, NULL, NULL, NULL };
102
103struct vliw_chain
104{
105 int num;
106 int insn_count;
107 struct vliw_insn_list *insn_list;
108 struct vliw_chain *next;
109};
110
111static struct vliw_chain *vliw_chain_top;
112static struct vliw_chain *current_vliw_chain;
113static struct vliw_chain *previous_vliw_chain;
114static struct vliw_insn_list *current_vliw_insn;
115
116const char comment_chars[] = ";";
117const char line_comment_chars[] = "#";
118const char line_separator_chars[] = "";
119const char EXP_CHARS[] = "eE";
120const char FLT_CHARS[] = "dD";
121
122static 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
1ae31fee
DB
150#else
151#ifdef DEFAULT_CPU_FR550
152#define DEFAULT_MACHINE bfd_mach_fr550
153#define DEFAULT_FLAGS EF_FRV_CPU_FR550
154
0ebb9a87
DB
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
1ae31fee 163#endif
0ebb9a87
DB
164
165static unsigned long frv_mach = bfd_mach_frv;
166
167/* Flags to set in the elf header */
168static flagword frv_flags = DEFAULT_FLAGS;
169
170static int frv_user_set_flags_p = 0;
171static int frv_pic_p = 0;
172static const char *frv_pic_flag = (const char *)0;
173
174/* Print tomcat-specific debugging info. */
175static int tomcat_debug = 0;
176
177/* Tomcat-specific NOP statistics. */
178static int tomcat_stats = 0;
179static int tomcat_doubles = 0;
180static int tomcat_singles = 0;
181
182/* Forward reference to static functions */
183static void frv_set_flags PARAMS ((int));
184static void frv_pic_ptr PARAMS ((int));
185static void frv_frob_file_section PARAMS ((bfd *, asection *, PTR));
186
187/* The target specific pseudo-ops which we support. */
188const pseudo_typeS md_pseudo_table[] =
189{
190 { "eflags", frv_set_flags, 0 },
191 { "word", cons, 4 },
192 { "picptr", frv_pic_ptr, 4 },
0ebb9a87
DB
193 { NULL, NULL, 0 }
194};
195
196\f
197#define FRV_SHORTOPTS "G:"
198const 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
222struct 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
249size_t md_longopts_size = sizeof (md_longopts);
250
251/* What value to give to bfd_set_gp_size. */
252static int g_switch_value = 8;
253
254int
255md_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
1ae31fee
DB
349 else if (strcmp (p, "fr550") == 0)
350 {
351 cpu_flags = EF_FRV_CPU_FR550;
352 frv_mach = bfd_mach_fr550;
353 }
354
0ebb9a87
DB
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
421void
422md_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"));
1ae31fee 442 fprintf (stream, _("-mcpu={fr500|fr550|fr400|fr300|frv|simple|tomcat}\n"));
0ebb9a87
DB
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
449void
450md_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
477int chain_num = 0;
478
a08333bb
AM
479struct vliw_insn_list *frv_insert_vliw_insn PARAMS ((bfd_boolean));
480
0ebb9a87
DB
481struct vliw_insn_list *
482frv_insert_vliw_insn (count)
b34976b6 483 bfd_boolean count;
0ebb9a87
DB
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
a08333bb
AM
552static struct vliw_insn_list *frv_find_in_vliw
553 PARAMS ((enum vliw_insn_type, struct vliw_chain *, symbolS *));
554
0ebb9a87
DB
555static struct vliw_insn_list *
556frv_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
577enum 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
a08333bb
AM
590static void frv_debug_tomcat PARAMS ((struct vliw_chain *));
591
0ebb9a87
DB
592static void
593frv_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
a08333bb 620static void frv_adjust_vliw_count PARAMS ((struct vliw_chain *));
0ebb9a87
DB
621
622static void
623frv_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
a08333bb
AM
643static struct vliw_chain *frv_tomcat_shuffle
644 PARAMS ((enum vliw_nop_type, struct vliw_chain *, struct vliw_insn_list *));
0ebb9a87
DB
645
646static struct vliw_chain *
647frv_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
b34976b6 653 bfd_boolean pack_prev = FALSE;
0ebb9a87
DB
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)
b34976b6 674 pack_prev = TRUE;
0ebb9a87
DB
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
a08333bb
AM
814static void frv_tomcat_analyze_vliw_chains PARAMS ((void));
815
0ebb9a87
DB
816static void
817frv_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
841workaround_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 {
a08333bb 885 if ((temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw2, this_insn->sym)) != NULL)
0ebb9a87
DB
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 {
a08333bb 916 if ((temp_insn = frv_find_in_vliw (VLIW_LABEL_TYPE, vliw1, this_insn->sym)) != NULL)
0ebb9a87
DB
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
933void
934frv_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
1ae31fee
DB
951static int
952fr550_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
1021static int
1022fr550_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
0ebb9a87
DB
1038void
1039md_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);
1ae31fee
DB
1120 if (frv_mach == bfd_mach_fr550 && ! packing_constraint)
1121 packing_constraint = fr550_check_acc_range (& vliw, & insn);
0ebb9a87
DB
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
1161void
1162md_operand (expressionP)
1163 expressionS * expressionP;
1164{
1165 if (* input_line_pointer == '#')
1166 {
1167 input_line_pointer ++;
1168 expression (expressionP);
1169 }
1170}
1171
1172valueT
1173md_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
1181symbolS *
1182md_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. */
1191const 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
1199long
1200frv_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
1218int
1219md_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
1241void
1242md_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
1265long
1266md_pcrel_from_section (fixP, sec)
1267 fixS * fixP;
a939d090 1268 segT sec;
0ebb9a87 1269{
a939d090
AO
1270 if (TC_FORCE_RELOCATION (fixP)
1271 || (fixP->fx_addsy != (symbolS *) NULL
1272 && S_GET_SEGMENT (fixP->fx_addsy) != sec))
1273 {
1274 /* If we can't adjust this relocation, or if it references a
1275 local symbol in a different section (which
1276 TC_FORCE_RELOCATION can't check), let the linker figure it
1277 out. */
1278 return 0;
1279 }
0ebb9a87
DB
1280
1281 return (fixP->fx_frag->fr_address + fixP->fx_where) & ~1;
1282}
1283
1284/* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
1285 Returns BFD_RELOC_NONE if no reloc type can be found.
1286 *FIXP may be modified if desired. */
1287
1288bfd_reloc_code_real_type
1289md_cgen_lookup_reloc (insn, operand, fixP)
1290 const CGEN_INSN * insn ATTRIBUTE_UNUSED;
1291 const CGEN_OPERAND * operand;
1292 fixS * fixP;
1293{
1294 switch (operand->type)
1295 {
1296 case FRV_OPERAND_LABEL16:
b34976b6 1297 fixP->fx_pcrel = TRUE;
0ebb9a87
DB
1298 return BFD_RELOC_FRV_LABEL16;
1299
1300 case FRV_OPERAND_LABEL24:
b34976b6 1301 fixP->fx_pcrel = TRUE;
0ebb9a87
DB
1302 return BFD_RELOC_FRV_LABEL24;
1303
1304 case FRV_OPERAND_UHI16:
1305 case FRV_OPERAND_ULO16:
1306 case FRV_OPERAND_SLO16:
1307
1308 /* The relocation type should be recorded in opinfo */
1309 if (fixP->fx_cgen.opinfo != 0)
1310 return fixP->fx_cgen.opinfo;
1311 break;
1312
1313 case FRV_OPERAND_D12:
1314 case FRV_OPERAND_S12:
1315 return BFD_RELOC_FRV_GPREL12;
1316
1317 case FRV_OPERAND_U12:
1318 return BFD_RELOC_FRV_GPRELU12;
1319
1320 default:
1321 break;
1322 }
1323 return BFD_RELOC_NONE;
1324}
1325
1326
1327/* See whether we need to force a relocation into the output file.
1328 This is used to force out switch and PC relative relocations when
1329 relaxing. */
1330
1331int
1332frv_force_relocation (fix)
1333 fixS * fix;
1334{
ae6063d4 1335 if (fix->fx_r_type == BFD_RELOC_FRV_GPREL12
0ebb9a87
DB
1336 || fix->fx_r_type == BFD_RELOC_FRV_GPRELU12)
1337 return 1;
1338
ae6063d4 1339 return generic_force_reloc (fix);
0ebb9a87
DB
1340}
1341\f
1342/* Write a value out to the object file, using the appropriate endianness. */
1343
1344void
1345frv_md_number_to_chars (buf, val, n)
1346 char * buf;
1347 valueT val;
1348 int n;
1349{
1350 number_to_chars_bigendian (buf, val, n);
1351}
1352
1353/* Turn a string in input_line_pointer into a floating point constant of type
1354 type, and store the appropriate bytes in *litP. The number of LITTLENUMS
1355 emitted is stored in *sizeP . An error message is returned, or NULL on OK.
1356*/
1357
1358/* Equal to MAX_PRECISION in atof-ieee.c */
1359#define MAX_LITTLENUMS 6
1360
1361char *
1362md_atof (type, litP, sizeP)
1363 char type;
1364 char * litP;
1365 int * sizeP;
1366{
1367 int i;
1368 int prec;
1369 LITTLENUM_TYPE words [MAX_LITTLENUMS];
1370 char * t;
0ebb9a87
DB
1371
1372 switch (type)
1373 {
1374 case 'f':
1375 case 'F':
1376 case 's':
1377 case 'S':
1378 prec = 2;
1379 break;
1380
1381 case 'd':
1382 case 'D':
1383 case 'r':
1384 case 'R':
1385 prec = 4;
1386 break;
1387
1388 /* FIXME: Some targets allow other format chars for bigger sizes here. */
1389
1390 default:
1391 * sizeP = 0;
1392 return _("Bad call to md_atof()");
1393 }
1394
1395 t = atof_ieee (input_line_pointer, type, words);
1396 if (t)
1397 input_line_pointer = t;
1398 * sizeP = prec * sizeof (LITTLENUM_TYPE);
1399
1400 for (i = 0; i < prec; i++)
1401 {
1402 md_number_to_chars (litP, (valueT) words[i],
1403 sizeof (LITTLENUM_TYPE));
1404 litP += sizeof (LITTLENUM_TYPE);
1405 }
1406
1407 return 0;
1408}
1409
b34976b6 1410bfd_boolean
0ebb9a87
DB
1411frv_fix_adjustable (fixP)
1412 fixS * fixP;
1413{
1414 bfd_reloc_code_real_type reloc_type;
1415
1416 if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
1417 {
1418 const CGEN_INSN *insn = NULL;
1419 int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
1420 const CGEN_OPERAND *operand = cgen_operand_lookup_by_num(gas_cgen_cpu_desc, opindex);
1421 reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
1422 }
1423 else
1424 reloc_type = fixP->fx_r_type;
1425
0ebb9a87
DB
1426 /* We need the symbol name for the VTABLE entries */
1427 if ( reloc_type == BFD_RELOC_VTABLE_INHERIT
1428 || reloc_type == BFD_RELOC_VTABLE_ENTRY
1429 || reloc_type == BFD_RELOC_FRV_GPREL12
1430 || reloc_type == BFD_RELOC_FRV_GPRELU12)
1431 return 0;
1432
1433 return 1;
1434}
1435
1436/* Allow user to set flags bits. */
1437void
1438frv_set_flags (arg)
1439 int arg ATTRIBUTE_UNUSED;
1440{
1441 flagword new_flags = get_absolute_expression ();
1442 flagword new_mask = ~ (flagword)0;
1443
1444 frv_user_set_flags_p = 1;
1445 if (*input_line_pointer == ',')
1446 {
1447 ++input_line_pointer;
1448 new_mask = get_absolute_expression ();
1449 }
1450
1451 frv_flags = (frv_flags & ~new_mask) | (new_flags & new_mask);
1452 bfd_set_private_flags (stdoutput, frv_flags);
1453}
1454
1455/* Frv specific function to handle 4 byte initializations for pointers that are
1456 considered 'safe' for use with pic support. Until frv_frob_file{,_section}
1457 is run, we encode it a BFD_RELOC_CTOR, and it is turned back into a normal
1458 BFD_RELOC_32 at that time. */
1459
1460void
1461frv_pic_ptr (nbytes)
1462 int nbytes;
1463{
1464 expressionS exp;
1465 char *p;
1466
1467 if (nbytes != 4)
1468 abort ();
1469
1470#ifdef md_flush_pending_output
1471 md_flush_pending_output ();
1472#endif
1473
1474 if (is_it_end_of_statement ())
1475 {
1476 demand_empty_rest_of_line ();
1477 return;
1478 }
1479
1480#ifdef md_cons_align
1481 md_cons_align (nbytes);
1482#endif
1483
1484 do
1485 {
1486 expression (&exp);
1487
1488 p = frag_more (4);
1489 memset (p, 0, 4);
1490 fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &exp, 0,
1491 BFD_RELOC_CTOR);
1492 }
1493 while (*input_line_pointer++ == ',');
1494
1495 input_line_pointer--; /* Put terminator back into stream. */
1496 demand_empty_rest_of_line ();
1497}
1498
1499\f
1500
1501#ifdef DEBUG
1502#define DPRINTF1(A) fprintf (stderr, A)
1503#define DPRINTF2(A,B) fprintf (stderr, A, B)
1504#define DPRINTF3(A,B,C) fprintf (stderr, A, B, C)
1505
1506#else
1507#define DPRINTF1(A)
1508#define DPRINTF2(A,B)
1509#define DPRINTF3(A,B,C)
1510#endif
1511
1512/* Go through a the sections looking for relocations that are problematical for
1513 pic. If not pic, just note that this object can't be linked with pic. If
1514 it is pic, see if it needs to be marked so that it will be fixed up, or if
1515 not possible, issue an error. */
1516
1517static void
1518frv_frob_file_section (abfd, sec, ptr)
1519 bfd *abfd;
1520 asection *sec;
1521 PTR ptr ATTRIBUTE_UNUSED;
1522{
1523 segment_info_type *seginfo = seg_info (sec);
1524 fixS *fixp;
1525 CGEN_CPU_DESC cd = gas_cgen_cpu_desc;
1526 flagword flags = bfd_get_section_flags (abfd, sec);
1527
1528 /* Skip relocations in known sections (.ctors, .dtors, and .gcc_except_table)
1529 since we can fix those up by hand. */
1530 int known_section_p = (sec->name
1531 && sec->name[0] == '.'
1532 && ((sec->name[1] == 'c'
1533 && strcmp (sec->name, ".ctor") == 0)
1534 || (sec->name[1] == 'd'
1535 && strcmp (sec->name, ".dtor") == 0)
1536 || (sec->name[1] == 'g'
1537 && strcmp (sec->name, ".gcc_except_table") == 0)));
1538
1539 DPRINTF3 ("\nFrv section %s%s\n", sec->name, (known_section_p) ? ", known section" : "");
1540 if ((flags & SEC_ALLOC) == 0)
1541 {
1542 DPRINTF1 ("\tSkipping non-loaded section\n");
1543 return;
1544 }
1545
1546 for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next)
1547 {
1548 symbolS *s = fixp->fx_addsy;
1549 bfd_reloc_code_real_type reloc;
1550 int non_pic_p;
1551 int opindex;
1552 const CGEN_OPERAND *operand;
1553 const CGEN_INSN *insn = fixp->fx_cgen.insn;
1554
1555 if (fixp->fx_done)
1556 {
1557 DPRINTF1 ("\tSkipping reloc that has already been done\n");
1558 continue;
1559 }
1560
1561 if (fixp->fx_pcrel)
1562 {
1563 DPRINTF1 ("\tSkipping reloc that is PC relative\n");
1564 continue;
1565 }
1566
1567 if (! s)
1568 {
1569 DPRINTF1 ("\tSkipping reloc without symbol\n");
1570 continue;
1571 }
1572
1573 if (fixp->fx_r_type < BFD_RELOC_UNUSED)
1574 {
1575 opindex = -1;
1576 reloc = fixp->fx_r_type;
1577 }
1578 else
1579 {
1580 opindex = (int) fixp->fx_r_type - (int) BFD_RELOC_UNUSED;
1581 operand = cgen_operand_lookup_by_num (cd, opindex);
1582 reloc = md_cgen_lookup_reloc (insn, operand, fixp);
1583 }
1584
1585 DPRINTF3 ("\treloc %s\t%s", bfd_get_reloc_code_name (reloc), S_GET_NAME (s));
1586
1587 non_pic_p = 0;
1588 switch (reloc)
1589 {
1590 default:
1591 break;
1592
1593 case BFD_RELOC_32:
1594 /* Skip relocations in known sections (.ctors, .dtors, and
1595 .gcc_except_table) since we can fix those up by hand. Also
1596 skip forward references to constants. Also skip a difference
1597 of two symbols, which still uses the BFD_RELOC_32 at this
1598 point. */
1599 if (! known_section_p
1600 && S_GET_SEGMENT (s) != absolute_section
1601 && !fixp->fx_subsy
1602 && (flags & (SEC_READONLY | SEC_CODE)) == 0)
1603 {
1604 non_pic_p = 1;
1605 }
1606 break;
1607
1608 /* FIXME -- should determine if any of the GP relocation really uses
1609 gr16 (which is not pic safe) or not. Right now, assume if we
1610 aren't being compiled with -mpic, the usage is non pic safe, but
1611 is safe with -mpic. */
1612 case BFD_RELOC_FRV_GPREL12:
1613 case BFD_RELOC_FRV_GPRELU12:
1614 case BFD_RELOC_FRV_GPREL32:
1615 case BFD_RELOC_FRV_GPRELHI:
1616 case BFD_RELOC_FRV_GPRELLO:
1617 non_pic_p = ! frv_pic_p;
1618 break;
1619
1620 case BFD_RELOC_FRV_LO16:
1621 case BFD_RELOC_FRV_HI16:
1622 if (S_GET_SEGMENT (s) != absolute_section)
1623 non_pic_p = 1;
1624 break;
1625
1626 case BFD_RELOC_VTABLE_INHERIT:
1627 case BFD_RELOC_VTABLE_ENTRY:
1628 non_pic_p = 1;
1629 break;
1630
1631 /* If this is a blessed BFD_RELOC_32, convert it back to the normal
1632 relocation. */
1633 case BFD_RELOC_CTOR:
1634 fixp->fx_r_type = BFD_RELOC_32;
1635 break;
1636 }
1637
1638 if (non_pic_p)
1639 {
1640 DPRINTF1 (" (Non-pic relocation)\n");
1641 if (frv_pic_p)
1642 as_warn_where (fixp->fx_file, fixp->fx_line,
1643 _("Relocation %s is not safe for %s"),
1644 bfd_get_reloc_code_name (reloc), frv_pic_flag);
1645
1646 else if ((frv_flags & EF_FRV_NON_PIC_RELOCS) == 0)
1647 {
1648 frv_flags |= EF_FRV_NON_PIC_RELOCS;
1649 bfd_set_private_flags (abfd, frv_flags);
1650 }
1651 }
1652#ifdef DEBUG
1653 else
1654 DPRINTF1 ("\n");
1655#endif
1656 }
1657}
1658
1659/* After all of the symbols have been adjusted, go over the file looking
1660 for any relocations that pic won't support. */
1661
1662void
1663frv_frob_file ()
1664{
1665 bfd_map_over_sections (stdoutput, frv_frob_file_section, (PTR)0);
1666}
1667
1668void
1669frv_frob_label (this_label)
1670 symbolS *this_label;
1671{
1672 struct vliw_insn_list *vliw_insn_list_entry;
1673
1674 if (frv_mach != bfd_mach_frvtomcat)
1675 return;
1676
1677 if (now_seg != text_section)
1678 return;
1679
1680 vliw_insn_list_entry = frv_insert_vliw_insn(DONT_COUNT);
1681 vliw_insn_list_entry->type = VLIW_LABEL_TYPE;
1682 vliw_insn_list_entry->sym = this_label;
1683}
1684
1685fixS *
1686frv_cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp)
1687 fragS * frag;
1688 int where;
1689 const CGEN_INSN * insn;
1690 int length;
1691 const CGEN_OPERAND * operand;
1692 int opinfo;
1693 expressionS * exp;
1694{
1695 fixS * fixP = gas_cgen_record_fixup_exp (frag, where, insn, length,
1696 operand, opinfo, exp);
1697
1698 if (frv_mach == bfd_mach_frvtomcat
1699 && current_vliw_insn
1700 && current_vliw_insn->type == VLIW_BRANCH_TYPE
1701 && exp != NULL)
1702 current_vliw_insn->sym = exp->X_add_symbol;
1703
1704 return fixP;
1705}
This page took 0.153319 seconds and 4 git commands to generate.