* tree.c (free_lang_data_in_decl): Also set target/optimization flags
[official-gcc.git] / gcc / cilk-common.c
blob9a2ed9d3b537ce1f30015da3d3da423155ccc4c5
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 "emit-rtl.h"
35 #include "recog.h"
36 #include "fold-const.h"
37 #include "stor-layout.h"
38 #include "langhooks.h"
39 #include "explow.h"
40 #include "expr.h"
41 #include "tree-iterator.h"
42 #include "gimplify.h"
43 #include "cilk.h"
45 /* This structure holds all the important fields of the internal structures,
46 internal built-in functions, and Cilk-specific data types. Explanation of
47 all the these fielsd are given in cilk.h. */
48 tree cilk_trees[(int) CILK_TI_MAX];
50 /* Returns the value in structure FRAME pointed by the FIELD_NUMBER
51 (e.g. X.y).
52 FIELD_NUMBER is an index to the structure FRAME_PTR. For details
53 about these fields, refer to cilk_trees structure in cilk.h and
54 cilk_init_builtins function in this file. Returns a TREE that is the type
55 of the field represented by FIELD_NUMBER. If VOLATIL parameter is set
56 to true then the returning field is set as volatile. */
58 tree
59 cilk_dot (tree frame, int field_number, bool volatil)
61 tree field = cilk_trees[field_number];
62 field = fold_build3 (COMPONENT_REF, TREE_TYPE (field), frame, field,
63 NULL_TREE);
64 TREE_THIS_VOLATILE (field) = volatil;
65 return field;
68 /* Returns the address of a field in FRAME_PTR, pointed by FIELD_NUMBER.
69 (e.g. (&X)->y). Please see cilk_dot function for explanation of the
70 FIELD_NUMBER. Returns a tree that is the type of the field represented
71 by FIELD_NUMBER. If VOLATIL parameter is set to true then the returning
72 field is set as volatile. */
74 tree
75 cilk_arrow (tree frame_ptr, int field_number, bool volatil)
77 return cilk_dot (build_simple_mem_ref (frame_ptr),
78 field_number, volatil);
82 /* This function will add FIELD of type TYPE to a defined built-in
83 structure. *NAME is the name of the field to be added. */
85 static tree
86 add_field (const char *name, tree type, tree fields)
88 tree t = get_identifier (name);
89 tree field = build_decl (BUILTINS_LOCATION, FIELD_DECL, t, type);
90 TREE_CHAIN (field) = fields;
91 return field;
94 /* This function will define a built-in function of NAME, of type FNTYPE and
95 register it under the built-in function code CODE. If PUBLISH is set then
96 the declaration is pushed into the declaration list. CODE is the index
97 to the cilk_trees array. *NAME is the name of the function to be added. */
99 static tree
100 install_builtin (const char *name, tree fntype, enum built_in_function code,
101 bool publish)
103 tree fndecl = build_fn_decl (name, fntype);
104 DECL_BUILT_IN_CLASS (fndecl) = BUILT_IN_NORMAL;
105 DECL_FUNCTION_CODE (fndecl) = code;
106 if (publish)
108 tree t = lang_hooks.decls.pushdecl (fndecl);
109 if (t)
110 fndecl = t;
112 set_builtin_decl (code, fndecl, true);
113 return fndecl;
116 /* Returns a FUNCTION_DECL of type TYPE whose name is *NAME. */
118 static tree
119 declare_cilk_for_builtin (const char *name, tree type,
120 enum built_in_function code)
122 tree cb, ft, fn;
124 cb = build_function_type_list (void_type_node,
125 ptr_type_node, type, type,
126 NULL_TREE);
127 cb = build_pointer_type (cb);
128 ft = build_function_type_list (void_type_node,
129 cb, ptr_type_node, type,
130 integer_type_node, NULL_TREE);
131 fn = install_builtin (name, ft, code, false);
132 TREE_NOTHROW (fn) = 0;
134 return fn;
137 /* Creates and initializes all the built-in Cilk keywords functions and three
138 structures: __cilkrts_stack_frame, __cilkrts_pedigree and __cilkrts_worker.
139 Detailed information about __cilkrts_stack_frame and
140 __cilkrts_worker structures are given in libcilkrts/include/internal/abi.h.
141 __cilkrts_pedigree is described in libcilkrts/include/cilk/common.h. */
143 void
144 cilk_init_builtins (void)
146 /* Now build the following __cilkrts_pedigree struct:
147 struct __cilkrts_pedigree {
148 uint64_t rank;
149 struct __cilkrts_pedigree *parent;
150 } */
152 tree pedigree_type = lang_hooks.types.make_type (RECORD_TYPE);
153 tree pedigree_ptr = build_pointer_type (pedigree_type);
154 tree field = add_field ("rank", uint64_type_node, NULL_TREE);
155 cilk_trees[CILK_TI_PEDIGREE_RANK] = field;
156 field = add_field ("parent", pedigree_ptr, field);
157 cilk_trees[CILK_TI_PEDIGREE_PARENT] = field;
158 finish_builtin_struct (pedigree_type, "__cilkrts_pedigree_GCC", field,
159 NULL_TREE);
160 lang_hooks.types.register_builtin_type (pedigree_type,
161 "__cilkrts_pedigree_t");
162 cilk_pedigree_type_decl = pedigree_type;
164 /* Build the Cilk Stack Frame:
165 struct __cilkrts_stack_frame {
166 uint32_t flags;
167 uint32_t size;
168 struct __cilkrts_stack_frame *call_parent;
169 __cilkrts_worker *worker;
170 void *except_data;
171 void *ctx[4];
172 uint32_t mxcsr;
173 uint16_t fpcsr;
174 uint16_t reserved;
175 __cilkrts_pedigree pedigree;
176 }; */
178 tree frame = lang_hooks.types.make_type (RECORD_TYPE);
179 tree frame_ptr = build_pointer_type (frame);
180 tree worker_type = lang_hooks.types.make_type (RECORD_TYPE);
181 tree worker_ptr = build_pointer_type (worker_type);
182 tree s_type_node = build_int_cst (size_type_node, 4);
184 tree flags = add_field ("flags", uint32_type_node, NULL_TREE);
185 tree size = add_field ("size", uint32_type_node, flags);
186 tree parent = add_field ("call_parent", frame_ptr, size);
187 tree worker = add_field ("worker", worker_ptr, parent);
188 tree except = add_field ("except_data", frame_ptr, worker);
189 tree context = add_field ("ctx",
190 build_array_type (ptr_type_node,
191 build_index_type (s_type_node)),
192 except);
193 tree mxcsr = add_field ("mxcsr", uint32_type_node, context);
194 tree fpcsr = add_field ("fpcsr", uint16_type_node, mxcsr);
195 tree reserved = add_field ("reserved", uint16_type_node, fpcsr);
196 tree pedigree = add_field ("pedigree", pedigree_type, reserved);
198 /* Now add them to a common structure whose fields are #defined to something
199 that is used at a later stage. */
200 cilk_trees[CILK_TI_FRAME_FLAGS] = flags;
201 cilk_trees[CILK_TI_FRAME_PARENT] = parent;
202 cilk_trees[CILK_TI_FRAME_WORKER] = worker;
203 cilk_trees[CILK_TI_FRAME_EXCEPTION] = except;
204 cilk_trees[CILK_TI_FRAME_CONTEXT] = context;
205 /* We don't care about reserved, so no need to store it in cilk_trees. */
206 cilk_trees[CILK_TI_FRAME_PEDIGREE] = pedigree;
207 TREE_ADDRESSABLE (frame) = 1;
209 finish_builtin_struct (frame, "__cilkrts_st_frame_GCC", pedigree, NULL_TREE);
210 cilk_frame_type_decl = frame;
211 lang_hooks.types.register_builtin_type (frame, "__cilkrts_frame_t");
213 cilk_frame_ptr_type_decl = build_qualified_type (frame_ptr,
214 TYPE_QUAL_VOLATILE);
215 /* Now let's do the following worker struct:
217 struct __cilkrts_worker {
218 __cilkrts_stack_frame *volatile *volatile tail;
219 __cilkrts_stack_frame *volatile *volatile head;
220 __cilkrts_stack_frame *volatile *volatile exc;
221 __cilkrts_stack_frame *volatile *volatile protected_tail;
222 __cilkrts_stack_frame *volatile *ltq_limit;
223 int32_t self;
224 global_state_t *g;
225 local_state *l;
226 cilkred_map *reducer_map;
227 __cilkrts_stack_frame *current_stack_frame;
228 void *reserved;
229 __cilkrts_worker_sysdep_state *sysdep;
230 __cilkrts_pedigree pedigree;
231 } */
233 tree fptr_volatil_type = build_qualified_type (frame_ptr, TYPE_QUAL_VOLATILE);
234 tree fptr_volatile_ptr = build_pointer_type (fptr_volatil_type);
235 tree fptr_vol_ptr_vol = build_qualified_type (fptr_volatile_ptr,
236 TYPE_QUAL_VOLATILE);
237 tree g = lang_hooks.types.make_type (RECORD_TYPE);
238 finish_builtin_struct (g, "__cilkrts_global_state", NULL_TREE, NULL_TREE);
239 tree l = lang_hooks.types.make_type (RECORD_TYPE);
240 finish_builtin_struct (l, "__cilkrts_local_state", NULL_TREE, NULL_TREE);
241 tree sysdep_t = lang_hooks.types.make_type (RECORD_TYPE);
242 finish_builtin_struct (sysdep_t, "__cilkrts_worker_sysdep_state", NULL_TREE,
243 NULL_TREE);
245 field = add_field ("tail", fptr_vol_ptr_vol, NULL_TREE);
246 cilk_trees[CILK_TI_WORKER_TAIL] = field;
247 field = add_field ("head", fptr_vol_ptr_vol, field);
248 field = add_field ("exc", fptr_vol_ptr_vol, field);
249 field = add_field ("protected_tail", fptr_vol_ptr_vol, field);
250 field = add_field ("ltq_limit", fptr_volatile_ptr, field);
251 field = add_field ("self", integer_type_node, field);
252 field = add_field ("g", build_pointer_type (g), field);
253 field = add_field ("l", build_pointer_type (g), field);
254 field = add_field ("reducer_map", ptr_type_node, field);
255 field = add_field ("current_stack_frame", frame_ptr, field);
256 cilk_trees[CILK_TI_WORKER_CUR] = field;
257 field = add_field ("saved_protected_tail", fptr_volatile_ptr, field);
258 field = add_field ("sysdep", build_pointer_type (sysdep_t), field);
259 field = add_field ("pedigree", pedigree_type, field);
260 cilk_trees[CILK_TI_WORKER_PEDIGREE] = field;
261 finish_builtin_struct (worker_type, "__cilkrts_worker_GCC", field,
262 NULL_TREE);
264 tree fptr_arglist = tree_cons (NULL_TREE, frame_ptr, void_list_node);
265 tree fptr_fun = build_function_type (void_type_node, fptr_arglist);
267 /* void __cilkrts_enter_frame_1 (__cilkrts_stack_frame *); */
268 cilk_enter_fndecl = install_builtin ("__cilkrts_enter_frame_1", fptr_fun,
269 BUILT_IN_CILK_ENTER_FRAME, false);
271 /* void __cilkrts_enter_frame_fast_1 (__cilkrts_stack_frame *); */
272 cilk_enter_fast_fndecl =
273 install_builtin ("__cilkrts_enter_frame_fast_1", fptr_fun,
274 BUILT_IN_CILK_ENTER_FRAME_FAST, false);
276 /* void __cilkrts_pop_frame (__cilkrts_stack_frame *); */
277 cilk_pop_fndecl = install_builtin ("__cilkrts_pop_frame", fptr_fun,
278 BUILT_IN_CILK_POP_FRAME, false);
280 /* void __cilkrts_leave_frame (__cilkrts_stack_frame *); */
281 cilk_leave_fndecl = install_builtin ("__cilkrts_leave_frame", fptr_fun,
282 BUILT_IN_CILK_LEAVE_FRAME, false);
284 /* void __cilkrts_sync (__cilkrts_stack_frame *); */
285 cilk_sync_fndecl = install_builtin ("__cilkrts_sync", fptr_fun,
286 BUILT_IN_CILK_SYNC, false);
288 /* void __cilkrts_detach (__cilkrts_stack_frame *); */
289 cilk_detach_fndecl = install_builtin ("__cilkrts_detach", fptr_fun,
290 BUILT_IN_CILK_DETACH, false);
292 /* __cilkrts_rethrow (struct stack_frame *); */
293 cilk_rethrow_fndecl = install_builtin ("__cilkrts_rethrow", fptr_fun,
294 BUILT_IN_CILK_RETHROW, false);
295 TREE_NOTHROW (cilk_rethrow_fndecl) = 0;
297 /* __cilkrts_save_fp_ctrl_state (__cilkrts_stack_frame *); */
298 cilk_save_fp_fndecl = install_builtin ("__cilkrts_save_fp_ctrl_state",
299 fptr_fun, BUILT_IN_CILK_SAVE_FP,
300 false);
301 /* __cilkrts_cilk_for_32 (...); */
302 cilk_for_32_fndecl = declare_cilk_for_builtin ("__cilkrts_cilk_for_32",
303 unsigned_intSI_type_node,
304 BUILT_IN_CILK_FOR_32);
305 /* __cilkrts_cilk_for_64 (...); */
306 cilk_for_64_fndecl = declare_cilk_for_builtin ("__cilkrts_cilk_for_64",
307 unsigned_intDI_type_node,
308 BUILT_IN_CILK_FOR_64);
311 /* Get the appropriate frame arguments for CALL that is of type CALL_EXPR. */
313 static tree
314 get_frame_arg (tree call)
316 tree arg, argtype;
318 gcc_assert (call_expr_nargs (call) >= 1);
320 arg = CALL_EXPR_ARG (call, 0);
321 argtype = TREE_TYPE (arg);
322 gcc_assert (TREE_CODE (argtype) == POINTER_TYPE);
324 argtype = TREE_TYPE (argtype);
326 /* If it is passed in as an address, then just use the value directly
327 since the function is inlined. */
328 if (TREE_CODE (arg) == ADDR_EXPR)
329 return TREE_OPERAND (arg, 0);
330 return arg;
333 /* Expands the __cilkrts_pop_frame function call stored in EXP. */
335 void
336 expand_builtin_cilk_pop_frame (tree exp)
338 tree frame = get_frame_arg (exp);
339 tree parent = cilk_dot (frame, CILK_TI_FRAME_PARENT, 0);
341 tree clear_parent = build2 (MODIFY_EXPR, void_type_node, parent,
342 build_int_cst (TREE_TYPE (parent), 0));
343 expand_expr (clear_parent, const0_rtx, VOIDmode, EXPAND_NORMAL);
345 /* During LTO, the is_cilk_function flag gets cleared.
346 If __cilkrts_pop_frame is called, then this definitely must be a
347 cilk function. */
348 if (cfun)
349 cfun->is_cilk_function = 1;
352 /* Expands the cilk_detach function call stored in EXP. */
354 void
355 expand_builtin_cilk_detach (tree exp)
357 rtx_insn *insn;
358 tree fptr = get_frame_arg (exp);
360 if (fptr == NULL_TREE)
361 return;
363 tree parent = cilk_dot (fptr, CILK_TI_FRAME_PARENT, 0);
364 tree worker = cilk_dot (fptr, CILK_TI_FRAME_WORKER, 0);
365 tree tail = cilk_arrow (worker, CILK_TI_WORKER_TAIL, 1);
367 rtx wreg = expand_expr (worker, NULL_RTX, Pmode, EXPAND_NORMAL);
368 if (GET_CODE (wreg) != REG)
369 wreg = copy_to_reg (wreg);
370 rtx preg = expand_expr (parent, NULL_RTX, Pmode, EXPAND_NORMAL);
372 /* TMP <- WORKER.TAIL
373 *TMP <- PARENT
374 TMP <- TMP + 1
375 WORKER.TAIL <- TMP */
377 HOST_WIDE_INT worker_tail_offset =
378 tree_to_shwi (DECL_FIELD_OFFSET (cilk_trees[CILK_TI_WORKER_TAIL])) +
379 tree_to_shwi (DECL_FIELD_BIT_OFFSET (cilk_trees[CILK_TI_WORKER_TAIL])) /
380 BITS_PER_UNIT;
381 rtx tmem0 = gen_rtx_MEM (Pmode,
382 plus_constant (Pmode, wreg, worker_tail_offset));
383 set_mem_attributes (tmem0, tail, 0);
384 MEM_NOTRAP_P (tmem0) = 1;
385 gcc_assert (MEM_VOLATILE_P (tmem0));
386 rtx treg = copy_to_mode_reg (Pmode, tmem0);
387 rtx tmem1 = gen_rtx_MEM (Pmode, treg);
388 set_mem_attributes (tmem1, TREE_TYPE (TREE_TYPE (tail)), 0);
389 MEM_NOTRAP_P (tmem1) = 1;
390 emit_move_insn (tmem1, preg);
391 emit_move_insn (treg, plus_constant (Pmode, treg, GET_MODE_SIZE (Pmode)));
393 /* There is a release barrier (st8.rel, membar #StoreStore,
394 sfence, lwsync, etc.) between the two stores. On x86
395 normal volatile stores have proper semantics; the sfence
396 would only be needed for nontemporal stores (which we
397 could generate using the storent optab, for no benefit
398 in this case).
400 The predicate may return false even for a REG if this is
401 the limited release operation that only stores 0. */
402 enum insn_code icode = direct_optab_handler (sync_lock_release_optab, Pmode);
403 if (icode != CODE_FOR_nothing
404 && insn_data[icode].operand[1].predicate (treg, Pmode)
405 && (insn = GEN_FCN (icode) (tmem0, treg)) != NULL_RTX)
406 emit_insn (insn);
407 else
408 emit_move_insn (tmem0, treg);
410 /* The memory barrier inserted above should not prevent
411 the load of flags from being moved before the stores,
412 but in practice it does because it is implemented with
413 unspec_volatile. In-order RISC machines should
414 explicitly load flags earlier. */
416 tree flags = cilk_dot (fptr, CILK_TI_FRAME_FLAGS, 0);
417 expand_expr (build2 (MODIFY_EXPR, void_type_node, flags,
418 build2 (BIT_IOR_EXPR, TREE_TYPE (flags), flags,
419 build_int_cst (TREE_TYPE (flags),
420 CILK_FRAME_DETACHED))),
421 const0_rtx, VOIDmode, EXPAND_NORMAL);
424 /* Returns a setjmp CALL_EXPR with FRAME->context as its parameter. */
426 tree
427 cilk_call_setjmp (tree frame)
429 tree c = cilk_dot (frame, CILK_TI_FRAME_CONTEXT, false);
430 c = build1 (ADDR_EXPR, build_pointer_type (ptr_type_node), c);
431 return build_call_expr (builtin_decl_implicit (BUILT_IN_SETJMP), 1, c);
434 /* This function will expand the _Cilk_sync keyword. */
436 static tree
437 expand_cilk_sync (void)
439 tree frame = cfun->cilk_frame_decl;
441 /* Cilk_sync is converted to the following code:
443 sf.pedigree = sf.worker->pedigree;
444 if (frame.flags & CILK_FRAME_UNSYNCHED)
446 __cilkrts_save_fp_state (&sf);
447 if (!builtin_setjmp (sf.ctx)
448 __cilkrts_sync (&sf);
449 else
450 if (sf.flags & CILK_FRAME_EXCEPTING)
451 __cilkrts_rethrow (&sf);
453 sf.worker->pedigree.rank = sf.worker->pedigree.rank + 1; */
455 tree flags = cilk_dot (frame, CILK_TI_FRAME_FLAGS, false);
457 tree unsynched = fold_build2 (BIT_AND_EXPR, TREE_TYPE (flags), flags,
458 build_int_cst (TREE_TYPE (flags),
459 CILK_FRAME_UNSYNCHED));
461 unsynched = fold_build2 (NE_EXPR, TREE_TYPE (unsynched), unsynched,
462 build_int_cst (TREE_TYPE (unsynched), 0));
464 tree frame_addr = build1 (ADDR_EXPR, cilk_frame_ptr_type_decl, frame);
466 /* Check if exception (0x10) bit is set in the sf->flags. */
467 tree except_flag = fold_build2 (BIT_AND_EXPR, TREE_TYPE (flags), flags,
468 build_int_cst (TREE_TYPE (flags),
469 CILK_FRAME_EXCEPTING));
470 except_flag = fold_build2 (NE_EXPR, TREE_TYPE (except_flag), except_flag,
471 build_int_cst (TREE_TYPE (except_flag), 0));
473 /* If the exception flag is set then call the __cilkrts_rethrow (&sf). */
474 tree except_cond = fold_build3 (COND_EXPR, void_type_node, except_flag,
475 build_call_expr (cilk_rethrow_fndecl, 1,
476 frame_addr),
477 build_empty_stmt (EXPR_LOCATION (unsynched)));
479 tree sync_expr = build_call_expr (cilk_sync_fndecl, 1, frame_addr);
480 tree setjmp_expr = cilk_call_setjmp (frame);
481 setjmp_expr = fold_build2 (EQ_EXPR, TREE_TYPE (setjmp_expr), setjmp_expr,
482 build_int_cst (TREE_TYPE (setjmp_expr), 0));
484 setjmp_expr = fold_build3 (COND_EXPR, void_type_node, setjmp_expr,
485 sync_expr, except_cond);
486 tree sync_list = alloc_stmt_list ();
487 append_to_statement_list (build_call_expr (cilk_save_fp_fndecl, 1,
488 frame_addr), &sync_list);
489 append_to_statement_list (setjmp_expr, &sync_list);
490 tree sync = fold_build3 (COND_EXPR, void_type_node, unsynched, sync_list,
491 build_empty_stmt (EXPR_LOCATION (unsynched)));
492 tree parent_pedigree = cilk_dot (frame, CILK_TI_FRAME_PEDIGREE, false);
493 tree worker = cilk_dot (frame, CILK_TI_FRAME_WORKER, false);
494 tree worker_pedigree = cilk_arrow (worker, CILK_TI_WORKER_PEDIGREE, false);
495 tree assign_pedigree = fold_build2 (MODIFY_EXPR, void_type_node,
496 parent_pedigree, worker_pedigree);
497 tree w_ped_rank = cilk_dot (unshare_expr (worker_pedigree),
498 CILK_TI_PEDIGREE_RANK, false);
499 tree incr_ped_rank = fold_build2 (PLUS_EXPR, TREE_TYPE (w_ped_rank),
500 w_ped_rank,
501 build_one_cst (TREE_TYPE (w_ped_rank)));
502 incr_ped_rank = fold_build2 (MODIFY_EXPR, void_type_node, w_ped_rank,
503 incr_ped_rank);
504 tree ret_sync_exp = alloc_stmt_list ();
505 append_to_statement_list (assign_pedigree, &ret_sync_exp);
506 append_to_statement_list (sync, &ret_sync_exp);
507 append_to_statement_list (incr_ped_rank, &ret_sync_exp);
508 return ret_sync_exp;
511 /* Gimplifies the cilk_sync expression passed in *EXPR_P. Returns GS_ALL_DONE
512 when finished. */
514 void
515 gimplify_cilk_sync (tree *expr_p, gimple_seq *pre_p)
517 tree sync_expr = expand_cilk_sync ();
518 *expr_p = NULL_TREE;
519 gimplify_and_add (sync_expr, pre_p);