afe88c95e6bd4e6002c6d0a9d98d1de84cfdc32d
[platform/upstream/gcc.git] / gcc / cilk-common.c
1 /* This file is part of the Intel(R) Cilk(TM) Plus support
2    This file contains the CilkPlus Intrinsics
3    Copyright (C) 2013-2014 Free Software Foundation, Inc.
4    Contributed by Balaji V. Iyer <balaji.v.iyer@intel.com>,
5    Intel Corporation
6
7 This file is part of GCC.
8
9 GCC is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3, or (at your option)
12 any later version.
13
14 GCC is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with GCC; see the file COPYING3.  If not see
21 <http://www.gnu.org/licenses/>.  */
22
23 #include "config.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "tree.h"
27 #include "stringpool.h"
28 #include "stor-layout.h"
29 #include "langhooks.h"
30 #include "expr.h"
31 #include "optabs.h"
32 #include "recog.h"
33 #include "tree-iterator.h"
34 #include "gimplify.h"
35 #include "cilk.h"
36
37 /* This structure holds all the important fields of the internal structures,
38    internal built-in functions, and Cilk-specific data types.  Explanation of 
39    all the these fielsd are given in cilk.h.  */
40 tree cilk_trees[(int) CILK_TI_MAX];
41
42 /* Returns the value in structure FRAME pointed by the FIELD_NUMBER
43    (e.g. X.y).  
44    FIELD_NUMBER is an index to the structure FRAME_PTR.  For details
45    about these fields, refer to cilk_trees structure in cilk.h and
46    cilk_init_builtins function  in this file.  Returns a TREE that is the type 
47    of the field represented by FIELD_NUMBER.  If VOLATIL parameter is set
48    to true then the returning field is set as volatile.  */
49
50 tree
51 cilk_dot (tree frame, int field_number, bool volatil)
52 {
53   tree field = cilk_trees[field_number];
54   field = fold_build3 (COMPONENT_REF, TREE_TYPE (field), frame, field, 
55                        NULL_TREE);
56   TREE_THIS_VOLATILE (field) = volatil;
57   return field;
58 }
59
60 /* Returns the address of a field in FRAME_PTR, pointed by FIELD_NUMBER.  
61    (e.g. (&X)->y).   Please see cilk_dot function for explanation of the 
62    FIELD_NUMBER.  Returns a tree that is the type of the field represented 
63    by FIELD_NUMBER. If VOLATIL parameter is set to true then the returning
64    field is set as volatile.  */
65
66 tree
67 cilk_arrow (tree frame_ptr, int field_number, bool volatil)
68 {
69   return cilk_dot (fold_build1 (INDIRECT_REF, 
70                                 TREE_TYPE (TREE_TYPE (frame_ptr)), frame_ptr), 
71                    field_number, volatil);
72 }
73
74
75 /* This function will add FIELD of type TYPE to a defined built-in 
76    structure.  *NAME is the name of the field to be added.  */
77
78 static tree
79 add_field (const char *name, tree type, tree fields)
80 {
81   tree t = get_identifier (name);
82   tree field = build_decl (BUILTINS_LOCATION, FIELD_DECL, t, type);
83   TREE_CHAIN (field) = fields;
84   return field;
85 }
86
87 /* This function will define a built-in function of NAME, of type FNTYPE and
88    register it under the built-in function code CODE.  If PUBLISH is set then
89    the declaration is pushed into the declaration list.  CODE is the index
90    to the cilk_trees array.  *NAME is the name of the function to be added.  */
91
92 static tree
93 install_builtin (const char *name, tree fntype, enum built_in_function code,
94                  bool publish)
95 {
96   tree fndecl = build_fn_decl (name, fntype);
97   DECL_BUILT_IN_CLASS (fndecl) = BUILT_IN_NORMAL;
98   DECL_FUNCTION_CODE (fndecl) = code;
99   if (publish)
100     {
101       tree t = lang_hooks.decls.pushdecl (fndecl);
102       if (t)
103         fndecl = t;
104     }
105   set_builtin_decl (code, fndecl, true);
106   return fndecl;
107 }
108
109 /* Creates and initializes all the built-in Cilk keywords functions and three
110    structures: __cilkrts_stack_frame, __cilkrts_pedigree and __cilkrts_worker.
111    Detailed information about __cilkrts_stack_frame and
112    __cilkrts_worker structures are given in libcilkrts/include/internal/abi.h.
113    __cilkrts_pedigree is described in libcilkrts/include/cilk/common.h.  */
114
115 void
116 cilk_init_builtins (void)
117 {
118   /* Now build the following __cilkrts_pedigree struct:
119      struct __cilkrts_pedigree {
120         uint64_t rank;
121         struct __cilkrts_pedigree *parent;
122       }  */
123        
124   tree pedigree_type = lang_hooks.types.make_type (RECORD_TYPE);
125   tree pedigree_ptr  = build_pointer_type (pedigree_type);
126   tree field = add_field ("rank", uint64_type_node, NULL_TREE);
127   cilk_trees[CILK_TI_PEDIGREE_RANK] = field;
128   field = add_field ("parent", pedigree_ptr, field);
129   cilk_trees[CILK_TI_PEDIGREE_PARENT] = field;
130   finish_builtin_struct (pedigree_type, "__cilkrts_pedigree_GCC", field,
131                          NULL_TREE);
132   lang_hooks.types.register_builtin_type (pedigree_type,
133                                           "__cilkrts_pedigree_t");
134   cilk_pedigree_type_decl = pedigree_type; 
135   
136   /* Build the Cilk Stack Frame:
137      struct __cilkrts_stack_frame {
138        uint32_t flags;
139        uint32_t size;
140        struct __cilkrts_stack_frame *call_parent;
141        __cilkrts_worker *worker;
142        void *except_data;
143        void *ctx[4];
144        uint32_t mxcsr;
145        uint16_t fpcsr;
146        uint16_t reserved;
147        __cilkrts_pedigree pedigree;
148      };  */
149
150   tree frame = lang_hooks.types.make_type (RECORD_TYPE);
151   tree frame_ptr = build_pointer_type (frame);
152   tree worker_type = lang_hooks.types.make_type (RECORD_TYPE);
153   tree worker_ptr = build_pointer_type (worker_type);
154   tree s_type_node = build_int_cst (size_type_node, 4);
155
156   tree flags = add_field ("flags", uint32_type_node, NULL_TREE);
157   tree size = add_field ("size", uint32_type_node, flags);
158   tree parent = add_field ("call_parent", frame_ptr, size);
159   tree worker = add_field ("worker", worker_ptr, parent);
160   tree except = add_field ("except_data", frame_ptr, worker);
161   tree context = add_field ("ctx",
162                             build_array_type (ptr_type_node,
163                                               build_index_type (s_type_node)),
164                             except);
165   tree mxcsr = add_field ("mxcsr", uint32_type_node, context);
166   tree fpcsr = add_field ("fpcsr", uint16_type_node, mxcsr);
167   tree reserved = add_field ("reserved", uint16_type_node, fpcsr);
168   tree pedigree = add_field ("pedigree", pedigree_type, reserved);
169   
170   /* Now add them to a common structure whose fields are #defined to something
171      that is used at a later stage.  */
172   cilk_trees[CILK_TI_FRAME_FLAGS] = flags;
173   cilk_trees[CILK_TI_FRAME_PARENT] = parent;
174   cilk_trees[CILK_TI_FRAME_WORKER] = worker;
175   cilk_trees[CILK_TI_FRAME_EXCEPTION] = except;
176   cilk_trees[CILK_TI_FRAME_CONTEXT] = context;
177   /* We don't care about reserved, so no need to store it in cilk_trees.  */
178   cilk_trees[CILK_TI_FRAME_PEDIGREE] = pedigree;
179   TREE_ADDRESSABLE (frame) = 1;
180
181   finish_builtin_struct (frame, "__cilkrts_st_frame_GCC", pedigree, NULL_TREE);
182   cilk_frame_type_decl = frame;
183   lang_hooks.types.register_builtin_type (frame, "__cilkrts_frame_t");
184
185   cilk_frame_ptr_type_decl = build_qualified_type (frame_ptr,
186                                                    TYPE_QUAL_VOLATILE);
187   /* Now let's do the following worker struct:
188
189      struct __cilkrts_worker {
190        __cilkrts_stack_frame *volatile *volatile tail;
191        __cilkrts_stack_frame *volatile *volatile head;
192        __cilkrts_stack_frame *volatile *volatile exc;
193        __cilkrts_stack_frame *volatile *volatile protected_tail;
194        __cilkrts_stack_frame *volatile *ltq_limit;
195        int32_t self;
196        global_state_t *g;
197        local_state *l;
198        cilkred_map *reducer_map;
199        __cilkrts_stack_frame *current_stack_frame;
200        void *reserved;
201        __cilkrts_worker_sysdep_state *sysdep;
202        __cilkrts_pedigree pedigree;
203     }   */
204
205   tree fptr_volatil_type = build_qualified_type (frame_ptr, TYPE_QUAL_VOLATILE);
206   tree fptr_volatile_ptr = build_pointer_type (fptr_volatil_type);
207   tree fptr_vol_ptr_vol = build_qualified_type (fptr_volatile_ptr,
208                                                 TYPE_QUAL_VOLATILE);
209   tree g = lang_hooks.types.make_type (RECORD_TYPE);
210   finish_builtin_struct (g, "__cilkrts_global_state", NULL_TREE, NULL_TREE);
211   tree l = lang_hooks.types.make_type (RECORD_TYPE);
212   finish_builtin_struct (l, "__cilkrts_local_state", NULL_TREE, NULL_TREE);
213   tree sysdep_t = lang_hooks.types.make_type (RECORD_TYPE);
214   finish_builtin_struct (sysdep_t, "__cilkrts_worker_sysdep_state", NULL_TREE,
215                          NULL_TREE);
216   
217   field = add_field ("tail", fptr_vol_ptr_vol, NULL_TREE);
218   cilk_trees[CILK_TI_WORKER_TAIL] = field;
219   field = add_field ("head", fptr_vol_ptr_vol, field);
220   field  = add_field ("exc", fptr_vol_ptr_vol, field);
221   field = add_field ("protected_tail", fptr_vol_ptr_vol, field);
222   field = add_field ("ltq_limit", fptr_volatile_ptr, field);
223   field = add_field ("self", integer_type_node, field);
224   field = add_field ("g", build_pointer_type (g), field);
225   field = add_field ("l", build_pointer_type (g), field);
226   field = add_field ("reducer_map", ptr_type_node, field);
227   field = add_field ("current_stack_frame", frame_ptr, field);
228   cilk_trees[CILK_TI_WORKER_CUR] = field;
229   field = add_field ("saved_protected_tail", fptr_volatile_ptr, field);
230   field = add_field ("sysdep", build_pointer_type (sysdep_t), field);
231   field = add_field ("pedigree", pedigree_type, field);
232   cilk_trees[CILK_TI_WORKER_PEDIGREE] = field;
233   finish_builtin_struct (worker_type, "__cilkrts_worker_GCC", field,
234                          NULL_TREE);
235
236   tree fptr_arglist = tree_cons (NULL_TREE, frame_ptr, void_list_node);
237   tree fptr_fun = build_function_type (void_type_node, fptr_arglist);
238   
239   /* void __cilkrts_enter_frame_1 (__cilkrts_stack_frame *);  */
240   cilk_enter_fndecl = install_builtin ("__cilkrts_enter_frame_1", fptr_fun,
241                                        BUILT_IN_CILK_ENTER_FRAME, false);
242
243   /* void __cilkrts_enter_frame_fast_1 (__cilkrts_stack_frame *);  */
244   cilk_enter_fast_fndecl = 
245     install_builtin ("__cilkrts_enter_frame_fast_1", fptr_fun, 
246                      BUILT_IN_CILK_ENTER_FRAME_FAST, false);
247   
248   /* void __cilkrts_pop_frame (__cilkrts_stack_frame *);  */
249   cilk_pop_fndecl = install_builtin ("__cilkrts_pop_frame", fptr_fun,
250                                      BUILT_IN_CILK_POP_FRAME, false);
251
252   /* void __cilkrts_leave_frame (__cilkrts_stack_frame *);  */
253   cilk_leave_fndecl = install_builtin ("__cilkrts_leave_frame", fptr_fun,
254                                        BUILT_IN_CILK_LEAVE_FRAME, false);
255
256   /* void __cilkrts_sync (__cilkrts_stack_frame *);  */
257   cilk_sync_fndecl = install_builtin ("__cilkrts_sync", fptr_fun,
258                                       BUILT_IN_CILK_SYNC, false);
259
260   /* void __cilkrts_detach (__cilkrts_stack_frame *);  */
261   cilk_detach_fndecl = install_builtin ("__cilkrts_detach", fptr_fun,
262                                         BUILT_IN_CILK_DETACH, false);
263
264   /* __cilkrts_rethrow (struct stack_frame *);  */
265   cilk_rethrow_fndecl = install_builtin ("__cilkrts_rethrow", fptr_fun, 
266                                          BUILT_IN_CILK_RETHROW, false);
267
268   /* __cilkrts_save_fp_ctrl_state (__cilkrts_stack_frame *);  */
269   cilk_save_fp_fndecl = install_builtin ("__cilkrts_save_fp_ctrl_state", 
270                                          fptr_fun, BUILT_IN_CILK_SAVE_FP,
271                                          false);
272 }
273
274 /* Get the appropriate frame arguments for CALL that is of type CALL_EXPR.  */
275
276 static tree
277 get_frame_arg (tree call)
278 {
279   tree arg, argtype;
280
281   gcc_assert (call_expr_nargs (call) >= 1);
282     
283   arg = CALL_EXPR_ARG (call, 0);
284   argtype = TREE_TYPE (arg);
285   gcc_assert (TREE_CODE (argtype) == POINTER_TYPE);
286
287   argtype = TREE_TYPE (argtype);
288   
289   gcc_assert (!lang_hooks.types_compatible_p
290               || lang_hooks.types_compatible_p (argtype, cilk_frame_type_decl));
291
292   /* If it is passed in as an address, then just use the value directly 
293      since the function is inlined.  */
294   if (TREE_CODE (arg) == INDIRECT_REF || TREE_CODE (arg) == ADDR_EXPR)
295     return TREE_OPERAND (arg, 0);
296   return arg;
297 }
298
299 /* Expands the __cilkrts_pop_frame function call stored in EXP.  */
300
301 void
302 expand_builtin_cilk_pop_frame (tree exp)
303 {
304   tree frame = get_frame_arg (exp);
305   tree parent = cilk_dot (frame, CILK_TI_FRAME_PARENT, 0);
306
307   tree clear_parent = build2 (MODIFY_EXPR, void_type_node, parent,
308                               build_int_cst (TREE_TYPE (parent), 0));
309   expand_expr (clear_parent, const0_rtx, VOIDmode, EXPAND_NORMAL);
310
311   /* During LTO, the is_cilk_function flag gets cleared.
312      If __cilkrts_pop_frame is called, then this definitely must be a
313      cilk function.  */
314   if (cfun)
315     cfun->is_cilk_function = 1;
316 }
317
318 /* Expands the cilk_detach function call stored in EXP.  */
319
320 void
321 expand_builtin_cilk_detach (tree exp)
322 {
323   rtx insn;
324   tree fptr = get_frame_arg (exp);
325
326   if (fptr == NULL_TREE)
327     return;
328
329   tree parent = cilk_dot (fptr, CILK_TI_FRAME_PARENT, 0);
330   tree worker = cilk_dot (fptr, CILK_TI_FRAME_WORKER, 0);
331   tree tail = cilk_arrow (worker, CILK_TI_WORKER_TAIL, 1);
332
333   rtx wreg = expand_expr (worker, NULL_RTX, Pmode, EXPAND_NORMAL);
334   if (GET_CODE (wreg) != REG)
335     wreg = copy_to_reg (wreg);
336   rtx preg = expand_expr (parent, NULL_RTX, Pmode, EXPAND_NORMAL);
337
338   /* TMP <- WORKER.TAIL
339     *TMP <- PARENT
340      TMP <- TMP + 1
341      WORKER.TAIL <- TMP   */
342
343   HOST_WIDE_INT worker_tail_offset =
344     tree_to_shwi (DECL_FIELD_OFFSET (cilk_trees[CILK_TI_WORKER_TAIL])) +
345     tree_to_shwi (DECL_FIELD_BIT_OFFSET (cilk_trees[CILK_TI_WORKER_TAIL])) /
346     BITS_PER_UNIT;
347   rtx tmem0 = gen_rtx_MEM (Pmode,
348                            plus_constant (Pmode, wreg, worker_tail_offset));
349   set_mem_attributes (tmem0, tail, 0);
350   MEM_NOTRAP_P (tmem0) = 1;
351   gcc_assert (MEM_VOLATILE_P (tmem0));
352   rtx treg = copy_to_mode_reg (Pmode, tmem0);
353   rtx tmem1 = gen_rtx_MEM (Pmode, treg);
354   set_mem_attributes (tmem1, TREE_TYPE (TREE_TYPE (tail)), 0);
355   MEM_NOTRAP_P (tmem1) = 1;
356   emit_move_insn (tmem1, preg);
357   emit_move_insn (treg, plus_constant (Pmode, treg, GET_MODE_SIZE (Pmode)));
358
359   /* There is a release barrier (st8.rel, membar #StoreStore,
360      sfence, lwsync, etc.) between the two stores.  On x86
361      normal volatile stores have proper semantics; the sfence
362      would only be needed for nontemporal stores (which we
363      could generate using the storent optab, for no benefit
364      in this case).
365
366      The predicate may return false even for a REG if this is
367      the limited release operation that only stores 0.  */
368   enum insn_code icode = direct_optab_handler (sync_lock_release_optab, Pmode); 
369   if (icode != CODE_FOR_nothing
370       && insn_data[icode].operand[1].predicate (treg, Pmode)
371       && (insn = GEN_FCN (icode) (tmem0, treg)) != NULL_RTX)
372     emit_insn (insn);
373   else
374     emit_move_insn (tmem0, treg);
375
376   /* The memory barrier inserted above should not prevent
377      the load of flags from being moved before the stores,
378      but in practice it does because it is implemented with
379      unspec_volatile.  In-order RISC machines should
380      explicitly load flags earlier.  */
381
382   tree flags = cilk_dot (fptr, CILK_TI_FRAME_FLAGS, 0);
383   expand_expr (build2 (MODIFY_EXPR, void_type_node, flags,
384                        build2 (BIT_IOR_EXPR, TREE_TYPE (flags), flags,
385                                build_int_cst (TREE_TYPE (flags),
386                                               CILK_FRAME_DETACHED))),
387                const0_rtx, VOIDmode, EXPAND_NORMAL);
388 }
389
390 /* Returns a setjmp CALL_EXPR with FRAME->context as its parameter.  */
391
392 tree
393 cilk_call_setjmp (tree frame)
394 {
395   tree c = cilk_dot (frame, CILK_TI_FRAME_CONTEXT, false);
396   c = build1 (ADDR_EXPR, build_pointer_type (ptr_type_node), c);
397   return build_call_expr (builtin_decl_implicit (BUILT_IN_SETJMP), 1, c);
398 }
399
400 /* This function will expand the _Cilk_sync keyword.  */
401
402 static tree
403 expand_cilk_sync (void)
404 {
405   tree frame = cfun->cilk_frame_decl;
406
407   /* Cilk_sync is converted to the following code:
408
409      sf.pedigree = sf.worker->pedigree;
410      if (frame.flags & CILK_FRAME_UNSYNCHED)
411      {
412         __cilkrts_save_fp_state (&sf);
413         if (!builtin_setjmp (sf.ctx) 
414             __cilkrts_sync (&sf); 
415         else 
416            if (sf.flags & CILK_FRAME_EXCEPTING) 
417              __cilkrts_rethrow (&sf); 
418       }
419       sf.worker->pedigree.rank = sf.worker->pedigree.rank + 1;  */
420
421   tree flags = cilk_dot (frame, CILK_TI_FRAME_FLAGS, false);
422   
423   tree unsynched = fold_build2 (BIT_AND_EXPR, TREE_TYPE (flags), flags,
424                                 build_int_cst (TREE_TYPE (flags),
425                                                CILK_FRAME_UNSYNCHED));
426
427   unsynched = fold_build2 (NE_EXPR, TREE_TYPE (unsynched), unsynched,
428                            build_int_cst (TREE_TYPE (unsynched), 0));
429
430   tree frame_addr = build1 (ADDR_EXPR, cilk_frame_ptr_type_decl, frame);
431
432   /* Check if exception (0x10) bit is set in the sf->flags.  */
433   tree except_flag = fold_build2 (BIT_AND_EXPR, TREE_TYPE (flags), flags,
434                                   build_int_cst (TREE_TYPE (flags),
435                                                  CILK_FRAME_EXCEPTING));
436   except_flag = fold_build2 (NE_EXPR, TREE_TYPE (except_flag), except_flag,
437                              build_int_cst (TREE_TYPE (except_flag), 0));
438
439   /* If the exception flag is set then call the __cilkrts_rethrow (&sf).  */
440   tree except_cond = fold_build3 (COND_EXPR, void_type_node, except_flag,
441                                   build_call_expr (cilk_rethrow_fndecl, 1,
442                                                    frame_addr),
443                                   build_empty_stmt (EXPR_LOCATION (unsynched)));
444   
445   tree sync_expr = build_call_expr (cilk_sync_fndecl, 1, frame_addr);
446   tree setjmp_expr = cilk_call_setjmp (frame);
447   setjmp_expr = fold_build2 (EQ_EXPR, TREE_TYPE (setjmp_expr), setjmp_expr,
448                              build_int_cst (TREE_TYPE (setjmp_expr), 0));
449   
450   setjmp_expr = fold_build3 (COND_EXPR, void_type_node, setjmp_expr,
451                              sync_expr, except_cond);
452   tree sync_list = alloc_stmt_list ();
453   append_to_statement_list (build_call_expr (cilk_save_fp_fndecl, 1,
454                                              frame_addr), &sync_list);
455   append_to_statement_list (setjmp_expr, &sync_list);
456   tree sync = fold_build3 (COND_EXPR, void_type_node, unsynched, sync_list,
457                            build_empty_stmt (EXPR_LOCATION (unsynched)));
458   tree parent_pedigree = cilk_dot (frame, CILK_TI_FRAME_PEDIGREE, false);
459   tree worker = cilk_dot (frame, CILK_TI_FRAME_WORKER, false);
460   tree worker_pedigree = cilk_arrow (worker, CILK_TI_WORKER_PEDIGREE, false);
461   tree assign_pedigree = fold_build2 (MODIFY_EXPR, void_type_node,
462                                       parent_pedigree, worker_pedigree);
463   tree w_ped_rank = cilk_dot (unshare_expr (worker_pedigree), 
464                               CILK_TI_PEDIGREE_RANK, false);
465   tree incr_ped_rank = fold_build2 (PLUS_EXPR, TREE_TYPE (w_ped_rank),
466                                     w_ped_rank,
467                                     build_one_cst (TREE_TYPE (w_ped_rank)));
468   incr_ped_rank = fold_build2 (MODIFY_EXPR, void_type_node, w_ped_rank,
469                                incr_ped_rank);
470   tree ret_sync_exp = alloc_stmt_list ();
471   append_to_statement_list (assign_pedigree, &ret_sync_exp);
472   append_to_statement_list (sync, &ret_sync_exp);
473   append_to_statement_list (incr_ped_rank, &ret_sync_exp);
474   return ret_sync_exp;
475 }
476
477 /* Gimplifies the cilk_sync expression passed in *EXPR_P.  Returns GS_ALL_DONE 
478    when finished.  */
479
480 void
481 gimplify_cilk_sync (tree *expr_p, gimple_seq *pre_p)
482 {
483   tree sync_expr = expand_cilk_sync ();
484   *expr_p = NULL_TREE;
485   gimplify_and_add (sync_expr, pre_p);
486 }