static void clear_reload_reg_in_use PROTO((int, int, enum reload_type,
enum machine_mode));
static int reload_reg_free_p PROTO((int, int, enum reload_type));
-static int reload_reg_free_before_p PROTO((int, int, enum reload_type, int));
-static int reload_reg_free_for_value_p PROTO((int, int, enum reload_type, rtx, rtx, int));
+static int reload_reg_free_for_value_p PROTO((int, int, enum reload_type, rtx, rtx, int, int));
static int reload_reg_reaches_end_p PROTO((int, int, enum reload_type));
static int allocate_reload_reg PROTO((struct insn_chain *, int, int,
int));
abort ();
}
-/* Return 1 if the value in reload reg REGNO, as used by a reload
- needed for the part of the insn specified by OPNUM and TYPE,
- is not in use for a reload in any prior part of the insn.
-
- We can assume that the reload reg was already tested for availability
- at the time it is needed, and we should not check this again,
- in case the reg has already been marked in use.
-
- However, if EQUIV is set, we are checking the availability of a register
- holding an equivalence to the value to be loaded into the reload register,
- not the availability of the reload register itself.
-
- This is still less stringent than what reload_reg_free_p checks; for
- example, compare the checks for RELOAD_OTHER. */
-
-static int
-reload_reg_free_before_p (regno, opnum, type, equiv)
- int regno;
- int opnum;
- enum reload_type type;
- int equiv;
-{
- int i;
-
- /* The code to handle EQUIV below is wrong.
-
- If we wnat to know if a value in a particular reload register is available
- at a particular point in time during reloading, we must check *all*
- prior reloads to see if they clobber the value.
-
- Note this is significantly different from determining when a register is
- free for usage in a reload!
-
- This change is temporary. It will go away. */
- if (equiv)
- return 0;
-
- switch (type)
- {
- case RELOAD_FOR_OTHER_ADDRESS:
- /* These always come first. */
- if (equiv && TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno))
- return 0;
- return 1;
-
- case RELOAD_OTHER:
- if (equiv && TEST_HARD_REG_BIT (reload_reg_used, regno))
- return 0;
- return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno);
-
- /* If this use is for part of the insn,
- check the reg is not in use for any prior part. It is tempting
- to try to do this by falling through from objecs that occur
- later in the insn to ones that occur earlier, but that will not
- correctly take into account the fact that here we MUST ignore
- things that would prevent the register from being allocated in
- the first place, since we know that it was allocated. */
-
- case RELOAD_FOR_OUTPUT_ADDRESS:
- if (equiv
- && TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[opnum], regno))
- return 0;
- /* Earlier reloads include RELOAD_FOR_OUTADDR_ADDRESS reloads. */
- if (TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[opnum], regno))
- return 0;
- /* ... fall through ... */
- case RELOAD_FOR_OUTADDR_ADDRESS:
- if (equiv
- && (TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[opnum], regno)
- || TEST_HARD_REG_BIT (reload_reg_used, regno)))
- return 0;
- /* Earlier reloads are for earlier outputs or their addresses,
- any RELOAD_FOR_INSN reloads, any inputs or their addresses, or any
- RELOAD_FOR_OTHER_ADDRESS reloads (we know it can't conflict with
- RELOAD_OTHER).. */
- for (i = 0; i < opnum; i++)
- if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
- || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno))
- return 0;
-
- if (TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno))
- return 0;
-
- for (i = 0; i < reload_n_operands; i++)
- if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
- || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno)
- || TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno)
- || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
- return 0;
-
- return (! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno)
- && ! TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno)
- && ! TEST_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, regno)
- && ! TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno));
-
- case RELOAD_FOR_OUTPUT:
- case RELOAD_FOR_INSN:
- /* There is no reason to call this function for output reloads, thus
- anything we'd put here wouldn't be tested. So just abort. */
- abort ();
-
- case RELOAD_FOR_OPERAND_ADDRESS:
- if (equiv && TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno))
- return 0;
-
- /* Earlier reloads include RELOAD_FOR_OPADDR_ADDR reloads. */
- if (TEST_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, regno))
- return 0;
-
- /* ... fall through ... */
-
- case RELOAD_FOR_OPADDR_ADDR:
- if (equiv)
- {
- if (TEST_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, regno)
- || TEST_HARD_REG_BIT (reload_reg_used, regno))
- return 0;
- for (i = 0; i < reload_n_operands; i++)
- if (TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
- return 0;
- }
- /* These can't conflict with inputs, or each other, so all we have to
- test is input addresses and the addresses of OTHER items. */
-
- for (i = 0; i < reload_n_operands; i++)
- if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
- || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno))
- return 0;
-
- return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno);
-
- case RELOAD_FOR_INPUT:
- if (equiv && TEST_HARD_REG_BIT (reload_reg_used, regno))
- return 0;
-
- /* The only things earlier are the address for this and
- earlier inputs, other inputs (which we know we don't conflict
- with), and addresses of RELOAD_OTHER objects.
- We can ignore the conflict with addresses of this operand, since
- when we inherit this operand, its address reloads are discarded. */
-
- for (i = 0; i < opnum; i++)
- if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
- || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno))
- return 0;
-
- return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno);
-
- case RELOAD_FOR_INPUT_ADDRESS:
- /* Earlier reloads include RELOAD_FOR_INPADDR_ADDRESS reloads. */
- if (TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[opnum], regno))
- return 0;
- /* ... fall through ... */
- case RELOAD_FOR_INPADDR_ADDRESS:
- if (equiv && TEST_HARD_REG_BIT (reload_reg_used, regno))
- return 0;
-
- /* Similarly, all we have to check is for use in earlier inputs'
- addresses. */
- for (i = 0; i < opnum; i++)
- if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
- || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno))
- return 0;
-
- return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno);
- }
- abort ();
-}
-
/* Return 1 if the value in reload reg REGNO, as used by a reload
needed for the part of the insn specified by OPNUM and TYPE,
is still available in REGNO at the end of the insn.
Other read-only reloads with the same value do not conflict
unless OUT is non-zero and these other reloads have to live while
output reloads live.
+ If OUT is CONST0_RTX, this is a special case: it means that the
+ test should not be for using register REGNO as reload register, but
+ for copying from register REGNO into the reload register.
RELOADNUM is the number of the reload we want to load this value for;
a reload does not conflict with itself.
+ When IGNORE_ADDRESS_RELOADS is set, we can not have conflicts with
+ reloads that load an address for the very reload we are considering.
+
The caller has to make sure that there is no conflict with the return
register. */
static int
-reload_reg_free_for_value_p (regno, opnum, type, value, out, reloadnum)
+reload_reg_free_for_value_p (regno, opnum, type, value, out, reloadnum,
+ ignore_address_reloads)
int regno;
int opnum;
enum reload_type type;
{
int time1;
int i;
+ int copy = 0;
+
+ if (out == const0_rtx)
+ {
+ copy = 1;
+ out = NULL_RTX;
+ }
/* We use some pseudo 'time' value to check if the lifetimes of the
new register use would overlap with the one of a previous reload
case RELOAD_FOR_OTHER_ADDRESS:
time1 = 0;
break;
+ case RELOAD_OTHER:
+ time1 = copy ? 1 : MAX_RECOG_OPERANDS * 5 + 5;
+ break;
/* For each input, we might have a sequence of RELOAD_FOR_INPADDR_ADDRESS,
RELOAD_FOR_INPUT_ADDRESS and RELOAD_FOR_INPUT. By adding 0 / 1 / 2 ,
respectively, to the time values for these, we get distinct time
multiply opnum by at least three. We round that up to four because
multiply by four is often cheaper. */
case RELOAD_FOR_INPADDR_ADDRESS:
- time1 = opnum * 4 + 1;
+ time1 = opnum * 4 + 2;
break;
case RELOAD_FOR_INPUT_ADDRESS:
- time1 = opnum * 4 + 2;
+ time1 = opnum * 4 + 3;
+ break;
+ case RELOAD_FOR_INPUT:
+ /* All RELOAD_FOR_INPUT reloads remain live till the instruction
+ executes (inclusive). */
+ time1 = copy ? opnum * 4 + 4 : MAX_RECOG_OPERANDS * 4 + 3;
break;
case RELOAD_FOR_OPADDR_ADDR:
- /* opnum * 4 + 3 < opnum * 4 + 4
+ /* opnum * 4 + 4
<= (MAX_RECOG_OPERANDS - 1) * 4 + 4 == MAX_RECOG_OPERANDS * 4 */
- time1 = MAX_RECOG_OPERANDS * 4;
- break;
- case RELOAD_FOR_INPUT:
- /* All RELOAD_FOR_INPUT reloads remain live till just before the
- instruction is executed. */
time1 = MAX_RECOG_OPERANDS * 4 + 1;
break;
case RELOAD_FOR_OPERAND_ADDRESS:
/* RELOAD_FOR_OPERAND_ADDRESS reloads are live even while the insn
is executed. */
- time1 = MAX_RECOG_OPERANDS * 4 + 2;
+ time1 = copy ? MAX_RECOG_OPERANDS * 4 + 2 : MAX_RECOG_OPERANDS * 4 + 3;
+ break;
+ case RELOAD_FOR_OUTADDR_ADDRESS:
+ time1 = MAX_RECOG_OPERANDS * 4 + 4 + opnum;
break;
case RELOAD_FOR_OUTPUT_ADDRESS:
- time1 = MAX_RECOG_OPERANDS * 4 + 3 + opnum;
+ time1 = MAX_RECOG_OPERANDS * 4 + 5 + opnum;
break;
default:
- time1 = MAX_RECOG_OPERANDS * 5 + 3;
+ time1 = MAX_RECOG_OPERANDS * 5 + 5;
}
for (i = 0; i < n_reloads; i++)
<= HARD_REGNO_NREGS (REGNO (reg), GET_MODE (reg)) - (unsigned)1)
&& i != reloadnum)
{
- if (out
- && reload_when_needed[i] != RELOAD_FOR_INPUT
- && reload_when_needed[i] != RELOAD_FOR_INPUT_ADDRESS
- && reload_when_needed[i] != RELOAD_FOR_INPADDR_ADDRESS)
- return 0;
if (! reload_in[i] || ! rtx_equal_p (reload_in[i], value)
|| reload_out[i])
{
RELOAD_FOR_{INPUT,OPERAND,OUTPUT}_ADDRESS . If the
address reload is inherited, the address address reload
goes away, so we can ignore this conflict. */
- if (type == RELOAD_FOR_INPUT_ADDRESS && reloadnum == i + 1)
+ if (type == RELOAD_FOR_INPUT_ADDRESS && reloadnum == i + 1
+ && ignore_address_reloads
+ /* Unless the RELOAD_FOR_INPUT is an auto_inc expression.
+ Then the address address is still needed to store
+ back the new address. */
+ && ! reload_out[reloadnum])
continue;
- time2 = reload_opnum[i] * 4 + 1;
+ /* Likewise, if a RELOAD_FOR_INPUT can inherit a value, its
+ RELOAD_FOR_INPUT_ADDRESS / RELOAD_FOR_INPADDR_ADDRESS
+ reloads go away. */
+ if (type == RELOAD_FOR_INPUT && opnum == reload_opnum[i]
+ && ignore_address_reloads
+ /* Unless we are reloading an auto_inc expression. */
+ && ! reload_out[reloadnum])
+ continue;
+ time2 = reload_opnum[i] * 4 + 2;
break;
case RELOAD_FOR_INPUT_ADDRESS:
- time2 = reload_opnum[i] * 4 + 2;
+ if (type == RELOAD_FOR_INPUT && opnum == reload_opnum[i]
+ && ignore_address_reloads
+ && ! reload_out[reloadnum])
+ continue;
+ time2 = reload_opnum[i] * 4 + 3;
break;
case RELOAD_FOR_INPUT:
- time2 = reload_opnum[i] * 4 + 3;
+ time2 = reload_opnum[i] * 4 + 4;
break;
+ /* reload_opnum[i] * 4 + 4 <= (MAX_RECOG_OPERAND - 1) * 4 + 4
+ == MAX_RECOG_OPERAND * 4 */
case RELOAD_FOR_OPADDR_ADDR:
- if (type == RELOAD_FOR_OPERAND_ADDRESS && reloadnum == i + 1)
+ if (type == RELOAD_FOR_OPERAND_ADDRESS && reloadnum == i + 1
+ && ignore_address_reloads
+ && ! reload_out[reloadnum])
continue;
- time2 = MAX_RECOG_OPERANDS * 4;
+ time2 = MAX_RECOG_OPERANDS * 4 + 1;
break;
case RELOAD_FOR_OPERAND_ADDRESS:
- time2 = MAX_RECOG_OPERANDS * 4 + 1;
+ time2 = MAX_RECOG_OPERANDS * 4 + 2;
+ break;
+ case RELOAD_FOR_INSN:
+ time2 = MAX_RECOG_OPERANDS * 4 + 3;
break;
case RELOAD_FOR_OUTPUT:
/* All RELOAD_FOR_OUTPUT reloads become live just after the
instruction is executed. */
- time2 = MAX_RECOG_OPERANDS * 4 + 3;
+ time2 = MAX_RECOG_OPERANDS * 4 + 4;
break;
+ /* The first RELOAD_FOR_OUTADDR_ADDRESS reload conflicts with
+ the RELOAD_FOR_OUTPUT reloads, so assign it the same time
+ value. */
case RELOAD_FOR_OUTADDR_ADDRESS:
- if (type == RELOAD_FOR_OUTPUT_ADDRESS && reloadnum == i + 1)
+ if (type == RELOAD_FOR_OUTPUT_ADDRESS && reloadnum == i + 1
+ && ignore_address_reloads
+ && ! reload_out[reloadnum])
continue;
- /* fall through. */
- /* The first RELOAD_FOR_OUTPUT_ADDRESS reload conflicts with the
- RELOAD_FOR_OUTPUT reloads, so assign it the same time value. */
+ time2 = MAX_RECOG_OPERANDS * 4 + 4 + reload_opnum[i];
+ break;
case RELOAD_FOR_OUTPUT_ADDRESS:
- time2 = MAX_RECOG_OPERANDS * 4 + 3 + reload_opnum[i];
+ time2 = MAX_RECOG_OPERANDS * 4 + 5 + reload_opnum[i];
break;
case RELOAD_OTHER:
+ /* If there is no conflict in the input part, handle this
+ like an output reload. */
if (! reload_in[i] || rtx_equal_p (reload_in[i], value))
{
- time2 = MAX_RECOG_OPERANDS * 4 + 3;
+ time2 = MAX_RECOG_OPERANDS * 4 + 4;
break;
}
+ time2 = 1;
+ /* RELOAD_OTHER might be live beyond instruction execution,
+ but this is not obvious when we set time2 = 1. So check
+ here if there might be a problem with the new reload
+ clobbering the register used by the RELOAD_OTHER. */
+ if (out)
+ return 0;
+ break;
default:
- time2 = 0;
+ return 0;
}
- if (time1 >= time2)
+ if (time1 >= time2
+ || (out && time2 >= MAX_RECOG_OPERANDS * 4 + 4))
return 0;
}
}
reload_opnum[r],
reload_when_needed[r],
reload_in[r],
- reload_out[r], r)))
+ reload_out[r], r, 1)))
&& TEST_HARD_REG_BIT (reg_class_contents[class], regnum)
&& HARD_REGNO_MODE_OK (regnum, reload_mode[r])
/* Look first for regs to share, then for unshared. But
&& (reload_nregs[r] == max_group_size
|| ! TEST_HARD_REG_BIT (reg_class_contents[(int) group_class],
i))
- && ((reload_reg_free_p (i, reload_opnum[r],
- reload_when_needed[r])
- && reload_reg_free_before_p (i, reload_opnum[r],
- reload_when_needed[r],
- 0))
- || reload_reg_free_for_value_p (i, reload_opnum[r],
- reload_when_needed[r],
- reload_in[r],
- reload_out[r], r)))
+ && reload_reg_free_for_value_p (i, reload_opnum[r],
+ reload_when_needed[r],
+ reload_in[r],
+ const0_rtx, r, 1))
{
/* If a group is needed, verify that all the subsequent
registers still have their values intact. */
break;
if (i1 != n_earlyclobbers
+ || ! (reload_reg_free_for_value_p
+ (i, reload_opnum[r], reload_when_needed[r],
+ reload_in[r], reload_out[r], r, 1))
/* Don't use it if we'd clobber a pseudo reg. */
|| (TEST_HARD_REG_BIT (reg_used_by_pseudo, i)
&& reload_out[r]
&& ! reload_reg_free_for_value_p (regno, reload_opnum[r],
reload_when_needed[r],
reload_in[r],
- reload_out[r], r))
+ reload_out[r], r, 1))
|| ! TEST_HARD_REG_BIT (reg_class_contents[(int) reload_reg_class[r]],
regno)))
equiv = 0;
check_reg = reload_override_in[r];
else
continue;
- if (! (reload_reg_free_before_p (true_regnum (check_reg),
- reload_opnum[r], reload_when_needed[r],
- ! reload_inherited[r])
- || reload_reg_free_for_value_p (true_regnum (check_reg),
+ if (! reload_reg_free_for_value_p (true_regnum (check_reg),
reload_opnum[r],
reload_when_needed[r],
reload_in[r],
- reload_out[r], r)))
+ (reload_inherited[r]
+ ? reload_out[r] : const0_rtx),
+ r, 1))
{
if (pass)
continue;
{
int regno = true_regnum (oldequiv);
- /* If OLDEQUIV is a spill register, don't use it for this
- if any other reload needs it at an earlier stage of this insn
- or at this stage. */
- if (spill_reg_order[regno] >= 0
- && (! reload_reg_free_p (regno, reload_opnum[j],
- reload_when_needed[j])
- || ! reload_reg_free_before_p (regno, reload_opnum[j],
- reload_when_needed[j], 1)))
+ /* Don't use OLDEQUIV if any other reload changes it at an
+ earlier stage of this insn or at this stage. */
+ if (! reload_reg_free_for_value_p (regno, reload_opnum[j],
+ reload_when_needed[j],
+ reload_in[j], const0_rtx, j,
+ 0))
oldequiv = 0;
- /* If OLDEQUIV is not a spill register,
- don't use it if any other reload wants it. */
- if (spill_reg_order[regno] < 0)
- {
- int k;
- for (k = 0; k < n_reloads; k++)
- if (reload_reg_rtx[k] != 0 && k != j
- && reg_overlap_mentioned_for_reload_p (reload_reg_rtx[k],
- oldequiv))
- {
- oldequiv = 0;
- break;
- }
- }
-
/* If it is no cheaper to copy from OLDEQUIV into the
reload register than it would be to move from memory,
don't use it. Likewise, if we need a secondary register
&& dead_or_set_p (insn, old)
/* This is unsafe if some other reload
uses the same reg first. */
- && reload_reg_free_before_p (REGNO (reloadreg),
- reload_opnum[j],
- reload_when_needed[j], 0))
+ && reload_reg_free_for_value_p (REGNO (reloadreg),
+ reload_opnum[j],
+ reload_when_needed[j],
+ old, reload_out[j],
+ j, 0))
{
rtx temp = PREV_INSN (insn);
while (temp && GET_CODE (temp) == NOTE)