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