Determine access types in ipa-icf-gimple.c
authorJan Hubicka <jh@suse.cz>
Fri, 13 Nov 2020 10:41:13 +0000 (11:41 +0100)
committerJan Hubicka <jh@suse.cz>
Fri, 13 Nov 2020 15:04:48 +0000 (16:04 +0100)
This patch adds logic to determine access type (normal or memory) for every
operand.  This makes it possible to compare memory accesses more carefully
which will be implemented in a followup patch.

* ipa-icf-gimple.c: Include gimple-walk.h.
(func_checker::compare_ssa_name): Update call of compare_operand.
(func_checker::hash_operand): Fix comment and add variant taking
operand_access_type parameter.
(func_checker::compare_operand): Add operand_access_type parameter.
(func_checker::compare_asm_inputs_outputs): Add
operand_access_type_map parameter; update use of
func_checker::compare_operand.
(func_checker::compare_gimple_call): Update use of
func_checker::compare_operand.
(func_checker::compare_gimple_assign): Likewise.
(func_checker::compare_gimple_cond): Likewise.
(func_checker::compare_gimple_switch): Likewise.
(func_checker::compare_gimple_return): Likewise.
(func_checker::compare_gimple_goto): Likewise.
(func_checker::compare_gimple_asm): Likewise.
(visit_load_store): New static functio.
(func_checker::classify_operands): New member function.
(func_checker::get_operand_access_type): New member function.
* ipa-icf-gimple.h (func_checker::operand_access_type): New enum
(func_checker::operand_access_type_map): New typedef.
(func_checker::compare_operand): Update prototype.
(func_checker::compare_asm_inputs_outputs): Likewise.
(func_checker::cleassify_operands): Declare.
(func_checker::get_operand_access_type): Declare.
(func_checker::hash_operand): New variant with operand_access_type.
* ipa-icf.c (sem_function::hash_stmt): Update uses of hash_operand.
(sem_function::compare_phi_node): Update use of compare_operand.

gcc/ipa-icf-gimple.c
gcc/ipa-icf-gimple.h
gcc/ipa-icf.c

index b755d7ec847a78038bb4df19774f647b2e23c8c3..0276b205951af676cbab4304f7e7589bb4e445fb 100644 (file)
@@ -38,6 +38,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "cfgloop.h"
 #include "attribs.h"
+#include "gimple-walk.h"
 
 #include "ipa-icf-gimple.h"
 
@@ -109,7 +110,7 @@ func_checker::compare_ssa_name (const_tree t1, const_tree t2)
       tree b1 = SSA_NAME_VAR (t1);
       tree b2 = SSA_NAME_VAR (t2);
 
-      return compare_operand (b1, b2);
+      return compare_operand (b1, b2, OP_NORMAL);
     }
 
   return true;
@@ -212,8 +213,8 @@ func_checker::compatible_types_p (tree t1, tree t2)
   return true;
 }
 
