public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] tree.cc: Add tree_builtin_call_types_compatible_p [PR105150]
@ 2022-04-06  7:18 Jakub Jelinek
  2022-04-06  7:49 ` Richard Biener
  0 siblings, 1 reply; 6+ messages in thread
From: Jakub Jelinek @ 2022-04-06  7:18 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches

Hi!

And here is the follow-up patch that does the argument checking
on GENERIC.  It ensures TYPE_MAIN_VARIANT == TYPE_MAIN_VARIANT
compatibility on the arguments, except for pointer arguments like
FILE *, const struct tm * etc. that would never match that way
and similarly to the gimple one also char/short promotions.
Tested that it works correctly with fprintf.

Not sure if we shouldn't allow any useless_type_conversion_p
differences for all pointers though, say if somebody uses
a K&R declared builtin and passes in char msg[] = "...";
then it will be char * instead of const char *.

Bootstrapped/regtested on {powerpc64le,x86_64,i686}-linux, ok for trunk?

2022-04-06  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/105150
	* tree.cc (tree_builtin_call_types_compatible_p): New function.
	(get_call_combined_fn): Use it.

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

--- gcc/tree.cc.jj	2022-03-26 08:11:28.447530077 +0100
+++ gcc/tree.cc	2022-04-05 17:09:46.892114064 +0200
@@ -8406,6 +8406,61 @@ get_callee_fndecl (const_tree call)
   return NULL_TREE;
 }
 
+/* Return true when STMTs arguments and return value match those of FNDECL,
+   a decl of a builtin function.  */
+
+static bool
+tree_builtin_call_types_compatible_p (const_tree call, tree fndecl)
+{
+  gcc_checking_assert (DECL_BUILT_IN_CLASS (fndecl) != NOT_BUILT_IN);
+
+  if (TYPE_MAIN_VARIANT (TREE_TYPE (call))
+      != TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (fndecl))))
+    return false;
+
+  tree targs = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
+  unsigned nargs = call_expr_nargs (call);
+  for (unsigned i = 0; i < nargs; ++i, targs = TREE_CHAIN (targs))
+    {
+      /* Variadic args follow.  */
+      if (!targs)
+	return true;
+      tree arg = CALL_EXPR_ARG (call, i);
+      tree type = TREE_VALUE (targs);
+      if (TYPE_MAIN_VARIANT (type) != TYPE_MAIN_VARIANT (TREE_TYPE (arg)))
+	{
+	  /* If argument in the builtin fndecl is the artificial pointer
+	     for FILE * etc., allow any pointer type arg for it.  */
+	  if (POINTER_TYPE_P (type)
+	      && POINTER_TYPE_P (TREE_TYPE (arg))
+	      && useless_type_conversion_p (type, TREE_TYPE (arg)))
+	    {
+	      unsigned int j;
+	      for (j = 0; j < ARRAY_SIZE (builtin_structptr_types); ++j)
+		if (type == builtin_structptr_types[j].node
+		    && (builtin_structptr_types[j].node
+			!= builtin_structptr_types[j].base))
+		  break;
+	      if (j < ARRAY_SIZE (builtin_structptr_types))
+		continue;
+	    }
+	  /* char/short integral arguments are promoted to int
+	     by several frontends if targetm.calls.promote_prototypes
+	     is true.  Allow such promotion too.  */
+	  if (INTEGRAL_TYPE_P (type)
+	      && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)
+	      && targetm.calls.promote_prototypes (TREE_TYPE (fndecl))
+	      && useless_type_conversion_p (integer_type_node,
+					    TREE_TYPE (arg)))
+	    continue;
+	  return false;
+	}
+    }
+  if (targs && !VOID_TYPE_P (TREE_VALUE (targs)))
+    return false;
+  return true;
+}
+
 /* If CALL_EXPR CALL calls a normal built-in function or an internal function,
    return the associated function code, otherwise return CFN_LAST.  */
 
@@ -8420,7 +8475,13 @@ get_call_combined_fn (const_tree call)
 
   tree fndecl = get_callee_fndecl (call);
   if (fndecl && fndecl_built_in_p (fndecl, BUILT_IN_NORMAL))
-    return as_combined_fn (DECL_FUNCTION_CODE (fndecl));
+    {
+      tree decl = builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl));
+      if (!decl)
+	decl = fndecl;
+      if (tree_builtin_call_types_compatible_p (call, decl))
+	return as_combined_fn (DECL_FUNCTION_CODE (fndecl));
+    }
 
   return CFN_LAST;
 }
--- gcc/testsuite/gcc.dg/pr105150.c.jj	2022-04-05 16:56:22.894319239 +0200
+++ gcc/testsuite/gcc.dg/pr105150.c	2022-04-05 16:56:16.646406314 +0200
@@ -0,0 +1,8 @@
+/* PR tree-optimization/105150 */
+/* { dg-options "-w -Ofast" } */
+
+#define A(name) __typeof (__builtin_##name (0)) name (); \
+  float name##1 () { return !name (1); } \
+  double name##2 () { return name (1.0L); }
+#define B(name) A(name) A(name##l)
+B (sqrt)

	Jakub


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] tree.cc: Add tree_builtin_call_types_compatible_p [PR105150]
  2022-04-06  7:18 [PATCH] tree.cc: Add tree_builtin_call_types_compatible_p [PR105150] Jakub Jelinek
@ 2022-04-06  7:49 ` Richard Biener
  2022-04-06  7:57   ` Jakub Jelinek
  2022-04-06 14:57   ` [PATCH] tree.cc, v2: " Jakub Jelinek
  0 siblings, 2 replies; 6+ messages in thread
