Index: var-tracking.c =================================================================== --- var-tracking.c (revision 174027) +++ var-tracking.c (working copy) @@ -429,7 +429,7 @@ static void var_reg_set (dataflow_set *, static void var_reg_delete_and_set (dataflow_set *, rtx, bool, enum var_init_status, rtx); static void var_reg_delete (dataflow_set *, rtx, bool); -static void var_regno_delete (dataflow_set *, int); +static void var_regno_delete (dataflow_set *, unsigned int); static void var_mem_set (dataflow_set *, rtx, enum var_init_status, rtx); static void var_mem_delete_and_set (dataflow_set *, rtx, bool, enum var_init_status, rtx); @@ -1690,6 +1690,36 @@ get_init_value (dataflow_set *set, rtx l return ret_val; } +/* Remove the one-part variable pointed to by SLOT from the set passed as + INFO if its location is a MEM. */ + +static int +delete_mem_loc (void **slot, void *info) +{ + dataflow_set *set = (dataflow_set *) info; + variable var = (variable) *slot; + + gcc_assert (var->n_var_parts == 1); + + if (MEM_P (var->var_part[0].loc_chain->loc)) + delete_variable_part (set, var->var_part[0].loc_chain->loc, var->dv, + var->var_part[0].offset); + + return 1; +} + +/* Remove all one-part variables from the entry block still live in SET + and whose location is a MEM. */ + +static void +delete_mem_locs_on_entry (dataflow_set *set) +{ + set->traversed_vars = VTI (ENTRY_BLOCK_PTR)->out.vars; + htab_traverse (shared_hash_htab (VTI (ENTRY_BLOCK_PTR)->out.vars), + delete_mem_loc, set); + set->traversed_vars = NULL; +} + /* Delete current content of register LOC in dataflow set SET and set the register to contain REG_EXPR (LOC), REG_OFFSET (LOC). If MODIFY is true, any other live copies of the same variable part are @@ -1701,6 +1731,7 @@ static void var_reg_delete_and_set (dataflow_set *set, rtx loc, bool modify, enum var_init_status initialized, rtx set_src) { + unsigned int regno = REGNO (loc); tree decl = REG_EXPR (loc); HOST_WIDE_INT offset = REG_OFFSET (loc); attrs node, next; @@ -1711,7 +1742,7 @@ var_reg_delete_and_set (dataflow_set *se if (initialized == VAR_INIT_STATUS_UNKNOWN) initialized = get_init_value (set, loc, dv_from_decl (decl)); - nextp = &set->regs[REGNO (loc)]; + nextp = &set->regs[regno]; for (node = *nextp; node; node = next) { next = node->next; @@ -1729,6 +1760,12 @@ var_reg_delete_and_set (dataflow_set *se } if (modify) clobber_variable_part (set, loc, dv_from_decl (decl), offset, set_src); + + /* If the DRAP register is set, then the incoming location of all parameters + not passed in registers is no longer valid. */ + if (stack_realign_drap && crtl->drap_reg && REGNO (crtl->drap_reg) == regno) + delete_mem_locs_on_entry (set); + var_reg_set (set, loc, initialized, set_src); } @@ -1740,7 +1777,8 @@ var_reg_delete_and_set (dataflow_set *se static void var_reg_delete (dataflow_set *set, rtx loc, bool clobber) { - attrs *nextp = &set->regs[REGNO (loc)]; + unsigned int regno = REGNO (loc); + attrs *nextp = &set->regs[regno]; attrs node, next; if (clobber) @@ -1751,6 +1789,13 @@ var_reg_delete (dataflow_set *set, rtx l decl = var_debug_decl (decl); clobber_variable_part (set, NULL, dv_from_decl (decl), offset, NULL); + + /* If the DRAP register is clobbered, then the incoming location of all + parameters not passed in registers is no longer valid. */ + if (stack_realign_drap + && crtl->drap_reg + && REGNO (crtl->drap_reg) == regno) + delete_mem_locs_on_entry (set); } for (node = *nextp; node; node = next) @@ -1770,7 +1815,7 @@ var_reg_delete (dataflow_set *set, rtx l /* Delete content of register with number REGNO in dataflow set SET. */ static void -var_regno_delete (dataflow_set *set, int regno) +var_regno_delete (dataflow_set *set, unsigned int regno) { attrs *reg = &set->regs[regno]; attrs node, next; @@ -1782,6 +1827,11 @@ var_regno_delete (dataflow_set *set, int pool_free (attrs_pool, node); } *reg = NULL; + + /* If the contents of the DRAP register are changed, then the incoming + location of parameters not passed in registers is no longer valid. */ + if (stack_realign_drap && crtl->drap_reg && REGNO (crtl->drap_reg) == regno) + delete_mem_locs_on_entry (set); } /* Set the location of DV, OFFSET as the MEM LOC. */ @@ -8658,13 +8708,61 @@ vt_init_cfa_base (void) 0, NULL_RTX, INSERT); } +/* Return the SET that initializes the DRAP register in INSN, if any. */ + +static rtx * +drap_setter (rtx insn) +{ + const unsigned int drap_reg = REGNO (crtl->drap_reg); + rtx pat = PATTERN (insn); + if (GET_CODE (pat) == SET + && REG_P (SET_DEST (pat)) + && REGNO (SET_DEST (pat)) == drap_reg) + return &PATTERN (insn); + else if (GET_CODE (pat) == PARALLEL) + { + int i; + for (i = XVECLEN (pat, 0) - 1; i >= 0; i--) + if (GET_CODE (XVECEXP (pat, 0, i)) == SET + && REG_P (SET_DEST (XVECEXP (pat, 0, i))) + && REGNO (SET_DEST (XVECEXP (pat, 0, i))) == drap_reg) + return &XVECEXP (pat, 0, i); + } + return NULL; +} + +/* Mask the SET that initializes the DRAP register and create a preserved VALUE + for it. We need to do this because the incoming location of parameters not + passed in registers references the DRAP register _before_ the SET, since the + parameters are attached to the entry block. */ + +static void +vt_init_drap_reg (rtx *set) +{ + cselib_val *val; + + validate_change (NULL_RTX, set, gen_rtx_USE (VOIDmode, SET_SRC (*set)), + true); + + if (!MAY_HAVE_DEBUG_INSNS) + return; + + val = cselib_lookup_from_insn (crtl->drap_reg, GET_MODE (crtl->drap_reg), + 1, VOIDmode, get_insns ()); + preserve_value (val); + var_reg_decl_set (&VTI (ENTRY_BLOCK_PTR)->out, crtl->drap_reg, + VAR_INIT_STATUS_INITIALIZED, dv_from_value (val->val_rtx), + 0, NULL_RTX, INSERT); +} + /* Allocate and initialize the data structures for variable tracking and parse the RTL to get the micro operations. */ static bool vt_initialize (void) { - basic_block bb, prologue_bb = NULL; + basic_block prologue_bb = single_succ (ENTRY_BLOCK_PTR), bb; + unsigned int drap_reg = INVALID_REGNUM; HOST_WIDE_INT fp_cfa_offset = -1; alloc_aux_for_blocks (sizeof (struct variable_tracking_info_def)); @@ -8764,8 +8862,6 @@ vt_initialize (void) } if (elim != hard_frame_pointer_rtx) fp_cfa_offset = -1; - else - prologue_bb = single_succ (ENTRY_BLOCK_PTR); } } if (frame_pointer_needed) @@ -8778,11 +8874,9 @@ vt_initialize (void) hard_frame_pointer_adjustment = -1; - vt_add_function_parameters (); - FOR_EACH_BB (bb) { - rtx insn; + rtx insn, *set; HOST_WIDE_INT pre, post = 0; basic_block first_bb, last_bb; @@ -8836,6 +8930,17 @@ vt_initialize (void) } } + if (bb == prologue_bb + && stack_realign_drap + && crtl->drap_reg + && drap_reg == INVALID_REGNUM + && RTX_FRAME_RELATED_P (insn) + && ((set = drap_setter (insn)) != NULL)) + { + vt_init_drap_reg (set); + drap_reg = REGNO (crtl->drap_reg); + } + cselib_hook_called = false; adjust_insn (bb, insn); if (MAY_HAVE_DEBUG_INSNS) @@ -8869,6 +8974,7 @@ vt_initialize (void) if (bb == prologue_bb && hard_frame_pointer_adjustment == -1 + && fp_cfa_offset != -1 && RTX_FRAME_RELATED_P (insn) && fp_setter (insn)) { @@ -8876,6 +8982,14 @@ vt_initialize (void) hard_frame_pointer_adjustment = fp_cfa_offset; } } + + /* Initialize the parameters right at the end of the prologue. + We can do this neither earlier because the insn establishing + the frame might invalidate all the previous MEMs, nor later + because the DRAP register might be clobbered in between. */ + else if (NOTE_P (insn) + && NOTE_KIND (insn) == NOTE_INSN_PROLOGUE_END) + vt_add_function_parameters (); } gcc_assert (offset == VTI (bb)->out.stack_adjust); }