Added opportunistic parallelisation of adjacent instructions.

This commit is contained in:
Nick Clifton 1998-01-21 01:13:47 +00:00
parent 1a702a2431
commit 775fdd0c3f
2 changed files with 227 additions and 76 deletions

View File

@ -1,3 +1,13 @@
start-sanitize-m32rx
Tue Jan 20 17:08:53 1998 Nick Clifton <nickc@cygnus.com>
* config/tc-m32r.c (md_assemble): Add code to swap explicitly
parallel instructions so that they are in the correct order.
(reads_from_src_reg, get_src_reg, can_make_parallel,
make_parallel): New functions to support opportunistic
parallelisation of adjacent instructions.
end-sanitize-m32rx
Fri Jan 16 14:51:48 1998 Ian Lance Taylor <ian@cygnus.com>
* read.c (dwarf_file_string): New file static variable.

View File

@ -27,6 +27,7 @@
/* 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;
/* Non-zero if we've seen a relaxable insn since the last 32 bit
alignment request. */
@ -203,7 +204,7 @@ m32r_do_align (n, fill, len, max)
/* 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
/* Only do this special handling if we're allowed to emit at
least two bytes. */
&& (max == 0 || max > 1))
{
@ -365,16 +366,156 @@ writes_to_dest_reg (insn)
return c;
}
/* Returns an integer representing the destination register of
the given insn, or -1 if the insn has no destination. */
/* 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). */
static int
get_dest_reg (insn)
reads_from_src_reg (insn, ignore)
const CGEN_INSN * insn;
unsigned char ignore;
{
/* XXX to be done. */
return -1;
unsigned char * syntax = CGEN_SYNTAX_STRING (CGEN_INSN_SYNTAX (insn));
unsigned char c;
/* 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;
}
return c;
}
/* Returns the integer value of the destination register held in the fields. */
#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;
CGEN_FIELDS * fields;
{
switch (syntax)
{
case 128 + M32R_OPERAND_SR: return fields->f_r2;
/* Relies upon the fact that no instruction with a $src1 operand
also has a $dr operand. */
case 128 + M32R_OPERAND_SRC1: return fields->f_r1;
case 128 + M32R_OPERAND_SRC2: return fields->f_r2;
default: abort(); return -1;
}
}
/* 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;
{
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)
abort();
a_pipe = CGEN_INSN_ATTR (a, CGEN_INSN_PIPE);
b_pipe = CGEN_INSN_ATTR (b, CGEN_INSN_PIPE);
if ( a_pipe == PIPE_NONE
|| b_pipe == PIPE_NONE)
return "Instructions do not use parallel execution pipelines.";
if ( a_pipe == PIPE_S
|| 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)))
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))
{
unsigned char skip = 1;
while (skip = reads_from_src_reg (b, skip))
{
if (get_src_reg (skip, 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))
{
unsigned char skip = 1;
while (skip = reads_from_src_reg (a, skip))
{
if (get_src_reg (skip, 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;
{
/* 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);
}
}
#else
static void
make_parallel (insn, buffer)
const CGEN_INSN * insn;
char * buffer;
{
/* Force the top bit of the second insn to be set. */
buffer [CGEN_CURRENT_ENDIAN == CGEN_ENDIAN_BIG ? 0 : 1] |= 0x80;
}
#endif
void
md_assemble (str)
char * str;
@ -387,7 +528,6 @@ md_assemble (str)
char prev_buffer [CGEN_MAX_INSN_SIZE];
#endif
CGEN_FIELDS fields;
CGEN_FIELDS prev_fields;
const CGEN_INSN * insn;
char * errmsg;
char * str2 = NULL;
@ -403,13 +543,15 @@ md_assemble (str)
* 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 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);
prev_insn = CGEN_SYM (assemble_insn) (str, & prev_fields, prev_buffer,
& errmsg);
if (! prev_insn)
{
as_bad (errmsg);
@ -450,8 +592,7 @@ md_assemble (str)
}
/* start-sanitize-m32rx */
if (! enable_m32rx
&& CGEN_INSN_ATTR (insn, CGEN_INSN_MACH) == (1 << MACH_M32RX))
if (! enable_m32rx && CGEN_INSN_ATTR (insn, CGEN_INSN_MACH) == (1 << MACH_M32RX))
{
as_bad ("instruction '%s' is for the M32RX only", str);
return;
@ -460,6 +601,8 @@ md_assemble (str)
if (is_parallel)
{
int swap = false;
/* start-sanitize-m32rx */
if (! enable_m32rx)
{
@ -470,70 +613,50 @@ md_assemble (str)
return;
}
}
/* Check to see if this is an allowable parallel insn. */
if (CGEN_INSN_ATTR (insn, CGEN_INSN_PIPE) == PIPE_NONE)
{
as_bad ("instruction '%s', cannot be executed in parallel.", str);
return;
}
/* Check to see that the two instructions can be placed in parallel. */
if ((CGEN_INSN_ATTR (insn, CGEN_INSN_PIPE) == CGEN_INSN_ATTR (prev_insn, CGEN_INSN_PIPE))
&& (CGEN_INSN_ATTR (insn, CGEN_INSN_PIPE) != PIPE_OS))
/* 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)
{
as_bad ("'%s': both instructions use the same execution pipeline", str2);
return;
}
/* end-sanitize-m32rx */
#if 0
/* Check that the instructions do not write to the same destination register. */
if (writes_to_dest_reg (insn)
&& writes_to_dest_reg (prev_insn) /* This test is actually redundant. */
&& get_dest_reg (insn) == get_dest_reg (prev_insn))
{
as_bad ("'%s': both instructions write to the same destination register", str2);
return;
}
#endif
/* Force the top bit of the second insn to be set. */
#if 0 /*def CGEN_INT_INSN*/
#define MAKE_PARALLEL(insn) ((insn) |= 0x8000)
switch (CGEN_FIELDS_BITSIZE (& fields))
{
bfd_vma value;
case 16:
if (CGEN_CURRENT_ENDIAN == CGEN_ENDIAN_BIG)
if ((errmsg = (char *) can_make_parallel (insn, & fields, prev_insn,
& prev_fields, false, false)) == NULL)
{
value = bfd_getb16 ((bfd_vma) * buffer);
MAKE_PARALLEL (value);
bfd_putb16 (value, buffer);
/* swap the two insns. */
swap = true;
}
else
{
value = bfd_getl16 ((bfd_vma) * buffer);
MAKE_PARALLEL (value);
bfd_putl16 (value, buffer);
as_bad ("'%s': %s", str2, errmsg);
return;
}
break;
default:
abort ();
}
#else
#define MAKE_PARALLEL(insn) ((insn) |= 0x80)
MAKE_PARALLEL (buffer [CGEN_CURRENT_ENDIAN == CGEN_ENDIAN_BIG ? 0 : 1]);
#endif
/* end-sanitize-m32rx */
/* Generate the parallel instructions */
cgen_asm_finish_insn (prev_insn, prev_buffer, CGEN_FIELDS_BITSIZE (& prev_fields));
cgen_asm_finish_insn (insn, buffer, CGEN_FIELDS_BITSIZE (& fields));
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);
/* If prev_ins is relaxable (and insn is not), then swap them, so that the test
after the end of this if-then-else section will work. */
if (CGEN_INSN_ATTR (prev_insn, CGEN_INSN_RELAXABLE))
insn = prev_insn;
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. */
@ -556,9 +679,24 @@ md_assemble (str)
/* 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 = NULL;
{
/* 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)
{
/* Swap instructions and make parallel. */
/* XXX TODO .... */
}
/* end-sanitize-m32rx */
prev_insn = NULL;
}
else
prev_insn = insn;
{
prev_insn = insn;
prev_fields = fields;
}
cgen_asm_finish_insn (insn, buffer, CGEN_FIELDS_BITSIZE (& fields));
@ -567,13 +705,13 @@ md_assemble (str)
if (prev_insn
&& CGEN_INSN_ATTR (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)
seen_relaxable_p = 1;
/* 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)
seen_relaxable_p = 1;
}
/* Set these so m32r_fill_insn can use them. */
prev_seg = now_seg;
@ -710,10 +848,13 @@ m32r_scomm (ignore)
record_alignment (sbss_section, align2);
subseg_set (sbss_section, 0);
if (align2)
frag_align (align2, 0, 0);
if (S_GET_SEGMENT (symbolP) == sbss_section)
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);
@ -891,9 +1032,9 @@ md_estimate_size_before_relax (fragP, segment)
void
md_convert_frag (abfd, sec, fragP)
bfd *abfd;
segT sec;
fragS *fragP;
bfd * abfd;
segT sec;
fragS * fragP;
{
char * opcode;
char * displacement;