* cgen.h: New file.

* cgen.c: Include it.
	(MAX_FIXUPS): Renamed to CGEN_MAX_FIXUPS.
	(cgen_asm_finish_insn): Result is now void.  New arg `result'.
	All callers updated.
	* config/tc-m32r.c: Include cgen.h.
	(m23r_insn): New members num_fixups,fixups.
	(assemble_parallel_insn): Initialize debug_sym_link for each insn.
	(md_assemble): Simplify code to pack two insns in parallel.
	When swapping two insns, update their fixups.
This commit is contained in:
Doug Evans 1998-05-07 09:31:42 +00:00
parent e2d7426296
commit defc70bf2b
4 changed files with 263 additions and 118 deletions

View file

@ -51,6 +51,7 @@ bignum-copy.c
bignum.h
bit_fix.h
cgen.c
cgen.h
cond.c
config
config-gas.com

View file

@ -1,3 +1,18 @@
Thu May 7 02:19:14 1998 Doug Evans <devans@charmed.cygnus.com>
* cgen.h: New file.
* cgen.c: Include it.
(MAX_FIXUPS): Renamed to CGEN_MAX_FIXUPS.
(cgen_asm_finish_insn): Result is now void. New arg `result'.
All callers updated.
* config/tc-m32r.c: Include cgen.h.
(m23r_insn): New members num_fixups,fixups.
start-sanitize-m32rx
(assemble_parallel_insn): Initialize debug_sym_link for each insn.
(md_assemble): Simplify code to pack two insns in parallel.
When swapping two insns, update their fixups.
end-sanitize-m32rx
start-sanitize-sky
Wed May 6 16:26:57 1998 Doug Evans <devans@canuck.cygnus.com>

View file

@ -24,6 +24,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#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.
@ -32,7 +33,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
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. */
@ -53,15 +54,13 @@ cgen_asm_record_register (name, number)
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. */
@ -80,7 +79,7 @@ cgen_queue_fixup (opindex, opinfo, expP)
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;
@ -92,8 +91,8 @@ cgen_queue_fixup (opindex, opinfo, expP)
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 ()
@ -118,7 +117,7 @@ cgen_restore_fixups ()
void
cgen_swap_fixups ()
{
int tmp;
int tmp;
struct fixup tmp_fixup;
if (num_fixups == 0)
@ -135,7 +134,7 @@ cgen_swap_fixups ()
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];
@ -235,23 +234,23 @@ static jmp_buf expr_jmp_buf;
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)
{
@ -322,18 +321,23 @@ cgen_md_operand (expressionP)
/* 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
@ -354,7 +358,7 @@ cgen_asm_finish_insn (insn, buf, length)
/* 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). */
@ -372,7 +376,7 @@ cgen_asm_finish_insn (insn, buf, length)
if (relax_operand != -1)
{
int max_len;
int max_len;
fragS * old_frag;
#ifdef TC_CGEN_MAX_RELAX
@ -405,9 +409,15 @@ cgen_asm_finish_insn (insn, buf, length)
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. */
@ -436,10 +446,13 @@ cgen_asm_finish_insn (insn, buf, length)
/* 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;
@ -448,14 +461,20 @@ cgen_asm_finish_insn (insn, buf, length)
#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

View file

@ -24,7 +24,18 @@
#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
{
@ -38,7 +49,10 @@ 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;
@ -69,10 +83,8 @@ static int enable_m32rx = 0;
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. */
@ -124,10 +136,10 @@ allow_m32rx (on)
/* end-sanitize-m32rx */
#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[] =
@ -162,11 +174,9 @@ md_parse_option (c, arg)
switch (c)
{
/* start-sanitize-m32rx */
/* start-sanitize-phase2-m32rx */
case 'O':
optimize = 1;
break;
/* end-sanitize-phase2-m32rx */
case OPTION_M32RX:
allow_m32rx (1);
@ -204,10 +214,8 @@ md_show_usage (stream)
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"));
@ -229,6 +237,8 @@ md_show_usage (stream)
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;
@ -237,12 +247,13 @@ static segT prev_seg;
/* 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 }
};
@ -324,6 +335,77 @@ fill_insn (ignore)
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
@ -608,6 +690,9 @@ assemble_parallel_insn (str, str2)
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)))
@ -656,6 +741,8 @@ assemble_parallel_insn (str, str2)
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)))
@ -721,8 +808,9 @@ assemble_parallel_insn (str, str2)
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);
@ -731,15 +819,17 @@ assemble_parallel_insn (str, str2)
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);
@ -748,8 +838,9 @@ assemble_parallel_insn (str, str2)
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
{
@ -785,6 +876,9 @@ md_assemble (str)
}
/* 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)
{
@ -810,26 +904,28 @@ md_assemble (str)
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,
@ -837,58 +933,61 @@ md_assemble (str)
if (insn.insn == NULL)
as_fatal (_("internal error: m32r_cgen_get_insn_operands failed"));
}
else
insn.orig_insn = insn.insn;
/* 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)
{
/* 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 */
prev_insn.insn = NULL;
}
else
{
prev_insn = insn;
}
/* 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*/);
/* 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;
/* 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)
)
{
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);
{
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
@ -899,21 +998,32 @@ md_assemble (str)
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);