[PATCH] Preliminary DW_OP_{implicit,stack}_value support (take 2)
Jakub Jelinek
jakub@redhat.com
Thu Jun 11 15:36:00 GMT 2009
On Thu, Jun 11, 2009 at 09:58:51AM -0300, Alexandre Oliva wrote:
> On Jun 11, 2009, Jakub Jelinek <jakub@redhat.com> wrote:
>
> >> DW_OP_implicit_value 0x9e
> >> DW_OP_stack_value 0x9f
>
> > Using http://www.dwarfstd.org/doc/DWARF4-draft3-090522.pdf
> > I've drafted up a preliminary support patch for these two.
> > First patch is against trunk, second against VTA branch.
>
Here is an updated version of the patch, which fixes
a bug reported by Alex and also handles even one var value being computable
from another value with some offset.
On Alex's
int f(int a) { int i, j, k; i = a; j = i + 1; k = j - 1; h(i, k); }
with -O2 -g the difference on VTA branch is:
.LLST3:
.quad .LVL1-.Ltext0 # Location list begin address (*.LLST3)
.quad .LVL2-.Ltext0 # Location list end address (*.LLST3)
- .value 0x0 # Location expression size
+ .value 0x5 # Location expression size
+ .byte 0x75 # DW_OP_breg5
+ .sleb128 1
+ .byte 0x9f # DW_OP_stack_value
+ .byte 0x93 # DW_OP_piece
+ .uleb128 0x4
.quad 0x0 # Location list terminator begin (*.LLST3)
.quad 0x0 # Location list terminator end (*.LLST3)
so all of a, i, j and k should now be inspectable in the debugger.
OT, unrelated to VTA and this patch, seems we should try harder to improve
location lists start/end handling, because the testcase is:
f:
.LFB0:
.file 1 "tt.c"
# tt.c:1
.loc 1 1 0
.cfi_startproc
.LVL0:
# basic block 2
.LVL1:
# tt.c:1
.loc 1 1 0
movl %edi, %esi
xorl %eax, %eax
jmp h
.LVL2:
.cfi_endproc
.LFE0:
.size f, .-f
(note empty range from .LVL0 to .LVL1 and that .LVL0 .. .LVL2 covers
the whole function - so except for DW_OP_stack_value/DW_OP_implicit_value
which are only allowed in .debug_loc we could avoid using .debug_loc).
Jakub
-------------- next part --------------
--- gcc/dwarf2.h (revision 148387)
+++ gcc/dwarf2.h (working copy)
@@ -546,6 +546,9 @@ enum dwarf_location_atom
DW_OP_form_tls_address = 0x9b,
DW_OP_call_frame_cfa = 0x9c,
DW_OP_bit_piece = 0x9d,
+ /* DWARF 4 extensions. */
+ DW_OP_implicit_value = 0x9e,
+ DW_OP_stack_value = 0x9f,
DW_OP_lo_user = 0xe0, /* Implementation-defined range start. */
DW_OP_hi_user = 0xff, /* Implementation-defined range end. */
--- gcc/dwarf2out.c (revision 148387)
+++ gcc/dwarf2out.c (working copy)
@@ -4195,6 +4195,10 @@ dwarf_stack_op_name (unsigned int op)
return "DW_OP_call4";
case DW_OP_call_ref:
return "DW_OP_call_ref";
+ case DW_OP_implicit_value:
+ return "DW_OP_implicit_value";
+ case DW_OP_stack_value:
+ return "DW_OP_stack_value";
case DW_OP_GNU_push_tls_address:
return "DW_OP_GNU_push_tls_address";
case DW_OP_GNU_uninit:
@@ -4396,6 +4400,10 @@ size_of_loc_descr (dw_loc_descr_ref loc)
case DW_OP_call_ref:
size += DWARF2_ADDR_SIZE;
break;
+ case DW_OP_implicit_value:
+ size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned)
+ + loc->dw_loc_oprnd1.v.val_unsigned;
+ break;
default:
break;
}
@@ -4431,6 +4439,10 @@ size_of_locs (dw_loc_descr_ref loc)
return size;
}
+#ifdef DWARF2_DEBUGGING_INFO
+static HOST_WIDE_INT extract_int (const unsigned char *, unsigned);
+#endif
+
/* Output location description stack opcode's operands (if any). */
static void
@@ -4469,6 +4481,60 @@ output_loc_operands (dw_loc_descr_ref lo
dw2_asm_output_data (2, offset, NULL);
}
break;
+ case DW_OP_implicit_value:
+ dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
+ switch (val2->val_class)
+ {
+ case dw_val_class_const:
+ dw2_asm_output_data (val1->v.val_unsigned, val2->v.val_int, NULL);
+ break;
+ case dw_val_class_vec:
+ {
+ unsigned int elt_size = val2->v.val_vec.elt_size;
+ unsigned int len = val2->v.val_vec.length;
+ unsigned int i;
+ unsigned char *p;
+
+ if (elt_size > sizeof (HOST_WIDE_INT))
+ {
+ elt_size /= 2;
+ len *= 2;
+ }
+ for (i = 0, p = val2->v.val_vec.array;
+ i < len;
+ i++, p += elt_size)
+ dw2_asm_output_data (elt_size, extract_int (p, elt_size),
+ "fp or vector constant word %u", i);
+ }
+ break;
+ case dw_val_class_long_long:
+ {
+ unsigned HOST_WIDE_INT first, second;
+
+ if (WORDS_BIG_ENDIAN)
+ {
+ first = val2->v.val_long_long.hi;
+ second = val2->v.val_long_long.low;
+ }
+ else
+ {
+ first = val2->v.val_long_long.low;
+ second = val2->v.val_long_long.hi;
+ }
+ dw2_asm_output_data (HOST_BITS_PER_LONG / HOST_BITS_PER_CHAR,
+ first, "long long constant");
+ dw2_asm_output_data (HOST_BITS_PER_LONG / HOST_BITS_PER_CHAR,
+ second, NULL);
+ }
+ break;
+ case dw_val_class_addr:
+ gcc_assert (val1->v.val_unsigned == DWARF2_ADDR_SIZE);
+ dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, val2->v.val_addr, NULL);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ break;
#else
case DW_OP_addr:
case DW_OP_const2u:
@@ -4479,6 +4545,7 @@ output_loc_operands (dw_loc_descr_ref lo
case DW_OP_const8s:
case DW_OP_skip:
case DW_OP_bra:
+ case DW_OP_implicit_value:
/* We currently don't make any attempt to make sure these are
aligned properly like we do for the main unwind info, so
don't support emitting things larger than a byte if we're
@@ -4599,6 +4666,7 @@ output_loc_operands_raw (dw_loc_descr_re
switch (loc->dw_loc_opc)
{
case DW_OP_addr:
+ case DW_OP_implicit_value:
/* We cannot output addresses in .cfi_escape, only bytes. */
gcc_unreachable ();
@@ -5495,7 +5563,8 @@ static dw_loc_descr_ref mem_loc_descript
enum var_init_status);
static dw_loc_descr_ref concat_loc_descriptor (rtx, rtx,
enum var_init_status);
-static dw_loc_descr_ref loc_descriptor (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 HOST_WIDE_INT ceiling (HOST_WIDE_INT, unsigned int);
@@ -5509,7 +5578,6 @@ static void add_AT_location_description
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 *);
-static HOST_WIDE_INT extract_int (const unsigned char *, unsigned);
static void insert_float (const_rtx, unsigned char *);
static rtx rtl_for_decl_location (tree);
static void add_location_or_const_value_attribute (dw_die_ref, tree,
@@ -10536,8 +10604,10 @@ static dw_loc_descr_ref
concat_loc_descriptor (rtx x0, rtx x1, enum var_init_status initialized)
{
dw_loc_descr_ref cc_loc_result = NULL;
- dw_loc_descr_ref x0_ref = loc_descriptor (x0, VAR_INIT_STATUS_INITIALIZED);
- dw_loc_descr_ref x1_ref = loc_descriptor (x1, VAR_INIT_STATUS_INITIALIZED);
+ dw_loc_descr_ref x0_ref
+ = loc_descriptor (x0, VOIDmode, VAR_INIT_STATUS_INITIALIZED);
+ dw_loc_descr_ref x1_ref
+ = loc_descriptor (x1, VOIDmode, VAR_INIT_STATUS_INITIALIZED);
if (x0_ref == 0 || x1_ref == 0)
return 0;
@@ -10569,7 +10639,7 @@ concatn_loc_descriptor (rtx concatn, enu
dw_loc_descr_ref ref;
rtx x = XVECEXP (concatn, 0, i);
- ref = loc_descriptor (x, VAR_INIT_STATUS_INITIALIZED);
+ ref = loc_descriptor (x, VOIDmode, VAR_INIT_STATUS_INITIALIZED);
if (ref == NULL)
return NULL;
@@ -10589,10 +10659,15 @@ concatn_loc_descriptor (rtx concatn, enu
memory location we provide a Dwarf postfix expression describing how to
generate the (dynamic) address of the object onto the address stack.
+ MODE is mode of the decl if this loc_descriptor is going to be used in
+ .debug_loc section where DW_OP_stack_value and DW_OP_implicit_value are
+ allowed, VOIDmode otherwise.
+
If we don't know how to describe it, return 0. */
static dw_loc_descr_ref
-loc_descriptor (rtx rtl, enum var_init_status initialized)
+loc_descriptor (rtx rtl, enum machine_mode mode,
+ enum var_init_status initialized)
{
dw_loc_descr_ref loc_result = NULL;
@@ -10632,7 +10707,8 @@ loc_descriptor (rtx rtl, enum var_init_s
/* Single part. */
if (GET_CODE (XEXP (rtl, 1)) != PARALLEL)
{
- loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0), initialized);
+ loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0), mode,
+ initialized);
break;
}
@@ -10648,7 +10724,7 @@ loc_descriptor (rtx rtl, enum var_init_s
/* Create the first one, so we have something to add to. */
loc_result = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0),
- initialized);
+ VOIDmode, initialized);
if (loc_result == NULL)
return NULL;
mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, 0), 0));
@@ -10658,7 +10734,7 @@ loc_descriptor (rtx rtl, enum var_init_s
dw_loc_descr_ref temp;
temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0),
- initialized);
+ VOIDmode, initialized);
if (temp == NULL)
return NULL;
add_loc_descr (&loc_result, temp);
@@ -10668,8 +10744,205 @@ loc_descriptor (rtx rtl, enum var_init_s
}
break;
+ 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:
+ 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
+ the constant requires more than one word in order to be
+ adequately represented. We output CONST_DOUBLEs as blocks. */
+ mode = GET_MODE (rtl);
+
+ loc_result = new_loc_descr (DW_OP_implicit_value,
+ GET_MODE_SIZE (mode), 0);
+ if (SCALAR_FLOAT_MODE_P (mode))
+ {
+ unsigned int length = GET_MODE_SIZE (mode);
+ unsigned char *array = GGC_NEWVEC (unsigned char, length);
+
+ insert_float (rtl, array);
+ loc_result->dw_loc_oprnd2.val_class = dw_val_class_vec;
+ loc_result->dw_loc_oprnd2.v.val_vec.length = length / 4;
+ loc_result->dw_loc_oprnd2.v.val_vec.elt_size = 4;
+ loc_result->dw_loc_oprnd2.v.val_vec.array = array;
+ }
+ else
+ {
+ /* ??? We really should be using HOST_WIDE_INT throughout. */
+ gcc_assert (HOST_BITS_PER_LONG == HOST_BITS_PER_WIDE_INT);
+
+ loc_result->dw_loc_oprnd2.val_class = dw_val_class_long_long;
+ loc_result->dw_loc_oprnd2.v.val_long_long.hi
+ = CONST_DOUBLE_HIGH (rtl);
+ loc_result->dw_loc_oprnd2.v.val_long_long.low
+ = CONST_DOUBLE_LOW (rtl);
+ }
+ }
+ break;
+
+ case CONST_VECTOR:
+ if (mode != VOIDmode)
+ {
+ unsigned int elt_size = GET_MODE_UNIT_SIZE (GET_MODE (rtl));
+ unsigned int length = CONST_VECTOR_NUNITS (rtl);
+ unsigned char *array = GGC_NEWVEC (unsigned char, length * elt_size);
+ unsigned int i;
+ unsigned char *p;
+
+ mode = GET_MODE (rtl);
+ switch (GET_MODE_CLASS (mode))
+ {
+ case MODE_VECTOR_INT:
+ for (i = 0, p = array; i < length; i++, p += elt_size)
+ {
+ rtx elt = CONST_VECTOR_ELT (rtl, i);
+ HOST_WIDE_INT lo, hi;
+
+ switch (GET_CODE (elt))
+ {
+ case CONST_INT:
+ lo = INTVAL (elt);
+ hi = -(lo < 0);
+ break;
+
+ case CONST_DOUBLE:
+ lo = CONST_DOUBLE_LOW (elt);
+ hi = CONST_DOUBLE_HIGH (elt);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ if (elt_size <= sizeof (HOST_WIDE_INT))
+ insert_int (lo, elt_size, p);
+ else
+ {
+ unsigned char *p0 = p;
+ unsigned char *p1 = p + sizeof (HOST_WIDE_INT);
+
+ gcc_assert (elt_size == 2 * sizeof (HOST_WIDE_INT));
+ if (WORDS_BIG_ENDIAN)
+ {
+ p0 = p1;
+ p1 = p;
+ }
+ insert_int (lo, sizeof (HOST_WIDE_INT), p0);
+ insert_int (hi, sizeof (HOST_WIDE_INT), p1);
+ }
+ }
+ break;
+
+ case MODE_VECTOR_FLOAT:
+ for (i = 0, p = array; i < length; i++, p += elt_size)
+ {
+ rtx elt = CONST_VECTOR_ELT (rtl, i);
+ insert_float (elt, p);
+ }
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ loc_result = new_loc_descr (DW_OP_implicit_value,
+ length * elt_size, 0);
+ loc_result->dw_loc_oprnd2.val_class = dw_val_class_vec;
+ loc_result->dw_loc_oprnd2.v.val_vec.length = length;
+ loc_result->dw_loc_oprnd2.v.val_vec.elt_size = elt_size;
+ loc_result->dw_loc_oprnd2.v.val_vec.array = array;
+ }
+ break;
+
+ case CONST:
+ if (mode == VOIDmode
+ || GET_CODE (XEXP (rtl, 0)) == CONST_INT
+ || GET_CODE (XEXP (rtl, 0)) == CONST_DOUBLE
+ || GET_CODE (XEXP (rtl, 0)) == CONST_VECTOR)
+ {
+ loc_result = loc_descriptor (XEXP (rtl, 0), mode, initialized);
+ break;
+ }
+ /* FALLTHROUGH */
+ case SYMBOL_REF:
+ case LABEL_REF:
+ if (mode != VOIDmode && GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE)
+ {
+ loc_result = new_loc_descr (DW_OP_implicit_value,
+ DWARF2_ADDR_SIZE, 0);
+ loc_result->dw_loc_oprnd2.val_class = dw_val_class_addr;
+ loc_result->dw_loc_oprnd2.v.val_addr = rtl;
+ VEC_safe_push (rtx, gc, used_rtx_array, rtl);
+ }
+ break;
+
default:
- gcc_unreachable ();
+ if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE (rtl) == mode)
+ {
+ /* Value expression. */
+ loc_result = mem_loc_descriptor (rtl, VOIDmode, initialized);
+ if (loc_result)
+ {
+ 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));
+ }
+ }
+ break;
}
return loc_result;
@@ -10809,7 +11082,8 @@ loc_descriptor_from_tree_1 (tree loc, in
/* Certain constructs can only be represented at top-level. */
if (want_address == 2)
- return loc_descriptor (rtl, VAR_INIT_STATUS_INITIALIZED);
+ return loc_descriptor (rtl, VOIDmode,
+ VAR_INIT_STATUS_INITIALIZED);
mode = GET_MODE (rtl);
if (MEM_P (rtl))
@@ -12142,7 +12416,8 @@ add_location_or_const_value_attribute (d
else
initialized = VAR_INIT_STATUS_INITIALIZED;
- descr = loc_by_reference (loc_descriptor (varloc, initialized), decl);
+ descr = loc_by_reference (loc_descriptor (varloc, DECL_MODE (decl),
+ initialized), decl);
list = new_loc_list (descr, node->label, node->next->label, secname, 1);
node = node->next;
@@ -12154,8 +12429,8 @@ add_location_or_const_value_attribute (d
enum var_init_status initialized =
NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
varloc = NOTE_VAR_LOCATION (node->var_loc_note);
- descr = loc_by_reference (loc_descriptor (varloc, initialized),
- decl);
+ descr = loc_by_reference (loc_descriptor (varloc, DECL_MODE (decl),
+ initialized), decl);
add_loc_descr_to_loc_list (&list, descr,
node->label, node->next->label, secname);
}
@@ -12177,7 +12452,9 @@ add_location_or_const_value_attribute (d
current_function_funcdef_no);
endname = ggc_strdup (label_id);
}
- descr = loc_by_reference (loc_descriptor (varloc, initialized),
+ descr = loc_by_reference (loc_descriptor (varloc,
+ DECL_MODE (decl),
+ initialized),
decl);
add_loc_descr_to_loc_list (&list, descr,
node->label, endname, secname);
@@ -12206,7 +12483,8 @@ add_location_or_const_value_attribute (d
enum var_init_status status;
node = loc_list->first;
status = NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
- descr = loc_descriptor (NOTE_VAR_LOCATION (node->var_loc_note), status);
+ descr = loc_descriptor (NOTE_VAR_LOCATION (node->var_loc_note),
+ VOIDmode, status);
if (descr)
{
descr = loc_by_reference (descr, decl);
-------------- next part --------------
--- gcc/dwarf2.h.jj 2009-06-10 22:23:08.000000000 +0200
+++ gcc/dwarf2.h 2009-06-11 09:41:52.000000000 +0200
@@ -546,6 +546,9 @@ enum dwarf_location_atom
DW_OP_form_tls_address = 0x9b,
DW_OP_call_frame_cfa = 0x9c,
DW_OP_bit_piece = 0x9d,
+ /* DWARF 4 extensions. */
+ DW_OP_implicit_value = 0x9e,
+ DW_OP_stack_value = 0x9f,
DW_OP_lo_user = 0xe0, /* Implementation-defined range start. */
DW_OP_hi_user = 0xff, /* Implementation-defined range end. */
--- gcc/dwarf2out.c.jj 2009-06-10 22:23:08.000000000 +0200
+++ gcc/dwarf2out.c 2009-06-11 16:00:20.000000000 +0200
@@ -3822,6 +3822,10 @@ dwarf_stack_op_name (unsigned int op)
return "DW_OP_call4";
case DW_OP_call_ref:
return "DW_OP_call_ref";
+ case DW_OP_implicit_value:
+ return "DW_OP_implicit_value";
+ case DW_OP_stack_value:
+ return "DW_OP_stack_value";
case DW_OP_GNU_push_tls_address:
return "DW_OP_GNU_push_tls_address";
case DW_OP_GNU_uninit:
@@ -4023,6 +4027,10 @@ size_of_loc_descr (dw_loc_descr_ref loc)
case DW_OP_call_ref:
size += DWARF2_ADDR_SIZE;
break;
+ case DW_OP_implicit_value:
+ size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned)
+ + loc->dw_loc_oprnd1.v.val_unsigned;
+ break;
default:
break;
}
@@ -4058,6 +4066,10 @@ size_of_locs (dw_loc_descr_ref loc)
return size;
}
+#ifdef DWARF2_DEBUGGING_INFO
+static HOST_WIDE_INT extract_int (const unsigned char *, unsigned);
+#endif
+
/* Output location description stack opcode's operands (if any). */
static void
@@ -4096,6 +4108,60 @@ output_loc_operands (dw_loc_descr_ref lo
dw2_asm_output_data (2, offset, NULL);
}
break;
+ case DW_OP_implicit_value:
+ dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
+ switch (val2->val_class)
+ {
+ case dw_val_class_const:
+ dw2_asm_output_data (val1->v.val_unsigned, val2->v.val_int, NULL);
+ break;
+ case dw_val_class_vec:
+ {
+ unsigned int elt_size = val2->v.val_vec.elt_size;
+ unsigned int len = val2->v.val_vec.length;
+ unsigned int i;
+ unsigned char *p;
+
+ if (elt_size > sizeof (HOST_WIDE_INT))
+ {
+ elt_size /= 2;
+ len *= 2;
+ }
+ for (i = 0, p = val2->v.val_vec.array;
+ i < len;
+ i++, p += elt_size)
+ dw2_asm_output_data (elt_size, extract_int (p, elt_size),
+ "fp or vector constant word %u", i);
+ }
+ break;
+ case dw_val_class_long_long:
+ {
+ unsigned HOST_WIDE_INT first, second;
+
+ if (WORDS_BIG_ENDIAN)
+ {
+ first = val2->v.val_long_long.hi;
+ second = val2->v.val_long_long.low;
+ }
+ else
+ {
+ first = val2->v.val_long_long.low;
+ second = val2->v.val_long_long.hi;
+ }
+ dw2_asm_output_data (HOST_BITS_PER_LONG / HOST_BITS_PER_CHAR,
+ first, "long long constant");
+ dw2_asm_output_data (HOST_BITS_PER_LONG / HOST_BITS_PER_CHAR,
+ second, NULL);
+ }
+ break;
+ case dw_val_class_addr:
+ gcc_assert (val1->v.val_unsigned == DWARF2_ADDR_SIZE);
+ dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, val2->v.val_addr, NULL);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ break;
#else
case DW_OP_addr:
case DW_OP_const2u:
@@ -4106,6 +4172,7 @@ output_loc_operands (dw_loc_descr_ref lo
case DW_OP_const8s:
case DW_OP_skip:
case DW_OP_bra:
+ case DW_OP_implicit_value:
/* We currently don't make any attempt to make sure these are
aligned properly like we do for the main unwind info, so
don't support emitting things larger than a byte if we're
@@ -4226,6 +4293,7 @@ output_loc_operands_raw (dw_loc_descr_re
switch (loc->dw_loc_opc)
{
case DW_OP_addr:
+ case DW_OP_implicit_value:
/* We cannot output addresses in .cfi_escape, only bytes. */
gcc_unreachable ();
@@ -5123,7 +5191,8 @@ static dw_loc_descr_ref mem_loc_descript
enum var_init_status);
static dw_loc_descr_ref concat_loc_descriptor (rtx, rtx,
enum var_init_status);
-static dw_loc_descr_ref loc_descriptor (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 HOST_WIDE_INT ceiling (HOST_WIDE_INT, unsigned int);
@@ -5137,7 +5206,6 @@ static void add_AT_location_description
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 *);
-static HOST_WIDE_INT extract_int (const unsigned char *, unsigned);
static void insert_float (const_rtx, unsigned char *);
static rtx rtl_for_decl_location (tree);
static void add_location_or_const_value_attribute (dw_die_ref, tree,
@@ -10274,8 +10342,10 @@ static dw_loc_descr_ref
concat_loc_descriptor (rtx x0, rtx x1, enum var_init_status initialized)
{
dw_loc_descr_ref cc_loc_result = NULL;
- dw_loc_descr_ref x0_ref = loc_descriptor (x0, VAR_INIT_STATUS_INITIALIZED);
- dw_loc_descr_ref x1_ref = loc_descriptor (x1, VAR_INIT_STATUS_INITIALIZED);
+ dw_loc_descr_ref x0_ref
+ = loc_descriptor (x0, VOIDmode, VAR_INIT_STATUS_INITIALIZED);
+ dw_loc_descr_ref x1_ref
+ = loc_descriptor (x1, VOIDmode, VAR_INIT_STATUS_INITIALIZED);
if (x0_ref == 0 || x1_ref == 0)
return 0;
@@ -10307,7 +10377,7 @@ concatn_loc_descriptor (rtx concatn, enu
dw_loc_descr_ref ref;
rtx x = XVECEXP (concatn, 0, i);
- ref = loc_descriptor (x, VAR_INIT_STATUS_INITIALIZED);
+ ref = loc_descriptor (x, VOIDmode, VAR_INIT_STATUS_INITIALIZED);
if (ref == NULL)
return NULL;
@@ -10327,10 +10397,15 @@ concatn_loc_descriptor (rtx concatn, enu
memory location we provide a Dwarf postfix expression describing how to
generate the (dynamic) address of the object onto the address stack.
+ MODE is mode of the decl if this loc_descriptor is going to be used in
+ .debug_loc section where DW_OP_stack_value and DW_OP_implicit_value are
+ allowed, VOIDmode otherwise.
+
If we don't know how to describe it, return 0. */
static dw_loc_descr_ref
-loc_descriptor (rtx rtl, enum var_init_status initialized)
+loc_descriptor (rtx rtl, enum machine_mode mode,
+ enum var_init_status initialized)
{
dw_loc_descr_ref loc_result = NULL;
@@ -10372,7 +10447,8 @@ loc_descriptor (rtx rtl, enum var_init_s
/* Single part. */
if (GET_CODE (XEXP (rtl, 1)) != PARALLEL)
{
- loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0), initialized);
+ loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0), mode,
+ initialized);
break;
}
@@ -10388,7 +10464,7 @@ loc_descriptor (rtx rtl, enum var_init_s
/* Create the first one, so we have something to add to. */
loc_result = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0),
- initialized);
+ VOIDmode, initialized);
if (loc_result == NULL)
return NULL;
mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, 0), 0));
@@ -10398,7 +10474,7 @@ loc_descriptor (rtx rtl, enum var_init_s
dw_loc_descr_ref temp;
temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0),
- initialized);
+ VOIDmode, initialized);
if (temp == NULL)
return NULL;
add_loc_descr (&loc_result, temp);
@@ -10408,12 +10484,204 @@ loc_descriptor (rtx rtl, enum var_init_s
}
break;
+ 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:
+ 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
+ the constant requires more than one word in order to be
+ adequately represented. We output CONST_DOUBLEs as blocks. */
+ mode = GET_MODE (rtl);
+
+ loc_result = new_loc_descr (DW_OP_implicit_value,
+ GET_MODE_SIZE (mode), 0);
+ if (SCALAR_FLOAT_MODE_P (mode))
+ {
+ unsigned int length = GET_MODE_SIZE (mode);
+ unsigned char *array = GGC_NEWVEC (unsigned char, length);
+
+ insert_float (rtl, array);
+ loc_result->dw_loc_oprnd2.val_class = dw_val_class_vec;
+ loc_result->dw_loc_oprnd2.v.val_vec.length = length / 4;
+ loc_result->dw_loc_oprnd2.v.val_vec.elt_size = 4;
+ loc_result->dw_loc_oprnd2.v.val_vec.array = array;
+ }
+ else
+ {
+ /* ??? We really should be using HOST_WIDE_INT throughout. */
+ gcc_assert (HOST_BITS_PER_LONG == HOST_BITS_PER_WIDE_INT);
+
+ loc_result->dw_loc_oprnd2.val_class = dw_val_class_long_long;
+ loc_result->dw_loc_oprnd2.v.val_long_long.hi
+ = CONST_DOUBLE_HIGH (rtl);
+ loc_result->dw_loc_oprnd2.v.val_long_long.low
+ = CONST_DOUBLE_LOW (rtl);
+ }
+ }
+ break;
+
+ case CONST_VECTOR:
+ if (mode != VOIDmode)
+ {
+ unsigned int elt_size = GET_MODE_UNIT_SIZE (GET_MODE (rtl));
+ unsigned int length = CONST_VECTOR_NUNITS (rtl);
+ unsigned char *array = GGC_NEWVEC (unsigned char, length * elt_size);
+ unsigned int i;
+ unsigned char *p;
+
+ mode = GET_MODE (rtl);
+ switch (GET_MODE_CLASS (mode))
+ {
+ case MODE_VECTOR_INT:
+ for (i = 0, p = array; i < length; i++, p += elt_size)
+ {
+ rtx elt = CONST_VECTOR_ELT (rtl, i);
+ HOST_WIDE_INT lo, hi;
+
+ switch (GET_CODE (elt))
+ {
+ case CONST_INT:
+ lo = INTVAL (elt);
+ hi = -(lo < 0);
+ break;
+
+ case CONST_DOUBLE:
+ lo = CONST_DOUBLE_LOW (elt);
+ hi = CONST_DOUBLE_HIGH (elt);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ if (elt_size <= sizeof (HOST_WIDE_INT))
+ insert_int (lo, elt_size, p);
+ else
+ {
+ unsigned char *p0 = p;
+ unsigned char *p1 = p + sizeof (HOST_WIDE_INT);
+
+ gcc_assert (elt_size == 2 * sizeof (HOST_WIDE_INT));
+ if (WORDS_BIG_ENDIAN)
+ {
+ p0 = p1;
+ p1 = p;
+ }
+ insert_int (lo, sizeof (HOST_WIDE_INT), p0);
+ insert_int (hi, sizeof (HOST_WIDE_INT), p1);
+ }
+ }
+ break;
+
+ case MODE_VECTOR_FLOAT:
+ for (i = 0, p = array; i < length; i++, p += elt_size)
+ {
+ rtx elt = CONST_VECTOR_ELT (rtl, i);
+ insert_float (elt, p);
+ }
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ loc_result = new_loc_descr (DW_OP_implicit_value,
+ length * elt_size, 0);
+ loc_result->dw_loc_oprnd2.val_class = dw_val_class_vec;
+ loc_result->dw_loc_oprnd2.v.val_vec.length = length;
+ loc_result->dw_loc_oprnd2.v.val_vec.elt_size = elt_size;
+ loc_result->dw_loc_oprnd2.v.val_vec.array = array;
+ }
+ break;
+
case CONST:
- loc_result = loc_descriptor (XEXP (rtl, 0), initialized);
+ if (mode == VOIDmode
+ || GET_CODE (XEXP (rtl, 0)) == CONST_INT
+ || GET_CODE (XEXP (rtl, 0)) == CONST_DOUBLE
+ || GET_CODE (XEXP (rtl, 0)) == CONST_VECTOR)
+ {
+ loc_result = loc_descriptor (XEXP (rtl, 0), mode, initialized);
+ break;
+ }
+ /* FALLTHROUGH */
+ case SYMBOL_REF:
+ case LABEL_REF:
+ if (mode != VOIDmode && GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE)
+ {
+ loc_result = new_loc_descr (DW_OP_implicit_value,
+ DWARF2_ADDR_SIZE, 0);
+ loc_result->dw_loc_oprnd2.val_class = dw_val_class_addr;
+ loc_result->dw_loc_oprnd2.v.val_addr = rtl;
+ VEC_safe_push (rtx, gc, used_rtx_array, rtl);
+ }
break;
default:
- /* Value expression. */
+ if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE (rtl) == mode)
+ {
+ /* Value expression. */
+ loc_result = mem_loc_descriptor (rtl, VOIDmode, initialized);
+ if (loc_result)
+ {
+ 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));
+ }
+ }
break;
}
@@ -10554,7 +10822,8 @@ loc_descriptor_from_tree_1 (tree loc, in
/* Certain constructs can only be represented at top-level. */
if (want_address == 2)
- return loc_descriptor (rtl, VAR_INIT_STATUS_INITIALIZED);
+ return loc_descriptor (rtl, VOIDmode,
+ VAR_INIT_STATUS_INITIALIZED);
mode = GET_MODE (rtl);
if (MEM_P (rtl))
@@ -11887,7 +12156,8 @@ add_location_or_const_value_attribute (d
else
initialized = VAR_INIT_STATUS_INITIALIZED;
- descr = loc_by_reference (loc_descriptor (varloc, initialized), decl);
+ descr = loc_by_reference (loc_descriptor (varloc, DECL_MODE (decl),
+ initialized), decl);
list = new_loc_list (descr, node->label, node->next->label, secname, 1);
node = node->next;
@@ -11899,8 +12169,8 @@ add_location_or_const_value_attribute (d
enum var_init_status initialized =
NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
varloc = NOTE_VAR_LOCATION (node->var_loc_note);
- descr = loc_by_reference (loc_descriptor (varloc, initialized),
- decl);
+ descr = loc_by_reference (loc_descriptor (varloc, DECL_MODE (decl),
+ initialized), decl);
add_loc_descr_to_loc_list (&list, descr,
node->label, node->next->label, secname);
}
@@ -11922,7 +12192,9 @@ add_location_or_const_value_attribute (d
current_function_funcdef_no);
endname = ggc_strdup (label_id);
}
- descr = loc_by_reference (loc_descriptor (varloc, initialized),
+ descr = loc_by_reference (loc_descriptor (varloc,
+ DECL_MODE (decl),
+ initialized),
decl);
add_loc_descr_to_loc_list (&list, descr,
node->label, endname, secname);
@@ -11951,7 +12223,8 @@ add_location_or_const_value_attribute (d
enum var_init_status status;
node = loc_list->first;
status = NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
- descr = loc_descriptor (NOTE_VAR_LOCATION (node->var_loc_note), status);
+ descr = loc_descriptor (NOTE_VAR_LOCATION (node->var_loc_note),
+ VOIDmode, status);
if (descr)
{
descr = loc_by_reference (descr, decl);
More information about the Gcc-patches
mailing list