diff options
Diffstat (limited to 'gnu/usr.bin/cc/cc_int/reload1.c')
-rw-r--r-- | gnu/usr.bin/cc/cc_int/reload1.c | 312 |
1 files changed, 142 insertions, 170 deletions
diff --git a/gnu/usr.bin/cc/cc_int/reload1.c b/gnu/usr.bin/cc/cc_int/reload1.c index e46d764..d6dadf2 100644 --- a/gnu/usr.bin/cc/cc_int/reload1.c +++ b/gnu/usr.bin/cc/cc_int/reload1.c @@ -327,7 +327,7 @@ struct hard_reg_n_uses { int regno; int uses; }; static int possible_group_p PROTO((int, int *)); static void count_possible_groups PROTO((int *, enum machine_mode *, - int *)); + int *, int)); static int modes_equiv_for_class_p PROTO((enum machine_mode, enum machine_mode, enum reg_class)); @@ -1153,7 +1153,8 @@ reload (first, global, dumpfile) if (other_mode != VOIDmode && other_mode != allocate_mode && ! modes_equiv_for_class_p (allocate_mode, other_mode, class)) - abort (); + fatal_insn ("Two dissimilar machine modes both need groups of consecutive regs of the same class", + insn); } else if (size == 1) { @@ -1349,19 +1350,14 @@ reload (first, global, dumpfile) } /* Now count extra regs if there might be a conflict with - the return value register. + the return value register. */ - ??? This is not quite correct because we don't properly - handle the case of groups, but if we end up doing - something wrong, it either will end up not mattering or - we will abort elsewhere. */ - for (r = regno; r < regno + nregs; r++) if (spill_reg_order[r] >= 0) for (i = 0; i < N_REG_CLASSES; i++) if (TEST_HARD_REG_BIT (reg_class_contents[i], r)) { - if (basic_needs[i] > 0 || basic_groups[i] > 0) + if (basic_needs[i] > 0) { enum reg_class *p; @@ -1370,6 +1366,15 @@ reload (first, global, dumpfile) while (*p != LIM_REG_CLASSES) insn_needs.other.regs[0][(int) *p++]++; } + if (basic_groups[i] > 0) + { + enum reg_class *p; + + insn_needs.other.groups[i]++; + p = reg_class_superclasses[i]; + while (*p != LIM_REG_CLASSES) + insn_needs.other.groups[(int) *p++]++; + } } } #endif /* SMALL_REGISTER_CLASSES */ @@ -1603,7 +1608,8 @@ reload (first, global, dumpfile) /* If any single spilled regs happen to form groups, count them now. Maybe we don't really need to spill another group. */ - count_possible_groups (group_size, group_mode, max_groups); + count_possible_groups (group_size, group_mode, max_groups, + class); if (max_groups[class] <= 0) break; @@ -2063,68 +2069,65 @@ possible_group_p (regno, max_groups) return 0; } -/* Count any groups that can be formed from the registers recently spilled. - This is done class by class, in order of ascending class number. */ +/* Count any groups of CLASS that can be formed from the registers recently + spilled. */ static void -count_possible_groups (group_size, group_mode, max_groups) +count_possible_groups (group_size, group_mode, max_groups, class) int *group_size; enum machine_mode *group_mode; int *max_groups; + int class; { - int i; + HARD_REG_SET new; + int i, j; + /* Now find all consecutive groups of spilled registers and mark each group off against the need for such groups. But don't count them against ordinary need, yet. */ - for (i = 0; i < N_REG_CLASSES; i++) - if (group_size[i] > 1) + if (group_size[class] == 0) + return; + + CLEAR_HARD_REG_SET (new); + + /* Make a mask of all the regs that are spill regs in class I. */ + for (i = 0; i < n_spills; i++) + if (TEST_HARD_REG_BIT (reg_class_contents[class], spill_regs[i]) + && ! TEST_HARD_REG_BIT (counted_for_groups, spill_regs[i]) + && ! TEST_HARD_REG_BIT (counted_for_nongroups, spill_regs[i])) + SET_HARD_REG_BIT (new, spill_regs[i]); + + /* Find each consecutive group of them. */ + for (i = 0; i < FIRST_PSEUDO_REGISTER && max_groups[class] > 0; i++) + if (TEST_HARD_REG_BIT (new, i) + && i + group_size[class] <= FIRST_PSEUDO_REGISTER + && HARD_REGNO_MODE_OK (i, group_mode[class])) { - HARD_REG_SET new; - int j; - - CLEAR_HARD_REG_SET (new); - - /* Make a mask of all the regs that are spill regs in class I. */ - for (j = 0; j < n_spills; j++) - if (TEST_HARD_REG_BIT (reg_class_contents[i], spill_regs[j]) - && ! TEST_HARD_REG_BIT (counted_for_groups, spill_regs[j]) - && ! TEST_HARD_REG_BIT (counted_for_nongroups, - spill_regs[j])) - SET_HARD_REG_BIT (new, spill_regs[j]); - - /* Find each consecutive group of them. */ - for (j = 0; j < FIRST_PSEUDO_REGISTER && max_groups[i] > 0; j++) - if (TEST_HARD_REG_BIT (new, j) - && j + group_size[i] <= FIRST_PSEUDO_REGISTER - /* Next line in case group-mode for this class - demands an even-odd pair. */ - && HARD_REGNO_MODE_OK (j, group_mode[i])) - { - int k; - for (k = 1; k < group_size[i]; k++) - if (! TEST_HARD_REG_BIT (new, j + k)) - break; - if (k == group_size[i]) - { - /* We found a group. Mark it off against this class's - need for groups, and against each superclass too. */ - register enum reg_class *p; - max_groups[i]--; - p = reg_class_superclasses[i]; - while (*p != LIM_REG_CLASSES) - max_groups[(int) *p++]--; - /* Don't count these registers again. */ - for (k = 0; k < group_size[i]; k++) - SET_HARD_REG_BIT (counted_for_groups, j + k); - } - /* Skip to the last reg in this group. When j is incremented - above, it will then point to the first reg of the next - possible group. */ - j += k - 1; - } - } + for (j = 1; j < group_size[class]; j++) + if (! TEST_HARD_REG_BIT (new, i + j)) + break; + + if (j == group_size[class]) + { + /* We found a group. Mark it off against this class's need for + groups, and against each superclass too. */ + register enum reg_class *p; + + max_groups[class]--; + p = reg_class_superclasses[class]; + while (*p != LIM_REG_CLASSES) + max_groups[(int) *p++]--; + + /* Don't count these registers again. */ + for (j = 0; j < group_size[class]; j++) + SET_HARD_REG_BIT (counted_for_groups, i + j); + } + /* Skip to the last reg in this group. When i is incremented above, + it will then point to the first reg of the next possible group. */ + i += j - 1; + } } /* ALLOCATE_MODE is a register mode that needs to be reloaded. OTHER_MODE is @@ -2165,7 +2168,7 @@ spill_failure (insn) if (asm_noperands (PATTERN (insn)) >= 0) error_for_asm (insn, "`asm' needs too many reloads"); else - abort (); + fatal_insn ("Unable to find a register to spill.", insn); } /* Add a new register to the tables of available spill-registers @@ -2886,11 +2889,20 @@ eliminate_regs (x, mem_mode, insn) /* If we didn't change anything, we must retain the pseudo. */ if (new == reg_equiv_memory_loc[REGNO (SUBREG_REG (x))]) - new = XEXP (x, 0); + new = SUBREG_REG (x); else - /* Otherwise, ensure NEW isn't shared in case we have to reload - it. */ - new = copy_rtx (new); + { + /* Otherwise, ensure NEW isn't shared in case we have to reload + it. */ + new = copy_rtx (new); + + /* In this case, we must show that the pseudo is used in this + insn so that delete_output_reload will do the right thing. */ + if (insn != 0 && GET_CODE (insn) != EXPR_LIST + && GET_CODE (insn) != INSN_LIST) + emit_insn_before (gen_rtx (USE, VOIDmode, SUBREG_REG (x)), + insn); + } } else new = eliminate_regs (SUBREG_REG (x), mem_mode, insn); @@ -2907,7 +2919,11 @@ eliminate_regs (x, mem_mode, insn) smaller. So leave the SUBREG then. */ && ! (GET_CODE (SUBREG_REG (x)) == REG && GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD - && GET_MODE_SIZE (GET_MODE (new)) <= UNITS_PER_WORD) + && GET_MODE_SIZE (GET_MODE (new)) <= UNITS_PER_WORD + && (GET_MODE_SIZE (GET_MODE (x)) + > GET_MODE_SIZE (GET_MODE (new))) + && INTEGRAL_MODE_P (GET_MODE (new)) + && LOAD_EXTEND_OP (GET_MODE (new)) != NIL) #endif ) { @@ -3668,11 +3684,12 @@ order_regs_for_reload () } /* Used in reload_as_needed to sort the spilled regs. */ + static int compare_spill_regs (r1, r2) short *r1, *r2; { - return *r1 < *r2 ? -1: 1; + return *r1 - *r2; } /* Reload pseudo-registers into hard regs around each insn as needed. @@ -3840,7 +3857,7 @@ reload_as_needed (first, live_known) && ! reload_optional[i] && (reload_in[i] != 0 || reload_out[i] != 0 || reload_secondary_p[i] != 0)) - abort (); + fatal_insn ("Non-optional registers need a spill register", insn); /* Now compute which reload regs to reload them into. Perhaps reusing reload regs from previous insns, or else output @@ -4836,7 +4853,7 @@ allocate_reload_reg (r, insn, last_reload, noerror) failure: if (asm_noperands (PATTERN (insn)) < 0) /* It's the compiler's fault. */ - abort (); + fatal_insn ("Could not find a spill register", insn); /* It's the user's fault; the operand's mode and constraint don't match. Disable this reload so we don't crash in final. */ @@ -5628,7 +5645,9 @@ emit_reload_insns (insn) { register rtx old; rtx oldequiv_reg = 0; - rtx store_insn = 0; + + if (reload_spill_index[j] >= 0) + new_spill_reg_store[reload_spill_index[j]] = 0; old = reload_in[j]; if (old != 0 && ! reload_inherited[j] @@ -6010,9 +6029,9 @@ emit_reload_insns (insn) third_reload_reg))); } else - gen_input_reload (second_reload_reg, oldequiv, - reload_opnum[j], - reload_when_needed[j]); + gen_reload (second_reload_reg, oldequiv, + reload_opnum[j], + reload_when_needed[j]); oldequiv = second_reload_reg; } @@ -6021,8 +6040,8 @@ emit_reload_insns (insn) #endif if (! special && ! rtx_equal_p (reloadreg, oldequiv)) - gen_input_reload (reloadreg, oldequiv, reload_opnum[j], - reload_when_needed[j]); + gen_reload (reloadreg, oldequiv, reload_opnum[j], + reload_when_needed[j]); #if defined(SECONDARY_INPUT_RELOAD_CLASS) && defined(PRESERVE_DEATH_INFO_REGNO_P) /* We may have to make a REG_DEAD note for the secondary reload @@ -6246,7 +6265,7 @@ emit_reload_insns (insn) /* VOIDmode should never happen for an output. */ if (asm_noperands (PATTERN (insn)) < 0) /* It's the compiler's fault. */ - abort (); + fatal_insn ("VOIDmode on an output", insn); error_for_asm (insn, "output operand is constant in `asm'"); /* Prevent crash--use something we know is valid. */ mode = word_mode; @@ -6259,7 +6278,7 @@ emit_reload_insns (insn) #ifdef SECONDARY_OUTPUT_RELOAD_CLASS /* If we need two reload regs, set RELOADREG to the intermediate - one, since it will be stored into OUT. We might need a secondary + one, since it will be stored into OLD. We might need a secondary register only for an input reload, so check again here. */ if (reload_secondary_out_reload[j] >= 0) @@ -6289,10 +6308,10 @@ emit_reload_insns (insn) { /* See if we need both a scratch and intermediate reload register. */ + int secondary_reload = reload_secondary_out_reload[j]; enum insn_code tertiary_icode = reload_secondary_out_icode[secondary_reload]; - rtx pat; if (GET_MODE (reloadreg) != mode) reloadreg = gen_rtx (REG, mode, REGNO (reloadreg)); @@ -6301,44 +6320,24 @@ emit_reload_insns (insn) { rtx third_reloadreg = reload_reg_rtx[reload_secondary_out_reload[secondary_reload]]; - pat = (GEN_FCN (tertiary_icode) - (reloadreg, second_reloadreg, third_reloadreg)); - } -#ifdef SECONDARY_MEMORY_NEEDED - /* If we need a memory location to do the move, do it that way. */ - else if (GET_CODE (reloadreg) == REG - && REGNO (reloadreg) < FIRST_PSEUDO_REGISTER - && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (reloadreg)), - REGNO_REG_CLASS (REGNO (second_reloadreg)), - GET_MODE (second_reloadreg))) - { - /* Get the memory to use and rewrite both registers - to its mode. */ - rtx loc - = get_secondary_mem (reloadreg, - GET_MODE (second_reloadreg), - reload_opnum[j], - reload_when_needed[j]); - rtx tmp_reloadreg; - - if (GET_MODE (loc) != GET_MODE (second_reloadreg)) - second_reloadreg = gen_rtx (REG, GET_MODE (loc), - REGNO (second_reloadreg)); - - if (GET_MODE (loc) != GET_MODE (reloadreg)) - tmp_reloadreg = gen_rtx (REG, GET_MODE (loc), - REGNO (reloadreg)); - else - tmp_reloadreg = reloadreg; - - emit_move_insn (loc, second_reloadreg); - pat = gen_move_insn (tmp_reloadreg, loc); + + /* Copy primary reload reg to secondary reload reg. + (Note that these have been swapped above, then + secondary reload reg to OLD using our insn. */ + + gen_reload (reloadreg, second_reloadreg, + reload_opnum[j], reload_when_needed[j]); + emit_insn ((GEN_FCN (tertiary_icode) + (real_old, reloadreg, third_reloadreg))); + special = 1; } -#endif + else - pat = gen_move_insn (reloadreg, second_reloadreg); + /* Copy between the reload regs here and then to + OUT later. */ - emit_insn (pat); + gen_reload (reloadreg, second_reloadreg, + reload_opnum[j], reload_when_needed[j]); } } } @@ -6346,34 +6345,8 @@ emit_reload_insns (insn) /* Output the last reload insn. */ if (! special) - { -#ifdef SECONDARY_MEMORY_NEEDED - /* If we need a memory location to do the move, do it that way. */ - if (GET_CODE (old) == REG && REGNO (old) < FIRST_PSEUDO_REGISTER - && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (old)), - REGNO_REG_CLASS (REGNO (reloadreg)), - GET_MODE (reloadreg))) - { - /* Get the memory to use and rewrite both registers to - its mode. */ - rtx loc = get_secondary_mem (old, GET_MODE (reloadreg), - reload_opnum[j], - reload_when_needed[j]); - - if (GET_MODE (loc) != GET_MODE (reloadreg)) - reloadreg = gen_rtx (REG, GET_MODE (loc), - REGNO (reloadreg)); - - if (GET_MODE (loc) != GET_MODE (old)) - old = gen_rtx (REG, GET_MODE (loc), REGNO (old)); - - emit_insn (gen_move_insn (loc, reloadreg)); - emit_insn (gen_move_insn (old, loc)); - } - else -#endif - emit_insn (gen_move_insn (old, reloadreg)); - } + gen_reload (old, reloadreg, reload_opnum[j], + reload_when_needed[j]); #ifdef PRESERVE_DEATH_INFO_REGNO_P /* If final will look at death notes for this reg, @@ -6408,17 +6381,14 @@ emit_reload_insns (insn) reg_has_output_reload will make this do nothing. */ note_stores (PATTERN (p), forget_old_reloads_1); - if (reg_mentioned_p (reload_reg_rtx[j], PATTERN (p))) - store_insn = p; + if (reg_mentioned_p (reload_reg_rtx[j], PATTERN (p)) + && reload_spill_index[j] >= 0) + new_spill_reg_store[reload_spill_index[j]] = p; } output_reload_insns[reload_opnum[j]] = get_insns (); end_sequence (); - } - - if (reload_spill_index[j] >= 0) - new_spill_reg_store[reload_spill_index[j]] = store_insn; } /* Now write all the insns we made for reloads in the order expected by @@ -6640,14 +6610,15 @@ emit_reload_insns (insn) } } -/* Emit code to perform an input reload of IN to RELOADREG. IN is from - operand OPNUM with reload type TYPE. +/* Emit code to perform a reload from IN (which may be a reload register) to + OUT (which may also be a reload register). IN or OUT is from operand + OPNUM with reload type TYPE. Returns first insn emitted. */ rtx -gen_input_reload (reloadreg, in, opnum, type) - rtx reloadreg; +gen_reload (out, in, opnum, type) + rtx out; rtx in; int opnum; enum reload_type type; @@ -6714,13 +6685,13 @@ gen_input_reload (reloadreg, in, opnum, type) it will be A = A + B as constrain_operands expects. */ if (GET_CODE (XEXP (in, 1)) == REG - && REGNO (reloadreg) == REGNO (XEXP (in, 1))) + && REGNO (out) == REGNO (XEXP (in, 1))) tem = op0, op0 = op1, op1 = tem; if (op0 != XEXP (in, 0) || op1 != XEXP (in, 1)) in = gen_rtx (PLUS, GET_MODE (in), op0, op1); - insn = emit_insn (gen_rtx (SET, VOIDmode, reloadreg, in)); + insn = emit_insn (gen_rtx (SET, VOIDmode, out, in)); code = recog_memoized (insn); if (code >= 0) @@ -6749,16 +6720,16 @@ gen_input_reload (reloadreg, in, opnum, type) && REGNO (op1) >= FIRST_PSEUDO_REGISTER)) tem = op0, op0 = op1, op1 = tem; - emit_insn (gen_move_insn (reloadreg, op0)); + emit_insn (gen_move_insn (out, op0)); - /* If OP0 and OP1 are the same, we can use RELOADREG for OP1. + /* If OP0 and OP1 are the same, we can use OUT for OP1. This fixes a problem on the 32K where the stack pointer cannot be used as an operand of an add insn. */ if (rtx_equal_p (op0, op1)) - op1 = reloadreg; + op1 = out; - insn = emit_insn (gen_add2_insn (reloadreg, op1)); + insn = emit_insn (gen_add2_insn (out, op1)); /* If that failed, copy the address register to the reload register. Then add the constant to the reload register. */ @@ -6777,43 +6748,44 @@ gen_input_reload (reloadreg, in, opnum, type) delete_insns_since (last); - emit_insn (gen_move_insn (reloadreg, op1)); - emit_insn (gen_add2_insn (reloadreg, op0)); + emit_insn (gen_move_insn (out, op1)); + emit_insn (gen_add2_insn (out, op0)); } #ifdef SECONDARY_MEMORY_NEEDED /* If we need a memory location to do the move, do it that way. */ else if (GET_CODE (in) == REG && REGNO (in) < FIRST_PSEUDO_REGISTER + && GET_CODE (out) == REG && REGNO (out) < FIRST_PSEUDO_REGISTER && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (in)), - REGNO_REG_CLASS (REGNO (reloadreg)), - GET_MODE (reloadreg))) + REGNO_REG_CLASS (REGNO (out)), + GET_MODE (out))) { /* Get the memory to use and rewrite both registers to its mode. */ - rtx loc = get_secondary_mem (in, GET_MODE (reloadreg), opnum, type); + rtx loc = get_secondary_mem (in, GET_MODE (out), opnum, type); - if (GET_MODE (loc) != GET_MODE (reloadreg)) - reloadreg = gen_rtx (REG, GET_MODE (loc), REGNO (reloadreg)); + if (GET_MODE (loc) != GET_MODE (out)) + out = gen_rtx (REG, GET_MODE (loc), REGNO (out)); if (GET_MODE (loc) != GET_MODE (in)) in = gen_rtx (REG, GET_MODE (loc), REGNO (in)); emit_insn (gen_move_insn (loc, in)); - emit_insn (gen_move_insn (reloadreg, loc)); + emit_insn (gen_move_insn (out, loc)); } #endif /* If IN is a simple operand, use gen_move_insn. */ else if (GET_RTX_CLASS (GET_CODE (in)) == 'o' || GET_CODE (in) == SUBREG) - emit_insn (gen_move_insn (reloadreg, in)); + emit_insn (gen_move_insn (out, in)); #ifdef HAVE_reload_load_address else if (HAVE_reload_load_address) - emit_insn (gen_reload_load_address (reloadreg, in)); + emit_insn (gen_reload_load_address (out, in)); #endif - /* Otherwise, just write (set REGLOADREG IN) and hope for the best. */ + /* Otherwise, just write (set OUT IN) and hope for the best. */ else - emit_insn (gen_rtx (SET, VOIDmode, reloadreg, in)); + emit_insn (gen_rtx (SET, VOIDmode, out, in)); /* Return the first insn emitted. We can not just return get_last_insn, because there may have @@ -6960,7 +6932,7 @@ inc_for_reload (reloadreg, value, inc_amount) emit_insn (gen_move_insn (reloadreg, incloc)); /* See if we can directly increment INCLOC. Use a method similar to that - in gen_input_reload. */ + in gen_reload. */ last = get_last_insn (); add_insn = emit_insn (gen_rtx (SET, VOIDmode, incloc, |