Hi, doing some further testing and analysis of icf miscompares I noticed tat my change for hadling OEP_ADDRESS_OF of COMPONENT_REF had last minute chnage that made it not effective, since flag is cleared before the conditional. After some exprimenting it seem cleanest to just use temporary bool.
Other problem is that obj-C++ produces OBJ_TYPE_REFs that are referring to something else than class types. obj_type_ref_class asserts for that since one is expected to use virutal_method_call_p predicate first. It would be nice to make obj-C++ either produce standard OBJ_TYEP_REFs or use different code for that, but that is for another day. I apologize for both - clearly need a break which I will do. Fortunately it seems that ICF issues tracked in PR92535 are almost resolved. lto-bootstraped and regtested x86_64-linux, comitted. Honza * fold-const.c (operand_compare::operand_equal_p): Fix thinko in COMPONENT_REF handling and guard types_same_for_odr by virtual_method_call_p. (operand_compare::hash_operand): Likewise. diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 820b08d26fd..1bce9e72c1d 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -3314,30 +3314,34 @@ operand_compare::operand_equal_p (const_tree arg0, const_tree arg1, may be NULL when we're called to compare MEM_EXPRs. */ if (!OP_SAME_WITH_NULL (0)) return false; - /* Most of time we only need to compare FIELD_DECLs for equality. - However when determining address look into actual offsets. - These may match for unions and unshared record types. */ - flags &= ~OEP_ADDRESS_OF; - if (!OP_SAME (1)) - { - if (flags & OEP_ADDRESS_OF) - { - if (TREE_OPERAND (arg0, 2) - || TREE_OPERAND (arg1, 2)) - return OP_SAME_WITH_NULL (2); - tree field0 = TREE_OPERAND (arg0, 1); - tree field1 = TREE_OPERAND (arg1, 1); - - if (!operand_equal_p (DECL_FIELD_OFFSET (field0), - DECL_FIELD_OFFSET (field1), flags) - || !operand_equal_p (DECL_FIELD_BIT_OFFSET (field0), - DECL_FIELD_BIT_OFFSET (field1), - flags)) - return false; - } - else - return false; - } + { + bool compare_address = flags & OEP_ADDRESS_OF; + + /* Most of time we only need to compare FIELD_DECLs for equality. + However when determining address look into actual offsets. + These may match for unions and unshared record types. */ + flags &= ~OEP_ADDRESS_OF; + if (!OP_SAME (1)) + { + if (compare_address) + { + if (TREE_OPERAND (arg0, 2) + || TREE_OPERAND (arg1, 2)) + return OP_SAME_WITH_NULL (2); + tree field0 = TREE_OPERAND (arg0, 1); + tree field1 = TREE_OPERAND (arg1, 1); + + if (!operand_equal_p (DECL_FIELD_OFFSET (field0), + DECL_FIELD_OFFSET (field1), flags) + || !operand_equal_p (DECL_FIELD_BIT_OFFSET (field0), + DECL_FIELD_BIT_OFFSET (field1), + flags)) + return false; + } + else + return false; + } + } return OP_SAME_WITH_NULL (2); case BIT_FIELD_REF: @@ -3436,8 +3440,11 @@ operand_compare::operand_equal_p (const_tree arg0, const_tree arg1, if (!operand_equal_p (OBJ_TYPE_REF_OBJECT (arg0), OBJ_TYPE_REF_OBJECT (arg1), flags)) return false; - if (!types_same_for_odr (obj_type_ref_class (arg0), - obj_type_ref_class (arg1))) + if (virtual_method_call_p (arg0) != virtual_method_call_p (arg1)) + return false; + if (virtual_method_call_p (arg0) + && !types_same_for_odr (obj_type_ref_class (arg0), + obj_type_ref_class (arg1))) return false; return true; @@ -3866,6 +3873,8 @@ operand_compare::hash_operand (const_tree t, inchash::hash &hstate, flags &= ~OEP_ADDRESS_OF; inchash::add_expr (OBJ_TYPE_REF_TOKEN (t), hstate, flags); inchash::add_expr (OBJ_TYPE_REF_OBJECT (t), hstate, flags); + if (!virtual_method_call_p (t)) + return; if (tree c = obj_type_ref_class (t)) { c = TYPE_NAME (TYPE_MAIN_VARIANT (c));