diff options
Diffstat (limited to 'gcc/dwarf2out.c')
-rw-r--r-- | gcc/dwarf2out.c | 785 |
1 files changed, 540 insertions, 245 deletions
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 14836d539e8..d2d2fefd153 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -89,6 +89,8 @@ along with GCC; see the file COPYING3. If not see #include "hashtab.h" #include "cgraph.h" #include "input.h" +#include "gimple.h" +#include "tree-pass.h" #ifdef DWARF2_DEBUGGING_INFO static void dwarf2out_source_line (unsigned int, const char *, int, bool); @@ -4655,6 +4657,16 @@ loc_descr_plus_const (dw_loc_descr_ref *list_head, HOST_WIDE_INT offset) } } +/* Add a constant OFFSET to a location list. */ + +static void +loc_list_plus_const (dw_loc_list_ref list_head, HOST_WIDE_INT offset) +{ + dw_loc_list_ref d; + for (d = list_head; d != NULL; d = d->dw_loc_next) + loc_descr_plus_const (&d->expr, offset); +} + /* Return the size of a location descriptor. */ static unsigned long @@ -5938,8 +5950,8 @@ static dw_loc_descr_ref concat_loc_descriptor (rtx, rtx, enum var_init_status); static dw_loc_descr_ref loc_descriptor (rtx, enum machine_mode mode, 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 dw_loc_list_ref loc_list_from_tree (tree, int); +static dw_loc_descr_ref loc_descriptor_from_tree (tree, int); static HOST_WIDE_INT ceiling (HOST_WIDE_INT, unsigned int); static tree field_type (const_tree); static unsigned int simple_type_align_in_bits (const_tree); @@ -5947,7 +5959,7 @@ static unsigned int simple_decl_align_in_bits (const_tree); static unsigned HOST_WIDE_INT simple_type_size_in_bits (const_tree); static HOST_WIDE_INT field_byte_offset (const_tree); static void add_AT_location_description (dw_die_ref, enum dwarf_attribute, - dw_loc_descr_ref); + dw_loc_list_ref); static void add_data_member_location_attribute (dw_die_ref, tree); static void add_const_value_attribute (dw_die_ref, rtx); static void insert_int (HOST_WIDE_INT, unsigned, unsigned char *); @@ -10958,36 +10970,6 @@ is_based_loc (const_rtx rtl) && CONST_INT_P (XEXP (rtl, 1))))); } -/* Return a descriptor that describes the concatenation of N locations - used to form the address of a memory location. */ - -static dw_loc_descr_ref -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; - unsigned int n = XVECLEN (concatn, 0); - - for (i = 0; i < n; ++i) - { - dw_loc_descr_ref ref; - rtx x = XVECEXP (concatn, 0, i); - - ref = mem_loc_descriptor (x, mode, VAR_INIT_STATUS_INITIALIZED); - if (ref == NULL) - return NULL; - - add_loc_descr (&cc_loc_result, ref); - 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; -} - /* Try to handle TLS MEMs, for which mem_loc_descriptor on XEXP (mem, 0) failed. */ @@ -11006,7 +10988,7 @@ tls_mem_loc_descriptor (rtx mem) || !DECL_THREAD_LOCAL_P (base)) return NULL; - loc_result = loc_descriptor_from_tree_1 (MEM_EXPR (mem), 2); + loc_result = loc_descriptor_from_tree (MEM_EXPR (mem), 2); if (loc_result == NULL) return NULL; @@ -11016,6 +10998,26 @@ tls_mem_loc_descriptor (rtx mem) return loc_result; } +/* Output debug info about reason why we failed to expand expression as dwarf + expression. */ + +static void +expansion_failed (tree expr, rtx rtl, char const *reason) +{ + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Failed to expand as dwarf: "); + if (expr) + print_generic_expr (dump_file, expr, dump_flags); + if (rtl) + { + fprintf (dump_file, "\n"); + print_rtl (dump_file, rtl); + } + fprintf (dump_file, "\nReason: %s\n", reason); + } +} + /* The following routine converts the RTL for a variable or parameter (resident in memory) into an equivalent Dwarf representation of a mechanism for getting the address of that same variable onto the top of a @@ -11163,7 +11165,11 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, FIXME: might try to use DW_OP_const_value here, though DW_OP_piece complicates it. */ if (!marked) - return 0; + { + expansion_failed (NULL_TREE, rtl, + "Constant was removed from constant pool.\n"); + return 0; + } } if (GET_CODE (rtl) == SYMBOL_REF @@ -11193,6 +11199,14 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, VEC_safe_push (rtx, gc, used_rtx_array, rtl); break; + case CONCAT: + case CONCATN: + case VAR_LOCATION: + expansion_failed (NULL_TREE, rtl, + "CONCAT/CONCATN/VAR_LOCATION is handled only by loc_descriptor"); + gcc_unreachable (); + return 0; + case PRE_MODIFY: /* Extract the PLUS expression nested inside and fall into PLUS code below. */ @@ -11322,11 +11336,6 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, mem_loc_result = int_loc_descriptor (INTVAL (rtl)); break; - case CONCATN: - mem_loc_result = concatn_mem_loc_descriptor (rtl, mode, - VAR_INIT_STATUS_INITIALIZED); - break; - case EQ: op = DW_OP_eq; goto do_scompare; @@ -11768,7 +11777,7 @@ loc_descriptor (rtx rtl, enum machine_mode mode, break; case CONST_INT: - if (mode != VOIDmode && mode != BLKmode && dwarf_version >= 4) + if (mode != VOIDmode && mode != BLKmode) { HOST_WIDE_INT i = INTVAL (rtl); int litsize; @@ -11822,7 +11831,7 @@ loc_descriptor (rtx rtl, enum machine_mode mode, break; case CONST_DOUBLE: - if (mode != VOIDmode && dwarf_version >= 4) + if (mode != VOIDmode) { /* Note that a CONST_DOUBLE rtx could represent either an integer or a floating-point constant. A CONST_DOUBLE is used whenever @@ -11853,7 +11862,7 @@ loc_descriptor (rtx rtl, enum machine_mode mode, break; case CONST_VECTOR: - if (mode != VOIDmode && dwarf_version >= 4) + if (mode != VOIDmode) { unsigned int elt_size = GET_MODE_UNIT_SIZE (GET_MODE (rtl)); unsigned int length = CONST_VECTOR_NUNITS (rtl); @@ -11941,8 +11950,7 @@ loc_descriptor (rtx rtl, enum machine_mode mode, && SYMBOL_REF_TLS_MODEL (rtl) != TLS_MODEL_NONE) break; case LABEL_REF: - if (mode != VOIDmode && GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE - && dwarf_version >= 4) + if (mode != VOIDmode && GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE) { loc_result = new_loc_descr (DW_OP_implicit_value, DWARF2_ADDR_SIZE, 0); @@ -11954,8 +11962,7 @@ loc_descriptor (rtx rtl, enum machine_mode mode, default: if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE (rtl) == mode - && GET_MODE_SIZE (GET_MODE (rtl)) <= DWARF2_ADDR_SIZE - && dwarf_version >= 4) + && GET_MODE_SIZE (GET_MODE (rtl)) <= DWARF2_ADDR_SIZE) { /* Value expression. */ loc_result = mem_loc_descriptor (rtl, VOIDmode, initialized); @@ -11972,16 +11979,310 @@ loc_descriptor (rtx rtl, enum machine_mode mode, return loc_result; } -/* Similar, but generate the descriptor from trees instead of rtl. This comes - up particularly with variable length arrays. WANT_ADDRESS is 2 if this is - a top-level invocation of loc_descriptor_from_tree; is 1 if this is not a - top-level invocation, and we require the address of LOC; is 0 if we require - the value of LOC. */ +/* We need to figure out what section we should use as the base for the + address ranges where a given location is valid. + 1. If this particular DECL has a section associated with it, use that. + 2. If this function has a section associated with it, use that. + 3. Otherwise, use the text section. + XXX: If you split a variable across multiple sections, we won't notice. */ + +static const char * +secname_for_decl (const_tree decl) +{ + const char *secname; + + if (VAR_OR_FUNCTION_DECL_P (decl) && DECL_SECTION_NAME (decl)) + { + tree sectree = DECL_SECTION_NAME (decl); + secname = TREE_STRING_POINTER (sectree); + } + else if (current_function_decl && DECL_SECTION_NAME (current_function_decl)) + { + tree sectree = DECL_SECTION_NAME (current_function_decl); + secname = TREE_STRING_POINTER (sectree); + } + else if (cfun && in_cold_section_p) + secname = crtl->subsections.cold_section_label; + else + secname = text_section_label; + + return secname; +} + +/* Return true when DECL_BY_REFERENCE is defined and set for DECL. */ + +static bool +decl_by_reference_p (tree decl) +{ + return ((TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == RESULT_DECL + || TREE_CODE (decl) == VAR_DECL) + && DECL_BY_REFERENCE (decl)); +} + + +/* Dereference a location expression LOC if DECL is passed by invisible + reference. */ static dw_loc_descr_ref -loc_descriptor_from_tree_1 (tree loc, int want_address) +loc_by_reference (dw_loc_descr_ref loc, tree decl) +{ + HOST_WIDE_INT size; + enum dwarf_location_atom op; + + if (loc == NULL) + return NULL; + + if (!decl_by_reference_p (decl)) + return loc; + + /* If loc is DW_OP_reg{0...31,x}, don't add DW_OP_deref, instead + change it into corresponding DW_OP_breg{0...31,x} 0. Then the + location expression is considered to be address of a memory location, + rather than the register itself. */ + if (((loc->dw_loc_opc >= DW_OP_reg0 && loc->dw_loc_opc <= DW_OP_reg31) + || loc->dw_loc_opc == DW_OP_regx) + && (loc->dw_loc_next == NULL + || (loc->dw_loc_next->dw_loc_opc == DW_OP_GNU_uninit + && loc->dw_loc_next->dw_loc_next == NULL))) + { + if (loc->dw_loc_opc == DW_OP_regx) + { + loc->dw_loc_opc = DW_OP_bregx; + loc->dw_loc_oprnd2.v.val_int = 0; + } + else + { + loc->dw_loc_opc + = (enum dwarf_location_atom) + (loc->dw_loc_opc + (DW_OP_breg0 - DW_OP_reg0)); + loc->dw_loc_oprnd1.v.val_int = 0; + } + return loc; + } + + size = int_size_in_bytes (TREE_TYPE (decl)); + if (size > DWARF2_ADDR_SIZE || size == -1) + return 0; + else if (size == DWARF2_ADDR_SIZE) + op = DW_OP_deref; + else + op = DW_OP_deref_size; + add_loc_descr (&loc, new_loc_descr (op, size, 0)); + return loc; +} + +/* Return dwarf representation of location list representing for + LOC_LIST of DECL. */ + +static dw_loc_list_ref +dw_loc_list (var_loc_list * loc_list, tree decl, bool toplevel) +{ + const char *endname, *secname; + dw_loc_list_ref list; + rtx varloc; + enum var_init_status initialized; + struct var_loc_node *node; + dw_loc_descr_ref descr; + char label_id[MAX_ARTIFICIAL_LABEL_BYTES]; + + bool by_reference = decl_by_reference_p (decl); + + /* Now that we know what section we are using for a base, + actually construct the list of locations. + The first location information is what is passed to the + function that creates the location list, and the remaining + locations just get added on to that list. + Note that we only know the start address for a location + (IE location changes), so to build the range, we use + the range [current location start, next location start]. + This means we have to special case the last node, and generate + a range of [last location start, end of function label]. */ + + node = loc_list->first; + varloc = NOTE_VAR_LOCATION (node->var_loc_note); + secname = secname_for_decl (decl); + + if (NOTE_VAR_LOCATION_LOC (node->var_loc_note)) + initialized = NOTE_VAR_LOCATION_STATUS (node->var_loc_note); + else + initialized = VAR_INIT_STATUS_INITIALIZED; + + if (!toplevel || by_reference) + { + gcc_assert (GET_CODE (varloc) == VAR_LOCATION); + /* Single part. */ + if (GET_CODE (XEXP (varloc, 1)) != PARALLEL) + descr = loc_by_reference (mem_loc_descriptor (XEXP (XEXP (varloc, 1), 0), + TYPE_MODE (TREE_TYPE (decl)), + initialized), + decl); + else + descr = NULL; + } + else + descr = loc_descriptor (varloc, DECL_MODE (decl), initialized); + + if (!current_function_decl) + endname = text_end_label; + else + { + ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL, + current_function_funcdef_no); + endname = ggc_strdup (label_id); + } + list = new_loc_list (descr, node->label, node->next ? node->next->label : endname, secname, 1); + node = node->next; + + if (!node) + return NULL; + + for (; node->next; node = node->next) + if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX) + { + /* 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); + if (!toplevel || by_reference) + { + gcc_assert (GET_CODE (varloc) == VAR_LOCATION); + /* Single part. */ + if (GET_CODE (XEXP (varloc, 1)) != PARALLEL) + descr = mem_loc_descriptor (XEXP (XEXP (varloc, 1), 0), + TYPE_MODE (TREE_TYPE (decl)), initialized); + else + descr = NULL; + descr = loc_by_reference (descr, decl); + } + else + descr = loc_descriptor (varloc, DECL_MODE (decl), initialized); + add_loc_descr_to_loc_list (&list, descr, + node->label, node->next->label, secname); + } + + /* If the variable has a location at the last label + it keeps its location until the end of function. */ + if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX) + { + enum var_init_status initialized = + NOTE_VAR_LOCATION_STATUS (node->var_loc_note); + + varloc = NOTE_VAR_LOCATION (node->var_loc_note); + if (!toplevel || by_reference) + { + gcc_assert (GET_CODE (varloc) == VAR_LOCATION); + /* Single part. */ + if (GET_CODE (XEXP (varloc, 1)) != PARALLEL) + descr = mem_loc_descriptor (XEXP (XEXP (varloc, 1), 0), + TYPE_MODE (TREE_TYPE (decl)), initialized); + else + descr = NULL; + descr = loc_by_reference (descr, decl); + } + else + descr = loc_descriptor (varloc, DECL_MODE (decl), initialized); + add_loc_descr_to_loc_list (&list, descr, node->label, endname, secname); + } + return list; +} + +/* Return single element location list containing loc descr REF. */ + +static dw_loc_list_ref +single_element_loc_list (dw_loc_descr_ref ref) +{ + return new_loc_list (ref, NULL, NULL, NULL, 0); +} + +/* Return if the loc_list has only single element and thus can be represented + as location description. */ + +static bool +single_element_loc_list_p (dw_loc_list_ref list) { - dw_loc_descr_ref ret, ret1; + return (!list->dw_loc_next && !list->begin && !list->end); +} + +/* To each location in list LIST add loc descr REF. */ + +static void +add_loc_descr_to_each (dw_loc_list_ref list, dw_loc_descr_ref ref) +{ + dw_loc_descr_ref copy; + add_loc_descr (&list->expr, ref); + list = list->dw_loc_next; + while (list) + { + copy = GGC_CNEW (dw_loc_descr_node); + memcpy (copy, ref, sizeof (dw_loc_descr_node)); + add_loc_descr (&list->expr, copy); + while (copy->dw_loc_next) + { + dw_loc_descr_ref new_copy = GGC_CNEW (dw_loc_descr_node); + memcpy (new_copy, copy->dw_loc_next, sizeof (dw_loc_descr_node)); + copy->dw_loc_next = new_copy; + copy = new_copy; + } + list = list->dw_loc_next; + } +} + +/* Given two lists RET and LIST + produce location list that is result of adding expression in LIST + to expression in RET on each possition in program. + Might be destructive on both RET and LIST. + + TODO: We handle only simple cases of RET or LIST having at most one + element. General case would inolve sorting the lists in program order + and merging them that will need some additional work. + Adding that will improve quality of debug info especially for SRA-ed + structures. */ + +static void +add_loc_list (dw_loc_list_ref *ret, dw_loc_list_ref list) +{ + if (!list) + return; + if (!*ret) + { + *ret = list; + return; + } + if (!list->dw_loc_next) + { + add_loc_descr_to_each (*ret, list->expr); + return; + } + if (!(*ret)->dw_loc_next) + { + add_loc_descr_to_each (list, (*ret)->expr); + *ret = list; + return; + } + expansion_failed (NULL_TREE, NULL_RTX, + "Don't know how to merge two non-trivial" + " location lists.\n"); + *ret = NULL; + return; +} + +/* Generate Dwarf location list representing LOC. + If WANT_ADDRESS is false, expression computing LOC will be computed + If WANT_ADDRESS is 1, expression computing address of LOC will be returned + if WANT_ADDRESS is 2, expression computing address useable in location + will be returned (i.e. DW_OP_reg can be used + to refer to register values) + TODO: Dwarf4 adds types to the stack machine that ought to be used here + DW_OP_stack_value will help in cases where we fail to find address of the + expression. + */ + +static dw_loc_list_ref +loc_list_from_tree (tree loc, int want_address) +{ + dw_loc_descr_ref ret = NULL, ret1 = NULL; + dw_loc_list_ref list_ret = NULL, list_ret1 = NULL; int have_address = 0; enum dwarf_location_atom op; @@ -11992,6 +12293,7 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) switch (TREE_CODE (loc)) { case ERROR_MARK: + expansion_failed (loc, NULL_RTX, "ERROR_MARK"); return 0; case PLACEHOLDER_EXPR: @@ -11999,25 +12301,32 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) position of other fields. We don't try to encode this here. The only user of this is Ada, which encodes the needed information using the names of types. */ + expansion_failed (loc, NULL_RTX, "PLACEHOLDER_EXPR"); return 0; case CALL_EXPR: + expansion_failed (loc, NULL_RTX, "CALL_EXPR"); + /* There are no opcodes for these operations. */ return 0; case PREINCREMENT_EXPR: case PREDECREMENT_EXPR: case POSTINCREMENT_EXPR: case POSTDECREMENT_EXPR: + expansion_failed (loc, NULL_RTX, "PRE/POST INDCREMENT/DECREMENT"); /* There are no opcodes for these operations. */ return 0; case ADDR_EXPR: /* If we already want an address, there's nothing we can do. */ if (want_address) - return 0; + { + expansion_failed (loc, NULL_RTX, "need address of ADDR_EXPR"); + return 0; + } /* Otherwise, process the argument and look for the address. */ - return loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 1); + return loc_list_from_tree (TREE_OPERAND (loc, 0), 1); case VAR_DECL: if (DECL_THREAD_LOCAL_P (loc)) @@ -12030,7 +12339,7 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) if (targetm.have_tls) { /* If this is not defined, we have no way to emit the - data. */ + data. */ if (!targetm.asm_out.output_dwarf_dtprel) return 0; @@ -12077,17 +12386,24 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) case PARM_DECL: if (DECL_HAS_VALUE_EXPR_P (loc)) - return loc_descriptor_from_tree_1 (DECL_VALUE_EXPR (loc), - want_address); + return loc_list_from_tree (DECL_VALUE_EXPR (loc), + want_address); /* FALLTHRU */ case RESULT_DECL: case FUNCTION_DECL: { rtx rtl = rtl_for_decl_location (loc); + var_loc_list *loc_list = lookup_decl_loc (loc); - if (rtl == NULL_RTX) - return 0; + if (loc_list && loc_list->first + && (list_ret = dw_loc_list (loc_list, loc, want_address == 2))) + have_address = 1; + else if (rtl == NULL_RTX) + { + expansion_failed (loc, NULL_RTX, "DECL has no RTL"); + return 0; + } else if (CONST_INT_P (rtl)) { HOST_WIDE_INT val = INTVAL (rtl); @@ -12096,7 +12412,10 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) ret = int_loc_descriptor (val); } else if (GET_CODE (rtl) == CONST_STRING) - return 0; + { + expansion_failed (loc, NULL_RTX, "CONST_STRING"); + return 0; + } else if (CONSTANT_P (rtl)) { ret = new_loc_descr (DW_OP_addr, 0, 0); @@ -12109,33 +12428,41 @@ 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, VOIDmode, - VAR_INIT_STATUS_INITIALIZED); - - mode = GET_MODE (rtl); - if (MEM_P (rtl)) { - rtl = XEXP (rtl, 0); + ret = loc_descriptor (rtl, VOIDmode, + VAR_INIT_STATUS_INITIALIZED); have_address = 1; } - ret = mem_loc_descriptor (rtl, mode, VAR_INIT_STATUS_INITIALIZED); + else + { + mode = GET_MODE (rtl); + if (MEM_P (rtl)) + { + rtl = XEXP (rtl, 0); + have_address = 1; + } + ret = mem_loc_descriptor (rtl, mode, VAR_INIT_STATUS_INITIALIZED); + } + if (!ret) + expansion_failed (loc, rtl, + "failed to produce loc descriptor for rtl"); } } break; case INDIRECT_REF: - ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0); + list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0); have_address = 1; break; case COMPOUND_EXPR: - return loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 1), want_address); + return loc_list_from_tree (TREE_OPERAND (loc, 1), want_address); CASE_CONVERT: case VIEW_CONVERT_EXPR: case SAVE_EXPR: case MODIFY_EXPR: - return loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), want_address); + return loc_list_from_tree (TREE_OPERAND (loc, 0), want_address); case COMPONENT_REF: case BIT_FIELD_REF: @@ -12151,26 +12478,35 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) obj = get_inner_reference (loc, &bitsize, &bitpos, &offset, &mode, &unsignedp, &volatilep, false); - if (obj == loc) - return 0; + gcc_assert (obj != loc); - ret = loc_descriptor_from_tree_1 (obj, 1); - if (ret == 0 - || bitpos % BITS_PER_UNIT != 0 || bitsize % BITS_PER_UNIT != 0) + list_ret = loc_list_from_tree (obj, 1); + if (list_ret == 0) return 0; + if (bitpos % BITS_PER_UNIT != 0 || bitsize % BITS_PER_UNIT != 0) + { + expansion_failed (loc, NULL_RTX, + "bitfield access"); + return 0; + } if (offset != NULL_TREE) { /* Variable offset. */ - ret1 = loc_descriptor_from_tree_1 (offset, 0); - if (ret1 == 0) + list_ret1 = loc_list_from_tree (offset, 0); + if (list_ret1 == 0) return 0; - add_loc_descr (&ret, ret1); - add_loc_descr (&ret, new_loc_descr (DW_OP_plus, 0, 0)); + add_loc_list (&list_ret, list_ret1); + if (!list_ret) + return 0; + add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_plus, 0, 0)); } bytepos = bitpos / BITS_PER_UNIT; - loc_descr_plus_const (&ret, bytepos); + if (bytepos > 0) + add_loc_descr_to_each (list_ret, new_loc_descr (DW_OP_plus_uconst, bytepos, 0)); + else if (bytepos < 0) + loc_list_plus_const (list_ret, bytepos); have_address = 1; break; @@ -12180,7 +12516,11 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) if (host_integerp (loc, 0)) ret = int_loc_descriptor (tree_low_cst (loc, 0)); else - return 0; + { + expansion_failed (loc, NULL_RTX, + "Integer operand is not host integer"); + return 0; + } break; case CONSTRUCTOR: @@ -12250,11 +12590,11 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) if (TREE_CODE (TREE_OPERAND (loc, 1)) == INTEGER_CST && host_integerp (TREE_OPERAND (loc, 1), 0)) { - ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0); - if (ret == 0) + list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0); + if (list_ret == 0) return 0; - loc_descr_plus_const (&ret, tree_low_cst (TREE_OPERAND (loc, 1), 0)); + loc_list_plus_const (list_ret, tree_low_cst (TREE_OPERAND (loc, 1), 0)); break; } @@ -12298,13 +12638,15 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) goto do_binop; do_binop: - ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0); - ret1 = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 1), 0); - if (ret == 0 || ret1 == 0) + list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0); + list_ret1 = loc_list_from_tree (TREE_OPERAND (loc, 1), 0); + if (list_ret == 0 || list_ret1 == 0) return 0; - add_loc_descr (&ret, ret1); - add_loc_descr (&ret, new_loc_descr (op, 0, 0)); + add_loc_list (&list_ret, list_ret1); + if (list_ret == 0) + return 0; + add_loc_descr_to_each (list_ret, new_loc_descr (op, 0, 0)); break; case TRUTH_NOT_EXPR: @@ -12321,11 +12663,11 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) goto do_unop; do_unop: - ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0); - if (ret == 0) + list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0); + if (list_ret == 0) return 0; - add_loc_descr (&ret, new_loc_descr (op, 0, 0)); + add_loc_descr_to_each (list_ret, new_loc_descr (op, 0, 0)); break; case MIN_EXPR: @@ -12345,29 +12687,29 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) case COND_EXPR: { dw_loc_descr_ref lhs - = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 1), 0); - dw_loc_descr_ref rhs - = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 2), 0); + = loc_descriptor_from_tree (TREE_OPERAND (loc, 1), 0); + dw_loc_list_ref rhs + = loc_list_from_tree (TREE_OPERAND (loc, 2), 0); dw_loc_descr_ref bra_node, jump_node, tmp; - ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0); - if (ret == 0 || lhs == 0 || rhs == 0) + list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0); + if (list_ret == 0 || lhs == 0 || rhs == 0) return 0; bra_node = new_loc_descr (DW_OP_bra, 0, 0); - add_loc_descr (&ret, bra_node); + add_loc_descr_to_each (list_ret, bra_node); - add_loc_descr (&ret, rhs); + add_loc_list (&list_ret, rhs); jump_node = new_loc_descr (DW_OP_skip, 0, 0); - add_loc_descr (&ret, jump_node); + add_loc_descr_to_each (list_ret, jump_node); - add_loc_descr (&ret, lhs); + add_loc_descr_to_each (list_ret, lhs); bra_node->dw_loc_oprnd1.val_class = dw_val_class_loc; bra_node->dw_loc_oprnd1.v.val_loc = lhs; /* ??? Need a node to point the skip at. Use a nop. */ tmp = new_loc_descr (DW_OP_nop, 0, 0); - add_loc_descr (&ret, tmp); + add_loc_descr_to_each (list_ret, tmp); jump_node->dw_loc_oprnd1.val_class = dw_val_class_loc; jump_node->dw_loc_oprnd1.v.val_loc = tmp; } @@ -12381,7 +12723,11 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) up, for instance, with the C STMT_EXPR. */ if ((unsigned int) TREE_CODE (loc) >= (unsigned int) LAST_AND_UNUSED_TREE_CODE) - return 0; + { + expansion_failed (loc, NULL_RTX, + "language specific tree node"); + return 0; + } #ifdef ENABLE_CHECKING /* Otherwise this is a generic code; we should just lists all of @@ -12394,32 +12740,60 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) #endif } + if (!ret && !list_ret) + return 0; + /* Show if we can't fill the request for an address. */ if (want_address && !have_address) - return 0; + { + expansion_failed (loc, NULL_RTX, + "Want address and only have value"); + return 0; + } + + gcc_assert (!ret || !list_ret); /* If we've got an address and don't want one, dereference. */ - if (!want_address && have_address && ret) + if (!want_address && have_address) { HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (loc)); if (size > DWARF2_ADDR_SIZE || size == -1) - return 0; + { + expansion_failed (loc, NULL_RTX, + "DWARF address size mismatch"); + return 0; + } else if (size == DWARF2_ADDR_SIZE) op = DW_OP_deref; else op = DW_OP_deref_size; - add_loc_descr (&ret, new_loc_descr (op, size, 0)); + if (ret) + add_loc_descr (&ret, new_loc_descr (op, size, 0)); + else + add_loc_descr_to_each (list_ret, new_loc_descr (op, size, 0)); } + if (ret) + list_ret = single_element_loc_list (ret); - return ret; + return list_ret; } -static inline dw_loc_descr_ref -loc_descriptor_from_tree (tree loc) +/* Same as above but return only single location expression. */ +static dw_loc_descr_ref +loc_descriptor_from_tree (tree loc, int want_address) { - return loc_descriptor_from_tree_1 (loc, 2); + dw_loc_list_ref ret = loc_list_from_tree (loc, want_address); + if (!ret) + return NULL; + if (ret->dw_loc_next) + { + expansion_failed (loc, NULL_RTX, + "Location list where only loc descriptor needed"); + return NULL; + } + return ret->expr; } /* Given a value, round it up to the lowest multiple of `boundary' @@ -12529,9 +12903,9 @@ field_byte_offset (const_tree decl) field_size_tree = DECL_SIZE (decl); /* The size could be unspecified if there was an error, or for - a flexible array member. */ + a flexible array member. */ if (!field_size_tree) - field_size_tree = bitsize_zero_node; + field_size_tree = bitsize_zero_node; /* If the size of the field is not constant, use the type size. */ if (host_integerp (field_size_tree, 1)) @@ -12626,10 +13000,14 @@ field_byte_offset (const_tree decl) static inline void add_AT_location_description (dw_die_ref die, enum dwarf_attribute attr_kind, - dw_loc_descr_ref descr) + dw_loc_list_ref descr) { - if (descr != 0) - add_AT_loc (die, attr_kind, descr); + if (descr == 0) + return; + if (single_element_loc_list_p (descr)) + add_AT_loc (die, attr_kind, descr->expr); + else + add_AT_loc_list (die, attr_kind, descr); } /* Attach the specialized form of location attribute used for data members of @@ -13267,36 +13645,6 @@ rtl_for_decl_location (tree decl) return rtl; } -/* We need to figure out what section we should use as the base for the - address ranges where a given location is valid. - 1. If this particular DECL has a section associated with it, use that. - 2. If this function has a section associated with it, use that. - 3. Otherwise, use the text section. - XXX: If you split a variable across multiple sections, we won't notice. */ - -static const char * -secname_for_decl (const_tree decl) -{ - const char *secname; - - if (VAR_OR_FUNCTION_DECL_P (decl) && DECL_SECTION_NAME (decl)) - { - tree sectree = DECL_SECTION_NAME (decl); - secname = TREE_STRING_POINTER (sectree); - } - else if (current_function_decl && DECL_SECTION_NAME (current_function_decl)) - { - tree sectree = DECL_SECTION_NAME (current_function_decl); - secname = TREE_STRING_POINTER (sectree); - } - else if (cfun && in_cold_section_p) - secname = crtl->subsections.cold_section_label; - else - secname = text_section_label; - - return secname; -} - /* Check whether decl is a Fortran COMMON symbol. If not, NULL_TREE is returned. If so, the decl for the COMMON block is returned, and the value is the offset into the common block for the symbol. */ @@ -13347,60 +13695,6 @@ fortran_common (tree decl, HOST_WIDE_INT *value) return cvar; } -/* Dereference a location expression LOC if DECL is passed by invisible - reference. */ - -static dw_loc_descr_ref -loc_by_reference (dw_loc_descr_ref loc, tree decl) -{ - HOST_WIDE_INT size; - enum dwarf_location_atom op; - - if (loc == NULL) - return NULL; - - if ((TREE_CODE (decl) != PARM_DECL - && TREE_CODE (decl) != RESULT_DECL - && TREE_CODE (decl) != VAR_DECL) - || !DECL_BY_REFERENCE (decl)) - return loc; - - /* If loc is DW_OP_reg{0...31,x}, don't add DW_OP_deref, instead - change it into corresponding DW_OP_breg{0...31,x} 0. Then the - location expression is considered to be address of a memory location, - rather than the register itself. */ - if (((loc->dw_loc_opc >= DW_OP_reg0 && loc->dw_loc_opc <= DW_OP_reg31) - || loc->dw_loc_opc == DW_OP_regx) - && (loc->dw_loc_next == NULL - || (loc->dw_loc_next->dw_loc_opc == DW_OP_GNU_uninit - && loc->dw_loc_next->dw_loc_next == NULL))) - { - if (loc->dw_loc_opc == DW_OP_regx) - { - loc->dw_loc_opc = DW_OP_bregx; - loc->dw_loc_oprnd2.v.val_int = 0; - } - else - { - loc->dw_loc_opc - = (enum dwarf_location_atom) - (loc->dw_loc_opc + (DW_OP_breg0 - DW_OP_reg0)); - loc->dw_loc_oprnd1.v.val_int = 0; - } - return loc; - } - - size = int_size_in_bytes (TREE_TYPE (decl)); - if (size > DWARF2_ADDR_SIZE || size == -1) - return 0; - else if (size == DWARF2_ADDR_SIZE) - op = DW_OP_deref; - else - op = DW_OP_deref_size; - add_loc_descr (&loc, new_loc_descr (op, size, 0)); - return loc; -} - /* Generate *either* a DW_AT_location attribute or else a DW_AT_const_value data attribute for a variable or a parameter. We generate the DW_AT_const_value attribute only in those cases where the given variable @@ -13418,6 +13712,7 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl, { rtx rtl; dw_loc_descr_ref descr; + dw_loc_list_ref descr_list; var_loc_list *loc_list; struct var_loc_node *node; if (TREE_CODE (decl) == ERROR_MARK) @@ -13539,18 +13834,18 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl, if (descr) { descr = loc_by_reference (descr, decl); - add_AT_location_description (die, attr, descr); + add_AT_location_description (die, attr, single_element_loc_list (descr)); return; } } /* We couldn't get any rtl, so try directly generating the location description from the tree. */ - descr = loc_descriptor_from_tree (decl); - if (descr) + descr_list = loc_list_from_tree (decl, 2); + if (descr_list) { descr = loc_by_reference (descr, decl); - add_AT_location_description (die, attr, descr); + add_AT_location_description (die, attr, descr_list); return; } /* None of that worked, so it must not really have a location; @@ -13967,7 +14262,7 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b case RESULT_DECL: { dw_die_ref decl_die = lookup_decl_die (bound); - dw_loc_descr_ref loc; + dw_loc_list_ref loc; /* ??? Can this happen, or should the variable have been bound first? Probably it can, since I imagine that we try to create @@ -13978,7 +14273,7 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b add_AT_die_ref (subrange_die, bound_attr, decl_die); else { - loc = loc_descriptor_from_tree_1 (bound, 0); + loc = loc_list_from_tree (bound, 0); add_AT_location_description (subrange_die, bound_attr, loc); } break; @@ -13990,10 +14285,10 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b evaluate the value of the array bound. */ dw_die_ref ctx, decl_die; - dw_loc_descr_ref loc; + dw_loc_list_ref list; - loc = loc_descriptor_from_tree (bound); - if (loc == NULL) + list = loc_list_from_tree (bound, 2); + if (list == NULL) break; if (current_function_decl == 0) @@ -14004,7 +14299,10 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b decl_die = new_die (DW_TAG_variable, ctx, bound); add_AT_flag (decl_die, DW_AT_artificial, 1); add_type_attribute (decl_die, TREE_TYPE (bound), 1, 0, ctx); - add_AT_loc (decl_die, DW_AT_location, loc); + if (list->dw_loc_next) + add_AT_loc_list (decl_die, DW_AT_location, list); + else + add_AT_loc (decl_die, DW_AT_location, list->expr); add_AT_die_ref (subrange_die, bound_attr, decl_die); break; @@ -14610,12 +14908,12 @@ gen_array_type_die (tree type, dw_die_ref context_die) && DECL_P (TYPE_MAX_VALUE (TYPE_DOMAIN (type)))) { tree szdecl = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); - dw_loc_descr_ref loc = loc_descriptor_from_tree (szdecl); + dw_loc_list_ref loc = loc_list_from_tree (szdecl, 2); size = int_size_in_bytes (TREE_TYPE (szdecl)); if (loc && size > 0) { - add_AT_loc (array_die, DW_AT_string_length, loc); + add_AT_location_description (array_die, DW_AT_string_length, loc); if (size != DWARF2_ADDR_SIZE) add_AT_unsigned (array_die, DW_AT_byte_size, size); } @@ -14709,7 +15007,7 @@ descr_info_loc (tree val, tree base_decl) CASE_CONVERT: return descr_info_loc (TREE_OPERAND (val, 0), base_decl); case VAR_DECL: - return loc_descriptor_from_tree_1 (val, 0); + return loc_descriptor_from_tree (val, 0); case INTEGER_CST: if (host_integerp (val, 0)) return int_loc_descriptor (tree_low_cst (val, 0)); @@ -15015,7 +15313,7 @@ gen_formal_parameter_die (tree node, tree origin, dw_die_ref context_die) { tree type = TREE_TYPE (node); add_name_and_src_coords_attributes (parm_die, node); - if (DECL_BY_REFERENCE (node)) + if (decl_by_reference_p (node)) add_type_attribute (parm_die, TREE_TYPE (type), 0, 0, context_die); else @@ -15467,7 +15765,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) if (cfun->static_chain_decl) add_AT_location_description (subr_die, DW_AT_static_link, - loc_descriptor_from_tree (cfun->static_chain_decl)); + loc_list_from_tree (cfun->static_chain_decl, 2)); } /* Generate child dies for template paramaters. */ @@ -15637,7 +15935,7 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) { tree field; dw_die_ref com_die; - dw_loc_descr_ref loc; + dw_loc_list_ref loc; die_node com_die_arg; var_die = lookup_decl_die (decl_or_origin); @@ -15645,22 +15943,23 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) { if (get_AT (var_die, DW_AT_location) == NULL) { - loc = loc_descriptor_from_tree (com_decl); + loc = loc_list_from_tree (com_decl, off ? 1 : 2); if (loc) { if (off) { /* Optimize the common case. */ - if (loc->dw_loc_opc == DW_OP_addr - && loc->dw_loc_next == NULL - && GET_CODE (loc->dw_loc_oprnd1.v.val_addr) + if (single_element_loc_list_p (loc) + && loc->expr->dw_loc_opc == DW_OP_addr + && loc->expr->dw_loc_next == NULL + && GET_CODE (loc->expr->dw_loc_oprnd1.v.val_addr) == SYMBOL_REF) - loc->dw_loc_oprnd1.v.val_addr - = plus_constant (loc->dw_loc_oprnd1.v.val_addr, off); + loc->expr->dw_loc_oprnd1.v.val_addr + = plus_constant (loc->expr->dw_loc_oprnd1.v.val_addr, off); else - loc_descr_plus_const (&loc, off); + loc_list_plus_const (loc, off); } - add_AT_loc (var_die, DW_AT_location, loc); + add_AT_location_description (var_die, DW_AT_location, loc); remove_AT (var_die, DW_AT_declaration); } } @@ -15676,7 +15975,7 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) com_die_arg.decl_id = DECL_UID (com_decl); com_die_arg.die_parent = context_die; com_die = (dw_die_ref) htab_find (common_block_die_table, &com_die_arg); - loc = loc_descriptor_from_tree (com_decl); + loc = loc_list_from_tree (com_decl, 2); if (com_die == NULL) { const char *cnam @@ -15687,10 +15986,10 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) add_name_and_src_coords_attributes (com_die, com_decl); if (loc) { - add_AT_loc (com_die, DW_AT_location, loc); + add_AT_location_description (com_die, DW_AT_location, loc); /* Avoid sharing the same loc descriptor between DW_TAG_common_block and DW_TAG_variable. */ - loc = loc_descriptor_from_tree (com_decl); + loc = loc_list_from_tree (com_decl, 2); } else if (DECL_EXTERNAL (decl)) add_AT_flag (com_die, DW_AT_declaration, 1); @@ -15701,8 +16000,8 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) } else if (get_AT (com_die, DW_AT_location) == NULL && loc) { - add_AT_loc (com_die, DW_AT_location, loc); - loc = loc_descriptor_from_tree (com_decl); + add_AT_location_description (com_die, DW_AT_location, loc); + loc = loc_list_from_tree (com_decl, 2); remove_AT (com_die, DW_AT_declaration); } var_die = new_die (DW_TAG_variable, com_die, decl); @@ -15715,15 +16014,16 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) if (off) { /* Optimize the common case. */ - if (loc->dw_loc_opc == DW_OP_addr - && loc->dw_loc_next == NULL - && GET_CODE (loc->dw_loc_oprnd1.v.val_addr) == SYMBOL_REF) - loc->dw_loc_oprnd1.v.val_addr - = plus_constant (loc->dw_loc_oprnd1.v.val_addr, off); + if (single_element_loc_list_p (loc) + && loc->expr->dw_loc_opc == DW_OP_addr + && loc->expr->dw_loc_next == NULL + && GET_CODE (loc->expr->dw_loc_oprnd1.v.val_addr) == SYMBOL_REF) + loc->expr->dw_loc_oprnd1.v.val_addr + = plus_constant (loc->expr->dw_loc_oprnd1.v.val_addr, off); else - loc_descr_plus_const (&loc, off); + loc_list_plus_const (loc, off); } - add_AT_loc (var_die, DW_AT_location, loc); + add_AT_location_description (var_die, DW_AT_location, loc); } else if (DECL_EXTERNAL (decl)) add_AT_flag (var_die, DW_AT_declaration, 1); @@ -15786,10 +16086,7 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) tree type = TREE_TYPE (decl); add_name_and_src_coords_attributes (var_die, decl); - if ((TREE_CODE (decl) == PARM_DECL - || TREE_CODE (decl) == RESULT_DECL - || TREE_CODE (decl) == VAR_DECL) - && DECL_BY_REFERENCE (decl)) + if (decl_by_reference_p (decl)) add_type_attribute (var_die, TREE_TYPE (type), 0, 0, context_die); else add_type_attribute (var_die, type, TREE_READONLY (decl), @@ -17066,9 +17363,7 @@ gen_decl_die (tree decl, tree origin, dw_die_ref context_die) /* Output any DIEs that are needed to specify the type of this data object. */ - if ((TREE_CODE (decl_or_origin) == RESULT_DECL - || TREE_CODE (decl_or_origin) == VAR_DECL) - && DECL_BY_REFERENCE (decl_or_origin)) + if (decl_by_reference_p (decl_or_origin)) gen_type_die (TREE_TYPE (TREE_TYPE (decl_or_origin)), context_die); else gen_type_die (TREE_TYPE (decl_or_origin), context_die); |