https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119006
--- Comment #11 from Jakub Jelinek <jakub at gcc dot gnu.org> --- --- gcc/ipa-icf-gimple.cc.jj 2025-02-01 00:50:02.080774328 +0100 +++ gcc/ipa-icf-gimple.cc 2025-02-27 14:13:27.446426589 +0100 @@ -437,12 +437,23 @@ func_checker::compare_operand (tree t1, ("compare_ao_refs failed (dependence clique difference)"); gcc_unreachable (); } + else if (TREE_CODE (t1) == ADDR_EXPR && TREE_CODE (t2) == ADDR_EXPR) + { + /* For ADDR_EXPR compare the operands of the ADDR_EXPR rather than + the ADDR_EXPRs themselves. operand_equal_p will compare the + operands with OEP_ADDRESS_OF and only care about the value + of the ADDR_EXPR, rather than e.g. types of MEM_REFs in there. + Some optimizations use such details though, see PR119006. */ + if (operand_equal_p (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0), + OEP_MATCH_SIDE_EFFECTS)) + return true; + return return_false_with_msg ("operand_equal_p failed"); + } else { if (operand_equal_p (t1, t2, OEP_MATCH_SIDE_EFFECTS)) return true; - return return_false_with_msg - ("operand_equal_p failed"); + return return_false_with_msg ("operand_equal_p failed"); } } fixes this. And so does --- gcc/ipa-icf-gimple.cc.jj 2025-02-01 00:50:02.080774328 +0100 +++ gcc/ipa-icf-gimple.cc 2025-02-27 14:24:20.815358621 +0100 @@ -440,9 +440,39 @@ func_checker::compare_operand (tree t1, else { if (operand_equal_p (t1, t2, OEP_MATCH_SIDE_EFFECTS)) - return true; - return return_false_with_msg - ("operand_equal_p failed"); + { + if (TREE_CODE (t1) == ADDR_EXPR && TREE_CODE (t2) == ADDR_EXPR) + { + /* For ADDR_EXPR operand_equal_p compares the operands of + it using OEP_ADDRESS_OF and only care about the value + of the ADDR_EXPR, rather than e.g. types of MEM_REFs in + there. Some optimizations use such details though, see + PR119006. */ + tree base1 = TREE_OPERAND (t1, 0); + tree base2 = TREE_OPERAND (t2, 0); + do + { + while (handled_component_p (base1)) + base1 = TREE_OPERAND (base1, 0); + while (handled_component_p (base2)) + base2 = TREE_OPERAND (base2, 0); + if (!compatible_types_p (TREE_TYPE (base1), + TREE_TYPE (base2))) + return return_false_with_msg ("ADDR_EXPR base type " + "difference"); + if (TREE_CODE (base1) != MEM_REF + || TREE_CODE (TREE_OPERAND (base1, 0)) != ADDR_EXPR + || TREE_CODE (base2) != MEM_REF + || TREE_CODE (TREE_OPERAND (base2, 0)) != ADDR_EXPR) + break; + base1 = TREE_OPERAND (TREE_OPERAND (base1, 0), 0); + base2 = TREE_OPERAND (TREE_OPERAND (base2, 0), 0); + } + while (1); + } + return true; + } + return return_false_with_msg ("operand_equal_p failed"); } } Any preference between the two? The first one is certainly safer, on the other side might punt even e.g. on alias set differences etc. which the strlen opts in gimple-fold.cc don't care about.