summaryrefslogtreecommitdiff
path: root/gcc/ipa-icf-gimple.h
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ipa-icf-gimple.h')
-rw-r--r--gcc/ipa-icf-gimple.h264
1 files changed, 264 insertions, 0 deletions
diff --git a/gcc/ipa-icf-gimple.h b/gcc/ipa-icf-gimple.h
new file mode 100644
index 00000000000..8487a2ad745
--- /dev/null
+++ b/gcc/ipa-icf-gimple.h
@@ -0,0 +1,264 @@
+/* Interprocedural semantic function equality pass
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+ Contributed by Jan Hubicka <hubicka@ucw.cz> and Martin Liska <mliska@suse.cz>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+/* Gimple identical code folding (class func_checker) is an infastructure
+ capable of comparing two given functions. The class compares every
+ gimple statement and uses many dictionaries to map source and target
+ SSA_NAMEs, declarations and other components.
+
+ To use the infrastructure, create an instanse of func_checker and call
+ a comparsion function based on type of gimple statement. */
+
+/* Prints string STRING to a FILE with a given number of SPACE_COUNT. */
+#define FPUTS_SPACES(file, space_count, string) \
+ fprintf (file, "%*s" string, space_count, " ");
+
+/* fprintf function wrapper that transforms given FORMAT to follow given
+ number for SPACE_COUNT and call fprintf for a FILE. */
+#define FPRINTF_SPACES(file, space_count, format, ...) \
+ fprintf (file, "%*s" format, space_count, " ", ##__VA_ARGS__);
+
+/* Prints a MESSAGE to dump_file if exists. FUNC is name of function and
+ LINE is location in the source file. */
+
+static inline void
+dump_message_1 (const char *message, const char *func, unsigned int line)
+{
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, " debug message: %s (%s:%u)\n", message, func, line);
+}
+
+/* Prints a MESSAGE to dump_file if exists. */
+#define dump_message(message) dump_message_1 (message, __func__, __LINE__)
+
+/* Logs a MESSAGE to dump_file if exists and returns false. FUNC is name
+ of function and LINE is location in the source file. */
+
+static inline bool
+return_false_with_message_1 (const char *message, const char *func,
+ unsigned int line)
+{
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, " false returned: '%s' (%s:%u)\n", message, func, line);
+ return false;
+}
+
+/* Logs a MESSAGE to dump_file if exists and returns false. */
+#define return_false_with_msg(message) \
+ return_false_with_message_1 (message, __func__, __LINE__)
+
+/* Return false and log that false value is returned. */
+#define return_false() return_false_with_msg ("")
+
+/* Logs return value if RESULT is false. FUNC is name of function and LINE
+ is location in the source file. */
+
+static inline bool
+return_with_result (bool result, const char *func, unsigned int line)
+{
+ if (!result && dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, " false returned (%s:%u)\n", func, line);
+
+ return result;
+}
+
+/* Logs return value if RESULT is false. */
+#define return_with_debug(result) return_with_result (result, __func__, __LINE__)
+
+/* Verbose logging function logging statements S1 and S2 of a CODE.
+ FUNC is name of function and LINE is location in the source file. */
+
+static inline bool
+return_different_stmts_1 (gimple s1, gimple s2, const char *code,
+ const char *func, unsigned int line)
+{
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, " different statement for code: %s (%s:%u):\n",
+ code, func, line);
+
+ print_gimple_stmt (dump_file, s1, 3, TDF_DETAILS);
+ print_gimple_stmt (dump_file, s2, 3, TDF_DETAILS);
+ }
+
+ return false;
+}
+
+/* Verbose logging function logging statements S1 and S2 of a CODE. */
+#define return_different_stmts(s1, s2, code) \
+ return_different_stmts_1 (s1, s2, code, __func__, __LINE__)
+
+namespace ipa_icf_gimple {
+
+/* Basic block struct for semantic equality pass. */
+class sem_bb
+{
+public:
+ sem_bb (basic_block bb_, unsigned nondbg_stmt_count_, unsigned edge_count_):
+ bb (bb_), nondbg_stmt_count (nondbg_stmt_count_), edge_count (edge_count_) {}
+
+ /* Basic block the structure belongs to. */
+ basic_block bb;
+
+ /* Number of non-debug statements in the basic block. */
+ unsigned nondbg_stmt_count;
+
+ /* Number of edges connected to the block. */
+ unsigned edge_count;
+};
+
+/* A class aggregating all connections and semantic equivalents
+ for a given pair of semantic function candidates. */
+class func_checker
+{
+public:
+ /* Initialize internal structures for a given SOURCE_FUNC_DECL and
+ TARGET_FUNC_DECL. Strict polymorphic comparison is processed if
+ an option COMPARE_POLYMORPHIC is true. For special cases, one can
+ set IGNORE_LABELS to skip label comparison.
+ Similarly, IGNORE_SOURCE_DECLS and IGNORE_TARGET_DECLS are sets
+ of declarations that can be skipped. */
+ func_checker (tree source_func_decl, tree target_func_decl,
+ bool compare_polymorphic,
+ bool ignore_labels = false,
+ hash_set<symtab_node *> *ignored_source_nodes = NULL,
+ hash_set<symtab_node *> *ignored_target_nodes = NULL);
+
+ /* Memory release routine. */
+ ~func_checker();
+
+ void parse_labels (sem_bb *bb);
+
+ /* Basic block equivalence comparison function that returns true if
+ basic blocks BB1 and BB2 correspond. */
+ bool compare_bb (sem_bb *bb1, sem_bb *bb2);
+
+ /* Verifies that trees T1 and T2 are equivalent from perspective of ICF. */
+ bool compare_ssa_name (tree t1, tree t2);
+
+ /* Verification function for edges E1 and E2. */
+ bool compare_edge (edge e1, edge e2);
+
+ /* Verifies for given GIMPLEs S1 and S2 that
+ call statements are semantically equivalent. */
+ bool compare_gimple_call (gimple s1, gimple s2);
+
+ /* Verifies for given GIMPLEs S1 and S2 that
+ assignment statements are semantically equivalent. */
+ bool compare_gimple_assign (gimple s1, gimple s2);
+
+ /* Verifies for given GIMPLEs S1 and S2 that
+ condition statements are semantically equivalent. */
+ bool compare_gimple_cond (gimple s1, gimple s2);
+
+ /* Verifies for given GIMPLEs S1 and S2 that
+ label statements are semantically equivalent. */
+ bool compare_gimple_label (gimple s1, gimple s2);
+
+ /* Verifies for given GIMPLEs S1 and S2 that
+ switch statements are semantically equivalent. */
+ bool compare_gimple_switch (gimple s1, gimple s2);
+
+ /* Verifies for given GIMPLEs S1 and S2 that
+ return statements are semantically equivalent. */
+ bool compare_gimple_return (gimple s1, gimple s2);
+
+ /* Verifies for given GIMPLEs S1 and S2 that
+ goto statements are semantically equivalent. */
+ bool compare_gimple_goto (gimple s1, gimple s2);
+
+ /* Verifies for given GIMPLEs S1 and S2 that
+ resx statements are semantically equivalent. */
+ bool compare_gimple_resx (gimple s1, gimple s2);
+
+ /* Verifies for given GIMPLEs S1 and S2 that ASM statements are equivalent.
+ For the beginning, the pass only supports equality for
+ '__asm__ __volatile__ ("", "", "", "memory")'. */
+ bool compare_gimple_asm (gimple s1, gimple s2);
+
+ /* Verification function for declaration trees T1 and T2. */
+ bool compare_decl (tree t1, tree t2);
+
+ /* Verifies that tree labels T1 and T2 correspond. */
+ bool compare_tree_ssa_label (tree t1, tree t2);
+
+ /* Function responsible for comparison of handled components T1 and T2.
+ If these components, from functions FUNC1 and FUNC2, are equal, true
+ is returned. */
+ bool compare_operand (tree t1, tree t2);
+
+ /* Compares two tree list operands T1 and T2 and returns true if these
+ two trees are semantically equivalent. */
+ bool compare_tree_list_operand (tree t1, tree t2);
+
+ /* Verifies that trees T1 and T2, representing function declarations
+ are equivalent from perspective of ICF. */
+ bool compare_function_decl (tree t1, tree t2);
+
+ /* Verifies that trees T1 and T2 do correspond. */
+ bool compare_variable_decl (tree t1, tree t2);
+
+ /* Return true if types are compatible from perspective of ICF.
+ FIRST_ARGUMENT indicates if the comparison is called for
+ first parameter of a function. */
+ static bool compatible_types_p (tree t1, tree t2,
+ bool compare_polymorphic = true,
+ bool first_argument = false);
+
+
+private:
+ /* Vector mapping source SSA names to target ones. */
+ vec <int> m_source_ssa_names;
+
+ /* Vector mapping target SSA names to source ones. */
+ vec <int> m_target_ssa_names;
+
+ /* Source TREE function declaration. */
+ tree m_source_func_decl;
+
+ /* Target TREE function declaration. */
+ tree m_target_func_decl;
+
+ /* Source symbol nodes that should be skipped by
+ declaration comparison. */
+ hash_set<symtab_node *> *m_ignored_source_nodes;
+
+ /* Target symbol nodes that should be skipped by
+ declaration comparison. */
+ hash_set<symtab_node *> *m_ignored_target_nodes;
+
+ /* Source to target edge map. */
+ hash_map <edge, edge> m_edge_map;
+
+ /* Source to target declaration map. */
+ hash_map <tree, tree> m_decl_map;
+
+ /* Label to basic block index mapping. */
+ hash_map <tree, int> m_label_bb_map;
+
+ /* Flag if polymorphic comparison should be executed. */
+ bool m_compare_polymorphic;
+
+ /* Flag if ignore labels in comparison. */
+ bool m_ignore_labels;
+};
+
+} // ipa_icf_gimple namespace