On 10/07/2014 10:29 AM, Jakub Jelinek wrote:
But isn't there a risk that you will have PLACEHOLDER_EXPRs (likely for Ada only) in some trees not constructed by the langhook? I mean, DW_OP_push_object_address isn't meaningful in all DWARF contexts, in some it is forbidden, in others there is really no object to push, and as implemented, you emit DW_OP_push_object_address (which emits the address of a context related particular object) for any kind of PLACEHOLDER_EXPR with RECORD_TYPE.
Even with GNAT, this is not _supposed_ to happen. However during the development (for instance with LTO) I noticed cases where PLACEHOLDER_EXPR nodes were incorrectly used. Thanks to current work on the early debug info pass, such cases are doomed to disappear, but I completely agree with your point, so thank you for raising it. :-)
Thus, I'd feel safer, even if you decide to use a PLACEHOLDER_EXPR, that the translation of that to DW_OP_push_object_address would be done only if the PLACEHOLDER_EXPR is equal to some global variable, normally NULL, and only changed temporarily while emitting loc for the array descriptor.
This is what the updated (and attached) patch does. Note that upcoming patches will enhance loc_list_from_tree (adding another parameter to loc_list_from_tree) and make it recurse to generate sub-expressions as DWARF procedures. Because of this kind recursion, I added a composite argument instead of relying on a global variable (so that "nested" contexts can exist at the same time).
But then IMHO a DEBUG_EXPR_DECL is better. [...] Also, please verify that with your patch the generated debug info for some Fortran arrays is the same.
It's fortunate that you asked this since I wrongly assumed there was the corresponding testing in the GDB testsuite. As a matter of fact, support for Fortran's variable length arrays in GDB is still a work in progress so tests are not commited yet. So I used the Fortran example I could find there <http://intel-gdb.github.io/> instead and discovered that my patch did break debugging information for Fortran array types.
Fixing it while keeping a PLACEHOLDER_EXPR-based implementation seems a too heavy task for my little experience in the Fortran front-end and after having a closer look I agree with you: it seems less adapted to how things are currently done, there. So I finally leveraged this new composite argument to re-introduce the base_decl mechanism. DEBUG_EXPR_DECL is back in the Fortran front-end. ;-) Now, the same example keeps the same debugging information.
The latest patches bootstrapped well and passed successfully the GCC testsuite on x86_64-pc-linux-gnu.
-- Pierre-Marie de Rodat
>From 794cafffae7202cd9ea8156bb7f7433a4e109e6c Mon Sep 17 00:00:00 2001 From: Pierre-Marie de Rodat <dero...@adacore.com> Date: Mon, 9 Jun 2014 15:13:45 +0200 Subject: [PATCH 5/5] dwarf2out.c: do not short-circuit add_bound_info in array descr. lang-hook gcc/ * dwarf2out.h (struct array_descr_info): Remove the base_decl field. * dwarf2out.c (enum dw_scalar_form): New. (struct loc_descr_context): New. (add_scalar_info): New. (add_bound_info): Add a context parameter. Use add_scalar_info. (loc_list_from_tree): Add a context parameter. Handle PLACEHOLDER_EXPR nodes for type-related expressions. Likewise for base declarations. (loc_descriptor_from_tree): Add a context parameter. (subrange_type_die): Update calls to add_bound_info. (tls_mem_loc_descriptor): Likewise. (loc_list_for_address_of_addr_expr_of_indirect_ref): Add a context parameter. Update calls to loc_list_from_tree. (add_subscript_info): Update calls to add_bound_info. (gen_array_type_die): Update calls to loc_list_from_tree and to add_bound_info. (descr_info_loc): Remove. (add_descr_info_field): Remove. (gen_descr_array_type_die): Switch add_descr_info_field calls into add_scalar_info/add_bound_info ones. (gen_subprogram_die): Update calls to loc_list_from_tree. (gen_variable_die): Likewise. --- gcc/dwarf2out.c | 569 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 294 insertions(+), 275 deletions(-) diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 3f3bdbb..30f429e 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -2981,6 +2981,15 @@ static bool frame_pointer_fb_offset_valid; static vec<dw_die_ref> base_types; +/* Flags to represent a set of attribute classes for attributes that represent + a scalar value (bounds, pointers, ...). */ +enum dw_scalar_form +{ + dw_scalar_form_constant = 0x01, + dw_scalar_form_exprloc = 0x02, + dw_scalar_form_reference = 0x04 +}; + /* Forward declarations for functions defined in this file. */ static int is_pseudo_reg (const_rtx); @@ -3163,8 +3172,11 @@ 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_list_ref loc_list_from_tree (tree, int); -static dw_loc_descr_ref loc_descriptor_from_tree (tree, int); +struct loc_descr_context; +static dw_loc_list_ref loc_list_from_tree (tree, int, + const struct loc_descr_context *); +static dw_loc_descr_ref loc_descriptor_from_tree (tree, int, + const struct loc_descr_context *); 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); @@ -3186,7 +3198,10 @@ static bool tree_add_const_value_attribute_for_decl (dw_die_ref, tree); static void add_name_attribute (dw_die_ref, const char *); static void add_gnat_descriptive_type_attribute (dw_die_ref, tree, dw_die_ref); static void add_comp_dir_attribute (dw_die_ref); -static void add_bound_info (dw_die_ref, enum dwarf_attribute, tree); +static void add_scalar_info (dw_die_ref, enum dwarf_attribute, tree, int, + const struct loc_descr_context *); +static void add_bound_info (dw_die_ref, enum dwarf_attribute, tree, + const struct loc_descr_context *); static void add_subscript_info (dw_die_ref, tree, bool); static void add_byte_size_attribute (dw_die_ref, tree); static void add_bit_offset_attribute (dw_die_ref, tree); @@ -10515,9 +10530,9 @@ subrange_type_die (tree type, tree low, tree high, dw_die_ref context_die) } if (low) - add_bound_info (subrange_die, DW_AT_lower_bound, low); + add_bound_info (subrange_die, DW_AT_lower_bound, low, NULL); if (high) - add_bound_info (subrange_die, DW_AT_upper_bound, high); + add_bound_info (subrange_die, DW_AT_upper_bound, high, NULL); return subrange_die; } @@ -11493,7 +11508,7 @@ tls_mem_loc_descriptor (rtx mem) || !DECL_THREAD_LOCAL_P (base)) return NULL; - loc_result = loc_descriptor_from_tree (MEM_EXPR (mem), 1); + loc_result = loc_descriptor_from_tree (MEM_EXPR (mem), 1, NULL); if (loc_result == NULL) return NULL; @@ -14231,10 +14246,13 @@ cst_pool_loc_descr (tree loc) /* Return dw_loc_list representing address of addr_expr LOC by looking for inner INDIRECT_REF expression and turning - it into simple arithmetics. */ + it into simple arithmetics. + + See loc_list_from_tree for the meaning of CONTEXT. */ static dw_loc_list_ref -loc_list_for_address_of_addr_expr_of_indirect_ref (tree loc, bool toplev) +loc_list_for_address_of_addr_expr_of_indirect_ref (tree loc, bool toplev, + const loc_descr_context *context) { tree obj, offset; HOST_WIDE_INT bitsize, bitpos, bytepos; @@ -14258,18 +14276,19 @@ loc_list_for_address_of_addr_expr_of_indirect_ref (tree loc, bool toplev) return 0; } if (!offset && !bitpos) - list_ret = loc_list_from_tree (TREE_OPERAND (obj, 0), toplev ? 2 : 1); + list_ret = loc_list_from_tree (TREE_OPERAND (obj, 0), toplev ? 2 : 1, + context); else if (toplev && int_size_in_bytes (TREE_TYPE (loc)) <= DWARF2_ADDR_SIZE && (dwarf_version >= 4 || !dwarf_strict)) { - list_ret = loc_list_from_tree (TREE_OPERAND (obj, 0), 0); + list_ret = loc_list_from_tree (TREE_OPERAND (obj, 0), 0, context); if (!list_ret) return 0; if (offset) { /* Variable offset. */ - list_ret1 = loc_list_from_tree (offset, 0); + list_ret1 = loc_list_from_tree (offset, 0, context); if (list_ret1 == 0) return 0; add_loc_list (&list_ret, list_ret1); @@ -14292,15 +14311,36 @@ loc_list_for_address_of_addr_expr_of_indirect_ref (tree loc, bool toplev) } +/* Helper structure for location descriptions generation. */ +struct loc_descr_context +{ + /* The type that is implicitely referenced by DW_OP_push_object_address, or + NULL_TREE if DW_OP_push_object_address in invalid for this location + description. This is used when processing PLACEHOLDER_EXPR nodes. */ + tree context_type; + /* The ..._DECL node that should be translated as a + DW_OP_push_object_address operation. */ + tree base_decl; +}; + /* 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). */ + to refer to register values). + + CONTEXT provides information to customize the location descriptions + generation. Its context_type field specifies what type is implicitely + referenced by DW_OP_push_object_address. If it is NULL_TREE, this operation + will not be generated. + + If CONTEXT is NULL, the behavior is the same as if the context_type field + was NULL_TREE. */ static dw_loc_list_ref -loc_list_from_tree (tree loc, int want_address) +loc_list_from_tree (tree loc, int want_address, + const struct loc_descr_context *context) { dw_loc_descr_ref ret = NULL, ret1 = NULL; dw_loc_list_ref list_ret = NULL, list_ret1 = NULL; @@ -14311,6 +14351,12 @@ loc_list_from_tree (tree loc, int want_address) extending the values properly. Hopefully this won't be a real problem... */ + if (context != NULL + && context->base_decl == loc + && want_address == 0) + return new_loc_list (new_loc_descr (DW_OP_push_object_address, 0, 0), + NULL, NULL, NULL); + switch (TREE_CODE (loc)) { case ERROR_MARK: @@ -14319,11 +14365,26 @@ loc_list_from_tree (tree loc, int want_address) case PLACEHOLDER_EXPR: /* This case involves extracting fields from an object to determine the - 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; + position of other fields. It is supposed to appear only as the first + operand of COMPONENT_REF nodes and to reference precisely the type + that the context allows. */ + if (context != NULL + && TREE_TYPE (loc) == context->context_type + && want_address >= 1) + { + if (dwarf_version >= 3 || !dwarf_strict) + { + ret = new_loc_descr (DW_OP_push_object_address, 0, 0); + have_address = 1; + break; + } + else + return NULL; + } + else + expansion_failed (loc, NULL_RTX, + "PLACEHOLDER_EXPR for a unexpected type"); + break; case CALL_EXPR: expansion_failed (loc, NULL_RTX, "CALL_EXPR"); @@ -14344,7 +14405,7 @@ loc_list_from_tree (tree loc, int want_address) if (want_address) { list_ret = loc_list_for_address_of_addr_expr_of_indirect_ref - (loc, want_address == 2); + (loc, want_address == 2, context); if (list_ret) have_address = 1; else if (decl_address_ip_invariant_p (TREE_OPERAND (loc, 0)) @@ -14353,7 +14414,7 @@ loc_list_from_tree (tree loc, int want_address) } /* Otherwise, process the argument and look for the address. */ if (!list_ret && !ret) - list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 1); + list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 1, context); else { if (want_address) @@ -14423,7 +14484,7 @@ loc_list_from_tree (tree loc, int want_address) case RESULT_DECL: if (DECL_HAS_VALUE_EXPR_P (loc)) return loc_list_from_tree (DECL_VALUE_EXPR (loc), - want_address); + want_address, context); /* FALLTHRU */ case FUNCTION_DECL: @@ -14497,7 +14558,7 @@ loc_list_from_tree (tree loc, int want_address) } /* Fallthru. */ case INDIRECT_REF: - list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0); + list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0, context); have_address = 1; break; @@ -14506,13 +14567,13 @@ loc_list_from_tree (tree loc, int want_address) return NULL; case COMPOUND_EXPR: - return loc_list_from_tree (TREE_OPERAND (loc, 1), want_address); + return loc_list_from_tree (TREE_OPERAND (loc, 1), want_address, context); CASE_CONVERT: case VIEW_CONVERT_EXPR: case SAVE_EXPR: case MODIFY_EXPR: - return loc_list_from_tree (TREE_OPERAND (loc, 0), want_address); + return loc_list_from_tree (TREE_OPERAND (loc, 0), want_address, context); case COMPONENT_REF: case BIT_FIELD_REF: @@ -14533,7 +14594,8 @@ loc_list_from_tree (tree loc, int want_address) list_ret = loc_list_from_tree (obj, want_address == 2 - && !bitpos && !offset ? 2 : 1); + && !bitpos && !offset ? 2 : 1, + context); /* TODO: We can extract value of the small expression via shifting even for nonzero bitpos. */ if (list_ret == 0) @@ -14548,7 +14610,7 @@ loc_list_from_tree (tree loc, int want_address) if (offset != NULL_TREE) { /* Variable offset. */ - list_ret1 = loc_list_from_tree (offset, 0); + list_ret1 = loc_list_from_tree (offset, 0, context); if (list_ret1 == 0) return 0; add_loc_list (&list_ret, list_ret1); @@ -14638,8 +14700,8 @@ loc_list_from_tree (tree loc, int want_address) op = DW_OP_mod; goto do_binop; } - list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0); - list_ret1 = loc_list_from_tree (TREE_OPERAND (loc, 1), 0); + list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0, context); + list_ret1 = loc_list_from_tree (TREE_OPERAND (loc, 1), 0, context); if (list_ret == 0 || list_ret1 == 0) return 0; @@ -14670,7 +14732,7 @@ loc_list_from_tree (tree loc, int want_address) do_plus: if (tree_fits_shwi_p (TREE_OPERAND (loc, 1))) { - list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0); + list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0, context); if (list_ret == 0) return 0; @@ -14718,8 +14780,8 @@ loc_list_from_tree (tree loc, int want_address) goto do_binop; do_binop: - list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0); - list_ret1 = loc_list_from_tree (TREE_OPERAND (loc, 1), 0); + list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0, context); + list_ret1 = loc_list_from_tree (TREE_OPERAND (loc, 1), 0, context); if (list_ret == 0 || list_ret1 == 0) return 0; @@ -14743,7 +14805,7 @@ loc_list_from_tree (tree loc, int want_address) goto do_unop; do_unop: - list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0); + list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0, context); if (list_ret == 0) return 0; @@ -14767,12 +14829,12 @@ loc_list_from_tree (tree loc, int want_address) case COND_EXPR: { dw_loc_descr_ref lhs - = loc_descriptor_from_tree (TREE_OPERAND (loc, 1), 0); + = loc_descriptor_from_tree (TREE_OPERAND (loc, 1), 0, context); dw_loc_list_ref rhs - = loc_list_from_tree (TREE_OPERAND (loc, 2), 0); + = loc_list_from_tree (TREE_OPERAND (loc, 2), 0, context); dw_loc_descr_ref bra_node, jump_node, tmp; - list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0); + list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0, context); if (list_ret == 0 || lhs == 0 || rhs == 0) return 0; @@ -14878,9 +14940,10 @@ loc_list_from_tree (tree loc, int want_address) /* Same as above but return only single location expression. */ static dw_loc_descr_ref -loc_descriptor_from_tree (tree loc, int want_address) +loc_descriptor_from_tree (tree loc, int want_address, + const struct loc_descr_context *context) { - dw_loc_list_ref ret = loc_list_from_tree (loc, want_address); + dw_loc_list_ref ret = loc_list_from_tree (loc, want_address, context); if (!ret) return NULL; if (ret->dw_loc_next) @@ -15940,7 +16003,8 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl, bool cache_p, } if (list == NULL) { - list = loc_list_from_tree (decl, decl_by_reference_p (decl) ? 0 : 2); + list = loc_list_from_tree (decl, decl_by_reference_p (decl) ? 0 : 2, + NULL); /* It is usually worth caching this result if the decl is from BLOCK_NONLOCALIZED_VARS and if the list has at least two elements. */ if (cache_p && list && list->dw_loc_next) @@ -16432,6 +16496,142 @@ add_comp_dir_attribute (dw_die_ref die) add_AT_string (die, DW_AT_comp_dir, wd); } +/* Given a tree node VALUE describing a scalar attribute ATTR (i.e. a bound, a + pointer computation, ...), output a representation for that bound according + to the accepted FORMS (see enum dw_scalar_form) and add it to DIE. See + loc_list_from_tree for the meaning of CONTEXT. */ + +static void +add_scalar_info (dw_die_ref die, enum dwarf_attribute attr, tree value, + int forms, const struct loc_descr_context *context) +{ + dw_die_ref ctx, decl_die; + dw_loc_list_ref list; + + bool strip_conversions = true; + + while (strip_conversions) + switch (TREE_CODE (value)) + { + case ERROR_MARK: + case SAVE_EXPR: + return; + + CASE_CONVERT: + case VIEW_CONVERT_EXPR: + value = TREE_OPERAND (value, 0); + break; + + default: + strip_conversions = false; + break; + } + + /* If possible and permitted, output the attribute as a constant. */ + if ((forms & dw_scalar_form_constant) != 0 + && TREE_CODE (value) == INTEGER_CST) + { + unsigned int prec = simple_type_size_in_bits (TREE_TYPE (value)); + + /* If HOST_WIDE_INT is big enough then represent the bound as + a constant value. We need to choose a form based on + whether the type is signed or unsigned. We cannot just + call add_AT_unsigned if the value itself is positive + (add_AT_unsigned might add the unsigned value encoded as + DW_FORM_data[1248]). Some DWARF consumers will lookup the + bounds type and then sign extend any unsigned values found + for signed types. This is needed only for + DW_AT_{lower,upper}_bound, since for most other attributes, + consumers will treat DW_FORM_data[1248] as unsigned values, + regardless of the underlying type. */ + if (prec <= HOST_BITS_PER_WIDE_INT + || tree_fits_uhwi_p (value)) + { + if (TYPE_UNSIGNED (TREE_TYPE (value))) + add_AT_unsigned (die, attr, TREE_INT_CST_LOW (value)); + else + add_AT_int (die, attr, TREE_INT_CST_LOW (value)); + } + else + /* Otherwise represent the bound as an unsigned value with + the precision of its type. The precision and signedness + of the type will be necessary to re-interpret it + unambiguously. */ + add_AT_wide (die, attr, value); + } + + /* Otherwise, if it's possible and permitted too, output a reference to + another DIE. */ + if ((forms & dw_scalar_form_reference) != 0) + { + tree decl = NULL_TREE; + + /* Some type attributes reference an outer type. For instance, the upper + bound of an array may reference an embedding record (this happens in + Ada). */ + if (TREE_CODE (value) == COMPONENT_REF + && TREE_CODE (TREE_OPERAND (value, 0)) == PLACEHOLDER_EXPR + && TREE_CODE (TREE_OPERAND (value, 1)) == FIELD_DECL) + decl = TREE_OPERAND (value, 1); + + else if (TREE_CODE (value) == VAR_DECL + || TREE_CODE (value) == PARM_DECL + || TREE_CODE (value) == RESULT_DECL) + decl = value; + + if (decl != NULL_TREE) + { + dw_die_ref decl_die = lookup_decl_die (decl); + + /* ??? Can this happen, or should the variable have been bound + first? Probably it can, since I imagine that we try to create + the types of parameters in the order in which they exist in + the list, and won't have created a forward reference to a + later parameter. */ + if (decl_die != NULL) + { + add_AT_die_ref (die, attr, decl_die); + return; + } + } + } + + /* Last chance: try to create a stack operation procedure to evaluate the + value. Do nothing if even that is not possible or permitted. */ + if ((forms & dw_scalar_form_exprloc) == 0) + return; + + list = loc_list_from_tree (value, 2, context); + if (list == NULL || single_element_loc_list_p (list)) + { + /* If this attribute is not a reference nor constant, it is + a DWARF expression rather than location description. For that + loc_list_from_tree (value, 0, &context) is needed. */ + dw_loc_list_ref list2 = loc_list_from_tree (value, 0, context); + if (list2 && single_element_loc_list_p (list2)) + { + add_AT_loc (die, attr, list2->expr); + return; + } + } + + /* If that failed to give a single element location list, fall back to + outputting this as a reference... still if permitted. */ + if (list == NULL || (forms & dw_scalar_form_reference) == 0) + return; + + if (current_function_decl == 0) + ctx = comp_unit_die (); + else + ctx = lookup_decl_die (current_function_decl); + + decl_die = new_die (DW_TAG_variable, ctx, value); + add_AT_flag (decl_die, DW_AT_artificial, 1); + add_type_attribute (decl_die, TREE_TYPE (value), TYPE_QUAL_CONST, ctx); + add_AT_location_description (decl_die, DW_AT_location, list); + add_AT_die_ref (die, attr, decl_die); +} + /* Return the default for DW_AT_lower_bound, or -1 if there is not any default. */ @@ -16473,121 +16673,41 @@ lower_bound_default (void) a representation for that bound. */ static void -add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree bound) +add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, + tree bound, const struct loc_descr_context *context) { - switch (TREE_CODE (bound)) - { - case ERROR_MARK: - return; + int dflt; - /* All fixed-bounds are represented by INTEGER_CST nodes. */ - case INTEGER_CST: + while (1) + switch (TREE_CODE (bound)) { - unsigned int prec = simple_type_size_in_bits (TREE_TYPE (bound)); - int dflt; + /* Strip all conversions. */ + CASE_CONVERT: + case VIEW_CONVERT_EXPR: + bound = TREE_OPERAND (bound, 0); + break; - /* Use the default if possible. */ + /* All fixed-bounds are represented by INTEGER_CST nodes. Lower bounds + are even omitted when they are the default. */ + case INTEGER_CST: + /* If the value for this bound is the default one, we can even omit the + attribute. */ if (bound_attr == DW_AT_lower_bound && tree_fits_shwi_p (bound) && (dflt = lower_bound_default ()) != -1 && tree_to_shwi (bound) == dflt) - ; - - /* If HOST_WIDE_INT is big enough then represent the bound as - a constant value. We need to choose a form based on - whether the type is signed or unsigned. We cannot just - call add_AT_unsigned if the value itself is positive - (add_AT_unsigned might add the unsigned value encoded as - DW_FORM_data[1248]). Some DWARF consumers will lookup the - bounds type and then sign extend any unsigned values found - for signed types. This is needed only for - DW_AT_{lower,upper}_bound, since for most other attributes, - consumers will treat DW_FORM_data[1248] as unsigned values, - regardless of the underlying type. */ - else if (prec <= HOST_BITS_PER_WIDE_INT - || tree_fits_uhwi_p (bound)) - { - if (TYPE_UNSIGNED (TREE_TYPE (bound))) - add_AT_unsigned (subrange_die, bound_attr, - TREE_INT_CST_LOW (bound)); - else - add_AT_int (subrange_die, bound_attr, TREE_INT_CST_LOW (bound)); - } - else - /* Otherwise represent the bound as an unsigned value with - the precision of its type. The precision and signedness - of the type will be necessary to re-interpret it - unambiguously. */ - add_AT_wide (subrange_die, bound_attr, bound); - } - break; - - CASE_CONVERT: - case VIEW_CONVERT_EXPR: - add_bound_info (subrange_die, bound_attr, TREE_OPERAND (bound, 0)); - break; - - case SAVE_EXPR: - break; - - case VAR_DECL: - case PARM_DECL: - case RESULT_DECL: - { - dw_die_ref decl_die = lookup_decl_die (bound); - - /* ??? Can this happen, or should the variable have been bound - first? Probably it can, since I imagine that we try to create - the types of parameters in the order in which they exist in - the list, and won't have created a forward reference to a - later parameter. */ - if (decl_die != NULL) - { - add_AT_die_ref (subrange_die, bound_attr, decl_die); - break; - } - } - /* FALLTHRU */ - - default: - { - /* Otherwise try to create a stack operation procedure to - evaluate the value of the array bound. */ - - dw_die_ref ctx, decl_die; - dw_loc_list_ref list; - - list = loc_list_from_tree (bound, 2); - if (list == NULL || single_element_loc_list_p (list)) - { - /* If DW_AT_*bound is not a reference nor constant, it is - a DWARF expression rather than location description. - For that loc_list_from_tree (bound, 0) is needed. - If that fails to give a single element list, - fall back to outputting this as a reference anyway. */ - dw_loc_list_ref list2 = loc_list_from_tree (bound, 0); - if (list2 && single_element_loc_list_p (list2)) - { - add_AT_loc (subrange_die, bound_attr, list2->expr); - break; - } - } - if (list == NULL) - break; + return; - if (current_function_decl == 0) - ctx = comp_unit_die (); - else - ctx = lookup_decl_die (current_function_decl); + /* FALLTHRU */ - 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), TYPE_QUAL_CONST, ctx); - add_AT_location_description (decl_die, DW_AT_location, list); - add_AT_die_ref (subrange_die, bound_attr, decl_die); - break; + default: + add_scalar_info (subrange_die, bound_attr, bound, + dw_scalar_form_constant + | dw_scalar_form_exprloc + | dw_scalar_form_reference, + context); + return; } - } } /* Add subscript info to TYPE_DIE, describing an array TYPE, collapsing @@ -16644,9 +16764,9 @@ add_subscript_info (dw_die_ref type_die, tree type, bool collapse_p) to produce useful results, go ahead and output the lower bound solo, and hope the debugger can cope. */ - add_bound_info (subrange_die, DW_AT_lower_bound, lower); + add_bound_info (subrange_die, DW_AT_lower_bound, lower, NULL); if (upper) - add_bound_info (subrange_die, DW_AT_upper_bound, upper); + add_bound_info (subrange_die, DW_AT_upper_bound, upper, NULL); } /* Otherwise we have an array type with an unspecified length. The @@ -17305,7 +17425,7 @@ 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_list_ref loc = loc_list_from_tree (szdecl, 2); + dw_loc_list_ref loc = loc_list_from_tree (szdecl, 2, NULL); size = int_size_in_bytes (TREE_TYPE (szdecl)); if (loc && size > 0) @@ -17347,9 +17467,9 @@ gen_array_type_die (tree type, dw_die_ref context_die) { /* For VECTOR_TYPEs we use an array die with appropriate bounds. */ dw_die_ref subrange_die = new_die (DW_TAG_subrange_type, array_die, NULL); - add_bound_info (subrange_die, DW_AT_lower_bound, size_zero_node); + add_bound_info (subrange_die, DW_AT_lower_bound, size_zero_node, NULL); add_bound_info (subrange_die, DW_AT_upper_bound, - size_int (TYPE_VECTOR_SUBPARTS (type) - 1)); + size_int (TYPE_VECTOR_SUBPARTS (type) - 1), NULL); } else add_subscript_info (array_die, type, collapse_nested_arrays); @@ -17375,99 +17495,6 @@ gen_array_type_die (tree type, dw_die_ref context_die) add_pubtype (type, array_die); } -static dw_loc_descr_ref -descr_info_loc (tree val, tree base_decl) -{ - HOST_WIDE_INT size; - dw_loc_descr_ref loc, loc2; - enum dwarf_location_atom op; - - if (val == base_decl) - return new_loc_descr (DW_OP_push_object_address, 0, 0); - - switch (TREE_CODE (val)) - { - CASE_CONVERT: - return descr_info_loc (TREE_OPERAND (val, 0), base_decl); - case VAR_DECL: - return loc_descriptor_from_tree (val, 0); - case INTEGER_CST: - if (tree_fits_shwi_p (val)) - return int_loc_descriptor (tree_to_shwi (val)); - break; - case INDIRECT_REF: - size = int_size_in_bytes (TREE_TYPE (val)); - if (size < 0) - break; - loc = descr_info_loc (TREE_OPERAND (val, 0), base_decl); - if (!loc) - break; - if (size == DWARF2_ADDR_SIZE) - add_loc_descr (&loc, new_loc_descr (DW_OP_deref, 0, 0)); - else - add_loc_descr (&loc, new_loc_descr (DW_OP_deref_size, size, 0)); - return loc; - case POINTER_PLUS_EXPR: - case PLUS_EXPR: - if (tree_fits_uhwi_p (TREE_OPERAND (val, 1)) - && tree_to_uhwi (TREE_OPERAND (val, 1)) < 16384) - { - loc = descr_info_loc (TREE_OPERAND (val, 0), base_decl); - if (!loc) - break; - loc_descr_plus_const (&loc, tree_to_shwi (TREE_OPERAND (val, 1))); - } - else - { - op = DW_OP_plus; - do_binop: - loc = descr_info_loc (TREE_OPERAND (val, 0), base_decl); - if (!loc) - break; - loc2 = descr_info_loc (TREE_OPERAND (val, 1), base_decl); - if (!loc2) - break; - add_loc_descr (&loc, loc2); - add_loc_descr (&loc2, new_loc_descr (op, 0, 0)); - } - return loc; - case MINUS_EXPR: - op = DW_OP_minus; - goto do_binop; - case MULT_EXPR: - op = DW_OP_mul; - goto do_binop; - case EQ_EXPR: - op = DW_OP_eq; - goto do_binop; - case NE_EXPR: - op = DW_OP_ne; - goto do_binop; - default: - break; - } - return NULL; -} - -static void -add_descr_info_field (dw_die_ref die, enum dwarf_attribute attr, - tree val, tree base_decl) -{ - dw_loc_descr_ref loc; - - if (tree_fits_shwi_p (val)) - { - add_AT_unsigned (die, attr, tree_to_shwi (val)); - return; - } - - loc = descr_info_loc (val, base_decl); - if (!loc) - return; - - add_AT_loc (die, attr, loc); -} - /* This routine generates DIE for array with hidden descriptor, details are filled into *info by a langhook. */ @@ -17477,6 +17504,7 @@ gen_descr_array_type_die (tree type, struct array_descr_info *info, { const dw_die_ref scope_die = scope_die_for (type, context_die); const dw_die_ref array_die = new_die (DW_TAG_array_type, scope_die, type); + const struct loc_descr_context context = { type, info->base_decl }; int dim; add_name_attribute (array_die, type_tag (type)); @@ -17498,15 +17526,18 @@ gen_descr_array_type_die (tree type, struct array_descr_info *info, if (dwarf_version >= 3 || !dwarf_strict) { if (info->data_location) - add_descr_info_field (array_die, DW_AT_data_location, - info->data_location, - info->base_decl); + add_scalar_info (array_die, DW_AT_data_location, info->data_location, + dw_scalar_form_exprloc, &context); if (info->associated) - add_descr_info_field (array_die, DW_AT_associated, info->associated, - info->base_decl); + add_scalar_info (array_die, DW_AT_associated, info->associated, + dw_scalar_form_constant + | dw_scalar_form_exprloc + | dw_scalar_form_reference, &context); if (info->allocated) - add_descr_info_field (array_die, DW_AT_allocated, info->allocated, - info->base_decl); + add_scalar_info (array_die, DW_AT_allocated, info->allocated, + dw_scalar_form_constant + | dw_scalar_form_exprloc + | dw_scalar_form_reference, &context); } add_gnat_descriptive_type_attribute (array_die, type, context_die); @@ -17521,30 +17552,18 @@ gen_descr_array_type_die (tree type, struct array_descr_info *info, info->dimen[dim].bounds_type, 0, context_die); if (info->dimen[dim].lower_bound) - { - /* If it is the default value, omit it. */ - int dflt; - - if (tree_fits_shwi_p (info->dimen[dim].lower_bound) - && (dflt = lower_bound_default ()) != -1 - && tree_to_shwi (info->dimen[dim].lower_bound) == dflt) - ; - else - add_descr_info_field (subrange_die, DW_AT_lower_bound, - info->dimen[dim].lower_bound, - info->base_decl); - } + add_bound_info (subrange_die, DW_AT_lower_bound, + info->dimen[dim].lower_bound, &context); if (info->dimen[dim].upper_bound) - add_descr_info_field (subrange_die, DW_AT_upper_bound, - info->dimen[dim].upper_bound, - info->base_decl); - if (dwarf_version >= 3 || !dwarf_strict) - { - if (info->dimen[dim].stride) - add_descr_info_field (subrange_die, DW_AT_byte_stride, - info->dimen[dim].stride, - info->base_decl); - } + add_bound_info (subrange_die, DW_AT_upper_bound, + info->dimen[dim].upper_bound, &context); + if ((dwarf_version >= 3 || !dwarf_strict) && info->dimen[dim].stride) + add_scalar_info (subrange_die, DW_AT_byte_stride, + info->dimen[dim].stride, + dw_scalar_form_constant + | dw_scalar_form_exprloc + | dw_scalar_form_reference, + &context); } gen_type_die (info->element_type, context_die); @@ -18602,7 +18621,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) if (fun->static_chain_decl) add_AT_location_description (subr_die, DW_AT_static_link, - loc_list_from_tree (fun->static_chain_decl, 2)); + loc_list_from_tree (fun->static_chain_decl, 2, NULL)); } /* Generate child dies for template paramaters. */ @@ -18933,7 +18952,7 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) { if (get_AT (var_die, DW_AT_location) == NULL) { - loc = loc_list_from_tree (com_decl, off ? 1 : 2); + loc = loc_list_from_tree (com_decl, off ? 1 : 2, NULL); if (loc) { if (off) @@ -18967,7 +18986,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_list_from_tree (com_decl, 2); + loc = loc_list_from_tree (com_decl, 2, NULL); if (com_die == NULL) { const char *cnam @@ -18981,7 +19000,7 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) 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_list_from_tree (com_decl, 2); + loc = loc_list_from_tree (com_decl, 2, NULL); } else if (DECL_EXTERNAL (decl)) add_AT_flag (com_die, DW_AT_declaration, 1); @@ -18994,7 +19013,7 @@ 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_location_description (com_die, DW_AT_location, loc); - loc = loc_list_from_tree (com_decl, 2); + loc = loc_list_from_tree (com_decl, 2, NULL); remove_AT (com_die, DW_AT_declaration); } var_die = new_die (DW_TAG_variable, com_die, decl); -- 1.7.10.4