-/* Function compare for equality given trees T1 and T2 which
-   can be either a constant or a declaration type.  */
+/* Add hash of ARG to HSTATE. FLAGS have same meaning
+   as for operand_equal_p.  Works only if operand acces type is OP_NORMAL.  */
 
 void
 func_checker::hash_operand (const_tree arg, inchash::hash &hstate,
@@ -246,6 +247,16 @@ func_checker::hash_operand (const_tree arg, inchash::hash &hstate,
   return operand_compare::hash_operand (arg, hstate, flags);
 }
 
+/* Add hash of ARG accesses according to ACCESS to HSTATE.
+   FLAGS have same meaning as for operand_equal_p.  */
+
+void
+func_checker::hash_operand (const_tree arg, inchash::hash &hstate,
+                           unsigned int flags, operand_access_type)
+{
+  return hash_operand (arg, hstate, flags);
+}
+
 bool
 func_checker::operand_equal_p (const_tree t1, const_tree t2,
                               unsigned int flags)
@@ -291,12 +302,13 @@ func_checker::operand_equal_p (const_tree t1, const_tree t2,
   return operand_compare::operand_equal_p (t1, t2, flags);
 }
 
-/* Function responsible for comparison of various operands T1 and T2.
+/* Function responsible for comparison of various operands T1 and T2
+   which are accessed as ACCESS.
    If these components, from functions FUNC1 and FUNC2, are equal, true
    is returned.  */
 
 bool
-func_checker::compare_operand (tree t1, tree t2)
+func_checker::compare_operand (tree t1, tree t2, operand_access_type access)
 {
   if (!t1 && !t2)
     return true;
@@ -304,11 +316,21 @@ func_checker::compare_operand (tree t1, tree t2)
     return false;
   if (operand_equal_p (t1, t2, OEP_MATCH_SIDE_EFFECTS))
     return true;
-  return return_false_with_msg ("operand_equal_p failed");
+  switch (access)
+    {
+    case OP_MEMORY:
+      return return_false_with_msg
+                ("operand_equal_p failed (access == memory)");
+    case OP_NORMAL:
+      return return_false_with_msg
+                ("operand_equal_p failed (access == normal)");
+    }
+  gcc_unreachable ();
 }
 
 bool
-func_checker::compare_asm_inputs_outputs (tree t1, tree t2)
+func_checker::compare_asm_inputs_outputs (tree t1, tree t2,
+                                         operand_access_type_map *map)
 {
   gcc_assert (TREE_CODE (t1) == TREE_LIST);
   gcc_assert (TREE_CODE (t2) == TREE_LIST);
@@ -318,7 +340,8 @@ func_checker::compare_asm_inputs_outputs (tree t1, tree t2)
       if (!t2)
        return false;
 
-      if (!compare_operand (TREE_VALUE (t1), TREE_VALUE (t2)))
+      if (!compare_operand (TREE_VALUE (t1), TREE_VALUE (t2),
+                           get_operand_access_type (map, t1)))
        return return_false ();
 
       tree p1 = TREE_PURPOSE (t1);
@@ -545,9 +568,12 @@ func_checker::compare_gimple_call (gcall *s1, gcall *s2)
   if (gimple_call_num_args (s1) != gimple_call_num_args (s2))
     return false;
 
+  operand_access_type_map map (5);
+  classify_operands (s1, &map);
+
   t1 = gimple_call_fn (s1);
   t2 = gimple_call_fn (s2);
-  if (!compare_operand (t1, t2))
+  if (!compare_operand (t1, t2, get_operand_access_type (&map, t1)))
     return return_false ();
 
   /* Compare flags.  */
@@ -579,7 +605,8 @@ func_checker::compare_gimple_call (gcall *s1, gcall *s2)
   tree chain2 = gimple_call_chain (s2);
   if ((chain1 && !chain2)
       || (!chain1 && chain2)
-      || !compare_operand (chain1, chain2))
+      || !compare_operand (chain1, chain2,
+                          get_operand_access_type (&map, chain1)))
     return return_false_with_msg ("static call chains are different");
 
   /* Checking of argument.  */
@@ -588,7 +615,7 @@ func_checker::compare_gimple_call (gcall *s1, gcall *s2)
       t1 = gimple_call_arg (s1, i);
       t2 = gimple_call_arg (s2, i);
 
-      if (!compare_operand (t1, t2))
+      if (!compare_operand (t1, t2, get_operand_access_type (&map, t1)))
        return return_false_with_msg ("GIMPLE call operands are different");
     }
 
@@ -596,7 +623,7 @@ func_checker::compare_gimple_call (gcall *s1, gcall *s2)
   t1 = gimple_get_lhs (s1);
   t2 = gimple_get_lhs (s2);
 
-  return compare_operand (t1, t2);
+  return compare_operand (t1, t2, get_operand_access_type (&map, t1));
 }
 
 
@@ -616,6 +643,9 @@ func_checker::compare_gimple_assign (gimple *s1, gimple *s2)
   if (code1 != code2)
     return false;
 
+  operand_access_type_map map (5);
+  classify_operands (s1, &map);
+
   for (i = 0; i < gimple_num_ops (s1); i++)
     {
       arg1 = gimple_op (s1, i);
@@ -628,7 +658,7 @@ func_checker::compare_gimple_assign (gimple *s1, gimple *s2)
            return return_false_with_msg ("GIMPLE NOP LHS type mismatch");
        }
 
-      if (!compare_operand (arg1, arg2))
+      if (!compare_operand (arg1, arg2, get_operand_access_type (&map, arg1)))
        return return_false_with_msg ("GIMPLE assignment operands "
                                      "are different");
     }
@@ -655,13 +685,13 @@ func_checker::compare_gimple_cond (gimple *s1, gimple *s2)
   t1 = gimple_cond_lhs (s1);
   t2 = gimple_cond_lhs (s2);
 
-  if (!compare_operand (t1, t2))
+  if (!compare_operand (t1, t2, OP_NORMAL))
     return false;
 
   t1 = gimple_cond_rhs (s1);
   t2 = gimple_cond_rhs (s2);
 
