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