From: Richard Biener @ 2022-04-06  7:49 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

On Wed, 6 Apr 2022, Jakub Jelinek wrote:

> Hi!
> 
> And here is the follow-up patch that does the argument checking
> on GENERIC.  It ensures TYPE_MAIN_VARIANT == TYPE_MAIN_VARIANT
> compatibility on the arguments, except for pointer arguments like
> FILE *, const struct tm * etc. that would never match that way
> and similarly to the gimple one also char/short promotions.
> Tested that it works correctly with fprintf.
> 
> Not sure if we shouldn't allow any useless_type_conversion_p
> differences for all pointers though, say if somebody uses
> a K&R declared builtin and passes in char msg[] = "...";
> then it will be char * instead of const char *.
> 
> Bootstrapped/regtested on {powerpc64le,x86_64,i686}-linux, ok for trunk?
> 
> 2022-04-06  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR tree-optimization/105150
> 	* tree.cc (tree_builtin_call_types_compatible_p): New function.
> 	(get_call_combined_fn): Use it.
> 
> 	* gcc.dg/pr105150.c: New test.
> 
> --- gcc/tree.cc.jj	2022-03-26 08:11:28.447530077 +0100
> +++ gcc/tree.cc	2022-04-05 17:09:46.892114064 +0200
> @@ -8406,6 +8406,61 @@ get_callee_fndecl (const_tree call)
>    return NULL_TREE;
>  }
>  
> +/* Return true when STMTs arguments and return value match those of FNDECL,
> +   a decl of a builtin function.  */
> +
> +static bool
> +tree_builtin_call_types_compatible_p (const_tree call, tree fndecl)
> +{
> +  gcc_checking_assert (DECL_BUILT_IN_CLASS (fndecl) != NOT_BUILT_IN);
> +
> +  if (TYPE_MAIN_VARIANT (TREE_TYPE (call))
> +      != TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (fndecl))))
> +    return false;
> +
> +  tree targs = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
> +  unsigned nargs = call_expr_nargs (call);
> +  for (unsigned i = 0; i < nargs; ++i, targs = TREE_CHAIN (targs))
> +    {
> +      /* Variadic args follow.  */
> +      if (!targs)
> +	return true;
> +      tree arg = CALL_EXPR_ARG (call, i);
> +      tree type = TREE_VALUE (targs);
> +      if (TYPE_MAIN_VARIANT (type) != TYPE_MAIN_VARIANT (TREE_TYPE (arg)))
> +	{
> +	  /* If argument in the builtin fndecl is the artificial pointer
> +	     for FILE * etc., allow any pointer type arg for it.  */
> +	  if (POINTER_TYPE_P (type)
> +	      && POINTER_TYPE_P (TREE_TYPE (arg))
> +	      && useless_type_conversion_p (type, TREE_TYPE (arg)))
> +	    {
> +	      unsigned int j;
> +	      for (j = 0; j < ARRAY_SIZE (builtin_structptr_types); ++j)
> +		if (type == builtin_structptr_types[j].node
> +		    && (builtin_structptr_types[j].node
> +			!= builtin_structptr_types[j].base))
> +		  break;
> +	      if (j < ARRAY_SIZE (builtin_structptr_types))
> +		continue;
> +	    }
> +	  /* char/short integral arguments are promoted to int
> +	     by several frontends if targetm.calls.promote_prototypes
> +	     is true.  Allow such promotion too.  */
> +	  if (INTEGRAL_TYPE_P (type)
> +	      && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)
> +	      && targetm.calls.promote_prototypes (TREE_TYPE (fndecl))
> +	      && useless_type_conversion_p (integer_type_node,
> +					    TREE_TYPE (arg)))

On trees we'd use tree_[sign_]nop_conversion () instead of
useless_type_conversion_p, I think it's OK to allow all such
pointer conversions.  In the end this probably means being
more forgiving than TYPE_MAIN_VARIANT equivalence throughout, that
would also make the code more similar to 
gimple_builtin_call_types_compatible_p besides
s/useless_type_conversion_p/tree_sign_nop_conversion/

What do you think?  If we don't go for strict TYPE_MAIN_VARIANT
compatibility we should apply lax rules for all, the return
type and all argument types.  It's not that the GENERIC we end
up building from GIMPLE in various places adheres to the strict
GENERIC type compatibility rules ...

Richard.

> +	    continue;
> +	  return false;
> +	}
> +    }
> +  if (targs && !VOID_TYPE_P (TREE_VALUE (targs)))
> +    return false;
> +  return true;
> +}
> +
>  /* If CALL_EXPR CALL calls a normal built-in function or an internal function,
>     return the associated function code, otherwise return CFN_LAST.  */
>  
> @@ -8420,7 +8475,13 @@ get_call_combined_fn (const_tree call)
>  
>    tree fndecl = get_callee_fndecl (call);
>    if (fndecl && fndecl_built_in_p (fndecl, BUILT_IN_NORMAL))
> -    return as_combined_fn (DECL_FUNCTION_CODE (fndecl));
> +    {
> +      tree decl = builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl));
> +      if (!decl)
> +	decl = fndecl;
> +      if (tree_builtin_call_types_compatible_p (call, decl))
> +	return as_combined_fn (DECL_FUNCTION_CODE (fndecl));
> +    }
>  
>    return CFN_LAST;
>  }
> --- gcc/testsuite/gcc.dg/pr105150.c.jj	2022-04-05 16:56:22.894319239 +0200
> +++ gcc/testsuite/gcc.dg/pr105150.c	2022-04-05 16:56:16.646406314 +0200
> @@ -0,0 +1,8 @@
> +/* PR tree-optimization/105150 */
> +/* { dg-options "-w -Ofast" } */
> +
> +#define A(name) __typeof (__builtin_##name (0)) name (); \
> +  float name##1 () { return !name (1); } \
> +  double name##2 () { return name (1.0L); }
> +#define B(name) A(name) A(name##l)
> +B (sqrt)
> 
> 	Jakub
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Ivo Totev; HRB 36809 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] tree.cc: Add tree_builtin_call_types_compatible_p [PR105150]
  2022-04-06  7:49 ` Richard Biener
@ 2022-04-06  7:57   ` Jakub Jelinek
  2022-04-06  8:01     ` Richard Biener
  2022-04-06 14:57   ` [PATCH] tree.cc, v2: " Jakub Jelinek
  1 sibling, 1 reply; 6+ messages in thread
