aboutsummaryrefslogtreecommitdiff
path: root/gcc/ipa-icf-gimple.c
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2020-11-13 15:58:41 +0100
committerJan Hubicka <jh@suse.cz>2020-11-13 16:04:48 +0100
commit602c6cfc79ce4ae61e277107e0a60079c1a93a97 (patch)
tree18887e2bfad2d6da7bcb7079212922628d6130d4 /gcc/ipa-icf-gimple.c
parenta1fdc16da341187846dd0577e96ee00df5f28608 (diff)
downloadgcc-602c6cfc79ce4ae61e277107e0a60079c1a93a97.zip
gcc-602c6cfc79ce4ae61e277107e0a60079c1a93a97.tar.gz
gcc-602c6cfc79ce4ae61e277107e0a60079c1a93a97.tar.bz2
Improve handling of memory operands in ipa-icf 2/4
this patch iplements new class ao_compare that is derived from operand_compare and adds a method to compare and hash ao_refs. This is used by ICF to enable more merging. Comparsion is done as follows 1) Verify that the memory access will happen at the same address and will have same size. For constant addresses this is done by comparing ao_ref_base and offset/size For varable accesses it uses operand_equal_p but with OEP_ADDRESS (that does not match TBAA metadata) and then operand_equal_p on type size. 2) Compare alignments. I use get_object_alignment_1 like ipa-icf did before revamp to operand_equal_p in gcc 9. I noticed that return value is bitodd so added a comment 3) Match MR_DEPENDENCE_CLIQUE At this point the memory refrences are same except for TBAA information. We continue by checking 4) ref and base alias sets. Now if lto streaming is going to happen instead of comparing alias sets themselves we compare alias_ptr_types (the patch depends on the ao_ref_alias_ptr_tyep and ao_ref_base_alias_ptr_type acessors I sent yesterday) 5) See if accesses are view converted. If they are we are done since access path is not present 6) Compare the part of access path relevant for TBAA. I recall FRE relies on the fact that if base and ref types are same the access path is, but I do not thing this is 100% reliable especially with LTO alias sets. The access path comparsion logic is also useful for modref (for next stage1). Tracking the access paths improves quite noticeably disambiguation in C++ code by being able to distinquish different fields of same type within a struct. I had the comparsion logic in my tree for some time and it seems to work quite well. During cc1plus build we have some cases where we find mismatch after matching the base/ref alias sets. These are due to failed type merging: access path oracle in LTO uses TYPE_MAIN_VARIANTs. I implemented relatively basic hashing using base and offset. gcc/ChangeLog: * ipa-icf-gimple.c: Include tree-ssa-alias-compare.h. (find_checker::func_checker): Initialize m_tbaa. (func_checker::hash_operand): Use hash_ao_ref for memory accesses. (func_checker::compare_operand): Use compare_ao_refs for memory accesses. (func_checker::cmopare_gimple_assign): Do not check LHS types of memory stores. * ipa-icf-gimple.h (func_checker): Derive from ao_compare; add m_tbaa. * ipa-icf.c: Include tree-ssa-alias-compare.h. (sem_function::equals_private): Update call of func_checker::func_checker. * ipa-utils.h (lto_streaming_expected_p): New inline predicate. * tree-ssa-alias-compare.h: New file. * tree-ssa-alias.c: Include tree-ssa-alias-compare.h and bultins.h (view_converted_memref_p): New function. (types_equal_for_same_type_for_tbaa_p): New function. (ao_ref_alias_ptr_type, ao_ref_base_alias_ptr_type): New functions. (ao_compare::compare_ao_refs): New member function. (ao_compare::hash_ao_ref): New function * tree-ssa-alias.h (ao_ref_base_alias_ptr_type, ao_ref_alias_ptr_type): Declare. gcc/testsuite/ChangeLog: * c-c++-common/Wstringop-overflow-2.c: Disable ICF. * g++.dg/warn/Warray-bounds-8.C: Disable ICF.
Diffstat (limited to 'gcc/ipa-icf-gimple.c')
-rw-r--r--gcc/ipa-icf-gimple.c75
1 files changed, 56 insertions, 19 deletions
diff --git a/gcc/ipa-icf-gimple.c b/gcc/ipa-icf-gimple.c
index 0276b20..ffb1bad 100644
--- a/gcc/ipa-icf-gimple.c
+++ b/gcc/ipa-icf-gimple.c
@@ -40,6 +40,7 @@ along with GCC; see the file COPYING3. If not see
#include "attribs.h"
#include "gimple-walk.h"
+#include "tree-ssa-alias-compare.h"
#include "ipa-icf-gimple.h"
namespace ipa_icf_gimple {
@@ -52,13 +53,13 @@ namespace ipa_icf_gimple {
of declarations that can be skipped. */
func_checker::func_checker (tree source_func_decl, tree target_func_decl,
- bool ignore_labels,
+ bool ignore_labels, bool tbaa,
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_ignore_labels (ignore_labels)
+ m_ignore_labels (ignore_labels), m_tbaa (tbaa)
{
function *source_func = DECL_STRUCT_FUNCTION (source_func_decl);
function *target_func = DECL_STRUCT_FUNCTION (target_func_decl);
@@ -252,9 +253,16 @@ func_checker::hash_operand (const_tree arg, inchash::hash &hstate,
void
func_checker::hash_operand (const_tree arg, inchash::hash &hstate,
- unsigned int flags, operand_access_type)
+ unsigned int flags, operand_access_type access)
{
- return hash_operand (arg, hstate, flags);
+ if (access == OP_MEMORY)
+ {
+ ao_ref ref;
+ ao_ref_init (&ref, const_cast <tree> (arg));
+ return hash_ao_ref (&ref, lto_streaming_expected_p (), m_tbaa, hstate);
+ }
+ else
+ return hash_operand (arg, hstate, flags);
}
bool
@@ -314,18 +322,40 @@ func_checker::compare_operand (tree t1, tree t2, operand_access_type access)
return true;
else if (!t1 || !t2)
return false;
- if (operand_equal_p (t1, t2, OEP_MATCH_SIDE_EFFECTS))
- return true;
- switch (access)
+ if (access == OP_MEMORY)
{
- case OP_MEMORY:
- return return_false_with_msg
- ("operand_equal_p failed (access == memory)");
- case OP_NORMAL:
+ ao_ref ref1, ref2;
+ ao_ref_init (&ref1, const_cast <tree> (t1));
+ ao_ref_init (&ref2, const_cast <tree> (t2));
+ int flags = compare_ao_refs (&ref1, &ref2,
+ lto_streaming_expected_p (), m_tbaa);
+
+ if (!flags)
+ return true;
+ if (flags & SEMANTICS)
+ return return_false_with_msg
+ ("compare_ao_refs failed (semantic difference)");
+ if (flags & BASE_ALIAS_SET)
+ return return_false_with_msg
+ ("compare_ao_refs failed (base alias set difference)");
+ if (flags & REF_ALIAS_SET)
+ return return_false_with_msg
+ ("compare_ao_refs failed (ref alias set difference)");
+ if (flags & ACCESS_PATH)
+ return return_false_with_msg
+ ("compare_ao_refs failed (access path difference)");
+ if (flags & DEPENDENCE_CLIQUE)
+ return return_false_with_msg
+ ("compare_ao_refs failed (dependence clique difference)");
+ gcc_unreachable ();
+ }
+ else
+ {
+ if (operand_equal_p (t1, t2, OEP_MATCH_SIDE_EFFECTS))
+ return true;
return return_false_with_msg
- ("operand_equal_p failed (access == normal)");
+ ("operand_equal_p failed");
}
- gcc_unreachable ();
}
bool
@@ -593,10 +623,17 @@ func_checker::compare_gimple_call (gcall *s1, gcall *s2)
tree fntype1 = gimple_call_fntype (s1);
tree fntype2 = gimple_call_fntype (s2);
- if ((fntype1 && !fntype2)
- || (!fntype1 && fntype2)
- || (fntype1 && !types_compatible_p (fntype1, fntype2)))
- return return_false_with_msg ("call function types are not compatible");
+
+ /* For direct calls we verify that types are comopatible so if we matced
+ callees, callers must match, too. For indirect calls however verify
+ function type. */
+ if (!gimple_call_fndecl (s1))
+ {
+ if ((fntype1 && !fntype2)
+ || (!fntype1 && fntype2)
+ || (fntype1 && !types_compatible_p (fntype1, fntype2)))
+ return return_false_with_msg ("call function types are not compatible");
+ }
if (fntype1 && fntype2 && comp_type_attributes (fntype1, fntype2) != 1)
return return_false_with_msg ("different fntype attributes");
@@ -652,10 +689,10 @@ func_checker::compare_gimple_assign (gimple *s1, gimple *s2)
arg2 = gimple_op (s2, i);
/* Compare types for LHS. */
- if (i == 0)
+ if (i == 0 && !gimple_store_p (s1))
{
if (!compatible_types_p (TREE_TYPE (arg1), TREE_TYPE (arg2)))
- return return_false_with_msg ("GIMPLE NOP LHS type mismatch");
+ return return_false_with_msg ("GIMPLE LHS type mismatch");
}
if (!compare_operand (arg1, arg2, get_operand_access_type (&map, arg1)))