Index: gcc/defaults.h =================================================================== --- gcc/defaults.h (revision 124192) +++ gcc/defaults.h (working copy) @@ -796,6 +796,12 @@ #define TARGET_C99_FUNCTIONS 0 #endif +/* Determine whether gcc should output DWARF information about + uninitialized variables or not. */ +#ifndef TARGET_DWARF_UNINIT_VARS +#define TARGET_DWARF_UNINIT_VARS 0 +#endif + /* Determine whether the target runtime library has a sincos implementation following the GNU extension. */ #ifndef TARGET_HAS_SINCOS Index: gcc/rtl.def =================================================================== --- gcc/rtl.def (revision 124192) +++ gcc/rtl.def (working copy) @@ -670,7 +670,7 @@ DEF_RTL_EXPR(US_TRUNCATE, "us_truncate", "e", RTX_UNARY) /* Information about the variable and its location. */ -DEF_RTL_EXPR(VAR_LOCATION, "var_location", "te", RTX_EXTRA) +DEF_RTL_EXPR(VAR_LOCATION, "var_location", "tei", RTX_EXTRA) /* All expressions from this point forward appear only in machine descriptions. */ Index: gcc/dwarf2out.c =================================================================== --- gcc/dwarf2out.c (revision 124192) +++ gcc/dwarf2out.c (working copy) @@ -3116,6 +3116,8 @@ return "DW_OP_call_ref"; case DW_OP_GNU_push_tls_address: return "DW_OP_GNU_push_tls_address"; + case DW_OP_GNU_uninit: + return "DW_OP_GNU_uninit"; default: return "OP_"; } @@ -4163,15 +4165,20 @@ static int type_is_enum (tree); static unsigned int dbx_reg_number (rtx); static void add_loc_descr_op_piece (dw_loc_descr_ref *, int); -static dw_loc_descr_ref reg_loc_descriptor (rtx); -static dw_loc_descr_ref one_reg_loc_descriptor (unsigned int); -static dw_loc_descr_ref multiple_reg_loc_descriptor (rtx, rtx); +static dw_loc_descr_ref reg_loc_descriptor (rtx, enum var_init_status); +static dw_loc_descr_ref one_reg_loc_descriptor (unsigned int, + enum var_init_status); +static dw_loc_descr_ref multiple_reg_loc_descriptor (rtx, rtx, + enum var_init_status); static dw_loc_descr_ref int_loc_descriptor (HOST_WIDE_INT); -static dw_loc_descr_ref based_loc_descr (rtx, HOST_WIDE_INT); +static dw_loc_descr_ref based_loc_descr (rtx, HOST_WIDE_INT, + enum var_init_status); static int is_based_loc (rtx); -static dw_loc_descr_ref mem_loc_descriptor (rtx, enum machine_mode mode); -static dw_loc_descr_ref concat_loc_descriptor (rtx, rtx); -static dw_loc_descr_ref loc_descriptor (rtx); +static dw_loc_descr_ref mem_loc_descriptor (rtx, enum machine_mode mode, + enum var_init_status); +static dw_loc_descr_ref concat_loc_descriptor (rtx, rtx, + enum var_init_status); +static dw_loc_descr_ref loc_descriptor (rtx, enum var_init_status); static dw_loc_descr_ref loc_descriptor_from_tree_1 (tree, int); static dw_loc_descr_ref loc_descriptor_from_tree (tree); static HOST_WIDE_INT ceiling (HOST_WIDE_INT, unsigned int); @@ -5727,9 +5734,16 @@ if (temp->last) { /* If the current location is the same as the end of the list, + and either both or neither of the locations is uninitialized, we have nothing to do. */ - if (!rtx_equal_p (NOTE_VAR_LOCATION_LOC (temp->last->var_loc_note), - NOTE_VAR_LOCATION_LOC (loc->var_loc_note))) + if ((!rtx_equal_p (NOTE_VAR_LOCATION_LOC (temp->last->var_loc_note), + NOTE_VAR_LOCATION_LOC (loc->var_loc_note))) + || ((NOTE_VAR_LOCATION_STATUS (temp->last->var_loc_note) + != NOTE_VAR_LOCATION_STATUS (loc->var_loc_note)) + && ((NOTE_VAR_LOCATION_STATUS (temp->last->var_loc_note) + == STATUS_UNINITIALIZED) + || (NOTE_VAR_LOCATION_STATUS (loc->var_loc_note) + == STATUS_UNINITIALIZED)))) { /* Add LOC to the end of list and update LAST. */ temp->last->next = loc; @@ -7039,6 +7053,9 @@ for (curr = list_head; curr != NULL; curr = curr->dw_loc_next) { unsigned long size; + /* Don't output an entry that starts and ends at the same address. */ + if (strcmp (curr->begin, curr->end) == 0) + continue; if (!have_multiple_function_sections) { dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->begin, curr->section, @@ -8648,7 +8665,7 @@ zero if there is none. */ static dw_loc_descr_ref -reg_loc_descriptor (rtx rtl) +reg_loc_descriptor (rtx rtl, enum var_init_status initialized) { rtx regs; @@ -8658,28 +8675,35 @@ regs = targetm.dwarf_register_span (rtl); if (hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)] > 1 || regs) - return multiple_reg_loc_descriptor (rtl, regs); + return multiple_reg_loc_descriptor (rtl, regs, initialized); else - return one_reg_loc_descriptor (dbx_reg_number (rtl)); + return one_reg_loc_descriptor (dbx_reg_number (rtl), initialized); } /* Return a location descriptor that designates a machine register for a given hard register number. */ static dw_loc_descr_ref -one_reg_loc_descriptor (unsigned int regno) +one_reg_loc_descriptor (unsigned int regno, enum var_init_status initialized) { + dw_loc_descr_ref reg_loc_descr; if (regno <= 31) - return new_loc_descr (DW_OP_reg0 + regno, 0, 0); + reg_loc_descr = new_loc_descr (DW_OP_reg0 + regno, 0, 0); else - return new_loc_descr (DW_OP_regx, regno, 0); + reg_loc_descr = new_loc_descr (DW_OP_regx, regno, 0); + + if (initialized == STATUS_UNINITIALIZED) + add_loc_descr (®_loc_descr, new_loc_descr (DW_OP_GNU_uninit, 0, 0)); + + return reg_loc_descr; } /* Given an RTL of a register, return a location descriptor that designates a value that spans more than one register. */ static dw_loc_descr_ref -multiple_reg_loc_descriptor (rtx rtl, rtx regs) +multiple_reg_loc_descriptor (rtx rtl, rtx regs, + enum var_init_status initialized) { int nregs, size, i; unsigned reg; @@ -8707,7 +8731,8 @@ { dw_loc_descr_ref t; - t = one_reg_loc_descriptor (DBX_REGISTER_NUMBER (reg)); + t = one_reg_loc_descriptor (DBX_REGISTER_NUMBER (reg), + STATUS_UNINITIALIZED); add_loc_descr (&loc_result, t); add_loc_descr_op_piece (&loc_result, size); ++reg; @@ -8726,11 +8751,15 @@ { dw_loc_descr_ref t; - t = one_reg_loc_descriptor (REGNO (XVECEXP (regs, 0, i))); + t = one_reg_loc_descriptor (REGNO (XVECEXP (regs, 0, i)), + STATUS_INITIALIZED); add_loc_descr (&loc_result, t); size = GET_MODE_SIZE (GET_MODE (XVECEXP (regs, 0, 0))); add_loc_descr_op_piece (&loc_result, size); } + + if (loc_result && initialized == STATUS_UNINITIALIZED) + add_loc_descr (&loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0)); return loc_result; } @@ -8776,9 +8805,11 @@ /* Return a location descriptor that designates a base+offset location. */ static dw_loc_descr_ref -based_loc_descr (rtx reg, HOST_WIDE_INT offset) +based_loc_descr (rtx reg, HOST_WIDE_INT offset, + enum var_init_status initialized) { unsigned int regno; + dw_loc_descr_ref result; /* We only use "frame base" when we're sure we're talking about the post-prologue local stack frame. We do this by *not* running @@ -8805,9 +8836,14 @@ regno = dbx_reg_number (reg); if (regno <= 31) - return new_loc_descr (DW_OP_breg0 + regno, offset, 0); + result = new_loc_descr (DW_OP_breg0 + regno, offset, 0); else - return new_loc_descr (DW_OP_bregx, regno, offset); + result = new_loc_descr (DW_OP_bregx, regno, offset); + + if (initialized == STATUS_UNINITIALIZED) + add_loc_descr (&result, new_loc_descr (DW_OP_GNU_uninit, 0, 0)); + + return result; } /* Return true if this RTL expression describes a base+offset calculation. */ @@ -8825,7 +8861,8 @@ used to form the address of a memory location. */ static dw_loc_descr_ref -concatn_mem_loc_descriptor (rtx concatn, enum machine_mode mode) +concatn_mem_loc_descriptor (rtx concatn, enum machine_mode mode, + enum var_init_status initialized) { unsigned int i; dw_loc_descr_ref cc_loc_result = NULL; @@ -8836,7 +8873,7 @@ dw_loc_descr_ref ref; rtx x = XVECEXP (concatn, 0, i); - ref = mem_loc_descriptor (x, mode); + ref = mem_loc_descriptor (x, mode, STATUS_INITIALIZED); if (ref == NULL) return NULL; @@ -8844,6 +8881,9 @@ add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x))); } + if (cc_loc_result && initialized == STATUS_UNINITIALIZED) + add_loc_descr (&cc_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0)); + return cc_loc_result; } @@ -8866,7 +8906,8 @@ Return 0 if we can't represent the location. */ static dw_loc_descr_ref -mem_loc_descriptor (rtx rtl, enum machine_mode mode) +mem_loc_descriptor (rtx rtl, enum machine_mode mode, + enum var_init_status initialized) { dw_loc_descr_ref mem_loc_result = NULL; enum dwarf_location_atom op; @@ -8913,11 +8954,12 @@ memory) so DWARF consumers need to be aware of the subtle distinction between OP_REG and OP_BASEREG. */ if (REGNO (rtl) < FIRST_PSEUDO_REGISTER) - mem_loc_result = based_loc_descr (rtl, 0); + mem_loc_result = based_loc_descr (rtl, 0, STATUS_INITIALIZED); break; case MEM: - mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl)); + mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl), + STATUS_INITIALIZED); if (mem_loc_result != 0) add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0)); break; @@ -8984,10 +9026,12 @@ plus: if (is_based_loc (rtl)) mem_loc_result = based_loc_descr (XEXP (rtl, 0), - INTVAL (XEXP (rtl, 1))); + INTVAL (XEXP (rtl, 1)), + STATUS_INITIALIZED); else { - mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode); + mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode, + STATUS_INITIALIZED); if (mem_loc_result == 0) break; @@ -8999,7 +9043,8 @@ else { add_loc_descr (&mem_loc_result, - mem_loc_descriptor (XEXP (rtl, 1), mode)); + mem_loc_descriptor (XEXP (rtl, 1), mode, + STATUS_INITIALIZED)); add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_plus, 0, 0)); } @@ -9026,8 +9071,10 @@ do_binop: { - dw_loc_descr_ref op0 = mem_loc_descriptor (XEXP (rtl, 0), mode); - dw_loc_descr_ref op1 = mem_loc_descriptor (XEXP (rtl, 1), mode); + dw_loc_descr_ref op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, + STATUS_INITIALIZED); + dw_loc_descr_ref op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, + STATUS_INITIALIZED); if (op0 == 0 || op1 == 0) break; @@ -9043,13 +9090,17 @@ break; case CONCATN: - mem_loc_result = concatn_mem_loc_descriptor (rtl, mode); + mem_loc_result = concatn_mem_loc_descriptor (rtl, mode, + STATUS_INITIALIZED); break; default: gcc_unreachable (); } + if (mem_loc_result && initialized == STATUS_UNINITIALIZED) + add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0)); + return mem_loc_result; } @@ -9057,11 +9108,11 @@ This is typically a complex variable. */ static dw_loc_descr_ref -concat_loc_descriptor (rtx x0, rtx x1) +concat_loc_descriptor (rtx x0, rtx x1, enum var_init_status initialized) { dw_loc_descr_ref cc_loc_result = NULL; - dw_loc_descr_ref x0_ref = loc_descriptor (x0); - dw_loc_descr_ref x1_ref = loc_descriptor (x1); + dw_loc_descr_ref x0_ref = loc_descriptor (x0, STATUS_INITIALIZED); + dw_loc_descr_ref x1_ref = loc_descriptor (x1, STATUS_INITIALIZED); if (x0_ref == 0 || x1_ref == 0) return 0; @@ -9072,6 +9123,9 @@ add_loc_descr (&cc_loc_result, x1_ref); add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x1))); + if (initialized == STATUS_UNINITIALIZED) + add_loc_descr (&cc_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0)); + return cc_loc_result; } @@ -9079,7 +9133,7 @@ locations. */ static dw_loc_descr_ref -concatn_loc_descriptor (rtx concatn) +concatn_loc_descriptor (rtx concatn, enum var_init_status initialized) { unsigned int i; dw_loc_descr_ref cc_loc_result = NULL; @@ -9090,7 +9144,7 @@ dw_loc_descr_ref ref; rtx x = XVECEXP (concatn, 0, i); - ref = loc_descriptor (x); + ref = loc_descriptor (x, STATUS_INITIALIZED); if (ref == NULL) return NULL; @@ -9098,6 +9152,9 @@ add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x))); } + if (cc_loc_result && initialized == STATUS_UNINITIALIZED) + add_loc_descr (&cc_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0)); + return cc_loc_result; } @@ -9110,7 +9167,7 @@ If we don't know how to describe it, return 0. */ static dw_loc_descr_ref -loc_descriptor (rtx rtl) +loc_descriptor (rtx rtl, enum var_init_status initialized) { dw_loc_descr_ref loc_result = NULL; @@ -9127,26 +9184,28 @@ /* ... fall through ... */ case REG: - loc_result = reg_loc_descriptor (rtl); + loc_result = reg_loc_descriptor (rtl, initialized); break; case MEM: - loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl)); + loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl), + initialized); break; case CONCAT: - loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1)); + loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1), + initialized); break; case CONCATN: - loc_result = concatn_loc_descriptor (rtl); + loc_result = concatn_loc_descriptor (rtl, initialized); break; case VAR_LOCATION: /* Single part. */ if (GET_CODE (XEXP (rtl, 1)) != PARALLEL) { - loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0)); + loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0), initialized); break; } @@ -9161,14 +9220,16 @@ int i; /* Create the first one, so we have something to add to. */ - loc_result = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0)); + loc_result = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0), + initialized); mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, 0), 0)); add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode)); for (i = 1; i < num_elem; i++) { dw_loc_descr_ref temp; - temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0)); + temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0), + initialized); add_loc_descr (&loc_result, temp); mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, i), 0)); add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode)); @@ -9300,7 +9361,7 @@ /* Certain constructs can only be represented at top-level. */ if (want_address == 2) - return loc_descriptor (rtl); + return loc_descriptor (rtl, STATUS_INITIALIZED); mode = GET_MODE (rtl); if (MEM_P (rtl)) @@ -9308,7 +9369,7 @@ rtl = XEXP (rtl, 0); have_address = 1; } - ret = mem_loc_descriptor (rtl, mode); + ret = mem_loc_descriptor (rtl, mode, STATUS_INITIALIZED); } } break; @@ -9389,7 +9450,7 @@ return 0; mode = GET_MODE (rtl); rtl = XEXP (rtl, 0); - ret = mem_loc_descriptor (rtl, mode); + ret = mem_loc_descriptor (rtl, mode, STATUS_INITIALIZED); have_address = 1; break; } @@ -10475,6 +10536,7 @@ const char *endname, *secname; dw_loc_list_ref list; rtx varloc; + enum var_init_status initialized; /* Now that we know what section we are using for a base, actually construct the list of locations. @@ -10491,7 +10553,12 @@ varloc = NOTE_VAR_LOCATION (node->var_loc_note); secname = secname_for_decl (decl); - list = new_loc_list (loc_descriptor (varloc), + if (NOTE_VAR_LOCATION_LOC (node->var_loc_note)) + initialized = NOTE_VAR_LOCATION_STATUS (node->var_loc_note); + else + initialized = STATUS_INITIALIZED; + + list = new_loc_list (loc_descriptor (varloc, initialized), node->label, node->next->label, secname, 1); node = node->next; @@ -10500,8 +10567,11 @@ { /* The variable has a location between NODE->LABEL and NODE->NEXT->LABEL. */ + enum var_init_status initialized = + NOTE_VAR_LOCATION_STATUS (node->var_loc_note); varloc = NOTE_VAR_LOCATION (node->var_loc_note); - add_loc_descr_to_loc_list (&list, loc_descriptor (varloc), + add_loc_descr_to_loc_list (&list, + loc_descriptor (varloc, initialized), node->label, node->next->label, secname); } @@ -10510,6 +10580,8 @@ if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX) { char label_id[MAX_ARTIFICIAL_LABEL_BYTES]; + enum var_init_status initialized = + NOTE_VAR_LOCATION_STATUS (node->var_loc_note); varloc = NOTE_VAR_LOCATION (node->var_loc_note); if (!current_function_decl) @@ -10520,7 +10592,8 @@ current_function_funcdef_no); endname = ggc_strdup (label_id); } - add_loc_descr_to_loc_list (&list, loc_descriptor (varloc), + add_loc_descr_to_loc_list (&list, + loc_descriptor (varloc, initialized), node->label, endname, secname); } @@ -10544,8 +10617,10 @@ location list, try generating a location from that. */ if (loc_list && loc_list->first) { + enum var_init_status status; node = loc_list->first; - descr = loc_descriptor (NOTE_VAR_LOCATION (node->var_loc_note)); + status = NOTE_VAR_LOCATION_STATUS (node->var_loc_note); + descr = loc_descriptor (NOTE_VAR_LOCATION (node->var_loc_note), status); if (descr) { add_AT_location_description (die, attr, descr); Index: gcc/dwarf2.h =================================================================== --- gcc/dwarf2.h (revision 124192) +++ gcc/dwarf2.h (working copy) @@ -540,6 +540,7 @@ DW_OP_bit_piece = 0x9d, /* GNU extensions. */ DW_OP_GNU_push_tls_address = 0xe0, + DW_OP_GNU_uninit = 0xf0, /* HP extensions. */ DW_OP_HP_unknown = 0xe0, /* Ouch, the same as GNU_push_tls_address. */ DW_OP_HP_is_value = 0xe1, Index: gcc/print-rtl.c =================================================================== --- gcc/print-rtl.c (revision 124192) +++ gcc/print-rtl.c (working copy) @@ -325,6 +325,8 @@ print_mem_expr (outfile, NOTE_VAR_LOCATION_DECL (in_rtx)); fprintf (outfile, " "); print_rtx (NOTE_VAR_LOCATION_LOC (in_rtx)); + if (NOTE_VAR_LOCATION_STATUS (in_rtx) == STATUS_UNINITIALIZED) + fprintf (outfile, " [uninit]"); fprintf (outfile, ")"); #endif break; Index: gcc/rtl.h =================================================================== --- gcc/rtl.h (revision 124192) +++ gcc/rtl.h (working copy) @@ -868,6 +868,16 @@ #define NOTE_VAR_LOCATION_LOC(INSN) (XCEXP (XCEXP (INSN, 4, NOTE), \ 1, VAR_LOCATION)) +#define NOTE_VAR_LOCATION_STATUS(INSN) (XCINT (XCEXP (INSN, 4, NOTE), \ + 2, VAR_LOCATION)) + +enum var_init_status +{ + STATUS_UNKNOWN, + STATUS_UNINITIALIZED, + STATUS_INITIALIZED +}; + /* Codes that appear in the NOTE_LINE_NUMBER field for kinds of notes that are not line numbers. These codes are all negative. Index: gcc/var-tracking.c =================================================================== --- gcc/var-tracking.c (revision 124192) +++ gcc/var-tracking.c (working copy) @@ -219,6 +219,12 @@ /* 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. */ @@ -294,16 +300,19 @@ 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); @@ -338,8 +347,10 @@ 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); @@ -727,7 +738,8 @@ /* 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; @@ -752,6 +764,14 @@ new_lc = 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 +839,8 @@ /* 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,9 +853,44 @@ 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); } + +/* Lookup the variable described by DECL in SET, and return its initialization + status for location LOC. */ + +static int +get_init_value (dataflow_set *set, rtx loc, tree decl) +{ + void **slot; + variable var; + int i; + int ret_val = STATUS_UNKNOWN; + + if (! TARGET_DWARF_UNINIT_VARS) + return 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 == 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 the register to contain REG_EXPR (LOC), REG_OFFSET (LOC). If MODIFY is true, any other live copies of the same variable part are @@ -843,7 +899,8 @@ 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 +909,9 @@ decl = var_debug_decl (decl); + if (initialized == STATUS_UNKNOWN) + initialized = get_init_value (set, loc, decl); + nextp = &set->regs[REGNO (loc)]; for (node = *nextp; node; node = next) { @@ -869,8 +929,8 @@ } } 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 +950,7 @@ 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 +984,15 @@ 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; 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 +1003,20 @@ 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; decl = var_debug_decl (decl); + if (initialized == 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 @@ -966,7 +1031,7 @@ 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); } @@ -1078,7 +1143,14 @@ } } if (k < src->n_var_parts) - unshare_variable (set, src); + { + enum var_init_status status = STATUS_UNKNOWN; + + if (! TARGET_DWARF_UNINIT_VARS) + status = STATUS_INITIALIZED; + + unshare_variable (set, src, status); + } else *dstp = src; @@ -1112,7 +1184,13 @@ 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 = STATUS_UNKNOWN; + + if (! TARGET_DWARF_UNINIT_VARS) + status = STATUS_INITIALIZED; + dst = unshare_variable (set, dst, status); + } i = src->n_var_parts - 1; j = dst->n_var_parts - 1; @@ -1145,10 +1223,12 @@ && REG_P (node->loc) && REGNO (node2->loc) == REGNO (node->loc)) || rtx_equal_p (node2->loc, node->loc))) + if (node2->init < node->init) + node2->init = node->init; break; } if (node || node2) - dst = unshare_variable (set, dst); + dst = unshare_variable (set, dst, STATUS_UNKNOWN); } src_l = 0; @@ -1194,6 +1274,11 @@ /* Copy the location from SRC. */ new_node = 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; @@ -1240,6 +1325,11 @@ new_lc = 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 +1348,18 @@ 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; } @@ -1679,7 +1781,7 @@ else mo->type = MO_SET; mo->u.loc = loc; - mo->insn = NEXT_INSN ((rtx) insn); + mo->insn = (rtx) insn; } else if (MEM_P (loc) && MEM_EXPR (loc) @@ -1700,10 +1802,109 @@ else mo->type = MO_SET; mo->u.loc = loc; - mo->insn = NEXT_INSN ((rtx) insn); + mo->insn = (rtx) insn; } } +/* Given a dataflow_set IN, a location LOC, and an instruction INSN that + supposedly assigns a value to loc, find the piece of the instruction + that is being assigned to LOC, check to see if it's a variable (decl), + and if so, look up and return its initialization status.*/ + +static enum var_init_status +find_src_status (dataflow_set *in, rtx loc, rtx insn) +{ + rtx src = NULL_RTX; + tree decl = NULL_TREE; + enum var_init_status status = STATUS_UNINITIALIZED; + + if (! TARGET_DWARF_UNINIT_VARS) + status = STATUS_INITIALIZED; + + if (GET_CODE (PATTERN (insn)) == SET) + src = SET_SRC (PATTERN (insn)); + else if (GET_CODE (PATTERN (insn)) == PARALLEL + || GET_CODE (PATTERN (insn)) == SEQUENCE) + { + int i; + for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--) + if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET + && SET_DEST (XVECEXP (PATTERN (insn), 0, i)) == loc) + src = SET_SRC (XVECEXP (PATTERN (insn), 0, i)); + } + + if (REG_P (src)) + decl = var_debug_decl (REG_EXPR (src)); + else if (MEM_P (src)) + decl = var_debug_decl (MEM_EXPR (src)); + + if (src && decl) + status = get_init_value (in, src, decl); + + return status; +} + +/* Given an assignment instruction (INSN) and an assignment destination + (LOC), find the piece of INSN that is being assigned to LOC. If it + corresponds to a variable (decl), look up the variable in SET and + return *its* set_src. + + In other words, (using 'set_src' as short hand for 'the value assigned + to'), look up and return the set_src of the variable being assigned + to LOC. */ + +static rtx +find_src_set_src (dataflow_set *set, rtx loc, rtx insn) +{ + tree decl = NULL_TREE; /* The variable being copied around. */ + rtx src = NULL_RTX; /* The location "decl" is being copied from. */ + rtx set_src = NULL_RTX; /* The value for "decl" stored in "src". */ + void **slot; + variable var; + location_chain nextp; + int i; + bool found; + + if (GET_CODE (PATTERN (insn)) == SET) + src = SET_SRC (PATTERN (insn)); + else if (GET_CODE (PATTERN (insn)) == PARALLEL + || GET_CODE (PATTERN (insn)) == SEQUENCE) + { + for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--) + if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET + && SET_DEST (XVECEXP (PATTERN (insn), 0, i)) == loc) + src = SET_SRC (XVECEXP (PATTERN (insn), 0, i)); + } + + if (REG_P (src)) + decl = var_debug_decl (REG_EXPR (src)); + else if (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 @@ -1733,33 +1934,65 @@ case MO_USE: { rtx loc = VTI (bb)->mos[i].u.loc; + enum var_init_status status = STATUS_UNINITIALIZED; + if (! TARGET_DWARF_UNINIT_VARS) + status = 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; + rtx insn = VTI (bb)->mos[i].insn; + if (GET_CODE (PATTERN (insn)) == SET) + set_src = SET_SRC (PATTERN (insn)); + else if (GET_CODE (PATTERN (insn)) == PARALLEL + || GET_CODE (PATTERN (insn)) == SEQUENCE) + { + int j; + for (j = XVECLEN (PATTERN (insn), 0) - 1; j >= 0; j--) + if (GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == SET + && SET_DEST (XVECEXP (PATTERN (insn), 0, j)) == loc) + set_src = SET_SRC (XVECEXP (PATTERN (insn), 0, j)); + } + if (REG_P (loc)) - var_reg_delete_and_set (out, loc, true); + var_reg_delete_and_set (out, loc, true, 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, 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; + if (! TARGET_DWARF_UNINIT_VARS) + src_status = STATUS_INITIALIZED; + else + src_status = find_src_status (in, loc, VTI (bb)->mos[i].insn); + + if (src_status == STATUS_UNKNOWN) + src_status = find_src_status (out, loc, VTI (bb)->mos[i].insn); + + set_src = find_src_set_src (in, loc, VTI (bb)->mos[i].insn); + 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; @@ -1932,6 +2165,8 @@ for (node = var->var_part[i].loc_chain; node; node = node->next) { fprintf (dump_file, " "); + if (node->init == STATUS_UNINITIALIZED) + fprintf (dump_file, "[uninit]"); print_rtl_single (dump_file, node->loc); } } @@ -2077,7 +2312,8 @@ 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; @@ -2119,13 +2355,19 @@ { /* 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 @@ -2134,7 +2376,7 @@ /* 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. */ @@ -2161,6 +2403,12 @@ && 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; @@ -2172,6 +2420,8 @@ /* Add the location to the beginning. */ node = 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; @@ -2190,7 +2440,7 @@ 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; @@ -2213,7 +2463,11 @@ for (node = next; node; node = next) { next = node->next; - if (node->loc != loc) + if (node->loc != loc + && (!(TARGET_DWARF_UNINIT_VARS) + || !set_src + || MEM_P (set_src) + || !rtx_equal_p (set_src, node->set_src))) { if (REG_P (node->loc)) { @@ -2278,7 +2532,10 @@ && REGNO (node->loc) == REGNO (loc)) || rtx_equal_p (node->loc, loc)) { - var = unshare_variable (set, var); + enum var_init_status status = STATUS_UNKNOWN; + if (! TARGET_DWARF_UNINIT_VARS) + status = STATUS_INITIALIZED; + var = unshare_variable (set, var, status); break; } } @@ -2345,6 +2602,7 @@ rtx note; int i, j, n_var_parts; bool complete; + enum var_init_status initialized = STATUS_UNINITIALIZED; HOST_WIDE_INT last_limit; tree type_size_unit; HOST_WIDE_INT offsets[MAX_VAR_PARTS]; @@ -2352,6 +2610,9 @@ gcc_assert (var->decl); + if (! TARGET_DWARF_UNINIT_VARS) + initialized = STATUS_INITIALIZED; + complete = true; last_limit = 0; n_var_parts = 0; @@ -2369,6 +2630,7 @@ 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. */ @@ -2448,10 +2710,13 @@ else note = emit_note_before (NOTE_INSN_VAR_LOCATION, insn); + if (!(TARGET_DWARF_UNINIT_VARS)) + initialized = STATUS_INITIALIZED; + if (!complete) { NOTE_VAR_LOCATION (note) = gen_rtx_VAR_LOCATION (VOIDmode, var->decl, - NULL_RTX); + NULL_RTX, 0); } else if (n_var_parts == 1) { @@ -2459,7 +2724,8 @@ = 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) { @@ -2472,9 +2738,12 @@ 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); } + NOTE_VAR_LOCATION_STATUS (note) = (int) initialized; + htab_clear_slot (changed_variables, varp); /* When there are no location parts the variable has been already @@ -2603,11 +2872,14 @@ case MO_USE: { rtx loc = VTI (bb)->mos[i].u.loc; - + + enum var_init_status status = STATUS_UNINITIALIZED; + if (! TARGET_DWARF_UNINIT_VARS) + status = 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); } @@ -2616,26 +2888,46 @@ case MO_SET: { rtx loc = VTI (bb)->mos[i].u.loc; + rtx set_src = NULL; + if (GET_CODE (PATTERN (insn)) == SET) + set_src = SET_SRC (PATTERN (insn)); + else if (GET_CODE (PATTERN (insn)) == PARALLEL + || GET_CODE (PATTERN (insn)) == SEQUENCE) + { + int j; + for (j = XVECLEN (PATTERN (insn), 0) - 1; j >= 0; j--) + if (GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == SET + && SET_DEST (XVECEXP (PATTERN (insn), 0, j)) == loc) + set_src = SET_SRC (XVECEXP (PATTERN (insn), 0, j)); + } + if (REG_P (loc)) - var_reg_delete_and_set (&set, loc, true); + var_reg_delete_and_set (&set, loc, true, STATUS_INITIALIZED, + set_src); else - var_mem_delete_and_set (&set, loc, true); + var_mem_delete_and_set (&set, loc, true, 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; + src_status = find_src_status (&set, loc, VTI (bb)->mos[i].insn); + set_src = find_src_set_src (&set, loc, VTI (bb)->mos[i].insn); + 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; @@ -2661,7 +2953,7 @@ 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; @@ -2777,10 +3069,12 @@ 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, STATUS_INITIALIZED, + NULL); } else if (MEM_P (incoming)) - set_variable_part (out, incoming, parm, offset); + set_variable_part (out, incoming, parm, offset, STATUS_INITIALIZED, + NULL); } } Index: gcc/config/i386/linux.h =================================================================== --- gcc/config/i386/linux.h (revision 124192) +++ gcc/config/i386/linux.h (working copy) @@ -195,3 +195,6 @@ /* i386 glibc provides __stack_chk_guard in %gs:0x14. */ #define TARGET_THREAD_SSP_OFFSET 0x14 #endif + +#undef TARGET_DWARF_UNINIT_VARS +#define TARGET_DWARF_UNINIT_VARS 1 Index: gcc/config/darwin.h =================================================================== --- gcc/config/darwin.h (revision 124192) +++ gcc/config/darwin.h (working copy) @@ -984,4 +984,8 @@ #define TARGET_HAS_TARGETCM 1 +#undef TARGET_DWARF_UNINIT_VARS +#define TARGET_DWARF_UNINIT_VARS \ + (strverscmp (darwin_macosx_version_min, "10.5") >= 0) + #endif /* CONFIG_DARWIN_H */