Bug 51695 - NOTE_INSN_VAR_LOCATION notes are sometimes too large
Summary: NOTE_INSN_VAR_LOCATION notes are sometimes too large
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: debug (show other bugs)
Version: 4.7.0
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: ice-on-valid-code
: 50203 (view as bug list)
Depends on:
Blocks:
 
Reported: 2011-12-28 11:29 UTC by Jakub Jelinek
Modified: 2012-07-02 13:00 UTC (History)
3 users (show)

See Also:
Host:
Target: x86_64-linux
Build:
Known to work:
Known to fail:
Last reconfirmed: 2011-12-30 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jakub Jelinek 2011-12-28 11:29:10 UTC
typedef struct
{
  struct { unsigned int t1, t2, t3, t4, t5, t6; } t;
  int p;
  struct { double X, Y, Z; } r;
} T;
typedef struct { T *h; } S;

static unsigned int v = 0x12345678;

int
foo (void)
{
  v = (v & 0x80000000) ? ((v << 1) ^ 0xa398655d) : (v << 1);
  return 0;
}

double
bar (void)
{
  unsigned int o;
  v = (v & 0x80000000) ? ((v << 1) ^ 0xa398655d) : (v << 1);
  o = v & 0xffff;
  return (double) o / 32768.0;
}

int
baz (void)
{
  foo ();
  return 0;
}

void
test (S *x)
{
  T *t = x->h;
  t->t.t1 = foo ();
  t->t.t2 = foo ();
  t->t.t3 = foo ();
  t->t.t4 = foo ();
  t->t.t5 = foo ();
  t->t.t6 = foo ();
  t->p = baz ();
  t->r.X = bar ();
  t->r.Y = bar ();
  t->r.Z = bar ();
}

ICEs at -O2 -g, starting with http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=180194
Comment 1 Jakub Jelinek 2011-12-28 11:35:23 UTC
The NOTE_INSN_VAR_LOCATION argument for variable o is extremely huge in this case and we hit the 64KB limit on .debug_loc expressions.
Comment 2 Andrew Pinski 2011-12-30 23:32:06 UTC
(note 218 174 131 2 (var_location o (and:SI (reg:SI 1 dx [orig:90 iftmp.0 ] [90])
    (const_int 65535 [0xffff]))) NOTE_INSN_VAR_LOCATION)

(insn:TI 131 218 219 2 (parallel [
            (set (reg:SI 2 cx [135])
                (and:SI (reg:SI 1 dx [orig:90 iftmp.0 ] [90])
                    (const_int 65535 [0xffff])))
            (clobber (reg:CC 17 flags))
        ]) t.c:23 380 {*andsi_1}
     (expr_list:REG_UNUSED (reg:CC 17 flags)
        (nil)))

