Re: [patch] Fix segfault during inlining of thunk

2019-01-23 Thread Richard Biener
On Wed, Jan 23, 2019 at 10:48 AM Eric Botcazou  wrote:
>
> Hi,
>
> this is a regression present in Ada on the mainline since we switched to using
> the internal support for thunks: expand_thunk segfaults during inlining when
> trying to access the DECL_RESULT of the special alias built to make the call
> from the thunk local, if the DECL_RESULT of the thunk is DECL_BY_REFERENCE.
>
> It turns out that neither the C++ nor the Ada front-end builds the DECL_RESULT
> of this special alias (the C++ front-end apparently doesn't even build that of
> the thunk itself so expand_thunk has code to patch this up).  Moreover it's a
> bit strange to first try:
>
>restmp = gimple_fold_indirect_ref (resdecl);
>
> i.e. build the dereference using the type of resdecl and then use the type of
> the DECL_RESULT of the alias if this failed.  So the attached fix changes this
> to using the type of resdecl in the latter case too.
>
> Bootstrapped/regtested on x86_64-suse-linux, OK for the mainline?

OK.

I guess the original (cut?) error was to look at DECL_RESULT (alias)
instead of DECL_RESULT (thunk_fndecl) which would have made this
consistent as well.

Richard.

>
> 2019-01-22  Eric Botcazou  
>
> * cgraphunit.c (cgraph_node::expand_thunk): When expanding a GIMPLE
> thunk that returns by reference, use the type of the return object
> of the thunk instead of that of the alias to build the dereference.
>
>
> 2019-01-23  Eric Botcazou  
>
> * gnat.dg/specs/opt4.ads: New test.
>
> --
> Eric Botcazou


[patch] Fix segfault during inlining of thunk

2019-01-23 Thread Eric Botcazou
Hi,

this is a regression present in Ada on the mainline since we switched to using 
the internal support for thunks: expand_thunk segfaults during inlining when 
trying to access the DECL_RESULT of the special alias built to make the call 
from the thunk local, if the DECL_RESULT of the thunk is DECL_BY_REFERENCE.

It turns out that neither the C++ nor the Ada front-end builds the DECL_RESULT 
of this special alias (the C++ front-end apparently doesn't even build that of 
the thunk itself so expand_thunk has code to patch this up).  Moreover it's a 
bit strange to first try:

   restmp = gimple_fold_indirect_ref (resdecl);

i.e. build the dereference using the type of resdecl and then use the type of 
the DECL_RESULT of the alias if this failed.  So the attached fix changes this 
to using the type of resdecl in the latter case too.

Bootstrapped/regtested on x86_64-suse-linux, OK for the mainline?


2019-01-22  Eric Botcazou  

* cgraphunit.c (cgraph_node::expand_thunk): When expanding a GIMPLE
thunk that returns by reference, use the type of the return object
of the thunk instead of that of the alias to build the dereference.


2019-01-23  Eric Botcazou  

* gnat.dg/specs/opt4.ads: New test.

