This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix inlining of calls with NULL block (PR56515)


When inlining call stmts with a NULL gimple_block we still remap
all the callee blocks into a block tree copy but we'll end up
not referencing it from anywhere.  This causes verification failures
because then we have nothing refering to the inline stmt blocks.

This seems to be an issue mostly with calls created by GCC itself
and later via LTO found to have a body and being inlineable.  But
with the new location block scheme it is a general defect of the
inliner (in case we don't want to force all call stmts to have
an associated block).

The following patch simply arranges for the callee blocks to
be remapped to NULL_TREE in the copy in the caller.  Another
possibility would be to put the remapped block tree into
the caller as sibling of its DECL_INITIAL (but that might
cause strange scope change artifacts when debugging).

A full solution might consist of adding a GIMPLE call stmt
flag to tell whether a call is artificial and decide what to
do when inlining such calls (the patch fails to re-set the
rest of the location info).  We'd then verify that all
non-artificial calls have an associated block.

Sofar very lightly tested (on the testcase in the PR).

Jakub, what do you think?

Thanks,
Richard.

2013-03-04  Richard Biener  <rguenther@suse.de>

	PR lto/56515
	* tree-inline.c (remap_blocks_to_null): New function.
	(expand_call_inline): When expanding a call stmt without
	an associated block inline remap all callee blocks to NULL.

Index: gcc/tree-inline.c
===================================================================
*** gcc/tree-inline.c	(revision 196423)
--- gcc/tree-inline.c	(working copy)
*************** remap_blocks (tree block, copy_body_data
*** 651,656 ****
--- 651,666 ----
    return new_tree;
  }
  
+ /* Remap the block tree rooted at BLOCK to nothing.  */
+ static void
+ remap_blocks_to_null (tree block, copy_body_data *id)
+ {
+   tree t;
+   insert_decl_map (id, block, NULL_TREE);
+   for (t = BLOCK_SUBBLOCKS (block); t ; t = BLOCK_CHAIN (t))
+     remap_blocks_to_null (t, id);
+ }
+ 
  static void
  copy_statement_list (tree *tp)
  {
*************** expand_call_inline (basic_block bb, gimp
*** 3909,3919 ****
       actual inline expansion of the body, and a label for the return
       statements within the function to jump to.  The type of the
       statement expression is the return type of the function call.  */
-   id->block = make_node (BLOCK);
-   BLOCK_ABSTRACT_ORIGIN (id->block) = fn;
-   BLOCK_SOURCE_LOCATION (id->block) = input_location;
    if (gimple_block (stmt))
!     prepend_lexical_block (gimple_block (stmt), id->block);
  
    /* Local declarations will be replaced by their equivalents in this
       map.  */
--- 3919,3931 ----
       actual inline expansion of the body, and a label for the return
       statements within the function to jump to.  The type of the
       statement expression is the return type of the function call.  */
    if (gimple_block (stmt))
!     {
!       id->block = make_node (BLOCK);
!       BLOCK_ABSTRACT_ORIGIN (id->block) = fn;
!       BLOCK_SOURCE_LOCATION (id->block) = input_location;
!       prepend_lexical_block (gimple_block (stmt), id->block);
!     }
  
    /* Local declarations will be replaced by their equivalents in this
       map.  */
*************** expand_call_inline (basic_block bb, gimp
*** 3942,3968 ****
  
    if (DECL_INITIAL (fn))
      {
!       tree *var;
  
!       prepend_lexical_block (id->block, remap_blocks (DECL_INITIAL (fn), id));
!       gcc_checking_assert (BLOCK_SUBBLOCKS (id->block)
! 			   && (BLOCK_CHAIN (BLOCK_SUBBLOCKS (id->block))
! 			       == NULL_TREE));
!       /* Move vars for PARM_DECLs from DECL_INITIAL block to id->block,
! 	 otherwise for DWARF DW_TAG_formal_parameter will not be children of
! 	 DW_TAG_inlined_subroutine, but of a DW_TAG_lexical_block
! 	 under it.  The parameters can be then evaluated in the debugger,
! 	 but don't show in backtraces.  */
!       for (var = &BLOCK_VARS (BLOCK_SUBBLOCKS (id->block)); *var; )
! 	if (TREE_CODE (DECL_ORIGIN (*var)) == PARM_DECL)
! 	  {
! 	    tree v = *var;
! 	    *var = TREE_CHAIN (v);
! 	    TREE_CHAIN (v) = BLOCK_VARS (id->block);
! 	    BLOCK_VARS (id->block) = v;
! 	  }
! 	else
! 	  var = &TREE_CHAIN (*var);
      }
  
    /* Return statements in the function body will be replaced by jumps
--- 3954,3986 ----
  
    if (DECL_INITIAL (fn))
      {
!       if (gimple_block (stmt))
! 	{
! 	  tree *var;
  
! 	  prepend_lexical_block (id->block,
! 				 remap_blocks (DECL_INITIAL (fn), id));
! 	  gcc_checking_assert (BLOCK_SUBBLOCKS (id->block)
! 			       && (BLOCK_CHAIN (BLOCK_SUBBLOCKS (id->block))
! 				   == NULL_TREE));
! 	  /* Move vars for PARM_DECLs from DECL_INITIAL block to id->block,
! 	     otherwise for DWARF DW_TAG_formal_parameter will not be children of
! 	     DW_TAG_inlined_subroutine, but of a DW_TAG_lexical_block
! 	     under it.  The parameters can be then evaluated in the debugger,
! 	     but don't show in backtraces.  */
! 	  for (var = &BLOCK_VARS (BLOCK_SUBBLOCKS (id->block)); *var; )
! 	    if (TREE_CODE (DECL_ORIGIN (*var)) == PARM_DECL)
! 	      {
! 		tree v = *var;
! 		*var = TREE_CHAIN (v);
! 		TREE_CHAIN (v) = BLOCK_VARS (id->block);
! 		BLOCK_VARS (id->block) = v;
! 	      }
! 	    else
! 	      var = &TREE_CHAIN (*var);
! 	}
!       else
! 	remap_blocks_to_null (DECL_INITIAL (fn), id);
      }
  
    /* Return statements in the function body will be replaced by jumps
*************** expand_call_inline (basic_block bb, gimp
*** 4106,4112 ****
       inlined.  If we don't do this now, we can lose the information about the
       variables in the function when the blocks get blown away as soon as we
       remove the cgraph node.  */
!   (*debug_hooks->outlining_inline_function) (cg_edge->callee->symbol.decl);
  
    /* Update callgraph if needed.  */
    cgraph_remove_node (cg_edge->callee);
--- 4124,4131 ----
       inlined.  If we don't do this now, we can lose the information about the
       variables in the function when the blocks get blown away as soon as we
       remove the cgraph node.  */
!   if (gimple_block (stmt))
!     (*debug_hooks->outlining_inline_function) (cg_edge->callee->symbol.decl);
  
    /* Update callgraph if needed.  */
    cgraph_remove_node (cg_edge->callee);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]