1 /* This file is part of the Intel(R) Cilk(TM) Plus support
2 This file contains the CilkPlus Intrinsics
3 Copyright (C) 2013-2015 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"
29 #include "fold-const.h"
30 #include "stringpool.h"
31 #include "stor-layout.h"
32 #include "langhooks.h"
37 #include "insn-config.h"
46 #include "insn-codes.h"
47 #include "optabs-query.h"
49 #include "tree-iterator.h"
53 /* This structure holds all the important fields of the internal structures,
54 internal built-in functions, and Cilk-specific data types. Explanation of
55 all the these fielsd are given in cilk.h. */
56 tree cilk_trees
[(int) CILK_TI_MAX
];
58 /* Returns the value in structure FRAME pointed by the FIELD_NUMBER
60 FIELD_NUMBER is an index to the structure FRAME_PTR. For details
61 about these fields, refer to cilk_trees structure in cilk.h and
62 cilk_init_builtins function in this file. Returns a TREE that is the type
63 of the field represented by FIELD_NUMBER. If VOLATIL parameter is set
64 to true then the returning field is set as volatile. */
67 cilk_dot (tree frame
, int field_number
, bool volatil
)
69 tree field
= cilk_trees
[field_number
];
70 field
= fold_build3 (COMPONENT_REF
, TREE_TYPE (field
), frame
, field
,
72 TREE_THIS_VOLATILE (field
) = volatil
;
76 /* Returns the address of a field in FRAME_PTR, pointed by FIELD_NUMBER.
77 (e.g. (&X)->y). Please see cilk_dot function for explanation of the
78 FIELD_NUMBER. Returns a tree that is the type of the field represented
79 by FIELD_NUMBER. If VOLATIL parameter is set to true then the returning
80 field is set as volatile. */
83 cilk_arrow (tree frame_ptr
, int field_number
, bool volatil
)
85 return cilk_dot (build_simple_mem_ref (frame_ptr
),
86 field_number
, volatil
);
90 /* This function will add FIELD of type TYPE to a defined built-in
91 structure. *NAME is the name of the field to be added. */
94 add_field (const char *name
, tree type
, tree fields
)
96 tree t
= get_identifier (name
);
97 tree field
= build_decl (BUILTINS_LOCATION
, FIELD_DECL
, t
, type
);
98 TREE_CHAIN (field
) = fields
;
102 /* This function will define a built-in function of NAME, of type FNTYPE and
103 register it under the built-in function code CODE. If PUBLISH is set then
104 the declaration is pushed into the declaration list. CODE is the index
105 to the cilk_trees array. *NAME is the name of the function to be added. */
108 install_builtin (const char *name
, tree fntype
, enum built_in_function code
,
111 tree fndecl
= build_fn_decl (name
, fntype
);
112 DECL_BUILT_IN_CLASS (fndecl
) = BUILT_IN_NORMAL
;
113 DECL_FUNCTION_CODE (fndecl
) = code
;
116 tree t
= lang_hooks
.decls
.pushdecl (fndecl
);
120 set_builtin_decl (code
, fndecl
, true);
124 /* Returns a FUNCTION_DECL of type TYPE whose name is *NAME. */
127 declare_cilk_for_builtin (const char *name
, tree type
,
128 enum built_in_function code
)
132 cb
= build_function_type_list (void_type_node
,
133 ptr_type_node
, type
, type
,
135 cb
= build_pointer_type (cb
);
136 ft
= build_function_type_list (void_type_node
,
137 cb
, ptr_type_node
, type
,
138 integer_type_node
, NULL_TREE
);
139 fn
= install_builtin (name
, ft
, code
, false);
140 TREE_NOTHROW (fn
) = 0;
145 /* Creates and initializes all the built-in Cilk keywords functions and three
146 structures: __cilkrts_stack_frame, __cilkrts_pedigree and __cilkrts_worker.
147 Detailed information about __cilkrts_stack_frame and
148 __cilkrts_worker structures are given in libcilkrts/include/internal/abi.h.
149 __cilkrts_pedigree is described in libcilkrts/include/cilk/common.h. */
152 cilk_init_builtins (void)
154 /* Now build the following __cilkrts_pedigree struct:
155 struct __cilkrts_pedigree {
157 struct __cilkrts_pedigree *parent;
160 tree pedigree_type
= lang_hooks
.types
.make_type (RECORD_TYPE
);
161 tree pedigree_ptr
= build_pointer_type (pedigree_type
);
162 tree field
= add_field ("rank", uint64_type_node
, NULL_TREE
);
163 cilk_trees
[CILK_TI_PEDIGREE_RANK
] = field
;
164 field
= add_field ("parent", pedigree_ptr
, field
);
165 cilk_trees
[CILK_TI_PEDIGREE_PARENT
] = field
;
166 finish_builtin_struct (pedigree_type
, "__cilkrts_pedigree_GCC", field
,
168 lang_hooks
.types
.register_builtin_type (pedigree_type
,
169 "__cilkrts_pedigree_t");
170 cilk_pedigree_type_decl
= pedigree_type
;
172 /* Build the Cilk Stack Frame:
173 struct __cilkrts_stack_frame {
176 struct __cilkrts_stack_frame *call_parent;
177 __cilkrts_worker *worker;
183 __cilkrts_pedigree pedigree;
186 tree frame
= lang_hooks
.types
.make_type (RECORD_TYPE
);
187 tree frame_ptr
= build_pointer_type (frame
);
188 tree worker_type
= lang_hooks
.types
.make_type (RECORD_TYPE
);
189 tree worker_ptr
= build_pointer_type (worker_type
);
190 tree s_type_node
= build_int_cst (size_type_node
, 4);
192 tree flags
= add_field ("flags", uint32_type_node
, NULL_TREE
);
193 tree size
= add_field ("size", uint32_type_node
, flags
);
194 tree parent
= add_field ("call_parent", frame_ptr
, size
);
195 tree worker
= add_field ("worker", worker_ptr
, parent
);
196 tree except
= add_field ("except_data", frame_ptr
, worker
);
197 tree context
= add_field ("ctx",
198 build_array_type (ptr_type_node
,
199 build_index_type (s_type_node
)),
201 tree mxcsr
= add_field ("mxcsr", uint32_type_node
, context
);
202 tree fpcsr
= add_field ("fpcsr", uint16_type_node
, mxcsr
);
203 tree reserved
= add_field ("reserved", uint16_type_node
, fpcsr
);
204 tree pedigree
= add_field ("pedigree", pedigree_type
, reserved
);
206 /* Now add them to a common structure whose fields are #defined to something
207 that is used at a later stage. */
208 cilk_trees
[CILK_TI_FRAME_FLAGS
] = flags
;
209 cilk_trees
[CILK_TI_FRAME_PARENT
] = parent
;
210 cilk_trees
[CILK_TI_FRAME_WORKER
] = worker
;
211 cilk_trees
[CILK_TI_FRAME_EXCEPTION
] = except
;
212 cilk_trees
[CILK_TI_FRAME_CONTEXT
] = context
;
213 /* We don't care about reserved, so no need to store it in cilk_trees. */
214 cilk_trees
[CILK_TI_FRAME_PEDIGREE
] = pedigree
;
215 TREE_ADDRESSABLE (frame
) = 1;
217 finish_builtin_struct (frame
, "__cilkrts_st_frame_GCC", pedigree
, NULL_TREE
);
218 cilk_frame_type_decl
= frame
;
219 lang_hooks
.types
.register_builtin_type (frame
, "__cilkrts_frame_t");
221 cilk_frame_ptr_type_decl
= build_qualified_type (frame_ptr
,
223 /* Now let's do the following worker struct:
225 struct __cilkrts_worker {
226 __cilkrts_stack_frame *volatile *volatile tail;
227 __cilkrts_stack_frame *volatile *volatile head;
228 __cilkrts_stack_frame *volatile *volatile exc;
229 __cilkrts_stack_frame *volatile *volatile protected_tail;
230 __cilkrts_stack_frame *volatile *ltq_limit;
234 cilkred_map *reducer_map;
235 __cilkrts_stack_frame *current_stack_frame;
237 __cilkrts_worker_sysdep_state *sysdep;
238 __cilkrts_pedigree pedigree;
241 tree fptr_volatil_type
= build_qualified_type (frame_ptr
, TYPE_QUAL_VOLATILE
);
242 tree fptr_volatile_ptr
= build_pointer_type (fptr_volatil_type
);
243 tree fptr_vol_ptr_vol
= build_qualified_type (fptr_volatile_ptr
,
245 tree g
= lang_hooks
.types
.make_type (RECORD_TYPE
);
246 finish_builtin_struct (g
, "__cilkrts_global_state", NULL_TREE
, NULL_TREE
);
247 tree l
= lang_hooks
.types
.make_type (RECORD_TYPE
);
248 finish_builtin_struct (l
, "__cilkrts_local_state", NULL_TREE
, NULL_TREE
);
249 tree sysdep_t
= lang_hooks
.types
.make_type (RECORD_TYPE
);
250 finish_builtin_struct (sysdep_t
, "__cilkrts_worker_sysdep_state", NULL_TREE
,
253 field
= add_field ("tail", fptr_vol_ptr_vol
, NULL_TREE
);
254 cilk_trees
[CILK_TI_WORKER_TAIL
] = field
;
255 field
= add_field ("head", fptr_vol_ptr_vol
, field
);
256 field
= add_field ("exc", fptr_vol_ptr_vol
, field
);
257 field
= add_field ("protected_tail", fptr_vol_ptr_vol
, field
);
258 field
= add_field ("ltq_limit", fptr_volatile_ptr
, field
);
259 field
= add_field ("self", integer_type_node
, field
);
260 field
= add_field ("g", build_pointer_type (g
), field
);
261 field
= add_field ("l", build_pointer_type (g
), field
);
262 field
= add_field ("reducer_map", ptr_type_node
, field
);
263 field
= add_field ("current_stack_frame", frame_ptr
, field
);
264 cilk_trees
[CILK_TI_WORKER_CUR
] = field
;
265 field
= add_field ("saved_protected_tail", fptr_volatile_ptr
, field
);
266 field
= add_field ("sysdep", build_pointer_type (sysdep_t
), field
);
267 field
= add_field ("pedigree", pedigree_type
, field
);
268 cilk_trees
[CILK_TI_WORKER_PEDIGREE
] = field
;
269 finish_builtin_struct (worker_type
, "__cilkrts_worker_GCC", field
,
272 tree fptr_arglist
= tree_cons (NULL_TREE
, frame_ptr
, void_list_node
);
273 tree fptr_fun
= build_function_type (void_type_node
, fptr_arglist
);
275 /* void __cilkrts_enter_frame_1 (__cilkrts_stack_frame *); */
276 cilk_enter_fndecl
= install_builtin ("__cilkrts_enter_frame_1", fptr_fun
,
277 BUILT_IN_CILK_ENTER_FRAME
, false);
279 /* void __cilkrts_enter_frame_fast_1 (__cilkrts_stack_frame *); */
280 cilk_enter_fast_fndecl
=
281 install_builtin ("__cilkrts_enter_frame_fast_1", fptr_fun
,
282 BUILT_IN_CILK_ENTER_FRAME_FAST
, false);
284 /* void __cilkrts_pop_frame (__cilkrts_stack_frame *); */
285 cilk_pop_fndecl
= install_builtin ("__cilkrts_pop_frame", fptr_fun
,
286 BUILT_IN_CILK_POP_FRAME
, false);
288 /* void __cilkrts_leave_frame (__cilkrts_stack_frame *); */
289 cilk_leave_fndecl
= install_builtin ("__cilkrts_leave_frame", fptr_fun
,
290 BUILT_IN_CILK_LEAVE_FRAME
, false);
292 /* void __cilkrts_sync (__cilkrts_stack_frame *); */
293 cilk_sync_fndecl
= install_builtin ("__cilkrts_sync", fptr_fun
,
294 BUILT_IN_CILK_SYNC
, false);
296 /* void __cilkrts_detach (__cilkrts_stack_frame *); */
297 cilk_detach_fndecl
= install_builtin ("__cilkrts_detach", fptr_fun
,
298 BUILT_IN_CILK_DETACH
, false);
300 /* __cilkrts_rethrow (struct stack_frame *); */
301 cilk_rethrow_fndecl
= install_builtin ("__cilkrts_rethrow", fptr_fun
,
302 BUILT_IN_CILK_RETHROW
, false);
303 TREE_NOTHROW (cilk_rethrow_fndecl
) = 0;
305 /* __cilkrts_save_fp_ctrl_state (__cilkrts_stack_frame *); */
306 cilk_save_fp_fndecl
= install_builtin ("__cilkrts_save_fp_ctrl_state",
307 fptr_fun
, BUILT_IN_CILK_SAVE_FP
,
309 /* __cilkrts_cilk_for_32 (...); */
310 cilk_for_32_fndecl
= declare_cilk_for_builtin ("__cilkrts_cilk_for_32",
311 unsigned_intSI_type_node
,
312 BUILT_IN_CILK_FOR_32
);
313 /* __cilkrts_cilk_for_64 (...); */
314 cilk_for_64_fndecl
= declare_cilk_for_builtin ("__cilkrts_cilk_for_64",
315 unsigned_intDI_type_node
,
316 BUILT_IN_CILK_FOR_64
);
319 /* Get the appropriate frame arguments for CALL that is of type CALL_EXPR. */
322 get_frame_arg (tree call
)
326 gcc_assert (call_expr_nargs (call
) >= 1);
328 arg
= CALL_EXPR_ARG (call
, 0);
329 argtype
= TREE_TYPE (arg
);
330 gcc_assert (TREE_CODE (argtype
) == POINTER_TYPE
);
332 argtype
= TREE_TYPE (argtype
);
334 /* If it is passed in as an address, then just use the value directly
335 since the function is inlined. */
336 if (TREE_CODE (arg
) == ADDR_EXPR
)
337 return TREE_OPERAND (arg
, 0);
341 /* Expands the __cilkrts_pop_frame function call stored in EXP. */
344 expand_builtin_cilk_pop_frame (tree exp
)
346 tree frame
= get_frame_arg (exp
);
347 tree parent
= cilk_dot (frame
, CILK_TI_FRAME_PARENT
, 0);
349 tree clear_parent
= build2 (MODIFY_EXPR
, void_type_node
, parent
,
350 build_int_cst (TREE_TYPE (parent
), 0));
351 expand_expr (clear_parent
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
353 /* During LTO, the is_cilk_function flag gets cleared.
354 If __cilkrts_pop_frame is called, then this definitely must be a
357 cfun
->is_cilk_function
= 1;
360 /* Expands the cilk_detach function call stored in EXP. */
363 expand_builtin_cilk_detach (tree exp
)
366 tree fptr
= get_frame_arg (exp
);
368 if (fptr
== NULL_TREE
)
371 tree parent
= cilk_dot (fptr
, CILK_TI_FRAME_PARENT
, 0);
372 tree worker
= cilk_dot (fptr
, CILK_TI_FRAME_WORKER
, 0);
373 tree tail
= cilk_arrow (worker
, CILK_TI_WORKER_TAIL
, 1);
375 rtx wreg
= expand_expr (worker
, NULL_RTX
, Pmode
, EXPAND_NORMAL
);
376 if (GET_CODE (wreg
) != REG
)
377 wreg
= copy_to_reg (wreg
);
378 rtx preg
= expand_expr (parent
, NULL_RTX
, Pmode
, EXPAND_NORMAL
);
380 /* TMP <- WORKER.TAIL
383 WORKER.TAIL <- TMP */
385 HOST_WIDE_INT worker_tail_offset
=
386 tree_to_shwi (DECL_FIELD_OFFSET (cilk_trees
[CILK_TI_WORKER_TAIL
])) +
387 tree_to_shwi (DECL_FIELD_BIT_OFFSET (cilk_trees
[CILK_TI_WORKER_TAIL
])) /
389 rtx tmem0
= gen_rtx_MEM (Pmode
,
390 plus_constant (Pmode
, wreg
, worker_tail_offset
));
391 set_mem_attributes (tmem0
, tail
, 0);
392 MEM_NOTRAP_P (tmem0
) = 1;
393 gcc_assert (MEM_VOLATILE_P (tmem0
));
394 rtx treg
= copy_to_mode_reg (Pmode
, tmem0
);
395 rtx tmem1
= gen_rtx_MEM (Pmode
, treg
);
396 set_mem_attributes (tmem1
, TREE_TYPE (TREE_TYPE (tail
)), 0);
397 MEM_NOTRAP_P (tmem1
) = 1;
398 emit_move_insn (tmem1
, preg
);
399 emit_move_insn (treg
, plus_constant (Pmode
, treg
, GET_MODE_SIZE (Pmode
)));
401 /* There is a release barrier (st8.rel, membar #StoreStore,
402 sfence, lwsync, etc.) between the two stores. On x86
403 normal volatile stores have proper semantics; the sfence
404 would only be needed for nontemporal stores (which we
405 could generate using the storent optab, for no benefit
408 The predicate may return false even for a REG if this is
409 the limited release operation that only stores 0. */
410 enum insn_code icode
= direct_optab_handler (sync_lock_release_optab
, Pmode
);
411 if (icode
!= CODE_FOR_nothing
412 && insn_data
[icode
].operand
[1].predicate (treg
, Pmode
)
413 && (insn
= GEN_FCN (icode
) (tmem0
, treg
)) != NULL_RTX
)
416 emit_move_insn (tmem0
, treg
);
418 /* The memory barrier inserted above should not prevent
419 the load of flags from being moved before the stores,
420 but in practice it does because it is implemented with
421 unspec_volatile. In-order RISC machines should
422 explicitly load flags earlier. */
424 tree flags
= cilk_dot (fptr
, CILK_TI_FRAME_FLAGS
, 0);
425 expand_expr (build2 (MODIFY_EXPR
, void_type_node
, flags
,
426 build2 (BIT_IOR_EXPR
, TREE_TYPE (flags
), flags
,
427 build_int_cst (TREE_TYPE (flags
),
428 CILK_FRAME_DETACHED
))),
429 const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
432 /* Returns a setjmp CALL_EXPR with FRAME->context as its parameter. */
435 cilk_call_setjmp (tree frame
)
437 tree c
= cilk_dot (frame
, CILK_TI_FRAME_CONTEXT
, false);
438 c
= build1 (ADDR_EXPR
, build_pointer_type (ptr_type_node
), c
);
439 return build_call_expr (builtin_decl_implicit (BUILT_IN_SETJMP
), 1, c
);
442 /* This function will expand the _Cilk_sync keyword. */
445 expand_cilk_sync (void)
447 tree frame
= cfun
->cilk_frame_decl
;
449 /* Cilk_sync is converted to the following code:
451 sf.pedigree = sf.worker->pedigree;
452 if (frame.flags & CILK_FRAME_UNSYNCHED)
454 __cilkrts_save_fp_state (&sf);
455 if (!builtin_setjmp (sf.ctx)
456 __cilkrts_sync (&sf);
458 if (sf.flags & CILK_FRAME_EXCEPTING)
459 __cilkrts_rethrow (&sf);
461 sf.worker->pedigree.rank = sf.worker->pedigree.rank + 1; */
463 tree flags
= cilk_dot (frame
, CILK_TI_FRAME_FLAGS
, false);
465 tree unsynched
= fold_build2 (BIT_AND_EXPR
, TREE_TYPE (flags
), flags
,
466 build_int_cst (TREE_TYPE (flags
),
467 CILK_FRAME_UNSYNCHED
));
469 unsynched
= fold_build2 (NE_EXPR
, TREE_TYPE (unsynched
), unsynched
,
470 build_int_cst (TREE_TYPE (unsynched
), 0));
472 tree frame_addr
= build1 (ADDR_EXPR
, cilk_frame_ptr_type_decl
, frame
);
474 /* Check if exception (0x10) bit is set in the sf->flags. */
475 tree except_flag
= fold_build2 (BIT_AND_EXPR
, TREE_TYPE (flags
), flags
,
476 build_int_cst (TREE_TYPE (flags
),
477 CILK_FRAME_EXCEPTING
));
478 except_flag
= fold_build2 (NE_EXPR
, TREE_TYPE (except_flag
), except_flag
,
479 build_int_cst (TREE_TYPE (except_flag
), 0));
481 /* If the exception flag is set then call the __cilkrts_rethrow (&sf). */
482 tree except_cond
= fold_build3 (COND_EXPR
, void_type_node
, except_flag
,
483 build_call_expr (cilk_rethrow_fndecl
, 1,
485 build_empty_stmt (EXPR_LOCATION (unsynched
)));
487 tree sync_expr
= build_call_expr (cilk_sync_fndecl
, 1, frame_addr
);
488 tree setjmp_expr
= cilk_call_setjmp (frame
);
489 setjmp_expr
= fold_build2 (EQ_EXPR
, TREE_TYPE (setjmp_expr
), setjmp_expr
,
490 build_int_cst (TREE_TYPE (setjmp_expr
), 0));
492 setjmp_expr
= fold_build3 (COND_EXPR
, void_type_node
, setjmp_expr
,
493 sync_expr
, except_cond
);
494 tree sync_list
= alloc_stmt_list ();
495 append_to_statement_list (build_call_expr (cilk_save_fp_fndecl
, 1,
496 frame_addr
), &sync_list
);
497 append_to_statement_list (setjmp_expr
, &sync_list
);
498 tree sync
= fold_build3 (COND_EXPR
, void_type_node
, unsynched
, sync_list
,
499 build_empty_stmt (EXPR_LOCATION (unsynched
)));
500 tree parent_pedigree
= cilk_dot (frame
, CILK_TI_FRAME_PEDIGREE
, false);
501 tree worker
= cilk_dot (frame
, CILK_TI_FRAME_WORKER
, false);
502 tree worker_pedigree
= cilk_arrow (worker
, CILK_TI_WORKER_PEDIGREE
, false);
503 tree assign_pedigree
= fold_build2 (MODIFY_EXPR
, void_type_node
,
504 parent_pedigree
, worker_pedigree
);
505 tree w_ped_rank
= cilk_dot (unshare_expr (worker_pedigree
),
506 CILK_TI_PEDIGREE_RANK
, false);
507 tree incr_ped_rank
= fold_build2 (PLUS_EXPR
, TREE_TYPE (w_ped_rank
),
509 build_one_cst (TREE_TYPE (w_ped_rank
)));
510 incr_ped_rank
= fold_build2 (MODIFY_EXPR
, void_type_node
, w_ped_rank
,
512 tree ret_sync_exp
= alloc_stmt_list ();
513 append_to_statement_list (assign_pedigree
, &ret_sync_exp
);
514 append_to_statement_list (sync
, &ret_sync_exp
);
515 append_to_statement_list (incr_ped_rank
, &ret_sync_exp
);
519 /* Gimplifies the cilk_sync expression passed in *EXPR_P. Returns GS_ALL_DONE
523 gimplify_cilk_sync (tree
*expr_p
, gimple_seq
*pre_p
)
525 tree sync_expr
= expand_cilk_sync ();
527 gimplify_and_add (sync_expr
, pre_p
);