Mercurial > hg > CbC > CbC_gcc
diff gcc/ipa-icf-gimple.c @ 145:1830386684a0
gcc-9.2.0
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 11:34:05 +0900 |
parents | 84e7813d76e9 |
children |
line wrap: on
line diff
--- a/gcc/ipa-icf-gimple.c Thu Oct 25 07:37:49 2018 +0900 +++ b/gcc/ipa-icf-gimple.c Thu Feb 13 11:34:05 2020 +0900 @@ -1,5 +1,5 @@ /* Interprocedural Identical Code Folding pass - Copyright (C) 2014-2018 Free Software Foundation, Inc. + Copyright (C) 2014-2020 Free Software Foundation, Inc. Contributed by Jan Hubicka <hubicka@ucw.cz> and Martin Liska <mliska@suse.cz> @@ -31,12 +31,12 @@ #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" #include "tree-eh.h" #include "builtins.h" +#include "cfgloop.h" #include "ipa-icf-gimple.h" @@ -50,14 +50,12 @@ 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); @@ -87,7 +85,7 @@ /* 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); @@ -110,13 +108,7 @@ 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; @@ -147,7 +139,7 @@ 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)) @@ -161,24 +153,8 @@ 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); + const_tree &slot = m_decl_map.get_or_insert (t1, &existed_p); if (existed_p) return return_with_debug (slot == t2); else @@ -232,154 +208,86 @@ 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; } -/* 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. */ +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; + case FIELD_DECL: + inchash::add_expr (DECL_FIELD_OFFSET (arg), hstate, flags); + inchash::add_expr (DECL_FIELD_BIT_OFFSET (arg), hstate, flags); + return; + default: + break; + } + + return operand_compare::hash_operand (arg, hstate, flags); +} + bool -func_checker::compare_cst_or_decl (tree t1, tree t2) +func_checker::operand_equal_p (const_tree t1, const_tree t2, + unsigned int flags) { - bool ret; + bool r; + if (verify_hash_value (t1, t2, flags, &r)) + return r; + + if (t1 == t2) + return true; + else if (!t1 || !t2) + return false; + + if (TREE_CODE (t1) != TREE_CODE (t2)) + return return_false (); 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 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) - 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); - } + return compare_decl (t1, t2); + case SSA_NAME: + return compare_ssa_name (t1, t2); default: - gcc_unreachable (); + break; } + + return operand_compare::operand_equal_p (t1, t2, flags); } /* Function responsible for comparison of various operands T1 and T2. @@ -389,158 +297,13 @@ bool func_checker::compare_operand (tree t1, tree t2) { - 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 (); - - switch (TREE_CODE (t1)) - { - case CONSTRUCTOR: - { - 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; - } - 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: - { - 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: - { - x1 = TREE_OPERAND (t1, 0); - x2 = TREE_OPERAND (t2, 0); - - 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); - - ret = compare_operand (x1, x2) - && compare_cst_or_decl (y1, y2) - && compare_cst_or_decl (z1, z2); - - 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"); - } + if (operand_equal_p (t1, t2, OEP_MATCH_SIDE_EFFECTS)) + return true; + return return_false_with_msg ("operand_equal_p failed"); } bool @@ -579,7 +342,7 @@ /* 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; @@ -593,7 +356,7 @@ 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 @@ -605,6 +368,40 @@ return return_with_debug (ret); } +/* Compare loop information for basic blocks BB1 and BB2. */ + +bool +func_checker::compare_loops (basic_block bb1, basic_block bb2) +{ + if ((bb1->loop_father == NULL) != (bb2->loop_father == NULL)) + return return_false (); + + class loop *l1 = bb1->loop_father; + class loop *l2 = bb2->loop_father; + if (l1 == NULL) + return true; + + if ((bb1 == l1->header) != (bb2 == l2->header)) + return return_false_with_msg ("header"); + if ((bb1 == l1->latch) != (bb2 == l2->latch)) + return return_false_with_msg ("latch"); + if (l1->simdlen != l2->simdlen) + return return_false_with_msg ("simdlen"); + if (l1->safelen != l2->safelen) + return return_false_with_msg ("safelen"); + if (l1->can_be_parallel != l2->can_be_parallel) + return return_false_with_msg ("can_be_parallel"); + if (l1->dont_vectorize != l2->dont_vectorize) + return return_false_with_msg ("dont_vectorize"); + if (l1->force_vectorize != l2->force_vectorize) + return return_false_with_msg ("force_vectorize"); + if (l1->unroll != l2->unroll) + return return_false_with_msg ("unroll"); + if (!compare_variable_decl (l1->simduid, l2->simduid)) + return return_false_with_msg ("simduid"); + + return true; +} /* Function visits all gimple labels and creates corresponding mapping between basic blocks and labels. */ @@ -619,7 +416,7 @@ 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); @@ -727,6 +524,9 @@ if (!gsi_end_p (gsi2)) return return_false (); + if (!compare_loops (bb1->bb, bb2->bb)) + return return_false (); + return true; } @@ -781,15 +581,15 @@ t1 = gimple_call_arg (s1, i); t2 = gimple_call_arg (s2, i); - if (!compare_memory_operand (t1, t2)) - return return_false_with_msg ("memory operands are different"); + if (!compare_operand (t1, t2)) + return return_false_with_msg ("GIMPLE call operands are different"); } /* Return value checking. */ t1 = gimple_get_lhs (s1); t2 = gimple_get_lhs (s2); - return compare_memory_operand (t1, t2); + return compare_operand (t1, t2); } @@ -820,8 +620,16 @@ arg1 = gimple_op (s1, i); arg2 = gimple_op (s2, i); - if (!compare_memory_operand (arg1, arg2)) - return return_false_with_msg ("memory operands are different"); + /* LHS types of NOP_EXPR must be compatible. */ + if (CONVERT_EXPR_CODE_P (code1) && i == 0) + { + if (!compatible_types_p (TREE_TYPE (arg1), TREE_TYPE (arg2))) + return return_false_with_msg ("GIMPLE NOP LHS type mismatch"); + } + + if (!compare_operand (arg1, arg2)) + return return_false_with_msg ("GIMPLE assignment operands " + "are different"); } @@ -855,14 +663,6 @@ return compare_operand (t1, t2); } -/* Verifies that tree labels T1 and T2 correspond in FUNC1 and FUNC2. */ - -bool -func_checker::compare_tree_ssa_label (tree t1, tree t2) -{ - return compare_operand (t1, t2); -} - /* Verifies for given GIMPLE_LABEL stmts S1 and S2 that label statements are semantically equivalent. */ @@ -993,6 +793,9 @@ if (gimple_asm_input_p (g1) != gimple_asm_input_p (g2)) return false; + if (gimple_asm_inline_p (g1) != gimple_asm_inline_p (g2)) + return false; + if (gimple_asm_ninputs (g1) != gimple_asm_ninputs (g2)) return false;