* config/tc-mips.c (RELAX_ENCODE): Remove WARN argument.

(RELAX_FIRST, RELAX_SECOND): Turn into 8-bit quantities.
	(RELAX_USE_SECOND): Bump to 0x10000.
	(RELAX_SECOND_LONGER, RELAX_NOMACRO, RELAX_DELAY_SLOT): New flags.
	(mips_macro_warning): New variable.
	(md_assemble): Wrap macro expansion in macro_start() and macro_end().
	(s_cpload, s_cpsetup, s_cprestore, s_cpreturn): Likewise.
	(relax_close_frag): Set mips_macro_warning.first_frag.  Adjust use
	of RELAX_ENCODE.
	(append_insn): Update mips_macro_warning.sizes.
	(macro_start, macro_warning, macro_end): New functions.
	(macro_build): Don't emit warnings here.
	(macro_build_lui, md_estimate_size_before_relax): ...or here.
	(md_convert_frag): Check for cases where one macro alternative
	needs a warning and the other doesn't.  Emit a warning if the
	longer sequence was chosen.
This commit is contained in:
Richard Sandiford 2004-01-23 13:00:18 +00:00
parent 4d7206a284
commit 584892a6d5
2 changed files with 157 additions and 53 deletions

View File

@ -1,3 +1,22 @@
2004-01-23 Richard Sandiford <rsandifo@redhat.com>
* config/tc-mips.c (RELAX_ENCODE): Remove WARN argument.
(RELAX_FIRST, RELAX_SECOND): Turn into 8-bit quantities.
(RELAX_USE_SECOND): Bump to 0x10000.
(RELAX_SECOND_LONGER, RELAX_NOMACRO, RELAX_DELAY_SLOT): New flags.
(mips_macro_warning): New variable.
(md_assemble): Wrap macro expansion in macro_start() and macro_end().
(s_cpload, s_cpsetup, s_cprestore, s_cpreturn): Likewise.
(relax_close_frag): Set mips_macro_warning.first_frag. Adjust use
of RELAX_ENCODE.
(append_insn): Update mips_macro_warning.sizes.
(macro_start, macro_warning, macro_end): New functions.
(macro_build): Don't emit warnings here.
(macro_build_lui, md_estimate_size_before_relax): ...or here.
(md_convert_frag): Check for cases where one macro alternative
needs a warning and the other doesn't. Emit a warning if the
longer sequence was chosen.
2004-01-23 Richard Sandiford <rsandifo@redhat.com>
* config/tc-mips.h (tc_frag_data_type, TC_FRAG_TYPE): Remove.

View File

