Skip to content

Commit eb48c8b

Browse files
jambormFrosty515
authored andcommitted
ipa: Compare jump functions in ICF (PR 113907)
This is a manual backport of r14-9840-g1162861439fd3c from master. Manual because the bits and value range representation in jump functions have changes during the gcc 14 development cycle. In PR 113907 comment gcc-mirror#58, Honza found a case where ICF thinks bodies of functions are equivalent but becaise of difference in aliases in a memory access, different aggregate jump functions are associated with supposedly equivalent call statements. This patch adds a way to compare jump functions and plugs it into ICF to avoid the issue. gcc/ChangeLog: 2024-05-14 Martin Jambor <[email protected]> PR ipa/113907 * ipa-prop.h (ipa_jump_functions_equivalent_p): Declare. (values_equal_for_ipcp_p): Likewise. * ipa-prop.cc (ipa_agg_pass_through_jf_equivalent_p): New function. (ipa_agg_jump_functions_equivalent_p): Likewise. (ipa_jump_functions_equivalent_p): Likewise. * ipa-cp.cc (values_equal_for_ipcp_p): Make function public. * ipa-icf-gimple.cc: Include alloc-pool.h, symbol-summary.h, sreal.h, ipa-cp.h and ipa-prop.h. (func_checker::compare_gimple_call): Comapre jump functions. gcc/testsuite/ChangeLog: 2024-05-10 Martin Jambor <[email protected]> PR ipa/113907 * gcc.dg/lto/pr113907_0.c: New. * gcc.dg/lto/pr113907_1.c: Likewise. * gcc.dg/lto/pr113907_2.c: Likewise.
1 parent f9732fa commit eb48c8b

File tree

7 files changed

+254
-1
lines changed

7 files changed

+254
-1
lines changed

gcc/ipa-cp.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ ipcp_lattice<valtype>::is_single_const ()
458458

459459
/* Return true iff X and Y should be considered equal values by IPA-CP. */
460460

461-
static bool
461+
bool
462462
values_equal_for_ipcp_p (tree x, tree y)
463463
{
464464
gcc_checking_assert (x != NULL_TREE && y != NULL_TREE);

gcc/ipa-icf-gimple.cc

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,11 @@ along with GCC; see the file COPYING3. If not see
4242
#include "tree-sra.h"
4343

4444
#include "tree-ssa-alias-compare.h"
45+
#include "alloc-pool.h"
46+
#include "symbol-summary.h"
4547
#include "ipa-icf-gimple.h"
48+
#include "sreal.h"
49+
#include "ipa-prop.h"
4650

4751
namespace ipa_icf_gimple {
4852

@@ -751,6 +755,31 @@ func_checker::compare_gimple_call (gcall *s1, gcall *s2)
751755
&& !compatible_types_p (TREE_TYPE (t1), TREE_TYPE (t2)))
752756
return return_false_with_msg ("GIMPLE internal call LHS type mismatch");
753757

758+
if (!gimple_call_internal_p (s1))
759+
{
760+
cgraph_edge *e1 = cgraph_node::get (m_source_func_decl)->get_edge (s1);
761+
cgraph_edge *e2 = cgraph_node::get (m_target_func_decl)->get_edge (s2);
762+
class ipa_edge_args *args1 = ipa_edge_args_sum->get (e1);
763+
class ipa_edge_args *args2 = ipa_edge_args_sum->get (e2);
764+
if ((args1 != nullptr) != (args2 != nullptr))
765+
return return_false_with_msg ("ipa_edge_args mismatch");
766+
if (args1)
767+
{
768+
int n1 = ipa_get_cs_argument_count (args1);
769+
int n2 = ipa_get_cs_argument_count (args2);
770+
if (n1 != n2)
771+
return return_false_with_msg ("ipa_edge_args nargs mismatch");
772+
for (int i = 0; i < n1; i++)
773+
{
774+
struct ipa_jump_func *jf1 = ipa_get_ith_jump_func (args1, i);
775+
struct ipa_jump_func *jf2 = ipa_get_ith_jump_func (args2, i);
776+
if (((jf1 != nullptr) != (jf2 != nullptr))
777+
|| (jf1 && !ipa_jump_functions_equivalent_p (jf1, jf2)))
778+
return return_false_with_msg ("jump function mismatch");
779+
}
780+
}
781+
}
782+
754783
return compare_operand (t1, t2, get_operand_access_type (&map, t1));
755784
}
756785

gcc/ipa-prop.cc

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6022,5 +6022,162 @@ ipcp_transform_function (struct cgraph_node *node)
60226022
return modified_mem_access ? TODO_update_ssa_only_virtuals : 0;
60236023
}
60246024