From: Jakub Jelinek @ 2022-04-06  7:57 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches

On Wed, Apr 06, 2022 at 09:49:25AM +0200, Richard Biener wrote:
> On trees we'd use tree_[sign_]nop_conversion () instead of
> useless_type_conversion_p, I think it's OK to allow all such
> pointer conversions.  In the end this probably means being
> more forgiving than TYPE_MAIN_VARIANT equivalence throughout, that
> would also make the code more similar to 
> gimple_builtin_call_types_compatible_p besides
> s/useless_type_conversion_p/tree_sign_nop_conversion/
> 
> What do you think?  If we don't go for strict TYPE_MAIN_VARIANT
> compatibility we should apply lax rules for all, the return
> type and all argument types.  It's not that the GENERIC we end
> up building from GIMPLE in various places adheres to the strict
> GENERIC type compatibility rules ...

Dunno, we don't really have a verifier for GENERIC.

Don't we even require that the types are actually same rather than
similar for say binary ops other than shifts, or for comparisons,
or result and first argument for unary and binary etc.?
I think at least for the most common cases the C/C++ FEs ensure that
through choosing some common type for the operation and folding the
arguments to that type.  Though I bet we violate it pretty often
with e.g. sizetype vs. size_type_node differences etc.

	Jakub


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] tree.cc: Add tree_builtin_call_types_compatible_p [PR105150]
  2022-04-06  7:57   ` Jakub Jelinek
@ 2022-04-06  8:01     ` Richard Biener
  0 siblings, 0 replies; 6+ messages in thread
