diff options
author | ctice <ctice@138bc75d-0d04-0410-961f-82ee72b054a4> | 2007-07-13 23:11:15 +0000 |
---|---|---|
committer | ctice <ctice@138bc75d-0d04-0410-961f-82ee72b054a4> | 2007-07-13 23:11:15 +0000 |
commit | d53bb22673261b227d5045c435bd2acd4c87c236 (patch) | |
tree | b87516d5c9ea7c2c70b26f837f1dada3f4c4d0f0 /gcc | |
parent | aa9311a1b831d7e2f0575a09def64eff0dac9f6a (diff) | |
download | gcc-d53bb22673261b227d5045c435bd2acd4c87c236.tar.gz |
Add ability to track uninitialized variables, and mark uninitialized
variables in the Dwarf debug info. Controlled by compile option
-fvar-tracking-uninit
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@126630 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 99 | ||||
-rw-r--r-- | gcc/common.opt | 4 | ||||
-rw-r--r-- | gcc/config/darwin.c | 3 | ||||
-rw-r--r-- | gcc/dwarf2.h | 2 | ||||
-rw-r--r-- | gcc/dwarf2out.c | 179 | ||||
-rw-r--r-- | gcc/print-rtl.c | 3 | ||||
-rw-r--r-- | gcc/rtl.def | 4 | ||||
-rw-r--r-- | gcc/rtl.h | 16 | ||||
-rw-r--r-- | gcc/toplev.c | 10 | ||||
-rw-r--r-- | gcc/var-tracking.c | 382 |
10 files changed, 596 insertions, 106 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6aeca7e06b9..01c0bdb3353 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,102 @@ +2007-07-13 Caroline Tice <ctice@apple.com> + + * toplev.c (process_options): Turn flag_var_tracking_uninit off when + flag_var_tracking is explicitly turned off (i.e. when variable + tracking is not feasible); otherwise, turn flag_var_tracking on when + flag_var_tracking_uninit is on. + * rtl.def (VAR_LOCATION): Add a new integer subfield to VAR_LOCATION + note definitions, to allow recording of initialization status in the + notes. + * dwarf2out.c (dwarf_stack_op_name): Add case for DW_OP_GNU_uninit. + (add_var_loc_to_decl): Add comparison of NOTE_VAR_LOCATION_STATUS to + determine if two note locations are equal. + (output_loc_list): Don't output list entries whose start & end labels + are the same. + (reg_loc_descriptor): Add parameter for initialization status; pass it + to other loc descriptor functions. + (one_reg_loc_descriptor): Add parameter for initialization status; + check its value and add DW_OP_GNU_uninit to returned loc descr if + appropriate. + (multiple_reg_loc_descriptor): Add parameter for initialization + status; + pass init status argument to other loc descriptor functions; check + value of intialization parameter and add DW_OP_GNU_uninit to returned + loc descr if appropriate. + (based_loc_descr): Add parameter for initialization status; add new + variable for return value; check value of initialization parameter and + add DW_OP_GNU_uninit to returned loc descr if appropriate. + (concatn_mem_loc_descriptor): Add parameter for initialization status; + pass init status argument to other loc descriptor functions; check + value of intialization parameter and add DW_OP_GNU_uninit to returned + loc descr if appropriate. + (mem_loc_descriptor): Likewise. + (concat_loc_descriptor): Likewise. + (concatn_loc_descriptor): Likewise. + (loc_descriptor): Add parameter for initialization status; pass it as + argument to other loc descriptor function calls. + (loc_descriptor_from_tree_1): Add appropriate initialization status + to loc descriptor function calls. + (add_location_or_const_value_attribute): Get initialization status + from VAR_LOCATION note; add initialization status to loc descriptor + function calls. + * dwarf2.h (enum dwarf_location_atom): New op, DW_OP_GNU_uninit. + * print-rtl.c (print_rtx): When printing a VAR_LOCATION note, if + status is uninitialized, add "[uninint]" to output. + * common.opt (fvar-tracking-uninit): New option, similar to + fvar-tracking, to turn on tracking of uninitialized variables; creates + a new global flag, flag_var_tracking_uninit. + * rtl.h (NOTE_VAR_LOCATION_STATUS): New macro for accessing new field. + (enum var_init_status): New type, for var initialization status field. + * var-tracking.c (struct location_chain_def): Two new fields, init, + for initialization status, and set_src for the assignment value expr. + (unshare_variable): New parameter for initialization status; + initialize new init and set_src fields. + (var_reg_set): New parameters for initialization status and value; + pass them to set_variable_part. + (var_mem_set): Likewise. + (get_init_value): New function. + (var_reg_delete_and_set): New initialization status & value + parameters; add call to get_init_value if status is unknown; pass new + parameters to clobber_variable_part and var_reg_set. + (var_mem_delete_and_set): Likewise. + (var_reg_delete): Pass null set_src value to clobber_variable_part. + (var_mem_delete): Likewise. + (variable_union): Pass status to unshare_variable; initialize new init + and set_src fields. If flag_var_tracking_uninit is not set, force + status to initialized. + (add_stores): Store insn, rather than NEXT_INSN(insn), so it can be + used later to get the set_src value. + (find_src_status): New function. + (find_src_set_src): New function. + (compute_bb_dataflow): Pass init status to calls to var_reg_set, + var_mem_set, var_reg_delete_and_set and var_mem_delete_and_set; for + MO_SET, get set_src value and pass it to var_reg_delete_and_set + and var_mem_delete_and_set. + (dump_variable): Print out "[uninit]" if appropriate. + (set_variable_part): Add new initialization and set_src parameters; + pass status to unshare_variable; set node->init and node- >set_src + fields and modify slot in hash table appropriately; save the init and + set_src values if appropriate and assign to the new node. + (clobber_variable_part): New set_src parameter; if two nodes have + same variable and same location but different set_src (assignment) + values, clobber old node. + (delete_variable_part): Pass init status to unshare_variable. + (emit_note_insn_var_location): Add initialized var; assign var's init + status to new 'initialized'; pass new init status field to calls to + gen_rtx_VAR_LOCATION. If flag_var_tracking_uninit is not set, force + status to initialized. + (emit_notes_in_bb): Pass initialization status to calls to + var_reg_set, var_mem_set, var_reg_delete_and_set and + var_mem_delete_and_set; for MO_SET, get set_src value and pass it to + var_reg_delete_and_set and var_mem_delete_and_set; call + emit_notes_for_changes on NEXT_INSN(insn) rather than on insn, to + make up for change in add_stores. + (vt_add_function_parameters): Add status to calls to + set_variable_part. + * config/darwin.c (darwin_override_options): Turn on uninitialized + tracking automatically, if var_tracking is on and the system is + 10.5 or higher. + 2007-07-13 Sa Liu <saliu@de.ibm.com> * config.gcc: Add options for arch and tune on SPU. diff --git a/gcc/common.opt b/gcc/common.opt index dfbbf92f10a..a37d3fcdd1d 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -1130,6 +1130,10 @@ fvar-tracking Common Report Var(flag_var_tracking) VarExists Optimization Perform variable tracking +fvar-tracking-uninit +Common Report Var(flag_var_tracking_uninit) Optimization +Perform variable tracking and also tag variables that are uninitialized + ftree-vectorize Common Report Var(flag_tree_vectorize) Optimization Enable loop vectorization on trees diff --git a/gcc/config/darwin.c b/gcc/config/darwin.c index 9d703da70a1..0673915200f 100644 --- a/gcc/config/darwin.c +++ b/gcc/config/darwin.c @@ -1728,6 +1728,9 @@ darwin_override_options (void) /* No -fnon-call-exceptions data in kexts. */ flag_non_call_exceptions = 0; } + if (flag_var_tracking + && strverscmp (darwin_macosx_version_min, "10.5") >= 0) + flag_var_tracking_uninit = 1; } #include "gt-darwin.h" diff --git a/gcc/dwarf2.h b/gcc/dwarf2.h index 31188372787..ac0b3ba1a97 100644 --- a/gcc/dwarf2.h +++ b/gcc/dwarf2.h @@ -540,6 +540,8 @@ enum dwarf_location_atom DW_OP_bit_piece = 0x9d, /* GNU extensions. */ DW_OP_GNU_push_tls_address = 0xe0, + /* The following is for marking variables that are uninitialized. */ + 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, diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index a54e517dc21..974419ffa75 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -3125,6 +3125,8 @@ dwarf_stack_op_name (unsigned int op) 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_<unknown>"; } @@ -4193,15 +4195,20 @@ static dw_die_ref modified_type_die (tree, int, int, dw_die_ref); 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); @@ -5757,9 +5764,16 @@ add_var_loc_to_decl (tree decl, struct var_loc_node *loc) 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) + == VAR_INIT_STATUS_UNINITIALIZED) + || (NOTE_VAR_LOCATION_STATUS (loc->var_loc_note) + == VAR_INIT_STATUS_UNINITIALIZED)))) { /* Add LOC to the end of list and update LAST. */ temp->last->next = loc; @@ -7069,6 +7083,9 @@ output_loc_list (dw_loc_list_ref list_head) 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, @@ -8747,7 +8764,7 @@ add_loc_descr_op_piece (dw_loc_descr_ref *list_head, int size) 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; @@ -8757,28 +8774,35 @@ reg_loc_descriptor (rtx rtl) 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 == VAR_INIT_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; @@ -8806,7 +8830,8 @@ multiple_reg_loc_descriptor (rtx rtl, rtx regs) { dw_loc_descr_ref t; - t = one_reg_loc_descriptor (DBX_REGISTER_NUMBER (reg)); + t = one_reg_loc_descriptor (DBX_REGISTER_NUMBER (reg), + VAR_INIT_STATUS_INITIALIZED); add_loc_descr (&loc_result, t); add_loc_descr_op_piece (&loc_result, size); ++reg; @@ -8825,11 +8850,15 @@ multiple_reg_loc_descriptor (rtx rtl, rtx regs) { 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)), + VAR_INIT_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 == VAR_INIT_STATUS_UNINITIALIZED) + add_loc_descr (&loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0)); return loc_result; } @@ -8875,9 +8904,11 @@ int_loc_descriptor (HOST_WIDE_INT i) /* 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 @@ -8904,9 +8935,14 @@ based_loc_descr (rtx reg, HOST_WIDE_INT offset) 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 == VAR_INIT_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. */ @@ -8924,7 +8960,8 @@ is_based_loc (rtx rtl) 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; @@ -8935,7 +8972,7 @@ concatn_mem_loc_descriptor (rtx concatn, enum machine_mode mode) dw_loc_descr_ref ref; rtx x = XVECEXP (concatn, 0, i); - ref = mem_loc_descriptor (x, mode); + ref = mem_loc_descriptor (x, mode, VAR_INIT_STATUS_INITIALIZED); if (ref == NULL) return NULL; @@ -8943,6 +8980,9 @@ concatn_mem_loc_descriptor (rtx concatn, enum machine_mode mode) add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x))); } + if (cc_loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED) + add_loc_descr (&cc_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0)); + return cc_loc_result; } @@ -8965,7 +9005,8 @@ concatn_mem_loc_descriptor (rtx concatn, enum machine_mode mode) 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; @@ -9012,11 +9053,12 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode) 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, VAR_INIT_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), + VAR_INIT_STATUS_INITIALIZED); if (mem_loc_result != 0) add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0)); break; @@ -9083,10 +9125,12 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode) plus: if (is_based_loc (rtl)) mem_loc_result = based_loc_descr (XEXP (rtl, 0), - INTVAL (XEXP (rtl, 1))); + INTVAL (XEXP (rtl, 1)), + VAR_INIT_STATUS_INITIALIZED); else { - mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode); + mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode, + VAR_INIT_STATUS_INITIALIZED); if (mem_loc_result == 0) break; @@ -9098,7 +9142,8 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode) else { add_loc_descr (&mem_loc_result, - mem_loc_descriptor (XEXP (rtl, 1), mode)); + mem_loc_descriptor (XEXP (rtl, 1), mode, + VAR_INIT_STATUS_INITIALIZED)); add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_plus, 0, 0)); } @@ -9125,8 +9170,10 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode) 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, + VAR_INIT_STATUS_INITIALIZED); + dw_loc_descr_ref op1 = mem_loc_descriptor (XEXP (rtl, 1), mode, + VAR_INIT_STATUS_INITIALIZED); if (op0 == 0 || op1 == 0) break; @@ -9142,13 +9189,17 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode) break; case CONCATN: - mem_loc_result = concatn_mem_loc_descriptor (rtl, mode); + mem_loc_result = concatn_mem_loc_descriptor (rtl, mode, + VAR_INIT_STATUS_INITIALIZED); break; default: gcc_unreachable (); } + if (mem_loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED) + add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0)); + return mem_loc_result; } @@ -9156,11 +9207,11 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode) 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, VAR_INIT_STATUS_INITIALIZED); + dw_loc_descr_ref x1_ref = loc_descriptor (x1, VAR_INIT_STATUS_INITIALIZED); if (x0_ref == 0 || x1_ref == 0) return 0; @@ -9171,6 +9222,9 @@ concat_loc_descriptor (rtx x0, rtx x1) add_loc_descr (&cc_loc_result, x1_ref); add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x1))); + if (initialized == VAR_INIT_STATUS_UNINITIALIZED) + add_loc_descr (&cc_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0)); + return cc_loc_result; } @@ -9178,7 +9232,7 @@ concat_loc_descriptor (rtx x0, rtx x1) 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; @@ -9189,7 +9243,7 @@ concatn_loc_descriptor (rtx concatn) dw_loc_descr_ref ref; rtx x = XVECEXP (concatn, 0, i); - ref = loc_descriptor (x); + ref = loc_descriptor (x, VAR_INIT_STATUS_INITIALIZED); if (ref == NULL) return NULL; @@ -9197,6 +9251,9 @@ concatn_loc_descriptor (rtx concatn) add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x))); } + if (cc_loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED) + add_loc_descr (&cc_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0)); + return cc_loc_result; } @@ -9209,7 +9266,7 @@ concatn_loc_descriptor (rtx concatn) 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; @@ -9226,26 +9283,28 @@ loc_descriptor (rtx rtl) /* ... 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; } @@ -9260,14 +9319,16 @@ loc_descriptor (rtx rtl) 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)); @@ -9399,7 +9460,7 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) /* Certain constructs can only be represented at top-level. */ if (want_address == 2) - return loc_descriptor (rtl); + return loc_descriptor (rtl, VAR_INIT_STATUS_INITIALIZED); mode = GET_MODE (rtl); if (MEM_P (rtl)) @@ -9407,7 +9468,7 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) rtl = XEXP (rtl, 0); have_address = 1; } - ret = mem_loc_descriptor (rtl, mode); + ret = mem_loc_descriptor (rtl, mode, VAR_INIT_STATUS_INITIALIZED); } } break; @@ -9488,7 +9549,7 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) return 0; mode = GET_MODE (rtl); rtl = XEXP (rtl, 0); - ret = mem_loc_descriptor (rtl, mode); + ret = mem_loc_descriptor (rtl, mode, VAR_INIT_STATUS_INITIALIZED); have_address = 1; break; } @@ -10575,6 +10636,7 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl, 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. @@ -10591,7 +10653,12 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl, 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 = VAR_INIT_STATUS_INITIALIZED; + + list = new_loc_list (loc_descriptor (varloc, initialized), node->label, node->next->label, secname, 1); node = node->next; @@ -10600,8 +10667,11 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl, { /* 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); } @@ -10610,6 +10680,8 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl, 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) @@ -10620,7 +10692,8 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl, 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); } @@ -10644,8 +10717,10 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl, 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); diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c index a47a02b87fe..52b5c658168 100644 --- a/gcc/print-rtl.c +++ b/gcc/print-rtl.c @@ -325,6 +325,9 @@ print_rtx (rtx in_rtx) 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) == + VAR_INIT_STATUS_UNINITIALIZED) + fprintf (outfile, " [uninit]"); fprintf (outfile, ")"); #endif break; diff --git a/gcc/rtl.def b/gcc/rtl.def index c82fa7e86ed..1326202cc88 100644 --- a/gcc/rtl.def +++ b/gcc/rtl.def @@ -680,7 +680,9 @@ DEF_RTL_EXPR(SS_TRUNCATE, "ss_truncate", "e", RTX_UNARY) 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) +/* Changed 'te' to 'tei'; the 'i' field is for recording + initialization status of variables. */ +DEF_RTL_EXPR(VAR_LOCATION, "var_location", "tei", RTX_EXTRA) /* All expressions from this point forward appear only in machine descriptions. */ diff --git a/gcc/rtl.h b/gcc/rtl.h index 124f5280950..63f65730d10 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -847,6 +847,22 @@ extern const char * const reg_note_name[]; #define NOTE_VAR_LOCATION_LOC(INSN) (XCEXP (XCEXP (INSN, 4, NOTE), \ 1, VAR_LOCATION)) +/* Initialization status of the variable in the location. Status + can be unknown, uninitialized or initialized. See enumeration + type below. */ +#define NOTE_VAR_LOCATION_STATUS(INSN) (XCINT (XCEXP (INSN, 4, NOTE), \ + 2, VAR_LOCATION)) + +/* Possible initialization status of a variable. When requested + by the user, this information is tracked and recorded in the DWARF + debug information, along with the variable's location. */ +enum var_init_status +{ + VAR_INIT_STATUS_UNKNOWN, + VAR_INIT_STATUS_UNINITIALIZED, + VAR_INIT_STATUS_INITIALIZED +}; + /* Codes that appear in the NOTE_KIND field for kinds of notes that are not line numbers. These codes are all negative. diff --git a/gcc/toplev.c b/gcc/toplev.c index ff0d8a3ea7d..de86b38ae16 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -1874,7 +1874,8 @@ process_options (void) if (debug_info_level < DINFO_LEVEL_NORMAL || debug_hooks->var_location == do_nothing_debug_hooks.var_location) { - if (flag_var_tracking == 1) + if (flag_var_tracking == 1 + || flag_var_tracking_uninit == 1) { if (debug_info_level < DINFO_LEVEL_NORMAL) warning (0, "variable tracking requested, but useless unless " @@ -1884,6 +1885,7 @@ process_options (void) "by this debug format"); } flag_var_tracking = 0; + flag_var_tracking_uninit = 0; } if (flag_rename_registers == AUTODETECT_VALUE) @@ -1893,6 +1895,12 @@ process_options (void) if (flag_var_tracking == AUTODETECT_VALUE) flag_var_tracking = optimize >= 1; + /* If the user specifically requested variable tracking with tagging + uninitialized variables, we need to turn on variable tracking. + (We already determined above that variable tracking is feasible.) */ + if (flag_var_tracking_uninit) + flag_var_tracking = 1; + /* If auxiliary info generation is desired, open the output file. This goes in the same directory as the source file--unlike all the other output files. */ diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c index 94a025a002b..56dcc198d7d 100644 --- a/gcc/var-tracking.c +++ b/gcc/var-tracking.c @@ -219,6 +219,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. */ @@ -294,16 +300,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); @@ -338,8 +347,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); @@ -727,7 +738,8 @@ 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; @@ -752,6 +764,14 @@ unshare_variable (dataflow_set *set, variable var) 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 @@ 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 +853,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 +895,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 +905,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 +925,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 +946,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 +980,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; 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 +999,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; 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 @@ -966,7 +1027,7 @@ var_mem_delete (dataflow_set *set, rtx loc, bool clobber) 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 +1139,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 +1180,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 +1219,12 @@ variable_union (void **slot, void *data) && 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, VAR_INIT_STATUS_UNKNOWN); } src_l = 0; @@ -1194,6 +1270,11 @@ variable_union (void **slot, void *data) /* 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 +1321,11 @@ variable_union (void **slot, void *data) 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 +1344,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; } @@ -1679,7 +1777,7 @@ add_stores (rtx loc, rtx expr, void *insn) 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 +1798,99 @@ add_stores (rtx loc, rtx expr, void *insn) else mo->type = MO_SET; mo->u.loc = loc; - mo->insn = NEXT_INSN ((rtx) insn); + mo->insn = (rtx) insn; } } +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 = VAR_INIT_STATUS_UNINITIALIZED; + + if (! flag_var_tracking_uninit) + status = VAR_INIT_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; +} + +/* LOC is the destination the variable is being copied to. INSN + contains the copy instruction. SET is the dataflow set containing + the variable in 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 +1920,65 @@ 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; + 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, 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; + + if (! flag_var_tracking_uninit) + src_status = VAR_INIT_STATUS_INITIALIZED; + else + src_status = find_src_status (in, loc, VTI (bb)->mos[i].insn); + + if (src_status == VAR_INIT_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 +2151,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); } } @@ -2077,7 +2298,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; @@ -2119,13 +2341,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 @@ -2134,7 +2362,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. */ @@ -2161,6 +2389,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; @@ -2172,6 +2406,8 @@ 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->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 +2426,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; @@ -2213,7 +2449,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)) { @@ -2278,7 +2518,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; } } @@ -2345,6 +2588,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]; @@ -2352,6 +2596,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; @@ -2369,6 +2616,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. */ @@ -2447,10 +2695,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 +2709,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 +2723,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); @@ -2602,11 +2855,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 +2871,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 (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, 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; + + 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; @@ -2660,7 +2936,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; @@ -2776,10 +3052,12 @@ vt_add_function_parameters (void) 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); + set_variable_part (out, incoming, parm, offset, VAR_INIT_STATUS_INITIALIZED, + NULL); } } |