6025+
/* Return true if the two pass_through components of two jump functions are
6026+
known to be equivalent. AGG_JF denotes whether they are part of aggregate
6027+
functions or not. The function can be used before the IPA phase of IPA-CP
6028+
or inlining because it cannot cope with refdesc changes these passes can
6029+
carry out. */
6030+
6031+
static bool
6032+
ipa_agg_pass_through_jf_equivalent_p (ipa_pass_through_data *ipt1,
6033+
ipa_pass_through_data *ipt2,
6034+
bool agg_jf)
6035+
6036+
{
6037+
gcc_assert (agg_jf ||
6038+
(!ipt1->refdesc_decremented && !ipt2->refdesc_decremented));
6039+
if (ipt1->operation != ipt2->operation
6040+
|| ipt1->formal_id != ipt2->formal_id
6041+
|| (!agg_jf && (ipt1->agg_preserved != ipt2->agg_preserved)))
6042+
return false;
6043+
if (((ipt1->operand != NULL_TREE) != (ipt2->operand != NULL_TREE))
6044+
|| (ipt1->operand
6045+
&& !values_equal_for_ipcp_p (ipt1->operand, ipt2->operand)))
6046+
return false;
6047+
return true;
6048+
}
6049+
6050+
/* Return true if the two aggregate jump functions are known to be equivalent.
6051+
The function can be used before the IPA phase of IPA-CP or inlining because
6052+
it cannot cope with refdesc changes these passes can carry out. */
6053+
6054+
static bool
6055+
ipa_agg_jump_functions_equivalent_p (ipa_agg_jf_item *ajf1,
6056+
ipa_agg_jf_item *ajf2)
6057+
{
6058+
if (ajf1->offset != ajf2->offset
6059+
|| ajf1->jftype != ajf2->jftype
6060+
|| !types_compatible_p (ajf1->type, ajf2->type))
6061+
return false;
6062+
6063+
switch (ajf1->jftype)
6064+
{
6065+
case IPA_JF_CONST:
6066+
if (!values_equal_for_ipcp_p (ajf1->value.constant,
6067+
ajf2->value.constant))
6068+
return false;
6069+
break;
6070+
case IPA_JF_PASS_THROUGH:
6071+
{
6072+
ipa_pass_through_data *ipt1 = &ajf1->value.pass_through;
6073+
ipa_pass_through_data *ipt2 = &ajf2->value.pass_through;
6074+
if (!ipa_agg_pass_through_jf_equivalent_p (ipt1, ipt2, true))
6075+
return false;
6076+
}
6077+
break;
6078+
case IPA_JF_LOAD_AGG:
6079+
{
6080+
ipa_load_agg_data *ila1 = &ajf1->value.load_agg;
6081+
ipa_load_agg_data *ila2 = &ajf2->value.load_agg;
6082+
if (!ipa_agg_pass_through_jf_equivalent_p (&ila1->pass_through,
6083+
&ila2->pass_through, true))
6084+
return false;
6085+
if (ila1->offset != ila2->offset
6086+
|| ila1->by_ref != ila2->by_ref
6087+
|| !types_compatible_p (ila1->type, ila2->type))
6088+
return false;
6089+
}
6090+
break;
6091+
default:
6092+
gcc_unreachable ();
6093+
}
6094+
return true;
6095+
}
6096+
6097+
/* Return true if the two jump functions are known to be equivalent. The
6098+
function can be used before the IPA phase of IPA-CP or inlining because it
6099+
cannot cope with refdesc changes these passes can carry out. */
6100+
6101+
bool
6102+
ipa_jump_functions_equivalent_p (ipa_jump_func *jf1, ipa_jump_func *jf2)
6103+
{
6104+
if (jf1->type != jf2->type)
6105+
return false;
6106+
6107+
switch (jf1->type)
6108+
{
6109+
case IPA_JF_UNKNOWN:
6110+
break;
6111+
case IPA_JF_CONST:
6112+
{
6113+
tree cst1 = ipa_get_jf_constant (jf1);
6114+
tree cst2 = ipa_get_jf_constant (jf2);
6115+
if (!values_equal_for_ipcp_p (cst1, cst2))
6116+
return false;
6117+
6118+
ipa_cst_ref_desc *rd1 = jfunc_rdesc_usable (jf1);
6119+
ipa_cst_ref_desc *rd2 = jfunc_rdesc_usable (jf2);
6120+
if (rd1 && rd2)
6121+
{
6122+
gcc_assert (rd1->refcount == 1
6123+
&& rd2->refcount == 1);
6124+
gcc_assert (!rd1->next_duplicate && !rd2->next_duplicate);
6125+
}
6126+
else if (rd1)
6127+
return false;
6128+
else if (rd2)
6129+
return false;
6130+
}
6131+
break;
6132+
case IPA_JF_PASS_THROUGH:
6133+
{
6134+
ipa_pass_through_data *ipt1 = &jf1->value.pass_through;
6135+
ipa_pass_through_data *ipt2 = &jf2->value.pass_through;
6136+
if (!ipa_agg_pass_through_jf_equivalent_p (ipt1, ipt2, false))
6137+
return false;
6138+
}
6139+
break;
6140+
case IPA_JF_ANCESTOR:
6141+
{
6142+
ipa_ancestor_jf_data *ia1 = &jf1->value.ancestor;
6143+
ipa_ancestor_jf_data *ia2 = &jf2->value.ancestor;
6144+
6145+
if (ia1->formal_id != ia2->formal_id
6146+
|| ia1->agg_preserved != ia2->agg_preserved
6147+
|| ia1->keep_null != ia2->keep_null
6148+
|| ia1->offset != ia2->offset)
6149+
return false;
6150+
}
6151+
break;
6152+
default:
6153+
gcc_unreachable ();
6154+
}
6155+
6156+
if (((jf1->bits != nullptr) != (jf2->bits != nullptr))
6157+
|| (jf1->bits && ((jf1->bits->value != jf2->bits->value)
6158+
|| (jf1->bits->mask != jf2->bits->mask))))
6159+
return false;
6160+
6161+
if (((jf1->m_vr != nullptr) != (jf2->m_vr != nullptr))
6162+
|| (jf1->m_vr && *jf1->m_vr != *jf2->m_vr))
6163+
return false;
6164+
6165+
unsigned alen = vec_safe_length (jf1->agg.items);
6166+
if (vec_safe_length (jf2->agg.items) != alen)
6167+
return false;
6168+
6169+
if (!alen)
6170+
return true;
6171+
6172+
if (jf1->agg.by_ref != jf2->agg.by_ref)
6173+
return false;
6174+
6175+
for (unsigned i = 0 ; i < alen; i++)
6176+
if (!ipa_agg_jump_functions_equivalent_p (&(*jf1->agg.items)[i],
6177+
&(*jf2->agg.items)[i]))
6178+
return false;
6179+
6180+
return true;
6181+
}
60256182

