This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] Emit Fortran PARAMETERs as DW_TAG_constant into debuginfo
I confirm the patch below is the source of the Ada bootstrap failure:
rev 139779 works and rev 139781 fails.
Laurent
On Sat, 2008-08-30 at 12:07 +0200, Laurent GUERBY wrote:
> Hi,
>
> Ada currently fails to bootstrap on x86_64-linux at rev 139798
>
> /home/guerby/build03/./prev-gcc/xgcc -B/home/guerby/build03/./prev-gcc/ -B/n/17/guerby/install03/x86_64-unknown-linux-gnu/bin/ -c -g -O2 -gnatpg -gnata -nostdinc -I- -I. -Iada -I../../trunk/gcc/ada -I../../trunk/gcc/ada/gcc-interface ../../trunk/gcc/ada/exp_attr.adb -o ada/exp_attr.o
> +===========================GNAT BUG DETECTED==============================+
> | 4.4.0 20080830 (experimental) [trunk revision 139798] (x86_64-unknown-linux-gnu) GCC error:|
> | in native_encode_initializer, at dwarf2out.c:11869 |
> | Error detected around ../../trunk/gcc/ada/eval_fat.adb:898 |
>
> Since your patch touches native_encode_initializer it might be
> the culprit, did you enable Ada during your test?
>
> Thanks in advance,
>
> Laurent
>
> On Tue, 2008-08-26 at 14:45 -0400, Jakub Jelinek wrote:
> > Hi!
> >
> > This patch emits Fortran PARAMETERs as DW_TAG_constant and unreferenced
> > non-use-associated variables with initializers as DW_TAG_variable with
> > DW_AT_const_value.
> >
> > Regtested on x86_64-linux, ok for trunk?
> >
> > 2008-08-26 Jakub Jelinek <jakub@redhat.com>
> >
> > * dwarf2out.c (gen_const_die): New function.
> > (size_of_die, value_format, output_die): Output larger
> > dw_val_class_vec using DW_FORM_block2 or DW_FORM_block4.
> > (native_encode_initializer): New function.
> > (tree_add_const_value_attribute): Call it.
> > (gen_decl_die, dwarf2out_decl): Handle CONST_DECLs if is_fortran ().
> >
> > * trans-decl.c (check_constant_initializer,
> > gfc_emit_parameter_debug_info): New functions.
> > (gfc_generate_module_vars, gfc_generate_function_code): Emit
> > PARAMETERs and unreferenced variables with initializers into
> > debug info.
> >
> > --- gcc/fortran/trans-decl.c.jj 2008-08-25 13:16:17.000000000 +0200
> > +++ gcc/fortran/trans-decl.c 2008-08-26 19:22:55.000000000 +0200
> > @@ -3232,6 +3232,134 @@ gfc_trans_use_stmts (gfc_namespace * ns)
> > }
> >
> >
> > +/* Return true if expr is a constant initializer that gfc_conv_initializer
> > + will handle. */
> > +
> > +static bool
> > +check_constant_initializer (gfc_expr *expr, gfc_typespec *ts, bool array,
> > + bool pointer)
> > +{
> > + gfc_constructor *c;
> > + gfc_component *cm;
> > +
> > + if (pointer)
> > + return true;
> > + else if (array)
> > + {
> > + if (expr->expr_type == EXPR_CONSTANT || expr->expr_type == EXPR_NULL)
> > + return true;
> > + else if (expr->expr_type == EXPR_STRUCTURE)
> > + return check_constant_initializer (expr, ts, false, false);
> > + else if (expr->expr_type != EXPR_ARRAY)
> > + return false;
> > + for (c = expr->value.constructor; c; c = c->next)
> > + {
> > + if (c->iterator)
> > + return false;
> > + if (c->expr->expr_type == EXPR_STRUCTURE)
> > + {
> > + if (!check_constant_initializer (c->expr, ts, false, false))
> > + return false;
> > + }
> > + else if (c->expr->expr_type != EXPR_CONSTANT)
> > + return false;
> > + }
> > + return true;
> > + }
> > + else switch (ts->type)
> > + {
> > + case BT_DERIVED:
> > + if (expr->expr_type != EXPR_STRUCTURE)
> > + return false;
> > + cm = expr->ts.derived->components;
> > + for (c = expr->value.constructor; c; c = c->next, cm = cm->next)
> > + {
> > + if (!c->expr || cm->allocatable)
> > + continue;
> > + if (!check_constant_initializer (c->expr, &cm->ts, cm->dimension,
> > + cm->pointer))
> > + return false;
> > + }
> > + return true;
> > + default:
> > + return expr->expr_type == EXPR_CONSTANT;
> > + }
> > +}
> > +
> > +/* Emit debug info for parameters and unreferenced variables with
> > + initializers. */
> > +
> > +static void
> > +gfc_emit_parameter_debug_info (gfc_symbol *sym)
> > +{
> > + tree decl;
> > +
> > + if (sym->attr.flavor != FL_PARAMETER
> > + && (sym->attr.flavor != FL_VARIABLE || sym->attr.referenced))
> > + return;
> > +
> > + if (sym->backend_decl != NULL
> > + || sym->value == NULL
> > + || sym->attr.use_assoc
> > + || sym->attr.dummy
> > + || sym->attr.result
> > + || sym->attr.function
> > + || sym->attr.intrinsic
> > + || sym->attr.pointer
> > + || sym->attr.allocatable
> > + || sym->attr.cray_pointee
> > + || sym->attr.threadprivate
> > + || sym->attr.is_bind_c
> > + || sym->attr.subref_array_pointer
> > + || sym->attr.assign)
> > + return;
> > +
> > + if (sym->ts.type == BT_CHARACTER)
> > + {
> > + gfc_conv_const_charlen (sym->ts.cl);
> > + if (sym->ts.cl->backend_decl == NULL
> > + || TREE_CODE (sym->ts.cl->backend_decl) != INTEGER_CST)
> > + return;
> > + }
> > + else if (sym->ts.type == BT_DERIVED && sym->ts.derived->attr.alloc_comp)
> > + return;
> > +
> > + if (sym->as)
> > + {
> > + int n;
> > +
> > + if (sym->as->type != AS_EXPLICIT)
> > + return;
> > + for (n = 0; n < sym->as->rank; n++)
> > + if (sym->as->lower[n]->expr_type != EXPR_CONSTANT
> > + || sym->as->upper[n] == NULL
> > + || sym->as->upper[n]->expr_type != EXPR_CONSTANT)
> > + return;
> > + }
> > +
> > + if (!check_constant_initializer (sym->value, &sym->ts,
> > + sym->attr.dimension, false))
> > + return;
> > +
> > + /* Create the decl for the variable or constant. */
> > + decl = build_decl (sym->attr.flavor == FL_PARAMETER ? CONST_DECL : VAR_DECL,
> > + gfc_sym_identifier (sym), gfc_sym_type (sym));
> > + if (sym->attr.flavor == FL_PARAMETER)
> > + TREE_READONLY (decl) = 1;
> > + gfc_set_decl_location (decl, &sym->declared_at);
> > + if (sym->attr.dimension)
> > + GFC_DECL_PACKED_ARRAY (decl) = 1;
> > + DECL_CONTEXT (decl) = sym->ns->proc_name->backend_decl;
> > + TREE_STATIC (decl) = 1;
> > + TREE_USED (decl) = 1;
> > + if (DECL_CONTEXT (decl) && TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL)
> > + TREE_PUBLIC (decl) = 1;
> > + DECL_INITIAL (decl)
> > + = gfc_conv_initializer (sym->value, &sym->ts, TREE_TYPE (decl),
> > + sym->attr.dimension, 0);
> > + debug_hooks->global_decl (decl);
> > +}
> > +
> > /* Generate all the required code for module variables. */
> >
> > void
> > @@ -3252,6 +3380,7 @@ gfc_generate_module_vars (gfc_namespace
> > cur_module = NULL;
> >
> > gfc_trans_use_stmts (ns);
> > + gfc_traverse_ns (ns, gfc_emit_parameter_debug_info);
> > }
> >
> >
> > @@ -3787,6 +3916,7 @@ gfc_generate_function_code (gfc_namespac
> > }
> >
> > gfc_trans_use_stmts (ns);
> > + gfc_traverse_ns (ns, gfc_emit_parameter_debug_info);
> > }
> >
> > void
> > --- gcc/dwarf2out.c.jj 2008-08-22 20:12:22.000000000 +0200
> > +++ gcc/dwarf2out.c 2008-08-26 19:46:49.000000000 +0200
> > @@ -5102,6 +5102,7 @@ static void gen_unspecified_parameters_d
> > static void gen_formal_types_die (tree, dw_die_ref);
> > static void gen_subprogram_die (tree, dw_die_ref);
> > static void gen_variable_die (tree, dw_die_ref);
> > +static void gen_const_die (tree, dw_die_ref);
> > static void gen_label_die (tree, dw_die_ref);
> > static void gen_lexical_block_die (tree, dw_die_ref, int);
> > static void gen_inlined_subroutine_die (tree, dw_die_ref, int);
> > @@ -7573,8 +7574,10 @@ size_of_die (dw_die_ref die)
> > size += 1 + 2*HOST_BITS_PER_LONG/HOST_BITS_PER_CHAR; /* block */
> > break;
> > case dw_val_class_vec:
> > - size += 1 + (a->dw_attr_val.v.val_vec.length
> > - * a->dw_attr_val.v.val_vec.elt_size); /* block */
> > + size += constant_size (a->dw_attr_val.v.val_vec.length
> > + * a->dw_attr_val.v.val_vec.elt_size)
> > + + a->dw_attr_val.v.val_vec.length
> > + * a->dw_attr_val.v.val_vec.elt_size; /* block */
> > break;
> > case dw_val_class_flag:
> > size += 1;
> > @@ -7773,7 +7776,18 @@ value_format (dw_attr_ref a)
> > case dw_val_class_long_long:
> > return DW_FORM_block1;
> > case dw_val_class_vec:
> > - return DW_FORM_block1;
> > + switch (constant_size (a->dw_attr_val.v.val_vec.length
> > + * a->dw_attr_val.v.val_vec.elt_size))
> > + {
> > + case 1:
> > + return DW_FORM_block1;
> > + case 2:
> > + return DW_FORM_block2;
> > + case 4:
> > + return DW_FORM_block4;
> > + default:
> > + gcc_unreachable ();
> > + }
> > case dw_val_class_flag:
> > return DW_FORM_flag;
> > case dw_val_class_die_ref:
> > @@ -8065,7 +8079,8 @@ output_die (dw_die_ref die)
> > unsigned int i;
> > unsigned char *p;
> >
> > - dw2_asm_output_data (1, len * elt_size, "%s", name);
> > + dw2_asm_output_data (constant_size (len * elt_size),
> > + len * elt_size, "%s", name);
> > if (elt_size > sizeof (HOST_WIDE_INT))
> > {
> > elt_size /= 2;
> > @@ -11771,6 +11786,150 @@ add_location_or_const_value_attribute (d
> > tree_add_const_value_attribute (die, decl);
> > }
> >
> > +/* Helper function for tree_add_const_value_attribute. Natively encode
> > + initializer INIT into an array. Return true if successful. */
> > +
> > +static bool
> > +native_encode_initializer (tree init, unsigned char *array, int size)
> > +{
> > + tree type;
> > +
> > + if (init == NULL_TREE)
> > + return false;
> > +
> > + STRIP_NOPS (init);
> > + switch (TREE_CODE (init))
> > + {
> > + case STRING_CST:
> > + type = TREE_TYPE (init);
> > + if (TREE_CODE (type) == ARRAY_TYPE)
> > + {
> > + tree enttype = TREE_TYPE (type);
> > + enum machine_mode mode = TYPE_MODE (enttype);
> > +
> > + if (GET_MODE_CLASS (mode) != MODE_INT || GET_MODE_SIZE (mode) != 1)
> > + return false;
> > + if (int_size_in_bytes (type) != size)
> > + return false;
> > + if (size > TREE_STRING_LENGTH (init))
> > + {
> > + memcpy (array, TREE_STRING_POINTER (init),
> > + TREE_STRING_LENGTH (init));
> > + memset (array + TREE_STRING_LENGTH (init),
> > + '\0', size - TREE_STRING_LENGTH (init));
> > + }
> > + else
> > + memcpy (array, TREE_STRING_POINTER (init), size);
> > + return true;
> > + }
> > + return false;
> > + case CONSTRUCTOR:
> > + type = TREE_TYPE (init);
> > + if (int_size_in_bytes (type) != size)
> > + return false;
> > + if (TREE_CODE (type) == ARRAY_TYPE)
> > + {
> > + HOST_WIDE_INT min_index;
> > + unsigned HOST_WIDE_INT cnt;
> > + int curpos = 0, fieldsize;
> > + constructor_elt *ce;
> > +
> > + if (TYPE_DOMAIN (type) == NULL_TREE
> > + || !host_integerp (TYPE_MIN_VALUE (TYPE_DOMAIN (type)), 0))
> > + return false;
> > +
> > + fieldsize = int_size_in_bytes (TREE_TYPE (type));
> > + if (fieldsize <= 0)
> > + return false;
> > +
> > + min_index = tree_low_cst (TYPE_MIN_VALUE (TYPE_DOMAIN (type)), 0);
> > + memset (array, '\0', size);
> > + for (cnt = 0;
> > + VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (init), cnt, ce);
> > + cnt++)
> > + {
> > + tree val = ce->value;
> > + tree index = ce->index;
> > + int pos = curpos;
> > + if (index && TREE_CODE (index) == RANGE_EXPR)
> > + pos = (tree_low_cst (TREE_OPERAND (index, 0), 0) - min_index)
> > + * fieldsize;
> > + else if (index)
> > + pos = tree_low_cst (index, 0) * fieldsize;
> > +
> > + if (val)
> > + {
> > + STRIP_NOPS (val);
> > + if (!native_encode_initializer (val, array + pos, fieldsize))
> > + return false;
> > + }
> > + curpos = pos + fieldsize;
> > + if (index && TREE_CODE (index) == RANGE_EXPR)
> > + {
> > + int count = tree_low_cst (TREE_OPERAND (index, 1), 0)
> > + - tree_low_cst (TREE_OPERAND (index, 0), 0);
> > + while (count > 0)
> > + {
> > + if (val)
> > + memcpy (array + curpos, array + pos, fieldsize);
> > + curpos += fieldsize;
> > + }
> > + }
> > + gcc_assert (curpos <= size);
> > + }
> > + return true;
> > + }
> > + else if (TREE_CODE (type) == RECORD_TYPE
> > + || TREE_CODE (type) == UNION_TYPE)
> > + {
> > + tree field = NULL_TREE;
> > + unsigned HOST_WIDE_INT cnt;
> > + constructor_elt *ce;
> > +
> > + if (int_size_in_bytes (type) != size)
> > + return false;
> > +
> > + if (TREE_CODE (type) == RECORD_TYPE)
> > + field = TYPE_FIELDS (type);
> > +
> > + for (cnt = 0;
> > + VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (init), cnt, ce);
> > + cnt++, field = field ? TREE_CHAIN (field) : 0)
> > + {
> > + tree val = ce->value;
> > + int pos, fieldsize;
> > +
> > + if (ce->index != 0)
> > + field = ce->index;
> > +
> > + if (val)
> > + STRIP_NOPS (val);
> > +
> > + if (field == NULL_TREE || DECL_BIT_FIELD (field))
> > + return false;
> > +
> > + if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
> > + && TYPE_DOMAIN (TREE_TYPE (field))
> > + && ! TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field))))
> > + return false;
> > + else if (DECL_SIZE_UNIT (field) == NULL_TREE
> > + || !host_integerp (DECL_SIZE_UNIT (field), 0))
> > + return false;
> > + fieldsize = tree_low_cst (DECL_SIZE_UNIT (field), 0);
> > + pos = int_byte_position (field);
> > + gcc_assert (pos + fieldsize <= size);
> > + if (val
> > + && !native_encode_initializer (val, array + pos, fieldsize))
> > + return false;
> > + }
> > + return true;
> > + }
> > + return false;
> > + default:
> > + return native_encode_expr (init, array, size) == size;
> > + }
> > +}
> > +
> > /* If we don't have a copy of this variable in memory for some reason (such
> > as a C++ member constant that doesn't have an out-of-line definition),
> > we should tell the debugger about the constant value. */
> > @@ -11790,6 +11949,18 @@ tree_add_const_value_attribute (dw_die_r
> > rtl = rtl_for_decl_init (init, type);
> > if (rtl)
> > add_const_value_attribute (var_die, rtl);
> > + /* If the host and target are sane, try harder. */
> > + else if (CHAR_BIT == 8 && BITS_PER_UNIT == 8)
> > + {
> > + HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (init));
> > + if (size > 0 && (int) size == size)
> > + {
> > + unsigned char *array = GGC_CNEWVEC (unsigned char, size);
> > +
> > + if (native_encode_initializer (init, array, size))
> > + add_AT_vec (var_die, DW_AT_const_value, size, 1, array);
> > + }
> > + }
> > }
> >
> > /* Convert the CFI instructions for the current function into a
> > @@ -13752,6 +13923,24 @@ gen_variable_die (tree decl, dw_die_ref
> > tree_add_const_value_attribute (var_die, decl);
> > }
> >
> > +/* Generate a DIE to represent a named constant. */
> > +
> > +static void
> > +gen_const_die (tree decl, dw_die_ref context_die)
> > +{
> > + dw_die_ref const_die;
> > + tree type = TREE_TYPE (decl);
> > +
> > + const_die = new_die (DW_TAG_constant, context_die, decl);
> > + add_name_and_src_coords_attributes (const_die, decl);
> > + add_type_attribute (const_die, type, 1, 0, context_die);
> > + if (TREE_PUBLIC (decl))
> > + add_AT_flag (const_die, DW_AT_external, 1);
> > + if (DECL_ARTIFICIAL (decl))
> > + add_AT_flag (const_die, DW_AT_artificial, 1);
> > + tree_add_const_value_attribute (const_die, decl);
> > +}
> > +
> > /* Generate a DIE to represent a label identifier. */
> >
> > static void
> > @@ -14892,8 +15081,20 @@ gen_decl_die (tree decl, dw_die_ref cont
> > break;
> >
> > case CONST_DECL:
> > - /* The individual enumerators of an enum type get output when we output
> > - the Dwarf representation of the relevant enum type itself. */
> > + if (!is_fortran ())
> > + {
> > + /* The individual enumerators of an enum type get output when we output
> > + the Dwarf representation of the relevant enum type itself. */
> > + break;
> > + }
> > +
> > + /* Emit its type. */
> > + gen_type_die (TREE_TYPE (decl), context_die);
> > +
> > + /* And its containing namespace. */
> > + context_die = declare_in_namespace (decl, context_die);
> > +
> > + gen_const_die (decl, context_die);
> > break;
> >
> > case FUNCTION_DECL:
> > @@ -15238,6 +15439,15 @@ dwarf2out_decl (tree decl)
> > return;
> > break;
> >
> > + case CONST_DECL:
> > + if (debug_info_level <= DINFO_LEVEL_TERSE)
> > + return;
> > + if (!is_fortran ())
> > + return;
> > + if (TREE_STATIC (decl) && decl_function_context (decl))
> > + context_die = lookup_decl_die (DECL_CONTEXT (decl));
> > + break;
> > +
> > case NAMESPACE_DECL:
> > if (debug_info_level <= DINFO_LEVEL_TERSE)
> > return;
> >
> > Jakub
> >
>
>