1 /* This file is part of the Intel(R) Cilk(TM) Plus support
2 This file contains the CilkPlus Intrinsics
3 Copyright (C) 2013-2014 Free Software Foundation, Inc.
4 Contributed by Balaji V. Iyer <balaji.v.iyer@intel.com>,
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)
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/>. */
25 #include "coretypes.h"
27 #include "stringpool.h"
28 #include "stor-layout.h"
29 #include "langhooks.h"
33 #include "tree-iterator.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
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. */
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
,
56 TREE_THIS_VOLATILE (field
) = volatil
;
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. */
67 cilk_arrow (tree frame_ptr
, int field_number
, bool volatil
)
69 return cilk_dot (build_simple_mem_ref (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. */
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
;
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. */
92 install_builtin (const char *name
, tree fntype
, enum built_in_function code
,
95 tree fndecl
= build_fn_decl (name
, fntype
);
96 DECL_BUILT_IN_CLASS (fndecl
) = BUILT_IN_NORMAL
;
97 DECL_FUNCTION_CODE (fndecl
) = code
;
100 tree t
= lang_hooks
.decls
.pushdecl (fndecl
);
104 set_builtin_decl (code
, fndecl
, true);
108 /* Returns a FUNCTION_DECL of type TYPE whose name is *NAME. */
111 declare_cilk_for_builtin (const char *name
, tree type
,
112 enum built_in_function code
)
116 cb
= build_function_type_list (void_type_node
,
117 ptr_type_node
, type
, type
,
119 cb
= build_pointer_type (cb
);
120 ft
= build_function_type_list (void_type_node
,
121 cb
, ptr_type_node
, type
,
122 integer_type_node
, NULL_TREE
);
123 fn
= install_builtin (name
, ft
, code
, false);
124 TREE_NOTHROW (fn
) = 0;
129 /* Creates and initializes all the built-in Cilk keywords functions and three
130 structures: __cilkrts_stack_frame, __cilkrts_pedigree and __cilkrts_worker.
131 Detailed information about __cilkrts_stack_frame and
132 __cilkrts_worker structures are given in libcilkrts/include/internal/abi.h.
133 __cilkrts_pedigree is described in libcilkrts/include/cilk/common.h. */
136 cilk_init_builtins (void)
138 /* Now build the following __cilkrts_pedigree struct:
139 struct __cilkrts_pedigree {
141 struct __cilkrts_pedigree *parent;
144 tree pedigree_type
= lang_hooks
.types
.make_type (RECORD_TYPE
);
145 tree pedigree_ptr
= build_pointer_type (pedigree_type
);
146 tree field
= add_field ("rank", uint64_type_node
, NULL_TREE
);
147 cilk_trees
[CILK_TI_PEDIGREE_RANK
] = field
;
148 field
= add_field ("parent", pedigree_ptr
, field
);
149 cilk_trees
[CILK_TI_PEDIGREE_PARENT
] = field
;
150 finish_builtin_struct (pedigree_type
, "__cilkrts_pedigree_GCC", field
,
152 lang_hooks
.types
.register_builtin_type (pedigree_type
,
153 "__cilkrts_pedigree_t");
154 cilk_pedigree_type_decl
= pedigree_type
;
156 /* Build the Cilk Stack Frame:
157 struct __cilkrts_stack_frame {
160 struct __cilkrts_stack_frame *call_parent;
161 __cilkrts_worker *worker;
167 __cilkrts_pedigree pedigree;
170 tree frame
= lang_hooks
.types
.make_type (RECORD_TYPE
);
171 tree frame_ptr
= build_pointer_type (frame
);
172 tree worker_type
= lang_hooks
.types
.make_type (RECORD_TYPE
);
173 tree worker_ptr
= build_pointer_type (worker_type
);
174 tree s_type_node
= build_int_cst (size_type_node
, 4);
176 tree flags
= add_field ("flags", uint32_type_node
, NULL_TREE
);
177 tree size
= add_field ("size", uint32_type_node
, flags
);
178 tree parent
= add_field ("call_parent", frame_ptr
, size
);
179 tree worker
= add_field ("worker", worker_ptr
, parent
);
180 tree except
= add_field ("except_data", frame_ptr
, worker
);
181 tree context
= add_field ("ctx",
182 build_array_type (ptr_type_node
,
183 build_index_type (s_type_node
)),
185 tree mxcsr
= add_field ("mxcsr", uint32_type_node
, context
);
186 tree fpcsr
= add_field ("fpcsr", uint16_type_node
, mxcsr
);
187 tree reserved
= add_field ("reserved", uint16_type_node
, fpcsr
);
188 tree pedigree
= add_field ("pedigree", pedigree_type
, reserved
);
190 /* Now add them to a common structure whose fields are #defined to something
191 that is used at a later stage. */
192 cilk_trees
[CILK_TI_FRAME_FLAGS
] = flags
;
193 cilk_trees
[CILK_TI_FRAME_PARENT
] = parent
;
194 cilk_trees
[CILK_TI_FRAME_WORKER
] = worker
;
195 cilk_trees
[CILK_TI_FRAME_EXCEPTION
] = except
;
196 cilk_trees
[CILK_TI_FRAME_CONTEXT
] = context
;
197 /* We don't care about reserved, so no need to store it in cilk_trees. */
198 cilk_trees
[CILK_TI_FRAME_PEDIGREE
] = pedigree
;
199 TREE_ADDRESSABLE (frame
) = 1;
201 finish_builtin_struct (frame
, "__cilkrts_st_frame_GCC", pedigree
, NULL_TREE
);
202 cilk_frame_type_decl
= frame
;
203 lang_hooks
.types
.register_builtin_type (frame
, "__cilkrts_frame_t");
205 cilk_frame_ptr_type_decl
= build_qualified_type (frame_ptr
,
207 /* Now let's do the following worker struct:
209 struct __cilkrts_worker {
210 __cilkrts_stack_frame *volatile *volatile tail;
211 __cilkrts_stack_frame *volatile *volatile head;
212 __cilkrts_stack_frame *volatile *volatile exc;
213 __cilkrts_stack_frame *volatile *volatile protected_tail;
214 __cilkrts_stack_frame *volatile *ltq_limit;
218 cilkred_map *reducer_map;
219 __cilkrts_stack_frame *current_stack_frame;
221 __cilkrts_worker_sysdep_state *sysdep;
222 __cilkrts_pedigree pedigree;
225 tree fptr_volatil_type
= build_qualified_type (frame_ptr
, TYPE_QUAL_VOLATILE
);
226 tree fptr_volatile_ptr
= build_pointer_type (fptr_volatil_type
);
227 tree fptr_vol_ptr_vol
= build_qualified_type (fptr_volatile_ptr
,
229 tree g
= lang_hooks
.types
.make_type (RECORD_TYPE
);
230 finish_builtin_struct (g
, "__cilkrts_global_state", NULL_TREE
, NULL_TREE
);
231 tree l
= lang_hooks
.types
.make_type (RECORD_TYPE
);
232 finish_builtin_struct (l
, "__cilkrts_local_state", NULL_TREE
, NULL_TREE
);
233 tree sysdep_t
= lang_hooks
.types
.make_type (RECORD_TYPE
);
234 finish_builtin_struct (sysdep_t
, "__cilkrts_worker_sysdep_state", NULL_TREE
,
237 field
= add_field ("tail", fptr_vol_ptr_vol
, NULL_TREE
);
238 cilk_trees
[CILK_TI_WORKER_TAIL
] = field
;
239 field
= add_field ("head", fptr_vol_ptr_vol
, field
);
240 field
= add_field ("exc", fptr_vol_ptr_vol
, field
);
241 field
= add_field ("protected_tail", fptr_vol_ptr_vol
, field
);
242 field
= add_field ("ltq_limit", fptr_volatile_ptr
, field
);
243 field
= add_field ("self", integer_type_node
, field
);
244 field
= add_field ("g", build_pointer_type (g
), field
);
245 field
= add_field ("l", build_pointer_type (g
), field
);
246 field
= add_field ("reducer_map", ptr_type_node
, field
);
247 field
= add_field ("current_stack_frame", frame_ptr
, field
);
248 cilk_trees
[CILK_TI_WORKER_CUR
] = field
;
249 field
= add_field ("saved_protected_tail", fptr_volatile_ptr
, field
);
250 field
= add_field ("sysdep", build_pointer_type (sysdep_t
), field
);
251 field
= add_field ("pedigree", pedigree_type
, field
);
252 cilk_trees
[CILK_TI_WORKER_PEDIGREE
] = field
;
253 finish_builtin_struct (worker_type
, "__cilkrts_worker_GCC", field
,
256 tree fptr_arglist
= tree_cons (NULL_TREE
, frame_ptr
, void_list_node
);
257 tree fptr_fun
= build_function_type (void_type_node
, fptr_arglist
);
259 /* void __cilkrts_enter_frame_1 (__cilkrts_stack_frame *); */
260 cilk_enter_fndecl
= install_builtin ("__cilkrts_enter_frame_1", fptr_fun
,
261 BUILT_IN_CILK_ENTER_FRAME
, false);
263 /* void __cilkrts_enter_frame_fast_1 (__cilkrts_stack_frame *); */
264 cilk_enter_fast_fndecl
=
265 install_builtin ("__cilkrts_enter_frame_fast_1", fptr_fun
,
266 BUILT_IN_CILK_ENTER_FRAME_FAST
, false);
268 /* void __cilkrts_pop_frame (__cilkrts_stack_frame *); */
269 cilk_pop_fndecl
= install_builtin ("__cilkrts_pop_frame", fptr_fun
,
270 BUILT_IN_CILK_POP_FRAME
, false);
272 /* void __cilkrts_leave_frame (__cilkrts_stack_frame *); */
273 cilk_leave_fndecl
= install_builtin ("__cilkrts_leave_frame", fptr_fun
,
274 BUILT_IN_CILK_LEAVE_FRAME
, false);
276 /* void __cilkrts_sync (__cilkrts_stack_frame *); */
277 cilk_sync_fndecl
= install_builtin ("__cilkrts_sync", fptr_fun
,
278 BUILT_IN_CILK_SYNC
, false);
280 /* void __cilkrts_detach (__cilkrts_stack_frame *); */
281 cilk_detach_fndecl
= install_builtin ("__cilkrts_detach", fptr_fun
,
282 BUILT_IN_CILK_DETACH
, false);
284 /* __cilkrts_rethrow (struct stack_frame *); */
285 cilk_rethrow_fndecl
= install_builtin ("__cilkrts_rethrow", fptr_fun
,
286 BUILT_IN_CILK_RETHROW
, false);
287 TREE_NOTHROW (cilk_rethrow_fndecl
) = 0;
289 /* __cilkrts_save_fp_ctrl_state (__cilkrts_stack_frame *); */
290 cilk_save_fp_fndecl
= install_builtin ("__cilkrts_save_fp_ctrl_state",
291 fptr_fun
, BUILT_IN_CILK_SAVE_FP
,
293 /* __cilkrts_cilk_for_32 (...); */
294 cilk_for_32_fndecl
= declare_cilk_for_builtin ("__cilkrts_cilk_for_32",
295 unsigned_intSI_type_node
,
296 BUILT_IN_CILK_FOR_32
);
297 /* __cilkrts_cilk_for_64 (...); */
298 cilk_for_64_fndecl
= declare_cilk_for_builtin ("__cilkrts_cilk_for_64",
299 unsigned_intDI_type_node
,
300 BUILT_IN_CILK_FOR_64
);
303 /* Get the appropriate frame arguments for CALL that is of type CALL_EXPR. */
306 get_frame_arg (tree call
)
310 gcc_assert (call_expr_nargs (call
) >= 1);
312 arg
= CALL_EXPR_ARG (call
, 0);
313 argtype
= TREE_TYPE (arg
);
314 gcc_assert (TREE_CODE (argtype
) == POINTER_TYPE
);
316 argtype
= TREE_TYPE (argtype
);
318 /* If it is passed in as an address, then just use the value directly
319 since the function is inlined. */
320 if (TREE_CODE (arg
) == ADDR_EXPR
)
321 return TREE_OPERAND (arg
, 0);
325 /* Expands the __cilkrts_pop_frame function call stored in EXP. */
328 expand_builtin_cilk_pop_frame (tree exp
)
330 tree frame
= get_frame_arg (exp
);
331 tree parent
= cilk_dot (frame
, CILK_TI_FRAME_PARENT
, 0);
333 tree clear_parent
= build2 (MODIFY_EXPR
, void_type_node
, parent
,
334 build_int_cst (TREE_TYPE (parent
), 0));
335 expand_expr (clear_parent
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
337 /* During LTO, the is_cilk_function flag gets cleared.
338 If __cilkrts_pop_frame is called, then this definitely must be a
341 cfun
->is_cilk_function
= 1;
344 /* Expands the cilk_detach function call stored in EXP. */
347 expand_builtin_cilk_detach (tree exp
)
350 tree fptr
= get_frame_arg (exp
);
352 if (fptr
== NULL_TREE
)
355 tree parent
= cilk_dot (fptr
, CILK_TI_FRAME_PARENT
, 0);
356 tree worker
= cilk_dot (fptr
, CILK_TI_FRAME_WORKER
, 0);
357 tree tail
= cilk_arrow (worker
, CILK_TI_WORKER_TAIL
, 1);
359 rtx wreg
= expand_expr (worker
, NULL_RTX
, Pmode
, EXPAND_NORMAL
);
360 if (GET_CODE (wreg
) != REG
)
361 wreg
= copy_to_reg (wreg
);
362 rtx preg
= expand_expr (parent
, NULL_RTX
, Pmode
, EXPAND_NORMAL
);
364 /* TMP <- WORKER.TAIL
367 WORKER.TAIL <- TMP */
369 HOST_WIDE_INT worker_tail_offset
=
370 tree_to_shwi (DECL_FIELD_OFFSET (cilk_trees
[CILK_TI_WORKER_TAIL
])) +
371 tree_to_shwi (DECL_FIELD_BIT_OFFSET (cilk_trees
[CILK_TI_WORKER_TAIL
])) /
373 rtx tmem0
= gen_rtx_MEM (Pmode
,
374 plus_constant (Pmode
, wreg
, worker_tail_offset
));
375 set_mem_attributes (tmem0
, tail
, 0);
376 MEM_NOTRAP_P (tmem0
) = 1;
377 gcc_assert (MEM_VOLATILE_P (tmem0
));
378 rtx treg
= copy_to_mode_reg (Pmode
, tmem0
);
379 rtx tmem1
= gen_rtx_MEM (Pmode
, treg
);
380 set_mem_attributes (tmem1
, TREE_TYPE (TREE_TYPE (tail
)), 0);
381 MEM_NOTRAP_P (tmem1
) = 1;
382 emit_move_insn (tmem1
, preg
);
383 emit_move_insn (treg
, plus_constant (Pmode
, treg
, GET_MODE_SIZE (Pmode
)));
385 /* There is a release barrier (st8.rel, membar #StoreStore,
386 sfence, lwsync, etc.) between the two stores. On x86
387 normal volatile stores have proper semantics; the sfence
388 would only be needed for nontemporal stores (which we
389 could generate using the storent optab, for no benefit
392 The predicate may return false even for a REG if this is
393 the limited release operation that only stores 0. */
394 enum insn_code icode
= direct_optab_handler (sync_lock_release_optab
, Pmode
);
395 if (icode
!= CODE_FOR_nothing
396 && insn_data
[icode
].operand
[1].predicate (treg
, Pmode
)
397 && (insn
= GEN_FCN (icode
) (tmem0
, treg
)) != NULL_RTX
)
400 emit_move_insn (tmem0
, treg
);
402 /* The memory barrier inserted above should not prevent
403 the load of flags from being moved before the stores,
404 but in practice it does because it is implemented with
405 unspec_volatile. In-order RISC machines should
406 explicitly load flags earlier. */
408 tree flags
= cilk_dot (fptr
, CILK_TI_FRAME_FLAGS
, 0);
409 expand_expr (build2 (MODIFY_EXPR
, void_type_node
, flags
,
410 build2 (BIT_IOR_EXPR
, TREE_TYPE (flags
), flags
,
411 build_int_cst (TREE_TYPE (flags
),
412 CILK_FRAME_DETACHED
))),
413 const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
416 /* Returns a setjmp CALL_EXPR with FRAME->context as its parameter. */
419 cilk_call_setjmp (tree frame
)
421 tree c
= cilk_dot (frame
, CILK_TI_FRAME_CONTEXT
, false);
422 c
= build1 (ADDR_EXPR
, build_pointer_type (ptr_type_node
), c
);
423 return build_call_expr (builtin_decl_implicit (BUILT_IN_SETJMP
), 1, c
);
426 /* This function will expand the _Cilk_sync keyword. */
429 expand_cilk_sync (void)
431 tree frame
= cfun
->cilk_frame_decl
;
433 /* Cilk_sync is converted to the following code:
435 sf.pedigree = sf.worker->pedigree;
436 if (frame.flags & CILK_FRAME_UNSYNCHED)
438 __cilkrts_save_fp_state (&sf);
439 if (!builtin_setjmp (sf.ctx)
440 __cilkrts_sync (&sf);
442 if (sf.flags & CILK_FRAME_EXCEPTING)
443 __cilkrts_rethrow (&sf);
445 sf.worker->pedigree.rank = sf.worker->pedigree.rank + 1; */
447 tree flags
= cilk_dot (frame
, CILK_TI_FRAME_FLAGS
, false);
449 tree unsynched
= fold_build2 (BIT_AND_EXPR
, TREE_TYPE (flags
), flags
,
450 build_int_cst (TREE_TYPE (flags
),
451 CILK_FRAME_UNSYNCHED
));
453 unsynched
= fold_build2 (NE_EXPR
, TREE_TYPE (unsynched
), unsynched
,
454 build_int_cst (TREE_TYPE (unsynched
), 0));
456 tree frame_addr
= build1 (ADDR_EXPR
, cilk_frame_ptr_type_decl
, frame
);
458 /* Check if exception (0x10) bit is set in the sf->flags. */
459 tree except_flag
= fold_build2 (BIT_AND_EXPR
, TREE_TYPE (flags
), flags
,
460 build_int_cst (TREE_TYPE (flags
),
461 CILK_FRAME_EXCEPTING
));
462 except_flag
= fold_build2 (NE_EXPR
, TREE_TYPE (except_flag
), except_flag
,
463 build_int_cst (TREE_TYPE (except_flag
), 0));
465 /* If the exception flag is set then call the __cilkrts_rethrow (&sf). */
466 tree except_cond
= fold_build3 (COND_EXPR
, void_type_node
, except_flag
,
467 build_call_expr (cilk_rethrow_fndecl
, 1,
469 build_empty_stmt (EXPR_LOCATION (unsynched
)));
471 tree sync_expr
= build_call_expr (cilk_sync_fndecl
, 1, frame_addr
);
472 tree setjmp_expr
= cilk_call_setjmp (frame
);
473 setjmp_expr
= fold_build2 (EQ_EXPR
, TREE_TYPE (setjmp_expr
), setjmp_expr
,
474 build_int_cst (TREE_TYPE (setjmp_expr
), 0));
476 setjmp_expr
= fold_build3 (COND_EXPR
, void_type_node
, setjmp_expr
,
477 sync_expr
, except_cond
);
478 tree sync_list
= alloc_stmt_list ();
479 append_to_statement_list (build_call_expr (cilk_save_fp_fndecl
, 1,
480 frame_addr
), &sync_list
);
481 append_to_statement_list (setjmp_expr
, &sync_list
);
482 tree sync
= fold_build3 (COND_EXPR
, void_type_node
, unsynched
, sync_list
,
483 build_empty_stmt (EXPR_LOCATION (unsynched
)));
484 tree parent_pedigree
= cilk_dot (frame
, CILK_TI_FRAME_PEDIGREE
, false);
485 tree worker
= cilk_dot (frame
, CILK_TI_FRAME_WORKER
, false);
486 tree worker_pedigree
= cilk_arrow (worker
, CILK_TI_WORKER_PEDIGREE
, false);
487 tree assign_pedigree
= fold_build2 (MODIFY_EXPR
, void_type_node
,
488 parent_pedigree
, worker_pedigree
);
489 tree w_ped_rank
= cilk_dot (unshare_expr (worker_pedigree
),
490 CILK_TI_PEDIGREE_RANK
, false);
491 tree incr_ped_rank
= fold_build2 (PLUS_EXPR
, TREE_TYPE (w_ped_rank
),
493 build_one_cst (TREE_TYPE (w_ped_rank
)));
494 incr_ped_rank
= fold_build2 (MODIFY_EXPR
, void_type_node
, w_ped_rank
,
496 tree ret_sync_exp
= alloc_stmt_list ();
497 append_to_statement_list (assign_pedigree
, &ret_sync_exp
);
498 append_to_statement_list (sync
, &ret_sync_exp
);
499 append_to_statement_list (incr_ped_rank
, &ret_sync_exp
);
503 /* Gimplifies the cilk_sync expression passed in *EXPR_P. Returns GS_ALL_DONE
507 gimplify_cilk_sync (tree
*expr_p
, gimple_seq
*pre_p
)
509 tree sync_expr
= expand_cilk_sync ();
511 gimplify_and_add (sync_expr
, pre_p
);