PR 34995: EXTRA_MEMORY_CONSTRAINTs and constant addresses
Richard Sandiford
rsandifo@nildram.co.uk
Wed Jan 30 14:46:00 GMT 2008
The documentation for EXTRA_MEMORY_CONSTRAINT says:
It should return 1 if the operand type represented by the constraint
at the start of @var{str}, the first letter of which is the letter @var{c},
comprises a subset of all memory references including
all those whose address is simply a base register.
What the documentation doesn't say is that if GO_IF_LEGITIMATE_ADDRESS
accepts constant-pool references of the form (mem (symbol_ref X)),
all EXTRA_MEMORY_CONSTRAINTS must too. This is due to:
/* Return 1 if alternative number ALTNUM in constraint-string CONSTRAINT
accepts a memory operand with constant address. */
static int
alternative_allows_memconst (const char *constraint, int altnum)
{
...
for (; (c = *constraint) && c != ',' && c != '#';
constraint += CONSTRAINT_LEN (c, constraint))
if (c == 'm' || c == 'o' || EXTRA_MEMORY_CONSTRAINT (c, constraint))
return 1;
return 0;
}
So if reload forces a constant into the constant pool for an
EXTRA_MEMORY_CONSTRAINT, and if the result is valid accordingly
to GO_IF_LEGITIMATE_ADDRESS, we unconditionally assume that the
result is valid for the extra constraint too, rather than reloading
the address into a register.
This causes problems with MIPS "W" constraints, which only allow
addresses based on BASE_REGS. It could theoretically also affect
"R" constraints with -mno-explicit-relocs, because some valid
(mem (symbol_ref X)) addresses are not single-insn ones.
The relevant find_reloads code is:
if (! goal_alternative_win[i]
&& CONST_POOL_OK_P (recog_data.operand[i])
&& ((PREFERRED_RELOAD_CLASS (recog_data.operand[i],
(enum reg_class) goal_alternative[i])
== NO_REGS)
|| no_input_reloads)
&& operand_mode[i] != VOIDmode)
{
substed_operand[i] = recog_data.operand[i]
= find_reloads_toplev (force_const_mem (operand_mode[i],
recog_data.operand[i]),
i, address_type[i], ind_levels, 0, insn,
NULL);
if (alternative_allows_memconst (recog_data.constraints[i],
goal_alternative_number))
goal_alternative_win[i] = 1;
}
Now if find_reloads_toplev generates an address reload for the
constant-pool reference, EXTRA_MEMORY_CONSTRAINTs must indeed accept
the result; the original address will have been a SYMBOL_REF and the
post-reload form will be a base register. However, if no address
reloads are generated, I think EXTRA_CONSTRAINT_STR should have the
option of forcing a reload anyway. If we don't set goal_alternative_win
to 1, such a reload will be generated by the normal 'o'/E_M_C handling:
if (! goal_alternative_win[i])
{
/* Operands that match previous ones have already been handled. */
if (goal_alternative_matches[i] >= 0)
;
/* Handle an operand with a nonoffsettable address
appearing where an offsettable address will do
by reloading the address into a base register.
??? We can also do this when the operand is a register and
reg_equiv_mem is not offsettable, but this is a bit tricky,
so we don't bother with it. It may not be worth doing. */
else if (goal_alternative_matched[i] == -1
&& goal_alternative_offmemok[i]
&& MEM_P (recog_data.operand[i]))
{
...
Boostrapped & regression-tested on x86_64-linux-gnu. Also
regression-tested on mipsisa64-elfoabi. OK to install?
Richard
gcc/
PR rtl-optimization/34995
* reload.c (alternative_allows_const_pool_ref): Take an rtx
parameter and return a bool. If the rtx parameter is nonnull,
check that it satisfies an EXTRA_MEMORY_CONSTRAINT.
(find_reloads): Update call accordingly. Pass the new operand
if it needed no address reloads, otherwise pass null.
Index: gcc/reload.c
===================================================================
--- gcc/reload.c 2008-01-29 10:06:14.000000000 +0000
+++ gcc/reload.c 2008-01-29 10:32:48.000000000 +0000
@@ -263,7 +263,7 @@ static rtx find_dummy_reload (rtx, rtx,
static int hard_reg_set_here_p (unsigned int, unsigned int, rtx);
static struct decomposition decompose (rtx);
static int immune_p (rtx, rtx, struct decomposition);
-static int alternative_allows_memconst (const char *, int);
+static bool alternative_allows_const_pool_ref (rtx, const char *, int);
static rtx find_reloads_toplev (rtx, int, enum reload_type, int, int, rtx,
int *);
static rtx make_memloc (rtx, int);
@@ -3836,13 +3836,19 @@ find_reloads (rtx insn, int replace, int
|| no_input_reloads)
&& operand_mode[i] != VOIDmode)
{
+ int this_address_reloaded;
+
+ this_address_reloaded = 0;
substed_operand[i] = recog_data.operand[i]
= find_reloads_toplev (force_const_mem (operand_mode[i],
recog_data.operand[i]),
i, address_type[i], ind_levels, 0, insn,
- NULL);
- if (alternative_allows_memconst (recog_data.constraints[i],
- goal_alternative_number))
+ &this_address_reloaded);
+ if (alternative_allows_const_pool_ref (this_address_reloaded == 0
+ ? substed_operand[i]
+ : NULL,
+ recog_data.constraints[i],
+ goal_alternative_number))
goal_alternative_win[i] = 1;
}
@@ -4498,13 +4504,16 @@ find_reloads (rtx insn, int replace, int
return retval;
}
-/* Return 1 if alternative number ALTNUM in constraint-string CONSTRAINT
- accepts a memory operand with constant address. */
+/* Return true if alternative number ALTNUM in constraint-string
+ CONSTRAINT is guaranteed to accept a reloaded constant-pool reference.
+ MEM gives the reference if it didn't need any reloads, otherwise it
+ is null. */
-static int
-alternative_allows_memconst (const char *constraint, int altnum)
+static bool
+alternative_allows_const_pool_ref (rtx mem, const char *constraint, int altnum)
{
int c;
+
/* Skip alternatives before the one requested. */
while (altnum > 0)
{
@@ -4512,12 +4521,21 @@ alternative_allows_memconst (const char
altnum--;
}
/* Scan the requested alternative for 'm' or 'o'.
- If one of them is present, this alternative accepts memory constants. */
+ If one of them is present, this alternative accepts the result of
+ passing a constant-pool reference through find_reloads_toplev.
+
+ The same is true of extra memory constraints if the address
+ was reloaded into a register. However, the target may elect
+ to disallow the original constant address, forcing it to be
+ reloaded into a register instead. */
for (; (c = *constraint) && c != ',' && c != '#';
constraint += CONSTRAINT_LEN (c, constraint))
- if (c == 'm' || c == 'o' || EXTRA_MEMORY_CONSTRAINT (c, constraint))
- return 1;
- return 0;
+ if (c == 'm'
+ || c == 'o'
+ || (EXTRA_MEMORY_CONSTRAINT (c, constraint)
+ && (mem == NULL || EXTRA_CONSTRAINT_STR (mem, c, constraint))))
+ return true;
+ return false;
}
/* Scan X for memory references and scan the addresses for reloading.
More information about the Gcc-patches
mailing list