public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [RFC] operand_equal_p with valueization
@ 2015-05-22 12:50 Jan Hubicka
  2015-05-22 13:40 ` Richard Biener
  0 siblings, 1 reply; 59+ messages in thread
From: Jan Hubicka @ 2015-05-22 12:50 UTC (permalink / raw)
  To: gcc-patches, rguenther

Hi,
with aliasing sanity checks I got burnt again with ipa-icf-gimple's
compare_operand doing alias set checks on all types it ever trips across.

I always tought that we do not need two equality testers - operand_equal_p and
compare_operand and given that it turns out to be non-trivial to fix issues in
compare_operand I decided to go ahead with plan to unify them.
I think operand_equal_p is better code base to start from since it is more
tested and knows more special cases.

The basic idea is to add valeize hook similar way as other folders do that
allows to do magic inside the recursive comparsion. I.e. declare two trees
equal if they are not (i.e. SSA_NAMES from differen functions).  I think it
should be useful for GVN/VRP/CCP too to improve folding of conditionals.

After trying out the hook and figuring out that ipa-icf does not have
global context to hold its tables, I dedcided that maybe more C++ way
is to have comparsion class that can be derived an adjusted for other
needs.

The following patch is a first step.  If it is considered sane, I will
continue by moving the code to one place - ipa-icf-gimple or special
ipa-icf-op.c. I will also recover Martin's diagnostics that is useful
to debug why things are considered different.

Also the code should be C++ized, for example it should use true/false
instead 0/1.

I think also the iterative hashing should be together with operand_equal_p
implementation because these two must match as I found with merging the two
cases that ipa-icf-gimple gets right and fold-const wrong - OBJ_TYPE_REF,
CONSTRUCTOR and PARM_DECL.

Finally I think we want compare_gimple class that does the same for
gimple and is independent of rest of the ipa-icf that may be better
suitable for stuff like tail merging.

The patch bootstraps/regtests ppc64-linux, but I think it is not quite
mainline ready as it noticeably reduces number of equivalences found. 
I will need to debug why that happens, but I am sending it as an RFC for
the basic concept and interfaces.

Honza

	* fold-const.c (operand_equal_p): Reorg to wrapper for
	(operand_compare::operand_equal_p): This function; add
	support for valueization, add missing type matching for
	OBJ_TYPE_REF, CONSTRUCTOR; relax matching of PARM_DECL.
	(operand_compare::operand_equal_valueize): New.
	* fold-const.h (operand_equal_p): Update prototype.
	(class operand_compare): New class.
	* ipa-icf-gimple.c (func_checker::operand_equal_valueize): Break
	ipa-icf specific bits out from ...
	(func_checker::compare_operand): ... here; remove most of generic
	handling and use operand_compare class.
	* ipa-icf-gimple.h (operand_compare): New.
	* ipa-icf.c (sem_function::equals_private): Arrange CFUN to be up to
	date so we operand_equal_p works well for flag_devirtualize.
Index: fold-const.c
===================================================================
--- fold-const.c	(revision 223500)
+++ fold-const.c	(working copy)
@@ -2716,8 +2730,9 @@ combine_comparisons (location_t loc,
    are considered the same.  It is used when the caller has other ways
    to ensure that global memory is unchanged in between.  */
 
-int
-operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
+bool
+operand_compare::operand_equal_p (const_tree arg0, const_tree arg1,
+				  unsigned int flags)
 {
   /* If either is ERROR_MARK, they aren't equal.  */
   if (TREE_CODE (arg0) == ERROR_MARK || TREE_CODE (arg1) == ERROR_MARK
@@ -2868,6 +2883,12 @@ operand_equal_p (const_tree arg0, const_
   if (flags & OEP_ONLY_CONST)
     return 0;
 
+  int val = operand_equal_valueize (arg0, arg1, flags);
+  if (val == 1)
+    return 1;
+  if (val == 0)
+    return 0;
+
 /* Define macros to test an operand from arg0 and arg1 for equality and a
    variant that allows null and views null as being different from any
    non-null value.  In the latter case, if either is null, the both
@@ -3104,12 +3174,50 @@ operand_equal_p (const_tree arg0, const_
 	      && DECL_FUNCTION_CODE (arg0) == DECL_FUNCTION_CODE (arg1));
 
     default:
       return 0;
     }
 
 #undef OP_SAME
 #undef OP_SAME_WITH_NULL
 }
+
+/* Valueizer is a virtual method that allows to introduce extra equalities
+   that are not directly visible from the operand.
+   N1 means values are known to be equal, 0 means values are known to be different
+   -1 means that operand_equal_p should continue processing.  */
+int
+operand_compare::operand_equal_valueize (const_tree, const_tree, unsigned int)
+{
+  return -1;
+}
+
+/* Conveinece wrapper around operand_compare class because usually we do
+   not need to play with the valueizer.  */
+bool
+operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
+{
+  static operand_compare default_compare_instance;
+  return default_compare_instance.operand_equal_p (arg0, arg1, flags);
+}
 \f
 /* Similar to operand_equal_p, but see if ARG0 might have been made by
    shorten_compare from ARG1 when ARG1 was being compared with OTHER.
Index: fold-const.h
===================================================================
--- fold-const.h	(revision 223500)
+++ fold-const.h	(working copy)
@@ -85,7 +85,7 @@ extern void fold_defer_overflow_warnings
 extern void fold_undefer_overflow_warnings (bool, const_gimple, int);
 extern void fold_undefer_and_ignore_overflow_warnings (void);
 extern bool fold_deferring_overflow_warnings_p (void);
-extern int operand_equal_p (const_tree, const_tree, unsigned int);
+extern bool operand_equal_p (const_tree, const_tree, unsigned int flags = 0);
 extern int multiple_of_p (tree, const_tree, const_tree);
 #define omit_one_operand(T1,T2,T3)\
    omit_one_operand_loc (UNKNOWN_LOCATION, T1, T2, T3)
@@ -189,4 +189,20 @@ extern tree fold_build_pointer_plus_hwi_
 
 #define fold_build_pointer_plus_hwi(p,o) \
 	fold_build_pointer_plus_hwi_loc (UNKNOWN_LOCATION, p, o)
+
+/* Class used to compare gimple operands.  */
+
+class operand_compare
+{
+public:
+  /* Return true if two operands are equal.  THe flags fields can be used
+     to specify OEP flags described above.   */
+  bool operand_equal_p (const_tree, const_tree, unsigned int flags = 0);
+private:
+  /* Valueizer can be used to make non-trivial equalities for expressions
+     that do not look same in isolation.
+     1 means values are known to be equal, 0 means values are known to be
+     different -1 means that operand_equal_p should continue processing.  */
+  virtual int operand_equal_valueize (const_tree, const_tree, unsigned int);
+};
 #endif // GCC_FOLD_CONST_H
Index: ipa-icf-gimple.c
===================================================================
--- ipa-icf-gimple.c	(revision 223500)
+++ ipa-icf-gimple.c	(working copy)
@@ -412,165 +428,57 @@ func_checker::compare_cst_or_decl (tree
     }
 }
 
-/* Function responsible for comparison of various operands T1 and T2.
-   If these components, from functions FUNC1 and FUNC2, are equal, true
-   is returned.  */
-
-bool
-func_checker::compare_operand (tree t1, tree t2)
+int
+func_checker::operand_equal_valueize (const_tree ct1, const_tree ct2, unsigned int)
 {
-  tree x1, x2, y1, y2, z1, z2;
+  tree t1 = const_cast <tree> (ct1);
+  tree t2 = const_cast <tree> (ct2);
   bool ret;
 
-  if (!t1 && !t2)
-    return true;
-  else if (!t1 || !t2)
-    return false;
-
-  tree tt1 = TREE_TYPE (t1);
-  tree tt2 = TREE_TYPE (t2);
-
-  if (!func_checker::compatible_types_p (tt1, tt2))
-    return false;
-
-  if (TREE_CODE (t1) != TREE_CODE (t2))
-    return return_false ();
-
   switch (TREE_CODE (t1))
     {
-    case CONSTRUCTOR:
-      {
-	unsigned length1 = vec_safe_length (CONSTRUCTOR_ELTS (t1));
-	unsigned length2 = vec_safe_length (CONSTRUCTOR_ELTS (t2));
-
-	if (length1 != length2)
-	  return return_false ();
-
-	for (unsigned i = 0; i < length1; i++)
-	  if (!compare_operand (CONSTRUCTOR_ELT (t1, i)->value,
-				CONSTRUCTOR_ELT (t2, i)->value))
-	    return return_false();
-
-	return true;
-      }
-    case ARRAY_REF:
-    case ARRAY_RANGE_REF:
-      /* First argument is the array, second is the index.  */
-      x1 = TREE_OPERAND (t1, 0);
-      x2 = TREE_OPERAND (t2, 0);
-      y1 = TREE_OPERAND (t1, 1);
-      y2 = TREE_OPERAND (t2, 1);
-
-      if (!compare_operand (array_ref_low_bound (t1),
-			    array_ref_low_bound (t2)))
-	return return_false_with_msg ("");
-      if (!compare_operand (array_ref_element_size (t1),
-			    array_ref_element_size (t2)))
-	return return_false_with_msg ("");
-
-      if (!compare_operand (x1, x2))
-	return return_false_with_msg ("");
-      return compare_operand (y1, y2);
-    case MEM_REF:
-      {
-	x1 = TREE_OPERAND (t1, 0);
-	x2 = TREE_OPERAND (t2, 0);
-	y1 = TREE_OPERAND (t1, 1);
-	y2 = TREE_OPERAND (t2, 1);
-
-	/* See if operand is an memory access (the test originate from
-	 gimple_load_p).
-
-	In this case the alias set of the function being replaced must
-	be subset of the alias set of the other function.  At the moment
-	we seek for equivalency classes, so simply require inclussion in
-	both directions.  */
-
-	if (!func_checker::compatible_types_p (TREE_TYPE (x1), TREE_TYPE (x2)))
-	  return return_false ();
-
-	if (!compare_operand (x1, x2))
-	  return return_false_with_msg ("");
-
-	/* Type of the offset on MEM_REF does not matter.  */
-	return wi::to_offset  (y1) == wi::to_offset  (y2);
-      }
-    case COMPONENT_REF:
-      {
-	x1 = TREE_OPERAND (t1, 0);
-	x2 = TREE_OPERAND (t2, 0);
-	y1 = TREE_OPERAND (t1, 1);
-	y2 = TREE_OPERAND (t2, 1);
-
-	ret = compare_operand (x1, x2)
-	      && compare_cst_or_decl (y1, y2);
-
-	return return_with_debug (ret);
-      }
-    /* Virtual table call.  */
-    case OBJ_TYPE_REF:
-      {
-	if (!compare_ssa_name (OBJ_TYPE_REF_EXPR (t1), OBJ_TYPE_REF_EXPR (t2)))
-	  return return_false ();
-	if (opt_for_fn (m_source_func_decl, flag_devirtualize)
-	    && virtual_method_call_p (t1))
-	  {
-	    if (tree_to_uhwi (OBJ_TYPE_REF_TOKEN (t1))
-		!= tree_to_uhwi (OBJ_TYPE_REF_TOKEN (t2)))
-	      return return_false_with_msg ("OBJ_TYPE_REF token mismatch");
-	    if (!types_same_for_odr (obj_type_ref_class (t1),
-				     obj_type_ref_class (t2)))
-	      return return_false_with_msg ("OBJ_TYPE_REF OTR type mismatch");
-	    if (!compare_operand (OBJ_TYPE_REF_OBJECT (t1),
-				  OBJ_TYPE_REF_OBJECT (t2)))
-	      return return_false_with_msg ("OBJ_TYPE_REF object mismatch");
-	  }
-
-	return return_with_debug (true);
-      }
-    case IMAGPART_EXPR:
-    case REALPART_EXPR:
-    case ADDR_EXPR:
+    case FUNCTION_DECL:
+      /* All function decls are in the symbol table and known to match
+	 before we start comparing bodies.  */
+      return true;
+    case VAR_DECL:
+      return return_with_debug (compare_variable_decl (t1, t2));
+    case LABEL_DECL:
       {
-	x1 = TREE_OPERAND (t1, 0);
-	x2 = TREE_OPERAND (t2, 0);
+	int *bb1 = m_label_bb_map.get (t1);
+	int *bb2 = m_label_bb_map.get (t2);
 
-	ret = compare_operand (x1, x2);
-	return return_with_debug (ret);
+	return return_with_debug (*bb1 == *bb2);
       }
-    case BIT_FIELD_REF:
+    case PARM_DECL:
+    case RESULT_DECL:
+    case CONST_DECL:
       {
-	x1 = TREE_OPERAND (t1, 0);
-	x2 = TREE_OPERAND (t2, 0);
-	y1 = TREE_OPERAND (t1, 1);
-	y2 = TREE_OPERAND (t2, 1);
-	z1 = TREE_OPERAND (t1, 2);
-	z2 = TREE_OPERAND (t2, 2);
-
-	ret = compare_operand (x1, x2)
-	      && compare_cst_or_decl (y1, y2)
-	      && compare_cst_or_decl (z1, z2);
-
+	ret = compare_decl (t1, t2);
 	return return_with_debug (ret);
       }
     case SSA_NAME:
-	return compare_ssa_name (t1, t2);
-    case INTEGER_CST:
-    case COMPLEX_CST:
-    case VECTOR_CST:
-    case STRING_CST:
-    case REAL_CST:
-    case FUNCTION_DECL:
-    case VAR_DECL:
-    case FIELD_DECL:
-    case LABEL_DECL:
-    case PARM_DECL:
-    case RESULT_DECL:
-    case CONST_DECL:
-      return compare_cst_or_decl (t1, t2);
+      return compare_ssa_name (t1, t2);
     default:
-      return return_false_with_msg ("Unknown TREE code reached");
+      break;
     }
+  return -1;
+}
+
+/* Function responsible for comparison of various operands T1 and T2.
+   If these components, from functions FUNC1 and FUNC2, are equal, true
+   is returned.  */
+
+bool
+func_checker::compare_operand (tree t1, tree t2)
+{
+  if (!t1 && !t2)
+    return true;
+  else if (!t1 || !t2)
+    return false;
+  if (operand_equal_p (t1, t2, 0))
+    return true;
+  return return_false_with_msg ("operand_equal_p failed");
 }
 
 /* Compares two tree list operands T1 and T2 and returns true if these
Index: ipa-icf-gimple.h
===================================================================
--- ipa-icf-gimple.h	(revision 223500)
+++ ipa-icf-gimple.h	(working copy)
@@ -127,7 +127,7 @@ public:
 
 /* A class aggregating all connections and semantic equivalents
    for a given pair of semantic function candidates.  */
-class func_checker
+class func_checker : operand_compare
 {
 public:
   /* Initialize internal structures for a given SOURCE_FUNC_DECL and
@@ -143,7 +143,7 @@ public:
 		hash_set<symtab_node *> *ignored_target_nodes = NULL);
 
   /* Memory release routine.  */
-  ~func_checker();
+  virtual ~func_checker();
 
   /* Function visits all gimple labels and creates corresponding
      mapping between basic blocks and labels.  */
@@ -273,6 +273,8 @@ private:
 
   /* Flag if ignore labels in comparison.  */
   bool m_ignore_labels;
+
+  virtual int operand_equal_valueize (const_tree, const_tree, unsigned int);
 };
 
 } // ipa_icf_gimple namespace
Index: ipa-icf.c
===================================================================
--- ipa-icf.c	(revision 223500)
+++ ipa-icf.c	(working copy)
@@ -953,9 +953,14 @@ sem_function::equals_private (sem_item *
     }
 
   /* Checking all basic blocks.  */
+  push_cfun (DECL_STRUCT_FUNCTION (decl));
   for (unsigned i = 0; i < bb_sorted.length (); ++i)
     if(!m_checker->compare_bb (bb_sorted[i], m_compared_func->bb_sorted[i]))
-      return return_false();
+      {
+	pop_cfun ();
+        return return_false();
+      }
+  pop_cfun ();
 
   dump_message ("All BBs are equal\n");
 

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

* Re: [RFC] operand_equal_p with valueization
  2015-05-22 12:50 [RFC] operand_equal_p with valueization Jan Hubicka
@ 2015-05-22 13:40 ` Richard Biener
  2015-05-22 14:12   ` Jan Hubicka
  0 siblings, 1 reply; 59+ messages in thread
From: Richard Biener @ 2015-05-22 13:40 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: gcc-patches

On Fri, 22 May 2015, Jan Hubicka wrote:

> Hi,
> with aliasing sanity checks I got burnt again with ipa-icf-gimple's
> compare_operand doing alias set checks on all types it ever trips across.
> 
> I always tought that we do not need two equality testers - operand_equal_p and
> compare_operand and given that it turns out to be non-trivial to fix issues in
> compare_operand I decided to go ahead with plan to unify them.
> I think operand_equal_p is better code base to start from since it is more
> tested and knows more special cases.
> 
> The basic idea is to add valeize hook similar way as other folders do that
> allows to do magic inside the recursive comparsion. I.e. declare two trees
> equal if they are not (i.e. SSA_NAMES from differen functions).  I think it
> should be useful for GVN/VRP/CCP too to improve folding of conditionals.
> 
> After trying out the hook and figuring out that ipa-icf does not have
> global context to hold its tables, I dedcided that maybe more C++ way
> is to have comparsion class that can be derived an adjusted for other
> needs.
> 
> The following patch is a first step.  If it is considered sane, I will
> continue by moving the code to one place - ipa-icf-gimple or special
> ipa-icf-op.c. I will also recover Martin's diagnostics that is useful
> to debug why things are considered different.
> 
> Also the code should be C++ized, for example it should use true/false
> instead 0/1.
> 
> I think also the iterative hashing should be together with operand_equal_p
> implementation because these two must match as I found with merging the two
> cases that ipa-icf-gimple gets right and fold-const wrong - OBJ_TYPE_REF,
> CONSTRUCTOR and PARM_DECL.
> 
> Finally I think we want compare_gimple class that does the same for
> gimple and is independent of rest of the ipa-icf that may be better
> suitable for stuff like tail merging.
> 
> The patch bootstraps/regtests ppc64-linux, but I think it is not quite
> mainline ready as it noticeably reduces number of equivalences found. 
> I will need to debug why that happens, but I am sending it as an RFC for
> the basic concept and interfaces.

I think for the case of IPA ICF it would be better to address the
issue that it cannot do merging of functions with TBAA conflicts.
That is, drop that TBAA code from IPA ICF and arrange for the
IPA inliner to inline original unmerged copies.  We were talking
about making the original nodes "inline clones" of the node that
eventually prevails, much similar to speculative inlining ones
(if I remember that suggestion from Martin correctly).

And no, I'm hesitant to change operand_equal_p too much.  It's
very much deep-rooted into GENERIC.

Richard.


> Honza
> 
> 	* fold-const.c (operand_equal_p): Reorg to wrapper for
> 	(operand_compare::operand_equal_p): This function; add
> 	support for valueization, add missing type matching for
> 	OBJ_TYPE_REF, CONSTRUCTOR; relax matching of PARM_DECL.
> 	(operand_compare::operand_equal_valueize): New.
> 	* fold-const.h (operand_equal_p): Update prototype.
> 	(class operand_compare): New class.
> 	* ipa-icf-gimple.c (func_checker::operand_equal_valueize): Break
> 	ipa-icf specific bits out from ...
> 	(func_checker::compare_operand): ... here; remove most of generic
> 	handling and use operand_compare class.
> 	* ipa-icf-gimple.h (operand_compare): New.
> 	* ipa-icf.c (sem_function::equals_private): Arrange CFUN to be up to
> 	date so we operand_equal_p works well for flag_devirtualize.
> Index: fold-const.c
> ===================================================================
> --- fold-const.c	(revision 223500)
> +++ fold-const.c	(working copy)
> @@ -2716,8 +2730,9 @@ combine_comparisons (location_t loc,
>     are considered the same.  It is used when the caller has other ways
>     to ensure that global memory is unchanged in between.  */
>  
> -int
> -operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
> +bool
> +operand_compare::operand_equal_p (const_tree arg0, const_tree arg1,
> +				  unsigned int flags)
>  {
>    /* If either is ERROR_MARK, they aren't equal.  */
>    if (TREE_CODE (arg0) == ERROR_MARK || TREE_CODE (arg1) == ERROR_MARK
> @@ -2868,6 +2883,12 @@ operand_equal_p (const_tree arg0, const_
>    if (flags & OEP_ONLY_CONST)
>      return 0;
>  
> +  int val = operand_equal_valueize (arg0, arg1, flags);
> +  if (val == 1)
> +    return 1;
> +  if (val == 0)
> +    return 0;
> +
>  /* Define macros to test an operand from arg0 and arg1 for equality and a
>     variant that allows null and views null as being different from any
>     non-null value.  In the latter case, if either is null, the both
> @@ -3104,12 +3174,50 @@ operand_equal_p (const_tree arg0, const_
>  	      && DECL_FUNCTION_CODE (arg0) == DECL_FUNCTION_CODE (arg1));
>  
>      default:
>        return 0;
>      }
>  
>  #undef OP_SAME
>  #undef OP_SAME_WITH_NULL
>  }
> +
> +/* Valueizer is a virtual method that allows to introduce extra equalities
> +   that are not directly visible from the operand.
> +   N1 means values are known to be equal, 0 means values are known to be different
> +   -1 means that operand_equal_p should continue processing.  */
> +int
> +operand_compare::operand_equal_valueize (const_tree, const_tree, unsigned int)
> +{
> +  return -1;
> +}
> +
> +/* Conveinece wrapper around operand_compare class because usually we do
> +   not need to play with the valueizer.  */
> +bool
> +operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
> +{
> +  static operand_compare default_compare_instance;
> +  return default_compare_instance.operand_equal_p (arg0, arg1, flags);
> +}
>  \f
>  /* Similar to operand_equal_p, but see if ARG0 might have been made by
>     shorten_compare from ARG1 when ARG1 was being compared with OTHER.
> Index: fold-const.h
> ===================================================================
> --- fold-const.h	(revision 223500)
> +++ fold-const.h	(working copy)
> @@ -85,7 +85,7 @@ extern void fold_defer_overflow_warnings
>  extern void fold_undefer_overflow_warnings (bool, const_gimple, int);
>  extern void fold_undefer_and_ignore_overflow_warnings (void);
>  extern bool fold_deferring_overflow_warnings_p (void);
> -extern int operand_equal_p (const_tree, const_tree, unsigned int);
> +extern bool operand_equal_p (const_tree, const_tree, unsigned int flags = 0);
>  extern int multiple_of_p (tree, const_tree, const_tree);
>  #define omit_one_operand(T1,T2,T3)\
>     omit_one_operand_loc (UNKNOWN_LOCATION, T1, T2, T3)
> @@ -189,4 +189,20 @@ extern tree fold_build_pointer_plus_hwi_
>  
>  #define fold_build_pointer_plus_hwi(p,o) \
>  	fold_build_pointer_plus_hwi_loc (UNKNOWN_LOCATION, p, o)
> +
> +/* Class used to compare gimple operands.  */
> +
> +class operand_compare
> +{
> +public:
> +  /* Return true if two operands are equal.  THe flags fields can be used
> +     to specify OEP flags described above.   */
> +  bool operand_equal_p (const_tree, const_tree, unsigned int flags = 0);
> +private:
> +  /* Valueizer can be used to make non-trivial equalities for expressions
> +     that do not look same in isolation.
> +     1 means values are known to be equal, 0 means values are known to be
> +     different -1 means that operand_equal_p should continue processing.  */
> +  virtual int operand_equal_valueize (const_tree, const_tree, unsigned int);
> +};
>  #endif // GCC_FOLD_CONST_H
> Index: ipa-icf-gimple.c
> ===================================================================
> --- ipa-icf-gimple.c	(revision 223500)
> +++ ipa-icf-gimple.c	(working copy)
> @@ -412,165 +428,57 @@ func_checker::compare_cst_or_decl (tree
>      }
>  }
>  
> -/* Function responsible for comparison of various operands T1 and T2.
> -   If these components, from functions FUNC1 and FUNC2, are equal, true
> -   is returned.  */
> -
> -bool
> -func_checker::compare_operand (tree t1, tree t2)
> +int
> +func_checker::operand_equal_valueize (const_tree ct1, const_tree ct2, unsigned int)
>  {
> -  tree x1, x2, y1, y2, z1, z2;
> +  tree t1 = const_cast <tree> (ct1);
> +  tree t2 = const_cast <tree> (ct2);
>    bool ret;
>  
> -  if (!t1 && !t2)
> -    return true;
> -  else if (!t1 || !t2)
> -    return false;
> -
> -  tree tt1 = TREE_TYPE (t1);
> -  tree tt2 = TREE_TYPE (t2);
> -
> -  if (!func_checker::compatible_types_p (tt1, tt2))
> -    return false;
> -
> -  if (TREE_CODE (t1) != TREE_CODE (t2))
> -    return return_false ();
> -
>    switch (TREE_CODE (t1))
>      {
> -    case CONSTRUCTOR:
> -      {
> -	unsigned length1 = vec_safe_length (CONSTRUCTOR_ELTS (t1));
> -	unsigned length2 = vec_safe_length (CONSTRUCTOR_ELTS (t2));
> -
> -	if (length1 != length2)
> -	  return return_false ();
> -
> -	for (unsigned i = 0; i < length1; i++)
> -	  if (!compare_operand (CONSTRUCTOR_ELT (t1, i)->value,
> -				CONSTRUCTOR_ELT (t2, i)->value))
> -	    return return_false();
> -
> -	return true;
> -      }
> -    case ARRAY_REF:
> -    case ARRAY_RANGE_REF:
> -      /* First argument is the array, second is the index.  */
> -      x1 = TREE_OPERAND (t1, 0);
> -      x2 = TREE_OPERAND (t2, 0);
> -      y1 = TREE_OPERAND (t1, 1);
> -      y2 = TREE_OPERAND (t2, 1);
> -
> -      if (!compare_operand (array_ref_low_bound (t1),
> -			    array_ref_low_bound (t2)))
> -	return return_false_with_msg ("");
> -      if (!compare_operand (array_ref_element_size (t1),
> -			    array_ref_element_size (t2)))
> -	return return_false_with_msg ("");
> -
> -      if (!compare_operand (x1, x2))
> -	return return_false_with_msg ("");
> -      return compare_operand (y1, y2);
> -    case MEM_REF:
> -      {
> -	x1 = TREE_OPERAND (t1, 0);
> -	x2 = TREE_OPERAND (t2, 0);
> -	y1 = TREE_OPERAND (t1, 1);
> -	y2 = TREE_OPERAND (t2, 1);
> -
> -	/* See if operand is an memory access (the test originate from
> -	 gimple_load_p).
> -
> -	In this case the alias set of the function being replaced must
> -	be subset of the alias set of the other function.  At the moment
> -	we seek for equivalency classes, so simply require inclussion in
> -	both directions.  */
> -
> -	if (!func_checker::compatible_types_p (TREE_TYPE (x1), TREE_TYPE (x2)))
> -	  return return_false ();
> -
> -	if (!compare_operand (x1, x2))
> -	  return return_false_with_msg ("");
> -
> -	/* Type of the offset on MEM_REF does not matter.  */
> -	return wi::to_offset  (y1) == wi::to_offset  (y2);
> -      }
> -    case COMPONENT_REF:
> -      {
> -	x1 = TREE_OPERAND (t1, 0);
> -	x2 = TREE_OPERAND (t2, 0);
> -	y1 = TREE_OPERAND (t1, 1);
> -	y2 = TREE_OPERAND (t2, 1);
> -
> -	ret = compare_operand (x1, x2)
> -	      && compare_cst_or_decl (y1, y2);
> -
> -	return return_with_debug (ret);
> -      }
> -    /* Virtual table call.  */
> -    case OBJ_TYPE_REF:
> -      {
> -	if (!compare_ssa_name (OBJ_TYPE_REF_EXPR (t1), OBJ_TYPE_REF_EXPR (t2)))
> -	  return return_false ();
> -	if (opt_for_fn (m_source_func_decl, flag_devirtualize)
> -	    && virtual_method_call_p (t1))
> -	  {
> -	    if (tree_to_uhwi (OBJ_TYPE_REF_TOKEN (t1))
> -		!= tree_to_uhwi (OBJ_TYPE_REF_TOKEN (t2)))
> -	      return return_false_with_msg ("OBJ_TYPE_REF token mismatch");
> -	    if (!types_same_for_odr (obj_type_ref_class (t1),
> -				     obj_type_ref_class (t2)))
> -	      return return_false_with_msg ("OBJ_TYPE_REF OTR type mismatch");
> -	    if (!compare_operand (OBJ_TYPE_REF_OBJECT (t1),
> -				  OBJ_TYPE_REF_OBJECT (t2)))
> -	      return return_false_with_msg ("OBJ_TYPE_REF object mismatch");
> -	  }
> -
> -	return return_with_debug (true);
> -      }
> -    case IMAGPART_EXPR:
> -    case REALPART_EXPR:
> -    case ADDR_EXPR:
> +    case FUNCTION_DECL:
> +      /* All function decls are in the symbol table and known to match
> +	 before we start comparing bodies.  */
> +      return true;
> +    case VAR_DECL:
> +      return return_with_debug (compare_variable_decl (t1, t2));
> +    case LABEL_DECL:
>        {
> -	x1 = TREE_OPERAND (t1, 0);
> -	x2 = TREE_OPERAND (t2, 0);
> +	int *bb1 = m_label_bb_map.get (t1);
> +	int *bb2 = m_label_bb_map.get (t2);
>  
> -	ret = compare_operand (x1, x2);
> -	return return_with_debug (ret);
> +	return return_with_debug (*bb1 == *bb2);
>        }
> -    case BIT_FIELD_REF:
> +    case PARM_DECL:
> +    case RESULT_DECL:
> +    case CONST_DECL:
>        {
> -	x1 = TREE_OPERAND (t1, 0);
> -	x2 = TREE_OPERAND (t2, 0);
> -	y1 = TREE_OPERAND (t1, 1);
> -	y2 = TREE_OPERAND (t2, 1);
> -	z1 = TREE_OPERAND (t1, 2);
> -	z2 = TREE_OPERAND (t2, 2);
> -
> -	ret = compare_operand (x1, x2)
> -	      && compare_cst_or_decl (y1, y2)
> -	      && compare_cst_or_decl (z1, z2);
> -
> +	ret = compare_decl (t1, t2);
>  	return return_with_debug (ret);
>        }
>      case SSA_NAME:
> -	return compare_ssa_name (t1, t2);
> -    case INTEGER_CST:
> -    case COMPLEX_CST:
> -    case VECTOR_CST:
> -    case STRING_CST:
> -    case REAL_CST:
> -    case FUNCTION_DECL:
> -    case VAR_DECL:
> -    case FIELD_DECL:
> -    case LABEL_DECL:
> -    case PARM_DECL:
> -    case RESULT_DECL:
> -    case CONST_DECL:
> -      return compare_cst_or_decl (t1, t2);
> +      return compare_ssa_name (t1, t2);
>      default:
> -      return return_false_with_msg ("Unknown TREE code reached");
> +      break;
>      }
> +  return -1;
> +}
> +
> +/* Function responsible for comparison of various operands T1 and T2.
> +   If these components, from functions FUNC1 and FUNC2, are equal, true
> +   is returned.  */
> +
> +bool
> +func_checker::compare_operand (tree t1, tree t2)
> +{
> +  if (!t1 && !t2)
> +    return true;
> +  else if (!t1 || !t2)
> +    return false;
> +  if (operand_equal_p (t1, t2, 0))
> +    return true;
> +  return return_false_with_msg ("operand_equal_p failed");
>  }
>  
>  /* Compares two tree list operands T1 and T2 and returns true if these
> Index: ipa-icf-gimple.h
> ===================================================================
> --- ipa-icf-gimple.h	(revision 223500)
> +++ ipa-icf-gimple.h	(working copy)
> @@ -127,7 +127,7 @@ public:
>  
>  /* A class aggregating all connections and semantic equivalents
>     for a given pair of semantic function candidates.  */
> -class func_checker
> +class func_checker : operand_compare
>  {
>  public:
>    /* Initialize internal structures for a given SOURCE_FUNC_DECL and
> @@ -143,7 +143,7 @@ public:
>  		hash_set<symtab_node *> *ignored_target_nodes = NULL);
>  
>    /* Memory release routine.  */
> -  ~func_checker();
> +  virtual ~func_checker();
>  
>    /* Function visits all gimple labels and creates corresponding
>       mapping between basic blocks and labels.  */
> @@ -273,6 +273,8 @@ private:
>  
>    /* Flag if ignore labels in comparison.  */
>    bool m_ignore_labels;
> +
> +  virtual int operand_equal_valueize (const_tree, const_tree, unsigned int);
>  };
>  
>  } // ipa_icf_gimple namespace
> Index: ipa-icf.c
> ===================================================================
> --- ipa-icf.c	(revision 223500)
> +++ ipa-icf.c	(working copy)
> @@ -953,9 +953,14 @@ sem_function::equals_private (sem_item *
>      }
>  
>    /* Checking all basic blocks.  */
> +  push_cfun (DECL_STRUCT_FUNCTION (decl));
>    for (unsigned i = 0; i < bb_sorted.length (); ++i)
>      if(!m_checker->compare_bb (bb_sorted[i], m_compared_func->bb_sorted[i]))
> -      return return_false();
> +      {
> +	pop_cfun ();
> +        return return_false();
> +      }
> +  pop_cfun ();
>  
>    dump_message ("All BBs are equal\n");
>  
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Dilip Upmanyu, Graham Norton, HRB 21284 (AG Nuernberg)

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

* Re: [RFC] operand_equal_p with valueization
  2015-05-22 13:40 ` Richard Biener
@ 2015-05-22 14:12   ` Jan Hubicka
  2015-05-26  8:18     ` Richard Biener
  0 siblings, 1 reply; 59+ messages in thread
From: Jan Hubicka @ 2015-05-22 14:12 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jan Hubicka, gcc-patches

> 
> And no, I'm hesitant to change operand_equal_p too much.  It's
> very much deep-rooted into GENERIC.

OK, as another option, i can bring relevant logic from operand_equal_p
to ipa-icf and separate it into the compare_operand class like I did.
Use it in ipa-icf-gimple now and we can slowly turn other uses of
operand_equal into the compare_operand users in middle end.

I agree that operand_equal is bit crazy code and it does not handle quite few
things we could do at gimple.  I have nothing against going this direction.
(after all I do not like touching fold-const much becuase it works on generic,
gimple and FE non-generic and it is not well specified what it should do)

Honza

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

* Re: [RFC] operand_equal_p with valueization
  2015-05-22 14:12   ` Jan Hubicka
@ 2015-05-26  8:18     ` Richard Biener
  2015-05-26 19:09       ` Jan Hubicka
  0 siblings, 1 reply; 59+ messages in thread
From: Richard Biener @ 2015-05-26  8:18 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: gcc-patches

On Fri, 22 May 2015, Jan Hubicka wrote:

> > 
> > And no, I'm hesitant to change operand_equal_p too much.  It's
> > very much deep-rooted into GENERIC.
> 
> OK, as another option, i can bring relevant logic from operand_equal_p
> to ipa-icf and separate it into the compare_operand class like I did.
> Use it in ipa-icf-gimple now and we can slowly turn other uses of
> operand_equal into the compare_operand users in middle end.
> 
> I agree that operand_equal is bit crazy code and it does not handle quite few
> things we could do at gimple.  I have nothing against going this direction.
> (after all I do not like touching fold-const much becuase it works on generic,
> gimple and FE non-generic and it is not well specified what it should do)

Yes, I've played with the idea of a GIMPLE specific operand_equal_p 
multiple times but then the changes required to operand_equal_p were
small all the times.  And having one piece of code that does sth is
always good ...

We might turn operand_equal_p to a "worker" (template?) that
operand_equal_p and gimple_operand_equal_p can share (with an extra
flag whether to turn on GIMPLE stuff and/or valueization).  And
then simply provide explicit instantiations for the original
operand_equal_p and a new gimple_operand_equal_p.

Of course we'll only know if we like that when seeing a patch that
does this ;0)

Richard.

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

* Re: [RFC] operand_equal_p with valueization
  2015-05-26  8:18     ` Richard Biener
@ 2015-05-26 19:09       ` Jan Hubicka
  2015-05-27  8:49         ` Richard Biener
  0 siblings, 1 reply; 59+ messages in thread
From: Jan Hubicka @ 2015-05-26 19:09 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jan Hubicka, gcc-patches

> On Fri, 22 May 2015, Jan Hubicka wrote:
> 
> > > 
> > > And no, I'm hesitant to change operand_equal_p too much.  It's
> > > very much deep-rooted into GENERIC.
> > 
> > OK, as another option, i can bring relevant logic from operand_equal_p
> > to ipa-icf and separate it into the compare_operand class like I did.
> > Use it in ipa-icf-gimple now and we can slowly turn other uses of
> > operand_equal into the compare_operand users in middle end.
> > 
> > I agree that operand_equal is bit crazy code and it does not handle quite few
> > things we could do at gimple.  I have nothing against going this direction.
> > (after all I do not like touching fold-const much becuase it works on generic,
> > gimple and FE non-generic and it is not well specified what it should do)
> 
> Yes, I've played with the idea of a GIMPLE specific operand_equal_p 
> multiple times but then the changes required to operand_equal_p were
> small all the times.  And having one piece of code that does sth is
> always good ...
> 
> We might turn operand_equal_p to a "worker" (template?) that

Hmm, OK that is precisely what I was shooting for by this patch.  I went by
wrapping it to a class with valueize helper.  It can be template, too, just it
semed that having the single valueize function lets me do everything I need
without actually needing to duplicate the code.

I can get around templatizing it.  Do you have some outline what interface
would seem more fit>

> operand_equal_p and gimple_operand_equal_p can share (with an extra
> flag whether to turn on GIMPLE stuff and/or valueization).  And
> then simply provide explicit instantiations for the original
> operand_equal_p and a new gimple_operand_equal_p.
> 
> Of course we'll only know if we like that when seeing a patch that
> does this ;0)
> 
> Richard.

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

* Re: [RFC] operand_equal_p with valueization
  2015-05-26 19:09       ` Jan Hubicka
@ 2015-05-27  8:49         ` Richard Biener
  2019-06-18 11:10           ` [RFC] " Martin Liška
  0 siblings, 1 reply; 59+ messages in thread
From: Richard Biener @ 2015-05-27  8:49 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: gcc-patches

On Tue, 26 May 2015, Jan Hubicka wrote:

> > On Fri, 22 May 2015, Jan Hubicka wrote:
> > 
> > > > 
> > > > And no, I'm hesitant to change operand_equal_p too much.  It's
> > > > very much deep-rooted into GENERIC.
> > > 
> > > OK, as another option, i can bring relevant logic from operand_equal_p
> > > to ipa-icf and separate it into the compare_operand class like I did.
> > > Use it in ipa-icf-gimple now and we can slowly turn other uses of
> > > operand_equal into the compare_operand users in middle end.
> > > 
> > > I agree that operand_equal is bit crazy code and it does not handle quite few
> > > things we could do at gimple.  I have nothing against going this direction.
> > > (after all I do not like touching fold-const much becuase it works on generic,
> > > gimple and FE non-generic and it is not well specified what it should do)
> > 
> > Yes, I've played with the idea of a GIMPLE specific operand_equal_p 
> > multiple times but then the changes required to operand_equal_p were
> > small all the times.  And having one piece of code that does sth is
> > always good ...
> > 
> > We might turn operand_equal_p to a "worker" (template?) that
> 
> Hmm, OK that is precisely what I was shooting for by this patch.  I went by
> wrapping it to a class with valueize helper.  It can be template, too, just it
> semed that having the single valueize function lets me do everything I need
> without actually needing to duplicate the code.
> 
> I can get around templatizing it.  Do you have some outline what interface
> would seem more fit>

I was thinking about

template <bool with_valueize>
int
operand_equal_p_1 (const_tree arg0, const_tree arg1, unsigned int flags,
                   tree (*valueize)(tree))
{
#define VALUEIZE(op) (with_valueize && valueize) ? valueize (op) : op 
...
}

and

extern template <>
int operand_equal_p_1<false> (const_tree arg0, const_tree arg1, 
unsigned int flags,
                   tree (*valueize)(tree));
extern template <>
int operand_equal_p_1<true> (const_tree arg0, const_tree arg1,    
unsigned int flags,
                   tree (*valueize)(tree));

int
operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
{
  return operand_equal_p_1<false> (arg0, arg1, flags, NULL);
}

we don't want to make 'valueize' a template parameter (that is,
we don't want to put operand_equal_p_1 to fold-const.h).

Same with an eventual 'gimple_p' template parameter (which eventually
could simply be the same as the with_valueize one).

I'm playing with the idea to make match-and-simplify similar,
providing explicit specializations for "common" valueize callbacks.
As it always has a valueize callback I'd do it like

template <tree (*fixed_valueize)(tree)>
bool
gimple_simplify (code_helper *res_code, tree *res_ops,
                 gimple_seq *seq, tree (*valueize)(tree),
                 code_helper code, tree type, tree op0)
{
#define do_valueize(op) \
  fixed_valueize != (void *)-1 \
  ? (fixed_valueize ? fixed_valueize (op) : op) \
  : (valueize ? valueize (op) : op)
...
}

Richard.

> > operand_equal_p and gimple_operand_equal_p can share (with an extra
> > flag whether to turn on GIMPLE stuff and/or valueization).  And
> > then simply provide explicit instantiations for the original
> > operand_equal_p and a new gimple_operand_equal_p.
> > 
> > Of course we'll only know if we like that when seeing a patch that
> > does this ;0)
> > 
> > Richard.
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Dilip Upmanyu, Graham Norton, HRB 21284 (AG Nuernberg)

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

* [RFC] Re: [RFC] operand_equal_p with valueization
  2015-05-27  8:49         ` Richard Biener
@ 2019-06-18 11:10           ` Martin Liška
  2019-08-06 15:44             ` [PATCH 0/9] IPA ICF overhaul Martin Liska
  0 siblings, 1 reply; 59+ messages in thread
From: Martin Liška @ 2019-06-18 11:10 UTC (permalink / raw)
  To: Richard Biener, Jan Hubicka; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 987 bytes --]

Hi.

It's quite some time the discussion has started. Now is time for me to refresh IPA ICF
and I would like integrate operand_equal_p with what I currently have in ICF (::compare_operand).
I like the idea of a class that will provide both operand_equal_valueize and hash_operand_valueize.
These will be implemented in func_checker and can provide basically the same what Honza suggested.

Reading the thread, I noticed Richi would prefer to use something like:

template <bool with_valueize>
int
operand_equal_p_1 (const_tree arg0, const_tree arg1, unsigned int flags,
                   tree (*valueize)(tree))
{
#define VALUEIZE(op) (with_valueize && valueize) ? valueize (op) : op 
...
}

To be honest, it looks to me only as an optimization which will fold call
to valueize in current operand_equal_p.

I'm sending a slightly tested pair of patches which does the abstraction
factoring and ICF adaptation.

I would expect a feedback before I'll prepare a proper fix.
Thanks,
Martin

[-- Attachment #2: 0002-Integrate-that-for-IPA-ICF.patch --]
[-- Type: text/x-patch, Size: 9470 bytes --]

From b864e44e14a86e9cc7ba494b7af687a0a3e74896 Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Mon, 10 Jun 2019 14:34:15 +0200
Subject: [PATCH 2/2] Integrate that for IPA ICF.

---
 gcc/ipa-icf-gimple.c | 224 +++++++++++++------------------------------
 gcc/ipa-icf-gimple.h |   8 +-
 gcc/ipa-icf.c        |   7 +-
 3 files changed, 79 insertions(+), 160 deletions(-)

diff --git a/gcc/ipa-icf-gimple.c b/gcc/ipa-icf-gimple.c
index 0713e125898..6da3e19e317 100644
--- a/gcc/ipa-icf-gimple.c
+++ b/gcc/ipa-icf-gimple.c
@@ -324,6 +324,28 @@ func_checker::compare_memory_operand (tree t1, tree t2)
 /* Function compare for equality given trees T1 and T2 which
    can be either a constant or a declaration type.  */
 
+bool
+func_checker::hash_operand_valueize (const_tree arg, inchash::hash &hstate,
+				     unsigned int flags)
+{
+  switch (TREE_CODE (arg))
+    {
+    case FUNCTION_DECL:
+    case VAR_DECL:
+    case LABEL_DECL:
+    case PARM_DECL:
+    case RESULT_DECL:
+    case CONST_DECL:
+    case SSA_NAME:
+      return true;
+
+    default:
+      break;
+    }
+
+  return false;
+}
+
 bool
 func_checker::compare_cst_or_decl (tree t1, tree t2)
 {
@@ -347,19 +369,6 @@ func_checker::compare_cst_or_decl (tree t1, tree t2)
       return true;
     case VAR_DECL:
       return return_with_debug (compare_variable_decl (t1, t2));
-    case FIELD_DECL:
-      {
-	tree offset1 = DECL_FIELD_OFFSET (t1);
-	tree offset2 = DECL_FIELD_OFFSET (t2);
-
-	tree bit_offset1 = DECL_FIELD_BIT_OFFSET (t1);
-	tree bit_offset2 = DECL_FIELD_BIT_OFFSET (t2);
-
-	ret = compare_operand (offset1, offset2)
-	      && compare_operand (bit_offset1, bit_offset2);
-
-	return return_with_debug (ret);
-      }
     case LABEL_DECL:
       {
 	if (t1 == t2)
@@ -383,165 +392,66 @@ func_checker::compare_cst_or_decl (tree t1, tree t2)
     }
 }
 
-/* Function responsible for comparison of various operands T1 and T2.
-   If these components, from functions FUNC1 and FUNC2, are equal, true
-   is returned.  */
-
-bool
-func_checker::compare_operand (tree t1, tree t2)
+int
+func_checker::operand_equal_valueize (const_tree ct1, const_tree ct2, unsigned int)
 {
-  tree x1, x2, y1, y2, z1, z2;
-  bool ret;
-
-  if (!t1 && !t2)
-    return true;
-  else if (!t1 || !t2)
-    return false;
-
-  tree tt1 = TREE_TYPE (t1);
-  tree tt2 = TREE_TYPE (t2);
-
-  if (!func_checker::compatible_types_p (tt1, tt2))
-    return false;
-
-  if (TREE_CODE (t1) != TREE_CODE (t2))
-    return return_false ();
+  tree t1 = const_cast <tree> (ct1);
+  tree t2 = const_cast <tree> (ct2);
 
   switch (TREE_CODE (t1))
     {
-    case CONSTRUCTOR:
+    case FUNCTION_DECL:
+      /* All function decls are in the symbol table and known to match
+	 before we start comparing bodies.  */
+      return true;
+    case VAR_DECL:
+      return return_with_debug (compare_variable_decl (t1, t2));
+    case LABEL_DECL:
       {
-	unsigned length1 = CONSTRUCTOR_NELTS (t1);
-	unsigned length2 = CONSTRUCTOR_NELTS (t2);
-
-	if (length1 != length2)
-	  return return_false ();
-
-	for (unsigned i = 0; i < length1; i++)
-	  if (!compare_operand (CONSTRUCTOR_ELT (t1, i)->value,
-				CONSTRUCTOR_ELT (t2, i)->value))
-	    return return_false();
-
-	return true;
+	int *bb1 = m_label_bb_map.get (t1);
+	int *bb2 = m_label_bb_map.get (t2);
+	return return_with_debug (*bb1 == *bb2);
       }
-    case ARRAY_REF:
-    case ARRAY_RANGE_REF:
-      /* First argument is the array, second is the index.  */
-      x1 = TREE_OPERAND (t1, 0);
-      x2 = TREE_OPERAND (t2, 0);
-      y1 = TREE_OPERAND (t1, 1);
-      y2 = TREE_OPERAND (t2, 1);
-
-      if (!compare_operand (array_ref_low_bound (t1),
-			    array_ref_low_bound (t2)))
-	return return_false_with_msg ("");
-      if (!compare_operand (array_ref_element_size (t1),
-			    array_ref_element_size (t2)))
-	return return_false_with_msg ("");
-
-      if (!compare_operand (x1, x2))
-	return return_false_with_msg ("");
-      return compare_operand (y1, y2);
-    case MEM_REF:
-      {
-	x1 = TREE_OPERAND (t1, 0);
-	x2 = TREE_OPERAND (t2, 0);
-	y1 = TREE_OPERAND (t1, 1);
-	y2 = TREE_OPERAND (t2, 1);
-
-	/* See if operand is an memory access (the test originate from
-	 gimple_load_p).
-
-	In this case the alias set of the function being replaced must
-	be subset of the alias set of the other function.  At the moment
-	we seek for equivalency classes, so simply require inclussion in
-	both directions.  */
-
-	if (!func_checker::compatible_types_p (TREE_TYPE (x1), TREE_TYPE (x2)))
-	  return return_false ();
 
-	if (!compare_operand (x1, x2))
-	  return return_false_with_msg ("");
-
-	/* Type of the offset on MEM_REF does not matter.  */
-	return known_eq (wi::to_poly_offset (y1), wi::to_poly_offset (y2));
-      }
-    case COMPONENT_REF:
+    case PARM_DECL:
+    case RESULT_DECL:
+    case CONST_DECL:
+      return compare_decl (t1, t2);
+    case SSA_NAME:
+      return compare_ssa_name (t1, t2);
+    case FIELD_DECL:
       {
-	x1 = TREE_OPERAND (t1, 0);
-	x2 = TREE_OPERAND (t2, 0);
-	y1 = TREE_OPERAND (t1, 1);
-	y2 = TREE_OPERAND (t2, 1);
+	tree offset1 = DECL_FIELD_OFFSET (t1);
+	tree offset2 = DECL_FIELD_OFFSET (t2);
 
-	ret = compare_operand (x1, x2)
-	      && compare_cst_or_decl (y1, y2);
+	tree bit_offset1 = DECL_FIELD_BIT_OFFSET (t1);
+	tree bit_offset2 = DECL_FIELD_BIT_OFFSET (t2);
 
+	bool ret = (compare_operand (offset1, offset2)
+		    && compare_operand (bit_offset1, bit_offset2));
 	return return_with_debug (ret);
       }
-    /* Virtual table call.  */
-    case OBJ_TYPE_REF:
-      {
-	if (!compare_ssa_name (OBJ_TYPE_REF_EXPR (t1), OBJ_TYPE_REF_EXPR (t2)))
-	  return return_false ();
-	if (opt_for_fn (m_source_func_decl, flag_devirtualize)
-	    && virtual_method_call_p (t1))
-	  {
-	    if (tree_to_uhwi (OBJ_TYPE_REF_TOKEN (t1))
-		!= tree_to_uhwi (OBJ_TYPE_REF_TOKEN (t2)))
-	      return return_false_with_msg ("OBJ_TYPE_REF token mismatch");
-	    if (!types_same_for_odr (obj_type_ref_class (t1),
-				     obj_type_ref_class (t2)))
-	      return return_false_with_msg ("OBJ_TYPE_REF OTR type mismatch");
-	    if (!compare_operand (OBJ_TYPE_REF_OBJECT (t1),
-				  OBJ_TYPE_REF_OBJECT (t2)))
-	      return return_false_with_msg ("OBJ_TYPE_REF object mismatch");
-	  }
-
-	return return_with_debug (true);
-      }
-    case IMAGPART_EXPR:
-    case REALPART_EXPR:
-    case ADDR_EXPR:
-      {
-	x1 = TREE_OPERAND (t1, 0);
-	x2 = TREE_OPERAND (t2, 0);
+    default:
+      break;
+    }
 
-	ret = compare_operand (x1, x2);
-	return return_with_debug (ret);
-      }
-    case BIT_FIELD_REF:
-      {
-	x1 = TREE_OPERAND (t1, 0);
-	x2 = TREE_OPERAND (t2, 0);
-	y1 = TREE_OPERAND (t1, 1);
-	y2 = TREE_OPERAND (t2, 1);
-	z1 = TREE_OPERAND (t1, 2);
-	z2 = TREE_OPERAND (t2, 2);
+  return -1;
+}
 
-	ret = compare_operand (x1, x2)
-	      && compare_cst_or_decl (y1, y2)
-	      && compare_cst_or_decl (z1, z2);
+/* Function responsible for comparison of various operands T1 and T2.
+   If these components, from functions FUNC1 and FUNC2, are equal, true
+   is returned.  */
 
-	return return_with_debug (ret);
-      }
-    case SSA_NAME:
-	return compare_ssa_name (t1, t2);
-    case INTEGER_CST:
-    case COMPLEX_CST:
-    case VECTOR_CST:
-    case STRING_CST:
-    case REAL_CST:
-    case FUNCTION_DECL:
-    case VAR_DECL:
-    case FIELD_DECL:
-    case LABEL_DECL:
-    case PARM_DECL:
-    case RESULT_DECL:
-    case CONST_DECL:
-      return compare_cst_or_decl (t1, t2);
-    default:
-      return return_false_with_msg ("Unknown TREE code reached");
-    }
+bool
+func_checker::compare_operand (tree t1, tree t2)
+{
+  if (!t1 && !t2)
+    return true;
+  else if (!t1 || !t2)
+    return false;
+  if (operand_equal_p (t1, t2, OEP_MATCH_SIDE_EFFECTS))
+    return true;
+  return return_false_with_msg ("operand_equal_p failed");
 }
 
 bool
diff --git a/gcc/ipa-icf-gimple.h b/gcc/ipa-icf-gimple.h
index 351bddfb2f6..85f95ed62e4 100644
--- a/gcc/ipa-icf-gimple.h
+++ b/gcc/ipa-icf-gimple.h
@@ -118,7 +118,7 @@ public:
 
 /* A class aggregating all connections and semantic equivalents
    for a given pair of semantic function candidates.  */
-class func_checker
+class func_checker : operand_compare
 {
 public:
   /* Initialize internal structures for a given SOURCE_FUNC_DECL and
@@ -134,7 +134,7 @@ public:
 		hash_set<symtab_node *> *ignored_target_nodes = NULL);
 
   /* Memory release routine.  */
-  ~func_checker();
+  virtual ~func_checker();
 
   /* Function visits all gimple labels and creates corresponding
      mapping between basic blocks and labels.  */
@@ -267,6 +267,10 @@ private:
 
   /* Flag if ignore labels in comparison.  */
   bool m_ignore_labels;
+
+  virtual int operand_equal_valueize (const_tree, const_tree, unsigned int);
+  virtual bool hash_operand_valueize (const_tree, inchash::hash &,
+				      unsigned int);
 };
 
 } // ipa_icf_gimple namespace
diff --git a/gcc/ipa-icf.c b/gcc/ipa-icf.c
index 7c486eda758..1a9a0f695be 100644
--- a/gcc/ipa-icf.c
+++ b/gcc/ipa-icf.c
@@ -878,9 +878,14 @@ sem_function::equals_private (sem_item *item)
     }
 
   /* Checking all basic blocks.  */
+  push_cfun (DECL_STRUCT_FUNCTION (decl));
   for (unsigned i = 0; i < bb_sorted.length (); ++i)
     if(!m_checker->compare_bb (bb_sorted[i], m_compared_func->bb_sorted[i]))
-      return return_false();
+      {
+	pop_cfun ();
+        return return_false();
+      }
+  pop_cfun ();
 
   auto_vec <int> bb_dict;
 
-- 
2.21.0


[-- Attachment #3: 0001-Come-up-with-an-abstraction.patch --]
[-- Type: text/x-patch, Size: 23455 bytes --]

From 03893a306d9c37f7590c23cbccf36f124e92f1f0 Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Mon, 10 Jun 2019 14:33:27 +0200
Subject: [PATCH 1/2] Come up with an abstraction.

---
 gcc/fold-const.c | 346 ++++++++++++++++++++++++++++++++++++++++++++++-
 gcc/fold-const.h |  30 +++-
 gcc/tree.c       | 286 ---------------------------------------
 3 files changed, 372 insertions(+), 290 deletions(-)

diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 1fdd085545a..001b7f02dc3 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -2940,7 +2940,8 @@ combine_comparisons (location_t loc,
    even if var is volatile.  */
 
 bool
-operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
+operand_compare::operand_equal_p (const_tree arg0, const_tree arg1,
+				  unsigned int flags)
 {
   /* When checking, verify at the outermost operand_equal_p call that
      if operand_equal_p returns non-zero then ARG0 and ARG1 has the same
@@ -2952,8 +2953,8 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 	  if (arg0 != arg1)
 	    {
 	      inchash::hash hstate0 (0), hstate1 (0);
-	      inchash::add_expr (arg0, hstate0, flags | OEP_HASH_CHECK);
-	      inchash::add_expr (arg1, hstate1, flags | OEP_HASH_CHECK);
+	      hash_operand (arg0, hstate0, flags | OEP_HASH_CHECK);
+	      hash_operand (arg1, hstate1, flags | OEP_HASH_CHECK);
 	      hashval_t h0 = hstate0.end ();
 	      hashval_t h1 = hstate1.end ();
 	      gcc_assert (h0 == h1);
@@ -3094,6 +3095,12 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 	  || (! TREE_SIDE_EFFECTS (arg0) && ! TREE_SIDE_EFFECTS (arg1))))
     return true;
 
+  int val = operand_equal_valueize (arg0, arg1, flags);
+  if (val == 1)
+    return 1;
+  if (val == 0)
+    return 0;
+
   /* Next handle constant cases, those for which we can return 1 even
      if ONLY_CONST is set.  */
   if (TREE_CONSTANT (arg0) && TREE_CONSTANT (arg1))
@@ -3606,6 +3613,339 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 #undef OP_SAME
 #undef OP_SAME_WITH_NULL
 }
+
+/* Generate a hash value for an expression.  This can be used iteratively
+   by passing a previous result as the HSTATE argument.  */
+
+void
+operand_compare::hash_operand (const_tree t, inchash::hash &hstate,
+			       unsigned int flags)
+{
+  int i;
+  enum tree_code code;
+  enum tree_code_class tclass;
+
+  if (t == NULL_TREE || t == error_mark_node)
+    {
+      hstate.merge_hash (0);
+      return;
+    }
+
+  STRIP_ANY_LOCATION_WRAPPER (t);
+
+  if (!(flags & OEP_ADDRESS_OF))
+    STRIP_NOPS (t);
+
+  code = TREE_CODE (t);
+
+  bool ret = hash_operand_valueize (t, hstate, flags);
+  if (ret)
+    return;
+
+  switch (code)
+    {
+    /* Alas, constants aren't shared, so we can't rely on pointer
+       identity.  */
+    case VOID_CST:
+      hstate.merge_hash (0);
+      return;
+    case INTEGER_CST:
+      gcc_checking_assert (!(flags & OEP_ADDRESS_OF));
+      for (i = 0; i < TREE_INT_CST_EXT_NUNITS (t); i++)
+	hstate.add_hwi (TREE_INT_CST_ELT (t, i));
+      return;
+    case REAL_CST:
+      {
+	unsigned int val2;
+	if (!HONOR_SIGNED_ZEROS (t) && real_zerop (t))
+	  val2 = rvc_zero;
+	else
+	  val2 = real_hash (TREE_REAL_CST_PTR (t));
+	hstate.merge_hash (val2);
+	return;
+      }
+    case FIXED_CST:
+      {
+	unsigned int val2 = fixed_hash (TREE_FIXED_CST_PTR (t));
+	hstate.merge_hash (val2);
+	return;
+      }
+    case STRING_CST:
+      hstate.add ((const void *) TREE_STRING_POINTER (t),
+		  TREE_STRING_LENGTH (t));
+      return;
+    case COMPLEX_CST:
+      hash_operand (TREE_REALPART (t), hstate, flags);
+      hash_operand (TREE_IMAGPART (t), hstate, flags);
+      return;
+    case VECTOR_CST:
+      {
+	hstate.add_int (VECTOR_CST_NPATTERNS (t));
+	hstate.add_int (VECTOR_CST_NELTS_PER_PATTERN (t));
+	unsigned int count = vector_cst_encoded_nelts (t);
+	for (unsigned int i = 0; i < count; ++i)
+	  hash_operand (VECTOR_CST_ENCODED_ELT (t, i), hstate, flags);
+	return;
+      }
+    case SSA_NAME:
+      /* We can just compare by pointer.  */
+      hstate.add_hwi (SSA_NAME_VERSION (t));
+      return;
+    case PLACEHOLDER_EXPR:
+      /* The node itself doesn't matter.  */
+      return;
+    case BLOCK:
+    case OMP_CLAUSE:
+      /* Ignore.  */
+      return;
+    case TREE_LIST:
+      /* A list of expressions, for a CALL_EXPR or as the elements of a
+	 VECTOR_CST.  */
+      for (; t; t = TREE_CHAIN (t))
+	hash_operand (TREE_VALUE (t), hstate, flags);
+      return;
+    case CONSTRUCTOR:
+      {
+	unsigned HOST_WIDE_INT idx;
+	tree field, value;
+	flags &= ~OEP_ADDRESS_OF;
+	FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), idx, field, value)
+	  {
+	    hash_operand (field, hstate, flags);
+	    hash_operand (value, hstate, flags);
+	  }
+	return;
+      }
+    case STATEMENT_LIST:
+      {
+	tree_stmt_iterator i;
+	for (i = tsi_start (CONST_CAST_TREE (t));
+	     !tsi_end_p (i); tsi_next (&i))
+	  hash_operand (tsi_stmt (i), hstate, flags);
+	return;
+      }
+    case TREE_VEC:
+      for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
+	hash_operand (TREE_VEC_ELT (t, i), hstate, flags);
+      return;
+    case IDENTIFIER_NODE:
+      hstate.add_object (IDENTIFIER_HASH_VALUE (t));
+      return;
+    case FIELD_DECL:
+      inchash::add_expr (DECL_FIELD_OFFSET (t), hstate, flags);
+      inchash::add_expr (DECL_FIELD_BIT_OFFSET (t), hstate, flags);
+      return;
+    case FUNCTION_DECL:
+      /* When referring to a built-in FUNCTION_DECL, use the __builtin__ form.
+	 Otherwise nodes that compare equal according to operand_equal_p might
+	 get different hash codes.  However, don't do this for machine specific
+	 or front end builtins, since the function code is overloaded in those
+	 cases.  */
+      if (DECL_BUILT_IN_CLASS (t) == BUILT_IN_NORMAL
+	  && builtin_decl_explicit_p (DECL_FUNCTION_CODE (t)))
+	{
+	  t = builtin_decl_explicit (DECL_FUNCTION_CODE (t));
+	  code = TREE_CODE (t);
+	}
+      /* FALL THROUGH */
+    default:
+      if (POLY_INT_CST_P (t))
+	{
+	  for (unsigned int i = 0; i < NUM_POLY_INT_COEFFS; ++i)
+	    hstate.add_wide_int (wi::to_wide (POLY_INT_CST_COEFF (t, i)));
+	  return;
+	}
+      tclass = TREE_CODE_CLASS (code);
+
+      if (tclass == tcc_declaration)
+	{
+	  /* DECL's have a unique ID */
+	  hstate.add_hwi (DECL_UID (t));
+	}
+      else if (tclass == tcc_comparison && !commutative_tree_code (code))
+	{
+	  /* For comparisons that can be swapped, use the lower
+	     tree code.  */
+	  enum tree_code ccode = swap_tree_comparison (code);
+	  if (code < ccode)
+	    ccode = code;
+	  hstate.add_object (ccode);
+	  hash_operand (TREE_OPERAND (t, ccode != code), hstate, flags);
+	  hash_operand (TREE_OPERAND (t, ccode == code), hstate, flags);
+	}
+      else if (CONVERT_EXPR_CODE_P (code))
+	{
+	  /* NOP_EXPR and CONVERT_EXPR are considered equal by
+	     operand_equal_p.  */
+	  enum tree_code ccode = NOP_EXPR;
+	  hstate.add_object (ccode);
+
+	  /* Don't hash the type, that can lead to having nodes which
+	     compare equal according to operand_equal_p, but which
+	     have different hash codes.  Make sure to include signedness
+	     in the hash computation.  */
+	  hstate.add_int (TYPE_UNSIGNED (TREE_TYPE (t)));
+	  hash_operand (TREE_OPERAND (t, 0), hstate, flags);
+	}
+      /* For OEP_ADDRESS_OF, hash MEM_EXPR[&decl, 0] the same as decl.  */
+      else if (code == MEM_REF
+	       && (flags & OEP_ADDRESS_OF) != 0
+	       && TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR
+	       && DECL_P (TREE_OPERAND (TREE_OPERAND (t, 0), 0))
+	       && integer_zerop (TREE_OPERAND (t, 1)))
+	hash_operand (TREE_OPERAND (TREE_OPERAND (t, 0), 0),
+		      hstate, flags);
+      /* Don't ICE on FE specific trees, or their arguments etc.
+	 during operand_equal_p hash verification.  */
+      else if (!IS_EXPR_CODE_CLASS (tclass))
+	gcc_assert (flags & OEP_HASH_CHECK);
+      else
+	{
+	  unsigned int sflags = flags;
+
+	  hstate.add_object (code);
+
+	  switch (code)
+	    {
+	    case ADDR_EXPR:
+	      gcc_checking_assert (!(flags & OEP_ADDRESS_OF));
+	      flags |= OEP_ADDRESS_OF;
+	      sflags = flags;
+	      break;
+
+	    case INDIRECT_REF:
+	    case MEM_REF:
+	    case TARGET_MEM_REF:
+	      flags &= ~OEP_ADDRESS_OF;
+	      sflags = flags;
+	      break;
+
+	    case ARRAY_REF:
+	    case ARRAY_RANGE_REF:
+	    case COMPONENT_REF:
+	    case BIT_FIELD_REF:
+	      sflags &= ~OEP_ADDRESS_OF;
+	      break;
+
+	    case COND_EXPR:
+	      flags &= ~OEP_ADDRESS_OF;
+	      break;
+
+	    case WIDEN_MULT_PLUS_EXPR:
+	    case WIDEN_MULT_MINUS_EXPR:
+	      {
+		/* The multiplication operands are commutative.  */
+		inchash::hash one, two;
+		hash_operand (TREE_OPERAND (t, 0), one, flags);
+		hash_operand (TREE_OPERAND (t, 1), two, flags);
+		hstate.add_commutative (one, two);
+		hash_operand (TREE_OPERAND (t, 2), two, flags);
+		return;
+	      }
+
+	    case CALL_EXPR:
+	      if (CALL_EXPR_FN (t) == NULL_TREE)
+		hstate.add_int (CALL_EXPR_IFN (t));
+	      break;
+
+	    case TARGET_EXPR:
+	      /* For TARGET_EXPR, just hash on the TARGET_EXPR_SLOT.
+		 Usually different TARGET_EXPRs just should use
+		 different temporaries in their slots.  */
+	      hash_operand (TARGET_EXPR_SLOT (t), hstate, flags);
+	      return;
+
+	    /* Virtual table call.  */
+	    case OBJ_TYPE_REF:
+	      inchash::add_expr (OBJ_TYPE_REF_EXPR (t), hstate, flags);
+	      if (virtual_method_call_p (t))
+		{
+		  inchash::add_expr (OBJ_TYPE_REF_TOKEN (t), hstate, flags);
+		  inchash::add_expr (OBJ_TYPE_REF_OBJECT (t), hstate, flags);
+		}
+	      return;
+	    default:
+	      break;
+	    }
+
+	  /* Don't hash the type, that can lead to having nodes which
+	     compare equal according to operand_equal_p, but which
+	     have different hash codes.  */
+	  if (code == NON_LVALUE_EXPR)
+	    {
+	      /* Make sure to include signness in the hash computation.  */
+	      hstate.add_int (TYPE_UNSIGNED (TREE_TYPE (t)));
+	      hash_operand (TREE_OPERAND (t, 0), hstate, flags);
+	    }
+
+	  else if (commutative_tree_code (code))
+	    {
+	      /* It's a commutative expression.  We want to hash it the same
+		 however it appears.  We do this by first hashing both operands
+		 and then rehashing based on the order of their independent
+		 hashes.  */
+	      inchash::hash one, two;
+	      hash_operand (TREE_OPERAND (t, 0), one, flags);
+	      hash_operand (TREE_OPERAND (t, 1), two, flags);
+	      hstate.add_commutative (one, two);
+	    }
+	  else
+	    for (i = TREE_OPERAND_LENGTH (t) - 1; i >= 0; --i)
+	      hash_operand (TREE_OPERAND (t, i), hstate,
+			    i == 0 ? flags : sflags);
+	}
+      return;
+    }
+}
+
+
+/* Valueizer is a virtual method that allows to introduce extra equalities
+   that are not directly visible from the operand.
+   N1 means values are known to be equal, 0 means values are known
+   to be different -1 means that operand_equal_p should
+   continue processing.  */
+
+int
+operand_compare::operand_equal_valueize (const_tree, const_tree, unsigned int)
+{
+  return -1;
+}
+
+/* Valueizer is a function that returns true when the function can
+   hash the ARG.  If so, hash value is added to H.  */
+bool
+operand_compare::hash_operand_valueize (const_tree, inchash::hash &,
+					unsigned int)
+{
+  return false;
+}
+
+static operand_compare default_compare_instance;
+
+/* Conveinece wrapper around operand_compare class because usually we do
+   not need to play with the valueizer.  */
+
+bool
+operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
+{
+  return default_compare_instance.operand_equal_p (arg0, arg1, flags);
+}
+
+namespace inchash
+{
+
+/* Generate a hash value for an expression.  This can be used iteratively
+   by passing a previous result as the HSTATE argument.
+
+   This function is intended to produce the same hash for expressions which
+   would compare equal using operand_equal_p.  */
+void
+add_expr (const_tree t, inchash::hash &hstate, unsigned int flags)
+{
+  default_compare_instance.hash_operand (t, hstate, flags);
+}
+
+}
 \f
 /* Similar to operand_equal_p, but see if ARG0 might be a variant of ARG1
    with a different signedness or a narrower precision.  */
diff --git a/gcc/fold-const.h b/gcc/fold-const.h
index 1519d77300e..9c963b9f994 100644
--- a/gcc/fold-const.h
+++ b/gcc/fold-const.h
@@ -83,7 +83,7 @@ extern bool fold_deferring_overflow_warnings_p (void);
 extern void fold_overflow_warning (const char*, enum warn_strict_overflow_code);
 extern enum tree_code fold_div_compare (enum tree_code, tree, tree,
 					tree *, tree *, bool *);
-extern bool operand_equal_p (const_tree, const_tree, unsigned int);
+extern bool operand_equal_p (const_tree, const_tree, unsigned int flags = 0);
 extern int multiple_of_p (tree, const_tree, const_tree);
 #define omit_one_operand(T1,T2,T3)\
    omit_one_operand_loc (UNKNOWN_LOCATION, T1, T2, T3)
@@ -211,4 +211,32 @@ extern tree fold_build_pointer_plus_hwi_loc (location_t loc, tree ptr, HOST_WIDE
 
 #define fold_build_pointer_plus_hwi(p,o) \
 	fold_build_pointer_plus_hwi_loc (UNKNOWN_LOCATION, p, o)
+
+
+/* Class used to compare gimple operands.  */
+
+class operand_compare
+{
+public:
+  /* Return true if two operands are equal.  The flags fields can be used
+     to specify OEP flags described above.  */
+  bool operand_equal_p (const_tree, const_tree, unsigned int flags = 0);
+
+  /* Generate a hash value for an expression.  This can be used iteratively
+     by passing a previous result as the HSTATE argument.  */
+  void hash_operand (const_tree, inchash::hash &, unsigned flags = 0);
+
+private:
+  /* Valueizer can be used to make non-trivial equalities for expressions
+     that do not look same in isolation.
+     1 means values are known to be equal, 0 means values are known to be
+     different -1 means that operand_equal_p should continue processing.  */
+  virtual int operand_equal_valueize (const_tree, const_tree, unsigned int);
+
+  /* Valueizer is a function that returns true when the function can
+     hash the ARG.  If so, hash value is added to H.  */
+  virtual bool hash_operand_valueize (const_tree arg, inchash::hash &h,
+				      unsigned int flags);
+};
+
 #endif // GCC_FOLD_CONST_H
diff --git a/gcc/tree.c b/gcc/tree.c
index 37e54b84089..1b36e918854 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -7760,292 +7760,6 @@ operation_no_trapping_overflow (tree type, enum tree_code code)
     }
 }
 
-namespace inchash
-{
-
-/* Generate a hash value for an expression.  This can be used iteratively
-   by passing a previous result as the HSTATE argument.
-
-   This function is intended to produce the same hash for expressions which
-   would compare equal using operand_equal_p.  */
-void
-add_expr (const_tree t, inchash::hash &hstate, unsigned int flags)
-{
-  int i;
-  enum tree_code code;
-  enum tree_code_class tclass;
-
-  if (t == NULL_TREE || t == error_mark_node)
-    {
-      hstate.merge_hash (0);
-      return;
-    }
-
-  STRIP_ANY_LOCATION_WRAPPER (t);
-
-  if (!(flags & OEP_ADDRESS_OF))
-    STRIP_NOPS (t);
-
-  code = TREE_CODE (t);
-
-  switch (code)
-    {
-    /* Alas, constants aren't shared, so we can't rely on pointer
-       identity.  */
-    case VOID_CST:
-      hstate.merge_hash (0);
-      return;
-    case INTEGER_CST:
-      gcc_checking_assert (!(flags & OEP_ADDRESS_OF));
-      for (i = 0; i < TREE_INT_CST_EXT_NUNITS (t); i++)
-	hstate.add_hwi (TREE_INT_CST_ELT (t, i));
-      return;
-    case REAL_CST:
-      {
-	unsigned int val2;
-	if (!HONOR_SIGNED_ZEROS (t) && real_zerop (t))
-	  val2 = rvc_zero;
-	else
-	  val2 = real_hash (TREE_REAL_CST_PTR (t));
-	hstate.merge_hash (val2);
-	return;
-      }
-    case FIXED_CST:
-      {
-	unsigned int val2 = fixed_hash (TREE_FIXED_CST_PTR (t));
-	hstate.merge_hash (val2);
-	return;
-      }
-    case STRING_CST:
-      hstate.add ((const void *) TREE_STRING_POINTER (t),
-		  TREE_STRING_LENGTH (t));
-      return;
-    case COMPLEX_CST:
-      inchash::add_expr (TREE_REALPART (t), hstate, flags);
-      inchash::add_expr (TREE_IMAGPART (t), hstate, flags);
-      return;
-    case VECTOR_CST:
-      {
-	hstate.add_int (VECTOR_CST_NPATTERNS (t));
-	hstate.add_int (VECTOR_CST_NELTS_PER_PATTERN (t));
-	unsigned int count = vector_cst_encoded_nelts (t);
-	for (unsigned int i = 0; i < count; ++i)
-	  inchash::add_expr (VECTOR_CST_ENCODED_ELT (t, i), hstate, flags);
-	return;
-      }
-    case SSA_NAME:
-      /* We can just compare by pointer.  */
-      hstate.add_hwi (SSA_NAME_VERSION (t));
-      return;
-    case PLACEHOLDER_EXPR:
-      /* The node itself doesn't matter.  */
-      return;
-    case BLOCK:
-    case OMP_CLAUSE:
-      /* Ignore.  */
-      return;
-    case TREE_LIST:
-      /* A list of expressions, for a CALL_EXPR or as the elements of a
-	 VECTOR_CST.  */
-      for (; t; t = TREE_CHAIN (t))
-	inchash::add_expr (TREE_VALUE (t), hstate, flags);
-      return;
-    case CONSTRUCTOR:
-      {
-	unsigned HOST_WIDE_INT idx;
-	tree field, value;
-	flags &= ~OEP_ADDRESS_OF;
-	FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), idx, field, value)
-	  {
-	    inchash::add_expr (field, hstate, flags);
-	    inchash::add_expr (value, hstate, flags);
-	  }
-	return;
-      }
-    case STATEMENT_LIST:
-      {
-	tree_stmt_iterator i;
-	for (i = tsi_start (CONST_CAST_TREE (t));
-	     !tsi_end_p (i); tsi_next (&i))
-	  inchash::add_expr (tsi_stmt (i), hstate, flags);
-	return;
-      }
-    case TREE_VEC:
-      for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
-	inchash::add_expr (TREE_VEC_ELT (t, i), hstate, flags);
-      return;
-    case IDENTIFIER_NODE:
-      hstate.add_object (IDENTIFIER_HASH_VALUE (t));
-      return;
-    case FIELD_DECL:
-      inchash::add_expr (DECL_FIELD_OFFSET (t), hstate, flags);
-      inchash::add_expr (DECL_FIELD_BIT_OFFSET (t), hstate, flags);
-      return;
-    case FUNCTION_DECL:
-      /* When referring to a built-in FUNCTION_DECL, use the __builtin__ form.
-	 Otherwise nodes that compare equal according to operand_equal_p might
-	 get different hash codes.  However, don't do this for machine specific
-	 or front end builtins, since the function code is overloaded in those
-	 cases.  */
-      if (DECL_BUILT_IN_CLASS (t) == BUILT_IN_NORMAL
-	  && builtin_decl_explicit_p (DECL_FUNCTION_CODE (t)))
-	{
-	  t = builtin_decl_explicit (DECL_FUNCTION_CODE (t));
-	  code = TREE_CODE (t);
-	}
-      /* FALL THROUGH */
-    default:
-      if (POLY_INT_CST_P (t))
-	{
-	  for (unsigned int i = 0; i < NUM_POLY_INT_COEFFS; ++i)
-	    hstate.add_wide_int (wi::to_wide (POLY_INT_CST_COEFF (t, i)));
-	  return;
-	}
-      tclass = TREE_CODE_CLASS (code);
-
-      if (tclass == tcc_declaration)
-	{
-	  /* DECL's have a unique ID */
-	  hstate.add_hwi (DECL_UID (t));
-	}
-      else if (tclass == tcc_comparison && !commutative_tree_code (code))
-	{
-	  /* For comparisons that can be swapped, use the lower
-	     tree code.  */
-	  enum tree_code ccode = swap_tree_comparison (code);
-	  if (code < ccode)
-	    ccode = code;
-	  hstate.add_object (ccode);
-	  inchash::add_expr (TREE_OPERAND (t, ccode != code), hstate, flags);
-	  inchash::add_expr (TREE_OPERAND (t, ccode == code), hstate, flags);
-	}
-      else if (CONVERT_EXPR_CODE_P (code))
-	{
-	  /* NOP_EXPR and CONVERT_EXPR are considered equal by
-	     operand_equal_p.  */
-	  enum tree_code ccode = NOP_EXPR;
-	  hstate.add_object (ccode);
-
-	  /* Don't hash the type, that can lead to having nodes which
-	     compare equal according to operand_equal_p, but which
-	     have different hash codes.  Make sure to include signedness
-	     in the hash computation.  */
-	  hstate.add_int (TYPE_UNSIGNED (TREE_TYPE (t)));
-	  inchash::add_expr (TREE_OPERAND (t, 0), hstate, flags);
-	}
-      /* For OEP_ADDRESS_OF, hash MEM_EXPR[&decl, 0] the same as decl.  */
-      else if (code == MEM_REF
-	       && (flags & OEP_ADDRESS_OF) != 0
-	       && TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR
-	       && DECL_P (TREE_OPERAND (TREE_OPERAND (t, 0), 0))
-	       && integer_zerop (TREE_OPERAND (t, 1)))
-	inchash::add_expr (TREE_OPERAND (TREE_OPERAND (t, 0), 0),
-			   hstate, flags);
-      /* Don't ICE on FE specific trees, or their arguments etc.
-	 during operand_equal_p hash verification.  */
-      else if (!IS_EXPR_CODE_CLASS (tclass))
-	gcc_assert (flags & OEP_HASH_CHECK);
-      else
-	{
-	  unsigned int sflags = flags;
-
-	  hstate.add_object (code);
-
-	  switch (code)
-	    {
-	    case ADDR_EXPR:
-	      gcc_checking_assert (!(flags & OEP_ADDRESS_OF));
-	      flags |= OEP_ADDRESS_OF;
-	      sflags = flags;
-	      break;
-
-	    case INDIRECT_REF:
-	    case MEM_REF:
-	    case TARGET_MEM_REF:
-	      flags &= ~OEP_ADDRESS_OF;
-	      sflags = flags;
-	      break;
-
-	    case ARRAY_REF:
-	    case ARRAY_RANGE_REF:
-	    case COMPONENT_REF:
-	    case BIT_FIELD_REF:
-	      sflags &= ~OEP_ADDRESS_OF;
-	      break;
-
-	    case COND_EXPR:
-	      flags &= ~OEP_ADDRESS_OF;
-	      break;
-
-	    case WIDEN_MULT_PLUS_EXPR:
-	    case WIDEN_MULT_MINUS_EXPR:
-	      {
-		/* The multiplication operands are commutative.  */
-		inchash::hash one, two;
-		inchash::add_expr (TREE_OPERAND (t, 0), one, flags);
-		inchash::add_expr (TREE_OPERAND (t, 1), two, flags);
-		hstate.add_commutative (one, two);
-		inchash::add_expr (TREE_OPERAND (t, 2), two, flags);
-		return;
-	      }
-
-	    case CALL_EXPR:
-	      if (CALL_EXPR_FN (t) == NULL_TREE)
-		hstate.add_int (CALL_EXPR_IFN (t));
-	      break;
-
-	    case TARGET_EXPR:
-	      /* For TARGET_EXPR, just hash on the TARGET_EXPR_SLOT.
-		 Usually different TARGET_EXPRs just should use
-		 different temporaries in their slots.  */
-	      inchash::add_expr (TARGET_EXPR_SLOT (t), hstate, flags);
-	      return;
-
-	    /* Virtual table call.  */
-	    case OBJ_TYPE_REF:
-	      inchash::add_expr (OBJ_TYPE_REF_EXPR (t), hstate, flags);
-	      if (virtual_method_call_p (t))
-		{
-		  inchash::add_expr (OBJ_TYPE_REF_TOKEN (t), hstate, flags);
-		  inchash::add_expr (OBJ_TYPE_REF_OBJECT (t), hstate, flags);
-		}
-	      return;
-	    default:
-	      break;
-	    }
-
-	  /* Don't hash the type, that can lead to having nodes which
-	     compare equal according to operand_equal_p, but which
-	     have different hash codes.  */
-	  if (code == NON_LVALUE_EXPR)
-	    {
-	      /* Make sure to include signness in the hash computation.  */
-	      hstate.add_int (TYPE_UNSIGNED (TREE_TYPE (t)));
-	      inchash::add_expr (TREE_OPERAND (t, 0), hstate, flags);
-	    }
-
-	  else if (commutative_tree_code (code))
-	    {
-	      /* It's a commutative expression.  We want to hash it the same
-		 however it appears.  We do this by first hashing both operands
-		 and then rehashing based on the order of their independent
-		 hashes.  */
-	      inchash::hash one, two;
-	      inchash::add_expr (TREE_OPERAND (t, 0), one, flags);
-	      inchash::add_expr (TREE_OPERAND (t, 1), two, flags);
-	      hstate.add_commutative (one, two);
-	    }
-	  else
-	    for (i = TREE_OPERAND_LENGTH (t) - 1; i >= 0; --i)
-	      inchash::add_expr (TREE_OPERAND (t, i), hstate,
-				 i == 0 ? flags : sflags);
-	}
-      return;
-    }
-}
-
-}
-
 /* Constructors for pointer, array and function types.
    (RECORD_TYPE, UNION_TYPE and ENUMERAL_TYPE nodes are
    constructed by language-dependent code, not here.)  */
-- 
2.21.0


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

* [PATCH 7/9] IPA ICF: remove dead code
  2019-08-06 15:44             ` [PATCH 0/9] IPA ICF overhaul Martin Liska
                                 ` (2 preceding siblings ...)
  2019-08-06 15:43               ` [PATCH 6/9] Integrate that for IPA ICF Martin Liska
@ 2019-08-06 15:43               ` Martin Liska
  2019-08-08 14:44                 ` Jeff Law
  2019-08-06 15:43               ` [PATCH 8/9] Remove comparison for polymorphic types Martin Liska
                                 ` (6 subsequent siblings)
  10 siblings, 1 reply; 59+ messages in thread
From: Martin Liska @ 2019-08-06 15:43 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 793 bytes --]


gcc/ChangeLog:

2019-07-24  Martin Liska  <mliska@suse.cz>

	* ipa-icf-gimple.c (func_checker::compare_ssa_name): Call
	compare_operand.
	(func_checker::compare_memory_operand): Remove.
	(func_checker::compare_cst_or_decl): Remove.
	(func_checker::operand_equal_valueize): Do not handle
	FIELD_DECL.
	(func_checker::compare_gimple_call): Call compare_operand.
	(func_checker::compare_gimple_assign): Likewise.
	* ipa-icf-gimple.h: Remove compare_cst_or_decl.
	* ipa-icf.c (sem_function::icf_handled_component_p): Remove.
	* ipa-icf.h (icf_handled_component_p): Remove.
---
 gcc/ipa-icf-gimple.c | 150 ++-----------------------------------------
 gcc/ipa-icf-gimple.h |   4 --
 gcc/ipa-icf.c        |  11 ----
 gcc/ipa-icf.h        |   3 -
 4 files changed, 6 insertions(+), 162 deletions(-)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0007-IPA-ICF-remove-dead-code.patch --]
[-- Type: text/x-patch; name="0007-IPA-ICF-remove-dead-code.patch", Size: 8023 bytes --]

diff --git a/gcc/ipa-icf-gimple.c b/gcc/ipa-icf-gimple.c
index 8448d387428..2d4c5d22534 100644
--- a/gcc/ipa-icf-gimple.c
+++ b/gcc/ipa-icf-gimple.c
@@ -111,13 +111,7 @@ func_checker::compare_ssa_name (tree t1, tree t2)
       tree b1 = SSA_NAME_VAR (t1);
       tree b2 = SSA_NAME_VAR (t2);
 
-      if (b1 == NULL && b2 == NULL)
-	return true;
-
-      if (b1 == NULL || b2 == NULL || TREE_CODE (b1) != TREE_CODE (b2))
-	return return_false ();
-
-      return compare_cst_or_decl (b1, b2);
+      return compare_operand (b1, b2);
     }
 
   return true;
@@ -247,86 +241,12 @@ func_checker::compatible_types_p (tree t1, tree t2)
   return true;
 }
 
-/* Function compare for equality given memory operands T1 and T2.  */
-
-bool
-func_checker::compare_memory_operand (tree t1, tree t2)
-{
-  if (!t1 && !t2)
-    return true;
-  else if (!t1 || !t2)
-    return false;
-
-  ao_ref r1, r2;
-  ao_ref_init (&r1, t1);
-  ao_ref_init (&r2, t2);
-
-  tree b1 = ao_ref_base (&r1);
-  tree b2 = ao_ref_base (&r2);
-
-  bool source_is_memop = DECL_P (b1) || INDIRECT_REF_P (b1)
-			 || TREE_CODE (b1) == MEM_REF
-			 || TREE_CODE (b1) == TARGET_MEM_REF;
-
-  bool target_is_memop = DECL_P (b2) || INDIRECT_REF_P (b2)
-			 || TREE_CODE (b2) == MEM_REF
-			 || TREE_CODE (b2) == TARGET_MEM_REF;
-
-  /* Compare alias sets for memory operands.  */
-  if (source_is_memop && target_is_memop)
-    {
-      if (TREE_THIS_VOLATILE (t1) != TREE_THIS_VOLATILE (t2))
-	return return_false_with_msg ("different operand volatility");
-
-      if (ao_ref_alias_set (&r1) != ao_ref_alias_set (&r2)
-	  || ao_ref_base_alias_set (&r1) != ao_ref_base_alias_set (&r2))
-	return return_false_with_msg ("ao alias sets are different");
-
-      /* We can't simply use get_object_alignment_1 on the full
-         reference as for accesses with variable indexes this reports
-	 too conservative alignment.  We also can't use the ao_ref_base
-	 base objects as ao_ref_base happily strips MEM_REFs around
-	 decls even though that may carry alignment info.  */
-      b1 = t1;
-      while (handled_component_p (b1))
-	b1 = TREE_OPERAND (b1, 0);
-      b2 = t2;
-      while (handled_component_p (b2))
-	b2 = TREE_OPERAND (b2, 0);
-      unsigned int align1, align2;
-      unsigned HOST_WIDE_INT tem;
-      get_object_alignment_1 (b1, &align1, &tem);
-      get_object_alignment_1 (b2, &align2, &tem);
-      if (align1 != align2)
-	return return_false_with_msg ("different access alignment");
-
-      /* Similarly we have to compare dependence info where equality
-         tells us we are safe (even some unequal values would be safe
-	 but then we have to maintain a map of bases and cliques).  */
-      unsigned short clique1 = 0, base1 = 0, clique2 = 0, base2 = 0;
-      if (TREE_CODE (b1) == MEM_REF)
-	{
-	  clique1 = MR_DEPENDENCE_CLIQUE (b1);
-	  base1 = MR_DEPENDENCE_BASE (b1);
-	}
-      if (TREE_CODE (b2) == MEM_REF)
-	{
-	  clique2 = MR_DEPENDENCE_CLIQUE (b2);
-	  base2 = MR_DEPENDENCE_BASE (b2);
-	}
-      if (clique1 != clique2 || base1 != base2)
-	return return_false_with_msg ("different dependence info");
-    }
-
-  return compare_operand (t1, t2);
-}
-
 /* Function compare for equality given trees T1 and T2 which
    can be either a constant or a declaration type.  */
 
 bool
-func_checker::hash_operand_valueize (const_tree arg, inchash::hash &hstate,
-				     unsigned int flags)
+func_checker::hash_operand_valueize (const_tree arg, inchash::hash &,
+				     unsigned int)
 {
   switch (TREE_CODE (arg))
     {
@@ -346,52 +266,6 @@ func_checker::hash_operand_valueize (const_tree arg, inchash::hash &hstate,
   return false;
 }
 
-bool
-func_checker::compare_cst_or_decl (tree t1, tree t2)
-{
-  bool ret;
-
-  switch (TREE_CODE (t1))
-    {
-    case INTEGER_CST:
-    case COMPLEX_CST:
-    case VECTOR_CST:
-    case STRING_CST:
-    case REAL_CST:
-      {
-	ret = compatible_types_p (TREE_TYPE (t1), TREE_TYPE (t2))
-	      && operand_equal_p (t1, t2, OEP_ONLY_CONST);
-	return return_with_debug (ret);
-      }
-    case FUNCTION_DECL:
-      /* All function decls are in the symbol table and known to match
-	 before we start comparing bodies.  */
-      return true;
-    case VAR_DECL:
-      return return_with_debug (compare_variable_decl (t1, t2));
-    case LABEL_DECL:
-      {
-	if (t1 == t2)
-	  return true;
-
-	int *bb1 = m_label_bb_map.get (t1);
-	int *bb2 = m_label_bb_map.get (t2);
-
-	/* Labels can point to another function (non-local GOTOs).  */
-	return return_with_debug (bb1 != NULL && bb2 != NULL && *bb1 == *bb2);
-      }
-    case PARM_DECL:
-    case RESULT_DECL:
-    case CONST_DECL:
-      {
-	ret = compare_decl (t1, t2);
-	return return_with_debug (ret);
-      }
-    default:
-      gcc_unreachable ();
-    }
-}
-
 int
 func_checker::operand_equal_valueize (const_tree ct1, const_tree ct2,
 				      unsigned int)
@@ -421,18 +295,6 @@ func_checker::operand_equal_valueize (const_tree ct1, const_tree ct2,
       return compare_decl (t1, t2);
     case SSA_NAME:
       return compare_ssa_name (t1, t2);
-    case FIELD_DECL:
-      {
-	tree offset1 = DECL_FIELD_OFFSET (t1);
-	tree offset2 = DECL_FIELD_OFFSET (t2);
-
-	tree bit_offset1 = DECL_FIELD_BIT_OFFSET (t1);
-	tree bit_offset2 = DECL_FIELD_BIT_OFFSET (t2);
-
-	bool ret = (compare_operand (offset1, offset2)
-		    && compare_operand (bit_offset1, bit_offset2));
-	return return_with_debug (ret);
-      }
     default:
       break;
     }
@@ -731,7 +593,7 @@ func_checker::compare_gimple_call (gcall *s1, gcall *s2)
       t1 = gimple_call_arg (s1, i);
       t2 = gimple_call_arg (s2, i);
 
-      if (!compare_memory_operand (t1, t2))
+      if (!compare_operand (t1, t2))
 	return return_false_with_msg ("memory operands are different");
     }
 
@@ -739,7 +601,7 @@ func_checker::compare_gimple_call (gcall *s1, gcall *s2)
   t1 = gimple_get_lhs (s1);
   t2 = gimple_get_lhs (s2);
 
-  return compare_memory_operand (t1, t2);
+  return compare_operand (t1, t2);
 }
 
 
@@ -770,7 +632,7 @@ func_checker::compare_gimple_assign (gimple *s1, gimple *s2)
       arg1 = gimple_op (s1, i);
       arg2 = gimple_op (s2, i);
 
-      if (!compare_memory_operand (arg1, arg2))
+      if (!compare_operand (arg1, arg2))
 	return return_false_with_msg ("memory operands are different");
     }
 
diff --git a/gcc/ipa-icf-gimple.h b/gcc/ipa-icf-gimple.h
index cb7d788e9ee..b760b0fdce3 100644
--- a/gcc/ipa-icf-gimple.h
+++ b/gcc/ipa-icf-gimple.h
@@ -197,10 +197,6 @@ public:
   /* Function compare for equality given memory operands T1 and T2.  */
   bool compare_memory_operand (tree t1, tree t2);
 
-  /* Function compare for equality given trees T1 and T2 which
-     can be either a constant or a declaration type.  */
-  bool compare_cst_or_decl (tree t1, tree t2);
-
   /* Function responsible for comparison of various operands T1 and T2.
      If these components, from functions FUNC1 and FUNC2, are equal, true
      is returned.  */
diff --git a/gcc/ipa-icf.c b/gcc/ipa-icf.c
index ce98eefe7f5..7cac480930b 100644
--- a/gcc/ipa-icf.c
+++ b/gcc/ipa-icf.c
@@ -1732,17 +1732,6 @@ sem_function::compare_phi_node (basic_block bb1, basic_block bb2)
   return true;
 }
 
-/* Returns true if tree T can be compared as a handled component.  */
-
-bool
-sem_function::icf_handled_component_p (tree t)
-{
-  tree_code tc = TREE_CODE (t);
-
-  return (handled_component_p (t)
-	  || tc == ADDR_EXPR || tc == MEM_REF || tc == OBJ_TYPE_REF);
-}
-
 /* Basic blocks dictionary BB_DICT returns true if SOURCE index BB
    corresponds to TARGET.  */
 
diff --git a/gcc/ipa-icf.h b/gcc/ipa-icf.h
index 2bf0f156ef6..0b99a612016 100644
--- a/gcc/ipa-icf.h
+++ b/gcc/ipa-icf.h
@@ -404,9 +404,6 @@ private:
   /* Processes function equality comparison.  */
   bool equals_private (sem_item *item);
 
-  /* Returns true if tree T can be compared as a handled component.  */
-  static bool icf_handled_component_p (tree t);
-
   /* Function checker stores binding between functions.   */
   ipa_icf_gimple::func_checker *m_checker;
 

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

* [PATCH 4/9] Strengthen alias_ptr_types_compatible_p in LTO mode.
  2019-08-06 15:44             ` [PATCH 0/9] IPA ICF overhaul Martin Liska
                                 ` (4 preceding siblings ...)
  2019-08-06 15:43               ` [PATCH 8/9] Remove comparison for polymorphic types Martin Liska
@ 2019-08-06 15:43               ` Martin Liska
  2019-08-07 12:05                 ` Richard Biener
  2019-08-06 15:43               ` [PATCH 2/9] operand_equal_p: add support for FIELD_DECL Martin Liska
                                 ` (4 subsequent siblings)
  10 siblings, 1 reply; 59+ messages in thread
From: Martin Liska @ 2019-08-06 15:43 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 223 bytes --]


gcc/ChangeLog:

2019-07-24  Martin Liska  <mliska@suse.cz>

	* alias.c (alias_ptr_types_compatible_p): Strengten
	type comparison in LTO mode.
---
 gcc/alias.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0004-Strengthen-alias_ptr_types_compatible_p-in-LTO-mode.patch --]
[-- Type: text/x-patch; name="0004-Strengthen-alias_ptr_types_compatible_p-in-LTO-mode.patch", Size: 551 bytes --]

diff --git a/gcc/alias.c b/gcc/alias.c
index 2755df72907..bae4ddaebaf 100644
--- a/gcc/alias.c
+++ b/gcc/alias.c
@@ -793,8 +793,11 @@ alias_ptr_types_compatible_p (tree t1, tree t2)
       || ref_all_alias_ptr_type_p (t2))
     return false;
 
-  return (TYPE_MAIN_VARIANT (TREE_TYPE (t1))
-	  == TYPE_MAIN_VARIANT (TREE_TYPE (t2)));
+  if (in_lto_p)
+    return get_alias_set (t1) == get_alias_set (t2);
+  else
+    return (TYPE_MAIN_VARIANT (TREE_TYPE (t1))
+	    == TYPE_MAIN_VARIANT (TREE_TYPE (t2)));
 }
 
 /* Create emptry alias set entry.  */

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

* [PATCH 8/9] Remove comparison for polymorphic types.
  2019-08-06 15:44             ` [PATCH 0/9] IPA ICF overhaul Martin Liska
                                 ` (3 preceding siblings ...)
  2019-08-06 15:43               ` [PATCH 7/9] IPA ICF: remove dead code Martin Liska
@ 2019-08-06 15:43               ` Martin Liska
  2019-08-06 15:43               ` [PATCH 4/9] Strengthen alias_ptr_types_compatible_p in LTO mode Martin Liska
                                 ` (5 subsequent siblings)
  10 siblings, 0 replies; 59+ messages in thread
From: Martin Liska @ 2019-08-06 15:43 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 498 bytes --]


gcc/ChangeLog:

2019-07-24  Martin Liska  <mliska@suse.cz>

	* ipa-icf-gimple.c (func_checker::func_checker): Do not
	initialize m_compare_polymorphic.
	(func_checker::compare_decl): Do not compare polymorphic types.
	* ipa-icf-gimple.h (m_compare_polymorphic): Remove.
	* ipa-icf.c (sem_function::equals_private): Do not call
	compare_polymorphic_p.
---
 gcc/ipa-icf-gimple.c | 18 ------------------
 gcc/ipa-icf-gimple.h |  4 ----
 gcc/ipa-icf.c        |  1 -
 3 files changed, 23 deletions(-)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0008-Remove-comparison-for-polymorphic-types.patch --]
[-- Type: text/x-patch; name="0008-Remove-comparison-for-polymorphic-types.patch", Size: 2875 bytes --]

diff --git a/gcc/ipa-icf-gimple.c b/gcc/ipa-icf-gimple.c
index 2d4c5d22534..375aadad412 100644
--- a/gcc/ipa-icf-gimple.c
+++ b/gcc/ipa-icf-gimple.c
@@ -51,14 +51,12 @@ namespace ipa_icf_gimple {
    of declarations that can be skipped.  */
 
 func_checker::func_checker (tree source_func_decl, tree target_func_decl,
-			    bool compare_polymorphic,
 			    bool ignore_labels,
 			    hash_set<symtab_node *> *ignored_source_nodes,
 			    hash_set<symtab_node *> *ignored_target_nodes)
   : m_source_func_decl (source_func_decl), m_target_func_decl (target_func_decl),
     m_ignored_source_nodes (ignored_source_nodes),
     m_ignored_target_nodes (ignored_target_nodes),
-    m_compare_polymorphic (compare_polymorphic),
     m_ignore_labels (ignore_labels)
 {
   function *source_func = DECL_STRUCT_FUNCTION (source_func_decl);
@@ -156,23 +154,7 @@ func_checker::compare_decl (tree t1, tree t2)
   if (!compatible_types_p (TREE_TYPE (t1), TREE_TYPE (t2)))
     return return_false ();
 
-  /* TODO: we are actually too strict here.  We only need to compare if
-     T1 can be used in polymorphic call.  */
-  if (TREE_ADDRESSABLE (t1)
-      && m_compare_polymorphic
-      && !compatible_polymorphic_types_p (TREE_TYPE (t1), TREE_TYPE (t2),
-					  false))
-    return return_false ();
-
-  if ((t == VAR_DECL || t == PARM_DECL || t == RESULT_DECL)
-      && DECL_BY_REFERENCE (t1)
-      && m_compare_polymorphic
-      && !compatible_polymorphic_types_p (TREE_TYPE (t1), TREE_TYPE (t2),
-					  true))
-    return return_false ();
-
   bool existed_p;
-
   tree &slot = m_decl_map.get_or_insert (t1, &existed_p);
   if (existed_p)
     return return_with_debug (slot == t2);
diff --git a/gcc/ipa-icf-gimple.h b/gcc/ipa-icf-gimple.h
index b760b0fdce3..75f2f24ff4a 100644
--- a/gcc/ipa-icf-gimple.h
+++ b/gcc/ipa-icf-gimple.h
@@ -128,7 +128,6 @@ public:
      Similarly, IGNORE_SOURCE_DECLS and IGNORE_TARGET_DECLS are sets
      of declarations that can be skipped.  */
   func_checker (tree source_func_decl, tree target_func_decl,
-		bool compare_polymorphic,
 		bool ignore_labels = false,
 		hash_set<symtab_node *> *ignored_source_nodes = NULL,
 		hash_set<symtab_node *> *ignored_target_nodes = NULL);
@@ -258,9 +257,6 @@ private:
   /* Label to basic block index mapping.  */
   hash_map <tree, int> m_label_bb_map;
 
-  /* Flag if polymorphic comparison should be executed.  */
-  bool m_compare_polymorphic;
-
   /* Flag if ignore labels in comparison.  */
   bool m_ignore_labels;
 
diff --git a/gcc/ipa-icf.c b/gcc/ipa-icf.c
index 7cac480930b..f6400d48e27 100644
--- a/gcc/ipa-icf.c
+++ b/gcc/ipa-icf.c
@@ -845,7 +845,6 @@ sem_function::equals_private (sem_item *item)
     return return_false ();
 
   m_checker = new func_checker (decl, m_compared_func->decl,
-				compare_polymorphic_p (),
 				false,
 				&refs_set,
 				&m_compared_func->refs_set);

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

* [PATCH 5/9] Come up with an abstraction.
  2019-08-06 15:44             ` [PATCH 0/9] IPA ICF overhaul Martin Liska
  2019-08-06 15:43               ` [PATCH 9/9] Remove alias set comparison Martin Liska
@ 2019-08-06 15:43               ` Martin Liska
  2019-08-08 16:29                 ` Michael Matz
  2019-08-09 11:48                 ` Richard Biener
  2019-08-06 15:43               ` [PATCH 6/9] Integrate that for IPA ICF Martin Liska
                                 ` (8 subsequent siblings)
  10 siblings, 2 replies; 59+ messages in thread
From: Martin Liska @ 2019-08-06 15:43 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 716 bytes --]


gcc/ChangeLog:

2019-07-24  Martin Liska  <mliska@suse.cz>

	* fold-const.c (operand_equal_p): Rename to ...
	(operand_compare::operand_equal_p): ... this.
	(add_expr):  Rename to ...
	(operand_compare::hash_operand): ... this.
	(operand_compare::operand_equal_valueize): Likewise.
	(operand_compare::hash_operand_valueize): Likewise.
	* fold-const.h (operand_equal_p): Set default
	value for last argument.
	(class operand_compare): New.
	* tree.c (add_expr): Move content to hash_operand.
---
 gcc/fold-const.c | 346 ++++++++++++++++++++++++++++++++++++++++++++++-
 gcc/fold-const.h |  30 +++-
 gcc/tree.c       | 286 ---------------------------------------
 3 files changed, 372 insertions(+), 290 deletions(-)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0005-Come-up-with-an-abstraction.patch --]
[-- Type: text/x-patch; name="0005-Come-up-with-an-abstraction.patch", Size: 22964 bytes --]

diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 4bcde22ada7..087c450cace 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -2940,7 +2940,8 @@ combine_comparisons (location_t loc,
    even if var is volatile.  */
 
 bool
-operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
+operand_compare::operand_equal_p (const_tree arg0, const_tree arg1,
+				  unsigned int flags)
 {
   /* When checking, verify at the outermost operand_equal_p call that
      if operand_equal_p returns non-zero then ARG0 and ARG1 has the same
@@ -2952,8 +2953,8 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 	  if (arg0 != arg1)
 	    {
 	      inchash::hash hstate0 (0), hstate1 (0);
-	      inchash::add_expr (arg0, hstate0, flags | OEP_HASH_CHECK);
-	      inchash::add_expr (arg1, hstate1, flags | OEP_HASH_CHECK);
+	      hash_operand (arg0, hstate0, flags | OEP_HASH_CHECK);
+	      hash_operand (arg1, hstate1, flags | OEP_HASH_CHECK);
 	      hashval_t h0 = hstate0.end ();
 	      hashval_t h1 = hstate1.end ();
 	      gcc_assert (h0 == h1);
@@ -3094,6 +3095,12 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 	  || (! TREE_SIDE_EFFECTS (arg0) && ! TREE_SIDE_EFFECTS (arg1))))
     return true;
 
+  int val = operand_equal_valueize (arg0, arg1, flags);
+  if (val == 1)
+    return 1;
+  if (val == 0)
+    return 0;
+
   /* Next handle constant cases, those for which we can return 1 even
      if ONLY_CONST is set.  */
   if (TREE_CONSTANT (arg0) && TREE_CONSTANT (arg1))
@@ -3605,6 +3612,339 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 
 #undef OP_SAME
 #undef OP_SAME_WITH_NULL
+}
+
+/* Generate a hash value for an expression.  This can be used iteratively
+   by passing a previous result as the HSTATE argument.  */
+
+void
+operand_compare::hash_operand (const_tree t, inchash::hash &hstate,
+			       unsigned int flags)
+{
+  int i;
+  enum tree_code code;
+  enum tree_code_class tclass;
+
+  if (t == NULL_TREE || t == error_mark_node)
+    {
+      hstate.merge_hash (0);
+      return;
+    }
+
+  STRIP_ANY_LOCATION_WRAPPER (t);
+
+  if (!(flags & OEP_ADDRESS_OF))
+    STRIP_NOPS (t);
+
+  code = TREE_CODE (t);
+
+  bool ret = hash_operand_valueize (t, hstate, flags);
+  if (ret)
+    return;
+
+  switch (code)
+    {
+    /* Alas, constants aren't shared, so we can't rely on pointer
+       identity.  */
+    case VOID_CST:
+      hstate.merge_hash (0);
+      return;
+    case INTEGER_CST:
+      gcc_checking_assert (!(flags & OEP_ADDRESS_OF));
+      for (i = 0; i < TREE_INT_CST_EXT_NUNITS (t); i++)
+	hstate.add_hwi (TREE_INT_CST_ELT (t, i));
+      return;
+    case REAL_CST:
+      {
+	unsigned int val2;
+	if (!HONOR_SIGNED_ZEROS (t) && real_zerop (t))
+	  val2 = rvc_zero;
+	else
+	  val2 = real_hash (TREE_REAL_CST_PTR (t));
+	hstate.merge_hash (val2);
+	return;
+      }
+    case FIXED_CST:
+      {
+	unsigned int val2 = fixed_hash (TREE_FIXED_CST_PTR (t));
+	hstate.merge_hash (val2);
+	return;
+      }
+    case STRING_CST:
+      hstate.add ((const void *) TREE_STRING_POINTER (t),
+		  TREE_STRING_LENGTH (t));
+      return;
+    case COMPLEX_CST:
+      hash_operand (TREE_REALPART (t), hstate, flags);
+      hash_operand (TREE_IMAGPART (t), hstate, flags);
+      return;
+    case VECTOR_CST:
+      {
+	hstate.add_int (VECTOR_CST_NPATTERNS (t));
+	hstate.add_int (VECTOR_CST_NELTS_PER_PATTERN (t));
+	unsigned int count = vector_cst_encoded_nelts (t);
+	for (unsigned int i = 0; i < count; ++i)
+	  hash_operand (VECTOR_CST_ENCODED_ELT (t, i), hstate, flags);
+	return;
+      }
+    case SSA_NAME:
+      /* We can just compare by pointer.  */
+      hstate.add_hwi (SSA_NAME_VERSION (t));
+      return;
+    case PLACEHOLDER_EXPR:
+      /* The node itself doesn't matter.  */
+      return;
+    case BLOCK:
+    case OMP_CLAUSE:
+      /* Ignore.  */
+      return;
+    case TREE_LIST:
+      /* A list of expressions, for a CALL_EXPR or as the elements of a
+	 VECTOR_CST.  */
+      for (; t; t = TREE_CHAIN (t))
+	hash_operand (TREE_VALUE (t), hstate, flags);
+      return;
+    case CONSTRUCTOR:
+      {
+	unsigned HOST_WIDE_INT idx;
+	tree field, value;
+	flags &= ~OEP_ADDRESS_OF;
+	FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), idx, field, value)
+	  {
+	    hash_operand (field, hstate, flags);
+	    hash_operand (value, hstate, flags);
+	  }
+	return;
+      }
+    case STATEMENT_LIST:
+      {
+	tree_stmt_iterator i;
+	for (i = tsi_start (CONST_CAST_TREE (t));
+	     !tsi_end_p (i); tsi_next (&i))
+	  hash_operand (tsi_stmt (i), hstate, flags);
+	return;
+      }
+    case TREE_VEC:
+      for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
+	hash_operand (TREE_VEC_ELT (t, i), hstate, flags);
+      return;
+    case IDENTIFIER_NODE:
+      hstate.add_object (IDENTIFIER_HASH_VALUE (t));
+      return;
+    case FIELD_DECL:
+      inchash::add_expr (DECL_FIELD_OFFSET (t), hstate, flags);
+      inchash::add_expr (DECL_FIELD_BIT_OFFSET (t), hstate, flags);
+      return;
+    case FUNCTION_DECL:
+      /* When referring to a built-in FUNCTION_DECL, use the __builtin__ form.
+	 Otherwise nodes that compare equal according to operand_equal_p might
+	 get different hash codes.  However, don't do this for machine specific
+	 or front end builtins, since the function code is overloaded in those
+	 cases.  */
+      if (DECL_BUILT_IN_CLASS (t) == BUILT_IN_NORMAL
+	  && builtin_decl_explicit_p (DECL_FUNCTION_CODE (t)))
+	{
+	  t = builtin_decl_explicit (DECL_FUNCTION_CODE (t));
+	  code = TREE_CODE (t);
+	}
+      /* FALL THROUGH */
+    default:
+      if (POLY_INT_CST_P (t))
+	{
+	  for (unsigned int i = 0; i < NUM_POLY_INT_COEFFS; ++i)
+	    hstate.add_wide_int (wi::to_wide (POLY_INT_CST_COEFF (t, i)));
+	  return;
+	}
+      tclass = TREE_CODE_CLASS (code);
+
+      if (tclass == tcc_declaration)
+	{
+	  /* DECL's have a unique ID */
+	  hstate.add_hwi (DECL_UID (t));
+	}
+      else if (tclass == tcc_comparison && !commutative_tree_code (code))
+	{
+	  /* For comparisons that can be swapped, use the lower
+	     tree code.  */
+	  enum tree_code ccode = swap_tree_comparison (code);
+	  if (code < ccode)
+	    ccode = code;
+	  hstate.add_object (ccode);
+	  hash_operand (TREE_OPERAND (t, ccode != code), hstate, flags);
+	  hash_operand (TREE_OPERAND (t, ccode == code), hstate, flags);
+	}
+      else if (CONVERT_EXPR_CODE_P (code))
+	{
+	  /* NOP_EXPR and CONVERT_EXPR are considered equal by
+	     operand_equal_p.  */
+	  enum tree_code ccode = NOP_EXPR;
+	  hstate.add_object (ccode);
+
+	  /* Don't hash the type, that can lead to having nodes which
+	     compare equal according to operand_equal_p, but which
+	     have different hash codes.  Make sure to include signedness
+	     in the hash computation.  */
+	  hstate.add_int (TYPE_UNSIGNED (TREE_TYPE (t)));
+	  hash_operand (TREE_OPERAND (t, 0), hstate, flags);
+	}
+      /* For OEP_ADDRESS_OF, hash MEM_EXPR[&decl, 0] the same as decl.  */
+      else if (code == MEM_REF
+	       && (flags & OEP_ADDRESS_OF) != 0
+	       && TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR
+	       && DECL_P (TREE_OPERAND (TREE_OPERAND (t, 0), 0))
+	       && integer_zerop (TREE_OPERAND (t, 1)))
+	hash_operand (TREE_OPERAND (TREE_OPERAND (t, 0), 0),
+		      hstate, flags);
+      /* Don't ICE on FE specific trees, or their arguments etc.
+	 during operand_equal_p hash verification.  */
+      else if (!IS_EXPR_CODE_CLASS (tclass))
+	gcc_assert (flags & OEP_HASH_CHECK);
+      else
+	{
+	  unsigned int sflags = flags;
+
+	  hstate.add_object (code);
+
+	  switch (code)
+	    {
+	    case ADDR_EXPR:
+	      gcc_checking_assert (!(flags & OEP_ADDRESS_OF));
+	      flags |= OEP_ADDRESS_OF;
+	      sflags = flags;
+	      break;
+
+	    case INDIRECT_REF:
+	    case MEM_REF:
+	    case TARGET_MEM_REF:
+	      flags &= ~OEP_ADDRESS_OF;
+	      sflags = flags;
+	      break;
+
+	    case ARRAY_REF:
+	    case ARRAY_RANGE_REF:
+	    case COMPONENT_REF:
+	    case BIT_FIELD_REF:
+	      sflags &= ~OEP_ADDRESS_OF;
+	      break;
+
+	    case COND_EXPR:
+	      flags &= ~OEP_ADDRESS_OF;
+	      break;
+
+	    case WIDEN_MULT_PLUS_EXPR:
+	    case WIDEN_MULT_MINUS_EXPR:
+	      {
+		/* The multiplication operands are commutative.  */
+		inchash::hash one, two;
+		hash_operand (TREE_OPERAND (t, 0), one, flags);
+		hash_operand (TREE_OPERAND (t, 1), two, flags);
+		hstate.add_commutative (one, two);
+		hash_operand (TREE_OPERAND (t, 2), two, flags);
+		return;
+	      }
+
+	    case CALL_EXPR:
+	      if (CALL_EXPR_FN (t) == NULL_TREE)
+		hstate.add_int (CALL_EXPR_IFN (t));
+	      break;
+
+	    case TARGET_EXPR:
+	      /* For TARGET_EXPR, just hash on the TARGET_EXPR_SLOT.
+		 Usually different TARGET_EXPRs just should use
+		 different temporaries in their slots.  */
+	      hash_operand (TARGET_EXPR_SLOT (t), hstate, flags);
+	      return;
+
+	    /* Virtual table call.  */
+	    case OBJ_TYPE_REF:
+	      inchash::add_expr (OBJ_TYPE_REF_EXPR (t), hstate, flags);
+	      if (virtual_method_call_p (t))
+		{
+		  inchash::add_expr (OBJ_TYPE_REF_TOKEN (t), hstate, flags);
+		  inchash::add_expr (OBJ_TYPE_REF_OBJECT (t), hstate, flags);
+		}
+	      return;
+	    default:
+	      break;
+	    }
+
+	  /* Don't hash the type, that can lead to having nodes which
+	     compare equal according to operand_equal_p, but which
+	     have different hash codes.  */
+	  if (code == NON_LVALUE_EXPR)
+	    {
+	      /* Make sure to include signness in the hash computation.  */
+	      hstate.add_int (TYPE_UNSIGNED (TREE_TYPE (t)));
+	      hash_operand (TREE_OPERAND (t, 0), hstate, flags);
+	    }
+
+	  else if (commutative_tree_code (code))
+	    {
+	      /* It's a commutative expression.  We want to hash it the same
+		 however it appears.  We do this by first hashing both operands
+		 and then rehashing based on the order of their independent
+		 hashes.  */
+	      inchash::hash one, two;
+	      hash_operand (TREE_OPERAND (t, 0), one, flags);
+	      hash_operand (TREE_OPERAND (t, 1), two, flags);
+	      hstate.add_commutative (one, two);
+	    }
+	  else
+	    for (i = TREE_OPERAND_LENGTH (t) - 1; i >= 0; --i)
+	      hash_operand (TREE_OPERAND (t, i), hstate,
+			    i == 0 ? flags : sflags);
+	}
+      return;
+    }
+}
+
+
+/* Valueizer is a virtual method that allows to introduce extra equalities
+   that are not directly visible from the operand.
+   N1 means values are known to be equal, 0 means values are known
+   to be different -1 means that operand_equal_p should
+   continue processing.  */
+
+int
+operand_compare::operand_equal_valueize (const_tree, const_tree, unsigned int)
+{
+  return -1;
+}
+
+/* Valueizer is a function that returns true when the function can
+   hash the ARG.  If so, hash value is added to H.  */
+bool
+operand_compare::hash_operand_valueize (const_tree, inchash::hash &,
+					unsigned int)
+{
+  return false;
+}
+
+static operand_compare default_compare_instance;
+
+/* Conveinece wrapper around operand_compare class because usually we do
+   not need to play with the valueizer.  */
+
+bool
+operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
+{
+  return default_compare_instance.operand_equal_p (arg0, arg1, flags);
+}
+
+namespace inchash
+{
+
+/* Generate a hash value for an expression.  This can be used iteratively
+   by passing a previous result as the HSTATE argument.
+
+   This function is intended to produce the same hash for expressions which
+   would compare equal using operand_equal_p.  */
+void
+add_expr (const_tree t, inchash::hash &hstate, unsigned int flags)
+{
+  default_compare_instance.hash_operand (t, hstate, flags);
+}
+
 }
 \f
 /* Similar to operand_equal_p, but see if ARG0 might be a variant of ARG1
diff --git a/gcc/fold-const.h b/gcc/fold-const.h
index 54c850a3ee1..e634975d382 100644
--- a/gcc/fold-const.h
+++ b/gcc/fold-const.h
@@ -84,7 +84,7 @@ extern bool fold_deferring_overflow_warnings_p (void);
 extern void fold_overflow_warning (const char*, enum warn_strict_overflow_code);
 extern enum tree_code fold_div_compare (enum tree_code, tree, tree,
 					tree *, tree *, bool *);
-extern bool operand_equal_p (const_tree, const_tree, unsigned int);
+extern bool operand_equal_p (const_tree, const_tree, unsigned int flags = 0);
 extern int multiple_of_p (tree, const_tree, const_tree);
 #define omit_one_operand(T1,T2,T3)\
    omit_one_operand_loc (UNKNOWN_LOCATION, T1, T2, T3)
@@ -212,4 +212,32 @@ extern tree fold_build_pointer_plus_hwi_loc (location_t loc, tree ptr, HOST_WIDE
 
 #define fold_build_pointer_plus_hwi(p,o) \
 	fold_build_pointer_plus_hwi_loc (UNKNOWN_LOCATION, p, o)
+
+
+/* Class used to compare gimple operands.  */
+
+class operand_compare
+{
+public:
+  /* Return true if two operands are equal.  The flags fields can be used
+     to specify OEP flags described above.  */
+  bool operand_equal_p (const_tree, const_tree, unsigned int flags = 0);
+
+  /* Generate a hash value for an expression.  This can be used iteratively
+     by passing a previous result as the HSTATE argument.  */
+  void hash_operand (const_tree, inchash::hash &, unsigned flags = 0);
+
+private:
+  /* Valueizer can be used to make non-trivial equalities for expressions
+     that do not look same in isolation.
+     1 means values are known to be equal, 0 means values are known to be
+     different -1 means that operand_equal_p should continue processing.  */
+  virtual int operand_equal_valueize (const_tree, const_tree, unsigned int);
+
+  /* Valueizer is a function that returns true when the function can
+     hash the ARG.  If so, hash value is added to H.  */
+  virtual bool hash_operand_valueize (const_tree arg, inchash::hash &h,
+				      unsigned int flags);
+};
+
 #endif // GCC_FOLD_CONST_H
diff --git a/gcc/tree.c b/gcc/tree.c
index 2207f644fed..86cb66d612e 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -7770,292 +7770,6 @@ operation_no_trapping_overflow (tree type, enum tree_code code)
     }
 }
 
-namespace inchash
-{
-
-/* Generate a hash value for an expression.  This can be used iteratively
-   by passing a previous result as the HSTATE argument.
-
-   This function is intended to produce the same hash for expressions which
-   would compare equal using operand_equal_p.  */
-void
-add_expr (const_tree t, inchash::hash &hstate, unsigned int flags)
-{
-  int i;
-  enum tree_code code;
-  enum tree_code_class tclass;
-
-  if (t == NULL_TREE || t == error_mark_node)
-    {
-      hstate.merge_hash (0);
-      return;
-    }
-
-  STRIP_ANY_LOCATION_WRAPPER (t);
-
-  if (!(flags & OEP_ADDRESS_OF))
-    STRIP_NOPS (t);
-
-  code = TREE_CODE (t);
-
-  switch (code)
-    {
-    /* Alas, constants aren't shared, so we can't rely on pointer
-       identity.  */
-    case VOID_CST:
-      hstate.merge_hash (0);
-      return;
-    case INTEGER_CST:
-      gcc_checking_assert (!(flags & OEP_ADDRESS_OF));
-      for (i = 0; i < TREE_INT_CST_EXT_NUNITS (t); i++)
-	hstate.add_hwi (TREE_INT_CST_ELT (t, i));
-      return;
-    case REAL_CST:
-      {
-	unsigned int val2;
-	if (!HONOR_SIGNED_ZEROS (t) && real_zerop (t))
-	  val2 = rvc_zero;
-	else
-	  val2 = real_hash (TREE_REAL_CST_PTR (t));
-	hstate.merge_hash (val2);
-	return;
-      }
-    case FIXED_CST:
-      {
-	unsigned int val2 = fixed_hash (TREE_FIXED_CST_PTR (t));
-	hstate.merge_hash (val2);
-	return;
-      }
-    case STRING_CST:
-      hstate.add ((const void *) TREE_STRING_POINTER (t),
-		  TREE_STRING_LENGTH (t));
-      return;
-    case COMPLEX_CST:
-      inchash::add_expr (TREE_REALPART (t), hstate, flags);
-      inchash::add_expr (TREE_IMAGPART (t), hstate, flags);
-      return;
-    case VECTOR_CST:
-      {
-	hstate.add_int (VECTOR_CST_NPATTERNS (t));
-	hstate.add_int (VECTOR_CST_NELTS_PER_PATTERN (t));
-	unsigned int count = vector_cst_encoded_nelts (t);
-	for (unsigned int i = 0; i < count; ++i)
-	  inchash::add_expr (VECTOR_CST_ENCODED_ELT (t, i), hstate, flags);
-	return;
-      }
-    case SSA_NAME:
-      /* We can just compare by pointer.  */
-      hstate.add_hwi (SSA_NAME_VERSION (t));
-      return;
-    case PLACEHOLDER_EXPR:
-      /* The node itself doesn't matter.  */
-      return;
-    case BLOCK:
-    case OMP_CLAUSE:
-      /* Ignore.  */
-      return;
-    case TREE_LIST:
-      /* A list of expressions, for a CALL_EXPR or as the elements of a
-	 VECTOR_CST.  */
-      for (; t; t = TREE_CHAIN (t))
-	inchash::add_expr (TREE_VALUE (t), hstate, flags);
-      return;
-    case CONSTRUCTOR:
-      {
-	unsigned HOST_WIDE_INT idx;
-	tree field, value;
-	flags &= ~OEP_ADDRESS_OF;
-	FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), idx, field, value)
-	  {
-	    inchash::add_expr (field, hstate, flags);
-	    inchash::add_expr (value, hstate, flags);
-	  }
-	return;
-      }
-    case STATEMENT_LIST:
-      {
-	tree_stmt_iterator i;
-	for (i = tsi_start (CONST_CAST_TREE (t));
-	     !tsi_end_p (i); tsi_next (&i))
-	  inchash::add_expr (tsi_stmt (i), hstate, flags);
-	return;
-      }
-    case TREE_VEC:
-      for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
-	inchash::add_expr (TREE_VEC_ELT (t, i), hstate, flags);
-      return;
-    case IDENTIFIER_NODE:
-      hstate.add_object (IDENTIFIER_HASH_VALUE (t));
-      return;
-    case FIELD_DECL:
-      inchash::add_expr (DECL_FIELD_OFFSET (t), hstate, flags);
-      inchash::add_expr (DECL_FIELD_BIT_OFFSET (t), hstate, flags);
-      return;
-    case FUNCTION_DECL:
-      /* When referring to a built-in FUNCTION_DECL, use the __builtin__ form.
-	 Otherwise nodes that compare equal according to operand_equal_p might
-	 get different hash codes.  However, don't do this for machine specific
-	 or front end builtins, since the function code is overloaded in those
-	 cases.  */
-      if (DECL_BUILT_IN_CLASS (t) == BUILT_IN_NORMAL
-	  && builtin_decl_explicit_p (DECL_FUNCTION_CODE (t)))
-	{
-	  t = builtin_decl_explicit (DECL_FUNCTION_CODE (t));
-	  code = TREE_CODE (t);
-	}
-      /* FALL THROUGH */
-    default:
-      if (POLY_INT_CST_P (t))
-	{
-	  for (unsigned int i = 0; i < NUM_POLY_INT_COEFFS; ++i)
-	    hstate.add_wide_int (wi::to_wide (POLY_INT_CST_COEFF (t, i)));
-	  return;
-	}
-      tclass = TREE_CODE_CLASS (code);
-
-      if (tclass == tcc_declaration)
-	{
-	  /* DECL's have a unique ID */
-	  hstate.add_hwi (DECL_UID (t));
-	}
-      else if (tclass == tcc_comparison && !commutative_tree_code (code))
-	{
-	  /* For comparisons that can be swapped, use the lower
-	     tree code.  */
-	  enum tree_code ccode = swap_tree_comparison (code);
-	  if (code < ccode)
-	    ccode = code;
-	  hstate.add_object (ccode);
-	  inchash::add_expr (TREE_OPERAND (t, ccode != code), hstate, flags);
-	  inchash::add_expr (TREE_OPERAND (t, ccode == code), hstate, flags);
-	}
-      else if (CONVERT_EXPR_CODE_P (code))
-	{
-	  /* NOP_EXPR and CONVERT_EXPR are considered equal by
-	     operand_equal_p.  */
-	  enum tree_code ccode = NOP_EXPR;
-	  hstate.add_object (ccode);
-
-	  /* Don't hash the type, that can lead to having nodes which
-	     compare equal according to operand_equal_p, but which
-	     have different hash codes.  Make sure to include signedness
-	     in the hash computation.  */
-	  hstate.add_int (TYPE_UNSIGNED (TREE_TYPE (t)));
-	  inchash::add_expr (TREE_OPERAND (t, 0), hstate, flags);
-	}
-      /* For OEP_ADDRESS_OF, hash MEM_EXPR[&decl, 0] the same as decl.  */
-      else if (code == MEM_REF
-	       && (flags & OEP_ADDRESS_OF) != 0
-	       && TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR
-	       && DECL_P (TREE_OPERAND (TREE_OPERAND (t, 0), 0))
-	       && integer_zerop (TREE_OPERAND (t, 1)))
-	inchash::add_expr (TREE_OPERAND (TREE_OPERAND (t, 0), 0),
-			   hstate, flags);
-      /* Don't ICE on FE specific trees, or their arguments etc.
-	 during operand_equal_p hash verification.  */
-      else if (!IS_EXPR_CODE_CLASS (tclass))
-	gcc_assert (flags & OEP_HASH_CHECK);
-      else
-	{
-	  unsigned int sflags = flags;
-
-	  hstate.add_object (code);
-
-	  switch (code)
-	    {
-	    case ADDR_EXPR:
-	      gcc_checking_assert (!(flags & OEP_ADDRESS_OF));
-	      flags |= OEP_ADDRESS_OF;
-	      sflags = flags;
-	      break;
-
-	    case INDIRECT_REF:
-	    case MEM_REF:
-	    case TARGET_MEM_REF:
-	      flags &= ~OEP_ADDRESS_OF;
-	      sflags = flags;
-	      break;
-
-	    case ARRAY_REF:
-	    case ARRAY_RANGE_REF:
-	    case COMPONENT_REF:
-	    case BIT_FIELD_REF:
-	      sflags &= ~OEP_ADDRESS_OF;
-	      break;
-
-	    case COND_EXPR:
-	      flags &= ~OEP_ADDRESS_OF;
-	      break;
-
-	    case WIDEN_MULT_PLUS_EXPR:
-	    case WIDEN_MULT_MINUS_EXPR:
-	      {
-		/* The multiplication operands are commutative.  */
-		inchash::hash one, two;
-		inchash::add_expr (TREE_OPERAND (t, 0), one, flags);
-		inchash::add_expr (TREE_OPERAND (t, 1), two, flags);
-		hstate.add_commutative (one, two);
-		inchash::add_expr (TREE_OPERAND (t, 2), two, flags);
-		return;
-	      }
-
-	    case CALL_EXPR:
-	      if (CALL_EXPR_FN (t) == NULL_TREE)
-		hstate.add_int (CALL_EXPR_IFN (t));
-	      break;
-
-	    case TARGET_EXPR:
-	      /* For TARGET_EXPR, just hash on the TARGET_EXPR_SLOT.
-		 Usually different TARGET_EXPRs just should use
-		 different temporaries in their slots.  */
-	      inchash::add_expr (TARGET_EXPR_SLOT (t), hstate, flags);
-	      return;
-
-	    /* Virtual table call.  */
-	    case OBJ_TYPE_REF:
-	      inchash::add_expr (OBJ_TYPE_REF_EXPR (t), hstate, flags);
-	      if (virtual_method_call_p (t))
-		{
-		  inchash::add_expr (OBJ_TYPE_REF_TOKEN (t), hstate, flags);
-		  inchash::add_expr (OBJ_TYPE_REF_OBJECT (t), hstate, flags);
-		}
-	      return;
-	    default:
-	      break;
-	    }
-
-	  /* Don't hash the type, that can lead to having nodes which
-	     compare equal according to operand_equal_p, but which
-	     have different hash codes.  */
-	  if (code == NON_LVALUE_EXPR)
-	    {
-	      /* Make sure to include signness in the hash computation.  */
-	      hstate.add_int (TYPE_UNSIGNED (TREE_TYPE (t)));
-	      inchash::add_expr (TREE_OPERAND (t, 0), hstate, flags);
-	    }
-
-	  else if (commutative_tree_code (code))
-	    {
-	      /* It's a commutative expression.  We want to hash it the same
-		 however it appears.  We do this by first hashing both operands
-		 and then rehashing based on the order of their independent
-		 hashes.  */
-	      inchash::hash one, two;
-	      inchash::add_expr (TREE_OPERAND (t, 0), one, flags);
-	      inchash::add_expr (TREE_OPERAND (t, 1), two, flags);
-	      hstate.add_commutative (one, two);
-	    }
-	  else
-	    for (i = TREE_OPERAND_LENGTH (t) - 1; i >= 0; --i)
-	      inchash::add_expr (TREE_OPERAND (t, i), hstate,
-				 i == 0 ? flags : sflags);
-	}
-      return;
-    }
-}
-
-}
-
 /* Constructors for pointer, array and function types.
    (RECORD_TYPE, UNION_TYPE and ENUMERAL_TYPE nodes are
    constructed by language-dependent code, not here.)  */

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

* [PATCH 9/9] Remove alias set comparison.
  2019-08-06 15:44             ` [PATCH 0/9] IPA ICF overhaul Martin Liska
@ 2019-08-06 15:43               ` Martin Liska
  2019-08-07 15:58                 ` Martin Sebor
  2019-08-08 14:44                 ` Jeff Law
  2019-08-06 15:43               ` [PATCH 5/9] Come up with an abstraction Martin Liska
                                 ` (9 subsequent siblings)
  10 siblings, 2 replies; 59+ messages in thread
From: Martin Liska @ 2019-08-06 15:43 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 866 bytes --]


gcc/ChangeLog:

2019-07-24  Martin Liska  <mliska@suse.cz>

	* ipa-icf-gimple.c (func_checker::compatible_types_p):
	Do not compare alias sets.  It's handled by operand_equal_p.

gcc/testsuite/ChangeLog:

2019-07-24  Martin Liska  <mliska@suse.cz>

	* c-c++-common/Wstringop-truncation-4.c: Disable IPA ICF.
	* gcc.dg/tree-ssa/pr64910-2.c: Likewise.
	* gcc.dg/tree-ssa/pr79352.c: Likewise.
	* gcc.dg/ipa/ipa-icf-40.c: New test.
---
 gcc/ipa-icf-gimple.c                          | 12 -------
 .../c-c++-common/Wstringop-truncation-4.c     |  2 +-
 gcc/testsuite/gcc.dg/ipa/ipa-icf-40.c         | 32 +++++++++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/pr64910-2.c     |  2 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr79352.c       |  2 +-
 5 files changed, 35 insertions(+), 15 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-icf-40.c


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0009-Remove-alias-set-comparison.patch --]
[-- Type: text/x-patch; name="0009-Remove-alias-set-comparison.patch", Size: 3783 bytes --]

diff --git a/gcc/ipa-icf-gimple.c b/gcc/ipa-icf-gimple.c
index 375aadad412..751d5859706 100644
--- a/gcc/ipa-icf-gimple.c
+++ b/gcc/ipa-icf-gimple.c
@@ -31,7 +31,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "cgraph.h"
 #include "data-streamer.h"
 #include "gimple-pretty-print.h"
-#include "alias.h"
 #include "fold-const.h"
 #include "gimple-iterator.h"
 #include "ipa-utils.h"
@@ -209,17 +208,6 @@ func_checker::compatible_types_p (tree t1, tree t2)
   if (!types_compatible_p (t1, t2))
     return return_false_with_msg ("types are not compatible");
 
-  /* We do a lot of unnecesary matching of types that are not being
-     accessed and thus do not need to be compatible.  In longer term we should
-     remove these checks on all types which are not accessed as memory
-     locations.
-
-     For time being just avoid calling get_alias_set on types that are not
-     having alias sets defined at all.  */
-  if (type_with_alias_set_p (t1) && type_with_alias_set_p (t2)
-      && get_alias_set (t1) != get_alias_set (t2))
-    return return_false_with_msg ("alias sets are different");
-
   return true;
 }
 
diff --git a/gcc/testsuite/c-c++-common/Wstringop-truncation-4.c b/gcc/testsuite/c-c++-common/Wstringop-truncation-4.c
index c76f2823daf..15209536add 100644
--- a/gcc/testsuite/c-c++-common/Wstringop-truncation-4.c
+++ b/gcc/testsuite/c-c++-common/Wstringop-truncation-4.c
@@ -3,7 +3,7 @@
    Verify that -Wstringop-truncation is issued for uses of arrays and
    pointers to qualified forms of characters of all three types.
    { dg-do compile }
-   { dg-options "-O2 -Wall -Wstringop-truncation" } */
+   { dg-options "-O2 -Wall -Wstringop-truncation -fno-ipa-icf" } */
 
 #if __cplusplus
 extern "C"
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-icf-40.c b/gcc/testsuite/gcc.dg/ipa/ipa-icf-40.c
new file mode 100644
index 00000000000..8d512cbc7d3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-icf-40.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-ipa-icf"  } */
+
+struct A { int i; char a1[10]; };
+struct B { int i; char a3[30]; };
+struct C { int i; char ax[]; };
+
+static int
+__attribute__((noinline))
+test_array_1 (int i, struct A *a)
+{
+  return __builtin_printf ("%-s\n", a->a1);
+}
+
+static int
+__attribute__((noinline))
+test_array_3 (int i, struct B *b)
+{
+  return __builtin_printf ("%-s\n", b->a3);
+}
+
+struct A a = { 0, "foo" };
+struct B b = { 0, "bar" };
+
+int main()
+{
+  test_array_1 (0, &a);
+  test_array_3 (0, &b);
+  return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Equal symbols: 1" "icf"  } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr64910-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr64910-2.c
index 2e3d6790776..812bfa48825 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr64910-2.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr64910-2.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-reassoc1" } */
+/* { dg-options "-O2 -fdump-tree-reassoc1 -fno-ipa-icf" } */
 
 /* We want to make sure that we reassociate in a way that has the
    constant last.  With the constant last, it's more likely to result
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr79352.c b/gcc/testsuite/gcc.dg/tree-ssa/pr79352.c
index 485e2d64cb3..36e195c3a06 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr79352.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr79352.c
@@ -1,7 +1,7 @@
 /* PR tree-optimization/79352 - -fprintf-return-value doesn't handle
    flexible-like array members properly
    { dg-do compile }
-   { dg-options "-O2 -fdump-tree-optimized" } */
+   { dg-options "-O2 -fdump-tree-optimized -fno-ipa-icf" } */
 
 struct A { int i; char a1[1]; };
 struct B { int i; char a3[3]; };

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

* [PATCH 6/9] Integrate that for IPA ICF.
  2019-08-06 15:44             ` [PATCH 0/9] IPA ICF overhaul Martin Liska
  2019-08-06 15:43               ` [PATCH 9/9] Remove alias set comparison Martin Liska
  2019-08-06 15:43               ` [PATCH 5/9] Come up with an abstraction Martin Liska
@ 2019-08-06 15:43               ` Martin Liska
  2019-08-16 11:10                 ` Martin Liška
  2019-08-06 15:43               ` [PATCH 7/9] IPA ICF: remove dead code Martin Liska
                                 ` (7 subsequent siblings)
  10 siblings, 1 reply; 59+ messages in thread
From: Martin Liska @ 2019-08-06 15:43 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 772 bytes --]


gcc/ChangeLog:

2019-07-24  Martin Liska  <mliska@suse.cz>

	* ipa-icf-gimple.c (func_checker::hash_operand_valueize): New
	function created from compare_operand.
	(func_checker::compare_cst_or_decl): Remove handling of
	FIELD_DECLs as it's handled in operand_equal_p.
	(func_checker::compare_operand): Transform
	to func_checker::operand_equal_valueize.
	(func_checker::operand_equal_valueize): New.
	* ipa-icf-gimple.h (class func_checker): Inherit from
	operand_compare.
	* ipa-icf.c (sem_function::equals_private): Properly
	set push_cfun and pop_cfun.
---
 gcc/ipa-icf-gimple.c | 226 +++++++++++++------------------------------
 gcc/ipa-icf-gimple.h |   8 +-
 gcc/ipa-icf.c        |   7 +-
 3 files changed, 81 insertions(+), 160 deletions(-)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0006-Integrate-that-for-IPA-ICF.patch --]
[-- Type: text/x-patch; name="0006-Integrate-that-for-IPA-ICF.patch", Size: 9491 bytes --]

diff --git a/gcc/ipa-icf-gimple.c b/gcc/ipa-icf-gimple.c
index 4060c0e8eb3..8448d387428 100644
--- a/gcc/ipa-icf-gimple.c
+++ b/gcc/ipa-icf-gimple.c
@@ -324,6 +324,28 @@ func_checker::compare_memory_operand (tree t1, tree t2)
 /* Function compare for equality given trees T1 and T2 which
    can be either a constant or a declaration type.  */
 
+bool
+func_checker::hash_operand_valueize (const_tree arg, inchash::hash &hstate,
+				     unsigned int flags)
+{
+  switch (TREE_CODE (arg))
+    {
+    case FUNCTION_DECL:
+    case VAR_DECL:
+    case LABEL_DECL:
+    case PARM_DECL:
+    case RESULT_DECL:
+    case CONST_DECL:
+    case SSA_NAME:
+      return true;
+
+    default:
+      break;
+    }
+
+  return false;
+}
+
 bool
 func_checker::compare_cst_or_decl (tree t1, tree t2)
 {
@@ -347,19 +369,6 @@ func_checker::compare_cst_or_decl (tree t1, tree t2)
       return true;
     case VAR_DECL:
       return return_with_debug (compare_variable_decl (t1, t2));
-    case FIELD_DECL:
-      {
-	tree offset1 = DECL_FIELD_OFFSET (t1);
-	tree offset2 = DECL_FIELD_OFFSET (t2);
-
-	tree bit_offset1 = DECL_FIELD_BIT_OFFSET (t1);
-	tree bit_offset2 = DECL_FIELD_BIT_OFFSET (t2);
-
-	ret = compare_operand (offset1, offset2)
-	      && compare_operand (bit_offset1, bit_offset2);
-
-	return return_with_debug (ret);
-      }
     case LABEL_DECL:
       {
 	if (t1 == t2)
@@ -383,165 +392,68 @@ func_checker::compare_cst_or_decl (tree t1, tree t2)
     }
 }
 
-/* Function responsible for comparison of various operands T1 and T2.
-   If these components, from functions FUNC1 and FUNC2, are equal, true
-   is returned.  */
-
-bool
-func_checker::compare_operand (tree t1, tree t2)
+int
+func_checker::operand_equal_valueize (const_tree ct1, const_tree ct2,
+				      unsigned int)
 {
-  tree x1, x2, y1, y2, z1, z2;
-  bool ret;
-
-  if (!t1 && !t2)
-    return true;
-  else if (!t1 || !t2)
-    return false;
-
-  tree tt1 = TREE_TYPE (t1);
-  tree tt2 = TREE_TYPE (t2);
-
-  if (!func_checker::compatible_types_p (tt1, tt2))
-    return false;
-
-  if (TREE_CODE (t1) != TREE_CODE (t2))
-    return return_false ();
+  tree t1 = const_cast <tree> (ct1);
+  tree t2 = const_cast <tree> (ct2);
 
   switch (TREE_CODE (t1))
     {
-    case CONSTRUCTOR:
+    case FUNCTION_DECL:
+      /* All function decls are in the symbol table and known to match
+	 before we start comparing bodies.  */
+      return true;
+    case VAR_DECL:
+      return return_with_debug (compare_variable_decl (t1, t2));
+    case LABEL_DECL:
       {
-	unsigned length1 = CONSTRUCTOR_NELTS (t1);
-	unsigned length2 = CONSTRUCTOR_NELTS (t2);
-
-	if (length1 != length2)
-	  return return_false ();
-
-	for (unsigned i = 0; i < length1; i++)
-	  if (!compare_operand (CONSTRUCTOR_ELT (t1, i)->value,
-				CONSTRUCTOR_ELT (t2, i)->value))
-	    return return_false();
-
-	return true;
+	int *bb1 = m_label_bb_map.get (t1);
+	int *bb2 = m_label_bb_map.get (t2);
+	/* Labels can point to another function (non-local GOTOs).  */
+	return return_with_debug (bb1 != NULL && bb2 != NULL && *bb1 == *bb2);
       }
-    case ARRAY_REF:
-    case ARRAY_RANGE_REF:
-      /* First argument is the array, second is the index.  */
-      x1 = TREE_OPERAND (t1, 0);
-      x2 = TREE_OPERAND (t2, 0);
-      y1 = TREE_OPERAND (t1, 1);
-      y2 = TREE_OPERAND (t2, 1);
-
-      if (!compare_operand (array_ref_low_bound (t1),
-			    array_ref_low_bound (t2)))
-	return return_false_with_msg ("");
-      if (!compare_operand (array_ref_element_size (t1),
-			    array_ref_element_size (t2)))
-	return return_false_with_msg ("");
-
-      if (!compare_operand (x1, x2))
-	return return_false_with_msg ("");
-      return compare_operand (y1, y2);
-    case MEM_REF:
-      {
-	x1 = TREE_OPERAND (t1, 0);
-	x2 = TREE_OPERAND (t2, 0);
-	y1 = TREE_OPERAND (t1, 1);
-	y2 = TREE_OPERAND (t2, 1);
-
-	/* See if operand is an memory access (the test originate from
-	 gimple_load_p).
-
-	In this case the alias set of the function being replaced must
-	be subset of the alias set of the other function.  At the moment
-	we seek for equivalency classes, so simply require inclussion in
-	both directions.  */
 
-	if (!func_checker::compatible_types_p (TREE_TYPE (x1), TREE_TYPE (x2)))
-	  return return_false ();
-
-	if (!compare_operand (x1, x2))
-	  return return_false_with_msg ("");
-
-	/* Type of the offset on MEM_REF does not matter.  */
-	return known_eq (wi::to_poly_offset (y1), wi::to_poly_offset (y2));
-      }
-    case COMPONENT_REF:
+    case PARM_DECL:
+    case RESULT_DECL:
+    case CONST_DECL:
+      return compare_decl (t1, t2);
+    case SSA_NAME:
+      return compare_ssa_name (t1, t2);
+    case FIELD_DECL:
       {
-	x1 = TREE_OPERAND (t1, 0);
-	x2 = TREE_OPERAND (t2, 0);
-	y1 = TREE_OPERAND (t1, 1);
-	y2 = TREE_OPERAND (t2, 1);
+	tree offset1 = DECL_FIELD_OFFSET (t1);
+	tree offset2 = DECL_FIELD_OFFSET (t2);
 
-	ret = compare_operand (x1, x2)
-	      && compare_cst_or_decl (y1, y2);
+	tree bit_offset1 = DECL_FIELD_BIT_OFFSET (t1);
+	tree bit_offset2 = DECL_FIELD_BIT_OFFSET (t2);
 
+	bool ret = (compare_operand (offset1, offset2)
+		    && compare_operand (bit_offset1, bit_offset2));
 	return return_with_debug (ret);
       }
-    /* Virtual table call.  */
-    case OBJ_TYPE_REF:
-      {
-	if (!compare_ssa_name (OBJ_TYPE_REF_EXPR (t1), OBJ_TYPE_REF_EXPR (t2)))
-	  return return_false ();
-	if (opt_for_fn (m_source_func_decl, flag_devirtualize)
-	    && virtual_method_call_p (t1))
-	  {
-	    if (tree_to_uhwi (OBJ_TYPE_REF_TOKEN (t1))
-		!= tree_to_uhwi (OBJ_TYPE_REF_TOKEN (t2)))
-	      return return_false_with_msg ("OBJ_TYPE_REF token mismatch");
-	    if (!types_same_for_odr (obj_type_ref_class (t1),
-				     obj_type_ref_class (t2)))
-	      return return_false_with_msg ("OBJ_TYPE_REF OTR type mismatch");
-	    if (!compare_operand (OBJ_TYPE_REF_OBJECT (t1),
-				  OBJ_TYPE_REF_OBJECT (t2)))
-	      return return_false_with_msg ("OBJ_TYPE_REF object mismatch");
-	  }
-
-	return return_with_debug (true);
-      }
-    case IMAGPART_EXPR:
-    case REALPART_EXPR:
-    case ADDR_EXPR:
-      {
-	x1 = TREE_OPERAND (t1, 0);
-	x2 = TREE_OPERAND (t2, 0);
+    default:
+      break;
+    }
 
-	ret = compare_operand (x1, x2);
-	return return_with_debug (ret);
-      }
-    case BIT_FIELD_REF:
-      {
-	x1 = TREE_OPERAND (t1, 0);
-	x2 = TREE_OPERAND (t2, 0);
-	y1 = TREE_OPERAND (t1, 1);
-	y2 = TREE_OPERAND (t2, 1);
-	z1 = TREE_OPERAND (t1, 2);
-	z2 = TREE_OPERAND (t2, 2);
+  return -1;
+}
 
-	ret = compare_operand (x1, x2)
-	      && compare_cst_or_decl (y1, y2)
-	      && compare_cst_or_decl (z1, z2);
+/* Function responsible for comparison of various operands T1 and T2.
+   If these components, from functions FUNC1 and FUNC2, are equal, true
+   is returned.  */
 
-	return return_with_debug (ret);
-      }
-    case SSA_NAME:
-	return compare_ssa_name (t1, t2);
-    case INTEGER_CST:
-    case COMPLEX_CST:
-    case VECTOR_CST:
-    case STRING_CST:
-    case REAL_CST:
-    case FUNCTION_DECL:
-    case VAR_DECL:
-    case FIELD_DECL:
-    case LABEL_DECL:
-    case PARM_DECL:
-    case RESULT_DECL:
-    case CONST_DECL:
-      return compare_cst_or_decl (t1, t2);
-    default:
-      return return_false_with_msg ("Unknown TREE code reached");
-    }
+bool
+func_checker::compare_operand (tree t1, tree t2)
+{
+  if (!t1 && !t2)
+    return true;
+  else if (!t1 || !t2)
+    return false;
+  if (operand_equal_p (t1, t2, OEP_MATCH_SIDE_EFFECTS))
+    return true;
+  return return_false_with_msg ("operand_equal_p failed");
 }
 
 bool
diff --git a/gcc/ipa-icf-gimple.h b/gcc/ipa-icf-gimple.h
index 351bddfb2f6..cb7d788e9ee 100644
--- a/gcc/ipa-icf-gimple.h
+++ b/gcc/ipa-icf-gimple.h
@@ -118,7 +118,7 @@ public:
 
 /* A class aggregating all connections and semantic equivalents
    for a given pair of semantic function candidates.  */
-class func_checker
+class func_checker : operand_compare
 {
 public:
   /* Initialize internal structures for a given SOURCE_FUNC_DECL and
@@ -134,7 +134,7 @@ public:
 		hash_set<symtab_node *> *ignored_target_nodes = NULL);
 
   /* Memory release routine.  */
-  ~func_checker();
+  virtual ~func_checker ();
 
   /* Function visits all gimple labels and creates corresponding
      mapping between basic blocks and labels.  */
@@ -267,6 +267,10 @@ private:
 
   /* Flag if ignore labels in comparison.  */
   bool m_ignore_labels;
+
+  virtual int operand_equal_valueize (const_tree, const_tree, unsigned int);
+  virtual bool hash_operand_valueize (const_tree, inchash::hash &,
+				      unsigned int);
 };
 
 } // ipa_icf_gimple namespace
diff --git a/gcc/ipa-icf.c b/gcc/ipa-icf.c
index 13e63b77af1..ce98eefe7f5 100644
--- a/gcc/ipa-icf.c
+++ b/gcc/ipa-icf.c
@@ -878,9 +878,14 @@ sem_function::equals_private (sem_item *item)
     }
 
   /* Checking all basic blocks.  */
+  push_cfun (DECL_STRUCT_FUNCTION (decl));
   for (unsigned i = 0; i < bb_sorted.length (); ++i)
     if(!m_checker->compare_bb (bb_sorted[i], m_compared_func->bb_sorted[i]))
-      return return_false();
+      {
+	pop_cfun ();
+	return return_false ();
+      }
+  pop_cfun ();
 
   auto_vec <int> bb_dict;
 

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

* [PATCH 2/9] operand_equal_p: add support for FIELD_DECL
  2019-08-06 15:44             ` [PATCH 0/9] IPA ICF overhaul Martin Liska
                                 ` (5 preceding siblings ...)
  2019-08-06 15:43               ` [PATCH 4/9] Strengthen alias_ptr_types_compatible_p in LTO mode Martin Liska
@ 2019-08-06 15:43               ` Martin Liska
  2019-08-07 12:21                 ` Richard Biener
  2019-08-06 15:43               ` [PATCH 1/9] Replace int with boolean in predicate functions Martin Liska
                                 ` (3 subsequent siblings)
  10 siblings, 1 reply; 59+ messages in thread
From: Martin Liska @ 2019-08-06 15:43 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 953 bytes --]


gcc/ChangeLog:

2019-07-24  Martin Liska  <mliska@suse.cz>

	* fold-const.c (operand_equal_p): Support FIELD_DECL
	as well.
	* tree.c (add_expr): Hast DECL_FIELD_OFFSET and
	DECL_FIELD_BIT_OFFSET for FIELD_DECL.

gcc/testsuite/ChangeLog:

2019-07-24  Martin Liska  <mliska@suse.cz>

	* gcc.dg/vect/vect-35-big-array.c: Vectorize one more loop.
	* gcc.dg/vect/vect-35.c: Likewise.
	* gcc.dg/pr70740.c: Move from torture and set -O2.
	* gfortran.dg/vect/vect-8.f90: Update scanned pattern.
---
 gcc/fold-const.c                              | 34 ++++++++++++++++---
 gcc/testsuite/gcc.dg/{torture => }/pr70740.c  |  3 +-
 gcc/testsuite/gcc.dg/vect/vect-35-big-array.c |  3 +-
 gcc/testsuite/gcc.dg/vect/vect-35.c           |  3 +-
 gcc/testsuite/gfortran.dg/vect/vect-8.f90     |  2 +-
 gcc/tree.c                                    |  4 +++
 6 files changed, 38 insertions(+), 11 deletions(-)
 rename gcc/testsuite/gcc.dg/{torture => }/pr70740.c (77%)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0002-operand_equal_p-add-support-for-FIELD_DECL.patch --]
[-- Type: text/x-patch; name="0002-operand_equal_p-add-support-for-FIELD_DECL.patch", Size: 4629 bytes --]

diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 0bd68b5e2d4..52414f7729e 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -3462,11 +3462,35 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 	}
 
     case tcc_declaration:
-      /* Consider __builtin_sqrt equal to sqrt.  */
-      return (TREE_CODE (arg0) == FUNCTION_DECL
-	      && fndecl_built_in_p (arg0) && fndecl_built_in_p (arg1)
-	      && DECL_BUILT_IN_CLASS (arg0) == DECL_BUILT_IN_CLASS (arg1)
-	      && DECL_FUNCTION_CODE (arg0) == DECL_FUNCTION_CODE (arg1));
+      switch (TREE_CODE (arg0))
+	{
+	case FUNCTION_DECL:
+	  /* Consider __builtin_sqrt equal to sqrt.  */
+	  return (fndecl_built_in_p (arg0) && fndecl_built_in_p (arg1)
+		  && DECL_BUILT_IN_CLASS (arg0) == DECL_BUILT_IN_CLASS (arg1)
+		  && DECL_FUNCTION_CODE (arg0) == DECL_FUNCTION_CODE (arg1));
+	case FIELD_DECL:
+	  {
+	    tree fo0 = DECL_FIELD_OFFSET (arg0);
+	    tree fo1 = DECL_FIELD_OFFSET (arg1);
+	    if (fo0 != NULL && fo1 != NULL
+		&& !operand_equal_p (fo0, fo1, OEP_ONLY_CONST))
+	      return false;
+	    else if (fo0 != fo1)
+	      return false;
+
+	    tree fbo0 = DECL_FIELD_BIT_OFFSET (arg0);
+	    tree fbo1 = DECL_FIELD_BIT_OFFSET (arg1);
+	    if (fbo0 != NULL && fbo1 != NULL
+		&& !operand_equal_p (fbo0, fbo1, OEP_ONLY_CONST))
+	      return false;
+	    else if (fbo0 != fbo1)
+	      return false;
+	    return true;
+	  }
+	default:
+	  return false;
+	}
 
     case tcc_exceptional:
       if (TREE_CODE (arg0) == CONSTRUCTOR)
diff --git a/gcc/testsuite/gcc.dg/torture/pr70740.c b/gcc/testsuite/gcc.dg/pr70740.c
similarity index 77%
rename from gcc/testsuite/gcc.dg/torture/pr70740.c
rename to gcc/testsuite/gcc.dg/pr70740.c
index 5bf8e4adc91..186da1b2637 100644
--- a/gcc/testsuite/gcc.dg/torture/pr70740.c
+++ b/gcc/testsuite/gcc.dg/pr70740.c
@@ -1,4 +1,5 @@
 /* { dg-do compile } */
+/* { dg-options "-O2" } */
 
 extern int foo (void);
 extern void *memcpy (void *, const void *, __SIZE_TYPE__);
@@ -32,7 +33,7 @@ baz ()
     e = c.a3;
   else
     e = c.a1;
-  memcpy (d.a, e, 6);
+  memcpy (d.a, e, 6); /* { dg-warning "reading 5 bytes from a region of size 0" } */
   f = bar ();
   memcpy (d.a, f, 1);
 }
diff --git a/gcc/testsuite/gcc.dg/vect/vect-35-big-array.c b/gcc/testsuite/gcc.dg/vect/vect-35-big-array.c
index ca57a10f714..fa356c2c4a2 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-35-big-array.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-35-big-array.c
@@ -47,5 +47,4 @@ int main (void)
 }
 
 
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect"  { xfail { ia64-*-* sparc*-*-* } } } } */
-/* { dg-final { scan-tree-dump "can't determine dependence between" "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 2 loops" 1 "vect"  { xfail { ia64-*-* sparc*-*-* } } } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-35.c b/gcc/testsuite/gcc.dg/vect/vect-35.c
index 76fe32d68ad..3023c8c714f 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-35.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-35.c
@@ -47,5 +47,4 @@ int main (void)
 } 
 
 
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect"  { xfail { ia64-*-* sparc*-*-* } } } } */
-/* { dg-final { scan-tree-dump "can't determine dependence between" "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 2 loops" 1 "vect"  { xfail { ia64-*-* sparc*-*-* } } } } */
diff --git a/gcc/testsuite/gfortran.dg/vect/vect-8.f90 b/gcc/testsuite/gfortran.dg/vect/vect-8.f90
index e26cdf95e51..f83f0d0aa27 100644
--- a/gcc/testsuite/gfortran.dg/vect/vect-8.f90
+++ b/gcc/testsuite/gfortran.dg/vect/vect-8.f90
@@ -704,5 +704,5 @@ CALL track('KERNEL  ')
 RETURN
 END SUBROUTINE kernel
 
-! { dg-final { scan-tree-dump-times "vectorized 22 loops" 1 "vect" { target vect_intdouble_cvt } } }
+! { dg-final { scan-tree-dump-times "vectorized 23 loops" 1 "vect" { target vect_intdouble_cvt } } }
 ! { dg-final { scan-tree-dump-times "vectorized 17 loops" 1 "vect" { target { ! vect_intdouble_cvt } } } }
diff --git a/gcc/tree.c b/gcc/tree.c
index efa49e99d65..91ebc9eddc4 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -7887,6 +7887,10 @@ add_expr (const_tree t, inchash::hash &hstate, unsigned int flags)
     case IDENTIFIER_NODE:
       hstate.add_object (IDENTIFIER_HASH_VALUE (t));
       return;
+    case FIELD_DECL:
+      inchash::add_expr (DECL_FIELD_OFFSET (t), hstate, flags);
+      inchash::add_expr (DECL_FIELD_BIT_OFFSET (t), hstate, flags);
+      return;
     case FUNCTION_DECL:
       /* When referring to a built-in FUNCTION_DECL, use the __builtin__ form.
 	 Otherwise nodes that compare equal according to operand_equal_p might

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

* [PATCH 1/9] Replace int with boolean in predicate functions.
  2019-08-06 15:44             ` [PATCH 0/9] IPA ICF overhaul Martin Liska
                                 ` (6 preceding siblings ...)
  2019-08-06 15:43               ` [PATCH 2/9] operand_equal_p: add support for FIELD_DECL Martin Liska
@ 2019-08-06 15:43               ` Martin Liska
  2019-08-07 12:38                 ` Richard Biener
  2019-08-06 15:55               ` [PATCH 3/9] operand_equal_p: add support for OBJ_TYPE_REF Martin Liska
                                 ` (2 subsequent siblings)
  10 siblings, 1 reply; 59+ messages in thread
From: Martin Liska @ 2019-08-06 15:43 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 448 bytes --]


gcc/ChangeLog:

2019-07-24  Martin Liska  <mliska@suse.cz>

	* fold-const.c (twoval_comparison_p): Replace int
	with bool as a return type.
	(simple_operand_p): Likewise.
	(operand_equal_p): Replace int with bool as a return type.
	* fold-const.h (operand_equal_p): Likewise.
---
 gcc/fold-const.c | 148 +++++++++++++++++++++++------------------------
 gcc/fold-const.h |   2 +-
 2 files changed, 75 insertions(+), 75 deletions(-)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Replace-int-with-boolean-in-predicate-functions.patch --]
[-- Type: text/x-patch; name="0001-Replace-int-with-boolean-in-predicate-functions.patch", Size: 18485 bytes --]

diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 716d7397b49..0bd68b5e2d4 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -115,11 +115,11 @@ static tree negate_expr (tree);
 static tree associate_trees (location_t, tree, tree, enum tree_code, tree);
 static enum comparison_code comparison_to_compcode (enum tree_code);
 static enum tree_code compcode_to_comparison (enum comparison_code);
-static int twoval_comparison_p (tree, tree *, tree *);
+static bool twoval_comparison_p (tree, tree *, tree *);
 static tree eval_subst (location_t, tree, tree, tree, tree, tree);
 static tree optimize_bit_field_compare (location_t, enum tree_code,
 					tree, tree, tree);
-static int simple_operand_p (const_tree);
+static bool simple_operand_p (const_tree);
 static bool simple_operand_p_2 (tree);
 static tree range_binop (enum tree_code, tree, tree, int, tree, int);
 static tree range_predecessor (tree);
@@ -2939,7 +2939,7 @@ combine_comparisons (location_t loc,
    addresses with TREE_CONSTANT flag set so we know that &var == &var
    even if var is volatile.  */
 
-int
+bool
 operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 {
   /* When checking, verify at the outermost operand_equal_p call that
@@ -2958,10 +2958,10 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 	      hashval_t h1 = hstate1.end ();
 	      gcc_assert (h0 == h1);
 	    }
-	  return 1;
+	  return true;
 	}
       else
-	return 0;
+	return false;
     }
 
   STRIP_ANY_LOCATION_WRAPPER (arg0);
@@ -2971,19 +2971,19 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
   if (TREE_CODE (arg0) == ERROR_MARK || TREE_CODE (arg1) == ERROR_MARK
       || TREE_TYPE (arg0) == error_mark_node
       || TREE_TYPE (arg1) == error_mark_node)
-    return 0;
+    return false;
 
   /* Similar, if either does not have a type (like a template id),
      they aren't equal.  */
   if (!TREE_TYPE (arg0) || !TREE_TYPE (arg1))
-    return 0;
+    return false;
 
   /* We cannot consider pointers to different address space equal.  */
   if (POINTER_TYPE_P (TREE_TYPE (arg0))
       && POINTER_TYPE_P (TREE_TYPE (arg1))
       && (TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (arg0)))
 	  != TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (arg1)))))
-    return 0;
+    return false;
 
   /* Check equality of integer constants before bailing out due to
      precision differences.  */
@@ -3005,13 +3005,13 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
       if (TYPE_UNSIGNED (TREE_TYPE (arg0)) != TYPE_UNSIGNED (TREE_TYPE (arg1))
 	  || POINTER_TYPE_P (TREE_TYPE (arg0))
 			     != POINTER_TYPE_P (TREE_TYPE (arg1)))
-	return 0;
+	return false;
 
       /* If both types don't have the same precision, then it is not safe
 	 to strip NOPs.  */
       if (element_precision (TREE_TYPE (arg0))
 	  != element_precision (TREE_TYPE (arg1)))
-	return 0;
+	return false;
 
       STRIP_NOPS (arg0);
       STRIP_NOPS (arg1);
@@ -3058,17 +3058,17 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 	      && TREE_CODE (TREE_OPERAND (arg0, 0)) == ADDR_EXPR
 	      && TREE_OPERAND (TREE_OPERAND (arg0, 0), 0) == arg1
 	      && integer_zerop (TREE_OPERAND (arg0, 1)))
-	    return 1;
+	    return true;
 	  else if (TREE_CODE (arg1) == MEM_REF
 		   && DECL_P (arg0)
 		   && TREE_CODE (TREE_OPERAND (arg1, 0)) == ADDR_EXPR
 		   && TREE_OPERAND (TREE_OPERAND (arg1, 0), 0) == arg0
 		   && integer_zerop (TREE_OPERAND (arg1, 1)))
-	    return 1;
-	  return 0;
+	    return true;
+	  return false;
 	}
       else
-	return 0;
+	return false;
     }
 
   /* When not checking adddresses, this is needed for conversions and for
@@ -3077,7 +3077,7 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
       || TREE_CODE (TREE_TYPE (arg1)) == ERROR_MARK
       || (TYPE_MODE (TREE_TYPE (arg0)) != TYPE_MODE (TREE_TYPE (arg1))
 	  && !(flags & OEP_ADDRESS_OF)))
-    return 0;
+    return false;
 
   /* If ARG0 and ARG1 are the same SAVE_EXPR, they are necessarily equal.
      We don't care about side effects in that case because the SAVE_EXPR
@@ -3092,7 +3092,7 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
       && (TREE_CODE (arg0) == SAVE_EXPR
 	  || (flags & OEP_MATCH_SIDE_EFFECTS)
 	  || (! TREE_SIDE_EFFECTS (arg0) && ! TREE_SIDE_EFFECTS (arg1))))
-    return 1;
+    return true;
 
   /* Next handle constant cases, those for which we can return 1 even
      if ONLY_CONST is set.  */
@@ -3108,7 +3108,7 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 
       case REAL_CST:
 	if (real_identical (&TREE_REAL_CST (arg0), &TREE_REAL_CST (arg1)))
-	  return 1;
+	  return true;
 
 
 	if (!HONOR_SIGNED_ZEROS (arg0))
@@ -3116,26 +3116,26 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 	    /* If we do not distinguish between signed and unsigned zero,
 	       consider them equal.  */
 	    if (real_zerop (arg0) && real_zerop (arg1))
-	      return 1;
+	      return true;
 	  }
-	return 0;
+	return false;
 
       case VECTOR_CST:
 	{
 	  if (VECTOR_CST_LOG2_NPATTERNS (arg0)
 	      != VECTOR_CST_LOG2_NPATTERNS (arg1))
-	    return 0;
+	    return false;
 
 	  if (VECTOR_CST_NELTS_PER_PATTERN (arg0)
 	      != VECTOR_CST_NELTS_PER_PATTERN (arg1))
-	    return 0;
+	    return false;
 
 	  unsigned int count = vector_cst_encoded_nelts (arg0);
 	  for (unsigned int i = 0; i < count; ++i)
 	    if (!operand_equal_p (VECTOR_CST_ENCODED_ELT (arg0, i),
 				  VECTOR_CST_ENCODED_ELT (arg1, i), flags))
-	      return 0;
-	  return 1;
+	      return false;
+	  return true;
 	}
 
       case COMPLEX_CST:
@@ -3164,7 +3164,7 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
       }
 
   if (flags & OEP_ONLY_CONST)
-    return 0;
+    return false;
 
 /* Define macros to test an operand from arg0 and arg1 for equality and a
    variant that allows null and views null as being different from any
@@ -3187,7 +3187,7 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
         case FIX_TRUNC_EXPR:
 	  if (TYPE_UNSIGNED (TREE_TYPE (arg0))
 	      != TYPE_UNSIGNED (TREE_TYPE (arg1)))
-	    return 0;
+	    return false;
 	  break;
 	default:
 	  break;
@@ -3199,7 +3199,7 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
     case tcc_comparison:
     case tcc_binary:
       if (OP_SAME (0) && OP_SAME (1))
-	return 1;
+	return true;
 
       /* For commutative ops, allow the other order.  */
       return (commutative_tree_code (TREE_CODE (arg0))
@@ -3215,7 +3215,7 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
       if ((flags & OEP_MATCH_SIDE_EFFECTS) == 0
 	  && (TREE_SIDE_EFFECTS (arg0)
 	      || TREE_SIDE_EFFECTS (arg1)))
-	return 0;
+	return false;
 
       switch (TREE_CODE (arg0))
 	{
@@ -3224,11 +3224,11 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 	    {
 	      if (TYPE_ALIGN (TREE_TYPE (arg0))
 		  != TYPE_ALIGN (TREE_TYPE (arg1)))
-		return 0;
+		return false;
 	      /* Verify that the access types are compatible.  */
 	      if (TYPE_MAIN_VARIANT (TREE_TYPE (arg0))
 		  != TYPE_MAIN_VARIANT (TREE_TYPE (arg1)))
-		return 0;
+		return false;
 	    }
 	  flags &= ~OEP_ADDRESS_OF;
 	  return OP_SAME (0);
@@ -3238,7 +3238,7 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 	  if (!operand_equal_p (TYPE_SIZE (TREE_TYPE (arg0)),
 				TYPE_SIZE (TREE_TYPE (arg1)),
 				flags & ~OEP_ADDRESS_OF))
-	    return 0;
+	    return false;
 
 	/* Fallthru.  */
 	case REALPART_EXPR:
@@ -3256,10 +3256,10 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 		      || !operand_equal_p (TYPE_SIZE (TREE_TYPE (arg0)),
 					   TYPE_SIZE (TREE_TYPE (arg1)),
 					   flags)))
-		return 0;
+		return false;
 	      /* Verify that access happens in similar types.  */
 	      if (!types_compatible_p (TREE_TYPE (arg0), TREE_TYPE (arg1)))
-		return 0;
+		return false;
 	      /* Verify that accesses are TBAA compatible.  */
 	      if (!alias_ptr_types_compatible_p
 		    (TREE_TYPE (TREE_OPERAND (arg0, 1)),
@@ -3268,11 +3268,11 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 		      != MR_DEPENDENCE_CLIQUE (arg1))
 		  || (MR_DEPENDENCE_BASE (arg0)
 		      != MR_DEPENDENCE_BASE (arg1)))
-		return 0;
+		return false;
 	     /* Verify that alignment is compatible.  */
 	     if (TYPE_ALIGN (TREE_TYPE (arg0))
 		 != TYPE_ALIGN (TREE_TYPE (arg1)))
-		return 0;
+		return false;
 	    }
 	  flags &= ~OEP_ADDRESS_OF;
 	  return (OP_SAME (0) && OP_SAME (1)
@@ -3285,7 +3285,7 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 	case ARRAY_REF:
 	case ARRAY_RANGE_REF:
 	  if (!OP_SAME (0))
-	    return 0;
+	    return false;
 	  flags &= ~OEP_ADDRESS_OF;
 	  /* Compare the array index by value if it is constant first as we
 	     may have different types but same value here.  */
@@ -3313,18 +3313,18 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 	     may be NULL when we're called to compare MEM_EXPRs.  */
 	  if (!OP_SAME_WITH_NULL (0)
 	      || !OP_SAME (1))
-	    return 0;
+	    return false;
 	  flags &= ~OEP_ADDRESS_OF;
 	  return OP_SAME_WITH_NULL (2);
 
 	case BIT_FIELD_REF:
 	  if (!OP_SAME (0))
-	    return 0;
+	    return false;
 	  flags &= ~OEP_ADDRESS_OF;
 	  return OP_SAME (1) && OP_SAME (2);
 
 	default:
-	  return 0;
+	  return false;
 	}
 
     case tcc_expression:
@@ -3347,7 +3347,7 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 	case WIDEN_MULT_PLUS_EXPR:
 	case WIDEN_MULT_MINUS_EXPR:
 	  if (!OP_SAME (2))
-	    return 0;
+	    return false;
 	  /* The multiplcation operands are commutative.  */
 	  /* FALLTHRU */
 
@@ -3355,7 +3355,7 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 	case TRUTH_OR_EXPR:
 	case TRUTH_XOR_EXPR:
 	  if (OP_SAME (0) && OP_SAME (1))
-	    return 1;
+	    return true;
 
 	  /* Otherwise take into account this is a commutative operation.  */
 	  return (operand_equal_p (TREE_OPERAND (arg0, 0),
@@ -3365,7 +3365,7 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 
 	case COND_EXPR:
 	  if (! OP_SAME (1) || ! OP_SAME_WITH_NULL (2))
-	    return 0;
+	    return false;
 	  flags &= ~OEP_ADDRESS_OF;
 	  return OP_SAME (0);
 
@@ -3392,17 +3392,17 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 	case POSTINCREMENT_EXPR:
 	  if (flags & OEP_LEXICOGRAPHIC)
 	    return OP_SAME (0) && OP_SAME (1);
-	  return 0;
+	  return false;
 
 	case CLEANUP_POINT_EXPR:
 	case EXPR_STMT:
 	case SAVE_EXPR:
 	  if (flags & OEP_LEXICOGRAPHIC)
 	    return OP_SAME (0);
-	  return 0;
+	  return false;
 
 	default:
-	  return 0;
+	  return false;
 	}
 
     case tcc_vl_exp:
@@ -3413,13 +3413,13 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 	      != (CALL_EXPR_FN (arg1) == NULL_TREE))
 	    /* If not both CALL_EXPRs are either internal or normal function
 	       functions, then they are not equal.  */
-	    return 0;
+	    return false;
 	  else if (CALL_EXPR_FN (arg0) == NULL_TREE)
 	    {
 	      /* If the CALL_EXPRs call different internal functions, then they
 		 are not equal.  */
 	      if (CALL_EXPR_IFN (arg0) != CALL_EXPR_IFN (arg1))
-		return 0;
+		return false;
 	    }
 	  else
 	    {
@@ -3427,7 +3427,7 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 		 equal.  */
 	      if (! operand_equal_p (CALL_EXPR_FN (arg0), CALL_EXPR_FN (arg1),
 				     flags))
-		return 0;
+		return false;
 	    }
 
 	  /* FIXME: We could skip this test for OEP_MATCH_SIDE_EFFECTS.  */
@@ -3438,7 +3438,7 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 	    else
 	      cef &= ECF_CONST;
 	    if (!cef && !(flags & OEP_LEXICOGRAPHIC))
-	      return 0;
+	      return false;
 	  }
 
 	  /* Now see if all the arguments are the same.  */
@@ -3451,14 +3451,14 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 		 a0 = next_const_call_expr_arg (&iter0),
 		   a1 = next_const_call_expr_arg (&iter1))
 	      if (! operand_equal_p (a0, a1, flags))
-		return 0;
+		return false;
 
 	    /* If we get here and both argument lists are exhausted
 	       then the CALL_EXPRs are equal.  */
 	    return ! (a0 || a1);
 	  }
 	default:
-	  return 0;
+	  return false;
 	}
 
     case tcc_declaration:
@@ -3480,7 +3480,7 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 	      constants).  */
 	  if (!VECTOR_TYPE_P (TREE_TYPE (arg0))
 	      || !VECTOR_TYPE_P (TREE_TYPE (arg1)))
-	    return 0;
+	    return false;
 
 	  /* Be sure that vectors constructed have the same representation.
 	     We only tested element precision and modes to match.
@@ -3488,14 +3488,14 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 	     parts match.  */
 	  if (maybe_ne (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)),
 			TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg1))))
-	    return 0;
+	    return false;
 
 	  vec<constructor_elt, va_gc> *v0 = CONSTRUCTOR_ELTS (arg0);
 	  vec<constructor_elt, va_gc> *v1 = CONSTRUCTOR_ELTS (arg1);
 	  unsigned int len = vec_safe_length (v0);
 
 	  if (len != vec_safe_length (v1))
-	    return 0;
+	    return false;
 
 	  for (unsigned int i = 0; i < len; i++)
 	    {
@@ -3512,9 +3512,9 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 		  || (c1->index
 		      && (TREE_CODE (c1->index) != INTEGER_CST 
 			  || compare_tree_int (c1->index, i))))
-		return 0;
+		return false;
 	    }
-	  return 1;
+	  return true;
 	}
       else if (TREE_CODE (arg0) == STATEMENT_LIST
 	       && (flags & OEP_LEXICOGRAPHIC))
@@ -3528,16 +3528,16 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 	    {
 	      /* The lists don't have the same number of statements.  */
 	      if (tsi_end_p (tsi1) ^ tsi_end_p (tsi2))
-		return 0;
+		return false;
 	      if (tsi_end_p (tsi1) && tsi_end_p (tsi2))
-		return 1;
+		return true;
 	      if (!operand_equal_p (tsi_stmt (tsi1), tsi_stmt (tsi2),
 				    flags & (OEP_LEXICOGRAPHIC
 					     | OEP_NO_HASH_CHECK)))
-		return 0;
+		return false;
 	    }
 	}
-      return 0;
+      return false;
 
     case tcc_statement:
       switch (TREE_CODE (arg0))
@@ -3545,17 +3545,17 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 	case RETURN_EXPR:
 	  if (flags & OEP_LEXICOGRAPHIC)
 	    return OP_SAME_WITH_NULL (0);
-	  return 0;
+	  return false;
 	case DEBUG_BEGIN_STMT:
 	  if (flags & OEP_LEXICOGRAPHIC)
-	    return 1;
-	  return 0;
+	    return true;
+	  return false;
 	default:
-	  return 0;
+	  return false;
 	 }
 
     default:
-      return 0;
+      return false;
     }
 
 #undef OP_SAME
@@ -3606,7 +3606,7 @@ operand_equal_for_comparison_p (tree arg0, tree arg1)
 
    If this is true, return 1.  Otherwise, return zero.  */
 
-static int
+static bool
 twoval_comparison_p (tree arg, tree *cval1, tree *cval2)
 {
   enum tree_code code = TREE_CODE (arg);
@@ -3630,14 +3630,14 @@ twoval_comparison_p (tree arg, tree *cval1, tree *cval2)
 	      && twoval_comparison_p (TREE_OPERAND (arg, 1), cval1, cval2));
 
     case tcc_constant:
-      return 1;
+      return true;
 
     case tcc_expression:
       if (code == COND_EXPR)
 	return (twoval_comparison_p (TREE_OPERAND (arg, 0), cval1, cval2)
 		&& twoval_comparison_p (TREE_OPERAND (arg, 1), cval1, cval2)
 		&& twoval_comparison_p (TREE_OPERAND (arg, 2), cval1, cval2));
-      return 0;
+      return false;
 
     case tcc_comparison:
       /* First see if we can handle the first operand, then the second.  For
@@ -3648,7 +3648,7 @@ twoval_comparison_p (tree arg, tree *cval1, tree *cval2)
 
       if (operand_equal_p (TREE_OPERAND (arg, 0),
 			   TREE_OPERAND (arg, 1), 0))
-	return 0;
+	return false;
 
       if (*cval1 == 0)
 	*cval1 = TREE_OPERAND (arg, 0);
@@ -3659,7 +3659,7 @@ twoval_comparison_p (tree arg, tree *cval1, tree *cval2)
       else if (operand_equal_p (*cval2, TREE_OPERAND (arg, 0), 0))
 	;
       else
-	return 0;
+	return false;
 
       if (operand_equal_p (*cval1, TREE_OPERAND (arg, 1), 0))
 	;
@@ -3668,12 +3668,12 @@ twoval_comparison_p (tree arg, tree *cval1, tree *cval2)
       else if (operand_equal_p (*cval2, TREE_OPERAND (arg, 1), 0))
 	;
       else
-	return 0;
+	return false;
 
-      return 1;
+      return true;
 
     default:
-      return 0;
+      return false;
     }
 }
 \f
@@ -4353,7 +4353,7 @@ decode_field_reference (location_t loc, tree *exp_, HOST_WIDE_INT *pbitsize,
 /* Return nonzero if MASK represents a mask of SIZE ones in the low-order
    bit positions and MASK is SIGNED.  */
 
-static int
+static bool
 all_ones_mask_p (const_tree mask, unsigned int size)
 {
   tree type = TREE_TYPE (mask);
@@ -4408,7 +4408,7 @@ sign_bit_p (tree exp, const_tree val)
 /* Subroutine for fold_truth_andor_1: determine if an operand is simple enough
    to be evaluated unconditionally.  */
 
-static int
+static bool
 simple_operand_p (const_tree exp)
 {
   /* Strip any conversions that don't change the machine mode.  */
diff --git a/gcc/fold-const.h b/gcc/fold-const.h
index eab2b47a260..54c850a3ee1 100644
--- a/gcc/fold-const.h
+++ b/gcc/fold-const.h
@@ -84,7 +84,7 @@ extern bool fold_deferring_overflow_warnings_p (void);
 extern void fold_overflow_warning (const char*, enum warn_strict_overflow_code);
 extern enum tree_code fold_div_compare (enum tree_code, tree, tree,
 					tree *, tree *, bool *);
-extern int operand_equal_p (const_tree, const_tree, unsigned int);
+extern bool operand_equal_p (const_tree, const_tree, unsigned int);
 extern int multiple_of_p (tree, const_tree, const_tree);
 #define omit_one_operand(T1,T2,T3)\
    omit_one_operand_loc (UNKNOWN_LOCATION, T1, T2, T3)

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

* [PATCH 0/9] IPA ICF overhaul
  2019-06-18 11:10           ` [RFC] " Martin Liška
@ 2019-08-06 15:44             ` Martin Liska
  2019-08-06 15:43               ` [PATCH 9/9] Remove alias set comparison Martin Liska
                                 ` (10 more replies)
  0 siblings, 11 replies; 59+ messages in thread
From: Martin Liska @ 2019-08-06 15:44 UTC (permalink / raw)
  To: gcc-patches

Hi.

It's some time I implemented first version of IPA ICF pass. Since that
I experienced more with the GCC internals and now is the right time
to do an overhaul.

Main motivation of changes is to share as many as possible in between
current operand_equal_p and ipa_icf::compare_operand. That's achieved
by a new class operand_compare. That allows use to share and unify
a lot of code. Apart from that I would like to learn current operand_equal_p
to handle new tree types.

Patch can bootstrap on x86_64-linux-gnu and survives regression tests. I also
built Firefox, Godot engine.

Thanks,
Martin

Martin Liska (9):
  Replace int with boolean in predicate functions.
  operand_equal_p: add support for FIELD_DECL
  operand_equal_p: add support for OBJ_TYPE_REF.
  Strengthen alias_ptr_types_compatible_p in LTO mode.
  Come up with an abstraction.
  Integrate that for IPA ICF.
  IPA ICF: remove dead code
  Remove comparison for polymorphic types.
  Remove alias set comparison.

 gcc/alias.c                                   |   7 +-
 gcc/fold-const.c                              | 547 +++++++++++++++---
 gcc/fold-const.h                              |  30 +-
 gcc/ipa-icf-gimple.c                          | 328 ++---------
 gcc/ipa-icf-gimple.h                          |  16 +-
 gcc/ipa-icf.c                                 |  19 +-
 gcc/ipa-icf.h                                 |   3 -
 .../c-c++-common/Wstringop-truncation-4.c     |   2 +-
 gcc/testsuite/gcc.dg/ipa/ipa-icf-40.c         |  32 +
 gcc/testsuite/gcc.dg/{torture => }/pr70740.c  |   3 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr64910-2.c     |   2 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr79352.c       |   2 +-
 gcc/testsuite/gcc.dg/vect/vect-35-big-array.c |   3 +-
 gcc/testsuite/gcc.dg/vect/vect-35.c           |   3 +-
 gcc/testsuite/gfortran.dg/vect/vect-8.f90     |   2 +-
 gcc/tree.c                                    | 273 ---------
 16 files changed, 588 insertions(+), 684 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-icf-40.c
 rename gcc/testsuite/gcc.dg/{torture => }/pr70740.c (77%)

-- 
2.22.0

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

* [PATCH 3/9] operand_equal_p: add support for OBJ_TYPE_REF.
  2019-08-06 15:44             ` [PATCH 0/9] IPA ICF overhaul Martin Liska
                                 ` (7 preceding siblings ...)
  2019-08-06 15:43               ` [PATCH 1/9] Replace int with boolean in predicate functions Martin Liska
@ 2019-08-06 15:55               ` Martin Liska
  2019-08-07 12:09                 ` Richard Biener
  2019-08-16 11:53               ` [PATCH 10/N] Use const_tree more in IPA ICF Martin Liška
  2019-10-30 11:54               ` [PATCH 0/9] IPA ICF overhaul Martin Liška
  10 siblings, 1 reply; 59+ messages in thread
From: Martin Liska @ 2019-08-06 15:55 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 286 bytes --]


gcc/ChangeLog:

2019-07-24  Martin Liska  <mliska@suse.cz>

	* fold-const.c (operand_equal_p): Support OBJ_TYPE_REF.
	* tree.c (add_expr): Hash parts of OBJ_TYPE_REF.
---
 gcc/fold-const.c | 21 +++++++++++++++++++++
 gcc/tree.c       |  9 +++++++++
 2 files changed, 30 insertions(+)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0003-operand_equal_p-add-support-for-OBJ_TYPE_REF.patch --]
[-- Type: text/x-patch; name="0003-operand_equal_p-add-support-for-OBJ_TYPE_REF.patch", Size: 1576 bytes --]

diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 52414f7729e..4bcde22ada7 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -3323,6 +3323,27 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 	  flags &= ~OEP_ADDRESS_OF;
 	  return OP_SAME (1) && OP_SAME (2);
 
+	/* Virtual table call.  */
+	case OBJ_TYPE_REF:
+	  {
+	    if (!operand_equal_p (OBJ_TYPE_REF_EXPR (arg0),
+				  OBJ_TYPE_REF_EXPR (arg1), flags))
+	      return false;
+	    if (virtual_method_call_p (arg0))
+	      {
+		if (tree_to_uhwi (OBJ_TYPE_REF_TOKEN (arg0))
+		    != tree_to_uhwi (OBJ_TYPE_REF_TOKEN (arg1)))
+		  return false;
+		if (!types_same_for_odr (obj_type_ref_class (arg0),
+					 obj_type_ref_class (arg1)))
+		  return false;
+		if (!operand_equal_p (OBJ_TYPE_REF_OBJECT (arg0),
+				      OBJ_TYPE_REF_OBJECT (arg1), flags))
+		  return false;
+	      }
+	    return true;
+	  }
+
 	default:
 	  return false;
 	}
diff --git a/gcc/tree.c b/gcc/tree.c
index 91ebc9eddc4..2207f644fed 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -8011,6 +8011,15 @@ add_expr (const_tree t, inchash::hash &hstate, unsigned int flags)
 	      inchash::add_expr (TARGET_EXPR_SLOT (t), hstate, flags);
 	      return;
 
+	    /* Virtual table call.  */
+	    case OBJ_TYPE_REF:
+	      inchash::add_expr (OBJ_TYPE_REF_EXPR (t), hstate, flags);
+	      if (virtual_method_call_p (t))
+		{
+		  inchash::add_expr (OBJ_TYPE_REF_TOKEN (t), hstate, flags);
+		  inchash::add_expr (OBJ_TYPE_REF_OBJECT (t), hstate, flags);
+		}
+	      return;
 	    default:
 	      break;
 	    }

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

* Re: [PATCH 4/9] Strengthen alias_ptr_types_compatible_p in LTO mode.
  2019-08-06 15:43               ` [PATCH 4/9] Strengthen alias_ptr_types_compatible_p in LTO mode Martin Liska
@ 2019-08-07 12:05                 ` Richard Biener
  2019-08-08 12:09                   ` Martin Liška
  0 siblings, 1 reply; 59+ messages in thread
From: Richard Biener @ 2019-08-07 12:05 UTC (permalink / raw)
  To: Martin Liska; +Cc: GCC Patches

On Tue, Aug 6, 2019 at 5:43 PM Martin Liska <mliska@suse.cz> wrote:

This warrants a comment like

  /* This function originally abstracts from simply comparing
get_deref_alias_set
     so that we are sure this still computes the same result after LTO
type merging
     is applied.  When in LTO type merging is done we can actually do
this compare.  */
  if (in_lto_p)
    return get_deref_alias_set (t1) == get_deref_alias_set (t2);
...

also note you want to call get_deref_alias_set as mentioned in the
function comment.

OK with this change.

Thanks,
Richard.

> gcc/ChangeLog:
>
> 2019-07-24  Martin Liska  <mliska@suse.cz>
>
>         * alias.c (alias_ptr_types_compatible_p): Strengten
>         type comparison in LTO mode.
> ---
>  gcc/alias.c | 7 +++++--
>  1 file changed, 5 insertions(+), 2 deletions(-)
>

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

* Re: [PATCH 3/9] operand_equal_p: add support for OBJ_TYPE_REF.
  2019-08-06 15:55               ` [PATCH 3/9] operand_equal_p: add support for OBJ_TYPE_REF Martin Liska
@ 2019-08-07 12:09                 ` Richard Biener
  2019-08-15 15:44                   ` Jan Hubicka
  0 siblings, 1 reply; 59+ messages in thread
From: Richard Biener @ 2019-08-07 12:09 UTC (permalink / raw)
  To: Martin Liska; +Cc: GCC Patches

On Tue, Aug 6, 2019 at 5:43 PM Martin Liska <mliska@suse.cz> wrote:
>
>
> gcc/ChangeLog:

+       /* Virtual table call.  */
+       case OBJ_TYPE_REF:
+         {
+           if (!operand_equal_p (OBJ_TYPE_REF_EXPR (arg0),
+                                 OBJ_TYPE_REF_EXPR (arg1), flags))
+             return false;
+           if (virtual_method_call_p (arg0))
+             {
+               if (tree_to_uhwi (OBJ_TYPE_REF_TOKEN (arg0))
+                   != tree_to_uhwi (OBJ_TYPE_REF_TOKEN (arg1)))
+                 return false;
+               if (!types_same_for_odr (obj_type_ref_class (arg0),
+                                        obj_type_ref_class (arg1)))
+                 return false;
+               if (!operand_equal_p (OBJ_TYPE_REF_OBJECT (arg0),
+                                     OBJ_TYPE_REF_OBJECT (arg1), flags))
+                 return false;

this all gets deep into the devirt machinery, including looking at
ODR type hashes.  So I'm not sure if we really want to handle
it this "optimistic" in operand_equal_p and completely ignore
other operands when !virtual_method_call_p?  That is, why
not compare OBJ_TYPE_REF_TOKEN/OBJECT always at least?

Do we then have cases where the OBJ_TYPE_REF is actually
distinct according to the remaining check?

+             }


> 2019-07-24  Martin Liska  <mliska@suse.cz>
>
>         * fold-const.c (operand_equal_p): Support OBJ_TYPE_REF.
>         * tree.c (add_expr): Hash parts of OBJ_TYPE_REF.
> ---
>  gcc/fold-const.c | 21 +++++++++++++++++++++
>  gcc/tree.c       |  9 +++++++++
>  2 files changed, 30 insertions(+)
>

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

* Re: [PATCH 2/9] operand_equal_p: add support for FIELD_DECL
  2019-08-06 15:43               ` [PATCH 2/9] operand_equal_p: add support for FIELD_DECL Martin Liska
@ 2019-08-07 12:21                 ` Richard Biener
  2019-08-15 14:19                   ` Jan Hubicka
  0 siblings, 1 reply; 59+ messages in thread
From: Richard Biener @ 2019-08-07 12:21 UTC (permalink / raw)
  To: Martin Liska, Jan Hubicka; +Cc: GCC Patches

On Tue, Aug 6, 2019 at 5:44 PM Martin Liska <mliska@suse.cz> wrote:
>
>
> gcc/ChangeLog:

So I suppose this isn't to call operand_equal_p on two FIELD_DECLs
but to make two COMPONENT_REFs "more equal"?  If so I then
I suggest to make this change "local" to the COMPONENT_REF handling.
This also interacts with path-based disambiguation so you want to make
sure to only make things equal here iff it wouldn't change the outcome
of path-based analysis.  Honza?

Richard.

> 2019-07-24  Martin Liska  <mliska@suse.cz>
>
>         * fold-const.c (operand_equal_p): Support FIELD_DECL
>         as well.
>         * tree.c (add_expr): Hast DECL_FIELD_OFFSET and
>         DECL_FIELD_BIT_OFFSET for FIELD_DECL.
>
> gcc/testsuite/ChangeLog:
>
> 2019-07-24  Martin Liska  <mliska@suse.cz>
>
>         * gcc.dg/vect/vect-35-big-array.c: Vectorize one more loop.
>         * gcc.dg/vect/vect-35.c: Likewise.
>         * gcc.dg/pr70740.c: Move from torture and set -O2.
>         * gfortran.dg/vect/vect-8.f90: Update scanned pattern.
> ---
>  gcc/fold-const.c                              | 34 ++++++++++++++++---
>  gcc/testsuite/gcc.dg/{torture => }/pr70740.c  |  3 +-
>  gcc/testsuite/gcc.dg/vect/vect-35-big-array.c |  3 +-
>  gcc/testsuite/gcc.dg/vect/vect-35.c           |  3 +-
>  gcc/testsuite/gfortran.dg/vect/vect-8.f90     |  2 +-
>  gcc/tree.c                                    |  4 +++
>  6 files changed, 38 insertions(+), 11 deletions(-)
>  rename gcc/testsuite/gcc.dg/{torture => }/pr70740.c (77%)
>

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

* Re: [PATCH 1/9] Replace int with boolean in predicate functions.
  2019-08-06 15:43               ` [PATCH 1/9] Replace int with boolean in predicate functions Martin Liska
@ 2019-08-07 12:38                 ` Richard Biener
  0 siblings, 0 replies; 59+ messages in thread
From: Richard Biener @ 2019-08-07 12:38 UTC (permalink / raw)
  To: Martin Liska; +Cc: GCC Patches

On Tue, Aug 6, 2019 at 5:45 PM Martin Liska <mliska@suse.cz> wrote:
>
>
> gcc/ChangeLog:

OK.

Richard.

> 2019-07-24  Martin Liska  <mliska@suse.cz>
>
>         * fold-const.c (twoval_comparison_p): Replace int
>         with bool as a return type.
>         (simple_operand_p): Likewise.
>         (operand_equal_p): Replace int with bool as a return type.
>         * fold-const.h (operand_equal_p): Likewise.
> ---
>  gcc/fold-const.c | 148 +++++++++++++++++++++++------------------------
>  gcc/fold-const.h |   2 +-
>  2 files changed, 75 insertions(+), 75 deletions(-)
>

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

* Re: [PATCH 9/9] Remove alias set comparison.
  2019-08-06 15:43               ` [PATCH 9/9] Remove alias set comparison Martin Liska
@ 2019-08-07 15:58                 ` Martin Sebor
  2019-08-08  8:43                   ` Martin Liška
  2019-08-08 14:44                 ` Jeff Law
  1 sibling, 1 reply; 59+ messages in thread
From: Martin Sebor @ 2019-08-07 15:58 UTC (permalink / raw)
  To: Martin Liska, gcc-patches

On 6/11/19 1:36 AM, Martin Liska wrote:
> 
> gcc/ChangeLog:
> 
> 2019-07-24  Martin Liska  <mliska@suse.cz>
> 
> 	* ipa-icf-gimple.c (func_checker::compatible_types_p):
> 	Do not compare alias sets.  It's handled by operand_equal_p.
> 
> gcc/testsuite/ChangeLog:
> 
> 2019-07-24  Martin Liska  <mliska@suse.cz>
> 
> 	* c-c++-common/Wstringop-truncation-4.c: Disable IPA ICF.

What fails without the change?

Thanks
Martin

> 	* gcc.dg/tree-ssa/pr64910-2.c: Likewise.
> 	* gcc.dg/tree-ssa/pr79352.c: Likewise.
> 	* gcc.dg/ipa/ipa-icf-40.c: New test.
> ---
>   gcc/ipa-icf-gimple.c                          | 12 -------
>   .../c-c++-common/Wstringop-truncation-4.c     |  2 +-
>   gcc/testsuite/gcc.dg/ipa/ipa-icf-40.c         | 32 +++++++++++++++++++
>   gcc/testsuite/gcc.dg/tree-ssa/pr64910-2.c     |  2 +-
>   gcc/testsuite/gcc.dg/tree-ssa/pr79352.c       |  2 +-
>   5 files changed, 35 insertions(+), 15 deletions(-)
>   create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-icf-40.c
> 

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

* Re: [PATCH 9/9] Remove alias set comparison.
  2019-08-07 15:58                 ` Martin Sebor
@ 2019-08-08  8:43                   ` Martin Liška
  2019-08-08 15:21                     ` Martin Sebor
  0 siblings, 1 reply; 59+ messages in thread
From: Martin Liška @ 2019-08-08  8:43 UTC (permalink / raw)
  To: Martin Sebor, gcc-patches

On 8/7/19 5:20 PM, Martin Sebor wrote:
> On 6/11/19 1:36 AM, Martin Liska wrote:
>>
>> gcc/ChangeLog:
>>
>> 2019-07-24  Martin Liska  <mliska@suse.cz>
>>
>>     * ipa-icf-gimple.c (func_checker::compatible_types_p):
>>     Do not compare alias sets.  It's handled by operand_equal_p.
>>
>> gcc/testsuite/ChangeLog:
>>
>> 2019-07-24  Martin Liska  <mliska@suse.cz>
>>
>>     * c-c++-common/Wstringop-truncation-4.c: Disable IPA ICF.
> 
> What fails without the change?

ICF will newly merge these functions:

grep hit: Wstringop-truncation-4.c.070i.icf 
Semantic equality hit:void test_arrays(Arrays*, const char*)->void test_const_arrays(ConstArrays*, const char*)
Semantic equality hit:void test_arrays(Arrays*, const char*)->void test_volatile_arrays(VolatileArrays*, const char*)
Semantic equality hit:void test_arrays(Arrays*, const char*)->void test_const_volatile_arrays(ConstVolatileArrays*, const char*)

So we'll get less warnings than expected.

Martin

> 
> Thanks
> Martin
> 
>>     * gcc.dg/tree-ssa/pr64910-2.c: Likewise.
>>     * gcc.dg/tree-ssa/pr79352.c: Likewise.
>>     * gcc.dg/ipa/ipa-icf-40.c: New test.
>> ---
>>   gcc/ipa-icf-gimple.c                          | 12 -------
>>   .../c-c++-common/Wstringop-truncation-4.c     |  2 +-
>>   gcc/testsuite/gcc.dg/ipa/ipa-icf-40.c         | 32 +++++++++++++++++++
>>   gcc/testsuite/gcc.dg/tree-ssa/pr64910-2.c     |  2 +-
>>   gcc/testsuite/gcc.dg/tree-ssa/pr79352.c       |  2 +-
>>   5 files changed, 35 insertions(+), 15 deletions(-)
>>   create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-icf-40.c
>>
> 

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

* Re: [PATCH 4/9] Strengthen alias_ptr_types_compatible_p in LTO mode.
  2019-08-07 12:05                 ` Richard Biener
@ 2019-08-08 12:09                   ` Martin Liška
  2019-08-09 11:20                     ` Richard Biener
  0 siblings, 1 reply; 59+ messages in thread
From: Martin Liška @ 2019-08-08 12:09 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches

[-- Attachment #1: Type: text/plain, Size: 1009 bytes --]

On 8/7/19 1:57 PM, Richard Biener wrote:
> On Tue, Aug 6, 2019 at 5:43 PM Martin Liska <mliska@suse.cz> wrote:
> 
> This warrants a comment like
> 
>   /* This function originally abstracts from simply comparing
> get_deref_alias_set
>      so that we are sure this still computes the same result after LTO
> type merging
>      is applied.  When in LTO type merging is done we can actually do
> this compare.  */
>   if (in_lto_p)
>     return get_deref_alias_set (t1) == get_deref_alias_set (t2);
> ...
> 
> also note you want to call get_deref_alias_set as mentioned in the
> function comment.

Thanks for review.

Hope it's addressed in the attached patch that I've just tested?

Martin

> 
> OK with this change.
> 
> Thanks,
> Richard.
> 
>> gcc/ChangeLog:
>>
>> 2019-07-24  Martin Liska  <mliska@suse.cz>
>>
>>         * alias.c (alias_ptr_types_compatible_p): Strengten
>>         type comparison in LTO mode.
>> ---
>>  gcc/alias.c | 7 +++++--
>>  1 file changed, 5 insertions(+), 2 deletions(-)
>>


[-- Attachment #2: 0001-Strengthen-alias_ptr_types_compatible_p-in-LTO-mode.patch --]
[-- Type: text/x-patch, Size: 1293 bytes --]

From bedcf4da9f352674390304bed1e71b79c5c28cc5 Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Tue, 4 Jun 2019 13:30:32 +0200
Subject: [PATCH] Strengthen alias_ptr_types_compatible_p in LTO mode.

gcc/ChangeLog:

2019-07-24  Martin Liska  <mliska@suse.cz>

	* alias.c (alias_ptr_types_compatible_p): Strengten
	type comparison in LTO mode.
---
 gcc/alias.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/gcc/alias.c b/gcc/alias.c
index 2755df72907..1579dfa68a7 100644
--- a/gcc/alias.c
+++ b/gcc/alias.c
@@ -793,8 +793,16 @@ alias_ptr_types_compatible_p (tree t1, tree t2)
       || ref_all_alias_ptr_type_p (t2))
     return false;
 
-  return (TYPE_MAIN_VARIANT (TREE_TYPE (t1))
-	  == TYPE_MAIN_VARIANT (TREE_TYPE (t2)));
+    /* This function originally abstracts from simply comparing
+       get_deref_alias_set so that we are sure this still computes
+       the same result after LTO type merging is applied.
+       When in LTO type merging is done we can actually do this compare.
+    */
+  if (in_lto_p)
+    return get_deref_alias_set (t1) == get_deref_alias_set (t2);
+  else
+    return (TYPE_MAIN_VARIANT (TREE_TYPE (t1))
+	    == TYPE_MAIN_VARIANT (TREE_TYPE (t2)));
 }
 
 /* Create emptry alias set entry.  */
-- 
2.22.0


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

* Re: [PATCH 9/9] Remove alias set comparison.
  2019-08-06 15:43               ` [PATCH 9/9] Remove alias set comparison Martin Liska
  2019-08-07 15:58                 ` Martin Sebor
@ 2019-08-08 14:44                 ` Jeff Law
  1 sibling, 0 replies; 59+ messages in thread
From: Jeff Law @ 2019-08-08 14:44 UTC (permalink / raw)
  To: Martin Liska, gcc-patches

On 6/11/19 1:36 AM, Martin Liska wrote:
> 
> gcc/ChangeLog:
> 
> 2019-07-24  Martin Liska  <mliska@suse.cz>
> 
> 	* ipa-icf-gimple.c (func_checker::compatible_types_p):
> 	Do not compare alias sets.  It's handled by operand_equal_p.
> 
> gcc/testsuite/ChangeLog:
> 
> 2019-07-24  Martin Liska  <mliska@suse.cz>
> 
> 	* c-c++-common/Wstringop-truncation-4.c: Disable IPA ICF.
> 	* gcc.dg/tree-ssa/pr64910-2.c: Likewise.
> 	* gcc.dg/tree-ssa/pr79352.c: Likewise.
> 	* gcc.dg/ipa/ipa-icf-40.c: New test.
OK for the trunk once any prereqs are approved.

jeff

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

* Re: [PATCH 7/9] IPA ICF: remove dead code
  2019-08-06 15:43               ` [PATCH 7/9] IPA ICF: remove dead code Martin Liska
@ 2019-08-08 14:44                 ` Jeff Law
  0 siblings, 0 replies; 59+ messages in thread
From: Jeff Law @ 2019-08-08 14:44 UTC (permalink / raw)
  To: Martin Liska, gcc-patches

On 7/24/19 6:24 AM, Martin Liska wrote:
> 
> gcc/ChangeLog:
> 
> 2019-07-24  Martin Liska  <mliska@suse.cz>
> 
> 	* ipa-icf-gimple.c (func_checker::compare_ssa_name): Call
> 	compare_operand.
> 	(func_checker::compare_memory_operand): Remove.
> 	(func_checker::compare_cst_or_decl): Remove.
> 	(func_checker::operand_equal_valueize): Do not handle
> 	FIELD_DECL.
> 	(func_checker::compare_gimple_call): Call compare_operand.
> 	(func_checker::compare_gimple_assign): Likewise.
> 	* ipa-icf-gimple.h: Remove compare_cst_or_decl.
> 	* ipa-icf.c (sem_function::icf_handled_component_p): Remove.
> 	* ipa-icf.h (icf_handled_component_p): Remove.
> ---
>  gcc/ipa-icf-gimple.c | 150 ++-----------------------------------------
>  gcc/ipa-icf-gimple.h |   4 --
>  gcc/ipa-icf.c        |  11 ----
>  gcc/ipa-icf.h        |   3 -
>  4 files changed, 6 insertions(+), 162 deletions(-)
> 

OK for the trunk once any prereqs are approved.
Jeff

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

* Re: [PATCH 9/9] Remove alias set comparison.
  2019-08-08  8:43                   ` Martin Liška
@ 2019-08-08 15:21                     ` Martin Sebor
  0 siblings, 0 replies; 59+ messages in thread
From: Martin Sebor @ 2019-08-08 15:21 UTC (permalink / raw)
  To: Martin Liška, gcc-patches

On 8/8/19 2:14 AM, Martin Liška wrote:
> On 8/7/19 5:20 PM, Martin Sebor wrote:
>> On 6/11/19 1:36 AM, Martin Liska wrote:
>>>
>>> gcc/ChangeLog:
>>>
>>> 2019-07-24  Martin Liska  <mliska@suse.cz>
>>>
>>>      * ipa-icf-gimple.c (func_checker::compatible_types_p):
>>>      Do not compare alias sets.  It's handled by operand_equal_p.
>>>
>>> gcc/testsuite/ChangeLog:
>>>
>>> 2019-07-24  Martin Liska  <mliska@suse.cz>
>>>
>>>      * c-c++-common/Wstringop-truncation-4.c: Disable IPA ICF.
>>
>> What fails without the change?
> 
> ICF will newly merge these functions:

I see.  I suppose the other alternatives are to either add
attribute noipa to the functions or make unique the string
each function copies so they can't be merged.

I have a mild preference for the last alternative but it's
your call.  If you decide to keep the option can you please
add a brief comment explaining why it's needed?

Thanks
Martin

> 
> grep hit: Wstringop-truncation-4.c.070i.icf
> Semantic equality hit:void test_arrays(Arrays*, const char*)->void test_const_arrays(ConstArrays*, const char*)
> Semantic equality hit:void test_arrays(Arrays*, const char*)->void test_volatile_arrays(VolatileArrays*, const char*)
> Semantic equality hit:void test_arrays(Arrays*, const char*)->void test_const_volatile_arrays(ConstVolatileArrays*, const char*)
> 
> So we'll get less warnings than expected.
> 
> Martin
> 
>>
>> Thanks
>> Martin
>>
>>>      * gcc.dg/tree-ssa/pr64910-2.c: Likewise.
>>>      * gcc.dg/tree-ssa/pr79352.c: Likewise.
>>>      * gcc.dg/ipa/ipa-icf-40.c: New test.
>>> ---
>>>    gcc/ipa-icf-gimple.c                          | 12 -------
>>>    .../c-c++-common/Wstringop-truncation-4.c     |  2 +-
>>>    gcc/testsuite/gcc.dg/ipa/ipa-icf-40.c         | 32 +++++++++++++++++++
>>>    gcc/testsuite/gcc.dg/tree-ssa/pr64910-2.c     |  2 +-
>>>    gcc/testsuite/gcc.dg/tree-ssa/pr79352.c       |  2 +-
>>>    5 files changed, 35 insertions(+), 15 deletions(-)
>>>    create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-icf-40.c
>>>
>>
> 

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

* Re: [PATCH 5/9] Come up with an abstraction.
  2019-08-06 15:43               ` [PATCH 5/9] Come up with an abstraction Martin Liska
@ 2019-08-08 16:29                 ` Michael Matz
  2019-08-12 11:49                   ` Martin Liška
  2019-08-09 11:48                 ` Richard Biener
  1 sibling, 1 reply; 59+ messages in thread
From: Michael Matz @ 2019-08-08 16:29 UTC (permalink / raw)
  To: Martin Liska; +Cc: gcc-patches

Hi,

On Mon, 10 Jun 2019, Martin Liska wrote:

> 2019-07-24  Martin Liska  <mliska@suse.cz>
> 
> 	* fold-const.c (operand_equal_p): Rename to ...
> 	(operand_compare::operand_equal_p): ... this.
> 	(add_expr):  Rename to ...
> 	(operand_compare::hash_operand): ... this.
> 	(operand_compare::operand_equal_valueize): Likewise.
> 	(operand_compare::hash_operand_valueize): Likewise.
> 	* fold-const.h (operand_equal_p): Set default
> 	value for last argument.
> 	(class operand_compare): New.

Hmpf.  A class without any data?  That doesn't sound like a good design.  
You seem to need it only to have the possibility of virtual functions, 
i.e. fancy callbacks.  AFAICS you only have one derived class, i.e. a 
simple distinction of two cases.  What do you think about encoding the 
additional new (ICF) case in the (existing) 'flags' argument to 
operand_equal_p (and in case the ICF flag is set simply call the 
"callback" directly)?  IMHO that would also make the logic within 
operand_equal_p clearer, because you don't have to think about all the 
potential callback functions that might be called.


Ciao,
Michael.

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

* Re: [PATCH 4/9] Strengthen alias_ptr_types_compatible_p in LTO mode.
  2019-08-08 12:09                   ` Martin Liška
@ 2019-08-09 11:20                     ` Richard Biener
  0 siblings, 0 replies; 59+ messages in thread
From: Richard Biener @ 2019-08-09 11:20 UTC (permalink / raw)
  To: Martin Liška; +Cc: GCC Patches

On Thu, Aug 8, 2019 at 12:04 PM Martin Liška <mliska@suse.cz> wrote:
>
> On 8/7/19 1:57 PM, Richard Biener wrote:
> > On Tue, Aug 6, 2019 at 5:43 PM Martin Liska <mliska@suse.cz> wrote:
> >
> > This warrants a comment like
> >
> >   /* This function originally abstracts from simply comparing
> > get_deref_alias_set
> >      so that we are sure this still computes the same result after LTO
> > type merging
> >      is applied.  When in LTO type merging is done we can actually do
> > this compare.  */
> >   if (in_lto_p)
> >     return get_deref_alias_set (t1) == get_deref_alias_set (t2);
> > ...
> >
> > also note you want to call get_deref_alias_set as mentioned in the
> > function comment.
>
> Thanks for review.
>
> Hope it's addressed in the attached patch that I've just tested?

Yes.
Thanks,
Richard.

> Martim
>
> >
> > OK with this change.
> >
> > Thanks,
> > Richard.
> >
> >> gcc/ChangeLog:
> >>
> >> 2019-07-24  Martin Liska  <mliska@suse.cz>
> >>
> >>         * alias.c (alias_ptr_types_compatible_p): Strengten
> >>         type comparison in LTO mode.
> >> ---
> >>  gcc/alias.c | 7 +++++--
> >>  1 file changed, 5 insertions(+), 2 deletions(-)
> >>
>

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

* Re: [PATCH 5/9] Come up with an abstraction.
  2019-08-06 15:43               ` [PATCH 5/9] Come up with an abstraction Martin Liska
  2019-08-08 16:29                 ` Michael Matz
@ 2019-08-09 11:48                 ` Richard Biener
  1 sibling, 0 replies; 59+ messages in thread
From: Richard Biener @ 2019-08-09 11:48 UTC (permalink / raw)
  To: Martin Liska; +Cc: GCC Patches

On Tue, Aug 6, 2019 at 5:44 PM Martin Liska <mliska@suse.cz> wrote:
>
>
> gcc/ChangeLog:

Hum.  I don't like the "abstraction" - how is it going to help you to not
duplicate all the code?  What's wrong with doing this all in ICF?

Richard.

> 2019-07-24  Martin Liska  <mliska@suse.cz>
>
>         * fold-const.c (operand_equal_p): Rename to ...
>         (operand_compare::operand_equal_p): ... this.
>         (add_expr):  Rename to ...
>         (operand_compare::hash_operand): ... this.
>         (operand_compare::operand_equal_valueize): Likewise.
>         (operand_compare::hash_operand_valueize): Likewise.
>         * fold-const.h (operand_equal_p): Set default
>         value for last argument.
>         (class operand_compare): New.
>         * tree.c (add_expr): Move content to hash_operand.
> ---
>  gcc/fold-const.c | 346 ++++++++++++++++++++++++++++++++++++++++++++++-
>  gcc/fold-const.h |  30 +++-
>  gcc/tree.c       | 286 ---------------------------------------
>  3 files changed, 372 insertions(+), 290 deletions(-)
>

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

* Re: [PATCH 5/9] Come up with an abstraction.
  2019-08-08 16:29                 ` Michael Matz
@ 2019-08-12 11:49                   ` Martin Liška
  2019-08-12 12:27                     ` Richard Biener
  2019-08-12 13:40                     ` Michael Matz
  0 siblings, 2 replies; 59+ messages in thread
From: Martin Liška @ 2019-08-12 11:49 UTC (permalink / raw)
  To: Michael Matz; +Cc: gcc-patches

On 8/8/19 5:55 PM, Michael Matz wrote:
> Hi,
> 
> On Mon, 10 Jun 2019, Martin Liska wrote:
> 
>> 2019-07-24  Martin Liska  <mliska@suse.cz>
>>
>> 	* fold-const.c (operand_equal_p): Rename to ...
>> 	(operand_compare::operand_equal_p): ... this.
>> 	(add_expr):  Rename to ...
>> 	(operand_compare::hash_operand): ... this.
>> 	(operand_compare::operand_equal_valueize): Likewise.
>> 	(operand_compare::hash_operand_valueize): Likewise.
>> 	* fold-const.h (operand_equal_p): Set default
>> 	value for last argument.
>> 	(class operand_compare): New.
> 
> Hmpf.  A class without any data?  That doesn't sound like a good design.

Yes, the base class (current operand_equal_p) does not have a data.
But the ICF derive class has a data and e.g. func_checker::operand_equal_valueize
will use m_label_bb_map.get (t1). Which are member data of class func_checker.
  
> You seem to need it only to have the possibility of virtual functions, 
> i.e. fancy callbacks.  AFAICS you only have one derived class, i.e. a 
> simple distinction of two cases.  What do you think about encoding the 
> additional new (ICF) case in the (existing) 'flags' argument to 
> operand_equal_p (and in case the ICF flag is set simply call the 
> "callback" directly)?

That's possible. I can add two more callbacks to the operand_equal_p function
(hash_operand_valueize and operand_equal_valueize).

Is Richi also supporting this approach?
Thanks,
Martin

> IMHO that would also make the logic within 
> operand_equal_p clearer, because you don't have to think about all the 
> potential callback functions that might be called.
> 
> 
> Ciao,
> Michael.
> 

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

* Re: [PATCH 5/9] Come up with an abstraction.
  2019-08-12 11:49                   ` Martin Liška
@ 2019-08-12 12:27                     ` Richard Biener
  2019-08-12 12:43                       ` Martin Liška
  2019-08-12 13:40                     ` Michael Matz
  1 sibling, 1 reply; 59+ messages in thread
From: Richard Biener @ 2019-08-12 12:27 UTC (permalink / raw)
  To: Martin Liška; +Cc: Michael Matz, GCC Patches

On Mon, Aug 12, 2019 at 1:19 PM Martin Liška <mliska@suse.cz> wrote:
>
> On 8/8/19 5:55 PM, Michael Matz wrote:
> > Hi,
> >
> > On Mon, 10 Jun 2019, Martin Liska wrote:
> >
> >> 2019-07-24  Martin Liska  <mliska@suse.cz>
> >>
> >>      * fold-const.c (operand_equal_p): Rename to ...
> >>      (operand_compare::operand_equal_p): ... this.
> >>      (add_expr):  Rename to ...
> >>      (operand_compare::hash_operand): ... this.
> >>      (operand_compare::operand_equal_valueize): Likewise.
> >>      (operand_compare::hash_operand_valueize): Likewise.
> >>      * fold-const.h (operand_equal_p): Set default
> >>      value for last argument.
> >>      (class operand_compare): New.
> >
> > Hmpf.  A class without any data?  That doesn't sound like a good design.
>
> Yes, the base class (current operand_equal_p) does not have a data.
> But the ICF derive class has a data and e.g. func_checker::operand_equal_valueize
> will use m_label_bb_map.get (t1). Which are member data of class func_checker.
>
> > You seem to need it only to have the possibility of virtual functions,
> > i.e. fancy callbacks.  AFAICS you only have one derived class, i.e. a
> > simple distinction of two cases.  What do you think about encoding the
> > additional new (ICF) case in the (existing) 'flags' argument to
> > operand_equal_p (and in case the ICF flag is set simply call the
> > "callback" directly)?
>
> That's possible. I can add two more callbacks to the operand_equal_p function
> (hash_operand_valueize and operand_equal_valueize).
>
> Is Richi also supporting this approach?

I still see no value in the abstraction since you invoke none of the
(virtual) methods from the base class operand_equal_p.

Richard.

> Thanks,
> Martin
>
> > IMHO that would also make the logic within
> > operand_equal_p clearer, because you don't have to think about all the
> > potential callback functions that might be called.
> >
> >
> > Ciao,
> > Michael.
> >
>

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

* Re: [PATCH 5/9] Come up with an abstraction.
  2019-08-12 12:27                     ` Richard Biener
@ 2019-08-12 12:43                       ` Martin Liška
  2019-08-12 13:26                         ` Richard Biener
  0 siblings, 1 reply; 59+ messages in thread
From: Martin Liška @ 2019-08-12 12:43 UTC (permalink / raw)
  To: Richard Biener; +Cc: Michael Matz, GCC Patches

On 8/12/19 1:40 PM, Richard Biener wrote:
> On Mon, Aug 12, 2019 at 1:19 PM Martin Liška <mliska@suse.cz> wrote:
>>
>> On 8/8/19 5:55 PM, Michael Matz wrote:
>>> Hi,
>>>
>>> On Mon, 10 Jun 2019, Martin Liska wrote:
>>>
>>>> 2019-07-24  Martin Liska  <mliska@suse.cz>
>>>>
>>>>      * fold-const.c (operand_equal_p): Rename to ...
>>>>      (operand_compare::operand_equal_p): ... this.
>>>>      (add_expr):  Rename to ...
>>>>      (operand_compare::hash_operand): ... this.
>>>>      (operand_compare::operand_equal_valueize): Likewise.
>>>>      (operand_compare::hash_operand_valueize): Likewise.
>>>>      * fold-const.h (operand_equal_p): Set default
>>>>      value for last argument.
>>>>      (class operand_compare): New.
>>>
>>> Hmpf.  A class without any data?  That doesn't sound like a good design.
>>
>> Yes, the base class (current operand_equal_p) does not have a data.
>> But the ICF derive class has a data and e.g. func_checker::operand_equal_valueize
>> will use m_label_bb_map.get (t1). Which are member data of class func_checker.
>>
>>> You seem to need it only to have the possibility of virtual functions,
>>> i.e. fancy callbacks.  AFAICS you only have one derived class, i.e. a
>>> simple distinction of two cases.  What do you think about encoding the
>>> additional new (ICF) case in the (existing) 'flags' argument to
>>> operand_equal_p (and in case the ICF flag is set simply call the
>>> "callback" directly)?
>>
>> That's possible. I can add two more callbacks to the operand_equal_p function
>> (hash_operand_valueize and operand_equal_valueize).
>>
>> Is Richi also supporting this approach?
> 
> I still see no value in the abstraction since you invoke none of the
> (virtual) methods from the base class operand_equal_p.

I call operand_equal_valueize (and hash_operand) from operand_equal_p.
These are then used in IPA ICF (patch 6/9).

Martin

> 
> Richard.
> 
>> Thanks,
>> Martin
>>
>>> IMHO that would also make the logic within
>>> operand_equal_p clearer, because you don't have to think about all the
>>> potential callback functions that might be called.
>>>
>>>
>>> Ciao,
>>> Michael.
>>>
>>

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

* Re: [PATCH 5/9] Come up with an abstraction.
  2019-08-12 12:43                       ` Martin Liška
@ 2019-08-12 13:26                         ` Richard Biener
  2019-08-12 14:48                           ` Martin Liška
  0 siblings, 1 reply; 59+ messages in thread
From: Richard Biener @ 2019-08-12 13:26 UTC (permalink / raw)
  To: Martin Liška; +Cc: Michael Matz, GCC Patches

On Mon, Aug 12, 2019 at 1:49 PM Martin Liška <mliska@suse.cz> wrote:
>
> On 8/12/19 1:40 PM, Richard Biener wrote:
> > On Mon, Aug 12, 2019 at 1:19 PM Martin Liška <mliska@suse.cz> wrote:
> >>
> >> On 8/8/19 5:55 PM, Michael Matz wrote:
> >>> Hi,
> >>>
> >>> On Mon, 10 Jun 2019, Martin Liska wrote:
> >>>
> >>>> 2019-07-24  Martin Liska  <mliska@suse.cz>
> >>>>
> >>>>      * fold-const.c (operand_equal_p): Rename to ...
> >>>>      (operand_compare::operand_equal_p): ... this.
> >>>>      (add_expr):  Rename to ...
> >>>>      (operand_compare::hash_operand): ... this.
> >>>>      (operand_compare::operand_equal_valueize): Likewise.
> >>>>      (operand_compare::hash_operand_valueize): Likewise.
> >>>>      * fold-const.h (operand_equal_p): Set default
> >>>>      value for last argument.
> >>>>      (class operand_compare): New.
> >>>
> >>> Hmpf.  A class without any data?  That doesn't sound like a good design.
> >>
> >> Yes, the base class (current operand_equal_p) does not have a data.
> >> But the ICF derive class has a data and e.g. func_checker::operand_equal_valueize
> >> will use m_label_bb_map.get (t1). Which are member data of class func_checker.
> >>
> >>> You seem to need it only to have the possibility of virtual functions,
> >>> i.e. fancy callbacks.  AFAICS you only have one derived class, i.e. a
> >>> simple distinction of two cases.  What do you think about encoding the
> >>> additional new (ICF) case in the (existing) 'flags' argument to
> >>> operand_equal_p (and in case the ICF flag is set simply call the
> >>> "callback" directly)?
> >>
> >> That's possible. I can add two more callbacks to the operand_equal_p function
> >> (hash_operand_valueize and operand_equal_valueize).
> >>
> >> Is Richi also supporting this approach?
> >
> > I still see no value in the abstraction since you invoke none of the
> > (virtual) methods from the base class operand_equal_p.
>
> I call operand_equal_valueize (and hash_operand) from operand_equal_p.
> These are then used in IPA ICF (patch 6/9).

Ugh.  I see you call that after

  if (TREE_CODE (arg0) != TREE_CODE (arg1))
    {
...
        }
      else
        return false;
    }

and also after

  /* Check equality of integer constants before bailing out due to
     precision differences.  */
  if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)

which means for arg0 == SSA_NAME and arg1 == INTEGER_CST you return false
instead of valueizing arg0 to the possibly same or same "lose" value
and returning true.

Also

+  int val = operand_equal_valueize (arg0, arg1, flags);
+  if (val == 1)
+    return 1;
+  if (val == 0)
+    return 0;

suggests that you pass in arbirtrary trees for "valueization" but it
isn't actually
valueization that is performed but instead it should do an alternate comparison
of arg0 and arg1 with valueization.  Why's this done this way instead of
sth like

  if (TREE_CODE (arg0) == SSA_NAME)
   arg0 = operand_equal_valueize (arg0, flags);
 if (TREE_CODE (arg1) == SSA_NAME)
   arg1 = operand_equal_valueize (arg1, flags);

and why's this done with virtual functions rather than a callback that we can
cheaply check for NULLness in the default implementation?

So - what does ICF want to make "equal" that isn't equal normally and how's
that "valueization"?

Thanks,
Richard.

> Martin
>
> >
> > Richard.
> >
> >> Thanks,
> >> Martin
> >>
> >>> IMHO that would also make the logic within
> >>> operand_equal_p clearer, because you don't have to think about all the
> >>> potential callback functions that might be called.
> >>>
> >>>
> >>> Ciao,
> >>> Michael.
> >>>
> >>
>

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

* Re: [PATCH 5/9] Come up with an abstraction.
  2019-08-12 11:49                   ` Martin Liška
  2019-08-12 12:27                     ` Richard Biener
@ 2019-08-12 13:40                     ` Michael Matz
  1 sibling, 0 replies; 59+ messages in thread
From: Michael Matz @ 2019-08-12 13:40 UTC (permalink / raw)
  To: Martin Liška; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 848 bytes --]

Hi,

On Mon, 12 Aug 2019, Martin Liška wrote:

> > You seem to need it only to have the possibility of virtual functions, 
> > i.e. fancy callbacks.  AFAICS you only have one derived class, i.e. a 
> > simple distinction of two cases.  What do you think about encoding the 
> > additional new (ICF) case in the (existing) 'flags' argument to 
> > operand_equal_p (and in case the ICF flag is set simply call the 
> > "callback" directly)?
> 
> That's possible. I can add two more callbacks to the operand_equal_p 
> function (hash_operand_valueize and operand_equal_valueize).

That's premature; why provide callbacks when it's always either NULL or 
a single value?  What I meant is put code like this into operand_equal_p:

  if (flags & OE_FOR_ICF)
    op0 = oep_icf_valueize (op0);
    ...

Less indirection, less confusion.


Ciao,
Michael.

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

* Re: [PATCH 5/9] Come up with an abstraction.
  2019-08-12 13:26                         ` Richard Biener
@ 2019-08-12 14:48                           ` Martin Liška
  2019-08-14 13:17                             ` Richard Biener
  0 siblings, 1 reply; 59+ messages in thread
From: Martin Liška @ 2019-08-12 14:48 UTC (permalink / raw)
  To: Richard Biener; +Cc: Michael Matz, GCC Patches

On 8/12/19 2:43 PM, Richard Biener wrote:
> On Mon, Aug 12, 2019 at 1:49 PM Martin Liška <mliska@suse.cz> wrote:
>>
>> On 8/12/19 1:40 PM, Richard Biener wrote:
>>> On Mon, Aug 12, 2019 at 1:19 PM Martin Liška <mliska@suse.cz> wrote:
>>>>
>>>> On 8/8/19 5:55 PM, Michael Matz wrote:
>>>>> Hi,
>>>>>
>>>>> On Mon, 10 Jun 2019, Martin Liska wrote:
>>>>>
>>>>>> 2019-07-24  Martin Liska  <mliska@suse.cz>
>>>>>>
>>>>>>      * fold-const.c (operand_equal_p): Rename to ...
>>>>>>      (operand_compare::operand_equal_p): ... this.
>>>>>>      (add_expr):  Rename to ...
>>>>>>      (operand_compare::hash_operand): ... this.
>>>>>>      (operand_compare::operand_equal_valueize): Likewise.
>>>>>>      (operand_compare::hash_operand_valueize): Likewise.
>>>>>>      * fold-const.h (operand_equal_p): Set default
>>>>>>      value for last argument.
>>>>>>      (class operand_compare): New.
>>>>>
>>>>> Hmpf.  A class without any data?  That doesn't sound like a good design.
>>>>
>>>> Yes, the base class (current operand_equal_p) does not have a data.
>>>> But the ICF derive class has a data and e.g. func_checker::operand_equal_valueize
>>>> will use m_label_bb_map.get (t1). Which are member data of class func_checker.
>>>>
>>>>> You seem to need it only to have the possibility of virtual functions,
>>>>> i.e. fancy callbacks.  AFAICS you only have one derived class, i.e. a
>>>>> simple distinction of two cases.  What do you think about encoding the
>>>>> additional new (ICF) case in the (existing) 'flags' argument to
>>>>> operand_equal_p (and in case the ICF flag is set simply call the
>>>>> "callback" directly)?
>>>>
>>>> That's possible. I can add two more callbacks to the operand_equal_p function
>>>> (hash_operand_valueize and operand_equal_valueize).
>>>>
>>>> Is Richi also supporting this approach?
>>>
>>> I still see no value in the abstraction since you invoke none of the
>>> (virtual) methods from the base class operand_equal_p.
>>
>> I call operand_equal_valueize (and hash_operand) from operand_equal_p.
>> These are then used in IPA ICF (patch 6/9).
> 
> Ugh.  I see you call that after
> 
>   if (TREE_CODE (arg0) != TREE_CODE (arg1))
>     {
> ...
>         }
>       else
>         return false;
>     }
> 
> and also after
> 
>   /* Check equality of integer constants before bailing out due to
>      precision differences.  */
>   if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
> 
> which means for arg0 == SSA_NAME and arg1 == INTEGER_CST you return false
> instead of valueizing arg0 to the possibly same or same "lose" value
> and returning true.

Yes. ICF does not allow to have anything where TREE_CODEs do not match.

> 
> Also
> 
> +  int val = operand_equal_valueize (arg0, arg1, flags);
> +  if (val == 1)
> +    return 1;
> +  if (val == 0)
> +    return 0;
> 
> suggests that you pass in arbirtrary trees for "valueization" but it
> isn't actually
> valueization that is performed but instead it should do an alternate comparison
> of arg0 and arg1 with valueization.  Why's this done this way instead of
> sth like
> 
>   if (TREE_CODE (arg0) == SSA_NAME)
>    arg0 = operand_equal_valueize (arg0, flags);
>  if (TREE_CODE (arg1) == SSA_NAME)
>    arg1 = operand_equal_valueize (arg1, flags);

Because I want to be given a pair of trees about which the function
operand_equal_valueize returns match/no-match/dunno.

> 
> and why's this done with virtual functions rather than a callback that we can
> cheaply check for NULLness in the default implementation?

I can transform it into a hook. But as mentioned I'll need two hooks.

> 
> So - what does ICF want to make "equal" that isn't equal normally and how's
> that "valueization"?

E.g. for a FUNCTION_DECL, ICF always return true because it can only calls
the operand_equal_p after callgraph is compared. Similarly for LABEL_DECLs,
we have a map (m_label_bb_map). Please take a look at patch 6/9 in this
series.

Thanks,
Martin

> 
> Thanks,
> Richard.
> 
>> Martin
>>
>>>
>>> Richard.
>>>
>>>> Thanks,
>>>> Martin
>>>>
>>>>> IMHO that would also make the logic within
>>>>> operand_equal_p clearer, because you don't have to think about all the
>>>>> potential callback functions that might be called.
>>>>>
>>>>>
>>>>> Ciao,
>>>>> Michael.
>>>>>
>>>>
>>

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

* Re: [PATCH 5/9] Come up with an abstraction.
  2019-08-12 14:48                           ` Martin Liška
@ 2019-08-14 13:17                             ` Richard Biener
  2019-08-14 13:50                               ` Martin Liška
  0 siblings, 1 reply; 59+ messages in thread
From: Richard Biener @ 2019-08-14 13:17 UTC (permalink / raw)
  To: Martin Liška; +Cc: Michael Matz, GCC Patches

On Mon, Aug 12, 2019 at 3:56 PM Martin Liška <mliska@suse.cz> wrote:
>
> On 8/12/19 2:43 PM, Richard Biener wrote:
> > On Mon, Aug 12, 2019 at 1:49 PM Martin Liška <mliska@suse.cz> wrote:
> >>
> >> On 8/12/19 1:40 PM, Richard Biener wrote:
> >>> On Mon, Aug 12, 2019 at 1:19 PM Martin Liška <mliska@suse.cz> wrote:
> >>>>
> >>>> On 8/8/19 5:55 PM, Michael Matz wrote:
> >>>>> Hi,
> >>>>>
> >>>>> On Mon, 10 Jun 2019, Martin Liska wrote:
> >>>>>
> >>>>>> 2019-07-24  Martin Liska  <mliska@suse.cz>
> >>>>>>
> >>>>>>      * fold-const.c (operand_equal_p): Rename to ...
> >>>>>>      (operand_compare::operand_equal_p): ... this.
> >>>>>>      (add_expr):  Rename to ...
> >>>>>>      (operand_compare::hash_operand): ... this.
> >>>>>>      (operand_compare::operand_equal_valueize): Likewise.
> >>>>>>      (operand_compare::hash_operand_valueize): Likewise.
> >>>>>>      * fold-const.h (operand_equal_p): Set default
> >>>>>>      value for last argument.
> >>>>>>      (class operand_compare): New.
> >>>>>
> >>>>> Hmpf.  A class without any data?  That doesn't sound like a good design.
> >>>>
> >>>> Yes, the base class (current operand_equal_p) does not have a data.
> >>>> But the ICF derive class has a data and e.g. func_checker::operand_equal_valueize
> >>>> will use m_label_bb_map.get (t1). Which are member data of class func_checker.
> >>>>
> >>>>> You seem to need it only to have the possibility of virtual functions,
> >>>>> i.e. fancy callbacks.  AFAICS you only have one derived class, i.e. a
> >>>>> simple distinction of two cases.  What do you think about encoding the
> >>>>> additional new (ICF) case in the (existing) 'flags' argument to
> >>>>> operand_equal_p (and in case the ICF flag is set simply call the
> >>>>> "callback" directly)?
> >>>>
> >>>> That's possible. I can add two more callbacks to the operand_equal_p function
> >>>> (hash_operand_valueize and operand_equal_valueize).
> >>>>
> >>>> Is Richi also supporting this approach?
> >>>
> >>> I still see no value in the abstraction since you invoke none of the
> >>> (virtual) methods from the base class operand_equal_p.
> >>
> >> I call operand_equal_valueize (and hash_operand) from operand_equal_p.
> >> These are then used in IPA ICF (patch 6/9).
> >
> > Ugh.  I see you call that after
> >
> >   if (TREE_CODE (arg0) != TREE_CODE (arg1))
> >     {
> > ...
> >         }
> >       else
> >         return false;
> >     }
> >
> > and also after
> >
> >   /* Check equality of integer constants before bailing out due to
> >      precision differences.  */
> >   if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
> >
> > which means for arg0 == SSA_NAME and arg1 == INTEGER_CST you return false
> > instead of valueizing arg0 to the possibly same or same "lose" value
> > and returning true.
>
> Yes. ICF does not allow to have anything where TREE_CODEs do not match.
>
> >
> > Also
> >
> > +  int val = operand_equal_valueize (arg0, arg1, flags);
> > +  if (val == 1)
> > +    return 1;
> > +  if (val == 0)
> > +    return 0;
> >
> > suggests that you pass in arbirtrary trees for "valueization" but it
> > isn't actually
> > valueization that is performed but instead it should do an alternate comparison
> > of arg0 and arg1 with valueization.  Why's this done this way instead of
> > sth like
> >
> >   if (TREE_CODE (arg0) == SSA_NAME)
> >    arg0 = operand_equal_valueize (arg0, flags);
> >  if (TREE_CODE (arg1) == SSA_NAME)
> >    arg1 = operand_equal_valueize (arg1, flags);
>
> Because I want to be given a pair of trees about which the function
> operand_equal_valueize returns match/no-match/dunno.
>
> >
> > and why's this done with virtual functions rather than a callback that we can
> > cheaply check for NULLness in the default implementation?
>
> I can transform it into a hook. But as mentioned I'll need two hooks.
>
> >
> > So - what does ICF want to make "equal" that isn't equal normally and how's
> > that "valueization"?
>
> E.g. for a FUNCTION_DECL, ICF always return true because it can only calls
> the operand_equal_p after callgraph is compared. Similarly for LABEL_DECLs,
> we have a map (m_label_bb_map). Please take a look at patch 6/9 in this
> series.

Hmm, ok, so you basically replace recursive calls to operand_equal_p with

  operand_equal_valueize (t1, t2, 0)
  || operand_equal_p (t1, t2, 0)

no?  But the same could be achieved by actually making t1 and t2 equal
according to operand_equal_p rules via the valueization hook?  So replace
FUNCTION_DECLs with their prevailing ones, LABEL_DECLs with theirs, etc.

As given your abstraction is quite awkward to use, say, from value-numbering
which knows how to "valueize" a single tree but doesn't compare things.

To make it work for your case you'd valueize not only SSA names but also
all DECL_P I guess.  After all your operand_equal_valueize only does
something for "leafs" but is called for all intermediate expressions as well.

Richard.

> Thanks,
> Martin
>
> >
> > Thanks,
> > Richard.
> >
> >> Martin
> >>
> >>>
> >>> Richard.
> >>>
> >>>> Thanks,
> >>>> Martin
> >>>>
> >>>>> IMHO that would also make the logic within
> >>>>> operand_equal_p clearer, because you don't have to think about all the
> >>>>> potential callback functions that might be called.
> >>>>>
> >>>>>
> >>>>> Ciao,
> >>>>> Michael.
> >>>>>
> >>>>
> >>
>

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

* Re: [PATCH 5/9] Come up with an abstraction.
  2019-08-14 13:17                             ` Richard Biener
@ 2019-08-14 13:50                               ` Martin Liška
  2019-08-14 14:38                                 ` Richard Biener
  0 siblings, 1 reply; 59+ messages in thread
From: Martin Liška @ 2019-08-14 13:50 UTC (permalink / raw)
  To: Richard Biener; +Cc: Michael Matz, GCC Patches

On 8/14/19 3:04 PM, Richard Biener wrote:
> On Mon, Aug 12, 2019 at 3:56 PM Martin Liška <mliska@suse.cz> wrote:
>>
>> On 8/12/19 2:43 PM, Richard Biener wrote:
>>> On Mon, Aug 12, 2019 at 1:49 PM Martin Liška <mliska@suse.cz> wrote:
>>>>
>>>> On 8/12/19 1:40 PM, Richard Biener wrote:
>>>>> On Mon, Aug 12, 2019 at 1:19 PM Martin Liška <mliska@suse.cz> wrote:
>>>>>>
>>>>>> On 8/8/19 5:55 PM, Michael Matz wrote:
>>>>>>> Hi,
>>>>>>>
>>>>>>> On Mon, 10 Jun 2019, Martin Liska wrote:
>>>>>>>
>>>>>>>> 2019-07-24  Martin Liska  <mliska@suse.cz>
>>>>>>>>
>>>>>>>>      * fold-const.c (operand_equal_p): Rename to ...
>>>>>>>>      (operand_compare::operand_equal_p): ... this.
>>>>>>>>      (add_expr):  Rename to ...
>>>>>>>>      (operand_compare::hash_operand): ... this.
>>>>>>>>      (operand_compare::operand_equal_valueize): Likewise.
>>>>>>>>      (operand_compare::hash_operand_valueize): Likewise.
>>>>>>>>      * fold-const.h (operand_equal_p): Set default
>>>>>>>>      value for last argument.
>>>>>>>>      (class operand_compare): New.
>>>>>>>
>>>>>>> Hmpf.  A class without any data?  That doesn't sound like a good design.
>>>>>>
>>>>>> Yes, the base class (current operand_equal_p) does not have a data.
>>>>>> But the ICF derive class has a data and e.g. func_checker::operand_equal_valueize
>>>>>> will use m_label_bb_map.get (t1). Which are member data of class func_checker.
>>>>>>
>>>>>>> You seem to need it only to have the possibility of virtual functions,
>>>>>>> i.e. fancy callbacks.  AFAICS you only have one derived class, i.e. a
>>>>>>> simple distinction of two cases.  What do you think about encoding the
>>>>>>> additional new (ICF) case in the (existing) 'flags' argument to
>>>>>>> operand_equal_p (and in case the ICF flag is set simply call the
>>>>>>> "callback" directly)?
>>>>>>
>>>>>> That's possible. I can add two more callbacks to the operand_equal_p function
>>>>>> (hash_operand_valueize and operand_equal_valueize).
>>>>>>
>>>>>> Is Richi also supporting this approach?
>>>>>
>>>>> I still see no value in the abstraction since you invoke none of the
>>>>> (virtual) methods from the base class operand_equal_p.
>>>>
>>>> I call operand_equal_valueize (and hash_operand) from operand_equal_p.
>>>> These are then used in IPA ICF (patch 6/9).
>>>
>>> Ugh.  I see you call that after
>>>
>>>   if (TREE_CODE (arg0) != TREE_CODE (arg1))
>>>     {
>>> ...
>>>         }
>>>       else
>>>         return false;
>>>     }
>>>
>>> and also after
>>>
>>>   /* Check equality of integer constants before bailing out due to
>>>      precision differences.  */
>>>   if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
>>>
>>> which means for arg0 == SSA_NAME and arg1 == INTEGER_CST you return false
>>> instead of valueizing arg0 to the possibly same or same "lose" value
>>> and returning true.
>>
>> Yes. ICF does not allow to have anything where TREE_CODEs do not match.
>>
>>>
>>> Also
>>>
>>> +  int val = operand_equal_valueize (arg0, arg1, flags);
>>> +  if (val == 1)
>>> +    return 1;
>>> +  if (val == 0)
>>> +    return 0;
>>>
>>> suggests that you pass in arbirtrary trees for "valueization" but it
>>> isn't actually
>>> valueization that is performed but instead it should do an alternate comparison
>>> of arg0 and arg1 with valueization.  Why's this done this way instead of
>>> sth like
>>>
>>>   if (TREE_CODE (arg0) == SSA_NAME)
>>>    arg0 = operand_equal_valueize (arg0, flags);
>>>  if (TREE_CODE (arg1) == SSA_NAME)
>>>    arg1 = operand_equal_valueize (arg1, flags);
>>
>> Because I want to be given a pair of trees about which the function
>> operand_equal_valueize returns match/no-match/dunno.
>>
>>>
>>> and why's this done with virtual functions rather than a callback that we can
>>> cheaply check for NULLness in the default implementation?
>>
>> I can transform it into a hook. But as mentioned I'll need two hooks.
>>
>>>
>>> So - what does ICF want to make "equal" that isn't equal normally and how's
>>> that "valueization"?
>>
>> E.g. for a FUNCTION_DECL, ICF always return true because it can only calls
>> the operand_equal_p after callgraph is compared. Similarly for LABEL_DECLs,
>> we have a map (m_label_bb_map). Please take a look at patch 6/9 in this
>> series.
> 
> Hmm, ok, so you basically replace recursive calls to operand_equal_p with
> 
>   operand_equal_valueize (t1, t2, 0)
>   || operand_equal_p (t1, t2, 0)
> 
> no?

This is not going to work ..

>  But the same could be achieved by actually making t1 and t2 equal
> according to operand_equal_p rules via the valueization hook?  So replace
> FUNCTION_DECLs with their prevailing ones, LABEL_DECLs with theirs, etc.
> 
> As given your abstraction is quite awkward to use, say, from value-numbering
> which knows how to "valueize" a single tree but doesn't compare things.
> 
> To make it work for your case you'd valueize not only SSA names but also
> all DECL_P I guess.  After all your operand_equal_valueize only does
> something for "leafs" but is called for all intermediate expressions as well.

... because I need to be called for all intermediate expression. One simple
example can be a ADDR_EXPR of a DECL. The first call will recursively call
operand_equal_p for the DECL and the DECL can be compared with operand_equal_valueize
in ICF.

Note that current ICF code is more complex than only selection of a canonical
form of a tree.

I'm not saying the suggested API change is beautiful. But having a more specific
equal hook seams to me a reasonable extension to current operand_equal_p.
Moreover, we'll be able to kill all the ICF duplicate comparison machinery.

Martin

> 
> Richard.
> 
>> Thanks,
>> Martin
>>
>>>
>>> Thanks,
>>> Richard.
>>>
>>>> Martin
>>>>
>>>>>
>>>>> Richard.
>>>>>
>>>>>> Thanks,
>>>>>> Martin
>>>>>>
>>>>>>> IMHO that would also make the logic within
>>>>>>> operand_equal_p clearer, because you don't have to think about all the
>>>>>>> potential callback functions that might be called.
>>>>>>>
>>>>>>>
>>>>>>> Ciao,
>>>>>>> Michael.
>>>>>>>
>>>>>>
>>>>
>>

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

* Re: [PATCH 5/9] Come up with an abstraction.
  2019-08-14 13:50                               ` Martin Liška
@ 2019-08-14 14:38                                 ` Richard Biener
  2019-08-16 11:06                                   ` Martin Liška
  0 siblings, 1 reply; 59+ messages in thread
From: Richard Biener @ 2019-08-14 14:38 UTC (permalink / raw)
  To: Martin Liška; +Cc: Michael Matz, GCC Patches

On Wed, Aug 14, 2019 at 3:19 PM Martin Liška <mliska@suse.cz> wrote:
>
> On 8/14/19 3:04 PM, Richard Biener wrote:
> > On Mon, Aug 12, 2019 at 3:56 PM Martin Liška <mliska@suse.cz> wrote:
> >>
> >> On 8/12/19 2:43 PM, Richard Biener wrote:
> >>> On Mon, Aug 12, 2019 at 1:49 PM Martin Liška <mliska@suse.cz> wrote:
> >>>>
> >>>> On 8/12/19 1:40 PM, Richard Biener wrote:
> >>>>> On Mon, Aug 12, 2019 at 1:19 PM Martin Liška <mliska@suse.cz> wrote:
> >>>>>>
> >>>>>> On 8/8/19 5:55 PM, Michael Matz wrote:
> >>>>>>> Hi,
> >>>>>>>
> >>>>>>> On Mon, 10 Jun 2019, Martin Liska wrote:
> >>>>>>>
> >>>>>>>> 2019-07-24  Martin Liska  <mliska@suse.cz>
> >>>>>>>>
> >>>>>>>>      * fold-const.c (operand_equal_p): Rename to ...
> >>>>>>>>      (operand_compare::operand_equal_p): ... this.
> >>>>>>>>      (add_expr):  Rename to ...
> >>>>>>>>      (operand_compare::hash_operand): ... this.
> >>>>>>>>      (operand_compare::operand_equal_valueize): Likewise.
> >>>>>>>>      (operand_compare::hash_operand_valueize): Likewise.
> >>>>>>>>      * fold-const.h (operand_equal_p): Set default
> >>>>>>>>      value for last argument.
> >>>>>>>>      (class operand_compare): New.
> >>>>>>>
> >>>>>>> Hmpf.  A class without any data?  That doesn't sound like a good design.
> >>>>>>
> >>>>>> Yes, the base class (current operand_equal_p) does not have a data.
> >>>>>> But the ICF derive class has a data and e.g. func_checker::operand_equal_valueize
> >>>>>> will use m_label_bb_map.get (t1). Which are member data of class func_checker.
> >>>>>>
> >>>>>>> You seem to need it only to have the possibility of virtual functions,
> >>>>>>> i.e. fancy callbacks.  AFAICS you only have one derived class, i.e. a
> >>>>>>> simple distinction of two cases.  What do you think about encoding the
> >>>>>>> additional new (ICF) case in the (existing) 'flags' argument to
> >>>>>>> operand_equal_p (and in case the ICF flag is set simply call the
> >>>>>>> "callback" directly)?
> >>>>>>
> >>>>>> That's possible. I can add two more callbacks to the operand_equal_p function
> >>>>>> (hash_operand_valueize and operand_equal_valueize).
> >>>>>>
> >>>>>> Is Richi also supporting this approach?
> >>>>>
> >>>>> I still see no value in the abstraction since you invoke none of the
> >>>>> (virtual) methods from the base class operand_equal_p.
> >>>>
> >>>> I call operand_equal_valueize (and hash_operand) from operand_equal_p.
> >>>> These are then used in IPA ICF (patch 6/9).
> >>>
> >>> Ugh.  I see you call that after
> >>>
> >>>   if (TREE_CODE (arg0) != TREE_CODE (arg1))
> >>>     {
> >>> ...
> >>>         }
> >>>       else
> >>>         return false;
> >>>     }
> >>>
> >>> and also after
> >>>
> >>>   /* Check equality of integer constants before bailing out due to
> >>>      precision differences.  */
> >>>   if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
> >>>
> >>> which means for arg0 == SSA_NAME and arg1 == INTEGER_CST you return false
> >>> instead of valueizing arg0 to the possibly same or same "lose" value
> >>> and returning true.
> >>
> >> Yes. ICF does not allow to have anything where TREE_CODEs do not match.
> >>
> >>>
> >>> Also
> >>>
> >>> +  int val = operand_equal_valueize (arg0, arg1, flags);
> >>> +  if (val == 1)
> >>> +    return 1;
> >>> +  if (val == 0)
> >>> +    return 0;
> >>>
> >>> suggests that you pass in arbirtrary trees for "valueization" but it
> >>> isn't actually
> >>> valueization that is performed but instead it should do an alternate comparison
> >>> of arg0 and arg1 with valueization.  Why's this done this way instead of
> >>> sth like
> >>>
> >>>   if (TREE_CODE (arg0) == SSA_NAME)
> >>>    arg0 = operand_equal_valueize (arg0, flags);
> >>>  if (TREE_CODE (arg1) == SSA_NAME)
> >>>    arg1 = operand_equal_valueize (arg1, flags);
> >>
> >> Because I want to be given a pair of trees about which the function
> >> operand_equal_valueize returns match/no-match/dunno.
> >>
> >>>
> >>> and why's this done with virtual functions rather than a callback that we can
> >>> cheaply check for NULLness in the default implementation?
> >>
> >> I can transform it into a hook. But as mentioned I'll need two hooks.
> >>
> >>>
> >>> So - what does ICF want to make "equal" that isn't equal normally and how's
> >>> that "valueization"?
> >>
> >> E.g. for a FUNCTION_DECL, ICF always return true because it can only calls
> >> the operand_equal_p after callgraph is compared. Similarly for LABEL_DECLs,
> >> we have a map (m_label_bb_map). Please take a look at patch 6/9 in this
> >> series.
> >
> > Hmm, ok, so you basically replace recursive calls to operand_equal_p with

_recursive calls_

> >
> >   operand_equal_valueize (t1, t2, 0)
> >   || operand_equal_p (t1, t2, 0)
> >
> > no?
>
> This is not going to work ..

I wonder if

class base
{
  virtual operand_equal_p (tree a, tree b, int f);
};

base::operand_equal_p (tree a, tree b, int f)
{
  as-is now, recursing to virtual operand_equal_p
}

class deriv : public base
{
  vritual operand_equal_p (tree a, tree b, int f);
};

deriv::operand_equal_p (tree a, tree b, int f)
{
  // just example
  if (TREE_CODE (a) == TREE_CODE (b)
     && TREE_CODE (a) == FUNCTION_DECL)
    return true;

  return base::operand_equal_p (tree a, tree b, int f);
}

would work?  ICF would call deriv::operand_equal_p and
base::operand_equal_p would recurse via the derived implementation.

That at least is cleaner from the "looks".

> >  But the same could be achieved by actually making t1 and t2 equal
> > according to operand_equal_p rules via the valueization hook?  So replace
> > FUNCTION_DECLs with their prevailing ones, LABEL_DECLs with theirs, etc.
> >
> > As given your abstraction is quite awkward to use, say, from value-numbering
> > which knows how to "valueize" a single tree but doesn't compare things.
> >
> > To make it work for your case you'd valueize not only SSA names but also
> > all DECL_P I guess.  After all your operand_equal_valueize only does
> > something for "leafs" but is called for all intermediate expressions as well.
>
> ... because I need to be called for all intermediate expression. One simple
> example can be a ADDR_EXPR of a DECL. The first call will recursively call
> operand_equal_p for the DECL and the DECL can be compared with operand_equal_valueize
> in ICF.
>
> Note that current ICF code is more complex than only selection of a canonical
> form of a tree.
>
> I'm not saying the suggested API change is beautiful. But having a more specific
> equal hook seams to me a reasonable extension to current operand_equal_p.
> Moreover, we'll be able to kill all the ICF duplicate comparison machinery.

I wonder if all FUNCTION_DECL are really equal.  If you just compare
the callgraph
you don't notice differences in the following (with disabled DSE/FRE
to retain both
stores to *dest)

void fna();
void fnb();

void foo (void *dest)
{
  *dest = (void *)fna;
  *dest = (void *)fnb;
}

void bar (void *dest)
{
  *dest = (void *)fnb;
  *dest = (void *)fna;
}

and if you compare IPA refs you'd need to identify the ref stmts as the same?


> Martin
>
> >
> > Richard.
> >
> >> Thanks,
> >> Martin
> >>
> >>>
> >>> Thanks,
> >>> Richard.
> >>>
> >>>> Martin
> >>>>
> >>>>>
> >>>>> Richard.
> >>>>>
> >>>>>> Thanks,
> >>>>>> Martin
> >>>>>>
> >>>>>>> IMHO that would also make the logic within
> >>>>>>> operand_equal_p clearer, because you don't have to think about all the
> >>>>>>> potential callback functions that might be called.
> >>>>>>>
> >>>>>>>
> >>>>>>> Ciao,
> >>>>>>> Michael.
> >>>>>>>
> >>>>>>
> >>>>
> >>
>

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

* Re: [PATCH 2/9] operand_equal_p: add support for FIELD_DECL
  2019-08-07 12:21                 ` Richard Biener
@ 2019-08-15 14:19                   ` Jan Hubicka
  2019-08-16  9:28                     ` Richard Biener
  0 siblings, 1 reply; 59+ messages in thread
From: Jan Hubicka @ 2019-08-15 14:19 UTC (permalink / raw)
  To: Richard Biener; +Cc: Martin Liska, GCC Patches

> On Tue, Aug 6, 2019 at 5:44 PM Martin Liska <mliska@suse.cz> wrote:
> >
> >
> > gcc/ChangeLog:
> 
> So I suppose this isn't to call operand_equal_p on two FIELD_DECLs
> but to make two COMPONENT_REFs "more equal"?  If so I then

yes. The patch originates from my original patchset I believe and it is
what ICF does.
> I suggest to make this change "local" to the COMPONENT_REF handling.
> This also interacts with path-based disambiguation so you want to make
> sure to only make things equal here iff it wouldn't change the outcome
> of path-based analysis.  Honza?

Indeed this can be handled as part of COMPONENT_REF match.
Access path oracle here basically checks:
 1) that MEM_REF type matches (we want predicate for this)
 2) if it finds type match via same_type_for_tbaa and then it applies
    the assumption about disjointness or overlap

So I guess ideally we should

 1) do matching part of COMPONENT_REF
 2) compare OFFSET, BIT_OFFSET 
    This establishes that the access has same semantics.
 3) for -fno-strict-aliasing be happy
 4) for -fstrict-aliaisng check if access path applies (we should export
    predicate from tree-ssa-alias as discussed earlier)
 5) compare types by same_type_for_tbaa_p

Honza

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

* Re: [PATCH 3/9] operand_equal_p: add support for OBJ_TYPE_REF.
  2019-08-07 12:09                 ` Richard Biener
@ 2019-08-15 15:44                   ` Jan Hubicka
  2019-08-16  9:25                     ` Richard Biener
  0 siblings, 1 reply; 59+ messages in thread
From: Jan Hubicka @ 2019-08-15 15:44 UTC (permalink / raw)
  To: Richard Biener; +Cc: Martin Liska, GCC Patches, hubicka

> On Tue, Aug 6, 2019 at 5:43 PM Martin Liska <mliska@suse.cz> wrote:
> >
> >
> > gcc/ChangeLog:
> 
> +       /* Virtual table call.  */
> +       case OBJ_TYPE_REF:
> +         {
> +           if (!operand_equal_p (OBJ_TYPE_REF_EXPR (arg0),
> +                                 OBJ_TYPE_REF_EXPR (arg1), flags))
> +             return false;
> +           if (virtual_method_call_p (arg0))
> +             {
> +               if (tree_to_uhwi (OBJ_TYPE_REF_TOKEN (arg0))
> +                   != tree_to_uhwi (OBJ_TYPE_REF_TOKEN (arg1)))
> +                 return false;
> +               if (!types_same_for_odr (obj_type_ref_class (arg0),
> +                                        obj_type_ref_class (arg1)))
> +                 return false;
> +               if (!operand_equal_p (OBJ_TYPE_REF_OBJECT (arg0),
> +                                     OBJ_TYPE_REF_OBJECT (arg1), flags))
> +                 return false;
> 
> this all gets deep into the devirt machinery, including looking at
> ODR type hashes.  So I'm not sure if we really want to handle
> it this "optimistic" in operand_equal_p and completely ignore
> other operands when !virtual_method_call_p?  That is, why
> not compare OBJ_TYPE_REF_TOKEN/OBJECT always at least?

For !virtual_method_call_p we do not use OBJ_TYPE_REF at all yet obj-C frontend
produce it.  I think we should remove them somewhere during gimplification.
We can definitly turn "optimistic" to "pesimistic" and return false here.

Otherwise the checks makes sense to me - it the tests above passes devirt
machinery ought to give same results.
> 
> Do we then have cases where the OBJ_TYPE_REF is actually
> distinct according to the remaining check?

I am not sure what you mean here?

Honza
> 
> +             }
> 
> 
> > 2019-07-24  Martin Liska  <mliska@suse.cz>
> >
> >         * fold-const.c (operand_equal_p): Support OBJ_TYPE_REF.
> >         * tree.c (add_expr): Hash parts of OBJ_TYPE_REF.
> > ---
> >  gcc/fold-const.c | 21 +++++++++++++++++++++
> >  gcc/tree.c       |  9 +++++++++
> >  2 files changed, 30 insertions(+)
> >

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

* Re: [PATCH 3/9] operand_equal_p: add support for OBJ_TYPE_REF.
  2019-08-15 15:44                   ` Jan Hubicka
@ 2019-08-16  9:25                     ` Richard Biener
  2019-08-16 12:11                       ` Jan Hubicka
  0 siblings, 1 reply; 59+ messages in thread
From: Richard Biener @ 2019-08-16  9:25 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: Martin Liska, GCC Patches

On Thu, Aug 15, 2019 at 4:57 PM Jan Hubicka <hubicka@ucw.cz> wrote:
>
> > On Tue, Aug 6, 2019 at 5:43 PM Martin Liska <mliska@suse.cz> wrote:
> > >
> > >
> > > gcc/ChangeLog:
> >
> > +       /* Virtual table call.  */
> > +       case OBJ_TYPE_REF:
> > +         {
> > +           if (!operand_equal_p (OBJ_TYPE_REF_EXPR (arg0),
> > +                                 OBJ_TYPE_REF_EXPR (arg1), flags))
> > +             return false;
> > +           if (virtual_method_call_p (arg0))
> > +             {
> > +               if (tree_to_uhwi (OBJ_TYPE_REF_TOKEN (arg0))
> > +                   != tree_to_uhwi (OBJ_TYPE_REF_TOKEN (arg1)))
> > +                 return false;
> > +               if (!types_same_for_odr (obj_type_ref_class (arg0),
> > +                                        obj_type_ref_class (arg1)))
> > +                 return false;
> > +               if (!operand_equal_p (OBJ_TYPE_REF_OBJECT (arg0),
> > +                                     OBJ_TYPE_REF_OBJECT (arg1), flags))
> > +                 return false;
> >
> > this all gets deep into the devirt machinery, including looking at
> > ODR type hashes.  So I'm not sure if we really want to handle
> > it this "optimistic" in operand_equal_p and completely ignore
> > other operands when !virtual_method_call_p?  That is, why
> > not compare OBJ_TYPE_REF_TOKEN/OBJECT always at least?
>
> For !virtual_method_call_p we do not use OBJ_TYPE_REF at all yet obj-C frontend
> produce it.  I think we should remove them somewhere during gimplification.
> We can definitly turn "optimistic" to "pesimistic" and return false here.
>
> Otherwise the checks makes sense to me - it the tests above passes devirt
> machinery ought to give same results.
> >
> > Do we then have cases where the OBJ_TYPE_REF is actually
> > distinct according to the remaining check?
>
> I am not sure what you mean here?

When we compare OBJ_TYPE_REF_TOKEN and OBJ_TYPE_REF_OBJECT
and they are equal, are there cases where types_same_for_odr returns false?

I guess we went over this some time ago when talking about value-numbering
of them.  I realize the devirt machinery use the class type to get at the
virtual table but since we later expand simply OBJ_TPE_REF_EXPR _that_
already has the result of the load from the vitual table.

So - do we need to compare obj_type_ref_class at all?  The worst thing
that could happen is that devirt no longer can devirtualize after the merging
but it should never result in "wrong" devirtualization?  So, do we really
want to inhibit ICF of two equal functions that could be eventually
devirtualized both but into different direct calls?  Can't this sort of thing
happen anyway when you'd factor in IPA-CP and two identical functions
with indirect calls to a function argument but called with different constant
args?  And should IPA-CP then not consider cloning after ICF merging
(not sure how ordering works here).

Richard.

> Honza
> >
> > +             }
> >
> >
> > > 2019-07-24  Martin Liska  <mliska@suse.cz>
> > >
> > >         * fold-const.c (operand_equal_p): Support OBJ_TYPE_REF.
> > >         * tree.c (add_expr): Hash parts of OBJ_TYPE_REF.
> > > ---
> > >  gcc/fold-const.c | 21 +++++++++++++++++++++
> > >  gcc/tree.c       |  9 +++++++++
> > >  2 files changed, 30 insertions(+)
> > >

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

* Re: [PATCH 2/9] operand_equal_p: add support for FIELD_DECL
  2019-08-15 14:19                   ` Jan Hubicka
@ 2019-08-16  9:28                     ` Richard Biener
  2019-08-16 12:17                       ` Jan Hubicka
  0 siblings, 1 reply; 59+ messages in thread
From: Richard Biener @ 2019-08-16  9:28 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: Martin Liska, GCC Patches

On Thu, Aug 15, 2019 at 4:17 PM Jan Hubicka <hubicka@ucw.cz> wrote:
>
> > On Tue, Aug 6, 2019 at 5:44 PM Martin Liska <mliska@suse.cz> wrote:
> > >
> > >
> > > gcc/ChangeLog:
> >
> > So I suppose this isn't to call operand_equal_p on two FIELD_DECLs
> > but to make two COMPONENT_REFs "more equal"?  If so I then
>
> yes. The patch originates from my original patchset I believe and it is
> what ICF does.
> > I suggest to make this change "local" to the COMPONENT_REF handling.
> > This also interacts with path-based disambiguation so you want to make
> > sure to only make things equal here iff it wouldn't change the outcome
> > of path-based analysis.  Honza?
>
> Indeed this can be handled as part of COMPONENT_REF match.
> Access path oracle here basically checks:
>  1) that MEM_REF type matches (we want predicate for this)
>  2) if it finds type match via same_type_for_tbaa and then it applies
>     the assumption about disjointness or overlap
>
> So I guess ideally we should
>
>  1) do matching part of COMPONENT_REF
>  2) compare OFFSET, BIT_OFFSET
>     This establishes that the access has same semantics.
>  3) for -fno-strict-aliasing be happy
>  4) for -fstrict-aliaisng check if access path applies (we should export
>     predicate from tree-ssa-alias as discussed earlier)
>  5) compare types by same_type_for_tbaa_p

Ick.  This smells like a layering violation to me.  IMHO this extended
equality handling should be handled with the overloading/callback
and not in native operand_equal_p.  Either on the level of the
COMPONENT_REF itself (sounds like that would be needed)
or the FIELD_DECL.  Not sure if the above suggestions make
it neccessary to look at more than a single COMPONENT_REF/FIELD_DECL
in the access path.  If so then watch out for quadraticness as operand_equal_p
traverses a reference chain...

Richard.

> Honza

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

* Re: [PATCH 5/9] Come up with an abstraction.
  2019-08-14 14:38                                 ` Richard Biener
@ 2019-08-16 11:06                                   ` Martin Liška
  2019-09-18  7:56                                     ` Martin Liška
  0 siblings, 1 reply; 59+ messages in thread
From: Martin Liška @ 2019-08-16 11:06 UTC (permalink / raw)
  To: Richard Biener; +Cc: Michael Matz, GCC Patches

[-- Attachment #1: Type: text/plain, Size: 7920 bytes --]

On 8/14/19 3:56 PM, Richard Biener wrote:
> On Wed, Aug 14, 2019 at 3:19 PM Martin Liška <mliska@suse.cz> wrote:
>>
>> On 8/14/19 3:04 PM, Richard Biener wrote:
>>> On Mon, Aug 12, 2019 at 3:56 PM Martin Liška <mliska@suse.cz> wrote:
>>>>
>>>> On 8/12/19 2:43 PM, Richard Biener wrote:
>>>>> On Mon, Aug 12, 2019 at 1:49 PM Martin Liška <mliska@suse.cz> wrote:
>>>>>>
>>>>>> On 8/12/19 1:40 PM, Richard Biener wrote:
>>>>>>> On Mon, Aug 12, 2019 at 1:19 PM Martin Liška <mliska@suse.cz> wrote:
>>>>>>>>
>>>>>>>> On 8/8/19 5:55 PM, Michael Matz wrote:
>>>>>>>>> Hi,
>>>>>>>>>
>>>>>>>>> On Mon, 10 Jun 2019, Martin Liska wrote:
>>>>>>>>>
>>>>>>>>>> 2019-07-24  Martin Liska  <mliska@suse.cz>
>>>>>>>>>>
>>>>>>>>>>      * fold-const.c (operand_equal_p): Rename to ...
>>>>>>>>>>      (operand_compare::operand_equal_p): ... this.
>>>>>>>>>>      (add_expr):  Rename to ...
>>>>>>>>>>      (operand_compare::hash_operand): ... this.
>>>>>>>>>>      (operand_compare::operand_equal_valueize): Likewise.
>>>>>>>>>>      (operand_compare::hash_operand_valueize): Likewise.
>>>>>>>>>>      * fold-const.h (operand_equal_p): Set default
>>>>>>>>>>      value for last argument.
>>>>>>>>>>      (class operand_compare): New.
>>>>>>>>>
>>>>>>>>> Hmpf.  A class without any data?  That doesn't sound like a good design.
>>>>>>>>
>>>>>>>> Yes, the base class (current operand_equal_p) does not have a data.
>>>>>>>> But the ICF derive class has a data and e.g. func_checker::operand_equal_valueize
>>>>>>>> will use m_label_bb_map.get (t1). Which are member data of class func_checker.
>>>>>>>>
>>>>>>>>> You seem to need it only to have the possibility of virtual functions,
>>>>>>>>> i.e. fancy callbacks.  AFAICS you only have one derived class, i.e. a
>>>>>>>>> simple distinction of two cases.  What do you think about encoding the
>>>>>>>>> additional new (ICF) case in the (existing) 'flags' argument to
>>>>>>>>> operand_equal_p (and in case the ICF flag is set simply call the
>>>>>>>>> "callback" directly)?
>>>>>>>>
>>>>>>>> That's possible. I can add two more callbacks to the operand_equal_p function
>>>>>>>> (hash_operand_valueize and operand_equal_valueize).
>>>>>>>>
>>>>>>>> Is Richi also supporting this approach?
>>>>>>>
>>>>>>> I still see no value in the abstraction since you invoke none of the
>>>>>>> (virtual) methods from the base class operand_equal_p.
>>>>>>
>>>>>> I call operand_equal_valueize (and hash_operand) from operand_equal_p.
>>>>>> These are then used in IPA ICF (patch 6/9).
>>>>>
>>>>> Ugh.  I see you call that after
>>>>>
>>>>>   if (TREE_CODE (arg0) != TREE_CODE (arg1))
>>>>>     {
>>>>> ...
>>>>>         }
>>>>>       else
>>>>>         return false;
>>>>>     }
>>>>>
>>>>> and also after
>>>>>
>>>>>   /* Check equality of integer constants before bailing out due to
>>>>>      precision differences.  */
>>>>>   if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
>>>>>
>>>>> which means for arg0 == SSA_NAME and arg1 == INTEGER_CST you return false
>>>>> instead of valueizing arg0 to the possibly same or same "lose" value
>>>>> and returning true.
>>>>
>>>> Yes. ICF does not allow to have anything where TREE_CODEs do not match.
>>>>
>>>>>
>>>>> Also
>>>>>
>>>>> +  int val = operand_equal_valueize (arg0, arg1, flags);
>>>>> +  if (val == 1)
>>>>> +    return 1;
>>>>> +  if (val == 0)
>>>>> +    return 0;
>>>>>
>>>>> suggests that you pass in arbirtrary trees for "valueization" but it
>>>>> isn't actually
>>>>> valueization that is performed but instead it should do an alternate comparison
>>>>> of arg0 and arg1 with valueization.  Why's this done this way instead of
>>>>> sth like
>>>>>
>>>>>   if (TREE_CODE (arg0) == SSA_NAME)
>>>>>    arg0 = operand_equal_valueize (arg0, flags);
>>>>>  if (TREE_CODE (arg1) == SSA_NAME)
>>>>>    arg1 = operand_equal_valueize (arg1, flags);
>>>>
>>>> Because I want to be given a pair of trees about which the function
>>>> operand_equal_valueize returns match/no-match/dunno.
>>>>
>>>>>
>>>>> and why's this done with virtual functions rather than a callback that we can
>>>>> cheaply check for NULLness in the default implementation?
>>>>
>>>> I can transform it into a hook. But as mentioned I'll need two hooks.
>>>>
>>>>>
>>>>> So - what does ICF want to make "equal" that isn't equal normally and how's
>>>>> that "valueization"?
>>>>
>>>> E.g. for a FUNCTION_DECL, ICF always return true because it can only calls
>>>> the operand_equal_p after callgraph is compared. Similarly for LABEL_DECLs,
>>>> we have a map (m_label_bb_map). Please take a look at patch 6/9 in this
>>>> series.
>>>
>>> Hmm, ok, so you basically replace recursive calls to operand_equal_p with
> 
> _recursive calls_
> 
>>>
>>>   operand_equal_valueize (t1, t2, 0)
>>>   || operand_equal_p (t1, t2, 0)
>>>
>>> no?
>>
>> This is not going to work ..
> 
> I wonder if
> 
> class base
> {
>   virtual operand_equal_p (tree a, tree b, int f);
> };
> 
> base::operand_equal_p (tree a, tree b, int f)
> {
>   as-is now, recursing to virtual operand_equal_p
> }
> 
> class deriv : public base
> {
>   vritual operand_equal_p (tree a, tree b, int f);
> };
> 
> deriv::operand_equal_p (tree a, tree b, int f)
> {
>   // just example
>   if (TREE_CODE (a) == TREE_CODE (b)
>      && TREE_CODE (a) == FUNCTION_DECL)
>     return true;
> 
>   return base::operand_equal_p (tree a, tree b, int f);
> }
> 
> would work?  ICF would call deriv::operand_equal_p and
> base::operand_equal_p would recurse via the derived implementation.
> 
> That at least is cleaner from the "looks".

LGTM, I'm sending updated for to address that.

> 
>>>  But the same could be achieved by actually making t1 and t2 equal
>>> according to operand_equal_p rules via the valueization hook?  So replace
>>> FUNCTION_DECLs with their prevailing ones, LABEL_DECLs with theirs, etc.
>>>
>>> As given your abstraction is quite awkward to use, say, from value-numbering
>>> which knows how to "valueize" a single tree but doesn't compare things.
>>>
>>> To make it work for your case you'd valueize not only SSA names but also
>>> all DECL_P I guess.  After all your operand_equal_valueize only does
>>> something for "leafs" but is called for all intermediate expressions as well.
>>
>> ... because I need to be called for all intermediate expression. One simple
>> example can be a ADDR_EXPR of a DECL. The first call will recursively call
>> operand_equal_p for the DECL and the DECL can be compared with operand_equal_valueize
>> in ICF.
>>
>> Note that current ICF code is more complex than only selection of a canonical
>> form of a tree.
>>
>> I'm not saying the suggested API change is beautiful. But having a more specific
>> equal hook seams to me a reasonable extension to current operand_equal_p.
>> Moreover, we'll be able to kill all the ICF duplicate comparison machinery.
> 
> I wonder if all FUNCTION_DECL are really equal.  If you just compare
> the callgraph
> you don't notice differences in the following (with disabled DSE/FRE
> to retain both
> stores to *dest)
> 
> void fna();
> void fnb();
> 
> void foo (void *dest)
> {
>   *dest = (void *)fna;
>   *dest = (void *)fnb;
> }
> 
> void bar (void *dest)
> {
>   *dest = (void *)fnb;
>   *dest = (void *)fna;
> }
> 
> and if you compare IPA refs you'd need to identify the ref stmts as the same?

This is all handled in IPA reference and IPA edge comparison in IPA ICF.
Don't worry ;)

Martin

> 
> 
>> Martin
>>
>>>
>>> Richard.
>>>
>>>> Thanks,
>>>> Martin
>>>>
>>>>>
>>>>> Thanks,
>>>>> Richard.
>>>>>
>>>>>> Martin
>>>>>>
>>>>>>>
>>>>>>> Richard.
>>>>>>>
>>>>>>>> Thanks,
>>>>>>>> Martin
>>>>>>>>
>>>>>>>>> IMHO that would also make the logic within
>>>>>>>>> operand_equal_p clearer, because you don't have to think about all the
>>>>>>>>> potential callback functions that might be called.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Ciao,
>>>>>>>>> Michael.
>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>>


[-- Attachment #2: 0005-Come-up-with-an-abstraction.patch --]
[-- Type: text/x-patch, Size: 23348 bytes --]

From 45c80314110c7227c697748c63394dce11b50966 Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Thu, 15 Aug 2019 10:35:14 +0200
Subject: [PATCH 5/9] Come up with an abstraction.

gcc/ChangeLog:

2019-08-15  Martin Liska  <mliska@suse.cz>

	* fold-const.c (operand_equal_p): Move to ...
	(operand_compare::operand_equal_p): ... here.
	(operand_compare::verify_hash_value): New.
	(add_expr): Move to ...
	(operand_compare::hash_operand): ... here.
	* fold-const.h (operand_equal_p): Move to the class.
	(class operand_compare): New.
	* tree.c (add_expr): Remove.
---
 gcc/fold-const.c | 366 ++++++++++++++++++++++++++++++++++++++++++++---
 gcc/fold-const.h |  25 +++-
 gcc/tree.c       | 286 ------------------------------------
 3 files changed, 368 insertions(+), 309 deletions(-)

diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 6b588d8e3ce..520a14041da 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -2940,29 +2940,12 @@ combine_comparisons (location_t loc,
    even if var is volatile.  */
 
 bool
-operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
+operand_compare::operand_equal_p (const_tree arg0, const_tree arg1,
+				  unsigned int flags)
 {
-  /* When checking, verify at the outermost operand_equal_p call that
-     if operand_equal_p returns non-zero then ARG0 and ARG1 has the same
-     hash value.  */
-  if (flag_checking && !(flags & OEP_NO_HASH_CHECK))
-    {
-      if (operand_equal_p (arg0, arg1, flags | OEP_NO_HASH_CHECK))
-	{
-	  if (arg0 != arg1)
-	    {
-	      inchash::hash hstate0 (0), hstate1 (0);
-	      inchash::add_expr (arg0, hstate0, flags | OEP_HASH_CHECK);
-	      inchash::add_expr (arg1, hstate1, flags | OEP_HASH_CHECK);
-	      hashval_t h0 = hstate0.end ();
-	      hashval_t h1 = hstate1.end ();
-	      gcc_assert (h0 == h1);
-	    }
-	  return true;
-	}
-      else
-	return false;
-    }
+  bool r;
+  if (verify_hash_value (arg0, arg1, flags, &r))
+    return r;
 
   STRIP_ANY_LOCATION_WRAPPER (arg0);
   STRIP_ANY_LOCATION_WRAPPER (arg1);
@@ -3606,6 +3589,345 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 
 #undef OP_SAME
 #undef OP_SAME_WITH_NULL
+}
+
+/* Generate a hash value for an expression.  This can be used iteratively
+   by passing a previous result as the HSTATE argument.  */
+
+void
+operand_compare::hash_operand (const_tree t, inchash::hash &hstate,
+			       unsigned int flags)
+{
+  int i;
+  enum tree_code code;
+  enum tree_code_class tclass;
+
+  if (t == NULL_TREE || t == error_mark_node)
+    {
+      hstate.merge_hash (0);
+      return;
+    }
+
+  STRIP_ANY_LOCATION_WRAPPER (t);
+
+  if (!(flags & OEP_ADDRESS_OF))
+    STRIP_NOPS (t);
+
+  code = TREE_CODE (t);
+
+  switch (code)
+    {
+    /* Alas, constants aren't shared, so we can't rely on pointer
+       identity.  */
+    case VOID_CST:
+      hstate.merge_hash (0);
+      return;
+    case INTEGER_CST:
+      gcc_checking_assert (!(flags & OEP_ADDRESS_OF));
+      for (i = 0; i < TREE_INT_CST_EXT_NUNITS (t); i++)
+	hstate.add_hwi (TREE_INT_CST_ELT (t, i));
+      return;
+    case REAL_CST:
+      {
+	unsigned int val2;
+	if (!HONOR_SIGNED_ZEROS (t) && real_zerop (t))
+	  val2 = rvc_zero;
+	else
+	  val2 = real_hash (TREE_REAL_CST_PTR (t));
+	hstate.merge_hash (val2);
+	return;
+      }
+    case FIXED_CST:
+      {
+	unsigned int val2 = fixed_hash (TREE_FIXED_CST_PTR (t));
+	hstate.merge_hash (val2);
+	return;
+      }
+    case STRING_CST:
+      hstate.add ((const void *) TREE_STRING_POINTER (t),
+		  TREE_STRING_LENGTH (t));
+      return;
+    case COMPLEX_CST:
+      hash_operand (TREE_REALPART (t), hstate, flags);
+      hash_operand (TREE_IMAGPART (t), hstate, flags);
+      return;
+    case VECTOR_CST:
+      {
+	hstate.add_int (VECTOR_CST_NPATTERNS (t));
+	hstate.add_int (VECTOR_CST_NELTS_PER_PATTERN (t));
+	unsigned int count = vector_cst_encoded_nelts (t);
+	for (unsigned int i = 0; i < count; ++i)
+	  hash_operand (VECTOR_CST_ENCODED_ELT (t, i), hstate, flags);
+	return;
+      }
+    case SSA_NAME:
+      /* We can just compare by pointer.  */
+      hstate.add_hwi (SSA_NAME_VERSION (t));
+      return;
+    case PLACEHOLDER_EXPR:
+      /* The node itself doesn't matter.  */
+      return;
+    case BLOCK:
+    case OMP_CLAUSE:
+      /* Ignore.  */
+      return;
+    case TREE_LIST:
+      /* A list of expressions, for a CALL_EXPR or as the elements of a
+	 VECTOR_CST.  */
+      for (; t; t = TREE_CHAIN (t))
+	hash_operand (TREE_VALUE (t), hstate, flags);
+      return;
+    case CONSTRUCTOR:
+      {
+	unsigned HOST_WIDE_INT idx;
+	tree field, value;
+	flags &= ~OEP_ADDRESS_OF;
+	FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), idx, field, value)
+	  {
+	    hash_operand (field, hstate, flags);
+	    hash_operand (value, hstate, flags);
+	  }
+	return;
+      }
+    case STATEMENT_LIST:
+      {
+	tree_stmt_iterator i;
+	for (i = tsi_start (CONST_CAST_TREE (t));
+	     !tsi_end_p (i); tsi_next (&i))
+	  hash_operand (tsi_stmt (i), hstate, flags);
+	return;
+      }
+    case TREE_VEC:
+      for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
+	hash_operand (TREE_VEC_ELT (t, i), hstate, flags);
+      return;
+    case IDENTIFIER_NODE:
+      hstate.add_object (IDENTIFIER_HASH_VALUE (t));
+      return;
+    case FIELD_DECL:
+      inchash::add_expr (DECL_FIELD_OFFSET (t), hstate, flags);
+      inchash::add_expr (DECL_FIELD_BIT_OFFSET (t), hstate, flags);
+      return;
+    case FUNCTION_DECL:
+      /* When referring to a built-in FUNCTION_DECL, use the __builtin__ form.
+	 Otherwise nodes that compare equal according to operand_equal_p might
+	 get different hash codes.  However, don't do this for machine specific
+	 or front end builtins, since the function code is overloaded in those
+	 cases.  */
+      if (DECL_BUILT_IN_CLASS (t) == BUILT_IN_NORMAL
+	  && builtin_decl_explicit_p (DECL_FUNCTION_CODE (t)))
+	{
+	  t = builtin_decl_explicit (DECL_FUNCTION_CODE (t));
+	  code = TREE_CODE (t);
+	}
+      /* FALL THROUGH */
+    default:
+      if (POLY_INT_CST_P (t))
+	{
+	  for (unsigned int i = 0; i < NUM_POLY_INT_COEFFS; ++i)
+	    hstate.add_wide_int (wi::to_wide (POLY_INT_CST_COEFF (t, i)));
+	  return;
+	}
+      tclass = TREE_CODE_CLASS (code);
+
+      if (tclass == tcc_declaration)
+	{
+	  /* DECL's have a unique ID */
+	  hstate.add_hwi (DECL_UID (t));
+	}
+      else if (tclass == tcc_comparison && !commutative_tree_code (code))
+	{
+	  /* For comparisons that can be swapped, use the lower
+	     tree code.  */
+	  enum tree_code ccode = swap_tree_comparison (code);
+	  if (code < ccode)
+	    ccode = code;
+	  hstate.add_object (ccode);
+	  hash_operand (TREE_OPERAND (t, ccode != code), hstate, flags);
+	  hash_operand (TREE_OPERAND (t, ccode == code), hstate, flags);
+	}
+      else if (CONVERT_EXPR_CODE_P (code))
+	{
+	  /* NOP_EXPR and CONVERT_EXPR are considered equal by
+	     operand_equal_p.  */
+	  enum tree_code ccode = NOP_EXPR;
+	  hstate.add_object (ccode);
+
+	  /* Don't hash the type, that can lead to having nodes which
+	     compare equal according to operand_equal_p, but which
+	     have different hash codes.  Make sure to include signedness
+	     in the hash computation.  */
+	  hstate.add_int (TYPE_UNSIGNED (TREE_TYPE (t)));
+	  hash_operand (TREE_OPERAND (t, 0), hstate, flags);
+	}
+      /* For OEP_ADDRESS_OF, hash MEM_EXPR[&decl, 0] the same as decl.  */
+      else if (code == MEM_REF
+	       && (flags & OEP_ADDRESS_OF) != 0
+	       && TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR
+	       && DECL_P (TREE_OPERAND (TREE_OPERAND (t, 0), 0))
+	       && integer_zerop (TREE_OPERAND (t, 1)))
+	hash_operand (TREE_OPERAND (TREE_OPERAND (t, 0), 0),
+		      hstate, flags);
+      /* Don't ICE on FE specific trees, or their arguments etc.
+	 during operand_equal_p hash verification.  */
+      else if (!IS_EXPR_CODE_CLASS (tclass))
+	gcc_assert (flags & OEP_HASH_CHECK);
+      else
+	{
+	  unsigned int sflags = flags;
+
+	  hstate.add_object (code);
+
+	  switch (code)
+	    {
+	    case ADDR_EXPR:
+	      gcc_checking_assert (!(flags & OEP_ADDRESS_OF));
+	      flags |= OEP_ADDRESS_OF;
+	      sflags = flags;
+	      break;
+
+	    case INDIRECT_REF:
+	    case MEM_REF:
+	    case TARGET_MEM_REF:
+	      flags &= ~OEP_ADDRESS_OF;
+	      sflags = flags;
+	      break;
+
+	    case ARRAY_REF:
+	    case ARRAY_RANGE_REF:
+	    case COMPONENT_REF:
+	    case BIT_FIELD_REF:
+	      sflags &= ~OEP_ADDRESS_OF;
+	      break;
+
+	    case COND_EXPR:
+	      flags &= ~OEP_ADDRESS_OF;
+	      break;
+
+	    case WIDEN_MULT_PLUS_EXPR:
+	    case WIDEN_MULT_MINUS_EXPR:
+	      {
+		/* The multiplication operands are commutative.  */
+		inchash::hash one, two;
+		hash_operand (TREE_OPERAND (t, 0), one, flags);
+		hash_operand (TREE_OPERAND (t, 1), two, flags);
+		hstate.add_commutative (one, two);
+		hash_operand (TREE_OPERAND (t, 2), two, flags);
+		return;
+	      }
+
+	    case CALL_EXPR:
+	      if (CALL_EXPR_FN (t) == NULL_TREE)
+		hstate.add_int (CALL_EXPR_IFN (t));
+	      break;
+
+	    case TARGET_EXPR:
+	      /* For TARGET_EXPR, just hash on the TARGET_EXPR_SLOT.
+		 Usually different TARGET_EXPRs just should use
+		 different temporaries in their slots.  */
+	      hash_operand (TARGET_EXPR_SLOT (t), hstate, flags);
+	      return;
+
+	    /* Virtual table call.  */
+	    case OBJ_TYPE_REF:
+	      inchash::add_expr (OBJ_TYPE_REF_EXPR (t), hstate, flags);
+	      if (virtual_method_call_p (t))
+		{
+		  inchash::add_expr (OBJ_TYPE_REF_TOKEN (t), hstate, flags);
+		  inchash::add_expr (OBJ_TYPE_REF_OBJECT (t), hstate, flags);
+		}
+	      return;
+	    default:
+	      break;
+	    }
+
+	  /* Don't hash the type, that can lead to having nodes which
+	     compare equal according to operand_equal_p, but which
+	     have different hash codes.  */
+	  if (code == NON_LVALUE_EXPR)
+	    {
+	      /* Make sure to include signness in the hash computation.  */
+	      hstate.add_int (TYPE_UNSIGNED (TREE_TYPE (t)));
+	      hash_operand (TREE_OPERAND (t, 0), hstate, flags);
+	    }
+
+	  else if (commutative_tree_code (code))
+	    {
+	      /* It's a commutative expression.  We want to hash it the same
+		 however it appears.  We do this by first hashing both operands
+		 and then rehashing based on the order of their independent
+		 hashes.  */
+	      inchash::hash one, two;
+	      hash_operand (TREE_OPERAND (t, 0), one, flags);
+	      hash_operand (TREE_OPERAND (t, 1), two, flags);
+	      hstate.add_commutative (one, two);
+	    }
+	  else
+	    for (i = TREE_OPERAND_LENGTH (t) - 1; i >= 0; --i)
+	      hash_operand (TREE_OPERAND (t, i), hstate,
+			    i == 0 ? flags : sflags);
+	}
+      return;
+    }
+}
+
+bool
+operand_compare::verify_hash_value (const_tree arg0, const_tree arg1,
+				    unsigned int flags, bool *ret)
+{
+  /* When checking, verify at the outermost operand_equal_p call that
+     if operand_equal_p returns non-zero then ARG0 and ARG1 has the same
+     hash value.  */
+  if (flag_checking && !(flags & OEP_NO_HASH_CHECK))
+    {
+      if (operand_equal_p (arg0, arg1, flags | OEP_NO_HASH_CHECK))
+	{
+	  if (arg0 != arg1)
+	    {
+	      inchash::hash hstate0 (0), hstate1 (0);
+	      hash_operand (arg0, hstate0, flags | OEP_HASH_CHECK);
+	      hash_operand (arg1, hstate1, flags | OEP_HASH_CHECK);
+	      hashval_t h0 = hstate0.end ();
+	      hashval_t h1 = hstate1.end ();
+	      gcc_assert (h0 == h1);
+	    }
+	  *ret = true;
+	}
+      else
+	*ret = false;
+
+      return true;
+    }
+
+  return false;
+}
+
+
+static operand_compare default_compare_instance;
+
+/* Conveinece wrapper around operand_compare class because usually we do
+   not need to play with the valueizer.  */
+
+bool
+operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
+{
+  return default_compare_instance.operand_equal_p (arg0, arg1, flags);
+}
+
+namespace inchash
+{
+
+/* Generate a hash value for an expression.  This can be used iteratively
+   by passing a previous result as the HSTATE argument.
+
+   This function is intended to produce the same hash for expressions which
+   would compare equal using operand_equal_p.  */
+void
+add_expr (const_tree t, inchash::hash &hstate, unsigned int flags)
+{
+  default_compare_instance.hash_operand (t, hstate, flags);
+}
+
 }
 \f
 /* Similar to operand_equal_p, but see if ARG0 might be a variant of ARG1
diff --git a/gcc/fold-const.h b/gcc/fold-const.h
index 54c850a3ee1..c9c5cbdae36 100644
--- a/gcc/fold-const.h
+++ b/gcc/fold-const.h
@@ -84,7 +84,7 @@ extern bool fold_deferring_overflow_warnings_p (void);
 extern void fold_overflow_warning (const char*, enum warn_strict_overflow_code);
 extern enum tree_code fold_div_compare (enum tree_code, tree, tree,
 					tree *, tree *, bool *);
-extern bool operand_equal_p (const_tree, const_tree, unsigned int);
+extern bool operand_equal_p (const_tree, const_tree, unsigned int flags = 0);
 extern int multiple_of_p (tree, const_tree, const_tree);
 #define omit_one_operand(T1,T2,T3)\
    omit_one_operand_loc (UNKNOWN_LOCATION, T1, T2, T3)
@@ -212,4 +212,27 @@ extern tree fold_build_pointer_plus_hwi_loc (location_t loc, tree ptr, HOST_WIDE
 
 #define fold_build_pointer_plus_hwi(p,o) \
 	fold_build_pointer_plus_hwi_loc (UNKNOWN_LOCATION, p, o)
+
+
+/* Class used to compare gimple operands.  */
+
+class operand_compare
+{
+public:
+  /* Return true if two operands are equal.  The flags fields can be used
+     to specify OEP flags described above.  */
+  virtual bool operand_equal_p (const_tree, const_tree, unsigned int flags);
+
+  /* Generate a hash value for an expression.  This can be used iteratively
+     by passing a previous result as the HSTATE argument.  */
+  virtual void hash_operand (const_tree, inchash::hash &, unsigned flags);
+
+protected:
+  /* Verify that when arguments (ARG0 and ARG1) are equal, then they have
+     an equal hash value.  When the function knowns comparison return,
+     true is returned.  Then RET is set to corresponding comparsion result.  */
+  bool verify_hash_value (const_tree arg0, const_tree arg1, unsigned int flags,
+			  bool *ret);
+};
+
 #endif // GCC_FOLD_CONST_H
diff --git a/gcc/tree.c b/gcc/tree.c
index 3a0851fdcf8..35c0a2c6fb7 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -7790,292 +7790,6 @@ operation_no_trapping_overflow (tree type, enum tree_code code)
     }
 }
 
-namespace inchash
-{
-
-/* Generate a hash value for an expression.  This can be used iteratively
-   by passing a previous result as the HSTATE argument.
-
-   This function is intended to produce the same hash for expressions which
-   would compare equal using operand_equal_p.  */
-void
-add_expr (const_tree t, inchash::hash &hstate, unsigned int flags)
-{
-  int i;
-  enum tree_code code;
-  enum tree_code_class tclass;
-
-  if (t == NULL_TREE || t == error_mark_node)
-    {
-      hstate.merge_hash (0);
-      return;
-    }
-
-  STRIP_ANY_LOCATION_WRAPPER (t);
-
-  if (!(flags & OEP_ADDRESS_OF))
-    STRIP_NOPS (t);
-
-  code = TREE_CODE (t);
-
-  switch (code)
-    {
-    /* Alas, constants aren't shared, so we can't rely on pointer
-       identity.  */
-    case VOID_CST:
-      hstate.merge_hash (0);
-      return;
-    case INTEGER_CST:
-      gcc_checking_assert (!(flags & OEP_ADDRESS_OF));
-      for (i = 0; i < TREE_INT_CST_EXT_NUNITS (t); i++)
-	hstate.add_hwi (TREE_INT_CST_ELT (t, i));
-      return;
-    case REAL_CST:
-      {
-	unsigned int val2;
-	if (!HONOR_SIGNED_ZEROS (t) && real_zerop (t))
-	  val2 = rvc_zero;
-	else
-	  val2 = real_hash (TREE_REAL_CST_PTR (t));
-	hstate.merge_hash (val2);
-	return;
-      }
-    case FIXED_CST:
-      {
-	unsigned int val2 = fixed_hash (TREE_FIXED_CST_PTR (t));
-	hstate.merge_hash (val2);
-	return;
-      }
-    case STRING_CST:
-      hstate.add ((const void *) TREE_STRING_POINTER (t),
-		  TREE_STRING_LENGTH (t));
-      return;
-    case COMPLEX_CST:
-      inchash::add_expr (TREE_REALPART (t), hstate, flags);
-      inchash::add_expr (TREE_IMAGPART (t), hstate, flags);
-      return;
-    case VECTOR_CST:
-      {
-	hstate.add_int (VECTOR_CST_NPATTERNS (t));
-	hstate.add_int (VECTOR_CST_NELTS_PER_PATTERN (t));
-	unsigned int count = vector_cst_encoded_nelts (t);
-	for (unsigned int i = 0; i < count; ++i)
-	  inchash::add_expr (VECTOR_CST_ENCODED_ELT (t, i), hstate, flags);
-	return;
-      }
-    case SSA_NAME:
-      /* We can just compare by pointer.  */
-      hstate.add_hwi (SSA_NAME_VERSION (t));
-      return;
-    case PLACEHOLDER_EXPR:
-      /* The node itself doesn't matter.  */
-      return;
-    case BLOCK:
-    case OMP_CLAUSE:
-      /* Ignore.  */
-      return;
-    case TREE_LIST:
-      /* A list of expressions, for a CALL_EXPR or as the elements of a
-	 VECTOR_CST.  */
-      for (; t; t = TREE_CHAIN (t))
-	inchash::add_expr (TREE_VALUE (t), hstate, flags);
-      return;
-    case CONSTRUCTOR:
-      {
-	unsigned HOST_WIDE_INT idx;
-	tree field, value;
-	flags &= ~OEP_ADDRESS_OF;
-	FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), idx, field, value)
-	  {
-	    inchash::add_expr (field, hstate, flags);
-	    inchash::add_expr (value, hstate, flags);
-	  }
-	return;
-      }
-    case STATEMENT_LIST:
-      {
-	tree_stmt_iterator i;
-	for (i = tsi_start (CONST_CAST_TREE (t));
-	     !tsi_end_p (i); tsi_next (&i))
-	  inchash::add_expr (tsi_stmt (i), hstate, flags);
-	return;
-      }
-    case TREE_VEC:
-      for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
-	inchash::add_expr (TREE_VEC_ELT (t, i), hstate, flags);
-      return;
-    case IDENTIFIER_NODE:
-      hstate.add_object (IDENTIFIER_HASH_VALUE (t));
-      return;
-    case FIELD_DECL:
-      inchash::add_expr (DECL_FIELD_OFFSET (t), hstate, flags);
-      inchash::add_expr (DECL_FIELD_BIT_OFFSET (t), hstate, flags);
-      return;
-    case FUNCTION_DECL:
-      /* When referring to a built-in FUNCTION_DECL, use the __builtin__ form.
-	 Otherwise nodes that compare equal according to operand_equal_p might
-	 get different hash codes.  However, don't do this for machine specific
-	 or front end builtins, since the function code is overloaded in those
-	 cases.  */
-      if (DECL_BUILT_IN_CLASS (t) == BUILT_IN_NORMAL
-	  && builtin_decl_explicit_p (DECL_FUNCTION_CODE (t)))
-	{
-	  t = builtin_decl_explicit (DECL_FUNCTION_CODE (t));
-	  code = TREE_CODE (t);
-	}
-      /* FALL THROUGH */
-    default:
-      if (POLY_INT_CST_P (t))
-	{
-	  for (unsigned int i = 0; i < NUM_POLY_INT_COEFFS; ++i)
-	    hstate.add_wide_int (wi::to_wide (POLY_INT_CST_COEFF (t, i)));
-	  return;
-	}
-      tclass = TREE_CODE_CLASS (code);
-
-      if (tclass == tcc_declaration)
-	{
-	  /* DECL's have a unique ID */
-	  hstate.add_hwi (DECL_UID (t));
-	}
-      else if (tclass == tcc_comparison && !commutative_tree_code (code))
-	{
-	  /* For comparisons that can be swapped, use the lower
-	     tree code.  */
-	  enum tree_code ccode = swap_tree_comparison (code);
-	  if (code < ccode)
-	    ccode = code;
-	  hstate.add_object (ccode);
-	  inchash::add_expr (TREE_OPERAND (t, ccode != code), hstate, flags);
-	  inchash::add_expr (TREE_OPERAND (t, ccode == code), hstate, flags);
-	}
-      else if (CONVERT_EXPR_CODE_P (code))
-	{
-	  /* NOP_EXPR and CONVERT_EXPR are considered equal by
-	     operand_equal_p.  */
-	  enum tree_code ccode = NOP_EXPR;
-	  hstate.add_object (ccode);
-
-	  /* Don't hash the type, that can lead to having nodes which
-	     compare equal according to operand_equal_p, but which
-	     have different hash codes.  Make sure to include signedness
-	     in the hash computation.  */
-	  hstate.add_int (TYPE_UNSIGNED (TREE_TYPE (t)));
-	  inchash::add_expr (TREE_OPERAND (t, 0), hstate, flags);
-	}
-      /* For OEP_ADDRESS_OF, hash MEM_EXPR[&decl, 0] the same as decl.  */
-      else if (code == MEM_REF
-	       && (flags & OEP_ADDRESS_OF) != 0
-	       && TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR
-	       && DECL_P (TREE_OPERAND (TREE_OPERAND (t, 0), 0))
-	       && integer_zerop (TREE_OPERAND (t, 1)))
-	inchash::add_expr (TREE_OPERAND (TREE_OPERAND (t, 0), 0),
-			   hstate, flags);
-      /* Don't ICE on FE specific trees, or their arguments etc.
-	 during operand_equal_p hash verification.  */
-      else if (!IS_EXPR_CODE_CLASS (tclass))
-	gcc_assert (flags & OEP_HASH_CHECK);
-      else
-	{
-	  unsigned int sflags = flags;
-
-	  hstate.add_object (code);
-
-	  switch (code)
-	    {
-	    case ADDR_EXPR:
-	      gcc_checking_assert (!(flags & OEP_ADDRESS_OF));
-	      flags |= OEP_ADDRESS_OF;
-	      sflags = flags;
-	      break;
-
-	    case INDIRECT_REF:
-	    case MEM_REF:
-	    case TARGET_MEM_REF:
-	      flags &= ~OEP_ADDRESS_OF;
-	      sflags = flags;
-	      break;
-
-	    case ARRAY_REF:
-	    case ARRAY_RANGE_REF:
-	    case COMPONENT_REF:
-	    case BIT_FIELD_REF:
-	      sflags &= ~OEP_ADDRESS_OF;
-	      break;
-
-	    case COND_EXPR:
-	      flags &= ~OEP_ADDRESS_OF;
-	      break;
-
-	    case WIDEN_MULT_PLUS_EXPR:
-	    case WIDEN_MULT_MINUS_EXPR:
-	      {
-		/* The multiplication operands are commutative.  */
-		inchash::hash one, two;
-		inchash::add_expr (TREE_OPERAND (t, 0), one, flags);
-		inchash::add_expr (TREE_OPERAND (t, 1), two, flags);
-		hstate.add_commutative (one, two);
-		inchash::add_expr (TREE_OPERAND (t, 2), two, flags);
-		return;
-	      }
-
-	    case CALL_EXPR:
-	      if (CALL_EXPR_FN (t) == NULL_TREE)
-		hstate.add_int (CALL_EXPR_IFN (t));
-	      break;
-
-	    case TARGET_EXPR:
-	      /* For TARGET_EXPR, just hash on the TARGET_EXPR_SLOT.
-		 Usually different TARGET_EXPRs just should use
-		 different temporaries in their slots.  */
-	      inchash::add_expr (TARGET_EXPR_SLOT (t), hstate, flags);
-	      return;
-
-	    /* Virtual table call.  */
-	    case OBJ_TYPE_REF:
-	      inchash::add_expr (OBJ_TYPE_REF_EXPR (t), hstate, flags);
-	      if (virtual_method_call_p (t))
-		{
-		  inchash::add_expr (OBJ_TYPE_REF_TOKEN (t), hstate, flags);
-		  inchash::add_expr (OBJ_TYPE_REF_OBJECT (t), hstate, flags);
-		}
-	      return;
-	    default:
-	      break;
-	    }
-
-	  /* Don't hash the type, that can lead to having nodes which
-	     compare equal according to operand_equal_p, but which
-	     have different hash codes.  */
-	  if (code == NON_LVALUE_EXPR)
-	    {
-	      /* Make sure to include signness in the hash computation.  */
-	      hstate.add_int (TYPE_UNSIGNED (TREE_TYPE (t)));
-	      inchash::add_expr (TREE_OPERAND (t, 0), hstate, flags);
-	    }
-
-	  else if (commutative_tree_code (code))
-	    {
-	      /* It's a commutative expression.  We want to hash it the same
-		 however it appears.  We do this by first hashing both operands
-		 and then rehashing based on the order of their independent
-		 hashes.  */
-	      inchash::hash one, two;
-	      inchash::add_expr (TREE_OPERAND (t, 0), one, flags);
-	      inchash::add_expr (TREE_OPERAND (t, 1), two, flags);
-	      hstate.add_commutative (one, two);
-	    }
-	  else
-	    for (i = TREE_OPERAND_LENGTH (t) - 1; i >= 0; --i)
-	      inchash::add_expr (TREE_OPERAND (t, i), hstate,
-				 i == 0 ? flags : sflags);
-	}
-      return;
-    }
-}
-
-}
-
 /* Constructors for pointer, array and function types.
    (RECORD_TYPE, UNION_TYPE and ENUMERAL_TYPE nodes are
    constructed by language-dependent code, not here.)  */
-- 
2.22.0


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

* Re: [PATCH 6/9] Integrate that for IPA ICF.
  2019-08-06 15:43               ` [PATCH 6/9] Integrate that for IPA ICF Martin Liska
@ 2019-08-16 11:10                 ` Martin Liška
  0 siblings, 0 replies; 59+ messages in thread
From: Martin Liška @ 2019-08-16 11:10 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 167 bytes --]

I'm sending updated version of the patch.

Note: there are some (tree)const_cast<tree> (t2) casting. I've got a clean up
patch for that which will improve it.

Martin

[-- Attachment #2: 0006-Integrate-that-for-IPA-ICF.patch --]
[-- Type: text/x-patch, Size: 10541 bytes --]

From 20020586beabf1fc9f7860f46bb0c092f8536539 Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Mon, 10 Jun 2019 14:34:15 +0200
Subject: [PATCH 6/9] Integrate that for IPA ICF.

gcc/ChangeLog:

2019-08-15  Martin Liska  <mliska@suse.cz>

	* ipa-icf-gimple.c (func_checker::hash_operand): New.
	(func_checker::compare_cst_or_decl): Remove handling
	of FIELD_DECL.
	(func_checker::compare_operand): Transform to ...
	(func_checker::operand_equal_p): ... this.
	* ipa-icf-gimple.h (class func_checker): Add
	operand_equal_p and hash_operand.
	* ipa-icf.c (sem_function::equals_private): Fix
	pushing and popping of cfun.
---
 gcc/ipa-icf-gimple.c | 228 +++++++++++++++----------------------------
 gcc/ipa-icf-gimple.h |  12 ++-
 gcc/ipa-icf.c        |   7 +-
 3 files changed, 95 insertions(+), 152 deletions(-)

diff --git a/gcc/ipa-icf-gimple.c b/gcc/ipa-icf-gimple.c
index 4060c0e8eb3..96e688c129d 100644
--- a/gcc/ipa-icf-gimple.c
+++ b/gcc/ipa-icf-gimple.c
@@ -324,6 +324,34 @@ func_checker::compare_memory_operand (tree t1, tree t2)
 /* Function compare for equality given trees T1 and T2 which
    can be either a constant or a declaration type.  */
 
+void
+func_checker::hash_operand (const_tree arg, inchash::hash &hstate,
+			    unsigned int flags)
+{
+  if (arg == NULL_TREE)
+    {
+      hstate.merge_hash (0);
+      return;
+    }
+
+  switch (TREE_CODE (arg))
+    {
+    case FUNCTION_DECL:
+    case VAR_DECL:
+    case LABEL_DECL:
+    case PARM_DECL:
+    case RESULT_DECL:
+    case CONST_DECL:
+    case SSA_NAME:
+      return;
+
+    default:
+      break;
+    }
+
+  return operand_compare::hash_operand (arg, hstate, flags);
+}
+
 bool
 func_checker::compare_cst_or_decl (tree t1, tree t2)
 {
@@ -347,19 +375,6 @@ func_checker::compare_cst_or_decl (tree t1, tree t2)
       return true;
     case VAR_DECL:
       return return_with_debug (compare_variable_decl (t1, t2));
-    case FIELD_DECL:
-      {
-	tree offset1 = DECL_FIELD_OFFSET (t1);
-	tree offset2 = DECL_FIELD_OFFSET (t2);
-
-	tree bit_offset1 = DECL_FIELD_BIT_OFFSET (t1);
-	tree bit_offset2 = DECL_FIELD_BIT_OFFSET (t2);
-
-	ret = compare_operand (offset1, offset2)
-	      && compare_operand (bit_offset1, bit_offset2);
-
-	return return_with_debug (ret);
-      }
     case LABEL_DECL:
       {
 	if (t1 == t2)
@@ -383,165 +398,80 @@ func_checker::compare_cst_or_decl (tree t1, tree t2)
     }
 }
 
-/* Function responsible for comparison of various operands T1 and T2.
-   If these components, from functions FUNC1 and FUNC2, are equal, true
-   is returned.  */
-
 bool
-func_checker::compare_operand (tree t1, tree t2)
+func_checker::operand_equal_p (const_tree t1, const_tree t2,
+			       unsigned int flags)
 {
-  tree x1, x2, y1, y2, z1, z2;
-  bool ret;
+  bool r;
+  if (verify_hash_value (t1, t2, flags, &r))
+    return r;
 
-  if (!t1 && !t2)
+  if (t1 == t2)
     return true;
   else if (!t1 || !t2)
     return false;
 
-  tree tt1 = TREE_TYPE (t1);
-  tree tt2 = TREE_TYPE (t2);
-
-  if (!func_checker::compatible_types_p (tt1, tt2))
-    return false;
-
   if (TREE_CODE (t1) != TREE_CODE (t2))
     return return_false ();
 
+  tree tree1 = (tree)const_cast<tree> (t1);
+  tree tree2 = (tree)const_cast<tree> (t2);
+
   switch (TREE_CODE (t1))
     {
-    case CONSTRUCTOR:
+    case FUNCTION_DECL:
+      /* All function decls are in the symbol table and known to match
+	 before we start comparing bodies.  */
+      return true;
+    case VAR_DECL:
+      return return_with_debug (compare_variable_decl (tree1, tree2));
+    case LABEL_DECL:
       {
-	unsigned length1 = CONSTRUCTOR_NELTS (t1);
-	unsigned length2 = CONSTRUCTOR_NELTS (t2);
-
-	if (length1 != length2)
-	  return return_false ();
-
-	for (unsigned i = 0; i < length1; i++)
-	  if (!compare_operand (CONSTRUCTOR_ELT (t1, i)->value,
-				CONSTRUCTOR_ELT (t2, i)->value))
-	    return return_false();
-
-	return true;
+	int *bb1 = m_label_bb_map.get (tree1);
+	int *bb2 = m_label_bb_map.get (tree2);
+	/* Labels can point to another function (non-local GOTOs).  */
+	return return_with_debug (bb1 != NULL && bb2 != NULL && *bb1 == *bb2);
       }
-    case ARRAY_REF:
-    case ARRAY_RANGE_REF:
-      /* First argument is the array, second is the index.  */
-      x1 = TREE_OPERAND (t1, 0);
-      x2 = TREE_OPERAND (t2, 0);
-      y1 = TREE_OPERAND (t1, 1);
-      y2 = TREE_OPERAND (t2, 1);
-
-      if (!compare_operand (array_ref_low_bound (t1),
-			    array_ref_low_bound (t2)))
-	return return_false_with_msg ("");
-      if (!compare_operand (array_ref_element_size (t1),
-			    array_ref_element_size (t2)))
-	return return_false_with_msg ("");
-
-      if (!compare_operand (x1, x2))
-	return return_false_with_msg ("");
-      return compare_operand (y1, y2);
-    case MEM_REF:
-      {
-	x1 = TREE_OPERAND (t1, 0);
-	x2 = TREE_OPERAND (t2, 0);
-	y1 = TREE_OPERAND (t1, 1);
-	y2 = TREE_OPERAND (t2, 1);
-
-	/* See if operand is an memory access (the test originate from
-	 gimple_load_p).
-
-	In this case the alias set of the function being replaced must
-	be subset of the alias set of the other function.  At the moment
-	we seek for equivalency classes, so simply require inclussion in
-	both directions.  */
 
-	if (!func_checker::compatible_types_p (TREE_TYPE (x1), TREE_TYPE (x2)))
-	  return return_false ();
-
-	if (!compare_operand (x1, x2))
-	  return return_false_with_msg ("");
-
-	/* Type of the offset on MEM_REF does not matter.  */
-	return known_eq (wi::to_poly_offset (y1), wi::to_poly_offset (y2));
-      }
-    case COMPONENT_REF:
+    case PARM_DECL:
+    case RESULT_DECL:
+    case CONST_DECL:
+      return compare_decl (tree1, tree2);
+    case SSA_NAME:
+      return compare_ssa_name (tree1, tree2);
+    case FIELD_DECL:
       {
-	x1 = TREE_OPERAND (t1, 0);
-	x2 = TREE_OPERAND (t2, 0);
-	y1 = TREE_OPERAND (t1, 1);
-	y2 = TREE_OPERAND (t2, 1);
+	tree offset1 = DECL_FIELD_OFFSET (t1);
+	tree offset2 = DECL_FIELD_OFFSET (t2);
 
-	ret = compare_operand (x1, x2)
-	      && compare_cst_or_decl (y1, y2);
+	tree bit_offset1 = DECL_FIELD_BIT_OFFSET (t1);
+	tree bit_offset2 = DECL_FIELD_BIT_OFFSET (t2);
 
+	bool ret = (compare_operand (offset1, offset2)
+		    && compare_operand (bit_offset1, bit_offset2));
 	return return_with_debug (ret);
       }
-    /* Virtual table call.  */
-    case OBJ_TYPE_REF:
-      {
-	if (!compare_ssa_name (OBJ_TYPE_REF_EXPR (t1), OBJ_TYPE_REF_EXPR (t2)))
-	  return return_false ();
-	if (opt_for_fn (m_source_func_decl, flag_devirtualize)
-	    && virtual_method_call_p (t1))
-	  {
-	    if (tree_to_uhwi (OBJ_TYPE_REF_TOKEN (t1))
-		!= tree_to_uhwi (OBJ_TYPE_REF_TOKEN (t2)))
-	      return return_false_with_msg ("OBJ_TYPE_REF token mismatch");
-	    if (!types_same_for_odr (obj_type_ref_class (t1),
-				     obj_type_ref_class (t2)))
-	      return return_false_with_msg ("OBJ_TYPE_REF OTR type mismatch");
-	    if (!compare_operand (OBJ_TYPE_REF_OBJECT (t1),
-				  OBJ_TYPE_REF_OBJECT (t2)))
-	      return return_false_with_msg ("OBJ_TYPE_REF object mismatch");
-	  }
-
-	return return_with_debug (true);
-      }
-    case IMAGPART_EXPR:
-    case REALPART_EXPR:
-    case ADDR_EXPR:
-      {
-	x1 = TREE_OPERAND (t1, 0);
-	x2 = TREE_OPERAND (t2, 0);
+    default:
+      break;
+    }
 
-	ret = compare_operand (x1, x2);
-	return return_with_debug (ret);
-      }
-    case BIT_FIELD_REF:
-      {
-	x1 = TREE_OPERAND (t1, 0);
-	x2 = TREE_OPERAND (t2, 0);
-	y1 = TREE_OPERAND (t1, 1);
-	y2 = TREE_OPERAND (t2, 1);
-	z1 = TREE_OPERAND (t1, 2);
-	z2 = TREE_OPERAND (t2, 2);
+  return operand_compare::operand_equal_p (t1, t2, flags);
+}
 
-	ret = compare_operand (x1, x2)
-	      && compare_cst_or_decl (y1, y2)
-	      && compare_cst_or_decl (z1, z2);
+/* Function responsible for comparison of various operands T1 and T2.
+   If these components, from functions FUNC1 and FUNC2, are equal, true
+   is returned.  */
 
-	return return_with_debug (ret);
-      }
-    case SSA_NAME:
-	return compare_ssa_name (t1, t2);
-    case INTEGER_CST:
-    case COMPLEX_CST:
-    case VECTOR_CST:
-    case STRING_CST:
-    case REAL_CST:
-    case FUNCTION_DECL:
-    case VAR_DECL:
-    case FIELD_DECL:
-    case LABEL_DECL:
-    case PARM_DECL:
-    case RESULT_DECL:
-    case CONST_DECL:
-      return compare_cst_or_decl (t1, t2);
-    default:
-      return return_false_with_msg ("Unknown TREE code reached");
-    }
+bool
+func_checker::compare_operand (tree t1, tree t2)
+{
+  if (!t1 && !t2)
+    return true;
+  else if (!t1 || !t2)
+    return false;
+  if (operand_equal_p (t1, t2, OEP_MATCH_SIDE_EFFECTS))
+    return true;
+  return return_false_with_msg ("operand_equal_p failed");
 }
 
 bool
diff --git a/gcc/ipa-icf-gimple.h b/gcc/ipa-icf-gimple.h
index 351bddfb2f6..f56427b13e5 100644
--- a/gcc/ipa-icf-gimple.h
+++ b/gcc/ipa-icf-gimple.h
@@ -118,7 +118,7 @@ public:
 
 /* A class aggregating all connections and semantic equivalents
    for a given pair of semantic function candidates.  */
-class func_checker
+class func_checker : operand_compare
 {
 public:
   /* Initialize internal structures for a given SOURCE_FUNC_DECL and
@@ -134,7 +134,7 @@ public:
 		hash_set<symtab_node *> *ignored_target_nodes = NULL);
 
   /* Memory release routine.  */
-  ~func_checker();
+  virtual ~func_checker ();
 
   /* Function visits all gimple labels and creates corresponding
      mapping between basic blocks and labels.  */
@@ -267,6 +267,14 @@ private:
 
   /* Flag if ignore labels in comparison.  */
   bool m_ignore_labels;
+
+  /* Return true if two operands are equal.  The flags fields can be used
+     to specify OEP flags described above.  */
+  virtual bool operand_equal_p (const_tree, const_tree, unsigned int flags);
+
+  /* Generate a hash value for an expression.  This can be used iteratively
+     by passing a previous result as the HSTATE argument.  */
+  virtual void hash_operand (const_tree, inchash::hash &, unsigned flags);
 };
 
 } // ipa_icf_gimple namespace
diff --git a/gcc/ipa-icf.c b/gcc/ipa-icf.c
index c9c3cb4a331..8b8cc26a69f 100644
--- a/gcc/ipa-icf.c
+++ b/gcc/ipa-icf.c
@@ -878,9 +878,14 @@ sem_function::equals_private (sem_item *item)
     }
 
   /* Checking all basic blocks.  */
+  push_cfun (DECL_STRUCT_FUNCTION (decl));
   for (unsigned i = 0; i < bb_sorted.length (); ++i)
     if(!m_checker->compare_bb (bb_sorted[i], m_compared_func->bb_sorted[i]))
-      return return_false();
+      {
+	pop_cfun ();
+	return return_false ();
+      }
+  pop_cfun ();
 
   auto_vec <int> bb_dict;
 
-- 
2.22.0


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

* [PATCH 10/N] Use const_tree more in IPA ICF.
  2019-08-06 15:44             ` [PATCH 0/9] IPA ICF overhaul Martin Liska
                                 ` (8 preceding siblings ...)
  2019-08-06 15:55               ` [PATCH 3/9] operand_equal_p: add support for OBJ_TYPE_REF Martin Liska
@ 2019-08-16 11:53               ` Martin Liška
  2019-08-19 13:57                 ` Richard Biener
  2019-10-30 11:54               ` [PATCH 0/9] IPA ICF overhaul Martin Liška
  10 siblings, 1 reply; 59+ messages in thread
From: Martin Liška @ 2019-08-16 11:53 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 131 bytes --]

Hi.

The patch is a mechanical clean up that changes some
functions and data structures to use const_tree instead
of tree.

Martin

[-- Attachment #2: 0010-Use-const_tree-more-in-IPA-ICF.patch --]
[-- Type: text/x-patch, Size: 5874 bytes --]

From 4f8267c542b038ff1c766b57f168fe817d8dbb91 Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Thu, 15 Aug 2019 13:38:51 +0200
Subject: [PATCH 10/10] Use const_tree more in IPA ICF.

gcc/ChangeLog:

2019-08-15  Martin Liska  <mliska@suse.cz>

	* ipa-icf-gimple.c (func_checker::compare_ssa_name): Use
	const_tree as function argument.
	(func_checker::compare_decl): Likewise.
	(func_checker::operand_equal_p): Likewise.
	(func_checker::compare_variable_decl): Likewise.
	(func_checker::parse_labels): Likewise.
	* ipa-icf-gimple.h: Likewise.
---
 gcc/ipa-icf-gimple.c | 25 +++++++++++--------------
 gcc/ipa-icf-gimple.h | 10 +++++-----
 2 files changed, 16 insertions(+), 19 deletions(-)

diff --git a/gcc/ipa-icf-gimple.c b/gcc/ipa-icf-gimple.c
index 5b0fbc19fc4..990ee046035 100644
--- a/gcc/ipa-icf-gimple.c
+++ b/gcc/ipa-icf-gimple.c
@@ -85,7 +85,7 @@ func_checker::~func_checker ()
 /* Verifies that trees T1 and T2 are equivalent from perspective of ICF.  */
 
 bool
-func_checker::compare_ssa_name (tree t1, tree t2)
+func_checker::compare_ssa_name (const_tree t1, const_tree t2)
 {
   gcc_assert (TREE_CODE (t1) == SSA_NAME);
   gcc_assert (TREE_CODE (t2) == SSA_NAME);
@@ -139,7 +139,7 @@ func_checker::compare_edge (edge e1, edge e2)
    come from functions FUNC1 and FUNC2.  */
 
 bool
-func_checker::compare_decl (tree t1, tree t2)
+func_checker::compare_decl (const_tree t1, const_tree t2)
 {
   if (!auto_var_in_fn_p (t1, m_source_func_decl)
       || !auto_var_in_fn_p (t2, m_target_func_decl))
@@ -154,7 +154,7 @@ func_checker::compare_decl (tree t1, tree t2)
     return return_false ();
 
   bool existed_p;
-  tree &slot = m_decl_map.get_or_insert (t1, &existed_p);
+  const_tree &slot = m_decl_map.get_or_insert (t1, &existed_p);
   if (existed_p)
     return return_with_debug (slot == t2);
   else
@@ -258,9 +258,6 @@ func_checker::operand_equal_p (const_tree t1, const_tree t2,
   if (TREE_CODE (t1) != TREE_CODE (t2))
     return return_false ();
 
-  tree tree1 = (tree)const_cast<tree> (t1);
-  tree tree2 = (tree)const_cast<tree> (t2);
-
   switch (TREE_CODE (t1))
     {
     case FUNCTION_DECL:
@@ -268,11 +265,11 @@ func_checker::operand_equal_p (const_tree t1, const_tree t2,
 	 before we start comparing bodies.  */
       return true;
     case VAR_DECL:
-      return return_with_debug (compare_variable_decl (tree1, tree2));
+      return return_with_debug (compare_variable_decl (t1, t2));
     case LABEL_DECL:
       {
-	int *bb1 = m_label_bb_map.get (tree1);
-	int *bb2 = m_label_bb_map.get (tree2);
+	int *bb1 = m_label_bb_map.get (t1);
+	int *bb2 = m_label_bb_map.get (t2);
 	/* Labels can point to another function (non-local GOTOs).  */
 	return return_with_debug (bb1 != NULL && bb2 != NULL && *bb1 == *bb2);
       }
@@ -280,9 +277,9 @@ func_checker::operand_equal_p (const_tree t1, const_tree t2,
     case PARM_DECL:
     case RESULT_DECL:
     case CONST_DECL:
-      return compare_decl (tree1, tree2);
+      return compare_decl (t1, t2);
     case SSA_NAME:
-      return compare_ssa_name (tree1, tree2);
+      return compare_ssa_name (t1, t2);
     default:
       break;
     }
@@ -342,7 +339,7 @@ func_checker::compare_asm_inputs_outputs (tree t1, tree t2)
 /* Verifies that trees T1 and T2 do correspond.  */
 
 bool
-func_checker::compare_variable_decl (tree t1, tree t2)
+func_checker::compare_variable_decl (const_tree t1, const_tree t2)
 {
   bool ret = false;
 
@@ -356,7 +353,7 @@ func_checker::compare_variable_decl (tree t1, tree t2)
     return return_false_with_msg ("DECL_HARD_REGISTER are different");
 
   if (DECL_HARD_REGISTER (t1)
-      && DECL_ASSEMBLER_NAME (t1) != DECL_ASSEMBLER_NAME (t2))
+      && DECL_ASSEMBLER_NAME_RAW (t1) != DECL_ASSEMBLER_NAME_RAW (t2))
     return return_false_with_msg ("HARD REGISTERS are different");
 
   /* Symbol table variables are known to match before we start comparing
@@ -416,7 +413,7 @@ func_checker::parse_labels (sem_bb *bb)
 
       if (glabel *label_stmt = dyn_cast <glabel *> (stmt))
 	{
-	  tree t = gimple_label_label (label_stmt);
+	  const_tree t = gimple_label_label (label_stmt);
 	  gcc_assert (TREE_CODE (t) == LABEL_DECL);
 
 	  m_label_bb_map.put (t, bb->bb->index);
diff --git a/gcc/ipa-icf-gimple.h b/gcc/ipa-icf-gimple.h
index 8e0f03c1d14..25dff31394b 100644
--- a/gcc/ipa-icf-gimple.h
+++ b/gcc/ipa-icf-gimple.h
@@ -144,7 +144,7 @@ public:
   bool compare_bb (sem_bb *bb1, sem_bb *bb2);
 
   /* Verifies that trees T1 and T2 are equivalent from perspective of ICF.  */
-  bool compare_ssa_name (tree t1, tree t2);
+  bool compare_ssa_name (const_tree t1, const_tree t2);
 
   /* Verification function for edges E1 and E2.  */
   bool compare_edge (edge e1, edge e2);
@@ -188,7 +188,7 @@ public:
   bool compare_gimple_asm (const gasm *s1, const gasm *s2);
 
   /* Verification function for declaration trees T1 and T2.  */
-  bool compare_decl (tree t1, tree t2);
+  bool compare_decl (const_tree t1, const_tree t2);
 
   /* Verifies that tree labels T1 and T2 correspond.  */
   bool compare_tree_ssa_label (tree t1, tree t2);
@@ -210,7 +210,7 @@ public:
   bool compare_function_decl (tree t1, tree t2);
 
   /* Verifies that trees T1 and T2 do correspond.  */
-  bool compare_variable_decl (tree t1, tree t2);
+  bool compare_variable_decl (const_tree t1, const_tree t2);
 
   /* Compare loop information for basic blocks BB1 and BB2.  */
   bool compare_loops (basic_block bb1, basic_block bb2);
@@ -252,10 +252,10 @@ private:
   hash_map <edge, edge> m_edge_map;
 
   /* Source to target declaration map.  */
-  hash_map <tree, tree> m_decl_map;
+  hash_map <const_tree, const_tree> m_decl_map;
 
   /* Label to basic block index mapping.  */
-  hash_map <tree, int> m_label_bb_map;
+  hash_map <const_tree, int> m_label_bb_map;
 
   /* Flag if ignore labels in comparison.  */
   bool m_ignore_labels;
-- 
2.22.0


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

* Re: [PATCH 3/9] operand_equal_p: add support for OBJ_TYPE_REF.
  2019-08-16  9:25                     ` Richard Biener
@ 2019-08-16 12:11                       ` Jan Hubicka
  2019-08-19 14:03                         ` Richard Biener
  0 siblings, 1 reply; 59+ messages in thread
From: Jan Hubicka @ 2019-08-16 12:11 UTC (permalink / raw)
  To: Richard Biener; +Cc: Martin Liska, GCC Patches

> 
> When we compare OBJ_TYPE_REF_TOKEN and OBJ_TYPE_REF_OBJECT
> and they are equal, are there cases where types_same_for_odr returns false?

OBJ_TYPE_REF_OBJECT is pointer to the instance, OBJ_TYPE_REF_TOKEN is
index in the vtable or the type given by obj_ref_type_class.  I guess
one can do something like

 void *ptr;
 ...
 if (cond)
   ((class_a *)ptr)->firstvirtualmethod_of_class_a ();
 else
   ((class_b *)ptr)->firstvirtualmethod_of_class_b ();

Here OBJECT will be always *ptr, TOKEN will be 0, but the actual virtual
method is different. So merging this may lead to invalid
devirtualization at least when the classes are anonymous namespace and
we work out late in compilation that they are not derived.
> 
> I guess we went over this some time ago when talking about value-numbering
> of them.  I realize the devirt machinery use the class type to get at the
> virtual table but since we later expand simply OBJ_TPE_REF_EXPR _that_
> already has the result of the load from the vitual table.
> 
> So - do we need to compare obj_type_ref_class at all?  The worst thing
> that could happen is that devirt no longer can devirtualize after the merging
> but it should never result in "wrong" devirtualization?  So, do we really
> want to inhibit ICF of two equal functions that could be eventually
> devirtualized both but into different direct calls?  Can't this sort of thing

I think it is like with the TBAA info.  I would suggest first implement
tests that preserve correctness of both TBAA and devirt annotations.
Incrementally we can teach ICF to be agressive with -Os and merge anyway
while dropping the metadata (removing OBJ_TYPE_REF or adjusting alias
sets
> happen anyway when you'd factor in IPA-CP and two identical functions
> with indirect calls to a function argument but called with different constant
> args?  And should IPA-CP then not consider cloning after ICF merging
> (not sure how ordering works here).

I am not sure how those are realated. For sure IPA-CP can clone when it
works out that different types are passed to the function and
devirtualize to different calls. But this is bit different - it is about
the type annotation we

Honza
> 
> Richard.
> 
> > Honza
> > >
> > > +             }
> > >
> > >
> > > > 2019-07-24  Martin Liska  <mliska@suse.cz>
> > > >
> > > >         * fold-const.c (operand_equal_p): Support OBJ_TYPE_REF.
> > > >         * tree.c (add_expr): Hash parts of OBJ_TYPE_REF.
> > > > ---
> > > >  gcc/fold-const.c | 21 +++++++++++++++++++++
> > > >  gcc/tree.c       |  9 +++++++++
> > > >  2 files changed, 30 insertions(+)
> > > >

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

* Re: [PATCH 2/9] operand_equal_p: add support for FIELD_DECL
  2019-08-16  9:28                     ` Richard Biener
@ 2019-08-16 12:17                       ` Jan Hubicka
  2019-09-11 12:58                         ` Martin Liška
  0 siblings, 1 reply; 59+ messages in thread
From: Jan Hubicka @ 2019-08-16 12:17 UTC (permalink / raw)
  To: Richard Biener; +Cc: Martin Liska, GCC Patches

> On Thu, Aug 15, 2019 at 4:17 PM Jan Hubicka <hubicka@ucw.cz> wrote:
> >
> > > On Tue, Aug 6, 2019 at 5:44 PM Martin Liska <mliska@suse.cz> wrote:
> > > >
> > > >
> > > > gcc/ChangeLog:
> > >
> > > So I suppose this isn't to call operand_equal_p on two FIELD_DECLs
> > > but to make two COMPONENT_REFs "more equal"?  If so I then
> >
> > yes. The patch originates from my original patchset I believe and it is
> > what ICF does.
> > > I suggest to make this change "local" to the COMPONENT_REF handling.
> > > This also interacts with path-based disambiguation so you want to make
> > > sure to only make things equal here iff it wouldn't change the outcome
> > > of path-based analysis.  Honza?
> >
> > Indeed this can be handled as part of COMPONENT_REF match.
> > Access path oracle here basically checks:
> >  1) that MEM_REF type matches (we want predicate for this)
> >  2) if it finds type match via same_type_for_tbaa and then it applies
> >     the assumption about disjointness or overlap
> >
> > So I guess ideally we should
> >
> >  1) do matching part of COMPONENT_REF
> >  2) compare OFFSET, BIT_OFFSET
> >     This establishes that the access has same semantics.
> >  3) for -fno-strict-aliasing be happy
> >  4) for -fstrict-aliaisng check if access path applies (we should export
> >     predicate from tree-ssa-alias as discussed earlier)
> >  5) compare types by same_type_for_tbaa_p
> 
> Ick.  This smells like a layering violation to me.  IMHO this extended
> equality handling should be handled with the overloading/callback
> and not in native operand_equal_p.  Either on the level of the
> COMPONENT_REF itself (sounds like that would be needed)
> or the FIELD_DECL.  Not sure if the above suggestions make
> it neccessary to look at more than a single COMPONENT_REF/FIELD_DECL
> in the access path.  If so then watch out for quadraticness as operand_equal_p
> traverses a reference chain...

I suppose we want to match whole access paths at once, since only having
the MEM_REF allows one to check whether access path oracle applies to
the given reference or not...

Honza
> 
> Richard.
> 
> > Honza

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

* Re: [PATCH 10/N] Use const_tree more in IPA ICF.
  2019-08-16 11:53               ` [PATCH 10/N] Use const_tree more in IPA ICF Martin Liška
@ 2019-08-19 13:57                 ` Richard Biener
  0 siblings, 0 replies; 59+ messages in thread
From: Richard Biener @ 2019-08-19 13:57 UTC (permalink / raw)
  To: Martin Liška; +Cc: GCC Patches

On Fri, Aug 16, 2019 at 1:06 PM Martin Liška <mliska@suse.cz> wrote:
>
> Hi.
>
> The patch is a mechanical clean up that changes some
> functions and data structures to use const_tree instead
> of tree.

I think this kind of changes are obvious.

Richard.

> Martin

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

* Re: [PATCH 3/9] operand_equal_p: add support for OBJ_TYPE_REF.
  2019-08-16 12:11                       ` Jan Hubicka
@ 2019-08-19 14:03                         ` Richard Biener
  2019-08-19 15:12                           ` Jan Hubicka
  0 siblings, 1 reply; 59+ messages in thread
From: Richard Biener @ 2019-08-19 14:03 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: Martin Liska, GCC Patches

On Fri, Aug 16, 2019 at 2:07 PM Jan Hubicka <hubicka@ucw.cz> wrote:
>
> >
> > When we compare OBJ_TYPE_REF_TOKEN and OBJ_TYPE_REF_OBJECT
> > and they are equal, are there cases where types_same_for_odr returns false?
>
> OBJ_TYPE_REF_OBJECT is pointer to the instance, OBJ_TYPE_REF_TOKEN is
> index in the vtable or the type given by obj_ref_type_class.  I guess
> one can do something like
>
>  void *ptr;
>  ...
>  if (cond)
>    ((class_a *)ptr)->firstvirtualmethod_of_class_a ();
>  else
>    ((class_b *)ptr)->firstvirtualmethod_of_class_b ();
>
> Here OBJECT will be always *ptr, TOKEN will be 0, but the actual virtual
> method is different. So merging this may lead to invalid
> devirtualization at least when the classes are anonymous namespace and
> we work out late in compilation that they are not derived.

But we also compare OBJ_TYPE_REF_EXPR and later we expand to a call
with exactly that address...

> >
> > I guess we went over this some time ago when talking about value-numbering
> > of them.  I realize the devirt machinery use the class type to get at the
> > virtual table but since we later expand simply OBJ_TPE_REF_EXPR _that_
> > already has the result of the load from the vitual table.
> >
> > So - do we need to compare obj_type_ref_class at all?  The worst thing
> > that could happen is that devirt no longer can devirtualize after the merging
> > but it should never result in "wrong" devirtualization?  So, do we really
> > want to inhibit ICF of two equal functions that could be eventually
> > devirtualized both but into different direct calls?  Can't this sort of thing
>
> I think it is like with the TBAA info.  I would suggest first implement
> tests that preserve correctness of both TBAA and devirt annotations.
> Incrementally we can teach ICF to be agressive with -Os and merge anyway
> while dropping the metadata (removing OBJ_TYPE_REF or adjusting alias
> sets
> > happen anyway when you'd factor in IPA-CP and two identical functions
> > with indirect calls to a function argument but called with different constant
> > args?  And should IPA-CP then not consider cloning after ICF merging
> > (not sure how ordering works here).
>
> I am not sure how those are realated. For sure IPA-CP can clone when it
> works out that different types are passed to the function and
> devirtualize to different calls. But this is bit different - it is about
> the type annotation we
>
> Honza
> >
> > Richard.
> >
> > > Honza
> > > >
> > > > +             }
> > > >
> > > >
> > > > > 2019-07-24  Martin Liska  <mliska@suse.cz>
> > > > >
> > > > >         * fold-const.c (operand_equal_p): Support OBJ_TYPE_REF.
> > > > >         * tree.c (add_expr): Hash parts of OBJ_TYPE_REF.
> > > > > ---
> > > > >  gcc/fold-const.c | 21 +++++++++++++++++++++
> > > > >  gcc/tree.c       |  9 +++++++++
> > > > >  2 files changed, 30 insertions(+)
> > > > >

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

* Re: [PATCH 3/9] operand_equal_p: add support for OBJ_TYPE_REF.
  2019-08-19 14:03                         ` Richard Biener
@ 2019-08-19 15:12                           ` Jan Hubicka
  2019-08-20 14:29                             ` Richard Biener
  0 siblings, 1 reply; 59+ messages in thread
From: Jan Hubicka @ 2019-08-19 15:12 UTC (permalink / raw)
  To: Richard Biener; +Cc: Martin Liska, GCC Patches

> On Fri, Aug 16, 2019 at 2:07 PM Jan Hubicka <hubicka@ucw.cz> wrote:
> >
> > >
> > > When we compare OBJ_TYPE_REF_TOKEN and OBJ_TYPE_REF_OBJECT
> > > and they are equal, are there cases where types_same_for_odr returns false?
> >
> > OBJ_TYPE_REF_OBJECT is pointer to the instance, OBJ_TYPE_REF_TOKEN is
> > index in the vtable or the type given by obj_ref_type_class.  I guess
> > one can do something like
> >
> >  void *ptr;
> >  ...
> >  if (cond)
> >    ((class_a *)ptr)->firstvirtualmethod_of_class_a ();
> >  else
> >    ((class_b *)ptr)->firstvirtualmethod_of_class_b ();
> >
> > Here OBJECT will be always *ptr, TOKEN will be 0, but the actual virtual
> > method is different. So merging this may lead to invalid
> > devirtualization at least when the classes are anonymous namespace and
> > we work out late in compilation that they are not derived.
> 
> But we also compare OBJ_TYPE_REF_EXPR and later we expand to a call
> with exactly that address...

I think this is same as with memory references.  Just because the
addresses compare equal and read same type we still can not merge w/o
verifying that the alias oracle will not give different answers 
(so we need to compare cliques and access paths). operand_equal_p does
checking in this case though it is bit random on way it understands
access paths.

To get more agressive unification we can drop the optional metadata
(i.e. remove OBJ_TYPE_REF or drop to alias set zero) while merging but I
think this will need more care and decisions what to do for -Os only and
what to do for -O2/fast.  For this reason I would first handle this
conservatively (i.e. require match of metadata as well) and then improve
from that.

Honza

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

* Re: [PATCH 3/9] operand_equal_p: add support for OBJ_TYPE_REF.
  2019-08-19 15:12                           ` Jan Hubicka
@ 2019-08-20 14:29                             ` Richard Biener
  2019-08-20 14:42                               ` Jan Hubicka
  2019-09-13 12:30                               ` Martin Liška
  0 siblings, 2 replies; 59+ messages in thread
From: Richard Biener @ 2019-08-20 14:29 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: Martin Liska, GCC Patches

On Mon, Aug 19, 2019 at 4:34 PM Jan Hubicka <hubicka@ucw.cz> wrote:
>
> > On Fri, Aug 16, 2019 at 2:07 PM Jan Hubicka <hubicka@ucw.cz> wrote:
> > >
> > > >
> > > > When we compare OBJ_TYPE_REF_TOKEN and OBJ_TYPE_REF_OBJECT
> > > > and they are equal, are there cases where types_same_for_odr returns false?
> > >
> > > OBJ_TYPE_REF_OBJECT is pointer to the instance, OBJ_TYPE_REF_TOKEN is
> > > index in the vtable or the type given by obj_ref_type_class.  I guess
> > > one can do something like
> > >
> > >  void *ptr;
> > >  ...
> > >  if (cond)
> > >    ((class_a *)ptr)->firstvirtualmethod_of_class_a ();
> > >  else
> > >    ((class_b *)ptr)->firstvirtualmethod_of_class_b ();
> > >
> > > Here OBJECT will be always *ptr, TOKEN will be 0, but the actual virtual
> > > method is different. So merging this may lead to invalid
> > > devirtualization at least when the classes are anonymous namespace and
> > > we work out late in compilation that they are not derived.
> >
> > But we also compare OBJ_TYPE_REF_EXPR and later we expand to a call
> > with exactly that address...
>
> I think this is same as with memory references.  Just because the
> addresses compare equal and read same type we still can not merge w/o
> verifying that the alias oracle will not give different answers
> (so we need to compare cliques and access paths). operand_equal_p does
> checking in this case though it is bit random on way it understands
> access paths.
>
> To get more agressive unification we can drop the optional metadata
> (i.e. remove OBJ_TYPE_REF or drop to alias set zero) while merging but I
> think this will need more care and decisions what to do for -Os only and
> what to do for -O2/fast.  For this reason I would first handle this
> conservatively (i.e. require match of metadata as well) and then improve
> from that.

I see.  I guess dropping them if !virtual_method_call_p (at what point
do we know?) would be a good thing.  As well as encoding
"types_same_for_odr" and obj_type_ref_class in a more direct manner.
I guess in reality OBJ_TYPE_REF should be all info on the
gimple_call rather than in a GENERIC tree in the call fn slot or
a separate stmt ...

Anyhow, the original patch is OK if you compare
OBJ_TYPE_REF_TOKEN/OBJECT irrespective of virtual_method_call_p
and order the types_same_for_odr last since that's most expensive.
I also wonder if virtual_method_call_p needs to return a
"maybe" and we have to say not equal in that case rather than just
not comparing obj_type_ref_class ...  (operand_equal_p might be called
from FEs during parsing)

Richard.

Thanks,
Richard.

> Honza

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

* Re: [PATCH 3/9] operand_equal_p: add support for OBJ_TYPE_REF.
  2019-08-20 14:29                             ` Richard Biener
@ 2019-08-20 14:42                               ` Jan Hubicka
  2019-09-13 12:30                               ` Martin Liška
  1 sibling, 0 replies; 59+ messages in thread
From: Jan Hubicka @ 2019-08-20 14:42 UTC (permalink / raw)
  To: Richard Biener; +Cc: Martin Liska, GCC Patches

> I see.  I guess dropping them if !virtual_method_call_p (at what point
> do we know?) would be a good thing.  As well as encoding
> "types_same_for_odr" and obj_type_ref_class in a more direct manner.
> I guess in reality OBJ_TYPE_REF should be all info on the
> gimple_call rather than in a GENERIC tree in the call fn slot or
> a separate stmt ...
> 
> Anyhow, the original patch is OK if you compare
> OBJ_TYPE_REF_TOKEN/OBJECT irrespective of virtual_method_call_p
> and order the types_same_for_odr last since that's most expensive.
> I also wonder if virtual_method_call_p needs to return a
virtual_mehtod_call_p is constant on the expression thorough
compilation.  I.e. if OBJ_TYPE_REF is born in C++ FE it will return true
if it is Obj-C FE it will return false and we will completely ignore
that OBJ_TYPE_REF in the middle-end (and thus we probably want to drop
it - I was just never brave enough to dig into obj-C gimplification to
figure out where it should be done and I also do not know how OBJ-C uses
OBJ_TYPE_REFs internally if at all)

Honza
> "maybe" and we have to say not equal in that case rather than just
> not comparing obj_type_ref_class ...  (operand_equal_p might be called
> from FEs during parsing)
> 
> Richard.
> 
> Thanks,
> Richard.
> 
> > Honza

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

* Re: [PATCH 2/9] operand_equal_p: add support for FIELD_DECL
  2019-08-16 12:17                       ` Jan Hubicka
@ 2019-09-11 12:58                         ` Martin Liška
  0 siblings, 0 replies; 59+ messages in thread
From: Martin Liška @ 2019-09-11 12:58 UTC (permalink / raw)
  To: Jan Hubicka, Richard Biener; +Cc: GCC Patches

On 8/16/19 2:09 PM, Jan Hubicka wrote:
>> On Thu, Aug 15, 2019 at 4:17 PM Jan Hubicka <hubicka@ucw.cz> wrote:
>>>
>>>> On Tue, Aug 6, 2019 at 5:44 PM Martin Liska <mliska@suse.cz> wrote:
>>>>>
>>>>>
>>>>> gcc/ChangeLog:
>>>>
>>>> So I suppose this isn't to call operand_equal_p on two FIELD_DECLs
>>>> but to make two COMPONENT_REFs "more equal"?  If so I then
>>>
>>> yes. The patch originates from my original patchset I believe and it is
>>> what ICF does.
>>>> I suggest to make this change "local" to the COMPONENT_REF handling.
>>>> This also interacts with path-based disambiguation so you want to make
>>>> sure to only make things equal here iff it wouldn't change the outcome
>>>> of path-based analysis.  Honza?
>>>
>>> Indeed this can be handled as part of COMPONENT_REF match.
>>> Access path oracle here basically checks:
>>>  1) that MEM_REF type matches (we want predicate for this)
>>>  2) if it finds type match via same_type_for_tbaa and then it applies
>>>     the assumption about disjointness or overlap
>>>
>>> So I guess ideally we should
>>>
>>>  1) do matching part of COMPONENT_REF
>>>  2) compare OFFSET, BIT_OFFSET
>>>     This establishes that the access has same semantics.
>>>  3) for -fno-strict-aliasing be happy
>>>  4) for -fstrict-aliaisng check if access path applies (we should export
>>>     predicate from tree-ssa-alias as discussed earlier)
>>>  5) compare types by same_type_for_tbaa_p
>>
>> Ick.  This smells like a layering violation to me.  IMHO this extended
>> equality handling should be handled with the overloading/callback
>> and not in native operand_equal_p.  Either on the level of the
>> COMPONENT_REF itself (sounds like that would be needed)
>> or the FIELD_DECL.  Not sure if the above suggestions make
>> it neccessary to look at more than a single COMPONENT_REF/FIELD_DECL
>> in the access path.  If so then watch out for quadraticness as operand_equal_p
>> traverses a reference chain...
> 
> I suppose we want to match whole access paths at once, since only having
> the MEM_REF allows one to check whether access path oracle applies to
> the given reference or not...

Doing that, can you please Honza point me to a function that should be used for it?

Martin

> 
> Honza
>>
>> Richard.
>>
>>> Honza

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

* Re: [PATCH 3/9] operand_equal_p: add support for OBJ_TYPE_REF.
  2019-08-20 14:29                             ` Richard Biener
  2019-08-20 14:42                               ` Jan Hubicka
@ 2019-09-13 12:30                               ` Martin Liška
  2019-09-16  6:45                                 ` Richard Biener
  1 sibling, 1 reply; 59+ messages in thread
From: Martin Liška @ 2019-09-13 12:30 UTC (permalink / raw)
  To: Richard Biener, Jan Hubicka; +Cc: GCC Patches

[-- Attachment #1: Type: text/plain, Size: 319 bytes --]

On 8/20/19 8:39 AM, Richard Biener wrote:
> Anyhow, the original patch is OK if you compare
> OBJ_TYPE_REF_TOKEN/OBJECT irrespective of virtual_method_call_p
> and order the types_same_for_odr last since that's most expensive.

Hi.

It's done in the attached patch that survives bootstrap and regression
tests.

Martin

[-- Attachment #2: 0003-operand_equal_p-add-support-for-OBJ_TYPE_REF.patch --]
[-- Type: text/x-patch, Size: 1991 bytes --]

From 645e2df84ccd1f9a4b41f0a73a5398ff81696cdc Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Thu, 15 Aug 2019 10:34:41 +0200
Subject: [PATCH 3/9] operand_equal_p: add support for OBJ_TYPE_REF.

gcc/ChangeLog:

2019-07-24  Martin Liska  <mliska@suse.cz>

	* fold-const.c (operand_equal_p): Support OBJ_TYPE_REF.
	* tree.c (add_expr): Hash parts of OBJ_TYPE_REF.
---
 gcc/fold-const.c | 18 ++++++++++++++++++
 gcc/tree.c       |  6 ++++++
 2 files changed, 24 insertions(+)

diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index f57fffb9655..12f5a06a524 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -3325,6 +3325,24 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 	  flags &= ~OEP_ADDRESS_OF;
 	  return OP_SAME (1) && OP_SAME (2);
 
+	/* Virtual table call.  */
+	case OBJ_TYPE_REF:
+	  {
+	    if (!operand_equal_p (OBJ_TYPE_REF_EXPR (arg0),
+				  OBJ_TYPE_REF_EXPR (arg1), flags))
+	      return false;
+	    if (tree_to_uhwi (OBJ_TYPE_REF_TOKEN (arg0))
+		!= tree_to_uhwi (OBJ_TYPE_REF_TOKEN (arg1)))
+	      return false;
+	    if (!operand_equal_p (OBJ_TYPE_REF_OBJECT (arg0),
+				  OBJ_TYPE_REF_OBJECT (arg1), flags))
+	      return false;
+	    if (!types_same_for_odr (obj_type_ref_class (arg0),
+				     obj_type_ref_class (arg1)))
+	      return false;
+	    return true;
+	  }
+
 	default:
 	  return false;
 	}
diff --git a/gcc/tree.c b/gcc/tree.c
index b5e5876bbb3..20eb1682435 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -8028,6 +8028,12 @@ add_expr (const_tree t, inchash::hash &hstate, unsigned int flags)
 	      inchash::add_expr (TARGET_EXPR_SLOT (t), hstate, flags);
 	      return;
 
+	    /* Virtual table call.  */
+	    case OBJ_TYPE_REF:
+	      inchash::add_expr (OBJ_TYPE_REF_EXPR (t), hstate, flags);
+	      inchash::add_expr (OBJ_TYPE_REF_TOKEN (t), hstate, flags);
+	      inchash::add_expr (OBJ_TYPE_REF_OBJECT (t), hstate, flags);
+	      return;
 	    default:
 	      break;
 	    }
-- 
2.23.0


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

* Re: [PATCH 3/9] operand_equal_p: add support for OBJ_TYPE_REF.
  2019-09-13 12:30                               ` Martin Liška
@ 2019-09-16  6:45                                 ` Richard Biener
  0 siblings, 0 replies; 59+ messages in thread
From: Richard Biener @ 2019-09-16  6:45 UTC (permalink / raw)
  To: Martin Liška; +Cc: Jan Hubicka, GCC Patches

On Fri, Sep 13, 2019 at 2:30 PM Martin Liška <mliska@suse.cz> wrote:
>
> On 8/20/19 8:39 AM, Richard Biener wrote:
> > Anyhow, the original patch is OK if you compare
> > OBJ_TYPE_REF_TOKEN/OBJECT irrespective of virtual_method_call_p
> > and order the types_same_for_odr last since that's most expensive.
>
> Hi.
>
> It's done in the attached patch that survives bootstrap and regression
> tests.

OK.

Richard.

> Martin

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

* Re: [PATCH 5/9] Come up with an abstraction.
  2019-08-16 11:06                                   ` Martin Liška
@ 2019-09-18  7:56                                     ` Martin Liška
  2019-09-19 11:30                                       ` Richard Biener
  0 siblings, 1 reply; 59+ messages in thread
From: Martin Liška @ 2019-09-18  7:56 UTC (permalink / raw)
  To: Richard Biener; +Cc: Michael Matz, GCC Patches

Hello.

Ok, so the current IPA ICF transformation is being blocked by the
patch 2/9 (about FIELD_DECL). I asked Honza for a help here.
In the meantime, can you Richi make an opinion about the part 5 which
is about the interaction in between old operand_equal_p and a new
hook in IPA ICF?

Thanks,
Martin

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

* Re: [PATCH 5/9] Come up with an abstraction.
  2019-09-18  7:56                                     ` Martin Liška
@ 2019-09-19 11:30                                       ` Richard Biener
  0 siblings, 0 replies; 59+ messages in thread
From: Richard Biener @ 2019-09-19 11:30 UTC (permalink / raw)
  To: Martin Liška; +Cc: Michael Matz, GCC Patches

On Wed, Sep 18, 2019 at 9:56 AM Martin Liška <mliska@suse.cz> wrote:
>
> Hello.
>
> Ok, so the current IPA ICF transformation is being blocked by the
> patch 2/9 (about FIELD_DECL). I asked Honza for a help here.
> In the meantime, can you Richi make an opinion about the part 5 which
> is about the interaction in between old operand_equal_p and a new
> hook in IPA ICF?

+static operand_compare default_compare_instance;
+
+/* Conveinece wrapper around operand_compare class because usually we do
+   not need to play with the valueizer.  */
+
+bool
+operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
+{
+  return default_compare_instance.operand_equal_p (arg0, arg1, flags);
+}

can we devirtualize this and thus further clone and devirtualize the
recursions in the default instance?  if not does making the default
instance const help (you need to make the methods const, possibly
a good idea if that works for your ICF use as well?)

+  if (flag_checking && !(flags & OEP_NO_HASH_CHECK))
+    {

better keep that in the caller (avoids the virtual call and also
then the function does what it says...).

Otherwise it looks OK.  Note I'd really like to see the
overhead for the regular operand_equal_p calls being zero,
thus devirt is important here - but it should work with
IPA-CP of 'this'?  But maybe the function is too big to
clone :/

Richard.

> Thanks,
> Martin

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

* Re: [PATCH 0/9] IPA ICF overhaul
  2019-08-06 15:44             ` [PATCH 0/9] IPA ICF overhaul Martin Liska
                                 ` (9 preceding siblings ...)
  2019-08-16 11:53               ` [PATCH 10/N] Use const_tree more in IPA ICF Martin Liška
@ 2019-10-30 11:54               ` Martin Liška
  10 siblings, 0 replies; 59+ messages in thread
From: Martin Liška @ 2019-10-30 11:54 UTC (permalink / raw)
  To: gcc-patches; +Cc: Jan Hubicka

[-- Attachment #1: Type: text/plain, Size: 394 bytes --]

Hi.

After a discussion with Honza, he recommended to install the patch set
(which should be completely approved) without the last missing piece:
[PATCH 2/9] operand_equal_p: add support for FIELD_DECL

He's going to write a function that will compare two access paths.
I've retested the whole patch without the patch and built also
Firefox with it. I'm going to install it.

Martin

[-- Attachment #2: pEpkey.asc --]
[-- Type: application/pgp-keys, Size: 1787 bytes --]

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

end of thread, other threads:[~2019-10-30 11:54 UTC | newest]

Thread overview: 59+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-22 12:50 [RFC] operand_equal_p with valueization Jan Hubicka
2015-05-22 13:40 ` Richard Biener
2015-05-22 14:12   ` Jan Hubicka
2015-05-26  8:18     ` Richard Biener
2015-05-26 19:09       ` Jan Hubicka
2015-05-27  8:49         ` Richard Biener
2019-06-18 11:10           ` [RFC] " Martin Liška
2019-08-06 15:44             ` [PATCH 0/9] IPA ICF overhaul Martin Liska
2019-08-06 15:43               ` [PATCH 9/9] Remove alias set comparison Martin Liska
2019-08-07 15:58                 ` Martin Sebor
2019-08-08  8:43                   ` Martin Liška
2019-08-08 15:21                     ` Martin Sebor
2019-08-08 14:44                 ` Jeff Law
2019-08-06 15:43               ` [PATCH 5/9] Come up with an abstraction Martin Liska
2019-08-08 16:29                 ` Michael Matz
2019-08-12 11:49                   ` Martin Liška
2019-08-12 12:27                     ` Richard Biener
2019-08-12 12:43                       ` Martin Liška
2019-08-12 13:26                         ` Richard Biener
2019-08-12 14:48                           ` Martin Liška
2019-08-14 13:17                             ` Richard Biener
2019-08-14 13:50                               ` Martin Liška
2019-08-14 14:38                                 ` Richard Biener
2019-08-16 11:06                                   ` Martin Liška
2019-09-18  7:56                                     ` Martin Liška
2019-09-19 11:30                                       ` Richard Biener
2019-08-12 13:40                     ` Michael Matz
2019-08-09 11:48                 ` Richard Biener
2019-08-06 15:43               ` [PATCH 6/9] Integrate that for IPA ICF Martin Liska
2019-08-16 11:10                 ` Martin Liška
2019-08-06 15:43               ` [PATCH 7/9] IPA ICF: remove dead code Martin Liska
2019-08-08 14:44                 ` Jeff Law
2019-08-06 15:43               ` [PATCH 8/9] Remove comparison for polymorphic types Martin Liska
2019-08-06 15:43               ` [PATCH 4/9] Strengthen alias_ptr_types_compatible_p in LTO mode Martin Liska
2019-08-07 12:05                 ` Richard Biener
2019-08-08 12:09                   ` Martin Liška
2019-08-09 11:20                     ` Richard Biener
2019-08-06 15:43               ` [PATCH 2/9] operand_equal_p: add support for FIELD_DECL Martin Liska
2019-08-07 12:21                 ` Richard Biener
2019-08-15 14:19                   ` Jan Hubicka
2019-08-16  9:28                     ` Richard Biener
2019-08-16 12:17                       ` Jan Hubicka
2019-09-11 12:58                         ` Martin Liška
2019-08-06 15:43               ` [PATCH 1/9] Replace int with boolean in predicate functions Martin Liska
2019-08-07 12:38                 ` Richard Biener
2019-08-06 15:55               ` [PATCH 3/9] operand_equal_p: add support for OBJ_TYPE_REF Martin Liska
2019-08-07 12:09                 ` Richard Biener
2019-08-15 15:44                   ` Jan Hubicka
2019-08-16  9:25                     ` Richard Biener
2019-08-16 12:11                       ` Jan Hubicka
2019-08-19 14:03                         ` Richard Biener
2019-08-19 15:12                           ` Jan Hubicka
2019-08-20 14:29                             ` Richard Biener
2019-08-20 14:42                               ` Jan Hubicka
2019-09-13 12:30                               ` Martin Liška
2019-09-16  6:45                                 ` Richard Biener
2019-08-16 11:53               ` [PATCH 10/N] Use const_tree more in IPA ICF Martin Liška
2019-08-19 13:57                 ` Richard Biener
2019-10-30 11:54               ` [PATCH 0/9] IPA ICF overhaul Martin Liška

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