From: Richard Biener @ 2022-04-06  8:01 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

On Wed, 6 Apr 2022, Jakub Jelinek wrote:

> On Wed, Apr 06, 2022 at 09:49:25AM +0200, Richard Biener wrote:
> > On trees we'd use tree_[sign_]nop_conversion () instead of
> > useless_type_conversion_p, I think it's OK to allow all such
> > pointer conversions.  In the end this probably means being
> > more forgiving than TYPE_MAIN_VARIANT equivalence throughout, that
> > would also make the code more similar to 
> > gimple_builtin_call_types_compatible_p besides
> > s/useless_type_conversion_p/tree_sign_nop_conversion/
> > 
> > What do you think?  If we don't go for strict TYPE_MAIN_VARIANT
> > compatibility we should apply lax rules for all, the return
> > type and all argument types.  It's not that the GENERIC we end
> > up building from GIMPLE in various places adheres to the strict
> > GENERIC type compatibility rules ...
> 
> Dunno, we don't really have a verifier for GENERIC.
> 
> Don't we even require that the types are actually same rather than
> similar for say binary ops other than shifts, or for comparisons,
> or result and first argument for unary and binary etc.?

I think it's fine to use typedef variants or CV qualified variants there.
But indeed fold-const.cc in most places fold_convert()s everything,
but mostly because it strips nop conversions before applying patterns.

> I think at least for the most common cases the C/C++ FEs ensure that
> through choosing some common type for the operation and folding the
> arguments to that type.  Though I bet we violate it pretty often
> with e.g. sizetype vs. size_type_node differences etc.

Yeah.  I think if we can trust the GENERIC input then we'll be fine.
Of course as we see here, the GENERIC input from frontends can be
garbage (which IMHO as said is a bug in the frontends).  We
shouldn't worry too much to be precise when trying to fend off
garbage input, we just have to make sure to make the output not
even worse.

Richard.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH] tree.cc, v2: Add tree_builtin_call_types_compatible_p [PR105150]
  2022-04-06  7:49 ` Richard Biener
  2022-04-06  7:57   ` Jakub Jelinek
@ 2022-04-06 14:57   ` Jakub Jelinek
  2022-04-07  5:58     ` Richard Biener
  1 sibling, 1 reply; 6+ messages in thread
