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