From dfe96118e51d6ac4c64cc198719c540c0c30b601 Mon Sep 17 00:00:00 2001 From: "J\"orn Rennecke" Date: Mon, 16 Nov 1998 13:04:01 +0000 Subject: [PATCH] reload1.c (reload_reg_free_before_p): Delete. * reload1.c (reload_reg_free_before_p): Delete. Changed all callers to use reload_reg_free_for_value_p instead. (reload_reg_free_for_value_p): Handle more reload types. A RELOAD_FOR_INPUT doesn't conflict with its RELOAD_FOR_INPUT_ADDRESS / RELOAD_FOR_INPADDR_ADDRESS. Add special case for OUT == const0_rtx. Added ignore_address_reloads argument. Changed all callers. From-SVN: r23675 --- gcc/ChangeLog | 10 ++ gcc/reload1.c | 358 ++++++++++++++++---------------------------------- 2 files changed, 122 insertions(+), 246 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7a5306486ce..af1367a8bbd 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +Mon Nov 16 21:02:52 1998 J"orn Rennecke + + * reload1.c (reload_reg_free_before_p): Delete. + Changed all callers to use reload_reg_free_for_value_p instead. + (reload_reg_free_for_value_p): Handle more reload types. + A RELOAD_FOR_INPUT doesn't conflict with its + RELOAD_FOR_INPUT_ADDRESS / RELOAD_FOR_INPADDR_ADDRESS. + Add special case for OUT == const0_rtx. + Added ignore_address_reloads argument. Changed all callers. + Mon Nov 16 02:22:29 1998 Jason Merrill * toplev.c (compile_file): Don't pedwarn about undefined static diff --git a/gcc/reload1.c b/gcc/reload1.c index 5df3c155f75..f21b6223fb4 100644 --- a/gcc/reload1.c +++ b/gcc/reload1.c @@ -406,8 +406,7 @@ static void mark_reload_reg_in_use PROTO((int, int, enum reload_type, 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)); @@ -4817,175 +4816,6 @@ reload_reg_free_p (regno, opnum, type) 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. @@ -5222,14 +5052,21 @@ int reload_spill_index[MAX_RELOADS]; 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; @@ -5238,6 +5075,13 @@ reload_reg_free_for_value_p (regno, opnum, type, value, out, reloadnum) { 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 @@ -5259,6 +5103,9 @@ reload_reg_free_for_value_p (regno, opnum, type, value, out, reloadnum) 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 @@ -5266,31 +5113,34 @@ reload_reg_free_for_value_p (regno, opnum, type, value, out, reloadnum) 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++) @@ -5301,11 +5151,6 @@ reload_reg_free_for_value_p (regno, opnum, type, value, out, reloadnum) <= 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]) { @@ -5322,48 +5167,87 @@ reload_reg_free_for_value_p (regno, opnum, type, value, out, reloadnum) 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; } } @@ -5455,7 +5339,7 @@ allocate_reload_reg (chain, r, last_reload, noerror) 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 @@ -5903,15 +5787,10 @@ choose_reload_regs (chain) && (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. */ @@ -5945,6 +5824,9 @@ choose_reload_regs (chain) 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] @@ -6032,7 +5914,7 @@ choose_reload_regs (chain) && ! 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; @@ -6240,14 +6122,13 @@ choose_reload_regs (chain) 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; @@ -6600,31 +6481,14 @@ emit_reload_insns (chain) { 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 @@ -6772,9 +6636,11 @@ emit_reload_insns (chain) && 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) -- 2.30.2