2015-09-29 Steven G. Kargl <kargl@gcc.gnu.org>
[official-gcc.git] / gcc / cilk-common.c
blob62acc186d31803a3bd73d6565f593b4dc9db96ea
1 /* This file is part of the Intel(R) Cilk(TM) Plus support
2 This file contains the CilkPlus Intrinsics
3 Copyright (C) 2013-2015 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 "alias.h"
27 #include "tree.h"
28 #include "options.h"
29 #include "fold-const.h"
30 #include "stringpool.h"
31 #include "stor-layout.h"
32 #include "langhooks.h"
33 #include "tm.h"
34 #include "rtl.h"
35 #include "function.h"
36 #include "flags.h"
37 #include "insn-config.h"
38 #include "expmed.h"
39 #include "dojump.h"
40 #include "explow.h"
41 #include "calls.h"
42 #include "emit-rtl.h"
43 #include "varasm.h"
44 #include "stmt.h"
45 #include "expr.h"
46 #include "insn-codes.h"
47 #include "optabs-query.h"
48 #include "recog.h"
49 #include "tree-iterator.h"
50 #include "gimplify.h"
51 #include "cilk.h"
53 /* This structure holds all the important fields of the internal structures,
54 internal built-in functions, and Cilk-specific data types. Explanation of
55 all the these fielsd are given in cilk.h. */
56 tree cilk_trees[(int) CILK_TI_MAX];
58 /* Returns the value in structure FRAME pointed by the FIELD_NUMBER
59 (e.g. X.y).
60 FIELD_NUMBER is an index to the structure FRAME_PTR. For details
61 about these fields, refer to cilk_trees structure in cilk.h and
62 cilk_init_builtins function in this file. Returns a TREE that is the type
63 of the field represented by FIELD_NUMBER. If VOLATIL parameter is set
64 to true then the returning field is set as volatile. */
66 tree
67 cilk_dot (tree frame, int field_number, bool volatil)
69 tree field = cilk_trees[field_number];
70 field = fold_build3 (COMPONENT_REF, TREE_TYPE (field), frame, field,
71 NULL_TREE);
72 TREE_THIS_VOLATILE (field) = volatil;
73 return field;
76 /* Returns the address of a field in FRAME_PTR, pointed by FIELD_NUMBER.
77 (e.g. (&X)->y). Please see cilk_dot function for explanation of the
78 FIELD_NUMBER. Returns a tree that is the type of the field represented
79 by FIELD_NUMBER. If VOLATIL parameter is set to true then the returning
80 field is set as volatile. */
82 tree
83 cilk_arrow (tree frame_ptr, int field_number, bool volatil)
85 return cilk_dot (build_simple_mem_ref (frame_ptr),
86 field_number, volatil);
90 /* This function will add FIELD of type TYPE to a defined built-in
91 structure. *NAME is the name of the field to be added. */
93 static tree
94 add_field (const char *name, tree type, tree fields)
96 tree t = get_identifier (name);
97 tree field = build_decl (BUILTINS_LOCATION, FIELD_DECL, t, type);
98 TREE_CHAIN (field) = fields;
99 return field;
102 /* This function will define a built-in function of NAME, of type FNTYPE and
103 register it under the built-in function code CODE. If PUBLISH is set then
104 the declaration is pushed into the declaration list. CODE is the index
105 to the cilk_trees array. *NAME is the name of the function to be added. */
107 static tree
108 install_builtin (const char *name, tree fntype, enum built_in_function code,
109 bool publish)
111 tree fndecl = build_fn_decl (name, fntype);
112 DECL_BUILT_IN_CLASS (fndecl) = BUILT_IN_NORMAL;
113 DECL_FUNCTION_CODE (fndecl) = code;
114 if (publish)
116 tree t = lang_hooks.decls.pushdecl (fndecl);
117 if (t)
118 fndecl = t;
120 set_builtin_decl (code, fndecl, true);
121 return fndecl;
124 /* Returns a FUNCTION_DECL of type TYPE whose name is *NAME. */
126 static tree
127 declare_cilk_for_builtin (const char *name, tree type,
128 enum built_in_function code)
130 tree cb, ft, fn;
132 cb = build_function_type_list (void_type_node,
133 ptr_type_node, type, type,
134 NULL_TREE);
135 cb = build_pointer_type (cb);
136 ft = build_function_type_list (void_type_node,
137 cb, ptr_type_node, type,
138 integer_type_node, NULL_TREE);
139 fn = install_builtin (name, ft, code, false);
140 TREE_NOTHROW (fn) = 0;
142 return fn;
145 /* Creates and initializes all the built-in Cilk keywords functions and three
146 structures: __cilkrts_stack_frame, __cilkrts_pedigree and __cilkrts_worker.
147 Detailed information about __cilkrts_stack_frame and
148 __cilkrts_worker structures are given in libcilkrts/include/internal/abi.h.
149 __cilkrts_pedigree is described in libcilkrts/include/cilk/common.h. */
151 void
152 cilk_init_builtins (void)
154 /* Now build the following __cilkrts_pedigree struct:
155 struct __cilkrts_pedigree {
156 uint64_t rank;
157 struct __cilkrts_pedigree *parent;
158 } */
160 tree pedigree_type = lang_hooks.types.make_type (RECORD_TYPE);
161 tree pedigree_ptr = build_pointer_type (pedigree_type);
162 tree field = add_field ("rank", uint64_type_node, NULL_TREE);
163 cilk_trees[CILK_TI_PEDIGREE_RANK] = field;
164 field = add_field ("parent", pedigree_ptr, field);
165 cilk_trees[CILK_TI_PEDIGREE_PARENT] = field;
166 finish_builtin_struct (pedigree_type, "__cilkrts_pedigree_GCC", field,
167 NULL_TREE);
168 lang_hooks.types.register_builtin_type (pedigree_type,
169 "__cilkrts_pedigree_t");
170 cilk_pedigree_type_decl = pedigree_type;
172 /* Build the Cilk Stack Frame:
173 struct __cilkrts_stack_frame {
174 uint32_t flags;
175 uint32_t size;
176 struct __cilkrts_stack_frame *call_parent;
177 __cilkrts_worker *worker;
178 void *except_data;
179 void *ctx[4];
180 uint32_t mxcsr;
181 uint16_t fpcsr;
182 uint16_t reserved;
183 __cilkrts_pedigree pedigree;
184 }; */
186 tree frame = lang_hooks.types.make_type (RECORD_TYPE);
187 tree frame_ptr = build_pointer_type (frame);
188 tree worker_type = lang_hooks.types.make_type (RECORD_TYPE);
189 tree worker_ptr = build_pointer_type (worker_type);
190 tree s_type_node = build_int_cst (size_type_node, 4);
192 tree flags = add_field ("flags", uint32_type_node, NULL_TREE);
193 tree size = add_field ("size", uint32_type_node, flags);
194 tree parent = add_field ("call_parent", frame_ptr, size);
195 tree worker = add_field ("worker", worker_ptr, parent);
196 tree except = add_field ("except_data", frame_ptr, worker);
197 tree context = add_field ("ctx",
198 build_array_type (ptr_type_node,
199 build_index_type (s_type_node)),
200 except);
201 tree mxcsr = add_field ("mxcsr", uint32_type_node, context);
202 tree fpcsr = add_field ("fpcsr", uint16_type_node, mxcsr);
203 tree reserved = add_field ("reserved", uint16_type_node, fpcsr);
204 tree pedigree = add_field ("pedigree", pedigree_type, reserved);
206 /* Now add them to a common structure whose fields are #defined to something
207 that is used at a later stage. */
208 cilk_trees[CILK_TI_FRAME_FLAGS] = flags;
209 cilk_trees[CILK_TI_FRAME_PARENT] = parent;
210 cilk_trees[CILK_TI_FRAME_WORKER] = worker;
211 cilk_trees[CILK_TI_FRAME_EXCEPTION] = except;
212 cilk_trees[CILK_TI_FRAME_CONTEXT] = context;
213 /* We don't care about reserved, so no need to store it in cilk_trees. */
214 cilk_trees[CILK_TI_FRAME_PEDIGREE] = pedigree;
215 TREE_ADDRESSABLE (frame) = 1;
217 finish_builtin_struct (frame, "__cilkrts_st_frame_GCC", pedigree, NULL_TREE);
218 cilk_frame_type_decl = frame;
219 lang_hooks.types.register_builtin_type (frame, "__cilkrts_frame_t");
221 cilk_frame_ptr_type_decl = build_qualified_type (frame_ptr,
222 TYPE_QUAL_VOLATILE);
223 /* Now let's do the following worker struct:
225 struct __cilkrts_worker {
226 __cilkrts_stack_frame *volatile *volatile tail;
227 __cilkrts_stack_frame *volatile *volatile head;
228 __cilkrts_stack_frame *volatile *volatile exc;
229 __cilkrts_stack_frame *volatile *volatile protected_tail;
230 __cilkrts_stack_frame *volatile *ltq_limit;
231 int32_t self;
232 global_state_t *g;
233 local_state *l;
234 cilkred_map *reducer_map;
235 __cilkrts_stack_frame *current_stack_frame;
236 void *reserved;
237 __cilkrts_worker_sysdep_state *sysdep;
238 __cilkrts_pedigree pedigree;
239 } */
241 tree fptr_volatil_type = build_qualified_type (frame_ptr, TYPE_QUAL_VOLATILE);
242 tree fptr_volatile_ptr = build_pointer_type (fptr_volatil_type);
243 tree fptr_vol_ptr_vol = build_qualified_type (fptr_volatile_ptr,
244 TYPE_QUAL_VOLATILE);
245 tree g = lang_hooks.types.make_type (RECORD_TYPE);
246 finish_builtin_struct (g, "__cilkrts_global_state", NULL_TREE, NULL_TREE);
247 tree l = lang_hooks.types.make_type (RECORD_TYPE);
248 finish_builtin_struct (l, "__cilkrts_local_state", NULL_TREE, NULL_TREE);
249 tree sysdep_t = lang_hooks.types.make_type (RECORD_TYPE);
250 finish_builtin_struct (sysdep_t, "__cilkrts_worker_sysdep_state", NULL_TREE,
251 NULL_TREE);
253 field = add_field ("tail", fptr_vol_ptr_vol, NULL_TREE);
254 cilk_trees[CILK_TI_WORKER_TAIL] = field;
255 field = add_field ("head", fptr_vol_ptr_vol, field);
256 field = add_field ("exc", fptr_vol_ptr_vol, field);
257 field = add_field ("protected_tail", fptr_vol_ptr_vol, field);
258 field = add_field ("ltq_limit", fptr_volatile_ptr, field);
259 field = add_field ("self", integer_type_node, field);
260 field = add_field ("g", build_pointer_type (g), field);
261 field = add_field ("l", build_pointer_type (g), field);
262 field = add_field ("reducer_map", ptr_type_node, field);
263 field = add_field ("current_stack_frame", frame_ptr, field);
264 cilk_trees[CILK_TI_WORKER_CUR] = field;
265 field = add_field ("saved_protected_tail", fptr_volatile_ptr, field);
266 field = add_field ("sysdep", build_pointer_type (sysdep_t), field);
267 field = add_field ("pedigree", pedigree_type, field);
268 cilk_trees[CILK_TI_WORKER_PEDIGREE] = field;
269 finish_builtin_struct (worker_type, "__cilkrts_worker_GCC", field,
270 NULL_TREE);
272 tree fptr_arglist = tree_cons (NULL_TREE, frame_ptr, void_list_node);
273 tree fptr_fun = build_function_type (void_type_node, fptr_arglist);
275 /* void __cilkrts_enter_frame_1 (__cilkrts_stack_frame *); */
276 cilk_enter_fndecl = install_builtin ("__cilkrts_enter_frame_1", fptr_fun,
277 BUILT_IN_CILK_ENTER_FRAME, false);
279 /* void __cilkrts_enter_frame_fast_1 (__cilkrts_stack_frame *); */
280 cilk_enter_fast_fndecl =
281 install_builtin ("__cilkrts_enter_frame_fast_1", fptr_fun,
282 BUILT_IN_CILK_ENTER_FRAME_FAST, false);
284 /* void __cilkrts_pop_frame (__cilkrts_stack_frame *); */
285 cilk_pop_fndecl = install_builtin ("__cilkrts_pop_frame", fptr_fun,
286 BUILT_IN_CILK_POP_FRAME, false);
288 /* void __cilkrts_leave_frame (__cilkrts_stack_frame *); */
289 cilk_leave_fndecl = install_builtin ("__cilkrts_leave_frame", fptr_fun,
290 BUILT_IN_CILK_LEAVE_FRAME, false);
292 /* void __cilkrts_sync (__cilkrts_stack_frame *); */
293 cilk_sync_fndecl = install_builtin ("__cilkrts_sync", fptr_fun,
294 BUILT_IN_CILK_SYNC, false);
296 /* void __cilkrts_detach (__cilkrts_stack_frame *); */
297 cilk_detach_fndecl = install_builtin ("__cilkrts_detach", fptr_fun,
298 BUILT_IN_CILK_DETACH, false);
300 /* __cilkrts_rethrow (struct stack_frame *); */
301 cilk_rethrow_fndecl = install_builtin ("__cilkrts_rethrow", fptr_fun,
302 BUILT_IN_CILK_RETHROW, false);
303 TREE_NOTHROW (cilk_rethrow_fndecl) = 0;
305 /* __cilkrts_save_fp_ctrl_state (__cilkrts_stack_frame *); */
306 cilk_save_fp_fndecl = install_builtin ("__cilkrts_save_fp_ctrl_state",
307 fptr_fun, BUILT_IN_CILK_SAVE_FP,
308 false);
309 /* __cilkrts_cilk_for_32 (...); */
310 cilk_for_32_fndecl = declare_cilk_for_builtin ("__cilkrts_cilk_for_32",
311 unsigned_intSI_type_node,
312 BUILT_IN_CILK_FOR_32);
313 /* __cilkrts_cilk_for_64 (...); */
314 cilk_for_64_fndecl = declare_cilk_for_builtin ("__cilkrts_cilk_for_64",
315 unsigned_intDI_type_node,
316 BUILT_IN_CILK_FOR_64);
319 /* Get the appropriate frame arguments for CALL that is of type CALL_EXPR. */
321 static tree
322 get_frame_arg (tree call)
324 tree arg, argtype;
326 gcc_assert (call_expr_nargs (call) >= 1);
328 arg = CALL_EXPR_ARG (call, 0);
329 argtype = TREE_TYPE (arg);
330 gcc_assert (TREE_CODE (argtype) == POINTER_TYPE);
332 argtype = TREE_TYPE (argtype);
334 /* If it is passed in as an address, then just use the value directly
335 since the function is inlined. */
336 if (TREE_CODE (arg) == ADDR_EXPR)
337 return TREE_OPERAND (arg, 0);
338 return arg;
341 /* Expands the __cilkrts_pop_frame function call stored in EXP. */
343 void
344 expand_builtin_cilk_pop_frame (tree exp)
346 tree frame = get_frame_arg (exp);
347 tree parent = cilk_dot (frame, CILK_TI_FRAME_PARENT, 0);
349 tree clear_parent = build2 (MODIFY_EXPR, void_type_node, parent,
350 build_int_cst (TREE_TYPE (parent), 0));
351 expand_expr (clear_parent, const0_rtx, VOIDmode, EXPAND_NORMAL);
353 /* During LTO, the is_cilk_function flag gets cleared.
354 If __cilkrts_pop_frame is called, then this definitely must be a
355 cilk function. */
356 if (cfun)
357 cfun->is_cilk_function = 1;
360 /* Expands the cilk_detach function call stored in EXP. */
362 void
363 expand_builtin_cilk_detach (tree exp)
365 rtx_insn *insn;
366 tree fptr = get_frame_arg (exp);
368 if (fptr == NULL_TREE)
369 return;
371 tree parent = cilk_dot (fptr, CILK_TI_FRAME_PARENT, 0);
372 tree worker = cilk_dot (fptr, CILK_TI_FRAME_WORKER, 0);
373 tree tail = cilk_arrow (worker, CILK_TI_WORKER_TAIL, 1);
375 rtx wreg = expand_expr (worker, NULL_RTX, Pmode, EXPAND_NORMAL);
376 if (GET_CODE (wreg) != REG)
377 wreg = copy_to_reg (wreg);
378 rtx preg = expand_expr (parent, NULL_RTX, Pmode, EXPAND_NORMAL);
380 /* TMP <- WORKER.TAIL
381 *TMP <- PARENT
382 TMP <- TMP + 1
383 WORKER.TAIL <- TMP */
385 HOST_WIDE_INT worker_tail_offset =
386 tree_to_shwi (DECL_FIELD_OFFSET (cilk_trees[CILK_TI_WORKER_TAIL])) +
387 tree_to_shwi (DECL_FIELD_BIT_OFFSET (cilk_trees[CILK_TI_WORKER_TAIL])) /
388 BITS_PER_UNIT;
389 rtx tmem0 = gen_rtx_MEM (Pmode,
390 plus_constant (Pmode, wreg, worker_tail_offset));
391 set_mem_attributes (tmem0, tail, 0);
392 MEM_NOTRAP_P (tmem0) = 1;
393 gcc_assert (MEM_VOLATILE_P (tmem0));
394 rtx treg = copy_to_mode_reg (Pmode, tmem0);
395 rtx tmem1 = gen_rtx_MEM (Pmode, treg);
396 set_mem_attributes (tmem1, TREE_TYPE (TREE_TYPE (tail)), 0);
397 MEM_NOTRAP_P (tmem1) = 1;
398 emit_move_insn (tmem1, preg);
399 emit_move_insn (treg, plus_constant (Pmode, treg, GET_MODE_SIZE (Pmode)));
401 /* There is a release barrier (st8.rel, membar #StoreStore,
402 sfence, lwsync, etc.) between the two stores. On x86
403 normal volatile stores have proper semantics; the sfence
404 would only be needed for nontemporal stores (which we
405 could generate using the storent optab, for no benefit
406 in this case).
408 The predicate may return false even for a REG if this is
409 the limited release operation that only stores 0. */
410 enum insn_code icode = direct_optab_handler (sync_lock_release_optab, Pmode);
411 if (icode != CODE_FOR_nothing
412 && insn_data[icode].operand[1].predicate (treg, Pmode)
413 && (insn = GEN_FCN (icode) (tmem0, treg)) != NULL_RTX)
414 emit_insn (insn);
415 else
416 emit_move_insn (tmem0, treg);
418 /* The memory barrier inserted above should not prevent
419 the load of flags from being moved before the stores,
420 but in practice it does because it is implemented with
421 unspec_volatile. In-order RISC machines should
422 explicitly load flags earlier. */
424 tree flags = cilk_dot (fptr, CILK_TI_FRAME_FLAGS, 0);
425 expand_expr (build2 (MODIFY_EXPR, void_type_node, flags,
426 build2 (BIT_IOR_EXPR, TREE_TYPE (flags), flags,
427 build_int_cst (TREE_TYPE (flags),
428 CILK_FRAME_DETACHED))),
429 const0_rtx, VOIDmode, EXPAND_NORMAL);
432 /* Returns a setjmp CALL_EXPR with FRAME->context as its parameter. */
434 tree
435 cilk_call_setjmp (tree frame)
437 tree c = cilk_dot (frame, CILK_TI_FRAME_CONTEXT, false);
438 c = build1 (ADDR_EXPR, build_pointer_type (ptr_type_node), c);
439 return build_call_expr (builtin_decl_implicit (BUILT_IN_SETJMP), 1, c);
442 /* This function will expand the _Cilk_sync keyword. */
444 static tree
445 expand_cilk_sync (void)
447 tree frame = cfun->cilk_frame_decl;
449 /* Cilk_sync is converted to the following code:
451 sf.pedigree = sf.worker->pedigree;
452 if (frame.flags & CILK_FRAME_UNSYNCHED)
454 __cilkrts_save_fp_state (&sf);
455 if (!builtin_setjmp (sf.ctx)
456 __cilkrts_sync (&sf);
457 else
458 if (sf.flags & CILK_FRAME_EXCEPTING)
459 __cilkrts_rethrow (&sf);
461 sf.worker->pedigree.rank = sf.worker->pedigree.rank + 1; */
463 tree flags = cilk_dot (frame, CILK_TI_FRAME_FLAGS, false);
465 tree unsynched = fold_build2 (BIT_AND_EXPR, TREE_TYPE (flags), flags,
466 build_int_cst (TREE_TYPE (flags),
467 CILK_FRAME_UNSYNCHED));
469 unsynched = fold_build2 (NE_EXPR, TREE_TYPE (unsynched), unsynched,
470 build_int_cst (TREE_TYPE (unsynched), 0));
472 tree frame_addr = build1 (ADDR_EXPR, cilk_frame_ptr_type_decl, frame);
474 /* Check if exception (0x10) bit is set in the sf->flags. */
475 tree except_flag = fold_build2 (BIT_AND_EXPR, TREE_TYPE (flags), flags,
476 build_int_cst (TREE_TYPE (flags),
477 CILK_FRAME_EXCEPTING));
478 except_flag = fold_build2 (NE_EXPR, TREE_TYPE (except_flag), except_flag,
479 build_int_cst (TREE_TYPE (except_flag), 0));
481 /* If the exception flag is set then call the __cilkrts_rethrow (&sf). */
482 tree except_cond = fold_build3 (COND_EXPR, void_type_node, except_flag,
483 build_call_expr (cilk_rethrow_fndecl, 1,
484 frame_addr),
485 build_empty_stmt (EXPR_LOCATION (unsynched)));
487 tree sync_expr = build_call_expr (cilk_sync_fndecl, 1, frame_addr);
488 tree setjmp_expr = cilk_call_setjmp (frame);
489 setjmp_expr = fold_build2 (EQ_EXPR, TREE_TYPE (setjmp_expr), setjmp_expr,
490 build_int_cst (TREE_TYPE (setjmp_expr), 0));
492 setjmp_expr = fold_build3 (COND_EXPR, void_type_node, setjmp_expr,
493 sync_expr, except_cond);
494 tree sync_list = alloc_stmt_list ();
495 append_to_statement_list (build_call_expr (cilk_save_fp_fndecl, 1,
496 frame_addr), &sync_list);
497 append_to_statement_list (setjmp_expr, &sync_list);
498 tree sync = fold_build3 (COND_EXPR, void_type_node, unsynched, sync_list,
499 build_empty_stmt (EXPR_LOCATION (unsynched)));
500 tree parent_pedigree = cilk_dot (frame, CILK_TI_FRAME_PEDIGREE, false);
501 tree worker = cilk_dot (frame, CILK_TI_FRAME_WORKER, false);
502 tree worker_pedigree = cilk_arrow (worker, CILK_TI_WORKER_PEDIGREE, false);
503 tree assign_pedigree = fold_build2 (MODIFY_EXPR, void_type_node,
504 parent_pedigree, worker_pedigree);
505 tree w_ped_rank = cilk_dot (unshare_expr (worker_pedigree),
506 CILK_TI_PEDIGREE_RANK, false);
507 tree incr_ped_rank = fold_build2 (PLUS_EXPR, TREE_TYPE (w_ped_rank),
508 w_ped_rank,
509 build_one_cst (TREE_TYPE (w_ped_rank)));
510 incr_ped_rank = fold_build2 (MODIFY_EXPR, void_type_node, w_ped_rank,
511 incr_ped_rank);
512 tree ret_sync_exp = alloc_stmt_list ();
513 append_to_statement_list (assign_pedigree, &ret_sync_exp);
514 append_to_statement_list (sync, &ret_sync_exp);
515 append_to_statement_list (incr_ped_rank, &ret_sync_exp);
516 return ret_sync_exp;
519 /* Gimplifies the cilk_sync expression passed in *EXPR_P. Returns GS_ALL_DONE
520 when finished. */
522 void
523 gimplify_cilk_sync (tree *expr_p, gimple_seq *pre_p)
525 tree sync_expr = expand_cilk_sync ();
526 *expr_p = NULL_TREE;
527 gimplify_and_add (sync_expr, pre_p);