]>
Commit | Line | Data |
---|---|---|
601d98be | 1 | /* Pass manager for Fortran front end. |
818ab71a | 2 | Copyright (C) 2010-2016 Free Software Foundation, Inc. |
601d98be TK |
3 | Contributed by Thomas König. |
4 | ||
5 | This file is part of GCC. | |
6 | ||
7 | GCC is free software; you can redistribute it and/or modify it under | |
8 | the terms of the GNU General Public License as published by the Free | |
9 | Software Foundation; either version 3, or (at your option) any later | |
10 | version. | |
11 | ||
12 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
15 | for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with GCC; see the file COPYING3. If not see | |
19 | <http://www.gnu.org/licenses/>. */ | |
20 | ||
21 | #include "config.h" | |
22 | #include "system.h" | |
953bee7c | 23 | #include "coretypes.h" |
2adfab87 | 24 | #include "options.h" |
601d98be | 25 | #include "gfortran.h" |
071bdb5f | 26 | #include "dependency.h" |
46f19baf | 27 | #include "constructor.h" |
f1abbf69 | 28 | #include "intrinsic.h" |
601d98be TK |
29 | |
30 | /* Forward declarations. */ | |
31 | ||
32 | static void strip_function_call (gfc_expr *); | |
2bfec368 | 33 | static void optimize_namespace (gfc_namespace *); |
601d98be | 34 | static void optimize_assignment (gfc_code *); |
601d98be | 35 | static bool optimize_op (gfc_expr *); |
32af57e2 | 36 | static bool optimize_comparison (gfc_expr *, gfc_intrinsic_op); |
4afeb65c | 37 | static bool optimize_trim (gfc_expr *); |
9046a4dc | 38 | static bool optimize_lexical_comparison (gfc_expr *); |
d2663912 | 39 | static void optimize_minmaxloc (gfc_expr **); |
9771b263 | 40 | static bool is_empty_string (gfc_expr *e); |
305a35da | 41 | static void doloop_warn (gfc_namespace *); |
e81e4b43 TK |
42 | static void optimize_reduction (gfc_namespace *); |
43 | static int callback_reduction (gfc_expr **, int *, void *); | |
8b7cec58 | 44 | static void realloc_strings (gfc_namespace *); |
f1abbf69 TK |
45 | static gfc_expr *create_var (gfc_expr *, const char *vname=NULL); |
46 | static int inline_matmul_assign (gfc_code **, int *, void *); | |
47 | static gfc_code * create_do_loop (gfc_expr *, gfc_expr *, gfc_expr *, | |
7474dcc1 | 48 | locus *, gfc_namespace *, |
f1abbf69 | 49 | char *vname=NULL); |
4afeb65c TK |
50 | |
51 | /* How deep we are inside an argument list. */ | |
52 | ||
53 | static int count_arglist; | |
601d98be | 54 | |
6c7069d6 | 55 | /* Vector of gfc_expr ** we operate on. */ |
2757d5ec | 56 | |
6c7069d6 | 57 | static vec<gfc_expr **> expr_array; |
2757d5ec TK |
58 | |
59 | /* Pointer to the gfc_code we currently work on - to be able to insert | |
5a87ca71 | 60 | a block before the statement. */ |
2757d5ec TK |
61 | |
62 | static gfc_code **current_code; | |
63 | ||
5a87ca71 TK |
64 | /* Pointer to the block to be inserted, and the statement we are |
65 | changing within the block. */ | |
66 | ||
67 | static gfc_code *inserted_block, **changed_statement; | |
68 | ||
2757d5ec TK |
69 | /* The namespace we are currently dealing with. */ |
70 | ||
930d4d4e | 71 | static gfc_namespace *current_ns; |
2757d5ec | 72 | |
2855325f TK |
73 | /* If we are within any forall loop. */ |
74 | ||
75 | static int forall_level; | |
76 | ||
e07e39f6 TK |
77 | /* Keep track of whether we are within an OMP workshare. */ |
78 | ||
79 | static bool in_omp_workshare; | |
80 | ||
fd42eed8 TK |
81 | /* Keep track of whether we are within a WHERE statement. */ |
82 | ||
83 | static bool in_where; | |
84 | ||
8144d290 TK |
85 | /* Keep track of iterators for array constructors. */ |
86 | ||
87 | static int iterator_level; | |
88 | ||
305a35da TK |
89 | /* Keep track of DO loop levels. */ |
90 | ||
6c7069d6 TK |
91 | static vec<gfc_code *> doloop_list; |
92 | ||
93 | static int doloop_level; | |
305a35da TK |
94 | |
95 | /* Vector of gfc_expr * to keep track of DO loops. */ | |
96 | ||
97 | struct my_struct *evec; | |
98 | ||
e3f9e757 TK |
99 | /* Keep track of association lists. */ |
100 | ||
101 | static bool in_assoc_list; | |
102 | ||
f1abbf69 TK |
103 | /* Counter for temporary variables. */ |
104 | ||
105 | static int var_num = 1; | |
106 | ||
107 | /* What sort of matrix we are dealing with when inlining MATMUL. */ | |
108 | ||
094773e8 | 109 | enum matrix_case { none=0, A2B2, A2B1, A1B2, A2B2T }; |
f1abbf69 | 110 | |
7474dcc1 | 111 | /* Keep track of the number of expressions we have inserted so far |
f1abbf69 TK |
112 | using create_var. */ |
113 | ||
114 | int n_vars; | |
115 | ||
1cc0e193 | 116 | /* Entry point - run all passes for a namespace. */ |
601d98be TK |
117 | |
118 | void | |
2bfec368 | 119 | gfc_run_passes (gfc_namespace *ns) |
601d98be | 120 | { |
305a35da TK |
121 | |
122 | /* Warn about dubious DO loops where the index might | |
123 | change. */ | |
124 | ||
305a35da | 125 | doloop_level = 0; |
305a35da | 126 | doloop_warn (ns); |
6c7069d6 | 127 | doloop_list.release (); |
a23404c9 | 128 | int w, e; |
305a35da | 129 | |
203c7ebf | 130 | if (flag_frontend_optimize) |
1607a827 TK |
131 | { |
132 | optimize_namespace (ns); | |
e81e4b43 | 133 | optimize_reduction (ns); |
c61819ff | 134 | if (flag_dump_fortran_optimized) |
1607a827 | 135 | gfc_dump_parse_tree (ns, stdout); |
2757d5ec | 136 | |
6c7069d6 | 137 | expr_array.release (); |
1607a827 | 138 | } |
8b7cec58 | 139 | |
a23404c9 PT |
140 | gfc_get_errors (&w, &e); |
141 | if (e > 0) | |
142 | return; | |
143 | ||
8b7cec58 TK |
144 | if (flag_realloc_lhs) |
145 | realloc_strings (ns); | |
146 | } | |
147 | ||
148 | /* Callback for each gfc_code node invoked from check_realloc_strings. | |
149 | For an allocatable LHS string which also appears as a variable on | |
7474dcc1 | 150 | the RHS, replace |
8b7cec58 TK |
151 | |
152 | a = a(x:y) | |
153 | ||
154 | with | |
155 | ||
156 | tmp = a(x:y) | |
157 | a = tmp | |
158 | */ | |
159 | ||
160 | static int | |
7b201a88 | 161 | realloc_string_callback (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED, |
8b7cec58 TK |
162 | void *data ATTRIBUTE_UNUSED) |
163 | { | |
164 | gfc_expr *expr1, *expr2; | |
165 | gfc_code *co = *c; | |
166 | gfc_expr *n; | |
d6598cf7 TK |
167 | gfc_ref *ref; |
168 | bool found_substr; | |
8b7cec58 | 169 | |
8b7cec58 TK |
170 | if (co->op != EXEC_ASSIGN) |
171 | return 0; | |
172 | ||
173 | expr1 = co->expr1; | |
174 | if (expr1->ts.type != BT_CHARACTER || expr1->rank != 0 | |
d6598cf7 TK |
175 | || !gfc_expr_attr(expr1).allocatable |
176 | || !expr1->ts.deferred) | |
8b7cec58 TK |
177 | return 0; |
178 | ||
179 | expr2 = gfc_discard_nops (co->expr2); | |
180 | if (expr2->expr_type != EXPR_VARIABLE) | |
181 | return 0; | |
182 | ||
d6598cf7 TK |
183 | found_substr = false; |
184 | for (ref = expr2->ref; ref; ref = ref->next) | |
185 | { | |
186 | if (ref->type == REF_SUBSTRING) | |
187 | { | |
188 | found_substr = true; | |
189 | break; | |
190 | } | |
191 | } | |
192 | if (!found_substr) | |
193 | return 0; | |
194 | ||
8b7cec58 TK |
195 | if (!gfc_check_dependency (expr1, expr2, true)) |
196 | return 0; | |
4f028369 | 197 | |
7474dcc1 PT |
198 | /* gfc_check_dependency doesn't always pick up identical expressions. |
199 | However, eliminating the above sends the compiler into an infinite | |
200 | loop on valid expressions. Without this check, the gimplifier emits | |
201 | an ICE for a = a, where a is deferred character length. */ | |
202 | if (!gfc_dep_compare_expr (expr1, expr2)) | |
203 | return 0; | |
204 | ||
8b7cec58 | 205 | current_code = c; |
4f028369 JJ |
206 | inserted_block = NULL; |
207 | changed_statement = NULL; | |
d6598cf7 | 208 | n = create_var (expr2, "realloc_string"); |
8b7cec58 TK |
209 | co->expr2 = n; |
210 | return 0; | |
2bfec368 TK |
211 | } |
212 | ||
4d42b5cd JJ |
213 | /* Callback for each gfc_code node invoked through gfc_code_walker |
214 | from optimize_namespace. */ | |
2bfec368 | 215 | |
4d42b5cd JJ |
216 | static int |
217 | optimize_code (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED, | |
218 | void *data ATTRIBUTE_UNUSED) | |
2bfec368 | 219 | { |
4afeb65c TK |
220 | |
221 | gfc_exec_op op; | |
222 | ||
223 | op = (*c)->op; | |
224 | ||
225 | if (op == EXEC_CALL || op == EXEC_COMPCALL || op == EXEC_ASSIGN_CALL | |
226 | || op == EXEC_CALL_PPC) | |
227 | count_arglist = 1; | |
228 | else | |
229 | count_arglist = 0; | |
230 | ||
4099436d TK |
231 | current_code = c; |
232 | inserted_block = NULL; | |
233 | changed_statement = NULL; | |
234 | ||
4afeb65c | 235 | if (op == EXEC_ASSIGN) |
4d42b5cd JJ |
236 | optimize_assignment (*c); |
237 | return 0; | |
601d98be TK |
238 | } |
239 | ||
4d42b5cd JJ |
240 | /* Callback for each gfc_expr node invoked through gfc_code_walker |
241 | from optimize_namespace. */ | |
242 | ||
243 | static int | |
244 | optimize_expr (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED, | |
245 | void *data ATTRIBUTE_UNUSED) | |
601d98be | 246 | { |
4afeb65c TK |
247 | bool function_expr; |
248 | ||
249 | if ((*e)->expr_type == EXPR_FUNCTION) | |
250 | { | |
251 | count_arglist ++; | |
252 | function_expr = true; | |
253 | } | |
254 | else | |
255 | function_expr = false; | |
256 | ||
257 | if (optimize_trim (*e)) | |
258 | gfc_simplify_expr (*e, 0); | |
259 | ||
9046a4dc TK |
260 | if (optimize_lexical_comparison (*e)) |
261 | gfc_simplify_expr (*e, 0); | |
262 | ||
4d42b5cd JJ |
263 | if ((*e)->expr_type == EXPR_OP && optimize_op (*e)) |
264 | gfc_simplify_expr (*e, 0); | |
4afeb65c | 265 | |
d2663912 JJ |
266 | if ((*e)->expr_type == EXPR_FUNCTION && (*e)->value.function.isym) |
267 | switch ((*e)->value.function.isym->id) | |
268 | { | |
269 | case GFC_ISYM_MINLOC: | |
270 | case GFC_ISYM_MAXLOC: | |
271 | optimize_minmaxloc (e); | |
272 | break; | |
273 | default: | |
274 | break; | |
275 | } | |
276 | ||
4afeb65c TK |
277 | if (function_expr) |
278 | count_arglist --; | |
279 | ||
4d42b5cd | 280 | return 0; |
601d98be TK |
281 | } |
282 | ||
e81e4b43 TK |
283 | /* Auxiliary function to handle the arguments to reduction intrnisics. If the |
284 | function is a scalar, just copy it; otherwise returns the new element, the | |
285 | old one can be freed. */ | |
286 | ||
287 | static gfc_expr * | |
b91a551f | 288 | copy_walk_reduction_arg (gfc_constructor *c, gfc_expr *fn) |
e81e4b43 | 289 | { |
b91a551f | 290 | gfc_expr *fcn, *e = c->expr; |
e81e4b43 | 291 | |
b91a551f TK |
292 | fcn = gfc_copy_expr (e); |
293 | if (c->iterator) | |
294 | { | |
295 | gfc_constructor_base newbase; | |
296 | gfc_expr *new_expr; | |
297 | gfc_constructor *new_c; | |
298 | ||
299 | newbase = NULL; | |
300 | new_expr = gfc_get_expr (); | |
301 | new_expr->expr_type = EXPR_ARRAY; | |
302 | new_expr->ts = e->ts; | |
303 | new_expr->where = e->where; | |
304 | new_expr->rank = 1; | |
305 | new_c = gfc_constructor_append_expr (&newbase, fcn, &(e->where)); | |
306 | new_c->iterator = c->iterator; | |
307 | new_expr->value.constructor = newbase; | |
308 | c->iterator = NULL; | |
309 | ||
310 | fcn = new_expr; | |
311 | } | |
312 | ||
313 | if (fcn->rank != 0) | |
e81e4b43 | 314 | { |
b91a551f | 315 | gfc_isym_id id = fn->value.function.isym->id; |
e81e4b43 TK |
316 | |
317 | if (id == GFC_ISYM_SUM || id == GFC_ISYM_PRODUCT) | |
b91a551f | 318 | fcn = gfc_build_intrinsic_call (current_ns, id, |
e81e4b43 | 319 | fn->value.function.isym->name, |
b91a551f | 320 | fn->where, 3, fcn, NULL, NULL); |
e81e4b43 | 321 | else if (id == GFC_ISYM_ANY || id == GFC_ISYM_ALL) |
b91a551f | 322 | fcn = gfc_build_intrinsic_call (current_ns, id, |
e81e4b43 | 323 | fn->value.function.isym->name, |
b91a551f | 324 | fn->where, 2, fcn, NULL); |
e81e4b43 TK |
325 | else |
326 | gfc_internal_error ("Illegal id in copy_walk_reduction_arg"); | |
327 | ||
328 | fcn->symtree->n.sym->attr.access = ACCESS_PRIVATE; | |
329 | } | |
330 | ||
e81e4b43 TK |
331 | return fcn; |
332 | } | |
333 | ||
334 | /* Callback function for optimzation of reductions to scalars. Transform ANY | |
335 | ([f1,f2,f3, ...]) to f1 .or. f2 .or. f3 .or. ..., with ANY, SUM and PRODUCT | |
336 | correspondingly. Handly only the simple cases without MASK and DIM. */ | |
337 | ||
338 | static int | |
339 | callback_reduction (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED, | |
340 | void *data ATTRIBUTE_UNUSED) | |
341 | { | |
342 | gfc_expr *fn, *arg; | |
343 | gfc_intrinsic_op op; | |
344 | gfc_isym_id id; | |
345 | gfc_actual_arglist *a; | |
346 | gfc_actual_arglist *dim; | |
347 | gfc_constructor *c; | |
348 | gfc_expr *res, *new_expr; | |
349 | gfc_actual_arglist *mask; | |
350 | ||
351 | fn = *e; | |
352 | ||
353 | if (fn->rank != 0 || fn->expr_type != EXPR_FUNCTION | |
354 | || fn->value.function.isym == NULL) | |
355 | return 0; | |
356 | ||
357 | id = fn->value.function.isym->id; | |
358 | ||
359 | if (id != GFC_ISYM_SUM && id != GFC_ISYM_PRODUCT | |
360 | && id != GFC_ISYM_ANY && id != GFC_ISYM_ALL) | |
361 | return 0; | |
362 | ||
363 | a = fn->value.function.actual; | |
364 | ||
365 | /* Don't handle MASK or DIM. */ | |
366 | ||
367 | dim = a->next; | |
368 | ||
369 | if (dim->expr != NULL) | |
370 | return 0; | |
371 | ||
372 | if (id == GFC_ISYM_SUM || id == GFC_ISYM_PRODUCT) | |
373 | { | |
374 | mask = dim->next; | |
375 | if ( mask->expr != NULL) | |
376 | return 0; | |
377 | } | |
378 | ||
379 | arg = a->expr; | |
380 | ||
381 | if (arg->expr_type != EXPR_ARRAY) | |
382 | return 0; | |
383 | ||
384 | switch (id) | |
385 | { | |
386 | case GFC_ISYM_SUM: | |
387 | op = INTRINSIC_PLUS; | |
388 | break; | |
389 | ||
390 | case GFC_ISYM_PRODUCT: | |
391 | op = INTRINSIC_TIMES; | |
392 | break; | |
393 | ||
394 | case GFC_ISYM_ANY: | |
395 | op = INTRINSIC_OR; | |
396 | break; | |
397 | ||
398 | case GFC_ISYM_ALL: | |
399 | op = INTRINSIC_AND; | |
400 | break; | |
401 | ||
402 | default: | |
403 | return 0; | |
404 | } | |
405 | ||
406 | c = gfc_constructor_first (arg->value.constructor); | |
407 | ||
a2d0800a TK |
408 | /* Don't do any simplififcation if we have |
409 | - no element in the constructor or | |
410 | - only have a single element in the array which contains an | |
411 | iterator. */ | |
412 | ||
b91a551f | 413 | if (c == NULL) |
e81e4b43 TK |
414 | return 0; |
415 | ||
b91a551f | 416 | res = copy_walk_reduction_arg (c, fn); |
e81e4b43 TK |
417 | |
418 | c = gfc_constructor_next (c); | |
419 | while (c) | |
420 | { | |
421 | new_expr = gfc_get_expr (); | |
422 | new_expr->ts = fn->ts; | |
423 | new_expr->expr_type = EXPR_OP; | |
424 | new_expr->rank = fn->rank; | |
425 | new_expr->where = fn->where; | |
426 | new_expr->value.op.op = op; | |
427 | new_expr->value.op.op1 = res; | |
b91a551f | 428 | new_expr->value.op.op2 = copy_walk_reduction_arg (c, fn); |
e81e4b43 TK |
429 | res = new_expr; |
430 | c = gfc_constructor_next (c); | |
431 | } | |
432 | ||
433 | gfc_simplify_expr (res, 0); | |
434 | *e = res; | |
435 | gfc_free_expr (fn); | |
436 | ||
437 | return 0; | |
438 | } | |
2757d5ec TK |
439 | |
440 | /* Callback function for common function elimination, called from cfe_expr_0. | |
42a2717c | 441 | Put all eligible function expressions into expr_array. */ |
2757d5ec TK |
442 | |
443 | static int | |
444 | cfe_register_funcs (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED, | |
445 | void *data ATTRIBUTE_UNUSED) | |
446 | { | |
6e98bce4 | 447 | |
2757d5ec TK |
448 | if ((*e)->expr_type != EXPR_FUNCTION) |
449 | return 0; | |
450 | ||
42a2717c | 451 | /* We don't do character functions with unknown charlens. */ |
7474dcc1 | 452 | if ((*e)->ts.type == BT_CHARACTER |
42a2717c TK |
453 | && ((*e)->ts.u.cl == NULL || (*e)->ts.u.cl->length == NULL |
454 | || (*e)->ts.u.cl->length->expr_type != EXPR_CONSTANT)) | |
2757d5ec TK |
455 | return 0; |
456 | ||
2855325f TK |
457 | /* We don't do function elimination within FORALL statements, it can |
458 | lead to wrong-code in certain circumstances. */ | |
459 | ||
460 | if (forall_level > 0) | |
461 | return 0; | |
462 | ||
8144d290 TK |
463 | /* Function elimination inside an iterator could lead to functions which |
464 | depend on iterator variables being moved outside. FIXME: We should check | |
465 | if the functions do indeed depend on the iterator variable. */ | |
466 | ||
467 | if (iterator_level > 0) | |
468 | return 0; | |
469 | ||
222c2a63 TK |
470 | /* If we don't know the shape at compile time, we create an allocatable |
471 | temporary variable to hold the intermediate result, but only if | |
472 | allocation on assignment is active. */ | |
2757d5ec | 473 | |
203c7ebf | 474 | if ((*e)->rank > 0 && (*e)->shape == NULL && !flag_realloc_lhs) |
2757d5ec | 475 | return 0; |
7474dcc1 | 476 | |
2757d5ec TK |
477 | /* Skip the test for pure functions if -faggressive-function-elimination |
478 | is specified. */ | |
479 | if ((*e)->value.function.esym) | |
480 | { | |
2757d5ec TK |
481 | /* Don't create an array temporary for elemental functions. */ |
482 | if ((*e)->value.function.esym->attr.elemental && (*e)->rank > 0) | |
483 | return 0; | |
484 | ||
485 | /* Only eliminate potentially impure functions if the | |
486 | user specifically requested it. */ | |
c61819ff | 487 | if (!flag_aggressive_function_elimination |
2757d5ec TK |
488 | && !(*e)->value.function.esym->attr.pure |
489 | && !(*e)->value.function.esym->attr.implicit_pure) | |
490 | return 0; | |
491 | } | |
492 | ||
493 | if ((*e)->value.function.isym) | |
494 | { | |
495 | /* Conversions are handled on the fly by the middle end, | |
42a2717c | 496 | transpose during trans-* stages and TRANSFER by the middle end. */ |
2757d5ec | 497 | if ((*e)->value.function.isym->id == GFC_ISYM_CONVERSION |
93ee6382 MM |
498 | || (*e)->value.function.isym->id == GFC_ISYM_TRANSFER |
499 | || gfc_inline_intrinsic_function_p (*e)) | |
2757d5ec TK |
500 | return 0; |
501 | ||
502 | /* Don't create an array temporary for elemental functions, | |
503 | as this would be wasteful of memory. | |
504 | FIXME: Create a scalar temporary during scalarization. */ | |
505 | if ((*e)->value.function.isym->elemental && (*e)->rank > 0) | |
506 | return 0; | |
507 | ||
508 | if (!(*e)->value.function.isym->pure) | |
509 | return 0; | |
510 | } | |
511 | ||
6c7069d6 | 512 | expr_array.safe_push (e); |
2757d5ec TK |
513 | return 0; |
514 | } | |
515 | ||
ba8aa6fc TK |
516 | /* Auxiliary function to check if an expression is a temporary created by |
517 | create var. */ | |
518 | ||
519 | static bool | |
520 | is_fe_temp (gfc_expr *e) | |
521 | { | |
522 | if (e->expr_type != EXPR_VARIABLE) | |
523 | return false; | |
524 | ||
525 | return e->symtree->n.sym->attr.fe_temp; | |
526 | } | |
527 | ||
8b7cec58 TK |
528 | /* Determine the length of a string, if it can be evaluated as a constant |
529 | expression. Return a newly allocated gfc_expr or NULL on failure. | |
530 | If the user specified a substring which is potentially longer than | |
531 | the string itself, the string will be padded with spaces, which | |
532 | is harmless. */ | |
533 | ||
534 | static gfc_expr * | |
535 | constant_string_length (gfc_expr *e) | |
536 | { | |
537 | ||
538 | gfc_expr *length; | |
539 | gfc_ref *ref; | |
540 | gfc_expr *res; | |
541 | mpz_t value; | |
542 | ||
543 | if (e->ts.u.cl) | |
544 | { | |
545 | length = e->ts.u.cl->length; | |
546 | if (length && length->expr_type == EXPR_CONSTANT) | |
547 | return gfc_copy_expr(length); | |
548 | } | |
549 | ||
550 | /* Return length of substring, if constant. */ | |
551 | for (ref = e->ref; ref; ref = ref->next) | |
552 | { | |
553 | if (ref->type == REF_SUBSTRING | |
554 | && gfc_dep_difference (ref->u.ss.end, ref->u.ss.start, &value)) | |
555 | { | |
556 | res = gfc_get_constant_expr (BT_INTEGER, gfc_charlen_int_kind, | |
557 | &e->where); | |
7474dcc1 | 558 | |
8b7cec58 TK |
559 | mpz_add_ui (res->value.integer, value, 1); |
560 | mpz_clear (value); | |
561 | return res; | |
562 | } | |
563 | } | |
564 | ||
565 | /* Return length of char symbol, if constant. */ | |
566 | ||
567 | if (e->symtree->n.sym->ts.u.cl && e->symtree->n.sym->ts.u.cl->length | |
568 | && e->symtree->n.sym->ts.u.cl->length->expr_type == EXPR_CONSTANT) | |
569 | return gfc_copy_expr (e->symtree->n.sym->ts.u.cl->length); | |
570 | ||
571 | return NULL; | |
572 | ||
573 | } | |
ba8aa6fc | 574 | |
f1abbf69 TK |
575 | /* Insert a block at the current position unless it has already |
576 | been inserted; in this case use the one already there. */ | |
2757d5ec | 577 | |
f1abbf69 TK |
578 | static gfc_namespace* |
579 | insert_block () | |
2757d5ec | 580 | { |
5a87ca71 | 581 | gfc_namespace *ns; |
ba8aa6fc | 582 | |
5a87ca71 TK |
583 | /* If the block hasn't already been created, do so. */ |
584 | if (inserted_block == NULL) | |
585 | { | |
586 | inserted_block = XCNEW (gfc_code); | |
587 | inserted_block->op = EXEC_BLOCK; | |
588 | inserted_block->loc = (*current_code)->loc; | |
589 | ns = gfc_build_block_ns (current_ns); | |
590 | inserted_block->ext.block.ns = ns; | |
591 | inserted_block->ext.block.assoc = NULL; | |
592 | ||
593 | ns->code = *current_code; | |
3d3b8193 TK |
594 | |
595 | /* If the statement has a label, make sure it is transferred to | |
596 | the newly created block. */ | |
597 | ||
7474dcc1 | 598 | if ((*current_code)->here) |
3d3b8193 TK |
599 | { |
600 | inserted_block->here = (*current_code)->here; | |
601 | (*current_code)->here = NULL; | |
602 | } | |
603 | ||
5a87ca71 TK |
604 | inserted_block->next = (*current_code)->next; |
605 | changed_statement = &(inserted_block->ext.block.ns->code); | |
606 | (*current_code)->next = NULL; | |
607 | /* Insert the BLOCK at the right position. */ | |
608 | *current_code = inserted_block; | |
930d4d4e | 609 | ns->parent = current_ns; |
5a87ca71 TK |
610 | } |
611 | else | |
612 | ns = inserted_block->ext.block.ns; | |
613 | ||
f1abbf69 TK |
614 | return ns; |
615 | } | |
616 | ||
617 | /* Returns a new expression (a variable) to be used in place of the old one, | |
618 | with an optional assignment statement before the current statement to set | |
619 | the value of the variable. Creates a new BLOCK for the statement if that | |
620 | hasn't already been done and puts the statement, plus the newly created | |
621 | variables, in that block. Special cases: If the expression is constant or | |
622 | a temporary which has already been created, just copy it. */ | |
623 | ||
624 | static gfc_expr* | |
625 | create_var (gfc_expr * e, const char *vname) | |
626 | { | |
627 | char name[GFC_MAX_SYMBOL_LEN +1]; | |
628 | gfc_symtree *symtree; | |
629 | gfc_symbol *symbol; | |
630 | gfc_expr *result; | |
631 | gfc_code *n; | |
632 | gfc_namespace *ns; | |
633 | int i; | |
874be74a | 634 | bool deferred; |
f1abbf69 TK |
635 | |
636 | if (e->expr_type == EXPR_CONSTANT || is_fe_temp (e)) | |
637 | return gfc_copy_expr (e); | |
638 | ||
639 | ns = insert_block (); | |
640 | ||
641 | if (vname) | |
642 | snprintf (name, GFC_MAX_SYMBOL_LEN, "__var_%d_%s", var_num++, vname); | |
643 | else | |
644 | snprintf (name, GFC_MAX_SYMBOL_LEN, "__var_%d", var_num++); | |
645 | ||
5a87ca71 | 646 | if (gfc_get_sym_tree (name, ns, &symtree, false) != 0) |
2757d5ec TK |
647 | gcc_unreachable (); |
648 | ||
649 | symbol = symtree->n.sym; | |
650 | symbol->ts = e->ts; | |
222c2a63 TK |
651 | |
652 | if (e->rank > 0) | |
2757d5ec | 653 | { |
222c2a63 TK |
654 | symbol->as = gfc_get_array_spec (); |
655 | symbol->as->rank = e->rank; | |
656 | ||
657 | if (e->shape == NULL) | |
658 | { | |
659 | /* We don't know the shape at compile time, so we use an | |
1cc0e193 | 660 | allocatable. */ |
222c2a63 TK |
661 | symbol->as->type = AS_DEFERRED; |
662 | symbol->attr.allocatable = 1; | |
663 | } | |
664 | else | |
665 | { | |
666 | symbol->as->type = AS_EXPLICIT; | |
667 | /* Copy the shape. */ | |
668 | for (i=0; i<e->rank; i++) | |
669 | { | |
670 | gfc_expr *p, *q; | |
7474dcc1 | 671 | |
222c2a63 TK |
672 | p = gfc_get_constant_expr (BT_INTEGER, gfc_default_integer_kind, |
673 | &(e->where)); | |
674 | mpz_set_si (p->value.integer, 1); | |
675 | symbol->as->lower[i] = p; | |
7474dcc1 | 676 | |
222c2a63 TK |
677 | q = gfc_get_constant_expr (BT_INTEGER, gfc_index_integer_kind, |
678 | &(e->where)); | |
679 | mpz_set (q->value.integer, e->shape[i]); | |
680 | symbol->as->upper[i] = q; | |
681 | } | |
682 | } | |
2757d5ec TK |
683 | } |
684 | ||
874be74a | 685 | deferred = 0; |
8b7cec58 TK |
686 | if (e->ts.type == BT_CHARACTER && e->rank == 0) |
687 | { | |
688 | gfc_expr *length; | |
689 | ||
36b54ce0 | 690 | symbol->ts.u.cl = gfc_new_charlen (ns, NULL); |
8b7cec58 TK |
691 | length = constant_string_length (e); |
692 | if (length) | |
36b54ce0 | 693 | symbol->ts.u.cl->length = length; |
8b7cec58 | 694 | else |
874be74a TK |
695 | { |
696 | symbol->attr.allocatable = 1; | |
697 | deferred = 1; | |
698 | } | |
8b7cec58 TK |
699 | } |
700 | ||
2757d5ec TK |
701 | symbol->attr.flavor = FL_VARIABLE; |
702 | symbol->attr.referenced = 1; | |
703 | symbol->attr.dimension = e->rank > 0; | |
ba8aa6fc | 704 | symbol->attr.fe_temp = 1; |
2757d5ec TK |
705 | gfc_commit_symbol (symbol); |
706 | ||
707 | result = gfc_get_expr (); | |
708 | result->expr_type = EXPR_VARIABLE; | |
709 | result->ts = e->ts; | |
874be74a | 710 | result->ts.deferred = deferred; |
2757d5ec TK |
711 | result->rank = e->rank; |
712 | result->shape = gfc_copy_shape (e->shape, e->rank); | |
713 | result->symtree = symtree; | |
714 | result->where = e->where; | |
715 | if (e->rank > 0) | |
716 | { | |
717 | result->ref = gfc_get_ref (); | |
718 | result->ref->type = REF_ARRAY; | |
719 | result->ref->u.ar.type = AR_FULL; | |
720 | result->ref->u.ar.where = e->where; | |
f1abbf69 | 721 | result->ref->u.ar.dimen = e->rank; |
102344e2 TB |
722 | result->ref->u.ar.as = symbol->ts.type == BT_CLASS |
723 | ? CLASS_DATA (symbol)->as : symbol->as; | |
73e42eef | 724 | if (warn_array_temporaries) |
48749dbc MLI |
725 | gfc_warning (OPT_Warray_temporaries, |
726 | "Creating array temporary at %L", &(e->where)); | |
2757d5ec TK |
727 | } |
728 | ||
729 | /* Generate the new assignment. */ | |
730 | n = XCNEW (gfc_code); | |
731 | n->op = EXEC_ASSIGN; | |
732 | n->loc = (*current_code)->loc; | |
5a87ca71 | 733 | n->next = *changed_statement; |
2757d5ec TK |
734 | n->expr1 = gfc_copy_expr (result); |
735 | n->expr2 = e; | |
5a87ca71 | 736 | *changed_statement = n; |
f1abbf69 | 737 | n_vars ++; |
2757d5ec TK |
738 | |
739 | return result; | |
740 | } | |
741 | ||
51a30b32 TK |
742 | /* Warn about function elimination. */ |
743 | ||
744 | static void | |
73e42eef | 745 | do_warn_function_elimination (gfc_expr *e) |
51a30b32 TK |
746 | { |
747 | if (e->expr_type != EXPR_FUNCTION) | |
748 | return; | |
749 | if (e->value.function.esym) | |
db30e21c | 750 | gfc_warning (0, "Removing call to function %qs at %L", |
51a30b32 TK |
751 | e->value.function.esym->name, &(e->where)); |
752 | else if (e->value.function.isym) | |
db30e21c | 753 | gfc_warning (0, "Removing call to function %qs at %L", |
51a30b32 TK |
754 | e->value.function.isym->name, &(e->where)); |
755 | } | |
2757d5ec TK |
756 | /* Callback function for the code walker for doing common function |
757 | elimination. This builds up the list of functions in the expression | |
758 | and goes through them to detect duplicates, which it then replaces | |
759 | by variables. */ | |
760 | ||
761 | static int | |
762 | cfe_expr_0 (gfc_expr **e, int *walk_subtrees, | |
763 | void *data ATTRIBUTE_UNUSED) | |
764 | { | |
765 | int i,j; | |
766 | gfc_expr *newvar; | |
6c7069d6 | 767 | gfc_expr **ei, **ej; |
2757d5ec | 768 | |
49a1164a | 769 | /* Don't do this optimization within OMP workshare or ASSOC lists. */ |
e07e39f6 | 770 | |
49a1164a | 771 | if (in_omp_workshare || in_assoc_list) |
e07e39f6 TK |
772 | { |
773 | *walk_subtrees = 0; | |
774 | return 0; | |
775 | } | |
776 | ||
6c7069d6 | 777 | expr_array.release (); |
2757d5ec TK |
778 | |
779 | gfc_expr_walker (e, cfe_register_funcs, NULL); | |
780 | ||
128e09f9 TK |
781 | /* Walk through all the functions. */ |
782 | ||
6c7069d6 | 783 | FOR_EACH_VEC_ELT_FROM (expr_array, i, ei, 1) |
2757d5ec TK |
784 | { |
785 | /* Skip if the function has been replaced by a variable already. */ | |
6c7069d6 | 786 | if ((*ei)->expr_type == EXPR_VARIABLE) |
2757d5ec TK |
787 | continue; |
788 | ||
789 | newvar = NULL; | |
128e09f9 | 790 | for (j=0; j<i; j++) |
2757d5ec | 791 | { |
6c7069d6 TK |
792 | ej = expr_array[j]; |
793 | if (gfc_dep_compare_functions (*ei, *ej, true) == 0) | |
2757d5ec TK |
794 | { |
795 | if (newvar == NULL) | |
f1abbf69 | 796 | newvar = create_var (*ei, "fcn"); |
51a30b32 | 797 | |
73e42eef TB |
798 | if (warn_function_elimination) |
799 | do_warn_function_elimination (*ej); | |
51a30b32 | 800 | |
6c7069d6 TK |
801 | free (*ej); |
802 | *ej = gfc_copy_expr (newvar); | |
2757d5ec TK |
803 | } |
804 | } | |
805 | if (newvar) | |
6c7069d6 | 806 | *ei = newvar; |
2757d5ec TK |
807 | } |
808 | ||
809 | /* We did all the necessary walking in this function. */ | |
810 | *walk_subtrees = 0; | |
811 | return 0; | |
812 | } | |
813 | ||
814 | /* Callback function for common function elimination, called from | |
815 | gfc_code_walker. This keeps track of the current code, in order | |
816 | to insert statements as needed. */ | |
817 | ||
818 | static int | |
4f83d583 | 819 | cfe_code (gfc_code **c, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) |
2757d5ec TK |
820 | { |
821 | current_code = c; | |
5a87ca71 TK |
822 | inserted_block = NULL; |
823 | changed_statement = NULL; | |
4f83d583 TK |
824 | |
825 | /* Do not do anything inside a WHERE statement; scalar assignments, BLOCKs | |
826 | and allocation on assigment are prohibited inside WHERE, and finally | |
827 | masking an expression would lead to wrong-code when replacing | |
828 | ||
829 | WHERE (a>0) | |
830 | b = sum(foo(a) + foo(a)) | |
831 | END WHERE | |
832 | ||
833 | with | |
834 | ||
835 | WHERE (a > 0) | |
836 | tmp = foo(a) | |
837 | b = sum(tmp + tmp) | |
838 | END WHERE | |
839 | */ | |
840 | ||
841 | if ((*c)->op == EXEC_WHERE) | |
842 | { | |
843 | *walk_subtrees = 0; | |
844 | return 0; | |
845 | } | |
7474dcc1 | 846 | |
4f83d583 | 847 | |
2757d5ec TK |
848 | return 0; |
849 | } | |
850 | ||
fa11ae6c TK |
851 | /* Dummy function for expression call back, for use when we |
852 | really don't want to do any walking. */ | |
853 | ||
854 | static int | |
855 | dummy_expr_callback (gfc_expr **e ATTRIBUTE_UNUSED, int *walk_subtrees, | |
856 | void *data ATTRIBUTE_UNUSED) | |
857 | { | |
858 | *walk_subtrees = 0; | |
859 | return 0; | |
860 | } | |
861 | ||
e81e4b43 TK |
862 | /* Dummy function for code callback, for use when we really |
863 | don't want to do anything. */ | |
5f23671d JJ |
864 | int |
865 | gfc_dummy_code_callback (gfc_code **e ATTRIBUTE_UNUSED, | |
866 | int *walk_subtrees ATTRIBUTE_UNUSED, | |
867 | void *data ATTRIBUTE_UNUSED) | |
e81e4b43 TK |
868 | { |
869 | return 0; | |
870 | } | |
871 | ||
fa11ae6c TK |
872 | /* Code callback function for converting |
873 | do while(a) | |
874 | end do | |
875 | into the equivalent | |
876 | do | |
877 | if (.not. a) exit | |
878 | end do | |
879 | This is because common function elimination would otherwise place the | |
880 | temporary variables outside the loop. */ | |
881 | ||
882 | static int | |
883 | convert_do_while (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED, | |
884 | void *data ATTRIBUTE_UNUSED) | |
885 | { | |
886 | gfc_code *co = *c; | |
887 | gfc_code *c_if1, *c_if2, *c_exit; | |
888 | gfc_code *loopblock; | |
889 | gfc_expr *e_not, *e_cond; | |
890 | ||
891 | if (co->op != EXEC_DO_WHILE) | |
892 | return 0; | |
893 | ||
894 | if (co->expr1 == NULL || co->expr1->expr_type == EXPR_CONSTANT) | |
895 | return 0; | |
896 | ||
897 | e_cond = co->expr1; | |
898 | ||
899 | /* Generate the condition of the if statement, which is .not. the original | |
900 | statement. */ | |
901 | e_not = gfc_get_expr (); | |
902 | e_not->ts = e_cond->ts; | |
903 | e_not->where = e_cond->where; | |
904 | e_not->expr_type = EXPR_OP; | |
905 | e_not->value.op.op = INTRINSIC_NOT; | |
906 | e_not->value.op.op1 = e_cond; | |
907 | ||
908 | /* Generate the EXIT statement. */ | |
909 | c_exit = XCNEW (gfc_code); | |
910 | c_exit->op = EXEC_EXIT; | |
911 | c_exit->ext.which_construct = co; | |
912 | c_exit->loc = co->loc; | |
913 | ||
914 | /* Generate the IF statement. */ | |
915 | c_if2 = XCNEW (gfc_code); | |
916 | c_if2->op = EXEC_IF; | |
917 | c_if2->expr1 = e_not; | |
918 | c_if2->next = c_exit; | |
919 | c_if2->loc = co->loc; | |
920 | ||
921 | /* ... plus the one to chain it to. */ | |
922 | c_if1 = XCNEW (gfc_code); | |
923 | c_if1->op = EXEC_IF; | |
924 | c_if1->block = c_if2; | |
925 | c_if1->loc = co->loc; | |
926 | ||
927 | /* Make the DO WHILE loop into a DO block by replacing the condition | |
928 | with a true constant. */ | |
929 | co->expr1 = gfc_get_logical_expr (gfc_default_integer_kind, &co->loc, true); | |
930 | ||
931 | /* Hang the generated if statement into the loop body. */ | |
932 | ||
933 | loopblock = co->block->next; | |
934 | co->block->next = c_if1; | |
935 | c_if1->next = loopblock; | |
936 | ||
937 | return 0; | |
938 | } | |
939 | ||
cf82db16 TK |
940 | /* Code callback function for converting |
941 | if (a) then | |
942 | ... | |
943 | else if (b) then | |
944 | end if | |
945 | ||
946 | into | |
947 | if (a) then | |
948 | else | |
949 | if (b) then | |
950 | end if | |
951 | end if | |
952 | ||
953 | because otherwise common function elimination would place the BLOCKs | |
954 | into the wrong place. */ | |
955 | ||
956 | static int | |
957 | convert_elseif (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED, | |
958 | void *data ATTRIBUTE_UNUSED) | |
959 | { | |
960 | gfc_code *co = *c; | |
961 | gfc_code *c_if1, *c_if2, *else_stmt; | |
962 | ||
963 | if (co->op != EXEC_IF) | |
964 | return 0; | |
965 | ||
966 | /* This loop starts out with the first ELSE statement. */ | |
967 | else_stmt = co->block->block; | |
968 | ||
969 | while (else_stmt != NULL) | |
970 | { | |
971 | gfc_code *next_else; | |
972 | ||
973 | /* If there is no condition, we're done. */ | |
974 | if (else_stmt->expr1 == NULL) | |
975 | break; | |
976 | ||
977 | next_else = else_stmt->block; | |
978 | ||
979 | /* Generate the new IF statement. */ | |
980 | c_if2 = XCNEW (gfc_code); | |
981 | c_if2->op = EXEC_IF; | |
982 | c_if2->expr1 = else_stmt->expr1; | |
983 | c_if2->next = else_stmt->next; | |
984 | c_if2->loc = else_stmt->loc; | |
985 | c_if2->block = next_else; | |
986 | ||
987 | /* ... plus the one to chain it to. */ | |
988 | c_if1 = XCNEW (gfc_code); | |
989 | c_if1->op = EXEC_IF; | |
990 | c_if1->block = c_if2; | |
991 | c_if1->loc = else_stmt->loc; | |
992 | ||
993 | /* Insert the new IF after the ELSE. */ | |
994 | else_stmt->expr1 = NULL; | |
995 | else_stmt->next = c_if1; | |
996 | else_stmt->block = NULL; | |
997 | ||
998 | else_stmt = next_else; | |
999 | } | |
1000 | /* Don't walk subtrees. */ | |
1001 | return 0; | |
1002 | } | |
f1abbf69 | 1003 | |
4d42b5cd | 1004 | /* Optimize a namespace, including all contained namespaces. */ |
601d98be TK |
1005 | |
1006 | static void | |
4d42b5cd | 1007 | optimize_namespace (gfc_namespace *ns) |
601d98be | 1008 | { |
f1abbf69 | 1009 | gfc_namespace *saved_ns = gfc_current_ns; |
2757d5ec | 1010 | current_ns = ns; |
f1abbf69 | 1011 | gfc_current_ns = ns; |
2855325f | 1012 | forall_level = 0; |
8144d290 | 1013 | iterator_level = 0; |
e3f9e757 | 1014 | in_assoc_list = false; |
e07e39f6 | 1015 | in_omp_workshare = false; |
2757d5ec | 1016 | |
fa11ae6c | 1017 | gfc_code_walker (&ns->code, convert_do_while, dummy_expr_callback, NULL); |
cf82db16 | 1018 | gfc_code_walker (&ns->code, convert_elseif, dummy_expr_callback, NULL); |
2757d5ec | 1019 | gfc_code_walker (&ns->code, cfe_code, cfe_expr_0, NULL); |
4d42b5cd | 1020 | gfc_code_walker (&ns->code, optimize_code, optimize_expr, NULL); |
f1abbf69 TK |
1021 | if (flag_inline_matmul_limit != 0) |
1022 | gfc_code_walker (&ns->code, inline_matmul_assign, dummy_expr_callback, | |
1023 | NULL); | |
601d98be | 1024 | |
930d4d4e | 1025 | /* BLOCKs are handled in the expression walker below. */ |
4d42b5cd | 1026 | for (ns = ns->contained; ns; ns = ns->sibling) |
930d4d4e TK |
1027 | { |
1028 | if (ns->code == NULL || ns->code->op != EXEC_BLOCK) | |
1029 | optimize_namespace (ns); | |
1030 | } | |
f1abbf69 | 1031 | gfc_current_ns = saved_ns; |
601d98be TK |
1032 | } |
1033 | ||
8b7cec58 TK |
1034 | /* Handle dependencies for allocatable strings which potentially redefine |
1035 | themselves in an assignment. */ | |
1036 | ||
1037 | static void | |
1038 | realloc_strings (gfc_namespace *ns) | |
1039 | { | |
1040 | current_ns = ns; | |
1041 | gfc_code_walker (&ns->code, realloc_string_callback, dummy_expr_callback, NULL); | |
1042 | ||
1043 | for (ns = ns->contained; ns; ns = ns->sibling) | |
1044 | { | |
1045 | if (ns->code == NULL || ns->code->op != EXEC_BLOCK) | |
f1abbf69 | 1046 | realloc_strings (ns); |
8b7cec58 TK |
1047 | } |
1048 | ||
1049 | } | |
1050 | ||
e81e4b43 TK |
1051 | static void |
1052 | optimize_reduction (gfc_namespace *ns) | |
1053 | { | |
1054 | current_ns = ns; | |
5f23671d JJ |
1055 | gfc_code_walker (&ns->code, gfc_dummy_code_callback, |
1056 | callback_reduction, NULL); | |
e81e4b43 TK |
1057 | |
1058 | /* BLOCKs are handled in the expression walker below. */ | |
1059 | for (ns = ns->contained; ns; ns = ns->sibling) | |
1060 | { | |
1061 | if (ns->code == NULL || ns->code->op != EXEC_BLOCK) | |
1062 | optimize_reduction (ns); | |
1063 | } | |
1064 | } | |
1065 | ||
5c599206 TK |
1066 | /* Replace code like |
1067 | a = matmul(b,c) + d | |
1068 | with | |
1069 | a = matmul(b,c) ; a = a + d | |
1070 | where the array function is not elemental and not allocatable | |
1071 | and does not depend on the left-hand side. | |
1072 | */ | |
1073 | ||
1074 | static bool | |
1075 | optimize_binop_array_assignment (gfc_code *c, gfc_expr **rhs, bool seen_op) | |
1076 | { | |
1077 | gfc_expr *e; | |
1078 | ||
f1c7e7f1 SK |
1079 | if (!*rhs) |
1080 | return false; | |
1081 | ||
5c599206 TK |
1082 | e = *rhs; |
1083 | if (e->expr_type == EXPR_OP) | |
1084 | { | |
1085 | switch (e->value.op.op) | |
1086 | { | |
1087 | /* Unary operators and exponentiation: Only look at a single | |
1088 | operand. */ | |
1089 | case INTRINSIC_NOT: | |
1090 | case INTRINSIC_UPLUS: | |
1091 | case INTRINSIC_UMINUS: | |
1092 | case INTRINSIC_PARENTHESES: | |
1093 | case INTRINSIC_POWER: | |
1094 | if (optimize_binop_array_assignment (c, &e->value.op.op1, seen_op)) | |
1095 | return true; | |
1096 | break; | |
1097 | ||
dc2c36fd TK |
1098 | case INTRINSIC_CONCAT: |
1099 | /* Do not do string concatenations. */ | |
1100 | break; | |
1101 | ||
5c599206 TK |
1102 | default: |
1103 | /* Binary operators. */ | |
1104 | if (optimize_binop_array_assignment (c, &e->value.op.op1, true)) | |
1105 | return true; | |
1106 | ||
1107 | if (optimize_binop_array_assignment (c, &e->value.op.op2, true)) | |
1108 | return true; | |
1109 | ||
1110 | break; | |
1111 | } | |
1112 | } | |
1113 | else if (seen_op && e->expr_type == EXPR_FUNCTION && e->rank > 0 | |
7474dcc1 PT |
1114 | && ! (e->value.function.esym |
1115 | && (e->value.function.esym->attr.elemental | |
962b8a0e TK |
1116 | || e->value.function.esym->attr.allocatable |
1117 | || e->value.function.esym->ts.type != c->expr1->ts.type | |
1118 | || e->value.function.esym->ts.kind != c->expr1->ts.kind)) | |
1119 | && ! (e->value.function.isym | |
1120 | && (e->value.function.isym->elemental | |
1121 | || e->ts.type != c->expr1->ts.type | |
93ee6382 MM |
1122 | || e->ts.kind != c->expr1->ts.kind)) |
1123 | && ! gfc_inline_intrinsic_function_p (e)) | |
5c599206 TK |
1124 | { |
1125 | ||
1126 | gfc_code *n; | |
1127 | gfc_expr *new_expr; | |
1128 | ||
1129 | /* Insert a new assignment statement after the current one. */ | |
1130 | n = XCNEW (gfc_code); | |
1131 | n->op = EXEC_ASSIGN; | |
1132 | n->loc = c->loc; | |
1133 | n->next = c->next; | |
1134 | c->next = n; | |
1135 | ||
1136 | n->expr1 = gfc_copy_expr (c->expr1); | |
1137 | n->expr2 = c->expr2; | |
1138 | new_expr = gfc_copy_expr (c->expr1); | |
1139 | c->expr2 = e; | |
1140 | *rhs = new_expr; | |
7474dcc1 | 1141 | |
5c599206 TK |
1142 | return true; |
1143 | ||
1144 | } | |
1145 | ||
1146 | /* Nothing to optimize. */ | |
1147 | return false; | |
1148 | } | |
1149 | ||
4f21f0da TK |
1150 | /* Remove unneeded TRIMs at the end of expressions. */ |
1151 | ||
1152 | static bool | |
1153 | remove_trim (gfc_expr *rhs) | |
1154 | { | |
1155 | bool ret; | |
1156 | ||
1157 | ret = false; | |
e5cf1629 SK |
1158 | if (!rhs) |
1159 | return ret; | |
4f21f0da TK |
1160 | |
1161 | /* Check for a // b // trim(c). Looping is probably not | |
1162 | necessary because the parser usually generates | |
1163 | (// (// a b ) trim(c) ) , but better safe than sorry. */ | |
1164 | ||
1165 | while (rhs->expr_type == EXPR_OP | |
1166 | && rhs->value.op.op == INTRINSIC_CONCAT) | |
1167 | rhs = rhs->value.op.op2; | |
1168 | ||
1169 | while (rhs->expr_type == EXPR_FUNCTION && rhs->value.function.isym | |
1170 | && rhs->value.function.isym->id == GFC_ISYM_TRIM) | |
1171 | { | |
1172 | strip_function_call (rhs); | |
1173 | /* Recursive call to catch silly stuff like trim ( a // trim(b)). */ | |
1174 | remove_trim (rhs); | |
1175 | ret = true; | |
1176 | } | |
1177 | ||
1178 | return ret; | |
1179 | } | |
1180 | ||
601d98be TK |
1181 | /* Optimizations for an assignment. */ |
1182 | ||
1183 | static void | |
1184 | optimize_assignment (gfc_code * c) | |
1185 | { | |
1186 | gfc_expr *lhs, *rhs; | |
1187 | ||
1188 | lhs = c->expr1; | |
1189 | rhs = c->expr2; | |
1190 | ||
0f6bfefd | 1191 | if (lhs->ts.type == BT_CHARACTER && !lhs->ts.deferred) |
94d145bf | 1192 | { |
0f6bfefd | 1193 | /* Optimize a = trim(b) to a = b. */ |
94d145bf TK |
1194 | remove_trim (rhs); |
1195 | ||
0f6bfefd | 1196 | /* Replace a = ' ' by a = '' to optimize away a memcpy. */ |
524af0d6 | 1197 | if (is_empty_string (rhs)) |
94d145bf TK |
1198 | rhs->value.character.length = 0; |
1199 | } | |
601d98be | 1200 | |
5c599206 TK |
1201 | if (lhs->rank > 0 && gfc_check_dependency (lhs, rhs, true) == 0) |
1202 | optimize_binop_array_assignment (c, &rhs, false); | |
601d98be TK |
1203 | } |
1204 | ||
1205 | ||
1206 | /* Remove an unneeded function call, modifying the expression. | |
1207 | This replaces the function call with the value of its | |
1208 | first argument. The rest of the argument list is freed. */ | |
1209 | ||
1210 | static void | |
1211 | strip_function_call (gfc_expr *e) | |
1212 | { | |
1213 | gfc_expr *e1; | |
1214 | gfc_actual_arglist *a; | |
1215 | ||
1216 | a = e->value.function.actual; | |
1217 | ||
1218 | /* We should have at least one argument. */ | |
1219 | gcc_assert (a->expr != NULL); | |
1220 | ||
1221 | e1 = a->expr; | |
1222 | ||
1223 | /* Free the remaining arglist, if any. */ | |
1224 | if (a->next) | |
1225 | gfc_free_actual_arglist (a->next); | |
1226 | ||
1227 | /* Graft the argument expression onto the original function. */ | |
1228 | *e = *e1; | |
cede9502 | 1229 | free (e1); |
601d98be TK |
1230 | |
1231 | } | |
1232 | ||
9046a4dc TK |
1233 | /* Optimization of lexical comparison functions. */ |
1234 | ||
1235 | static bool | |
1236 | optimize_lexical_comparison (gfc_expr *e) | |
1237 | { | |
1238 | if (e->expr_type != EXPR_FUNCTION || e->value.function.isym == NULL) | |
1239 | return false; | |
1240 | ||
1241 | switch (e->value.function.isym->id) | |
1242 | { | |
1243 | case GFC_ISYM_LLE: | |
1244 | return optimize_comparison (e, INTRINSIC_LE); | |
1245 | ||
1246 | case GFC_ISYM_LGE: | |
1247 | return optimize_comparison (e, INTRINSIC_GE); | |
1248 | ||
1249 | case GFC_ISYM_LGT: | |
1250 | return optimize_comparison (e, INTRINSIC_GT); | |
1251 | ||
1252 | case GFC_ISYM_LLT: | |
1253 | return optimize_comparison (e, INTRINSIC_LT); | |
1254 | ||
1255 | default: | |
1256 | break; | |
1257 | } | |
1258 | return false; | |
1259 | } | |
1260 | ||
4099436d TK |
1261 | /* Combine stuff like [a]>b into [a>b], for easier optimization later. Do not |
1262 | do CHARACTER because of possible pessimization involving character | |
1263 | lengths. */ | |
1264 | ||
1265 | static bool | |
1266 | combine_array_constructor (gfc_expr *e) | |
1267 | { | |
1268 | ||
1269 | gfc_expr *op1, *op2; | |
1270 | gfc_expr *scalar; | |
1271 | gfc_expr *new_expr; | |
1272 | gfc_constructor *c, *new_c; | |
1273 | gfc_constructor_base oldbase, newbase; | |
1274 | bool scalar_first; | |
1275 | ||
1276 | /* Array constructors have rank one. */ | |
1277 | if (e->rank != 1) | |
1278 | return false; | |
1279 | ||
e3f9e757 TK |
1280 | /* Don't try to combine association lists, this makes no sense |
1281 | and leads to an ICE. */ | |
1282 | if (in_assoc_list) | |
1283 | return false; | |
1284 | ||
9c3e121b TK |
1285 | /* With FORALL, the BLOCKS created by create_var will cause an ICE. */ |
1286 | if (forall_level > 0) | |
1287 | return false; | |
1288 | ||
1603ebe0 TK |
1289 | /* Inside an iterator, things can get hairy; we are likely to create |
1290 | an invalid temporary variable. */ | |
1291 | if (iterator_level > 0) | |
1292 | return false; | |
1293 | ||
4099436d TK |
1294 | op1 = e->value.op.op1; |
1295 | op2 = e->value.op.op2; | |
1296 | ||
e5cf1629 SK |
1297 | if (!op1 || !op2) |
1298 | return false; | |
1299 | ||
4099436d TK |
1300 | if (op1->expr_type == EXPR_ARRAY && op2->rank == 0) |
1301 | scalar_first = false; | |
1302 | else if (op2->expr_type == EXPR_ARRAY && op1->rank == 0) | |
1303 | { | |
1304 | scalar_first = true; | |
1305 | op1 = e->value.op.op2; | |
1306 | op2 = e->value.op.op1; | |
1307 | } | |
1308 | else | |
1309 | return false; | |
1310 | ||
1311 | if (op2->ts.type == BT_CHARACTER) | |
1312 | return false; | |
1313 | ||
f1abbf69 | 1314 | scalar = create_var (gfc_copy_expr (op2), "constr"); |
4099436d TK |
1315 | |
1316 | oldbase = op1->value.constructor; | |
1317 | newbase = NULL; | |
1318 | e->expr_type = EXPR_ARRAY; | |
1319 | ||
4099436d TK |
1320 | for (c = gfc_constructor_first (oldbase); c; |
1321 | c = gfc_constructor_next (c)) | |
1322 | { | |
1323 | new_expr = gfc_get_expr (); | |
1324 | new_expr->ts = e->ts; | |
1325 | new_expr->expr_type = EXPR_OP; | |
1326 | new_expr->rank = c->expr->rank; | |
1327 | new_expr->where = c->where; | |
1328 | new_expr->value.op.op = e->value.op.op; | |
1329 | ||
1330 | if (scalar_first) | |
1331 | { | |
1332 | new_expr->value.op.op1 = gfc_copy_expr (scalar); | |
1333 | new_expr->value.op.op2 = gfc_copy_expr (c->expr); | |
1334 | } | |
1335 | else | |
1336 | { | |
1337 | new_expr->value.op.op1 = gfc_copy_expr (c->expr); | |
1338 | new_expr->value.op.op2 = gfc_copy_expr (scalar); | |
1339 | } | |
1340 | ||
1341 | new_c = gfc_constructor_append_expr (&newbase, new_expr, &(e->where)); | |
1342 | new_c->iterator = c->iterator; | |
1343 | c->iterator = NULL; | |
1344 | } | |
1345 | ||
1346 | gfc_free_expr (op1); | |
1347 | gfc_free_expr (op2); | |
36abe895 | 1348 | gfc_free_expr (scalar); |
4099436d TK |
1349 | |
1350 | e->value.constructor = newbase; | |
1351 | return true; | |
1352 | } | |
1353 | ||
0de1e4a6 TK |
1354 | /* Change (-1)**k into 1-ishift(iand(k,1),1) and |
1355 | 2**k into ishift(1,k) */ | |
1356 | ||
1357 | static bool | |
1358 | optimize_power (gfc_expr *e) | |
1359 | { | |
1360 | gfc_expr *op1, *op2; | |
1361 | gfc_expr *iand, *ishft; | |
1362 | ||
1363 | if (e->ts.type != BT_INTEGER) | |
1364 | return false; | |
1365 | ||
1366 | op1 = e->value.op.op1; | |
1367 | ||
1368 | if (op1 == NULL || op1->expr_type != EXPR_CONSTANT) | |
1369 | return false; | |
1370 | ||
1371 | if (mpz_cmp_si (op1->value.integer, -1L) == 0) | |
1372 | { | |
1373 | gfc_free_expr (op1); | |
1374 | ||
1375 | op2 = e->value.op.op2; | |
1376 | ||
1377 | if (op2 == NULL) | |
1378 | return false; | |
1379 | ||
1380 | iand = gfc_build_intrinsic_call (current_ns, GFC_ISYM_IAND, | |
1381 | "_internal_iand", e->where, 2, op2, | |
1382 | gfc_get_int_expr (e->ts.kind, | |
1383 | &e->where, 1)); | |
7474dcc1 | 1384 | |
0de1e4a6 TK |
1385 | ishft = gfc_build_intrinsic_call (current_ns, GFC_ISYM_ISHFT, |
1386 | "_internal_ishft", e->where, 2, iand, | |
1387 | gfc_get_int_expr (e->ts.kind, | |
1388 | &e->where, 1)); | |
1389 | ||
1390 | e->value.op.op = INTRINSIC_MINUS; | |
1391 | e->value.op.op1 = gfc_get_int_expr (e->ts.kind, &e->where, 1); | |
1392 | e->value.op.op2 = ishft; | |
1393 | return true; | |
1394 | } | |
1395 | else if (mpz_cmp_si (op1->value.integer, 2L) == 0) | |
1396 | { | |
1397 | gfc_free_expr (op1); | |
1398 | ||
1399 | op2 = e->value.op.op2; | |
1400 | if (op2 == NULL) | |
1401 | return false; | |
1402 | ||
1403 | ishft = gfc_build_intrinsic_call (current_ns, GFC_ISYM_ISHFT, | |
1404 | "_internal_ishft", e->where, 2, | |
1405 | gfc_get_int_expr (e->ts.kind, | |
1406 | &e->where, 1), | |
1407 | op2); | |
1408 | *e = *ishft; | |
1409 | return true; | |
1410 | } | |
068b04fe TK |
1411 | |
1412 | else if (mpz_cmp_si (op1->value.integer, 1L) == 0) | |
1413 | { | |
1414 | op2 = e->value.op.op2; | |
1415 | if (op2 == NULL) | |
1416 | return false; | |
1417 | ||
1418 | gfc_free_expr (op1); | |
1419 | gfc_free_expr (op2); | |
1420 | ||
1421 | e->expr_type = EXPR_CONSTANT; | |
1422 | e->value.op.op1 = NULL; | |
1423 | e->value.op.op2 = NULL; | |
1424 | mpz_init_set_si (e->value.integer, 1); | |
e1e14947 | 1425 | /* Typespec and location are still OK. */ |
068b04fe TK |
1426 | return true; |
1427 | } | |
1428 | ||
0de1e4a6 TK |
1429 | return false; |
1430 | } | |
4099436d | 1431 | |
601d98be TK |
1432 | /* Recursive optimization of operators. */ |
1433 | ||
1434 | static bool | |
1435 | optimize_op (gfc_expr *e) | |
1436 | { | |
4099436d TK |
1437 | bool changed; |
1438 | ||
4d42b5cd | 1439 | gfc_intrinsic_op op = e->value.op.op; |
601d98be | 1440 | |
4099436d TK |
1441 | changed = false; |
1442 | ||
eea58adb | 1443 | /* Only use new-style comparisons. */ |
91077d4e TK |
1444 | switch(op) |
1445 | { | |
1446 | case INTRINSIC_EQ_OS: | |
1447 | op = INTRINSIC_EQ; | |
1448 | break; | |
1449 | ||
1450 | case INTRINSIC_GE_OS: | |
1451 | op = INTRINSIC_GE; | |
1452 | break; | |
1453 | ||
1454 | case INTRINSIC_LE_OS: | |
1455 | op = INTRINSIC_LE; | |
1456 | break; | |
1457 | ||
1458 | case INTRINSIC_NE_OS: | |
1459 | op = INTRINSIC_NE; | |
1460 | break; | |
1461 | ||
1462 | case INTRINSIC_GT_OS: | |
1463 | op = INTRINSIC_GT; | |
1464 | break; | |
1465 | ||
1466 | case INTRINSIC_LT_OS: | |
1467 | op = INTRINSIC_LT; | |
1468 | break; | |
1469 | ||
1470 | default: | |
1471 | break; | |
1472 | } | |
1473 | ||
601d98be TK |
1474 | switch (op) |
1475 | { | |
1476 | case INTRINSIC_EQ: | |
601d98be | 1477 | case INTRINSIC_GE: |
601d98be | 1478 | case INTRINSIC_LE: |
601d98be | 1479 | case INTRINSIC_NE: |
601d98be | 1480 | case INTRINSIC_GT: |
601d98be | 1481 | case INTRINSIC_LT: |
4099436d TK |
1482 | changed = optimize_comparison (e, op); |
1483 | ||
81fea426 | 1484 | gcc_fallthrough (); |
4099436d TK |
1485 | /* Look at array constructors. */ |
1486 | case INTRINSIC_PLUS: | |
1487 | case INTRINSIC_MINUS: | |
1488 | case INTRINSIC_TIMES: | |
1489 | case INTRINSIC_DIVIDE: | |
1490 | return combine_array_constructor (e) || changed; | |
601d98be | 1491 | |
0de1e4a6 TK |
1492 | case INTRINSIC_POWER: |
1493 | return optimize_power (e); | |
1494 | break; | |
1495 | ||
601d98be TK |
1496 | default: |
1497 | break; | |
1498 | } | |
1499 | ||
1500 | return false; | |
1501 | } | |
1502 | ||
91077d4e TK |
1503 | |
1504 | /* Return true if a constant string contains only blanks. */ | |
1505 | ||
1506 | static bool | |
9771b263 | 1507 | is_empty_string (gfc_expr *e) |
91077d4e TK |
1508 | { |
1509 | int i; | |
1510 | ||
1511 | if (e->ts.type != BT_CHARACTER || e->expr_type != EXPR_CONSTANT) | |
1512 | return false; | |
1513 | ||
1514 | for (i=0; i < e->value.character.length; i++) | |
1515 | { | |
1516 | if (e->value.character.string[i] != ' ') | |
1517 | return false; | |
1518 | } | |
1519 | ||
1520 | return true; | |
1521 | } | |
1522 | ||
1523 | ||
1524 | /* Insert a call to the intrinsic len_trim. Use a different name for | |
1525 | the symbol tree so we don't run into trouble when the user has | |
1526 | renamed len_trim for some reason. */ | |
1527 | ||
1528 | static gfc_expr* | |
1529 | get_len_trim_call (gfc_expr *str, int kind) | |
1530 | { | |
1531 | gfc_expr *fcn; | |
1532 | gfc_actual_arglist *actual_arglist, *next; | |
1533 | ||
1534 | fcn = gfc_get_expr (); | |
1535 | fcn->expr_type = EXPR_FUNCTION; | |
1536 | fcn->value.function.isym = gfc_intrinsic_function_by_id (GFC_ISYM_LEN_TRIM); | |
1537 | actual_arglist = gfc_get_actual_arglist (); | |
1538 | actual_arglist->expr = str; | |
1539 | next = gfc_get_actual_arglist (); | |
1540 | next->expr = gfc_get_int_expr (gfc_default_integer_kind, NULL, kind); | |
1541 | actual_arglist->next = next; | |
1542 | ||
1543 | fcn->value.function.actual = actual_arglist; | |
1544 | fcn->where = str->where; | |
1545 | fcn->ts.type = BT_INTEGER; | |
1546 | fcn->ts.kind = gfc_charlen_int_kind; | |
1547 | ||
1548 | gfc_get_sym_tree ("__internal_len_trim", current_ns, &fcn->symtree, false); | |
1549 | fcn->symtree->n.sym->ts = fcn->ts; | |
1550 | fcn->symtree->n.sym->attr.flavor = FL_PROCEDURE; | |
1551 | fcn->symtree->n.sym->attr.function = 1; | |
1552 | fcn->symtree->n.sym->attr.elemental = 1; | |
1553 | fcn->symtree->n.sym->attr.referenced = 1; | |
1554 | fcn->symtree->n.sym->attr.access = ACCESS_PRIVATE; | |
1555 | gfc_commit_symbol (fcn->symtree->n.sym); | |
1556 | ||
1557 | return fcn; | |
1558 | } | |
1559 | ||
601d98be TK |
1560 | /* Optimize expressions for equality. */ |
1561 | ||
1562 | static bool | |
32af57e2 | 1563 | optimize_comparison (gfc_expr *e, gfc_intrinsic_op op) |
601d98be | 1564 | { |
601d98be TK |
1565 | gfc_expr *op1, *op2; |
1566 | bool change; | |
32af57e2 TK |
1567 | int eq; |
1568 | bool result; | |
9046a4dc | 1569 | gfc_actual_arglist *firstarg, *secondarg; |
601d98be | 1570 | |
9046a4dc TK |
1571 | if (e->expr_type == EXPR_OP) |
1572 | { | |
1573 | firstarg = NULL; | |
1574 | secondarg = NULL; | |
1575 | op1 = e->value.op.op1; | |
1576 | op2 = e->value.op.op2; | |
1577 | } | |
1578 | else if (e->expr_type == EXPR_FUNCTION) | |
1579 | { | |
eea58adb | 1580 | /* One of the lexical comparison functions. */ |
9046a4dc TK |
1581 | firstarg = e->value.function.actual; |
1582 | secondarg = firstarg->next; | |
1583 | op1 = firstarg->expr; | |
1584 | op2 = secondarg->expr; | |
1585 | } | |
1586 | else | |
1587 | gcc_unreachable (); | |
601d98be TK |
1588 | |
1589 | /* Strip off unneeded TRIM calls from string comparisons. */ | |
1590 | ||
4f21f0da | 1591 | change = remove_trim (op1); |
601d98be | 1592 | |
4f21f0da TK |
1593 | if (remove_trim (op2)) |
1594 | change = true; | |
601d98be | 1595 | |
c0d15a77 MM |
1596 | /* An expression of type EXPR_CONSTANT is only valid for scalars. */ |
1597 | /* TODO: A scalar constant may be acceptable in some cases (the scalarizer | |
1598 | handles them well). However, there are also cases that need a non-scalar | |
1599 | argument. For example the any intrinsic. See PR 45380. */ | |
1600 | if (e->rank > 0) | |
4f21f0da | 1601 | return change; |
c0d15a77 | 1602 | |
91077d4e TK |
1603 | /* Replace a == '' with len_trim(a) == 0 and a /= '' with |
1604 | len_trim(a) != 0 */ | |
1605 | if (op1->ts.type == BT_CHARACTER && op2->ts.type == BT_CHARACTER | |
1606 | && (op == INTRINSIC_EQ || op == INTRINSIC_NE)) | |
1607 | { | |
1608 | bool empty_op1, empty_op2; | |
9771b263 DN |
1609 | empty_op1 = is_empty_string (op1); |
1610 | empty_op2 = is_empty_string (op2); | |
91077d4e TK |
1611 | |
1612 | if (empty_op1 || empty_op2) | |
1613 | { | |
1614 | gfc_expr *fcn; | |
1615 | gfc_expr *zero; | |
1616 | gfc_expr *str; | |
1617 | ||
1618 | /* This can only happen when an error for comparing | |
1619 | characters of different kinds has already been issued. */ | |
1620 | if (empty_op1 && empty_op2) | |
1621 | return false; | |
1622 | ||
1623 | zero = gfc_get_int_expr (gfc_charlen_int_kind, &e->where, 0); | |
1624 | str = empty_op1 ? op2 : op1; | |
1625 | ||
1626 | fcn = get_len_trim_call (str, gfc_charlen_int_kind); | |
1627 | ||
1628 | ||
1629 | if (empty_op1) | |
1630 | gfc_free_expr (op1); | |
1631 | else | |
1632 | gfc_free_expr (op2); | |
1633 | ||
1634 | op1 = fcn; | |
1635 | op2 = zero; | |
1636 | e->value.op.op1 = fcn; | |
1637 | e->value.op.op2 = zero; | |
1638 | } | |
1639 | } | |
1640 | ||
1641 | ||
32af57e2 TK |
1642 | /* Don't compare REAL or COMPLEX expressions when honoring NaNs. */ |
1643 | ||
1644 | if (flag_finite_math_only | |
1645 | || (op1->ts.type != BT_REAL && op2->ts.type != BT_REAL | |
1646 | && op1->ts.type != BT_COMPLEX && op2->ts.type != BT_COMPLEX)) | |
601d98be | 1647 | { |
32af57e2 | 1648 | eq = gfc_dep_compare_expr (op1, op2); |
13001f33 | 1649 | if (eq <= -2) |
32af57e2 TK |
1650 | { |
1651 | /* Replace A // B < A // C with B < C, and A // B < C // B | |
1652 | with A < C. */ | |
1653 | if (op1->ts.type == BT_CHARACTER && op2->ts.type == BT_CHARACTER | |
2ce29890 | 1654 | && op1->expr_type == EXPR_OP |
32af57e2 | 1655 | && op1->value.op.op == INTRINSIC_CONCAT |
2ce29890 | 1656 | && op2->expr_type == EXPR_OP |
32af57e2 TK |
1657 | && op2->value.op.op == INTRINSIC_CONCAT) |
1658 | { | |
1659 | gfc_expr *op1_left = op1->value.op.op1; | |
1660 | gfc_expr *op2_left = op2->value.op.op1; | |
1661 | gfc_expr *op1_right = op1->value.op.op2; | |
1662 | gfc_expr *op2_right = op2->value.op.op2; | |
1663 | ||
1664 | if (gfc_dep_compare_expr (op1_left, op2_left) == 0) | |
1665 | { | |
1666 | /* Watch out for 'A ' // x vs. 'A' // x. */ | |
1667 | ||
1668 | if (op1_left->expr_type == EXPR_CONSTANT | |
1669 | && op2_left->expr_type == EXPR_CONSTANT | |
1670 | && op1_left->value.character.length | |
1671 | != op2_left->value.character.length) | |
4f21f0da | 1672 | return change; |
32af57e2 TK |
1673 | else |
1674 | { | |
cede9502 JM |
1675 | free (op1_left); |
1676 | free (op2_left); | |
9046a4dc TK |
1677 | if (firstarg) |
1678 | { | |
1679 | firstarg->expr = op1_right; | |
1680 | secondarg->expr = op2_right; | |
1681 | } | |
1682 | else | |
1683 | { | |
1684 | e->value.op.op1 = op1_right; | |
1685 | e->value.op.op2 = op2_right; | |
1686 | } | |
32af57e2 TK |
1687 | optimize_comparison (e, op); |
1688 | return true; | |
1689 | } | |
1690 | } | |
1691 | if (gfc_dep_compare_expr (op1_right, op2_right) == 0) | |
1692 | { | |
cede9502 JM |
1693 | free (op1_right); |
1694 | free (op2_right); | |
9046a4dc TK |
1695 | if (firstarg) |
1696 | { | |
1697 | firstarg->expr = op1_left; | |
1698 | secondarg->expr = op2_left; | |
1699 | } | |
1700 | else | |
1701 | { | |
1702 | e->value.op.op1 = op1_left; | |
1703 | e->value.op.op2 = op2_left; | |
1704 | } | |
1705 | ||
32af57e2 TK |
1706 | optimize_comparison (e, op); |
1707 | return true; | |
1708 | } | |
1709 | } | |
1710 | } | |
1711 | else | |
1712 | { | |
1713 | /* eq can only be -1, 0 or 1 at this point. */ | |
1714 | switch (op) | |
1715 | { | |
1716 | case INTRINSIC_EQ: | |
32af57e2 TK |
1717 | result = eq == 0; |
1718 | break; | |
7474dcc1 | 1719 | |
32af57e2 | 1720 | case INTRINSIC_GE: |
32af57e2 TK |
1721 | result = eq >= 0; |
1722 | break; | |
1723 | ||
1724 | case INTRINSIC_LE: | |
32af57e2 TK |
1725 | result = eq <= 0; |
1726 | break; | |
1727 | ||
1728 | case INTRINSIC_NE: | |
32af57e2 TK |
1729 | result = eq != 0; |
1730 | break; | |
1731 | ||
1732 | case INTRINSIC_GT: | |
32af57e2 TK |
1733 | result = eq > 0; |
1734 | break; | |
1735 | ||
1736 | case INTRINSIC_LT: | |
32af57e2 TK |
1737 | result = eq < 0; |
1738 | break; | |
7474dcc1 | 1739 | |
32af57e2 TK |
1740 | default: |
1741 | gfc_internal_error ("illegal OP in optimize_comparison"); | |
1742 | break; | |
1743 | } | |
1744 | ||
1745 | /* Replace the expression by a constant expression. The typespec | |
1746 | and where remains the way it is. */ | |
cede9502 JM |
1747 | free (op1); |
1748 | free (op2); | |
32af57e2 TK |
1749 | e->expr_type = EXPR_CONSTANT; |
1750 | e->value.logical = result; | |
1751 | return true; | |
1752 | } | |
601d98be | 1753 | } |
32af57e2 | 1754 | |
4f21f0da | 1755 | return change; |
601d98be TK |
1756 | } |
1757 | ||
4afeb65c TK |
1758 | /* Optimize a trim function by replacing it with an equivalent substring |
1759 | involving a call to len_trim. This only works for expressions where | |
1760 | variables are trimmed. Return true if anything was modified. */ | |
1761 | ||
1762 | static bool | |
1763 | optimize_trim (gfc_expr *e) | |
1764 | { | |
1765 | gfc_expr *a; | |
1766 | gfc_ref *ref; | |
1767 | gfc_expr *fcn; | |
7e3b6543 | 1768 | gfc_ref **rr = NULL; |
4afeb65c TK |
1769 | |
1770 | /* Don't do this optimization within an argument list, because | |
1771 | otherwise aliasing issues may occur. */ | |
1772 | ||
1773 | if (count_arglist != 1) | |
1774 | return false; | |
1775 | ||
1776 | if (e->ts.type != BT_CHARACTER || e->expr_type != EXPR_FUNCTION | |
1777 | || e->value.function.isym == NULL | |
1778 | || e->value.function.isym->id != GFC_ISYM_TRIM) | |
1779 | return false; | |
1780 | ||
1781 | a = e->value.function.actual->expr; | |
1782 | ||
1783 | if (a->expr_type != EXPR_VARIABLE) | |
1784 | return false; | |
1785 | ||
8b7cec58 TK |
1786 | /* This would pessimize the idiom a = trim(a) for reallocatable strings. */ |
1787 | ||
1788 | if (a->symtree->n.sym->attr.allocatable) | |
1789 | return false; | |
1790 | ||
7e3b6543 TK |
1791 | /* Follow all references to find the correct place to put the newly |
1792 | created reference. FIXME: Also handle substring references and | |
1793 | array references. Array references cause strange regressions at | |
1794 | the moment. */ | |
1795 | ||
4afeb65c TK |
1796 | if (a->ref) |
1797 | { | |
7e3b6543 TK |
1798 | for (rr = &(a->ref); *rr; rr = &((*rr)->next)) |
1799 | { | |
1800 | if ((*rr)->type == REF_SUBSTRING || (*rr)->type == REF_ARRAY) | |
1801 | return false; | |
1802 | } | |
4afeb65c | 1803 | } |
4afeb65c | 1804 | |
7e3b6543 | 1805 | strip_function_call (e); |
4afeb65c | 1806 | |
7e3b6543 TK |
1807 | if (e->ref == NULL) |
1808 | rr = &(e->ref); | |
4afeb65c | 1809 | |
7e3b6543 | 1810 | /* Create the reference. */ |
4afeb65c | 1811 | |
7e3b6543 TK |
1812 | ref = gfc_get_ref (); |
1813 | ref->type = REF_SUBSTRING; | |
4afeb65c | 1814 | |
7e3b6543 | 1815 | /* Set the start of the reference. */ |
4afeb65c | 1816 | |
7e3b6543 | 1817 | ref->u.ss.start = gfc_get_int_expr (gfc_default_integer_kind, NULL, 1); |
4afeb65c | 1818 | |
0f6bfefd | 1819 | /* Build the function call to len_trim(x, gfc_default_integer_kind). */ |
4afeb65c | 1820 | |
91077d4e | 1821 | fcn = get_len_trim_call (gfc_copy_expr (e), gfc_default_integer_kind); |
7e3b6543 TK |
1822 | |
1823 | /* Set the end of the reference to the call to len_trim. */ | |
1824 | ||
1825 | ref->u.ss.end = fcn; | |
efb63364 | 1826 | gcc_assert (rr != NULL && *rr == NULL); |
7e3b6543 TK |
1827 | *rr = ref; |
1828 | return true; | |
4afeb65c TK |
1829 | } |
1830 | ||
d2663912 JJ |
1831 | /* Optimize minloc(b), where b is rank 1 array, into |
1832 | (/ minloc(b, dim=1) /), and similarly for maxloc, | |
1833 | as the latter forms are expanded inline. */ | |
1834 | ||
1835 | static void | |
1836 | optimize_minmaxloc (gfc_expr **e) | |
1837 | { | |
1838 | gfc_expr *fn = *e; | |
1839 | gfc_actual_arglist *a; | |
1840 | char *name, *p; | |
1841 | ||
1842 | if (fn->rank != 1 | |
1843 | || fn->value.function.actual == NULL | |
1844 | || fn->value.function.actual->expr == NULL | |
1845 | || fn->value.function.actual->expr->rank != 1) | |
1846 | return; | |
1847 | ||
1848 | *e = gfc_get_array_expr (fn->ts.type, fn->ts.kind, &fn->where); | |
1849 | (*e)->shape = fn->shape; | |
1850 | fn->rank = 0; | |
1851 | fn->shape = NULL; | |
1852 | gfc_constructor_append_expr (&(*e)->value.constructor, fn, &fn->where); | |
1853 | ||
1854 | name = XALLOCAVEC (char, strlen (fn->value.function.name) + 1); | |
1855 | strcpy (name, fn->value.function.name); | |
1856 | p = strstr (name, "loc0"); | |
1857 | p[3] = '1'; | |
1858 | fn->value.function.name = gfc_get_string (name); | |
1859 | if (fn->value.function.actual->next) | |
1860 | { | |
1861 | a = fn->value.function.actual->next; | |
1862 | gcc_assert (a->expr == NULL); | |
1863 | } | |
1864 | else | |
1865 | { | |
1866 | a = gfc_get_actual_arglist (); | |
1867 | fn->value.function.actual->next = a; | |
1868 | } | |
1869 | a->expr = gfc_get_constant_expr (BT_INTEGER, gfc_default_integer_kind, | |
1870 | &fn->where); | |
1871 | mpz_set_ui (a->expr->value.integer, 1); | |
1872 | } | |
1873 | ||
305a35da TK |
1874 | /* Callback function for code checking that we do not pass a DO variable to an |
1875 | INTENT(OUT) or INTENT(INOUT) dummy variable. */ | |
1876 | ||
1877 | static int | |
1878 | doloop_code (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED, | |
1879 | void *data ATTRIBUTE_UNUSED) | |
1880 | { | |
1881 | gfc_code *co; | |
1882 | int i; | |
1883 | gfc_formal_arglist *f; | |
1884 | gfc_actual_arglist *a; | |
6c7069d6 | 1885 | gfc_code *cl; |
305a35da TK |
1886 | |
1887 | co = *c; | |
1888 | ||
6c7069d6 TK |
1889 | /* If the doloop_list grew, we have to truncate it here. */ |
1890 | ||
1891 | if ((unsigned) doloop_level < doloop_list.length()) | |
1892 | doloop_list.truncate (doloop_level); | |
1893 | ||
305a35da TK |
1894 | switch (co->op) |
1895 | { | |
1896 | case EXEC_DO: | |
1897 | ||
305a35da | 1898 | if (co->ext.iterator && co->ext.iterator->var) |
6c7069d6 | 1899 | doloop_list.safe_push (co); |
305a35da | 1900 | else |
6c7069d6 | 1901 | doloop_list.safe_push ((gfc_code *) NULL); |
305a35da TK |
1902 | break; |
1903 | ||
1904 | case EXEC_CALL: | |
da52ef43 TK |
1905 | |
1906 | if (co->resolved_sym == NULL) | |
1907 | break; | |
1908 | ||
4cbc9039 | 1909 | f = gfc_sym_get_dummy_args (co->resolved_sym); |
305a35da TK |
1910 | |
1911 | /* Withot a formal arglist, there is only unknown INTENT, | |
1912 | which we don't check for. */ | |
1913 | if (f == NULL) | |
1914 | break; | |
1915 | ||
1916 | a = co->ext.actual; | |
1917 | ||
1918 | while (a && f) | |
1919 | { | |
6c7069d6 | 1920 | FOR_EACH_VEC_ELT (doloop_list, i, cl) |
305a35da TK |
1921 | { |
1922 | gfc_symbol *do_sym; | |
7474dcc1 | 1923 | |
6c7069d6 | 1924 | if (cl == NULL) |
305a35da TK |
1925 | break; |
1926 | ||
6c7069d6 | 1927 | do_sym = cl->ext.iterator->var->symtree->n.sym; |
7474dcc1 | 1928 | |
305a35da TK |
1929 | if (a->expr && a->expr->symtree |
1930 | && a->expr->symtree->n.sym == do_sym) | |
1931 | { | |
1932 | if (f->sym->attr.intent == INTENT_OUT) | |
fea70c99 MLI |
1933 | gfc_error_now ("Variable %qs at %L set to undefined " |
1934 | "value inside loop beginning at %L as " | |
1935 | "INTENT(OUT) argument to subroutine %qs", | |
1936 | do_sym->name, &a->expr->where, | |
1937 | &doloop_list[i]->loc, | |
1938 | co->symtree->n.sym->name); | |
305a35da | 1939 | else if (f->sym->attr.intent == INTENT_INOUT) |
fea70c99 MLI |
1940 | gfc_error_now ("Variable %qs at %L not definable inside " |
1941 | "loop beginning at %L as INTENT(INOUT) " | |
1942 | "argument to subroutine %qs", | |
1943 | do_sym->name, &a->expr->where, | |
1944 | &doloop_list[i]->loc, | |
1945 | co->symtree->n.sym->name); | |
305a35da TK |
1946 | } |
1947 | } | |
1948 | a = a->next; | |
1949 | f = f->next; | |
1950 | } | |
1951 | break; | |
1952 | ||
1953 | default: | |
1954 | break; | |
1955 | } | |
1956 | return 0; | |
1957 | } | |
1958 | ||
1959 | /* Callback function for functions checking that we do not pass a DO variable | |
1960 | to an INTENT(OUT) or INTENT(INOUT) dummy variable. */ | |
1961 | ||
1962 | static int | |
1963 | do_function (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED, | |
1964 | void *data ATTRIBUTE_UNUSED) | |
1965 | { | |
1966 | gfc_formal_arglist *f; | |
1967 | gfc_actual_arglist *a; | |
1968 | gfc_expr *expr; | |
6c7069d6 | 1969 | gfc_code *dl; |
305a35da TK |
1970 | int i; |
1971 | ||
1972 | expr = *e; | |
1973 | if (expr->expr_type != EXPR_FUNCTION) | |
1974 | return 0; | |
1975 | ||
1976 | /* Intrinsic functions don't modify their arguments. */ | |
1977 | ||
1978 | if (expr->value.function.isym) | |
1979 | return 0; | |
1980 | ||
4cbc9039 | 1981 | f = gfc_sym_get_dummy_args (expr->symtree->n.sym); |
305a35da TK |
1982 | |
1983 | /* Without a formal arglist, there is only unknown INTENT, | |
1984 | which we don't check for. */ | |
1985 | if (f == NULL) | |
1986 | return 0; | |
1987 | ||
1988 | a = expr->value.function.actual; | |
1989 | ||
1990 | while (a && f) | |
1991 | { | |
6c7069d6 | 1992 | FOR_EACH_VEC_ELT (doloop_list, i, dl) |
305a35da TK |
1993 | { |
1994 | gfc_symbol *do_sym; | |
6c7069d6 TK |
1995 | |
1996 | if (dl == NULL) | |
305a35da TK |
1997 | break; |
1998 | ||
6c7069d6 | 1999 | do_sym = dl->ext.iterator->var->symtree->n.sym; |
7474dcc1 | 2000 | |
305a35da TK |
2001 | if (a->expr && a->expr->symtree |
2002 | && a->expr->symtree->n.sym == do_sym) | |
2003 | { | |
2004 | if (f->sym->attr.intent == INTENT_OUT) | |
fea70c99 MLI |
2005 | gfc_error_now ("Variable %qs at %L set to undefined value " |
2006 | "inside loop beginning at %L as INTENT(OUT) " | |
2007 | "argument to function %qs", do_sym->name, | |
2008 | &a->expr->where, &doloop_list[i]->loc, | |
2009 | expr->symtree->n.sym->name); | |
305a35da | 2010 | else if (f->sym->attr.intent == INTENT_INOUT) |
fea70c99 MLI |
2011 | gfc_error_now ("Variable %qs at %L not definable inside loop" |
2012 | " beginning at %L as INTENT(INOUT) argument to" | |
2013 | " function %qs", do_sym->name, | |
2014 | &a->expr->where, &doloop_list[i]->loc, | |
2015 | expr->symtree->n.sym->name); | |
305a35da TK |
2016 | } |
2017 | } | |
2018 | a = a->next; | |
2019 | f = f->next; | |
2020 | } | |
2021 | ||
2022 | return 0; | |
2023 | } | |
2024 | ||
2025 | static void | |
2026 | doloop_warn (gfc_namespace *ns) | |
2027 | { | |
2028 | gfc_code_walker (&ns->code, doloop_code, do_function, NULL); | |
2029 | } | |
2030 | ||
f1abbf69 TK |
2031 | /* This selction deals with inlining calls to MATMUL. */ |
2032 | ||
2033 | /* Auxiliary function to build and simplify an array inquiry function. | |
2034 | dim is zero-based. */ | |
2035 | ||
2036 | static gfc_expr * | |
2037 | get_array_inq_function (gfc_isym_id id, gfc_expr *e, int dim) | |
2038 | { | |
2039 | gfc_expr *fcn; | |
2040 | gfc_expr *dim_arg, *kind; | |
2041 | const char *name; | |
2042 | gfc_expr *ec; | |
2043 | ||
2044 | switch (id) | |
2045 | { | |
2046 | case GFC_ISYM_LBOUND: | |
2047 | name = "_gfortran_lbound"; | |
2048 | break; | |
2049 | ||
2050 | case GFC_ISYM_UBOUND: | |
2051 | name = "_gfortran_ubound"; | |
2052 | break; | |
2053 | ||
2054 | case GFC_ISYM_SIZE: | |
2055 | name = "_gfortran_size"; | |
2056 | break; | |
2057 | ||
2058 | default: | |
2059 | gcc_unreachable (); | |
2060 | } | |
2061 | ||
2062 | dim_arg = gfc_get_int_expr (gfc_default_integer_kind, &e->where, dim); | |
2063 | kind = gfc_get_int_expr (gfc_default_integer_kind, &e->where, | |
2064 | gfc_index_integer_kind); | |
2065 | ||
2066 | ec = gfc_copy_expr (e); | |
2067 | fcn = gfc_build_intrinsic_call (current_ns, id, name, e->where, 3, | |
2068 | ec, dim_arg, kind); | |
2069 | gfc_simplify_expr (fcn, 0); | |
2070 | return fcn; | |
2071 | } | |
2072 | ||
2073 | /* Builds a logical expression. */ | |
2074 | ||
2075 | static gfc_expr* | |
2076 | build_logical_expr (gfc_intrinsic_op op, gfc_expr *e1, gfc_expr *e2) | |
2077 | { | |
2078 | gfc_typespec ts; | |
2079 | gfc_expr *res; | |
2080 | ||
2081 | ts.type = BT_LOGICAL; | |
2082 | ts.kind = gfc_default_logical_kind; | |
2083 | res = gfc_get_expr (); | |
2084 | res->where = e1->where; | |
2085 | res->expr_type = EXPR_OP; | |
2086 | res->value.op.op = op; | |
2087 | res->value.op.op1 = e1; | |
2088 | res->value.op.op2 = e2; | |
2089 | res->ts = ts; | |
2090 | ||
2091 | return res; | |
2092 | } | |
2093 | ||
2094 | ||
2095 | /* Return an operation of one two gfc_expr (one if e2 is NULL). This assumes | |
2096 | compatible typespecs. */ | |
2097 | ||
2098 | static gfc_expr * | |
2099 | get_operand (gfc_intrinsic_op op, gfc_expr *e1, gfc_expr *e2) | |
2100 | { | |
2101 | gfc_expr *res; | |
2102 | ||
2103 | res = gfc_get_expr (); | |
2104 | res->ts = e1->ts; | |
2105 | res->where = e1->where; | |
2106 | res->expr_type = EXPR_OP; | |
2107 | res->value.op.op = op; | |
2108 | res->value.op.op1 = e1; | |
2109 | res->value.op.op2 = e2; | |
2110 | gfc_simplify_expr (res, 0); | |
2111 | return res; | |
2112 | } | |
2113 | ||
2114 | /* Generate the IF statement for a runtime check if we want to do inlining or | |
2115 | not - putting in the code for both branches and putting it into the syntax | |
2116 | tree is the caller's responsibility. For fixed array sizes, this should be | |
2117 | removed by DCE. Only called for rank-two matrices A and B. */ | |
2118 | ||
2119 | static gfc_code * | |
2120 | inline_limit_check (gfc_expr *a, gfc_expr *b, enum matrix_case m_case) | |
2121 | { | |
2122 | gfc_expr *inline_limit; | |
2123 | gfc_code *if_1, *if_2, *else_2; | |
2124 | gfc_expr *b2, *a2, *a1, *m1, *m2; | |
2125 | gfc_typespec ts; | |
2126 | gfc_expr *cond; | |
2127 | ||
094773e8 | 2128 | gcc_assert (m_case == A2B2 || m_case == A2B2T); |
f1abbf69 TK |
2129 | |
2130 | /* Calculation is done in real to avoid integer overflow. */ | |
2131 | ||
2132 | inline_limit = gfc_get_constant_expr (BT_REAL, gfc_default_real_kind, | |
2133 | &a->where); | |
2134 | mpfr_set_si (inline_limit->value.real, flag_inline_matmul_limit, | |
2135 | GFC_RND_MODE); | |
2136 | mpfr_pow_ui (inline_limit->value.real, inline_limit->value.real, 3, | |
2137 | GFC_RND_MODE); | |
2138 | ||
2139 | a1 = get_array_inq_function (GFC_ISYM_SIZE, a, 1); | |
2140 | a2 = get_array_inq_function (GFC_ISYM_SIZE, a, 2); | |
2141 | b2 = get_array_inq_function (GFC_ISYM_SIZE, b, 2); | |
2142 | ||
2143 | gfc_clear_ts (&ts); | |
2144 | ts.type = BT_REAL; | |
2145 | ts.kind = gfc_default_real_kind; | |
2146 | gfc_convert_type_warn (a1, &ts, 2, 0); | |
2147 | gfc_convert_type_warn (a2, &ts, 2, 0); | |
2148 | gfc_convert_type_warn (b2, &ts, 2, 0); | |
2149 | ||
2150 | m1 = get_operand (INTRINSIC_TIMES, a1, a2); | |
2151 | m2 = get_operand (INTRINSIC_TIMES, m1, b2); | |
2152 | ||
2153 | cond = build_logical_expr (INTRINSIC_LE, m2, inline_limit); | |
2154 | gfc_simplify_expr (cond, 0); | |
2155 | ||
2156 | else_2 = XCNEW (gfc_code); | |
2157 | else_2->op = EXEC_IF; | |
2158 | else_2->loc = a->where; | |
2159 | ||
2160 | if_2 = XCNEW (gfc_code); | |
2161 | if_2->op = EXEC_IF; | |
2162 | if_2->expr1 = cond; | |
2163 | if_2->loc = a->where; | |
2164 | if_2->block = else_2; | |
2165 | ||
2166 | if_1 = XCNEW (gfc_code); | |
2167 | if_1->op = EXEC_IF; | |
2168 | if_1->block = if_2; | |
2169 | if_1->loc = a->where; | |
2170 | ||
2171 | return if_1; | |
2172 | } | |
2173 | ||
2174 | ||
2175 | /* Insert code to issue a runtime error if the expressions are not equal. */ | |
2176 | ||
2177 | static gfc_code * | |
2178 | runtime_error_ne (gfc_expr *e1, gfc_expr *e2, const char *msg) | |
2179 | { | |
2180 | gfc_expr *cond; | |
2181 | gfc_code *if_1, *if_2; | |
2182 | gfc_code *c; | |
2183 | gfc_actual_arglist *a1, *a2, *a3; | |
2184 | ||
2185 | gcc_assert (e1->where.lb); | |
2186 | /* Build the call to runtime_error. */ | |
2187 | c = XCNEW (gfc_code); | |
2188 | c->op = EXEC_CALL; | |
2189 | c->loc = e1->where; | |
2190 | ||
2191 | /* Get a null-terminated message string. */ | |
2192 | ||
2193 | a1 = gfc_get_actual_arglist (); | |
2194 | a1->expr = gfc_get_character_expr (gfc_default_character_kind, &e1->where, | |
2195 | msg, strlen(msg)+1); | |
2196 | c->ext.actual = a1; | |
2197 | ||
2198 | /* Pass the value of the first expression. */ | |
2199 | a2 = gfc_get_actual_arglist (); | |
2200 | a2->expr = gfc_copy_expr (e1); | |
2201 | a1->next = a2; | |
2202 | ||
2203 | /* Pass the value of the second expression. */ | |
2204 | a3 = gfc_get_actual_arglist (); | |
2205 | a3->expr = gfc_copy_expr (e2); | |
2206 | a2->next = a3; | |
2207 | ||
2208 | gfc_check_fe_runtime_error (c->ext.actual); | |
2209 | gfc_resolve_fe_runtime_error (c); | |
2210 | ||
2211 | if_2 = XCNEW (gfc_code); | |
2212 | if_2->op = EXEC_IF; | |
2213 | if_2->loc = e1->where; | |
2214 | if_2->next = c; | |
2215 | ||
2216 | if_1 = XCNEW (gfc_code); | |
2217 | if_1->op = EXEC_IF; | |
2218 | if_1->block = if_2; | |
2219 | if_1->loc = e1->where; | |
2220 | ||
2221 | cond = build_logical_expr (INTRINSIC_NE, e1, e2); | |
2222 | gfc_simplify_expr (cond, 0); | |
2223 | if_2->expr1 = cond; | |
2224 | ||
2225 | return if_1; | |
2226 | } | |
2227 | ||
2228 | /* Handle matrix reallocation. Caller is responsible to insert into | |
2229 | the code tree. | |
2230 | ||
7474dcc1 | 2231 | For the two-dimensional case, build |
f1abbf69 TK |
2232 | |
2233 | if (allocated(c)) then | |
2234 | if (size(c,1) /= size(a,1) .or. size(c,2) /= size(b,2)) then | |
2235 | deallocate(c) | |
2236 | allocate (c(size(a,1), size(b,2))) | |
2237 | end if | |
2238 | else | |
2239 | allocate (c(size(a,1),size(b,2))) | |
2240 | end if | |
2241 | ||
2242 | and for the other cases correspondingly. | |
2243 | */ | |
2244 | ||
2245 | static gfc_code * | |
2246 | matmul_lhs_realloc (gfc_expr *c, gfc_expr *a, gfc_expr *b, | |
2247 | enum matrix_case m_case) | |
2248 | { | |
2249 | ||
2250 | gfc_expr *allocated, *alloc_expr; | |
2251 | gfc_code *if_alloc_1, *if_alloc_2, *if_size_1, *if_size_2; | |
2252 | gfc_code *else_alloc; | |
2253 | gfc_code *deallocate, *allocate1, *allocate_else; | |
2254 | gfc_array_ref *ar; | |
2255 | gfc_expr *cond, *ne1, *ne2; | |
2256 | ||
2257 | if (warn_realloc_lhs) | |
2258 | gfc_warning (OPT_Wrealloc_lhs, | |
2259 | "Code for reallocating the allocatable array at %L will " | |
2260 | "be added", &c->where); | |
2261 | ||
2262 | alloc_expr = gfc_copy_expr (c); | |
2263 | ||
2264 | ar = gfc_find_array_ref (alloc_expr); | |
2265 | gcc_assert (ar && ar->type == AR_FULL); | |
2266 | ||
2267 | /* c comes in as a full ref. Change it into a copy and make it into an | |
2268 | element ref so it has the right form for for ALLOCATE. In the same | |
2269 | switch statement, also generate the size comparison for the secod IF | |
2270 | statement. */ | |
2271 | ||
2272 | ar->type = AR_ELEMENT; | |
2273 | ||
2274 | switch (m_case) | |
2275 | { | |
2276 | case A2B2: | |
2277 | ar->start[0] = get_array_inq_function (GFC_ISYM_SIZE, a, 1); | |
2278 | ar->start[1] = get_array_inq_function (GFC_ISYM_SIZE, b, 2); | |
2279 | ne1 = build_logical_expr (INTRINSIC_NE, | |
2280 | get_array_inq_function (GFC_ISYM_SIZE, c, 1), | |
2281 | get_array_inq_function (GFC_ISYM_SIZE, a, 1)); | |
2282 | ne2 = build_logical_expr (INTRINSIC_NE, | |
2283 | get_array_inq_function (GFC_ISYM_SIZE, c, 2), | |
2284 | get_array_inq_function (GFC_ISYM_SIZE, b, 2)); | |
2285 | cond = build_logical_expr (INTRINSIC_OR, ne1, ne2); | |
2286 | break; | |
2287 | ||
094773e8 TK |
2288 | case A2B2T: |
2289 | ar->start[0] = get_array_inq_function (GFC_ISYM_SIZE, a, 1); | |
2290 | ar->start[1] = get_array_inq_function (GFC_ISYM_SIZE, b, 1); | |
2291 | ||
2292 | ne1 = build_logical_expr (INTRINSIC_NE, | |
2293 | get_array_inq_function (GFC_ISYM_SIZE, c, 1), | |
2294 | get_array_inq_function (GFC_ISYM_SIZE, a, 1)); | |
2295 | ne2 = build_logical_expr (INTRINSIC_NE, | |
2296 | get_array_inq_function (GFC_ISYM_SIZE, c, 2), | |
2297 | get_array_inq_function (GFC_ISYM_SIZE, b, 1)); | |
2298 | cond = build_logical_expr (INTRINSIC_OR, ne1, ne2); | |
a220f43d | 2299 | break; |
094773e8 | 2300 | |
f1abbf69 TK |
2301 | case A2B1: |
2302 | ar->start[0] = get_array_inq_function (GFC_ISYM_SIZE, a, 1); | |
2303 | cond = build_logical_expr (INTRINSIC_NE, | |
2304 | get_array_inq_function (GFC_ISYM_SIZE, c, 1), | |
2305 | get_array_inq_function (GFC_ISYM_SIZE, a, 2)); | |
2306 | break; | |
2307 | ||
2308 | case A1B2: | |
2309 | ar->start[0] = get_array_inq_function (GFC_ISYM_SIZE, b, 1); | |
2310 | cond = build_logical_expr (INTRINSIC_NE, | |
2311 | get_array_inq_function (GFC_ISYM_SIZE, c, 1), | |
2312 | get_array_inq_function (GFC_ISYM_SIZE, b, 2)); | |
2313 | break; | |
2314 | ||
2315 | default: | |
2316 | gcc_unreachable(); | |
2317 | ||
2318 | } | |
2319 | ||
2320 | gfc_simplify_expr (cond, 0); | |
2321 | ||
2322 | /* We need two identical allocate statements in two | |
2323 | branches of the IF statement. */ | |
7474dcc1 | 2324 | |
f1abbf69 TK |
2325 | allocate1 = XCNEW (gfc_code); |
2326 | allocate1->op = EXEC_ALLOCATE; | |
2327 | allocate1->ext.alloc.list = gfc_get_alloc (); | |
2328 | allocate1->loc = c->where; | |
2329 | allocate1->ext.alloc.list->expr = gfc_copy_expr (alloc_expr); | |
2330 | ||
2331 | allocate_else = XCNEW (gfc_code); | |
2332 | allocate_else->op = EXEC_ALLOCATE; | |
2333 | allocate_else->ext.alloc.list = gfc_get_alloc (); | |
2334 | allocate_else->loc = c->where; | |
2335 | allocate_else->ext.alloc.list->expr = alloc_expr; | |
2336 | ||
2337 | allocated = gfc_build_intrinsic_call (current_ns, GFC_ISYM_ALLOCATED, | |
2338 | "_gfortran_allocated", c->where, | |
2339 | 1, gfc_copy_expr (c)); | |
2340 | ||
2341 | deallocate = XCNEW (gfc_code); | |
2342 | deallocate->op = EXEC_DEALLOCATE; | |
2343 | deallocate->ext.alloc.list = gfc_get_alloc (); | |
2344 | deallocate->ext.alloc.list->expr = gfc_copy_expr (c); | |
2345 | deallocate->next = allocate1; | |
2346 | deallocate->loc = c->where; | |
7474dcc1 | 2347 | |
f1abbf69 TK |
2348 | if_size_2 = XCNEW (gfc_code); |
2349 | if_size_2->op = EXEC_IF; | |
2350 | if_size_2->expr1 = cond; | |
2351 | if_size_2->loc = c->where; | |
2352 | if_size_2->next = deallocate; | |
2353 | ||
2354 | if_size_1 = XCNEW (gfc_code); | |
2355 | if_size_1->op = EXEC_IF; | |
2356 | if_size_1->block = if_size_2; | |
2357 | if_size_1->loc = c->where; | |
2358 | ||
2359 | else_alloc = XCNEW (gfc_code); | |
2360 | else_alloc->op = EXEC_IF; | |
2361 | else_alloc->loc = c->where; | |
2362 | else_alloc->next = allocate_else; | |
2363 | ||
2364 | if_alloc_2 = XCNEW (gfc_code); | |
2365 | if_alloc_2->op = EXEC_IF; | |
2366 | if_alloc_2->expr1 = allocated; | |
2367 | if_alloc_2->loc = c->where; | |
2368 | if_alloc_2->next = if_size_1; | |
2369 | if_alloc_2->block = else_alloc; | |
2370 | ||
2371 | if_alloc_1 = XCNEW (gfc_code); | |
2372 | if_alloc_1->op = EXEC_IF; | |
2373 | if_alloc_1->block = if_alloc_2; | |
2374 | if_alloc_1->loc = c->where; | |
2375 | ||
2376 | return if_alloc_1; | |
2377 | } | |
2378 | ||
2379 | /* Callback function for has_function_or_op. */ | |
2380 | ||
2381 | static int | |
2382 | is_function_or_op (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED, | |
2383 | void *data ATTRIBUTE_UNUSED) | |
2384 | { | |
2385 | if ((*e) == 0) | |
2386 | return 0; | |
2387 | else | |
2388 | return (*e)->expr_type == EXPR_FUNCTION | |
2389 | || (*e)->expr_type == EXPR_OP; | |
2390 | } | |
2391 | ||
2392 | /* Returns true if the expression contains a function. */ | |
2393 | ||
2394 | static bool | |
2395 | has_function_or_op (gfc_expr **e) | |
2396 | { | |
2397 | if (e == NULL) | |
2398 | return false; | |
2399 | else | |
2400 | return gfc_expr_walker (e, is_function_or_op, NULL); | |
2401 | } | |
2402 | ||
2403 | /* Freeze (assign to a temporary variable) a single expression. */ | |
2404 | ||
2405 | static void | |
2406 | freeze_expr (gfc_expr **ep) | |
2407 | { | |
2408 | gfc_expr *ne; | |
2409 | if (has_function_or_op (ep)) | |
2410 | { | |
2411 | ne = create_var (*ep, "freeze"); | |
2412 | *ep = ne; | |
2413 | } | |
2414 | } | |
2415 | ||
2416 | /* Go through an expression's references and assign them to temporary | |
2417 | variables if they contain functions. This is usually done prior to | |
2418 | front-end scalarization to avoid multiple invocations of functions. */ | |
2419 | ||
2420 | static void | |
2421 | freeze_references (gfc_expr *e) | |
2422 | { | |
2423 | gfc_ref *r; | |
2424 | gfc_array_ref *ar; | |
2425 | int i; | |
2426 | ||
2427 | for (r=e->ref; r; r=r->next) | |
2428 | { | |
2429 | if (r->type == REF_SUBSTRING) | |
2430 | { | |
2431 | if (r->u.ss.start != NULL) | |
2432 | freeze_expr (&r->u.ss.start); | |
2433 | ||
2434 | if (r->u.ss.end != NULL) | |
2435 | freeze_expr (&r->u.ss.end); | |
2436 | } | |
2437 | else if (r->type == REF_ARRAY) | |
2438 | { | |
2439 | ar = &r->u.ar; | |
2440 | switch (ar->type) | |
2441 | { | |
2442 | case AR_FULL: | |
2443 | break; | |
2444 | ||
2445 | case AR_SECTION: | |
2446 | for (i=0; i<ar->dimen; i++) | |
2447 | { | |
2448 | if (ar->dimen_type[i] == DIMEN_RANGE) | |
2449 | { | |
2450 | freeze_expr (&ar->start[i]); | |
2451 | freeze_expr (&ar->end[i]); | |
2452 | freeze_expr (&ar->stride[i]); | |
2453 | } | |
2454 | else if (ar->dimen_type[i] == DIMEN_ELEMENT) | |
2455 | { | |
2456 | freeze_expr (&ar->start[i]); | |
2457 | } | |
2458 | } | |
2459 | break; | |
2460 | ||
2461 | case AR_ELEMENT: | |
2462 | for (i=0; i<ar->dimen; i++) | |
2463 | freeze_expr (&ar->start[i]); | |
2464 | break; | |
2465 | ||
2466 | default: | |
2467 | break; | |
2468 | } | |
2469 | } | |
2470 | } | |
2471 | } | |
2472 | ||
2473 | /* Convert to gfc_index_integer_kind if needed, just do a copy otherwise. */ | |
2474 | ||
2475 | static gfc_expr * | |
2476 | convert_to_index_kind (gfc_expr *e) | |
2477 | { | |
2478 | gfc_expr *res; | |
2479 | ||
2480 | gcc_assert (e != NULL); | |
2481 | ||
2482 | res = gfc_copy_expr (e); | |
2483 | ||
2484 | gcc_assert (e->ts.type == BT_INTEGER); | |
2485 | ||
2486 | if (res->ts.kind != gfc_index_integer_kind) | |
2487 | { | |
2488 | gfc_typespec ts; | |
2489 | gfc_clear_ts (&ts); | |
2490 | ts.type = BT_INTEGER; | |
2491 | ts.kind = gfc_index_integer_kind; | |
2492 | ||
2493 | gfc_convert_type_warn (e, &ts, 2, 0); | |
2494 | } | |
2495 | ||
2496 | return res; | |
2497 | } | |
2498 | ||
2499 | /* Function to create a DO loop including creation of the | |
2500 | iteration variable. gfc_expr are copied.*/ | |
2501 | ||
2502 | static gfc_code * | |
2503 | create_do_loop (gfc_expr *start, gfc_expr *end, gfc_expr *step, locus *where, | |
2504 | gfc_namespace *ns, char *vname) | |
2505 | { | |
2506 | ||
2507 | char name[GFC_MAX_SYMBOL_LEN +1]; | |
2508 | gfc_symtree *symtree; | |
2509 | gfc_symbol *symbol; | |
2510 | gfc_expr *i; | |
2511 | gfc_code *n, *n2; | |
2512 | ||
2513 | /* Create an expression for the iteration variable. */ | |
2514 | if (vname) | |
2515 | sprintf (name, "__var_%d_do_%s", var_num++, vname); | |
2516 | else | |
2517 | sprintf (name, "__var_%d_do", var_num++); | |
2518 | ||
2519 | ||
2520 | if (gfc_get_sym_tree (name, ns, &symtree, false) != 0) | |
2521 | gcc_unreachable (); | |
2522 | ||
2523 | /* Create the loop variable. */ | |
2524 | ||
2525 | symbol = symtree->n.sym; | |
2526 | symbol->ts.type = BT_INTEGER; | |
2527 | symbol->ts.kind = gfc_index_integer_kind; | |
2528 | symbol->attr.flavor = FL_VARIABLE; | |
2529 | symbol->attr.referenced = 1; | |
2530 | symbol->attr.dimension = 0; | |
2531 | symbol->attr.fe_temp = 1; | |
2532 | gfc_commit_symbol (symbol); | |
2533 | ||
2534 | i = gfc_get_expr (); | |
2535 | i->expr_type = EXPR_VARIABLE; | |
2536 | i->ts = symbol->ts; | |
2537 | i->rank = 0; | |
2538 | i->where = *where; | |
2539 | i->symtree = symtree; | |
2540 | ||
2541 | /* ... and the nested DO statements. */ | |
2542 | n = XCNEW (gfc_code); | |
2543 | n->op = EXEC_DO; | |
2544 | n->loc = *where; | |
2545 | n->ext.iterator = gfc_get_iterator (); | |
2546 | n->ext.iterator->var = i; | |
2547 | n->ext.iterator->start = convert_to_index_kind (start); | |
2548 | n->ext.iterator->end = convert_to_index_kind (end); | |
2549 | if (step) | |
2550 | n->ext.iterator->step = convert_to_index_kind (step); | |
2551 | else | |
2552 | n->ext.iterator->step = gfc_get_int_expr (gfc_index_integer_kind, | |
2553 | where, 1); | |
2554 | ||
2555 | n2 = XCNEW (gfc_code); | |
2556 | n2->op = EXEC_DO; | |
2557 | n2->loc = *where; | |
2558 | n2->next = NULL; | |
2559 | n->block = n2; | |
2560 | return n; | |
2561 | } | |
2562 | ||
2563 | /* Get the upper bound of the DO loops for matmul along a dimension. This | |
2564 | is one-based. */ | |
2565 | ||
2566 | static gfc_expr* | |
2567 | get_size_m1 (gfc_expr *e, int dimen) | |
2568 | { | |
2569 | mpz_t size; | |
2570 | gfc_expr *res; | |
2571 | ||
2572 | if (gfc_array_dimen_size (e, dimen - 1, &size)) | |
2573 | { | |
2574 | res = gfc_get_constant_expr (BT_INTEGER, | |
2575 | gfc_index_integer_kind, &e->where); | |
2576 | mpz_sub_ui (res->value.integer, size, 1); | |
2577 | mpz_clear (size); | |
2578 | } | |
2579 | else | |
2580 | { | |
2581 | res = get_operand (INTRINSIC_MINUS, | |
2582 | get_array_inq_function (GFC_ISYM_SIZE, e, dimen), | |
2583 | gfc_get_int_expr (gfc_index_integer_kind, | |
2584 | &e->where, 1)); | |
2585 | gfc_simplify_expr (res, 0); | |
2586 | } | |
2587 | ||
2588 | return res; | |
2589 | } | |
2590 | ||
2591 | /* Function to return a scalarized expression. It is assumed that indices are | |
2592 | zero based to make generation of DO loops easier. A zero as index will | |
2593 | access the first element along a dimension. Single element references will | |
2594 | be skipped. A NULL as an expression will be replaced by a full reference. | |
2595 | This assumes that the index loops have gfc_index_integer_kind, and that all | |
2596 | references have been frozen. */ | |
2597 | ||
2598 | static gfc_expr* | |
2599 | scalarized_expr (gfc_expr *e_in, gfc_expr **index, int count_index) | |
2600 | { | |
2601 | gfc_array_ref *ar; | |
2602 | int i; | |
2603 | int rank; | |
2604 | gfc_expr *e; | |
2605 | int i_index; | |
2606 | bool was_fullref; | |
2607 | ||
2608 | e = gfc_copy_expr(e_in); | |
2609 | ||
2610 | rank = e->rank; | |
2611 | ||
2612 | ar = gfc_find_array_ref (e); | |
2613 | ||
2614 | /* We scalarize count_index variables, reducing the rank by count_index. */ | |
2615 | ||
2616 | e->rank = rank - count_index; | |
2617 | ||
2618 | was_fullref = ar->type == AR_FULL; | |
2619 | ||
2620 | if (e->rank == 0) | |
2621 | ar->type = AR_ELEMENT; | |
2622 | else | |
2623 | ar->type = AR_SECTION; | |
2624 | ||
2625 | /* Loop over the indices. For each index, create the expression | |
2626 | index * stride + lbound(e, dim). */ | |
7474dcc1 | 2627 | |
f1abbf69 TK |
2628 | i_index = 0; |
2629 | for (i=0; i < ar->dimen; i++) | |
2630 | { | |
2631 | if (was_fullref || ar->dimen_type[i] == DIMEN_RANGE) | |
2632 | { | |
2633 | if (index[i_index] != NULL) | |
2634 | { | |
2635 | gfc_expr *lbound, *nindex; | |
2636 | gfc_expr *loopvar; | |
7474dcc1 PT |
2637 | |
2638 | loopvar = gfc_copy_expr (index[i_index]); | |
2639 | ||
f1abbf69 TK |
2640 | if (ar->stride[i]) |
2641 | { | |
2642 | gfc_expr *tmp; | |
2643 | ||
2644 | tmp = gfc_copy_expr(ar->stride[i]); | |
2645 | if (tmp->ts.kind != gfc_index_integer_kind) | |
2646 | { | |
2647 | gfc_typespec ts; | |
2648 | gfc_clear_ts (&ts); | |
2649 | ts.type = BT_INTEGER; | |
2650 | ts.kind = gfc_index_integer_kind; | |
2651 | gfc_convert_type (tmp, &ts, 2); | |
2652 | } | |
2653 | nindex = get_operand (INTRINSIC_TIMES, loopvar, tmp); | |
2654 | } | |
2655 | else | |
2656 | nindex = loopvar; | |
7474dcc1 | 2657 | |
f1abbf69 TK |
2658 | /* Calculate the lower bound of the expression. */ |
2659 | if (ar->start[i]) | |
2660 | { | |
2661 | lbound = gfc_copy_expr (ar->start[i]); | |
2662 | if (lbound->ts.kind != gfc_index_integer_kind) | |
2663 | { | |
2664 | gfc_typespec ts; | |
2665 | gfc_clear_ts (&ts); | |
2666 | ts.type = BT_INTEGER; | |
2667 | ts.kind = gfc_index_integer_kind; | |
2668 | gfc_convert_type (lbound, &ts, 2); | |
2669 | ||
2670 | } | |
2671 | } | |
2672 | else | |
2673 | { | |
7fc67fcb TK |
2674 | gfc_expr *lbound_e; |
2675 | gfc_ref *ref; | |
2676 | ||
2677 | lbound_e = gfc_copy_expr (e_in); | |
2678 | ||
2679 | for (ref = lbound_e->ref; ref; ref = ref->next) | |
2680 | if (ref->type == REF_ARRAY | |
2681 | && (ref->u.ar.type == AR_FULL | |
2682 | || ref->u.ar.type == AR_SECTION)) | |
2683 | break; | |
2684 | ||
2685 | if (ref->next) | |
2686 | { | |
2687 | gfc_free_ref_list (ref->next); | |
2688 | ref->next = NULL; | |
2689 | } | |
2690 | ||
f1abbf69 TK |
2691 | if (!was_fullref) |
2692 | { | |
2693 | /* Look at full individual sections, like a(:). The first index | |
2694 | is the lbound of a full ref. */ | |
7fc67fcb | 2695 | int j; |
f1abbf69 TK |
2696 | gfc_array_ref *ar; |
2697 | ||
7fc67fcb | 2698 | ar = &ref->u.ar; |
f1abbf69 | 2699 | ar->type = AR_FULL; |
7fc67fcb TK |
2700 | for (j = 0; j < ar->dimen; j++) |
2701 | { | |
2702 | gfc_free_expr (ar->start[j]); | |
2703 | ar->start[j] = NULL; | |
2704 | gfc_free_expr (ar->end[j]); | |
2705 | ar->end[j] = NULL; | |
2706 | gfc_free_expr (ar->stride[j]); | |
2707 | ar->stride[j] = NULL; | |
2708 | } | |
2709 | ||
2710 | /* We have to get rid of the shape, if there is one. Do | |
2711 | so by freeing it and calling gfc_resolve to rebuild | |
2712 | it, if necessary. */ | |
2713 | ||
2714 | if (lbound_e->shape) | |
2715 | gfc_free_shape (&(lbound_e->shape), lbound_e->rank); | |
2716 | ||
2717 | lbound_e->rank = ar->dimen; | |
2718 | gfc_resolve_expr (lbound_e); | |
f1abbf69 | 2719 | } |
7fc67fcb TK |
2720 | lbound = get_array_inq_function (GFC_ISYM_LBOUND, lbound_e, |
2721 | i + 1); | |
2722 | gfc_free_expr (lbound_e); | |
f1abbf69 | 2723 | } |
7474dcc1 | 2724 | |
f1abbf69 TK |
2725 | ar->dimen_type[i] = DIMEN_ELEMENT; |
2726 | ||
2727 | gfc_free_expr (ar->start[i]); | |
2728 | ar->start[i] = get_operand (INTRINSIC_PLUS, nindex, lbound); | |
7474dcc1 | 2729 | |
f1abbf69 TK |
2730 | gfc_free_expr (ar->end[i]); |
2731 | ar->end[i] = NULL; | |
2732 | gfc_free_expr (ar->stride[i]); | |
2733 | ar->stride[i] = NULL; | |
2734 | gfc_simplify_expr (ar->start[i], 0); | |
2735 | } | |
2736 | else if (was_fullref) | |
2737 | { | |
2738 | gfc_internal_error ("Scalarization using DIMEN_RANGE unimplemented"); | |
2739 | } | |
2740 | i_index ++; | |
2741 | } | |
2742 | } | |
7fc67fcb | 2743 | |
f1abbf69 TK |
2744 | return e; |
2745 | } | |
2746 | ||
7e269fe8 TK |
2747 | /* Helper function to check for a dimen vector as subscript. */ |
2748 | ||
2749 | static bool | |
2750 | has_dimen_vector_ref (gfc_expr *e) | |
2751 | { | |
2752 | gfc_array_ref *ar; | |
2753 | int i; | |
2754 | ||
2755 | ar = gfc_find_array_ref (e); | |
2756 | gcc_assert (ar); | |
2757 | if (ar->type == AR_FULL) | |
2758 | return false; | |
2759 | ||
2760 | for (i=0; i<ar->dimen; i++) | |
2761 | if (ar->dimen_type[i] == DIMEN_VECTOR) | |
2762 | return true; | |
2763 | ||
2764 | return false; | |
2765 | } | |
f1abbf69 | 2766 | |
c39d5e4a TK |
2767 | /* If handed an expression of the form |
2768 | ||
094773e8 | 2769 | TRANSPOSE(CONJG(A)) |
c39d5e4a TK |
2770 | |
2771 | check if A can be handled by matmul and return if there is an uneven number | |
2772 | of CONJG calls. Return a pointer to the array when everything is OK, NULL | |
2773 | otherwise. The caller has to check for the correct rank. */ | |
2774 | ||
2775 | static gfc_expr* | |
094773e8 | 2776 | check_conjg_transpose_variable (gfc_expr *e, bool *conjg, bool *transpose) |
c39d5e4a TK |
2777 | { |
2778 | *conjg = false; | |
094773e8 | 2779 | *transpose = false; |
c39d5e4a TK |
2780 | |
2781 | do | |
2782 | { | |
2783 | if (e->expr_type == EXPR_VARIABLE) | |
2784 | { | |
2785 | gcc_assert (e->rank == 1 || e->rank == 2); | |
2786 | return e; | |
2787 | } | |
2788 | else if (e->expr_type == EXPR_FUNCTION) | |
2789 | { | |
2790 | if (e->value.function.isym == NULL) | |
2791 | return NULL; | |
2792 | ||
2793 | if (e->value.function.isym->id == GFC_ISYM_CONJG) | |
2794 | *conjg = !*conjg; | |
094773e8 TK |
2795 | else if (e->value.function.isym->id == GFC_ISYM_TRANSPOSE) |
2796 | *transpose = !*transpose; | |
c39d5e4a TK |
2797 | else return NULL; |
2798 | } | |
2799 | else | |
2800 | return NULL; | |
2801 | ||
2802 | e = e->value.function.actual->expr; | |
2803 | } | |
2804 | while(1); | |
2805 | ||
2806 | return NULL; | |
2807 | } | |
2808 | ||
f1abbf69 TK |
2809 | /* Inline assignments of the form c = matmul(a,b). |
2810 | Handle only the cases currently where b and c are rank-two arrays. | |
2811 | ||
2812 | This basically translates the code to | |
2813 | ||
2814 | BLOCK | |
2815 | integer i,j,k | |
2816 | c = 0 | |
2817 | do j=0, size(b,2)-1 | |
2818 | do k=0, size(a, 2)-1 | |
2819 | do i=0, size(a, 1)-1 | |
2820 | c(i * stride(c,1) + lbound(c,1), j * stride(c,2) + lbound(c,2)) = | |
2821 | c(i * stride(c,1) + lbound(c,1), j * stride(c,2) + lbound(c,2)) + | |
2822 | a(i * stride(a,1) + lbound(a,1), k * stride(a,2) + lbound(a,2)) * | |
2823 | b(k * stride(b,1) + lbound(b,1), j * stride(b,2) + lbound(b,2)) | |
2824 | end do | |
2825 | end do | |
2826 | end do | |
2827 | END BLOCK | |
7474dcc1 | 2828 | |
f1abbf69 TK |
2829 | */ |
2830 | ||
2831 | static int | |
2832 | inline_matmul_assign (gfc_code **c, int *walk_subtrees, | |
2833 | void *data ATTRIBUTE_UNUSED) | |
2834 | { | |
2835 | gfc_code *co = *c; | |
2836 | gfc_expr *expr1, *expr2; | |
2837 | gfc_expr *matrix_a, *matrix_b; | |
2838 | gfc_actual_arglist *a, *b; | |
2839 | gfc_code *do_1, *do_2, *do_3, *assign_zero, *assign_matmul; | |
2840 | gfc_expr *zero_e; | |
2841 | gfc_expr *u1, *u2, *u3; | |
2842 | gfc_expr *list[2]; | |
2843 | gfc_expr *ascalar, *bscalar, *cscalar; | |
2844 | gfc_expr *mult; | |
2845 | gfc_expr *var_1, *var_2, *var_3; | |
2846 | gfc_expr *zero; | |
2847 | gfc_namespace *ns; | |
2848 | gfc_intrinsic_op op_times, op_plus; | |
2849 | enum matrix_case m_case; | |
2850 | int i; | |
2851 | gfc_code *if_limit = NULL; | |
2852 | gfc_code **next_code_point; | |
094773e8 | 2853 | bool conjg_a, conjg_b, transpose_a, transpose_b; |
f1abbf69 TK |
2854 | |
2855 | if (co->op != EXEC_ASSIGN) | |
2856 | return 0; | |
2857 | ||
fd42eed8 TK |
2858 | if (in_where) |
2859 | return 0; | |
2860 | ||
56a3d28b JJ |
2861 | /* For now don't do anything in OpenMP workshare, it confuses |
2862 | its translation, which expects only the allowed statements in there. | |
2863 | We should figure out how to parallelize this eventually. */ | |
2864 | if (in_omp_workshare) | |
2865 | return 0; | |
2866 | ||
f1abbf69 TK |
2867 | expr1 = co->expr1; |
2868 | expr2 = co->expr2; | |
2869 | if (expr2->expr_type != EXPR_FUNCTION | |
2870 | || expr2->value.function.isym == NULL | |
2871 | || expr2->value.function.isym->id != GFC_ISYM_MATMUL) | |
2872 | return 0; | |
2873 | ||
2874 | current_code = c; | |
2875 | inserted_block = NULL; | |
2876 | changed_statement = NULL; | |
2877 | ||
2878 | a = expr2->value.function.actual; | |
094773e8 TK |
2879 | matrix_a = check_conjg_transpose_variable (a->expr, &conjg_a, &transpose_a); |
2880 | if (transpose_a || matrix_a == NULL) | |
c39d5e4a | 2881 | return 0; |
f1abbf69 | 2882 | |
c39d5e4a | 2883 | b = a->next; |
094773e8 | 2884 | matrix_b = check_conjg_transpose_variable (b->expr, &conjg_b, &transpose_b); |
c39d5e4a | 2885 | if (matrix_b == NULL) |
f1abbf69 TK |
2886 | return 0; |
2887 | ||
7e269fe8 TK |
2888 | if (has_dimen_vector_ref (expr1) || has_dimen_vector_ref (matrix_a) |
2889 | || has_dimen_vector_ref (matrix_b)) | |
2890 | return 0; | |
2891 | ||
c39d5e4a TK |
2892 | /* We do not handle data dependencies yet. */ |
2893 | if (gfc_check_dependency (expr1, matrix_a, true) | |
2894 | || gfc_check_dependency (expr1, matrix_b, true)) | |
2895 | return 0; | |
2896 | ||
f1abbf69 | 2897 | if (matrix_a->rank == 2) |
094773e8 TK |
2898 | { |
2899 | if (matrix_b->rank == 1) | |
2900 | m_case = A2B1; | |
2901 | else | |
2902 | { | |
2903 | if (transpose_b) | |
2904 | m_case = A2B2T; | |
2905 | else | |
2906 | m_case = A2B2; | |
2907 | } | |
2908 | } | |
f1abbf69 | 2909 | else |
094773e8 TK |
2910 | { |
2911 | /* Vector * Transpose(B) not handled yet. */ | |
2912 | if (transpose_b) | |
2913 | m_case = none; | |
2914 | else | |
2915 | m_case = A1B2; | |
2916 | } | |
f1abbf69 | 2917 | |
094773e8 TK |
2918 | if (m_case == none) |
2919 | return 0; | |
f1abbf69 TK |
2920 | |
2921 | ns = insert_block (); | |
2922 | ||
2923 | /* Assign the type of the zero expression for initializing the resulting | |
2924 | array, and the expression (+ and * for real, integer and complex; | |
2925 | .and. and .or for logical. */ | |
2926 | ||
2927 | switch(expr1->ts.type) | |
2928 | { | |
2929 | case BT_INTEGER: | |
2930 | zero_e = gfc_get_int_expr (expr1->ts.kind, &expr1->where, 0); | |
2931 | op_times = INTRINSIC_TIMES; | |
2932 | op_plus = INTRINSIC_PLUS; | |
2933 | break; | |
2934 | ||
2935 | case BT_LOGICAL: | |
2936 | op_times = INTRINSIC_AND; | |
2937 | op_plus = INTRINSIC_OR; | |
2938 | zero_e = gfc_get_logical_expr (expr1->ts.kind, &expr1->where, | |
2939 | 0); | |
2940 | break; | |
2941 | case BT_REAL: | |
2942 | zero_e = gfc_get_constant_expr (BT_REAL, expr1->ts.kind, | |
2943 | &expr1->where); | |
2944 | mpfr_set_si (zero_e->value.real, 0, GFC_RND_MODE); | |
2945 | op_times = INTRINSIC_TIMES; | |
2946 | op_plus = INTRINSIC_PLUS; | |
2947 | break; | |
2948 | ||
2949 | case BT_COMPLEX: | |
2950 | zero_e = gfc_get_constant_expr (BT_COMPLEX, expr1->ts.kind, | |
2951 | &expr1->where); | |
2952 | mpc_set_si_si (zero_e->value.complex, 0, 0, GFC_RND_MODE); | |
2953 | op_times = INTRINSIC_TIMES; | |
2954 | op_plus = INTRINSIC_PLUS; | |
2955 | ||
2956 | break; | |
2957 | ||
2958 | default: | |
2959 | gcc_unreachable(); | |
2960 | } | |
2961 | ||
2962 | current_code = &ns->code; | |
2963 | ||
2964 | /* Freeze the references, keeping track of how many temporary variables were | |
2965 | created. */ | |
2966 | n_vars = 0; | |
2967 | freeze_references (matrix_a); | |
2968 | freeze_references (matrix_b); | |
2969 | freeze_references (expr1); | |
2970 | ||
2971 | if (n_vars == 0) | |
2972 | next_code_point = current_code; | |
2973 | else | |
2974 | { | |
2975 | next_code_point = &ns->code; | |
2976 | for (i=0; i<n_vars; i++) | |
2977 | next_code_point = &(*next_code_point)->next; | |
2978 | } | |
2979 | ||
2980 | /* Take care of the inline flag. If the limit check evaluates to a | |
2981 | constant, dead code elimination will eliminate the unneeded branch. */ | |
2982 | ||
2983 | if (m_case == A2B2 && flag_inline_matmul_limit > 0) | |
2984 | { | |
2985 | if_limit = inline_limit_check (matrix_a, matrix_b, m_case); | |
2986 | ||
2987 | /* Insert the original statement into the else branch. */ | |
2988 | if_limit->block->block->next = co; | |
2989 | co->next = NULL; | |
2990 | ||
2991 | /* ... and the new ones go into the original one. */ | |
2992 | *next_code_point = if_limit; | |
2993 | next_code_point = &if_limit->block->next; | |
2994 | } | |
2995 | ||
2996 | assign_zero = XCNEW (gfc_code); | |
2997 | assign_zero->op = EXEC_ASSIGN; | |
2998 | assign_zero->loc = co->loc; | |
2999 | assign_zero->expr1 = gfc_copy_expr (expr1); | |
3000 | assign_zero->expr2 = zero_e; | |
3001 | ||
3002 | /* Handle the reallocation, if needed. */ | |
3003 | if (flag_realloc_lhs && gfc_is_reallocatable_lhs (expr1)) | |
3004 | { | |
3005 | gfc_code *lhs_alloc; | |
3006 | ||
3007 | /* Only need to check a single dimension for the A2B2 case for | |
3008 | bounds checking, the rest will be allocated. */ | |
3009 | ||
3010 | if (gfc_option.rtcheck & GFC_RTCHECK_BOUNDS && m_case == A2B2) | |
3011 | { | |
3012 | gfc_code *test; | |
3013 | gfc_expr *a2, *b1; | |
3014 | ||
3015 | a2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 2); | |
3016 | b1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 1); | |
3017 | test = runtime_error_ne (b1, a2, "Dimension of array B incorrect " | |
3018 | "in MATMUL intrinsic: Is %ld, should be %ld"); | |
3019 | *next_code_point = test; | |
3020 | next_code_point = &test->next; | |
3021 | } | |
3022 | ||
3023 | ||
3024 | lhs_alloc = matmul_lhs_realloc (expr1, matrix_a, matrix_b, m_case); | |
3025 | ||
3026 | *next_code_point = lhs_alloc; | |
3027 | next_code_point = &lhs_alloc->next; | |
3028 | ||
3029 | } | |
3030 | else if (gfc_option.rtcheck & GFC_RTCHECK_BOUNDS) | |
3031 | { | |
3032 | gfc_code *test; | |
3033 | gfc_expr *a2, *b1, *c1, *c2, *a1, *b2; | |
3034 | ||
3035 | if (m_case == A2B2 || m_case == A2B1) | |
3036 | { | |
3037 | a2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 2); | |
3038 | b1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 1); | |
3039 | test = runtime_error_ne (b1, a2, "Dimension of array B incorrect " | |
3040 | "in MATMUL intrinsic: Is %ld, should be %ld"); | |
3041 | *next_code_point = test; | |
3042 | next_code_point = &test->next; | |
3043 | ||
3044 | c1 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 1); | |
3045 | a1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 1); | |
3046 | ||
3047 | if (m_case == A2B2) | |
3048 | test = runtime_error_ne (c1, a1, "Incorrect extent in return array in " | |
3049 | "MATMUL intrinsic for dimension 1: " | |
3050 | "is %ld, should be %ld"); | |
3051 | else if (m_case == A2B1) | |
3052 | test = runtime_error_ne (c1, a1, "Incorrect extent in return array in " | |
3053 | "MATMUL intrinsic: " | |
3054 | "is %ld, should be %ld"); | |
3055 | ||
3056 | ||
3057 | *next_code_point = test; | |
3058 | next_code_point = &test->next; | |
3059 | } | |
3060 | else if (m_case == A1B2) | |
3061 | { | |
3062 | a1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 1); | |
3063 | b1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 1); | |
3064 | test = runtime_error_ne (b1, a1, "Dimension of array B incorrect " | |
3065 | "in MATMUL intrinsic: Is %ld, should be %ld"); | |
3066 | *next_code_point = test; | |
3067 | next_code_point = &test->next; | |
3068 | ||
3069 | c1 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 1); | |
3070 | b2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 2); | |
3071 | ||
3072 | test = runtime_error_ne (c1, b2, "Incorrect extent in return array in " | |
3073 | "MATMUL intrinsic: " | |
3074 | "is %ld, should be %ld"); | |
3075 | ||
3076 | *next_code_point = test; | |
3077 | next_code_point = &test->next; | |
3078 | } | |
3079 | ||
3080 | if (m_case == A2B2) | |
3081 | { | |
3082 | c2 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 2); | |
3083 | b2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 2); | |
3084 | test = runtime_error_ne (c2, b2, "Incorrect extent in return array in " | |
3085 | "MATMUL intrinsic for dimension 2: is %ld, should be %ld"); | |
3086 | ||
3087 | *next_code_point = test; | |
3088 | next_code_point = &test->next; | |
3089 | } | |
094773e8 TK |
3090 | |
3091 | if (m_case == A2B2T) | |
3092 | { | |
3093 | c1 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 1); | |
3094 | a1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 1); | |
3095 | test = runtime_error_ne (c1, a1, "Incorrect extent in return array in " | |
3096 | "MATMUL intrinsic for dimension 1: " | |
3097 | "is %ld, should be %ld"); | |
3098 | ||
3099 | *next_code_point = test; | |
3100 | next_code_point = &test->next; | |
3101 | ||
3102 | c2 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 2); | |
3103 | b1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 1); | |
3104 | test = runtime_error_ne (c2, b1, "Incorrect extent in return array in " | |
3105 | "MATMUL intrinsic for dimension 2: " | |
3106 | "is %ld, should be %ld"); | |
3107 | *next_code_point = test; | |
3108 | next_code_point = &test->next; | |
3109 | ||
3110 | a2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 2); | |
3111 | b2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 2); | |
3112 | ||
3113 | test = runtime_error_ne (b2, a2, "Incorrect extent in argument B in " | |
3114 | "MATMUL intrnisic for dimension 2: " | |
3115 | "is %ld, should be %ld"); | |
3116 | *next_code_point = test; | |
3117 | next_code_point = &test->next; | |
3118 | ||
3119 | } | |
f1abbf69 TK |
3120 | } |
3121 | ||
3122 | *next_code_point = assign_zero; | |
3123 | ||
3124 | zero = gfc_get_int_expr (gfc_index_integer_kind, &co->loc, 0); | |
3125 | ||
3126 | assign_matmul = XCNEW (gfc_code); | |
3127 | assign_matmul->op = EXEC_ASSIGN; | |
3128 | assign_matmul->loc = co->loc; | |
3129 | ||
3130 | /* Get the bounds for the loops, create them and create the scalarized | |
3131 | expressions. */ | |
3132 | ||
3133 | switch (m_case) | |
3134 | { | |
3135 | case A2B2: | |
3136 | inline_limit_check (matrix_a, matrix_b, m_case); | |
3137 | ||
3138 | u1 = get_size_m1 (matrix_b, 2); | |
3139 | u2 = get_size_m1 (matrix_a, 2); | |
3140 | u3 = get_size_m1 (matrix_a, 1); | |
3141 | ||
3142 | do_1 = create_do_loop (gfc_copy_expr (zero), u1, NULL, &co->loc, ns); | |
3143 | do_2 = create_do_loop (gfc_copy_expr (zero), u2, NULL, &co->loc, ns); | |
3144 | do_3 = create_do_loop (gfc_copy_expr (zero), u3, NULL, &co->loc, ns); | |
3145 | ||
3146 | do_1->block->next = do_2; | |
3147 | do_2->block->next = do_3; | |
3148 | do_3->block->next = assign_matmul; | |
3149 | ||
3150 | var_1 = do_1->ext.iterator->var; | |
3151 | var_2 = do_2->ext.iterator->var; | |
3152 | var_3 = do_3->ext.iterator->var; | |
3153 | ||
3154 | list[0] = var_3; | |
3155 | list[1] = var_1; | |
7fc67fcb | 3156 | cscalar = scalarized_expr (co->expr1, list, 2); |
f1abbf69 TK |
3157 | |
3158 | list[0] = var_3; | |
3159 | list[1] = var_2; | |
7fc67fcb | 3160 | ascalar = scalarized_expr (matrix_a, list, 2); |
f1abbf69 TK |
3161 | |
3162 | list[0] = var_2; | |
3163 | list[1] = var_1; | |
7fc67fcb | 3164 | bscalar = scalarized_expr (matrix_b, list, 2); |
f1abbf69 TK |
3165 | |
3166 | break; | |
3167 | ||
094773e8 TK |
3168 | case A2B2T: |
3169 | inline_limit_check (matrix_a, matrix_b, m_case); | |
3170 | ||
3171 | u1 = get_size_m1 (matrix_b, 1); | |
3172 | u2 = get_size_m1 (matrix_a, 2); | |
3173 | u3 = get_size_m1 (matrix_a, 1); | |
3174 | ||
3175 | do_1 = create_do_loop (gfc_copy_expr (zero), u1, NULL, &co->loc, ns); | |
3176 | do_2 = create_do_loop (gfc_copy_expr (zero), u2, NULL, &co->loc, ns); | |
3177 | do_3 = create_do_loop (gfc_copy_expr (zero), u3, NULL, &co->loc, ns); | |
3178 | ||
3179 | do_1->block->next = do_2; | |
3180 | do_2->block->next = do_3; | |
3181 | do_3->block->next = assign_matmul; | |
3182 | ||
3183 | var_1 = do_1->ext.iterator->var; | |
3184 | var_2 = do_2->ext.iterator->var; | |
3185 | var_3 = do_3->ext.iterator->var; | |
3186 | ||
3187 | list[0] = var_3; | |
3188 | list[1] = var_1; | |
3189 | cscalar = scalarized_expr (co->expr1, list, 2); | |
3190 | ||
3191 | list[0] = var_3; | |
3192 | list[1] = var_2; | |
3193 | ascalar = scalarized_expr (matrix_a, list, 2); | |
3194 | ||
3195 | list[0] = var_1; | |
3196 | list[1] = var_2; | |
3197 | bscalar = scalarized_expr (matrix_b, list, 2); | |
3198 | ||
3199 | break; | |
3200 | ||
f1abbf69 TK |
3201 | case A2B1: |
3202 | u1 = get_size_m1 (matrix_b, 1); | |
3203 | u2 = get_size_m1 (matrix_a, 1); | |
3204 | ||
3205 | do_1 = create_do_loop (gfc_copy_expr (zero), u1, NULL, &co->loc, ns); | |
3206 | do_2 = create_do_loop (gfc_copy_expr (zero), u2, NULL, &co->loc, ns); | |
3207 | ||
3208 | do_1->block->next = do_2; | |
3209 | do_2->block->next = assign_matmul; | |
3210 | ||
3211 | var_1 = do_1->ext.iterator->var; | |
3212 | var_2 = do_2->ext.iterator->var; | |
3213 | ||
3214 | list[0] = var_2; | |
7fc67fcb | 3215 | cscalar = scalarized_expr (co->expr1, list, 1); |
f1abbf69 TK |
3216 | |
3217 | list[0] = var_2; | |
3218 | list[1] = var_1; | |
7fc67fcb | 3219 | ascalar = scalarized_expr (matrix_a, list, 2); |
f1abbf69 TK |
3220 | |
3221 | list[0] = var_1; | |
7fc67fcb | 3222 | bscalar = scalarized_expr (matrix_b, list, 1); |
f1abbf69 TK |
3223 | |
3224 | break; | |
3225 | ||
3226 | case A1B2: | |
3227 | u1 = get_size_m1 (matrix_b, 2); | |
3228 | u2 = get_size_m1 (matrix_a, 1); | |
3229 | ||
3230 | do_1 = create_do_loop (gfc_copy_expr (zero), u1, NULL, &co->loc, ns); | |
3231 | do_2 = create_do_loop (gfc_copy_expr (zero), u2, NULL, &co->loc, ns); | |
3232 | ||
3233 | do_1->block->next = do_2; | |
3234 | do_2->block->next = assign_matmul; | |
3235 | ||
3236 | var_1 = do_1->ext.iterator->var; | |
3237 | var_2 = do_2->ext.iterator->var; | |
3238 | ||
3239 | list[0] = var_1; | |
7fc67fcb | 3240 | cscalar = scalarized_expr (co->expr1, list, 1); |
f1abbf69 TK |
3241 | |
3242 | list[0] = var_2; | |
7fc67fcb | 3243 | ascalar = scalarized_expr (matrix_a, list, 1); |
f1abbf69 TK |
3244 | |
3245 | list[0] = var_2; | |
3246 | list[1] = var_1; | |
7fc67fcb | 3247 | bscalar = scalarized_expr (matrix_b, list, 2); |
f1abbf69 TK |
3248 | |
3249 | break; | |
3250 | ||
3251 | default: | |
3252 | gcc_unreachable(); | |
3253 | } | |
3254 | ||
c39d5e4a TK |
3255 | if (conjg_a) |
3256 | ascalar = gfc_build_intrinsic_call (ns, GFC_ISYM_CONJG, "conjg", | |
3257 | matrix_a->where, 1, ascalar); | |
3258 | ||
3259 | if (conjg_b) | |
7474dcc1 | 3260 | bscalar = gfc_build_intrinsic_call (ns, GFC_ISYM_CONJG, "conjg", |
c39d5e4a TK |
3261 | matrix_b->where, 1, bscalar); |
3262 | ||
f1abbf69 TK |
3263 | /* First loop comes after the zero assignment. */ |
3264 | assign_zero->next = do_1; | |
3265 | ||
3266 | /* Build the assignment expression in the loop. */ | |
3267 | assign_matmul->expr1 = gfc_copy_expr (cscalar); | |
3268 | ||
3269 | mult = get_operand (op_times, ascalar, bscalar); | |
3270 | assign_matmul->expr2 = get_operand (op_plus, cscalar, mult); | |
3271 | ||
3272 | /* If we don't want to keep the original statement around in | |
3273 | the else branch, we can free it. */ | |
3274 | ||
3275 | if (if_limit == NULL) | |
3276 | gfc_free_statements(co); | |
3277 | else | |
3278 | co->next = NULL; | |
3279 | ||
3280 | gfc_free_expr (zero); | |
3281 | *walk_subtrees = 0; | |
3282 | return 0; | |
3283 | } | |
305a35da | 3284 | |
4d42b5cd JJ |
3285 | #define WALK_SUBEXPR(NODE) \ |
3286 | do \ | |
3287 | { \ | |
3288 | result = gfc_expr_walker (&(NODE), exprfn, data); \ | |
3289 | if (result) \ | |
3290 | return result; \ | |
3291 | } \ | |
3292 | while (0) | |
3293 | #define WALK_SUBEXPR_TAIL(NODE) e = &(NODE); continue | |
601d98be | 3294 | |
4d42b5cd JJ |
3295 | /* Walk expression *E, calling EXPRFN on each expression in it. */ |
3296 | ||
3297 | int | |
3298 | gfc_expr_walker (gfc_expr **e, walk_expr_fn_t exprfn, void *data) | |
601d98be | 3299 | { |
4d42b5cd JJ |
3300 | while (*e) |
3301 | { | |
3302 | int walk_subtrees = 1; | |
3303 | gfc_actual_arglist *a; | |
46f19baf TK |
3304 | gfc_ref *r; |
3305 | gfc_constructor *c; | |
3306 | ||
4d42b5cd JJ |
3307 | int result = exprfn (e, &walk_subtrees, data); |
3308 | if (result) | |
3309 | return result; | |
3310 | if (walk_subtrees) | |
3311 | switch ((*e)->expr_type) | |
3312 | { | |
3313 | case EXPR_OP: | |
3314 | WALK_SUBEXPR ((*e)->value.op.op1); | |
3315 | WALK_SUBEXPR_TAIL ((*e)->value.op.op2); | |
3316 | break; | |
3317 | case EXPR_FUNCTION: | |
3318 | for (a = (*e)->value.function.actual; a; a = a->next) | |
3319 | WALK_SUBEXPR (a->expr); | |
3320 | break; | |
3321 | case EXPR_COMPCALL: | |
3322 | case EXPR_PPC: | |
3323 | WALK_SUBEXPR ((*e)->value.compcall.base_object); | |
3324 | for (a = (*e)->value.compcall.actual; a; a = a->next) | |
3325 | WALK_SUBEXPR (a->expr); | |
3326 | break; | |
46f19baf TK |
3327 | |
3328 | case EXPR_STRUCTURE: | |
3329 | case EXPR_ARRAY: | |
3330 | for (c = gfc_constructor_first ((*e)->value.constructor); c; | |
3331 | c = gfc_constructor_next (c)) | |
3332 | { | |
8144d290 TK |
3333 | if (c->iterator == NULL) |
3334 | WALK_SUBEXPR (c->expr); | |
3335 | else | |
46f19baf | 3336 | { |
8144d290 TK |
3337 | iterator_level ++; |
3338 | WALK_SUBEXPR (c->expr); | |
3339 | iterator_level --; | |
46f19baf TK |
3340 | WALK_SUBEXPR (c->iterator->var); |
3341 | WALK_SUBEXPR (c->iterator->start); | |
3342 | WALK_SUBEXPR (c->iterator->end); | |
3343 | WALK_SUBEXPR (c->iterator->step); | |
3344 | } | |
3345 | } | |
3346 | ||
3347 | if ((*e)->expr_type != EXPR_ARRAY) | |
3348 | break; | |
3349 | ||
3350 | /* Fall through to the variable case in order to walk the | |
dd5a833e | 3351 | reference. */ |
81fea426 | 3352 | gcc_fallthrough (); |
46f19baf | 3353 | |
1151446c | 3354 | case EXPR_SUBSTRING: |
46f19baf TK |
3355 | case EXPR_VARIABLE: |
3356 | for (r = (*e)->ref; r; r = r->next) | |
3357 | { | |
3358 | gfc_array_ref *ar; | |
3359 | int i; | |
3360 | ||
3361 | switch (r->type) | |
3362 | { | |
3363 | case REF_ARRAY: | |
3364 | ar = &r->u.ar; | |
3365 | if (ar->type == AR_SECTION || ar->type == AR_ELEMENT) | |
3366 | { | |
3367 | for (i=0; i< ar->dimen; i++) | |
3368 | { | |
3369 | WALK_SUBEXPR (ar->start[i]); | |
3370 | WALK_SUBEXPR (ar->end[i]); | |
3371 | WALK_SUBEXPR (ar->stride[i]); | |
3372 | } | |
3373 | } | |
3374 | ||
3375 | break; | |
3376 | ||
3377 | case REF_SUBSTRING: | |
3378 | WALK_SUBEXPR (r->u.ss.start); | |
3379 | WALK_SUBEXPR (r->u.ss.end); | |
3380 | break; | |
3381 | ||
3382 | case REF_COMPONENT: | |
3383 | break; | |
3384 | } | |
3385 | } | |
3386 | ||
4d42b5cd JJ |
3387 | default: |
3388 | break; | |
3389 | } | |
3390 | return 0; | |
3391 | } | |
3392 | return 0; | |
3393 | } | |
601d98be | 3394 | |
4d42b5cd JJ |
3395 | #define WALK_SUBCODE(NODE) \ |
3396 | do \ | |
3397 | { \ | |
3398 | result = gfc_code_walker (&(NODE), codefn, exprfn, data); \ | |
3399 | if (result) \ | |
3400 | return result; \ | |
3401 | } \ | |
3402 | while (0) | |
3403 | ||
3404 | /* Walk code *C, calling CODEFN on each gfc_code node in it and calling EXPRFN | |
3405 | on each expression in it. If any of the hooks returns non-zero, that | |
3406 | value is immediately returned. If the hook sets *WALK_SUBTREES to 0, | |
3407 | no subcodes or subexpressions are traversed. */ | |
3408 | ||
3409 | int | |
3410 | gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn, | |
3411 | void *data) | |
3412 | { | |
3413 | for (; *c; c = &(*c)->next) | |
601d98be | 3414 | { |
4d42b5cd JJ |
3415 | int walk_subtrees = 1; |
3416 | int result = codefn (c, &walk_subtrees, data); | |
3417 | if (result) | |
3418 | return result; | |
bc81f559 | 3419 | |
4d42b5cd JJ |
3420 | if (walk_subtrees) |
3421 | { | |
3422 | gfc_code *b; | |
bc81f559 | 3423 | gfc_actual_arglist *a; |
82358e09 | 3424 | gfc_code *co; |
930d4d4e | 3425 | gfc_association_list *alist; |
e07e39f6 | 3426 | bool saved_in_omp_workshare; |
fd42eed8 | 3427 | bool saved_in_where; |
82358e09 TK |
3428 | |
3429 | /* There might be statement insertions before the current code, | |
3430 | which must not affect the expression walker. */ | |
3431 | ||
3432 | co = *c; | |
e07e39f6 | 3433 | saved_in_omp_workshare = in_omp_workshare; |
fd42eed8 | 3434 | saved_in_where = in_where; |
bc81f559 | 3435 | |
82358e09 | 3436 | switch (co->op) |
4d42b5cd | 3437 | { |
930d4d4e TK |
3438 | |
3439 | case EXEC_BLOCK: | |
3440 | WALK_SUBCODE (co->ext.block.ns->code); | |
e3f9e757 TK |
3441 | if (co->ext.block.assoc) |
3442 | { | |
3443 | bool saved_in_assoc_list = in_assoc_list; | |
3444 | ||
3445 | in_assoc_list = true; | |
3446 | for (alist = co->ext.block.assoc; alist; alist = alist->next) | |
3447 | WALK_SUBEXPR (alist->target); | |
3448 | ||
3449 | in_assoc_list = saved_in_assoc_list; | |
3450 | } | |
3451 | ||
930d4d4e TK |
3452 | break; |
3453 | ||
4d42b5cd | 3454 | case EXEC_DO: |
305a35da | 3455 | doloop_level ++; |
82358e09 TK |
3456 | WALK_SUBEXPR (co->ext.iterator->var); |
3457 | WALK_SUBEXPR (co->ext.iterator->start); | |
3458 | WALK_SUBEXPR (co->ext.iterator->end); | |
3459 | WALK_SUBEXPR (co->ext.iterator->step); | |
4d42b5cd | 3460 | break; |
bc81f559 | 3461 | |
fd42eed8 TK |
3462 | case EXEC_WHERE: |
3463 | in_where = true; | |
3464 | break; | |
3465 | ||
bc81f559 TK |
3466 | case EXEC_CALL: |
3467 | case EXEC_ASSIGN_CALL: | |
82358e09 | 3468 | for (a = co->ext.actual; a; a = a->next) |
bc81f559 TK |
3469 | WALK_SUBEXPR (a->expr); |
3470 | break; | |
3471 | ||
3472 | case EXEC_CALL_PPC: | |
82358e09 TK |
3473 | WALK_SUBEXPR (co->expr1); |
3474 | for (a = co->ext.actual; a; a = a->next) | |
bc81f559 TK |
3475 | WALK_SUBEXPR (a->expr); |
3476 | break; | |
3477 | ||
4d42b5cd | 3478 | case EXEC_SELECT: |
82358e09 TK |
3479 | WALK_SUBEXPR (co->expr1); |
3480 | for (b = co->block; b; b = b->block) | |
4d42b5cd JJ |
3481 | { |
3482 | gfc_case *cp; | |
29a63d67 | 3483 | for (cp = b->ext.block.case_list; cp; cp = cp->next) |
4d42b5cd JJ |
3484 | { |
3485 | WALK_SUBEXPR (cp->low); | |
3486 | WALK_SUBEXPR (cp->high); | |
3487 | } | |
3488 | WALK_SUBCODE (b->next); | |
3489 | } | |
3490 | continue; | |
bc81f559 | 3491 | |
4d42b5cd JJ |
3492 | case EXEC_ALLOCATE: |
3493 | case EXEC_DEALLOCATE: | |
3494 | { | |
3495 | gfc_alloc *a; | |
82358e09 | 3496 | for (a = co->ext.alloc.list; a; a = a->next) |
4d42b5cd JJ |
3497 | WALK_SUBEXPR (a->expr); |
3498 | break; | |
3499 | } | |
bc81f559 | 3500 | |
4d42b5cd | 3501 | case EXEC_FORALL: |
8c6a85e3 | 3502 | case EXEC_DO_CONCURRENT: |
4d42b5cd JJ |
3503 | { |
3504 | gfc_forall_iterator *fa; | |
82358e09 | 3505 | for (fa = co->ext.forall_iterator; fa; fa = fa->next) |
4d42b5cd JJ |
3506 | { |
3507 | WALK_SUBEXPR (fa->var); | |
3508 | WALK_SUBEXPR (fa->start); | |
3509 | WALK_SUBEXPR (fa->end); | |
3510 | WALK_SUBEXPR (fa->stride); | |
3511 | } | |
2855325f TK |
3512 | if (co->op == EXEC_FORALL) |
3513 | forall_level ++; | |
4d42b5cd JJ |
3514 | break; |
3515 | } | |
bc81f559 | 3516 | |
4d42b5cd | 3517 | case EXEC_OPEN: |
82358e09 TK |
3518 | WALK_SUBEXPR (co->ext.open->unit); |
3519 | WALK_SUBEXPR (co->ext.open->file); | |
3520 | WALK_SUBEXPR (co->ext.open->status); | |
3521 | WALK_SUBEXPR (co->ext.open->access); | |
3522 | WALK_SUBEXPR (co->ext.open->form); | |
3523 | WALK_SUBEXPR (co->ext.open->recl); | |
3524 | WALK_SUBEXPR (co->ext.open->blank); | |
3525 | WALK_SUBEXPR (co->ext.open->position); | |
3526 | WALK_SUBEXPR (co->ext.open->action); | |
3527 | WALK_SUBEXPR (co->ext.open->delim); | |
3528 | WALK_SUBEXPR (co->ext.open->pad); | |
3529 | WALK_SUBEXPR (co->ext.open->iostat); | |
3530 | WALK_SUBEXPR (co->ext.open->iomsg); | |
3531 | WALK_SUBEXPR (co->ext.open->convert); | |
3532 | WALK_SUBEXPR (co->ext.open->decimal); | |
3533 | WALK_SUBEXPR (co->ext.open->encoding); | |
3534 | WALK_SUBEXPR (co->ext.open->round); | |
3535 | WALK_SUBEXPR (co->ext.open->sign); | |
3536 | WALK_SUBEXPR (co->ext.open->asynchronous); | |
3537 | WALK_SUBEXPR (co->ext.open->id); | |
3538 | WALK_SUBEXPR (co->ext.open->newunit); | |
4d42b5cd | 3539 | break; |
bc81f559 | 3540 | |
4d42b5cd | 3541 | case EXEC_CLOSE: |
82358e09 TK |
3542 | WALK_SUBEXPR (co->ext.close->unit); |
3543 | WALK_SUBEXPR (co->ext.close->status); | |
3544 | WALK_SUBEXPR (co->ext.close->iostat); | |
3545 | WALK_SUBEXPR (co->ext.close->iomsg); | |
4d42b5cd | 3546 | break; |
bc81f559 | 3547 | |
4d42b5cd JJ |
3548 | case EXEC_BACKSPACE: |
3549 | case EXEC_ENDFILE: | |
3550 | case EXEC_REWIND: | |
3551 | case EXEC_FLUSH: | |
82358e09 TK |
3552 | WALK_SUBEXPR (co->ext.filepos->unit); |
3553 | WALK_SUBEXPR (co->ext.filepos->iostat); | |
3554 | WALK_SUBEXPR (co->ext.filepos->iomsg); | |
4d42b5cd | 3555 | break; |
bc81f559 | 3556 | |
4d42b5cd | 3557 | case EXEC_INQUIRE: |
82358e09 TK |
3558 | WALK_SUBEXPR (co->ext.inquire->unit); |
3559 | WALK_SUBEXPR (co->ext.inquire->file); | |
3560 | WALK_SUBEXPR (co->ext.inquire->iomsg); | |
3561 | WALK_SUBEXPR (co->ext.inquire->iostat); | |
3562 | WALK_SUBEXPR (co->ext.inquire->exist); | |
3563 | WALK_SUBEXPR (co->ext.inquire->opened); | |
3564 | WALK_SUBEXPR (co->ext.inquire->number); | |
3565 | WALK_SUBEXPR (co->ext.inquire->named); | |
3566 | WALK_SUBEXPR (co->ext.inquire->name); | |
3567 | WALK_SUBEXPR (co->ext.inquire->access); | |
3568 | WALK_SUBEXPR (co->ext.inquire->sequential); | |
3569 | WALK_SUBEXPR (co->ext.inquire->direct); | |
3570 | WALK_SUBEXPR (co->ext.inquire->form); | |
3571 | WALK_SUBEXPR (co->ext.inquire->formatted); | |
3572 | WALK_SUBEXPR (co->ext.inquire->unformatted); | |
3573 | WALK_SUBEXPR (co->ext.inquire->recl); | |
3574 | WALK_SUBEXPR (co->ext.inquire->nextrec); | |
3575 | WALK_SUBEXPR (co->ext.inquire->blank); | |
3576 | WALK_SUBEXPR (co->ext.inquire->position); | |
3577 | WALK_SUBEXPR (co->ext.inquire->action); | |
3578 | WALK_SUBEXPR (co->ext.inquire->read); | |
3579 | WALK_SUBEXPR (co->ext.inquire->write); | |
3580 | WALK_SUBEXPR (co->ext.inquire->readwrite); | |
3581 | WALK_SUBEXPR (co->ext.inquire->delim); | |
3582 | WALK_SUBEXPR (co->ext.inquire->encoding); | |
3583 | WALK_SUBEXPR (co->ext.inquire->pad); | |
3584 | WALK_SUBEXPR (co->ext.inquire->iolength); | |
3585 | WALK_SUBEXPR (co->ext.inquire->convert); | |
3586 | WALK_SUBEXPR (co->ext.inquire->strm_pos); | |
3587 | WALK_SUBEXPR (co->ext.inquire->asynchronous); | |
3588 | WALK_SUBEXPR (co->ext.inquire->decimal); | |
3589 | WALK_SUBEXPR (co->ext.inquire->pending); | |
3590 | WALK_SUBEXPR (co->ext.inquire->id); | |
3591 | WALK_SUBEXPR (co->ext.inquire->sign); | |
3592 | WALK_SUBEXPR (co->ext.inquire->size); | |
3593 | WALK_SUBEXPR (co->ext.inquire->round); | |
4d42b5cd | 3594 | break; |
bc81f559 | 3595 | |
4d42b5cd | 3596 | case EXEC_WAIT: |
82358e09 TK |
3597 | WALK_SUBEXPR (co->ext.wait->unit); |
3598 | WALK_SUBEXPR (co->ext.wait->iostat); | |
3599 | WALK_SUBEXPR (co->ext.wait->iomsg); | |
3600 | WALK_SUBEXPR (co->ext.wait->id); | |
4d42b5cd | 3601 | break; |
bc81f559 | 3602 | |
4d42b5cd JJ |
3603 | case EXEC_READ: |
3604 | case EXEC_WRITE: | |
82358e09 TK |
3605 | WALK_SUBEXPR (co->ext.dt->io_unit); |
3606 | WALK_SUBEXPR (co->ext.dt->format_expr); | |
3607 | WALK_SUBEXPR (co->ext.dt->rec); | |
3608 | WALK_SUBEXPR (co->ext.dt->advance); | |
3609 | WALK_SUBEXPR (co->ext.dt->iostat); | |
3610 | WALK_SUBEXPR (co->ext.dt->size); | |
3611 | WALK_SUBEXPR (co->ext.dt->iomsg); | |
3612 | WALK_SUBEXPR (co->ext.dt->id); | |
3613 | WALK_SUBEXPR (co->ext.dt->pos); | |
3614 | WALK_SUBEXPR (co->ext.dt->asynchronous); | |
3615 | WALK_SUBEXPR (co->ext.dt->blank); | |
3616 | WALK_SUBEXPR (co->ext.dt->decimal); | |
3617 | WALK_SUBEXPR (co->ext.dt->delim); | |
3618 | WALK_SUBEXPR (co->ext.dt->pad); | |
3619 | WALK_SUBEXPR (co->ext.dt->round); | |
3620 | WALK_SUBEXPR (co->ext.dt->sign); | |
3621 | WALK_SUBEXPR (co->ext.dt->extra_comma); | |
4d42b5cd | 3622 | break; |
bc81f559 | 3623 | |
4d42b5cd JJ |
3624 | case EXEC_OMP_PARALLEL: |
3625 | case EXEC_OMP_PARALLEL_DO: | |
dd2fc525 | 3626 | case EXEC_OMP_PARALLEL_DO_SIMD: |
4d42b5cd | 3627 | case EXEC_OMP_PARALLEL_SECTIONS: |
e07e39f6 TK |
3628 | |
3629 | in_omp_workshare = false; | |
3630 | ||
3631 | /* This goto serves as a shortcut to avoid code | |
3632 | duplication or a larger if or switch statement. */ | |
3633 | goto check_omp_clauses; | |
7474dcc1 | 3634 | |
e07e39f6 | 3635 | case EXEC_OMP_WORKSHARE: |
4d42b5cd | 3636 | case EXEC_OMP_PARALLEL_WORKSHARE: |
e07e39f6 TK |
3637 | |
3638 | in_omp_workshare = true; | |
3639 | ||
3640 | /* Fall through */ | |
f014c653 JJ |
3641 | |
3642 | case EXEC_OMP_DISTRIBUTE: | |
3643 | case EXEC_OMP_DISTRIBUTE_PARALLEL_DO: | |
3644 | case EXEC_OMP_DISTRIBUTE_PARALLEL_DO_SIMD: | |
3645 | case EXEC_OMP_DISTRIBUTE_SIMD: | |
e07e39f6 | 3646 | case EXEC_OMP_DO: |
dd2fc525 | 3647 | case EXEC_OMP_DO_SIMD: |
4d42b5cd JJ |
3648 | case EXEC_OMP_SECTIONS: |
3649 | case EXEC_OMP_SINGLE: | |
4d42b5cd | 3650 | case EXEC_OMP_END_SINGLE: |
dd2fc525 | 3651 | case EXEC_OMP_SIMD: |
f014c653 JJ |
3652 | case EXEC_OMP_TARGET: |
3653 | case EXEC_OMP_TARGET_DATA: | |
3654 | case EXEC_OMP_TARGET_TEAMS: | |
3655 | case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE: | |
3656 | case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO: | |
3657 | case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD: | |
3658 | case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_SIMD: | |
3659 | case EXEC_OMP_TARGET_UPDATE: | |
4d42b5cd | 3660 | case EXEC_OMP_TASK: |
f014c653 JJ |
3661 | case EXEC_OMP_TEAMS: |
3662 | case EXEC_OMP_TEAMS_DISTRIBUTE: | |
3663 | case EXEC_OMP_TEAMS_DISTRIBUTE_PARALLEL_DO: | |
3664 | case EXEC_OMP_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD: | |
3665 | case EXEC_OMP_TEAMS_DISTRIBUTE_SIMD: | |
e07e39f6 TK |
3666 | |
3667 | /* Come to this label only from the | |
3668 | EXEC_OMP_PARALLEL_* cases above. */ | |
3669 | ||
3670 | check_omp_clauses: | |
3671 | ||
82358e09 | 3672 | if (co->ext.omp_clauses) |
4d42b5cd | 3673 | { |
f014c653 JJ |
3674 | gfc_omp_namelist *n; |
3675 | static int list_types[] | |
3676 | = { OMP_LIST_ALIGNED, OMP_LIST_LINEAR, OMP_LIST_DEPEND, | |
3677 | OMP_LIST_MAP, OMP_LIST_TO, OMP_LIST_FROM }; | |
3678 | size_t idx; | |
82358e09 | 3679 | WALK_SUBEXPR (co->ext.omp_clauses->if_expr); |
20906c66 | 3680 | WALK_SUBEXPR (co->ext.omp_clauses->final_expr); |
82358e09 TK |
3681 | WALK_SUBEXPR (co->ext.omp_clauses->num_threads); |
3682 | WALK_SUBEXPR (co->ext.omp_clauses->chunk_size); | |
dd2fc525 JJ |
3683 | WALK_SUBEXPR (co->ext.omp_clauses->safelen_expr); |
3684 | WALK_SUBEXPR (co->ext.omp_clauses->simdlen_expr); | |
f014c653 JJ |
3685 | WALK_SUBEXPR (co->ext.omp_clauses->num_teams); |
3686 | WALK_SUBEXPR (co->ext.omp_clauses->device); | |
3687 | WALK_SUBEXPR (co->ext.omp_clauses->thread_limit); | |
3688 | WALK_SUBEXPR (co->ext.omp_clauses->dist_chunk_size); | |
3689 | for (idx = 0; | |
3690 | idx < sizeof (list_types) / sizeof (list_types[0]); | |
3691 | idx++) | |
3692 | for (n = co->ext.omp_clauses->lists[list_types[idx]]; | |
3693 | n; n = n->next) | |
3694 | WALK_SUBEXPR (n->expr); | |
4d42b5cd JJ |
3695 | } |
3696 | break; | |
3697 | default: | |
3698 | break; | |
3699 | } | |
bc81f559 | 3700 | |
82358e09 TK |
3701 | WALK_SUBEXPR (co->expr1); |
3702 | WALK_SUBEXPR (co->expr2); | |
3703 | WALK_SUBEXPR (co->expr3); | |
5493aa17 | 3704 | WALK_SUBEXPR (co->expr4); |
82358e09 | 3705 | for (b = co->block; b; b = b->block) |
4d42b5cd JJ |
3706 | { |
3707 | WALK_SUBEXPR (b->expr1); | |
3708 | WALK_SUBEXPR (b->expr2); | |
3709 | WALK_SUBCODE (b->next); | |
3710 | } | |
2855325f TK |
3711 | |
3712 | if (co->op == EXEC_FORALL) | |
3713 | forall_level --; | |
3714 | ||
305a35da TK |
3715 | if (co->op == EXEC_DO) |
3716 | doloop_level --; | |
3717 | ||
e07e39f6 | 3718 | in_omp_workshare = saved_in_omp_workshare; |
fd42eed8 | 3719 | in_where = saved_in_where; |
4d42b5cd | 3720 | } |
601d98be | 3721 | } |
4d42b5cd | 3722 | return 0; |
601d98be | 3723 | } |