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