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"
31 #include "insn-codes.h"
34 #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 (build_simple_mem_ref (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. */
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
;
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. */
93 install_builtin (const char *name
, tree fntype
, enum built_in_function code
,
96 tree fndecl
= build_fn_decl (name
, fntype
);
97 DECL_BUILT_IN_CLASS (fndecl
) = BUILT_IN_NORMAL
;
98 DECL_FUNCTION_CODE (fndecl
) = code
;
101 tree t
= lang_hooks
.decls
.pushdecl (fndecl
);
105 set_builtin_decl (code
, fndecl
, true);
109 /* Returns a FUNCTION_DECL of type TYPE whose name is *NAME. */
112 declare_cilk_for_builtin (const char *name
, tree type
,
113 enum built_in_function code
)
117 cb
= build_function_type_list (void_type_node
,
118 ptr_type_node
, type
, type
,
120 cb
= build_pointer_type (cb
);
121 ft
= build_function_type_list (void_type_node
,
122 cb
, ptr_type_node
, type
,
123 integer_type_node
, NULL_TREE
);
124 fn
= install_builtin (name
, ft
, code
, false);
125 TREE_NOTHROW (fn
) = 0;
130 /* Creates and initializes all the built-in Cilk keywords functions and three
131 structures: __cilkrts_stack_frame, __cilkrts_pedigree and __cilkrts_worker.
132 Detailed information about __cilkrts_stack_frame and
133 __cilkrts_worker structures are given in libcilkrts/include/internal/abi.h.
134 __cilkrts_pedigree is described in libcilkrts/include/cilk/common.h. */
137 cilk_init_builtins (void)
139 /* Now build the following __cilkrts_pedigree struct:
140 struct __cilkrts_pedigree {
142 struct __cilkrts_pedigree *parent;
145 tree pedigree_type
= lang_hooks
.types
.make_type (RECORD_TYPE
);
146 tree pedigree_ptr
= build_pointer_type (pedigree_type
);
147 tree field
= add_field ("rank", uint64_type_node
, NULL_TREE
);
148 cilk_trees
[CILK_TI_PEDIGREE_RANK
] = field
;
149 field
= add_field ("parent", pedigree_ptr
, field
);
150 cilk_trees
[CILK_TI_PEDIGREE_PARENT
] = field
;
151 finish_builtin_struct (pedigree_type
, "__cilkrts_pedigree_GCC", field
,
153 lang_hooks
.types
.register_builtin_type (pedigree_type
,
154 "__cilkrts_pedigree_t");
155 cilk_pedigree_type_decl
= pedigree_type
;
157 /* Build the Cilk Stack Frame:
158 struct __cilkrts_stack_frame {
161 struct __cilkrts_stack_frame *call_parent;
162 __cilkrts_worker *worker;
168 __cilkrts_pedigree pedigree;
171 tree frame
= lang_hooks
.types
.make_type (RECORD_TYPE
);
172 tree frame_ptr
= build_pointer_type (frame
);
173 tree worker_type
= lang_hooks
.types
.make_type (RECORD_TYPE
);
174 tree worker_ptr
= build_pointer_type (worker_type
);
175 tree s_type_node
= build_int_cst (size_type_node
, 4);
177 tree flags
= add_field ("flags", uint32_type_node
, NULL_TREE
);
178 tree size
= add_field ("size", uint32_type_node
, flags
);
179 tree parent
= add_field ("call_parent", frame_ptr
, size
);
180 tree worker
= add_field ("worker", worker_ptr
, parent
);
181 tree except
= add_field ("except_data", frame_ptr
, worker
);
182 tree context
= add_field ("ctx",
183 build_array_type (ptr_type_node
,
184 build_index_type (s_type_node
)),
186 tree mxcsr
= add_field ("mxcsr", uint32_type_node
, context
);
187 tree fpcsr
= add_field ("fpcsr", uint16_type_node
, mxcsr
);
188 tree reserved
= add_field ("reserved", uint16_type_node
, fpcsr
);
189 tree pedigree
= add_field ("pedigree", pedigree_type
, reserved
);
191 /* Now add them to a common structure whose fields are #defined to something
192 that is used at a later stage. */
193 cilk_trees
[CILK_TI_FRAME_FLAGS
] = flags
;
194 cilk_trees
[CILK_TI_FRAME_PARENT
] = parent
;
195 cilk_trees
[CILK_TI_FRAME_WORKER
] = worker
;
196 cilk_trees
[CILK_TI_FRAME_EXCEPTION
] = except
;
197 cilk_trees
[CILK_TI_FRAME_CONTEXT
] = context
;
198 /* We don't care about reserved, so no need to store it in cilk_trees. */
199 cilk_trees
[CILK_TI_FRAME_PEDIGREE
] = pedigree
;
200 TREE_ADDRESSABLE (frame
) = 1;
202 finish_builtin_struct (frame
, "__cilkrts_st_frame_GCC", pedigree
, NULL_TREE
);
203 cilk_frame_type_decl
= frame
;
204 lang_hooks
.types
.register_builtin_type (frame
, "__cilkrts_frame_t");
206 cilk_frame_ptr_type_decl
= build_qualified_type (frame_ptr
,
208 /* Now let's do the following worker struct:
210 struct __cilkrts_worker {
211 __cilkrts_stack_frame *volatile *volatile tail;
212 __cilkrts_stack_frame *volatile *volatile head;
213 __cilkrts_stack_frame *volatile *volatile exc;
214 __cilkrts_stack_frame *volatile *volatile protected_tail;
215 __cilkrts_stack_frame *volatile *ltq_limit;
219 cilkred_map *reducer_map;
220 __cilkrts_stack_frame *current_stack_frame;
222 __cilkrts_worker_sysdep_state *sysdep;
223 __cilkrts_pedigree pedigree;
226 tree fptr_volatil_type
= build_qualified_type (frame_ptr
, TYPE_QUAL_VOLATILE
);
227 tree fptr_volatile_ptr
= build_pointer_type (fptr_volatil_type
);
228 tree fptr_vol_ptr_vol
= build_qualified_type (fptr_volatile_ptr
,
230 tree g
= lang_hooks
.types
.make_type (RECORD_TYPE
);
231 finish_builtin_struct (g
, "__cilkrts_global_state", NULL_TREE
, NULL_TREE
);
232 tree l
= lang_hooks
.types
.make_type (RECORD_TYPE
);
233 finish_builtin_struct (l
, "__cilkrts_local_state", NULL_TREE
, NULL_TREE
);
234 tree sysdep_t
= lang_hooks
.types
.make_type (RECORD_TYPE
);
235 finish_builtin_struct (sysdep_t
, "__cilkrts_worker_sysdep_state", NULL_TREE
,
238 field
= add_field ("tail", fptr_vol_ptr_vol
, NULL_TREE
);
239 cilk_trees
[CILK_TI_WORKER_TAIL
] = field
;
240 field
= add_field ("head", fptr_vol_ptr_vol
, field
);
241 field
= add_field ("exc", fptr_vol_ptr_vol
, field
);
242 field
= add_field ("protected_tail", fptr_vol_ptr_vol
, field
);
243 field
= add_field ("ltq_limit", fptr_volatile_ptr
, field
);
244 field
= add_field ("self", integer_type_node
, field
);
245 field
= add_field ("g", build_pointer_type (g
), field
);
246 field
= add_field ("l", build_pointer_type (g
), field
);
247 field
= add_field ("reducer_map", ptr_type_node
, field
);
248 field
= add_field ("current_stack_frame", frame_ptr
, field
);
249 cilk_trees
[CILK_TI_WORKER_CUR
] = field
;
250 field
= add_field ("saved_protected_tail", fptr_volatile_ptr
, field
);
251 field
= add_field ("sysdep", build_pointer_type (sysdep_t
), field
);
252 field
= add_field ("pedigree", pedigree_type
, field
);
253 cilk_trees
[CILK_TI_WORKER_PEDIGREE
] = field
;
254 finish_builtin_struct (worker_type
, "__cilkrts_worker_GCC", field
,
257 tree fptr_arglist
= tree_cons (NULL_TREE
, frame_ptr
, void_list_node
);
258 tree fptr_fun
= build_function_type (void_type_node
, fptr_arglist
);
260 /* void __cilkrts_enter_frame_1 (__cilkrts_stack_frame *); */
261 cilk_enter_fndecl
= install_builtin ("__cilkrts_enter_frame_1", fptr_fun
,
262 BUILT_IN_CILK_ENTER_FRAME
, false);
264 /* void __cilkrts_enter_frame_fast_1 (__cilkrts_stack_frame *); */
265 cilk_enter_fast_fndecl
=
266 install_builtin ("__cilkrts_enter_frame_fast_1", fptr_fun
,
267 BUILT_IN_CILK_ENTER_FRAME_FAST
, false);
269 /* void __cilkrts_pop_frame (__cilkrts_stack_frame *); */
270 cilk_pop_fndecl
= install_builtin ("__cilkrts_pop_frame", fptr_fun
,
271 BUILT_IN_CILK_POP_FRAME
, false);
273 /* void __cilkrts_leave_frame (__cilkrts_stack_frame *); */
274 cilk_leave_fndecl
= install_builtin ("__cilkrts_leave_frame", fptr_fun
,
275 BUILT_IN_CILK_LEAVE_FRAME
, false);
277 /* void __cilkrts_sync (__cilkrts_stack_frame *); */
278 cilk_sync_fndecl
= install_builtin ("__cilkrts_sync", fptr_fun
,
279 BUILT_IN_CILK_SYNC
, false);
281 /* void __cilkrts_detach (__cilkrts_stack_frame *); */
282 cilk_detach_fndecl
= install_builtin ("__cilkrts_detach", fptr_fun
,
283 BUILT_IN_CILK_DETACH
, false);
285 /* __cilkrts_rethrow (struct stack_frame *); */
286 cilk_rethrow_fndecl
= install_builtin ("__cilkrts_rethrow", fptr_fun
,
287 BUILT_IN_CILK_RETHROW
, false);
288 TREE_NOTHROW (cilk_rethrow_fndecl
) = 0;
290 /* __cilkrts_save_fp_ctrl_state (__cilkrts_stack_frame *); */
291 cilk_save_fp_fndecl
= install_builtin ("__cilkrts_save_fp_ctrl_state",
292 fptr_fun
, BUILT_IN_CILK_SAVE_FP
,
294 /* __cilkrts_cilk_for_32 (...); */
295 cilk_for_32_fndecl
= declare_cilk_for_builtin ("__cilkrts_cilk_for_32",
296 unsigned_intSI_type_node
,
297 BUILT_IN_CILK_FOR_32
);
298 /* __cilkrts_cilk_for_64 (...); */
299 cilk_for_64_fndecl
= declare_cilk_for_builtin ("__cilkrts_cilk_for_64",
300 unsigned_intDI_type_node
,
301 BUILT_IN_CILK_FOR_64
);
304 /* Get the appropriate frame arguments for CALL that is of type CALL_EXPR. */
307 get_frame_arg (tree call
)
311 gcc_assert (call_expr_nargs (call
) >= 1);
313 arg
= CALL_EXPR_ARG (call
, 0);
314 argtype
= TREE_TYPE (arg
);
315 gcc_assert (TREE_CODE (argtype
) == POINTER_TYPE
);
317 argtype
= TREE_TYPE (argtype
);
319 /* If it is passed in as an address, then just use the value directly
320 since the function is inlined. */
321 if (TREE_CODE (arg
) == ADDR_EXPR
)
322 return TREE_OPERAND (arg
, 0);
326 /* Expands the __cilkrts_pop_frame function call stored in EXP. */
329 expand_builtin_cilk_pop_frame (tree exp
)
331 tree frame
= get_frame_arg (exp
);
332 tree parent
= cilk_dot (frame
, CILK_TI_FRAME_PARENT
, 0);
334 tree clear_parent
= build2 (MODIFY_EXPR
, void_type_node
, parent
,
335 build_int_cst (TREE_TYPE (parent
), 0));
336 expand_expr (clear_parent
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
338 /* During LTO, the is_cilk_function flag gets cleared.
339 If __cilkrts_pop_frame is called, then this definitely must be a
342 cfun
->is_cilk_function
= 1;
345 /* Expands the cilk_detach function call stored in EXP. */
348 expand_builtin_cilk_detach (tree exp
)
351 tree fptr
= get_frame_arg (exp
);
353 if (fptr
== NULL_TREE
)
356 tree parent
= cilk_dot (fptr
, CILK_TI_FRAME_PARENT
, 0);
357 tree worker
= cilk_dot (fptr
, CILK_TI_FRAME_WORKER
, 0);
358 tree tail
= cilk_arrow (worker
, CILK_TI_WORKER_TAIL
, 1);
360 rtx wreg
= expand_expr (worker
, NULL_RTX
, Pmode
, EXPAND_NORMAL
);
361 if (GET_CODE (wreg
) != REG
)
362 wreg
= copy_to_reg (wreg
);
363 rtx preg
= expand_expr (parent
, NULL_RTX
, Pmode
, EXPAND_NORMAL
);
365 /* TMP <- WORKER.TAIL
368 WORKER.TAIL <- TMP */
370 HOST_WIDE_INT worker_tail_offset
=
371 tree_to_shwi (DECL_FIELD_OFFSET (cilk_trees
[CILK_TI_WORKER_TAIL
])) +
372 tree_to_shwi (DECL_FIELD_BIT_OFFSET (cilk_trees
[CILK_TI_WORKER_TAIL
])) /
374 rtx tmem0
= gen_rtx_MEM (Pmode
,
375 plus_constant (Pmode
, wreg
, worker_tail_offset
));
376 set_mem_attributes (tmem0
, tail
, 0);
377 MEM_NOTRAP_P (tmem0
) = 1;
378 gcc_assert (MEM_VOLATILE_P (tmem0
));
379 rtx treg
= copy_to_mode_reg (Pmode
, tmem0
);
380 rtx tmem1
= gen_rtx_MEM (Pmode
, treg
);
381 set_mem_attributes (tmem1
, TREE_TYPE (TREE_TYPE (tail
)), 0);
382 MEM_NOTRAP_P (tmem1
) = 1;
383 emit_move_insn (tmem1
, preg
);
384 emit_move_insn (treg
, plus_constant (Pmode
, treg
, GET_MODE_SIZE (Pmode
)));
386 /* There is a release barrier (st8.rel, membar #StoreStore,
387 sfence, lwsync, etc.) between the two stores. On x86
388 normal volatile stores have proper semantics; the sfence
389 would only be needed for nontemporal stores (which we
390 could generate using the storent optab, for no benefit
393 The predicate may return false even for a REG if this is
394 the limited release operation that only stores 0. */
395 enum insn_code icode
= direct_optab_handler (sync_lock_release_optab
, Pmode
);
396 if (icode
!= CODE_FOR_nothing
397 && insn_data
[icode
].operand
[1].predicate (treg
, Pmode
)
398 && (insn
= GEN_FCN (icode
) (tmem0
, treg
)) != NULL_RTX
)
401 emit_move_insn (tmem0
, treg
);
403 /* The memory barrier inserted above should not prevent
404 the load of flags from being moved before the stores,
405 but in practice it does because it is implemented with
406 unspec_volatile. In-order RISC machines should
407 explicitly load flags earlier. */
409 tree flags
= cilk_dot (fptr
, CILK_TI_FRAME_FLAGS
, 0);
410 expand_expr (build2 (MODIFY_EXPR
, void_type_node
, flags
,
411 build2 (BIT_IOR_EXPR
, TREE_TYPE (flags
), flags
,
412 build_int_cst (TREE_TYPE (flags
),
413 CILK_FRAME_DETACHED
))),
414 const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
417 /* Returns a setjmp CALL_EXPR with FRAME->context as its parameter. */
420 cilk_call_setjmp (tree frame
)
422 tree c
= cilk_dot (frame
, CILK_TI_FRAME_CONTEXT
, false);
423 c
= build1 (ADDR_EXPR
, build_pointer_type (ptr_type_node
), c
);
424 return build_call_expr (builtin_decl_implicit (BUILT_IN_SETJMP
), 1, c
);
427 /* This function will expand the _Cilk_sync keyword. */
430 expand_cilk_sync (void)
432 tree frame
= cfun
->cilk_frame_decl
;
434 /* Cilk_sync is converted to the following code:
436 sf.pedigree = sf.worker->pedigree;
437 if (frame.flags & CILK_FRAME_UNSYNCHED)
439 __cilkrts_save_fp_state (&sf);
440 if (!builtin_setjmp (sf.ctx)
441 __cilkrts_sync (&sf);
443 if (sf.flags & CILK_FRAME_EXCEPTING)
444 __cilkrts_rethrow (&sf);
446 sf.worker->pedigree.rank = sf.worker->pedigree.rank + 1; */
448 tree flags
= cilk_dot (frame
, CILK_TI_FRAME_FLAGS
, false);
450 tree unsynched
= fold_build2 (BIT_AND_EXPR
, TREE_TYPE (flags
), flags
,
451 build_int_cst (TREE_TYPE (flags
),
452 CILK_FRAME_UNSYNCHED
));
454 unsynched
= fold_build2 (NE_EXPR
, TREE_TYPE (unsynched
), unsynched
,
455 build_int_cst (TREE_TYPE (unsynched
), 0));
457 tree frame_addr
= build1 (ADDR_EXPR
, cilk_frame_ptr_type_decl
, frame
);
459 /* Check if exception (0x10) bit is set in the sf->flags. */
460 tree except_flag
= fold_build2 (BIT_AND_EXPR
, TREE_TYPE (flags
), flags
,
461 build_int_cst (TREE_TYPE (flags
),
462 CILK_FRAME_EXCEPTING
));
463 except_flag
= fold_build2 (NE_EXPR
, TREE_TYPE (except_flag
), except_flag
,
464 build_int_cst (TREE_TYPE (except_flag
), 0));
466 /* If the exception flag is set then call the __cilkrts_rethrow (&sf). */
467 tree except_cond
= fold_build3 (COND_EXPR
, void_type_node
, except_flag
,
468 build_call_expr (cilk_rethrow_fndecl
, 1,
470 build_empty_stmt (EXPR_LOCATION (unsynched
)));
472 tree sync_expr
= build_call_expr (cilk_sync_fndecl
, 1, frame_addr
);
473 tree setjmp_expr
= cilk_call_setjmp (frame
);
474 setjmp_expr
= fold_build2 (EQ_EXPR
, TREE_TYPE (setjmp_expr
), setjmp_expr
,
475 build_int_cst (TREE_TYPE (setjmp_expr
), 0));
477 setjmp_expr
= fold_build3 (COND_EXPR
, void_type_node
, setjmp_expr
,
478 sync_expr
, except_cond
);
479 tree sync_list
= alloc_stmt_list ();
480 append_to_statement_list (build_call_expr (cilk_save_fp_fndecl
, 1,
481 frame_addr
), &sync_list
);
482 append_to_statement_list (setjmp_expr
, &sync_list
);
483 tree sync
= fold_build3 (COND_EXPR
, void_type_node
, unsynched
, sync_list
,
484 build_empty_stmt (EXPR_LOCATION (unsynched
)));
485 tree parent_pedigree
= cilk_dot (frame
, CILK_TI_FRAME_PEDIGREE
, false);
486 tree worker
= cilk_dot (frame
, CILK_TI_FRAME_WORKER
, false);
487 tree worker_pedigree
= cilk_arrow (worker
, CILK_TI_WORKER_PEDIGREE
, false);
488 tree assign_pedigree
= fold_build2 (MODIFY_EXPR
, void_type_node
,
489 parent_pedigree
, worker_pedigree
);
490 tree w_ped_rank
= cilk_dot (unshare_expr (worker_pedigree
),
491 CILK_TI_PEDIGREE_RANK
, false);
492 tree incr_ped_rank
= fold_build2 (PLUS_EXPR
, TREE_TYPE (w_ped_rank
),
494 build_one_cst (TREE_TYPE (w_ped_rank
)));
495 incr_ped_rank
= fold_build2 (MODIFY_EXPR
, void_type_node
, w_ped_rank
,
497 tree ret_sync_exp
= alloc_stmt_list ();
498 append_to_statement_list (assign_pedigree
, &ret_sync_exp
);
499 append_to_statement_list (sync
, &ret_sync_exp
);
500 append_to_statement_list (incr_ped_rank
, &ret_sync_exp
);
504 /* Gimplifies the cilk_sync expression passed in *EXPR_P. Returns GS_ALL_DONE
508 gimplify_cilk_sync (tree
*expr_p
, gimple_seq
*pre_p
)
510 tree sync_expr
= expand_cilk_sync ();
512 gimplify_and_add (sync_expr
, pre_p
);