summaryrefslogtreecommitdiff
path: root/gcc/ipa-icf-gimple.h
blob: 40f7474738ef2ff5647715ef35c4e521bb7ed931 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
/* Interprocedural semantic function equality pass
   Copyright (C) 2014-2020 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 infrastructure
   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 instance of func_checker and call
   a comparison 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__);

/* 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 *filename,
			     const char *func, unsigned int line)
{
  if (dump_file && (dump_flags & TDF_DETAILS))
    fprintf (dump_file, "  false returned: '%s' in %s at %s:%u\n", message, func,
	     filename, 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, __FILE__, __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 *filename,
		    const char *func, unsigned int line)
{
  if (!result && dump_file && (dump_flags & TDF_DETAILS))
    fprintf (dump_file, "  false returned: '' in %s at %s:%u\n", func,
	     filename, line);

  return result;
}

/* Logs return value if RESULT is false.  */
#define return_with_debug(result) return_with_result \
  (result, __FILE__, __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 : ao_compare
{
public:
  /* Default constructor.  */
  func_checker ():
    m_source_func_decl (NULL_TREE), m_target_func_decl (NULL_TREE),
    m_ignored_source_nodes (NULL), m_ignored_target_nodes (NULL),
    m_ignore_labels (false), m_tbaa (true)
  {
    m_source_ssa_names.create (0);
    m_target_ssa_names.create (0);
  }

  /* 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 ignore_labels = false,
		bool tbaa = true,
		hash_set<symtab_node *> *ignored_source_nodes = NULL,
		hash_set<symtab_node *> *ignored_target_nodes = NULL);

  /* Memory release routine.  */
  virtual ~func_checker ();

  /* Function visits all gimple labels and creates corresponding
     mapping between basic blocks and labels.  */
  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 (const_tree t1, const_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 (gcall *s1, gcall *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 GIMPLE_LABEL stmts S1 and S2 that
     label statements are semantically equivalent.  */
  bool compare_gimple_label (const glabel *s1, const glabel *s2);

  /* Verifies for given GIMPLE_SWITCH stmts S1 and S2 that
     switch statements are semantically equivalent.  */
  bool compare_gimple_switch (const gswitch *s1, const gswitch *s2);

  /* Verifies for given GIMPLE_RETURN stmts S1 and S2 that
     return statements are semantically equivalent.  */
  bool compare_gimple_return (const greturn *s1, const greturn *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 GIMPLE_RESX stmts S1 and S2 that
     resx statements are semantically equivalent.  */
  bool compare_gimple_resx (const gresx *s1, const gresx *s2);

  /* Verifies for given GIMPLE_ASM stmts S1 and S2 that ASM statements
     are equivalent.
     For the beginning, the pass only supports equality for
     '__asm__ __volatile__ ("", "", "", "memory")'.  */
  bool compare_gimple_asm (const gasm *s1, const gasm *s2);

  /* Verification function for declaration trees T1 and T2.  */
  bool compare_decl (const_tree t1, const_tree t2);

  /* Compute hash map MAP that determines loads and stores of STMT.  */
  enum operand_access_type {OP_MEMORY, OP_NORMAL};
  typedef hash_set<tree> operand_access_type_map;

  /* Function responsible for comparison of various operands T1 and T2.
     If these components, from functions FUNC1 and FUNC2, are equal, true
     is returned.  */
  bool compare_operand (tree t1, tree t2, operand_access_type type);

  /* Compares GIMPLE ASM inputs (or outputs) where we iterate tree chain
     and compare both TREE_PURPOSEs and TREE_VALUEs.  */
  bool compare_asm_inputs_outputs (tree t1, tree t2,
				   operand_access_type_map *map);

  /* 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 (const_tree t1, const_tree t2);

  /* Compare loop information for basic blocks BB1 and BB2.  */
  bool compare_loops (basic_block bb1, basic_block bb2);

  /* Return true if types are compatible for polymorphic call analysis.
     COMPARE_PTR indicates if polymorphic type comparison should be
     done for pointers, too.  */
  static bool compatible_polymorphic_types_p (tree t1, tree t2,
					      bool compare_ptr);

  /* 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);

  /* Compute hash map determining access types of operands.  */
  static void classify_operands (const gimple *stmt,
				 operand_access_type_map *map);

  /* Return access type of a given operand.  */
  static operand_access_type get_operand_access_type
		 (operand_access_type_map *map, tree);
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 <const_tree, const_tree> m_decl_map;

  /* Label to basic block index mapping.  */
  hash_map <const_tree, int> m_label_bb_map;

  /* Flag if ignore labels in comparison.  */
  bool m_ignore_labels;

  /* Flag if we should compare type based alias analysis info.  */
  bool m_tbaa;

public:
  /* Return true if two operands are equal.  The flags fields can be used
     to specify OEP flags described above.  */
  virtual bool operand_equal_p (const_tree, const_tree, unsigned int flags);

  /* Generate a hash value for an expression.  This can be used iteratively
     by passing a previous result as the HSTATE argument.  */
  virtual void hash_operand (const_tree, inchash::hash &, unsigned flags);
  void hash_operand (const_tree, inchash::hash &, unsigned flags,
		     operand_access_type access);
};

} // ipa_icf_gimple namespace