1*38fd1498Szrj /* Passes for transactional memory support.
2*38fd1498Szrj Copyright (C) 2008-2018 Free Software Foundation, Inc.
3*38fd1498Szrj Contributed by Richard Henderson <rth@redhat.com>
4*38fd1498Szrj and Aldy Hernandez <aldyh@redhat.com>.
5*38fd1498Szrj
6*38fd1498Szrj This file is part of GCC.
7*38fd1498Szrj
8*38fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
9*38fd1498Szrj the terms of the GNU General Public License as published by the Free
10*38fd1498Szrj Software Foundation; either version 3, or (at your option) any later
11*38fd1498Szrj version.
12*38fd1498Szrj
13*38fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14*38fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
15*38fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16*38fd1498Szrj for more details.
17*38fd1498Szrj
18*38fd1498Szrj You should have received a copy of the GNU General Public License
19*38fd1498Szrj along with GCC; see the file COPYING3. If not see
20*38fd1498Szrj <http://www.gnu.org/licenses/>. */
21*38fd1498Szrj
22*38fd1498Szrj #include "config.h"
23*38fd1498Szrj #include "system.h"
24*38fd1498Szrj #include "coretypes.h"
25*38fd1498Szrj #include "backend.h"
26*38fd1498Szrj #include "target.h"
27*38fd1498Szrj #include "rtl.h"
28*38fd1498Szrj #include "tree.h"
29*38fd1498Szrj #include "gimple.h"
30*38fd1498Szrj #include "cfghooks.h"
31*38fd1498Szrj #include "tree-pass.h"
32*38fd1498Szrj #include "ssa.h"
33*38fd1498Szrj #include "cgraph.h"
34*38fd1498Szrj #include "gimple-pretty-print.h"
35*38fd1498Szrj #include "diagnostic-core.h"
36*38fd1498Szrj #include "fold-const.h"
37*38fd1498Szrj #include "tree-eh.h"
38*38fd1498Szrj #include "calls.h"
39*38fd1498Szrj #include "gimplify.h"
40*38fd1498Szrj #include "gimple-iterator.h"
41*38fd1498Szrj #include "gimplify-me.h"
42*38fd1498Szrj #include "gimple-walk.h"
43*38fd1498Szrj #include "tree-cfg.h"
44*38fd1498Szrj #include "tree-into-ssa.h"
45*38fd1498Szrj #include "tree-inline.h"
46*38fd1498Szrj #include "demangle.h"
47*38fd1498Szrj #include "output.h"
48*38fd1498Szrj #include "trans-mem.h"
49*38fd1498Szrj #include "params.h"
50*38fd1498Szrj #include "langhooks.h"
51*38fd1498Szrj #include "cfgloop.h"
52*38fd1498Szrj #include "tree-ssa-address.h"
53*38fd1498Szrj #include "stringpool.h"
54*38fd1498Szrj #include "attribs.h"
55*38fd1498Szrj
56*38fd1498Szrj #define A_RUNINSTRUMENTEDCODE 0x0001
57*38fd1498Szrj #define A_RUNUNINSTRUMENTEDCODE 0x0002
58*38fd1498Szrj #define A_SAVELIVEVARIABLES 0x0004
59*38fd1498Szrj #define A_RESTORELIVEVARIABLES 0x0008
60*38fd1498Szrj #define A_ABORTTRANSACTION 0x0010
61*38fd1498Szrj
62*38fd1498Szrj #define AR_USERABORT 0x0001
63*38fd1498Szrj #define AR_USERRETRY 0x0002
64*38fd1498Szrj #define AR_TMCONFLICT 0x0004
65*38fd1498Szrj #define AR_EXCEPTIONBLOCKABORT 0x0008
66*38fd1498Szrj #define AR_OUTERABORT 0x0010
67*38fd1498Szrj
68*38fd1498Szrj #define MODE_SERIALIRREVOCABLE 0x0000
69*38fd1498Szrj
70*38fd1498Szrj
71*38fd1498Szrj /* The representation of a transaction changes several times during the
72*38fd1498Szrj lowering process. In the beginning, in the front-end we have the
73*38fd1498Szrj GENERIC tree TRANSACTION_EXPR. For example,
74*38fd1498Szrj
75*38fd1498Szrj __transaction {
76*38fd1498Szrj local++;
77*38fd1498Szrj if (++global == 10)
78*38fd1498Szrj __tm_abort;
79*38fd1498Szrj }
80*38fd1498Szrj
81*38fd1498Szrj During initial gimplification (gimplify.c) the TRANSACTION_EXPR node is
82*38fd1498Szrj trivially replaced with a GIMPLE_TRANSACTION node.
83*38fd1498Szrj
84*38fd1498Szrj During pass_lower_tm, we examine the body of transactions looking
85*38fd1498Szrj for aborts. Transactions that do not contain an abort may be
86*38fd1498Szrj merged into an outer transaction. We also add a TRY-FINALLY node
87*38fd1498Szrj to arrange for the transaction to be committed on any exit.
88*38fd1498Szrj
89*38fd1498Szrj [??? Think about how this arrangement affects throw-with-commit
90*38fd1498Szrj and throw-with-abort operations. In this case we want the TRY to
91*38fd1498Szrj handle gotos, but not to catch any exceptions because the transaction
92*38fd1498Szrj will already be closed.]
93*38fd1498Szrj
94*38fd1498Szrj GIMPLE_TRANSACTION [label=NULL] {
95*38fd1498Szrj try {
96*38fd1498Szrj local = local + 1;
97*38fd1498Szrj t0 = global;
98*38fd1498Szrj t1 = t0 + 1;
99*38fd1498Szrj global = t1;
100*38fd1498Szrj if (t1 == 10)
101*38fd1498Szrj __builtin___tm_abort ();
102*38fd1498Szrj } finally {
103*38fd1498Szrj __builtin___tm_commit ();
104*38fd1498Szrj }
105*38fd1498Szrj }
106*38fd1498Szrj
107*38fd1498Szrj During pass_lower_eh, we create EH regions for the transactions,
108*38fd1498Szrj intermixed with the regular EH stuff. This gives us a nice persistent
109*38fd1498Szrj mapping (all the way through rtl) from transactional memory operation
110*38fd1498Szrj back to the transaction, which allows us to get the abnormal edges
111*38fd1498Szrj correct to model transaction aborts and restarts:
112*38fd1498Szrj
113*38fd1498Szrj GIMPLE_TRANSACTION [label=over]
114*38fd1498Szrj local = local + 1;
115*38fd1498Szrj t0 = global;
116*38fd1498Szrj t1 = t0 + 1;
117*38fd1498Szrj global = t1;
118*38fd1498Szrj if (t1 == 10)
119*38fd1498Szrj __builtin___tm_abort ();
120*38fd1498Szrj __builtin___tm_commit ();
121*38fd1498Szrj over:
122*38fd1498Szrj
123*38fd1498Szrj This is the end of all_lowering_passes, and so is what is present
124*38fd1498Szrj during the IPA passes, and through all of the optimization passes.
125*38fd1498Szrj
126*38fd1498Szrj During pass_ipa_tm, we examine all GIMPLE_TRANSACTION blocks in all
127*38fd1498Szrj functions and mark functions for cloning.
128*38fd1498Szrj
129*38fd1498Szrj At the end of gimple optimization, before exiting SSA form,
130*38fd1498Szrj pass_tm_edges replaces statements that perform transactional
131*38fd1498Szrj memory operations with the appropriate TM builtins, and swap
132*38fd1498Szrj out function calls with their transactional clones. At this
133*38fd1498Szrj point we introduce the abnormal transaction restart edges and
134*38fd1498Szrj complete lowering of the GIMPLE_TRANSACTION node.
135*38fd1498Szrj
136*38fd1498Szrj x = __builtin___tm_start (MAY_ABORT);
137*38fd1498Szrj eh_label:
138*38fd1498Szrj if (x & abort_transaction)
139*38fd1498Szrj goto over;
140*38fd1498Szrj local = local + 1;
141*38fd1498Szrj t0 = __builtin___tm_load (global);
142*38fd1498Szrj t1 = t0 + 1;
143*38fd1498Szrj __builtin___tm_store (&global, t1);
144*38fd1498Szrj if (t1 == 10)
145*38fd1498Szrj __builtin___tm_abort ();
146*38fd1498Szrj __builtin___tm_commit ();
147*38fd1498Szrj over:
148*38fd1498Szrj */
149*38fd1498Szrj
150*38fd1498Szrj static void *expand_regions (struct tm_region *,
151*38fd1498Szrj void *(*callback)(struct tm_region *, void *),
152*38fd1498Szrj void *, bool);
153*38fd1498Szrj
154*38fd1498Szrj
155*38fd1498Szrj /* Return the attributes we want to examine for X, or NULL if it's not
156*38fd1498Szrj something we examine. We look at function types, but allow pointers
157*38fd1498Szrj to function types and function decls and peek through. */
158*38fd1498Szrj
159*38fd1498Szrj static tree
get_attrs_for(const_tree x)160*38fd1498Szrj get_attrs_for (const_tree x)
161*38fd1498Szrj {
162*38fd1498Szrj if (x == NULL_TREE)
163*38fd1498Szrj return NULL_TREE;
164*38fd1498Szrj
165*38fd1498Szrj switch (TREE_CODE (x))
166*38fd1498Szrj {
167*38fd1498Szrj case FUNCTION_DECL:
168*38fd1498Szrj return TYPE_ATTRIBUTES (TREE_TYPE (x));
169*38fd1498Szrj
170*38fd1498Szrj default:
171*38fd1498Szrj if (TYPE_P (x))
172*38fd1498Szrj return NULL_TREE;
173*38fd1498Szrj x = TREE_TYPE (x);
174*38fd1498Szrj if (TREE_CODE (x) != POINTER_TYPE)
175*38fd1498Szrj return NULL_TREE;
176*38fd1498Szrj /* FALLTHRU */
177*38fd1498Szrj
178*38fd1498Szrj case POINTER_TYPE:
179*38fd1498Szrj x = TREE_TYPE (x);
180*38fd1498Szrj if (TREE_CODE (x) != FUNCTION_TYPE && TREE_CODE (x) != METHOD_TYPE)
181*38fd1498Szrj return NULL_TREE;
182*38fd1498Szrj /* FALLTHRU */
183*38fd1498Szrj
184*38fd1498Szrj case FUNCTION_TYPE:
185*38fd1498Szrj case METHOD_TYPE:
186*38fd1498Szrj return TYPE_ATTRIBUTES (x);
187*38fd1498Szrj }
188*38fd1498Szrj }
189*38fd1498Szrj
190*38fd1498Szrj /* Return true if X has been marked TM_PURE. */
191*38fd1498Szrj
192*38fd1498Szrj bool
is_tm_pure(const_tree x)193*38fd1498Szrj is_tm_pure (const_tree x)
194*38fd1498Szrj {
195*38fd1498Szrj unsigned flags;
196*38fd1498Szrj
197*38fd1498Szrj switch (TREE_CODE (x))
198*38fd1498Szrj {
199*38fd1498Szrj case FUNCTION_DECL:
200*38fd1498Szrj case FUNCTION_TYPE:
201*38fd1498Szrj case METHOD_TYPE:
202*38fd1498Szrj break;
203*38fd1498Szrj
204*38fd1498Szrj default:
205*38fd1498Szrj if (TYPE_P (x))
206*38fd1498Szrj return false;
207*38fd1498Szrj x = TREE_TYPE (x);
208*38fd1498Szrj if (TREE_CODE (x) != POINTER_TYPE)
209*38fd1498Szrj return false;
210*38fd1498Szrj /* FALLTHRU */
211*38fd1498Szrj
212*38fd1498Szrj case POINTER_TYPE:
213*38fd1498Szrj x = TREE_TYPE (x);
214*38fd1498Szrj if (TREE_CODE (x) != FUNCTION_TYPE && TREE_CODE (x) != METHOD_TYPE)
215*38fd1498Szrj return false;
216*38fd1498Szrj break;
217*38fd1498Szrj }
218*38fd1498Szrj
219*38fd1498Szrj flags = flags_from_decl_or_type (x);
220*38fd1498Szrj return (flags & ECF_TM_PURE) != 0;
221*38fd1498Szrj }
222*38fd1498Szrj
223*38fd1498Szrj /* Return true if X has been marked TM_IRREVOCABLE. */
224*38fd1498Szrj
225*38fd1498Szrj static bool
is_tm_irrevocable(tree x)226*38fd1498Szrj is_tm_irrevocable (tree x)
227*38fd1498Szrj {
228*38fd1498Szrj tree attrs = get_attrs_for (x);
229*38fd1498Szrj
230*38fd1498Szrj if (attrs && lookup_attribute ("transaction_unsafe", attrs))
231*38fd1498Szrj return true;
232*38fd1498Szrj
233*38fd1498Szrj /* A call to the irrevocable builtin is by definition,
234*38fd1498Szrj irrevocable. */
235*38fd1498Szrj if (TREE_CODE (x) == ADDR_EXPR)
236*38fd1498Szrj x = TREE_OPERAND (x, 0);
237*38fd1498Szrj if (TREE_CODE (x) == FUNCTION_DECL
238*38fd1498Szrj && DECL_BUILT_IN_CLASS (x) == BUILT_IN_NORMAL
239*38fd1498Szrj && DECL_FUNCTION_CODE (x) == BUILT_IN_TM_IRREVOCABLE)
240*38fd1498Szrj return true;
241*38fd1498Szrj
242*38fd1498Szrj return false;
243*38fd1498Szrj }
244*38fd1498Szrj
245*38fd1498Szrj /* Return true if X has been marked TM_SAFE. */
246*38fd1498Szrj
247*38fd1498Szrj bool
is_tm_safe(const_tree x)248*38fd1498Szrj is_tm_safe (const_tree x)
249*38fd1498Szrj {
250*38fd1498Szrj if (flag_tm)
251*38fd1498Szrj {
252*38fd1498Szrj tree attrs = get_attrs_for (x);
253*38fd1498Szrj if (attrs)
254*38fd1498Szrj {
255*38fd1498Szrj if (lookup_attribute ("transaction_safe", attrs))
256*38fd1498Szrj return true;
257*38fd1498Szrj if (lookup_attribute ("transaction_may_cancel_outer", attrs))
258*38fd1498Szrj return true;
259*38fd1498Szrj }
260*38fd1498Szrj }
261*38fd1498Szrj return false;
262*38fd1498Szrj }
263*38fd1498Szrj
264*38fd1498Szrj /* Return true if CALL is const, or tm_pure. */
265*38fd1498Szrj
266*38fd1498Szrj static bool
is_tm_pure_call(gimple * call)267*38fd1498Szrj is_tm_pure_call (gimple *call)
268*38fd1498Szrj {
269*38fd1498Szrj if (gimple_call_internal_p (call))
270*38fd1498Szrj return (gimple_call_flags (call) & (ECF_CONST | ECF_TM_PURE)) != 0;
271*38fd1498Szrj
272*38fd1498Szrj tree fn = gimple_call_fn (call);
273*38fd1498Szrj
274*38fd1498Szrj if (TREE_CODE (fn) == ADDR_EXPR)
275*38fd1498Szrj {
276*38fd1498Szrj fn = TREE_OPERAND (fn, 0);
277*38fd1498Szrj gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
278*38fd1498Szrj }
279*38fd1498Szrj else
280*38fd1498Szrj fn = TREE_TYPE (fn);
281*38fd1498Szrj
282*38fd1498Szrj return is_tm_pure (fn);
283*38fd1498Szrj }
284*38fd1498Szrj
285*38fd1498Szrj /* Return true if X has been marked TM_CALLABLE. */
286*38fd1498Szrj
287*38fd1498Szrj static bool
is_tm_callable(tree x)288*38fd1498Szrj is_tm_callable (tree x)
289*38fd1498Szrj {
290*38fd1498Szrj tree attrs = get_attrs_for (x);
291*38fd1498Szrj if (attrs)
292*38fd1498Szrj {
293*38fd1498Szrj if (lookup_attribute ("transaction_callable", attrs))
294*38fd1498Szrj return true;
295*38fd1498Szrj if (lookup_attribute ("transaction_safe", attrs))
296*38fd1498Szrj return true;
297*38fd1498Szrj if (lookup_attribute ("transaction_may_cancel_outer", attrs))
298*38fd1498Szrj return true;
299*38fd1498Szrj }
300*38fd1498Szrj return false;
301*38fd1498Szrj }
302*38fd1498Szrj
303*38fd1498Szrj /* Return true if X has been marked TRANSACTION_MAY_CANCEL_OUTER. */
304*38fd1498Szrj
305*38fd1498Szrj bool
is_tm_may_cancel_outer(tree x)306*38fd1498Szrj is_tm_may_cancel_outer (tree x)
307*38fd1498Szrj {
308*38fd1498Szrj tree attrs = get_attrs_for (x);
309*38fd1498Szrj if (attrs)
310*38fd1498Szrj return lookup_attribute ("transaction_may_cancel_outer", attrs) != NULL;
311*38fd1498Szrj return false;
312*38fd1498Szrj }
313*38fd1498Szrj
314*38fd1498Szrj /* Return true for built in functions that "end" a transaction. */
315*38fd1498Szrj
316*38fd1498Szrj bool
is_tm_ending_fndecl(tree fndecl)317*38fd1498Szrj is_tm_ending_fndecl (tree fndecl)
318*38fd1498Szrj {
319*38fd1498Szrj if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
320*38fd1498Szrj switch (DECL_FUNCTION_CODE (fndecl))
321*38fd1498Szrj {
322*38fd1498Szrj case BUILT_IN_TM_COMMIT:
323*38fd1498Szrj case BUILT_IN_TM_COMMIT_EH:
324*38fd1498Szrj case BUILT_IN_TM_ABORT:
325*38fd1498Szrj case BUILT_IN_TM_IRREVOCABLE:
326*38fd1498Szrj return true;
327*38fd1498Szrj default:
328*38fd1498Szrj break;
329*38fd1498Szrj }
330*38fd1498Szrj
331*38fd1498Szrj return false;
332*38fd1498Szrj }
333*38fd1498Szrj
334*38fd1498Szrj /* Return true if STMT is a built in function call that "ends" a
335*38fd1498Szrj transaction. */
336*38fd1498Szrj
337*38fd1498Szrj bool
is_tm_ending(gimple * stmt)338*38fd1498Szrj is_tm_ending (gimple *stmt)
339*38fd1498Szrj {
340*38fd1498Szrj tree fndecl;
341*38fd1498Szrj
342*38fd1498Szrj if (gimple_code (stmt) != GIMPLE_CALL)
343*38fd1498Szrj return false;
344*38fd1498Szrj
345*38fd1498Szrj fndecl = gimple_call_fndecl (stmt);
346*38fd1498Szrj return (fndecl != NULL_TREE
347*38fd1498Szrj && is_tm_ending_fndecl (fndecl));
348*38fd1498Szrj }
349*38fd1498Szrj
350*38fd1498Szrj /* Return true if STMT is a TM load. */
351*38fd1498Szrj
352*38fd1498Szrj static bool
is_tm_load(gimple * stmt)353*38fd1498Szrj is_tm_load (gimple *stmt)
354*38fd1498Szrj {
355*38fd1498Szrj tree fndecl;
356*38fd1498Szrj
357*38fd1498Szrj if (gimple_code (stmt) != GIMPLE_CALL)
358*38fd1498Szrj return false;
359*38fd1498Szrj
360*38fd1498Szrj fndecl = gimple_call_fndecl (stmt);
361*38fd1498Szrj return (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
362*38fd1498Szrj && BUILTIN_TM_LOAD_P (DECL_FUNCTION_CODE (fndecl)));
363*38fd1498Szrj }
364*38fd1498Szrj
365*38fd1498Szrj /* Same as above, but for simple TM loads, that is, not the
366*38fd1498Szrj after-write, after-read, etc optimized variants. */
367*38fd1498Szrj
368*38fd1498Szrj static bool
is_tm_simple_load(gimple * stmt)369*38fd1498Szrj is_tm_simple_load (gimple *stmt)
370*38fd1498Szrj {
371*38fd1498Szrj tree fndecl;
372*38fd1498Szrj
373*38fd1498Szrj if (gimple_code (stmt) != GIMPLE_CALL)
374*38fd1498Szrj return false;
375*38fd1498Szrj
376*38fd1498Szrj fndecl = gimple_call_fndecl (stmt);
377*38fd1498Szrj if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
378*38fd1498Szrj {
379*38fd1498Szrj enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
380*38fd1498Szrj return (fcode == BUILT_IN_TM_LOAD_1
381*38fd1498Szrj || fcode == BUILT_IN_TM_LOAD_2
382*38fd1498Szrj || fcode == BUILT_IN_TM_LOAD_4
383*38fd1498Szrj || fcode == BUILT_IN_TM_LOAD_8
384*38fd1498Szrj || fcode == BUILT_IN_TM_LOAD_FLOAT
385*38fd1498Szrj || fcode == BUILT_IN_TM_LOAD_DOUBLE
386*38fd1498Szrj || fcode == BUILT_IN_TM_LOAD_LDOUBLE
387*38fd1498Szrj || fcode == BUILT_IN_TM_LOAD_M64
388*38fd1498Szrj || fcode == BUILT_IN_TM_LOAD_M128
389*38fd1498Szrj || fcode == BUILT_IN_TM_LOAD_M256);
390*38fd1498Szrj }
391*38fd1498Szrj return false;
392*38fd1498Szrj }
393*38fd1498Szrj
394*38fd1498Szrj /* Return true if STMT is a TM store. */
395*38fd1498Szrj
396*38fd1498Szrj static bool
is_tm_store(gimple * stmt)397*38fd1498Szrj is_tm_store (gimple *stmt)
398*38fd1498Szrj {
399*38fd1498Szrj tree fndecl;
400*38fd1498Szrj
401*38fd1498Szrj if (gimple_code (stmt) != GIMPLE_CALL)
402*38fd1498Szrj return false;
403*38fd1498Szrj
404*38fd1498Szrj fndecl = gimple_call_fndecl (stmt);
405*38fd1498Szrj return (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
406*38fd1498Szrj && BUILTIN_TM_STORE_P (DECL_FUNCTION_CODE (fndecl)));
407*38fd1498Szrj }
408*38fd1498Szrj
409*38fd1498Szrj /* Same as above, but for simple TM stores, that is, not the
410*38fd1498Szrj after-write, after-read, etc optimized variants. */
411*38fd1498Szrj
412*38fd1498Szrj static bool
is_tm_simple_store(gimple * stmt)413*38fd1498Szrj is_tm_simple_store (gimple *stmt)
414*38fd1498Szrj {
415*38fd1498Szrj tree fndecl;
416*38fd1498Szrj
417*38fd1498Szrj if (gimple_code (stmt) != GIMPLE_CALL)
418*38fd1498Szrj return false;
419*38fd1498Szrj
420*38fd1498Szrj fndecl = gimple_call_fndecl (stmt);
421*38fd1498Szrj if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
422*38fd1498Szrj {
423*38fd1498Szrj enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
424*38fd1498Szrj return (fcode == BUILT_IN_TM_STORE_1
425*38fd1498Szrj || fcode == BUILT_IN_TM_STORE_2
426*38fd1498Szrj || fcode == BUILT_IN_TM_STORE_4
427*38fd1498Szrj || fcode == BUILT_IN_TM_STORE_8
428*38fd1498Szrj || fcode == BUILT_IN_TM_STORE_FLOAT
429*38fd1498Szrj || fcode == BUILT_IN_TM_STORE_DOUBLE
430*38fd1498Szrj || fcode == BUILT_IN_TM_STORE_LDOUBLE
431*38fd1498Szrj || fcode == BUILT_IN_TM_STORE_M64
432*38fd1498Szrj || fcode == BUILT_IN_TM_STORE_M128
433*38fd1498Szrj || fcode == BUILT_IN_TM_STORE_M256);
434*38fd1498Szrj }
435*38fd1498Szrj return false;
436*38fd1498Szrj }
437*38fd1498Szrj
438*38fd1498Szrj /* Return true if FNDECL is BUILT_IN_TM_ABORT. */
439*38fd1498Szrj
440*38fd1498Szrj static bool
is_tm_abort(tree fndecl)441*38fd1498Szrj is_tm_abort (tree fndecl)
442*38fd1498Szrj {
443*38fd1498Szrj return (fndecl
444*38fd1498Szrj && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
445*38fd1498Szrj && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_TM_ABORT);
446*38fd1498Szrj }
447*38fd1498Szrj
448*38fd1498Szrj /* Build a GENERIC tree for a user abort. This is called by front ends
449*38fd1498Szrj while transforming the __tm_abort statement. */
450*38fd1498Szrj
451*38fd1498Szrj tree
build_tm_abort_call(location_t loc,bool is_outer)452*38fd1498Szrj build_tm_abort_call (location_t loc, bool is_outer)
453*38fd1498Szrj {
454*38fd1498Szrj return build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TM_ABORT), 1,
455*38fd1498Szrj build_int_cst (integer_type_node,
456*38fd1498Szrj AR_USERABORT
457*38fd1498Szrj | (is_outer ? AR_OUTERABORT : 0)));
458*38fd1498Szrj }
459*38fd1498Szrj
460*38fd1498Szrj /* Map for arbitrary function replacement under TM, as created
461*38fd1498Szrj by the tm_wrap attribute. */
462*38fd1498Szrj
463*38fd1498Szrj struct tm_wrapper_hasher : ggc_cache_ptr_hash<tree_map>
464*38fd1498Szrj {
hashtm_wrapper_hasher465*38fd1498Szrj static inline hashval_t hash (tree_map *m) { return m->hash; }
466*38fd1498Szrj static inline bool
equaltm_wrapper_hasher467*38fd1498Szrj equal (tree_map *a, tree_map *b)
468*38fd1498Szrj {
469*38fd1498Szrj return a->base.from == b->base.from;
470*38fd1498Szrj }
471*38fd1498Szrj
472*38fd1498Szrj static int
keep_cache_entrytm_wrapper_hasher473*38fd1498Szrj keep_cache_entry (tree_map *&m)
474*38fd1498Szrj {
475*38fd1498Szrj return ggc_marked_p (m->base.from);
476*38fd1498Szrj }
477*38fd1498Szrj };
478*38fd1498Szrj
479*38fd1498Szrj static GTY((cache)) hash_table<tm_wrapper_hasher> *tm_wrap_map;
480*38fd1498Szrj
481*38fd1498Szrj void
record_tm_replacement(tree from,tree to)482*38fd1498Szrj record_tm_replacement (tree from, tree to)
483*38fd1498Szrj {
484*38fd1498Szrj struct tree_map **slot, *h;
485*38fd1498Szrj
486*38fd1498Szrj /* Do not inline wrapper functions that will get replaced in the TM
487*38fd1498Szrj pass.
488*38fd1498Szrj
489*38fd1498Szrj Suppose you have foo() that will get replaced into tmfoo(). Make
490*38fd1498Szrj sure the inliner doesn't try to outsmart us and inline foo()
491*38fd1498Szrj before we get a chance to do the TM replacement. */
492*38fd1498Szrj DECL_UNINLINABLE (from) = 1;
493*38fd1498Szrj
494*38fd1498Szrj if (tm_wrap_map == NULL)
495*38fd1498Szrj tm_wrap_map = hash_table<tm_wrapper_hasher>::create_ggc (32);
496*38fd1498Szrj
497*38fd1498Szrj h = ggc_alloc<tree_map> ();
498*38fd1498Szrj h->hash = htab_hash_pointer (from);
499*38fd1498Szrj h->base.from = from;
500*38fd1498Szrj h->to = to;
501*38fd1498Szrj
502*38fd1498Szrj slot = tm_wrap_map->find_slot_with_hash (h, h->hash, INSERT);
503*38fd1498Szrj *slot = h;
504*38fd1498Szrj }
505*38fd1498Szrj
506*38fd1498Szrj /* Return a TM-aware replacement function for DECL. */
507*38fd1498Szrj
508*38fd1498Szrj static tree
find_tm_replacement_function(tree fndecl)509*38fd1498Szrj find_tm_replacement_function (tree fndecl)
510*38fd1498Szrj {
511*38fd1498Szrj if (tm_wrap_map)
512*38fd1498Szrj {
513*38fd1498Szrj struct tree_map *h, in;
514*38fd1498Szrj
515*38fd1498Szrj in.base.from = fndecl;
516*38fd1498Szrj in.hash = htab_hash_pointer (fndecl);
517*38fd1498Szrj h = tm_wrap_map->find_with_hash (&in, in.hash);
518*38fd1498Szrj if (h)
519*38fd1498Szrj return h->to;
520*38fd1498Szrj }
521*38fd1498Szrj
522*38fd1498Szrj /* ??? We may well want TM versions of most of the common <string.h>
523*38fd1498Szrj functions. For now, we've already these two defined. */
524*38fd1498Szrj /* Adjust expand_call_tm() attributes as necessary for the cases
525*38fd1498Szrj handled here: */
526*38fd1498Szrj if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
527*38fd1498Szrj switch (DECL_FUNCTION_CODE (fndecl))
528*38fd1498Szrj {
529*38fd1498Szrj case BUILT_IN_MEMCPY:
530*38fd1498Szrj return builtin_decl_explicit (BUILT_IN_TM_MEMCPY);
531*38fd1498Szrj case BUILT_IN_MEMMOVE:
532*38fd1498Szrj return builtin_decl_explicit (BUILT_IN_TM_MEMMOVE);
533*38fd1498Szrj case BUILT_IN_MEMSET:
534*38fd1498Szrj return builtin_decl_explicit (BUILT_IN_TM_MEMSET);
535*38fd1498Szrj default:
536*38fd1498Szrj return NULL;
537*38fd1498Szrj }
538*38fd1498Szrj
539*38fd1498Szrj return NULL;
540*38fd1498Szrj }
541*38fd1498Szrj
542*38fd1498Szrj /* When appropriate, record TM replacement for memory allocation functions.
543*38fd1498Szrj
544*38fd1498Szrj FROM is the FNDECL to wrap. */
545*38fd1498Szrj void
tm_malloc_replacement(tree from)546*38fd1498Szrj tm_malloc_replacement (tree from)
547*38fd1498Szrj {
548*38fd1498Szrj const char *str;
549*38fd1498Szrj tree to;
550*38fd1498Szrj
551*38fd1498Szrj if (TREE_CODE (from) != FUNCTION_DECL)
552*38fd1498Szrj return;
553*38fd1498Szrj
554*38fd1498Szrj /* If we have a previous replacement, the user must be explicitly
555*38fd1498Szrj wrapping malloc/calloc/free. They better know what they're
556*38fd1498Szrj doing... */
557*38fd1498Szrj if (find_tm_replacement_function (from))
558*38fd1498Szrj return;
559*38fd1498Szrj
560*38fd1498Szrj str = IDENTIFIER_POINTER (DECL_NAME (from));
561*38fd1498Szrj
562*38fd1498Szrj if (!strcmp (str, "malloc"))
563*38fd1498Szrj to = builtin_decl_explicit (BUILT_IN_TM_MALLOC);
564*38fd1498Szrj else if (!strcmp (str, "calloc"))
565*38fd1498Szrj to = builtin_decl_explicit (BUILT_IN_TM_CALLOC);
566*38fd1498Szrj else if (!strcmp (str, "free"))
567*38fd1498Szrj to = builtin_decl_explicit (BUILT_IN_TM_FREE);
568*38fd1498Szrj else
569*38fd1498Szrj return;
570*38fd1498Szrj
571*38fd1498Szrj TREE_NOTHROW (to) = 0;
572*38fd1498Szrj
573*38fd1498Szrj record_tm_replacement (from, to);
574*38fd1498Szrj }
575*38fd1498Szrj
576*38fd1498Szrj /* Diagnostics for tm_safe functions/regions. Called by the front end
577*38fd1498Szrj once we've lowered the function to high-gimple. */
578*38fd1498Szrj
579*38fd1498Szrj /* Subroutine of diagnose_tm_safe_errors, called through walk_gimple_seq.
580*38fd1498Szrj Process exactly one statement. WI->INFO is set to non-null when in
581*38fd1498Szrj the context of a tm_safe function, and null for a __transaction block. */
582*38fd1498Szrj
583*38fd1498Szrj #define DIAG_TM_OUTER 1
584*38fd1498Szrj #define DIAG_TM_SAFE 2
585*38fd1498Szrj #define DIAG_TM_RELAXED 4
586*38fd1498Szrj
587*38fd1498Szrj struct diagnose_tm
588*38fd1498Szrj {
589*38fd1498Szrj unsigned int summary_flags : 8;
590*38fd1498Szrj unsigned int block_flags : 8;
591*38fd1498Szrj unsigned int func_flags : 8;
592*38fd1498Szrj unsigned int saw_volatile : 1;
593*38fd1498Szrj gimple *stmt;
594*38fd1498Szrj };
595*38fd1498Szrj
596*38fd1498Szrj /* Return true if T is a volatile lvalue of some kind. */
597*38fd1498Szrj
598*38fd1498Szrj static bool
volatile_lvalue_p(tree t)599*38fd1498Szrj volatile_lvalue_p (tree t)
600*38fd1498Szrj {
601*38fd1498Szrj return ((SSA_VAR_P (t) || REFERENCE_CLASS_P (t))
602*38fd1498Szrj && TREE_THIS_VOLATILE (TREE_TYPE (t)));
603*38fd1498Szrj }
604*38fd1498Szrj
605*38fd1498Szrj /* Tree callback function for diagnose_tm pass. */
606*38fd1498Szrj
607*38fd1498Szrj static tree
diagnose_tm_1_op(tree * tp,int * walk_subtrees,void * data)608*38fd1498Szrj diagnose_tm_1_op (tree *tp, int *walk_subtrees, void *data)
609*38fd1498Szrj {
610*38fd1498Szrj struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
611*38fd1498Szrj struct diagnose_tm *d = (struct diagnose_tm *) wi->info;
612*38fd1498Szrj
613*38fd1498Szrj if (TYPE_P (*tp))
614*38fd1498Szrj *walk_subtrees = false;
615*38fd1498Szrj else if (volatile_lvalue_p (*tp)
616*38fd1498Szrj && !d->saw_volatile)
617*38fd1498Szrj {
618*38fd1498Szrj d->saw_volatile = 1;
619*38fd1498Szrj if (d->block_flags & DIAG_TM_SAFE)
620*38fd1498Szrj error_at (gimple_location (d->stmt),
621*38fd1498Szrj "invalid use of volatile lvalue inside transaction");
622*38fd1498Szrj else if (d->func_flags & DIAG_TM_SAFE)
623*38fd1498Szrj error_at (gimple_location (d->stmt),
624*38fd1498Szrj "invalid use of volatile lvalue inside %<transaction_safe%> "
625*38fd1498Szrj "function");
626*38fd1498Szrj }
627*38fd1498Szrj
628*38fd1498Szrj return NULL_TREE;
629*38fd1498Szrj }
630*38fd1498Szrj
631*38fd1498Szrj static inline bool
is_tm_safe_or_pure(const_tree x)632*38fd1498Szrj is_tm_safe_or_pure (const_tree x)
633*38fd1498Szrj {
634*38fd1498Szrj return is_tm_safe (x) || is_tm_pure (x);
635*38fd1498Szrj }
636*38fd1498Szrj
637*38fd1498Szrj static tree
diagnose_tm_1(gimple_stmt_iterator * gsi,bool * handled_ops_p,struct walk_stmt_info * wi)638*38fd1498Szrj diagnose_tm_1 (gimple_stmt_iterator *gsi, bool *handled_ops_p,
639*38fd1498Szrj struct walk_stmt_info *wi)
640*38fd1498Szrj {
641*38fd1498Szrj gimple *stmt = gsi_stmt (*gsi);
642*38fd1498Szrj struct diagnose_tm *d = (struct diagnose_tm *) wi->info;
643*38fd1498Szrj
644*38fd1498Szrj /* Save stmt for use in leaf analysis. */
645*38fd1498Szrj d->stmt = stmt;
646*38fd1498Szrj
647*38fd1498Szrj switch (gimple_code (stmt))
648*38fd1498Szrj {
649*38fd1498Szrj case GIMPLE_CALL:
650*38fd1498Szrj {
651*38fd1498Szrj tree fn = gimple_call_fn (stmt);
652*38fd1498Szrj
653*38fd1498Szrj if ((d->summary_flags & DIAG_TM_OUTER) == 0
654*38fd1498Szrj && is_tm_may_cancel_outer (fn))
655*38fd1498Szrj error_at (gimple_location (stmt),
656*38fd1498Szrj "%<transaction_may_cancel_outer%> function call not within"
657*38fd1498Szrj " outer transaction or %<transaction_may_cancel_outer%>");
658*38fd1498Szrj
659*38fd1498Szrj if (d->summary_flags & DIAG_TM_SAFE)
660*38fd1498Szrj {
661*38fd1498Szrj bool is_safe, direct_call_p;
662*38fd1498Szrj tree replacement;
663*38fd1498Szrj
664*38fd1498Szrj if (TREE_CODE (fn) == ADDR_EXPR
665*38fd1498Szrj && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL)
666*38fd1498Szrj {
667*38fd1498Szrj direct_call_p = true;
668*38fd1498Szrj replacement = TREE_OPERAND (fn, 0);
669*38fd1498Szrj replacement = find_tm_replacement_function (replacement);
670*38fd1498Szrj if (replacement)
671*38fd1498Szrj fn = replacement;
672*38fd1498Szrj }
673*38fd1498Szrj else
674*38fd1498Szrj {
675*38fd1498Szrj direct_call_p = false;
676*38fd1498Szrj replacement = NULL_TREE;
677*38fd1498Szrj }
678*38fd1498Szrj
679*38fd1498Szrj if (is_tm_safe_or_pure (fn))
680*38fd1498Szrj is_safe = true;
681*38fd1498Szrj else if (is_tm_callable (fn) || is_tm_irrevocable (fn))
682*38fd1498Szrj {
683*38fd1498Szrj /* A function explicitly marked transaction_callable as
684*38fd1498Szrj opposed to transaction_safe is being defined to be
685*38fd1498Szrj unsafe as part of its ABI, regardless of its contents. */
686*38fd1498Szrj is_safe = false;
687*38fd1498Szrj }
688*38fd1498Szrj else if (direct_call_p)
689*38fd1498Szrj {
690*38fd1498Szrj if (IS_TYPE_OR_DECL_P (fn)
691*38fd1498Szrj && flags_from_decl_or_type (fn) & ECF_TM_BUILTIN)
692*38fd1498Szrj is_safe = true;
693*38fd1498Szrj else if (replacement)
694*38fd1498Szrj {
695*38fd1498Szrj /* ??? At present we've been considering replacements
696*38fd1498Szrj merely transaction_callable, and therefore might
697*38fd1498Szrj enter irrevocable. The tm_wrap attribute has not
698*38fd1498Szrj yet made it into the new language spec. */
699*38fd1498Szrj is_safe = false;
700*38fd1498Szrj }
701*38fd1498Szrj else
702*38fd1498Szrj {
703*38fd1498Szrj /* ??? Diagnostics for unmarked direct calls moved into
704*38fd1498Szrj the IPA pass. Section 3.2 of the spec details how
705*38fd1498Szrj functions not marked should be considered "implicitly
706*38fd1498Szrj safe" based on having examined the function body. */
707*38fd1498Szrj is_safe = true;
708*38fd1498Szrj }
709*38fd1498Szrj }
710*38fd1498Szrj else
711*38fd1498Szrj {
712*38fd1498Szrj /* An unmarked indirect call. Consider it unsafe even
713*38fd1498Szrj though optimization may yet figure out how to inline. */
714*38fd1498Szrj is_safe = false;
715*38fd1498Szrj }
716*38fd1498Szrj
717*38fd1498Szrj if (!is_safe)
718*38fd1498Szrj {
719*38fd1498Szrj if (TREE_CODE (fn) == ADDR_EXPR)
720*38fd1498Szrj fn = TREE_OPERAND (fn, 0);
721*38fd1498Szrj if (d->block_flags & DIAG_TM_SAFE)
722*38fd1498Szrj {
723*38fd1498Szrj if (direct_call_p)
724*38fd1498Szrj error_at (gimple_location (stmt),
725*38fd1498Szrj "unsafe function call %qD within "
726*38fd1498Szrj "atomic transaction", fn);
727*38fd1498Szrj else
728*38fd1498Szrj {
729*38fd1498Szrj if ((!DECL_P (fn) || DECL_NAME (fn))
730*38fd1498Szrj && TREE_CODE (fn) != SSA_NAME)
731*38fd1498Szrj error_at (gimple_location (stmt),
732*38fd1498Szrj "unsafe function call %qE within "
733*38fd1498Szrj "atomic transaction", fn);
734*38fd1498Szrj else
735*38fd1498Szrj error_at (gimple_location (stmt),
736*38fd1498Szrj "unsafe indirect function call within "
737*38fd1498Szrj "atomic transaction");
738*38fd1498Szrj }
739*38fd1498Szrj }
740*38fd1498Szrj else
741*38fd1498Szrj {
742*38fd1498Szrj if (direct_call_p)
743*38fd1498Szrj error_at (gimple_location (stmt),
744*38fd1498Szrj "unsafe function call %qD within "
745*38fd1498Szrj "%<transaction_safe%> function", fn);
746*38fd1498Szrj else
747*38fd1498Szrj {
748*38fd1498Szrj if ((!DECL_P (fn) || DECL_NAME (fn))
749*38fd1498Szrj && TREE_CODE (fn) != SSA_NAME)
750*38fd1498Szrj error_at (gimple_location (stmt),
751*38fd1498Szrj "unsafe function call %qE within "
752*38fd1498Szrj "%<transaction_safe%> function", fn);
753*38fd1498Szrj else
754*38fd1498Szrj error_at (gimple_location (stmt),
755*38fd1498Szrj "unsafe indirect function call within "
756*38fd1498Szrj "%<transaction_safe%> function");
757*38fd1498Szrj }
758*38fd1498Szrj }
759*38fd1498Szrj }
760*38fd1498Szrj }
761*38fd1498Szrj }
762*38fd1498Szrj break;
763*38fd1498Szrj
764*38fd1498Szrj case GIMPLE_ASM:
765*38fd1498Szrj /* ??? We ought to come up with a way to add attributes to
766*38fd1498Szrj asm statements, and then add "transaction_safe" to it.
767*38fd1498Szrj Either that or get the language spec to resurrect __tm_waiver. */
768*38fd1498Szrj if (d->block_flags & DIAG_TM_SAFE)
769*38fd1498Szrj error_at (gimple_location (stmt),
770*38fd1498Szrj "asm not allowed in atomic transaction");
771*38fd1498Szrj else if (d->func_flags & DIAG_TM_SAFE)
772*38fd1498Szrj error_at (gimple_location (stmt),
773*38fd1498Szrj "asm not allowed in %<transaction_safe%> function");
774*38fd1498Szrj break;
775*38fd1498Szrj
776*38fd1498Szrj case GIMPLE_TRANSACTION:
777*38fd1498Szrj {
778*38fd1498Szrj gtransaction *trans_stmt = as_a <gtransaction *> (stmt);
779*38fd1498Szrj unsigned char inner_flags = DIAG_TM_SAFE;
780*38fd1498Szrj
781*38fd1498Szrj if (gimple_transaction_subcode (trans_stmt) & GTMA_IS_RELAXED)
782*38fd1498Szrj {
783*38fd1498Szrj if (d->block_flags & DIAG_TM_SAFE)
784*38fd1498Szrj error_at (gimple_location (stmt),
785*38fd1498Szrj "relaxed transaction in atomic transaction");
786*38fd1498Szrj else if (d->func_flags & DIAG_TM_SAFE)
787*38fd1498Szrj error_at (gimple_location (stmt),
788*38fd1498Szrj "relaxed transaction in %<transaction_safe%> function");
789*38fd1498Szrj inner_flags = DIAG_TM_RELAXED;
790*38fd1498Szrj }
791*38fd1498Szrj else if (gimple_transaction_subcode (trans_stmt) & GTMA_IS_OUTER)
792*38fd1498Szrj {
793*38fd1498Szrj if (d->block_flags)
794*38fd1498Szrj error_at (gimple_location (stmt),
795*38fd1498Szrj "outer transaction in transaction");
796*38fd1498Szrj else if (d->func_flags & DIAG_TM_OUTER)
797*38fd1498Szrj error_at (gimple_location (stmt),
798*38fd1498Szrj "outer transaction in "
799*38fd1498Szrj "%<transaction_may_cancel_outer%> function");
800*38fd1498Szrj else if (d->func_flags & DIAG_TM_SAFE)
801*38fd1498Szrj error_at (gimple_location (stmt),
802*38fd1498Szrj "outer transaction in %<transaction_safe%> function");
803*38fd1498Szrj inner_flags |= DIAG_TM_OUTER;
804*38fd1498Szrj }
805*38fd1498Szrj
806*38fd1498Szrj *handled_ops_p = true;
807*38fd1498Szrj if (gimple_transaction_body (trans_stmt))
808*38fd1498Szrj {
809*38fd1498Szrj struct walk_stmt_info wi_inner;
810*38fd1498Szrj struct diagnose_tm d_inner;
811*38fd1498Szrj
812*38fd1498Szrj memset (&d_inner, 0, sizeof (d_inner));
813*38fd1498Szrj d_inner.func_flags = d->func_flags;
814*38fd1498Szrj d_inner.block_flags = d->block_flags | inner_flags;
815*38fd1498Szrj d_inner.summary_flags = d_inner.func_flags | d_inner.block_flags;
816*38fd1498Szrj
817*38fd1498Szrj memset (&wi_inner, 0, sizeof (wi_inner));
818*38fd1498Szrj wi_inner.info = &d_inner;
819*38fd1498Szrj
820*38fd1498Szrj walk_gimple_seq (gimple_transaction_body (trans_stmt),
821*38fd1498Szrj diagnose_tm_1, diagnose_tm_1_op, &wi_inner);
822*38fd1498Szrj }
823*38fd1498Szrj }
824*38fd1498Szrj break;
825*38fd1498Szrj
826*38fd1498Szrj default:
827*38fd1498Szrj break;
828*38fd1498Szrj }
829*38fd1498Szrj
830*38fd1498Szrj return NULL_TREE;
831*38fd1498Szrj }
832*38fd1498Szrj
833*38fd1498Szrj static unsigned int
diagnose_tm_blocks(void)834*38fd1498Szrj diagnose_tm_blocks (void)
835*38fd1498Szrj {
836*38fd1498Szrj struct walk_stmt_info wi;
837*38fd1498Szrj struct diagnose_tm d;
838*38fd1498Szrj
839*38fd1498Szrj memset (&d, 0, sizeof (d));
840*38fd1498Szrj if (is_tm_may_cancel_outer (current_function_decl))
841*38fd1498Szrj d.func_flags = DIAG_TM_OUTER | DIAG_TM_SAFE;
842*38fd1498Szrj else if (is_tm_safe (current_function_decl))
843*38fd1498Szrj d.func_flags = DIAG_TM_SAFE;
844*38fd1498Szrj d.summary_flags = d.func_flags;
845*38fd1498Szrj
846*38fd1498Szrj memset (&wi, 0, sizeof (wi));
847*38fd1498Szrj wi.info = &d;
848*38fd1498Szrj
849*38fd1498Szrj walk_gimple_seq (gimple_body (current_function_decl),
850*38fd1498Szrj diagnose_tm_1, diagnose_tm_1_op, &wi);
851*38fd1498Szrj
852*38fd1498Szrj return 0;
853*38fd1498Szrj }
854*38fd1498Szrj
855*38fd1498Szrj namespace {
856*38fd1498Szrj
857*38fd1498Szrj const pass_data pass_data_diagnose_tm_blocks =
858*38fd1498Szrj {
859*38fd1498Szrj GIMPLE_PASS, /* type */
860*38fd1498Szrj "*diagnose_tm_blocks", /* name */
861*38fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */
862*38fd1498Szrj TV_TRANS_MEM, /* tv_id */
863*38fd1498Szrj PROP_gimple_any, /* properties_required */
864*38fd1498Szrj 0, /* properties_provided */
865*38fd1498Szrj 0, /* properties_destroyed */
866*38fd1498Szrj 0, /* todo_flags_start */
867*38fd1498Szrj 0, /* todo_flags_finish */
868*38fd1498Szrj };
869*38fd1498Szrj
870*38fd1498Szrj class pass_diagnose_tm_blocks : public gimple_opt_pass
871*38fd1498Szrj {
872*38fd1498Szrj public:
pass_diagnose_tm_blocks(gcc::context * ctxt)873*38fd1498Szrj pass_diagnose_tm_blocks (gcc::context *ctxt)
874*38fd1498Szrj : gimple_opt_pass (pass_data_diagnose_tm_blocks, ctxt)
875*38fd1498Szrj {}
876*38fd1498Szrj
877*38fd1498Szrj /* opt_pass methods: */
gate(function *)878*38fd1498Szrj virtual bool gate (function *) { return flag_tm; }
execute(function *)879*38fd1498Szrj virtual unsigned int execute (function *) { return diagnose_tm_blocks (); }
880*38fd1498Szrj
881*38fd1498Szrj }; // class pass_diagnose_tm_blocks
882*38fd1498Szrj
883*38fd1498Szrj } // anon namespace
884*38fd1498Szrj
885*38fd1498Szrj gimple_opt_pass *
make_pass_diagnose_tm_blocks(gcc::context * ctxt)886*38fd1498Szrj make_pass_diagnose_tm_blocks (gcc::context *ctxt)
887*38fd1498Szrj {
888*38fd1498Szrj return new pass_diagnose_tm_blocks (ctxt);
889*38fd1498Szrj }
890*38fd1498Szrj
891*38fd1498Szrj /* Instead of instrumenting thread private memory, we save the
892*38fd1498Szrj addresses in a log which we later use to save/restore the addresses
893*38fd1498Szrj upon transaction start/restart.
894*38fd1498Szrj
895*38fd1498Szrj The log is keyed by address, where each element contains individual
896*38fd1498Szrj statements among different code paths that perform the store.
897*38fd1498Szrj
898*38fd1498Szrj This log is later used to generate either plain save/restore of the
899*38fd1498Szrj addresses upon transaction start/restart, or calls to the ITM_L*
900*38fd1498Szrj logging functions.
901*38fd1498Szrj
902*38fd1498Szrj So for something like:
903*38fd1498Szrj
904*38fd1498Szrj struct large { int x[1000]; };
905*38fd1498Szrj struct large lala = { 0 };
906*38fd1498Szrj __transaction {
907*38fd1498Szrj lala.x[i] = 123;
908*38fd1498Szrj ...
909*38fd1498Szrj }
910*38fd1498Szrj
911*38fd1498Szrj We can either save/restore:
912*38fd1498Szrj
913*38fd1498Szrj lala = { 0 };
914*38fd1498Szrj trxn = _ITM_startTransaction ();
915*38fd1498Szrj if (trxn & a_saveLiveVariables)
916*38fd1498Szrj tmp_lala1 = lala.x[i];
917*38fd1498Szrj else if (a & a_restoreLiveVariables)
918*38fd1498Szrj lala.x[i] = tmp_lala1;
919*38fd1498Szrj
920*38fd1498Szrj or use the logging functions:
921*38fd1498Szrj
922*38fd1498Szrj lala = { 0 };
923*38fd1498Szrj trxn = _ITM_startTransaction ();
924*38fd1498Szrj _ITM_LU4 (&lala.x[i]);
925*38fd1498Szrj
926*38fd1498Szrj Obviously, if we use _ITM_L* to log, we prefer to call _ITM_L* as
927*38fd1498Szrj far up the dominator tree to shadow all of the writes to a given
928*38fd1498Szrj location (thus reducing the total number of logging calls), but not
929*38fd1498Szrj so high as to be called on a path that does not perform a
930*38fd1498Szrj write. */
931*38fd1498Szrj
932*38fd1498Szrj /* One individual log entry. We may have multiple statements for the
933*38fd1498Szrj same location if neither dominate each other (on different
934*38fd1498Szrj execution paths). */
935*38fd1498Szrj struct tm_log_entry
936*38fd1498Szrj {
937*38fd1498Szrj /* Address to save. */
938*38fd1498Szrj tree addr;
939*38fd1498Szrj /* Entry block for the transaction this address occurs in. */
940*38fd1498Szrj basic_block entry_block;
941*38fd1498Szrj /* Dominating statements the store occurs in. */
942*38fd1498Szrj vec<gimple *> stmts;
943*38fd1498Szrj /* Initially, while we are building the log, we place a nonzero
944*38fd1498Szrj value here to mean that this address *will* be saved with a
945*38fd1498Szrj save/restore sequence. Later, when generating the save sequence
946*38fd1498Szrj we place the SSA temp generated here. */
947*38fd1498Szrj tree save_var;
948*38fd1498Szrj };
949*38fd1498Szrj
950*38fd1498Szrj
951*38fd1498Szrj /* Log entry hashtable helpers. */
952*38fd1498Szrj
953*38fd1498Szrj struct log_entry_hasher : pointer_hash <tm_log_entry>
954*38fd1498Szrj {
955*38fd1498Szrj static inline hashval_t hash (const tm_log_entry *);
956*38fd1498Szrj static inline bool equal (const tm_log_entry *, const tm_log_entry *);
957*38fd1498Szrj static inline void remove (tm_log_entry *);
958*38fd1498Szrj };
959*38fd1498Szrj
960*38fd1498Szrj /* Htab support. Return hash value for a `tm_log_entry'. */
961*38fd1498Szrj inline hashval_t
hash(const tm_log_entry * log)962*38fd1498Szrj log_entry_hasher::hash (const tm_log_entry *log)
963*38fd1498Szrj {
964*38fd1498Szrj return iterative_hash_expr (log->addr, 0);
965*38fd1498Szrj }
966*38fd1498Szrj
967*38fd1498Szrj /* Htab support. Return true if two log entries are the same. */
968*38fd1498Szrj inline bool
equal(const tm_log_entry * log1,const tm_log_entry * log2)969*38fd1498Szrj log_entry_hasher::equal (const tm_log_entry *log1, const tm_log_entry *log2)
970*38fd1498Szrj {
971*38fd1498Szrj /* FIXME:
972*38fd1498Szrj
973*38fd1498Szrj rth: I suggest that we get rid of the component refs etc.
974*38fd1498Szrj I.e. resolve the reference to base + offset.
975*38fd1498Szrj
976*38fd1498Szrj We may need to actually finish a merge with mainline for this,
977*38fd1498Szrj since we'd like to be presented with Richi's MEM_REF_EXPRs more
978*38fd1498Szrj often than not. But in the meantime your tm_log_entry could save
979*38fd1498Szrj the results of get_inner_reference.
980*38fd1498Szrj
981*38fd1498Szrj See: g++.dg/tm/pr46653.C
982*38fd1498Szrj */
983*38fd1498Szrj
984*38fd1498Szrj /* Special case plain equality because operand_equal_p() below will
985*38fd1498Szrj return FALSE if the addresses are equal but they have
986*38fd1498Szrj side-effects (e.g. a volatile address). */
987*38fd1498Szrj if (log1->addr == log2->addr)
988*38fd1498Szrj return true;
989*38fd1498Szrj
990*38fd1498Szrj return operand_equal_p (log1->addr, log2->addr, 0);
991*38fd1498Szrj }
992*38fd1498Szrj
993*38fd1498Szrj /* Htab support. Free one tm_log_entry. */
994*38fd1498Szrj inline void
remove(tm_log_entry * lp)995*38fd1498Szrj log_entry_hasher::remove (tm_log_entry *lp)
996*38fd1498Szrj {
997*38fd1498Szrj lp->stmts.release ();
998*38fd1498Szrj free (lp);
999*38fd1498Szrj }
1000*38fd1498Szrj
1001*38fd1498Szrj
1002*38fd1498Szrj /* The actual log. */
1003*38fd1498Szrj static hash_table<log_entry_hasher> *tm_log;
1004*38fd1498Szrj
1005*38fd1498Szrj /* Addresses to log with a save/restore sequence. These should be in
1006*38fd1498Szrj dominator order. */
1007*38fd1498Szrj static vec<tree> tm_log_save_addresses;
1008*38fd1498Szrj
1009*38fd1498Szrj enum thread_memory_type
1010*38fd1498Szrj {
1011*38fd1498Szrj mem_non_local = 0,
1012*38fd1498Szrj mem_thread_local,
1013*38fd1498Szrj mem_transaction_local,
1014*38fd1498Szrj mem_max
1015*38fd1498Szrj };
1016*38fd1498Szrj
1017*38fd1498Szrj struct tm_new_mem_map
1018*38fd1498Szrj {
1019*38fd1498Szrj /* SSA_NAME being dereferenced. */
1020*38fd1498Szrj tree val;
1021*38fd1498Szrj enum thread_memory_type local_new_memory;
1022*38fd1498Szrj };
1023*38fd1498Szrj
1024*38fd1498Szrj /* Hashtable helpers. */
1025*38fd1498Szrj
1026*38fd1498Szrj struct tm_mem_map_hasher : free_ptr_hash <tm_new_mem_map>
1027*38fd1498Szrj {
1028*38fd1498Szrj static inline hashval_t hash (const tm_new_mem_map *);
1029*38fd1498Szrj static inline bool equal (const tm_new_mem_map *, const tm_new_mem_map *);
1030*38fd1498Szrj };
1031*38fd1498Szrj
1032*38fd1498Szrj inline hashval_t
hash(const tm_new_mem_map * v)1033*38fd1498Szrj tm_mem_map_hasher::hash (const tm_new_mem_map *v)
1034*38fd1498Szrj {
1035*38fd1498Szrj return (intptr_t)v->val >> 4;
1036*38fd1498Szrj }
1037*38fd1498Szrj
1038*38fd1498Szrj inline bool
equal(const tm_new_mem_map * v,const tm_new_mem_map * c)1039*38fd1498Szrj tm_mem_map_hasher::equal (const tm_new_mem_map *v, const tm_new_mem_map *c)
1040*38fd1498Szrj {
1041*38fd1498Szrj return v->val == c->val;
1042*38fd1498Szrj }
1043*38fd1498Szrj
1044*38fd1498Szrj /* Map for an SSA_NAME originally pointing to a non aliased new piece
1045*38fd1498Szrj of memory (malloc, alloc, etc). */
1046*38fd1498Szrj static hash_table<tm_mem_map_hasher> *tm_new_mem_hash;
1047*38fd1498Szrj
1048*38fd1498Szrj /* Initialize logging data structures. */
1049*38fd1498Szrj static void
tm_log_init(void)1050*38fd1498Szrj tm_log_init (void)
1051*38fd1498Szrj {
1052*38fd1498Szrj tm_log = new hash_table<log_entry_hasher> (10);
1053*38fd1498Szrj tm_new_mem_hash = new hash_table<tm_mem_map_hasher> (5);
1054*38fd1498Szrj tm_log_save_addresses.create (5);
1055*38fd1498Szrj }
1056*38fd1498Szrj
1057*38fd1498Szrj /* Free logging data structures. */
1058*38fd1498Szrj static void
tm_log_delete(void)1059*38fd1498Szrj tm_log_delete (void)
1060*38fd1498Szrj {
1061*38fd1498Szrj delete tm_log;
1062*38fd1498Szrj tm_log = NULL;
1063*38fd1498Szrj delete tm_new_mem_hash;
1064*38fd1498Szrj tm_new_mem_hash = NULL;
1065*38fd1498Szrj tm_log_save_addresses.release ();
1066*38fd1498Szrj }
1067*38fd1498Szrj
1068*38fd1498Szrj /* Return true if MEM is a transaction invariant memory for the TM
1069*38fd1498Szrj region starting at REGION_ENTRY_BLOCK. */
1070*38fd1498Szrj static bool
transaction_invariant_address_p(const_tree mem,basic_block region_entry_block)1071*38fd1498Szrj transaction_invariant_address_p (const_tree mem, basic_block region_entry_block)
1072*38fd1498Szrj {
1073*38fd1498Szrj if ((TREE_CODE (mem) == INDIRECT_REF || TREE_CODE (mem) == MEM_REF)
1074*38fd1498Szrj && TREE_CODE (TREE_OPERAND (mem, 0)) == SSA_NAME)
1075*38fd1498Szrj {
1076*38fd1498Szrj basic_block def_bb;
1077*38fd1498Szrj
1078*38fd1498Szrj def_bb = gimple_bb (SSA_NAME_DEF_STMT (TREE_OPERAND (mem, 0)));
1079*38fd1498Szrj return def_bb != region_entry_block
1080*38fd1498Szrj && dominated_by_p (CDI_DOMINATORS, region_entry_block, def_bb);
1081*38fd1498Szrj }
1082*38fd1498Szrj
1083*38fd1498Szrj mem = strip_invariant_refs (mem);
1084*38fd1498Szrj return mem && (CONSTANT_CLASS_P (mem) || decl_address_invariant_p (mem));
1085*38fd1498Szrj }
1086*38fd1498Szrj
1087*38fd1498Szrj /* Given an address ADDR in STMT, find it in the memory log or add it,
1088*38fd1498Szrj making sure to keep only the addresses highest in the dominator
1089*38fd1498Szrj tree.
1090*38fd1498Szrj
1091*38fd1498Szrj ENTRY_BLOCK is the entry_block for the transaction.
1092*38fd1498Szrj
1093*38fd1498Szrj If we find the address in the log, make sure it's either the same
1094*38fd1498Szrj address, or an equivalent one that dominates ADDR.
1095*38fd1498Szrj
1096*38fd1498Szrj If we find the address, but neither ADDR dominates the found
1097*38fd1498Szrj address, nor the found one dominates ADDR, we're on different
1098*38fd1498Szrj execution paths. Add it.
1099*38fd1498Szrj
1100*38fd1498Szrj If known, ENTRY_BLOCK is the entry block for the region, otherwise
1101*38fd1498Szrj NULL. */
1102*38fd1498Szrj static void
tm_log_add(basic_block entry_block,tree addr,gimple * stmt)1103*38fd1498Szrj tm_log_add (basic_block entry_block, tree addr, gimple *stmt)
1104*38fd1498Szrj {
1105*38fd1498Szrj tm_log_entry **slot;
1106*38fd1498Szrj struct tm_log_entry l, *lp;
1107*38fd1498Szrj
1108*38fd1498Szrj l.addr = addr;
1109*38fd1498Szrj slot = tm_log->find_slot (&l, INSERT);
1110*38fd1498Szrj if (!*slot)
1111*38fd1498Szrj {
1112*38fd1498Szrj tree type = TREE_TYPE (addr);
1113*38fd1498Szrj
1114*38fd1498Szrj lp = XNEW (struct tm_log_entry);
1115*38fd1498Szrj lp->addr = addr;
1116*38fd1498Szrj *slot = lp;
1117*38fd1498Szrj
1118*38fd1498Szrj /* Small invariant addresses can be handled as save/restores. */
1119*38fd1498Szrj if (entry_block
1120*38fd1498Szrj && transaction_invariant_address_p (lp->addr, entry_block)
1121*38fd1498Szrj && TYPE_SIZE_UNIT (type) != NULL
1122*38fd1498Szrj && tree_fits_uhwi_p (TYPE_SIZE_UNIT (type))
1123*38fd1498Szrj && ((HOST_WIDE_INT) tree_to_uhwi (TYPE_SIZE_UNIT (type))
1124*38fd1498Szrj < PARAM_VALUE (PARAM_TM_MAX_AGGREGATE_SIZE))
1125*38fd1498Szrj /* We must be able to copy this type normally. I.e., no
1126*38fd1498Szrj special constructors and the like. */
1127*38fd1498Szrj && !TREE_ADDRESSABLE (type))
1128*38fd1498Szrj {
1129*38fd1498Szrj lp->save_var = create_tmp_reg (TREE_TYPE (lp->addr), "tm_save");
1130*38fd1498Szrj lp->stmts.create (0);
1131*38fd1498Szrj lp->entry_block = entry_block;
1132*38fd1498Szrj /* Save addresses separately in dominator order so we don't
1133*38fd1498Szrj get confused by overlapping addresses in the save/restore
1134*38fd1498Szrj sequence. */
1135*38fd1498Szrj tm_log_save_addresses.safe_push (lp->addr);
1136*38fd1498Szrj }
1137*38fd1498Szrj else
1138*38fd1498Szrj {
1139*38fd1498Szrj /* Use the logging functions. */
1140*38fd1498Szrj lp->stmts.create (5);
1141*38fd1498Szrj lp->stmts.quick_push (stmt);
1142*38fd1498Szrj lp->save_var = NULL;
1143*38fd1498Szrj }
1144*38fd1498Szrj }
1145*38fd1498Szrj else
1146*38fd1498Szrj {
1147*38fd1498Szrj size_t i;
1148*38fd1498Szrj gimple *oldstmt;
1149*38fd1498Szrj
1150*38fd1498Szrj lp = *slot;
1151*38fd1498Szrj
1152*38fd1498Szrj /* If we're generating a save/restore sequence, we don't care
1153*38fd1498Szrj about statements. */
1154*38fd1498Szrj if (lp->save_var)
1155*38fd1498Szrj return;
1156*38fd1498Szrj
1157*38fd1498Szrj for (i = 0; lp->stmts.iterate (i, &oldstmt); ++i)
1158*38fd1498Szrj {
1159*38fd1498Szrj if (stmt == oldstmt)
1160*38fd1498Szrj return;
1161*38fd1498Szrj /* We already have a store to the same address, higher up the
1162*38fd1498Szrj dominator tree. Nothing to do. */
1163*38fd1498Szrj if (dominated_by_p (CDI_DOMINATORS,
1164*38fd1498Szrj gimple_bb (stmt), gimple_bb (oldstmt)))
1165*38fd1498Szrj return;
1166*38fd1498Szrj /* We should be processing blocks in dominator tree order. */
1167*38fd1498Szrj gcc_assert (!dominated_by_p (CDI_DOMINATORS,
1168*38fd1498Szrj gimple_bb (oldstmt), gimple_bb (stmt)));
1169*38fd1498Szrj }
1170*38fd1498Szrj /* Store is on a different code path. */
1171*38fd1498Szrj lp->stmts.safe_push (stmt);
1172*38fd1498Szrj }
1173*38fd1498Szrj }
1174*38fd1498Szrj
1175*38fd1498Szrj /* Gimplify the address of a TARGET_MEM_REF. Return the SSA_NAME
1176*38fd1498Szrj result, insert the new statements before GSI. */
1177*38fd1498Szrj
1178*38fd1498Szrj static tree
gimplify_addr(gimple_stmt_iterator * gsi,tree x)1179*38fd1498Szrj gimplify_addr (gimple_stmt_iterator *gsi, tree x)
1180*38fd1498Szrj {
1181*38fd1498Szrj if (TREE_CODE (x) == TARGET_MEM_REF)
1182*38fd1498Szrj x = tree_mem_ref_addr (build_pointer_type (TREE_TYPE (x)), x);
1183*38fd1498Szrj else
1184*38fd1498Szrj x = build_fold_addr_expr (x);
1185*38fd1498Szrj return force_gimple_operand_gsi (gsi, x, true, NULL, true, GSI_SAME_STMT);
1186*38fd1498Szrj }
1187*38fd1498Szrj
1188*38fd1498Szrj /* Instrument one address with the logging functions.
1189*38fd1498Szrj ADDR is the address to save.
1190*38fd1498Szrj STMT is the statement before which to place it. */
1191*38fd1498Szrj static void
tm_log_emit_stmt(tree addr,gimple * stmt)1192*38fd1498Szrj tm_log_emit_stmt (tree addr, gimple *stmt)
1193*38fd1498Szrj {
1194*38fd1498Szrj tree type = TREE_TYPE (addr);
1195*38fd1498Szrj gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
1196*38fd1498Szrj gimple *log;
1197*38fd1498Szrj enum built_in_function code = BUILT_IN_TM_LOG;
1198*38fd1498Szrj
1199*38fd1498Szrj if (type == float_type_node)
1200*38fd1498Szrj code = BUILT_IN_TM_LOG_FLOAT;
1201*38fd1498Szrj else if (type == double_type_node)
1202*38fd1498Szrj code = BUILT_IN_TM_LOG_DOUBLE;
1203*38fd1498Szrj else if (type == long_double_type_node)
1204*38fd1498Szrj code = BUILT_IN_TM_LOG_LDOUBLE;
1205*38fd1498Szrj else if (TYPE_SIZE (type) != NULL
1206*38fd1498Szrj && tree_fits_uhwi_p (TYPE_SIZE (type)))
1207*38fd1498Szrj {
1208*38fd1498Szrj unsigned HOST_WIDE_INT type_size = tree_to_uhwi (TYPE_SIZE (type));
1209*38fd1498Szrj
1210*38fd1498Szrj if (TREE_CODE (type) == VECTOR_TYPE)
1211*38fd1498Szrj {
1212*38fd1498Szrj switch (type_size)
1213*38fd1498Szrj {
1214*38fd1498Szrj case 64:
1215*38fd1498Szrj code = BUILT_IN_TM_LOG_M64;
1216*38fd1498Szrj break;
1217*38fd1498Szrj case 128:
1218*38fd1498Szrj code = BUILT_IN_TM_LOG_M128;
1219*38fd1498Szrj break;
1220*38fd1498Szrj case 256:
1221*38fd1498Szrj code = BUILT_IN_TM_LOG_M256;
1222*38fd1498Szrj break;
1223*38fd1498Szrj default:
1224*38fd1498Szrj goto unhandled_vec;
1225*38fd1498Szrj }
1226*38fd1498Szrj if (!builtin_decl_explicit_p (code))
1227*38fd1498Szrj goto unhandled_vec;
1228*38fd1498Szrj }
1229*38fd1498Szrj else
1230*38fd1498Szrj {
1231*38fd1498Szrj unhandled_vec:
1232*38fd1498Szrj switch (type_size)
1233*38fd1498Szrj {
1234*38fd1498Szrj case 8:
1235*38fd1498Szrj code = BUILT_IN_TM_LOG_1;
1236*38fd1498Szrj break;
1237*38fd1498Szrj case 16:
1238*38fd1498Szrj code = BUILT_IN_TM_LOG_2;
1239*38fd1498Szrj break;
1240*38fd1498Szrj case 32:
1241*38fd1498Szrj code = BUILT_IN_TM_LOG_4;
1242*38fd1498Szrj break;
1243*38fd1498Szrj case 64:
1244*38fd1498Szrj code = BUILT_IN_TM_LOG_8;
1245*38fd1498Szrj break;
1246*38fd1498Szrj }
1247*38fd1498Szrj }
1248*38fd1498Szrj }
1249*38fd1498Szrj
1250*38fd1498Szrj if (code != BUILT_IN_TM_LOG && !builtin_decl_explicit_p (code))
1251*38fd1498Szrj code = BUILT_IN_TM_LOG;
1252*38fd1498Szrj tree decl = builtin_decl_explicit (code);
1253*38fd1498Szrj
1254*38fd1498Szrj addr = gimplify_addr (&gsi, addr);
1255*38fd1498Szrj if (code == BUILT_IN_TM_LOG)
1256*38fd1498Szrj log = gimple_build_call (decl, 2, addr, TYPE_SIZE_UNIT (type));
1257*38fd1498Szrj else
1258*38fd1498Szrj log = gimple_build_call (decl, 1, addr);
1259*38fd1498Szrj gsi_insert_before (&gsi, log, GSI_SAME_STMT);
1260*38fd1498Szrj }
1261*38fd1498Szrj
1262*38fd1498Szrj /* Go through the log and instrument address that must be instrumented
1263*38fd1498Szrj with the logging functions. Leave the save/restore addresses for
1264*38fd1498Szrj later. */
1265*38fd1498Szrj static void
tm_log_emit(void)1266*38fd1498Szrj tm_log_emit (void)
1267*38fd1498Szrj {
1268*38fd1498Szrj hash_table<log_entry_hasher>::iterator hi;
1269*38fd1498Szrj struct tm_log_entry *lp;
1270*38fd1498Szrj
1271*38fd1498Szrj FOR_EACH_HASH_TABLE_ELEMENT (*tm_log, lp, tm_log_entry_t, hi)
1272*38fd1498Szrj {
1273*38fd1498Szrj size_t i;
1274*38fd1498Szrj gimple *stmt;
1275*38fd1498Szrj
1276*38fd1498Szrj if (dump_file)
1277*38fd1498Szrj {
1278*38fd1498Szrj fprintf (dump_file, "TM thread private mem logging: ");
1279*38fd1498Szrj print_generic_expr (dump_file, lp->addr);
1280*38fd1498Szrj fprintf (dump_file, "\n");
1281*38fd1498Szrj }
1282*38fd1498Szrj
1283*38fd1498Szrj if (lp->save_var)
1284*38fd1498Szrj {
1285*38fd1498Szrj if (dump_file)
1286*38fd1498Szrj fprintf (dump_file, "DUMPING to variable\n");
1287*38fd1498Szrj continue;
1288*38fd1498Szrj }
1289*38fd1498Szrj else
1290*38fd1498Szrj {
1291*38fd1498Szrj if (dump_file)
1292*38fd1498Szrj fprintf (dump_file, "DUMPING with logging functions\n");
1293*38fd1498Szrj for (i = 0; lp->stmts.iterate (i, &stmt); ++i)
1294*38fd1498Szrj tm_log_emit_stmt (lp->addr, stmt);
1295*38fd1498Szrj }
1296*38fd1498Szrj }
1297*38fd1498Szrj }
1298*38fd1498Szrj
1299*38fd1498Szrj /* Emit the save sequence for the corresponding addresses in the log.
1300*38fd1498Szrj ENTRY_BLOCK is the entry block for the transaction.
1301*38fd1498Szrj BB is the basic block to insert the code in. */
1302*38fd1498Szrj static void
tm_log_emit_saves(basic_block entry_block,basic_block bb)1303*38fd1498Szrj tm_log_emit_saves (basic_block entry_block, basic_block bb)
1304*38fd1498Szrj {
1305*38fd1498Szrj size_t i;
1306*38fd1498Szrj gimple_stmt_iterator gsi = gsi_last_bb (bb);
1307*38fd1498Szrj gimple *stmt;
1308*38fd1498Szrj struct tm_log_entry l, *lp;
1309*38fd1498Szrj
1310*38fd1498Szrj for (i = 0; i < tm_log_save_addresses.length (); ++i)
1311*38fd1498Szrj {
1312*38fd1498Szrj l.addr = tm_log_save_addresses[i];
1313*38fd1498Szrj lp = *(tm_log->find_slot (&l, NO_INSERT));
1314*38fd1498Szrj gcc_assert (lp->save_var != NULL);
1315*38fd1498Szrj
1316*38fd1498Szrj /* We only care about variables in the current transaction. */
1317*38fd1498Szrj if (lp->entry_block != entry_block)
1318*38fd1498Szrj continue;
1319*38fd1498Szrj
1320*38fd1498Szrj stmt = gimple_build_assign (lp->save_var, unshare_expr (lp->addr));
1321*38fd1498Szrj
1322*38fd1498Szrj /* Make sure we can create an SSA_NAME for this type. For
1323*38fd1498Szrj instance, aggregates aren't allowed, in which case the system
1324*38fd1498Szrj will create a VOP for us and everything will just work. */
1325*38fd1498Szrj if (is_gimple_reg_type (TREE_TYPE (lp->save_var)))
1326*38fd1498Szrj {
1327*38fd1498Szrj lp->save_var = make_ssa_name (lp->save_var, stmt);
1328*38fd1498Szrj gimple_assign_set_lhs (stmt, lp->save_var);
1329*38fd1498Szrj }
1330*38fd1498Szrj
1331*38fd1498Szrj gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
1332*38fd1498Szrj }
1333*38fd1498Szrj }
1334*38fd1498Szrj
1335*38fd1498Szrj /* Emit the restore sequence for the corresponding addresses in the log.
1336*38fd1498Szrj ENTRY_BLOCK is the entry block for the transaction.
1337*38fd1498Szrj BB is the basic block to insert the code in. */
1338*38fd1498Szrj static void
tm_log_emit_restores(basic_block entry_block,basic_block bb)1339*38fd1498Szrj tm_log_emit_restores (basic_block entry_block, basic_block bb)
1340*38fd1498Szrj {
1341*38fd1498Szrj int i;
1342*38fd1498Szrj struct tm_log_entry l, *lp;
1343*38fd1498Szrj gimple_stmt_iterator gsi;
1344*38fd1498Szrj gimple *stmt;
1345*38fd1498Szrj
1346*38fd1498Szrj for (i = tm_log_save_addresses.length () - 1; i >= 0; i--)
1347*38fd1498Szrj {
1348*38fd1498Szrj l.addr = tm_log_save_addresses[i];
1349*38fd1498Szrj lp = *(tm_log->find_slot (&l, NO_INSERT));
1350*38fd1498Szrj gcc_assert (lp->save_var != NULL);
1351*38fd1498Szrj
1352*38fd1498Szrj /* We only care about variables in the current transaction. */
1353*38fd1498Szrj if (lp->entry_block != entry_block)
1354*38fd1498Szrj continue;
1355*38fd1498Szrj
1356*38fd1498Szrj /* Restores are in LIFO order from the saves in case we have
1357*38fd1498Szrj overlaps. */
1358*38fd1498Szrj gsi = gsi_start_bb (bb);
1359*38fd1498Szrj
1360*38fd1498Szrj stmt = gimple_build_assign (unshare_expr (lp->addr), lp->save_var);
1361*38fd1498Szrj gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
1362*38fd1498Szrj }
1363*38fd1498Szrj }
1364*38fd1498Szrj
1365*38fd1498Szrj
1366*38fd1498Szrj static tree lower_sequence_tm (gimple_stmt_iterator *, bool *,
1367*38fd1498Szrj struct walk_stmt_info *);
1368*38fd1498Szrj static tree lower_sequence_no_tm (gimple_stmt_iterator *, bool *,
1369*38fd1498Szrj struct walk_stmt_info *);
1370*38fd1498Szrj
1371*38fd1498Szrj /* Evaluate an address X being dereferenced and determine if it
1372*38fd1498Szrj originally points to a non aliased new chunk of memory (malloc,
1373*38fd1498Szrj alloca, etc).
1374*38fd1498Szrj
1375*38fd1498Szrj Return MEM_THREAD_LOCAL if it points to a thread-local address.
1376*38fd1498Szrj Return MEM_TRANSACTION_LOCAL if it points to a transaction-local address.
1377*38fd1498Szrj Return MEM_NON_LOCAL otherwise.
1378*38fd1498Szrj
1379*38fd1498Szrj ENTRY_BLOCK is the entry block to the transaction containing the
1380*38fd1498Szrj dereference of X. */
1381*38fd1498Szrj static enum thread_memory_type
thread_private_new_memory(basic_block entry_block,tree x)1382*38fd1498Szrj thread_private_new_memory (basic_block entry_block, tree x)
1383*38fd1498Szrj {
1384*38fd1498Szrj gimple *stmt = NULL;
1385*38fd1498Szrj enum tree_code code;
1386*38fd1498Szrj tm_new_mem_map **slot;
1387*38fd1498Szrj tm_new_mem_map elt, *elt_p;
1388*38fd1498Szrj tree val = x;
1389*38fd1498Szrj enum thread_memory_type retval = mem_transaction_local;
1390*38fd1498Szrj
1391*38fd1498Szrj if (!entry_block
1392*38fd1498Szrj || TREE_CODE (x) != SSA_NAME
1393*38fd1498Szrj /* Possible uninitialized use, or a function argument. In
1394*38fd1498Szrj either case, we don't care. */
1395*38fd1498Szrj || SSA_NAME_IS_DEFAULT_DEF (x))
1396*38fd1498Szrj return mem_non_local;
1397*38fd1498Szrj
1398*38fd1498Szrj /* Look in cache first. */
1399*38fd1498Szrj elt.val = x;
1400*38fd1498Szrj slot = tm_new_mem_hash->find_slot (&elt, INSERT);
1401*38fd1498Szrj elt_p = *slot;
1402*38fd1498Szrj if (elt_p)
1403*38fd1498Szrj return elt_p->local_new_memory;
1404*38fd1498Szrj
1405*38fd1498Szrj /* Optimistically assume the memory is transaction local during
1406*38fd1498Szrj processing. This catches recursion into this variable. */
1407*38fd1498Szrj *slot = elt_p = XNEW (tm_new_mem_map);
1408*38fd1498Szrj elt_p->val = val;
1409*38fd1498Szrj elt_p->local_new_memory = mem_transaction_local;
1410*38fd1498Szrj
1411*38fd1498Szrj /* Search DEF chain to find the original definition of this address. */
1412*38fd1498Szrj do
1413*38fd1498Szrj {
1414*38fd1498Szrj if (ptr_deref_may_alias_global_p (x))
1415*38fd1498Szrj {
1416*38fd1498Szrj /* Address escapes. This is not thread-private. */
1417*38fd1498Szrj retval = mem_non_local;
1418*38fd1498Szrj goto new_memory_ret;
1419*38fd1498Szrj }
1420*38fd1498Szrj
1421*38fd1498Szrj stmt = SSA_NAME_DEF_STMT (x);
1422*38fd1498Szrj
1423*38fd1498Szrj /* If the malloc call is outside the transaction, this is
1424*38fd1498Szrj thread-local. */
1425*38fd1498Szrj if (retval != mem_thread_local
1426*38fd1498Szrj && !dominated_by_p (CDI_DOMINATORS, gimple_bb (stmt), entry_block))
1427*38fd1498Szrj retval = mem_thread_local;
1428*38fd1498Szrj
1429*38fd1498Szrj if (is_gimple_assign (stmt))
1430*38fd1498Szrj {
1431*38fd1498Szrj code = gimple_assign_rhs_code (stmt);
1432*38fd1498Szrj /* x = foo ==> foo */
1433*38fd1498Szrj if (code == SSA_NAME)
1434*38fd1498Szrj x = gimple_assign_rhs1 (stmt);
1435*38fd1498Szrj /* x = foo + n ==> foo */
1436*38fd1498Szrj else if (code == POINTER_PLUS_EXPR)
1437*38fd1498Szrj x = gimple_assign_rhs1 (stmt);
1438*38fd1498Szrj /* x = (cast*) foo ==> foo */
1439*38fd1498Szrj else if (code == VIEW_CONVERT_EXPR || CONVERT_EXPR_CODE_P (code))
1440*38fd1498Szrj x = gimple_assign_rhs1 (stmt);
1441*38fd1498Szrj /* x = c ? op1 : op2 == > op1 or op2 just like a PHI */
1442*38fd1498Szrj else if (code == COND_EXPR)
1443*38fd1498Szrj {
1444*38fd1498Szrj tree op1 = gimple_assign_rhs2 (stmt);
1445*38fd1498Szrj tree op2 = gimple_assign_rhs3 (stmt);
1446*38fd1498Szrj enum thread_memory_type mem;
1447*38fd1498Szrj retval = thread_private_new_memory (entry_block, op1);
1448*38fd1498Szrj if (retval == mem_non_local)
1449*38fd1498Szrj goto new_memory_ret;
1450*38fd1498Szrj mem = thread_private_new_memory (entry_block, op2);
1451*38fd1498Szrj retval = MIN (retval, mem);
1452*38fd1498Szrj goto new_memory_ret;
1453*38fd1498Szrj }
1454*38fd1498Szrj else
1455*38fd1498Szrj {
1456*38fd1498Szrj retval = mem_non_local;
1457*38fd1498Szrj goto new_memory_ret;
1458*38fd1498Szrj }
1459*38fd1498Szrj }
1460*38fd1498Szrj else
1461*38fd1498Szrj {
1462*38fd1498Szrj if (gimple_code (stmt) == GIMPLE_PHI)
1463*38fd1498Szrj {
1464*38fd1498Szrj unsigned int i;
1465*38fd1498Szrj enum thread_memory_type mem;
1466*38fd1498Szrj tree phi_result = gimple_phi_result (stmt);
1467*38fd1498Szrj
1468*38fd1498Szrj /* If any of the ancestors are non-local, we are sure to
1469*38fd1498Szrj be non-local. Otherwise we can avoid doing anything
1470*38fd1498Szrj and inherit what has already been generated. */
1471*38fd1498Szrj retval = mem_max;
1472*38fd1498Szrj for (i = 0; i < gimple_phi_num_args (stmt); ++i)
1473*38fd1498Szrj {
1474*38fd1498Szrj tree op = PHI_ARG_DEF (stmt, i);
1475*38fd1498Szrj
1476*38fd1498Szrj /* Exclude self-assignment. */
1477*38fd1498Szrj if (phi_result == op)
1478*38fd1498Szrj continue;
1479*38fd1498Szrj
1480*38fd1498Szrj mem = thread_private_new_memory (entry_block, op);
1481*38fd1498Szrj if (mem == mem_non_local)
1482*38fd1498Szrj {
1483*38fd1498Szrj retval = mem;
1484*38fd1498Szrj goto new_memory_ret;
1485*38fd1498Szrj }
1486*38fd1498Szrj retval = MIN (retval, mem);
1487*38fd1498Szrj }
1488*38fd1498Szrj goto new_memory_ret;
1489*38fd1498Szrj }
1490*38fd1498Szrj break;
1491*38fd1498Szrj }
1492*38fd1498Szrj }
1493*38fd1498Szrj while (TREE_CODE (x) == SSA_NAME);
1494*38fd1498Szrj
1495*38fd1498Szrj if (stmt && is_gimple_call (stmt) && gimple_call_flags (stmt) & ECF_MALLOC)
1496*38fd1498Szrj /* Thread-local or transaction-local. */
1497*38fd1498Szrj ;
1498*38fd1498Szrj else
1499*38fd1498Szrj retval = mem_non_local;
1500*38fd1498Szrj
1501*38fd1498Szrj new_memory_ret:
1502*38fd1498Szrj elt_p->local_new_memory = retval;
1503*38fd1498Szrj return retval;
1504*38fd1498Szrj }
1505*38fd1498Szrj
1506*38fd1498Szrj /* Determine whether X has to be instrumented using a read
1507*38fd1498Szrj or write barrier.
1508*38fd1498Szrj
1509*38fd1498Szrj ENTRY_BLOCK is the entry block for the region where stmt resides
1510*38fd1498Szrj in. NULL if unknown.
1511*38fd1498Szrj
1512*38fd1498Szrj STMT is the statement in which X occurs in. It is used for thread
1513*38fd1498Szrj private memory instrumentation. If no TPM instrumentation is
1514*38fd1498Szrj desired, STMT should be null. */
1515*38fd1498Szrj static bool
requires_barrier(basic_block entry_block,tree x,gimple * stmt)1516*38fd1498Szrj requires_barrier (basic_block entry_block, tree x, gimple *stmt)
1517*38fd1498Szrj {
1518*38fd1498Szrj tree orig = x;
1519*38fd1498Szrj while (handled_component_p (x))
1520*38fd1498Szrj x = TREE_OPERAND (x, 0);
1521*38fd1498Szrj
1522*38fd1498Szrj switch (TREE_CODE (x))
1523*38fd1498Szrj {
1524*38fd1498Szrj case INDIRECT_REF:
1525*38fd1498Szrj case MEM_REF:
1526*38fd1498Szrj {
1527*38fd1498Szrj enum thread_memory_type ret;
1528*38fd1498Szrj
1529*38fd1498Szrj ret = thread_private_new_memory (entry_block, TREE_OPERAND (x, 0));
1530*38fd1498Szrj if (ret == mem_non_local)
1531*38fd1498Szrj return true;
1532*38fd1498Szrj if (stmt && ret == mem_thread_local)
1533*38fd1498Szrj /* ?? Should we pass `orig', or the INDIRECT_REF X. ?? */
1534*38fd1498Szrj tm_log_add (entry_block, orig, stmt);
1535*38fd1498Szrj
1536*38fd1498Szrj /* Transaction-locals require nothing at all. For malloc, a
1537*38fd1498Szrj transaction restart frees the memory and we reallocate.
1538*38fd1498Szrj For alloca, the stack pointer gets reset by the retry and
1539*38fd1498Szrj we reallocate. */
1540*38fd1498Szrj return false;
1541*38fd1498Szrj }
1542*38fd1498Szrj
1543*38fd1498Szrj case TARGET_MEM_REF:
1544*38fd1498Szrj if (TREE_CODE (TMR_BASE (x)) != ADDR_EXPR)
1545*38fd1498Szrj return true;
1546*38fd1498Szrj x = TREE_OPERAND (TMR_BASE (x), 0);
1547*38fd1498Szrj if (TREE_CODE (x) == PARM_DECL)
1548*38fd1498Szrj return false;
1549*38fd1498Szrj gcc_assert (VAR_P (x));
1550*38fd1498Szrj /* FALLTHRU */
1551*38fd1498Szrj
1552*38fd1498Szrj case PARM_DECL:
1553*38fd1498Szrj case RESULT_DECL:
1554*38fd1498Szrj case VAR_DECL:
1555*38fd1498Szrj if (DECL_BY_REFERENCE (x))
1556*38fd1498Szrj {
1557*38fd1498Szrj /* ??? This value is a pointer, but aggregate_value_p has been
1558*38fd1498Szrj jigged to return true which confuses needs_to_live_in_memory.
1559*38fd1498Szrj This ought to be cleaned up generically.
1560*38fd1498Szrj
1561*38fd1498Szrj FIXME: Verify this still happens after the next mainline
1562*38fd1498Szrj merge. Testcase ie g++.dg/tm/pr47554.C.
1563*38fd1498Szrj */
1564*38fd1498Szrj return false;
1565*38fd1498Szrj }
1566*38fd1498Szrj
1567*38fd1498Szrj if (is_global_var (x))
1568*38fd1498Szrj return !TREE_READONLY (x);
1569*38fd1498Szrj if (/* FIXME: This condition should actually go below in the
1570*38fd1498Szrj tm_log_add() call, however is_call_clobbered() depends on
1571*38fd1498Szrj aliasing info which is not available during
1572*38fd1498Szrj gimplification. Since requires_barrier() gets called
1573*38fd1498Szrj during lower_sequence_tm/gimplification, leave the call
1574*38fd1498Szrj to needs_to_live_in_memory until we eliminate
1575*38fd1498Szrj lower_sequence_tm altogether. */
1576*38fd1498Szrj needs_to_live_in_memory (x))
1577*38fd1498Szrj return true;
1578*38fd1498Szrj else
1579*38fd1498Szrj {
1580*38fd1498Szrj /* For local memory that doesn't escape (aka thread private
1581*38fd1498Szrj memory), we can either save the value at the beginning of
1582*38fd1498Szrj the transaction and restore on restart, or call a tm
1583*38fd1498Szrj function to dynamically save and restore on restart
1584*38fd1498Szrj (ITM_L*). */
1585*38fd1498Szrj if (stmt)
1586*38fd1498Szrj tm_log_add (entry_block, orig, stmt);
1587*38fd1498Szrj return false;
1588*38fd1498Szrj }
1589*38fd1498Szrj
1590*38fd1498Szrj default:
1591*38fd1498Szrj return false;
1592*38fd1498Szrj }
1593*38fd1498Szrj }
1594*38fd1498Szrj
1595*38fd1498Szrj /* Mark the GIMPLE_ASSIGN statement as appropriate for being inside
1596*38fd1498Szrj a transaction region. */
1597*38fd1498Szrj
1598*38fd1498Szrj static void
examine_assign_tm(unsigned * state,gimple_stmt_iterator * gsi)1599*38fd1498Szrj examine_assign_tm (unsigned *state, gimple_stmt_iterator *gsi)
1600*38fd1498Szrj {
1601*38fd1498Szrj gimple *stmt = gsi_stmt (*gsi);
1602*38fd1498Szrj
1603*38fd1498Szrj if (requires_barrier (/*entry_block=*/NULL, gimple_assign_rhs1 (stmt), NULL))
1604*38fd1498Szrj *state |= GTMA_HAVE_LOAD;
1605*38fd1498Szrj if (requires_barrier (/*entry_block=*/NULL, gimple_assign_lhs (stmt), NULL))
1606*38fd1498Szrj *state |= GTMA_HAVE_STORE;
1607*38fd1498Szrj }
1608*38fd1498Szrj
1609*38fd1498Szrj /* Mark a GIMPLE_CALL as appropriate for being inside a transaction. */
1610*38fd1498Szrj
1611*38fd1498Szrj static void
examine_call_tm(unsigned * state,gimple_stmt_iterator * gsi)1612*38fd1498Szrj examine_call_tm (unsigned *state, gimple_stmt_iterator *gsi)
1613*38fd1498Szrj {
1614*38fd1498Szrj gimple *stmt = gsi_stmt (*gsi);
1615*38fd1498Szrj tree fn;
1616*38fd1498Szrj
1617*38fd1498Szrj if (is_tm_pure_call (stmt))
1618*38fd1498Szrj return;
1619*38fd1498Szrj
1620*38fd1498Szrj /* Check if this call is a transaction abort. */
1621*38fd1498Szrj fn = gimple_call_fndecl (stmt);
1622*38fd1498Szrj if (is_tm_abort (fn))
1623*38fd1498Szrj *state |= GTMA_HAVE_ABORT;
1624*38fd1498Szrj
1625*38fd1498Szrj /* Note that something may happen. */
1626*38fd1498Szrj *state |= GTMA_HAVE_LOAD | GTMA_HAVE_STORE;
1627*38fd1498Szrj }
1628*38fd1498Szrj
1629*38fd1498Szrj /* Iterate through the statements in the sequence, moving labels
1630*38fd1498Szrj (and thus edges) of transactions from "label_norm" to "label_uninst". */
1631*38fd1498Szrj
1632*38fd1498Szrj static tree
make_tm_uninst(gimple_stmt_iterator * gsi,bool * handled_ops_p,struct walk_stmt_info *)1633*38fd1498Szrj make_tm_uninst (gimple_stmt_iterator *gsi, bool *handled_ops_p,
1634*38fd1498Szrj struct walk_stmt_info *)
1635*38fd1498Szrj {
1636*38fd1498Szrj gimple *stmt = gsi_stmt (*gsi);
1637*38fd1498Szrj
1638*38fd1498Szrj if (gtransaction *txn = dyn_cast <gtransaction *> (stmt))
1639*38fd1498Szrj {
1640*38fd1498Szrj *handled_ops_p = true;
1641*38fd1498Szrj txn->label_uninst = txn->label_norm;
1642*38fd1498Szrj txn->label_norm = NULL;
1643*38fd1498Szrj }
1644*38fd1498Szrj else
1645*38fd1498Szrj *handled_ops_p = !gimple_has_substatements (stmt);
1646*38fd1498Szrj
1647*38fd1498Szrj return NULL_TREE;
1648*38fd1498Szrj }
1649*38fd1498Szrj
1650*38fd1498Szrj /* Lower a GIMPLE_TRANSACTION statement. */
1651*38fd1498Szrj
1652*38fd1498Szrj static void
lower_transaction(gimple_stmt_iterator * gsi,struct walk_stmt_info * wi)1653*38fd1498Szrj lower_transaction (gimple_stmt_iterator *gsi, struct walk_stmt_info *wi)
1654*38fd1498Szrj {
1655*38fd1498Szrj gimple *g;
1656*38fd1498Szrj gtransaction *stmt = as_a <gtransaction *> (gsi_stmt (*gsi));
1657*38fd1498Szrj unsigned int *outer_state = (unsigned int *) wi->info;
1658*38fd1498Szrj unsigned int this_state = 0;
1659*38fd1498Szrj struct walk_stmt_info this_wi;
1660*38fd1498Szrj
1661*38fd1498Szrj /* First, lower the body. The scanning that we do inside gives
1662*38fd1498Szrj us some idea of what we're dealing with. */
1663*38fd1498Szrj memset (&this_wi, 0, sizeof (this_wi));
1664*38fd1498Szrj this_wi.info = (void *) &this_state;
1665*38fd1498Szrj walk_gimple_seq_mod (gimple_transaction_body_ptr (stmt),
1666*38fd1498Szrj lower_sequence_tm, NULL, &this_wi);
1667*38fd1498Szrj
1668*38fd1498Szrj /* If there was absolutely nothing transaction related inside the
1669*38fd1498Szrj transaction, we may elide it. Likewise if this is a nested
1670*38fd1498Szrj transaction and does not contain an abort. */
1671*38fd1498Szrj if (this_state == 0
1672*38fd1498Szrj || (!(this_state & GTMA_HAVE_ABORT) && outer_state != NULL))
1673*38fd1498Szrj {
1674*38fd1498Szrj if (outer_state)
1675*38fd1498Szrj *outer_state |= this_state;
1676*38fd1498Szrj
1677*38fd1498Szrj gsi_insert_seq_before (gsi, gimple_transaction_body (stmt),
1678*38fd1498Szrj GSI_SAME_STMT);
1679*38fd1498Szrj gimple_transaction_set_body (stmt, NULL);
1680*38fd1498Szrj
1681*38fd1498Szrj gsi_remove (gsi, true);
1682*38fd1498Szrj wi->removed_stmt = true;
1683*38fd1498Szrj return;
1684*38fd1498Szrj }
1685*38fd1498Szrj
1686*38fd1498Szrj /* Wrap the body of the transaction in a try-finally node so that
1687*38fd1498Szrj the commit call is always properly called. */
1688*38fd1498Szrj g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TM_COMMIT), 0);
1689*38fd1498Szrj if (flag_exceptions)
1690*38fd1498Szrj {
1691*38fd1498Szrj tree ptr;
1692*38fd1498Szrj gimple_seq n_seq, e_seq;
1693*38fd1498Szrj
1694*38fd1498Szrj n_seq = gimple_seq_alloc_with_stmt (g);
1695*38fd1498Szrj e_seq = NULL;
1696*38fd1498Szrj
1697*38fd1498Szrj g = gimple_build_call (builtin_decl_explicit (BUILT_IN_EH_POINTER),
1698*38fd1498Szrj 1, integer_zero_node);
1699*38fd1498Szrj ptr = create_tmp_var (ptr_type_node);
1700*38fd1498Szrj gimple_call_set_lhs (g, ptr);
1701*38fd1498Szrj gimple_seq_add_stmt (&e_seq, g);
1702*38fd1498Szrj
1703*38fd1498Szrj g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TM_COMMIT_EH),
1704*38fd1498Szrj 1, ptr);
1705*38fd1498Szrj gimple_seq_add_stmt (&e_seq, g);
1706*38fd1498Szrj
1707*38fd1498Szrj g = gimple_build_eh_else (n_seq, e_seq);
1708*38fd1498Szrj }
1709*38fd1498Szrj
1710*38fd1498Szrj g = gimple_build_try (gimple_transaction_body (stmt),
1711*38fd1498Szrj gimple_seq_alloc_with_stmt (g), GIMPLE_TRY_FINALLY);
1712*38fd1498Szrj
1713*38fd1498Szrj /* For a (potentially) outer transaction, create two paths. */
1714*38fd1498Szrj gimple_seq uninst = NULL;
1715*38fd1498Szrj if (outer_state == NULL)
1716*38fd1498Szrj {
1717*38fd1498Szrj uninst = copy_gimple_seq_and_replace_locals (g);
1718*38fd1498Szrj /* In the uninstrumented copy, reset inner transactions to have only
1719*38fd1498Szrj an uninstrumented code path. */
1720*38fd1498Szrj memset (&this_wi, 0, sizeof (this_wi));
1721*38fd1498Szrj walk_gimple_seq (uninst, make_tm_uninst, NULL, &this_wi);
1722*38fd1498Szrj }
1723*38fd1498Szrj
1724*38fd1498Szrj tree label1 = create_artificial_label (UNKNOWN_LOCATION);
1725*38fd1498Szrj gsi_insert_after (gsi, gimple_build_label (label1), GSI_CONTINUE_LINKING);
1726*38fd1498Szrj gsi_insert_after (gsi, g, GSI_CONTINUE_LINKING);
1727*38fd1498Szrj gimple_transaction_set_label_norm (stmt, label1);
1728*38fd1498Szrj
1729*38fd1498Szrj /* If the transaction calls abort or if this is an outer transaction,
1730*38fd1498Szrj add an "over" label afterwards. */
1731*38fd1498Szrj tree label3 = NULL;
1732*38fd1498Szrj if ((this_state & GTMA_HAVE_ABORT)
1733*38fd1498Szrj || outer_state == NULL
1734*38fd1498Szrj || (gimple_transaction_subcode (stmt) & GTMA_IS_OUTER))
1735*38fd1498Szrj {
1736*38fd1498Szrj label3 = create_artificial_label (UNKNOWN_LOCATION);
1737*38fd1498Szrj gimple_transaction_set_label_over (stmt, label3);
1738*38fd1498Szrj }
1739*38fd1498Szrj
1740*38fd1498Szrj if (uninst != NULL)
1741*38fd1498Szrj {
1742*38fd1498Szrj gsi_insert_after (gsi, gimple_build_goto (label3), GSI_CONTINUE_LINKING);
1743*38fd1498Szrj
1744*38fd1498Szrj tree label2 = create_artificial_label (UNKNOWN_LOCATION);
1745*38fd1498Szrj gsi_insert_after (gsi, gimple_build_label (label2), GSI_CONTINUE_LINKING);
1746*38fd1498Szrj gsi_insert_seq_after (gsi, uninst, GSI_CONTINUE_LINKING);
1747*38fd1498Szrj gimple_transaction_set_label_uninst (stmt, label2);
1748*38fd1498Szrj }
1749*38fd1498Szrj
1750*38fd1498Szrj if (label3 != NULL)
1751*38fd1498Szrj gsi_insert_after (gsi, gimple_build_label (label3), GSI_CONTINUE_LINKING);
1752*38fd1498Szrj
1753*38fd1498Szrj gimple_transaction_set_body (stmt, NULL);
1754*38fd1498Szrj
1755*38fd1498Szrj /* Record the set of operations found for use later. */
1756*38fd1498Szrj this_state |= gimple_transaction_subcode (stmt) & GTMA_DECLARATION_MASK;
1757*38fd1498Szrj gimple_transaction_set_subcode (stmt, this_state);
1758*38fd1498Szrj }
1759*38fd1498Szrj
1760*38fd1498Szrj /* Iterate through the statements in the sequence, lowering them all
1761*38fd1498Szrj as appropriate for being in a transaction. */
1762*38fd1498Szrj
1763*38fd1498Szrj static tree
lower_sequence_tm(gimple_stmt_iterator * gsi,bool * handled_ops_p,struct walk_stmt_info * wi)1764*38fd1498Szrj lower_sequence_tm (gimple_stmt_iterator *gsi, bool *handled_ops_p,
1765*38fd1498Szrj struct walk_stmt_info *wi)
1766*38fd1498Szrj {
1767*38fd1498Szrj unsigned int *state = (unsigned int *) wi->info;
1768*38fd1498Szrj gimple *stmt = gsi_stmt (*gsi);
1769*38fd1498Szrj
1770*38fd1498Szrj *handled_ops_p = true;
1771*38fd1498Szrj switch (gimple_code (stmt))
1772*38fd1498Szrj {
1773*38fd1498Szrj case GIMPLE_ASSIGN:
1774*38fd1498Szrj /* Only memory reads/writes need to be instrumented. */
1775*38fd1498Szrj if (gimple_assign_single_p (stmt))
1776*38fd1498Szrj examine_assign_tm (state, gsi);
1777*38fd1498Szrj break;
1778*38fd1498Szrj
1779*38fd1498Szrj case GIMPLE_CALL:
1780*38fd1498Szrj examine_call_tm (state, gsi);
1781*38fd1498Szrj break;
1782*38fd1498Szrj
1783*38fd1498Szrj case GIMPLE_ASM:
1784*38fd1498Szrj *state |= GTMA_MAY_ENTER_IRREVOCABLE;
1785*38fd1498Szrj break;
1786*38fd1498Szrj
1787*38fd1498Szrj case GIMPLE_TRANSACTION:
1788*38fd1498Szrj lower_transaction (gsi, wi);
1789*38fd1498Szrj break;
1790*38fd1498Szrj
1791*38fd1498Szrj default:
1792*38fd1498Szrj *handled_ops_p = !gimple_has_substatements (stmt);
1793*38fd1498Szrj break;
1794*38fd1498Szrj }
1795*38fd1498Szrj
1796*38fd1498Szrj return NULL_TREE;
1797*38fd1498Szrj }
1798*38fd1498Szrj
1799*38fd1498Szrj /* Iterate through the statements in the sequence, lowering them all
1800*38fd1498Szrj as appropriate for being outside of a transaction. */
1801*38fd1498Szrj
1802*38fd1498Szrj static tree
lower_sequence_no_tm(gimple_stmt_iterator * gsi,bool * handled_ops_p,struct walk_stmt_info * wi)1803*38fd1498Szrj lower_sequence_no_tm (gimple_stmt_iterator *gsi, bool *handled_ops_p,
1804*38fd1498Szrj struct walk_stmt_info * wi)
1805*38fd1498Szrj {
1806*38fd1498Szrj gimple *stmt = gsi_stmt (*gsi);
1807*38fd1498Szrj
1808*38fd1498Szrj if (gimple_code (stmt) == GIMPLE_TRANSACTION)
1809*38fd1498Szrj {
1810*38fd1498Szrj *handled_ops_p = true;
1811*38fd1498Szrj lower_transaction (gsi, wi);
1812*38fd1498Szrj }
1813*38fd1498Szrj else
1814*38fd1498Szrj *handled_ops_p = !gimple_has_substatements (stmt);
1815*38fd1498Szrj
1816*38fd1498Szrj return NULL_TREE;
1817*38fd1498Szrj }
1818*38fd1498Szrj
1819*38fd1498Szrj /* Main entry point for flattening GIMPLE_TRANSACTION constructs. After
1820*38fd1498Szrj this, GIMPLE_TRANSACTION nodes still exist, but the nested body has
1821*38fd1498Szrj been moved out, and all the data required for constructing a proper
1822*38fd1498Szrj CFG has been recorded. */
1823*38fd1498Szrj
1824*38fd1498Szrj static unsigned int
execute_lower_tm(void)1825*38fd1498Szrj execute_lower_tm (void)
1826*38fd1498Szrj {
1827*38fd1498Szrj struct walk_stmt_info wi;
1828*38fd1498Szrj gimple_seq body;
1829*38fd1498Szrj
1830*38fd1498Szrj /* Transactional clones aren't created until a later pass. */
1831*38fd1498Szrj gcc_assert (!decl_is_tm_clone (current_function_decl));
1832*38fd1498Szrj
1833*38fd1498Szrj body = gimple_body (current_function_decl);
1834*38fd1498Szrj memset (&wi, 0, sizeof (wi));
1835*38fd1498Szrj walk_gimple_seq_mod (&body, lower_sequence_no_tm, NULL, &wi);
1836*38fd1498Szrj gimple_set_body (current_function_decl, body);
1837*38fd1498Szrj
1838*38fd1498Szrj return 0;
1839*38fd1498Szrj }
1840*38fd1498Szrj
1841*38fd1498Szrj namespace {
1842*38fd1498Szrj
1843*38fd1498Szrj const pass_data pass_data_lower_tm =
1844*38fd1498Szrj {
1845*38fd1498Szrj GIMPLE_PASS, /* type */
1846*38fd1498Szrj "tmlower", /* name */
1847*38fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */
1848*38fd1498Szrj TV_TRANS_MEM, /* tv_id */
1849*38fd1498Szrj PROP_gimple_lcf, /* properties_required */
1850*38fd1498Szrj 0, /* properties_provided */
1851*38fd1498Szrj 0, /* properties_destroyed */
1852*38fd1498Szrj 0, /* todo_flags_start */
1853*38fd1498Szrj 0, /* todo_flags_finish */
1854*38fd1498Szrj };
1855*38fd1498Szrj
1856*38fd1498Szrj class pass_lower_tm : public gimple_opt_pass
1857*38fd1498Szrj {
1858*38fd1498Szrj public:
pass_lower_tm(gcc::context * ctxt)1859*38fd1498Szrj pass_lower_tm (gcc::context *ctxt)
1860*38fd1498Szrj : gimple_opt_pass (pass_data_lower_tm, ctxt)
1861*38fd1498Szrj {}
1862*38fd1498Szrj
1863*38fd1498Szrj /* opt_pass methods: */
gate(function *)1864*38fd1498Szrj virtual bool gate (function *) { return flag_tm; }
execute(function *)1865*38fd1498Szrj virtual unsigned int execute (function *) { return execute_lower_tm (); }
1866*38fd1498Szrj
1867*38fd1498Szrj }; // class pass_lower_tm
1868*38fd1498Szrj
1869*38fd1498Szrj } // anon namespace
1870*38fd1498Szrj
1871*38fd1498Szrj gimple_opt_pass *
make_pass_lower_tm(gcc::context * ctxt)1872*38fd1498Szrj make_pass_lower_tm (gcc::context *ctxt)
1873*38fd1498Szrj {
1874*38fd1498Szrj return new pass_lower_tm (ctxt);
1875*38fd1498Szrj }
1876*38fd1498Szrj
1877*38fd1498Szrj /* Collect region information for each transaction. */
1878*38fd1498Szrj
1879*38fd1498Szrj struct tm_region
1880*38fd1498Szrj {
1881*38fd1498Szrj public:
1882*38fd1498Szrj
1883*38fd1498Szrj /* The field "transaction_stmt" is initially a gtransaction *,
1884*38fd1498Szrj but eventually gets lowered to a gcall *(to BUILT_IN_TM_START).
1885*38fd1498Szrj
1886*38fd1498Szrj Helper method to get it as a gtransaction *, with code-checking
1887*38fd1498Szrj in a checked-build. */
1888*38fd1498Szrj
1889*38fd1498Szrj gtransaction *
get_transaction_stmttm_region1890*38fd1498Szrj get_transaction_stmt () const
1891*38fd1498Szrj {
1892*38fd1498Szrj return as_a <gtransaction *> (transaction_stmt);
1893*38fd1498Szrj }
1894*38fd1498Szrj
1895*38fd1498Szrj public:
1896*38fd1498Szrj
1897*38fd1498Szrj /* Link to the next unnested transaction. */
1898*38fd1498Szrj struct tm_region *next;
1899*38fd1498Szrj
1900*38fd1498Szrj /* Link to the next inner transaction. */
1901*38fd1498Szrj struct tm_region *inner;
1902*38fd1498Szrj
1903*38fd1498Szrj /* Link to the next outer transaction. */
1904*38fd1498Szrj struct tm_region *outer;
1905*38fd1498Szrj
1906*38fd1498Szrj /* The GIMPLE_TRANSACTION statement beginning this transaction.
1907*38fd1498Szrj After TM_MARK, this gets replaced by a call to
1908*38fd1498Szrj BUILT_IN_TM_START.
1909*38fd1498Szrj Hence this will be either a gtransaction *or a gcall *. */
1910*38fd1498Szrj gimple *transaction_stmt;
1911*38fd1498Szrj
1912*38fd1498Szrj /* After TM_MARK expands the GIMPLE_TRANSACTION into a call to
1913*38fd1498Szrj BUILT_IN_TM_START, this field is true if the transaction is an
1914*38fd1498Szrj outer transaction. */
1915*38fd1498Szrj bool original_transaction_was_outer;
1916*38fd1498Szrj
1917*38fd1498Szrj /* Return value from BUILT_IN_TM_START. */
1918*38fd1498Szrj tree tm_state;
1919*38fd1498Szrj
1920*38fd1498Szrj /* The entry block to this region. This will always be the first
1921*38fd1498Szrj block of the body of the transaction. */
1922*38fd1498Szrj basic_block entry_block;
1923*38fd1498Szrj
1924*38fd1498Szrj /* The first block after an expanded call to _ITM_beginTransaction. */
1925*38fd1498Szrj basic_block restart_block;
1926*38fd1498Szrj
1927*38fd1498Szrj /* The set of all blocks that end the region; NULL if only EXIT_BLOCK.
1928*38fd1498Szrj These blocks are still a part of the region (i.e., the border is
1929*38fd1498Szrj inclusive). Note that this set is only complete for paths in the CFG
1930*38fd1498Szrj starting at ENTRY_BLOCK, and that there is no exit block recorded for
1931*38fd1498Szrj the edge to the "over" label. */
1932*38fd1498Szrj bitmap exit_blocks;
1933*38fd1498Szrj
1934*38fd1498Szrj /* The set of all blocks that have an TM_IRREVOCABLE call. */
1935*38fd1498Szrj bitmap irr_blocks;
1936*38fd1498Szrj };
1937*38fd1498Szrj
1938*38fd1498Szrj /* True if there are pending edge statements to be committed for the
1939*38fd1498Szrj current function being scanned in the tmmark pass. */
1940*38fd1498Szrj bool pending_edge_inserts_p;
1941*38fd1498Szrj
1942*38fd1498Szrj static struct tm_region *all_tm_regions;
1943*38fd1498Szrj static bitmap_obstack tm_obstack;
1944*38fd1498Szrj
1945*38fd1498Szrj
1946*38fd1498Szrj /* A subroutine of tm_region_init. Record the existence of the
1947*38fd1498Szrj GIMPLE_TRANSACTION statement in a tree of tm_region elements. */
1948*38fd1498Szrj
1949*38fd1498Szrj static struct tm_region *
tm_region_init_0(struct tm_region * outer,basic_block bb,gtransaction * stmt)1950*38fd1498Szrj tm_region_init_0 (struct tm_region *outer, basic_block bb,
1951*38fd1498Szrj gtransaction *stmt)
1952*38fd1498Szrj {
1953*38fd1498Szrj struct tm_region *region;
1954*38fd1498Szrj
1955*38fd1498Szrj region = (struct tm_region *)
1956*38fd1498Szrj obstack_alloc (&tm_obstack.obstack, sizeof (struct tm_region));
1957*38fd1498Szrj
1958*38fd1498Szrj if (outer)
1959*38fd1498Szrj {
1960*38fd1498Szrj region->next = outer->inner;
1961*38fd1498Szrj outer->inner = region;
1962*38fd1498Szrj }
1963*38fd1498Szrj else
1964*38fd1498Szrj {
1965*38fd1498Szrj region->next = all_tm_regions;
1966*38fd1498Szrj all_tm_regions = region;
1967*38fd1498Szrj }
1968*38fd1498Szrj region->inner = NULL;
1969*38fd1498Szrj region->outer = outer;
1970*38fd1498Szrj
1971*38fd1498Szrj region->transaction_stmt = stmt;
1972*38fd1498Szrj region->original_transaction_was_outer = false;
1973*38fd1498Szrj region->tm_state = NULL;
1974*38fd1498Szrj
1975*38fd1498Szrj /* There are either one or two edges out of the block containing
1976*38fd1498Szrj the GIMPLE_TRANSACTION, one to the actual region and one to the
1977*38fd1498Szrj "over" label if the region contains an abort. The former will
1978*38fd1498Szrj always be the one marked FALLTHRU. */
1979*38fd1498Szrj region->entry_block = FALLTHRU_EDGE (bb)->dest;
1980*38fd1498Szrj
1981*38fd1498Szrj region->exit_blocks = BITMAP_ALLOC (&tm_obstack);
1982*38fd1498Szrj region->irr_blocks = BITMAP_ALLOC (&tm_obstack);
1983*38fd1498Szrj
1984*38fd1498Szrj return region;
1985*38fd1498Szrj }
1986*38fd1498Szrj
1987*38fd1498Szrj /* A subroutine of tm_region_init. Record all the exit and
1988*38fd1498Szrj irrevocable blocks in BB into the region's exit_blocks and
1989*38fd1498Szrj irr_blocks bitmaps. Returns the new region being scanned. */
1990*38fd1498Szrj
1991*38fd1498Szrj static struct tm_region *
tm_region_init_1(struct tm_region * region,basic_block bb)1992*38fd1498Szrj tm_region_init_1 (struct tm_region *region, basic_block bb)
1993*38fd1498Szrj {
1994*38fd1498Szrj gimple_stmt_iterator gsi;
1995*38fd1498Szrj gimple *g;
1996*38fd1498Szrj
1997*38fd1498Szrj if (!region
1998*38fd1498Szrj || (!region->irr_blocks && !region->exit_blocks))
1999*38fd1498Szrj return region;
2000*38fd1498Szrj
2001*38fd1498Szrj /* Check to see if this is the end of a region by seeing if it
2002*38fd1498Szrj contains a call to __builtin_tm_commit{,_eh}. Note that the
2003*38fd1498Szrj outermost region for DECL_IS_TM_CLONE need not collect this. */
2004*38fd1498Szrj for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi))
2005*38fd1498Szrj {
2006*38fd1498Szrj g = gsi_stmt (gsi);
2007*38fd1498Szrj if (gimple_code (g) == GIMPLE_CALL)
2008*38fd1498Szrj {
2009*38fd1498Szrj tree fn = gimple_call_fndecl (g);
2010*38fd1498Szrj if (fn && DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL)
2011*38fd1498Szrj {
2012*38fd1498Szrj if ((DECL_FUNCTION_CODE (fn) == BUILT_IN_TM_COMMIT
2013*38fd1498Szrj || DECL_FUNCTION_CODE (fn) == BUILT_IN_TM_COMMIT_EH)
2014*38fd1498Szrj && region->exit_blocks)
2015*38fd1498Szrj {
2016*38fd1498Szrj bitmap_set_bit (region->exit_blocks, bb->index);
2017*38fd1498Szrj region = region->outer;
2018*38fd1498Szrj break;
2019*38fd1498Szrj }
2020*38fd1498Szrj if (DECL_FUNCTION_CODE (fn) == BUILT_IN_TM_IRREVOCABLE)
2021*38fd1498Szrj bitmap_set_bit (region->irr_blocks, bb->index);
2022*38fd1498Szrj }
2023*38fd1498Szrj }
2024*38fd1498Szrj }
2025*38fd1498Szrj return region;
2026*38fd1498Szrj }
2027*38fd1498Szrj
2028*38fd1498Szrj /* Collect all of the transaction regions within the current function
2029*38fd1498Szrj and record them in ALL_TM_REGIONS. The REGION parameter may specify
2030*38fd1498Szrj an "outermost" region for use by tm clones. */
2031*38fd1498Szrj
2032*38fd1498Szrj static void
tm_region_init(struct tm_region * region)2033*38fd1498Szrj tm_region_init (struct tm_region *region)
2034*38fd1498Szrj {
2035*38fd1498Szrj gimple *g;
2036*38fd1498Szrj edge_iterator ei;
2037*38fd1498Szrj edge e;
2038*38fd1498Szrj basic_block bb;
2039*38fd1498Szrj auto_vec<basic_block> queue;
2040*38fd1498Szrj bitmap visited_blocks = BITMAP_ALLOC (NULL);
2041*38fd1498Szrj struct tm_region *old_region;
2042*38fd1498Szrj auto_vec<tm_region *> bb_regions;
2043*38fd1498Szrj
2044*38fd1498Szrj /* We could store this information in bb->aux, but we may get called
2045*38fd1498Szrj through get_all_tm_blocks() from another pass that may be already
2046*38fd1498Szrj using bb->aux. */
2047*38fd1498Szrj bb_regions.safe_grow_cleared (last_basic_block_for_fn (cfun));
2048*38fd1498Szrj
2049*38fd1498Szrj all_tm_regions = region;
2050*38fd1498Szrj bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
2051*38fd1498Szrj queue.safe_push (bb);
2052*38fd1498Szrj bitmap_set_bit (visited_blocks, bb->index);
2053*38fd1498Szrj bb_regions[bb->index] = region;
2054*38fd1498Szrj
2055*38fd1498Szrj do
2056*38fd1498Szrj {
2057*38fd1498Szrj bb = queue.pop ();
2058*38fd1498Szrj region = bb_regions[bb->index];
2059*38fd1498Szrj bb_regions[bb->index] = NULL;
2060*38fd1498Szrj
2061*38fd1498Szrj /* Record exit and irrevocable blocks. */
2062*38fd1498Szrj region = tm_region_init_1 (region, bb);
2063*38fd1498Szrj
2064*38fd1498Szrj /* Check for the last statement in the block beginning a new region. */
2065*38fd1498Szrj g = last_stmt (bb);
2066*38fd1498Szrj old_region = region;
2067*38fd1498Szrj if (g)
2068*38fd1498Szrj if (gtransaction *trans_stmt = dyn_cast <gtransaction *> (g))
2069*38fd1498Szrj region = tm_region_init_0 (region, bb, trans_stmt);
2070*38fd1498Szrj
2071*38fd1498Szrj /* Process subsequent blocks. */
2072*38fd1498Szrj FOR_EACH_EDGE (e, ei, bb->succs)
2073*38fd1498Szrj if (!bitmap_bit_p (visited_blocks, e->dest->index))
2074*38fd1498Szrj {
2075*38fd1498Szrj bitmap_set_bit (visited_blocks, e->dest->index);
2076*38fd1498Szrj queue.safe_push (e->dest);
2077*38fd1498Szrj
2078*38fd1498Szrj /* If the current block started a new region, make sure that only
2079*38fd1498Szrj the entry block of the new region is associated with this region.
2080*38fd1498Szrj Other successors are still part of the old region. */
2081*38fd1498Szrj if (old_region != region && e->dest != region->entry_block)
2082*38fd1498Szrj bb_regions[e->dest->index] = old_region;
2083*38fd1498Szrj else
2084*38fd1498Szrj bb_regions[e->dest->index] = region;
2085*38fd1498Szrj }
2086*38fd1498Szrj }
2087*38fd1498Szrj while (!queue.is_empty ());
2088*38fd1498Szrj BITMAP_FREE (visited_blocks);
2089*38fd1498Szrj }
2090*38fd1498Szrj
2091*38fd1498Szrj /* The "gate" function for all transactional memory expansion and optimization
2092*38fd1498Szrj passes. We collect region information for each top-level transaction, and
2093*38fd1498Szrj if we don't find any, we skip all of the TM passes. Each region will have
2094*38fd1498Szrj all of the exit blocks recorded, and the originating statement. */
2095*38fd1498Szrj
2096*38fd1498Szrj static bool
gate_tm_init(void)2097*38fd1498Szrj gate_tm_init (void)
2098*38fd1498Szrj {
2099*38fd1498Szrj if (!flag_tm)
2100*38fd1498Szrj return false;
2101*38fd1498Szrj
2102*38fd1498Szrj calculate_dominance_info (CDI_DOMINATORS);
2103*38fd1498Szrj bitmap_obstack_initialize (&tm_obstack);
2104*38fd1498Szrj
2105*38fd1498Szrj /* If the function is a TM_CLONE, then the entire function is the region. */
2106*38fd1498Szrj if (decl_is_tm_clone (current_function_decl))
2107*38fd1498Szrj {
2108*38fd1498Szrj struct tm_region *region = (struct tm_region *)
2109*38fd1498Szrj obstack_alloc (&tm_obstack.obstack, sizeof (struct tm_region));
2110*38fd1498Szrj memset (region, 0, sizeof (*region));
2111*38fd1498Szrj region->entry_block = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
2112*38fd1498Szrj /* For a clone, the entire function is the region. But even if
2113*38fd1498Szrj we don't need to record any exit blocks, we may need to
2114*38fd1498Szrj record irrevocable blocks. */
2115*38fd1498Szrj region->irr_blocks = BITMAP_ALLOC (&tm_obstack);
2116*38fd1498Szrj
2117*38fd1498Szrj tm_region_init (region);
2118*38fd1498Szrj }
2119*38fd1498Szrj else
2120*38fd1498Szrj {
2121*38fd1498Szrj tm_region_init (NULL);
2122*38fd1498Szrj
2123*38fd1498Szrj /* If we didn't find any regions, cleanup and skip the whole tree
2124*38fd1498Szrj of tm-related optimizations. */
2125*38fd1498Szrj if (all_tm_regions == NULL)
2126*38fd1498Szrj {
2127*38fd1498Szrj bitmap_obstack_release (&tm_obstack);
2128*38fd1498Szrj return false;
2129*38fd1498Szrj }
2130*38fd1498Szrj }
2131*38fd1498Szrj
2132*38fd1498Szrj return true;
2133*38fd1498Szrj }
2134*38fd1498Szrj
2135*38fd1498Szrj namespace {
2136*38fd1498Szrj
2137*38fd1498Szrj const pass_data pass_data_tm_init =
2138*38fd1498Szrj {
2139*38fd1498Szrj GIMPLE_PASS, /* type */
2140*38fd1498Szrj "*tminit", /* name */
2141*38fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */
2142*38fd1498Szrj TV_TRANS_MEM, /* tv_id */
2143*38fd1498Szrj ( PROP_ssa | PROP_cfg ), /* properties_required */
2144*38fd1498Szrj 0, /* properties_provided */
2145*38fd1498Szrj 0, /* properties_destroyed */
2146*38fd1498Szrj 0, /* todo_flags_start */
2147*38fd1498Szrj 0, /* todo_flags_finish */
2148*38fd1498Szrj };
2149*38fd1498Szrj
2150*38fd1498Szrj class pass_tm_init : public gimple_opt_pass
2151*38fd1498Szrj {
2152*38fd1498Szrj public:
pass_tm_init(gcc::context * ctxt)2153*38fd1498Szrj pass_tm_init (gcc::context *ctxt)
2154*38fd1498Szrj : gimple_opt_pass (pass_data_tm_init, ctxt)
2155*38fd1498Szrj {}
2156*38fd1498Szrj
2157*38fd1498Szrj /* opt_pass methods: */
gate(function *)2158*38fd1498Szrj virtual bool gate (function *) { return gate_tm_init (); }
2159*38fd1498Szrj
2160*38fd1498Szrj }; // class pass_tm_init
2161*38fd1498Szrj
2162*38fd1498Szrj } // anon namespace
2163*38fd1498Szrj
2164*38fd1498Szrj gimple_opt_pass *
make_pass_tm_init(gcc::context * ctxt)2165*38fd1498Szrj make_pass_tm_init (gcc::context *ctxt)
2166*38fd1498Szrj {
2167*38fd1498Szrj return new pass_tm_init (ctxt);
2168*38fd1498Szrj }
2169*38fd1498Szrj
2170*38fd1498Szrj /* Add FLAGS to the GIMPLE_TRANSACTION subcode for the transaction region
2171*38fd1498Szrj represented by STATE. */
2172*38fd1498Szrj
2173*38fd1498Szrj static inline void
transaction_subcode_ior(struct tm_region * region,unsigned flags)2174*38fd1498Szrj transaction_subcode_ior (struct tm_region *region, unsigned flags)
2175*38fd1498Szrj {
2176*38fd1498Szrj if (region && region->transaction_stmt)
2177*38fd1498Szrj {
2178*38fd1498Szrj gtransaction *transaction_stmt = region->get_transaction_stmt ();
2179*38fd1498Szrj flags |= gimple_transaction_subcode (transaction_stmt);
2180*38fd1498Szrj gimple_transaction_set_subcode (transaction_stmt, flags);
2181*38fd1498Szrj }
2182*38fd1498Szrj }
2183*38fd1498Szrj
2184*38fd1498Szrj /* Construct a memory load in a transactional context. Return the
2185*38fd1498Szrj gimple statement performing the load, or NULL if there is no
2186*38fd1498Szrj TM_LOAD builtin of the appropriate size to do the load.
2187*38fd1498Szrj
2188*38fd1498Szrj LOC is the location to use for the new statement(s). */
2189*38fd1498Szrj
2190*38fd1498Szrj static gcall *
build_tm_load(location_t loc,tree lhs,tree rhs,gimple_stmt_iterator * gsi)2191*38fd1498Szrj build_tm_load (location_t loc, tree lhs, tree rhs, gimple_stmt_iterator *gsi)
2192*38fd1498Szrj {
2193*38fd1498Szrj tree t, type = TREE_TYPE (rhs);
2194*38fd1498Szrj gcall *gcall;
2195*38fd1498Szrj
2196*38fd1498Szrj built_in_function code;
2197*38fd1498Szrj if (type == float_type_node)
2198*38fd1498Szrj code = BUILT_IN_TM_LOAD_FLOAT;
2199*38fd1498Szrj else if (type == double_type_node)
2200*38fd1498Szrj code = BUILT_IN_TM_LOAD_DOUBLE;
2201*38fd1498Szrj else if (type == long_double_type_node)
2202*38fd1498Szrj code = BUILT_IN_TM_LOAD_LDOUBLE;
2203*38fd1498Szrj else
2204*38fd1498Szrj {
2205*38fd1498Szrj if (TYPE_SIZE (type) == NULL || !tree_fits_uhwi_p (TYPE_SIZE (type)))
2206*38fd1498Szrj return NULL;
2207*38fd1498Szrj unsigned HOST_WIDE_INT type_size = tree_to_uhwi (TYPE_SIZE (type));
2208*38fd1498Szrj
2209*38fd1498Szrj if (TREE_CODE (type) == VECTOR_TYPE)
2210*38fd1498Szrj {
2211*38fd1498Szrj switch (type_size)
2212*38fd1498Szrj {
2213*38fd1498Szrj case 64:
2214*38fd1498Szrj code = BUILT_IN_TM_LOAD_M64;
2215*38fd1498Szrj break;
2216*38fd1498Szrj case 128:
2217*38fd1498Szrj code = BUILT_IN_TM_LOAD_M128;
2218*38fd1498Szrj break;
2219*38fd1498Szrj case 256:
2220*38fd1498Szrj code = BUILT_IN_TM_LOAD_M256;
2221*38fd1498Szrj break;
2222*38fd1498Szrj default:
2223*38fd1498Szrj goto unhandled_vec;
2224*38fd1498Szrj }
2225*38fd1498Szrj if (!builtin_decl_explicit_p (code))
2226*38fd1498Szrj goto unhandled_vec;
2227*38fd1498Szrj }
2228*38fd1498Szrj else
2229*38fd1498Szrj {
2230*38fd1498Szrj unhandled_vec:
2231*38fd1498Szrj switch (type_size)
2232*38fd1498Szrj {
2233*38fd1498Szrj case 8:
2234*38fd1498Szrj code = BUILT_IN_TM_LOAD_1;
2235*38fd1498Szrj break;
2236*38fd1498Szrj case 16:
2237*38fd1498Szrj code = BUILT_IN_TM_LOAD_2;
2238*38fd1498Szrj break;
2239*38fd1498Szrj case 32:
2240*38fd1498Szrj code = BUILT_IN_TM_LOAD_4;
2241*38fd1498Szrj break;
2242*38fd1498Szrj case 64:
2243*38fd1498Szrj code = BUILT_IN_TM_LOAD_8;
2244*38fd1498Szrj break;
2245*38fd1498Szrj default:
2246*38fd1498Szrj return NULL;
2247*38fd1498Szrj }
2248*38fd1498Szrj }
2249*38fd1498Szrj }
2250*38fd1498Szrj
2251*38fd1498Szrj tree decl = builtin_decl_explicit (code);
2252*38fd1498Szrj gcc_assert (decl);
2253*38fd1498Szrj
2254*38fd1498Szrj t = gimplify_addr (gsi, rhs);
2255*38fd1498Szrj gcall = gimple_build_call (decl, 1, t);
2256*38fd1498Szrj gimple_set_location (gcall, loc);
2257*38fd1498Szrj
2258*38fd1498Szrj t = TREE_TYPE (TREE_TYPE (decl));
2259*38fd1498Szrj if (useless_type_conversion_p (type, t))
2260*38fd1498Szrj {
2261*38fd1498Szrj gimple_call_set_lhs (gcall, lhs);
2262*38fd1498Szrj gsi_insert_before (gsi, gcall, GSI_SAME_STMT);
2263*38fd1498Szrj }
2264*38fd1498Szrj else
2265*38fd1498Szrj {
2266*38fd1498Szrj gimple *g;
2267*38fd1498Szrj tree temp;
2268*38fd1498Szrj
2269*38fd1498Szrj temp = create_tmp_reg (t);
2270*38fd1498Szrj gimple_call_set_lhs (gcall, temp);
2271*38fd1498Szrj gsi_insert_before (gsi, gcall, GSI_SAME_STMT);
2272*38fd1498Szrj
2273*38fd1498Szrj t = fold_build1 (VIEW_CONVERT_EXPR, type, temp);
2274*38fd1498Szrj g = gimple_build_assign (lhs, t);
2275*38fd1498Szrj gsi_insert_before (gsi, g, GSI_SAME_STMT);
2276*38fd1498Szrj }
2277*38fd1498Szrj
2278*38fd1498Szrj return gcall;
2279*38fd1498Szrj }
2280*38fd1498Szrj
2281*38fd1498Szrj
2282*38fd1498Szrj /* Similarly for storing TYPE in a transactional context. */
2283*38fd1498Szrj
2284*38fd1498Szrj static gcall *
build_tm_store(location_t loc,tree lhs,tree rhs,gimple_stmt_iterator * gsi)2285*38fd1498Szrj build_tm_store (location_t loc, tree lhs, tree rhs, gimple_stmt_iterator *gsi)
2286*38fd1498Szrj {
2287*38fd1498Szrj tree t, fn, type = TREE_TYPE (rhs), simple_type;
2288*38fd1498Szrj gcall *gcall;
2289*38fd1498Szrj
2290*38fd1498Szrj built_in_function code;
2291*38fd1498Szrj if (type == float_type_node)
2292*38fd1498Szrj code = BUILT_IN_TM_STORE_FLOAT;
2293*38fd1498Szrj else if (type == double_type_node)
2294*38fd1498Szrj code = BUILT_IN_TM_STORE_DOUBLE;
2295*38fd1498Szrj else if (type == long_double_type_node)
2296*38fd1498Szrj code = BUILT_IN_TM_STORE_LDOUBLE;
2297*38fd1498Szrj else
2298*38fd1498Szrj {
2299*38fd1498Szrj if (TYPE_SIZE (type) == NULL || !tree_fits_uhwi_p (TYPE_SIZE (type)))
2300*38fd1498Szrj return NULL;
2301*38fd1498Szrj unsigned HOST_WIDE_INT type_size = tree_to_uhwi (TYPE_SIZE (type));
2302*38fd1498Szrj
2303*38fd1498Szrj if (TREE_CODE (type) == VECTOR_TYPE)
2304*38fd1498Szrj {
2305*38fd1498Szrj switch (type_size)
2306*38fd1498Szrj {
2307*38fd1498Szrj case 64:
2308*38fd1498Szrj code = BUILT_IN_TM_STORE_M64;
2309*38fd1498Szrj break;
2310*38fd1498Szrj case 128:
2311*38fd1498Szrj code = BUILT_IN_TM_STORE_M128;
2312*38fd1498Szrj break;
2313*38fd1498Szrj case 256:
2314*38fd1498Szrj code = BUILT_IN_TM_STORE_M256;
2315*38fd1498Szrj break;
2316*38fd1498Szrj default:
2317*38fd1498Szrj goto unhandled_vec;
2318*38fd1498Szrj }
2319*38fd1498Szrj if (!builtin_decl_explicit_p (code))
2320*38fd1498Szrj goto unhandled_vec;
2321*38fd1498Szrj }
2322*38fd1498Szrj else
2323*38fd1498Szrj {
2324*38fd1498Szrj unhandled_vec:
2325*38fd1498Szrj switch (type_size)
2326*38fd1498Szrj {
2327*38fd1498Szrj case 8:
2328*38fd1498Szrj code = BUILT_IN_TM_STORE_1;
2329*38fd1498Szrj break;
2330*38fd1498Szrj case 16:
2331*38fd1498Szrj code = BUILT_IN_TM_STORE_2;
2332*38fd1498Szrj break;
2333*38fd1498Szrj case 32:
2334*38fd1498Szrj code = BUILT_IN_TM_STORE_4;
2335*38fd1498Szrj break;
2336*38fd1498Szrj case 64:
2337*38fd1498Szrj code = BUILT_IN_TM_STORE_8;
2338*38fd1498Szrj break;
2339*38fd1498Szrj default:
2340*38fd1498Szrj return NULL;
2341*38fd1498Szrj }
2342*38fd1498Szrj }
2343*38fd1498Szrj }
2344*38fd1498Szrj
2345*38fd1498Szrj fn = builtin_decl_explicit (code);
2346*38fd1498Szrj gcc_assert (fn);
2347*38fd1498Szrj
2348*38fd1498Szrj simple_type = TREE_VALUE (TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (fn))));
2349*38fd1498Szrj
2350*38fd1498Szrj if (TREE_CODE (rhs) == CONSTRUCTOR)
2351*38fd1498Szrj {
2352*38fd1498Szrj /* Handle the easy initialization to zero. */
2353*38fd1498Szrj if (!CONSTRUCTOR_ELTS (rhs))
2354*38fd1498Szrj rhs = build_int_cst (simple_type, 0);
2355*38fd1498Szrj else
2356*38fd1498Szrj {
2357*38fd1498Szrj /* ...otherwise punt to the caller and probably use
2358*38fd1498Szrj BUILT_IN_TM_MEMMOVE, because we can't wrap a
2359*38fd1498Szrj VIEW_CONVERT_EXPR around a CONSTRUCTOR (below) and produce
2360*38fd1498Szrj valid gimple. */
2361*38fd1498Szrj return NULL;
2362*38fd1498Szrj }
2363*38fd1498Szrj }
2364*38fd1498Szrj else if (!useless_type_conversion_p (simple_type, type))
2365*38fd1498Szrj {
2366*38fd1498Szrj gimple *g;
2367*38fd1498Szrj tree temp;
2368*38fd1498Szrj
2369*38fd1498Szrj temp = create_tmp_reg (simple_type);
2370*38fd1498Szrj t = fold_build1 (VIEW_CONVERT_EXPR, simple_type, rhs);
2371*38fd1498Szrj g = gimple_build_assign (temp, t);
2372*38fd1498Szrj gimple_set_location (g, loc);
2373*38fd1498Szrj gsi_insert_before (gsi, g, GSI_SAME_STMT);
2374*38fd1498Szrj
2375*38fd1498Szrj rhs = temp;
2376*38fd1498Szrj }
2377*38fd1498Szrj
2378*38fd1498Szrj t = gimplify_addr (gsi, lhs);
2379*38fd1498Szrj gcall = gimple_build_call (fn, 2, t, rhs);
2380*38fd1498Szrj gimple_set_location (gcall, loc);
2381*38fd1498Szrj gsi_insert_before (gsi, gcall, GSI_SAME_STMT);
2382*38fd1498Szrj
2383*38fd1498Szrj return gcall;
2384*38fd1498Szrj }
2385*38fd1498Szrj
2386*38fd1498Szrj
2387*38fd1498Szrj /* Expand an assignment statement into transactional builtins. */
2388*38fd1498Szrj
2389*38fd1498Szrj static void
expand_assign_tm(struct tm_region * region,gimple_stmt_iterator * gsi)2390*38fd1498Szrj expand_assign_tm (struct tm_region *region, gimple_stmt_iterator *gsi)
2391*38fd1498Szrj {
2392*38fd1498Szrj gimple *stmt = gsi_stmt (*gsi);
2393*38fd1498Szrj location_t loc = gimple_location (stmt);
2394*38fd1498Szrj tree lhs = gimple_assign_lhs (stmt);
2395*38fd1498Szrj tree rhs = gimple_assign_rhs1 (stmt);
2396*38fd1498Szrj bool store_p = requires_barrier (region->entry_block, lhs, NULL);
2397*38fd1498Szrj bool load_p = requires_barrier (region->entry_block, rhs, NULL);
2398*38fd1498Szrj gimple *gcall = NULL;
2399*38fd1498Szrj
2400*38fd1498Szrj if (!load_p && !store_p)
2401*38fd1498Szrj {
2402*38fd1498Szrj /* Add thread private addresses to log if applicable. */
2403*38fd1498Szrj requires_barrier (region->entry_block, lhs, stmt);
2404*38fd1498Szrj gsi_next (gsi);
2405*38fd1498Szrj return;
2406*38fd1498Szrj }
2407*38fd1498Szrj
2408*38fd1498Szrj if (load_p)
2409*38fd1498Szrj transaction_subcode_ior (region, GTMA_HAVE_LOAD);
2410*38fd1498Szrj if (store_p)
2411*38fd1498Szrj transaction_subcode_ior (region, GTMA_HAVE_STORE);
2412*38fd1498Szrj
2413*38fd1498Szrj // Remove original load/store statement.
2414*38fd1498Szrj gsi_remove (gsi, true);
2415*38fd1498Szrj
2416*38fd1498Szrj // Attempt to use a simple load/store helper function.
2417*38fd1498Szrj if (load_p && !store_p)
2418*38fd1498Szrj gcall = build_tm_load (loc, lhs, rhs, gsi);
2419*38fd1498Szrj else if (store_p && !load_p)
2420*38fd1498Szrj gcall = build_tm_store (loc, lhs, rhs, gsi);
2421*38fd1498Szrj
2422*38fd1498Szrj // If gcall has not been set, then we do not have a simple helper
2423*38fd1498Szrj // function available for the type. This may be true of larger
2424*38fd1498Szrj // structures, vectors, and non-standard float types.
2425*38fd1498Szrj if (!gcall)
2426*38fd1498Szrj {
2427*38fd1498Szrj tree lhs_addr, rhs_addr, ltmp = NULL, copy_fn;
2428*38fd1498Szrj
2429*38fd1498Szrj // If this is a type that we couldn't handle above, but it's
2430*38fd1498Szrj // in a register, we must spill it to memory for the copy.
2431*38fd1498Szrj if (is_gimple_reg (lhs))
2432*38fd1498Szrj {
2433*38fd1498Szrj ltmp = create_tmp_var (TREE_TYPE (lhs));
2434*38fd1498Szrj lhs_addr = build_fold_addr_expr (ltmp);
2435*38fd1498Szrj }
2436*38fd1498Szrj else
2437*38fd1498Szrj lhs_addr = gimplify_addr (gsi, lhs);
2438*38fd1498Szrj if (is_gimple_reg (rhs))
2439*38fd1498Szrj {
2440*38fd1498Szrj tree rtmp = create_tmp_var (TREE_TYPE (rhs));
2441*38fd1498Szrj rhs_addr = build_fold_addr_expr (rtmp);
2442*38fd1498Szrj gcall = gimple_build_assign (rtmp, rhs);
2443*38fd1498Szrj gsi_insert_before (gsi, gcall, GSI_SAME_STMT);
2444*38fd1498Szrj }
2445*38fd1498Szrj else
2446*38fd1498Szrj rhs_addr = gimplify_addr (gsi, rhs);
2447*38fd1498Szrj
2448*38fd1498Szrj // Choose the appropriate memory transfer function.
2449*38fd1498Szrj if (load_p && store_p)
2450*38fd1498Szrj {
2451*38fd1498Szrj // ??? Figure out if there's any possible overlap between
2452*38fd1498Szrj // the LHS and the RHS and if not, use MEMCPY.
2453*38fd1498Szrj copy_fn = builtin_decl_explicit (BUILT_IN_TM_MEMMOVE);
2454*38fd1498Szrj }
2455*38fd1498Szrj else if (load_p)
2456*38fd1498Szrj {
2457*38fd1498Szrj // Note that the store is non-transactional and cannot overlap.
2458*38fd1498Szrj copy_fn = builtin_decl_explicit (BUILT_IN_TM_MEMCPY_RTWN);
2459*38fd1498Szrj }
2460*38fd1498Szrj else
2461*38fd1498Szrj {
2462*38fd1498Szrj // Note that the load is non-transactional and cannot overlap.
2463*38fd1498Szrj copy_fn = builtin_decl_explicit (BUILT_IN_TM_MEMCPY_RNWT);
2464*38fd1498Szrj }
2465*38fd1498Szrj
2466*38fd1498Szrj gcall = gimple_build_call (copy_fn, 3, lhs_addr, rhs_addr,
2467*38fd1498Szrj TYPE_SIZE_UNIT (TREE_TYPE (lhs)));
2468*38fd1498Szrj gimple_set_location (gcall, loc);
2469*38fd1498Szrj gsi_insert_before (gsi, gcall, GSI_SAME_STMT);
2470*38fd1498Szrj
2471*38fd1498Szrj if (ltmp)
2472*38fd1498Szrj {
2473*38fd1498Szrj gcall = gimple_build_assign (lhs, ltmp);
2474*38fd1498Szrj gsi_insert_before (gsi, gcall, GSI_SAME_STMT);
2475*38fd1498Szrj }
2476*38fd1498Szrj }
2477*38fd1498Szrj
2478*38fd1498Szrj // Now that we have the load/store in its instrumented form, add
2479*38fd1498Szrj // thread private addresses to the log if applicable.
2480*38fd1498Szrj if (!store_p)
2481*38fd1498Szrj requires_barrier (region->entry_block, lhs, gcall);
2482*38fd1498Szrj }
2483*38fd1498Szrj
2484*38fd1498Szrj
2485*38fd1498Szrj /* Expand a call statement as appropriate for a transaction. That is,
2486*38fd1498Szrj either verify that the call does not affect the transaction, or
2487*38fd1498Szrj redirect the call to a clone that handles transactions, or change
2488*38fd1498Szrj the transaction state to IRREVOCABLE. Return true if the call is
2489*38fd1498Szrj one of the builtins that end a transaction. */
2490*38fd1498Szrj
2491*38fd1498Szrj static bool
expand_call_tm(struct tm_region * region,gimple_stmt_iterator * gsi)2492*38fd1498Szrj expand_call_tm (struct tm_region *region,
2493*38fd1498Szrj gimple_stmt_iterator *gsi)
2494*38fd1498Szrj {
2495*38fd1498Szrj gcall *stmt = as_a <gcall *> (gsi_stmt (*gsi));
2496*38fd1498Szrj tree lhs = gimple_call_lhs (stmt);
2497*38fd1498Szrj tree fn_decl;
2498*38fd1498Szrj struct cgraph_node *node;
2499*38fd1498Szrj bool retval = false;
2500*38fd1498Szrj
2501*38fd1498Szrj fn_decl = gimple_call_fndecl (stmt);
2502*38fd1498Szrj
2503*38fd1498Szrj if (fn_decl == builtin_decl_explicit (BUILT_IN_TM_MEMCPY)
2504*38fd1498Szrj || fn_decl == builtin_decl_explicit (BUILT_IN_TM_MEMMOVE))
2505*38fd1498Szrj transaction_subcode_ior (region, GTMA_HAVE_STORE | GTMA_HAVE_LOAD);
2506*38fd1498Szrj if (fn_decl == builtin_decl_explicit (BUILT_IN_TM_MEMSET))
2507*38fd1498Szrj transaction_subcode_ior (region, GTMA_HAVE_STORE);
2508*38fd1498Szrj
2509*38fd1498Szrj if (is_tm_pure_call (stmt))
2510*38fd1498Szrj return false;
2511*38fd1498Szrj
2512*38fd1498Szrj if (fn_decl)
2513*38fd1498Szrj retval = is_tm_ending_fndecl (fn_decl);
2514*38fd1498Szrj if (!retval)
2515*38fd1498Szrj {
2516*38fd1498Szrj /* Assume all non-const/pure calls write to memory, except
2517*38fd1498Szrj transaction ending builtins. */
2518*38fd1498Szrj transaction_subcode_ior (region, GTMA_HAVE_STORE);
2519*38fd1498Szrj }
2520*38fd1498Szrj
2521*38fd1498Szrj /* For indirect calls, we already generated a call into the runtime. */
2522*38fd1498Szrj if (!fn_decl)
2523*38fd1498Szrj {
2524*38fd1498Szrj tree fn = gimple_call_fn (stmt);
2525*38fd1498Szrj
2526*38fd1498Szrj /* We are guaranteed never to go irrevocable on a safe or pure
2527*38fd1498Szrj call, and the pure call was handled above. */
2528*38fd1498Szrj if (is_tm_safe (fn))
2529*38fd1498Szrj return false;
2530*38fd1498Szrj else
2531*38fd1498Szrj transaction_subcode_ior (region, GTMA_MAY_ENTER_IRREVOCABLE);
2532*38fd1498Szrj
2533*38fd1498Szrj return false;
2534*38fd1498Szrj }
2535*38fd1498Szrj
2536*38fd1498Szrj node = cgraph_node::get (fn_decl);
2537*38fd1498Szrj /* All calls should have cgraph here. */
2538*38fd1498Szrj if (!node)
2539*38fd1498Szrj {
2540*38fd1498Szrj /* We can have a nodeless call here if some pass after IPA-tm
2541*38fd1498Szrj added uninstrumented calls. For example, loop distribution
2542*38fd1498Szrj can transform certain loop constructs into __builtin_mem*
2543*38fd1498Szrj calls. In this case, see if we have a suitable TM
2544*38fd1498Szrj replacement and fill in the gaps. */
2545*38fd1498Szrj gcc_assert (DECL_BUILT_IN_CLASS (fn_decl) == BUILT_IN_NORMAL);
2546*38fd1498Szrj enum built_in_function code = DECL_FUNCTION_CODE (fn_decl);
2547*38fd1498Szrj gcc_assert (code == BUILT_IN_MEMCPY
2548*38fd1498Szrj || code == BUILT_IN_MEMMOVE
2549*38fd1498Szrj || code == BUILT_IN_MEMSET);
2550*38fd1498Szrj
2551*38fd1498Szrj tree repl = find_tm_replacement_function (fn_decl);
2552*38fd1498Szrj if (repl)
2553*38fd1498Szrj {
2554*38fd1498Szrj gimple_call_set_fndecl (stmt, repl);
2555*38fd1498Szrj update_stmt (stmt);
2556*38fd1498Szrj node = cgraph_node::create (repl);
2557*38fd1498Szrj node->local.tm_may_enter_irr = false;
2558*38fd1498Szrj return expand_call_tm (region, gsi);
2559*38fd1498Szrj }
2560*38fd1498Szrj gcc_unreachable ();
2561*38fd1498Szrj }
2562*38fd1498Szrj if (node->local.tm_may_enter_irr)
2563*38fd1498Szrj transaction_subcode_ior (region, GTMA_MAY_ENTER_IRREVOCABLE);
2564*38fd1498Szrj
2565*38fd1498Szrj if (is_tm_abort (fn_decl))
2566*38fd1498Szrj {
2567*38fd1498Szrj transaction_subcode_ior (region, GTMA_HAVE_ABORT);
2568*38fd1498Szrj return true;
2569*38fd1498Szrj }
2570*38fd1498Szrj
2571*38fd1498Szrj /* Instrument the store if needed.
2572*38fd1498Szrj
2573*38fd1498Szrj If the assignment happens inside the function call (return slot
2574*38fd1498Szrj optimization), there is no instrumentation to be done, since
2575*38fd1498Szrj the callee should have done the right thing. */
2576*38fd1498Szrj if (lhs && requires_barrier (region->entry_block, lhs, stmt)
2577*38fd1498Szrj && !gimple_call_return_slot_opt_p (stmt))
2578*38fd1498Szrj {
2579*38fd1498Szrj tree tmp = create_tmp_reg (TREE_TYPE (lhs));
2580*38fd1498Szrj location_t loc = gimple_location (stmt);
2581*38fd1498Szrj edge fallthru_edge = NULL;
2582*38fd1498Szrj gassign *assign_stmt;
2583*38fd1498Szrj
2584*38fd1498Szrj /* Remember if the call was going to throw. */
2585*38fd1498Szrj if (stmt_can_throw_internal (stmt))
2586*38fd1498Szrj {
2587*38fd1498Szrj edge_iterator ei;
2588*38fd1498Szrj edge e;
2589*38fd1498Szrj basic_block bb = gimple_bb (stmt);
2590*38fd1498Szrj
2591*38fd1498Szrj FOR_EACH_EDGE (e, ei, bb->succs)
2592*38fd1498Szrj if (e->flags & EDGE_FALLTHRU)
2593*38fd1498Szrj {
2594*38fd1498Szrj fallthru_edge = e;
2595*38fd1498Szrj break;
2596*38fd1498Szrj }
2597*38fd1498Szrj }
2598*38fd1498Szrj
2599*38fd1498Szrj gimple_call_set_lhs (stmt, tmp);
2600*38fd1498Szrj update_stmt (stmt);
2601*38fd1498Szrj assign_stmt = gimple_build_assign (lhs, tmp);
2602*38fd1498Szrj gimple_set_location (assign_stmt, loc);
2603*38fd1498Szrj
2604*38fd1498Szrj /* We cannot throw in the middle of a BB. If the call was going
2605*38fd1498Szrj to throw, place the instrumentation on the fallthru edge, so
2606*38fd1498Szrj the call remains the last statement in the block. */
2607*38fd1498Szrj if (fallthru_edge)
2608*38fd1498Szrj {
2609*38fd1498Szrj gimple_seq fallthru_seq = gimple_seq_alloc_with_stmt (assign_stmt);
2610*38fd1498Szrj gimple_stmt_iterator fallthru_gsi = gsi_start (fallthru_seq);
2611*38fd1498Szrj expand_assign_tm (region, &fallthru_gsi);
2612*38fd1498Szrj gsi_insert_seq_on_edge (fallthru_edge, fallthru_seq);
2613*38fd1498Szrj pending_edge_inserts_p = true;
2614*38fd1498Szrj }
2615*38fd1498Szrj else
2616*38fd1498Szrj {
2617*38fd1498Szrj gsi_insert_after (gsi, assign_stmt, GSI_CONTINUE_LINKING);
2618*38fd1498Szrj expand_assign_tm (region, gsi);
2619*38fd1498Szrj }
2620*38fd1498Szrj
2621*38fd1498Szrj transaction_subcode_ior (region, GTMA_HAVE_STORE);
2622*38fd1498Szrj }
2623*38fd1498Szrj
2624*38fd1498Szrj return retval;
2625*38fd1498Szrj }
2626*38fd1498Szrj
2627*38fd1498Szrj
2628*38fd1498Szrj /* Expand all statements in BB as appropriate for being inside
2629*38fd1498Szrj a transaction. */
2630*38fd1498Szrj
2631*38fd1498Szrj static void
expand_block_tm(struct tm_region * region,basic_block bb)2632*38fd1498Szrj expand_block_tm (struct tm_region *region, basic_block bb)
2633*38fd1498Szrj {
2634*38fd1498Szrj gimple_stmt_iterator gsi;
2635*38fd1498Szrj
2636*38fd1498Szrj for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
2637*38fd1498Szrj {
2638*38fd1498Szrj gimple *stmt = gsi_stmt (gsi);
2639*38fd1498Szrj switch (gimple_code (stmt))
2640*38fd1498Szrj {
2641*38fd1498Szrj case GIMPLE_ASSIGN:
2642*38fd1498Szrj /* Only memory reads/writes need to be instrumented. */
2643*38fd1498Szrj if (gimple_assign_single_p (stmt)
2644*38fd1498Szrj && !gimple_clobber_p (stmt))
2645*38fd1498Szrj {
2646*38fd1498Szrj expand_assign_tm (region, &gsi);
2647*38fd1498Szrj continue;
2648*38fd1498Szrj }
2649*38fd1498Szrj break;
2650*38fd1498Szrj
2651*38fd1498Szrj case GIMPLE_CALL:
2652*38fd1498Szrj if (expand_call_tm (region, &gsi))
2653*38fd1498Szrj return;
2654*38fd1498Szrj break;
2655*38fd1498Szrj
2656*38fd1498Szrj case GIMPLE_ASM:
2657*38fd1498Szrj gcc_unreachable ();
2658*38fd1498Szrj
2659*38fd1498Szrj default:
2660*38fd1498Szrj break;
2661*38fd1498Szrj }
2662*38fd1498Szrj if (!gsi_end_p (gsi))
2663*38fd1498Szrj gsi_next (&gsi);
2664*38fd1498Szrj }
2665*38fd1498Szrj }
2666*38fd1498Szrj
2667*38fd1498Szrj /* Return the list of basic-blocks in REGION.
2668*38fd1498Szrj
2669*38fd1498Szrj STOP_AT_IRREVOCABLE_P is true if caller is uninterested in blocks
2670*38fd1498Szrj following a TM_IRREVOCABLE call.
2671*38fd1498Szrj
2672*38fd1498Szrj INCLUDE_UNINSTRUMENTED_P is TRUE if we should include the
2673*38fd1498Szrj uninstrumented code path blocks in the list of basic blocks
2674*38fd1498Szrj returned, false otherwise. */
2675*38fd1498Szrj
2676*38fd1498Szrj static vec<basic_block>
2677*38fd1498Szrj get_tm_region_blocks (basic_block entry_block,
2678*38fd1498Szrj bitmap exit_blocks,
2679*38fd1498Szrj bitmap irr_blocks,
2680*38fd1498Szrj bitmap all_region_blocks,
2681*38fd1498Szrj bool stop_at_irrevocable_p,
2682*38fd1498Szrj bool include_uninstrumented_p = true)
2683*38fd1498Szrj {
2684*38fd1498Szrj vec<basic_block> bbs = vNULL;
2685*38fd1498Szrj unsigned i;
2686*38fd1498Szrj edge e;
2687*38fd1498Szrj edge_iterator ei;
2688*38fd1498Szrj bitmap visited_blocks = BITMAP_ALLOC (NULL);
2689*38fd1498Szrj
2690*38fd1498Szrj i = 0;
2691*38fd1498Szrj bbs.safe_push (entry_block);
2692*38fd1498Szrj bitmap_set_bit (visited_blocks, entry_block->index);
2693*38fd1498Szrj
2694*38fd1498Szrj do
2695*38fd1498Szrj {
2696*38fd1498Szrj basic_block bb = bbs[i++];
2697*38fd1498Szrj
2698*38fd1498Szrj if (exit_blocks &&
2699*38fd1498Szrj bitmap_bit_p (exit_blocks, bb->index))
2700*38fd1498Szrj continue;
2701*38fd1498Szrj
2702*38fd1498Szrj if (stop_at_irrevocable_p
2703*38fd1498Szrj && irr_blocks
2704*38fd1498Szrj && bitmap_bit_p (irr_blocks, bb->index))
2705*38fd1498Szrj continue;
2706*38fd1498Szrj
2707*38fd1498Szrj FOR_EACH_EDGE (e, ei, bb->succs)
2708*38fd1498Szrj if ((include_uninstrumented_p
2709*38fd1498Szrj || !(e->flags & EDGE_TM_UNINSTRUMENTED))
2710*38fd1498Szrj && !bitmap_bit_p (visited_blocks, e->dest->index))
2711*38fd1498Szrj {
2712*38fd1498Szrj bitmap_set_bit (visited_blocks, e->dest->index);
2713*38fd1498Szrj bbs.safe_push (e->dest);
2714*38fd1498Szrj }
2715*38fd1498Szrj }
2716*38fd1498Szrj while (i < bbs.length ());
2717*38fd1498Szrj
2718*38fd1498Szrj if (all_region_blocks)
2719*38fd1498Szrj bitmap_ior_into (all_region_blocks, visited_blocks);
2720*38fd1498Szrj
2721*38fd1498Szrj BITMAP_FREE (visited_blocks);
2722*38fd1498Szrj return bbs;
2723*38fd1498Szrj }
2724*38fd1498Szrj
2725*38fd1498Szrj // Callback data for collect_bb2reg.
2726*38fd1498Szrj struct bb2reg_stuff
2727*38fd1498Szrj {
2728*38fd1498Szrj vec<tm_region *> *bb2reg;
2729*38fd1498Szrj bool include_uninstrumented_p;
2730*38fd1498Szrj };
2731*38fd1498Szrj
2732*38fd1498Szrj // Callback for expand_regions, collect innermost region data for each bb.
2733*38fd1498Szrj static void *
collect_bb2reg(struct tm_region * region,void * data)2734*38fd1498Szrj collect_bb2reg (struct tm_region *region, void *data)
2735*38fd1498Szrj {
2736*38fd1498Szrj struct bb2reg_stuff *stuff = (struct bb2reg_stuff *)data;
2737*38fd1498Szrj vec<tm_region *> *bb2reg = stuff->bb2reg;
2738*38fd1498Szrj vec<basic_block> queue;
2739*38fd1498Szrj unsigned int i;
2740*38fd1498Szrj basic_block bb;
2741*38fd1498Szrj
2742*38fd1498Szrj queue = get_tm_region_blocks (region->entry_block,
2743*38fd1498Szrj region->exit_blocks,
2744*38fd1498Szrj region->irr_blocks,
2745*38fd1498Szrj NULL,
2746*38fd1498Szrj /*stop_at_irr_p=*/true,
2747*38fd1498Szrj stuff->include_uninstrumented_p);
2748*38fd1498Szrj
2749*38fd1498Szrj // We expect expand_region to perform a post-order traversal of the region
2750*38fd1498Szrj // tree. Therefore the last region seen for any bb is the innermost.
2751*38fd1498Szrj FOR_EACH_VEC_ELT (queue, i, bb)
2752*38fd1498Szrj (*bb2reg)[bb->index] = region;
2753*38fd1498Szrj
2754*38fd1498Szrj queue.release ();
2755*38fd1498Szrj return NULL;
2756*38fd1498Szrj }
2757*38fd1498Szrj
2758*38fd1498Szrj // Returns a vector, indexed by BB->INDEX, of the innermost tm_region to
2759*38fd1498Szrj // which a basic block belongs. Note that we only consider the instrumented
2760*38fd1498Szrj // code paths for the region; the uninstrumented code paths are ignored if
2761*38fd1498Szrj // INCLUDE_UNINSTRUMENTED_P is false.
2762*38fd1498Szrj //
2763*38fd1498Szrj // ??? This data is very similar to the bb_regions array that is collected
2764*38fd1498Szrj // during tm_region_init. Or, rather, this data is similar to what could
2765*38fd1498Szrj // be used within tm_region_init. The actual computation in tm_region_init
2766*38fd1498Szrj // begins and ends with bb_regions entirely full of NULL pointers, due to
2767*38fd1498Szrj // the way in which pointers are swapped in and out of the array.
2768*38fd1498Szrj //
2769*38fd1498Szrj // ??? Our callers expect that blocks are not shared between transactions.
2770*38fd1498Szrj // When the optimizers get too smart, and blocks are shared, then during
2771*38fd1498Szrj // the tm_mark phase we'll add log entries to only one of the two transactions,
2772*38fd1498Szrj // and in the tm_edge phase we'll add edges to the CFG that create invalid
2773*38fd1498Szrj // cycles. The symptom being SSA defs that do not dominate their uses.
2774*38fd1498Szrj // Note that the optimizers were locally correct with their transformation,
2775*38fd1498Szrj // as we have no info within the program that suggests that the blocks cannot
2776*38fd1498Szrj // be shared.
2777*38fd1498Szrj //
2778*38fd1498Szrj // ??? There is currently a hack inside tree-ssa-pre.c to work around the
2779*38fd1498Szrj // only known instance of this block sharing.
2780*38fd1498Szrj
2781*38fd1498Szrj static vec<tm_region *>
get_bb_regions_instrumented(bool traverse_clones,bool include_uninstrumented_p)2782*38fd1498Szrj get_bb_regions_instrumented (bool traverse_clones,
2783*38fd1498Szrj bool include_uninstrumented_p)
2784*38fd1498Szrj {
2785*38fd1498Szrj unsigned n = last_basic_block_for_fn (cfun);
2786*38fd1498Szrj struct bb2reg_stuff stuff;
2787*38fd1498Szrj vec<tm_region *> ret;
2788*38fd1498Szrj
2789*38fd1498Szrj ret.create (n);
2790*38fd1498Szrj ret.safe_grow_cleared (n);
2791*38fd1498Szrj stuff.bb2reg = &ret;
2792*38fd1498Szrj stuff.include_uninstrumented_p = include_uninstrumented_p;
2793*38fd1498Szrj expand_regions (all_tm_regions, collect_bb2reg, &stuff, traverse_clones);
2794*38fd1498Szrj
2795*38fd1498Szrj return ret;
2796*38fd1498Szrj }
2797*38fd1498Szrj
2798*38fd1498Szrj /* Set the IN_TRANSACTION for all gimple statements that appear in a
2799*38fd1498Szrj transaction. */
2800*38fd1498Szrj
2801*38fd1498Szrj void
compute_transaction_bits(void)2802*38fd1498Szrj compute_transaction_bits (void)
2803*38fd1498Szrj {
2804*38fd1498Szrj struct tm_region *region;
2805*38fd1498Szrj vec<basic_block> queue;
2806*38fd1498Szrj unsigned int i;
2807*38fd1498Szrj basic_block bb;
2808*38fd1498Szrj
2809*38fd1498Szrj /* ?? Perhaps we need to abstract gate_tm_init further, because we
2810*38fd1498Szrj certainly don't need it to calculate CDI_DOMINATOR info. */
2811*38fd1498Szrj gate_tm_init ();
2812*38fd1498Szrj
2813*38fd1498Szrj FOR_EACH_BB_FN (bb, cfun)
2814*38fd1498Szrj bb->flags &= ~BB_IN_TRANSACTION;
2815*38fd1498Szrj
2816*38fd1498Szrj for (region = all_tm_regions; region; region = region->next)
2817*38fd1498Szrj {
2818*38fd1498Szrj queue = get_tm_region_blocks (region->entry_block,
2819*38fd1498Szrj region->exit_blocks,
2820*38fd1498Szrj region->irr_blocks,
2821*38fd1498Szrj NULL,
2822*38fd1498Szrj /*stop_at_irr_p=*/true);
2823*38fd1498Szrj for (i = 0; queue.iterate (i, &bb); ++i)
2824*38fd1498Szrj bb->flags |= BB_IN_TRANSACTION;
2825*38fd1498Szrj queue.release ();
2826*38fd1498Szrj }
2827*38fd1498Szrj
2828*38fd1498Szrj if (all_tm_regions)
2829*38fd1498Szrj bitmap_obstack_release (&tm_obstack);
2830*38fd1498Szrj }
2831*38fd1498Szrj
2832*38fd1498Szrj /* Replace the GIMPLE_TRANSACTION in this region with the corresponding
2833*38fd1498Szrj call to BUILT_IN_TM_START. */
2834*38fd1498Szrj
2835*38fd1498Szrj static void *
expand_transaction(struct tm_region * region,void * data ATTRIBUTE_UNUSED)2836*38fd1498Szrj expand_transaction (struct tm_region *region, void *data ATTRIBUTE_UNUSED)
2837*38fd1498Szrj {
2838*38fd1498Szrj tree tm_start = builtin_decl_explicit (BUILT_IN_TM_START);
2839*38fd1498Szrj basic_block transaction_bb = gimple_bb (region->transaction_stmt);
2840*38fd1498Szrj tree tm_state = region->tm_state;
2841*38fd1498Szrj tree tm_state_type = TREE_TYPE (tm_state);
2842*38fd1498Szrj edge abort_edge = NULL;
2843*38fd1498Szrj edge inst_edge = NULL;
2844*38fd1498Szrj edge uninst_edge = NULL;
2845*38fd1498Szrj edge fallthru_edge = NULL;
2846*38fd1498Szrj
2847*38fd1498Szrj // Identify the various successors of the transaction start.
2848*38fd1498Szrj {
2849*38fd1498Szrj edge_iterator i;
2850*38fd1498Szrj edge e;
2851*38fd1498Szrj FOR_EACH_EDGE (e, i, transaction_bb->succs)
2852*38fd1498Szrj {
2853*38fd1498Szrj if (e->flags & EDGE_TM_ABORT)
2854*38fd1498Szrj abort_edge = e;
2855*38fd1498Szrj else if (e->flags & EDGE_TM_UNINSTRUMENTED)
2856*38fd1498Szrj uninst_edge = e;
2857*38fd1498Szrj else
2858*38fd1498Szrj inst_edge = e;
2859*38fd1498Szrj if (e->flags & EDGE_FALLTHRU)
2860*38fd1498Szrj fallthru_edge = e;
2861*38fd1498Szrj }
2862*38fd1498Szrj }
2863*38fd1498Szrj
2864*38fd1498Szrj /* ??? There are plenty of bits here we're not computing. */
2865*38fd1498Szrj {
2866*38fd1498Szrj int subcode = gimple_transaction_subcode (region->get_transaction_stmt ());
2867*38fd1498Szrj int flags = 0;
2868*38fd1498Szrj if (subcode & GTMA_DOES_GO_IRREVOCABLE)
2869*38fd1498Szrj flags |= PR_DOESGOIRREVOCABLE;
2870*38fd1498Szrj if ((subcode & GTMA_MAY_ENTER_IRREVOCABLE) == 0)
2871*38fd1498Szrj flags |= PR_HASNOIRREVOCABLE;
2872*38fd1498Szrj /* If the transaction does not have an abort in lexical scope and is not
2873*38fd1498Szrj marked as an outer transaction, then it will never abort. */
2874*38fd1498Szrj if ((subcode & GTMA_HAVE_ABORT) == 0 && (subcode & GTMA_IS_OUTER) == 0)
2875*38fd1498Szrj flags |= PR_HASNOABORT;
2876*38fd1498Szrj if ((subcode & GTMA_HAVE_STORE) == 0)
2877*38fd1498Szrj flags |= PR_READONLY;
2878*38fd1498Szrj if (inst_edge && !(subcode & GTMA_HAS_NO_INSTRUMENTATION))
2879*38fd1498Szrj flags |= PR_INSTRUMENTEDCODE;
2880*38fd1498Szrj if (uninst_edge)
2881*38fd1498Szrj flags |= PR_UNINSTRUMENTEDCODE;
2882*38fd1498Szrj if (subcode & GTMA_IS_OUTER)
2883*38fd1498Szrj region->original_transaction_was_outer = true;
2884*38fd1498Szrj tree t = build_int_cst (tm_state_type, flags);
2885*38fd1498Szrj gcall *call = gimple_build_call (tm_start, 1, t);
2886*38fd1498Szrj gimple_call_set_lhs (call, tm_state);
2887*38fd1498Szrj gimple_set_location (call, gimple_location (region->transaction_stmt));
2888*38fd1498Szrj
2889*38fd1498Szrj // Replace the GIMPLE_TRANSACTION with the call to BUILT_IN_TM_START.
2890*38fd1498Szrj gimple_stmt_iterator gsi = gsi_last_bb (transaction_bb);
2891*38fd1498Szrj gcc_assert (gsi_stmt (gsi) == region->transaction_stmt);
2892*38fd1498Szrj gsi_insert_before (&gsi, call, GSI_SAME_STMT);
2893*38fd1498Szrj gsi_remove (&gsi, true);
2894*38fd1498Szrj region->transaction_stmt = call;
2895*38fd1498Szrj }
2896*38fd1498Szrj
2897*38fd1498Szrj // Generate log saves.
2898*38fd1498Szrj if (!tm_log_save_addresses.is_empty ())
2899*38fd1498Szrj tm_log_emit_saves (region->entry_block, transaction_bb);
2900*38fd1498Szrj
2901*38fd1498Szrj // In the beginning, we've no tests to perform on transaction restart.
2902*38fd1498Szrj // Note that after this point, transaction_bb becomes the "most recent
2903*38fd1498Szrj // block containing tests for the transaction".
2904*38fd1498Szrj region->restart_block = region->entry_block;
2905*38fd1498Szrj
2906*38fd1498Szrj // Generate log restores.
2907*38fd1498Szrj if (!tm_log_save_addresses.is_empty ())
2908*38fd1498Szrj {
2909*38fd1498Szrj basic_block test_bb = create_empty_bb (transaction_bb);
2910*38fd1498Szrj basic_block code_bb = create_empty_bb (test_bb);
2911*38fd1498Szrj basic_block join_bb = create_empty_bb (code_bb);
2912*38fd1498Szrj add_bb_to_loop (test_bb, transaction_bb->loop_father);
2913*38fd1498Szrj add_bb_to_loop (code_bb, transaction_bb->loop_father);
2914*38fd1498Szrj add_bb_to_loop (join_bb, transaction_bb->loop_father);
2915*38fd1498Szrj if (region->restart_block == region->entry_block)
2916*38fd1498Szrj region->restart_block = test_bb;
2917*38fd1498Szrj
2918*38fd1498Szrj tree t1 = create_tmp_reg (tm_state_type);
2919*38fd1498Szrj tree t2 = build_int_cst (tm_state_type, A_RESTORELIVEVARIABLES);
2920*38fd1498Szrj gimple *stmt = gimple_build_assign (t1, BIT_AND_EXPR, tm_state, t2);
2921*38fd1498Szrj gimple_stmt_iterator gsi = gsi_last_bb (test_bb);
2922*38fd1498Szrj gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
2923*38fd1498Szrj
2924*38fd1498Szrj t2 = build_int_cst (tm_state_type, 0);
2925*38fd1498Szrj stmt = gimple_build_cond (NE_EXPR, t1, t2, NULL, NULL);
2926*38fd1498Szrj gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
2927*38fd1498Szrj
2928*38fd1498Szrj tm_log_emit_restores (region->entry_block, code_bb);
2929*38fd1498Szrj
2930*38fd1498Szrj edge ei = make_edge (transaction_bb, test_bb, EDGE_FALLTHRU);
2931*38fd1498Szrj edge et = make_edge (test_bb, code_bb, EDGE_TRUE_VALUE);
2932*38fd1498Szrj edge ef = make_edge (test_bb, join_bb, EDGE_FALSE_VALUE);
2933*38fd1498Szrj redirect_edge_pred (fallthru_edge, join_bb);
2934*38fd1498Szrj
2935*38fd1498Szrj join_bb->count = test_bb->count = transaction_bb->count;
2936*38fd1498Szrj
2937*38fd1498Szrj ei->probability = profile_probability::always ();
2938*38fd1498Szrj et->probability = profile_probability::likely ();
2939*38fd1498Szrj ef->probability = profile_probability::unlikely ();
2940*38fd1498Szrj
2941*38fd1498Szrj code_bb->count = et->count ();
2942*38fd1498Szrj
2943*38fd1498Szrj transaction_bb = join_bb;
2944*38fd1498Szrj }
2945*38fd1498Szrj
2946*38fd1498Szrj // If we have an ABORT edge, create a test to perform the abort.
2947*38fd1498Szrj if (abort_edge)
2948*38fd1498Szrj {
2949*38fd1498Szrj basic_block test_bb = create_empty_bb (transaction_bb);
2950*38fd1498Szrj add_bb_to_loop (test_bb, transaction_bb->loop_father);
2951*38fd1498Szrj if (region->restart_block == region->entry_block)
2952*38fd1498Szrj region->restart_block = test_bb;
2953*38fd1498Szrj
2954*38fd1498Szrj tree t1 = create_tmp_reg (tm_state_type);
2955*38fd1498Szrj tree t2 = build_int_cst (tm_state_type, A_ABORTTRANSACTION);
2956*38fd1498Szrj gimple *stmt = gimple_build_assign (t1, BIT_AND_EXPR, tm_state, t2);
2957*38fd1498Szrj gimple_stmt_iterator gsi = gsi_last_bb (test_bb);
2958*38fd1498Szrj gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
2959*38fd1498Szrj
2960*38fd1498Szrj t2 = build_int_cst (tm_state_type, 0);
2961*38fd1498Szrj stmt = gimple_build_cond (NE_EXPR, t1, t2, NULL, NULL);
2962*38fd1498Szrj gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
2963*38fd1498Szrj
2964*38fd1498Szrj edge ei = make_edge (transaction_bb, test_bb, EDGE_FALLTHRU);
2965*38fd1498Szrj test_bb->count = transaction_bb->count;
2966*38fd1498Szrj ei->probability = profile_probability::always ();
2967*38fd1498Szrj
2968*38fd1498Szrj // Not abort edge. If both are live, chose one at random as we'll
2969*38fd1498Szrj // we'll be fixing that up below.
2970*38fd1498Szrj redirect_edge_pred (fallthru_edge, test_bb);
2971*38fd1498Szrj fallthru_edge->flags = EDGE_FALSE_VALUE;
2972*38fd1498Szrj fallthru_edge->probability = profile_probability::very_likely ();
2973*38fd1498Szrj
2974*38fd1498Szrj // Abort/over edge.
2975*38fd1498Szrj redirect_edge_pred (abort_edge, test_bb);
2976*38fd1498Szrj abort_edge->flags = EDGE_TRUE_VALUE;
2977*38fd1498Szrj abort_edge->probability = profile_probability::unlikely ();
2978*38fd1498Szrj
2979*38fd1498Szrj transaction_bb = test_bb;
2980*38fd1498Szrj }
2981*38fd1498Szrj
2982*38fd1498Szrj // If we have both instrumented and uninstrumented code paths, select one.
2983*38fd1498Szrj if (inst_edge && uninst_edge)
2984*38fd1498Szrj {
2985*38fd1498Szrj basic_block test_bb = create_empty_bb (transaction_bb);
2986*38fd1498Szrj add_bb_to_loop (test_bb, transaction_bb->loop_father);
2987*38fd1498Szrj if (region->restart_block == region->entry_block)
2988*38fd1498Szrj region->restart_block = test_bb;
2989*38fd1498Szrj
2990*38fd1498Szrj tree t1 = create_tmp_reg (tm_state_type);
2991*38fd1498Szrj tree t2 = build_int_cst (tm_state_type, A_RUNUNINSTRUMENTEDCODE);
2992*38fd1498Szrj
2993*38fd1498Szrj gimple *stmt = gimple_build_assign (t1, BIT_AND_EXPR, tm_state, t2);
2994*38fd1498Szrj gimple_stmt_iterator gsi = gsi_last_bb (test_bb);
2995*38fd1498Szrj gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
2996*38fd1498Szrj
2997*38fd1498Szrj t2 = build_int_cst (tm_state_type, 0);
2998*38fd1498Szrj stmt = gimple_build_cond (NE_EXPR, t1, t2, NULL, NULL);
2999*38fd1498Szrj gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
3000*38fd1498Szrj
3001*38fd1498Szrj // Create the edge into test_bb first, as we want to copy values
3002*38fd1498Szrj // out of the fallthru edge.
3003*38fd1498Szrj edge e = make_edge (transaction_bb, test_bb, fallthru_edge->flags);
3004*38fd1498Szrj e->probability = fallthru_edge->probability;
3005*38fd1498Szrj test_bb->count = fallthru_edge->count ();
3006*38fd1498Szrj
3007*38fd1498Szrj // Now update the edges to the inst/uninist implementations.
3008*38fd1498Szrj // For now assume that the paths are equally likely. When using HTM,
3009*38fd1498Szrj // we'll try the uninst path first and fallback to inst path if htm
3010*38fd1498Szrj // buffers are exceeded. Without HTM we start with the inst path and
3011*38fd1498Szrj // use the uninst path when falling back to serial mode.
3012*38fd1498Szrj redirect_edge_pred (inst_edge, test_bb);
3013*38fd1498Szrj inst_edge->flags = EDGE_FALSE_VALUE;
3014*38fd1498Szrj inst_edge->probability = profile_probability::even ();
3015*38fd1498Szrj
3016*38fd1498Szrj redirect_edge_pred (uninst_edge, test_bb);
3017*38fd1498Szrj uninst_edge->flags = EDGE_TRUE_VALUE;
3018*38fd1498Szrj uninst_edge->probability = profile_probability::even ();
3019*38fd1498Szrj }
3020*38fd1498Szrj
3021*38fd1498Szrj // If we have no previous special cases, and we have PHIs at the beginning
3022*38fd1498Szrj // of the atomic region, this means we have a loop at the beginning of the
3023*38fd1498Szrj // atomic region that shares the first block. This can cause problems with
3024*38fd1498Szrj // the transaction restart abnormal edges to be added in the tm_edges pass.
3025*38fd1498Szrj // Solve this by adding a new empty block to receive the abnormal edges.
3026*38fd1498Szrj if (region->restart_block == region->entry_block
3027*38fd1498Szrj && phi_nodes (region->entry_block))
3028*38fd1498Szrj {
3029*38fd1498Szrj basic_block empty_bb = create_empty_bb (transaction_bb);
3030*38fd1498Szrj region->restart_block = empty_bb;
3031*38fd1498Szrj add_bb_to_loop (empty_bb, transaction_bb->loop_father);
3032*38fd1498Szrj
3033*38fd1498Szrj redirect_edge_pred (fallthru_edge, empty_bb);
3034*38fd1498Szrj make_edge (transaction_bb, empty_bb, EDGE_FALLTHRU);
3035*38fd1498Szrj }
3036*38fd1498Szrj
3037*38fd1498Szrj return NULL;
3038*38fd1498Szrj }
3039*38fd1498Szrj
3040*38fd1498Szrj /* Generate the temporary to be used for the return value of
3041*38fd1498Szrj BUILT_IN_TM_START. */
3042*38fd1498Szrj
3043*38fd1498Szrj static void *
generate_tm_state(struct tm_region * region,void * data ATTRIBUTE_UNUSED)3044*38fd1498Szrj generate_tm_state (struct tm_region *region, void *data ATTRIBUTE_UNUSED)
3045*38fd1498Szrj {
3046*38fd1498Szrj tree tm_start = builtin_decl_explicit (BUILT_IN_TM_START);
3047*38fd1498Szrj region->tm_state =
3048*38fd1498Szrj create_tmp_reg (TREE_TYPE (TREE_TYPE (tm_start)), "tm_state");
3049*38fd1498Szrj
3050*38fd1498Szrj // Reset the subcode, post optimizations. We'll fill this in
3051*38fd1498Szrj // again as we process blocks.
3052*38fd1498Szrj if (region->exit_blocks)
3053*38fd1498Szrj {
3054*38fd1498Szrj gtransaction *transaction_stmt = region->get_transaction_stmt ();
3055*38fd1498Szrj unsigned int subcode = gimple_transaction_subcode (transaction_stmt);
3056*38fd1498Szrj
3057*38fd1498Szrj if (subcode & GTMA_DOES_GO_IRREVOCABLE)
3058*38fd1498Szrj subcode &= (GTMA_DECLARATION_MASK | GTMA_DOES_GO_IRREVOCABLE
3059*38fd1498Szrj | GTMA_MAY_ENTER_IRREVOCABLE
3060*38fd1498Szrj | GTMA_HAS_NO_INSTRUMENTATION);
3061*38fd1498Szrj else
3062*38fd1498Szrj subcode &= GTMA_DECLARATION_MASK;
3063*38fd1498Szrj gimple_transaction_set_subcode (transaction_stmt, subcode);
3064*38fd1498Szrj }
3065*38fd1498Szrj
3066*38fd1498Szrj return NULL;
3067*38fd1498Szrj }
3068*38fd1498Szrj
3069*38fd1498Szrj // Propagate flags from inner transactions outwards.
3070*38fd1498Szrj static void
propagate_tm_flags_out(struct tm_region * region)3071*38fd1498Szrj propagate_tm_flags_out (struct tm_region *region)
3072*38fd1498Szrj {
3073*38fd1498Szrj if (region == NULL)
3074*38fd1498Szrj return;
3075*38fd1498Szrj propagate_tm_flags_out (region->inner);
3076*38fd1498Szrj
3077*38fd1498Szrj if (region->outer && region->outer->transaction_stmt)
3078*38fd1498Szrj {
3079*38fd1498Szrj unsigned s
3080*38fd1498Szrj = gimple_transaction_subcode (region->get_transaction_stmt ());
3081*38fd1498Szrj s &= (GTMA_HAVE_ABORT | GTMA_HAVE_LOAD | GTMA_HAVE_STORE
3082*38fd1498Szrj | GTMA_MAY_ENTER_IRREVOCABLE);
3083*38fd1498Szrj s |= gimple_transaction_subcode (region->outer->get_transaction_stmt ());
3084*38fd1498Szrj gimple_transaction_set_subcode (region->outer->get_transaction_stmt (),
3085*38fd1498Szrj s);
3086*38fd1498Szrj }
3087*38fd1498Szrj
3088*38fd1498Szrj propagate_tm_flags_out (region->next);
3089*38fd1498Szrj }
3090*38fd1498Szrj
3091*38fd1498Szrj /* Entry point to the MARK phase of TM expansion. Here we replace
3092*38fd1498Szrj transactional memory statements with calls to builtins, and function
3093*38fd1498Szrj calls with their transactional clones (if available). But we don't
3094*38fd1498Szrj yet lower GIMPLE_TRANSACTION or add the transaction restart back-edges. */
3095*38fd1498Szrj
3096*38fd1498Szrj static unsigned int
execute_tm_mark(void)3097*38fd1498Szrj execute_tm_mark (void)
3098*38fd1498Szrj {
3099*38fd1498Szrj pending_edge_inserts_p = false;
3100*38fd1498Szrj
3101*38fd1498Szrj expand_regions (all_tm_regions, generate_tm_state, NULL,
3102*38fd1498Szrj /*traverse_clones=*/true);
3103*38fd1498Szrj
3104*38fd1498Szrj tm_log_init ();
3105*38fd1498Szrj
3106*38fd1498Szrj vec<tm_region *> bb_regions
3107*38fd1498Szrj = get_bb_regions_instrumented (/*traverse_clones=*/true,
3108*38fd1498Szrj /*include_uninstrumented_p=*/false);
3109*38fd1498Szrj struct tm_region *r;
3110*38fd1498Szrj unsigned i;
3111*38fd1498Szrj
3112*38fd1498Szrj // Expand memory operations into calls into the runtime.
3113*38fd1498Szrj // This collects log entries as well.
3114*38fd1498Szrj FOR_EACH_VEC_ELT (bb_regions, i, r)
3115*38fd1498Szrj {
3116*38fd1498Szrj if (r != NULL)
3117*38fd1498Szrj {
3118*38fd1498Szrj if (r->transaction_stmt)
3119*38fd1498Szrj {
3120*38fd1498Szrj unsigned sub
3121*38fd1498Szrj = gimple_transaction_subcode (r->get_transaction_stmt ());
3122*38fd1498Szrj
3123*38fd1498Szrj /* If we're sure to go irrevocable, there won't be
3124*38fd1498Szrj anything to expand, since the run-time will go
3125*38fd1498Szrj irrevocable right away. */
3126*38fd1498Szrj if (sub & GTMA_DOES_GO_IRREVOCABLE
3127*38fd1498Szrj && sub & GTMA_MAY_ENTER_IRREVOCABLE)
3128*38fd1498Szrj continue;
3129*38fd1498Szrj }
3130*38fd1498Szrj expand_block_tm (r, BASIC_BLOCK_FOR_FN (cfun, i));
3131*38fd1498Szrj }
3132*38fd1498Szrj }
3133*38fd1498Szrj
3134*38fd1498Szrj bb_regions.release ();
3135*38fd1498Szrj
3136*38fd1498Szrj // Propagate flags from inner transactions outwards.
3137*38fd1498Szrj propagate_tm_flags_out (all_tm_regions);
3138*38fd1498Szrj
3139*38fd1498Szrj // Expand GIMPLE_TRANSACTIONs into calls into the runtime.
3140*38fd1498Szrj expand_regions (all_tm_regions, expand_transaction, NULL,
3141*38fd1498Szrj /*traverse_clones=*/false);
3142*38fd1498Szrj
3143*38fd1498Szrj tm_log_emit ();
3144*38fd1498Szrj tm_log_delete ();
3145*38fd1498Szrj
3146*38fd1498Szrj if (pending_edge_inserts_p)
3147*38fd1498Szrj gsi_commit_edge_inserts ();
3148*38fd1498Szrj free_dominance_info (CDI_DOMINATORS);
3149*38fd1498Szrj return 0;
3150*38fd1498Szrj }
3151*38fd1498Szrj
3152*38fd1498Szrj namespace {
3153*38fd1498Szrj
3154*38fd1498Szrj const pass_data pass_data_tm_mark =
3155*38fd1498Szrj {
3156*38fd1498Szrj GIMPLE_PASS, /* type */
3157*38fd1498Szrj "tmmark", /* name */
3158*38fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */
3159*38fd1498Szrj TV_TRANS_MEM, /* tv_id */
3160*38fd1498Szrj ( PROP_ssa | PROP_cfg ), /* properties_required */
3161*38fd1498Szrj 0, /* properties_provided */
3162*38fd1498Szrj 0, /* properties_destroyed */
3163*38fd1498Szrj 0, /* todo_flags_start */
3164*38fd1498Szrj TODO_update_ssa, /* todo_flags_finish */
3165*38fd1498Szrj };
3166*38fd1498Szrj
3167*38fd1498Szrj class pass_tm_mark : public gimple_opt_pass
3168*38fd1498Szrj {
3169*38fd1498Szrj public:
pass_tm_mark(gcc::context * ctxt)3170*38fd1498Szrj pass_tm_mark (gcc::context *ctxt)
3171*38fd1498Szrj : gimple_opt_pass (pass_data_tm_mark, ctxt)
3172*38fd1498Szrj {}
3173*38fd1498Szrj
3174*38fd1498Szrj /* opt_pass methods: */
execute(function *)3175*38fd1498Szrj virtual unsigned int execute (function *) { return execute_tm_mark (); }
3176*38fd1498Szrj
3177*38fd1498Szrj }; // class pass_tm_mark
3178*38fd1498Szrj
3179*38fd1498Szrj } // anon namespace
3180*38fd1498Szrj
3181*38fd1498Szrj gimple_opt_pass *
make_pass_tm_mark(gcc::context * ctxt)3182*38fd1498Szrj make_pass_tm_mark (gcc::context *ctxt)
3183*38fd1498Szrj {
3184*38fd1498Szrj return new pass_tm_mark (ctxt);
3185*38fd1498Szrj }
3186*38fd1498Szrj
3187*38fd1498Szrj
3188*38fd1498Szrj /* Create an abnormal edge from STMT at iter, splitting the block
3189*38fd1498Szrj as necessary. Adjust *PNEXT as needed for the split block. */
3190*38fd1498Szrj
3191*38fd1498Szrj static inline void
split_bb_make_tm_edge(gimple * stmt,basic_block dest_bb,gimple_stmt_iterator iter,gimple_stmt_iterator * pnext)3192*38fd1498Szrj split_bb_make_tm_edge (gimple *stmt, basic_block dest_bb,
3193*38fd1498Szrj gimple_stmt_iterator iter, gimple_stmt_iterator *pnext)
3194*38fd1498Szrj {
3195*38fd1498Szrj basic_block bb = gimple_bb (stmt);
3196*38fd1498Szrj if (!gsi_one_before_end_p (iter))
3197*38fd1498Szrj {
3198*38fd1498Szrj edge e = split_block (bb, stmt);
3199*38fd1498Szrj *pnext = gsi_start_bb (e->dest);
3200*38fd1498Szrj }
3201*38fd1498Szrj edge e = make_edge (bb, dest_bb, EDGE_ABNORMAL);
3202*38fd1498Szrj if (e)
3203*38fd1498Szrj e->probability = profile_probability::guessed_never ();
3204*38fd1498Szrj
3205*38fd1498Szrj // Record the need for the edge for the benefit of the rtl passes.
3206*38fd1498Szrj if (cfun->gimple_df->tm_restart == NULL)
3207*38fd1498Szrj cfun->gimple_df->tm_restart
3208*38fd1498Szrj = hash_table<tm_restart_hasher>::create_ggc (31);
3209*38fd1498Szrj
3210*38fd1498Szrj struct tm_restart_node dummy;
3211*38fd1498Szrj dummy.stmt = stmt;
3212*38fd1498Szrj dummy.label_or_list = gimple_block_label (dest_bb);
3213*38fd1498Szrj
3214*38fd1498Szrj tm_restart_node **slot = cfun->gimple_df->tm_restart->find_slot (&dummy,
3215*38fd1498Szrj INSERT);
3216*38fd1498Szrj struct tm_restart_node *n = *slot;
3217*38fd1498Szrj if (n == NULL)
3218*38fd1498Szrj {
3219*38fd1498Szrj n = ggc_alloc<tm_restart_node> ();
3220*38fd1498Szrj *n = dummy;
3221*38fd1498Szrj }
3222*38fd1498Szrj else
3223*38fd1498Szrj {
3224*38fd1498Szrj tree old = n->label_or_list;
3225*38fd1498Szrj if (TREE_CODE (old) == LABEL_DECL)
3226*38fd1498Szrj old = tree_cons (NULL, old, NULL);
3227*38fd1498Szrj n->label_or_list = tree_cons (NULL, dummy.label_or_list, old);
3228*38fd1498Szrj }
3229*38fd1498Szrj }
3230*38fd1498Szrj
3231*38fd1498Szrj /* Split block BB as necessary for every builtin function we added, and
3232*38fd1498Szrj wire up the abnormal back edges implied by the transaction restart. */
3233*38fd1498Szrj
3234*38fd1498Szrj static void
expand_block_edges(struct tm_region * const region,basic_block bb)3235*38fd1498Szrj expand_block_edges (struct tm_region *const region, basic_block bb)
3236*38fd1498Szrj {
3237*38fd1498Szrj gimple_stmt_iterator gsi, next_gsi;
3238*38fd1498Szrj
3239*38fd1498Szrj for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi = next_gsi)
3240*38fd1498Szrj {
3241*38fd1498Szrj gimple *stmt = gsi_stmt (gsi);
3242*38fd1498Szrj gcall *call_stmt;
3243*38fd1498Szrj
3244*38fd1498Szrj next_gsi = gsi;
3245*38fd1498Szrj gsi_next (&next_gsi);
3246*38fd1498Szrj
3247*38fd1498Szrj // ??? Shouldn't we split for any non-pure, non-irrevocable function?
3248*38fd1498Szrj call_stmt = dyn_cast <gcall *> (stmt);
3249*38fd1498Szrj if ((!call_stmt)
3250*38fd1498Szrj || (gimple_call_flags (call_stmt) & ECF_TM_BUILTIN) == 0)
3251*38fd1498Szrj continue;
3252*38fd1498Szrj
3253*38fd1498Szrj if (DECL_FUNCTION_CODE (gimple_call_fndecl (call_stmt))
3254*38fd1498Szrj == BUILT_IN_TM_ABORT)
3255*38fd1498Szrj {
3256*38fd1498Szrj // If we have a ``_transaction_cancel [[outer]]'', there is only
3257*38fd1498Szrj // one abnormal edge: to the transaction marked OUTER.
3258*38fd1498Szrj // All compiler-generated instances of BUILT_IN_TM_ABORT have a
3259*38fd1498Szrj // constant argument, which we can examine here. Users invoking
3260*38fd1498Szrj // TM_ABORT directly get what they deserve.
3261*38fd1498Szrj tree arg = gimple_call_arg (call_stmt, 0);
3262*38fd1498Szrj if (TREE_CODE (arg) == INTEGER_CST
3263*38fd1498Szrj && (TREE_INT_CST_LOW (arg) & AR_OUTERABORT) != 0
3264*38fd1498Szrj && !decl_is_tm_clone (current_function_decl))
3265*38fd1498Szrj {
3266*38fd1498Szrj // Find the GTMA_IS_OUTER transaction.
3267*38fd1498Szrj for (struct tm_region *o = region; o; o = o->outer)
3268*38fd1498Szrj if (o->original_transaction_was_outer)
3269*38fd1498Szrj {
3270*38fd1498Szrj split_bb_make_tm_edge (call_stmt, o->restart_block,
3271*38fd1498Szrj gsi, &next_gsi);
3272*38fd1498Szrj break;
3273*38fd1498Szrj }
3274*38fd1498Szrj
3275*38fd1498Szrj // Otherwise, the front-end should have semantically checked
3276*38fd1498Szrj // outer aborts, but in either case the target region is not
3277*38fd1498Szrj // within this function.
3278*38fd1498Szrj continue;
3279*38fd1498Szrj }
3280*38fd1498Szrj
3281*38fd1498Szrj // Non-outer, TM aborts have an abnormal edge to the inner-most
3282*38fd1498Szrj // transaction, the one being aborted;
3283*38fd1498Szrj split_bb_make_tm_edge (call_stmt, region->restart_block, gsi,
3284*38fd1498Szrj &next_gsi);
3285*38fd1498Szrj }
3286*38fd1498Szrj
3287*38fd1498Szrj // All TM builtins have an abnormal edge to the outer-most transaction.
3288*38fd1498Szrj // We never restart inner transactions. For tm clones, we know a-priori
3289*38fd1498Szrj // that the outer-most transaction is outside the function.
3290*38fd1498Szrj if (decl_is_tm_clone (current_function_decl))
3291*38fd1498Szrj continue;
3292*38fd1498Szrj
3293*38fd1498Szrj if (cfun->gimple_df->tm_restart == NULL)
3294*38fd1498Szrj cfun->gimple_df->tm_restart
3295*38fd1498Szrj = hash_table<tm_restart_hasher>::create_ggc (31);
3296*38fd1498Szrj
3297*38fd1498Szrj // All TM builtins have an abnormal edge to the outer-most transaction.
3298*38fd1498Szrj // We never restart inner transactions.
3299*38fd1498Szrj for (struct tm_region *o = region; o; o = o->outer)
3300*38fd1498Szrj if (!o->outer)
3301*38fd1498Szrj {
3302*38fd1498Szrj split_bb_make_tm_edge (call_stmt, o->restart_block, gsi, &next_gsi);
3303*38fd1498Szrj break;
3304*38fd1498Szrj }
3305*38fd1498Szrj
3306*38fd1498Szrj // Delete any tail-call annotation that may have been added.
3307*38fd1498Szrj // The tail-call pass may have mis-identified the commit as being
3308*38fd1498Szrj // a candidate because we had not yet added this restart edge.
3309*38fd1498Szrj gimple_call_set_tail (call_stmt, false);
3310*38fd1498Szrj }
3311*38fd1498Szrj }
3312*38fd1498Szrj
3313*38fd1498Szrj /* Entry point to the final expansion of transactional nodes. */
3314*38fd1498Szrj
3315*38fd1498Szrj namespace {
3316*38fd1498Szrj
3317*38fd1498Szrj const pass_data pass_data_tm_edges =
3318*38fd1498Szrj {
3319*38fd1498Szrj GIMPLE_PASS, /* type */
3320*38fd1498Szrj "tmedge", /* name */
3321*38fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */
3322*38fd1498Szrj TV_TRANS_MEM, /* tv_id */
3323*38fd1498Szrj ( PROP_ssa | PROP_cfg ), /* properties_required */
3324*38fd1498Szrj 0, /* properties_provided */
3325*38fd1498Szrj 0, /* properties_destroyed */
3326*38fd1498Szrj 0, /* todo_flags_start */
3327*38fd1498Szrj TODO_update_ssa, /* todo_flags_finish */
3328*38fd1498Szrj };
3329*38fd1498Szrj
3330*38fd1498Szrj class pass_tm_edges : public gimple_opt_pass
3331*38fd1498Szrj {
3332*38fd1498Szrj public:
pass_tm_edges(gcc::context * ctxt)3333*38fd1498Szrj pass_tm_edges (gcc::context *ctxt)
3334*38fd1498Szrj : gimple_opt_pass (pass_data_tm_edges, ctxt)
3335*38fd1498Szrj {}
3336*38fd1498Szrj
3337*38fd1498Szrj /* opt_pass methods: */
3338*38fd1498Szrj virtual unsigned int execute (function *);
3339*38fd1498Szrj
3340*38fd1498Szrj }; // class pass_tm_edges
3341*38fd1498Szrj
3342*38fd1498Szrj unsigned int
execute(function * fun)3343*38fd1498Szrj pass_tm_edges::execute (function *fun)
3344*38fd1498Szrj {
3345*38fd1498Szrj vec<tm_region *> bb_regions
3346*38fd1498Szrj = get_bb_regions_instrumented (/*traverse_clones=*/false,
3347*38fd1498Szrj /*include_uninstrumented_p=*/true);
3348*38fd1498Szrj struct tm_region *r;
3349*38fd1498Szrj unsigned i;
3350*38fd1498Szrj
3351*38fd1498Szrj FOR_EACH_VEC_ELT (bb_regions, i, r)
3352*38fd1498Szrj if (r != NULL)
3353*38fd1498Szrj expand_block_edges (r, BASIC_BLOCK_FOR_FN (fun, i));
3354*38fd1498Szrj
3355*38fd1498Szrj bb_regions.release ();
3356*38fd1498Szrj
3357*38fd1498Szrj /* We've got to release the dominance info now, to indicate that it
3358*38fd1498Szrj must be rebuilt completely. Otherwise we'll crash trying to update
3359*38fd1498Szrj the SSA web in the TODO section following this pass. */
3360*38fd1498Szrj free_dominance_info (CDI_DOMINATORS);
3361*38fd1498Szrj /* We'ge also wrecked loops badly with inserting of abnormal edges. */
3362*38fd1498Szrj loops_state_set (LOOPS_NEED_FIXUP);
3363*38fd1498Szrj bitmap_obstack_release (&tm_obstack);
3364*38fd1498Szrj all_tm_regions = NULL;
3365*38fd1498Szrj
3366*38fd1498Szrj return 0;
3367*38fd1498Szrj }
3368*38fd1498Szrj
3369*38fd1498Szrj } // anon namespace
3370*38fd1498Szrj
3371*38fd1498Szrj gimple_opt_pass *
make_pass_tm_edges(gcc::context * ctxt)3372*38fd1498Szrj make_pass_tm_edges (gcc::context *ctxt)
3373*38fd1498Szrj {
3374*38fd1498Szrj return new pass_tm_edges (ctxt);
3375*38fd1498Szrj }
3376*38fd1498Szrj
3377*38fd1498Szrj /* Helper function for expand_regions. Expand REGION and recurse to
3378*38fd1498Szrj the inner region. Call CALLBACK on each region. CALLBACK returns
3379*38fd1498Szrj NULL to continue the traversal, otherwise a non-null value which
3380*38fd1498Szrj this function will return as well. TRAVERSE_CLONES is true if we
3381*38fd1498Szrj should traverse transactional clones. */
3382*38fd1498Szrj
3383*38fd1498Szrj static void *
expand_regions_1(struct tm_region * region,void * (* callback)(struct tm_region *,void *),void * data,bool traverse_clones)3384*38fd1498Szrj expand_regions_1 (struct tm_region *region,
3385*38fd1498Szrj void *(*callback)(struct tm_region *, void *),
3386*38fd1498Szrj void *data,
3387*38fd1498Szrj bool traverse_clones)
3388*38fd1498Szrj {
3389*38fd1498Szrj void *retval = NULL;
3390*38fd1498Szrj if (region->exit_blocks
3391*38fd1498Szrj || (traverse_clones && decl_is_tm_clone (current_function_decl)))
3392*38fd1498Szrj {
3393*38fd1498Szrj retval = callback (region, data);
3394*38fd1498Szrj if (retval)
3395*38fd1498Szrj return retval;
3396*38fd1498Szrj }
3397*38fd1498Szrj if (region->inner)
3398*38fd1498Szrj {
3399*38fd1498Szrj retval = expand_regions (region->inner, callback, data, traverse_clones);
3400*38fd1498Szrj if (retval)
3401*38fd1498Szrj return retval;
3402*38fd1498Szrj }
3403*38fd1498Szrj return retval;
3404*38fd1498Szrj }
3405*38fd1498Szrj
3406*38fd1498Szrj /* Traverse the regions enclosed and including REGION. Execute
3407*38fd1498Szrj CALLBACK for each region, passing DATA. CALLBACK returns NULL to
3408*38fd1498Szrj continue the traversal, otherwise a non-null value which this
3409*38fd1498Szrj function will return as well. TRAVERSE_CLONES is true if we should
3410*38fd1498Szrj traverse transactional clones. */
3411*38fd1498Szrj
3412*38fd1498Szrj static void *
expand_regions(struct tm_region * region,void * (* callback)(struct tm_region *,void *),void * data,bool traverse_clones)3413*38fd1498Szrj expand_regions (struct tm_region *region,
3414*38fd1498Szrj void *(*callback)(struct tm_region *, void *),
3415*38fd1498Szrj void *data,
3416*38fd1498Szrj bool traverse_clones)
3417*38fd1498Szrj {
3418*38fd1498Szrj void *retval = NULL;
3419*38fd1498Szrj while (region)
3420*38fd1498Szrj {
3421*38fd1498Szrj retval = expand_regions_1 (region, callback, data, traverse_clones);
3422*38fd1498Szrj if (retval)
3423*38fd1498Szrj return retval;
3424*38fd1498Szrj region = region->next;
3425*38fd1498Szrj }
3426*38fd1498Szrj return retval;
3427*38fd1498Szrj }
3428*38fd1498Szrj
3429*38fd1498Szrj
3430*38fd1498Szrj /* A unique TM memory operation. */
3431*38fd1498Szrj struct tm_memop
3432*38fd1498Szrj {
3433*38fd1498Szrj /* Unique ID that all memory operations to the same location have. */
3434*38fd1498Szrj unsigned int value_id;
3435*38fd1498Szrj /* Address of load/store. */
3436*38fd1498Szrj tree addr;
3437*38fd1498Szrj };
3438*38fd1498Szrj
3439*38fd1498Szrj /* TM memory operation hashtable helpers. */
3440*38fd1498Szrj
3441*38fd1498Szrj struct tm_memop_hasher : free_ptr_hash <tm_memop>
3442*38fd1498Szrj {
3443*38fd1498Szrj static inline hashval_t hash (const tm_memop *);
3444*38fd1498Szrj static inline bool equal (const tm_memop *, const tm_memop *);
3445*38fd1498Szrj };
3446*38fd1498Szrj
3447*38fd1498Szrj /* Htab support. Return a hash value for a `tm_memop'. */
3448*38fd1498Szrj inline hashval_t
hash(const tm_memop * mem)3449*38fd1498Szrj tm_memop_hasher::hash (const tm_memop *mem)
3450*38fd1498Szrj {
3451*38fd1498Szrj tree addr = mem->addr;
3452*38fd1498Szrj /* We drill down to the SSA_NAME/DECL for the hash, but equality is
3453*38fd1498Szrj actually done with operand_equal_p (see tm_memop_eq). */
3454*38fd1498Szrj if (TREE_CODE (addr) == ADDR_EXPR)
3455*38fd1498Szrj addr = TREE_OPERAND (addr, 0);
3456*38fd1498Szrj return iterative_hash_expr (addr, 0);
3457*38fd1498Szrj }
3458*38fd1498Szrj
3459*38fd1498Szrj /* Htab support. Return true if two tm_memop's are the same. */
3460*38fd1498Szrj inline bool
equal(const tm_memop * mem1,const tm_memop * mem2)3461*38fd1498Szrj tm_memop_hasher::equal (const tm_memop *mem1, const tm_memop *mem2)
3462*38fd1498Szrj {
3463*38fd1498Szrj return operand_equal_p (mem1->addr, mem2->addr, 0);
3464*38fd1498Szrj }
3465*38fd1498Szrj
3466*38fd1498Szrj /* Sets for solving data flow equations in the memory optimization pass. */
3467*38fd1498Szrj struct tm_memopt_bitmaps
3468*38fd1498Szrj {
3469*38fd1498Szrj /* Stores available to this BB upon entry. Basically, stores that
3470*38fd1498Szrj dominate this BB. */
3471*38fd1498Szrj bitmap store_avail_in;
3472*38fd1498Szrj /* Stores available at the end of this BB. */
3473*38fd1498Szrj bitmap store_avail_out;
3474*38fd1498Szrj bitmap store_antic_in;
3475*38fd1498Szrj bitmap store_antic_out;
3476*38fd1498Szrj /* Reads available to this BB upon entry. Basically, reads that
3477*38fd1498Szrj dominate this BB. */
3478*38fd1498Szrj bitmap read_avail_in;
3479*38fd1498Szrj /* Reads available at the end of this BB. */
3480*38fd1498Szrj bitmap read_avail_out;
3481*38fd1498Szrj /* Reads performed in this BB. */
3482*38fd1498Szrj bitmap read_local;
3483*38fd1498Szrj /* Writes performed in this BB. */
3484*38fd1498Szrj bitmap store_local;
3485*38fd1498Szrj
3486*38fd1498Szrj /* Temporary storage for pass. */
3487*38fd1498Szrj /* Is the current BB in the worklist? */
3488*38fd1498Szrj bool avail_in_worklist_p;
3489*38fd1498Szrj /* Have we visited this BB? */
3490*38fd1498Szrj bool visited_p;
3491*38fd1498Szrj };
3492*38fd1498Szrj
3493*38fd1498Szrj static bitmap_obstack tm_memopt_obstack;
3494*38fd1498Szrj
3495*38fd1498Szrj /* Unique counter for TM loads and stores. Loads and stores of the
3496*38fd1498Szrj same address get the same ID. */
3497*38fd1498Szrj static unsigned int tm_memopt_value_id;
3498*38fd1498Szrj static hash_table<tm_memop_hasher> *tm_memopt_value_numbers;
3499*38fd1498Szrj
3500*38fd1498Szrj #define STORE_AVAIL_IN(BB) \
3501*38fd1498Szrj ((struct tm_memopt_bitmaps *) ((BB)->aux))->store_avail_in
3502*38fd1498Szrj #define STORE_AVAIL_OUT(BB) \
3503*38fd1498Szrj ((struct tm_memopt_bitmaps *) ((BB)->aux))->store_avail_out
3504*38fd1498Szrj #define STORE_ANTIC_IN(BB) \
3505*38fd1498Szrj ((struct tm_memopt_bitmaps *) ((BB)->aux))->store_antic_in
3506*38fd1498Szrj #define STORE_ANTIC_OUT(BB) \
3507*38fd1498Szrj ((struct tm_memopt_bitmaps *) ((BB)->aux))->store_antic_out
3508*38fd1498Szrj #define READ_AVAIL_IN(BB) \
3509*38fd1498Szrj ((struct tm_memopt_bitmaps *) ((BB)->aux))->read_avail_in
3510*38fd1498Szrj #define READ_AVAIL_OUT(BB) \
3511*38fd1498Szrj ((struct tm_memopt_bitmaps *) ((BB)->aux))->read_avail_out
3512*38fd1498Szrj #define READ_LOCAL(BB) \
3513*38fd1498Szrj ((struct tm_memopt_bitmaps *) ((BB)->aux))->read_local
3514*38fd1498Szrj #define STORE_LOCAL(BB) \
3515*38fd1498Szrj ((struct tm_memopt_bitmaps *) ((BB)->aux))->store_local
3516*38fd1498Szrj #define AVAIL_IN_WORKLIST_P(BB) \
3517*38fd1498Szrj ((struct tm_memopt_bitmaps *) ((BB)->aux))->avail_in_worklist_p
3518*38fd1498Szrj #define BB_VISITED_P(BB) \
3519*38fd1498Szrj ((struct tm_memopt_bitmaps *) ((BB)->aux))->visited_p
3520*38fd1498Szrj
3521*38fd1498Szrj /* Given a TM load/store in STMT, return the value number for the address
3522*38fd1498Szrj it accesses. */
3523*38fd1498Szrj
3524*38fd1498Szrj static unsigned int
tm_memopt_value_number(gimple * stmt,enum insert_option op)3525*38fd1498Szrj tm_memopt_value_number (gimple *stmt, enum insert_option op)
3526*38fd1498Szrj {
3527*38fd1498Szrj struct tm_memop tmpmem, *mem;
3528*38fd1498Szrj tm_memop **slot;
3529*38fd1498Szrj
3530*38fd1498Szrj gcc_assert (is_tm_load (stmt) || is_tm_store (stmt));
3531*38fd1498Szrj tmpmem.addr = gimple_call_arg (stmt, 0);
3532*38fd1498Szrj slot = tm_memopt_value_numbers->find_slot (&tmpmem, op);
3533*38fd1498Szrj if (*slot)
3534*38fd1498Szrj mem = *slot;
3535*38fd1498Szrj else if (op == INSERT)
3536*38fd1498Szrj {
3537*38fd1498Szrj mem = XNEW (struct tm_memop);
3538*38fd1498Szrj *slot = mem;
3539*38fd1498Szrj mem->value_id = tm_memopt_value_id++;
3540*38fd1498Szrj mem->addr = tmpmem.addr;
3541*38fd1498Szrj }
3542*38fd1498Szrj else
3543*38fd1498Szrj gcc_unreachable ();
3544*38fd1498Szrj return mem->value_id;
3545*38fd1498Szrj }
3546*38fd1498Szrj
3547*38fd1498Szrj /* Accumulate TM memory operations in BB into STORE_LOCAL and READ_LOCAL. */
3548*38fd1498Szrj
3549*38fd1498Szrj static void
tm_memopt_accumulate_memops(basic_block bb)3550*38fd1498Szrj tm_memopt_accumulate_memops (basic_block bb)
3551*38fd1498Szrj {
3552*38fd1498Szrj gimple_stmt_iterator gsi;
3553*38fd1498Szrj
3554*38fd1498Szrj for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
3555*38fd1498Szrj {
3556*38fd1498Szrj gimple *stmt = gsi_stmt (gsi);
3557*38fd1498Szrj bitmap bits;
3558*38fd1498Szrj unsigned int loc;
3559*38fd1498Szrj
3560*38fd1498Szrj if (is_tm_store (stmt))
3561*38fd1498Szrj bits = STORE_LOCAL (bb);
3562*38fd1498Szrj else if (is_tm_load (stmt))
3563*38fd1498Szrj bits = READ_LOCAL (bb);
3564*38fd1498Szrj else
3565*38fd1498Szrj continue;
3566*38fd1498Szrj
3567*38fd1498Szrj loc = tm_memopt_value_number (stmt, INSERT);
3568*38fd1498Szrj bitmap_set_bit (bits, loc);
3569*38fd1498Szrj if (dump_file)
3570*38fd1498Szrj {
3571*38fd1498Szrj fprintf (dump_file, "TM memopt (%s): value num=%d, BB=%d, addr=",
3572*38fd1498Szrj is_tm_load (stmt) ? "LOAD" : "STORE", loc,
3573*38fd1498Szrj gimple_bb (stmt)->index);
3574*38fd1498Szrj print_generic_expr (dump_file, gimple_call_arg (stmt, 0));
3575*38fd1498Szrj fprintf (dump_file, "\n");
3576*38fd1498Szrj }
3577*38fd1498Szrj }
3578*38fd1498Szrj }
3579*38fd1498Szrj
3580*38fd1498Szrj /* Prettily dump one of the memopt sets. BITS is the bitmap to dump. */
3581*38fd1498Szrj
3582*38fd1498Szrj static void
dump_tm_memopt_set(const char * set_name,bitmap bits)3583*38fd1498Szrj dump_tm_memopt_set (const char *set_name, bitmap bits)
3584*38fd1498Szrj {
3585*38fd1498Szrj unsigned i;
3586*38fd1498Szrj bitmap_iterator bi;
3587*38fd1498Szrj const char *comma = "";
3588*38fd1498Szrj
3589*38fd1498Szrj fprintf (dump_file, "TM memopt: %s: [", set_name);
3590*38fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (bits, 0, i, bi)
3591*38fd1498Szrj {
3592*38fd1498Szrj hash_table<tm_memop_hasher>::iterator hi;
3593*38fd1498Szrj struct tm_memop *mem = NULL;
3594*38fd1498Szrj
3595*38fd1498Szrj /* Yeah, yeah, yeah. Whatever. This is just for debugging. */
3596*38fd1498Szrj FOR_EACH_HASH_TABLE_ELEMENT (*tm_memopt_value_numbers, mem, tm_memop_t, hi)
3597*38fd1498Szrj if (mem->value_id == i)
3598*38fd1498Szrj break;
3599*38fd1498Szrj gcc_assert (mem->value_id == i);
3600*38fd1498Szrj fprintf (dump_file, "%s", comma);
3601*38fd1498Szrj comma = ", ";
3602*38fd1498Szrj print_generic_expr (dump_file, mem->addr);
3603*38fd1498Szrj }
3604*38fd1498Szrj fprintf (dump_file, "]\n");
3605*38fd1498Szrj }
3606*38fd1498Szrj
3607*38fd1498Szrj /* Prettily dump all of the memopt sets in BLOCKS. */
3608*38fd1498Szrj
3609*38fd1498Szrj static void
dump_tm_memopt_sets(vec<basic_block> blocks)3610*38fd1498Szrj dump_tm_memopt_sets (vec<basic_block> blocks)
3611*38fd1498Szrj {
3612*38fd1498Szrj size_t i;
3613*38fd1498Szrj basic_block bb;
3614*38fd1498Szrj
3615*38fd1498Szrj for (i = 0; blocks.iterate (i, &bb); ++i)
3616*38fd1498Szrj {
3617*38fd1498Szrj fprintf (dump_file, "------------BB %d---------\n", bb->index);
3618*38fd1498Szrj dump_tm_memopt_set ("STORE_LOCAL", STORE_LOCAL (bb));
3619*38fd1498Szrj dump_tm_memopt_set ("READ_LOCAL", READ_LOCAL (bb));
3620*38fd1498Szrj dump_tm_memopt_set ("STORE_AVAIL_IN", STORE_AVAIL_IN (bb));
3621*38fd1498Szrj dump_tm_memopt_set ("STORE_AVAIL_OUT", STORE_AVAIL_OUT (bb));
3622*38fd1498Szrj dump_tm_memopt_set ("READ_AVAIL_IN", READ_AVAIL_IN (bb));
3623*38fd1498Szrj dump_tm_memopt_set ("READ_AVAIL_OUT", READ_AVAIL_OUT (bb));
3624*38fd1498Szrj }
3625*38fd1498Szrj }
3626*38fd1498Szrj
3627*38fd1498Szrj /* Compute {STORE,READ}_AVAIL_IN for the basic block BB. */
3628*38fd1498Szrj
3629*38fd1498Szrj static void
tm_memopt_compute_avin(basic_block bb)3630*38fd1498Szrj tm_memopt_compute_avin (basic_block bb)
3631*38fd1498Szrj {
3632*38fd1498Szrj edge e;
3633*38fd1498Szrj unsigned ix;
3634*38fd1498Szrj
3635*38fd1498Szrj /* Seed with the AVOUT of any predecessor. */
3636*38fd1498Szrj for (ix = 0; ix < EDGE_COUNT (bb->preds); ix++)
3637*38fd1498Szrj {
3638*38fd1498Szrj e = EDGE_PRED (bb, ix);
3639*38fd1498Szrj /* Make sure we have already visited this BB, and is thus
3640*38fd1498Szrj initialized.
3641*38fd1498Szrj
3642*38fd1498Szrj If e->src->aux is NULL, this predecessor is actually on an
3643*38fd1498Szrj enclosing transaction. We only care about the current
3644*38fd1498Szrj transaction, so ignore it. */
3645*38fd1498Szrj if (e->src->aux && BB_VISITED_P (e->src))
3646*38fd1498Szrj {
3647*38fd1498Szrj bitmap_copy (STORE_AVAIL_IN (bb), STORE_AVAIL_OUT (e->src));
3648*38fd1498Szrj bitmap_copy (READ_AVAIL_IN (bb), READ_AVAIL_OUT (e->src));
3649*38fd1498Szrj break;
3650*38fd1498Szrj }
3651*38fd1498Szrj }
3652*38fd1498Szrj
3653*38fd1498Szrj for (; ix < EDGE_COUNT (bb->preds); ix++)
3654*38fd1498Szrj {
3655*38fd1498Szrj e = EDGE_PRED (bb, ix);
3656*38fd1498Szrj if (e->src->aux && BB_VISITED_P (e->src))
3657*38fd1498Szrj {
3658*38fd1498Szrj bitmap_and_into (STORE_AVAIL_IN (bb), STORE_AVAIL_OUT (e->src));
3659*38fd1498Szrj bitmap_and_into (READ_AVAIL_IN (bb), READ_AVAIL_OUT (e->src));
3660*38fd1498Szrj }
3661*38fd1498Szrj }
3662*38fd1498Szrj
3663*38fd1498Szrj BB_VISITED_P (bb) = true;
3664*38fd1498Szrj }
3665*38fd1498Szrj
3666*38fd1498Szrj /* Compute the STORE_ANTIC_IN for the basic block BB. */
3667*38fd1498Szrj
3668*38fd1498Szrj static void
tm_memopt_compute_antin(basic_block bb)3669*38fd1498Szrj tm_memopt_compute_antin (basic_block bb)
3670*38fd1498Szrj {
3671*38fd1498Szrj edge e;
3672*38fd1498Szrj unsigned ix;
3673*38fd1498Szrj
3674*38fd1498Szrj /* Seed with the ANTIC_OUT of any successor. */
3675*38fd1498Szrj for (ix = 0; ix < EDGE_COUNT (bb->succs); ix++)
3676*38fd1498Szrj {
3677*38fd1498Szrj e = EDGE_SUCC (bb, ix);
3678*38fd1498Szrj /* Make sure we have already visited this BB, and is thus
3679*38fd1498Szrj initialized. */
3680*38fd1498Szrj if (BB_VISITED_P (e->dest))
3681*38fd1498Szrj {
3682*38fd1498Szrj bitmap_copy (STORE_ANTIC_IN (bb), STORE_ANTIC_OUT (e->dest));
3683*38fd1498Szrj break;
3684*38fd1498Szrj }
3685*38fd1498Szrj }
3686*38fd1498Szrj
3687*38fd1498Szrj for (; ix < EDGE_COUNT (bb->succs); ix++)
3688*38fd1498Szrj {
3689*38fd1498Szrj e = EDGE_SUCC (bb, ix);
3690*38fd1498Szrj if (BB_VISITED_P (e->dest))
3691*38fd1498Szrj bitmap_and_into (STORE_ANTIC_IN (bb), STORE_ANTIC_OUT (e->dest));
3692*38fd1498Szrj }
3693*38fd1498Szrj
3694*38fd1498Szrj BB_VISITED_P (bb) = true;
3695*38fd1498Szrj }
3696*38fd1498Szrj
3697*38fd1498Szrj /* Compute the AVAIL sets for every basic block in BLOCKS.
3698*38fd1498Szrj
3699*38fd1498Szrj We compute {STORE,READ}_AVAIL_{OUT,IN} as follows:
3700*38fd1498Szrj
3701*38fd1498Szrj AVAIL_OUT[bb] = union (AVAIL_IN[bb], LOCAL[bb])
3702*38fd1498Szrj AVAIL_IN[bb] = intersect (AVAIL_OUT[predecessors])
3703*38fd1498Szrj
3704*38fd1498Szrj This is basically what we do in lcm's compute_available(), but here
3705*38fd1498Szrj we calculate two sets of sets (one for STOREs and one for READs),
3706*38fd1498Szrj and we work on a region instead of the entire CFG.
3707*38fd1498Szrj
3708*38fd1498Szrj REGION is the TM region.
3709*38fd1498Szrj BLOCKS are the basic blocks in the region. */
3710*38fd1498Szrj
3711*38fd1498Szrj static void
tm_memopt_compute_available(struct tm_region * region,vec<basic_block> blocks)3712*38fd1498Szrj tm_memopt_compute_available (struct tm_region *region,
3713*38fd1498Szrj vec<basic_block> blocks)
3714*38fd1498Szrj {
3715*38fd1498Szrj edge e;
3716*38fd1498Szrj basic_block *worklist, *qin, *qout, *qend, bb;
3717*38fd1498Szrj unsigned int qlen, i;
3718*38fd1498Szrj edge_iterator ei;
3719*38fd1498Szrj bool changed;
3720*38fd1498Szrj
3721*38fd1498Szrj /* Allocate a worklist array/queue. Entries are only added to the
3722*38fd1498Szrj list if they were not already on the list. So the size is
3723*38fd1498Szrj bounded by the number of basic blocks in the region. */
3724*38fd1498Szrj qlen = blocks.length () - 1;
3725*38fd1498Szrj qin = qout = worklist =
3726*38fd1498Szrj XNEWVEC (basic_block, qlen);
3727*38fd1498Szrj
3728*38fd1498Szrj /* Put every block in the region on the worklist. */
3729*38fd1498Szrj for (i = 0; blocks.iterate (i, &bb); ++i)
3730*38fd1498Szrj {
3731*38fd1498Szrj /* Seed AVAIL_OUT with the LOCAL set. */
3732*38fd1498Szrj bitmap_ior_into (STORE_AVAIL_OUT (bb), STORE_LOCAL (bb));
3733*38fd1498Szrj bitmap_ior_into (READ_AVAIL_OUT (bb), READ_LOCAL (bb));
3734*38fd1498Szrj
3735*38fd1498Szrj AVAIL_IN_WORKLIST_P (bb) = true;
3736*38fd1498Szrj /* No need to insert the entry block, since it has an AVIN of
3737*38fd1498Szrj null, and an AVOUT that has already been seeded in. */
3738*38fd1498Szrj if (bb != region->entry_block)
3739*38fd1498Szrj *qin++ = bb;
3740*38fd1498Szrj }
3741*38fd1498Szrj
3742*38fd1498Szrj /* The entry block has been initialized with the local sets. */
3743*38fd1498Szrj BB_VISITED_P (region->entry_block) = true;
3744*38fd1498Szrj
3745*38fd1498Szrj qin = worklist;
3746*38fd1498Szrj qend = &worklist[qlen];
3747*38fd1498Szrj
3748*38fd1498Szrj /* Iterate until the worklist is empty. */
3749*38fd1498Szrj while (qlen)
3750*38fd1498Szrj {
3751*38fd1498Szrj /* Take the first entry off the worklist. */
3752*38fd1498Szrj bb = *qout++;
3753*38fd1498Szrj qlen--;
3754*38fd1498Szrj
3755*38fd1498Szrj if (qout >= qend)
3756*38fd1498Szrj qout = worklist;
3757*38fd1498Szrj
3758*38fd1498Szrj /* This block can be added to the worklist again if necessary. */
3759*38fd1498Szrj AVAIL_IN_WORKLIST_P (bb) = false;
3760*38fd1498Szrj tm_memopt_compute_avin (bb);
3761*38fd1498Szrj
3762*38fd1498Szrj /* Note: We do not add the LOCAL sets here because we already
3763*38fd1498Szrj seeded the AVAIL_OUT sets with them. */
3764*38fd1498Szrj changed = bitmap_ior_into (STORE_AVAIL_OUT (bb), STORE_AVAIL_IN (bb));
3765*38fd1498Szrj changed |= bitmap_ior_into (READ_AVAIL_OUT (bb), READ_AVAIL_IN (bb));
3766*38fd1498Szrj if (changed
3767*38fd1498Szrj && (region->exit_blocks == NULL
3768*38fd1498Szrj || !bitmap_bit_p (region->exit_blocks, bb->index)))
3769*38fd1498Szrj /* If the out state of this block changed, then we need to add
3770*38fd1498Szrj its successors to the worklist if they are not already in. */
3771*38fd1498Szrj FOR_EACH_EDGE (e, ei, bb->succs)
3772*38fd1498Szrj if (!AVAIL_IN_WORKLIST_P (e->dest)
3773*38fd1498Szrj && e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun))
3774*38fd1498Szrj {
3775*38fd1498Szrj *qin++ = e->dest;
3776*38fd1498Szrj AVAIL_IN_WORKLIST_P (e->dest) = true;
3777*38fd1498Szrj qlen++;
3778*38fd1498Szrj
3779*38fd1498Szrj if (qin >= qend)
3780*38fd1498Szrj qin = worklist;
3781*38fd1498Szrj }
3782*38fd1498Szrj }
3783*38fd1498Szrj
3784*38fd1498Szrj free (worklist);
3785*38fd1498Szrj
3786*38fd1498Szrj if (dump_file)
3787*38fd1498Szrj dump_tm_memopt_sets (blocks);
3788*38fd1498Szrj }
3789*38fd1498Szrj
3790*38fd1498Szrj /* Compute ANTIC sets for every basic block in BLOCKS.
3791*38fd1498Szrj
3792*38fd1498Szrj We compute STORE_ANTIC_OUT as follows:
3793*38fd1498Szrj
3794*38fd1498Szrj STORE_ANTIC_OUT[bb] = union(STORE_ANTIC_IN[bb], STORE_LOCAL[bb])
3795*38fd1498Szrj STORE_ANTIC_IN[bb] = intersect(STORE_ANTIC_OUT[successors])
3796*38fd1498Szrj
3797*38fd1498Szrj REGION is the TM region.
3798*38fd1498Szrj BLOCKS are the basic blocks in the region. */
3799*38fd1498Szrj
3800*38fd1498Szrj static void
tm_memopt_compute_antic(struct tm_region * region,vec<basic_block> blocks)3801*38fd1498Szrj tm_memopt_compute_antic (struct tm_region *region,
3802*38fd1498Szrj vec<basic_block> blocks)
3803*38fd1498Szrj {
3804*38fd1498Szrj edge e;
3805*38fd1498Szrj basic_block *worklist, *qin, *qout, *qend, bb;
3806*38fd1498Szrj unsigned int qlen;
3807*38fd1498Szrj int i;
3808*38fd1498Szrj edge_iterator ei;
3809*38fd1498Szrj
3810*38fd1498Szrj /* Allocate a worklist array/queue. Entries are only added to the
3811*38fd1498Szrj list if they were not already on the list. So the size is
3812*38fd1498Szrj bounded by the number of basic blocks in the region. */
3813*38fd1498Szrj qin = qout = worklist = XNEWVEC (basic_block, blocks.length ());
3814*38fd1498Szrj
3815*38fd1498Szrj for (qlen = 0, i = blocks.length () - 1; i >= 0; --i)
3816*38fd1498Szrj {
3817*38fd1498Szrj bb = blocks[i];
3818*38fd1498Szrj
3819*38fd1498Szrj /* Seed ANTIC_OUT with the LOCAL set. */
3820*38fd1498Szrj bitmap_ior_into (STORE_ANTIC_OUT (bb), STORE_LOCAL (bb));
3821*38fd1498Szrj
3822*38fd1498Szrj /* Put every block in the region on the worklist. */
3823*38fd1498Szrj AVAIL_IN_WORKLIST_P (bb) = true;
3824*38fd1498Szrj /* No need to insert exit blocks, since their ANTIC_IN is NULL,
3825*38fd1498Szrj and their ANTIC_OUT has already been seeded in. */
3826*38fd1498Szrj if (region->exit_blocks
3827*38fd1498Szrj && !bitmap_bit_p (region->exit_blocks, bb->index))
3828*38fd1498Szrj {
3829*38fd1498Szrj qlen++;
3830*38fd1498Szrj *qin++ = bb;
3831*38fd1498Szrj }
3832*38fd1498Szrj }
3833*38fd1498Szrj
3834*38fd1498Szrj /* The exit blocks have been initialized with the local sets. */
3835*38fd1498Szrj if (region->exit_blocks)
3836*38fd1498Szrj {
3837*38fd1498Szrj unsigned int i;
3838*38fd1498Szrj bitmap_iterator bi;
3839*38fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (region->exit_blocks, 0, i, bi)
3840*38fd1498Szrj BB_VISITED_P (BASIC_BLOCK_FOR_FN (cfun, i)) = true;
3841*38fd1498Szrj }
3842*38fd1498Szrj
3843*38fd1498Szrj qin = worklist;
3844*38fd1498Szrj qend = &worklist[qlen];
3845*38fd1498Szrj
3846*38fd1498Szrj /* Iterate until the worklist is empty. */
3847*38fd1498Szrj while (qlen)
3848*38fd1498Szrj {
3849*38fd1498Szrj /* Take the first entry off the worklist. */
3850*38fd1498Szrj bb = *qout++;
3851*38fd1498Szrj qlen--;
3852*38fd1498Szrj
3853*38fd1498Szrj if (qout >= qend)
3854*38fd1498Szrj qout = worklist;
3855*38fd1498Szrj
3856*38fd1498Szrj /* This block can be added to the worklist again if necessary. */
3857*38fd1498Szrj AVAIL_IN_WORKLIST_P (bb) = false;
3858*38fd1498Szrj tm_memopt_compute_antin (bb);
3859*38fd1498Szrj
3860*38fd1498Szrj /* Note: We do not add the LOCAL sets here because we already
3861*38fd1498Szrj seeded the ANTIC_OUT sets with them. */
3862*38fd1498Szrj if (bitmap_ior_into (STORE_ANTIC_OUT (bb), STORE_ANTIC_IN (bb))
3863*38fd1498Szrj && bb != region->entry_block)
3864*38fd1498Szrj /* If the out state of this block changed, then we need to add
3865*38fd1498Szrj its predecessors to the worklist if they are not already in. */
3866*38fd1498Szrj FOR_EACH_EDGE (e, ei, bb->preds)
3867*38fd1498Szrj if (!AVAIL_IN_WORKLIST_P (e->src))
3868*38fd1498Szrj {
3869*38fd1498Szrj *qin++ = e->src;
3870*38fd1498Szrj AVAIL_IN_WORKLIST_P (e->src) = true;
3871*38fd1498Szrj qlen++;
3872*38fd1498Szrj
3873*38fd1498Szrj if (qin >= qend)
3874*38fd1498Szrj qin = worklist;
3875*38fd1498Szrj }
3876*38fd1498Szrj }
3877*38fd1498Szrj
3878*38fd1498Szrj free (worklist);
3879*38fd1498Szrj
3880*38fd1498Szrj if (dump_file)
3881*38fd1498Szrj dump_tm_memopt_sets (blocks);
3882*38fd1498Szrj }
3883*38fd1498Szrj
3884*38fd1498Szrj /* Offsets of load variants from TM_LOAD. For example,
3885*38fd1498Szrj BUILT_IN_TM_LOAD_RAR* is an offset of 1 from BUILT_IN_TM_LOAD*.
3886*38fd1498Szrj See gtm-builtins.def. */
3887*38fd1498Szrj #define TRANSFORM_RAR 1
3888*38fd1498Szrj #define TRANSFORM_RAW 2
3889*38fd1498Szrj #define TRANSFORM_RFW 3
3890*38fd1498Szrj /* Offsets of store variants from TM_STORE. */
3891*38fd1498Szrj #define TRANSFORM_WAR 1
3892*38fd1498Szrj #define TRANSFORM_WAW 2
3893*38fd1498Szrj
3894*38fd1498Szrj /* Inform about a load/store optimization. */
3895*38fd1498Szrj
3896*38fd1498Szrj static void
dump_tm_memopt_transform(gimple * stmt)3897*38fd1498Szrj dump_tm_memopt_transform (gimple *stmt)
3898*38fd1498Szrj {
3899*38fd1498Szrj if (dump_file)
3900*38fd1498Szrj {
3901*38fd1498Szrj fprintf (dump_file, "TM memopt: transforming: ");
3902*38fd1498Szrj print_gimple_stmt (dump_file, stmt, 0);
3903*38fd1498Szrj fprintf (dump_file, "\n");
3904*38fd1498Szrj }
3905*38fd1498Szrj }
3906*38fd1498Szrj
3907*38fd1498Szrj /* Perform a read/write optimization. Replaces the TM builtin in STMT
3908*38fd1498Szrj by a builtin that is OFFSET entries down in the builtins table in
3909*38fd1498Szrj gtm-builtins.def. */
3910*38fd1498Szrj
3911*38fd1498Szrj static void
tm_memopt_transform_stmt(unsigned int offset,gcall * stmt,gimple_stmt_iterator * gsi)3912*38fd1498Szrj tm_memopt_transform_stmt (unsigned int offset,
3913*38fd1498Szrj gcall *stmt,
3914*38fd1498Szrj gimple_stmt_iterator *gsi)
3915*38fd1498Szrj {
3916*38fd1498Szrj tree fn = gimple_call_fn (stmt);
3917*38fd1498Szrj gcc_assert (TREE_CODE (fn) == ADDR_EXPR);
3918*38fd1498Szrj TREE_OPERAND (fn, 0)
3919*38fd1498Szrj = builtin_decl_explicit ((enum built_in_function)
3920*38fd1498Szrj (DECL_FUNCTION_CODE (TREE_OPERAND (fn, 0))
3921*38fd1498Szrj + offset));
3922*38fd1498Szrj gimple_call_set_fn (stmt, fn);
3923*38fd1498Szrj gsi_replace (gsi, stmt, true);
3924*38fd1498Szrj dump_tm_memopt_transform (stmt);
3925*38fd1498Szrj }
3926*38fd1498Szrj
3927*38fd1498Szrj /* Perform the actual TM memory optimization transformations in the
3928*38fd1498Szrj basic blocks in BLOCKS. */
3929*38fd1498Szrj
3930*38fd1498Szrj static void
tm_memopt_transform_blocks(vec<basic_block> blocks)3931*38fd1498Szrj tm_memopt_transform_blocks (vec<basic_block> blocks)
3932*38fd1498Szrj {
3933*38fd1498Szrj size_t i;
3934*38fd1498Szrj basic_block bb;
3935*38fd1498Szrj gimple_stmt_iterator gsi;
3936*38fd1498Szrj
3937*38fd1498Szrj for (i = 0; blocks.iterate (i, &bb); ++i)
3938*38fd1498Szrj {
3939*38fd1498Szrj for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
3940*38fd1498Szrj {
3941*38fd1498Szrj gimple *stmt = gsi_stmt (gsi);
3942*38fd1498Szrj bitmap read_avail = READ_AVAIL_IN (bb);
3943*38fd1498Szrj bitmap store_avail = STORE_AVAIL_IN (bb);
3944*38fd1498Szrj bitmap store_antic = STORE_ANTIC_OUT (bb);
3945*38fd1498Szrj unsigned int loc;
3946*38fd1498Szrj
3947*38fd1498Szrj if (is_tm_simple_load (stmt))
3948*38fd1498Szrj {
3949*38fd1498Szrj gcall *call_stmt = as_a <gcall *> (stmt);
3950*38fd1498Szrj loc = tm_memopt_value_number (stmt, NO_INSERT);
3951*38fd1498Szrj if (store_avail && bitmap_bit_p (store_avail, loc))
3952*38fd1498Szrj tm_memopt_transform_stmt (TRANSFORM_RAW, call_stmt, &gsi);
3953*38fd1498Szrj else if (store_antic && bitmap_bit_p (store_antic, loc))
3954*38fd1498Szrj {
3955*38fd1498Szrj tm_memopt_transform_stmt (TRANSFORM_RFW, call_stmt, &gsi);
3956*38fd1498Szrj bitmap_set_bit (store_avail, loc);
3957*38fd1498Szrj }
3958*38fd1498Szrj else if (read_avail && bitmap_bit_p (read_avail, loc))
3959*38fd1498Szrj tm_memopt_transform_stmt (TRANSFORM_RAR, call_stmt, &gsi);
3960*38fd1498Szrj else
3961*38fd1498Szrj bitmap_set_bit (read_avail, loc);
3962*38fd1498Szrj }
3963*38fd1498Szrj else if (is_tm_simple_store (stmt))
3964*38fd1498Szrj {
3965*38fd1498Szrj gcall *call_stmt = as_a <gcall *> (stmt);
3966*38fd1498Szrj loc = tm_memopt_value_number (stmt, NO_INSERT);
3967*38fd1498Szrj if (store_avail && bitmap_bit_p (store_avail, loc))
3968*38fd1498Szrj tm_memopt_transform_stmt (TRANSFORM_WAW, call_stmt, &gsi);
3969*38fd1498Szrj else
3970*38fd1498Szrj {
3971*38fd1498Szrj if (read_avail && bitmap_bit_p (read_avail, loc))
3972*38fd1498Szrj tm_memopt_transform_stmt (TRANSFORM_WAR, call_stmt, &gsi);
3973*38fd1498Szrj bitmap_set_bit (store_avail, loc);
3974*38fd1498Szrj }
3975*38fd1498Szrj }
3976*38fd1498Szrj }
3977*38fd1498Szrj }
3978*38fd1498Szrj }
3979*38fd1498Szrj
3980*38fd1498Szrj /* Return a new set of bitmaps for a BB. */
3981*38fd1498Szrj
3982*38fd1498Szrj static struct tm_memopt_bitmaps *
tm_memopt_init_sets(void)3983*38fd1498Szrj tm_memopt_init_sets (void)
3984*38fd1498Szrj {
3985*38fd1498Szrj struct tm_memopt_bitmaps *b
3986*38fd1498Szrj = XOBNEW (&tm_memopt_obstack.obstack, struct tm_memopt_bitmaps);
3987*38fd1498Szrj b->store_avail_in = BITMAP_ALLOC (&tm_memopt_obstack);
3988*38fd1498Szrj b->store_avail_out = BITMAP_ALLOC (&tm_memopt_obstack);
3989*38fd1498Szrj b->store_antic_in = BITMAP_ALLOC (&tm_memopt_obstack);
3990*38fd1498Szrj b->store_antic_out = BITMAP_ALLOC (&tm_memopt_obstack);
3991*38fd1498Szrj b->store_avail_out = BITMAP_ALLOC (&tm_memopt_obstack);
3992*38fd1498Szrj b->read_avail_in = BITMAP_ALLOC (&tm_memopt_obstack);
3993*38fd1498Szrj b->read_avail_out = BITMAP_ALLOC (&tm_memopt_obstack);
3994*38fd1498Szrj b->read_local = BITMAP_ALLOC (&tm_memopt_obstack);
3995*38fd1498Szrj b->store_local = BITMAP_ALLOC (&tm_memopt_obstack);
3996*38fd1498Szrj return b;
3997*38fd1498Szrj }
3998*38fd1498Szrj
3999*38fd1498Szrj /* Free sets computed for each BB. */
4000*38fd1498Szrj
4001*38fd1498Szrj static void
tm_memopt_free_sets(vec<basic_block> blocks)4002*38fd1498Szrj tm_memopt_free_sets (vec<basic_block> blocks)
4003*38fd1498Szrj {
4004*38fd1498Szrj size_t i;
4005*38fd1498Szrj basic_block bb;
4006*38fd1498Szrj
4007*38fd1498Szrj for (i = 0; blocks.iterate (i, &bb); ++i)
4008*38fd1498Szrj bb->aux = NULL;
4009*38fd1498Szrj }
4010*38fd1498Szrj
4011*38fd1498Szrj /* Clear the visited bit for every basic block in BLOCKS. */
4012*38fd1498Szrj
4013*38fd1498Szrj static void
tm_memopt_clear_visited(vec<basic_block> blocks)4014*38fd1498Szrj tm_memopt_clear_visited (vec<basic_block> blocks)
4015*38fd1498Szrj {
4016*38fd1498Szrj size_t i;
4017*38fd1498Szrj basic_block bb;
4018*38fd1498Szrj
4019*38fd1498Szrj for (i = 0; blocks.iterate (i, &bb); ++i)
4020*38fd1498Szrj BB_VISITED_P (bb) = false;
4021*38fd1498Szrj }
4022*38fd1498Szrj
4023*38fd1498Szrj /* Replace TM load/stores with hints for the runtime. We handle
4024*38fd1498Szrj things like read-after-write, write-after-read, read-after-read,
4025*38fd1498Szrj read-for-write, etc. */
4026*38fd1498Szrj
4027*38fd1498Szrj static unsigned int
execute_tm_memopt(void)4028*38fd1498Szrj execute_tm_memopt (void)
4029*38fd1498Szrj {
4030*38fd1498Szrj struct tm_region *region;
4031*38fd1498Szrj vec<basic_block> bbs;
4032*38fd1498Szrj
4033*38fd1498Szrj tm_memopt_value_id = 0;
4034*38fd1498Szrj tm_memopt_value_numbers = new hash_table<tm_memop_hasher> (10);
4035*38fd1498Szrj
4036*38fd1498Szrj for (region = all_tm_regions; region; region = region->next)
4037*38fd1498Szrj {
4038*38fd1498Szrj /* All the TM stores/loads in the current region. */
4039*38fd1498Szrj size_t i;
4040*38fd1498Szrj basic_block bb;
4041*38fd1498Szrj
4042*38fd1498Szrj bitmap_obstack_initialize (&tm_memopt_obstack);
4043*38fd1498Szrj
4044*38fd1498Szrj /* Save all BBs for the current region. */
4045*38fd1498Szrj bbs = get_tm_region_blocks (region->entry_block,
4046*38fd1498Szrj region->exit_blocks,
4047*38fd1498Szrj region->irr_blocks,
4048*38fd1498Szrj NULL,
4049*38fd1498Szrj false);
4050*38fd1498Szrj
4051*38fd1498Szrj /* Collect all the memory operations. */
4052*38fd1498Szrj for (i = 0; bbs.iterate (i, &bb); ++i)
4053*38fd1498Szrj {
4054*38fd1498Szrj bb->aux = tm_memopt_init_sets ();
4055*38fd1498Szrj tm_memopt_accumulate_memops (bb);
4056*38fd1498Szrj }
4057*38fd1498Szrj
4058*38fd1498Szrj /* Solve data flow equations and transform each block accordingly. */
4059*38fd1498Szrj tm_memopt_clear_visited (bbs);
4060*38fd1498Szrj tm_memopt_compute_available (region, bbs);
4061*38fd1498Szrj tm_memopt_clear_visited (bbs);
4062*38fd1498Szrj tm_memopt_compute_antic (region, bbs);
4063*38fd1498Szrj tm_memopt_transform_blocks (bbs);
4064*38fd1498Szrj
4065*38fd1498Szrj tm_memopt_free_sets (bbs);
4066*38fd1498Szrj bbs.release ();
4067*38fd1498Szrj bitmap_obstack_release (&tm_memopt_obstack);
4068*38fd1498Szrj tm_memopt_value_numbers->empty ();
4069*38fd1498Szrj }
4070*38fd1498Szrj
4071*38fd1498Szrj delete tm_memopt_value_numbers;
4072*38fd1498Szrj tm_memopt_value_numbers = NULL;
4073*38fd1498Szrj return 0;
4074*38fd1498Szrj }
4075*38fd1498Szrj
4076*38fd1498Szrj namespace {
4077*38fd1498Szrj
4078*38fd1498Szrj const pass_data pass_data_tm_memopt =
4079*38fd1498Szrj {
4080*38fd1498Szrj GIMPLE_PASS, /* type */
4081*38fd1498Szrj "tmmemopt", /* name */
4082*38fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */
4083*38fd1498Szrj TV_TRANS_MEM, /* tv_id */
4084*38fd1498Szrj ( PROP_ssa | PROP_cfg ), /* properties_required */
4085*38fd1498Szrj 0, /* properties_provided */
4086*38fd1498Szrj 0, /* properties_destroyed */
4087*38fd1498Szrj 0, /* todo_flags_start */
4088*38fd1498Szrj 0, /* todo_flags_finish */
4089*38fd1498Szrj };
4090*38fd1498Szrj
4091*38fd1498Szrj class pass_tm_memopt : public gimple_opt_pass
4092*38fd1498Szrj {
4093*38fd1498Szrj public:
pass_tm_memopt(gcc::context * ctxt)4094*38fd1498Szrj pass_tm_memopt (gcc::context *ctxt)
4095*38fd1498Szrj : gimple_opt_pass (pass_data_tm_memopt, ctxt)
4096*38fd1498Szrj {}
4097*38fd1498Szrj
4098*38fd1498Szrj /* opt_pass methods: */
gate(function *)4099*38fd1498Szrj virtual bool gate (function *) { return flag_tm && optimize > 0; }
execute(function *)4100*38fd1498Szrj virtual unsigned int execute (function *) { return execute_tm_memopt (); }
4101*38fd1498Szrj
4102*38fd1498Szrj }; // class pass_tm_memopt
4103*38fd1498Szrj
4104*38fd1498Szrj } // anon namespace
4105*38fd1498Szrj
4106*38fd1498Szrj gimple_opt_pass *
make_pass_tm_memopt(gcc::context * ctxt)4107*38fd1498Szrj make_pass_tm_memopt (gcc::context *ctxt)
4108*38fd1498Szrj {
4109*38fd1498Szrj return new pass_tm_memopt (ctxt);
4110*38fd1498Szrj }
4111*38fd1498Szrj
4112*38fd1498Szrj
4113*38fd1498Szrj /* Interprocedual analysis for the creation of transactional clones.
4114*38fd1498Szrj The aim of this pass is to find which functions are referenced in
4115*38fd1498Szrj a non-irrevocable transaction context, and for those over which
4116*38fd1498Szrj we have control (or user directive), create a version of the
4117*38fd1498Szrj function which uses only the transactional interface to reference
4118*38fd1498Szrj protected memories. This analysis proceeds in several steps:
4119*38fd1498Szrj
4120*38fd1498Szrj (1) Collect the set of all possible transactional clones:
4121*38fd1498Szrj
4122*38fd1498Szrj (a) For all local public functions marked tm_callable, push
4123*38fd1498Szrj it onto the tm_callee queue.
4124*38fd1498Szrj
4125*38fd1498Szrj (b) For all local functions, scan for calls in transaction blocks.
4126*38fd1498Szrj Push the caller and callee onto the tm_caller and tm_callee
4127*38fd1498Szrj queues. Count the number of callers for each callee.
4128*38fd1498Szrj
4129*38fd1498Szrj (c) For each local function on the callee list, assume we will
4130*38fd1498Szrj create a transactional clone. Push *all* calls onto the
4131*38fd1498Szrj callee queues; count the number of clone callers separately
4132*38fd1498Szrj to the number of original callers.
4133*38fd1498Szrj
4134*38fd1498Szrj (2) Propagate irrevocable status up the dominator tree:
4135*38fd1498Szrj
4136*38fd1498Szrj (a) Any external function on the callee list that is not marked
4137*38fd1498Szrj tm_callable is irrevocable. Push all callers of such onto
4138*38fd1498Szrj a worklist.
4139*38fd1498Szrj
4140*38fd1498Szrj (b) For each function on the worklist, mark each block that
4141*38fd1498Szrj contains an irrevocable call. Use the AND operator to
4142*38fd1498Szrj propagate that mark up the dominator tree.
4143*38fd1498Szrj
4144*38fd1498Szrj (c) If we reach the entry block for a possible transactional
4145*38fd1498Szrj clone, then the transactional clone is irrevocable, and
4146*38fd1498Szrj we should not create the clone after all. Push all
4147*38fd1498Szrj callers onto the worklist.
4148*38fd1498Szrj
4149*38fd1498Szrj (d) Place tm_irrevocable calls at the beginning of the relevant
4150*38fd1498Szrj blocks. Special case here is the entry block for the entire
4151*38fd1498Szrj transaction region; there we mark it GTMA_DOES_GO_IRREVOCABLE for
4152*38fd1498Szrj the library to begin the region in serial mode. Decrement
4153*38fd1498Szrj the call count for all callees in the irrevocable region.
4154*38fd1498Szrj
4155*38fd1498Szrj (3) Create the transactional clones:
4156*38fd1498Szrj
4157*38fd1498Szrj Any tm_callee that still has a non-zero call count is cloned.
4158*38fd1498Szrj */
4159*38fd1498Szrj
4160*38fd1498Szrj /* This structure is stored in the AUX field of each cgraph_node. */
4161*38fd1498Szrj struct tm_ipa_cg_data
4162*38fd1498Szrj {
4163*38fd1498Szrj /* The clone of the function that got created. */
4164*38fd1498Szrj struct cgraph_node *clone;
4165*38fd1498Szrj
4166*38fd1498Szrj /* The tm regions in the normal function. */
4167*38fd1498Szrj struct tm_region *all_tm_regions;
4168*38fd1498Szrj
4169*38fd1498Szrj /* The blocks of the normal/clone functions that contain irrevocable
4170*38fd1498Szrj calls, or blocks that are post-dominated by irrevocable calls. */
4171*38fd1498Szrj bitmap irrevocable_blocks_normal;
4172*38fd1498Szrj bitmap irrevocable_blocks_clone;
4173*38fd1498Szrj
4174*38fd1498Szrj /* The blocks of the normal function that are involved in transactions. */
4175*38fd1498Szrj bitmap transaction_blocks_normal;
4176*38fd1498Szrj
4177*38fd1498Szrj /* The number of callers to the transactional clone of this function
4178*38fd1498Szrj from normal and transactional clones respectively. */
4179*38fd1498Szrj unsigned tm_callers_normal;
4180*38fd1498Szrj unsigned tm_callers_clone;
4181*38fd1498Szrj
4182*38fd1498Szrj /* True if all calls to this function's transactional clone
4183*38fd1498Szrj are irrevocable. Also automatically true if the function
4184*38fd1498Szrj has no transactional clone. */
4185*38fd1498Szrj bool is_irrevocable;
4186*38fd1498Szrj
4187*38fd1498Szrj /* Flags indicating the presence of this function in various queues. */
4188*38fd1498Szrj bool in_callee_queue;
4189*38fd1498Szrj bool in_worklist;
4190*38fd1498Szrj
4191*38fd1498Szrj /* Flags indicating the kind of scan desired while in the worklist. */
4192*38fd1498Szrj bool want_irr_scan_normal;
4193*38fd1498Szrj };
4194*38fd1498Szrj
4195*38fd1498Szrj typedef vec<cgraph_node *> cgraph_node_queue;
4196*38fd1498Szrj
4197*38fd1498Szrj /* Return the ipa data associated with NODE, allocating zeroed memory
4198*38fd1498Szrj if necessary. TRAVERSE_ALIASES is true if we must traverse aliases
4199*38fd1498Szrj and set *NODE accordingly. */
4200*38fd1498Szrj
4201*38fd1498Szrj static struct tm_ipa_cg_data *
get_cg_data(struct cgraph_node ** node,bool traverse_aliases)4202*38fd1498Szrj get_cg_data (struct cgraph_node **node, bool traverse_aliases)
4203*38fd1498Szrj {
4204*38fd1498Szrj struct tm_ipa_cg_data *d;
4205*38fd1498Szrj
4206*38fd1498Szrj if (traverse_aliases && (*node)->alias)
4207*38fd1498Szrj *node = (*node)->get_alias_target ();
4208*38fd1498Szrj
4209*38fd1498Szrj d = (struct tm_ipa_cg_data *) (*node)->aux;
4210*38fd1498Szrj
4211*38fd1498Szrj if (d == NULL)
4212*38fd1498Szrj {
4213*38fd1498Szrj d = (struct tm_ipa_cg_data *)
4214*38fd1498Szrj obstack_alloc (&tm_obstack.obstack, sizeof (*d));
4215*38fd1498Szrj (*node)->aux = (void *) d;
4216*38fd1498Szrj memset (d, 0, sizeof (*d));
4217*38fd1498Szrj }
4218*38fd1498Szrj
4219*38fd1498Szrj return d;
4220*38fd1498Szrj }
4221*38fd1498Szrj
4222*38fd1498Szrj /* Add NODE to the end of QUEUE, unless IN_QUEUE_P indicates that
4223*38fd1498Szrj it is already present. */
4224*38fd1498Szrj
4225*38fd1498Szrj static void
maybe_push_queue(struct cgraph_node * node,cgraph_node_queue * queue_p,bool * in_queue_p)4226*38fd1498Szrj maybe_push_queue (struct cgraph_node *node,
4227*38fd1498Szrj cgraph_node_queue *queue_p, bool *in_queue_p)
4228*38fd1498Szrj {
4229*38fd1498Szrj if (!*in_queue_p)
4230*38fd1498Szrj {
4231*38fd1498Szrj *in_queue_p = true;
4232*38fd1498Szrj queue_p->safe_push (node);
4233*38fd1498Szrj }
4234*38fd1498Szrj }
4235*38fd1498Szrj
4236*38fd1498Szrj /* A subroutine of ipa_tm_scan_calls_transaction and ipa_tm_scan_calls_clone.
4237*38fd1498Szrj Queue all callees within block BB. */
4238*38fd1498Szrj
4239*38fd1498Szrj static void
ipa_tm_scan_calls_block(cgraph_node_queue * callees_p,basic_block bb,bool for_clone)4240*38fd1498Szrj ipa_tm_scan_calls_block (cgraph_node_queue *callees_p,
4241*38fd1498Szrj basic_block bb, bool for_clone)
4242*38fd1498Szrj {
4243*38fd1498Szrj gimple_stmt_iterator gsi;
4244*38fd1498Szrj
4245*38fd1498Szrj for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
4246*38fd1498Szrj {
4247*38fd1498Szrj gimple *stmt = gsi_stmt (gsi);
4248*38fd1498Szrj if (is_gimple_call (stmt) && !is_tm_pure_call (stmt))
4249*38fd1498Szrj {
4250*38fd1498Szrj tree fndecl = gimple_call_fndecl (stmt);
4251*38fd1498Szrj if (fndecl)
4252*38fd1498Szrj {
4253*38fd1498Szrj struct tm_ipa_cg_data *d;
4254*38fd1498Szrj unsigned *pcallers;
4255*38fd1498Szrj struct cgraph_node *node;
4256*38fd1498Szrj
4257*38fd1498Szrj if (is_tm_ending_fndecl (fndecl))
4258*38fd1498Szrj continue;
4259*38fd1498Szrj if (find_tm_replacement_function (fndecl))
4260*38fd1498Szrj continue;
4261*38fd1498Szrj
4262*38fd1498Szrj node = cgraph_node::get (fndecl);
4263*38fd1498Szrj gcc_assert (node != NULL);
4264*38fd1498Szrj d = get_cg_data (&node, true);
4265*38fd1498Szrj
4266*38fd1498Szrj pcallers = (for_clone ? &d->tm_callers_clone
4267*38fd1498Szrj : &d->tm_callers_normal);
4268*38fd1498Szrj *pcallers += 1;
4269*38fd1498Szrj
4270*38fd1498Szrj maybe_push_queue (node, callees_p, &d->in_callee_queue);
4271*38fd1498Szrj }
4272*38fd1498Szrj }
4273*38fd1498Szrj }
4274*38fd1498Szrj }
4275*38fd1498Szrj
4276*38fd1498Szrj /* Scan all calls in NODE that are within a transaction region,
4277*38fd1498Szrj and push the resulting nodes into the callee queue. */
4278*38fd1498Szrj
4279*38fd1498Szrj static void
ipa_tm_scan_calls_transaction(struct tm_ipa_cg_data * d,cgraph_node_queue * callees_p)4280*38fd1498Szrj ipa_tm_scan_calls_transaction (struct tm_ipa_cg_data *d,
4281*38fd1498Szrj cgraph_node_queue *callees_p)
4282*38fd1498Szrj {
4283*38fd1498Szrj d->transaction_blocks_normal = BITMAP_ALLOC (&tm_obstack);
4284*38fd1498Szrj d->all_tm_regions = all_tm_regions;
4285*38fd1498Szrj
4286*38fd1498Szrj for (tm_region *r = all_tm_regions; r; r = r->next)
4287*38fd1498Szrj {
4288*38fd1498Szrj vec<basic_block> bbs;
4289*38fd1498Szrj basic_block bb;
4290*38fd1498Szrj unsigned i;
4291*38fd1498Szrj
4292*38fd1498Szrj bbs = get_tm_region_blocks (r->entry_block, r->exit_blocks, NULL,
4293*38fd1498Szrj d->transaction_blocks_normal, false, false);
4294*38fd1498Szrj
4295*38fd1498Szrj FOR_EACH_VEC_ELT (bbs, i, bb)
4296*38fd1498Szrj ipa_tm_scan_calls_block (callees_p, bb, false);
4297*38fd1498Szrj
4298*38fd1498Szrj bbs.release ();
4299*38fd1498Szrj }
4300*38fd1498Szrj }
4301*38fd1498Szrj
4302*38fd1498Szrj /* Scan all calls in NODE as if this is the transactional clone,
4303*38fd1498Szrj and push the destinations into the callee queue. */
4304*38fd1498Szrj
4305*38fd1498Szrj static void
ipa_tm_scan_calls_clone(struct cgraph_node * node,cgraph_node_queue * callees_p)4306*38fd1498Szrj ipa_tm_scan_calls_clone (struct cgraph_node *node,
4307*38fd1498Szrj cgraph_node_queue *callees_p)
4308*38fd1498Szrj {
4309*38fd1498Szrj struct function *fn = DECL_STRUCT_FUNCTION (node->decl);
4310*38fd1498Szrj basic_block bb;
4311*38fd1498Szrj
4312*38fd1498Szrj FOR_EACH_BB_FN (bb, fn)
4313*38fd1498Szrj ipa_tm_scan_calls_block (callees_p, bb, true);
4314*38fd1498Szrj }
4315*38fd1498Szrj
4316*38fd1498Szrj /* The function NODE has been detected to be irrevocable. Push all
4317*38fd1498Szrj of its callers onto WORKLIST for the purpose of re-scanning them. */
4318*38fd1498Szrj
4319*38fd1498Szrj static void
ipa_tm_note_irrevocable(struct cgraph_node * node,cgraph_node_queue * worklist_p)4320*38fd1498Szrj ipa_tm_note_irrevocable (struct cgraph_node *node,
4321*38fd1498Szrj cgraph_node_queue *worklist_p)
4322*38fd1498Szrj {
4323*38fd1498Szrj struct tm_ipa_cg_data *d = get_cg_data (&node, true);
4324*38fd1498Szrj struct cgraph_edge *e;
4325*38fd1498Szrj
4326*38fd1498Szrj d->is_irrevocable = true;
4327*38fd1498Szrj
4328*38fd1498Szrj for (e = node->callers; e ; e = e->next_caller)
4329*38fd1498Szrj {
4330*38fd1498Szrj basic_block bb;
4331*38fd1498Szrj struct cgraph_node *caller;
4332*38fd1498Szrj
4333*38fd1498Szrj /* Don't examine recursive calls. */
4334*38fd1498Szrj if (e->caller == node)
4335*38fd1498Szrj continue;
4336*38fd1498Szrj /* Even if we think we can go irrevocable, believe the user
4337*38fd1498Szrj above all. */
4338*38fd1498Szrj if (is_tm_safe_or_pure (e->caller->decl))
4339*38fd1498Szrj continue;
4340*38fd1498Szrj
4341*38fd1498Szrj caller = e->caller;
4342*38fd1498Szrj d = get_cg_data (&caller, true);
4343*38fd1498Szrj
4344*38fd1498Szrj /* Check if the callee is in a transactional region. If so,
4345*38fd1498Szrj schedule the function for normal re-scan as well. */
4346*38fd1498Szrj bb = gimple_bb (e->call_stmt);
4347*38fd1498Szrj gcc_assert (bb != NULL);
4348*38fd1498Szrj if (d->transaction_blocks_normal
4349*38fd1498Szrj && bitmap_bit_p (d->transaction_blocks_normal, bb->index))
4350*38fd1498Szrj d->want_irr_scan_normal = true;
4351*38fd1498Szrj
4352*38fd1498Szrj maybe_push_queue (caller, worklist_p, &d->in_worklist);
4353*38fd1498Szrj }
4354*38fd1498Szrj }
4355*38fd1498Szrj
4356*38fd1498Szrj /* A subroutine of ipa_tm_scan_irr_blocks; return true iff any statement
4357*38fd1498Szrj within the block is irrevocable. */
4358*38fd1498Szrj
4359*38fd1498Szrj static bool
ipa_tm_scan_irr_block(basic_block bb)4360*38fd1498Szrj ipa_tm_scan_irr_block (basic_block bb)
4361*38fd1498Szrj {
4362*38fd1498Szrj gimple_stmt_iterator gsi;
4363*38fd1498Szrj tree fn;
4364*38fd1498Szrj
4365*38fd1498Szrj for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
4366*38fd1498Szrj {
4367*38fd1498Szrj gimple *stmt = gsi_stmt (gsi);
4368*38fd1498Szrj switch (gimple_code (stmt))
4369*38fd1498Szrj {
4370*38fd1498Szrj case GIMPLE_ASSIGN:
4371*38fd1498Szrj if (gimple_assign_single_p (stmt))
4372*38fd1498Szrj {
4373*38fd1498Szrj tree lhs = gimple_assign_lhs (stmt);
4374*38fd1498Szrj tree rhs = gimple_assign_rhs1 (stmt);
4375*38fd1498Szrj if (volatile_lvalue_p (lhs) || volatile_lvalue_p (rhs))
4376*38fd1498Szrj return true;
4377*38fd1498Szrj }
4378*38fd1498Szrj break;
4379*38fd1498Szrj
4380*38fd1498Szrj case GIMPLE_CALL:
4381*38fd1498Szrj {
4382*38fd1498Szrj tree lhs = gimple_call_lhs (stmt);
4383*38fd1498Szrj if (lhs && volatile_lvalue_p (lhs))
4384*38fd1498Szrj return true;
4385*38fd1498Szrj
4386*38fd1498Szrj if (is_tm_pure_call (stmt))
4387*38fd1498Szrj break;
4388*38fd1498Szrj
4389*38fd1498Szrj fn = gimple_call_fn (stmt);
4390*38fd1498Szrj
4391*38fd1498Szrj /* Functions with the attribute are by definition irrevocable. */
4392*38fd1498Szrj if (is_tm_irrevocable (fn))
4393*38fd1498Szrj return true;
4394*38fd1498Szrj
4395*38fd1498Szrj /* For direct function calls, go ahead and check for replacement
4396*38fd1498Szrj functions, or transitive irrevocable functions. For indirect
4397*38fd1498Szrj functions, we'll ask the runtime. */
4398*38fd1498Szrj if (TREE_CODE (fn) == ADDR_EXPR)
4399*38fd1498Szrj {
4400*38fd1498Szrj struct tm_ipa_cg_data *d;
4401*38fd1498Szrj struct cgraph_node *node;
4402*38fd1498Szrj
4403*38fd1498Szrj fn = TREE_OPERAND (fn, 0);
4404*38fd1498Szrj if (is_tm_ending_fndecl (fn))
4405*38fd1498Szrj break;
4406*38fd1498Szrj if (find_tm_replacement_function (fn))
4407*38fd1498Szrj break;
4408*38fd1498Szrj
4409*38fd1498Szrj node = cgraph_node::get (fn);
4410*38fd1498Szrj d = get_cg_data (&node, true);
4411*38fd1498Szrj
4412*38fd1498Szrj /* Return true if irrevocable, but above all, believe
4413*38fd1498Szrj the user. */
4414*38fd1498Szrj if (d->is_irrevocable
4415*38fd1498Szrj && !is_tm_safe_or_pure (fn))
4416*38fd1498Szrj return true;
4417*38fd1498Szrj }
4418*38fd1498Szrj break;
4419*38fd1498Szrj }
4420*38fd1498Szrj
4421*38fd1498Szrj case GIMPLE_ASM:
4422*38fd1498Szrj /* ??? The Approved Method of indicating that an inline
4423*38fd1498Szrj assembly statement is not relevant to the transaction
4424*38fd1498Szrj is to wrap it in a __tm_waiver block. This is not
4425*38fd1498Szrj yet implemented, so we can't check for it. */
4426*38fd1498Szrj if (is_tm_safe (current_function_decl))
4427*38fd1498Szrj {
4428*38fd1498Szrj tree t = build1 (NOP_EXPR, void_type_node, size_zero_node);
4429*38fd1498Szrj SET_EXPR_LOCATION (t, gimple_location (stmt));
4430*38fd1498Szrj error ("%Kasm not allowed in %<transaction_safe%> function", t);
4431*38fd1498Szrj }
4432*38fd1498Szrj return true;
4433*38fd1498Szrj
4434*38fd1498Szrj default:
4435*38fd1498Szrj break;
4436*38fd1498Szrj }
4437*38fd1498Szrj }
4438*38fd1498Szrj
4439*38fd1498Szrj return false;
4440*38fd1498Szrj }
4441*38fd1498Szrj
4442*38fd1498Szrj /* For each of the blocks seeded witin PQUEUE, walk the CFG looking
4443*38fd1498Szrj for new irrevocable blocks, marking them in NEW_IRR. Don't bother
4444*38fd1498Szrj scanning past OLD_IRR or EXIT_BLOCKS. */
4445*38fd1498Szrj
4446*38fd1498Szrj static bool
ipa_tm_scan_irr_blocks(vec<basic_block> * pqueue,bitmap new_irr,bitmap old_irr,bitmap exit_blocks)4447*38fd1498Szrj ipa_tm_scan_irr_blocks (vec<basic_block> *pqueue, bitmap new_irr,
4448*38fd1498Szrj bitmap old_irr, bitmap exit_blocks)
4449*38fd1498Szrj {
4450*38fd1498Szrj bool any_new_irr = false;
4451*38fd1498Szrj edge e;
4452*38fd1498Szrj edge_iterator ei;
4453*38fd1498Szrj bitmap visited_blocks = BITMAP_ALLOC (NULL);
4454*38fd1498Szrj
4455*38fd1498Szrj do
4456*38fd1498Szrj {
4457*38fd1498Szrj basic_block bb = pqueue->pop ();
4458*38fd1498Szrj
4459*38fd1498Szrj /* Don't re-scan blocks we know already are irrevocable. */
4460*38fd1498Szrj if (old_irr && bitmap_bit_p (old_irr, bb->index))
4461*38fd1498Szrj continue;
4462*38fd1498Szrj
4463*38fd1498Szrj if (ipa_tm_scan_irr_block (bb))
4464*38fd1498Szrj {
4465*38fd1498Szrj bitmap_set_bit (new_irr, bb->index);
4466*38fd1498Szrj any_new_irr = true;
4467*38fd1498Szrj }
4468*38fd1498Szrj else if (exit_blocks == NULL || !bitmap_bit_p (exit_blocks, bb->index))
4469*38fd1498Szrj {
4470*38fd1498Szrj FOR_EACH_EDGE (e, ei, bb->succs)
4471*38fd1498Szrj if (!bitmap_bit_p (visited_blocks, e->dest->index))
4472*38fd1498Szrj {
4473*38fd1498Szrj bitmap_set_bit (visited_blocks, e->dest->index);
4474*38fd1498Szrj pqueue->safe_push (e->dest);
4475*38fd1498Szrj }
4476*38fd1498Szrj }
4477*38fd1498Szrj }
4478*38fd1498Szrj while (!pqueue->is_empty ());
4479*38fd1498Szrj
4480*38fd1498Szrj BITMAP_FREE (visited_blocks);
4481*38fd1498Szrj
4482*38fd1498Szrj return any_new_irr;
4483*38fd1498Szrj }
4484*38fd1498Szrj
4485*38fd1498Szrj /* Propagate the irrevocable property both up and down the dominator tree.
4486*38fd1498Szrj BB is the current block being scanned; EXIT_BLOCKS are the edges of the
4487*38fd1498Szrj TM regions; OLD_IRR are the results of a previous scan of the dominator
4488*38fd1498Szrj tree which has been fully propagated; NEW_IRR is the set of new blocks
4489*38fd1498Szrj which are gaining the irrevocable property during the current scan. */
4490*38fd1498Szrj
4491*38fd1498Szrj static void
ipa_tm_propagate_irr(basic_block entry_block,bitmap new_irr,bitmap old_irr,bitmap exit_blocks)4492*38fd1498Szrj ipa_tm_propagate_irr (basic_block entry_block, bitmap new_irr,
4493*38fd1498Szrj bitmap old_irr, bitmap exit_blocks)
4494*38fd1498Szrj {
4495*38fd1498Szrj vec<basic_block> bbs;
4496*38fd1498Szrj bitmap all_region_blocks;
4497*38fd1498Szrj
4498*38fd1498Szrj /* If this block is in the old set, no need to rescan. */
4499*38fd1498Szrj if (old_irr && bitmap_bit_p (old_irr, entry_block->index))
4500*38fd1498Szrj return;
4501*38fd1498Szrj
4502*38fd1498Szrj all_region_blocks = BITMAP_ALLOC (&tm_obstack);
4503*38fd1498Szrj bbs = get_tm_region_blocks (entry_block, exit_blocks, NULL,
4504*38fd1498Szrj all_region_blocks, false);
4505*38fd1498Szrj do
4506*38fd1498Szrj {
4507*38fd1498Szrj basic_block bb = bbs.pop ();
4508*38fd1498Szrj bool this_irr = bitmap_bit_p (new_irr, bb->index);
4509*38fd1498Szrj bool all_son_irr = false;
4510*38fd1498Szrj edge_iterator ei;
4511*38fd1498Szrj edge e;
4512*38fd1498Szrj
4513*38fd1498Szrj /* Propagate up. If my children are, I am too, but we must have
4514*38fd1498Szrj at least one child that is. */
4515*38fd1498Szrj if (!this_irr)
4516*38fd1498Szrj {
4517*38fd1498Szrj FOR_EACH_EDGE (e, ei, bb->succs)
4518*38fd1498Szrj {
4519*38fd1498Szrj if (!bitmap_bit_p (new_irr, e->dest->index))
4520*38fd1498Szrj {
4521*38fd1498Szrj all_son_irr = false;
4522*38fd1498Szrj break;
4523*38fd1498Szrj }
4524*38fd1498Szrj else
4525*38fd1498Szrj all_son_irr = true;
4526*38fd1498Szrj }
4527*38fd1498Szrj if (all_son_irr)
4528*38fd1498Szrj {
4529*38fd1498Szrj /* Add block to new_irr if it hasn't already been processed. */
4530*38fd1498Szrj if (!old_irr || !bitmap_bit_p (old_irr, bb->index))
4531*38fd1498Szrj {
4532*38fd1498Szrj bitmap_set_bit (new_irr, bb->index);
4533*38fd1498Szrj this_irr = true;
4534*38fd1498Szrj }
4535*38fd1498Szrj }
4536*38fd1498Szrj }
4537*38fd1498Szrj
4538*38fd1498Szrj /* Propagate down to everyone we immediately dominate. */
4539*38fd1498Szrj if (this_irr)
4540*38fd1498Szrj {
4541*38fd1498Szrj basic_block son;
4542*38fd1498Szrj for (son = first_dom_son (CDI_DOMINATORS, bb);
4543*38fd1498Szrj son;
4544*38fd1498Szrj son = next_dom_son (CDI_DOMINATORS, son))
4545*38fd1498Szrj {
4546*38fd1498Szrj /* Make sure block is actually in a TM region, and it
4547*38fd1498Szrj isn't already in old_irr. */
4548*38fd1498Szrj if ((!old_irr || !bitmap_bit_p (old_irr, son->index))
4549*38fd1498Szrj && bitmap_bit_p (all_region_blocks, son->index))
4550*38fd1498Szrj bitmap_set_bit (new_irr, son->index);
4551*38fd1498Szrj }
4552*38fd1498Szrj }
4553*38fd1498Szrj }
4554*38fd1498Szrj while (!bbs.is_empty ());
4555*38fd1498Szrj
4556*38fd1498Szrj BITMAP_FREE (all_region_blocks);
4557*38fd1498Szrj bbs.release ();
4558*38fd1498Szrj }
4559*38fd1498Szrj
4560*38fd1498Szrj static void
ipa_tm_decrement_clone_counts(basic_block bb,bool for_clone)4561*38fd1498Szrj ipa_tm_decrement_clone_counts (basic_block bb, bool for_clone)
4562*38fd1498Szrj {
4563*38fd1498Szrj gimple_stmt_iterator gsi;
4564*38fd1498Szrj
4565*38fd1498Szrj for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
4566*38fd1498Szrj {
4567*38fd1498Szrj gimple *stmt = gsi_stmt (gsi);
4568*38fd1498Szrj if (is_gimple_call (stmt) && !is_tm_pure_call (stmt))
4569*38fd1498Szrj {
4570*38fd1498Szrj tree fndecl = gimple_call_fndecl (stmt);
4571*38fd1498Szrj if (fndecl)
4572*38fd1498Szrj {
4573*38fd1498Szrj struct tm_ipa_cg_data *d;
4574*38fd1498Szrj unsigned *pcallers;
4575*38fd1498Szrj struct cgraph_node *tnode;
4576*38fd1498Szrj
4577*38fd1498Szrj if (is_tm_ending_fndecl (fndecl))
4578*38fd1498Szrj continue;
4579*38fd1498Szrj if (find_tm_replacement_function (fndecl))
4580*38fd1498Szrj continue;
4581*38fd1498Szrj
4582*38fd1498Szrj tnode = cgraph_node::get (fndecl);
4583*38fd1498Szrj d = get_cg_data (&tnode, true);
4584*38fd1498Szrj
4585*38fd1498Szrj pcallers = (for_clone ? &d->tm_callers_clone
4586*38fd1498Szrj : &d->tm_callers_normal);
4587*38fd1498Szrj
4588*38fd1498Szrj gcc_assert (*pcallers > 0);
4589*38fd1498Szrj *pcallers -= 1;
4590*38fd1498Szrj }
4591*38fd1498Szrj }
4592*38fd1498Szrj }
4593*38fd1498Szrj }
4594*38fd1498Szrj
4595*38fd1498Szrj /* (Re-)Scan the transaction blocks in NODE for calls to irrevocable functions,
4596*38fd1498Szrj as well as other irrevocable actions such as inline assembly. Mark all
4597*38fd1498Szrj such blocks as irrevocable and decrement the number of calls to
4598*38fd1498Szrj transactional clones. Return true if, for the transactional clone, the
4599*38fd1498Szrj entire function is irrevocable. */
4600*38fd1498Szrj
4601*38fd1498Szrj static bool
ipa_tm_scan_irr_function(struct cgraph_node * node,bool for_clone)4602*38fd1498Szrj ipa_tm_scan_irr_function (struct cgraph_node *node, bool for_clone)
4603*38fd1498Szrj {
4604*38fd1498Szrj struct tm_ipa_cg_data *d;
4605*38fd1498Szrj bitmap new_irr, old_irr;
4606*38fd1498Szrj bool ret = false;
4607*38fd1498Szrj
4608*38fd1498Szrj /* Builtin operators (operator new, and such). */
4609*38fd1498Szrj if (DECL_STRUCT_FUNCTION (node->decl) == NULL
4610*38fd1498Szrj || DECL_STRUCT_FUNCTION (node->decl)->cfg == NULL)
4611*38fd1498Szrj return false;
4612*38fd1498Szrj
4613*38fd1498Szrj push_cfun (DECL_STRUCT_FUNCTION (node->decl));
4614*38fd1498Szrj calculate_dominance_info (CDI_DOMINATORS);
4615*38fd1498Szrj
4616*38fd1498Szrj d = get_cg_data (&node, true);
4617*38fd1498Szrj auto_vec<basic_block, 10> queue;
4618*38fd1498Szrj new_irr = BITMAP_ALLOC (&tm_obstack);
4619*38fd1498Szrj
4620*38fd1498Szrj /* Scan each tm region, propagating irrevocable status through the tree. */
4621*38fd1498Szrj if (for_clone)
4622*38fd1498Szrj {
4623*38fd1498Szrj old_irr = d->irrevocable_blocks_clone;
4624*38fd1498Szrj queue.quick_push (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
4625*38fd1498Szrj if (ipa_tm_scan_irr_blocks (&queue, new_irr, old_irr, NULL))
4626*38fd1498Szrj {
4627*38fd1498Szrj ipa_tm_propagate_irr (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)),
4628*38fd1498Szrj new_irr,
4629*38fd1498Szrj old_irr, NULL);
4630*38fd1498Szrj ret = bitmap_bit_p (new_irr,
4631*38fd1498Szrj single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun))->index);
4632*38fd1498Szrj }
4633*38fd1498Szrj }
4634*38fd1498Szrj else
4635*38fd1498Szrj {
4636*38fd1498Szrj struct tm_region *region;
4637*38fd1498Szrj
4638*38fd1498Szrj old_irr = d->irrevocable_blocks_normal;
4639*38fd1498Szrj for (region = d->all_tm_regions; region; region = region->next)
4640*38fd1498Szrj {
4641*38fd1498Szrj queue.quick_push (region->entry_block);
4642*38fd1498Szrj if (ipa_tm_scan_irr_blocks (&queue, new_irr, old_irr,
4643*38fd1498Szrj region->exit_blocks))
4644*38fd1498Szrj ipa_tm_propagate_irr (region->entry_block, new_irr, old_irr,
4645*38fd1498Szrj region->exit_blocks);
4646*38fd1498Szrj }
4647*38fd1498Szrj }
4648*38fd1498Szrj
4649*38fd1498Szrj /* If we found any new irrevocable blocks, reduce the call count for
4650*38fd1498Szrj transactional clones within the irrevocable blocks. Save the new
4651*38fd1498Szrj set of irrevocable blocks for next time. */
4652*38fd1498Szrj if (!bitmap_empty_p (new_irr))
4653*38fd1498Szrj {
4654*38fd1498Szrj bitmap_iterator bmi;
4655*38fd1498Szrj unsigned i;
4656*38fd1498Szrj
4657*38fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (new_irr, 0, i, bmi)
4658*38fd1498Szrj ipa_tm_decrement_clone_counts (BASIC_BLOCK_FOR_FN (cfun, i),
4659*38fd1498Szrj for_clone);
4660*38fd1498Szrj
4661*38fd1498Szrj if (old_irr)
4662*38fd1498Szrj {
4663*38fd1498Szrj bitmap_ior_into (old_irr, new_irr);
4664*38fd1498Szrj BITMAP_FREE (new_irr);
4665*38fd1498Szrj }
4666*38fd1498Szrj else if (for_clone)
4667*38fd1498Szrj d->irrevocable_blocks_clone = new_irr;
4668*38fd1498Szrj else
4669*38fd1498Szrj d->irrevocable_blocks_normal = new_irr;
4670*38fd1498Szrj
4671*38fd1498Szrj if (dump_file && new_irr)
4672*38fd1498Szrj {
4673*38fd1498Szrj const char *dname;
4674*38fd1498Szrj bitmap_iterator bmi;
4675*38fd1498Szrj unsigned i;
4676*38fd1498Szrj
4677*38fd1498Szrj dname = lang_hooks.decl_printable_name (current_function_decl, 2);
4678*38fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (new_irr, 0, i, bmi)
4679*38fd1498Szrj fprintf (dump_file, "%s: bb %d goes irrevocable\n", dname, i);
4680*38fd1498Szrj }
4681*38fd1498Szrj }
4682*38fd1498Szrj else
4683*38fd1498Szrj BITMAP_FREE (new_irr);
4684*38fd1498Szrj
4685*38fd1498Szrj pop_cfun ();
4686*38fd1498Szrj
4687*38fd1498Szrj return ret;
4688*38fd1498Szrj }
4689*38fd1498Szrj
4690*38fd1498Szrj /* Return true if, for the transactional clone of NODE, any call
4691*38fd1498Szrj may enter irrevocable mode. */
4692*38fd1498Szrj
4693*38fd1498Szrj static bool
ipa_tm_mayenterirr_function(struct cgraph_node * node)4694*38fd1498Szrj ipa_tm_mayenterirr_function (struct cgraph_node *node)
4695*38fd1498Szrj {
4696*38fd1498Szrj struct tm_ipa_cg_data *d;
4697*38fd1498Szrj tree decl;
4698*38fd1498Szrj unsigned flags;
4699*38fd1498Szrj
4700*38fd1498Szrj d = get_cg_data (&node, true);
4701*38fd1498Szrj decl = node->decl;
4702*38fd1498Szrj flags = flags_from_decl_or_type (decl);
4703*38fd1498Szrj
4704*38fd1498Szrj /* Handle some TM builtins. Ordinarily these aren't actually generated
4705*38fd1498Szrj at this point, but handling these functions when written in by the
4706*38fd1498Szrj user makes it easier to build unit tests. */
4707*38fd1498Szrj if (flags & ECF_TM_BUILTIN)
4708*38fd1498Szrj return false;
4709*38fd1498Szrj
4710*38fd1498Szrj /* Filter out all functions that are marked. */
4711*38fd1498Szrj if (flags & ECF_TM_PURE)
4712*38fd1498Szrj return false;
4713*38fd1498Szrj if (is_tm_safe (decl))
4714*38fd1498Szrj return false;
4715*38fd1498Szrj if (is_tm_irrevocable (decl))
4716*38fd1498Szrj return true;
4717*38fd1498Szrj if (is_tm_callable (decl))
4718*38fd1498Szrj return true;
4719*38fd1498Szrj if (find_tm_replacement_function (decl))
4720*38fd1498Szrj return true;
4721*38fd1498Szrj
4722*38fd1498Szrj /* If we aren't seeing the final version of the function we don't
4723*38fd1498Szrj know what it will contain at runtime. */
4724*38fd1498Szrj if (node->get_availability () < AVAIL_AVAILABLE)
4725*38fd1498Szrj return true;
4726*38fd1498Szrj
4727*38fd1498Szrj /* If the function must go irrevocable, then of course true. */
4728*38fd1498Szrj if (d->is_irrevocable)
4729*38fd1498Szrj return true;
4730*38fd1498Szrj
4731*38fd1498Szrj /* If there are any blocks marked irrevocable, then the function
4732*38fd1498Szrj as a whole may enter irrevocable. */
4733*38fd1498Szrj if (d->irrevocable_blocks_clone)
4734*38fd1498Szrj return true;
4735*38fd1498Szrj
4736*38fd1498Szrj /* We may have previously marked this function as tm_may_enter_irr;
4737*38fd1498Szrj see pass_diagnose_tm_blocks. */
4738*38fd1498Szrj if (node->local.tm_may_enter_irr)
4739*38fd1498Szrj return true;
4740*38fd1498Szrj
4741*38fd1498Szrj /* Recurse on the main body for aliases. In general, this will
4742*38fd1498Szrj result in one of the bits above being set so that we will not
4743*38fd1498Szrj have to recurse next time. */
4744*38fd1498Szrj if (node->alias)
4745*38fd1498Szrj return ipa_tm_mayenterirr_function (cgraph_node::get (node->thunk.alias));
4746*38fd1498Szrj
4747*38fd1498Szrj /* What remains is unmarked local functions without items that force
4748*38fd1498Szrj the function to go irrevocable. */
4749*38fd1498Szrj return false;
4750*38fd1498Szrj }
4751*38fd1498Szrj
4752*38fd1498Szrj /* Diagnose calls from transaction_safe functions to unmarked
4753*38fd1498Szrj functions that are determined to not be safe. */
4754*38fd1498Szrj
4755*38fd1498Szrj static void
ipa_tm_diagnose_tm_safe(struct cgraph_node * node)4756*38fd1498Szrj ipa_tm_diagnose_tm_safe (struct cgraph_node *node)
4757*38fd1498Szrj {
4758*38fd1498Szrj struct cgraph_edge *e;
4759*38fd1498Szrj
4760*38fd1498Szrj for (e = node->callees; e ; e = e->next_callee)
4761*38fd1498Szrj if (!is_tm_callable (e->callee->decl)
4762*38fd1498Szrj && e->callee->local.tm_may_enter_irr)
4763*38fd1498Szrj error_at (gimple_location (e->call_stmt),
4764*38fd1498Szrj "unsafe function call %qD within "
4765*38fd1498Szrj "%<transaction_safe%> function", e->callee->decl);
4766*38fd1498Szrj }
4767*38fd1498Szrj
4768*38fd1498Szrj /* Diagnose call from atomic transactions to unmarked functions
4769*38fd1498Szrj that are determined to not be safe. */
4770*38fd1498Szrj
4771*38fd1498Szrj static void
ipa_tm_diagnose_transaction(struct cgraph_node * node,struct tm_region * all_tm_regions)4772*38fd1498Szrj ipa_tm_diagnose_transaction (struct cgraph_node *node,
4773*38fd1498Szrj struct tm_region *all_tm_regions)
4774*38fd1498Szrj {
4775*38fd1498Szrj struct tm_region *r;
4776*38fd1498Szrj
4777*38fd1498Szrj for (r = all_tm_regions; r ; r = r->next)
4778*38fd1498Szrj if (gimple_transaction_subcode (r->get_transaction_stmt ())
4779*38fd1498Szrj & GTMA_IS_RELAXED)
4780*38fd1498Szrj {
4781*38fd1498Szrj /* Atomic transactions can be nested inside relaxed. */
4782*38fd1498Szrj if (r->inner)
4783*38fd1498Szrj ipa_tm_diagnose_transaction (node, r->inner);
4784*38fd1498Szrj }
4785*38fd1498Szrj else
4786*38fd1498Szrj {
4787*38fd1498Szrj vec<basic_block> bbs;
4788*38fd1498Szrj gimple_stmt_iterator gsi;
4789*38fd1498Szrj basic_block bb;
4790*38fd1498Szrj size_t i;
4791*38fd1498Szrj
4792*38fd1498Szrj bbs = get_tm_region_blocks (r->entry_block, r->exit_blocks,
4793*38fd1498Szrj r->irr_blocks, NULL, false);
4794*38fd1498Szrj
4795*38fd1498Szrj for (i = 0; bbs.iterate (i, &bb); ++i)
4796*38fd1498Szrj for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
4797*38fd1498Szrj {
4798*38fd1498Szrj gimple *stmt = gsi_stmt (gsi);
4799*38fd1498Szrj tree fndecl;
4800*38fd1498Szrj
4801*38fd1498Szrj if (gimple_code (stmt) == GIMPLE_ASM)
4802*38fd1498Szrj {
4803*38fd1498Szrj error_at (gimple_location (stmt),
4804*38fd1498Szrj "asm not allowed in atomic transaction");
4805*38fd1498Szrj continue;
4806*38fd1498Szrj }
4807*38fd1498Szrj
4808*38fd1498Szrj if (!is_gimple_call (stmt))
4809*38fd1498Szrj continue;
4810*38fd1498Szrj fndecl = gimple_call_fndecl (stmt);
4811*38fd1498Szrj
4812*38fd1498Szrj /* Indirect function calls have been diagnosed already. */
4813*38fd1498Szrj if (!fndecl)
4814*38fd1498Szrj continue;
4815*38fd1498Szrj
4816*38fd1498Szrj /* Stop at the end of the transaction. */
4817*38fd1498Szrj if (is_tm_ending_fndecl (fndecl))
4818*38fd1498Szrj {
4819*38fd1498Szrj if (bitmap_bit_p (r->exit_blocks, bb->index))
4820*38fd1498Szrj break;
4821*38fd1498Szrj continue;
4822*38fd1498Szrj }
4823*38fd1498Szrj
4824*38fd1498Szrj /* Marked functions have been diagnosed already. */
4825*38fd1498Szrj if (is_tm_pure_call (stmt))
4826*38fd1498Szrj continue;
4827*38fd1498Szrj if (is_tm_callable (fndecl))
4828*38fd1498Szrj continue;
4829*38fd1498Szrj
4830*38fd1498Szrj if (cgraph_node::local_info (fndecl)->tm_may_enter_irr)
4831*38fd1498Szrj error_at (gimple_location (stmt),
4832*38fd1498Szrj "unsafe function call %qD within "
4833*38fd1498Szrj "atomic transaction", fndecl);
4834*38fd1498Szrj }
4835*38fd1498Szrj
4836*38fd1498Szrj bbs.release ();
4837*38fd1498Szrj }
4838*38fd1498Szrj }
4839*38fd1498Szrj
4840*38fd1498Szrj /* Return a transactional mangled name for the DECL_ASSEMBLER_NAME in
4841*38fd1498Szrj OLD_DECL. The returned value is a freshly malloced pointer that
4842*38fd1498Szrj should be freed by the caller. */
4843*38fd1498Szrj
4844*38fd1498Szrj static tree
tm_mangle(tree old_asm_id)4845*38fd1498Szrj tm_mangle (tree old_asm_id)
4846*38fd1498Szrj {
4847*38fd1498Szrj const char *old_asm_name;
4848*38fd1498Szrj char *tm_name;
4849*38fd1498Szrj void *alloc = NULL;
4850*38fd1498Szrj struct demangle_component *dc;
4851*38fd1498Szrj tree new_asm_id;
4852*38fd1498Szrj
4853*38fd1498Szrj /* Determine if the symbol is already a valid C++ mangled name. Do this
4854*38fd1498Szrj even for C, which might be interfacing with C++ code via appropriately
4855*38fd1498Szrj ugly identifiers. */
4856*38fd1498Szrj /* ??? We could probably do just as well checking for "_Z" and be done. */
4857*38fd1498Szrj old_asm_name = IDENTIFIER_POINTER (old_asm_id);
4858*38fd1498Szrj dc = cplus_demangle_v3_components (old_asm_name, DMGL_NO_OPTS, &alloc);
4859*38fd1498Szrj
4860*38fd1498Szrj if (dc == NULL)
4861*38fd1498Szrj {
4862*38fd1498Szrj char length[8];
4863*38fd1498Szrj
4864*38fd1498Szrj do_unencoded:
4865*38fd1498Szrj sprintf (length, "%u", IDENTIFIER_LENGTH (old_asm_id));
4866*38fd1498Szrj tm_name = concat ("_ZGTt", length, old_asm_name, NULL);
4867*38fd1498Szrj }
4868*38fd1498Szrj else
4869*38fd1498Szrj {
4870*38fd1498Szrj old_asm_name += 2; /* Skip _Z */
4871*38fd1498Szrj
4872*38fd1498Szrj switch (dc->type)
4873*38fd1498Szrj {
4874*38fd1498Szrj case DEMANGLE_COMPONENT_TRANSACTION_CLONE:
4875*38fd1498Szrj case DEMANGLE_COMPONENT_NONTRANSACTION_CLONE:
4876*38fd1498Szrj /* Don't play silly games, you! */
4877*38fd1498Szrj goto do_unencoded;
4878*38fd1498Szrj
4879*38fd1498Szrj case DEMANGLE_COMPONENT_HIDDEN_ALIAS:
4880*38fd1498Szrj /* I'd really like to know if we can ever be passed one of
4881*38fd1498Szrj these from the C++ front end. The Logical Thing would
4882*38fd1498Szrj seem that hidden-alias should be outer-most, so that we
4883*38fd1498Szrj get hidden-alias of a transaction-clone and not vice-versa. */
4884*38fd1498Szrj old_asm_name += 2;
4885*38fd1498Szrj break;
4886*38fd1498Szrj
4887*38fd1498Szrj default:
4888*38fd1498Szrj break;
4889*38fd1498Szrj }
4890*38fd1498Szrj
4891*38fd1498Szrj tm_name = concat ("_ZGTt", old_asm_name, NULL);
4892*38fd1498Szrj }
4893*38fd1498Szrj free (alloc);
4894*38fd1498Szrj
4895*38fd1498Szrj new_asm_id = get_identifier (tm_name);
4896*38fd1498Szrj free (tm_name);
4897*38fd1498Szrj
4898*38fd1498Szrj return new_asm_id;
4899*38fd1498Szrj }
4900*38fd1498Szrj
4901*38fd1498Szrj static inline void
ipa_tm_mark_force_output_node(struct cgraph_node * node)4902*38fd1498Szrj ipa_tm_mark_force_output_node (struct cgraph_node *node)
4903*38fd1498Szrj {
4904*38fd1498Szrj node->mark_force_output ();
4905*38fd1498Szrj node->analyzed = true;
4906*38fd1498Szrj }
4907*38fd1498Szrj
4908*38fd1498Szrj static inline void
ipa_tm_mark_forced_by_abi_node(struct cgraph_node * node)4909*38fd1498Szrj ipa_tm_mark_forced_by_abi_node (struct cgraph_node *node)
4910*38fd1498Szrj {
4911*38fd1498Szrj node->forced_by_abi = true;
4912*38fd1498Szrj node->analyzed = true;
4913*38fd1498Szrj }
4914*38fd1498Szrj
4915*38fd1498Szrj /* Callback data for ipa_tm_create_version_alias. */
4916*38fd1498Szrj struct create_version_alias_info
4917*38fd1498Szrj {
4918*38fd1498Szrj struct cgraph_node *old_node;
4919*38fd1498Szrj tree new_decl;
4920*38fd1498Szrj };
4921*38fd1498Szrj
4922*38fd1498Szrj /* A subroutine of ipa_tm_create_version, called via
4923*38fd1498Szrj cgraph_for_node_and_aliases. Create new tm clones for each of
4924*38fd1498Szrj the existing aliases. */
4925*38fd1498Szrj static bool
ipa_tm_create_version_alias(struct cgraph_node * node,void * data)4926*38fd1498Szrj ipa_tm_create_version_alias (struct cgraph_node *node, void *data)
4927*38fd1498Szrj {
4928*38fd1498Szrj struct create_version_alias_info *info
4929*38fd1498Szrj = (struct create_version_alias_info *)data;
4930*38fd1498Szrj tree old_decl, new_decl, tm_name;
4931*38fd1498Szrj struct cgraph_node *new_node;
4932*38fd1498Szrj
4933*38fd1498Szrj if (!node->cpp_implicit_alias)
4934*38fd1498Szrj return false;
4935*38fd1498Szrj
4936*38fd1498Szrj old_decl = node->decl;
4937*38fd1498Szrj tm_name = tm_mangle (DECL_ASSEMBLER_NAME (old_decl));
4938*38fd1498Szrj new_decl = build_decl (DECL_SOURCE_LOCATION (old_decl),
4939*38fd1498Szrj TREE_CODE (old_decl), tm_name,
4940*38fd1498Szrj TREE_TYPE (old_decl));
4941*38fd1498Szrj
4942*38fd1498Szrj SET_DECL_ASSEMBLER_NAME (new_decl, tm_name);
4943*38fd1498Szrj SET_DECL_RTL (new_decl, NULL);
4944*38fd1498Szrj
4945*38fd1498Szrj /* Based loosely on C++'s make_alias_for(). */
4946*38fd1498Szrj TREE_PUBLIC (new_decl) = TREE_PUBLIC (old_decl);
4947*38fd1498Szrj DECL_CONTEXT (new_decl) = DECL_CONTEXT (old_decl);
4948*38fd1498Szrj DECL_LANG_SPECIFIC (new_decl) = DECL_LANG_SPECIFIC (old_decl);
4949*38fd1498Szrj TREE_READONLY (new_decl) = TREE_READONLY (old_decl);
4950*38fd1498Szrj DECL_EXTERNAL (new_decl) = 0;
4951*38fd1498Szrj DECL_ARTIFICIAL (new_decl) = 1;
4952*38fd1498Szrj TREE_ADDRESSABLE (new_decl) = 1;
4953*38fd1498Szrj TREE_USED (new_decl) = 1;
4954*38fd1498Szrj TREE_SYMBOL_REFERENCED (tm_name) = 1;
4955*38fd1498Szrj
4956*38fd1498Szrj /* Perform the same remapping to the comdat group. */
4957*38fd1498Szrj if (DECL_ONE_ONLY (new_decl))
4958*38fd1498Szrj varpool_node::get (new_decl)->set_comdat_group
4959*38fd1498Szrj (tm_mangle (decl_comdat_group_id (old_decl)));
4960*38fd1498Szrj
4961*38fd1498Szrj new_node = cgraph_node::create_same_body_alias (new_decl, info->new_decl);
4962*38fd1498Szrj new_node->tm_clone = true;
4963*38fd1498Szrj new_node->externally_visible = info->old_node->externally_visible;
4964*38fd1498Szrj new_node->no_reorder = info->old_node->no_reorder;
4965*38fd1498Szrj /* ?? Do not traverse aliases here. */
4966*38fd1498Szrj get_cg_data (&node, false)->clone = new_node;
4967*38fd1498Szrj
4968*38fd1498Szrj record_tm_clone_pair (old_decl, new_decl);
4969*38fd1498Szrj
4970*38fd1498Szrj if (info->old_node->force_output
4971*38fd1498Szrj || info->old_node->ref_list.first_referring ())
4972*38fd1498Szrj ipa_tm_mark_force_output_node (new_node);
4973*38fd1498Szrj if (info->old_node->forced_by_abi)
4974*38fd1498Szrj ipa_tm_mark_forced_by_abi_node (new_node);
4975*38fd1498Szrj return false;
4976*38fd1498Szrj }
4977*38fd1498Szrj
4978*38fd1498Szrj /* Create a copy of the function (possibly declaration only) of OLD_NODE,
4979*38fd1498Szrj appropriate for the transactional clone. */
4980*38fd1498Szrj
4981*38fd1498Szrj static void
ipa_tm_create_version(struct cgraph_node * old_node)4982*38fd1498Szrj ipa_tm_create_version (struct cgraph_node *old_node)
4983*38fd1498Szrj {
4984*38fd1498Szrj tree new_decl, old_decl, tm_name;
4985*38fd1498Szrj struct cgraph_node *new_node;
4986*38fd1498Szrj
4987*38fd1498Szrj old_decl = old_node->decl;
4988*38fd1498Szrj new_decl = copy_node (old_decl);
4989*38fd1498Szrj
4990*38fd1498Szrj /* DECL_ASSEMBLER_NAME needs to be set before we call
4991*38fd1498Szrj cgraph_copy_node_for_versioning below, because cgraph_node will
4992*38fd1498Szrj fill the assembler_name_hash. */
4993*38fd1498Szrj tm_name = tm_mangle (DECL_ASSEMBLER_NAME (old_decl));
4994*38fd1498Szrj SET_DECL_ASSEMBLER_NAME (new_decl, tm_name);
4995*38fd1498Szrj SET_DECL_RTL (new_decl, NULL);
4996*38fd1498Szrj TREE_SYMBOL_REFERENCED (tm_name) = 1;
4997*38fd1498Szrj
4998*38fd1498Szrj /* Perform the same remapping to the comdat group. */
4999*38fd1498Szrj if (DECL_ONE_ONLY (new_decl))
5000*38fd1498Szrj varpool_node::get (new_decl)->set_comdat_group
5001*38fd1498Szrj (tm_mangle (DECL_COMDAT_GROUP (old_decl)));
5002*38fd1498Szrj
5003*38fd1498Szrj gcc_assert (!old_node->ipa_transforms_to_apply.exists ());
5004*38fd1498Szrj new_node = old_node->create_version_clone (new_decl, vNULL, NULL);
5005*38fd1498Szrj new_node->local.local = false;
5006*38fd1498Szrj new_node->externally_visible = old_node->externally_visible;
5007*38fd1498Szrj new_node->lowered = true;
5008*38fd1498Szrj new_node->tm_clone = 1;
5009*38fd1498Szrj if (!old_node->implicit_section)
5010*38fd1498Szrj new_node->set_section (old_node->get_section ());
5011*38fd1498Szrj get_cg_data (&old_node, true)->clone = new_node;
5012*38fd1498Szrj
5013*38fd1498Szrj if (old_node->get_availability () >= AVAIL_INTERPOSABLE)
5014*38fd1498Szrj {
5015*38fd1498Szrj /* Remap extern inline to static inline. */
5016*38fd1498Szrj /* ??? Is it worth trying to use make_decl_one_only? */
5017*38fd1498Szrj if (DECL_DECLARED_INLINE_P (new_decl) && DECL_EXTERNAL (new_decl))
5018*38fd1498Szrj {
5019*38fd1498Szrj DECL_EXTERNAL (new_decl) = 0;
5020*38fd1498Szrj TREE_PUBLIC (new_decl) = 0;
5021*38fd1498Szrj DECL_WEAK (new_decl) = 0;
5022*38fd1498Szrj }
5023*38fd1498Szrj
5024*38fd1498Szrj tree_function_versioning (old_decl, new_decl,
5025*38fd1498Szrj NULL, false, NULL,
5026*38fd1498Szrj false, NULL, NULL);
5027*38fd1498Szrj }
5028*38fd1498Szrj
5029*38fd1498Szrj record_tm_clone_pair (old_decl, new_decl);
5030*38fd1498Szrj
5031*38fd1498Szrj symtab->call_cgraph_insertion_hooks (new_node);
5032*38fd1498Szrj if (old_node->force_output
5033*38fd1498Szrj || old_node->ref_list.first_referring ())
5034*38fd1498Szrj ipa_tm_mark_force_output_node (new_node);
5035*38fd1498Szrj if (old_node->forced_by_abi)
5036*38fd1498Szrj ipa_tm_mark_forced_by_abi_node (new_node);
5037*38fd1498Szrj
5038*38fd1498Szrj /* Do the same thing, but for any aliases of the original node. */
5039*38fd1498Szrj {
5040*38fd1498Szrj struct create_version_alias_info data;
5041*38fd1498Szrj data.old_node = old_node;
5042*38fd1498Szrj data.new_decl = new_decl;
5043*38fd1498Szrj old_node->call_for_symbol_thunks_and_aliases (ipa_tm_create_version_alias,
5044*38fd1498Szrj &data, true);
5045*38fd1498Szrj }
5046*38fd1498Szrj }
5047*38fd1498Szrj
5048*38fd1498Szrj /* Construct a call to TM_IRREVOCABLE and insert it at the beginning of BB. */
5049*38fd1498Szrj
5050*38fd1498Szrj static void
ipa_tm_insert_irr_call(struct cgraph_node * node,struct tm_region * region,basic_block bb)5051*38fd1498Szrj ipa_tm_insert_irr_call (struct cgraph_node *node, struct tm_region *region,
5052*38fd1498Szrj basic_block bb)
5053*38fd1498Szrj {
5054*38fd1498Szrj gimple_stmt_iterator gsi;
5055*38fd1498Szrj gcall *g;
5056*38fd1498Szrj
5057*38fd1498Szrj transaction_subcode_ior (region, GTMA_MAY_ENTER_IRREVOCABLE);
5058*38fd1498Szrj
5059*38fd1498Szrj g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TM_IRREVOCABLE),
5060*38fd1498Szrj 1, build_int_cst (NULL_TREE, MODE_SERIALIRREVOCABLE));
5061*38fd1498Szrj
5062*38fd1498Szrj split_block_after_labels (bb);
5063*38fd1498Szrj gsi = gsi_after_labels (bb);
5064*38fd1498Szrj gsi_insert_before (&gsi, g, GSI_SAME_STMT);
5065*38fd1498Szrj
5066*38fd1498Szrj node->create_edge (cgraph_node::get_create
5067*38fd1498Szrj (builtin_decl_explicit (BUILT_IN_TM_IRREVOCABLE)),
5068*38fd1498Szrj g, gimple_bb (g)->count);
5069*38fd1498Szrj }
5070*38fd1498Szrj
5071*38fd1498Szrj /* Construct a call to TM_GETTMCLONE and insert it before GSI. */
5072*38fd1498Szrj
5073*38fd1498Szrj static bool
ipa_tm_insert_gettmclone_call(struct cgraph_node * node,struct tm_region * region,gimple_stmt_iterator * gsi,gcall * stmt)5074*38fd1498Szrj ipa_tm_insert_gettmclone_call (struct cgraph_node *node,
5075*38fd1498Szrj struct tm_region *region,
5076*38fd1498Szrj gimple_stmt_iterator *gsi, gcall *stmt)
5077*38fd1498Szrj {
5078*38fd1498Szrj tree gettm_fn, ret, old_fn, callfn;
5079*38fd1498Szrj gcall *g;
5080*38fd1498Szrj gassign *g2;
5081*38fd1498Szrj bool safe;
5082*38fd1498Szrj
5083*38fd1498Szrj old_fn = gimple_call_fn (stmt);
5084*38fd1498Szrj
5085*38fd1498Szrj if (TREE_CODE (old_fn) == ADDR_EXPR)
5086*38fd1498Szrj {
5087*38fd1498Szrj tree fndecl = TREE_OPERAND (old_fn, 0);
5088*38fd1498Szrj tree clone = get_tm_clone_pair (fndecl);
5089*38fd1498Szrj
5090*38fd1498Szrj /* By transforming the call into a TM_GETTMCLONE, we are
5091*38fd1498Szrj technically taking the address of the original function and
5092*38fd1498Szrj its clone. Explain this so inlining will know this function
5093*38fd1498Szrj is needed. */
5094*38fd1498Szrj cgraph_node::get (fndecl)->mark_address_taken () ;
5095*38fd1498Szrj if (clone)
5096*38fd1498Szrj cgraph_node::get (clone)->mark_address_taken ();
5097*38fd1498Szrj }
5098*38fd1498Szrj
5099*38fd1498Szrj safe = is_tm_safe (TREE_TYPE (old_fn));
5100*38fd1498Szrj gettm_fn = builtin_decl_explicit (safe ? BUILT_IN_TM_GETTMCLONE_SAFE
5101*38fd1498Szrj : BUILT_IN_TM_GETTMCLONE_IRR);
5102*38fd1498Szrj ret = create_tmp_var (ptr_type_node);
5103*38fd1498Szrj
5104*38fd1498Szrj if (!safe)
5105*38fd1498Szrj transaction_subcode_ior (region, GTMA_MAY_ENTER_IRREVOCABLE);
5106*38fd1498Szrj
5107*38fd1498Szrj /* Discard OBJ_TYPE_REF, since we weren't able to fold it. */
5108*38fd1498Szrj if (TREE_CODE (old_fn) == OBJ_TYPE_REF)
5109*38fd1498Szrj old_fn = OBJ_TYPE_REF_EXPR (old_fn);
5110*38fd1498Szrj
5111*38fd1498Szrj g = gimple_build_call (gettm_fn, 1, old_fn);
5112*38fd1498Szrj ret = make_ssa_name (ret, g);
5113*38fd1498Szrj gimple_call_set_lhs (g, ret);
5114*38fd1498Szrj
5115*38fd1498Szrj gsi_insert_before (gsi, g, GSI_SAME_STMT);
5116*38fd1498Szrj
5117*38fd1498Szrj node->create_edge (cgraph_node::get_create (gettm_fn), g, gimple_bb (g)->count);
5118*38fd1498Szrj
5119*38fd1498Szrj /* Cast return value from tm_gettmclone* into appropriate function
5120*38fd1498Szrj pointer. */
5121*38fd1498Szrj callfn = create_tmp_var (TREE_TYPE (old_fn));
5122*38fd1498Szrj g2 = gimple_build_assign (callfn,
5123*38fd1498Szrj fold_build1 (NOP_EXPR, TREE_TYPE (callfn), ret));
5124*38fd1498Szrj callfn = make_ssa_name (callfn, g2);
5125*38fd1498Szrj gimple_assign_set_lhs (g2, callfn);
5126*38fd1498Szrj gsi_insert_before (gsi, g2, GSI_SAME_STMT);
5127*38fd1498Szrj
5128*38fd1498Szrj /* ??? This is a hack to preserve the NOTHROW bit on the call,
5129*38fd1498Szrj which we would have derived from the decl. Failure to save
5130*38fd1498Szrj this bit means we might have to split the basic block. */
5131*38fd1498Szrj if (gimple_call_nothrow_p (stmt))
5132*38fd1498Szrj gimple_call_set_nothrow (stmt, true);
5133*38fd1498Szrj
5134*38fd1498Szrj gimple_call_set_fn (stmt, callfn);
5135*38fd1498Szrj
5136*38fd1498Szrj /* Discarding OBJ_TYPE_REF above may produce incompatible LHS and RHS
5137*38fd1498Szrj for a call statement. Fix it. */
5138*38fd1498Szrj {
5139*38fd1498Szrj tree lhs = gimple_call_lhs (stmt);
5140*38fd1498Szrj tree rettype = TREE_TYPE (gimple_call_fntype (stmt));
5141*38fd1498Szrj if (lhs
5142*38fd1498Szrj && !useless_type_conversion_p (TREE_TYPE (lhs), rettype))
5143*38fd1498Szrj {
5144*38fd1498Szrj tree temp;
5145*38fd1498Szrj
5146*38fd1498Szrj temp = create_tmp_reg (rettype);
5147*38fd1498Szrj gimple_call_set_lhs (stmt, temp);
5148*38fd1498Szrj
5149*38fd1498Szrj g2 = gimple_build_assign (lhs,
5150*38fd1498Szrj fold_build1 (VIEW_CONVERT_EXPR,
5151*38fd1498Szrj TREE_TYPE (lhs), temp));
5152*38fd1498Szrj gsi_insert_after (gsi, g2, GSI_SAME_STMT);
5153*38fd1498Szrj }
5154*38fd1498Szrj }
5155*38fd1498Szrj
5156*38fd1498Szrj update_stmt (stmt);
5157*38fd1498Szrj cgraph_edge *e = cgraph_node::get (current_function_decl)->get_edge (stmt);
5158*38fd1498Szrj if (e && e->indirect_info)
5159*38fd1498Szrj e->indirect_info->polymorphic = false;
5160*38fd1498Szrj
5161*38fd1498Szrj return true;
5162*38fd1498Szrj }
5163*38fd1498Szrj
5164*38fd1498Szrj /* Helper function for ipa_tm_transform_calls*. Given a call
5165*38fd1498Szrj statement in GSI which resides inside transaction REGION, redirect
5166*38fd1498Szrj the call to either its wrapper function, or its clone. */
5167*38fd1498Szrj
5168*38fd1498Szrj static void
ipa_tm_transform_calls_redirect(struct cgraph_node * node,struct tm_region * region,gimple_stmt_iterator * gsi,bool * need_ssa_rename_p)5169*38fd1498Szrj ipa_tm_transform_calls_redirect (struct cgraph_node *node,
5170*38fd1498Szrj struct tm_region *region,
5171*38fd1498Szrj gimple_stmt_iterator *gsi,
5172*38fd1498Szrj bool *need_ssa_rename_p)
5173*38fd1498Szrj {
5174*38fd1498Szrj gcall *stmt = as_a <gcall *> (gsi_stmt (*gsi));
5175*38fd1498Szrj struct cgraph_node *new_node;
5176*38fd1498Szrj struct cgraph_edge *e = node->get_edge (stmt);
5177*38fd1498Szrj tree fndecl = gimple_call_fndecl (stmt);
5178*38fd1498Szrj
5179*38fd1498Szrj /* For indirect calls, pass the address through the runtime. */
5180*38fd1498Szrj if (fndecl == NULL)
5181*38fd1498Szrj {
5182*38fd1498Szrj *need_ssa_rename_p |=
5183*38fd1498Szrj ipa_tm_insert_gettmclone_call (node, region, gsi, stmt);
5184*38fd1498Szrj return;
5185*38fd1498Szrj }
5186*38fd1498Szrj
5187*38fd1498Szrj /* Handle some TM builtins. Ordinarily these aren't actually generated
5188*38fd1498Szrj at this point, but handling these functions when written in by the
5189*38fd1498Szrj user makes it easier to build unit tests. */
5190*38fd1498Szrj if (flags_from_decl_or_type (fndecl) & ECF_TM_BUILTIN)
5191*38fd1498Szrj return;
5192*38fd1498Szrj
5193*38fd1498Szrj /* Fixup recursive calls inside clones. */
5194*38fd1498Szrj /* ??? Why did cgraph_copy_node_for_versioning update the call edges
5195*38fd1498Szrj for recursion but not update the call statements themselves? */
5196*38fd1498Szrj if (e->caller == e->callee && decl_is_tm_clone (current_function_decl))
5197*38fd1498Szrj {
5198*38fd1498Szrj gimple_call_set_fndecl (stmt, current_function_decl);
5199*38fd1498Szrj return;
5200*38fd1498Szrj }
5201*38fd1498Szrj
5202*38fd1498Szrj /* If there is a replacement, use it. */
5203*38fd1498Szrj fndecl = find_tm_replacement_function (fndecl);
5204*38fd1498Szrj if (fndecl)
5205*38fd1498Szrj {
5206*38fd1498Szrj new_node = cgraph_node::get_create (fndecl);
5207*38fd1498Szrj
5208*38fd1498Szrj /* ??? Mark all transaction_wrap functions tm_may_enter_irr.
5209*38fd1498Szrj
5210*38fd1498Szrj We can't do this earlier in record_tm_replacement because
5211*38fd1498Szrj cgraph_remove_unreachable_nodes is called before we inject
5212*38fd1498Szrj references to the node. Further, we can't do this in some
5213*38fd1498Szrj nice central place in ipa_tm_execute because we don't have
5214*38fd1498Szrj the exact list of wrapper functions that would be used.
5215*38fd1498Szrj Marking more wrappers than necessary results in the creation
5216*38fd1498Szrj of unnecessary cgraph_nodes, which can cause some of the
5217*38fd1498Szrj other IPA passes to crash.
5218*38fd1498Szrj
5219*38fd1498Szrj We do need to mark these nodes so that we get the proper
5220*38fd1498Szrj result in expand_call_tm. */
5221*38fd1498Szrj /* ??? This seems broken. How is it that we're marking the
5222*38fd1498Szrj CALLEE as may_enter_irr? Surely we should be marking the
5223*38fd1498Szrj CALLER. Also note that find_tm_replacement_function also
5224*38fd1498Szrj contains mappings into the TM runtime, e.g. memcpy. These
5225*38fd1498Szrj we know won't go irrevocable. */
5226*38fd1498Szrj new_node->local.tm_may_enter_irr = 1;
5227*38fd1498Szrj }
5228*38fd1498Szrj else
5229*38fd1498Szrj {
5230*38fd1498Szrj struct tm_ipa_cg_data *d;
5231*38fd1498Szrj struct cgraph_node *tnode = e->callee;
5232*38fd1498Szrj
5233*38fd1498Szrj d = get_cg_data (&tnode, true);
5234*38fd1498Szrj new_node = d->clone;
5235*38fd1498Szrj
5236*38fd1498Szrj /* As we've already skipped pure calls and appropriate builtins,
5237*38fd1498Szrj and we've already marked irrevocable blocks, if we can't come
5238*38fd1498Szrj up with a static replacement, then ask the runtime. */
5239*38fd1498Szrj if (new_node == NULL)
5240*38fd1498Szrj {
5241*38fd1498Szrj *need_ssa_rename_p |=
5242*38fd1498Szrj ipa_tm_insert_gettmclone_call (node, region, gsi, stmt);
5243*38fd1498Szrj return;
5244*38fd1498Szrj }
5245*38fd1498Szrj
5246*38fd1498Szrj fndecl = new_node->decl;
5247*38fd1498Szrj }
5248*38fd1498Szrj
5249*38fd1498Szrj e->redirect_callee (new_node);
5250*38fd1498Szrj gimple_call_set_fndecl (stmt, fndecl);
5251*38fd1498Szrj }
5252*38fd1498Szrj
5253*38fd1498Szrj /* Helper function for ipa_tm_transform_calls. For a given BB,
5254*38fd1498Szrj install calls to tm_irrevocable when IRR_BLOCKS are reached,
5255*38fd1498Szrj redirect other calls to the generated transactional clone. */
5256*38fd1498Szrj
5257*38fd1498Szrj static bool
ipa_tm_transform_calls_1(struct cgraph_node * node,struct tm_region * region,basic_block bb,bitmap irr_blocks)5258*38fd1498Szrj ipa_tm_transform_calls_1 (struct cgraph_node *node, struct tm_region *region,
5259*38fd1498Szrj basic_block bb, bitmap irr_blocks)
5260*38fd1498Szrj {
5261*38fd1498Szrj gimple_stmt_iterator gsi;
5262*38fd1498Szrj bool need_ssa_rename = false;
5263*38fd1498Szrj
5264*38fd1498Szrj if (irr_blocks && bitmap_bit_p (irr_blocks, bb->index))
5265*38fd1498Szrj {
5266*38fd1498Szrj ipa_tm_insert_irr_call (node, region, bb);
5267*38fd1498Szrj return true;
5268*38fd1498Szrj }
5269*38fd1498Szrj
5270*38fd1498Szrj for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
5271*38fd1498Szrj {
5272*38fd1498Szrj gimple *stmt = gsi_stmt (gsi);
5273*38fd1498Szrj
5274*38fd1498Szrj if (!is_gimple_call (stmt))
5275*38fd1498Szrj continue;
5276*38fd1498Szrj if (is_tm_pure_call (stmt))
5277*38fd1498Szrj continue;
5278*38fd1498Szrj
5279*38fd1498Szrj /* Redirect edges to the appropriate replacement or clone. */
5280*38fd1498Szrj ipa_tm_transform_calls_redirect (node, region, &gsi, &need_ssa_rename);
5281*38fd1498Szrj }
5282*38fd1498Szrj
5283*38fd1498Szrj return need_ssa_rename;
5284*38fd1498Szrj }
5285*38fd1498Szrj
5286*38fd1498Szrj /* Walk the CFG for REGION, beginning at BB. Install calls to
5287*38fd1498Szrj tm_irrevocable when IRR_BLOCKS are reached, redirect other calls to
5288*38fd1498Szrj the generated transactional clone. */
5289*38fd1498Szrj
5290*38fd1498Szrj static bool
ipa_tm_transform_calls(struct cgraph_node * node,struct tm_region * region,basic_block bb,bitmap irr_blocks)5291*38fd1498Szrj ipa_tm_transform_calls (struct cgraph_node *node, struct tm_region *region,
5292*38fd1498Szrj basic_block bb, bitmap irr_blocks)
5293*38fd1498Szrj {
5294*38fd1498Szrj bool need_ssa_rename = false;
5295*38fd1498Szrj edge e;
5296*38fd1498Szrj edge_iterator ei;
5297*38fd1498Szrj auto_vec<basic_block> queue;
5298*38fd1498Szrj bitmap visited_blocks = BITMAP_ALLOC (NULL);
5299*38fd1498Szrj
5300*38fd1498Szrj queue.safe_push (bb);
5301*38fd1498Szrj do
5302*38fd1498Szrj {
5303*38fd1498Szrj bb = queue.pop ();
5304*38fd1498Szrj
5305*38fd1498Szrj need_ssa_rename |=
5306*38fd1498Szrj ipa_tm_transform_calls_1 (node, region, bb, irr_blocks);
5307*38fd1498Szrj
5308*38fd1498Szrj if (irr_blocks && bitmap_bit_p (irr_blocks, bb->index))
5309*38fd1498Szrj continue;
5310*38fd1498Szrj
5311*38fd1498Szrj if (region && bitmap_bit_p (region->exit_blocks, bb->index))
5312*38fd1498Szrj continue;
5313*38fd1498Szrj
5314*38fd1498Szrj FOR_EACH_EDGE (e, ei, bb->succs)
5315*38fd1498Szrj if (!bitmap_bit_p (visited_blocks, e->dest->index))
5316*38fd1498Szrj {
5317*38fd1498Szrj bitmap_set_bit (visited_blocks, e->dest->index);
5318*38fd1498Szrj queue.safe_push (e->dest);
5319*38fd1498Szrj }
5320*38fd1498Szrj }
5321*38fd1498Szrj while (!queue.is_empty ());
5322*38fd1498Szrj
5323*38fd1498Szrj BITMAP_FREE (visited_blocks);
5324*38fd1498Szrj
5325*38fd1498Szrj return need_ssa_rename;
5326*38fd1498Szrj }
5327*38fd1498Szrj
5328*38fd1498Szrj /* Transform the calls within the TM regions within NODE. */
5329*38fd1498Szrj
5330*38fd1498Szrj static void
ipa_tm_transform_transaction(struct cgraph_node * node)5331*38fd1498Szrj ipa_tm_transform_transaction (struct cgraph_node *node)
5332*38fd1498Szrj {
5333*38fd1498Szrj struct tm_ipa_cg_data *d;
5334*38fd1498Szrj struct tm_region *region;
5335*38fd1498Szrj bool need_ssa_rename = false;
5336*38fd1498Szrj
5337*38fd1498Szrj d = get_cg_data (&node, true);
5338*38fd1498Szrj
5339*38fd1498Szrj push_cfun (DECL_STRUCT_FUNCTION (node->decl));
5340*38fd1498Szrj calculate_dominance_info (CDI_DOMINATORS);
5341*38fd1498Szrj
5342*38fd1498Szrj for (region = d->all_tm_regions; region; region = region->next)
5343*38fd1498Szrj {
5344*38fd1498Szrj /* If we're sure to go irrevocable, don't transform anything. */
5345*38fd1498Szrj if (d->irrevocable_blocks_normal
5346*38fd1498Szrj && bitmap_bit_p (d->irrevocable_blocks_normal,
5347*38fd1498Szrj region->entry_block->index))
5348*38fd1498Szrj {
5349*38fd1498Szrj transaction_subcode_ior (region, GTMA_DOES_GO_IRREVOCABLE
5350*38fd1498Szrj | GTMA_MAY_ENTER_IRREVOCABLE
5351*38fd1498Szrj | GTMA_HAS_NO_INSTRUMENTATION);
5352*38fd1498Szrj continue;
5353*38fd1498Szrj }
5354*38fd1498Szrj
5355*38fd1498Szrj need_ssa_rename |=
5356*38fd1498Szrj ipa_tm_transform_calls (node, region, region->entry_block,
5357*38fd1498Szrj d->irrevocable_blocks_normal);
5358*38fd1498Szrj }
5359*38fd1498Szrj
5360*38fd1498Szrj if (need_ssa_rename)
5361*38fd1498Szrj update_ssa (TODO_update_ssa_only_virtuals);
5362*38fd1498Szrj
5363*38fd1498Szrj pop_cfun ();
5364*38fd1498Szrj }
5365*38fd1498Szrj
5366*38fd1498Szrj /* Transform the calls within the transactional clone of NODE. */
5367*38fd1498Szrj
5368*38fd1498Szrj static void
ipa_tm_transform_clone(struct cgraph_node * node)5369*38fd1498Szrj ipa_tm_transform_clone (struct cgraph_node *node)
5370*38fd1498Szrj {
5371*38fd1498Szrj struct tm_ipa_cg_data *d;
5372*38fd1498Szrj bool need_ssa_rename;
5373*38fd1498Szrj
5374*38fd1498Szrj d = get_cg_data (&node, true);
5375*38fd1498Szrj
5376*38fd1498Szrj /* If this function makes no calls and has no irrevocable blocks,
5377*38fd1498Szrj then there's nothing to do. */
5378*38fd1498Szrj /* ??? Remove non-aborting top-level transactions. */
5379*38fd1498Szrj if (!node->callees && !node->indirect_calls && !d->irrevocable_blocks_clone)
5380*38fd1498Szrj return;
5381*38fd1498Szrj
5382*38fd1498Szrj push_cfun (DECL_STRUCT_FUNCTION (d->clone->decl));
5383*38fd1498Szrj calculate_dominance_info (CDI_DOMINATORS);
5384*38fd1498Szrj
5385*38fd1498Szrj need_ssa_rename =
5386*38fd1498Szrj ipa_tm_transform_calls (d->clone, NULL,
5387*38fd1498Szrj single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)),
5388*38fd1498Szrj d->irrevocable_blocks_clone);
5389*38fd1498Szrj
5390*38fd1498Szrj if (need_ssa_rename)
5391*38fd1498Szrj update_ssa (TODO_update_ssa_only_virtuals);
5392*38fd1498Szrj
5393*38fd1498Szrj pop_cfun ();
5394*38fd1498Szrj }
5395*38fd1498Szrj
5396*38fd1498Szrj /* Main entry point for the transactional memory IPA pass. */
5397*38fd1498Szrj
5398*38fd1498Szrj static unsigned int
ipa_tm_execute(void)5399*38fd1498Szrj ipa_tm_execute (void)
5400*38fd1498Szrj {
5401*38fd1498Szrj cgraph_node_queue tm_callees = cgraph_node_queue ();
5402*38fd1498Szrj /* List of functions that will go irrevocable. */
5403*38fd1498Szrj cgraph_node_queue irr_worklist = cgraph_node_queue ();
5404*38fd1498Szrj
5405*38fd1498Szrj struct cgraph_node *node;
5406*38fd1498Szrj struct tm_ipa_cg_data *d;
5407*38fd1498Szrj enum availability a;
5408*38fd1498Szrj unsigned int i;
5409*38fd1498Szrj
5410*38fd1498Szrj cgraph_node::checking_verify_cgraph_nodes ();
5411*38fd1498Szrj
5412*38fd1498Szrj bitmap_obstack_initialize (&tm_obstack);
5413*38fd1498Szrj initialize_original_copy_tables ();
5414*38fd1498Szrj
5415*38fd1498Szrj /* For all local functions marked tm_callable, queue them. */
5416*38fd1498Szrj FOR_EACH_DEFINED_FUNCTION (node)
5417*38fd1498Szrj if (is_tm_callable (node->decl)
5418*38fd1498Szrj && node->get_availability () >= AVAIL_INTERPOSABLE)
5419*38fd1498Szrj {
5420*38fd1498Szrj d = get_cg_data (&node, true);
5421*38fd1498Szrj maybe_push_queue (node, &tm_callees, &d->in_callee_queue);
5422*38fd1498Szrj }
5423*38fd1498Szrj
5424*38fd1498Szrj /* For all local reachable functions... */
5425*38fd1498Szrj FOR_EACH_DEFINED_FUNCTION (node)
5426*38fd1498Szrj if (node->lowered
5427*38fd1498Szrj && node->get_availability () >= AVAIL_INTERPOSABLE)
5428*38fd1498Szrj {
5429*38fd1498Szrj /* ... marked tm_pure, record that fact for the runtime by
5430*38fd1498Szrj indicating that the pure function is its own tm_callable.
5431*38fd1498Szrj No need to do this if the function's address can't be taken. */
5432*38fd1498Szrj if (is_tm_pure (node->decl))
5433*38fd1498Szrj {
5434*38fd1498Szrj if (!node->local.local)
5435*38fd1498Szrj record_tm_clone_pair (node->decl, node->decl);
5436*38fd1498Szrj continue;
5437*38fd1498Szrj }
5438*38fd1498Szrj
5439*38fd1498Szrj push_cfun (DECL_STRUCT_FUNCTION (node->decl));
5440*38fd1498Szrj calculate_dominance_info (CDI_DOMINATORS);
5441*38fd1498Szrj
5442*38fd1498Szrj tm_region_init (NULL);
5443*38fd1498Szrj if (all_tm_regions)
5444*38fd1498Szrj {
5445*38fd1498Szrj d = get_cg_data (&node, true);
5446*38fd1498Szrj
5447*38fd1498Szrj /* Scan for calls that are in each transaction, and
5448*38fd1498Szrj generate the uninstrumented code path. */
5449*38fd1498Szrj ipa_tm_scan_calls_transaction (d, &tm_callees);
5450*38fd1498Szrj
5451*38fd1498Szrj /* Put it in the worklist so we can scan the function
5452*38fd1498Szrj later (ipa_tm_scan_irr_function) and mark the
5453*38fd1498Szrj irrevocable blocks. */
5454*38fd1498Szrj maybe_push_queue (node, &irr_worklist, &d->in_worklist);
5455*38fd1498Szrj d->want_irr_scan_normal = true;
5456*38fd1498Szrj }
5457*38fd1498Szrj
5458*38fd1498Szrj pop_cfun ();
5459*38fd1498Szrj }
5460*38fd1498Szrj
5461*38fd1498Szrj /* For every local function on the callee list, scan as if we will be
5462*38fd1498Szrj creating a transactional clone, queueing all new functions we find
5463*38fd1498Szrj along the way. */
5464*38fd1498Szrj for (i = 0; i < tm_callees.length (); ++i)
5465*38fd1498Szrj {
5466*38fd1498Szrj node = tm_callees[i];
5467*38fd1498Szrj a = node->get_availability ();
5468*38fd1498Szrj d = get_cg_data (&node, true);
5469*38fd1498Szrj
5470*38fd1498Szrj /* Put it in the worklist so we can scan the function later
5471*38fd1498Szrj (ipa_tm_scan_irr_function) and mark the irrevocable
5472*38fd1498Szrj blocks. */
5473*38fd1498Szrj maybe_push_queue (node, &irr_worklist, &d->in_worklist);
5474*38fd1498Szrj
5475*38fd1498Szrj /* Some callees cannot be arbitrarily cloned. These will always be
5476*38fd1498Szrj irrevocable. Mark these now, so that we need not scan them. */
5477*38fd1498Szrj if (is_tm_irrevocable (node->decl))
5478*38fd1498Szrj ipa_tm_note_irrevocable (node, &irr_worklist);
5479*38fd1498Szrj else if (a <= AVAIL_NOT_AVAILABLE
5480*38fd1498Szrj && !is_tm_safe_or_pure (node->decl))
5481*38fd1498Szrj ipa_tm_note_irrevocable (node, &irr_worklist);
5482*38fd1498Szrj else if (a >= AVAIL_INTERPOSABLE)
5483*38fd1498Szrj {
5484*38fd1498Szrj if (!tree_versionable_function_p (node->decl))
5485*38fd1498Szrj ipa_tm_note_irrevocable (node, &irr_worklist);
5486*38fd1498Szrj else if (!d->is_irrevocable)
5487*38fd1498Szrj {
5488*38fd1498Szrj /* If this is an alias, make sure its base is queued as well.
5489*38fd1498Szrj we need not scan the callees now, as the base will do. */
5490*38fd1498Szrj if (node->alias)
5491*38fd1498Szrj {
5492*38fd1498Szrj node = cgraph_node::get (node->thunk.alias);
5493*38fd1498Szrj d = get_cg_data (&node, true);
5494*38fd1498Szrj maybe_push_queue (node, &tm_callees, &d->in_callee_queue);
5495*38fd1498Szrj continue;
5496*38fd1498Szrj }
5497*38fd1498Szrj
5498*38fd1498Szrj /* Add all nodes called by this function into
5499*38fd1498Szrj tm_callees as well. */
5500*38fd1498Szrj ipa_tm_scan_calls_clone (node, &tm_callees);
5501*38fd1498Szrj }
5502*38fd1498Szrj }
5503*38fd1498Szrj }
5504*38fd1498Szrj
5505*38fd1498Szrj /* Iterate scans until no more work to be done. Prefer not to use
5506*38fd1498Szrj vec::pop because the worklist tends to follow a breadth-first
5507*38fd1498Szrj search of the callgraph, which should allow convergance with a
5508*38fd1498Szrj minimum number of scans. But we also don't want the worklist
5509*38fd1498Szrj array to grow without bound, so we shift the array up periodically. */
5510*38fd1498Szrj for (i = 0; i < irr_worklist.length (); ++i)
5511*38fd1498Szrj {
5512*38fd1498Szrj if (i > 256 && i == irr_worklist.length () / 8)
5513*38fd1498Szrj {
5514*38fd1498Szrj irr_worklist.block_remove (0, i);
5515*38fd1498Szrj i = 0;
5516*38fd1498Szrj }
5517*38fd1498Szrj
5518*38fd1498Szrj node = irr_worklist[i];
5519*38fd1498Szrj d = get_cg_data (&node, true);
5520*38fd1498Szrj d->in_worklist = false;
5521*38fd1498Szrj
5522*38fd1498Szrj if (d->want_irr_scan_normal)
5523*38fd1498Szrj {
5524*38fd1498Szrj d->want_irr_scan_normal = false;
5525*38fd1498Szrj ipa_tm_scan_irr_function (node, false);
5526*38fd1498Szrj }
5527*38fd1498Szrj if (d->in_callee_queue && ipa_tm_scan_irr_function (node, true))
5528*38fd1498Szrj ipa_tm_note_irrevocable (node, &irr_worklist);
5529*38fd1498Szrj }
5530*38fd1498Szrj
5531*38fd1498Szrj /* For every function on the callee list, collect the tm_may_enter_irr
5532*38fd1498Szrj bit on the node. */
5533*38fd1498Szrj irr_worklist.truncate (0);
5534*38fd1498Szrj for (i = 0; i < tm_callees.length (); ++i)
5535*38fd1498Szrj {
5536*38fd1498Szrj node = tm_callees[i];
5537*38fd1498Szrj if (ipa_tm_mayenterirr_function (node))
5538*38fd1498Szrj {
5539*38fd1498Szrj d = get_cg_data (&node, true);
5540*38fd1498Szrj gcc_assert (d->in_worklist == false);
5541*38fd1498Szrj maybe_push_queue (node, &irr_worklist, &d->in_worklist);
5542*38fd1498Szrj }
5543*38fd1498Szrj }
5544*38fd1498Szrj
5545*38fd1498Szrj /* Propagate the tm_may_enter_irr bit to callers until stable. */
5546*38fd1498Szrj for (i = 0; i < irr_worklist.length (); ++i)
5547*38fd1498Szrj {
5548*38fd1498Szrj struct cgraph_node *caller;
5549*38fd1498Szrj struct cgraph_edge *e;
5550*38fd1498Szrj struct ipa_ref *ref;
5551*38fd1498Szrj
5552*38fd1498Szrj if (i > 256 && i == irr_worklist.length () / 8)
5553*38fd1498Szrj {
5554*38fd1498Szrj irr_worklist.block_remove (0, i);
5555*38fd1498Szrj i = 0;
5556*38fd1498Szrj }
5557*38fd1498Szrj
5558*38fd1498Szrj node = irr_worklist[i];
5559*38fd1498Szrj d = get_cg_data (&node, true);
5560*38fd1498Szrj d->in_worklist = false;
5561*38fd1498Szrj node->local.tm_may_enter_irr = true;
5562*38fd1498Szrj
5563*38fd1498Szrj /* Propagate back to normal callers. */
5564*38fd1498Szrj for (e = node->callers; e ; e = e->next_caller)
5565*38fd1498Szrj {
5566*38fd1498Szrj caller = e->caller;
5567*38fd1498Szrj if (!is_tm_safe_or_pure (caller->decl)
5568*38fd1498Szrj && !caller->local.tm_may_enter_irr)
5569*38fd1498Szrj {
5570*38fd1498Szrj d = get_cg_data (&caller, true);
5571*38fd1498Szrj maybe_push_queue (caller, &irr_worklist, &d->in_worklist);
5572*38fd1498Szrj }
5573*38fd1498Szrj }
5574*38fd1498Szrj
5575*38fd1498Szrj /* Propagate back to referring aliases as well. */
5576*38fd1498Szrj FOR_EACH_ALIAS (node, ref)
5577*38fd1498Szrj {
5578*38fd1498Szrj caller = dyn_cast<cgraph_node *> (ref->referring);
5579*38fd1498Szrj if (!caller->local.tm_may_enter_irr)
5580*38fd1498Szrj {
5581*38fd1498Szrj /* ?? Do not traverse aliases here. */
5582*38fd1498Szrj d = get_cg_data (&caller, false);
5583*38fd1498Szrj maybe_push_queue (caller, &irr_worklist, &d->in_worklist);
5584*38fd1498Szrj }
5585*38fd1498Szrj }
5586*38fd1498Szrj }
5587*38fd1498Szrj
5588*38fd1498Szrj /* Now validate all tm_safe functions, and all atomic regions in
5589*38fd1498Szrj other functions. */
5590*38fd1498Szrj FOR_EACH_DEFINED_FUNCTION (node)
5591*38fd1498Szrj if (node->lowered
5592*38fd1498Szrj && node->get_availability () >= AVAIL_INTERPOSABLE)
5593*38fd1498Szrj {
5594*38fd1498Szrj d = get_cg_data (&node, true);
5595*38fd1498Szrj if (is_tm_safe (node->decl))
5596*38fd1498Szrj ipa_tm_diagnose_tm_safe (node);
5597*38fd1498Szrj else if (d->all_tm_regions)
5598*38fd1498Szrj ipa_tm_diagnose_transaction (node, d->all_tm_regions);
5599*38fd1498Szrj }
5600*38fd1498Szrj
5601*38fd1498Szrj /* Create clones. Do those that are not irrevocable and have a
5602*38fd1498Szrj positive call count. Do those publicly visible functions that
5603*38fd1498Szrj the user directed us to clone. */
5604*38fd1498Szrj for (i = 0; i < tm_callees.length (); ++i)
5605*38fd1498Szrj {
5606*38fd1498Szrj bool doit = false;
5607*38fd1498Szrj
5608*38fd1498Szrj node = tm_callees[i];
5609*38fd1498Szrj if (node->cpp_implicit_alias)
5610*38fd1498Szrj continue;
5611*38fd1498Szrj
5612*38fd1498Szrj a = node->get_availability ();
5613*38fd1498Szrj d = get_cg_data (&node, true);
5614*38fd1498Szrj
5615*38fd1498Szrj if (a <= AVAIL_NOT_AVAILABLE)
5616*38fd1498Szrj doit = is_tm_callable (node->decl);
5617*38fd1498Szrj else if (a <= AVAIL_AVAILABLE && is_tm_callable (node->decl))
5618*38fd1498Szrj doit = true;
5619*38fd1498Szrj else if (!d->is_irrevocable
5620*38fd1498Szrj && d->tm_callers_normal + d->tm_callers_clone > 0)
5621*38fd1498Szrj doit = true;
5622*38fd1498Szrj
5623*38fd1498Szrj if (doit)
5624*38fd1498Szrj ipa_tm_create_version (node);
5625*38fd1498Szrj }
5626*38fd1498Szrj
5627*38fd1498Szrj /* Redirect calls to the new clones, and insert irrevocable marks. */
5628*38fd1498Szrj for (i = 0; i < tm_callees.length (); ++i)
5629*38fd1498Szrj {
5630*38fd1498Szrj node = tm_callees[i];
5631*38fd1498Szrj if (node->analyzed)
5632*38fd1498Szrj {
5633*38fd1498Szrj d = get_cg_data (&node, true);
5634*38fd1498Szrj if (d->clone)
5635*38fd1498Szrj ipa_tm_transform_clone (node);
5636*38fd1498Szrj }
5637*38fd1498Szrj }
5638*38fd1498Szrj FOR_EACH_DEFINED_FUNCTION (node)
5639*38fd1498Szrj if (node->lowered
5640*38fd1498Szrj && node->get_availability () >= AVAIL_INTERPOSABLE)
5641*38fd1498Szrj {
5642*38fd1498Szrj d = get_cg_data (&node, true);
5643*38fd1498Szrj if (d->all_tm_regions)
5644*38fd1498Szrj ipa_tm_transform_transaction (node);
5645*38fd1498Szrj }
5646*38fd1498Szrj
5647*38fd1498Szrj /* Free and clear all data structures. */
5648*38fd1498Szrj tm_callees.release ();
5649*38fd1498Szrj irr_worklist.release ();
5650*38fd1498Szrj bitmap_obstack_release (&tm_obstack);
5651*38fd1498Szrj free_original_copy_tables ();
5652*38fd1498Szrj
5653*38fd1498Szrj FOR_EACH_FUNCTION (node)
5654*38fd1498Szrj node->aux = NULL;
5655*38fd1498Szrj
5656*38fd1498Szrj cgraph_node::checking_verify_cgraph_nodes ();
5657*38fd1498Szrj
5658*38fd1498Szrj return 0;
5659*38fd1498Szrj }
5660*38fd1498Szrj
5661*38fd1498Szrj namespace {
5662*38fd1498Szrj
5663*38fd1498Szrj const pass_data pass_data_ipa_tm =
5664*38fd1498Szrj {
5665*38fd1498Szrj SIMPLE_IPA_PASS, /* type */
5666*38fd1498Szrj "tmipa", /* name */
5667*38fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */
5668*38fd1498Szrj TV_TRANS_MEM, /* tv_id */
5669*38fd1498Szrj ( PROP_ssa | PROP_cfg ), /* properties_required */
5670*38fd1498Szrj 0, /* properties_provided */
5671*38fd1498Szrj 0, /* properties_destroyed */
5672*38fd1498Szrj 0, /* todo_flags_start */
5673*38fd1498Szrj 0, /* todo_flags_finish */
5674*38fd1498Szrj };
5675*38fd1498Szrj
5676*38fd1498Szrj class pass_ipa_tm : public simple_ipa_opt_pass
5677*38fd1498Szrj {
5678*38fd1498Szrj public:
pass_ipa_tm(gcc::context * ctxt)5679*38fd1498Szrj pass_ipa_tm (gcc::context *ctxt)
5680*38fd1498Szrj : simple_ipa_opt_pass (pass_data_ipa_tm, ctxt)
5681*38fd1498Szrj {}
5682*38fd1498Szrj
5683*38fd1498Szrj /* opt_pass methods: */
gate(function *)5684*38fd1498Szrj virtual bool gate (function *) { return flag_tm; }
execute(function *)5685*38fd1498Szrj virtual unsigned int execute (function *) { return ipa_tm_execute (); }
5686*38fd1498Szrj
5687*38fd1498Szrj }; // class pass_ipa_tm
5688*38fd1498Szrj
5689*38fd1498Szrj } // anon namespace
5690*38fd1498Szrj
5691*38fd1498Szrj simple_ipa_opt_pass *
make_pass_ipa_tm(gcc::context * ctxt)5692*38fd1498Szrj make_pass_ipa_tm (gcc::context *ctxt)
5693*38fd1498Szrj {
5694*38fd1498Szrj return new pass_ipa_tm (ctxt);
5695*38fd1498Szrj }
5696*38fd1498Szrj
5697*38fd1498Szrj #include "gt-trans-mem.h"
5698