diff options
author | law <law@138bc75d-0d04-0410-961f-82ee72b054a4> | 1998-10-22 23:08:26 +0000 |
---|---|---|
committer | law <law@138bc75d-0d04-0410-961f-82ee72b054a4> | 1998-10-22 23:08:26 +0000 |
commit | c426f6be7acdf5ed85372c7e50edf68bc3312bbd (patch) | |
tree | f33d6ad0bb1c8108c5fa289f5f24460c5ec2ec3e /gcc | |
parent | c13446dbca45deeeb4891a157e74a53521246bda (diff) | |
download | gcc-c426f6be7acdf5ed85372c7e50edf68bc3312bbd.tar.gz |
* regclass.c (regclass): Break out some code into new function
scan_one_insn, and into regclass_init.
(init_cost): New static variable, moved out of regclass.
(regclass_init): Initialize it here, not in .
(scan_one_insn): New static function, broken out of regclass.
* recog.c (apply_change_group): Break out some code into new
function insn_invalid_p.
(insn_invalid_p): New static fn, broken out of apply_change_group.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@23236 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 11 | ||||
-rw-r--r-- | gcc/recog.c | 50 | ||||
-rw-r--r-- | gcc/regclass.c | 433 |
3 files changed, 283 insertions, 211 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 22c2bd042ef..3c5452f519b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +Fri Oct 23 00:07:01 1998 Bernd Schmidt <crux@pool.informatik.rwth-aachen.de> + + * regclass.c (regclass): Break out some code into new function + scan_one_insn, and into regclass_init. + (init_cost): New static variable, moved out of regclass. + (regclass_init): Initialize it here, not in . + (scan_one_insn): New static function, broken out of regclass. + * recog.c (apply_change_group): Break out some code into new + function insn_invalid_p. + (insn_invalid_p): New static fn, broken out of apply_change_group. + Thu Oct 22 22:34:42 1998 Jim Wilson <wilson@cygnus.com> * reload1.c (reload_as_needed): When rewrite POST_INC, verify diff --git a/gcc/recog.c b/gcc/recog.c index 261bb4d1646..d525d47a051 100644 --- a/gcc/recog.c +++ b/gcc/recog.c @@ -40,9 +40,10 @@ Boston, MA 02111-1307, USA. */ #endif #endif -static void validate_replace_rtx_1 PROTO((rtx *, rtx, rtx, rtx)); -static rtx *find_single_use_1 PROTO((rtx, rtx *)); -static rtx *find_constant_term_loc PROTO((rtx *)); +static void validate_replace_rtx_1 PROTO((rtx *, rtx, rtx, rtx)); +static rtx *find_single_use_1 PROTO((rtx, rtx *)); +static rtx *find_constant_term_loc PROTO((rtx *)); +static int insn_invalid_p PROTO((rtx)); /* Nonzero means allow operands to be volatile. This should be 0 if you are generating rtl, such as if you are calling @@ -252,6 +253,41 @@ validate_change (object, loc, new, in_group) return apply_change_group (); } +/* This subroutine of apply_change_group verifies whether the changes to INSN + were valid; i.e. whether INSN can still be recognized. */ + +static int +insn_invalid_p (insn) + rtx insn; +{ + int icode = recog_memoized (insn); + int is_asm = icode < 0 && asm_noperands (PATTERN (insn)) >= 0; + + if (is_asm) + { + if (! check_asm_operands (PATTERN (insn))) + return 1; + + /* Disallow modification of ASM_OPERANDS after reload; verifying the + constraints is too difficult. */ + if (reload_completed) + return 1; + } + else if (icode < 0) + return 1; + + /* After reload, verify that all constraints are satisfied. */ + if (reload_completed) + { + insn_extract (insn); + + if (! constrain_operands (INSN_CODE (insn), 1)) + return 1; + } + + return 0; +} + /* Apply a group of changes previously issued with `validate_change'. Return 1 if all changes are valid, zero otherwise. */ @@ -282,13 +318,7 @@ apply_change_group () if (! memory_address_p (GET_MODE (object), XEXP (object, 0))) break; } - else if ((recog_memoized (object) < 0 - && (asm_noperands (PATTERN (object)) < 0 - || ! check_asm_operands (PATTERN (object)) - || reload_completed)) - || (reload_completed - && (insn_extract (object), - ! constrain_operands (INSN_CODE (object), 1)))) + else if (insn_invalid_p (object)) { rtx pat = PATTERN (object); diff --git a/gcc/regclass.c b/gcc/regclass.c index 73960c80a99..75d73024885 100644 --- a/gcc/regclass.c +++ b/gcc/regclass.c @@ -648,6 +648,10 @@ struct costs static struct costs *costs; +/* Initialized once, and used to initialize cost values for each insn. */ + +static struct costs init_cost; + /* Record the same data by operand number, accumulated for each alternative in an insn. The contribution to a pseudo is that of the minimum-cost alternative. */ @@ -685,6 +689,7 @@ static int loop_depth; static int loop_cost; static int n_occurrences PROTO((int, char *)); +static rtx scan_one_insn PROTO((rtx, int)); static void record_reg_classes PROTO((int, int, rtx *, enum machine_mode *, char **, rtx)); static int copy_cost PROTO((rtx, enum machine_mode, @@ -718,12 +723,19 @@ reg_alternate_class (regno) return (enum reg_class) altclass[regno]; } -/* This prevents dump_flow_info from losing if called - before regclass is run. */ +/* Initialize some global data for this pass. */ void regclass_init () { + int i; + + init_cost.mem_cost = 10000; + for (i = 0; i < N_REG_CLASSES; i++) + init_cost.cost[i] = 10000; + + /* This prevents dump_flow_info from losing if called + before regclass is run. */ prefclass = 0; } @@ -739,6 +751,221 @@ n_occurrences (c, s) return n; } +/* Subroutine of regclass, processes one insn INSN. Scan it and record each + time it would save code to put a certain register in a certain class. + PASS, when nonzero, inhibits some optimizations which need only be done + once. + Return the last insn processed, so that the scan can be continued from + there. */ + +static rtx +scan_one_insn (insn, pass) + rtx insn; + int pass; +{ + enum rtx_code code = GET_CODE (insn); + enum rtx_code pat_code; + + char *constraints[MAX_RECOG_OPERANDS]; + enum machine_mode modes[MAX_RECOG_OPERANDS]; + int nalternatives; + int noperands; + rtx set; + int i, j; + + /* Show that an insn inside a loop is likely to be executed three + times more than insns outside a loop. This is much more aggressive + than the assumptions made elsewhere and is being tried as an + experiment. */ + + if (code == NOTE) + { + if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG) + loop_depth++, loop_cost = 1 << (2 * MIN (loop_depth, 5)); + else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END) + loop_depth--, loop_cost = 1 << (2 * MIN (loop_depth, 5)); + + return insn; + } + + if (GET_RTX_CLASS (code) != 'i') + return insn; + + pat_code = GET_CODE (PATTERN (insn)); + if (pat_code == USE + || pat_code == CLOBBER + || pat_code == ASM_INPUT + || pat_code == ADDR_VEC + || pat_code == ADDR_DIFF_VEC) + return insn; + + if (code == INSN + && (noperands = asm_noperands (PATTERN (insn))) >= 0) + { + decode_asm_operands (PATTERN (insn), recog_operand, NULL_PTR, + constraints, modes); + nalternatives = (noperands == 0 ? 0 + : n_occurrences (',', constraints[0]) + 1); + } + else + { + int insn_code_number = recog_memoized (insn); + rtx note; + + set = single_set (insn); + insn_extract (insn); + + nalternatives = insn_n_alternatives[insn_code_number]; + noperands = insn_n_operands[insn_code_number]; + + /* If this insn loads a parameter from its stack slot, then + it represents a savings, rather than a cost, if the + parameter is stored in memory. Record this fact. */ + + if (set != 0 && GET_CODE (SET_DEST (set)) == REG + && GET_CODE (SET_SRC (set)) == MEM + && (note = find_reg_note (insn, REG_EQUIV, + NULL_RTX)) != 0 + && GET_CODE (XEXP (note, 0)) == MEM) + { + costs[REGNO (SET_DEST (set))].mem_cost + -= (MEMORY_MOVE_COST (GET_MODE (SET_DEST (set)), + GENERAL_REGS, 1) + * loop_cost); + record_address_regs (XEXP (SET_SRC (set), 0), + BASE_REG_CLASS, loop_cost * 2); + return insn; + } + + /* Improve handling of two-address insns such as + (set X (ashift CONST Y)) where CONST must be made to + match X. Change it into two insns: (set X CONST) + (set X (ashift X Y)). If we left this for reloading, it + would probably get three insns because X and Y might go + in the same place. This prevents X and Y from receiving + the same hard reg. + + We can only do this if the modes of operands 0 and 1 + (which might not be the same) are tieable and we only need + do this during our first pass. */ + + if (pass == 0 && optimize + && noperands >= 3 + && insn_operand_constraint[insn_code_number][1][0] == '0' + && insn_operand_constraint[insn_code_number][1][1] == 0 + && CONSTANT_P (recog_operand[1]) + && ! rtx_equal_p (recog_operand[0], recog_operand[1]) + && ! rtx_equal_p (recog_operand[0], recog_operand[2]) + && GET_CODE (recog_operand[0]) == REG + && MODES_TIEABLE_P (GET_MODE (recog_operand[0]), + insn_operand_mode[insn_code_number][1])) + { + rtx previnsn = prev_real_insn (insn); + rtx dest + = gen_lowpart (insn_operand_mode[insn_code_number][1], + recog_operand[0]); + rtx newinsn + = emit_insn_before (gen_move_insn (dest, + recog_operand[1]), + insn); + + /* If this insn was the start of a basic block, + include the new insn in that block. + We need not check for code_label here; + while a basic block can start with a code_label, + INSN could not be at the beginning of that block. */ + if (previnsn == 0 || GET_CODE (previnsn) == JUMP_INSN) + { + int b; + for (b = 0; b < n_basic_blocks; b++) + if (insn == basic_block_head[b]) + basic_block_head[b] = newinsn; + } + + /* This makes one more setting of new insns's dest. */ + REG_N_SETS (REGNO (recog_operand[0]))++; + + *recog_operand_loc[1] = recog_operand[0]; + for (i = insn_n_dups[insn_code_number] - 1; i >= 0; i--) + if (recog_dup_num[i] == 1) + *recog_dup_loc[i] = recog_operand[0]; + + return PREV_INSN (newinsn); + } + + for (i = 0; i < noperands; i++) + { + constraints[i] + = insn_operand_constraint[insn_code_number][i]; + modes[i] = insn_operand_mode[insn_code_number][i]; + } + } + + /* If we get here, we are set up to record the costs of all the + operands for this insn. Start by initializing the costs. + Then handle any address registers. Finally record the desired + classes for any pseudos, doing it twice if some pair of + operands are commutative. */ + + for (i = 0; i < noperands; i++) + { + op_costs[i] = init_cost; + + if (GET_CODE (recog_operand[i]) == SUBREG) + recog_operand[i] = SUBREG_REG (recog_operand[i]); + + if (GET_CODE (recog_operand[i]) == MEM) + record_address_regs (XEXP (recog_operand[i], 0), + BASE_REG_CLASS, loop_cost * 2); + else if (constraints[i][0] == 'p') + record_address_regs (recog_operand[i], + BASE_REG_CLASS, loop_cost * 2); + } + + /* Check for commutative in a separate loop so everything will + have been initialized. We must do this even if one operand + is a constant--see addsi3 in m68k.md. */ + + for (i = 0; i < noperands - 1; i++) + if (constraints[i][0] == '%') + { + char *xconstraints[MAX_RECOG_OPERANDS]; + int j; + + /* Handle commutative operands by swapping the constraints. + We assume the modes are the same. */ + + for (j = 0; j < noperands; j++) + xconstraints[j] = constraints[j]; + + xconstraints[i] = constraints[i+1]; + xconstraints[i+1] = constraints[i]; + record_reg_classes (nalternatives, noperands, + recog_operand, modes, xconstraints, + insn); + } + + record_reg_classes (nalternatives, noperands, recog_operand, + modes, constraints, insn); + + /* Now add the cost for each operand to the total costs for + its register. */ + + for (i = 0; i < noperands; i++) + if (GET_CODE (recog_operand[i]) == REG + && REGNO (recog_operand[i]) >= FIRST_PSEUDO_REGISTER) + { + int regno = REGNO (recog_operand[i]); + struct costs *p = &costs[regno], *q = &op_costs[i]; + + p->mem_cost += q->mem_cost * loop_cost; + for (j = 0; j < N_REG_CLASSES; j++) + p->cost[j] += q->cost[j] * loop_cost; + } + + return insn; +} + /* This is a pass of the compiler that scans all instructions and calculates the preferred class for each pseudo-register. This information can be accessed later by calling `reg_preferred_class'. @@ -751,9 +978,7 @@ regclass (f, nregs) { #ifdef REGISTER_CONSTRAINTS register rtx insn; - register int i, j; - struct costs init_cost; - rtx set; + register int i; int pass; init_recog (); @@ -812,10 +1037,6 @@ regclass (f, nregs) } #endif /* FORBIDDEN_INC_DEC_CLASSES */ - init_cost.mem_cost = 10000; - for (i = 0; i < N_REG_CLASSES; i++) - init_cost.cost[i] = 10000; - /* Normally we scan the insns once and determine the best class to use for each register. However, if -fexpensive_optimizations are on, we do so twice, the second time using the tentative best classes to guide the @@ -838,199 +1059,9 @@ regclass (f, nregs) for (insn = f; insn; insn = NEXT_INSN (insn)) { - char *constraints[MAX_RECOG_OPERANDS]; - enum machine_mode modes[MAX_RECOG_OPERANDS]; - int nalternatives; - int noperands; - - /* Show that an insn inside a loop is likely to be executed three - times more than insns outside a loop. This is much more aggressive - than the assumptions made elsewhere and is being tried as an - experiment. */ - - if (GET_CODE (insn) == NOTE - && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG) - loop_depth++, loop_cost = 1 << (2 * MIN (loop_depth, 5)); - else if (GET_CODE (insn) == NOTE - && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END) - loop_depth--, loop_cost = 1 << (2 * MIN (loop_depth, 5)); - - else if ((GET_CODE (insn) == INSN - && GET_CODE (PATTERN (insn)) != USE - && GET_CODE (PATTERN (insn)) != CLOBBER - && GET_CODE (PATTERN (insn)) != ASM_INPUT) - || (GET_CODE (insn) == JUMP_INSN - && GET_CODE (PATTERN (insn)) != ADDR_VEC - && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC) - || GET_CODE (insn) == CALL_INSN) - { - if (GET_CODE (insn) == INSN - && (noperands = asm_noperands (PATTERN (insn))) >= 0) - { - decode_asm_operands (PATTERN (insn), recog_operand, NULL_PTR, - constraints, modes); - nalternatives = (noperands == 0 ? 0 - : n_occurrences (',', constraints[0]) + 1); - } - else - { - int insn_code_number = recog_memoized (insn); - rtx note; - - set = single_set (insn); - insn_extract (insn); - - nalternatives = insn_n_alternatives[insn_code_number]; - noperands = insn_n_operands[insn_code_number]; - - /* If this insn loads a parameter from its stack slot, then - it represents a savings, rather than a cost, if the - parameter is stored in memory. Record this fact. */ - - if (set != 0 && GET_CODE (SET_DEST (set)) == REG - && GET_CODE (SET_SRC (set)) == MEM - && (note = find_reg_note (insn, REG_EQUIV, - NULL_RTX)) != 0 - && GET_CODE (XEXP (note, 0)) == MEM) - { - costs[REGNO (SET_DEST (set))].mem_cost - -= (MEMORY_MOVE_COST (GET_MODE (SET_DEST (set)), - GENERAL_REGS, 1) - * loop_cost); - record_address_regs (XEXP (SET_SRC (set), 0), - BASE_REG_CLASS, loop_cost * 2); - continue; - } - - /* Improve handling of two-address insns such as - (set X (ashift CONST Y)) where CONST must be made to - match X. Change it into two insns: (set X CONST) - (set X (ashift X Y)). If we left this for reloading, it - would probably get three insns because X and Y might go - in the same place. This prevents X and Y from receiving - the same hard reg. - - We can only do this if the modes of operands 0 and 1 - (which might not be the same) are tieable and we only need - do this during our first pass. */ - - if (pass == 0 && optimize - && noperands >= 3 - && insn_operand_constraint[insn_code_number][1][0] == '0' - && insn_operand_constraint[insn_code_number][1][1] == 0 - && CONSTANT_P (recog_operand[1]) - && ! rtx_equal_p (recog_operand[0], recog_operand[1]) - && ! rtx_equal_p (recog_operand[0], recog_operand[2]) - && GET_CODE (recog_operand[0]) == REG - && MODES_TIEABLE_P (GET_MODE (recog_operand[0]), - insn_operand_mode[insn_code_number][1])) - { - rtx previnsn = prev_real_insn (insn); - rtx dest - = gen_lowpart (insn_operand_mode[insn_code_number][1], - recog_operand[0]); - rtx newinsn - = emit_insn_before (gen_move_insn (dest, - recog_operand[1]), - insn); - - /* If this insn was the start of a basic block, - include the new insn in that block. - We need not check for code_label here; - while a basic block can start with a code_label, - INSN could not be at the beginning of that block. */ - if (previnsn == 0 || GET_CODE (previnsn) == JUMP_INSN) - { - int b; - for (b = 0; b < n_basic_blocks; b++) - if (insn == basic_block_head[b]) - basic_block_head[b] = newinsn; - } - - /* This makes one more setting of new insns's dest. */ - REG_N_SETS (REGNO (recog_operand[0]))++; - - *recog_operand_loc[1] = recog_operand[0]; - for (i = insn_n_dups[insn_code_number] - 1; i >= 0; i--) - if (recog_dup_num[i] == 1) - *recog_dup_loc[i] = recog_operand[0]; - - insn = PREV_INSN (newinsn); - continue; - } - - for (i = 0; i < noperands; i++) - { - constraints[i] - = insn_operand_constraint[insn_code_number][i]; - modes[i] = insn_operand_mode[insn_code_number][i]; - } - } - - /* If we get here, we are set up to record the costs of all the - operands for this insn. Start by initializing the costs. - Then handle any address registers. Finally record the desired - classes for any pseudos, doing it twice if some pair of - operands are commutative. */ - - for (i = 0; i < noperands; i++) - { - op_costs[i] = init_cost; - - if (GET_CODE (recog_operand[i]) == SUBREG) - recog_operand[i] = SUBREG_REG (recog_operand[i]); - - if (GET_CODE (recog_operand[i]) == MEM) - record_address_regs (XEXP (recog_operand[i], 0), - BASE_REG_CLASS, loop_cost * 2); - else if (constraints[i][0] == 'p') - record_address_regs (recog_operand[i], - BASE_REG_CLASS, loop_cost * 2); - } - - /* Check for commutative in a separate loop so everything will - have been initialized. We must do this even if one operand - is a constant--see addsi3 in m68k.md. */ - - for (i = 0; i < noperands - 1; i++) - if (constraints[i][0] == '%') - { - char *xconstraints[MAX_RECOG_OPERANDS]; - int j; - - /* Handle commutative operands by swapping the constraints. - We assume the modes are the same. */ - - for (j = 0; j < noperands; j++) - xconstraints[j] = constraints[j]; - - xconstraints[i] = constraints[i+1]; - xconstraints[i+1] = constraints[i]; - record_reg_classes (nalternatives, noperands, - recog_operand, modes, xconstraints, - insn); - } - - record_reg_classes (nalternatives, noperands, recog_operand, - modes, constraints, insn); - - /* Now add the cost for each operand to the total costs for - its register. */ - - for (i = 0; i < noperands; i++) - if (GET_CODE (recog_operand[i]) == REG - && REGNO (recog_operand[i]) >= FIRST_PSEUDO_REGISTER) - { - int regno = REGNO (recog_operand[i]); - struct costs *p = &costs[regno], *q = &op_costs[i]; - - p->mem_cost += q->mem_cost * loop_cost; - for (j = 0; j < N_REG_CLASSES; j++) - p->cost[j] += q->cost[j] * loop_cost; - } - } + insn = scan_one_insn (insn, pass); } - + /* Now for each register look at how desirable each class is and find which class is preferred. Store that in `prefclass[REGNO]'. Record in `altclass[REGNO]' the largest register |