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