-  return compare_operand (t1, t2);
+  return compare_operand (t1, t2, OP_NORMAL);
 }
 
 /* Verifies for given GIMPLE_LABEL stmts S1 and S2 that
@@ -700,7 +730,7 @@ func_checker::compare_gimple_switch (const gswitch *g1, const gswitch *g2)
   tree t1 = gimple_switch_index (g1);
   tree t2 = gimple_switch_index (g2);
 
-  if (!compare_operand (t1, t2))
+  if (!compare_operand (t1, t2, OP_NORMAL))
     return false;
 
   for (i = 0; i < lsize1; i++)
@@ -727,7 +757,7 @@ func_checker::compare_gimple_switch (const gswitch *g1, const gswitch *g2)
          label1 = CASE_LABEL (label1);
          label2 = CASE_LABEL (label2);
 
-         if (!compare_operand (label1, label2))
+         if (!compare_operand (label1, label2, OP_NORMAL))
            return return_false_with_msg ("switch label_exprs are different");
        }
       else if (!tree_int_cst_equal (label1, label2))
@@ -752,7 +782,10 @@ func_checker::compare_gimple_return (const greturn *g1, const greturn *g2)
   if (t1 == NULL && t2 == NULL)
     return true;
   else
-    return compare_operand (t1, t2);
+    {
+      operand_access_type_map map (3);
+      return compare_operand (t1, t2, get_operand_access_type (&map, t1));
+    }
 }
 
 /* Verifies for given GIMPLEs S1 and S2 that
@@ -769,7 +802,7 @@ func_checker::compare_gimple_goto (gimple *g1, gimple *g2)
   if (TREE_CODE (dest1) != TREE_CODE (dest2) || TREE_CODE (dest1) != SSA_NAME)
     return false;
 
-  return compare_operand (dest1, dest2);
+  return compare_operand (dest1, dest2, OP_NORMAL);
 }
 
 /* Verifies for given GIMPLE_RESX stmts S1 and S2 that
@@ -813,12 +846,15 @@ func_checker::compare_gimple_asm (const gasm *g1, const gasm *g2)
   if (strcmp (gimple_asm_string (g1), gimple_asm_string (g2)) != 0)
     return return_false_with_msg ("ASM strings are different");
 
+  operand_access_type_map map (5);
+  classify_operands (g1, &map);
+
   for (unsigned i = 0; i < gimple_asm_ninputs (g1); i++)
     {
       tree input1 = gimple_asm_input_op (g1, i);
       tree input2 = gimple_asm_input_op (g2, i);
 
-      if (!compare_asm_inputs_outputs (input1, input2))
+      if (!compare_asm_inputs_outputs (input1, input2, &map))
        return return_false_with_msg ("ASM input is different");
     }
 
@@ -827,7 +863,7 @@ func_checker::compare_gimple_asm (const gasm *g1, const gasm *g2)
       tree output1 = gimple_asm_output_op (g1, i);
       tree output2 = gimple_asm_output_op (g2, i);
 
-      if (!compare_asm_inputs_outputs (output1, output2))
+      if (!compare_asm_inputs_outputs (output1, output2, &map))
        return return_false_with_msg ("ASM output is different");
     }
 
@@ -844,4 +880,35 @@ func_checker::compare_gimple_asm (const gasm *g1, const gasm *g2)
   return true;
 }
 
+/* Helper for func_checker::classify_operands.  Record that T is a load.  */
+
+static bool
+visit_load_store (gimple *, tree, tree t, void *data)
+{
+  func_checker::operand_access_type_map *map =
+    (func_checker::operand_access_type_map *) data;
+  map->add (t);
+  return false;
+}
+
+/* Compute hash map determining access types of operands.  */
+
+void
+func_checker::classify_operands (const gimple *stmt,
+                                operand_access_type_map *map)
+{
+  walk_stmt_load_store_ops (const_cast <gimple *> (stmt),
+                           (void *)map, visit_load_store, visit_load_store);
+}
+
+/* Return access type of a given operand.  */
+
+func_checker::operand_access_type
+func_checker::get_operand_access_type (operand_access_type_map *map, tree t)
+{
+  if (map->contains (t))
+    return OP_MEMORY;
+  return OP_NORMAL;
+}
+
 } // ipa_icf_gimple namespace
index 28459d217ea470897dbe3f69daec64c6e3bb6448..84a0b9deebdcaddb6f941f7b23eaa0fedc2eec7b 100644 (file)
@@ -200,14 +200,19 @@ public:
   /* Verification function for declaration trees T1 and T2.  */
   bool compare_decl (const_tree t1, const_tree t2);
 
+  /* Compute hash map MAP that determines loads and stores of STMT.  */
+  enum operand_access_type {OP_MEMORY, OP_NORMAL};
+  typedef hash_set<tree> operand_access_type_map;
+
   /* Function responsible for comparison of various operands T1 and T2.
      If these components, from functions FUNC1 and FUNC2, are equal, true
      is returned.  */
-  bool compare_operand (tree t1, tree t2);
+  bool compare_operand (tree t1, tree t2, operand_access_type type);
 
   /* Compares GIMPLE ASM inputs (or outputs) where we iterate tree chain
      and compare both TREE_PURPOSEs and TREE_VALUEs.  */
