[PATCH] DWARF5 - Emit DW_AT_rank and DW_TAG_generic_subrange for assumed-rank arrays
Jakub Jelinek
jakub@redhat.com
Wed Oct 26 16:05:00 GMT 2016
Hi!
The following patch starts emitting another new DWARF5 feature - DW_AT_rank
and DW_TAG_generic_subrange for Fortran assumed-rank arrays.
Unlike DW_TAG_subrange_type, the expressions in DW_TAG_generic_subrange
attributes have a magic 0 to rank-1 values pushed onto the DWARF stack
first; rather than allocating yet another DEBUG_EXPR_DECL for that,
I've used a PLACEHOLDER_EXPR with integral type.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
BTW, DWARF5 also has DW_TAG_coarray_type support, guess the
gfc_get_array_descr_info lang hook interface should be extended for that
(perhaps just as little as including ncodimensions next to dimensions
and filling the rest of the coranges, but I'm afraid I don't know enough
about the coarray stuff to be able to write the Fortran side of it.
So, Tobias or others, if you could come up with the trans-types.c side
and some examples, I can help with the dwarf2out.c side.
2016-10-26 Jakub Jelinek <jakub@redhat.com>
* dwarf2out.h (struct dw_loc_descr_node): Adjust comment
for frame_offset_rel bit.
(struct array_descr_info): Add rank field.
* dwarf2out.c (struct loc_descr_context): Add placeholder_arg
and placeholder_seen fields.
(resolve_args_picking_1): Handle also frame_offset_rel DW_OP_dup
and DW_OP_over. Optimize DW_OP_pick 0 into DW_OP_dup and
DW_OP_pick 1 into DW_OP_over.
(function_to_dwarf_procedure, type_byte_size, field_byte_offset,
gen_variant_part): Clear placeholder_{arg,seen}.
(loc_list_from_tree_1): Drop const from context argument.
Handle integral PLACEHOLDER_EXPR if context->placeholder_arg.
(loc_list_for_address_of_addr_expr_of_indirect_ref,
loc_list_from_tree, loc_descriptor_from_tree): Drop const from
context argument.
(add_scalar_info): Drop const from context argument. Handle
context->placeholder_arg.
(add_bound_info): Drop const from context argument.
(gen_descr_array_type_die): Drop const from ctx variable.
Initialize placeholder_arg and placeholder_seen. Add DW_AT_rank
attribute and use a single DW_TAG_generic_subrange instead of
7 DW_TAG_subrange_type for assumed rank arrays.
fortran/
* trans-types.c (gfc_get_array_descr_info): For -gdwarf-5 or
-gno-strict-dwarf, handle assumed rank arrays the way dwarf2out
expects.
ada/
* gcc-interface/misc.c (gnat_get_array_descr_info): Clear rank
field.
--- gcc/dwarf2out.h.jj 2016-10-22 18:57:43.000000000 +0200
+++ gcc/dwarf2out.h 2016-10-26 10:45:44.104651085 +0200
@@ -234,9 +234,9 @@ struct GTY((chain_next ("%h.dw_loc_next"
/* Used to distinguish DW_OP_addr with a direct symbol relocation
from DW_OP_addr with a dtp-relative symbol relocation. */
unsigned int dtprel : 1;
- /* For DW_OP_pick operations: true iff. it targets a DWARF prodecure
- argument. In this case, it needs to be relocated according to the current
- frame offset. */
+ /* For DW_OP_pick, DW_OP_dup and DW_OP_over operations: true iff.
+ it targets a DWARF prodecure argument. In this case, it needs to be
+ relocated according to the current frame offset. */
unsigned int frame_offset_rel : 1;
int dw_loc_addr;
dw_val_node dw_loc_oprnd1;
@@ -322,6 +322,7 @@ struct array_descr_info
tree allocated;
tree associated;
tree stride;
+ tree rank;
bool stride_in_bits;
struct array_descr_dimen
{
--- gcc/dwarf2out.c.jj 2016-10-25 22:13:57.000000000 +0200
+++ gcc/dwarf2out.c 2016-10-26 10:49:31.041820289 +0200
@@ -3293,9 +3293,9 @@ struct loc_descr_context;
static void add_loc_descr_to_each (dw_loc_list_ref list, dw_loc_descr_ref ref);
static void add_loc_list (dw_loc_list_ref *ret, dw_loc_list_ref list);
static dw_loc_list_ref loc_list_from_tree (tree, int,
- const struct loc_descr_context *);
+ struct loc_descr_context *);
static dw_loc_descr_ref loc_descriptor_from_tree (tree, int,
- const struct loc_descr_context *);
+ 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);
@@ -3320,9 +3320,9 @@ static void add_name_attribute (dw_die_r
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_scalar_info (dw_die_ref, enum dwarf_attribute, tree, int,
- const struct loc_descr_context *);
+ struct loc_descr_context *);
static void add_bound_info (dw_die_ref, enum dwarf_attribute, tree,
- const struct loc_descr_context *);
+ 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 inline void add_bit_offset_attribute (dw_die_ref, tree,
@@ -15157,7 +15157,7 @@ cst_pool_loc_descr (tree loc)
static dw_loc_list_ref
loc_list_for_address_of_addr_expr_of_indirect_ref (tree loc, bool toplev,
- const loc_descr_context *context)
+ loc_descr_context *context)
{
tree obj, offset;
HOST_WIDE_INT bitsize, bitpos, bytepos;
@@ -15291,6 +15291,11 @@ struct loc_descr_context
/* Information about the DWARF procedure we are currently generating. NULL if
we are not generating a DWARF procedure. */
struct dwarf_procedure_info *dpi;
+ /* True if integral PLACEHOLDER_EXPR stands for the first argument passed
+ by consumer. Used for DW_TAG_generic_subrange attributes. */
+ bool placeholder_arg;
+ /* True if PLACEHOLDER_EXPR has been seen. */
+ bool placeholder_seen;
};
/* DWARF procedures generation
@@ -15400,8 +15405,23 @@ resolve_args_picking_1 (dw_loc_descr_ref
/* If needed, relocate the picking offset with respect to the frame
offset. */
- if (l->dw_loc_opc == DW_OP_pick && l->frame_offset_rel)
+ if (l->frame_offset_rel)
{
+ unsigned HOST_WIDE_INT off;
+ switch (l->dw_loc_opc)
+ {
+ case DW_OP_pick:
+ off = l->dw_loc_oprnd1.v.val_unsigned;
+ break;
+ case DW_OP_dup:
+ off = 0;
+ break;
+ case DW_OP_over:
+ off = 1;
+ break;
+ default:
+ gcc_unreachable ();
+ }
/* frame_offset_ is the size of the current stack frame, including
incoming arguments. Besides, the arguments are pushed
right-to-left. Thus, in order to access the Nth argument from
@@ -15412,11 +15432,27 @@ resolve_args_picking_1 (dw_loc_descr_ref
The targetted argument number (N) is already set as the operand,
and the number of temporaries can be computed with:
frame_offsets_ - dpi->args_count */
- l->dw_loc_oprnd1.v.val_unsigned += frame_offset_ - dpi->args_count;
+ off += frame_offset_ - dpi->args_count;
/* DW_OP_pick handles only offsets from 0 to 255 (inclusive)... */
- if (l->dw_loc_oprnd1.v.val_unsigned > 255)
+ if (off > 255)
return false;
+
+ if (off == 0)
+ {
+ l->dw_loc_opc = DW_OP_dup;
+ l->dw_loc_oprnd1.v.val_unsigned = 0;
+ }
+ else if (off == 1)
+ {
+ l->dw_loc_opc = DW_OP_over;
+ l->dw_loc_oprnd1.v.val_unsigned = 0;
+ }
+ else
+ {
+ l->dw_loc_opc = DW_OP_pick;
+ l->dw_loc_oprnd1.v.val_unsigned = off;
+ }
}
/* Update frame_offset according to the effect the current operation has
@@ -15712,6 +15748,8 @@ function_to_dwarf_procedure (tree fndecl
ctx.context_type = NULL_TREE;
ctx.base_decl = NULL_TREE;
ctx.dpi = &dpi;
+ ctx.placeholder_arg = false;
+ ctx.placeholder_seen = false;
dpi.fndecl = fndecl;
dpi.args_count = list_length (DECL_ARGUMENTS (fndecl));
loc_body = loc_descriptor_from_tree (tree_body, 0, &ctx);
@@ -15774,7 +15812,7 @@ function_to_dwarf_procedure (tree fndecl
static dw_loc_list_ref
loc_list_from_tree_1 (tree loc, int want_address,
- const struct loc_descr_context *context)
+ struct loc_descr_context *context)
{
dw_loc_descr_ref ret = NULL, ret1 = NULL;
dw_loc_list_ref list_ret = NULL, list_ret1 = NULL;
@@ -15820,6 +15858,18 @@ loc_list_from_tree_1 (tree loc, int want
else
return NULL;
}
+ /* For DW_TAG_generic_subrange attributes, PLACEHOLDER_EXPR stands for
+ the single argument passed by consumer. */
+ else if (context != NULL
+ && context->placeholder_arg
+ && INTEGRAL_TYPE_P (TREE_TYPE (loc))
+ && want_address == 0)
+ {
+ ret = new_loc_descr (DW_OP_pick, 0, 0);
+ ret->frame_offset_rel = 1;
+ context->placeholder_seen = true;
+ break;
+ }
else
expansion_failed (loc, NULL_RTX,
"PLACEHOLDER_EXPR for an unexpected type");
@@ -16573,7 +16623,7 @@ loc_list_from_tree_1 (tree loc, int want
static dw_loc_list_ref
loc_list_from_tree (tree loc, int want_address,
- const struct loc_descr_context *context)
+ struct loc_descr_context *context)
{
dw_loc_list_ref result = loc_list_from_tree_1 (loc, want_address, context);
@@ -16587,7 +16637,7 @@ loc_list_from_tree (tree loc, int want_a
/* Same as above but return only single location expression. */
static dw_loc_descr_ref
loc_descriptor_from_tree (tree loc, int want_address,
- const struct loc_descr_context *context)
+ struct loc_descr_context *context)
{
dw_loc_list_ref ret = loc_list_from_tree (loc, want_address, context);
if (!ret)
@@ -16673,6 +16723,8 @@ type_byte_size (const_tree type, HOST_WI
ctx.context_type = const_cast<tree> (type);
ctx.base_decl = NULL_TREE;
ctx.dpi = NULL;
+ ctx.placeholder_arg = false;
+ ctx.placeholder_seen = false;
type = TYPE_MAIN_VARIANT (type);
tree_size = TYPE_SIZE_UNIT (type);
@@ -16852,7 +16904,9 @@ field_byte_offset (const_tree decl, stru
struct loc_descr_context loc_ctx = {
ctx->struct_type, /* context_type */
NULL_TREE, /* base_decl */
- NULL /* dpi */
+ NULL, /* dpi */
+ false, /* placeholder_arg */
+ false /* placeholder_seen */
};
loc_result = loc_list_from_tree (tree_result, 0, &loc_ctx);
@@ -18245,12 +18299,12 @@ add_comp_dir_attribute (dw_die_ref die)
static void
add_scalar_info (dw_die_ref die, enum dwarf_attribute attr, tree value,
- int forms, const struct loc_descr_context *context)
+ int forms, struct loc_descr_context *context)
{
dw_die_ref context_die, decl_die;
dw_loc_list_ref list;
-
bool strip_conversions = true;
+ bool placeholder_seen = false;
while (strip_conversions)
switch (TREE_CODE (value))
@@ -18345,6 +18399,11 @@ add_scalar_info (dw_die_ref die, enum dw
return;
list = loc_list_from_tree (value, 2, context);
+ if (context && context->placeholder_arg)
+ {
+ placeholder_seen = context->placeholder_seen;
+ context->placeholder_seen = false;
+ }
if (list == NULL || single_element_loc_list_p (list))
{
/* If this attribute is not a reference nor constant, it is
@@ -18353,6 +18412,14 @@ add_scalar_info (dw_die_ref die, enum dw
dw_loc_list_ref list2 = loc_list_from_tree (value, 0, context);
if (list2 && single_element_loc_list_p (list2))
{
+ if (placeholder_seen)
+ {
+ struct dwarf_procedure_info dpi;
+ dpi.fndecl = NULL_TREE;
+ dpi.args_count = 1;
+ if (!resolve_args_picking (list2->expr, 1, &dpi))
+ return;
+ }
add_AT_loc (die, attr, list2->expr);
return;
}
@@ -18360,7 +18427,9 @@ add_scalar_info (dw_die_ref die, enum dw
/* 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)
+ if (list == NULL
+ || (forms & dw_scalar_form_reference) == 0
+ || placeholder_seen)
return;
if (current_function_decl == 0)
@@ -18423,7 +18492,7 @@ lower_bound_default (void)
static void
add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr,
- tree bound, const struct loc_descr_context *context)
+ tree bound, struct loc_descr_context *context)
{
int dflt;
@@ -18454,7 +18523,8 @@ add_bound_info (dw_die_ref subrange_die,
encodings, GDB isn't ready yet to handle proper DWARF description
for self-referencial subrange bounds: let GNAT encodings do the
magic in such a case. */
- if (gnat_encodings != DWARF_GNAT_ENCODINGS_MINIMAL
+ if (is_ada ()
+ && gnat_encodings != DWARF_GNAT_ENCODINGS_MINIMAL
&& contains_placeholder_p (bound))
return;
@@ -19480,7 +19550,9 @@ gen_descr_array_type_die (tree type, str
{
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, NULL };
+ struct loc_descr_context context = { type, info->base_decl, NULL,
+ false, false };
+ enum dwarf_tag subrange_tag = DW_TAG_subrange_type;
int dim;
add_name_attribute (array_die, type_tag (type));
@@ -19528,13 +19600,23 @@ gen_descr_array_type_die (tree type, str
add_scalar_info (array_die, attr, info->stride, forms, &context);
}
}
+ if (dwarf_version >= 5)
+ {
+ if (info->rank)
+ {
+ add_scalar_info (array_die, DW_AT_rank, info->rank,
+ dw_scalar_form_constant
+ | dw_scalar_form_exprloc, &context);
+ subrange_tag = DW_TAG_generic_subrange;
+ context.placeholder_arg = true;
+ }
+ }
add_gnat_descriptive_type_attribute (array_die, type, context_die);
for (dim = 0; dim < info->ndimensions; dim++)
{
- dw_die_ref subrange_die
- = new_die (DW_TAG_subrange_type, array_die, NULL);
+ dw_die_ref subrange_die = new_die (subrange_tag, array_die, NULL);
if (info->dimen[dim].bounds_type)
add_type_attribute (subrange_die,
@@ -22459,7 +22541,9 @@ gen_variant_part (tree variant_part_decl
struct loc_descr_context ctx = {
vlr_ctx->struct_type, /* context_type */
NULL_TREE, /* base_decl */
- NULL /* dpi */
+ NULL, /* dpi */
+ false, /* placeholder_arg */
+ false /* placeholder_seen */
};
/* The FIELD_DECL node in STRUCT_TYPE that acts as the discriminant, or
--- gcc/fortran/trans-types.c.jj 2016-09-30 16:24:49.000000000 +0200
+++ gcc/fortran/trans-types.c 2016-10-26 10:56:09.348851132 +0200
@@ -3129,7 +3129,7 @@ gfc_get_array_descr_info (const_tree typ
int rank, dim;
bool indirect = false;
tree etype, ptype, field, t, base_decl;
- tree data_off, dim_off, dim_size, elem_size;
+ tree data_off, dim_off, dtype_off, dim_size, elem_size;
tree lower_suboff, upper_suboff, stride_suboff;
if (! GFC_DESCRIPTOR_TYPE_P (type))
@@ -3193,6 +3193,7 @@ gfc_get_array_descr_info (const_tree typ
data_off = byte_position (field);
field = DECL_CHAIN (field);
field = DECL_CHAIN (field);
+ dtype_off = byte_position (field);
field = DECL_CHAIN (field);
dim_off = byte_position (field);
dim_size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (field)));
@@ -3215,6 +3216,24 @@ gfc_get_array_descr_info (const_tree typ
|| GFC_TYPE_ARRAY_AKIND (type) == GFC_ARRAY_POINTER_CONT)
info->associated = build2 (NE_EXPR, boolean_type_node,
info->data_location, null_pointer_node);
+ if ((GFC_TYPE_ARRAY_AKIND (type) == GFC_ARRAY_ASSUMED_RANK
+ || GFC_TYPE_ARRAY_AKIND (type) == GFC_ARRAY_ASSUMED_RANK_CONT)
+ && dwarf_version >= 5)
+ {
+ rank = 1;
+ info->ndimensions = 1;
+ t = base_decl;
+ if (!integer_zerop (dtype_off))
+ t = fold_build_pointer_plus (t, dtype_off);
+ t = build1 (NOP_EXPR, build_pointer_type (gfc_array_index_type), t);
+ t = build1 (INDIRECT_REF, gfc_array_index_type, t);
+ info->rank = build2 (BIT_AND_EXPR, gfc_array_index_type, t,
+ build_int_cst (gfc_array_index_type,
+ GFC_DTYPE_RANK_MASK));
+ t = build0 (PLACEHOLDER_EXPR, TREE_TYPE (dim_off));
+ t = size_binop (MULT_EXPR, t, dim_size);
+ dim_off = build2 (PLUS_EXPR, TREE_TYPE (dim_off), t, dim_off);
+ }
for (dim = 0; dim < rank; dim++)
{
@@ -3250,7 +3269,8 @@ gfc_get_array_descr_info (const_tree typ
t = build1 (INDIRECT_REF, gfc_array_index_type, t);
t = build2 (MULT_EXPR, gfc_array_index_type, t, elem_size);
info->dimen[dim].stride = t;
- dim_off = size_binop (PLUS_EXPR, dim_off, dim_size);
+ if (dim + 1 < rank)
+ dim_off = size_binop (PLUS_EXPR, dim_off, dim_size);
}
return true;
--- gcc/ada/gcc-interface/misc.c.jj 2016-10-17 08:42:35.000000000 +0200
+++ gcc/ada/gcc-interface/misc.c 2016-10-26 09:18:55.626505126 +0200
@@ -898,6 +898,7 @@ gnat_get_array_descr_info (const_tree co
}
info->ndimensions = i;
+ info->rank = NULL_TREE;
/* Too many dimensions? Give up generating proper description: yield instead
nested arrays. Note that in this case, this hook is invoked once on each
Jakub
More information about the Gcc-patches
mailing list