From: Jakub Jelinek @ 2022-04-06 14:57 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches

On Wed, Apr 06, 2022 at 09:49:25AM +0200, Richard Biener wrote:
> On trees we'd use tree_[sign_]nop_conversion () instead of
> useless_type_conversion_p, I think it's OK to allow all such
> pointer conversions.  In the end this probably means being
> more forgiving than TYPE_MAIN_VARIANT equivalence throughout, that
> would also make the code more similar to 
> gimple_builtin_call_types_compatible_p besides
> s/useless_type_conversion_p/tree_sign_nop_conversion/

Here is an updated patch to do that, allow differences in pointer types
and tweak the promotion handling.
There is no tree_sign_nop_conversion_p, so I've used
tree_nop_conversion_p.  What tree_sign_nop_conversion does on top of
that is just that it verifies both types are pointer types or
neither is and in the latter case TYPE_UNSIGNED is the same.
So the patch verifies both are POINTER_TYPE_P for the one case
and for the promotion where it already checks the unpromoted type
is integral checks if promoted one is integral too and signed.

I've also changed the patch to match the now committed gimple.cc
change where the builtin_decl_explicit is inside of the
*_call_types_compatible_p function instead of the caller.

Bootstrapped/regtested on powerpc64le-linux, ok for trunk?

2022-04-06  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/105150
	* tree.cc (tree_builtin_call_types_compatible_p): New function.
	(get_call_combined_fn): Use it.

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

--- gcc/tree.cc.jj	2022-04-06 09:59:03.312066863 +0200
+++ gcc/tree.cc	2022-04-06 10:52:55.176755024 +0200
@@ -8406,6 +8406,59 @@ get_callee_fndecl (const_tree call)
   return NULL_TREE;
 }
 
+/* Return true when STMTs arguments and return value match those of FNDECL,
+   a decl of a builtin function.  */
+
+static bool
+tree_builtin_call_types_compatible_p (const_tree call, tree fndecl)
+{
+  gcc_checking_assert (DECL_BUILT_IN_CLASS (fndecl) != NOT_BUILT_IN);
+
+  if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+    if (tree decl = builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl)))
+      fndecl = decl;
+
+  if (TYPE_MAIN_VARIANT (TREE_TYPE (call))
+      != TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (fndecl))))
+    return false;
+
+  tree targs = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
+  unsigned nargs = call_expr_nargs (call);
+  for (unsigned i = 0; i < nargs; ++i, targs = TREE_CHAIN (targs))
+    {
+      /* Variadic args follow.  */
+      if (!targs)
+	return true;
+      tree arg = CALL_EXPR_ARG (call, i);
+      tree type = TREE_VALUE (targs);
+      if (TYPE_MAIN_VARIANT (type) != TYPE_MAIN_VARIANT (TREE_TYPE (arg)))
+	{
+	  /* For pointer arguments be more forgiving, e.g. due to
+	     FILE * vs. fileptr_type_node, or say char * vs. const char *
+	     differences etc.  */
+	  if (POINTER_TYPE_P (type)
+	      && POINTER_TYPE_P (TREE_TYPE (arg))
+	      && tree_nop_conversion_p (type, TREE_TYPE (arg)))
+	    continue;
+	  /* char/short integral arguments are promoted to int
+	     by several frontends if targetm.calls.promote_prototypes
+	     is true.  Allow such promotion too.  */
+	  if (INTEGRAL_TYPE_P (type)
+	      && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)
+	      && INTEGRAL_TYPE_P (TREE_TYPE (arg))
+	      && !TYPE_UNSIGNED (TREE_TYPE (arg))
+	      && targetm.calls.promote_prototypes (TREE_TYPE (fndecl))
+	      && tree_nop_conversion_p (integer_type_node,
+					TREE_TYPE (arg)))
+	    continue;
+	  return false;
+	}
+    }
+  if (targs && !VOID_TYPE_P (TREE_VALUE (targs)))
+    return false;
+  return true;
+}
+
 /* If CALL_EXPR CALL calls a normal built-in function or an internal function,
    return the associated function code, otherwise return CFN_LAST.  */
 
