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 (ct1); + tree t2 = const_cast (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 *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 bb_dict;