From 30dc1902a777966dc1d1dad0fb5f19b7a960e5ca Mon Sep 17 00:00:00 2001 From: Alan Hayward Date: Mon, 6 Aug 2018 09:51:01 +0000 Subject: [PATCH] lra support for clobber_high gcc/ * lra-eliminations.c (lra_eliminate_regs_1): Check for clobber high. (mark_not_eliminable): Likewise. * lra-int.h (struct lra_insn_reg): Add clobber high marker. * lra-lives.c (process_bb_lives): Check for clobber high. * lra.c (new_insn_reg): Remember clobber highs. (collect_non_operand_hard_regs): Check for clobber high. (lra_set_insn_recog_data): Likewise. (add_regs_to_insn_regno_info): Likewise. (lra_update_insn_regno_info): Likewise. From-SVN: r263329 --- gcc/ChangeLog | 12 ++++++++ gcc/lra-eliminations.c | 11 +++++++ gcc/lra-int.h | 2 ++ gcc/lra-lives.c | 31 +++++++++++++------- gcc/lra.c | 66 +++++++++++++++++++++++++++++------------- 5 files changed, 92 insertions(+), 30 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 36f604d76fc..8d9b158861d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2018-08-06 Alan Hayward + + * lra-eliminations.c (lra_eliminate_regs_1): Check for clobber high. + (mark_not_eliminable): Likewise. + * lra-int.h (struct lra_insn_reg): Add clobber high marker. + * lra-lives.c (process_bb_lives): Check for clobber high. + * lra.c (new_insn_reg): Remember clobber highs. + (collect_non_operand_hard_regs): Check for clobber high. + (lra_set_insn_recog_data): Likewise. + (add_regs_to_insn_regno_info): Likewise. + (lra_update_insn_regno_info): Likewise. + 2018-08-06 Alan Hayward * rtl.h (reg_is_clobbered_by_clobber_high): Add declarations. diff --git a/gcc/lra-eliminations.c b/gcc/lra-eliminations.c index f5f104020b3..d0cfaa8714a 100644 --- a/gcc/lra-eliminations.c +++ b/gcc/lra-eliminations.c @@ -654,6 +654,7 @@ lra_eliminate_regs_1 (rtx_insn *insn, rtx x, machine_mode mem_mode, return x; case CLOBBER: + case CLOBBER_HIGH: case SET: gcc_unreachable (); @@ -806,6 +807,16 @@ mark_not_eliminable (rtx x, machine_mode mem_mode) setup_can_eliminate (ep, false); return; + case CLOBBER_HIGH: + gcc_assert (REG_P (XEXP (x, 0))); + gcc_assert (REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER); + for (ep = reg_eliminate; + ep < ®_eliminate[NUM_ELIMINABLE_REGS]; + ep++) + if (reg_is_clobbered_by_clobber_high (ep->to_rtx, XEXP (x, 0))) + setup_can_eliminate (ep, false); + return; + case SET: if (SET_DEST (x) == stack_pointer_rtx && GET_CODE (SET_SRC (x)) == PLUS diff --git a/gcc/lra-int.h b/gcc/lra-int.h index 86e103b7480..5267b53c5e3 100644 --- a/gcc/lra-int.h +++ b/gcc/lra-int.h @@ -168,6 +168,8 @@ struct lra_insn_reg /* True if there is an early clobber alternative for this operand. */ unsigned int early_clobber : 1; + /* True if the reg is clobber highed by the operand. */ + unsigned int clobber_high : 1; /* The corresponding regno of the register. */ int regno; /* Next reg info of the same insn. */ diff --git a/gcc/lra-lives.c b/gcc/lra-lives.c index 920fd02b997..433c819d9e3 100644 --- a/gcc/lra-lives.c +++ b/gcc/lra-lives.c @@ -658,7 +658,7 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p) bool call_p; int n_alt, dst_regno, src_regno; rtx set; - struct lra_insn_reg *reg; + struct lra_insn_reg *reg, *hr; if (!NONDEBUG_INSN_P (curr_insn)) continue; @@ -690,11 +690,12 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p) break; } for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next) - if (reg->type != OP_IN) + if (reg->type != OP_IN && !reg->clobber_high) { remove_p = false; break; } + if (remove_p && ! volatile_refs_p (PATTERN (curr_insn))) { dst_regno = REGNO (SET_DEST (set)); @@ -812,14 +813,24 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p) unused values because they still conflict with quantities that are live at the time of the definition. */ for (reg = curr_id->regs; reg != NULL; reg = reg->next) - if (reg->type != OP_IN) - { - need_curr_point_incr - |= mark_regno_live (reg->regno, reg->biggest_mode, - curr_point); - check_pseudos_live_through_calls (reg->regno, - last_call_used_reg_set); - } + { + if (reg->type != OP_IN) + { + need_curr_point_incr + |= mark_regno_live (reg->regno, reg->biggest_mode, + curr_point); + check_pseudos_live_through_calls (reg->regno, + last_call_used_reg_set); + } + + if (reg->regno >= FIRST_PSEUDO_REGISTER) + for (hr = curr_static_id->hard_regs; hr != NULL; hr = hr->next) + if (hr->clobber_high + && maybe_gt (GET_MODE_SIZE (PSEUDO_REGNO_MODE (reg->regno)), + GET_MODE_SIZE (hr->biggest_mode))) + SET_HARD_REG_BIT (lra_reg_info[reg->regno].conflict_hard_regs, + hr->regno); + } for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next) if (reg->type != OP_IN) diff --git a/gcc/lra.c b/gcc/lra.c index b410b90f126..aa768fb2a23 100644 --- a/gcc/lra.c +++ b/gcc/lra.c @@ -535,13 +535,14 @@ object_allocator lra_insn_reg_pool ("insn regs"); 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 @@ new_insn_reg (rtx_insn *insn, int regno, enum op_type type, 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; @@ -821,12 +823,13 @@ setup_operand_alternative (lra_insn_recog_data_t data, 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_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; @@ -890,7 +893,8 @@ collect_non_operand_hard_regs (rtx_insn *insn, rtx *x, #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; @@ -899,24 +903,31 @@ collect_non_operand_hard_regs (rtx_insn *insn, rtx *x, { case SET: list = collect_non_operand_hard_regs (insn, &SET_DEST (op), data, - list, OP_OUT, false); + list, OP_OUT, false, false); list = collect_non_operand_hard_regs (insn, &SET_SRC (op), data, - list, OP_IN, false); + list, OP_IN, false, false); break; case CLOBBER: /* 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); + 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 (insn, &XEXP (op, 0), data, - list, OP_INOUT, false); + list, OP_INOUT, false, false); break; case PRE_MODIFY: case POST_MODIFY: list = collect_non_operand_hard_regs (insn, &XEXP (op, 0), data, - list, OP_INOUT, false); + list, OP_INOUT, false, false); list = collect_non_operand_hard_regs (insn, &XEXP (op, 1), data, - list, OP_IN, false); + list, OP_IN, false, false); break; default: fmt = GET_RTX_FORMAT (code); @@ -924,11 +935,12 @@ collect_non_operand_hard_regs (rtx_insn *insn, rtx *x, { if (fmt[i] == 'e') list = collect_non_operand_hard_regs (insn, &XEXP (op, i), data, - list, OP_IN, false); + 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 (insn, &XVECEXP (op, i, j), - data, list, OP_IN, false); + data, list, OP_IN, false, + false); } } return list; @@ -1081,7 +1093,7 @@ lra_set_insn_recog_data (rtx_insn *insn) else insn_static_data->hard_regs = collect_non_operand_hard_regs (insn, &PATTERN (insn), data, - NULL, OP_IN, false); + NULL, OP_IN, false, false); data->arg_hard_regs = NULL; if (CALL_P (insn)) { @@ -1107,6 +1119,11 @@ lra_set_insn_recog_data (rtx_insn *insn) 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; @@ -1469,7 +1486,7 @@ add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x, { data->regs = new_insn_reg (data->insn, regno, type, mode, subreg_p, early_clobber, early_clobber_alts, - data->regs); + data->regs, false); return; } else @@ -1482,7 +1499,8 @@ add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x, 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) @@ -1509,6 +1527,8 @@ add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x, 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), insn, OP_INOUT, false, 0); break; @@ -1643,10 +1663,16 @@ lra_update_insn_regno_info (rtx_insn *insn) 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), insn, - 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); } -- 2.30.2