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>,
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"
38 /* This structure holds all the important fields of the internal structures,
39 internal built-in functions, and Cilk-specific data types. Explanation of
40 all the these fielsd are given in cilk.h. */
41 tree cilk_trees
[(int) CILK_TI_MAX
];
43 /* Returns the value in structure FRAME pointed by the FIELD_NUMBER
45 FIELD_NUMBER is an index to the structure FRAME_PTR. For details
46 about these fields, refer to cilk_trees structure in cilk.h and
47 cilk_init_builtins function in this file. Returns a TREE that is the type
48 of the field represented by FIELD_NUMBER. If VOLATIL parameter is set
49 to true then the returning field is set as volatile. */
52 cilk_dot (tree frame
, int field_number
, bool volatil
)
54 tree field
= cilk_trees
[field_number
];
55 field
= fold_build3 (COMPONENT_REF
, TREE_TYPE (field
), frame
, field
,
57 TREE_THIS_VOLATILE (field
) = volatil
;
61 /* Returns the address of a field in FRAME_PTR, pointed by FIELD_NUMBER.
62 (e.g. (&X)->y). Please see cilk_dot function for explanation of the
63 FIELD_NUMBER. Returns a tree that is the type of the field represented
64 by FIELD_NUMBER. If VOLATIL parameter is set to true then the returning
65 field is set as volatile. */
68 cilk_arrow (tree frame_ptr
, int field_number
, bool volatil
)
70 return cilk_dot (fold_build1 (INDIRECT_REF
,
71 TREE_TYPE (TREE_TYPE (frame_ptr
)), frame_ptr
),
72 field_number
, volatil
);
76 /* This function will add FIELD of type TYPE to a defined built-in
77 structure. *NAME is the name of the field to be added. */
80 add_field (const char *name
, tree type
, tree fields
)
82 tree t
= get_identifier (name
);
83 tree field
= build_decl (BUILTINS_LOCATION
, FIELD_DECL
, t
, type
);
84 TREE_CHAIN (field
) = fields
;
88 /* This function will define a built-in function of NAME, of type FNTYPE and
89 register it under the built-in function code CODE. If PUBLISH is set then
90 the declaration is pushed into the declaration list. CODE is the index
91 to the cilk_trees array. *NAME is the name of the function to be added. */
94 install_builtin (const char *name
, tree fntype
, enum built_in_function code
,
97 tree fndecl
= build_fn_decl (name
, fntype
);
98 DECL_BUILT_IN_CLASS (fndecl
) = BUILT_IN_NORMAL
;
99 DECL_FUNCTION_CODE (fndecl
) = code
;
102 tree t
= lang_hooks
.decls
.pushdecl (fndecl
);
106 set_builtin_decl (code
, fndecl
, true);
110 /* Creates and initializes all the built-in Cilk keywords functions and three
111 structures: __cilkrts_stack_frame, __cilkrts_pedigree and __cilkrts_worker.
112 Detailed information about __cilkrts_stack_frame and
113 __cilkrts_worker structures are given in libcilkrts/include/internal/abi.h.
114 __cilkrts_pedigree is described in libcilkrts/include/cilk/common.h. */
117 cilk_init_builtins (void)
119 /* Now build the following __cilkrts_pedigree struct:
120 struct __cilkrts_pedigree {
122 struct __cilkrts_pedigree *parent;
125 tree pedigree_type
= lang_hooks
.types
.make_type (RECORD_TYPE
);
126 tree pedigree_ptr
= build_pointer_type (pedigree_type
);
127 tree field
= add_field ("rank", uint64_type_node
, NULL_TREE
);
128 cilk_trees
[CILK_TI_PEDIGREE_RANK
] = field
;
129 field
= add_field ("parent", pedigree_ptr
, field
);
130 cilk_trees
[CILK_TI_PEDIGREE_PARENT
] = field
;
131 finish_builtin_struct (pedigree_type
, "__cilkrts_pedigree_GCC", field
,
133 lang_hooks
.types
.register_builtin_type (pedigree_type
,
134 "__cilkrts_pedigree_t");
135 cilk_pedigree_type_decl
= pedigree_type
;
137 /* Build the Cilk Stack Frame:
138 struct __cilkrts_stack_frame {
141 struct __cilkrts_stack_frame *call_parent;
142 __cilkrts_worker *worker;
148 __cilkrts_pedigree pedigree;
151 tree frame
= lang_hooks
.types
.make_type (RECORD_TYPE
);
152 tree frame_ptr
= build_pointer_type (frame
);
153 tree worker_type
= lang_hooks
.types
.make_type (RECORD_TYPE
);
154 tree worker_ptr
= build_pointer_type (worker_type
);
155 tree s_type_node
= build_int_cst (size_type_node
, 4);
157 tree flags
= add_field ("flags", uint32_type_node
, NULL_TREE
);
158 tree size
= add_field ("size", uint32_type_node
, flags
);
159 tree parent
= add_field ("call_parent", frame_ptr
, size
);
160 tree worker
= add_field ("worker", worker_ptr
, parent
);
161 tree except
= add_field ("except_data", frame_ptr
, worker
);
162 tree context
= add_field ("ctx",
163 build_array_type (ptr_type_node
,
164 build_index_type (s_type_node
)),
166 tree mxcsr
= add_field ("mxcsr", uint32_type_node
, context
);
167 tree fpcsr
= add_field ("fpcsr", uint16_type_node
, mxcsr
);
168 tree reserved
= add_field ("reserved", uint16_type_node
, fpcsr
);
169 tree pedigree
= add_field ("pedigree", pedigree_type
, reserved
);
171 /* Now add them to a common structure whose fields are #defined to something
172 that is used at a later stage. */
173 cilk_trees
[CILK_TI_FRAME_FLAGS
] = flags
;
174 cilk_trees
[CILK_TI_FRAME_PARENT
] = parent
;
175 cilk_trees
[CILK_TI_FRAME_WORKER
] = worker
;
176 cilk_trees
[CILK_TI_FRAME_EXCEPTION
] = except
;
177 cilk_trees
[CILK_TI_FRAME_CONTEXT
] = context
;
178 /* We don't care about reserved, so no need to store it in cilk_trees. */
179 cilk_trees
[CILK_TI_FRAME_PEDIGREE
] = pedigree
;
180 TREE_ADDRESSABLE (frame
) = 1;
182 finish_builtin_struct (frame
, "__cilkrts_st_frame_GCC", pedigree
, NULL_TREE
);
183 cilk_frame_type_decl
= frame
;
184 lang_hooks
.types
.register_builtin_type (frame
, "__cilkrts_frame_t");
186 cilk_frame_ptr_type_decl
= build_qualified_type (frame_ptr
,
188 /* Now let's do the following worker struct:
190 struct __cilkrts_worker {
191 __cilkrts_stack_frame *volatile *volatile tail;
192 __cilkrts_stack_frame *volatile *volatile head;
193 __cilkrts_stack_frame *volatile *volatile exc;
194 __cilkrts_stack_frame *volatile *volatile protected_tail;
195 __cilkrts_stack_frame *volatile *ltq_limit;
199 cilkred_map *reducer_map;
200 __cilkrts_stack_frame *current_stack_frame;
202 __cilkrts_worker_sysdep_state *sysdep;
203 __cilkrts_pedigree pedigree;
206 tree fptr_volatil_type
= build_qualified_type (frame_ptr
, TYPE_QUAL_VOLATILE
);
207 tree fptr_volatile_ptr
= build_pointer_type (fptr_volatil_type
);
208 tree fptr_vol_ptr_vol
= build_qualified_type (fptr_volatile_ptr
,
210 tree g
= lang_hooks
.types
.make_type (RECORD_TYPE
);
211 finish_builtin_struct (g
, "__cilkrts_global_state", NULL_TREE
, NULL_TREE
);
212 tree l
= lang_hooks
.types
.make_type (RECORD_TYPE
);
213 finish_builtin_struct (l
, "__cilkrts_local_state", NULL_TREE
, NULL_TREE
);
214 tree sysdep_t
= lang_hooks
.types
.make_type (RECORD_TYPE
);
215 finish_builtin_struct (sysdep_t
, "__cilkrts_worker_sysdep_state", NULL_TREE
,
218 field
= add_field ("tail", fptr_vol_ptr_vol
, NULL_TREE
);
219 cilk_trees
[CILK_TI_WORKER_TAIL
] = field
;
220 field
= add_field ("head", fptr_vol_ptr_vol
, field
);
221 field
= add_field ("exc", fptr_vol_ptr_vol
, field
);
222 field
= add_field ("protected_tail", fptr_vol_ptr_vol
, field
);
223 field
= add_field ("ltq_limit", fptr_volatile_ptr
, field
);
224 field
= add_field ("self", integer_type_node
, field
);
225 field
= add_field ("g", build_pointer_type (g
), field
);
226 field
= add_field ("l", build_pointer_type (g
), field
);
227 field
= add_field ("reducer_map", ptr_type_node
, field
);
228 field
= add_field ("current_stack_frame", frame_ptr
, field
);
229 cilk_trees
[CILK_TI_WORKER_CUR
] = field
;
230 field
= add_field ("saved_protected_tail", fptr_volatile_ptr
, field
);
231 field
= add_field ("sysdep", build_pointer_type (sysdep_t
), field
);
232 field
= add_field ("pedigree", pedigree_type
, field
);
233 cilk_trees
[CILK_TI_WORKER_PEDIGREE
] = field
;
234 finish_builtin_struct (worker_type
, "__cilkrts_worker_GCC", field
,
237 tree fptr_arglist
= tree_cons (NULL_TREE
, frame_ptr
, void_list_node
);
238 tree fptr_fun
= build_function_type (void_type_node
, fptr_arglist
);
240 /* void __cilkrts_enter_frame_1 (__cilkrts_stack_frame *); */
241 cilk_enter_fndecl
= install_builtin ("__cilkrts_enter_frame_1", fptr_fun
,
242 BUILT_IN_CILK_ENTER_FRAME
, false);
244 /* void __cilkrts_enter_frame_fast_1 (__cilkrts_stack_frame *); */
245 cilk_enter_fast_fndecl
=
246 install_builtin ("__cilkrts_enter_frame_fast_1", fptr_fun
,
247 BUILT_IN_CILK_ENTER_FRAME_FAST
, false);
249 /* void __cilkrts_pop_frame (__cilkrts_stack_frame *); */
250 cilk_pop_fndecl
= install_builtin ("__cilkrts_pop_frame", fptr_fun
,
251 BUILT_IN_CILK_POP_FRAME
, false);
253 /* void __cilkrts_leave_frame (__cilkrts_stack_frame *); */
254 cilk_leave_fndecl
= install_builtin ("__cilkrts_leave_frame", fptr_fun
,
255 BUILT_IN_CILK_LEAVE_FRAME
, false);
257 /* void __cilkrts_sync (__cilkrts_stack_frame *); */
258 cilk_sync_fndecl
= install_builtin ("__cilkrts_sync", fptr_fun
,
259 BUILT_IN_CILK_SYNC
, false);
261 /* void __cilkrts_detach (__cilkrts_stack_frame *); */
262 cilk_detach_fndecl
= install_builtin ("__cilkrts_detach", fptr_fun
,
263 BUILT_IN_CILK_DETACH
, false);
265 /* __cilkrts_rethrow (struct stack_frame *); */
266 cilk_rethrow_fndecl
= install_builtin ("__cilkrts_rethrow", fptr_fun
,
267 BUILT_IN_CILK_RETHROW
, false);
269 /* __cilkrts_save_fp_ctrl_state (__cilkrts_stack_frame *); */
270 cilk_save_fp_fndecl
= install_builtin ("__cilkrts_save_fp_ctrl_state",
271 fptr_fun
, BUILT_IN_CILK_SAVE_FP
,
275 /* Get the appropriate frame arguments for CALL that is of type CALL_EXPR. */
278 get_frame_arg (tree call
)
282 gcc_assert (call_expr_nargs (call
) >= 1);
284 arg
= CALL_EXPR_ARG (call
, 0);
285 argtype
= TREE_TYPE (arg
);
286 gcc_assert (TREE_CODE (argtype
) == POINTER_TYPE
);
288 argtype
= TREE_TYPE (argtype
);
290 gcc_assert (!lang_hooks
.types_compatible_p
291 || lang_hooks
.types_compatible_p (argtype
, cilk_frame_type_decl
));
293 /* If it is passed in as an address, then just use the value directly
294 since the function is inlined. */
295 if (TREE_CODE (arg
) == INDIRECT_REF
|| TREE_CODE (arg
) == ADDR_EXPR
)
296 return TREE_OPERAND (arg
, 0);
300 /* Expands the __cilkrts_pop_frame function call stored in EXP. */
303 expand_builtin_cilk_pop_frame (tree exp
)
305 tree frame
= get_frame_arg (exp
);
306 tree parent
= cilk_dot (frame
, CILK_TI_FRAME_PARENT
, 0);
308 tree clear_parent
= build2 (MODIFY_EXPR
, void_type_node
, parent
,
309 build_int_cst (TREE_TYPE (parent
), 0));
310 expand_expr (clear_parent
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
312 /* During LTO, the is_cilk_function flag gets cleared.
313 If __cilkrts_pop_frame is called, then this definitely must be a
316 cfun
->is_cilk_function
= 1;
319 /* Expands the cilk_detach function call stored in EXP. */
322 expand_builtin_cilk_detach (tree exp
)
325 tree fptr
= get_frame_arg (exp
);
327 if (fptr
== NULL_TREE
)
330 tree parent
= cilk_dot (fptr
, CILK_TI_FRAME_PARENT
, 0);
331 tree worker
= cilk_dot (fptr
, CILK_TI_FRAME_WORKER
, 0);
332 tree tail
= cilk_dot (worker
, CILK_TI_WORKER_TAIL
, 1);
334 rtx wreg
= expand_expr (worker
, NULL_RTX
, Pmode
, EXPAND_NORMAL
);
335 if (GET_CODE (wreg
) != REG
)
336 wreg
= copy_to_reg (wreg
);
337 rtx preg
= expand_expr (parent
, NULL_RTX
, Pmode
, EXPAND_NORMAL
);
339 /* TMP <- WORKER.TAIL
342 WORKER.TAIL <- TMP */
344 HOST_WIDE_INT worker_tail_offset
=
345 tree_to_shwi (DECL_FIELD_OFFSET (cilk_trees
[CILK_TI_WORKER_TAIL
])) +
346 tree_to_shwi (DECL_FIELD_BIT_OFFSET (cilk_trees
[CILK_TI_WORKER_TAIL
])) /
348 rtx tmem0
= gen_rtx_MEM (Pmode
,
349 plus_constant (Pmode
, wreg
, worker_tail_offset
));
350 set_mem_attributes (tmem0
, tail
, 0);
351 MEM_NOTRAP_P (tmem0
) = 1;
352 gcc_assert (MEM_VOLATILE_P (tmem0
));
353 rtx treg
= copy_to_mode_reg (Pmode
, tmem0
);
354 rtx tmem1
= gen_rtx_MEM (Pmode
, treg
);
355 set_mem_attributes (tmem1
, TREE_TYPE (TREE_TYPE (tail
)), 0);
356 MEM_NOTRAP_P (tmem1
) = 1;
357 emit_move_insn (tmem1
, preg
);
358 emit_move_insn (treg
, plus_constant (Pmode
, treg
, GET_MODE_SIZE (Pmode
)));
360 /* There is a release barrier (st8.rel, membar #StoreStore,
361 sfence, lwsync, etc.) between the two stores. On x86
362 normal volatile stores have proper semantics; the sfence
363 would only be needed for nontemporal stores (which we
364 could generate using the storent optab, for no benefit
367 The predicate may return false even for a REG if this is
368 the limited release operation that only stores 0. */
369 enum insn_code icode
= direct_optab_handler (sync_lock_release_optab
, Pmode
);
370 if (icode
!= CODE_FOR_nothing
371 && insn_data
[icode
].operand
[1].predicate (treg
, Pmode
)
372 && (insn
= GEN_FCN (icode
) (tmem0
, treg
)) != NULL_RTX
)
375 emit_move_insn (tmem0
, treg
);
377 /* The memory barrier inserted above should not prevent
378 the load of flags from being moved before the stores,
379 but in practice it does because it is implemented with
380 unspec_volatile. In-order RISC machines should
381 explicitly load flags earlier. */
383 tree flags
= cilk_dot (fptr
, CILK_TI_FRAME_FLAGS
, 0);
384 expand_expr (build2 (MODIFY_EXPR
, void_type_node
, flags
,
385 build2 (BIT_IOR_EXPR
, TREE_TYPE (flags
), flags
,
386 build_int_cst (TREE_TYPE (flags
),
387 CILK_FRAME_DETACHED
))),
388 const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
391 /* Returns a setjmp CALL_EXPR with FRAME->context as its parameter. */
394 cilk_call_setjmp (tree frame
)
396 tree c
= cilk_dot (frame
, CILK_TI_FRAME_CONTEXT
, false);
397 c
= build1 (ADDR_EXPR
, build_pointer_type (ptr_type_node
), c
);
398 return build_call_expr (builtin_decl_implicit (BUILT_IN_SETJMP
), 1, c
);
401 /* This function will expand the _Cilk_sync keyword. */
404 expand_cilk_sync (void)
406 tree frame
= cfun
->cilk_frame_decl
;
408 /* Cilk_sync is converted to the following code:
410 sf.pedigree = sf.worker->pedigree;
411 if (frame.flags & CILK_FRAME_UNSYNCHED)
413 __cilkrts_save_fp_state (&sf);
414 if (!builtin_setjmp (sf.ctx)
415 __cilkrts_sync (&sf);
417 if (sf.flags & CILK_FRAME_EXCEPTING)
418 __cilkrts_rethrow (&sf);
420 sf.worker->pedigree.rank = sf.worker->pedigree.rank + 1; */
422 tree flags
= cilk_dot (frame
, CILK_TI_FRAME_FLAGS
, false);
424 tree unsynched
= fold_build2 (BIT_AND_EXPR
, TREE_TYPE (flags
), flags
,
425 build_int_cst (TREE_TYPE (flags
),
426 CILK_FRAME_UNSYNCHED
));
428 unsynched
= fold_build2 (NE_EXPR
, TREE_TYPE (unsynched
), unsynched
,
429 build_int_cst (TREE_TYPE (unsynched
), 0));
431 tree frame_addr
= build1 (ADDR_EXPR
, cilk_frame_ptr_type_decl
, frame
);
433 /* Check if exception (0x10) bit is set in the sf->flags. */
434 tree except_flag
= fold_build2 (BIT_AND_EXPR
, TREE_TYPE (flags
), flags
,
435 build_int_cst (TREE_TYPE (flags
),
436 CILK_FRAME_EXCEPTING
));
437 except_flag
= fold_build2 (NE_EXPR
, TREE_TYPE (except_flag
), except_flag
,
438 build_int_cst (TREE_TYPE (except_flag
), 0));
440 /* If the exception flag is set then call the __cilkrts_rethrow (&sf). */
441 tree except_cond
= fold_build3 (COND_EXPR
, void_type_node
, except_flag
,
442 build_call_expr (cilk_rethrow_fndecl
, 1,
444 build_empty_stmt (EXPR_LOCATION (unsynched
)));
446 tree sync_expr
= build_call_expr (cilk_sync_fndecl
, 1, frame_addr
);
447 tree setjmp_expr
= cilk_call_setjmp (frame
);
448 setjmp_expr
= fold_build2 (EQ_EXPR
, TREE_TYPE (setjmp_expr
), setjmp_expr
,
449 build_int_cst (TREE_TYPE (setjmp_expr
), 0));
451 setjmp_expr
= fold_build3 (COND_EXPR
, void_type_node
, setjmp_expr
,
452 sync_expr
, except_cond
);
453 tree sync_list
= alloc_stmt_list ();
454 append_to_statement_list (build_call_expr (cilk_save_fp_fndecl
, 1,
455 frame_addr
), &sync_list
);
456 append_to_statement_list (setjmp_expr
, &sync_list
);
457 tree sync
= fold_build3 (COND_EXPR
, void_type_node
, unsynched
, sync_list
,
458 build_empty_stmt (EXPR_LOCATION (unsynched
)));
459 tree parent_pedigree
= cilk_dot (frame
, CILK_TI_FRAME_PEDIGREE
, false);
460 tree worker
= cilk_dot (frame
, CILK_TI_FRAME_WORKER
, false);
461 tree worker_pedigree
= cilk_arrow (worker
, CILK_TI_WORKER_PEDIGREE
, false);
462 tree assign_pedigree
= fold_build2 (MODIFY_EXPR
, void_type_node
,
463 parent_pedigree
, worker_pedigree
);
464 tree w_ped_rank
= cilk_dot (unshare_expr (worker_pedigree
),
465 CILK_TI_PEDIGREE_RANK
, false);
466 tree incr_ped_rank
= fold_build2 (PLUS_EXPR
, TREE_TYPE (w_ped_rank
),
468 build_one_cst (TREE_TYPE (w_ped_rank
)));
469 incr_ped_rank
= fold_build2 (MODIFY_EXPR
, void_type_node
, w_ped_rank
,
471 tree ret_sync_exp
= alloc_stmt_list ();
472 append_to_statement_list (assign_pedigree
, &ret_sync_exp
);
473 append_to_statement_list (sync
, &ret_sync_exp
);
474 append_to_statement_list (incr_ped_rank
, &ret_sync_exp
);
478 /* Gimplifies the cilk_sync expression passed in *EXPR_P. Returns GS_ALL_DONE
482 gimplify_cilk_sync (tree
*expr_p
, gimple_seq
*pre_p
)
484 tree sync_expr
= expand_cilk_sync ();
486 gimplify_and_add (sync_expr
, pre_p
);