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 "double-int.h"
37 #include "fold-const.h"
38 #include "stringpool.h"
39 #include "stor-layout.h"
40 #include "langhooks.h"
43 #include "hard-reg-set.h"
47 #include "statistics.h"
49 #include "fixed-value.h"
50 #include "insn-config.h"
59 #include "insn-codes.h"
62 #include "tree-iterator.h"
66 /* This structure holds all the important fields of the internal structures,
67 internal built-in functions, and Cilk-specific data types. Explanation of
68 all the these fielsd are given in cilk.h. */
69 tree cilk_trees
[(int) CILK_TI_MAX
];
71 /* Returns the value in structure FRAME pointed by the FIELD_NUMBER
73 FIELD_NUMBER is an index to the structure FRAME_PTR. For details
74 about these fields, refer to cilk_trees structure in cilk.h and
75 cilk_init_builtins function in this file. Returns a TREE that is the type
76 of the field represented by FIELD_NUMBER. If VOLATIL parameter is set
77 to true then the returning field is set as volatile. */
80 cilk_dot (tree frame
, int field_number
, bool volatil
)
82 tree field
= cilk_trees
[field_number
];
83 field
= fold_build3 (COMPONENT_REF
, TREE_TYPE (field
), frame
, field
,
85 TREE_THIS_VOLATILE (field
) = volatil
;
89 /* Returns the address of a field in FRAME_PTR, pointed by FIELD_NUMBER.
90 (e.g. (&X)->y). Please see cilk_dot function for explanation of the
91 FIELD_NUMBER. Returns a tree that is the type of the field represented
92 by FIELD_NUMBER. If VOLATIL parameter is set to true then the returning
93 field is set as volatile. */
96 cilk_arrow (tree frame_ptr
, int field_number
, bool volatil
)
98 return cilk_dot (build_simple_mem_ref (frame_ptr
),
99 field_number
, volatil
);
103 /* This function will add FIELD of type TYPE to a defined built-in
104 structure. *NAME is the name of the field to be added. */
107 add_field (const char *name
, tree type
, tree fields
)
109 tree t
= get_identifier (name
);
110 tree field
= build_decl (BUILTINS_LOCATION
, FIELD_DECL
, t
, type
);
111 TREE_CHAIN (field
) = fields
;
115 /* This function will define a built-in function of NAME, of type FNTYPE and
116 register it under the built-in function code CODE. If PUBLISH is set then
117 the declaration is pushed into the declaration list. CODE is the index
118 to the cilk_trees array. *NAME is the name of the function to be added. */
121 install_builtin (const char *name
, tree fntype
, enum built_in_function code
,
124 tree fndecl
= build_fn_decl (name
, fntype
);
125 DECL_BUILT_IN_CLASS (fndecl
) = BUILT_IN_NORMAL
;
126 DECL_FUNCTION_CODE (fndecl
) = code
;
129 tree t
= lang_hooks
.decls
.pushdecl (fndecl
);
133 set_builtin_decl (code
, fndecl
, true);
137 /* Returns a FUNCTION_DECL of type TYPE whose name is *NAME. */
140 declare_cilk_for_builtin (const char *name
, tree type
,
141 enum built_in_function code
)
145 cb
= build_function_type_list (void_type_node
,
146 ptr_type_node
, type
, type
,
148 cb
= build_pointer_type (cb
);
149 ft
= build_function_type_list (void_type_node
,
150 cb
, ptr_type_node
, type
,
151 integer_type_node
, NULL_TREE
);
152 fn
= install_builtin (name
, ft
, code
, false);
153 TREE_NOTHROW (fn
) = 0;
158 /* Creates and initializes all the built-in Cilk keywords functions and three
159 structures: __cilkrts_stack_frame, __cilkrts_pedigree and __cilkrts_worker.
160 Detailed information about __cilkrts_stack_frame and
161 __cilkrts_worker structures are given in libcilkrts/include/internal/abi.h.
162 __cilkrts_pedigree is described in libcilkrts/include/cilk/common.h. */
165 cilk_init_builtins (void)
167 /* Now build the following __cilkrts_pedigree struct:
168 struct __cilkrts_pedigree {
170 struct __cilkrts_pedigree *parent;
173 tree pedigree_type
= lang_hooks
.types
.make_type (RECORD_TYPE
);
174 tree pedigree_ptr
= build_pointer_type (pedigree_type
);
175 tree field
= add_field ("rank", uint64_type_node
, NULL_TREE
);
176 cilk_trees
[CILK_TI_PEDIGREE_RANK
] = field
;
177 field
= add_field ("parent", pedigree_ptr
, field
);
178 cilk_trees
[CILK_TI_PEDIGREE_PARENT
] = field
;
179 finish_builtin_struct (pedigree_type
, "__cilkrts_pedigree_GCC", field
,
181 lang_hooks
.types
.register_builtin_type (pedigree_type
,
182 "__cilkrts_pedigree_t");
183 cilk_pedigree_type_decl
= pedigree_type
;
185 /* Build the Cilk Stack Frame:
186 struct __cilkrts_stack_frame {
189 struct __cilkrts_stack_frame *call_parent;
190 __cilkrts_worker *worker;
196 __cilkrts_pedigree pedigree;
199 tree frame
= lang_hooks
.types
.make_type (RECORD_TYPE
);
200 tree frame_ptr
= build_pointer_type (frame
);
201 tree worker_type
= lang_hooks
.types
.make_type (RECORD_TYPE
);
202 tree worker_ptr
= build_pointer_type (worker_type
);
203 tree s_type_node
= build_int_cst (size_type_node
, 4);
205 tree flags
= add_field ("flags", uint32_type_node
, NULL_TREE
);
206 tree size
= add_field ("size", uint32_type_node
, flags
);
207 tree parent
= add_field ("call_parent", frame_ptr
, size
);
208 tree worker
= add_field ("worker", worker_ptr
, parent
);
209 tree except
= add_field ("except_data", frame_ptr
, worker
);
210 tree context
= add_field ("ctx",
211 build_array_type (ptr_type_node
,
212 build_index_type (s_type_node
)),
214 tree mxcsr
= add_field ("mxcsr", uint32_type_node
, context
);
215 tree fpcsr
= add_field ("fpcsr", uint16_type_node
, mxcsr
);
216 tree reserved
= add_field ("reserved", uint16_type_node
, fpcsr
);
217 tree pedigree
= add_field ("pedigree", pedigree_type
, reserved
);
219 /* Now add them to a common structure whose fields are #defined to something
220 that is used at a later stage. */
221 cilk_trees
[CILK_TI_FRAME_FLAGS
] = flags
;
222 cilk_trees
[CILK_TI_FRAME_PARENT
] = parent
;
223 cilk_trees
[CILK_TI_FRAME_WORKER
] = worker
;
224 cilk_trees
[CILK_TI_FRAME_EXCEPTION
] = except
;
225 cilk_trees
[CILK_TI_FRAME_CONTEXT
] = context
;
226 /* We don't care about reserved, so no need to store it in cilk_trees. */
227 cilk_trees
[CILK_TI_FRAME_PEDIGREE
] = pedigree
;
228 TREE_ADDRESSABLE (frame
) = 1;
230 finish_builtin_struct (frame
, "__cilkrts_st_frame_GCC", pedigree
, NULL_TREE
);
231 cilk_frame_type_decl
= frame
;
232 lang_hooks
.types
.register_builtin_type (frame
, "__cilkrts_frame_t");
234 cilk_frame_ptr_type_decl
= build_qualified_type (frame_ptr
,
236 /* Now let's do the following worker struct:
238 struct __cilkrts_worker {
239 __cilkrts_stack_frame *volatile *volatile tail;
240 __cilkrts_stack_frame *volatile *volatile head;
241 __cilkrts_stack_frame *volatile *volatile exc;
242 __cilkrts_stack_frame *volatile *volatile protected_tail;
243 __cilkrts_stack_frame *volatile *ltq_limit;
247 cilkred_map *reducer_map;
248 __cilkrts_stack_frame *current_stack_frame;
250 __cilkrts_worker_sysdep_state *sysdep;
251 __cilkrts_pedigree pedigree;
254 tree fptr_volatil_type
= build_qualified_type (frame_ptr
, TYPE_QUAL_VOLATILE
);
255 tree fptr_volatile_ptr
= build_pointer_type (fptr_volatil_type
);
256 tree fptr_vol_ptr_vol
= build_qualified_type (fptr_volatile_ptr
,
258 tree g
= lang_hooks
.types
.make_type (RECORD_TYPE
);
259 finish_builtin_struct (g
, "__cilkrts_global_state", NULL_TREE
, NULL_TREE
);
260 tree l
= lang_hooks
.types
.make_type (RECORD_TYPE
);
261 finish_builtin_struct (l
, "__cilkrts_local_state", NULL_TREE
, NULL_TREE
);
262 tree sysdep_t
= lang_hooks
.types
.make_type (RECORD_TYPE
);
263 finish_builtin_struct (sysdep_t
, "__cilkrts_worker_sysdep_state", NULL_TREE
,
266 field
= add_field ("tail", fptr_vol_ptr_vol
, NULL_TREE
);
267 cilk_trees
[CILK_TI_WORKER_TAIL
] = field
;
268 field
= add_field ("head", fptr_vol_ptr_vol
, field
);
269 field
= add_field ("exc", fptr_vol_ptr_vol
, field
);
270 field
= add_field ("protected_tail", fptr_vol_ptr_vol
, field
);
271 field
= add_field ("ltq_limit", fptr_volatile_ptr
, field
);
272 field
= add_field ("self", integer_type_node
, field
);
273 field
= add_field ("g", build_pointer_type (g
), field
);
274 field
= add_field ("l", build_pointer_type (g
), field
);
275 field
= add_field ("reducer_map", ptr_type_node
, field
);
276 field
= add_field ("current_stack_frame", frame_ptr
, field
);
277 cilk_trees
[CILK_TI_WORKER_CUR
] = field
;
278 field
= add_field ("saved_protected_tail", fptr_volatile_ptr
, field
);
279 field
= add_field ("sysdep", build_pointer_type (sysdep_t
), field
);
280 field
= add_field ("pedigree", pedigree_type
, field
);
281 cilk_trees
[CILK_TI_WORKER_PEDIGREE
] = field
;
282 finish_builtin_struct (worker_type
, "__cilkrts_worker_GCC", field
,
285 tree fptr_arglist
= tree_cons (NULL_TREE
, frame_ptr
, void_list_node
);
286 tree fptr_fun
= build_function_type (void_type_node
, fptr_arglist
);
288 /* void __cilkrts_enter_frame_1 (__cilkrts_stack_frame *); */
289 cilk_enter_fndecl
= install_builtin ("__cilkrts_enter_frame_1", fptr_fun
,
290 BUILT_IN_CILK_ENTER_FRAME
, false);
292 /* void __cilkrts_enter_frame_fast_1 (__cilkrts_stack_frame *); */
293 cilk_enter_fast_fndecl
=
294 install_builtin ("__cilkrts_enter_frame_fast_1", fptr_fun
,
295 BUILT_IN_CILK_ENTER_FRAME_FAST
, false);
297 /* void __cilkrts_pop_frame (__cilkrts_stack_frame *); */
298 cilk_pop_fndecl
= install_builtin ("__cilkrts_pop_frame", fptr_fun
,
299 BUILT_IN_CILK_POP_FRAME
, false);
301 /* void __cilkrts_leave_frame (__cilkrts_stack_frame *); */
302 cilk_leave_fndecl
= install_builtin ("__cilkrts_leave_frame", fptr_fun
,
303 BUILT_IN_CILK_LEAVE_FRAME
, false);
305 /* void __cilkrts_sync (__cilkrts_stack_frame *); */
306 cilk_sync_fndecl
= install_builtin ("__cilkrts_sync", fptr_fun
,
307 BUILT_IN_CILK_SYNC
, false);
309 /* void __cilkrts_detach (__cilkrts_stack_frame *); */
310 cilk_detach_fndecl
= install_builtin ("__cilkrts_detach", fptr_fun
,
311 BUILT_IN_CILK_DETACH
, false);
313 /* __cilkrts_rethrow (struct stack_frame *); */
314 cilk_rethrow_fndecl
= install_builtin ("__cilkrts_rethrow", fptr_fun
,
315 BUILT_IN_CILK_RETHROW
, false);
316 TREE_NOTHROW (cilk_rethrow_fndecl
) = 0;
318 /* __cilkrts_save_fp_ctrl_state (__cilkrts_stack_frame *); */
319 cilk_save_fp_fndecl
= install_builtin ("__cilkrts_save_fp_ctrl_state",
320 fptr_fun
, BUILT_IN_CILK_SAVE_FP
,
322 /* __cilkrts_cilk_for_32 (...); */
323 cilk_for_32_fndecl
= declare_cilk_for_builtin ("__cilkrts_cilk_for_32",
324 unsigned_intSI_type_node
,
325 BUILT_IN_CILK_FOR_32
);
326 /* __cilkrts_cilk_for_64 (...); */
327 cilk_for_64_fndecl
= declare_cilk_for_builtin ("__cilkrts_cilk_for_64",
328 unsigned_intDI_type_node
,
329 BUILT_IN_CILK_FOR_64
);
332 /* Get the appropriate frame arguments for CALL that is of type CALL_EXPR. */
335 get_frame_arg (tree call
)
339 gcc_assert (call_expr_nargs (call
) >= 1);
341 arg
= CALL_EXPR_ARG (call
, 0);
342 argtype
= TREE_TYPE (arg
);
343 gcc_assert (TREE_CODE (argtype
) == POINTER_TYPE
);
345 argtype
= TREE_TYPE (argtype
);
347 /* If it is passed in as an address, then just use the value directly
348 since the function is inlined. */
349 if (TREE_CODE (arg
) == ADDR_EXPR
)
350 return TREE_OPERAND (arg
, 0);
354 /* Expands the __cilkrts_pop_frame function call stored in EXP. */
357 expand_builtin_cilk_pop_frame (tree exp
)
359 tree frame
= get_frame_arg (exp
);
360 tree parent
= cilk_dot (frame
, CILK_TI_FRAME_PARENT
, 0);
362 tree clear_parent
= build2 (MODIFY_EXPR
, void_type_node
, parent
,
363 build_int_cst (TREE_TYPE (parent
), 0));
364 expand_expr (clear_parent
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
366 /* During LTO, the is_cilk_function flag gets cleared.
367 If __cilkrts_pop_frame is called, then this definitely must be a
370 cfun
->is_cilk_function
= 1;
373 /* Expands the cilk_detach function call stored in EXP. */
376 expand_builtin_cilk_detach (tree exp
)
379 tree fptr
= get_frame_arg (exp
);
381 if (fptr
== NULL_TREE
)
384 tree parent
= cilk_dot (fptr
, CILK_TI_FRAME_PARENT
, 0);
385 tree worker
= cilk_dot (fptr
, CILK_TI_FRAME_WORKER
, 0);
386 tree tail
= cilk_arrow (worker
, CILK_TI_WORKER_TAIL
, 1);
388 rtx wreg
= expand_expr (worker
, NULL_RTX
, Pmode
, EXPAND_NORMAL
);
389 if (GET_CODE (wreg
) != REG
)
390 wreg
= copy_to_reg (wreg
);
391 rtx preg
= expand_expr (parent
, NULL_RTX
, Pmode
, EXPAND_NORMAL
);
393 /* TMP <- WORKER.TAIL
396 WORKER.TAIL <- TMP */
398 HOST_WIDE_INT worker_tail_offset
=
399 tree_to_shwi (DECL_FIELD_OFFSET (cilk_trees
[CILK_TI_WORKER_TAIL
])) +
400 tree_to_shwi (DECL_FIELD_BIT_OFFSET (cilk_trees
[CILK_TI_WORKER_TAIL
])) /
402 rtx tmem0
= gen_rtx_MEM (Pmode
,
403 plus_constant (Pmode
, wreg
, worker_tail_offset
));
404 set_mem_attributes (tmem0
, tail
, 0);
405 MEM_NOTRAP_P (tmem0
) = 1;
406 gcc_assert (MEM_VOLATILE_P (tmem0
));
407 rtx treg
= copy_to_mode_reg (Pmode
, tmem0
);
408 rtx tmem1
= gen_rtx_MEM (Pmode
, treg
);
409 set_mem_attributes (tmem1
, TREE_TYPE (TREE_TYPE (tail
)), 0);
410 MEM_NOTRAP_P (tmem1
) = 1;
411 emit_move_insn (tmem1
, preg
);
412 emit_move_insn (treg
, plus_constant (Pmode
, treg
, GET_MODE_SIZE (Pmode
)));
414 /* There is a release barrier (st8.rel, membar #StoreStore,
415 sfence, lwsync, etc.) between the two stores. On x86
416 normal volatile stores have proper semantics; the sfence
417 would only be needed for nontemporal stores (which we
418 could generate using the storent optab, for no benefit
421 The predicate may return false even for a REG if this is
422 the limited release operation that only stores 0. */
423 enum insn_code icode
= direct_optab_handler (sync_lock_release_optab
, Pmode
);
424 if (icode
!= CODE_FOR_nothing
425 && insn_data
[icode
].operand
[1].predicate (treg
, Pmode
)
426 && (insn
= GEN_FCN (icode
) (tmem0
, treg
)) != NULL_RTX
)
429 emit_move_insn (tmem0
, treg
);
431 /* The memory barrier inserted above should not prevent
432 the load of flags from being moved before the stores,
433 but in practice it does because it is implemented with
434 unspec_volatile. In-order RISC machines should
435 explicitly load flags earlier. */
437 tree flags
= cilk_dot (fptr
, CILK_TI_FRAME_FLAGS
, 0);
438 expand_expr (build2 (MODIFY_EXPR
, void_type_node
, flags
,
439 build2 (BIT_IOR_EXPR
, TREE_TYPE (flags
), flags
,
440 build_int_cst (TREE_TYPE (flags
),
441 CILK_FRAME_DETACHED
))),
442 const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
445 /* Returns a setjmp CALL_EXPR with FRAME->context as its parameter. */
448 cilk_call_setjmp (tree frame
)
450 tree c
= cilk_dot (frame
, CILK_TI_FRAME_CONTEXT
, false);
451 c
= build1 (ADDR_EXPR
, build_pointer_type (ptr_type_node
), c
);
452 return build_call_expr (builtin_decl_implicit (BUILT_IN_SETJMP
), 1, c
);
455 /* This function will expand the _Cilk_sync keyword. */
458 expand_cilk_sync (void)
460 tree frame
= cfun
->cilk_frame_decl
;
462 /* Cilk_sync is converted to the following code:
464 sf.pedigree = sf.worker->pedigree;
465 if (frame.flags & CILK_FRAME_UNSYNCHED)
467 __cilkrts_save_fp_state (&sf);
468 if (!builtin_setjmp (sf.ctx)
469 __cilkrts_sync (&sf);
471 if (sf.flags & CILK_FRAME_EXCEPTING)
472 __cilkrts_rethrow (&sf);
474 sf.worker->pedigree.rank = sf.worker->pedigree.rank + 1; */
476 tree flags
= cilk_dot (frame
, CILK_TI_FRAME_FLAGS
, false);
478 tree unsynched
= fold_build2 (BIT_AND_EXPR
, TREE_TYPE (flags
), flags
,
479 build_int_cst (TREE_TYPE (flags
),
480 CILK_FRAME_UNSYNCHED
));
482 unsynched
= fold_build2 (NE_EXPR
, TREE_TYPE (unsynched
), unsynched
,
483 build_int_cst (TREE_TYPE (unsynched
), 0));
485 tree frame_addr
= build1 (ADDR_EXPR
, cilk_frame_ptr_type_decl
, frame
);
487 /* Check if exception (0x10) bit is set in the sf->flags. */
488 tree except_flag
= fold_build2 (BIT_AND_EXPR
, TREE_TYPE (flags
), flags
,
489 build_int_cst (TREE_TYPE (flags
),
490 CILK_FRAME_EXCEPTING
));
491 except_flag
= fold_build2 (NE_EXPR
, TREE_TYPE (except_flag
), except_flag
,
492 build_int_cst (TREE_TYPE (except_flag
), 0));
494 /* If the exception flag is set then call the __cilkrts_rethrow (&sf). */
495 tree except_cond
= fold_build3 (COND_EXPR
, void_type_node
, except_flag
,
496 build_call_expr (cilk_rethrow_fndecl
, 1,
498 build_empty_stmt (EXPR_LOCATION (unsynched
)));
500 tree sync_expr
= build_call_expr (cilk_sync_fndecl
, 1, frame_addr
);
501 tree setjmp_expr
= cilk_call_setjmp (frame
);
502 setjmp_expr
= fold_build2 (EQ_EXPR
, TREE_TYPE (setjmp_expr
), setjmp_expr
,
503 build_int_cst (TREE_TYPE (setjmp_expr
), 0));
505 setjmp_expr
= fold_build3 (COND_EXPR
, void_type_node
, setjmp_expr
,
506 sync_expr
, except_cond
);
507 tree sync_list
= alloc_stmt_list ();
508 append_to_statement_list (build_call_expr (cilk_save_fp_fndecl
, 1,
509 frame_addr
), &sync_list
);
510 append_to_statement_list (setjmp_expr
, &sync_list
);
511 tree sync
= fold_build3 (COND_EXPR
, void_type_node
, unsynched
, sync_list
,
512 build_empty_stmt (EXPR_LOCATION (unsynched
)));
513 tree parent_pedigree
= cilk_dot (frame
, CILK_TI_FRAME_PEDIGREE
, false);
514 tree worker
= cilk_dot (frame
, CILK_TI_FRAME_WORKER
, false);
515 tree worker_pedigree
= cilk_arrow (worker
, CILK_TI_WORKER_PEDIGREE
, false);
516 tree assign_pedigree
= fold_build2 (MODIFY_EXPR
, void_type_node
,
517 parent_pedigree
, worker_pedigree
);
518 tree w_ped_rank
= cilk_dot (unshare_expr (worker_pedigree
),
519 CILK_TI_PEDIGREE_RANK
, false);
520 tree incr_ped_rank
= fold_build2 (PLUS_EXPR
, TREE_TYPE (w_ped_rank
),
522 build_one_cst (TREE_TYPE (w_ped_rank
)));
523 incr_ped_rank
= fold_build2 (MODIFY_EXPR
, void_type_node
, w_ped_rank
,
525 tree ret_sync_exp
= alloc_stmt_list ();
526 append_to_statement_list (assign_pedigree
, &ret_sync_exp
);
527 append_to_statement_list (sync
, &ret_sync_exp
);
528 append_to_statement_list (incr_ped_rank
, &ret_sync_exp
);
532 /* Gimplifies the cilk_sync expression passed in *EXPR_P. Returns GS_ALL_DONE
536 gimplify_cilk_sync (tree
*expr_p
, gimple_seq
*pre_p
)
538 tree sync_expr
= expand_cilk_sync ();
540 gimplify_and_add (sync_expr
, pre_p
);