Parallelisation code changed to used cgen's new ins operands feature.

This commit is contained in:
Nick Clifton 1998-02-13 18:01:19 +00:00
parent 6eacba2e77
commit 6cf2575a22
2 changed files with 77 additions and 127 deletions

View file

@ -1,3 +1,11 @@
Fri Feb 13 09:57:11 1998 Nick Clifton <nickc@cygnus.com>
* config/tc-m32r.c (first_writes_to_seconds_operands): New
function. Replaces get_src_reg(), check_for_side_effects(),
reads_from_src_reg(). Uses new insn operand features of cgen.
(writes_to_pc): New function.
(md_assemble): Call first_writes_to_seconds_operands().
Fri Feb 13 00:47:44 1998 Ian Lance Taylor <ian@cygnus.com> Fri Feb 13 00:47:44 1998 Ian Lance Taylor <ian@cygnus.com>
* config/tc-mips.c (macro_build): Handle operand type 'C'. * config/tc-mips.c (macro_build): Handle operand type 'C'.

View file

@ -35,6 +35,7 @@ typedef struct
#endif #endif
char * addr; char * addr;
fragS * frag; fragS * frag;
int indices [MAX_OPERAND_INSTANCES];
} }
m32r_insn; m32r_insn;
@ -386,124 +387,63 @@ md_begin ()
/* start-sanitize-m32rx */ /* start-sanitize-m32rx */
#ifdef HAVE_CPU_M32RX #ifdef HAVE_CPU_M32RX
/* Returns non zero if the given instruction writes to a destination register. */ /* Returns true if an output of instruction 'a' is referenced by an operand
of instruction 'b'. If 'check_outputs' is true then b's outputs are
checked, otherwise its inputs are examined. */
static int static int
writes_to_dest_reg (insn) first_writes_to_seconds_operands (a, b, check_outputs)
const CGEN_INSN * insn;
{
unsigned char * syntax = CGEN_SYNTAX_STRING (CGEN_INSN_SYNTAX (insn));
unsigned char c;
/* Scan the syntax string looking for a destination register. */
while ((c = (* syntax ++)) != 0)
if (c == 128 + M32R_OPERAND_DR)
break;
return c;
}
/* Returns non zero if the given instruction reads from a source register.
Ignores the first 'num_ignore' macthes in the syntax string. */
static int
reads_from_src_reg (insn, num_ignore)
const CGEN_INSN * insn;
int num_ignore;
{
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 == 128 + M32R_OPERAND_SR
|| c == 128 + M32R_OPERAND_SRC1
|| c == 128 + M32R_OPERAND_SRC2)
{
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
/* Returns an integer representing the source register of the given type. */
static int
get_src_reg (syntax_field, fields)
unsigned char syntax_field;
CGEN_FIELDS * fields;
{
/* Relies upon the fact that no instruction with a $src1 operand
also has a $dr operand. */
return m32r_cgen_get_operand (CGEN_SYNTAX_FIELD (syntax_field), fields);
}
/* Returns zero iff the output register of instruction 'a'
is an input register to instruction 'b'. */
static int
check_parallel_io_clash (a, b)
m32r_insn * a; m32r_insn * a;
m32r_insn * b; m32r_insn * b;
const int check_outputs;
{ {
#if 0 /* FIXME: to be revisited. */ const CGEN_OPERAND_INSTANCE * a_operands;
{ int a_index;
const CGEN_INSN *insn;
int a_indices[MAX_OPERAND_INSTANCES];
/* FIXME: CGEN_FIELDS is already recorded, but relying on that fact /* Scan the operand list of 'a' looking for an output operand. */
doesn't seem right. Perhaps allow passing fields like we do insn. */ for (a_index = 0, a_operands = CGEN_INSN_OPERANDS (a->insn);
insn = m32r_cgen_get_insn_operands (a->insn, CGEN_OPERAND_INSTANCE_TYPE (a_operands) != CGEN_OPERAND_INSTANCE_END;
bfd_getb16 ((char *) a->buffer), 16, a_index ++, a_operands ++)
a_indices); {
if (! insn) if (CGEN_OPERAND_INSTANCE_TYPE (a_operands) == CGEN_OPERAND_INSTANCE_OUTPUT)
as_fatal ("internal error: m32r_cgen_get_insn_operands"); {
const CGEN_OPERAND_INSTANCE * b_operands;
int b_index;
/* Scan operand list of 'b' looking for an operand that references
the same hardware element, and which goes in the right direction. */
for (b_index = 0, b_operands = CGEN_INSN_OPERANDS (b->insn);
CGEN_OPERAND_INSTANCE_TYPE (b_operands) != CGEN_OPERAND_INSTANCE_END;
b_index ++, b_operands ++)
{
if ((CGEN_OPERAND_INSTANCE_TYPE (b_operands) ==
(check_outputs ? CGEN_OPERAND_INSTANCE_OUTPUT : CGEN_OPERAND_INSTANCE_INPUT))
&& (CGEN_OPERAND_INSTANCE_HW (b_operands) == CGEN_OPERAND_INSTANCE_HW (a_operands))
&& (a->indices [a_index] == b->indices [b_index]))
return 1;
}
}
} }
#endif
if (writes_to_dest_reg (a->insn))
{
unsigned char syntax_field;
int skip = 0;
while (syntax_field = reads_from_src_reg (b->insn, skip ++))
{
if (get_src_reg (syntax_field, & b->fields) == get_dest_reg (a->fields))
return 0; return 0;
} }
}
/* Returns true if the insn can (potentially) alter the program counter. */
static int
writes_to_pc (a)
m32r_insn * a;
{
const CGEN_OPERAND_INSTANCE * a_operands;
for (a_operands = CGEN_INSN_OPERANDS (a->insn);
CGEN_OPERAND_INSTANCE_TYPE (a_operands) != CGEN_OPERAND_INSTANCE_END;
a_operands ++)
{
if (CGEN_OPERAND_INSTANCE_OPERAND (a_operands) != NULL
&& CGEN_OPERAND_INDEX (CGEN_OPERAND_INSTANCE_OPERAND (a_operands)) == M32R_OPERAND_PC)
return 1; return 1;
} }
/* Returns non zero iff instruction 'a' has a side effect
that affects the destination of instruction 'b'. */
static int
check_for_side_effects (a, b)
m32r_insn * a;
m32r_insn * b;
{
unsigned char syntax_field;
if (CGEN_INSN_ATTR (a->insn, CGEN_INSN_WRITE_SRC) != WRITE_SRC_YES)
return 0; return 0;
if (! writes_to_dest_reg (b->insn))
return 0;
/* Find the source register. */
syntax_field = reads_from_src_reg (a->insn, 0);
/* The st-plus and st-minus instructions have two sources,
only the second one has a side effect. */
if (syntax_field == 128 + M32R_OPERAND_SRC1)
syntax_field = reads_from_src_reg (a->insn, 1); /* We know that this will be src2 */
return get_dest_reg (b->fields) == get_src_reg (syntax_field, & a->fields);
} }
/* Returns NULL if the two 16 bit insns can be executed in parallel, /* Returns NULL if the two 16 bit insns can be executed in parallel,
@ -521,25 +461,9 @@ can_make_parallel (a, b)
|| CGEN_FIELDS_BITSIZE (& b->fields) != 16) || CGEN_FIELDS_BITSIZE (& b->fields) != 16)
abort(); abort();
/* Make sure that the destinations are different. */ if (first_writes_to_seconds_operands (a, b, true))
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."; return "Instructions write to the same destination register.";
/* Special case: Some instructions also modify their source register. */
if (check_for_side_effects (a, b))
return "Destination of second instruction written to by side effect of first instruction.";
if (check_for_side_effects (b, a))
return "Destination of first instruction written to by side effect of second instruction.";
/* Special case: The branch-and-link type instructions also write to r14. */
if (writes_to_dest_reg (b->insn)
&& get_dest_reg (b->fields) == 14
&& CGEN_INSN_ATTR (a->insn, CGEN_INSN_WRITE_LR) == WRITE_LR_YES)
return "Both instructions write to the link register";
a_pipe = CGEN_INSN_ATTR (a->insn, CGEN_INSN_PIPE); a_pipe = CGEN_INSN_ATTR (a->insn, CGEN_INSN_PIPE);
b_pipe = CGEN_INSN_ATTR (b->insn, CGEN_INSN_PIPE); b_pipe = CGEN_INSN_ATTR (b->insn, CGEN_INSN_PIPE);
@ -639,6 +563,13 @@ assemble_parallel_insn (str, str2)
/* Preserve any fixups that have been generated and reset the list to empty. */ /* Preserve any fixups that have been generated and reset the list to empty. */
cgen_save_fixups(); cgen_save_fixups();
/* Get the indicies of the operands of the instruction. */
/* FIXME: CGEN_FIELDS is already recorded, but relying on that fact
doesn't seem right. Perhaps allow passing fields like we do insn. */
if (m32r_cgen_get_insn_operands (first.insn, bfd_getb16 ((char *) first.buffer), 16,
first.indices) == NULL)
as_fatal ("internal error: m32r_cgen_get_insn_operands failed for first insn");
/* Parse the second instruction. */ /* Parse the second instruction. */
if (! (second.insn = CGEN_SYM (assemble_insn) if (! (second.insn = CGEN_SYM (assemble_insn)
(str, & second.fields, second.buffer, & errmsg))) (str, & second.fields, second.buffer, & errmsg)))
@ -665,6 +596,11 @@ assemble_parallel_insn (str, str2)
} }
} }
/* Get the indicies of the operands of the instruction. */
if (m32r_cgen_get_insn_operands (second.insn, bfd_getb16 ((char *) second.buffer), 16,
second.indices) == NULL)
as_fatal ("internal error: m32r_cgen_get_insn_operands failed for second insn");
/* We assume that if the first instruction writes to a register that is /* We assume that if the first instruction writes to a register that is
read by the second instruction it is because the programmer intended read by the second instruction it is because the programmer intended
this to happen, (after all they have explicitly requested that these this to happen, (after all they have explicitly requested that these
@ -675,11 +611,11 @@ assemble_parallel_insn (str, str2)
if (warn_explicit_parallel_conflicts) if (warn_explicit_parallel_conflicts)
{ {
if (! check_parallel_io_clash (& first, & second)) if (first_writes_to_seconds_operands (& first, & second, false))
as_warn ("%s: output of first instruction is the same as the input of second instruction - is this intentional ?", str2); as_warn ("%s: output of 1st instruction is the same as an input to 2nd instruction - is this intentional ?", str2);
if (! check_parallel_io_clash (& second, & first)) if (first_writes_to_seconds_operands (& second, & first, false))
as_warn ("%s: output of second instruction is the same as the input of first instruction - is this intentional ?", str2); as_warn ("%s: output of 2nd instruction is the same as an input to 1st instruction - is this intentional ?", str2);
} }
if ((errmsg = (char *) can_make_parallel (& first, & second)) == NULL) if ((errmsg = (char *) can_make_parallel (& first, & second)) == NULL)
@ -702,7 +638,7 @@ assemble_parallel_insn (str, str2)
CGEN_FIELDS_BITSIZE (& second.fields)); CGEN_FIELDS_BITSIZE (& second.fields));
} }
/* Try swapping the instructions to see if they work that way. */ /* Try swapping the instructions to see if they work that way. */
else if (can_make_parallel (& second, & first, false, false) == NULL) else if (can_make_parallel (& second, & first) == NULL)
{ {
/* Write out the second instruction first. */ /* Write out the second instruction first. */
(void) cgen_asm_finish_insn (second.insn, second.buffer, (void) cgen_asm_finish_insn (second.insn, second.buffer,
@ -799,6 +735,13 @@ md_assemble (str)
if (CGEN_INSN_BITSIZE (insn.insn) != 16) if (CGEN_INSN_BITSIZE (insn.insn) != 16)
abort(); abort();
/* Get the indicies of the operands of the instruction. */
/* FIXME: CGEN_FIELDS is already recorded, but relying on that fact
doesn't seem right. Perhaps allow passing fields like we do insn. */
if (m32r_cgen_get_insn_operands (insn.insn, bfd_getb16 ((char *) insn.buffer), 16,
insn.indices) == NULL)
as_fatal ("internal error: m32r_cgen_get_insn_operands failed");
/* Keep track of whether we've seen a pair of 16 bit insns. /* 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. */ prev_insn.insn is NULL when we're on a 32 bit boundary. */
if (prev_insn.insn) if (prev_insn.insn)
@ -814,9 +757,8 @@ md_assemble (str)
is used as an input to the current instruction then it cannot is used as an input to the current instruction then it cannot
be combined. Otherwise call can_make_parallel() with both be combined. Otherwise call can_make_parallel() with both
orderings of the instructions to see if they can be combined. */ orderings of the instructions to see if they can be combined. */
if ( ! CGEN_INSN_ATTR (prev_insn.insn, CGEN_INSN_COND_CTI) if (! writes_to_pc (& prev_insn)
&& ! CGEN_INSN_ATTR (prev_insn.insn, CGEN_INSN_UNCOND_CTI) && ! first_writes_to_seconds_operands (& prev_insn, &insn, false)
&& check_parallel_io_clash (& prev_insn, &insn)
) )
{ {
if (can_make_parallel (& prev_insn, & insn) == NULL) if (can_make_parallel (& prev_insn, & insn) == NULL)