Fixed infinite loop bug in can_make_parallel().
Added second level of sanization to remove phase 2 work.
This commit is contained in:
parent
d001edb7ba
commit
b6930bdf46
3 changed files with 363 additions and 221 deletions
|
@ -1,3 +1,12 @@
|
|||
start-sanitize-m32rx
|
||||
Mon Jan 26 12:38:54 1998 Nick Clifton <nickc@cygnus.com>
|
||||
|
||||
* config/tc-m32r.c (reads_from_src_reg): Change second parameter
|
||||
to a count of the number of matches to skip.
|
||||
(can_make_parallel): Pass count of number of matches to skip to
|
||||
reads_from_src_reg().
|
||||
|
||||
end-sanitize-m32rx
|
||||
start-sanitize-sky
|
||||
Fri Jan 23 18:41:18 1998 Doug Evans <devans@canuck.cygnus.com>
|
||||
|
||||
|
|
|
@ -387,7 +387,7 @@ fi
|
|||
m32rx_files="tc-m32r.c tc-m32r.h"
|
||||
if ( echo $* | grep keep\-m32rx > /dev/null ) ; then
|
||||
for i in $m32rx_files ; do
|
||||
if test ! -d $i && (grep sanitize-m32rx $i > /dev/null) ; then
|
||||
if test ! -d $i && (grep sanitize\-m32rx $i > /dev/null) ; then
|
||||
if [ -n "${verbose}" ] ; then
|
||||
echo Keeping m32rx stuff in $i
|
||||
fi
|
||||
|
@ -395,7 +395,7 @@ if ( echo $* | grep keep\-m32rx > /dev/null ) ; then
|
|||
done
|
||||
else
|
||||
for i in $m32rx_files ; do
|
||||
if test -r $i && (grep sanitize-m32rx $i > /dev/null) ; then
|
||||
if test -r $i && (grep sanitize\-m32rx $i > /dev/null) ; then
|
||||
if [ -n "${verbose}" ] ; then
|
||||
echo Removing traces of \"m32rx\" from $i...
|
||||
fi
|
||||
|
@ -411,6 +411,32 @@ else
|
|||
fi
|
||||
done
|
||||
fi
|
||||
if ( echo $* | grep keep\-phase2\-m32rx > /dev/null ) ; then
|
||||
for i in $m32rx_files ; do
|
||||
if test ! -d $i && (grep sanitize\-phase2\-m32rx $i > /dev/null) ; then
|
||||
if [ -n "${verbose}" ] ; then
|
||||
echo Keeping m32rx stuff in $i
|
||||
fi
|
||||
fi
|
||||
done
|
||||
else
|
||||
for i in $m32rx_files ; do
|
||||
if test -r $i && (grep sanitize\-phase2\-m32rx $i > /dev/null) ; then
|
||||
if [ -n "${verbose}" ] ; then
|
||||
echo Removing traces of \"m32rx\" from $i...
|
||||
fi
|
||||
cp $i new
|
||||
sed '/start\-sanitize\-phase2\-m32rx/,/end\-sanitize\-phase2\-m32rx/d' < $i > new
|
||||
if [ -n "${safe}" -a ! -f .Recover/$i ] ; then
|
||||
if [ -n "${verbose}" ] ; then
|
||||
echo Caching $i in .Recover...
|
||||
fi
|
||||
mv $i .Recover
|
||||
fi
|
||||
mv new $i
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
vr4111_files="tc-mips.c"
|
||||
if ( echo $* | grep keep\-vr4111 > /dev/null ) ; then
|
||||
|
|
|
@ -24,10 +24,23 @@
|
|||
#include "subsegs.h"
|
||||
#include "cgen-opc.h"
|
||||
|
||||
/* Non-null if last insn was a 16 bit insn on a 32 bit boundary
|
||||
(i.e. was the first of two 16 bit insns). */
|
||||
static const CGEN_INSN * prev_insn = NULL;
|
||||
static CGEN_FIELDS prev_fields;
|
||||
typedef struct
|
||||
{
|
||||
const CGEN_INSN * insn;
|
||||
CGEN_FIELDS fields;
|
||||
#ifdef CGEN_INT_INSN
|
||||
cgen_insn_t buffer [CGEN_MAX_INSN_SIZE / sizeof (cgen_insn_t)];
|
||||
#else
|
||||
char buffer [CGEN_MAX_INSN_SIZE];
|
||||
#endif
|
||||
char * addr;
|
||||
fragS * frag;
|
||||
}
|
||||
m32r_insn;
|
||||
|
||||
/* prev_insn.insn is non-null if last insn was a 16 bit insn on a 32 bit
|
||||
boundary (i.e. was the first of two 16 bit insns). */
|
||||
static m32r_insn prev_insn;
|
||||
|
||||
/* Non-zero if we've seen a relaxable insn since the last 32 bit
|
||||
alignment request. */
|
||||
|
@ -47,6 +60,10 @@ static char * m32r_cpu_desc;
|
|||
/* 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 the programmer should be warned when an explicit parallel
|
||||
instruction might have constraint violations. */
|
||||
static int warn_explicit_parallel_conflicts = 1;
|
||||
/* end-sanitize-m32rx */
|
||||
|
||||
/* stuff for .scomm symbols. */
|
||||
|
@ -83,8 +100,6 @@ struct m32r_hi_fixup
|
|||
|
||||
static struct m32r_hi_fixup * m32r_hi_fixup_list;
|
||||
|
||||
static void m32r_record_hi16 PARAMS ((int, fixS *, segT seg));
|
||||
|
||||
|
||||
/* start-sanitize-m32rx */
|
||||
static void
|
||||
|
@ -105,12 +120,16 @@ 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},
|
||||
#define OPTION_NO_WARN (OPTION_MD_BASE + 2)
|
||||
{"no-warn-explicit-parallel-conflicts", no_argument, NULL, OPTION_NO_WARN},
|
||||
/* end-sanitize-m32rx */
|
||||
|
||||
#if 0 /* not supported yet */
|
||||
#define OPTION_RELAX (OPTION_MD_BASE + 1)
|
||||
#define OPTION_RELAX (OPTION_MD_BASE + 3)
|
||||
{"relax", no_argument, NULL, OPTION_RELAX},
|
||||
#define OPTION_CPU_DESC (OPTION_MD_BASE + 2)
|
||||
#define OPTION_CPU_DESC (OPTION_MD_BASE + 4)
|
||||
{"cpu-desc", required_argument, NULL, OPTION_CPU_DESC},
|
||||
#endif
|
||||
|
||||
|
@ -129,6 +148,14 @@ md_parse_option (c, arg)
|
|||
case OPTION_M32RX:
|
||||
allow_m32rx (1);
|
||||
break;
|
||||
|
||||
case OPTION_WARN:
|
||||
warn_explicit_parallel_conflicts = 1;
|
||||
break;
|
||||
|
||||
case OPTION_NO_WARN:
|
||||
warn_explicit_parallel_conflicts = 0;
|
||||
break;
|
||||
/* end-sanitize-m32rx */
|
||||
|
||||
#if 0 /* not supported yet */
|
||||
|
@ -153,6 +180,10 @@ md_show_usage (stream)
|
|||
/* start-sanitize-m32rx */
|
||||
fprintf (stream, "\
|
||||
--m32rx support the extended m32rx instruction set\n");
|
||||
|
||||
fprintf (stream, "\
|
||||
--warn-explicit-parallel-conflicts Warn when parallel instrucitons violate contraints\
|
||||
--no-warn-explicit-parallel-conflicts Do not warn when parallel instrucitons violate contraints\n");
|
||||
/* end-sanitize-m32rx */
|
||||
|
||||
#if 0
|
||||
|
@ -256,7 +287,7 @@ fill_insn (ignore)
|
|||
int ignore;
|
||||
{
|
||||
(void) m32r_do_align (2, NULL, 0, 0);
|
||||
prev_insn = NULL;
|
||||
prev_insn.insn = NULL;
|
||||
seen_relaxable_p = 0;
|
||||
}
|
||||
|
||||
|
@ -350,6 +381,7 @@ md_begin ()
|
|||
/* end-sanitize-m32rx */
|
||||
}
|
||||
|
||||
/* start-sanitize-m32rx */
|
||||
/* Returns non zero if the given instruction writes to a destination register. */
|
||||
static int
|
||||
writes_to_dest_reg (insn)
|
||||
|
@ -367,13 +399,11 @@ writes_to_dest_reg (insn)
|
|||
}
|
||||
|
||||
/* Returns non zero if the given instruction reads from a source register.
|
||||
Syntax characters equal to 'ignore' are skipped as they have already been
|
||||
processed. (This works provided that no potential parallel instruction
|
||||
can have more than 2 input registers). */
|
||||
Ignores the first 'num_ignore' macthes in the syntax string. */
|
||||
static int
|
||||
reads_from_src_reg (insn, ignore)
|
||||
reads_from_src_reg (insn, num_ignore)
|
||||
const CGEN_INSN * insn;
|
||||
unsigned char ignore;
|
||||
int num_ignore;
|
||||
{
|
||||
unsigned char * syntax = CGEN_SYNTAX_STRING (CGEN_INSN_SYNTAX (insn));
|
||||
unsigned char c;
|
||||
|
@ -381,28 +411,30 @@ reads_from_src_reg (insn, ignore)
|
|||
/* Scan the syntax string looking for a source register. */
|
||||
while ((c = (* syntax ++)) != 0)
|
||||
{
|
||||
if (c == ignore)
|
||||
continue;
|
||||
|
||||
if ( c == 128 + M32R_OPERAND_SR
|
||||
|| c == 128 + M32R_OPERAND_SRC1
|
||||
|| c == 128 + M32R_OPERAND_SRC2)
|
||||
break;
|
||||
{
|
||||
if (num_ignore -- > 0)
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Returns the integer value of the destination register held in the fields. */
|
||||
#define get_dest_reg(fields) fields->f_r1
|
||||
#define get_dest_reg(fields) (fields).f_r1
|
||||
|
||||
/* Returns an integer representing the source register of the given type. */
|
||||
static int
|
||||
get_src_reg (syntax, fields)
|
||||
unsigned char syntax;
|
||||
get_src_reg (syntax_field, fields)
|
||||
unsigned char syntax_field;
|
||||
CGEN_FIELDS * fields;
|
||||
{
|
||||
switch (syntax)
|
||||
switch (syntax_field)
|
||||
{
|
||||
case 128 + M32R_OPERAND_SR: return fields->f_r2;
|
||||
/* Relies upon the fact that no instruction with a $src1 operand
|
||||
|
@ -413,29 +445,27 @@ get_src_reg (syntax, fields)
|
|||
}
|
||||
}
|
||||
|
||||
/* start-sanitize-m32rx */
|
||||
/* Returns NULL if the two 16 bit insns can be executed in parallel,
|
||||
otherwise it returns a pointer to an error message explaining why not. */
|
||||
static const char *
|
||||
can_make_parallel (a, a_fields, b, b_fields, test_a_inputs, test_b_inputs)
|
||||
const CGEN_INSN * a;
|
||||
CGEN_FIELDS * a_fields;
|
||||
const CGEN_INSN * b;
|
||||
CGEN_FIELDS * b_fields;
|
||||
int test_a_inputs;
|
||||
int test_b_inputs;
|
||||
can_make_parallel (a, b, test_a_inputs, test_b_inputs)
|
||||
m32r_insn * a;
|
||||
m32r_insn * b;
|
||||
int test_a_inputs;
|
||||
int test_b_inputs;
|
||||
{
|
||||
PIPE_ATTR a_pipe;
|
||||
PIPE_ATTR b_pipe;
|
||||
|
||||
/* Make sure the instructions are the right length. */
|
||||
if ( CGEN_FIELDS_BITSIZE (a_fields) != 16
|
||||
|| CGEN_FIELDS_BITSIZE (b_fields) != 16)
|
||||
if ( CGEN_FIELDS_BITSIZE (& a->fields) != 16
|
||||
|| CGEN_FIELDS_BITSIZE (& b->fields) != 16)
|
||||
abort();
|
||||
|
||||
a_pipe = CGEN_INSN_ATTR (a, CGEN_INSN_PIPE);
|
||||
b_pipe = CGEN_INSN_ATTR (b, CGEN_INSN_PIPE);
|
||||
a_pipe = CGEN_INSN_ATTR (a->insn, CGEN_INSN_PIPE);
|
||||
b_pipe = CGEN_INSN_ATTR (b->insn, CGEN_INSN_PIPE);
|
||||
|
||||
/* Make sure that the instructions use the correct execution pipelines. */
|
||||
if ( a_pipe == PIPE_NONE
|
||||
|| b_pipe == PIPE_NONE)
|
||||
return "Instructions do not use parallel execution pipelines.";
|
||||
|
@ -444,47 +474,46 @@ can_make_parallel (a, a_fields, b, b_fields, test_a_inputs, test_b_inputs)
|
|||
|| b_pipe == PIPE_O)
|
||||
return "Instructions share the same execution pipeline";
|
||||
|
||||
if ( writes_to_dest_reg (a)
|
||||
&& writes_to_dest_reg (b)
|
||||
&& (get_dest_reg (a_fields) == get_dest_reg (b_fields)))
|
||||
if ( writes_to_dest_reg (a->insn)
|
||||
&& writes_to_dest_reg (b->insn)
|
||||
&& (get_dest_reg (a->fields) == get_dest_reg (b->fields)))
|
||||
return "Instructions write to the same destination register.";
|
||||
|
||||
/* If requested, make sure that the first instruction does not
|
||||
overwrite the inputs of the second instruction. */
|
||||
if (test_b_inputs && writes_to_dest_reg (a))
|
||||
if (test_b_inputs && writes_to_dest_reg (a->insn))
|
||||
{
|
||||
unsigned char skip = 1;
|
||||
unsigned char syntax_field;
|
||||
int skip = 0;
|
||||
|
||||
while (skip = reads_from_src_reg (b, skip))
|
||||
while (syntax_field = reads_from_src_reg (b->insn, skip ++))
|
||||
{
|
||||
if (get_src_reg (skip, b_fields) == get_dest_reg (a_fields))
|
||||
if (get_src_reg (syntax_field, & b->fields) == get_dest_reg (a->fields))
|
||||
return "First instruction writes to register read by the second instruction";
|
||||
}
|
||||
}
|
||||
|
||||
/* Similarly, if requested, make sure that the second instruction
|
||||
does not overwrite the inputs of the first instruction. */
|
||||
if (test_a_inputs && writes_to_dest_reg (b))
|
||||
if (test_a_inputs && writes_to_dest_reg (b->insn))
|
||||
{
|
||||
unsigned char skip = 1;
|
||||
unsigned char syntax_field;
|
||||
int skip = 0;
|
||||
|
||||
while (skip = reads_from_src_reg (a, skip))
|
||||
while (syntax_field = reads_from_src_reg (a->insn, skip ++))
|
||||
{
|
||||
if (get_src_reg (skip, a_fields) == get_dest_reg (b_fields))
|
||||
if (get_src_reg (syntax_field, & a->fields) == get_dest_reg (b->fields))
|
||||
return "Second instruction writes to register read by the first instruction";
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
/* end-sanitize-m32rx */
|
||||
|
||||
|
||||
#ifdef CGEN_INT_INSN
|
||||
static void
|
||||
make_parallel (insn, buffer)
|
||||
const CGEN_INSN * insn;
|
||||
cgen_insn_t * buffer;
|
||||
make_parallel (buffer)
|
||||
cgen_insn_t * buffer;
|
||||
{
|
||||
/* Force the top bit of the second insn to be set. */
|
||||
|
||||
|
@ -505,9 +534,8 @@ make_parallel (insn, buffer)
|
|||
}
|
||||
#else
|
||||
static void
|
||||
make_parallel (insn, buffer)
|
||||
const CGEN_INSN * insn;
|
||||
char * buffer;
|
||||
make_parallel (buffer)
|
||||
char * buffer;
|
||||
{
|
||||
/* Force the top bit of the second insn to be set. */
|
||||
|
||||
|
@ -516,200 +544,277 @@ make_parallel (insn, buffer)
|
|||
#endif
|
||||
|
||||
|
||||
static void
|
||||
assemble_parallel_insn (str, str2)
|
||||
char * str;
|
||||
char * str2;
|
||||
{
|
||||
char * str3;
|
||||
m32r_insn first;
|
||||
m32r_insn second;
|
||||
char * errmsg;
|
||||
|
||||
* 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);
|
||||
|
||||
/* Parse the first instruction. */
|
||||
if (! (first.insn = CGEN_SYM (assemble_insn)
|
||||
(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)
|
||||
{
|
||||
as_bad ("instruction '%s' cannot be executed in parallel.", str);
|
||||
return;
|
||||
}
|
||||
|
||||
if (! enable_m32rx
|
||||
&& CGEN_INSN_ATTR (first.insn, CGEN_INSN_MACH) == (1 << MACH_M32RX))
|
||||
{
|
||||
as_bad ("instruction '%s' is for the M32RX only", str);
|
||||
return;
|
||||
}
|
||||
|
||||
*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. */
|
||||
|
||||
/* Preserve any fixups that have been generated and reset the list to empty. */
|
||||
cgen_save_fixups();
|
||||
|
||||
/* Parse the second instruction. */
|
||||
if (! (second.insn = CGEN_SYM (assemble_insn)
|
||||
(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))
|
||||
{
|
||||
as_bad ("instruction '%s' is for the M32RX only", str);
|
||||
return;
|
||||
}
|
||||
|
||||
if (! enable_m32rx)
|
||||
{
|
||||
if ( strcmp (first.insn->name, "nop") != 0
|
||||
&& strcmp (second.insn->name, "nop") != 0)
|
||||
{
|
||||
as_bad ("'%s': only the NOP instruction can be issued in parallel on the m32r", str2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* We assume that if the first instruction writes to a register that is
|
||||
read by the second instruction it is because the programmer intended
|
||||
this to happen, (after all they have explicitly requested that these
|
||||
two instructions be executed in parallel). Similarly we assume that
|
||||
parallel branch and jump instructions are deliberate and should not
|
||||
produce errors. If warn_explicit_parallel is defined however, we do
|
||||
generate warning messages. */
|
||||
|
||||
if (can_make_parallel (& first, & second, false, false) == NULL)
|
||||
{
|
||||
/* Get the fixups for the first instruction. */
|
||||
cgen_swap_fixups ();
|
||||
|
||||
/* Write it out. */
|
||||
(void) cgen_asm_finish_insn (first.insn, first.buffer,
|
||||
CGEN_FIELDS_BITSIZE (& first.fields));
|
||||
|
||||
/* Force the top bit of the second insn to be set. */
|
||||
make_parallel (second.buffer);
|
||||
|
||||
/* Get its fixups. */
|
||||
cgen_restore_fixups ();
|
||||
|
||||
/* Write it out. */
|
||||
(void) cgen_asm_finish_insn (second.insn, second.buffer,
|
||||
CGEN_FIELDS_BITSIZE (& second.fields));
|
||||
}
|
||||
else if ((errmsg = (char *) can_make_parallel (& second, & first,
|
||||
false, false)) == NULL)
|
||||
{
|
||||
/* Write out the second instruction first. */
|
||||
(void) cgen_asm_finish_insn (second.insn, second.buffer,
|
||||
CGEN_FIELDS_BITSIZE (& second.fields));
|
||||
|
||||
/* 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 ();
|
||||
|
||||
/* Write out the first instruction. */
|
||||
(void) cgen_asm_finish_insn (first.insn, first.buffer,
|
||||
CGEN_FIELDS_BITSIZE (& first.fields));
|
||||
}
|
||||
else
|
||||
{
|
||||
as_bad ("'%s': %s", str2, errmsg);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
{
|
||||
#ifdef CGEN_INT_INSN
|
||||
cgen_insn_t buffer [CGEN_MAX_INSN_SIZE / sizeof (cgen_insn_t)];
|
||||
cgen_insn_t prev_buffer [CGEN_MAX_INSN_SIZE / sizeof (cgen_insn_t)];
|
||||
#else
|
||||
char buffer [CGEN_MAX_INSN_SIZE];
|
||||
char prev_buffer [CGEN_MAX_INSN_SIZE];
|
||||
#endif
|
||||
CGEN_FIELDS fields;
|
||||
const CGEN_INSN * insn;
|
||||
char * errmsg;
|
||||
char * str2 = NULL;
|
||||
int is_parallel = false;
|
||||
|
||||
m32r_insn insn;
|
||||
char * errmsg;
|
||||
char * str2 = NULL;
|
||||
|
||||
/* Initialize GAS's cgen interface for a new instruction. */
|
||||
cgen_asm_init_parse ();
|
||||
|
||||
/* start-sanitize-m32rx */
|
||||
/* Look for a parallel instruction seperator. */
|
||||
if ((str2 = strstr (str, "||")) != NULL)
|
||||
{
|
||||
char * str3;
|
||||
|
||||
* 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)
|
||||
fill_insn (0);
|
||||
|
||||
/* Assemble the first instruction. */
|
||||
prev_insn = CGEN_SYM (assemble_insn) (str, & prev_fields, prev_buffer,
|
||||
& errmsg);
|
||||
if (! prev_insn)
|
||||
{
|
||||
as_bad (errmsg);
|
||||
return;
|
||||
}
|
||||
|
||||
/* start-sanitize-m32rx */
|
||||
/* Check to see if this is an allowable parallel insn. */
|
||||
if (CGEN_INSN_ATTR (prev_insn, CGEN_INSN_PIPE) == PIPE_NONE)
|
||||
{
|
||||
as_bad ("instruction '%s' cannot be executed in parallel.", str);
|
||||
return;
|
||||
}
|
||||
|
||||
if (! enable_m32rx &&
|
||||
CGEN_INSN_ATTR (prev_insn, CGEN_INSN_MACH) == MACH_M32RX)
|
||||
{
|
||||
as_bad ("instruction '%s' is for the M32RX only", str);
|
||||
return;
|
||||
}
|
||||
assemble_parallel_insn (str, str2);
|
||||
return;
|
||||
}
|
||||
/* end-sanitize-m32rx */
|
||||
|
||||
/* fixups = fixups->next; */
|
||||
|
||||
*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. */
|
||||
|
||||
is_parallel = true;
|
||||
}
|
||||
|
||||
insn = CGEN_SYM (assemble_insn) (str, & fields, buffer, & errmsg);
|
||||
if (!insn)
|
||||
insn.insn = CGEN_SYM (assemble_insn) (str, & insn.fields, insn.buffer, & errmsg);
|
||||
if (!insn.insn)
|
||||
{
|
||||
as_bad (errmsg);
|
||||
return;
|
||||
}
|
||||
|
||||
/* start-sanitize-m32rx */
|
||||
if (! enable_m32rx && CGEN_INSN_ATTR (insn, CGEN_INSN_MACH) == (1 << MACH_M32RX))
|
||||
if (! enable_m32rx && CGEN_INSN_ATTR (insn.insn, CGEN_INSN_MACH) == (1 << MACH_M32RX))
|
||||
{
|
||||
as_bad ("instruction '%s' is for the M32RX only", str);
|
||||
return;
|
||||
}
|
||||
/* end-sanitize-m32rx */
|
||||
|
||||
if (is_parallel)
|
||||
{
|
||||
int swap = false;
|
||||
|
||||
/* start-sanitize-m32rx */
|
||||
if (! enable_m32rx)
|
||||
{
|
||||
if (strcmp (prev_insn->name, "nop") != 0
|
||||
&& strcmp (insn->name, "nop") != 0)
|
||||
{
|
||||
as_bad ("'%s': only the NOP instruction can be issued in parallel on the m32r", str2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* We assume that if the first instruction writes to a register that is
|
||||
read by the second instruction it is because the programmer intended
|
||||
this to happen, (after all they have explicitly requested that these
|
||||
two instructions be executed in parallel). So we do not generate an
|
||||
error if this happens. */
|
||||
if (can_make_parallel (prev_insn, & prev_fields, insn,
|
||||
& fields, false, false) != NULL)
|
||||
{
|
||||
if ((errmsg = (char *) can_make_parallel (insn, & fields, prev_insn,
|
||||
& prev_fields, false, false)) == NULL)
|
||||
{
|
||||
/* swap the two insns. */
|
||||
swap = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
as_bad ("'%s': %s", str2, errmsg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* end-sanitize-m32rx */
|
||||
|
||||
/* Generate the parallel instructions */
|
||||
if (swap)
|
||||
{
|
||||
cgen_asm_finish_insn (insn, buffer, CGEN_FIELDS_BITSIZE (& fields));
|
||||
|
||||
/* Force the top bit of the second insn to be set. */
|
||||
make_parallel (prev_insn, prev_buffer);
|
||||
|
||||
cgen_asm_finish_insn (prev_insn, prev_buffer,
|
||||
CGEN_FIELDS_BITSIZE (& prev_fields));
|
||||
}
|
||||
else
|
||||
{
|
||||
cgen_asm_finish_insn (prev_insn, prev_buffer,
|
||||
CGEN_FIELDS_BITSIZE (& prev_fields));
|
||||
|
||||
/* Force the top bit of the second insn to be set. */
|
||||
make_parallel (insn, buffer);
|
||||
|
||||
cgen_asm_finish_insn (insn, buffer, CGEN_FIELDS_BITSIZE (& fields));
|
||||
}
|
||||
|
||||
/* Clear the prev_insn variable, since it only used if the insn was the first
|
||||
16 bit insn in a 32 bit word. */
|
||||
prev_insn = NULL;
|
||||
}
|
||||
else if (CGEN_INSN_BITSIZE (insn) == 32)
|
||||
if (CGEN_INSN_BITSIZE (insn.insn) == 32)
|
||||
{
|
||||
/* 32 bit insns must live on 32 bit boundaries. */
|
||||
if (prev_insn || seen_relaxable_p)
|
||||
if (prev_insn.insn || seen_relaxable_p)
|
||||
{
|
||||
/* FIXME: If calling fill_insn too many times turns us into a memory
|
||||
pig, can we call assemble_nop instead of !seen_relaxable_p? */
|
||||
fill_insn (0);
|
||||
}
|
||||
|
||||
cgen_asm_finish_insn (insn, buffer, CGEN_FIELDS_BITSIZE (& fields));
|
||||
(void) cgen_asm_finish_insn (insn.insn, insn.buffer,
|
||||
CGEN_FIELDS_BITSIZE (& insn.fields));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 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();
|
||||
|
||||
/* Keep track of whether we've seen a pair of 16 bit insns.
|
||||
PREV_INSN is NULL when we're on a 32 bit boundary. */
|
||||
if (prev_insn)
|
||||
prev_insn.insn is NULL when we're on a 32 bit boundary. */
|
||||
if (prev_insn.insn)
|
||||
{
|
||||
/* start-sanitize-m32rx */
|
||||
if (can_make_parallel (prev_insn, & prev_fields, insn, & fields, false, true) == NULL)
|
||||
make_parallel (insn, buffer);
|
||||
else if (can_make_parallel (insn, & fields, prev_insn, & prev_fields, true, false) == NULL)
|
||||
/* 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, otherwise call can_make_parallel() with both
|
||||
orderings of the instructions to see if they can be combined. */
|
||||
if ( ! CGEN_INSN_ATTR (prev_insn.insn, CGEN_INSN_COND_CTI)
|
||||
&& ! CGEN_INSN_ATTR (prev_insn.insn, CGEN_INSN_UNCOND_CTI))
|
||||
{
|
||||
/* Swap instructions and make parallel. */
|
||||
/* XXX TODO .... */
|
||||
if (can_make_parallel (& prev_insn, & insn, false, true) == NULL)
|
||||
{
|
||||
make_parallel (insn.buffer);
|
||||
}
|
||||
else if (can_make_parallel (& insn, & prev_insn.insn, true, false) == NULL)
|
||||
{
|
||||
swap = true;
|
||||
}
|
||||
}
|
||||
/* end-sanitize-phase2-m32rx */
|
||||
/* end-sanitize-m32rx */
|
||||
|
||||
prev_insn = NULL;
|
||||
prev_insn.insn = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev_insn = insn;
|
||||
prev_fields = fields;
|
||||
prev_insn = insn;
|
||||
}
|
||||
|
||||
cgen_asm_finish_insn (insn, buffer, CGEN_FIELDS_BITSIZE (& fields));
|
||||
|
||||
/* 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));
|
||||
|
||||
/* start-sanitize-m32rx */
|
||||
/* start-sanitize-phase2-m32rx */
|
||||
if (swap)
|
||||
{
|
||||
int 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);
|
||||
|
||||
/* Swap any relaxable frags recorded for the two 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;
|
||||
/* end-sanitize-m32rx */
|
||||
|
||||
/* 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
|
||||
&& CGEN_INSN_ATTR (insn, CGEN_INSN_FILL_SLOT) != 0)
|
||||
if (prev_insn.insn
|
||||
&& CGEN_INSN_ATTR (insn.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, CGEN_INSN_RELAXABLE) != 0)
|
||||
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)
|
||||
seen_relaxable_p = 1;
|
||||
}
|
||||
|
||||
|
@ -781,7 +886,7 @@ m32r_scomm (ignore)
|
|||
return;
|
||||
}
|
||||
|
||||
input_line_pointer++; /* skip ',' */
|
||||
input_line_pointer ++; /* skip ',' */
|
||||
if ((size = get_absolute_expression ()) < 0)
|
||||
{
|
||||
as_warn (".SCOMMon length (%ld.) <0! Ignored.", (long) size);
|
||||
|
@ -856,6 +961,7 @@ m32r_scomm (ignore)
|
|||
symbolP->sy_frag->fr_symbol = 0;
|
||||
|
||||
symbolP->sy_frag = frag_now;
|
||||
|
||||
pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, size,
|
||||
(char *) 0);
|
||||
* pfrag = 0;
|
||||
|
@ -869,7 +975,7 @@ m32r_scomm (ignore)
|
|||
S_SET_VALUE (symbolP, (valueT) size);
|
||||
S_SET_ALIGN (symbolP, align2);
|
||||
S_SET_EXTERNAL (symbolP);
|
||||
S_SET_SEGMENT (symbolP, &scom_section);
|
||||
S_SET_SEGMENT (symbolP, & scom_section);
|
||||
}
|
||||
|
||||
demand_empty_rest_of_line ();
|
||||
|
@ -1014,6 +1120,7 @@ md_estimate_size_before_relax (fragP, segment)
|
|||
}
|
||||
if (i == 4)
|
||||
abort ();
|
||||
|
||||
fragP->fr_cgen.insn = insn;
|
||||
return 2;
|
||||
}
|
||||
|
@ -1164,6 +1271,28 @@ CGEN_SYM (lookup_reloc) (insn, operand, fixP)
|
|||
return BFD_RELOC_NONE;
|
||||
}
|
||||
|
||||
/* Record a HI16 reloc for later matching with its LO16 cousin. */
|
||||
|
||||
static void
|
||||
m32r_record_hi16 (reloc_type, fixP, seg)
|
||||
int reloc_type;
|
||||
fixS * fixP;
|
||||
segT seg;
|
||||
{
|
||||
struct m32r_hi_fixup * hi_fixup;
|
||||
|
||||
assert (reloc_type == BFD_RELOC_M32R_HI16_SLO
|
||||
|| reloc_type == BFD_RELOC_M32R_HI16_ULO);
|
||||
|
||||
hi_fixup = ((struct m32r_hi_fixup *)
|
||||
xmalloc (sizeof (struct m32r_hi_fixup)));
|
||||
hi_fixup->fixp = fixP;
|
||||
hi_fixup->seg = now_seg;
|
||||
hi_fixup->next = m32r_hi_fixup_list;
|
||||
|
||||
m32r_hi_fixup_list = hi_fixup;
|
||||
}
|
||||
|
||||
/* Called while parsing an instruction to create a fixup.
|
||||
We need to check for HI16 relocs and queue them up for later sorting. */
|
||||
|
||||
|
@ -1193,28 +1322,6 @@ m32r_cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp)
|
|||
return fixP;
|
||||
}
|
||||
|
||||
/* Record a HI16 reloc for later matching with its LO16 cousin. */
|
||||
|
||||
static void
|
||||
m32r_record_hi16 (reloc_type, fixP, seg)
|
||||
int reloc_type;
|
||||
fixS * fixP;
|
||||
segT seg;
|
||||
{
|
||||
struct m32r_hi_fixup * hi_fixup;
|
||||
|
||||
assert (reloc_type == BFD_RELOC_M32R_HI16_SLO
|
||||
|| reloc_type == BFD_RELOC_M32R_HI16_ULO);
|
||||
|
||||
hi_fixup = ((struct m32r_hi_fixup *)
|
||||
xmalloc (sizeof (struct m32r_hi_fixup)));
|
||||
hi_fixup->fixp = fixP;
|
||||
hi_fixup->seg = now_seg;
|
||||
hi_fixup->next = m32r_hi_fixup_list;
|
||||
|
||||
m32r_hi_fixup_list = hi_fixup;
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
|
Loading…
Reference in a new issue