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