Foixes for PR16116 and ER15940 - improve parallel insn handling.

This commit is contained in:
Nick Clifton 1998-06-09 01:33:23 +00:00
parent f79ebb2c0f
commit 7a0f469b1c
2 changed files with 118 additions and 61 deletions

View file

@ -1,3 +1,13 @@
Mon Jun 8 18:32:01 1998 Nick Clifton <nickc@cygnus.com>
* config/tc-d30v.c (md_assemble): Fix handling of reverse
sequential word multiply instructions.
(do_assemble): Add extra command line argument, to allow mul32
attribute to be preserved across parallel insns.
(md_assemble): Insert NOPs between explicitly parallel insns which
contain an 32 bit multiply and a 16 multiply.
start-sanitize-sky
Mon Jun 8 15:41:43 1998 Doug Evans <devans@canuck.cygnus.com>

View file

@ -111,7 +111,7 @@ static void write_1_short PARAMS ((struct d30v_insn *opcode, long long insn, Fix
static int write_2_short PARAMS ((struct d30v_insn *opcode1, long long insn1,
struct d30v_insn *opcode2, long long insn2, exec_type_enum exec_type, Fixups *fx));
static long long do_assemble PARAMS ((char *str, struct d30v_insn *opcode,
int shortp));
int shortp, int is_parallel));
static int parallel_ok PARAMS ((struct d30v_insn *opcode1, unsigned long insn1,
struct d30v_insn *opcode2, unsigned long insn2,
exec_type_enum exec_type));
@ -159,7 +159,7 @@ reg_name_search (name)
int cmp;
low = 0;
high = reg_name_cnt() - 1;
high = reg_name_cnt () - 1;
do
{
@ -245,7 +245,7 @@ void
md_show_usage (stream)
FILE *stream;
{
fprintf(stream, _("\nD30V options:\n\
fprintf (stream, _("\nD30V options:\n\
-O Make adjacent short instructions parallel if possible.\n\
-n Warn about all NOPs inserted by the assembler.\n\
-N Warn about NOPs inserted after word multiplies.\n"));
@ -352,7 +352,7 @@ void
md_begin ()
{
struct d30v_opcode *opcode;
d30v_hash = hash_new();
d30v_hash = hash_new ();
/* Insert opcode names into a hash table. */
for (opcode = (struct d30v_opcode *)d30v_opcode_table; opcode->name; opcode++)
@ -409,14 +409,14 @@ get_reloc (op, rel_flag)
break;
case 12:
if (!(op->flags & OPERAND_SHIFT))
as_warn(_("unexpected 12-bit reloc type"));
as_warn (_("unexpected 12-bit reloc type"));
if (rel_flag == RELOC_PCREL)
return BFD_RELOC_D30V_15_PCREL;
else
return BFD_RELOC_D30V_15;
case 18:
if (!(op->flags & OPERAND_SHIFT))
as_warn(_("unexpected 18-bit reloc type"));
as_warn (_("unexpected 18-bit reloc type"));
if (rel_flag == RELOC_PCREL)
return BFD_RELOC_D30V_21_PCREL;
else
@ -585,7 +585,7 @@ build_insn (opcode, opers)
as_fatal (_("too many fixups"));
fixups->fix[fixups->fc].reloc =
get_reloc((struct d30v_operand *)&d30v_operand_table[form->operands[i]], op->reloc_flag);
get_reloc ((struct d30v_operand *)&d30v_operand_table[form->operands[i]], op->reloc_flag);
fixups->fix[fixups->fc].size = 4;
fixups->fix[fixups->fc].exp = opers[i];
fixups->fix[fixups->fc].operand = form->operands[i];
@ -598,7 +598,7 @@ build_insn (opcode, opers)
/* truncate to the proper number of bits */
if ((opers[i].X_op == O_constant) && check_range (number, bits, flags))
as_bad(_("operand out of range: %d"),number);
as_bad (_("operand out of range: %d"),number);
if (bits < 31)
number &= 0x7FFFFFFF >> (31 - bits);
if (flags & OPERAND_SHIFT)
@ -626,7 +626,7 @@ write_long (opcode, insn, fx)
Fixups *fx;
{
int i, where;
char *f = frag_more(8);
char *f = frag_more (8);
insn |= FM11;
d30v_number_to_chars (f, insn, 8);
@ -655,7 +655,7 @@ write_1_short (opcode, insn, fx)
long long insn;
Fixups *fx;
{
char *f = frag_more(8);
char *f = frag_more (8);
int i, where;
if (warn_nops == NOP_ALL)
@ -700,7 +700,7 @@ write_2_short (opcode1, insn1, opcode2, insn2, exec_type, fx)
char *f;
int i,j, where;
if(exec_type != EXEC_PARALLEL &&
if (exec_type != EXEC_PARALLEL &&
((opcode1->op->flags_used & (FLAG_JSR | FLAG_DELAY)) == FLAG_JSR))
{
/* subroutines must be called from 32-bit boundaries */
@ -782,11 +782,11 @@ write_2_short (opcode1, insn1, opcode2, insn2, exec_type, fx)
break;
default:
as_fatal(_("unknown execution type passed to write_2_short()"));
as_fatal (_("unknown execution type passed to write_2_short()"));
}
/* printf("writing out %llx\n",insn); */
f = frag_more(8);
f = frag_more (8);
d30v_number_to_chars (f, insn, 8);
/* If the previous instruction was a 32-bit multiply but it is put into a
@ -1030,7 +1030,7 @@ parallel_ok (op1, insn1, op2, insn2, exec_type)
mod_reg[0][2] = mod_reg[1][2] = 0;
}
for(j = 0; j < 3; j++)
for (j = 0; j < 3; j++)
{
/* If the second instruction depends on the first, we obviously
cannot parallelize. Note, the mod flag implies use, so
@ -1078,7 +1078,7 @@ md_assemble (str)
if ((prev_insn != -1) && prev_seg
&& ((prev_seg != now_seg) || (prev_subseg != now_subseg)))
d30v_cleanup();
d30v_cleanup ();
if (d30v_current_align < 3)
d30v_align (3, NULL, d30v_last_label);
@ -1116,10 +1116,10 @@ md_assemble (str)
/* if two instructions are present and we already have one saved
then first write it out */
d30v_cleanup();
d30v_cleanup ();
/* assemble first instruction and save it */
prev_insn = do_assemble (str, &prev_opcode, 1);
prev_insn = do_assemble (str, &prev_opcode, 1, 0);
if (prev_insn == -1)
as_fatal (_("Cannot assemble instruction"));
if (prev_opcode.form->form >= LONG)
@ -1132,7 +1132,8 @@ md_assemble (str)
}
insn = do_assemble (str, &opcode,
(extype != EXEC_UNKNOWN || etype != EXEC_UNKNOWN));
(extype != EXEC_UNKNOWN || etype != EXEC_UNKNOWN),
extype == EXEC_PARALLEL);
if (insn == -1)
{
if (extype != EXEC_UNKNOWN)
@ -1151,11 +1152,12 @@ md_assemble (str)
/* Word multiply instructions must not be followed by either a load or a
16-bit multiply instruction in the next cycle. */
if (prev_mul32_p && (opcode.op->flags_used & (FLAG_MEM | FLAG_MUL16)))
if ( (extype != EXEC_REVSEQ)
&& prev_mul32_p
&& (opcode.op->flags_used & (FLAG_MEM | FLAG_MUL16)))
{
/* However, load and multiply should able to be combined in a parallel
operation, so check for that first. */
if (prev_insn != -1
&& (opcode.op->flags_used & FLAG_MEM)
&& opcode.form->form < LONG
@ -1169,14 +1171,47 @@ md_assemble (str)
prev_insn = -1;
return;
}
/* Can't parallelize, flush current instruction and emit a word of NOPS */
else
{
char *f;
d30v_cleanup();
/* Can't parallelize, flush previous instruction and emit a word of NOPS,
unless the previous instruction is a NOP, in whcih case just flush it,
as this will generate a word of NOPs for us. */
f = frag_more(8);
if (prev_insn != -1 && (strcmp (prev_opcode.op->name, "nop") == 0))
{
d30v_cleanup ();
}
else
{
char * f;
d30v_cleanup ();
f = frag_more (8);
d30v_number_to_chars (f, NOP2, 8);
if (warn_nops == NOP_ALL || warn_nops == NOP_MULTIPLY)
{
if (opcode.op->flags_used & FLAG_MEM)
as_warn (_("word of NOPs added between word multiply and load"));
else
as_warn (_("word of NOPs added between word multiply and 16-bit multiply"));
}
}
extype = EXEC_UNKNOWN;
}
}
else if ( (extype == EXEC_REVSEQ)
&& cur_mul32_p
&& (prev_opcode.op->flags_used & (FLAG_MEM | FLAG_MUL16)))
{
/* Can't parallelize, flush current instruction and emit a word of NOPS */
write_1_short (& opcode, (long) insn, fixups->next->next);
if (strcmp (opcode.op->name, "nop") != 0)
{
char * f;
f = frag_more (8);
d30v_number_to_chars (f, NOP2, 8);
if (warn_nops == NOP_ALL || warn_nops == NOP_MULTIPLY)
{
@ -1185,34 +1220,40 @@ md_assemble (str)
else
as_warn (_("word of NOPs added between word multiply and 16-bit multiply"));
}
extype = EXEC_UNKNOWN;
}
/* Make the previous instruction the current one. */
extype = EXEC_UNKNOWN;
insn = prev_insn;
now_seg = prev_seg;
now_subseg = prev_subseg;
prev_insn = -1;
cur_mul32_p = prev_mul32_p;
prev_mul32_p = 0;
}
/* if this is a long instruction, write it and any previous short instruction */
/* If this is a long instruction, write it and any previous short instruction. */
if (opcode.form->form >= LONG)
{
if (extype)
as_fatal(_("Unable to mix instructions as specified"));
d30v_cleanup();
if (extype != EXEC_UNKNOWN)
as_fatal (_("Unable to mix instructions as specified"));
d30v_cleanup ();
write_long (&opcode, insn, fixups);
prev_insn = -1;
return;
}
if ((prev_insn != -1) &&
else if ((prev_insn != -1) &&
(write_2_short (&prev_opcode, (long)prev_insn, &opcode, (long)insn, extype, fixups) == 0))
{
/* no instructions saved */
/* No instructions saved. */
prev_insn = -1;
}
else
{
if (extype)
as_fatal(_("Unable to mix instructions as specified"));
/* save off last instruction so it may be packed on next pass */
memcpy(&prev_opcode, &opcode, sizeof(prev_opcode));
if (extype != EXEC_UNKNOWN)
as_fatal (_("Unable to mix instructions as specified"));
/* Save off last instruction so it may be packed on next pass. */
memcpy (&prev_opcode, &opcode, sizeof (prev_opcode));
prev_insn = insn;
prev_seg = now_seg;
prev_subseg = now_subseg;
@ -1225,10 +1266,11 @@ md_assemble (str)
/* it returns -1 (an invalid opcode) on error */
static long long
do_assemble (str, opcode, shortp)
do_assemble (str, opcode, shortp, is_parallel)
char *str;
struct d30v_insn *opcode;
int shortp;
int is_parallel;
{
unsigned char *op_start, *save;
unsigned char *op_end;
@ -1249,7 +1291,7 @@ do_assemble (str, opcode, shortp)
&& !is_end_of_line[*op_end] && *op_end != ' ';
op_end++)
{
name[nlen] = tolower(op_start[nlen]);
name[nlen] = tolower (op_start[nlen]);
nlen++;
}
@ -1262,13 +1304,13 @@ do_assemble (str, opcode, shortp)
if (*op_end == '/')
{
int i = 0;
while ( (i < ECC_MAX) && strncasecmp(d30v_ecc_names[i],op_end+1,2))
while ( (i < ECC_MAX) && strncasecmp (d30v_ecc_names[i],op_end+1,2))
i++;
if (i == ECC_MAX)
{
char tmp[4];
strncpy(tmp,op_end+1,2);
strncpy (tmp,op_end+1,2);
tmp[2] = 0;
as_fatal (_("unknown condition code: %s"),tmp);
return -1;
@ -1282,7 +1324,7 @@ do_assemble (str, opcode, shortp)
/* CMP and CMPU change their name based on condition codes */
if (!strncmp(name,"cmp",3))
if (!strncmp (name,"cmp",3))
{
int p,i;
char **str = (char **)d30v_cc_names;
@ -1291,7 +1333,7 @@ do_assemble (str, opcode, shortp)
else
p = 3;
for(i=1; *str && strncmp(*str,&name[p],2); i++, str++)
for (i=1; *str && strncmp (*str,&name[p],2); i++, str++)
;
/* cmpu only supports some condition codes */
@ -1336,14 +1378,14 @@ do_assemble (str, opcode, shortp)
/* find the first opcode with the proper name */
opcode->op = (struct d30v_opcode *)hash_find (d30v_hash, name);
if (opcode->op == NULL)
as_fatal (_("unknown opcode: %s"),name);
as_fatal (_("unknown opcode: %s"),name);
save = input_line_pointer;
input_line_pointer = op_end;
while (!(opcode->form = find_format (opcode->op, myops, fsize, cmp_hack)))
{
opcode->op++;
if (strcmp(opcode->op->name,name))
if (strcmp (opcode->op->name,name))
as_fatal (_("operands for opcode `%s' do not match any valid format"), name);
}
input_line_pointer = save;
@ -1353,8 +1395,13 @@ do_assemble (str, opcode, shortp)
/* Propigate multiply status */
if (insn != -1)
{
prev_mul32_p = cur_mul32_p;
cur_mul32_p = (opcode->op->flags_used & FLAG_MUL32) != 0;
if (is_parallel && prev_mul32_p)
cur_mul32_p = 1;
else
{
prev_mul32_p = cur_mul32_p;
cur_mul32_p = (opcode->op->flags_used & FLAG_MUL32) != 0;
}
}
return (insn);
@ -1460,8 +1507,8 @@ find_format (opcode, myops, fsize, cmp_hack)
match = 0;
}
else if (X_op == O_symbol
&& S_IS_DEFINED(myops[j].X_add_symbol)
&& S_GET_SEGMENT(myops[j].X_add_symbol) == now_seg
&& S_IS_DEFINED (myops[j].X_add_symbol)
&& S_GET_SEGMENT (myops[j].X_add_symbol) == now_seg
&& opcode->reloc_flag == RELOC_PCREL)
{
/* If the symbol is defined, see if the value will fit
@ -1474,8 +1521,8 @@ find_format (opcode, myops, fsize, cmp_hack)
value = 0;
for (f = frchain_now->frch_root; f; f = f->fr_next)
value += f->fr_fix + f->fr_offset;
value = (S_GET_VALUE(myops[j].X_add_symbol) - value
- (obstack_next_free(&frchain_now->frch_obstack)
value = (S_GET_VALUE (myops[j].X_add_symbol) - value
- (obstack_next_free (&frchain_now->frch_obstack)
- frag_now->fr_literal));
if (check_range (value, bits, flags))
match = 0;
@ -1709,15 +1756,15 @@ d30v_number_to_chars (buf, value, n)
/* then write out any unwritten instructions */
void
d30v_start_line()
d30v_start_line ()
{
char *c = input_line_pointer;
while(isspace(*c))
while (isspace (*c))
c++;
if (*c == '.')
d30v_cleanup();
if (*c == '.')
d30v_cleanup ();
}
static void
@ -1749,7 +1796,7 @@ d30v_frob_label (lab)
symbolS *lab;
{
/* Emit any pending instructions. */
d30v_cleanup();
d30v_cleanup ();
/* Update the label's address with the current output pointer. */
lab->sy_frag = frag_now;
@ -1797,7 +1844,7 @@ d30v_align (n, pfill, label)
if (d30v_current_align >= n && !switched_seg_p)
return;
d30v_cleanup();
d30v_cleanup ();
if (pfill == NULL)
{
@ -1833,7 +1880,7 @@ d30v_align (n, pfill, label)
old_frag = label->sy_frag;
old_value = S_GET_VALUE (label);
new_value = (valueT) frag_now_fix();
new_value = (valueT) frag_now_fix ();
/* It is possible to have more than one label at a particular
address, especially if debugging is enabled, so we must
@ -1859,7 +1906,7 @@ d30v_align (n, pfill, label)
}
}
record_alignment(now_seg, n);
record_alignment (now_seg, n);
}
/* Handle the .align pseudo-op. This aligns to a power of two. We