(note 219 131 116 2 (var_location o (and:SI ....

I think that last var_location should just be like the others and use cx instead.

Confirmed.
Comment 3 Jakub Jelinek 2012-01-04 11:04:41 UTC
We can always work around this as in (completely untested):

--- gcc/dwarf2out.c	2012-01-03 16:22:48.794866121 +0100
+++ gcc/dwarf2out.c	2012-01-04 11:50:30.516022278 +0100
@@ -8166,6 +8166,13 @@ output_loc_list (dw_loc_list_ref list_he
       /* Don't output an entry that starts and ends at the same address.  */
       if (strcmp (curr->begin, curr->end) == 0 && !curr->force)
 	continue;
+      size = size_of_locs (curr->expr);
+      /* If the expression is too large, drop it on the floor.  We could
+	 perhaps put it into DW_TAG_dwarf_procedure and refer to that
+	 in the expression, but >= 64KB expressions for a single value
+	 in a single range are unlikely very useful.  */
+      if (size > 0xffff)
+	continue;
       if (!have_multiple_function_sections)
 	{
 	  dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->begin, curr->section,
@@ -8184,7 +8191,6 @@ output_loc_list (dw_loc_list_ref list_he
 			       "Location list end address (%s)",
 			       list_head->ll_symbol);
 	}
-      size = size_of_locs (curr->expr);
 
       /* Output the block length for this list of location operations.  */
       gcc_assert (size <= 0xffff);

But it would be nice to a) find out how can we limit the excessive expression sizes still during var-tracking, because it might consume lots of compile time memory b) if we can't do anything smarter at least in cases like PR51695 where the expression is so huge just because it keeps computing the same values again and again and again.  If we remembered we have computed some VALUE (with a non-trivial expression of more than say 16 rtxes in it), we could represent it
as tmpforvalueXXX = the_rtx, and then just use the temporary in all places.
In the DWARF expression it would mean we'd compute (all the temporaries) first
and keep them pushed into the DWARF stack, then once all those are computed we'd just DW_OP_picked the values we want (as many times as needed).
So, e.g. in the pr51695 case, we'd have a temporary for:
(if_then_else:SI (lt (mem/c/i:SI (symbol_ref:DI ("v") [flags 0x2]  <var_decl 0x7 f431dcea140 v>) [2 v+0 S4 A32]) (const_int 0 [0]))
(xor:SI (ashift:SI (mem/c/i:SI (symbol_ref:DI ("v") [flags 0x2]  <var_decl 0x7f431dcea140 v>) [2 v+0 S4 A32]) (const_int 1 [0x1]))
(const_int -1550293667 [0xffffffffa398655d]))
(ashift:SI (mem/c/i:SI (symbol_ref:DI ("v") [flags 0x2]  <var_decl 0x7f431dcea140 v>) [2 v+0 S4 A32]) (const_int 1 [0x1])))
expression and use it in all the places where it is used (in that testcase this is used over 2000 times), then perhaps some larger expression that uses these many times would be again a temporary, etc. and here we could end up with a DWARF expression of only few dozens of bytes.
Comment 4 Jakub Jelinek 2012-01-04 11:25:57 UTC
One problem with such temporaries approach would be that if the temporaries are in the whole expression evaluated only conditionally, they could have unwanted side-effects (reading uninitialized memory, division by zero, producing NaNs etc.) that the debugger might complain about loudly.
Say if the expression is (if_then_else (r1 < 56) (temp1) (const_int 0))
where temp1 is (mem (foo + r1)) or similar, if we evaluate it upfront, the debugger might complain.
Another alternative would be (for a dwarf2out.c solution, so the compile time memory issue would be still there) when we'd be finalizing all the DWARF expressions in the CU, we'd somehow hash the larger subexpressions where it might be beneficial and if they are long enough and occur at least twice, create a DW_TAG_dwarf_procedure for them and just replace those subexpressions with DW_OP_call* to that procedure.
Comment 5 Jan Kratochvil 2012-01-04 14:20:29 UTC
(In reply to comment #4)
> they could have unwanted
> side-effects (reading uninitialized memory, division by zero, producing NaNs
> etc.) that the debugger might complain about loudly.

GDB will complain.


> create a DW_TAG_dwarf_procedure for them and just replace those subexpressions
> with DW_OP_call* to that procedure.

DW_OP_call{2,4} is supported by GDB now.  DW_TAG_dwarf_procedure is unsupported now but it looks like a "oneliner" patch, ping me for DW_TAG_dwarf_procedure implementation, please.
Comment 6 Jakub Jelinek 2012-01-04 19:58:07 UTC
Author: jakub
Date: Wed Jan  4 19:58:03 2012
New Revision: 182886

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=182886
Log:
	PR debug/51695
	* dwarf2out.c (output_loc_list): For now drop >= 64KB expressions
	in .debug_loc on the floor.

	* gcc.dg/pr51695.c: New test.

Added:
    trunk/gcc/testsuite/gcc.dg/pr51695.c
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/dwarf2out.c
    trunk/gcc/testsuite/ChangeLog
Comment 7 Jakub Jelinek 2012-01-05 06:49:59 UTC
The ICE is now fixed, keeping the bug open to track doing something about limiting the expression sizes on the var-tracking side and/or doing something with the temporaries and/or subexpression redundancy removal.
Comment 8 Andrew Pinski 2012-01-19 05:47:40 UTC
*** Bug 50203 has been marked as a duplicate of this bug. ***
Comment 9 Jakub Jelinek 2012-02-09 17:18:51 UTC
Author: jakub
Date: Thu Feb  9 17:18:42 2012
New Revision: 184052

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=184052
Log:
	Backported from mainline
	2012-01-04  Jakub Jelinek  <jakub@redhat.com>

	PR debug/51695
	* dwarf2out.c (output_loc_list): For now drop >= 64KB expressions
	in .debug_loc on the floor.

	* gcc.dg/pr51695.c: New test.

Added:
    branches/gcc-4_6-branch/gcc/testsuite/gcc.dg/pr51695.c
Modified:
    branches/gcc-4_6-branch/gcc/ChangeLog
    branches/gcc-4_6-branch/gcc/dwarf2out.c
    branches/gcc-4_6-branch/gcc/testsuite/ChangeLog
Comment 10 Richard Biener 2012-03-22 08:26:59 UTC
GCC 4.7.0 is being released, adjusting target milestone.