#include "cgen-opc.h"
#include "as.h"
#include "subsegs.h"
+#include "cgen.h"
/* Callback to insert a register into the symbol table.
A target may choose to let GAS parse the registers.
void
cgen_asm_record_register (name, number)
char * name;
- int number;
+ int number;
{
/* Use symbol_create here instead of symbol_new so we don't try to
output registers into the object file's symbol table. */
struct fixup
{
- int opindex;
- int opinfo;
+ int opindex;
+ int opinfo;
expressionS exp;
};
-#define MAX_FIXUPS 5
-
-static struct fixup fixups [MAX_FIXUPS];
-static int num_fixups;
+static struct fixup fixups [CGEN_MAX_FIXUPS];
+static int num_fixups;
/* Prepare to parse an instruction.
??? May wish to make this static and delete calls in md_assemble. */
expressionS * expP;
{
/* We need to generate a fixup for this expression. */
- if (num_fixups >= MAX_FIXUPS)
+ if (num_fixups >= CGEN_MAX_FIXUPS)
as_fatal (_("too many fixups"));
fixups[num_fixups].exp = * expP;
fixups[num_fixups].opindex = opindex;
and to have this backup be swapped with the current chain. This allows
certain ports, eg the m32r, to swap two instructions and swap their fixups
at the same time. */
-static struct fixup saved_fixups [MAX_FIXUPS];
-static int saved_num_fixups;
+static struct fixup saved_fixups [CGEN_MAX_FIXUPS];
+static int saved_num_fixups;
void
cgen_save_fixups ()
void
cgen_swap_fixups ()
{
- int tmp;
+ int tmp;
struct fixup tmp_fixup;
if (num_fixups == 0)
saved_num_fixups = num_fixups;
num_fixups = tmp;
- for (tmp = MAX_FIXUPS; tmp--;)
+ for (tmp = CGEN_MAX_FIXUPS; tmp--;)
{
tmp_fixup = saved_fixups [tmp];
saved_fixups [tmp] = fixups [tmp];
const char *
cgen_parse_operand (want, strP, opindex, opinfo, resultP, valueP)
- enum cgen_parse_operand_type want;
- const char ** strP;
- int opindex;
- int opinfo;
+ enum cgen_parse_operand_type want;
+ const char ** strP;
+ int opindex;
+ int opinfo;
enum cgen_parse_operand_result * resultP;
- bfd_vma * valueP;
+ bfd_vma * valueP;
{
#ifdef __STDC__
- /* These is volatile to survive the setjmp. */
- char * volatile hold;
+ /* These are volatile to survive the setjmp. */
+ char * volatile hold;
enum cgen_parse_operand_result * volatile resultP_1;
#else
- static char * hold;
- static enum cgen_parse_operand_result * resultP_1;
+ static char * hold;
+ static enum cgen_parse_operand_result * resultP_1;
#endif
- const char * errmsg = NULL;
- expressionS exp;
+ const char * errmsg = NULL;
+ expressionS exp;
if (want == CGEN_PARSE_OPERAND_INIT)
{
/* Finish assembling instruction INSN.
BUF contains what we've built up so far.
LENGTH is the size of the insn in bits.
+ RELAX_P is non-zero if relaxable insns should be emitted as such.
+ Otherwise they're emitted in non-relaxable forms.
+ The "result" is stored in RESULT if non-NULL.
Returns the address of the buffer containing the assembled instruction,
in case the caller needs to modify it for some reason. */
-char *
-cgen_asm_finish_insn (insn, buf, length)
+void
+cgen_asm_finish_insn (insn, buf, length, relax_p, result)
const CGEN_INSN * insn;
- cgen_insn_t * buf;
- unsigned int length;
+ cgen_insn_t * buf;
+ unsigned int length;
+ int relax_p;
+ finished_insn * result;
{
- int i;
- int relax_operand;
- char * f;
+ int i;
+ int relax_operand;
+ char * f;
unsigned int byte_len = length / 8;
/* ??? Target foo issues various warnings here, so one might want to provide
/* Is there a relaxable insn with the relaxable operand needing a fixup? */
relax_operand = -1;
- if (CGEN_INSN_ATTR (insn, CGEN_INSN_RELAXABLE) != 0)
+ if (relax_p && CGEN_INSN_ATTR (insn, CGEN_INSN_RELAXABLE) != 0)
{
/* Scan the fixups for the operand affected by relaxing
(i.e. the branch address). */
if (relax_operand != -1)
{
- int max_len;
+ int max_len;
fragS * old_frag;
#ifdef TC_CGEN_MAX_RELAX
old_frag->fr_cgen.insn = insn;
old_frag->fr_cgen.opindex = fixups[relax_operand].opindex;
old_frag->fr_cgen.opinfo = fixups[relax_operand].opinfo;
+ if (result)
+ result->frag = old_frag;
}
else
- f = frag_more (byte_len);
+ {
+ f = frag_more (byte_len);
+ if (result)
+ result->frag = frag_now;
+ }
/* If we're recording insns as numbers (rather than a string of bytes),
target byte order handling is deferred until now. */
/* Create any fixups. */
for (i = 0; i < num_fixups; ++i)
{
+ fixS * fixP;
+
/* Don't create fixups for these. That's done during relaxation.
We don't need to test for CGEN_INSN_RELAX as they can't get here
(see above). */
- if (CGEN_INSN_ATTR (insn, CGEN_INSN_RELAXABLE) != 0
+ if (relax_p
+ && CGEN_INSN_ATTR (insn, CGEN_INSN_RELAXABLE) != 0
&& CGEN_OPERAND_ATTR (& CGEN_SYM (operand_table) [fixups[i].opindex],
CGEN_OPERAND_RELAX) != 0)
continue;
#define md_cgen_record_fixup_exp cgen_record_fixup_exp
#endif
- md_cgen_record_fixup_exp (frag_now, f - frag_now->fr_literal,
- insn, length,
- & CGEN_SYM (operand_table) [fixups[i].opindex],
- fixups[i].opinfo,
- & fixups[i].exp);
+ fixP = md_cgen_record_fixup_exp (frag_now, f - frag_now->fr_literal,
+ insn, length,
+ & CGEN_SYM (operand_table) [fixups[i].opindex],
+ fixups[i].opinfo,
+ & fixups[i].exp);
+ if (result)
+ result->fixups[i] = fixP;
}
- return f;
+ if (result)
+ {
+ result->num_fixups = num_fixups;
+ result->addr = f;
+ }
}
/* Apply a fixup to the object code. This is called for all the
#include "subsegs.h"
#include "symcat.h"
#include "cgen-opc.h"
+#include "cgen.h"
+/* 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
{
#endif
char * addr;
fragS * frag;
+ int num_fixups;
+ fixS * fixups [CGEN_MAX_FIXUPS];
int indices [MAX_OPERAND_INSTANCES];
+ sym_linkS *debug_sym_link;
}
m32r_insn;
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. */
/* end-sanitize-m32rx */
\f
#define M32R_SHORTOPTS ""
-/* start-sanitize-phase2-m32rx */
+/* start-sanitize-m32rx */
#undef M32R_SHORTOPTS
#define M32R_SHORTOPTS "O"
-/* end-sanitize-phase2-m32rx */
+/* end-sanitize-m32rx */
const char * md_shortopts = M32R_SHORTOPTS;
struct option 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);
fprintf (stream, _("\
--m32rx support the extended m32rx instruction set\n"));
-/* start-sanitize-phase2-m32rx */
fprintf (stream, _("\
-O try to combine instructions in parallel\n"));
-/* end-sanitize-phase2-m32rx */
fprintf (stream, _("\
--warn-explicit-parallel-conflicts warn when parallel instrucitons violate contraints\n"));
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 },
+ { "word", cons, 4 },
+ { "fillinsn", fill_insn, 0 },
+ { "scomm", m32r_scomm, 0 },
+ { "debugsym", debug_sym, 0 },
/* start-sanitize-m32rx */
- { "m32r", allow_m32rx, 0},
- { "m32rx", allow_m32rx, 1},
+ { "m32r", allow_m32rx, 0 },
+ { "m32rx", allow_m32rx, 1 },
/* end-sanitize-m32rx */
{ NULL, NULL, 0 }
};
seen_relaxable_p = 0;
}
+/* 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)
+ 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;
+ 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;
+ expressionS exp;
+
+ 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
if (prev_insn.insn)
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 == NULL)
as_fatal (_("internal error: m32r_cgen_lookup_get_insn_operands failed for first insn"));
+ second.debug_sym_link = NULL;
+
/* Parse the second instruction. */
if (! (second.insn = CGEN_SYM (assemble_insn)
(str, & second.fields, second.buffer, & errmsg)))
cgen_swap_fixups ();
/* Write it out. */
- (void) cgen_asm_finish_insn (first.orig_insn, first.buffer,
- CGEN_FIELDS_BITSIZE (& first.fields), 0);
+ expand_debug_syms (first.debug_sym_link, 1);
+ cgen_asm_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);
cgen_restore_fixups ();
/* Write it out. */
- (void) cgen_asm_finish_insn (second.orig_insn, second.buffer,
- CGEN_FIELDS_BITSIZE (& second.fields), 0);
+ expand_debug_syms (second.debug_sym_link, 1);
+ cgen_asm_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), 0);
+ expand_debug_syms (second.debug_sym_link, 1);
+ cgen_asm_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);
cgen_restore_fixups ();
/* Write out the first instruction. */
- (void) cgen_asm_finish_insn (first.orig_insn, first.buffer,
- CGEN_FIELDS_BITSIZE (& first.fields), 0);
+ expand_debug_syms (first.debug_sym_link, 1);
+ cgen_asm_finish_insn (first.orig_insn, first.buffer,
+ CGEN_FIELDS_BITSIZE (& first.fields), 0, NULL);
}
else
{
}
/* end-sanitize-m32rx */
+ insn.debug_sym_link = debug_sym_link;
+ debug_sym_link = (sym_linkS *)0;
+
insn.insn = CGEN_SYM (assemble_insn) (str, & insn.fields, insn.buffer, & errmsg);
if (!insn.insn)
{
fill_insn (0);
}
+ expand_debug_syms (insn.debug_sym_link, 2);
+
/* Doesn't really matter what we pass for RELAX_P here. */
- (void) cgen_asm_finish_insn (insn.insn, insn.buffer,
- CGEN_FIELDS_BITSIZE (& insn.fields), 1);
+ cgen_asm_finish_insn (insn.insn, insn.buffer,
+ CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL);
}
else
{
+ int on_32bit_boundary_p;
/* start-sanitize-m32rx */
-/* start-sanitize-phase2-m32rx */
int swap = false;
-/* end-sanitize-phase2-m32rx */
/* end-sanitize-m32rx */
if (CGEN_INSN_BITSIZE (insn.insn) != 16)
abort();
+ insn.orig_insn = insn.insn;
+/* start-sanitize-m32rx */
if (enable_m32rx)
{
/* Get the indices of the operands of the instruction.
FIXME: See assemble_parallel for notes on orig_insn. */
- insn.orig_insn = insn.insn;
insn.insn = m32r_cgen_lookup_get_insn_operands (NULL,
bfd_getb16 ((char *) insn.buffer),
16,
if (insn.insn == NULL)
as_fatal (_("internal error: m32r_cgen_get_insn_operands failed"));
}
- else
- insn.orig_insn = insn.insn;
+/* end-sanitize-m32rx */
- /* Keep track of whether we've seen a pair of 16 bit insns.
+ /* Compute whether we're on a 32 bit boundary or not.
prev_insn.insn is NULL when we're on a 32 bit boundary. */
- if (prev_insn.insn)
- {
-/* 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.orig_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) == NULL)
- swap = true;
- }
-/* end-sanitize-phase2-m32rx */
-/* end-sanitize-m32rx */
+ on_32bit_boundary_p = prev_insn.insn == NULL;
- prev_insn.insn = NULL;
- }
- else
+/* start-sanitize-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 ( ! on_32bit_boundary_p
+ && enable_m32rx
+ && optimize
+ && CGEN_INSN_ATTR (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;
}
+/* end-sanitize-m32rx */
+
+ expand_debug_syms (insn.debug_sym_link, 1);
- /* Record the frag that might be used by this insn. */
- insn.frag = frag_now;
- insn.addr = cgen_asm_finish_insn (insn.orig_insn, insn.buffer,
- CGEN_FIELDS_BITSIZE (& insn.fields),
- 1 /*relax_p*/);
+ {
+ int i;
+ finished_insnS fi;
+
+ /* Ensure each pair of 16 bit insns is in the same frag. */
+ frag_grow (4);
+
+ cgen_asm_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
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;
- }
-/* end-sanitize-phase2-m32rx */
- /* Record where this instruction was assembled. */
- prev_insn.addr = insn.addr;
- prev_insn.frag = insn.frag;
+ /* 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-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
+ if (on_32bit_boundary_p
&& CGEN_INSN_ATTR (insn.orig_insn, CGEN_INSN_FILL_SLOT) != 0)
fill_insn (0);