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