diff mbox series

tree.cc, v2: Add tree_builtin_call_types_compatible_p [PR105150]

Message ID Yk2qQ5Ln9BKPOwNc@tucnak
State New
Headers show
Series tree.cc, v2: Add tree_builtin_call_types_compatible_p [PR105150] | expand

Commit Message

Jakub Jelinek April 6, 2022, 2:57 p.m. UTC
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.



	Jakub

Comments

Richard Biener April 7, 2022, 5:58 a.m. UTC | #1
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
> 
>
diff mbox series

Patch

--- 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)