Remove redundant variable in hash_set.
[official-gcc.git] / gcc / tsan.c
blob7631c3ff4199dc483d38b964f2bc2b10a1fc76e6
1 /* GCC instrumentation plugin for ThreadSanitizer.
2 Copyright (C) 2011, 2012 Free Software Foundation, Inc.
3 Contributed by Dmitry Vyukov <dvyukov@google.com>
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tree.h"
26 #include "intl.h"
27 #include "tm.h"
28 #include "basic-block.h"
29 #include "gimple.h"
30 #include "function.h"
31 #include "tree-flow.h"
32 #include "tree-pass.h"
33 #include "tree-iterator.h"
34 #include "langhooks.h"
35 #include "output.h"
36 #include "options.h"
37 #include "target.h"
38 #include "cgraph.h"
39 #include "diagnostic.h"
41 /* Number of instrumented memory accesses in the current function. */
43 /* Builds the following decl
44 void __tsan_read/writeX (void *addr); */
46 static tree
47 get_memory_access_decl (bool is_write, unsigned size)
49 enum built_in_function fcode;
51 if (size <= 1)
52 fcode = is_write ? BUILT_IN_TSAN_WRITE_1
53 : BUILT_IN_TSAN_READ_1;
54 else if (size <= 3)
55 fcode = is_write ? BUILT_IN_TSAN_WRITE_2
56 : BUILT_IN_TSAN_READ_2;
57 else if (size <= 7)
58 fcode = is_write ? BUILT_IN_TSAN_WRITE_4
59 : BUILT_IN_TSAN_READ_4;
60 else if (size <= 15)
61 fcode = is_write ? BUILT_IN_TSAN_WRITE_8
62 : BUILT_IN_TSAN_READ_8;
63 else
64 fcode = is_write ? BUILT_IN_TSAN_WRITE_16
65 : BUILT_IN_TSAN_READ_16;
67 return builtin_decl_implicit (fcode);
70 /* Check as to whether EXPR refers to a store to vptr. */
72 static tree
73 is_vptr_store (gimple stmt, tree expr, bool is_write)
75 if (is_write == true
76 && gimple_assign_single_p (stmt)
77 && TREE_CODE (expr) == COMPONENT_REF)
79 tree field = TREE_OPERAND (expr, 1);
80 if (TREE_CODE (field) == FIELD_DECL
81 && DECL_VIRTUAL_P (field))
82 return gimple_assign_rhs1 (stmt);
84 return NULL;
87 /* Checks as to whether EXPR refers to constant var/field/param.
88 Don't bother to instrument them. */
90 static bool
91 is_load_of_const_p (tree expr, bool is_write)
93 if (is_write)
94 return false;
95 if (TREE_CODE (expr) == COMPONENT_REF)
96 expr = TREE_OPERAND (expr, 1);
97 if (TREE_CODE (expr) == VAR_DECL
98 || TREE_CODE (expr) == PARM_DECL
99 || TREE_CODE (expr) == FIELD_DECL)
101 if (TREE_READONLY (expr))
102 return true;
104 return false;
107 /* Instruments EXPR if needed. If any instrumentation is inserted,
108 return true. */
110 static bool
111 instrument_expr (gimple_stmt_iterator gsi, tree expr, bool is_write)
113 enum tree_code tcode;
114 tree base, rhs, expr_type, expr_ptr, builtin_decl;
115 basic_block bb;
116 HOST_WIDE_INT size;
117 gimple stmt, g;
118 location_t loc;
120 base = get_base_address (expr);
121 if (base == NULL_TREE
122 || TREE_CODE (base) == SSA_NAME
123 || TREE_CODE (base) == STRING_CST)
124 return false;
126 tcode = TREE_CODE (expr);
128 /* Below are things we do not instrument
129 (no possibility of races or not implemented yet). */
130 if (/* Compiler-emitted artificial variables. */
131 (DECL_P (expr) && DECL_ARTIFICIAL (expr))
132 /* The var does not live in memory -> no possibility of races. */
133 || (tcode == VAR_DECL
134 && !TREE_ADDRESSABLE (expr)
135 && TREE_STATIC (expr) == 0)
136 /* Not implemented. */
137 || TREE_CODE (TREE_TYPE (expr)) == RECORD_TYPE
138 /* Not implemented. */
139 || tcode == CONSTRUCTOR
140 /* Not implemented. */
141 || tcode == PARM_DECL
142 /* Load of a const variable/parameter/field. */
143 || is_load_of_const_p (expr, is_write))
144 return false;
146 size = int_size_in_bytes (TREE_TYPE (expr));
147 if (size == -1)
148 return false;
150 /* For now just avoid instrumenting bit field acceses.
151 TODO: handle bit-fields as if touching the whole field. */
152 HOST_WIDE_INT bitsize, bitpos;
153 tree offset;
154 enum machine_mode mode;
155 int volatilep = 0, unsignedp = 0;
156 get_inner_reference (expr, &bitsize, &bitpos, &offset,
157 &mode, &unsignedp, &volatilep, false);
158 if (bitpos % (size * BITS_PER_UNIT)
159 || bitsize != size * BITS_PER_UNIT)
160 return false;
162 /* TODO: handle other case: ARRAY_RANGE_REF. */
163 if (tcode != ARRAY_REF
164 && tcode != VAR_DECL
165 && tcode != COMPONENT_REF
166 && tcode != INDIRECT_REF
167 && tcode != MEM_REF)
168 return false;
170 stmt = gsi_stmt (gsi);
171 loc = gimple_location (stmt);
172 rhs = is_vptr_store (stmt, expr, is_write);
173 gcc_checking_assert (rhs != NULL || is_gimple_addressable (expr));
174 expr_ptr = build_fold_addr_expr (unshare_expr (expr));
175 if (rhs == NULL)
177 expr_type = TREE_TYPE (expr);
178 while (TREE_CODE (expr_type) == ARRAY_TYPE)
179 expr_type = TREE_TYPE (expr_type);
180 size = int_size_in_bytes (expr_type);
181 g = gimple_build_call (get_memory_access_decl (is_write, size),
182 1, expr_ptr);
184 else
186 builtin_decl = builtin_decl_implicit (BUILT_IN_TSAN_VPTR_UPDATE);
187 g = gimple_build_call (builtin_decl, 1, expr_ptr);
189 gimple_set_location (g, loc);
190 /* Instrumentation for assignment of a function result
191 must be inserted after the call. Instrumentation for
192 reads of function arguments must be inserted before the call.
193 That's because the call can contain synchronization. */
194 if (is_gimple_call (stmt) && is_write)
196 /* If the call can throw, it must be the last stmt in
197 a basic block, so the instrumented stmts need to be
198 inserted in successor bbs. */
199 if (is_ctrl_altering_stmt (stmt))
201 edge e;
203 bb = gsi_bb (gsi);
204 e = find_fallthru_edge (bb->succs);
205 if (e)
206 gsi_insert_seq_on_edge_immediate (e, g);
208 else
209 gsi_insert_after (&gsi, g, GSI_NEW_STMT);
211 else
212 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
214 return true;
217 /* Instruments the gimple pointed to by GSI. Return
218 true if func entry/exit should be instrumented. */
220 static bool
221 instrument_gimple (gimple_stmt_iterator gsi)
223 gimple stmt;
224 tree rhs, lhs;
225 bool instrumented = false;
227 stmt = gsi_stmt (gsi);
228 if (is_gimple_call (stmt)
229 && (gimple_call_fndecl (stmt)
230 != builtin_decl_implicit (BUILT_IN_TSAN_INIT)))
231 return true;
232 else if (is_gimple_assign (stmt)
233 && !gimple_clobber_p (stmt))
235 if (gimple_store_p (stmt))
237 lhs = gimple_assign_lhs (stmt);
238 instrumented = instrument_expr (gsi, lhs, true);
240 if (gimple_assign_load_p (stmt))
242 rhs = gimple_assign_rhs1 (stmt);
243 instrumented = instrument_expr (gsi, rhs, false);
246 return instrumented;
249 /* Instruments all interesting memory accesses in the current function.
250 Return true if func entry/exit should be instrumented. */
252 static bool
253 instrument_memory_accesses (void)
255 basic_block bb;
256 gimple_stmt_iterator gsi;
257 bool fentry_exit_instrument = false;
259 FOR_EACH_BB (bb)
260 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
261 fentry_exit_instrument |= instrument_gimple (gsi);
262 return fentry_exit_instrument;
265 /* Instruments function entry. */
267 static void
268 instrument_func_entry (void)
270 basic_block succ_bb;
271 gimple_stmt_iterator gsi;
272 tree ret_addr, builtin_decl;
273 gimple g;
275 succ_bb = single_succ (ENTRY_BLOCK_PTR);
276 gsi = gsi_after_labels (succ_bb);
278 builtin_decl = builtin_decl_implicit (BUILT_IN_RETURN_ADDRESS);
279 g = gimple_build_call (builtin_decl, 1, integer_zero_node);
280 ret_addr = make_ssa_name (ptr_type_node, NULL);
281 gimple_call_set_lhs (g, ret_addr);
282 gimple_set_location (g, cfun->function_start_locus);
283 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
285 builtin_decl = builtin_decl_implicit (BUILT_IN_TSAN_FUNC_ENTRY);
286 g = gimple_build_call (builtin_decl, 1, ret_addr);
287 gimple_set_location (g, cfun->function_start_locus);
288 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
291 /* Instruments function exits. */
293 static void
294 instrument_func_exit (void)
296 location_t loc;
297 basic_block exit_bb;
298 gimple_stmt_iterator gsi;
299 gimple stmt, g;
300 tree builtin_decl;
301 edge e;
302 edge_iterator ei;
304 /* Find all function exits. */
305 exit_bb = EXIT_BLOCK_PTR;
306 FOR_EACH_EDGE (e, ei, exit_bb->preds)
308 gsi = gsi_last_bb (e->src);
309 stmt = gsi_stmt (gsi);
310 gcc_assert (gimple_code (stmt) == GIMPLE_RETURN);
311 loc = gimple_location (stmt);
312 builtin_decl = builtin_decl_implicit (BUILT_IN_TSAN_FUNC_EXIT);
313 g = gimple_build_call (builtin_decl, 0);
314 gimple_set_location (g, loc);
315 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
319 /* ThreadSanitizer instrumentation pass. */
321 static unsigned
322 tsan_pass (void)
324 if (instrument_memory_accesses ())
326 instrument_func_entry ();
327 instrument_func_exit ();
329 return 0;
332 /* The pass's gate. */
334 static bool
335 tsan_gate (void)
337 return flag_tsan != 0
338 && builtin_decl_implicit_p (BUILT_IN_TSAN_INIT);
341 /* Inserts __tsan_init () into the list of CTORs. */
343 void
344 tsan_finish_file (void)
346 tree ctor_statements;
347 tree init_decl;
349 ctor_statements = NULL_TREE;
350 init_decl = builtin_decl_implicit (BUILT_IN_TSAN_INIT);
351 append_to_statement_list (build_call_expr (init_decl, 0),
352 &ctor_statements);
353 cgraph_build_static_cdtor ('I', ctor_statements,
354 MAX_RESERVED_INIT_PRIORITY - 1);
357 /* The pass descriptor. */
359 struct gimple_opt_pass pass_tsan =
362 GIMPLE_PASS,
363 "tsan", /* name */
364 OPTGROUP_NONE, /* optinfo_flags */
365 tsan_gate, /* gate */
366 tsan_pass, /* execute */
367 NULL, /* sub */
368 NULL, /* next */
369 0, /* static_pass_number */
370 TV_NONE, /* tv_id */
371 PROP_ssa | PROP_cfg, /* properties_required */
372 0, /* properties_provided */
373 0, /* properties_destroyed */
374 0, /* todo_flags_start */
375 TODO_verify_all | TODO_update_ssa /* todo_flags_finish */
379 static bool
380 tsan_gate_O0 (void)
382 return flag_tsan != 0 && !optimize
383 && builtin_decl_implicit_p (BUILT_IN_TSAN_INIT);
386 struct gimple_opt_pass pass_tsan_O0 =
389 GIMPLE_PASS,
390 "tsan0", /* name */
391 OPTGROUP_NONE, /* optinfo_flags */
392 tsan_gate_O0, /* gate */
393 tsan_pass, /* execute */
394 NULL, /* sub */
395 NULL, /* next */
396 0, /* static_pass_number */
397 TV_NONE, /* tv_id */
398 PROP_ssa | PROP_cfg, /* properties_required */
399 0, /* properties_provided */
400 0, /* properties_destroyed */
401 0, /* todo_flags_start */
402 TODO_verify_all | TODO_update_ssa /* todo_flags_finish */