1/* This file is part of the Intel(R) Cilk(TM) Plus support
2   This file contains routines to handle Cilk Plus specific
3   routines for the C++ Compiler.
4   Copyright (C) 2013-2015 Free Software Foundation, Inc.
5   Contributed by Aldy Hernandez <aldyh@redhat.com>.
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 "cp-tree.h"
27#include "diagnostic-core.h"
28#include "tree-iterator.h"
29#include "tree-inline.h"  /* for copy_tree_body_r.  */
30#include "ggc.h"
31#include "cilk.h"
32
33/* Callback for cp_walk_tree to validate the body of a pragma simd loop
34   or _cilk_for loop.
35
36   This function is passed in as a function pointer to walk_tree.  *TP is
37   the current tree pointer, *WALK_SUBTREES is set to 0 by this function if
38   recursing into TP's subtrees is unnecessary. *DATA is a bool variable that
39   is set to false if an error has occured.  */
40
41static tree
42cpp_validate_cilk_plus_loop_aux (tree *tp, int *walk_subtrees, void *data)
43{
44  bool *valid = (bool *) data;
45
46  if (!tp || !*tp)
47    return NULL_TREE;
48
49  location_t loc = EXPR_LOCATION (*tp);
50  if (TREE_CODE (*tp) == THROW_EXPR)
51    {
52      error_at (loc, "throw expressions are not allowed inside loops "
53		"marked with pragma simd");
54      *walk_subtrees = 0;
55      *valid = false;
56    }
57  else if (TREE_CODE (*tp) == TRY_BLOCK)
58    {
59      error_at (loc, "try statements are not allowed inside loops marked "
60		"with #pragma simd");
61      *valid = false;
62      *walk_subtrees = 0;
63    }
64  return NULL_TREE;
65}
66
67
68/* Walks through all the subtrees of BODY using walk_tree to make sure
69   invalid statements/expressions are not found inside BODY.  Returns
70   false if any invalid statements are found.  */
71
72bool
73cpp_validate_cilk_plus_loop (tree body)
74{
75  bool valid = true;
76  cp_walk_tree (&body, cpp_validate_cilk_plus_loop_aux,
77		(void *) &valid, NULL);
78  return valid;
79}
80
81/* Sets the EXCEPTION bit (0x10) in the FRAME.flags field.  */
82
83static tree
84set_cilk_except_flag (tree frame)
85{
86  tree flags = cilk_dot (frame, CILK_TI_FRAME_FLAGS, 0);
87
88  flags = build2 (MODIFY_EXPR, void_type_node, flags,
89		  build2 (BIT_IOR_EXPR, TREE_TYPE (flags), flags,
90			  build_int_cst (TREE_TYPE (flags),
91					 CILK_FRAME_EXCEPTING)));
92  return flags;
93}
94
95/* Sets the frame.EXCEPT_DATA field to the head of the exception pointer.  */
96
97static tree
98set_cilk_except_data (tree frame)
99{
100  tree except_data = cilk_dot (frame, CILK_TI_FRAME_EXCEPTION, 0);
101  tree uresume_fn = builtin_decl_implicit (BUILT_IN_EH_POINTER);
102  tree ret_expr;
103  uresume_fn  = build_call_expr (uresume_fn, 1,
104				 build_int_cst (integer_type_node, 0));
105  ret_expr = build2 (MODIFY_EXPR, void_type_node, except_data, uresume_fn);
106  return ret_expr;
107}
108
109/* Installs BODY into function FNDECL with appropriate exception handling
110   code.  WD holds information of wrapper function used to pass into the
111   outlining function, cilk_outline.  */
112
113void
114cilk_install_body_with_frame_cleanup (tree fndecl, tree orig_body, void *wd)
115{
116  tree frame = make_cilk_frame (fndecl);
117  tree dtor = create_cilk_function_exit (frame, false, false);
118  add_local_decl (cfun, frame);
119
120  cfun->language = ggc_cleared_alloc<language_function> ();
121
122  location_t loc = EXPR_LOCATION (orig_body);
123  tree list = alloc_stmt_list ();
124  DECL_SAVED_TREE (fndecl) = list;
125  tree fptr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (frame)), frame);
126  tree body = cilk_install_body_pedigree_operations (fptr);
127  gcc_assert (TREE_CODE (body) == STATEMENT_LIST);
128  tree detach_expr = build_call_expr (cilk_detach_fndecl, 1, fptr);
129  append_to_statement_list (detach_expr, &body);
130  cilk_outline (fndecl, &orig_body, (struct wrapper_data *) wd);
131  append_to_statement_list (orig_body, &body);
132  if (flag_exceptions)
133    {
134      tree except_flag = set_cilk_except_flag (frame);
135      tree except_data = set_cilk_except_data (frame);
136      tree catch_list = alloc_stmt_list ();
137      append_to_statement_list (except_flag, &catch_list);
138      append_to_statement_list (except_data, &catch_list);
139      body = create_try_catch_expr (body, catch_list);
140    }
141  append_to_statement_list (build_stmt (loc, TRY_FINALLY_EXPR, body, dtor),
142			    &list);
143}
144