-/* tc-m32r.c -- Assembler for the Mitsubishi M32R.
- Copyright (C) 1996, 1997, 1998, 1999, 2000
+/* tc-m32r.c -- Assembler for the Renesas M32R.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
Boston, MA 02111-1307, USA. */
#include <stdio.h>
-#include <ctype.h>
#include "as.h"
+#include "safe-ctype.h"
#include "subsegs.h"
#include "symcat.h"
#include "opcodes/m32r-desc.h"
static struct m32r_hi_fixup *m32r_hi_fixup_list;
\f
+static void allow_m32rx PARAMS ((int));
+
static void
allow_m32rx (on)
int on;
int
md_parse_option (c, arg)
int c;
- char *arg;
+ char *arg ATTRIBUTE_UNUSED;
{
switch (c)
{
#define NOP_INSN 0x7000
#define PAR_NOP_INSN 0xf000 /* Can only be used in 2nd slot. */
-/* When we align the .text section, insert the correct NOP pattern.
- N is the power of 2 alignment. LEN is the length of pattern FILL.
- MAX is the maximum number of characters to skip when doing the alignment,
- or 0 if there is no maximum. */
+/* This is called from HANDLE_ALIGN in write.c. Fill in the contents
+ of an rs_align_code fragment. */
-int
-m32r_do_align (n, fill, len, max)
- int n;
- const char *fill;
- int len;
- int max;
+void
+m32r_handle_align (fragp)
+ fragS *fragp;
{
- /* 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
- /* Only do this special handling if we're allowed to emit at
- least two bytes. */
- && (max == 0 || max > 1))
- {
- static const unsigned char nop_pattern[] = { 0xf0, 0x00 };
+ static const unsigned char nop_pattern[] = { 0xf0, 0x00 };
+ static const unsigned char multi_nop_pattern[] = { 0x70, 0x00, 0xf0, 0x00 };
-#if 0
- /* First align to a 2 byte boundary, in case there is an odd .byte. */
- /* FIXME: How much memory will cause gas to use when assembling a big
- program? Perhaps we can avoid the frag_align call? */
- frag_align (1, 0, 0);
-#endif
- /* Next align to a 4 byte boundary (we know n >= 2) using a parallel
- nop. */
- frag_align_pattern (2, nop_pattern, sizeof nop_pattern, 0);
- /* If doing larger alignments use a repeating sequence of appropriate
- nops. */
- if (n > 2)
- {
- static const unsigned char multi_nop_pattern[] =
- { 0x70, 0x00, 0xf0, 0x00 };
- frag_align_pattern (n, multi_nop_pattern, sizeof multi_nop_pattern,
- max ? max - 2 : 0);
- }
+ int bytes, fix;
+ char *p;
- prev_insn.insn = NULL;
- return 1;
+ if (fragp->fr_type != rs_align_code)
+ return;
+
+ bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
+ p = fragp->fr_literal + fragp->fr_fix;
+ fix = 0;
+
+ if (bytes & 1)
+ {
+ fix = 1;
+ *p++ = 0;
+ bytes--;
}
- return 0;
+ if (bytes & 2)
+ {
+ memcpy (p, nop_pattern, 2);
+ p += 2;
+ bytes -= 2;
+ fix += 2;
+ }
+
+ memcpy (p, multi_nop_pattern, 4);
+
+ fragp->fr_fix += fix;
+ fragp->fr_var = 4;
}
/* If the last instruction was the first of 2 16 bit insns,
static void
fill_insn (ignore)
- int ignore;
+ int ignore ATTRIBUTE_UNUSED;
{
- (void) m32r_do_align (2, NULL, 0, 0);
+ frag_align_code (2, 0);
prev_insn.insn = NULL;
seen_relaxable_p = 0;
}
static void
debug_sym (ignore)
- int ignore;
+ int ignore ATTRIBUTE_UNUSED;
{
register char *name;
register char delim;
if (!syms)
return;
- (void) m32r_do_align (align, NULL, 0, 0);
+ (void) frag_align_code (align, 0);
for (; syms != (sym_linkS *) 0; syms = next_syms)
{
symbolS *symbolP = syms->symbol;
scom_symbol.section = &scom_section;
allow_m32rx (enable_m32rx);
+
+ gas_cgen_initialize_saved_fixups_array ();
}
#define OPERAND_IS_COND_BIT(operand, indices, index) \
of instruction 'b'. If 'check_outputs' is true then b's outputs are
checked, otherwise its inputs are examined. */
+static int first_writes_to_seconds_operands
+ PARAMS ((m32r_insn *, m32r_insn *, const int));
+
static int
first_writes_to_seconds_operands (a, b, check_outputs)
m32r_insn *a;
/* Returns true if the insn can (potentially) alter the program counter. */
+static int writes_to_pc PARAMS ((m32r_insn *));
+
static int
writes_to_pc (a)
m32r_insn *a;
/* Return NULL if the two 16 bit insns can be executed in parallel.
Otherwise return a pointer to an error message explaining why not. */
+static const char *can_make_parallel PARAMS ((m32r_insn *, m32r_insn *));
+
static const char *
can_make_parallel (a, b)
m32r_insn *a;
|| CGEN_FIELDS_BITSIZE (&b->fields) != 16)
abort ();
- if (first_writes_to_seconds_operands (a, b, true))
+ if (first_writes_to_seconds_operands (a, b, TRUE))
return _("Instructions write to the same destination register.");
a_pipe = CGEN_INSN_ATTR_VALUE (a->insn, CGEN_INSN_PIPE);
/* Force the top bit of the second 16-bit insn to be set. */
+static void make_parallel PARAMS ((CGEN_INSN_BYTES_PTR));
+
static void
make_parallel (buffer)
CGEN_INSN_BYTES_PTR buffer;
/* Same as make_parallel except buffer contains the bytes in target order. */
+static void target_make_parallel PARAMS ((char *));
+
static void
target_make_parallel (buffer)
char *buffer;
/* Assemble two instructions with an explicit parallel operation (||) or
sequential operation (->). */
+static void assemble_two_insns PARAMS ((char *, char *, int));
+
static void
assemble_two_insns (str, str2, parallel_p)
char *str;
{
char *s2 = str;
- while (isspace (*s2++))
+ while (ISSPACE (*s2++))
continue;
--s2;
- while (isalnum (*s2))
+ while (ISALNUM (*s2))
{
- if (isupper ((unsigned char) *s2))
- *s2 = tolower (*s2);
+ *s2 = TOLOWER (*s2);
s2++;
}
}
/* Preserve any fixups that have been generated and reset the list
to empty. */
- gas_cgen_save_fixups ();
+ gas_cgen_save_fixups (0);
/* Get the indices of the operands of the instruction. */
/* FIXME: CGEN_FIELDS is already recorded, but relying on that fact
if (parallel_p && warn_explicit_parallel_conflicts)
{
- if (first_writes_to_seconds_operands (&first, &second, false))
+ 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))
+ 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);
}
|| (errmsg = (char *) can_make_parallel (&first, &second)) == NULL)
{
/* Get the fixups for the first instruction. */
- gas_cgen_swap_fixups ();
+ gas_cgen_swap_fixups (0);
/* Write it out. */
expand_debug_syms (first.debug_sym_link, 1);
make_parallel (second.buffer);
/* Get its fixups. */
- gas_cgen_restore_fixups ();
+ gas_cgen_restore_fixups (0);
/* Write it out. */
expand_debug_syms (second.debug_sym_link, 1);
make_parallel (first.buffer);
/* Get the fixups for the first instruction. */
- gas_cgen_restore_fixups ();
+ gas_cgen_restore_fixups (0);
/* Write out the first instruction. */
expand_debug_syms (first.debug_sym_link, 1);
else
{
int on_32bit_boundary_p;
- int swap = false;
+ int swap = FALSE;
if (CGEN_INSN_BITSIZE (insn.insn) != 16)
abort ();
&& 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))
+ && ! 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) == NULL)
- swap = true;
+ swap = TRUE;
}
expand_debug_syms (insn.debug_sym_link, 1);
symbolS *
md_undefined_symbol (name)
- char *name;
+ char *name ATTRIBUTE_UNUSED;
{
return 0;
}
static void
m32r_scomm (ignore)
- int ignore;
+ int ignore ATTRIBUTE_UNUSED;
{
register char *name;
register char c;
};
long
-m32r_relax_frag (fragP, stretch)
+m32r_relax_frag (segment, fragP, stretch)
+ segT segment;
fragS *fragP;
long stretch;
{
}
else
{
- growth = relax_frag (fragP, stretch);
+ growth = relax_frag (segment, fragP, stretch);
/* Long jump on odd halfword boundary? */
if (fragP->fr_subtype == 2 && (address & 3) != 0)
fragS *fragP;
segT segment;
{
- int old_fr_fix = fragP->fr_fix;
-
/* 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
which case linker scripts may place them anywhere.
if (S_GET_SEGMENT (fragP->fr_symbol) != segment)
{
+#if 0
+ int old_fr_fix = fragP->fr_fix;
+#endif
+
/* The symbol is undefined in this segment.
Change the relaxation subtype to the max allowable and leave
all further handling to md_convert_frag. */
/* Mark this fragment as finished. */
frag_wane (fragP);
+ return fragP->fr_fix - old_fr_fix;
#else
{
const CGEN_INSN *insn;
if ((strcmp (CGEN_INSN_MNEMONIC (insn),
CGEN_INSN_MNEMONIC (fragP->fr_cgen.insn))
== 0)
- && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAX))
+ && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED))
break;
}
if (i == 4)
#endif
}
- return (fragP->fr_var + fragP->fr_fix - old_fr_fix);
+ return md_relax_table[fragP->fr_subtype].rlx_length;
}
/* *FRAGP has been relaxed to its final size, and now needs to have
void
md_convert_frag (abfd, sec, fragP)
- bfd *abfd;
+ bfd *abfd ATTRIBUTE_UNUSED;
segT sec;
fragS *fragP;
{
{
/* Address we want to reach in file space. */
target_address = S_GET_VALUE (fragP->fr_symbol) + fragP->fr_offset;
- target_address += symbol_get_frag (fragP->fr_symbol)->fr_address;
addend = (target_address - (opcode_address & -4)) >> 2;
}
bfd_reloc_code_real_type
md_cgen_lookup_reloc (insn, operand, fixP)
- const CGEN_INSN *insn;
+ const CGEN_INSN *insn ATTRIBUTE_UNUSED;
const CGEN_OPERAND *operand;
fixS *fixP;
{
/* Record a HI16 reloc for later matching with its LO16 cousin. */
+static void m32r_record_hi16 PARAMS ((int, fixS *, segT));
+
static void
m32r_record_hi16 (reloc_type, fixP, seg)
int reloc_type;
fixS *fixP;
- segT seg;
+ segT seg ATTRIBUTE_UNUSED;
{
struct m32r_hi_fixup *hi_fixup;
#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
+ the corresponding LO16 reloc. This is called before md_apply_fix3 and
tc_gen_reloc. */
void
m32r_force_relocation (fix)
fixS *fix;
{
- if (fix->fx_r_type == BFD_RELOC_VTABLE_INHERIT
- || fix->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+ if (generic_force_reloc (fix))
return 1;
if (! m32r_relax)
int prec;
LITTLENUM_TYPE words[MAX_LITTLENUMS];
char *t;
- char *atof_ieee ();
switch (type)
{
/* Return true if can adjust the reloc to be relative to its section
(such as .data) instead of relative to some symbol. */
-boolean
+bfd_boolean
m32r_fix_adjustable (fixP)
fixS *fixP;
{
-
bfd_reloc_code_real_type reloc_type;
if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
else
reloc_type = fixP->fx_r_type;
- 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 (reloc_type == BFD_RELOC_VTABLE_INHERIT
|| reloc_type == BFD_RELOC_VTABLE_ENTRY)