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