* config/rx/rx.c (ADD_RX_BUILTIN0): New macro, used for builtins
[official-gcc.git] / gcc / cilk-common.c
blobca178c00cd365f3e2d39924baf944154a1b160ea
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 "cilk.h"
35 /* This structure holds all the important fields of the internal structures,
36 internal built-in functions, and Cilk-specific data types. Explanation of
37 all the these fielsd are given in cilk.h. */
38 tree cilk_trees[(int) CILK_TI_MAX];
40 /* Returns the value in structure FRAME pointed by the FIELD_NUMBER
41 (e.g. X.y).
42 FIELD_NUMBER is an index to the structure FRAME_PTR. For details
43 about these fields, refer to cilk_trees structure in cilk.h and
44 cilk_init_builtins function in this file. Returns a TREE that is the type
45 of the field represented by FIELD_NUMBER. If VOLATIL parameter is set
46 to true then the returning field is set as volatile. */
48 tree
49 cilk_dot (tree frame, int field_number, bool volatil)
51 tree field = cilk_trees[field_number];
52 field = fold_build3 (COMPONENT_REF, TREE_TYPE (field), frame, field,
53 NULL_TREE);
54 TREE_THIS_VOLATILE (field) = volatil;
55 return field;
58 /* Returns the address of a field in FRAME_PTR, pointed by FIELD_NUMBER.
59 (e.g. (&X)->y). Please see cilk_dot function for explanation of the
60 FIELD_NUMBER. Returns a tree that is the type of the field represented
61 by FIELD_NUMBER. If VOLATIL parameter is set to true then the returning
62 field is set as volatile. */
64 tree
65 cilk_arrow (tree frame_ptr, int field_number, bool volatil)
67 return cilk_dot (fold_build1 (INDIRECT_REF,
68 TREE_TYPE (TREE_TYPE (frame_ptr)), frame_ptr),
69 field_number, volatil);
73 /* This function will add FIELD of type TYPE to a defined built-in
74 structure. *NAME is the name of the field to be added. */
76 static tree
77 add_field (const char *name, tree type, tree fields)
79 tree t = get_identifier (name);
80 tree field = build_decl (BUILTINS_LOCATION, FIELD_DECL, t, type);
81 TREE_CHAIN (field) = fields;
82 return field;
85 /* This function will define a built-in function of NAME, of type FNTYPE and
86 register it under the built-in function code CODE. If PUBLISH is set then
87 the declaration is pushed into the declaration list. CODE is the index
88 to the cilk_trees array. *NAME is the name of the function to be added. */
90 static tree
91 install_builtin (const char *name, tree fntype, enum built_in_function code,
92 bool publish)
94 tree fndecl = build_fn_decl (name, fntype);
95 DECL_BUILT_IN_CLASS (fndecl) = BUILT_IN_NORMAL;
96 DECL_FUNCTION_CODE (fndecl) = code;
97 if (publish)
99 tree t = lang_hooks.decls.pushdecl (fndecl);
100 if (t)
101 fndecl = t;
103 set_builtin_decl (code, fndecl, true);
104 return fndecl;
107 /* Creates and initializes all the built-in Cilk keywords functions and three
108 structures: __cilkrts_stack_frame, __cilkrts_pedigree and __cilkrts_worker.
109 Detailed information about __cilkrts_stack_frame and
110 __cilkrts_worker structures are given in libcilkrts/include/internal/abi.h.
111 __cilkrts_pedigree is described in libcilkrts/include/cilk/common.h. */
113 void
114 cilk_init_builtins (void)
116 /* Now build the following __cilkrts_pedigree struct:
117 struct __cilkrts_pedigree {
118 uint64_t rank;
119 struct __cilkrts_pedigree *parent;
120 } */
122 tree pedigree_type = lang_hooks.types.make_type (RECORD_TYPE);
123 tree pedigree_ptr = build_pointer_type (pedigree_type);
124 tree field = add_field ("rank", uint64_type_node, NULL_TREE);
125 cilk_trees[CILK_TI_PEDIGREE_RANK] = field;
126 field = add_field ("parent", pedigree_ptr, field);
127 cilk_trees[CILK_TI_PEDIGREE_PARENT] = field;
128 finish_builtin_struct (pedigree_type, "__cilkrts_pedigree_GCC", field,
129 NULL_TREE);
130 lang_hooks.types.register_builtin_type (pedigree_type,
131 "__cilkrts_pedigree_t");
132 cilk_pedigree_type_decl = pedigree_type;
134 /* Build the Cilk Stack Frame:
135 struct __cilkrts_stack_frame {
136 uint32_t flags;
137 uint32_t size;
138 struct __cilkrts_stack_frame *call_parent;
139 __cilkrts_worker *worker;
140 void *except_data;
141 void *ctx[4];
142 uint32_t mxcsr;
143 uint16_t fpcsr;
144 uint16_t reserved;
145 __cilkrts_pedigree pedigree;
146 }; */
148 tree frame = lang_hooks.types.make_type (RECORD_TYPE);
149 tree frame_ptr = build_pointer_type (frame);
150 tree worker_type = lang_hooks.types.make_type (RECORD_TYPE);
151 tree worker_ptr = build_pointer_type (worker_type);
152 tree s_type_node = build_int_cst (size_type_node, 4);
154 tree flags = add_field ("flags", uint32_type_node, NULL_TREE);
155 tree size = add_field ("size", uint32_type_node, flags);
156 tree parent = add_field ("call_parent", frame_ptr, size);
157 tree worker = add_field ("worker", worker_ptr, parent);
158 tree except = add_field ("except_data", frame_ptr, worker);
159 tree context = add_field ("ctx",
160 build_array_type (ptr_type_node,
161 build_index_type (s_type_node)),
162 except);
163 tree mxcsr = add_field ("mxcsr", uint32_type_node, context);
164 tree fpcsr = add_field ("fpcsr", uint16_type_node, mxcsr);
165 tree reserved = add_field ("reserved", uint16_type_node, fpcsr);
166 tree pedigree = add_field ("pedigree", pedigree_type, reserved);
168 /* Now add them to a common structure whose fields are #defined to something
169 that is used at a later stage. */
170 cilk_trees[CILK_TI_FRAME_FLAGS] = flags;
171 cilk_trees[CILK_TI_FRAME_PARENT] = parent;
172 cilk_trees[CILK_TI_FRAME_WORKER] = worker;
173 cilk_trees[CILK_TI_FRAME_EXCEPTION] = except;
174 cilk_trees[CILK_TI_FRAME_CONTEXT] = context;
175 /* We don't care about reserved, so no need to store it in cilk_trees. */
176 cilk_trees[CILK_TI_FRAME_PEDIGREE] = pedigree;
177 TREE_ADDRESSABLE (frame) = 1;
179 finish_builtin_struct (frame, "__cilkrts_st_frame_GCC", pedigree, NULL_TREE);
180 cilk_frame_type_decl = frame;
181 lang_hooks.types.register_builtin_type (frame, "__cilkrts_frame_t");
183 cilk_frame_ptr_type_decl = build_qualified_type (frame_ptr,
184 TYPE_QUAL_VOLATILE);
185 /* Now let's do the following worker struct:
187 struct __cilkrts_worker {
188 __cilkrts_stack_frame *volatile *volatile tail;
189 __cilkrts_stack_frame *volatile *volatile head;
190 __cilkrts_stack_frame *volatile *volatile exc;
191 __cilkrts_stack_frame *volatile *volatile protected_tail;
192 __cilkrts_stack_frame *volatile *ltq_limit;
193 int32_t self;
194 global_state_t *g;
195 local_state *l;
196 cilkred_map *reducer_map;
197 __cilkrts_stack_frame *current_stack_frame;
198 void *reserved;
199 __cilkrts_worker_sysdep_state *sysdep;
200 __cilkrts_pedigree pedigree;
201 } */
203 tree fptr_volatil_type = build_qualified_type (frame_ptr, TYPE_QUAL_VOLATILE);
204 tree fptr_volatile_ptr = build_pointer_type (fptr_volatil_type);
205 tree fptr_vol_ptr_vol = build_qualified_type (fptr_volatile_ptr,
206 TYPE_QUAL_VOLATILE);
207 tree g = lang_hooks.types.make_type (RECORD_TYPE);
208 finish_builtin_struct (g, "__cilkrts_global_state", NULL_TREE, NULL_TREE);
209 tree l = lang_hooks.types.make_type (RECORD_TYPE);
210 finish_builtin_struct (l, "__cilkrts_local_state", NULL_TREE, NULL_TREE);
211 tree sysdep_t = lang_hooks.types.make_type (RECORD_TYPE);
212 finish_builtin_struct (sysdep_t, "__cilkrts_worker_sysdep_state", NULL_TREE,
213 NULL_TREE);
215 field = add_field ("tail", fptr_vol_ptr_vol, NULL_TREE);
216 cilk_trees[CILK_TI_WORKER_TAIL] = field;
217 field = add_field ("head", fptr_vol_ptr_vol, field);
218 field = add_field ("exc", fptr_vol_ptr_vol, field);
219 field = add_field ("protected_tail", fptr_vol_ptr_vol, field);
220 field = add_field ("ltq_limit", fptr_volatile_ptr, field);
221 field = add_field ("self", integer_type_node, field);
222 field = add_field ("g", build_pointer_type (g), field);
223 field = add_field ("l", build_pointer_type (g), field);
224 field = add_field ("reducer_map", ptr_type_node, field);
225 field = add_field ("current_stack_frame", frame_ptr, field);
226 cilk_trees[CILK_TI_WORKER_CUR] = field;
227 field = add_field ("saved_protected_tail", fptr_volatile_ptr, field);
228 field = add_field ("sysdep", build_pointer_type (sysdep_t), field);
229 field = add_field ("pedigree", pedigree_type, field);
230 cilk_trees[CILK_TI_WORKER_PEDIGREE] = field;
231 finish_builtin_struct (worker_type, "__cilkrts_worker_GCC", field,
232 NULL_TREE);
234 tree fptr_arglist = tree_cons (NULL_TREE, frame_ptr, void_list_node);
235 tree fptr_fun = build_function_type (void_type_node, fptr_arglist);
237 /* void __cilkrts_enter_frame_1 (__cilkrts_stack_frame *); */
238 cilk_enter_fndecl = install_builtin ("__cilkrts_enter_frame_1", fptr_fun,
239 BUILT_IN_CILK_ENTER_FRAME, false);
241 /* void __cilkrts_enter_frame_fast_1 (__cilkrts_stack_frame *); */
242 cilk_enter_fast_fndecl =
243 install_builtin ("__cilkrts_enter_frame_fast_1", fptr_fun,
244 BUILT_IN_CILK_ENTER_FRAME_FAST, false);
246 /* void __cilkrts_pop_frame (__cilkrts_stack_frame *); */
247 cilk_pop_fndecl = install_builtin ("__cilkrts_pop_frame", fptr_fun,
248 BUILT_IN_CILK_POP_FRAME, false);
250 /* void __cilkrts_leave_frame (__cilkrts_stack_frame *); */
251 cilk_leave_fndecl = install_builtin ("__cilkrts_leave_frame", fptr_fun,
252 BUILT_IN_CILK_LEAVE_FRAME, false);
254 /* void __cilkrts_sync (__cilkrts_stack_frame *); */
255 cilk_sync_fndecl = install_builtin ("__cilkrts_sync", fptr_fun,
256 BUILT_IN_CILK_SYNC, false);
258 /* void __cilkrts_detach (__cilkrts_stack_frame *); */
259 cilk_detach_fndecl = install_builtin ("__cilkrts_detach", fptr_fun,
260 BUILT_IN_CILK_DETACH, false);
262 /* __cilkrts_rethrow (struct stack_frame *); */
263 cilk_rethrow_fndecl = install_builtin ("__cilkrts_rethrow", fptr_fun,
264 BUILT_IN_CILK_RETHROW, false);
266 /* __cilkrts_save_fp_ctrl_state (__cilkrts_stack_frame *); */
267 cilk_save_fp_fndecl = install_builtin ("__cilkrts_save_fp_ctrl_state",
268 fptr_fun, BUILT_IN_CILK_SAVE_FP,
269 false);
272 /* Get the appropriate frame arguments for CALL that is of type CALL_EXPR. */
274 static tree
275 get_frame_arg (tree call)
277 tree arg, argtype;
279 gcc_assert (call_expr_nargs (call) >= 1);
281 arg = CALL_EXPR_ARG (call, 0);
282 argtype = TREE_TYPE (arg);
283 gcc_assert (TREE_CODE (argtype) == POINTER_TYPE);
285 argtype = TREE_TYPE (argtype);
287 gcc_assert (!lang_hooks.types_compatible_p
288 || lang_hooks.types_compatible_p (argtype, cilk_frame_type_decl));
290 /* If it is passed in as an address, then just use the value directly
291 since the function is inlined. */
292 if (TREE_CODE (arg) == INDIRECT_REF || TREE_CODE (arg) == ADDR_EXPR)
293 return TREE_OPERAND (arg, 0);
294 return arg;
297 /* Expands the __cilkrts_pop_frame function call stored in EXP. */
299 void
300 expand_builtin_cilk_pop_frame (tree exp)
302 tree frame = get_frame_arg (exp);
303 tree parent = cilk_dot (frame, CILK_TI_FRAME_PARENT, 0);
305 tree clear_parent = build2 (MODIFY_EXPR, void_type_node, parent,
306 build_int_cst (TREE_TYPE (parent), 0));
307 expand_expr (clear_parent, const0_rtx, VOIDmode, EXPAND_NORMAL);
309 /* During LTO, the is_cilk_function flag gets cleared.
310 If __cilkrts_pop_frame is called, then this definitely must be a
311 cilk function. */
312 if (cfun)
313 cfun->is_cilk_function = 1;
316 /* Expands the cilk_detach function call stored in EXP. */
318 void
319 expand_builtin_cilk_detach (tree exp)
321 rtx insn;
322 tree fptr = get_frame_arg (exp);
324 if (fptr == NULL_TREE)
325 return;
327 tree parent = cilk_dot (fptr, CILK_TI_FRAME_PARENT, 0);
328 tree worker = cilk_dot (fptr, CILK_TI_FRAME_WORKER, 0);
329 tree tail = cilk_dot (worker, CILK_TI_WORKER_TAIL, 1);
331 rtx wreg = expand_expr (worker, NULL_RTX, Pmode, EXPAND_NORMAL);
332 if (GET_CODE (wreg) != REG)
333 wreg = copy_to_reg (wreg);
334 rtx preg = expand_expr (parent, NULL_RTX, Pmode, EXPAND_NORMAL);
336 /* TMP <- WORKER.TAIL
337 *TMP <- PARENT
338 TMP <- TMP + 1
339 WORKER.TAIL <- TMP */
341 HOST_WIDE_INT worker_tail_offset =
342 tree_low_cst (DECL_FIELD_OFFSET (cilk_trees[CILK_TI_WORKER_TAIL]), 0) +
343 tree_low_cst (DECL_FIELD_BIT_OFFSET (cilk_trees[CILK_TI_WORKER_TAIL]), 0) /
344 BITS_PER_UNIT;
345 rtx tmem0 = gen_rtx_MEM (Pmode,
346 plus_constant (Pmode, wreg, worker_tail_offset));
347 set_mem_attributes (tmem0, tail, 0);
348 MEM_NOTRAP_P (tmem0) = 1;
349 gcc_assert (MEM_VOLATILE_P (tmem0));
350 rtx treg = copy_to_mode_reg (Pmode, tmem0);
351 rtx tmem1 = gen_rtx_MEM (Pmode, treg);
352 set_mem_attributes (tmem1, TREE_TYPE (TREE_TYPE (tail)), 0);
353 MEM_NOTRAP_P (tmem1) = 1;
354 emit_move_insn (tmem1, preg);
355 emit_move_insn (treg, plus_constant (Pmode, treg, GET_MODE_SIZE (Pmode)));
357 /* There is a release barrier (st8.rel, membar #StoreStore,
358 sfence, lwsync, etc.) between the two stores. On x86
359 normal volatile stores have proper semantics; the sfence
360 would only be needed for nontemporal stores (which we
361 could generate using the storent optab, for no benefit
362 in this case).
364 The predicate may return false even for a REG if this is
365 the limited release operation that only stores 0. */
366 enum insn_code icode = direct_optab_handler (sync_lock_release_optab, Pmode);
367 if (icode != CODE_FOR_nothing
368 && insn_data[icode].operand[1].predicate (treg, Pmode)
369 && (insn = GEN_FCN (icode) (tmem0, treg)) != NULL_RTX)
370 emit_insn (insn);
371 else
372 emit_move_insn (tmem0, treg);
374 /* The memory barrier inserted above should not prevent
375 the load of flags from being moved before the stores,
376 but in practice it does because it is implemented with
377 unspec_volatile. In-order RISC machines should
378 explicitly load flags earlier. */
380 tree flags = cilk_dot (fptr, CILK_TI_FRAME_FLAGS, 0);
381 expand_expr (build2 (MODIFY_EXPR, void_type_node, flags,
382 build2 (BIT_IOR_EXPR, TREE_TYPE (flags), flags,
383 build_int_cst (TREE_TYPE (flags),
384 CILK_FRAME_DETACHED))),
385 const0_rtx, VOIDmode, EXPAND_NORMAL);
388 /* Returns a setjmp CALL_EXPR with FRAME->context as its parameter. */
390 tree
391 cilk_call_setjmp (tree frame)
393 tree c = cilk_dot (frame, CILK_TI_FRAME_CONTEXT, false);
394 c = build1 (ADDR_EXPR, build_pointer_type (ptr_type_node), c);
395 return build_call_expr (builtin_decl_implicit (BUILT_IN_SETJMP), 1, c);
398 /* This function will expand the _Cilk_sync keyword. */
400 static tree
401 expand_cilk_sync (void)
403 tree frame = cfun->cilk_frame_decl;
405 /* Cilk_sync is converted to the following code:
407 sf.pedigree = sf.worker->pedigree;
408 if (frame.flags & CILK_FRAME_UNSYNCHED)
410 __cilkrts_save_fp_state (&sf);
411 if (!builtin_setjmp (sf.ctx)
412 __cilkrts_sync (&sf);
413 else
414 if (sf.flags & CILK_FRAME_EXCEPTING)
415 __cilkrts_rethrow (&sf);
417 sf.worker->pedigree.rank = sf.worker->pedigree.rank + 1; */
419 tree flags = cilk_dot (frame, CILK_TI_FRAME_FLAGS, false);
421 tree unsynched = fold_build2 (BIT_AND_EXPR, TREE_TYPE (flags), flags,
422 build_int_cst (TREE_TYPE (flags),
423 CILK_FRAME_UNSYNCHED));
425 unsynched = fold_build2 (NE_EXPR, TREE_TYPE (unsynched), unsynched,
426 build_int_cst (TREE_TYPE (unsynched), 0));
428 tree frame_addr = build1 (ADDR_EXPR, cilk_frame_ptr_type_decl, frame);
430 /* Check if exception (0x10) bit is set in the sf->flags. */
431 tree except_flag = fold_build2 (BIT_AND_EXPR, TREE_TYPE (flags), flags,
432 build_int_cst (TREE_TYPE (flags),
433 CILK_FRAME_EXCEPTING));
434 except_flag = fold_build2 (NE_EXPR, TREE_TYPE (except_flag), except_flag,
435 build_int_cst (TREE_TYPE (except_flag), 0));
437 /* If the exception flag is set then call the __cilkrts_rethrow (&sf). */
438 tree except_cond = fold_build3 (COND_EXPR, void_type_node, except_flag,
439 build_call_expr (cilk_rethrow_fndecl, 1,
440 frame_addr),
441 build_empty_stmt (EXPR_LOCATION (unsynched)));
443 tree sync_expr = build_call_expr (cilk_sync_fndecl, 1, frame_addr);
444 tree setjmp_expr = cilk_call_setjmp (frame);
445 setjmp_expr = fold_build2 (EQ_EXPR, TREE_TYPE (setjmp_expr), setjmp_expr,
446 build_int_cst (TREE_TYPE (setjmp_expr), 0));
448 setjmp_expr = fold_build3 (COND_EXPR, void_type_node, setjmp_expr,
449 sync_expr, except_cond);
450 tree sync_list = alloc_stmt_list ();
451 append_to_statement_list (build_call_expr (cilk_save_fp_fndecl, 1,
452 frame_addr), &sync_list);
453 append_to_statement_list (setjmp_expr, &sync_list);
454 tree sync = fold_build3 (COND_EXPR, void_type_node, unsynched, sync_list,
455 build_empty_stmt (EXPR_LOCATION (unsynched)));
456 tree parent_pedigree = cilk_dot (frame, CILK_TI_FRAME_PEDIGREE, false);
457 tree worker = cilk_dot (frame, CILK_TI_FRAME_WORKER, false);
458 tree worker_pedigree = cilk_arrow (worker, CILK_TI_WORKER_PEDIGREE, false);
459 tree assign_pedigree = fold_build2 (MODIFY_EXPR, void_type_node,
460 parent_pedigree, worker_pedigree);
461 tree w_ped_rank = cilk_dot (unshare_expr (worker_pedigree),
462 CILK_TI_PEDIGREE_RANK, false);
463 tree incr_ped_rank = fold_build2 (PLUS_EXPR, TREE_TYPE (w_ped_rank),
464 w_ped_rank,
465 build_one_cst (TREE_TYPE (w_ped_rank)));
466 incr_ped_rank = fold_build2 (MODIFY_EXPR, void_type_node, w_ped_rank,
467 incr_ped_rank);
468 tree ret_sync_exp = alloc_stmt_list ();
469 append_to_statement_list (assign_pedigree, &ret_sync_exp);
470 append_to_statement_list (sync, &ret_sync_exp);
471 append_to_statement_list (incr_ped_rank, &ret_sync_exp);
472 return ret_sync_exp;
475 /* Gimplifies the cilk_sync expression passed in *EXPR_P. Returns GS_ALL_DONE
476 when finished. */
478 void
479 gimplify_cilk_sync (tree *expr_p, gimple_seq *pre_p)
481 tree sync_expr = expand_cilk_sync ();
482 *expr_p = NULL_TREE;
483 gimplify_and_add (sync_expr, pre_p);