-  bool compare_asm_inputs_outputs (tree t1, tree t2);
+  bool compare_asm_inputs_outputs (tree t1, tree t2,
+                                  operand_access_type_map *map);
 
   /* Verifies that trees T1 and T2, representing function declarations
      are equivalent from perspective of ICF.  */
@@ -230,7 +235,13 @@ public:
      first parameter of a function.  */
   static bool compatible_types_p (tree t1, tree t2);
 
+  /* Compute hash map determining access types of operands.  */
+  static void classify_operands (const gimple *stmt,
+                                operand_access_type_map *map);
 
+  /* Return access type of a given operand.  */
+  static operand_access_type get_operand_access_type
+                (operand_access_type_map *map, tree);
 private:
   /* Vector mapping source SSA names to target ones.  */
   vec <int> m_source_ssa_names;
@@ -272,6 +283,8 @@ public:
   /* 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);
+  void hash_operand (const_tree, inchash::hash &, unsigned flags,
+                    operand_access_type access);
 };
 
 } // ipa_icf_gimple namespace
index 8cae076b3cef806008c280d061dca483c003b6b3..83f9786b4b2a46d3cd3034b65cf07c1ea361ee28 100644 (file)
@@ -1419,33 +1419,32 @@ sem_function::hash_stmt (gimple *stmt, inchash::hash &hstate)
     {
     case GIMPLE_SWITCH:
       m_checker->hash_operand (gimple_switch_index (as_a <gswitch *> (stmt)),
-                            hstate, 0);
+                              hstate, 0, func_checker::OP_NORMAL);
       break;
     case GIMPLE_ASSIGN:
       hstate.add_int (gimple_assign_rhs_code (stmt));
-      if (commutative_tree_code (gimple_assign_rhs_code (stmt))
-         || commutative_ternary_tree_code (gimple_assign_rhs_code (stmt)))
-       {
-         m_checker->hash_operand (gimple_assign_rhs1 (stmt), hstate, 0);
-         m_checker->hash_operand (gimple_assign_rhs2 (stmt), hstate, 0);
-         if (commutative_ternary_tree_code (gimple_assign_rhs_code (stmt)))
-           m_checker->hash_operand (gimple_assign_rhs3 (stmt), hstate, 0);
-         m_checker->hash_operand (gimple_assign_lhs (stmt), hstate, 0);
-       }
       /* fall through */
     case GIMPLE_CALL:
     case GIMPLE_ASM:
     case GIMPLE_COND:
     case GIMPLE_GOTO:
     case GIMPLE_RETURN:
-      /* All these statements are equivalent if their operands are.  */
-      for (unsigned i = 0; i < gimple_num_ops (stmt); ++i)
-       m_checker->hash_operand (gimple_op (stmt, i), hstate, 0);
-      /* Consider nocf_check attribute in hash as it affects code
-        generation.  */
-      if (code == GIMPLE_CALL
-         && flag_cf_protection & CF_BRANCH)
-       hstate.add_flag (gimple_call_nocf_check_p (as_a <gcall *> (stmt)));
+      {
+       func_checker::operand_access_type_map map (5);
+       func_checker::classify_operands (stmt, &map);
+
+       /* All these statements are equivalent if their operands are.  */
+       for (unsigned i = 0; i < gimple_num_ops (stmt); ++i)
+         m_checker->hash_operand (gimple_op (stmt, i), hstate, 0,
+                                  func_checker::get_operand_access_type
+                                       (&map, gimple_op (stmt, i)));
+       /* Consider nocf_check attribute in hash as it affects code
+          generation.  */
+       if (code == GIMPLE_CALL
+           && flag_cf_protection & CF_BRANCH)
+         hstate.add_flag (gimple_call_nocf_check_p (as_a <gcall *> (stmt)));
+      }
+      break;
     default:
       break;
     }
@@ -1534,7 +1533,8 @@ sem_function::compare_phi_node (basic_block bb1, basic_block bb2)
       tree phi_result1 = gimple_phi_result (phi1);
       tree phi_result2 = gimple_phi_result (phi2);
 
-      if (!m_checker->compare_operand (phi_result1, phi_result2))
+      if (!m_checker->compare_operand (phi_result1, phi_result2,
+                                      func_checker::OP_NORMAL))
        return return_false_with_msg ("PHI results are different");
 
       size1 = gimple_phi_num_args (phi1);
@@ -1548,7 +1548,7 @@ sem_function::compare_phi_node (basic_block bb1, basic_block bb2)
          t1 = gimple_phi_arg (phi1, i)->def;
          t2 = gimple_phi_arg (phi2, i)->def;
 
-         if (!m_checker->compare_operand (t1, t2))
+         if (!m_checker->compare_operand (t1, t2, func_checker::OP_NORMAL))
            return return_false ();
 
          e1 = gimple_phi_arg_edge (phi1, i);