aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2020-11-13 11:41:13 +0100
committerJan Hubicka <jh@suse.cz>2020-11-13 16:04:48 +0100
commita1fdc16da341187846dd0577e96ee00df5f28608 (patch)
tree78db15ad478a4d755ad7282e1f824d1c32f9e95f
parent156edf21fab7dd5891c72db7ec58b38ef7d52bfa (diff)
downloadgcc-a1fdc16da341187846dd0577e96ee00df5f28608.zip
gcc-a1fdc16da341187846dd0577e96ee00df5f28608.tar.gz
gcc-a1fdc16da341187846dd0577e96ee00df5f28608.tar.bz2
Determine access types in ipa-icf-gimple.c
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.
-rw-r--r--gcc/ipa-icf-gimple.c109
-rw-r--r--gcc/ipa-icf-gimple.h17
-rw-r--r--gcc/ipa-icf.c40
3 files changed, 123 insertions, 43 deletions
diff --git a/gcc/ipa-icf-gimple.c b/gcc/ipa-icf-gimple.c
index b755d7e..0276b20 100644
--- a/gcc/ipa-icf-gimple.c
+++ b/gcc/ipa-icf-gimple.c
@@ -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
diff --git a/gcc/ipa-icf-gimple.h b/gcc/ipa-icf-gimple.h
index 28459d2..84a0b9d 100644
--- a/gcc/ipa-icf-gimple.h
+++ b/gcc/ipa-icf-gimple.h
@@ -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
diff --git a/gcc/ipa-icf.c b/gcc/ipa-icf.c
index 8cae076..83f9786 100644
--- a/gcc/ipa-icf.c
+++ b/gcc/ipa-icf.c
@@ -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);