From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 12940 invoked by alias); 28 Oct 2011 15:56:23 -0000 Received: (qmail 12845 invoked by uid 22791); 28 Oct 2011 15:56:10 -0000 X-SWARE-Spam-Status: No, hits=-2.2 required=5.0 tests=AWL,BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,RP_MATCHES_RCVD,SPF_HELO_PASS,TW_CP,TW_TM,TW_VP,TW_VT X-Spam-Check-By: sourceware.org Received: from smtp-out.google.com (HELO smtp-out.google.com) (74.125.121.67) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 28 Oct 2011 15:55:46 +0000 Received: from wpaz29.hot.corp.google.com (wpaz29.hot.corp.google.com [172.24.198.93]) by smtp-out.google.com with ESMTP id p9SFthCc007141 for ; Fri, 28 Oct 2011 08:55:44 -0700 Received: from vcbfl15 (vcbfl15.prod.google.com [10.220.204.79]) by wpaz29.hot.corp.google.com with ESMTP id p9SFpPtx000573 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=NOT) for ; Fri, 28 Oct 2011 08:55:43 -0700 Received: by vcbfl15 with SMTP id fl15so5667064vcb.5 for ; Fri, 28 Oct 2011 08:55:42 -0700 (PDT) Received: by 10.150.205.19 with SMTP id c19mr3252374ybg.58.1319817342837; Fri, 28 Oct 2011 08:55:42 -0700 (PDT) MIME-Version: 1.0 Received: by 10.150.205.19 with SMTP id c19mr3252326ybg.58.1319817342394; Fri, 28 Oct 2011 08:55:42 -0700 (PDT) Received: by 10.150.218.16 with HTTP; Fri, 28 Oct 2011 08:55:42 -0700 (PDT) In-Reply-To: References: <20111028132511.873EAC1B4C@1024cores.msk.corp.google.com> Date: Fri, 28 Oct 2011 16:32:00 -0000 Message-ID: Subject: Re: [C-compiler-team] [google] ThreadSanitizer instrumentation pass (issue5303083) From: Diego Novillo To: Xinliang David Li Cc: Dmitriy Vyukov , reply@codereview.appspotmail.com, kcc@google.com, gcc-patches@gcc.gnu.org Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable X-System-Of-Record: true X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org X-SW-Source: 2011-10/txt/msg02687.txt.bz2 [ Removing closed list from CCs, please trim CC in future replies. Thanks.= ] On Fri, Oct 28, 2011 at 08:53, Xinliang David Li wrote: > Dmitriy, I will review it next week. > > Do you have some runtime overhead data ? > > thanks, > > David > > On Fri, Oct 28, 2011 at 6:25 AM, Dmitriy Vyukov wrot= e: >> The patch is for google/main branch. >> ThreadSanitizer is a data race detector for C/C++ programs. >> http://code.google.com/p/data-race-test/wiki/ThreadSanitizer >> >> The tool consists of two parts: >> instrumentation module (this file) and a run-time library. >> The instrumentation module mainintains shadow call stacks >> and intercepts interesting memory accesses. >> The instrumentation is enabled with -ftsan flag. >> >> Instrumentation for shadow stack maintainance is as follows: >> void somefunc () >> { >> =C2=A0__tsan_shadow_stack [-1] =3D __builtin_return_address (0); >> =C2=A0__tsan_shadow_stack++; >> =C2=A0// function body >> =C2=A0__tsan_shadow_stack--; >> } >> >> Interception for memory access interception is as follows: >> *addr =3D 1; >> __tsan_handle_mop (addr, flags); >> where flags are (is_sblock | (is_store << 1) | ((sizeof (*addr) - 1) << = 2). >> is_sblock is used merely for optimization purposes and can always >> be set to 1, see comments in instrument_mops function. >> >> Ignore files can be used to selectively non instrument some functions. >> Ignore file is specified with -ftsan-ignore=3Dfilename flag. >> There are 3 types of ignores: (1) do not instrument memory accesses >> in the function, (2) do not create sblocks in the function >> and (3) recursively ignore memory accesses in the function. >> That last ignore type requires additional instrumentation of the form: >> void somefunc () >> { >> =C2=A0__tsan_thread_ignore++; >> =C2=A0// function body >> =C2=A0__tsan_thread_ignore--; >> } >> >> The run-time library provides __tsan_handle_mop function, >> definitions of __tsan_shadow_stack and __tsan_thread_ignore variables, >> and intercepts synchronization related functions. >> >> 2011-10-28 =C2=A0 Dmitriy Vyukov =C2=A0 >> >> =C2=A0 =C2=A0 =C2=A0 =C2=A0* gcc/doc/invoke.texi: >> =C2=A0 =C2=A0 =C2=A0 =C2=A0* gcc/tree-tsan.c (enum tsan_ignore_e): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(enum bb_state_e): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(struct bb_data_t): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(struct mop_desc_t): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(struct tsan_ignore_desc_t): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(lookup_name): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(shadow_stack_def): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(thread_ignore_def): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(rtl_mop_def): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(ignore_append): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(ignore_match): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(ignore_load): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(tsan_ignore): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(decl_name): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(build_stack_op): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(build_rec_ignore_op): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(build_stack_assign): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(instr_mop): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(instr_vptr_store): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(instr_func): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(set_location): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(is_dtor_vptr_store): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(is_vtbl_read): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(is_load_of_const): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(handle_expr): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(handle_gimple): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(instrument_bblock): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(instrument_mops): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(instrument_function): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(tsan_pass): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(tsan_gate): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0* gcc/tree-pass.h: >> =C2=A0 =C2=A0 =C2=A0 =C2=A0* gcc/testsuite/gcc.dg/tsan-ignore.ignore: >> =C2=A0 =C2=A0 =C2=A0 =C2=A0* gcc/testsuite/gcc.dg/tsan.h (__tsan_init): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(__tsan_expect_mop): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(__tsan_handle_mop): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0* gcc/testsuite/gcc.dg/tsan-ignore.c (foo): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(int bar): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(int baz): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(int bla): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(int xxx): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0(main): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0* gcc/testsuite/gcc.dg/tsan-ignore.h (in_tsan= _ignore_header): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0* gcc/testsuite/gcc.dg/tsan-stack.c (foobar): >> =C2=A0 =C2=A0 =C2=A0 =C2=A0* gcc/testsuite/gcc.dg/tsan-mop.c: >> =C2=A0 =C2=A0 =C2=A0 =C2=A0* gcc/common.opt: >> =C2=A0 =C2=A0 =C2=A0 =C2=A0* gcc/Makefile.in: >> =C2=A0 =C2=A0 =C2=A0 =C2=A0* gcc/passes.c: >> >> Index: gcc/doc/invoke.texi >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> --- gcc/doc/invoke.texi (revision 180522) >> +++ gcc/doc/invoke.texi (working copy) >> @@ -308,6 +308,7 @@ >> =C2=A0-fdump-tree-ssa@r{[}-@var{n}@r{]} -fdump-tree-pre@r{[}-@var{n}@r{]= } @gol >> =C2=A0-fdump-tree-ccp@r{[}-@var{n}@r{]} -fdump-tree-dce@r{[}-@var{n}@r{]= } @gol >> =C2=A0-fdump-tree-gimple@r{[}-raw@r{]} -fdump-tree-mudflap@r{[}-@var{n}@= r{]} @gol >> +-fdump-tree-tsan@r{[}-@var{n}@r{]} @gol >> =C2=A0-fdump-tree-dom@r{[}-@var{n}@r{]} @gol >> =C2=A0-fdump-tree-dse@r{[}-@var{n}@r{]} @gol >> =C2=A0-fdump-tree-phiprop@r{[}-@var{n}@r{]} @gol >> @@ -381,8 +382,8 @@ >> =C2=A0-floop-parallelize-all -flto -flto-compression-level @gol >> =C2=A0-flto-partition=3D@var{alg} -flto-report -fmerge-all-constants @gol >> =C2=A0-fmerge-constants -fmodulo-sched -fmodulo-sched-allow-regmoves @gol >> --fmove-loop-invariants fmudflap -fmudflapir -fmudflapth -fno-branch-cou= nt-reg @gol >> --fno-default-inline @gol >> +-fmove-loop-invariants -fmudflap -fmudflapir -fmudflapth -fno-branch-co= unt-reg @gol >> +-ftsan -ftsan-ignore -fno-default-inline @gol >> =C2=A0-fno-defer-pop -fno-function-cse -fno-guess-branch-probability @gol >> =C2=A0-fno-inline -fno-math-errno -fno-peephole -fno-peephole2 @gol >> =C2=A0-fno-sched-interblock -fno-sched-spec -fno-signed-zeros @gol >> @@ -5896,6 +5897,11 @@ >> =C2=A0Dump each function after adding mudflap instrumentation. =C2=A0The= file name is >> =C2=A0made by appending @file{.mudflap} to the source file name. >> >> +@item tsan >> +@opindex fdump-tree-tsan >> +Dump each function after adding ThreadSanitizer instrumentation. =C2=A0= The file name is >> +made by appending @file{.tsan} to the source file name. >> + >> =C2=A0@item sra >> =C2=A0@opindex fdump-tree-sra >> =C2=A0Dump each function after performing scalar replacement of aggregat= es. =C2=A0The >> @@ -6674,6 +6680,12 @@ >> =C2=A0some protection against outright memory corrupting writes, but all= ows >> =C2=A0erroneously read data to propagate within a program. >> >> +@item -ftsan -ftsan-ignore >> +@opindex ftsan >> +@opindex ftsan-ignore >> +Add ThreadSanitizer instrumentation. Use @option{-ftsan-ignore} to spec= ify >> +an ignore file. Refer to http://go/tsan for details. >> + >> =C2=A0@item -fthread-jumps >> =C2=A0@opindex fthread-jumps >> =C2=A0Perform optimizations where we check to see if a jump branches to a >> Index: gcc/tree-tsan.c >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> --- gcc/tree-tsan.c =C2=A0 =C2=A0 (revision 0) >> +++ gcc/tree-tsan.c =C2=A0 =C2=A0 (revision 0) >> @@ -0,0 +1,1204 @@ >> +/* ThreadSanitizer instrumentation pass. >> + =C2=A0 http://code.google.com/p/data-race-test >> + =C2=A0 Copyright (C) 2011 >> + =C2=A0 Free Software Foundation, Inc. >> + =C2=A0 Contributed by Dmitry Vyukov >> + >> +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. =C2=A0See 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. =C2=A0If not see >> +. =C2=A0*/ >> + >> +#include "config.h" >> +#include "system.h" >> +#include "coretypes.h" >> +#include "tree.h" >> +#include "intl.h" >> +#include "tm.h" >> +#include "basic-block.h" >> +#include "gimple.h" >> +#include "function.h" >> +#include "tree-flow.h" >> +#include "tree-pass.h" >> +#include "cfghooks.h" >> +#include "langhooks.h" >> +#include "output.h" >> +#include "options.h" >> + >> +/* The file can be compiled either as compiler pass or plugin. =C2=A0*/ >> +#ifdef GCC_PLG >> +# include "c-common.h" >> +#else >> +# include "c-family/c-common.h" >> +#endif >> + >> +#include "diagnostic.h" >> + >> +#include >> +#include >> + >> +/* ThreadSanitizer is a data race detector for C/C++ programs. >> + =C2=A0 http://code.google.com/p/data-race-test/wiki/ThreadSanitizer >> + >> + =C2=A0 The tool consists of two parts: >> + =C2=A0 instrumentation module (this file) and a run-time library. >> + =C2=A0 The instrumentation module mainintains shadow call stacks >> + =C2=A0 and intercepts interesting memory accesses. >> + =C2=A0 The instrumentation is enabled with -ftsan flag. >> + >> + =C2=A0 Instrumentation for shadow stack maintainance is as follows: >> + =C2=A0 void somefunc () >> + =C2=A0 { >> + =C2=A0 =C2=A0 __tsan_shadow_stack [-1] =3D __builtin_return_address (0= ); >> + =C2=A0 =C2=A0 __tsan_shadow_stack++; >> + =C2=A0 =C2=A0 // function body >> + =C2=A0 =C2=A0 __tsan_shadow_stack--; >> + =C2=A0 } >> + >> + =C2=A0 Interception for memory access interception is as follows: >> + =C2=A0 *addr =3D 1; >> + =C2=A0 __tsan_handle_mop (addr, flags); >> + =C2=A0 where flags are (is_sblock | (is_store << 1) | ((sizeof (*addr)= - 1) << 2). >> + =C2=A0 is_sblock is used merely for optimization purposes and can alwa= ys >> + =C2=A0 be set to 1, see comments in instrument_mops function. >> + >> + =C2=A0 Ignore files can be used to selectively non instrument some fun= ctions. >> + =C2=A0 Ignore file is specified with -ftsan-ignore=3Dfilename flag. >> + =C2=A0 There are 3 types of ignores: (1) do not instrument memory acce= sses >> + =C2=A0 in the function, (2) do not create sblocks in the function >> + =C2=A0 and (3) recursively ignore memory accesses in the function. >> + =C2=A0 That last ignore type requires additional instrumentation of th= e form: >> + =C2=A0 void somefunc () >> + =C2=A0 { >> + =C2=A0 =C2=A0 __tsan_thread_ignore++; >> + =C2=A0 =C2=A0 // function body >> + =C2=A0 =C2=A0 __tsan_thread_ignore--; >> + =C2=A0 } >> + >> + =C2=A0 The run-time library provides __tsan_handle_mop function, >> + =C2=A0 definitions of __tsan_shadow_stack and __tsan_thread_ignore var= iables, >> + =C2=A0 and intercepts synchronization related functions. =C2=A0*/ >> + >> +#define RTL_IGNORE "__tsan_thread_ignore" >> +#define RTL_STACK "__tsan_shadow_stack" >> +#define RTL_MOP "__tsan_handle_mop" >> +#define RTL_PERFIX "__tsan_" >> +#define MAX_MOP_BYTES 16 >> +#define SBLOCK_SIZE 5 >> + >> +enum tsan_ignore_e >> +{ >> + =C2=A0tsan_ignore_none =C2=A0=3D 1 << 0, /* Do not ignore. =C2=A0*/ >> + =C2=A0tsan_ignore_func =C2=A0=3D 1 << 1, /* Completely ignore the whol= e func. =C2=A0*/ >> + =C2=A0tsan_ignore_mop =C2=A0 =3D 1 << 2, /* Do not instrument memory a= ccesses. =C2=A0*/ >> + =C2=A0tsan_ignore_rec =C2=A0 =3D 1 << 3, /* Do not instrument memory a= ccesses recursively. =C2=A0*/ >> + =C2=A0tsan_ignore_hist =C2=A0=3D 1 << 4 =C2=A0/* Do not create superbl= ocks. =C2=A0*/ >> +}; >> + >> +/* Basic block state during CFG traversal. =C2=A0*/ >> +enum bb_state_e >> +{ >> + =C2=A0bb_not_visited, >> + =C2=A0bb_candidate, >> + =C2=A0bb_visited >> +}; >> + >> +/* Info associated with each basic block. >> + =C2=A0 Used to determine super-blocks (see instrument_mops ()). =C2=A0= */ >> +struct bb_data_t >> +{ >> + =C2=A0enum bb_state_e =C2=A0 =C2=A0 =C2=A0 state; >> + =C2=A0int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 has_sb; >> + =C2=A0const char =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 *sb_file; >> + =C2=A0int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 sb_line_min; >> + =C2=A0int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 sb_line_max; >> +}; >> + >> +/* Memory access descriptor. =C2=A0*/ >> +struct mop_desc_t >> +{ >> + =C2=A0int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 is_call; >> + =C2=A0gimple_stmt_iterator =C2=A0gsi; >> + =C2=A0tree =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0expr; >> + =C2=A0tree =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0dtor_vptr_expr; >> + =C2=A0int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 is_store; >> +}; >> + >> +struct tsan_ignore_desc_t >> +{ >> + =C2=A0struct tsan_ignore_desc_t *next; >> + =C2=A0enum tsan_ignore_e =C2=A0 =C2=A0 =C2=A0 =C2=A0 type; >> + =C2=A0char =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0*name; >> +}; >> + >> +/* Number of instrumented memory accesses in the current function. =C2= =A0*/ >> +static int func_mops; >> +/* Number of function calls in the current function. =C2=A0*/ >> +static int func_calls; >> +/* Ignore status for the current function (see tsan_ignore_e). =C2=A0*/ >> +static enum tsan_ignore_e func_ignore; >> + >> +static int ignore_init =3D 0; >> +static struct tsan_ignore_desc_t *ignore_head; >> + >> +typedef struct mop_desc_t mop_desc_t; >> +DEF_VEC_O (mop_desc_t); >> +DEF_VEC_ALLOC_O (mop_desc_t, heap); >> +static VEC (mop_desc_t, heap) *mop_list; >> + >> +/* The function is not available in some modules. =C2=A0*/ >> +tree __attribute__((weak)) >> +lookup_name (tree t) >> +{ >> + =C2=A0(void)t; >> + =C2=A0return NULL_TREE; >> +} >> + >> +/* Builds the following decl >> + =C2=A0 extern __thread void **__tsan_shadow_stack; */ >> +static tree >> +shadow_stack_def (void) >> +{ >> + =C2=A0static tree def; >> + >> + =C2=A0if (def !=3D NULL) >> + =C2=A0 =C2=A0return def; >> + >> + =C2=A0/* Check if a user has defined it for testing */ >> + =C2=A0def =3D lookup_name (get_identifier (RTL_STACK)); >> + =C2=A0if (def !=3D NULL) >> + =C2=A0 =C2=A0return def; >> + >> + =C2=A0def =3D build_decl (UNKNOWN_LOCATION, VAR_DECL, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 get_ide= ntifier (RTL_STACK), >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 build_p= ointer_type (ptr_type_node)); >> + =C2=A0TREE_STATIC (def) =3D 1; >> + =C2=A0TREE_PUBLIC (def) =3D 1; >> + =C2=A0DECL_EXTERNAL (def) =3D 1; >> + =C2=A0DECL_TLS_MODEL (def) =3D decl_default_tls_model (def); >> + =C2=A0TREE_USED (def) =3D 1; >> + =C2=A0TREE_THIS_VOLATILE (def) =3D 1; >> + =C2=A0SET_DECL_ASSEMBLER_NAME (def, get_identifier (RTL_STACK)); >> + =C2=A0return def; >> +} >> + >> +/* Builds the following decl >> + =C2=A0 extern __thread int __tsan_thread_ignore; */ >> +static tree >> +thread_ignore_def (void) >> +{ >> + =C2=A0static tree def; >> + >> + =C2=A0if (def !=3D NULL) >> + =C2=A0 =C2=A0return def; >> + >> + =C2=A0/* Check if a user has defined it for testing */ >> + =C2=A0def =3D lookup_name (get_identifier (RTL_IGNORE)); >> + =C2=A0if (def !=3D NULL) >> + =C2=A0 =C2=A0return def; >> + >> + =C2=A0def =3D build_decl (UNKNOWN_LOCATION, VAR_DECL, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 get_ide= ntifier (RTL_IGNORE), >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 integer= _type_node); >> + =C2=A0TREE_STATIC (def) =3D 1; >> + =C2=A0TREE_PUBLIC (def) =3D 1; >> + =C2=A0DECL_EXTERNAL (def) =3D 1; >> + =C2=A0DECL_TLS_MODEL (def) =3D decl_default_tls_model (def); >> + =C2=A0TREE_USED (def) =3D 1; >> + =C2=A0TREE_THIS_VOLATILE (def) =3D 1; >> + =C2=A0SET_DECL_ASSEMBLER_NAME (def, get_identifier (RTL_IGNORE)); >> + =C2=A0return def; >> +} >> + >> +/* Builds the following decl >> + =C2=A0 void __tsan_handle_mop (void *addr, unsigned flags); */ >> +static tree >> +rtl_mop_def (void) >> +{ >> + =C2=A0tree fn_type; >> + >> + =C2=A0static tree def; >> + >> + =C2=A0if (def !=3D NULL) >> + =C2=A0 =C2=A0return def; >> + >> + =C2=A0/* Check if a user has defined it for testing */ >> + =C2=A0def =3D lookup_name (get_identifier (RTL_MOP)); >> + =C2=A0if (def !=3D NULL) >> + =C2=A0 =C2=A0return def; >> + >> + =C2=A0fn_type =3D build_function_type_list (void_type_node, ptr_type_n= ode, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0integer_type_= node , NULL_TREE); >> + =C2=A0def =3D build_fn_decl (RTL_MOP, fn_type); >> + =C2=A0TREE_NOTHROW (def) =3D 1; >> + =C2=A0DECL_ATTRIBUTES (def) =3D tree_cons (get_identifier ("leaf"), >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 NULL, DECL_ATTRIBUT= ES (def)); >> + =C2=A0DECL_ASSEMBLER_NAME (def); >> + =C2=A0return def; >> +} >> + >> +/* Adds new ignore definition to the global list */ >> +static void >> +ignore_append (enum tsan_ignore_e type, char *name) >> +{ >> + =C2=A0struct tsan_ignore_desc_t *desc; >> + >> + =C2=A0desc =3D (struct tsan_ignore_desc_t*)xmalloc (sizeof (*desc)); >> + =C2=A0desc->type =3D type; >> + =C2=A0desc->name =3D xstrdup (name); >> + =C2=A0desc->next =3D ignore_head; >> + =C2=A0ignore_head =3D desc; >> +} >> + >> +/* Checks as to whether identifier 'str' matches template 'templ'. >> + =C2=A0 Templates can only contain '*', e.g. 'std*string*insert'. >> + =C2=A0 Templates implicitly start and end with '*' >> + =C2=A0 since they are matched against mangled names. =C2=A0*/ >> +static int >> +ignore_match (char *templ, const char *str) >> +{ >> + =C2=A0char *tpos; >> + =C2=A0const char *spos; >> + >> + =C2=A0while (templ && templ [0]) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0if (templ [0] =3D=3D '*') >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0templ++; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0continue; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + =C2=A0 =C2=A0 =C2=A0if (str [0] =3D=3D 0) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0return 0; >> + =C2=A0 =C2=A0 =C2=A0tpos =3D strchr (templ, '*'); >> + =C2=A0 =C2=A0 =C2=A0if (tpos !=3D NULL) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0tpos [0] =3D 0; >> + =C2=A0 =C2=A0 =C2=A0spos =3D strstr (str, templ); >> + =C2=A0 =C2=A0 =C2=A0str =3D spos + strlen (templ); >> + =C2=A0 =C2=A0 =C2=A0templ =3D tpos; >> + =C2=A0 =C2=A0 =C2=A0if (tpos !=3D NULL) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0tpos [0] =3D '*'; >> + =C2=A0 =C2=A0 =C2=A0if (spos =3D=3D NULL) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0return 0; >> + =C2=A0 =C2=A0} >> + =C2=A0return 1; >> +} >> + >> +/* Loads ignore definitions from the file specified by -ftsan-ignore=3D= filename. >> + =C2=A0 Ignore files have the following format: >> + >> +# This is a comment - ignored >> + >> +# The below line says to not instrument memory accesses >> +# in all functions that match 'std*string*insert' >> +fun:std*string*insert >> + >> +# The below line says to not instrument memory accesses >> +# in the function called 'foobar' *and* in all functions >> +# that it calls recursively >> +fun_r:foobar >> + >> +# The below line says to not create superblocks >> +# in the function called 'barbaz' >> +fun_hist:barbaz >> + >> +# Ignore all functions in the source file >> +src:atomic.c >> + >> +# Everything else is uninteresting for us (e.g. obj:) >> +*/ >> +static void >> +ignore_load (void) >> +{ >> + =C2=A0FILE *f; >> + =C2=A0char *line; >> + =C2=A0size_t linesz; >> + =C2=A0ssize_t sz; >> + =C2=A0char buf [PATH_MAX]; >> + >> + =C2=A0if (flag_tsan_ignore =3D=3D NULL || flag_tsan_ignore [0] =3D=3D = 0) >> + =C2=A0 =C2=A0return; >> + >> + =C2=A0f =3D fopen (flag_tsan_ignore, "r"); >> + =C2=A0if (f =3D=3D NULL) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0/* Try to open it relative to main_input_filename.= =C2=A0*/ >> + =C2=A0 =C2=A0 =C2=A0strncpy (buf, main_input_filename, sizeof (buf)); >> + =C2=A0 =C2=A0 =C2=A0buf [sizeof (buf) - 1] =3D 0; >> + =C2=A0 =C2=A0 =C2=A0line =3D strrchr (buf, '/'); >> + =C2=A0 =C2=A0 =C2=A0if (line !=3D NULL) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0line++; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0strncpy (line, flag_tsan_ignore, siz= eof (buf) - (line - buf)); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf [sizeof (buf) - 1] =3D 0; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0f =3D fopen (buf, "r"); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + =C2=A0 =C2=A0} >> + =C2=A0if (f =3D=3D NULL) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0printf ("failed to open ignore file '%s'\n", flag_= tsan_ignore); >> + =C2=A0 =C2=A0 =C2=A0exit (1); >> + =C2=A0 =C2=A0} >> + >> + =C2=A0line =3D 0; >> + =C2=A0linesz =3D 0; >> + =C2=A0while ((sz =3D getline (&line, &linesz, f)) !=3D -1) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0if (sz =3D=3D 0) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0continue; >> + =C2=A0 =C2=A0 =C2=A0/* strip line terminator */ >> + =C2=A0 =C2=A0 =C2=A0if (line [sz-1] =3D=3D '\r' || line [sz-1] =3D=3D = '\n') >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0line [sz-1] =3D 0; >> + =C2=A0 =C2=A0 =C2=A0if (strncmp (line, "src:", sizeof ("src:")-1) =3D= =3D 0) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0ignore_append (tsan_ignore_func, line + siz= eof ("src:")-1); >> + =C2=A0 =C2=A0 =C2=A0else if (strncmp (line, "fun:", sizeof ("fun:")-1)= =3D=3D 0) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0ignore_append (tsan_ignore_mop, line + size= of ("fun:")-1); >> + =C2=A0 =C2=A0 =C2=A0else if (strncmp (line, "fun_r:", sizeof ("fun_r:"= )-1) =3D=3D 0) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0ignore_append (tsan_ignore_rec, line + size= of ("fun_r:")-1); >> + =C2=A0 =C2=A0 =C2=A0else if (strncmp (line, "fun_hist:", sizeof ("fun_= hist:")-1) =3D=3D 0) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0ignore_append (tsan_ignore_hist, line + siz= eof ("fun_hist:")-1); >> + =C2=A0 =C2=A0 =C2=A0/* other lines are not interesting */ >> + =C2=A0 =C2=A0} >> + >> + =C2=A0free (line); >> + =C2=A0fclose (f); >> +} >> + >> +/* Returns ignore status for the current function */ >> +static enum tsan_ignore_e >> +tsan_ignore (void) >> +{ >> + =C2=A0const char *func_name; >> + =C2=A0const char *src_name; >> + =C2=A0struct tsan_ignore_desc_t *desc; >> + >> + =C2=A0if (ignore_init =3D=3D 0) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0ignore_load (); >> + =C2=A0 =C2=A0 =C2=A0ignore_init =3D 1; >> + =C2=A0 =C2=A0} >> + >> + =C2=A0src_name =3D expand_location(cfun->function_start_locus).file; >> + =C2=A0if (src_name =3D=3D NULL) >> + =C2=A0 =C2=A0src_name =3D ""; >> + >> + =C2=A0func_name =3D IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (cfun->dec= l)); >> + =C2=A0/* Ignore all functions starting with __tsan_ - intended for tes= ting */ >> + =C2=A0if (strncmp (func_name, RTL_PERFIX, sizeof (RTL_PERFIX) - 1) =3D= =3D 0) >> + =C2=A0 =C2=A0return tsan_ignore_func; >> + >> + =C2=A0for (desc =3D ignore_head; desc; desc =3D desc->next) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0if (desc->type =3D=3D tsan_ignore_func) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (ignore_match (desc->name, src_na= me)) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return desc->type; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + =C2=A0 =C2=A0 =C2=A0else if (ignore_match (desc->name, func_name)) >> + =C2=A0 =C2=A0 =C2=A0 return desc->type; >> + =C2=A0 =C2=A0} >> + =C2=A0return tsan_ignore_none; >> +} >> + >> +static const char * >> +decl_name (tree decl) >> +{ >> + =C2=A0tree id; >> + =C2=A0const char *name; >> + >> + =C2=A0if (decl !=3D 0 && DECL_P (decl)) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0id =3D DECL_NAME (decl); >> + =C2=A0 =C2=A0 =C2=A0if (id !=3D NULL) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0name =3D IDENTIFIER_POINTER (id); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (name !=3D NULL) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return name; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + =C2=A0 =C2=A0} >> + =C2=A0return ""; >> +} >> + >> +/* Builds either (__tsan_shadow_stack +=3D 1) or (__tsan_shadow_stack -= =3D 1) expression >> + =C2=A0 depending on 'do_dec' parameter. =C2=A0Appends the result to se= q. =C2=A0*/ >> +static void >> +build_stack_op (gimple_seq *seq, bool do_dec) >> +{ >> + =C2=A0tree op_size; >> + =C2=A0double_int op_size_cst; >> + =C2=A0unsigned long long size_val; >> + =C2=A0unsigned long long size_valhi; >> + =C2=A0tree op_expr; >> + =C2=A0tree assign; >> + =C2=A0tree rtl_stack; >> + =C2=A0gimple_seq s; >> + >> + =C2=A0op_size =3D TYPE_SIZE (ptr_type_node); >> + =C2=A0op_size_cst =3D tree_to_double_int (op_size); >> + =C2=A0size_val =3D op_size_cst.low / BITS_PER_UNIT; >> + =C2=A0size_valhi =3D 0; >> + =C2=A0if (do_dec) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0size_val =3D -size_val; >> + =C2=A0 =C2=A0 =C2=A0size_valhi =3D -1; >> + =C2=A0 =C2=A0} >> + =C2=A0op_size =3D build_int_cst_wide (sizetype, size_val, size_valhi); >> + =C2=A0rtl_stack =3D shadow_stack_def (); >> + =C2=A0op_expr =3D build2 (POINTER_PLUS_EXPR, ptr_type_node, rtl_stack,= op_size); >> + =C2=A0assign =3D build2 (MODIFY_EXPR, ptr_type_node, rtl_stack, op_exp= r); >> + =C2=A0s =3D NULL; >> + =C2=A0force_gimple_operand (assign, &s, true, NULL_TREE); >> + =C2=A0gimple_seq_add_seq (seq, s); >> +} >> + >> +/* Builds either (__tsan_thread_ignore +=3D 1) or (__tsan_thread_ignore= -=3D 1) expression >> + =C2=A0 depending on op parameter. =C2=A0Stores the result in seq. =C2= =A0*/ >> +static void >> +build_rec_ignore_op (gimple_seq *seq, enum tree_code op) >> +{ >> + =C2=A0tree rec_expr; >> + =C2=A0gimple_seq rec_inc; >> + =C2=A0gimple rec_assign; >> + =C2=A0tree rtl_ignore; >> + >> + =C2=A0rtl_ignore =3D thread_ignore_def (); >> + =C2=A0rec_expr =3D build2 (op, integer_type_node, rtl_ignore, integer_= one_node); >> + =C2=A0rec_inc =3D NULL; >> + =C2=A0rec_expr =3D force_gimple_operand (rec_expr, &rec_inc, true, NUL= L_TREE); >> + =C2=A0rec_assign =3D gimple_build_assign (rtl_ignore, rec_expr); >> + =C2=A0gimple_seq_add_seq (seq, rec_inc); >> + =C2=A0gimple_seq_add_stmt (seq, rec_assign); >> +} >> + >> +/* Build the following gimple sequence: >> + =C2=A0 __tsan_shadow_stack [-1] =3D __builtin_return_address (0); >> + =C2=A0 Stores the result in seq. =C2=A0*/ >> +static void >> +build_stack_assign (gimple_seq *seq) >> +{ >> + =C2=A0tree pc_addr; >> + =C2=A0tree op_size; >> + =C2=A0tree op_expr; >> + =C2=A0tree stack_op; >> + =C2=A0tree assign; >> + =C2=A0tree rtl_retaddr; >> + >> + =C2=A0rtl_retaddr =3D implicit_built_in_decls [BUILT_IN_RETURN_ADDRESS= ]; >> + =C2=A0pc_addr =3D build_call_expr (rtl_retaddr, 1, integer_zero_node); >> + =C2=A0op_size =3D build_int_cst_wide (sizetype, -(POINTER_SIZE / BITS_= PER_UNIT), -1); >> + =C2=A0op_expr =3D build2 (POINTER_PLUS_EXPR, ptr_type_node, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0shadow_stack_def (), op_size); >> + =C2=A0stack_op =3D build1 (INDIRECT_REF, ptr_type_node, op_expr); >> + =C2=A0assign =3D build2 (MODIFY_EXPR, ptr_type_node, stack_op, pc_addr= ); >> + =C2=A0force_gimple_operand (assign, seq, true, NULL_TREE); >> +} >> + >> +/* Builds the following gimple sequence: >> + =C2=A0 __tsan_handle_mop (&expr, (is_sblock | (is_store << 1) | ((size= of (expr)-1) << 2) >> + =C2=A0 The result is stored in gseq. =C2=A0*/ >> +static void >> +instr_mop (tree expr, int is_store, int is_sblock, gimple_seq *gseq) >> +{ >> + =C2=A0tree addr_expr; >> + =C2=A0tree expr_type; >> + =C2=A0unsigned size; >> + =C2=A0unsigned flags; >> + =C2=A0tree flags_expr; >> + =C2=A0tree call_expr; >> + >> + =C2=A0gcc_assert (gseq !=3D 0 && *gseq =3D=3D 0); >> + =C2=A0gcc_assert (is_gimple_addressable (expr)); >> + >> + =C2=A0addr_expr =3D build_addr (expr, current_function_decl); >> + =C2=A0expr_type =3D TREE_TYPE (expr); >> + =C2=A0while (TREE_CODE (expr_type) =3D=3D ARRAY_TYPE) >> + =C2=A0 =C2=A0expr_type =3D TREE_TYPE (expr_type); >> + =C2=A0size =3D TREE_INT_CST_LOW (TYPE_SIZE (expr_type)); >> + =C2=A0size =3D size / BITS_PER_UNIT; >> + =C2=A0if (size > MAX_MOP_BYTES) >> + =C2=A0 =C2=A0size =3D MAX_MOP_BYTES; >> + =C2=A0size -=3D 1; >> + =C2=A0flags =3D ((!!is_sblock << 0) + (!!is_store << 1) + (size << 2)); >> + =C2=A0flags_expr =3D build_int_cst (unsigned_type_node, flags); >> + =C2=A0call_expr =3D build_call_expr (rtl_mop_def (), 2, addr_expr, fla= gs_expr); >> + =C2=A0force_gimple_operand (call_expr, gseq, true, 0); >> +} >> + >> +/* Builds the following gimple sequence: >> + =C2=A0 int is_store =3D (expr !=3D rhs); // the temp is not actually i= ntroduced >> + =C2=A0 __tsan_handle_mop (&expr, (is_sblock | (is_store << 1) | ((size= of (expr)-1) << 2) >> + =C2=A0 The result is stored in gseq. =C2=A0*/ >> +static void >> +instr_vptr_store (tree expr, tree rhs, int is_sblock, gimple_seq *gseq) >> +{ >> + =C2=A0tree expr_ptr; >> + =C2=A0tree addr_expr; >> + =C2=A0tree expr_type; >> + =C2=A0tree expr_size; >> + =C2=A0double_int size; >> + =C2=A0unsigned flags; >> + =C2=A0tree flags_expr; >> + =C2=A0gimple_seq flags_seq; >> + =C2=A0gimple collect; >> + =C2=A0tree is_store_expr; >> + >> + =C2=A0expr_ptr =3D build_addr (expr, current_function_decl); >> + =C2=A0addr_expr =3D force_gimple_operand (expr_ptr, gseq, true, NULL_T= REE); >> + =C2=A0expr_type =3D TREE_TYPE (expr); >> + =C2=A0while (TREE_CODE (expr_type) =3D=3D ARRAY_TYPE) >> + =C2=A0 =C2=A0expr_type =3D TREE_TYPE (expr_type); >> + =C2=A0expr_size =3D TYPE_SIZE (expr_type); >> + =C2=A0size =3D tree_to_double_int (expr_size); >> + =C2=A0gcc_assert (size.high =3D=3D 0 && size.low !=3D 0); >> + =C2=A0if (size.low > 128) >> + =C2=A0 =C2=A0size.low =3D 128; >> + =C2=A0size.low =3D (size.low / 8) - 1; >> + =C2=A0flags =3D ((!!is_sblock << 0) + (size.low << 2)); >> + =C2=A0flags_expr =3D build_int_cst (unsigned_type_node, flags); >> + =C2=A0is_store_expr =3D build2 (NE_EXPR, integer_type_node, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0build1 (VIEW_CONVERT_EXPR, size_type_node= , expr), >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0build1 (VIEW_CONVERT_EXPR, size_type_node= , rhs)); >> + =C2=A0is_store_expr =3D build2 (LSHIFT_EXPR, integer_type_node, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0is_store_expr, integer_one_node); >> + =C2=A0flags_expr =3D build2 (BIT_IOR_EXPR, integer_type_node, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0is_store_expr, flags_expr); >> + =C2=A0flags_seq =3D 0; >> + =C2=A0flags_expr =3D force_gimple_operand (flags_expr, &flags_seq, tru= e, NULL_TREE); >> + =C2=A0gimple_seq_add_seq (gseq, flags_seq); >> + =C2=A0collect =3D gimple_build_call ( >> + =C2=A0 =C2=A0 =C2=A0rtl_mop_def (), 2, addr_expr, flags_expr); >> + =C2=A0gimple_seq_add_stmt (gseq, collect); >> +} >> + >> +/* Builds gimple sequences that must be inserted at function entry (pre) >> + =C2=A0 and before function exit (post). =C2=A0*/ >> +static void >> +instr_func (gimple_seq *pre, gimple_seq *post) >> +{ >> + =C2=A0/* In this case we need no instrumentation for the function */ >> + =C2=A0if (func_calls =3D=3D 0 && func_mops =3D=3D 0) >> + =C2=A0 =C2=A0return; >> + >> + =C2=A0if (func_ignore !=3D tsan_ignore_rec) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0build_stack_assign (pre); >> + =C2=A0 =C2=A0 =C2=A0build_stack_op (pre, false); >> + =C2=A0 =C2=A0 =C2=A0build_stack_op (post, true); >> + =C2=A0 =C2=A0} >> + >> + =C2=A0if (func_ignore =3D=3D tsan_ignore_rec && func_calls !=3D 0) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0build_rec_ignore_op (pre, PLUS_EXPR); >> + =C2=A0 =C2=A0 =C2=A0build_rec_ignore_op (post, MINUS_EXPR); >> + =C2=A0 =C2=A0} >> +} >> + >> +/* Sets location for all gimples in the seq. =C2=A0*/ >> +static void >> +set_location (gimple_seq seq, location_t loc) >> +{ >> + =C2=A0gimple_seq_node n; >> + >> + =C2=A0for (n =3D gimple_seq_first (seq); n !=3D NULL; n =3D n->next) >> + =C2=A0 =C2=A0gimple_set_location (n->stmt, loc); >> +} >> + >> +/* Check as to whether expr refers to a store to vptr. =C2=A0*/ >> +static tree >> +is_dtor_vptr_store (gimple stmt, tree expr, int is_store) >> +{ >> + =C2=A0if (is_store =3D=3D 1 >> + =C2=A0 =C2=A0 =C2=A0&& TREE_CODE (expr) =3D=3D COMPONENT_REF >> + =C2=A0 =C2=A0 =C2=A0&& gimple_assign_single_p (stmt) >> + =C2=A0 =C2=A0 =C2=A0&& strcmp (decl_name (cfun->decl), "__base_dtor ")= =3D=3D 0) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0tree comp =3D expr->exp.operands [0]; >> + =C2=A0 =C2=A0 =C2=A0while (TREE_CODE (comp) =3D=3D COMPONENT_REF) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0comp =3D comp->exp.operands [0]; >> + =C2=A0 =C2=A0 =C2=A0if (TREE_CODE (comp) =3D=3D INDIRECT_REF || TREE_C= ODE (comp) =3D=3D MEM_REF) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0comp =3D comp->exp.operands [0]; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (TREE_CODE (comp) =3D=3D SSA_NAME) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0comp =3D SSA_NAME_VAR (comp); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (strcmp (decl_name (comp), "this"= ) =3D=3D 0) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tree field =3D expr->e= xp.operands [1]; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (TREE_CODE (field) = =3D=3D FIELD_DECL >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&& strnc= mp (decl_name (field), >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0"_vptr.", sizeof ("_vptr.") - 1) =3D=3D 0) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return gimple_a= ssign_rhs1 (stmt); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + =C2=A0 =C2=A0} >> + =C2=A0return 0; >> +} >> + >> +/* Checks as to whether expr refers to a read from vtlb. >> + =C2=A0 Vtlbs are immutable, so don't bother to instrument them. =C2=A0= */ >> +static int >> +is_vtbl_read (tree expr, int is_store) >> +{ >> + =C2=A0/* We may not instrument reads from vtbl, because the data is co= nstant. >> + =C2=A0 =C2=A0 vtbl read is of the form: >> + =C2=A0 =C2=A0 =C2=A0 gimple_assign _vptr.X,= NULL> >> + =C2=A0 =C2=A0 =C2=A0 gimple_assign >> + =C2=A0 =C2=A0 or: >> + =C2=A0 =C2=A0 =C2=A0 gimple_assign _vptr.X,= NULL> >> + =C2=A0 =C2=A0 =C2=A0 gimple_assign >> + =C2=A0 =C2=A0 =C2=A0 gimple_assign */ >> + >> + =C2=A0if (is_store =3D=3D 0 >> + =C2=A0 =C2=A0 =C2=A0&& TREE_CODE (expr) =3D=3D INDIRECT_REF) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0tree ref_target =3D expr->exp.operands [0]; >> + =C2=A0 =C2=A0 =C2=A0if (TREE_CODE (ref_target) =3D=3D SSA_NAME) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0gimple ref_stmt =3D ref_target->ssa_= name.def_stmt; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (gimple_code (ref_stmt) =3D=3D GI= MPLE_ASSIGN) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (gimple_expr_code (= ref_stmt) =3D=3D POINTER_PLUS_EXPR) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tree tmp= =3D ref_stmt->gsmem.op [1]; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (TREE= _CODE (tmp) =3D=3D SSA_NAME >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0&& gimple_code (tmp->ssa_name.def_stmt) =3D=3D GIMPLE_ASSIGN) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0r= ef_stmt =3D tmp->ssa_name.def_stmt; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (gimple_expr_code (= ref_stmt) =3D=3D COMPONENT_REF >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&= & gimple_assign_single_p (ref_stmt)) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tree com= p_expr =3D ref_stmt->gsmem.op [1]; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tree fie= ld_expr =3D comp_expr->exp.operands [1]; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (TREE= _CODE (field_expr) =3D=3D FIELD_DECL >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0&& strncmp (decl_name (field_expr), >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0"_vptr.", sizeof ("_vptr.")= - 1) =3D=3D 0) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0r= eturn 1; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + =C2=A0 =C2=A0} >> + >> + =C2=A0return 0; >> +} >> + >> +/* Checks as to whether expr refers to constant var/field/param. >> + =C2=A0 Don't bother to instrument them. =C2=A0*/ >> +static int >> +is_load_of_const (tree expr, int is_store) >> +{ >> + =C2=A0if (is_store =3D=3D 0) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0if (TREE_CODE (expr) =3D=3D COMPONENT_REF) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0expr =3D expr->exp.operands [1]; >> + =C2=A0 =C2=A0 =C2=A0if (TREE_CODE (expr) =3D=3D VAR_DECL >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0|| TREE_CODE (expr) =3D=3D PARM_DECL >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0|| TREE_CODE (expr) =3D=3D FIELD_DEC= L) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (TREE_READONLY (expr)) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return 1; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + =C2=A0 =C2=A0} >> + =C2=A0return 0; >> +} >> + >> +static void >> +handle_expr (gimple stmt, gimple_stmt_iterator gsi, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 tree expr, int is_store, VEC= (mop_desc_t, heap) **mop_list) >> +{ >> + =C2=A0enum tree_code tcode; >> + =C2=A0struct mop_desc_t mop; >> + =C2=A0unsigned fld_off; >> + =C2=A0unsigned fld_size; >> + >> + =C2=A0/* map SSA name to real name */ >> + =C2=A0if (TREE_CODE (expr) =3D=3D SSA_NAME) >> + =C2=A0 =C2=A0expr =3D SSA_NAME_VAR (expr); >> + >> + =C2=A0tcode =3D TREE_CODE (expr); >> + >> + =C2=A0/* Below are things we do NOT want to instrument. =C2=A0*/ >> + =C2=A0if (func_ignore & (tsan_ignore_mop | tsan_ignore_rec)) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0return; >> + =C2=A0 =C2=A0} >> + =C2=A0else if (TREE_CODE_CLASS (tcode) =3D=3D tcc_constant) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0/* various constant literals */ >> + =C2=A0 =C2=A0 =C2=A0return; >> + =C2=A0 =C2=A0} >> + =C2=A0else if (TREE_CODE_CLASS (tcode) =3D=3D tcc_declaration >> + =C2=A0 =C2=A0 =C2=A0&& DECL_ARTIFICIAL (expr)) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0/* compiler-emitted artificial variables */ >> + =C2=A0 =C2=A0 =C2=A0return; >> + =C2=A0 =C2=A0} >> + =C2=A0if (tcode =3D=3D RESULT_DECL) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0/* store to function result */ >> + =C2=A0 =C2=A0 =C2=A0return; >> + =C2=A0 =C2=A0} >> + =C2=A0else if (tcode =3D=3D VAR_DECL >> + =C2=A0 =C2=A0 =C2=A0&& TREE_ADDRESSABLE (expr) =3D=3D 0 >> + =C2=A0 =C2=A0 =C2=A0&& TREE_STATIC (expr) =3D=3D 0) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0/* the var does not live in memory -> no possibili= ty of races */ >> + =C2=A0 =C2=A0 =C2=A0return; >> + =C2=A0 =C2=A0} >> + =C2=A0else if (TREE_CODE (TREE_TYPE (expr)) =3D=3D RECORD_TYPE) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0/* TODO (dvyukov): implement me */ >> + =C2=A0 =C2=A0 =C2=A0return; >> + =C2=A0 =C2=A0} >> + =C2=A0else if (tcode =3D=3D CONSTRUCTOR) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0/* TODO (dvyukov): implement me */ >> + =C2=A0 =C2=A0 =C2=A0return; >> + =C2=A0 =C2=A0} >> + =C2=A0else if (tcode =3D=3D PARM_DECL) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0/* TODO (dvyukov): implement me */ >> + =C2=A0 =C2=A0 =C2=A0return; >> + =C2=A0 =C2=A0} >> + =C2=A0else if (is_load_of_const (expr, is_store)) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0/* load of a const variable/parameter/field */ >> + =C2=A0 =C2=A0 =C2=A0return; >> + =C2=A0 =C2=A0} >> + =C2=A0else if (is_vtbl_read (expr, is_store)) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0/* vtbl read */ >> + =C2=A0 =C2=A0 =C2=A0return; >> + =C2=A0 =C2=A0} >> + =C2=A0else if (tcode =3D=3D COMPONENT_REF) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0tree field =3D expr->exp.operands [1]; >> + =C2=A0 =C2=A0 =C2=A0if (TREE_CODE (field) =3D=3D FIELD_DECL) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0fld_off =3D field->field_decl.bit_of= fset->int_cst.int_cst.low; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0fld_size =3D field->decl_common.size= ->int_cst.int_cst.low; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (((fld_off % BITS_PER_UNIT) !=3D = 0) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0|| ((fld_size % BITS_P= ER_UNIT) !=3D 0)) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* As of now it crashe= s compilation. >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 TODO (dvyukov)= : handle bit-fields as if touching the whole field */ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + =C2=A0 =C2=A0} >> + >> + =C2=A0/* TODO (dvyukov): handle other cases >> + =C2=A0 =C2=A0 (FIELD_DECL, MEM_REF, ARRAY_RANGE_REF, TARGET_MEM_REF, A= DDR_EXPR) */ >> + =C2=A0if (tcode !=3D ARRAY_REF >> + =C2=A0 =C2=A0 =C2=A0&& tcode !=3D VAR_DECL >> + =C2=A0 =C2=A0 =C2=A0&& tcode !=3D COMPONENT_REF >> + =C2=A0 =C2=A0 =C2=A0&& tcode !=3D INDIRECT_REF >> + =C2=A0 =C2=A0 =C2=A0&& tcode !=3D MEM_REF) >> + =C2=A0 =C2=A0return; >> + >> + =C2=A0mop.is_call =3D 0; >> + =C2=A0mop.gsi =3D gsi; >> + =C2=A0mop.expr =3D expr; >> + =C2=A0mop.dtor_vptr_expr =3D is_dtor_vptr_store (stmt, expr, is_store); >> + =C2=A0mop.is_store =3D is_store; >> + =C2=A0VEC_safe_push (mop_desc_t, heap, *mop_list, &mop); >> +} >> + >> +static void >> +handle_gimple (gimple_stmt_iterator gsi, VEC (mop_desc_t, heap) **mop_l= ist) >> +{ >> + =C2=A0unsigned i; >> + =C2=A0struct mop_desc_t mop; >> + =C2=A0gimple stmt; >> + =C2=A0enum gimple_code gcode; >> + =C2=A0location_t loc; >> + =C2=A0tree rhs; >> + =C2=A0tree lhs; >> + >> + =C2=A0stmt =3D gsi_stmt (gsi); >> + =C2=A0gcode =3D gimple_code (stmt); >> + =C2=A0if (gcode >=3D LAST_AND_UNUSED_GIMPLE_CODE) >> + =C2=A0 =C2=A0return; >> + >> + =C2=A0loc =3D gimple_location (stmt); >> + >> + =C2=A0switch (gcode) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0/* TODO (dvyukov): handle GIMPLE_COND (can it acce= ss memmory?) */ >> + =C2=A0 =C2=A0 =C2=A0case GIMPLE_CALL: >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0func_calls +=3D 1; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* Handle call arguments as loads */ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0for (i =3D 0; i < gimple_call_num_ar= gs (stmt); i++) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0rhs =3D gimple_call_ar= g (stmt, i); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0handle_expr (stmt, gsi= , rhs, 0, mop_list); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0memset (&mop, 0, sizeof (mop)); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0mop.is_call =3D 1; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0VEC_safe_push (mop_desc_t, heap, *mo= p_list, &mop); >> + >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* Handle assignment lhs as store */ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0lhs =3D gimple_call_lhs (stmt); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (lhs !=3D 0) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0handle_expr (stmt, gsi, lhs, = 1, mop_list); >> + >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + >> + =C2=A0 =C2=A0 =C2=A0case GIMPLE_ASSIGN: >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* Handle assignment lhs as store */ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0lhs =3D gimple_assign_lhs (stmt); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0handle_expr (stmt, gsi, lhs, 1, mop_= list); >> + >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* Handle operands as loads */ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0for (i =3D 1; i < gimple_num_ops (st= mt); i++) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0rhs =3D gimple_op (stm= t, i); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0handle_expr (stmt, gsi= , rhs, 0, mop_list); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + >> + =C2=A0 =C2=A0 =C2=A0case GIMPLE_BIND: >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0gcc_assert (!"there should be no GIM= PLE_BIND on this level"); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + >> + =C2=A0 =C2=A0 =C2=A0default: >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0break; >> + =C2=A0 =C2=A0} >> +} >> + >> +/* Instruments single basic block. =C2=A0*/ >> +static void >> +instrument_bblock (struct bb_data_t *bbd, basic_block bb) >> +{ >> + =C2=A0int ix; >> + =C2=A0int is_sblock; >> + =C2=A0gimple_stmt_iterator gsi; >> + =C2=A0struct mop_desc_t *mop; >> + =C2=A0gimple stmt; >> + =C2=A0location_t loc; >> + =C2=A0expanded_location eloc; >> + =C2=A0gimple_seq instr_seq; >> + >> + =C2=A0/* Iterate over all gimples and collect interesting mops into mo= p_list. =C2=A0*/ >> + =C2=A0VEC_free (mop_desc_t, heap, mop_list); >> + =C2=A0for (gsi =3D gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi= )) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0handle_gimple (gsi, &mop_list); >> + =C2=A0 =C2=A0} >> + >> + =C2=A0mop =3D 0; >> + =C2=A0for (ix =3D 0; VEC_iterate (mop_desc_t, mop_list, ix, mop); ix += =3D 1) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0if (mop->is_call !=3D 0) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* After a function call we must sta= rt a brand new sblock, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 because the function can con= tain synchronization. =C2=A0*/ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bbd->has_sb =3D 0; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0continue; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + >> + =C2=A0 =C2=A0 =C2=A0func_mops +=3D 1; >> + =C2=A0 =C2=A0 =C2=A0stmt =3D gsi_stmt (mop->gsi); >> + =C2=A0 =C2=A0 =C2=A0loc =3D gimple_location (stmt); >> + =C2=A0 =C2=A0 =C2=A0eloc =3D expand_location (loc); >> + >> + =C2=A0 =C2=A0 =C2=A0/* Check as to whether we may not set sblock flag >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 for the access */ >> + =C2=A0 =C2=A0 =C2=A0is_sblock =3D (bbd->has_sb =3D=3D 0 >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0|| !(eloc.file !=3D 0 >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&& bbd->sb_file !=3D 0 >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&& strcmp (eloc.file, = bbd->sb_file) =3D=3D 0 >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&& eloc.line >=3D bbd-= >sb_line_min >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&& eloc.line <=3D bbd-= >sb_line_max)); >> + >> + =C2=A0 =C2=A0 =C2=A0if (func_ignore =3D=3D tsan_ignore_hist) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0is_sblock =3D 0; >> + >> + =C2=A0 =C2=A0 =C2=A0if (is_sblock) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* Start new sblock with new source = info. =C2=A0*/ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bbd->has_sb =3D 1; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bbd->sb_file =3D eloc.file; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bbd->sb_line_min =3D eloc.line; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bbd->sb_line_max =3D eloc.line + SBL= OCK_SIZE; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + >> + =C2=A0 =C2=A0 =C2=A0instr_seq =3D 0; >> + =C2=A0 =C2=A0 =C2=A0if (mop->dtor_vptr_expr =3D=3D 0) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0instr_mop (mop->expr, mop->is_store, is_sbl= ock, &instr_seq); >> + =C2=A0 =C2=A0 =C2=A0else >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0instr_vptr_store (mop->expr, mop->dtor_vptr= _expr, is_sblock, &instr_seq); >> + =C2=A0 =C2=A0 =C2=A0gcc_assert (instr_seq !=3D 0); >> + =C2=A0 =C2=A0 =C2=A0set_location (instr_seq, loc); >> + =C2=A0 =C2=A0 =C2=A0/* Instrumentation for assignment of a function re= sult >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 must be inserted after the call. =C2=A0Ins= trumentation for >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 reads of function arguments must be insert= ed before the call. >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 That's because the call can contain synchr= onization. =C2=A0*/ >> + =C2=A0 =C2=A0 =C2=A0if (is_gimple_call (stmt) && mop->is_store =3D=3D = 1) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0gsi_insert_seq_after (&mop->gsi, instr_seq,= GSI_NEW_STMT); >> + =C2=A0 =C2=A0 =C2=A0else >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0gsi_insert_seq_before (&mop->gsi, instr_seq= , GSI_SAME_STMT); >> + =C2=A0 =C2=A0} >> +} >> + >> +/* Instruments all interesting memory accesses in the function */ >> +static void >> +instrument_mops (void) >> +{ >> + =C2=A0int sb_line_min; >> + =C2=A0int sb_line_max; >> + =C2=A0int bb_cnt; >> + =C2=A0int eidx; >> + =C2=A0basic_block bb; >> + =C2=A0basic_block entry_bb; >> + =C2=A0basic_block cur_bb; >> + =C2=A0basic_block any_bb; >> + =C2=A0struct bb_data_t *pred; >> + =C2=A0struct bb_data_t *succ; >> + =C2=A0struct bb_data_t *bb_data; >> + =C2=A0struct bb_data_t *bbd; >> + =C2=A0edge entry_edge; >> + =C2=A0edge e; >> + >> + =C2=A0/* The function does breadth-first traversal of CFG. >> + =C2=A0 =C2=A0 BB is visited preferably if all its predecessors are vis= ited. >> + =C2=A0 =C2=A0 Such order is required to properly mark super-blocks. >> + =C2=A0 =C2=A0 The idea behind super-blocks is as follows. >> + =C2=A0 =C2=A0 If several memory accesses happen within SBLOCK_SIZE sou= rce code lines >> + =C2=A0 =C2=A0 from each other, then we only mark the first access as S= BLOCK. >> + =C2=A0 =C2=A0 This allows runtime library to memorize stack trace >> + =C2=A0 =C2=A0 only for the first access and do not memorize for others. >> + =C2=A0 =C2=A0 This significantly reduces memory consumption in exchang= e for slightly >> + =C2=A0 =C2=A0 imprecise stack traces for previous accesses. =C2=A0*/ >> + >> + =C2=A0/* First, mark all blocks as not visited, and entry block as can= didate. =C2=A0*/ >> + =C2=A0bb_cnt =3D cfun->cfg->x_n_basic_blocks; >> + =C2=A0bb_data =3D (struct bb_data_t*) xcalloc (bb_cnt, sizeof (struct = bb_data_t)); >> + =C2=A0entry_bb =3D ENTRY_BLOCK_PTR; >> + =C2=A0entry_edge =3D single_succ_edge (entry_bb); >> + =C2=A0entry_bb =3D entry_edge->dest; >> + =C2=A0bb =3D 0; >> + =C2=A0FOR_EACH_BB (bb) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0bb_data [bb->index].state =3D (bb =3D=3D entry_bb)= ? bb_candidate : bb_not_visited; >> + =C2=A0 =C2=A0} >> + >> + =C2=A0/* Until all blocks are visited. =C2=A0*/ >> + =C2=A0for (; ; ) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0cur_bb =3D 0; >> + =C2=A0 =C2=A0 =C2=A0any_bb =3D 0; >> + =C2=A0 =C2=A0 =C2=A0/* Look for a candidate with all visited predecess= ors. =C2=A0*/ >> + =C2=A0 =C2=A0 =C2=A0FOR_EACH_BB (bb) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bbd =3D &bb_data [bb->index]; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (bbd->state =3D=3D bb_candidate) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cur_bb =3D bb; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0any_bb =3D bb; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0e =3D 0; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0for (eidx =3D 0; VEC_i= terate (edge, bb->preds, eidx, e); eidx++) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0pred =3D= &bb_data [e->src->index]; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (pred= ->state !=3D bb_visited) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0cur_bb =3D 0; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0break; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (cur_bb !=3D 0) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + =C2=A0 =C2=A0 =C2=A0/* All blocks are visited. =C2=A0*/ >> + =C2=A0 =C2=A0 =C2=A0if (any_bb =3D=3D 0) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0break; >> + =C2=A0 =C2=A0 =C2=A0/* If no blocks with all visited predecessors, cho= ose any candidate. >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 Must be a loop. =C2=A0*/ >> + =C2=A0 =C2=A0 =C2=A0cur_bb =3D cur_bb ? cur_bb : any_bb; >> + =C2=A0 =C2=A0 =C2=A0bbd =3D &bb_data [cur_bb->index]; >> + =C2=A0 =C2=A0 =C2=A0gcc_assert (bbd->state =3D=3D bb_candidate); >> + =C2=A0 =C2=A0 =C2=A0bbd->state =3D bb_visited; >> + >> + =C2=A0 =C2=A0 =C2=A0/* Iterate over all predecessors and merge their s= block info. =C2=A0*/ >> + =C2=A0 =C2=A0 =C2=A0e =3D 0; >> + =C2=A0 =C2=A0 =C2=A0for (eidx =3D 0; VEC_iterate (edge, cur_bb->preds,= eidx, e); eidx++) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0pred =3D &bb_data [e->src->index]; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if ((pred->state !=3D bb_visited) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0|| (pred->has_sb =3D= =3D 0) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0|| (pred =3D=3D bbd)) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* If there is a not v= isited predecessor, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 or a predecess= or with no active sblock info, >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 or a self-loop= , then we will have to start >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 a brand new sb= lock on next memory access. =C2=A0*/ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bbd->has_sb =3D 0; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0else if (bbd->has_sb =3D=3D 0) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* If it's a first pre= decessor, just copy the info. =C2=A0*/ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bbd->has_sb =3D 1; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bbd->sb_file =3D pred-= >sb_file; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bbd->sb_line_min =3D p= red->sb_line_min; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bbd->sb_line_max =3D p= red->sb_line_max; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0else >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* Otherwise, find the= interception >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 between two sb= lock descriptors. =C2=A0*/ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bbd->has_sb =3D 0; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (bbd->sb_file !=3D = 0 && pred->sb_file !=3D 0 >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&& strcm= p (bbd->sb_file, pred->sb_file) =3D=3D 0) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sb_line_= min =3D MAX (bbd->sb_line_min, pred->sb_line_min); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sb_line_= max =3D MIN (bbd->sb_line_max, pred->sb_line_max); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (sb_l= ine_min <=3D sb_line_max) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0bbd->has_sb =3D 1; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0bbd->sb_line_min =3D sb_line_min; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0bbd->sb_line_max =3D sb_line_max; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* No interception, ha= ve to start new sblock. =C2=A0*/ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (bbd->has_sb =3D=3D= 0) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + >> + =C2=A0 =C2=A0 =C2=A0/* Finally, instrument the block. =C2=A0*/ >> + =C2=A0 =C2=A0 =C2=A0instrument_bblock (bbd, cur_bb); >> + >> + =C2=A0 =C2=A0 =C2=A0/* Mark all successors as candidates. =C2=A0*/ >> + =C2=A0 =C2=A0 =C2=A0for (eidx =3D 0; VEC_iterate (edge, cur_bb->succs,= eidx, e); eidx++) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0succ =3D &bb_data [e->dest->index]; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (succ->state =3D=3D bb_not_visite= d) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0succ->state =3D bb_candidate; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + =C2=A0 =C2=A0} >> +} >> + >> +/* Instruments function entry and exit, if necessary. =C2=A0*/ >> +static void >> +instrument_function (void) >> +{ >> + =C2=A0location_t loc; >> + =C2=A0gimple_seq pre_func_seq; >> + =C2=A0gimple_seq post_func_seq; >> + =C2=A0basic_block entry_bb; >> + =C2=A0basic_block first_bb; >> + =C2=A0basic_block bb; >> + =C2=A0edge entry_edge; >> + =C2=A0gimple_stmt_iterator first_gsi; >> + =C2=A0gimple_stmt_iterator gsi; >> + =C2=A0gimple_stmt_iterator gsi2; >> + =C2=A0gimple first_stmt; >> + =C2=A0gimple stmt; >> + >> + =C2=A0pre_func_seq =3D 0; >> + =C2=A0post_func_seq =3D 0; >> + =C2=A0instr_func (&pre_func_seq, &post_func_seq); >> + >> + =C2=A0if (pre_func_seq !=3D 0) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0/* Insert new BB before the first BB. =C2=A0*/ >> + =C2=A0 =C2=A0 =C2=A0entry_bb =3D ENTRY_BLOCK_PTR; >> + =C2=A0 =C2=A0 =C2=A0entry_edge =3D single_succ_edge (entry_bb); >> + =C2=A0 =C2=A0 =C2=A0first_bb =3D entry_edge->dest; >> + =C2=A0 =C2=A0 =C2=A0first_gsi =3D gsi_start_bb (first_bb); >> + =C2=A0 =C2=A0 =C2=A0if (!gsi_end_p (first_gsi)) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0first_stmt =3D gsi_stmt (first_gsi); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0loc =3D gimple_location (first_stmt); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0set_location (pre_func_seq, loc); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + =C2=A0 =C2=A0 =C2=A0entry_bb =3D split_edge (entry_edge); >> + =C2=A0 =C2=A0 =C2=A0gsi =3D gsi_start_bb (entry_bb); >> + =C2=A0 =C2=A0 =C2=A0gsi_insert_seq_after (&gsi, pre_func_seq, GSI_NEW_= STMT); >> + =C2=A0 =C2=A0} >> + >> + =C2=A0if (post_func_seq !=3D 0) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0/* Find all function exits. =C2=A0*/ >> + =C2=A0 =C2=A0 =C2=A0FOR_EACH_BB (bb) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0gsi2 =3D gsi_start_bb (bb); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0for (; ; ) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0gsi =3D gsi2; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (gsi_end_p (gsi)) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0gsi_next (&gsi2); >> + >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0stmt =3D gsi_stmt (gsi= ); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0loc =3D gimple_locatio= n (stmt); >> + >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (gimple_code (stmt)= =3D=3D GIMPLE_RETURN) >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0set_loca= tion (post_func_seq, loc); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0gsi_inse= rt_seq_before (&gsi, post_func_seq, GSI_SAME_STMT); >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + =C2=A0 =C2=A0 =C2=A0 =C2=A0} >> + =C2=A0 =C2=A0} >> +} >> + >> +static unsigned >> +tsan_pass (void) >> +{ >> + =C2=A0if (errorcount !=3D 0 || sorrycount !=3D 0) >> + =C2=A0 =C2=A0return 0; >> + >> + =C2=A0func_ignore =3D tsan_ignore (); >> + =C2=A0if (func_ignore =3D=3D tsan_ignore_func) >> + =C2=A0 =C2=A0return 0; >> + >> + =C2=A0func_calls =3D 0; >> + =C2=A0func_mops =3D 0; >> + >> + =C2=A0instrument_mops (); >> + =C2=A0instrument_function (); >> + >> + =C2=A0return 0; >> +} >> + >> +static bool >> +tsan_gate (void) >> +{ >> + =C2=A0return flag_tsan !=3D 0; >> +} >> + >> +struct gimple_opt_pass pass_tsan =3D {{ >> + =C2=A0GIMPLE_PASS, >> + =C2=A0"tsan", =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 /* name */ >> + =C2=A0tsan_gate, =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* gate */ >> + =C2=A0tsan_pass, =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* execute */ >> + =C2=A0NULL, =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 /* sub */ >> + =C2=A0NULL, =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 /* next */ >> + =C2=A00, =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* static= _pass_number */ >> + =C2=A0TV_NONE, =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* tv_id */ >> + =C2=A0PROP_trees | PROP_cfg, =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0/* properties_required */ >> + =C2=A00, =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* proper= ties_provided */ >> + =C2=A00, =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* proper= ties_destroyed */ >> + =C2=A00, =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* todo_f= lags_start */ >> + =C2=A0TODO_dump_cgraph | TODO_dump_func | TODO_verify_all >> + =C2=A0 =C2=A0| TODO_update_ssa | TODO_update_address_taken /* todo_fla= gs_finish */ >> +}}; >> + >> >> Property changes on: gcc/tree-tsan.c >> ___________________________________________________________________ >> Added: svn:eol-style >> =C2=A0 + LF >> >> Index: gcc/tree-pass.h >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> --- gcc/tree-pass.h =C2=A0 =C2=A0 (revision 180522) >> +++ gcc/tree-pass.h =C2=A0 =C2=A0 (working copy) >> @@ -352,6 +352,7 @@ >> >> =C2=A0extern struct gimple_opt_pass pass_mudflap_1; >> =C2=A0extern struct gimple_opt_pass pass_mudflap_2; >> +extern struct gimple_opt_pass pass_tsan; >> =C2=A0extern struct gimple_opt_pass pass_lower_cf; >> =C2=A0extern struct gimple_opt_pass pass_refactor_eh; >> =C2=A0extern struct gimple_opt_pass pass_lower_eh; >> Index: gcc/testsuite/gcc.dg/tsan-ignore.ignore >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> --- gcc/testsuite/gcc.dg/tsan-ignore.ignore =C2=A0 =C2=A0 (revision 0) >> +++ gcc/testsuite/gcc.dg/tsan-ignore.ignore =C2=A0 =C2=A0 (revision 0) >> @@ -0,0 +1,7 @@ >> +#comment >> +fun:foo >> +fun:*bar >> +fun:baz* >> +fun:*bla* >> +fun:x*x >> +src:tsan-ignore.h >> Index: gcc/testsuite/gcc.dg/tsan.h >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> --- gcc/testsuite/gcc.dg/tsan.h (revision 0) >> +++ gcc/testsuite/gcc.dg/tsan.h (revision 0) >> @@ -0,0 +1,87 @@ >> +/* Helper declarations and functions for ThreadSanitizer instrumentatio= n (-ftsan) testing */ >> + >> +int printf (char *str, ...); >> +void exit (int); >> + >> +/* Variables referenced by the instrumentation */ >> +__thread void **__tsan_shadow_stack; >> +__thread int __tsan_thread_ignore; >> + >> +/* Local helper vars */ >> +__thread void *shadow_stack[1024]; >> +__thread int mop_expect; >> +__thread int mop_depth; >> +__thread void* mop_addr; >> +__thread unsigned long long mop_pc; >> +__thread unsigned mop_flags; >> + >> +/* Setups shadow stack var (not instrumented) */ >> +void __attribute__ ((constructor)) >> +__tsan_init (void) >> +{ >> + =C2=A0__tsan_shadow_stack =3D shadow_stack; >> +} >> + >> +/* Declare that we expect an instrumented memory access (not instrument= ed). >> + =C2=A0 depth - stack depth of the mop (0 - main, 1 - func called from = main and so on). >> + =C2=A0 addr - memory access address. >> + =C2=A0 is_store - store/load. >> + =C2=A0 is_sblock - superblock flag of the access. >> + =C2=A0 size - memory access size in bytes. */ >> +void >> +__tsan_expect_mop (int depth, void *addr, int is_store, int is_sblock, = int size) >> +{ >> + =C2=A0if (mop_expect) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0printf ("missed mop: addr=3D%p pc=3D%d\n", mop_add= r, mop_pc); >> + =C2=A0 =C2=A0 =C2=A0exit (1); >> + =C2=A0 =C2=A0} >> + >> + =C2=A0mop_expect =3D 1; >> + =C2=A0mop_depth =3D depth; >> + =C2=A0mop_addr =3D addr; >> + =C2=A0mop_pc =3D (unsigned long long)__builtin_return_address(0); >> + =C2=A0mop_flags =3D !!is_sblock | (!!is_store << 1) | ((size - 1) << 2= ); >> +} >> + >> +/* Memory access function (referenced by instrumentation, not instrumen= ted). */ >> +void >> +__tsan_handle_mop (void *addr, unsigned flags) >> +{ >> + =C2=A0unsigned long long pc; >> + =C2=A0int depth; >> + >> + =C2=A0printf ("mop: addr=3D%p flags=3D%x called from %p/%p\n", addr, f= lags, __builtin_return_address(1), __tsan_shadow_stack[-2]); >> + =C2=A0if (mop_expect =3D=3D 0) >> + =C2=A0 =C2=A0return; >> + >> + =C2=A0/* Verify parameters with what we expect. */ >> + >> + =C2=A0if (addr !=3D mop_addr) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0printf ("incorrect mop addr: %p/%p\n", addr, =C2= =A0mop_addr); >> + =C2=A0 =C2=A0 =C2=A0exit (1); >> + =C2=A0 =C2=A0} >> + >> + =C2=A0pc =3D (unsigned long long)__builtin_return_address(0); >> + =C2=A0if (pc < mop_pc - 100 || pc > mop_pc + 100) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0printf ("incorrect mop pc: %p/%p\n", (void*)pc, (v= oid*)mop_pc); >> + =C2=A0 =C2=A0 =C2=A0exit (1); >> + =C2=A0 =C2=A0} >> + >> + =C2=A0depth =3D __tsan_shadow_stack - shadow_stack - 1; >> + =C2=A0if (depth !=3D mop_depth) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0printf ("incorrect mop depth: %d/%d\n", depth, mop= _depth); >> + =C2=A0 =C2=A0 =C2=A0exit (1); >> + =C2=A0 =C2=A0} >> + >> + =C2=A0if (flags !=3D mop_flags) >> + =C2=A0 =C2=A0{ >> + =C2=A0 =C2=A0 =C2=A0printf ("incorrect mop flags: %x/%x\n", flags, mop= _flags); >> + =C2=A0 =C2=A0 =C2=A0exit (1); >> + =C2=A0 =C2=A0} >> + >> + =C2=A0mop_expect =3D 0; >> +} >> >> Property changes on: gcc/testsuite/gcc.dg/tsan.h >> ___________________________________________________________________ >> Added: svn:eol-style >> =C2=A0 + LF >> >> Index: gcc/testsuite/gcc.dg/tsan-ignore.c >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> --- gcc/testsuite/gcc.dg/tsan-ignore.c =C2=A0(revision 0) >> +++ gcc/testsuite/gcc.dg/tsan-ignore.c =C2=A0(revision 0) >> @@ -0,0 +1,49 @@ >> +/* { dg-do run } */ >> +/* { dg-options "-ftsan -ftsan-ignore=3Dtsan-ignore.ignore" } */ >> +#include "tsan.h" >> +#include "tsan-ignore.h" >> + >> +/* Check ignore file handling. */ >> + >> +int >> +foo (int *p) >> +{ >> + =C2=A0p [0] =3D 1; >> +} >> + >> +int bar (int *p) >> +{ >> + =C2=A0p [0] =3D 1; >> +} >> + >> +int baz (int *p) >> +{ >> + =C2=A0p [0] =3D 1; >> +} >> + >> +int bla (int *p) >> +{ >> + =C2=A0p [0] =3D 1; >> +} >> + >> +int xxx (int *p) >> +{ >> + =C2=A0p [0] =3D 1; >> +} >> + >> +int >> +main (void) >> +{ >> + =C2=A0int p, x; >> + >> + =C2=A0__tsan_expect_mop(0, &p, 1, 1, sizeof(p)); >> + =C2=A0/* All these functions must be ignored. */ >> + =C2=A0foo (&x); >> + =C2=A0bar (&x); >> + =C2=A0baz (&x); >> + =C2=A0bla (&x); >> + =C2=A0xxx (&x); >> + =C2=A0in_tsan_ignore_header (&x); >> + =C2=A0p =3D 0; >> + =C2=A0return 0; >> +} >> >> Property changes on: gcc/testsuite/gcc.dg/tsan-ignore.c >> ___________________________________________________________________ >> Added: svn:eol-style >> =C2=A0 + LF >> >> Index: gcc/testsuite/gcc.dg/tsan-ignore.h >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> --- gcc/testsuite/gcc.dg/tsan-ignore.h =C2=A0(revision 0) >> +++ gcc/testsuite/gcc.dg/tsan-ignore.h =C2=A0(revision 0) >> @@ -0,0 +1,5 @@ >> +int >> +in_tsan_ignore_header (int *p) >> +{ >> + =C2=A0p [0] =3D 1; >> +} >> >> Property changes on: gcc/testsuite/gcc.dg/tsan-ignore.h >> ___________________________________________________________________ >> Added: svn:eol-style >> =C2=A0 + LF >> >> Index: gcc/testsuite/gcc.dg/tsan-stack.c >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> --- gcc/testsuite/gcc.dg/tsan-stack.c =C2=A0 (revision 0) >> +++ gcc/testsuite/gcc.dg/tsan-stack.c =C2=A0 (revision 0) >> @@ -0,0 +1,23 @@ >> +/* { dg-do run } */ >> +/* { dg-options "-ftsan" } */ >> +#include "tsan.h" >> + >> +/* Check shadow stack maintance. */ >> + >> +int >> +foobar (int *p) >> +{ >> + =C2=A0__tsan_expect_mop(1, p, 1, 1, sizeof(*p)); >> + =C2=A0p[0] =3D 1; >> +} >> + >> +int >> +main (void) >> +{ >> + =C2=A0int p; >> + >> + =C2=A0__tsan_expect_mop(0, &p, 1, 1, sizeof(p)); >> + =C2=A0p =3D 0; >> + =C2=A0foobar (&p); >> + =C2=A0return 0; >> +} >> >> Property changes on: gcc/testsuite/gcc.dg/tsan-stack.c >> ___________________________________________________________________ >> Added: svn:eol-style >> =C2=A0 + LF >> >> Index: gcc/testsuite/gcc.dg/tsan-mop.c >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> --- gcc/testsuite/gcc.dg/tsan-mop.c =C2=A0 =C2=A0 (revision 0) >> +++ gcc/testsuite/gcc.dg/tsan-mop.c =C2=A0 =C2=A0 (revision 0) >> @@ -0,0 +1,29 @@ >> +/* { dg-do run } */ >> +/* { dg-options "-ftsan" } */ >> +#include "tsan.h" >> + >> +/* Sanity check for memory accesses instrumentation. */ >> + >> +int >> +foobar (int *p) >> +{ >> + =C2=A0__tsan_expect_mop(1, p, 1, 1, sizeof(*p)); >> + =C2=A0p[0] =3D 1; >> + >> + =C2=A0__tsan_expect_mop(1, p, 1, 1, sizeof(*p)); >> + =C2=A0*p =3D 2; >> + >> + =C2=A0__tsan_expect_mop(1, (char*)p+3, 1, 1, 1); >> + =C2=A0*((char*)p+3) =3D 3; >> +} >> + >> +int >> +main (void) >> +{ >> + =C2=A0int p; >> + >> + =C2=A0__tsan_expect_mop(0, &p, 1, 1, sizeof(p)); >> + =C2=A0p =3D 0; >> + =C2=A0foobar (&p); >> + =C2=A0return 0; >> +} >> >> Property changes on: gcc/testsuite/gcc.dg/tsan-mop.c >> ___________________________________________________________________ >> Added: svn:eol-style >> =C2=A0 + LF >> >> Index: gcc/common.opt >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> --- gcc/common.opt =C2=A0 =C2=A0 =C2=A0(revision 180522) >> +++ gcc/common.opt =C2=A0 =C2=A0 =C2=A0(working copy) >> @@ -1547,6 +1547,14 @@ >> =C2=A0Common RejectNegative Report Var(flag_mudflap_ignore_reads) >> =C2=A0Ignore read operations when inserting mudflap instrumentation >> >> +ftsan >> +Common RejectNegative Report Var(flag_tsan) >> +Add ThreadSanitizer instrumentation >> + >> +ftsan-ignore=3D >> +Common RejectNegative Joined Var(flag_tsan_ignore) >> +-ftsan-ignore=3Dfilename ThreadSanitizer ignore file >> + >> =C2=A0fdce >> =C2=A0Common Var(flag_dce) Init(1) Optimization >> =C2=A0Use the RTL dead code elimination pass >> Index: gcc/Makefile.in >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> --- gcc/Makefile.in =C2=A0 =C2=A0 (revision 180522) >> +++ gcc/Makefile.in =C2=A0 =C2=A0 (working copy) >> @@ -1494,6 +1494,7 @@ >> =C2=A0 =C2=A0 =C2=A0 =C2=A0tree-streamer-out.o \ >> =C2=A0 =C2=A0 =C2=A0 =C2=A0tree-tailcall.o \ >> =C2=A0 =C2=A0 =C2=A0 =C2=A0tree-threadsafe-analyze.o \ >> + =C2=A0 =C2=A0 =C2=A0 tree-tsan.o \ >> =C2=A0 =C2=A0 =C2=A0 =C2=A0tree-vect-generic.o \ >> =C2=A0 =C2=A0 =C2=A0 =C2=A0tree-vect-patterns.o \ >> =C2=A0 =C2=A0 =C2=A0 =C2=A0tree-vect-data-refs.o \ >> @@ -2814,6 +2815,12 @@ >> =C2=A0 =C2=A0$(C_TREE_H) $(C_COMMON_H) $(GIMPLE_H) $(DIAGNOSTIC_H) $(HAS= HTAB_H) \ >> =C2=A0 =C2=A0output.h langhooks.h tree-mudflap.h $(TM_H) coretypes.h \ >> =C2=A0 =C2=A0$(GGC_H) gt-tree-mudflap.h $(TREE_PASS_H) $(DIAGNOSTIC_CORE= _H) >> +tree-tsan.o : $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(TREE_INLINE_H) \ >> + =C2=A0 $(GIMPLE_H) $(DIAGNOSTIC_H) langhooks.h \ >> + =C2=A0 $(TM_H) coretypes.h $(TREE_DUMP_H) $(TREE_PASS_H) $(CGRAPH_H) $= (GGC_H) \ >> + =C2=A0 $(BASIC_BLOCK_H) $(FLAGS_H) $(FUNCTION_H) \ >> + =C2=A0 $(TM_P_H) $(TREE_FLOW_H) $(DIAGNOSTIC_CORE_H) $(GIMPLE_H) tree-= iterator.h \ >> + =C2=A0 intl.h cfghooks.h output.h options.h c-family/c-common.h >> =C2=A0tree-pretty-print.o : tree-pretty-print.c $(CONFIG_H) $(SYSTEM_H) \ >> =C2=A0 =C2=A0$(TREE_H) $(DIAGNOSTIC_H) $(HASHTAB_H) $(TREE_FLOW_H) \ >> =C2=A0 =C2=A0$(TM_H) coretypes.h tree-iterator.h $(SCEV_H) langhooks.h \ >> Index: gcc/passes.c >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> --- gcc/passes.c =C2=A0 =C2=A0 =C2=A0 =C2=A0(revision 180522) >> +++ gcc/passes.c =C2=A0 =C2=A0 =C2=A0 =C2=A0(working copy) >> @@ -1420,6 +1420,7 @@ >> =C2=A0 NEXT_PASS (pass_lower_resx); >> =C2=A0 NEXT_PASS (pass_nrv); >> =C2=A0 NEXT_PASS (pass_mudflap_2); >> + =C2=A0NEXT_PASS (pass_tsan); >> =C2=A0 NEXT_PASS (pass_cleanup_cfg_post_optimizing); >> =C2=A0 NEXT_PASS (pass_warn_function_noreturn); >> >> >> -- >> This patch is available for review at http://codereview.appspot.com/5303= 083 >> >> -- >> You received this message because you are subscribed to the Google Group= s "C-compiler-team" group. >> To post to this group, send email to c-compiler-team@google.com. >> To unsubscribe from this group, send email to c-compiler-team+unsubscrib= e@google.com. >> For more options, visit this group at http://groups.google.com/a/google.= com/group/c-compiler-team/?hl=3Den. >> >> > > -- > You received this message because you are subscribed to the Google Groups= "C-compiler-team" group. > To post to this group, send email to c-compiler-team@google.com. > To unsubscribe from this group, send email to c-compiler-team+unsubscribe= @google.com. > For more options, visit this group at http://groups.google.com/a/google.c= om/group/c-compiler-team/?hl=3Den. > >