@@ -8419,7 +8472,9 @@ get_call_combined_fn (const_tree call)
     return as_combined_fn (CALL_EXPR_IFN (call));
 
   tree fndecl = get_callee_fndecl (call);
-  if (fndecl && fndecl_built_in_p (fndecl, BUILT_IN_NORMAL))
+  if (fndecl
+      && fndecl_built_in_p (fndecl, BUILT_IN_NORMAL)
+      && tree_builtin_call_types_compatible_p (call, fndecl))
     return as_combined_fn (DECL_FUNCTION_CODE (fndecl));
 
   return CFN_LAST;
--- gcc/testsuite/gcc.dg/pr105150.c.jj	2022-04-06 10:51:12.801191206 +0200
+++ gcc/testsuite/gcc.dg/pr105150.c	2022-04-06 10:51:12.801191206 +0200
@@ -0,0 +1,8 @@
+/* PR tree-optimization/105150 */
+/* { dg-options "-w -Ofast" } */
+
+#define A(name) __typeof (__builtin_##name (0)) name (); \
+  float name##1 () { return !name (1); } \
+  double name##2 () { return name (1.0L); }
+#define B(name) A(name) A(name##l)
+B (sqrt)


	Jakub


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] tree.cc, v2: Add tree_builtin_call_types_compatible_p [PR105150]
  2022-04-06 14:57   ` [PATCH] tree.cc, v2: " Jakub Jelinek
@ 2022-04-07  5:58     ` Richard Biener
  0 siblings, 0 replies; 6+ messages in thread
From: Richard Biener @ 2022-04-07  5:58 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

On Wed, 6 Apr 2022, Jakub Jelinek wrote:

> On Wed, Apr 06, 2022 at 09:49:25AM +0200, Richard Biener wrote:
> > On trees we'd use tree_[sign_]nop_conversion () instead of
> > useless_type_conversion_p, I think it's OK to allow all such
> > pointer conversions.  In the end this probably means being
> > more forgiving than TYPE_MAIN_VARIANT equivalence throughout, that
> > would also make the code more similar to 
> > gimple_builtin_call_types_compatible_p besides
> > s/useless_type_conversion_p/tree_sign_nop_conversion/
> 
> Here is an updated patch to do that, allow differences in pointer types
> and tweak the promotion handling.
> There is no tree_sign_nop_conversion_p, so I've used
> tree_nop_conversion_p.  What tree_sign_nop_conversion does on top of
> that is just that it verifies both types are pointer types or
> neither is and in the latter case TYPE_UNSIGNED is the same.
> So the patch verifies both are POINTER_TYPE_P for the one case
> and for the promotion where it already checks the unpromoted type
> is integral checks if promoted one is integral too and signed.
> 
> I've also changed the patch to match the now committed gimple.cc
> change where the builtin_decl_explicit is inside of the
> *_call_types_compatible_p function instead of the caller.
> 
> Bootstrapped/regtested on powerpc64le-linux, ok for trunk?

OK.

Thanks,
Richard.

