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