2014-07-29 Ed Smith-Rowland <3dw4rd@verizon.net>
[official-gcc.git] / gcc / cilk-common.c
bloba6a1aa2a9681ddee5eca2fb5b4065137baf96f69
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
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 "gimplify.h"
35 #include "cilk.h"
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];
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. */
50 tree
51 cilk_dot (tree frame, int field_number, bool volatil)
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;
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. */
66 tree
67 cilk_arrow (tree frame_ptr, int field_number, bool volatil)
69 return cilk_dot (build_simple_mem_ref (frame_ptr),
70 field_number, volatil);
74 /* This function will add FIELD of type TYPE to a defined built-in
75 structure. *NAME is the name of the field to be added. */
77 static tree
78 add_field (const char *name, tree type, tree fields)
80 tree t = get_identifier (name);
81 tree field = build_decl (BUILTINS_LOCATION, FIELD_DECL, t, type);
82 TREE_CHAIN (field) = fields;
83 return field;
86 /* This function will define a built-in function of NAME, of type FNTYPE and
87 register it under the built-in function code CODE. If PUBLISH is set then
88 the declaration is pushed into the declaration list. CODE is the index
89 to the cilk_trees array. *NAME is the name of the function to be added. */
91 static tree
92 install_builtin (const char *name, tree fntype, enum built_in_function code,
93 bool publish)
95 tree fndecl = build_fn_decl (name, fntype);
96 DECL_BUILT_IN_CLASS (fndecl) = BUILT_IN_NORMAL;
97 DECL_FUNCTION_CODE (fndecl) = code;
98 if (publish)
100 tree t = lang_hooks.decls.pushdecl (fndecl);
101 if (t)
102 fndecl = t;
104 set_builtin_decl (code, fndecl, true);
105 return fndecl;
108 /* Creates and initializes all the built-in Cilk keywords functions and three
109 structures: __cilkrts_stack_frame, __cilkrts_pedigree and __cilkrts_worker.
110 Detailed information about __cilkrts_stack_frame and
111 __cilkrts_worker structures are given in libcilkrts/include/internal/abi.h.
112 __cilkrts_pedigree is described in libcilkrts/include/cilk/common.h. */
114 void
115 cilk_init_builtins (void)
117 /* Now build the following __cilkrts_pedigree struct:
118 struct __cilkrts_pedigree {
119 uint64_t rank;
120 struct __cilkrts_pedigree *parent;
121 } */
123 tree pedigree_type = lang_hooks.types.make_type (RECORD_TYPE);
124 tree pedigree_ptr = build_pointer_type (pedigree_type);
125 tree field = add_field ("rank", uint64_type_node, NULL_TREE);
126 cilk_trees[CILK_TI_PEDIGREE_RANK] = field;
127 field = add_field ("parent", pedigree_ptr, field);
128 cilk_trees[CILK_TI_PEDIGREE_PARENT] = field;
129 finish_builtin_struct (pedigree_type, "__cilkrts_pedigree_GCC", field,
130 NULL_TREE);
131 lang_hooks.types.register_builtin_type (pedigree_type,
132 "__cilkrts_pedigree_t");
133 cilk_pedigree_type_decl = pedigree_type;
135 /* Build the Cilk Stack Frame:
136 struct __cilkrts_stack_frame {
137 uint32_t flags;
138 uint32_t size;
139 struct __cilkrts_stack_frame *call_parent;
140 __cilkrts_worker *worker;
141 void *except_data;
142 void *ctx[4];
143 uint32_t mxcsr;
144 uint16_t fpcsr;
145 uint16_t reserved;
146 __cilkrts_pedigree pedigree;
147 }; */
149 tree frame = lang_hooks.types.make_type (RECORD_TYPE);
150 tree frame_ptr = build_pointer_type (frame);
151 tree worker_type = lang_hooks.types.make_type (RECORD_TYPE);
152 tree worker_ptr = build_pointer_type (worker_type);
153 tree s_type_node = build_int_cst (size_type_node, 4);
155 tree flags = add_field ("flags", uint32_type_node, NULL_TREE);
156 tree size = add_field ("size", uint32_type_node, flags);
157 tree parent = add_field ("call_parent", frame_ptr, size);
158 tree worker = add_field ("worker", worker_ptr, parent);
159 tree except = add_field ("except_data", frame_ptr, worker);
160 tree context = add_field ("ctx",
161 build_array_type (ptr_type_node,
162 build_index_type (s_type_node)),
163 except);
164 tree mxcsr = add_field ("mxcsr", uint32_type_node, context);
165 tree fpcsr = add_field ("fpcsr", uint16_type_node, mxcsr);
166 tree reserved = add_field ("reserved", uint16_type_node, fpcsr);
167 tree pedigree = add_field ("pedigree", pedigree_type, reserved);
169 /* Now add them to a common structure whose fields are #defined to something
170 that is used at a later stage. */
171 cilk_trees[CILK_TI_FRAME_FLAGS] = flags;
172 cilk_trees[CILK_TI_FRAME_PARENT] = parent;
173 cilk_trees[CILK_TI_FRAME_WORKER] = worker;
174 cilk_trees[CILK_TI_FRAME_EXCEPTION] = except;
175 cilk_trees[CILK_TI_FRAME_CONTEXT] = context;
176 /* We don't care about reserved, so no need to store it in cilk_trees. */
177 cilk_trees[CILK_TI_FRAME_PEDIGREE] = pedigree;
178 TREE_ADDRESSABLE (frame) = 1;
180 finish_builtin_struct (frame, "__cilkrts_st_frame_GCC", pedigree, NULL_TREE);
181 cilk_frame_type_decl = frame;
182 lang_hooks.types.register_builtin_type (frame, "__cilkrts_frame_t");
184 cilk_frame_ptr_type_decl = build_qualified_type (frame_ptr,
185 TYPE_QUAL_VOLATILE);
186 /* Now let's do the following worker struct:
188 struct __cilkrts_worker {
189 __cilkrts_stack_frame *volatile *volatile tail;
190 __cilkrts_stack_frame *volatile *volatile head;
191 __cilkrts_stack_frame *volatile *volatile exc;
192 __cilkrts_stack_frame *volatile *volatile protected_tail;
193 __cilkrts_stack_frame *volatile *ltq_limit;
194 int32_t self;
195 global_state_t *g;
196 local_state *l;
197 cilkred_map *reducer_map;
198 __cilkrts_stack_frame *current_stack_frame;
199 void *reserved;
200 __cilkrts_worker_sysdep_state *sysdep;
201 __cilkrts_pedigree pedigree;
202 } */
204 tree fptr_volatil_type = build_qualified_type (frame_ptr, TYPE_QUAL_VOLATILE);
205 tree fptr_volatile_ptr = build_pointer_type (fptr_volatil_type);
206 tree fptr_vol_ptr_vol = build_qualified_type (fptr_volatile_ptr,
207 TYPE_QUAL_VOLATILE);
208 tree g = lang_hooks.types.make_type (RECORD_TYPE);
209 finish_builtin_struct (g, "__cilkrts_global_state", NULL_TREE, NULL_TREE);
210 tree l = lang_hooks.types.make_type (RECORD_TYPE);
211 finish_builtin_struct (l, "__cilkrts_local_state", NULL_TREE, NULL_TREE);
212 tree sysdep_t = lang_hooks.types.make_type (RECORD_TYPE);
213 finish_builtin_struct (sysdep_t, "__cilkrts_worker_sysdep_state", NULL_TREE,
214 NULL_TREE);
216 field = add_field ("tail", fptr_vol_ptr_vol, NULL_TREE);
217 cilk_trees[CILK_TI_WORKER_TAIL] = field;
218 field = add_field ("head", fptr_vol_ptr_vol, field);
219 field = add_field ("exc", fptr_vol_ptr_vol, field);
220 field = add_field ("protected_tail", fptr_vol_ptr_vol, field);
221 field = add_field ("ltq_limit", fptr_volatile_ptr, field);
222 field = add_field ("self", integer_type_node, field);
223 field = add_field ("g", build_pointer_type (g), field);
224 field = add_field ("l", build_pointer_type (g), field);
225 field = add_field ("reducer_map", ptr_type_node, field);
226 field = add_field ("current_stack_frame", frame_ptr, field);
227 cilk_trees[CILK_TI_WORKER_CUR] = field;
228 field = add_field ("saved_protected_tail", fptr_volatile_ptr, field);
229 field = add_field ("sysdep", build_pointer_type (sysdep_t), field);
230 field = add_field ("pedigree", pedigree_type, field);
231 cilk_trees[CILK_TI_WORKER_PEDIGREE] = field;
232 finish_builtin_struct (worker_type, "__cilkrts_worker_GCC", field,
233 NULL_TREE);
235 tree fptr_arglist = tree_cons (NULL_TREE, frame_ptr, void_list_node);
236 tree fptr_fun = build_function_type (void_type_node, fptr_arglist);
238 /* void __cilkrts_enter_frame_1 (__cilkrts_stack_frame *); */
239 cilk_enter_fndecl = install_builtin ("__cilkrts_enter_frame_1", fptr_fun,
240 BUILT_IN_CILK_ENTER_FRAME, false);
242 /* void __cilkrts_enter_frame_fast_1 (__cilkrts_stack_frame *); */
243 cilk_enter_fast_fndecl =
244 install_builtin ("__cilkrts_enter_frame_fast_1", fptr_fun,
245 BUILT_IN_CILK_ENTER_FRAME_FAST, false);
247 /* void __cilkrts_pop_frame (__cilkrts_stack_frame *); */
248 cilk_pop_fndecl = install_builtin ("__cilkrts_pop_frame", fptr_fun,
249 BUILT_IN_CILK_POP_FRAME, false);
251 /* void __cilkrts_leave_frame (__cilkrts_stack_frame *); */
252 cilk_leave_fndecl = install_builtin ("__cilkrts_leave_frame", fptr_fun,
253 BUILT_IN_CILK_LEAVE_FRAME, false);
255 /* void __cilkrts_sync (__cilkrts_stack_frame *); */
256 cilk_sync_fndecl = install_builtin ("__cilkrts_sync", fptr_fun,
257 BUILT_IN_CILK_SYNC, false);
259 /* void __cilkrts_detach (__cilkrts_stack_frame *); */
260 cilk_detach_fndecl = install_builtin ("__cilkrts_detach", fptr_fun,
261 BUILT_IN_CILK_DETACH, false);
263 /* __cilkrts_rethrow (struct stack_frame *); */
264 cilk_rethrow_fndecl = install_builtin ("__cilkrts_rethrow", fptr_fun,
265 BUILT_IN_CILK_RETHROW, false);
266 TREE_NOTHROW (cilk_rethrow_fndecl) = 0;
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);
274 /* Get the appropriate frame arguments for CALL that is of type CALL_EXPR. */
276 static tree
277 get_frame_arg (tree call)
279 tree arg, argtype;
281 gcc_assert (call_expr_nargs (call) >= 1);
283 arg = CALL_EXPR_ARG (call, 0);
284 argtype = TREE_TYPE (arg);
285 gcc_assert (TREE_CODE (argtype) == POINTER_TYPE);
287 argtype = TREE_TYPE (argtype);
289 /* If it is passed in as an address, then just use the value directly
290 since the function is inlined. */
291 if (TREE_CODE (arg) == ADDR_EXPR)
292 return TREE_OPERAND (arg, 0);
293 return arg;
296 /* Expands the __cilkrts_pop_frame function call stored in EXP. */
298 void
299 expand_builtin_cilk_pop_frame (tree exp)
301 tree frame = get_frame_arg (exp);
302 tree parent = cilk_dot (frame, CILK_TI_FRAME_PARENT, 0);
304 tree clear_parent = build2 (MODIFY_EXPR, void_type_node, parent,
305 build_int_cst (TREE_TYPE (parent), 0));
306 expand_expr (clear_parent, const0_rtx, VOIDmode, EXPAND_NORMAL);
308 /* During LTO, the is_cilk_function flag gets cleared.
309 If __cilkrts_pop_frame is called, then this definitely must be a
310 cilk function. */
311 if (cfun)
312 cfun->is_cilk_function = 1;
315 /* Expands the cilk_detach function call stored in EXP. */
317 void
318 expand_builtin_cilk_detach (tree exp)
320 rtx insn;
321 tree fptr = get_frame_arg (exp);
323 if (fptr == NULL_TREE)
324 return;
326 tree parent = cilk_dot (fptr, CILK_TI_FRAME_PARENT, 0);
327 tree worker = cilk_dot (fptr, CILK_TI_FRAME_WORKER, 0);
328 tree tail = cilk_arrow (worker, CILK_TI_WORKER_TAIL, 1);
330 rtx wreg = expand_expr (worker, NULL_RTX, Pmode, EXPAND_NORMAL);
331 if (GET_CODE (wreg) != REG)
332 wreg = copy_to_reg (wreg);
333 rtx preg = expand_expr (parent, NULL_RTX, Pmode, EXPAND_NORMAL);
335 /* TMP <- WORKER.TAIL
336 *TMP <- PARENT
337 TMP <- TMP + 1
338 WORKER.TAIL <- TMP */
340 HOST_WIDE_INT worker_tail_offset =
341 tree_to_shwi (DECL_FIELD_OFFSET (cilk_trees[CILK_TI_WORKER_TAIL])) +
342 tree_to_shwi (DECL_FIELD_BIT_OFFSET (cilk_trees[CILK_TI_WORKER_TAIL])) /
343 BITS_PER_UNIT;
344 rtx tmem0 = gen_rtx_MEM (Pmode,
345 plus_constant (Pmode, wreg, worker_tail_offset));
346 set_mem_attributes (tmem0, tail, 0);
347 MEM_NOTRAP_P (tmem0) = 1;
348 gcc_assert (MEM_VOLATILE_P (tmem0));
349 rtx treg = copy_to_mode_reg (Pmode, tmem0);
350 rtx tmem1 = gen_rtx_MEM (Pmode, treg);
351 set_mem_attributes (tmem1, TREE_TYPE (TREE_TYPE (tail)), 0);
352 MEM_NOTRAP_P (tmem1) = 1;
353 emit_move_insn (tmem1, preg);
354 emit_move_insn (treg, plus_constant (Pmode, treg, GET_MODE_SIZE (Pmode)));
356 /* There is a release barrier (st8.rel, membar #StoreStore,
357 sfence, lwsync, etc.) between the two stores. On x86
358 normal volatile stores have proper semantics; the sfence
359 would only be needed for nontemporal stores (which we
360 could generate using the storent optab, for no benefit
361 in this case).
363 The predicate may return false even for a REG if this is
364 the limited release operation that only stores 0. */
365 enum insn_code icode = direct_optab_handler (sync_lock_release_optab, Pmode);
366 if (icode != CODE_FOR_nothing
367 && insn_data[icode].operand[1].predicate (treg, Pmode)
368 && (insn = GEN_FCN (icode) (tmem0, treg)) != NULL_RTX)
369 emit_insn (insn);
370 else
371 emit_move_insn (tmem0, treg);
373 /* The memory barrier inserted above should not prevent
374 the load of flags from being moved before the stores,
375 but in practice it does because it is implemented with
376 unspec_volatile. In-order RISC machines should
377 explicitly load flags earlier. */
379 tree flags = cilk_dot (fptr, CILK_TI_FRAME_FLAGS, 0);
380 expand_expr (build2 (MODIFY_EXPR, void_type_node, flags,
381 build2 (BIT_IOR_EXPR, TREE_TYPE (flags), flags,
382 build_int_cst (TREE_TYPE (flags),
383 CILK_FRAME_DETACHED))),
384 const0_rtx, VOIDmode, EXPAND_NORMAL);
387 /* Returns a setjmp CALL_EXPR with FRAME->context as its parameter. */
389 tree
390 cilk_call_setjmp (tree frame)
392 tree c = cilk_dot (frame, CILK_TI_FRAME_CONTEXT, false);
393 c = build1 (ADDR_EXPR, build_pointer_type (ptr_type_node), c);
394 return build_call_expr (builtin_decl_implicit (BUILT_IN_SETJMP), 1, c);
397 /* This function will expand the _Cilk_sync keyword. */
399 static tree
400 expand_cilk_sync (void)
402 tree frame = cfun->cilk_frame_decl;
404 /* Cilk_sync is converted to the following code:
406 sf.pedigree = sf.worker->pedigree;
407 if (frame.flags & CILK_FRAME_UNSYNCHED)
409 __cilkrts_save_fp_state (&sf);
410 if (!builtin_setjmp (sf.ctx)
411 __cilkrts_sync (&sf);
412 else
413 if (sf.flags & CILK_FRAME_EXCEPTING)
414 __cilkrts_rethrow (&sf);
416 sf.worker->pedigree.rank = sf.worker->pedigree.rank + 1; */
418 tree flags = cilk_dot (frame, CILK_TI_FRAME_FLAGS, false);
420 tree unsynched = fold_build2 (BIT_AND_EXPR, TREE_TYPE (flags), flags,
421 build_int_cst (TREE_TYPE (flags),
422 CILK_FRAME_UNSYNCHED));
424 unsynched = fold_build2 (NE_EXPR, TREE_TYPE (unsynched), unsynched,
425 build_int_cst (TREE_TYPE (unsynched), 0));
427 tree frame_addr = build1 (ADDR_EXPR, cilk_frame_ptr_type_decl, frame);
429 /* Check if exception (0x10) bit is set in the sf->flags. */
430 tree except_flag = fold_build2 (BIT_AND_EXPR, TREE_TYPE (flags), flags,
431 build_int_cst (TREE_TYPE (flags),
432 CILK_FRAME_EXCEPTING));
433 except_flag = fold_build2 (NE_EXPR, TREE_TYPE (except_flag), except_flag,
434 build_int_cst (TREE_TYPE (except_flag), 0));
436 /* If the exception flag is set then call the __cilkrts_rethrow (&sf). */
437 tree except_cond = fold_build3 (COND_EXPR, void_type_node, except_flag,
438 build_call_expr (cilk_rethrow_fndecl, 1,
439 frame_addr),
440 build_empty_stmt (EXPR_LOCATION (unsynched)));
442 tree sync_expr = build_call_expr (cilk_sync_fndecl, 1, frame_addr);
443 tree setjmp_expr = cilk_call_setjmp (frame);
444 setjmp_expr = fold_build2 (EQ_EXPR, TREE_TYPE (setjmp_expr), setjmp_expr,
445 build_int_cst (TREE_TYPE (setjmp_expr), 0));
447 setjmp_expr = fold_build3 (COND_EXPR, void_type_node, setjmp_expr,
448 sync_expr, except_cond);
449 tree sync_list = alloc_stmt_list ();
450 append_to_statement_list (build_call_expr (cilk_save_fp_fndecl, 1,
451 frame_addr), &sync_list);
452 append_to_statement_list (setjmp_expr, &sync_list);
453 tree sync = fold_build3 (COND_EXPR, void_type_node, unsynched, sync_list,
454 build_empty_stmt (EXPR_LOCATION (unsynched)));
455 tree parent_pedigree = cilk_dot (frame, CILK_TI_FRAME_PEDIGREE, false);
456 tree worker = cilk_dot (frame, CILK_TI_FRAME_WORKER, false);
457 tree worker_pedigree = cilk_arrow (worker, CILK_TI_WORKER_PEDIGREE, false);
458 tree assign_pedigree = fold_build2 (MODIFY_EXPR, void_type_node,
459 parent_pedigree, worker_pedigree);
460 tree w_ped_rank = cilk_dot (unshare_expr (worker_pedigree),
461 CILK_TI_PEDIGREE_RANK, false);
462 tree incr_ped_rank = fold_build2 (PLUS_EXPR, TREE_TYPE (w_ped_rank),
463 w_ped_rank,
464 build_one_cst (TREE_TYPE (w_ped_rank)));
465 incr_ped_rank = fold_build2 (MODIFY_EXPR, void_type_node, w_ped_rank,
466 incr_ped_rank);
467 tree ret_sync_exp = alloc_stmt_list ();
468 append_to_statement_list (assign_pedigree, &ret_sync_exp);
469 append_to_statement_list (sync, &ret_sync_exp);
470 append_to_statement_list (incr_ped_rank, &ret_sync_exp);
471 return ret_sync_exp;
474 /* Gimplifies the cilk_sync expression passed in *EXPR_P. Returns GS_ALL_DONE
475 when finished. */
477 void
478 gimplify_cilk_sync (tree *expr_p, gimple_seq *pre_p)
480 tree sync_expr = expand_cilk_sync ();
481 *expr_p = NULL_TREE;
482 gimplify_and_add (sync_expr, pre_p);