60266183
#include "gt-ipa-prop.h"

gcc/ipa-prop.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,11 +1194,14 @@ bool ipcp_get_parm_bits (tree, tree *, widest_int *);
11941194
bool unadjusted_ptr_and_unit_offset (tree op, tree *ret,
11951195
poly_int64 *offset_ret);
11961196

1197+
bool ipa_jump_functions_equivalent_p (ipa_jump_func *jf1, ipa_jump_func *jf2);
1198+
11971199
/* From tree-sra.cc: */
11981200
tree build_ref_for_offset (location_t, tree, poly_int64, bool, tree,
11991201
gimple_stmt_iterator *, bool);
12001202

12011203
/* In ipa-cp.cc */
12021204
void ipa_cp_cc_finalize (void);
1205+
bool values_equal_for_ipcp_p (tree x, tree y);
12031206

12041207
#endif /* IPA_PROP_H */
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/* { dg-lto-do run } */
2+
/* { dg-lto-options {{-O3 -flto}} } */
3+
4+
struct bar {int a;};
5+
struct foo {int a;};
6+
struct barp {struct bar *f; struct bar *g;};
7+
extern struct foo **ptr;
8+
int test2 (void *);
9+
int test3 (void *);
10+
int
11+
testb(void)
12+
{
13+
struct bar *fp;
14+
test2 ((void *)&fp);
15+
fp = (void *) 0;
16+
(*ptr)++;
17+
test3 ((void *)&fp);
18+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
__attribute__((used)) int val,val2 = 1;
2+
3+
struct foo {int a;};
4+
5+
struct foo **ptr;
6+
7+
__attribute__ ((noipa))
8+
int
9+
test2 (void *a)
10+
{
11+
ptr = (struct foo **)a;
12+
}
13+
int test3 (void *a);
14+
15+
int
16+
test(void)
17+
{
18+
struct foo *fp;
19+
test2 ((void *)&fp);
20+
fp = (void *) 0;
21+
(*ptr)++;
22+
test3 ((void *)&fp);
23+
}
24+
25+
int testb (void);
26+
27+
int
28+
main()
29+
{
30+
for (int i = 0; i < val2; i++)
31+
if (val)
32+
testb ();
33+
else
34+
test();
35+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/* { dg-options "-O3 -flto -fno-strict-aliasing" } */
2+
3+
__attribute__ ((noinline))
4+
int
5+
test3 (void *a)
6+
{
7+
if (!*(void **)a)
8+
__builtin_abort ();
9+
return 0;
10+
}
11+

0 commit comments

Comments
 (0)