]>
Commit | Line | Data |
---|---|---|
36536d79 BI |
1 | /* This file is part of the Intel(R) Cilk(TM) Plus support |
2 | This file contains routines to handle Array Notation expression | |
3 | handling routines in the C Compiler. | |
5624e564 | 4 | Copyright (C) 2013-2015 Free Software Foundation, Inc. |
36536d79 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 | |
29 | 3. Number of elements we need to acess (we call it length) | |
30 | 4. Stride | |
31 | ||
32 | For example, A[0:5:2], implies that 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 overall | |
38 | technique: | |
39 | ||
40 | Let's say we have an array notation in a statement like this: | |
41 | ||
42 | A[St1:Ln:Str1] = B[St2:Ln:Str2] + <NON ARRAY_NOTATION_STMT> | |
43 | ||
44 | where St{1,2} = Starting index, | |
45 | Ln = Number of elements we need to access, | |
46 | and Str{1,2} = the stride. | |
47 | Note: The length of both the array notation expressions must be the same. | |
48 | ||
49 | The above expression is broken into the following | |
50 | (with the help of c_finish_loop function from c-typeck.c): | |
51 | ||
52 | Tmp_Var = 0; | |
53 | goto compare_label: | |
54 | body_label: | |
55 | ||
56 | A[St1+Tmp_Var*Str1] = B[St1+Tmp_Var*Str2] + <NON ARRAY_NOTATION_STMT>; | |
57 | Tmp_Var++; | |
58 | ||
59 | compare_label: | |
60 | if (Tmp_Var < Ln) | |
61 | goto body_label; | |
62 | else | |
63 | goto exit_label; | |
64 | exit_label: | |
65 | ||
66 | */ | |
67 | ||
68 | #include "config.h" | |
69 | #include "system.h" | |
70 | #include "coretypes.h" | |
40e23961 MC |
71 | #include "hash-set.h" |
72 | #include "vec.h" | |
73 | #include "symtab.h" | |
74 | #include "input.h" | |
75 | #include "alias.h" | |
76 | #include "double-int.h" | |
77 | #include "machmode.h" | |
78 | #include "flags.h" | |
79 | #include "inchash.h" | |
36536d79 BI |
80 | #include "tree.h" |
81 | #include "c-tree.h" | |
2f6babac | 82 | #include "gimple-expr.h" |
36536d79 BI |
83 | #include "tree-iterator.h" |
84 | #include "opts.h" | |
85 | #include "c-family/c-common.h" | |
86 | ||
713b46fa BI |
87 | /* If *VALUE is not of type INTEGER_CST, PARM_DECL or VAR_DECL, then map it |
88 | to a variable and then set *VALUE to the new variable. */ | |
89 | ||
90 | static inline void | |
91 | make_triplet_val_inv (location_t loc, tree *value) | |
92 | { | |
93 | tree var, new_exp; | |
94 | if (TREE_CODE (*value) != INTEGER_CST | |
95 | && TREE_CODE (*value) != PARM_DECL | |
96 | && TREE_CODE (*value) != VAR_DECL) | |
97 | { | |
98 | var = build_decl (loc, VAR_DECL, NULL_TREE, integer_type_node); | |
99 | new_exp = build_modify_expr (loc, var, TREE_TYPE (var), NOP_EXPR, loc, | |
100 | *value, TREE_TYPE (*value)); | |
101 | add_stmt (new_exp); | |
102 | *value = var; | |
103 | } | |
104 | } | |
105 | ||
106 | /* Populates the INCR and CMP vectors with the increment (of type POSTINCREMENT | |
107 | or POSTDECREMENT) and comparison (of TYPE GT_EXPR or LT_EXPR) expressions, | |
108 | using data from LENGTH, COUNT_DOWN, and VAR. INCR and CMP vectors are of | |
109 | size RANK. */ | |
110 | ||
111 | static void | |
112 | create_cmp_incr (location_t loc, vec<an_loop_parts> *node, size_t rank, | |
113 | vec<vec<an_parts> > an_info) | |
114 | { | |
115 | for (size_t ii = 0; ii < rank; ii++) | |
116 | { | |
117 | tree var = (*node)[ii].var; | |
118 | tree length = an_info[0][ii].length; | |
119 | (*node)[ii].incr = build_unary_op (loc, POSTINCREMENT_EXPR, var, 0); | |
120 | (*node)[ii].cmp = build2 (LT_EXPR, boolean_type_node, var, length); | |
121 | } | |
122 | } | |
123 | ||
124 | /* Returns a vector of size RANK that contains an array ref that is derived from | |
125 | array notation triplet parameters stored in VALUE, START, STRIDE. IS_VECTOR | |
126 | is used to check if the data stored at its corresponding location is an | |
127 | array notation. VAR is the induction variable passed in by the caller. | |
128 | ||
129 | For example: For an array notation A[5:10:2], the vector start will be | |
130 | of size 1 holding '5', stride of same size as start but holding the value of | |
131 | as 2, is_vector as true and count_down as false. Let's assume VAR is 'x' | |
132 | This function returns a vector of size 1 with the following data: | |
133 | A[5 + (x * 2)] . | |
134 | */ | |
135 | ||
136 | static vec<tree, va_gc> * | |
137 | create_array_refs (location_t loc, vec<vec<an_parts> > an_info, | |
138 | vec<an_loop_parts> an_loop_info, size_t size, size_t rank) | |
139 | { | |
140 | tree ind_mult, ind_incr; | |
141 | vec<tree, va_gc> *array_operand = NULL; | |
142 | for (size_t ii = 0; ii < size; ii++) | |
143 | if (an_info[ii][0].is_vector) | |
144 | { | |
145 | tree array_opr = an_info[ii][rank - 1].value; | |
146 | for (int s_jj = rank - 1; s_jj >= 0; s_jj--) | |
147 | { | |
148 | tree var = an_loop_info[s_jj].var; | |
149 | tree stride = an_info[ii][s_jj].stride; | |
150 | tree start = an_info[ii][s_jj].start; | |
151 | ind_mult = build2 (MULT_EXPR, TREE_TYPE (var), var, stride); | |
152 | ind_incr = build2 (PLUS_EXPR, TREE_TYPE (var), start, ind_mult); | |
153 | array_opr = build_array_ref (loc, array_opr, ind_incr); | |
154 | } | |
155 | vec_safe_push (array_operand, array_opr); | |
156 | } | |
157 | else | |
158 | /* This is just a dummy node to make sure both the list sizes for both | |
159 | array list and array operand list are the same. */ | |
160 | vec_safe_push (array_operand, integer_one_node); | |
161 | return array_operand; | |
162 | } | |
163 | ||
36536d79 BI |
164 | /* Replaces all the scalar expressions in *NODE. Returns a STATEMENT_LIST that |
165 | holds the NODE along with variables that holds the results of the invariant | |
166 | expressions. */ | |
167 | ||
168 | tree | |
169 | replace_invariant_exprs (tree *node) | |
170 | { | |
171 | size_t ix = 0; | |
172 | tree node_list = NULL_TREE; | |
173 | tree t = NULL_TREE, new_var = NULL_TREE, new_node; | |
174 | struct inv_list data; | |
175 | ||
176 | data.list_values = NULL; | |
177 | data.replacement = NULL; | |
d60f1706 | 178 | data.additional_tcodes = NULL; |
36536d79 BI |
179 | walk_tree (node, find_inv_trees, (void *)&data, NULL); |
180 | ||
181 | if (vec_safe_length (data.list_values)) | |
182 | { | |
183 | node_list = push_stmt_list (); | |
184 | for (ix = 0; vec_safe_iterate (data.list_values, ix, &t); ix++) | |
185 | { | |
186 | new_var = build_decl (EXPR_LOCATION (t), VAR_DECL, NULL_TREE, | |
187 | TREE_TYPE (t)); | |
188 | gcc_assert (new_var != NULL_TREE && new_var != error_mark_node); | |
189 | new_node = build2 (MODIFY_EXPR, TREE_TYPE (t), new_var, t); | |
190 | add_stmt (new_node); | |
191 | vec_safe_push (data.replacement, new_var); | |
192 | } | |
193 | walk_tree (node, replace_inv_trees, (void *)&data, NULL); | |
194 | node_list = pop_stmt_list (node_list); | |
195 | } | |
196 | return node_list; | |
197 | } | |
198 | ||
199 | /* Given a CALL_EXPR to an array notation built-in function in | |
200 | AN_BUILTIN_FN, replace the call with the appropriate loop and | |
201 | computation. Return the computation in *NEW_VAR. | |
202 | ||
203 | The return value in *NEW_VAR will always be a scalar. If the | |
204 | built-in is __sec_reduce_mutating, *NEW_VAR is set to NULL_TREE. */ | |
205 | ||
206 | static tree | |
207 | fix_builtin_array_notation_fn (tree an_builtin_fn, tree *new_var) | |
208 | { | |
209 | tree new_var_type = NULL_TREE, func_parm, new_expr, new_yes_expr, new_no_expr; | |
210 | tree array_ind_value = NULL_TREE, new_no_ind, new_yes_ind, new_no_list; | |
211 | tree new_yes_list, new_cond_expr, new_var_init = NULL_TREE; | |
212 | tree new_exp_init = NULL_TREE; | |
213 | vec<tree, va_gc> *array_list = NULL, *array_operand = NULL; | |
713b46fa BI |
214 | size_t list_size = 0, rank = 0, ii = 0; |
215 | tree loop_init, array_op0; | |
36536d79 | 216 | tree identity_value = NULL_TREE, call_fn = NULL_TREE, new_call_expr, body; |
36536d79 BI |
217 | location_t location = UNKNOWN_LOCATION; |
218 | tree loop_with_init = alloc_stmt_list (); | |
713b46fa BI |
219 | vec<vec<an_parts> > an_info = vNULL; |
220 | vec<an_loop_parts> an_loop_info = vNULL; | |
36536d79 BI |
221 | enum built_in_function an_type = |
222 | is_cilkplus_reduce_builtin (CALL_EXPR_FN (an_builtin_fn)); | |
223 | if (an_type == BUILT_IN_NONE) | |
224 | return NULL_TREE; | |
225 | ||
5e88a8f4 IZ |
226 | /* Builtin call should contain at least one argument. */ |
227 | if (call_expr_nargs (an_builtin_fn) == 0) | |
228 | { | |
229 | error_at (EXPR_LOCATION (an_builtin_fn), "Invalid builtin arguments"); | |
230 | return error_mark_node; | |
231 | } | |
232 | ||
36536d79 BI |
233 | if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE |
234 | || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING) | |
235 | { | |
236 | call_fn = CALL_EXPR_ARG (an_builtin_fn, 2); | |
00b8517d | 237 | if (TREE_CODE (call_fn) == ADDR_EXPR) |
36536d79 | 238 | call_fn = TREE_OPERAND (call_fn, 0); |
36536d79 | 239 | identity_value = CALL_EXPR_ARG (an_builtin_fn, 0); |
36536d79 BI |
240 | func_parm = CALL_EXPR_ARG (an_builtin_fn, 1); |
241 | } | |
242 | else | |
243 | func_parm = CALL_EXPR_ARG (an_builtin_fn, 0); | |
244 | ||
00b8517d BI |
245 | /* Fully fold any EXCESSIVE_PRECISION EXPR that can occur in the function |
246 | parameter. */ | |
247 | func_parm = c_fully_fold (func_parm, false, NULL); | |
97563bc8 IZ |
248 | if (func_parm == error_mark_node) |
249 | return error_mark_node; | |
00b8517d | 250 | |
36536d79 BI |
251 | location = EXPR_LOCATION (an_builtin_fn); |
252 | ||
253 | if (!find_rank (location, an_builtin_fn, an_builtin_fn, true, &rank)) | |
254 | return error_mark_node; | |
255 | ||
256 | if (rank == 0) | |
5e88a8f4 IZ |
257 | { |
258 | error_at (location, "Invalid builtin arguments"); | |
259 | return error_mark_node; | |
260 | } | |
36536d79 BI |
261 | else if (rank > 1 |
262 | && (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND | |
263 | || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND)) | |
264 | { | |
265 | error_at (location, "__sec_reduce_min_ind or __sec_reduce_max_ind cannot" | |
266 | " have arrays with dimension greater than 1"); | |
267 | return error_mark_node; | |
268 | } | |
269 | ||
270 | extract_array_notation_exprs (func_parm, true, &array_list); | |
271 | list_size = vec_safe_length (array_list); | |
272 | switch (an_type) | |
273 | { | |
274 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD: | |
275 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL: | |
276 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX: | |
277 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN: | |
278 | new_var_type = TREE_TYPE ((*array_list)[0]); | |
279 | break; | |
280 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO: | |
281 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO: | |
282 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO: | |
283 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO: | |
284 | new_var_type = integer_type_node; | |
285 | break; | |
286 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND: | |
287 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND: | |
288 | new_var_type = integer_type_node; | |
289 | break; | |
290 | case BUILT_IN_CILKPLUS_SEC_REDUCE: | |
291 | if (call_fn && identity_value) | |
292 | new_var_type = TREE_TYPE ((*array_list)[0]); | |
293 | break; | |
294 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING: | |
295 | new_var_type = NULL_TREE; | |
296 | break; | |
297 | default: | |
298 | gcc_unreachable (); | |
299 | } | |
36536d79 | 300 | |
713b46fa BI |
301 | an_loop_info.safe_grow_cleared (rank); |
302 | cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info); | |
36536d79 BI |
303 | loop_init = alloc_stmt_list (); |
304 | ||
305 | for (ii = 0; ii < rank; ii++) | |
306 | { | |
b731b390 | 307 | an_loop_info[ii].var = create_tmp_var (integer_type_node); |
713b46fa BI |
308 | an_loop_info[ii].ind_init = |
309 | build_modify_expr (location, an_loop_info[ii].var, | |
310 | TREE_TYPE (an_loop_info[ii].var), NOP_EXPR, | |
36536d79 | 311 | location, |
713b46fa BI |
312 | build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0), |
313 | TREE_TYPE (an_loop_info[ii].var)); | |
36536d79 | 314 | } |
713b46fa BI |
315 | array_operand = create_array_refs (location, an_info, an_loop_info, |
316 | list_size, rank); | |
36536d79 | 317 | replace_array_notations (&func_parm, true, array_list, array_operand); |
36536d79 | 318 | |
713b46fa | 319 | create_cmp_incr (location, &an_loop_info, rank, an_info); |
36536d79 BI |
320 | if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING) |
321 | { | |
322 | *new_var = build_decl (location, VAR_DECL, NULL_TREE, new_var_type); | |
323 | gcc_assert (*new_var && *new_var != error_mark_node); | |
324 | } | |
325 | else | |
326 | *new_var = NULL_TREE; | |
327 | ||
328 | if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND | |
329 | || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND) | |
330 | array_ind_value = build_decl (location, VAR_DECL, NULL_TREE, | |
331 | TREE_TYPE (func_parm)); | |
9dc7743c IZ |
332 | array_op0 = (*array_operand)[0]; |
333 | if (TREE_CODE (array_op0) == INDIRECT_REF) | |
334 | array_op0 = TREE_OPERAND (array_op0, 0); | |
36536d79 BI |
335 | switch (an_type) |
336 | { | |
337 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD: | |
338 | new_var_init = build_modify_expr | |
339 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
340 | location, build_zero_cst (new_var_type), new_var_type); | |
341 | new_expr = build_modify_expr | |
342 | (location, *new_var, TREE_TYPE (*new_var), PLUS_EXPR, | |
343 | location, func_parm, TREE_TYPE (func_parm)); | |
344 | break; | |
345 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL: | |
346 | new_var_init = build_modify_expr | |
347 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
348 | location, build_one_cst (new_var_type), new_var_type); | |
349 | new_expr = build_modify_expr | |
350 | (location, *new_var, TREE_TYPE (*new_var), MULT_EXPR, | |
351 | location, func_parm, TREE_TYPE (func_parm)); | |
352 | break; | |
353 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO: | |
354 | new_var_init = build_modify_expr | |
355 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
356 | location, build_one_cst (new_var_type), new_var_type); | |
357 | /* Initially you assume everything is zero, now if we find a case where | |
358 | it is NOT true, then we set the result to false. Otherwise | |
359 | we just keep the previous value. */ | |
360 | new_yes_expr = build_modify_expr | |
361 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
362 | location, build_zero_cst (TREE_TYPE (*new_var)), | |
363 | TREE_TYPE (*new_var)); | |
364 | new_no_expr = build_modify_expr | |
365 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
366 | location, *new_var, TREE_TYPE (*new_var)); | |
367 | new_cond_expr = build2 (NE_EXPR, TREE_TYPE (func_parm), func_parm, | |
368 | build_zero_cst (TREE_TYPE (func_parm))); | |
369 | new_expr = build_conditional_expr | |
370 | (location, new_cond_expr, false, new_yes_expr, | |
371 | TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr)); | |
372 | break; | |
373 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO: | |
374 | new_var_init = build_modify_expr | |
375 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
376 | location, build_one_cst (new_var_type), new_var_type); | |
377 | /* Initially you assume everything is non-zero, now if we find a case | |
378 | where it is NOT true, then we set the result to false. Otherwise | |
379 | we just keep the previous value. */ | |
380 | new_yes_expr = build_modify_expr | |
381 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
382 | location, build_zero_cst (TREE_TYPE (*new_var)), | |
383 | TREE_TYPE (*new_var)); | |
384 | new_no_expr = build_modify_expr | |
385 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
386 | location, *new_var, TREE_TYPE (*new_var)); | |
387 | new_cond_expr = build2 (EQ_EXPR, TREE_TYPE (func_parm), func_parm, | |
388 | build_zero_cst (TREE_TYPE (func_parm))); | |
389 | new_expr = build_conditional_expr | |
390 | (location, new_cond_expr, false, new_yes_expr, | |
391 | TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr)); | |
392 | break; | |
393 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO: | |
394 | new_var_init = build_modify_expr | |
395 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
396 | location, build_zero_cst (new_var_type), new_var_type); | |
397 | /* Initially we assume there are NO zeros in the list. When we find | |
398 | a non-zero, we keep the previous value. If we find a zero, we | |
399 | set the value to true. */ | |
400 | new_yes_expr = build_modify_expr | |
401 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
402 | location, build_one_cst (new_var_type), new_var_type); | |
403 | new_no_expr = build_modify_expr | |
404 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
405 | location, *new_var, TREE_TYPE (*new_var)); | |
406 | new_cond_expr = build2 (EQ_EXPR, TREE_TYPE (func_parm), func_parm, | |
407 | build_zero_cst (TREE_TYPE (func_parm))); | |
408 | new_expr = build_conditional_expr | |
409 | (location, new_cond_expr, false, new_yes_expr, | |
410 | TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr)); | |
411 | break; | |
412 | case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO: | |
413 | new_var_init = build_modify_expr | |
414 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
415 | location, build_zero_cst (new_var_type), new_var_type); | |
416 | /* Initially we assume there are NO non-zeros in the list. When we find | |
417 | a zero, we keep the previous value. If we find a non-zero, we set | |
418 | the value to true. */ | |
419 | new_yes_expr = build_modify_expr | |
420 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
421 | location, build_one_cst (new_var_type), new_var_type); | |
422 | new_no_expr = build_modify_expr | |
423 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
424 | location, *new_var, TREE_TYPE (*new_var)); | |
425 | new_cond_expr = build2 (NE_EXPR, TREE_TYPE (func_parm), func_parm, | |
426 | build_zero_cst (TREE_TYPE (func_parm))); | |
427 | new_expr = build_conditional_expr | |
428 | (location, new_cond_expr, false, new_yes_expr, | |
429 | TREE_TYPE (new_yes_expr), new_no_expr, TREE_TYPE (new_no_expr)); | |
430 | break; | |
431 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX: | |
432 | if (TYPE_MIN_VALUE (new_var_type)) | |
433 | new_var_init = build_modify_expr | |
434 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
435 | location, TYPE_MIN_VALUE (new_var_type), new_var_type); | |
436 | else | |
437 | new_var_init = build_modify_expr | |
438 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
439 | location, func_parm, new_var_type); | |
440 | new_no_expr = build_modify_expr | |
441 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
442 | location, *new_var, TREE_TYPE (*new_var)); | |
443 | new_yes_expr = build_modify_expr | |
444 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
445 | location, func_parm, TREE_TYPE (*new_var)); | |
446 | new_expr = build_conditional_expr | |
447 | (location, | |
448 | build2 (LT_EXPR, TREE_TYPE (*new_var), *new_var, func_parm), false, | |
449 | new_yes_expr, TREE_TYPE (*new_var), new_no_expr, TREE_TYPE (*new_var)); | |
450 | break; | |
451 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN: | |
452 | if (TYPE_MAX_VALUE (new_var_type)) | |
453 | new_var_init = build_modify_expr | |
454 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
455 | location, TYPE_MAX_VALUE (new_var_type), new_var_type); | |
456 | else | |
457 | new_var_init = build_modify_expr | |
458 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
459 | location, func_parm, new_var_type); | |
460 | new_no_expr = build_modify_expr | |
461 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
462 | location, *new_var, TREE_TYPE (*new_var)); | |
463 | new_yes_expr = build_modify_expr | |
464 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
465 | location, func_parm, TREE_TYPE (*new_var)); | |
466 | new_expr = build_conditional_expr | |
467 | (location, | |
468 | build2 (GT_EXPR, TREE_TYPE (*new_var), *new_var, func_parm), false, | |
469 | new_yes_expr, TREE_TYPE (*new_var), new_no_expr, TREE_TYPE (*new_var)); | |
470 | break; | |
471 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND: | |
472 | new_var_init = build_modify_expr | |
473 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
474 | location, build_zero_cst (new_var_type), new_var_type); | |
475 | new_exp_init = build_modify_expr | |
476 | (location, array_ind_value, TREE_TYPE (array_ind_value), | |
477 | NOP_EXPR, location, func_parm, TREE_TYPE (func_parm)); | |
478 | new_no_ind = build_modify_expr | |
479 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
480 | location, *new_var, TREE_TYPE (*new_var)); | |
481 | new_no_expr = build_modify_expr | |
482 | (location, array_ind_value, TREE_TYPE (array_ind_value), | |
483 | NOP_EXPR, | |
484 | location, array_ind_value, TREE_TYPE (array_ind_value)); | |
485 | if (list_size > 1) | |
486 | { | |
487 | new_yes_ind = build_modify_expr | |
488 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
713b46fa | 489 | location, an_loop_info[0].var, TREE_TYPE (an_loop_info[0].var)); |
36536d79 BI |
490 | new_yes_expr = build_modify_expr |
491 | (location, array_ind_value, TREE_TYPE (array_ind_value), | |
492 | NOP_EXPR, | |
493 | location, func_parm, TREE_TYPE ((*array_operand)[0])); | |
494 | } | |
495 | else | |
496 | { | |
497 | new_yes_ind = build_modify_expr | |
498 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
499 | location, TREE_OPERAND (array_op0, 1), | |
500 | TREE_TYPE (TREE_OPERAND (array_op0, 1))); | |
501 | new_yes_expr = build_modify_expr | |
502 | (location, array_ind_value, TREE_TYPE (array_ind_value), | |
503 | NOP_EXPR, | |
504 | location, func_parm, TREE_OPERAND (array_op0, 1)); | |
505 | } | |
506 | new_yes_list = alloc_stmt_list (); | |
507 | append_to_statement_list (new_yes_ind, &new_yes_list); | |
508 | append_to_statement_list (new_yes_expr, &new_yes_list); | |
509 | ||
510 | new_no_list = alloc_stmt_list (); | |
511 | append_to_statement_list (new_no_ind, &new_no_list); | |
512 | append_to_statement_list (new_no_expr, &new_no_list); | |
513 | ||
514 | new_expr = build_conditional_expr | |
515 | (location, | |
516 | build2 (LE_EXPR, TREE_TYPE (array_ind_value), array_ind_value, | |
517 | func_parm), | |
518 | false, | |
519 | new_yes_list, TREE_TYPE (*new_var), new_no_list, TREE_TYPE (*new_var)); | |
520 | break; | |
521 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND: | |
522 | new_var_init = build_modify_expr | |
523 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
524 | location, build_zero_cst (new_var_type), new_var_type); | |
525 | new_exp_init = build_modify_expr | |
526 | (location, array_ind_value, TREE_TYPE (array_ind_value), | |
527 | NOP_EXPR, location, func_parm, TREE_TYPE (func_parm)); | |
528 | new_no_ind = build_modify_expr | |
529 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
530 | location, *new_var, TREE_TYPE (*new_var)); | |
531 | new_no_expr = build_modify_expr | |
532 | (location, array_ind_value, TREE_TYPE (array_ind_value), | |
533 | NOP_EXPR, | |
534 | location, array_ind_value, TREE_TYPE (array_ind_value)); | |
535 | if (list_size > 1) | |
536 | { | |
537 | new_yes_ind = build_modify_expr | |
538 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
713b46fa | 539 | location, an_loop_info[0].var, TREE_TYPE (an_loop_info[0].var)); |
36536d79 BI |
540 | new_yes_expr = build_modify_expr |
541 | (location, array_ind_value, TREE_TYPE (array_ind_value), | |
542 | NOP_EXPR, | |
543 | location, func_parm, TREE_TYPE (array_op0)); | |
544 | } | |
545 | else | |
546 | { | |
547 | new_yes_ind = build_modify_expr | |
548 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
549 | location, TREE_OPERAND (array_op0, 1), | |
550 | TREE_TYPE (TREE_OPERAND (array_op0, 1))); | |
551 | new_yes_expr = build_modify_expr | |
552 | (location, array_ind_value, TREE_TYPE (array_ind_value), | |
553 | NOP_EXPR, | |
554 | location, func_parm, TREE_OPERAND (array_op0, 1)); | |
555 | } | |
556 | new_yes_list = alloc_stmt_list (); | |
557 | append_to_statement_list (new_yes_ind, &new_yes_list); | |
558 | append_to_statement_list (new_yes_expr, &new_yes_list); | |
559 | ||
560 | new_no_list = alloc_stmt_list (); | |
561 | append_to_statement_list (new_no_ind, &new_no_list); | |
562 | append_to_statement_list (new_no_expr, &new_no_list); | |
563 | ||
564 | new_expr = build_conditional_expr | |
565 | (location, | |
566 | build2 (GE_EXPR, TREE_TYPE (array_ind_value), array_ind_value, | |
567 | func_parm), | |
568 | false, | |
569 | new_yes_list, TREE_TYPE (*new_var), new_no_list, TREE_TYPE (*new_var)); | |
570 | break; | |
571 | case BUILT_IN_CILKPLUS_SEC_REDUCE: | |
572 | new_var_init = build_modify_expr | |
573 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
574 | location, identity_value, new_var_type); | |
575 | new_call_expr = build_call_expr (call_fn, 2, *new_var, func_parm); | |
576 | new_expr = build_modify_expr | |
577 | (location, *new_var, TREE_TYPE (*new_var), NOP_EXPR, | |
578 | location, new_call_expr, TREE_TYPE (*new_var)); | |
579 | break; | |
580 | case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING: | |
581 | new_expr = build_call_expr (call_fn, 2, identity_value, func_parm); | |
582 | break; | |
583 | default: | |
584 | gcc_unreachable (); | |
585 | break; | |
586 | } | |
587 | ||
588 | for (ii = 0; ii < rank; ii++) | |
713b46fa | 589 | append_to_statement_list (an_loop_info[ii].ind_init, &loop_init); |
36536d79 BI |
590 | |
591 | if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND | |
592 | || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND) | |
593 | append_to_statement_list (new_exp_init, &loop_init); | |
594 | if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING) | |
595 | append_to_statement_list (new_var_init, &loop_init); | |
596 | ||
597 | append_to_statement_list_force (loop_init, &loop_with_init); | |
598 | body = new_expr; | |
599 | for (ii = 0; ii < rank; ii++) | |
600 | { | |
601 | tree new_loop = push_stmt_list (); | |
713b46fa BI |
602 | c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr, |
603 | body, NULL_TREE, NULL_TREE, true); | |
36536d79 BI |
604 | body = pop_stmt_list (new_loop); |
605 | } | |
606 | append_to_statement_list_force (body, &loop_with_init); | |
713b46fa BI |
607 | |
608 | an_info.release (); | |
609 | an_loop_info.release (); | |
36536d79 BI |
610 | |
611 | return loop_with_init; | |
612 | } | |
613 | ||
614 | /* Returns a loop with ARRAY_REF inside it with an appropriate modify expr. | |
615 | The LHS and/or RHS will be array notation expressions that have a MODIFYCODE | |
616 | Their locations are specified by LHS_LOC, RHS_LOC. The location of the | |
617 | modify expression is location. The original type of LHS and RHS are passed | |
618 | in LHS_ORIGTYPE and RHS_ORIGTYPE. */ | |
619 | ||
620 | tree | |
621 | build_array_notation_expr (location_t location, tree lhs, tree lhs_origtype, | |
622 | enum tree_code modifycode, location_t rhs_loc, | |
623 | tree rhs, tree rhs_origtype) | |
624 | { | |
713b46fa | 625 | bool found_builtin_fn = false; |
36536d79 BI |
626 | tree array_expr_lhs = NULL_TREE, array_expr_rhs = NULL_TREE; |
627 | tree array_expr = NULL_TREE; | |
713b46fa BI |
628 | tree an_init = NULL_TREE; |
629 | vec<tree> cond_expr = vNULL; | |
36536d79 BI |
630 | tree body, loop_with_init = alloc_stmt_list(); |
631 | tree scalar_mods = NULL_TREE; | |
36536d79 BI |
632 | vec<tree, va_gc> *rhs_array_operand = NULL, *lhs_array_operand = NULL; |
633 | size_t lhs_rank = 0, rhs_rank = 0; | |
713b46fa | 634 | size_t ii = 0; |
36536d79 | 635 | vec<tree, va_gc> *lhs_list = NULL, *rhs_list = NULL; |
713b46fa BI |
636 | tree new_modify_expr, new_var = NULL_TREE, builtin_loop = NULL_TREE; |
637 | size_t rhs_list_size = 0, lhs_list_size = 0; | |
638 | vec<vec<an_parts> > lhs_an_info = vNULL, rhs_an_info = vNULL; | |
639 | vec<an_loop_parts> lhs_an_loop_info = vNULL, rhs_an_loop_info = vNULL; | |
640 | ||
36536d79 BI |
641 | /* If either of this is true, an error message must have been send out |
642 | already. Not necessary to send out multiple error messages. */ | |
643 | if (lhs == error_mark_node || rhs == error_mark_node) | |
644 | return error_mark_node; | |
645 | ||
646 | if (!find_rank (location, rhs, rhs, false, &rhs_rank)) | |
647 | return error_mark_node; | |
648 | ||
649 | extract_array_notation_exprs (rhs, false, &rhs_list); | |
650 | rhs_list_size = vec_safe_length (rhs_list); | |
651 | an_init = push_stmt_list (); | |
652 | if (rhs_rank) | |
653 | { | |
654 | scalar_mods = replace_invariant_exprs (&rhs); | |
655 | if (scalar_mods) | |
656 | add_stmt (scalar_mods); | |
657 | } | |
658 | for (ii = 0; ii < rhs_list_size; ii++) | |
659 | { | |
660 | tree rhs_node = (*rhs_list)[ii]; | |
661 | if (TREE_CODE (rhs_node) == CALL_EXPR) | |
662 | { | |
663 | builtin_loop = fix_builtin_array_notation_fn (rhs_node, &new_var); | |
664 | if (builtin_loop == error_mark_node) | |
665 | { | |
666 | pop_stmt_list (an_init); | |
667 | return error_mark_node; | |
668 | } | |
669 | else if (builtin_loop) | |
670 | { | |
671 | add_stmt (builtin_loop); | |
672 | found_builtin_fn = true; | |
673 | if (new_var) | |
674 | { | |
675 | vec<tree, va_gc> *rhs_sub_list = NULL, *new_var_list = NULL; | |
676 | vec_safe_push (rhs_sub_list, rhs_node); | |
677 | vec_safe_push (new_var_list, new_var); | |
678 | replace_array_notations (&rhs, false, rhs_sub_list, | |
679 | new_var_list); | |
680 | } | |
681 | } | |
682 | } | |
683 | } | |
684 | ||
685 | lhs_rank = 0; | |
686 | rhs_rank = 0; | |
687 | if (!find_rank (location, lhs, lhs, true, &lhs_rank)) | |
688 | { | |
689 | pop_stmt_list (an_init); | |
690 | return error_mark_node; | |
691 | } | |
692 | ||
693 | if (!find_rank (location, rhs, rhs, true, &rhs_rank)) | |
694 | { | |
695 | pop_stmt_list (an_init); | |
696 | return error_mark_node; | |
697 | } | |
698 | ||
699 | if (lhs_rank == 0 && rhs_rank == 0) | |
700 | { | |
701 | if (found_builtin_fn) | |
702 | { | |
703 | new_modify_expr = build_modify_expr (location, lhs, lhs_origtype, | |
704 | modifycode, rhs_loc, rhs, | |
705 | rhs_origtype); | |
706 | add_stmt (new_modify_expr); | |
707 | pop_stmt_list (an_init); | |
708 | return an_init; | |
709 | } | |
710 | else | |
711 | { | |
712 | pop_stmt_list (an_init); | |
713 | return NULL_TREE; | |
714 | } | |
715 | } | |
716 | rhs_list_size = 0; | |
717 | rhs_list = NULL; | |
718 | extract_array_notation_exprs (rhs, true, &rhs_list); | |
719 | extract_array_notation_exprs (lhs, true, &lhs_list); | |
720 | rhs_list_size = vec_safe_length (rhs_list); | |
721 | lhs_list_size = vec_safe_length (lhs_list); | |
722 | ||
73a23b06 | 723 | if (lhs_rank == 0 && rhs_rank != 0) |
36536d79 BI |
724 | { |
725 | tree rhs_base = rhs; | |
726 | if (TREE_CODE (rhs_base) == ARRAY_NOTATION_REF) | |
727 | { | |
728 | for (ii = 0; ii < (size_t) rhs_rank; ii++) | |
729 | rhs_base = ARRAY_NOTATION_ARRAY (rhs); | |
730 | ||
731 | error_at (location, "%qE cannot be scalar when %qE is not", lhs, | |
732 | rhs_base); | |
733 | return error_mark_node; | |
734 | } | |
735 | else | |
736 | { | |
737 | error_at (location, "%qE cannot be scalar when %qE is not", lhs, | |
738 | rhs_base); | |
739 | return error_mark_node; | |
740 | } | |
741 | } | |
742 | if (lhs_rank != 0 && rhs_rank != 0 && lhs_rank != rhs_rank) | |
743 | { | |
36536d79 BI |
744 | error_at (location, "rank mismatch between %qE and %qE", lhs, rhs); |
745 | pop_stmt_list (an_init); | |
746 | return error_mark_node; | |
747 | } | |
748 | ||
749 | /* Here we assign the array notation components to variable so that we can | |
750 | satisfy the exec once rule. */ | |
751 | for (ii = 0; ii < lhs_list_size; ii++) | |
713b46fa | 752 | { |
36536d79 | 753 | tree array_node = (*lhs_list)[ii]; |
713b46fa BI |
754 | make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node)); |
755 | make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node)); | |
756 | make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node)); | |
36536d79 | 757 | } |
36536d79 | 758 | for (ii = 0; ii < rhs_list_size; ii++) |
713b46fa BI |
759 | if ((*rhs_list)[ii] && TREE_CODE ((*rhs_list)[ii]) == ARRAY_NOTATION_REF) |
760 | { | |
761 | tree array_node = (*rhs_list)[ii]; | |
762 | make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node)); | |
763 | make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node)); | |
764 | make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node)); | |
765 | } | |
36536d79 | 766 | |
713b46fa | 767 | cond_expr.safe_grow_cleared (MAX (lhs_rank, rhs_rank)); |
36536d79 | 768 | |
713b46fa | 769 | lhs_an_loop_info.safe_grow_cleared (lhs_rank); |
36536d79 | 770 | if (rhs_rank) |
713b46fa | 771 | rhs_an_loop_info.safe_grow_cleared (rhs_rank); |
36536d79 | 772 | |
713b46fa BI |
773 | cilkplus_extract_an_triplets (lhs_list, lhs_list_size, lhs_rank, |
774 | &lhs_an_info); | |
775 | if (rhs_rank) | |
36536d79 | 776 | { |
713b46fa BI |
777 | rhs_an_loop_info.safe_grow_cleared (rhs_rank); |
778 | cilkplus_extract_an_triplets (rhs_list, rhs_list_size, rhs_rank, | |
779 | &rhs_an_info); | |
36536d79 | 780 | } |
713b46fa BI |
781 | if (length_mismatch_in_expr_p (EXPR_LOCATION (lhs), lhs_an_info) |
782 | || (rhs_rank | |
783 | && length_mismatch_in_expr_p (EXPR_LOCATION (rhs), rhs_an_info))) | |
36536d79 BI |
784 | { |
785 | pop_stmt_list (an_init); | |
786 | return error_mark_node; | |
787 | } | |
36536d79 | 788 | if (lhs_list_size > 0 && rhs_list_size > 0 && lhs_rank > 0 && rhs_rank > 0 |
713b46fa BI |
789 | && TREE_CODE (lhs_an_info[0][0].length) == INTEGER_CST |
790 | && rhs_an_info[0][0].length | |
791 | && TREE_CODE (rhs_an_info[0][0].length) == INTEGER_CST) | |
36536d79 | 792 | { |
713b46fa BI |
793 | HOST_WIDE_INT l_length = int_cst_value (lhs_an_info[0][0].length); |
794 | HOST_WIDE_INT r_length = int_cst_value (rhs_an_info[0][0].length); | |
36536d79 BI |
795 | /* Length can be negative or positive. As long as the magnitude is OK, |
796 | then the array notation is valid. */ | |
065ce7f1 | 797 | if (absu_hwi (l_length) != absu_hwi (r_length)) |
36536d79 BI |
798 | { |
799 | error_at (location, "length mismatch between LHS and RHS"); | |
800 | pop_stmt_list (an_init); | |
801 | return error_mark_node; | |
802 | } | |
803 | } | |
804 | for (ii = 0; ii < lhs_rank; ii++) | |
713b46fa BI |
805 | if (lhs_an_info[0][ii].is_vector) |
806 | { | |
b731b390 | 807 | lhs_an_loop_info[ii].var = create_tmp_var (integer_type_node); |
713b46fa BI |
808 | lhs_an_loop_info[ii].ind_init = build_modify_expr |
809 | (location, lhs_an_loop_info[ii].var, | |
810 | TREE_TYPE (lhs_an_loop_info[ii].var), NOP_EXPR, | |
811 | location, build_zero_cst (TREE_TYPE (lhs_an_loop_info[ii].var)), | |
812 | TREE_TYPE (lhs_an_loop_info[ii].var)); | |
813 | } | |
36536d79 BI |
814 | for (ii = 0; ii < rhs_rank; ii++) |
815 | { | |
816 | /* When we have a polynomial, we assume that the indices are of type | |
817 | integer. */ | |
b731b390 | 818 | rhs_an_loop_info[ii].var = create_tmp_var (integer_type_node); |
713b46fa BI |
819 | rhs_an_loop_info[ii].ind_init = build_modify_expr |
820 | (location, rhs_an_loop_info[ii].var, | |
821 | TREE_TYPE (rhs_an_loop_info[ii].var), NOP_EXPR, | |
822 | location, build_int_cst (TREE_TYPE (rhs_an_loop_info[ii].var), 0), | |
823 | TREE_TYPE (rhs_an_loop_info[ii].var)); | |
36536d79 BI |
824 | } |
825 | if (lhs_rank) | |
826 | { | |
713b46fa BI |
827 | lhs_array_operand = create_array_refs |
828 | (location, lhs_an_info, lhs_an_loop_info, lhs_list_size, lhs_rank); | |
36536d79 BI |
829 | replace_array_notations (&lhs, true, lhs_list, lhs_array_operand); |
830 | array_expr_lhs = lhs; | |
831 | } | |
713b46fa BI |
832 | if (rhs_array_operand) |
833 | vec_safe_truncate (rhs_array_operand, 0); | |
36536d79 BI |
834 | if (rhs_rank) |
835 | { | |
713b46fa BI |
836 | rhs_array_operand = create_array_refs |
837 | (location, rhs_an_info, rhs_an_loop_info, rhs_list_size, rhs_rank); | |
838 | replace_array_notations (&rhs, true, rhs_list, rhs_array_operand); | |
839 | vec_safe_truncate (rhs_array_operand, 0); | |
840 | rhs_array_operand = fix_sec_implicit_args (location, rhs_list, | |
841 | rhs_an_loop_info, rhs_rank, | |
842 | rhs); | |
843 | if (!rhs_array_operand) | |
844 | return error_mark_node; | |
36536d79 | 845 | replace_array_notations (&rhs, true, rhs_list, rhs_array_operand); |
36536d79 | 846 | } |
713b46fa | 847 | else if (rhs_list_size > 0) |
36536d79 | 848 | { |
713b46fa BI |
849 | rhs_array_operand = fix_sec_implicit_args (location, rhs_list, |
850 | lhs_an_loop_info, lhs_rank, | |
851 | lhs); | |
852 | if (!rhs_array_operand) | |
853 | return error_mark_node; | |
36536d79 | 854 | replace_array_notations (&rhs, true, rhs_list, rhs_array_operand); |
36536d79 | 855 | } |
713b46fa BI |
856 | array_expr_lhs = lhs; |
857 | array_expr_rhs = rhs; | |
36536d79 BI |
858 | array_expr = build_modify_expr (location, array_expr_lhs, lhs_origtype, |
859 | modifycode, rhs_loc, array_expr_rhs, | |
860 | rhs_origtype); | |
713b46fa BI |
861 | create_cmp_incr (location, &lhs_an_loop_info, lhs_rank, lhs_an_info); |
862 | if (rhs_rank) | |
863 | create_cmp_incr (location, &rhs_an_loop_info, rhs_rank, rhs_an_info); | |
864 | ||
865 | for (ii = 0; ii < MAX (lhs_rank, rhs_rank); ii++) | |
866 | if (ii < lhs_rank && ii < rhs_rank) | |
867 | cond_expr[ii] = build2 (TRUTH_ANDIF_EXPR, boolean_type_node, | |
868 | lhs_an_loop_info[ii].cmp, | |
869 | rhs_an_loop_info[ii].cmp); | |
870 | else if (ii < lhs_rank && ii >= rhs_rank) | |
871 | cond_expr[ii] = lhs_an_loop_info[ii].cmp; | |
872 | else | |
873 | gcc_unreachable (); | |
36536d79 BI |
874 | |
875 | an_init = pop_stmt_list (an_init); | |
876 | append_to_statement_list_force (an_init, &loop_with_init); | |
877 | body = array_expr; | |
878 | for (ii = 0; ii < MAX (lhs_rank, rhs_rank); ii++) | |
879 | { | |
880 | tree incr_list = alloc_stmt_list (); | |
881 | tree new_loop = push_stmt_list (); | |
882 | if (lhs_rank) | |
713b46fa | 883 | add_stmt (lhs_an_loop_info[ii].ind_init); |
36536d79 | 884 | if (rhs_rank) |
713b46fa | 885 | add_stmt (rhs_an_loop_info[ii].ind_init); |
36536d79 | 886 | if (lhs_rank) |
713b46fa BI |
887 | append_to_statement_list_force (lhs_an_loop_info[ii].incr, &incr_list); |
888 | if (rhs_rank && rhs_an_loop_info[ii].incr) | |
889 | append_to_statement_list_force (rhs_an_loop_info[ii].incr, &incr_list); | |
36536d79 BI |
890 | c_finish_loop (location, cond_expr[ii], incr_list, body, NULL_TREE, |
891 | NULL_TREE, true); | |
892 | body = pop_stmt_list (new_loop); | |
893 | } | |
894 | append_to_statement_list_force (body, &loop_with_init); | |
713b46fa BI |
895 | |
896 | lhs_an_info.release (); | |
897 | lhs_an_loop_info.release (); | |
898 | if (rhs_rank) | |
899 | { | |
900 | rhs_an_info.release (); | |
901 | rhs_an_loop_info.release (); | |
902 | } | |
903 | cond_expr.release (); | |
36536d79 BI |
904 | return loop_with_init; |
905 | } | |
906 | ||
907 | /* Helper function for fix_conditional_array_notations. Encloses the | |
908 | conditional statement passed in STMT with a loop around it | |
909 | and replaces the condition in STMT with a ARRAY_REF tree-node to the array. | |
910 | The condition must have an ARRAY_NOTATION_REF tree. An expansion of array | |
911 | notation in STMT is returned in a STATEMENT_LIST. */ | |
912 | ||
913 | static tree | |
914 | fix_conditional_array_notations_1 (tree stmt) | |
915 | { | |
916 | vec<tree, va_gc> *array_list = NULL, *array_operand = NULL; | |
917 | size_t list_size = 0; | |
918 | tree cond = NULL_TREE, builtin_loop = NULL_TREE, new_var = NULL_TREE; | |
713b46fa BI |
919 | size_t rank = 0, ii = 0; |
920 | tree loop_init; | |
36536d79 BI |
921 | location_t location = EXPR_LOCATION (stmt); |
922 | tree body = NULL_TREE, loop_with_init = alloc_stmt_list (); | |
713b46fa BI |
923 | vec<vec<an_parts> > an_info = vNULL; |
924 | vec<an_loop_parts> an_loop_info = vNULL; | |
925 | ||
36536d79 BI |
926 | if (TREE_CODE (stmt) == COND_EXPR) |
927 | cond = COND_EXPR_COND (stmt); | |
928 | else if (TREE_CODE (stmt) == SWITCH_EXPR) | |
929 | cond = SWITCH_COND (stmt); | |
318cda85 BI |
930 | else if (truth_value_p (TREE_CODE (stmt))) |
931 | cond = TREE_OPERAND (stmt, 0); | |
36536d79 BI |
932 | else |
933 | /* Otherwise dont even touch the statement. */ | |
934 | return stmt; | |
935 | ||
936 | if (!find_rank (location, cond, cond, false, &rank)) | |
937 | return error_mark_node; | |
938 | ||
25c22937 | 939 | extract_array_notation_exprs (stmt, false, &array_list); |
36536d79 BI |
940 | loop_init = push_stmt_list (); |
941 | for (ii = 0; ii < vec_safe_length (array_list); ii++) | |
942 | { | |
943 | tree array_node = (*array_list)[ii]; | |
944 | if (TREE_CODE (array_node) == CALL_EXPR) | |
945 | { | |
946 | builtin_loop = fix_builtin_array_notation_fn (array_node, &new_var); | |
947 | if (builtin_loop == error_mark_node) | |
948 | { | |
949 | add_stmt (error_mark_node); | |
950 | pop_stmt_list (loop_init); | |
951 | return loop_init; | |
952 | } | |
953 | else if (builtin_loop) | |
954 | { | |
955 | vec <tree, va_gc>* sub_list = NULL, *new_var_list = NULL; | |
956 | vec_safe_push (sub_list, array_node); | |
957 | vec_safe_push (new_var_list, new_var); | |
958 | add_stmt (builtin_loop); | |
25c22937 | 959 | replace_array_notations (&stmt, false, sub_list, new_var_list); |
36536d79 BI |
960 | } |
961 | } | |
962 | } | |
25c22937 | 963 | if (!find_rank (location, stmt, stmt, true, &rank)) |
36536d79 BI |
964 | { |
965 | pop_stmt_list (loop_init); | |
966 | return error_mark_node; | |
967 | } | |
968 | if (rank == 0) | |
969 | { | |
970 | add_stmt (stmt); | |
971 | pop_stmt_list (loop_init); | |
972 | return loop_init; | |
973 | } | |
25c22937 | 974 | extract_array_notation_exprs (stmt, true, &array_list); |
36536d79 BI |
975 | |
976 | if (vec_safe_length (array_list) == 0) | |
977 | return stmt; | |
978 | ||
979 | list_size = vec_safe_length (array_list); | |
713b46fa BI |
980 | an_loop_info.safe_grow_cleared (rank); |
981 | ||
36536d79 | 982 | for (ii = 0; ii < list_size; ii++) |
713b46fa BI |
983 | if ((*array_list)[ii] |
984 | && TREE_CODE ((*array_list)[ii]) == ARRAY_NOTATION_REF) | |
985 | { | |
986 | tree array_node = (*array_list)[ii]; | |
987 | make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node)); | |
988 | make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node)); | |
989 | make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node)); | |
990 | } | |
991 | cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info); | |
36536d79 BI |
992 | for (ii = 0; ii < rank; ii++) |
993 | { | |
b731b390 | 994 | an_loop_info[ii].var = create_tmp_var (integer_type_node); |
713b46fa BI |
995 | an_loop_info[ii].ind_init = |
996 | build_modify_expr (location, an_loop_info[ii].var, | |
997 | TREE_TYPE (an_loop_info[ii].var), NOP_EXPR, | |
36536d79 | 998 | location, |
713b46fa BI |
999 | build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0), |
1000 | TREE_TYPE (an_loop_info[ii].var)); | |
36536d79 | 1001 | } |
713b46fa BI |
1002 | array_operand = create_array_refs (location, an_info, an_loop_info, |
1003 | list_size, rank); | |
36536d79 | 1004 | replace_array_notations (&stmt, true, array_list, array_operand); |
713b46fa BI |
1005 | create_cmp_incr (location, &an_loop_info, rank, an_info); |
1006 | ||
36536d79 BI |
1007 | loop_init = pop_stmt_list (loop_init); |
1008 | body = stmt; | |
1009 | append_to_statement_list_force (loop_init, &loop_with_init); | |
1010 | ||
1011 | for (ii = 0; ii < rank; ii++) | |
1012 | { | |
1013 | tree new_loop = push_stmt_list (); | |
713b46fa BI |
1014 | add_stmt (an_loop_info[ii].ind_init); |
1015 | c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr, | |
1016 | body, NULL_TREE, NULL_TREE, true); | |
36536d79 BI |
1017 | body = pop_stmt_list (new_loop); |
1018 | } | |
1019 | append_to_statement_list_force (body, &loop_with_init); | |
36536d79 | 1020 | |
713b46fa BI |
1021 | an_loop_info.release (); |
1022 | an_info.release (); | |
36536d79 BI |
1023 | |
1024 | return loop_with_init; | |
1025 | } | |
1026 | ||
1027 | /* Top-level function to replace ARRAY_NOTATION_REF in a conditional statement | |
1028 | in STMT. An expansion of array notation in STMT is returned as a | |
1029 | STATEMENT_LIST. */ | |
1030 | ||
1031 | tree | |
1032 | fix_conditional_array_notations (tree stmt) | |
1033 | { | |
1034 | if (TREE_CODE (stmt) == STATEMENT_LIST) | |
1035 | { | |
1036 | tree_stmt_iterator tsi; | |
1037 | for (tsi = tsi_start (stmt); !tsi_end_p (tsi); tsi_next (&tsi)) | |
1038 | { | |
1039 | tree single_stmt = *tsi_stmt_ptr (tsi); | |
1040 | *tsi_stmt_ptr (tsi) = | |
1041 | fix_conditional_array_notations_1 (single_stmt); | |
1042 | } | |
1043 | return stmt; | |
1044 | } | |
1045 | else | |
1046 | return fix_conditional_array_notations_1 (stmt); | |
1047 | } | |
1048 | ||
1049 | /* Create a struct c_expr that contains a loop with ARRAY_REF expr at location | |
1050 | LOCATION with the tree_code CODE and the array notation expr is | |
1051 | passed in ARG. Returns the fixed c_expr in ARG itself. */ | |
1052 | ||
1053 | struct c_expr | |
1054 | fix_array_notation_expr (location_t location, enum tree_code code, | |
1055 | struct c_expr arg) | |
1056 | { | |
1057 | ||
1058 | vec<tree, va_gc> *array_list = NULL, *array_operand = NULL; | |
713b46fa BI |
1059 | size_t list_size = 0, rank = 0, ii = 0; |
1060 | tree loop_init; | |
36536d79 | 1061 | tree body, loop_with_init = alloc_stmt_list (); |
713b46fa BI |
1062 | vec<vec<an_parts> > an_info = vNULL; |
1063 | vec<an_loop_parts> an_loop_info = vNULL; | |
36536d79 BI |
1064 | |
1065 | if (!find_rank (location, arg.value, arg.value, false, &rank)) | |
1066 | { | |
1067 | /* If this function returns a NULL, we convert the tree value in the | |
1068 | structure to error_mark_node and the parser should take care of the | |
1069 | rest. */ | |
1070 | arg.value = error_mark_node; | |
1071 | return arg; | |
1072 | } | |
1073 | ||
1074 | if (rank == 0) | |
1075 | return arg; | |
1076 | ||
1077 | extract_array_notation_exprs (arg.value, true, &array_list); | |
1078 | ||
1079 | if (vec_safe_length (array_list) == 0) | |
1080 | return arg; | |
1081 | ||
1082 | list_size = vec_safe_length (array_list); | |
36536d79 | 1083 | |
713b46fa BI |
1084 | an_loop_info.safe_grow_cleared (rank); |
1085 | cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info); | |
36536d79 BI |
1086 | |
1087 | loop_init = push_stmt_list (); | |
36536d79 BI |
1088 | for (ii = 0; ii < rank; ii++) |
1089 | { | |
b731b390 | 1090 | an_loop_info[ii].var = create_tmp_var (integer_type_node); |
713b46fa BI |
1091 | an_loop_info[ii].ind_init = |
1092 | build_modify_expr (location, an_loop_info[ii].var, | |
1093 | TREE_TYPE (an_loop_info[ii].var), NOP_EXPR, | |
36536d79 | 1094 | location, |
713b46fa BI |
1095 | build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0), |
1096 | TREE_TYPE (an_loop_info[ii].var));; | |
36536d79 BI |
1097 | |
1098 | } | |
713b46fa BI |
1099 | array_operand = create_array_refs (location, an_info, an_loop_info, |
1100 | list_size, rank); | |
36536d79 | 1101 | replace_array_notations (&arg.value, true, array_list, array_operand); |
713b46fa | 1102 | create_cmp_incr (location, &an_loop_info, rank, an_info); |
36536d79 | 1103 | |
713b46fa | 1104 | arg = default_function_array_read_conversion (location, arg); |
36536d79 | 1105 | if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR) |
713b46fa | 1106 | arg.value = build_unary_op (location, code, arg.value, 0); |
36536d79 | 1107 | else if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR) |
713b46fa | 1108 | arg = parser_build_unary_op (location, code, arg); |
36536d79 BI |
1109 | |
1110 | loop_init = pop_stmt_list (loop_init); | |
1111 | append_to_statement_list_force (loop_init, &loop_with_init); | |
1112 | body = arg.value; | |
1113 | ||
1114 | for (ii = 0; ii < rank; ii++) | |
1115 | { | |
1116 | tree new_loop = push_stmt_list (); | |
713b46fa BI |
1117 | add_stmt (an_loop_info[ii].ind_init); |
1118 | c_finish_loop (location, an_loop_info[ii].cmp, | |
1119 | an_loop_info[ii].incr, body, NULL_TREE, | |
36536d79 BI |
1120 | NULL_TREE, true); |
1121 | body = pop_stmt_list (new_loop); | |
1122 | } | |
1123 | append_to_statement_list_force (body, &loop_with_init); | |
36536d79 | 1124 | arg.value = loop_with_init; |
713b46fa BI |
1125 | an_info.release (); |
1126 | an_loop_info.release (); | |
36536d79 BI |
1127 | return arg; |
1128 | } | |
1129 | ||
36536d79 BI |
1130 | /* Replaces array notations in a void function call arguments in ARG and returns |
1131 | a STATEMENT_LIST. */ | |
1132 | ||
1133 | static tree | |
1134 | fix_array_notation_call_expr (tree arg) | |
1135 | { | |
1136 | vec<tree, va_gc> *array_list = NULL, *array_operand = NULL; | |
1137 | tree new_var = NULL_TREE; | |
713b46fa BI |
1138 | size_t list_size = 0, rank = 0, ii = 0; |
1139 | tree loop_init; | |
36536d79 | 1140 | tree body, loop_with_init = alloc_stmt_list (); |
36536d79 | 1141 | location_t location = UNKNOWN_LOCATION; |
713b46fa BI |
1142 | vec<vec<an_parts> > an_info = vNULL; |
1143 | vec<an_loop_parts> an_loop_info = vNULL; | |
36536d79 BI |
1144 | |
1145 | if (TREE_CODE (arg) == CALL_EXPR | |
1146 | && is_cilkplus_reduce_builtin (CALL_EXPR_FN (arg))) | |
1147 | { | |
1148 | loop_init = fix_builtin_array_notation_fn (arg, &new_var); | |
1149 | /* We are ignoring the new var because either the user does not want to | |
1150 | capture it OR he is using sec_reduce_mutating function. */ | |
1151 | return loop_init; | |
713b46fa | 1152 | } |
36536d79 BI |
1153 | if (!find_rank (location, arg, arg, false, &rank)) |
1154 | return error_mark_node; | |
1155 | ||
1156 | if (rank == 0) | |
1157 | return arg; | |
1158 | ||
1159 | extract_array_notation_exprs (arg, true, &array_list); | |
1160 | if (vec_safe_length (array_list) == 0) | |
1161 | return arg; | |
1162 | ||
1163 | list_size = vec_safe_length (array_list); | |
1164 | location = EXPR_LOCATION (arg); | |
713b46fa | 1165 | an_loop_info.safe_grow_cleared (rank); |
36536d79 BI |
1166 | |
1167 | loop_init = push_stmt_list (); | |
1168 | for (ii = 0; ii < list_size; ii++) | |
713b46fa BI |
1169 | if ((*array_list)[ii] |
1170 | && TREE_CODE ((*array_list)[ii]) == ARRAY_NOTATION_REF) | |
36536d79 | 1171 | { |
713b46fa BI |
1172 | tree array_node = (*array_list)[ii]; |
1173 | make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node)); | |
1174 | make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node)); | |
1175 | make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node)); | |
36536d79 | 1176 | } |
713b46fa BI |
1177 | cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info); |
1178 | if (length_mismatch_in_expr_p (location, an_info)) | |
36536d79 BI |
1179 | { |
1180 | pop_stmt_list (loop_init); | |
1181 | return error_mark_node; | |
1182 | } | |
36536d79 BI |
1183 | for (ii = 0; ii < rank; ii++) |
1184 | { | |
b731b390 | 1185 | an_loop_info[ii].var = create_tmp_var (integer_type_node); |
713b46fa BI |
1186 | an_loop_info[ii].ind_init = |
1187 | build_modify_expr (location, an_loop_info[ii].var, | |
1188 | TREE_TYPE (an_loop_info[ii].var), NOP_EXPR, location, | |
1189 | build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0), | |
1190 | TREE_TYPE (an_loop_info[ii].var)); | |
36536d79 BI |
1191 | |
1192 | } | |
713b46fa BI |
1193 | array_operand = create_array_refs (location, an_info, an_loop_info, |
1194 | list_size, rank); | |
36536d79 | 1195 | replace_array_notations (&arg, true, array_list, array_operand); |
713b46fa | 1196 | create_cmp_incr (location, &an_loop_info, rank, an_info); |
36536d79 BI |
1197 | loop_init = pop_stmt_list (loop_init); |
1198 | append_to_statement_list_force (loop_init, &loop_with_init); | |
1199 | body = arg; | |
1200 | for (ii = 0; ii < rank; ii++) | |
1201 | { | |
1202 | tree new_loop = push_stmt_list (); | |
713b46fa BI |
1203 | add_stmt (an_loop_info[ii].ind_init); |
1204 | c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr, | |
1205 | body, NULL_TREE, NULL_TREE, true); | |
36536d79 BI |
1206 | body = pop_stmt_list (new_loop); |
1207 | } | |
1208 | append_to_statement_list_force (body, &loop_with_init); | |
713b46fa BI |
1209 | an_loop_info.release (); |
1210 | an_info.release (); | |
36536d79 BI |
1211 | return loop_with_init; |
1212 | } | |
1213 | ||
1214 | /* Expands the built-in functions in a return. EXPR is a RETURN_EXPR with | |
1215 | a built-in reduction function. This function returns the expansion code for | |
1216 | the built-in function. */ | |
1217 | ||
1218 | static tree | |
1219 | fix_return_expr (tree expr) | |
1220 | { | |
1221 | tree new_mod_list, new_var, new_mod, retval_expr, retval_type; | |
1222 | location_t loc = EXPR_LOCATION (expr); | |
1223 | ||
1224 | new_mod_list = alloc_stmt_list (); | |
1225 | retval_expr = TREE_OPERAND (expr, 0); | |
1226 | retval_type = TREE_TYPE (TREE_OPERAND (retval_expr, 1)); | |
1227 | new_var = build_decl (loc, VAR_DECL, NULL_TREE, TREE_TYPE (retval_expr)); | |
1228 | new_mod = build_array_notation_expr (loc, new_var, TREE_TYPE (new_var), | |
1229 | NOP_EXPR, loc, | |
1230 | TREE_OPERAND (retval_expr, 1), | |
1231 | retval_type); | |
1232 | TREE_OPERAND (retval_expr, 1) = new_var; | |
1233 | TREE_OPERAND (expr, 0) = retval_expr; | |
1234 | append_to_statement_list_force (new_mod, &new_mod_list); | |
1235 | append_to_statement_list_force (expr, &new_mod_list); | |
1236 | return new_mod_list; | |
1237 | } | |
1238 | ||
40f14e9f BI |
1239 | /* Callback for walk_tree. Expands all array notations in *TP. *WALK_SUBTREES |
1240 | is set to 1 unless *TP contains no array notation expressions. */ | |
36536d79 | 1241 | |
40f14e9f BI |
1242 | static tree |
1243 | expand_array_notations (tree *tp, int *walk_subtrees, void *) | |
36536d79 | 1244 | { |
40f14e9f BI |
1245 | if (!contains_array_notation_expr (*tp)) |
1246 | { | |
1247 | *walk_subtrees = 0; | |
1248 | return NULL_TREE; | |
1249 | } | |
1250 | *walk_subtrees = 1; | |
36536d79 | 1251 | |
40f14e9f | 1252 | switch (TREE_CODE (*tp)) |
36536d79 | 1253 | { |
318cda85 BI |
1254 | case TRUTH_ORIF_EXPR: |
1255 | case TRUTH_ANDIF_EXPR: | |
1256 | case TRUTH_OR_EXPR: | |
1257 | case TRUTH_AND_EXPR: | |
1258 | case TRUTH_XOR_EXPR: | |
1259 | case TRUTH_NOT_EXPR: | |
36536d79 | 1260 | case COND_EXPR: |
40f14e9f BI |
1261 | *tp = fix_conditional_array_notations (*tp); |
1262 | break; | |
25c22937 BI |
1263 | case MODIFY_EXPR: |
1264 | { | |
40f14e9f | 1265 | location_t loc = EXPR_HAS_LOCATION (*tp) ? EXPR_LOCATION (*tp) : |
25c22937 | 1266 | UNKNOWN_LOCATION; |
40f14e9f BI |
1267 | tree lhs = TREE_OPERAND (*tp, 0); |
1268 | tree rhs = TREE_OPERAND (*tp, 1); | |
25c22937 BI |
1269 | location_t rhs_loc = EXPR_HAS_LOCATION (rhs) ? EXPR_LOCATION (rhs) : |
1270 | UNKNOWN_LOCATION; | |
40f14e9f BI |
1271 | *tp = build_array_notation_expr (loc, lhs, TREE_TYPE (lhs), NOP_EXPR, |
1272 | rhs_loc, rhs, TREE_TYPE (rhs)); | |
25c22937 | 1273 | } |
40f14e9f | 1274 | break; |
a7ee52fb IZ |
1275 | case DECL_EXPR: |
1276 | { | |
1277 | tree x = DECL_EXPR_DECL (*tp); | |
1278 | if (DECL_INITIAL (x)) | |
1279 | { | |
1280 | location_t loc = DECL_SOURCE_LOCATION (x); | |
1281 | tree lhs = x; | |
1282 | tree rhs = DECL_INITIAL (x); | |
1283 | DECL_INITIAL (x) = NULL; | |
1284 | tree new_modify_expr = build_modify_expr (loc, lhs, | |
1285 | TREE_TYPE (lhs), | |
1286 | NOP_EXPR, | |
1287 | loc, rhs, | |
1288 | TREE_TYPE(rhs)); | |
1289 | expand_array_notations (&new_modify_expr, walk_subtrees, NULL); | |
1290 | *tp = new_modify_expr; | |
1291 | } | |
1292 | } | |
1293 | break; | |
36536d79 | 1294 | case CALL_EXPR: |
40f14e9f BI |
1295 | *tp = fix_array_notation_call_expr (*tp); |
1296 | break; | |
36536d79 | 1297 | case RETURN_EXPR: |
40f14e9f BI |
1298 | *tp = fix_return_expr (*tp); |
1299 | break; | |
1300 | case COMPOUND_EXPR: | |
1301 | if (TREE_CODE (TREE_OPERAND (*tp, 0)) == SAVE_EXPR) | |
1302 | { | |
1303 | /* In here we are calling expand_array_notations because | |
1304 | we need to be able to catch the return value and check if | |
1305 | it is an error_mark_node. */ | |
1306 | expand_array_notations (&TREE_OPERAND (*tp, 1), walk_subtrees, NULL); | |
1307 | ||
1308 | /* SAVE_EXPR cannot have an error_mark_node inside it. This check | |
1309 | will make sure that if there is an error in expanding of | |
1310 | array notations (e.g. rank mismatch) then replace the entire | |
1311 | SAVE_EXPR with an error_mark_node. */ | |
1312 | if (TREE_OPERAND (*tp, 1) == error_mark_node) | |
1313 | *tp = error_mark_node; | |
1314 | } | |
1315 | break; | |
1509bdda | 1316 | case ARRAY_NOTATION_REF: |
40f14e9f | 1317 | /* If we are here, then we are dealing with cases like this: |
1509bdda BI |
1318 | A[:]; |
1319 | A[x:y:z]; | |
1320 | A[x:y]; | |
1321 | Replace those with just void zero node. */ | |
632f2871 | 1322 | *tp = void_node; |
36536d79 | 1323 | default: |
40f14e9f | 1324 | break; |
36536d79 | 1325 | } |
40f14e9f BI |
1326 | return NULL_TREE; |
1327 | } | |
1328 | ||
1329 | /* Walks through tree node T and expands all array notations in its subtrees. | |
1330 | The return value is the same type as T but with all array notations | |
1331 | replaced with appropriate ARRAY_REFS with a loop around it. */ | |
1332 | ||
1333 | tree | |
1334 | expand_array_notation_exprs (tree t) | |
1335 | { | |
1336 | walk_tree (&t, expand_array_notations, NULL, NULL); | |
36536d79 BI |
1337 | return t; |
1338 | } | |
1339 | ||
1340 | /* This handles expression of the form "a[i:j:k]" or "a[:]" or "a[i:j]," which | |
1341 | denotes an array notation expression. If a is a variable or a member, then | |
1342 | we generate a ARRAY_NOTATION_REF front-end tree and return it. | |
1343 | This tree is broken down to ARRAY_REF toward the end of parsing. | |
1344 | ARRAY_NOTATION_REF tree holds the START_INDEX, LENGTH, STRIDE and the TYPE | |
1345 | of ARRAY_REF. Restrictions on START_INDEX, LENGTH and STRIDE is same as that | |
1346 | of the index field passed into ARRAY_REF. The only additional restriction | |
1347 | is that, unlike index in ARRAY_REF, stride, length and start_index cannot | |
1348 | contain ARRAY_NOTATIONS. */ | |
1349 | ||
1350 | tree | |
1351 | build_array_notation_ref (location_t loc, tree array, tree start_index, | |
1352 | tree length, tree stride, tree type) | |
1353 | { | |
1354 | tree array_ntn_tree = NULL_TREE; | |
1355 | size_t stride_rank = 0, length_rank = 0, start_rank = 0; | |
1356 | ||
1357 | if (!INTEGRAL_TYPE_P (TREE_TYPE (start_index))) | |
1358 | { | |
1359 | error_at (loc, | |
1360 | "start-index of array notation triplet is not an integer"); | |
1361 | return error_mark_node; | |
1362 | } | |
1363 | if (!INTEGRAL_TYPE_P (TREE_TYPE (length))) | |
1364 | { | |
1365 | error_at (loc, "length of array notation triplet is not an integer"); | |
1366 | return error_mark_node; | |
1367 | } | |
1368 | ||
1369 | /* The stride is an optional field. */ | |
1370 | if (stride && !INTEGRAL_TYPE_P (TREE_TYPE (stride))) | |
1371 | { | |
1372 | error_at (loc, "stride of array notation triplet is not an integer"); | |
1373 | return error_mark_node; | |
1374 | } | |
1375 | if (!stride) | |
1376 | { | |
1377 | if (TREE_CONSTANT (start_index) && TREE_CONSTANT (length) | |
1378 | && tree_int_cst_lt (length, start_index)) | |
1379 | stride = build_int_cst (TREE_TYPE (start_index), -1); | |
1380 | else | |
1381 | stride = build_int_cst (TREE_TYPE (start_index), 1); | |
1382 | } | |
1383 | ||
1384 | if (!find_rank (loc, start_index, start_index, false, &start_rank)) | |
1385 | return error_mark_node; | |
1386 | if (!find_rank (loc, length, length, false, &length_rank)) | |
1387 | return error_mark_node; | |
1388 | if (!find_rank (loc, stride, stride, false, &stride_rank)) | |
1389 | return error_mark_node; | |
1390 | ||
1391 | if (start_rank != 0) | |
1392 | { | |
1393 | error_at (loc, "rank of an array notation triplet's start-index is not " | |
1394 | "zero"); | |
1395 | return error_mark_node; | |
1396 | } | |
1397 | if (length_rank != 0) | |
1398 | { | |
1399 | error_at (loc, "rank of an array notation triplet's length is not zero"); | |
1400 | return error_mark_node; | |
1401 | } | |
1402 | if (stride_rank != 0) | |
1403 | { | |
1404 | error_at (loc, "rank of array notation triplet's stride is not zero"); | |
1405 | return error_mark_node; | |
1406 | } | |
1407 | array_ntn_tree = build4 (ARRAY_NOTATION_REF, NULL_TREE, NULL_TREE, NULL_TREE, | |
1408 | NULL_TREE, NULL_TREE); | |
1409 | ARRAY_NOTATION_ARRAY (array_ntn_tree) = array; | |
1410 | ARRAY_NOTATION_START (array_ntn_tree) = start_index; | |
1411 | ARRAY_NOTATION_LENGTH (array_ntn_tree) = length; | |
1412 | ARRAY_NOTATION_STRIDE (array_ntn_tree) = stride; | |
1413 | TREE_TYPE (array_ntn_tree) = type; | |
1414 | ||
1415 | return array_ntn_tree; | |
1416 | } |