/* tc-m32r.c -- Assembler for the Mitsubishi M32R.
- Copyright (C) 1996, 1997, 1998 Free Software Foundation.
+ Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation.
This file is part of GAS, the GNU Assembler.
#include "as.h"
#include "subsegs.h"
#include "symcat.h"
-#include "cgen-opc.h"
+#include "opcodes/m32r-desc.h"
+#include "opcodes/m32r-opc.h"
+#include "cgen.h"
-/* Structure to hold all of the different components describing an individual instruction. */
+/* Linked list of symbols that are debugging symbols to be defined as the
+ beginning of the current instruction. */
+typedef struct sym_link
+{
+ struct sym_link *next;
+ symbolS *symbol;
+} sym_linkS;
+
+static sym_linkS *debug_sym_link = (sym_linkS *)0;
+
+/* Structure to hold all of the different components describing
+ an individual instruction. */
typedef struct
{
const CGEN_INSN * insn;
const CGEN_INSN * orig_insn;
CGEN_FIELDS fields;
-#ifdef CGEN_INT_INSN
- cgen_insn_t buffer [CGEN_MAX_INSN_SIZE / sizeof (cgen_insn_t)];
+#if CGEN_INT_INSN_P
+ CGEN_INSN_INT buffer [1];
+#define INSN_VALUE(buf) (*(buf))
#else
- char buffer [CGEN_MAX_INSN_SIZE];
+ unsigned char buffer [CGEN_MAX_INSN_SIZE];
+#define INSN_VALUE(buf) (buf)
#endif
char * addr;
fragS * frag;
+ int num_fixups;
+ fixS * fixups [GAS_CGEN_MAX_FIXUPS];
int indices [MAX_OPERAND_INSTANCES];
+ sym_linkS *debug_sym_link;
}
m32r_insn;
This flag does not apply to them. */
static int m32r_relax;
+#if 0 /* not supported yet */
/* If non-NULL, pointer to cpu description file to read.
This allows runtime additions to the assembler. */
-static char * m32r_cpu_desc;
+static const char * m32r_cpu_desc;
+#endif
+
+/* Non-zero if warn when a high/shigh reloc has no matching low reloc.
+ Each high/shigh reloc must be paired with it's low cousin in order to
+ properly calculate the addend in a relocatable link (since there is a
+ potential carry from the low to the high/shigh).
+ This option is off by default though for user-written assembler code it
+ might make sense to make the default be on (i.e. have gcc pass a flag
+ to turn it off). This warning must not be on for GCC created code as
+ optimization may delete the low but not the high/shigh (at least we
+ shouldn't assume or require it to). */
+static int warn_unmatched_high = 0;
-/* start-sanitize-m32rx */
/* Non-zero if -m32rx has been specified, in which case support for the
extended M32RX instruction set should be enabled. */
static int enable_m32rx = 0;
+/* Non-zero if -m32rx -hidden has been specified, in which case support for
+ the special M32RX instruction set should be enabled. */
+static int enable_special = 0;
+
/* Non-zero if the programmer should be warned when an explicit parallel
instruction might have constraint violations. */
static int warn_explicit_parallel_conflicts = 1;
-/* start-sanitize-phase2-m32rx */
/* Non-zero if insns can be made parallel. */
static int optimize;
-/* end-sanitize-phase2-m32rx */
-/* end-sanitize-m32rx */
/* stuff for .scomm symbols. */
static segT sbss_section;
static struct m32r_hi_fixup * m32r_hi_fixup_list;
\f
-/* start-sanitize-m32rx */
static void
allow_m32rx (on)
int on;
bfd_set_arch_mach (stdoutput, TARGET_ARCH,
enable_m32rx ? bfd_mach_m32rx : bfd_mach_m32r);
}
-/* end-sanitize-m32rx */
\f
-#define M32R_SHORTOPTS ""
-/* start-sanitize-phase2-m32rx */
-#undef M32R_SHORTOPTS
#define M32R_SHORTOPTS "O"
-/* end-sanitize-phase2-m32rx */
const char * md_shortopts = M32R_SHORTOPTS;
struct option md_longopts[] =
{
-/* start-sanitize-m32rx */
#define OPTION_M32RX (OPTION_MD_BASE)
{"m32rx", no_argument, NULL, OPTION_M32RX},
-#define OPTION_WARN (OPTION_MD_BASE + 1)
- {"warn-explicit-parallel-conflicts", no_argument, NULL, OPTION_WARN},
- {"Wp", no_argument, NULL, OPTION_WARN},
-#define OPTION_NO_WARN (OPTION_MD_BASE + 2)
- {"no-warn-explicit-parallel-conflicts", no_argument, NULL, OPTION_NO_WARN},
- {"Wnp", no_argument, NULL, OPTION_NO_WARN},
-/* end-sanitize-m32rx */
+#define OPTION_WARN_PARALLEL (OPTION_MD_BASE + 1)
+ {"warn-explicit-parallel-conflicts", no_argument, NULL, OPTION_WARN_PARALLEL},
+ {"Wp", no_argument, NULL, OPTION_WARN_PARALLEL},
+#define OPTION_NO_WARN_PARALLEL (OPTION_MD_BASE + 2)
+ {"no-warn-explicit-parallel-conflicts", no_argument, NULL, OPTION_NO_WARN_PARALLEL},
+ {"Wnp", no_argument, NULL, OPTION_NO_WARN_PARALLEL},
+#define OPTION_SPECIAL (OPTION_MD_BASE + 3)
+ {"hidden", no_argument, NULL, OPTION_SPECIAL},
+
+ /* Sigh. I guess all warnings must now have both variants. */
+#define OPTION_WARN_UNMATCHED (OPTION_MD_BASE + 4)
+ {"warn-unmatched-high", no_argument, NULL, OPTION_WARN_UNMATCHED},
+ {"Wuh", no_argument, NULL, OPTION_WARN_UNMATCHED},
+#define OPTION_NO_WARN_UNMATCHED (OPTION_MD_BASE + 5)
+ {"no-warn-unmatched-high", no_argument, NULL, OPTION_NO_WARN_UNMATCHED},
+ {"Wnuh", no_argument, NULL, OPTION_NO_WARN_UNMATCHED},
#if 0 /* not supported yet */
-#define OPTION_RELAX (OPTION_MD_BASE + 3)
+#define OPTION_RELAX (OPTION_MD_BASE + 6)
{"relax", no_argument, NULL, OPTION_RELAX},
-#define OPTION_CPU_DESC (OPTION_MD_BASE + 4)
+#define OPTION_CPU_DESC (OPTION_MD_BASE + 7)
{"cpu-desc", required_argument, NULL, OPTION_CPU_DESC},
#endif
-
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof (md_longopts);
{
switch (c)
{
-/* start-sanitize-m32rx */
-/* start-sanitize-phase2-m32rx */
case 'O':
optimize = 1;
break;
-/* end-sanitize-phase2-m32rx */
case OPTION_M32RX:
allow_m32rx (1);
break;
- case OPTION_WARN:
+ case OPTION_WARN_PARALLEL:
warn_explicit_parallel_conflicts = 1;
break;
- case OPTION_NO_WARN:
+ case OPTION_NO_WARN_PARALLEL:
warn_explicit_parallel_conflicts = 0;
break;
-/* end-sanitize-m32rx */
+
+ case OPTION_SPECIAL:
+ if (enable_m32rx)
+ enable_special = 1;
+ else
+ {
+ /* Pretend that we do not recognise this option. */
+ as_bad (_("Unrecognised option: -hidden"));
+ return 0;
+ }
+ break;
+
+ case OPTION_WARN_UNMATCHED:
+ warn_unmatched_high = 1;
+ break;
+
+ case OPTION_NO_WARN_UNMATCHED:
+ warn_unmatched_high = 0;
+ break;
#if 0 /* not supported yet */
case OPTION_RELAX:
m32r_cpu_desc = arg;
break;
#endif
+
default:
return 0;
}
+
return 1;
}
md_show_usage (stream)
FILE * stream;
{
-/* start-sanitize-m32rx */
- fprintf (stream, _("M32R/X specific command line options:\n"));
+ fprintf (stream, _(" M32R specific command line options:\n"));
+
+ fprintf (stream, _("\
+ -m32rx support the extended m32rx instruction set\n"));
fprintf (stream, _("\
---m32rx support the extended m32rx instruction set\n"));
+ -O try to combine instructions in parallel\n"));
-/* start-sanitize-phase2-m32rx */
fprintf (stream, _("\
--O try to combine instructions in parallel\n"));
-/* end-sanitize-phase2-m32rx */
+ -warn-explicit-parallel-conflicts warn when parallel instructions\n"));
+ fprintf (stream, _("\
+ violate contraints\n"));
+ fprintf (stream, _("\
+ -no-warn-explicit-parallel-conflicts do not warn when parallel\n"));
+ fprintf (stream, _("\
+ instructions violate contraints\n"));
+ fprintf (stream, _("\
+ -Wp synonym for -warn-explicit-parallel-conflicts\n"));
+ fprintf (stream, _("\
+ -Wnp synonym for -no-warn-explicit-parallel-conflicts\n"));
fprintf (stream, _("\
---warn-explicit-parallel-conflicts warn when parallel instrucitons violate contraints\n"));
+ -warn-unmatched-high warn when an (s)high reloc has no matching low reloc\n"));
fprintf (stream, _("\
---no-warn-explicit-parallel-conflicts do not warn when parallel instrucitons violate contraints\n"));
+ -no-warn-unmatched-high do not warn about missing low relocs\n"));
fprintf (stream, _("\
---Wp synonym for --warn-explicit-parallel-conflicts\n"));
+ -Wuh synonym for -warn-unmatched-high\n"));
fprintf (stream, _("\
---Wnp synonym for --no-warn-explicit-parallel-conflicts\n"));
-/* end-sanitize-m32rx */
+ -Wnuh synonym for -no-warn-unmatched-high\n"));
#if 0
fprintf (stream, _("\
---relax create linker relaxable code\n"));
+ -relax create linker relaxable code\n"));
fprintf (stream, _("\
---cpu-desc provide runtime cpu description file\n"));
+ -cpu-desc provide runtime cpu description file\n"));
#endif
}
static void fill_insn PARAMS ((int));
static void m32r_scomm PARAMS ((int));
+static void debug_sym PARAMS ((int));
+static void expand_debug_syms PARAMS ((sym_linkS *, int));
/* Set by md_assemble for use by m32r_fill_insn. */
static subsegT prev_subseg;
/* The target specific pseudo-ops which we support. */
const pseudo_typeS md_pseudo_table[] =
{
- { "word", cons, 4 },
- { "fillinsn", fill_insn, 0 },
- { "scomm", m32r_scomm, 0 },
-/* start-sanitize-m32rx */
- { "m32r", allow_m32rx, 0},
- { "m32rx", allow_m32rx, 1},
-/* end-sanitize-m32rx */
+ { "word", cons, 4 },
+ { "fillinsn", fill_insn, 0 },
+ { "scomm", m32r_scomm, 0 },
+ { "debugsym", debug_sym, 0 },
+ /* Not documented as so far there is no need for them.... */
+ { "m32r", allow_m32rx, 0 },
+ { "m32rx", allow_m32rx, 1 },
{ NULL, NULL, 0 }
};
int len;
int max;
{
- if ((fill == NULL || (* fill == 0 && len == 1))
- && (now_seg->flags & SEC_CODE) != 0
+ /* Only do this if the fill pattern wasn't specified. */
+ if (fill == NULL
+ && subseg_text_p (now_seg)
/* Only do this special handling if aligning to at least a
4 byte boundary. */
&& n > 1
frag_align_pattern (n, multi_nop_pattern, sizeof multi_nop_pattern,
max ? max - 2 : 0);
}
+
+ prev_insn.insn = NULL;
return 1;
}
return 0;
}
-static void
-assemble_nop (opcode)
- int opcode;
-{
- char * f = frag_more (2);
- md_number_to_chars (f, opcode, 2);
-}
-
/* If the last instruction was the first of 2 16 bit insns,
output a nop to move the PC to a 32 bit boundary.
seen_relaxable_p = 0;
}
-/* Cover function to fill_insn called after a label and at end of assembly.
+/* Record the symbol so that when we output the insn, we can create
+ a symbol that is at the start of the instruction. This is used
+ to emit the label for the start of a breakpoint without causing
+ the assembler to emit a NOP if the previous instruction was a
+ 16 bit instruction. */
+static void
+debug_sym (ignore)
+ int ignore;
+{
+ register char *name;
+ register char delim;
+ register char *end_name;
+ register symbolS *symbolP;
+ register sym_linkS *link;
+
+ name = input_line_pointer;
+ delim = get_symbol_end ();
+ end_name = input_line_pointer;
+
+ if ((symbolP = symbol_find (name)) == NULL
+ && (symbolP = md_undefined_symbol (name)) == NULL)
+ {
+ symbolP = symbol_new (name, undefined_section, 0, &zero_address_frag);
+ }
+
+ symbol_table_insert (symbolP);
+ if (S_IS_DEFINED (symbolP) && S_GET_SEGMENT (symbolP) != reg_section)
+ /* xgettext:c-format */
+ as_bad (_("symbol `%s' already defined"), S_GET_NAME (symbolP));
+
+ else
+ {
+ link = (sym_linkS *) xmalloc (sizeof (sym_linkS));
+ link->symbol = symbolP;
+ link->next = debug_sym_link;
+ debug_sym_link = link;
+ symbol_get_obj (symbolP)->local = 1;
+ }
+
+ *end_name = delim;
+ demand_empty_rest_of_line ();
+}
+
+/* Second pass to expanding the debug symbols, go through linked
+ list of symbols and reassign the address. */
+
+static void
+expand_debug_syms (syms, align)
+ sym_linkS *syms;
+ int align;
+{
+ char *save_input_line = input_line_pointer;
+ sym_linkS *next_syms;
+
+ if (!syms)
+ return;
+
+ (void) m32r_do_align (align, NULL, 0, 0);
+ for (; syms != (sym_linkS *)0; syms = next_syms)
+ {
+ symbolS *symbolP = syms->symbol;
+ next_syms = syms->next;
+ input_line_pointer = ".\n";
+ pseudo_set (symbolP);
+ free ((char *)syms);
+ }
+
+ input_line_pointer = save_input_line;
+}
+
+/* Cover function to fill_insn called after a label and at end of assembly.
The result is always 1: we're called in a conditional to see if the
current line is a label. */
subseg_set (prev_seg, prev_subseg);
fill_insn (0);
-
+
subseg_set (seg, subseg);
}
-
+
+ if (done && debug_sym_link)
+ {
+ expand_debug_syms (debug_sym_link, 1);
+ debug_sym_link = (sym_linkS *)0;
+ }
+
return 1;
}
\f
subsegT subseg;
/* Initialize the `cgen' interface. */
-
- /* This is a callback from cgen to gas to parse operands. */
- cgen_parse_operand_fn = cgen_parse_operand;
/* Set the machine number and endian. */
- CGEN_SYM (init_asm) (0 /* mach number */,
- target_big_endian ?
- CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE);
+ gas_cgen_cpu_desc = m32r_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
+ CGEN_CPU_OPEN_ENDIAN,
+ CGEN_ENDIAN_BIG,
+ CGEN_CPU_OPEN_END);
+ m32r_cgen_init_asm (gas_cgen_cpu_desc);
+
+ /* The operand instance table is used during optimization to determine
+ which insns can be executed in parallel. It is also used to give
+ warnings regarding operand interference in parallel insns. */
+ m32r_cgen_init_opinst_table (gas_cgen_cpu_desc);
+
+ /* This is a callback from cgen to gas to parse operands. */
+ cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
#if 0 /* not supported yet */
/* If a runtime cpu description file was provided, parse it. */
{
const char * errmsg;
- errmsg = cgen_read_cpu_file (m32r_cpu_desc);
+ errmsg = cgen_read_cpu_file (gas_cgen_cpu_desc, m32r_cpu_desc);
if (errmsg != NULL)
as_bad ("%s: %s", m32r_cpu_desc, errmsg);
}
scom_symbol.name = ".scommon";
scom_symbol.section = & scom_section;
-/* start-sanitize-m32rx */
allow_m32rx (enable_m32rx);
-/* end-sanitize-m32rx */
}
-/* start-sanitize-m32rx */
+#define OPERAND_IS_COND_BIT(operand, indices, index) \
+ ((operand)->hw_type == HW_H_COND \
+ || ((operand)->hw_type == HW_H_PSW) \
+ || ((operand)->hw_type == HW_H_CR \
+ && (indices [index] == 0 || indices [index] == 1)))
-#define OPERAND_IS_COND_BIT(operand, indices, index) \
- (CGEN_OPERAND_INSTANCE_HW (operand)->type == HW_H_COND \
- || (CGEN_OPERAND_INSTANCE_HW (operand)->type == HW_H_CR \
- && (indices [index] == 0 || indices [index] == 1)))
-
/* Returns true if an output of instruction 'a' is referenced by an operand
of instruction 'b'. If 'check_outputs' is true then b's outputs are
checked, otherwise its inputs are examined. */
m32r_insn * b;
const int check_outputs;
{
- const CGEN_OPERAND_INSTANCE * a_operands = CGEN_INSN_OPERANDS (a->insn);
- const CGEN_OPERAND_INSTANCE * b_ops = CGEN_INSN_OPERANDS (b->insn);
- int a_index;
+ const CGEN_OPINST * a_operands = CGEN_INSN_OPERANDS (a->insn);
+ const CGEN_OPINST * b_ops = CGEN_INSN_OPERANDS (b->insn);
+ int a_index;
/* If at least one of the instructions takes no operands, then there is
nothing to check. There really are instructions without operands,
/* Scan the operand list of 'a' looking for an output operand. */
for (a_index = 0;
- CGEN_OPERAND_INSTANCE_TYPE (a_operands) != CGEN_OPERAND_INSTANCE_END;
+ a_operands->type != CGEN_OPINST_END;
a_index ++, a_operands ++)
{
- if (CGEN_OPERAND_INSTANCE_TYPE (a_operands) == CGEN_OPERAND_INSTANCE_OUTPUT)
+ if (a_operands->type == CGEN_OPINST_OUTPUT)
{
int b_index;
- const CGEN_OPERAND_INSTANCE * b_operands = b_ops;
+ const CGEN_OPINST * b_operands = b_ops;
/* Special Case:
The Condition bit 'C' is a shadow of the CBR register (control
/* Scan operand list of 'b' looking for another reference to the
condition bit, which goes in the right direction. */
for (b_index = 0;
- CGEN_OPERAND_INSTANCE_TYPE (b_operands) != CGEN_OPERAND_INSTANCE_END;
+ b_operands->type != CGEN_OPINST_END;
b_index ++, b_operands ++)
{
- if ((CGEN_OPERAND_INSTANCE_TYPE (b_operands) ==
- (check_outputs ? CGEN_OPERAND_INSTANCE_OUTPUT : CGEN_OPERAND_INSTANCE_INPUT))
+ if ((b_operands->type
+ == (check_outputs
+ ? CGEN_OPINST_OUTPUT
+ : CGEN_OPINST_INPUT))
&& OPERAND_IS_COND_BIT (b_operands, b->indices, b_index))
return 1;
}
}
else
{
- /* Scan operand list of 'b' looking for an operand that references
- the same hardware element, and which goes in the right direction. */
+ /* Scan operand list of 'b' looking for an operand that
+ references the same hardware element, and which goes in the
+ right direction. */
for (b_index = 0;
- CGEN_OPERAND_INSTANCE_TYPE (b_operands) != CGEN_OPERAND_INSTANCE_END;
+ b_operands->type != CGEN_OPINST_END;
b_index ++, b_operands ++)
{
- if ((CGEN_OPERAND_INSTANCE_TYPE (b_operands) ==
- (check_outputs ? CGEN_OPERAND_INSTANCE_OUTPUT : CGEN_OPERAND_INSTANCE_INPUT))
- && (CGEN_OPERAND_INSTANCE_HW (b_operands) == CGEN_OPERAND_INSTANCE_HW (a_operands))
+ if ((b_operands->type
+ == (check_outputs
+ ? CGEN_OPINST_OUTPUT
+ : CGEN_OPINST_INPUT))
+ && (b_operands->hw_type == a_operands->hw_type)
&& (a->indices [a_index] == b->indices [b_index]))
return 1;
}
}
}
- return 0;
+ return 0;
}
/* Returns true if the insn can (potentially) alter the program counter. */
m32r_insn * a;
{
#if 0 /* Once PC operands are working.... */
- const CGEN_OPERAND_INSTANCE * a_operands == CGEN_INSN_OPERANDS (a->insn);
+ const CGEN_OPINST * a_operands == CGEN_INSN_OPERANDS (gas_cgen_cpu_desc,
+ a->insn);
if (a_operands == NULL)
return 0;
- while (CGEN_OPERAND_INSTANCE_TYPE (a_operands) != CGEN_OPERAND_INSTANCE_END)
+ while (a_operands->type != CGEN_OPINST_END)
{
- if (CGEN_OPERAND_INSTANCE_OPERAND (a_operands) != NULL
- && CGEN_OPERAND_INDEX (CGEN_OPERAND_INSTANCE_OPERAND (a_operands)) == M32R_OPERAND_PC)
+ if (a_operands->operand != NULL
+ && CGEN_OPERAND_INDEX (gas_cgen_cpu_desc, a_operands->operand) == M32R_OPERAND_PC)
return 1;
a_operands ++;
}
#else
- if (CGEN_INSN_ATTR (a->insn, CGEN_INSN_UNCOND_CTI)
- || CGEN_INSN_ATTR (a->insn, CGEN_INSN_COND_CTI))
+ if (CGEN_INSN_ATTR_VALUE (a->insn, CGEN_INSN_UNCOND_CTI)
+ || CGEN_INSN_ATTR_VALUE (a->insn, CGEN_INSN_COND_CTI))
return 1;
#endif
return 0;
if (first_writes_to_seconds_operands (a, b, true))
return _("Instructions write to the same destination register.");
- a_pipe = CGEN_INSN_ATTR (a->insn, CGEN_INSN_PIPE);
- b_pipe = CGEN_INSN_ATTR (b->insn, CGEN_INSN_PIPE);
+ a_pipe = CGEN_INSN_ATTR_VALUE (a->insn, CGEN_INSN_PIPE);
+ b_pipe = CGEN_INSN_ATTR_VALUE (b->insn, CGEN_INSN_PIPE);
/* Make sure that the instructions use the correct execution pipelines. */
if ( a_pipe == PIPE_NONE
return NULL;
}
-#ifdef CGEN_INT_INSN
+/* Force the top bit of the second 16-bit insn to be set. */
+
static void
make_parallel (buffer)
- cgen_insn_t * buffer;
+ CGEN_INSN_BYTES_PTR buffer;
{
- /* Force the top bit of the second insn to be set. */
-
- bfd_vma value;
-
- if (CGEN_CURRENT_ENDIAN == CGEN_ENDIAN_BIG)
- {
- value = bfd_getb16 ((bfd_byte *) buffer);
- value |= 0x8000;
- bfd_putb16 (value, (char *) buffer);
- }
- else
- {
- value = bfd_getl16 ((bfd_byte *) buffer);
- value |= 0x8000;
- bfd_putl16 (value, (char *) buffer);
- }
-}
+#if CGEN_INT_INSN_P
+ *buffer |= 0x8000;
#else
+ buffer [CGEN_CPU_ENDIAN (gas_cgen_cpu_desc) == CGEN_ENDIAN_BIG ? 0 : 1]
+ |= 0x80;
+#endif
+}
+
+/* Same as make_parallel except buffer contains the bytes in target order. */
+
static void
-make_parallel (buffer)
- char * buffer;
+target_make_parallel (buffer)
+ char *buffer;
{
- /* Force the top bit of the second insn to be set. */
-
- buffer [CGEN_CURRENT_ENDIAN == CGEN_ENDIAN_BIG ? 0 : 1] |= 0x80;
+ buffer [CGEN_CPU_ENDIAN (gas_cgen_cpu_desc) == CGEN_ENDIAN_BIG ? 0 : 1]
+ |= 0x80;
}
-#endif
+/* Assemble two instructions with an explicit parallel operation (||) or
+ sequential operation (->). */
static void
-assemble_parallel_insn (str, str2)
+assemble_two_insns (str, str2, parallel_p)
char * str;
char * str2;
+ int parallel_p;
{
char * str3;
m32r_insn first;
m32r_insn second;
char * errmsg;
-
+ char save_str2 = *str2;
+
* str2 = 0; /* Seperate the two instructions. */
- /* If there was a previous 16 bit insn, then fill the following 16 bit slot,
- so that the parallel instruction will start on a 32 bit boundary. */
- if (prev_insn.insn)
- fill_insn (0);
+ /* Make sure the two insns begin on a 32 bit boundary.
+ This is also done for the serial case (foo -> bar), relaxing doesn't
+ affect insns written like this.
+ Note that we must always do this as we can't assume anything about
+ whether we're currently on a 32 bit boundary or not. Relaxing may
+ change this. */
+ fill_insn (0);
+
+ first.debug_sym_link = debug_sym_link;
+ debug_sym_link = (sym_linkS *)0;
/* Parse the first instruction. */
- if (! (first.insn = CGEN_SYM (assemble_insn)
- (str, & first.fields, first.buffer, & errmsg)))
+ if (! (first.insn = m32r_cgen_assemble_insn
+ (gas_cgen_cpu_desc, str, & first.fields, first.buffer, & errmsg)))
{
as_bad (errmsg);
return;
}
-
- /* Check to see if this is an allowable parallel insn. */
- if (CGEN_INSN_ATTR (first.insn, CGEN_INSN_PIPE) == PIPE_NONE)
+
+ /* Check it. */
+ if (CGEN_FIELDS_BITSIZE (&first.fields) != 16)
{
- as_bad (_("instruction '%s' cannot be executed in parallel."), str);
+ /* xgettext:c-format */
+ as_bad (_("not a 16 bit instruction '%s'"), str);
return;
}
-
- if (! enable_m32rx
- && CGEN_INSN_ATTR (first.insn, CGEN_INSN_MACH) == (1 << MACH_M32RX))
+ else if (! enable_special
+ && CGEN_INSN_ATTR_VALUE (first.insn, CGEN_INSN_SPECIAL))
{
+ /* xgettext:c-format */
+ as_bad (_("unknown instruction '%s'"), str);
+ return;
+ }
+ else if (! enable_m32rx
+ /* FIXME: Need standard macro to perform this test. */
+ && CGEN_INSN_ATTR_VALUE (first.insn, CGEN_INSN_MACH) == (1 << MACH_M32RX))
+ {
+ /* xgettext:c-format */
as_bad (_("instruction '%s' is for the M32RX only"), str);
return;
}
-
- /* Temporary Hack:
- If the instruciton is relaxable, reparse it looking for a non-relaxable variant.
- (We do not want to relax instructions inside a parallel construction, and if it
- turns out that the branch is too far for the displacement field available to the
- non-relaxed instruction, then this is the programmer's fault.
- A better solution would be to pass attribute requirements to assemble_insn() so
- that the relaxable variant would not be accepted as a valid parse of the instruction. */
-
- if (CGEN_INSN_ATTR (first.insn, CGEN_INSN_RELAXABLE) != 0)
+
+ /* Check to see if this is an allowable parallel insn. */
+ if (parallel_p && CGEN_INSN_ATTR_VALUE (first.insn, CGEN_INSN_PIPE) == PIPE_NONE)
{
- char buf[128];
- char * p;
- /* Oh dear - the insn is relaxable, so it might be replaced with a longer,
- non-parallel version. Try appending ".s" to the instruction and reparsing it. */
-
- p = strchr (str, ' ');
- if (p == NULL)
- abort();
- * p = 0;
- sprintf (buf, "%s.s %s", str, p + 1);
- * p = ' ';
-
- /* Reset fixup list to empty. */
- cgen_save_fixups();
-
- first.insn = CGEN_SYM (assemble_insn) (buf, & first.fields, first.buffer, & errmsg);
-
- if (first.insn == NULL)
- abort();
+ /* xgettext:c-format */
+ as_bad (_("instruction '%s' cannot be executed in parallel."), str);
+ return;
}
- *str2 = '|'; /* Restore the original assembly text, just in case it is needed. */
+ *str2 = save_str2; /* Restore the original assembly text, just in case it is needed. */
str3 = str; /* Save the original string pointer. */
str = str2 + 2; /* Advanced past the parsed string. */
str2 = str3; /* Remember the entire string in case it is needed for error messages. */
+
+ /* Convert the opcode to lower case. */
+ {
+ char *s2 = str;
+
+ while (isspace (*s2 ++))
+ continue;
+
+ --s2;
+
+ while (isalnum (*s2))
+ {
+ if (isupper ((unsigned char) *s2))
+ *s2 = tolower (*s2);
+ s2 ++;
+ }
+ }
/* Preserve any fixups that have been generated and reset the list to empty. */
- cgen_save_fixups();
+ gas_cgen_save_fixups ();
- /* Get the indicies of the operands of the instruction. */
+ /* Get the indices of the operands of the instruction. */
/* FIXME: CGEN_FIELDS is already recorded, but relying on that fact
doesn't seem right. Perhaps allow passing fields like we do insn. */
/* FIXME: ALIAS insns do not have operands, so we use this function
version (eg relaxability). When aliases behave differently this
may have to change. */
first.orig_insn = first.insn;
- first.insn = m32r_cgen_get_insn_operands (first.insn, bfd_getb16 ((char *) first.buffer), 16,
- first.indices);
+ {
+ CGEN_FIELDS tmp_fields;
+ first.insn = cgen_lookup_get_insn_operands
+ (gas_cgen_cpu_desc, NULL, INSN_VALUE (first.buffer), NULL, 16,
+ first.indices, &tmp_fields);
+ }
+
if (first.insn == NULL)
- as_fatal (_("internal error: m32r_cgen_get_insn_operands failed for first insn"));
+ as_fatal (_("internal error: lookup/get operands failed"));
+
+ second.debug_sym_link = NULL;
/* Parse the second instruction. */
- if (! (second.insn = CGEN_SYM (assemble_insn)
- (str, & second.fields, second.buffer, & errmsg)))
+ if (! (second.insn = m32r_cgen_assemble_insn
+ (gas_cgen_cpu_desc, str, & second.fields, second.buffer, & errmsg)))
{
as_bad (errmsg);
return;
}
/* Check it. */
- if (! enable_m32rx
- && CGEN_INSN_ATTR (second.insn, CGEN_INSN_MACH) == (1 << MACH_M32RX))
+ if (CGEN_FIELDS_BITSIZE (&second.fields) != 16)
+ {
+ /* xgettext:c-format */
+ as_bad (_("not a 16 bit instruction '%s'"), str);
+ return;
+ }
+ else if (! enable_special
+ && CGEN_INSN_ATTR_VALUE (second.insn, CGEN_INSN_SPECIAL))
+ {
+ /* xgettext:c-format */
+ as_bad (_("unknown instruction '%s'"), str);
+ return;
+ }
+ else if (! enable_m32rx
+ && CGEN_INSN_ATTR_VALUE (second.insn, CGEN_INSN_MACH) == (1 << MACH_M32RX))
{
+ /* xgettext:c-format */
as_bad (_("instruction '%s' is for the M32RX only"), str);
return;
}
+
+ /* Check to see if this is an allowable parallel insn. */
+ if (parallel_p && CGEN_INSN_ATTR_VALUE (second.insn, CGEN_INSN_PIPE) == PIPE_NONE)
+ {
+ /* xgettext:c-format */
+ as_bad (_("instruction '%s' cannot be executed in parallel."), str);
+ return;
+ }
- if (! enable_m32rx)
+ if (parallel_p && ! enable_m32rx)
{
- if ( strcmp (first.insn->name, "nop") != 0
- && strcmp (second.insn->name, "nop") != 0)
+ if (CGEN_INSN_NUM (first.insn) != M32R_INSN_NOP
+ && CGEN_INSN_NUM (second.insn) != M32R_INSN_NOP)
{
+ /* xgettext:c-format */
as_bad (_("'%s': only the NOP instruction can be issued in parallel on the m32r"), str2);
return;
}
}
- /* See comment above. */
- if (CGEN_INSN_ATTR (second.insn, CGEN_INSN_RELAXABLE) != 0)
- {
- char buf[128];
- char * p;
- /* Oh dear - the insn is relaxable, so it might be replaced with a longer,
- non-parallel version. Try appending ".s" to the instruction and reparsing it. */
-
- p = strchr (str, ' ');
- if (p == NULL)
- abort();
- * p = 0;
- sprintf (buf, "%s.s %s", str, p + 1);
- * p = ' ';
-
- /* Reset fixup list to empty, preserving saved fixups. */
- cgen_restore_fixups();
- cgen_save_fixups();
-
- second.insn = CGEN_SYM (assemble_insn) (buf, & second.fields, second.buffer, & errmsg);
-
- if (second.insn == NULL)
- abort();
- }
-
- /* Get the indicies of the operands of the instruction. */
+ /* Get the indices of the operands of the instruction. */
second.orig_insn = second.insn;
- second.insn = m32r_cgen_get_insn_operands (second.insn, bfd_getb16 ((char *) second.buffer), 16,
- second.indices);
+ {
+ CGEN_FIELDS tmp_fields;
+ second.insn = cgen_lookup_get_insn_operands
+ (gas_cgen_cpu_desc, NULL, INSN_VALUE (second.buffer), NULL, 16,
+ second.indices, &tmp_fields);
+ }
+
if (second.insn == NULL)
- as_fatal (_("internal error: m32r_cgen_get_insn_operands failed for second insn"));
+ as_fatal (_("internal error: lookup/get operands failed"));
/* We assume that if the first instruction writes to a register that is
read by the second instruction it is because the programmer intended
a warning message. Similarly we assume that parallel branch and jump
instructions are deliberate and should not produce errors. */
- if (warn_explicit_parallel_conflicts)
+ if (parallel_p && warn_explicit_parallel_conflicts)
{
if (first_writes_to_seconds_operands (& first, & second, false))
+ /* xgettext:c-format */
as_warn (_("%s: output of 1st instruction is the same as an input to 2nd instruction - is this intentional ?"), str2);
if (first_writes_to_seconds_operands (& second, & first, false))
+ /* xgettext:c-format */
as_warn (_("%s: output of 2nd instruction is the same as an input to 1st instruction - is this intentional ?"), str2);
}
- if ((errmsg = (char *) can_make_parallel (& first, & second)) == NULL)
+ if (!parallel_p
+ || (errmsg = (char *) can_make_parallel (& first, & second)) == NULL)
{
/* Get the fixups for the first instruction. */
- cgen_swap_fixups ();
+ gas_cgen_swap_fixups ();
/* Write it out. */
- (void) cgen_asm_finish_insn (first.orig_insn, first.buffer,
- CGEN_FIELDS_BITSIZE (& first.fields));
+ expand_debug_syms (first.debug_sym_link, 1);
+ gas_cgen_finish_insn (first.orig_insn, first.buffer,
+ CGEN_FIELDS_BITSIZE (& first.fields), 0, NULL);
/* Force the top bit of the second insn to be set. */
- make_parallel (second.buffer);
+ if (parallel_p)
+ make_parallel (second.buffer);
/* Get its fixups. */
- cgen_restore_fixups ();
+ gas_cgen_restore_fixups ();
/* Write it out. */
- (void) cgen_asm_finish_insn (second.orig_insn, second.buffer,
- CGEN_FIELDS_BITSIZE (& second.fields));
+ expand_debug_syms (second.debug_sym_link, 1);
+ gas_cgen_finish_insn (second.orig_insn, second.buffer,
+ CGEN_FIELDS_BITSIZE (& second.fields), 0, NULL);
}
/* Try swapping the instructions to see if they work that way. */
else if (can_make_parallel (& second, & first) == NULL)
{
/* Write out the second instruction first. */
- (void) cgen_asm_finish_insn (second.orig_insn, second.buffer,
- CGEN_FIELDS_BITSIZE (& second.fields));
+ expand_debug_syms (second.debug_sym_link, 1);
+ gas_cgen_finish_insn (second.orig_insn, second.buffer,
+ CGEN_FIELDS_BITSIZE (& second.fields), 0, NULL);
/* Force the top bit of the first instruction to be set. */
make_parallel (first.buffer);
/* Get the fixups for the first instruction. */
- cgen_restore_fixups ();
+ gas_cgen_restore_fixups ();
/* Write out the first instruction. */
- (void) cgen_asm_finish_insn (first.orig_insn, first.buffer,
- CGEN_FIELDS_BITSIZE (& first.fields));
+ expand_debug_syms (first.debug_sym_link, 1);
+ gas_cgen_finish_insn (first.orig_insn, first.buffer,
+ CGEN_FIELDS_BITSIZE (& first.fields), 0, NULL);
}
else
{
/* Set these so m32r_fill_insn can use them. */
prev_seg = now_seg;
prev_subseg = now_subseg;
-
- return;
}
-/* end-sanitize-m32rx */
-
-
void
md_assemble (str)
char * str;
char * str2 = NULL;
/* Initialize GAS's cgen interface for a new instruction. */
- cgen_asm_init_parse ();
+ gas_cgen_init_parse ();
-/* start-sanitize-m32rx */
/* Look for a parallel instruction seperator. */
if ((str2 = strstr (str, "||")) != NULL)
{
- assemble_parallel_insn (str, str2);
+ assemble_two_insns (str, str2, 1);
+ return;
+ }
+
+ /* Also look for a sequential instruction seperator. */
+ if ((str2 = strstr (str, "->")) != NULL)
+ {
+ assemble_two_insns (str, str2, 0);
return;
}
-/* end-sanitize-m32rx */
- insn.insn = CGEN_SYM (assemble_insn) (str, & insn.fields, insn.buffer, & errmsg);
+ insn.debug_sym_link = debug_sym_link;
+ debug_sym_link = (sym_linkS *)0;
+
+ insn.insn = m32r_cgen_assemble_insn
+ (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
+
if (!insn.insn)
{
as_bad (errmsg);
return;
}
-/* start-sanitize-m32rx */
- if (! enable_m32rx && CGEN_INSN_ATTR (insn.insn, CGEN_INSN_MACH) == (1 << MACH_M32RX))
+ if (! enable_special
+ && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_SPECIAL))
{
+ /* xgettext:c-format */
+ as_bad (_("unknown instruction '%s'"), str);
+ return;
+ }
+ else if (! enable_m32rx
+ && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_MACH) == (1 << MACH_M32RX))
+ {
+ /* xgettext:c-format */
as_bad (_("instruction '%s' is for the M32RX only"), str);
return;
}
-/* end-sanitize-m32rx */
if (CGEN_INSN_BITSIZE (insn.insn) == 32)
{
if (prev_insn.insn || seen_relaxable_p)
{
/* ??? If calling fill_insn too many times turns us into a memory
- pig, can we call assemble_nop instead of !seen_relaxable_p? */
+ pig, can we call a fn to assemble a nop instead of
+ !seen_relaxable_p? */
fill_insn (0);
}
-
- (void) cgen_asm_finish_insn (insn.insn, insn.buffer,
- CGEN_FIELDS_BITSIZE (& insn.fields));
+
+ expand_debug_syms (insn.debug_sym_link, 2);
+
+ /* Doesn't really matter what we pass for RELAX_P here. */
+ gas_cgen_finish_insn (insn.insn, insn.buffer,
+ CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL);
}
else
{
-/* start-sanitize-m32rx */
-/* start-sanitize-phase2-m32rx */
+ int on_32bit_boundary_p;
int swap = false;
-/* end-sanitize-phase2-m32rx */
-/* end-sanitize-m32rx */
-
+
if (CGEN_INSN_BITSIZE (insn.insn) != 16)
abort();
-
- /* Get the indices of the operands of the instruction. */
- insn.insn = m32r_cgen_get_insn_operands (insn.insn,
- bfd_getb16 ((char *) insn.buffer),
- 16,
- insn.indices);
- if (insn.insn == NULL)
- as_fatal (_("internal error: m32r_cgen_get_insn_operands failed"));
- /* Keep track of whether we've seen a pair of 16 bit insns.
- prev_insn.insn is NULL when we're on a 32 bit boundary. */
- if (prev_insn.insn)
+ insn.orig_insn = insn.insn;
+
+ /* If the previous insn was relaxable, then it may be expanded
+ to fill the current 16 bit slot. Emit a NOP here to occupy
+ this slot, so that we can start at optimizing at a 32 bit
+ boundary. */
+ if (prev_insn.insn && seen_relaxable_p && optimize)
+ fill_insn (0);
+
+ if (enable_m32rx)
{
-/* start-sanitize-m32rx */
-/* start-sanitize-phase2-m32rx */
- /* Look to see if this instruction can be combined with the
- previous instruction to make one, parallel, 32 bit instruction.
- If the previous instruction (potentially) changed the flow of
- program control, then it cannot be combined with the current
- instruction. If the current instruction is relaxable, then it
- might be replaced with a longer version, so we cannot combine it.
- Also if the output of the previous instruction is used as an
- input to the current instruction then it cannot be combined.
- Otherwise call can_make_parallel() with both orderings of the
- instructions to see if they can be combined. */
- if ( enable_m32rx
- && optimize
- && CGEN_INSN_ATTR (insn.insn, CGEN_INSN_RELAXABLE) == 0
- && ! writes_to_pc (& prev_insn)
- && ! first_writes_to_seconds_operands (& prev_insn, &insn, false)
- )
- {
- if (can_make_parallel (& prev_insn, & insn) == NULL)
- make_parallel (insn.buffer);
- else if (can_make_parallel (& insn, & prev_insn.insn) == NULL)
- swap = true;
- }
-/* end-sanitize-phase2-m32rx */
-/* end-sanitize-m32rx */
+ /* Get the indices of the operands of the instruction.
+ FIXME: See assemble_parallel for notes on orig_insn. */
+ {
+ CGEN_FIELDS tmp_fields;
+ insn.insn = cgen_lookup_get_insn_operands
+ (gas_cgen_cpu_desc, NULL, INSN_VALUE (insn.buffer), NULL,
+ 16, insn.indices, &tmp_fields);
+ }
- prev_insn.insn = NULL;
+ if (insn.insn == NULL)
+ as_fatal (_("internal error: lookup/get operands failed"));
}
- else
+
+ /* Compute whether we're on a 32 bit boundary or not.
+ prev_insn.insn is NULL when we're on a 32 bit boundary. */
+ on_32bit_boundary_p = prev_insn.insn == NULL;
+
+ /* Look to see if this instruction can be combined with the
+ previous instruction to make one, parallel, 32 bit instruction.
+ If the previous instruction (potentially) changed the flow of
+ program control, then it cannot be combined with the current
+ instruction. If the current instruction is relaxable, then it
+ might be replaced with a longer version, so we cannot combine it.
+ Also if the output of the previous instruction is used as an
+ input to the current instruction then it cannot be combined.
+ Otherwise call can_make_parallel() with both orderings of the
+ instructions to see if they can be combined. */
+ if ( ! on_32bit_boundary_p
+ && enable_m32rx
+ && optimize
+ && CGEN_INSN_ATTR_VALUE (insn.orig_insn, CGEN_INSN_RELAXABLE) == 0
+ && ! writes_to_pc (& prev_insn)
+ && ! first_writes_to_seconds_operands (& prev_insn, &insn, false)
+ )
{
- prev_insn = insn;
+ if (can_make_parallel (& prev_insn, & insn) == NULL)
+ make_parallel (insn.buffer);
+ else if (can_make_parallel (& insn, & prev_insn) == NULL)
+ swap = true;
}
- /* Record the frag that might be used by this insn. */
- insn.frag = frag_now;
- insn.addr = cgen_asm_finish_insn (insn.insn, insn.buffer,
- CGEN_FIELDS_BITSIZE (& insn.fields));
+ expand_debug_syms (insn.debug_sym_link, 1);
+
+ {
+ int i;
+ finished_insnS fi;
+
+ /* Ensure each pair of 16 bit insns is in the same frag. */
+ frag_grow (4);
+
+ gas_cgen_finish_insn (insn.orig_insn, insn.buffer,
+ CGEN_FIELDS_BITSIZE (& insn.fields),
+ 1 /*relax_p*/, &fi);
+ insn.addr = fi.addr;
+ insn.frag = fi.frag;
+ insn.num_fixups = fi.num_fixups;
+ for (i = 0; i < fi.num_fixups; ++i)
+ insn.fixups[i] = fi.fixups[i];
+ }
-/* start-sanitize-m32rx */
-/* start-sanitize-phase2-m32rx */
if (swap)
{
- int tmp;
-
+ int i,tmp;
+
#define SWAP_BYTES(a,b) tmp = a; a = b; b = tmp
/* Swap the two insns */
SWAP_BYTES (prev_insn.addr [0], insn.addr [0]);
SWAP_BYTES (prev_insn.addr [1], insn.addr [1]);
- make_parallel (insn.addr);
+ target_make_parallel (insn.addr);
/* Swap any relaxable frags recorded for the two insns. */
+ /* FIXME: Clarify. relaxation precludes parallel insns */
if (prev_insn.frag->fr_opcode == prev_insn.addr)
prev_insn.frag->fr_opcode = insn.addr;
else if (insn.frag->fr_opcode == insn.addr)
insn.frag->fr_opcode = prev_insn.addr;
+
+ /* Update the addresses in any fixups.
+ Note that we don't have to handle the case where each insn is in
+ a different frag as we ensure they're in the same frag above. */
+ for (i = 0; i < prev_insn.num_fixups; ++i)
+ prev_insn.fixups[i]->fx_where += 2;
+ for (i = 0; i < insn.num_fixups; ++i)
+ insn.fixups[i]->fx_where -= 2;
}
-/* end-sanitize-phase2-m32rx */
- /* Record where this instruction was assembled. */
- prev_insn.addr = insn.addr;
- prev_insn.frag = insn.frag;
-/* end-sanitize-m32rx */
+ /* Keep track of whether we've seen a pair of 16 bit insns.
+ prev_insn.insn is NULL when we're on a 32 bit boundary. */
+ if (on_32bit_boundary_p)
+ prev_insn = insn;
+ else
+ prev_insn.insn = NULL;
/* If the insn needs the following one to be on a 32 bit boundary
(e.g. subroutine calls), fill this insn's slot. */
- if (prev_insn.insn != NULL
- && CGEN_INSN_ATTR (insn.insn, CGEN_INSN_FILL_SLOT) != 0)
+ if (on_32bit_boundary_p
+ && CGEN_INSN_ATTR_VALUE (insn.orig_insn, CGEN_INSN_FILL_SLOT) != 0)
fill_insn (0);
/* If this is a relaxable insn (can be replaced with a larger version)
mark the fact so that we can emit an alignment directive for a
following 32 bit insn if we see one. */
- if (CGEN_INSN_ATTR (insn.insn, CGEN_INSN_RELAXABLE) != 0)
+ if (CGEN_INSN_ATTR_VALUE (insn.orig_insn, CGEN_INSN_RELAXABLE) != 0)
seen_relaxable_p = 1;
}
input_line_pointer ++; /* skip ',' */
if ((size = get_absolute_expression ()) < 0)
{
+ /* xgettext:c-format */
as_warn (_(".SCOMMon length (%ld.) <0! Ignored."), (long) size);
ignore_rest_of_line ();
return;
if (S_IS_DEFINED (symbolP))
{
+ /* xgettext:c-format */
as_bad (_("Ignoring attempt to re-define symbol `%s'."),
S_GET_NAME (symbolP));
ignore_rest_of_line ();
if (S_GET_VALUE (symbolP) && S_GET_VALUE (symbolP) != (valueT) size)
{
+ /* xgettext:c-format */
as_bad (_("Length of .scomm \"%s\" is already %ld. Not changed to %ld."),
S_GET_NAME (symbolP),
(long) S_GET_VALUE (symbolP),
return;
}
- if (symbolP->local)
+ if (symbol_get_obj (symbolP)->local)
{
segT old_sec = now_seg;
int old_subsec = now_subseg;
frag_align (align2, 0, 0);
if (S_GET_SEGMENT (symbolP) == sbss_section)
- symbolP->sy_frag->fr_symbol = 0;
+ symbol_get_frag (symbolP)->fr_symbol = 0;
- symbolP->sy_frag = frag_now;
+ symbol_set_frag (symbolP, frag_now);
pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, size,
(char *) 0);
segT segment;
{
int old_fr_fix = fragP->fr_fix;
- char * opcode = fragP->fr_opcode;
/* The only thing we have to handle here are symbols outside of the
current segment. They may be undefined or in a different segment in
#if 0 /* Can't use this, but leave in for illustration. */
/* Change 16 bit insn to 32 bit insn. */
- opcode[0] |= 0x80;
+ fragP->fr_opcode[0] |= 0x80;
/* Increase known (fixed) size of fragment. */
fragP->fr_fix += 2;
fragP->fr_symbol,
fragP->fr_offset, 1 /* pcrel */,
/* FIXME: Can't use a real BFD reloc here.
- cgen_md_apply_fix3 can't handle it. */
+ gas_cgen_md_apply_fix3 can't handle it. */
BFD_RELOC_M32R_26_PCREL);
/* Mark this fragment as finished. */
if ((strcmp (CGEN_INSN_MNEMONIC (insn),
CGEN_INSN_MNEMONIC (fragP->fr_cgen.insn))
== 0)
- && CGEN_INSN_ATTR (insn, CGEN_INSN_RELAX))
+ && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAX))
break;
}
if (i == 4)
{
/* Address we want to reach in file space. */
target_address = S_GET_VALUE (fragP->fr_symbol) + fragP->fr_offset;
- target_address += fragP->fr_symbol->sy_frag->fr_address;
+ target_address += symbol_get_frag (fragP->fr_symbol)->fr_address;
addend = (target_address - (opcode_address & -4)) >> 2;
}
{
assert (fragP->fr_subtype != 1);
assert (fragP->fr_cgen.insn != 0);
- cgen_record_fixup (fragP,
- /* Offset of branch insn in frag. */
- fragP->fr_fix + extension - 4,
- fragP->fr_cgen.insn,
- 4 /*length*/,
- /* FIXME: quick hack */
+ gas_cgen_record_fixup (fragP,
+ /* Offset of branch insn in frag. */
+ fragP->fr_fix + extension - 4,
+ fragP->fr_cgen.insn,
+ 4 /*length*/,
+ /* FIXME: quick hack */
#if 0
- CGEN_OPERAND_ENTRY (fragP->fr_cgen.opindex),
+ cgen_operand_lookup_by_num (gas_cgen_cpu_desc,
+ fragP->fr_cgen.opindex),
#else
- CGEN_OPERAND_ENTRY (M32R_OPERAND_DISP24),
+ cgen_operand_lookup_by_num (gas_cgen_cpu_desc,
+ M32R_OPERAND_DISP24),
#endif
- fragP->fr_cgen.opinfo,
- fragP->fr_symbol, fragP->fr_offset);
+ fragP->fr_cgen.opinfo,
+ fragP->fr_symbol, fragP->fr_offset);
}
#define SIZE_FROM_RELAX_STATE(n) ((n) == 1 ? 1 : 3)
*FIXP may be modified if desired. */
bfd_reloc_code_real_type
-CGEN_SYM (lookup_reloc) (insn, operand, fixP)
+md_cgen_lookup_reloc (insn, operand, fixP)
const CGEN_INSN * insn;
const CGEN_OPERAND * operand;
fixS * fixP;
{
- switch (CGEN_OPERAND_TYPE (operand))
+ switch (operand->type)
{
case M32R_OPERAND_DISP8 : return BFD_RELOC_M32R_10_PCREL;
case M32R_OPERAND_DISP16 : return BFD_RELOC_M32R_18_PCREL;
case M32R_OPERAND_SLO16 :
case M32R_OPERAND_ULO16 :
/* If low/high/shigh/sda was used, it is recorded in `opinfo'. */
- if (fixP->tc_fix_data.opinfo != 0)
- return fixP->tc_fix_data.opinfo;
+ if (fixP->fx_cgen.opinfo != 0)
+ return fixP->fx_cgen.opinfo;
+ break;
+ default : /* avoid -Wall warning */
break;
}
return BFD_RELOC_NONE;
int opinfo;
expressionS * exp;
{
- fixS * fixP = cgen_record_fixup_exp (frag, where, insn, length,
- operand, opinfo, exp);
+ fixS * fixP = gas_cgen_record_fixup_exp (frag, where, insn, length,
+ operand, opinfo, exp);
- switch (CGEN_OPERAND_TYPE (operand))
+ switch (operand->type)
{
case M32R_OPERAND_HI16 :
/* If low/high/shigh/sda was used, it is recorded in `opinfo'. */
- if (fixP->tc_fix_data.opinfo == BFD_RELOC_M32R_HI16_SLO
- || fixP->tc_fix_data.opinfo == BFD_RELOC_M32R_HI16_ULO)
- m32r_record_hi16 (fixP->tc_fix_data.opinfo, fixP, now_seg);
+ if (fixP->fx_cgen.opinfo == BFD_RELOC_M32R_HI16_SLO
+ || fixP->fx_cgen.opinfo == BFD_RELOC_M32R_HI16_ULO)
+ m32r_record_hi16 (fixP->fx_cgen.opinfo, fixP, now_seg);
+ break;
+ default : /* avoid -Wall warning */
break;
}
/* Return BFD reloc type from opinfo field in a fixS.
It's tricky using fx_r_type in m32r_frob_file because the values
are BFD_RELOC_UNUSED + operand number. */
-#define FX_OPINFO_R_TYPE(f) ((f)->tc_fix_data.opinfo)
+#define FX_OPINFO_R_TYPE(f) ((f)->fx_cgen.opinfo)
/* Sort any unmatched HI16 relocs so that they immediately precede
the corresponding LO16 reloc. This is called before md_apply_fix and
if (f != NULL)
break;
- if (pass == 1)
+ if (pass == 1
+ && warn_unmatched_high)
as_warn_where (l->fixp->fx_file, l->fixp->fx_line,
_("Unmatched high/shigh reloc"));
}
m32r_force_relocation (fix)
fixS * fix;
{
+ if (fix->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+ || fix->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+ return 1;
+
if (! m32r_relax)
return 0;
int i;
int prec;
LITTLENUM_TYPE words [MAX_LITTLENUMS];
- LITTLENUM_TYPE * wordP;
char * t;
char * atof_ieee ();
if (prev_insn.insn || seen_relaxable_p)
(void) m32r_fill_insn (0);
}
+
+boolean
+m32r_fix_adjustable (fixP)
+ fixS *fixP;
+{
+
+ if (fixP->fx_addsy == NULL)
+ return 1;
+
+ /* Prevent all adjustments to global symbols. */
+ if (S_IS_EXTERN (fixP->fx_addsy))
+ return 0;
+ if (S_IS_WEAK (fixP->fx_addsy))
+ return 0;
+
+ /* We need the symbol name for the VTABLE entries */
+ if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+ || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+ return 0;
+
+ return 1;
+}