Reverting merge from trunk
[official-gcc.git] / gcc / cilk-common.c
blob8e070a3a32dd18fbc6579eea7b2e324d984c653e
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 "langhooks.h"
28 #include "expr.h"
29 #include "optabs.h"
30 #include "recog.h"
31 #include "tree-iterator.h"
32 #include "gimple.h"
33 #include "gimplify.h"
34 #include "cilk.h"
36 /* This structure holds all the important fields of the internal structures,
37 internal built-in functions, and Cilk-specific data types. Explanation of
38 all the these fielsd are given in cilk.h. */
39 tree cilk_trees[(int) CILK_TI_MAX];
41 /* Returns the value in structure FRAME pointed by the FIELD_NUMBER
42 (e.g. X.y).
43 FIELD_NUMBER is an index to the structure FRAME_PTR. For details
44 about these fields, refer to cilk_trees structure in cilk.h and
45 cilk_init_builtins function in this file. Returns a TREE that is the type
46 of the field represented by FIELD_NUMBER. If VOLATIL parameter is set
47 to true then the returning field is set as volatile. */
49 tree
50 cilk_dot (tree frame, int field_number, bool volatil)
52 tree field = cilk_trees[field_number];
53 field = fold_build3 (COMPONENT_REF, TREE_TYPE (field), frame, field,
54 NULL_TREE);
55 TREE_THIS_VOLATILE (field) = volatil;
56 return field;
59 /* Returns the address of a field in FRAME_PTR, pointed by FIELD_NUMBER.
60 (e.g. (&X)->y). Please see cilk_dot function for explanation of the
61 FIELD_NUMBER. Returns a tree that is the type of the field represented
62 by FIELD_NUMBER. If VOLATIL parameter is set to true then the returning
63 field is set as volatile. */
65 tree
66 cilk_arrow (tree frame_ptr, int field_number, bool volatil)
68 return cilk_dot (fold_build1 (INDIRECT_REF,
69 TREE_TYPE (TREE_TYPE (frame_ptr)), 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);
267 /* __cilkrts_save_fp_ctrl_state (__cilkrts_stack_frame *); */
268 cilk_save_fp_fndecl = install_builtin ("__cilkrts_save_fp_ctrl_state",
269 fptr_fun, BUILT_IN_CILK_SAVE_FP,
270 false);
273 /* Get the appropriate frame arguments for CALL that is of type CALL_EXPR. */
275 static tree
276 get_frame_arg (tree call)
278 tree arg, argtype;
280 gcc_assert (call_expr_nargs (call) >= 1);
282 arg = CALL_EXPR_ARG (call, 0);
283 argtype = TREE_TYPE (arg);
284 gcc_assert (TREE_CODE (argtype) == POINTER_TYPE);
286 argtype = TREE_TYPE (argtype);
288 gcc_assert (!lang_hooks.types_compatible_p
289 || lang_hooks.types_compatible_p (argtype, cilk_frame_type_decl));
291 /* If it is passed in as an address, then just use the value directly
292 since the function is inlined. */
293 if (TREE_CODE (arg) == INDIRECT_REF || TREE_CODE (arg) == ADDR_EXPR)
294 return TREE_OPERAND (arg, 0);
295 return arg;
298 /* Expands the __cilkrts_pop_frame function call stored in EXP. */
300 void
301 expand_builtin_cilk_pop_frame (tree exp)
303 tree frame = get_frame_arg (exp);
304 tree parent = cilk_dot (frame, CILK_TI_FRAME_PARENT, 0);
306 tree clear_parent = build2 (MODIFY_EXPR, void_type_node, parent,
307 build_int_cst (TREE_TYPE (parent), 0));
308 expand_expr (clear_parent, const0_rtx, VOIDmode, EXPAND_NORMAL);
310 /* During LTO, the is_cilk_function flag gets cleared.
311 If __cilkrts_pop_frame is called, then this definitely must be a
312 cilk function. */
313 if (cfun)
314 cfun->is_cilk_function = 1;
317 /* Expands the cilk_detach function call stored in EXP. */
319 void
320 expand_builtin_cilk_detach (tree exp)
322 rtx insn;
323 tree fptr = get_frame_arg (exp);
325 if (fptr == NULL_TREE)
326 return;
328 tree parent = cilk_dot (fptr, CILK_TI_FRAME_PARENT, 0);
329 tree worker = cilk_dot (fptr, CILK_TI_FRAME_WORKER, 0);
330 tree tail = cilk_dot (worker, CILK_TI_WORKER_TAIL, 1);
332 rtx wreg = expand_expr (worker, NULL_RTX, Pmode, EXPAND_NORMAL);
333 if (GET_CODE (wreg) != REG)
334 wreg = copy_to_reg (wreg);
335 rtx preg = expand_expr (parent, NULL_RTX, Pmode, EXPAND_NORMAL);
337 /* TMP <- WORKER.TAIL
338 *TMP <- PARENT
339 TMP <- TMP + 1
340 WORKER.TAIL <- TMP */
342 HOST_WIDE_INT worker_tail_offset =
343 tree_low_cst (DECL_FIELD_OFFSET (cilk_trees[CILK_TI_WORKER_TAIL]), 0) +
344 tree_low_cst (DECL_FIELD_BIT_OFFSET (cilk_trees[CILK_TI_WORKER_TAIL]), 0) /
345 BITS_PER_UNIT;
346 rtx tmem0 = gen_rtx_MEM (Pmode,
347 plus_constant (Pmode, wreg, worker_tail_offset));
348 set_mem_attributes (tmem0, tail, 0);
349 MEM_NOTRAP_P (tmem0) = 1;
350 gcc_assert (MEM_VOLATILE_P (tmem0));
351 rtx treg = copy_to_mode_reg (Pmode, tmem0);
352 rtx tmem1 = gen_rtx_MEM (Pmode, treg);
353 set_mem_attributes (tmem1, TREE_TYPE (TREE_TYPE (tail)), 0);
354 MEM_NOTRAP_P (tmem1) = 1;
355 emit_move_insn (tmem1, preg);
356 emit_move_insn (treg, plus_constant (Pmode, treg, GET_MODE_SIZE (Pmode)));
358 /* There is a release barrier (st8.rel, membar #StoreStore,
359 sfence, lwsync, etc.) between the two stores. On x86
360 normal volatile stores have proper semantics; the sfence
361 would only be needed for nontemporal stores (which we
362 could generate using the storent optab, for no benefit
363 in this case).
365 The predicate may return false even for a REG if this is
366 the limited release operation that only stores 0. */
367 enum insn_code icode = direct_optab_handler (sync_lock_release_optab, Pmode);
368 if (icode != CODE_FOR_nothing
369 && insn_data[icode].operand[1].predicate (treg, Pmode)
370 && (insn = GEN_FCN (icode) (tmem0, treg)) != NULL_RTX)
371 emit_insn (insn);
372 else
373 emit_move_insn (tmem0, treg);
375 /* The memory barrier inserted above should not prevent
376 the load of flags from being moved before the stores,
377 but in practice it does because it is implemented with
378 unspec_volatile. In-order RISC machines should
379 explicitly load flags earlier. */
381 tree flags = cilk_dot (fptr, CILK_TI_FRAME_FLAGS, 0);
382 expand_expr (build2 (MODIFY_EXPR, void_type_node, flags,
383 build2 (BIT_IOR_EXPR, TREE_TYPE (flags), flags,
384 build_int_cst (TREE_TYPE (flags),
385 CILK_FRAME_DETACHED))),
386 const0_rtx, VOIDmode, EXPAND_NORMAL);
389 /* Returns a setjmp CALL_EXPR with FRAME->context as its parameter. */
391 tree
392 cilk_call_setjmp (tree frame)
394 tree c = cilk_dot (frame, CILK_TI_FRAME_CONTEXT, false);
395 c = build1 (ADDR_EXPR, build_pointer_type (ptr_type_node), c);
396 return build_call_expr (builtin_decl_implicit (BUILT_IN_SETJMP), 1, c);
399 /* This function will expand the _Cilk_sync keyword. */
401 static tree
402 expand_cilk_sync (void)
404 tree frame = cfun->cilk_frame_decl;
406 /* Cilk_sync is converted to the following code:
408 sf.pedigree = sf.worker->pedigree;
409 if (frame.flags & CILK_FRAME_UNSYNCHED)
411 __cilkrts_save_fp_state (&sf);
412 if (!builtin_setjmp (sf.ctx)
413 __cilkrts_sync (&sf);
414 else
415 if (sf.flags & CILK_FRAME_EXCEPTING)
416 __cilkrts_rethrow (&sf);
418 sf.worker->pedigree.rank = sf.worker->pedigree.rank + 1; */
420 tree flags = cilk_dot (frame, CILK_TI_FRAME_FLAGS, false);
422 tree unsynched = fold_build2 (BIT_AND_EXPR, TREE_TYPE (flags), flags,
423 build_int_cst (TREE_TYPE (flags),
424 CILK_FRAME_UNSYNCHED));
426 unsynched = fold_build2 (NE_EXPR, TREE_TYPE (unsynched), unsynched,
427 build_int_cst (TREE_TYPE (unsynched), 0));
429 tree frame_addr = build1 (ADDR_EXPR, cilk_frame_ptr_type_decl, frame);
431 /* Check if exception (0x10) bit is set in the sf->flags. */
432 tree except_flag = fold_build2 (BIT_AND_EXPR, TREE_TYPE (flags), flags,
433 build_int_cst (TREE_TYPE (flags),
434 CILK_FRAME_EXCEPTING));
435 except_flag = fold_build2 (NE_EXPR, TREE_TYPE (except_flag), except_flag,
436 build_int_cst (TREE_TYPE (except_flag), 0));
438 /* If the exception flag is set then call the __cilkrts_rethrow (&sf). */
439 tree except_cond = fold_build3 (COND_EXPR, void_type_node, except_flag,
440 build_call_expr (cilk_rethrow_fndecl, 1,
441 frame_addr),
442 build_empty_stmt (EXPR_LOCATION (unsynched)));
444 tree sync_expr = build_call_expr (cilk_sync_fndecl, 1, frame_addr);
445 tree setjmp_expr = cilk_call_setjmp (frame);
446 setjmp_expr = fold_build2 (EQ_EXPR, TREE_TYPE (setjmp_expr), setjmp_expr,
447 build_int_cst (TREE_TYPE (setjmp_expr), 0));
449 setjmp_expr = fold_build3 (COND_EXPR, void_type_node, setjmp_expr,
450 sync_expr, except_cond);
451 tree sync_list = alloc_stmt_list ();
452 append_to_statement_list (build_call_expr (cilk_save_fp_fndecl, 1,
453 frame_addr), &sync_list);
454 append_to_statement_list (setjmp_expr, &sync_list);
455 tree sync = fold_build3 (COND_EXPR, void_type_node, unsynched, sync_list,
456 build_empty_stmt (EXPR_LOCATION (unsynched)));
457 tree parent_pedigree = cilk_dot (frame, CILK_TI_FRAME_PEDIGREE, false);
458 tree worker = cilk_dot (frame, CILK_TI_FRAME_WORKER, false);
459 tree worker_pedigree = cilk_arrow (worker, CILK_TI_WORKER_PEDIGREE, false);
460 tree assign_pedigree = fold_build2 (MODIFY_EXPR, void_type_node,
461 parent_pedigree, worker_pedigree);
462 tree w_ped_rank = cilk_dot (unshare_expr (worker_pedigree),
463 CILK_TI_PEDIGREE_RANK, false);
464 tree incr_ped_rank = fold_build2 (PLUS_EXPR, TREE_TYPE (w_ped_rank),
465 w_ped_rank,
466 build_one_cst (TREE_TYPE (w_ped_rank)));
467 incr_ped_rank = fold_build2 (MODIFY_EXPR, void_type_node, w_ped_rank,
468 incr_ped_rank);
469 tree ret_sync_exp = alloc_stmt_list ();
470 append_to_statement_list (assign_pedigree, &ret_sync_exp);
471 append_to_statement_list (sync, &ret_sync_exp);
472 append_to_statement_list (incr_ped_rank, &ret_sync_exp);
473 return ret_sync_exp;
476 /* Gimplifies the cilk_sync expression passed in *EXPR_P. Returns GS_ALL_DONE
477 when finished. */
479 void
480 gimplify_cilk_sync (tree *expr_p, gimple_seq *pre_p)
482 tree sync_expr = expand_cilk_sync ();
483 *expr_p = NULL_TREE;
484 gimplify_and_add (sync_expr, pre_p);