This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
loc_list_from_tree improvements and DW_OP_stack_values support
- From: Jan Hubicka <hubicka at ucw dot cz>
- To: gcc-patches at gcc dot gnu dot org, jakub at redhat dot com, jason at redhat dot com, rguenther at suse dot de
- Date: Fri, 18 Sep 2009 12:31:27 +0200
- Subject: loc_list_from_tree improvements and DW_OP_stack_values support
Hi,
this patch combines all important improvements into loc_list_from_tree
so we have realistic chance to actually expand generic expressions.
Unlike pretty-ipa version, handling of DW_OP_stack_value is
re-implemented and I tried to be in sync with what loc_descriptor does.
What we do now:
1) We do not give up on "address of ADDR_EXPR" and handle ADDR_EXPR
containing indirect ref. I.e. &this->subobject is translated to "this"
or "this + offset". This is most common case for inliner substitution
tracking
2) I commonized handling of "address" of INTEGER_CST with Jakub's code
handling CONST_INT. I didn't go for the other types of constants, we can
do this later
3) All constants are now looked up in constant pool. The code was there
for handling CONSTRUCTOR, but it is in fact most useful for strings. I.e
function (params, "my pretty debug string") common in C++ code now gets
tracked after function is inlined and the argument completely substituted
for "my pretty debug string".
There was latent bug in that code causing undefined references to constant
pool values that was optimized out. This is fixed now.
4) DW_OP_stack_value is now used when we manage to get value of expression
but not address.
There are still some improvements, in particular we can handle better
small constants that are not in constant pool similar way as
loc_desriptor does and perhaps we can apply the constant pool trick for
loc_descriptor. I would like to handle this incrementally so testcases
can be constructed once substitution tracking is on place.
With (pretty-ipa variant of) this patch the probability that tracked
expression will sucesfully expand to dwarf increase from about 10% to
60% (on sucesfully tracked substitutions in tramp3d), remaining cases
are mostly valid cases where we lose track of user vars so we can't
expand them or FP expressions that don't have dwarf equivalent. With
VTA we can hope for even better coverage ;)
Bootstrapped/retested x86_64. OK?
* dwarf2out.c (address_of_int_loc_descriptor): Break out from ...
(loc_descriptor): ... here;
(loc_list_for_address_of_addr_expr_of_indirect_ref): New function.
(cst_pool_loc_descr): Break out from ...; do not reffer constant
pool items that was not marked for output.
(loc_list_from_tree): ... here; handle special cases of ADDR_EXPR;
(loc_list_for_address_of_addr_expr_of_indirect_ref): New function.
(loc_list_for_address_of_addr_expr_of_indirect_ref): New function.
handle ALIGN_INDIRECT_REF, MISALIGNED_INDIRECT_REF, REALPART_EXPR,
IMAGPART_EXPR; handle address of INTEGER_CST; improve handling of
CONSTRUCTOR; handle REAL_CST, STRING_CST, COMPLEX_CST; use
DW_OP_stack_value to get address of items that are not available
as addresses.
Index: dwarf2out.c
===================================================================
*** dwarf2out.c (revision 151837)
--- dwarf2out.c (working copy)
*************** int_loc_descriptor (HOST_WIDE_INT i)
*** 10882,10887 ****
--- 10882,10945 ----
return new_loc_descr (op, i, 0);
}
+
+ /* Return loc description representing "address" of integer value.
+ This can appear only as toplevel expression. */
+
+ static dw_loc_descr_ref
+ address_of_int_loc_descriptor (int size, HOST_WIDE_INT i)
+ {
+ int litsize;
+ dw_loc_descr_ref loc_result = NULL;
+
+ if (i >= 0)
+ {
+ if (i <= 31)
+ litsize = 1;
+ else if (i <= 0xff)
+ litsize = 2;
+ else if (i <= 0xffff)
+ litsize = 3;
+ else if (HOST_BITS_PER_WIDE_INT == 32
+ || i <= 0xffffffff)
+ litsize = 5;
+ else
+ litsize = 1 + size_of_uleb128 ((unsigned HOST_WIDE_INT) i);
+ }
+ else
+ {
+ if (i >= -0x80)
+ litsize = 2;
+ else if (i >= -0x8000)
+ litsize = 3;
+ else if (HOST_BITS_PER_WIDE_INT == 32
+ || i >= -0x80000000)
+ litsize = 5;
+ else
+ litsize = 1 + size_of_sleb128 (i);
+ }
+ /* Determine if DW_OP_stack_value or DW_OP_implicit_value
+ is more compact. For DW_OP_stack_value we need:
+ litsize + 1 (DW_OP_stack_value) + 1 (DW_OP_bit_size)
+ + 1 (mode size)
+ and for DW_OP_implicit_value:
+ 1 (DW_OP_implicit_value) + 1 (length) + mode_size. */
+ if (DWARF2_ADDR_SIZE >= size
+ && litsize + 1 + 1 + 1 < 1 + 1 + size)
+ {
+ loc_result = int_loc_descriptor (i);
+ add_loc_descr (&loc_result,
+ new_loc_descr (DW_OP_stack_value, 0, 0));
+ add_loc_descr_op_piece (&loc_result, size);
+ return loc_result;
+ }
+
+ loc_result = new_loc_descr (DW_OP_implicit_value,
+ size, 0);
+ loc_result->dw_loc_oprnd2.val_class = dw_val_class_const;
+ loc_result->dw_loc_oprnd2.v.val_int = i;
+ return loc_result;
+ }
#endif
#ifdef DWARF2_DEBUGGING_INFO
*************** loc_descriptor (rtx rtl, enum machine_mo
*** 11778,11833 ****
case CONST_INT:
if (mode != VOIDmode && mode != BLKmode)
! {
! HOST_WIDE_INT i = INTVAL (rtl);
! int litsize;
! if (i >= 0)
! {
! if (i <= 31)
! litsize = 1;
! else if (i <= 0xff)
! litsize = 2;
! else if (i <= 0xffff)
! litsize = 3;
! else if (HOST_BITS_PER_WIDE_INT == 32
! || i <= 0xffffffff)
! litsize = 5;
! else
! litsize = 1 + size_of_uleb128 ((unsigned HOST_WIDE_INT) i);
! }
! else
! {
! if (i >= -0x80)
! litsize = 2;
! else if (i >= -0x8000)
! litsize = 3;
! else if (HOST_BITS_PER_WIDE_INT == 32
! || i >= -0x80000000)
! litsize = 5;
! else
! litsize = 1 + size_of_sleb128 (i);
! }
! /* Determine if DW_OP_stack_value or DW_OP_implicit_value
! is more compact. For DW_OP_stack_value we need:
! litsize + 1 (DW_OP_stack_value) + 1 (DW_OP_bit_size)
! + 1 (mode size)
! and for DW_OP_implicit_value:
! 1 (DW_OP_implicit_value) + 1 (length) + mode_size. */
! if (DWARF2_ADDR_SIZE >= GET_MODE_SIZE (mode)
! && litsize + 1 + 1 + 1 < 1 + 1 + GET_MODE_SIZE (mode))
! {
! loc_result = int_loc_descriptor (i);
! add_loc_descr (&loc_result,
! new_loc_descr (DW_OP_stack_value, 0, 0));
! add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
! return loc_result;
! }
!
! loc_result = new_loc_descr (DW_OP_implicit_value,
! GET_MODE_SIZE (mode), 0);
! loc_result->dw_loc_oprnd2.val_class = dw_val_class_const;
! loc_result->dw_loc_oprnd2.v.val_int = i;
! }
break;
case CONST_DOUBLE:
--- 11836,11843 ----
case CONST_INT:
if (mode != VOIDmode && mode != BLKmode)
! loc_result = address_of_int_loc_descriptor (GET_MODE_SIZE (mode),
! INTVAL (rtl));
break;
case CONST_DOUBLE:
*************** add_loc_list (dw_loc_list_ref *ret, dw_l
*** 12267,12272 ****
--- 12277,12372 ----
return;
}
+ /* LOC is constant expression. Try a luck, look it up in constant
+ pool and return its loc_descr of its address. */
+
+ static dw_loc_descr_ref
+ cst_pool_loc_descr (tree loc)
+ {
+ /* Get an RTL for this, if something has been emitted. */
+ rtx rtl = lookup_constant_def (loc);
+ enum machine_mode mode;
+
+ if (!rtl || !MEM_P (rtl))
+ {
+ gcc_assert (!rtl);
+ return 0;
+ }
+ gcc_assert (GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF);
+
+ /* TODO: We might get more coverage if we was actually delaying expansion
+ of all expressions till end of compilation when constant pools are fully
+ populated. */
+ if (!TREE_ASM_WRITTEN (SYMBOL_REF_DECL (XEXP (rtl, 0))))
+ {
+ expansion_failed (loc, NULL_RTX,
+ "CST value in contant pool but not marked.");
+ return 0;
+ }
+ mode = GET_MODE (rtl);
+ rtl = XEXP (rtl, 0);
+ return mem_loc_descriptor (rtl, mode, VAR_INIT_STATUS_INITIALIZED);
+ }
+
+ /* Return dw_loc_list representing address of addr_expr LOC
+ by looking for innder INDIRECT_REF expression and turing it
+ into simple arithmetics. */
+
+ static dw_loc_list_ref
+ loc_list_for_address_of_addr_expr_of_indirect_ref (tree loc, bool toplev)
+ {
+ tree obj, offset;
+ HOST_WIDE_INT bitsize, bitpos, bytepos;
+ enum machine_mode mode;
+ int volatilep;
+ int unsignedp = TYPE_UNSIGNED (TREE_TYPE (loc));
+ dw_loc_list_ref list_ret = NULL, list_ret1 = NULL;
+
+ obj = get_inner_reference (TREE_OPERAND (loc, 0),
+ &bitsize, &bitpos, &offset, &mode,
+ &unsignedp, &volatilep, false);
+ STRIP_NOPS (obj);
+ if (INDIRECT_REF_P (obj) && (bitpos % BITS_PER_UNIT) == 0)
+ {
+ if (!offset && !bitpos)
+ list_ret = loc_list_from_tree (TREE_OPERAND (obj, 0), toplev ? 2 : 1);
+ else if (toplev
+ && int_size_in_bytes (TREE_TYPE (loc)) <= DWARF2_ADDR_SIZE)
+ {
+ list_ret = loc_list_from_tree (TREE_OPERAND (obj, 0), 1);
+ if (!list_ret)
+ return 0;
+ if (offset)
+ {
+ /* Variable offset. */
+ list_ret1 = loc_list_from_tree (offset, 0);
+ if (list_ret1 == 0)
+ return 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;
+ 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);
+ add_loc_descr_to_each (list_ret,
+ new_loc_descr (DW_OP_stack_value, 0, 0));
+ add_loc_descr_to_each (list_ret,
+ new_loc_descr (DW_OP_piece,
+ int_size_in_bytes (TREE_TYPE
+ (loc)),
+ 0));
+ }
+ }
+ return list_ret;
+ }
+
/* 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
*************** loc_list_from_tree (tree loc, int want_a
*** 12318,12332 ****
return 0;
case ADDR_EXPR:
! /* If we already want an address, there's nothing we can do. */
if (want_address)
{
! expansion_failed (loc, NULL_RTX, "need address of ADDR_EXPR");
! return 0;
}
!
! /* Otherwise, process the argument and look for the address. */
! return loc_list_from_tree (TREE_OPERAND (loc, 0), 1);
case VAR_DECL:
if (DECL_THREAD_LOCAL_P (loc))
--- 12418,12443 ----
return 0;
case ADDR_EXPR:
! /* If we already want an address, see if there is INDIRECT_REF inside
! e.g. for &this->field. */
if (want_address)
{
! list_ret = loc_list_for_address_of_addr_expr_of_indirect_ref
! (loc, want_address == 2);
! if (list_ret)
! have_address = 1;
! else if ((ret = cst_pool_loc_descr (loc)))
! have_address = 1;
! else
! {
! expansion_failed (loc, NULL_RTX, "need address of ADDR_EXPR");
! return NULL;
! }
}
! else
! /* Otherwise, process the argument and look for the address. */
! return loc_list_from_tree (TREE_OPERAND (loc, 0), 1);
! break;
case VAR_DECL:
if (DECL_THREAD_LOCAL_P (loc))
*************** loc_list_from_tree (tree loc, int want_a
*** 12387,12393 ****
case PARM_DECL:
if (DECL_HAS_VALUE_EXPR_P (loc))
return loc_list_from_tree (DECL_VALUE_EXPR (loc),
! want_address);
/* FALLTHRU */
case RESULT_DECL:
--- 12498,12504 ----
case PARM_DECL:
if (DECL_HAS_VALUE_EXPR_P (loc))
return loc_list_from_tree (DECL_VALUE_EXPR (loc),
! want_address);
/* FALLTHRU */
case RESULT_DECL:
*************** loc_list_from_tree (tree loc, int want_a
*** 12451,12456 ****
--- 12562,12569 ----
break;
case INDIRECT_REF:
+ case ALIGN_INDIRECT_REF:
+ case MISALIGNED_INDIRECT_REF:
list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
have_address = 1;
break;
*************** loc_list_from_tree (tree loc, int want_a
*** 12468,12473 ****
--- 12581,12588 ----
case BIT_FIELD_REF:
case ARRAY_REF:
case ARRAY_RANGE_REF:
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
{
tree obj, offset;
HOST_WIDE_INT bitsize, bitpos, bytepos;
*************** loc_list_from_tree (tree loc, int want_a
*** 12513,12519 ****
}
case INTEGER_CST:
! if (host_integerp (loc, 0))
ret = int_loc_descriptor (tree_low_cst (loc, 0));
else
{
--- 12628,12643 ----
}
case INTEGER_CST:
! if ((want_address || !host_integerp (loc, 0))
! && (ret = cst_pool_loc_descr (loc)))
! have_address = 1;
! else if (want_address == 2
! && host_integerp (loc, 0)
! && (ret = address_of_int_loc_descriptor
! (int_size_in_bytes (TREE_TYPE (loc)),
! tree_low_cst (loc, 0))))
! have_address = 1;
! else if (host_integerp (loc, 0))
ret = int_loc_descriptor (tree_low_cst (loc, 0));
else
{
*************** loc_list_from_tree (tree loc, int want_a
*** 12524,12542 ****
break;
case CONSTRUCTOR:
! {
! /* Get an RTL for this, if something has been emitted. */
! rtx rtl = lookup_constant_def (loc);
! enum machine_mode mode;
!
! if (!rtl || !MEM_P (rtl))
! return 0;
! mode = GET_MODE (rtl);
! rtl = XEXP (rtl, 0);
! ret = mem_loc_descriptor (rtl, mode, VAR_INIT_STATUS_INITIALIZED);
have_address = 1;
! break;
! }
case TRUTH_AND_EXPR:
case TRUTH_ANDIF_EXPR:
--- 12648,12663 ----
break;
case CONSTRUCTOR:
! case REAL_CST:
! case STRING_CST:
! case COMPLEX_CST:
! if ((ret = cst_pool_loc_descr (loc)))
have_address = 1;
! else
! /* We can construct small constants here using int_loc_descriptor. */
! expansion_failed (loc, NULL_RTX,
! "constructor or constant not in constant pool");
! break;
case TRUTH_AND_EXPR:
case TRUTH_ANDIF_EXPR:
*************** loc_list_from_tree (tree loc, int want_a
*** 12743,12748 ****
--- 12864,12886 ----
if (!ret && !list_ret)
return 0;
+ if (want_address == 2 && !have_address)
+ {
+ if (int_size_in_bytes (TREE_TYPE (loc)) > DWARF2_ADDR_SIZE)
+ {
+ expansion_failed (loc, NULL_RTX,
+ "DWARF address size mismatch");
+ return 0;
+ }
+ add_loc_descr_to_each (list_ret,
+ new_loc_descr (DW_OP_stack_value, 0, 0));
+ add_loc_descr_to_each (list_ret,
+ new_loc_descr (DW_OP_piece,
+ int_size_in_bytes (TREE_TYPE
+ (loc)),
+ 0));
+ have_address = 1;
+ }
/* Show if we can't fill the request for an address. */
if (want_address && !have_address)
{