From: Jan Hubicka Date: Fri, 13 Nov 2020 10:41:13 +0000 (+0100) Subject: Determine access types in ipa-icf-gimple.c X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=a1fdc16da341187846dd0577e96ee00df5f28608;p=gcc.git 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. --- diff --git a/gcc/ipa-icf-gimple.c b/gcc/ipa-icf-gimple.c index b755d7ec847..0276b205951 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 (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 28459d217ea..84a0b9deebd 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 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 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 8cae076b3ce..83f9786b4b2 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 (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 (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 (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);