On Fri, Aug 15, 2014 at 9:59 PM, Aldy Hernandez <al...@redhat.com> wrote: > So... I've been getting my feet wet with LTO and debugging and I noticed a > seemingly unrelated yet annoying problem. On x86-64, > gcc.dg/guality/pr48437.c fails when run in LTO mode. > > I've compared the dwarf output with and without LTO, and I noticed that the > DW_TAG_lexical_block is missing from the LTO case. > > The relevant bit is that without LTO, we have a DW_TAG_lexical_block for > lines 3-6, which is not present in the LTO case: > > 1 volatile int i; > 2 for (i = 3; i < 7; ++i) > 3 { > 4 extern int i; > 5 asm volatile (NOP : : : "memory"); > 6 } > > The reason this tag is not generated is because gen_block_die() unsets > must_output_die because there are no BLOCK_VARS associated with the BLOCK. > > must_output_die = ((BLOCK_VARS (stmt) != NULL > || BLOCK_NUM_NONLOCALIZED_VARS (stmt)) > && (TREE_USED (stmt) > || TREE_ASM_WRITTEN (stmt) > || BLOCK_ABSTRACT (stmt))); > > And there is no block var because the streamer purposely avoided streaming > an extern block var: > > /* We avoid outputting external vars or functions by reference > to the global decls section as we do not want to have them > enter decl merging. This is, of course, only for the call > for streaming BLOCK_VARS, but other callers are safe. */ > /* ??? FIXME wrt SCC streaming. Drop these for now. */ > if (VAR_OR_FUNCTION_DECL_P (t) > && DECL_EXTERNAL (t)) > ; /* stream_write_tree_shallow_non_ref (ob, t, ref_p); */ > else > stream_write_tree (ob, t, ref_p); > > I naively tried to uncomment the offending line, but that brought about > other problems in DFS assertions. > > I wasn't on the hunt for this, but I'm now curious. Can you (or anyone > else) pontificate on this? Do we avoid streaming extern block variables by > design?
Apart from other comments about emitting DIEs early the commented code above tried to "force" to not put 't' into the global decls table but retain it as local tree to avoid (as Honza says) merging it with other entities and thus screwing up DECL_CHAIN. With the SCC way this didn't work out (you can't simply do stream_write_tree_shallow_non_ref here for reasons I don't remember). The ??? comment means I've wanted to come back to this... ;) "shallow non-ref" means treat 't' as !ref but not the trees it references. Note that the biggest "hack" wrt lexical scopes is that we don't stream any abstract origins /* Write all pointer fields in the TS_BLOCK structure of EXPR to output block OB. If REF_P is true, write a reference to EXPR's pointer fields. */ static void write_ts_block_tree_pointers (struct output_block *ob, tree expr, bool ref_p) { streamer_write_chain (ob, BLOCK_VARS (expr), ref_p); stream_write_tree (ob, BLOCK_SUPERCONTEXT (expr), ref_p); /* Stream BLOCK_ABSTRACT_ORIGIN for the limited cases we can handle - those that represent inlined function scopes. For the rest them on the floor instead of ICEing in dwarf2out.c. */ if (inlined_function_outer_scope_p (expr)) { tree ultimate_origin = block_ultimate_origin (expr); stream_write_tree (ob, ultimate_origin, ref_p); } else stream_write_tree (ob, NULL_TREE, ref_p); which makes early inlined functions behave differently (?) in the debugger with LTO than without (you still get blocks, but they do not refer to the out-of-line copy by reference but get fully re-created with DIEs for each inline instance). But maybe the abstract origins are only a dwarf-size optimization here. Richard. > Thanks. > Aldy