]>
Commit | Line | Data |
---|---|---|
2ce86d2e BI |
1 | /* This file is part of the Intel(R) Cilk(TM) Plus support |
2 | It contains routines to handle Array Notation expression | |
3 | handling routines in the C++ Compiler. | |
818ab71a | 4 | Copyright (C) 2013-2016 Free Software Foundation, Inc. |
2ce86d2e BI |
5 | Contributed by Balaji V. Iyer <balaji.v.iyer@intel.com>, |
6 | Intel Corporation | |
7 | ||
8 | This file is part of GCC. | |
9 | ||
10 | GCC is free software; you can redistribute it and/or modify it | |
11 | under the terms of the GNU General Public License as published by | |
12 | the Free Software Foundation; either version 3, or (at your option) | |
13 | any later version. | |
14 | ||
15 | GCC is distributed in the hope that it will be useful, but | |
16 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
18 | General Public License for more details. | |
19 | ||
20 | You should have received a copy of the GNU General Public License | |
21 | along with GCC; see the file COPYING3. If not see | |
22 | <http://www.gnu.org/licenses/>. */ | |
23 | ||
24 | /* The Array Notation Transformation Technique: | |
25 | ||
26 | An array notation expression has 4 major components: | |
27 | 1. The array name | |
28 | 2. Start Index | |
d8000f03 | 29 | 3. Number of elements we need to access (we call it length) |
2ce86d2e BI |
30 | 4. Stride |
31 | ||
32 | So, if we have something like A[0:5:2], we are accessing A[0], A[2], A[4], | |
33 | A[6] and A[8]. The user is responsible to make sure the access length does | |
34 | not step outside the array's size. | |
35 | ||
36 | In this section, I highlight the overall method on how array notations are | |
37 | broken up into C/C++ code. Almost all the functions follows this step: | |
38 | ||
39 | Let's say the user has used the array notation in a statement like this: | |
40 | ||
41 | A[St1:Ln:Str1] = B[St2:Ln:Str2] + <NON ARRAY_NOT STMT> | |
42 | ||
43 | where St{1,2} = Starting index, Ln = Number of elements we need to access, | |
44 | and Str{1,2} = the stride. | |
45 | Note: The length of both the array notation expressions must be the same. | |
46 | ||
47 | The above expression is broken into the following: | |
48 | ||
49 | for (Tmp_Var = 0; Tmp_Var < Ln; Tmp_Var++) | |
50 | A[St1 + Tmp_Var * Str1] = B[St1 + Tmp_Var * Str2] + <NON_ARRAY_NOT_STMT>; | |
51 | */ | |
52 | ||
53 | #include "config.h" | |
54 | #include "system.h" | |
55 | #include "coretypes.h" | |
2ce86d2e | 56 | #include "cp-tree.h" |
2ce86d2e | 57 | #include "tree-iterator.h" |
2ce86d2e BI |
58 | |
59 | /* Creates a FOR_STMT with INIT, COND, INCR and BODY as the initializer, | |
60 | condition, increment expression and the loop-body, respectively. */ | |
61 | ||
62 | static void | |
63 | create_an_loop (tree init, tree cond, tree incr, tree body) | |
64 | { | |
65 | tree for_stmt; | |
66 | ||
67 | finish_expr_stmt (init); | |
68 | for_stmt = begin_for_stmt (NULL_TREE, NULL_TREE); | |
69 | finish_for_init_stmt (for_stmt); | |
c5028d80 | 70 | finish_for_cond (cond, for_stmt, false); |
2ce86d2e BI |
71 | finish_for_expr (incr, for_stmt); |
72 | finish_expr_stmt (body); | |
73 | finish_for_stmt (for_stmt); | |
74 | } | |
75 | ||
2ce86d2e BI |
76 | /* If *VALUE is not a constant integer, then this function replaces it with |
77 | a variable to make it loop invariant for array notations. */ | |
78 | ||
79 | static inline void | |
1141ed3f | 80 | make_triplet_val_inv (tree *value) |
2ce86d2e | 81 | { |
2ce86d2e BI |
82 | if (TREE_CODE (*value) != INTEGER_CST |
83 | && TREE_CODE (*value) != PARM_DECL | |
56a6f1d3 | 84 | && !VAR_P (*value)) |
1141ed3f | 85 | *value = get_temp_regvar (ptrdiff_type_node, *value); |
2ce86d2e BI |
86 | } |
87 | ||
88 | /* Returns a vector of size RANK that contains an ARRAY_REF. This vector is | |
89 | created using array notation-triplet information stored in AN_INFO. The | |
90 | induction var is taken from AN_LOOP_INFO. | |
91 | ||
92 | For example: For an array notation A[5:10:2], the vector start will be | |
93 | of size 1 holding '5', stride of same size as start but holding the value of | |
94 | as 2, and is_vector as true. Let's assume VAR is 'x' | |
95 | This function returns a vector of size 1 with the following data: | |
96 | A[5 + (x * 2)] . | |
97 | */ | |
98 | ||
99 | static vec<tree, va_gc> * | |
100 | create_array_refs (location_t loc, vec<vec<an_parts> > an_info, | |
101 | vec<an_loop_parts> an_loop_info, size_t size, size_t rank) | |
102 | { | |
103 | tree ind_mult, ind_incr; | |
104 | vec<tree, va_gc> *array_operand = NULL; | |
1141ed3f | 105 | |
2ce86d2e BI |
106 | for (size_t ii = 0; ii < size; ii++) |
107 | if (an_info[ii][0].is_vector) | |
108 | { | |
109 | tree array_opr = an_info[ii][rank - 1].value; | |
110 | for (int s_jj = rank -1; s_jj >= 0; s_jj--) | |
111 | { | |
1141ed3f BI |
112 | tree start = cp_fold_convert (ptrdiff_type_node, |
113 | an_info[ii][s_jj].start); | |
114 | tree stride = cp_fold_convert (ptrdiff_type_node, | |
115 | an_info[ii][s_jj].stride); | |
116 | tree var = cp_fold_convert (ptrdiff_type_node, | |
117 | an_loop_info[s_jj].var); | |
118 | ||
119 | ind_mult = build2 (MULT_EXPR, TREE_TYPE (var), var, stride); | |
120 | ind_incr = build2 (PLUS_EXPR, TREE_TYPE (var), start, ind_mult); | |
2ce86d2e BI |
121 | /* Array [ start_index + (induction_var * stride)] */ |
122 | array_opr = grok_array_decl (loc, array_opr, ind_incr, false); | |
123 | } | |
124 | vec_safe_push (array_operand, array_opr); | |
125 | } | |
126 | else | |
127 | vec_safe_push (array_operand, integer_one_node); | |
128 | return array_operand; | |
129 | } | |
130 | ||
131 | /* Populates the INCR and CMP fields in *NODE with the increment | |
132 | (of type POSTINCREMENT) and comparison (of TYPE LT_EXPR) expressions, using | |
133 | data from AN_INFO. */ | |
134 | ||
135 | void | |
136 | create_cmp_incr (location_t loc, vec <an_loop_parts> *node, size_t rank, | |
137 | vec<vec<an_parts> > an_info, tsubst_flags_t complain) | |
138 | { | |
139 | for (size_t ii = 0; ii < rank; ii++) | |
140 | { | |
141 | (*node)[ii].incr = build_x_unary_op (loc, POSTINCREMENT_EXPR, | |
142 | (*node)[ii].var, complain); | |
143 | (*node)[ii].cmp = build_x_binary_op (loc, LT_EXPR, (*node)[ii].var, | |
144 | TREE_CODE ((*node)[ii].var), | |
145 | an_info[0][ii].length, | |
146 | TREE_CODE (an_info[0][ii].length), | |
147 | NULL, complain); | |
148 | } | |
149 | } | |
150 | ||
151 | /* Replaces all the scalar expressions in *NODE. Returns a STATEMENT LIST that | |
152 | holds the NODE along with the variables that hold the results of the | |
153 | invariant expressions. */ | |
154 | ||
155 | static tree | |
156 | replace_invariant_exprs (tree *node) | |
157 | { | |
158 | size_t ix = 0; | |
159 | tree node_list = NULL_TREE; | |
1141ed3f | 160 | tree t = NULL_TREE, new_var = NULL_TREE; |
2ce86d2e BI |
161 | struct inv_list data; |
162 | ||
163 | data.list_values = NULL; | |
164 | data.replacement = NULL; | |
165 | data.additional_tcodes = NULL; | |
166 | cp_walk_tree (node, find_inv_trees, (void *) &data, NULL); | |
167 | ||
168 | if (vec_safe_length (data.list_values)) | |
169 | { | |
170 | node_list = push_stmt_list (); | |
171 | for (ix = 0; vec_safe_iterate (data.list_values, ix, &t); ix++) | |
1141ed3f BI |
172 | { |
173 | /* Sometimes, when comma_expr has a function call in it, it will | |
174 | typecast it to void. Find_inv_trees finds those nodes and so | |
175 | if it void type, then don't bother creating a new var to hold | |
176 | the return value. */ | |
177 | if (VOID_TYPE_P (TREE_TYPE (t))) | |
178 | { | |
179 | finish_expr_stmt (t); | |
632f2871 | 180 | new_var = void_node; |
1141ed3f BI |
181 | } |
182 | else | |
183 | new_var = get_temp_regvar (TREE_TYPE (t), t); | |
2ce86d2e BI |
184 | vec_safe_push (data.replacement, new_var); |
185 | } | |
186 | cp_walk_tree (node, replace_inv_trees, (void *) &data, NULL); | |
187 | node_list = pop_stmt_list (node_list); | |
188 | } | |
189 | return node_list; | |
190 | } | |
191 | ||
192 | /* Replace array notation's built-in function passed in AN_BUILTIN_FN with | |
193 | the appropriate loop and computation (all stored in variable LOOP of type | |
026c3cfd | 194 | tree node). The output of the function is always a scalar and that |
2ce86d2e BI |
195 | result is returned in *NEW_VAR. *NEW_VAR is NULL_TREE if the function is |
196 | __sec_reduce_mutating. */ | |
197 | ||
198 | static tree | |
199 | expand_sec_reduce_builtin (tree an_builtin_fn, tree *new_var) | |
200 | { | |
201 | tree new_var_type = NULL_TREE, func_parm, new_yes_expr, new_no_expr; | |
202 | tree array_ind_value = NULL_TREE, new_no_ind, new_yes_ind, new_no_list; | |
203 | tree new_yes_list, new_cond_expr, new_expr = NULL_TREE; | |
2ce86d2e BI |
204 | vec<tree, va_gc> *array_list = NULL, *array_operand = NULL; |
205 | size_t list_size = 0, rank = 0, ii = 0; | |
206 | tree body, an_init, loop_with_init = alloc_stmt_list (); | |
207 | tree array_op0, comp_node = NULL_TREE; | |
208 | tree call_fn = NULL_TREE, identity_value = NULL_TREE; | |
209 | tree init = NULL_TREE, cond_init = NULL_TREE; | |
210 | enum tree_code code = NOP_EXPR; | |
211 | location_t location = UNKNOWN_LOCATION; | |
212 | vec<vec<an_parts> > an_info = vNULL; | |
b58d3df2 | 213 | auto_vec<an_loop_parts> an_loop_info; |
2ce86d2e BI |
214 | enum built_in_function an_type = |
215 | is_cilkplus_reduce_builtin (CALL_EXPR_FN (an_builtin_fn)); | |
216 | vec <tree, va_gc> *func_args; | |
217 | ||
218 | if (an_type == BUILT_IN_NONE) | |
219 | return NULL_TREE; | |
220 | ||
221 | if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE | |
222 | && an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING) | |
223 | func_parm = CALL_EXPR_ARG (an_builtin_fn, 0); | |
224 | else | |
225 | { | |
226 | call_fn = CALL_EXPR_ARG (an_builtin_fn, 2); | |
227 | ||
228 | /* We need to do this because we are "faking" the builtin function types, | |
229 | so the compiler does a bunch of typecasts and this will get rid of | |
230 | all that! */ | |
231 | STRIP_NOPS (call_fn); | |
232 | if (TREE_CODE (call_fn) != OVERLOAD | |
233 | && TREE_CODE (call_fn) != FUNCTION_DECL) | |
234 | call_fn = TREE_OPERAND (call_fn, 0); | |
235 | identity_value = CALL_EXPR_ARG (an_builtin_fn, 0); | |
236 | func_parm = CALL_EXPR_ARG (an_builtin_fn, 1); | |
237 | STRIP_NOPS (identity_value); | |
238 | } | |
239 | STRIP_NOPS (func_parm); | |
240 | ||
241 | location = EXPR_LOCATION (an_builtin_fn); | |
242 | ||
243 | /* Note about using find_rank (): If find_rank returns false, then it must | |
244 | have already reported an error, thus we just return an error_mark_node | |
245 | without any doing any error emission. */ | |
246 | if (!find_rank (location, an_builtin_fn, an_builtin_fn, true, &rank)) | |
247 | return error_mark_node; | |
248 | if (rank == 0) | |
5e88a8f4 IZ |
249 | { |
250 | error_at (location, "Invalid builtin arguments"); | |
251 | return error_mark_node; | |
252 | } | |
2ce86d2e BI |
253 | else if (rank > 1 |
254 | && (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND | |
255 | || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND)) | |
256 | { | |
257 | error_at (location, "__sec_reduce_min_ind or __sec_reduce_max_ind cannot " | |
258 | "have arrays with dimension greater than 1"); | |
259 | return error_mark_node; | |
260 | } | |
261 | ||
262 | extract_array_notation_exprs (func_parm, true, &array_list); | |
263 | list_size = vec_safe_length (array_list); | |
264 | switch (an_type) | |
265 | { | |
266 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD: | |
267 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL: | |
268 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX: | |
269 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN: | |
270 | new_var_type = TREE_TYPE ((*array_list)[0]); | |
271 | break; | |
272 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO: | |
273 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO: | |
274 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO: | |
275 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO: | |
1141ed3f | 276 | new_var_type = boolean_type_node; |
2ce86d2e BI |
277 | break; |
278 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND: | |
279 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND: | |
280 | new_var_type = size_type_node; | |
281 | break; | |
282 | case BUILT_IN_CILKPLUS_SEC_REDUCE: | |
283 | if (call_fn && identity_value) | |
284 | new_var_type = TREE_TYPE ((*array_list)[0]); | |
285 | break; | |
286 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING: | |
287 | new_var_type = NULL_TREE; | |
288 | break; | |
289 | default: | |
290 | gcc_unreachable (); | |
291 | } | |
292 | ||
293 | if (new_var_type && TREE_CODE (new_var_type) == ARRAY_TYPE) | |
294 | new_var_type = TREE_TYPE (new_var_type); | |
295 | an_loop_info.safe_grow_cleared (rank); | |
296 | ||
297 | an_init = push_stmt_list (); | |
298 | ||
299 | /* Assign the array notation components to variable so that they can satisfy | |
300 | the exec-once rule. */ | |
301 | for (ii = 0; ii < list_size; ii++) | |
302 | if (TREE_CODE ((*array_list)[ii]) == ARRAY_NOTATION_REF) | |
303 | { | |
304 | tree anode = (*array_list)[ii]; | |
1141ed3f BI |
305 | make_triplet_val_inv (&ARRAY_NOTATION_START (anode)); |
306 | make_triplet_val_inv (&ARRAY_NOTATION_LENGTH (anode)); | |
307 | make_triplet_val_inv (&ARRAY_NOTATION_STRIDE (anode)); | |
2ce86d2e BI |
308 | } |
309 | cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info); | |
310 | for (ii = 0; ii < rank; ii++) | |
311 | { | |
1141ed3f BI |
312 | tree typ = ptrdiff_type_node; |
313 | ||
314 | /* In this place, we are using get_temp_regvar instead of | |
315 | create_temporary_var if an_type is SEC_REDUCE_MAX/MIN_IND because | |
316 | the array_ind_value depends on this value being initalized to 0. */ | |
317 | if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND | |
318 | || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND) | |
319 | an_loop_info[ii].var = get_temp_regvar (typ, build_zero_cst (typ)); | |
320 | else | |
321 | { | |
322 | an_loop_info[ii].var = create_temporary_var (typ); | |
323 | add_decl_expr (an_loop_info[ii].var); | |
324 | } | |
325 | an_loop_info[ii].ind_init = | |
326 | build_x_modify_expr (location, an_loop_info[ii].var, INIT_EXPR, | |
327 | build_zero_cst (typ), tf_warning_or_error); | |
2ce86d2e | 328 | } |
2ce86d2e BI |
329 | array_operand = create_array_refs (location, an_info, an_loop_info, |
330 | list_size, rank); | |
331 | replace_array_notations (&func_parm, true, array_list, array_operand); | |
332 | ||
333 | if (!TREE_TYPE (func_parm)) | |
334 | TREE_TYPE (func_parm) = TREE_TYPE ((*array_list)[0]); | |
335 | ||
336 | create_cmp_incr (location, &an_loop_info, rank, an_info, tf_warning_or_error); | |
2ce86d2e | 337 | if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND |
1141ed3f BI |
338 | || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND) |
339 | array_ind_value = get_temp_regvar (TREE_TYPE (func_parm), func_parm); | |
2ce86d2e BI |
340 | |
341 | array_op0 = (*array_operand)[0]; | |
311bd4d8 | 342 | if (INDIRECT_REF_P (array_op0)) |
9dc7743c | 343 | array_op0 = TREE_OPERAND (array_op0, 0); |
2ce86d2e BI |
344 | switch (an_type) |
345 | { | |
346 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD: | |
347 | code = PLUS_EXPR; | |
348 | init = build_zero_cst (new_var_type); | |
349 | break; | |
350 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL: | |
351 | code = MULT_EXPR; | |
352 | init = build_one_cst (new_var_type); | |
353 | break; | |
354 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO: | |
355 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO: | |
1141ed3f BI |
356 | code = ((an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO) ? EQ_EXPR |
357 | : NE_EXPR); | |
2ce86d2e BI |
358 | init = build_zero_cst (new_var_type); |
359 | cond_init = build_one_cst (new_var_type); | |
360 | comp_node = build_zero_cst (TREE_TYPE (func_parm)); | |
361 | break; | |
362 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO: | |
363 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO: | |
1141ed3f BI |
364 | code = ((an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO) ? NE_EXPR |
365 | : EQ_EXPR); | |
2ce86d2e BI |
366 | init = build_one_cst (new_var_type); |
367 | cond_init = build_zero_cst (new_var_type); | |
368 | comp_node = build_zero_cst (TREE_TYPE (func_parm)); | |
369 | break; | |
370 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX: | |
371 | code = MAX_EXPR; | |
1141ed3f BI |
372 | init = (TYPE_MIN_VALUE (new_var_type) ? TYPE_MIN_VALUE (new_var_type) |
373 | : func_parm); | |
2ce86d2e BI |
374 | break; |
375 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN: | |
376 | code = MIN_EXPR; | |
1141ed3f BI |
377 | init = (TYPE_MAX_VALUE (new_var_type) ? TYPE_MAX_VALUE (new_var_type) |
378 | : func_parm); | |
2ce86d2e BI |
379 | break; |
380 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND: | |
381 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND: | |
1141ed3f BI |
382 | code = (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND ? LE_EXPR |
383 | : GE_EXPR); | |
2ce86d2e | 384 | init = an_loop_info[0].var; |
1141ed3f | 385 | break; |
2ce86d2e BI |
386 | case BUILT_IN_CILKPLUS_SEC_REDUCE: |
387 | init = identity_value; | |
388 | break; | |
389 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING: | |
390 | init = NULL_TREE; | |
391 | break; | |
392 | default: | |
393 | gcc_unreachable (); | |
394 | } | |
395 | ||
1141ed3f BI |
396 | if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING) |
397 | *new_var = get_temp_regvar (new_var_type, init); | |
398 | else | |
399 | *new_var = NULL_TREE; | |
400 | ||
2ce86d2e BI |
401 | switch (an_type) |
402 | { | |
403 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD: | |
404 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL: | |
405 | new_expr = build_x_modify_expr (location, *new_var, code, func_parm, | |
406 | tf_warning_or_error); | |
407 | break; | |
408 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO: | |
409 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO: | |
410 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO: | |
411 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO: | |
412 | /* In all these cases, assume the false case is true and as soon as | |
413 | we find a true case, set the true flag on and latch it in. */ | |
414 | new_yes_expr = build_x_modify_expr (location, *new_var, NOP_EXPR, | |
415 | cond_init, tf_warning_or_error); | |
416 | new_no_expr = build_x_modify_expr (location, *new_var, NOP_EXPR, | |
417 | *new_var, tf_warning_or_error); | |
418 | new_cond_expr = build_x_binary_op | |
419 | (location, code, func_parm, TREE_CODE (func_parm), comp_node, | |
420 | TREE_CODE (comp_node), NULL, tf_warning_or_error); | |
421 | new_expr = build_x_conditional_expr (location, new_cond_expr, | |
422 | new_yes_expr, new_no_expr, | |
423 | tf_warning_or_error); | |
424 | break; | |
425 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX: | |
426 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN: | |
427 | new_cond_expr = build_x_binary_op | |
428 | (location, code, *new_var, TREE_CODE (*new_var), func_parm, | |
429 | TREE_CODE (func_parm), NULL, tf_warning_or_error); | |
430 | new_expr = build_x_modify_expr (location, *new_var, NOP_EXPR, func_parm, | |
431 | tf_warning_or_error); | |
432 | break; | |
433 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND: | |
434 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND: | |
2ce86d2e BI |
435 | new_yes_expr = build_x_modify_expr (location, array_ind_value, NOP_EXPR, |
436 | func_parm, tf_warning_or_error); | |
437 | new_no_expr = build_x_modify_expr (location, array_ind_value, NOP_EXPR, | |
438 | array_ind_value, tf_warning_or_error); | |
439 | if (list_size > 1) | |
440 | new_yes_ind = build_x_modify_expr (location, *new_var, NOP_EXPR, | |
441 | an_loop_info[0].var, | |
442 | tf_warning_or_error); | |
443 | else | |
444 | new_yes_ind = build_x_modify_expr (location, *new_var, NOP_EXPR, | |
445 | TREE_OPERAND (array_op0, 1), | |
446 | tf_warning_or_error); | |
447 | new_no_ind = build_x_modify_expr (location, *new_var, NOP_EXPR, *new_var, | |
448 | tf_warning_or_error); | |
449 | new_yes_list = alloc_stmt_list (); | |
450 | append_to_statement_list (new_yes_ind, &new_yes_list); | |
451 | append_to_statement_list (new_yes_expr, &new_yes_list); | |
452 | ||
453 | new_no_list = alloc_stmt_list (); | |
454 | append_to_statement_list (new_no_ind, &new_no_list); | |
455 | append_to_statement_list (new_no_expr, &new_no_list); | |
456 | ||
457 | new_cond_expr = build_x_binary_op (location, code, array_ind_value, | |
458 | TREE_CODE (array_ind_value), func_parm, | |
459 | TREE_CODE (func_parm), NULL, | |
460 | tf_warning_or_error); | |
461 | new_expr = build_x_conditional_expr (location, new_cond_expr, | |
462 | new_yes_list, new_no_list, | |
463 | tf_warning_or_error); | |
464 | break; | |
465 | case BUILT_IN_CILKPLUS_SEC_REDUCE: | |
466 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING: | |
467 | func_args = make_tree_vector (); | |
468 | if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE) | |
469 | vec_safe_push (func_args, *new_var); | |
470 | else | |
471 | vec_safe_push (func_args, identity_value); | |
472 | vec_safe_push (func_args, func_parm); | |
473 | ||
474 | new_expr = finish_call_expr (call_fn, &func_args, false, true, | |
475 | tf_warning_or_error); | |
476 | if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE) | |
477 | new_expr = build_x_modify_expr (location, *new_var, NOP_EXPR, new_expr, | |
478 | tf_warning_or_error); | |
479 | release_tree_vector (func_args); | |
480 | break; | |
481 | default: | |
482 | gcc_unreachable (); | |
483 | } | |
2ce86d2e | 484 | an_init = pop_stmt_list (an_init); |
1141ed3f | 485 | append_to_statement_list (an_init, &loop_with_init); |
2ce86d2e BI |
486 | body = new_expr; |
487 | ||
488 | for (ii = 0; ii < rank; ii++) | |
489 | { | |
490 | tree new_loop = push_stmt_list (); | |
491 | create_an_loop (an_loop_info[ii].ind_init, an_loop_info[ii].cmp, | |
492 | an_loop_info[ii].incr, body); | |
493 | body = pop_stmt_list (new_loop); | |
494 | } | |
1141ed3f | 495 | append_to_statement_list (body, &loop_with_init); |
2ce86d2e | 496 | |
b58d3df2 | 497 | release_vec_vec (an_info); |
2ce86d2e BI |
498 | |
499 | return loop_with_init; | |
500 | } | |
501 | ||
502 | /* Returns a loop with ARRAY_REF inside it with an appropriate modify expr. | |
503 | The LHS and/or RHS will be array notation expressions that have a | |
504 | MODIFYCODE. The location of the variable is specified by LOCATION. */ | |
505 | ||
506 | static tree | |
507 | expand_an_in_modify_expr (location_t location, tree lhs, | |
508 | enum tree_code modifycode, tree rhs, | |
509 | tsubst_flags_t complain) | |
510 | { | |
511 | tree array_expr_lhs = NULL_TREE, array_expr_rhs = NULL_TREE; | |
512 | tree array_expr = NULL_TREE; | |
513 | tree body = NULL_TREE; | |
b58d3df2 | 514 | auto_vec<tree> cond_expr; |
2ce86d2e BI |
515 | vec<tree, va_gc> *lhs_array_operand = NULL, *rhs_array_operand = NULL; |
516 | size_t lhs_rank = 0, rhs_rank = 0, ii = 0; | |
517 | vec<tree, va_gc> *rhs_list = NULL, *lhs_list = NULL; | |
518 | size_t rhs_list_size = 0, lhs_list_size = 0; | |
519 | tree new_modify_expr, new_var = NULL_TREE, builtin_loop, scalar_mods; | |
520 | bool found_builtin_fn = false; | |
521 | tree an_init, loop_with_init = alloc_stmt_list (); | |
522 | vec<vec<an_parts> > lhs_an_info = vNULL, rhs_an_info = vNULL; | |
b58d3df2 ML |
523 | auto_vec<an_loop_parts> lhs_an_loop_info, rhs_an_loop_info; |
524 | tree lhs_len, rhs_len; | |
2ce86d2e BI |
525 | |
526 | if (!find_rank (location, rhs, rhs, false, &rhs_rank)) | |
527 | return error_mark_node; | |
528 | extract_array_notation_exprs (rhs, false, &rhs_list); | |
529 | rhs_list_size = vec_safe_length (rhs_list); | |
530 | an_init = push_stmt_list (); | |
531 | if (rhs_rank) | |
532 | { | |
533 | scalar_mods = replace_invariant_exprs (&rhs); | |
534 | if (scalar_mods) | |
535 | finish_expr_stmt (scalar_mods); | |
536 | } | |
537 | for (ii = 0; ii < rhs_list_size; ii++) | |
538 | { | |
539 | tree rhs_node = (*rhs_list)[ii]; | |
540 | if (TREE_CODE (rhs_node) == CALL_EXPR) | |
541 | { | |
542 | builtin_loop = expand_sec_reduce_builtin (rhs_node, &new_var); | |
543 | if (builtin_loop == error_mark_node) | |
544 | return error_mark_node; | |
545 | else if (builtin_loop) | |
546 | { | |
547 | finish_expr_stmt (builtin_loop); | |
548 | found_builtin_fn = true; | |
549 | if (new_var) | |
550 | { | |
551 | vec <tree, va_gc> *rhs_sub_list = NULL, *new_var_list = NULL; | |
552 | vec_safe_push (rhs_sub_list, rhs_node); | |
553 | vec_safe_push (new_var_list, new_var); | |
554 | replace_array_notations (&rhs, false, rhs_sub_list, | |
555 | new_var_list); | |
556 | } | |
557 | } | |
558 | } | |
559 | } | |
560 | lhs_rank = 0; | |
561 | rhs_rank = 0; | |
562 | if (!find_rank (location, lhs, lhs, true, &lhs_rank) | |
563 | || !find_rank (location, rhs, rhs, true, &rhs_rank)) | |
564 | { | |
565 | pop_stmt_list (an_init); | |
566 | return error_mark_node; | |
567 | } | |
568 | ||
569 | /* If both are scalar, then the only reason why we will get this far is if | |
570 | there is some array notations inside it and was using a builtin array | |
571 | notation functions. If so, we have already broken those guys up and now | |
572 | a simple build_x_modify_expr would do. */ | |
573 | if (lhs_rank == 0 && rhs_rank == 0) | |
574 | { | |
575 | if (found_builtin_fn) | |
576 | { | |
577 | new_modify_expr = build_x_modify_expr (location, lhs, | |
578 | modifycode, rhs, complain); | |
579 | finish_expr_stmt (new_modify_expr); | |
580 | pop_stmt_list (an_init); | |
581 | return an_init; | |
582 | } | |
583 | else | |
1141ed3f | 584 | gcc_unreachable (); |
2ce86d2e BI |
585 | } |
586 | ||
587 | /* If for some reason location is not set, then find if LHS or RHS has | |
588 | location info. If so, then use that so we atleast have an idea. */ | |
589 | if (location == UNKNOWN_LOCATION) | |
590 | { | |
591 | if (EXPR_LOCATION (lhs) != UNKNOWN_LOCATION) | |
592 | location = EXPR_LOCATION (lhs); | |
593 | else if (EXPR_LOCATION (rhs) != UNKNOWN_LOCATION) | |
594 | location = EXPR_LOCATION (rhs); | |
595 | } | |
596 | ||
597 | /* We need this when we have a scatter issue. */ | |
598 | extract_array_notation_exprs (lhs, true, &lhs_list); | |
599 | rhs_list = NULL; | |
600 | extract_array_notation_exprs (rhs, true, &rhs_list); | |
601 | rhs_list_size = vec_safe_length (rhs_list); | |
602 | lhs_list_size = vec_safe_length (lhs_list); | |
603 | ||
604 | if (lhs_rank == 0 && rhs_rank != 0) | |
605 | { | |
fba8a9e3 | 606 | error_at (location, "%qE cannot be scalar when %qE is not", lhs, rhs); |
2ce86d2e BI |
607 | return error_mark_node; |
608 | } | |
609 | if (lhs_rank != 0 && rhs_rank != 0 && lhs_rank != rhs_rank) | |
610 | { | |
611 | error_at (location, "rank mismatch between %qE and %qE", lhs, rhs); | |
612 | return error_mark_node; | |
613 | } | |
614 | ||
615 | /* Assign the array notation components to variable so that they can satisfy | |
616 | the execute-once rule. */ | |
617 | for (ii = 0; ii < lhs_list_size; ii++) | |
618 | { | |
619 | tree anode = (*lhs_list)[ii]; | |
1141ed3f BI |
620 | make_triplet_val_inv (&ARRAY_NOTATION_START (anode)); |
621 | make_triplet_val_inv (&ARRAY_NOTATION_LENGTH (anode)); | |
622 | make_triplet_val_inv (&ARRAY_NOTATION_STRIDE (anode)); | |
2ce86d2e BI |
623 | } |
624 | for (ii = 0; ii < rhs_list_size; ii++) | |
625 | if ((*rhs_list)[ii] && TREE_CODE ((*rhs_list)[ii]) == ARRAY_NOTATION_REF) | |
626 | { | |
627 | tree aa = (*rhs_list)[ii]; | |
1141ed3f BI |
628 | make_triplet_val_inv (&ARRAY_NOTATION_START (aa)); |
629 | make_triplet_val_inv (&ARRAY_NOTATION_LENGTH (aa)); | |
630 | make_triplet_val_inv (&ARRAY_NOTATION_STRIDE (aa)); | |
2ce86d2e BI |
631 | } |
632 | lhs_an_loop_info.safe_grow_cleared (lhs_rank); | |
633 | ||
634 | if (rhs_rank) | |
635 | rhs_an_loop_info.safe_grow_cleared (rhs_rank); | |
636 | ||
637 | cond_expr.safe_grow_cleared (MAX (lhs_rank, rhs_rank)); | |
638 | cilkplus_extract_an_triplets (lhs_list, lhs_list_size, lhs_rank, | |
639 | &lhs_an_info); | |
640 | if (rhs_list) | |
641 | cilkplus_extract_an_triplets (rhs_list, rhs_list_size, rhs_rank, | |
642 | &rhs_an_info); | |
713b46fa BI |
643 | if (length_mismatch_in_expr_p (EXPR_LOCATION (lhs), lhs_an_info) |
644 | || (rhs_list && length_mismatch_in_expr_p (EXPR_LOCATION (rhs), | |
645 | rhs_an_info))) | |
2ce86d2e BI |
646 | { |
647 | pop_stmt_list (an_init); | |
b58d3df2 | 648 | goto error; |
2ce86d2e | 649 | } |
b58d3df2 | 650 | rhs_len = ((rhs_list_size > 0 && rhs_rank > 0) ? |
1141ed3f | 651 | rhs_an_info[0][0].length : NULL_TREE); |
b58d3df2 | 652 | lhs_len = ((lhs_list_size > 0 && lhs_rank > 0) ? |
1141ed3f | 653 | lhs_an_info[0][0].length : NULL_TREE); |
2ce86d2e BI |
654 | if (lhs_list_size > 0 && rhs_list_size > 0 && lhs_rank > 0 && rhs_rank > 0 |
655 | && TREE_CODE (lhs_len) == INTEGER_CST && rhs_len | |
1141ed3f BI |
656 | && TREE_CODE (rhs_len) == INTEGER_CST |
657 | && !tree_int_cst_equal (rhs_len, lhs_len)) | |
658 | { | |
659 | error_at (location, "length mismatch between LHS and RHS"); | |
660 | pop_stmt_list (an_init); | |
b58d3df2 | 661 | goto error; |
2ce86d2e | 662 | } |
1141ed3f BI |
663 | for (ii = 0; ii < lhs_rank; ii++) |
664 | { | |
665 | tree typ = ptrdiff_type_node; | |
666 | lhs_an_loop_info[ii].var = create_temporary_var (typ); | |
667 | add_decl_expr (lhs_an_loop_info[ii].var); | |
668 | lhs_an_loop_info[ii].ind_init = build_x_modify_expr | |
669 | (location, lhs_an_loop_info[ii].var, INIT_EXPR, build_zero_cst (typ), | |
670 | complain); | |
671 | } | |
672 | ||
2ce86d2e BI |
673 | if (rhs_list_size > 0) |
674 | { | |
675 | rhs_array_operand = fix_sec_implicit_args (location, rhs_list, | |
676 | lhs_an_loop_info, lhs_rank, | |
677 | lhs); | |
678 | if (!rhs_array_operand) | |
b58d3df2 | 679 | goto error; |
2ce86d2e BI |
680 | } |
681 | replace_array_notations (&rhs, true, rhs_list, rhs_array_operand); | |
682 | rhs_list_size = 0; | |
683 | rhs_list = NULL; | |
684 | extract_array_notation_exprs (rhs, true, &rhs_list); | |
685 | rhs_list_size = vec_safe_length (rhs_list); | |
1141ed3f | 686 | |
2ce86d2e BI |
687 | for (ii = 0; ii < rhs_rank; ii++) |
688 | { | |
1141ed3f BI |
689 | tree typ = ptrdiff_type_node; |
690 | rhs_an_loop_info[ii].var = create_temporary_var (typ); | |
691 | add_decl_expr (rhs_an_loop_info[ii].var); | |
2ce86d2e | 692 | rhs_an_loop_info[ii].ind_init = build_x_modify_expr |
1141ed3f BI |
693 | (location, rhs_an_loop_info[ii].var, INIT_EXPR, build_zero_cst (typ), |
694 | complain); | |
2ce86d2e BI |
695 | } |
696 | ||
697 | if (lhs_rank) | |
698 | { | |
699 | lhs_array_operand = | |
700 | create_array_refs (location, lhs_an_info, lhs_an_loop_info, | |
701 | lhs_list_size, lhs_rank); | |
702 | replace_array_notations (&lhs, true, lhs_list, lhs_array_operand); | |
703 | } | |
704 | ||
705 | if (rhs_array_operand) | |
706 | vec_safe_truncate (rhs_array_operand, 0); | |
707 | if (rhs_rank) | |
708 | { | |
709 | rhs_array_operand = create_array_refs (location, rhs_an_info, | |
710 | rhs_an_loop_info, rhs_list_size, | |
711 | rhs_rank); | |
712 | /* Replace all the array refs created by the above function because this | |
713 | variable is blown away by the fix_sec_implicit_args function below. */ | |
714 | replace_array_notations (&rhs, true, rhs_list, rhs_array_operand); | |
715 | vec_safe_truncate (rhs_array_operand , 0); | |
716 | rhs_array_operand = fix_sec_implicit_args (location, rhs_list, | |
717 | rhs_an_loop_info, rhs_rank, | |
718 | rhs); | |
719 | if (!rhs_array_operand) | |
b58d3df2 | 720 | goto error; |
2ce86d2e BI |
721 | replace_array_notations (&rhs, true, rhs_list, rhs_array_operand); |
722 | } | |
723 | ||
724 | array_expr_rhs = rhs; | |
725 | array_expr_lhs = lhs; | |
726 | ||
727 | array_expr = build_x_modify_expr (location, array_expr_lhs, modifycode, | |
728 | array_expr_rhs, complain); | |
729 | create_cmp_incr (location, &lhs_an_loop_info, lhs_rank, lhs_an_info, | |
730 | complain); | |
731 | if (rhs_rank) | |
732 | create_cmp_incr (location, &rhs_an_loop_info, rhs_rank, rhs_an_info, | |
733 | complain); | |
734 | for (ii = 0; ii < MAX (rhs_rank, lhs_rank); ii++) | |
735 | if (ii < lhs_rank && ii < rhs_rank) | |
736 | cond_expr[ii] = build_x_binary_op | |
737 | (location, TRUTH_ANDIF_EXPR, lhs_an_loop_info[ii].cmp, | |
738 | TREE_CODE (lhs_an_loop_info[ii].cmp), rhs_an_loop_info[ii].cmp, | |
739 | TREE_CODE (rhs_an_loop_info[ii].cmp), NULL, complain); | |
740 | else if (ii < lhs_rank && ii >= rhs_rank) | |
741 | cond_expr[ii] = lhs_an_loop_info[ii].cmp; | |
742 | else | |
1141ed3f BI |
743 | /* No need to compare ii < rhs_rank && ii >= lhs_rank because in a valid |
744 | Array notation expression, rank of RHS cannot be greater than LHS. */ | |
2ce86d2e BI |
745 | gcc_unreachable (); |
746 | ||
747 | an_init = pop_stmt_list (an_init); | |
1141ed3f | 748 | append_to_statement_list (an_init, &loop_with_init); |
2ce86d2e BI |
749 | body = array_expr; |
750 | for (ii = 0; ii < MAX (lhs_rank, rhs_rank); ii++) | |
751 | { | |
752 | tree incr_list = alloc_stmt_list (); | |
753 | tree init_list = alloc_stmt_list (); | |
754 | tree new_loop = push_stmt_list (); | |
755 | ||
756 | if (lhs_rank) | |
757 | { | |
1141ed3f BI |
758 | append_to_statement_list (lhs_an_loop_info[ii].ind_init, &init_list); |
759 | append_to_statement_list (lhs_an_loop_info[ii].incr, &incr_list); | |
2ce86d2e BI |
760 | } |
761 | if (rhs_rank) | |
762 | { | |
1141ed3f BI |
763 | append_to_statement_list (rhs_an_loop_info[ii].ind_init, &init_list); |
764 | append_to_statement_list (rhs_an_loop_info[ii].incr, &incr_list); | |
2ce86d2e BI |
765 | } |
766 | create_an_loop (init_list, cond_expr[ii], incr_list, body); | |
767 | body = pop_stmt_list (new_loop); | |
768 | } | |
769 | append_to_statement_list (body, &loop_with_init); | |
770 | ||
b58d3df2 ML |
771 | release_vec_vec (lhs_an_info); |
772 | release_vec_vec (rhs_an_info); | |
2ce86d2e BI |
773 | |
774 | return loop_with_init; | |
b58d3df2 ML |
775 | |
776 | error: | |
777 | release_vec_vec (lhs_an_info); | |
778 | release_vec_vec (rhs_an_info); | |
779 | ||
780 | return error_mark_node; | |
2ce86d2e BI |
781 | } |
782 | ||
783 | /* Helper function for expand_conditonal_array_notations. Encloses the | |
784 | conditional statement passed in ORIG_STMT with a loop around it and | |
785 | replaces the condition in STMT with a ARRAY_REF tree-node to the array. | |
786 | The condition must have a ARRAY_NOTATION_REF tree. */ | |
787 | ||
788 | static tree | |
789 | cp_expand_cond_array_notations (tree orig_stmt) | |
790 | { | |
791 | vec<tree, va_gc> *array_list = NULL, *array_operand = NULL; | |
792 | size_t list_size = 0; | |
793 | size_t rank = 0, ii = 0; | |
794 | tree an_init, body, stmt = NULL_TREE; | |
795 | tree builtin_loop, new_var = NULL_TREE; | |
796 | tree loop_with_init = alloc_stmt_list (); | |
2ce86d2e BI |
797 | location_t location = UNKNOWN_LOCATION; |
798 | vec<vec<an_parts> > an_info = vNULL; | |
b58d3df2 | 799 | auto_vec<an_loop_parts> an_loop_info; |
2ce86d2e BI |
800 | |
801 | if (TREE_CODE (orig_stmt) == COND_EXPR) | |
802 | { | |
803 | size_t cond_rank = 0, yes_rank = 0, no_rank = 0; | |
804 | tree yes_expr = COND_EXPR_THEN (orig_stmt); | |
805 | tree no_expr = COND_EXPR_ELSE (orig_stmt); | |
806 | tree cond = COND_EXPR_COND (orig_stmt); | |
807 | if (!find_rank (EXPR_LOCATION (cond), cond, cond, true, &cond_rank) | |
808 | || !find_rank (EXPR_LOCATION (yes_expr), yes_expr, yes_expr, true, | |
809 | &yes_rank) | |
810 | || find_rank (EXPR_LOCATION (no_expr), no_expr, no_expr, true, | |
811 | &no_rank)) | |
812 | return error_mark_node; | |
1141ed3f | 813 | /* If the condition has a zero rank, then handle array notations in body |
c65cb8d1 | 814 | separately. */ |
1141ed3f BI |
815 | if (cond_rank == 0) |
816 | return orig_stmt; | |
817 | if (cond_rank != yes_rank && yes_rank != 0) | |
2ce86d2e BI |
818 | { |
819 | error_at (EXPR_LOCATION (yes_expr), "rank mismatch with controlling" | |
820 | " expression of parent if-statement"); | |
821 | return error_mark_node; | |
822 | } | |
1141ed3f | 823 | else if (cond_rank != no_rank && no_rank != 0) |
2ce86d2e BI |
824 | { |
825 | error_at (EXPR_LOCATION (no_expr), "rank mismatch with controlling " | |
826 | "expression of parent if-statement"); | |
827 | return error_mark_node; | |
828 | } | |
829 | } | |
830 | else if (TREE_CODE (orig_stmt) == IF_STMT) | |
831 | { | |
832 | size_t cond_rank = 0, yes_rank = 0, no_rank = 0; | |
833 | tree yes_expr = THEN_CLAUSE (orig_stmt); | |
834 | tree no_expr = ELSE_CLAUSE (orig_stmt); | |
835 | tree cond = IF_COND (orig_stmt); | |
836 | if (!find_rank (EXPR_LOCATION (cond), cond, cond, true, &cond_rank) | |
837 | || (yes_expr | |
838 | && !find_rank (EXPR_LOCATION (yes_expr), yes_expr, yes_expr, true, | |
839 | &yes_rank)) | |
840 | || (no_expr | |
841 | && !find_rank (EXPR_LOCATION (no_expr), no_expr, no_expr, true, | |
842 | &no_rank))) | |
843 | return error_mark_node; | |
1141ed3f BI |
844 | |
845 | /* Same reasoning as for COND_EXPR. */ | |
846 | if (cond_rank == 0) | |
847 | return orig_stmt; | |
848 | else if (cond_rank != yes_rank && yes_rank != 0) | |
2ce86d2e BI |
849 | { |
850 | error_at (EXPR_LOCATION (yes_expr), "rank mismatch with controlling" | |
851 | " expression of parent if-statement"); | |
852 | return error_mark_node; | |
853 | } | |
1141ed3f | 854 | else if (cond_rank != no_rank && no_rank != 0) |
2ce86d2e BI |
855 | { |
856 | error_at (EXPR_LOCATION (no_expr), "rank mismatch with controlling " | |
857 | "expression of parent if-statement"); | |
858 | return error_mark_node; | |
859 | } | |
860 | } | |
318cda85 BI |
861 | else if (truth_value_p (TREE_CODE (orig_stmt))) |
862 | { | |
863 | size_t left_rank = 0, right_rank = 0; | |
864 | tree left_expr = TREE_OPERAND (orig_stmt, 0); | |
865 | tree right_expr = TREE_OPERAND (orig_stmt, 1); | |
866 | if (!find_rank (EXPR_LOCATION (left_expr), left_expr, left_expr, true, | |
867 | &left_rank) | |
868 | || !find_rank (EXPR_LOCATION (right_expr), right_expr, right_expr, | |
869 | true, &right_rank)) | |
870 | return error_mark_node; | |
871 | if (right_rank == 0 && left_rank == 0) | |
872 | return orig_stmt; | |
873 | } | |
2ce86d2e BI |
874 | |
875 | if (!find_rank (EXPR_LOCATION (orig_stmt), orig_stmt, orig_stmt, true, | |
876 | &rank)) | |
877 | return error_mark_node; | |
878 | if (rank == 0) | |
879 | return orig_stmt; | |
880 | ||
881 | extract_array_notation_exprs (orig_stmt, false, &array_list); | |
882 | stmt = alloc_stmt_list (); | |
883 | for (ii = 0; ii < vec_safe_length (array_list); ii++) | |
884 | { | |
885 | tree array_node = (*array_list)[ii]; | |
886 | if (TREE_CODE (array_node) == CALL_EXPR | |
887 | || TREE_CODE (array_node) == AGGR_INIT_EXPR) | |
888 | { | |
889 | builtin_loop = expand_sec_reduce_builtin (array_node, &new_var); | |
890 | if (builtin_loop == error_mark_node) | |
891 | finish_expr_stmt (error_mark_node); | |
892 | else if (new_var) | |
893 | { | |
894 | vec<tree, va_gc> *sub_list = NULL, *new_var_list = NULL; | |
895 | vec_safe_push (sub_list, array_node); | |
896 | vec_safe_push (new_var_list, new_var); | |
897 | replace_array_notations (&orig_stmt, false, sub_list, | |
898 | new_var_list); | |
1141ed3f | 899 | append_to_statement_list (builtin_loop, &stmt); |
2ce86d2e BI |
900 | } |
901 | } | |
902 | } | |
1141ed3f | 903 | append_to_statement_list (orig_stmt, &stmt); |
2ce86d2e BI |
904 | rank = 0; |
905 | array_list = NULL; | |
906 | if (!find_rank (EXPR_LOCATION (stmt), stmt, stmt, true, &rank)) | |
907 | return error_mark_node; | |
908 | if (rank == 0) | |
909 | return stmt; | |
910 | ||
911 | extract_array_notation_exprs (stmt, true, &array_list); | |
912 | list_size = vec_safe_length (array_list); | |
913 | if (list_size == 0) | |
914 | return stmt; | |
915 | ||
916 | location = EXPR_LOCATION (orig_stmt); | |
917 | list_size = vec_safe_length (array_list); | |
918 | an_loop_info.safe_grow_cleared (rank); | |
919 | ||
920 | an_init = push_stmt_list (); | |
921 | ||
922 | /* Assign the array notation components to variable so that they can | |
923 | satisfy the exec-once rule. */ | |
924 | for (ii = 0; ii < list_size; ii++) | |
925 | { | |
926 | tree anode = (*array_list)[ii]; | |
1141ed3f BI |
927 | make_triplet_val_inv (&ARRAY_NOTATION_START (anode)); |
928 | make_triplet_val_inv (&ARRAY_NOTATION_LENGTH (anode)); | |
929 | make_triplet_val_inv (&ARRAY_NOTATION_STRIDE (anode)); | |
2ce86d2e BI |
930 | } |
931 | cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info); | |
1141ed3f BI |
932 | |
933 | for (ii = 0; ii < rank; ii++) | |
934 | { | |
935 | tree typ = ptrdiff_type_node; | |
936 | an_loop_info[ii].var = create_temporary_var (typ); | |
937 | add_decl_expr (an_loop_info[ii].var); | |
938 | an_loop_info[ii].ind_init = | |
939 | build_x_modify_expr (location, an_loop_info[ii].var, INIT_EXPR, | |
940 | build_zero_cst (typ), tf_warning_or_error); | |
941 | } | |
2ce86d2e BI |
942 | array_operand = create_array_refs (location, an_info, an_loop_info, |
943 | list_size, rank); | |
944 | replace_array_notations (&stmt, true, array_list, array_operand); | |
945 | create_cmp_incr (location, &an_loop_info, rank, an_info, tf_warning_or_error); | |
946 | ||
947 | an_init = pop_stmt_list (an_init); | |
1141ed3f | 948 | append_to_statement_list (an_init, &loop_with_init); |
2ce86d2e BI |
949 | body = stmt; |
950 | ||
951 | for (ii = 0; ii < rank; ii++) | |
952 | { | |
953 | tree new_loop = push_stmt_list (); | |
954 | create_an_loop (an_loop_info[ii].ind_init, an_loop_info[ii].cmp, | |
955 | an_loop_info[ii].incr, body); | |
956 | body = pop_stmt_list (new_loop); | |
957 | } | |
1141ed3f | 958 | append_to_statement_list (body, &loop_with_init); |
2ce86d2e | 959 | |
b58d3df2 | 960 | release_vec_vec (an_info); |
2ce86d2e BI |
961 | |
962 | return loop_with_init; | |
963 | } | |
964 | ||
965 | /* Transforms array notations inside unary expression ORIG_STMT with an | |
966 | appropriate loop and ARRAY_REF (and returns all this as a super-tree called | |
967 | LOOP). */ | |
968 | ||
969 | static tree | |
970 | expand_unary_array_notation_exprs (tree orig_stmt) | |
971 | { | |
972 | vec<tree, va_gc> *array_list = NULL, *array_operand = NULL; | |
973 | size_t list_size = 0, rank = 0, ii = 0; | |
974 | tree body; | |
975 | tree builtin_loop, stmt = NULL_TREE, new_var = NULL_TREE; | |
976 | location_t location = EXPR_LOCATION (orig_stmt); | |
977 | tree an_init, loop_with_init = alloc_stmt_list (); | |
978 | vec<vec<an_parts> > an_info = vNULL; | |
b58d3df2 | 979 | auto_vec<an_loop_parts> an_loop_info; |
2ce86d2e BI |
980 | |
981 | if (!find_rank (location, orig_stmt, orig_stmt, true, &rank)) | |
982 | return error_mark_node; | |
983 | if (rank == 0) | |
984 | return orig_stmt; | |
985 | ||
986 | extract_array_notation_exprs (orig_stmt, false, &array_list); | |
987 | list_size = vec_safe_length (array_list); | |
988 | location = EXPR_LOCATION (orig_stmt); | |
989 | stmt = NULL_TREE; | |
990 | for (ii = 0; ii < list_size; ii++) | |
991 | if (TREE_CODE ((*array_list)[ii]) == CALL_EXPR | |
992 | || TREE_CODE ((*array_list)[ii]) == AGGR_INIT_EXPR) | |
993 | { | |
994 | tree list_node = (*array_list)[ii]; | |
995 | builtin_loop = expand_sec_reduce_builtin (list_node, &new_var); | |
996 | if (builtin_loop == error_mark_node) | |
997 | return error_mark_node; | |
998 | else if (builtin_loop) | |
999 | { | |
1000 | vec<tree, va_gc> *sub_list = NULL, *new_var_list = NULL; | |
1001 | stmt = alloc_stmt_list (); | |
1141ed3f | 1002 | append_to_statement_list (builtin_loop, &stmt); |
2ce86d2e BI |
1003 | vec_safe_push (sub_list, list_node); |
1004 | vec_safe_push (new_var_list, new_var); | |
1005 | replace_array_notations (&orig_stmt, false, sub_list, new_var_list); | |
1006 | } | |
1007 | } | |
1008 | if (stmt != NULL_TREE) | |
1141ed3f | 1009 | append_to_statement_list (finish_expr_stmt (orig_stmt), &stmt); |
2ce86d2e BI |
1010 | else |
1011 | stmt = orig_stmt; | |
1012 | rank = 0; | |
1013 | list_size = 0; | |
1014 | array_list = NULL; | |
1015 | extract_array_notation_exprs (stmt, true, &array_list); | |
1016 | list_size = vec_safe_length (array_list); | |
1017 | ||
1018 | if (!find_rank (EXPR_LOCATION (stmt), stmt, stmt, true, &rank)) | |
1019 | return error_mark_node; | |
1020 | if (rank == 0 || list_size == 0) | |
1021 | return stmt; | |
1022 | an_loop_info.safe_grow_cleared (rank); | |
1023 | an_init = push_stmt_list (); | |
1024 | /* Assign the array notation components to variable so that they can satisfy | |
1025 | the exec-once rule. */ | |
1026 | for (ii = 0; ii < list_size; ii++) | |
1027 | { | |
1028 | tree array_node = (*array_list)[ii]; | |
1141ed3f BI |
1029 | make_triplet_val_inv (&ARRAY_NOTATION_START (array_node)); |
1030 | make_triplet_val_inv (&ARRAY_NOTATION_LENGTH (array_node)); | |
1031 | make_triplet_val_inv (&ARRAY_NOTATION_STRIDE (array_node)); | |
2ce86d2e BI |
1032 | } |
1033 | cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info); | |
1034 | ||
1035 | for (ii = 0; ii < rank; ii++) | |
1036 | { | |
1141ed3f BI |
1037 | tree typ = ptrdiff_type_node; |
1038 | an_loop_info[ii].var = create_temporary_var (typ); | |
1039 | add_decl_expr (an_loop_info[ii].var); | |
2ce86d2e | 1040 | an_loop_info[ii].ind_init = build_x_modify_expr |
1141ed3f | 1041 | (location, an_loop_info[ii].var, INIT_EXPR, build_zero_cst (typ), |
2ce86d2e BI |
1042 | tf_warning_or_error); |
1043 | } | |
1044 | array_operand = create_array_refs (location, an_info, an_loop_info, | |
1045 | list_size, rank); | |
1046 | replace_array_notations (&stmt, true, array_list, array_operand); | |
1047 | create_cmp_incr (location, &an_loop_info, rank, an_info, tf_warning_or_error); | |
1048 | ||
1049 | an_init = pop_stmt_list (an_init); | |
1141ed3f | 1050 | append_to_statement_list (an_init, &loop_with_init); |
2ce86d2e BI |
1051 | body = stmt; |
1052 | ||
1053 | for (ii = 0; ii < rank; ii++) | |
1054 | { | |
1055 | tree new_loop = push_stmt_list (); | |
1056 | create_an_loop (an_loop_info[ii].ind_init, an_loop_info[ii].cmp, | |
1057 | an_loop_info[ii].incr, body); | |
1058 | body = pop_stmt_list (new_loop); | |
1059 | } | |
1141ed3f | 1060 | append_to_statement_list (body, &loop_with_init); |
2ce86d2e | 1061 | |
b58d3df2 | 1062 | release_vec_vec (an_info); |
2ce86d2e BI |
1063 | |
1064 | return loop_with_init; | |
1065 | } | |
1066 | ||
1067 | /* Expands the array notation's builtin reduction function in EXPR | |
1068 | (of type RETURN_EXPR) and returns a STATEMENT_LIST that contains a loop | |
1069 | with the builtin function expansion and a return statement at the end. */ | |
1070 | ||
1071 | static tree | |
1072 | expand_return_expr (tree expr) | |
1073 | { | |
1074 | tree new_mod_list, new_var, new_mod, retval_expr; | |
1141ed3f BI |
1075 | size_t rank = 0; |
1076 | location_t loc = EXPR_LOCATION (expr); | |
2ce86d2e BI |
1077 | if (TREE_CODE (expr) != RETURN_EXPR) |
1078 | return expr; | |
1141ed3f BI |
1079 | |
1080 | if (!find_rank (loc, expr, expr, false, &rank)) | |
1081 | return error_mark_node; | |
2ce86d2e | 1082 | |
1141ed3f BI |
1083 | /* If the return expression contains array notations, then flag it as |
1084 | error. */ | |
1085 | if (rank >= 1) | |
1086 | { | |
1087 | error_at (loc, "array notation expression cannot be used as a return " | |
1088 | "value"); | |
1089 | return error_mark_node; | |
1090 | } | |
1091 | ||
1092 | new_mod_list = push_stmt_list (); | |
2ce86d2e | 1093 | retval_expr = TREE_OPERAND (expr, 0); |
1141ed3f BI |
1094 | new_var = create_temporary_var (TREE_TYPE (retval_expr)); |
1095 | add_decl_expr (new_var); | |
2ce86d2e | 1096 | new_mod = expand_an_in_modify_expr (loc, new_var, NOP_EXPR, |
1141ed3f BI |
1097 | TREE_OPERAND (retval_expr, 1), |
1098 | tf_warning_or_error); | |
2ce86d2e BI |
1099 | TREE_OPERAND (retval_expr, 1) = new_var; |
1100 | TREE_OPERAND (expr, 0) = retval_expr; | |
1141ed3f BI |
1101 | add_stmt (new_mod); |
1102 | add_stmt (expr); | |
1103 | new_mod_list = pop_stmt_list (new_mod_list); | |
2ce86d2e BI |
1104 | return new_mod_list; |
1105 | } | |
1106 | ||
1107 | /* Expands ARRAY_NOTATION_REF and builtin functions in a compound statement, | |
1108 | STMT. Returns the STMT with expanded array notations. */ | |
1109 | ||
1110 | tree | |
1111 | expand_array_notation_exprs (tree t) | |
1112 | { | |
1113 | enum tree_code code; | |
1114 | bool is_expr; | |
1115 | location_t loc = UNKNOWN_LOCATION; | |
1116 | ||
1117 | if (!t) | |
1118 | return t; | |
1119 | ||
1120 | loc = EXPR_LOCATION (t); | |
1121 | ||
1122 | code = TREE_CODE (t); | |
1123 | is_expr = IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code)); | |
1124 | switch (code) | |
1125 | { | |
1126 | case ERROR_MARK: | |
1127 | case IDENTIFIER_NODE: | |
632f2871 | 1128 | case VOID_CST: |
2ce86d2e BI |
1129 | case INTEGER_CST: |
1130 | case REAL_CST: | |
1131 | case FIXED_CST: | |
1132 | case STRING_CST: | |
1133 | case BLOCK: | |
1134 | case PLACEHOLDER_EXPR: | |
1135 | case FIELD_DECL: | |
1136 | case VOID_TYPE: | |
1137 | case REAL_TYPE: | |
1138 | case SSA_NAME: | |
1139 | case LABEL_DECL: | |
1140 | case RESULT_DECL: | |
1141 | case VAR_DECL: | |
1142 | case PARM_DECL: | |
1143 | case NON_LVALUE_EXPR: | |
1144 | case NOP_EXPR: | |
2ce86d2e BI |
1145 | case ADDR_EXPR: |
1146 | case ARRAY_REF: | |
1147 | case BIT_FIELD_REF: | |
1148 | case VECTOR_CST: | |
1149 | case COMPLEX_CST: | |
1150 | return t; | |
a7ee52fb | 1151 | case INIT_EXPR: |
2ce86d2e BI |
1152 | case MODIFY_EXPR: |
1153 | if (contains_array_notation_expr (t)) | |
1154 | t = expand_an_in_modify_expr (loc, TREE_OPERAND (t, 0), NOP_EXPR, | |
1155 | TREE_OPERAND (t, 1), | |
1156 | tf_warning_or_error); | |
1157 | return t; | |
1158 | case MODOP_EXPR: | |
1159 | if (contains_array_notation_expr (t) && !processing_template_decl) | |
1160 | t = expand_an_in_modify_expr | |
1161 | (loc, TREE_OPERAND (t, 0), TREE_CODE (TREE_OPERAND (t, 1)), | |
1162 | TREE_OPERAND (t, 2), tf_warning_or_error); | |
1163 | return t; | |
1164 | case CONSTRUCTOR: | |
1165 | return t; | |
1166 | case BIND_EXPR: | |
1167 | { | |
1168 | BIND_EXPR_BODY (t) = | |
1169 | expand_array_notation_exprs (BIND_EXPR_BODY (t)); | |
1170 | return t; | |
1171 | } | |
1172 | case DECL_EXPR: | |
a7ee52fb IZ |
1173 | if (contains_array_notation_expr (t)) |
1174 | { | |
1175 | tree x = DECL_EXPR_DECL (t); | |
2ce86d2e | 1176 | if (DECL_INITIAL (x)) |
a7ee52fb IZ |
1177 | { |
1178 | location_t loc = DECL_SOURCE_LOCATION (x); | |
1179 | tree lhs = x; | |
1180 | tree rhs = DECL_INITIAL (x); | |
1181 | DECL_INITIAL (x) = NULL; | |
1182 | tree new_modify_expr = build_modify_expr (loc, lhs, | |
1183 | TREE_TYPE (lhs), | |
1184 | NOP_EXPR, | |
1185 | loc, rhs, | |
1186 | TREE_TYPE(rhs)); | |
1187 | t = expand_array_notation_exprs (new_modify_expr); | |
1188 | } | |
1189 | } | |
2ce86d2e | 1190 | return t; |
2ce86d2e BI |
1191 | case STATEMENT_LIST: |
1192 | { | |
1193 | tree_stmt_iterator i; | |
1194 | for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i)) | |
1195 | *tsi_stmt_ptr (i) = | |
1196 | expand_array_notation_exprs (*tsi_stmt_ptr (i)); | |
1197 | return t; | |
1198 | } | |
1199 | ||
1200 | case OMP_PARALLEL: | |
1201 | case OMP_TASK: | |
1202 | case OMP_FOR: | |
1203 | case OMP_SINGLE: | |
1204 | case OMP_SECTION: | |
1205 | case OMP_SECTIONS: | |
1206 | case OMP_MASTER: | |
acf0174b | 1207 | case OMP_TASKGROUP: |
2ce86d2e BI |
1208 | case OMP_ORDERED: |
1209 | case OMP_CRITICAL: | |
1210 | case OMP_ATOMIC: | |
1211 | case OMP_CLAUSE: | |
1212 | case TARGET_EXPR: | |
1213 | case INTEGER_TYPE: | |
1214 | case ENUMERAL_TYPE: | |
1215 | case BOOLEAN_TYPE: | |
1216 | case POINTER_TYPE: | |
1217 | case ARRAY_TYPE: | |
1218 | case RECORD_TYPE: | |
1219 | case METHOD_TYPE: | |
1220 | return t; | |
1221 | case RETURN_EXPR: | |
1222 | if (contains_array_notation_expr (t)) | |
1223 | t = expand_return_expr (t); | |
1224 | return t; | |
1225 | case PREDECREMENT_EXPR: | |
1226 | case PREINCREMENT_EXPR: | |
1227 | case POSTDECREMENT_EXPR: | |
1228 | case POSTINCREMENT_EXPR: | |
1229 | case AGGR_INIT_EXPR: | |
1230 | case CALL_EXPR: | |
1231 | t = expand_unary_array_notation_exprs (t); | |
1232 | return t; | |
1233 | case CONVERT_EXPR: | |
1234 | case CLEANUP_POINT_EXPR: | |
1235 | case EXPR_STMT: | |
1236 | TREE_OPERAND (t, 0) = expand_array_notation_exprs (TREE_OPERAND (t, 0)); | |
1237 | /* It is not necessary to wrap error_mark_node in EXPR_STMT. */ | |
1238 | if (TREE_OPERAND (t, 0) == error_mark_node) | |
1239 | return TREE_OPERAND (t, 0); | |
1240 | return t; | |
318cda85 BI |
1241 | case TRUTH_ANDIF_EXPR: |
1242 | case TRUTH_ORIF_EXPR: | |
1243 | case TRUTH_AND_EXPR: | |
1244 | case TRUTH_OR_EXPR: | |
1245 | case TRUTH_XOR_EXPR: | |
1246 | case TRUTH_NOT_EXPR: | |
2ce86d2e BI |
1247 | case COND_EXPR: |
1248 | t = cp_expand_cond_array_notations (t); | |
1249 | if (TREE_CODE (t) == COND_EXPR) | |
1250 | { | |
1251 | COND_EXPR_THEN (t) = | |
1252 | expand_array_notation_exprs (COND_EXPR_THEN (t)); | |
1253 | COND_EXPR_ELSE (t) = | |
1254 | expand_array_notation_exprs (COND_EXPR_ELSE (t)); | |
1255 | } | |
2ce86d2e | 1256 | return t; |
1141ed3f BI |
1257 | case FOR_STMT: |
1258 | if (contains_array_notation_expr (FOR_COND (t))) | |
1259 | { | |
1260 | error_at (EXPR_LOCATION (FOR_COND (t)), | |
1261 | "array notation cannot be used in a condition for " | |
1262 | "a for-loop"); | |
1263 | return error_mark_node; | |
1264 | } | |
2ce86d2e BI |
1265 | /* FIXME: Add a check for CILK_FOR_STMT here when we add Cilk tasking |
1266 | keywords. */ | |
1267 | if (TREE_CODE (t) == FOR_STMT) | |
1141ed3f BI |
1268 | { |
1269 | FOR_BODY (t) = expand_array_notation_exprs (FOR_BODY (t)); | |
1270 | FOR_EXPR (t) = expand_array_notation_exprs (FOR_EXPR (t)); | |
1271 | } | |
2ce86d2e BI |
1272 | else |
1273 | t = expand_array_notation_exprs (t); | |
1274 | return t; | |
1275 | case IF_STMT: | |
1276 | t = cp_expand_cond_array_notations (t); | |
1277 | /* If the above function added some extra instructions above the original | |
1278 | if statement, then we can't assume it is still IF_STMT so we have to | |
1279 | check again. */ | |
1280 | if (TREE_CODE (t) == IF_STMT) | |
1281 | { | |
1282 | if (THEN_CLAUSE (t)) | |
1283 | THEN_CLAUSE (t) = expand_array_notation_exprs (THEN_CLAUSE (t)); | |
1284 | if (ELSE_CLAUSE (t)) | |
1285 | ELSE_CLAUSE (t) = expand_array_notation_exprs (ELSE_CLAUSE (t)); | |
1286 | } | |
1287 | else | |
1288 | t = expand_array_notation_exprs (t); | |
1289 | return t; | |
1290 | case SWITCH_STMT: | |
1141ed3f | 1291 | if (contains_array_notation_expr (SWITCH_STMT_COND (t))) |
2ce86d2e | 1292 | { |
1141ed3f BI |
1293 | error_at (EXPR_LOCATION (SWITCH_STMT_COND (t)), |
1294 | "array notation cannot be used as a condition for " | |
1295 | "switch statement"); | |
1296 | return error_mark_node; | |
2ce86d2e | 1297 | } |
1141ed3f BI |
1298 | if (SWITCH_STMT_BODY (t)) |
1299 | SWITCH_STMT_BODY (t) = | |
1300 | expand_array_notation_exprs (SWITCH_STMT_BODY (t)); | |
2ce86d2e BI |
1301 | return t; |
1302 | case WHILE_STMT: | |
1141ed3f | 1303 | if (contains_array_notation_expr (WHILE_COND (t))) |
2ce86d2e | 1304 | { |
1141ed3f BI |
1305 | if (EXPR_LOCATION (WHILE_COND (t)) != UNKNOWN_LOCATION) |
1306 | loc = EXPR_LOCATION (WHILE_COND (t)); | |
1307 | error_at (loc, "array notation cannot be used as a condition for " | |
1308 | "while statement"); | |
1309 | return error_mark_node; | |
2ce86d2e | 1310 | } |
1141ed3f BI |
1311 | if (WHILE_BODY (t)) |
1312 | WHILE_BODY (t) = expand_array_notation_exprs (WHILE_BODY (t)); | |
2ce86d2e BI |
1313 | return t; |
1314 | case DO_STMT: | |
1141ed3f BI |
1315 | if (contains_array_notation_expr (DO_COND (t))) |
1316 | { | |
1317 | error_at (EXPR_LOCATION (DO_COND (t)), | |
1318 | "array notation cannot be used as a condition for a " | |
1319 | "do-while statement"); | |
1320 | return error_mark_node; | |
2ce86d2e | 1321 | } |
1141ed3f BI |
1322 | if (DO_BODY (t)) |
1323 | DO_BODY (t) = expand_array_notation_exprs (DO_BODY (t)); | |
2ce86d2e BI |
1324 | return t; |
1325 | default: | |
1326 | if (is_expr) | |
1327 | { | |
1328 | int i, len; | |
1329 | ||
1330 | /* Walk over all the sub-trees of this operand. */ | |
1331 | len = TREE_CODE_LENGTH (code); | |
1332 | ||
1333 | /* Go through the subtrees. We need to do this in forward order so | |
1334 | that the scope of a FOR_EXPR is handled properly. */ | |
1335 | for (i = 0; i < len; ++i) | |
1336 | TREE_OPERAND (t, i) = | |
1337 | expand_array_notation_exprs (TREE_OPERAND (t, i)); | |
1338 | } | |
1339 | return t; | |
1340 | } | |
1341 | return t; | |
1342 | } | |
1343 | ||
1141ed3f BI |
1344 | /* Given the base of an array (ARRAY), the START (start_index), the number of |
1345 | elements to be accessed (LENGTH) and the STRIDE, construct an | |
1346 | ARRAY_NOTATION_REF tree of type TYPE and return it. Restrictions on START, | |
1347 | LENGTH and STRIDE are the same as that of index field passed into ARRAY_REF. | |
1348 | The only additional restriction is that, unlike index in ARRAY_REF, stride, | |
1349 | length and start_index cannot contain array notations. */ | |
2ce86d2e BI |
1350 | |
1351 | tree | |
1141ed3f BI |
1352 | build_array_notation_ref (location_t loc, tree array, tree start, tree length, |
1353 | tree stride, tree type) | |
2ce86d2e BI |
1354 | { |
1355 | tree array_ntn_expr = NULL_TREE; | |
1141ed3f BI |
1356 | |
1357 | /* If we enter the then-case of the if-statement below, we have hit a case | |
1358 | like this: ARRAY [:]. */ | |
1359 | if (!start && !length) | |
2ce86d2e | 1360 | { |
1141ed3f BI |
1361 | if (TREE_CODE (type) != ARRAY_TYPE) |
1362 | { | |
1363 | error_at (loc, "start-index and length fields necessary for " | |
1364 | "using array notation in pointers or records"); | |
1365 | return error_mark_node; | |
1366 | } | |
1367 | tree domain = TYPE_DOMAIN (type); | |
1368 | if (!domain) | |
1369 | { | |
1370 | error_at (loc, "start-index and length fields necessary for " | |
1371 | "using array notation with array of unknown bound"); | |
1372 | return error_mark_node; | |
1373 | } | |
1374 | start = cp_fold_convert (ptrdiff_type_node, TYPE_MINVAL (domain)); | |
1375 | length = size_binop (PLUS_EXPR, TYPE_MAXVAL (domain), size_one_node); | |
1376 | length = cp_fold_convert (ptrdiff_type_node, length); | |
2ce86d2e | 1377 | } |
1141ed3f BI |
1378 | |
1379 | if (!stride) | |
1380 | stride = build_one_cst (ptrdiff_type_node); | |
cda0a029 JM |
1381 | |
1382 | stride = maybe_constant_value (stride); | |
1383 | length = maybe_constant_value (length); | |
1384 | if (start) | |
1385 | start = maybe_constant_value (start); | |
1386 | ||
1141ed3f BI |
1387 | /* When dealing with templates, triplet type-checking will be done in pt.c |
1388 | after type substitution. */ | |
1389 | if (processing_template_decl | |
1390 | && (type_dependent_expression_p (array) | |
1391 | || type_dependent_expression_p (length) | |
1392 | || type_dependent_expression_p (start) | |
1393 | || type_dependent_expression_p (stride))) | |
1394 | array_ntn_expr = build_min_nt_loc (loc, ARRAY_NOTATION_REF, array, start, | |
1395 | length, stride, NULL_TREE); | |
1396 | else | |
1397 | { | |
1398 | if (!cilkplus_an_triplet_types_ok_p (loc, start, length, stride, type)) | |
1399 | return error_mark_node; | |
1400 | array_ntn_expr = build4 (ARRAY_NOTATION_REF, NULL_TREE, array, start, | |
1401 | length, stride); | |
2ce86d2e | 1402 | } |
1141ed3f BI |
1403 | if (TREE_CODE (type) == ARRAY_TYPE || TREE_CODE (type) == POINTER_TYPE) |
1404 | TREE_TYPE (array_ntn_expr) = TREE_TYPE (type); | |
1405 | else | |
671a475e IZ |
1406 | { |
1407 | error_at (loc, "base of array section must be pointer or array type"); | |
1408 | return error_mark_node; | |
1409 | } | |
2ce86d2e | 1410 | |
2ce86d2e | 1411 | SET_EXPR_LOCATION (array_ntn_expr, loc); |
2ce86d2e BI |
1412 | return array_ntn_expr; |
1413 | } | |
1414 | ||
1415 | /* Returns false if any of the Array notation triplet values: START_INDEX, | |
1416 | LENGTH and STRIDE, are not of integral type and have a rank greater than | |
1417 | zero. */ | |
1418 | ||
1419 | bool | |
1420 | cilkplus_an_triplet_types_ok_p (location_t loc, tree start_index, tree length, | |
1421 | tree stride, tree type) | |
1422 | { | |
1423 | size_t stride_rank = 0, length_rank = 0, start_rank = 0; | |
1424 | if (!TREE_TYPE (start_index) || !INTEGRAL_TYPE_P (TREE_TYPE (start_index))) | |
1425 | { | |
1426 | error_at (loc, "start-index of array notation triplet is not an integer"); | |
1427 | return false; | |
1428 | } | |
1429 | if (!TREE_TYPE (length) || !INTEGRAL_TYPE_P (TREE_TYPE (length))) | |
1430 | { | |
1431 | error_at (loc, "length of array notation triplet is not an integer"); | |
1432 | return false; | |
1433 | } | |
1434 | if (!TREE_TYPE (stride) || !INTEGRAL_TYPE_P (TREE_TYPE (stride))) | |
1435 | { | |
1436 | error_at (loc, "stride of array notation triplet is not an integer"); | |
1437 | return false; | |
1438 | } | |
d8000f03 | 1439 | if (TREE_CODE (type) == FUNCTION_TYPE) |
2ce86d2e | 1440 | { |
1141ed3f | 1441 | error_at (loc, "array notation cannot be used with function type"); |
2ce86d2e BI |
1442 | return false; |
1443 | } | |
2ce86d2e BI |
1444 | if (!find_rank (loc, start_index, start_index, false, &start_rank) |
1445 | || !find_rank (loc, length, length, false, &length_rank) | |
1446 | || !find_rank (loc, stride, stride, false, &stride_rank)) | |
1447 | return false; | |
1448 | ||
1449 | if (start_rank != 0) | |
1450 | { | |
1451 | error_at (loc, "rank of an array notation triplet%'s start-index is not " | |
1452 | "zero"); | |
1453 | return false; | |
1454 | } | |
1455 | if (length_rank != 0) | |
1456 | { | |
1457 | error_at (loc, "rank of an array notation triplet%'s length is not zero"); | |
1458 | return false; | |
1459 | } | |
1460 | if (stride_rank != 0) | |
1461 | { | |
1462 | error_at (loc, "rank of array notation triplet%'s stride is not zero"); | |
1463 | return false; | |
1464 | } | |
1465 | return true; | |
1466 | } |