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