x86: correct "-Q" option handling
[external/binutils.git] / gas / config / tc-mt.c
1 /* tc-mt.c -- Assembler for the Morpho Technologies mt .
2    Copyright (C) 2005-2019 Free Software Foundation, Inc.
3
4    This file is part of GAS, the GNU Assembler.
5
6    GAS is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3, or (at your option)
9    any later version.
10
11    GAS is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19    MA 02110-1301, USA.  */
20
21 #include "as.h"
22 #include "dwarf2dbg.h"
23 #include "subsegs.h"
24 #include "symcat.h"
25 #include "opcodes/mt-desc.h"
26 #include "opcodes/mt-opc.h"
27 #include "cgen.h"
28 #include "elf/common.h"
29 #include "elf/mt.h"
30
31 /* Structure to hold all of the different components
32    describing an individual instruction.  */
33 typedef struct
34 {
35   const CGEN_INSN *     insn;
36   const CGEN_INSN *     orig_insn;
37   CGEN_FIELDS           fields;
38 #if CGEN_INT_INSN_P
39   CGEN_INSN_INT         buffer [1];
40 #define INSN_VALUE(buf) (*(buf))
41 #else
42   unsigned char         buffer [CGEN_MAX_INSN_SIZE];
43 #define INSN_VALUE(buf) (buf)
44 #endif
45   char *                addr;
46   fragS *               frag;
47   int                   num_fixups;
48   fixS *                fixups [GAS_CGEN_MAX_FIXUPS];
49   int                   indices [MAX_OPERAND_INSTANCES];
50 }
51 mt_insn;
52
53
54 const char comment_chars[]        = ";";
55 const char line_comment_chars[]   = "#";
56 const char line_separator_chars[] = "";
57 const char EXP_CHARS[]            = "eE";
58 const char FLT_CHARS[]            = "dD";
59
60 /* The target specific pseudo-ops which we support.  */
61 const pseudo_typeS md_pseudo_table[] =
62 {
63     { "word",   cons,                   4 },
64     { NULL,     NULL,                   0 }
65 };
66
67 \f
68
69 static int no_scheduling_restrictions = 0;
70
71 struct option md_longopts[] =
72 {
73 #define OPTION_NO_SCHED_REST    (OPTION_MD_BASE)
74   { "nosched",     no_argument, NULL, OPTION_NO_SCHED_REST },
75 #define OPTION_MARCH            (OPTION_MD_BASE + 1)
76   { "march", required_argument, NULL, OPTION_MARCH},
77   { NULL,          no_argument, NULL, 0 },
78 };
79 size_t md_longopts_size = sizeof (md_longopts);
80
81 const char * md_shortopts = "";
82
83 /* Mach selected from command line.  */
84 static int mt_mach = bfd_mach_ms1;
85 static unsigned mt_mach_bitmask = 1 << MACH_MS1;
86
87 /* Flags to set in the elf header */
88 static flagword mt_flags = EF_MT_CPU_MRISC;
89
90 /* The architecture to use.  */
91 enum mt_architectures
92   {
93     ms1_64_001,
94     ms1_16_002,
95     ms1_16_003,
96     ms2
97   };
98
99 /* MT architecture we are using for this output file.  */
100 static enum mt_architectures mt_arch = ms1_16_002;
101
102 int
103 md_parse_option (int c ATTRIBUTE_UNUSED, const char * arg)
104 {
105   switch (c)
106     {
107     case OPTION_MARCH:
108       if (strcmp (arg, "ms1-64-001") == 0)
109         {
110           mt_flags = (mt_flags & ~EF_MT_CPU_MASK) | EF_MT_CPU_MRISC;
111           mt_mach = bfd_mach_ms1;
112           mt_mach_bitmask = 1 << MACH_MS1;
113           mt_arch = ms1_64_001;
114         }
115       else if (strcmp (arg, "ms1-16-002") == 0)
116         {
117           mt_flags = (mt_flags & ~EF_MT_CPU_MASK) | EF_MT_CPU_MRISC;
118           mt_mach = bfd_mach_ms1;
119           mt_mach_bitmask = 1 << MACH_MS1;
120           mt_arch = ms1_16_002;
121         }
122       else if (strcmp (arg, "ms1-16-003") == 0)
123         {
124           mt_flags = (mt_flags & ~EF_MT_CPU_MASK) | EF_MT_CPU_MRISC2;
125           mt_mach = bfd_mach_mrisc2;
126           mt_mach_bitmask = 1 << MACH_MS1_003;
127           mt_arch = ms1_16_003;
128         }
129       else if (strcmp (arg, "ms2") == 0)
130         {
131           mt_flags = (mt_flags & ~EF_MT_CPU_MASK) | EF_MT_CPU_MS2;
132           mt_mach = bfd_mach_mrisc2;
133           mt_mach_bitmask = 1 << MACH_MS2;
134           mt_arch = ms2;
135         }
136       break;
137     case OPTION_NO_SCHED_REST:
138       no_scheduling_restrictions = 1;
139       break;
140     default:
141       return 0;
142     }
143
144   return 1;
145 }
146
147
148 void
149 md_show_usage (FILE * stream)
150 {
151   fprintf (stream, _("MT specific command line options:\n"));
152   fprintf (stream, _("  -march=ms1-64-001         allow ms1-64-001 instructions\n"));
153   fprintf (stream, _("  -march=ms1-16-002         allow ms1-16-002 instructions (default)\n"));
154   fprintf (stream, _("  -march=ms1-16-003         allow ms1-16-003 instructions\n"));
155   fprintf (stream, _("  -march=ms2                allow ms2 instructions \n"));
156   fprintf (stream, _("  -nosched                  disable scheduling restrictions\n"));
157 }
158
159 \f
160 void
161 md_begin (void)
162 {
163   /* Initialize the `cgen' interface.  */
164
165   /* Set the machine number and endian.  */
166   gas_cgen_cpu_desc = mt_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, mt_mach_bitmask,
167                                         CGEN_CPU_OPEN_ENDIAN,
168                                         CGEN_ENDIAN_BIG,
169                                         CGEN_CPU_OPEN_END);
170   mt_cgen_init_asm (gas_cgen_cpu_desc);
171
172   /* This is a callback from cgen to gas to parse operands.  */
173   cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
174
175   /* Set the ELF flags if desired. */
176   if (mt_flags)
177     bfd_set_private_flags (stdoutput, mt_flags);
178
179   /* Set the machine type.  */
180   bfd_default_set_arch_mach (stdoutput, bfd_arch_mt, mt_mach);
181
182   literal_prefix_dollar_hex = TRUE;
183 }
184
185 void
186 md_assemble (char * str)
187 {
188   static long delayed_load_register = 0;
189   static long prev_delayed_load_register = 0;
190   static int last_insn_had_delay_slot = 0;
191   static int last_insn_in_noncond_delay_slot = 0;
192   static int last_insn_has_load_delay = 0;
193   static int last_insn_was_memory_access = 0;
194   static int last_insn_was_io_insn = 0;
195   static int last_insn_was_arithmetic_or_logic = 0;
196   static int last_insn_was_branch_insn = 0;
197   static int last_insn_was_conditional_branch_insn = 0;
198
199   mt_insn insn;
200   char * errmsg;
201
202   /* Initialize GAS's cgen interface for a new instruction.  */
203   gas_cgen_init_parse ();
204
205   insn.insn = mt_cgen_assemble_insn
206       (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
207
208   if (!insn.insn)
209     {
210       as_bad ("%s", errmsg);
211       return;
212     }
213
214   /* Doesn't really matter what we pass for RELAX_P here.  */
215   gas_cgen_finish_insn (insn.insn, insn.buffer,
216                         CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL);
217
218
219   /* Handle Scheduling Restrictions.  */
220   if (!no_scheduling_restrictions)
221     {
222       /* Detect consecutive Memory Accesses.  */
223       if (last_insn_was_memory_access
224           && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_MEMORY_ACCESS)
225           && mt_mach == ms1_64_001)
226         as_warn (_("instruction %s may not follow another memory access instruction."),
227                  CGEN_INSN_NAME (insn.insn));
228
229       /* Detect consecutive I/O Instructions.  */
230       else if (last_insn_was_io_insn
231                && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_IO_INSN))
232         as_warn (_("instruction %s may not follow another I/O instruction."),
233                  CGEN_INSN_NAME (insn.insn));
234
235       /* Detect consecutive branch instructions.  */
236       else if (last_insn_was_branch_insn
237                && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN))
238         as_warn (_("%s may not occupy the delay slot of another branch insn."),
239                  CGEN_INSN_NAME (insn.insn));
240
241       /* Detect data dependencies on delayed loads: memory and input insns.  */
242       if (last_insn_has_load_delay && delayed_load_register)
243         {
244           if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1)
245               && insn.fields.f_sr1 == delayed_load_register)
246             as_warn (_("operand references R%ld of previous load."),
247                      insn.fields.f_sr1);
248
249           if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2)
250               && insn.fields.f_sr2 == delayed_load_register)
251             as_warn (_("operand references R%ld of previous load."),
252                      insn.fields.f_sr2);
253         }
254
255       /* Detect JAL/RETI hazard */
256       if (mt_mach == ms2
257           && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_JAL_HAZARD))
258         {
259           if ((CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1)
260                && insn.fields.f_sr1 == delayed_load_register)
261               || (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2)
262                   && insn.fields.f_sr2 == delayed_load_register))
263             as_warn (_("operand references R%ld of previous instruction."),
264                      delayed_load_register);
265           else if ((CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1)
266                     && insn.fields.f_sr1 == prev_delayed_load_register)
267                    || (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2)
268                        && insn.fields.f_sr2 == prev_delayed_load_register))
269             as_warn (_("operand references R%ld of instruction before previous."),
270                      prev_delayed_load_register);
271         }
272
273       /* Detect data dependency between conditional branch instruction
274          and an immediately preceding arithmetic or logical instruction.  */
275       if (last_insn_was_arithmetic_or_logic
276           && !last_insn_in_noncond_delay_slot
277           && (delayed_load_register != 0)
278           && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN)
279           && mt_arch == ms1_64_001)
280         {
281           if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1)
282               && insn.fields.f_sr1 == delayed_load_register)
283             as_warn (_("conditional branch or jal insn's operand references R%ld of previous arithmetic or logic insn."),
284                      insn.fields.f_sr1);
285
286           if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2)
287               && insn.fields.f_sr2 == delayed_load_register)
288             as_warn (_("conditional branch or jal insn's operand references R%ld of previous arithmetic or logic insn."),
289                      insn.fields.f_sr2);
290         }
291     }
292
293   /* Keep track of details of this insn for processing next insn.  */
294   last_insn_in_noncond_delay_slot = last_insn_was_branch_insn
295     && !last_insn_was_conditional_branch_insn;
296
297   last_insn_had_delay_slot =
298     CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_DELAY_SLOT);
299   (void) last_insn_had_delay_slot;
300
301   last_insn_has_load_delay =
302     CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_LOAD_DELAY);
303
304   last_insn_was_memory_access =
305     CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_MEMORY_ACCESS);
306
307   last_insn_was_io_insn =
308     CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_IO_INSN);
309
310   last_insn_was_arithmetic_or_logic =
311     CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_AL_INSN);
312
313   last_insn_was_branch_insn =
314     CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN);
315
316   last_insn_was_conditional_branch_insn =
317   CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN)
318     && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2);
319
320   prev_delayed_load_register = delayed_load_register;
321
322   if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRDR))
323      delayed_load_register = insn.fields.f_dr;
324   else if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRDRRR))
325      delayed_load_register = insn.fields.f_drrr;
326   else  /* Insns has no destination register.  */
327      delayed_load_register = 0;
328
329   /* Generate dwarf2 line numbers.  */
330   dwarf2_emit_insn (4);
331 }
332
333 valueT
334 md_section_align (segT segment, valueT size)
335 {
336   int align = bfd_get_section_alignment (stdoutput, segment);
337
338   return ((size + (1 << align) - 1) & -(1 << align));
339 }
340
341 symbolS *
342 md_undefined_symbol (char * name ATTRIBUTE_UNUSED)
343 {
344     return NULL;
345 }
346 \f
347 int
348 md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED,
349                                segT    segment ATTRIBUTE_UNUSED)
350 {
351   as_fatal (_("md_estimate_size_before_relax\n"));
352   return 1;
353 }
354
355 /* *fragP has been relaxed to its final size, and now needs to have
356    the bytes inside it modified to conform to the new size.
357
358    Called after relaxation is finished.
359    fragP->fr_type == rs_machine_dependent.
360    fragP->fr_subtype is the subtype of what the address relaxed to.  */
361
362 void
363 md_convert_frag (bfd   * abfd  ATTRIBUTE_UNUSED,
364                  segT    sec   ATTRIBUTE_UNUSED,
365                  fragS * fragP ATTRIBUTE_UNUSED)
366 {
367 }
368
369 \f
370 /* Functions concerning relocs.  */
371
372 long
373 md_pcrel_from_section (fixS *fixP, segT sec)
374 {
375   if (fixP->fx_addsy != (symbolS *) NULL
376       && (!S_IS_DEFINED (fixP->fx_addsy)
377           || S_GET_SEGMENT (fixP->fx_addsy) != sec))
378     /* The symbol is undefined (or is defined but not in this section).
379        Let the linker figure it out.  */
380     return 0;
381
382   /* Return the address of the opcode - cgen adjusts for opcode size
383      itself, to be consistent with the disassembler, which must do
384      so.  */
385   return fixP->fx_where + fixP->fx_frag->fr_address;
386 }
387
388
389 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
390    Returns BFD_RELOC_NONE if no reloc type can be found.
391    *FIXP may be modified if desired.  */
392
393 bfd_reloc_code_real_type
394 md_cgen_lookup_reloc (const CGEN_INSN *    insn     ATTRIBUTE_UNUSED,
395                       const CGEN_OPERAND * operand,
396                       fixS *               fixP     ATTRIBUTE_UNUSED)
397 {
398   bfd_reloc_code_real_type result;
399
400   result = BFD_RELOC_NONE;
401
402   switch (operand->type)
403     {
404     case MT_OPERAND_IMM16O:
405       result = BFD_RELOC_16_PCREL;
406       fixP->fx_pcrel = 1;
407       /* fixP->fx_no_overflow = 1; */
408       break;
409     case MT_OPERAND_IMM16:
410     case MT_OPERAND_IMM16Z:
411       /* These may have been processed at parse time.  */
412       if (fixP->fx_cgen.opinfo != 0)
413         result = fixP->fx_cgen.opinfo;
414       fixP->fx_no_overflow = 1;
415       break;
416     case MT_OPERAND_LOOPSIZE:
417       result = BFD_RELOC_MT_PCINSN8;
418       fixP->fx_pcrel = 1;
419       /* Adjust for the delay slot, which is not part of the loop  */
420       fixP->fx_offset -= 8;
421       break;
422     default:
423       result = BFD_RELOC_NONE;
424       break;
425     }
426
427   return result;
428 }
429
430 /* Write a value out to the object file, using the appropriate endianness.  */
431
432 void
433 md_number_to_chars (char * buf, valueT val, int n)
434 {
435   number_to_chars_bigendian (buf, val, n);
436 }
437
438 const char *
439 md_atof (int type, char * litP, int * sizeP)
440 {
441   return ieee_md_atof (type, litP, sizeP, FALSE);
442 }
443
444 /* See whether we need to force a relocation into the output file.  */
445
446 int
447 mt_force_relocation (fixS * fixp ATTRIBUTE_UNUSED)
448 {
449   return 0;
450 }
451
452 void
453 mt_apply_fix (fixS *fixP, valueT *valueP, segT seg)
454 {
455   if ((fixP->fx_pcrel != 0) && (fixP->fx_r_type == BFD_RELOC_32))
456     fixP->fx_r_type = BFD_RELOC_32_PCREL;
457
458   gas_cgen_md_apply_fix (fixP, valueP, seg);
459 }
460
461 bfd_boolean
462 mt_fix_adjustable (fixS * fixP)
463 {
464   if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
465     {
466       const CGEN_INSN *insn = NULL;
467       int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
468       const CGEN_OPERAND *operand;
469
470       operand = cgen_operand_lookup_by_num(gas_cgen_cpu_desc, opindex);
471       md_cgen_lookup_reloc (insn, operand, fixP);
472     }
473
474   if (fixP->fx_addsy == NULL)
475     return TRUE;
476
477   /* Prevent all adjustments to global symbols.  */
478   if (S_IS_EXTERNAL (fixP->fx_addsy))
479     return FALSE;
480
481   if (S_IS_WEAK (fixP->fx_addsy))
482     return FALSE;
483
484   return 1;
485 }