* config/tc-arc.c (delay_slot_type): New function.

(md_assemble): Use hashed list of insns.
	Print warning if 8 byte insn appears in delay slot.
	(md_operand): Handle %st(sym1-sym2).
	(get_arc_exp_reloc_type): Likewise.
	(md_apply_fix, case BFD_RELOC_ARC_B26): Now using implicit addends
	so must store them here.
This commit is contained in:
David Edelsohn
1995-04-12 14:41:21 +00:00
parent 5d57a66b5a
commit fa7a56f8dc

View File

@ -31,6 +31,7 @@ static arc_insn arc_insert_operand PARAMS ((arc_insn,
const struct arc_operand *, int, const struct arc_operand *, int,
const struct arc_operand_value *, const struct arc_operand_value *,
offsetT, char *, unsigned int)); offsetT, char *, unsigned int));
static int delay_slot_type PARAMS ((arc_insn));
static void arc_common PARAMS ((int)); static void arc_common PARAMS ((int));
static void arc_cpu PARAMS ((int)); static void arc_cpu PARAMS ((int));
/*static void arc_rename PARAMS ((int));*/ /*static void arc_rename PARAMS ((int));*/
@ -277,6 +278,18 @@ arc_insert_operand (insn, operand, mods, reg, val, file, line)
return insn; return insn;
} }
/* Return the delay slot type for INSN (or -1 if it isn't a branch). */
/* ??? This is a quick hack. May wish to later generalize this concept
to record all suffixes the insn contains (for various warnings, etc.). */
static int
delay_slot_type (arc_insn insn)
{
if ((insn >> 27) >= 4 && (insn >> 27) <= 7)
return (insn & 0x60) >> 5;
return -1;
}
/* We need to keep a list of fixups. We can't simply generate them as /* We need to keep a list of fixups. We can't simply generate them as
we go, because that would require us to first create the frag, and we go, because that would require us to first create the frag, and
that would screw up references to ``.''. */ that would screw up references to ``.''. */
@ -296,7 +309,7 @@ void
md_assemble (str) md_assemble (str)
char *str; char *str;
{ {
const struct arc_opcode *opcode,*opcode_end; const struct arc_opcode *opcode;
char *start; char *start;
arc_insn insn; arc_insn insn;
static int init_tables_p = 0; static int init_tables_p = 0;
@ -313,23 +326,15 @@ md_assemble (str)
while (isspace (*str)) while (isspace (*str))
str++; str++;
/* The instructions are sorted by the first letter. Scan the opcode table /* The instructions are stored in lists hashed by the first letter (though
until we find the right one. */ we needn't care how they're hashed). Get the first in the list. */
opcode_end = arc_opcodes + arc_opcodes_count;
for (opcode = arc_opcodes; opcode < opcode_end; opcode++)
if (*opcode->syntax == *str)
break;
if (opcode == opcode_end)
{
as_bad ("bad instruction `%s'", str);
return;
}
/* Keep looking until we find a match. If we haven't found a match, and the opcode = arc_opcode_asm_list (str);
first character no longer matches, we needn't look any further. */
/* Keep looking until we find a match. */
start = str; start = str;
for ( ; opcode < opcode_end && *opcode->syntax == *start; ++opcode) for ( ; opcode != NULL; opcode = ARC_OPCODE_NEXT_ASM (opcode))
{ {
int past_opcode_p; int past_opcode_p;
char *syn; char *syn;
@ -604,11 +609,12 @@ md_assemble (str)
{ {
int i; int i;
char *f; char *f;
long limm; long limm, limm_p;
/* ??? For the moment we assume a valid `str' can only contain blanks /* For the moment we assume a valid `str' can only contain blanks
now. IE: We needn't try again with a longer version of the now. IE: We needn't try again with a longer version of the
insn. */ insn and it is assumed that longer versions of insns appear
before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3). */
while (isspace (*str)) while (isspace (*str))
++str; ++str;
@ -616,11 +622,28 @@ md_assemble (str)
if (*str != '\0') if (*str != '\0')
as_bad ("junk at end of line: `%s'", str); as_bad ("junk at end of line: `%s'", str);
/* Is there a limm value? */
limm_p = arc_opcode_limm_p (&limm);
/* Putting an insn with a limm value in a delay slot is supposed to
be legal, but let's warn the user anyway. Ditto for 8 byte jumps
with delay slots. */
{
static int in_delay_slot_p = 0;
int this_insn_delay_slot_type = delay_slot_type (insn);
if (in_delay_slot_p && limm_p)
as_warn ("8 byte instruction in delay slot");
if (this_insn_delay_slot_type > 0 && limm_p)
as_warn ("8 byte jump instruction with delay slot");
in_delay_slot_p = (this_insn_delay_slot_type > 0) && !limm_p;
}
/* Write out the instruction. /* Write out the instruction.
It is important to fetch enough space in one call to `frag_more'. It is important to fetch enough space in one call to `frag_more'.
We use (f - frag_now->fr_literal) to compute where we are and we We use (f - frag_now->fr_literal) to compute where we are and we
don't want frag_now to change between calls. */ don't want frag_now to change between calls. */
if (arc_opcode_limm_p (&limm)) if (limm_p)
{ {
f = frag_more (8); f = frag_more (8);
md_number_to_chars (f, insn, 4); md_number_to_chars (f, insn, 4);
@ -1036,8 +1059,6 @@ md_operand (expressionP)
if (*p == '%' && strncmp (p, "%st(", 4) == 0) if (*p == '%' && strncmp (p, "%st(", 4) == 0)
{ {
expressionS two;
input_line_pointer += 4; input_line_pointer += 4;
expression (expressionP); expression (expressionP);
if (*input_line_pointer != ')') if (*input_line_pointer != ')')
@ -1046,18 +1067,40 @@ md_operand (expressionP)
return; return;
} }
++input_line_pointer; ++input_line_pointer;
if (expressionP->X_op != O_symbol if (expressionP->X_op == O_symbol
|| expressionP->X_add_number != 0) && expressionP->X_add_number == 0
/* I think this test is unnecessary but just as a sanity check... */
&& expressionP->X_op_symbol == NULL)
{ {
as_bad ("expression too complex for %st"); expressionS two;
return;
}
expressionP->X_op = O_right_shift; expressionP->X_op = O_right_shift;
two.X_op = O_constant; two.X_op = O_constant;
two.X_add_symbol = two.X_op_symbol = NULL; two.X_add_symbol = two.X_op_symbol = NULL;
two.X_add_number = 2; two.X_add_number = 2;
expressionP->X_op_symbol = make_expr_symbol (&two); expressionP->X_op_symbol = make_expr_symbol (&two);
} }
/* allow %st(sym1-sym2) */
else if (expressionP->X_op == O_subtract
&& expressionP->X_add_symbol != NULL
&& expressionP->X_op_symbol != NULL
&& expressionP->X_add_number == 0)
{
expressionS two;
expressionP->X_add_symbol = make_expr_symbol (expressionP);
expressionP->X_op = O_right_shift;
two.X_op = O_constant;
two.X_add_symbol = two.X_op_symbol = NULL;
two.X_add_number = 2;
expressionP->X_op_symbol = make_expr_symbol (&two);
}
else
{
as_bad ("expression too complex for %%st");
return;
}
}
} }
/* We have no need to default values of symbols. /* We have no need to default values of symbols.
@ -1160,25 +1203,31 @@ get_arc_exp_reloc_type (data_p, default_type, exp, expnew)
expressionS *expnew; expressionS *expnew;
{ {
/* If the expression is "symbol >> 2" we must change it to just "symbol", /* If the expression is "symbol >> 2" we must change it to just "symbol",
as fix_new_exp can't handle it. That's ok though. What's really going as fix_new_exp can't handle it. Similarily for (symbol - symbol) >> 2.
on here is that we're using ">> 2" as a special syntax for specifying That's ok though. What's really going on here is that we're using
BFD_RELOC_ARC_B26. */ ">> 2" as a special syntax for specifying BFD_RELOC_ARC_B26. */
if (exp->X_op == O_right_shift) if (exp->X_op == O_right_shift
{
if (exp->X_add_symbol != NULL
&& (exp->X_add_symbol->sy_value.X_op == O_constant
|| exp->X_add_symbol->sy_value.X_op == O_symbol)
&& exp->X_op_symbol != NULL && exp->X_op_symbol != NULL
&& exp->X_op_symbol->sy_value.X_op == O_constant && exp->X_op_symbol->sy_value.X_op == O_constant
&& exp->X_op_symbol->sy_value.X_add_number == 2 && exp->X_op_symbol->sy_value.X_add_number == 2
&& exp->X_add_number == 0) && exp->X_add_number == 0)
{
if (exp->X_add_symbol != NULL
&& (exp->X_add_symbol->sy_value.X_op == O_constant
|| exp->X_add_symbol->sy_value.X_op == O_symbol))
{ {
*expnew = *exp; *expnew = *exp;
expnew->X_op = O_symbol; expnew->X_op = O_symbol;
expnew->X_op_symbol = NULL; expnew->X_op_symbol = NULL;
return data_p ? BFD_RELOC_ARC_B26 : arc_operand_map['J']; return data_p ? BFD_RELOC_ARC_B26 : arc_operand_map['J'];
} }
else if (exp->X_add_symbol != NULL
&& exp->X_add_symbol->sy_value.X_op == O_subtract)
{
*expnew = exp->X_add_symbol->sy_value;
return data_p ? BFD_RELOC_ARC_B26 : arc_operand_map['J'];
}
} }
*expnew = *exp; *expnew = *exp;
@ -1314,7 +1363,6 @@ md_apply_fix (fixP, valueP)
value, 2); value, 2);
break; break;
case BFD_RELOC_32: case BFD_RELOC_32:
case BFD_RELOC_ARC_B26:
md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
value, 4); value, 4);
break; break;
@ -1324,6 +1372,15 @@ md_apply_fix (fixP, valueP)
value, 8); value, 8);
break; break;
#endif #endif
case BFD_RELOC_ARC_B26:
/* If !fixP->fx_done then `value' is an implicit addend.
We must shift it right by 2 in this case as well because the
linker performs the relocation and then adds this in (as opposed
to adding this in and then shifting right by 2). */
value >>= 2;
md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
value, 4);
break;
default: default:
abort (); abort ();
} }