@ -629,14 +629,27 @@ static int mips_relax_branch;
absolute one. In SVR4 PIC, the first sequence will be for global
symbols and the second will be for local symbols.
The frag's "subtype" is RELAX_ENCODE (FIRST, SECOND, WARN), where
FIRST and SECOND are the lengths of the two sequences in bytes
and WARN is true if ".set nomacro" was in effect when the macro
was expanded. These fields can be extracted using RELAX_FIRST(),
RELAX_SECOND() and RELAX_WARN().
The frag's "subtype" is RELAX_ENCODE (FIRST, SECOND), where FIRST and
SECOND are the lengths of the two sequences in bytes. These fields
can be extracted using RELAX_FIRST() and RELAX_SECOND(). In addition,
the subtype has the following flags:
In addition, the RELAX_USE_SECOND flag is set if it has been decided
that we should use the second sequence instead of the first.
RELAX_USE_SECOND
Set if it has been decided that we should use the second
sequence instead of the first.
RELAX_SECOND_LONGER
Set in the first variant frag if the macro's second implementation
is longer than its first. This refers to the macro as a whole,
not an individual relaxation.
RELAX_NOMACRO
Set in the first variant frag if the macro appeared in a .set nomacro
block and if one alternative requires a warning but the other does not.
RELAX_DELAY_SLOT
Like RELAX_NOMACRO, but indicates that the macro appears in a branch
delay slot.
The frag's "opcode" points to the first fixup for relaxable code.
@ -650,13 +663,14 @@ static int mips_relax_branch;
The code and fixups for the unwanted alternative are discarded
by md_convert_frag. */
#define RELAX_ENCODE(FIRST, SECOND, WARN) \
(((FIRST) << 8) | ((SECOND) << 1) | ((WARN) != 0))
#define RELAX_ENCODE(FIRST, SECOND) (((FIRST) << 8) | (SECOND))
#define RELAX_FIRST(X) (((X) >> 8) & 0x7f)
#define RELAX_SECOND(X) (((X) >> 1) & 0x7f)
#define RELAX_WARN(X) ((X) & 1)
#define RELAX_USE_SECOND 0x8000
#define RELAX_FIRST(X) (((X) >> 8) & 0xff)
#define RELAX_SECOND(X) ((X) & 0xff)
#define RELAX_USE_SECOND 0x10000
#define RELAX_SECOND_LONGER 0x20000
#define RELAX_NOMACRO 0x40000
#define RELAX_DELAY_SLOT 0x80000
/* Branch without likely bit. If label is out of range, we turn:
@ -810,6 +824,21 @@ static struct {
symbolS *symbol;
} mips_relax;
/* Global variables used to decide whether a macro needs a warning. */
static struct {
/* True if the macro is in a branch delay slot. */
bfd_boolean delay_slot_p;
/* For relaxable macros, sizes[0] is the length of the first alternative
in bytes and sizes[1] is the length of the second alternative.
For non-relaxable macros, both elements give the length of the
macro in bytes. */
unsigned int sizes[2];
/* The first variant frag for this macro. */
fragS *first_frag;
} mips_macro_warning;
/* Prototypes for static functions. */
#define internalError() \
@ -823,6 +852,8 @@ static void mips_no_prev_insn (int);
static void mips16_macro_build
(int *, expressionS *, const char *, const char *, va_list);
static void load_register (int *, int, expressionS *, int);
static void macro_start (void);
static void macro_end (void);
static void macro (struct mips_cl_insn * ip);
static void mips16_macro (struct mips_cl_insn * ip);
#ifdef LOSING_COMPILER
@ -1340,10 +1371,12 @@ md_assemble (char *str)
if (insn.insn_mo->pinfo == INSN_MACRO)
{
macro_start ();
if (mips_opts.mips16)
mips16_macro (&insn);
else
macro (&insn);
macro_end ();
}
else
{
@ -1518,10 +1551,9 @@ mips16_mark_labels (void)
static void
relax_close_frag (void)
{
mips_macro_warning.first_frag = frag_now;
frag_var (rs_machine_dependent, 0, 0,
RELAX_ENCODE (mips_relax.sizes[0],
mips_relax.sizes[1],
mips_opts.warn_about_macros),
RELAX_ENCODE (mips_relax.sizes[0], mips_relax.sizes[1]),
mips_relax.symbol, 0, (char *) mips_relax.first_fixup);
memset (&mips_relax.sizes, 0, sizeof (mips_relax.sizes));
@ -2025,6 +2057,11 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
mips_relax.sizes[mips_relax.sequence - 1] += 4;
}
if (mips_relax.sequence != 2)
mips_macro_warning.sizes[0] += 4;
if (mips_relax.sequence != 1)
mips_macro_warning.sizes[1] += 4;
f = frag_more (4);
}
@ -2851,6 +2888,71 @@ mips_emit_delays (bfd_boolean insns)
mips_no_prev_insn (insns);
}
/* Set up global variables for the start of a new macro. */
static void
macro_start (void)
{
memset (&mips_macro_warning.sizes, 0, sizeof (mips_macro_warning.sizes));
mips_macro_warning.delay_slot_p = (mips_opts.noreorder
&& (prev_insn.insn_mo->pinfo
& (INSN_UNCOND_BRANCH_DELAY
| INSN_COND_BRANCH_DELAY
| INSN_COND_BRANCH_LIKELY)) != 0);
}
/* Given that a macro is longer than 4 bytes, return the appropriate warning
for it. Return null if no warning is needed. SUBTYPE is a bitmask of
RELAX_DELAY_SLOT and RELAX_NOMACRO. */
static const char *
macro_warning (relax_substateT subtype)
{
if (subtype & RELAX_DELAY_SLOT)
return _("Macro instruction expanded into multiple instructions"
" in a branch delay slot");
else if (subtype & RELAX_NOMACRO)
return _("Macro instruction expanded into multiple instructions");
else
return 0;
}
/* Finish up a macro. Emit warnings as appropriate. */
static void
macro_end (void)
{
if (mips_macro_warning.sizes[0] > 4 || mips_macro_warning.sizes[1] > 4)
{
relax_substateT subtype;
/* Set up the relaxation warning flags. */
subtype = 0;
if (mips_macro_warning.sizes[1] > mips_macro_warning.sizes[0])
subtype |= RELAX_SECOND_LONGER;
if (mips_opts.warn_about_macros)
subtype |= RELAX_NOMACRO;
if (mips_macro_warning.delay_slot_p)
subtype |= RELAX_DELAY_SLOT;
if (mips_macro_warning.sizes[0] > 4 && mips_macro_warning.sizes[1] > 4)
{
/* Either the macro has a single implementation or both
implementations are longer than 4 bytes. Emit the
warning now. */
const char *msg = macro_warning (subtype);
if (msg != 0)
as_warn (msg);
}
else
{
/* One implementation might need a warning but the other
definitely doesn't. */
mips_macro_warning.first_frag->fr_subtype |= subtype;
}
}
}
/* Build an instruction created by a macro expansion. This is passed
a pointer to the count of instructions created so far, an
expression, the name of the instruction to build, an operand format
@ -2866,28 +2968,6 @@ macro_build (char *place ATTRIBUTE_UNUSED, int *counter,
va_start (args, fmt);
if (mips_relax.sequence != 2)
{
if (*counter == 1)
{
/* If the macro is about to expand into a second instruction,
and it is in a delay slot, print a warning. */
if (mips_opts.noreorder
&& (prev_prev_insn.insn_mo->pinfo
& (INSN_UNCOND_BRANCH_DELAY
| INSN_COND_BRANCH_DELAY
| INSN_COND_BRANCH_LIKELY)) != 0)
as_warn (_("Macro instruction expanded into multiple instructions in a branch delay slot"));
/* If the macro is about to expand into a second instruction,
print a warning if needed. We need to pass ip as a parameter
to generate a better warning message here... */
else if (mips_opts.warn_about_macros)
as_warn (_("Macro instruction expanded into multiple instructions"));
}
++*counter;
}
if (mips_opts.mips16)
{
mips16_macro_build (counter, ep, name, fmt, args);
@ -3253,7 +3333,7 @@ macro_build_jalr (int icnt, expressionS *ep)
* Generate a "lui" instruction.
*/
static void
macro_build_lui (char *place ATTRIBUTE_UNUSED, int *counter,
macro_build_lui (char *place ATTRIBUTE_UNUSED, int *counter ATTRIBUTE_UNUSED,
expressionS *ep, int regnum)
{
expressionS high_expr;
@ -3266,15 +3346,6 @@ macro_build_lui (char *place ATTRIBUTE_UNUSED, int *counter,
assert (! mips_opts.mips16);
high_expr = *ep;
if (mips_relax.sequence != 2)
{
/* If the macro is about to expand into a second instruction,
print a warning if needed. We need to pass ip as a parameter
to generate a better warning message here... */
if (mips_opts.warn_about_macros && *counter == 1)
as_warn (_("Macro instruction expanded into multiple instructions"));
++*counter;
}
if (high_expr.X_op == O_constant)
{
@ -12230,12 +12301,14 @@ s_cpload (int ignore ATTRIBUTE_UNUSED)
/* In ELF, this symbol is implicitly an STT_OBJECT symbol. */
symbol_get_bfdsym (ex.X_add_symbol)->flags |= BSF_OBJECT;
macro_start ();
macro_build_lui (NULL, &icnt, &ex, mips_gp_register);
macro_build (NULL, &icnt, &ex, "addiu", "t,r,j", mips_gp_register,
mips_gp_register, BFD_RELOC_LO16);
macro_build (NULL, &icnt, NULL, "addu", "d,v,t", mips_gp_register,
mips_gp_register, tc_get_register (0));
macro_end ();
demand_empty_rest_of_line ();
}
@ -12303,6 +12376,7 @@ s_cpsetup (int ignore ATTRIBUTE_UNUSED)
SKIP_WHITESPACE ();
expression (&ex_sym);
macro_start ();
if (mips_cpreturn_register == -1)
{
ex_off.X_op = O_constant;
@ -12338,6 +12412,7 @@ s_cpsetup (int ignore ATTRIBUTE_UNUSED)
macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t", mips_gp_register,
mips_gp_register, reg1);
macro_end ();
demand_empty_rest_of_line ();
}
@ -12383,8 +12458,10 @@ s_cprestore (int ignore ATTRIBUTE_UNUSED)
ex.X_op_symbol = NULL;
ex.X_add_number = mips_cprestore_offset;
macro_start ();
macro_build_ldst_constoffset (NULL, &icnt, &ex, ADDRESS_STORE_INSN,
mips_gp_register, SP, HAVE_64BIT_ADDRESSES);
macro_end ();
demand_empty_rest_of_line ();
}
@ -12410,6 +12487,7 @@ s_cpreturn (int ignore ATTRIBUTE_UNUSED)
return;
}
macro_start ();
if (mips_cpreturn_register == -1)
{
ex.X_op = O_constant;
@ -12423,6 +12501,7 @@ s_cpreturn (int ignore ATTRIBUTE_UNUSED)
else
macro_build (NULL, &icnt, NULL, "daddu", "d,v,t", mips_gp_register,
mips_cpreturn_register, 0);
macro_end ();
demand_empty_rest_of_line ();
}
@ -12545,9 +12624,11 @@ s_cpadd (int ignore ATTRIBUTE_UNUSED)
}
/* Add $gp to the register named as an argument. */
macro_start ();
reg = tc_get_register (0);
macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
reg, reg, mips_gp_register);
macro_end ();
demand_empty_rest_of_line ();
}
@ -13155,11 +13236,6 @@ md_estimate_size_before_relax (fragS *fragp, asection *segtype)
if (change)
{
fragp->fr_subtype |= RELAX_USE_SECOND;
/* FIXME: This really needs as_warn_where. */
if (RELAX_WARN (fragp->fr_subtype))
as_warn (_("AT used after \".set noat\" or macro used after "
"\".set nomacro\""));
return -RELAX_FIRST (fragp->fr_subtype);
}
else
@ -13680,6 +13756,15 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
second = RELAX_SECOND (fragp->fr_subtype);
fixp = (fixS *) fragp->fr_opcode;
/* Possibly emit a warning if we've chosen the longer option. */
if (((fragp->fr_subtype & RELAX_USE_SECOND) != 0)
== ((fragp->fr_subtype & RELAX_SECOND_LONGER) != 0))
{
const char *msg = macro_warning (fragp->fr_subtype);
if (msg != 0)
as_warn_where (fragp->fr_file, fragp->fr_line, msg);
}
/* Go through all the fixups for the first sequence. Disable them
(by marking them as done) if we're going to use the second
sequence instead. */