X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fvar-tracking.c;h=ab4d93cb76b89298a9cfc2aa019a5e84f65d71bf;hb=76c47433a7a7d3c156fba4ad1e9331e38abd41da;hp=815facae1820e47b06f0c10b7aac1e6ecd781f7d;hpb=1441be6b64cb4fe3c058f1090dfb0f1d8a544b66;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c index 815facae182..ab4d93cb76b 100644 --- a/gcc/var-tracking.c +++ b/gcc/var-tracking.c @@ -1,11 +1,11 @@ /* Variable tracking routines for the GNU compiler. - Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc. This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) + the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT @@ -14,9 +14,8 @@ License for more details. You should have received a copy of the GNU General Public License - along with GCC; see the file COPYING. If not, write to the Free - Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. */ + along with GCC; see the file COPYING3. If not see + . */ /* This file contains the variable tracking pass. It computes where variables are located (which registers or where in memory) at each position @@ -135,7 +134,9 @@ typedef struct micro_operation_def enum micro_operation_type type; union { - /* Location. */ + /* Location. For MO_SET and MO_COPY, this is the SET that performs + the assignment, if known, otherwise it is the target of the + assignment. */ rtx loc; /* Stack adjustment. */ @@ -219,6 +220,12 @@ typedef struct location_chain_def /* The location (REG or MEM). */ rtx loc; + + /* The "value" stored in this location. */ + rtx set_src; + + /* Initialized? */ + enum var_init_status init; } *location_chain; /* Structure describing one part of variable. */ @@ -252,6 +259,7 @@ typedef struct variable_def /* The variable parts. */ variable_part var_part[MAX_VAR_PARTS]; } *variable; +typedef const struct variable_def *const_variable; /* Hash function for DECL for VARIABLE_HTAB. */ #define VARIABLE_HASH_VAL(decl) (DECL_UID (decl)) @@ -259,6 +267,9 @@ typedef struct variable_def /* Pointer to the BB's information specific to variable tracking pass. */ #define VTI(BB) ((variable_tracking_info) (BB)->aux) +/* Macro to access MEM_OFFSET as an HOST_WIDE_INT. Evaluates MEM twice. */ +#define INT_MEM_OFFSET(mem) (MEM_OFFSET (mem) ? INTVAL (MEM_OFFSET (mem)) : 0) + /* Alloc pool for struct attrs_def. */ static alloc_pool attrs_pool; @@ -294,16 +305,19 @@ static void attrs_list_copy (attrs *, attrs); static void attrs_list_union (attrs *, attrs); static void vars_clear (htab_t); -static variable unshare_variable (dataflow_set *set, variable var); +static variable unshare_variable (dataflow_set *set, variable var, + enum var_init_status); static int vars_copy_1 (void **, void *); static void vars_copy (htab_t, htab_t); static tree var_debug_decl (tree); -static void var_reg_set (dataflow_set *, rtx); -static void var_reg_delete_and_set (dataflow_set *, rtx, bool); +static void var_reg_set (dataflow_set *, rtx, enum var_init_status, rtx); +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_mem_set (dataflow_set *, rtx); -static void var_mem_delete_and_set (dataflow_set *, rtx, bool); +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); static void var_mem_delete (dataflow_set *, rtx, bool); static void dataflow_set_init (dataflow_set *, int); @@ -324,10 +338,10 @@ static bool track_expr_p (tree); static bool same_variable_part_p (rtx, tree, HOST_WIDE_INT); static int count_uses (rtx *, void *); static void count_uses_1 (rtx *, void *); -static void count_stores (rtx, rtx, void *); +static void count_stores (rtx, const_rtx, void *); static int add_uses (rtx *, void *); static void add_uses_1 (rtx *, void *); -static void add_stores (rtx, rtx, void *); +static void add_stores (rtx, const_rtx, void *); static bool compute_bb_dataflow (basic_block); static void vt_find_locations (void); @@ -338,8 +352,10 @@ static void dump_dataflow_set (dataflow_set *); static void dump_dataflow_sets (void); static void variable_was_changed (variable, htab_t); -static void set_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT); -static void clobber_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT); +static void set_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT, + enum var_init_status, rtx); +static void clobber_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT, + rtx); static void delete_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT); static int emit_note_insn_var_location (void **, void *); static void emit_notes_for_changes (rtx, enum emit_note_where); @@ -590,7 +606,7 @@ adjust_stack_reference (rtx mem, HOST_WIDE_INT adjustment) static hashval_t variable_htab_hash (const void *x) { - const variable v = (const variable) x; + const_variable const v = (const_variable) x; return (VARIABLE_HASH_VAL (v->decl)); } @@ -600,8 +616,8 @@ variable_htab_hash (const void *x) static int variable_htab_eq (const void *x, const void *y) { - const variable v = (const variable) x; - const tree decl = (const tree) y; + const_variable const v = (const_variable) x; + const_tree const decl = (const_tree) y; return (VARIABLE_HASH_VAL (v->decl) == VARIABLE_HASH_VAL (decl)); } @@ -677,7 +693,7 @@ attrs_list_insert (attrs *listp, tree decl, HOST_WIDE_INT offset, rtx loc) { attrs list; - list = pool_alloc (attrs_pool); + list = (attrs) pool_alloc (attrs_pool); list->loc = loc; list->decl = decl; list->offset = offset; @@ -695,7 +711,7 @@ attrs_list_copy (attrs *dstp, attrs src) attrs_list_clear (dstp); for (; src; src = src->next) { - n = pool_alloc (attrs_pool); + n = (attrs) pool_alloc (attrs_pool); n->loc = src->loc; n->decl = src->decl; n->offset = src->offset; @@ -727,13 +743,14 @@ vars_clear (htab_t vars) /* Return a copy of a variable VAR and insert it to dataflow set SET. */ static variable -unshare_variable (dataflow_set *set, variable var) +unshare_variable (dataflow_set *set, variable var, + enum var_init_status initialized) { void **slot; variable new_var; int i; - new_var = pool_alloc (var_pool); + new_var = (variable) pool_alloc (var_pool); new_var->decl = var->decl; new_var->refcount = 1; var->refcount--; @@ -750,8 +767,16 @@ unshare_variable (dataflow_set *set, variable var) { location_chain new_lc; - new_lc = pool_alloc (loc_chain_pool); + new_lc = (location_chain) pool_alloc (loc_chain_pool); new_lc->next = NULL; + if (node->init > initialized) + new_lc->init = node->init; + else + new_lc->init = initialized; + if (node->set_src && !(MEM_P (node->set_src))) + new_lc->set_src = node->set_src; + else + new_lc->set_src = NULL; new_lc->loc = node->loc; *nextp = new_lc; @@ -819,7 +844,8 @@ var_debug_decl (tree decl) /* Set the register to contain REG_EXPR (LOC), REG_OFFSET (LOC). */ static void -var_reg_set (dataflow_set *set, rtx loc) +var_reg_set (dataflow_set *set, rtx loc, enum var_init_status initialized, + rtx set_src) { tree decl = REG_EXPR (loc); HOST_WIDE_INT offset = REG_OFFSET (loc); @@ -832,7 +858,38 @@ var_reg_set (dataflow_set *set, rtx loc) break; if (!node) attrs_list_insert (&set->regs[REGNO (loc)], decl, offset, loc); - set_variable_part (set, loc, decl, offset); + set_variable_part (set, loc, decl, offset, initialized, set_src); +} + +static int +get_init_value (dataflow_set *set, rtx loc, tree decl) +{ + void **slot; + variable var; + int i; + int ret_val = VAR_INIT_STATUS_UNKNOWN; + + if (! flag_var_tracking_uninit) + return VAR_INIT_STATUS_INITIALIZED; + + slot = htab_find_slot_with_hash (set->vars, decl, VARIABLE_HASH_VAL (decl), + NO_INSERT); + if (slot) + { + var = * (variable *) slot; + for (i = 0; i < var->n_var_parts && ret_val == VAR_INIT_STATUS_UNKNOWN; i++) + { + location_chain nextp; + for (nextp = var->var_part[i].loc_chain; nextp; nextp = nextp->next) + if (rtx_equal_p (nextp->loc, loc)) + { + ret_val = nextp->init; + break; + } + } + } + + return ret_val; } /* Delete current content of register LOC in dataflow set SET and set @@ -843,7 +900,8 @@ var_reg_set (dataflow_set *set, rtx loc) part. */ static void -var_reg_delete_and_set (dataflow_set *set, rtx loc, bool modify) +var_reg_delete_and_set (dataflow_set *set, rtx loc, bool modify, + enum var_init_status initialized, rtx set_src) { tree decl = REG_EXPR (loc); HOST_WIDE_INT offset = REG_OFFSET (loc); @@ -852,6 +910,9 @@ var_reg_delete_and_set (dataflow_set *set, rtx loc, bool modify) decl = var_debug_decl (decl); + if (initialized == VAR_INIT_STATUS_UNKNOWN) + initialized = get_init_value (set, loc, decl); + nextp = &set->regs[REGNO (loc)]; for (node = *nextp; node; node = next) { @@ -869,8 +930,8 @@ var_reg_delete_and_set (dataflow_set *set, rtx loc, bool modify) } } if (modify) - clobber_variable_part (set, loc, decl, offset); - var_reg_set (set, loc); + clobber_variable_part (set, loc, decl, offset, set_src); + var_reg_set (set, loc, initialized, set_src); } /* Delete current content of register LOC in dataflow set SET. If @@ -890,7 +951,7 @@ var_reg_delete (dataflow_set *set, rtx loc, bool clobber) decl = var_debug_decl (decl); - clobber_variable_part (set, NULL, decl, offset); + clobber_variable_part (set, NULL, decl, offset, NULL); } for (node = *reg; node; node = next) @@ -924,14 +985,15 @@ var_regno_delete (dataflow_set *set, int regno) Adjust the address first if it is stack pointer based. */ static void -var_mem_set (dataflow_set *set, rtx loc) +var_mem_set (dataflow_set *set, rtx loc, enum var_init_status initialized, + rtx set_src) { tree decl = MEM_EXPR (loc); - HOST_WIDE_INT offset = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0; + HOST_WIDE_INT offset = INT_MEM_OFFSET (loc); decl = var_debug_decl (decl); - set_variable_part (set, loc, decl, offset); + set_variable_part (set, loc, decl, offset, initialized, set_src); } /* Delete and set the location part of variable MEM_EXPR (LOC) in @@ -942,16 +1004,20 @@ var_mem_set (dataflow_set *set, rtx loc) Adjust the address first if it is stack pointer based. */ static void -var_mem_delete_and_set (dataflow_set *set, rtx loc, bool modify) +var_mem_delete_and_set (dataflow_set *set, rtx loc, bool modify, + enum var_init_status initialized, rtx set_src) { tree decl = MEM_EXPR (loc); - HOST_WIDE_INT offset = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0; + HOST_WIDE_INT offset = INT_MEM_OFFSET (loc); decl = var_debug_decl (decl); + if (initialized == VAR_INIT_STATUS_UNKNOWN) + initialized = get_init_value (set, loc, decl); + if (modify) - clobber_variable_part (set, NULL, decl, offset); - var_mem_set (set, loc); + clobber_variable_part (set, NULL, decl, offset, set_src); + var_mem_set (set, loc, initialized, set_src); } /* Delete the location part LOC from dataflow set SET. If CLOBBER is @@ -962,11 +1028,11 @@ static void var_mem_delete (dataflow_set *set, rtx loc, bool clobber) { tree decl = MEM_EXPR (loc); - HOST_WIDE_INT offset = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0; + HOST_WIDE_INT offset = INT_MEM_OFFSET (loc); decl = var_debug_decl (decl); if (clobber) - clobber_variable_part (set, NULL, decl, offset); + clobber_variable_part (set, NULL, decl, offset, NULL); delete_variable_part (set, loc, decl, offset); } @@ -1029,8 +1095,10 @@ struct variable_union_info static int variable_union_info_cmp_pos (const void *n1, const void *n2) { - const struct variable_union_info *i1 = n1; - const struct variable_union_info *i2 = n2; + const struct variable_union_info *const i1 = + (const struct variable_union_info *) n1; + const struct variable_union_info *const i2 = + ( const struct variable_union_info *) n2; if (i1->pos != i2->pos) return i1->pos - i2->pos; @@ -1078,7 +1146,14 @@ variable_union (void **slot, void *data) } } if (k < src->n_var_parts) - unshare_variable (set, src); + { + enum var_init_status status = VAR_INIT_STATUS_UNKNOWN; + + if (! flag_var_tracking_uninit) + status = VAR_INIT_STATUS_INITIALIZED; + + unshare_variable (set, src, status); + } else *dstp = src; @@ -1112,7 +1187,13 @@ variable_union (void **slot, void *data) gcc_assert (k <= MAX_VAR_PARTS); if (dst->refcount > 1 && dst->n_var_parts != k) - dst = unshare_variable (set, dst); + { + enum var_init_status status = VAR_INIT_STATUS_UNKNOWN; + + if (! flag_var_tracking_uninit) + status = VAR_INIT_STATUS_INITIALIZED; + dst = unshare_variable (set, dst, status); + } i = src->n_var_parts - 1; j = dst->n_var_parts - 1; @@ -1145,10 +1226,14 @@ variable_union (void **slot, void *data) && REG_P (node->loc) && REGNO (node2->loc) == REGNO (node->loc)) || rtx_equal_p (node2->loc, node->loc))) - break; + { + if (node2->init < node->init) + node2->init = node->init; + break; + } } if (node || node2) - dst = unshare_variable (set, dst); + dst = unshare_variable (set, dst, VAR_INIT_STATUS_UNKNOWN); } src_l = 0; @@ -1192,8 +1277,13 @@ variable_union (void **slot, void *data) location_chain new_node; /* Copy the location from SRC. */ - new_node = pool_alloc (loc_chain_pool); + new_node = (location_chain) pool_alloc (loc_chain_pool); new_node->loc = node->loc; + new_node->init = node->init; + if (!node->set_src || MEM_P (node->set_src)) + new_node->set_src = NULL; + else + new_node->set_src = node->set_src; vui[n].lc = new_node; vui[n].pos_src = ii; vui[n].pos_dst = src_l + dst_l; @@ -1238,8 +1328,13 @@ variable_union (void **slot, void *data) { location_chain new_lc; - new_lc = pool_alloc (loc_chain_pool); + new_lc = (location_chain) pool_alloc (loc_chain_pool); new_lc->next = NULL; + new_lc->init = node->init; + if (!node->set_src || MEM_P (node->set_src)) + new_lc->set_src = NULL; + else + new_lc->set_src = node->set_src; new_lc->loc = node->loc; *nextp = new_lc; @@ -1258,6 +1353,18 @@ variable_union (void **slot, void *data) dst->var_part[k].cur_loc = NULL; } + for (i = 0; i < src->n_var_parts && i < dst->n_var_parts; i++) + { + location_chain node, node2; + for (node = src->var_part[i].loc_chain; node; node = node->next) + for (node2 = dst->var_part[i].loc_chain; node2; node2 = node2->next) + if (rtx_equal_p (node->loc, node2->loc)) + { + if (node->init > node2->init) + node2->init = node->init; + } + } + /* Continue traversing the hash table. */ return 1; } @@ -1350,7 +1457,7 @@ dataflow_set_different_1 (void **slot, void *data) variable var1, var2; var1 = *(variable *) slot; - var2 = htab_find_with_hash (htab, var1->decl, + var2 = (variable) htab_find_with_hash (htab, var1->decl, VARIABLE_HASH_VAL (var1->decl)); if (!var2) { @@ -1382,7 +1489,7 @@ dataflow_set_different_2 (void **slot, void *data) variable var1, var2; var1 = *(variable *) slot; - var2 = htab_find_with_hash (htab, var1->decl, + var2 = (variable) htab_find_with_hash (htab, var1->decl, VARIABLE_HASH_VAL (var1->decl)); if (!var2) { @@ -1529,7 +1636,8 @@ track_expr_p (tree expr) if (MEM_P (decl_rtl)) { /* Do not track structures and arrays. */ - if (GET_MODE (decl_rtl) == BLKmode) + if (GET_MODE (decl_rtl) == BLKmode + || AGGREGATE_TYPE_P (TREE_TYPE (realdecl))) return 0; if (MEM_SIZE (decl_rtl) && INTVAL (MEM_SIZE (decl_rtl)) > MAX_VAR_PARTS) @@ -1559,7 +1667,7 @@ same_variable_part_p (rtx loc, tree expr, HOST_WIDE_INT offset) else if (MEM_P (loc)) { expr2 = MEM_EXPR (loc); - offset2 = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0; + offset2 = INT_MEM_OFFSET (loc); } else return false; @@ -1573,6 +1681,92 @@ same_variable_part_p (rtx loc, tree expr, HOST_WIDE_INT offset) return (expr == expr2 && offset == offset2); } +/* LOC is a REG or MEM that we would like to track if possible. + If EXPR is null, we don't know what expression LOC refers to, + otherwise it refers to EXPR + OFFSET. STORE_REG_P is true if + LOC is an lvalue register. + + Return true if EXPR is nonnull and if LOC, or some lowpart of it, + is something we can track. When returning true, store the mode of + the lowpart we can track in *MODE_OUT (if nonnull) and its offset + from EXPR in *OFFSET_OUT (if nonnull). */ + +static bool +track_loc_p (rtx loc, tree expr, HOST_WIDE_INT offset, bool store_reg_p, + enum machine_mode *mode_out, HOST_WIDE_INT *offset_out) +{ + enum machine_mode mode; + + if (expr == NULL || !track_expr_p (expr)) + return false; + + /* If REG was a paradoxical subreg, its REG_ATTRS will describe the + whole subreg, but only the old inner part is really relevant. */ + mode = GET_MODE (loc); + if (REG_P (loc) && !HARD_REGISTER_NUM_P (ORIGINAL_REGNO (loc))) + { + enum machine_mode pseudo_mode; + + pseudo_mode = PSEUDO_REGNO_MODE (ORIGINAL_REGNO (loc)); + if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (pseudo_mode)) + { + offset += byte_lowpart_offset (pseudo_mode, mode); + mode = pseudo_mode; + } + } + + /* If LOC is a paradoxical lowpart of EXPR, refer to EXPR itself. + Do the same if we are storing to a register and EXPR occupies + the whole of register LOC; in that case, the whole of EXPR is + being changed. We exclude complex modes from the second case + because the real and imaginary parts are represented as separate + pseudo registers, even if the whole complex value fits into one + hard register. */ + if ((GET_MODE_SIZE (mode) > GET_MODE_SIZE (DECL_MODE (expr)) + || (store_reg_p + && !COMPLEX_MODE_P (DECL_MODE (expr)) + && hard_regno_nregs[REGNO (loc)][DECL_MODE (expr)] == 1)) + && offset + byte_lowpart_offset (DECL_MODE (expr), mode) == 0) + { + mode = DECL_MODE (expr); + offset = 0; + } + + if (offset < 0 || offset >= MAX_VAR_PARTS) + return false; + + if (mode_out) + *mode_out = mode; + if (offset_out) + *offset_out = offset; + return true; +} + +/* Return the MODE lowpart of LOC, or null if LOC is not something we + want to track. When returning nonnull, make sure that the attributes + on the returned value are updated. */ + +static rtx +var_lowpart (enum machine_mode mode, rtx loc) +{ + unsigned int offset, reg_offset, regno; + + if (!REG_P (loc) && !MEM_P (loc)) + return NULL; + + if (GET_MODE (loc) == mode) + return loc; + + offset = byte_lowpart_offset (mode, GET_MODE (loc)); + + if (MEM_P (loc)) + return adjust_address_nv (loc, mode, offset); + + reg_offset = subreg_lowpart_offset (mode, GET_MODE (loc)); + regno = REGNO (loc) + subreg_regno_offset (REGNO (loc), GET_MODE (loc), + reg_offset, mode); + return gen_rtx_REG_offset (loc, mode, regno, offset); +} /* Count uses (register and memory references) LOC which will be tracked. INSN is instruction which the LOC is part of. */ @@ -1588,8 +1782,8 @@ count_uses (rtx *loc, void *insn) VTI (bb)->n_mos++; } else if (MEM_P (*loc) - && MEM_EXPR (*loc) - && track_expr_p (MEM_EXPR (*loc))) + && track_loc_p (*loc, MEM_EXPR (*loc), INT_MEM_OFFSET (*loc), + false, NULL, NULL)) { VTI (bb)->n_mos++; } @@ -1609,7 +1803,7 @@ count_uses_1 (rtx *x, void *insn) INSN is instruction which the LOC is part of. */ static void -count_stores (rtx loc, rtx expr ATTRIBUTE_UNUSED, void *insn) +count_stores (rtx loc, const_rtx expr ATTRIBUTE_UNUSED, void *insn) { count_uses (&loc, insn); } @@ -1620,25 +1814,35 @@ count_stores (rtx loc, rtx expr ATTRIBUTE_UNUSED, void *insn) static int add_uses (rtx *loc, void *insn) { + enum machine_mode mode; + if (REG_P (*loc)) { basic_block bb = BLOCK_FOR_INSN ((rtx) insn); micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++; - mo->type = ((REG_EXPR (*loc) && track_expr_p (REG_EXPR (*loc))) - ? MO_USE : MO_USE_NO_VAR); - mo->u.loc = *loc; + if (track_loc_p (*loc, REG_EXPR (*loc), REG_OFFSET (*loc), + false, &mode, NULL)) + { + mo->type = MO_USE; + mo->u.loc = var_lowpart (mode, *loc); + } + else + { + mo->type = MO_USE_NO_VAR; + mo->u.loc = *loc; + } mo->insn = (rtx) insn; } else if (MEM_P (*loc) - && MEM_EXPR (*loc) - && track_expr_p (MEM_EXPR (*loc))) + && track_loc_p (*loc, MEM_EXPR (*loc), INT_MEM_OFFSET (*loc), + false, &mode, NULL)) { basic_block bb = BLOCK_FOR_INSN ((rtx) insn); micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++; mo->type = MO_USE; - mo->u.loc = *loc; + mo->u.loc = var_lowpart (mode, *loc); mo->insn = (rtx) insn; } @@ -1658,51 +1862,154 @@ add_uses_1 (rtx *x, void *insn) INSN is instruction which the LOC is part of. */ static void -add_stores (rtx loc, rtx expr, void *insn) +add_stores (rtx loc, const_rtx expr, void *insn) { + enum machine_mode mode; + if (REG_P (loc)) { basic_block bb = BLOCK_FOR_INSN ((rtx) insn); micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++; if (GET_CODE (expr) == CLOBBER - || ! REG_EXPR (loc) - || ! track_expr_p (REG_EXPR (loc))) - mo->type = MO_CLOBBER; - else if (GET_CODE (expr) == SET - && SET_DEST (expr) == loc - && same_variable_part_p (SET_SRC (expr), - REG_EXPR (loc), - REG_OFFSET (loc))) - mo->type = MO_COPY; + || !track_loc_p (loc, REG_EXPR (loc), REG_OFFSET (loc), + true, &mode, NULL)) + { + mo->type = MO_CLOBBER; + mo->u.loc = loc; + } else - mo->type = MO_SET; - mo->u.loc = loc; - mo->insn = NEXT_INSN ((rtx) insn); + { + rtx src = NULL; + + if (GET_CODE (expr) == SET && SET_DEST (expr) == loc) + src = var_lowpart (mode, SET_SRC (expr)); + loc = var_lowpart (mode, loc); + + if (src == NULL) + { + mo->type = MO_SET; + mo->u.loc = loc; + } + else + { + if (SET_SRC (expr) != src) + expr = gen_rtx_SET (VOIDmode, loc, src); + if (same_variable_part_p (src, REG_EXPR (loc), REG_OFFSET (loc))) + mo->type = MO_COPY; + else + mo->type = MO_SET; + mo->u.loc = CONST_CAST_RTX (expr); + } + } + mo->insn = (rtx) insn; } else if (MEM_P (loc) - && MEM_EXPR (loc) - && track_expr_p (MEM_EXPR (loc))) + && track_loc_p (loc, MEM_EXPR (loc), INT_MEM_OFFSET (loc), + false, &mode, NULL)) { basic_block bb = BLOCK_FOR_INSN ((rtx) insn); micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++; if (GET_CODE (expr) == CLOBBER) - mo->type = MO_CLOBBER; - else if (GET_CODE (expr) == SET - && SET_DEST (expr) == loc - && same_variable_part_p (SET_SRC (expr), - MEM_EXPR (loc), - MEM_OFFSET (loc) - ? INTVAL (MEM_OFFSET (loc)) : 0)) - mo->type = MO_COPY; + { + mo->type = MO_CLOBBER; + mo->u.loc = var_lowpart (mode, loc); + } else - mo->type = MO_SET; - mo->u.loc = loc; - mo->insn = NEXT_INSN ((rtx) insn); + { + rtx src = NULL; + + if (GET_CODE (expr) == SET && SET_DEST (expr) == loc) + src = var_lowpart (mode, SET_SRC (expr)); + loc = var_lowpart (mode, loc); + + if (src == NULL) + { + mo->type = MO_SET; + mo->u.loc = loc; + } + else + { + if (SET_SRC (expr) != src) + expr = gen_rtx_SET (VOIDmode, loc, src); + if (same_variable_part_p (SET_SRC (expr), + MEM_EXPR (loc), + INT_MEM_OFFSET (loc))) + mo->type = MO_COPY; + else + mo->type = MO_SET; + mo->u.loc = CONST_CAST_RTX (expr); + } + } + mo->insn = (rtx) insn; } } +static enum var_init_status +find_src_status (dataflow_set *in, rtx src) +{ + tree decl = NULL_TREE; + enum var_init_status status = VAR_INIT_STATUS_UNINITIALIZED; + + if (! flag_var_tracking_uninit) + status = VAR_INIT_STATUS_INITIALIZED; + + if (src && REG_P (src)) + decl = var_debug_decl (REG_EXPR (src)); + else if (src && MEM_P (src)) + decl = var_debug_decl (MEM_EXPR (src)); + + if (src && decl) + status = get_init_value (in, src, decl); + + return status; +} + +/* SRC is the source of an assignment. Use SET to try to find what + was ultimately assigned to SRC. Return that value if known, + otherwise return SRC itself. */ + +static rtx +find_src_set_src (dataflow_set *set, rtx src) +{ + tree decl = NULL_TREE; /* The variable being copied around. */ + rtx set_src = NULL_RTX; /* The value for "decl" stored in "src". */ + void **slot; + variable var; + location_chain nextp; + int i; + bool found; + + if (src && REG_P (src)) + decl = var_debug_decl (REG_EXPR (src)); + else if (src && MEM_P (src)) + decl = var_debug_decl (MEM_EXPR (src)); + + if (src && decl) + { + slot = htab_find_slot_with_hash (set->vars, decl, + VARIABLE_HASH_VAL (decl), NO_INSERT); + + if (slot) + { + var = *(variable *) slot; + found = false; + for (i = 0; i < var->n_var_parts && !found; i++) + for (nextp = var->var_part[i].loc_chain; nextp && !found; + nextp = nextp->next) + if (rtx_equal_p (nextp->loc, src)) + { + set_src = nextp->set_src; + found = true; + } + + } + } + + return set_src; +} + /* Compute the changes of variable locations in the basic block BB. */ static bool @@ -1732,33 +2039,64 @@ compute_bb_dataflow (basic_block bb) case MO_USE: { rtx loc = VTI (bb)->mos[i].u.loc; + enum var_init_status status = VAR_INIT_STATUS_UNINITIALIZED; + + if (! flag_var_tracking_uninit) + status = VAR_INIT_STATUS_INITIALIZED; if (GET_CODE (loc) == REG) - var_reg_set (out, loc); + var_reg_set (out, loc, status, NULL); else if (GET_CODE (loc) == MEM) - var_mem_set (out, loc); + var_mem_set (out, loc, status, NULL); } break; case MO_SET: { rtx loc = VTI (bb)->mos[i].u.loc; + rtx set_src = NULL; + + if (GET_CODE (loc) == SET) + { + set_src = SET_SRC (loc); + loc = SET_DEST (loc); + } if (REG_P (loc)) - var_reg_delete_and_set (out, loc, true); + var_reg_delete_and_set (out, loc, true, VAR_INIT_STATUS_INITIALIZED, + set_src); else if (MEM_P (loc)) - var_mem_delete_and_set (out, loc, true); + var_mem_delete_and_set (out, loc, true, VAR_INIT_STATUS_INITIALIZED, + set_src); } break; case MO_COPY: { rtx loc = VTI (bb)->mos[i].u.loc; + enum var_init_status src_status; + rtx set_src = NULL; + + if (GET_CODE (loc) == SET) + { + set_src = SET_SRC (loc); + loc = SET_DEST (loc); + } + + if (! flag_var_tracking_uninit) + src_status = VAR_INIT_STATUS_INITIALIZED; + else + src_status = find_src_status (in, set_src); + + if (src_status == VAR_INIT_STATUS_UNKNOWN) + src_status = find_src_status (out, set_src); + + set_src = find_src_set_src (in, set_src); if (REG_P (loc)) - var_reg_delete_and_set (out, loc, false); + var_reg_delete_and_set (out, loc, false, src_status, set_src); else if (MEM_P (loc)) - var_mem_delete_and_set (out, loc, false); + var_mem_delete_and_set (out, loc, false, src_status, set_src); } break; @@ -1841,7 +2179,7 @@ vt_find_locations (void) while (!fibheap_empty (worklist)) { - bb = fibheap_extract_min (worklist); + bb = (basic_block) fibheap_extract_min (worklist); RESET_BIT (in_worklist, bb->index); if (!TEST_BIT (visited, bb->index)) { @@ -1922,8 +2260,13 @@ dump_variable (void **slot, void *data ATTRIBUTE_UNUSED) int i; location_chain node; - fprintf (dump_file, " name: %s\n", + fprintf (dump_file, " name: %s", IDENTIFIER_POINTER (DECL_NAME (var->decl))); + if (dump_flags & TDF_UID) + fprintf (dump_file, " D.%u\n", DECL_UID (var->decl)); + else + fprintf (dump_file, "\n"); + for (i = 0; i < var->n_var_parts; i++) { fprintf (dump_file, " offset %ld\n", @@ -1931,6 +2274,8 @@ dump_variable (void **slot, void *data ATTRIBUTE_UNUSED) for (node = var->var_part[i].loc_chain; node; node = node->next) { fprintf (dump_file, " "); + if (node->init == VAR_INIT_STATUS_UNINITIALIZED) + fprintf (dump_file, "[uninit]"); print_rtl_single (dump_file, node->loc); } } @@ -2009,7 +2354,7 @@ variable_was_changed (variable var, htab_t htab) variable empty_var; void **old; - empty_var = pool_alloc (var_pool); + empty_var = (variable) pool_alloc (var_pool); empty_var->decl = var->decl; empty_var->refcount = 1; empty_var->n_var_parts = 0; @@ -2076,7 +2421,8 @@ find_variable_location_part (variable var, HOST_WIDE_INT offset, part's location by LOC. */ static void -set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset) +set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset, + enum var_init_status initialized, rtx set_src) { int pos; location_chain node, next; @@ -2089,7 +2435,7 @@ set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset) if (!*slot) { /* Create new variable information. */ - var = pool_alloc (var_pool); + var = (variable) pool_alloc (var_pool); var->decl = decl; var->refcount = 1; var->n_var_parts = 1; @@ -2118,13 +2464,19 @@ set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset) { /* LOC is in the beginning of the chain so we have nothing to do. */ + if (node->init < initialized) + node->init = initialized; + if (set_src != NULL) + node->set_src = set_src; + + *slot = var; return; } else { /* We have to make a copy of a shared variable. */ if (var->refcount > 1) - var = unshare_variable (set, var); + var = unshare_variable (set, var, initialized); } } else @@ -2133,7 +2485,7 @@ set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset) /* We have to make a copy of the shared variable. */ if (var->refcount > 1) - var = unshare_variable (set, var); + var = unshare_variable (set, var, initialized); /* We track only variables whose size is <= MAX_VAR_PARTS bytes thus there are at most MAX_VAR_PARTS different offsets. */ @@ -2160,6 +2512,12 @@ set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset) && REGNO (node->loc) == REGNO (loc)) || rtx_equal_p (node->loc, loc)) { + /* Save these values, to assign to the new node, before + deleting this one. */ + if (node->init > initialized) + initialized = node->init; + if (node->set_src != NULL && set_src == NULL) + set_src = node->set_src; pool_free (loc_chain_pool, node); *nextp = next; break; @@ -2169,8 +2527,10 @@ set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset) } /* Add the location to the beginning. */ - node = pool_alloc (loc_chain_pool); + node = (location_chain) pool_alloc (loc_chain_pool); node->loc = loc; + node->init = initialized; + node->set_src = set_src; node->next = var->var_part[pos].loc_chain; var->var_part[pos].loc_chain = node; @@ -2189,7 +2549,7 @@ set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset) static void clobber_variable_part (dataflow_set *set, rtx loc, tree decl, - HOST_WIDE_INT offset) + HOST_WIDE_INT offset, rtx set_src) { void **slot; @@ -2212,7 +2572,11 @@ clobber_variable_part (dataflow_set *set, rtx loc, tree decl, for (node = next; node; node = next) { next = node->next; - if (node->loc != loc) + if (node->loc != loc + && (!flag_var_tracking_uninit + || !set_src + || MEM_P (set_src) + || !rtx_equal_p (set_src, node->set_src))) { if (REG_P (node->loc)) { @@ -2233,6 +2597,8 @@ clobber_variable_part (dataflow_set *set, rtx loc, tree decl, pool_free (attrs_pool, anode); *anextp = anext; } + else + anextp = &anode->next; } } @@ -2277,7 +2643,10 @@ delete_variable_part (dataflow_set *set, rtx loc, tree decl, && REGNO (node->loc) == REGNO (loc)) || rtx_equal_p (node->loc, loc)) { - var = unshare_variable (set, var); + enum var_init_status status = VAR_INIT_STATUS_UNKNOWN; + if (! flag_var_tracking_uninit) + status = VAR_INIT_STATUS_INITIALIZED; + var = unshare_variable (set, var, status); break; } } @@ -2344,6 +2713,7 @@ emit_note_insn_var_location (void **varp, void *data) rtx note; int i, j, n_var_parts; bool complete; + enum var_init_status initialized = VAR_INIT_STATUS_UNINITIALIZED; HOST_WIDE_INT last_limit; tree type_size_unit; HOST_WIDE_INT offsets[MAX_VAR_PARTS]; @@ -2351,6 +2721,9 @@ emit_note_insn_var_location (void **varp, void *data) gcc_assert (var->decl); + if (! flag_var_tracking_uninit) + initialized = VAR_INIT_STATUS_INITIALIZED; + complete = true; last_limit = 0; n_var_parts = 0; @@ -2368,6 +2741,7 @@ emit_note_insn_var_location (void **varp, void *data) offsets[n_var_parts] = var->var_part[i].offset; loc[n_var_parts] = var->var_part[i].loc_chain->loc; mode = GET_MODE (loc[n_var_parts]); + initialized = var->var_part[i].loc_chain->init; last_limit = offsets[n_var_parts] + GET_MODE_SIZE (mode); /* Attempt to merge adjacent registers or memory. */ @@ -2388,8 +2762,7 @@ emit_note_insn_var_location (void **varp, void *data) if (REG_P (loc[n_var_parts]) && hard_regno_nregs[REGNO (loc[n_var_parts])][mode] * 2 == hard_regno_nregs[REGNO (loc[n_var_parts])][wider_mode] - && REGNO (loc[n_var_parts]) - + hard_regno_nregs[REGNO (loc[n_var_parts])][mode] + && end_hard_regno (mode, REGNO (loc[n_var_parts])) == REGNO (loc2)) { if (! WORDS_BIG_ENDIAN && ! BYTES_BIG_ENDIAN) @@ -2447,10 +2820,13 @@ emit_note_insn_var_location (void **varp, void *data) else note = emit_note_before (NOTE_INSN_VAR_LOCATION, insn); + if (! flag_var_tracking_uninit) + initialized = VAR_INIT_STATUS_INITIALIZED; + if (!complete) { NOTE_VAR_LOCATION (note) = gen_rtx_VAR_LOCATION (VOIDmode, var->decl, - NULL_RTX); + NULL_RTX, (int) initialized); } else if (n_var_parts == 1) { @@ -2458,7 +2834,8 @@ emit_note_insn_var_location (void **varp, void *data) = gen_rtx_EXPR_LIST (VOIDmode, loc[0], GEN_INT (offsets[0])); NOTE_VAR_LOCATION (note) = gen_rtx_VAR_LOCATION (VOIDmode, var->decl, - expr_list); + expr_list, + (int) initialized); } else if (n_var_parts) { @@ -2471,7 +2848,8 @@ emit_note_insn_var_location (void **varp, void *data) parallel = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (n_var_parts, loc)); NOTE_VAR_LOCATION (note) = gen_rtx_VAR_LOCATION (VOIDmode, var->decl, - parallel); + parallel, + (int) initialized); } htab_clear_slot (changed_variables, varp); @@ -2512,7 +2890,7 @@ emit_notes_for_differences_1 (void **slot, void *data) variable old_var, new_var; old_var = *(variable *) slot; - new_var = htab_find_with_hash (new_vars, old_var->decl, + new_var = (variable) htab_find_with_hash (new_vars, old_var->decl, VARIABLE_HASH_VAL (old_var->decl)); if (!new_var) @@ -2520,7 +2898,7 @@ emit_notes_for_differences_1 (void **slot, void *data) /* Variable has disappeared. */ variable empty_var; - empty_var = pool_alloc (var_pool); + empty_var = (variable) pool_alloc (var_pool); empty_var->decl = old_var->decl; empty_var->refcount = 1; empty_var->n_var_parts = 0; @@ -2545,7 +2923,7 @@ emit_notes_for_differences_2 (void **slot, void *data) variable old_var, new_var; new_var = *(variable *) slot; - old_var = htab_find_with_hash (old_vars, new_var->decl, + old_var = (variable) htab_find_with_hash (old_vars, new_var->decl, VARIABLE_HASH_VAL (new_var->decl)); if (!old_var) { @@ -2602,11 +2980,14 @@ emit_notes_in_bb (basic_block bb) case MO_USE: { rtx loc = VTI (bb)->mos[i].u.loc; - + + enum var_init_status status = VAR_INIT_STATUS_UNINITIALIZED; + if (! flag_var_tracking_uninit) + status = VAR_INIT_STATUS_INITIALIZED; if (GET_CODE (loc) == REG) - var_reg_set (&set, loc); + var_reg_set (&set, loc, status, NULL); else - var_mem_set (&set, loc); + var_mem_set (&set, loc, status, NULL); emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN); } @@ -2615,26 +2996,46 @@ emit_notes_in_bb (basic_block bb) case MO_SET: { rtx loc = VTI (bb)->mos[i].u.loc; + rtx set_src = NULL; + + if (GET_CODE (loc) == SET) + { + set_src = SET_SRC (loc); + loc = SET_DEST (loc); + } if (REG_P (loc)) - var_reg_delete_and_set (&set, loc, true); + var_reg_delete_and_set (&set, loc, true, VAR_INIT_STATUS_INITIALIZED, + set_src); else - var_mem_delete_and_set (&set, loc, true); + var_mem_delete_and_set (&set, loc, true, VAR_INIT_STATUS_INITIALIZED, + set_src); - emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN); + emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN); } break; case MO_COPY: { rtx loc = VTI (bb)->mos[i].u.loc; + enum var_init_status src_status; + rtx set_src = NULL; + + if (GET_CODE (loc) == SET) + { + set_src = SET_SRC (loc); + loc = SET_DEST (loc); + } + + src_status = find_src_status (&set, set_src); + set_src = find_src_set_src (&set, set_src); if (REG_P (loc)) - var_reg_delete_and_set (&set, loc, false); + var_reg_delete_and_set (&set, loc, false, src_status, set_src); else - var_mem_delete_and_set (&set, loc, false); + var_mem_delete_and_set (&set, loc, false, src_status, set_src); - emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN); + emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN); } break; @@ -2660,7 +3061,7 @@ emit_notes_in_bb (basic_block bb) else var_mem_delete (&set, loc, true); - emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN); + emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN); } break; @@ -2725,7 +3126,7 @@ vt_get_decl_and_offset (rtx rtl, tree *declp, HOST_WIDE_INT *offsetp) if (MEM_ATTRS (rtl)) { *declp = MEM_EXPR (rtl); - *offsetp = MEM_OFFSET (rtl) ? INTVAL (MEM_OFFSET (rtl)) : 0; + *offsetp = INT_MEM_OFFSET (rtl); return true; } } @@ -2745,6 +3146,7 @@ vt_add_function_parameters (void) rtx decl_rtl = DECL_RTL_IF_SET (parm); rtx incoming = DECL_INCOMING_RTL (parm); tree decl; + enum machine_mode mode; HOST_WIDE_INT offset; dataflow_set *out; @@ -2761,25 +3163,38 @@ vt_add_function_parameters (void) continue; if (!vt_get_decl_and_offset (incoming, &decl, &offset)) - if (!vt_get_decl_and_offset (decl_rtl, &decl, &offset)) - continue; + { + if (!vt_get_decl_and_offset (decl_rtl, &decl, &offset)) + continue; + offset += byte_lowpart_offset (GET_MODE (incoming), + GET_MODE (decl_rtl)); + } if (!decl) continue; gcc_assert (parm == decl); + if (!track_loc_p (incoming, parm, offset, false, &mode, &offset)) + continue; + out = &VTI (ENTRY_BLOCK_PTR)->out; if (REG_P (incoming)) { + incoming = var_lowpart (mode, incoming); gcc_assert (REGNO (incoming) < FIRST_PSEUDO_REGISTER); attrs_list_insert (&out->regs[REGNO (incoming)], parm, offset, incoming); - set_variable_part (out, incoming, parm, offset); + set_variable_part (out, incoming, parm, offset, VAR_INIT_STATUS_INITIALIZED, + NULL); } else if (MEM_P (incoming)) - set_variable_part (out, incoming, parm, offset); + { + incoming = var_lowpart (mode, incoming); + set_variable_part (out, incoming, parm, offset, + VAR_INIT_STATUS_INITIALIZED, NULL); + } } } @@ -2993,8 +3408,10 @@ gate_handle_var_tracking (void) -struct tree_opt_pass pass_variable_tracking = +struct rtl_opt_pass pass_variable_tracking = { + { + RTL_PASS, "vartrack", /* name */ gate_handle_var_tracking, /* gate */ variable_tracking_main, /* execute */ @@ -3006,7 +3423,7 @@ struct tree_opt_pass pass_variable_tracking = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_dump_func, /* todo_flags_finish */ - 'V' /* letter */ + TODO_dump_func | TODO_verify_rtl_sharing/* todo_flags_finish */ + } };