-- 
Eric BotcazouIndex: cgraphunit.c
===
--- cgraphunit.c	(revision 268071)
+++ cgraphunit.c	(working copy)
@@ -1916,10 +1916,9 @@ cgraph_node::expand_thunk (bool output_a
 	  restmp = gimple_fold_indirect_ref (resdecl);
 	  if (!restmp)
 		restmp = build2 (MEM_REF,
- TREE_TYPE (TREE_TYPE (DECL_RESULT (alias))),
+ TREE_TYPE (TREE_TYPE (resdecl)),
  resdecl,
- build_int_cst (TREE_TYPE
-   (DECL_RESULT (alias)), 0));
+ build_int_cst (TREE_TYPE (resdecl), 0));
 	}
 	  else if (!is_gimple_reg_type (restype))
 	{
-- { dg-do compile }
-- { dg-options "-O" }

package Opt4 is

   type Rec (D : Boolean := False) is record
  case D is
 when False => null;
 when True => I : Integer;
  end case;
   end record;

   Null_Rec : constant Rec := (D => False);

   type I1 is limited interface;

   type I2 is limited interface;

   function Func (Data : I2) return Rec is abstract;

   type Ext is limited new I1 and I2 with null record;

   overriding function Func (Data : Ext) return Rec is (Null_Rec);

end Opt4;


Re: [PATCH] Fix segfault with inlining

2013-09-17 Thread Eric Botcazou
 I've looked at the C++ testcase
 
 int foo (int x)
 {
   try {
 return x;
   }
   catch (...)
   {
 return 0;
   }
 }
 
 which exhibits exactly the behavior you quote - return x is considered
 throwing an exception.  The C++ FE doesn't arrange for TREE_THIS_NOTRAP to
 be set here (maybe due to this issue you quote?).

I presume that you compiled with -fnon-call-exceptions?  Otherwise, I don't 
see how something that isn't a call can throw an exception in C++, it should 
be seen at most as possibly trapping, which is less blocking.

 Other than that the patch looks reasonable (I suppose you need
 is_parameter_of only because as we recursively handle the trees
 PARM_DECLs from the destination could already have leaked into
 the tree we recurse into?)

Do you mean that the test on DECL_CONTEXT is superfluous?  Possibly indeed, 
but with nested functions you can have PARM_DECLs of different origins in a 
given function body, although this may be irrelevant for tree-inline.c.

-- 
Eric Botcazou


Re: [PATCH] Fix segfault with inlining

2013-09-17 Thread Richard Biener
On Tue, Sep 17, 2013 at 9:03 AM, Eric Botcazou ebotca...@adacore.com wrote:
 I've looked at the C++ testcase

 int foo (int x)
 {
   try {
 return x;
   }
   catch (...)
   {
 return 0;
   }
 }

 which exhibits exactly the behavior you quote - return x is considered
 throwing an exception.  The C++ FE doesn't arrange for TREE_THIS_NOTRAP to
 be set here (maybe due to this issue you quote?).

 I presume that you compiled with -fnon-call-exceptions?  Otherwise, I don't
 see how something that isn't a call can throw an exception in C++, it should
 be seen at most as possibly trapping, which is less blocking.

Yes, with -fnon-call-exceptions.

 Other than that the patch looks reasonable (I suppose you need
 is_parameter_of only because as we recursively handle the trees
 PARM_DECLs from the destination could already have leaked into
 the tree we recurse into?)

 Do you mean that the test on DECL_CONTEXT is superfluous?  Possibly indeed,
 but with nested functions you can have PARM_DECLs of different origins in a
 given function body, although this may be irrelevant for tree-inline.c.

Yeah, I thought testing for a PARM_DECL should be sufficient?  For
nested functions
references to outer parms should have been lowered via the static
chain at the point
tree-inline.c sees them.

So, if you agree that the DECL_CONTEXT test is superfluous the patch is ok
with the is_parameter_of function removed.

Thanks,
Richard.

 --
 Eric Botcazou


Re: [PATCH] Fix segfault with inlining

2013-09-17 Thread Eric Botcazou
 Yeah, I thought testing for a PARM_DECL should be sufficient?  For
 nested functions references to outer parms should have been lowered via the
 static chain at the point tree-inline.c sees them.

OK for the latter point, but are you sure for the former?  My understanding is 
that we're already in SSA form, so parameters can be represented by SSA_NAMEs 
without defining statements.

-- 
Eric Botcazou


Re: [PATCH] Fix segfault with inlining

2013-09-17 Thread Jakub Jelinek
On Fri, Sep 13, 2013 at 04:29:48PM +0200, Eric Botcazou wrote:
 @@ -4748,6 +4774,8 @@ copy_gimple_seq_and_replace_locals (gimp
id.transform_call_graph_edges = CB_CGE_DUPLICATE;
id.transform_new_cfg = false;
id.transform_return_to_modify = false;
 +  id.transform_parameter = false;
 +  id.transform_parameter = false;
id.transform_lang_insert_block = NULL;
  
/* Walk the tree once to find local labels.  */

Why are you storing the same thing twice?

Jakub


Re: [PATCH] Fix segfault with inlining

2013-09-17 Thread Richard Biener
On Tue, Sep 17, 2013 at 10:42 AM, Eric Botcazou ebotca...@adacore.com wrote:
 Yeah, I thought testing for a PARM_DECL should be sufficient?  For
 nested functions references to outer parms should have been lowered via the
 static chain at the point tree-inline.c sees them.

 OK for the latter point, but are you sure for the former?  My understanding is
 that we're already in SSA form, so parameters can be represented by SSA_NAMEs
 without defining statements.

That's true...  so you can only simplify is_parameter_of by dropping
the context check.

Richard.

 --
 Eric Botcazou


Re: [PATCH] Fix segfault with inlining

2013-09-17 Thread Eric Botcazou
 That's true...  so you can only simplify is_parameter_of by dropping
 the context check.

OK, thanks, installed with this modification and the fix for the oversight 
spotted by Jakub, after retesting on x86-64/Linux.

-- 
Eric Botcazou


Re: [PATCH] Fix segfault with inlining

2013-09-16 Thread Richard Biener
On Fri, Sep 13, 2013 at 4:29 PM, Eric Botcazou ebotca...@adacore.com wrote:
 Hi,

 in Ada parameters can be passed by reference: in this case, the address of the
 argument is directly passed to the callee, which dereferences it to access the
 argument; now Ada also enables -fexceptions -fnon-call-exceptions, which means
 that any pointer dereference is seen as the potential source of an exception,
 which can quickly block the optimizer.  That's why we put TREE_THIS_NOTRAP on
 the dereferences associated with a parameter.

 This works fine as long as the function isn't inlined, because it may happen
 that the argument is itself the dereference of a pointer, properly guarded by
 a null check on the pointer.  When the function is inlined, the dereference in
 the caller is replaced with that of the callee, which is TREE_THIS_NOTRAP and
 thus can be moved ahead of the null pointer check, for example by LIM.

 The patch ensures that this cannot happen by clearing TREE_THIS_NOTRAP in the
 inliner.  I think that this affects only the Ada compiler in practice.

 Tested on x86_64-suse-linux, OK for the mainline?

I've looked at the C++ testcase

int foo (int x)
{
  try {
return x;
  }
  catch (...)
  {
return 0;
  }
}

which exhibits exactly the behavior you quote - return x is considered throwing
an exception.  The C++ FE doesn't arrange for TREE_THIS_NOTRAP to be
set here (maybe due to this issue you quote?).

Other than that the patch looks reasonable (I suppose you need
is_parameter_of only because as we recursively handle the trees
PARM_DECLs from the destination could already have leaked into
the tree we recurse into?)

Thanks,
Richard.


 2013-09-13  Eric Botcazou  ebotca...@adacore.com

 * tree-inline.h (struct copy_body_data): Add transform_parameter.
 * tree-inline.c (is_parameter_of): New predicate.
 (remap_gimple_op_r): Do not propagate TREE_THIS_NOTRAP on MEM_REF if
 a parameter has been remapped.
 (copy_tree_body_r): Likewise on INDIRECT_REF and MEM_REF.
 (optimize_inline_calls): Initialize transform_parameter.
 (unsave_expr_now): Likewise.
 (copy_gimple_seq_and_replace_locals): Likewise.
 (tree_function_versioning): Likewise.
 (maybe_inline_call_in_expr): Likewise.


 2013-09-13  Eric Botcazou  ebotca...@adacore.com

 * gnat.dg/opt27.adb: New test.
 * gnat.dg/opt27_pkg.ad[sb]: New helper.


 --
 Eric Botcazou


Re: [PATCH] Fix segfault with inlining

2013-09-16 Thread Jason Merrill

On 09/16/2013 05:28 AM, Richard Biener wrote:

which exhibits exactly the behavior you quote - return x is considered throwing
an exception.  The C++ FE doesn't arrange for TREE_THIS_NOTRAP to be
set here (maybe due to this issue you quote?).


I haven't been aware of TREE_THIS_NOTRAP, but we could certainly start 
setting it.


Jason



[PATCH] Fix segfault with inlining

2013-09-13 Thread Eric Botcazou
Hi,

in Ada parameters can be passed by reference: in this case, the address of the 
argument is directly passed to the callee, which dereferences it to access the 
argument; now Ada also enables -fexceptions -fnon-call-exceptions, which means 
that any pointer dereference is seen as the potential source of an exception, 
which can quickly block the optimizer.  That's why we put TREE_THIS_NOTRAP on 
the dereferences associated with a parameter.

This works fine as long as the function isn't inlined, because it may happen 
that the argument is itself the dereference of a pointer, properly guarded by 
a null check on the pointer.  When the function is inlined, the dereference in 
the caller is replaced with that of the callee, which is TREE_THIS_NOTRAP and 
thus can be moved ahead of the null pointer check, for example by LIM.

The patch ensures that this cannot happen by clearing TREE_THIS_NOTRAP in the 
inliner.  I think that this affects only the Ada compiler in practice.

Tested on x86_64-suse-linux, OK for the mainline?


2013-09-13  Eric Botcazou  ebotca...@adacore.com

* tree-inline.h (struct copy_body_data): Add transform_parameter.
* tree-inline.c (is_parameter_of): New predicate.
(remap_gimple_op_r): Do not propagate TREE_THIS_NOTRAP on MEM_REF if
a parameter has been remapped.
(copy_tree_body_r): Likewise on INDIRECT_REF and MEM_REF.
(optimize_inline_calls): Initialize transform_parameter.
(unsave_expr_now): Likewise.
(copy_gimple_seq_and_replace_locals): Likewise.
(tree_function_versioning): Likewise.
(maybe_inline_call_in_expr): Likewise.


2013-09-13  Eric Botcazou  ebotca...@adacore.com

* gnat.dg/opt27.adb: New test.
* gnat.dg/opt27_pkg.ad[sb]: New helper.


-- 
Eric BotcazouIndex: tree-inline.c
===
--- tree-inline.c	(revision 202431)
+++ tree-inline.c	(working copy)
@@ -751,6 +751,21 @@ copy_gimple_bind (gimple stmt, copy_body
   return new_bind;
 }
 
+/* Return true if DECL is a parameter or a SSA_NAME for a parameter of
+   function FNDECL.  */
+
+static bool
+is_parameter_of (tree decl, tree fndecl)
+{
+  if (TREE_CODE (decl) == SSA_NAME)
+{
+  decl = SSA_NAME_VAR (decl);
+  if (!decl)
+	return false;
+}
+
+  return (TREE_CODE (decl) == PARM_DECL  DECL_CONTEXT (decl) == fndecl);
+}
 
 /* Remap the GIMPLE operand pointed to by *TP.  DATA is really a
'struct walk_stmt_info *'.  DATA-INFO is a 'copy_body_data *'.
@@ -840,20 +855,25 @@ remap_gimple_op_r (tree *tp, int *walk_s
 
   if (TREE_CODE (*tp) == MEM_REF)
 	{
-	  tree ptr = TREE_OPERAND (*tp, 0);
-	  tree type = remap_type (TREE_TYPE (*tp), id);
-	  tree old = *tp;
-
 	  /* We need to re-canonicalize MEM_REFs from inline substitutions
 	 that can happen when a pointer argument is an ADDR_EXPR.
 	 Recurse here manually to allow that.  */
+	  tree ptr = TREE_OPERAND (*tp, 0);
+	  tree type = remap_type (TREE_TYPE (*tp), id);
+	  tree old = *tp;
 	  walk_tree (ptr, remap_gimple_op_r, data, NULL);
-	  *tp = fold_build2 (MEM_REF, type,
-			 ptr, TREE_OPERAND (*tp, 1));
-	  TREE_THIS_NOTRAP (*tp) = TREE_THIS_NOTRAP (old);
+	  *tp = fold_build2 (MEM_REF, type, ptr, TREE_OPERAND (*tp, 1));
 	  TREE_THIS_VOLATILE (*tp) = TREE_THIS_VOLATILE (old);
 	  TREE_SIDE_EFFECTS (*tp) = TREE_SIDE_EFFECTS (old);
 	  TREE_NO_WARNING (*tp) = TREE_NO_WARNING (old);
+	  /* We cannot propagate the TREE_THIS_NOTRAP flag if we have
+	 remapped a parameter as the property might be valid only
+	 for the parameter itself.  */
+	  if (TREE_THIS_NOTRAP (old)
+	   (!is_parameter_of (TREE_OPERAND (old, 0), id-src_fn)
+		  || (!id-transform_parameter
+		   is_parameter_of (ptr, id-dst_fn
+	TREE_THIS_NOTRAP (*tp) = 1;
 	  *walk_subtrees = 0;
 	  return NULL;
 	}
@@ -1043,45 +1063,45 @@ copy_tree_body_r (tree *tp, int *walk_su
 	  /* Get rid of * from inline substitutions that can happen when a
 	 pointer argument is an ADDR_EXPR.  */
 	  tree decl = TREE_OPERAND (*tp, 0);
-	  tree *n;
-
-	  n = (tree *) pointer_map_contains (id-decl_map, decl);
+	  tree *n = (tree *) pointer_map_contains (id-decl_map, decl);
 	  if (n)
 	{
-	  tree new_tree;
-	  tree old;
 	  /* If we happen to get an ADDR_EXPR in n-value, strip
 	 it manually here as we'll eventually get ADDR_EXPRs
 		 which lie about their types pointed to.  In this case
 		 build_fold_indirect_ref wouldn't strip the INDIRECT_REF,
 		 but we absolutely rely on that.  As fold_indirect_ref
 	 does other useful transformations, try that first, though.  */
-	  tree type = TREE_TYPE (TREE_TYPE (*n));
-	  if (id-do_not_unshare)
-		new_tree = *n;
-	  else
-		new_tree = unshare_expr (*n);
-	  old = *tp;
-	  *tp = gimple_fold_indirect_ref (new_tree);
+	  tree type = TREE_TYPE (*tp);
+	  tree ptr = id-do_not_unshare ? *n : unshare_expr (*n);
+