PR rtl-optimization/78437
[official-gcc.git] / gcc / cilk-common.c
blobecd7abe0adf57cd185338a7efbadaeb6e2e6f2bc
1 /* This file is part of the Intel(R) Cilk(TM) Plus support
2 This file contains the CilkPlus Intrinsics
3 Copyright (C) 2013-2016 Free Software Foundation, Inc.
4 Contributed by Balaji V. Iyer <balaji.v.iyer@intel.com>,
5 Intel Corporation
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)
12 any later version.
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/>. */
23 #include "config.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "tm.h"
27 #include "function.h"
28 #include "rtl.h"
29 #include "tree.h"
30 #include "stringpool.h"
31 #include "expmed.h"
32 #include "optabs-query.h"
33 #include "insn-config.h"
34 #include "memmodel.h"
35 #include "emit-rtl.h"
36 #include "recog.h"
37 #include "fold-const.h"
38 #include "stor-layout.h"
39 #include "langhooks.h"
40 #include "explow.h"
41 #include "expr.h"
42 #include "tree-iterator.h"
43 #include "gimplify.h"
44 #include "cilk.h"
46 /* This structure holds all the important fields of the internal structures,
47 internal built-in functions, and Cilk-specific data types. Explanation of
48 all the these fielsd are given in cilk.h. */
49 tree cilk_trees[(int) CILK_TI_MAX];
51 /* Returns the value in structure FRAME pointed by the FIELD_NUMBER
52 (e.g. X.y).
53 FIELD_NUMBER is an index to the structure FRAME_PTR. For details
54 about these fields, refer to cilk_trees structure in cilk.h and
55 cilk_init_builtins function in this file. Returns a TREE that is the type
56 of the field represented by FIELD_NUMBER. If VOLATIL parameter is set
57 to true then the returning field is set as volatile. */
59 tree
60 cilk_dot (tree frame, int field_number, bool volatil)
62 tree field = cilk_trees[field_number];
63 field = fold_build3 (COMPONENT_REF, TREE_TYPE (field), frame, field,
64 NULL_TREE);
65 TREE_THIS_VOLATILE (field) = volatil;
66 return field;
69 /* Returns the address of a field in FRAME_PTR, pointed by FIELD_NUMBER.
70 (e.g. (&X)->y). Please see cilk_dot function for explanation of the
71 FIELD_NUMBER. Returns a tree that is the type of the field represented
72 by FIELD_NUMBER. If VOLATIL parameter is set to true then the returning
73 field is set as volatile. */
75 tree
76 cilk_arrow (tree frame_ptr, int field_number, bool volatil)
78 return cilk_dot (build_simple_mem_ref (frame_ptr),
79 field_number, volatil);
83 /* This function will add FIELD of type TYPE to a defined built-in
84 structure. *NAME is the name of the field to be added. */
86 static tree
87 add_field (const char *name, tree type, tree fields)
89 tree t = get_identifier (name);
90 tree field = build_decl (BUILTINS_LOCATION, FIELD_DECL, t, type);
91 TREE_CHAIN (field) = fields;
92 return field;
95 /* This function will define a built-in function of NAME, of type FNTYPE and
96 register it under the built-in function code CODE. If PUBLISH is set then
97 the declaration is pushed into the declaration list. CODE is the index
98 to the cilk_trees array. *NAME is the name of the function to be added. */
100 static tree
101 install_builtin (const char *name, tree fntype, enum built_in_function code,
102 bool publish)
104 tree fndecl = build_fn_decl (name, fntype);
105 DECL_BUILT_IN_CLASS (fndecl) = BUILT_IN_NORMAL;
106 DECL_FUNCTION_CODE (fndecl) = code;
107 if (publish)
109 tree t = lang_hooks.decls.pushdecl (fndecl);
110 if (t)
111 fndecl = t;
113 set_builtin_decl (code, fndecl, true);
114 return fndecl;
117 /* Returns a FUNCTION_DECL of type TYPE whose name is *NAME. */
119 static tree
120 declare_cilk_for_builtin (const char *name, tree type,
121 enum built_in_function code)
123 tree cb, ft, fn;
125 cb = build_function_type_list (void_type_node,
126 ptr_type_node, type, type,
127 NULL_TREE);
128 cb = build_pointer_type (cb);
129 ft = build_function_type_list (void_type_node,
130 cb, ptr_type_node, type,
131 integer_type_node, NULL_TREE);
132 fn = install_builtin (name, ft, code, false);
133 TREE_NOTHROW (fn) = 0;
135 return fn;
138 /* Creates and initializes all the built-in Cilk keywords functions and three
139 structures: __cilkrts_stack_frame, __cilkrts_pedigree and __cilkrts_worker.
140 Detailed information about __cilkrts_stack_frame and
141 __cilkrts_worker structures are given in libcilkrts/include/internal/abi.h.
142 __cilkrts_pedigree is described in libcilkrts/include/cilk/common.h. */
144 void
145 cilk_init_builtins (void)
147 /* Now build the following __cilkrts_pedigree struct:
148 struct __cilkrts_pedigree {
149 uint64_t rank;
150 struct __cilkrts_pedigree *parent;
151 } */
153 tree pedigree_type = lang_hooks.types.make_type (RECORD_TYPE);
154 tree pedigree_ptr = build_pointer_type (pedigree_type);
155 tree field = add_field ("rank", uint64_type_node, NULL_TREE);
156 cilk_trees[CILK_TI_PEDIGREE_RANK] = field;
157 field = add_field ("parent", pedigree_ptr, field);
158 cilk_trees[CILK_TI_PEDIGREE_PARENT] = field;
159 finish_builtin_struct (pedigree_type, "__cilkrts_pedigree_GCC", field,
160 NULL_TREE);
161 lang_hooks.types.register_builtin_type (pedigree_type,
162 "__cilkrts_pedigree_t");
163 cilk_pedigree_type_decl = pedigree_type;
165 /* Build the Cilk Stack Frame:
166 struct __cilkrts_stack_frame {
167 uint32_t flags;
168 uint32_t size;
169 struct __cilkrts_stack_frame *call_parent;
170 __cilkrts_worker *worker;
171 void *except_data;
172 void *ctx[4];
173 uint32_t mxcsr;
174 uint16_t fpcsr;
175 uint16_t reserved;
176 __cilkrts_pedigree pedigree;
177 }; */
179 tree frame = lang_hooks.types.make_type (RECORD_TYPE);
180 tree frame_ptr = build_pointer_type (frame);
181 tree worker_type = lang_hooks.types.make_type (RECORD_TYPE);
182 tree worker_ptr = build_pointer_type (worker_type);
183 tree s_type_node = build_int_cst (size_type_node, 4);
185 tree flags = add_field ("flags", uint32_type_node, NULL_TREE);
186 tree size = add_field ("size", uint32_type_node, flags);
187 tree parent = add_field ("call_parent", frame_ptr, size);
188 tree worker = add_field ("worker", worker_ptr, parent);
189 tree except = add_field ("except_data", frame_ptr, worker);
190 tree context = add_field ("ctx",
191 build_array_type (ptr_type_node,
192 build_index_type (s_type_node)),
193 except);
194 tree mxcsr = add_field ("mxcsr", uint32_type_node, context);
195 tree fpcsr = add_field ("fpcsr", uint16_type_node, mxcsr);
196 tree reserved = add_field ("reserved", uint16_type_node, fpcsr);
197 tree pedigree = add_field ("pedigree", pedigree_type, reserved);
199 /* Now add them to a common structure whose fields are #defined to something
200 that is used at a later stage. */
201 cilk_trees[CILK_TI_FRAME_FLAGS] = flags;
202 cilk_trees[CILK_TI_FRAME_PARENT] = parent;
203 cilk_trees[CILK_TI_FRAME_WORKER] = worker;
204 cilk_trees[CILK_TI_FRAME_EXCEPTION] = except;
205 cilk_trees[CILK_TI_FRAME_CONTEXT] = context;
206 /* We don't care about reserved, so no need to store it in cilk_trees. */
207 cilk_trees[CILK_TI_FRAME_PEDIGREE] = pedigree;
208 TREE_ADDRESSABLE (frame) = 1;
210 finish_builtin_struct (frame, "__cilkrts_st_frame_GCC", pedigree, NULL_TREE);
211 cilk_frame_type_decl = frame;
212 lang_hooks.types.register_builtin_type (frame, "__cilkrts_frame_t");
214 cilk_frame_ptr_type_decl = build_qualified_type (frame_ptr,
215 TYPE_QUAL_VOLATILE);
216 /* Now let's do the following worker struct:
218 struct __cilkrts_worker {
219 __cilkrts_stack_frame *volatile *volatile tail;
220 __cilkrts_stack_frame *volatile *volatile head;
221 __cilkrts_stack_frame *volatile *volatile exc;
222 __cilkrts_stack_frame *volatile *volatile protected_tail;
223 __cilkrts_stack_frame *volatile *ltq_limit;
224 int32_t self;
225 global_state_t *g;
226 local_state *l;
227 cilkred_map *reducer_map;
228 __cilkrts_stack_frame *current_stack_frame;
229 void *reserved;
230 __cilkrts_worker_sysdep_state *sysdep;
231 __cilkrts_pedigree pedigree;
232 } */
234 tree fptr_volatil_type = build_qualified_type (frame_ptr, TYPE_QUAL_VOLATILE);
235 tree fptr_volatile_ptr = build_pointer_type (fptr_volatil_type);
236 tree fptr_vol_ptr_vol = build_qualified_type (fptr_volatile_ptr,
237 TYPE_QUAL_VOLATILE);
238 tree g = lang_hooks.types.make_type (RECORD_TYPE);
239 finish_builtin_struct (g, "__cilkrts_global_state", NULL_TREE, NULL_TREE);
240 tree l = lang_hooks.types.make_type (RECORD_TYPE);
241 finish_builtin_struct (l, "__cilkrts_local_state", NULL_TREE, NULL_TREE);
242 tree sysdep_t = lang_hooks.types.make_type (RECORD_TYPE);
243 finish_builtin_struct (sysdep_t, "__cilkrts_worker_sysdep_state", NULL_TREE,
244 NULL_TREE);
246 field = add_field ("tail", fptr_vol_ptr_vol, NULL_TREE);
247 cilk_trees[CILK_TI_WORKER_TAIL] = field;
248 field = add_field ("head", fptr_vol_ptr_vol, field);
249 field = add_field ("exc", fptr_vol_ptr_vol, field);
250 field = add_field ("protected_tail", fptr_vol_ptr_vol, field);
251 field = add_field ("ltq_limit", fptr_volatile_ptr, field);
252 field = add_field ("self", integer_type_node, field);
253 field = add_field ("g", build_pointer_type (g), field);
254 field = add_field ("l", build_pointer_type (g), field);
255 field = add_field ("reducer_map", ptr_type_node, field);
256 field = add_field ("current_stack_frame", frame_ptr, field);
257 cilk_trees[CILK_TI_WORKER_CUR] = field;
258 field = add_field ("saved_protected_tail", fptr_volatile_ptr, field);
259 field = add_field ("sysdep", build_pointer_type (sysdep_t), field);
260 field = add_field ("pedigree", pedigree_type, field);
261 cilk_trees[CILK_TI_WORKER_PEDIGREE] = field;
262 finish_builtin_struct (worker_type, "__cilkrts_worker_GCC", field,
263 NULL_TREE);
265 tree fptr_arglist = tree_cons (NULL_TREE, frame_ptr, void_list_node);
266 tree fptr_fun = build_function_type (void_type_node, fptr_arglist);
268 /* void __cilkrts_enter_frame_1 (__cilkrts_stack_frame *); */
269 cilk_enter_fndecl = install_builtin ("__cilkrts_enter_frame_1", fptr_fun,
270 BUILT_IN_CILK_ENTER_FRAME, false);
272 /* void __cilkrts_enter_frame_fast_1 (__cilkrts_stack_frame *); */
273 cilk_enter_fast_fndecl =
274 install_builtin ("__cilkrts_enter_frame_fast_1", fptr_fun,
275 BUILT_IN_CILK_ENTER_FRAME_FAST, false);
277 /* void __cilkrts_pop_frame (__cilkrts_stack_frame *); */
278 cilk_pop_fndecl = install_builtin ("__cilkrts_pop_frame", fptr_fun,
279 BUILT_IN_CILK_POP_FRAME, false);
281 /* void __cilkrts_leave_frame (__cilkrts_stack_frame *); */
282 cilk_leave_fndecl = install_builtin ("__cilkrts_leave_frame", fptr_fun,
283 BUILT_IN_CILK_LEAVE_FRAME, false);
285 /* void __cilkrts_sync (__cilkrts_stack_frame *); */
286 cilk_sync_fndecl = install_builtin ("__cilkrts_sync", fptr_fun,
287 BUILT_IN_CILK_SYNC, false);
289 /* void __cilkrts_detach (__cilkrts_stack_frame *); */
290 cilk_detach_fndecl = install_builtin ("__cilkrts_detach", fptr_fun,
291 BUILT_IN_CILK_DETACH, false);
293 /* __cilkrts_rethrow (struct stack_frame *); */
294 cilk_rethrow_fndecl = install_builtin ("__cilkrts_rethrow", fptr_fun,
295 BUILT_IN_CILK_RETHROW, false);
296 TREE_NOTHROW (cilk_rethrow_fndecl) = 0;
298 /* __cilkrts_save_fp_ctrl_state (__cilkrts_stack_frame *); */
299 cilk_save_fp_fndecl = install_builtin ("__cilkrts_save_fp_ctrl_state",
300 fptr_fun, BUILT_IN_CILK_SAVE_FP,
301 false);
302 /* __cilkrts_cilk_for_32 (...); */
303 cilk_for_32_fndecl = declare_cilk_for_builtin ("__cilkrts_cilk_for_32",
304 unsigned_intSI_type_node,
305 BUILT_IN_CILK_FOR_32);
306 /* __cilkrts_cilk_for_64 (...); */
307 cilk_for_64_fndecl = declare_cilk_for_builtin ("__cilkrts_cilk_for_64",
308 unsigned_intDI_type_node,
309 BUILT_IN_CILK_FOR_64);
312 /* Get the appropriate frame arguments for CALL that is of type CALL_EXPR. */
314 static tree
315 get_frame_arg (tree call)
317 tree arg, argtype;
319 gcc_assert (call_expr_nargs (call) >= 1);
321 arg = CALL_EXPR_ARG (call, 0);
322 argtype = TREE_TYPE (arg);
323 gcc_assert (TREE_CODE (argtype) == POINTER_TYPE);
325 argtype = TREE_TYPE (argtype);
327 /* If it is passed in as an address, then just use the value directly
328 since the function is inlined. */
329 if (TREE_CODE (arg) == ADDR_EXPR)
330 return TREE_OPERAND (arg, 0);
331 return arg;
334 /* Expands the __cilkrts_pop_frame function call stored in EXP. */
336 void
337 expand_builtin_cilk_pop_frame (tree exp)
339 tree frame = get_frame_arg (exp);
340 tree parent = cilk_dot (frame, CILK_TI_FRAME_PARENT, 0);
342 tree clear_parent = build2 (MODIFY_EXPR, void_type_node, parent,
343 build_int_cst (TREE_TYPE (parent), 0));
344 expand_expr (clear_parent, const0_rtx, VOIDmode, EXPAND_NORMAL);
346 /* During LTO, the is_cilk_function flag gets cleared.
347 If __cilkrts_pop_frame is called, then this definitely must be a
348 cilk function. */
349 if (cfun)
350 cfun->is_cilk_function = 1;
353 /* Expands the cilk_detach function call stored in EXP. */
355 void
356 expand_builtin_cilk_detach (tree exp)
358 rtx_insn *insn;
359 tree fptr = get_frame_arg (exp);
361 if (fptr == NULL_TREE)
362 return;
364 tree parent = cilk_dot (fptr, CILK_TI_FRAME_PARENT, 0);
365 tree worker = cilk_dot (fptr, CILK_TI_FRAME_WORKER, 0);
366 tree tail = cilk_arrow (worker, CILK_TI_WORKER_TAIL, 1);
368 rtx wreg = expand_expr (worker, NULL_RTX, Pmode, EXPAND_NORMAL);
369 if (GET_CODE (wreg) != REG)
370 wreg = copy_to_reg (wreg);
371 rtx preg = expand_expr (parent, NULL_RTX, Pmode, EXPAND_NORMAL);
373 /* TMP <- WORKER.TAIL
374 *TMP <- PARENT
375 TMP <- TMP + 1
376 WORKER.TAIL <- TMP */
378 HOST_WIDE_INT worker_tail_offset =
379 tree_to_shwi (DECL_FIELD_OFFSET (cilk_trees[CILK_TI_WORKER_TAIL])) +
380 tree_to_shwi (DECL_FIELD_BIT_OFFSET (cilk_trees[CILK_TI_WORKER_TAIL])) /
381 BITS_PER_UNIT;
382 rtx tmem0 = gen_rtx_MEM (Pmode,
383 plus_constant (Pmode, wreg, worker_tail_offset));
384 set_mem_attributes (tmem0, tail, 0);
385 MEM_NOTRAP_P (tmem0) = 1;
386 gcc_assert (MEM_VOLATILE_P (tmem0));
387 rtx treg = copy_to_mode_reg (Pmode, tmem0);
388 rtx tmem1 = gen_rtx_MEM (Pmode, treg);
389 set_mem_attributes (tmem1, TREE_TYPE (TREE_TYPE (tail)), 0);
390 MEM_NOTRAP_P (tmem1) = 1;
391 emit_move_insn (tmem1, preg);
392 emit_move_insn (treg, plus_constant (Pmode, treg, GET_MODE_SIZE (Pmode)));
394 /* There is a release barrier (st8.rel, membar #StoreStore,
395 sfence, lwsync, etc.) between the two stores. On x86
396 normal volatile stores have proper semantics; the sfence
397 would only be needed for nontemporal stores (which we
398 could generate using the storent optab, for no benefit
399 in this case).
401 The predicate may return false even for a REG if this is
402 the limited release operation that only stores 0. */
403 enum insn_code icode = direct_optab_handler (sync_lock_release_optab, Pmode);
404 if (icode != CODE_FOR_nothing
405 && insn_data[icode].operand[1].predicate (treg, Pmode)
406 && (insn = GEN_FCN (icode) (tmem0, treg)) != NULL_RTX)
407 emit_insn (insn);
408 else
409 emit_move_insn (tmem0, treg);
411 /* The memory barrier inserted above should not prevent
412 the load of flags from being moved before the stores,
413 but in practice it does because it is implemented with
414 unspec_volatile. In-order RISC machines should
415 explicitly load flags earlier. */
417 tree flags = cilk_dot (fptr, CILK_TI_FRAME_FLAGS, 0);
418 expand_expr (build2 (MODIFY_EXPR, void_type_node, flags,
419 build2 (BIT_IOR_EXPR, TREE_TYPE (flags), flags,
420 build_int_cst (TREE_TYPE (flags),
421 CILK_FRAME_DETACHED))),
422 const0_rtx, VOIDmode, EXPAND_NORMAL);
425 /* Returns a setjmp CALL_EXPR with FRAME->context as its parameter. */
427 tree
428 cilk_call_setjmp (tree frame)
430 tree c = cilk_dot (frame, CILK_TI_FRAME_CONTEXT, false);
431 c = build1 (ADDR_EXPR, build_pointer_type (ptr_type_node), c);
432 return build_call_expr (builtin_decl_implicit (BUILT_IN_SETJMP), 1, c);
435 /* This function will expand the _Cilk_sync keyword. */
437 static tree
438 expand_cilk_sync (void)
440 tree frame = cfun->cilk_frame_decl;
442 /* Cilk_sync is converted to the following code:
444 sf.pedigree = sf.worker->pedigree;
445 if (frame.flags & CILK_FRAME_UNSYNCHED)
447 __cilkrts_save_fp_state (&sf);
448 if (!builtin_setjmp (sf.ctx)
449 __cilkrts_sync (&sf);
450 else
451 if (sf.flags & CILK_FRAME_EXCEPTING)
452 __cilkrts_rethrow (&sf);
454 sf.worker->pedigree.rank = sf.worker->pedigree.rank + 1; */
456 tree flags = cilk_dot (frame, CILK_TI_FRAME_FLAGS, false);
458 tree unsynched = fold_build2 (BIT_AND_EXPR, TREE_TYPE (flags), flags,
459 build_int_cst (TREE_TYPE (flags),
460 CILK_FRAME_UNSYNCHED));
462 unsynched = fold_build2 (NE_EXPR, TREE_TYPE (unsynched), unsynched,
463 build_int_cst (TREE_TYPE (unsynched), 0));
465 tree frame_addr = build1 (ADDR_EXPR, cilk_frame_ptr_type_decl, frame);
467 /* Check if exception (0x10) bit is set in the sf->flags. */
468 tree except_flag = fold_build2 (BIT_AND_EXPR, TREE_TYPE (flags), flags,
469 build_int_cst (TREE_TYPE (flags),
470 CILK_FRAME_EXCEPTING));
471 except_flag = fold_build2 (NE_EXPR, TREE_TYPE (except_flag), except_flag,
472 build_int_cst (TREE_TYPE (except_flag), 0));
474 /* If the exception flag is set then call the __cilkrts_rethrow (&sf). */
475 tree except_cond = fold_build3 (COND_EXPR, void_type_node, except_flag,
476 build_call_expr (cilk_rethrow_fndecl, 1,
477 frame_addr),
478 build_empty_stmt (EXPR_LOCATION (unsynched)));
480 tree sync_expr = build_call_expr (cilk_sync_fndecl, 1, frame_addr);
481 tree setjmp_expr = cilk_call_setjmp (frame);
482 setjmp_expr = fold_build2 (EQ_EXPR, TREE_TYPE (setjmp_expr), setjmp_expr,
483 build_int_cst (TREE_TYPE (setjmp_expr), 0));
485 setjmp_expr = fold_build3 (COND_EXPR, void_type_node, setjmp_expr,
486 sync_expr, except_cond);
487 tree sync_list = alloc_stmt_list ();
488 append_to_statement_list (build_call_expr (cilk_save_fp_fndecl, 1,
489 frame_addr), &sync_list);
490 append_to_statement_list (setjmp_expr, &sync_list);
491 tree sync = fold_build3 (COND_EXPR, void_type_node, unsynched, sync_list,
492 build_empty_stmt (EXPR_LOCATION (unsynched)));
493 tree parent_pedigree = cilk_dot (frame, CILK_TI_FRAME_PEDIGREE, false);
494 tree worker = cilk_dot (frame, CILK_TI_FRAME_WORKER, false);
495 tree worker_pedigree = cilk_arrow (worker, CILK_TI_WORKER_PEDIGREE, false);
496 tree assign_pedigree = fold_build2 (MODIFY_EXPR, void_type_node,
497 parent_pedigree, worker_pedigree);
498 tree w_ped_rank = cilk_dot (unshare_expr (worker_pedigree),
499 CILK_TI_PEDIGREE_RANK, false);
500 tree incr_ped_rank = fold_build2 (PLUS_EXPR, TREE_TYPE (w_ped_rank),
501 w_ped_rank,
502 build_one_cst (TREE_TYPE (w_ped_rank)));
503 incr_ped_rank = fold_build2 (MODIFY_EXPR, void_type_node, w_ped_rank,
504 incr_ped_rank);
505 tree ret_sync_exp = alloc_stmt_list ();
506 append_to_statement_list (assign_pedigree, &ret_sync_exp);
507 append_to_statement_list (sync, &ret_sync_exp);
508 append_to_statement_list (incr_ped_rank, &ret_sync_exp);
509 return ret_sync_exp;
512 /* Gimplifies the cilk_sync expression passed in *EXPR_P. Returns GS_ALL_DONE
513 when finished. */
515 void
516 gimplify_cilk_sync (tree *expr_p, gimple_seq *pre_p)
518 tree sync_expr = expand_cilk_sync ();
519 *expr_p = NULL_TREE;
520 gimplify_and_add (sync_expr, pre_p);