Mercurial > hg > CbC > CbC_gcc
diff gcc/lra.c @ 131:84e7813d76e9
gcc-8.2
author | mir3636 |
---|---|
date | Thu, 25 Oct 2018 07:37:49 +0900 |
parents | 04ced10e8804 |
children | 1830386684a0 |
line wrap: on
line diff
--- a/gcc/lra.c Fri Oct 27 22:46:09 2017 +0900 +++ b/gcc/lra.c Thu Oct 25 07:37:49 2018 +0900 @@ -1,5 +1,5 @@ /* LRA (local register allocator) driver and LRA utilities. - Copyright (C) 2010-2017 Free Software Foundation, Inc. + Copyright (C) 2010-2018 Free Software Foundation, Inc. Contributed by Vladimir Makarov <vmakarov@redhat.com>. This file is part of GCC. @@ -535,13 +535,14 @@ clobbered in the insn (EARLY_CLOBBER), and reference to the next insn reg info (NEXT). If REGNO can be early clobbered, alternatives in which it can be early clobbered are given by - EARLY_CLOBBER_ALTS. */ + EARLY_CLOBBER_ALTS. CLOBBER_HIGH marks if reference is a clobber + high. */ static struct lra_insn_reg * new_insn_reg (rtx_insn *insn, int regno, enum op_type type, machine_mode mode, bool subreg_p, bool early_clobber, alternative_mask early_clobber_alts, - struct lra_insn_reg *next) + struct lra_insn_reg *next, bool clobber_high) { lra_insn_reg *ir = lra_insn_reg_pool.allocate (); ir->type = type; @@ -552,6 +553,7 @@ ir->subreg_p = subreg_p; ir->early_clobber = early_clobber; ir->early_clobber_alts = early_clobber_alts; + ir->clobber_high = clobber_high; ir->regno = regno; ir->next = next; return ir; @@ -602,9 +604,9 @@ }; /* The following data are used as static insn data for all debug - insns. If structure lra_static_insn_data is changed, the + bind insns. If structure lra_static_insn_data is changed, the initializer should be changed too. */ -static struct lra_static_insn_data debug_insn_static_data = +static struct lra_static_insn_data debug_bind_static_data = { &debug_operand_data, 0, /* Duplication operands #. */ @@ -618,6 +620,22 @@ NULL /* Descriptions of operands in alternatives. */ }; +/* The following data are used as static insn data for all debug + marker insns. If structure lra_static_insn_data is changed, the + initializer should be changed too. */ +static struct lra_static_insn_data debug_marker_static_data = + { + &debug_operand_data, + 0, /* Duplication operands #. */ + -1, /* Commutative operand #. */ + 0, /* Operands #. There isn't any operand. */ + 0, /* Duplications #. */ + 0, /* Alternatives #. We are not interesting in alternatives + because we does not proceed debug_insns for reloads. */ + NULL, /* Hard registers referenced in machine description. */ + NULL /* Descriptions of operands in alternatives. */ + }; + /* Called once per compiler work to initialize some LRA data related to insns. */ static void @@ -805,11 +823,13 @@ not the insn operands, in X with TYPE (in/out/inout) and flag that it is early clobbered in the insn (EARLY_CLOBBER) and add the info to LIST. X is a part of insn given by DATA. Return the result - list. */ + list. CLOBBER_HIGH marks if X is a clobber high. */ static struct lra_insn_reg * -collect_non_operand_hard_regs (rtx *x, lra_insn_recog_data_t data, +collect_non_operand_hard_regs (rtx_insn *insn, rtx *x, + lra_insn_recog_data_t data, struct lra_insn_reg *list, - enum op_type type, bool early_clobber) + enum op_type type, bool early_clobber, + bool clobber_high) { int i, j, regno, last; bool subreg_p; @@ -873,7 +893,8 @@ #endif list = new_insn_reg (data->insn, regno, type, mode, subreg_p, early_clobber, - early_clobber ? ALL_ALTERNATIVES : 0, list); + early_clobber ? ALL_ALTERNATIVES : 0, list, + clobber_high); } } return list; @@ -881,38 +902,45 @@ switch (code) { case SET: - list = collect_non_operand_hard_regs (&SET_DEST (op), data, - list, OP_OUT, false); - list = collect_non_operand_hard_regs (&SET_SRC (op), data, - list, OP_IN, false); + list = collect_non_operand_hard_regs (insn, &SET_DEST (op), data, + list, OP_OUT, false, false); + list = collect_non_operand_hard_regs (insn, &SET_SRC (op), data, + list, OP_IN, false, false); break; case CLOBBER: - /* We treat clobber of non-operand hard registers as early - clobber (the behavior is expected from asm). */ - list = collect_non_operand_hard_regs (&XEXP (op, 0), data, - list, OP_OUT, true); + /* We treat clobber of non-operand hard registers as early clobber. */ + list = collect_non_operand_hard_regs (insn, &XEXP (op, 0), data, + list, OP_OUT, true, false); + break; + case CLOBBER_HIGH: + /* Clobber high should always span exactly one register. */ + gcc_assert (REG_NREGS (XEXP (op, 0)) == 1); + /* We treat clobber of non-operand hard registers as early clobber. */ + list = collect_non_operand_hard_regs (insn, &XEXP (op, 0), data, + list, OP_OUT, true, true); break; case PRE_INC: case PRE_DEC: case POST_INC: case POST_DEC: - list = collect_non_operand_hard_regs (&XEXP (op, 0), data, - list, OP_INOUT, false); + list = collect_non_operand_hard_regs (insn, &XEXP (op, 0), data, + list, OP_INOUT, false, false); break; case PRE_MODIFY: case POST_MODIFY: - list = collect_non_operand_hard_regs (&XEXP (op, 0), data, - list, OP_INOUT, false); - list = collect_non_operand_hard_regs (&XEXP (op, 1), data, - list, OP_IN, false); + list = collect_non_operand_hard_regs (insn, &XEXP (op, 0), data, + list, OP_INOUT, false, false); + list = collect_non_operand_hard_regs (insn, &XEXP (op, 1), data, + list, OP_IN, false, false); break; default: fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') - list = collect_non_operand_hard_regs (&XEXP (op, i), data, - list, OP_IN, false); + list = collect_non_operand_hard_regs (insn, &XEXP (op, i), data, + list, OP_IN, false, false); else if (fmt[i] == 'E') for (j = XVECLEN (op, i) - 1; j >= 0; j--) - list = collect_non_operand_hard_regs (&XVECEXP (op, i, j), data, - list, OP_IN, false); + list = collect_non_operand_hard_regs (insn, &XVECEXP (op, i, j), + data, list, OP_IN, false, + false); } } return list; @@ -942,17 +970,25 @@ data = XNEW (struct lra_insn_recog_data); lra_insn_recog_data[uid] = data; data->insn = insn; - data->used_insn_alternative = -1; + data->used_insn_alternative = LRA_UNKNOWN_ALT; data->icode = icode; data->regs = NULL; if (DEBUG_INSN_P (insn)) { - data->insn_static_data = &debug_insn_static_data; data->dup_loc = NULL; data->arg_hard_regs = NULL; data->preferred_alternatives = ALL_ALTERNATIVES; - data->operand_loc = XNEWVEC (rtx *, 1); - data->operand_loc[0] = &INSN_VAR_LOCATION_LOC (insn); + if (DEBUG_BIND_INSN_P (insn)) + { + data->insn_static_data = &debug_bind_static_data; + data->operand_loc = XNEWVEC (rtx *, 1); + data->operand_loc[0] = &INSN_VAR_LOCATION_LOC (insn); + } + else if (DEBUG_MARKER_INSN_P (insn)) + { + data->insn_static_data = &debug_marker_static_data; + data->operand_loc = NULL; + } return data; } if (icode < 0) @@ -1015,7 +1051,8 @@ { operand_alternative *op_alt = XCNEWVEC (operand_alternative, nalt * nop); - preprocess_constraints (nop, nalt, constraints, op_alt); + preprocess_constraints (nop, nalt, constraints, op_alt, + data->operand_loc); setup_operand_alternative (data, op_alt); } } @@ -1055,8 +1092,8 @@ insn_static_data->hard_regs = NULL; else insn_static_data->hard_regs - = collect_non_operand_hard_regs (&PATTERN (insn), data, - NULL, OP_IN, false); + = collect_non_operand_hard_regs (insn, &PATTERN (insn), data, + NULL, OP_IN, false, false); data->arg_hard_regs = NULL; if (CALL_P (insn)) { @@ -1082,6 +1119,11 @@ arg_hard_regs[n_hard_regs++] = regno + i + (use_p ? 0 : FIRST_PSEUDO_REGISTER); } + else if (GET_CODE (XEXP (link, 0)) == CLOBBER_HIGH) + /* We could support CLOBBER_HIGH and treat it in the same way as + HARD_REGNO_CALL_PART_CLOBBERED, but no port needs that yet. */ + gcc_unreachable (); + if (n_hard_regs != 0) { arg_hard_regs[n_hard_regs++] = -1; @@ -1164,7 +1206,7 @@ int n; unsigned int uid = INSN_UID (insn); struct lra_static_insn_data *insn_static_data; - HOST_WIDE_INT sp_offset = 0; + poly_int64 sp_offset = 0; check_and_expand_insn_recog_data (uid); if ((data = lra_insn_recog_data[uid]) != NULL @@ -1183,7 +1225,7 @@ return data; } insn_static_data = data->insn_static_data; - data->used_insn_alternative = -1; + data->used_insn_alternative = LRA_UNKNOWN_ALT; if (DEBUG_INSN_P (insn)) return data; if (data->icode < 0) @@ -1265,6 +1307,8 @@ /* Common info about each register. */ struct lra_reg *lra_reg_info; +HARD_REG_SET hard_regs_spilled_into; + /* Last register value. */ static int last_reg_value; @@ -1314,6 +1358,7 @@ for (i = 0; i < reg_info_size; i++) initialize_lra_reg_info_element (i); copy_vec.truncate (0); + CLEAR_HARD_REG_SET (hard_regs_spilled_into); } @@ -1402,13 +1447,14 @@ /* This page contains code dealing with info about registers in insns. */ -/* Process X of insn UID recursively and add info (operand type is +/* Process X of INSN recursively and add info (operand type is given by TYPE, flag of that it is early clobber is EARLY_CLOBBER) about registers in X to the insn DATA. If X can be early clobbered, alternatives in which it can be early clobbered are given by EARLY_CLOBBER_ALTS. */ static void -add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x, int uid, +add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x, + rtx_insn *insn, enum op_type type, bool early_clobber, alternative_mask early_clobber_alts) { @@ -1436,11 +1482,11 @@ /* Process all regs even unallocatable ones as we need info about all regs for rematerialization pass. */ expand_reg_info (); - if (bitmap_set_bit (&lra_reg_info[regno].insn_bitmap, uid)) + if (bitmap_set_bit (&lra_reg_info[regno].insn_bitmap, INSN_UID (insn))) { data->regs = new_insn_reg (data->insn, regno, type, mode, subreg_p, early_clobber, early_clobber_alts, - data->regs); + data->regs, false); return; } else @@ -1453,7 +1499,8 @@ structure. */ data->regs = new_insn_reg (data->insn, regno, type, mode, subreg_p, early_clobber, - early_clobber_alts, data->regs); + early_clobber_alts, data->regs, + false); else { if (curr->type != type) @@ -1471,20 +1518,23 @@ switch (code) { case SET: - add_regs_to_insn_regno_info (data, SET_DEST (x), uid, OP_OUT, false, 0); - add_regs_to_insn_regno_info (data, SET_SRC (x), uid, OP_IN, false, 0); + add_regs_to_insn_regno_info (data, SET_DEST (x), insn, OP_OUT, false, 0); + add_regs_to_insn_regno_info (data, SET_SRC (x), insn, OP_IN, false, 0); break; case CLOBBER: /* We treat clobber of non-operand hard registers as early - clobber (the behavior is expected from asm). */ - add_regs_to_insn_regno_info (data, XEXP (x, 0), uid, OP_OUT, true, ALL_ALTERNATIVES); + clobber. */ + add_regs_to_insn_regno_info (data, XEXP (x, 0), insn, OP_OUT, + true, ALL_ALTERNATIVES); break; + case CLOBBER_HIGH: + gcc_unreachable (); case PRE_INC: case PRE_DEC: case POST_INC: case POST_DEC: - add_regs_to_insn_regno_info (data, XEXP (x, 0), uid, OP_INOUT, false, 0); + add_regs_to_insn_regno_info (data, XEXP (x, 0), insn, OP_INOUT, false, 0); break; case PRE_MODIFY: case POST_MODIFY: - add_regs_to_insn_regno_info (data, XEXP (x, 0), uid, OP_INOUT, false, 0); - add_regs_to_insn_regno_info (data, XEXP (x, 1), uid, OP_IN, false, 0); + add_regs_to_insn_regno_info (data, XEXP (x, 0), insn, OP_INOUT, false, 0); + add_regs_to_insn_regno_info (data, XEXP (x, 1), insn, OP_IN, false, 0); break; default: if ((code != PARALLEL && code != EXPR_LIST) || type != OP_OUT) @@ -1505,11 +1555,11 @@ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') - add_regs_to_insn_regno_info (data, XEXP (x, i), uid, type, false, 0); + add_regs_to_insn_regno_info (data, XEXP (x, i), insn, type, false, 0); else if (fmt[i] == 'E') { for (j = XVECLEN (x, i) - 1; j >= 0; j--) - add_regs_to_insn_regno_info (data, XVECEXP (x, i, j), uid, + add_regs_to_insn_regno_info (data, XVECEXP (x, i, j), insn, type, false, 0); } } @@ -1585,7 +1635,7 @@ void lra_update_insn_regno_info (rtx_insn *insn) { - int i, uid, freq; + int i, freq; lra_insn_recog_data_t data; struct lra_static_insn_data *static_data; enum rtx_code code; @@ -1595,16 +1645,15 @@ return; data = lra_get_insn_recog_data (insn); static_data = data->insn_static_data; - freq = get_insn_freq (insn); + freq = NONDEBUG_INSN_P (insn) ? get_insn_freq (insn) : 0; invalidate_insn_data_regno_info (data, insn, freq); - uid = INSN_UID (insn); for (i = static_data->n_operands - 1; i >= 0; i--) - add_regs_to_insn_regno_info (data, *data->operand_loc[i], uid, + add_regs_to_insn_regno_info (data, *data->operand_loc[i], insn, static_data->operand[i].type, static_data->operand[i].early_clobber, static_data->operand[i].early_clobber_alts); if ((code = GET_CODE (PATTERN (insn))) == CLOBBER || code == USE) - add_regs_to_insn_regno_info (data, XEXP (PATTERN (insn), 0), uid, + add_regs_to_insn_regno_info (data, XEXP (PATTERN (insn), 0), insn, code == USE ? OP_IN : OP_OUT, false, 0); if (CALL_P (insn)) /* On some targets call insns can refer to pseudos in memory in @@ -1614,10 +1663,16 @@ for (link = CALL_INSN_FUNCTION_USAGE (insn); link != NULL_RTX; link = XEXP (link, 1)) - if (((code = GET_CODE (XEXP (link, 0))) == USE || code == CLOBBER) - && MEM_P (XEXP (XEXP (link, 0), 0))) - add_regs_to_insn_regno_info (data, XEXP (XEXP (link, 0), 0), uid, - code == USE ? OP_IN : OP_OUT, false, 0); + { + code = GET_CODE (XEXP (link, 0)); + /* We could support CLOBBER_HIGH and treat it in the same way as + HARD_REGNO_CALL_PART_CLOBBERED, but no port needs that yet. */ + gcc_assert (code != CLOBBER_HIGH); + if ((code == USE || code == CLOBBER) + && MEM_P (XEXP (XEXP (link, 0), 0))) + add_regs_to_insn_regno_info (data, XEXP (XEXP (link, 0), 0), insn, + code == USE ? OP_IN : OP_OUT, false, 0); + } if (NONDEBUG_INSN_P (insn)) setup_insn_reg_info (data, freq); } @@ -1805,9 +1860,9 @@ static void setup_sp_offset (rtx_insn *from, rtx_insn *last) { - rtx_insn *before = next_nonnote_insn_bb (last); - HOST_WIDE_INT offset = (before == NULL_RTX || ! INSN_P (before) - ? 0 : lra_get_insn_recog_data (before)->sp_offset); + rtx_insn *before = next_nonnote_nondebug_insn_bb (last); + poly_int64 offset = (before == NULL_RTX || ! INSN_P (before) + ? 0 : lra_get_insn_recog_data (before)->sp_offset); for (rtx_insn *insn = from; insn != NEXT_INSN (last); insn = NEXT_INSN (insn)) lra_get_insn_recog_data (insn)->sp_offset = offset; @@ -1868,9 +1923,11 @@ /* Replace all references to register OLD_REGNO in *LOC with pseudo register NEW_REG. Try to simplify subreg of constant if SUBREG_P. - Return true if any change was made. */ + DEBUG_P is if LOC is within a DEBUG_INSN. Return true if any + change was made. */ bool -lra_substitute_pseudo (rtx *loc, int old_regno, rtx new_reg, bool subreg_p) +lra_substitute_pseudo (rtx *loc, int old_regno, rtx new_reg, bool subreg_p, + bool debug_p) { rtx x = *loc; bool result = false; @@ -1906,11 +1963,14 @@ if (mode != inner_mode && ! (CONST_INT_P (new_reg) && SCALAR_INT_MODE_P (mode))) { - if (!partial_subreg_p (mode, inner_mode) - || ! SCALAR_INT_MODE_P (inner_mode)) - new_reg = gen_rtx_SUBREG (mode, new_reg, 0); + poly_uint64 offset = 0; + if (partial_subreg_p (mode, inner_mode) + && SCALAR_INT_MODE_P (inner_mode)) + offset = subreg_lowpart_offset (mode, inner_mode); + if (debug_p) + new_reg = gen_rtx_raw_SUBREG (mode, new_reg, offset); else - new_reg = gen_lowpart_SUBREG (mode, new_reg); + new_reg = gen_rtx_SUBREG (mode, new_reg, offset); } *loc = new_reg; return true; @@ -1923,14 +1983,14 @@ if (fmt[i] == 'e') { if (lra_substitute_pseudo (&XEXP (x, i), old_regno, - new_reg, subreg_p)) + new_reg, subreg_p, debug_p)) result = true; } else if (fmt[i] == 'E') { for (j = XVECLEN (x, i) - 1; j >= 0; j--) if (lra_substitute_pseudo (&XVECEXP (x, i, j), old_regno, - new_reg, subreg_p)) + new_reg, subreg_p, debug_p)) result = true; } } @@ -1945,7 +2005,8 @@ rtx new_reg, bool subreg_p) { rtx loc = insn; - return lra_substitute_pseudo (&loc, old_regno, new_reg, subreg_p); + return lra_substitute_pseudo (&loc, old_regno, new_reg, subreg_p, + DEBUG_INSN_P (insn)); } @@ -2372,7 +2433,7 @@ bitmap_initialize (&lra_optional_reload_pseudos, ®_obstack); bitmap_initialize (&lra_subreg_reload_pseudos, ®_obstack); live_p = false; - if (get_frame_size () != 0 && crtl->stack_alignment_needed) + if (maybe_ne (get_frame_size (), 0) && crtl->stack_alignment_needed) /* If we have a stack frame, we must align it now. The stack size may be a part of the offset computation for register elimination. */ @@ -2426,38 +2487,54 @@ } if (live_p) lra_clear_live_ranges (); - /* We need live ranges for lra_assign -- so build them. But - don't remove dead insns or change global live info as we - can undo inheritance transformations after inheritance - pseudo assigning. */ - lra_create_live_ranges (true, false); - live_p = true; - /* If we don't spill non-reload and non-inheritance pseudos, - there is no sense to run memory-memory move coalescing. - If inheritance pseudos were spilled, the memory-memory - moves involving them will be removed by pass undoing - inheritance. */ - if (lra_simple_p) - lra_assign (); - else + bool fails_p; + do { - bool spill_p = !lra_assign (); - - if (lra_undo_inheritance ()) - live_p = false; - if (spill_p) + /* We need live ranges for lra_assign -- so build them. + But don't remove dead insns or change global live + info as we can undo inheritance transformations after + inheritance pseudo assigning. */ + lra_create_live_ranges (true, false); + live_p = true; + /* If we don't spill non-reload and non-inheritance + pseudos, there is no sense to run memory-memory move + coalescing. If inheritance pseudos were spilled, the + memory-memory moves involving them will be removed by + pass undoing inheritance. */ + if (lra_simple_p) + lra_assign (fails_p); + else { - if (! live_p) + bool spill_p = !lra_assign (fails_p); + + if (lra_undo_inheritance ()) + live_p = false; + if (spill_p && ! fails_p) { - lra_create_live_ranges (true, true); - live_p = true; + if (! live_p) + { + lra_create_live_ranges (true, true); + live_p = true; + } + if (lra_coalesce ()) + live_p = false; } - if (lra_coalesce ()) - live_p = false; + if (! live_p) + lra_clear_live_ranges (); } - if (! live_p) - lra_clear_live_ranges (); + if (fails_p) + { + /* It is a very rare case. It is the last hope to + split a hard regno live range for a reload + pseudo. */ + if (live_p) + lra_clear_live_ranges (); + live_p = false; + if (! lra_split_hard_reg_for ()) + break; + } } + while (fails_p); } /* Don't clear optional reloads bitmap until all constraints are satisfied as we need to differ them from regular reloads. */