> 2022-04-06  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR tree-optimization/105150
> 	* tree.cc (tree_builtin_call_types_compatible_p): New function.
> 	(get_call_combined_fn): Use it.
> 
> 	* gcc.dg/pr105150.c: New test.
> 
> --- gcc/tree.cc.jj	2022-04-06 09:59:03.312066863 +0200
> +++ gcc/tree.cc	2022-04-06 10:52:55.176755024 +0200
> @@ -8406,6 +8406,59 @@ get_callee_fndecl (const_tree call)
>    return NULL_TREE;
>  }
>  
> +/* Return true when STMTs arguments and return value match those of FNDECL,
> +   a decl of a builtin function.  */
> +
> +static bool
> +tree_builtin_call_types_compatible_p (const_tree call, tree fndecl)
> +{
> +  gcc_checking_assert (DECL_BUILT_IN_CLASS (fndecl) != NOT_BUILT_IN);
> +
> +  if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
> +    if (tree decl = builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl)))
> +      fndecl = decl;
> +
> +  if (TYPE_MAIN_VARIANT (TREE_TYPE (call))
> +      != TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (fndecl))))
> +    return false;
> +
> +  tree targs = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
> +  unsigned nargs = call_expr_nargs (call);
> +  for (unsigned i = 0; i < nargs; ++i, targs = TREE_CHAIN (targs))
> +    {
> +      /* Variadic args follow.  */
> +      if (!targs)
> +	return true;
> +      tree arg = CALL_EXPR_ARG (call, i);
> +      tree type = TREE_VALUE (targs);
> +      if (TYPE_MAIN_VARIANT (type) != TYPE_MAIN_VARIANT (TREE_TYPE (arg)))
> +	{
> +	  /* For pointer arguments be more forgiving, e.g. due to
> +	     FILE * vs. fileptr_type_node, or say char * vs. const char *
> +	     differences etc.  */
> +	  if (POINTER_TYPE_P (type)
> +	      && POINTER_TYPE_P (TREE_TYPE (arg))
> +	      && tree_nop_conversion_p (type, TREE_TYPE (arg)))
> +	    continue;
> +	  /* char/short integral arguments are promoted to int
> +	     by several frontends if targetm.calls.promote_prototypes
> +	     is true.  Allow such promotion too.  */
> +	  if (INTEGRAL_TYPE_P (type)
> +	      && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)
> +	      && INTEGRAL_TYPE_P (TREE_TYPE (arg))
> +	      && !TYPE_UNSIGNED (TREE_TYPE (arg))
> +	      && targetm.calls.promote_prototypes (TREE_TYPE (fndecl))
> +	      && tree_nop_conversion_p (integer_type_node,
> +					TREE_TYPE (arg)))
> +	    continue;
> +	  return false;
> +	}
> +    }
> +  if (targs && !VOID_TYPE_P (TREE_VALUE (targs)))
> +    return false;
> +  return true;
> +}
> +
>  /* If CALL_EXPR CALL calls a normal built-in function or an internal function,
>     return the associated function code, otherwise return CFN_LAST.  */
>  
> @@ -8419,7 +8472,9 @@ get_call_combined_fn (const_tree call)
>      return as_combined_fn (CALL_EXPR_IFN (call));
>  
>    tree fndecl = get_callee_fndecl (call);
> -  if (fndecl && fndecl_built_in_p (fndecl, BUILT_IN_NORMAL))
> +  if (fndecl
> +      && fndecl_built_in_p (fndecl, BUILT_IN_NORMAL)
> +      && tree_builtin_call_types_compatible_p (call, fndecl))
>      return as_combined_fn (DECL_FUNCTION_CODE (fndecl));
>  
>    return CFN_LAST;
> --- gcc/testsuite/gcc.dg/pr105150.c.jj	2022-04-06 10:51:12.801191206 +0200
> +++ gcc/testsuite/gcc.dg/pr105150.c	2022-04-06 10:51:12.801191206 +0200
> @@ -0,0 +1,8 @@
> +/* PR tree-optimization/105150 */
> +/* { dg-options "-w -Ofast" } */
> +
> +#define A(name) __typeof (__builtin_##name (0)) name (); \
> +  float name##1 () { return !name (1); } \
> +  double name##2 () { return name (1.0L); }
> +#define B(name) A(name) A(name##l)
> +B (sqrt)
> 
> 
> 	Jakub
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Ivo Totev; HRB 36809 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2022-04-07  5:58 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-06  7:18 [PATCH] tree.cc: Add tree_builtin_call_types_compatible_p [PR105150] Jakub Jelinek
2022-04-06  7:49 ` Richard Biener
2022-04-06  7:57   ` Jakub Jelinek
2022-04-06  8:01     ` Richard Biener
2022-04-06 14:57   ` [PATCH] tree.cc, v2: " Jakub Jelinek
2022-04-07  5:58     ` Richard Biener

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).